Beispiel #1
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(Frame));
                generator.Builder.Emit(OpCodes.Ldarg_0);
                generator.LoadTaskMaster();
                generator.GenerateNextId();
                source_reference.Load(generator);
                context.Load(generator);
                self_frame.Load(generator);
                generator.Builder.Emit(OpCodes.Newobj, typeof(Frame).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(Frame).GetMethod("set_Item", 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>();
            string narrow_error      = null;

            foreach (var info in Children.Values)
            {
                if (info == null)
                {
                    continue;
                }
                info.AddAll(all_children);
            }
            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}.", 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;
        }
Beispiel #2
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));
        }
Beispiel #3
0
 public override LoadableCache Load(Generator generator, LoadableValue source_reference, LoadableValue context)
 {
     return(new LoadableCache(GenerateLookupField(generator, source_reference, context), RestrictedType, this, must_unbox));
 }
Beispiel #4
0
 public override LoadableCache Load(Generator generator, LoadableValue source_reference, LoadableValue context)
 {
     throw new InvalidOperationException("Attempted to load invalid name.");
 }
Beispiel #5
0
 public override LoadableCache Load(Generator generator, LoadableValue source_reference, LoadableValue context)
 {
     return(new LoadableCache(((FunctionGenerator)generator).InitialOriginal, RealType, this, must_unbox));
 }
Beispiel #6
0
 public abstract LoadableCache Load(Generator generator, LoadableValue source_reference, LoadableValue context);