private void GenerateDeclaration(IlProcessor il, ref Instruction start, ref Instruction current, ParseTreeNode node) { string name; switch (node.Term.Name) { case "VarStmt": var declarators = node.ChildNodes[1].ChildNodes; foreach (var dec in declarators) { GenerateDeclaration(il, ref start, ref current, dec); } break; case "VarExpr": name = node.ChildNodes[0].Token.ValueString; il.Add(ref current, Instruction.Create(OpCodes.Ldarg_0)); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, name)); if (node.ChildNodes.Count > 1) { GenerateExpression(il, ref start, ref current, node.ChildNodes[1].ChildNodes[1]); } else { il.Add(ref current, Instruction.Create(OpCodes.Call, undefined)); } il.Add(ref current, Instruction.Create(OpCodes.Callvirt, function_local_dec)); break; default: throw new InvalidOperationException("Term " + node.Term.Name + " is not a declaration statement"); } }
private void GenerateConst(IlProcessor il, Instruction start, ref Instruction current, ParseTreeNode node) { var obj = node.Token.Value; if (node.Token.Terminal is KeyTerm) { switch ((string)obj) { case "true": il.Add(ref current, Instruction.Create(OpCodes.Ldc_I4_1)); il.Add(ref current, Instruction.Create(OpCodes.Newobj, bool_ctor)); break; case "false": il.Add(ref current, Instruction.Create(OpCodes.Ldc_I4_0)); il.Add(ref current, Instruction.Create(OpCodes.Newobj, bool_ctor)); break; case "null": il.Add(ref current, Instruction.Create(OpCodes.Call, @null)); break; case "undefined": il.Add(ref current, Instruction.Create(OpCodes.Call, undefined)); break; default: throw new InvalidOperationException("Unknown keyword " + obj); } } else if (obj is string) { il.Add(ref current, Instruction.Create(OpCodes.Ldstr, (string)obj)); il.Add(ref current, Instruction.Create(OpCodes.Newobj, string_ctor)); } else if (obj is int || obj is long) { il.Add(ref current, Instruction.Create(OpCodes.Ldc_I8, Convert.ToInt64(obj))); il.Add(ref current, Instruction.Create(OpCodes.Newobj, number_ctor_long)); } else { throw new InvalidOperationException("Unknown constant type " + obj.GetType()); } }
private void GenerateExpression(IlProcessor il, ref Instruction start, ref Instruction current, ParseTreeNode node) { string name; LocalBuilder pn; var prev = start; switch (node.Term.Name) { case "ConstExpr": GenerateConst(il, start, ref current, node.ChildNodes[0]); break; case "BinExpr": GenerateExpression(il, ref start, ref current, node.ChildNodes[0]); // left GenerateExpression(il, ref start, ref current, node.ChildNodes[2]); // right var keySymbol = node.ChildNodes[1].Token.ValueString; switch (keySymbol) { case "+": il.Add(ref current, Instruction.Create(OpCodes.Call, value_add)); break; case "-": il.Add(ref current, Instruction.Create(OpCodes.Call, value_sub)); break; case "<": il.Add(ref current, Instruction.Create(OpCodes.Call, value_lt)); break; case ">": il.Add(ref current, Instruction.Create(OpCodes.Call, value_gt)); break; case "==": il.Add(ref current, Instruction.Create(OpCodes.Call, value_eq)); break; case "!=": il.Add(ref current, Instruction.Create(OpCodes.Call, value_neq)); break; case "*": il.Add(ref current, Instruction.Create(OpCodes.Call, value_mul)); break; case "/": il.Add(ref current, Instruction.Create(OpCodes.Call, value_div)); break; case "<=": il.Add(ref current, Instruction.Create(OpCodes.Call, value_lte)); break; case ">=": il.Add(ref current, Instruction.Create(OpCodes.Call, value_gte)); break; default: throw new InvalidOperationException("Unknown bin expression key symbol " + keySymbol); } break; case "TerExpr": // a < b ? c : d Label trueLabel = il.DefineLabel(), endLabel = il.DefineLabel(); GenerateExpression(il, ref start, ref current, node.ChildNodes[0]); // a < b il.Add(ref current, Instruction.Create(OpCodes.Call, value_istrue)); il.Add(ref current, Instruction.Create(OpCodes.Brtrue, trueLabel)); GenerateExpression(il, ref start, ref current, node.ChildNodes[3]); // d il.Add(ref current, Instruction.Create(OpCodes.Br, endLabel)); il.Add(ref current, Instruction.Create(Specials.Label, trueLabel)); GenerateExpression(il, ref start, ref current, node.ChildNodes[2]); // c il.Add(ref current, Instruction.Create(Specials.Label, endLabel)); break; case "FunctionCallExpr": pn = GetSVar(arguments); il.Add(ref prev, Instruction.Create(OpCodes.Newobj, arguments_ctor)); il.Add(ref prev, Instruction.Create(OpCodes.Stloc, pn)); foreach (var arg in node.ChildNodes[1].ChildNodes) { il.Add(ref prev, Instruction.Create(OpCodes.Ldloc, pn)); if (arg.ChildNodes.Count == 1) { il.Add(ref prev, Instruction.Create(OpCodes.Ldnull)); } else { il.Add(ref prev, Instruction.Create(OpCodes.Ldstr, arg.ChildNodes[0].Token.ValueString)); } GenerateExpression(il, ref start, ref prev, arg.ChildNodes[arg.ChildNodes.Count - 1]); il.Add(ref prev, Instruction.Create(OpCodes.Callvirt, arguments_add)); } start = prev; GenerateExpression(il, ref start, ref current, node.ChildNodes[0]); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, execute)); break; case "AssignExpr": switch (node.ChildNodes[0].Term.Name) { case "identifier": pn = GetSVar(value); if (node.ChildNodes.Count == 3) // a = b / a += b etc. { GenerateExpression(il, ref start, ref start, node.ChildNodes[2]); il.Add(ref start, Instruction.Create(OpCodes.Stloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Ldarg_0)); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, node.ChildNodes[0].Token.ValueString)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, function_local_set)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); } else { var pn2 = GetSVar(value); il.Add(ref current, Instruction.Create(OpCodes.Ldarg_0)); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, node.ChildNodes[0].Token.ValueString)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, function_local_get)); il.Add(ref current, Instruction.Create(OpCodes.Dup)); il.Add(ref current, Instruction.Create(OpCodes.Stloc, pn)); // Increment/decrement and restore if (node.ChildNodes[1].Token.ValueString == "++") { il.Add(ref current, Instruction.Create(OpCodes.Call, value_incr)); } else if (node.ChildNodes[1].Token.ValueString == "--") { il.Add(ref current, Instruction.Create(OpCodes.Call, value_decr)); } else { throw new InvalidOperationException("??"); } il.Add(ref current, Instruction.Create(OpCodes.Stloc, pn2)); il.Add(ref current, Instruction.Create(OpCodes.Ldarg_0)); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, node.ChildNodes[0].Token.ValueString)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn2)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, function_local_set)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); } break; case "MemberExpr": pn = GetSVar(value); if (node.ChildNodes.Count == 3) // a = b / a += b etc. { GenerateExpression(il, ref start, ref start, node.ChildNodes[2]); il.Add(ref start, Instruction.Create(OpCodes.Stloc, pn)); GenerateExpression(il, ref start, ref current, node.ChildNodes[0].ChildNodes[0]); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, node.ChildNodes[0].ChildNodes[2].Token.ValueString)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, set_prop)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); } else { var pn2 = GetSVar(value); GenerateExpression(il, ref start, ref start, node.ChildNodes[2]); } break; case "ArrOpExpr": pn = GetSVar(value); if (node.ChildNodes.Count == 3) // a = b / a += b etc. { GenerateExpression(il, ref start, ref start, node.ChildNodes[2]); il.Add(ref start, Instruction.Create(OpCodes.Stloc, pn)); GenerateExpression(il, ref start, ref current, node.ChildNodes[0].ChildNodes[0]); GenerateExpression(il, ref start, ref current, node.ChildNodes[0].ChildNodes[1]); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, value_lookup_set)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); } else { var pn2 = GetSVar(value); GenerateExpression(il, ref start, ref start, node.ChildNodes[2]); } break; default: throw new InvalidOperationException("Invalid QualifiedName term " + node.ChildNodes[0].Term.Name); } break; case "identifier": name = node.Token.ValueString; il.Add(ref current, Instruction.Create(OpCodes.Ldarg_0)); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, name)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, function_local_get)); break; case "FuncDefExpr": if (node.ChildNodes[1] != null && node.ChildNodes[1].Token != null && node.ChildNodes[1].Token.Text == "=>") { name = "anonymous"; var mName = MakeFunctionName(name); IEnumerable <ParseTreeNode> bodyNodes; ParseTreeNodeList parameters; if (node.ChildNodes[2].Term.Name == "Block") { bodyNodes = node.ChildNodes[2].ChildNodes[0].ChildNodes; } else if (node.ChildNodes[2].Term.Name.Contains("Stmt")) { bodyNodes = new ParseTreeNode[] { node.ChildNodes[2] }; } else { var flowCtrlStmtNode = new ParseTreeNode(grammar.FlowControlStmt, new SourceSpan()); flowCtrlStmtNode.ChildNodes.Add(new ParseTreeNode(new Token(grammar.@return, new SourceLocation(), "return", "return"))); flowCtrlStmtNode.ChildNodes.Add(node.ChildNodes[2]); bodyNodes = new ParseTreeNode[] { flowCtrlStmtNode }; } if (node.ChildNodes[0].Term.Name == "identifier") { parameters = new ParseTreeNodeList(); var param = new ParseTreeNode(grammar.Parameter, node.ChildNodes[0].Span); param.ChildNodes.Add(node.ChildNodes[0]); parameters.Add(param); } else { parameters = node.ChildNodes[0].ChildNodes; } GenerateFunction(il, ref start, ref current, name, mName, parameters, bodyNodes); } else { if (node.ChildNodes[1].ChildNodes.Count == 1) { name = node.ChildNodes[1].ChildNodes[0].Token.ValueString; } else { name = "anonymous"; } var mName = MakeFunctionName(name); GenerateFunction(il, ref start, ref current, name, mName, node.ChildNodes[2].ChildNodes, node.ChildNodes[3].ChildNodes[0].ChildNodes); } break; case "MemberExpr": GenerateExpression(il, ref start, ref current, node.ChildNodes[0]); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, node.ChildNodes[2].Token.ValueString)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, get_prop)); break; case "ObjLitExpr": pn = GetSVar(map); il.Add(ref prev, Instruction.Create(OpCodes.Newobj, map_ctor)); il.Add(ref prev, Instruction.Create(OpCodes.Stloc, pn)); if (node.ChildNodes.Count > 0) { foreach (var prop in node.ChildNodes[0].ChildNodes) { il.Add(ref prev, Instruction.Create(OpCodes.Ldloc, pn)); il.Add(ref prev, Instruction.Create(OpCodes.Ldstr, prop.ChildNodes[0].Token.ValueString)); il.Add(ref prev, Instruction.Create(OpCodes.Newobj, string_ctor)); GenerateExpression(il, ref start, ref prev, prop.ChildNodes[1]); il.Add(ref prev, Instruction.Create(OpCodes.Callvirt, map_add)); } } il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); start = prev; break; case "ArrLitExpr": pn = GetSVar(array); il.Add(ref prev, Instruction.Create(OpCodes.Newobj, array_ctor)); il.Add(ref prev, Instruction.Create(OpCodes.Stloc, pn)); if (node.ChildNodes.Count > 0) { foreach (var elm in node.ChildNodes[0].ChildNodes) { il.Add(ref prev, Instruction.Create(OpCodes.Ldloc, pn)); GenerateExpression(il, ref start, ref prev, elm); il.Add(ref prev, Instruction.Create(OpCodes.Callvirt, array_add)); } } il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); start = prev; break; case "ArrOpExpr": GenerateExpression(il, ref start, ref current, node.ChildNodes[0]); GenerateExpression(il, ref start, ref current, node.ChildNodes[1]); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, value_lookup_get)); break; default: throw new InvalidOperationException("Term " + node.Term.Name + " is not a valid expression term"); } }
private void GenerateStatement(IlProcessor il, ref Instruction current, ParseTreeNode node) { var label = CreateStatementLabel(il); var start = current; LocalBuilder pn = null, pn2 = null; il.Add(ref current, Instruction.Create(OpCodes.Nop)); switch (node.Term.Name) { case "VarStmt": GenerateDeclaration(il, ref start, ref current, node); break; case "FuncDefStmt": var name = node.ChildNodes[1].Token.ValueString; var mName = MakeFunctionName(name); il.Add(ref current, Instruction.Create(OpCodes.Ldarg_0)); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, name)); GenerateFunction(il, ref start, ref current, name, mName, node.ChildNodes[2].ChildNodes, node.ChildNodes[3].ChildNodes[0].ChildNodes); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, function_local_dec)); break; case "FlowControlStmt": var keyword = node.ChildNodes[0].Token.ValueString; switch (keyword) { case "return": if (node.ChildNodes.Count > 1) { GenerateExpression(il, ref start, ref current, node.ChildNodes[1]); } else { il.Add(ref current, Instruction.Create(OpCodes.Call, undefined)); } il.Add(ref current, Instruction.Create(OpCodes.Ret)); break; case "continue": il.Add(ref current, Instruction.Create(OpCodes.Br, GetLoopDec().ContinueLabel)); break; case "break": il.Add(ref current, Instruction.Create(OpCodes.Br, GetLoopDec().BreakLabel)); break; default: throw new InvalidOperationException("Unknown flow control keyword " + keyword); } break; case "ExprStmt": GenerateExpression(il, ref start, ref current, node.ChildNodes[0]); il.Add(ref current, Instruction.Create(OpCodes.Pop)); break; case "IfElseStmt": pn = GetSVar(sys_bool); var endLabel = il.DefineLabel(); GenerateExpression(il, ref start, ref current, node.ChildNodes[1].ChildNodes[0]); il.Add(ref current, Instruction.Create(OpCodes.Call, value_istrue)); il.Add(ref current, Instruction.Create(OpCodes.Ldc_I4_0)); il.Add(ref current, Instruction.Create(OpCodes.Ceq)); il.Add(ref current, Instruction.Create(OpCodes.Stloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); if (node.ChildNodes.Count == 5) { var elseLabel = il.DefineLabel(); il.Add(ref current, Instruction.Create(OpCodes.Brtrue, elseLabel)); GenerateStatement(il, ref current, node.ChildNodes[2]); il.Add(ref current, Instruction.Create(OpCodes.Br, endLabel)); il.Add(ref current, Instruction.Create(Specials.Label, elseLabel)); GenerateStatement(il, ref current, node.ChildNodes[4]); } else { il.Add(ref current, Instruction.Create(OpCodes.Brtrue, endLabel)); GenerateStatement(il, ref current, node.ChildNodes[2]); } il.Add(ref current, Instruction.Create(Specials.Label, endLabel)); break; case "ForStmt": AddLoopDec(il); // Push new scope pn = GetVar(scope); il.Add(ref start, Instruction.Create(Specials.BeginTotemScope, pn)); // Initializer il.Add(ref current, Instruction.Create(OpCodes.Nop)); var initializer = node.ChildNodes[1]; if (initializer.ChildNodes.Count != 0) { initializer = initializer.ChildNodes[0]; if (initializer.ChildNodes.Count == 1) { GenerateExpression(il, ref start, ref current, initializer.ChildNodes[0]); il.Add(ref current, Instruction.Create(OpCodes.Pop)); } else { foreach (var dec in initializer.ChildNodes[1].ChildNodes) { GenerateDeclaration(il, ref start, ref current, dec); } } } var conditionLabel = il.DefineLabel(); var bodyLabel = il.DefineLabel(); endLabel = il.DefineLabel(); il.Add(ref current, Instruction.Create(OpCodes.Br, conditionLabel)); // Body il.Add(ref current, Instruction.Create(Specials.Label, bodyLabel)); GenerateStatement(il, ref current, node.ChildNodes[4]); il.Add(ref current, Instruction.Create(OpCodes.Nop)); // Increment Instruction incr = il.Add(ref current, Instruction.Create(Specials.Label, GetLoopDec().ContinueLabel)); var increment = node.ChildNodes[3]; if (increment.ChildNodes.Count != 0) { GenerateExpression(il, ref start, ref current, increment.ChildNodes[0]); } // Condition il.Add(ref current, Instruction.Create(Specials.Label, conditionLabel)); var condition = node.ChildNodes[2]; if (condition.ChildNodes.Count == 0) { il.Add(ref current, Instruction.Create(OpCodes.Ldc_I4_1)); il.Add(ref current, Instruction.Create(OpCodes.Call, bool_ctor)); // Create TotemBool true } else { GenerateExpression(il, ref start, ref current, condition.ChildNodes[0]); } il.Add(ref current, Instruction.Create(OpCodes.Call, value_istrue)); il.Add(ref current, Instruction.Create(OpCodes.Brtrue, bodyLabel)); il.Add(ref current, Instruction.Create(Specials.Label, GetLoopDec().BreakLabel)); il.Add(ref current, Instruction.Create(OpCodes.Leave, endLabel)); pn2 = GetSVar(Load(typeof(bool))); // Pop scope il.Add(ref current, Instruction.Create(Specials.EndTotemScope, pn)); RemLoopDec(); RelVar(pn); il.Add(ref current, Instruction.Create(Specials.Label, endLabel)); break; case "Block": foreach (var stmt in node.ChildNodes[0].ChildNodes) { GenerateStatement(il, ref current, stmt); } break; default: throw new InvalidOperationException("Term " + node.Term.Name + " is not a statement"); } RelSVars(); il.Add(ref current, Instruction.Create(Specials.Label, label)); }
private void GenerateFunction(IlProcessor il, ref Instruction start, ref Instruction current, string name, string mName, ParseTreeNodeList parameters, IEnumerable <ParseTreeNode> body) { var fn = module.DefineType(nsp + "." + mName, r.TypeAttributes.Public | r.TypeAttributes.Sealed, function); var ctor = fn.DefineConstructor(r.MethodAttributes.Public, r.CallingConventions.Standard, new IKType[] { Load(typeof(TotemScope)), Load(typeof(string)), arr_parameters }); ctor.DefineParameter(0, r.ParameterAttributes.In, "env"); ctor.DefineParameter(1, r.ParameterAttributes.In, "name"); ctor.DefineParameter(2, r.ParameterAttributes.In, "parameters"); var ctorIl = ctor.GetILGenerator(); ctorIl.Emit(OpCodes.Ldarg_0); ctorIl.Emit(OpCodes.Ldarg_1); ctorIl.Emit(OpCodes.Ldarg_2); ctorIl.Emit(OpCodes.Ldarg_3); ctorIl.Emit(OpCodes.Call, function_ctor); ctorIl.Emit(OpCodes.Ret); var fnc = fn.DefineMethod("TotemRun", r.MethodAttributes.Family | r.MethodAttributes.HideBySig | r.MethodAttributes.Virtual, r.CallingConventions.Standard, value, IKType.EmptyTypes); using (var fnil = fnc.GetILProcessor()) { functionPoints.Push(new FunctionPoints { Avail = new HashSet <LocalBuilder>(), SVars = new HashSet <LocalBuilder>(), MethodDefinition = fnc, Il = fnil }); GenerateFunction(fnil, body); fnil.Emit(OpCodes.Nop); fnil.Emit(OpCodes.Call, undefined); fnil.Emit(OpCodes.Ret); functionPoints.Pop(); } fn.CreateType(); var pn = GetSVar(arr_parameters); var prev = start; il.Add(ref prev, Instruction.Create(OpCodes.Ldc_I4, parameters.Count)); il.Add(ref prev, Instruction.Create(OpCodes.Newarr, Generator.parameter)); il.Add(ref prev, Instruction.Create(OpCodes.Stloc, pn)); for (var i = 0; i < parameters.Count; i++) { var param = parameters[i]; il.Add(ref prev, Instruction.Create(OpCodes.Ldloc, pn)); il.Add(ref prev, Instruction.Create(OpCodes.Ldc_I4, i)); il.Add(ref prev, Instruction.Create(OpCodes.Ldstr, param.ChildNodes[0].Token.ValueString)); if (param.ChildNodes.Count > 1) { GenerateExpression(il, ref start, ref prev, param.ChildNodes[1].ChildNodes[1]); } else { il.Add(ref prev, Instruction.Create(OpCodes.Call, undefined)); } il.Add(ref prev, Instruction.Create(OpCodes.Newobj, parameter_ctor)); il.Add(ref prev, Instruction.Create(OpCodes.Stelem_Ref)); } start = prev; il.Add(ref current, Instruction.Create(OpCodes.Ldarg_0)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, function_env)); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, name)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Newobj, ctor)); }