0

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?

pacificprince
  • 53
  • 2
  • 5
  • There's a lot of code here, the purpose of most of which is not explained, so I'm not sure what you want to accomplish, particularly how the constructs you haven't yet implemented are supposed to work. And, you say that your attempts "fail" without saying what's going wrong. Try to minimize your code and specify your question to the essential thing that you're confused about. Also, upgrade to Hy master, which, among other things, has changed lambda-list syntax in ways that will likely make this kind of problem easier. – Kodiologist Aug 25 '21 at 02:18
  • Thanks for the comments @Kodiologist! I have simplified the code to just the essentials. I am basically trying to write a template class generator. The idea is to generate a class with given input attributes. The class is populated with properties (read-only) corresponding to the input attributes. Let me know if further clarification is needed. – pacificprince Aug 25 '21 at 03:10
  • "upgrade to Hy master, which, among other things, has changed lambda-list syntax in ways that will likely make this kind of problem easier". – Kodiologist Aug 25 '21 at 03:26

0 Answers0