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 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; }
private void CompileForEachLoop(Parser parser, ByteBuffer buffer, ForEachLoop forEachLoop) { buffer.Add(null, OpCode.LITERAL, parser.GetIntConstant(0)); buffer.Add(null, OpCode.LITERAL, parser.GetIntConstant(forEachLoop.IterationVariableId)); this.CompileExpression(parser, buffer, forEachLoop.IterationExpression, true); buffer.Add(forEachLoop.IterationExpression.FirstToken, OpCode.VERIFY_TYPE_IS_ITERABLE); ByteBuffer body = new ByteBuffer(); ByteBuffer body2 = new Crayon.ByteBuffer(); this.Compile(parser, body2, forEachLoop.Code); body.Add(forEachLoop.FirstToken, OpCode.ITERATION_STEP, body2.Size + 1); body2.Add(null, OpCode.JUMP, -body2.Size - 2); body.Concat(body2); body.ResolveBreaks(); body.ResolveContinues(); buffer.Concat(body); buffer.Add(null, OpCode.POP); // list buffer.Add(null, OpCode.POP); // var ID buffer.Add(null, OpCode.POP); // index }