/* -*- mode: java; mode: font-lock; tab-width: 4; insert-tabs-mode: nil; indent-tabs-mode: nil -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is [Open Source Virtual Machine.]. * * The Initial Developer of the Original Code is * Adobe System Incorporated. * Portions created by the Initial Developer are Copyright (C) 2004-2006 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Adobe AS3 Team * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ package com.hurlant.eval.parse { import com.hurlant.eval.*; import com.hurlant.eval.ast.*; // PATTERNS == Array //type PATTERNS = [IParserPattern]; // type IParserPattern = // ( ObjectPattern // , ArrayPattern // , SimplePattern // , IdentifierPattern ); // // type Array = [FieldPattern]; // type FieldPattern = FieldPattern; //type ENV = [FIXTURES]; //type PRAGMAS = Pragmas; //type PRAGMA_ENV = [PRAGMAS]; public class Parser { //type IAlpha = (NoColon, AllowColon); const noColon = new NoColon; const allowColon = new AllowColon; //type IBeta = (NoIn, AllowIn); const noIn = new NoIn; const allowIn = new AllowIn; //type IGamma = (NoExpr, AllowExpr); const noExpr = new NoExpr; const allowExpr = new AllowExpr; //type ITau = (GlobalBlk, ClassBlk, InterfaceBlk, LocalBlk); const globalBlk = new GlobalBlk; const classBlk = new ClassBlk; const interfaceBlk = new InterfaceBlk; const localBlk = new LocalBlk; /* const AbbrevIfElse = 0; const AbbrevDoWhile = AbbrevIfElse + 1; const AbbrevFunction = AbbrevDoWhile + 1; const Abbrev = AbbrevFunction + 1; const Full = Abbrev + 1; */ //type IOmega = (FullStmt, AbbrevStmt); const fullStmt = new FullStmt; const abbrevStmt = new AbbrevStmt; var scan : Scanner; var cx: Context; function Parser(src,topFixtures:Array = null) { if (topFixtures==null) { topFixtures = []; } this.cx = new Context (topFixtures) this.scan = new Scanner (src,"") } var defaultNamespace: IAstNamespace; var currentPackageName: String; var currentClassName: String; var coordList; function hd (ts:TokenStream):int { //Debug.enter("hd ",ts.head()); var tk:int = Token.tokenKind (ts.head()); //print ("hd ",tk); return tk; } function hd2 (ts:TokenStream):int { //Debug.enter("hd ",ts.head()); var tk:int = Token.tokenKind (ts.head2()); //print ("hd ",tk); return tk; } function eat (ts:TokenStream,tc:int) { //print("eating ",Token.tokenText(tc)); var tk:int = hd (ts); if (tk == tc) { return tl (ts); } throw "expecting "+Token.tokenText(tc)+" found "+Token.tokenText(tk); } /* Replace the first token in the stream with another one. Raise an exception if the first token is not of a specified kind. */ function swap (ts,t0,t1) { var tk = hd (ts); if (tk === t0) { ts.ts.position = ts.n-4; ts.ts.writeInt (t1); return t1; } throw "expecting "+Token.tokenText(t0)+" found "+Token.tokenText(tk); } function tl (ts:TokenStream) : TokenStream { ts.next (); return ts; //return new TokenStream (ts.ts,ts.n+1); } //ts.slice (1,ts.length); /* Notation [] list (fl,el) head fl fixture list el expr list - il init list sl stmt list it init target = VAR, LET (default=LET) ie init expr se set expr initexpr init it (fl,el) il letexpr let (fl,el) el block (fl,el) sl Bindings var x = y [x], init VAR () [x=y] var [x] = y [x], init VAR ([t0],[init t0=y]) [x=t0[0]] let (x=y) ... let ([x], init x=y) ... let x=y [x], init x=y] Assignments x = y [], set x=y [x] = y [], let ([t0],[init t0=y]) [set x=t0[0]] Blocks { } () {} {stmt} () {stmt} {let x} ([x],[x=undef]) {} is undef the right val? let (x) {} ([x],[x=undef]) {} what about reping uninit? Mixture { var x = y; let z = y } => ([x],[]) { blkstmt ([z],[]) { init VAR () x=y; init LET () z=y } } assignment, create a let for each aggregate, a temp for each level of nesting x = y set x=y [x] = y let (t0=y) set x=t0[0] [[x]] = y let (t0=y) let (t1=t0[0]) set x=t1[0] [[x],[x]] = y let (t0=y) let (t1=t0[0]) set x=t1[0] , let (t1=t0[1]) set x=t1[0] initialization, create an init rather than a set for the leaf nodes var x = v let (t0=v) init () [x=t0] var [x] = v let (t0=v) init () [x=t0[0]] var [x,[y,z]] = v let (t0=v) init () [x=t0[0]] , let (t1=t0[1]) init () [y=t1[0], z=t1[1]] var [x,[y,[z]]] = v let (t0=v) init () [x=t0[0]] , let (t1=t0[1]) init () [y=t1[0] , let (t2=t1[0]) init () [z=t2[0]] for initialization, we need to know the namespace and the target so we make INITS to go into the InitExpr inside the LetExpr let x = y init x=y flattening. var [x,[y,z]] = v let (t0=v) init () [x=t0[0]] , let (t1=t0[1]) init () [y=t1[0], z=t1[0]] t0=v x=t0[0] t1=t0[1] y=t1[0] z=t1[1] head = {[t0,x,t1,y,z], flattening doesn't work because it mixes named and temporary fixtures lets and params have the same problem. both allow destructuring patterns that can expand into a nested expression. let ([x,[y,z]]=v) ... top heads only have named fixtures. sub heads only have temporaries. temporaries are always immediately initialized. a head is a list of fixtures and a list of expressions. the expressions get evaluated in the scope outside the head. settings is a sub head. it has temporary fixtures and init exprs that target instance variables */ function desugarAssignmentPattern (p: IParserPattern, t: IAstTypeExpr, e: IAstExpr, op: IAstAssignOp) : Array //[FIXTURES, IAstExpr] { return desugarPattern (p,t,e,null,null,null,op); } function desugarBindingPattern (p: IParserPattern, t: IAstTypeExpr, e: IAstExpr, ns: IAstNamespace?, it: IAstInitTarget?, ro: Boolean?) : Array //[FIXTURES, IAstExpr] { return desugarPattern (p,t,e,ns,it,ro,null); } function desugarPattern (p: IParserPattern, t: IAstTypeExpr, e: IAstExpr, ns: IAstNamespace?, it: IAstInitTarget ?, ro: Boolean?, op: IAstAssignOp?) : Array //[FIXTURES, IAstExpr] { return desugarSubPattern (p,t,e,0); function identExprFromExpr (e: IAstExpr) : IAstIdentExpr { Debug.enter("identExprFromExpr",""); var x = e; if (x is LexicalRef) { var ie = (e as LexicalRef).ident; } else { throw "invalid init lhs " + e; } Debug.exit("identExprFromExpr",""); return ie; } function desugarSubPattern (p: IParserPattern, t: IAstTypeExpr, e: IAstExpr, n: int) : Array //[FIXTURES, IAstExpr] { Debug.enter("desugarSubPattern",""); var x = p; if (x is IdentifierPattern) { var nm = new PropName ({ns:ns,id:(p as IdentifierPattern).ident}); var fx = new ValFixture (t,ro); var fxtrs = [[nm,fx]]; if (e !== null) { var inits = [[nm,e]]; } else { var inits = []; } var expr = new InitExpr (it, new Head ([],[]), inits); } else if (x is SimplePattern) { if (e === null) throw "simple pattern without initializer"; var fxtrs = []; if (it != null) { // we have an init target so must be an init var ie = identExprFromExpr ((p as SimplePattern).expr); var nm = cx.resolveIdentExpr (ie,it); var expr = new InitExpr (it, new Head ([],[]), [[nm,e]]); } else { var expr = new SetExpr (op,(p as SimplePattern).expr,e); } } else { var tn = new TempName (n); var fxtrs = []; var exprs = []; var ptrns = (p as Object).ptrns; for (var i=0; i ( TypeExpression ) .< TypeExpressionList > e.g. A.,D.>> */ function propertyName (ts: TokenStream) : Array //[TokenStream, IAstIdentExpr] { Debug.enter("Parser::propertyName ", ts); switch (hd (ts)) { /* FIXME: this is a grammar bug case Token.LeftParen: var [ts1,nd1] = typeExpression (tl (ts)); ts1 = eat (ts1,Token.RightParen); break; */ default: //var [ts1,nd1] = nonAttributeQualifiedName (ts); var tmp = nonAttributeQualifiedName (ts); var ts1 = tmp[0], nd1 = tmp[1]; } switch (hd (ts1)) { case Token.LeftDotAngle: //var [ts2,nd2] = typeExpressionList (tl (ts1)); var tmp = typeExpressionList (tl (ts1)); var ts2 = tmp[0], nd2 = tmp[1]; switch (hd (ts2)) { case Token.UnsignedRightShift: // downgrade >>> to >> to eat one > ts2 = swap (ts2,Token.UnsignedRightShift,Token.RightShift); break; case Token.RightShift: // downgrade >> to > to eat one > ts2 = swap (ts2,Token.RightShift,Token.GreaterThan); break; default: ts2 = eat (ts2,Token.GreaterThan); break; } break; default: //var [ts2,nd2] = [ts1,nd1]; var ts2 = ts1, nd2 = nd1; break; } Debug.exit("Parser::propertyName ", ts2); return [ts2,nd2]; } /* PrimaryName Path . PropertyName PropertyName */ function primaryName (ts: TokenStream) : Array //[TokenStream, IAstIdentExpr] { Debug.enter("Parser::primaryName ", ts); switch (hd (ts)) { case Token.Identifier: switch (hd2 (ts)) { case Token.Dot: var tx = Token.tokenText(ts.head()); //var [ts1,nd1] = path (tl (tl (ts)), [tx]); var tmp = path (tl (tl (ts)), [tx]); var ts1=tmp[0], nd1=tmp[1]; //var [ts2,nd2] = propertyName (ts1); var tmp = propertyName (ts1); var ts2=tmp[0], nd2=tmp[1]; nd2 = new UnresolvedPath (nd1,nd2); break; default: //var [ts2,nd2] = propertyName (ts); var tmp = propertyName (ts); var ts2=tmp[0], nd2=tmp[1]; break; } break; default: //var [ts2,nd2] = propertyName (ts); var tmp = propertyName (ts); var ts2=tmp[0], nd2=tmp[1]; break; } Debug.exit("Parser::primaryName ", ts2); return [ts2,nd2]; } /* Path Identifier Path . Identifier */ function path (ts: TokenStream, nd /*: [IDENT]*/ ) /* FIXME: verifier bug */ : Array //[TokenStream, [IDENT]] { Debug.enter("Parser::path ", ts); switch (hd (ts)) { case Token.Identifier: switch (hd2 (ts)) { case Token.Dot: nd.push(Token.tokenText(ts.head())); //var [ts1,nd1] = path (tl (tl (ts)), nd); var tmp = path (tl (tl (ts)), nd); var ts1=tmp[0], nd1=tmp[1]; break; default: //var [ts1,nd1] = [ts,nd]; var ts1=ts, nd1=nd; break; } break; default: //var [ts1,nd1] = [ts,nd]; var ts1=ts, nd1=nd; break; } Debug.exit("Parser::path ", ts1); return [ts1,nd1]; } function parenExpression (ts: TokenStream) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::parenExpression ", ts); var ts1 = eat (ts,Token.LeftParen); //var [ts2,ndx] = assignmentExpression (ts1, allowIn); var tmp = assignmentExpression (ts1, allowIn); var ts2=tmp[0], ndx=tmp[1]; var tsx = eat (ts2,Token.RightParen); Debug.exit("Parser::parenExpression ", tsx); return [tsx, ndx]; } function parenListExpression (ts: TokenStream) : Array //[TokenStream, [IAstExpr]] { Debug.enter("Parser::parenListExpression ", ts); var ts1 = eat (ts,Token.LeftParen); //var [ts2,ndx] = listExpression (ts1, allowIn); var tmp = listExpression (ts1, allowIn); var ts2=tmp[0], ndx=tmp[1]; var tsx = eat (ts2,Token.RightParen); Debug.exit("Parser::parenListExpression ", tsx); return [tsx, ndx]; } /* ObjectLiteral(noColon) { FieldList } ObjectLiteral(allowColon) { FieldList } { FieldList } : TypeExpression */ function objectLiteral (ts: TokenStream /*, alpha: IAlpha*/) : Array //[TokenStream, IAstTypeExpr] { Debug.enter("Parser::objectLiteral ", ts); var alpha: IAlpha = allowColon; // FIXME need to get this from caller ts = eat (ts,Token.LeftBrace); //var [ts1,nd1] = fieldList (ts); var tmp = fieldList (ts); var ts1=tmp[0], nd1=tmp[1]; ts1 = eat (ts1,Token.RightBrace); switch (alpha) { case allowColon: switch (hd (ts1)) { case Token.Colon: //var [ts2,nd2] = typeExpression (tl (ts1)); var tmp = typeExpression (tl (ts1)); var ts2=tmp[0], nd2=tmp[1]; break; default: //var [ts2,nd2] = [ts1,new ObjectType ([])]; // FIXME I mean {*} var tmp = [ts1,new ObjectType ([])]; // FIXME I mean {*} var ts2=tmp[0], nd2=tmp[1]; break; } break; default: //var [ts2,nd2] = [ts1,new ObjectType ([])]; // FIXME I mean {*} var tmp = [ts1,new ObjectType ([])]; // FIXME I mean {*} var ts2=tmp[0], nd2=tmp[1]; break; } Debug.exit("Parser::objectLiteral ", ts2); return [ts2,new LiteralExpr (new LiteralObject (nd1,nd2))]; } /* FieldList empty LiteralField LiteralField , LiteralFieldList */ function fieldList (ts: TokenStream) // : [TokenStream, [FIELD_TYPE]] { Debug.enter("Parser::fieldList ", ts); var nd1 = []; var ts1 = ts; if (hd (ts) !== Token.RightBrace) { //var [ts1,ndx] = literalField (ts); var tmp = literalField (ts); var ts1=tmp[0], ndx=tmp[1]; nd1.push (ndx); while (hd (ts1) === Token.Comma) { //var [ts1,ndx] = literalField (tl (ts1)); var tmp = literalField (tl (ts1)); var ts1=tmp[0], ndx=tmp[1]; nd1.push (ndx); } } Debug.exit("Parser::fieldList ", ts1); return [ts1,nd1]; } /* LiteralField FieldKind FieldName : AssignmentExpressionallowColon, allowIn get FieldName FunctionSignature FunctionExpressionBodyallowColon, allowIn set FieldName FunctionSignature FunctionExpressionBodyallowColon, allowIn */ function literalField (ts: TokenStream) : Array //[TokenStream, FIELD_TYPE] { Debug.enter("Parser::literalField",ts); switch (hd (ts)) { case Token.Const: //var [ts1,nd1] = [tl (ts), constTag]; var ts1= tl (ts), nd1=Ast.constTag; break; default: //var [ts1,nd1] = [ts,varTag]; var ts1=ts, nd1=Ast.varTag; break; } //var [ts2,nd2] = fieldName (ts); var tmp = fieldName (ts); var ts2=tmp[0], nd2=tmp[1]; ts2 = eat (ts2,Token.Colon); switch (hd (ts2)) { case Token.LeftBrace: // short cut to avoid recursion //var [ts3,nd3] = objectLiteral (ts2); var tmp = objectLiteral (ts2); var ts3=tmp[0], nd3=tmp[1]; break; case Token.LeftBracket: //var [ts3,nd3] = arrayLiteral (ts2); var tmp = arrayLiteral (ts2); var ts3=tmp[0], nd3=tmp[1]; break; default: //var [ts3,nd3] = assignmentExpression (ts2,allowIn); var tmp = assignmentExpression (ts2,allowIn); var ts3=tmp[0], nd3=tmp[1]; break; } Debug.exit("Parser::literalField", ts3); return [ts3, new LiteralField (nd1,nd2,nd3)]; } /* FieldName NonAttributeQualifiedName StringLiteral NumberLiteral ReservedIdentifier */ function fieldName (ts: TokenStream) : Array //[TokenStream, IAstIdentExpr] { Debug.enter("Parser::fieldName",ts); switch (hd (ts)) { case Token.StringLiteral: var nd = new Identifier (Token.tokenText (ts.head()),cx.pragmas.openNamespaces); //var [ts1,nd1] = [tl (ts), nd]; var ts1=tl (ts), nd1=nd; break; case Token.DecimalLiteral: case Token.DecimalIntegerLiteral: case Token.HexIntegerLiteral: throw "unsupported fieldName " + hd(ts); break; default: if (isReserved (hd (ts))) { var nd = new Identifier (Token.tokenText (ts.head()),cx.pragmas.openNamespaces); //var [ts1,nd1] = [tl (ts), nd]; var ts1=tl (ts), nd1=nd; // NOTE we use openNamespaces here to indicate that the name is // unqualified. the generator should use the expando namespace, // which is probably Public "". } else { //var [ts1,nd1] = nonAttributeQualifiedName (ts); var tmp = nonAttributeQualifiedName (ts); var ts1=tmp[0], nd1=tmp[1]; } break; } Debug.exit("Parser::fieldName"); return [ts1,nd1]; } /* ArrayLiteral(noColon) [ Elements ] ArrayLiteral(allowColon) [ Elements ] [ Elements ] : TypeExpression Elements ElementList ElementComprehension */ function arrayLiteral (ts: TokenStream) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::arrayLiteral ", ts); ts = eat (ts,Token.LeftBracket); //var [ts1,nd1] = elementList (ts); var tmp = elementList (ts); var ts1=tmp[0], nd1=tmp[1]; ts1 = eat (ts1,Token.RightBracket); Debug.exit("Parser::arrayLiteral ", ts1); return [ts1, new LiteralExpr (new LiteralArray (nd1,new ArrayType ([])))]; } /* ElementList empty LiteralElement , ElementList LiteralElement , ElementList LiteralElement AssignmentExpression(allowColon,allowIn) */ function elementList (ts: TokenStream) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::elementList ", ts); var nd1 = []; var ts1 = ts; if (hd (ts) !== Token.RightBracket) { switch (hd (ts)) { case Token.Comma: //var [ts1,ndx] = [tl (ts),new LiteralExpr (new LiteralUndefined)]; var ts1=tl (ts), ndx=new LiteralExpr (new LiteralUndefined); break; default: switch (hd (ts1)) { case Token.LeftBrace: //var [ts1,ndx] = objectLiteral (ts1); var tmp = objectLiteral (ts1); var ts1=tmp[0], ndx=tmp[1]; break; case Token.LeftBracket: //var [ts1,ndx] = arrayLiteral (ts1); var tmp = arrayLiteral (ts1); var ts1=tmp[0], ndx=tmp[1]; break; default: //var [ts1,ndx] = assignmentExpression (ts1,allowIn); var tmp = assignmentExpression (ts1,allowIn); var ts1=tmp[0], ndx=tmp[1]; break; } break; } nd1.push (ndx); while (hd (ts1) === Token.Comma) { ts1 = eat (ts1,Token.Comma); switch (hd (ts1)) { case Token.Comma: //var [ts1,ndx] = [ts1,new LiteralExpr (new LiteralUndefined)]; var ts1=ts1, ndx=new LiteralExpr (new LiteralUndefined); break; case Token.RightBracket: continue; // we're done default: switch (hd (ts1)) { case Token.LeftBrace: //var [ts1,ndx] = objectLiteral (ts1); var tmp = objectLiteral (ts1); var ts1=tmp[0], ndx=tmp[1]; break; case Token.LeftBracket: //var [ts1,ndx] = arrayLiteral (ts1); var tmp = arrayLiteral (ts1); var ts1=tmp[0], ndx=tmp[1]; break; default: //var [ts1,ndx] = assignmentExpression (ts1,allowIn); var tmp = assignmentExpression (ts1,allowIn); var ts1=tmp[0], ndx=tmp[1]; break; } break; } nd1.push (ndx); } } Debug.exit("Parser::elementList ", ts1); return [ts1, nd1]; } /* PrimaryExpression null true false NumberLiteral StringLiteral this RegularExpression XMLInitialiser ParenListExpression ArrayLiteral ObjectLiteral FunctionExpressionb AttributeIdentifier PrimaryIdentifier */ function primaryExpression(ts:TokenStream,beta:IBeta) : Array //[TokenStream,IAstExpr] { Debug.enter("Parser::primaryExpression ",ts); switch (hd (ts)) { case Token.Null: //var [ts1,nd1] = [tl (ts), new LiteralExpr (new LiteralNull ())]; var ts1=tl (ts), nd1=new LiteralExpr (new LiteralNull ()); break; case Token.True: //var [ts1,nd1] = [tl (ts), new LiteralExpr (new LiteralBoolean (true))]; var ts1=tl (ts), nd1=new LiteralExpr (new LiteralBoolean (true)); break; case Token.False: //var [ts1,nd1] = [tl (ts), new LiteralExpr (new LiteralBoolean (false))]; var ts1=tl (ts), nd1=new LiteralExpr (new LiteralBoolean (false)); break; case Token.DecimalLiteral: var tx = Token.tokenText (ts.head()); //var [ts1,nd1] = [tl (ts), new LiteralExpr (new LiteralDecimal (tx))]; var ts1=tl (ts), nd1=new LiteralExpr (new LiteralDecimal (tx)); break; case Token.StringLiteral: var tx = Token.tokenText (ts.head()); //var [ts1,nd1] = [tl (ts), new LiteralExpr (new LiteralString (tx))]; var ts1=tl (ts), nd1=new LiteralExpr (new LiteralString (tx)); break; case Token.This: //var [ts1,nd1] = [tl (ts), new ThisExpr ()]; var ts1=tl (ts), nd1=new ThisExpr (); break; // else // if( lookahead(regexpliteral_token) ) // { // var result = // } // else // if( lookahead(function_token) ) // { // match(function_token); // var first = null // if( lookahead(identifier_token) ) // { // first = parseIdentifier(); // } // var result = parseFunctionCommon(first); // } case Token.LeftParen: //var [ts1,nd1] = parenListExpression(ts); var tmp = parenListExpression(ts); var ts1=tmp[0], nd1=tmp[1]; break; case Token.LeftBracket: //var [ts1,nd1] = arrayLiteral (ts); var tmp = arrayLiteral (ts); var ts1=tmp[0], nd1=tmp[1]; break; case Token.LeftBrace: //var [ts1,nd1] = objectLiteral (ts); var tmp = objectLiteral (ts); var ts1=tmp[0], nd1=tmp[1]; break; default: //var [ts1,nd1] = primaryName (ts); var tmp = primaryName (ts); var ts1=tmp[0], nd1=tmp[1]; var x=nd1; if (x is UnresolvedPath) { var nd = x as UnresolvedPath; var base = resolvePath (nd.path,null); nd1 = new ObjectRef (base,nd.ident); // FIXME: not good for package qualified refs } else { nd1 = new LexicalRef (nd1); } break; } Debug.exit("Parser::primaryExpression ",ts1); return [ts1,nd1]; } function resolvePath (path/*: [IDENT]*/, expr: IAstExpr) { return resolveObjectPath (path,expr); } function resolveObjectPath (path /*: [IDENT]*/, expr: IAstExpr) : IAstExpr { if (path.length === 0) { return expr; } else if (expr === null) { var base = new LexicalRef (new Identifier (path[0],cx.pragmas.openNamespaces)); return resolveObjectPath (path.slice (1,path.length), base); } else { var base = new ObjectRef (expr, new Identifier (path[0],cx.pragmas.openNamespaces)); return resolveObjectPath (path.slice (1,path.length), base); } } /* SuperExpression super super Arguments */ /* PropertyOperator . ReservedIdentifier . PropertyName . AttributeName .. QualifiedName . ParenListExpression . ParenListExpression :: QualifiedNameIdentifier Brackets */ function propertyOperator (ts: TokenStream, nd: IAstExpr) : Array //[TokenStream, [IAstExpr]] { Debug.enter("Parser::propertyOperator ", ts); switch (hd (ts)) { case Token.Dot: switch (hd2 (ts)) { case Token.LeftParen: throw "filter operator not implemented"; break; default: // if (isReservedIdentifier (hd (ts))) { // } //var [ts1,nd1] = propertyName (tl (ts)); var tmp = propertyName (tl (ts)); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = [ts1, new ObjectRef (nd,nd1)]; var tsx=ts1, ndx= new ObjectRef (nd,nd1); break; } break; case Token.LeftBracket: //var [ts1,nd1] = listExpression (tl (ts), allowIn); var tmp = listExpression (tl (ts), allowIn); var ts1=tmp[0], nd1=tmp[1]; ts1 = eat (ts1,Token.RightBracket); //var [tsx,ndx] = [ts1, new ObjectRef (nd,new ExpressionIdentifier (nd1,cx.pragmas.openNamespaces))]; var tsx=ts1, ndx=new ObjectRef (nd,new ExpressionIdentifier (nd1,cx.pragmas.openNamespaces)); break; case Token.DoubleDot: throw "descendents operator not implemented"; break; default: throw "internal error: propertyOperator"; break; } Debug.exit("Parser::propertyOperator ", tsx); return [tsx, ndx]; } /* Arguments ( ) ( ArgumentList ) ArgumentList AssignmentExpression(allowIn) ArgumentList , AssignmentExpression(allowIn) */ function arguments (ts: TokenStream) : Array //[TokenStream, * /*[IAstExpr]*/] { Debug.enter("Parser::arguments ", ts); var ts1 = eat (ts,Token.LeftParen); switch (hd (ts1)) { case Token.RightParen: var tsx = eat (ts1,Token.RightParen); var ndx = []; break; default: //var [ts2,nd2] = listExpression (ts1, allowIn); var tmp = listExpression (ts1, allowIn); var ts2=tmp[0], nd2=tmp[1]; var tsx = eat (ts2,Token.RightParen); var ndx = nd2.exprs; break; } Debug.exit("Parser::arguments ", tsx); return [tsx, ndx]; } /* MemberExpression(beta) PrimaryExpression(beta) new MemberExpression(beta) Arguments SuperExpression PropertyOperator MemberExpression(beta) PropertyOperator Refactored: MemberExpression(beta) PrimaryExpression(beta) MemberExpressionPrime(beta) new MemberExpression(beta) Arguments MemberExpressionPrime(beta) SuperExpression PropertyOperator MemberExpressionPrime(beta) MemberExpressionPrime(beta) PropertyOperator MemberExpressionPrime(beta) empty Note: member expressions always have balanced new and (). The LHS parser is responsible for dispatching extra 'new' or '()' to */ function memberExpression (ts: TokenStream, beta:IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::memberExpression ", ts); switch (hd (ts)) { case Token.New: //var [ts1,nd1] = memberExpression (tl (ts), beta); var tmp = memberExpression (tl (ts), beta); var ts1=tmp[0], nd1=tmp[1]; //var [ts2,nd2] = this.arguments (ts1); var tmp = this.arguments (ts1); var ts2=tmp[0], nd2=tmp[1]; //var [tsx,ndx] = memberExpressionPrime (ts2, beta, new NewExpr (nd1,nd2)); var tmp = memberExpressionPrime (ts2, beta, new NewExpr (nd1,nd2)); var tsx=tmp[0], ndx=tmp[1]; break; case Token.Super: //var [ts1,nd1] = superExpression (ts); var tmp = superExpression (ts); var ts1=tmp[0],nd1=tmp[1]; //var [ts2,nd2] = propertyOperator (ts1,nd1); var tmp = propertyOperator (ts1,nd1); var ts2=tmp[0], nd2=tmp[1]; //var [tsx,ndx] = memberExpressionPrime (ts2, beta, nd2); var tmp = memberExpressionPrime (ts2, beta, nd2); var tsx=tmp[0], ndx=tmp[1]; default: //var [ts1,nd1] = primaryExpression (ts,beta); var tmp = primaryExpression (ts,beta); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = memberExpressionPrime (ts1, beta, nd1); var tmp = memberExpressionPrime (ts1, beta, nd1); var tsx=tmp[0], ndx=tmp[1]; break; } Debug.exit("Parser::memberExpression ", tsx); return [tsx, ndx]; } function memberExpressionPrime (ts: TokenStream, beta:IBeta, nd: IAstExpr) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::memberExpressionPrime ", ts); switch (hd (ts)) { case Token.LeftBracket: case Token.Dot: case Token.DoubleDot: //var [ts1,nd1] = propertyOperator (ts,nd); var tmp = propertyOperator (ts,nd); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = memberExpressionPrime (ts1, beta, nd1); var tmp = memberExpressionPrime (ts1, beta, nd1); var tsx=tmp[0], ndx=tmp[1]; break; default: //var [tsx,ndx] = [ts,nd] var tsx=ts, ndx=nd; break; } Debug.exit("Parser::memberExpressionPrime ", tsx); return [tsx, ndx]; } /* CallExpression(beta) MemberExpression(beta) Arguments CallExpressionPrime(beta) CallExpressionPrime(beta) Arguments CallExpressionPrime(beta) [ Expression ] CallExpressionPrime(beta) . Identifier CallExpressionPrime(beta) empty */ function callExpression (ts: TokenStream, beta:IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::callExpression ", ts); //var [ts1,nd1] = memberExpression (ts,beta); var tmp = memberExpression (ts,beta); var ts1=tmp[0], nd1=tmp[1]; //var [ts2,nd2] = this.arguments (ts); var tmp = this.arguments (ts); var ts2=tmp[0], nd2=tmp[1]; //var [tsx,ndx] = callExpressionPrime (ts2, beta, new CallExpr (nd1,nd2)); var tmp = callExpressionPrime (ts2, beta, new CallExpr (nd1,nd2)); var tsx=tmp[0], ndx=tmp[1]; Debug.exit("Parser::callExpressionPrime ", ndx); return [tsx, ndx]; } function callExpressionPrime (ts: TokenStream, beta:IBeta, nd: IAstExpr) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::callExpressionPrime ", ts); switch (hd (ts)) { case Token.LeftParen: //var [ts1,nd1] = this.arguments (ts); var tmp = this.arguments (ts); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = callExpressionPrime (ts1, beta, new CallExpr (nd,nd1)); var tmp = callExpressionPrime (ts1, beta, new CallExpr (nd,nd1)); var tsx=tmp[0], ndx=tmp[1]; break; case Token.LeftBracket: case Token.Dot: case Token.DoubleDot: //var [ts1,nd1] = propertyOperator (ts,nd); var tmp = propertyOperator (ts,nd); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = callExpressionPrime (ts1, beta, nd1); var tmp = callExpressionPrime (ts1, beta, nd1); var tsx=tmp[0], ndx=tmp[1]; break; default: //var [tsx,ndx] = [ts,nd] var tsx=ts, ndx=nd; break; } Debug.exit("Parser::callExpressionPrime ", ndx); return [tsx, ndx]; } /* NewExpression MemberExpression new NewExpression */ function newExpression (ts: TokenStream, beta:IBeta, new_count=0) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::newExpression ", ts); switch (hd (ts)) { case Token.New: //var [ts1,nd1] = newExpression (tl (ts), beta, new_count+1); var tmp = newExpression (tl (ts), beta, new_count+1); var ts1=tmp[0], nd1=tmp[1] switch (hd (ts1)) { case Token.LeftParen: // no more new exprs so this paren must start a call expr //var [ts2,nd2] = this.arguments (ts1); // refer to parser method var tmp = this.arguments (ts1); // refer to parser method var ts2=tmp[0], nd2=tmp[1]; if (new_count == 0) { //var [tsx,ndx] = callExpressionPrime (ts2,beta,new CallExpr (nd1,nd2)); var tmp = callExpressionPrime (ts2,beta,new CallExpr (nd1,nd2)); var tsx=tmp[0], ndx=tmp[1]; } else { //var [tsx,ndx] = [ts2,new NewExpr (nd1,nd2)]; var tsx=ts2, ndx=new NewExpr (nd1,nd2); } break; default: if (new_count == 0) { //var [tsx,ndx] = memberExpressionPrime (ts1,beta,nd1); var tmp = memberExpressionPrime (ts1,beta,nd1); var tsx=tmp[0], ndx=tmp[1]; } else { //var [tsx,ndx] = [ts1,new NewExpr (nd1,[])]; var tsx=ts1, ndx=new NewExpr (nd1,[]); } break; } break; default: //var [ts1,nd1] = memberExpression (ts,beta); var tmp = memberExpression (ts,beta); var ts1=tmp[0], nd1=tmp[1]; switch (hd (ts1)) { case Token.LeftParen: //var [ts2,nd2] = this.arguments (ts1); // refer to parser method var tmp = this.arguments (ts1); // refer to parser method var ts2=tmp[0], nd2=tmp[1]; if( new_count == 0 ) { //var [tsx,ndx] = callExpressionPrime (ts2,beta,new CallExpr (nd1,nd2)); var tmp = callExpressionPrime (ts2,beta,new CallExpr (nd1,nd2)); var tsx=tmp[0], ndx=tmp[1]; } else { //var [tsx,ndx] = [ts2,new NewExpr (nd1,nd2)]; var tsx=ts2, ndx=new NewExpr (nd1,nd2); } break; default: if( new_count == 0 ) { //var [tsx,ndx] = [ts1,nd1]; var tsx=ts1, ndx=nd1; } else { //var [tsx,ndx] = [ts1,new NewExpr (nd1,[])]; var tsx=ts1, ndx=new NewExpr (nd1,[]); } break; } break; } Debug.exit("Parser::newExpression ", ndx); return [tsx, ndx]; } /* LeftHandSideExpression NewExpression CallExpression Refactored: LeftHandSideExpression NewExpression MemberExpression Arguments CallExpressionPrime MemberExpression */ function leftHandSideExpression (ts: TokenStream, beta:IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::leftHandSideExpression ", ts); switch (hd (ts)) { case Token.New: //var [ts1,nd1] = newExpression (ts,beta,0); var tmp = newExpression (ts,beta,0); var ts1=tmp[0], nd1=tmp[1]; switch (hd (ts1)) { case Token.LeftParen: //var [ts2,nd2] = this.arguments (ts1); // refer to parser method var tmp = this.arguments (ts1); // refer to parser method var ts2=tmp[0], nd2=tmp[1]; //var [tsx,ndx] = callExpressionPrime (ts2, beta, new CallExpr (nd1,nd2)); var tmp = callExpressionPrime (ts2, beta, new CallExpr (nd1,nd2)); var tsx=tmp[0], ndx=tmp[1]; break; default: //var [tsx,ndx] = [ts1,nd1]; var tsx=ts1, ndx=nd1; break; } break; default: //var [ts1,nd1] = memberExpression (ts,beta); var tmp = memberExpression (ts,beta); var ts1=tmp[0], nd1=tmp[1]; switch (hd (ts1)) { case Token.LeftParen: //var [ts2,nd2] = this.arguments (ts1); // refer to parser method var tmp = this.arguments (ts1); // refer to parser method var ts2=tmp[0], nd2=tmp[1]; //var [tsx,ndx] = callExpressionPrime (ts2, beta, new CallExpr (nd1,nd2)); var tmp = callExpressionPrime (ts2, beta, new CallExpr (nd1,nd2)); var tsx=tmp[0], ndx=tmp[1]; break; default: //var [tsx,ndx] = [ts1,nd1]; var tsx=ts1, ndx=nd1; break; } break; } Debug.exit("Parser::leftHandSideExpression ", ndx); return [tsx, ndx]; } /* PostfixExpression(beta) LeftHandSideExpression(beta) LeftHandSideExpression(beta) [no line break] ++ LeftHandSideExpression(beta) [no line break] -- */ function postfixExpression (ts: TokenStream, beta:IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::postfixExpression ", ts); //var [ts1, nd1] = leftHandSideExpression (ts, beta); var tmp = leftHandSideExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; switch (hd (ts1)) { case Token.PlusPlus: //var [tsx,ndx] = [tl (ts1), new UnaryExpr (postIncrOp,nd1)]; var tsx=tl (ts1), ndx=new UnaryExpr (Ast.postIncrOp,nd1); break; case Token.MinusMinus: //var [tsx,ndx] = [tl (ts1), new UnaryExpr (postDecrOp,nd1)]; var tsx=tl (ts1), ndx=new UnaryExpr (Ast.postDecrOp,nd1); break; default: //var [tsx,ndx] = [ts1,nd1]; var tsx=ts1, ndx=nd1; break; } Debug.exit("Parser::postfixExpression ", tsx); return [tsx, ndx]; } /* UnaryExpression(beta) PostfixExpression(beta) delete PostfixExpression(beta) void UnaryExpression(beta) typeof UnaryExpression(beta) ++ PostfixExpression(beta) -- PostfixExpression(beta) + UnaryExpression(beta) - UnaryExpression(beta) ~ UnaryExpression(beta) ! UnaryExpression(beta) type NullableTypeExpression */ function unaryExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::unaryExpression ", ts); switch (hd (ts)) { case Token.Delete: //var [ts1,nd1] = postfixExpression (tl (ts),beta); var tmp = postfixExpression (tl (ts),beta); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = [ts1,new UnaryExpr (deleteOp,nd1)]; var tsx=ts1, ndx=new UnaryExpr (Ast.deleteOp,nd1); break; case Token.Void: //var [ts1,nd1] = unaryExpression (tl (ts),beta); var tmp = unaryExpression (tl (ts),beta); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = [ts1,new UnaryExpr (voidOp,nd1)]; var tsx=ts1, ndx=new UnaryExpr (Ast.voidOp,nd1); break; case Token.TypeOf: //var [ts1,nd1] = unaryExpression (tl (ts),beta); var tmp = unaryExpression (tl (ts),beta); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = [ts1,new UnaryExpr (typeOfOp,nd1)]; var tsx=ts1, ndx=new UnaryExpr (Ast.typeOfOp,nd1); break; case Token.PlusPlus: //var [ts1,nd1] = postfixExpression (tl (ts),beta); var tmp = postfixExpression (tl (ts),beta); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = [ts1,new UnaryExpr (preIncrOp,nd1)]; var tsx=ts1, ndx=new UnaryExpr (Ast.preIncrOp,nd1); break; case Token.MinusMinus: //var [ts1,nd1] = postfixExpression (tl (ts),beta); var tmp = postfixExpression (tl (ts),beta); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = [ts1,new UnaryExpr (preDecrOp,nd1)]; var tsx=ts1, ndx=new UnaryExpr (Ast.preDecrOp,nd1); break; case Token.Plus: //var [ts1,nd1] = unaryExpression (tl (ts),beta); var tmp = unaryExpression (tl (ts),beta); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = [ts1,new UnaryExpr (unaryPlusOp,nd1)]; var tsx=ts1, ndx=new UnaryExpr (Ast.unaryPlusOp,nd1); break; case Token.Minus: //var [ts1,nd1] = unaryExpression (tl (ts),beta); var tmp = unaryExpression (tl (ts),beta); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = [ts1,new UnaryExpr (unaryMinusOp,nd1)]; var tsx=ts1, ndx=new UnaryExpr (Ast.unaryMinusOp,nd1); break; case Token.BitwiseNot: //var [ts1,nd1] = unaryExpression (tl (ts),beta); var tmp = unaryExpression (tl (ts),beta); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = [ts1,new UnaryExpr (bitwiseNotOp,nd1)]; var tsx=ts1, ndx=new UnaryExpr (Ast.bitwiseNotOp,nd1); break; case Token.Not: //var [ts1,nd1] = unaryExpression (tl (ts),beta); var tmp = unaryExpression (tl (ts),beta); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = [ts1,new UnaryExpr (logicalNotOp,nd1)]; var tsx=ts1, ndx=new UnaryExpr (Ast.logicalNotOp,nd1); break; case Token.Type: //var [ts1,nd1] = nullableTypeExpression (tl (ts),beta); var tmp = nullableTypeExpression (tl (ts),beta); var ts1=tmp[0], nd1=tmp[1]; //var [tsx,ndx] = [ts1,new TypeExpr (nd1)]; var tsx=ts1, ndx=new TypeExpr (nd1); break; default: //var [tsx,ndx] = postfixExpression (ts,beta); var tmp = postfixExpression (ts,beta); var tsx=tmp[0], ndx=tmp[1]; break; } Debug.exit("Parser::unaryExpression ", tsx); return [tsx,ndx]; } /* MultiplicativeExpression UnaryExpression MultiplicativeExpression * UnaryExpression MultiplicativeExpression / UnaryExpression MultiplicativeExpression % UnaryExpression */ function multiplicativeExpression (ts: TokenStream, beta:IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::multiplicativeExpression ", ts); //var [ts1,nd1] = unaryExpression (ts, beta); var tmp = unaryExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; /// done: var done = false; while (true) { if (hd (ts1) === Token.BREAK) { var tsx; var csx; //[tsx,csx] = scan.tokenList (scan.div); tmp = scan.tokenList (scan.div); tsx=tmp[0]; csx=tmp[1]; coordList = csx; ts1 = new TokenStream (tsx); } switch (hd (ts1)) { case Token.Mult: var op = Ast.timesOp; break; case Token.Div: var op = Ast.divideOp; break; case Token.Remainder: var op = Ast.remainderOp; break; default: done = true; break /// done; } if (done) break; //var [ts2, nd2] = unaryExpression (tl (ts1), beta); var tmp = unaryExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; ts1 = ts2; nd1 = new BinaryExpr (op, nd1, nd2); } Debug.exit("Parser::multiplicativeExpression ", ts1); return [ts1, nd1]; } /* AdditiveExpression MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression - MultiplicativeExpression */ function additiveExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::additiveExpression ", ts); //var [ts1, nd1] = multiplicativeExpression (ts, beta); var tmp = multiplicativeExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; /// done: var done = false; while (true) { switch (hd (ts1)) { case Token.Plus: var op = Ast.plusOp; break; case Token.Minus: var op = Ast.minusOp; break; default: done = true; break /// done; } if (done) break; //var [ts2, nd2] = multiplicativeExpression (tl (ts1), beta); var tmp = multiplicativeExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; //[ts1, nd1] = [ts2, new BinaryExpr (op, nd1, nd2)]; ts1=ts2; nd1=new BinaryExpr (op, nd1, nd2); } Debug.exit("Parser::additiveExpression ", ts1); return [ts1, nd1]; } /* ShiftExpression AdditiveExpression ShiftExpression << AdditiveExpression ShiftExpression >> AdditiveExpression ShiftExpression >>> AdditiveExpression */ function shiftExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::shiftExpression ", ts); //var [ts1, nd1] = additiveExpression (ts, beta); var tmp = additiveExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; var done = false; /// done: while (true) { switch (hd (ts1)) { case Token.LeftShift: var op = Ast.leftShiftOp; break; case Token.RightShift: var op = Ast.rightShiftOp; break; case Token.UnsignedRightShift: var op = Ast.rightShiftUnsignedOp; break; default: done = true; break /// done; } if (done) break; //var [ts2, nd2] = additiveExpression (tl (ts1), beta); var tmp = additiveExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; //var [ts1, nd1] = [ts2, new BinaryExpr (op, nd1, nd2)]; var ts1=ts2, nd1=new BinaryExpr (op, nd1, nd2); } Debug.exit("Parser::shiftExpression ", ts1); return [ts1, nd1]; } /* RelationalExpression(noIn) ShiftExpression(noIn) RelationalExpression(noIn) < ShiftExpression(noIn) RelationalExpression(noIn) > ShiftExpression(noIn) RelationalExpression(noIn) <= ShiftExpression(noIn) RelationalExpression(noIn) >= ShiftExpression(noIn) RelationalExpression(noIn) instanceof ShiftExpression(noIn) RelationalExpression(noIn) is TypeExpression RelationalExpression(noIn) to TypeExpression RelationalExpression(noIn) cast TypeExpression RelationalExpression(allowIn) ShiftExpression(allowIn) RelationalExpression(allowIn) < ShiftExpression(allowIn) RelationalExpression(allowIn) > ShiftExpression(allowIn) RelationalExpression(allowIn) <= ShiftExpression(allowIn) RelationalExpression(allowIn) >= ShiftExpression(allowIn) RelationalExpression(allowIn) in ShiftExpression(allowIn) RelationalExpression(allowIn) instanceof ShiftExpression(allowIn) RelationalExpression(allowIn) is TypeExpression RelationalExpression(allowIn) to TypeExpression RelationalExpression(allowIn) cast TypeExpression */ function relationalExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::relationalExpression ", ts); //var [ts1, nd1] = shiftExpression (ts, beta); var tmp = shiftExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; /// done: var done = false; while (true) { switch (hd (ts1)) { case Token.LessThan: //var [ts2, nd2] = shiftExpression (tl (ts1), beta); var tmp = shiftExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; nd2 = new BinaryExpr (Ast.lessOp,nd1,nd2); break; case Token.GreaterThan: //var [ts2, nd2] = shiftExpression (tl (ts1), beta); var tmp = shiftExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; nd2 = new BinaryExpr (Ast.greaterOp,nd1,nd2); break; case Token.LessThanOrEqual: //var [ts2, nd2] = shiftExpression (tl (ts1), beta); var tmp = shiftExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; nd2 = new BinaryExpr (Ast.lessOrEqualOp,nd1,nd2); break; case Token.GreaterThanOrEqual: //var [ts2, nd2] = shiftExpression (tl (ts1), beta); var tmp = shiftExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; nd2 = new BinaryExpr (Ast.greaterOrEqualOp,nd1,nd2); break; case Token.In: if (beta == noIn) { done = true; break /// done; } //var [ts2, nd2] = shiftExpression (tl (ts1), beta); var tmp = shiftExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; nd2 = new BinaryExpr (Ast.inOp,nd1,nd2); break; case Token.InstanceOf: //var [ts2, nd2] = shiftExpression (tl (ts1), beta); var tmp = shiftExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; nd2 = new BinaryExpr (Ast.instanceOfOp,nd1,nd2); break; case Token.Is: //var [ts2, nd2] = typeExpression (tl (ts1)); var tmp = typeExpression (tl (ts1)); var ts2=tmp[0], nd2=tmp[1]; nd2 = new BinaryTypeExpr (Ast.isOp,nd1,nd2); break; case Token.To: //var [ts2, nd2] = typeExpression (tl (ts1)); var tmp = typeExpression (tl (ts1)); var ts2=tmp[0], nd2=tmp[1]; nd2 = new BinaryTypeExpr (Ast.toOp,nd1,nd2); break; case Token.Cast: //var [ts2, nd2] = typeExpression (tl (ts1)); var tmp = typeExpression (tl (ts1)); var ts2=tmp[0], nd2=tmp[1]; nd2 = new BinaryTypeExpr (Ast.castOp,nd1,nd2); break; default: done = true; break /// done; } if (done) break; //var [ts1, nd1] = [ts2,nd2]; var ts1=ts2, nd1=nd2; } Debug.exit("Parser::equalityExpression ", ts1); return [ts1, nd1]; } /* EqualityExpression(beta) RelationalExpression(beta) EqualityExpression(beta) == RelationalExpression(beta) EqualityExpression(beta) != RelationalExpression(beta) EqualityExpression(beta) === RelationalExpression(beta) EqualityExpression(beta) !== RelationalExpression(beta) */ function equalityExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::equalityExpression ", ts); //var [ts1, nd1] = relationalExpression (ts, beta); var tmp = relationalExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; /// done: var done = false; while (true) { switch (hd (ts1)) { case Token.Equal: var op = Ast.equalOp; break; case Token.NotEqual: var op = Ast.notEqualOp; break; case Token.StrictEqual: var op = Ast.strictEqualOp; break; case Token.StrictNotEqual: var op = Ast.strictNotEqualOp; break; default: done = true; break /// done; } if (done) break; //var [ts2, nd2] = relationalExpression (tl (ts1), beta); var tmp = relationalExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; //var [ts1, nd1] = [ts2, new BinaryExpr (op, nd1, nd2)]; var ts1=ts2, nd1=new BinaryExpr (op, nd1, nd2); } Debug.exit("Parser::equalityExpression ", ts1); return [ts1, nd1]; } /* BitwiseAndExpression(beta) EqualityExpression(beta) BitwiseAndExpressionr(beta) & EqualityExpression(beta) */ function bitwiseAndExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::bitwiseAndExpression ", ts); //var [ts1, nd1] = equalityExpression (ts, beta); var tmp = equalityExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; while (hd (ts1) === Token.BitwiseAnd) { //var [ts2, nd2] = equalityExpression (tl (ts1), beta); var tmp = equalityExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; //var [ts1, nd1] = [ts2, new BinaryExpr (bitwiseAndOp, nd1, nd2)]; var ts1=ts2, nd1=new BinaryExpr (Ast.bitwiseAndOp, nd1, nd2); } Debug.exit("Parser::bitwiseAndExpression ", ts1); return [ts1, nd1]; } /* BitwiseXorExpressionb BitwiseAndExpressionb BitwiseXorExpressionb ^ BitwiseAndExpressionb */ function bitwiseXorExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::bitwiseXorExpression ", ts); //var [ts1, nd1] = bitwiseAndExpression (ts, beta); var tmp = bitwiseAndExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; while (hd (ts1) === Token.BitwiseXor) { //var [ts2, nd2] = bitwiseAndExpression (tl (ts1), beta); var tmp = bitwiseAndExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; //var [ts1, nd1] = [ts2, new BinaryExpr (bitwiseXorOp, nd1, nd2)]; var ts1=ts2, nd1=new BinaryExpr (Ast.bitwiseXorOp, nd1, nd2); } Debug.exit("Parser::bitwiseXorExpression ", ts1); return [ts1, nd1]; } /* BitwiseOrExpression(beta) BitwiseXorExpression(beta) BitwiseOrExpression(beta) | BitwiseXorExpression(beta) */ function bitwiseOrExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::bitwiseOrExpression ", ts); //var [ts1, nd1] = bitwiseXorExpression (ts, beta); var tmp = bitwiseXorExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; while (hd (ts1) === Token.BitwiseOr) { //var [ts2, nd2] = bitwiseXorExpression (tl (ts1), beta); var tmp = bitwiseXorExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; //var [ts1, nd1] = [ts2, new BinaryExpr (bitwiseOrOp, nd1, nd2)]; var ts1=ts2, nd1=new BinaryExpr (Ast.bitwiseOrOp, nd1, nd2); } Debug.exit("Parser::bitwiseOrExpression ", ts1); return [ts1, nd1]; } /* LogicalAndExpression(beta) BitwiseOrExpression(beta) LogicalAndExpression(beta) && BitwiseOrExpression(beta) */ function logicalAndExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::logicalAndExpression ", ts); //var [ts1, nd1] = bitwiseOrExpression (ts, beta); var tmp = bitwiseOrExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; while (hd (ts1) === Token.LogicalAnd) { //var [ts2, nd2] = bitwiseOrExpression (tl (ts1), beta); var tmp = bitwiseOrExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; //var [ts1, nd1] = [ts2, new BinaryExpr (logicalAndOp, nd1, nd2)]; var ts1=ts2, nd1=new BinaryExpr (Ast.logicalAndOp, nd1, nd2); } Debug.exit("Parser::logicalAndExpression ", ts1); return [ts1, nd1]; } /* LogicalXorExpressionb LogicalAndExpressionb LogicalXorExpressionb ^^ LogicalAndExpressionb */ function logicalXorExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::logicalXorExpression ", ts); //var [ts1, nd1] = logicalAndExpression (ts, beta); var tmp = logicalAndExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; while (hd (ts1) === Token.LogicalXor) { //var [ts2, nd2] = logicalAndExpression (tl (ts1), beta); var tmp = logicalAndExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1]; //var [ts1, nd1] = [ts2, new BinaryExpr (logicalXor, nd1, nd2)]; var ts1=ts2, nd1=new BinaryExpr (Ast.logicalXorOp, nd1, nd2); } Debug.exit("Parser::logicalXorExpression ", ts1); return [ts1, nd1]; } /* LogicalOrExpression(beta) LogicalXorExpression(beta) LogicalOrExpression(AllowIn) || LogicalXorExpression(beta) */ function logicalOrExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::logicalOrExpression ", ts); //var [ts1, nd1] = logicalXorExpression (ts, beta); var tmp = logicalXorExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; while (hd (ts1) === Token.LogicalOr) { //var [ts2, nd2] = logicalXorExpression (tl (ts1), beta); var tmp = logicalXorExpression (tl (ts1), beta); var ts2=tmp[0], nd2=tmp[1] //var [ts1, nd1] = [ts2, new BinaryExpr (logicalOrOp, nd1, nd2)]; var ts1=ts2, nd1=new BinaryExpr (Ast.logicalOrOp, nd1, nd2); } Debug.exit("Parser::logicalOrExpression ", ts1); return [ts1, nd1]; } /* YieldExpression UnaryExpression yield UnaryExpression */ /* NonAssignmentExpressiona, b LetExpressiona, b YieldExpressiona, b LogicalOrExpressiona, b LogicalOrExpressiona, b ? NonAssignmentExpressiona, b : NonAssignmentExpressiona, b */ function nonAssignmentExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::nonAssignmentExpression ", ts); switch (hd (ts)) { case Token.Let: //var [ts1,nd1] = letExpression (ts,beta); var tmp = letExpression (ts,beta); var ts1=tmp[0], nd1=tmp[1]; break; case Token.Yield: //var [ts1,nd1] = yieldExpression (ts,beta); var tmp = yieldExpression (ts,beta); var ts1=tmp[0], nd1=tmp[1]; break; default: //var [ts1,nd1] = logicalOrExpression (ts,beta); var tmp = logicalOrExpression (ts,beta); var ts1=tmp[0], nd1=tmp[1]; switch (hd (ts1)) { case Token.QuestionMark: //var [ts2,nd2] = nonAssignmentExpression (tl (ts1),beta); var tmp = nonAssignmentExpression (tl (ts1),beta); var ts2=tmp[0], nd2=tmp[1]; ts2 = eat (ts2,Token.Colon); //var [ts3,nd3] = nonAssignmentExpression (ts2,beta); var tmp = nonAssignmentExpression (ts2,beta); var ts3=tmp[0], nd3=tmp[1]; //var [ts1,nd1] = [ts3, new TernaryExpr (nd1,nd2,nd3)]; var ts1=ts3, nd1=new TernaryExpr (nd1,nd2,nd3) break; default: break; } break; } Debug.exit("Parser::nonAssignmentExpression ", ts1); return [ts1,nd1]; } /* ConditionalExpression(beta) LetExpression(beta) YieldExpression(beta) LogicalOrExpression(beta) LogicalOrExpression(beta) ? AssignmentExpression(beta) : AssignmentExpression(beta) */ function conditionalExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::conditionalExpression ", ts); switch (hd (ts)) { case Token.Let: var tmp = letExpression (ts,beta); var ts1=tmp[0], nd1=tmp[1]; break; case Token.Yield: var tmp = yieldExpression (ts,beta); var ts1=tmp[0], nd1=tmp[1]; break; default: var tmp = logicalOrExpression (ts,beta); var ts1=tmp[0], nd1=tmp[1]; switch (hd (ts1)) { case Token.QuestionMark: var tmp = assignmentExpression (tl (ts1),beta); var ts2=tmp[0], nd2=tmp[1]; ts2 = eat (ts2,Token.Colon); var tmp = assignmentExpression (ts2,beta); var ts3=tmp[0], nd3=tmp[1]; //var [ts1,nd1] = [ts3, new TernaryExpr (nd1,nd2,nd3)]; var ts1=ts3, nd1=new TernaryExpr (nd1,nd2,nd3); break; default: break; } } Debug.exit("Parser::conditionalExpression ", ts1); return [ts1,nd1]; } /* AssignmentExpression(beta) ConditionalExpression(beta) Pattern(beta, allowExpr) = AssignmentExpression(beta) SimplePattern(beta, allowExpr) CompoundAssignmentOperator AssignmentExpression(beta) */ function assignmentExpression (ts: TokenStream, beta: IBeta) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::assignmentExpression ", ts); var tmp = conditionalExpression (ts, beta); var ts1=tmp[0], nd1=tmp[1]; switch (hd (ts1)) { case Token.Assign: //var [ts1,nd1] = [tl (ts1), patternFromExpr (nd1)]; var ts1=tl (ts1), nd1=patternFromExpr (nd1); var tmp = assignmentExpression (ts1,beta); var ts2=tmp[0], nd2=tmp[1]; var tmp = desugarAssignmentPattern (nd1,Ast.anyType,nd2,Ast.assignOp); var fxtrs=tmp[0],expr=tmp[1],head=tmp[2]; break; default: var op = undefined; switch(hd (ts1)) { case Token.PlusAssign: op = Ast.plusOp; break; case Token.MinusAssign: op = Ast.minusOp; break; case Token.MultAssign: op = Ast.timesOp; break; case Token.DivAssign: op = Ast.divideOp; break; case Token.RemainderAssign: op = Ast.remainderOp; break; case Token.LogicalAndAssign: op = Ast.logicalAndOp; break; case Token.BitwiseAndAssign: op = Ast.bitwiseAndOp; break; case Token.LogicalOrAssign: op = Ast.logicalOrOp; break; case Token.BitwiseXorAssign: op = Ast.bitwiseXorOp; break; case Token.BitwiseOrAssign: op = Ast.bitwiseOrOp; break; case Token.LeftShiftAssign: op = Ast.leftShiftOp; break; case Token.RightShiftAssign: op = Ast.rightShiftOp; break; case Token.UnsignedRightShiftAssign: op = Ast.rightShiftUnsignedOp; break; } if( op != undefined ) { var nd_orig = nd1; //var [ts1,nd1] = [tl (ts1), patternFromExpr(nd1)]; var ts1=tl (ts1), nd1=patternFromExpr(nd1); var tmp = assignmentExpression(ts1, beta); var ts2=tmp[0], nd2=tmp[1]; nd2 = new BinaryExpr(op, nd_orig, nd2); var tmp = desugarAssignmentPattern (nd1,Ast.anyType,nd2,Ast.assignOp); var fxtrs=tmp[0],expr=tmp[1],head=tmp[2]; } else { var ts2=ts1, expr=nd1; } break; } Debug.exit("Parser::assignmentExpression ", ts1); return [ts2,expr]; // expression to pattern converters function patternFromExpr (e: IAstExpr) { var x = e; if (x is LiteralExpr) { var y = (e as LiteralExpr).literal; if (y is LiteralArray) { var p = arrayPatternFromLiteral (y); } else if (y is LiteralObject) { var p = objectPatternFromLiteral (y); } else { throw "invalid lhs expr " + e; } } else if (x is LexicalRef) { var p = new SimplePattern (e); } else if (x is ObjectRef) { var p = new SimplePattern (e); } else { throw "error patternFromExpr, unhandled expression kind " + e; } return p; } function arrayPatternFromLiteral (nd: IAstLiteral) : IParserPattern { Debug.enter("Parser::arrayPatternFromLiteral ", ts); var nd1 = elementListPatternFromLiteral ((nd as LiteralArray).exprs); Debug.exit("Parser::arrayPatternFromLiteral ", ts1); return new ArrayPattern (nd1); } function elementListPatternFromLiteral (nd: Array) : Array { Debug.enter("Parser::elementListPatternFromLiteral ", nd); var nd1 = []; for (var i=0; i // match(let_token) // match(leftparen_token) // if( lookahead(rightparen_token) ) // { // var first = <> // } // else // { // var first = <> // first += parseVariableBinding(,var_token,allowIn_mode,prologue) // while( lookahead(comma_token) ) // { // match(comma_token) // first += parseVariableBinding(,var_token,allowIn_mode,prologue) // } // prologue.* += first // } // match(rightparen_token) // var second = parseAssignmentExpression(mode) // var result = {prologue}{second} // // Debug.exit("parseLetExpression",result) // return result // } // // /* // // YieldExpressionb // yield AssignmentExpressionb // // */ // ///* // function parseYieldExpression(mode) // { // Debug.enter("parseYieldExpression") // // Debug.exit("parseYieldExpression",result) // return result // } //*/ // PATTERNS /* Pattern(beta,gamma) SimplePattern(beta,gamma) ObjectPattern(gamma) ArrayPattern(gamma) */ function pattern (ts: TokenStream, beta: IBeta, gamma: IGamma) : Array //[TokenStream, IParserPattern] { Debug.enter("Parser::pattern", ts); switch (hd (ts)) { case Token.LeftBrace: var tmp = objectPattern (ts, gamma); var ts1=tmp[0], nd1=tmp[1]; break; case Token.LeftBracket: var tmp = arrayPattern (ts, gamma); var ts1=tmp[0], nd1=tmp[1]; break; default: var tmp = simplePattern (ts, beta, gamma); var ts1=tmp[0], nd1=tmp[1]; break; } Debug.exit("Parser::pattern ", ts1); return [ts1,nd1]; } /* SimplePattern(beta, noExpr) Identifier SimplePattern(beta, allowExpr) LeftHandSideExpression(beta) */ function simplePattern (ts: TokenStream, beta: IBeta, gamma: IGamma) : Array //[TokenStream, IParserPattern] { Debug.enter("Parser::simplePattern", ts); switch (gamma) { case noExpr: var tmp = identifier (ts); var ts1=tmp[0], nd1=tmp[1]; var tsx=ts1, ndx=new IdentifierPattern (nd1); break; case allowExpr: var tmp = leftHandSideExpression (ts,beta); var ts1=tmp[0], nd1=tmp[1]; var tsx=ts1, ndx=new SimplePattern (nd1); break; } Debug.exit("Parser::simplePattern", tsx); return [tsx,ndx]; } /* ArrayPattern(gamma) [ ElementListPattern(gamma) ] */ function arrayPattern (ts: TokenStream, gamma: IGamma) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::arrayPattern ", ts); ts = eat (ts,Token.LeftBracket); var tmp = elementListPattern (ts,gamma); var ts1=tmp[0], nd1=tmp[1]; ts1 = eat (ts1,Token.RightBracket); Debug.exit("Parser::arrayPattern ", ts1); return [ts1, new ArrayPattern (nd1)]; } /* ElementListPattern(gamma) empty LiteralElementPattern , ElementListPattern LiteralElementPattern , ElementListPattern LiteralElementPattern Pattern(allowColon,allowIn,gamma) */ function elementListPattern (ts: TokenStream, gamma:IGamma) : Array //[TokenStream, Array] { Debug.enter("Parser::elementListPattern ", ts); var nd1 = []; if (hd (ts) !== Token.RightBracket) { switch (hd (ts)) { case Token.Comma: //var [ts1,ndx] = [tl (ts),new LiteralExpr (new LiteralUndefined)]; var ts1=tl (ts), ndx=new LiteralExpr (new LiteralUndefined); break; default: var tmp = pattern (ts,allowIn,gamma); var ts1=tmp[0], ndx=tmp[1]; break; } nd1.push (ndx); while (hd (ts1) === Token.Comma) { ts1 = eat (ts1,Token.Comma); switch (hd (ts1)) { case Token.Comma: var tmp = [ts1,new LiteralExpr (new LiteralUndefined)]; var ts1=tmp[0], ndx=tmp[1]; break; default: var tmp = pattern (ts1,allowIn,gamma); var ts1=tmp[0], ndx=tmp[1]; break; } nd1.push (ndx); } } Debug.exit("Parser::elementListPattern ", ts1); return [ts1, nd1]; } /* ObjectPattern(gamma) [ FieldListPattern(gamma) ] */ function objectPattern (ts: TokenStream, gamma: IGamma) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::objectPattern ", ts); ts = eat (ts,Token.LeftBrace); var tmp = fieldListPattern (ts,gamma); var ts1=tmp[0], nd1=tmp[1]; ts1 = eat (ts1,Token.RightBrace); Debug.exit("Parser::objectPattern ", ts1); return [ts1, new ObjectPattern (nd1)]; } /* FieldListPattern(gamma) empty FieldPattern FieldPattern , FieldListPattern FieldPattern FieldName FieldName : Pattern(allowColon,allowIn,gamma) */ function fieldListPattern (ts: TokenStream, gamma:IGamma) : Array //[TokenStream, IAstExpr] { Debug.enter("Parser::fieldListPattern ", ts); var nd1 = []; if (hd (ts) !== Token.RightBrace) { var tmp = fieldPattern (ts,gamma); var ts1=tmp[0], ndx=tmp[1]; nd1.push (ndx); while (hd (ts1) === Token.Comma) { ts1 = eat (ts1,Token.Comma); var tmp = fieldPattern (ts1,gamma); var ts1=tmp[0], ndx=tmp[1]; nd1.push (ndx); } } Debug.exit("Parser::fieldListPattern ", ts1); return [ts1, nd1]; } function fieldPattern (ts: TokenStream, gamma:IGamma) : Array //[TokenStream, FieldPattern] { Debug.enter("Parser::fieldPattern ", ts); var tmp = fieldName (ts); var ts1=tmp[0], nd1=tmp[1]; switch (hd (ts1)) { case Token.Colon: var tmp = pattern (tl (ts1),allowIn,gamma); var ts2=tmp[0], nd2=tmp[1]; break; default: var x = nd1; if (x is Identifier) { //var [ts2,nd2] = [ts1, new IdentifierPattern (nd1.ident)]; var ts2=ts1, nd2=new IdentifierPattern (nd1.ident); } else { throw "unsupported fieldPattern " + nd1; } break; } Debug.exit("Parser::fieldPattern ", ts2); return [ts2, new FieldPattern (nd1,nd2)]; } /* TypedIdentifier(beta) SimplePattern(beta, noExpr) SimplePattern(beta, noExpr) : NullableTypeExpression TypedPattern(beta) Pattern(beta, noExpr) Pattern(beta, noExpr) : NullableTypeExpression */ function typedPattern (ts: TokenStream, beta: IBeta) : Array //[TokenStream, [IParserPattern,IAstTypeExpr]] { Debug.enter("Parser::typedPattern ", ts); var tmp = pattern (ts,beta,noExpr); var ts1=tmp[0], nd1=tmp[1]; switch (hd (ts1)) { case Token.Colon: var tmp = nullableTypeExpression (tl (ts1)); var ts2=tmp[0], nd2=tmp[1]; break; default: //var [ts2,nd2] = [ts1,Ast.anyType]; var ts2=ts1, nd2=Ast.anyType; break; } Debug.exit("Parser::typedPattern ", ts2); return [ts2,[nd1,nd2]]; } // TYPE EXPRESSIONS /* NullableTypeExpression TypeExpression TypeExpression ? TypeExpression ! */ function nullableTypeExpression (ts: TokenStream, junk:*=null) : Array //[TokenStream, IAstTypeExpr] { Debug.enter("Parser::nullableTypeExpression ", ts); var tmp = typeExpression (ts); var ts1=tmp[0], nd1=tmp[1]; switch (hd (ts1)) { case Token.QuestionMark: //var [ts1,nd1] = [tl (ts1), new NullableType (nd1,true)]; var ts1=tl (ts1), nd1=new NullableType (nd1,true); break; case Token.Not: //var [ts1,nd1] = [tl (ts1), new NullableType (nd1,false)]; var ts1=tl (ts1), nd1=new NullableType (nd1,false); break; default: // do nothing break; } Debug.exit("Parser::nullableTypeExpression ", ts1); return [ts1,nd1]; } /* TypeExpression null undefined FunctionType UnionType RecordType ArrayType PrimaryName */ function typeExpression (ts: TokenStream) : Array //[TokenStream, IAstTypeExpr] { Debug.enter("Parser::typeExpression ", ts); switch (hd (ts)) { case Token.Mult: var ts1=tl (ts),nd1= Ast.anyType; break; case Token.Null: var ts1=tl (ts),nd1= Ast.nullType; break; case Token.Undefined: var ts1=tl (ts),nd1= Ast.undefinedType; break; case Token.Function: var tmp = functionType (ts); var ts1=tmp[0], nd1=tmp[1]; break; case Token.LeftParen: var tmp = unionType (ts); var ts1=tmp[0], nd1=tmp[1]; break; case Token.LeftBrace: var tmp = objectType (ts); var ts1=tmp[0], nd1=tmp[1]; break; case Token.LeftBracket: var tmp = arrayType (ts); var ts1=tmp[0], nd1=tmp[1]; break; default: var tmp = primaryName (ts); var ts1=tmp[0], nd1=tmp[1]; nd1 = new TypeName (nd1); break; } Debug.exit("Parser::typeExpression ", ts1); return [ts1,nd1]; } /* UnionType ( TypeExpressionList ) */ function unionType (ts: TokenStream) : Array //[TokenStream, IAstTypeExpr] { Debug.enter("Parser::unionType ", ts); ts = eat (ts,Token.LeftParen); var tmp = typeExpressionList (ts); var ts1=tmp[0], nd1=tmp[1]; ts1 = eat (ts1,Token.RightParen); Debug.exit("Parser::unionType ", ts1); return [ts1,new UnionType (nd1)]; } /* ObjectType { FieldTypeTypeList } */ function objectType (ts: TokenStream) : Array //[TokenStream, IAstTypeExpr] { Debug.enter("Parser::objectType ", ts); ts = eat (ts,Token.LeftBrace); var tmp = fieldTypeList (ts); var ts1=tmp[0], nd1=tmp[1]; ts1 = eat (ts1,Token.RightBrace); Debug.exit("Parser::objectType ", ts1); return [ts1,new ObjectType (nd1)]; } /* FieldTypeList empty NonemptyFieldTypeList NonemptyFieldTypeList FieldType FieldType , NonemptyFieldTypeList */ function fieldTypeList (ts: TokenStream) // : [TokenStream, [FIELD_TYPE]] { Debug.enter("Parser::fieldTypeList ", ts); var nd1 = []; if (hd (ts) !== Token.RightBrace) { var tmp = fieldType (ts); var ts1=tmp[0], ndx=tmp[1]; nd1.push (ndx); while (hd (ts1) === Token.Comma) { var tmp = fieldType (tl (ts1)); var ts1=tmp[0], ndx=tmp[1]; nd1.push (ndx); } } Debug.exit("Parser::fieldTypeList ", ts1); return [ts1,nd1]; } function fieldType (ts: TokenStream) : Array //[TokenStream, FIELD_TYPE] { Debug.enter("Parser::fieldType"); var tmp = fieldName (ts); var ts1=tmp[0], nd1=tmp[1]; ts1 = eat (ts1,Token.Colon); var tmp = nullableTypeExpression (ts1); var ts2=tmp[0], nd2=tmp[1]; Debug.exit("Parser::fieldType"); return [ts2, new FieldType (nd1,nd2)]; } /* ArrayType [ ElementTypeList ] ElementTypeList empty NullableTypeExpression , ElementTypeList NullableTypeExpression , ElementTypeList */ function arrayType (ts: TokenStream) : Array //[TokenStream, IAstTypeExpr] { Debug.enter("Parser::arrayType ", ts); ts = eat (ts,Token.LeftBracket); var tmp = elementTypeList (ts); var ts1=tmp[0], nd1=tmp[1]; ts1 = eat (ts1,Token.RightBracket); Debug.exit("Parser::arrayType ", ts1); return [ts1,new ArrayType (nd1)]; } function elementTypeList (ts: TokenStream) // : [TokenStream, [ELEMENT_TYPE]] { Debug.enter("Parser::elementTypeList ", ts); var nd1 = []; if (hd (ts) !== Token.RightBracket) { switch (hd (ts)) { case Token.Comma: var tmp = [tl (ts),new LiteralExpr (new LiteralUndefined)]; var ts1=tmp[0], ndx=tmp[1]; break; default: var tmp = nullableTypeExpression (ts); var ts1=tmp[0], ndx=tmp[1]; break; } nd1.push (ndx); while (hd (ts1) === Token.Comma) { ts1 = eat (ts1,Token.Comma); switch (hd (ts1)) { case Token.Comma: var tmp = [ts1,new LiteralExpr (new LiteralUndefined)]; var ts1=tmp[0], ndx=tmp[1]; break; default: var tmp = nullableTypeExpression (ts1); var ts1=tmp[0], ndx=tmp[1]; break; } nd1.push (ndx); } } Debug.exit("Parser::elementTypeList ", ts1); return [ts1,nd1]; } /* TypeExpressionList NullableTypeExpression TypeExpressionList , NullableTypeExpression refactored TypeExpressionList NullableTypeExpression TypeExpressionListPrime TypeExpressionListPrime empty , NullableTypeExpression TypeExpressionListPrime */ function typeExpressionList (ts: TokenStream) // : [TokenStream, [IAstTypeExpr]] { Debug.enter("Parser::typeExpressionList ", ts); var nd1 = []; var tmp = nullableTypeExpression (ts); var ts1=tmp[0], ndx=tmp[1]; nd1.push (ndx); while (hd (ts1) === Token.Comma) { var tmp = nullableTypeExpression (tl (ts1)); var ts1=tmp[0], ndx=tmp[1]; nd1.push (ndx); } Debug.exit("Parser::typeExpressionList ", ts1); return [ts1,nd1]; } // STATEMENTS /* Statement(tau, omega) BlockStatement(tau) BreakStatement Semicolon(omega) ContinueStatement Semicolon(omega) DefaultXMLNamespaceStatement Semicolon(omega) DoStatement Semicolon(omega) ExpressionStatement Semicolon(omega) ForStatement(omega) IfStatement(omega) LabeledStatement(omega) LetStatement(omega) ReturnStatement Semicolon(omega) SwitchStatement ThrowStatement Semicolon(omega) TryStatement WhileStatement(omega) WithStatement(omega) */ function statement (ts: TokenStream, tau: ITau, omega: IOmega) : Array //[TokenStream, STMT] { Debug.enter("Parser::statement ", ts); switch (hd(ts)) { case Token.If: var tmp = ifStatement (ts,omega); var ts2=tmp[0], nd2=tmp[1]; break; case Token.While: var tmp = whileStatement (ts,omega); var ts2=tmp[0], nd2=tmp[1]; break; case Token.For: var tmp = forStatement (ts,omega); var ts2=tmp[0], nd2=tmp[1]; break; case Token.Return: var tmp = returnStatement (ts); var ts1=tmp[0], nd1=tmp[1]; var ts2=semicolon (ts1,omega),nd2=nd1; break; case Token.Break: var tmp = breakStatement (ts); var ts1=tmp[0], nd1=tmp[1]; var ts2=semicolon (ts1,omega),nd2=nd1; break; case Token.Continue: var tmp = continueStatement (ts); var ts1=tmp[0], nd1=tmp[1]; var ts2=semicolon (ts1,omega),nd2=nd1; break; case Token.LeftBrace: var tmp = block (ts, tau); var ts1=tmp[0], nd1=tmp[1]; var ts2=ts1,nd2=new BlockStmt (nd1); break; case Token.Switch: switch (hd2 (ts)) { case Token.Type: var tmp = switchTypeStatement (ts); var ts2=tmp[0], nd2=tmp[1]; break; default: var tmp = switchStatement (ts); var ts2=tmp[0], nd2=tmp[1]; break; } break; case Token.Throw: var tmp = throwStatement (ts); var ts1=tmp[0], nd1=tmp[1]; var ts2=semicolon (ts1,omega),nd2=nd1; break; case Token.Try: var tmp = tryStatement (ts); var ts2=tmp[0], nd2=tmp[1]; break; default: var tmp = expressionStatement (ts); var ts1=tmp[0], nd1=tmp[1]; var ts2=semicolon (ts1,omega),nd2=nd1; break; } Debug.exit("Parser::statement ", ts2); return [ts2,nd2]; } function substatement (ts: TokenStream, omega: IOmega) : Array //[TokenStream, STMT] { Debug.enter("Parser::substatement ", ts); switch (hd(ts)) { case Token.SemiColon: var ts1=tl (ts),nd1= new EmptyStmt; break; default: var tmp = statement (ts,localBlk,omega); var ts1=tmp[0], nd1=tmp[1]; break; } Debug.exit("Parser::substatement ", ts1); return [ts1,nd1]; } var logicalLn = 0; function countLn () { ++logicalLn; } function printLn (ts:TokenStream) { Debug.enter("printLn ",ts.n/4); if (coordList.length <= ts.n/4) { //print("line eos"); } else { var coord = coordList[ts.n/4]; //print ("ln ",coord[0]+1," ",logicalLn); //print ("ln "+(coord[0]+1)); } Debug.exit("printLn"); } function newline (ts: TokenStream) : Boolean { var offset = ts.n/4; if (offset == 0) return true; // first token, so follows newline, but whose asking? //print ("ts.ts.position",ts.ts.position); //print ("offset ",offset); //print ("coordList",coordList); //print ("coordList.length",coordList.length); var coord = coordList[offset]; var prevCoord = coordList[offset-1]; //print("coord=",coord); //print("prevCoord=",prevCoord); if(coord[0] != prevCoord[0]) // do line coords match? return true; else return false; } function semicolon (ts: TokenStream, omega: IOmega) : TokenStream //[TokenStream] { Debug.enter("Parser::semicolon ", ts); switch (omega) { case fullStmt: switch (hd (ts)) { case Token.SemiColon: // print ("semicolon found"); var ts1 = tl (ts); break; case Token.EOS: case Token.RightBrace: var ts1 = ts; break; default: if (newline (ts)) { var ts1=ts; //print ("inserting semicolon") } else { throw "** error: expecting semicolon" } break; } break; case abbrevStmt: // Abbrev, ShortIf //print("abbrevStmt"); switch (hd (ts)) { case Token.SemiColon: var ts1 = tl (ts); break; default: var ts1 = ts; break; } break; default: throw "unhandled statement mode"; } Debug.exit("Parser::semicolon ", ts1); return ts1; } function expressionStatement (ts: TokenStream) : Array //[TokenStream, STMT] { Debug.enter("Parser::expressionStatement ", ts); var tmp = listExpression (ts,allowIn); var ts1=tmp[0], nd1=tmp[1]; Debug.exit("Parser::expressionStatement ", ts1); return [ts1, new ExprStmt (nd1)]; } function returnStatement (ts: TokenStream) : Array //[TokenStream, STMT] { Debug.enter("Parser::returnStatement ", ts); ts = eat (ts, Token.Return); switch (hd (ts)) { case Token.SemiColon: case Token.RightBrace: var ts1=ts,nd1=null; break; default: if (newline(ts)) { var ts1=ts,nd1=null; } else { var tmp = listExpression (ts,allowIn); var ts1=tmp[0], nd1=tmp[1]; } break; } Debug.exit("Parser::returnStatement ", ts1); return [ts1, new ReturnStmt (nd1)]; } function breakStatement (ts: TokenStream) : Array //[TokenStream, STMT] { Debug.enter("Parser::breakStatement ", ts); ts = eat (ts, Token.Break); switch (hd (ts)) { case Token.SemiColon: var ts1=tl (ts),nd1=null; break; case Token.RightBrace: var ts1=ts,nd1=null; break; default: if (newline(ts)) { var ts1=ts,nd1=null; } else { var tmp = identifier (ts); var ts1=tmp[0], nd1=tmp[1]; } break; } Debug.exit("Parser::breakStatement ", ts1); return [ts1, new BreakStmt (nd1)]; } function continueStatement (ts: TokenStream) : Array //[TokenStream, STMT] { Debug.enter("Parser::continueStatement ", ts); ts = eat (ts, Token.Continue); switch (hd (ts)) { case Token.SemiColon: var ts1=tl (ts),nd1=null; break; case Token.RightBrace: var ts1=ts,nd1=null; break; default: if (newline(ts)) { var ts1=ts,nd1=null; } else { var tmp = identifier (ts); var ts1=tmp[0], nd1=tmp[1]; } break; } Debug.exit("Parser::continueStatement ", ts1); return [ts1, new ContinueStmt (nd1)]; } function ifStatement (ts: TokenStream, omega) : Array //[TokenStream, STMT] { Debug.enter("Parser::ifStatement ", ts); ts = eat (ts,Token.If); var tmp = parenListExpression (ts); var ts1=tmp[0], nd1=tmp[1]; var tmp = substatement (ts1, omega); var ts2=tmp[0], nd2=tmp[1]; switch (hd (ts2)) { case Token.Else: var tmp = substatement (tl (ts2), omega); var ts3=tmp[0], nd3=tmp[1]; break; default: var ts3=ts2,nd3=null; break; } Debug.exit("Parser::ifStatement ", ts3); return [ts3, new IfStmt (nd1,nd2,nd3)]; } /* WhileStatement(omega) while ParenListExpression Substatement(omega) */ function whileStatement (ts: TokenStream, omega) : Array //[TokenStream, STMT] { Debug.enter("Parser::whileStatement ", ts); ts = eat (ts,Token.While); var tmp = parenListExpression (ts); var ts1=tmp[0], nd1=tmp[1]; var tmp = substatement (ts1, omega); var ts2=tmp[0], nd2=tmp[1]; var labels = []; Debug.exit("Parser::whileStatement ", ts2); return [ts2, new WhileStmt (nd1,nd2,labels)]; } /* ForStatement(omega) for ( ForInitialiser ; OptionalExpression ; OptionalExpression ) Substatement(omega) for ( ForInBinding in ListExpression(allowColon, allowIn) ) Substatement(omega) for each ( ForInBinding in ListExpression(allowColon, allowIn) ) Substatement(omega) */ function forStatement (ts: TokenStream, omega: IOmega) : Array //[TokenStream, STMT] { Debug.enter("Parser::forStatement ", ts); cx.enterLetBlock (); var stmt:IAstStmt; ts = eat (ts,Token.For); if (hd(ts)==Token.Each) { throw "For each loops not supported yet"; } else { ts = eat (ts,Token.LeftParen); var tmp = forInitialiser (ts); var ts1=tmp[0], nd1=tmp[1]; if (hd(ts1)==Token.In) { ts1 = eat(ts1,Token.In); var tmp = listExpression(ts1, allowIn); var ts2=tmp[0], nd2=tmp[1]; ts2 = eat (ts2,Token.RightParen); var tmp = substatement (ts2, omega); var ts4=tmp[0], nd4=tmp[1]; var labels = []; var head = cx.exitLetBlock (); stmt = new ForInStmt(head, nd1, nd2, nd4,labels); } else { ts1 = eat (ts1,Token.SemiColon); var tmp = optionalExpression (ts1); var ts2=tmp[0], nd2=tmp[1]; ts2 = eat (ts2,Token.SemiColon); var tmp = optionalExpression (ts2); var ts3=tmp[0], nd3=tmp[1]; ts3 = eat (ts3,Token.RightParen); var tmp = substatement (ts3, omega); var ts4=tmp[0], nd4=tmp[1]; var labels = []; var head = cx.exitLetBlock (); stmt = new ForStmt (head,nd1,nd2,nd3,nd4,labels) } } Debug.exit("Parser::forStatement ", ts4); return [ts4, stmt]; } /* ForInitialiser empty ListExpression(allowColon, noIn) VariableDefinition(noIn) ForInBinding Pattern(allowColon, noIn, allowExpr) VariableDefinitionKind VariableBinding(noIn) */ function forInitialiser (ts: TokenStream) : Array //[TokenStream, IAstExpr?] { Debug.enter("Parser::forInitialiser ", ts); switch (hd (ts)) { case Token.SemiColon: var ts1=ts,nd1=null; break; case Token.Const: case Token.Let: case Token.Var: var tmp = variableDefinition (ts,allowIn,localBlk,cx.pragmas.defaultNamespace,false,false); // XXX was noIn var ts1=tmp[0], nd1=tmp[1]; //assert (nd1.length==1); if (nd1[0] is ExprStmt) { var nd = nd1[0] as ExprStmt; nd1 = nd.expr; } else { throw "error forInitialiser " + nd; } break; default: var tmp = listExpression (ts,noIn); var ts1=tmp[0], nd1=tmp[1]; break; } //print ("nd1=",nd1); Debug.exit("Parser::forInitialiser ", ts1); return [ts1,nd1]; } /* */ function forInBinding (ts: TokenStream): Array { Debug.enter("Parser::forInBinding ", ts); // no really doing what the grammar chunk above is calling for. XXX switch (hd(ts)) { case Token.Const: case Token.Let: case Token.Var: var tmp = variableDefinition(ts, noIn, localBlk,cx.pragmas.defaultNamespace, false, false); var ts1=tmp[0], nd1=tmp[1]; if (nd1[0] is ExprStmt) { var nd = nd1[0] as ExprStmt; nd1 = nd.expr; } else { throw "error forInBinding "+ nd; } break; default: var tmp = listExpression (ts, noIn); var ts1=tmp[0], nd1=tmp[1]; break; } Debug.exit("Parser::forInBinding ", ts1); return [ts1,nd1]; } /* OptionalExpression empty ListExpression(allowColon, allowIn) */ function optionalExpression (ts: TokenStream) : Array //[TokenStream, IAstExpr?] { Debug.enter("Parser::optionalExpression ", ts); switch (hd (ts)) { case Token.SemiColon: case Token.RightBrace: var ts1=ts,nd1=null break; default: var tmp = listExpression (ts,noIn); var ts1=tmp[0], nd1=tmp[1]; break; } Debug.exit("Parser::optionalExpression ", ts1); return [ts1,nd1]; } /* SwitchStatement switch ParenListExpression { CaseElements } CaseElements empty CaseLabel CaseLabel CaseElementsPrefix CaseLabel CaseLabel CaseElementsPrefix Directives(abbrev) CaseElementsPrefix empty CaseElementsPrefix CaseLabel CaseElementsPrefix Directives(full) right recursive: CaseElementsPrefix empty CaseLabel CaseElementsPrefix Directives(full) CaseElementsPrefix */ function switchStatement (ts: TokenStream) : Array //[TokenStream, STMT] { Debug.enter("Parser::switchStatement ", ts); ts = eat (ts,Token.Switch); var tmp = parenListExpression (ts); var ts1=tmp[0], nd1=tmp[1]; ts1 = eat (ts1,Token.LeftBrace); switch (hd (ts1)) { case Token.Case: case Token.Default: var tmp = caseElementsPrefix (ts1); var ts2=tmp[0], nd2=tmp[1]; break; default: // do nothing break; } ts2 = eat (ts2,Token.RightBrace); var nd3 = []; // FIXME labels Debug.exit("Parser::switchStatement ", ts2); return [ts2, new SwitchStmt (nd1,nd2,nd3)]; } function caseElementsPrefix (ts: TokenStream) : Array //[TokenStream, CASES] { Debug.enter("Parser::caseElements ", ts); var ts1 = ts; var nd1 = []; while (hd (ts1) !== Token.RightBrace) { switch (hd (ts1)) { case Token.Case: case Token.Default: var tmp = caseLabel (ts1); var ts1=tmp[0], ndx=tmp[1]; nd1.push (new Case (ndx,[])); break; default: var tmp = directive (ts1,localBlk,fullStmt); // 'abbrev' is handled by RightBrace check in head var ts1=tmp[0], ndx=tmp[1]; for (var i=0; i */ function typeParameters (ts: TokenStream) : Array //[TokenStream, [IDENT]] { Debug.enter("Parser::typeParameters ", ts); switch (hd (ts)) { case Token.LeftDotAngle: ts = eat (ts, Token.LeftDotAngle); var tmp = typeParameterList (ts); var ts1=tmp[0], nd1=tmp[1]; ts1 = eat (ts1, Token.GreaterThan); break; default: var ts1=ts,nd1=[]; break; } Debug.exit("Parser::typeParameters ", ts1); return [ts1,nd1]; } /* TypeParameterList Identifier Identifier , TypeParameterList */ function typeParameterList (ts: TokenStream) : Array //[TokenStream, [IDENT]] { Debug.enter("Parser::typeParameterList ", ts); function typeParameterListPrime (ts) : Array //[TokenStream, [IDENT]] { switch (hd (ts)) { case Token.Comma: ts = eat (ts, Token.Comma); var tmp = identifier (ts); var ts1=tmp[0], nd1=tmp[1]; var tmp = typeParameterListPrime (ts1); var ts2=tmp[0], nd2=tmp[1]; break; default: var ts2=ts,nd2=[]; break; } return [ts2,nd2]; } var tmp = identifier (ts); var ts1=tmp[0], nd1=tmp[1]; var tmp = typeParameterListPrime (ts1); var ts2=tmp[0], nd2=tmp[1]; nd2.unshift (nd1); Debug.exit("Parser::typeParameterList ", ts2); return [ts2,nd2]; } /* Parameters empty NonemptyParameters */ function parameters (ts: TokenStream) : Array //[TokenStream, [[FIXTURES, Array], [IAstExpr], [IAstTypeExpr]], Boolean] { Debug.enter("Parser::parameters ", ts); switch (hd (ts)) { case Token.RightParen: var b1 = []; var i1 = []; var e1 = []; var t1 = []; //var [ts1,nd1,hasRest] = [ts,[[[],[]],e1,t1],false]; var ts1=ts, nd1=[[[],[]],e1,t1], hasRest=false; break; default: var tmp = nonemptyParameters (ts,0,false); var ts1=tmp[0], nd1=tmp[1], hasRest=tmp[2]; break; } Debug.exit("Parser::parameters ", ts1); return [ts1,nd1,hasRest]; } /* NonemptyParameters ParameterInit ParameterInit , NonemptyParameters RestParameter */ function nonemptyParameters (ts: TokenStream, n:int, initRequired) : Array //[TokenStream, [[FIXTURES,Array], Array, TYPE_EXPRS], Boolean] { Debug.enter("Parser::nonemptyParameters ", ts); switch (hd (ts)) { case Token.TripleDot: var tmp = restParameter (ts,n); var ts1=tmp[0], nd1=tmp[1]; /* var */ hasRest = true; break; default: var tmp = parameterInit (ts,n,initRequired); var ts1=tmp[0], nd1=tmp[1]; switch (hd (ts1)) { case Token.Comma: ts1 = eat (ts1, Token.Comma); //var [[f1,i1],e1,t1] = nd1; var f1=nd1[0][0], i1=nd1[0][1], e1=nd1[1], t1=nd1[2]; var tmp = nonemptyParameters (ts1, n+1, e1.length!=0); var ts2=tmp[0], nd2=tmp[1], hasRest=tmp[2]; //var [[f2,i2],e2,t2] = nd2; var f2=nd2[0][0], i2=nd2[0][1], e2=nd2[1], t2=nd2[2]; // FIXME when Array.concat works for (var i=0; i , w .< x > > > >", "q::[expr]", "(expr)::id", "(expr)::[expr]", "@a", "@q::id", "@q::[expr]", "@(expr)::id", "@(expr)::[expr]", "@[expr]", "/abcdefg/g", "/abcdefg/", "/abcdefg/i", "/abcdefg/x", "true", "false", "null", "(a)::x", "(function(a,b,c){})", "{x:a,y:b,z:c}", "[a,b,c]", "{(x):y}", "(function(){})", "(function f(a:A,b:B){})", "(function f.(a:T,b:U,c:V){})", // type expressions "T", "?T", "T!", "T~", "T.", "T.>", "T.<{a:A,t:{i:I,s:S}}>", "T.<{x:[A,B,C]}>", "T.<{x:(A,B,C)}>", "T.>>>", "T.!", "?T.", // Postfixx expressions "x.y", "new x", "new x()", "x()", "x.y()", "x++", "x--", "x.y++", "x.y()++", "new x.y++", */ ] var n = 0; // for each ( var p in programs ) for (;n ", p, tx1); // var nd2 = Decode::program (eval("("+tx1+")")); // var tx2 = Encode::program (nd2); // print(n, "-2> ", p, tx2); // // print("tx1.length=",tx1.length); // print("tx2.length=",tx2.length); // for (var i = 0; i < tx1.length; ++i) { // if (tx1[i] != tx2[i]) throw "error at pos "+i+" "+tx1[i]+ " != "+tx2[i]+" prefix: "+tx1.slice(i,tx1.length); // } // print("txt==tx2"); // } // catch(x) // { // print(x) // } } } // function }// class } // package import com.hurlant.eval.ast.*; import com.hurlant.eval.parse.Token; import com.hurlant.eval.Debug; import com.hurlant.eval.Util; interface IParserPattern {} class FieldPattern { // use default namespace public; public var ident: IAstIdentExpr; public var ptrn: IParserPattern; function FieldPattern (ident,ptrn) { this.ident = ident; this.ptrn = ptrn; } } class ObjectPattern implements IParserPattern { var ptrns //: Array; function ObjectPattern (ptrns) { this.ptrns = ptrns; } } class ArrayPattern implements IParserPattern { var ptrns //: PATTERNS; function ArrayPattern (ptrns) { this.ptrns = ptrns; } } class SimplePattern implements IParserPattern { var expr : IAstExpr; function SimplePattern (expr) { this.expr = expr; } } class IdentifierPattern implements IParserPattern { var ident : String; function IdentifierPattern (ident) { this.ident = ident; } } interface IAlpha {} class NoColon implements IAlpha {} class AllowColon implements IAlpha {} interface IBeta {} class NoIn implements IBeta {} class AllowIn implements IBeta {} interface IGamma {} class NoExpr implements IGamma {} class AllowExpr implements IGamma {} interface ITau {} class GlobalBlk implements ITau {} class ClassBlk implements ITau {} class InterfaceBlk implements ITau {} class LocalBlk implements ITau {} interface IOmega {} class FullStmt implements IOmega {} class AbbrevStmt implements IOmega {} class Context { //use default namespace public; public var env: Array; //ENV; public var varHeads //: [HEAD]; public var letHeads //: [HEAD]; public var ctor: Constructor; public var pragmas: Pragmas; public var pragmaEnv: Array; //PRAGMA_ENV; // push one PRAGMAS for each scope function Context (topFixtures) { env = [topFixtures]; varHeads = []; letHeads = []; ctor = null; pragmas = null; pragmaEnv = []; //print ("topFixtures.length=",topFixtures.length); // print ("env[0].length=",env[0].length); } function enterVarBlock () { //use namespace Ast; Debug.enter("enterVarBlock"); var varHead = new Head ([],[]); this.varHeads.push(varHead); this.env.push (varHead.fixtures); this.pragmas = new Pragmas (this.pragmas); this.pragmaEnv.push (this.pragmas); Debug.exit("exitVarBlock"); } function exitVarBlock () { Debug.enter("exitVarBlock"); var varHead = this.varHeads.pop (); this.env.pop (); this.pragmaEnv.pop (); if (this.pragmaEnv.length === 0) { this.pragmas = null; } else { this.pragmas = this.pragmaEnv[this.pragmaEnv.length-1]; } Debug.exit("exitVarBlock"); return varHead; } function hasFixture (fxtrs,fb) { //use namespace Ast; //var [fn,f1] = fb; var fn = fb[0], f1 = fb[1]; var x = fn; if (x is PropName) { if (hasName (fxtrs,fn.name.id,fn.name.ns)) { //print("hasName ",ns,"::",id); var f2 = getFixture (fxtrs,fn.name.id,fn.name.ns); if (f1 is ValFixture && f2 is ValFixture) { if (f1.type==Ast.anyType) return true; else if (f2.type==Ast.anyType) return true; // other positive cases here } throw "incompatible fixture redef "+fn.id; } } else if (x is TempName) { return false; // for now } } function addVarFixtures (fxtrs, isStatic=false) { var varHead = this.varHeads[this.varHeads.length-(isStatic?2:1)]; for (var n = 0, len = fxtrs.length; n < len; ++n) // until array conact works { var fb = fxtrs[n]; /// if (!hasFixture (varHead.fixtures,fb)) { varHead.fixtures.push (fxtrs[n]); /// } } } function addVarInits (inits, isStatic=false) { var varHead = this.varHeads[this.varHeads.length-(isStatic?2:1)]; for (var n = 0, len = inits.length; n < len; ++n) // until array conact works varHead.exprs.push (inits[n]); } function enterLetBlock () { Debug.enter("enterLetBlock"); var letHead = new Head ([],[]); this.letHeads.push(letHead); this.env.push (letHead.fixtures); this.pragmas = new Pragmas (this.pragmas); this.pragmaEnv.push (this.pragmas); Debug.exit("enterLetBlock"); } function exitLetBlock () { Debug.enter("exitLetBlock"); var letHead = this.letHeads.pop (); this.env.pop (); this.pragmaEnv.pop (); this.pragmas = this.pragmaEnv[this.pragmaEnv.length-1]; Debug.exit("exitLetBlock"); return letHead; } function addLetFixtures (fxtrs) { var letHead = this.letHeads[this.letHeads.length-1]; for (var n = 0, len = fxtrs.length; n < len; ++n) // until array conact works letHead.fixtures.push (fxtrs[n]); } function addLetInits (inits) { var letHead = this.letHeads[this.letHeads.length-1]; for (var n = 0, len = inits.length; n < len; ++n) // until array conact works letHead.exprs.push (inits[n]); } function openNamespace (nd: IAstIdentExpr) { Debug.enter("openNamespace"); var ns = evalIdentExprToNamespace (nd); //print("this.pragmas=",this.pragmas); var opennss = this.pragmas.openNamespaces; //print ("opennss=",opennss); //print ("opennss.length=",opennss.length); //print ("adding ns ",ns); opennss[opennss.length-1].push (ns); Debug.exit("openNamespace"); } function defaultNamespace (nd: IAstIdentExpr) { Debug.enter("defaultNamespace"); var ns = evalIdentExprToNamespace (nd); this.pragmas.defaultNamespace = ns; Debug.exit("defaultNamespace"); } function hasName (fxtrs,id,ns) { Debug.enter("hasName ",id); if (fxtrs.length==0) { Debug.exit("hasName false"); return false; } var pn = fxtrs[0][0]; //print ("pn",pn," is PropName",pn is PropName); //print ("pn.name",pn.name); //print ("pn..id=",pn.name.id," id=",id); //print ("pn..ns=",pn.name.ns.hash()," ns=",ns.hash()); if (pn.name.id==id && pn.name.ns.hash()==ns.hash()) // FIXME: need ns compare { Debug.exit("hasName true"); return true; } else { Debug.exit("hasName looking"); return hasName (fxtrs.slice (1,fxtrs.length),id,ns); } } function getFixture (fxtrs,id,ns) { Debug.enter("getFixture "); if (fxtrs.length===0) { throw "name not found " + ns + "::" + id; } var pn = fxtrs[0][0]; if (pn.name.id==id && pn.name.ns.toString()==ns.toString()) { Debug.exit("getFixture"); return fxtrs[0]; } else { Debug.exit("getFixture"); return getFixture (fxtrs.slice (1,fxtrs.length),id,ns); } } /* two dimensional search repeat for each shadowed name each name in each head dup is error for each namespace set find all names in the inner most head */ function findFixtureWithNames (id,nss, it: IAstInitTarget ?) { Debug.enter("findFixtureWithNames"); var env = this.env; switch (it) { case Ast.instanceInit: var start = env.length-2; var stop = start; break; case null: var start = env.length-1; var stop = 0; break; default: throw "error findFixtureWithName: unimplemented target"; } //print ("env.length=",env.length); for (var i=start; i>=stop; --i) // for each head { var ns = null; var fxtrs = env[i]; //print ("nss.length=",nss.length); for (var j=nss.length-1; j>=0; --j) { //print ("nss[",j,"]=",nss[j]); if (hasName (fxtrs,id,nss[j])) { if (ns !== null) { throw "ambiguous reference to " + id; } ns = nss[j]; } } if (ns!==null) { Debug.exit("findFixtureWithNames"); return getFixture (fxtrs,id,ns); } } Debug.exit("findFixtureWithNames"); return null; } function findFixtureWithIdentifier (id: String, it: IAstInitTarget ?) { Debug.enter("findFixtureWithIdentifier ", id); //print ("this.pragmas=",this.pragmas); var nsss = this.pragmas.openNamespaces; //print ("nsss.length=",nsss.length); for (var i=nsss.length-1; i>=0; --i) { //print ("nsss[",i,"]=",nsss[i]); var fx = findFixtureWithNames (id,nsss[i],it); if (fx !== null) { Debug.exit("findFixtureWithIdentifier"); return fx; } } throw "fixture not found: " + id; } function evalIdentExprToNamespace (nd: IAstIdentExpr) : IAstNamespace { Debug.enter("evalIdentExprToNamespace"); var fxtr = null; var val = null; var x = nd; if (x is Identifier) { var fxtr = findFixtureWithIdentifier ((nd as Identifier).ident,null); var x2 = fxtr[1]; if (x2 is NamespaceFixture) { var val = fxtr.ns; return fxtr.ns; } else { throw "fixture with unknown value " + fxtr; } } else if (x is ReservedNamespace) { var val = (nd as ReservedNamespace).ns; return val; } else { throw "evalIdentExprToNamespace: case not implemented " + nd; } Debug.exit("evalIdentExprToNamespace ", val); return val; } function resolveIdentExpr (nd: IAstIdentExpr, it: IAstInitTarget ) : IAstFixtureName { Debug.enter("resolveIdentExpr"); var x = nd; if (x is Identifier) { var fxtr = findFixtureWithIdentifier ((nd as Identifier).ident, it); } else { throw "resolveIdentExpr: case not implemented " + nd; } Debug.exit("resolveIdentExpr ", fxtr); return fxtr[0]; } } //type TOKENS = TokenStream; // [int]; class TokenStream { import flash.utils.*; var ts: ByteArray var n: int; var current_tok; function TokenStream (ts) { this.ts = ts; n = 0; ts.position = n; } function head () : int { //print("head ts.position ",ts.position," n ",n); if (ts.position == n) { current_tok = ts.readInt (); //print ("current_tok ",current_tok); } Util.assert (ts.position == n+4); return current_tok; } function head2 () : int { //print("head2 ts.position ",ts.position," n ",n); if (ts.position == n) { current_tok = ts.readInt (); //print ("current_tok ",current_tok); } Util.assert (ts.position == n+4); var pos = ts.position; var tk = ts.readInt (); ts.position = pos; return tk; } function next () : void { n = n + 4; head (); //print ("next n",n); } public function toString () { return Token.tokenText(this.head()) } } class Pragmas { //use default namespace public; public var openNamespaces //: [[IAstNamespace]]; public var defaultNamespace: IAstNamespace; function Pragmas (pragmas) { Debug.enter("Pragma ",pragmas); if (pragmas==null) { this.openNamespaces = [[]]; this.defaultNamespace = new PublicNamespace (""); } else { this.openNamespaces = Util.copyArray (pragmas.openNamespaces); this.defaultNamespace = pragmas.defaultNamespace; } if (this.openNamespaces[this.openNamespaces.length-1].length !== 0) { this.openNamespaces.push ([]); // otherwise reuse the last one pushed } Debug.exit("Pragma"); } } // more stubs for functions that are mysteriously missing. // [HOW THE FARK IS THIS STUFF EVER SUPPOSED TO COMPILE?? ] function brackets(ts:TokenStream):Array { throw new Error("not implemented."); return [ts,null]; } function expressionQualifiedIdentifier(ts:TokenStream):Array { throw new Error("not implemented."); return [ts,null]; } function functionType(ts:TokenStream):Array { throw new Error("not implemented."); return [ts,null]; } function letExpression(ts:TokenStream, beta:IBeta):Array { throw new Error("not implemented."); return [ts,null]; } // http://wiki.ecmascript.org/doku.php?id=proposals:local_packages function packages(ts:TokenStream):Array { throw new Error("not implemented."); return [ts,null]; } function primaryNameList(ts:TokenStream):Array { throw new Error("not implemented."); return [ts,null]; } function restParameter(ts:TokenStream, n:int):Array { throw new Error("not implemented."); return [ts,null]; } function superExpression(ts:TokenStream):Array { throw new Error("not implemented."); return [ts,null]; } function yieldExpression(ts:TokenStream, beta:IBeta):Array { throw new Error("not implemented."); return [ts,null]; }