Пример #1
0
		} // CaptureTokens
	
	
	// Read JavaScript source text and output a C# file.  progClassName
	// is the name of the C# class we generate.  inputFileLabel denotes
	// the source of the input text; it is inserted in a comment in the
	// C# source.
	public static void CompileToCSharp( TextReader input, TextWriter output,
										string progClassName,
										string inputFileLabel,
										bool forEvalCode )
		{
		Tokenizer tokenizer = new Tokenizer(input);
		TokenListNode tokenList = CaptureTokens(tokenizer);
		
		Phase1Parser parser = new Phase1Parser(new Retokenizer(tokenList));
		
		ProgramInfo programInfo = new ProgramInfo();
		FunctionInfo rootFunc = new FunctionInfo(programInfo, null, null);
		
		parser.ParseProgram(rootFunc);
		
		PrettyPrinter pp = new PrettyPrinter(output);
		
		pp.Line("// JANET compiler output for source file " + inputFileLabel);
		pp.Line("// ");
		
		CSharpGenerator gen = new CSharpGenerator( rootFunc, pp, progClassName,
												   forEvalCode );
		Phase2Parser parser2 = new Phase2Parser( new Retokenizer(tokenList),
												 gen );
		parser2.ParseProgram(rootFunc);
		} // CompileToCSharp
Пример #2
0
		} // Phase2Parser constructor
	
	
	// Parse a program from the input stream, given the FunctionInfo
	// object for the program's root scope.
	public void ParseProgram(FunctionInfo info)
		{
		gen.EmitProgramPrefix();
		
		CGFuncInfo cgFuncInfo = gen.NewFuncInfo(info);
		
		curCGFuncInfo = cgFuncInfo;
		gen.EmitMainFunction(ParseSourceElements(info, cgFuncInfo));
		
		Trace.Assert(curCGFuncInfo == cgFuncInfo);
		Trace.Assert(loops.Count == 0);
		Trace.Assert(withs.Count == 0);
		
		curCGFuncInfo = null;
		
		gen.EmitProgramSuffix();
		} // ParseProgram
Пример #3
0
		} // 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
Пример #4
0
		} // ParseSourceElements
	
	
	// Parse a FunctionDeclaration or FunctionExpression.  The "function"
	// keyword should already have been matched.
	private void ParseFunction(FunctionInfo info, bool isExpression)
		{
		// Save the current loop and with stacks.  OPTIMIZATION: don't need to
		// do this if the stack was empty.
		Stack savedLoops = loops;
		loops = new Stack();
		
		Stack savedWiths = withs;
		withs = new Stack();
		
		CGFuncInfo savedCGFuncInfo = curCGFuncInfo;
		CGFuncInfo cgFuncInfo = gen.NewFuncInfo(info);
		curCGFuncInfo = cgFuncInfo;
		
		string functionName = null;
		
		if (isExpression)
			tok.TryMatchID(out functionName);
		else
			functionName = tok.MatchID();
		
		// Scan to the end of the parameter list.  We don't bother parsing
		// it in detail, as this was done during the first phase.
		while (!tok.TryMatchOp(")"))
			tok.Match();
		
		tok.MatchOp("{");
		StmtFrag body = ParseSourceElements(info, cgFuncInfo);
		tok.MatchOp("}");
		
		gen.EmitFunction(info, body);
		
		Trace.Assert(loops.Count == 0);
		Trace.Assert(withs.Count == 0);
		Trace.Assert(curCGFuncInfo == cgFuncInfo);
		loops = savedLoops;
		withs = savedWiths;
		curCGFuncInfo = savedCGFuncInfo;
		} // ParseFunction
Пример #5
0
	// Construct a FunctionInfo object.  parent should be the info object
	// for the enclosing function, or null if we are the root program.
	// nameInParent should be the function name, or null for functions that
	// are defined in an expression (even if the function is named in the
	// expression, since such names don't create an entry in the parent's
	// scope).  nameInParent should also be null for the root function.
	// 
	// If parent is not null, we add ourselves to its children list.
	public FunctionInfo(ProgramInfo program, FunctionInfo parent, string nameInParent)
		{
		program_    = program;
		parent_     = parent;
		firstChild_ = null;
		lastChild_  = null;
		nextSib_    = null;
		childScan_  = null;
		
		nameInParent_ = nameInParent;
		
		callsEval_ = false;
		usesArgs_  = false;
		
		params_ = new StringCollection();
		locals_ = new StringCollection();
		
		// Register ourselves in our parent scope.
		if (parent != null)
			{
			if (parent.firstChild_ == null)
				{
				Trace.Assert(parent.lastChild_ == null);
				parent.firstChild_ = this;
				parent.childScan_  = this;
				parent.lastChild_  = this;
				}
			else
				{
				Trace.Assert(parent.lastChild_ != null);
				parent.lastChild_.nextSib_ = this;
				parent.lastChild_ = this;
				}
			
			}
		
		} // FunctionInfo constructor
Пример #6
0
		} // ParseExpression
	
	
	// Parse a LeftHandSideExpression.
	// 
	// If checkForCallExpr is false, then we don't check for CallExpressions.
	// This is used when parsing the function in a "new" expression, to
	// avoid parsing arguments to "new" as part of the expression that
	// specifies the function.
	private ExprFrag ParseLeftHandSideExpression( FunctionInfo info,
												  bool checkForCallExpr )
		{
		ExprFrag expr;
		if (tok.TryMatchKeyword("new"))
			{
			SrcLoc newLoc = tok.Prev().loc;
			
			ExprFrag constructor = ParseLeftHandSideExpression(info, false);
			ArrayList args = null;
			if (tok.TryMatchOp("("))
				args = MatchOptionalArgumentList(info);
			
			expr = gen.Construct(newLoc, constructor, args);
			}
		else if (tok.TryMatchKeyword("function"))
			{
			SrcLoc functionLoc = tok.Prev().loc;
			FunctionInfo childInfo = info.GetNextChild();
			ParseFunction(childInfo, true);
			expr = gen.FunctionExpr(functionLoc, childInfo);
			}
		else
			expr = ParsePrimaryExpression(info);
		
		while (true)
			if (checkForCallExpr && tok.TryMatchOp("("))
				{
				SrcLoc opLoc = tok.Prev().loc;
				ArrayList args = MatchOptionalArgumentList(info);
				expr = gen.Call(opLoc, expr, args);
				}
			else if (tok.TryMatchOp("["))
				{
				SrcLoc opLoc = tok.Prev().loc;
				expr = gen.ArrayReference(opLoc, expr, this.ParseExpression(info, true));
				tok.MatchOp("]");
				}
			else if (tok.TryMatchOp("."))
				{
				SrcLoc opLoc = tok.Prev().loc;
				expr = gen.FieldReference(opLoc, expr, tok.MatchID());
				}
			else
				return expr;
		
		} // ParseLeftHandSideExpression
Пример #7
0
		} // ParseStatement
	
	
	// Parse a VariableDeclaration, filling in info with any declarations.
	// See ParseExpression for an explanation of allowIN.
	private void ParseVariableDeclaration(FunctionInfo info, bool allowIN)
		{
		info.AddLocalName(tok.MatchID());
		if (tok.TryMatchOp("="))
			ParseExpression(info, allowIN, assignmentPrec);
		
		} // ParseVariableDeclaration
Пример #8
0
		} // CSharpGenerator constructor
	
	
	// Create a CGFuncInfo object for the given function.
	public CGFuncInfo NewFuncInfo(FunctionInfo func)
		{
		return new CSharpGenFuncInfo(func);
		} // NewFuncInfo
Пример #9
0
		} // ParseExpression
	
	
	// Simplified version of ParseExpression (no isLHS parameter).
	private void ParseExpression( FunctionInfo info, bool allowIN,
								 int maxPrecedence )
		{
		bool isLHS; // Unused result
		ParseExpression(info, allowIN, maxPrecedence, out isLHS);
		} // ParseExpression
Пример #10
0
		} // StringLiteralExpr
	
	
	// Return an expression to reference the given identifier.
	// enclosingWiths should be a stack of WithInfo objects, giving
	// all with scopes in the current function that enclose the identifier
	// reference.
	// 
	// HACK snewman 8/13/01: this method, and ArgumentsExpr below, need a
	// way to search "with" statements in enclosing scopes (for function
	// expressions and expr code).
	public ExprFrag IdentifierExpr( SrcLoc loc, string id,
									FunctionInfo function,
									Stack enclosingWiths )
		{
		// HACK snewman 8/20/01: extend this to support function scopes
		// where not all identifiers are known at compile time (because
		// they invoke "eval").
		
		// Determine which enclosing scope, if any, defines the identifier.
		FunctionInfo bindingScope = function;
		while (bindingScope != null && !bindingScope.IDBoundInThisScope(id))
			bindingScope = bindingScope.parent;
		
		// HACK snewman 8/20/01: add support for locals that are implemented
		// directly as C# locals.  I think this needs to be added in some
		// other places as well, such as EmitFunction.
		if (bindingScope == null || bindingScope.isRoot)
			return new CSharpVariableRef(loc, id, null, enclosingWiths);
		else if (bindingScope == function)
			return new CSharpVariableRef(loc, id, function, enclosingWiths);
		else
			{
			// HACK snewman 8/20/01: add support for referencing a local
			// variable of an enclosing scope.
			throw new ParseError( "Access to parent function variables not yet implemented",
								  loc );
			}
		
		} // IdentifierExpr
Пример #11
0
		} // 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
Пример #12
0
		} // 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
Пример #13
0
		} // ParsePrimaryExpression
	
	
	// Match an ArgumentList (if any) and the trailing ')'.  Fill in info
	// with any declarations.
	void MatchOptionalArgumentList(FunctionInfo info)
		{
		if (!tok.PeekOp(")"))
			{
			do
				ParseExpression(info, true, assignmentPrec);
			while (tok.TryMatchOp(","));
			}
		
		tok.MatchOp(")");
		} // MatchOptionalArgumentList
Пример #14
0
		} // ParseLeftHandSideExpression
	
	
	// Parse a PrimaryExpression, filling in info with any declarations.
	void ParsePrimaryExpression(FunctionInfo info)
		{
		string id;
		double d;
		string s;
		
		if (tok.TryMatchKeyword("this"))
			{}
		else if (tok.TryMatchKeyword("null"))
			{}
		else if (tok.TryMatchKeyword("true"))
			{}
		else if (tok.TryMatchKeyword("false"))
			{}
		else if (tok.TryMatchOp("("))
			{
			ParseExpression(info, true);
			tok.MatchOp(")");
			}
		else if (tok.TryMatchOp("{"))
			{
			if (!tok.PeekOp("}"))
				{
				do
					{
					if (tok.TryMatchNumLit(out d))
						{}
					else if (tok.TryMatchStringLit(out s))
						{}
					else
						tok.MatchID();
					
					tok.MatchOp(":");
					ParseExpression(info, true, assignmentPrec);
					}
				while (tok.TryMatchOp(","));
				}
			
			tok.MatchOp("}");
			}
		else if (tok.TryMatchOp("["))
			{
			bool requireComma = false;
			while (!tok.PeekOp("]"))
				if (tok.TryMatchOp(","))
					requireComma = false;
				else if (!requireComma)
					{
					ParseExpression(info, true, assignmentPrec);
					requireComma = true;
					}
				else
					break;
			
			tok.MatchOp("]");
			}
		else if (tok.TryMatchID(out id))
			{
			if (id == "eval")
				info.CallsEval();
			else if (id == "arguments")
				info.UsesArgs();
			
			// If the id is not bound in any enclosing scope, then list it
			// as a potential global.  Note that this is conservative -- it
			// may actually be bound by a declaration we haven't parsed yet.
			// 
			// HACK snewman 8/9/01: as currently implemented, this will not
			// filter out identifiers that are bound by an enclosing "catch"
			// clause.
			if (!info.IDHasNonglobalBinding(id))
				info.program.PotentialGlobal(id);
			
			}
		else if (tok.TryMatchNumLit(out d))
			{}
		else if (tok.TryMatchStringLit(out s))
			{}
		else
			{
			tok.Match();
			ReportError("bad token when an expression was expected");
			}
		
		} // ParsePrimaryExpression
Пример #15
0
		} // ParseExpression
	
	
	// Parse a LeftHandSideExpression, filling in info with any declarations.
	// 
	// If checkForCallExpr is false, then we don't check for CallExpressions.
	// This is used when parsing the function in a "new" expression, to
	// avoid parsing arguments to "new" as part of the expression that
	// specifies the function.
	void ParseLeftHandSideExpression(FunctionInfo info, bool checkForCallExpr)
		{
		if (tok.TryMatchKeyword("new"))
			{
			ParseLeftHandSideExpression(info, false);
			if (tok.TryMatchOp("("))
				MatchOptionalArgumentList(info);
			
			}
		else if (tok.TryMatchKeyword("function"))
			ParseFunction(info, true);
		else
			ParsePrimaryExpression(info);
		
		while (true)
			if (checkForCallExpr && tok.TryMatchOp("("))
				MatchOptionalArgumentList(info);
			else if (tok.TryMatchOp("["))
				{
				this.ParseExpression(info, true);
				tok.MatchOp("]");
				}
			else if (tok.TryMatchOp("."))
				tok.MatchID();
			else
				break;
		
		} // ParseLeftHandSideExpression
Пример #16
0
		} // ParseExpression
	
	
	// Parse an Expression, filling in info with any declarations.
	// 
	// If allowIN is false, then we don't look for "in" operators.  (This
	// implements the "NoIn" variant of the grammar, e.g. ExpressionNoIn
	// as opposed to Expression.)
	// 
	// This method can also be used to parse "smaller" nonterminals such
	// as AssignmentExpression, ConditionalExpression, and so on down to
	// MultiplicativeExpression.  This is controlled by the maxPrecedence
	// parameter: we ignore any operators with a looser (numerically
	// greater) precedence than maxPrecedence.
	// 
	// We set isLHS to true if this was a simple LeftHandSideExpression,
	// false if it included any operators.
	void ParseExpression( FunctionInfo info, bool allowIN,
						  int maxPrecedence, out bool isLHS )
		{
		// Note that we don't strictly follow the ECMAScript grammar here.
		// The grammar is designed to prevent assignment to a non-lvalue.
		// This is a hassle to implement in the parser, and leads to confusing
		// error messages.  Instead, we allow any expression (except an
		// assignment expression) to parse as the left-hand side of an
		// assignment, but then we report an error if the parsed LHS is not
		// a valid LeftHandSideExpression.
		
		isLHS = true;
		
		// Parse any prefix operators.
		OperatorInfo matchedOp;
		while (TryMatchOperator(true, -1, out matchedOp, true))
			isLHS = false;
		
		ParseLeftHandSideExpression(info, true);
		
		while (TryMatchOperator(allowIN, maxPrecedence, out matchedOp, true))
			{
			if (matchedOp.text == "?")
				{
				ParseExpression(info, allowIN, assignmentPrec);
				tok.MatchOp(":");
				ParseExpression(info, allowIN, assignmentPrec);
				}
			else if (matchedOp.opType == OperatorInfo.Types.assignment)
				{
				if (!isLHS)
					ReportError("illegal expression in left side of assignment");
				ParseExpression( info, allowIN, matchedOp.precedence,
								 out isLHS );
				}
			else if (matchedOp.opType == OperatorInfo.Types.binary)
				ParseExpression( info, allowIN, matchedOp.precedence-1,
								 out isLHS );
			
			isLHS = false;
			}
		
		} // ParseExpression
Пример #17
0
		} // ParseLeftHandSideExpression
	
	
	// Parse a PrimaryExpression.
	private ExprFrag ParsePrimaryExpression(FunctionInfo info)
		{
		string id;
		double d;
		string s;
		
		if (tok.TryMatchKeyword("this"))
			return gen.ThisExpr(tok.Prev().loc, info);
		else if (tok.TryMatchKeyword("null"))
			return gen.NullExpr(tok.Prev().loc);
		else if (tok.TryMatchKeyword("true"))
			return gen.BoolLiteralExpr(tok.Prev().loc, true);
		else if (tok.TryMatchKeyword("false"))
			return gen.BoolLiteralExpr(tok.Prev().loc, false);
		else if (tok.TryMatchOp("("))
			{
			ExprFrag expr = ParseExpression(info, true);
			tok.MatchOp(")");
			return expr;
			}
		else if (tok.TryMatchOp("{"))
			{
			SrcLoc startLoc = tok.Prev().loc;
			ObjectLiteralInfo litInfo = gen.NewObjectLiteralInfo();
			
			if (!tok.PeekOp("}"))
				{
				do
					{
					double tempD;
					if (tok.TryMatchNumLit(out tempD))
						{
						// HACK snewman 7/26/01: format according to the ECMA spec.
						id = System.Convert.ToString(tempD);
						}
					else if (tok.TryMatchStringLit(out id))
						{}
					else
						id = tok.MatchID();
					
					SrcLoc idLoc = tok.Prev().loc;
					tok.MatchOp(":");
					ExprFrag value = ParseExpression(info, true, assignmentPrec);
					
					litInfo.AddProp(idLoc, id, value);
					}
				while (tok.TryMatchOp(","));
				}
			
			tok.MatchOp("}");
			
			return gen.ObjectLiteralExpr(startLoc, litInfo);
			}
		else if (tok.TryMatchOp("["))
			{
			SrcLoc startLoc = tok.Prev().loc;
			ArrayLiteralInfo arrayInfo = gen.NewArrayLiteralInfo();
			
			bool anyCommas = false;
			bool requireComma = false;
			while (!tok.PeekOp("]"))
				if (tok.TryMatchOp(","))
					{
					anyCommas = true;
					if (!requireComma)
						arrayInfo.AddEntry(null);
					else
						requireComma = false;
					}
				else if (!requireComma)
					{
					ExprFrag value = ParseExpression(info, true, assignmentPrec);
					arrayInfo.AddEntry(value);
					requireComma = true;
					}
				else
					break;
			
			// If the list ends with a comma, then add one more null entry
			// to the end.
			if (anyCommas && !requireComma)
				arrayInfo.AddEntry(null);
			
			tok.MatchOp("]");
			return gen.ArrayLiteralExpr(startLoc, arrayInfo);
			}
		else if (tok.TryMatchID(out id))
			{
			SrcLoc idLoc = tok.Prev().loc;
			if (id == "eval")
				return gen.IdentifierExpr(idLoc, id, info, CloneStack(withs));
			else if (id == "arguments")
				return gen.ArgumentsExpr(idLoc, info, CloneStack(withs));
			else
				return gen.IdentifierExpr(idLoc, id, info, CloneStack(withs));
			
			}
		else if (tok.TryMatchNumLit(out d))
			return gen.NumLiteralExpr(tok.Prev().loc, d);
		else if (tok.TryMatchStringLit(out s))
			return gen.StringLiteralExpr(tok.Prev().loc, s);
		else
			{
			// One of the if clauses should fire; if not, the phase 1
			// parser would have reported an error.
			Trace.Assert(false);
			return null;
			}
		
		} // ParsePrimaryExpression
Пример #18
0
		} // 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
Пример #19
0
		} // ParsePrimaryExpression
	
	
	// Match an ArgumentList (if any) and the trailing ')'.  Return
	// an array of ExprFrag objects.
	private ArrayList MatchOptionalArgumentList(FunctionInfo info)
		{
		ArrayList argList = new ArrayList();
		
		if (!tok.PeekOp(")"))
			{
			do
				argList.Add(ParseExpression(info, true, assignmentPrec));
			while (tok.TryMatchOp(","));
			}
		
		tok.MatchOp(")");
		return argList;
		} // MatchOptionalArgumentList
Пример #20
0
		} // ArgumentsExpr
	
	
	// Return a FunctionExpr.
	public ExprFrag FunctionExpr(SrcLoc loc, FunctionInfo childInfo)
		{
		// HACK snewman 8/15/01: implement function expressions.
		throw new ParseError( "Function expressions not yet implemented",
							  loc );
		} // FunctionExpr
Пример #21
0
		} // Construct
	
	
	// Return an expression for the keyword "this".
	public ExprFrag ThisExpr(SrcLoc loc, FunctionInfo info)
		{
		if (info.isRoot)
			return new CSharpRHSExpr(loc, "globals");
		else
			return new CSharpRHSExpr(loc, "this_");
		
		} // ThisExpr
Пример #22
0
	// Construct a CSharpVariableRef for a reference at the given location,
	// to the given variable, in the given function, and in the given stack
	// of WithInfo objects.  function should be null for global variable
	// references.
	internal CSharpVariableRef( SrcLoc loc, string id, FunctionInfo function,
							    Stack enclosingWiths )
	  : base(loc)
		{
		this.id = id;
		this.function = function;
		this.enclosingWiths = enclosingWiths;
		} // CSharpVariableRef constructor
Пример #23
0
		} // IdentifierExpr
	
	
	// Return an expression to reference the identifier "arguments".
	// enclosingWiths should be a stack of WithInfo objects, giving
	// all with scopes in the current function that enclose the identifier
	// reference.
	public ExprFrag ArgumentsExpr( SrcLoc loc, FunctionInfo function,
								   Stack enclosingWiths )
		{
		// HACK snewman 8/20/01: implement this.  Support "with"
		// scopes... we may be able to just fall through into
		// IdentifierExpr.
		throw new ParseError( "\"arguments\" not yet implemented",
							  loc );
		} // ArgumentsExpr
Пример #24
0
		} // ParseVariableDeclaration
	
	
	// Parse an Expression, filling in info with any declarations.
	// 
	// If allowIN is false, then we don't look for "in" operators.  (This
	// implements the "NoIn" variant of the grammar, e.g. ExpressionNoIn
	// as opposed to Expression.)
	private void ParseExpression(FunctionInfo info, bool allowIN)
		{
		ParseExpression(info, allowIN, 99);
		} // ParseExpression
Пример #25
0
	internal CSharpGenFuncInfo(FunctionInfo func) { this.func = func; }
Пример #26
0
		} // ParseStatement
	
	
	// Parse a VariableDeclaration.  See ParseExpression for an explanation
	// of allowIN.  We set varName to the name of the declared variable.
	private StmtFrag ParseVariableDeclaration( FunctionInfo info, bool allowIN,
											   out string varName,
											   out SrcLoc varLoc )
		{
		varName = tok.MatchID();
		varLoc = tok.Prev().loc;
		if (tok.TryMatchOp("="))
			{
			SrcLoc opLoc = tok.Prev().loc;
			ExprFrag lhs = gen.IdentifierExpr( varLoc, varName, info,
											   CloneStack(withs) );
			ExprFrag rhs = ParseExpression(info, allowIN, assignmentPrec);
			ExprFrag assignment = gen.BinaryExpr(opLoc, "=", lhs, rhs);
			return gen.ExpressionStmt(assignment);
			}
		else
			return gen.NewStmtFrag(tok.Prev().loc);
		
		} // ParseVariableDeclaration
Пример #27
0
	// Construct a CSharpGenerator.  Parameters:
	// 
	// 	rootInfo				Info object for the program's root function.
	//	pp						Object where we write the generated program.
	//	progClassName			C# class name to use for the generated program.
	//  forEvalCode				True if the code being compiled came from a
	//							call to eval().
	public CSharpGenerator( FunctionInfo rootInfo, PrettyPrinter pp,
							String progClassName, bool forEvalCode )
		{
		this.rootInfo      = rootInfo;
		this.pp            = pp;
		this.progClassName = progClassName;
		this.forEvalCode   = forEvalCode;
		} // CSharpGenerator constructor
Пример #28
0
		} // ParseVariableDeclaration
	
	
	// Parse an Expression.
	// 
	// If allowIN is false, then we don't look for "in" operators.  (This
	// implements the "NoIn" variant of the grammar, e.g. ExpressionNoIn
	// as opposed to Expression.)
	private ExprFrag ParseExpression(FunctionInfo info, bool allowIN)
		{
		return ParseExpression(info, allowIN, 99);
		} // ParseExpression
Пример #29
0
		} // EmitMainFunction
	
	
	// Generate code for the given function (other than the main function),
	// given the function's FunctionInfo object and its body.
	public void EmitFunction(FunctionInfo info, StmtFrag body)
		{
		// HACK snewman 8/15/01: review the way locals are handled here, to
		// make sure we're declaring them in precise accordance with the spec.
		
		// HACK snewman 8/15/01: add support for nested functions
		if (info.firstChild != null)
			throw new ParseError( "EmitFunction: nested functions not yet implemented",
								  body.loc );
		
		string functionLabel, functionName;
		if (info.nameInParent == null)
			{
			functionLabel = "Anonymous function";
			functionName = "anon_";
			}
		else
			{
			functionLabel = "Function \"" + info.nameInParent + "\"";
			functionName = info.nameInParent + "_";
			}
		
		functionName = MakeUniqueMethodName(functionName);
		
		pp.Line();
		pp.Line("// {0}", functionLabel);
		
		pp.Line("public static object {0}(object this_, params object[] args)", functionName);
		pp.Indent();
		pp.Line("{");
		
		pp.Text("JActivationObject activation = new JActivationObject(args");
		foreach (string paramName in info.paramNames)
			pp.Text(", \"{0}\"", paramName);
		pp.EndLine(");");
		
		foreach (string varName in info.locals)
			pp.Line("activation.Put(\"{0}\", JUndefinedObject.instance);", varName);
		
		EmitStatements(body);
		
		pp.Line("return JUndefinedObject.instance;");
		
		pp.Line("{0} // {1}", "}", functionName);
		pp.Outdent();
		} // EmitFunction
Пример #30
0
		} // ParseExpression
	
	
	// Parse an Expression.
	// 
	// If allowIN is false, then we don't look for "in" operators.  (This
	// implements the "NoIn" variant of the grammar, e.g. ExpressionNoIn
	// as opposed to Expression.)
	// 
	// This method can also be used to parse "smaller" nonterminals such
	// as AssignmentExpression, ConditionalExpression, and so on down to
	// MultiplicativeExpression.  This is controlled by the maxPrecedence
	// parameter: we ignore any operators with a looser (numerically
	// greater) precedence than maxPrecedence.
	private ExprFrag ParseExpression( FunctionInfo info, bool allowIN,
								      int maxPrecedence )
		{
		// Note that we use a simpler grammar than ECMAScript, because
		// we don't need to catch assignment to non-lvalue in the parser
		// (it will have been caught in phase 1).
		
		// Parse any prefix operators.
		Stack stackedOps = new Stack();
		Stack stackedOpsLocs = new Stack();
		OperatorInfo matchedOp;
		while (TryMatchOperator(true, -1, out matchedOp, true))
			{
			stackedOps.Push(matchedOp);
			stackedOpsLocs.Push(tok.Prev().loc);
			}
		
		ExprFrag expr = ParseLeftHandSideExpression(info, true);
		
		if (stackedOps.Count > 0)
			{
			while (TryMatchOperator(allowIN, unarySuffixPrec, out matchedOp, true))
				{
				Trace.Assert(matchedOp.opType == OperatorInfo.Types.unarySuffix);
				expr = gen.UnaryExpr( tok.Prev().loc, matchedOp.text,
									  matchedOp.opType == OperatorInfo.Types.unarySuffix,
									  expr );
				}
			
			while (stackedOps.Count > 0)
				{
				OperatorInfo curOp = (OperatorInfo)stackedOps.Pop();
				expr = gen.UnaryExpr( (SrcLoc)stackedOpsLocs.Pop(),
									  curOp.text,
									  curOp.opType == OperatorInfo.Types.unarySuffix,
									  expr );
				}
			
			} // if (stackedOps.Count > 0)
		
		while (TryMatchOperator(allowIN, maxPrecedence, out matchedOp, true))
			{
			SrcLoc opLoc = tok.Prev().loc;
			if (matchedOp.text == "?")
				{
				ExprFrag p1 = ParseExpression(info, allowIN, assignmentPrec);
				tok.MatchOp(":");
				ExprFrag p2 = ParseExpression(info, allowIN, assignmentPrec);
				expr = gen.ConditionalExpr(opLoc, expr, p1, p2);
				}
			else if (matchedOp.opType == OperatorInfo.Types.assignment)
				expr = gen.BinaryExpr( opLoc, matchedOp.text, expr,
									   ParseExpression(info, allowIN, matchedOp.precedence) );
			else if (matchedOp.opType == OperatorInfo.Types.binary)
				expr = gen.BinaryExpr( opLoc, matchedOp.text, expr,
									   ParseExpression(info, allowIN, matchedOp.precedence-1) );
			else
				{
				Trace.Assert(matchedOp.opType == OperatorInfo.Types.unarySuffix);
				expr = gen.UnaryExpr( opLoc, matchedOp.text,
									  matchedOp.opType == OperatorInfo.Types.unarySuffix,
									  expr );
				}
			
			}
		
		return expr;
		} // ParseExpression