private Executable ParseFor(TokenStream tokens, TopLevelConstruct owner) { Token forToken = tokens.PopExpected(this.parser.Keywords.FOR); tokens.PopExpected("("); if (!tokens.HasMore) { tokens.ThrowEofException(); } if (this.parser.IsValidIdentifier(tokens.PeekValue()) && tokens.PeekValue(1) == ":") { Token iteratorToken = tokens.Pop(); if (this.parser.IsReservedKeyword(iteratorToken.Value)) { throw new ParserException(iteratorToken, "Cannot use this name for an iterator."); } tokens.PopExpected(":"); Expression iterationExpression = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); IList <Executable> body = ParserContext.ParseBlock(parser, tokens, false, owner); return(new ForEachLoop(forToken, iteratorToken, iterationExpression, body, owner)); } else { List <Executable> init = new List <Executable>(); while (!tokens.PopIfPresent(";")) { if (init.Count > 0) { tokens.PopExpected(","); } init.Add(this.Parse(tokens, true, false, owner)); } Expression condition = null; if (!tokens.PopIfPresent(";")) { condition = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected(";"); } List <Executable> step = new List <Executable>(); while (!tokens.PopIfPresent(")")) { if (step.Count > 0) { tokens.PopExpected(","); } step.Add(this.Parse(tokens, true, false, owner)); } IList <Executable> body = ParserContext.ParseBlock(parser, tokens, false, owner); return(new ForLoop(forToken, init, condition, step, body, owner)); } }
private Expression ParseMultiplication(TokenStream tokens, Node owner) { Expression expr = ParseNegate(tokens, owner); string next = tokens.PeekValue(); while (MULTIPLICATION_OPS.Contains(next)) { Token op = tokens.Pop(); Expression right = ParseNegate(tokens, owner); expr = new OpChain(expr, op, right, owner); next = tokens.PeekValue(); } return(expr); }
private Expression ParseAddition(TokenStream tokens, TopLevelConstruct owner) { Expression expr = ParseMultiplication(tokens, owner); string next = tokens.PeekValue(); while (ADDITION_OPS.Contains(next)) { Token op = tokens.Pop(); Expression right = ParseMultiplication(tokens, owner); expr = new BinaryOpChain(expr, op, right, owner); next = tokens.PeekValue(); } return(expr); }
public static ModifierCollection Parse(TokenStream tokens) { if (!tokens.HasMore || !LOOKUP.ContainsKey(tokens.PeekValue())) { return(EMPTY); } List <Token> modifierTokens = new List <Token>(); while (LOOKUP.ContainsKey(tokens.PeekValue())) { modifierTokens.Add(tokens.Pop()); } return(new ModifierCollection(modifierTokens)); }
private Expression ParseEqualityComparison(TokenStream tokens, Node owner) { Expression expr = ParseInequalityComparison(tokens, owner); string next = tokens.PeekValue(); if (next == "==" || next == "!=") { Token equalityToken = tokens.Pop(); Expression rightExpr = ParseEqualityComparison(tokens, owner); return(new OpChain(expr, equalityToken, rightExpr, owner)); } return(expr); }
private Expression ParseBitwiseOp(TokenStream tokens, Node owner) { Expression expr = ParseEqualityComparison(tokens, owner); string next = tokens.PeekValue(); if (next == "|" || next == "&" || next == "^") { Token bitwiseToken = tokens.Pop(); Expression rightExpr = ParseBitwiseOp(tokens, owner); return(new OpChain(expr, bitwiseToken, rightExpr, owner)); } return(expr); }
private Expression ParseBooleanCombination(TokenStream tokens, Node owner) { Expression expr = ParseBitwiseOp(tokens, owner); string next = tokens.PeekValue(); if (next == "||" || next == "&&") { List <Expression> expressions = new List <Expression>() { expr }; List <Token> ops = new List <Token>(); while (next == "||" || next == "&&") { ops.Add(tokens.Pop()); expressions.Add(ParseBitwiseOp(tokens, owner)); next = tokens.PeekValue(); } return(new BooleanCombination(expressions, ops, owner)); } return(expr); }
private Expression ParseExponents(TokenStream tokens, Node owner) { Expression expr = ParseIncrement(tokens, owner); string next = tokens.PeekValue(); if (next == "**") { Token op = tokens.Pop(); Expression right = ParseNegate(tokens, owner); expr = new OpChain(expr, op, right, owner); } return(expr); }
private Expression ParseBitShift(TokenStream tokens, Node owner) { Expression expr = ParseAddition(tokens, owner); string next = tokens.PeekValue(); if (next == "<<" || next == ">>") { Token opToken = tokens.Pop(); Expression rightExpr = ParseBitShift(tokens, owner); return(new OpChain(expr, opToken, rightExpr, owner)); } return(expr); }
private Expression ParseInequalityComparison(TokenStream tokens, Node owner) { Expression expr = ParseBitShift(tokens, owner); string next = tokens.PeekValue(); if (next == "<" || next == ">" || next == "<=" || next == ">=") { // Don't allow chaining of inqeualities Token opToken = tokens.Pop(); Expression rightExpr = ParseBitShift(tokens, owner); return(new OpChain(expr, opToken, rightExpr, owner)); } return(expr); }
private Expression ParseNegate(TokenStream tokens, Node owner) { string next = tokens.PeekValue(); if (NEGATE_OPS.Contains(next)) { Token negateOp = tokens.Pop(); Expression root = ParseNegate(tokens, owner); if (negateOp.Value == "!") { return(new BooleanNot(negateOp, root, owner)); } if (negateOp.Value == "-") { return(new NegativeSign(negateOp, root, owner)); } throw new Exception("This shouldn't happen."); } return(ParseExponents(tokens, owner)); }
public TopLevelConstruct ParseTopLevel( TokenStream tokens, TopLevelConstruct owner, FileScope fileScope) { AnnotationCollection annotations = annotations = this.parser.AnnotationParser.ParseAnnotations(tokens); string value = tokens.PeekValue(); // The returns are inline, so you'll have to refactor or put the check inside each parse call. // Or maybe a try/finally. TODO.CheckForUnusedAnnotations(); Token staticToken = null; Token finalToken = null; while (value == this.parser.Keywords.STATIC || value == this.parser.Keywords.FINAL) { if (value == this.parser.Keywords.STATIC && staticToken == null) { staticToken = tokens.Pop(); value = tokens.PeekValue(); } if (value == this.parser.Keywords.FINAL && finalToken == null) { finalToken = tokens.Pop(); value = tokens.PeekValue(); } } if (staticToken != null || finalToken != null) { if (value != this.parser.Keywords.CLASS) { if (staticToken != null) { throw ParserException.ThrowException(this.parser.CurrentLocale, ErrorMessages.ONLY_CLASSES_METHODS_FIELDS_MAY_BE_STATIC, staticToken); } else { throw ParserException.ThrowException(this.parser.CurrentLocale, ErrorMessages.ONLY_CLASSES_MAY_BE_FINAL, finalToken); } } if (staticToken != null && finalToken != null) { throw ParserException.ThrowException(this.parser.CurrentLocale, ErrorMessages.CLASSES_CANNOT_BE_STATIC_AND_FINAL_SIMULTANEOUSLY, staticToken); } } if (value == parser.Keywords.IMPORT) { Token importToken = tokens.PopExpected(parser.Keywords.IMPORT); List <string> importPathBuilder = new List <string>(); while (!tokens.PopIfPresent(";")) { if (importPathBuilder.Count > 0) { tokens.PopExpected("."); } Token pathToken = tokens.Pop(); parser.VerifyIdentifier(pathToken); importPathBuilder.Add(pathToken.Value); } string importPath = string.Join(".", importPathBuilder); return(new ImportStatement(importToken, importPath, parser.CurrentLibrary, fileScope)); } if (value == this.parser.Keywords.NAMESPACE) { return(this.ParseNamespace(tokens, owner, fileScope, annotations)); } if (value == this.parser.Keywords.CONST) { return(this.ParseConst(tokens, owner, fileScope, annotations)); } if (value == this.parser.Keywords.FUNCTION) { return(this.ParseFunction(tokens, owner, fileScope, annotations)); } if (value == this.parser.Keywords.CLASS) { return(this.ParseClassDefinition(tokens, owner, staticToken, finalToken, fileScope, annotations)); } if (value == this.parser.Keywords.ENUM) { return(this.ParseEnumDefinition(tokens, owner, fileScope, annotations)); } if (value == this.parser.Keywords.CONSTRUCTOR) { return(this.ParseConstructor(tokens, owner, annotations)); } Token token = tokens.Peek(); throw ParserException.ThrowException( this.parser.CurrentLocale, ErrorMessages.UNEXPECTED_TOKEN_NO_SPECIFIC_EXPECTATIONS, token, token.Value); }
public Executable Parse( TokenStream tokens, bool simpleOnly, bool semicolonPresent, TopLevelConstruct owner) { string value = tokens.PeekValue(); if (!simpleOnly) { if (value == this.parser.Keywords.FUNCTION || value == this.parser.Keywords.CLASS) { throw new ParserException( tokens.Peek(), (value == this.parser.Keywords.FUNCTION ? "Function" : "Class") + " definition cannot be nested in another construct."); } if (value == parser.Keywords.IMPORT) { throw this.parser.GenerateParseError(ErrorMessages.ALL_IMPORTS_MUST_OCCUR_AT_BEGINNING_OF_FILE, tokens.Peek()); } if (value == this.parser.Keywords.ENUM) { throw new ParserException(tokens.Peek(), "Enums can only be defined from the root of a file and cannot be nested inside functions/loops/etc."); } if (value == this.parser.Keywords.NAMESPACE) { throw new ParserException(tokens.Peek(), "Namespace declarations cannot be nested in other constructs."); } if (value == this.parser.Keywords.CONST) { throw new ParserException(tokens.Peek(), "Constant declarations cannot be nested in other constructs."); } if (value == this.parser.Keywords.FOR) { return(this.ParseFor(tokens, owner)); } if (value == this.parser.Keywords.WHILE) { return(this.ParseWhile(tokens, owner)); } if (value == this.parser.Keywords.DO) { return(this.ParseDoWhile(tokens, owner)); } if (value == this.parser.Keywords.SWITCH) { return(this.ParseSwitch(tokens, owner)); } if (value == this.parser.Keywords.IF) { return(this.ParseIf(tokens, owner)); } if (value == this.parser.Keywords.TRY) { return(this.ParseTry(tokens, owner)); } if (value == this.parser.Keywords.RETURN) { return(this.ParseReturn(tokens, owner)); } if (value == this.parser.Keywords.BREAK) { return(this.ParseBreak(tokens, owner)); } if (value == this.parser.Keywords.CONTINUE) { return(this.ParseContinue(tokens, owner)); } if (value == this.parser.Keywords.THROW) { return(this.ParseThrow(tokens, owner)); } } Expression expr = this.parser.ExpressionParser.Parse(tokens, owner); value = tokens.PeekValue(); if (ASSIGNMENT_OPS.Contains(value)) { Token assignment = tokens.Pop(); Expression assignmentValue = this.parser.ExpressionParser.Parse(tokens, owner); if (semicolonPresent) { tokens.PopExpected(";"); } return(new Assignment(expr, assignment, assignment.Value, assignmentValue, owner)); } if (semicolonPresent) { tokens.PopExpected(";"); } return(new ExpressionAsExecutable(expr, owner)); }
private Expression ParseEntityWithoutSuffixChain(TokenStream tokens, TopLevelConstruct owner) { string next = tokens.PeekValue(); if (next == null) { tokens.ThrowEofException(); } if (next == this.parser.Keywords.NULL) { return(new NullConstant(tokens.Pop(), owner)); } if (next == this.parser.Keywords.TRUE) { return(new BooleanConstant(tokens.Pop(), true, owner)); } if (next == this.parser.Keywords.FALSE) { return(new BooleanConstant(tokens.Pop(), false, owner)); } Token peekToken = tokens.Peek(); if (next.StartsWith("'")) { return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner)); } if (next.StartsWith("\"")) { return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner)); } if (next == this.parser.Keywords.NEW) { return(this.ParseInstantiate(tokens, owner)); } char firstChar = next[0]; if (VARIABLE_STARTER.Contains(firstChar)) { Token varToken = tokens.Pop(); return(new Variable(varToken, varToken.Value, owner)); } if (firstChar == '[') { Token bracketToken = tokens.PopExpected("["); List <Expression> elements = new List <Expression>(); bool previousHasCommaOrFirst = true; while (!tokens.PopIfPresent("]")) { if (!previousHasCommaOrFirst) { tokens.PopExpected("]"); // throws appropriate error } elements.Add(Parse(tokens, owner)); previousHasCommaOrFirst = tokens.PopIfPresent(","); } return(new ListDefinition(bracketToken, elements, owner)); } if (firstChar == '{') { Token braceToken = tokens.PopExpected("{"); List <Expression> keys = new List <Expression>(); List <Expression> values = new List <Expression>(); bool previousHasCommaOrFirst = true; while (!tokens.PopIfPresent("}")) { if (!previousHasCommaOrFirst) { tokens.PopExpected("}"); // throws appropriate error } keys.Add(Parse(tokens, owner)); tokens.PopExpected(":"); values.Add(Parse(tokens, owner)); previousHasCommaOrFirst = tokens.PopIfPresent(","); } return(new DictionaryDefinition(braceToken, keys, values, owner)); } if (next.Length > 2 && next.Substring(0, 2) == "0x") { Token intToken = tokens.Pop(); int intValue = IntegerConstant.ParseIntConstant(intToken, intToken.Value); return(new IntegerConstant(intToken, intValue, owner)); } if (ParserContext.IsInteger(next)) { Token numberToken = tokens.Pop(); string numberValue = numberToken.Value; if (tokens.IsNext(".")) { Token decimalToken = tokens.Pop(); if (decimalToken.HasWhitespacePrefix) { throw new ParserException(decimalToken, "Decimals cannot have whitespace before them."); } Token afterDecimal = tokens.Pop(); if (afterDecimal.HasWhitespacePrefix) { throw new ParserException(afterDecimal, "Cannot have whitespace after the decimal."); } if (!ParserContext.IsInteger(afterDecimal.Value)) { throw new ParserException(afterDecimal, "Decimal must be followed by an integer."); } numberValue += "." + afterDecimal.Value; double floatValue = FloatConstant.ParseValue(numberToken, numberValue); return(new FloatConstant(numberToken, floatValue, owner)); } int intValue = IntegerConstant.ParseIntConstant(numberToken, numberToken.Value); return(new IntegerConstant(numberToken, intValue, owner)); } if (tokens.IsNext(".")) { Token dotToken = tokens.PopExpected("."); string numberValue = "0."; Token postDecimal = tokens.Pop(); if (postDecimal.HasWhitespacePrefix || !ParserContext.IsInteger(postDecimal.Value)) { throw new ParserException(dotToken, "Unexpected dot."); } numberValue += postDecimal.Value; double floatValue; if (Util.ParseDouble(numberValue, out floatValue)) { return(new FloatConstant(dotToken, floatValue, owner)); } throw new ParserException(dotToken, "Invalid float literal."); } throw new ParserException(tokens.Peek(), "Encountered unexpected token: '" + tokens.PeekValue() + "'"); }
public TopLevelConstruct ParseTopLevel( TokenStream tokens, TopLevelConstruct owner, FileScope fileScope) { AnnotationCollection annotations = annotations = this.parser.AnnotationParser.ParseAnnotations(tokens); string value = tokens.PeekValue(); // The returns are inline, so you'll have to refactor or put the check inside each parse call. // Or maybe a try/finally. TODO.CheckForUnusedAnnotations(); Token staticToken = null; Token finalToken = null; while (value == this.parser.Keywords.STATIC || value == this.parser.Keywords.FINAL) { if (value == this.parser.Keywords.STATIC && staticToken == null) { staticToken = tokens.Pop(); value = tokens.PeekValue(); } if (value == this.parser.Keywords.FINAL && finalToken == null) { finalToken = tokens.Pop(); value = tokens.PeekValue(); } } if (staticToken != null || finalToken != null) { if (value != this.parser.Keywords.CLASS) { if (staticToken != null) { throw new ParserException(staticToken, "Only classes, methods, and fields may be marked as static"); } else { throw new ParserException(finalToken, "Only classes may be marked as final."); } } if (staticToken != null && finalToken != null) { throw new ParserException(staticToken, "Classes cannot be both static and final."); } } if (value == parser.Keywords.IMPORT) { Token importToken = tokens.PopExpected(parser.Keywords.IMPORT); List <string> importPathBuilder = new List <string>(); while (!tokens.PopIfPresent(";")) { if (importPathBuilder.Count > 0) { tokens.PopExpected("."); } Token pathToken = tokens.Pop(); parser.VerifyIdentifier(pathToken); importPathBuilder.Add(pathToken.Value); } string importPath = string.Join(".", importPathBuilder); return(new ImportStatement(importToken, importPath, parser.CurrentLibrary, fileScope)); } if (value == this.parser.Keywords.NAMESPACE) { return(this.ParseNamespace(tokens, owner, fileScope, annotations)); } if (value == this.parser.Keywords.CONST) { return(this.ParseConst(tokens, owner, fileScope, annotations)); } if (value == this.parser.Keywords.FUNCTION) { return(this.ParseFunction(tokens, owner, fileScope, annotations)); } if (value == this.parser.Keywords.CLASS) { return(this.ParseClassDefinition(tokens, owner, staticToken, finalToken, fileScope, annotations)); } if (value == this.parser.Keywords.ENUM) { return(this.ParseEnumDefinition(tokens, owner, fileScope, annotations)); } if (value == this.parser.Keywords.CONSTRUCTOR) { return(this.ParseConstructor(tokens, owner, annotations)); } throw new ParserException(tokens.Peek(), "Unrecognized token."); }
internal virtual TopLevelEntity Parse( TokenStream tokens, TopLevelEntity owner, FileScope fileScope) { AnnotationCollection annotations = this.parser.AnnotationParser.ParseAnnotations(tokens); ModifierCollection modifiers = ModifierCollection.Parse(tokens); string value = tokens.PeekValue(); if (value == this.parser.Keywords.IMPORT) { throw this.parser.GenerateParseError( ErrorMessages.ALL_IMPORTS_MUST_OCCUR_AT_BEGINNING_OF_FILE, tokens.Pop()); } // The returns are inline, so you'll have to refactor or put the check inside each parse call. // Or maybe a try/finally. TODO.CheckForUnusedAnnotations(); if (value == this.parser.Keywords.NAMESPACE) { return(this.ParseNamespace(tokens, owner, fileScope, annotations)); } if (value == this.parser.Keywords.CONST) { return(this.ParseConst(tokens, owner, fileScope, modifiers, annotations)); } if (value == this.parser.Keywords.FUNCTION) { return(this.ParseFunction(tokens, owner, fileScope, modifiers, annotations)); } if (value == this.parser.Keywords.CLASS) { return(this.ParseClassDefinition(tokens, owner, fileScope, modifiers, annotations)); } if (value == this.parser.Keywords.ENUM) { return(this.ParseEnumDefinition(tokens, owner, fileScope, modifiers, annotations)); } if (value == this.parser.Keywords.CONSTRUCTOR && owner is ClassDefinition) { return(this.ParseConstructor(tokens, (ClassDefinition)owner, modifiers, annotations)); } FunctionDefinition nullableFunctionDef = this.MaybeParseFunctionDefinition(tokens, owner, fileScope, annotations, modifiers); if (nullableFunctionDef != null) { return(nullableFunctionDef); } Token token = tokens.Peek(); throw ParserException.ThrowException( this.parser.CurrentLocale, ErrorMessages.UNEXPECTED_TOKEN_NO_SPECIFIC_EXPECTATIONS, token, token.Value); }
private Expression ParseEntityWithoutSuffixChain(TokenStream tokens, Node owner) { tokens.EnsureNotEof(); Token nextToken = tokens.Peek(); string next = nextToken.Value; if (next == this.parser.Keywords.NULL) { return(new NullConstant(tokens.Pop(), owner)); } if (next == this.parser.Keywords.TRUE) { return(new BooleanConstant(tokens.Pop(), true, owner)); } if (next == this.parser.Keywords.FALSE) { return(new BooleanConstant(tokens.Pop(), false, owner)); } if (next == this.parser.Keywords.THIS) { return(new ThisKeyword(tokens.Pop(), owner)); } if (next == this.parser.Keywords.BASE) { return(new BaseKeyword(tokens.Pop(), owner)); } Token peekToken = tokens.Peek(); if (next.StartsWith("'")) { return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner)); } if (next.StartsWith("\"")) { return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner)); } if (next == "@") // Raw strings (no escape sequences, a backslash is a literal backslash) { Token atToken = tokens.Pop(); Token stringToken = tokens.Pop(); char stringTokenChar = stringToken.Value[0]; if (stringTokenChar != '"' && stringTokenChar != '\'') { throw new ParserException(atToken, "Unexpected token: '@'"); } string stringValue = stringToken.Value.Substring(1, stringToken.Value.Length - 2); return(new StringConstant(atToken, stringValue, owner)); } if (next == this.parser.Keywords.NEW) { return(this.ParseInstantiate(tokens, owner)); } char firstChar = next[0]; if (nextToken.Type == TokenType.WORD) { Token varToken = tokens.Pop(); if (tokens.IsNext("=>")) { return(this.ParseLambda( tokens, varToken, new AType[] { AType.Any() }, new Token[] { varToken }, owner)); } else { return(new Variable(varToken, varToken.Value, owner)); } } if (firstChar == '[' && nextToken.File.CompilationScope.IsCrayon) { Token bracketToken = tokens.PopExpected("["); List <Expression> elements = new List <Expression>(); bool previousHasCommaOrFirst = true; while (!tokens.PopIfPresent("]")) { if (!previousHasCommaOrFirst) { tokens.PopExpected("]"); // throws appropriate error } elements.Add(Parse(tokens, owner)); previousHasCommaOrFirst = tokens.PopIfPresent(","); } return(new ListDefinition(bracketToken, elements, AType.Any(), owner, false, null)); } if (firstChar == '{' && nextToken.File.CompilationScope.IsCrayon) { Token braceToken = tokens.PopExpected("{"); List <Expression> keys = new List <Expression>(); List <Expression> values = new List <Expression>(); bool previousHasCommaOrFirst = true; while (!tokens.PopIfPresent("}")) { if (!previousHasCommaOrFirst) { tokens.PopExpected("}"); // throws appropriate error } keys.Add(Parse(tokens, owner)); tokens.PopExpected(":"); values.Add(Parse(tokens, owner)); previousHasCommaOrFirst = tokens.PopIfPresent(","); } return(new DictionaryDefinition(braceToken, AType.Any(), AType.Any(), keys, values, owner)); } if (nextToken.Type == TokenType.NUMBER) { if (next.Contains(".")) { double floatValue; if (double.TryParse(next, out floatValue)) { return(new FloatConstant(tokens.Pop(), floatValue, owner)); } throw new ParserException(nextToken, "Invalid float literal."); } return(new IntegerConstant( tokens.Pop(), IntegerConstant.ParseIntConstant(nextToken, next), owner)); } throw new ParserException(tokens.Peek(), "Encountered unexpected token: '" + tokens.PeekValue() + "'"); }