public TopLevelConstruct ParseTopLevel( TokenStream tokens, TopLevelConstruct owner, FileScope fileScope) { string value = tokens.PeekValue(); 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.ENUM) { return(this.ParseEnumDefinition(tokens, owner, fileScope)); } if (value == this.parser.Keywords.NAMESPACE) { return(this.ParseNamespace(tokens, owner, fileScope)); } if (value == this.parser.Keywords.CONST) { return(this.ParseConst(tokens, owner, fileScope)); } if (value == this.parser.Keywords.FUNCTION) { return(this.ParseFunction(tokens, owner, fileScope)); } if (value == this.parser.Keywords.CLASS) { return(this.ParseClassDefinition(tokens, owner, staticToken, finalToken, fileScope)); } if (value == this.parser.Keywords.ENUM) { return(this.ParseEnumDefinition(tokens, owner, fileScope)); } if (value == this.parser.Keywords.CONSTRUCTOR) { return(this.ParseConstructor(tokens, owner)); } throw new ParserException(tokens.Peek(), "Unrecognized token."); }
private Executable ParseSwitch(TokenStream tokens, TopLevelConstruct owner) { Token switchToken = tokens.PopExpected(this.parser.Keywords.SWITCH); Expression explicitMax = null; Token explicitMaxToken = null; if (tokens.IsNext("{")) { explicitMaxToken = tokens.Pop(); explicitMax = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected("}"); } tokens.PopExpected("("); Expression condition = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); tokens.PopExpected("{"); List <List <Expression> > cases = new List <List <Expression> >(); List <Token> firstTokens = new List <Token>(); List <List <Executable> > code = new List <List <Executable> >(); char state = '?'; // ? - first, O - code, A - case bool defaultEncountered = false; while (!tokens.PopIfPresent("}")) { if (tokens.IsNext(this.parser.Keywords.CASE)) { if (defaultEncountered) { throw new ParserException(tokens.Peek(), "default condition in a switch statement must be the last condition."); } Token caseToken = tokens.PopExpected(this.parser.Keywords.CASE); if (state != 'A') { cases.Add(new List <Expression>()); firstTokens.Add(caseToken); code.Add(null); state = 'A'; } cases[cases.Count - 1].Add(this.parser.ExpressionParser.Parse(tokens, owner)); tokens.PopExpected(":"); } else if (tokens.IsNext(this.parser.Keywords.DEFAULT)) { Token defaultToken = tokens.PopExpected(this.parser.Keywords.DEFAULT); if (state != 'A') { cases.Add(new List <Expression>()); firstTokens.Add(defaultToken); code.Add(null); state = 'A'; } cases[cases.Count - 1].Add(null); tokens.PopExpected(":"); defaultEncountered = true; } else { if (state != 'O') { cases.Add(null); firstTokens.Add(null); code.Add(new List <Executable>()); state = 'O'; } code[code.Count - 1].Add(this.parser.ExecutableParser.Parse(tokens, false, true, owner)); } } return(new SwitchStatement(switchToken, condition, firstTokens, cases, code, explicitMax, explicitMaxToken, owner)); }
private static Expression ParseEntityWithoutSuffixChain(TokenStream tokens, Executable owner) { string next = tokens.PeekValue(); if (next == "null") { return(new NullConstant(tokens.Pop(), owner)); } if (next == "true") { return(new BooleanConstant(tokens.Pop(), true, owner)); } if (next == "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 == "new") { return(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 (Parser.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 (!Parser.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 || !Parser.IsInteger(postDecimal.Value)) { throw new ParserException(dotToken, "Unexpected dot."); } numberValue += postDecimal.Value; double floatValue; if (double.TryParse(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 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 new ParserException(tokens.Peek(), "Imports can only be made from the root of a file and cannot be nested inside other constructs."); } 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)); }
public Executable Parse( TokenStream tokens, bool simpleOnly, bool semicolonPresent, bool isRoot, Executable owner) { string value = tokens.PeekValue(); if (!simpleOnly) { 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 (!isRoot && (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) { Token importToken = tokens.PopExpected(parser.Keywords.IMPORT); if (!isRoot) { throw new ParserException(tokens.Peek(), "Imports can only be made from the root of a file and cannot be nested inside other constructs."); } 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)); } if (value == this.parser.Keywords.ENUM) { if (!isRoot) { throw new ParserException(tokens.Peek(), "Enums can only be defined from the root of a file and cannot be nested inside functions/loops/etc."); } return(this.ParseEnumDefinition(tokens, owner)); } if (value == this.parser.Keywords.NAMESPACE) { if (!isRoot) { throw new ParserException(tokens.Peek(), "Namespace declarations cannot be nested in other constructs."); } return(this.ParseNamespace(tokens, owner)); } if (value == this.parser.Keywords.CONST) { return(this.ParseConst(tokens, owner)); } if (value == this.parser.Keywords.FUNCTION) { return(this.ParseFunction(tokens, owner)); } if (value == this.parser.Keywords.CLASS) { return(this.ParseClassDefinition(tokens, owner, staticToken, finalToken)); } if (value == this.parser.Keywords.ENUM) { return(this.ParseEnumDefinition(tokens, owner)); } 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.CONSTRUCTOR) { return(this.ParseConstructor(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 static Executable ParseSwitch(Parser parser, TokenStream tokens, Executable owner) { Token switchToken = tokens.PopExpected("switch"); Expression explicitMax = null; Token explicitMaxToken = null; if (tokens.IsNext("{")) { explicitMaxToken = tokens.Pop(); explicitMax = ExpressionParser.Parse(tokens, owner); tokens.PopExpected("}"); } tokens.PopExpected("("); Expression condition = ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); tokens.PopExpected("{"); List<List<Expression>> cases = new List<List<Expression>>(); List<Token> firstTokens = new List<Token>(); List<List<Executable>> code = new List<List<Executable>>(); char state = '?'; // ? - first, O - code, A - case bool defaultEncountered = false; while (!tokens.PopIfPresent("}")) { if (tokens.IsNext("case")) { if (defaultEncountered) { throw new ParserException(tokens.Peek(), "default condition in a switch statement must be the last condition."); } Token caseToken = tokens.PopExpected("case"); if (state != 'A') { cases.Add(new List<Expression>()); firstTokens.Add(caseToken); code.Add(null); state = 'A'; } cases[cases.Count - 1].Add(ExpressionParser.Parse(tokens, owner)); tokens.PopExpected(":"); } else if (tokens.IsNext("default")) { Token defaultToken = tokens.PopExpected("default"); if (state != 'A') { cases.Add(new List<Expression>()); firstTokens.Add(defaultToken); code.Add(null); state = 'A'; } cases[cases.Count - 1].Add(null); tokens.PopExpected(":"); defaultEncountered = true; } else { if (state != 'O') { cases.Add(null); firstTokens.Add(null); code.Add(new List<Executable>()); state = 'O'; } code[code.Count - 1].Add(ExecutableParser.Parse(parser, tokens, false, true, false, owner)); } } return new SwitchStatement(switchToken, condition, firstTokens, cases, code, explicitMax, explicitMaxToken, owner); }
public static Executable Parse(Parser parser, TokenStream tokens, bool simpleOnly, bool semicolonPresent, bool isRoot, Executable owner) { string value = tokens.PeekValue(); if (!simpleOnly) { if (parser.IsTranslateMode && value == "struct") { if (!isRoot) { throw new ParserException(tokens.Peek(), "structs cannot be nested into any other construct."); } // struct is special. If you are not compiling in JS mode, if (Parser.IsValidIdentifier(tokens.PeekValue(1)) && tokens.PeekValue(2) == "{") { return ParseStruct(tokens, owner); } } if (!isRoot && (value == "function" || value == "class")) { throw new ParserException(tokens.Peek(), (value == "function" ? "Function" : "Class") + " definition cannot be nested in another construct."); } if (value == "import") { Token importToken = tokens.PopExpected("import"); bool inline = parser.IsTranslateMode && tokens.PopIfPresent("inline"); if (inline) { Token fileToken = tokens.Pop(); char c = fileToken.Value[0]; if (c != '\'' && c != '"') throw new ParserException(fileToken, "Inline imports are supposed to be strings."); tokens.PopExpected(";"); string inlineImportFileName = fileToken.Value.Substring(1, fileToken.Value.Length - 2); string inlineImportFileContents = Util.ReadFileInternally(inlineImportFileName); // TODO: Anti-pattern alert. Clean this up. if (inlineImportFileContents.Contains("%%%")) { Dictionary<string, string> replacements = parser.NullablePlatform.InterpreterCompiler.BuildReplacementsDictionary(); inlineImportFileContents = Constants.DoReplacements(inlineImportFileContents, replacements); } TokenStream inlineTokens = Tokenizer.Tokenize(inlineImportFileName, inlineImportFileContents, 0, true); // OMGHAX - insert the inline import into the current token stream. tokens.InsertTokens(inlineTokens); return ExecutableParser.Parse(parser, tokens, simpleOnly, semicolonPresent, isRoot, owner); // start exectuable parser anew. } if (!isRoot) { throw new ParserException(tokens.Peek(), "Imports can only be made from the root of a file and cannot be nested inside other constructs."); } 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); } if (value == "enum") { if (!isRoot) { throw new ParserException(tokens.Peek(), "Enums can only be defined from the root of a file and cannot be nested inside functions/loops/etc."); } return ParseEnumDefinition(parser, tokens, owner); } if (value == "namespace") { if (!isRoot) { throw new ParserException(tokens.Peek(), "Namespace declarations cannot be nested in other constructs."); } } switch (value) { case "namespace": return ParseNamespace(parser, tokens, owner); case "function": return ParseFunction(parser, tokens, owner); case "class": return ParseClassDefinition(parser, tokens, owner); case "enum": return ParseEnumDefinition(parser, tokens, owner); case "for": return ParseFor(parser, tokens, owner); case "while": return ParseWhile(parser, tokens, owner); case "do": return ParseDoWhile(parser, tokens, owner); case "switch": return ParseSwitch(parser, tokens, owner); case "if": return ParseIf(parser, tokens, owner); case "try": return ParseTry(parser, tokens, owner); case "return": return ParseReturn(tokens, owner); case "break": return ParseBreak(tokens, owner); case "continue": return ParseContinue(tokens, owner); case "const": return ParseConst(parser, tokens, owner); case "constructor": return ParseConstructor(parser, tokens, owner); default: break; } } Expression expr = ExpressionParser.Parse(tokens, owner); value = tokens.PeekValue(); if (ASSIGNMENT_OPS.Contains(value)) { Token assignment = tokens.Pop(); Expression assignmentValue = 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); }
public static Executable Parse(Parser parser, TokenStream tokens, bool simpleOnly, bool semicolonPresent, bool isRoot, Executable owner) { string value = tokens.PeekValue(); if (!simpleOnly) { Token staticToken = null; Token finalToken = null; while (value == "static" || value == "final") { if (value == "static" && staticToken == null) { staticToken = tokens.Pop(); value = tokens.PeekValue(); } if (value == "final" && finalToken == null) { finalToken = tokens.Pop(); value = tokens.PeekValue(); } } if (staticToken != null || finalToken != null) { if (value != "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 (!isRoot && (value == "function" || value == "class")) { throw new ParserException(tokens.Peek(), (value == "function" ? "Function" : "Class") + " definition cannot be nested in another construct."); } if (parser.IsTranslateMode && value == "struct") { if (!isRoot) { throw new ParserException(tokens.Peek(), "structs cannot be nested into any other construct."); } return(ParseStruct(tokens, owner)); } if (value == "import") { Token importToken = tokens.PopExpected("import"); bool inline = parser.IsTranslateMode && tokens.PopIfPresent("inline"); if (inline) { Token fileToken = tokens.Pop(); char c = fileToken.Value[0]; if (c != '\'' && c != '"') { throw new ParserException(fileToken, "Inline imports are supposed to be strings."); } tokens.PopExpected(";"); string inlineImportFileName = fileToken.Value.Substring(1, fileToken.Value.Length - 2); string inlineImportFileContents; if (inlineImportFileName.StartsWith("LIB:")) { string[] parts = inlineImportFileName.Split(':'); string libraryName = parts[1]; string filename = FileUtil.JoinPath(parts[2].Split('/')); Library library = parser.SystemLibraryManager.GetLibraryFromKey(libraryName.ToLower()); inlineImportFileContents = library.ReadFile(filename, false); } else { inlineImportFileContents = Util.ReadInterpreterFileInternally(inlineImportFileName); } // TODO: Anti-pattern alert. Clean this up. if (inlineImportFileContents.Contains("%%%")) { Dictionary <string, string> replacements = parser.NullablePlatform.InterpreterCompiler.BuildReplacementsDictionary(); inlineImportFileContents = Constants.DoReplacements(inlineImportFileContents, replacements); } Token[] inlineTokens = Tokenizer.Tokenize(inlineImportFileName, inlineImportFileContents, 0, true); tokens.InsertTokens(inlineTokens); return(ExecutableParser.Parse(parser, tokens, simpleOnly, semicolonPresent, isRoot, owner)); // start exectuable parser anew. } if (!isRoot) { throw new ParserException(tokens.Peek(), "Imports can only be made from the root of a file and cannot be nested inside other constructs."); } 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)); } if (value == "enum") { if (!isRoot) { throw new ParserException(tokens.Peek(), "Enums can only be defined from the root of a file and cannot be nested inside functions/loops/etc."); } return(ParseEnumDefinition(parser, tokens, owner)); } if (value == "namespace") { if (!isRoot) { throw new ParserException(tokens.Peek(), "Namespace declarations cannot be nested in other constructs."); } } switch (value) { case "namespace": return(ParseNamespace(parser, tokens, owner)); case "function": return(ParseFunction(parser, tokens, owner)); case "class": return(ParseClassDefinition(parser, tokens, owner, staticToken, finalToken)); case "enum": return(ParseEnumDefinition(parser, tokens, owner)); case "for": return(ParseFor(parser, tokens, owner)); case "while": return(ParseWhile(parser, tokens, owner)); case "do": return(ParseDoWhile(parser, tokens, owner)); case "switch": return(ParseSwitch(parser, tokens, owner)); case "if": return(ParseIf(parser, tokens, owner)); case "try": return(ParseTry(parser, tokens, owner)); case "return": return(ParseReturn(tokens, owner)); case "break": return(ParseBreak(tokens, owner)); case "continue": return(ParseContinue(tokens, owner)); case "const": return(ParseConst(parser, tokens, owner)); case "constructor": return(ParseConstructor(parser, tokens, owner)); default: break; } } Expression expr = ExpressionParser.Parse(tokens, owner); value = tokens.PeekValue(); if (ASSIGNMENT_OPS.Contains(value)) { Token assignment = tokens.Pop(); Expression assignmentValue = 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 static Expression ParseEntityWithoutSuffixChain(TokenStream tokens, Executable owner) { string next = tokens.PeekValue(); if (next == "null") return new NullConstant(tokens.Pop(), owner); if (next == "true") return new BooleanConstant(tokens.Pop(), true, owner); if (next == "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 == "new") return 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 (Parser.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 (!Parser.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 || !Parser.IsInteger(postDecimal.Value)) { throw new ParserException(dotToken, "Unexpected dot."); } numberValue += postDecimal.Value; double floatValue; if (double.TryParse(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() + "'"); }