Chromium Code Reviews| Index: frog/leg/compile_time_constants.dart |
| diff --git a/frog/leg/compile_time_constants.dart b/frog/leg/compile_time_constants.dart |
| index 9a55ecbd1dadd4f473264dc9866855c2ec86f0b0..5ec4e39b80077be870d3d97ed028ecb87d979bea 100644 |
| --- a/frog/leg/compile_time_constants.dart |
| +++ b/frog/leg/compile_time_constants.dart |
| @@ -96,7 +96,15 @@ class CompileTimeConstantHandler extends CompilerTask { |
| if (value === null) { |
| buffer.add("(void 0)"); |
| } else if (value is num) { |
| - buffer.add("($value)"); |
| + if (value.isNaN()) { |
| + buffer.add("(0/0)"); |
| + } else if (value == double.INFINITY) { |
| + buffer.add("(1/0)"); |
| + } else if (value == -double.INFINITY) { |
| + buffer.add("(-1/0)"); |
| + } else { |
| + buffer.add("($value)"); |
| + } |
| } else if (value === true) { |
| buffer.add("true"); |
| } else if (value === false) { |
| @@ -111,7 +119,7 @@ class CompileTimeConstantHandler extends CompilerTask { |
| // TODO(floitsch): support more values. |
| compiler.unimplemented("CompileTimeConstantHandler" + |
| "writeJsCodeForVariable", |
| - node: element.parseNode(compiler)); |
| + element: element); |
| } |
| return buffer; |
| } |
| @@ -196,25 +204,128 @@ class CompileTimeConstantEvaluator extends AbstractVisitor { |
| return literal.value; |
| } |
| + // TODO(floitsch): provide better error-messages. |
| visitSend(Send send) { |
| Element element = definitions[send]; |
| - if (element !== null && element.kind == ElementKind.FIELD) { |
| - if (element.isInstanceMember() || |
| - element.modifiers === null || |
| + if (Elements.isStaticOrTopLevelField(element)) { |
| + if (element.modifiers === null || |
| !element.modifiers.isFinal()) { |
| - error(element); |
| + error(send); |
| } |
| return constantHandler.compileVariable(element); |
| + } else if (send.isPrefix) { |
| + assert(send.isOperator); |
| + var receiverValue = evaluate(send.receiver); |
| + Operator op = send.selector; |
| + switch (op.source.stringValue) { |
| + case "-": |
| + if (receiverValue is !num) error(send); |
| + return -receiverValue; |
| + case "~": |
| + if (receiverValue is !int) error(send); |
| + return ~receiverValue; |
| + case "!": |
| + if (receiverValue is !bool) error(send); |
| + return !receiverValue; |
| + default: error(send); |
|
ngeoffray
2012/02/21 11:22:09
new line after default?
floitsch
2012/02/22 10:17:51
Done.
|
| + } |
| + } else if (send.isOperator && !send.isPostfix) { |
| + assert(send.argumentCount() == 1); |
| + var left = evaluate(send.receiver); |
| + var right = evaluate(send.argumentsNode.nodes.head); |
| + String op = send.selector.asOperator().source.stringValue; |
| + |
| + if (op == "==" || op == "===") { |
| + // We use == instead of === so that non-canonicalized DartStrings can |
| + // use their equality operator. |
| + return left == right; |
| + } else if (op == "!=" || op == "!==") { |
| + // We use == instead of === so that non-canonicalized DartStrings can |
|
ngeoffray
2012/02/21 11:22:09
Remove comment, or adjust it to !=.
floitsch
2012/02/22 10:17:51
Done.
|
| + // use their equality operator. |
| + return left != right; |
| + } |
| + if (left is num && right is num) { |
| + switch (op) { |
| + case "+": return left + right; |
| + case "-": return left - right; |
| + case "*": return left * right; |
| + case "/": return left / right; |
| + case "~/": |
| + case "%": |
| + if (left is int && right is int && right == 0) { |
| + error(send); |
| + } |
| + return op == "~/" ? left ~/ right : left % right; |
| + case "<": return left < right; |
| + case "<=": return left <= right; |
| + case ">": return left > right; |
| + case ">=": return left >= right; |
| + } |
| + } |
| + if (left is int && right is int) { |
| + switch (op) { |
| + case "|": return left | right; |
| + case "&": return left & right; |
| + case "<<": |
| + // TODO(floitsch): find a better way to guard against shifts to the |
| + // left. |
| + if (right > 100) error(send); |
| + if (right < 0) error(send); |
| + return left << right; |
| + case ">>": |
| + if (right < 0) error(send); |
| + return left >> right; |
| + case "^": return left ^ right; |
| + } |
| + } |
| + if (left is DartString) { |
| + DartString dartString = left; |
| + if (op == "+") { |
| + if (right is DartString) { |
| + return new ConsDartString(dartString, right); |
|
ngeoffray
2012/02/21 11:22:09
Could we have operator+ defined in DartString? (li
floitsch
2012/02/22 10:17:51
let's keep it without +.
|
| + } else if (right is num || |
| + right is bool || |
| + right === null) { |
| + return new ConsDartString(left, |
|
ngeoffray
2012/02/21 11:22:09
Please move ConsDartString from ssa nodes to ast n
floitsch
2012/02/22 10:17:51
Done.
|
| + new DartString.literal(right.toString())); |
| + } else { |
| + error(send); |
| + } |
| + } else if (op == "[]" && right is int) { |
|
ngeoffray
2012/02/21 11:22:09
Is "op == '[]'" equivalent to send.isIndex?
floitsch
2012/02/22 10:17:51
Done.
|
| + if (0 <= right && right < left.length) { |
| + Iterator iterator = dartString.iterator(); |
| + for (int i = 0; i < right; i++) iterator.next(); |
| + String oneCharString = new String.fromCharCodes([iterator.next()]); |
| + return new DartString.literal(oneCharString); |
| + } else { |
| + error(send); |
| + } |
| + } |
| + } |
| + } else if (send.isPropertyAccess) { |
| + Identifier selector = send.selector.asIdentifier(); |
| + if (selector == null) error(send); |
| + if (selector.source != const SourceString("length")) error(send); |
| + var receiver = evaluate(send.receiver); |
| + if (receiver is DartString) { |
| + DartString dartString = receiver; |
| + return dartString.length; |
| + } |
| + compiler.unimplemented( |
| + "CompileTimeConstantEvaluator 'length' property-lookup on non-string", |
| + node: send); |
| } |
| return super.visitSend(send); |
| } |
| - error(Element element) { |
| + visitSendSet(SendSet node) { |
| + error(node); |
| + } |
| + |
| + error(Node node) { |
| // TODO(floitsch): get the list of constants that are currently compiled |
| // and present some kind of stack-trace. |
| MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| - List arguments = [element.name]; |
| - Node node = element.parseNode(compiler); |
| - compiler.reportError(node, new CompileTimeConstantError(kind, arguments)); |
| + compiler.reportError(node, new CompileTimeConstantError(kind, const [])); |
| } |
| } |