} // ReadNextToken // Parse an identifier beginning at the current stream location. private Token ParseIdentifier(SrcLoc loc) { // Get a buffer from which we can parse the identifier. char[] charBuf; int startPos; int bufLen = buffer.GetBuffer(maxTokenLen, out charBuf, out startPos); if (bufLen > maxTokenLen) { bufLen = maxTokenLen; } // Find the last character in the identifier. We begin // at 1 because we know (from matcher.Match returning // TokDispatch.ident) that the identifier is at least // one character long. int tokenLen = 1; while (tokenLen < bufLen && CharUtils.IsIdentifierChar(charBuf[startPos + tokenLen])) { tokenLen++; } Identifier token = new Identifier(); token.rawText = buffer.ConsumeString(tokenLen); loc.len = tokenLen; token.loc = loc; return(token); } // ParseIdentifier
} // 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
} // ParseStringLiteral // Advance the stream past a comment beginning at the current stream // location. private void SkipComment(SrcLoc loc) { // HACK SN 7/13/01: rewrite this to support comments longer // than maxTokenLen. // Get a buffer from which we can parse the comment. char[] charBuf; int startPos; int bufLen = buffer.GetBuffer(maxTokenLen, out charBuf, out startPos); int tokenLen = 2; if (charBuf[startPos + 1] == '/') { // C++ style comment; search for end of line while (tokenLen < bufLen && !CharUtils.IsEOLChar(charBuf[startPos + tokenLen])) { tokenLen++; } } else { // C style comment; search for "*/" // NOTE: we might extend this to warn for nested comments. while (tokenLen < bufLen - 1 && (charBuf[startPos + tokenLen] != '*' || charBuf[startPos + tokenLen + 1] != '/')) { tokenLen++; } if (tokenLen >= bufLen - 1) { loc.len = tokenLen; throw new ParseError("unterminated /* comment", loc); } // Include the trailing "*/" in tokenLen. tokenLen += 2; } buffer.Skip(tokenLen); } // SkipComment
} // 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
} // BoolLiteralExpr // Return an expression for the given numeric literal. public ExprFrag NumLiteralExpr(SrcLoc loc, double d) { return new CSharpRHSExpr(loc, System.Convert.ToString(d)); } // NumLiteralExpr
} // ParseNumber // Parse a string literal or regexp expression beginning at the current // stream location. private Token ParseStringLiteral(SrcLoc loc) { // HACK SN 7/14/01: rewrite this to support literals longer // than maxTokenLen. // HACK SN 7/14/01: parse regexps as well as single- or double-quoted strings // Get a buffer from which we can parse the string. char[] charBuf; int startPos; int bufLen = buffer.GetBuffer(maxTokenLen, out charBuf, out startPos); Trace.Assert(bufLen > 1); // Scan to find the end of the string. char quoteChar = charBuf[startPos]; int tokenLen = 1; StringBuilder parsedValueBuilder = new StringBuilder(); while (tokenLen < bufLen) { char curChar = charBuf[startPos + tokenLen]; if (curChar == quoteChar) { break; } else if (curChar == '\\') { // HACK SN 7/14/01: extend this to parse all ECMAScript backslash // sequences. if (tokenLen + 1 >= bufLen) { throw new ParseError("unterminated string literal or regexp", loc); } curChar = charBuf[startPos + tokenLen + 1]; switch (curChar) { case 'b': curChar = '\b'; break; case 'f': curChar = '\f'; break; case 'n': curChar = '\n'; break; case 'r': curChar = '\r'; break; case 't': curChar = '\t'; break; case 'v': curChar = '\v'; break; } parsedValueBuilder.Append(curChar); tokenLen += 2; } else { parsedValueBuilder.Append(curChar); tokenLen++; } } // while (tokenLen < bufLen) if (tokenLen >= bufLen) { throw new ParseError("unterminated string literal or regexp", loc); } loc.len = tokenLen + 1; StringLit litToken = new StringLit(); litToken.rawText = buffer.ConsumeString(tokenLen + 1); litToken.loc = loc; litToken.parsedText = parsedValueBuilder.ToString(); switch (quoteChar) { case '\'': litToken.quoteType = StringLit.QuoteType.singleQ; break; case '"': litToken.quoteType = StringLit.QuoteType.doubleQ; break; case '/': litToken.quoteType = StringLit.QuoteType.regexp; break; default: Trace.Assert(false); break; } return(litToken); } // ParseStringLiteral
} // ParseIdentifier // Parse a numeric literal beginning at the current stream location. private Token ParseNumber(SrcLoc loc) { // Get a buffer from which we can parse the number. char[] charBuf; int startPos; int bufLen = buffer.GetBuffer(maxTokenLen, out charBuf, out startPos); if (bufLen > maxTokenLen) { bufLen = maxTokenLen; } // Find the end of the number. We match for the following // components: // // integer part (1 or more digits) // optional fractional part ('.' plus one or more digits) // optional exponent ('E' or 'e', optional '+' or '-', and 1-3 digits) // // HACK SN 7/14/01: for now, we aren't enforcing that the fractional // part must have at least one digit, or that the exponent must have // at least 1 and no more than 3 digits. Review the ECMAScript spec for // the correct rules. Also, should we allow numbers that begin with a '.' // (no integer part)? int tokenLen = 0; while (tokenLen < bufLen && CharUtils.IsDigitChar(charBuf[startPos + tokenLen])) { tokenLen++; } if (tokenLen < bufLen && charBuf[startPos + tokenLen] == '.') { tokenLen++; while (tokenLen < bufLen && CharUtils.IsDigitChar(charBuf[startPos + tokenLen])) { tokenLen++; } } if (tokenLen < bufLen && (charBuf[startPos + tokenLen] == 'E' || charBuf[startPos + tokenLen] == 'e')) { tokenLen++; if (tokenLen < bufLen && (charBuf[startPos + tokenLen] == '+' || charBuf[startPos + tokenLen] == '-')) { tokenLen++; } while (tokenLen < bufLen && CharUtils.IsDigitChar(charBuf[startPos + tokenLen])) { tokenLen++; } } NumLit token = new NumLit(); token.rawText = buffer.ConsumeString(tokenLen); loc.len = tokenLen; token.loc = loc; try { token.value = Double.Parse(token.rawText); } catch (FormatException e) { throw new ParseError("FormatException parsing numeric literal \"" + token.rawText + "\": " + e.ToString(), loc); } catch (OverflowException e) { throw new ParseError("OverflowException parsing numeric literal \"" + token.rawText + "\": " + e.ToString(), loc); } return(token); } // ParseNumber
} // NewLabeledStmtInfo // Return a new WithInfo object. public WithInfo NewWithInfo(CGFuncInfo cgFuncInfo, SrcLoc loc) { return new CSharpWithInfo((CSharpGenFuncInfo)cgFuncInfo, loc); } // NewWithInfo
} // NewStmtFrag // Return a new LoopInfo object for an iteratiion statement with the // given label set. The labels parameter can be null if there were no // labels. public LoopInfo NewLoopInfo( CGFuncInfo cgFuncInfo, SrcLoc loc, StringCollection labels ) { return new CSharpLoopInfo( (CSharpGenFuncInfo)cgFuncInfo, loc, labels, true, false ); } // NewLoopInfo
internal CSharpRHSExpr(SrcLoc loc, string code) : base(loc) { code_ = code; } // CSharpRHSExpr constructor
internal CSharpWithInfo(CSharpGenFuncInfo cgInfo, SrcLoc loc) { this.loc = loc; this.index = cgInfo.withCount++; } // CSharpWithInfo constructor
} // NullExpr // Return a BooleanLiteral expression. public ExprFrag BoolLiteralExpr(SrcLoc loc, bool b) { return new CSharpRHSExpr(loc, (b) ? "true" : "false"); } // BoolLiteralExpr
} // ParseStringLiteral // Advance the stream past a comment beginning at the current stream // location. private void SkipComment(SrcLoc loc) { // HACK SN 7/13/01: rewrite this to support comments longer // than maxTokenLen. // Get a buffer from which we can parse the comment. char[] charBuf; int startPos; int bufLen = buffer.GetBuffer( maxTokenLen, out charBuf, out startPos ); int tokenLen = 2; if (charBuf[startPos+1] == '/') { // C++ style comment; search for end of line while ( tokenLen < bufLen && !CharUtils.IsEOLChar(charBuf[startPos+tokenLen]) ) tokenLen++; } else { // C style comment; search for "*/" // NOTE: we might extend this to warn for nested comments. while ( tokenLen < bufLen-1 && ( charBuf[startPos+tokenLen ] != '*' || charBuf[startPos+tokenLen+1] != '/' ) ) tokenLen++; if (tokenLen >= bufLen-1) { loc.len = tokenLen; throw new ParseError("unterminated /* comment", loc); } // Include the trailing "*/" in tokenLen. tokenLen += 2; } buffer.Skip(tokenLen); } // SkipComment
} // ThisExpr // Return an expression for the keyword "null". public ExprFrag NullExpr(SrcLoc loc) { return new CSharpRHSExpr(loc, "null"); } // NullExpr
} // 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
} // Call // Return an expression for a constructor call (a "new" expression). // args is an array of ExprFrags, or null if no parameter list was // provided. public ExprFrag Construct(SrcLoc loc, ExprFrag functionExpr, ArrayList args) { String code = ((CSharpExprFrag)functionExpr).GenerateCall(args, true); return new CSharpRHSExpr(loc, code); } // Construct
} // 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
} // 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
} // ReadNextToken // Parse an identifier beginning at the current stream location. private Token ParseIdentifier(SrcLoc loc) { // Get a buffer from which we can parse the identifier. char[] charBuf; int startPos; int bufLen = buffer.GetBuffer( maxTokenLen, out charBuf, out startPos ); if (bufLen > maxTokenLen) bufLen = maxTokenLen; // Find the last character in the identifier. We begin // at 1 because we know (from matcher.Match returning // TokDispatch.ident) that the identifier is at least // one character long. int tokenLen = 1; while ( tokenLen < bufLen && CharUtils.IsIdentifierChar(charBuf[startPos+tokenLen]) ) tokenLen++; Identifier token = new Identifier(); token.rawText = buffer.ConsumeString(tokenLen); loc.len = tokenLen; token.loc = loc; return token; } // ParseIdentifier
} // NumLiteralExpr // Return a StringLiteral expression. public ExprFrag StringLiteralExpr(SrcLoc loc, string s) { StringBuilder escapedBuilder = new StringBuilder(); escapedBuilder.Append("@\""); foreach (char c in s) if (c == '"') escapedBuilder.Append("\"\""); else escapedBuilder.Append(c); escapedBuilder.Append("\""); return new CSharpRHSExpr(loc, escapedBuilder.ToString()); } // StringLiteralExpr
internal CSharpLoopInfo( CSharpGenFuncInfo cgInfo, SrcLoc loc, StringCollection labels, bool isLoop, bool isSwitch ) { this.loc = loc; this.labels = labels; this.isLoop = isLoop; this.isSwitch = isSwitch; this.index = cgInfo.loopCount++; } // CSharpLoopInfo constructor
} // 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
public void AddProp(SrcLoc loc, string id, ExprFrag value) { Entry newEntry = new Entry(); newEntry.loc = loc; newEntry.id = id; newEntry.value = value; entries.Add(newEntry); }
} // 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
} // EmitStatements // Return a new, empty StmtFrag object. public StmtFrag NewStmtFrag(SrcLoc loc) { return new CSharpStmtFrag(loc); } // NewStmtFrag
} // 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
} // NewLoopInfo // Return a new LoopInfo object for a labeled non-iteration statement // with the given label set. isSwitch should be true if the statement // was a switch statement; in this case, if the statement had no labels, // the labels parameter can be null. public LoopInfo NewLabeledStmtInfo( CGFuncInfo cgFuncInfo, SrcLoc loc, StringCollection labels, bool isSwitch ) { Trace.Assert(labels != null || isSwitch); return new CSharpLoopInfo( (CSharpGenFuncInfo)cgFuncInfo, loc, labels, false, isSwitch ); } // NewLabeledStmtInfo
} // FunctionExpr // Return an ObjectLiteral expression. public ExprFrag ObjectLiteralExpr(SrcLoc loc, ObjectLiteralInfo litInfo) { StringBuilder builder = new StringBuilder(); builder.Append("Support.LiteralObject("); CSharpObjectLiteral csInfo = (CSharpObjectLiteral)litInfo; bool first = true; foreach (CSharpObjectLiteral.Entry entry in csInfo.entries) { if (first) first = false; else builder.Append(", "); builder.Append("\""); builder.Append(entry.id); builder.Append("\", "); builder.Append(((CSharpExprFrag)entry.value).GenerateRHS()); } builder.Append(")"); return new CSharpRHSExpr(loc, builder.ToString()); } // ObjectLiteralExpr
} // ExpressionStmt // Return an if/then or if/then/else statement. If there was no else // clause, elseClause will be null. public StmtFrag IfThenElse( SrcLoc loc, ExprFrag condition, StmtFrag ifClause, StmtFrag elseClause ) { CSharpStmtFrag frag = new CSharpStmtFrag(loc); CSharpExprFrag csCondition = (CSharpExprFrag)condition; frag.Append("if (Support.BoolTest(" + csCondition.GenerateRHS() + "))"); frag.AppendIndentedBody(ifClause); if (elseClause != null) { frag.Append("else"); frag.AppendIndentedBody(elseClause); } return frag; } // IfThenElse
} // ObjectLiteralExpr // Return an ArrayLiteral expression. public ExprFrag ArrayLiteralExpr(SrcLoc loc, ArrayLiteralInfo arrayInfo) { // HACK snewman 8/28/01: properly implement missing elements in // the original array literal (commas with no values in between // them). Properly implement the array "length" property. StringBuilder builder = new StringBuilder(); builder.Append("Support.LiteralArray("); CSharpArrayLiteral csInfo = (CSharpArrayLiteral)arrayInfo; bool first = true; foreach (CSharpExprFrag entry in csInfo.entries) { if (first) first = false; else builder.Append(", "); builder.Append(entry.GenerateRHS()); } builder.Append(")"); return new CSharpRHSExpr(loc, builder.ToString()); } // ArrayLiteralInfo
public ParseError(string message, SrcLoc loc) : base(message) { this.loc = loc; }
internal CSharpArrayRef(SrcLoc loc, string arrayCode, string indexCode) : base(loc) { this.arrayCode = arrayCode; this.indexCode = indexCode; } // CSharpArrayRef constructor
internal CSharpFieldRef(SrcLoc loc, string objectCode, string id) : base(loc) { this.objectCode = objectCode; this.id = id; } // CSharpFieldRef constructor
// 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
} // ParseNumber // Parse a string literal or regexp expression beginning at the current // stream location. private Token ParseStringLiteral(SrcLoc loc) { // HACK SN 7/14/01: rewrite this to support literals longer // than maxTokenLen. // HACK SN 7/14/01: parse regexps as well as single- or double-quoted strings // Get a buffer from which we can parse the string. char[] charBuf; int startPos; int bufLen = buffer.GetBuffer(maxTokenLen, out charBuf, out startPos); Trace.Assert(bufLen > 1); // Scan to find the end of the string. char quoteChar = charBuf[startPos]; int tokenLen = 1; StringBuilder parsedValueBuilder = new StringBuilder(); while (tokenLen < bufLen) { char curChar = charBuf[startPos+tokenLen]; if (curChar == quoteChar) break; else if (curChar == '\\') { // HACK SN 7/14/01: extend this to parse all ECMAScript backslash // sequences. if (tokenLen+1 >= bufLen) throw new ParseError("unterminated string literal or regexp", loc); curChar = charBuf[startPos+tokenLen+1]; switch (curChar) { case 'b': curChar = '\b'; break; case 'f': curChar = '\f'; break; case 'n': curChar = '\n'; break; case 'r': curChar = '\r'; break; case 't': curChar = '\t'; break; case 'v': curChar = '\v'; break; } parsedValueBuilder.Append(curChar); tokenLen += 2; } else { parsedValueBuilder.Append(curChar); tokenLen++; } } // while (tokenLen < bufLen) if (tokenLen >= bufLen) throw new ParseError("unterminated string literal or regexp", loc); loc.len = tokenLen + 1; StringLit litToken = new StringLit(); litToken.rawText = buffer.ConsumeString(tokenLen+1); litToken.loc = loc; litToken.parsedText = parsedValueBuilder.ToString(); switch (quoteChar) { case '\'': litToken.quoteType = StringLit.QuoteType.singleQ; break; case '"': litToken.quoteType = StringLit.QuoteType.doubleQ; break; case '/': litToken.quoteType = StringLit.QuoteType.regexp; break; default: Trace.Assert(false); break; } return litToken; } // ParseStringLiteral
internal CSharpExprFrag(SrcLoc loc) { loc_ = loc; } // CSharpExprFrag constructor
internal CSharpStmtFrag(SrcLoc loc) { loc_ = loc; code_ = null; last_ = null; used_ = false; } // CSharpStmtFrag constructor
} // ParseIdentifier // Parse a numeric literal beginning at the current stream location. private Token ParseNumber(SrcLoc loc) { // Get a buffer from which we can parse the number. char[] charBuf; int startPos; int bufLen = buffer.GetBuffer( maxTokenLen, out charBuf, out startPos ); if (bufLen > maxTokenLen) bufLen = maxTokenLen; // Find the end of the number. We match for the following // components: // // integer part (1 or more digits) // optional fractional part ('.' plus one or more digits) // optional exponent ('E' or 'e', optional '+' or '-', and 1-3 digits) // // HACK SN 7/14/01: for now, we aren't enforcing that the fractional // part must have at least one digit, or that the exponent must have // at least 1 and no more than 3 digits. Review the ECMAScript spec for // the correct rules. Also, should we allow numbers that begin with a '.' // (no integer part)? int tokenLen = 0; while ( tokenLen < bufLen && CharUtils.IsDigitChar(charBuf[startPos+tokenLen]) ) tokenLen++; if (tokenLen < bufLen && charBuf[startPos+tokenLen] == '.') { tokenLen++; while ( tokenLen < bufLen && CharUtils.IsDigitChar(charBuf[startPos+tokenLen]) ) tokenLen++; } if ( tokenLen < bufLen && ( charBuf[startPos+tokenLen] == 'E' || charBuf[startPos+tokenLen] == 'e' ) ) { tokenLen++; if ( tokenLen < bufLen && ( charBuf[startPos+tokenLen] == '+' || charBuf[startPos+tokenLen] == '-' ) ) tokenLen++; while ( tokenLen < bufLen && CharUtils.IsDigitChar(charBuf[startPos+tokenLen]) ) tokenLen++; } NumLit token = new NumLit(); token.rawText = buffer.ConsumeString(tokenLen); loc.len = tokenLen; token.loc = loc; try { token.value = Double.Parse(token.rawText); } catch (FormatException e) { throw new ParseError( "FormatException parsing numeric literal \"" + token.rawText + "\": " + e.ToString(), loc ); } catch (OverflowException e) { throw new ParseError( "OverflowException parsing numeric literal \"" + token.rawText + "\": " + e.ToString(), loc ); } return token; } // ParseNumber
} // 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