예제 #1
0
            public object CallScriptProcedure(ScriptProcedure procedure, List <object> actuals)
            {
                int startFrame     = frames.Count;
                int startEvalStack = evalStack.Count;

                {
                    Env localEnv = new Env {
                        prevEnv = null, variables = new object[procedure.meta.localVarCount],
                    };
                    for (int i = 0; i < actuals.Count; ++i)
                    {
                        localEnv.variables[i] = actuals[i];
                    }
                    frames.Push(new StackFrame {
                        procedure = procedure, localEnv = localEnv, pc = 0,
                    });
                }

Label_PeekFrame:
                while (frames.Count > startFrame)
                {
                    if (frames.Count > MaxStackFrameCount)
                    {
                        throw new Exception("Stack frame overflow: " + MaxStackFrameCount);
                    }
                    if (evalStack.Count > MaxEvalStackDepth)
                    {
                        throw new Exception("Eval stack overflow: " + MaxEvalStackDepth);
                    }

                    StackFrame    frame           = frames.Peek();
                    object[]      localVaraibles  = frame.localEnv.variables;
                    object[][]    freeVariables   = frame.procedure.freeVariables;
                    List <object> globalVariables = GlobalEnv.Instance().variables;
                    object[]      literals        = frame.procedure.meta.literals;
                    int[]         byteCodes       = frame.procedure.meta.byteCodes;

                    int pc = frame.pc;
                    while (pc < byteCodes.Length)
                    {
                        switch (byteCodes[pc])
                        {
                        case ByteCodeEnum.PUSH_LITERAL: {
                            evalStack.Add(literals[byteCodes[pc + 1]]);
                            pc += 2;
                        }
                        break;

                        case ByteCodeEnum.PUSH_LOCAL: {
                            evalStack.Add(localVaraibles[byteCodes[pc + 1]]);
                            pc += 2;
                        }
                        break;

                        case ByteCodeEnum.POP_LOCAL: {
                            localVaraibles[byteCodes[pc + 1]] = evalStack.Last();
                            evalStack.RemoveAt(evalStack.Count - 1);
                            pc += 2;
                        }
                        break;

                        case ByteCodeEnum.PUSH_GLOBAL: {
                            evalStack.Add(globalVariables[byteCodes[pc + 1]]);
                            pc += 2;
                        }
                        break;

                        case ByteCodeEnum.POP_GLOBAL: {
                            globalVariables[byteCodes[pc + 1]] = evalStack.Last();
                            evalStack.RemoveAt(evalStack.Count - 1);
                            pc += 2;
                        }
                        break;

                        case ByteCodeEnum.PUSH_FREE: {
                            evalStack.Add(freeVariables[byteCodes[pc + 1]][byteCodes[pc + 2]]);
                            pc += 3;
                        }
                        break;

                        case ByteCodeEnum.POP_FREE: {
                            freeVariables[byteCodes[pc + 1]][byteCodes[pc + 2]] = evalStack.Last();
                            evalStack.RemoveAt(evalStack.Count - 1);
                            pc += 3;
                        }
                        break;

                        case ByteCodeEnum.POP1: {
                            evalStack.RemoveAt(evalStack.Count - 1);
                            pc += 1;
                        }
                        break;

                        case ByteCodeEnum.CJMP: {
                            var b = (bool)evalStack.Last();
                            evalStack.RemoveAt(evalStack.Count - 1);
                            if (b)
                            {
                                pc = byteCodes[pc + 1];
                            }
                            else
                            {
                                pc += 2;
                            }
                        }
                        break;

                        case ByteCodeEnum.JMP: {
                            pc = byteCodes[pc + 1];
                        }
                        break;

                        case ByteCodeEnum.PUSH_SCRIPT_PROCEDURE: {
                            evalStack.Add(new ScriptProcedure(frame.localEnv, (ScriptProcedureMeta)literals[byteCodes[pc + 1]]));
                            pc += 2;
                        }
                        break;

                        case ByteCodeEnum.TAIL_CALL:
                        case ByteCodeEnum.CALL: {
                            int    actualCount    = byteCodes[pc + 1];
                            object p              = evalStack[evalStack.Count - actualCount - 1];
                            var    hostProcuedure = p as HostProcedure;
                            if (hostProcuedure != null)
                            {
                                hostProcuedure(evalStack, evalStack.Count - actualCount - 1);
                                evalStack.RemoveRange(evalStack.Count - actualCount, actualCount);
                                pc += 2;
                            }
                            else
                            {
                                if (byteCodes[pc] == ByteCodeEnum.TAIL_CALL)
                                {
                                    frames.Pop();
                                }
                                else
                                {
                                    frame.pc = pc + 2;
                                }

                                var scriptProcedure = (ScriptProcedure)p;
                                Env localEnv        = new Env {
                                    prevEnv = scriptProcedure.freeEnv, variables = new object[scriptProcedure.meta.localVarCount]
                                };
                                for (int i = 0; i < actualCount; ++i)
                                {
                                    localEnv.variables[i] = evalStack[evalStack.Count - actualCount + i];
                                }
                                evalStack.RemoveRange(evalStack.Count - actualCount - 1, actualCount + 1);

                                frames.Push(new StackFrame {
                                        procedure = scriptProcedure, localEnv = localEnv, pc = 0
                                    });
                                goto Label_PeekFrame;
                            }
                        }
                        break;

                        default:
                            throw new Exception("Unkown bytecode :" + byteCodes[pc]);
                        }
                    }

                    frames.Pop();
                }

                object r = evalStack[startEvalStack];

                evalStack.RemoveAt(startEvalStack);
                return(r);
            }
예제 #2
0
            public object CallScriptProcedure(ScriptProcedure procedure, List<object> actuals)
            {
                int startFrame = frames.Count;
                int startEvalStack = evalStack.Count;

                {
                    Env localEnv = new Env { prevEnv=null, variables=new object[procedure.meta.localVarCount],};
                    for (int i = 0; i < actuals.Count; ++i) localEnv.variables[i] = actuals[i];
                    frames.Push(new StackFrame { procedure=procedure, localEnv=localEnv, pc=0, });
                }

                Label_PeekFrame:
                while (frames.Count > startFrame) {
                    if (frames.Count > MaxStackFrameCount) throw new Exception("Stack frame overflow: " + MaxStackFrameCount);
                    if (evalStack.Count > MaxEvalStackDepth) throw new Exception("Eval stack overflow: " + MaxEvalStackDepth);

                    StackFrame frame = frames.Peek();
                    object[] localVaraibles = frame.localEnv.variables;
                    object[][] freeVariables = frame.procedure.freeVariables;
                    List<object> globalVariables = GlobalEnv.Instance().variables;
                    object[] literals = frame.procedure.meta.literals;
                    int[] byteCodes = frame.procedure.meta.byteCodes;

                    int pc = frame.pc;
                    while (pc < byteCodes.Length) {
                        switch (byteCodes[pc]) {
                            case ByteCodeEnum.PUSH_LITERAL: {
                                    evalStack.Add(literals[byteCodes[pc + 1]]);
                                    pc += 2;
                                }
                                break;
                            case ByteCodeEnum.PUSH_LOCAL: {
                                    evalStack.Add(localVaraibles[byteCodes[pc + 1]]);
                                    pc += 2;
                                }
                                break;
                            case ByteCodeEnum.POP_LOCAL: {
                                    localVaraibles[byteCodes[pc + 1]] = evalStack.Last();
                                    evalStack.RemoveAt(evalStack.Count - 1);
                                    pc += 2;
                                }
                                break;
                            case ByteCodeEnum.PUSH_GLOBAL: {
                                    evalStack.Add(globalVariables[byteCodes[pc + 1]]);
                                    pc += 2;
                                }
                                break;
                            case ByteCodeEnum.POP_GLOBAL: {
                                    globalVariables[byteCodes[pc + 1]] = evalStack.Last();
                                    evalStack.RemoveAt(evalStack.Count - 1);
                                    pc += 2;
                                }
                                break;
                            case ByteCodeEnum.PUSH_FREE: {
                                    evalStack.Add(freeVariables[byteCodes[pc + 1]][byteCodes[pc + 2]]);
                                    pc += 3;
                                }
                                break;
                            case ByteCodeEnum.POP_FREE: {
                                    freeVariables[byteCodes[pc + 1]][byteCodes[pc + 2]] = evalStack.Last();
                                    evalStack.RemoveAt(evalStack.Count - 1);
                                    pc += 3;
                                }
                                break;
                            case ByteCodeEnum.POP1: {
                                    evalStack.RemoveAt(evalStack.Count - 1);
                                    pc += 1;
                                }
                                break;
                            case ByteCodeEnum.CJMP: {
                                    var b = (bool)evalStack.Last();
                                    evalStack.RemoveAt(evalStack.Count - 1);
                                    if (b) pc = byteCodes[pc + 1];
                                    else pc += 2;
                                }
                                break;
                            case ByteCodeEnum.JMP: {
                                    pc = byteCodes[pc + 1];
                                }
                                break;
                            case ByteCodeEnum.PUSH_SCRIPT_PROCEDURE: {
                                evalStack.Add(new ScriptProcedure(frame.localEnv, (ScriptProcedureMeta)literals[byteCodes[pc + 1]]));
                                pc += 2;
                            }
                                break;
                            case ByteCodeEnum.TAIL_CALL:
                            case ByteCodeEnum.CALL: {
                                int actualCount = byteCodes[pc + 1];
                                object p = evalStack[evalStack.Count - actualCount - 1];
                                var hostProcuedure = p as HostProcedure;
                                if (hostProcuedure != null) {
                                    hostProcuedure(evalStack, evalStack.Count - actualCount - 1);
                                    evalStack.RemoveRange(evalStack.Count - actualCount, actualCount);
                                    pc += 2;
                                } else {
                                    if (byteCodes[pc] == ByteCodeEnum.TAIL_CALL) {
                                        frames.Pop();
                                    } else {
                                        frame.pc = pc + 2;
                                    }

                                    var scriptProcedure = (ScriptProcedure)p;
                                    Env localEnv = new Env { prevEnv=scriptProcedure.freeEnv, variables=new object[scriptProcedure.meta.localVarCount]};
                                    for (int i = 0; i < actualCount; ++i) {
                                        localEnv.variables[i] = evalStack[evalStack.Count - actualCount + i];
                                    }
                                    evalStack.RemoveRange(evalStack.Count - actualCount - 1, actualCount + 1);

                                    frames.Push(new StackFrame { procedure = scriptProcedure, localEnv = localEnv, pc = 0 });
                                    goto Label_PeekFrame;
                                }
                            }
                                break;
                            default:
                                throw new Exception("Unkown bytecode :" + byteCodes[pc]);
                        }
                    }

                    frames.Pop();
                }

                object r = evalStack[startEvalStack];
                evalStack.RemoveAt(startEvalStack);
                return r;
            }