| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 class CGBlock { | 5 class CGBlock { |
| 6 int _blockType; // Code type of this block | 6 int _blockType; // Code type of this block |
| 7 int _indent; // Number of spaces to prefix for each statement | 7 int _indent; // Number of spaces to prefix for each statement |
| 8 bool _inEach; // This block or any currently active blocks is a | 8 bool _inEach; // This block or any currently active blocks is a |
| 9 // #each. If so then any element marked with a | 9 // #each. If so then any element marked with a |
| 10 // var attribute is repeated therefore the var | 10 // var attribute is repeated therefore the var |
| 11 // is a List type instead of an Element type. | 11 // is a List type instead of an Element type. |
| 12 String _localName; // optional local name for #each or #with |
| 12 List<CGStatement> _stmts; | 13 List<CGStatement> _stmts; |
| 13 int localIndex; // Local variable index (e.g., e0, e1, etc.) | 14 int localIndex; // Local variable index (e.g., e0, e1, etc.) |
| 14 | 15 |
| 15 // Block Types: | 16 // Block Types: |
| 16 static final int CONSTRUCTOR = 0; | 17 static final int CONSTRUCTOR = 0; |
| 17 static final int EACH = 1; | 18 static final int EACH = 1; |
| 18 static final int WITH = 2; | 19 static final int WITH = 2; |
| 19 | 20 |
| 20 CGBlock([this._indent = 4, | 21 CGBlock([this._indent = 4, |
| 21 this._blockType = CGBlock.CONSTRUCTOR, | 22 this._blockType = CGBlock.CONSTRUCTOR, |
| 22 this._inEach = false]) : | 23 this._inEach = false, |
| 24 this._localName = null]) : |
| 23 _stmts = new List<CGStatement>(), localIndex = 0 { | 25 _stmts = new List<CGStatement>(), localIndex = 0 { |
| 24 assert(_blockType >= CGBlock.CONSTRUCTOR && _blockType <= CGBlock.WITH); | 26 assert(_blockType >= CGBlock.CONSTRUCTOR && _blockType <= CGBlock.WITH); |
| 25 } | 27 } |
| 26 | 28 |
| 27 bool get isConstructor() => _blockType == CGBlock.CONSTRUCTOR; | 29 bool get isConstructor() => _blockType == CGBlock.CONSTRUCTOR; |
| 28 bool get isEach() => _blockType == CGBlock.EACH; | 30 bool get isEach() => _blockType == CGBlock.EACH; |
| 29 bool get isWith() => _blockType == CGBlock.WITH; | 31 bool get isWith() => _blockType == CGBlock.WITH; |
| 30 | 32 |
| 33 bool get hasLocalName() => _localName != null; |
| 34 String get localName() => _localName; |
| 35 |
| 31 CGStatement push(var elem, var parentName, [bool exact = false]) { | 36 CGStatement push(var elem, var parentName, [bool exact = false]) { |
| 32 var varName; | 37 var varName; |
| 33 if (elem is TemplateElement && elem.hasVar) { | 38 if (elem is TemplateElement && elem.hasVar) { |
| 34 varName = elem.varName; | 39 varName = elem.varName; |
| 35 } else { | 40 } else { |
| 36 varName = localIndex++; | 41 varName = localIndex++; |
| 37 } | 42 } |
| 38 | 43 |
| 39 CGStatement stmt = new CGStatement(elem, _indent, parentName, varName, | 44 CGStatement stmt = new CGStatement(elem, _indent, parentName, varName, |
| 40 exact, _inEach); | 45 exact, _inEach); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 } | 111 } |
| 107 | 112 |
| 108 return buff.toString(); | 113 return buff.toString(); |
| 109 } | 114 } |
| 110 } | 115 } |
| 111 | 116 |
| 112 class CGStatement { | 117 class CGStatement { |
| 113 bool _exact; // If True not HTML construct instead exact stmt | 118 bool _exact; // If True not HTML construct instead exact stmt |
| 114 bool _repeating; // Stmt in a #each this block or nested block. | 119 bool _repeating; // Stmt in a #each this block or nested block. |
| 115 StringBuffer _buff; | 120 StringBuffer _buff; |
| 116 TemplateElement _elem; | 121 var _elem; |
| 117 int _indent; | 122 int _indent; |
| 118 var parentName; | 123 var parentName; |
| 119 String varName; | 124 String varName; |
| 120 bool _globalVariable; | 125 bool _globalVariable; |
| 121 bool _closed; | 126 bool _closed; |
| 122 | 127 |
| 123 CGStatement(this._elem, this._indent, this.parentName, var varNameOrIndex, | 128 CGStatement(this._elem, this._indent, this.parentName, var varNameOrIndex, |
| 124 [this._exact = false, this._repeating = false]) : | 129 [this._exact = false, this._repeating = false]) : |
| 125 _buff = new StringBuffer(), _closed = false { | 130 _buff = new StringBuffer(), _closed = false { |
| 126 | 131 |
| 127 if (varNameOrIndex is String) { | 132 if (varNameOrIndex is String) { |
| 128 // We have the global variable name | 133 // We have the global variable name |
| 129 varName = varNameOrIndex; | 134 varName = varNameOrIndex; |
| 130 _globalVariable = true; | 135 _globalVariable = true; |
| 131 } else { | 136 } else { |
| 132 // local index generate local variable name. | 137 // local index generate local variable name. |
| 133 varName = "e${varNameOrIndex}"; | 138 varName = "e${varNameOrIndex}"; |
| 134 _globalVariable = false; | 139 _globalVariable = false; |
| 135 } | 140 } |
| 136 } | 141 } |
| 137 | 142 |
| 138 bool get hasGlobalVariable() => _globalVariable; | 143 bool get hasGlobalVariable() => _globalVariable; |
| 139 String get variableName() => varName; | 144 String get variableName() => varName; |
| 140 | 145 |
| 141 String globalDeclaration() { | 146 String globalDeclaration() { |
| 142 if (hasGlobalVariable) { | 147 if (hasGlobalVariable) { |
| 143 String spaces = Codegen.spaces(_indent); | 148 String spaces = Codegen.spaces(_indent); |
| 144 return (_repeating) ? | 149 return (_repeating) ? |
| 145 " List ${varName}; // Repeated elements.\r" : " var ${varName};\r"; | 150 " List ${varName}; // Repeated elements.\n" : " var ${varName};\n"; |
| 146 } | 151 } |
| 147 | 152 |
| 148 return ""; | 153 return ""; |
| 149 } | 154 } |
| 150 | 155 |
| 151 String globalInitializers() { | 156 String globalInitializers() { |
| 152 if (hasGlobalVariable && _repeating) { | 157 if (hasGlobalVariable && _repeating) { |
| 153 return " ${varName} = [];\r"; | 158 return " ${varName} = [];\n"; |
| 154 } | 159 } |
| 155 | 160 |
| 156 return ""; | 161 return ""; |
| 157 } | 162 } |
| 158 | 163 |
| 159 void add(String value) { | 164 void add(String value) { |
| 160 _buff.add(value); | 165 _buff.add(value); |
| 161 } | 166 } |
| 162 | 167 |
| 163 bool get isClosed() => _closed; | 168 bool get isClosed() => _closed; |
| 164 | 169 |
| 165 void close() { | 170 void close() { |
| 166 if (_elem is TemplateElement) { | 171 if (_elem is TemplateElement) { |
| 167 add("</${_elem.tagName}>"); | 172 add("</${_elem.tagName}>"); |
| 168 } | 173 } |
| 169 _closed = true; | 174 _closed = true; |
| 170 } | 175 } |
| 171 | 176 |
| 172 String emitDartStatement() { | 177 String emitDartStatement() { |
| 173 StringBuffer statement = new StringBuffer(); | 178 StringBuffer statement = new StringBuffer(); |
| 174 | 179 |
| 175 String spaces = Codegen.spaces(_indent); | 180 String spaces = Codegen.spaces(_indent); |
| 176 | 181 |
| 177 if (_exact) { | 182 if (_exact) { |
| 178 statement.add("${spaces}${_buff.toString()};\r"); | 183 statement.add("${spaces}${_buff.toString()};\n"); |
| 179 } else { | 184 } else { |
| 180 String localVar = ""; | 185 String localVar = ""; |
| 181 String tmpRepeat; | 186 String tmpRepeat; |
| 182 if (hasGlobalVariable) { | 187 if (hasGlobalVariable) { |
| 183 if (_repeating) { | 188 if (_repeating) { |
| 184 tmpRepeat = "tmp_${varName}"; | 189 tmpRepeat = "tmp_${varName}"; |
| 185 localVar = "var "; | 190 localVar = "var "; |
| 186 } | 191 } |
| 187 } else { | 192 } else { |
| 188 localVar = "var "; | 193 localVar = "var "; |
| 189 } | 194 } |
| 190 | 195 |
| 191 /* Emiting the following code fragment where varName is the attribute | 196 /* Emiting the following code fragment where varName is the attribute |
| 192 value for var= | 197 value for var= |
| 193 | 198 |
| 194 varName = new Element.html('HTML GOES HERE'); | 199 varName = new Element.html('HTML GOES HERE'); |
| 195 parent.elements.add(varName); | 200 parent.elements.add(varName); |
| 196 | 201 |
| 197 for repeating elements in a #each: | 202 for repeating elements in a #each: |
| 198 | 203 |
| 199 var tmp_nnn = new Element.html('HTML GOES HERE'); | 204 var tmp_nnn = new Element.html('HTML GOES HERE'); |
| 200 varName.add(tmp_nnn); | 205 varName.add(tmp_nnn); |
| 201 parent.elements.add(tmp_nnn); | 206 parent.elements.add(tmp_nnn); |
| 202 | 207 |
| 203 for elements w/o var attribute set: | 208 for elements w/o var attribute set: |
| 204 | 209 |
| 205 var eNNN = new Element.html('HTML GOES HERE'); | 210 var eNNN = new Element.html('HTML GOES HERE'); |
| 206 parent.elements.add(eNNN); | 211 parent.elements.add(eNNN); |
| 207 */ | 212 */ |
| 208 if (tmpRepeat == null) { | 213 if (_elem is TemplateCall) { |
| 209 statement.add("${spaces}${localVar}${varName} = new Element.html('"); | 214 // Call template NameEntry2 |
| 215 String cls = _elem.toCall; |
| 216 String params = _elem.params; |
| 217 statement.add("\n${spaces}// Call template ${cls}.\n"); |
| 218 statement.add( |
| 219 "${spaces}${localVar}${varName} = new ${cls}${params};\n"); |
| 220 statement.add( |
| 221 "${spaces}${parentName}.elements.add(${varName}.root);\n"); |
| 210 } else { | 222 } else { |
| 211 statement.add("${spaces}${localVar}${tmpRepeat} = new Element.html('"); | 223 bool isTextNode = _elem is TemplateText; |
| 212 } | 224 String createType = isTextNode ? "Text" : "Element.html"; |
| 213 statement.add(_buff.toString()); | 225 if (tmpRepeat == null) { |
| 226 statement.add("${spaces}${localVar}${varName} = new ${createType}('"); |
| 227 } else { |
| 228 statement.add( |
| 229 "${spaces}${localVar}${tmpRepeat} = new ${createType}('"); |
| 230 } |
| 231 statement.add(isTextNode ? _buff.toString().trim() : _buff.toString()); |
| 214 | 232 |
| 215 if (tmpRepeat == null) { | 233 if (tmpRepeat == null) { |
| 216 statement.add( | 234 statement.add( |
| 217 "');\r${spaces}${parentName}.elements.add(${varName});\r"); | 235 "');\n${spaces}${parentName}.elements.add(${varName});\n"); |
| 218 } else { | 236 } else { |
| 219 statement.add( | 237 statement.add( |
| 220 "');\r${spaces}${parentName}.elements.add(${tmpRepeat});\r"); | 238 "');\n${spaces}${parentName}.elements.add(${tmpRepeat});\n"); |
| 221 statement.add("${spaces}${varName}.add(${tmpRepeat});\r"); | 239 statement.add("${spaces}${varName}.add(${tmpRepeat});\n"); |
| 240 } |
| 222 } | 241 } |
| 223 } | 242 } |
| 224 | 243 |
| 225 return statement.toString(); | 244 return statement.toString(); |
| 226 } | 245 } |
| 227 } | 246 } |
| 228 | 247 |
| 229 class Codegen { | 248 class Codegen { |
| 230 static final String SPACES = " "; | 249 static final String SPACES = " "; |
| 231 static String spaces(int numSpaces) { | 250 static String spaces(int numSpaces) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 243 // the HTML tree looking for a parent template prefix that | 262 // the HTML tree looking for a parent template prefix that |
| 244 // matches the CSS prefix. (more thinking needed). | 263 // matches the CSS prefix. (more thinking needed). |
| 245 static String generate(List<Template> templates, String filename) { | 264 static String generate(List<Template> templates, String filename) { |
| 246 List<String> fileParts = filename.split('.'); | 265 List<String> fileParts = filename.split('.'); |
| 247 assert(fileParts.length == 2); | 266 assert(fileParts.length == 2); |
| 248 filename = fileParts[0]; | 267 filename = fileParts[0]; |
| 249 | 268 |
| 250 StringBuffer buff = new StringBuffer(); | 269 StringBuffer buff = new StringBuffer(); |
| 251 int injectId = 0; // Inject function id | 270 int injectId = 0; // Inject function id |
| 252 | 271 |
| 253 buff.add("// Generated Dart class from HTML template.\r"); | 272 buff.add("// Generated Dart class from HTML template.\n"); |
| 254 buff.add("// DO NOT EDIT.\r\r"); | 273 buff.add("// DO NOT EDIT.\n\n"); |
| 255 | 274 |
| 256 buff.add("String safeHTML(String html) {\r"); | 275 buff.add("String safeHTML(String html) {\n"); |
| 257 buff.add(" // TODO(terry): Escaping for XSS vulnerabilities TBD.\r"); | 276 buff.add(" // TODO(terry): Escaping for XSS vulnerabilities TBD.\n"); |
| 258 buff.add(" return html;\r"); | 277 buff.add(" return html;\n"); |
| 259 buff.add("}\r\r"); | 278 buff.add("}\n\n"); |
| 260 | 279 |
| 261 String addStylesheetFuncName = "add_${filename}_templatesStyles"; | 280 String addStylesheetFuncName = "add_${filename}_templatesStyles"; |
| 262 | 281 |
| 263 for (final template in templates) { | 282 for (final template in templates) { |
| 264 // Emit the template class. | 283 // Emit the template class. |
| 265 TemplateSignature sig = template.signature; | 284 TemplateSignature sig = template.signature; |
| 266 buff.add(_emitClass(sig.name, sig.params, template.content, | 285 buff.add(_emitClass(sig.name, sig.params, template.content, |
| 267 addStylesheetFuncName)); | 286 addStylesheetFuncName)); |
| 268 } | 287 } |
| 269 | 288 |
| 270 // TODO(terry): Stylesheet aggregator should not be global needs to be | 289 // TODO(terry): Stylesheet aggregator should not be global needs to be |
| 271 // bound to this template file not global to the app. | 290 // bound to this template file not global to the app. |
| 272 | 291 |
| 273 // Emit the stylesheet aggregator. | 292 // Emit the stylesheet aggregator. |
| 274 buff.add("\r\r// Inject all templates stylesheet once into the head.\r"); | 293 buff.add("\n\n// Inject all templates stylesheet once into the head.\n"); |
| 275 buff.add("bool ${filename}_stylesheet_added = false;\r"); | 294 buff.add("bool ${filename}_stylesheet_added = false;\n"); |
| 276 buff.add("void ${addStylesheetFuncName}() {\r"); | 295 buff.add("void ${addStylesheetFuncName}() {\n"); |
| 277 buff.add(" if (!${filename}_stylesheet_added) {\r"); | 296 buff.add(" if (!${filename}_stylesheet_added) {\n"); |
| 278 buff.add(" StringBuffer styles = new StringBuffer();\r\r"); | 297 buff.add(" StringBuffer styles = new StringBuffer();\n\n"); |
| 279 | 298 |
| 280 buff.add(" // All templates stylesheet.\r"); | 299 buff.add(" // All templates stylesheet.\n"); |
| 281 | 300 |
| 282 for (final template in templates) { | 301 for (final template in templates) { |
| 283 TemplateSignature sig = template.signature; | 302 TemplateSignature sig = template.signature; |
| 284 buff.add(" styles.add(${sig.name}.stylesheet);\r"); | 303 buff.add(" styles.add(${sig.name}.stylesheet);\n"); |
| 285 } | 304 } |
| 286 | 305 |
| 287 buff.add("\r ${filename}_stylesheet_added = true;\r"); | 306 buff.add("\n ${filename}_stylesheet_added = true;\n"); |
| 288 | 307 |
| 289 buff.add(" document.head.elements.add(new Element.html('<style>" | 308 buff.add(" document.head.elements.add(new Element.html('<style>" |
| 290 "\${styles.toString()}</style>'));\r"); | 309 "\${styles.toString()}</style>'));\n"); |
| 291 buff.add(" }\r"); | 310 buff.add(" }\n"); |
| 292 buff.add("}\r"); | 311 buff.add("}\n"); |
| 293 | 312 |
| 294 return buff.toString(); | 313 return buff.toString(); |
| 295 } | 314 } |
| 296 | 315 |
| 297 static String _emitCSSSelectors(css.Stylesheet stylesheet) { | 316 static String _emitCSSSelectors(css.Stylesheet stylesheet) { |
| 298 if (stylesheet == null) { | 317 if (stylesheet == null) { |
| 299 return ""; | 318 return ""; |
| 300 } | 319 } |
| 301 | 320 |
| 302 List<String> classes = []; | 321 List<String> classes = []; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 325 // Character between 'a'..'z' mapped to 'A'..'Z' | 344 // Character between 'a'..'z' mapped to 'A'..'Z' |
| 326 dartName.add("${part[0].toUpperCase()}${part.substring(1)}"); | 345 dartName.add("${part[0].toUpperCase()}${part.substring(1)}"); |
| 327 } | 346 } |
| 328 dartNames.add(dartName.toString()); | 347 dartNames.add(dartName.toString()); |
| 329 } | 348 } |
| 330 } | 349 } |
| 331 | 350 |
| 332 StringBuffer buff = new StringBuffer(); | 351 StringBuffer buff = new StringBuffer(); |
| 333 if (classes.length > 0) { | 352 if (classes.length > 0) { |
| 334 assert(classes.length == dartNames.length); | 353 assert(classes.length == dartNames.length); |
| 335 buff.add("\r // CSS class selectors for this template.\r"); | 354 buff.add("\n // CSS class selectors for this template.\n"); |
| 336 for (int i = 0; i < classes.length; i++) { | 355 for (int i = 0; i < classes.length; i++) { |
| 337 buff.add( | 356 buff.add( |
| 338 " static String get ${dartNames[i]}() => \"${classes[i]}\";\r"); | 357 " static String get ${dartNames[i]}() => \"${classes[i]}\";\n"); |
| 339 } | 358 } |
| 340 } | 359 } |
| 341 | 360 |
| 342 return buff.toString(); | 361 return buff.toString(); |
| 343 } | 362 } |
| 344 | 363 |
| 345 static String _emitClass(String className, | 364 static String _emitClass(String className, |
| 346 List<Map<Identifier, Identifier>> params, | 365 List<Map<Identifier, Identifier>> params, |
| 347 TemplateContent content, | 366 TemplateContent content, |
| 348 String addStylesheetFuncName) { | 367 String addStylesheetFuncName) { |
| 349 StringBuffer buff = new StringBuffer(); | 368 StringBuffer buff = new StringBuffer(); |
| 350 | 369 |
| 351 // Emit the template class. | 370 // Emit the template class. |
| 352 buff.add("class ${className} {\r"); | 371 buff.add("class ${className} {\n"); |
| 353 | 372 |
| 354 buff.add(" Element _fragment;\r\r"); | 373 buff.add(" Map<String, Object> _scopes;\n"); |
| 374 buff.add(" Element _fragment;\n\n"); |
| 355 | 375 |
| 356 bool anyParams = false; | 376 bool anyParams = false; |
| 357 for (final param in params) { | 377 for (final param in params) { |
| 358 buff.add(" ${param['type']} ${param['name']};\r"); | 378 buff.add(" ${param['type']} ${param['name']};\n"); |
| 359 anyParams = true; | 379 anyParams = true; |
| 360 } | 380 } |
| 361 if (anyParams) buff.add("\r"); | 381 if (anyParams) buff.add("\n"); |
| 362 | 382 |
| 363 ElemCG ecg = new ElemCG(); | 383 ElemCG ecg = new ElemCG(); |
| 364 | 384 |
| 365 ecg.pushBlock(); | 385 if (!ecg.pushBlock()) { |
| 386 world.error("Error at ${content}"); |
| 387 } |
| 366 | 388 |
| 367 // TODO(terry): Only supports singlely rooted need to fix. | 389 var root = content.html.children[0]; |
| 368 ecg.emitConstructHtml(content.html.children[0], "", "_fragment"); | 390 bool firstTime = true; |
| 391 for (var child in root.children) { |
| 392 if (child is TemplateText) { |
| 393 if (!firstTime) { |
| 394 ecg.closeStatement(); |
| 395 } |
| 396 CGStatement stmt = ecg.pushStatement(child, "_fragment"); |
| 397 } |
| 398 ecg.emitConstructHtml(child, "", "_fragment"); |
| 399 firstTime = false; |
| 400 } |
| 369 | 401 |
| 370 // Create all element names marked with var. | 402 // Create all element names marked with var. |
| 371 String decls = ecg.globalDeclarations; | 403 String decls = ecg.globalDeclarations; |
| 372 if (decls.length > 0) { | 404 if (decls.length > 0) { |
| 373 buff.add("\r // Elements bound to a variable:\r"); | 405 buff.add("\n // Elements bound to a variable:\n"); |
| 374 buff.add("${decls}\r"); | 406 buff.add("${decls}\n"); |
| 375 } | 407 } |
| 376 | 408 |
| 377 // Create the constructor. | 409 // Create the constructor. |
| 378 buff.add(" ${className}("); | 410 buff.add(" ${className}("); |
| 379 bool firstParam = true; | 411 bool firstParam = true; |
| 380 for (final param in params) { | 412 for (final param in params) { |
| 381 if (!firstParam) { | 413 if (!firstParam) { |
| 382 buff.add(", "); | 414 buff.add(", "); |
| 383 } | 415 } |
| 384 buff.add("this.${param['name']}"); | 416 buff.add("this.${param['name']}"); |
| 385 firstParam = false; | 417 firstParam = false; |
| 386 } | 418 } |
| 387 buff.add(") {\r"); | 419 buff.add(") : _scopes = new Map<String, Object>() {\n"); |
| 388 | 420 |
| 389 String initializers = ecg.globalInitializers; | 421 String initializers = ecg.globalInitializers; |
| 390 if (initializers.length > 0) { | 422 if (initializers.length > 0) { |
| 391 buff.add(" //Global initializers.\r"); | 423 buff.add(" //Global initializers.\n"); |
| 392 buff.add("${initializers}\r"); | 424 buff.add("${initializers}\n"); |
| 393 } | 425 } |
| 394 | 426 |
| 395 buff.add(" // Insure stylesheet for template exist in the document.\r"); | 427 buff.add(" // Insure stylesheet for template exist in the document.\n"); |
| 396 buff.add(" ${addStylesheetFuncName}();\r\r"); | 428 buff.add(" ${addStylesheetFuncName}();\n\n"); |
| 397 | 429 |
| 398 buff.add(" _fragment = new Element.tag('div');\r"); | 430 buff.add(" _fragment = new DocumentFragment();\n"); |
| 399 | 431 |
| 400 buff.add(ecg.codeBody); // HTML for constructor to build. | 432 buff.add(ecg.codeBody); // HTML for constructor to build. |
| 401 | 433 |
| 402 buff.add(" }\r\r"); // End constructor | 434 buff.add(" }\n\n"); // End constructor |
| 403 | 435 |
| 404 buff.add(" Element get root() => _fragment.nodes.first;\r"); | 436 buff.add(" Element get root() => _fragment;\n"); |
| 405 | 437 |
| 406 // Emit all CSS class selectors: | 438 // Emit all CSS class selectors: |
| 407 buff.add(_emitCSSSelectors(content.css)); | 439 buff.add(_emitCSSSelectors(content.css)); |
| 408 | 440 |
| 409 // Emit the injection functions. | 441 // Emit the injection functions. |
| 410 buff.add("\r // Injection functions:"); | 442 buff.add("\n // Injection functions:"); |
| 411 for (final expr in ecg.expressions) { | 443 for (final expr in ecg.expressions) { |
| 412 buff.add("${expr}"); | 444 buff.add("${expr}"); |
| 413 } | 445 } |
| 414 | 446 |
| 415 buff.add("\r // Each functions:\r"); | 447 buff.add("\n // Each functions:\n"); |
| 416 for (var eachFunc in ecg.eachs) { | 448 for (var eachFunc in ecg.eachs) { |
| 417 buff.add("${eachFunc}\r"); | 449 buff.add("${eachFunc}\n"); |
| 418 } | 450 } |
| 419 | 451 |
| 420 buff.add("\r // With functions:\r"); | 452 buff.add("\n // With functions:\n"); |
| 421 for (var withFunc in ecg.withs) { | 453 for (var withFunc in ecg.withs) { |
| 422 buff.add("${withFunc}\r"); | 454 buff.add("${withFunc}\n"); |
| 423 } | 455 } |
| 424 | 456 |
| 425 buff.add("\r // CSS for this template.\r"); | 457 buff.add("\n // CSS for this template.\n"); |
| 426 buff.add(" static final String stylesheet = "); | 458 buff.add(" static final String stylesheet = "); |
| 427 | 459 |
| 428 if (content.css != null) { | 460 if (content.css != null) { |
| 429 buff.add("\'\'\'\r ${content.css.toString()}\r"); | 461 buff.add("\'\'\'\n ${content.css.toString()}\n"); |
| 430 buff.add(" \'\'\';\r\r"); | 462 buff.add(" \'\'\';\n\n"); |
| 431 | 463 |
| 432 // TODO(terry): Emit all known selectors for this template. | 464 // TODO(terry): Emit all known selectors for this template. |
| 433 buff.add(" // Stylesheet class selectors:\r"); | 465 buff.add(" // Stylesheet class selectors:\n"); |
| 434 } else { | 466 } else { |
| 435 buff.add("\"\";\r"); | 467 buff.add("\"\";\n"); |
| 436 } | 468 } |
| 437 | 469 |
| 438 buff.add("}\r"); // End class | 470 buff.add("}\n"); // End class |
| 439 | 471 |
| 440 return buff.toString(); | 472 return buff.toString(); |
| 441 } | 473 } |
| 442 } | 474 } |
| 443 | 475 |
| 444 class ElemCG { | 476 class ElemCG { |
| 445 // List of identifiers and quoted strings (single and double quoted). | 477 // List of identifiers and quoted strings (single and double quoted). |
| 446 var identRe = const RegExp( | 478 var identRe = const RegExp( |
| 447 "\s*('\"\\'\\\"[^'\"\\'\\\"]+'\"\\'\\\"|[_A-Za-z][_A-Za-z0-9]*)"); | 479 "\s*('\"\\'\\\"[^'\"\\'\\\"]+'\"\\'\\\"|[_A-Za-z][_A-Za-z0-9]*)"); |
| 448 | 480 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 461 withs = [], | 493 withs = [], |
| 462 _cgBlocks = [], | 494 _cgBlocks = [], |
| 463 _globalDecls = new StringBuffer(), | 495 _globalDecls = new StringBuffer(), |
| 464 _globalInits = new StringBuffer(); | 496 _globalInits = new StringBuffer(); |
| 465 | 497 |
| 466 bool get isLastBlockConstructor() { | 498 bool get isLastBlockConstructor() { |
| 467 CGBlock block = _cgBlocks.last(); | 499 CGBlock block = _cgBlocks.last(); |
| 468 return block.isConstructor; | 500 return block.isConstructor; |
| 469 } | 501 } |
| 470 | 502 |
| 503 List<String> activeBlocksLocalNames() { |
| 504 List<String> result = []; |
| 505 |
| 506 for (final CGBlock block in _cgBlocks) { |
| 507 if (block.isEach || block.isWith) { |
| 508 if (block.hasLocalName) { |
| 509 result.add(block.localName); |
| 510 } |
| 511 } |
| 512 } |
| 513 |
| 514 return result; |
| 515 } |
| 516 |
| 517 /** |
| 518 * Active block with this localName. |
| 519 */ |
| 520 bool matchBlocksLocalName(String name) { |
| 521 for (final CGBlock block in _cgBlocks) { |
| 522 if (block.isEach || block.isWith) { |
| 523 if (block.hasLocalName && block.localName == name) { |
| 524 return true; |
| 525 } |
| 526 } |
| 527 } |
| 528 |
| 529 return false; |
| 530 } |
| 531 |
| 532 /** |
| 533 * Any active blocks? |
| 534 */ |
| 535 bool isNestedBlock() { |
| 536 for (final CGBlock block in _cgBlocks) { |
| 537 if (block.isEach || block.isWith) { |
| 538 return true; |
| 539 } |
| 540 } |
| 541 |
| 542 return false; |
| 543 } |
| 544 |
| 545 /** |
| 546 * Any active blocks with localName? |
| 547 */ |
| 548 bool isNestedNamedBlock() { |
| 549 for (final CGBlock block in _cgBlocks) { |
| 550 if ((block.isEach || block.isWith) && block.hasLocalName) { |
| 551 return true; |
| 552 } |
| 553 } |
| 554 |
| 555 return false; |
| 556 } |
| 557 |
| 471 // Any current active #each blocks. | 558 // Any current active #each blocks. |
| 472 bool anyEachBlocks(int blockToCreateType) { | 559 bool anyEachBlocks(int blockToCreateType) { |
| 473 bool result = blockToCreateType == CGBlock.EACH; | 560 bool result = blockToCreateType == CGBlock.EACH; |
| 474 | 561 |
| 475 for (final CGBlock block in _cgBlocks) { | 562 for (final CGBlock block in _cgBlocks) { |
| 476 if (block.isEach) { | 563 if (block.isEach) { |
| 477 result = result || true; | 564 result = result || true; |
| 478 } | 565 } |
| 479 } | 566 } |
| 480 | 567 |
| 481 return result; | 568 return result; |
| 482 } | 569 } |
| 483 | 570 |
| 484 void pushBlock([int indent = 4, int blockType = CGBlock.CONSTRUCTOR]) { | 571 bool pushBlock([int indent = 4, int blockType = CGBlock.CONSTRUCTOR, |
| 572 String itemName = null]) { |
| 485 closeStatement(); | 573 closeStatement(); |
| 486 _cgBlocks.add(new CGBlock(indent, blockType, anyEachBlocks(blockType))); | 574 if (itemName != null && matchBlocksLocalName(itemName)) { |
| 575 world.error("Active block already exist with local name: ${itemName}."); |
| 576 return false; |
| 577 } else if (itemName == null && this.isNestedBlock()) { |
| 578 world.error(''' |
| 579 Nested #each or #with must have a localName; |
| 580 \n #each list [localName]\n #with object [localName]'''); |
| 581 return false; |
| 582 } |
| 583 _cgBlocks.add( |
| 584 new CGBlock(indent, blockType, anyEachBlocks(blockType), itemName)); |
| 585 |
| 586 return true; |
| 487 } | 587 } |
| 488 | 588 |
| 489 void popBlock() { | 589 void popBlock() { |
| 490 _globalDecls.add(lastBlock.globalDeclarations); | 590 _globalDecls.add(lastBlock.globalDeclarations); |
| 491 _globalInits.add(lastBlock.globalInitializers); | 591 _globalInits.add(lastBlock.globalInitializers); |
| 492 _cgBlocks.removeLast(); | 592 _cgBlocks.removeLast(); |
| 493 } | 593 } |
| 494 | 594 |
| 495 CGStatement pushStatement(var elem, var parentName) { | 595 CGStatement pushStatement(var elem, var parentName) { |
| 496 return lastBlock.push(elem, parentName, false); | 596 return lastBlock.push(elem, parentName, false); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 561 closeStatement(); | 661 closeStatement(); |
| 562 } else { | 662 } else { |
| 563 closeStatement(); | 663 closeStatement(); |
| 564 emitConstructHtml(childElem, scopeName, prevParent); | 664 emitConstructHtml(childElem, scopeName, prevParent); |
| 565 closeStatement(); | 665 closeStatement(); |
| 566 } | 666 } |
| 567 } else { | 667 } else { |
| 568 emitElement(childElem, scopeName, parentVarOrIdx); | 668 emitElement(childElem, scopeName, parentVarOrIdx); |
| 569 } | 669 } |
| 570 } | 670 } |
| 671 |
| 672 // Close this tag. |
| 673 closeStatement(); |
| 571 } else if (elem is TemplateText) { | 674 } else if (elem is TemplateText) { |
| 572 add("${elem.value}"); | 675 add("${elem.value}"); |
| 573 } else if (elem is TemplateExpression) { | 676 } else if (elem is TemplateExpression) { |
| 574 emitExpressions(elem, scopeName); | 677 emitExpressions(elem, scopeName); |
| 575 } else if (elem is TemplateEachCommand) { | 678 } else if (elem is TemplateEachCommand) { |
| 576 // Signal to caller new block coming in, returns "each_" prefix | 679 // Signal to caller new block coming in, returns "each_" prefix |
| 577 emitEach(elem, "List", elem.listName.name, "parent", immediateNestedEach); | 680 emitEach(elem, "List", elem.listName.name, "parent", immediateNestedEach, |
| 681 elem.hasLoopItem ? elem.loopItem.name : null); |
| 578 } else if (elem is TemplateWithCommand) { | 682 } else if (elem is TemplateWithCommand) { |
| 579 // Signal to caller new block coming in, returns "each_" prefix | 683 // Signal to caller new block coming in, returns "each_" prefix |
| 580 emitWith(elem, "var", elem.objectName.name, "parent"); | 684 emitWith(elem, "var", elem.objectName.name, "parent", |
| 685 elem.hasBlockItem ? elem.blockItem.name : null); |
| 686 } else if (elem is TemplateCall) { |
| 687 emitCall(elem, parentVarOrIdx); |
| 581 } | 688 } |
| 582 } | 689 } |
| 583 | 690 |
| 584 // TODO(terry): Hack prefixing all names with "${scopeName}." but don't touch | 691 // TODO(terry): Hack prefixing all names with "${scopeName}." but don't touch |
| 585 // quoted strings. | 692 // quoted strings. |
| 586 String _resolveNames(String expr, String prefixPart) { | 693 String _resolveNames(String expr, String prefixPart) { |
| 587 StringBuffer newExpr = new StringBuffer(); | 694 StringBuffer newExpr = new StringBuffer(); |
| 588 Iterable<Match> matches = identRe.allMatches(expr); | 695 Iterable<Match> matches = identRe.allMatches(expr); |
| 589 | 696 |
| 590 int lastIdx = 0; | 697 int lastIdx = 0; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 624 * control structures (with, each, if, etc.). We could | 731 * control structures (with, each, if, etc.). We could |
| 625 * synthesize a root node and create all the top-level nodes | 732 * synthesize a root node and create all the top-level nodes |
| 626 * under the root node with one innerHTML. | 733 * under the root node with one innerHTML. |
| 627 */ | 734 */ |
| 628 void emitConstructHtml(var elem, | 735 void emitConstructHtml(var elem, |
| 629 [String scopeName = "", | 736 [String scopeName = "", |
| 630 String parentName = "parent", | 737 String parentName = "parent", |
| 631 var varIndex = 0, | 738 var varIndex = 0, |
| 632 bool immediateNestedEach = false]) { | 739 bool immediateNestedEach = false]) { |
| 633 if (elem is TemplateElement) { | 740 if (elem is TemplateElement) { |
| 634 // Never look at the root node (fragment) get it's children. | |
| 635 if (elem.isFragment) { | |
| 636 elem = elem.children[0]; | |
| 637 } | |
| 638 | |
| 639 CGStatement stmt = pushStatement(elem, parentName); | 741 CGStatement stmt = pushStatement(elem, parentName); |
| 640 emitElement(elem, scopeName, stmt.hasGlobalVariable ? | 742 emitElement(elem, scopeName, stmt.hasGlobalVariable ? |
| 641 stmt.variableName : varIndex); | 743 stmt.variableName : varIndex); |
| 642 } else { | 744 } else { |
| 643 emitElement(elem, scopeName, varIndex, immediateNestedEach); | 745 emitElement(elem, scopeName, varIndex, immediateNestedEach); |
| 644 } | 746 } |
| 645 } | 747 } |
| 646 | 748 |
| 647 /* Any references to products.sales needs to be remaped to item.sales | 749 /* Any references to products.sales needs to be remaped to item.sales |
| 648 * for now it's a hack look for first dot and replace with item. | 750 * for now it's a hack look for first dot and replace with item. |
| 649 */ | 751 */ |
| 650 String eachIterNameToItem(String iterName) { | 752 String eachIterNameToItem(String iterName) { |
| 651 String newName = iterName; | 753 String newName = iterName; |
| 652 var dotForIter = iterName.indexOf('.'); | 754 var dotForIter = iterName.indexOf('.'); |
| 653 if (dotForIter >= 0) { | 755 if (dotForIter >= 0) { |
| 654 newName = "item${iterName.substring(dotForIter)}"; | 756 newName = "_item${iterName.substring(dotForIter)}"; |
| 655 } | 757 } |
| 656 | 758 |
| 657 return newName; | 759 return newName; |
| 658 } | 760 } |
| 659 | 761 |
| 660 emitExpressions(TemplateExpression elem, String scopeName) { | 762 emitExpressions(TemplateExpression elem, String scopeName) { |
| 661 StringBuffer func = new StringBuffer(); | 763 StringBuffer func = new StringBuffer(); |
| 662 | 764 |
| 663 String newExpr = elem.expression; | 765 String newExpr = elem.expression; |
| 664 if (scopeName.length > 0) { | 766 bool anyNesting = isNestedNamedBlock(); |
| 767 if (scopeName.length > 0 && !anyNesting) { |
| 665 // In a block #command need the scope passed in. | 768 // In a block #command need the scope passed in. |
| 666 add("\$\{inject_${expressions.length}(item)\}"); | 769 add("\$\{inject_${expressions.length}(_item)\}"); |
| 667 func.add("\r String inject_${expressions.length}(var item) {\r"); | 770 func.add("\n String inject_${expressions.length}(var _item) {\n"); |
| 668 // Escape all single-quotes, this expression is embedded as a string | 771 // Escape all single-quotes, this expression is embedded as a string |
| 669 // parameter for the call to safeHTML. | 772 // parameter for the call to safeHTML. |
| 670 newExpr = _resolveNames(newExpr.replaceAll("'", "\\'"), "item"); | 773 newExpr = _resolveNames(newExpr.replaceAll("'", "\\'"), "_item"); |
| 671 } else { | 774 } else { |
| 672 // Not in a block #command item isn't passed in. | 775 // Not in a block #command item isn't passed in. |
| 673 add("\$\{inject_${expressions.length}()\}"); | 776 add("\$\{inject_${expressions.length}()\}"); |
| 674 func.add("\r String inject_${expressions.length}() {\r"); | 777 func.add("\n String inject_${expressions.length}() {\n"); |
| 778 |
| 779 if (anyNesting) { |
| 780 func.add(defineScopes()); |
| 781 } |
| 675 } | 782 } |
| 676 | 783 |
| 677 func.add(" return safeHTML('\$\{${newExpr}\}');\r"); | 784 // Construct the active scope names for name resolution. |
| 678 func.add(" }\r"); | 785 |
| 786 func.add(" return safeHTML('\$\{${newExpr}\}');\n"); |
| 787 func.add(" }\n"); |
| 679 | 788 |
| 680 expressions.add(func.toString()); | 789 expressions.add(func.toString()); |
| 681 } | 790 } |
| 791 |
| 792 emitCall(TemplateCall elem, String scopeName) { |
| 793 pushStatement(elem, scopeName); |
| 794 } |
| 795 |
| 682 emitEach(TemplateEachCommand elem, String iterType, String iterName, | 796 emitEach(TemplateEachCommand elem, String iterType, String iterName, |
| 683 var parentVarOrIdx, bool nestedImmediateEach) { | 797 var parentVarOrIdx, bool nestedImmediateEach, [String itemName = null]) { |
| 684 TemplateDocument docFrag = elem.documentFragment; | 798 TemplateDocument docFrag = elem.documentFragment; |
| 685 | 799 |
| 686 int eachIndex = eachs.length; | 800 int eachIndex = eachs.length; |
| 687 eachs.add(""); | 801 eachs.add(""); |
| 688 | 802 |
| 689 StringBuffer funcBuff = new StringBuffer(); | 803 StringBuffer funcBuff = new StringBuffer(); |
| 690 // Prepare function call "each_N(iterName," parent param computed later. | 804 // Prepare function call "each_N(iterName," parent param computed later. |
| 691 String funcName = "each_${eachIndex}"; | 805 String funcName = "each_${eachIndex}"; |
| 692 | 806 |
| 693 funcBuff.add(" ${funcName}(${iterType} items, Element parent) {\r"); | 807 funcBuff.add(" ${funcName}(${iterType} items, Element parent) {\n"); |
| 694 funcBuff.add(" for (var item in items) {\r"); | |
| 695 | 808 |
| 696 pushBlock(6, CGBlock.EACH); | 809 String paramName = injectParamName(itemName); |
| 810 if (paramName == null) { |
| 811 world.error("Use a different local name; ${itemName} is reserved."); |
| 812 } |
| 813 funcBuff.add(" for (var ${paramName} in items) {\n"); |
| 814 |
| 815 if (!pushBlock(6, CGBlock.EACH, itemName)) { |
| 816 world.error("Error at ${elem}"); |
| 817 } |
| 818 |
| 819 addScope(6, funcBuff, itemName); |
| 697 | 820 |
| 698 TemplateElement docFragChild = docFrag.children[0]; | 821 TemplateElement docFragChild = docFrag.children[0]; |
| 699 var children = docFragChild.isFragment ? | 822 var children = docFragChild.isFragment ? |
| 700 docFragChild.children : docFrag.children; | 823 docFragChild.children : docFrag.children; |
| 701 for (var child in children) { | 824 for (var child in children) { |
| 702 // If any immediate children of the parent #each is an #each then | 825 // If any immediate children of the parent #each is an #each then |
| 703 // so we need to pass the outer #each parent not the last statement's | 826 // so we need to pass the outer #each parent not the last statement's |
| 704 // variableName when calling the nested #each. | 827 // variableName when calling the nested #each. |
| 705 bool eachChild = (child is TemplateEachCommand); | 828 bool eachChild = (child is TemplateEachCommand); |
| 706 emitConstructHtml(child, iterName, parentVarOrIdx, 0, eachChild); | 829 emitConstructHtml(child, iterName, parentVarOrIdx, 0, eachChild); |
| 707 } | 830 } |
| 708 | 831 |
| 709 funcBuff.add(codeBody); | 832 funcBuff.add(codeBody); |
| 710 | 833 |
| 834 removeScope(6, funcBuff, itemName); |
| 835 |
| 711 popBlock(); | 836 popBlock(); |
| 712 | 837 |
| 713 funcBuff.add(" }\r"); | 838 funcBuff.add(" }\n"); |
| 714 funcBuff.add(" }\r"); | 839 funcBuff.add(" }\n"); |
| 715 | 840 |
| 716 eachs[eachIndex] = funcBuff.toString(); | 841 eachs[eachIndex] = funcBuff.toString(); |
| 717 | 842 |
| 718 // If nested each then we want to pass the parent otherwise we'll use the | 843 // If nested each then we want to pass the parent otherwise we'll use the |
| 719 // varName. | 844 // varName. |
| 720 var varName = nestedImmediateEach ? "parent" : lastBlock.last.variableName; | 845 var varName = nestedImmediateEach ? "parent" : lastBlock.last.variableName; |
| 721 | 846 |
| 722 pushExactStatement(elem, parentVarOrIdx); | 847 pushExactStatement(elem, parentVarOrIdx); |
| 723 | 848 |
| 724 // Setup call to each func as "each_n(xxxxx, " the parent param is filled | 849 // Setup call to each func as "each_n(xxxxx, " the parent param is filled |
| 725 // in later when we known the parent variable. | 850 // in later when we known the parent variable. |
| 726 add("${funcName}(${eachIterNameToItem(iterName)}, ${varName})"); | 851 String eachParam = |
| 727 } | 852 (itemName == null) ? eachIterNameToItem(iterName) : iterName; |
| 853 add("${funcName}(${eachParam}, ${varName})"); |
| 854 } |
| 728 | 855 |
| 729 emitWith(TemplateWithCommand elem, String withType, String withName, | 856 emitWith(TemplateWithCommand elem, String withType, String withName, |
| 730 var parentVarIndex) { | 857 var parentVarIndex, [String itemName = null]) { |
| 731 TemplateDocument docFrag = elem.documentFragment; | 858 TemplateDocument docFrag = elem.documentFragment; |
| 732 | 859 |
| 733 int withIndex = withs.length; | 860 int withIndex = withs.length; |
| 734 withs.add(""); | 861 withs.add(""); |
| 735 | 862 |
| 736 StringBuffer funcBuff = new StringBuffer(); | 863 StringBuffer funcBuff = new StringBuffer(); |
| 737 // Prepare function call "each_N(iterName," parent param computed later. | 864 // Prepare function call "each_N(iterName," parent param computed later. |
| 738 String funcName = "with_${withIndex}"; | 865 String funcName = "with_${withIndex}"; |
| 739 | 866 |
| 740 funcBuff.add(" ${funcName}(${withType} item, Element parent) {\r"); | 867 String paramName = injectParamName(itemName); |
| 868 if (paramName == null) { |
| 869 world.error("Use a different local name; ${itemName} is reserved."); |
| 870 } |
| 871 funcBuff.add(" ${funcName}(${withType} ${paramName}, Element parent) {\n"); |
| 741 | 872 |
| 742 pushBlock(CGBlock.WITH); | 873 if (!pushBlock(4, CGBlock.WITH, itemName)) { |
| 874 world.error("Error at ${elem}"); |
| 875 } |
| 743 | 876 |
| 744 TemplateElement docFragChild = docFrag.children[0]; | 877 TemplateElement docFragChild = docFrag.children[0]; |
| 745 var children = docFragChild.isFragment ? | 878 var children = docFragChild.isFragment ? |
| 746 docFragChild.children : docFrag.children; | 879 docFragChild.children : docFrag.children; |
| 747 for (var child in children) { | 880 for (var child in children) { |
| 748 emitConstructHtml(child, withName, "parent"); | 881 emitConstructHtml(child, withName, "parent"); |
| 749 } | 882 } |
| 750 | 883 |
| 884 addScope(4, funcBuff, itemName); |
| 751 funcBuff.add(codeBody); | 885 funcBuff.add(codeBody); |
| 886 removeScope(4, funcBuff, itemName); |
| 752 | 887 |
| 753 popBlock(); | 888 popBlock(); |
| 754 | 889 |
| 755 funcBuff.add(" }\r"); | 890 funcBuff.add(" }\n"); |
| 756 | 891 |
| 757 withs[withIndex] = funcBuff.toString(); | 892 withs[withIndex] = funcBuff.toString(); |
| 758 | 893 |
| 759 var varName = lastBlock.last.variableName; | 894 var varName = lastBlock.last.variableName; |
| 760 | 895 |
| 761 pushExactStatement(elem, parentVarIndex); | 896 pushExactStatement(elem, parentVarIndex); |
| 762 | 897 |
| 763 // Setup call to each func as "each_n(xxxxx, " the parent param is filled | 898 // Setup call to each func as "each_n(xxxxx, " the parent param is filled |
| 764 // in later when we known the parent variable. | 899 // in later when we known the parent variable. |
| 765 add("${funcName}(${withName}, ${varName})"); | 900 add("${funcName}(${withName}, ${varName})"); |
| 766 } | 901 } |
| 902 |
| 903 String injectParamName(String name) { |
| 904 // Local name _item is reserved. |
| 905 if (name != null && name == "_item") { |
| 906 return null; // Local name is not valid. |
| 907 } |
| 908 |
| 909 return (name == null) ? "_item" : name; |
| 910 } |
| 911 |
| 912 addScope(int indent, StringBuffer buff, String item) { |
| 913 String spaces = Codegen.spaces(indent); |
| 914 |
| 915 if (item == null) { |
| 916 item = "_item"; |
| 917 } |
| 918 buff.add("${spaces}_scopes[\"${item}\"] = ${item};\n"); |
| 919 } |
| 920 |
| 921 removeScope(int indent, StringBuffer buff, String item) { |
| 922 String spaces = Codegen.spaces(indent); |
| 923 |
| 924 if (item == null) { |
| 925 item = "_item"; |
| 926 } |
| 927 buff.add("${spaces}_scopes.remove(\"${item}\");\n"); |
| 928 } |
| 929 |
| 930 String defineScopes() { |
| 931 StringBuffer buff = new StringBuffer(); |
| 932 |
| 933 // Construct the active scope names for name resolution. |
| 934 List<String> names = activeBlocksLocalNames(); |
| 935 if (names.length > 0) { |
| 936 buff.add(" // Local scoped block names.\n"); |
| 937 for (String name in names) { |
| 938 buff.add(" var ${name} = _scopes[\"${name}\"];\n"); |
| 939 } |
| 940 buff.add("\n"); |
| 941 } |
| 942 |
| 943 return buff.toString(); |
| 944 } |
| 945 |
| 767 } | 946 } |
| OLD | NEW |