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

[Java] More fixes! #727

Merged
merged 16 commits into from
Dec 15, 2016
Merged

[Java] More fixes! #727

merged 16 commits into from
Dec 15, 2016

Conversation

djspiewak
Copy link
Contributor

@djspiewak djspiewak commented Dec 10, 2016

Lots of stuff. In no particular order:

  • Removed all of the lookbehind (updates Remove Incompatible Regex Patterns #481)
  • Added support for lambdas (I'm pretty sure anyway…)
  • Fixed scoping of ?, extends and super inside of generics
  • Removed a metric boatload of storage.type
  • Fixed some random punctuation scoping that was incorrect (including .)
  • Added kitchy invalid scoping on primitive-instantiated generics (it's pretty safe to say these will always be invalid, given how generics are implemented on the JVM)
  • Implemented full-state field declaration parsing

There's a bit of a question here though, and I don't know the answer. Specifically:

private String memberString = "Hello";

What should the scope of String be? Clearly, if we replace String with int, the answer is storage.type.primitive.java with some additional meta scoping for fun. But it's a lot less clear what we do if it's a non-primitive type.

The C++ mode says "no scoping at all", which is certainly a perspective I can rationalize. The Scala mode says either support.class.java or support.type.java (probably the former, since Java is super class-oriented). The strict reading of the scoping guidelines says storage.type.java.

Initially, I tried storage.type, but then I ran into the following signature:

private Map<Foo, Bar> map = null;

Should the storage.type just cover the Map? Or should it cover the whole type? Both look very weird. And what if the type contains a wildcard, resulting in some keyword.operator scoping in the middle of our storage.type? That doesn't make any sense.

By the same token, extending the Scala support.class/support.type regime to Java also has some problems. < is just a more syntactically heavyweight token than [, which means that Java's generics just seem more visually intrusive when the operators are not colored uniformly with the surrounding types. Or maybe I'm just used to reading Scala. Either way, it seems pretty darn weird.

I left the support.type and support.class scopes commented out, just so I can remember where they need to be rematerialized. For the time being, we're just going to go with the C++ mode's minimalist scoping, rather than Scala's rich (and complicated) scoping. Java types are a lot closer to C++ types (in terms of average complexity) than Scala types, so I think that's somewhat justifiable, even if it does make code look a little plain.

Anyway, I think the only remaining item for the Java mode is to fix annotations, which you could argue is pending a resolution on #709.


Disclaimer I do not use Java on a regular basis. Or at all, really. So unlike the Scala mode, I'm not dogfooding any of this. I'm happy to fix bugs and corner cases, but I'm probably not going to find them myself.

@keith-hall
Copy link
Collaborator

keith-hall commented Dec 10, 2016

With private Map<Foo, Bar> map = null;, I would personally apply a meta scope to the whole Map<Foo, Bar>, and scope Map, Foo and Bar separately as types, and give punctuation scopes to the <, , and >. I think this is how the C# PR does it.

@djspiewak
Copy link
Contributor Author

Would you scope them as support.class?

@djspiewak
Copy link
Contributor Author

Restored scoping and employed support.class and support.type.

Copy link
Member

@wbond wbond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for all of this work. This looks like it will be a nice step forward for the Java syntax!

I think most of the changes are missing scopes or some slight tweaks.

- match: '{{primitives}}'
scope: storage.type.primitive.java
set: instantiation-arrays
- match: '{{qualified_id}}'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this I'd like to use a look-ahead and them push into a scope where we match . as punctuation.accessor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed this in my initial scan of your review…

This would be a trickier change, since we're nesting {{qualified_id}} matches within other lookahead contexts (for field matching). It's not impossible, and I agree it's the right thing to do, it's just probably going to be very messy. If it's alright with you, I'd rather tilt that windmill in a separate PR, since it's going to require some deeper changes.

keywords:
- match: '::'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be either punctuation.accesor (that would be for more "color" consistency at the expense of semantic correctness), or keyword.operator for semantic correctness, correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think keyword.operator.method-reference might make sense. punctuation.accessor would also be sort of accurate. This is a deference operator which returns a pointer rather than invoking the method. I don't have a strong feeling about it, but I will say that my color scheme (which colors keyword.operator and not punctuation) makes the test example look nicer with a keyword-based scope than a punctuation one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From reading about this it seemed as though most authors considered it more of an operator, in that it transforms something, rather than a basic accessor. So let's go with keyword.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keyword.operator.method-reference.java it is!

Copy link
Collaborator

@FichteFoll FichteFoll Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I will say that my color scheme (which colors keyword.operator and not punctuation) makes the test example look nicer with a keyword-based scope than a punctuation one.

That's totally subjective though. I'm fine with my Python code not showing dots as blue (for keyword.operator).

Either way, this is apparently a discussion about whether or not accessors are in fact "operators". I vote for a keyword.operator.accessor scope for all of them, if we were to decide on them being operators.
By the way, semantically this has the same scope as dot access for attributes like this.field_name, but I don't think those are scoped as keyword.operator, are they?

If all these were punctuation.accessor.<character-identifier> (for example punctuation.accessor.double-colon), a color scheme could simply highlight all accessors that use two colons for some kind of member access with a simple selector.

Copy link
Contributor Author

@djspiewak djspiewak Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, semantically this has the same scope as dot access for attributes

It doesn't really though. The best analogue is honestly the -> vs . operators in C, except sort of inverted. The . operator in C directly accesses a member, while the -> operator dereferences a pointer and then accesses the member. The . operator in Java accesses a member function and applies it, while the :: operator accesses a member function and creates a pointer to it (without application).

foo::bar

In C syntax:

&(foo->bar)

In the C/C++ mode, both . and -> are given scope punctuation.accessor. In Java, . is (now) given punctuation.accessor while :: is given keyword.operator.method-reference. That's certainly a bit inconsistent.

By another perspective though, the :: operator in Java is analogous to the & operator in C (creating a pointer), which is scoped as keyword.operator.c.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both of you, and as you can see from my original comment I didn't have a strong opinion either way.

For consistency with other punctuation operators, including the :: in PHP, let's go with punctuation.accessor. That was my first instinct, however the docs I had been reading about it made it sound as if it was doing more. I think the visual consistency and style-ability wins here over pure semantic correctness. Kind of like how we scope docstrings in Python as comments because they are used as comments, but technically are just strings.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wbond I'll make the change. I preferred keyword.operator before we were scoping the identifier on the right (since it offered a strong visual distinction), but now that we're scoping the id, there's no real reason to avoid the punctuation scope.

Either way, I don't have much of a horse in the race since I don't use Java at all. :-D

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I certainly appreciate all of these fixes you are doing considering you never really use it!

- match: '::'
scope: keyword.control.method-reference.java
push:
- match: '{{id}}'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a scope we could add here that would be useful?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps variable.function?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, now that you confirmed this is for static references to methods, I believe that would be the correct scope.

@@ -270,8 +390,17 @@ contexts:
push:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a scope for the (?

@@ -270,8 +390,17 @@ contexts:
push:
- meta_scope: meta.method.identifier.java
- match: \)
scope: meta.method.identifier.java
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should add a punctuation scope for the ).

set:
- meta_scope: meta.generic.java
- match: '>'
scope: punctuation.definition.generic.end.java
pop: true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be including a context here to scope the types in the generic list?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most definitely. This is a bug.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, correction: it's already included on line 429. I was puzzled when I attempted to add a failing test and it passed. :-)

set: method-parameter-after
- match: ','
scope: punctuation.separator.java
- match: \)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a punctuation scope here

- match: '<'
scope: punctuation.definition.generic.begin.java
set:
- match: '>'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add meta.generic.java to this, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep

@djspiewak
Copy link
Contributor Author

@wbond I believe everything except the qualified_id bit is now addressed. As I said, due to the way this interacts with the other lookahead contexts, I would prefer to address that in another PR where I can fix some of the other structural issues with the mode.

@FichteFoll
Copy link
Collaborator

FichteFoll commented Dec 14, 2016

Note that #481 will be closed when this PR is merged becuase it includes "fixes #481" in the OP. I highly suggest editing that to read "updates #481" instead.

@djspiewak
Copy link
Contributor Author

@FichteFoll Done.

@djspiewak
Copy link
Contributor Author

@wbond Done. If you approve the deferral (to a subsequent PR) on the qualified_id issue, this should be good to go.

keywords:
- match: '::'
scope: punctuation.accessor.java
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind changing this to punctuation.accessor.double-colon.java?

- match: (?<=\S)\.(?=\S)
scope: keyword.operator.dereference.java
- match: \.
scope: punctuation.accessor.java
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this to punctuation.accessor.dot.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this seems like a reasonable idea @FichteFoll. I'll add it to the official guidelines, and then we can tweak existing syntaxes as they are worked on.

Copy link
Collaborator

@FichteFoll FichteFoll Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great. Some suggestions from my side.

. → dot
: → colon
:: → double-colon
-> → arrow
=> → fat-arrow ? (probably not used as an accessor anywhere but whatever)
\ → backslash (yes, Moonscript uses this...)

Copy link
Member

@wbond wbond Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PHP uses \ for namespace "accessor", in the way that C++ uses ::, although right now I believe in PHP it is scoped as a punctuation.separator.namespace.

I suppose it would make sense to standardize to accessor since most other syntaxes use accessor for namespace resolution.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, : is used by Lua. Anyway, we can probably continue any further conversation about this on a new issue rather than flooding this PR.

@djspiewak
Copy link
Contributor Author

@FichteFoll Revised to use dot and double-colon. I agree on your proposed guidelines, btw. Using the syntactic name for these operators rather than a language-specific semantic term seems the most sane.

@wbond wbond merged commit c5b019e into sublimehq:master Dec 15, 2016
@wbond
Copy link
Member

wbond commented Dec 15, 2016

Thanks!

@djspiewak djspiewak deleted the feature/java-fixes branch December 24, 2016 07:55
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

Successfully merging this pull request may close these issues.

4 participants