public EmitSyntax Build(EmitSyntax emit)
        {
            var result = emit.Locals.Generate().GetRef();

            emit
                .Local(result.Def, emit.Types.Import(LanguageBase.Fields.tokenKeyToId.FieldType))
                .Newobj(() => new Dictionary<object,int>())
                .Stloc(result);

            foreach (var pair in EnumerateTokenKeyToId())
            {
                emit.Ldloc(result);

                if (pair.Item1 is string)
                {
                    emit.Ldstr(new QStr((string)pair.Item1));
                }
                else if (pair.Item1 is Type)
                {
                    emit
                        .Ldtoken(emit.Types.Import((Type)pair.Item1))
                        .Call((RuntimeTypeHandle h) => Type.GetTypeFromHandle(h));
                }
                else
                {
                    throw new InvalidOperationException("Internal error: Unsupported token key type");
                }

                emit
                    .Ldc_I4(pair.Item2)
                    .Call((Dictionary<object, int> self, object _key, int _id) => self.Add(_key, _id))
                    ;
            }

            return emit.Ldloc(result);
        }
        public EmitSyntax StackLoop(EmitSyntax emit, Action <EmitSyntax, Def <Locals> > emitLoopBody)
        {
            var labels = emit.Labels;
            var START  = labels.Generate();
            var END    = labels.Generate();

            var item = emit.Locals.Generate();

            emit
            .Local(item, itemType)
            .Label(START)
            .Ldloc(index.GetRef())
            .Ldc_I4(0)
            .Beq(END.GetRef())
            .Do(Pop)
            .Stloc(item.GetRef())
            ;

            emitLoopBody(emit, item);

            emit
            .Br(START.GetRef())
            .Label(END)
            .Nop();

            return(emit);
        }
Beispiel #3
0
        public IActionCode ChangeCondition(Type conditionType)
        {
            var contextTemp       = emit.Locals.Generate().GetRef();
            var DONOT_CHANGE_MODE = emit.Labels.Generate().GetRef();

            emit
            .Local(contextTemp.Def, emit.Types.Object)
            .Stloc(contextTemp)
            .Ldloc(contextTemp)
            .Brfalse(DONOT_CHANGE_MODE)
            .Do(ldCursor)
            .Ldloc(contextTemp)
            .Stfld((ScanCursor c) => c.RootContext)
            ;

            var condition = FindConditionByType(conditionType);

            if (condition == null)
            {
                throw new InvalidOperationException("Internal Error: Condition not found.");
            }

            emit
            .Do(ldCursor)
            .LdMethodDelegate(declaringType, ConditionMethods.GetMethodName(condition.Index), typeof(Scan1Delegate))
            .Stfld((ScanCursor c) => c.CurrentMode)

            .Label(DONOT_CHANGE_MODE.Def)
            .Nop()
            ;

            return(this);
        }
        public EmitSyntax EmitInitialization(EmitSyntax emit)
        {
            var types = emit.Types;

            var labels = emit.Labels;

            END   = labels.Generate();
            START = labels.Generate();

            var locals = emit.Locals;

            count = locals.Generate();
            if (Index == null)
            {
                Index = locals.Generate();
                emit.Local(Index, types.Int32);
            }

            if (Value == null)
            {
                Value = locals.Generate();
                emit
                .Local(Value, valueType)
                .Ldc_I4(int.MinValue)
                .Stloc(Value.GetRef());
            }

            emit
            // int count;
            .Local(count, types.Int32);

            // count = array.Length
            ldarray(emit);
            return(emit
                   .Ldlen()
                   .Stloc(count.GetRef())

                   // Index = 0
                   .Ldc_I4(-1)
                   .Stloc(Index.GetRef())
                   // Value = -1
                   .Ldc_I4(-1)
                   .Stloc(Value.GetRef()));

            ;
        }
        public EmitSyntax EmitInitialization(EmitSyntax emit)
        {
            var types = emit.Types;

            var labels = emit.Labels;
            END = labels.Generate();
            START = labels.Generate();

            var locals = emit.Locals;
            count = locals.Generate();
            if (Index == null)
            {
                Index = locals.Generate();
                emit.Local(Index, types.Int32);
            }

            if (Value == null)
            {
                Value = locals.Generate();
                emit
                    .Local(Value, valueType)
                    .Ldc_I4(int.MinValue)
                    .Stloc(Value.GetRef());
            }

            emit
                // int count;
                .Local(count, types.Int32);

            // count = array.Length
            ldarray(emit);
            return emit
                .Ldlen()
                .Stloc(count.GetRef())

                // Index = 0
                .Ldc_I4(-1)
                .Stloc(Index.GetRef())
                // Value = -1
                .Ldc_I4(-1)
                .Stloc(Value.GetRef());
                ;
        }
Beispiel #6
0
        private EmitSyntax EmitFactoryCode(
            EmitSyntax emit,
            PlannedClass contextPlannedClass,
            Type type,
            bool nullAllowed)
        {
            if (type == typeof(void))
            {
            }
            else if (type == typeof(int))
            {
                emit = emit.Ldc_I4_0();
            }
            else if (type.IsValueType)
            {
                var resultType = emit.Types.Import(type);
                var resultLoc  = emit.Locals.Generate("result");

                emit = emit
                       .Local(resultLoc, resultType)
                       .Ldloca(resultLoc.GetRef())
                       .Initobj(resultType)
                       .Ldloc(resultLoc.GetRef())
                ;
            }
            else if (nullAllowed)
            {
                emit.Ldnull();
            }
            else if (!type.IsAbstract && !type.IsInterface)
            {
                emit = emit.Newobj(
                    emit.Types.Import(type));
            }
            else if (contextPlannedClass != null && contextPlannedClass.Implements(type))
            {
                emit = emit.Ldarg(0);
            }
            else if (plan.Exists(e => e.Implements(type)))
            {
                var otherEntry = plan.Find(e => e.Implements(type));
                emit = emit.Newobj(
                    emit.Types.Class_(
                        ClassName.Parse(
                            otherEntry.ClassName)));
            }
            else
            {
                throw new InvalidOperationException(
                          "Internal error: non-planned abstract result type");
            }

            return(emit);
        }
        public StackGenerator(EmitSyntax emit, Type itemType, bool nullContainer = false)
        {
            this.itemType = emit.Types.Import(itemType);
            this.stackType = emit.Types.Import(itemType.MakeArrayType());
            this.nullContainer = nullContainer;

            this.stack = emit.Locals.Generate();
            this.index = emit.Locals.Generate();
            emit
                .Local(stack, stackType)
                .Local(index, emit.Types.Int32)
                ;
        }
        public StackGenerator(EmitSyntax emit, Type itemType, bool nullContainer = false)
        {
            this.itemType      = emit.Types.Import(itemType);
            this.stackType     = emit.Types.Import(itemType.MakeArrayType());
            this.nullContainer = nullContainer;

            this.stack = emit.Locals.Generate();
            this.index = emit.Locals.Generate();
            emit
            .Local(stack, stackType)
            .Local(index, emit.Types.Int32)
            ;
        }
        public EmitSyntax Build(EmitSyntax emit)
        {
            var result = emit.Locals.Generate().GetRef();

            emit
            .Local(result.Def, emit.Types.Import(LanguageBase.Fields.tokenKeyToId.FieldType))
            .Newobj(() => new Dictionary <object, int>())
            .Stloc(result);

            foreach (var pair in EnumerateTokenKeyToId())
            {
                emit.Ldloc(result);

                if (pair.Item1 is string)
                {
                    emit.Ldstr(new QStr((string)pair.Item1));
                }
                else if (pair.Item1 is Type)
                {
                    emit
                    .Ldtoken(emit.Types.Import((Type)pair.Item1))
                    .Call((RuntimeTypeHandle h) => Type.GetTypeFromHandle(h));
                }
                else
                {
                    throw new InvalidOperationException("Internal error: Unsupported token key type");
                }

                emit
                .Ldc_I4(pair.Item2)
                .Call((Dictionary <object, int> self, object _key, int _id) => self.Add(_key, _id))
                ;
            }

            return(emit.Ldloc(result));
        }
        public ILNfaCompiler(AstNode node, EmitSyntax emit, ILCompilerSettings settings)
        {
            this.Scanner = new StemScanner();

            this.emit = emit;
            this.settings = settings;

            var labels = emit.Labels;
            NEXT_THREAD     = labels.Generate();
            RESUME_ALL      = labels.Generate();
            NEXT_INPUT      = labels.Generate();
            THREAD_SUSPEND  = labels.Generate();
            THREAD_DISPATCH = labels.Generate();

            var LABEL0      = labels.Generate();
            var LABEL1      = labels.Generate();
            var POSTCOMPILEINIT = labels.Generate();
            var POSTCOMPILEINIT_BACK = labels.Generate();

            var locals = emit.Locals;
            slots        = locals.Generate();
            labelIndexToLocation = locals.Generate();
            intTmp       = locals.Generate();
            threadTmp    = locals.Generate();

            INfaVM code = this;

            this.inputPump = new ArrayLoopGenerator(
                       valueType: emit.Types.Int32,
                       ldarray:   settings.LdInput,
                       body:
                           il => il
                               .Do(matchedStack.Clear)
                               .Br(RESUME_ALL.GetRef())
                        );

            this.runningStack   = new StackGenerator(emit, typeof(Thread));
            this.suspendedStack = new StackGenerator(emit, typeof(Thread));
            this.matchedStack   = new StackGenerator(emit, typeof(Thread));
            this.tmpStack       = new StackGenerator(emit, typeof(Thread), nullContainer: true);

            emit
                .Local(intTmp, emit.Types.Int32)
                .Local(slots, emit.Types.Import(typeof(int[])))
                .Local(labelIndexToLocation, emit.Types.Import(typeof(int[])))
                .Br(POSTCOMPILEINIT.GetRef())
                .Label(POSTCOMPILEINIT_BACK)
                .Local(threadTmp, emit.Types.Import(typeof(Thread)))
                .Ldloca(threadTmp.GetRef())
                .Initobj(emit.Types.Import(typeof(Thread)))
                .Do(inputPump.EmitInitialization)
                ;

            new RegularNfaVMCompiler().Compile(node, code);

            int LabelCount = Math.Max(1, indexToLabel.Count);

            this.runningStack.SetSize(LabelCount);
            this.suspendedStack.SetSize(LabelCount);
            this.matchedStack.SetSize(LabelCount);
            this.tmpStack.SetSize(LabelCount);

            emit
                .Label(POSTCOMPILEINIT)
                .Do(runningStack.Init)
                .Do(suspendedStack.Init)
                .Do(matchedStack.Init)
                .Do(tmpStack.Init)
                .Ldc_I4(slotCount)
                .Newarr(emit.Types.Int32)
                .Stloc(slots.GetRef())

                .Ldc_I4(LabelCount)
                .Newarr(emit.Types.Int32)
                .Stloc(labelIndexToLocation.GetRef())
                // Fill labelIndexToLocation with -1 :
                .Ldc_I4(LabelCount).Stloc(intTmp.GetRef())

                .Label(LABEL1)
                .Ldloc(intTmp.GetRef())
                .Ldc_I4_0()
                .Beq(LABEL0.GetRef())
                .Ldloc(intTmp.GetRef())
                .Ldc_I4(1)
                .Sub()
                .Stloc(intTmp.GetRef())
                .Ldloc(labelIndexToLocation.GetRef())
                .Ldloc(intTmp.GetRef())
                .Ldc_I4(int.MinValue)
                .Stelem_I4()
                .Br(LABEL1.GetRef())
                .Label(LABEL0)
                .Br(POSTCOMPILEINIT_BACK.GetRef());

            // Save thread as suspended (stack should already contain label index to suspend)
            emit.Label(THREAD_SUSPEND);
            StThreadValueByRuntimeLabelIndex();
            emit
                // Don't add thread if same thread (same label index
                // with current input location) already exists in a list.
                .Ldloc(labelIndexToLocation.GetRef())
                .Ldloca(threadTmp.GetRef())
                .Ldfld(LabelIndexField)
                .Ldelem_I4()
                .Ldloc(inputPump.Index.GetRef())
                .Beq(NEXT_THREAD.GetRef())

                // Mark label index as visited
                .Ldloc(labelIndexToLocation.GetRef())
                .Ldloca(threadTmp.GetRef())
                .Ldfld(LabelIndexField)
                .Ldloc(inputPump.Index.GetRef())
                .Stelem_I4()
                ;

            suspendedStack.PushFrom(emit, threadTmp);

            emit
                .Br(NEXT_THREAD.GetRef())

                .Label(RESUME_ALL)
                .Swap(suspendedStack.Stack, runningStack.Stack, tmpStack.Stack)
                .Swap(suspendedStack.Index, runningStack.Index, tmpStack.Index)
                .Label(NEXT_THREAD)
                ;

            runningStack
                .StackLoop(
                    emit,
                    (emit2, thread) =>
                    {
                        emit2
                            .Ldloca(thread.GetRef())
                            .Ldfld(LabelIndexField)
                            .Label(THREAD_DISPATCH)
                            .Switch(indexToLabel.Select(def => def.GetRef()).ToArray())
                            .Br(settings.FAILURE.GetRef());
                    })
                    ;
            emit
                .Br(NEXT_INPUT.GetRef())
                ;

            emit
                .Label(NEXT_INPUT)
                ;

            inputPump.EmitLoopPass(emit, false);

            emit
                // Check if there are matched threads:
                .Do(matchedStack.LdCount)
                .Ldc_I4_0()
                .Beq(settings.FAILURE.GetRef())
                .Br(settings.SUCCESS.GetRef());
        }
Beispiel #11
0
        public void Build(EmitSyntax emit)
        {
            // Debug.WriteLine("DFA for " + descriptor.Name + ":");
            // Debug.WriteLine(dfa);
            int failState = dfa.StateCount;

            var locals = emit.Locals;
            var labels = emit.Labels;

            var FIN     = labels.Generate();
            var current = locals.Generate("ch");

            var Lgoto = new Ref <Labels> [dfa.StateCount + 1]; // label for incrementing ch position
            var Mgoto = new Ref <Labels> [dfa.StateCount];     // assing ch using current position
            var Tgoto = new Ref <Labels> [dfa.StateCount];     // transition dispatching switch-code

            for (int i = 0; i != dfa.StateCount; ++i)
            {
                Lgoto[i] = labels.Generate().GetRef();
                Mgoto[i] = labels.Generate().GetRef();
                Tgoto[i] = labels.Generate().GetRef();
            }

            Lgoto[failState] = FIN.GetRef();

            emit
            .Local(current, emit.Types.Char)
            .Ldarg(0).Ldfld((ScanCursor c) => c.InnerState)
            .Switch(Mgoto)
            .Br(Lgoto[0])
            ;

            foreach (var S in dfa.EnumerateStates())
            {
                int state = S.Index;

                emit
                .Label(Lgoto[state].Def);

                if (state != dfa.Start)
                {
                    // ++Cursor
                    emit
                    .Ldarg(0)     // for Stfld
                    .Ldarg(0).Ldfld((ScanCursor c) => c.Cursor)
                    .Ldc_I4_1()
                    .Add()
                    .Stfld((ScanCursor c) => c.Cursor)
                    ;
                }

                // If state is accepring then remember position
                // in Marker and save corresponding ActionId.
                if (S.IsAccepting)
                {
                    int actionCount = 0;
                    foreach (var action in S.Actions)
                    {
                        emit
                        .Ldarg(0)
                        .Ldfld((ScanCursor c) => c.Actions)
                        .Ldc_I4(actionCount++)
                        .Ldc_I4(action)
                        .Stelem_I4()
                        ;
                    }

                    emit
                    .Ldarg(0)
                    .Ldc_I4(actionCount)
                    .Stfld((ScanCursor c) => c.ActionCount)
                    ;

                    emit
                    .Ldarg(0)
                    .Ldc_I4(S.EnvelopeId)
                    .Stfld((ScanCursor c) => c.EnvelopeId)
                    ;

                    emit
                    .Ldarg(0)
                    .Ldarg(0).Ldfld((ScanCursor c) => c.Cursor)
                    .Stfld((ScanCursor c) => c.Marker);

                    // Save line/column information

                    emit
                    // cursor.MarkerLine = cursor.CursorLine;
                    .Ldarg(0)
                    .Ldarg(0)
                    .Ldfld((ScanCursor c) => c.CursorLine)
                    .Stfld((ScanCursor c) => c.MarkerLine)
                    // cursor.MarkerLineStart = cursor.CursorLineStart;
                    .Ldarg(0)
                    .Ldarg(0)
                    .Ldfld((ScanCursor c) => c.CursorLineStart)
                    .Stfld((ScanCursor c) => c.MarkerLineStart)
                    ;
                }

                if (S.IsNewline)
                {
                    emit
                    // ++cursor.CursorLine;
                    .Ldarg(0)
                    .Ldarg(0)
                    .Ldfld((ScanCursor c) => c.CursorLine)
                    .Ldc_I4_1()
                    .Add()
                    .Stfld((ScanCursor c) => c.CursorLine)
                    // cursor.CursorLineStart = cursor.Cursor;
                    .Ldarg(0)
                    .Ldarg(0)
                    .Ldfld((ScanCursor c) => c.Cursor)
                    .Stfld((ScanCursor c) => c.CursorLineStart)
                    ;
                }

                emit
                .Label(Mgoto[state].Def)
                // Get current input symbol
                .Ldarg(0).Ldfld((ScanCursor c) => c.Buffer)
                .Ldarg(0).Ldfld((ScanCursor c) => c.Cursor)
                .Ldelem_U2()
                .Stloc(current.GetRef())
                // Label for tunneling
                .Label(Tgoto[state].Def)
                ;

                if (S.IsFinal && state != 0)
                {
                    emit
                    .Br(FIN.GetRef());
                    continue;
                }

                int checkSentinelState = failState + 1;

                var stateRealTransitions = dfa.EnumerateRealTransitions(S).ToList();


                // Find custom sentinel transtion
                int customSentinelToState         = -1;
                var customSentinelTransitionIndex =
                    stateRealTransitions.FindIndex(pair => pair.Key.Contains(Sentinel));
                if (customSentinelTransitionIndex >= 0)
                {
                    customSentinelToState = stateRealTransitions[customSentinelTransitionIndex].Value;
                }

                // Sentinel check transiiton
                var sentinelTransition = new IntArrow <int>(Sentinel, checkSentinelState);
                stateRealTransitions.Insert(0, sentinelTransition);

                var generator = SwitchGenerator.Sparse(
                    stateRealTransitions.ToArray(),
                    failState,
                    UnicodeIntSetType.UnicodeInterval,
                    frequency: UnicodeFrequency.Default);
                generator.Build(
                    emit,
                    il => il.Ldloc(current.GetRef()),
                    (EmitSyntax il, int value) =>
                {
                    if (value == checkSentinelState)
                    {
                        var handleSentinelCharLabel =
                            (customSentinelToState >= 0)
                                    ? Lgoto[customSentinelToState]
                                    : FIN.GetRef();

                        // return for buffer filling if Cursor == Limit,
                        // otherwise transite on char
                        il
                        .Ldarg(0).Ldfld((ScanCursor c) => c.Limit)
                        .Ldarg(0).Ldfld((ScanCursor c) => c.Cursor)
                        .Bne_Un(handleSentinelCharLabel)

                        // Return for buffer filling
                        .Ldarg(0)
                        .Ldc_I4(state)
                        .Stfld((ScanCursor c) => c.InnerState)
                        .Ldc_I4(1)
                        .Ret()
                        ;
                    }
                    else if (value == failState && S.Tunnel >= 0)
                    {
                        // Tunnel-jump to other state and verify current
                        // input again in that state.
                        il.Br(Tgoto[S.Tunnel]);
                    }
                    else
                    {
                        // Transite to the valid or failed state
                        il.Br(Lgoto[value]);
                    }
                });
            }

            // Return to the last accepted position and report accept stage
            emit
            .Label(FIN)
            .Ldc_I4(0)
            .Ret()
            ;
        }
        public void Build(
            EmitSyntax emit,
            Pipe <EmitSyntax> ldCursor,
            Pipe <EmitSyntax> ldTokenPtr)
        {
            var labels = emit.Labels;
            var locals = emit.Locals;

            var RETURN = labels.Generate();

            var valueTmp = locals.Generate();
            var tokenId  = locals.Generate();

            emit
            .Local(valueTmp, emit.Types.Object)
            .Ldnull()
            .Stloc(valueTmp.GetRef())

            .Local(tokenId, emit.Types.Int32)
            .Ldc_I4(-1)
            .Stloc(tokenId.GetRef())
            ;

            int ruleCount = data.Grammar.Conditions.Sum(cond => cond.Matchers.Count);

            var action = new Ref <Labels> [ruleCount];

            for (int i = 0; i != ruleCount; ++i)
            {
                action[i] = labels.Generate().GetRef();
            }

            emit
            .Do(ldCursor)
            .Ldfld((ScanCursor c) => c.CurrentActionId)
            .Switch(action)
            ;

            foreach (var cond in data.Grammar.Conditions)
            {
                var contextResolver = new ContextCode(
                    emit,
                    il => il
                    .Do(ldCursor)
                    .Ldfld((ScanCursor c) => c.RootContext),
                    null,
                    data,
                    cond.ContextProvider);
                IActionCode code = new MatcherCode(
                    emit,
                    contextResolver,
                    ldCursor,
                    declaringType,
                    data.Grammar.Conditions,
                    RETURN.GetRef());

                foreach (var matcher in cond.Matchers)
                {
                    emit
                    .Label(action[matcher.Index].Def)
                    .Ldc_I4(matcher.Outcome == null ? -1 : matcher.Outcome.Index)
                    .Stloc(tokenId.GetRef())
                    ;

                    var productionBinding = matcher.Joint.The <CilMatcher>();
                    code = code
                           .Do(productionBinding.Context.Load)
                           .Do(productionBinding.ActionBuilder);
                }
            }

            // Load null value for incorrectly implemented actions
            emit.Ldnull();

            emit
            .Label(RETURN)

            .Stloc(valueTmp.GetRef())
            .Do(ldTokenPtr)
            .Ldloc(valueTmp.GetRef())
            .Stind_Ref()

            .Ldloc(tokenId.GetRef())
            .Ret()
            ;
        }
        public EmitSyntax StackLoop(EmitSyntax emit, Action<EmitSyntax, Def<Locals>> emitLoopBody)
        {
            var labels = emit.Labels;
            var START = labels.Generate();
            var END = labels.Generate();

            var item = emit.Locals.Generate();

            emit
                .Local(item, itemType)
                .Label(START)
                .Ldloc(index.GetRef())
                .Ldc_I4(0)
                .Beq(END.GetRef())
                .Do(Pop)
                .Stloc(item.GetRef())
                ;

            emitLoopBody(emit, item);

            emit
                .Br(START.GetRef())
                .Label(END)
                .Nop();

            return emit;
        }
        public EmitSyntax Build(EmitSyntax emit)
        {
            var resultVar   = emit.Locals.Generate("result");
            var partsVar    = emit.Locals.Generate("parts");
            var symbolVar   = emit.Locals.Generate("symbol").GetRef();
            var intArrayVar = emit.Locals.Generate("intArray").GetRef();

            emit
            .Local(resultVar, emit.Types.Import(typeof(Grammar)))
            .Local(partsVar, emit.Types.Import(typeof(int[])))
            .Local(symbolVar.Def, emit.Types.Import(typeof(SymbolBase)))
            .Local(intArrayVar.Def, emit.Types.Array(emit.Types.Int32))

            .Newobj(() => new Grammar())
            .Stloc(resultVar.GetRef())
            ;

            foreach (var symbol in grammar.Symbols)
            {
                if (symbol.IsPredefined)
                {
                    continue;
                }

                if (symbol is Symbol)
                {
                    var determSymbol = (Symbol)symbol;
                    emit
                    .Ldstr(new QStr(symbol.Name))
                    .Newobj((string name) => new Symbol(name))
                    .Stloc(symbolVar)
                    ;

                    if (symbol.Categories != SymbolCategory.None)
                    {
                        emit
                        .Ldloc(symbolVar)
                        .Ldc_I4((int)symbol.Categories)
                        .Stprop((Symbol s) => s.Categories)
                        ;
                    }

                    if (symbol.Precedence != null)
                    {
                        var precedence = symbol.Precedence;

                        emit
                        .Ldloc(symbolVar)

                        .Ldc_I4(precedence.Value)
                        .Ldc_I4((int)precedence.Assoc)
                        .Newobj((int _prec, Associativity _assoc) => new Precedence(_prec, _assoc))

                        .Stprop((Symbol s) => s.Precedence)
                        ;
                    }
                }
                else if (symbol is AmbiguousSymbol)
                {
                    var ambSymbol = (AmbiguousSymbol)symbol;

                    emit
                    .Ldc_I4(ambSymbol.Tokens.Count)
                    .Newarr(emit.Types.Int32)
                    .Stloc(intArrayVar)
                    ;

                    for (int i = 0; i != ambSymbol.Tokens.Count; ++i)
                    {
                        emit
                        .Ldloc(intArrayVar)
                        .Ldc_I4(i)
                        .Ldc_I4(ambSymbol.Tokens[i])
                        .Stelem_I4()
                        ;
                    }

                    emit
                    .Ldc_I4(ambSymbol.MainToken)
                    .Ldloc(intArrayVar)
                    .Newobj((int main, int[] tokens) => new AmbiguousSymbol(main, tokens))
                    .Stloc(symbolVar)
                    ;
                }
                else
                {
                    throw new InvalidOperationException("Internal error: unknown symbol type.");
                }

                emit
                .Ldloc(resultVar.GetRef())
                .Ldprop((Grammar g) => g.Symbols)
                .Ldloc(symbolVar)
                .Call((SymbolCollection coll, Symbol sym) => coll.Add(sym))
                .Pop()
                ;
            }

            if (grammar.Start != null)
            {
                emit
                .Ldloc(resultVar.GetRef())
                .Dup()
                .Ldprop((Grammar g) => g.Symbols)
                .Ldc_I4(grammar.Start.Index)
                .Call((SymbolCollection coll, int index) => coll[index])
                .Stprop((Grammar g) => g.Start);
            }

            foreach (var production in grammar.Productions)
            {
                if (production.Outcome.IsAugmentedStart)
                {
                    // Start rule is defined automatically when first token is defined
                    continue;
                }

                emit
                .Ldc_I4(production.PatternTokens.Length)
                .Newarr(emit.Types.Int32)
                .Stloc(partsVar.GetRef())
                ;

                int i = 0;
                foreach (int part in production.PatternTokens)
                {
                    emit
                    .Ldloc(partsVar.GetRef())
                    .Ldc_I4(i)
                    .Ldc_I4(part)
                    .Stelem_I4()
                    ;
                    ++i;
                }

                emit
                .Ldloc(resultVar.GetRef())
                .Ldprop((Grammar g) => g.Productions)
                .Ldc_I4(production.Outcome.Index)
                .Ldloc(partsVar.GetRef())
                .Call((ProductionCollection prods, int l, IEnumerable <int> p) => prods.Define(l, p))
                .Pop()
                ;
            }

            return(emit.Ldloc(resultVar.GetRef()));
        }
        public void Build(
            EmitSyntax          emit,
            Pipe<EmitSyntax>    ldCursor,
            Pipe<EmitSyntax>    ldTokenPtr)
        {
            var labels = emit.Labels;
            var locals = emit.Locals;

            var RETURN = labels.Generate();

            var valueTmp = locals.Generate();
            var tokenId  = locals.Generate();

            emit
                .Local(valueTmp, emit.Types.Object)
                .Ldnull()
                .Stloc(valueTmp.GetRef())

                .Local(tokenId, emit.Types.Int32)
                .Ldc_I4(-1)
                .Stloc(tokenId.GetRef())
                ;

            int ruleCount = data.Grammar.Conditions.Sum(cond => cond.Matchers.Count);

            var action = new Ref<Labels>[ruleCount];
            for (int i = 0; i != ruleCount; ++i)
            {
                action[i] = labels.Generate().GetRef();
            }

            emit
                .Do(ldCursor)
                .Ldfld((ScanCursor c) => c.CurrentActionId)
                .Switch(action)
                ;

            foreach (var cond in data.Grammar.Conditions)
            {
                var contextResolver = new ContextCode(
                                        emit,
                                        il => il
                                            .Do(ldCursor)
                                            .Ldfld((ScanCursor c) => c.RootContext),
                                        null,
                                        data,
                                        cond.ContextProvider);
                IActionCode code = new MatcherCode(
                                emit,
                                contextResolver,
                                ldCursor,
                                declaringType,
                                data.Grammar.Conditions,
                                RETURN.GetRef());

                foreach (var matcher in cond.Matchers)
                {
                    emit
                        .Label(action[matcher.Index].Def)
                        .Ldc_I4(matcher.Outcome == null ? -1 : matcher.Outcome.Index)
                        .Stloc(tokenId.GetRef())
                        ;

                    var productionBinding = matcher.Joint.The<CilMatcher>();
                    code = code
                        .Do(productionBinding.Context.Load)
                        .Do(productionBinding.ActionBuilder);
                }
            }

            // Load null value for incorrectly implemented actions
            emit.Ldnull();

            emit
                .Label(RETURN)

                .Stloc(valueTmp.GetRef())
                .Do(ldTokenPtr)
                .Ldloc(valueTmp.GetRef())
                .Stind_Ref()

                .Ldloc(tokenId.GetRef())
                .Ret()
                ;
        }
        private EmitSyntax EmitFactoryCode(
            EmitSyntax   emit,
            PlannedClass contextPlannedClass,
            Type         type,
            bool         nullAllowed)
        {
            if (type == typeof(void))
            {
            }
            else if (type == typeof(int))
            {
                emit = emit.Ldc_I4_0();
            }
            else if (type.IsValueType)
            {
                var resultType = emit.Types.Import(type);
                var resultLoc = emit.Locals.Generate("result");

                emit = emit
                    .Local(resultLoc, resultType)
                    .Ldloca(resultLoc.GetRef())
                    .Initobj(resultType)
                    .Ldloc(resultLoc.GetRef())
                    ;
            }
            else if (nullAllowed)
            {
                emit.Ldnull();
            }
            else if (!type.IsAbstract && !type.IsInterface)
            {
                emit = emit.Newobj(
                         emit.Types.Import(type));
            }
            else if (contextPlannedClass != null && contextPlannedClass.Implements(type))
            {
                emit = emit.Ldarg(0);
            }
            else if (plan.Exists(e => e.Implements(type)))
            {
                var otherEntry = plan.Find(e => e.Implements(type));
                emit = emit.Newobj(
                         emit.Types.Class_(
                            ClassName.Parse(
                                otherEntry.ClassName)));
            }
            else
            {
                throw new InvalidOperationException(
                    "Internal error: non-planned abstract result type");
            }

            return emit;
        }
        public void Build(EmitSyntax emit)
        {
            // Debug.WriteLine("DFA for " + descriptor.Name + ":");
            // Debug.WriteLine(dfa);
            int failState  = dfa.StateCount;

            var locals = emit.Locals;
            var labels = emit.Labels;

            var FIN     = labels.Generate();
            var current = locals.Generate("ch");

            var Lgoto = new Ref<Labels>[dfa.StateCount + 1]; // label for incrementing ch position
            var Mgoto = new Ref<Labels>[dfa.StateCount];     // assing ch using current position
            var Tgoto = new Ref<Labels>[dfa.StateCount];     // transition dispatching switch-code

            for (int i = 0; i != dfa.StateCount; ++i)
            {
                Lgoto[i] = labels.Generate().GetRef();
                Mgoto[i] = labels.Generate().GetRef();
                Tgoto[i] = labels.Generate().GetRef();
            }

            Lgoto[failState] = FIN.GetRef();

            emit
                .Local(current, emit.Types.Char)
                .Ldarg(0) .Ldfld((ScanCursor c) => c.InnerState)
                .Switch(Mgoto)
                .Br(Lgoto[0])
                ;

            foreach (var S in dfa.EnumerateStates())
            {
                int state = S.Index;

                emit
                    .Label(Lgoto[state].Def);

                if (state != dfa.Start)
                {
                    // ++Cursor
                    emit
                        .Ldarg(0) // for Stfld
                        .Ldarg(0).Ldfld((ScanCursor c) => c.Cursor)
                        .Ldc_I4_1()
                        .Add()
                        .Stfld((ScanCursor c) => c.Cursor)
                    ;
                }

                // If state is accepring then remember position
                // in Marker and save corresponding ActionId.
                if (S.IsAccepting)
                {
                    int actionCount = 0;
                    foreach (var action in S.Actions)
                    {
                        emit
                            .Ldarg(0)
                            .Ldfld((ScanCursor c) => c.Actions)
                            .Ldc_I4(actionCount++)
                            .Ldc_I4(action)
                            .Stelem_I4()
                            ;
                    }

                    emit
                        .Ldarg(0)
                        .Ldc_I4(actionCount)
                        .Stfld((ScanCursor c) => c.ActionCount)
                        ;

                    emit
                        .Ldarg(0)
                        .Ldc_I4(S.EnvelopeId)
                        .Stfld((ScanCursor c) => c.EnvelopeId)
                        ;

                    emit
                        .Ldarg(0)
                        .Ldarg(0) .Ldfld((ScanCursor c) => c.Cursor)
                        .Stfld((ScanCursor c) => c.Marker);

                    // Save line/column information

                    emit
                        // cursor.MarkerLine = cursor.CursorLine;
                        .Ldarg(0)
                        .Ldarg(0)
                        .Ldfld((ScanCursor c) => c.CursorLine)
                        .Stfld((ScanCursor c) => c.MarkerLine)
                        // cursor.MarkerLineStart = cursor.CursorLineStart;
                        .Ldarg(0)
                        .Ldarg(0)
                        .Ldfld((ScanCursor c) => c.CursorLineStart)
                        .Stfld((ScanCursor c) => c.MarkerLineStart)
                        ;
                }

                if (S.IsNewline)
                {
                    emit
                        // ++cursor.CursorLine;
                        .Ldarg(0)
                        .Ldarg(0)
                        .Ldfld((ScanCursor c) => c.CursorLine)
                        .Ldc_I4_1()
                        .Add()
                        .Stfld((ScanCursor c) => c.CursorLine)
                        // cursor.CursorLineStart = cursor.Cursor;
                        .Ldarg(0)
                        .Ldarg(0)
                        .Ldfld((ScanCursor c) => c.Cursor)
                        .Stfld((ScanCursor c) => c.CursorLineStart)
                        ;
                }

                emit
                    .Label(Mgoto[state].Def)
                // Get current input symbol
                    .Ldarg(0) .Ldfld((ScanCursor c) => c.Buffer)
                    .Ldarg(0) .Ldfld((ScanCursor c) => c.Cursor)
                    .Ldelem_U2()
                    .Stloc(current.GetRef())
                // Label for tunneling
                    .Label(Tgoto[state].Def)
                    ;

                if (S.IsFinal && state != 0)
                {
                    emit
                        .Br(FIN.GetRef());
                    continue;
                }

                int checkSentinelState = failState + 1;

                var stateRealTransitions = dfa.EnumerateRealTransitions(S).ToList();

                // Find custom sentinel transtion
                int customSentinelToState = -1;
                var customSentinelTransitionIndex =
                    stateRealTransitions.FindIndex(pair => pair.Key.Contains(Sentinel));
                if (customSentinelTransitionIndex >= 0)
                {
                    customSentinelToState = stateRealTransitions[customSentinelTransitionIndex].Value;
                }

                // Sentinel check transiiton
                var sentinelTransition = new IntArrow<int>(Sentinel, checkSentinelState);
                stateRealTransitions.Insert(0, sentinelTransition);

                var generator = SwitchGenerator.Sparse(
                                    stateRealTransitions.ToArray(),
                                    failState,
                                    UnicodeIntSetType.UnicodeInterval,
                                    frequency: UnicodeFrequency.Default);
                generator.Build(
                    emit,
                    il => il.Ldloc(current.GetRef()),
                    (EmitSyntax il, int value) =>
                    {
                        if (value == checkSentinelState)
                        {
                            var handleSentinelCharLabel =
                                    (customSentinelToState >= 0)
                                    ? Lgoto[customSentinelToState]
                                    : FIN.GetRef();

                            // return for buffer filling if Cursor == Limit,
                            // otherwise transite on char
                            il
                                .Ldarg(0) .Ldfld((ScanCursor c) => c.Limit)
                                .Ldarg(0) .Ldfld((ScanCursor c) => c.Cursor)
                                .Bne_Un(handleSentinelCharLabel)

                                // Return for buffer filling
                                .Ldarg(0)
                                .Ldc_I4(state)
                                .Stfld((ScanCursor c) => c.InnerState)
                                .Ldc_I4(1)
                                .Ret()
                                ;
                        }
                        else if (value == failState && S.Tunnel >= 0)
                        {
                            // Tunnel-jump to other state and verify current
                            // input again in that state.
                            il.Br(Tgoto[S.Tunnel]);
                        }
                        else
                        {
                            // Transite to the valid or failed state
                            il.Br(Lgoto[value]);
                        }
                    });
            }

            // Return to the last accepted position and report accept stage
            emit
                .Label(FIN)
                .Ldc_I4(0)
                .Ret()
                ;
        }
Beispiel #18
0
        public ILNfaCompiler(AstNode node, EmitSyntax emit, ILCompilerSettings settings)
        {
            this.Scanner = new StemScanner();

            this.emit     = emit;
            this.settings = settings;

            var labels = emit.Labels;

            NEXT_THREAD     = labels.Generate();
            RESUME_ALL      = labels.Generate();
            NEXT_INPUT      = labels.Generate();
            THREAD_SUSPEND  = labels.Generate();
            THREAD_DISPATCH = labels.Generate();

            var LABEL0               = labels.Generate();
            var LABEL1               = labels.Generate();
            var POSTCOMPILEINIT      = labels.Generate();
            var POSTCOMPILEINIT_BACK = labels.Generate();

            var locals = emit.Locals;

            slots = locals.Generate();
            labelIndexToLocation = locals.Generate();
            intTmp    = locals.Generate();
            threadTmp = locals.Generate();


            INfaVM code = this;

            this.inputPump = new ArrayLoopGenerator(
                valueType: emit.Types.Int32,
                ldarray:   settings.LdInput,
                body:
                il => il
                .Do(matchedStack.Clear)
                .Br(RESUME_ALL.GetRef())
                );

            this.runningStack   = new StackGenerator(emit, typeof(Thread));
            this.suspendedStack = new StackGenerator(emit, typeof(Thread));
            this.matchedStack   = new StackGenerator(emit, typeof(Thread));
            this.tmpStack       = new StackGenerator(emit, typeof(Thread), nullContainer: true);

            emit
            .Local(intTmp, emit.Types.Int32)
            .Local(slots, emit.Types.Import(typeof(int[])))
            .Local(labelIndexToLocation, emit.Types.Import(typeof(int[])))
            .Br(POSTCOMPILEINIT.GetRef())
            .Label(POSTCOMPILEINIT_BACK)
            .Local(threadTmp, emit.Types.Import(typeof(Thread)))
            .Ldloca(threadTmp.GetRef())
            .Initobj(emit.Types.Import(typeof(Thread)))
            .Do(inputPump.EmitInitialization)
            ;

            new RegularNfaVMCompiler().Compile(node, code);

            int LabelCount = Math.Max(1, indexToLabel.Count);

            this.runningStack.SetSize(LabelCount);
            this.suspendedStack.SetSize(LabelCount);
            this.matchedStack.SetSize(LabelCount);
            this.tmpStack.SetSize(LabelCount);

            emit
            .Label(POSTCOMPILEINIT)
            .Do(runningStack.Init)
            .Do(suspendedStack.Init)
            .Do(matchedStack.Init)
            .Do(tmpStack.Init)
            .Ldc_I4(slotCount)
            .Newarr(emit.Types.Int32)
            .Stloc(slots.GetRef())

            .Ldc_I4(LabelCount)
            .Newarr(emit.Types.Int32)
            .Stloc(labelIndexToLocation.GetRef())
            // Fill labelIndexToLocation with -1 :
            .Ldc_I4(LabelCount).Stloc(intTmp.GetRef())

            .Label(LABEL1)
            .Ldloc(intTmp.GetRef())
            .Ldc_I4_0()
            .Beq(LABEL0.GetRef())
            .Ldloc(intTmp.GetRef())
            .Ldc_I4(1)
            .Sub()
            .Stloc(intTmp.GetRef())
            .Ldloc(labelIndexToLocation.GetRef())
            .Ldloc(intTmp.GetRef())
            .Ldc_I4(int.MinValue)
            .Stelem_I4()
            .Br(LABEL1.GetRef())
            .Label(LABEL0)
            .Br(POSTCOMPILEINIT_BACK.GetRef());

            // Save thread as suspended (stack should already contain label index to suspend)
            emit.Label(THREAD_SUSPEND);
            StThreadValueByRuntimeLabelIndex();
            emit
            // Don't add thread if same thread (same label index
            // with current input location) already exists in a list.
            .Ldloc(labelIndexToLocation.GetRef())
            .Ldloca(threadTmp.GetRef())
            .Ldfld(LabelIndexField)
            .Ldelem_I4()
            .Ldloc(inputPump.Index.GetRef())
            .Beq(NEXT_THREAD.GetRef())

            // Mark label index as visited
            .Ldloc(labelIndexToLocation.GetRef())
            .Ldloca(threadTmp.GetRef())
            .Ldfld(LabelIndexField)
            .Ldloc(inputPump.Index.GetRef())
            .Stelem_I4()
            ;

            suspendedStack.PushFrom(emit, threadTmp);

            emit
            .Br(NEXT_THREAD.GetRef())

            .Label(RESUME_ALL)
            .Swap(suspendedStack.Stack, runningStack.Stack, tmpStack.Stack)
            .Swap(suspendedStack.Index, runningStack.Index, tmpStack.Index)
            .Label(NEXT_THREAD)
            ;

            runningStack
            .StackLoop(
                emit,
                (emit2, thread) =>
            {
                emit2
                .Ldloca(thread.GetRef())
                .Ldfld(LabelIndexField)
                .Label(THREAD_DISPATCH)
                .Switch(indexToLabel.Select(def => def.GetRef()).ToArray())
                .Br(settings.FAILURE.GetRef());
            })
            ;
            emit
            .Br(NEXT_INPUT.GetRef())
            ;

            emit
            .Label(NEXT_INPUT)
            ;

            inputPump.EmitLoopPass(emit, false);

            emit
            // Check if there are matched threads:
            .Do(matchedStack.LdCount)
            .Ldc_I4_0()
            .Beq(settings.FAILURE.GetRef())
            .Br(settings.SUCCESS.GetRef());
        }