Exemplo n.º 1
0
        public void TestFunctionObject()
        {
            string     input     = "fn(x) { x + 2; };";
            Object_AST evaluated = testEval(input);

            Function_AST fn = evaluated as Function_AST;

            if (fn == null)
            {
                Assert.Fail(string.Format("object is not Function. got={0}", evaluated));
            }

            if (fn.Parameters.Count != 1)
            {
                Assert.Fail(string.Format("function has wrong parameters. Parameters={0}", fn.Parameters));
            }

            if (fn.Parameters[0].Value != "x")  //could have used ToString() as well
            {
                Assert.Fail(string.Format("parameter is not 'x'. got={0}", fn.Parameters[0]));
            }

            string expectedBody = "(x + 2)";

            if (fn.Body.ToString() != expectedBody)
            {
                Assert.Fail(string.Format("body is not {0}. got={1}", expectedBody, fn.Body.ToString()));
            }
        }
Exemplo n.º 2
0
        private static Object_AST evalHashLiteral(HashLiteral hash, Environment_AST env)
        {
            Dictionary <HashKey, HashPair> pairs = new Dictionary <HashKey, HashPair>();

            foreach (var item in hash.Pairs)
            {
                Object_AST key = Eval(item.Key, env);
                if (key is Error_AST)  //for recursive Eval calls, check the returned result of the recursive Eval. If an error, return rightaway. Otherwise we will get a
                {
                    return(key);       //higher level error obscuring the true source of error
                }

                IHashable hashKey = key as IHashable;
                if (hashKey is null)
                {
                    return(new Error_AST(string.Format("unusable as hash key: {0}", key.Type)));
                }

                Object_AST val = Eval(item.Value, env);
                if (val is Error_AST)  //for recursive Eval calls, check the returned result of the recursive Eval. If an error, return rightaway. Otherwise we will get a
                {
                    return(val);       //higher level error obscuring the true source of error
                }

                HashKey hashed = hashKey.HashKey();
                pairs[hashed] = new HashPair {
                    Key = key, Value = val
                };
            }

            return(new Hash_AST {
                Pairs = pairs
            });
        }
Exemplo n.º 3
0
        //it only assert integer aray elements at the moment..implement functionality in Array_AST to test equality
        private void testArrayObject(Object_AST resultObj, Array_AST expectedObj)
        {
            Array_AST result = resultObj as Array_AST;

            if (result is null)
            {
                Assert.Fail(string.Format("resultObj is not Array_AST. got={0}", resultObj));//Assert.Fail will internally anyways throw an AssertFailedException
            }

            Array_AST expected = expectedObj as Array_AST;

            if (expected is null)
            {
                Assert.Fail(string.Format("expectedObj is not Array_AST. got={0}", expected));
            }

            Assert.AreEqual(result.Elements.Count, expected.Elements.Count, string.Format("resultObj has wrong number of array elements. got={0}, want={1}", result.Elements.Count, expected.Elements.Count));

            for (int i = 0; i < expected.Elements.Count; i++)
            {
                Integer_AST exp_int = expected.Elements[i] as Integer_AST;
                Integer_AST res_int = result.Elements[i] as Integer_AST;
                Assert.AreEqual(res_int.Value, exp_int.Value, string.Format("resultObj array elements do not match. got={0}, want={1}", res_int, exp_int));
            }
        }
Exemplo n.º 4
0
        private void testStringObject(Object_AST resultObj, Object_AST expectedObj)
        {
            String_AST result = resultObj as String_AST;

            if (result is null)
            {
                throw new AssertFailedException(string.Format("resultObj is not String_AST. got={0}", resultObj));
            }

            String_AST expected = expectedObj as String_AST;

            if (expected is null)
            {
                throw new AssertFailedException(string.Format("expectedObj is not String_AST. got={0}", expected));
            }

            Assert.AreEqual(result.Value, expected.Value, string.Format("resultObj has wrong value. got={0}, want={1}", result.Value, expected.Value));
        }
Exemplo n.º 5
0
        private void testErrorObject(Object_AST resultObj, Error_AST expectedObj)
        {
            Error_AST result = resultObj as Error_AST;

            if (result is null)
            {
                Assert.Fail(string.Format("resultObj is not Error_AST. got={0}", resultObj));//Assert.Fail will internally anyways throw an AssertFailedException
            }

            Error_AST expected = expectedObj as Error_AST;

            if (expected is null)
            {
                Assert.Fail(string.Format("expectedObj is not Error_AST. got={0}", expected));
            }

            Assert.AreEqual(result.Message, expected.Message, string.Format("resultObj has wrong error message. got={0}, want={1}", result.Message, expected.Message));
        }
Exemplo n.º 6
0
        public static void Start(TextReader tIn, TextWriter tOut)
        {
            //create the env variable in outer scope so that it persists after executing a line of code and we can use a IDENT later
            Environment_AST env = Environment_AST.NewEnvironment_AST();

            while (true)
            {
                tOut.Write(prompt);

                string line = tIn.ReadLine();
                if (string.IsNullOrEmpty(line))
                {
                    break;
                }

                Lexer lex = new Lexer(line);
                #region MyRegion
                //var tok = lex.NextToken();
                //while (tok.Type != TokenHelper.TokenType.EOF) {
                //    tOut.WriteLine(tok);
                //    tok = lex.NextToken();
                //}
                #endregion
                Parser p = new Parser(lex);

                Program program = p.ParseProgram();
                if (p.Errors().Count != 0)
                {
                    printParserError(tOut, p.Errors());
                    continue;
                }

                //tOut.WriteLine(program.ToString());
                //tOut.WriteLine();
                Object_AST evaluated = Evaluator.Eval(program, env);
                if (evaluated != null)
                {
                    tOut.WriteLine(evaluated.Inspect());
                }
            }
        }
Exemplo n.º 7
0
 public Object_AST Set(string name, Object_AST value)
 {
     _store[name] = value;
     return(value);
 }
Exemplo n.º 8
0
 public ReturnValue_AST(Object_AST value)
 {
     Value = value;
 }
Exemplo n.º 9
0
 private void testNullObject(Object_AST resultObj, Object_AST expectedObj)
 {
     Assert.AreEqual(resultObj, expectedObj, string.Format("resultObj is not NULL. got={0}", resultObj));
 }
Exemplo n.º 10
0
 private static Object_AST evalIndexExpression(Object_AST left, Object_AST index)
 {
     switch (left, index)
     {
Exemplo n.º 11
0
        public static Object_AST Eval(AST_Helper.Node node, Environment_AST env)
        {
            switch (node)  //makes use of pattern matching. otherwise would have to use if else
            {
            case Program p:
                return(EvalProgram(p.Statements, env));   //logic for Program and BlockStatement is similar but varies in the case where the BlockStatement is

            //actually a nested block having a return in the nested(deeper/inner) level

            case BlockStatement blkStmt:    //would handle, for e.g., consequence and alternative statement blocks in IfExpression
                return(EvalBlockStatement(blkStmt.Statements, env));

            case ExpressionStatement stmt:
                return(Eval(stmt.Expression, env));

            case FunctionExpression funcExpr:
                return(new Function_AST(funcExpr.Parameters, funcExpr.Body, env));

            case HashLiteral hash:
                return(evalHashLiteral(hash, env));

            case FunctionCallExpression funcCallExpr:
                Object_AST func = Eval(funcCallExpr.Function, env); //Function could be Identifier(case below) or FunctionExpression(case above)
                if (func is Error_AST)                              //for recursive Eval calls, check the returned result of the recursive Eval. If an error, return rightaway. Otherwise we will get a
                {
                    return(func);                                   //higher level error obscuring the true source of error
                }

                List <Object_AST> args = evalExpressions(funcCallExpr.Arguments, env);   //Arguments is just a list of Expression
                if (args.Count == 1 && args[0] is Error_AST)
                {
                    return(args[0]);
                }

                //now that we have Eval 'ed the Function(Identifier or FunctionExpression) as well as the arguments, why do't we just Eval the Body which is just a BlockStatement.
                //Before we Eval the Body, we have to provide it its own Enviroment (for binding the above eval'ed arguments to the function parameters)

                return(applyFunction(func, args));

            case ArrayIndexExpression arrIdxExpr:
                Object_AST left = Eval(arrIdxExpr.Left, env);
                if (left is Error_AST)     //for recursive Eval calls, check the returned result of the recursive Eval. If an error, return rightaway. Otherwise we will get a
                {
                    return(left);          //higher level error obscuring the true source of error
                }

                Object_AST index = Eval(arrIdxExpr.Index, env);
                if (index is Error_AST)    //for recursive Eval calls, check the returned result of the recursive Eval. If an error, return rightaway. Otherwise we will get a
                {
                    return(left);          //higher level error obscuring the true source of error
                }

                return(evalIndexExpression(left, index));

            case LetStatement letStmt:
                Object_AST val = Eval(letStmt.Value, env);
                if (val is Error_AST)     //for recursive Eval calls, check the returned result of the recursive Eval. If an error, return rightaway. Otherwise we will get a
                {
                    return(val);          //higher level error obscuring the true source of error
                }

                env.Set(letStmt.Name.Value, val);
                return(val);

            case ArrayLiteral arr:
                List <Object_AST> elements = evalExpressions(arr.Elements, env);
                if (elements.Count == 1 && elements[0] is Error_AST)
                {
                    return(elements[0]);
                }

                return(new Array_AST {
                    Elements = elements
                });

            case Identifier ident:
                return(evalIdentifier(ident, env));

            case PrefixExpression prefixExpression:
                Object_AST rightExpr = Eval(prefixExpression.Right, env);
                if (rightExpr is Error_AST)     //for recursive Eval calls, check the returned result of the recursive Eval. If an error, return rightaway. Otherwise we will get a
                {
                    return(rightExpr);          //higher level error obscuring the true source of error
                }

                return(evalPrefixExpression(prefixExpression.Operator, rightExpr));

            case InfixExpression infixExpression:
                Object_AST leftExpr = Eval(infixExpression.Left, env);
                if (leftExpr is Error_AST)      //for recursive Eval calls, check the returned result of the recursive Eval. If an error, return rightaway. Otherwise we will get a
                {
                    return(leftExpr);           //higher level error obscuring the true source of error
                }
                Object_AST right = Eval(infixExpression.Right, env);
                if (right is Error_AST)     //for recursive Eval calls, check the returned result of the recursive Eval. If an error, return rightaway. Otherwise we will get a
                {
                    return(right);          //higher level error obscuring the true source of error
                }

                return(evalInfixExpression(infixExpression.Operator, leftExpr, right));

            case ReturnStatement retStmt:                           //we evaluate the expression associated with ReturnStatement and wrap that in a ReturnValue_AST object to be used later
                Object_AST retVal = Eval(retStmt.ReturnValue, env); //so if we are returning a int, that int is first evaluated and wrapped in a Integer_AST
                if (retVal is Error_AST)                            //for recursive Eval calls, check the returned result of the recursive Eval. If an error, return rightaway. Otherwise we will get a
                {
                    return(retVal);                                 //higher level error obscuring the true source of error
                }

                return(new ReturnValue_AST(retVal));   //and then that Integer_AST is again wrapped inside a ReturnValue_AST.

            case IfExpression ifExpr:
                return(evalIfExpression(ifExpr, env));

            case IntegerLiteral i:
                return(new Integer_AST(i.Value));

            case BooleanLiteral i:
                //return new Boolean_AST(i.Value);// this will create new objects for every true or false encountered. stop this profileration
                return(nativeBoolToBooleanObject(i.Value));

            case StringLiteral i:
                return(new String_AST(i.Value));

            default:
                //return new Null_AST();// this will create new null objects every time. stop this profileration
                return(null_AST);

            case null:
                throw new ArgumentNullException(nameof(node));
            }
        }