Пример #1
0
        private void GenerateLookupPermutation(Generator generator, LoadableValue context, LookupCache cache, int index, LoadableCache[] values, LoadableValue source_reference, Block block)
        {
            if (index >= values.Length)
            {
                block(context, cache);
                generator.DebugPosition(this);
                return;
            }
            var labels = new Label[values[index].Types.Length];

            for (var it = 0; it < labels.Length; it++)
            {
                labels[it] = generator.Builder.DefineLabel();
                values[index].Value.Load(generator);
                generator.Builder.Emit(OpCodes.Isinst, values[index].Types[it]);
                generator.Builder.Emit(OpCodes.Brtrue, labels[it]);
            }
            generator.EmitTypeError(source_reference, String.Format("Expected type {0} for “{1}”, but got {2}.", String.Join(" or ", from t in values[index].Types select Stringish.NameForType(t)), values[index].NameInfo.Name, "{0}"), values[index].Value);
            for (var it = 0; it < labels.Length; it++)
            {
                generator.Builder.MarkLabel(labels[it]);
                var sub_cache = new LookupCache(cache);
                sub_cache[values[index].NameInfo] = new AutoUnboxValue(values[index].Value, values[index].Types[it]);
                var builder = generator.Builder;
                GenerateLookupPermutation(generator, context, sub_cache, index + 1, values, source_reference, block);
                generator.Builder = builder;
            }
        }
Пример #2
0
        protected LoadableValue GenerateLookupField(Generator generator, LoadableValue source_reference, LoadableValue context)
        {
            var lookup_result = generator.MakeField("lookup_" + Name, typeof(object));

            generator.LoadTaskMaster();
            generator.Builder.Emit(OpCodes.Dup);
            source_reference.Load(generator);
            var name_parts = Name.Split('.');

            generator.Builder.Emit(OpCodes.Ldc_I4, name_parts.Length);
            generator.Builder.Emit(OpCodes.Newarr, typeof(string));
            for (var it = 0; it < name_parts.Length; it++)
            {
                generator.Builder.Emit(OpCodes.Dup);
                generator.Builder.Emit(OpCodes.Ldc_I4, it);
                generator.Builder.Emit(OpCodes.Ldstr, name_parts[it]);
                generator.Builder.Emit(OpCodes.Stelem, typeof(string));
            }
            context.Load(generator);
            generator.Builder.Emit(OpCodes.Newobj, typeof(Lookup).GetConstructors()[0]);
            generator.Builder.Emit(OpCodes.Dup);
            generator.GenerateConsumeResult(lookup_result, true);
            generator.Builder.Emit(OpCodes.Call, typeof(Lookup).GetMethod("Notify", new[] { typeof(ConsumeResult) }));
            generator.Builder.Emit(OpCodes.Call, typeof(TaskMaster).GetMethod("Slot", new[] { typeof(Computation) }));
            return(lookup_result);
        }
Пример #3
0
 private void ToStringishHelperStringish(bool boxed, LoadableValue source)
 {
     source.Load(Builder);
     if (boxed)
     {
         Builder.Emit(OpCodes.Unbox_Any, typeof(Stringish));
     }
 }
Пример #4
0
 public LoadableCache(LoadableValue loadable_value, Type type, NameInfo name_info, bool must_unbox)
 {
     Value         = loadable_value;
     PossibleTypes = type;
     NameInfo      = name_info;
     Types         = AstTypeableNode.ClrTypeFromType(type);
     NeedsUnbox    = must_unbox;
 }
Пример #5
0
 private void ToStringishHelper <T>(bool boxed, LoadableValue source)
 {
     source.Load(Builder);
     if (boxed)
     {
         Builder.Emit(OpCodes.Unbox_Any, typeof(T));
     }
     Builder.Emit(OpCodes.Call, typeof(T).GetMethod("ToString", new System.Type[] { typeof(T) }));
 }
Пример #6
0
 private void ToStringishHelperBool(bool boxed, LoadableValue source)
 {
     Builder.Emit(OpCodes.Ldsfld, typeof(Stringish).GetField("BOOLEANS"));
     source.Load(Builder);
     if (boxed)
     {
         Builder.Emit(OpCodes.Unbox_Any, typeof(bool));
     }
     Builder.Emit(OpCodes.Ldelem);
 }
Пример #7
0
 /**
  * Load the key and ordinal from an iterator instance and place them in the appropriate fields.
  */
 public void LoadIteratorData(LoadableValue iterator, FieldValue key, FieldValue ordinal)
 {
     Builder.Emit(OpCodes.Ldarg_0);
     iterator.Load(Builder);
     Builder.Emit(OpCodes.Callvirt, typeof(MergeIterator).GetMethod("get_Current"));
     Builder.Emit(OpCodes.Stfld, key.Field);
     Builder.Emit(OpCodes.Ldarg_0);
     iterator.Load(Builder);
     Builder.Emit(OpCodes.Callvirt, typeof(MergeIterator).GetMethod("get_Position"));
     Builder.Emit(OpCodes.Stfld, ordinal.Field);
 }
Пример #8
0
        /**
         * Create a new source reference based on an existing one, updated to reflect
         * entry into a new AST node.
         */
        public FieldValue AmendSourceReference(AstNode node, string message, LoadableValue source_reference)
        {
            var field = MakeField("source_reference", typeof(SourceReference));

            Builder.Emit(OpCodes.Ldarg_0);
            Builder.Emit(OpCodes.Ldstr, message);
            Builder.Emit(OpCodes.Ldc_I4, node.StartRow);
            Builder.Emit(OpCodes.Ldc_I4, node.StartColumn);
            Builder.Emit(OpCodes.Ldc_I4, node.EndRow);
            Builder.Emit(OpCodes.Ldc_I4, node.EndColumn);
            source_reference.Load(Builder);
            Builder.Emit(OpCodes.Newobj, typeof(SourceReference).GetConstructors()[0]);
            Builder.Emit(OpCodes.Stfld, field.Field);
            return(field);
        }
Пример #9
0
 void CopyField(LoadableValue source, FieldInfo target)
 {
     Builder.Emit(OpCodes.Ldarg_0);
     source.Load(Builder);
     if (source.BackingType != target.FieldType)
     {
         if (target.FieldType == typeof(object))
         {
             Builder.Emit(OpCodes.Box);
         }
         else
         {
             Builder.Emit(OpCodes.Unbox_Any, target.FieldType);
         }
     }
     Builder.Emit(OpCodes.Stfld, target);
 }
Пример #10
0
        /**
         * Generate a runtime dispatch that checks each of the provided types.
         */
        void DynamicTypeDispatch(LoadableValue original, LoadableValue source_reference, System.Type[] types, ParameterisedBlock block)
        {
            var labels = new Label[types.Length];

            for (var it = 0; it < types.Length; it++)
            {
                labels[it] = Builder.DefineLabel();
                original.Load(Builder);
                Builder.Emit(OpCodes.Isinst, types[it]);
                Builder.Emit(OpCodes.Brtrue, labels[it]);
            }
            EmitTypeError(source_reference, String.Format("Unexpected type {0} instead of {1}.", "{0}", string.Join(", ", (object[])types)), original);

            for (var it = 0; it < types.Length; it++)
            {
                Builder.MarkLabel(labels[it]);
                var converted_field = MakeField("converted", types[it]);
                CopyField(original, converted_field);
                block(converted_field);
            }
        }
Пример #11
0
        public void EmitTypeError(LoadableValue source_reference, string message, params LoadableValue[] data)
        {
            LoadTaskMaster();
            source_reference.Load(Builder);
            Builder.Emit(OpCodes.Ldstr, message);
            foreach (var item in data)
            {
                item.Load(Builder);
                Builder.Emit(OpCodes.Call, typeof(object).GetMethod("GetType"));
            }
            var signature = new System.Type[data.Length + 1];

            signature[0] = typeof(string);
            for (var it = 0; it < data.Length; it++)
            {
                signature[it + 1] = typeof(object);
            }
            Builder.Emit(OpCodes.Call, typeof(String).GetMethod("Format", signature));
            Builder.Emit(OpCodes.Callvirt, typeof(TaskMaster).GetMethod("ReportOtherError"));
            Builder.Emit(OpCodes.Ldc_I4_0);
            Builder.Emit(OpCodes.Ret);
        }
Пример #12
0
        public void ToStringish(LoadableValue source, LoadableValue source_reference)
        {
            var boxed      = source.BackingType == typeof(object);
            var converters = new Dictionary <System.Type, Action>()
            {
                { typeof(bool), () => ToStringishHelper <double>(boxed, source) },
                { typeof(bool), () => ToStringishHelper <long>(boxed, source) },
                { typeof(bool), () => ToStringishHelperBool(boxed, source) },
                { typeof(Stringish), () => ToStringishHelperStringish(boxed, source) }
            };

            if (boxed)
            {
                var end    = Builder.DefineLabel();
                var labels = new Dictionary <System.Type, Label>();
                foreach (var type in converters.Keys)
                {
                    var label = Builder.DefineLabel();
                    labels[type] = label;
                    source.Load(Builder);
                    Builder.Emit(OpCodes.Isinst, type);
                    Builder.Emit(OpCodes.Brtrue, label);
                }

                EmitTypeError(source_reference, "Cannot convert type {0} to string.", source);

                foreach (var entry in converters)
                {
                    Builder.MarkLabel(labels[entry.Key]);
                    entry.Value();
                    Builder.Emit(OpCodes.Br, end);
                }
                Builder.MarkLabel(end);
            }
            else
            {
                converters[source.BackingType]();
            }
        }
Пример #13
0
 /**
  * Generate a successful return.
  */
 public void Return(LoadableValue result)
 {
     if (result.BackingType == typeof(Frame) || result.BackingType == typeof(object))
     {
         var end = Builder.DefineLabel();
         if (result.BackingType == typeof(object))
         {
             result.Load(Builder);
             Builder.Emit(OpCodes.Isinst, typeof(Frame));
             result.Load(Builder);
             Builder.Emit(OpCodes.Castclass, typeof(Frame));
         }
         else
         {
             result.Load(Builder);
         }
         LoadTaskMaster();
         Builder.Emit(OpCodes.Callvirt, typeof(Frame).GetMethod("Slot"));
         Builder.MarkLabel(end);
     }
     CopyField(result, typeof(Computation).GetField("result"));
     Builder.Emit(OpCodes.Ldc_I4_1);
     Builder.Emit(System.Reflection.Emit.OpCodes.Ret);
 }
Пример #14
0
        internal void IntrinsicDispatch(Generator generator, AstNode node, LoadableValue original, LoadableValue source_reference, Generator.ParameterisedBlock <LoadableValue> block)
        {
            var intrinsic = Intrinsics[node];

            if (!intrinsic.Item2)
            {
                block(original);
                return;
            }
            var types = AstTypeableNode.ClrTypeFromType(intrinsic.Item1);

            foreach (var type in types)
            {
                var next_label = generator.Builder.DefineLabel();
                original.Load(generator);
                generator.Builder.Emit(OpCodes.Isinst, type);
                generator.Builder.Emit(OpCodes.Brfalse, next_label);
                var builder = generator.Builder;
                block(new AutoUnboxValue(original, type));
                generator.Builder = builder;
                generator.Builder.MarkLabel(next_label);
            }
            generator.EmitTypeError(source_reference, String.Format("Expected type {0} for {1}, but got {2}.", String.Join(" or ", from t in types select Stringish.NameForType(t)), node.PrettyName, "{0}"), original);
        }
Пример #15
0
        internal void GenerateLookupCache(Generator generator, IEnumerable <Tuple <RestrictableType, Generator.ParameterisedBlock <Generator.ParameterisedBlock <LoadableValue> > > > specials, LookupCache current, LoadableValue source_reference, LoadableValue context, LoadableValue self_frame, Block block)
        {
            generator.DebugPosition(this);
            var lookup_results = new List <LoadableCache>();

            if (specials != null)
            {
                var child_context = generator.MakeField("anon_ctxt", typeof(Context));
                var child_frame   = generator.MakeField("anon_frame", typeof(MutableFrame));
                generator.Builder.Emit(OpCodes.Ldarg_0);
                generator.LoadTaskMaster();
                source_reference.Load(generator);
                context.Load(generator);
                self_frame.Load(generator);
                generator.Builder.Emit(OpCodes.Newobj, typeof(MutableFrame).GetConstructors()[0]);
                generator.Builder.Emit(OpCodes.Stfld, child_frame.Field);

                generator.Builder.Emit(OpCodes.Ldarg_0);
                child_frame.Load(generator.Builder);
                context.Load(generator.Builder);
                generator.Builder.Emit(OpCodes.Call, typeof(Context).GetMethod("Prepend", new[] { typeof(Frame), typeof(Context) }));
                generator.Builder.Emit(OpCodes.Stfld, child_context.Field);
                // Promote the context with the specials to proper status
                context = child_context;

                foreach (var entry in specials)
                {
                    var next  = generator.DefineState();
                    var field = generator.MakeField("special$" + entry.Item1.Name, typeof(object));

                    // The types that we might allow are a superset of the ones we
                    // might actually see. So, build a set of the ones we see.
                    Type known_types = 0;
                    entry.Item2(result => {
                        child_frame.Load(generator.Builder);
                        generator.Builder.Emit(OpCodes.Ldstr, entry.Item1.Name);
                        generator.LoadReboxed(result, typeof(object));
                        generator.Builder.Emit(OpCodes.Call, typeof(MutableFrame).GetMethod("Set", new[] { typeof(string), typeof(object) }));
                        generator.CopyField(result, field);
                        generator.JumpToState(next);
                        known_types |= AstTypeableNode.TypeFromClrType(result.BackingType);
                    });
                    generator.MarkState(next);
                    lookup_results.Add(new LoadableCache(field, entry.Item1.RestrictedType & known_types, entry.Item1, entry.Item1.MustUnbox));
                }
            }

            var base_lookup_cache = new LookupCache(current);
            var all_children      = new List <NameInfo>();

            foreach (var info in Children.Values)
            {
                if (info == null)
                {
                    continue;
                }
                info.AddAll(all_children);
            }
            if (current != null)
            {
                string narrow_error = null;
                foreach (var info in all_children)
                {
                    var current_narrow_error = info.CheckValidNarrowing(base_lookup_cache, current);
                    if (narrow_error != null && current_narrow_error != null)
                    {
                        narrow_error = String.Format("{0}\n{1}", narrow_error, current_narrow_error);
                    }
                    else
                    {
                        narrow_error = narrow_error ?? current_narrow_error;
                    }
                }
                if (narrow_error != null)
                {
                    generator.LoadTaskMaster();
                    source_reference.Load(generator);
                    generator.Builder.Emit(OpCodes.Ldstr, narrow_error);
                    generator.Builder.Emit(OpCodes.Callvirt, typeof(TaskMaster).GetMethod("ReportOtherError", new[] { typeof(SourceReference), typeof(string) }));
                    generator.Builder.Emit(OpCodes.Ldc_I4_0);
                    generator.Builder.Emit(OpCodes.Ret);
                    return;
                }
            }
            var load_count = all_children.Sum(info => info.NeedsLoad(current) ? 1 : 0);

            if (load_count > 0)
            {
                generator.StartInterlock(load_count);
                lookup_results.AddRange(from info in all_children where info.NeedsLoad(current) select info.Load(generator, source_reference, context));
                var state = generator.DefineState();
                generator.SetState(state);
                generator.DecrementInterlock(generator.Builder);
                var end_label = generator.Builder.DefineLabel();
                generator.Builder.Emit(OpCodes.Brfalse, end_label);
                generator.Builder.Emit(OpCodes.Ldc_I4_0);
                generator.Builder.Emit(OpCodes.Ret);
                generator.Builder.MarkLabel(end_label);
                generator.JumpToState(state);
                generator.MarkState(state);
            }
            foreach (var lookup_result in lookup_results.Where(x => x.DirectCopy))
            {
                base_lookup_cache[lookup_result.NameInfo] = lookup_result.Value;
            }
            foreach (var lookup_result in lookup_results.Where(x => x.SinglyTyped && !x.DirectCopy))
            {
                base_lookup_cache[lookup_result.NameInfo] = new AutoUnboxValue(lookup_result.Value, lookup_result.Types[0]);
                var label = generator.Builder.DefineLabel();
                lookup_result.Value.Load(generator);
                generator.Builder.Emit(OpCodes.Isinst, lookup_result.Types[0]);
                generator.Builder.Emit(OpCodes.Brtrue, label);
                generator.EmitTypeError(source_reference, String.Format("Expected type {0} for “{1}”, but got {2}.", Stringish.NameForType(lookup_result.Types[0]), lookup_result.NameInfo.Name, "{0}"), lookup_result.Value);
                generator.Builder.MarkLabel(label);
            }
            var permutable_caches = lookup_results.Where(x => !x.SinglyTyped && !x.DirectCopy).ToArray();
            var old_paths         = generator.Paths;

            generator.Paths = permutable_caches.Aggregate(old_paths, (acc, c) => acc * c.Types.Length);
            if (generator.Paths > 200 && !combinatorial_explosion)
            {
                Console.Error.WriteLine("{0}:{1}:{2}-{3}:{4}: There are {5} type-derived flows in the generated code. This will be slow to compile.", FileName, StartRow, StartColumn, EndRow, EndColumn, generator.Paths);
                combinatorial_explosion = true;
            }
            GenerateLookupPermutation(generator, context, base_lookup_cache, 0, permutable_caches, source_reference, block);
            generator.Paths = old_paths;
        }
Пример #16
0
 public LoadableCache(LoadableValue loadable_value, RestrictableType name_info) : this(loadable_value, name_info.RestrictedType, name_info, name_info.MustUnbox)
 {
 }
Пример #17
0
 /**
  * Slot a computation for execution by the task master.
  */
 public void Slot(LoadableValue target)
 {
     LoadTaskMaster();
     target.Load(Builder);
     Builder.Emit(OpCodes.Callvirt, typeof(TaskMaster).GetMethod("Slot"));
 }
Пример #18
0
 public override LoadableCache Load(Generator generator, LoadableValue source_reference, LoadableValue context)
 {
     return(new LoadableCache(GenerateLookupField(generator, source_reference, context), RestrictedType, this, must_unbox));
 }
Пример #19
0
        public override LoadableCache Load(Generator generator, LoadableValue source_reference, LoadableValue context)
        {
            var source_cache = Source.Load(generator, source_reference, context);

            return(new LoadableCache(source_cache.Value, source_cache.PossibleTypes & Mask, this, must_unbox));
        }
Пример #20
0
 public override LoadableCache Load(Generator generator, LoadableValue source_reference, LoadableValue context)
 {
     throw new InvalidOperationException("Attempted to load invalid name.");
 }
Пример #21
0
 public override LoadableCache Load(Generator generator, LoadableValue source_reference, LoadableValue context)
 {
     return(new LoadableCache(((FunctionGenerator)generator).InitialOriginal, RealType, this, must_unbox));
 }
Пример #22
0
 private void FoldHelper <T>(List <T> list, FoldBlock <T> expand, ParameterisedBlock result, LoadableValue curr_result, int it)
 {
     if (it < list.Count)
     {
         expand(it, list[it], curr_result, (next_result) => FoldHelper(list, expand, result, next_result, it + 1));
     }
     else
     {
         result(curr_result);
     }
 }
Пример #23
0
 /**
  * Copies the contents of one field to another, boxing or unboxing based on
  * the field types.
  */
 void CopyField(LoadableValue source, FieldValue target)
 {
     CopyField(source, target.Field);
 }
Пример #24
0
 /**
  * Slot a computation for execution and stop execution.
  */
 public void SlotSleep(LoadableValue target)
 {
     Slot(target);
     Builder.Emit(OpCodes.Ldc_I4_0);
     Builder.Emit(OpCodes.Ret);
 }
Пример #25
0
 public abstract LoadableCache Load(Generator generator, LoadableValue source_reference, LoadableValue context);
Пример #26
0
 /**
  * Generate code for a list using a fold (i.e., each computation in the list
  * is made from the previous computation).
  */
 public void Fold <T>(LoadableValue initial, List <T> list, FoldBlock <T> expand, ParameterisedBlock result)
 {
     FoldHelper(list, expand, result, initial, 0);
 }