I need help with parsing arguments in a Hy Macro that generates code for a class.
What I am trying to accomplish: A macro that will generate a class with predefined properties. The property names are the variables used to initialize the class.
Here is what I have so far,
Property Generator
The function below generates the code for the property getter (convention is to use __variable__
name for private/internal variables)
(eval-and-compile
(defn defproperty [attribute &optional docstring &rest body]
`(with-decorator property
(defn ~attribute [self]
~docstring
(do ~@body)
(return (getattr self (+ "__" (str '~attribute) "__")))))))
Class Generator
The macro below generates the code for the class using variable names passed in the __init__
method.
(defmacro/g! defrecord [recname inherits properties
&optional docstring &rest body]
(setv g!properties% (-> (cut properties 1 (len properties) 2) (list)))
`(defclass ~recname [~@inherits]
~docstring
(defn __init__ [self ~@properties]
(for [prop% '~g!properties%]
(setattr self (+ "__" (str prop%) "__") (eval prop%))))
~@(lfor prop% g!properties% `(defproperty ~prop%))
(do ~@body)))
Test Cases
The above works nicely for the simplistic case below,
(defrecord record [] (^(of float) data ^(of int) x ^(of str) doc))
(setv rec (record 2.0 3 "abc"))
(. rec doc) ;; => "abc"
(. rec info) ;; => 5.0
but fails for more complicated argument structures,
(^(of float) data ^(of int) x &optional ^(of str) doc)
(^(of float) data ^(of int) x &kwonly ^(of str) [doc None])
This is because of the following statement in the macro,
(setv g!properties% (-> (cut properties 1 (len properties) 2) (list)))
Question: How can the macro be generalized so as to accommodate the more complicated use cases?