private ByteBuffer BuildSwitchStatementTables(Parser parser) { ByteBuffer output = new Crayon.ByteBuffer(); List<Dictionary<int, int>> intSwitches = parser.GetIntegerSwitchStatements(); for (int i = 0; i < intSwitches.Count; ++i) { List<int> args = new List<int>(); Dictionary<int, int> lookup = intSwitches[i]; foreach (int key in lookup.Keys) { int offset = lookup[key]; args.Add(key); args.Add(offset); } output.Add(null, OpCode.BUILD_SWITCH_INT, args.ToArray()); } List<Dictionary<string, int>> stringSwitches = parser.GetStringSwitchStatements(); for (int i = 0; i < stringSwitches.Count; ++i) { Dictionary<string, int> lookup = stringSwitches[i]; foreach (string key in lookup.Keys) { int offset = lookup[key]; output.Add(null, OpCode.BUILD_SWITCH_STRING, key, i, offset); } } return output; }
public ByteBuffer GenerateByteCode(Parser parser, IList<Executable> lines, IList<string> spriteSheetOpsStringArgs, IList<int[]> spriteSheetOpsIntArgs) { FunctionDefinition mainFunction = lines .OfType<FunctionDefinition>() .Where<FunctionDefinition>(fd => fd.NameToken.Value == "main") .FirstOrDefault<FunctionDefinition>(); if (mainFunction == null) { throw new Exception(); // should have thrown before if there was no main function. } ByteBuffer userCode = new ByteBuffer(); this.Compile(parser, userCode, lines); ByteBuffer literalsTable = parser.LiteralLookup.BuildByteCode(); ByteBuffer tokenData = this.BuildTokenData(userCode); ByteBuffer fileContent = this.BuildFileContent(parser.GetFilesById()); ByteBuffer switchStatements = this.BuildSwitchStatementTables(parser); ByteBuffer spriteSheetStuff = this.BuildSpriteSheetStuff(spriteSheetOpsStringArgs, spriteSheetOpsIntArgs); ByteBuffer header = new Crayon.ByteBuffer(); header.Concat(literalsTable); header.Concat(tokenData); header.Concat(fileContent); header.Concat(switchStatements); header.Concat(spriteSheetStuff); header.Add(null, OpCode.FINALIZE_INITIALIZATION); ByteBuffer output = new Crayon.ByteBuffer(); output.Add(null, OpCode.USER_CODE_START, header.Size + 1, parser.VariableIds.Size); output.Concat(header); output.Concat(userCode); // artificially inject a function call to main() at the very end after all declarations are done. if (parser.MainFunctionHasArg) { output.Add(null, OpCode.DEF_LIST, 0); // TODO: op code to build a list of the command line args. For now just pass in an empty list. output.Add(null, OpCode.CALL_FUNCTION, (int)FunctionInvocationType.NORMAL_FUNCTION, 1, mainFunction.FunctionID, 0, 0); } else { output.Add(null, OpCode.CALL_FUNCTION, (int)FunctionInvocationType.NORMAL_FUNCTION, 0, mainFunction.FunctionID, 0, 0); } output.Add(null, OpCode.RETURN, 0); return output; }
private ByteBuffer GenerateByteCode(BuildContext buildContext, string inputFolder, List<string> spriteSheetOpsStringArgs, List<int[]> spriteSheetOpsIntArgs) { Parser userCodeParser = new Parser(null, buildContext, null); ParseTree.Executable[] userCode = userCodeParser.ParseAllTheThings(inputFolder); foreach (Executable ex in userCode) { ex.GenerateGlobalNameIdManifest(userCodeParser.VariableIds); } ByteCodeCompiler bcc = new ByteCodeCompiler(); ByteBuffer buffer = bcc.GenerateByteCode(userCodeParser, userCode, spriteSheetOpsStringArgs, spriteSheetOpsIntArgs); this.LibraryBigSwitchStatement = userCodeParser.SystemLibraryManager.GetLibrarySwitchStatement(this.LanguageId, this.PlatformId); this.InterpreterCompiler = new InterpreterCompiler(this, userCodeParser.SystemLibraryManager); return buffer; }
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 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; }
// Convert anything that looks like a function call into a verified pointer to the function if possible using the // available namespaces. public static List<Executable> CreateVerifiedFunctionCalls(Parser parser, IList<Executable> original) { // All code that doesn't have a function or class surrounding it. List<Executable> looseCode = new List<Executable>(); // First create a fully-qualified lookup of all functions and classes. Dictionary<string, Executable> functionsAndClasses = new Dictionary<string, Executable>(); foreach (Executable exec in original) { if (exec is FunctionDefinition) { FunctionDefinition fd = (FunctionDefinition)exec; string key = fd.Namespace + ":" + fd.NameToken.Value; functionsAndClasses[key] = fd; } else if (exec is ClassDefinition) { ClassDefinition cd = (ClassDefinition)exec; string key = cd.Namespace + ":" + cd.NameToken.Value; functionsAndClasses[key] = cd; } } List<Executable> output = new List<Executable>(); return output; }
private void CompileBooleanCombination(Parser parser, ByteBuffer buffer, BooleanCombination boolComb, bool outputUsed) { if (!outputUsed) throw new ParserException(boolComb.FirstToken, "Cannot have this expression here."); ByteBuffer rightBuffer = new ByteBuffer(); Expression[] expressions = boolComb.Expressions; this.CompileExpression(parser, rightBuffer, expressions[expressions.Length - 1], true); for (int i = expressions.Length - 2; i >= 0; --i) { ByteBuffer leftBuffer = new ByteBuffer(); this.CompileExpression(parser, leftBuffer, expressions[i], true); Token op = boolComb.Ops[i]; if (op.Value == "&&") { leftBuffer.Add(op, OpCode.JUMP_IF_FALSE_NO_POP, rightBuffer.Size); } else { leftBuffer.Add(op, OpCode.JUMP_IF_TRUE_NO_POP, rightBuffer.Size); } leftBuffer.Concat(rightBuffer); rightBuffer = leftBuffer; } buffer.Concat(rightBuffer); }
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 ParseTry(Parser parser, TokenStream tokens, Executable owner) { Token tryToken = tokens.PopExpected("try"); throw new NotImplementedException(); }
private void CompileIncrement(Parser parser, ByteBuffer buffer, Increment increment, bool outputUsed) { if (!outputUsed) { throw new Exception("This should have been optimized into a += or -="); } if (increment.Root is Variable) { // OpCode re-use be damned. This should be not one, but two top-level op codes. // INCREMENT_INLINE and INCREMENT_POP (depending on whether outputUsed is true) // In fact, the code here in its current form is actually WRONG because someString++ will have // a '1' appended to it when it really should be an error if the variable is not an integer. // Same for the others below. Ideally the DUPLICATE_STACK_TOP op should be removed. Variable variable = (Variable)increment.Root; int scopeId = variable.LocalScopeId; this.CompileExpression(parser, buffer, increment.Root, true); if (increment.IsPrefix) { buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)BinaryOps.ADDITION : (int)BinaryOps.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 1); buffer.Add(variable.FirstToken, OpCode.ASSIGN_LOCAL, scopeId); } else { buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 1); buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)BinaryOps.ADDITION : (int)BinaryOps.SUBTRACTION); buffer.Add(variable.FirstToken, OpCode.ASSIGN_LOCAL, scopeId); } } else if (increment.Root is BracketIndex) { BracketIndex bracketIndex = (BracketIndex)increment.Root; this.CompileExpression(parser, buffer, bracketIndex.Root, true); this.CompileExpression(parser, buffer, bracketIndex.Index, true); buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 2); buffer.Add(bracketIndex.BracketToken, OpCode.INDEX); if (increment.IsPrefix) { buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)BinaryOps.ADDITION : (int)BinaryOps.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.ASSIGN_INDEX, 1); } else { buffer.Add(increment.IncrementToken, OpCode.STACK_INSERTION_FOR_INCREMENT); buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)BinaryOps.ADDITION : (int)BinaryOps.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.ASSIGN_INDEX, 0); } } else if (increment.Root is DotStep) { DotStep dotStep = (DotStep)increment.Root; this.CompileExpression(parser, buffer, dotStep.Root, true); buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 1); buffer.Add(dotStep.DotToken, OpCode.DEREF_DOT, parser.GetId(dotStep.StepToken.Value)); if (increment.IsPrefix) { buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)BinaryOps.ADDITION : (int)BinaryOps.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.ASSIGN_STEP, parser.GetId(dotStep.StepToken.Value), 1); } else { buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 2); buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)BinaryOps.ADDITION : (int)BinaryOps.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.ASSIGN_STEP, parser.GetId(dotStep.StepToken.Value), 0); buffer.Add(increment.IncrementToken, OpCode.STACK_SWAP_POP); } } else { throw new ParserException(increment.IncrementToken, "Cannot apply " + (increment.IsIncrement ? "++" : "--") + " to this sort of expression."); } }
private static Executable ParseWhile(Parser parser, TokenStream tokens, Executable owner) { Token whileToken = tokens.PopExpected("while"); tokens.PopExpected("("); Expression condition = ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); IList<Executable> body = Parser.ParseBlock(parser, tokens, false, owner); return new WhileLoop(whileToken, condition, body, owner); }
private void CompileNullConstant(Parser parser, ByteBuffer buffer, NullConstant nullConstant, bool outputUsed) { if (!outputUsed) throw new ParserException(nullConstant.FirstToken, "This expression doesn't do anything."); buffer.Add(nullConstant.FirstToken, OpCode.LITERAL, parser.GetNullConstant()); }
private void CompileFloatConstant(Parser parser, ByteBuffer buffer, FloatConstant floatConstant, bool outputUsed) { if (!outputUsed) throw new ParserException(floatConstant.FirstToken, "This expression doesn't do anything."); buffer.Add(floatConstant.FirstToken, OpCode.LITERAL, parser.GetFloatConstant(floatConstant.Value)); }
private void CompileThisKeyword(Parser parser, ByteBuffer buffer, ThisKeyword thisKeyword, bool outputUsed) { if (!outputUsed) throw new ParserException(thisKeyword.FirstToken, "This expression doesn't do anything."); buffer.Add(thisKeyword.FirstToken, OpCode.THIS); }
private void CompileInstantiate(Parser parser, ByteBuffer buffer, Instantiate instantiate, bool outputUsed) { ClassDefinition cd = (ClassDefinition)instantiate.Class; ConstructorDefinition constructor = cd.Constructor; this.CompileExpressionList(parser, buffer, instantiate.Args, true); buffer.Add(instantiate.NameToken, OpCode.CALL_FUNCTION, (int)FunctionInvocationType.CONSTRUCTOR, instantiate.Args.Length, constructor.FunctionID, outputUsed ? 1 : 0, cd.ClassID); }
private void CompileDictionaryDefinition(Parser parser, ByteBuffer buffer, DictionaryDefinition dictDef, bool outputUsed) { if (!outputUsed) throw new ParserException(dictDef.FirstToken, "Cannot have a dictionary all by itself."); int itemCount = dictDef.Keys.Length; List<Expression> expressionList = new List<Expression>(); for (int i = 0; i < itemCount; ++i) { expressionList.Add(dictDef.Keys[i]); expressionList.Add(dictDef.Values[i]); } this.CompileExpressionList(parser, buffer, expressionList, true); buffer.Add(dictDef.FirstToken, OpCode.DEF_DICTIONARY, itemCount); }
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; }
public Executable[] ImportLibrary(Parser parser, Token throwToken, string name) { name = name.Split('.')[0]; if (alreadyImported.Contains(name)) { return EMPTY_EXECUTABLE; } alreadyImported.Add(name); string dllPath = this.GetSystemLibraryPath(name); if (dllPath == null) { return EMPTY_EXECUTABLE; } System.Reflection.Assembly assembly = null; try { assembly = System.Reflection.Assembly.LoadFrom(dllPath); } catch (Exception) { throw new ParserException(throwToken, "Could not import library: " + name); } ILibraryConfig libraryConfig = assembly.CreateInstance(name + ".LibraryConfig") as ILibraryConfig; if (libraryConfig == null) { throw new ParserException(throwToken, "Error creating LibraryConfig instance in Library '" + name + "'"); } this.importedLibraries[name] = libraryConfig; this.librariesByKey[name.ToLowerInvariant()] = libraryConfig; string oldSystemLibrary = parser.CurrentSystemLibrary; parser.CurrentSystemLibrary = name; string libraryCode = libraryConfig.GetEmbeddedCode(); Executable[] libraryParseTree = parser.ParseInterpretedCode("[" + name + "]", libraryCode, name); parser.CurrentSystemLibrary = oldSystemLibrary; return libraryParseTree; }
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 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 ParseDoWhile(Parser parser, TokenStream tokens, Executable owner) { Token doToken = tokens.PopExpected("do"); IList<Executable> body = Parser.ParseBlock(parser, tokens, true, owner); tokens.PopExpected("while"); tokens.PopExpected("("); Expression condition = ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); tokens.PopExpected(";"); return new DoWhileLoop(doToken, body, condition, owner); }
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 Executable ParseIf(Parser parser, TokenStream tokens, Executable owner) { Token ifToken = tokens.PopExpected("if"); tokens.PopExpected("("); Expression condition = ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); IList<Executable> body = Parser.ParseBlock(parser, tokens, false, owner); IList<Executable> elseBody; if (tokens.PopIfPresent("else")) { elseBody = Parser.ParseBlock(parser, tokens, false, owner); } else { elseBody = new Executable[0]; } return new IfStatement(ifToken, condition, body, elseBody, owner); }
public InterpreterCompiler(AbstractPlatform platform, SystemLibraryManager sysLibMan) { this.platform = platform; this.interpreterParser = new Parser(platform, null, sysLibMan); }
public Resolver(Parser parser, IList<Executable> originalCode) { this.parser = parser; this.currentCode = originalCode.ToArray(); }
private void CompileNullCoalescer(Parser parser, ByteBuffer buffer, NullCoalescer nullCoalescer, bool outputUsed) { EnsureUsed(nullCoalescer.FirstToken, outputUsed); this.CompileExpression(parser, buffer, nullCoalescer.PrimaryExpression, true); ByteBuffer secondaryExpression = new ByteBuffer(); this.CompileExpression(parser, secondaryExpression, nullCoalescer.SecondaryExpression, true); buffer.Add(nullCoalescer.FirstToken, OpCode.POP_IF_NULL_OR_JUMP, secondaryExpression.Size); buffer.Concat(secondaryExpression); }
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 void CompileBooleanNot(Parser parser, ByteBuffer buffer, BooleanNot boolNot, bool outputUsed) { if (!outputUsed) throw new ParserException(boolNot.FirstToken, "Cannot have this expression here."); this.CompileExpression(parser, buffer, boolNot.Root, true); buffer.Add(boolNot.FirstToken, OpCode.BOOLEAN_NOT); }
internal static IList<Executable> ParseBlock(Parser parser, TokenStream tokens, bool bracketsRequired, Executable owner) { List<Executable> output = new List<Executable>(); if (tokens.PopIfPresent("{")) { while (!tokens.PopIfPresent("}")) { output.Add(ExecutableParser.Parse(parser, tokens, false, true, false, owner)); } } else { if (bracketsRequired) { tokens.PopExpected("{"); // throws with reasonable exception message. } if (tokens.PopIfPresent(";")) { return output; } output.Add(ExecutableParser.Parse(parser, tokens, false, true, false, owner)); } return output; }
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); }