Chromium Code Reviews| 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 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 124 var lib = toCheck.removeFirst(); | 124 var lib = toCheck.removeFirst(); |
| 125 if (seen.contains(lib)) continue; | 125 if (seen.contains(lib)) continue; |
| 126 seen.add(lib); | 126 seen.add(lib); |
| 127 lib.imports.forEach((i) => toCheck.addLast(lib)); | 127 lib.imports.forEach((i) => toCheck.addLast(lib)); |
| 128 lib.types.getValues().forEach((t) => types.add(t)); | 128 lib.types.getValues().forEach((t) => types.add(t)); |
| 129 } | 129 } |
| 130 } | 130 } |
| 131 return types; | 131 return types; |
| 132 } | 132 } |
| 133 | 133 |
| 134 GlobalValue globalForStaticField(FieldMember field, Value fieldValue, | 134 GlobalValue globalForStaticField(FieldMember field, Value exp, |
| 135 List<Value> dependencies) { | 135 List<Value> dependencies) { |
| 136 hasStatics = true; | 136 hasStatics = true; |
| 137 var fullname = "${field.declaringType.jsname}.${field.jsname}"; | 137 var key = "${field.declaringType.jsname}.${field.jsname}"; |
| 138 if (!globals.containsKey(fullname)) { | 138 var ret = globals[key]; |
| 139 globals[fullname] = new GlobalValue.fromStatic( | 139 if (ret === null) { |
| 140 field, fieldValue, dependencies); | 140 ret = new GlobalValue(exp.type, exp.code, field.isFinal, field, null, |
| 141 exp, exp.span, dependencies); | |
| 142 globals[key] = ret; | |
| 141 } | 143 } |
| 142 return globals[fullname]; | 144 return ret; |
| 143 } | 145 } |
| 144 | 146 |
| 145 GlobalValue globalForConst(EvaluatedValue exp, List<Value> dependencies) { | 147 GlobalValue globalForConst(EvaluatedValue exp, List<Value> dependencies) { |
| 146 // Include type name to ensure unique constants - this matches | 148 // Include type name to ensure unique constants - this matches |
| 147 // the code above that includes the type name for static fields. | 149 // the code above that includes the type name for static fields. |
| 148 var key = exp.type.jsname + ':' + exp.canonicalCode; | 150 var key = exp.type.jsname + ':' + exp.code; |
| 149 if (!globals.containsKey(key)) { | 151 var ret = globals[key]; |
| 150 globals[key] = | 152 if (ret === null) { |
| 151 new GlobalValue.fromConst(globals.length, exp, dependencies); | 153 var name = "const\$${globals.length}"; |
| 154 ret = new GlobalValue(exp.type, name, true, null, name, exp, | |
| 155 exp.span, dependencies); | |
| 156 globals[key] = ret; | |
| 152 } | 157 } |
| 153 assert(globals[key].type == exp.type); | 158 assert(ret.type == exp.type); |
| 154 return globals[key]; | 159 return ret; |
| 155 } | 160 } |
| 156 | 161 |
| 157 writeTypes(Library lib) { | 162 writeTypes(Library lib) { |
| 158 if (lib.isWritten) return; | 163 if (lib.isWritten) return; |
| 159 | 164 |
| 160 // Do this first to be safe in the face of circular refs. | 165 // Do this first to be safe in the face of circular refs. |
| 161 lib.isWritten = true; | 166 lib.isWritten = true; |
| 162 | 167 |
| 163 // Ensure all imports have been written. | 168 // Ensure all imports have been written. |
| 164 for (var import in lib.imports) { | 169 for (var import in lib.imports) { |
| (...skipping 1763 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1928 meth.generator.writeDefinition(w, node); | 1933 meth.generator.writeDefinition(w, node); |
| 1929 return new Value(meth.functionType, w.text, node.span); | 1934 return new Value(meth.functionType, w.text, node.span); |
| 1930 } | 1935 } |
| 1931 | 1936 |
| 1932 visitCallExpression(CallExpression node) { | 1937 visitCallExpression(CallExpression node) { |
| 1933 var target; | 1938 var target; |
| 1934 var position = node.target; | 1939 var position = node.target; |
| 1935 var name = ':call'; | 1940 var name = ':call'; |
| 1936 if (node.target is DotExpression) { | 1941 if (node.target is DotExpression) { |
| 1937 DotExpression dot = node.target; | 1942 DotExpression dot = node.target; |
| 1938 // ???? | 1943 target = dot.self.visit(this); |
| 1939 if (dot.self is LiteralExpression) { | |
| 1940 target = (new ParenExpression(dot.self, dot.self.span)).visit(this); | |
| 1941 } else { | |
| 1942 target = dot.self.visit(this); | |
| 1943 } | |
| 1944 name = dot.name.name; | 1944 name = dot.name.name; |
| 1945 position = dot.name; | 1945 position = dot.name; |
| 1946 } else if (node.target is VarExpression) { | 1946 } else if (node.target is VarExpression) { |
| 1947 VarExpression varExpr = node.target; | 1947 VarExpression varExpr = node.target; |
| 1948 name = varExpr.name.name; | 1948 name = varExpr.name.name; |
| 1949 // First check in block scopes. | 1949 // First check in block scopes. |
| 1950 target = _scope.lookup(name); | 1950 target = _scope.lookup(name); |
| 1951 if (target != null) { | 1951 if (target != null) { |
| 1952 return target.invoke(this, ':call', node, _makeArgs(node.arguments)); | 1952 return target.invoke(this, ':call', node, _makeArgs(node.arguments)); |
| 1953 } | 1953 } |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 1971 return (e is BinaryExpression || e is ConditionalExpression | 1971 return (e is BinaryExpression || e is ConditionalExpression |
| 1972 || e is PostfixExpression || _isUnaryIncrement(e)); | 1972 || e is PostfixExpression || _isUnaryIncrement(e)); |
| 1973 } | 1973 } |
| 1974 | 1974 |
| 1975 visitBinaryExpression(BinaryExpression node, [bool isVoid = false]) { | 1975 visitBinaryExpression(BinaryExpression node, [bool isVoid = false]) { |
| 1976 final kind = node.op.kind; | 1976 final kind = node.op.kind; |
| 1977 // TODO(jimhug): Ensure these have same semantics as JS! | 1977 // TODO(jimhug): Ensure these have same semantics as JS! |
| 1978 if (kind == TokenKind.AND || kind == TokenKind.OR) { | 1978 if (kind == TokenKind.AND || kind == TokenKind.OR) { |
| 1979 var x = visitTypedValue(node.x, world.nonNullBool); | 1979 var x = visitTypedValue(node.x, world.nonNullBool); |
| 1980 var y = visitTypedValue(node.y, world.nonNullBool); | 1980 var y = visitTypedValue(node.y, world.nonNullBool); |
| 1981 final code = '${x.code} ${node.op} ${y.code}'; | 1981 return x.binop(kind, y, this, node); |
|
Jennifer Messerly
2012/01/09 19:06:54
so nice!
| |
| 1982 if (x.isConst && y.isConst) { | |
| 1983 var value = (kind == TokenKind.AND) | |
| 1984 ? x.actualValue && y.actualValue : x.actualValue || y.actualValue; | |
| 1985 return Value.fromBool(value, node.span); | |
| 1986 } | |
| 1987 return new Value(world.nonNullBool, code, node.span); | |
| 1988 } else if (kind == TokenKind.EQ_STRICT || kind == TokenKind.NE_STRICT) { | 1982 } else if (kind == TokenKind.EQ_STRICT || kind == TokenKind.NE_STRICT) { |
| 1989 var x = visitValue(node.x); | 1983 var x = visitValue(node.x); |
| 1990 var y = visitValue(node.y); | 1984 var y = visitValue(node.y); |
| 1991 if (x.isConst && y.isConst) { | 1985 return x.binop(kind, y, this, node); |
| 1992 var xVal = x.actualValue; | |
| 1993 var yVal = y.actualValue; | |
| 1994 | |
| 1995 // Note: it is ok to use == and not === here since all of these | |
| 1996 // constant comparisons are applied to doubles, bool, or strings. | |
| 1997 // We need it for the compile-time evaluator because | |
| 1998 // (9).toDouble() === 9.0 is false in dartvm. | |
| 1999 var value = kind == TokenKind.EQ_STRICT ? xVal == yVal : xVal != yVal; | |
| 2000 return Value.fromBool(value, node.span); | |
| 2001 } | |
| 2002 if (x.code == 'null' || y.code == 'null') { | |
| 2003 // Switching to == ensures that null and undefined are interchangable. | |
| 2004 final op = node.op.toString().substring(0,2); | |
| 2005 return new Value(world.nonNullBool, '${x.code} $op ${y.code}', | |
| 2006 node.span); | |
| 2007 } else { | |
| 2008 // TODO(jimhug): Resolve issue with undefined and null here. | |
| 2009 return new Value(world.nonNullBool, '${x.code} ${node.op} ${y.code}', | |
| 2010 node.span); | |
| 2011 } | |
| 2012 } | 1986 } |
| 2013 | 1987 |
| 2014 final assignKind = TokenKind.kindFromAssign(node.op.kind); | 1988 final assignKind = TokenKind.kindFromAssign(node.op.kind); |
| 2015 if (assignKind == -1) { | 1989 if (assignKind == -1) { |
| 2016 final x = visitValue(node.x); | 1990 final x = visitValue(node.x); |
| 2017 final y = visitValue(node.y); | 1991 final y = visitValue(node.y); |
| 2018 var name = TokenKind.binaryMethodName(node.op.kind); | 1992 return x.binop(kind, y, this, node); |
| 2019 if (node.op.kind == TokenKind.NE) { | |
| 2020 name = ':ne'; | |
| 2021 } | |
| 2022 if (name == null) { | |
| 2023 world.internalError('unimplemented binary op ${node.op}', node.span); | |
| 2024 return; | |
| 2025 } | |
| 2026 return x.invoke(this, name, node, new Arguments(null, [y])); | |
| 2027 } else if ((assignKind != 0) && _expressionNeedsParens(node.y)) { | 1993 } else if ((assignKind != 0) && _expressionNeedsParens(node.y)) { |
| 2028 return _visitAssign(assignKind, node.x, | 1994 return _visitAssign(assignKind, node.x, |
| 2029 new ParenExpression(node.y, node.y.span), node, null, isVoid); | 1995 new ParenExpression(node.y, node.y.span), node, null, isVoid); |
| 2030 } else { | 1996 } else { |
| 2031 return _visitAssign(assignKind, node.x, node.y, node, null, isVoid); | 1997 return _visitAssign(assignKind, node.x, node.y, node, null, isVoid); |
| 2032 } | 1998 } |
| 2033 } | 1999 } |
| 2034 | 2000 |
| 2035 /** | 2001 /** |
| 2036 * Visits an assignment expression. | 2002 * Visits an assignment expression. |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2195 this, xn.name.name, xn.name, y); | 2161 this, xn.name.name, xn.name, y); |
| 2196 if (tmptarget != target) freeTemp(tmptarget); | 2162 if (tmptarget != target) freeTemp(tmptarget); |
| 2197 return ret; | 2163 return ret; |
| 2198 } | 2164 } |
| 2199 | 2165 |
| 2200 visitUnaryExpression(UnaryExpression node) { | 2166 visitUnaryExpression(UnaryExpression node) { |
| 2201 var value = visitValue(node.self); | 2167 var value = visitValue(node.self); |
| 2202 switch (node.op.kind) { | 2168 switch (node.op.kind) { |
| 2203 case TokenKind.INCR: | 2169 case TokenKind.INCR: |
| 2204 case TokenKind.DECR: | 2170 case TokenKind.DECR: |
| 2171 // TODO(jimhug): Requires non-null num to be correct. | |
| 2205 if (value.type.isNum) { | 2172 if (value.type.isNum) { |
| 2206 return new Value(value.type, '${node.op}${value.code}', node.span); | 2173 return new Value(value.type, '${node.op}${value.code}', node.span); |
| 2207 } else { | 2174 } else { |
| 2208 // ++x becomes x += 1 | 2175 // ++x becomes x += 1 |
| 2209 // --x becomes x -= 1 | 2176 // --x becomes x -= 1 |
| 2210 // TODO(jimhug): Confirm that --x becomes x -= 1 as it is in VM. | 2177 // TODO(jimhug): Confirm that --x becomes x -= 1 as it is in VM. |
| 2211 var kind = (TokenKind.INCR == node.op.kind ? | 2178 var kind = (TokenKind.INCR == node.op.kind ? |
| 2212 TokenKind.ADD : TokenKind.SUB); | 2179 TokenKind.ADD : TokenKind.SUB); |
| 2213 // TODO(jimhug): Shouldn't need a full-expression here. | 2180 // TODO(jimhug): Shouldn't need a full-expression here. |
| 2214 var operand = new LiteralExpression(Value.fromInt(1, node.span), | 2181 var operand = new LiteralExpression(Value.fromInt(1, node.span), |
| 2215 node.span); | 2182 node.span); |
| 2216 | 2183 |
| 2217 var assignValue = _visitAssign(kind, node.self, operand, node, null); | 2184 var assignValue = _visitAssign(kind, node.self, operand, node, null); |
| 2218 return new Value(assignValue.type, '(${assignValue.code})', | 2185 return new Value(assignValue.type, '(${assignValue.code})', |
| 2219 node.span); | 2186 node.span); |
| 2220 } | 2187 } |
| 2221 case TokenKind.NOT: | 2188 case TokenKind.NOT: |
| 2222 // TODO(jimhug): Issue #359 seeks to clarify this behavior. | 2189 // TODO(jimhug): Issue #359 seeks to clarify this behavior. |
| 2223 if (value.type.isBool && value.isConst) { | 2190 if (value.type.isBool && value.isConst) { |
| 2224 var newVal = !value.actualValue; | 2191 var newVal = !value.actualValue; |
| 2225 return new EvaluatedValue(value.type, newVal, '${newVal}', node.span); | 2192 return Value.fromBool(newVal, node.span); |
| 2226 } else { | 2193 } else { |
| 2227 var newVal = value.convertTo(this, world.nonNullBool); | 2194 var newVal = value.convertTo(this, world.nonNullBool); |
| 2228 return new Value(newVal.type, '!${newVal.code}', node.span); | 2195 return new Value(newVal.type, '!${newVal.code}', node.span); |
| 2229 } | 2196 } |
| 2230 | 2197 |
| 2231 case TokenKind.ADD: | 2198 case TokenKind.ADD: |
| 2232 // TODO(jimhug): Issue #359 seeks to clarify this behavior. | 2199 // TODO(jimhug): Issue #359 seeks to clarify this behavior. |
| 2233 return value.convertTo(this, world.numType); | 2200 return value.convertTo(this, world.numType); |
| 2234 | 2201 |
| 2235 case TokenKind.SUB: | 2202 case TokenKind.SUB: |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2353 | 2320 |
| 2354 // Call the constructor on the type we want to construct. | 2321 // Call the constructor on the type we want to construct. |
| 2355 // NOTE: this is important for correct type checking of factories. | 2322 // NOTE: this is important for correct type checking of factories. |
| 2356 // If the user calls "new Interface()" we want the result type to be the | 2323 // If the user calls "new Interface()" we want the result type to be the |
| 2357 // interface, not the class. | 2324 // interface, not the class. |
| 2358 var target = new Value.type(type, typeRef.span); | 2325 var target = new Value.type(type, typeRef.span); |
| 2359 return m.invoke(this, node, target, _makeArgs(node.arguments)); | 2326 return m.invoke(this, node, target, _makeArgs(node.arguments)); |
| 2360 } | 2327 } |
| 2361 | 2328 |
| 2362 visitListExpression(ListExpression node) { | 2329 visitListExpression(ListExpression node) { |
| 2363 // TODO(jimhug): Use node.type or other type inference here. | |
| 2364 var argsCode = []; | |
| 2365 var argValues = []; | 2330 var argValues = []; |
| 2366 var type = null; | 2331 //var listType = node.isConst ? world.immutableListType : world.listType; |
|
Jennifer Messerly
2012/01/09 19:06:54
remove?
jimhug
2012/01/09 21:34:30
Done.
| |
| 2367 if (node.type != null) { | 2332 var listType = world.listType; |
| 2368 // The parser makes node.type a list type, we extract its type argument. | 2333 var type = world.varType; |
| 2369 type = method.resolveType(node.type, true).typeArgsInOrder[0]; | 2334 if (node.itemType != null) { |
| 2335 type = method.resolveType(node.itemType, true); | |
| 2370 if (node.isConst && (type is ParameterType || type.hasTypeParams)) { | 2336 if (node.isConst && (type is ParameterType || type.hasTypeParams)) { |
| 2371 world.error('type parameter cannot be used in const list literals'); | 2337 world.error('type parameter cannot be used in const list literals'); |
| 2372 } | 2338 } |
| 2339 listType = listType.getOrMakeConcreteType([type]); | |
|
Jennifer Messerly
2012/01/09 19:06:54
correct generic List type, awesome :)
| |
| 2373 } | 2340 } |
| 2374 for (var item in node.values) { | 2341 for (var item in node.values) { |
| 2375 var arg = visitTypedValue(item, type); | 2342 var arg = visitTypedValue(item, type); |
| 2376 argValues.add(arg); | 2343 argValues.add(arg); |
| 2377 if (node.isConst) { | 2344 if (node.isConst && !arg.isConst) { |
| 2378 if (!arg.isConst) { | 2345 world.error('const list can only contain const values', arg.span); |
| 2379 world.error('const list can only contain const values', item.span); | |
| 2380 argsCode.add(arg.code); | |
| 2381 } else { | |
| 2382 argsCode.add(arg.canonicalCode); | |
| 2383 } | |
| 2384 } else { | |
| 2385 argsCode.add(arg.code); | |
| 2386 } | 2346 } |
| 2387 } | 2347 } |
| 2388 | 2348 |
| 2389 world.listFactoryType.markUsed(); | 2349 world.listFactoryType.markUsed(); |
| 2390 | 2350 |
| 2391 final code = '[${Strings.join(argsCode, ", ")}]'; | 2351 var ret = new ListValue(argValues, node.isConst, listType, node.span); |
| 2392 var value = new Value(world.listType, code, node.span); | 2352 if (ret.isConst) return ret.getGlobalValue(); |
| 2393 if (node.isConst) { | 2353 return ret; |
| 2394 final immutableList = world.immutableListType; | |
| 2395 final immutableListCtor = immutableList.getConstructor('from'); | |
| 2396 final result = immutableListCtor.invoke(this, node, | |
| 2397 new Value.type(value.type, node.span), new Arguments(null, [value])); | |
| 2398 value = world.gen.globalForConst( | |
| 2399 new ConstListValue(immutableList, argValues, 'const $code', | |
| 2400 result.code, node.span), | |
| 2401 argValues); | |
| 2402 } | |
| 2403 return value; | |
| 2404 } | 2354 } |
| 2405 | 2355 |
| 2406 | 2356 |
| 2407 visitMapExpression(MapExpression node) { | 2357 visitMapExpression(MapExpression node) { |
| 2408 // Special case the empty non-const map. | 2358 // Special case the empty non-const map. |
| 2409 if (node.items.length == 0 && !node.isConst) { | 2359 if (node.items.length == 0 && !node.isConst) { |
| 2410 return world.mapType.getConstructor('').invoke(this, node, | 2360 return world.mapType.getConstructor('').invoke(this, node, |
| 2411 new Value.type(world.mapType, node.span), Arguments.EMPTY); | 2361 new Value.type(world.mapType, node.span), Arguments.EMPTY); |
| 2412 } | 2362 } |
| 2413 | 2363 |
| 2414 var argValues = []; | 2364 var values = new List<Value>(); |
|
Jennifer Messerly
2012/01/09 19:06:54
perhaps:
var values = <Value>[];
?
jimhug
2012/01/09 21:34:30
Done.
| |
| 2415 var argsCode = []; | 2365 var valueType = world.varType, keyType = world.stringType; |
| 2416 var type = null; | 2366 var mapType = world.mapType; // TODO(jimhug): immutable type? |
| 2417 if (node.type != null) { | 2367 if (node.valueType !== null) { |
| 2418 // node.type is a map type, extract the type argument for the values. | 2368 if (node.keyType !== null) { |
| 2419 type = method.resolveType(node.type, true).typeArgsInOrder[1]; | 2369 keyType = method.resolveType(node.keyType, true); |
| 2420 if (node.isConst && (type is ParameterType || type.hasTypeParams)) { | 2370 // TODO(jimhug): Would be nice to allow arbitrary keys here (this is |
| 2371 // currently not allowed by the spec). | |
| 2372 if (!keyType.isString) { | |
| 2373 world.error('the key type of a map literal must be "String"', | |
| 2374 keyType.span); | |
| 2375 } | |
| 2376 if (node.isConst && (keyType is ParameterType || keyType.hasTypeParams)) { | |
|
Jennifer Messerly
2012/01/09 19:06:54
long line
Jennifer Messerly
2012/01/09 19:06:54
keyType.isUnboundType, or something like that? Whe
jimhug
2012/01/09 21:34:30
Done.
jimhug
2012/01/09 21:34:30
Good idea - for longer-term cleanup.
On 2012/01/09
| |
| 2377 world.error('type parameter cannot be used in const map literals'); | |
| 2378 } | |
| 2379 } | |
| 2380 | |
| 2381 valueType = method.resolveType(node.valueType, true); | |
| 2382 if (node.isConst && (valueType is ParameterType || valueType.hasTypeParams )) { | |
| 2421 world.error('type parameter cannot be used in const map literals'); | 2383 world.error('type parameter cannot be used in const map literals'); |
| 2422 } | 2384 } |
| 2423 } | |
| 2424 for (int i = 0; i < node.items.length; i += 2) { | |
| 2425 // TODO(jimhug): Use node.type or other type inference here. | |
| 2426 // TODO(jimhug): Would be nice to allow arbitrary keys here (this is | |
| 2427 // currently not allowed by the spec). | |
| 2428 var key = visitTypedValue(node.items[i], world.stringType); | |
| 2429 final valueItem = node.items[i+1]; | |
| 2430 var value = visitTypedValue(valueItem, type); | |
| 2431 argValues.add(key); | |
| 2432 argValues.add(value); | |
| 2433 | 2385 |
| 2434 if (node.isConst) { | 2386 mapType = mapType.getOrMakeConcreteType([keyType, valueType]); |
| 2435 if (!key.isConst || !value.isConst) { | |
| 2436 world.error('const map can only contain const values', | |
| 2437 valueItem.span); | |
| 2438 argsCode.add(key.code); | |
| 2439 argsCode.add(value.code); | |
| 2440 } else { | |
| 2441 argsCode.add(key.canonicalCode); | |
| 2442 argsCode.add(value.canonicalCode); | |
| 2443 } | |
| 2444 } else { | |
| 2445 argsCode.add(key.code); | |
| 2446 argsCode.add(value.code); | |
| 2447 } | |
| 2448 } | 2387 } |
| 2449 | 2388 |
| 2450 var argList = '[${Strings.join(argsCode, ", ")}]'; | 2389 for (int i = 0; i < node.items.length; i += 2) { |
| 2451 var items = new Value(world.listType, argList, node.span); | 2390 var key = visitTypedValue(node.items[i], keyType); |
| 2452 var tp = world.corelib.topType; | 2391 if (node.isConst && !key.isConst) { |
| 2453 Member f = node.isConst ? tp.getMember('_constMap') : tp.getMember('_map'); | 2392 world.error('const map can only contain const keys', key.span); |
| 2454 var value = f.invoke(this, node, new Value.type(tp, null), | 2393 } |
| 2455 new Arguments(null, [items])); | 2394 values.add(key); |
| 2456 | 2395 |
| 2457 if (node.isConst) { | 2396 var value = visitTypedValue(node.items[i+1], valueType); |
|
Jennifer Messerly
2012/01/09 19:06:54
nit: spacing on i + 1
jimhug
2012/01/09 21:34:30
Done.
| |
| 2458 value = new ConstMapValue(value.type, argValues, value.code, | 2397 if (node.isConst && !value.isConst) { |
| 2459 value.code, value.span); | 2398 world.error('const map can only contain const values', value.span); |
| 2460 return world.gen.globalForConst(value, argValues); | 2399 } |
| 2461 } else { | 2400 values.add(value); |
| 2462 return value; | |
| 2463 } | 2401 } |
| 2402 | |
| 2403 var ret = new MapValue(values, node.isConst, mapType, node.span); | |
| 2404 if (ret.isConst) return ret.getGlobalValue(); | |
| 2405 return ret; | |
| 2464 } | 2406 } |
| 2465 | 2407 |
| 2466 visitConditionalExpression(ConditionalExpression node) { | 2408 visitConditionalExpression(ConditionalExpression node) { |
| 2467 var test = visitBool(node.test); | 2409 var test = visitBool(node.test); |
| 2468 var trueBranch = visitValue(node.trueBranch); | 2410 var trueBranch = visitValue(node.trueBranch); |
| 2469 var falseBranch = visitValue(node.falseBranch); | 2411 var falseBranch = visitValue(node.falseBranch); |
| 2470 | 2412 |
| 2471 var code = '${test.code} ? ${trueBranch.code} : ${falseBranch.code}'; | 2413 var code = '${test.code} ? ${trueBranch.code} : ${falseBranch.code}'; |
| 2472 return new Value(Type.union(trueBranch.type, falseBranch.type), code, | 2414 return new Value(Type.union(trueBranch.type, falseBranch.type), code, |
| 2473 node.span); | 2415 node.span); |
| 2474 } | 2416 } |
| 2475 | 2417 |
| 2476 visitIsExpression(IsExpression node) { | 2418 visitIsExpression(IsExpression node) { |
| 2477 var value = visitValue(node.x); | 2419 var value = visitValue(node.x); |
| 2478 var type = method.resolveType(node.type, false); | 2420 var type = method.resolveType(node.type, false); |
| 2479 return value.instanceOf(this, type, node.span, node.isTrue); | 2421 return value.instanceOf(this, type, node.span, node.isTrue); |
| 2480 } | 2422 } |
| 2481 | 2423 |
| 2482 visitParenExpression(ParenExpression node) { | 2424 visitParenExpression(ParenExpression node) { |
| 2483 var body = visitValue(node.body); | 2425 var body = visitValue(node.body); |
| 2484 if (body.isConst) { | 2426 // Assumption implicit here that const values never need parens... |
| 2485 return new EvaluatedValue(body.type, body.actualValue, | 2427 if (body.isConst) return body; |
| 2486 '(${body.canonicalCode})', node.span); | |
| 2487 } | |
| 2488 return new Value(body.type, '(${body.code})', node.span); | 2428 return new Value(body.type, '(${body.code})', node.span); |
| 2489 } | 2429 } |
| 2490 | 2430 |
| 2491 visitDotExpression(DotExpression node) { | 2431 visitDotExpression(DotExpression node) { |
| 2492 // Types are legal targets of . | 2432 // Types are legal targets of . |
| 2493 var target = node.self.visit(this); | 2433 var target = node.self.visit(this); |
| 2494 return target.get_(this, node.name.name, node.name); | 2434 return target.get_(this, node.name.name, node.name); |
| 2495 } | 2435 } |
| 2496 | 2436 |
| 2497 visitVarExpression(VarExpression node) { | 2437 visitVarExpression(VarExpression node) { |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2669 result.add(new Value(world.varType, '\$$i', null, /*needsTemp:*/false)); | 2609 result.add(new Value(world.varType, '\$$i', null, /*needsTemp:*/false)); |
| 2670 } | 2610 } |
| 2671 for (int i = bareCount; i < length; i++) { | 2611 for (int i = bareCount; i < length; i++) { |
| 2672 var name = getName(i); | 2612 var name = getName(i); |
| 2673 if (name == null) name = '\$$i'; | 2613 if (name == null) name = '\$$i'; |
| 2674 result.add(new Value(world.varType, name, null, /*needsTemp:*/false)); | 2614 result.add(new Value(world.varType, name, null, /*needsTemp:*/false)); |
| 2675 } | 2615 } |
| 2676 return new Arguments(nodes, result); | 2616 return new Arguments(nodes, result); |
| 2677 } | 2617 } |
| 2678 } | 2618 } |
| OLD | NEW |