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

Annotations #977

Merged
merged 24 commits into from
Jun 27, 2022
Merged

Annotations #977

merged 24 commits into from
Jun 27, 2022

Conversation

lsk567
Copy link
Collaborator

@lsk567 lsk567 commented Feb 24, 2022

This is a pull request tracking the progress of an annotation system in LF (#756).

This PR extends the syntax to support "attributes," which has the form @<attrName>(<paramName1> = <paramValue1>, <paramName2> = <paramValue2>, ...). <paramName> is optional, though @oowekyala pointed out that it would be good to have named parameters to conform with Java annotation grammar.

As a proof of concept, the label mechanism is implemented using an @label attribute.

Example: Label.lf

target C {
    threads: 1,
    keepalive: true
};

@label(value="This is a controller.")
reactor Controller {
    
    output out:bool;
    
    @label("startup reaction")
    reaction(startup) -> out {==}
}

@label("This is a vision system.")
reactor Vision {
    @label("A timer")
    timer t;
    
    input _in:bool;
    output out:bool;
    state ramp_exists:bool(false);
    
    @label(value="Action") 
    logical action act;
    
    @label(value="Processing visual input")
    reaction(_in) -> out, act {==}
}

reactor Door {
    input _in:bool;
    state door:bool;
    
    reaction(_in) {==}
}

@label("Top-level reactor")
main reactor {
    
    controller  = new Controller();
    vision      = new Vision();
    door        = new Door();
    
    controller.out -> vision._in;
    vision.out -> door._in;
}

label

TODOs:

  • Address a Duplicate AttrParm 'name' issue.
  • Support a clean way to incorporate DSLs, such as logic, into attributes based on the attribute name.

if (list.length != 0)
commentText = list.get(0).getAttrParms.get(0).getValue.replaceAll("^\"|\"$", "")
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not sure how to resolve this code duplication... Xtend's support for polymorphism seems insufficient to avoid it.

@lhstrh lhstrh marked this pull request as ready for review June 18, 2022 00:26
@@ -55,6 +57,7 @@
import org.eclipse.xtext.validation.Check;
import org.eclipse.xtext.validation.CheckType;
import org.eclipse.xtext.validation.ValidationMessageAcceptor;
import org.jetbrains.annotations.NotNull;
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we want to introduce this dependency. It will break things for Eclipse users.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I build the eclipse product, and it looks like Epoch isn't broken by this dependency.

Copy link
Member

Choose a reason for hiding this comment

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

☝️

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

But it also seems like this can be safely removed.

Copy link
Member

Choose a reason for hiding this comment

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

How did you build Epoch? In Eclipse?

Copy link
Member

Choose a reason for hiding this comment

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

The point is not that it would break Epoch, it would prevent developers from building Epoch in Eclipse. This is because Eclipse doesn't use Maven or Gradle but it's own build system that is severely deprived from otherwise generally accessible dependencies like this one. We've run into this issue several times before...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Okay, got it...

/**
* Specification of the structure of an annotation.
*/
static class AttributeSpec {
Copy link
Member

Choose a reason for hiding this comment

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

This seems like a good candidate to factor out into its own file.

Copy link
Member

Choose a reason for hiding this comment

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

Everything until line 1296 could be moved there.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Factoring out seems a bit tricky, since check() (L1229) calls error(), which is a protected method inherited from AbstractDeclarativeValidator. We could move the check functions back to the validator class, but that would sort of invalidate the refactoring because most of the code is still in the validator class.

Copy link
Member

Choose a reason for hiding this comment

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

Could pass in a lambda?

Copy link
Collaborator

Choose a reason for hiding this comment

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

We can override the error function and just call super, this will make it visible

Copy link
Collaborator Author

@lsk567 lsk567 Jun 23, 2022

Choose a reason for hiding this comment

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

Works like magic. Thanks for the great advice.

Copy link
Member

@lhstrh lhstrh left a comment

Choose a reason for hiding this comment

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

Looks good! There is some code in the validator that still needs some attention.

@lhstrh
Copy link
Member

lhstrh commented Jun 18, 2022

Shall we punt on the DSLs in the interest of getting this merged in soon? They should be a proper extension, anyway, so this can be addressed at a later time.

/**
* Search for an `@label` annotation for a given reaction.
*
*
* @param n the reaction for which the label should be searched
* @return The annotated string if an `@label` annotation was found. `null` otherwise.
*/
public static String label(Reaction n) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

note that this overload could be removed if binary compatibility is not important, which seems likely.

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I didn't get this comment. What binary compatibility?

Copy link
Collaborator

Choose a reason for hiding this comment

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

If someone has compiled a class that depends on this method and we remove it, their class will break. Minor releases generally preserve binary compatibility. I'm not sure whether this java API is publicly supported since you've started public releases... If the only ide extensions that use the java API are in this repo then we can most likely remove it (we're also pre-1.0.0)

@lsk567 lsk567 requested a review from lhstrh June 23, 2022 05:19
Copy link
Member

@lhstrh lhstrh left a comment

Choose a reason for hiding this comment

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

Much better! Left some more comments/requests.

org.lflang/src/org/lflang/validation/LFValidator.java Outdated Show resolved Hide resolved
org.lflang/src/org/lflang/validation/LFValidator.java Outdated Show resolved Hide resolved
private static String USERNAME_REGEX = "^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\\$)$";

Copy link
Member

Choose a reason for hiding this comment

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

Lines 1743:1758 belong in the AttributeSpec class.

org.lflang/src/org/lflang/validation/AttributeSpec.java Outdated Show resolved Hide resolved
org.lflang/src/org/lflang/validation/AttributeSpec.java Outdated Show resolved Hide resolved
org.lflang/src/org/lflang/validation/AttributeSpec.java Outdated Show resolved Hide resolved
* so that it can be called from the AttributeSpec class.
*/
@Override
public void error(java.lang.String message,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Technically you can also leave it protected. Protected visibility is subclasses + current package, so it would be visible in AttributeSpec, which is in this package. This is a detail though

@lsk567 lsk567 requested a review from lhstrh June 23, 2022 20:42
@lsk567
Copy link
Collaborator Author

lsk567 commented Jun 24, 2022

The current Attribute syntax generates 2 warnings from Antlr.

warning(200): //home/runner/work/lingua-franca/lingua-franca/org.lflang/../org.lflang/srcgen/org/lflang/parser/antlr/internal/InternalLF.g:5661:3: Decision can match input such as "RULE_ID '-' RULE_ID '@' {RULE_ID, 'physical'}" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input

warning(200): //home/runner/work/lingua-franca/lingua-franca/org.lflang/../org.lflang.ide/srcgen/org/lflang/ide/contentassist/antlr/internal/InternalLF.g:13820:2: Decision can match input such as "RULE_ID '-' RULE_ID '@' {RULE_ID, 'physical'}" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input

It seems that the leading @ sign in the Attribute syntax is confusing the parser since @ is also used in IPV4Host, IPV6Host, and NamedHost. Changing @ to @@ in the Attribute syntax got rid of the warnings, which confirms the previous observation, but we need a cleaner solution.

Any thoughts on this? @lhstrh @oowekyala

@Soroosh129
Copy link
Contributor

Soroosh129 commented Jun 24, 2022

There are two possible solutions that come immediately to my mind:

  • Get rid of the at notation entirely and use attributes instead if needed
  • Change Host to just a string and check it in the validator

Under both solutions, IPV4Host, IPV6Host, and NamedHost are no longer needed.

@lhstrh
Copy link
Member

lhstrh commented Jun 24, 2022

Any thoughts on this? @lhstrh @oowekyala

The ambiguity comes from the "at" clause of an instantiation in combination with the annotations that can be featured inside of a reactor definition (i.e., above declarations of inputs, outputs, reactions, etc.).

Once the parser encounters something like x = new X() at foo followed by an @bar, its doesn't know whether the @bar should be part of the host or, instead, is an annotation of the subsequent declaration (such as a input y:baz).

@oowekyala
Copy link
Collaborator

@lhstrh is right. One solution would be to mandate a semicolon to terminate all declarations. I also like Soroush's idea to change Host back to a string, the productions are really complicated and anyway some checking is still done in the validator:

IPV6Addr:
// NOTE: This rule is too permissive by design.
// Further checking is done during validation.
// IPV6 with truncation.
'::' | ('::' (IPV6Seg (':'))* IPV6Seg) | ((IPV6Seg (':'|'::'))+ IPV6Seg?) |
// (Link-local IPv6 addresses with zone index) "fe80::7:8%1"
(ID '::' IPV6Seg (':' IPV6Seg)* '%' (INT | ID)+) |
// IPv4-mapped IPv6 addresses and IPv4-translated addresses
('::' IPV4Addr) | ('::' ID ':' (INT ':')? IPV4Addr) |
// IPv4-Embedded IPv6 Address
(((IPV6Seg (':' IPV6Seg)* '::') | (IPV6Seg (':' IPV6Seg)*) ':') IPV4Addr)
;

@Soroosh129
Copy link
Contributor

I personally think that an attribute instead of at is the more elegant solution. Where a federate resides I believe is an attribute anyway.

How about something like this:

@Host([email protected]:1000)
foo = new Foo($

and

@Host([email protected]:1000)
federated reactor {}

@lhstrh
Copy link
Member

lhstrh commented Jun 24, 2022

While I agree that using an annotation or surrounding the host with quotes might be better, I think that for this PR it's preferable to just require the semicolon in the offending production. I think we might want to more carefully evaluate the 'at' clause and its use before changing it. We can link this convo in a new issue.

@lhstrh
Copy link
Member

lhstrh commented Jun 24, 2022

I just want to emphasize that we don't need a semicolon on all declarations, just on instantiations that have an at clause. The impact of this change would be minimal.

@Soroosh129
Copy link
Contributor

just on instantiations that have an at clause.

That would be a bit weird.

I think we might want to more carefully evaluate the 'at' clause and its use before changing it.

I'm not proposing to change its meaning in this PR. Just how it can be declared. If we convert it to an attribute, then we can of course later still have a discussion about whether to keep it or change what it does.

*
* @throws IllegalArgumentException If the node cannot have attributes
*/
public static String findLabelAttribute(EObject node) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make sense if this was in a separate class like AttributeUtils? Same for other stuff here that relate to attributes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, I like this idea.

@lhstrh
Copy link
Member

lhstrh commented Jun 24, 2022

I just want to emphasize that we don't need a semicolon on all declarations, just on instantiations that have an at clause. The impact of this change would be minimal.

Concretely, my suggestion for a quick fix to the ambiguity problem is to replace the following line on LinguaFranca.xtext:233:

    ')' ('at' host=Host)? ';'?;

with

    ')' (('at' host=Host ';') | ';'?);

@lsk567
Copy link
Collaborator Author

lsk567 commented Jun 26, 2022

Looks like we are ready to go?

Copy link
Member

@lhstrh lhstrh left a comment

Choose a reason for hiding this comment

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

Looks good! Thanks for making all the requested changes :-)

@lhstrh lhstrh changed the title Attributes Attribute syntax Jun 27, 2022
@lhstrh lhstrh merged commit 292f812 into master Jun 27, 2022
@lhstrh lhstrh deleted the attribute branch June 27, 2022 19:23
@petervdonovan petervdonovan added enhancement Enhancement of existing feature language Related to the syntax and semantics of LF labels Jul 1, 2022
@lhstrh lhstrh added feature New feature and removed enhancement Enhancement of existing feature labels Jul 7, 2022
@lhstrh lhstrh changed the title Attribute syntax Annotations Jul 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature language Related to the syntax and semantics of LF
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants