public override void Process(LOLMethod lm, CompilerErrorCollection errors, ILGenerator gen) { breakIdx = lm.breakables.Count - 1; if (label == null) { while (breakIdx >= 0 && !lm.breakables[breakIdx].ContinueLabel.HasValue) { breakIdx--; } } else { while (breakIdx >= 0 && (lm.breakables[breakIdx].Name != label || !lm.breakables[breakIdx].ContinueLabel.HasValue)) { breakIdx--; } } if (breakIdx < 0) { if (label == null) { errors.Add(new CompilerError(location.filename, location.startLine, location.startColumn, null, "MOAR encountered, but nothing to continue!")); } else { errors.Add(new CompilerError(location.filename, location.startLine, location.startColumn, null, string.Format("Named MOAR \"{0}\" encountered, but nothing by that name exists to continue!", label))); } } }
public override void Emit(LOLMethod lm, ILGenerator gen) { location.MarkSequencePoint(gen); //Get the appropriate stream if (stderr) { gen.EmitCall(OpCodes.Call, typeof(Console).GetProperty("Error", BindingFlags.Public | BindingFlags.Static).GetGetMethod(), null); } else { gen.EmitCall(OpCodes.Call, typeof(Console).GetProperty("Out", BindingFlags.Public | BindingFlags.Static).GetGetMethod(), null); } //Get the message message.Emit(lm, typeof(object), gen); //Indicate if it requires a newline or not if (newline) { gen.Emit(OpCodes.Ldc_I4_1); } else { gen.Emit(OpCodes.Ldc_I4_0); } gen.EmitCall(OpCodes.Call, typeof(stdlol.Utils).GetMethod("PrintObject"), null); }
public override void Emit(LOLMethod lm, ILGenerator gen) { location.MarkSequencePoint(gen); dest.StartSet(lm, typeof(string), gen); gen.EmitCall(OpCodes.Call, typeof(Console).GetProperty("In", BindingFlags.Public | BindingFlags.Static).GetGetMethod(), null); switch (amount) { case IOAmount.Letter: gen.EmitCall(OpCodes.Callvirt, typeof(TextReader).GetMethod("Read", new Type[0]), null); gen.EmitCall(OpCodes.Call, typeof(char).GetMethod("ToString", new Type[] { typeof(char) }), null); break; case IOAmount.Word: gen.EmitCall(OpCodes.Call, typeof(stdlol.Utils).GetMethod("ReadWord"), null); break; case IOAmount.Line: gen.EmitCall(OpCodes.Callvirt, typeof(TextReader).GetMethod("ReadLine", new Type[0]), null); break; } dest.EndSet(lm, typeof(string), gen); }
public override void Emit(LOLMethod lm, ILGenerator gen) { foreach (Statement stat in statements) { stat.Emit(lm, gen); } }
public override void Process(LOLMethod lm, CompilerErrorCollection errors, ILGenerator gen) { foreach (Statement stat in statements) { stat.Process(lm, errors, gen); } }
public override void Emit(LOLMethod lm, Type t, ILGenerator gen) { if (vars.Length == 0) { //Just output the string gen.Emit(OpCodes.Ldstr, str); } else { //Output a call to string.Format gen.Emit(OpCodes.Ldstr, str); gen.Emit(OpCodes.Ldc_I4, vars.Length); gen.Emit(OpCodes.Newarr, typeof(object)); for (int i = 0; i < vars.Length; i++) { gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Ldc_I4, i); vars[i].EmitGet(lm, vars[i].EvaluationType, gen); gen.Emit(OpCodes.Stelem, vars[i].EvaluationType); } gen.EmitCall(OpCodes.Call, typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object[]) }), null); } }
private void EmitIntegerJumpTable(LOLMethod lm, ILGenerator gen) { int len = ((int)sortedCases[sortedCases.Length - 1].name) - ((int)sortedCases[0].name) + 1; int offset = (int)sortedCases[0].name; if (offset < len / 2) { len += offset; offset = 0; } Label[] jumpTable = new Label[len]; int casePtr = 0; if (offset > 0) { gen.Emit(OpCodes.Ldc_I4, offset); gen.Emit(OpCodes.Sub); } for (int i = 0; i < len; i++) { if (((int)sortedCases[casePtr].name) == i + offset) { jumpTable[i] = sortedCases[casePtr++].label = gen.DefineLabel(); } else { jumpTable[i] = defaultLabel; } } gen.Emit(OpCodes.Switch, jumpTable); }
public override void Emit(LOLMethod lm, Type t, ILGenerator gen) { exp.Emit(lm, destType, gen); if (destType != t) { Expression.EmitCast(gen, destType, t); } }
public override void Emit(LOLMethod lm, ILGenerator gen) { location.MarkSequencePoint(gen); lval.StartSet(lm, rval.EvaluationType, gen); rval.Emit(lm, rval.EvaluationType, gen); lval.EndSet(lm, rval.EvaluationType, gen); }
public override void Process(LOLMethod lm, CompilerErrorCollection errors, ILGenerator gen) { if (value.GetType() != typeof(int) && value.GetType() != typeof(string)) { //We throw an exception here because this would indicate an issue with the compiler, not with the code being compiled. throw new InvalidOperationException("PrimitiveExpression values must be int or string."); } return; }
public override void Process(LOLMethod lm, CompilerErrorCollection errors, ILGenerator gen) { m_breakLabel = gen.DefineLabel(); if (defaultCase != null) { defaultLabel = gen.DefineLabel(); } Type t = null; foreach (Case c in cases) { if (c.name.GetType() != t) { if (t != null) { errors.Add(new CompilerError(location.filename, location.startLine, location.startColumn, null, "A WTF statement cannot have OMGs with more than one type")); break; } else { t = c.name.GetType(); } } } if (t != typeof(int) && t != typeof(string)) { errors.Add(new CompilerError(location.filename, location.startLine, location.startColumn, null, "OMG labels must be NUMBARs or YARNs")); } //Sort the cases sortedCases = new Case[cases.Count]; cases.CopyTo(sortedCases); Array.Sort <Case>(sortedCases); //Check for duplicates for (int i = 1; i < sortedCases.Length; i++) { if (sortedCases[i - 1].CompareTo(sortedCases[i]) == 0) { errors.Add(new CompilerError(location.filename, location.startLine, location.startColumn, null, string.Format("Duplicate OMG label: \"{0}\"", sortedCases[i].name))); } } //Process child statements lm.breakables.Add(this); control.Process(lm, errors, gen); foreach (Case c in cases) { c.statement.Process(lm, errors, gen); } defaultCase.Process(lm, errors, gen); lm.breakables.RemoveAt(lm.breakables.Count - 1); }
private void EmitStringSwitch(LOLMethod lm, ILGenerator gen) { LocalBuilder loc = lm.GetTempLocal(gen, typeof(string)); gen.Emit(OpCodes.Stloc, loc); EmitSwitchTree(lm, gen, 0, sortedCases.Length, loc, delegate(ILGenerator ig, Case c) { ig.Emit(OpCodes.Ldstr, (string)c.name); ig.EmitCall(OpCodes.Call, typeof(string).GetMethod("Compare", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(string), typeof(string) }, null), null); }); lm.ReleaseTempLocal(loc); }
public override void Emit(LOLMethod lm, Type t, ILGenerator gen) { if (value is int && t == typeof(string)) { value = ((int)value).ToString(); } if (value is float && t == typeof(string)) { value = ((float)value).ToString(); } if (value is string && t == typeof(int)) { value = int.Parse((string)value); } if (value is string && t == typeof(float)) { value = float.Parse((string)value); } if (value.GetType() != t && t != typeof(object)) { throw new ArgumentException(string.Format("{0} encountered, {1} expected.", value.GetType().Name, t.Name)); } if (value is int) { gen.Emit(OpCodes.Ldc_I4, (int)value); if (t == typeof(object)) { gen.Emit(OpCodes.Box, typeof(int)); } } else if (value is float) { gen.Emit(OpCodes.Ldc_R4, (float)value); if (t == typeof(object)) { gen.Emit(OpCodes.Box, typeof(float)); } } else if (value is string) { gen.Emit(OpCodes.Ldstr, (string)value); if (t == typeof(object)) { gen.Emit(OpCodes.Castclass, typeof(object)); } } }
public override void Process(LOLMethod lm, CompilerErrorCollection errors, ILGenerator gen) { if (arguments.Count != func.Arity && !func.IsVariadic) { errors.Add(new CompilerError(location.filename, location.startLine, location.startColumn, null, string.Format("Function \"{0}\" requires {1} arguments, passed {2}.", func.Name, func.Arity, arguments.Count))); } else if (arguments.Count < func.Arity && func.IsVariadic) { errors.Add(new CompilerError(location.filename, location.startLine, location.startColumn, null, string.Format("Function \"{0}\" requires at least {1} arguments, passed {2}.", func.Name, func.Arity, arguments.Count))); } foreach (Expression arg in arguments) { arg.Process(lm, errors, gen); } }
public override void EmitGet(LOLMethod lm, Type t, ILGenerator gen) { if (var is LocalRef) { if (t == typeof(Dictionary <object, object>)) { gen.Emit(OpCodes.Ldloca, (var as LocalRef).Local); gen.EmitCall(OpCodes.Call, typeof(stdlol.Utils).GetMethod("ToDict"), null); } else { gen.Emit(OpCodes.Ldloc, (var as LocalRef).Local); } } else if (var is GlobalRef) { if (t == typeof(Dictionary <object, object>)) { gen.Emit(OpCodes.Ldnull); gen.Emit(OpCodes.Ldflda, (var as GlobalRef).Field); gen.EmitCall(OpCodes.Call, typeof(stdlol.Utils).GetMethod("ToDict"), null); } else { gen.Emit(OpCodes.Ldnull); gen.Emit(OpCodes.Ldfld, (var as GlobalRef).Field); } } else if (var is ArgumentRef) { if (t == typeof(Dictionary <object, object>)) { gen.Emit(OpCodes.Ldarga, (var as ArgumentRef).Number); gen.EmitCall(OpCodes.Call, typeof(stdlol.Utils).GetMethod("ToDict"), null); } else { gen.Emit(OpCodes.Ldarg, (var as ArgumentRef).Number); } } else { throw new InvalidOperationException("Unknown variable type"); } Expression.EmitCast(gen, var.Type, t); }
public override void Emit(LOLMethod lm, ILGenerator gen) { //Create the loop variable if it's defined /*if (operation != null) * lm.DefineLocal(gen, ((operation as AssignmentStatement).lval as VariableLValue).var as LocalRef);*/ lm.breakables.Add(this); gen.MarkLabel(m_continueLabel); //Evaluate the condition (if one exists) if (condition != null) { condition.Emit(lm, typeof(bool), gen); if (type == LoopType.While) { gen.Emit(OpCodes.Brfalse, m_breakLabel); } else if (type == LoopType.Until) { gen.Emit(OpCodes.Brtrue, m_breakLabel); } else { throw new InvalidOperationException("Unknown loop type"); } } //lm.BeginScope(gen); //Emit the loop body statements.Emit(lm, gen); //lm.EndScope(gen); //Emit the loop op (if one exists) if (operation != null) { operation.Emit(lm, gen); } gen.Emit(OpCodes.Br, m_continueLabel); gen.MarkLabel(m_breakLabel); lm.breakables.RemoveAt(lm.breakables.Count - 1); }
public override void Process(LOLMethod lm, CompilerErrorCollection errors, ILGenerator gen) { if (operation != null) { FunctionRef fr = ((operation as AssignmentStatement).rval as FunctionExpression).func; if (fr.Arity > 1 || (fr.IsVariadic && fr.Arity != 0)) { errors.Add(new CompilerError(location.filename, location.startLine, location.startColumn, null, "Function used in loop must take 1 argument")); } } m_breakLabel = gen.DefineLabel(); m_continueLabel = gen.DefineLabel(); lm.breakables.Add(this); statements.Process(lm, errors, gen); lm.breakables.RemoveAt(lm.breakables.Count - 1); }
public override void Emit(LOLMethod lm, ILGenerator gen) { location.MarkSequencePoint(gen); if (breakIdx < 0) { if (lm.info.ReturnType != typeof(void)) { //TODO: When we optimise functions to possibly return other values, worry about this gen.Emit(OpCodes.Ldnull); } gen.Emit(OpCodes.Ret); } else { gen.Emit(OpCodes.Br, lm.breakables[breakIdx].BreakLabel.Value); } }
private void EmitIntegerSwitch(LOLMethod lm, ILGenerator gen) { if (sortedCases.Length * 2 >= (((int)sortedCases[sortedCases.Length - 1].name) - ((int)sortedCases[0].name))) { //Switch is compact, emit a jump table EmitIntegerJumpTable(lm, gen); } else { //Switch is not compact - emit a binary tree LocalBuilder loc = lm.GetTempLocal(gen, typeof(int)); gen.Emit(OpCodes.Stloc, loc); EmitSwitchTree(lm, gen, 0, sortedCases.Length, loc, delegate(ILGenerator ig, Case c) { ig.Emit(OpCodes.Ldc_I4, (int)c.name); ig.Emit(OpCodes.Sub); }); lm.ReleaseTempLocal(loc); } }
public override void Process(LOLMethod lm, CompilerErrorCollection errors, ILGenerator gen) { ifFalse = gen.DefineLabel(); statementEnd = gen.DefineLabel(); //If there are false statements but no true statements, invert the comparison and the branches if (trueStatements is BlockStatement && ((BlockStatement)trueStatements).statements.Count == 0) { Statement temp = trueStatements; trueStatements = falseStatements; falseStatements = temp; invert = true; } condition.Process(lm, errors, gen); trueStatements.Process(lm, errors, gen); if (falseStatements != null) { falseStatements.Process(lm, errors, gen); } }
public override void Emit(LOLMethod lm, ILGenerator gen) { if (var is LocalRef) { lm.DefineLocal(gen, var as LocalRef); } if (expression != null) { expression.Emit(lm, gen); if (var is LocalRef) { gen.Emit(OpCodes.Stloc, (var as LocalRef).Local); } else { gen.Emit(OpCodes.Ldnull); gen.Emit(OpCodes.Stfld, (var as GlobalRef).Field); } } }
public override void Emit(LOLMethod lm, ILGenerator gen) { lm.breakables.Add(this); //lm.BeginScope(gen); location.MarkSequencePoint(gen); if (cases[0].name is int) { //Switch is integer control.Emit(lm, typeof(int), gen); EmitIntegerSwitch(lm, gen); } else if (cases[0].name is string) { //Switch is string control.Emit(lm, typeof(string), gen); EmitStringSwitch(lm, gen); } gen.Emit(OpCodes.Br, defaultLabel); //Output code for all the cases foreach (Case c in cases) { gen.MarkLabel(c.label); c.statement.Emit(lm, gen); } //Default case gen.MarkLabel(defaultLabel); defaultCase.Emit(lm, gen); //End of statement gen.MarkLabel(m_breakLabel); //lm.EndScope(gen); lm.breakables.RemoveAt(lm.breakables.Count - 1); }
public override void Emit(LOLMethod lm, Type t, ILGenerator gen) { if (func.IsVariadic) { //First do standard (non variadic) arguments) for (int i = 0; i < func.Arity; i++) { arguments[i].Emit(lm, func.ArgumentTypes[i], gen); } //Now any variadic arguments go into an array Type argType = func.ArgumentTypes[func.Arity].GetElementType(); gen.Emit(OpCodes.Ldc_I4, arguments.Count - func.Arity); gen.Emit(OpCodes.Newarr, argType); for (int i = func.Arity; i < arguments.Count; i++) { gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Ldc_I4, i - func.Arity); arguments[i].Emit(lm, argType, gen); gen.Emit(OpCodes.Stelem, argType); } gen.EmitCall(OpCodes.Call, func.Method, null); } else { for (int i = 0; i < arguments.Count; i++) { arguments[i].Emit(lm, func.ArgumentTypes[i], gen); } gen.EmitCall(OpCodes.Call, func.Method, null); } //Finally, make sure the return type is correct Expression.EmitCast(gen, func.ReturnType, t); }
public override void EndSet(LOLMethod lm, Type t, ILGenerator gen) { //LOLProgram.WrapObject(t, gen); Expression.EmitCast(gen, t, var.Type); //Store it if (var is LocalRef) { gen.Emit(OpCodes.Stloc, (var as LocalRef).Local); } else if (var is GlobalRef) { gen.Emit(OpCodes.Stfld, (var as GlobalRef).Field); } else if (var is ArgumentRef) { gen.Emit(OpCodes.Starg, (var as ArgumentRef).Number); } else { throw new InvalidOperationException("Unknown variable type"); } }
public override void Emit(LOLMethod lm, ILGenerator gen) { location.MarkSequencePoint(gen); condition.Emit(lm, typeof(bool), gen); if (invert) { gen.Emit(OpCodes.Brtrue, ifFalse); } else { gen.Emit(OpCodes.Brfalse, ifFalse); } //True statements //lm.BeginScope(gen); trueStatements.Emit(lm, gen); if (!(falseStatements is BlockStatement) || ((BlockStatement)falseStatements).statements.Count > 0) { gen.Emit(OpCodes.Br, statementEnd); } //lm.EndScope(gen); //False statements gen.MarkLabel(ifFalse); if (!(falseStatements is BlockStatement) || ((BlockStatement)falseStatements).statements.Count > 0) { //lm.BeginScope(gen); falseStatements.Emit(lm, gen); //lm.EndScope(gen); } //End of conditional gen.MarkLabel(statementEnd); }
public abstract void Process(LOLMethod lm, CompilerErrorCollection errors, ILGenerator gen);
private void EmitSwitchTree(LOLMethod lm, ILGenerator gen, int off, int len, LocalBuilder loc, SwitchComparisonDelegate compare) { Label branch; int idx = off + len / 2; Case c = sortedCases[idx]; c.label = gen.DefineLabel(); //Load the variable and compare it with the current case gen.Emit(OpCodes.Ldloc, loc); compare(gen, c); if (len == 1) { //If we're in a range of one, we can simplify things gen.Emit(OpCodes.Ldc_I4_0); gen.Emit(OpCodes.Beq, c.label); gen.Emit(OpCodes.Br, defaultLabel); } else if (idx == off) { //The less-than case is default, so test that last gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Ldc_I4_0); branch = gen.DefineLabel(); gen.Emit(OpCodes.Bgt, branch); gen.Emit(OpCodes.Brfalse, c.label); //Not greater and not zero - must be less gen.Emit(OpCodes.Br, defaultLabel); gen.MarkLabel(branch); gen.Emit(OpCodes.Pop); EmitSwitchTree(lm, gen, off + 1, len - 1, loc, compare); } else if (idx == off + len - 1) { //The greater-than case is default, so test that last gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Ldc_I4_0); branch = gen.DefineLabel(); gen.Emit(OpCodes.Blt, branch); gen.Emit(OpCodes.Brfalse, c.label); //Not less and not zero - must be greater gen.Emit(OpCodes.Br, defaultLabel); gen.MarkLabel(branch); gen.Emit(OpCodes.Pop); EmitSwitchTree(lm, gen, off, len - 1, loc, compare); } else { //Both branches are non-empty gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Ldc_I4_0); branch = gen.DefineLabel(); gen.Emit(OpCodes.Blt, branch); gen.Emit(OpCodes.Brfalse, c.label); //Not less and not zero - must be greater EmitSwitchTree(lm, gen, idx + 1, len - (idx - off) - 1, loc, compare); gen.MarkLabel(branch); gen.Emit(OpCodes.Pop); EmitSwitchTree(lm, gen, off, idx - off, loc, compare); } }
public override void Process(LOLMethod lm, CompilerErrorCollection errors, ILGenerator gen) { return; }
public override void Emit(LOLMethod lm, ILGenerator gen) { this.Emit(lm, typeof(object), gen); }
public abstract void Emit(LOLMethod lm, Type t, ILGenerator gen);