enso-org / enso

Hybrid visual and textual functional programming.
https://ensoanalytics.com
Apache License 2.0
7.36k stars 323 forks source link

Curried chained method calls no longer work #301

Closed kustosz closed 5 years ago

kustosz commented 6 years ago

Please ensure that you are running the latest version of Luna before reporting the bug! It may have been fixed since.

General Summary

In the 1.5 version of Luna (new parser) expressions like .foo.bar do not work properly, rendering most of my projects unusable. Expressions like [1,2,3].each .succ.pred parse to something like [1,2,3].each (.succ).pred, which results in type errors. This is a new behavior since 1.4 where things worked properly.

Steps to Reproduce

Use an expression like [1,2,3].each .succ.pred. Results in type error about not being able to call a method on a function. Pretty printer shows it as [1,2,3].each (.succ . pred), instead of [1,2,3].each .succ.pred how it used to be in 1.4.

Expected Result

Same behavior as 1.4

Actual Result

Broken semantics

Luna Version

1.5

wdanilo commented 6 years ago

Description This is a complex issue. The real solution should be implemented in passes, probably in desugaring, as this situation is very similar to wildcard handling.

The old approach The old parser translates a .foo.bar to application between Var "a" and AccSection ["foo", "bar"], a core constructor of form AccSection { path :: Vec16 Name }. The constructor is deprecated, as it supports only named sections and discards information about code spans. We want to support code like foo (. bar 1 . baz), so we cannot assume the sections are always names. Moreover, we should not have a special construction in AST if we can express exactly the same information using existing constructions.

The current results The result we get right now are 100% correct. The code a .foo.bar generates the following AST:

App
    (Var "a")
    (InfixApp
        (SectionRight (Operator ".") (Var "foo"))
        (Operator ".")
        (Var "bar")) :|
    []

The AST is correct and until we think about dots like about a very special syntax, not just regular operators, this is the expected output.

Possible solutions

We've got 3 solutions available here:

  1. We could consider dot to be a very special syntax, not a regular operator anymore and such cases would generate a new type of core, like AccSection { path :: LinksTo Terms }. IMO this is wrong because of few reasons:

    1. It adds very special cases to operator handling.
    2. It is relatively complex and time consuming to implement.
    3. It adds a new core constructor. Moreover, this constructor is just a special case for what is expressable without it. In fact, it just makes some constructions never appear, so this is clearly bad.
  2. As this AST structure is completely correct, it should be handled in passes (probably in the desugaring pass). The answer if we should go this way depends on how hard would it be to implement. Other than possible high time requirements (to be confirmed) it does not has any disadvantages.

  3. Making hack to current parser implementation. After parsing we can traverse the whole AST searching for this AST structure pattern and translate it to the old, obsolete approach. It would require approx 1 day to be implemented (either mine or @mikusp as he already knows the code of AST -> IR translator), but it's also ugly as hell as it requires manual code spans merging and it's a very short term solution. I'm afraid we don't have the choice here and we need to implement it this way.

piotrMocz commented 6 years ago

Works ok ;)