示例#1
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
            });
        }
示例#2
0
        public static Environment_AST NewEnclosedEnvironment_AST(Environment_AST outer)
        {
            //Environment_AST env = new Environment_AST() { _outer = outer};
            //env._outer = outer;

            return(new Environment_AST()
            {
                _outer = outer
            });
        }
示例#3
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());
                }
            }
        }
示例#4
0
        private Environment_AST _outer;//used to keep track of nested scopes

        private Environment_AST()
        {
            this._store = new Dictionary <string, Object_AST>();
            this._outer = null;
        }
示例#5
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));
            }
        }