private Executable ParseContinue(TokenStream tokens, TopLevelConstruct owner) { Token continueToken = tokens.PopExpected(this.parser.Keywords.CONTINUE); tokens.PopExpected(";"); return(new ContinueStatement(continueToken, owner)); }
private 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); } Annotation annotation = new Annotation(annotationToken, 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, annotation)); } } annotation.SetArgs(args); return(annotation); }
protected ForLoopComponents ParseForLoopComponents(TokenStream tokens, Node owner) { 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)); } return(new ForLoopComponents() { Init = init, Condition = condition, Step = step }); }
protected Executable ParseFor(TokenStream tokens, Node owner) { Token forToken = tokens.PopExpected(this.parser.Keywords.FOR); tokens.PopExpected("("); tokens.EnsureNotEof(); if (this.IsForEachLoopParenthesisContents(tokens)) { Pair <AType, Token> iteratorVariable = this.ParseForEachLoopIteratorVariable(tokens, owner); AType iteratorVariableType = iteratorVariable.First; Token iteratorToken = iteratorVariable.Second; tokens.PopExpected(":"); Expression iterationExpression = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); IList <Executable> body = this.ParseBlock(tokens, false, owner); return(new ForEachLoop(forToken, iteratorVariableType, iteratorVariable.Second, iterationExpression, body, owner)); } else { ForLoopComponents parts = this.ParseForLoopComponents(tokens, owner); IList <Executable> body = this.ParseBlock(tokens, false, owner); return(new ForLoop(forToken, parts.Init, parts.Condition, parts.Step, body, owner)); } }
private Executable ParseBreak(TokenStream tokens, TopLevelConstruct owner) { Token breakToken = tokens.PopExpected(this.parser.Keywords.BREAK); tokens.PopExpected(";"); return(new BreakStatement(breakToken, owner)); }
private Executable ParseThrow(TokenStream tokens, TopLevelConstruct owner) { Token throwToken = tokens.PopExpected(this.parser.Keywords.THROW); Expression throwExpression = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected(";"); return(new ThrowStatement(throwToken, throwExpression, owner)); }
private FunctionDefinition ParseFunction( TokenStream tokens, TopLevelConstruct nullableOwner, FileScope fileScope, AnnotationCollection annotations) { bool isStatic = nullableOwner != null && nullableOwner is ClassDefinition && tokens.PopIfPresent(this.parser.Keywords.STATIC); Token functionToken = tokens.PopExpected(this.parser.Keywords.FUNCTION); Token functionNameToken = tokens.Pop(); this.parser.VerifyIdentifier(functionNameToken); FunctionDefinition fd = new FunctionDefinition(functionToken, parser.CurrentLibrary, nullableOwner, isStatic, functionNameToken, annotations, fileScope); tokens.PopExpected("("); List <Token> argNames = new List <Token>(); List <Expression> defaultValues = new List <Expression>(); bool optionalArgFound = false; while (!tokens.PopIfPresent(")")) { if (argNames.Count > 0) { tokens.PopExpected(","); } Token argName = tokens.Pop(); Expression defaultValue = null; this.parser.VerifyIdentifier(argName); if (tokens.PopIfPresent("=")) { optionalArgFound = true; defaultValue = this.parser.ExpressionParser.Parse(tokens, fd); } else if (optionalArgFound) { throw new ParserException(argName, "All optional arguments must come at the end of the argument list."); } argNames.Add(argName); defaultValues.Add(defaultValue); } IList <Executable> code = ParserContext.ParseBlock(parser, tokens, true, fd); fd.ArgNames = argNames.ToArray(); fd.DefaultValues = defaultValues.ToArray(); fd.Code = code.ToArray(); return(fd); }
protected virtual Namespace ParseNamespace( TokenStream tokens, Node owner, FileScope fileScope, AnnotationCollection annotations) { Token namespaceToken = tokens.PopExpected(this.parser.Keywords.NAMESPACE); Token first = tokens.Pop(); this.parser.VerifyIdentifier(first); List <Token> namespacePieces = new List <Token>() { first }; string namespaceBuilder = first.Value; parser.RegisterNamespace(namespaceBuilder); while (tokens.PopIfPresent(".")) { Token nsToken = tokens.Pop(); this.parser.VerifyIdentifier(nsToken); namespacePieces.Add(nsToken); namespaceBuilder += "." + nsToken.Value; parser.RegisterNamespace(namespaceBuilder); } string name = string.Join(".", namespacePieces.Select <Token, string>(t => t.Value)); Namespace namespaceInstance = new Namespace(namespaceToken, name, owner, fileScope, ModifierCollection.EMPTY, annotations); tokens.PopExpected("{"); List <TopLevelEntity> namespaceMembers = new List <TopLevelEntity>(); while (!tokens.PopIfPresent("}")) { TopLevelEntity executable = this.Parse(tokens, namespaceInstance, fileScope); if (executable is FunctionDefinition || executable is ClassDefinition || executable is EnumDefinition || executable is ConstDefinition || executable is Namespace) { namespaceMembers.Add(executable); } else { throw new ParserException(executable, "Only function, class, and nested namespace declarations may exist as direct members of a namespace."); } } namespaceInstance.Code = namespaceMembers.ToArray(); return(namespaceInstance); }
private Executable ParseWhile(TokenStream tokens, TopLevelConstruct owner) { Token whileToken = tokens.PopExpected(this.parser.Keywords.WHILE); tokens.PopExpected("("); Expression condition = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); IList <Executable> body = ParserContext.ParseBlock(parser, tokens, false, owner); return(new WhileLoop(whileToken, condition, body, owner)); }
private ConstStatement ParseConst(TokenStream tokens, TopLevelConstruct owner, FileScope fileScope, AnnotationCollection annotations) { Token constToken = tokens.PopExpected(this.parser.Keywords.CONST); Token nameToken = tokens.Pop(); ConstStatement constStatement = new ConstStatement(constToken, nameToken, owner, parser.CurrentLibrary, fileScope, annotations); this.parser.VerifyIdentifier(nameToken); tokens.PopExpected("="); constStatement.Expression = this.parser.ExpressionParser.Parse(tokens, constStatement); tokens.PopExpected(";"); return(constStatement); }
private Executable ParseReturn(TokenStream tokens, TopLevelConstruct owner) { Token returnToken = tokens.PopExpected(this.parser.Keywords.RETURN); Expression expr = null; if (!tokens.PopIfPresent(";")) { expr = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected(";"); } return(new ReturnStatement(returnToken, expr, owner)); }
private Executable ParseDoWhile(TokenStream tokens, TopLevelConstruct owner) { Token doToken = tokens.PopExpected(this.parser.Keywords.DO); IList <Executable> body = ParserContext.ParseBlock(parser, tokens, true, owner); tokens.PopExpected(this.parser.Keywords.DO_WHILE_END); tokens.PopExpected("("); Expression condition = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); tokens.PopExpected(";"); return(new DoWhileLoop(doToken, body, condition, owner)); }
protected IList <Expression> ParseArgumentList(TokenStream tokens, Node owner) { List <Expression> args = new List <Expression>(); tokens.PopExpected("("); while (!tokens.PopIfPresent(")")) { if (args.Count > 0) { tokens.PopExpected(","); } args.Add(Parse(tokens, owner)); } return(args); }
internal virtual IList <Executable> ParseBlock(TokenStream tokens, bool bracketsRequired, Node owner, bool semicolonRequired) { List <Executable> output = new List <Executable>(); if (tokens.PopIfPresent("{")) { while (!tokens.PopIfPresent("}")) { output.Add(this.parser.ExecutableParser.Parse(tokens, false, true, owner)); } } else { if (bracketsRequired) { tokens.PopExpected("{"); // throws with reasonable exception message. } if (tokens.PopIfPresent(";")) { return(output); } output.Add(this.parser.ExecutableParser.Parse(tokens, false, semicolonRequired, owner)); } return(output); }
private FieldDeclaration ParseField(TokenStream tokens, ClassDefinition owner, AnnotationCollection annotations) { bool isStatic = tokens.PopIfPresent(this.parser.Keywords.STATIC); Token fieldToken = tokens.PopExpected(this.parser.Keywords.FIELD); Token nameToken = tokens.Pop(); this.parser.VerifyIdentifier(nameToken); FieldDeclaration fd = new FieldDeclaration(fieldToken, nameToken, owner, isStatic, annotations); if (tokens.PopIfPresent("=")) { fd.DefaultValue = this.parser.ExpressionParser.Parse(tokens, owner); } tokens.PopExpected(";"); return(fd); }
private Expression ParseLambda( TokenStream tokens, Token firstToken, IList <AType> argTypes, IList <Token> args, Node owner) { tokens.PopExpected("=>"); Lambda lambda = new Lambda(firstToken, owner, args, argTypes); IList <Executable> lambdaCode; if (tokens.IsNext("{")) { lambdaCode = this.parser.ExecutableParser.ParseBlock(tokens, false, lambda, false); } else { Expression lambdaBodyExpression = this.parser.ExpressionParser.ParseTernary(tokens, lambda); lambdaCode = new Executable[] { new ExpressionAsExecutable(lambdaBodyExpression, lambda) }; } if (lambdaCode.Count == 1 && lambdaCode[0] is ExpressionAsExecutable) { // If a lambda contains a single expression as its code body, then this is an implicit return statement. ExpressionAsExecutable eae = (ExpressionAsExecutable)lambdaCode[0]; lambdaCode[0] = new ReturnStatement(eae.FirstToken, eae.Expression, lambda); } lambda.Code = lambdaCode.ToArray(); return(lambda); }
internal static IList <Executable> ParseBlock(ParserContext parser, TokenStream tokens, bool bracketsRequired, TopLevelConstruct owner) { List <Executable> output = new List <Executable>(); if (tokens.PopIfPresent("{")) { while (!tokens.PopIfPresent("}")) { output.Add(parser.ExecutableParser.Parse(tokens, false, true, owner)); } } else { if (bracketsRequired) { tokens.PopExpected("{"); // throws with reasonable exception message. } if (tokens.PopIfPresent(";")) { return(output); } output.Add(parser.ExecutableParser.Parse(tokens, false, true, owner)); } return(output); }
protected virtual ConstructorDefinition ParseConstructor( TokenStream tokens, ClassDefinition owner, ModifierCollection modifiers, AnnotationCollection annotations) { Token constructorToken = tokens.PopExpected(this.parser.Keywords.CONSTRUCTOR); ConstructorDefinition ctor = new ConstructorDefinition(constructorToken, modifiers, annotations, owner); tokens.PopExpected("("); List <AType> argTypes = new List <AType>(); List <Token> argNames = new List <Token>(); List <Expression> argValues = new List <Expression>(); this.ParseArgumentListDeclaration(tokens, ctor, argTypes, argNames, argValues); List <Expression> baseArgs = new List <Expression>(); Token baseToken = null; if (tokens.PopIfPresent(":")) { baseToken = tokens.PopExpected(this.parser.Keywords.BASE); tokens.PopExpected("("); while (!tokens.PopIfPresent(")")) { if (baseArgs.Count > 0) { tokens.PopExpected(","); } baseArgs.Add(this.parser.ExpressionParser.Parse(tokens, ctor)); } } IList <Executable> code = this.parser.ExecutableParser.ParseBlock(tokens, true, ctor); ctor.SetArgs(argNames, argValues, argTypes); ctor.SetBaseArgs(baseArgs); ctor.SetCode(code); ctor.BaseToken = baseToken; return(ctor); }
protected virtual EnumDefinition ParseEnumDefinition( TokenStream tokens, Node owner, FileScope fileScope, ModifierCollection modifiers, AnnotationCollection annotations) { Token enumToken = tokens.PopExpected(this.parser.Keywords.ENUM); Token nameToken = tokens.Pop(); this.parser.VerifyIdentifier(nameToken); string name = nameToken.Value; EnumDefinition ed = new EnumDefinition(enumToken, nameToken, owner, fileScope, modifiers, annotations); 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(); this.parser.VerifyIdentifier(enumItem); if (tokens.PopIfPresent("=")) { values.Add(this.parser.ExpressionParser.Parse(tokens, ed)); } else { values.Add(null); } nextForbidden = !tokens.PopIfPresent(","); items.Add(enumItem); } ed.SetItems(items, values); return(ed); }
private Expression ParseInstantiate(TokenStream tokens, TopLevelConstruct owner) { Token newToken = tokens.PopExpected(this.parser.Keywords.NEW); Token classNameToken = tokens.Pop(); string name = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classNameToken); List <Expression> args = new List <Expression>(); tokens.PopExpected("("); while (!tokens.PopIfPresent(")")) { if (args.Count > 0) { tokens.PopExpected(","); } args.Add(Parse(tokens, owner)); } return(new Instantiate(newToken, classNameToken, name, args, owner)); }
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 ForEachLoop ParseForEachCSharp(TokenStream tokens, Node owner) { if (!this.parser.IsCSharpCompat) { throw new System.InvalidOperationException(); } Token foreachToken = tokens.PopExpected("foreach"); tokens.PopExpected("("); AType iteratorVariableType = this.parser.TypeParser.Parse(tokens); Token iteratorVariable = tokens.PopWord(); tokens.PopExpected("in"); Expression listExpr = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); IList <Executable> body = this.ParseBlock(tokens, false, owner); return(new ForEachLoop(foreachToken, iteratorVariableType, iteratorVariable, listExpr, body, owner)); }
private Executable ParseIf(TokenStream tokens, TopLevelConstruct owner) { Token ifToken = tokens.PopExpected(this.parser.Keywords.IF); tokens.PopExpected("("); Expression condition = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); IList <Executable> body = ParserContext.ParseBlock(parser, tokens, false, owner); IList <Executable> elseBody; if (tokens.PopIfPresent(this.parser.Keywords.ELSE)) { elseBody = ParserContext.ParseBlock(parser, tokens, false, owner); } else { elseBody = new Executable[0]; } return(new IfStatement(ifToken, condition, body, elseBody, owner)); }
private ConstructorDefinition ParseConstructor( TokenStream tokens, TopLevelConstruct owner, AnnotationCollection annotations) { Token constructorToken = tokens.PopExpected(this.parser.Keywords.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(); this.parser.VerifyIdentifier(argName); Expression defaultValue = null; if (tokens.PopIfPresent("=")) { defaultValue = this.parser.ExpressionParser.Parse(tokens, owner); optionalArgFound = true; } else if (optionalArgFound) { throw this.parser.GenerateParseError( ErrorMessages.OPTIONAL_ARGUMENT_WAS_NOT_AT_END_OF_ARGUMENT_LIST, argName); } argNames.Add(argName); argValues.Add(defaultValue); } List <Expression> baseArgs = new List <Expression>(); Token baseToken = null; if (tokens.PopIfPresent(":")) { baseToken = tokens.PopExpected(this.parser.Keywords.BASE); tokens.PopExpected("("); while (!tokens.PopIfPresent(")")) { if (baseArgs.Count > 0) { tokens.PopExpected(","); } baseArgs.Add(this.parser.ExpressionParser.Parse(tokens, owner)); } } IList <Executable> code = ParserContext.ParseBlock(parser, tokens, true, owner); return(new ConstructorDefinition(constructorToken, argNames, argValues, baseArgs, code, baseToken, annotations, owner)); }
internal virtual ImportStatement ParseImport(TokenStream tokens, FileScope fileScope) { Token importToken = this.parser.IsCSharpCompat ? tokens.PopExpected(parser.Keywords.IMPORT, "using") : 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, fileScope)); }
private Expression ParseTernary(TokenStream tokens, Node owner) { Expression root = ParseNullCoalescing(tokens, owner); if (tokens.PopIfPresent("?")) { Expression trueExpr = ParseTernary(tokens, owner); tokens.PopExpected(":"); Expression falseExpr = ParseTernary(tokens, owner); return(new Ternary(root, trueExpr, falseExpr, owner)); } return(root); }
protected void ParseArgumentListDeclaration( TokenStream tokens, Node owner, IList <AType> argTypesOut, IList <Token> argNamesOut, IList <Expression> argDefaultValuesOut) { bool optionalArgFound = false; while (!tokens.PopIfPresent(")")) { if (argNamesOut.Count > 0) { tokens.PopExpected(","); } AType argType = this.HasTypes ? this.parser.TypeParser.Parse(tokens) : AType.Any(tokens.Peek()); Token argName = tokens.Pop(); this.parser.VerifyIdentifier(argName); Expression defaultValue = null; if (tokens.PopIfPresent("=")) { defaultValue = this.parser.ExpressionParser.Parse(tokens, owner); optionalArgFound = true; } else if (optionalArgFound) { throw this.parser.GenerateParseError( ErrorMessages.OPTIONAL_ARGUMENT_WAS_NOT_AT_END_OF_ARGUMENT_LIST, argName); } argTypesOut.Add(argType); argNamesOut.Add(argName); argDefaultValuesOut.Add(defaultValue); } }
protected virtual ClassDefinition ParseClassDefinition( TokenStream tokens, Node owner, FileScope fileScope, ModifierCollection modifiers, AnnotationCollection classAnnotations) { Token classToken = tokens.PopExpected(this.parser.Keywords.CLASS); Token classNameToken = tokens.Pop(); if (classNameToken.Type != TokenType.WORD) { throw new ParserException(classNameToken, "This is not a valid class name."); } 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; this.parser.VerifyIdentifier(baseClassToken); while (tokens.PopIfPresent(".")) { Token baseClassTokenNext = tokens.Pop(); this.parser.VerifyIdentifier(baseClassTokenNext); baseClassName += "." + baseClassTokenNext.Value; } baseClassTokens.Add(baseClassToken); baseClassStrings.Add(baseClassName); } ClassDefinition cd = new ClassDefinition( classToken, classNameToken, baseClassTokens, baseClassStrings, owner, fileScope, modifiers, classAnnotations); tokens.PopExpected("{"); List <FunctionDefinition> methods = new List <FunctionDefinition>(); List <FieldDefinition> fields = new List <FieldDefinition>(); List <PropertyDefinition> properties = new List <PropertyDefinition>(); while (!tokens.PopIfPresent("}")) { this.ParseClassMember(tokens, fileScope, cd, methods, fields, properties); } cd.Methods = methods.ToArray(); cd.Fields = fields.ToArray(); if (cd.Constructor == null) { // This should be empty if there is no base class, or just pass along the base class' args if there is. cd.Constructor = new ConstructorDefinition( cd, ModifierCollection.EMPTY, new AnnotationCollection(parser)); if (cd.BaseClassTokens.Length > 0) { cd.Constructor.BaseToken = cd.FirstToken; cd.Constructor.SetBaseArgs(new Expression[0]); } } return(cd); }
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 Executable ParseTry(TokenStream tokens, TopLevelConstruct owner) { Token tryToken = tokens.PopExpected(this.parser.Keywords.TRY); IList <Executable> tryBlock = ParserContext.ParseBlock(parser, tokens, true, owner); List <Token> catchTokens = new List <Token>(); List <string[]> exceptionTypes = new List <string[]>(); List <Token[]> exceptionTypeTokens = new List <Token[]>(); List <Token> exceptionVariables = new List <Token>(); List <Executable[]> catchBlocks = new List <Executable[]>(); Token finallyToken = null; IList <Executable> finallyBlock = null; while (tokens.IsNext(this.parser.Keywords.CATCH)) { /* * Parse patterns: * All exceptions: * 1a: catch { ... } * 1b: catch (e) { ... } * * A certain exception: * 2a: catch (ExceptionName) { ... } * 2b: catch (ExceptionName e) { ... } * * Certain exceptions: * 3a: catch (ExceptionName1 | ExceptionName2) { ... } * 3b: catch (ExceptionName1 | ExceptionName2 e) { ... } * * Non-Context-Free alert: * Note that if the exception variable does not contain a '.' character, 1b and 2a are * ambiguous at parse time. Treat them both as 1b and then if the classname resolution * fails, treat this as a variable. * * This is actually kind of bad because a typo in the classname will not be known. * e.g "catch (Excpetion) {" will compile as a variable called "Excpetion" * * End-user workarounds: * - always use a variable name OR * - always fully qualify exception types e.g. Core.Exception * Long-term plan: * - add warning support and emit warnings for: * - unused variables * - style-breaking uppercase variables. */ Token catchToken = tokens.PopExpected(this.parser.Keywords.CATCH); List <string> classNames = new List <string>(); List <Token> classTokens = new List <Token>(); Token variableToken = null; if (tokens.PopIfPresent("(")) { // This first one might actually be a variable. Assume class for now and sort it out later. // (and by "later" I mean the ResolveNames phase) Token classFirstToken = tokens.Pop(); string className = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classFirstToken); classNames.Add(className); classTokens.Add(classFirstToken); while (tokens.PopIfPresent("|")) { classFirstToken = tokens.Pop(); className = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classFirstToken); classNames.Add(className); classTokens.Add(classFirstToken); } if (!tokens.IsNext(")")) { variableToken = tokens.Pop(); this.parser.VerifyIdentifier(variableToken); } tokens.PopExpected(")"); } else { classNames.Add(null); classTokens.Add(null); } Executable[] catchBlockCode = ParserContext.ParseBlock(parser, tokens, true, owner).ToArray(); catchTokens.Add(catchToken); exceptionTypes.Add(classNames.ToArray()); exceptionTypeTokens.Add(classTokens.ToArray()); exceptionVariables.Add(variableToken); catchBlocks.Add(catchBlockCode); } if (tokens.IsNext(this.parser.Keywords.FINALLY)) { finallyToken = tokens.Pop(); finallyBlock = ParserContext.ParseBlock(parser, tokens, true, owner); } return(new TryStatement(tryToken, tryBlock, catchTokens, exceptionVariables, exceptionTypeTokens, exceptionTypes, catchBlocks, finallyToken, finallyBlock, owner)); }