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 /** | 5 /** |
6 * Top level generator object for writing code and keeping track of | 6 * Top level generator object for writing code and keeping track of |
7 * dependencies. | 7 * dependencies. |
8 * | 8 * |
9 * Should have two compilation models, but only one implemented so far. | 9 * Should have two compilation models, but only one implemented so far. |
10 * | 10 * |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 } else { | 353 } else { |
354 writer.writeln('var ${global.name} = ${global.exp.code};'); | 354 writer.writeln('var ${global.name} = ${global.exp.code};'); |
355 } | 355 } |
356 } | 356 } |
357 } | 357 } |
358 | 358 |
359 /** Order a list of values in a Map by SourceSpan, then by name. */ | 359 /** Order a list of values in a Map by SourceSpan, then by name. */ |
360 List _orderValues(Map map) { | 360 List _orderValues(Map map) { |
361 // TODO(jmesserly): should we copy the list? | 361 // TODO(jmesserly): should we copy the list? |
362 // Right now, the Maps are returning a copy already. | 362 // Right now, the Maps are returning a copy already. |
363 List values = map.getValues(); | 363 final values = map.getValues(); |
364 values.sort(_compareMembers); | 364 values.sort(_compareMembers); |
365 return values; | 365 return values; |
366 } | 366 } |
367 | 367 |
368 int _compareMembers(x, y) { | 368 int _compareMembers(x, y) { |
369 if (x.span != null && y.span != null) { | 369 if (x.span != null && y.span != null) { |
370 // First compare by source span. | 370 // First compare by source span. |
371 int spans = x.span.compareTo(y.span); | 371 int spans = x.span.compareTo(y.span); |
372 if (spans != 0) return spans; | 372 if (spans != 0) return spans; |
373 } | 373 } |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
565 : writer = new CodeWriter(), needsThis = false { | 565 : writer = new CodeWriter(), needsThis = false { |
566 if (enclosingMethod != null) { | 566 if (enclosingMethod != null) { |
567 _scope = new BlockScope(this, enclosingMethod._scope); | 567 _scope = new BlockScope(this, enclosingMethod._scope); |
568 captures = new Set(); | 568 captures = new Set(); |
569 } else { | 569 } else { |
570 _scope = new BlockScope(this, null); | 570 _scope = new BlockScope(this, null); |
571 } | 571 } |
572 // For named lambdas, add the name to this scope so we can call it | 572 // For named lambdas, add the name to this scope so we can call it |
573 // recursively. | 573 // recursively. |
574 if (enclosingMethod != null && method.name != '') { | 574 if (enclosingMethod != null && method.name != '') { |
575 MethodMember m = method; // lambdas must be MethodMembers | 575 _scope.create(method.name, method.functionType, method.definition); |
576 _scope.create(m.name, m.functionType, m.definition); | |
577 } | 576 } |
578 _usedTemps = new Set(); | 577 _usedTemps = new Set(); |
579 _freeTemps = []; | 578 _freeTemps = []; |
580 } | 579 } |
581 | 580 |
582 // TODO(jimhug): Where does this really belong? | 581 // TODO(jimhug): Where does this really belong? |
583 MemberSet findMembers(String name) { | 582 MemberSet findMembers(String name) { |
584 return method.library._findMembers(name); | 583 return method.library._findMembers(name); |
585 } | 584 } |
586 | 585 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
709 defWriter.exitBlock('}'); | 708 defWriter.exitBlock('}'); |
710 } | 709 } |
711 if (method.isConstructor && method.constructorName != '') { | 710 if (method.isConstructor && method.constructorName != '') { |
712 defWriter.writeln( | 711 defWriter.writeln( |
713 '${method.declaringType.jsname}.${method.constructorName}\$ctor.prototyp
e = ' + | 712 '${method.declaringType.jsname}.${method.constructorName}\$ctor.prototyp
e = ' + |
714 '${method.declaringType.jsname}.prototype;'); | 713 '${method.declaringType.jsname}.prototype;'); |
715 } | 714 } |
716 | 715 |
717 _provideOptionalParamInfo(defWriter); | 716 _provideOptionalParamInfo(defWriter); |
718 | 717 |
719 if (method is MethodMember) { | 718 if (method is MethodMember && method._providePropertySyntax) { |
720 MethodMember m = method; | 719 defWriter.enterBlock( |
721 if (m._providePropertySyntax) { | 720 '${method.declaringType.jsname}.prototype.get\$${method.jsname} = functi
on() {'); |
722 defWriter.enterBlock('${m.declaringType.jsname}.prototype' | 721 // TODO(jimhug): Bind not availabe in Safari, need fallback. |
723 + '.get\$${m.jsname} = function() {'); | 722 defWriter.writeln( |
724 // TODO(jimhug): Bind not available in older Safari, need fallback? | 723 'return ${method.declaringType.jsname}.prototype.${method.jsname}.bind(t
his);'); |
725 defWriter.writeln('return ${m.declaringType.jsname}.prototype.' | 724 defWriter.exitBlock('}'); |
726 + '${m.jsname}.bind(this);'); | |
727 defWriter.exitBlock('}'); | |
728 | 725 |
729 if (m._provideFieldSyntax) { | 726 if (method._provideFieldSyntax) { |
730 world.internalError('bound m accessed with field syntax'); | 727 world.internalError('bound method accessed with field syntax'); |
731 } | |
732 } | 728 } |
733 } | 729 } |
734 } | 730 } |
735 | 731 |
736 /** | 732 /** |
737 * Generates information about the default/named arguments into the JS code. | 733 * Generates information about the default/named arguments into the JS code. |
738 * Only methods that are passed as bound methods to "var" need this. It is | 734 * Only methods that are passed as bound methods to "var" need this. It is |
739 * generated to support run time stub creation. | 735 * generated to support run time stub creation. |
740 */ | 736 */ |
741 _provideOptionalParamInfo(CodeWriter defWriter) { | 737 _provideOptionalParamInfo(CodeWriter defWriter) { |
742 if (method is MethodMember) { | 738 if (method is MethodMember && method._provideOptionalParamInfo) { |
743 MethodMember meth = method; | 739 var optNames = []; |
744 if (meth._provideOptionalParamInfo) { | 740 var optValues = []; |
745 var optNames = []; | 741 method.genParameterValues(); |
746 var optValues = []; | 742 for (var param in method.parameters) { |
747 meth.genParameterValues(); | 743 if (param.isOptional) { |
748 for (var param in meth.parameters) { | 744 optNames.add(param.name); |
749 if (param.isOptional) { | 745 optValues.add(_escapeString(param.value.code)); |
750 optNames.add(param.name); | 746 } |
751 optValues.add(_escapeString(param.value.code)); | 747 } |
| 748 if (optNames.length > 0) { |
| 749 // TODO(jmesserly): the logic for how to refer to |
| 750 // static/instance/top-level members is duplicated all over the place. |
| 751 // Badly needs cleanup. |
| 752 var start = ''; |
| 753 if (method.isStatic) { |
| 754 if (!method.declaringType.isTop) { |
| 755 start = method.declaringType.jsname + '.'; |
752 } | 756 } |
| 757 } else { |
| 758 start = method.declaringType.jsname + '.prototype.'; |
753 } | 759 } |
754 if (optNames.length > 0) { | |
755 // TODO(jmesserly): the logic for how to refer to | |
756 // static/instance/top-level members is duplicated all over the place. | |
757 // Badly needs cleanup. | |
758 var start = ''; | |
759 if (meth.isStatic) { | |
760 if (!meth.declaringType.isTop) { | |
761 start = meth.declaringType.jsname + '.'; | |
762 } | |
763 } else { | |
764 start = meth.declaringType.jsname + '.prototype.'; | |
765 } | |
766 | 760 |
767 optNames.addAll(optValues); | 761 optNames.addAll(optValues); |
768 var optional = "['" + Strings.join(optNames, "', '") + "']"; | 762 var optional = "['" + Strings.join(optNames, "', '") + "']"; |
769 defWriter.writeln('${start}${meth.jsname}.\$optional = $optional'); | 763 defWriter.writeln('${start}${method.jsname}.\$optional = $optional'); |
770 } | |
771 } | 764 } |
772 } | 765 } |
773 } | 766 } |
774 | 767 |
775 writeBody() { | 768 writeBody() { |
776 var initializers = null; | 769 var initializers = null; |
777 var initializedFields = null; // to check that final fields are initialized | 770 var initializedFields = null; // to check that final fields are initialized |
778 if (method.isConstructor) { | 771 if (method.isConstructor) { |
779 initializers = []; | 772 initializers = []; |
780 initializedFields = new Set(); | 773 initializedFields = new Set(); |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
967 */ | 960 */ |
968 static String _escapeString(String text) { | 961 static String _escapeString(String text) { |
969 // TODO(jimhug): Use a regex for performance here. | 962 // TODO(jimhug): Use a regex for performance here. |
970 return text.replaceAll('\\', '\\\\').replaceAll('"', '\\"').replaceAll( | 963 return text.replaceAll('\\', '\\\\').replaceAll('"', '\\"').replaceAll( |
971 '\n', '\\n').replaceAll('\r', '\\r'); | 964 '\n', '\\n').replaceAll('\r', '\\r'); |
972 } | 965 } |
973 | 966 |
974 /** Visits [body] without creating a new block for a [BlockStatement]. */ | 967 /** Visits [body] without creating a new block for a [BlockStatement]. */ |
975 bool visitStatementsInBlock(Statement body) { | 968 bool visitStatementsInBlock(Statement body) { |
976 if (body is BlockStatement) { | 969 if (body is BlockStatement) { |
977 BlockStatement block = body; | 970 for (var stmt in body.body) { |
978 for (var stmt in block.body) { | |
979 stmt.visit(this); | 971 stmt.visit(this); |
980 } | 972 } |
981 } else { | 973 } else { |
982 if (body != null) body.visit(this); | 974 if (body != null) body.visit(this); |
983 } | 975 } |
984 return false; | 976 return false; |
985 } | 977 } |
986 | 978 |
987 _pushBlock([bool reentrant = false]) { | 979 _pushBlock([bool reentrant = false]) { |
988 _scope = new BlockScope(this, _scope, reentrant); | 980 _scope = new BlockScope(this, _scope, reentrant); |
(...skipping 546 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1535 meth.generator.writeDefinition(w, node); | 1527 meth.generator.writeDefinition(w, node); |
1536 | 1528 |
1537 return new Value(meth.functionType, w.text); | 1529 return new Value(meth.functionType, w.text); |
1538 } | 1530 } |
1539 | 1531 |
1540 visitCallExpression(CallExpression node) { | 1532 visitCallExpression(CallExpression node) { |
1541 var target; | 1533 var target; |
1542 var position = node.target; | 1534 var position = node.target; |
1543 var name = '\$call'; | 1535 var name = '\$call'; |
1544 if (node.target is DotExpression) { | 1536 if (node.target is DotExpression) { |
1545 DotExpression dot = node.target; | 1537 target = node.target.self.visit(this); |
1546 target = dot.self.visit(this); | 1538 name = node.target.name.name; |
1547 name = dot.name.name; | 1539 position = node.target.name; |
1548 position = dot.name; | |
1549 } else if (node.target is VarExpression) { | 1540 } else if (node.target is VarExpression) { |
1550 VarExpression varExpr = node.target; | 1541 name = node.target.name.name; |
1551 name = varExpr.name.name; | |
1552 var meth = method.declaringType.resolveMember(name); | 1542 var meth = method.declaringType.resolveMember(name); |
1553 if (meth != null) { | 1543 if (meth != null) { |
1554 target = _makeThisOrType(); | 1544 target = _makeThisOrType(); |
1555 return meth.invoke(this, varExpr, target, | 1545 return meth.invoke(this, node.target, target, |
1556 _makeArgs(node.arguments)); | 1546 _makeArgs(node.arguments)); |
1557 } | 1547 } |
1558 // Look for members of the top-level type (or imported libs). | 1548 // Look for members of the top-level type (or imported libs). |
1559 meth = method.declaringType.library.lookup(name, varExpr.span); | 1549 meth = method.declaringType.library.lookup(name, node.target.span); |
1560 if (meth != null) { | 1550 if (meth != null) { |
1561 return meth.invoke(this, varExpr, null, _makeArgs(node.arguments)); | 1551 return meth.invoke(this, node.target, null, |
| 1552 _makeArgs(node.arguments)); |
1562 } | 1553 } |
1563 | 1554 |
1564 name = '\$call'; | 1555 name = '\$call'; |
1565 target = varExpr.visit(this); | 1556 target = node.target.visit(this); |
1566 } else { | 1557 } else { |
1567 target = node.target.visit(this); | 1558 target = node.target.visit(this); |
1568 } | 1559 } |
1569 | 1560 |
1570 return target.invoke(this, name, position, _makeArgs(node.arguments)); | 1561 return target.invoke(this, name, position, _makeArgs(node.arguments)); |
1571 } | 1562 } |
1572 | 1563 |
1573 visitIndexExpression(IndexExpression node) { | 1564 visitIndexExpression(IndexExpression node) { |
1574 var target = visitValue(node.target); | 1565 var target = visitValue(node.target); |
1575 var index = visitValue(node.index); | 1566 var index = visitValue(node.index); |
(...skipping 647 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2223 result.add(new Value(world.varType, '\$$i', false, /*needsTemp:*/false)); | 2214 result.add(new Value(world.varType, '\$$i', false, /*needsTemp:*/false)); |
2224 } | 2215 } |
2225 for (int i = bareCount; i < length; i++) { | 2216 for (int i = bareCount; i < length; i++) { |
2226 var name = getName(i); | 2217 var name = getName(i); |
2227 if (name == null) name = '\$$i'; | 2218 if (name == null) name = '\$$i'; |
2228 result.add(new Value(world.varType, name, false, /*needsTemp:*/false)); | 2219 result.add(new Value(world.varType, name, false, /*needsTemp:*/false)); |
2229 } | 2220 } |
2230 return new Arguments(nodes, result); | 2221 return new Arguments(nodes, result); |
2231 } | 2222 } |
2232 } | 2223 } |
OLD | NEW |