Beispiel #1
0
        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);
        }
Beispiel #2
0
        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));
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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);
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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);
        }
Beispiel #10
0
        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);
        }
Beispiel #11
0
        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);
        }
Beispiel #12
0
        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);
        }
Beispiel #13
0
        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);
        }
Beispiel #14
0
        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;
        }
Beispiel #15
0
        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.
        }
Beispiel #16
0
        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);
        }
Beispiel #17
0
        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);
        }
Beispiel #18
0
        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);
        }
Beispiel #19
0
        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);
        }
Beispiel #20
0
        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);
        }
Beispiel #21
0
        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);
        }
Beispiel #22
0
        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);
        }
Beispiel #23
0
        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);
        }
Beispiel #24
0
        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);
        }
Beispiel #25
0
        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);
        }
Beispiel #26
0
        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}"));
        }
Beispiel #27
0
        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);
        }
Beispiel #28
0
        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);
        }
Beispiel #29
0
        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);
        }
Beispiel #30
0
        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);
        }