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