| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using MoonSharp.Interpreter.DataStructs;
- using MoonSharp.Interpreter.Debugging;
- namespace MoonSharp.Interpreter.Execution.VM
- {
- sealed partial class Processor
- {
- private DynValue Processing_Loop(int instructionPtr)
- {
- repeat_execution:
- try
- {
- while (true)
- {
- Instruction i = m_RootChunk.Code[instructionPtr];
- if (m_DebuggerAttached != null)
- {
- ListenDebugger(i, instructionPtr);
- }
- ++instructionPtr;
- switch (i.OpCode)
- {
- case OpCode.Nop:
- case OpCode.Debug:
- break;
- case OpCode.Pop:
- m_ValueStack.RemoveLast(i.NumVal);
- break;
- case OpCode.Copy:
- m_ValueStack.Push(m_ValueStack.Peek(i.NumVal));
- break;
- case OpCode.Swap:
- ExecSwap(i);
- break;
- case OpCode.Literal:
- m_ValueStack.Push(i.Value);
- break;
- case OpCode.Add:
- instructionPtr = ExecAdd(i, instructionPtr);
- break;
- case OpCode.Concat:
- instructionPtr = ExecConcat(i, instructionPtr);
- break;
- case OpCode.Neg:
- instructionPtr = ExecNeg(i, instructionPtr);
- break;
- case OpCode.Sub:
- instructionPtr = ExecSub(i, instructionPtr);
- break;
- case OpCode.Mul:
- instructionPtr = ExecMul(i, instructionPtr);
- break;
- case OpCode.Div:
- instructionPtr = ExecDiv(i, instructionPtr);
- break;
- case OpCode.Mod:
- instructionPtr = ExecMod(i, instructionPtr);
- break;
- case OpCode.Power:
- instructionPtr = ExecPower(i, instructionPtr);
- break;
- case OpCode.Eq:
- instructionPtr = ExecEq(i, instructionPtr);
- break;
- case OpCode.LessEq:
- instructionPtr = ExecLessEq(i, instructionPtr);
- break;
- case OpCode.Less:
- instructionPtr = ExecLess(i, instructionPtr);
- break;
- case OpCode.Len:
- instructionPtr = ExecLen(i, instructionPtr);
- break;
- case OpCode.Call:
- instructionPtr = Internal_ExecCall(i.NumVal, instructionPtr);
- break;
- case OpCode.Scalar:
- m_ValueStack.Push(m_ValueStack.Pop().ToScalar());
- break;
- case OpCode.Not:
- ExecNot(i);
- break;
- case OpCode.JfOrPop:
- case OpCode.JtOrPop:
- instructionPtr = ExecShortCircuitingOperator(i, instructionPtr);
- break;
- case OpCode.JNil:
- {
- DynValue v = m_ValueStack.Pop();
- if (v.Type == DataType.Nil)
- instructionPtr = i.NumVal;
- }
- break;
- case OpCode.Jf:
- instructionPtr = JumpBool(i, false, instructionPtr);
- break;
- case OpCode.Jump:
- instructionPtr = i.NumVal;
- break;
- case OpCode.MkTuple:
- ExecMkTuple(i);
- break;
- case OpCode.Enter:
- NilifyBlockData(i);
- break;
- case OpCode.Leave:
- case OpCode.Exit:
- ClearBlockData(i);
- break;
- case OpCode.Closure:
- ExecClosure(i);
- break;
- case OpCode.BeginFn:
- ExecBeginFn(i);
- break;
- case OpCode.ToBool:
- m_ValueStack.Push(DynValue.NewBoolean(m_ValueStack.Pop().CastToBool()));
- break;
- case OpCode.Args:
- ExecArgs(i);
- break;
- case OpCode.Ret:
- instructionPtr = ExecRet(i);
- if (instructionPtr < 0)
- goto return_to_native_code;
- break;
- case OpCode.Incr:
- ExecIncr(i);
- break;
- case OpCode.ToNum:
- ExecToNum(i);
- break;
- case OpCode.JFor:
- instructionPtr = ExecJFor(i, instructionPtr);
- break;
- case OpCode.NewTable:
- m_ValueStack.Push(DynValue.NewTable(this.m_Script));
- break;
- case OpCode.IterPrep:
- ExecIterPrep(i);
- break;
- case OpCode.IterUpd:
- ExecIterUpd(i);
- break;
- case OpCode.ExpTuple:
- ExecExpTuple(i);
- break;
- case OpCode.Local:
- m_ValueStack.Push(m_ExecutionStack.Peek().LocalScope[i.Symbol.i_Index]);
- break;
- case OpCode.Upvalue:
- m_ValueStack.Push(m_ExecutionStack.Peek().ClosureScope[i.Symbol.i_Index]);
- break;
- case OpCode.StoreUpv:
- ExecStoreUpv(i);
- break;
- case OpCode.StoreLcl:
- ExecStoreLcl(i);
- break;
- case OpCode.TblInitN:
- ExecTblInitN(i);
- break;
- case OpCode.TblInitI:
- ExecTblInitI(i);
- break;
- case OpCode.Index:
- instructionPtr = ExecIndex(i, instructionPtr);
- break;
- case OpCode.PushEnv:
- m_ValueStack.Push(DynValue.NewTable(m_GlobalTable));
- break;
- case OpCode.IndexSet:
- instructionPtr = ExecIndexSet(i, instructionPtr);
- break;
- case OpCode.Invalid:
- throw new NotImplementedException(string.Format("Invalid opcode : {0}", i.Name));
- default:
- throw new NotImplementedException(string.Format("Execution for {0} not implented yet!", i.OpCode));
- }
- }
- }
- catch (ScriptRuntimeException ex)
- {
- while (m_ExecutionStack.Count > 0)
- {
- CallStackItem csi = PopToBasePointer();
- CallMode mode = csi.Mode;
- if (mode == CallMode.PCall)
- {
- instructionPtr = csi.ReturnAddress;
- var argscnt = (int)(m_ValueStack.Pop().Number);
- m_ValueStack.RemoveLast(argscnt + 1);
- m_ValueStack.Push(DynValue.NewTuple(DynValue.False, DynValue.NewString(ex.Message)));
- goto repeat_execution;
- }
- }
- if (m_ExecutionStack.Count == 0)
- {
- throw;
- }
- }
- return_to_native_code:
- if (m_ValueStack.Count == 1)
- return m_ValueStack.Pop();
- else if (m_ValueStack.Count == 0)
- return DynValue.Nil;
- else
- throw new InternalErrorException("Unexpected value stack count at program end : {0}", m_ValueStack.Count);
- }
- private void AssignLocal(SymbolRef symref, DynValue value)
- {
- var stackframe = m_ExecutionStack.Peek();
- DynValue v = stackframe.LocalScope[symref.i_Index];
- if (v == null)
- stackframe.LocalScope[symref.i_Index] = v = DynValue.NewNil();
- v.Assign(value);
- }
- private void ExecStoreLcl(Instruction i)
- {
- DynValue value = GetStoreValue(i);
- SymbolRef symref = i.Symbol;
- AssignLocal(symref, value);
- }
- private void ExecStoreUpv(Instruction i)
- {
- DynValue value = GetStoreValue(i);
- SymbolRef symref = i.Symbol;
- var stackframe = m_ExecutionStack.Peek();
- DynValue v = stackframe.ClosureScope[symref.i_Index];
- if (v == null)
- stackframe.ClosureScope[symref.i_Index] = v = DynValue.NewNil();
- v.Assign(value);
- }
- private void ExecSwap(Instruction i)
- {
- DynValue v1 = m_ValueStack.Peek(i.NumVal);
- DynValue v2 = m_ValueStack.Peek(i.NumVal2);
- m_ValueStack.Set(i.NumVal, v2);
- m_ValueStack.Set(i.NumVal2, v1);
- }
- private DynValue GetStoreValue(Instruction i)
- {
- int stackofs = i.NumVal;
- int tupleidx = i.NumVal2;
- DynValue v = m_ValueStack.Peek(stackofs);
- if (v.Type == DataType.Tuple)
- {
- return (tupleidx < v.Tuple.Length) ? v.Tuple[tupleidx] : DynValue.NewNil();
- }
- else
- {
- return (tupleidx == 0) ? v : DynValue.NewNil();
- }
- }
- private void ExecClosure(Instruction i)
- {
- Closure c = new Closure(this.m_Script, i.NumVal, i.SymbolList,
- i.SymbolList.Select(s => this.GetUpvalueSymbol(s)).ToList());
- m_ValueStack.Push(DynValue.NewClosure(c));
- }
- private DynValue GetUpvalueSymbol(SymbolRef s)
- {
- if (s.Type == SymbolRefType.Local)
- return m_ExecutionStack.Peek().LocalScope[s.i_Index];
- else if (s.Type == SymbolRefType.Upvalue)
- return m_ExecutionStack.Peek().ClosureScope[s.i_Index];
- else
- throw new Exception("unsupported symbol type");
- }
- private void ExecMkTuple(Instruction i)
- {
- Slice<DynValue> slice = new Slice<DynValue>(m_ValueStack, m_ValueStack.Count - i.NumVal, i.NumVal, false);
- var v = Internal_AdjustTuple(slice);
- m_ValueStack.RemoveLast(i.NumVal);
- m_ValueStack.Push(DynValue.NewTuple(v));
- }
- private void ExecToNum(Instruction i)
- {
- double? v = m_ValueStack.Pop().CastToNumber();
- if (v.HasValue)
- m_ValueStack.Push(DynValue.NewNumber(v.Value));
- else
- throw new ScriptRuntimeException(null, "Can't convert value to number");
- }
- private void ExecIterUpd(Instruction i)
- {
- DynValue v = m_ValueStack.Peek(0);
- DynValue t = m_ValueStack.Peek(1);
- t.Tuple[2] = v;
- }
- private void ExecExpTuple(Instruction i)
- {
- DynValue t = m_ValueStack.Peek(i.NumVal);
- if (t.Type == DataType.Tuple)
- {
- for (int idx = 0; idx < t.Tuple.Length; idx++)
- m_ValueStack.Push(t.Tuple[idx]);
- }
- else
- {
- m_ValueStack.Push(t);
- }
- }
- private void ExecIterPrep(Instruction i)
- {
- DynValue v = m_ValueStack.Pop();
- if (v.Type != DataType.Tuple)
- {
- v = DynValue.NewTuple(v, DynValue.Nil, DynValue.Nil);
- }
- else if (v.Tuple.Length > 3)
- {
- v = DynValue.NewTuple(v.Tuple[0], v.Tuple[1], v.Tuple[2]);
- }
- else if (v.Tuple.Length == 2)
- {
- v = DynValue.NewTuple(v.Tuple[0], v.Tuple[1], DynValue.Nil);
- }
- else if (v.Tuple.Length == 1)
- {
- v = DynValue.NewTuple(v.Tuple[0], DynValue.Nil, DynValue.Nil);
- }
- m_ValueStack.Push(v);
- }
- private int ExecJFor(Instruction i, int instructionPtr)
- {
- double val = m_ValueStack.Peek(0).Number;
- double step = m_ValueStack.Peek(1).Number;
- double stop = m_ValueStack.Peek(2).Number;
- bool whileCond = (step > 0) ? val <= stop : val >= stop;
- if (!whileCond)
- return i.NumVal;
- else
- return instructionPtr;
- }
- private void ExecIncr(Instruction i)
- {
- DynValue top = m_ValueStack.Peek(0);
- DynValue btm = m_ValueStack.Peek(i.NumVal);
- if (top.ReadOnly)
- {
- m_ValueStack.Pop();
- top = top.CloneAsWritable();
- m_ValueStack.Push(top);
- }
- top.AssignNumber(top.Number + btm.Number);
- }
- private void ExecNot(Instruction i)
- {
- DynValue v = m_ValueStack.Pop();
- m_ValueStack.Push(DynValue.NewBoolean(!(v.CastToBool())));
- }
- private void ExecBeginFn(Instruction i)
- {
- CallStackItem c = m_ExecutionStack.Peek();
- c.Debug_Symbols = i.SymbolList;
- c.LocalScope = new DynValue[i.NumVal];
- if (i.NumVal2 >= 0 && i.NumVal > 0)
- {
- for (int idx = 0; idx < i.NumVal2; idx++)
- {
- c.LocalScope[idx] = DynValue.NewNil();
- }
- }
- }
- private CallStackItem PopToBasePointer()
- {
- var csi = m_ExecutionStack.Pop();
- m_ValueStack.CropAtCount(csi.BasePointer);
- return csi;
- }
- private int PopExecStackAndCheckVStack(int vstackguard)
- {
- var xs = m_ExecutionStack.Pop();
- if (vstackguard != xs.BasePointer)
- throw new InternalErrorException("StackGuard violation");
- return xs.ReturnAddress;
- }
- private void ExecArgs(Instruction I)
- {
- int numargs = (int)m_ValueStack.Peek(0).Number;
- for (int i = 0; i < I.SymbolList.Length; i++)
- {
- if (i >= numargs)
- {
- this.AssignLocal(I.SymbolList[i], DynValue.NewNil());
- }
- else if ((i == I.SymbolList.Length - 1) && (I.SymbolList[i].i_Name == "..."))
- {
- int len = numargs - i;
- DynValue[] varargs = new DynValue[len];
- for (int ii = 0; ii < len; ii++)
- {
- varargs[ii] = m_ValueStack.Peek(numargs - i - ii).CloneAsWritable();
- }
- this.AssignLocal(I.SymbolList[i], DynValue.NewTuple(varargs));
- }
- else
- {
- this.AssignLocal(I.SymbolList[i], m_ValueStack.Peek(numargs - i).CloneAsWritable());
- }
- }
- }
- private int Internal_ExecCall(int argsCount, int instructionPtr, CallMode mode = CallMode.Normal)
- {
- DynValue fn = m_ValueStack.Peek(argsCount);
- if (fn.Type == DataType.ClrFunction)
- {
- IList<DynValue> args = new Slice<DynValue>(m_ValueStack, m_ValueStack.Count - argsCount, argsCount, false);
- var ret = fn.Callback.Invoke(new ScriptExecutionContext(this, fn.Callback), args);
- m_ValueStack.RemoveLast(argsCount + 1);
- m_ValueStack.Push(ret);
- return Internal_CheckForTailRequests(null, instructionPtr);
- }
- else if (fn.Type == DataType.Function)
- {
- m_ValueStack.Push(DynValue.NewNumber(argsCount));
- m_ExecutionStack.Push(new CallStackItem()
- {
- BasePointer = m_ValueStack.Count,
- ReturnAddress = instructionPtr,
- Debug_EntryPoint = fn.Function.ByteCodeLocation,
- ClosureScope = fn.Function.ClosureContext,
- Mode = mode,
- });
- return fn.Function.ByteCodeLocation;
- }
- else
- {
- if (fn.MetaTable != null)
- {
- var m = fn.MetaTable.RawGet("__call");
- if (m != null && m.Type != DataType.Nil)
- {
- DynValue[] tmp = new DynValue[argsCount + 1];
- for (int i = 0; i < argsCount + 1; i++)
- tmp[i] = m_ValueStack.Pop();
- m_ValueStack.Push(m);
- for (int i = argsCount; i >= 0; i--)
- m_ValueStack.Push(tmp[i]);
- return Internal_ExecCall(argsCount + 1, instructionPtr);
- }
- }
- throw new NotImplementedException("Can't call non function - " + fn.ToString());
- }
- }
- private int ExecRet(Instruction i)
- {
- CallStackItem csi;
- int retpoint = 0;
- if (i.NumVal == 0)
- {
- csi = PopToBasePointer();
- retpoint = csi.ReturnAddress;
- var argscnt = (int)(m_ValueStack.Pop().Number);
- m_ValueStack.RemoveLast(argscnt + 1);
- m_ValueStack.Push(DynValue.Nil);
- }
- else if (i.NumVal == 1)
- {
- var retval = m_ValueStack.Pop();
- csi = PopToBasePointer();
- retpoint = csi.ReturnAddress;
- var argscnt = (int)(m_ValueStack.Pop().Number);
- m_ValueStack.RemoveLast(argscnt + 1);
- m_ValueStack.Push(retval);
- retpoint = Internal_CheckForTailRequests(i, retpoint);
- }
- else
- {
- throw new InternalErrorException("RET supports only 0 and 1 ret val scenarios");
- }
- if (csi.Mode != CallMode.Normal)
- AdjustRetValueForMode(csi.Mode);
- return retpoint;
- }
- private void AdjustRetValueForMode(CallMode callMode)
- {
- DynValue r = m_ValueStack.Pop();
- switch (callMode)
- {
- case CallMode.PCall:
- m_ValueStack.Push(DynValue.NewTupleNested(DynValue.True, r));
- break;
- case CallMode.Require:
- break;
- case CallMode.Normal:
- default:
- throw new InternalErrorException("Unreachable case .. reached");
- }
-
- }
- private int Internal_CheckForTailRequests(Instruction i, int instructionPtr)
- {
- DynValue tail = m_ValueStack.Peek(0);
- if (tail.Type == DataType.TailCallRequest)
- {
- m_ValueStack.Pop(); // discard tail call request
- TailCallData tcd = (TailCallData)tail.UserObject;
- m_ValueStack.Push(tcd.Function);
- for (int ii = 0; ii < tcd.Args.Length; ii++)
- m_ValueStack.Push(tcd.Args[ii]);
- //instructionPtr -= 1;
- return Internal_ExecCall(tcd.Args.Length, instructionPtr, tcd.Mode);
- }
- return instructionPtr;
- }
- private int JumpBool(Instruction i, bool expectedValueForJump, int instructionPtr)
- {
- DynValue op = m_ValueStack.Pop();
- if (op.CastToBool() == expectedValueForJump)
- return i.NumVal;
- return instructionPtr;
- }
- private int ExecShortCircuitingOperator(Instruction i, int instructionPtr)
- {
- bool expectedValToShortCircuit = i.OpCode == OpCode.JtOrPop;
- DynValue op = m_ValueStack.Peek();
- if (op.CastToBool() == expectedValToShortCircuit)
- {
- return i.NumVal;
- }
- else
- {
- m_ValueStack.Pop();
- return instructionPtr;
- }
- }
- private int ExecAdd(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop();
- DynValue l = m_ValueStack.Pop();
- double? rn = r.CastToNumber();
- double? ln = l.CastToNumber();
- if (ln.HasValue && rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(ln.Value + rn.Value));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__add", instructionPtr);
- if (ip >= 0) return ip;
- else throw new ScriptRuntimeException(null, "Arithmetic on non numbers");
- }
- }
- private int ExecSub(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop();
- DynValue l = m_ValueStack.Pop();
- double? rn = r.CastToNumber();
- double? ln = l.CastToNumber();
- if (ln.HasValue && rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(ln.Value - rn.Value));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__sub", instructionPtr);
- if (ip >= 0) return ip;
- else throw new ScriptRuntimeException(null, "Arithmetic on non numbers");
- }
- }
- private int ExecMul(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop();
- DynValue l = m_ValueStack.Pop();
- double? rn = r.CastToNumber();
- double? ln = l.CastToNumber();
- if (ln.HasValue && rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(ln.Value * rn.Value));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__mul", instructionPtr);
- if (ip >= 0) return ip;
- else throw new ScriptRuntimeException(null, "Arithmetic on non numbers");
- }
- }
- private int ExecMod(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop();
- DynValue l = m_ValueStack.Pop();
- double? rn = r.CastToNumber();
- double? ln = l.CastToNumber();
- if (ln.HasValue && rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(Math.IEEERemainder(ln.Value, rn.Value)));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__div", instructionPtr);
- if (ip >= 0) return ip;
- else throw new ScriptRuntimeException(null, "Arithmetic on non numbers");
- }
- }
- private int ExecDiv(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop();
- DynValue l = m_ValueStack.Pop();
- double? rn = r.CastToNumber();
- double? ln = l.CastToNumber();
- if (ln.HasValue && rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(ln.Value / rn.Value));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__div", instructionPtr);
- if (ip >= 0) return ip;
- else throw new ScriptRuntimeException(null, "Arithmetic on non numbers");
- }
- }
- private int ExecPower(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop();
- DynValue l = m_ValueStack.Pop();
- double? rn = r.CastToNumber();
- double? ln = l.CastToNumber();
- if (ln.HasValue && rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(Math.Pow(ln.Value, rn.Value)));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__pow", instructionPtr);
- if (ip >= 0) return ip;
- else throw new ScriptRuntimeException(null, "Arithmetic on non numbers");
- }
- }
- private int ExecNeg(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop();
- double? rn = r.CastToNumber();
- if (rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(-rn.Value));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeUnaryMetaMethod(r, "__unm", instructionPtr);
- if (ip >= 0) return ip;
- else throw new ScriptRuntimeException(null, "Arithmetic on non number");
- }
- }
- private int ExecEq(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop();
- DynValue l = m_ValueStack.Pop();
- if (object.ReferenceEquals(r, l))
- {
- m_ValueStack.Push(DynValue.True);
- }
- else if (r.Type != l.Type)
- {
- m_ValueStack.Push(DynValue.False);
- }
- else if ((l.Type == DataType.Table || l.Type == DataType.UserData) && (l.MetaTable != null) && (l.MetaTable == r.MetaTable))
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__eq", instructionPtr);
- if (ip < 0)
- m_ValueStack.Push(DynValue.NewBoolean(r.Equals(l)));
- else
- return ip;
- }
- else
- {
- m_ValueStack.Push(DynValue.NewBoolean(r.Equals(l)));
- }
- return instructionPtr;
- }
- private int ExecLess(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop();
- DynValue l = m_ValueStack.Pop();
- if (l.Type == DataType.Number && r.Type == DataType.Number)
- {
- m_ValueStack.Push(DynValue.NewBoolean(l.Number < r.Number));
- }
- else if (l.Type == DataType.String && r.Type == DataType.String)
- {
- m_ValueStack.Push(DynValue.NewBoolean(l.String.CompareTo(r.String) < 0));
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__lt", instructionPtr);
- if (ip < 0)
- throw new ScriptRuntimeException(null, "Can't compare on non number non string");
- else
- return ip;
- }
- return instructionPtr;
- }
- private int ExecLessEq(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop();
- DynValue l = m_ValueStack.Pop();
- if (l.Type == DataType.Number && r.Type == DataType.Number)
- {
- m_ValueStack.Push(DynValue.NewBoolean(l.Number <= r.Number));
- }
- else if (l.Type == DataType.String && r.Type == DataType.String)
- {
- m_ValueStack.Push(DynValue.NewBoolean(l.String.CompareTo(r.String) <= 0));
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__le", instructionPtr);
- if (ip < 0)
- {
- ip = Internal_InvokeBinaryMetaMethod(r, l, "__lt", instructionPtr);
- if (ip < 0)
- throw new ScriptRuntimeException(null, "Can't compare on non number non string");
- else
- return ip;
- }
- else
- return ip;
- }
- return instructionPtr;
- }
- private int ExecLen(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop();
- if (r.Type == DataType.String)
- m_ValueStack.Push(DynValue.NewNumber(r.String.Length));
- else
- {
- int ip = Internal_InvokeUnaryMetaMethod(r, "__len", instructionPtr);
- if (ip >= 0)
- return ip;
- else if (r.Type == DataType.Table)
- m_ValueStack.Push(DynValue.NewNumber(r.Table.Length));
- else
- throw new ScriptRuntimeException(null, "Arithmetic on non number");
- }
- return instructionPtr;
- }
- private int ExecConcat(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop();
- DynValue l = m_ValueStack.Pop();
- string rs = r.CastToString();
- string ls = l.CastToString();
- if (rs != null && ls != null)
- {
- m_ValueStack.Push(DynValue.NewString(ls + rs));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__concat", instructionPtr);
- if (ip >= 0) return ip;
- else throw new ScriptRuntimeException(null, "Concatenation on non strings");
- }
- }
- private void ExecTblInitI(Instruction i)
- {
- // stack: tbl - val
- DynValue val = m_ValueStack.Pop();
- DynValue tbl = m_ValueStack.Peek();
- if (tbl.Type != DataType.Table)
- throw new InternalErrorException("Unexpected type in table ctor : {0}", tbl);
- tbl.Table.InitNextArrayKeys(val);
- }
- private void ExecTblInitN(Instruction i)
- {
- // stack: tbl - key - val
- DynValue val = m_ValueStack.Pop();
- DynValue key = m_ValueStack.Pop();
- DynValue tbl = m_ValueStack.Peek();
- if (tbl.Type != DataType.Table)
- throw new InternalErrorException("Unexpected type in table ctor : {0}", tbl);
- tbl.Table[key] = val.ToScalar();
- }
- private int ExecIndexSet(Instruction i, int instructionPtr)
- {
- int nestedMetaOps = 100; // sanity check, to avoid potential infinite loop here
-
- // stack: vals.. - base - index
- DynValue idx = i.Value ?? m_ValueStack.Pop();
- DynValue obj = m_ValueStack.Pop();
- var value = GetStoreValue(i);
- DynValue h = null;
- while (nestedMetaOps > 0)
- {
- --nestedMetaOps;
- if (obj.Type == DataType.Table)
- {
- if (!obj.Table[idx].IsNil())
- {
- obj.Table[idx] = value;
- return instructionPtr;
- }
- if (obj.MetaTable != null)
- h = obj.MetaTable.RawGet("__newindex");
- if (h == null || h.IsNil())
- {
- obj.Table[idx] = value;
- return instructionPtr;
- }
- }
- else
- {
- h = obj.MetaTable.RawGet("__newindex");
- if (h == null || h.IsNil())
- throw new ScriptRuntimeException("Can't index non table: {0}", obj);
- }
- if (h.Type == DataType.Function || h.Type == DataType.ClrFunction)
- {
- m_ValueStack.Push(h);
- m_ValueStack.Push(obj);
- m_ValueStack.Push(idx);
- m_ValueStack.Push(value);
- return Internal_ExecCall(3, instructionPtr);
- }
- else
- {
- obj = h;
- h = null;
- }
- }
- throw new ScriptRuntimeException("__newindex returning too many nested tables");
- }
- private int ExecIndex(Instruction i, int instructionPtr)
- {
- int nestedMetaOps = 100; // sanity check, to avoid potential infinite loop here
- // stack: base - index
- DynValue idx = i.Value ?? m_ValueStack.Pop();
- DynValue obj = m_ValueStack.Pop();
- DynValue h = null;
- while (nestedMetaOps > 0)
- {
- --nestedMetaOps;
- if (obj.Type == DataType.Table)
- {
- var v = obj.Table[idx];
- if (!v.IsNil())
- {
- m_ValueStack.Push(v);
- return instructionPtr;
- }
- if (obj.MetaTable != null)
- h = obj.MetaTable.RawGet("__index");
- if (h == null || h.IsNil())
- {
- m_ValueStack.Push(DynValue.NewNil());
- return instructionPtr;
- }
- }
- else
- {
- if (obj.MetaTable != null)
- h = obj.MetaTable.RawGet("__index");
- if (h == null || h.IsNil())
- throw new ScriptRuntimeException("Can't index non table: {0}", obj);
- }
- if (h.Type == DataType.Function || h.Type == DataType.ClrFunction)
- {
- m_ValueStack.Push(h);
- m_ValueStack.Push(obj);
- m_ValueStack.Push(idx);
- return Internal_ExecCall(2, instructionPtr);
- }
- else
- {
- obj = h;
- h = null;
- }
- }
- throw new ScriptRuntimeException("__index returning too many nested tables");
- }
- }
- }
|