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

Custom _macro_ types #254

Merged
merged 2 commits into from
Jan 25, 2024
Merged

Custom _macro_ types #254

merged 2 commits into from
Jan 25, 2024

Conversation

gilch
Copy link
Owner

@gilch gilch commented Jan 24, 2024

This makes the compiler a little more consistent with the reader. Using the _macro_ object's __getattr__ as a hook for overriding invocations (for example, making the module a Lisp-2) was a use case I intended at least since version 0.2.0 as mentioned in the old FAQ.

When I actually tried doing it, I noticed that the compiler would require a small tweak. That's this change.

There are some subtleties around how dots should be handled. I might need more experience with this version before I can say if further changes are warranted. For use cases I'm imagining, I think local invocations with single dots like (self.foo) should be overridable, but external invocations with double dots like (builtins..print) should not, although (foo.._macro_.bar) should probably be overridable via the foo. module's _macro_ rather than the local one.

It's a bit tricky because foo.bar.baz is different from (getattr foo 'bar.baz).

@gilch
Copy link
Owner Author

gilch commented Jan 24, 2024

Here's an example of turning the current module into a Lisp-2.

(hissp.._macro_.prelude)
(alias bn builtins.)

(define #' my#my) ; The function namespace.

(defmacro defun (name params : :* body)
  "Defines a function in the function namespace"
  `(setattr #' ',name (lambda ,params ,@body)))

(deftype _Macro ()
  __init__ (lambda (self) (.update (vars self) (vars _macro_))) ; Keep prelude macros.
  __getattr__ (lambda (self name)
                (if-else (op#contains name ".")
                  (throw (bn#AttributeError name)) ; Macro not found, do normal behavior.
                  (lambda (: :* args)
                   `(,(.format "{}.{}" '#' name) ,@args)))))

(define _macro_ (_Macro))
(define __builtins__ (% '__import__ __import__)) ; Removes builtins, except __import__.

(bn#print "Hi!") ; builtins still available via alias.
(defun print x (bn#print "print:" x)) ; Lives in function namespace.
(define print 42) ; Just a global.
(print print) ; No conflict in a Lisp-2!
(print #'.print) ; You can still get the function object.

@gilch
Copy link
Owner Author

gilch commented Jan 24, 2024

Note that this kind of override would only apply to invocations of symbols. Tuple expressions that resolve to callables wouldn't be affected. Fully qualified identifiers mostly wouldn't be affected either, but direct use of an affected _macro_ object would be.

@gilch
Copy link
Owner Author

gilch commented Jan 25, 2024

Other uses might be to change how call syntax works. You could change the default active control words : :? :* :** to something else, for example, add new ones, or change how those work. Macros mostly expand to fully-qualified invocations or special forms, so they'd mostly still be usable. Any expansion that invokes a gensym local might break though. Hmm.

@gilch gilch merged commit 21bb7c4 into master Jan 25, 2024
3 checks passed
@gilch gilch deleted the custom-_macro_-types branch January 25, 2024 00:05
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

Successfully merging this pull request may close these issues.

1 participant