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); }
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()); ; }
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 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()); }
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() ; }