fe icon indicating copy to clipboard operation
fe copied to clipboard

how to make an eval function?

Open philanc opened this issue 5 years ago • 3 comments

Thanks for fe -- a very nice tiny interpreter.

How could I make an eval function (or macro)? i.e. such that

(= a '(+ 1 2)) (eval a) => 3

I tried using mac and fn but couldn't make it. Did I miss something obvious?

philanc avatar Jan 24 '21 06:01 philanc

Here's how I did it:

  1. In fe.c, at line 44, add a new primitive type P_EVAL to the enum. You can insert it anywhere before the final field, P_MAX.
  2. In fe.c, at line 50, add the string name for P_EVAL as "eval". N.B. you need to insert the string at the matching index based on the value of the enum field you just added.
  3. In fe.c, at line 634, add this code:
case P_EVAL:
    va = checktype(ctx, evalarg(), FE_TPAIR);
    res = eval(ctx, va, env, NULL);
    break;

You now have a functional eval primitive. The following scheme code should work:

(print "(eval '(+ 100 200)) =" (eval '(+ 100 200)))

(do
    (let expr '(for x (list 1 2 3 4 5)
                       (print "x =" x)))
    (print "(eval expr) =" (eval expr)))

Keep in mind that fe doesn't support tail call optimization. This implementation of the eval primitive invokes two peer recursive calls to the C eval function.

jeffpanici75 avatar Mar 21 '21 14:03 jeffpanici75

Thanks for your solution!

Any chance the original author (rxi) would include it in 'fe'?

philanc avatar Mar 21 '21 20:03 philanc

I realized this well after my last post, but I sort of over fitted my implementation to your example. You can simplify the case statement I provided:

case P_EVAL:
    res = eval(ctx, EVAL_ARG(), env, NULL);
    break;

The prior version would only evaluate function application. This version will dynamically evaluate any legitimate s-expression. For example:

        (do
            (let a 42)
            (print "(eval 'a) =" (eval 'a)))

Now works, evaluating the variable. Either version works, depending on your needs. Just thought I'd mention it.

I don't want to speak for @rxi but I think the idea is that fe is so simple others can take it and mold it to their specific requirements. I've heavily customized fe for my use cases.

@rxi If you like the idea of officially adding an eval primitive to the interpreter, let me know. I'd be happy to prepare a pull request.

jeffpanici75 avatar Mar 22 '21 02:03 jeffpanici75