public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * ARRAY_KEYS ( a -- {@} ) * Returns the keys of an array in a stackrange. Example: * * "index0" "index1" 2 */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "ARRAY_VALS requires one parameter")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.Array) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "ARRAY_VALS requires the top parameter on the stack to be an array")); } var array = n1.UnwrapArray(); for (int i = 0; i < array.Length; i++) { parameters.Stack.Push(new ForthDatum(array[i].Key ?? $"index{i}")); } parameters.Stack.Push(new ForthDatum(array.Length)); return(ForthPrimativeResult.SUCCESS); }
public static async Task <ForthPrimativeResult> ExecuteAsync(ForthPrimativeParameters parameters) { /* * CONTENTS ( d -- d' ) * * Pushes the dbref of the first thing contained by d. This dbref can then be referenced by `next' to cycle through all of the contents of d. d may be a room or a player. */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "CONTENTS requires one parameter")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.DbRef) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "CONTENTS requires the top parameter on the stack to be a dbref")); } var target = await n1.UnwrapDbref().Get(parameters.CancellationToken); if (target == null || (target.Type != DbrefObjectType.Room && target.Type != DbrefObjectType.Player)) { parameters.Stack.Push(new ForthDatum(Dbref.NOT_FOUND, 0)); return(ForthPrimativeResult.SUCCESS); } var container = target; var first = container.FirstContent(); parameters.Stack.Push(new ForthDatum(first, 0)); return(new ForthPrimativeResult("CONTENTS completed", first)); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * ! ( x v -- ) * Sets variable v's value to x. */ if (parameters.Stack.Count < 2) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "! requires two parameters")); } var svar = parameters.Stack.Pop(); if (svar.Value == null) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "! requires two parameters, but the variable name was null")); } var sval = parameters.Stack.Pop(); if (sval.Value == null) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "! requires two parameters, but the variable value was null")); } var result = new ForthPrimativeResult($"Variable {svar.Value} set to {sval.Value}") { dirtyVariables = new Dictionary <string, ForthVariable> { { svar.Value.ToString() !.ToLowerInvariant(), new ForthVariable(sval.Value, sval.Type == DatumType.String ? VariableType.String : (sval.Type == DatumType.Float ? VariableType.Float : (sval.Type == DatumType.Integer ? VariableType.Integer : (sval.Type == DatumType.DbRef ? VariableType.DbRef : VariableType.Unknown))), false) } } }; return(result); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { // POPN ( ?n..?1 i -- ) // Pops the top i stack items. if (parameters.Stack.Count == 0) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "POPN requires at least one parameter")); } var si = parameters.Stack.Pop(); if (si.Type != DatumType.Integer) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "POPN requires the top parameter on the stack to be an integer")); } int i = si.UnwrapInt(); if (parameters.Stack.Count < i) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, $"POPN would have removed {i} items on the stack, but only {parameters.Stack.Count} were present.")); } for (int n = 0; n < i; n++) { parameters.Stack.Pop(); } return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * TIMESPLIT ( i -- is im ih id im iy iw iyd ) * * Splits a systime value into 8 values in the following order: * seconds, minutes, hours, monthday, month, year, weekday, yearday. * Weekday starts with sunday as 1, and yearday is the day of the year (1-366). */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "TIMESPLIT requires one parameter")); } var si = parameters.Stack.Pop(); if (si.Type != DatumType.Integer) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "TIMESPLIT requires the top parameter on the stack to be an integer")); } var offset = DateTimeOffset.FromUnixTimeSeconds(si.UnwrapInt()); parameters.Stack.Push(new ForthDatum(offset.DateTime.Second)); parameters.Stack.Push(new ForthDatum(offset.DateTime.Minute)); parameters.Stack.Push(new ForthDatum(offset.DateTime.Hour)); parameters.Stack.Push(new ForthDatum(offset.DateTime.Day)); parameters.Stack.Push(new ForthDatum(offset.DateTime.Month)); parameters.Stack.Push(new ForthDatum(offset.DateTime.Year)); parameters.Stack.Push(new ForthDatum(((int)offset.DateTime.DayOfWeek) + 1)); parameters.Stack.Push(new ForthDatum(offset.DateTime.DayOfYear)); return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * INSTR ( s s1 -- i ) * * Returns the first occurrence of string s1 in string s, or 0 if s1 is not found. */ if (parameters.Stack.Count < 2) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "INSTR requires two parameters")); } var n2 = parameters.Stack.Pop(); if (n2.Type != DatumType.String || n2.Value == null) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "INSTR requires the second-to-top parameter on the stack to be a string")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.String || n1.Value == null) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "INSTR requires the top parameter on the stack to be a string")); } var s1 = (string)n1.Value; var s2 = (string)n2.Value; parameters.Stack.Push(new ForthDatum(s1.IndexOf(s2) + 1)); return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * DESCRCON (i -- i) * * Takes a descriptor and returns the associated connection number, or 0 if no match was found. (Requires Mucker Level 3) * Also see: DESCRIPTORS and CONDESCR */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "DESCRCON requires one parameter")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.Integer) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "DESCRCON requires the top parameter on the stack to be an integer")); } var connectionNumber = Server.GetConnectionNumberForConnectionDescriptor(n1.UnwrapInt()); parameters.Stack.Push(new ForthDatum(connectionNumber ?? 0)); return(ForthPrimativeResult.SUCCESS); }
public static async Task <ForthPrimativeResult> ExecuteAsync(ForthPrimativeParameters parameters) { /* * PENNIES ( d -- i ) * * Gets the amount of pennies player object d has, or the penny value of thing d. */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "PENNIES requires one parameter")); } var d = parameters.Stack.Pop(); if (d.Type != DatumType.DbRef) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "PENNIES requires the top parameter on the stack to be a dbref")); } var target = d.UnwrapDbref(); var targetResult = await ThingRepository.Instance.GetAsync <Thing>(target, parameters.CancellationToken); if (!targetResult.isSuccess || targetResult.value == null) { parameters.Stack.Push(new ForthDatum(0)); return(ForthPrimativeResult.SUCCESS); } parameters.Stack.Push(new ForthDatum(targetResult.value.pennies)); return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * ARRAY_MAKE ( {?} -- a ) * * Creates a list type array from a stackrange. */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "ARRAY_MAKE requires at LEAST one parameter")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.Integer) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "ARRAY_MAKE requires the top parameter on the stack to be an integer")); } if (parameters.Stack.Count < n1.UnwrapInt()) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, $"ARRAY_MAKE has fewer than requested {n1.UnwrapInt()} items on the stack")); } var arrayList = new List <ForthDatum>(parameters.Stack.Count); for (int i = 0; i < n1.UnwrapInt(); i++) { arrayList.Add(parameters.Stack.Pop()); } parameters.Stack.Push(new ForthDatum(arrayList.ToArray())); return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * DESCRIPTORS (d -- ix...i1 i) * * Takes a player dbref, or #-1, and returns the range of descriptor numbers associated with that dbref (or all for #-1) with their count on top. Descriptors are numbers that always stay the same for a connection, while a connection# is the relative position in the WHO list of a connection. * Also see: DESCRCON and CONDESCR */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "DESCRIPTORS requires two parameters")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.DbRef) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "DESCRIPTORS requires the top parameter on the stack to be a dbref")); } var connectionDescriptors = Server.GetConnectionDescriptors(n1.UnwrapDbref()).ToArray(); foreach (var connectionDescriptor in connectionDescriptors) { parameters.Stack.Push(new ForthDatum(connectionDescriptor)); } parameters.Stack.Push(new ForthDatum(connectionDescriptors.Length)); return(ForthPrimativeResult.SUCCESS); }
public static async Task <ForthPrimativeResult> ExecuteAsync(ForthPrimativeParameters parameters) { /* * OWNER ( d -- d' ) * * d is any database object. Returns d', the player object that owns d. If d is a player, d' will be the same as d. */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "OWNER requires one parameter")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.DbRef) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "OWNER requires the top parameter on the stack to be a dbref")); } var target = n1.UnwrapDbref(); var targetResult = await ThingRepository.Instance.GetAsync <Thing>(target, parameters.CancellationToken); if (!targetResult.isSuccess || targetResult.value == null) { parameters.Stack.Push(new ForthDatum(Dbref.NOT_FOUND, 0)); return(ForthPrimativeResult.SUCCESS); } parameters.Stack.Push(new ForthDatum(targetResult.value.Owner, 0)); return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * STRCMP ( s1 s2 -- i ) * * Compares strings s1 and s2. Returns i as 0 if they are equal, * otherwise returns i as the difference between the first non-matching character in the strings. * * For example, "z" "a" strcmp returns 25. The reason it returns a 0 for a match, and the difference on a non-match, * is to allow for nice things like string sorting functions. This primitive is case sensitive, unlike stringcmp. */ if (parameters.Stack.Count < 2) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "STRCMP requires two parameters")); } var n2 = parameters.Stack.Pop(); if (n2.Type != DatumType.String) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "STRCMP requires the second-to-top parameter on the stack to be a string")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.String) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "STRCMP requires the top parameter on the stack to be a string")); } var s1 = (string?)n1.Value ?? string.Empty; var s2 = (string?)n2.Value ?? string.Empty; for (var n = 0; n < Math.Max(s1.Length, s2.Length); n++) { if (n > s1.Length - 1) { parameters.Stack.Push(new ForthDatum((int)Encoding.ASCII.GetBytes(s2[n].ToString())[0])); return(ForthPrimativeResult.SUCCESS); } else if (n > s2.Length - 1) { parameters.Stack.Push(new ForthDatum(-1 * (int)Encoding.ASCII.GetBytes(s1[n].ToString())[0])); return(ForthPrimativeResult.SUCCESS); } else { var c1 = (int)Encoding.ASCII.GetBytes(s1[n].ToString())[0]; var c2 = (int)Encoding.ASCII.GetBytes(s2[n].ToString())[0]; if (c1 != c2) { parameters.Stack.Push(new ForthDatum(c2 - c1)); return(ForthPrimativeResult.SUCCESS); } } } parameters.Stack.Push(new ForthDatum(0)); return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * STRINGPFX (s s2 -- i) * * Returns 1 if string s2 is a prefix of string s. If s2 is NOT a prefix of s, then it returns 0. Case insensitive. */ if (parameters.Stack.Count < 2) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "STRINGPFX requires two parameters")); } var n2 = parameters.Stack.Pop(); if (n2.Type != DatumType.String) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "STRINGPFX requires the second-to-top parameter on the stack to be a string")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.String) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "STRINGPFX requires the top parameter on the stack to be a string")); } var s1 = (string?)n1.Value ?? string.Empty; var s2 = (string?)n2.Value ?? string.Empty; parameters.Stack.Push(new ForthDatum(s1.StartsWith(s2) ? 1 : 0)); return(ForthPrimativeResult.SUCCESS); }
public static async Task<ForthPrimativeResult> ExecuteAsync(ForthPrimativeParameters parameters) { /* SETPROP (d s ? -- ) Stores a lock, dbref, integer, or string into the named property on the given object. Permissions are the same as for ADDPROP. */ if (parameters.Stack.Count < 3) return new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "SETPROP requires four parameters"); var v = parameters.Stack.Pop(); var s = parameters.Stack.Pop(); if (s.Type != DatumType.String) return new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "SETPROP requires the second-to-top parameter on the stack to be a string"); var d = parameters.Stack.Pop(); if (d.Type != DatumType.DbRef) return new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "SETPROP requires the third-to-top parameter on the stack to be a dbref"); var targetResult = await ThingRepository.Instance.GetAsync<Thing>(d.UnwrapDbref(), parameters.CancellationToken); if (!targetResult.isSuccess || targetResult.value == null) return new ForthPrimativeResult(ForthErrorResult.NO_SUCH_OBJECT, $"Unable to find object with dbref {d.UnwrapDbref()}"); var path = ((string?)s.Value) ?? string.Empty; targetResult.value.SetPropertyPathValue(path, new ForthVariable(v)); return ForthPrimativeResult.SUCCESS; }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * / ( n1 n2 -- n ) * * This divides two numbers, n1 / n2. If both numbers are integers, an integer will be returned. If one of them is a floating * point number, then a float will be returned. You can also use this on a dbref or a variable number, so long as the * second argument is an integer. In those cases, this will return a dbref or variable number, respectively. */ if (parameters.Stack.Count < 2) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "* requires two parameters")); } var n2 = parameters.Stack.Pop(); var n1 = parameters.Stack.Pop(); if (n1.Type == DatumType.Integer && n2.Type == DatumType.Integer) { var n2v = n2.UnwrapInt(); if (n2v == 0) { return(new ForthPrimativeResult(ForthErrorResult.DIVISION_BY_ZERO, "Attempt to divide by zero was aborted")); } parameters.Stack.Push(new ForthDatum(n1.UnwrapInt() / n2v)); return(ForthPrimativeResult.SUCCESS); } if ((n1.Type == DatumType.Integer || n1.Type == DatumType.Float) && (n2.Type == DatumType.Integer || n2.Type == DatumType.Float)) { var n2v = Convert.ToSingle(n2.Value); if (n2v == 0) { return(new ForthPrimativeResult(ForthErrorResult.DIVISION_BY_ZERO, "Attempt to divide by zero was aborted")); } parameters.Stack.Push(new ForthDatum(Convert.ToSingle(n1.Value) / n2v)); return(ForthPrimativeResult.SUCCESS); } if (n1.Type == DatumType.DbRef || n2.Type == DatumType.Integer) { var n1v = n1.UnwrapDbref().ToInt32(); var n2v = n2.UnwrapInt(); if (n2v == 0) { return(new ForthPrimativeResult(ForthErrorResult.DIVISION_BY_ZERO, "Attempt to divide by zero was aborted")); } parameters.Stack.Push(new ForthDatum(new Dbref(n1v / n2v, DbrefObjectType.Thing), 0)); return(ForthPrimativeResult.SUCCESS); } return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "/ expects integers or floating point numbers, or no more than one dbref and an integer")); // TODO: We do not support variable numbers today. They're depreciated anyway. }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * BITOR (i i -- i) * * Does a mathematical bitwise or. */ if (parameters.Stack.Count < 2) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "BITAND requires two parameters")); } var n2 = parameters.Stack.Pop(); var n1 = parameters.Stack.Pop(); if (n2.Type != DatumType.Integer) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "BITAND requires arguments to be integers")); } if (n1.Type != DatumType.Integer) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "BITAND requires arguments to be integers")); } parameters.Stack.Push(new ForthDatum(n1.UnwrapInt() & n2.UnwrapInt())); return(ForthPrimativeResult.SUCCESS); }
public static async Task <ForthPrimativeResult> ExecuteAsync(ForthPrimativeParameters parameters) { /* * UNPARSEOBJ ( d -- s ) * * Returns the name-and-flag string for an object. It always has the dbref and flag string after the name, even if the player doesn't control the object. For example: "One(#1PW)" */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "UNPARSEOBJ requires one parameter")); } var sTarget = parameters.Stack.Pop(); if (sTarget.Type != DatumType.DbRef) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "UNPARSEOBJ requires the top parameter on the stack to be a dbref")); } var targetResult = await ThingRepository.Instance.GetAsync <Thing>(sTarget.UnwrapDbref(), parameters.CancellationToken); if (!targetResult.isSuccess || targetResult.value == null) { parameters.Stack.Push(new ForthDatum(string.Empty)); return(ForthPrimativeResult.SUCCESS); } var unparsed = await targetResult.value.UnparseObject(parameters.Player, parameters.CancellationToken); parameters.Stack.Push(new ForthDatum(unparsed, sTarget.FileLineNumber, null, sTarget.WordName, sTarget.WordLineNumber)); return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * DBREF ( i -- d ) * * Converts integer i to object reference d. */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "DBREF requires one parameter")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.Integer) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "DBREF requires the top parameter on the stack to be an integer")); } var ni = n1.UnwrapInt(); if (ni < 0) { parameters.Stack.Push(new ForthDatum(NOT_FOUND, 0)); } else { parameters.Stack.Push(new ForthDatum(new Dbref(ni, DbrefObjectType.Unknown), 0)); } return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { // DUPN ( ?n..?1 i -- ?n..?1 ?n..?1 ) // Duplicates the top i stack items. if (parameters.Stack.Count == 0) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "DUPN requires at least one parameter")); } var si = parameters.Stack.Pop(); if (si.Type != DatumType.Integer) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "DUPN requires the top parameter on the stack to be an integer")); } int i = si.UnwrapInt(); if (parameters.Stack.Count < i) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, $"DUPN would have duplicated {i} items on the stack, but only {parameters.Stack.Count} were present.")); } foreach (var source in parameters.Stack.Reverse().Take(i)) { parameters.Stack.Push(source); } return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * STRCAT ( s1 s2 -- s ) * * Concatenates two strings s1 and s2 and pushes the result s = s1s2 onto the stack. */ if (parameters.Stack.Count < 2) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "STRCAT requires two parameters")); } var n2 = parameters.Stack.Peek(); if (n2.Type != DatumType.String) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "STRCAT requires the second-to-top parameter on the stack to be a string")); } parameters.Stack.Pop(); var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.String) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "STRCAT requires the top parameter on the stack to be a string")); } parameters.Stack.Push(new ForthDatum($"{n1.Value ?? string.Empty}{n2.Value ?? string.Empty}", n2.FileLineNumber, null, n2.WordName, n2.WordLineNumber)); return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * CTOI ( s -- i ) * * Converts the first character in s into its ASCII equivilent. */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "CTOI requires one parameter")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.String) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "CTOI requires the top parameter on the stack to be a string")); } if (n1.Value == null || ((string)n1.Value).Length == 0) { parameters.Stack.Push(new ForthDatum(0)); } else { var ascii = Encoding.ASCII.GetBytes((string)n1.Value); parameters.Stack.Push(new ForthDatum(Convert.ToInt32(ascii[0]))); } return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * ARRAY_VALS ( a -- {?} ) * * Returns the values of an array in a stackrange. Example: * * "value0" "value1" 2 */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "ARRAY_VALS requires one parameter")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.Array) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "ARRAY_VALS requires the top parameter on the stack to be an array")); } var array = n1.UnwrapArray(); foreach (var elem in array) { parameters.Stack.Push(elem); } parameters.Stack.Push(new ForthDatum(array.Length)); return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * <= ( n1 n2 -- i ) * * Compares two numbers and returns 1 if n1 is less than or equal to n2, and 0 otherwise. */ if (parameters.Stack.Count < 2) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "<= requires two parameters")); } var n2 = parameters.Stack.Pop(); if (n2.Type != DatumType.Integer && n2.Type != DatumType.Float) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "<= requires the second-to-top parameter on the stack to be a number")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.Integer && n1.Type != DatumType.Float) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "<= requires the top parameter on the stack to be a number")); } parameters.Stack.Push(new ForthDatum(Convert.ToSingle(n1.Value) <= Convert.ToSingle(n2.Value) ? 1 : 0)); return(ForthPrimativeResult.SUCCESS); }
public static async Task <ForthPrimativeResult> ExecuteAsync(ForthPrimativeParameters parameters) { /* * NAME ( d -- s ) * * Takes object d and returns its name (@name) string field. */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "NAME requires two parameters")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.DbRef) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "NAME requires the top parameter on the stack to be a dbref")); } var target = n1.UnwrapDbref(); var targetResult = await ThingRepository.Instance.GetAsync <Thing>(target, parameters.CancellationToken); if (!targetResult.isSuccess || targetResult.value == null) { parameters.Stack.Push(new ForthDatum("")); return(ForthPrimativeResult.SUCCESS); } parameters.Stack.Push(new ForthDatum(targetResult.value.name)); return(ForthPrimativeResult.SUCCESS); }
public static async Task <ForthPrimativeResult> ExecuteAsync(ForthPrimativeParameters parameters) { /* * LOCATION ( d -- d' ) * * Returns location of object d as object d'. */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "LOCATION requires one parameter")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.DbRef) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "LOCATION requires the top parameter on the stack to be a dbref")); } var target = n1.UnwrapDbref(); var targetLocation = await target.GetLocation(parameters.CancellationToken); parameters.Stack.Push(new ForthDatum(targetLocation, 0)); return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * @ ( v -- x ) * Retrieves variable v's value x. */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "@ requires one parameter")); } var reference = parameters.Stack.Pop(); if (reference.Type != ForthDatum.DatumType.Variable) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "@ requires the top parameter on the stack to be a variable")); } var variableName = reference.Value.ToString().ToLowerInvariant(); var variableValue = ResolveVariableByName(parameters.Variables, parameters.Player, parameters.Location, parameters.Trigger, parameters.Command, variableName); if (default(ForthVariable).Equals(variableValue) && !parameters.Variables.ContainsKey(variableName)) { return(new ForthPrimativeResult(ForthErrorResult.VARIABLE_NOT_FOUND, $"No variable named {variableName} was found")); } if (!default(ForthVariable).Equals(variableValue)) { parameters.Stack.Push(new ForthDatum(variableValue, reference.FileLineNumber, null, reference.WordName, reference.WordLineNumber)); return(ForthPrimativeResult.SUCCESS); } return(new ForthPrimativeResult(ForthErrorResult.UNKNOWN_TYPE, $"Unable to determine data type for {variableName}: {variableValue.Value}")); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * % ( n1 n2 -- i ) * * This returns the integer modulo (remainder) of the division of two numbers, n1 % n2. * Floats cannot use the % modulo function. For them, use either the FMOD or MODF primitives. */ if (parameters.Stack.Count < 2) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "% requires two parameters")); } var n2 = parameters.Stack.Pop(); var n1 = parameters.Stack.Pop(); if (n2.Type != DatumType.Integer) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "% requires arguments to be integers")); } if (n1.Type != DatumType.Integer) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "% requires arguments to be integers")); } parameters.Stack.Push(new ForthDatum(n1.UnwrapInt() % n2.UnwrapInt())); return(ForthPrimativeResult.SUCCESS); }
public static async Task <ForthPrimativeResult> ExecuteAsync(ForthPrimativeParameters parameters) { /* * GETLINK ( d -- d' ) * * Returns what object d is linked to, or #-1 if d is unlinked. The interpretation of link depends on the * type of d: for an exit, returns the room, player, action, or thing that the exit is linked to. * * For a player or thing, it returns its `home', and for rooms returns the drop-to. */ if (parameters.Stack.Count < 1) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "GETLINK requires one parameter")); } var sTarget = parameters.Stack.Pop(); if (sTarget.Type != DatumType.DbRef) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "GETLINK requires the top parameter on the stack to be a dbref")); } var target = await sTarget.UnwrapDbref().Get(parameters.CancellationToken); if (target == null) { return(new ForthPrimativeResult(ForthErrorResult.NO_SUCH_OBJECT, $"Unable to find object with dbref {sTarget.UnwrapDbref()}")); } parameters.Stack.Push(new ForthDatum(target.LinkTargets.DefaultIfEmpty(Dbref.NOT_FOUND).FirstOrDefault(), 0)); return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * DBCMP ( d1 d2 -- i ) * * Performs comparison of database objects d1 and d2. If they are the same object, then i is 1, otherwise i is 0. Use of this primitive is deprecated, as dbrefs may be compared with the standard comparison functions (< <= > >= =). */ if (parameters.Stack.Count < 2) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "DBCMP requires two parameters")); } var n2 = parameters.Stack.Pop(); if (n2.Type != DatumType.DbRef) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "DBCMP requires the second-to-top parameter on the stack to be a dbref")); } var n1 = parameters.Stack.Pop(); if (n1.Type != DatumType.DbRef) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "DBCMP requires the top parameter on the stack to be a dbref")); } parameters.Stack.Push(new ForthDatum(n1.UnwrapDbref() == n2.UnwrapDbref() ? 1 : 0)); return(ForthPrimativeResult.SUCCESS); }
public static ForthPrimativeResult Execute(ForthPrimativeParameters parameters) { /* * ROTATE ( ni ... n1 i -- n(i-1) ... n1 ni ) * Rotates the top i things on the stack. Using a negative rotational value rotates backwards. Examples: * "a" "b" "c" "d" 4 rotate * would leave * "b" "c" "d" "a" * on the stack. * "a" "b" "c" "d" -4 rotate * would leave * "d" "a" "b" "c" on the stack. */ if (parameters.Stack.Count == 0) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, "ROTATE requires at least one parameter")); } var si = parameters.Stack.Pop(); if (si.Type != DatumType.Integer) { return(new ForthPrimativeResult(ForthErrorResult.TYPE_MISMATCH, "ROTATE requires the top parameter on the stack to be an integer")); } var i = si.UnwrapInt(); var ai = Math.Abs(i); if (parameters.Stack.Count < ai) { return(new ForthPrimativeResult(ForthErrorResult.STACK_UNDERFLOW, $"ROTATE would have rotated {ai} items on the stack, but only {parameters.Stack.Count} were present.")); } var data = new ForthDatum[ai]; for (int n = 0; n < ai; n++) { data[n] = parameters.Stack.Pop(); } if (i > 0) { for (int n = ai - 2; n >= 0; n--) { parameters.Stack.Push(data[n]); } parameters.Stack.Push(data[ai - 1]); } else { parameters.Stack.Push(data[0]); for (int n = ai - 1; n > 0; n--) { parameters.Stack.Push(data[n]); } } return(ForthPrimativeResult.SUCCESS); }