The dot one is easy, I think we can have the outer meta be the meta of the call identifier. A PR is welcome.
For aliases, it is trickier, as you said. One alternative is to have something similar to [end: ...] that we have for constructs like do-blocks, so we can at least say where the whole alias extends to? WDYT? On Fri, Jun 4, 2021 at 6:00 PM i Dorgan <[email protected]> wrote: > Hi all, > > I'm writing a function that takes a quoted expression and calculates the > start and end positions of the node in the source code. So for example for > this expression: > > :"foo#{ > 2 > }bar" > > It would tell us that it starts at line: 1, column: 1 and ends at line: > 3, column: 6. The idea is that by knowing the boundaries of a node, a > refactoring tool can say things like "replace the code between these > positions with this other code". > > The issue I'm facing is that there are two cases where the AST does not > contain enough information to calculate those positions, the first one is > qualified identifiers: > > foo > . > bar > > which produces the ast: > > {{:., [line: 2, column: 1], > [ > {:foo, [line: 1, column: 1], nil}, > :bar > ]}, > [no_parens: true, line: 2, column: 1], []} > > Note that we don't have any information about the location of :bar, only > for the dot. This makes it impossible to accurately calculate the ending > location for the expression, and we are forced to assume :bar is at the > same line as the dot. > > The second case happens with aliases: > > Foo. > Bar > .Baz > > produces: > > {:__aliases__, [line: 1, column: 1], [:Foo, :Bar, :Baz]} > > Here we have even less information, we know nothing about dots or segments > location, and we are forced to assume everything happens at the same line. > > I looked into the parser and this information is being discarded in the > build_dot function for qualified identifiers and in build_dot_alias for > aliases. > > My proposal is to keep that information in the ast metadata instead of > discarding it when the :token_metadata option is true, similarly to how > it is done with do/end, closing and end_of_expression. > > The quoted form of the first example would be something like this: > > {{:., > [ > identifier_location: [line: 3, column: 1], > line: 2, > column: 1 > ], > [ > {:foo, [line: 1, column: 1], nil}, > :bar > ]}, > [no_parens: true, line: 2, column: 1], []} > > For the aliases it would be a bit more involved, because there are two > kind of locations that would need to be preserved: dots and segments. I've > considered something like this to keep only the segments: > > {:__aliases__, > [ > line: 1, > column: 1, > alias_segments: [ > [token: :Foo, line: 1, column: 1], > [token: :Bar, line: 2, column: 1], > [token: :Baz, line: 4, column: 1] > ] > ], [:Foo, :Bar, :Baz]} > > I already have a working version, so I will gladly submit a PR if you > consider this to be viable. I'm still unsure on how to tackle the dots > positions in a meaningful way. While just knowing the segments positions is > enough for my use cases, I figure dot positions may also need to be > preserved for the sake of completeness. > > I'd like to know your thoughts! > > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/815d3113-dae6-4e99-8427-a873a704c4aan%40googlegroups.com > <https://groups.google.com/d/msgid/elixir-lang-core/815d3113-dae6-4e99-8427-a873a704c4aan%40googlegroups.com?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2BXT2%3DdngBh5u7GtEY5-Hvs9UUJeUr0DnXFN7uVjoph0Q%40mail.gmail.com.
