OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * Tools for Java code generation. | 6 * Tools for Java code generation. |
7 */ | 7 */ |
8 library CodegenJava; | 8 library CodegenJava; |
9 | 9 |
10 import 'package:html5lib/dom.dart' as dom; | 10 import 'package:html5lib/dom.dart' as dom; |
| 11 |
11 import 'api.dart'; | 12 import 'api.dart'; |
12 import 'codegen_tools.dart'; | 13 import 'codegen_tools.dart'; |
13 import 'from_html.dart'; | 14 import 'from_html.dart'; |
14 import 'to_html.dart'; | 15 import 'to_html.dart'; |
15 | 16 |
16 /** | 17 /** |
| 18 * Create a [GeneratedFile] that creates Java code and outputs it to [path]. |
| 19 * [path] uses Posix-style path separators regardless of the OS. |
| 20 */ |
| 21 GeneratedFile javaGeneratedFile(String path, CodegenJavaVisitor |
| 22 createVisitor(Api api)) { |
| 23 return new GeneratedFile(path, () { |
| 24 CodegenJavaVisitor visitor = createVisitor(readApi()); |
| 25 return visitor.collectCode(visitor.visitApi); |
| 26 }); |
| 27 } |
| 28 |
| 29 /** |
| 30 * Iterate through the values in [map] in the order of increasing keys. |
| 31 */ |
| 32 Iterable<String> _valuesSortedByKey(Map<String, String> map) { |
| 33 List<String> keys = map.keys.toList(); |
| 34 keys.sort(); |
| 35 return keys.map((String key) => map[key]); |
| 36 } |
| 37 |
| 38 /** |
17 * Common code for all Java code generation. | 39 * Common code for all Java code generation. |
18 */ | 40 */ |
19 class CodegenJavaVisitor extends HierarchicalApiVisitor with CodeGenerator { | 41 class CodegenJavaVisitor extends HierarchicalApiVisitor with CodeGenerator { |
20 _CodegenJavaState _state; | |
21 | |
22 /** | 42 /** |
23 * Variable names which must be changed in order to avoid conflict with | 43 * Variable names which must be changed in order to avoid conflict with |
24 * reserved words in Java. | 44 * reserved words in Java. |
25 */ | 45 */ |
26 static const Map<String, String> _variableRenames = const { | 46 static const Map<String, String> _variableRenames = const { |
27 'default': 'defaultSdk' | 47 'default': 'defaultSdk' |
28 }; | 48 }; |
29 | 49 |
30 /** | 50 /** |
31 * Type references in the spec that are named something else in Java. | 51 * Type references in the spec that are named something else in Java. |
32 */ | 52 */ |
33 static const Map<String, String> _typeRenames = const { | 53 static const Map<String, String> _typeRenames = const { |
34 'bool': 'boolean', | 54 'bool': 'boolean', |
35 'int': 'int', | 55 'int': 'int', |
36 'ExecutionContextId': 'String', | 56 'ExecutionContextId': 'String', |
37 'FilePath': 'String', | 57 'FilePath': 'String', |
38 'DebugContextId': 'String', | 58 'DebugContextId': 'String', |
39 'object': 'Object', | 59 'object': 'Object', |
40 'Override': 'OverrideMember', | 60 'Override': 'OverrideMember', |
41 }; | 61 }; |
42 | 62 |
| 63 _CodegenJavaState _state; |
| 64 |
43 /** | 65 /** |
44 * Visitor used to produce doc comments. | 66 * Visitor used to produce doc comments. |
45 */ | 67 */ |
46 final ToHtmlVisitor toHtmlVisitor; | 68 final ToHtmlVisitor toHtmlVisitor; |
47 | 69 |
48 CodegenJavaVisitor(Api api) | 70 CodegenJavaVisitor(Api api) |
49 : super(api), | 71 : super(api), |
50 toHtmlVisitor = new ToHtmlVisitor(api); | 72 toHtmlVisitor = new ToHtmlVisitor(api); |
51 | 73 |
52 /** | 74 /** |
| 75 * Create a constructor, using [callback] to create its contents. |
| 76 */ |
| 77 void constructor(String name, void callback()) { |
| 78 _state.constructors[name] = collectCode(callback); |
| 79 } |
| 80 |
| 81 /** |
| 82 * Return true iff the passed [TypeDecl] will represent an array in Java. |
| 83 */ |
| 84 bool isArray(TypeDecl type) { |
| 85 return type is TypeList && isPrimitive(type.itemType); |
| 86 } |
| 87 |
| 88 /** |
| 89 * Return true iff the passed [TypeDecl] is a type declared in the spec_input. |
| 90 */ |
| 91 bool isDeclaredInSpec(TypeDecl type) { |
| 92 // TypeReference resolvedType = super.resolveTypeReferenceChain(type); |
| 93 // if(resolvedType is TypeObject) { |
| 94 // return truye; |
| 95 // } |
| 96 if (type is TypeReference) { |
| 97 return api.types.containsKey(type.typeName) && javaType(type) != 'String'; |
| 98 } |
| 99 return false; |
| 100 } |
| 101 |
| 102 /** |
| 103 * Return true iff the passed [TypeDecl] will represent an array in Java. |
| 104 */ |
| 105 bool isList(TypeDecl type) { |
| 106 return type is TypeList && !isPrimitive(type.itemType); |
| 107 } |
| 108 |
| 109 /** |
| 110 * Return true iff the passed [TypeDecl] will represent a Map in type. |
| 111 */ |
| 112 bool isMap(TypeDecl type) { |
| 113 return type is TypeMap; |
| 114 } |
| 115 |
| 116 /** |
| 117 * Return true iff the passed [TypeDecl] will be represented as Object in Java
. |
| 118 */ |
| 119 bool isObject(TypeDecl type) { |
| 120 String typeStr = javaType(type); |
| 121 return typeStr == 'Object'; |
| 122 } |
| 123 |
| 124 /** |
| 125 * Return true iff the passed [TypeDecl] will represent a primitive Java type. |
| 126 */ |
| 127 bool isPrimitive(TypeDecl type) { |
| 128 if (type is TypeReference) { |
| 129 String typeStr = javaType(type); |
| 130 return typeStr == 'boolean' || typeStr == 'int' || typeStr == 'long'; |
| 131 } |
| 132 return false; |
| 133 } |
| 134 |
| 135 /** |
53 * Convenience method for subclasses for calling docComment. | 136 * Convenience method for subclasses for calling docComment. |
54 */ | 137 */ |
55 void javadocComment(List<dom.Node> docs) { | 138 void javadocComment(List<dom.Node> docs) { |
56 docComment(docs, width: 99, javadocStyle: true); | 139 docComment(docs, width: 99, javadocStyle: true); |
57 } | 140 } |
58 | 141 |
59 /** | 142 /** |
60 * Create a public field, using [callback] to create its contents. | |
61 */ | |
62 void publicField(String fieldName, void callback()) { | |
63 _state.publicFields[fieldName] = collectCode(callback); | |
64 } | |
65 | |
66 /** | |
67 * Create a private field, using [callback] to create its contents. | |
68 */ | |
69 void privateField(String fieldName, void callback()) { | |
70 _state.privateFields[fieldName] = collectCode(callback); | |
71 } | |
72 | |
73 /** | |
74 * Create a constructor, using [callback] to create its contents. | |
75 */ | |
76 void constructor(String name, void callback()) { | |
77 _state.constructors[name] = collectCode(callback); | |
78 } | |
79 | |
80 /** | |
81 * Create a private method, using [callback] to create its contents. | |
82 */ | |
83 void privateMethod(String methodName, void callback()) { | |
84 _state.privateMethods[methodName] = collectCode(callback); | |
85 } | |
86 | |
87 /** | |
88 * Create a public method, using [callback] to create its contents. | |
89 */ | |
90 void publicMethod(String methodName, void callback()) { | |
91 _state.publicMethods[methodName] = collectCode(callback); | |
92 } | |
93 | |
94 /** | |
95 * Execute [callback], collecting any methods that are output using | |
96 * [privateMethod] or [publicMethod], and insert the class (with methods | |
97 * sorted). [header] is the part of the class declaration before the | |
98 * opening brace. | |
99 */ | |
100 void makeClass(String header, void callback()) { | |
101 _CodegenJavaState oldState = _state; | |
102 try { | |
103 _state = new _CodegenJavaState(); | |
104 callback(); | |
105 writeln('$header {'); | |
106 indent(() { | |
107 // fields | |
108 List<String> allFields = _state.publicFields.values.toList(); | |
109 allFields.addAll(_state.privateFields.values.toList()); | |
110 for (String field in allFields) { | |
111 writeln(); | |
112 write(field); | |
113 } | |
114 | |
115 // constructors | |
116 List<String> allConstructors = _state.constructors.values.toList(); | |
117 for (String constructor in allConstructors) { | |
118 writeln(); | |
119 write(constructor); | |
120 } | |
121 | |
122 // methods (ordered by method name) | |
123 List<String> allMethods = | |
124 _valuesSortedByKey(_state.publicMethods).toList(); | |
125 allMethods.addAll(_valuesSortedByKey(_state.privateMethods)); | |
126 for (String method in allMethods) { | |
127 writeln(); | |
128 write(method); | |
129 } | |
130 writeln(); | |
131 }); | |
132 writeln('}'); | |
133 } finally { | |
134 _state = oldState; | |
135 } | |
136 } | |
137 | |
138 /** | |
139 * Return a Java type for the given [TypeObjectField]. | 143 * Return a Java type for the given [TypeObjectField]. |
140 */ | 144 */ |
141 String javaFieldType(TypeObjectField field) { | 145 String javaFieldType(TypeObjectField field) { |
142 return javaType(field.type, field.optional); | 146 return javaType(field.type, field.optional); |
143 } | 147 } |
144 | 148 |
145 /** | 149 /** |
| 150 * Return a suitable representation of [name] as the name of a Java variable. |
| 151 */ |
| 152 String javaName(String name) { |
| 153 if (_variableRenames.containsKey(name)) { |
| 154 return _variableRenames[name]; |
| 155 } |
| 156 return name; |
| 157 } |
| 158 |
| 159 /** |
146 * Convert the given [TypeDecl] to a Java type. | 160 * Convert the given [TypeDecl] to a Java type. |
147 */ | 161 */ |
148 String javaType(TypeDecl type, [bool optional = false]) { | 162 String javaType(TypeDecl type, [bool optional = false]) { |
149 if (type is TypeReference) { | 163 if (type is TypeReference) { |
150 TypeReference resolvedType = resolveTypeReferenceChain(type); | 164 TypeReference resolvedType = resolveTypeReferenceChain(type); |
151 String typeName = resolvedType.typeName; | 165 String typeName = resolvedType.typeName; |
152 if (_typeRenames.containsKey(typeName)) { | 166 if (_typeRenames.containsKey(typeName)) { |
153 typeName = _typeRenames[typeName]; | 167 typeName = _typeRenames[typeName]; |
154 if (optional) { | 168 if (optional) { |
155 if (typeName == 'boolean') { | 169 if (typeName == 'boolean') { |
(...skipping 13 matching lines...) Expand all Loading... |
169 } else if (type is TypeMap) { | 183 } else if (type is TypeMap) { |
170 return 'Map<${javaType(type.keyType)}, ${javaType(type.valueType)}>'; | 184 return 'Map<${javaType(type.keyType)}, ${javaType(type.valueType)}>'; |
171 } else if (type is TypeUnion) { | 185 } else if (type is TypeUnion) { |
172 return 'Object'; | 186 return 'Object'; |
173 } else { | 187 } else { |
174 throw new Exception("Can't make type buildable"); | 188 throw new Exception("Can't make type buildable"); |
175 } | 189 } |
176 } | 190 } |
177 | 191 |
178 /** | 192 /** |
179 * Return true iff the passed [TypeDecl] will represent a primitive Java type. | 193 * Execute [callback], collecting any methods that are output using |
| 194 * [privateMethod] or [publicMethod], and insert the class (with methods |
| 195 * sorted). [header] is the part of the class declaration before the |
| 196 * opening brace. |
180 */ | 197 */ |
181 bool isPrimitive(TypeDecl type) { | 198 void makeClass(String header, void callback()) { |
182 if (type is TypeReference) { | 199 _CodegenJavaState oldState = _state; |
183 String typeStr = javaType(type); | 200 try { |
184 return typeStr == 'boolean' || typeStr == 'int' || typeStr == 'long'; | 201 _state = new _CodegenJavaState(); |
| 202 callback(); |
| 203 writeln('$header {'); |
| 204 indent(() { |
| 205 // fields |
| 206 List<String> allFields = _state.publicFields.values.toList(); |
| 207 allFields.addAll(_state.privateFields.values.toList()); |
| 208 for (String field in allFields) { |
| 209 writeln(); |
| 210 write(field); |
| 211 } |
| 212 |
| 213 // constructors |
| 214 List<String> allConstructors = _state.constructors.values.toList(); |
| 215 for (String constructor in allConstructors) { |
| 216 writeln(); |
| 217 write(constructor); |
| 218 } |
| 219 |
| 220 // methods (ordered by method name) |
| 221 List<String> allMethods = |
| 222 _valuesSortedByKey(_state.publicMethods).toList(); |
| 223 allMethods.addAll(_valuesSortedByKey(_state.privateMethods)); |
| 224 for (String method in allMethods) { |
| 225 writeln(); |
| 226 write(method); |
| 227 } |
| 228 writeln(); |
| 229 }); |
| 230 writeln('}'); |
| 231 } finally { |
| 232 _state = oldState; |
185 } | 233 } |
186 return false; | |
187 } | 234 } |
188 | 235 |
189 /** | 236 /** |
190 * Return true iff the passed [TypeDecl] is a type declared in the spec_input. | 237 * Create a private field, using [callback] to create its contents. |
191 */ | 238 */ |
192 bool isDeclaredInSpec(TypeDecl type) { | 239 void privateField(String fieldName, void callback()) { |
193 // TypeReference resolvedType = super.resolveTypeReferenceChain(type); | 240 _state.privateFields[fieldName] = collectCode(callback); |
194 // if(resolvedType is TypeObject) { | |
195 // return truye; | |
196 // } | |
197 if (type is TypeReference) { | |
198 return api.types.containsKey(type.typeName) && javaType(type) != 'String'; | |
199 } | |
200 return false; | |
201 } | 241 } |
202 | 242 |
203 /** | 243 /** |
204 * Return true iff the passed [TypeDecl] will be represented as Object in Java
. | 244 * Create a private method, using [callback] to create its contents. |
205 */ | 245 */ |
206 bool isObject(TypeDecl type) { | 246 void privateMethod(String methodName, void callback()) { |
207 String typeStr = javaType(type); | 247 _state.privateMethods[methodName] = collectCode(callback); |
208 return typeStr == 'Object'; | |
209 } | 248 } |
210 | 249 |
211 /** | 250 /** |
212 * Return true iff the passed [TypeDecl] will represent an array in Java. | 251 * Create a public field, using [callback] to create its contents. |
213 */ | 252 */ |
214 bool isList(TypeDecl type) { | 253 void publicField(String fieldName, void callback()) { |
215 return type is TypeList && !isPrimitive(type.itemType); | 254 _state.publicFields[fieldName] = collectCode(callback); |
216 } | 255 } |
217 | 256 |
218 /** | 257 /** |
219 * Return true iff the passed [TypeDecl] will represent an array in Java. | 258 * Create a public method, using [callback] to create its contents. |
220 */ | 259 */ |
221 bool isArray(TypeDecl type) { | 260 void publicMethod(String methodName, void callback()) { |
222 return type is TypeList && isPrimitive(type.itemType); | 261 _state.publicMethods[methodName] = collectCode(callback); |
223 } | |
224 | |
225 /** | |
226 * Return true iff the passed [TypeDecl] will represent a Map in type. | |
227 */ | |
228 bool isMap(TypeDecl type) { | |
229 return type is TypeMap; | |
230 } | |
231 | |
232 /** | |
233 * Return a suitable representation of [name] as the name of a Java variable. | |
234 */ | |
235 String javaName(String name) { | |
236 if (_variableRenames.containsKey(name)) { | |
237 return _variableRenames[name]; | |
238 } | |
239 return name; | |
240 } | 262 } |
241 | 263 |
242 @override | 264 @override |
243 TypeReference resolveTypeReferenceChain(TypeReference type) { | 265 TypeReference resolveTypeReferenceChain(TypeReference type) { |
244 TypeDecl typeDecl = super.resolveTypeReferenceChain(type); | 266 TypeDecl typeDecl = super.resolveTypeReferenceChain(type); |
245 if (typeDecl is TypeEnum) { | 267 if (typeDecl is TypeEnum) { |
246 return new TypeReference('String', null); | 268 return new TypeReference('String', null); |
247 } | 269 } |
248 return type; | 270 return type; |
249 } | 271 } |
250 } | 272 } |
251 | 273 |
252 /** | 274 /** |
253 * Iterate through the values in [map] in the order of increasing keys. | |
254 */ | |
255 Iterable<String> _valuesSortedByKey(Map<String, String> map) { | |
256 List<String> keys = map.keys.toList(); | |
257 keys.sort(); | |
258 return keys.map((String key) => map[key]); | |
259 } | |
260 | |
261 /** | |
262 * State used by [CodegenJavaVisitor]. | 275 * State used by [CodegenJavaVisitor]. |
263 */ | 276 */ |
264 class _CodegenJavaState { | 277 class _CodegenJavaState { |
265 /** | 278 /** |
266 * Temporary storage for public methods. | 279 * Temporary storage for public methods. |
267 */ | 280 */ |
268 Map<String, String> publicMethods = <String, String>{}; | 281 Map<String, String> publicMethods = <String, String>{}; |
269 | 282 |
270 /** | 283 /** |
271 * Temporary storage for private methods. | 284 * Temporary storage for private methods. |
272 */ | 285 */ |
273 Map<String, String> privateMethods = <String, String>{}; | 286 Map<String, String> privateMethods = <String, String>{}; |
274 | 287 |
275 /** | 288 /** |
276 * Temporary storage for public fields. | 289 * Temporary storage for public fields. |
277 */ | 290 */ |
278 Map<String, String> publicFields = <String, String>{}; | 291 Map<String, String> publicFields = <String, String>{}; |
279 | 292 |
280 /** | 293 /** |
281 * Temporary storage for private fields. | 294 * Temporary storage for private fields. |
282 */ | 295 */ |
283 Map<String, String> privateFields = <String, String>{}; | 296 Map<String, String> privateFields = <String, String>{}; |
284 | 297 |
285 /** | 298 /** |
286 * Temporary storage for constructors. | 299 * Temporary storage for constructors. |
287 */ | 300 */ |
288 Map<String, String> constructors = <String, String>{}; | 301 Map<String, String> constructors = <String, String>{}; |
289 } | 302 } |
290 | |
291 /** | |
292 * Create a [GeneratedFile] that creates Java code and outputs it to [path]. | |
293 * [path] uses Posix-style path separators regardless of the OS. | |
294 */ | |
295 GeneratedFile javaGeneratedFile(String path, CodegenJavaVisitor | |
296 createVisitor(Api api)) { | |
297 return new GeneratedFile(path, () { | |
298 CodegenJavaVisitor visitor = createVisitor(readApi()); | |
299 return visitor.collectCode(visitor.visitApi); | |
300 }); | |
301 } | |
OLD | NEW |