protected override FunctionDefinition MaybeParseFunctionDefinition( TokenStream tokens, Node owner, FileScope fileScope, AnnotationCollection annotations, ModifierCollection modifiers) { TokenStream.StreamState tss = tokens.RecordState(); AType returnType = this.parser.TypeParser.TryParse(tokens); if (returnType == null) { return(null); } Token functionName = tokens.PopIfWord(); if (functionName == null) { tokens.RestoreState(tss); return(null); } if (tokens.IsNext("(")) { tokens.RestoreState(tss); return(this.ParseFunction(tokens, owner as TopLevelEntity, fileScope, modifiers, annotations)); } tokens.RestoreState(tss); return(null); }
protected override AType MaybeParseCastPrefix(TokenStream tokens) { TokenStream.StreamState tss = tokens.RecordState(); if (tokens.PopIfPresent("(")) { AType output = this.parser.TypeParser.TryParse(tokens); if (output != null) { if (tokens.PopIfPresent(")")) { if (!tokens.HasMore) { return(output); // let the next thing throw an error } if (output.Generics.Length > 0) { return(output); } switch (output.RootType) { case "int": case "bool": case "float": case "string": case "object": return(output); } Token nextToken = tokens.Peek(); switch (nextToken.Type) { case TokenType.NUMBER: case TokenType.STRING: case TokenType.WORD: return(output); case TokenType.KEYWORD: switch (nextToken.Value) { case "this": case "base": return(output); } break; case TokenType.PUNCTUATION: if (tokens.IsNext("(")) { return(output); } break; } } } } tokens.RestoreState(tss); return(null); }
public override AType TryParse(TokenStream tokens) { TokenStream.StreamState startIndex = tokens.RecordState(); bool useMultichar = tokens.IsMultiCharTokensEnabled; tokens.IsMultiCharTokensEnabled = false; AType type = this.ParseImpl(tokens); tokens.IsMultiCharTokensEnabled = useMultichar; if (type == null) { tokens.RestoreState(startIndex); } return type; }
private AType ParseImplRoot(TokenStream tokens) { switch (tokens.PeekValue()) { // Don't even try to parse generics or namespaces on primitive types. case "int": case "bool": case "double": case "string": SIMPLE_TOKEN_LIST[0] = tokens.Pop(); return(new AType(SIMPLE_TOKEN_LIST, EMPTY_TYPE_LIST)); } Token firstToken = tokens.PopIfWord(); if (firstToken != null) { List <Token> rootType = new List <Token>() { firstToken }; while (tokens.PopIfPresent(".")) { TokenStream.StreamState tss = tokens.RecordState(); Token next = tokens.PopIfWord(); if (next == null) { tokens.RestoreState(tss); break; } else { rootType.Add(next); } } IList <AType> generics = EMPTY_TYPE_LIST; if (tokens.IsNext("<")) { TokenStream.StreamState tss = tokens.RecordState(); generics = this.ParseGenerics(tokens); if (generics.Count == 0) { tokens.RestoreState(tss); } } return(new AType(rootType, generics)); } return(null); }
protected override bool IsForEachLoopParenthesisContents(TokenStream tokens) { TokenStream.StreamState tss = tokens.RecordState(); try { if (tokens.PopIfWord() == null) { return(false); } return(tokens.IsNext(":")); } finally { tokens.RestoreState(tss); } }
protected override Assignment MaybeParseTypedVariableDeclaration(TokenStream tokens, Node owner) { TokenStream.StreamState tss = tokens.RecordState(); AType possiblyAVariableDeclaration = this.parser.TypeParser.TryParse(tokens); if (possiblyAVariableDeclaration != null) { AType variableDeclarationType = possiblyAVariableDeclaration; Token variableToken = tokens.PopIfWord(); if (variableToken != null) { // This is a variable declaration. Expression assignmentValue = null; Token assignmentOpToken = tokens.Peek(); if (tokens.PopIfPresent("=")) { assignmentValue = this.parser.ExpressionParser.Parse(tokens, owner); } else if (tokens.IsNext(";")) { return(new Assignment( new Variable(variableToken, variableToken.Value, owner), variableDeclarationType, assignmentOpToken, Ops.EQUALS, null, owner)); } if (assignmentValue != null) { return(new Assignment( new Variable(variableToken, variableToken.Value, owner), variableDeclarationType, assignmentOpToken, assignmentValue, owner)); } } } tokens.RestoreState(tss); return(null); }
protected override void ParseClassMember( TokenStream tokens, FileScope fileScope, ClassDefinition classDef, IList <FunctionDefinition> methodsOut, IList <FieldDefinition> fieldsOut, IList <PropertyDefinition> propertiesOut) { AnnotationCollection annotations = this.parser.AnnotationParser.ParseAnnotations(tokens); ModifierCollection modifiers = ModifierCollection.Parse(tokens); if (tokens.IsNext(this.parser.Keywords.CONSTRUCTOR)) { if (modifiers.HasStatic) { if (classDef.StaticConstructor != null) { throw new ParserException(tokens.Pop(), "Multiple static constructors are not allowed."); } classDef.StaticConstructor = this.ParseConstructor(tokens, classDef, modifiers, annotations); } else { if (classDef.Constructor != null) { throw this.parser.GenerateParseError( ErrorMessages.CLASS_CANNOT_HAVE_MULTIPLE_CONSTRUCTORS, tokens.Pop()); } classDef.Constructor = this.ParseConstructor(tokens, classDef, modifiers, annotations); } } else if (tokens.IsNext(this.parser.Keywords.CLASS)) { throw new ParserException(tokens.Pop(), "Nested classes are not currently supported."); } else { // Parsing the type and then throwing it away is a little wasteful, but feels less weird than parsing // the type here and passing it into ParseFunction()/ParseField(). ParseX() should ParseX from the start. TokenStream.StreamState fieldOrFunctionStart = tokens.RecordState(); AType fieldOrFunctionType = this.parser.TypeParser.TryParse(tokens); Token tokenAfterName = fieldOrFunctionType != null?tokens.PeekAhead(1) : null; tokens.RestoreState(fieldOrFunctionStart); if (tokenAfterName == null) { tokens.PopExpected("}"); // intentionally induce error } switch (tokenAfterName.Value) { case "=": case ";": fieldsOut.Add(this.ParseField(tokens, classDef, modifiers, annotations)); break; case "(": methodsOut.Add(this.ParseFunction(tokens, classDef, fileScope, modifiers, annotations)); break; case "{": // TODO(acrylic): properties should be implemented in Acrylic, just not yet. tokens.PopExpected("}"); // intentionally induce error break; default: tokens.PopExpected("}"); // intentionally induce error break; } } // TODO: check for annotations that aren't used. // https://github.com/blakeohare/crayon/issues/305 }