private static Executable ParseEnumDefinition(Parser parser, TokenStream tokens, Executable owner) { Token enumToken = tokens.PopExpected("enum"); Token nameToken = tokens.Pop(); Parser.VerifyIdentifier(nameToken); string name = nameToken.Value; tokens.PopExpected("{"); bool nextForbidden = false; List <Token> items = new List <Token>(); List <Expression> values = new List <Expression>(); while (!tokens.PopIfPresent("}")) { if (nextForbidden) { tokens.PopExpected("}"); // crash } Token enumItem = tokens.Pop(); Parser.VerifyIdentifier(enumItem); if (tokens.PopIfPresent("=")) { values.Add(ExpressionParser.Parse(tokens, owner)); } else { values.Add(null); } nextForbidden = !tokens.PopIfPresent(","); items.Add(enumItem); } return(new EnumDefinition(enumToken, nameToken, parser.CurrentNamespace, items, values, owner)); }
private static Executable ParseStruct(TokenStream tokens, Executable owner) { Token structToken = tokens.PopExpected("struct"); Token structNameToken = tokens.Pop(); Parser.VerifyIdentifier(structNameToken); tokens.PopExpected("{"); List <Token> fieldTokens = new List <Token>(); List <Annotation> typeAnnotations = new List <Annotation>(); bool nextForbidden = false; while (!tokens.PopIfPresent("}")) { if (nextForbidden) { tokens.PopExpected("}"); // crash } Annotation annotation = tokens.IsNext("@") ? AnnotationParser.ParseAnnotation(tokens) : null; Token fieldToken = tokens.Pop(); Parser.VerifyIdentifier(fieldToken); nextForbidden = !tokens.PopIfPresent(","); fieldTokens.Add(fieldToken); typeAnnotations.Add(annotation); } return(new StructDefinition(structToken, structNameToken, fieldTokens, typeAnnotations, owner)); }
private Namespace ParseNamespace(TokenStream tokens, TopLevelConstruct owner, FileScope fileScope) { 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)); parser.PushNamespacePrefix(name); Namespace namespaceInstance = new Namespace(namespaceToken, name, owner, parser.CurrentLibrary, fileScope); tokens.PopExpected("{"); List <TopLevelConstruct> namespaceMembers = new List <TopLevelConstruct>(); while (!tokens.PopIfPresent("}")) { TopLevelConstruct executable = this.parser.ExecutableParser.ParseTopLevel(tokens, namespaceInstance, fileScope); if (executable is FunctionDefinition || executable is ClassDefinition || executable is EnumDefinition || executable is ConstStatement || executable is Namespace) { namespaceMembers.Add(executable); } else { throw new ParserException(executable.FirstToken, "Only function, class, and nested namespace declarations may exist as direct members of a namespace."); } } namespaceInstance.Code = namespaceMembers.ToArray(); parser.PopNamespacePrefix(); return(namespaceInstance); }
private static Executable ParseNamespace(Parser parser, TokenStream tokens, Executable owner) { Token namespaceToken = tokens.PopExpected("namespace"); Token first = tokens.Pop(); Parser.VerifyIdentifier(first); List <Token> namespacePieces = new List <Token>() { first }; while (tokens.PopIfPresent(".")) { Token nsToken = tokens.Pop(); Parser.VerifyIdentifier(nsToken); namespacePieces.Add(nsToken); } string name = string.Join(".", namespacePieces.Select <Token, string>(t => t.Value)); parser.PushNamespacePrefix(name); Namespace namespaceInstance = new Namespace(namespaceToken, name, owner); tokens.PopExpected("{"); List <Executable> namespaceMembers = new List <Executable>(); while (!tokens.PopIfPresent("}")) { Executable executable = ExecutableParser.Parse(parser, tokens, false, false, true, namespaceInstance); if (executable is FunctionDefinition || executable is ClassDefinition || executable is EnumDefinition || executable is ConstStatement || executable is Namespace) { namespaceMembers.Add(executable); } else { throw new ParserException(executable.FirstToken, "Only function, class, and nested namespace declarations may exist as direct members of a namespace."); } } namespaceInstance.Code = namespaceMembers.ToArray(); parser.PopNamespacePrefix(); return(namespaceInstance); }
public Annotation ParseAnnotation(TokenStream tokens) { Token annotationToken = tokens.PopExpected("@"); Token typeToken = tokens.Pop(); // TODO: refactor this. All built-in annotations should be exempt from the VerifyIdentifier check in an extensible way. if (typeToken.Value != this.parser.Keywords.PRIVATE) { parser.VerifyIdentifier(typeToken); } List <Expression> args = new List <Expression>(); if (tokens.PopIfPresent("(")) { while (!tokens.PopIfPresent(")")) { if (args.Count > 0) { tokens.PopExpected(","); } args.Add(this.parser.ExpressionParser.Parse(tokens, null)); } } return(new Annotation(annotationToken, typeToken, args)); }
private 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 = Parser.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 = Parser.ParseBlock(parser, tokens, false, owner); return(new ForLoop(forToken, init, condition, step, body, owner)); } }
private ConstructorDefinition ParseConstructor(TokenStream tokens, TopLevelConstruct owner) { 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 new ParserException(argName, "All optional arguments must come at the end of the argument list."); } argNames.Add(argName); argValues.Add(defaultValue); } List <Expression> baseArgs = new List <Expression>(); Token baseToken = null; if (tokens.PopIfPresent(":")) { baseToken = tokens.PopExpected(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 = Parser.ParseBlock(parser, tokens, true, owner); return(new ConstructorDefinition(constructorToken, argNames, argValues, baseArgs, code, baseToken, owner)); }
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 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 ParseBitwiseOp(TokenStream tokens, Executable 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 BinaryOpChain(expr, bitwiseToken, rightExpr, owner); } return expr; }
private static Executable ParseConst(Parser parser, TokenStream tokens, Executable owner) { Token constToken = tokens.PopExpected("const"); Token nameToken = tokens.Pop(); Parser.VerifyIdentifier(nameToken); tokens.PopExpected("="); Expression expression = ExpressionParser.Parse(tokens, owner); tokens.PopExpected(";"); return(new ConstStatement(constToken, nameToken, parser.CurrentNamespace, expression, owner)); }
private Executable ParseConst(TokenStream tokens, Executable owner) { Token constToken = tokens.PopExpected(this.parser.Keywords.CONST); Token nameToken = tokens.Pop(); ConstStatement constStatement = new ConstStatement(constToken, nameToken, parser.CurrentNamespace, owner); this.parser.VerifyIdentifier(nameToken); tokens.PopExpected("="); constStatement.Expression = this.parser.ExpressionParser.Parse(tokens, constStatement); tokens.PopExpected(";"); return(constStatement); }
private ConstStatement ParseConst(TokenStream tokens, TopLevelConstruct owner, FileScope fileScope) { Token constToken = tokens.PopExpected(this.parser.Keywords.CONST); Token nameToken = tokens.Pop(); ConstStatement constStatement = new ConstStatement(constToken, nameToken, parser.CurrentNamespace, owner, parser.CurrentLibrary, fileScope); this.parser.VerifyIdentifier(nameToken); tokens.PopExpected("="); constStatement.Expression = this.parser.ExpressionParser.Parse(tokens, constStatement); tokens.PopExpected(";"); return(constStatement); }
private Expression ParseBitwiseOp(TokenStream tokens, Executable 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 BinaryOpChain(expr, bitwiseToken, rightExpr, owner)); } return(expr); }
private static Expression ParseBitShift(TokenStream tokens, Executable owner) { Expression expr = ParseAddition(tokens, owner); string next = tokens.PeekValue(); if (next == "<<" || next == ">>") { Token opToken = tokens.Pop(); Expression rightExpr = ParseBitShift(tokens, owner); return(new BinaryOpChain(expr, opToken, rightExpr, owner)); } return(expr); }
private static Expression ParseEqualityComparison(TokenStream tokens, Executable owner) { Expression expr = ParseInequalityComparison(tokens, owner); string next = tokens.PeekValue(); if (next == "==" || next == "!=") { Token equalityToken = tokens.Pop(); Expression rightExpr = ParseEqualityComparison(tokens, owner); return(new BinaryOpChain(expr, equalityToken, rightExpr, owner)); } return(expr); }
private static string PopClassName(TokenStream tokens, Token firstToken) { Parser.VerifyIdentifier(firstToken); string name = firstToken.Value; while (tokens.PopIfPresent(".")) { Token nameNext = tokens.Pop(); Parser.VerifyIdentifier(nameNext); name += "." + nameNext.Value; } return(name); }
private static Expression ParseExponents(TokenStream tokens, Executable owner) { Expression expr = ParseIncrement(tokens, owner); string next = tokens.PeekValue(); if (next == "**") { Token op = tokens.Pop(); Expression right = ParseNegate(tokens, owner); expr = new BinaryOpChain(expr, op, right, owner); } return(expr); }
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 static Expression ParseMultiplication(TokenStream tokens, Executable 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 BinaryOpChain(expr, op, right, owner); next = tokens.PeekValue(); } return(expr); }
private static Expression ParseInequalityComparison(TokenStream tokens, Executable 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 BinaryOpChain(expr, opToken, rightExpr, owner)); } return(expr); }
private EnumDefinition ParseEnumDefinition(TokenStream tokens, TopLevelConstruct owner, FileScope fileScope) { 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, parser.CurrentNamespace, owner, parser.CurrentLibrary, fileScope); 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 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 static FieldDeclaration ParseField(TokenStream tokens, ClassDefinition owner) { bool isStatic = tokens.PopIfPresent("static"); Token fieldToken = tokens.PopExpected("field"); Token nameToken = tokens.Pop(); Parser.VerifyIdentifier(nameToken); FieldDeclaration fd = new FieldDeclaration(fieldToken, nameToken, owner, isStatic); if (tokens.PopIfPresent("=")) { fd.DefaultValue = ExpressionParser.Parse(tokens, owner); } tokens.PopExpected(";"); return(fd); }
private FieldDeclaration ParseField(TokenStream tokens, ClassDefinition owner) { 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); if (tokens.PopIfPresent("=")) { fd.DefaultValue = this.parser.ExpressionParser.Parse(tokens, owner); } tokens.PopExpected(";"); return(fd); }
private static Expression ParseBooleanCombination(TokenStream tokens, Executable 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; }
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 Expression ParseInstantiate(TokenStream tokens, Executable 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 static Expression ParseInstantiate(TokenStream tokens, Executable owner) { Token newToken = tokens.PopExpected("new"); Token classNameToken = tokens.Pop(); string name = PopClassName(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)); }
public static Annotation ParseAnnotation(TokenStream tokens) { Token annotationToken = tokens.PopExpected("@"); Token typeToken = tokens.Pop(); Parser.VerifyIdentifier(typeToken); List<Expression> args = new List<Expression>(); if (tokens.PopIfPresent("(")) { while (!tokens.PopIfPresent(")")) { if (args.Count > 0) { tokens.PopExpected(","); } args.Add(ExpressionParser.Parse(tokens, null)); } } return new Annotation(annotationToken, typeToken, args); }
private static Expression ParseNegate(TokenStream tokens, Executable 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)); }
public static Annotation ParseAnnotation(TokenStream tokens) { Token annotationToken = tokens.PopExpected("@"); Token typeToken = tokens.Pop(); Parser.VerifyIdentifier(typeToken); List <Expression> args = new List <Expression>(); if (tokens.PopIfPresent("(")) { while (!tokens.PopIfPresent(")")) { if (args.Count > 0) { tokens.PopExpected(","); } args.Add(ExpressionParser.Parse(tokens, null)); } } return(new Annotation(annotationToken, typeToken, args)); }
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(); }
public static Executable Parse(Parser parser, TokenStream tokens, bool simpleOnly, bool semicolonPresent, bool isRoot, Executable owner) { string value = tokens.PeekValue(); if (!simpleOnly) { if (parser.IsTranslateMode && value == "struct") { if (!isRoot) { throw new ParserException(tokens.Peek(), "structs cannot be nested into any other construct."); } // struct is special. If you are not compiling in JS mode, if (Parser.IsValidIdentifier(tokens.PeekValue(1)) && tokens.PeekValue(2) == "{") { return ParseStruct(tokens, owner); } } if (!isRoot && (value == "function" || value == "class")) { throw new ParserException(tokens.Peek(), (value == "function" ? "Function" : "Class") + " definition cannot be nested in another construct."); } if (value == "import") { Token importToken = tokens.PopExpected("import"); bool inline = parser.IsTranslateMode && tokens.PopIfPresent("inline"); if (inline) { Token fileToken = tokens.Pop(); char c = fileToken.Value[0]; if (c != '\'' && c != '"') throw new ParserException(fileToken, "Inline imports are supposed to be strings."); tokens.PopExpected(";"); string inlineImportFileName = fileToken.Value.Substring(1, fileToken.Value.Length - 2); string inlineImportFileContents = Util.ReadFileInternally(inlineImportFileName); // TODO: Anti-pattern alert. Clean this up. if (inlineImportFileContents.Contains("%%%")) { Dictionary<string, string> replacements = parser.NullablePlatform.InterpreterCompiler.BuildReplacementsDictionary(); inlineImportFileContents = Constants.DoReplacements(inlineImportFileContents, replacements); } TokenStream inlineTokens = Tokenizer.Tokenize(inlineImportFileName, inlineImportFileContents, 0, true); // OMGHAX - insert the inline import into the current token stream. tokens.InsertTokens(inlineTokens); return ExecutableParser.Parse(parser, tokens, simpleOnly, semicolonPresent, isRoot, owner); // start exectuable parser anew. } if (!isRoot) { throw new ParserException(tokens.Peek(), "Imports can only be made from the root of a file and cannot be nested inside other constructs."); } List<string> importPathBuilder = new List<string>(); while (!tokens.PopIfPresent(";")) { if (importPathBuilder.Count > 0) { tokens.PopExpected("."); } Token pathToken = tokens.Pop(); Parser.VerifyIdentifier(pathToken); importPathBuilder.Add(pathToken.Value); } string importPath = string.Join(".", importPathBuilder); return new ImportStatement(importToken, importPath); } if (value == "enum") { if (!isRoot) { throw new ParserException(tokens.Peek(), "Enums can only be defined from the root of a file and cannot be nested inside functions/loops/etc."); } return ParseEnumDefinition(parser, tokens, owner); } if (value == "namespace") { if (!isRoot) { throw new ParserException(tokens.Peek(), "Namespace declarations cannot be nested in other constructs."); } } switch (value) { case "namespace": return ParseNamespace(parser, tokens, owner); case "function": return ParseFunction(parser, tokens, owner); case "class": return ParseClassDefinition(parser, tokens, owner); case "enum": return ParseEnumDefinition(parser, tokens, owner); case "for": return ParseFor(parser, tokens, owner); case "while": return ParseWhile(parser, tokens, owner); case "do": return ParseDoWhile(parser, tokens, owner); case "switch": return ParseSwitch(parser, tokens, owner); case "if": return ParseIf(parser, tokens, owner); case "try": return ParseTry(parser, tokens, owner); case "return": return ParseReturn(tokens, owner); case "break": return ParseBreak(tokens, owner); case "continue": return ParseContinue(tokens, owner); case "const": return ParseConst(parser, tokens, owner); case "constructor": return ParseConstructor(parser, tokens, owner); default: break; } } Expression expr = ExpressionParser.Parse(tokens, owner); value = tokens.PeekValue(); if (ASSIGNMENT_OPS.Contains(value)) { Token assignment = tokens.Pop(); Expression assignmentValue = ExpressionParser.Parse(tokens, owner); if (semicolonPresent) tokens.PopExpected(";"); return new Assignment(expr, assignment, assignment.Value, assignmentValue, owner); } if (semicolonPresent) { tokens.PopExpected(";"); } return new ExpressionAsExecutable(expr, owner); }
private static Expression ParseExponents(TokenStream tokens, Executable owner) { Expression expr = ParseIncrement(tokens, owner); string next = tokens.PeekValue(); if (next == "**") { Token op = tokens.Pop(); Expression right = ParseNegate(tokens, owner); expr = new BinaryOpChain(expr, op, right, owner); } return expr; }
private static Expression ParseNegate(TokenStream tokens, Executable owner) { string next = tokens.PeekValue(); if (NEGATE_OPS.Contains(next)) { Token negateOp = tokens.Pop(); Expression root = ParseNegate(tokens, owner); // TODO: just make a negation parse tree node 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); }
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 FieldDeclaration ParseField(TokenStream tokens, ClassDefinition owner) { bool isStatic = tokens.PopIfPresent("static"); Token fieldToken = tokens.PopExpected("field"); Token nameToken = tokens.Pop(); Parser.VerifyIdentifier(nameToken); FieldDeclaration fd = new FieldDeclaration(fieldToken, nameToken, owner, isStatic); if (tokens.PopIfPresent("=")) { fd.DefaultValue = ExpressionParser.Parse(tokens, owner); } tokens.PopExpected(";"); return fd; }
private static Expression ParseInstantiate(TokenStream tokens, Executable owner) { Token newToken = tokens.PopExpected("new"); Token classNameToken = tokens.Pop(); Parser.VerifyIdentifier(classNameToken); string name = classNameToken.Value; while (tokens.PopIfPresent(".")) { Token nameNext = tokens.Pop(); Parser.VerifyIdentifier(nameNext); name += "." + nameNext.Value; } 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 static Executable ParseStruct(TokenStream tokens, Executable owner) { Token structToken = tokens.PopExpected("struct"); Token structNameToken = tokens.Pop(); Parser.VerifyIdentifier(structNameToken); tokens.PopExpected("{"); List<Token> fieldTokens = new List<Token>(); List<Annotation> typeAnnotations = new List<Annotation>(); bool nextForbidden = false; while (!tokens.PopIfPresent("}")) { if (nextForbidden) tokens.PopExpected("}"); // crash Annotation annotation = tokens.IsNext("@") ? AnnotationParser.ParseAnnotation(tokens) : null; Token fieldToken = tokens.Pop(); Parser.VerifyIdentifier(fieldToken); nextForbidden = !tokens.PopIfPresent(","); fieldTokens.Add(fieldToken); typeAnnotations.Add(annotation); } return new StructDefinition(structToken, structNameToken, fieldTokens, typeAnnotations, owner); }
private static 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 { anySuffixes = false; } } return root; }
private static Executable ParseEnumDefinition(Parser parser, TokenStream tokens, Executable owner) { Token enumToken = tokens.PopExpected("enum"); Token nameToken = tokens.Pop(); Parser.VerifyIdentifier(nameToken); string name = nameToken.Value; tokens.PopExpected("{"); bool nextForbidden = false; List<Token> items = new List<Token>(); List<Expression> values = new List<Expression>(); while (!tokens.PopIfPresent("}")) { if (nextForbidden) tokens.PopExpected("}"); // crash Token enumItem = tokens.Pop(); Parser.VerifyIdentifier(enumItem); if (tokens.PopIfPresent("=")) { values.Add(ExpressionParser.Parse(tokens, owner)); } else { values.Add(null); } nextForbidden = !tokens.PopIfPresent(","); items.Add(enumItem); } return new EnumDefinition(enumToken, nameToken, parser.CurrentNamespace, items, values, owner); }
private static Executable ParseNamespace(Parser parser, TokenStream tokens, Executable owner) { Token namespaceToken = tokens.PopExpected("namespace"); Token first = tokens.Pop(); Parser.VerifyIdentifier(first); List<Token> namespacePieces = new List<Token>() { first }; while (tokens.PopIfPresent(".")) { Token nsToken = tokens.Pop(); Parser.VerifyIdentifier(nsToken); namespacePieces.Add(nsToken); } string name = string.Join(".", namespacePieces.Select<Token, string>(t => t.Value)); parser.PushNamespacePrefix(name); Namespace namespaceInstance = new Namespace(namespaceToken, name, owner); tokens.PopExpected("{"); List<Executable> namespaceMembers = new List<Executable>(); while (!tokens.PopIfPresent("}")) { Executable executable = ExecutableParser.Parse(parser, tokens, false, false, true, namespaceInstance); if (executable is FunctionDefinition || executable is ClassDefinition || executable is Namespace) { namespaceMembers.Add(executable); } else { throw new ParserException(executable.FirstToken, "Only function, class, and nested namespace declarations may exist as direct members of a namespace."); } } namespaceInstance.Code = namespaceMembers.ToArray(); parser.PopNamespacePrefix(); return namespaceInstance; }
private static Expression ParseBitShift(TokenStream tokens, Executable owner) { Expression expr = ParseAddition(tokens, owner); string next = tokens.PeekValue(); if (next == "<<" || next == ">>") { Token opToken = tokens.Pop(); Expression rightExpr = ParseBitShift(tokens, owner); return new BinaryOpChain(expr, opToken, rightExpr, owner); } return expr; }
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 ParseInequalityComparison(TokenStream tokens, Executable 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 BinaryOpChain(expr, opToken, rightExpr, owner); } return expr; }
private static Executable ParseFor(Parser parser, TokenStream tokens, Executable owner) { Token forToken = tokens.PopExpected("for"); tokens.PopExpected("("); if (Parser.IsValidIdentifier(tokens.PeekValue()) && tokens.PeekValue(1) == ":") { Token iteratorToken = tokens.Pop(); if (Parser.IsReservedKeyword(iteratorToken.Value)) { throw new ParserException(iteratorToken, "Cannot use this name for an iterator."); } tokens.PopExpected(":"); Expression iterationExpression = ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); IList<Executable> body = Parser.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(Parse(parser, tokens, true, false, false, owner)); } Expression condition = null; if (!tokens.PopIfPresent(";")) { condition = ExpressionParser.Parse(tokens, owner); tokens.PopExpected(";"); } List<Executable> step = new List<Executable>(); while (!tokens.PopIfPresent(")")) { if (step.Count > 0) tokens.PopExpected(","); step.Add(Parse(parser, tokens, true, false, false, owner)); } IList<Executable> body = Parser.ParseBlock(parser, tokens, false, owner); return new ForLoop(forToken, init, condition, step, body, owner); } }
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 Expression ParseMultiplication(TokenStream tokens, Executable 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 BinaryOpChain(expr, op, right, owner); next = tokens.PeekValue(); } return expr; }
private static Executable ParseConstructor(Parser parser, TokenStream tokens, Executable owner) { Token constructorToken = tokens.PopExpected("constructor"); tokens.PopExpected("("); List<Token> argNames = new List<Token>(); List<Expression> argValues = new List<Expression>(); bool optionalArgFound = false; while (!tokens.PopIfPresent(")")) { if (argNames.Count > 0) { tokens.PopExpected(","); } Token argName = tokens.Pop(); Parser.VerifyIdentifier(argName); Expression defaultValue = null; if (tokens.PopIfPresent("=")) { defaultValue = ExpressionParser.Parse(tokens, owner); optionalArgFound = true; } else if (optionalArgFound) { throw new ParserException(argName, "All optional arguments must come at the end of the argument list."); } argNames.Add(argName); argValues.Add(defaultValue); } List<Expression> baseArgs = new List<Expression>(); Token baseToken = null; if (tokens.PopIfPresent(":")) { baseToken = tokens.PopExpected("base"); tokens.PopExpected("("); while (!tokens.PopIfPresent(")")) { if (baseArgs.Count > 0) { tokens.PopExpected(","); } baseArgs.Add(ExpressionParser.Parse(tokens, owner)); } } IList<Executable> code = Parser.ParseBlock(parser, tokens, true, owner); return new ConstructorDefinition(constructorToken, argNames, argValues, baseArgs, code, baseToken, owner); }
private static 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; }
private static Executable ParseConst(Parser parser, TokenStream tokens, Executable owner) { Token constToken = tokens.PopExpected("const"); Token nameToken = tokens.Pop(); Parser.VerifyIdentifier(nameToken); tokens.PopExpected("="); Expression expression = ExpressionParser.Parse(tokens, owner); tokens.PopExpected(";"); return new ConstStatement(constToken, nameToken, parser.CurrentNamespace, expression, owner); }