While trying to workaround the #176 I've stumped on a kinda weird bug. I've defined the following macro:
(macro defrecord [name ...]
"Create a constructor and accessor functions for a new record type."
{:fnl/arglist [name field1 field2 & fields]}
(let [name (tostring name)
fields (faccumulate [fields {}
i 1 (select :# ...)]
(doto fields
(tset (tostring (select i ...)) i)))
metatable {:__newindex
(list 'fn [(sym :record#) (sym :f#) (sym :v#)]
(list 'rawset (sym :record#) (list '. fields (sym :f#)) (sym :v#)))}
constructor `(fn [...]
`(setmetatable [(,'unquote ...)] ,metatable))
accessors (collect [f (pairs fields)
:into {name constructor}]
(.. name :- f)
`(fn [,(sym :record#)]
`(. (,'unquote ,(sym :record#)) ,(. fields f))))]
`(macros ,accessors)))
It expands to a bunch of other macros that act as inlined functions:
>> (macrodebug (defrecord foo a b c))
(macros {:foo (fn [...]
(quote (setmetatable
[(unquote ...)]
{:__newindex (fn [record# f# v#]
(rawset record# (. {:a 1 :b 2 :c 3} f#) v#))})))
:foo-a (fn [record#] (quote (. (unquote record#) 1)))
:foo-b (fn [record#] (quote (. (unquote record#) 2)))
:foo-c (fn [record#] (quote (. (unquote record#) 3)))})
The weird part is that if I copy the output - it works. But if I just execute the macro above as (defrecord foo a b c)
it fails with the error:
Compile error: /data/data/com.termux/files/usr/bin/fennel:3562: attempt to index a nil value (local 'source')
The even weirder part is that removing the setmetatable
call from the code that is generated by the defrecord
macro makes the error go away.
redacted
It seems like this macro uses nested quoting; do you mean to say it's a duplicate of #176?
While it does it's not a duplicate, probably, because the problem with its evaluation resulting with an odd error. As I've described, it can be manually macroexpanded first, then the result can be evaluated without errors, but not fully automatically as it supposed to, unless the newindex metamethod is present.