Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 * The [CompileTimeConstantHandler] keeps track of compile-time constants, | 6 * The [CompileTimeConstantHandler] keeps track of compile-time constants, |
| 7 * initializations of global and static fields, and default values of | 7 * initializations of global and static fields, and default values of |
| 8 * optional parameters. | 8 * optional parameters. |
| 9 */ | 9 */ |
| 10 class CompileTimeConstantHandler extends CompilerTask { | 10 class CompileTimeConstantHandler extends CompilerTask { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 89 && element.modifiers.isFinal(); | 89 && element.modifiers.isFinal(); |
| 90 }); | 90 }); |
| 91 } | 91 } |
| 92 | 92 |
| 93 StringBuffer writeJsCodeForVariable(StringBuffer buffer, | 93 StringBuffer writeJsCodeForVariable(StringBuffer buffer, |
| 94 VariableElement element) { | 94 VariableElement element) { |
| 95 var value = initialVariableValues[element]; | 95 var value = initialVariableValues[element]; |
| 96 if (value === null) { | 96 if (value === null) { |
| 97 buffer.add("(void 0)"); | 97 buffer.add("(void 0)"); |
| 98 } else if (value is num) { | 98 } else if (value is num) { |
| 99 buffer.add("($value)"); | 99 if (value.isNaN()) { |
| 100 buffer.add("(0/0)"); | |
| 101 } else if (value == double.INFINITY) { | |
| 102 buffer.add("(1/0)"); | |
| 103 } else if (value == -double.INFINITY) { | |
| 104 buffer.add("(-1/0)"); | |
| 105 } else { | |
| 106 buffer.add("($value)"); | |
| 107 } | |
| 100 } else if (value === true) { | 108 } else if (value === true) { |
| 101 buffer.add("true"); | 109 buffer.add("true"); |
| 102 } else if (value === false) { | 110 } else if (value === false) { |
| 103 buffer.add("false"); | 111 buffer.add("false"); |
| 104 } else if (value is DartString) { | 112 } else if (value is DartString) { |
| 105 buffer.add("'"); | 113 buffer.add("'"); |
| 106 writeEscapedString(value, buffer, (reason) { | 114 writeEscapedString(value, buffer, (reason) { |
| 107 compiler.cancel("failed to write escaped string: $value"); | 115 compiler.cancel("failed to write escaped string: $value"); |
| 108 }); | 116 }); |
| 109 buffer.add("'"); | 117 buffer.add("'"); |
| 110 } else { | 118 } else { |
| 111 // TODO(floitsch): support more values. | 119 // TODO(floitsch): support more values. |
| 112 compiler.unimplemented("CompileTimeConstantHandler" + | 120 compiler.unimplemented("CompileTimeConstantHandler" + |
| 113 "writeJsCodeForVariable", | 121 "writeJsCodeForVariable", |
| 114 node: element.parseNode(compiler)); | 122 element: element); |
| 115 } | 123 } |
| 116 return buffer; | 124 return buffer; |
| 117 } | 125 } |
| 118 | 126 |
| 119 /** | 127 /** |
| 120 * Write the contents of the quoted string to a [StringBuffer] in | 128 * Write the contents of the quoted string to a [StringBuffer] in |
| 121 * a form that is valid as JavaScript string literal content. | 129 * a form that is valid as JavaScript string literal content. |
| 122 * The string is assumed quoted by single quote characters. | 130 * The string is assumed quoted by single quote characters. |
| 123 */ | 131 */ |
| 124 static void writeEscapedString(DartString string, | 132 static void writeEscapedString(DartString string, |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 189 } | 197 } |
| 190 | 198 |
| 191 visitLiteral(Literal literal) { | 199 visitLiteral(Literal literal) { |
| 192 if (literal is LiteralString) { | 200 if (literal is LiteralString) { |
| 193 assert(literal.asLiteralString().isValidated()); | 201 assert(literal.asLiteralString().isValidated()); |
| 194 return literal.asLiteralString().dartString; | 202 return literal.asLiteralString().dartString; |
| 195 } | 203 } |
| 196 return literal.value; | 204 return literal.value; |
| 197 } | 205 } |
| 198 | 206 |
| 207 // TODO(floitsch): provide better error-messages. | |
| 199 visitSend(Send send) { | 208 visitSend(Send send) { |
| 200 Element element = definitions[send]; | 209 Element element = definitions[send]; |
| 201 if (element !== null && element.kind == ElementKind.FIELD) { | 210 if (Elements.isStaticOrTopLevelField(element)) { |
| 202 if (element.isInstanceMember() || | 211 if (element.modifiers === null || |
| 203 element.modifiers === null || | |
| 204 !element.modifiers.isFinal()) { | 212 !element.modifiers.isFinal()) { |
| 205 error(element); | 213 error(send); |
| 206 } | 214 } |
| 207 return constantHandler.compileVariable(element); | 215 return constantHandler.compileVariable(element); |
| 216 } else if (send.isPrefix) { | |
| 217 assert(send.isOperator); | |
| 218 var receiverValue = evaluate(send.receiver); | |
| 219 Operator op = send.selector; | |
| 220 switch (op.source.stringValue) { | |
| 221 case "-": | |
| 222 if (receiverValue is !num) error(send); | |
| 223 return -receiverValue; | |
| 224 case "~": | |
| 225 if (receiverValue is !int) error(send); | |
| 226 return ~receiverValue; | |
| 227 case "!": | |
| 228 if (receiverValue is !bool) error(send); | |
| 229 return !receiverValue; | |
| 230 default: error(send); | |
|
ngeoffray
2012/02/21 11:22:09
new line after default?
floitsch
2012/02/22 10:17:51
Done.
| |
| 231 } | |
| 232 } else if (send.isOperator && !send.isPostfix) { | |
| 233 assert(send.argumentCount() == 1); | |
| 234 var left = evaluate(send.receiver); | |
| 235 var right = evaluate(send.argumentsNode.nodes.head); | |
| 236 String op = send.selector.asOperator().source.stringValue; | |
| 237 | |
| 238 if (op == "==" || op == "===") { | |
| 239 // We use == instead of === so that non-canonicalized DartStrings can | |
| 240 // use their equality operator. | |
| 241 return left == right; | |
| 242 } else if (op == "!=" || op == "!==") { | |
| 243 // 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.
| |
| 244 // use their equality operator. | |
| 245 return left != right; | |
| 246 } | |
| 247 if (left is num && right is num) { | |
| 248 switch (op) { | |
| 249 case "+": return left + right; | |
| 250 case "-": return left - right; | |
| 251 case "*": return left * right; | |
| 252 case "/": return left / right; | |
| 253 case "~/": | |
| 254 case "%": | |
| 255 if (left is int && right is int && right == 0) { | |
| 256 error(send); | |
| 257 } | |
| 258 return op == "~/" ? left ~/ right : left % right; | |
| 259 case "<": return left < right; | |
| 260 case "<=": return left <= right; | |
| 261 case ">": return left > right; | |
| 262 case ">=": return left >= right; | |
| 263 } | |
| 264 } | |
| 265 if (left is int && right is int) { | |
| 266 switch (op) { | |
| 267 case "|": return left | right; | |
| 268 case "&": return left & right; | |
| 269 case "<<": | |
| 270 // TODO(floitsch): find a better way to guard against shifts to the | |
| 271 // left. | |
| 272 if (right > 100) error(send); | |
| 273 if (right < 0) error(send); | |
| 274 return left << right; | |
| 275 case ">>": | |
| 276 if (right < 0) error(send); | |
| 277 return left >> right; | |
| 278 case "^": return left ^ right; | |
| 279 } | |
| 280 } | |
| 281 if (left is DartString) { | |
| 282 DartString dartString = left; | |
| 283 if (op == "+") { | |
| 284 if (right is DartString) { | |
| 285 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 +.
| |
| 286 } else if (right is num || | |
| 287 right is bool || | |
| 288 right === null) { | |
| 289 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.
| |
| 290 new DartString.literal(right.toString())); | |
| 291 } else { | |
| 292 error(send); | |
| 293 } | |
| 294 } 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.
| |
| 295 if (0 <= right && right < left.length) { | |
| 296 Iterator iterator = dartString.iterator(); | |
| 297 for (int i = 0; i < right; i++) iterator.next(); | |
| 298 String oneCharString = new String.fromCharCodes([iterator.next()]); | |
| 299 return new DartString.literal(oneCharString); | |
| 300 } else { | |
| 301 error(send); | |
| 302 } | |
| 303 } | |
| 304 } | |
| 305 } else if (send.isPropertyAccess) { | |
| 306 Identifier selector = send.selector.asIdentifier(); | |
| 307 if (selector == null) error(send); | |
| 308 if (selector.source != const SourceString("length")) error(send); | |
| 309 var receiver = evaluate(send.receiver); | |
| 310 if (receiver is DartString) { | |
| 311 DartString dartString = receiver; | |
| 312 return dartString.length; | |
| 313 } | |
| 314 compiler.unimplemented( | |
| 315 "CompileTimeConstantEvaluator 'length' property-lookup on non-string", | |
| 316 node: send); | |
| 208 } | 317 } |
| 209 return super.visitSend(send); | 318 return super.visitSend(send); |
| 210 } | 319 } |
| 211 | 320 |
| 212 error(Element element) { | 321 visitSendSet(SendSet node) { |
| 322 error(node); | |
| 323 } | |
| 324 | |
| 325 error(Node node) { | |
| 213 // TODO(floitsch): get the list of constants that are currently compiled | 326 // TODO(floitsch): get the list of constants that are currently compiled |
| 214 // and present some kind of stack-trace. | 327 // and present some kind of stack-trace. |
| 215 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 328 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| 216 List arguments = [element.name]; | 329 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); |
| 217 Node node = element.parseNode(compiler); | |
| 218 compiler.reportError(node, new CompileTimeConstantError(kind, arguments)); | |
| 219 } | 330 } |
| 220 } | 331 } |
| OLD | NEW |