private void ProcessCurrentEvi(NativeCallContext currentFrame, ElfVmInstruction currentEvi) { // perverted solution, but I really cba to introduce an enum for evis // neither I like solution with introduction of visitor var @this = Ctx.CallStack.Peek().Scopes.Last()["@this"]; var scopeResolver = (IScopeResolver)Activator.CreateInstance(@this.Type.ScopeResolver); var invocationResolver = (IInvocationResolver)Activator.CreateInstance(@this.Type.InvocationResolver); switch (currentEvi.GetType().Name.ToLower()) { case "decl": var decl = (Decl)currentEvi; scopeResolver.Declare(Ctx, decl.Name, @this); ++currentFrame.CurrentEvi; break; case "dup": currentFrame.Stack.Push(currentFrame.Stack.Peek()); ++currentFrame.CurrentEvi; break; case "enter": scopeResolver.EnterScope(Ctx, @this); ++currentFrame.CurrentEvi; break; case "invoke": var invoke = (Invoke)currentEvi; var args = new IElfObject[invoke.Argc]; for (var i = invoke.Argc - 1; i >= 0; --i) args[i] = currentFrame.Stack.Pop(); try {invocationResolver.PrepareCallContext(Ctx, invoke.Name, @this, args);} catch (Exception e) { // that's pretty awful, tho logically correct if (e is ErroneousScriptRuntimeException) throw; throw new UnexpectedRtimplRuntimeException(VM, String.Format( "Fatal runtime error in an Elf thread. VM dump:{0}{1}", Environment.NewLine, VM.DumpAll()), e); } if (Ctx.PendingClrCall != null) ProcessClrCall(Ctx.PendingClrCall); ++currentFrame.CurrentEvi; break; case "jf": case "jt": var test = currentFrame.Stack.Pop(); if (!(test is ElfBoolean)) { throw new ErroneousScriptRuntimeException(ElfExceptionType.ConditionNotBoolean, VM); } else { var jf = currentEvi as Jf; var jt = currentEvi as Jt; var jlabel = jf != null ? jf.Label : jt.Label; if ((((ElfBoolean)test).Val) ^ jf != null) { var target = currentFrame.Source.Body .OfType<Label>().Single(b => b.Name == jlabel); currentFrame.CurrentEvi = Array.IndexOf(currentFrame.Source.Body, target); } else { ++currentFrame.CurrentEvi; } } break; case "label": ++currentFrame.CurrentEvi; break; case "leave": scopeResolver.LeaveScope(Ctx, @this); ++currentFrame.CurrentEvi; break; case "pop": currentFrame.Stack.Pop(); ++currentFrame.CurrentEvi; break; case "popall": currentFrame.Stack.Clear(); ++currentFrame.CurrentEvi; break; case "popref": var value = currentFrame.Stack.Pop(); var popRef = (PopRef)currentEvi; try {scopeResolver.Set(Ctx, popRef.Ref, value, @this);} catch (Exception e) { // that's pretty awful, tho logically correct if (e is ErroneousScriptRuntimeException) throw; throw new UnexpectedRtimplRuntimeException(VM, String.Format( "Fatal runtime error in an Elf thread. VM dump:{0}{1}", Environment.NewLine, VM.DumpAll()), e); } ++currentFrame.CurrentEvi; break; case "pushref": var pushRef = (PushRef)currentEvi; IElfObject value2; try { value2 = scopeResolver.Get(Ctx, pushRef.Ref, @this); } catch(Exception e) { // that's pretty awful, tho logically correct if (e is ErroneousScriptRuntimeException) throw; throw new UnexpectedRtimplRuntimeException(VM, String.Format( "Fatal runtime error in an Elf thread. VM dump:{0}{1}", Environment.NewLine, VM.DumpAll()), e); } currentFrame.Stack.Push(value2); ++currentFrame.CurrentEvi; break; case "pushval": var pushVal = (PushVal)currentEvi; var value3 = VM.Marshaller.Unmarshal(pushVal.Val); currentFrame.Stack.Push(value3); ++currentFrame.CurrentEvi; break; case "ret": var retval = currentFrame.Stack.SingleOrDefault() ?? new ElfVoid(); Ctx.CallStack.Pop(); if (Ctx.CallStack.Count > 0) { Ctx.CallStack.Peek().Stack.Push(retval); } else { ExecutionResult = retval; } break; default: throw new UnexpectedElfRuntimeException(VM, String.Format( "Fatal error executing evi '{0}'. Reason: evi type '{1}' not supported.", currentEvi, currentEvi.GetType())); } }
private IEnumerable<ElfVmInstruction> Compile(AstNode node) { try { if (node == null) { return new ElfVmInstruction[0]; } else { IEnumerable<ElfVmInstruction> compiledImpl; switch (node.NodeType) { case AstNodeType.Block: compiledImpl = CompileBlock((Block)node); break; case AstNodeType.EmptyStatement: compiledImpl = new ElfVmInstruction[0]; break; case AstNodeType.ExpressionStatement: compiledImpl = CompileExpression((ExpressionStatement)node); break; case AstNodeType.VarStatement: compiledImpl = CompileVar((VarStatement)node); break; case AstNodeType.IfStatement: compiledImpl = CompileIf((IfStatement)node); break; case AstNodeType.ReturnStatement: compiledImpl = CompileReturn((ReturnStatement)node); break; case AstNodeType.LiteralExpression: compiledImpl = CompileLiteral((LiteralExpression)node); break; case AstNodeType.VariableExpression: compiledImpl = CompileVariable((VariableExpression)node); break; case AstNodeType.AssignmentExpression: compiledImpl = CompileAssignment((AssignmentExpression)node); break; case AstNodeType.InvocationExpression: compiledImpl = CompileInvocation((InvocationExpression)node); break; default: throw new NotSupportedException(node.ToString()); } var compiled = compiledImpl.ToArray(); compiled.ForEach(evi => evi.BindToAstNode(node)); return compiled; } } catch (Exception e) { if (e is UnexpectedCompilerException) throw; throw new UnexpectedCompilerException(Func, node, e); } }