// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using Antlr.Runtime; using Antlr.Runtime.Tree; namespace Xebic.Parsers.ES3 { using IToken = Antlr.Runtime.IToken; /// /// This partial class is complementary to the parser generated with ANTLR from the JavaScript.g grammar. /// It implements the actions used in the parser. /// public partial class ES3Parser { /// /// Is a RuleReturnScope node candidate for the left-hand-side of an assignment expression? /// /// The RuleReturnScope node /// The cached result of a former call to this method /// True if so, false otherwise public bool IsLeftHandSideAssign(IAstRuleReturnScope lhs, ref bool? cached) { if (cached.HasValue) { return cached.Value; } bool result; if (IsLeftHandSideExpression(lhs)) { switch (input.LA(1)) { case ASSIGN: case MULASS: case DIVASS: case MODASS: case ADDASS: case SUBASS: case SHLASS: case SHRASS: case SHUASS: case ANDASS: case XORASS: case ORASS: result = true; break; default: result = false; break; } } else { result = false; } cached = result; return result; } /// /// Is a RuleReturnScope node candidate a left-hand-side expression? /// /// The RuleReturnScope node /// True if so, false otherwise private bool IsLeftHandSideExpression(IAstRuleReturnScope lhs) { if (lhs.Tree == null) // e.g. during backtracking { return true; } else { switch (((ITree)lhs.Tree).Type) { // primaryExpression case THIS: case Identifier: case NULL: case TRUE: case FALSE: case DecimalLiteral: case OctalIntegerLiteral: case HexIntegerLiteral: case StringLiteral: case RegularExpressionLiteral: case ARRAY: case OBJECT: case PAREXPR: // functionExpression case FUNCTION: // newExpression case NEW: // leftHandSideExpression case CALL: case BYFIELD: case BYINDEX: return true; default: return false; } } } /// /// Is a RuleReturnScope node candidate for the left-hand-side of an in expression? /// /// The RuleReturnScope node /// The cached result of a former call to this method /// True if so, false otherwise public bool IsLeftHandSideIn(IAstRuleReturnScope lhs, ref bool? cached) { if (cached.HasValue) { return cached.Value; } bool result = IsLeftHandSideExpression(lhs) && (input.LA(1) == IN); cached = result; return result; } /// /// This method handles promotion of an EOL token to on channel in situations where the ECMA 3 specification /// states there should be a semicolon inserted because of an EOL between the current (offending) token /// and the previous token. /// So an semicolon is not actually inserted but the EOL present is switched from off to on channel. In this /// way that EOL gets the notion of an "virtual" semicolon. /// As a side effect a given rule's return scope starting point is set to the found EOL and the input stream is repositioned on it. /// A multi line comment with an EOL is also promoted. /// /// The invoking rule's return scope public void PromoteEOL(ParserRuleReturnScope rule) { // Get current token and its type (the possibly offending token). IToken lt = input.LT(1); int la = lt.Type; // We only need to promote an EOL when the current token is offending (not a SEMIC, EOF, RBRACE or EOL). // Promoting an EOL means switching it from off channel to on channel. if (!(la == SEMIC || la == EOF || la == RBRACE || la == EOL)) { // Start on the possition before the current token and scan backwards off channel tokens until the previous on channel token. for (int ix = lt.TokenIndex - 1; ix > 0; ix--) { lt = input.Get(ix); if (lt.Channel == DefaultTokenChannel) { // On channel token found: stop scanning. break; } else if (lt.Type == EOL || (lt.Type == MultiLineComment && Regex.IsMatch(lt.Text, "/.*\r\n|\r|\n"))) { // We found our EOL: promote it to on channel, position the input on it and reset the rule start. lt.Channel = DefaultTokenChannel; input.Seek(lt.TokenIndex); if (rule != null) { rule.Start = lt; } break; } } } } } }