/// <summary> /// Initializes the context. /// </summary> /// <param name="StaticCodeObject"></param> /// <param name="Caller"></param> public Context(RakudoObject StaticCodeObject_Uncast, Context Caller, RakudoObject Capture) { // Set up static code object and caller pointers. var StaticCodeObject = (RakudoCodeRef.Instance)StaticCodeObject_Uncast; this.StaticCodeObject = StaticCodeObject; this.Caller = Caller; this.Capture = Capture; // Static sub object should have this as the current // context. StaticCodeObject.CurrentContext = this; // Lex pad should be an "instantiation" of the static one. // Instantiating a lexpad creates a new dynamic instance of it // from a static one, copying over the slot storage entries // from the static one but sharing the slot mapping. this.LexPad.SlotMapping = StaticCodeObject.StaticLexPad.SlotMapping; this.LexPad.Storage = (RakudoObject[])StaticCodeObject.StaticLexPad.Storage.Clone(); // Set outer context. if (StaticCodeObject.OuterForNextInvocation != null) { this.Outer = StaticCodeObject.OuterForNextInvocation; } else if (StaticCodeObject.OuterBlock.CurrentContext != null) { this.Outer = StaticCodeObject.OuterBlock.CurrentContext; } else { // Auto-close. In this we go setting up fake contexts // that use the static lexpad until we find a real one. var CurContext = this; var OuterBlock = StaticCodeObject.OuterBlock; while (OuterBlock != null) { // If we found a block with a context, we're done. if (OuterBlock.CurrentContext != null) { CurContext.Outer = OuterBlock.CurrentContext; break; } // Build the fake context. var OuterContext = new Context(); OuterContext.StaticCodeObject = OuterBlock; OuterContext.LexPad = OuterBlock.StaticLexPad; // Link it. CurContext.Outer = OuterContext; // Step back one level. CurContext = OuterContext; OuterBlock = OuterBlock.OuterBlock; } } }
/// <summary> /// Sets up the bootstrapping setting that we use to compile the /// real setting. /// </summary> /// <param name="KnowHOW"></param> /// <returns></returns> private static Context BootstrapSetting(RakudoObject KnowHOW, RakudoObject KnowHOWAttribute) { var SettingContext = new Context(); SettingContext.LexPad = new Lexpad(new string[] { "KnowHOW", "KnowHOWAttribute", "capture", "NQPInt", "NQPNum", "NQPStr", "NQPList", "NQPCode", "list", "NQPArray", "NQPHash" }); SettingContext.LexPad.Storage = new RakudoObject[] { KnowHOW, KnowHOWAttribute, REPRRegistry.get_REPR_by_name("P6capture").type_object_for(null, null), REPRRegistry.get_REPR_by_name("P6int").type_object_for(null, null), REPRRegistry.get_REPR_by_name("P6num").type_object_for(null, null), REPRRegistry.get_REPR_by_name("P6str").type_object_for(null, null), REPRRegistry.get_REPR_by_name("P6list").type_object_for(null, null), REPRRegistry.get_REPR_by_name("RakudoCodeRef").type_object_for(null, KnowHOW.STable.REPR.instance_of(null, KnowHOW)), CodeObjectUtility.WrapNativeMethod((TC, self, C) => { var NQPList = Ops.get_lex(TC, "NQPList"); var List = NQPList.STable.REPR.instance_of(TC, NQPList) as P6list.Instance; var NativeCapture = C as P6capture.Instance; foreach (var Obj in NativeCapture.Positionals) List.Storage.Add(Obj); return List; }), null, null }; return SettingContext; }
/// <summary> /// Binds the capture against the given signature and stores the /// bound values into variables in the lexpad. /// /// XXX No type-checking is available just yet. :-( /// /// XXX No support for nameds mapping to positionals yet either. /// /// (In other words, this kinda sucks...) /// </summary> /// <param name="C"></param> /// <param name="Capture"></param> public static void Bind(ThreadContext TC, Context C, RakudoObject Capture) { // Make sure the object is really a low level capture (don't handle // otherwise yet) and grab the pieces. var NativeCapture = Capture as P6capture.Instance; if (NativeCapture == null) throw new NotImplementedException("Can only deal with native captures at the moment"); var Positionals = NativeCapture.Positionals ?? EmptyPos; var Nameds = NativeCapture.Nameds ?? EmptyNamed; Dictionary<string, bool> SeenNames = null; // See if we have to do any flattening. if (NativeCapture.FlattenSpec != null) Flatten(NativeCapture.FlattenSpec, ref Positionals, ref Nameds); // If we have no signature, that's same as an empty signature. var Sig = C.StaticCodeObject.Sig; if (Sig == null) return; // Current positional. var CurPositional = 0; // Iterate over the parameters. var Params = Sig.Parameters; var NumParams = Params.Length; for (int i = 0; i < NumParams; i++) { var Param = Params[i]; // Positional required? if (Param.Flags == Parameter.POS_FLAG) { if (CurPositional < Positionals.Length) { // We have an argument, just bind it. C.LexPad.Storage[Param.VariableLexpadPosition] = Positionals[CurPositional]; } else { throw new Exception("Not enough positional parameters; got " + CurPositional.ToString() + " but needed " + NumRequiredPositionals(C.StaticCodeObject.Sig).ToString()); } // Increment positional counter. CurPositional++; } // Positional optional? else if (Param.Flags == Parameter.OPTIONAL_FLAG) { if (CurPositional < Positionals.Length) { // We have an argument, just bind it. C.LexPad.Storage[Param.VariableLexpadPosition] = Positionals[CurPositional]; CurPositional++; } else { // Default value, vivification. // ((RakudoCodeRef.Instance)Param.DefaultValue).CurrentContext = TC.CurrentContext; C.LexPad.Storage[Param.VariableLexpadPosition] = Param.DefaultValue.STable.Invoke(TC, Param.DefaultValue, Capture); } } // Named slurpy? else if ((Param.Flags & Parameter.NAMED_SLURPY_FLAG) != 0) { var SlurpyHolder = TC.DefaultHashType.STable.REPR.instance_of(TC, TC.DefaultHashType); C.LexPad.Storage[Param.VariableLexpadPosition] = SlurpyHolder; foreach (var Name in Nameds.Keys) if (SeenNames == null || !SeenNames.ContainsKey(Name)) Ops.llmapping_bind_at_key(TC, SlurpyHolder, Ops.box_str(TC, Name, TC.DefaultStrBoxType), Nameds[Name]); } // Positional slurpy? else if ((Param.Flags & Parameter.POS_SLURPY_FLAG) != 0) { var SlurpyHolder = TC.DefaultArrayType.STable.REPR.instance_of(TC, TC.DefaultArrayType); C.LexPad.Storage[Param.VariableLexpadPosition] = SlurpyHolder; int j; for (j = CurPositional; j < Positionals.Length; j++) Ops.lllist_push(TC, SlurpyHolder, Positionals[j]); CurPositional = j; } // Named? else if (Param.Name != null) { // Yes, try and get argument. RakudoObject Value; if (Nameds.TryGetValue(Param.Name, out Value)) { // We have an argument, just bind it. C.LexPad.Storage[Param.VariableLexpadPosition] = Value; if (SeenNames == null) SeenNames = new Dictionary<string, bool>(); SeenNames.Add(Param.Name, true); } else { // Optional? if ((Param.Flags & Parameter.OPTIONAL_FLAG) == 0) { throw new Exception("Required named parameter " + Param.Name + " missing"); } else { C.LexPad.Storage[Param.VariableLexpadPosition] = Param.DefaultValue.STable.Invoke(TC, Param.DefaultValue, Capture); } } } // Otherwise, WTF? else { } } // Ensure we had enough positionals. var PossiesInCapture = Positionals.Length; if (CurPositional > PossiesInCapture) throw new Exception("Too many positional arguments passed; expected " + NumRequiredPositionals(C.StaticCodeObject.Sig).ToString() + " but got " + PossiesInCapture.ToString()); // XXX TODO; Ensure we don't have leftover nameds. }