Beispiel #1
0
        /// <summary>
        /// Converts an S-Expression into a Q-Expression
        /// </summary>
        /// <returns>The list.</returns>
        internal static Value List(Env environment, Value arguments)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");
            return(sexprValue.CreateQExpression());;
        }
Beispiel #2
0
        /// <summary>
        /// Lists the environment (and optionally parent environment) as key value pairs
        /// (A Q-expr of Q-exprs)
        /// </summary>
        internal static Value ListEnv(Env environment, Value arguments)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            // Check Error Conditions
            var check = ArgumentsExactCount(sexprValue, 1, "printenv");

            if (check != null)
            {
                return(check);
            }

            var result = new QExprValue();

            foreach (var k in environment.Keys(true))
            {
                var kvp = new QExprValue();
                kvp.Cell.Add(new SymbolValue(k));
                kvp.Cell.Add(environment.Get(k));
                result.Cell.Add(kvp);
            }

            return(result);
        }
Beispiel #3
0
        /// <summary>
        /// Returns the tail of a list
        /// Argument 0 should be a Q-Expression representing the list
        /// </summary>
        internal static Value Tail(Env environment, Value arguments)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            // Check Error Conditions
            var check = ArgumentsExactCount(sexprValue, 1, "tail");

            if (check != null)
            {
                return(check);
            }

            check = ArgumentsIOfType(sexprValue, 0, QExprValue.TYPE, "tail");
            if (check != null)
            {
                return(check);
            }

            if (sexprValue.Cell[0].As <QExprValue>().Cell.Count == 0)
            {
                return(new ErrorValue("Function 'tail' passed {}."));
            }

            // Take first argument
            var qexpr = sexprValue.Cell[0].As <QExprValue>();

            // And remove the head
            qexpr.Cell.RemoveAt(0);

            return(qexpr);
        }
Beispiel #4
0
        /// <summary>
        /// Joins multiple q-expressions together
        /// </summary>
        /// <returns>The join.</returns>
        internal static Value Join(Env environment, Value arguments)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            var check = ArgumentsAllOfType(sexprValue, QExprValue.TYPE, "join");

            if (check != null)
            {
                return(check);
            }

            QExprValue x = sexprValue.Cell[0].As <QExprValue>();

            sexprValue.Cell.RemoveAt(0);

            while (sexprValue.Cell.Count > 0)
            {
                QExprValue y = sexprValue.Cell[0].As <QExprValue>();
                sexprValue.Cell.RemoveAt(0);
                x = Join(environment, x, y);
            }

            return(x);
        }
Beispiel #5
0
        /// <summary>
        /// Comparisons.
        /// </summary>
        static Value EqualityOp(Env environment, Value arguments, string op)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            var check = ArgumentsExactCount(sexprValue, 2, op);

            if (check != null)
            {
                return(check);
            }

            bool r = false;

            if (op.Equals("==", StringComparison.Ordinal))
            {
                r = sexprValue.Cell[0].IsEqivalent(sexprValue.Cell[1]);
            }
            if (op.Equals("!=", StringComparison.Ordinal))
            {
                r = !sexprValue.Cell[0].IsEqivalent(sexprValue.Cell[1]);
            }

            if (r == false)
            {
                return(new LongValue(FALSE));
            }
            else
            {
                return(new LongValue(TRUE));
            }
        }
Beispiel #6
0
        /// <summary>
        /// Returns a list containing the head of supplied list.
        /// Argument 0 should be a Q-Expression representing the list
        /// </summary>
        internal static Value Head(Env environment, Value arguments)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            var check = ArgumentsExactCount(sexprValue, 1, "head");

            if (check != null)
            {
                return(check);
            }

            check = ArgumentsIOfType(sexprValue, 0, QExprValue.TYPE, "head");
            if (check != null)
            {
                return(check);
            }

            if (sexprValue.Cell[0].As <QExprValue>().Cell.Count == 0)
            {
                return(new ErrorValue("Function 'head' passed {}."));
            }

            // Otherwise take first argument
            var qexpr = sexprValue.Cell[0].As <QExprValue>();

            // Remove everything but the head
            while (qexpr.Cell.Count > 1)
            {
                qexpr.Cell.RemoveAt(1);
            }

            return(qexpr); // And return
        }
Beispiel #7
0
 static ErrorValue ArgumentsAtLeastCount(SExprValue sexprValue, int n, string name)
 {
     if (sexprValue == null || sexprValue.Cell.Count < n)
     {
         return(new ErrorValue($"Function '{name}' expects at least {n} arguments.  Got {sexprValue.Cell.Count}."));
     }
     return(null);
 }
Beispiel #8
0
        /// <summary>
        /// Processes a file.
        /// </summary>
        /// <returns>The file.</returns>
        /// <param name="fileName">File name.</param>
        public Value EvaluateFile(string fileName)
        {
            var sexpr = new SExprValue();

            sexpr.Cell.Add(new BuiltinFuncValue(Builtins.Load));
            sexpr.Cell.Add(StringValue.ReadEscapedString(fileName));
            return(Evaluate(sexpr));
        }
Beispiel #9
0
 static ErrorValue ArgumentsExactCount(SExprValue sExprValue, int n, string name)
 {
     if (sExprValue == null || sExprValue.Cell.Count != n)
     {
         return(new ErrorValue($"Function '{name}' expects {n} arguments.  Got {sExprValue.Cell.Count}."));
     }
     return(null);
 }
Beispiel #10
0
 static ErrorValue ArgumentsIOfType(SExprValue sexprValue, int i, string type, string name)
 {
     Debug.Assert(sexprValue.Cell.Count > i, "i too high");
     if (sexprValue.Cell[i].Type != type)
     {
         return(new ErrorValue($"Function '{name}' expects argument {i} to be of type '{type}'.  Got {sexprValue.Cell[i].Type}."));
     }
     return(null);
 }
Beispiel #11
0
        /// <summary>
        /// Ordinal functions
        /// </summary>
        static Value OrdinalOp(Env environment, Value arguments, string op)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            var check = ArgumentsExactCount(sexprValue, 2, op);

            if (check != null)
            {
                return(check);
            }

            check = ArgumentsIOfType(sexprValue, 0, LongValue.TYPE, op);
            if (check != null)
            {
                return(check);
            }

            check = ArgumentsIOfType(sexprValue, 1, LongValue.TYPE, op);
            if (check != null)
            {
                return(check);
            }

            bool r = false;

            var n1 = sexprValue.Cell[0].As <LongValue>().Value;
            var n2 = sexprValue.Cell[1].As <LongValue>().Value;

            if (op.Equals(">", StringComparison.Ordinal))
            {
                r = n1 > n2;
            }
            if (op.Equals("<", StringComparison.Ordinal))
            {
                r = n1 < n2;
            }
            if (op.Equals(">=", StringComparison.Ordinal))
            {
                r = n1 >= n2;
            }
            if (op.Equals("<=", StringComparison.Ordinal))
            {
                r = n1 <= n2;
            }

            if (r == false)
            {
                return(new LongValue(FALSE));
            }
            else
            {
                return(new LongValue(TRUE));
            }
        }
Beispiel #12
0
 static ErrorValue ArgumentsAllOfType(SExprValue sexprValue, string type, string name)
 {
     if (sexprValue.Cell.Any(c => c.Type != type))
     {
         var example = sexprValue.Cell.First(c => c.Type != type);
         var index   = sexprValue.Cell.IndexOf(example);
         return(new ErrorValue($"Function '{name}' expects all arguments to be of type '{type}'.  Got {example.Type} at {index}."));
     }
     return(null);
 }
Beispiel #13
0
        /// <summary>
        /// Similar to print, but shows string values unescpaed.
        /// </summary>
        internal static Value Show(Env environment, Value arguments)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            // Print each argument followed by a space
            Console.WriteLine(string.Join(" ", sexprValue.Cell.Select(c => c.Type == StringValue.TYPE ? c.As <StringValue>().Value : c.ToString())));

            return(new SExprValue());
        }
Beispiel #14
0
        /// <summary>
        /// Print arguments to console.
        /// </summary>
        internal static Value Print(Env environment, Value arguments)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            // Print each argument followed by a space
            Console.WriteLine(string.Join(" ", sexprValue.Cell));

            return(new SExprValue());
        }
Beispiel #15
0
        /// <summary>
        /// Load the specified file and evaluates its contents
        /// </summary>
        internal static Value Load(Env environment, Value arguments)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            var check = ArgumentsExactCount(sexprValue, 1, "load");

            if (check != null)
            {
                return(check);
            }

            check = ArgumentsIOfType(sexprValue, 0, StringValue.TYPE, "load");
            if (check != null)
            {
                return(check);
            }

            string fileContents;

            try
            {
                string fileName = sexprValue.Cell[0].As <StringValue>().Value;
                if (!Path.IsPathRooted(fileName))
                {
                    var folder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                    fileName = Path.Combine(folder, fileName);
                }

                fileContents = File.ReadAllText(fileName);
            }
            catch (IOException e)
            {
                return(new ErrorValue("Unable to load: " + e.Message));
            }

            foreach (var result in environment.Evaluate(fileContents))
            {
                // Dump error values only
                if (result is ErrorValue)
                {
                    Console.WriteLine(result);
                }
            }
            return(new SExprValue()); // Empty S-Expr to finish
        }
Beispiel #16
0
        /// <summary>
        /// If 0th argument is FALSE, evaluate the 2nd argument, otherwise evaluate the 1st argument.
        /// Argument 0 should be LongValue.
        /// Arguments 1 and 2 should be Q-Expressions
        /// </summary>
        internal static Value If(Env environment, Value arguments)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            var check = ArgumentsExactCount(sexprValue, 3, "if");

            if (check != null)
            {
                return(check);
            }

            check = ArgumentsIOfType(sexprValue, 0, LongValue.TYPE, "if");
            if (check != null)
            {
                return(check);
            }

            check = ArgumentsIOfType(sexprValue, 1, QExprValue.TYPE, "if");
            if (check != null)
            {
                return(check);
            }

            check = ArgumentsIOfType(sexprValue, 2, QExprValue.TYPE, "if");
            if (check != null)
            {
                return(check);
            }

            Value res;

            if (sexprValue.Cell[0].As <LongValue>().Value != FALSE)
            {
                var s = sexprValue.Cell[1].As <QExprValue>().CreateSExpression();
                res = environment.Evaluate(s);
            }
            else
            {
                var s = sexprValue.Cell[2].As <QExprValue>().CreateSExpression();
                res = environment.Evaluate(s);
            }
            return(res);;
        }
Beispiel #17
0
        /// <summary>
        /// Variable put and def.
        /// </summary>
        static Value Var(Env environment, Value arguments, string func)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            var check = ArgumentsIOfType(sexprValue, 0, QExprValue.TYPE, func);

            if (check != null)
            {
                return(check);
            }

            QExprValue syms = sexprValue.Cell[0].As <QExprValue>();

            for (int i = 0; i < syms.Cell.Count; i++)
            {
                if (!(syms.Cell[i] is SymbolValue))
                {
                    return(new ErrorValue($"Function '{func}' cannot define non-symbol.  Got {syms.Cell[i].Type}. Expected {SymbolValue.TYPE}"));
                }
            }

            if (syms.Cell.Count != sexprValue.Cell.Count - 1)
            {
                return(new ErrorValue($"Function '{func}' passed wrong number of arguments.  Got {syms.Cell.Count} symbols and {sexprValue.Cell.Count - 1} arguments."));
            }

            for (int i = 0; i < syms.Cell.Count; i++)
            {
                // If 'def' define in globally. If 'put' define in locally
                if (func == "def")
                {
                    environment.Def(syms.Cell[i].As <SymbolValue>().Value, sexprValue.Cell[i + 1]);
                }

                if (func == "=")
                {
                    environment.Put(syms.Cell[i].As <SymbolValue>().Value, sexprValue.Cell[i + 1]);
                }
            }

            return(new SExprValue());
        }
Beispiel #18
0
        /// <summary>
        /// Creates a lambda function consisting of two q-expressions
        /// representing the formal parameters (all must be symbols) and the body.
        /// </summary>
        internal static Value Lambda(Env environment, Value arguments)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            // Check Error Conditions
            var check = ArgumentsExactCount(sexprValue, 2, "lambda");

            if (check != null)
            {
                return(check);
            }

            check = ArgumentsIOfType(sexprValue, 0, QExprValue.TYPE, "lambda (formals)");
            if (check != null)
            {
                return(check);
            }

            check = ArgumentsIOfType(sexprValue, 1, QExprValue.TYPE, "lambda (body)");
            if (check != null)
            {
                return(check);
            }

            // Check first Q-Expression contains only Symbols
            QExprValue formals = sexprValue.Cell[0].As <QExprValue>();

            for (int i = 0; i < formals.Cell.Count; i++)
            {
                if (!(formals.Cell[i] is SymbolValue))
                {
                    return(new ErrorValue($"Cannot define non-symbol.  Got {formals.Cell[i].Type} Expected {SymbolValue.TYPE}."));
                }
            }

            Value body = sexprValue.Cell[1];

            return(new LambdaFuncValue(formals, body));
        }
Beispiel #19
0
        /// <summary>
        /// Generates an error value
        /// </summary>
        internal static Value Error(Env environment, Value arguments)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            var check = ArgumentsExactCount(sexprValue, 1, "error");

            if (check != null)
            {
                return(check);
            }

            check = ArgumentsIOfType(sexprValue, 0, StringValue.TYPE, "load");
            if (check != null)
            {
                return(check);
            }

            // Construct Error from first argument
            return(new ErrorValue(sexprValue.Cell[0].As <StringValue>().Value));
        }
Beispiel #20
0
        /// <summary>
        /// Evaluates the q-expression contained as first child of this s-expr
        /// </summary>
        /// <returns>The eval.</returns>
        internal static Value Eval(Env environment, Value arguments)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            var check = ArgumentsExactCount(sexprValue, 1, "eval");

            if (check != null)
            {
                return(check);
            }

            check = ArgumentsIOfType(sexprValue, 0, QExprValue.TYPE, "eval");
            if (check != null)
            {
                return(check);
            }

            QExprValue x = sexprValue.Cell[0].As <QExprValue>();

            return(environment.Evaluate(x.CreateSExpression()));
        }
Beispiel #21
0
        /// <summary>
        /// Mathematical functions
        /// </summary>
        static Value MathOp(Env environment, Value arguments, string op)
        {
            SExprValue sexprValue = arguments.As <SExprValue>();

            Debug.Assert(sexprValue != null, "Non s-expr");

            // Ensure all numbers
            var check = ArgumentsAllOfType(sexprValue, LongValue.TYPE, op);

            if (check != null)
            {
                return(check);
            }

            // Pop the first element
            Value     xBase = sexprValue.Cell[0];
            LongValue x     = xBase.As <LongValue>();

            sexprValue.Cell.RemoveAt(0);

            // If no arguments and sub then perform unary negation
            if (op.Equals("-", StringComparison.Ordinal) && sexprValue.Cell.Count == 0)
            {
                x.Value = -x.Value;
            }

            // While there are still elements remaining
            while (sexprValue.Cell.Count > 0)
            {
                // Pop the next element
                LongValue y = sexprValue.Cell[0].As <LongValue>();
                sexprValue.Cell.RemoveAt(0);

                if (op.Equals("+", StringComparison.Ordinal))
                {
                    x.Value += y.Value;
                }
                else if (op.Equals("-", StringComparison.Ordinal))
                {
                    x.Value -= y.Value;
                }
                else if (op.Equals("*", StringComparison.Ordinal))
                {
                    x.Value *= y.Value;
                }
                else if (op.Equals("/", StringComparison.Ordinal))
                {
                    if (y.Value == 0)
                    {
                        xBase = new ErrorValue("Division By Zero.");
                        break;
                    }
                    x.Value /= y.Value;
                }
                else if (op.Equals("%", StringComparison.Ordinal))
                {
                    if (y.Value == 0)
                    {
                        xBase = new ErrorValue("Division By Zero.");
                        break;
                    }
                    x.Value %= y.Value;
                }
                else if (op.Equals("^", StringComparison.Ordinal))
                {
                    x.Value = (long)Math.Pow(x.Value, y.Value);
                }
            }

            return(xBase);
        }