/// <summary> /// Take the topmost arguments down to the ARG_MARKER_STRING, pop them off, and then /// put them back again in reversed order so a function can read them in normal order. /// Note that if this is an indirect call, it will also consume the thing just under /// the ARG_MARKER, since that's expected to be the delegate or KOSDelegate that we already /// read and pulled the needed information from. /// <param name="cpu">the cpu we are running on, fur stack manipulation purposes</param> /// <param name="direct">need to know if this was a direct or indirect call. If indirect, /// then that means it also needs to consume the indirect reference off the stack just under /// the args</param> /// </summary> public static void ReverseStackArgs(ICpu cpu, bool direct) { List <object> args = new List <object>(); object arg = cpu.PopValue(); while (cpu.GetStackSize() > 0 && arg.GetType() != ArgMarkerType) { args.Add(arg); // It's important to dereference with PopValue, not using PopStack, because the function // being called might not even be able to see the variable in scope anyway. // In other words, if calling a function like so: // declare foo to 3. // myfunc(foo). // The code inside myfunc needs to see that as being identical to just saying: // myfunc(3). // It has to be unaware of the fact that the name of the argument was 'foo'. It just needs to // see the contents that were inside foo. arg = cpu.PopValue(); } if (!direct) { cpu.PopStack(); // throw away the delegate or KOSDelegate info - we already snarfed it by now. } // Push the arg marker back on again. cpu.PushStack(new KOSArgMarkerType()); // Push the arguments back on again, which will invert their order: foreach (object item in args) { cpu.PushStack(item); } }
/// <summary> /// Take the topmost arguments down to the ARG_MARKER_STRING, pop them off, and then /// put them back again in reversed order so a function can read them in normal order. /// Note that if this is an indirect call, it will also consume the thing just under /// the ARG_MARKER, since that's expected to be the delegate or KOSDelegate that we already /// read and pulled the needed information from. /// <param name="cpu">the cpu we are running on, fur stack manipulation purposes</param> /// <param name="direct">need to know if this was a direct or indirect call. If indirect, /// then that means it also needs to consume the indirect reference off the stack just under /// the args</param> /// </summary> public static void ReverseStackArgs(ICpu cpu, bool direct) { List<object> args = new List<object>(); object arg = cpu.PopValue(); while (cpu.GetStackSize() > 0 && arg.GetType() != ArgMarkerType) { args.Add(arg); // It's important to dereference with PopValue, not using PopStack, because the function // being called might not even be able to see the variable in scope anyway. // In other words, if calling a function like so: // declare foo to 3. // myfunc(foo). // The code inside myfunc needs to see that as being identical to just saying: // myfunc(3). // It has to be unaware of the fact that the name of the argument was 'foo'. It just needs to // see the contents that were inside foo. arg = cpu.PopValue(); } if (! direct) cpu.PopStack(); // throw away the delegate or KOSDelegate info - we already snarfed it by now. // Push the arg marker back on again. cpu.PushStack(new KOSArgMarkerType()); // Push the arguments back on again, which will invert their order: foreach (object item in args) cpu.PushStack(item); }
public void CanGetDelegateValue() { var obj = new MockStructure(); var suffix = new NoArgsSuffix <Encapsulation.Structure>(() => obj); var del = suffix.Get(); Assert.IsNotNull(del); cpu.PushStack(null); // dummy variable for ReverseStackArgs to pop cpu.PushStack(new KOSArgMarkerType()); del.Invoke(cpu); var value = del.Value; Assert.IsNotNull(value); Assert.AreSame(obj, value); }
public void CanGetListIndex() { var list = new ListValue(); list.Add(new StringValue("bar")); cpu.PushStack(list); const int INDEX = 0; cpu.PushStack(INDEX); var opcode = new OpcodeGetIndex(); opcode.Execute(cpu); Assert.AreEqual(1, list.Count()); Assert.AreEqual(new StringValue("bar"), cpu.PopStack()); }
public override void Execute(ICpu cpu) { object value = cpu.PopValue(); object result; if (value is bool) result = !((bool)value); else if (value is int) result = Convert.ToBoolean(value) ? 0 : 1; else if ((value is double) || (value is float)) result = Convert.ToBoolean(value) ? 0.0 : 1.0; else throw new KOSUnaryOperandTypeException("boolean-not", value); cpu.PushStack(result); }
public override void Execute(ICpu cpu) { bool result = false; //pessimistic default // Convert to string instead of cast in case the identifier is stored // as an encapsulated StringValue, preventing an unboxing collision. string ident = Convert.ToString(cpu.PopStack()); if (ident != null && cpu.IdentifierExistsInScope(ident)) { result = true; } cpu.PushStack(result); }
public override void Execute(ICpu cpu) { // Return value should be atop the stack. // Pop it, eval it, and push it back, // i.e. if the statement was RETURN X, and X is 2, then you want // it to return the number 2, not the variable name $x, which could // be a variable local to this function which is about to go out of scope // so the caller can't access it: object returnVal = cpu.PopValue(); // Now dig down through the stack until the argbottom is found. // anything still leftover above that should be unread parameters we // should throw away: object shouldBeArgMarker = 0; // just a temp to force the loop to execute at least once. while (shouldBeArgMarker == null || (shouldBeArgMarker.GetType() != OpcodeCall.ArgMarkerType)) { if (cpu.GetStackSize() <= 0) { throw new KOSArgumentMismatchException( string.Format("Something is wrong with the stack - no arg bottom mark when doing a return. This is an internal problem with kOS") ); } shouldBeArgMarker = cpu.PopStack(); } cpu.PushStack(Structure.FromPrimitive(returnVal)); // Now, after the eval was done, NOW finally pop the scope, after we don't need local vars anymore: if( Depth > 0 ) OpcodePopScope.DoPopScope(cpu, Depth); // The only thing on the "above stack" now that is allowed to get in the way of // finding the context record that tells us where to jump back to, are the potential // closure scope frames that might have been pushed if this subroutine was // called via a delegate reference. Consume any of those that are in // the way, then expect the context record. Any other pattern encountered // is proof the stack alignment got screwed up: bool okay; VariableScope peeked = cpu.PeekRaw(-1, out okay) as VariableScope; while (okay && peeked != null && peeked.IsClosure) { cpu.PopAboveStack(1); peeked = cpu.PeekRaw(-1, out okay) as VariableScope; } object shouldBeContextRecord = cpu.PopAboveStack(1); if ( !(shouldBeContextRecord is SubroutineContext) ) { // This should never happen with any user code: throw new Exception( "kOS internal error: Stack misalignment detected when returning from routine."); } var contextRecord = shouldBeContextRecord as SubroutineContext; // Special case for when the subroutine was really being called as an interrupt // trigger from the kOS CPU itself. In that case we don't want to leave the // return value atop the stack, and instead want to pop it and use it to decide // whether or not the re-insert the trigger for next time: if (contextRecord.IsTrigger) { cpu.PopStack(); // already got the return value up above, just ignore it. if (returnVal is bool || returnVal is BooleanValue ) if (Convert.ToBoolean(returnVal)) cpu.AddTrigger(contextRecord.TriggerPointer); } int destinationPointer = contextRecord.CameFromInstPtr; int currentPointer = cpu.InstructionPointer; DeltaInstructionPointer = destinationPointer - currentPointer; }
public override void Execute(ICpu cpu) { bool worked; object shouldBeArgMarker = cpu.PeekRaw(0,out worked); if ( !worked || (shouldBeArgMarker == null) || (shouldBeArgMarker.GetType() != OpcodeCall.ArgMarkerType) ) { cpu.PushStack(false); // these are internally used, so no Strucutre.FromPrimitive wrapper call. } else { cpu.PushStack(true); // these are internally used, so no Strucutre.FromPrimitive wrapper call. } }
public override void Execute(ICpu cpu) { // This may look like it's just pointlessly converting from a // ScalarBoolean to a primitive boolean and then back into a // ScalarBoolean, and in the case where the operand was already // a ScalarBoolean that would be true. But the purpose of this opcode // is to also change integers and floats into booleans. Thus the call to // Convert.ToBoolean(): object value = cpu.PopValue(); bool result = Convert.ToBoolean(value); cpu.PushStack(Structure.FromPrimitive(result)); }
public override void Execute(ICpu cpu) { cpu.PushStack(Argument); }
public override void Execute(ICpu cpu) { string suffixName = cpu.PopStack().ToString().ToUpper(); object popValue = cpu.PopValue(); var specialValue = popValue as ISuffixed; if (specialValue == null) { var s = popValue as string; if (s != null) { specialValue = new StringValue(s); } else { throw new Exception(string.Format("Values of type {0} cannot have suffixes", popValue.GetType())); } } object value = specialValue.GetSuffix(suffixName); if (value is Delegate && !IsMethodCallAttempt) { // This is what happens when someone tries to call a suffix method as if // it wasn't a method (i.e. leaving the parentheses off the call). The // member returned is a delegate that needs to be called to get its actual // value. Borrowing the same routine that OpcodeCall uses for its method calls: cpu.PushStack(new KOSArgMarkerType()); value = OpcodeCall.ExecuteDelegate(cpu, (Delegate)value); } cpu.PushStack(value); }
public override void Execute(ICpu cpu) { object value = cpu.PopValue(); object result; // Convert to bool instead of cast in case the identifier is stored // as an encapsulated BooleanValue, preventing an unboxing collision. // Wrapped in a try/catch since the Convert framework doesn't have a // way to determine if a type can be converted. try { result = !Convert.ToBoolean(value); } catch { throw new KOSCastException(value.GetType(), typeof(BooleanValue)); } cpu.PushStack(Structure.FromPrimitive(result)); }
public override void Execute(ICpu cpu) { Argument2 = cpu.PopValue(); Argument1 = cpu.PopValue(); // convert floats to doubles if (Argument1 is float) Argument1 = Convert.ToDouble(Argument1); if (Argument2 is float) Argument2 = Convert.ToDouble(Argument2); Calculator calc = Calculator.GetCalculator(Argument1, Argument2); object result = ExecuteCalculation(calc); cpu.PushStack(result); }
public override void Execute(ICpu cpu) { bool result = false; //pessimistic default string ident = cpu.PopStack() as string; if (ident != null && cpu.IdentifierExistsInScope(ident)) { result = true; } cpu.PushStack(result); }
public override void Execute(ICpu cpu) { cpu.PushStack(cpu.PopValue()); }
public override void Execute(ICpu cpu) { object functionPointer; object delegateReturn = null; if (Direct) { functionPointer = cpu.GetValue(Destination); if (functionPointer == null) throw new KOSException("Attempt to call function failed - Value of function pointer for " + Destination + " is null."); } else // for indirect calls, dig down to find what's underneath the argument list in the stack and use that: { bool foundBottom = false; int digDepth; int argsCount = 0; for (digDepth = 0; (! foundBottom) && digDepth < cpu.GetStackSize() ; ++digDepth) { object arg = cpu.PeekValue(digDepth); if (arg != null && arg.GetType() == ArgMarkerType) foundBottom = true; else ++argsCount; } functionPointer = cpu.PeekValue(digDepth); if (! ( functionPointer is Delegate)) { // Indirect calls are meant to be delegates. If they are not, then that means the // function parentheses were put on by the user when they weren't required. Just dig // through the stack to the result of the getMember and skip the rest of the execute logic // If args were passed to a non-method, then clean them off the stack, and complain: if (argsCount>0) { for (int i=1 ; i<=argsCount; ++i) cpu.PopValue(); throw new KOSArgumentMismatchException( 0, argsCount, "\n(In fact in this case the parentheses are entirely optional)"); } cpu.PopValue(); // pop the ArgMarkerString too. return; } } // If it's a string it might not really be a built-in, it might still be a user func. // Detect whether it's built-in, and if it's not, then convert it into the equivalent // user func call by making it be an integer instruction pointer instead: if (functionPointer is string) { string functionName = functionPointer as string; if (functionName.EndsWith("()")) functionName = functionName.Substring(0, functionName.Length - 2); if (!(cpu.BuiltInExists(functionName))) { // It is not a built-in, so instead get its value as a user function pointer variable, despite // the fact that it's being called AS IF it was direct. if (!functionName.EndsWith("*")) functionName = functionName + "*"; if (!functionName.StartsWith("$")) functionName = "$" + functionName; functionPointer = cpu.GetValue(functionName); } } IUserDelegate userDelegate = functionPointer as IUserDelegate; if (userDelegate != null) functionPointer = userDelegate.EntryPoint; if (functionPointer is int) { ReverseStackArgs(cpu); int currentPointer = cpu.InstructionPointer; DeltaInstructionPointer = (int)functionPointer - currentPointer; var contextRecord = new SubroutineContext(currentPointer+1); cpu.PushAboveStack(contextRecord); if (userDelegate != null) { cpu.AssertValidDelegateCall(userDelegate); // Reverse-push the closure's scope record, just after the function return context got put on the stack. for (int i = userDelegate.Closure.Count - 1 ; i >= 0 ; --i) cpu.PushAboveStack(userDelegate.Closure[i]); } } else if (functionPointer is string) { // Built-ins don't need to dereference the stack values because they // don't leave the scope - they're not implemented that way. But later we // might want to change that. var name = functionPointer as string; string functionName = name; if (functionName.EndsWith("()")) functionName = functionName.Substring(0, functionName.Length - 2); cpu.CallBuiltinFunction(functionName); } else if (functionPointer is Delegate) { delegateReturn = ExecuteDelegate(cpu, (Delegate)functionPointer); } else { // This is one of those "the user had better NEVER see this error" sorts of messages that's here to keep us in check: throw new Exception( string.Format("kOS internal error: OpcodeCall calling a function described using {0} which is of type {1} and kOS doesn't know how to call that.", functionPointer, functionPointer.GetType().Name) ); } if (! Direct) { cpu.PopValue(); // consume function name, branch index, or delegate } if (functionPointer is Delegate) { cpu.PushStack(delegateReturn); // And now leave the return value on the stack to be read. } }
public override void Execute(ICpu cpu) { bool argument2 = Convert.ToBoolean(cpu.PopValue()); bool argument1 = Convert.ToBoolean(cpu.PopValue()); object result = argument1 | argument2; cpu.PushStack(result); }
public override void Execute(ICpu cpu) { Structure index = cpu.PopStructureEncapsulated(); Structure collection = cpu.PopStructureEncapsulated(); Structure result; var indexable = collection as IIndexable; if (indexable != null) { result = indexable.GetIndex(index); } else { throw new Exception(string.Format("Can't iterate on an object of type {0}", collection.GetType())); } cpu.PushStack(result); }
public override void Execute(ICpu cpu) { object index = cpu.PopValue(); object list = cpu.PopValue(); object value; var indexable = list as IIndexable; if (indexable != null) { value = indexable.GetIndex(index); } // Box strings if necessary to allow them to be indexed else if (list is string) { value = new StringValue((string) list).GetIndex(index); } else { throw new Exception(string.Format("Can't iterate on an object of type {0}", list.GetType())); } if (!(list is IIndexable)) throw new Exception(string.Format("Can't iterate on an object of type {0}", list.GetType())); cpu.PushStack(value); }
public override void Execute(ICpu cpu) { string suffixName = cpu.PopStack().ToString().ToUpper(); object popValue = cpu.PopValueEncapsulated(); var specialValue = popValue as ISuffixed; if (specialValue == null) { throw new Exception(string.Format("Values of type {0} cannot have suffixes", popValue.GetType())); } ISuffixResult result = specialValue.GetSuffix(suffixName); // If the result is a suffix that is still in need of being invoked and hasn't resolved to a value yet: if (result != null && !IsMethodCallAttempt && !result.HasValue) { // This is what happens when someone tries to call a suffix method as if // it wasn't a method (i.e. leaving the parentheses off the call). The // member returned is a delegate that needs to be called to get its actual // value. Borrowing the same routine that OpcodeCall uses for its method calls: cpu.PushStack(result); cpu.PushStack(new KOSArgMarkerType()); OpcodeCall.StaticExecute(cpu, false, "", false); // this will push the return value on the stack for us. } else { if (result.HasValue) { // Push the already calculated value. cpu.PushStack(result.Value); } else { // Push the indirect suffix delegate, but don't execute it yet // because we need to put the upcoming arg list above it on the stack. // Eventually an <indirect> OpcodeCall will occur further down the program which // will actually execute this. cpu.PushStack(result); } } }
public override void Execute(ICpu cpu) { object value = cpu.PopValue(); object result; if (value is int) result = -((int)value); else if (value is float) result = -(Convert.ToDouble(value)); else if (value is double) result = -((double)value); else { // Generic last-ditch to catch any sort of object that has // overloaded the unary negate operator '-'. // (For example, kOS.Suffixed.Vector and kOS.Suffixed.Direction) Type t = value.GetType(); MethodInfo negateMe = t.GetMethod("op_UnaryNegation", BindingFlags.Static | BindingFlags.Public); // C#'s alternate name for '-' operator if (negateMe != null) result = negateMe.Invoke(null, new[]{value}); // value is an arg, not the 'this'. (Method is static.) else throw new KOSUnaryOperandTypeException("negate", value); } cpu.PushStack(result); }
public override void Execute(ICpu cpu) { bool argument2 = Convert.ToBoolean(cpu.PopValue()); bool argument1 = Convert.ToBoolean(cpu.PopValue()); object result = argument1 || argument2; cpu.PushStack(Structure.FromPrimitive(result)); }
public void CanSetListIndex() { var list = new ListValue(); list.Add(new StringValue("bar")); cpu.PushStack(list); const int INDEX = 0; cpu.PushStack(INDEX); const string VALUE = "foo"; cpu.PushStack(VALUE); var opcode = new OpcodeSetIndex(); opcode.Execute(cpu); Assert.AreEqual(1, list.Count()); Assert.AreNotEqual(new StringValue("bar"), list[0]); Assert.AreEqual(new StringValue("foo"), list[0]); }
public override void Execute(ICpu cpu) { Structure value = cpu.PopStructureEncapsulated(); var scalarValue = value as ScalarValue; if (scalarValue != null && scalarValue.IsValid) { cpu.PushStack(-scalarValue); return; } // Generic last-ditch to catch any sort of object that has // overloaded the unary negate operator '-'. // (For example, kOS.Suffixed.Vector and kOS.Suffixed.Direction) Type t = value.GetType(); MethodInfo negateMe = t.GetMethod("op_UnaryNegation", BindingFlags.FlattenHierarchy |BindingFlags.Static | BindingFlags.Public); if (negateMe != null) { object result = negateMe.Invoke(null, new[]{value}); cpu.PushStack(result); } else throw new KOSUnaryOperandTypeException("negate", value); }
public override void Execute(ICpu cpu) { // Return value should be atop the stack - we have to pop it so that // we can reach the arg start marker under it: object returnVal = cpu.PopValue(); // The next thing on the stack under the return value should be the marker that indicated where // the parameters started. It should be thrown away now. If the next thing is NOT the marker // of where the parameters started, that is proof the stack is misaligned, probably because the // number of args passed didn't match the number of DECLARE PARAMETER statements in the function: string shouldBeArgMarker = cpu.PopStack() as string; if ( (shouldBeArgMarker == null) || (!(shouldBeArgMarker.Equals(OpcodeCall.ARG_MARKER_STRING))) ) { throw new KOSArgumentMismatchException( string.Format("(detected when returning from function and the stack still had {0} on it)", (shouldBeArgMarker ?? "a non-string value")) ); } // If the proper argument marker was found, then it's all okay, so put the return value // back, where it belongs, now that the arg start marker was popped off: cpu.PushStack(returnVal); // Now, after the eval was done, NOW finally pop the scope, after we don't need local vars anymore: if( Depth > 0 ) OpcodePopScope.DoPopScope(cpu, Depth); // The only thing on the "above stack" now that is allowed to get in the way of // finding the context record that tells us where to jump back to, are the potential // closure scope frames that might have been pushed if this subroutine was // called via a delegate reference. Consume any of those that are in // the way, then expect the context record. Any other pattern encountered // is proof the stack alignment got screwed up: bool okay; VariableScope peeked = cpu.PeekRaw(-1, out okay) as VariableScope; while (okay && peeked != null && peeked.IsClosure) { cpu.PopAboveStack(1); peeked = cpu.PeekRaw(-1, out okay) as VariableScope; } object shouldBeContextRecord = cpu.PopAboveStack(1); if ( !(shouldBeContextRecord is SubroutineContext) ) { // This should never happen with any user code: throw new Exception( "kOS internal error: Stack misalignment detected when returning from routine."); } var contextRecord = shouldBeContextRecord as SubroutineContext; int destinationPointer = contextRecord.CameFromInstPtr; int currentPointer = cpu.InstructionPointer; DeltaInstructionPointer = destinationPointer - currentPointer; }
public override void Execute(ICpu cpu) { IUserDelegate pushMe = cpu.MakeUserDelegate(EntryPoint, WithClosure); cpu.PushStack(pushMe); }
public override void Execute(ICpu cpu) { object index = cpu.PopValue(); if (index is double || index is float) { index = Convert.ToInt32(index); // allow expressions like (1.0) to be indexes } object list = cpu.PopValue(); if (!(list is IIndexable)) throw new Exception(string.Format("Can't iterate on an object of type {0}", list.GetType())); if (!(index is int)) throw new Exception("The index must be an integer number"); object value = ((IIndexable)list).GetIndex((int)index); cpu.PushStack(value); }
public override void Execute(ICpu cpu) { object value1 = cpu.PopStack(); object value2 = cpu.PopStack(); cpu.PushStack(value1); cpu.PushStack(value2); }
public override void Execute(ICpu cpu) { cpu.PushStack(cpu.PopValueEncapsulated()); }
/// <summary> /// Performs the actual execution of a subroutine call, either from this opcode or externally from elsewhere. /// All "call a routine" logic should shunt through this code here, which handles all the complex cases, /// or at least it should. /// Note that in the case of a user function, this does not *ACTUALLY* execute the function yet. It just /// arranges the stack correctly for the call and returns the new location that the IP should be jumped to /// on the next instruction to begin the subroutine. For all built-in cases, it actually executes the /// call right now and doesn't return until it's done. But for User functions it can't do that - it can only /// advise on where to jump on the next instruction to begin the function. /// </summary> /// <param name="cpu">the cpu its running on</param> /// <param name="direct">same meaning as OpcodeCall.Direct</param> /// <param name="destination">if direct, then this is the function name</param> /// <param name="calledFromKOSDelegateCall">true if KOSDelegate.Call() brought us here. If true that /// means any pre-bound args are already on the stack. If false it means they aren't and this will have to /// put them there.</param> /// <returns>new IP to jump to, if this should be followed up by a jump. If -1 then it means don't jump.</returns> public static int StaticExecute(ICpu cpu, bool direct, object destination, bool calledFromKOSDelegateCall) { object functionPointer; object delegateReturn = null; int newIP = -1; // new instruction pointer to jump to, next, if any. if (direct) { functionPointer = cpu.GetValue(destination); if (functionPointer == null) throw new KOSException("Attempt to call function failed - Value of function pointer for " + destination + " is null."); } else // for indirect calls, dig down to find what's underneath the argument list in the stack and use that: { bool foundBottom = false; int digDepth; int argsCount = 0; for (digDepth = 0; (! foundBottom) && digDepth < cpu.GetStackSize() ; ++digDepth) { object arg = cpu.PeekValue(digDepth); if (arg != null && arg.GetType() == ArgMarkerType) foundBottom = true; else ++argsCount; } functionPointer = cpu.PeekValue(digDepth); if (! ( functionPointer is Delegate || functionPointer is KOSDelegate || functionPointer is ISuffixResult)) { // Indirect calls are meant to be delegates. If they are not, then that means the // function parentheses were put on by the user when they weren't required. Just dig // through the stack to the result of the getMember and skip the rest of the execute logic // If args were passed to a non-method, then clean them off the stack, and complain: if (argsCount>0) { for (int i=1 ; i<=argsCount; ++i) cpu.PopValue(); throw new KOSArgumentMismatchException( 0, argsCount, "\n(In fact in this case the parentheses are entirely optional)"); } cpu.PopValue(); // pop the ArgMarkerString too. return -1; } } // If it's a string it might not really be a built-in, it might still be a user func. // Detect whether it's built-in, and if it's not, then convert it into the equivalent // user func call by making it be an integer instruction pointer instead: if (functionPointer is string || functionPointer is StringValue) { string functionName = functionPointer.ToString(); if (functionName.EndsWith("()")) functionName = functionName.Substring(0, functionName.Length - 2); if (!(cpu.BuiltInExists(functionName))) { // It is not a built-in, so instead get its value as a user function pointer variable, despite // the fact that it's being called AS IF it was direct. if (!functionName.EndsWith("*")) functionName = functionName + "*"; if (!functionName.StartsWith("$")) functionName = "$" + functionName; functionPointer = cpu.GetValue(functionName); } } KOSDelegate kosDelegate = functionPointer as KOSDelegate; if (kosDelegate != null) { if (! calledFromKOSDelegateCall) kosDelegate.InsertPreBoundArgs(); } IUserDelegate userDelegate = functionPointer as IUserDelegate; if (userDelegate != null) functionPointer = userDelegate.EntryPoint; BuiltinDelegate builtinDel = functionPointer as BuiltinDelegate; if (builtinDel != null && (! calledFromKOSDelegateCall) ) functionPointer = builtinDel.Name; // If the IP for a jump location got encapsulated as a user int when it got stored // into the internal variable, then get the primitive int back out of it again: ScalarIntValue userInt = functionPointer as ScalarIntValue; if (userInt != null) functionPointer = userInt.GetIntValue(); // Convert to int instead of cast in case the identifier is stored // as an encapsulated ScalarValue, preventing an unboxing collision. if (functionPointer is int || functionPointer is ScalarValue) { CpuUtility.ReverseStackArgs(cpu, direct); var contextRecord = new SubroutineContext(cpu.InstructionPointer+1); newIP = Convert.ToInt32(functionPointer); cpu.PushAboveStack(contextRecord); if (userDelegate != null) { cpu.AssertValidDelegateCall(userDelegate); // Reverse-push the closure's scope record, just after the function return context got put on the stack. for (int i = userDelegate.Closure.Count - 1 ; i >= 0 ; --i) cpu.PushAboveStack(userDelegate.Closure[i]); } } else if (functionPointer is string) { // Built-ins don't need to dereference the stack values because they // don't leave the scope - they're not implemented that way. But later we // might want to change that. var name = functionPointer as string; string functionName = name; if (functionName.EndsWith("()")) functionName = functionName.Substring(0, functionName.Length - 2); cpu.CallBuiltinFunction(functionName); // If this was indirect, we need to consume the thing under the return value. // as that was the indirect BuiltInDelegate: if ((! direct) && builtinDel != null) { object topThing = cpu.PopStack(); cpu.PopStack(); // remove BuiltInDelegate object. cpu.PushStack(topThing); // put return value back. } } else if (functionPointer is ISuffixResult) { var result = (ISuffixResult) functionPointer; if (!result.HasValue) { result.Invoke(cpu); } delegateReturn = result.Value; } // TODO:erendrake This else if is likely never used anymore else if (functionPointer is Delegate) { throw new KOSYouShouldNeverSeeThisException("OpcodeCall unexpected function pointer delegate"); } else { throw new KOSNotInvokableException(functionPointer); } if (functionPointer is ISuffixResult) { if (! (delegateReturn is KOSPassThruReturn)) cpu.PushStack(delegateReturn); // And now leave the return value on the stack to be read. } return newIP; }
public override void Execute(ICpu cpu) { object value = cpu.PopValue(); bool result = Convert.ToBoolean(value); cpu.PushStack(result); }
public override void Execute(ICpu cpu) { object right = cpu.PopValue(); object left = cpu.PopValue(); var operands = new OperandPair(left, right); Calculator calc = Calculator.GetCalculator(operands); Operands = operands; object result = ExecuteCalculation(calc); cpu.PushStack(result); }
/// <summary> /// Take the topmost arguments down to the ARG_MARKER_STRING, pop them off, and then /// put them back again in reversed order so a function can read them in normal order. /// </summary> public void ReverseStackArgs(ICpu cpu) { List<object> args = new List<object>(); object arg = cpu.PopValue(); while (arg != null && (!(arg.ToString().Equals(ARG_MARKER_STRING)))) { args.Add(arg); // It's important to dereference with PopValue, not using PopStack, because the function // being called might not even be able to see the variable in scope anyway. // In other words, if calling a function like so: // declare foo to 3. // myfunc(foo). // The code inside myfunc needs to see that as being identical to just saying: // myfunc(3). // It has to be unaware of the fact that the name of the argument was 'foo'. It just needs to // see the contents that were inside foo. arg = cpu.PopValue(); } // Push the arg marker back on again. cpu.PushStack(ARG_MARKER_STRING); // Push the arguments back on again, which will invert their order: foreach (object item in args) cpu.PushStack(item); }