Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to make an eval function? #11

Open
philanc opened this issue Jan 24, 2021 · 4 comments
Open

how to make an eval function? #11

philanc opened this issue Jan 24, 2021 · 4 comments

Comments

@philanc
Copy link

philanc commented Jan 24, 2021

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?

@jeffpanici75
Copy link

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.

@philanc
Copy link
Author

philanc commented Mar 21, 2021

Thanks for your solution!

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

@jeffpanici75
Copy link

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.

@j0euk
Copy link

j0euk commented Jun 15, 2024

@jeffpanici75 What is EVAL_ARG()? There is no mention of it at all in fe.c or fe.h.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants