public override void GenerateCode(ILGenerator codeGenerator, TypeBuilder typeBuilder, ModuleBuilder moduleBuilder) { Type elementType = Environment.GetCLRType(((ArrayType)ReturnType).ElementsType); codeGenerator.BeginScope(); Label forStart = codeGenerator.DefineLabel(); Label forEnd = codeGenerator.DefineLabel(); LocalBuilder lengthBuilder = codeGenerator.DeclareLocal(typeof(int)); LocalBuilder i = codeGenerator.DeclareLocal(typeof(int)); codeGenerator.Emit(OpCodes.Ldc_I4_M1); codeGenerator.Emit(OpCodes.Stloc, i); SizeExp.GenerateCode(codeGenerator, typeBuilder, moduleBuilder); codeGenerator.Emit(OpCodes.Stloc, lengthBuilder); codeGenerator.Emit(OpCodes.Ldloc, lengthBuilder); codeGenerator.Emit(OpCodes.Newarr, elementType); codeGenerator.MarkLabel(forStart); // i++ codeGenerator.Emit(OpCodes.Dup); codeGenerator.Emit(OpCodes.Ldloc, i); codeGenerator.Emit(OpCodes.Ldc_I4_1); codeGenerator.Emit(OpCodes.Add); codeGenerator.Emit(OpCodes.Stloc, i); codeGenerator.Emit(OpCodes.Ldloc, i); // if i >= lengthBuilder goto END codeGenerator.Emit(OpCodes.Ldloc, lengthBuilder); codeGenerator.Emit(OpCodes.Bge, forEnd); // Stack: arrayRef / i / obj / Stelem codeGenerator.Emit(OpCodes.Ldloc, i); InitialValueExp.GenerateCode(codeGenerator, typeBuilder, moduleBuilder); codeGenerator.Emit(OpCodes.Stelem, elementType); codeGenerator.Emit(OpCodes.Br, forStart); codeGenerator.MarkLabel(forEnd); codeGenerator.Emit(OpCodes.Pop); codeGenerator.EndScope(); }
internal override void TranslateToIL(ILGenerator il, Type rtype){ //This assumes that rtype == Void.class. bool savedInsideProtectedRegion = compilerGlobals.InsideProtectedRegion; compilerGlobals.InsideProtectedRegion = true; compilerGlobals.BreakLabelStack.Push(compilerGlobals.BreakLabelStack.Peek(0)); compilerGlobals.ContinueLabelStack.Push(compilerGlobals.ContinueLabelStack.Peek(0)); il.BeginExceptionBlock(); if (this.finally_block != null){ if (this.finallyHasControlFlowOutOfIt) il.BeginExceptionBlock(); if (this.handler != null) il.BeginExceptionBlock(); } this.body.TranslateToIL(il, Typeob.Void); if (this.tryEndContext != null) this.tryEndContext.EmitLineInfo(il); if (this.handler != null){ if (this.type == null){ il.BeginCatchBlock(typeof(Exception)); this.handler.context.EmitLineInfo(il); this.EmitILToLoadEngine(il); il.Emit(OpCodes.Call, CompilerGlobals.jScriptExceptionValueMethod); }else{ Type filterType = this.type.ToType(); if (typeof(Exception).IsAssignableFrom(filterType)){ il.BeginCatchBlock(filterType); this.handler.context.EmitLineInfo(il); } else{ il.BeginExceptFilterBlock(); this.handler.context.EmitLineInfo(il); this.EmitILToLoadEngine(il); il.Emit(OpCodes.Call, CompilerGlobals.jScriptExceptionValueMethod); il.Emit(OpCodes.Isinst, filterType); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Cgt_Un); il.BeginCatchBlock(null); this.EmitILToLoadEngine(il); il.Emit(OpCodes.Call, CompilerGlobals.jScriptExceptionValueMethod); Convert.Emit(this, il, Typeob.Object, filterType); } } Object tok = this.field is JSVariableField ? ((JSVariableField)this.field).GetMetaData() : this.field; if (tok is LocalBuilder) il.Emit(OpCodes.Stloc, (LocalBuilder)tok); else if (tok is FieldInfo) il.Emit(OpCodes.Stsfld, (FieldInfo)tok); else Convert.EmitLdarg(il, (short)tok); if (this.handler_scope != null){ if (!this.handler_scope.isKnownAtCompileTime){ //I.e. eval or nested func this.EmitILToLoadEngine(il); il.Emit(OpCodes.Ldstr, this.fieldName); ConstantWrapper.TranslateToILInt(il, this.handler_scope.scopeId); il.Emit(OpCodes.Call, typeof(Try).GetMethod("PushHandlerScope")); Globals.ScopeStack.Push(this.handler_scope); } il.BeginScope(); // so that we can emit local scoped information for the handler variable if (this.context.document.debugOn) this.handler_scope.EmitLocalInfoForFields(il); } this.handler.TranslateToIL(il, Typeob.Void); if (this.handler_scope != null){ il.EndScope(); if (!this.handler_scope.isKnownAtCompileTime){ //I.e. eval or nested func this.EmitILToLoadEngine(il); il.Emit(OpCodes.Call, CompilerGlobals.popScriptObjectMethod); il.Emit(OpCodes.Pop); Globals.ScopeStack.Pop(); } } il.EndExceptionBlock(); } if (this.finally_block != null){ bool savedInsideFinally = compilerGlobals.InsideFinally; int savedFinallyStackTop = compilerGlobals.FinallyStackTop; compilerGlobals.InsideFinally = true; compilerGlobals.FinallyStackTop = compilerGlobals.BreakLabelStack.Size(); il.BeginFinallyBlock(); this.finally_block.TranslateToIL(il, Typeob.Void); il.EndExceptionBlock(); compilerGlobals.InsideFinally = savedInsideFinally; compilerGlobals.FinallyStackTop = savedFinallyStackTop; if (this.finallyHasControlFlowOutOfIt){ il.BeginCatchBlock(typeof(BreakOutOfFinally)); il.Emit(OpCodes.Ldfld, typeof(BreakOutOfFinally).GetField("target")); // don't need to go to 0 in the loop because 0 is the outmost block (i.e. function body) // and that would generate a JIT assert because the jump is sometimes outside the function for (int i = compilerGlobals.BreakLabelStack.Size()-1, n = i; i > 0; i--){ il.Emit(OpCodes.Dup); ConstantWrapper.TranslateToILInt(il, i); Label lab = il.DefineLabel(); il.Emit(OpCodes.Blt_S, lab); il.Emit(OpCodes.Pop); if (savedInsideFinally && i < savedFinallyStackTop) il.Emit(OpCodes.Rethrow); else il.Emit(OpCodes.Leave, (Label)compilerGlobals.BreakLabelStack.Peek(n-i)); il.MarkLabel(lab); } il.Emit(OpCodes.Pop); il.BeginCatchBlock(typeof(ContinueOutOfFinally)); il.Emit(OpCodes.Ldfld, typeof(ContinueOutOfFinally).GetField("target")); // don't need to go to 0 in the loop because 0 is the outmost block (i.e. function body) for (int i = compilerGlobals.ContinueLabelStack.Size()-1, n = i; i > 0; i--){ il.Emit(OpCodes.Dup); ConstantWrapper.TranslateToILInt(il, i); Label lab = il.DefineLabel(); il.Emit(OpCodes.Blt_S, lab); il.Emit(OpCodes.Pop); if (savedInsideFinally && i < savedFinallyStackTop) il.Emit(OpCodes.Rethrow); else il.Emit(OpCodes.Leave, (Label)compilerGlobals.ContinueLabelStack.Peek(n-i)); il.MarkLabel(lab); } il.Emit(OpCodes.Pop); ScriptObject scope = Globals.ScopeStack.Peek(); while (scope != null && !(scope is FunctionScope)) scope = scope.GetParent(); if (scope != null && !savedInsideFinally){ il.BeginCatchBlock(typeof(ReturnOutOfFinally)); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Leave, ((FunctionScope)scope).owner.returnLabel); } il.EndExceptionBlock(); } } compilerGlobals.InsideProtectedRegion = savedInsideProtectedRegion; compilerGlobals.BreakLabelStack.Pop(); compilerGlobals.ContinueLabelStack.Pop(); }
internal override void TranslateToIL(ILGenerator il, Type rtype){ //This assumes that rtype == Void.class this.context.EmitLineInfo(il); Globals.ScopeStack.Push(new WithObject(Globals.ScopeStack.Peek(), new JSObject(null, false))); bool savedInsideProtectedRegion = compilerGlobals.InsideProtectedRegion; compilerGlobals.InsideProtectedRegion = true; Label lab = il.DefineLabel(); compilerGlobals.BreakLabelStack.Push(lab); compilerGlobals.ContinueLabelStack.Push(lab); this.obj.TranslateToIL(il, Typeob.Object); this.EmitILToLoadEngine(il); il.Emit(OpCodes.Call, CompilerGlobals.jScriptWithMethod); // JScriptWith returns the with object as an 'Object' (used by the debugger EE) // define a local named 'with()' that the debugger EE will use to bind to the with object LocalBuilder withObj = null; if (context.document.debugOn){ il.BeginScope(); // used by the debugger to mark a with block withObj = il.DeclareLocal(Typeob.Object); withObj.SetLocalSymInfo("with()"); il.Emit(OpCodes.Stloc, withObj); }else il.Emit(OpCodes.Pop); il.BeginExceptionBlock(); this.block.TranslateToILInitializer(il); this.block.TranslateToIL(il, Typeob.Void); il.BeginFinallyBlock(); if (context.document.debugOn){ // null the local used by the debugger EE il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stloc, withObj); } this.EmitILToLoadEngine(il); il.Emit(OpCodes.Call, CompilerGlobals.popScriptObjectMethod); il.Emit(OpCodes.Pop); il.EndExceptionBlock(); if (context.document.debugOn) il.EndScope(); // used by the debugger to mark a with block il.MarkLabel(lab); compilerGlobals.BreakLabelStack.Pop(); compilerGlobals.ContinueLabelStack.Pop(); compilerGlobals.InsideProtectedRegion = savedInsideProtectedRegion; Globals.ScopeStack.Pop(); }
public override void Compile(ILGenerator il) { SymbolTable.PushScope(); il.BeginScope(); EmitDebugInfo(il, 0, true); if (Options.Debug) { il.Emit(OpCodes.Nop); //To step correctly } if (Variables != null) { Variables.Compile(il); } Statements.Compile(il); il.EndScope(); SymbolTable.PopScope(); EmitDebugInfo(il, 1, true); }
internal override void TranslateToIL(ILGenerator il, Type rtype) { base.context.EmitLineInfo(il); base.Globals.ScopeStack.Push(new WithObject(base.Globals.ScopeStack.Peek(), new JSObject(null, false))); bool insideProtectedRegion = base.compilerGlobals.InsideProtectedRegion; base.compilerGlobals.InsideProtectedRegion = true; Label item = il.DefineLabel(); base.compilerGlobals.BreakLabelStack.Push(item); base.compilerGlobals.ContinueLabelStack.Push(item); this.obj.TranslateToIL(il, Typeob.Object); base.EmitILToLoadEngine(il); il.Emit(OpCodes.Call, CompilerGlobals.jScriptWithMethod); LocalBuilder local = null; if (base.context.document.debugOn) { il.BeginScope(); local = il.DeclareLocal(Typeob.Object); local.SetLocalSymInfo("with()"); il.Emit(OpCodes.Stloc, local); } else { il.Emit(OpCodes.Pop); } il.BeginExceptionBlock(); this.block.TranslateToILInitializer(il); this.block.TranslateToIL(il, Typeob.Void); il.BeginFinallyBlock(); if (base.context.document.debugOn) { il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stloc, local); } base.EmitILToLoadEngine(il); il.Emit(OpCodes.Call, CompilerGlobals.popScriptObjectMethod); il.Emit(OpCodes.Pop); il.EndExceptionBlock(); if (base.context.document.debugOn) { il.EndScope(); } il.MarkLabel(item); base.compilerGlobals.BreakLabelStack.Pop(); base.compilerGlobals.ContinueLabelStack.Pop(); base.compilerGlobals.InsideProtectedRegion = insideProtectedRegion; base.Globals.ScopeStack.Pop(); }
static void HandleStatement(Mizu.Parser.ParseNode stmt, ILGenerator ILgen, ref List<LocalBuilderEx> locals, out bool err) { switch (stmt.Token.Type) { case Parser.TokenType.VarStatement: { #region VAR int i = 0; while (i != stmt.Nodes.Count - 1) { var token = stmt.Nodes[i]; if (IsDebug) { int sline = 0, scol = 0; FindLineAndCol(code, stmt.Token.StartPos, ref sline, ref scol); int eline = 0, ecol = 0; FindLineAndCol(code, stmt.Token.EndPos, ref eline, ref ecol); ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol); } if (token.Token.Type == TokenType.IDENTIFIER) //If its a var declaration. { if (locals.Find(it => it.Name == token.Token.Text) == null) { var set = stmt.Nodes[i + 1]; if (set.Token.Type == TokenType.SET) { i += 1; var next = stmt.Nodes[i + 1]; if (next.Token.Type == TokenType.NUMBER) //Integers { //Declares a variable and leaves a reference to it. LocalBuilderEx local = new LocalBuilderEx(); local.VariableType = typeof(int); local.Base = ILgen.DeclareLocal(local.VariableType); if (IsDebug) local.Base.SetLocalSymInfo(token.Token.Text); //Set variable name for debug info. ILgen.Emit(OpCodes.Ldc_I4, int.Parse(next.Token.Text)); //Sets the number ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable. local.Name = token.Token.Text; local.Type = LocalType.Var; locals.Add(local); //Remembers the variable. i += 1; } else if (next.Token.Type == TokenType.FLOAT) { //Declares a variable and leaves a reference to it. LocalBuilderEx local = new LocalBuilderEx(); local.VariableType = typeof(float); local.Base = ILgen.DeclareLocal(local.VariableType); if (IsDebug) local.Base.SetLocalSymInfo(token.Token.Text); //Set variable name for debug info. ILgen.Emit(OpCodes.Ldc_R4, float.Parse(next.Token.Text)); //Sets the number ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable. local.Name = token.Token.Text; local.Type = LocalType.Var; locals.Add(local); //Remembers the variable. i += 1; } else if (next.Token.Type == TokenType.UPPER) { //A variable that reads from stdin (Console.ReadLne) //Declares a variable and leaves a reference to it. LocalBuilderEx local = new LocalBuilderEx(); local.VariableType = typeof(int); local.Base = ILgen.DeclareLocal(local.VariableType); local.Name = token.Token.Text; local.Type = LocalType.Var; if (IsDebug) local.Base.SetLocalSymInfo(token.Token.Text); //Set variable name for debug info. try { //If theres a WAVEY symbol, print the variable name. var wavey = stmt.Nodes[i + 2]; ILgen.Emit(OpCodes.Ldstr, local.Name + " = "); ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("Write", new Type[] { typeof(string) })); i += 1; } catch (Exception) { } ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine")); //Sets the number from STDIN. ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new Type[] { typeof(string) })); //Parses it into an integer. ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable. locals.Add(local); //Remembers the variable. i += 1; } else if (next.Token.Type == TokenType.COMMA) { //An array. dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: Static arrays are not supported at this time. Line: {0}, Col: {1}", info.Line, info.Col); err = true; return; } else { #region Iterating Variable //Its a range var lowNum = stmt.Nodes[i + 2]; //Name is mis-informing. This is really the first number. var highNum = stmt.Nodes[i + 5]; //Same ^^, this is the second number. LocalBuilderEx local = new LocalBuilderEx(); local.LoopHigh = int.Parse(highNum.Token.Text); local.LoopLow = int.Parse(lowNum.Token.Text); local.Name = token.Token.Text; local.Type = LocalType.LoopVar; local.VariableType = typeof(int); var looplab = ILgen.DefineLabel(); ILgen.BeginScope(); local.Base = ILgen.DeclareLocal(local.VariableType); local.LoopLabel = looplab; if (IsDebug) local.Base.SetLocalSymInfo(token.Token.Text); //Set variable name for debug info. ILgen.Emit(OpCodes.Ldc_I4, local.LoopLow); //Sets the number ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable. ILgen.MarkLabel(looplab); //this is where the IL will execute. local.LoopAction = () => { //Updates the iterator by 1 ILgen.Emit(OpCodes.Ldloc, local.Base); ILgen.Emit(OpCodes.Ldc_I4_1); if (local.LoopLow < local.LoopHigh) { ILgen.Emit(OpCodes.Add); //Loop up local.LoopDirection = LoopDirectionEnum.Up; } else if (local.LoopLow > local.LoopHigh) { ILgen.Emit(OpCodes.Sub); //Loop down. local.LoopDirection = LoopDirectionEnum.Down; } else { dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: Variable '{0}' should be set as {1}. In this case, looping is not allowed. Line: {2}, Col: {3}", local.Name, local.LoopLow.ToString(), info.Line, info.Col); return true; //Abort because of error. } ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); ILgen.EndScope(); return false; }; locals.Add(local); //Remembers the variable. i += 6; #endregion } } } else { //Report an error and stop compile process. dynamic info = GetLineAndCol(code, stmt.Token.StartPos); err = true; Console.Error.WriteLine("Error: '{0}' already exist! Line: {1}, Col: {2}", token.Token.Text, info.Line, info.Col); return; } } } break; #endregion } case TokenType.PrintStatement: { #region Printing if (IsDebug) { int sline = 0, scol = 0; FindLineAndCol(code, stmt.Token.StartPos, ref sline, ref scol); int eline = 0, ecol = 0; FindLineAndCol(code, stmt.Token.EndPos, ref eline, ref ecol); ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol); } ///Generates output by making a print statement. var period = stmt.Nodes[0]; var outpt = stmt.Nodes[1]; switch (outpt.Token.Type) { case TokenType.IDENTIFIER: { //Prints a variable. LocalBuilderEx local = locals.Find(it => it.Name == outpt.Token.Text); if (local == null) { dynamic info = GetLineAndCol(code, stmt.Token.StartPos); err = true; Console.Error.WriteLine("Error: '{0}' doesn't exist! Line: {1}, Col: {2}", outpt.Token.Text, info.Line, info.Col); return; } ILgen.Emit(OpCodes.Ldloc, local.Base); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { local.VariableType })); //Converts the integer to a string. ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //Prints the newly formed string. break; } case TokenType.FLOAT: case TokenType.NUMBER: { //Prints a integer or float (decimal) number. if (outpt.Token.Type == TokenType.NUMBER) //if its a integer { ILgen.Emit(OpCodes.Ldc_I4, int.Parse(outpt.Token.Text)); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) })); //Converts the integer to a string. } else { //Otherwise, its a float (decimal). ILgen.Emit(OpCodes.Ldc_R4, float.Parse(outpt.Token.Text)); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(float) })); //Converts the integer to a string. } ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //Prints the newly formed string. break; } case TokenType.STRING: { //Prints just a plain string. See the next case for a format string. string formt = outpt.Token.Text.Substring(1); formt = formt.Remove(formt.Length - 1); //Removes surrounding quotes. ILgen.Emit(OpCodes.Ldstr, formt); //Loads the string onto the stack ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //Prints the newly formed string. break; } case TokenType.SIN: { //Prints a format string ParseNode formtnd = stmt.Nodes[2]; string formt = formtnd.Token.Text.Substring(1); formt = formt.Remove(formt.Length - 1); //Removes surrounding quotes. ILgen.Emit(OpCodes.Ldstr, formt); //Loads the format string. int arrymax = (stmt.Nodes.Count / 2 - 1); ILgen.Emit(OpCodes.Ldc_I4, arrymax); ILgen.Emit(OpCodes.Newarr, typeof(string)); int arry_i = 0; for (int i = 3; i < stmt.Nodes.Count; i++) { if (stmt.Nodes[i].Token.Type == TokenType.WHITESPACE) { if (stmt.Nodes.Count - 1 == i) break; continue; } else if (stmt.Nodes[i].Token.Type == TokenType.PERIOD) { break; } else { ParseNode nd = stmt.Nodes[i]; ILgen.Emit(OpCodes.Dup); ILgen.Emit(OpCodes.Ldc_I4, arry_i); switch (nd.Token.Type) { case TokenType.IDENTIFIER: { LocalBuilderEx local = locals.Find(it => it.Name == nd.Token.Text); if (local == null) { err = true; Console.Error.WriteLine("Error: '{0}' doesn't exist!", nd.Token.Text); return; } ILgen.Emit(OpCodes.Ldloc, local.Base); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) })); break; } case TokenType.NUMBER: { ILgen.Emit(OpCodes.Ldc_I4, int.Parse(nd.Token.Text)); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) })); break; } } ILgen.Emit(OpCodes.Stelem_Ref); arry_i += 1; } } ILgen.Emit(OpCodes.Call, typeof(System.String).GetMethod("Format", new Type[] { typeof(string), typeof(string[]) })); ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //Prints the newly formed string. break; } } break; #endregion } case TokenType.EvalStatement: { #region EvalStatement var identifier = stmt.Nodes[1]; var expr = stmt.Nodes[3]; LocalBuilderEx local = new LocalBuilderEx(); //Check if a variable of the same name exist. LocalBuilderEx lct = locals.Find(it => it.Name == identifier.Token.Text); if (lct != null) { //Variable exist, stop compiling. dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: {0} variable already exist! Line: {1}, Col: {2}", identifier.Token.Text, info.Line, info.Col); if (lct.Type == LocalType.LoopVar) Console.Error.WriteLine("- Error: Iterating variables are readonly!"); err = true; return; } if (!NoEval) { #region Eval using Mizu.Lib.Evaluator local.VariableType = typeof(int); local.Base = ILgen.DeclareLocal(local.VariableType); //Sets the number var exprstr = ""; bool localsadded = false; List<LocalBuilder> tmplocals = new List<LocalBuilder>(); foreach (LocalBuilderEx lc in locals) { ILgen.Emit(OpCodes.Ldstr, "var " + lc.Name + "={0}"); ILgen.Emit(OpCodes.Ldloc, (LocalBuilder)lc.Base); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) })); ILgen.Emit(OpCodes.Call, typeof(System.String).GetMethod("Format", new Type[] { typeof(string), typeof(string) })); LocalBuilder lb = ILgen.DeclareLocal(typeof(string)); ILgen.Emit(OpCodes.Stloc, lb); tmplocals.Add(lb); localsadded = true; } //Creates an array to store all of the variables for the String.Concat call. int arrymax = (tmplocals.Count * 2) + 1; ILgen.Emit(OpCodes.Ldc_I4, arrymax); ILgen.Emit(OpCodes.Newarr, typeof(string)); int arry_i = 0; if (localsadded) { foreach (LocalBuilder tmploc in tmplocals) { ILgen.Emit(OpCodes.Dup); ILgen.Emit(OpCodes.Ldc_I4, arry_i); ILgen.Emit(OpCodes.Ldloc, tmploc); ILgen.Emit(OpCodes.Stelem_Ref); arry_i += 1; ILgen.Emit(OpCodes.Dup); ILgen.Emit(OpCodes.Ldc_I4, arry_i); ILgen.Emit(OpCodes.Ldstr, ";"); ILgen.Emit(OpCodes.Stelem_Ref); arry_i += 1; } } ILgen.Emit(OpCodes.Dup); ILgen.Emit(OpCodes.Ldc_I4, arry_i); exprstr += GenerateExprStr(expr); ILgen.Emit(OpCodes.Ldstr, exprstr); ILgen.Emit(OpCodes.Stelem_Ref); arry_i += 1; ILgen.Emit(OpCodes.Call, typeof(System.String).GetMethod("Concat", new Type[] { typeof(string[]) })); ILgen.Emit(OpCodes.Call, typeof(Mizu.Lib.Evaluator.Evaluator).GetMethod("Eval")); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new Type[] { typeof(string) })); //Parses it into an integer. ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable. #endregion } else { if (ExprStrHasVar(expr)) { HandleMathExpr(ILgen, locals, expr); local.VariableType = typeof(float); local.Base = ILgen.DeclareLocal(local.VariableType); //Sets the number; } else { //Optimize. If the equation is constant, might as well calculate the result and place it in the code. var res = Mizu.Lib.Evaluator.Evaluator.Eval(GenerateExprStr(expr)); if (res.Contains(".")) { local.VariableType = typeof(float); local.Base = ILgen.DeclareLocal(local.VariableType); //Sets the number ILgen.Emit(OpCodes.Ldc_R4, float.Parse(res)); } else { local.VariableType = typeof(int); local.Base = ILgen.DeclareLocal(local.VariableType); //Sets the number ILgen.Emit(OpCodes.Ldc_I4, int.Parse(res)); } } ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable. } if (IsDebug) local.Base.SetLocalSymInfo(identifier.Token.Text); local.Name = identifier.Token.Text; local.Type = LocalType.Var; locals.Add(local); //Remembers the variable. break; #endregion } case TokenType.MathCMDStatement: { #region MathCommandStatement var cmd = stmt.Nodes[0]; var input = stmt.Nodes[2]; var local = locals.Find(it => it.Name == input.Token.Text); if (local != null) { if (IsDebug) { int sline = 0, scol = 0; FindLineAndCol(code, cmd.Token.StartPos, ref sline, ref scol); int eline = 0, ecol = 0; FindLineAndCol(code, cmd.Token.EndPos, ref eline, ref ecol); ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol); } switch (cmd.Token.Type) { case TokenType.SQRT: { ILgen.Emit(OpCodes.Ldloca, local.Base); ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Sqrt")); ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); break; } case TokenType.SIN: { ILgen.Emit(OpCodes.Ldloca, local.Base); ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Sin")); ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); break; } case TokenType.ABS: { ILgen.Emit(OpCodes.Ldloca, local.Base); ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Abs", new Type[] { typeof(int) })); ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); break; } case TokenType.TAN: { ILgen.Emit(OpCodes.Ldloca, local.Base); ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Tan")); ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); break; } case TokenType.COS: { ILgen.Emit(OpCodes.Ldloca, local.Base); ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Cos")); ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); break; } } } else { //Report an error and stop compile process. dynamic info = GetLineAndCol(code, stmt.Token.StartPos); err = true; Console.Error.WriteLine("Error: '{0}' doesn't exist! Line: {1}, Col: {2}", input.Token.Text, info.Line, info.Col); return; } break; #endregion } case TokenType.BlockedStatement: { //Due to parser limitations, I have to handle this token in order for both the if blocks and the switch blocks to begin with [. HandleStatement(stmt.Nodes[1], ILgen, ref locals, out err); break; } case TokenType.IfStatement: //If block { #region If Statement bool hasElse = false; var left = stmt.Nodes[0]; var com = stmt.Nodes[1]; var right = stmt.Nodes[2]; if (IsDebug) { int sline = 0, scol = 0; FindLineAndCol(code, left.Token.StartPos, ref sline, ref scol); int eline = 0, ecol = 0; FindLineAndCol(code, right.Token.EndPos, ref eline, ref ecol); ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol); } var bodies = stmt.Nodes.FindAll(it => it.Token.Type == TokenType.Statements); hasElse = bodies.Count == 2; //Load the 'left' hand type onto the stack. HandleDataToken(ILgen, locals, left, out err); //Load the 'right' hand type to the stack. HandleDataToken(ILgen, locals, right, out err); //Load the 'comparison' function onto the stack. HandleDataToken(ILgen, locals, com, out err); Label endofifblock = ILgen.DefineLabel(); Label ifbodyloc = ILgen.DefineLabel(); Label elsebodyloc = ILgen.DefineLabel(); if (!hasElse) { //No else block. ILgen.Emit(OpCodes.Brfalse, endofifblock); } else { //Has an else block. //ILgen.Emit(OpCodes.Brtrue, ifbodyloc); //ILgen.Emit(OpCodes.Brtrue, ifbodyloc); ILgen.Emit(OpCodes.Brfalse, elsebodyloc); //ILgen.Emit(OpCodes.Br, ifbodyloc); } // Handle the first body of an if statement. ILgen.MarkLabel(ifbodyloc); ILgen.BeginScope(); var ifbody = bodies[0]; List<LocalBuilderEx> ifbody_locals = new List<LocalBuilderEx>(); locals.ForEach((it) => ifbody_locals.Add(it)); foreach (ParseNode pn in ifbody.Nodes) { bool iferr = false; HandleStatement(pn.Nodes[0], ILgen, ref ifbody_locals, out iferr); if (iferr) { err = true; return; } } ILgen.Emit(OpCodes.Br, endofifblock); ILgen.EndScope(); //Handle the else bit (if any) if (hasElse) { ILgen.MarkLabel(elsebodyloc); ILgen.BeginScope(); var elsebody = bodies[1]; List<LocalBuilderEx> elsebody_locals = new List<LocalBuilderEx>(); locals.ForEach((it) => elsebody_locals.Add(it)); foreach (ParseNode pn in elsebody.Nodes) { bool elerr = false; HandleStatement(pn.Nodes[0], ILgen, ref elsebody_locals, out elerr); if (elerr) { err = true; return; } } ILgen.Emit(OpCodes.Br, endofifblock); ILgen.EndScope(); } ILgen.MarkLabel(endofifblock); break; #endregion } case TokenType.SwitchStatement: //Switch block { #region Switch Statement Label endofswitch = ILgen.DefineLabel(); SwitchCaseInfo defaultcase = new SwitchCaseInfo() { Label = ILgen.DefineLabel() }; List<SwitchCaseInfo> caselist = new List<SwitchCaseInfo>(); bool hasDefault = false; var ident = stmt.Nodes[1]; var compar = new Comparison<ParseNode>((node1, node2) => { try { if (node1 == node2) { return 0; } else if (node1.Nodes[0].Token.Type == TokenType.NUMBER) { return -1; } else { return 1; } } catch (Exception) { return 0; } }); var cases = stmt.Nodes.FindAll(it => it.Token.Type == TokenType.SwitchCaseStatement); cases.Sort(compar); var addedcases = new List<int>(); if (IsDebug) { int sline = 0, scol = 0; FindLineAndCol(code, ident.Token.StartPos, ref sline, ref scol); int eline = 0, ecol = 0; FindLineAndCol(code, ident.Token.EndPos, ref eline, ref ecol); ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol); } foreach (ParseNode casen in cases) { SwitchCaseInfo caseinfo = new SwitchCaseInfo(); var casename = casen.Nodes[0]; if (casename.Token.Text == "*") { defaultcase.Node = casen; defaultcase.CaseName = casename; defaultcase.CaseType = SwitchCase_TypeEnum.Default; if (hasDefault == true) { //Report an error and stop compile process. err = true; dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: Switch block already has a default case. Line: {0}, Col: {1}", info.Line, info.Col); return; } hasDefault = true; } else { caseinfo.Number = int.Parse(casen.Nodes[0].Token.Text); caseinfo.CaseType = SwitchCase_TypeEnum.Number; caseinfo.CaseName = casename; caseinfo.Node = casen; caseinfo.Label = ILgen.DefineLabel(); if (addedcases.Contains(caseinfo.Number)) { err = true; dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: Switch block already has a case for '{0}'. Line: {1}, Col: {2}",caseinfo.Number, info.Line, info.Col); return; } addedcases.Add(caseinfo.Number); caselist.Add(caseinfo); } } foreach (SwitchCaseInfo cse in caselist) { //Build the instruction table. if (cse.CaseType == SwitchCase_TypeEnum.Number) { HandleDataToken(ILgen, locals, ident, out err); //Load identifier. HandleDataToken(ILgen, locals, cse.CaseName, out err); //Loads the number. ILgen.Emit(OpCodes.Ceq); ILgen.Emit(OpCodes.Brtrue, cse.Label); } else { ILgen.Emit(OpCodes.Br, defaultcase.Label); } } if (hasDefault == false) { //Report an error and stop compile process. err = true; dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: Switch block doesn't have a default case. Line: {0}, Col: {1}", info.Line, info.Col); return; } ///Handle default case var dcase = defaultcase.Node; ILgen.BeginScope(); List<LocalBuilderEx> d_locals = new List<LocalBuilderEx>(); locals.ForEach((it) => d_locals.Add(it)); var dstmts = dcase.Nodes.Find(it => it.Token.Type == TokenType.Statements); ILgen.MarkLabel(defaultcase.Label); foreach (ParseNode pn in dstmts.Nodes) { HandleStatement(pn.Nodes[0], ILgen, ref d_locals, out err); } ILgen.EndScope(); ILgen.Emit(OpCodes.Br, endofswitch); //Jumps out of switvch at the end of the method. //// foreach (SwitchCaseInfo inner in caselist) { ILgen.BeginScope(); List<LocalBuilderEx> tmp_locals = new List<LocalBuilderEx>(); locals.ForEach((it) => tmp_locals.Add(it)); var stmts = inner.Node.Nodes.Find(it => it.Token.Type == TokenType.Statements); ILgen.MarkLabel(inner.Label); bool ierr = false; foreach (ParseNode pn in stmts.Nodes) { HandleStatement(pn.Nodes[0], ILgen, ref tmp_locals, out ierr); } if (ierr) { err = true; return; } ILgen.EndScope(); ILgen.Emit(OpCodes.Br, endofswitch); //Jumps out of switvch at the end of the method. } ILgen.MarkLabel(endofswitch); break; #endregion } default: { //Report an error and stop compile process. err = true; dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: Unsupported statement: {0}. Line: {1}, Col: {2}", stmt.Text, info.Line, info.Col); return; } } err = false; }
/// <summary> /// Produces BetterFuck initialization code to specified generator. /// </summary> private static void ProduceInitCode(ILGenerator ilGenerator) { ilGenerator.BeginScope(); ilGenerator.DeclareLocal(typeof(Engine)); ilGenerator.Emit(OpCodes.Ldc_I4, DefaultMemorySize); var constructorInfo = typeof(Engine).GetConstructor(new[] { typeof(int) }); ilGenerator.Emit(OpCodes.Newobj, constructorInfo); ilGenerator.Emit(OpCodes.Stloc_0); }
public override void GenCode(TypeBuilder tb, MethodBuilder mb, ILGenerator cg) { Type elementType; if (Value.ReturnType.Name == "nil") elementType = Compiler.SearchType(Name); else elementType = Compiler.SearchType(Value.ReturnType.Name); Type tipoArray = elementType.MakeArrayType();//int[] LocalBuilder array = cg.DeclareLocal(tipoArray);//int[]array Length.GenCode(tb, mb, cg); cg.Emit(OpCodes.Dup); cg.Emit(OpCodes.Newarr, elementType);//int[5] cg.Emit(OpCodes.Stloc, array);//array=int[5] LocalBuilder extremoIntervalo = cg.DeclareLocal(typeof(int)); cg.Emit(OpCodes.Stloc, extremoIntervalo);//guarda el tamnno del array cg.BeginScope();//crea un nuevo scope que al final se cierrra LocalBuilder value = cg.DeclareLocal(elementType); //comienzo a llenar el array..es un for cuando lo desemsamblo System.Reflection.Emit.Label star = cg.DefineLabel(); System.Reflection.Emit.Label end = cg.DefineLabel(); LocalBuilder i = cg.DeclareLocal(typeof(int)); cg.Emit(OpCodes.Ldc_I4_0); cg.Emit(OpCodes.Stloc, i); cg.MarkLabel(star); cg.Emit(OpCodes.Ldloc, i); cg.Emit(OpCodes.Ldloc, extremoIntervalo); cg.Emit(OpCodes.Bge, end); Value.GenCode(tb, mb, cg); cg.Emit(OpCodes.Stloc, value); cg.Emit(OpCodes.Ldloc, array); cg.Emit(OpCodes.Ldloc, i); cg.Emit(OpCodes.Ldloc, value); cg.Emit(OpCodes.Stelem, value.LocalType); cg.Emit(OpCodes.Ldc_I4_1); cg.Emit(OpCodes.Ldloc, i); cg.Emit(OpCodes.Add); cg.Emit(OpCodes.Stloc, i); cg.Emit(OpCodes.Br, star); cg.MarkLabel(end); cg.EndScope(); cg.Emit(OpCodes.Ldloc, array); }
private void GenStmt(ParseTreeNode stmt, ILGenerator il, SymbolTable symbolTable, Label? exitScope = null) { if (stmt.Term.Name == "program") { if (stmt.ChildNodes.Count > 0) { this.GenStmt(stmt.ChildNodes[0].ChildNodes[0], il, symbolTable); this.GenStmt(stmt.ChildNodes[1], il, symbolTable); } } else if (stmt.Term.Name == "variableDeclaration") { Type localType; // declare a local if (stmt.ChildNodes[2].Term.Name == "typeSpecifier") { localType = this.TypeOfTypeDeclaration(stmt.ChildNodes[2].ChildNodes[0]); } else { localType = TypeOfExpr(stmt.ChildNodes[2].ChildNodes[1], symbolTable); } Action<string> generateAssign = null; ParseTreeNode assign = stmt.ChildNodes.Where(x => x.Term.Name == "setEqual").SingleOrDefault(); // set the initial value if (assign != null) { generateAssign = new Action<string>(name => { this.GenExpr(assign.ChildNodes[1], symbolTable.Locals[name].LocalType, il, symbolTable); symbolTable.Store(name, TypeOfExpr(assign.ChildNodes[1], symbolTable), il); }); } var variableIden = stmt.ChildNodes[1]; while (true) { string name = variableIden.ChildNodes[0].Token.ValueString; symbolTable.AddLocal(name, il.DeclareLocal(localType)); if (generateAssign != null) generateAssign(name); if (variableIden.ChildNodes.Count < 2) break; variableIden = variableIden.ChildNodes[1]; } } else if (stmt.Term.Name == "io") { if (stmt.ChildNodes[0].Token.ValueString == "put") { //the first argument is always there, until we can build a proper AST this'll have to do ParseTreeNode argItem = stmt.ChildNodes[1]; this.GenExpr(argItem.ChildNodes[0], typeof(string), il, symbolTable); il.Emit(OpCodes.Call, typeof(System.Console).GetMethod("Write", new System.Type[] { typeof(string) })); argItem = stmt.ChildNodes[2]; while (true) { if (argItem.ChildNodes.Count == 0) break; this.GenExpr(argItem.ChildNodes[0].ChildNodes[0], typeof(string), il, symbolTable); il.Emit(OpCodes.Call, typeof(System.Console).GetMethod("Write", new System.Type[] { typeof(string) })); argItem = argItem.ChildNodes[1]; } if (stmt.ChildNodes[3].ChildNodes.Count == 0)//put a newline character if there is no ... il.Emit(OpCodes.Call, typeof(System.Console).GetMethod("WriteLine", new System.Type[] { })); } else if (stmt.ChildNodes[0].Token.ValueString == "get") { foreach (var argument in stmt.ChildNodes[1].ChildNodes) { //switch(symbolTable.TypeOfVar( il.Emit(OpCodes.Call, typeof(System.Console).GetMethod("ReadLine", new System.Type[] { })); symbolTable.Store(argument.Token.ValueString, typeof(string), il); } } } else if (stmt.Term.Name == "assignment") { if (stmt.ChildNodes[0].Term.Name == "functionCall")//if we see this as a function call, we know that's not true, and it's actually an array (which is kinda the same thing in turing) { string arrayName = stmt.ChildNodes[0].ChildNodes[0].Token.ValueString; if (symbolTable.TypeOfVar(arrayName).IsArray) { symbolTable.PushVar(arrayName, il); if (stmt.ChildNodes[0].ChildNodes[1].ChildNodes.Count > 1) throw new NotImplementedException("Multi-Dimensional arrays are not yet supported"); this.GenExpr(stmt.ChildNodes[0].ChildNodes[1].ChildNodes[0], typeof(int), il, symbolTable); this.GenExpr(stmt.ChildNodes[1].ChildNodes[1], TypeOfExpr(stmt.ChildNodes[1].ChildNodes[1], symbolTable), il, symbolTable); il.Emit(OpCodes.Stelem, symbolTable.TypeOfVar(arrayName).GetElementType()); } else throw new NotSupportedException(String.Format("Non-array identifier used like an array: {0}", arrayName)); } else { this.GenExpr(stmt.ChildNodes[1].ChildNodes[1], TypeOfExpr(stmt.ChildNodes[1].ChildNodes[1], symbolTable), il, symbolTable); string ident = stmt.ChildNodes[0].Token.ValueString; symbolTable.Store(ident, TypeOfExpr(stmt.ChildNodes[1].ChildNodes[1], symbolTable), il); } } else if (stmt.Term.Name == "functionDefinition") { string functionName = stmt.ChildNodes[0].ChildNodes[1].Token.ValueString; SymbolTable localSymbols = new SymbolTable(symbolTable); foreach (var parameter in symbolTable.functionTable[functionName].arguments) { localSymbols.AddParameter(parameter.argName, parameter.argType); } var ilMeth = symbolTable.functionTable[functionName].GetILGenerator(); GenStmt(stmt.ChildNodes[1], ilMeth, localSymbols); ilMeth.Emit(OpCodes.Ret); } else if (stmt.Term.Name == "result") { GenExpr(stmt.ChildNodes[1], TypeOfExpr(stmt.ChildNodes[1], symbolTable), il, symbolTable); var result = il.DeclareLocal(TypeOfExpr(stmt.ChildNodes[1], symbolTable)); il.Emit(OpCodes.Stloc, result); il.Emit(OpCodes.Ldloc, result); il.Emit(OpCodes.Ret, result); } else if (stmt.Term.Name == "functionCall" | stmt.Term.Name == "memberCall") { GenExpr(stmt, null, il, symbolTable); } else if (stmt.Term.Name == "ifBlock") { Label ifTrue = il.DefineLabel(); Label ifFalse = il.DefineLabel(); Label endLabel = il.DefineLabel(); GenExpr(stmt.ChildNodes[0], typeof(bool), il, symbolTable);//expression to check if true il.Emit(OpCodes.Brtrue, ifTrue);//if true then jump to true block il.Emit(OpCodes.Br, ifFalse);//otherwise jump to false block il.MarkLabel(ifTrue);//true block GenStmt(stmt.ChildNodes[1], il, symbolTable); il.Emit(OpCodes.Br, endLabel);//jump to after false block il.MarkLabel(ifFalse);//false block if (stmt.ChildNodes[2].ChildNodes.Count > 0)//then there's an else-if, this takes place in the else section { ParseTreeNode elseBlockStmt = stmt.ChildNodes[2];//Turn the elsif to an inner if statement elseBlockStmt.ChildNodes.Add(stmt.ChildNodes[3]);//Move the optional else statement to the inner if statement elseBlockStmt.Term.Name = "ifBlock"; GenStmt(elseBlockStmt, il, symbolTable); } else if (stmt.ChildNodes[3].ChildNodes.Count > 0) GenStmt(stmt.ChildNodes[3].ChildNodes[0], il, symbolTable);//generate expresson for false section, otherwise the label will be at the same spot as the end il.MarkLabel(endLabel);//the end of the if statement } else if (stmt.Term.Name == "loop") { Label beginLoop = il.DefineLabel(); Label endLoop = il.DefineLabel(); il.MarkLabel(beginLoop); GenStmt(stmt.ChildNodes[0], il, symbolTable, endLoop); il.Emit(OpCodes.Br, beginLoop); il.MarkLabel(endLoop); } else if (stmt.Term.Name == "forLoop") { il.BeginScope(); Label beginLoop = il.DefineLabel(); Label endLoop = il.DefineLabel(); LocalBuilder i = il.DeclareLocal(typeof(int)); string identName = stmt.ChildNodes[1].Token.ValueString; symbolTable.AddLocal(identName, i); symbolTable.AddLocal("___endLoop", il.DeclareLocal(typeof(int))); if (stmt.ChildNodes[2].ChildNodes.Count == 1)//then an identifier is used as a range, or char. We just fail for now throw new NotImplementedException(); else { GenExpr(stmt.ChildNodes[2].ChildNodes[0], typeof(int), il, symbolTable); symbolTable.Store(identName, typeof(int), il); GenExpr(stmt.ChildNodes[2].ChildNodes[1], typeof(int), il, symbolTable); symbolTable.Store("___endLoop", typeof(int), il); } il.MarkLabel(beginLoop); GenStmt(stmt.ChildNodes[4], il, symbolTable, endLoop); symbolTable.PushVar(identName, il); il.Emit(OpCodes.Ldc_I4_1); if (stmt.ChildNodes[3].ChildNodes.Count > 0)//then there is a decreasing statement, so do decreasing il.Emit(OpCodes.Sub); else il.Emit(OpCodes.Add); il.Emit(OpCodes.Dup); symbolTable.Store(identName, typeof(int), il); symbolTable.PushVar("___endLoop", il); if (stmt.ChildNodes[3].ChildNodes.Count > 0)//then there is a decreasing statement, so do decreasing il.Emit(OpCodes.Bge, beginLoop); else il.Emit(OpCodes.Ble, beginLoop); il.MarkLabel(endLoop); symbolTable.RemoveLocal(identName); symbolTable.RemoveLocal("___endLoop"); il.EndScope(); } else { throw new System.Exception("don't know how to gen a " + stmt.Term.Name); } }