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 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); }
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)); }
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)); } }
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 ParseIncrement(TokenStream tokens, Node owner) { Expression root; if (tokens.IsNext("++") || tokens.IsNext("--")) { Token incrementToken = tokens.Pop(); root = this.ParseEntity(tokens, owner); return(new Increment(incrementToken, incrementToken, incrementToken.Value == "++", true, root, owner)); } root = this.ParseEntity(tokens, owner); if (tokens.IsNext("++") || tokens.IsNext("--")) { Token incrementToken = tokens.Pop(); return(new Increment(root.FirstToken, incrementToken, incrementToken.Value == "++", false, root, owner)); } return(root); }
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 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 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); }
public string PopClassNameWithFirstTokenAlreadyPopped(TokenStream tokens, Token firstToken) { this.VerifyIdentifier(firstToken); string name = firstToken.Value; while (tokens.PopIfPresent(".")) { Token nameNext = tokens.Pop(); this.VerifyIdentifier(nameNext); name += "." + nameNext.Value; } return(name); }
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); }
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 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); }
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 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 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 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)); }
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); } }
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); }
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)); }
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); }
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 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 ClassDefinition ParseClassDefinition(TokenStream tokens, TopLevelConstruct owner, Token staticToken, Token finalToken, FileScope fileScope, AnnotationCollection classAnnotations) { Token classToken = tokens.PopExpected(this.parser.Keywords.CLASS); Token classNameToken = tokens.Pop(); this.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; 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, parser.CurrentLibrary, staticToken, finalToken, fileScope, classAnnotations); tokens.PopExpected("{"); List <FunctionDefinition> methods = new List <FunctionDefinition>(); List <FieldDeclaration> fields = new List <FieldDeclaration>(); ConstructorDefinition constructorDef = null; ConstructorDefinition staticConstructorDef = null; while (!tokens.PopIfPresent("}")) { AnnotationCollection annotations = this.parser.AnnotationParser.ParseAnnotations(tokens); if (tokens.IsNext(this.parser.Keywords.FUNCTION) || tokens.AreNext(this.parser.Keywords.STATIC, this.parser.Keywords.FUNCTION)) { methods.Add(this.parser.ExecutableParser.ParseFunction(tokens, cd, fileScope, annotations)); } else if (tokens.IsNext(this.parser.Keywords.CONSTRUCTOR)) { if (constructorDef != null) { throw this.parser.GenerateParseError( ErrorMessages.CLASS_CANNOT_HAVE_MULTIPLE_CONSTRUCTORS, tokens.Pop()); } constructorDef = this.parser.ExecutableParser.ParseConstructor(tokens, cd, annotations); } else if (tokens.AreNext(this.parser.Keywords.STATIC, this.parser.Keywords.CONSTRUCTOR)) { tokens.Pop(); // static token if (staticConstructorDef != null) { throw new ParserException(tokens.Pop(), "Multiple static constructors are not allowed."); } staticConstructorDef = this.parser.ExecutableParser.ParseConstructor(tokens, cd, annotations); } else if (tokens.IsNext(this.parser.Keywords.FIELD) || tokens.AreNext(this.parser.Keywords.STATIC, this.parser.Keywords.FIELD)) { fields.Add(this.parser.ExecutableParser.ParseField(tokens, cd, annotations)); } else { tokens.PopExpected("}"); } TODO.CheckForUnusedAnnotations(); } cd.Methods = methods.ToArray(); cd.Constructor = constructorDef; cd.StaticConstructor = staticConstructorDef; cd.Fields = fields.ToArray(); return(cd); }
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 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)); }
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); }