private static Executable ParseStruct(TokenStream tokens, Executable owner) { Token structToken = tokens.PopExpected("struct"); Token structNameToken = tokens.Pop(); Parser.VerifyIdentifier(structNameToken); tokens.PopExpected("{"); List <Token> fieldTokens = new List <Token>(); List <Annotation> typeAnnotations = new List <Annotation>(); bool nextForbidden = false; while (!tokens.PopIfPresent("}")) { if (nextForbidden) { tokens.PopExpected("}"); // crash } Annotation annotation = tokens.IsNext("@") ? AnnotationParser.ParseAnnotation(tokens) : null; Token fieldToken = tokens.Pop(); Parser.VerifyIdentifier(fieldToken); nextForbidden = !tokens.PopIfPresent(","); fieldTokens.Add(fieldToken); typeAnnotations.Add(annotation); } return(new StructDefinition(structToken, structNameToken, fieldTokens, typeAnnotations, owner)); }
private static Executable ParseEnumDefinition(Parser parser, TokenStream tokens, Executable owner) { Token enumToken = tokens.PopExpected("enum"); Token nameToken = tokens.Pop(); Parser.VerifyIdentifier(nameToken); string name = nameToken.Value; tokens.PopExpected("{"); bool nextForbidden = false; List <Token> items = new List <Token>(); List <Expression> values = new List <Expression>(); while (!tokens.PopIfPresent("}")) { if (nextForbidden) { tokens.PopExpected("}"); // crash } Token enumItem = tokens.Pop(); Parser.VerifyIdentifier(enumItem); if (tokens.PopIfPresent("=")) { values.Add(ExpressionParser.Parse(tokens, owner)); } else { values.Add(null); } nextForbidden = !tokens.PopIfPresent(","); items.Add(enumItem); } return(new EnumDefinition(enumToken, nameToken, parser.CurrentNamespace, items, values, owner)); }
public Annotation ParseAnnotation(TokenStream tokens) { Token annotationToken = tokens.PopExpected("@"); Token typeToken = tokens.Pop(); // TODO: refactor this. All built-in annotations should be exempt from the VerifyIdentifier check in an extensible way. if (typeToken.Value != this.parser.Keywords.PRIVATE) { parser.VerifyIdentifier(typeToken); } List <Expression> args = new List <Expression>(); if (tokens.PopIfPresent("(")) { while (!tokens.PopIfPresent(")")) { if (args.Count > 0) { tokens.PopExpected(","); } args.Add(this.parser.ExpressionParser.Parse(tokens, null)); } } return(new Annotation(annotationToken, typeToken, args)); }
private static Executable ParseConstructor(Parser parser, TokenStream tokens, Executable owner) { Token constructorToken = tokens.PopExpected("constructor"); tokens.PopExpected("("); List <Token> argNames = new List <Token>(); List <Expression> argValues = new List <Expression>(); bool optionalArgFound = false; while (!tokens.PopIfPresent(")")) { if (argNames.Count > 0) { tokens.PopExpected(","); } Token argName = tokens.Pop(); Parser.VerifyIdentifier(argName); Expression defaultValue = null; if (tokens.PopIfPresent("=")) { defaultValue = ExpressionParser.Parse(tokens, owner); optionalArgFound = true; } else if (optionalArgFound) { throw new ParserException(argName, "All optional arguments must come at the end of the argument list."); } argNames.Add(argName); argValues.Add(defaultValue); } List <Expression> baseArgs = new List <Expression>(); Token baseToken = null; if (tokens.PopIfPresent(":")) { baseToken = tokens.PopExpected("base"); tokens.PopExpected("("); while (!tokens.PopIfPresent(")")) { if (baseArgs.Count > 0) { tokens.PopExpected(","); } baseArgs.Add(ExpressionParser.Parse(tokens, owner)); } } IList <Executable> code = Parser.ParseBlock(parser, tokens, true, owner); return(new ConstructorDefinition(constructorToken, argNames, argValues, baseArgs, code, baseToken, owner)); }
private static string PopClassName(TokenStream tokens, Token firstToken) { Parser.VerifyIdentifier(firstToken); string name = firstToken.Value; while (tokens.PopIfPresent(".")) { Token nameNext = tokens.Pop(); Parser.VerifyIdentifier(nameNext); name += "." + nameNext.Value; } return(name); }
private static Executable ParseConst(Parser parser, TokenStream tokens, Executable owner) { Token constToken = tokens.PopExpected("const"); Token nameToken = tokens.Pop(); Parser.VerifyIdentifier(nameToken); tokens.PopExpected("="); Expression expression = ExpressionParser.Parse(tokens, owner); tokens.PopExpected(";"); return(new ConstStatement(constToken, nameToken, parser.CurrentNamespace, expression, owner)); }
private static Executable ParseNamespace(Parser parser, TokenStream tokens, Executable owner) { Token namespaceToken = tokens.PopExpected("namespace"); Token first = tokens.Pop(); Parser.VerifyIdentifier(first); List <Token> namespacePieces = new List <Token>() { first }; while (tokens.PopIfPresent(".")) { Token nsToken = tokens.Pop(); Parser.VerifyIdentifier(nsToken); namespacePieces.Add(nsToken); } string name = string.Join(".", namespacePieces.Select <Token, string>(t => t.Value)); parser.PushNamespacePrefix(name); Namespace namespaceInstance = new Namespace(namespaceToken, name, owner); tokens.PopExpected("{"); List <Executable> namespaceMembers = new List <Executable>(); while (!tokens.PopIfPresent("}")) { Executable executable = ExecutableParser.Parse(parser, tokens, false, false, true, namespaceInstance); if (executable is FunctionDefinition || executable is ClassDefinition || executable is EnumDefinition || executable is ConstStatement || executable is Namespace) { namespaceMembers.Add(executable); } else { throw new ParserException(executable.FirstToken, "Only function, class, and nested namespace declarations may exist as direct members of a namespace."); } } namespaceInstance.Code = namespaceMembers.ToArray(); parser.PopNamespacePrefix(); return(namespaceInstance); }
private static FieldDeclaration ParseField(TokenStream tokens, ClassDefinition owner) { bool isStatic = tokens.PopIfPresent("static"); Token fieldToken = tokens.PopExpected("field"); Token nameToken = tokens.Pop(); Parser.VerifyIdentifier(nameToken); FieldDeclaration fd = new FieldDeclaration(fieldToken, nameToken, owner, isStatic); if (tokens.PopIfPresent("=")) { fd.DefaultValue = ExpressionParser.Parse(tokens, owner); } tokens.PopExpected(";"); return(fd); }
public static Annotation ParseAnnotation(TokenStream tokens) { Token annotationToken = tokens.PopExpected("@"); Token typeToken = tokens.Pop(); Parser.VerifyIdentifier(typeToken); List <Expression> args = new List <Expression>(); if (tokens.PopIfPresent("(")) { while (!tokens.PopIfPresent(")")) { if (args.Count > 0) { tokens.PopExpected(","); } args.Add(ExpressionParser.Parse(tokens, null)); } } return(new Annotation(annotationToken, typeToken, args)); }
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 static Expression ParseEntity(TokenStream tokens, Executable owner) { Expression root; if (tokens.PopIfPresent("(")) { root = Parse(tokens, owner); tokens.PopExpected(")"); } else { root = ParseEntityWithoutSuffixChain(tokens, owner); } bool anySuffixes = true; while (anySuffixes) { if (tokens.IsNext(".")) { Token dotToken = tokens.Pop(); Token stepToken = tokens.Pop(); Parser.VerifyIdentifier(stepToken); root = new DotStep(root, dotToken, stepToken, owner); } else if (tokens.IsNext("[")) { Token openBracket = tokens.Pop(); List <Expression> sliceComponents = new List <Expression>(); if (tokens.IsNext(":")) { sliceComponents.Add(null); } else { sliceComponents.Add(Parse(tokens, owner)); } for (int i = 0; i < 2; ++i) { if (tokens.PopIfPresent(":")) { if (tokens.IsNext(":") || tokens.IsNext("]")) { sliceComponents.Add(null); } else { sliceComponents.Add(Parse(tokens, owner)); } } } tokens.PopExpected("]"); if (sliceComponents.Count == 1) { Expression index = sliceComponents[0]; root = new BracketIndex(root, openBracket, index, owner); } else { root = new ListSlice(root, sliceComponents, openBracket, owner); } } else if (tokens.IsNext("(")) { Token openParen = tokens.Pop(); List <Expression> args = new List <Expression>(); while (!tokens.PopIfPresent(")")) { if (args.Count > 0) { tokens.PopExpected(","); } args.Add(Parse(tokens, owner)); } root = new FunctionCall(root, openParen, args, owner); } else if (tokens.IsNext("is")) { Token isToken = tokens.Pop(); Token classToken = tokens.Pop(); string className = PopClassName(tokens, classToken); root = new IsComparison(root, isToken, classToken, className, owner); } else { anySuffixes = false; } } return(root); }
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 ParseFunction(Parser parser, TokenStream tokens, Executable nullableOwner) { bool isStatic = nullableOwner != null && nullableOwner is ClassDefinition && tokens.PopIfPresent("static"); Token functionToken = tokens.PopExpected("function"); List <Annotation> functionAnnotations = new List <Annotation>(); while (tokens.IsNext("@")) { functionAnnotations.Add(AnnotationParser.ParseAnnotation(tokens)); } Token functionNameToken = tokens.Pop(); Parser.VerifyIdentifier(functionNameToken); FunctionDefinition fd = new FunctionDefinition(functionToken, nullableOwner, isStatic, functionNameToken, functionAnnotations, parser.CurrentNamespace); tokens.PopExpected("("); List <Token> argNames = new List <Token>(); List <Expression> defaultValues = new List <Expression>(); List <Annotation> argAnnotations = new List <Annotation>(); bool optionalArgFound = false; while (!tokens.PopIfPresent(")")) { if (argNames.Count > 0) { tokens.PopExpected(","); } Annotation annotation = tokens.IsNext("@") ? AnnotationParser.ParseAnnotation(tokens) : null; Token argName = tokens.Pop(); Expression defaultValue = null; Parser.VerifyIdentifier(argName); if (tokens.PopIfPresent("=")) { optionalArgFound = true; defaultValue = ExpressionParser.Parse(tokens, fd); } else if (optionalArgFound) { throw new ParserException(argName, "All optional arguments must come at the end of the argument list."); } argAnnotations.Add(annotation); argNames.Add(argName); defaultValues.Add(defaultValue); } IList <Executable> code = Parser.ParseBlock(parser, tokens, true, fd); fd.ArgNames = argNames.ToArray(); fd.DefaultValues = defaultValues.ToArray(); fd.ArgAnnotations = argAnnotations.ToArray(); fd.Code = code.ToArray(); return(fd); }
private static Executable ParseClassDefinition(Parser parser, TokenStream tokens, Executable owner, Token staticToken, Token finalToken) { Token classToken = tokens.PopExpected("class"); Token classNameToken = tokens.Pop(); Parser.VerifyIdentifier(classNameToken); List <Token> baseClassTokens = new List <Token>(); List <string> baseClassStrings = new List <string>(); if (tokens.PopIfPresent(":")) { if (baseClassTokens.Count > 0) { tokens.PopExpected(","); } Token baseClassToken = tokens.Pop(); string baseClassName = baseClassToken.Value; Parser.VerifyIdentifier(baseClassToken); while (tokens.PopIfPresent(".")) { Token baseClassTokenNext = tokens.Pop(); Parser.VerifyIdentifier(baseClassTokenNext); baseClassName += "." + baseClassTokenNext.Value; } baseClassTokens.Add(baseClassToken); baseClassStrings.Add(baseClassName); } ClassDefinition cd = new ClassDefinition( classToken, classNameToken, baseClassTokens, baseClassStrings, parser.CurrentNamespace, owner, staticToken, finalToken); tokens.PopExpected("{"); List <FunctionDefinition> methods = new List <FunctionDefinition>(); List <FieldDeclaration> fields = new List <FieldDeclaration>(); ConstructorDefinition constructorDef = null; ConstructorDefinition staticConstructorDef = null; while (!tokens.PopIfPresent("}")) { Dictionary <string, List <Annotation> > annotations = null; while (tokens.IsNext("@")) { annotations = annotations ?? new Dictionary <string, List <Annotation> >(); Annotation annotation = AnnotationParser.ParseAnnotation(tokens); if (!annotations.ContainsKey(annotation.Type)) { annotations[annotation.Type] = new List <Annotation>(); } annotations[annotation.Type].Add(annotation); } if (tokens.IsNext("function") || tokens.AreNext("static", "function")) { methods.Add((FunctionDefinition)ExecutableParser.ParseFunction(parser, tokens, cd)); } else if (tokens.IsNext("constructor")) { if (constructorDef != null) { throw new ParserException(tokens.Pop(), "Multiple constructors are not allowed. Use optional arguments."); } constructorDef = (ConstructorDefinition)ExecutableParser.ParseConstructor(parser, tokens, cd); if (annotations != null && annotations.ContainsKey("private")) { constructorDef.PrivateAnnotation = annotations["private"][0]; annotations["private"].RemoveAt(0); } } else if (tokens.AreNext("static", "constructor")) { tokens.Pop(); // static token if (staticConstructorDef != null) { throw new ParserException(tokens.Pop(), "Multiple static constructors are not allowed."); } staticConstructorDef = (ConstructorDefinition)ExecutableParser.ParseConstructor(parser, tokens, cd); } else if (tokens.IsNext("field") || tokens.AreNext("static", "field")) { fields.Add(ExecutableParser.ParseField(tokens, cd)); } else { tokens.PopExpected("}"); } if (annotations != null) { foreach (List <Annotation> annotationsOfType in annotations.Values) { if (annotationsOfType.Count > 0) { throw new ParserException(annotationsOfType[0].FirstToken, "Unused or extra annotation."); } } } } cd.Methods = methods.ToArray(); cd.Constructor = constructorDef; cd.StaticConstructor = staticConstructorDef; cd.Fields = fields.ToArray(); return(cd); }
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)); }