public static Expression Parse(TokenStream tokens, Executable owner) { Dictionary<string, Annotation> annotations = null; if (tokens.IsNext("@")) { annotations = new Dictionary<string, Annotation>(); while (tokens.IsNext("@")) { Annotation annotation = AnnotationParser.ParseAnnotation(tokens); annotations[annotation.Type] = annotation; } } Expression output = ParseTernary(tokens, owner); output.Annotations = annotations; return output; }
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)); }
public void ParseInterpretedCode(string filename, string code) { FileScope fileScope = new FileScope(filename); int fileId = this.GetNextFileId(); this.RegisterFileUsed(filename, code, fileId); Token[] tokenList = Tokenizer.Tokenize(filename, code, fileId, true); TokenStream tokens = new TokenStream(tokenList, filename); List <string> namespaceImportsBuilder = new List <string>(); tokens.InsertTokens(this.GetImplicitCoreImport()); if (this.CurrentLibrary != null && this.CurrentLibrary.CanonicalKey != "en:Core") { Library coreLibrary = this.LibraryManager.GetCoreLibrary(this); this.CurrentLibrary.AddLibraryDependency(coreLibrary); } List <CompilationScope> scopesAdded = new List <CompilationScope>(); while (tokens.HasMore && tokens.IsNext(this.Keywords.IMPORT)) { ImportStatement importStatement = this.ExecutableParser.ParseTopLevel(tokens, null, fileScope) as ImportStatement; if (importStatement == null) { throw new Exception(); } namespaceImportsBuilder.Add(importStatement.ImportPath); Library library = this.LibraryManager.ImportLibrary(this, importStatement.FirstToken, importStatement.ImportPath); if (library == null) { this.unresolvedImports.Add(importStatement); } else { if (this.CurrentLibrary != null) { this.CurrentLibrary.AddLibraryDependency(library); } scopesAdded.Add(library.Scope); } } string[] namespaceImports = namespaceImportsBuilder.ToArray(); while (tokens.HasMore) { TopLevelConstruct executable = this.ExecutableParser.ParseTopLevel(tokens, null, fileScope); if (executable is ImportStatement) { throw new ParserException( executable.FirstToken, this.CurrentLocale.Strings.Get("ALL_IMPORTS_MUST_OCCUR_AT_BEGINNING_OF_FILE")); } this.CurrentScope.AddExecutable(executable); } }
public Executable[] ParseInterpretedCode(string filename, string code, string libraryName) { int fileId = this.GetNextFileId(); this.RegisterFileUsed(filename, code, fileId); Token[] tokenList = Tokenizer.Tokenize(filename, code, fileId, true); TokenStream tokens = new TokenStream(tokenList); List <Executable> executables = new List <Executable>(); List <string> namespaceImportsBuilder = new List <string>(); tokens.InsertTokens(implicitCoreImport); while (tokens.HasMore && tokens.IsNext("import")) { ImportStatement importStatement = ExecutableParser.Parse(this, tokens, false, true, true, null) as ImportStatement; if (importStatement == null) { throw new Exception(); } namespaceImportsBuilder.Add(importStatement.ImportPath); Executable[] libraryEmbeddedCode = this.SystemLibraryManager.ImportLibrary(this, importStatement.FirstToken, importStatement.ImportPath); executables.AddRange(libraryEmbeddedCode); } string[] namespaceImports = namespaceImportsBuilder.ToArray(); while (tokens.HasMore) { Executable executable; try { executable = ExecutableParser.Parse(this, tokens, false, true, true, null); } catch (EofException) { throw new ParserException(null, "Unexpected EOF encountered while parsing " + filename + ". Did you forget a closing curly brace?"); } if (executable is ImportStatement) { throw new ParserException(executable.FirstToken, "All imports must occur at the beginning of the file."); } executable.NamespacePrefixSearch = namespaceImports; executable.LibraryName = libraryName; if (executable is Namespace) { ((Namespace)executable).GetFlattenedCode(executables, namespaceImports, libraryName); } else { executables.Add(executable); } } return(executables.ToArray()); }
public static Expression Parse(TokenStream tokens, Executable owner) { Dictionary <string, Annotation> annotations = null; if (tokens.IsNext("@")) { annotations = new Dictionary <string, Annotation>(); while (tokens.IsNext("@")) { Annotation annotation = AnnotationParser.ParseAnnotation(tokens); annotations[annotation.Type] = annotation; } } Expression output = ParseTernary(tokens, owner); output.Annotations = annotations; return(output); }
private Expression ParseIncrement(TokenStream tokens, TopLevelConstruct 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 static Expression ParseIncrement(TokenStream tokens, Executable owner) { Expression root; if (tokens.IsNext("++") || tokens.IsNext("--")) { Token incrementToken = tokens.Pop(); root = ParseEntity(tokens, owner); return(new Increment(incrementToken, incrementToken, incrementToken.Value == "++", true, root, owner)); } root = 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 static Executable ParseTry(Parser parser, TokenStream tokens, Executable owner) { Token tryToken = tokens.PopExpected("try"); IList <Executable> tryBlock = Parser.ParseBlock(parser, tokens, true, owner); Token catchToken = null; IList <Executable> catchBlock = null; Token exceptionToken = null; Token finallyToken = null; IList <Executable> finallyBlock = null; if (tokens.IsNext("catch")) { catchToken = tokens.Pop(); if (tokens.PopIfPresent("(")) { exceptionToken = tokens.Pop(); char firstChar = exceptionToken.Value[0]; if (firstChar != '_' && !(firstChar >= 'a' && firstChar <= 'z') && !(firstChar >= 'A' && firstChar <= 'Z')) { throw new ParserException(exceptionToken, "Invalid name for variable."); } tokens.PopExpected(")"); } catchBlock = Parser.ParseBlock(parser, tokens, true, owner); } if (tokens.IsNext("finally")) { finallyToken = tokens.Pop(); finallyBlock = Parser.ParseBlock(parser, tokens, true, owner); } return(new TryStatement(tryToken, tryBlock, catchToken, exceptionToken, catchBlock, finallyToken, finallyBlock, owner)); }
private void Initialize(Token annotationToken, TokenStream proxyTokenStream) { this.Token = annotationToken; Token token = proxyTokenStream.Pop(); if (!Parser.IsValidIdentifier(token.Value)) { throw new ParserException(annotationToken, "Invalid type"); } this.Name = token.Value; while (proxyTokenStream.PopIfPresent(".")) { this.Name += "."; this.Name += proxyTokenStream.PopValue(); } List <AnnotatedType> generics = new List <AnnotatedType>(); if (proxyTokenStream.PopIfPresent("<")) { while (proxyTokenStream.HasMore && !proxyTokenStream.IsNext(">")) { if (generics.Count > 0 && !proxyTokenStream.PopIfPresent(",")) { throw new ParserException(annotationToken, "Expected comma in generic list"); } AnnotatedType genericItem = new AnnotatedType(annotationToken, proxyTokenStream); generics.Add(genericItem); } if (!proxyTokenStream.PopIfPresent(">")) { throw new ParserException(annotationToken, "Unclosed generic bracket."); } } this.Generics = generics.ToArray(); }
private void Initialize(Token annotationToken, TokenStream proxyTokenStream) { this.Token = annotationToken; Token token = proxyTokenStream.Pop(); if (!Parser.IsValidIdentifier(token.Value)) throw new ParserException(annotationToken, "Invalid type"); this.Name = token.Value; while (proxyTokenStream.PopIfPresent(".")) { this.Name += "."; this.Name += proxyTokenStream.PopValue(); } List<AnnotatedType> generics = new List<AnnotatedType>(); if (proxyTokenStream.PopIfPresent("<")) { while (proxyTokenStream.HasMore && !proxyTokenStream.IsNext(">")) { if (generics.Count > 0 && !proxyTokenStream.PopIfPresent(",")) { throw new ParserException(annotationToken, "Expected comma in generic list"); } AnnotatedType genericItem = new AnnotatedType(annotationToken, proxyTokenStream); generics.Add(genericItem); } if (!proxyTokenStream.PopIfPresent(">")) { throw new ParserException(annotationToken, "Unclosed generic bracket."); } } this.Generics = generics.ToArray(); }
private ClassDefinition ParseClassDefinition(TokenStream tokens, TopLevelConstruct owner, Token staticToken, Token finalToken, FileScope fileScope) { 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, parser.CurrentNamespace, owner, parser.CurrentLibrary, staticToken, finalToken, fileScope); 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 = this.parser.AnnotationParser.ParseAnnotation(tokens); if (!annotations.ContainsKey(annotation.Type)) { annotations[annotation.Type] = new List <Annotation>(); } annotations[annotation.Type].Add(annotation); } if (tokens.IsNext(this.parser.Keywords.FUNCTION) || tokens.AreNext(this.parser.Keywords.STATIC, this.parser.Keywords.FUNCTION)) { methods.Add((FunctionDefinition)this.parser.ExecutableParser.ParseFunction(tokens, cd, fileScope)); } else if (tokens.IsNext(this.parser.Keywords.CONSTRUCTOR)) { if (constructorDef != null) { throw new ParserException(tokens.Pop(), "Multiple constructors are not allowed. Use optional arguments."); } constructorDef = (ConstructorDefinition)this.parser.ExecutableParser.ParseConstructor(tokens, cd); if (annotations != null && annotations.ContainsKey(this.parser.Keywords.PRIVATE)) { constructorDef.PrivateAnnotation = annotations[this.parser.Keywords.PRIVATE][0]; annotations[this.parser.Keywords.PRIVATE].RemoveAt(0); } } 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 = (ConstructorDefinition)this.parser.ExecutableParser.ParseConstructor(tokens, cd); } 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)); } 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); }
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 { anySuffixes = false; } } return root; }
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() + "'"); }
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); }
private Expression ParseEntity(TokenStream tokens, Executable owner) { Expression root; if (tokens.PopIfPresent("(")) { root = this.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(); // HACK alert: "class" is a valid field on a class. // ParserVerifyIdentifier is invoked downstream for non-resolved fields. if (stepToken.Value != this.parser.Keywords.CLASS) { this.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(this.parser.Keywords.IS)) { Token isToken = tokens.Pop(); Token classToken = tokens.Pop(); string className = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classToken); root = new IsComparison(root, isToken, classToken, className, owner); } else { anySuffixes = false; } } return(root); }
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); }
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 Expression ParseIncrement(TokenStream tokens, Executable owner) { Expression root; if (tokens.IsNext("++") || tokens.IsNext("--")) { Token incrementToken = tokens.Pop(); root = ParseEntity(tokens, owner); return new Increment(incrementToken, incrementToken, incrementToken.Value == "++", true, root, owner); } root = 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 Executable ParseTry(TokenStream tokens, TopLevelConstruct owner) { Token tryToken = tokens.PopExpected(this.parser.Keywords.TRY); IList <Executable> tryBlock = Parser.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 = Parser.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 = Parser.ParseBlock(parser, tokens, true, owner); } return(new TryStatement(tryToken, tryBlock, catchTokens, exceptionVariables, exceptionTypeTokens, exceptionTypes, catchBlocks, finallyToken, finallyBlock, owner)); }
private FunctionDefinition ParseFunction(TokenStream tokens, TopLevelConstruct nullableOwner, FileScope fileScope) { bool isStatic = nullableOwner != null && nullableOwner is ClassDefinition && tokens.PopIfPresent(this.parser.Keywords.STATIC); Token functionToken = tokens.PopExpected(this.parser.Keywords.FUNCTION); List <Annotation> functionAnnotations = new List <Annotation>(); while (tokens.IsNext("@")) { functionAnnotations.Add(this.parser.AnnotationParser.ParseAnnotation(tokens)); } Token functionNameToken = tokens.Pop(); this.parser.VerifyIdentifier(functionNameToken); FunctionDefinition fd = new FunctionDefinition(functionToken, parser.CurrentLibrary, nullableOwner, isStatic, functionNameToken, functionAnnotations, parser.CurrentNamespace, fileScope); 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("@") ? this.parser.AnnotationParser.ParseAnnotation(tokens) : null; 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."); } 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 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() + "'"); }
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); }
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 Executable ParseClassDefinition(Parser parser, TokenStream tokens, Executable owner) { 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); tokens.PopExpected("{"); List<FunctionDefinition> methods = new List<FunctionDefinition>(); List<FieldDeclaration> fields = new List<FieldDeclaration>(); ConstructorDefinition constructorDef = null; ConstructorDefinition staticConstructorDef = null; while (!tokens.PopIfPresent("}")) { 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); } 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("}"); } } cd.Methods = methods.ToArray(); cd.Constructor = constructorDef; cd.StaticConstructor = staticConstructorDef; cd.Fields = fields.ToArray(); return cd; }
public Executable[] ParseInterpretedCode(string filename, string code, string libraryName) { int fileId = this.GetNextFileId(); this.RegisterFileUsed(filename, code, fileId); Token[] tokenList = Tokenizer.Tokenize(filename, code, fileId, true); TokenStream tokens = new TokenStream(tokenList, filename); List <Executable> executables = new List <Executable>(); List <string> namespaceImportsBuilder = new List <string>(); tokens.InsertTokens(this.GetImplicitCoreImport()); Library activeLibrary = libraryName == null ? null : this.LibraryManager.GetLibraryFromName(libraryName); if (libraryName != null && libraryName != "Core") { activeLibrary.AddLibraryDependency(this.LibraryManager.GetLibraryFromName("Core")); } while (tokens.HasMore && tokens.IsNext(this.Keywords.IMPORT)) { ImportStatement importStatement = this.ExecutableParser.Parse(tokens, false, true, true, null) as ImportStatement; if (importStatement == null) { throw new Exception(); } namespaceImportsBuilder.Add(importStatement.ImportPath); List <Executable> libraryEmbeddedCode = new List <Executable>(); Library library = this.LibraryManager.ImportLibrary(this, importStatement.FirstToken, importStatement.ImportPath, libraryEmbeddedCode); if (library == null) { this.unresolvedImports.Add(importStatement); } else { if (activeLibrary != null) { activeLibrary.AddLibraryDependency(library); } executables.AddRange(libraryEmbeddedCode); } } string[] namespaceImports = namespaceImportsBuilder.ToArray(); while (tokens.HasMore) { Executable executable = this.ExecutableParser.Parse(tokens, false, true, true, null); if (executable is ImportStatement) { throw new ParserException( executable.FirstToken, this.Locale.Strings.Get("ALL_IMPORTS_MUST_OCCUR_AT_BEGINNING_OF_FILE")); } executable.NamespacePrefixSearch = namespaceImports; executable.LibraryName = libraryName; if (executable is Namespace) { ((Namespace)executable).GetFlattenedCode(executables, namespaceImports, libraryName); } else { executables.Add(executable); } } return(executables.ToArray()); }
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); }