Arc Forumnew | comments | leaders | submitlogin
2 points by vincenz 5926 days ago | link | parent

Seems the problem is with ac-macro?

Debugging a bit, it seemed this gave #f for the second case, cause it's not a symbol. Simply replacing ac-macro? with something that just keeps 'fn' when it's not a symbol does not work. And then I realised why, if 'fn' is not a symbol, then it is still some input arc-code.

And this poses a big problem, one reason why I don't think macros will ever be first-class fully in this system. The problem is that you could have an arbitrary expression as first parameter and the only way to know whether it's a macro or not is to run it to its end.

This same issue is showing also with 'set which seems to be special. For instance, if one plays with acompile to compile arc-code, the crack starts to show. Normally, compiling should not have side-effects, simply compile to scheme code from arc code. However, now I see why macros work the way they work, 'set' code runs right off the bat. Simply try to compile the following code:

    (set do (annotate 'mac
              (fn args `((fn () ,@args)))))
    
    (set def (annotate 'mac
                (fn (name parms . body)
                  `(do (sref sig ',parms ',name)
                       (set ,name (fn ,parms ,@body))))))
    (set mac (annotate 'mac
               (fn (name parms . body)
                 `(do (sref sig ',parms ',name)
                      (set ,name (annotate 'mac (fn ,parms ,@body)))))))
    
    (def id (x) x)
    (def pr args
      (disp (car args))
      (car args))
    
    (set foo (pr (annotate 'mac id)))
You will see that it will print at compile time.


2 points by vincenz 5926 days ago | link

While digging through the code to try and fix this bug, I did come up with the following cleanup for ac-call:

    (define (ac-call fn args env)
      (let* ((afn (ac fn env))
            (macfn (ac-macro? fn)))
        (cond (macfn
               (ac-mac-call macfn args env))
              ((and (pair? fn) (eqv? (car fn) 'fn))
               `(,afn ,@(map (lambda (x) (ac x env)) args)))
              ((= (length args) 0)
               `(ar-funcall0 ,afn ,@(map (lambda (x) (ac x env)) args)))
              ((= (length args) 1)
               `(ar-funcall1 ,afn ,@(map (lambda (x) (ac x env)) args)))
              ((= (length args) 2)
               `(ar-funcall2 , afn ,@(map (lambda (x) (ac x env)) args)))
              ((= (length args) 3)
               `(ar-funcall3 ,afn ,@(map (lambda (x) (ac x env)) args)))
              ((= (length args) 4)
               `(ar-funcall4 ,afn ,@(map (lambda (x) (ac x env)) args)))
              (#t
               `(ar-apply ,afn
                          (list ,@(map (lambda (x) (ac x env)) args)))))))

-----

1 point by vincenz 5926 days ago | link

Refactoring some more:

    (define (ac-call fn args env)
      (let ((macfn (ac-macro? fn)))
        (if macfn
          (ac-mac-call macfn args env)
          (let ((afn (ac fn env))
                (aargs (map (lambda (x) (ac x env)) args))
                (nargs (length args)))
            (cond 
              ((and (pair? fn) (eqv? (car fn) 'fn))
               `(,afn ,@aargs))
              ((and (>= nargs 0) (<= nargs 4))
               `(,(string->symbol (string-append "ar-funcall" (number->string nargs)))
                                  ,afn ,@aargs))
               (#t
                `(ar-apply ,afn (list ,@aargs))))))))

-----