protected override LayeObject Infix__notEqualTo(LayeState state, LayeObject ths, params LayeObject[] args) { var arg = args[0]; if (!(arg is LayeString)) return TRUE; return (LayeBool)((ths as LayeString).value != (arg as LayeString).value); }
protected override LayeObject Infix__notEqualTo(LayeState state, LayeObject ths, params LayeObject[] args) { var arg = args[0]; if (ReferenceEquals(this, arg)) return FALSE; if (!(arg is LayeSymbol)) return TRUE; return (LayeBool)((ths as LayeSymbol).value != (arg as LayeSymbol).value); }
protected override LayeObject Infix__notEqualTo(LayeState state, LayeObject ths, params LayeObject[] args) { if (ReferenceEquals(ths, args[0])) return FALSE; var arg = args[0] as LayeFloat; if (arg == null) return TRUE; return (LayeBool)((ths as LayeFloat).value != arg.value); }
public override LayeObject InvokeAsMethod(LayeState state, LayeObject ths, params LayeObject[] args) { try { return callback(state, ths, args); } catch (UnhandledLayeException e) { throw e; } catch (Exception e) { state.RaiseException(e.GetType().FullName + ": " + e.Message + Environment.NewLine + e.StackTrace); return NULL; } }
public override LayeObject Infix(LayeState state, string op, LayeObject that) { if (that.IsNumeric) { lfloat thatValue = that is LayeInt ? (that as LayeInt).value : (that as LayeFloat).value; switch (op) { case "+": return new LayeFloat(value + thatValue); case "-": return new LayeFloat(value - thatValue); case "*": return new LayeFloat(value * thatValue); case "/": if (thatValue == 0) { state.RaiseException("Attempt to divide by zero."); return NULL; } return new LayeFloat(value / thatValue); case "//": if (thatValue == 0) { state.RaiseException("Attempt to divide by zero."); return NULL; } return LayeInt.ValueOf((lint)(value / thatValue)); case "%": if (thatValue == 0) { state.RaiseException("Attempt to divide by zero."); return NULL; } return new LayeFloat(value % thatValue); case "^": return new LayeFloat((lfloat)Math.Pow(value, thatValue)); case "==": return value == thatValue ? TRUE : FALSE; case "!=": return value != thatValue ? TRUE : FALSE; case "<": return value < thatValue ? TRUE : FALSE; case "<=": return value <= thatValue ? TRUE : FALSE; case ">": return value > thatValue ? TRUE : FALSE; case ">=": return value >= thatValue ? TRUE : FALSE; default: break; } } return base.Infix(state, op, that); }
private LayeObject Infix__repeat(LayeState state, LayeObject ths, params LayeObject[] args) { var arg = args[0] as LayeInt; if (arg == null) { state.RaiseException("Can only multiply a string by an integer value, got a(n) {0}.", args[0].TypeName); return NULL; } var count = arg.value; switch (count) { case 0: return EMPTY_STRING; case 1: return ths; case 2: return new LayeString((ths as LayeString).value + (ths as LayeString).value); default: var value = (ths as LayeString).value; var builder = new System.Text.StringBuilder(); for (var i = 0; i < count; i++) builder.Append(value); return new LayeString(builder.ToString()); } }
internal LayeClosure(LayeKit kit, FunctionPrototype proto, LayeTypeDef definedType = null, LayeObject[] defaults = null) : base(TYPE) { if (kit == null) throw new ArgumentNullException("kit"); this.kit = kit; this.proto = proto; outers = new OuterValue[proto.outers.Length]; this.definedType = definedType == null ? NULL : definedType; var numParams = proto.hasVargs ? proto.numParams - 1 : proto.numParams; this.defaults = new LayeObject[numParams]; if (defaults == null || defaults.Length == 0) for (int i = 0; i < numParams; i++) this.defaults[i] = NULL; else { for (uint i = 0; i < numParams - defaults.Length; i++) this.defaults[i] = NULL; for (uint i = numParams - (uint)defaults.Length, j = 0; i < numParams; i++, j++) this.defaults[i] = defaults[j]; } }
internal LayeObject[] PopCount(int count) { LayeObject[] result = new LayeObject[count]; while (--count >= 0) result[count] = Pop(); return result; }
public OuterValue(LayeObject[] stack, uint index) { values = stack; Index = index; }
internal StackFrame PushFrame(LayeClosure closure, LayeObject ths, LayeObject[] args) { FrameCount++; return Top = new StackFrame(Top, closure, ths, args); }
internal void Push(LayeObject value) { if (value == null) throw new ArgumentNullException("value"); CheckOverflow(); stack[++stackPointer] = value; }
protected override LayeObject IMethod__toString(LayeState state, LayeObject ths, params LayeObject[] args) { return new LayeString("null"); }
protected override LayeObject IPropertyGet__hashCode(LayeState state, LayeObject ths, params LayeObject[] args) { return LayeInt.ValueOf(0); }
protected virtual LayeObject Infix__Concat(LayeState state, LayeObject ths, params LayeObject[] args) { return new LayeString(ths.ToString(state) + args[0].ToString(state)); }
internal StackFrame NewFrame(LayeClosure closure, LayeObject ths, LayeObject[] args) { return new StackFrame(Top, closure, ths, args); }
private LayeObject As__Int(LayeState state, LayeObject ths, params LayeObject[] args) { return LayeInt.ValueOf((lint)(ths as LayeFloat).value); }
protected override LayeObject IMethod__toString(LayeState state, LayeObject ths, params LayeObject[] args) { return new LayeString((ths as LayeFloat).value.ToString()); }
protected override LayeObject As__Bool(LayeState state, LayeObject ths, params LayeObject[] args) { return (LayeBool)((ths as LayeFloat).value != 0); }
protected override LayeObject IPropertyGet__hashCode(LayeState state, LayeObject ths, params LayeObject[] args) { return LayeInt.ValueOf((ths as LayeFloat).value.GetHashCode()); }
protected override LayeObject Infix__notEqualTo(LayeState state, LayeObject ths, params LayeObject[] args) { return ReferenceEquals(ths, args[0]) ? FALSE : TRUE; }
internal void Set(LayeState state, LayeObject value) { LayeObject temp; if ((temp = values[Index]) is LayeReference) (temp as LayeReference).Store(state, value); else values[Index] = value; }
internal LayeClosure BuildClosure(FunctionPrototype proto, OuterValue[] openOuters, LayeTypeDef definedType, LayeObject[] defaults) { var top = stack.Top; var closure = new LayeClosure(top.closure.kit, proto, definedType, defaults); var protoOuters = proto.outers; for (var i = 0; i < protoOuters.Length; i++) if (protoOuters[i].type == OuterValueType.LOCAL) closure.outers[i] = FindOuterValue(top.Locals, protoOuters[i].location, openOuters); else closure.outers[i] = top.closure.outers[protoOuters[i].location]; return closure; }
private static OuterValue FindOuterValue(LayeObject[] locals, uint idx, OuterValue[] openOuters) { int n = openOuters.Length; for (int i = 0; i < n; i++) if (openOuters[i] != null && openOuters[i].Index == idx) return openOuters[i]; for (int i = 0; i < n; i++) if (openOuters[i] == null) return openOuters[i] = new OuterValue(locals, idx); throw new ArgumentException("no space for new outer value."); }
private void DoThisInvoke(StackFrame frame, LayeObject ths, string methodName, uint insn) { var args = frame.PopCount((int)Insn.GET_A(insn)); frame.Push(ths.MethodInvoke(this, methodName, args)); }
/// <summary> /// Raises an exception in this Laye state. /// The exception will propogate up the call stack until handled. /// If the exception propogates through all stacks, the exception is thrown /// as a <c>UnhandledLayeException</c> exception. /// /// The given exception can be any Laye object. /// /// A specific type is provided for detailed exceptions, the <c>Exception</c> type. /// It's not necessary to use this type, but it's provided for convenience. /// </summary> /// <param name="obj"></param> public void RaiseException(LayeObject obj) { if (exceptionHandlers.Count == 0) throw new UnhandledLayeException(GetStackTrace(), obj.ToString(this)); else { lastException = obj; var handler = exceptionHandlers.Pop(); stack.Top.activeExceptionHandlers--; stack.Unwind(stack.FrameCount - handler.frameIndex); stack.Top.ip = handler.catchIP - 1; } }
protected override LayeObject As__Bool(LayeState state, LayeObject ths, params LayeObject[] args) { return FALSE; }
internal LayeObject Execute(StackFrame frame, LayeClosure closure, LayeObject ths = null, params LayeObject[] args) { if (frame == null) frame = stack.PushFrame(closure, ths, args); else stack.PushFrame(frame); reentry: var kit = closure.kit; var outers = closure.outers; var nested = closure.proto.nested; var strings = closure.proto.strings; var numericConsts = closure.proto.numericConsts; var code = closure.proto.code; var codeLen = (uint)code.Length; var paramc = closure.proto.numParams; var argc = args.Length; var vargs = closure.proto.hasVargs; var openOuters = frame.openOuters; uint insn; OpCode op; for (; frame.ip < codeLen && !frame.Aborted && !frame.yielded; frame.ip++) { op = (OpCode)((insn = code[frame.ip]) & Insn.MAX_OP); #if DEBUG_STACK Console.WriteLine(frame.ip + " " + op); frame.PrintLocals(this); frame.PrintStack(this); #endif switch (op) { default: RaiseException(string.Format("Unhandled op code {0}.", op)); return NULL; case OpCode.NOP: continue; case OpCode.POP: frame.Pop(); continue; case OpCode.DUP: frame.Dup(); continue; case OpCode.CLOSE: CloseOuters(openOuters, Insn.GET_C(insn)); continue; // These all do n - 1 because frame.ip++ happens anyway. I hate it, but oh well. case OpCode.JUMP: frame.ip = Insn.GET_C(insn) - 1; continue; case OpCode.JUMPEQ: if (frame.SwapPop().Equals(frame.Pop())) frame.ip = Insn.GET_C(insn) - 1; continue; case OpCode.JUMPNEQ: if (!frame.SwapPop().Equals(frame.Pop())) frame.ip = Insn.GET_C(insn) - 1; continue; case OpCode.JUMPT: if (frame.Pop().ToBool(this)) frame.ip = Insn.GET_C(insn) - 1; continue; case OpCode.JUMPF: if (!frame.Pop().ToBool(this)) frame.ip = Insn.GET_C(insn) - 1; continue; case OpCode.LLOAD: frame.Push(frame[Insn.GET_C(insn)]); continue; case OpCode.LSTORE: frame[Insn.GET_C(insn)] = frame.Top; continue; case OpCode.OLOAD: frame.Push(outers[Insn.GET_C(insn)].Value); continue; case OpCode.OSTORE: outers[Insn.GET_C(insn)].Set(this, frame.Top); continue; case OpCode.KLOAD: frame.Push(kit[this, strings[Insn.GET_C(insn)]]); continue; case OpCode.KSTORE: kit[this, strings[Insn.GET_C(insn)]] = frame.Top; continue; case OpCode.GLOAD: frame.Push(kit.GetGlobal(this, strings[Insn.GET_C(insn)])); continue; case OpCode.GSTORE: kit.SetGlobal(this, strings[Insn.GET_C(insn)], frame.Top); continue; case OpCode.ILOAD: DoILoad(frame, insn); continue; case OpCode.ISTORE: DoIStore(frame, insn); continue; case OpCode.OILOAD: frame.Push(frame.Pop().OperatorIndexGet(this, strings[Insn.GET_C(insn)])); continue; case OpCode.OISTORE: frame.SwapPop().OperatorIndexSet(this, strings[Insn.GET_C(insn)], frame.Top); continue; case OpCode.FLOAD: frame.Push(frame.Pop()[this, strings[Insn.GET_C(insn)]]); continue; case OpCode.FSTORE: frame.SwapPop()[this, strings[Insn.GET_C(insn)]] = frame.Top; continue; case OpCode.LOAD: DoLoad(frame, kit, strings[Insn.GET_C(insn)]); continue; case OpCode.STORE: DoStore(frame, kit, strings[Insn.GET_C(insn)]); continue; case OpCode.NULL: frame.Push(NULL); continue; case OpCode.TRUE: frame.Push(TRUE); continue; case OpCode.FALSE: frame.Push(FALSE); continue; case OpCode.ENDL: frame.Push(ENDL); continue; case OpCode.NCONST: frame.Push(numericConsts[Insn.GET_C(insn)]); continue; case OpCode.SCONST: frame.Push(Insn.GET_B(insn) == 0 ? new LayeString(strings[Insn.GET_A(insn)]) as LayeObject : LayeSymbol.getUnsafe(strings[Insn.GET_A(insn)])); continue; case OpCode.ICONSTM1: frame.Push(ICONSTM1); continue; case OpCode.ICONST0: frame.Push(ICONST0); continue; case OpCode.ICONST1: frame.Push(ICONST1); continue; case OpCode.ICONST2: frame.Push(ICONST2); continue; case OpCode.ICONST3: frame.Push(ICONST3); continue; case OpCode.ICONST4: frame.Push(ICONST4); continue; case OpCode.ICONST5: frame.Push(ICONST5); continue; case OpCode.FCONSTM1: frame.Push(FCONSTM1); continue; case OpCode.FCONST0: frame.Push(FCONST0); continue; case OpCode.FCONST1: frame.Push(FCONST1); continue; case OpCode.FCONST2: frame.Push(FCONST2); continue; case OpCode.LIST: frame.Push(new LayeList(frame.PopCount((int)Insn.GET_C(insn)))); continue; case OpCode.TUPLE: frame.Push(new LayeTuple(frame.PopCount((int)Insn.GET_C(insn)))); continue; case OpCode.CLOSURE: frame.Push(BuildClosure(nested[Insn.GET_A(insn)], openOuters, null, frame.PopCount((int)Insn.GET_B(insn)))); continue; case OpCode.GENERATOR: frame.Push(new LayeClosureGeneratorSpawner(frame.Pop() as LayeClosure)); continue; case OpCode.INVOKE: DoInvoke(frame, insn); continue; case OpCode.MINVOKE: DoMethodInvoke(frame, strings[Insn.GET_B(insn)], insn); continue; case OpCode.TINVOKE: DoThisInvoke(frame, ths, strings[Insn.GET_B(insn)], insn); continue; case OpCode.TAILINVOKE: var saveArgs = frame.PopCount((int)Insn.GET_C(insn)); EndCall(frame, openOuters); frame.Reset(); frame.SetArgs(saveArgs); goto reentry; case OpCode.YIELD: frame.yielded = true; continue; case OpCode.RES: DoRes(frame); continue; case OpCode.KIT: frame.Push(kit); continue; case OpCode.THIS: frame.Push(ths); continue; case OpCode.SELF: frame.Push(closure); continue; case OpCode.STATIC: frame.Push(closure.definedType); continue; case OpCode.PREFIX: frame.Push(frame.Pop().Prefix(this, strings[Insn.GET_C(insn)])); continue; case OpCode.INFIX: frame.Push(frame.SwapPop().Infix(this, strings[Insn.GET_C(insn)], frame.Pop())); continue; case OpCode.AS: frame.Push(frame.SwapPop().As(this, frame.Pop())); continue; case OpCode.NOT: frame.Push(frame.Pop().ToBool(this) ? FALSE : TRUE); continue; case OpCode.AND: if (frame.Top.ToBool(this)) frame.Pop(); else frame.ip = Insn.GET_C(insn) - 1; continue; case OpCode.OR: if (frame.Top.ToBool(this)) frame.ip = Insn.GET_C(insn) - 1; else frame.Pop(); continue; case OpCode.XOR: frame.Push((frame.Pop().ToBool(this) != frame.Pop().ToBool(this)) ? TRUE : FALSE); continue; case OpCode.COMPIS: frame.Push((LayeBool)ReferenceEquals(frame.Pop(), frame.Pop())); continue; case OpCode.COMPNOTIS: frame.Push((LayeBool)!ReferenceEquals(frame.Pop(), frame.Pop())); continue; case OpCode.COMPTYPEOF: frame.Push((LayeBool)frame.SwapPop().TypeOf(this, frame.Pop())); continue; case OpCode.COMPNOTTYPEOF: frame.Push((LayeBool)!frame.SwapPop().TypeOf(this, frame.Pop())); continue; case OpCode.TYPEOF: frame.Push(frame.Pop().TypeDef); continue; case OpCode.THROW: RaiseException(frame.Pop()); continue; case OpCode.STOREEX: frame[Insn.GET_C(insn)] = lastException; continue; case OpCode.BEGINEXH: var c = Insn.GET_C(insn); while (frame.stackPointer >= c) frame.Pop(); continue; case OpCode.PUSHEXH: frame.activeExceptionHandlers++; exceptionHandlers.Push(new ExceptionHandler(stack.FrameCount, Insn.GET_C(insn))); continue; case OpCode.POPEXH: frame.activeExceptionHandlers--; exceptionHandlers.Pop(); continue; case OpCode.ITERPREP: DoIterPrep(frame, Insn.GET_A(insn), Insn.GET_B(insn) != 0); continue; case OpCode.ITERLOOP: DoIterLoop(frame, Insn.GET_A(insn), Insn.GET_B(insn)); continue; case OpCode.EACHPREP: DoEachPrep(frame, Insn.GET_A(insn)); continue; case OpCode.EACHLOOP: DoEachLoop(frame, Insn.GET_A(insn), Insn.GET_B(insn)); continue; case OpCode.IEACHPREP: DoIEachPrep(frame, Insn.GET_A(insn)); continue; case OpCode.IEACHLOOP: DoIEachLoop(frame, Insn.GET_A(insn), Insn.GET_B(insn)); continue; } // end switch } // end for EndCall(frame, openOuters); #if DEBUG_STACK frame.PrintStack(this); #endif if (frame.Aborted) return NULL; stack.PopFrame(); return frame.HasValue() ? frame.Top : NULL; }
internal StackFrame(StackFrame previous, LayeClosure closure, LayeObject ths, LayeObject[] args) { this.previous = previous; this.closure = closure; this.ths = ths; locals = new LayeObject[closure.proto.maxLocalCount]; stack = new LayeObject[closure.proto.maxStackCount]; openOuters = closure.proto.nested.Length != 0 ? new OuterValue[closure.proto.maxStackCount] : null; SetArgs(args); }
internal void SetArgs(LayeObject[] args) { var paramc = closure.proto.numParams; var argc = args.Length; var vargs = closure.proto.hasVargs; for (int argi = 0; argi < paramc; argi++) { int index = argi; LayeObject arg; if (argi < argc) if (argi == paramc - 1 && vargs) { var vargsArray = new LayeObject[argc - argi]; Array.Copy(args, argi, vargsArray, 0, argc - argi); arg = new LayeList(vargsArray); argi = argc; } else arg = args[argi]; else arg = closure.defaults[argi]; this[(uint)index] = arg; } }
internal void SetGlobal(LayeState state, string key, LayeObject value) { globals[key] = value; }