-
-
Notifications
You must be signed in to change notification settings - Fork 22
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
Proposal: Expand node identification and manipulation API #105
Comments
This would be a welcome change!
Also, what if instead of |
Good points! Agree with both of these.
My real motivation for this is wanting to know, regardless of what node I have, whether I should be able to call My first thought was to actually suggest a change to
Unfortunately, these issues also sort of apply to a Given that, the next-best thing I could think of was a |
I see, though wouldn't the addition of Regardless, I think |
Hmm... Maybe so! Let's see what happens with the implementation and can decide then what the right API is 🙂 |
Sounds good! |
Re: the |
I started working on this a bit, but realized that I need a precise definition for unqualified calls. For context, here's some "prior art" from ElixirSense: defguardp is_call(call, params)
when is_atom(call) and is_list(params) and
call not in [:., :__aliases__, :"::", :{}, :|>, :%, :%{}] I think this generally makes sense, but the definition doesn't strike me as complete. For instance, it doesn't account for So what makes something a "call" vs. a special form? I think the critical element that can be used to evaluate something is whether that thing is definable by users without modifying the compiler. By that definition, the following would not be considered calls because they are reserved words or forms that cannot be overridden:
This is a much larger set than what ElixirSense is using. Given this, here's a possible definition:
Does this make sense and is it a useful definition? An alternative could be to define calls more broadly and to add an additional
If we accept this second definition, I'd think that Am I overthinking this? 😅 |
@zachallaun those are good calls, but from my point of view Sourceror works at a lower level As far as we are concerned, In Elixir AST you can boil it down to two scenarios: In some cases, a call So from Sourceror's point of view, a Now, from the point of view of a tool like ElixirSense it does make more sense to narrow down the definition because it's dealing with a higher level where the language semantics do matter. I do welcome functions that deal with a higher level for the sake of making it easier to navigate the AST considering the semantics, maybe in a separate module under |
An useful thing however may be to exclude I'm torn on |
Thanks for sharing your thoughts! This largely makes sense. I'm interested in identifying higher level semantics, but agree that it makes sense in a separate module. The existing Identifier module kinda does this, right? Perhaps it makes sense in there? I think |
Actually now that you mention this, I do agree with you that I think the next step for semantics aware functions would be to come up with a name/place for such functions, maybe We can't have environment aware functions like ElixirSense may have, but we definitely can provide functions that operate on AST informed by vanilla elixir semantics |
Sounds good! Another thing we need is a good definition for are literals. I can imagine two versions, one that's lower level and lives in The lower-level would be The higher-level definition would be Thoughts? |
I'm actually thinking these should be called: Sourceror.Identifier.is_atomic_literal/1
Sourceror.Code.quoted_literal?/1 |
Regarding moving the existing Sourceror.Vendored.Code
Sourceror.Vendored.Code.Formatter
Sourceror.Vendored.Code.Normalizer |
That sounds like a good change, so yes we can do that! |
I've recently found myself writing a handful of functions and guards that I think would be useful additions to Sourceror.
The motivation for this is to have a handful of primitives that allow you to differentiate between and navigate the nodes of an AST parsed by Sourceror (and to a lesser extent, the default
Code.string_to_quoted
options). This is based on an assumption that the fundamental "categories" of nodes in an Elixir AST are::__block__
in order to retain additional metadataProposed guards:
is_local_call(node)
- local calls likefoo()
,1 + 1
, etc. Excludes special nodes like:__block__
,:__aliases__
, or data structures like:%{}
.is_qualified_call(node)
- similar to above but for qualified/dot calls,Foo.bar()
,foo.()
, etc.is_call(node)
- helper for local or qualified callis_var(node)
- identifies variablesis_literal(node)
- literals in the AST and wrapped{:__block__, _, [literal]}
nodes. (A block containing multiple literals is not a literal. I think this distinction is very useful when navigating AST.)Proposed functions:
fetch_literal(node)
- returns{:ok, value} | :error
- these would return the same thing:fetch_literal({:__block__, _, [:foo]})
/fetch_literal(:foo)
fetch_children(node)
- returns{:ok, [child]} | :error
(removed in favor of Changehas_range?
- iftrue
, node can be passed toget_range
without raisingget_range/1
to allow returningnil
and add syntax corpus #107)branch?(tree)
andchildren(tree)
, eventually make private?Additional considerations:
Some of this may be related to the
Access
work you've been doing. Can it be unified?The text was updated successfully, but these errors were encountered: