Skip to main content

Eval1

rascal-0.40.17

Synopsis

Like Eval0 but with support for let-expressions.

Description

Interpreter Eval1 supports the following features of Func:

FeatureEval1
function declarationy
integer constanty
variabley
arithmetic operatorsy
comparison operatorsy
cally
ify
lety
sequence
assignment
address operator
dereference operator

In particular, the let construct is supported and this requires the addition of an extra environment for <name, value> bindings.

Examples

module demo::lang::Func::Eval1

// using env, allowing let

import demo::lang::Func::AST;

import List;

alias Env = map[str, int];
alias PEnv = map[str, Func];

int eval1(str main, list[int] args, Prog prog) {
penv = ( f.name: f | f <- prog.funcs );
f = penv[main];
env = ( f.formals[i] : args[i] | i <- index(f.formals) );
return eval1(f.body, env, penv);
}


int eval1(nat(int nat), Env env, PEnv penv) = nat;

int eval1(var(str n), Env env, PEnv penv) = env[n];

int eval1(mul(Exp lhs, Exp rhs), Env env, PEnv penv) =
eval1(lhs, env, penv) * eval1(rhs, env, penv);

int eval1(div(Exp lhs, Exp rhs), Env env, PEnv penv) =
eval1(lhs, env, penv) / eval1(rhs, env, penv);

int eval1(add(Exp lhs, Exp rhs), Env env, PEnv penv) =
eval1(lhs, env, penv) + eval1(rhs, env, penv);

int eval1(sub(Exp lhs, Exp rhs), Env env, PEnv penv) =
eval1(lhs, env, penv) - eval1(rhs, env, penv);

int eval1(gt(Exp lhs, Exp rhs), Env env, PEnv penv) =
eval1(lhs, env, penv) > eval1(rhs, env, penv) ? 1 : 0;

int eval1(lt(Exp lhs, Exp rhs), Env env, PEnv penv) =
eval1(lhs, env, penv) < eval1(rhs, env, penv) ? 1 : 0;

int eval1(geq(Exp lhs, Exp rhs), Env env, PEnv penv) =
eval1(lhs, env, penv) >= eval1(rhs, env, penv) ? 1 : 0;

int eval1(leq(Exp lhs, Exp rhs), Env env, PEnv penv) =
eval1(lhs, env, penv) <= eval1(rhs, env, penv) ? 1 : 0;

int eval1(cond(Exp cond, Exp then, Exp otherwise), Env env, PEnv penv) =
(eval1(cond, env, penv) != 0) ? eval1(then, env, penv) : eval1(otherwise, env, penv);

int eval1(call(str name, list[Exp] args), Env env, PEnv penv) {
f = penv[name];
env = ( f.formals[i]: eval1(args[i], env, penv) | i <- index(f.formals) );
return eval1(f.body, env, penv);
}

int eval1(let(list[Binding] bindings, Exp exp), Env env, PEnv penv) {
env += ( b.var : eval1(b.exp, env, penv) | b <- bindings );
return eval1(exp, env, penv);
}

  • ❶ The alias Env is introduced that maps strings to integers. All evaluation functions get an extra Env argument.
  • ❷ The environment is used to retrieve a variable's value.
  • ❸ The environment is extended with new bindings.

Let's try this with F1:

fact(n) = let
x = n
in
if x <= 1 then
x
else
x * fact(x-1)
end
end

The result:

rascal>import demo::lang::Func::Load;
ok
rascal>import demo::lang::Func::Eval1;
ok
rascal>import demo::lang::Func::programs::F1;
ok
rascal>eval1("fact", [10], load(F1));
int: 3628800