-
Notifications
You must be signed in to change notification settings - Fork 173
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
Add s-exp
primitive and Introspection module
#826
Conversation
This primitive returns the s-expression associated with a binding--in other words, the form a user wrote to define a binding. We handle special cases such as interfaces and deftypes, whose original defining forms are stored in the type environment instead of the global environment. Note that presently this doesn't always return *exactly* the form the user wrote. Specifically, the following cases are special: - Interfaces -- returns `(interface foo)` instead of the full form - Defndynamic -- returns `(dynamic foo [x] x)` instead of `defndynamic` - Defmacro -- returns `(macro [x] x)` instead of `defmacro` In spite of these wrinkles, I think it's a useful function to have, particularly for type introspection in dynamic functions/macros.
This is another special case. Instead of `(defmodule Foo)` it will only return the module name. Note that we only return the module name if it's actually only a module and not found in the type environment.
This commit makes the forms returned by the s-exp primitive usable with other dynamic functions that operate on symbols. By default, a special form like `Defn` is *not* a symbol. So, we map all the special forms to symbols in order to use the returned s-exps smoothly with other dynamic functions (which operate on symbols).
This commit changes the s-exp primitive to lookup paths in the global env--using the context env isn't sufficient for type/module definitions.
The introspect module contains functions that return information about program bindings based on their s-expressions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really great, amazing work!
Maybe we should point out somewhere what happens on name conflicts, e.g. when a thing is both a type and a module. Which binding wins? I see below that this is special-cased and we get the type, so we should probably tell people about that.
And how would we go about getting the module, if we really wanted to? This is not necessarily a breaker for this PR, but IMO there should definitely be a way. Maybe we could separate type and value handling and push that logic into Carp?
Before we used dyanmicNil, which, while equivalent to the empty list, isn't quite the same thing. This new approach ensures an empty list is actually printed to the REPL.
Great points as always. I think it'd be really valuable to be able to get either the type or module of a binding. I'm not certain, but that functionality may still need to remain in the compiler since it requires peeking into two different environments. If you don't mind, I'll leave this out of this PR for the sake of simplicity, but it's definitely worth pursuing, so I'll add an issue for it! |
In Carp, types automatically generate modules. When a type binding is passed to `s-exp` it returns the deftype form rather than the type's module form.
I like it! Instead of |
Looks great to me! I kinda like the |
I also like |
With the naming thing, I don't like abbreviations unless they are used quite often and are pretty common. In most cases, it makes it hard for me to remember the correct names, and I think that Looking over what the function does again, I agree that |
Good point! I agree that full names are better, unless anyone objects, I'm fine with calling it |
I agree that |
Sounds good! Made the name change...but now I'm weirdly getting an error in |
Weirdly the error doesn't happen when the form is named |
Ah, looks like it has to do with the fact that some macro bindings are named is |
Sounds good to me! |
Haha oops, that’s weird. Works for me. |
This PR adds an
s-exp
primitive, which returns the s-expression or form associated with a binding. It's similar to the default behavior of dynamic xobjs, but it does some extra checking on receiving module xobjs to return the original deftype forms whenever the modules are generated from a type.s-exp
is the backbone of a newIntrospection
module, which contains predicates about bindings and their associated forms. One can use this module in a dynamic context to determine if a binding is a function, struct, sumtype, interface, it's arity, etc.Here are a few examples of
s-exp
:and the
Introspect
module:Let's go ahead and say this fixes #560?