} // ParseFunction // Parse a Block. The stream should be positioned at the "{" token. private StmtFrag ParseBlock(FunctionInfo info) { StmtFrag frag = gen.NewStmtFrag(tok.Prev().loc); tok.MatchOp("{"); while (!tok.TryMatchOp("}")) frag.Append(ParseStatement(info)); return frag; } // ParseBlock
} // ParseProgram // Parse a SourceElements (i.e. the main program, or a function body) // and return the generated code. private StmtFrag ParseSourceElements( FunctionInfo info, CGFuncInfo cgFuncInfo ) { SrcLoc loc; loc.lineNum = 1; loc.colNum = 1; loc.absPosition = 0; loc.len = 1; StmtFrag frag = gen.NewStmtFrag(loc); while (!tok.atEnd && !tok.PeekOp("}")) if (tok.TryMatchKeyword("function")) ParseFunction(info.GetNextChild(), false); else frag.Append(ParseStatement(info)); return frag; } // ParseSourceElements
} // ParseForStatement // Parse a Statement. private StmtFrag ParseStatement(FunctionInfo info) { StringCollection labels = MatchLabelSet(); if (tok.TryMatchKeyword("do")) { LoopInfo loopInfo = gen.NewLoopInfo( curCGFuncInfo, tok.Prev().loc, labels ); loops.Push(loopInfo); StmtFrag body = ParseStatement(info); tok.MatchKeyword("while"); tok.MatchOp("("); ExprFrag condition = ParseExpression(info, true); tok.MatchOp(")"); tok.MatchOp(";"); LoopInfo temp = (LoopInfo) loops.Pop(); Trace.Assert(temp == loopInfo); return gen.DoWhile(loopInfo, body, condition); } else if (tok.TryMatchKeyword("while")) { LoopInfo loopInfo = gen.NewLoopInfo( curCGFuncInfo, tok.Prev().loc, labels ); loops.Push(loopInfo); tok.MatchOp("("); ExprFrag condition = ParseExpression(info, true); tok.MatchOp(")"); StmtFrag body = ParseStatement(info); LoopInfo temp = (LoopInfo) loops.Pop(); Trace.Assert(temp == loopInfo); return gen.WhileDo(loopInfo, condition, body); } else if (tok.TryMatchKeyword("for")) return ParseForStatement(info, labels); else { bool isSwitch = tok.PeekKeyword("switch"); LoopInfo labelInfo = null; if (labels != null || isSwitch) { labelInfo = gen.NewLabeledStmtInfo( curCGFuncInfo, tok.Prev().loc, labels, isSwitch ); loops.Push(labelInfo); } StmtFrag stmt; if (tok.PeekOp("{")) stmt = ParseBlock(info); else if (tok.TryMatchKeyword("var")) { stmt = gen.NewStmtFrag(tok.Prev().loc); do { string varName; SrcLoc varLoc; stmt.Append(ParseVariableDeclaration( info, true, out varName, out varLoc )); } while (tok.TryMatchOp(",")); tok.MatchOp(";"); } else if (tok.TryMatchOp(";")) { // EmptyStatement stmt = gen.NewStmtFrag(tok.Prev().loc); } else if (tok.TryMatchKeyword("if")) { SrcLoc ifLoc = tok.Prev().loc; tok.MatchOp("("); ExprFrag condition = ParseExpression(info, true); tok.MatchOp(")"); StmtFrag ifClause = ParseStatement(info); StmtFrag elseClause = null; if (tok.TryMatchKeyword("else")) elseClause = ParseStatement(info); stmt = gen.IfThenElse(ifLoc, condition, ifClause, elseClause); } else if (tok.TryMatchKeyword("continue")) { SrcLoc continueLoc = tok.Prev().loc; // HACK snewman 8/7/01: the grammar (ContinueStatement) specifies // "no LineTerminator here". string id; tok.TryMatchID(out id); tok.MatchOp(";"); stmt = gen.Continue(continueLoc, id, CloneStack(loops)); } else if (tok.TryMatchKeyword("break")) { SrcLoc breakLoc = tok.Prev().loc; // HACK snewman 8/7/01: the grammar (BreakStatement) specifies // "no LineTerminator here". string id; tok.TryMatchID(out id); tok.MatchOp(";"); stmt = gen.Break(breakLoc, id, CloneStack(loops)); } else if (tok.TryMatchKeyword("return")) { SrcLoc returnLoc = tok.Prev().loc; // HACK snewman 8/7/01: the grammar (ReturnStatement) specifies // "no LineTerminator here". if (tok.TryMatchOp(";")) stmt = gen.Return(returnLoc, null); else { ExprFrag value = ParseExpression(info, true); tok.MatchOp(";"); stmt = gen.Return(returnLoc, value); } } else if (tok.TryMatchKeyword("with")) { SrcLoc withLoc = tok.Prev().loc; tok.MatchOp("("); ExprFrag value = ParseExpression(info, true); tok.MatchOp(")"); WithInfo withInfo = gen.NewWithInfo(curCGFuncInfo, withLoc); withs.Push(withInfo); StmtFrag body = ParseStatement(info); WithInfo temp = (WithInfo) withs.Pop(); Trace.Assert(temp == withInfo); stmt = gen.With(withInfo, value, body); } else if (tok.TryMatchKeyword("switch")) { SrcLoc switchLoc = tok.Prev().loc; SwitchInfo switchInfo = gen.NewSwitchInfo(); tok.MatchOp("("); ExprFrag switchValue = ParseExpression(info, true); tok.MatchOp(")"); tok.MatchOp("{"); while (!tok.TryMatchOp("}")) { ExprFrag caseValue; if (tok.TryMatchKeyword("default")) caseValue = null; else { tok.MatchKeyword("case"); caseValue = ParseExpression(info, true); } StmtFrag clauseStmt = null; tok.MatchOp(":"); while ( !tok.PeekOp("}") && !tok.PeekKeyword("case") && !tok.PeekKeyword("default") ) { StmtFrag tempStmt = ParseStatement(info); if (clauseStmt == null) clauseStmt = tempStmt; else clauseStmt.Append(tempStmt); } switchInfo.AddCase(caseValue, clauseStmt); } stmt = gen.Switch(switchLoc, switchValue, switchInfo); } else if (tok.TryMatchKeyword("throw")) { SrcLoc throwLoc = tok.Prev().loc; // HACK snewman 8/7/01: the grammar (ThrowStatement) specifies // "no LineTerminator here". ExprFrag value = ParseExpression(info, true); tok.MatchOp(";"); stmt = gen.Throw(throwLoc, value); } else if (tok.TryMatchKeyword("try")) { SrcLoc tryLoc = tok.Prev().loc; StmtFrag tryBody = ParseBlock(info); String catchVar = null; WithInfo catchWithInfo = null; StmtFrag catchBody = null; StmtFrag finallyBody = null; if (tok.TryMatchKeyword("catch")) { SrcLoc catchLoc = tok.Prev().loc; tok.MatchOp("("); catchVar = tok.MatchID(); tok.MatchOp(")"); catchWithInfo = gen.NewWithInfo(curCGFuncInfo, catchLoc); withs.Push(catchWithInfo); catchBody = ParseBlock(info); WithInfo temp = (WithInfo) withs.Pop(); Trace.Assert(temp == catchWithInfo); } if (tok.TryMatchKeyword("finally")) finallyBody = ParseBlock(info); stmt = gen.TryCatchFinally( tryLoc, tryBody, catchVar, catchWithInfo, catchBody, finallyBody ); } else { ExprFrag expr = ParseExpression(info, true); tok.MatchOp(";"); stmt = gen.ExpressionStmt(expr); } if (labelInfo != null) { LoopInfo temp2 = (LoopInfo) loops.Pop(); Trace.Assert(temp2 == labelInfo); stmt = gen.LabeledStmt(labelInfo, stmt); } return stmt; } } // ParseStatement
} // MatchLabelSet // Parse a for statement. The caller should already have matched // the "for" keyword. private StmtFrag ParseForStatement(FunctionInfo info, StringCollection labels) { LoopInfo loopInfo = gen.NewLoopInfo(curCGFuncInfo, tok.Prev().loc, labels); loops.Push(loopInfo); // HACK snewman 8/13/01: need to review this section against the // specific semantics for "for" statements, and especially for/in // statements, in section 12.6 of the ECMA spec. tok.MatchOp("("); bool isIn; // True for for/in, false otherwise StmtFrag init=null; // Initializer; used for both types of loop ExprFrag cond=null; // Condition; only used for non-in loops ExprFrag update=null; // Update step; only used for non-in loops ExprFrag inLHS=null; // LHS expression where in loops put prop names ExprFrag inRHS=null; // RHS object that in loops iterate over if (tok.TryMatchKeyword("var")) { string varName; SrcLoc varLoc; init = ParseVariableDeclaration(info, false, out varName, out varLoc); isIn = tok.TryMatchKeyword("in"); if (isIn) inLHS = gen.IdentifierExpr( varLoc, varName, info, CloneStack(withs) ); else { while (tok.TryMatchOp(",")) init.Append(ParseVariableDeclaration( info, false, out varName, out varLoc )); } } else { if (!tok.PeekOp(";")) { ExprFrag initExpr = ParseExpression(info, false, 99); isIn = tok.TryMatchKeyword("in"); if (isIn) inLHS = initExpr; else init = gen.ExpressionStmt(initExpr); } else isIn = false; } if (isIn) inRHS = ParseExpression(info, true); else { tok.MatchOp(";"); if (!tok.PeekOp(";")) cond = ParseExpression(info, true); tok.MatchOp(";"); if (!tok.PeekOp(")")) update = ParseExpression(info, true); } tok.MatchOp(")"); StmtFrag body = ParseStatement(info); LoopInfo temp = (LoopInfo) loops.Pop(); Trace.Assert(temp == loopInfo); if (isIn) return gen.ForIn(loopInfo, init, inLHS, inRHS, body); else return gen.For(loopInfo, init, cond, update, body); } // ParseForStatement