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); }
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); }
private void ParseAssignmentStmtCore(TokenQueue q, Ast.AssignmentStmt stmt) { stmt.VariableName = ParseVariableName(q); if (q.Peek() == "=") { q.Take(); stmt.InitialValue = ParseExpr(q); } ConsumeSemicolon(q); }
private Ast.Stmt ParseTryCatchStmt(TokenQueue q) { var stmt = new Ast.TryCatchStmt { SourceToken = q.SourceToken }; q.Take("begin"); q.Take("try"); stmt.TryBlock = new Ast.Block { SourceToken = q.SourceToken }; while (q.Peek() != "end") { var tryStmt = ParseStmt(q); if (tryStmt != null) { stmt.TryBlock.Statements.Add(tryStmt); } } q.Take("end"); q.Take("try"); q.Take("begin"); q.Take("catch"); stmt.CatchBlock = new Ast.Block { SourceToken = q.SourceToken }; while (q.Peek() != "end") { var catchStmt = ParseStmt(q); if (catchStmt != null) { stmt.CatchBlock.Statements.Add(catchStmt); } } q.Take("end"); q.Take("catch"); return(stmt); }
private Ast.Stmt ParseStmt(TokenQueue q) // or null { switch (q.Peek(0)) { case ";": q.Take(";"); return(null); case "declare": return(ParseDeclareStmt(q)); case "while": return(ParseWhileStmt(q)); case "break": return(ParseBreakStmt(q)); case "continue": return(ParseContinueStmt(q)); case "print": return(ParsePrintStmt(q)); case "exec": case "execute": return(ParseExecuteStmt(q)); case "return": return(ParseReturnStmt(q)); case "throw": return(ParseThrowStmt(q)); case "set": return(ParseSetStmt(q)); case "if": return(ParseIfStmt(q)); case "begin": return(q.Peek(1) == "try" ? ParseTryCatchStmt(q) : ParseSqlStmt(q)); case "import": return(ParseImportStmt(q)); case "export": return(ParseExportStmt(q)); case "for": return(ParseForStmt(q)); default: return(ParseSqlStmt(q)); } }
private Ast.DeclareStmt ParseDeclareStmt(TokenQueue q) { var stmt = new Ast.DeclareStmt { SourceToken = q.SourceToken }; q.Take("declare"); if (q.Peek() == "parameter") { q.Take(); stmt.IsParameter = true; } ParseAssignmentStmtCore(q, stmt); return(stmt); }
private Ast.Stmt ParseIfStmt(TokenQueue q) { var stmt = new Ast.IfStmt { SourceToken = q.SourceToken }; q.Take("if"); stmt.Condition = ParseExpr(q); stmt.Block = ParseBlock(q); if (q.Peek() == "else") { q.Take("else"); stmt.ElseBlock = ParseBlock(q); } return(stmt); }
// Read a JKLSequence, checking that it starts and terminates correctly. // Named read_list to follow the ref, but has been genericized to handle vectors as well. static public JKLSeqBase read_list(TokenQueue TQ, JKLSeqBase sequence, char start, char end) { // Check that we are in fact at the start of a list. string token = TQ.Next(); if (token[0] != start) { // Parse error - probably internal if the list code is correct. throw new JKLInternalError("Sequence expected '" + start + "' but got: " + token); } // Use read_form to get the list's contents, accumulating them into the list. while (true) { token = TQ.Peek(); if (token != null) { // We are in the list or at the end. if (token[0] == end) { // Reached valid end of list. Consume the end char. TQ.Next(); // And we are done. break; } // Mutually recurse to read the next list element. JKLVal newVal = read_form(TQ); sequence.Add(newVal); } else { // The input has finished but the list hasn't. Try to get more input. TQ.LoadMoreTokens(start, end); } } return(sequence); }
// Read a JKLVal form - which is either an atom or a sequence. static public JKLVal read_form(TokenQueue TQ) { if (TQ.Peek() == null) { // Reader is empty - caused by a comment line in the input. return(null); } else if (TQ.Peek().StartsWith('(')) { // Create a new List and read it's body. return(read_list(TQ, new JKLList(), '(', ')')); } else if (TQ.Peek().StartsWith('[')) { // Create a new Vector and read it's body. return(read_list(TQ, new JKLVector(), '[', ']')); } else if (TQ.Peek().StartsWith('{')) { // Create a new HashMap and read it's body. EVAL checks it has valid key val pairs. return(read_list(TQ, new JKLHashMap(), '{', '}')); } else if (TQ.Peek().StartsWith(')') || TQ.Peek().StartsWith(']') || TQ.Peek().StartsWith('}')) { // A sequence close character that doesn't match a start. // This correctly handles a case like [1 ( 2 ] 3). throw new JKLParseError("Expecting sequence or atom but got '" + TQ.Peek() + "'"); } else if (TQ.Peek().StartsWith('&')) { // Reader macro. We have '&atomName'. Convert this into (deref atomName); string varArgAtom = TQ.Peek(); if (varArgAtom.Length == 1) { // Treat a solo '&' as a varargs symbol, TQ.Next(); return(jklVarArgsChar); } else { throw new JKLParseError("'&' can't start a symbol name: '" + varArgAtom.ToString() + "'"); } } else if (TQ.Peek().StartsWith('@')) { TQ.Next(); // Build a deref form. JKLList derefForm = new JKLList(); derefForm.Add(new JKLSym("deref")); derefForm.Add(read_form(TQ)); return(derefForm); } else if (TQ.Peek().StartsWith('\'')) { // Return a list containing a quote symbol and the quoted form. TQ.Next(); JKLList quoteForm = new JKLList(); quoteForm.Add(new JKLSym("quote")); quoteForm.Add(read_form(TQ)); return(quoteForm); } else if (TQ.Peek().StartsWith('`')) { // Return a list containing a quasiquote symbol and the quasiquoted form. TQ.Next(); JKLList quasiquoteForm = new JKLList(); quasiquoteForm.Add(new JKLSym("quasiquote")); quasiquoteForm.Add(read_form(TQ)); return(quasiquoteForm); } else if (TQ.Peek().StartsWith("~@")) { // Return a list containing a splice-unquote symbol and the next form. // Dammit! I'd missed the '~' here and spent several days wondering why (or ...) didn't work. TQ.Next(); JKLList quasiquoteForm = new JKLList(); quasiquoteForm.Add(new JKLSym("splice-unquote")); quasiquoteForm.Add(read_form(TQ)); return(quasiquoteForm); } else if (TQ.Peek().StartsWith('~')) { // Return a list containing an unquote symbol and the next form. TQ.Next(); JKLList quasiquoteForm = new JKLList(); quasiquoteForm.Add(new JKLSym("unquote")); quasiquoteForm.Add(read_form(TQ)); return(quasiquoteForm); } else if (TQ.Peek().StartsWith('^')) { // Return a new list that contains the symbol "with-meta" and the result of reading the // next next form (2nd argument) (read_form) and the next form (1st argument) in that order TQ.Next(); JKLList withMetaForm = new JKLList(); withMetaForm.Add(new JKLSym("with-meta")); JKLVal firstArg = read_form(TQ); JKLVal secondArg = read_form(TQ); withMetaForm.Add(secondArg); withMetaForm.Add(firstArg); return(withMetaForm); } else { // This isn't a list so parse it as an atom. return(read_token(TQ)); } }
private Ast.Stmt ParseImportStmt(TokenQueue q) => q.Peek(1) switch { "csv" => Check(q, ParseImportCsvStmt(q)),
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; }
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); }