예제 #1
0
        /// <summary>
        /// FactorTail := Number | '(' Expr ')' | Function
        /// </summary>
        void ParseFactorTail(TokenQueue tokens)
        {
            Token current = tokens.PeekToken();

            if (current.TokenType == TokenType.OpenParenthesis)
            {
                current = tokens.NextToken();
                ParseExpressionR(tokens);

                // Skip the closing bracket
                if (tokens.PeekToken().TokenType != TokenType.CloseParenthesis)
                {
                    throw new ParserExceptionWithPosistion(string.Format("Expected close bracket at {0}.", current.Position), current.Position);
                }
                tokens.NextToken();
            }
            else if (current.TokenType == TokenType.Text && IsRegisteredFunction(current.Value))
            {
                ParseFunction(tokens);
            }
            else if (current.TokenType == TokenType.Numeric)
            {
                ParseNumber(tokens);
            }
            else
            {
                throw new ParserExceptionWithPosistion(string.Format("Unrecognised factor at {0}.", current.Position), current.Position);
            }
        }
예제 #2
0
        private void ByAttribute()
        {
            TokenQueue cq  = new TokenQueue(tq.ChompBalanced('[', ']'));         // content queue
            string     key = cq.ConsumeToAny("=", "!=", "^=", "$=", "*=", "~="); // eq, not, start, end, contain, match, (no val)

            if (key.Length == 0)
            {
                throw Failure.EmptyString("key");
            }

            cq.ConsumeWhitespace();

            if (cq.IsEmpty)
            {
                if (key.StartsWith("^", StringComparison.Ordinal))
                {
                    evals.Add(new Evaluator.AttributeStarting(key.Substring(1)));
                }
                else
                {
                    evals.Add(new Evaluator.Attribute(key));
                }
            }
            else
            {
                if (cq.MatchChomp("="))
                {
                    evals.Add(new Evaluator.AttributeWithValue(key, cq.Remainder()));
                }

                else if (cq.MatchChomp("!="))
                {
                    evals.Add(new Evaluator.AttributeWithValueNot(key, cq.Remainder()));
                }

                else if (cq.MatchChomp("^="))
                {
                    evals.Add(new Evaluator.AttributeWithValueStarting(key, cq.Remainder()));
                }

                else if (cq.MatchChomp("$="))
                {
                    evals.Add(new Evaluator.AttributeWithValueEnding(key, cq.Remainder()));
                }

                else if (cq.MatchChomp("*="))
                {
                    evals.Add(new Evaluator.AttributeWithValueContaining(key, cq.Remainder()));
                }

                else if (cq.MatchChomp("~="))
                {
                    evals.Add(new Evaluator.AttributeWithValueMatching(key, new Regex(cq.Remainder())));
                }
                else
                {
                    throw DomFailure.CannotParseAttributeQuery(query, cq.Remainder());
                }
            }
        }
예제 #3
0
        /// <summary>
        /// TermTail := nil | '*' Factor | '/' Factor
        /// </summary>
        void ParseTermTail(TokenQueue tokens)
        {
            Token current = tokens.PeekToken();

            if (current.TokenType == TokenType.Divide)
            {
                current = tokens.NextToken();

                ParseFactor(tokens);

                // Append operators postfix
                EmitBinaryOperator("/", current.Position);

                ParseTermTail(tokens);
            }
            else if (current.TokenType == TokenType.Multiply)
            {
                current = tokens.NextToken();

                ParseFactor(tokens);

                // Append operators postfix
                EmitBinaryOperator("*", current.Position);

                ParseTermTail(tokens);
            }
            else
            {
                // nil - but this is ok
            }
        }
예제 #4
0
    public override MatchResult?MatchStep(MatchStack stack, MatchFrame frame, TokenQueue q)
    {
        int idx   = (int)q.Take().Type;
        var match = idx >= 0 && idx < _bitmap.Length && _bitmap[idx];

        return(match ? MatchResult.Matched : MatchResult.NoMatch);
    }
예제 #5
0
        public override ExcutableCommand Create(TokenQueue seq, Token first, CompilerApplication context)
        {
            List <ExcutableCommand> result = context.context.Results;
            int i;

            for (i = result.Count - 1; i >= 0; i--)
            {
                if (result[i].keyword.Type == TokenType.MACRO_COMMAND)
                {
                    break;
                }
            }
            ExcutableCommand[] param = new ExcutableCommand[result.Count - i - 1];
            for (int j = param.Length - 1, k = result.Count - 1; j >= 0; j--, k--)
            {
                param[j] = result[k];
                result.RemoveAt(k);
            }

            MacroCommand macro = (MacroCommand)result[i];

            macro.content = param;
            result.RemoveAt(i);
            macro.CompileMacro();
            return(null);
        }
예제 #6
0
        /// <summary>
        /// ExprTail := nil | '+' Term ExprTail | '-' Term ExprTail
        /// </summary>
        void ParseExprTail(TokenQueue tokens)
        {
            Token current = tokens.PeekToken();

            if (current.TokenType == TokenType.Plus)
            {
                current = tokens.NextToken();

                ParseTerm(tokens);

                // Append operators postfix
                EmitBinaryOperator("+", current.Position);

                ParseExprTail(tokens);
            }
            else if (current.TokenType == TokenType.Minus)
            {
                current = tokens.NextToken();

                ParseTerm(tokens);

                // Append operators postfix
                EmitBinaryOperator("-", current.Position);

                ParseExprTail(tokens);
            }
            else
            {
                // nil - but this is ok.
            }
        }
예제 #7
0
        /// Function := Name '(' ArgList ')'
        void ParseFunction(TokenQueue tokens)
        {
            var funcStartPosition       = tokens.PeekToken().Position;
            RegisteredFunction function = ParseFunctionName(tokens);
            Token current = tokens.PeekToken();

            if (current.TokenType != TokenType.OpenParenthesis)
            {
                throw new ParserExceptionWithPosistion(string.Format("Expected open bracket at {0}.", current.Position), current.Position);
            }
            tokens.NextToken();
            int args = 0;

            ParseArgList(tokens, ref args);
            current = tokens.PeekToken();
            if (args != function.ArgCount)
            {
                throw new ParserExceptionWithPosistion(string.Format("Invalid number of function parameters in function {0}.  Expected {1} at {2}.", function.Name, function.ArgCount, current.Position), current.Position);
            }
            if (current.TokenType != TokenType.CloseParenthesis)
            {
                throw new ParserExceptionWithPosistion(string.Format("Expected close bracket at {0}.", current.Position), current.Position);
            }

            // Append function names after all their arguments.
            EmitFunction(function, funcStartPosition);

            tokens.NextToken();
        }
        public void addFirst()
        {
            TokenQueue tq = new TokenQueue("One Two");

            tq.ConsumeWord();
            tq.AddFirst("Three");
            Assert.AreEqual("Three Two", tq.Remainder());
        }
예제 #9
0
 /// <summary>
 /// Parse the supplied expression.
 /// If the expression is not valid, then a ParserException will be thrown.
 /// Finally we test to see that all tokens have been parsed.
 /// If not, this is likely to be an error in the expression, for example something like
 /// 4535+54345+5345345POWER(2, 3)
 /// </summary>
 public void ParseExpression(TokenQueue tokens)
 {
     ParseExpressionR(tokens);
     if (tokens.PeekToken().TokenType != TokenType.EOF)
     {
         throw new ParserException(string.Format("Tokens remain after parsing: {0}.", tokens.ToString()));
     }
     return;
 }
        public void chompBalancedMatchesAsMuchAsPossible()
        {
            TokenQueue tq = new TokenQueue("unbalanced(something(or another");

            tq.ConsumeTo("(");
            string match = tq.ChompBalanced('(', ')');

            Assert.AreEqual("something(or another", match);
        }
        public override ExcutableCommand Create(TokenQueue seq, Token first, CompilerApplication context)
        {
            context.SetLabel(first.Text, first);
            LableCommand c = new LableCommand {
                keyword = first
            };

            return(c);
        }
예제 #12
0
    private Ast.Stmt ParseContinueStmt(TokenQueue q)
    {
        var stmt = new Ast.ContinueStmt {
            SourceToken = q.SourceToken
        };

        q.Take("continue");
        ConsumeSemicolon(q);
        return(stmt);
    }
예제 #13
0
    private Ast.Stmt ParseBreakStmt(TokenQueue q)
    {
        var stmt = new Ast.BreakStmt {
            SourceToken = q.SourceToken
        };

        q.Take("break");
        ConsumeSemicolon(q);
        return(stmt);
    }
예제 #14
0
 private void ParseAssignmentStmtCore(TokenQueue q, Ast.AssignmentStmt stmt)
 {
     stmt.VariableName = ParseVariableName(q);
     if (q.Peek() == "=")
     {
         q.Take();
         stmt.InitialValue = ParseExpr(q);
     }
     ConsumeSemicolon(q);
 }
예제 #15
0
        /// ArgList :=nil  |  NonEmptyArgList
        void ParseArgList(TokenQueue tokens, ref int argc)
        {
            Token current = tokens.PeekToken();

            // If it is a close parenthesis then its the end of the arglist.
            if (current.TokenType != TokenType.CloseParenthesis)
            {
                ParseNonEmptyArgList(tokens, ref argc);
            }
        }
예제 #16
0
    private Ast.Stmt ParseSetStmt(TokenQueue q)
    {
        var stmt = new Ast.SetStmt {
            SourceToken = q.SourceToken
        };

        q.Take("set");
        ParseAssignmentStmtCore(q, stmt);
        return(stmt);
    }
예제 #17
0
        private void ByAttribute()
        {
            TokenQueue cq  = new TokenQueue(_tq.ChompBalanced('[', ']'));        // content queue
            string     key = cq.ConsumeToAny("=", "!=", "^=", "$=", "*=", "~="); // eq, not, start, end, contain, match, (no val)

            if (string.IsNullOrEmpty(key))
            {
                throw new Exception("key is empty.");
            }

            cq.ConsumeWhitespace();

            if (cq.IsEmpty)
            {
                if (key.StartsWith("^"))
                {
                    _evals.Add(new Evaluator.AttributeStarting(key.Substring(1)));
                }
                else
                {
                    _evals.Add(new Evaluator.Attribute(key));
                }
            }
            else
            {
                if (cq.MatchChomp("="))
                {
                    _evals.Add(new Evaluator.AttributeWithValue(key, cq.Remainder()));
                }
                else if (cq.MatchChomp("!="))
                {
                    _evals.Add(new Evaluator.AttributeWithValueNot(key, cq.Remainder()));
                }
                else if (cq.MatchChomp("^="))
                {
                    _evals.Add(new Evaluator.AttributeWithValueStarting(key, cq.Remainder()));
                }
                else if (cq.MatchChomp("$="))
                {
                    _evals.Add(new Evaluator.AttributeWithValueEnding(key, cq.Remainder()));
                }
                else if (cq.MatchChomp("*="))
                {
                    _evals.Add(new Evaluator.AttributeWithValueContaining(key, cq.Remainder()));
                }
                else if (cq.MatchChomp("~="))
                {
                    _evals.Add(new Evaluator.AttributeWithValueMatching(key, new Regex(cq.Remainder())));
                }
                else
                {
                    throw new Selector.SelectorParseException("Could not parse attribute query '{0}': unexpected token at '{1}'", _query, cq.Remainder());
                }
            }
        }
예제 #18
0
        /// <summary>
        /// Loads a RDF Dataset from the NQuads input using a RDF Handler
        /// </summary>
        /// <param name="handler">RDF Handler to use</param>
        /// <param name="input">Input to load from</param>
        public void Load(IRdfHandler handler, TextReader input)
        {
            if (handler == null)
            {
                throw new RdfParseException("Cannot parse an RDF Dataset using a null handler");
            }
            if (input == null)
            {
                throw new RdfParseException("Cannot parse an RDF Dataset from a null input");
            }

            try
            {
                //Setup Token Queue and Tokeniser
                NTriplesTokeniser tokeniser = new NTriplesTokeniser(input);
                tokeniser.NQuadsMode = true;
                ITokenQueue tokens;
                switch (this._queueMode)
                {
                case TokenQueueMode.AsynchronousBufferDuringParsing:
                    tokens = new AsynchronousBufferedTokenQueue(tokeniser);
                    break;

                case TokenQueueMode.QueueAllBeforeParsing:
                    tokens = new TokenQueue(tokeniser);
                    break;

                case TokenQueueMode.SynchronousBufferDuringParsing:
                default:
                    tokens = new BufferedTokenQueue(tokeniser);
                    break;
                }
                tokens.Tracing = this._tracetokeniser;
                tokens.InitialiseBuffer();

                //Invoke the Parser
                this.Parse(handler, tokens);
            }
            catch
            {
                throw;
            }
            finally
            {
                try
                {
                    input.Close();
                }
                catch
                {
                    //No catch actions - just cleaning up
                }
            }
        }
예제 #19
0
    private Ast.Stmt ParsePrintStmt(TokenQueue q)
    {
        var stmt = new Ast.PrintStmt {
            SourceToken = q.SourceToken
        };

        q.Take("print");
        stmt.Value = ParseExpr(q);
        ConsumeSemicolon(q);
        return(stmt);
    }
        public void chompBalanced()
        {
            TokenQueue tq        = new TokenQueue(":contains(one (two) three) four");
            string     pre       = tq.ConsumeTo("(");
            string     guts      = tq.ChompBalanced('(', ')');
            string     remainder = tq.Remainder();

            Assert.AreEqual(":contains", pre);
            Assert.AreEqual("one (two) three", guts);
            Assert.AreEqual(" four", remainder);
        }
        public void chompToIgnoreCase()
        {
            string     t    = "<textarea>one < two </TEXTarea>";
            TokenQueue tq   = new TokenQueue(t);
            string     data = tq.ChompToIgnoreCase("</textarea");

            Assert.AreEqual("<textarea>one < two ", data);

            tq   = new TokenQueue("<textarea> one two < three </oops>");
            data = tq.ChompToIgnoreCase("</textarea");
            Assert.AreEqual("<textarea> one two < three </oops>", data);
        }
예제 #22
0
        public void ProcessResponseHeaders(WebHeaderCollection resHeaders)
        {
            foreach (string name in resHeaders.AllKeys)
            {
                if (string.IsNullOrWhiteSpace(name))
                {
                    continue;                     // http/1.1 line
                }

                var value = resHeaders[name];                 //.Split(';');

                if (name.Equals("Set-Cookie", StringComparison.OrdinalIgnoreCase))
                {
                    var values = resHeaders["Set-Cookie"].Split(';', ',');
                    foreach (string v in values)
                    {
                        if (string.IsNullOrWhiteSpace(v))
                        {
                            continue;
                        }

                        var cd         = new TokenQueue(v);
                        var cookieName = cd.ChompTo("=").Trim();
                        var cookieVal  = cd.ConsumeTo(";").Trim();

                        if (cookieVal == null)
                        {
                            cookieVal = string.Empty;
                        }

                        // ignores path, date, domain, secure et al. req'd?
                        if (StringUtil.In(cookieName.ToLowerInvariant(), "domain", "path", "expires", "max-age", "secure", "httponly"))
                        {
                            // This is added for NSoup, since we do headers a bit differently around here.
                            continue;
                        }

                        // name not blank, value not null
                        if (!string.IsNullOrEmpty(cookieName))
                        {
                            Cookie(cookieName, cookieVal);
                        }
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(value))
                    {
                        Header(name, /*values[0]*/ value);
                    }
                }
            }
        }
        public override bool Match(Token first, CompilerApplication context)
        {
            TokenQueue tokens = context.context.Tokens;

            if (tokens.Peek().Text.Equals(":"))
            {
                tokens.Peek().Type = TokenType.LABEL;
                return(true);
            }

            return(false);
        }
예제 #24
0
    private Ast.Stmt ParseWhileStmt(TokenQueue q)
    {
        var stmt = new Ast.WhileStmt {
            SourceToken = q.SourceToken
        };

        q.Take("while");
        stmt.Condition = ParseExpr(q);
        stmt.Block     = ParseBlock(q);
        ConsumeSemicolon(q);
        return(stmt);
    }
예제 #25
0
        public void ProcessResponseHeaders(WebHeaderCollection resHeaders)
        {
            foreach (string name in resHeaders.Keys)
            {
                if (name == null)
                {
                    continue; // http/1.1 line
                }

                string value = resHeaders[name]; //.Split(';');

                if (name.Equals("Set-Cookie", StringComparison.InvariantCultureIgnoreCase))
                {
                    string[] values = resHeaders["Set-Cookie"].Split(';', ',');
                    foreach (string v in values)
                    {
                        if (v == null)
                        {
                            continue;
                        }

                        TokenQueue cd         = new TokenQueue(v);
                        string     cookieName = cd.ChompTo("=").Trim();
                        string     cookieVal  = cd.ConsumeTo(";").Trim();

                        if (cookieVal == null)
                        {
                            cookieVal = string.Empty;
                        }

                        // ignores path, date, domain, secure et al. req'd?
                        if (StringUtil.In(cookieName.ToLowerInvariant(), "domain", "path", "expires", "max-age", "secure", "httponly"))
                        {
                            // This is added for Texxtoor.BaseLibrary.Core.HtmlAgility.ToXml, since we do headers a bit differently around here.
                            continue;
                        }

                        // name not blank, value not null
                        if (!string.IsNullOrEmpty(cookieName))
                        {
                            Cookie(cookieName, cookieVal);
                        }
                    }
                }
                else
                { // only take the first instance of each header
                    if (/*values.Length > 0*/ !string.IsNullOrEmpty(value))
                    {
                        Header(name, /*values[0]*/ value);
                    }
                }
            }
        }
예제 #26
0
    public override MatchResult?MatchStep(MatchStack stack, MatchFrame frame, TokenQueue q)
    {
        switch (q.Take().Type)
        {
        case TokenType.Id:
        case TokenType.Ties:
        case TokenType.Variable when AllowVariable:
            return(MatchResult.Matched);

        default:
            return(MatchResult.NoMatch);
        }
    }
예제 #27
0
 public override ExcutableCommand Create(TokenQueue seq, Token first, CompilerApplication context)
 {
     if (base.Match(first, context))
     {
         MacroCommand c = (MacroCommand)Clone();
         c.keyword      = seq.Dequeue();
         c.keyword.Type = TokenType.MACRO_COMMAND;
         c.parameters   = seq.DeQueueLine();
         context.SetMacro(c.keyword.Text, c);
         return(c);
     }
     return((MacroCommand)Clone(seq, context.GetMacro(first.Text)));
 }
예제 #28
0
        private void ByAttribute()
        {
            TokenQueue cq  = new TokenQueue(tq.ChompBalanced('[', ']')); // content queue
            string     key = cq.ConsumeToAny(AttributeEvals);            // eq, not, start, end, contain, match, (no val)

            Validate.NotEmpty(key);
            cq.ConsumeWhitespace();
            if (cq.IsEmpty())
            {
                if (key.StartsWith("^", StringComparison.Ordinal))
                {
                    evals.Add(new Evaluator.AttributeStarting(key.Substring(1))); /*substring*/
                }
                else
                {
                    evals.Add(new Evaluator.Attribute(key));
                }
            }
            else
            {
                if (cq.MatchChomp("="))
                {
                    evals.Add(new Evaluator.AttributeWithValue(key, cq.Remainder()));
                }
                else if (cq.MatchChomp("!="))
                {
                    evals.Add(new Evaluator.AttributeWithValueNot(key, cq.Remainder()));
                }
                else if (cq.MatchChomp("^="))
                {
                    evals.Add(new Evaluator.AttributeWithValueStarting(key, cq.Remainder()));
                }
                else if (cq.MatchChomp("$="))
                {
                    evals.Add(new Evaluator.AttributeWithValueEnding(key, cq.Remainder()));
                }
                else if (cq.MatchChomp("*="))
                {
                    evals.Add(new Evaluator.AttributeWithValueContaining(key, cq.Remainder()));
                }
                else if (cq.MatchChomp("~="))
                {
                    evals.Add(new Evaluator.AttributeWithValueMatching(key, new Regex(cq.Remainder(), RegexOptions.Compiled)));
                }
                else
                {
                    throw new Selector.SelectorParseException("Could not parse attribute query '{0}': unexpected token at '{1}'", query, cq.Remainder());
                }
            }
        }
예제 #29
0
    private Ast.Stmt ParseReturnStmt(TokenQueue q)
    {
        var stmt = new Ast.ReturnStmt {
            SourceToken = q.SourceToken
        };

        q.Take("return");
        if (PeekExpr(q))
        {
            stmt.Value = ParseExpr(q);
        }
        ConsumeSemicolon(q);
        return(stmt);
    }
예제 #30
0
    private Ast.Stmt ParseExecuteStmt(TokenQueue q)
    {
        var stmt = new Ast.ExecuteStmt {
            SourceToken = q.SourceToken
        };

        q.Take("exec", "execute");

        if (q.Peek(1) == "=")
        {
            stmt.ReturnVariableName = ParseVariableName(q);
            q.Take("=");
        }

        if (q.PeekToken().Type == TokenType.String || q.PeekToken().Type == TokenType.Id)
        {
            stmt.ScriptName = q.Take().GetUnescapedText();
        }
        else
        {
            throw new SyntaxException(new[] { "string", "identifier" }, q);
        }

        if (IsVariableName(q.PeekToken()?.GetUnescapedText() ?? "") && q.Peek(1) == "=")
        {
            while (true)
            {
                var arg = new Ast.ArgumentPair();
                arg.Name = ParseVariableName(q);
                q.Take("=");
                if (q.Peek() == "default")
                {
                    q.Take();
                }
                else
                {
                    arg.Value = ParseExpr(q);
                }
                stmt.Arguments.Add(arg);
                if (!q.TakeMaybe(","))
                {
                    break;
                }
            }
        }

        ConsumeSemicolon(q);
        return(stmt);
    }
예제 #31
0
파일: Parser.cs 프로젝트: xsharper/xsharper
 /// <summary>
 /// Parse stream and return the expression tree
 /// </summary>
 /// <param name="r">Stream</param>
 /// <returns>Parsed expression or null if no expression is found on stream</returns>
 public IOperation Parse(ParsingReader r)
 {
     List<IOperation> data = new List<IOperation>();
     while (!r.IsEOF)
     {
         TokenQueue tokenQueue = new TokenQueue(this, r);
         var ex = parseSingleStatement(tokenQueue,-1);
         if (ex == null)
             break;
         if (data.Count > 0)
             data.Add(new Operations.OperationPop());
         data.Add(ex);
         r.SkipWhiteSpaceAndComments();
         if (r.Peek() != ';')
             break;
         do
         {
             r.Read();
             r.SkipWhiteSpaceAndComments();
         } while (r.Peek() == ';');
     }
     if (data.Count == 0)
         return null;
     if (data.Count == 1)
         return data[0];
     return new Operations.OperationExpression(data.ToArray());
 }
예제 #32
0
파일: Parser.cs 프로젝트: xsharper/xsharper
        private static IOperation parseSingleStatement(TokenQueue tokenQueue, int precedenceAtLeast)
        {
            Queue<IOperation> queue = new Queue<IOperation>();
            Stack<QToken> stack = new Stack<QToken>();
            QToken token = null;
            bool argumentExpected = false;
            bool dotIsProperty = false;
            bool exitLoop = false;
            while (!exitLoop)
            {
                token = tokenQueue.Pop();
                if (token == null)
                    break;

                switch (token.TokenType)
                {
                    case QType.ParenthesisOpen:
                        // C# has typecasts, such as ((IInterface)x) so when seeing an opening (, we must try to read type.
                        // This however does not work if there is an identifier before the (, for example func(Enum.Value,(Enum.Value)).
                        if (stack.Count == 0 || (stack.Peek().TokenType != QType.Id && !stack.Peek().IsOperator(Operators.New)))
                        {
                            string sType = tokenQueue.GetTypeNameFollowedByClosingParenthesis();
                            if (sType != null)
                            {
                                var q = tokenQueue.Peek();
                                if (q==null || (q.TokenType!=QType.Id && q.TokenType!=QType.Value && q.TokenType!=QType.Subexpr && !q.IsOpenBrace))
                                {
                                    token = new QToken(QType.Id, sType);
                                    goto case QType.Id;
                                }
                                stack.Push(new QToken(Operators.TypeCast) {Param = sType});
                                argumentExpected = dotIsProperty = false;
                                break;
                            }
                        }
                        goto case QType.SquareOpen;
                    case QType.SquareOpen:
                    case QType.BlockOpen:
                        token.ExtraInt = -(queue.Count + stack.Count + 1);
                        stack.Push(token);
                        argumentExpected = false;
                        dotIsProperty = false;
                        break;

                    case QType.Value:
                        queue.Enqueue(operationFromToken(token));
                        argumentExpected = false;
                        dotIsProperty = true;
                        break;
                    case QType.Subexpr:
                        queue.Enqueue(operationFromToken(token));
                        argumentExpected = false;
                        dotIsProperty = true;
                        break;
                    case QType.Typeof:
                        if (tokenQueue.Peek() == null || tokenQueue.Peek().TokenType != QType.ParenthesisOpen)
                            tokenQueue.ThrowParsingException("Expected (");
                        tokenQueue.Pop();
                        token.Param = tokenQueue.ReadTypeName();
                        if (tokenQueue.Peek() == null || tokenQueue.Peek().TokenType != QType.ParenthesisClose)
                            tokenQueue.ThrowParsingException("Expected )");
                        tokenQueue.Pop();
                        queue.Enqueue(operationFromToken(token));
                        argumentExpected = false;
                        dotIsProperty = true;
                        break;

                    case QType.Id:
                        string curId = (string)token.Param;
                        bool startsWithDot = curId.StartsWith(".", StringComparison.Ordinal);
                        if (dotIsProperty)
                        {
                            if (!startsWithDot)
                                tokenQueue.ThrowParsingException("Expected .");
                            token.Param = curId.Substring(1);
                            token.ExtraInt = 1;
                        }
                        else if (token.ExtraInt == 0)
                        {
                            var n = tokenQueue.Peek();
                            if (n != null && (n.TokenType != QType.ParenthesisOpen) && (n.TokenType != QType.SquareOpen))
                                goto case QType.Value;
                        }
                        stack.Push(token);
                        argumentExpected = false;
                        dotIsProperty = true;
                        break;
                    case QType.Colon:
                        tokenQueue.Push(token);
                        exitLoop = true;
                        break;
                    case QType.Operator:
                        Operators op = token.Operator;
                        if (argumentExpected || !dotIsProperty)
                        {
                            if (op == Operators.Minus) token = new QToken(op = Operators.UnaryMinus);
                            if (op == Operators.Plus) token = new QToken(op = Operators.UnaryPlus);
                        }

                        cleanStack(queue, stack, op);

                        if (precedenceAtLeast >= 0 && s_precedence[op] < precedenceAtLeast && stack.Count == 0)
                        {
                            tokenQueue.Push(token);
                            exitLoop = true;
                            argumentExpected = false;
                            break;
                        }

                        switch (op)
                        {
                            case Operators.Or:
                            case Operators.And:
                                {
                                    // Or and AND short-circuit, so a || b || c => a?true:(b?true:c)
                                    // and a && b &&c => a?(b?c:false):false
                                    Stack<IOperation> terms = new Stack<IOperation>();
                                    bool isOr = (op == Operators.Or);
                                    do
                                    {
                                        var e1 = parseSingleStatement(tokenQueue, s_precedence[op] + 1);
                                        if (e1 == null)
                                            tokenQueue.ThrowParsingException("Expression expected after " + (isOr ? "||" : "&&"));
                                        terms.Push(e1);
                                        var n = tokenQueue.Peek();
                                        if (n == null || !n.IsOperator(op))
                                            break;
                                        tokenQueue.Pop();
                                    } while (true);

                                    IOperation o = null;
                                    while (terms.Count > 0)
                                    {
                                        if (o == null)
                                            o = terms.Pop();
                                        else
                                            o = new Operations.OperationExpression(terms.Pop(),
                                                                                    (isOr) ? new Operations.OperationConditional(createConstant(true), o) :
                                                                                          new Operations.OperationConditional(o, createConstant(false)));
                                    }
                                    o = (isOr) ? new Operations.OperationConditional(createConstant(true), o) :
                                                new Operations.OperationConditional(o, createConstant(false));

                                    queue.Enqueue(o);
                                    argumentExpected = dotIsProperty = false;
                                    break;
                                }
                            case Operators.Conditional:
                                {
                                    var e1 = parseSingleStatement(tokenQueue, -1);
                                    if (e1 == null)
                                        tokenQueue.ThrowParsingException("Failed to parse the first part of the conditional expression");
                                    var n = tokenQueue.Pop();
                                    if (n == null || n.TokenType != QType.Colon)
                                        tokenQueue.ThrowParsingException("Expected :");

                                    var e2 = parseSingleStatement(tokenQueue, -1);
                                    if (e2 == null)
                                        tokenQueue.ThrowParsingException("Failed to parse the second part of the conditional expression");
                                    queue.Enqueue(new Operations.OperationConditional(e1, e2));
                                    argumentExpected = dotIsProperty = false;
                                }
                                break;
                            case Operators.Coalesce:
                                {
                                    var e2 = parseSingleStatement(tokenQueue, -1);
                                    if (e2 == null)
                                        tokenQueue.ThrowParsingException("Expression expected after ??");

                                    queue.Enqueue(new Operations.OperationCoalesce(e2));
                                    argumentExpected = dotIsProperty = false;
                                }
                                break;

                            case Operators.Comma:
                                while (stack.Count > 0 && !stack.Peek().IsOpenBrace)
                                    queue.Enqueue(operationFromToken(stack.Pop()));
                                if (stack.Count > 0 && stack.Peek().IsOpenBrace)
                                {
                                    var p = stack.Pop();
                                    if (p.ExtraInt <= 0)
                                        p.ExtraInt = 1;
                                    p.ExtraInt++; // Count the number of comma-separated entities in braces
                                    stack.Push(p);
                                }
                                argumentExpected = dotIsProperty = false;
                                break;
                            case Operators.New:
                            case Operators.Is:
                            case Operators.As:
                                // After this there is a typename, which in case of typeof() MUST be in parentheses (unlike C++)
                                token.Param = tokenQueue.ReadTypeName();
                                if (token.Param==null && op!=Operators.New)
                                    tokenQueue.ThrowParsingException("Expected type");
                                stack.Push(token);
                                argumentExpected = false;
                                dotIsProperty = true;
                                break;

                            default:
                                argumentExpected = true;
                                dotIsProperty = false;
                                stack.Push(token);
                                break;
                        }
                        break;

                    case QType.ParenthesisClose:
                    case QType.BlockClose:
                    case QType.SquareClose:
                        if (argumentExpected)
                            tokenQueue.ThrowParsingException("Argument expected");
                        QType match = QType.ParenthesisOpen;
                        if (token.TokenType == QType.SquareClose) match = QType.SquareOpen;
                        if (token.TokenType == QType.BlockClose) match = QType.BlockOpen;

                        while (stack.Count > 0 && stack.Peek().TokenType != match)
                        {
                            var sp = stack.Pop();
                            if (sp.IsOpenBrace)
                                tokenQueue.ThrowParsingException("Parentheses or square brackets do not match");
                            queue.Enqueue(operationFromToken(sp));

                        }

                        if (stack.Count == 0)
                        {
                            tokenQueue.Push(token);
                            exitLoop = true;
                            break;
                        }

                        var args = stack.Pop().ExtraInt;
                        if (args < 0)
                            args = (args == -(queue.Count + stack.Count + 1)) ? 0 : 1;

                        var nextToken = tokenQueue.Peek();

                        if (stack.Count > 0 && stack.Peek().IsOperator(Operators.New))
                        {
                            var newOp = stack.Pop();
                            switch (token.TokenType)
                            {
                                case QType.SquareClose:
                                    if (nextToken == null || nextToken.TokenType != QType.BlockOpen)
                                        queue.Enqueue(new Operations.OperationNewObject((string)newOp.Param, args, false));
                                    else
                                    {
                                        newOp.ExtraInt = args;
                                        stack.Push(newOp);
                                    }
                                    break;
                                case QType.BlockClose:
                                    queue.Enqueue(new Operations.OperationCreateBlock(args));
                                    queue.Enqueue(new Operations.OperationNewObject((string)newOp.Param, newOp.ExtraInt + 1, (token.TokenType == QType.BlockClose)));
                                    break;
                                default:
                                    queue.Enqueue(new Operations.OperationNewObject((string)newOp.Param, args, (token.TokenType == QType.BlockClose)));
                                    break;
                            }
                        }
                        else if (token.TokenType == QType.ParenthesisClose || token.TokenType == QType.SquareClose)
                        {
                            if (stack.Count > 0 && (stack.Peek().TokenType == QType.Id))
                            {
                                var pop = stack.Pop();
                                string id = (string)pop.Param;
                                bool isProperty = (token.TokenType == QType.SquareClose);
                                queue.Enqueue(new Operations.OperationCall(id, pop.ExtraInt != 0, isProperty, args));
                            }
                            else if (token.TokenType == QType.SquareClose)
                                queue.Enqueue(new Operations.OperationCall(string.Empty, true, true, args));
                        }
                        else // if (token.Type == QType.BlockClose)
                        {
                            queue.Enqueue(new Operations.OperationCreateBlock(args));
                        }
                        argumentExpected = false;
                        dotIsProperty = true;
                        break;

                }

            }

            if (argumentExpected)
                tokenQueue.ThrowParsingException("Argument expected");

            while (stack.Count > 0)
                queue.Enqueue(operationFromToken(stack.Pop()));

            IOperation ex;
            if (queue.Count == 0)
                return null;
            if (queue.Count == 1)
                ex = queue.Peek();
            else
                ex = new Operations.OperationExpression(queue.ToArray());
            if (ex.StackBalance != 1)
                tokenQueue.ThrowParsingException("Invalid expression syntax");
            return ex;
        }
예제 #33
0
		/*Create a token buffer */
		public TokenBuffer(TokenStream input_)
		{
			input = input_;
			queue = new TokenQueue(1);
		}