Problem 2: Evaluating Call Expressions (200 pts)
Now, let's add logic for evaluating call expressions, such as add(2, 3)
. Remember that a call expression consists of an operator and 0 or more operands.
In our implementation, a call expression is represented as a CallExpr
instance. Each instance of the CallExpr
class has the attributes operator
and operands
. operator
is an instance of Expr
, and, since a call expression can have multiple operands, operands
is a list of Expr
instances.
For example, in the CallExpr
instance representing add(3, 4)
:
self.operator
would beName('add')
self.operands
would be the list[Literal(3), Literal(4)]
In CallExpr.eval
, implement the three steps to evaluate a call expression:
- Evaluate the operator in the current environment.
- Evaluate the operand(s) in the current environment.
- Apply the value of the operator, a function, to the value(s) of the operand(s).
Hint: Since the operator and operands are all instances of
Expr
, you can evaluate them by calling theireval
methods. Also, you can apply a function (an instance ofPrimitiveFunction
orLambdaFunction
) by calling itsapply
method, which takes in a list of arguments (Value
instances).
def eval(self, env):
"""
>>> from reader import read
>>> new_env = global_env.copy()
>>> new_env.update({'a': Number(1), 'b': Number(2)})
>>> add = CallExpr(Name('add'), [Literal(3), Name('a')])
>>> add.eval(new_env)
Number(4)
>>> new_env['a'] = Number(5)
>>> add.eval(new_env)
Number(8)
>>> read('max(b, a, 4, -1)').eval(new_env)
Number(5)
>>> read('add(mul(3, 4), b)').eval(new_env)
Number(14)
"""
"*** YOUR CODE HERE ***"
Use Ok to test your code:
python ok -q callexpr_eval
Now that you have implemented the evaluation of call expressions, we can use our interpreter for simple expressions like sub(3, 4)
and add(mul(4, 5), 4)
. Open your interpreter to do some cool math:
python repl.py