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

Location doesn't handle multiline nodes #36

Closed
Jozott00 opened this issue Sep 12, 2022 · 13 comments
Closed

Location doesn't handle multiline nodes #36

Jozott00 opened this issue Sep 12, 2022 · 13 comments
Assignees

Comments

@Jozott00
Copy link
Collaborator

Jozott00 commented Sep 12, 2022

class A {}

class A {}

class A {
}

This code results in the following error message:

-- CompileError ----------------------------------------------------------------

  4| class A {}
     ^^^^^^^^^^

Class `A` was already defined.
-- CompileError ----------------------------------------------------------------

  6| class A {
     ^

Class `A` was already defined.

As you can see, the first error, the class definition is completely marked (as it should be) since it is a one-liner, but in the second error message only the first letter is marked.

This problem holds for all multiline expressions.

@flofriday
Copy link
Owner

True this is just a missing feature in CompileError. It already has the full location but does not really know how to render them.

@Jozott00
Copy link
Collaborator Author

Ok nice!

I added some methods to Location and Token, so we can merge via method calls.

someTokenOrLocation.mergeLocations(otherTokenOrLocation)

@flofriday
Copy link
Owner

flofriday commented Sep 12, 2022 via email

@Jozott00
Copy link
Collaborator Author

The merge logic is bundled in mergeLocations(_, _) but I find the object oriented approach much cleaner than calling a global function.

@Jozott00

This comment was marked as outdated.

@Jozott00
Copy link
Collaborator Author

Jozott00 commented Sep 12, 2022

I found a mistake in the mergeLocation function:

    // Lets assume b is the last one
    var endCol = b.endCol

    // Now check if we made another mistake
    if (a.line > b.line) || (a.line == b.line && a.endLine > b.endLine) {
        endCol = a.endCol
    }

The correct condition would be

if (a.endLine > b.endLine) || (a.endLine == b.endLine && a.endCol > b.endCol) {

However I would suggest that we take advantage of the swift tuple comparison to implement the logic:

    // Lets assume a is the first one
    var col = a.col

    // Now check if we made a mistake and if so lets correct for it
    if (b.line, b.col) < (a.line, a.col) {
        col = b.col
    }

    // Lets assume b is the last one
    var endCol = b.endCol

    // Now check if we made another mistake
    if (b.endLine, b.endCol) < (a.endLine, a.endCol) {
        endCol = a.endCol
    }

Is it ok for you if I use the second implementation? I think it is easier to understand

@flofriday
Copy link
Owner

Sure go ahead, could you also add some unit tests?

@flofriday
Copy link
Owner

Ok I will work on this now.

@flofriday
Copy link
Owner

Ok nice!

I added some methods to Location and Token, so we can merge via method calls.

someTokenOrLocation.mergeLocations(otherTokenOrLocation)

I actually think it might be preferable to have many constructors of location which take tokens and other locations and merge them. Since it is a natural way to create new Locations by merging two existing ones.

@flofriday
Copy link
Owner

Also I now have implemented multiline error highlighting, however I think that this issue should stay open since we should aim to not highlight the whole class but probably only the class keyword and the name:

-- CompileError ----------------------------------------------------------------

   |
  4| class A {}
   | ^^^^^^^
     
Class `A` was already defined.

This would make the error message much shorter, easier to read without loosing any meaningful information.

@Jozott00
Copy link
Collaborator Author

Yes, this is done by the parser by using not the closing bracket as second location mergepoint but the first one.
In any case we could limit the printed code inside the error to one line with an ending ... in case their are more then one line.

@flofriday
Copy link
Owner

Well I thought that in the typechecker we could create another error method that takes a a location instead of an AST node or token. And in special cases like this we could create a special location of the thing we want to highlight. Like in this case we could merge the class token of the keyword and the name and send this to the error.

@flofriday
Copy link
Owner

image

On class redefinition we will now only print the relevant part of the class, and ignore the body since it doesn't matter here.

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

No branches or pull requests

2 participants