/// <summary> /// Binds a value at a given positional index from a low level list /// (something that uses the P6list representation). /// </summary> /// <param name="TC"></param> /// <param name="LLList"></param> /// <param name="Index"></param> /// <returns></returns> public static RakudoObject lllist_bind_at_pos(ThreadContext TC, RakudoObject LLList, RakudoObject IndexObj, RakudoObject Value) { if (LLList is P6list.Instance) { var Storage = ((P6list.Instance)LLList).Storage; var Index = Ops.unbox_int(TC, IndexObj); if (Index < Storage.Count) { Storage[Index] = Value; } else { // XXX Need some more efficient resizable array approach... // Also this is no way thread safe. while (Index > Storage.Count) Storage.Add(null); Storage.Add(Value); } return Value; } else { throw new Exception("Cannot use lllist_bind_at_pos if representation is not P6list"); } }
/// <summary> /// /// </summary> /// <param name="Object"></param> /// <param name="ClassHandle"></param> /// <param name="Name"></param> /// <param name="Value"></param> public override void bind_attribute(ThreadContext TC, RakudoObject Object, RakudoObject ClassHandle, string Name, RakudoObject Value) { var I = (Instance)Object; // Try the slot allocation first. Dictionary<string, int> ClassAllocation; int Position; if (SlotAllocation != null && SlotAllocation.TryGetValue(ClassHandle, out ClassAllocation)) if (ClassAllocation.TryGetValue(Name, out Position)) { I.SlotStorage[Position] = Value; return; } // Fall back to the spill storage. if (I.SpillStorage == null) I.SpillStorage = new Dictionary<RakudoObject, Dictionary<string, RakudoObject>>(); if (!I.SpillStorage.ContainsKey(ClassHandle)) I.SpillStorage.Add(ClassHandle, new Dictionary<string, RakudoObject>()); var ClassStore = I.SpillStorage[ClassHandle]; if (ClassStore.ContainsKey(Name)) ClassStore[Name] = Value; else ClassStore.Add(Name, Value); }
/// <summary> /// Creates an instantiation of the dispatch routine (or proto, which may /// serve as one) supplied and augments it with the provided candidates. /// It relies on being passed the instantiation of the dispatcher from the /// last outer scope that had an instantiation, and we thus take its /// candidates. This may or may not hold up in the long run; it works out /// in the Perl 6-y "you can make a new instance from any object" sense /// though, and seems more likely to get the closure semantics right than /// any of the other approaches I've considered so far. /// </summary> /// <param name="TC"></param> /// <param name="ToInstantiate"></param> /// <param name="ExtraDispatchees"></param> /// <returns></returns> public static RakudoObject create_dispatch_and_add_candidates(ThreadContext TC, RakudoObject ToInstantiate, RakudoObject ExtraDispatchees) { // Make sure we got the right things. var Source = ToInstantiate as RakudoCodeRef.Instance; var AdditionalDispatchList = ExtraDispatchees as P6list.Instance; if (Source == null || AdditionalDispatchList == null) throw new Exception("create_dispatch_and_add_candidates expects a RakudoCodeRef and a P6list"); // Clone all but SC (since it's a new object and doesn't live in any // SC yet) and dispatchees (which we want to munge). var NewDispatch = new RakudoCodeRef.Instance(Source.STable); NewDispatch.Body = Source.Body; NewDispatch.CurrentContext = Source.CurrentContext; NewDispatch.Handlers = Source.Handlers; NewDispatch.OuterBlock = Source.OuterBlock; NewDispatch.OuterForNextInvocation = Source.OuterForNextInvocation; NewDispatch.Sig = Source.Sig; NewDispatch.StaticLexPad = Source.StaticLexPad; // Take existing candidates and add new ones. NewDispatch.Dispatchees = new RakudoObject[Source.Dispatchees.Length + AdditionalDispatchList.Storage.Count]; var i = 0; for (int j = 0; j < Source.Dispatchees.Length; j++) NewDispatch.Dispatchees[i++] = Source.Dispatchees[j]; for (int j = 0; j < AdditionalDispatchList.Storage.Count; j++) NewDispatch.Dispatchees[i++] = AdditionalDispatchList.Storage[j]; return NewDispatch; }
/// <summary> /// Boxes a native string into its matching value type. /// </summary> /// <param name="Value"></param> /// <returns></returns> public static RakudoObject box_str(ThreadContext TC, string Value, RakudoObject To) { var REPR = To.STable.REPR; var Result = REPR.instance_of(TC, To); REPR.set_str(TC, Result, Value); return Result; }
/// <summary> /// Create an instance of the given object. /// </summary> /// <param name="WHAT"></param> /// <returns></returns> public override RakudoObject instance_of(ThreadContext TC, RakudoObject WHAT) { var Object = new KnowHOWInstance(WHAT.STable); Object.Methods = new Dictionary<string, RakudoObject>(); Object.Attributes = new List<RakudoObject>(); return Object; }
/// <summary> /// Checks if a routine is considered a dispatcher (that is, if it has a /// candidate list). /// </summary> /// <param name="TC"></param> /// <param name="Check"></param> /// <returns></returns> public static RakudoObject is_dispatcher(ThreadContext TC, RakudoObject Check) { var Checkee = Check as RakudoCodeRef.Instance; if (Checkee != null && Checkee.Dispatchees != null) return Ops.box_int(TC, 1, TC.DefaultBoolBoxType); else return Ops.box_int(TC, 0, TC.DefaultBoolBoxType); }
/// <summary> /// Gets the attribute with the given value. /// </summary> /// <param name="ClassHandle"></param> /// <param name="Name"></param> /// <returns></returns> public override RakudoObject get_attribute(ThreadContext TC, RakudoObject Object, RakudoObject ClassHandle, string Name) { // If no storage ever allocated, trivially no value. Otherwise, // return what we find. var I = (Instance)Object; if (I.Storage == null || !I.Storage.ContainsKey(ClassHandle)) return null; var ClassStore = I.Storage[ClassHandle]; return ClassStore.ContainsKey(Name) ? ClassStore[Name] : null; }
/// <summary> /// Gets a value at a given positional index from a low level list /// (something that uses the P6list representation). /// </summary> /// <param name="TC"></param> /// <param name="LLList"></param> /// <param name="Index"></param> /// <returns></returns> public static RakudoObject lllist_get_at_pos(ThreadContext TC, RakudoObject LLList, RakudoObject Index) { if (LLList is P6list.Instance) { return ((P6list.Instance)LLList).Storage[Ops.unbox_int(TC, Index)]; } else { throw new Exception("Cannot use lllist_get_at_pos if representation is not P6list"); } }
/// <summary> /// Gets the number of elements in a low level list (something that /// uses the P6list representation). /// </summary> /// <param name="TC"></param> /// <param name="LLList"></param> /// <returns></returns> public static RakudoObject lllist_elems(ThreadContext TC, RakudoObject LLList) { if (LLList is P6list.Instance) { return Ops.box_int(TC, ((P6list.Instance)LLList).Storage.Count, TC.DefaultIntBoxType); } else { throw new Exception("Cannot use lllist_elems if representation is not P6list"); } }
/// <summary> /// Loads a module (that is, some pre-compiled compilation unit that /// was compiled using NQP). Expects the path minus an extension /// (that is, the .dll will be added). Returns what the body of the /// compilation unit evaluated to. /// </summary> /// <param name="TC"></param> /// <param name="Path"></param> /// <returns></returns> public static RakudoObject load_module(ThreadContext TC, RakudoObject Path) { // Load the assembly and grab the first type in it. var Assembly = AppDomain.CurrentDomain.Load(Ops.unbox_str(TC, Path)); var Class = Assembly.GetTypes()[0]; // Call the Load method, passing along the current thread context // and the setting to use with it. What's returned is what the main // body of the compilation unit evaluates to. var Method = Class.GetMethod("Load", BindingFlags.NonPublic | BindingFlags.Static); return (RakudoObject)Method.Invoke(null, new object[] { TC, TC.Domain.Setting }); }
/// <summary> /// Looks up a variable in the dynamic scope. /// </summary> /// <param name="C"></param> /// <param name="Name"></param> /// <returns></returns> public static RakudoObject get_dynamic(ThreadContext TC, string Name) { var CurContext = TC.CurrentContext; while (CurContext != null) { int Index; if (CurContext.LexPad.SlotMapping.TryGetValue(Name, out Index)) return CurContext.LexPad.Storage[Index]; CurContext = CurContext.Caller; } throw new InvalidOperationException("No variable " + Name + " found in the dynamic scope"); }
/// <summary> /// Binds the given value to a lexical variable of the given name. /// </summary> /// <param name="TC"></param> /// <param name="name"></param> /// <returns></returns> public static RakudoObject bind_lex(ThreadContext TC, string Name, RakudoObject Value) { var CurContext = TC.CurrentContext; while (CurContext != null) { int Index; if (CurContext.LexPad.SlotMapping.TryGetValue(Name, out Index)) { CurContext.LexPad.Storage[Index] = Value; return Value; } CurContext = CurContext.Outer; } throw new InvalidOperationException("No variable " + Name + " found in the lexical scope"); }
/// <summary> /// Entry point to multi-dispatch over the current dispatchee list. /// </summary> /// <param name="TC"></param> /// <returns></returns> public static RakudoObject multi_dispatch_over_lexical_candidates(ThreadContext TC) { var CurOuter = TC.CurrentContext; while (CurOuter != null) { var CodeObj = CurOuter.StaticCodeObject; if (CodeObj.Dispatchees != null) { var Candidate = MultiDispatch.MultiDispatcher.FindBestCandidate(TC, CodeObj, CurOuter.Capture); return Candidate.STable.Invoke(TC, Candidate, CurOuter.Capture); } CurOuter = CurOuter.Outer; } throw new Exception("Could not find dispatchee list!"); }
/// <summary> /// Gets a value at a given key from a low level mapping (something that /// uses the P6mapping representation). /// </summary> /// <param name="TC"></param> /// <param name="LLMapping"></param> /// <param name="Key"></param> /// <returns></returns> public static RakudoObject llmapping_get_at_key(ThreadContext TC, RakudoObject LLMapping, RakudoObject Key) { if (LLMapping is P6mapping.Instance) { var Storage = ((P6mapping.Instance)LLMapping).Storage; var StrKey = Ops.unbox_str(TC, Key); if (Storage.ContainsKey(StrKey)) return Storage[StrKey]; else return null; } else { throw new Exception("Cannot use llmapping_get_at_key if representation is not P6mapping"); } }
/// <summary> /// Binds a value at a given key from a low level mapping (something that /// uses the P6mapping representation). /// </summary> /// <param name="TC"></param> /// <param name="LLMapping"></param> /// <param name="Key"></param> /// <param name="Value"></param> /// <returns></returns> public static RakudoObject llmapping_bind_at_key(ThreadContext TC, RakudoObject LLMapping, RakudoObject Key, RakudoObject Value) { if (LLMapping is P6mapping.Instance) { var Storage = ((P6mapping.Instance)LLMapping).Storage; var StrKey = Ops.unbox_str(TC, Key); if (Storage.ContainsKey(StrKey)) Storage[StrKey] = Value; else Storage.Add(StrKey, Value); return Value; } else { throw new Exception("Cannot use llmapping_bind_at_key if representation is not P6mapping"); } }
/// <summary> /// Creates a clone of the given code object, and makes its outer context /// be set to the current context. /// </summary> /// <param name="TC"></param> /// <param name="Block"></param> /// <returns></returns> public static RakudoObject new_closure(ThreadContext TC, RakudoCodeRef.Instance Block) { // Clone all but OuterForNextInvocation and SC (since it's a new // object and doesn't live in any SC yet). var NewBlock = new RakudoCodeRef.Instance(Block.STable); NewBlock.Body = Block.Body; NewBlock.CurrentContext = Block.CurrentContext; NewBlock.Dispatchees = Block.Dispatchees; NewBlock.Handlers = Block.Handlers; NewBlock.OuterBlock = Block.OuterBlock; NewBlock.Sig = Block.Sig; NewBlock.StaticLexPad = Block.StaticLexPad; // Set the outer for next invocation and return the cloned block. NewBlock.OuterForNextInvocation = TC.CurrentContext; return NewBlock; }
/// <summary> /// Binds an attribute to the given value. /// </summary> /// <param name="Object"></param> /// <param name="ClassHandle"></param> /// <param name="Name"></param> /// <param name="Value"></param> public override void bind_attribute(ThreadContext TC, RakudoObject Object, RakudoObject ClassHandle, string Name, RakudoObject Value) { // If no storage at all, allocate some. var I = (Instance)Object; if (I.Storage == null) I.Storage = new Dictionary<RakudoObject, Dictionary<string, RakudoObject>>(); if (!I.Storage.ContainsKey(ClassHandle)) I.Storage.Add(ClassHandle, new Dictionary<string, RakudoObject>()); // Now stick in the name slot for the class storage, creating if it // needed. var ClassStore = I.Storage[ClassHandle]; if (ClassStore.ContainsKey(Name)) ClassStore[Name] = Value; else ClassStore.Add(Name, Value); }
/// <summary> /// Throws the specified exception, looking for an exception handler in the /// dynamic scope. /// </summary> /// <param name="TC"></param> /// <param name="ExceptionObject"></param> /// <param name="ExceptionType"></param> /// <returns></returns> public static RakudoObject throw_dynamic(ThreadContext TC, RakudoObject ExceptionObject, RakudoObject ExceptionType) { int WantType = Ops.unbox_int(TC, ExceptionType); var CurContext = TC.CurrentContext; while (CurContext != null) { if (CurContext.StaticCodeObject != null) { var Handlers = CurContext.StaticCodeObject.Handlers; if (Handlers != null) for (int i = 0; i < Handlers.Length; i++) if (Handlers[i].Type == WantType) return Exceptions.ExceptionDispatcher.CallHandler(TC, Handlers[i].HandleBlock, ExceptionObject); } CurContext = CurContext.Caller; } Exceptions.ExceptionDispatcher.DieFromUnhandledException(TC, ExceptionObject); return null; // Unreachable; above call exits always. }
/// <summary> /// Handles the various bits of initialization that are needed. /// Probably needs some don't-dupe-this work. /// </summary> public static ThreadContext Initialize(string SettingName) { // Bootstrap the meta-model. RegisterRepresentations(); var KnowHOW = KnowHOWBootstrapper.Bootstrap(); var KnowHOWAttribute = KnowHOWBootstrapper.SetupKnowHOWAttribute(KnowHOW); // See if we're to load a setting or use the fake bootstrapping one. Context SettingContext; if (SettingName == null) { SettingContext = BootstrapSetting(KnowHOW, KnowHOWAttribute); } else { SettingContext = LoadSetting(SettingName, KnowHOW, KnowHOWAttribute); } // Cache native capture and LLCode type object. CaptureHelper.CaptureTypeObject = SettingContext.LexPad.GetByName("capture"); CodeObjectUtility.LLCodeTypeObject = (RakudoCodeRef.Instance)SettingContext.LexPad.GetByName("NQPCode"); // Create an execution domain and a thread context for it. var ExecDom = new ExecutionDomain(); ExecDom.Setting = SettingContext; var Thread = new ThreadContext(); Thread.Domain = ExecDom; Thread.CurrentContext = SettingContext; Thread.DefaultBoolBoxType = SettingContext.LexPad.GetByName("NQPInt"); Thread.DefaultIntBoxType = SettingContext.LexPad.GetByName("NQPInt"); Thread.DefaultNumBoxType = SettingContext.LexPad.GetByName("NQPNum"); Thread.DefaultStrBoxType = SettingContext.LexPad.GetByName("NQPStr"); Thread.DefaultListType = SettingContext.LexPad.GetByName("NQPList"); Thread.DefaultArrayType = SettingContext.LexPad.GetByName("NQPArray"); Thread.DefaultHashType = SettingContext.LexPad.GetByName("NQPHash"); return Thread; }
/// <summary> /// Bind the attribute, using the hint if possible. /// </summary> /// <param name="Object"></param> /// <param name="ClassHandle"></param> /// <param name="Name"></param> /// <param name="Hint"></param> /// <param name="Value"></param> public override void bind_attribute_with_hint(ThreadContext TC, RakudoObject Object, RakudoObject ClassHandle, string Name, int Hint, RakudoObject Value) { var I = (Instance)Object; if (Hint < I.SlotStorage.Length) { I.SlotStorage[Hint] = Value; } else if ((Hint = hint_for(TC, ClassHandle, Name)) != Hints.NO_HINT && Hint < I.SlotStorage.Length) { I.SlotStorage[Hint] = Value; } else { if (I.SpillStorage == null) I.SpillStorage = new Dictionary<RakudoObject, Dictionary<string, RakudoObject>>(); if (!I.SpillStorage.ContainsKey(ClassHandle)) I.SpillStorage.Add(ClassHandle, new Dictionary<string, RakudoObject>()); var ClassStore = I.SpillStorage[ClassHandle]; if (ClassStore.ContainsKey(Name)) ClassStore[Name] = Value; else ClassStore.Add(Name, Value); } }
public override int get_int(ThreadContext TC, RakudoObject Object) { throw new InvalidOperationException("This type of representation cannot unbox to a native int"); }
/// <summary> /// This representation doesn't use hints, so this just delegates /// straight off to the hint-less version. /// </summary> /// <param name="ClassHandle"></param> /// <param name="Name"></param> /// <param name="Hint"></param> /// <returns></returns> public override RakudoObject get_attribute_with_hint(ThreadContext TC, RakudoObject Object, RakudoObject ClassHandle, string Name, int Hint) { return get_attribute(TC, Object, ClassHandle, Name); }
/// <summary> /// Checks if the object is defined, which boils down to "is /// this a type object", which in trun means "did we allocate /// any storage". /// </summary> /// <param name="Object"></param> /// <returns></returns> public override bool defined(ThreadContext TC, RakudoObject Object) { return ((Instance)Object).Storage != null; }
/// <summary> /// This representation doesn't do hints, so this delegates straight /// off to the hint-less version. /// </summary> /// <param name="ClassHandle"></param> /// <param name="Name"></param> /// <param name="Hint"></param> /// <param name="Value"></param> public override void bind_attribute_with_hint(ThreadContext TC, RakudoObject Object, RakudoObject ClassHandle, string Name, int Hint, RakudoObject Value) { bind_attribute(TC, Object, ClassHandle, Name, Value); }
/// <summary> /// Creates a type object that references the given HOW and /// this REPR; note we just use the singleton instance for /// all of them, since the REPR stores nothing distinct. /// </summary> /// <param name="HOW"></param> /// <returns></returns> public override RakudoObject type_object_for(ThreadContext TC, RakudoObject MetaPackage) { var STable = new SharedTable(); STable.HOW = MetaPackage; STable.REPR = this; STable.WHAT = new Instance(STable); return STable.WHAT; }
public override void set_str(ThreadContext TC, RakudoObject Object, string Value) { throw new InvalidOperationException("This type of representation cannot box a native string"); }
public override void set_num(ThreadContext TC, RakudoObject Object, double Value) { throw new InvalidOperationException("This type of representation cannot box a native num"); }
/// <summary> /// Allocates and returns a new object based upon the type object /// supplied. /// </summary> /// <param name="HOW"></param> /// <returns></returns> public override RakudoObject instance_of(ThreadContext TC, RakudoObject WHAT) { var Object = new Instance(WHAT.STable); Object.Storage = new Dictionary<RakudoObject, Dictionary<string, RakudoObject>>(); return Object; }
/// <summary> /// No hints for P6Hash. /// </summary> /// <param name="ClassHandle"></param> /// <param name="Name"></param> /// <returns></returns> public override int hint_for(ThreadContext TC, RakudoObject ClassHandle, string Name) { return Hints.NO_HINT; }
/// <summary> /// Compares two floating point numbers for greater-than inequality. /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="ResultType"></param> /// <returns></returns> public static RakudoObject greater_than_nums(ThreadContext TC, RakudoObject x, RakudoObject y) { return Ops.box_int(TC, (Ops.unbox_num(TC, x) > Ops.unbox_num(TC, y) ? 1 : 0), TC.DefaultBoolBoxType); }