@@ -259,6 +259,34 @@ define([], function asm_llvm() {
259259 } ;
260260 test_types ( ) ;
261261
262+ // ### Use-site coercions.
263+ // The different use types. This is top-down context for
264+ // expression parsing. (See the "Parser" section below.)
265+ var Use = {
266+ ToDouble : "ToDouble" ,
267+ ToInt : "ToInt" ,
268+ Void : "Void" ,
269+ NoCoercion : "NoCoercion" // usually works out to "ToInt" in practice
270+ } ;
271+ // Utility methods.
272+ var Uses = {
273+ toType : ( function ( ) {
274+ var map = Object . create ( null ) ;
275+ map [ Use . ToDouble ] = Type . Doublish ;
276+ map [ Use . ToInt ] = Type . Intish ;
277+ map [ Use . Void ] = Type . Void ;
278+ // The map of NoCoercion to Intish differs from Mozilla;
279+ // we want to default to Intish so we don't have to lookahead
280+ // to parse the int-coercion suffix. We will fail typechecking
281+ // later if our assumption turns out to be mistaken.
282+ map [ Use . NoCoercion ] = Type . Intish ;
283+ return function ( use ) {
284+ console . assert ( map [ use ] ) ;
285+ return map [ use ] ;
286+ } ;
287+ } ) ( )
288+ } ;
289+
262290 // ### Operator and standard library type tables.
263291
264292 // Unary operator types, from
@@ -278,6 +306,14 @@ define([], function asm_llvm() {
278306 '~~' : Types . FunctionTypes (
279307 [ Types . Arrow ( [ Types . Double ] , Types . Signed ) ] )
280308 } ;
309+ // Use-site coercions.
310+ Uses . unary = {
311+ '+' : Use . ToDouble ,
312+ '-' : Use . ToDouble ,
313+ '~' : Use . ToInt ,
314+ '~~' : Use . ToInt ,
315+ '!' : Use . NoCoercion
316+ } ;
281317
282318 // Binary operator types, from
283319 // http://asmjs.org/spec/latest/#binary-operators
@@ -299,15 +335,25 @@ define([], function asm_llvm() {
299335 '>>>' : Types . FunctionTypes (
300336 [ Types . Arrow ( [ Types . Intish , Types . Intish ] , Types . Unsigned ) ] )
301337 } ;
338+ Uses . binary = {
339+ '+' : Use . NoCoercion ,
340+ '-' : Use . NoCoercion ,
341+ '*' : Use . ToDouble ,
342+ '/' : Use . ToDouble ,
343+ '%' : Use . ToDouble ,
344+ '>>>' : Use . ToInt
345+ } ;
302346 [ '|' , '&' , '^' , '<<' , '>>' ] . forEach ( function ( op ) {
303347 Types . binary [ op ] = Types . FunctionTypes (
304348 [ Types . Arrow ( [ Types . Intish , Types . Intish ] , Types . Signed ) ] ) ;
349+ Uses . binary [ op ] = Use . ToInt ;
305350 } ) ;
306351 [ '<' , '<=' , '>' , '>=' , '==' , '!=' ] . forEach ( function ( op ) {
307352 Types . binary [ op ] = Types . FunctionTypes (
308353 [ Types . Arrow ( [ Types . Signed , Types . Signed ] , Types . Int ) ,
309354 Types . Arrow ( [ Types . Unsigned , Types . Unsigned ] , Types . Int ) ,
310355 Types . Arrow ( [ Types . Double , Types . Double ] , Types . Int ) ] ) ;
356+ Uses . binary [ op ] = Use . NoCoercion ;
311357 } ) ;
312358
313359 // Standard library member types, from
@@ -1576,7 +1622,13 @@ define([], function asm_llvm() {
15761622 // precedence, for all of the ten binary precedence levels
15771623 // that JavaScript defines.
15781624 //
1625+ // Like the [SpiderMonkey asm.js parser][sm], we pass some coercion
1626+ // information top-down to allow single-pass type checking of
1627+ // call sites (including function table call sites). (Unlike
1628+ // SpiderMonkey, we do additive chain processing bottom-up.)
1629+
15791630 // [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser
1631+ // [sm]: https://hg.mozilla.org/mozilla-central/file/42bcb974cfdd/js/src/ion/AsmJS.cpp#l552
15801632
15811633 var parseTopLevel ; // forward declaration
15821634
@@ -1770,7 +1822,7 @@ define([], function asm_llvm() {
17701822 }
17711823
17721824 if ( allowEmpty && tokType === _comma ) { elts . push ( null ) ; }
1773- else { elts . push ( parseExpression ( true ) ) ; }
1825+ else { elts . push ( parseExpression ( true , Use . NoCoercion ) ) ; }
17741826 }
17751827 return elts ;
17761828 } ;
@@ -1780,7 +1832,7 @@ define([], function asm_llvm() {
17801832 // `new`, or an expression wrapped in punctuation like `()`, `[]`,
17811833 // or `{}`.
17821834
1783- var parseExprAtom = function ( ) {
1835+ var parseExprAtom = function ( use ) {
17841836 if ( tokType === _name ) {
17851837 var id = parseIdent ( ) ;
17861838 var binding = moduleLookup ( id ) ;
@@ -1800,7 +1852,7 @@ define([], function asm_llvm() {
18001852
18011853 } else if ( tokType === _parenL ) {
18021854 next ( ) ;
1803- var val = parseExpression ( ) ;
1855+ var val = parseExpression ( use ) ;
18041856 expect ( _parenR ) ;
18051857 return val ;
18061858
@@ -1844,6 +1896,8 @@ define([], function asm_llvm() {
18441896 } else if ( property . andy ) {
18451897 // Try to parse as a function table lookup:
18461898 // `x:Identifier[index:Expression & n:NumericLiteral](arg:Expression,...)`
1899+
1900+ //return TableBinding.New(basem
18471901 raise ( startPos , "unimplemented" ) ;
18481902 } else {
18491903 raise ( startPos , "bad member expression" ) ;
@@ -1852,13 +1906,13 @@ define([], function asm_llvm() {
18521906
18531907 // Parse call, dot, and `[]`-subscript expressions.
18541908
1855- var parseSubscripts = function ( base , noCalls ) {
1909+ var parseSubscripts = function ( base , use , noCalls ) {
18561910 if ( eat ( _dot ) ) {
18571911 raise ( lastStart , "operator not allowed: ." ) ;
18581912 } else if ( eat ( _bracketL ) ) {
18591913 base = parseBracketExpression ( base ) ;
18601914 expect ( _bracketR ) ;
1861- return parseSubscripts ( base , noCalls ) ;
1915+ return parseSubscripts ( base , use , noCalls ) ;
18621916 } else if ( ! noCalls && eat ( _parenL ) ) {
18631917 /* XXX handle base=ForwardRef */
18641918 var startPos = lastStart ;
@@ -1883,17 +1937,17 @@ define([], function asm_llvm() {
18831937 } else {
18841938 raise ( startPos , "bad call expression" ) ;
18851939 }
1886- return parseSubscripts ( binding , noCalls ) ;
1940+ return parseSubscripts ( binding , use , noCalls ) ;
18871941 } else { return base ; }
18881942 } ;
18891943
1890- var parseExprSubscripts = function ( ) {
1891- return parseSubscripts ( parseExprAtom ( ) ) ;
1944+ var parseExprSubscripts = function ( use ) {
1945+ return parseSubscripts ( parseExprAtom ( use ) , use ) ;
18921946 } ;
18931947
18941948 // Parse unary operators, both prefix and postfix.
18951949
1896- function parseMaybeUnary ( noIn ) {
1950+ function parseMaybeUnary ( use ) {
18971951 var node ;
18981952 if ( tokType . prefix ) {
18991953 var opPos = tokStart ;
@@ -1905,7 +1959,7 @@ define([], function asm_llvm() {
19051959 }
19061960 console . assert ( ! update ) ;
19071961 next ( ) ;
1908- var argument = parseMaybeUnary ( noIn ) ;
1962+ var argument = parseMaybeUnary ( Uses . unary [ operator ] ) ;
19091963 // Special case the negation of a constant.
19101964 if ( ConstantBinding . hasInstance ( argument ) && operator === '-' ) {
19111965 return argument . negate ( ) ;
@@ -1917,7 +1971,7 @@ define([], function asm_llvm() {
19171971 }
19181972 return TempBinding . New ( ty ) ;
19191973 }
1920- var expr = parseExprSubscripts ( ) ;
1974+ var expr = parseExprSubscripts ( use ) ;
19211975 if ( tokType . postfix && ! canInsertSemicolon ( ) ) {
19221976 raise ( tokStart , "postfix operators not allowed" ) ;
19231977 }
@@ -1933,11 +1987,11 @@ define([], function asm_llvm() {
19331987 // defer further parser to one of its callers when it encounters an
19341988 // operator that has a lower precedence than the set it is parsing.
19351989
1936- var parseExprOp = function ( left , minPrec , noIn ) {
1990+ var parseExprOp = function ( left , minPrec , use ) {
19371991 var TWO_TO_THE_TWENTY = 0x100000 ;
19381992 var prec = tokType . binop ;
19391993 console . assert ( prec !== null , tokType ) ;
1940- if ( prec !== undefined && ( ! noIn || tokType !== _in ) ) {
1994+ if ( prec !== undefined ) {
19411995 if ( prec > minPrec ) {
19421996 var additiveChain = 0 ;
19431997 var opPos = tokStart ;
@@ -1946,8 +2000,9 @@ define([], function asm_llvm() {
19462000 if ( ! ty ) {
19472001 raise ( opPos , operator + " not allowed" ) ;
19482002 }
2003+ use = Uses . binary [ operator ] ; //XXXX probably wrong
19492004 next ( ) ;
1950- var right = parseExprOp ( parseMaybeUnary ( noIn ) , prec , noIn ) ;
2005+ var right = parseExprOp ( parseMaybeUnary ( use ) , prec , use ) ;
19512006 ty = ty . apply ( [ left . type , right . type ] ) ;
19522007 if ( ty === null && ( operator === '+' || operator === '-' ) ) {
19532008 /* Special validation for "AdditiveExpression" */
@@ -2001,27 +2056,27 @@ define([], function asm_llvm() {
20012056 binding . andAmount = right . value ;
20022057 }
20032058 }
2004- return parseExprOp ( binding , minPrec , noIn ) ;
2059+ return parseExprOp ( binding , minPrec , use ) ;
20052060 }
20062061 }
20072062 return left ;
20082063 } ;
20092064
2010- var parseExprOps = function ( noIn ) {
2011- return parseExprOp ( parseMaybeUnary ( noIn ) , - 1 , noIn ) ;
2065+ var parseExprOps = function ( use ) {
2066+ return parseExprOp ( parseMaybeUnary ( use ) , - 1 , use ) ;
20122067 } ;
20132068
20142069 // Parse a ternary conditional (`?:`) operator.
20152070
2016- var parseMaybeConditional = function ( noIn ) {
2017- var expr = parseExprOps ( noIn ) ;
2071+ var parseMaybeConditional = function ( use ) {
2072+ var expr = parseExprOps ( use ) ;
20182073 var startPos = tokStart ;
20192074 if ( eat ( _question ) ) {
20202075 var test = expr ;
20212076 typecheck ( test . type , Types . Int , "conditional test" , startPos ) ;
20222077 var consequent = parseExpression ( true ) ;
20232078 expect ( _colon ) ;
2024- var alternate = parseExpression ( true , noIn ) ;
2079+ var alternate = parseExpression ( true , use ) ;
20252080 var ty ;
20262081 if ( consequent . type . isSubtypeOf ( Types . Int ) &&
20272082 alternate . type . isSubtypeOf ( Types . Int ) ) {
@@ -2044,16 +2099,16 @@ define([], function asm_llvm() {
20442099 // Parse an assignment expression. This includes applications of
20452100 // operators like `+=`.
20462101
2047- var parseMaybeAssign = function ( noIn ) {
2048- var left = parseMaybeConditional ( noIn ) ;
2102+ var parseMaybeAssign = function ( use ) {
2103+ var left = parseMaybeConditional ( use ) ;
20492104 if ( tokType . isAssign ) {
20502105 var startPos = tokStart ;
20512106 var operator = tokVal ;
20522107 if ( operator !== '=' ) {
20532108 raise ( startPos , "Operator disallowed: " + operator ) ;
20542109 }
20552110 next ( ) ;
2056- var right = parseMaybeAssign ( noIn ) ;
2111+ var right = parseMaybeAssign ( use ) ;
20572112 // Check that `left` is an lval. First, let's check
20582113 // the `x:Identifier = ...` case.
20592114 if ( LocalBinding . hasInstance ( left ) ) {
@@ -2081,12 +2136,12 @@ define([], function asm_llvm() {
20812136 // sequences (in argument lists, array literals, or object literals)
20822137 // or the `in` operator (in for loops initalization expressions).
20832138
2084- parseExpression = function ( noComma , noIn ) {
2085- var expr = parseMaybeAssign ( noIn ) ;
2139+ parseExpression = function ( noComma , use ) {
2140+ var expr = parseMaybeAssign ( use ) ;
20862141 if ( ! noComma && tokType === _comma ) {
20872142 var expressions = [ expr ] ;
20882143 while ( eat ( _comma ) ) {
2089- expressions . push ( expr = parseMaybeAssign ( noIn ) ) ;
2144+ expressions . push ( expr = parseMaybeAssign ( use ) ) ;
20902145 }
20912146 }
20922147 return expr ;
@@ -2095,9 +2150,9 @@ define([], function asm_llvm() {
20952150 // Used for constructs like `switch` and `if` that insist on
20962151 // parentheses around their expression.
20972152
2098- var parseParenExpression = function ( ) {
2153+ var parseParenExpression = function ( use ) {
20992154 expect ( _parenL ) ;
2100- var val = parseExpression ( ) ;
2155+ var val = parseExpression ( use ) ;
21012156 expect ( _parenR ) ;
21022157 return val ;
21032158 } ;
@@ -2154,7 +2209,7 @@ define([], function asm_llvm() {
21542209 // Parse a while loop.
21552210 next ( ) ;
21562211 startPos = tokStart ;
2157- var whileTest = parseParenExpression ( ) ;
2212+ var whileTest = parseParenExpression ( Use . NoCoercion ) ;
21582213 typecheck ( whileTest . type , Types . Int , "while loop condition" ,
21592214 startPos ) ;
21602215 module . func . labels . push ( loopLabel ) ;
@@ -2170,7 +2225,7 @@ define([], function asm_llvm() {
21702225 module . func . labels . pop ( ) ;
21712226 expect ( _while ) ;
21722227 startPos = tokStart ;
2173- var doTest = parseParenExpression ( ) ;
2228+ var doTest = parseParenExpression ( Use . NoCoercion ) ;
21742229 semicolon ( ) ;
21752230 typecheck ( doTest . type , Types . Int , "do-while loop condition" ,
21762231 startPos ) ;
@@ -2194,7 +2249,7 @@ define([], function asm_llvm() {
21942249 } else if ( starttype === _if ) {
21952250 next ( ) ;
21962251 startPos = tokStart ;
2197- var ifTest = parseParenExpression ( ) ;
2252+ var ifTest = parseParenExpression ( Use . NoCoercion ) ;
21982253 typecheck ( ifTest . type , Types . Int , "if statement condition" ,
21992254 startPos ) ;
22002255 var consequent = parseStatement ( ) ;
@@ -2225,7 +2280,7 @@ define([], function asm_llvm() {
22252280 } else if ( starttype === _switch ) {
22262281 next ( ) ;
22272282 startPos = tokStart ;
2228- var switchTest = parseParenExpression ( ) ;
2283+ var switchTest = parseParenExpression ( Use . NoCoercion ) ;
22292284 typecheck ( switchTest , Types . Signed , "switch discriminant" ,
22302285 startPos ) ;
22312286 var cases = [ ] ;
0 commit comments