void ICilCompilerAware.ImplementInCil(CompilerState state, Instruction ins) { if (ins.Arguments > 0) throw new PrexoniteException("The meta command no longer accepts arguments."); state.EmitLoadLocal(state.SctxLocal); state.EmitLoadArg(CompilerState.ParamSourceIndex); var getMeta = typeof (PFunction).GetProperty("Meta").GetGetMethod(); state.Il.EmitCall(OpCodes.Callvirt, getMeta, null); state.Il.EmitCall(OpCodes.Call, Compiler.Cil.Compiler.CreateNativePValue, null); }
private static void _parseParameters(CompilerState state) { for (var i = 0; i < state.Source.Parameters.Count; i++) { var id = state.Source.Parameters[i]; var sym = state.Symbols[id]; LocalBuilder local; //Determine whether local variables for parameters have already been created and create them if necessary switch (sym.Kind) { case SymbolKind.Local: local = sym.Local ?? state.Il.DeclareLocal(typeof (PValue)); break; case SymbolKind.LocalRef: if (sym.Local == null) { local = state.Il.DeclareLocal(typeof (PVariable)); state.Il.Emit(OpCodes.Newobj, NewPVariableCtor); state.EmitStoreLocal(local); //PVariable objects already contain PValue.Null and need not be initialized if no // argument has been passed. } else { local = sym.Local; } break; default: throw new PrexoniteException("Cannot create variable to represent symbol"); } sym.Local = local; var hasArg = state.Il.DefineLabel(); var end = state.Il.DefineLabel(); if (sym.Kind == SymbolKind.Local) // var = idx < len ? args[idx] : null; { //The closure below is only accessed once. The capture is therefore transparent. // ReSharper disable AccessToModifiedClosure state.EmitStorePValue ( sym, delegate { //(idx < argc) ? args[idx] : null; state.EmitLdcI4(i); state.EmitLoadLocal(state.ArgcLocal); state.Il.Emit(OpCodes.Blt_S, hasArg); state.EmitLoadNullAsPValue(); state.Il.Emit(OpCodes.Br_S, end); state.Il.MarkLabel(hasArg); state.EmitLoadArg(CompilerState.ParamArgsIndex); state.EmitLdcI4(i); state.Il.Emit(OpCodes.Ldelem_Ref); state.Il.MarkLabel(end); } ); // ReSharper restore AccessToModifiedClosure } else // if(idx < len) var = args[idx]; { state.EmitLdcI4(i); state.EmitLoadLocal(state.ArgcLocal); state.Il.Emit(OpCodes.Bge_S, end); //The following closure is only accessed once. The capture is therefore transparent. // ReSharper disable AccessToModifiedClosure state.EmitStorePValue ( sym, delegate { state.EmitLoadArg(CompilerState.ParamArgsIndex); state.EmitLdcI4(i); state.Il.Emit(OpCodes.Ldelem_Ref); }); // ReSharper restore AccessToModifiedClosure state.Il.MarkLabel(end); } } }
private static void _analysisAndPreparation(CompilerState state) { var tempMaxOrder = 1; // var needsSharedVariables = false; foreach (var ins in state.Source.Code.InReverse()) { string toConvert; switch (ins.OpCode) { case OpCode.ldr_loci: //see ldr_loc toConvert = state.IndexMap[ins.Arguments]; goto Convert; case OpCode.ldr_loc: toConvert = ins.Id; Convert: //Normal local variables are implemented as CIL locals. // If the function uses variable references, they must be converted to reference variables. state.Symbols[toConvert].Kind = SymbolKind.LocalRef; break; case OpCode.rot: //Determine the maximum number of temporary variables for the implementation of rot[ate] var order = (int) ins.GenericArgument; if (order > tempMaxOrder) tempMaxOrder = order; break; case OpCode.newclo: MetaEntry[] entries; var func = state.Source.ParentApplication.Functions[ins.Id]; MetaEntry entry; if (func.Meta.ContainsKey(PFunction.SharedNamesKey) && (entry = func.Meta[PFunction.SharedNamesKey]).IsList) entries = entry.List; else entries = new MetaEntry[] {}; foreach (var t in entries) { var symbolName = t.Text; if (!state.Symbols.ContainsKey(symbolName)) throw new PrexoniteException (func + " does not contain a mapping for the symbol " + symbolName); //In order for variables to be shared, they too, need to be converted to reference locals. state.Symbols[symbolName].Kind = SymbolKind.LocalRef; } //Notify the compiler of the presence of closures with shared variables needsSharedVariables = needsSharedVariables || entries.Length > 0; break; } } //Create temporary variables for rotation state.TempLocals = new LocalBuilder[tempMaxOrder]; for (var i = 0; i < tempMaxOrder; i++) { var rotTemp = state.Il.DeclareLocal(typeof (PValue)); state.TempLocals[i] = rotTemp; } //Create temporary variable for argv and sharedVariables state.ArgvLocal = state.Il.DeclareLocal(typeof (PValue[])); state.SharedLocal = needsSharedVariables ? state.Il.DeclareLocal(typeof (PVariable[])) : null; //Create argc local variable and initialize it, if needed if (state.Source.Parameters.Count > 0) { state.ArgcLocal = state.Il.DeclareLocal(typeof (Int32)); state.EmitLoadArg(CompilerState.ParamArgsIndex); state.Il.Emit(OpCodes.Ldlen); state.Il.Emit(OpCodes.Conv_I4); state.EmitStoreLocal(state.ArgcLocal); } //Determine stack size at every instruction _determineStackSize(state); }
private static void _buildSymbolTable(CompilerState state) { //Create local ref variables for shared names // and populate them with the contents of the sharedVariables parameter if (state.Source.Meta.ContainsKey(PFunction.SharedNamesKey)) { var sharedNames = state.Source.Meta[PFunction.SharedNamesKey].List; for (var i = 0; i < sharedNames.Length; i++) { if (state.Source.Variables.Contains(sharedNames[i])) continue; //Arguments are redeclarations. var sym = new CilSymbol(SymbolKind.LocalRef) { Local = state.Il.DeclareLocal(typeof (PVariable)) }; var id = sharedNames[i].Text; state.EmitLoadArg(CompilerState.ParamSharedVariablesIndex); state.Il.Emit(OpCodes.Ldc_I4, i); state.Il.Emit(OpCodes.Ldelem_Ref); state.EmitStoreLocal(sym.Local.LocalIndex); state.Symbols.Add(id, sym); } } //Create index -> id map foreach (var mapping in state.Source.LocalVariableMapping) state.IndexMap.Add(mapping.Value, mapping.Key); //Add entries for paramters foreach (var parameter in state.Source.Parameters) if (!state.Symbols.ContainsKey(parameter)) state.Symbols.Add(parameter, new CilSymbol(SymbolKind.Local)); //Add entries for enumerator variables foreach (var hint in state._ForeachHints) { if (state.Symbols.ContainsKey(hint.EnumVar)) throw new PrexoniteException( "Invalid foreach hint. Enumerator variable is shared."); state.Symbols.Add(hint.EnumVar, new CilSymbol(SymbolKind.LocalEnum)); } //Add entries for non-shared local variables foreach (var variable in state.Source.Variables) if (!state.Symbols.ContainsKey(variable)) state.Symbols.Add(variable, new CilSymbol(SymbolKind.Local)); }
private static void _emitCilImplementationHeader(CompilerState state) { //Create local cil function stack context // CilFunctionContext cfctx = CilFunctionContext.New(sctx, source); state.SctxLocal = state.Il.DeclareLocal(typeof (CilFunctionContext)); state.EmitLoadArg(CompilerState.ParamSctxIndex); state.EmitLoadArg(CompilerState.ParamSourceIndex); state.Il.EmitCall(OpCodes.Call, CilFunctionContext.NewMethod, null); state.EmitStoreLocal(state.SctxLocal.LocalIndex); //Initialize result and assign default return mode // Result = null; state._EmitAssignReturnMode(ReturnMode.Exit); state.EmitLoadArg(CompilerState.ParamResultIndex); state.EmitLoadNullAsPValue(); state.Il.Emit(OpCodes.Stind_Ref); }
private static void _emitLoadArgV(CompilerState state) { state.EmitLoadArg(CompilerState.ParamArgsIndex); state.Il.Emit(OpCodes.Newobj, NewPValueListCtor); state.Il.EmitCall(OpCodes.Call, GetPTypeListMethod, null); state.Il.Emit(OpCodes.Newobj, NewPValue); }