예제 #1
0
        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()));
            }
        }
예제 #2
0
        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);
            }
        }