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

Meta-syntax and annotations. #6571

Draft
wants to merge 11 commits into
base: dev/feature
Choose a base branch
from

Conversation

Moderocky
Copy link
Member

Summary

This defines the concept of syntax that only affects other syntax (rather than actually having its own function.)
This also adds an 'annotation': a metadata note visible at parse-time to the upcoming line of code.

(Drafted based on this internal discussion.)

Meta-syntax

This adds an interface for meta-syntax elements.

Meta syntax is syntax that (only) affects other syntax, (e.g. things that do something at parsing time, syntax that modifies another syntax inside it, etc.) but doesn't really do anything by itself.
We don't really have many examples in Skript right now: we usually prefer to add optional flag patterns to the end of syntax [with [my cool option[s]]].
You could say that a lot of entries in structures are meta-syntax since they're modifying what the structure is doing rather than actually doing something on their own.

Meta-syntax can be a powerful tool, for example:

  • To break a long, complex pattern into two lines: a real effect and a meta-effect.
  • To toggle some special parse-time feature.
  • To allow granular control of an element without needing a clumsy, long pattern for each case.

Annotations

Annotations are a kind of meta-syntax, they don't do anything functional by themselves at all (they're basically a comment) but they're also visible to upcoming code, which might do something special based on them.

In most languages that have the concept, annotations are used to include metadata for self-reflection, compiler (parsing/interpreting in our case) instructions, debugging and the like.

Annotation Format

Annotations start with the @ character (similar to Java). I felt that having some character was important to help users differentiate them from code (in the same way that # marks the beginning of a comment). As annotations are essentially a (visible) comment, it makes sense that they're quite similar.

@suppress warnings
@case sensitive variables
broadcast "hello!"

There's no verification or rules for what follows the @: it won't error if a user writes something random (@foo bar), but it won't have any impact either. I decided to be very relaxed about verification and leave it up to the thing that requires the annotation.

@foo bar fake annotation
@this is essentially a glorified comment
broadcast "hello!"

Annotation Placement

An @annotation is a piece of metadata attached to code. By itself, it does nothing. There are no errors or penalties for writing a bogus or unknown annotation (in this case it acts like a comment does).

An annotation is visible to (and only to) the line of code it is placed before:

on event:
    @my cool annotation
    my annotated effect # sees '@my cool annotation'

If multiple annotations are placed before a line of code then all will be visible to that line.

on event:
    @my cool annotation
    @another annotation
    my annotated effect # sees both '@my cool annotation' and '@another annotation'

Annotations are visible to every element within the line, and are discarded after the line has been parsed.

on event:
    @my cool annotation
    my annotated effect # sees '@my cool annotation'
    my not-so-annotated effect # sees nothing :(

Annotations placed on a section header line are visible only to the section header.

@something
if {foo} is true: # sees '@something'
    broadcast "A" # sees nothing :(
broadcast "B" # sees nothing :(

Annotations placed at the root level before a structure are visible only in that structure's initialisation.
Entries (like triggers) are typically handled in the structure's load method, so a structure would have to keep a copy of annotations and make them available here if intended.
Annotations don't have native support at the entry-level (since the definition of entries depends entirely on the structure).

@some annotation
command /test: # sees '@some annotation'
    trigger:
        ... # we can't see '@some annotation' here

It is up to elements within a line how to (or whether to) interact with annotations. Some may have a global effect on any syntax (e. g. suppressing a warning, changing parsing order) whereas others might be relevant ONLY to one syntax.

Annotation-checking API

Most annotation usage will simply be checking is-present.
Annotations can be checked from the parser instance.
They can be checked for presence by:

  • Instance (this probably isn't useful externally): parserInstance.hasAnnotation(annotation)
  • Exact content (text): parserInstance.hasAnnotation(text)
  • Skript pattern matching (text): parserInstance.hasAnnotationMatching(pattern)
  • Skript pattern matching (compiled pattern): parserInstance.hasAnnotationMatching(pattern)

Annotation instances can also be fetched by pattern.
This is useful if an annotation is designed to include some kind of data input. This uses skript pattern matching.
In this case, the pattern match result AND the annotation instance are returned together as a Match if present.

Any matching annotation can be fetched with parserInstance.getAnnotationMatching(text/pattern), which returns a nullable match.

All matching annotations can be fetched with parserInstance.getAnnotationsMatching(text/pattern), which returns a non-null array of (potentially zero) non-null matches.

Example Use-cases

  • Suppressing warnings/errors
    This is actually included in this PR as a test dummy currently,
    I don't know if it'll stay in after draft, it should probably be more comprehensive.
  • Providing parse-time type hints (e.g. set {x} to snowball - item? entity type? event entity?)
  • Parse-time syntax hints (e.g. specifying what a line ought to match if there's some weird parser ambiguity?)
  • Switching variable case sensitivity mode
  • Function signature hints
  • Weird edge cases for syntax that exceed normal behaviour
  • Addons (e.g. skript-reflect type hints?)

We don't intend this to be overused -- it should be kept for cases where it's unreasonable (or somehow bad) to build in regular support for something, or where it should be a meta-control toggle rather than a real syntax.


Target Minecraft Versions: any
Requirements: none
Related Issues: requires #6551

@AyhamAl-Ali AyhamAl-Ali added the feature Pull request adding a new feature. label Apr 15, 2024
@sovdeeth
Copy link
Member

sovdeeth commented Apr 15, 2024

In regards to only the sections/structures seeing their annotations and their contents being blind to them, I think it would be nice to provide a standard way to access the annotations of a parent section/structure, so you can suppress warnings in a block instead of on every line that needs it.

@TheLimeGlass
Copy link
Collaborator

TheLimeGlass commented Apr 15, 2024

I like annotations, but the meta syntax is Essentially a WrapperExpression. See that class for reference. I don't want to add two variants of the same functionality, unless it does more than modify expressions inside the pattern.

@Moderocky
Copy link
Member Author

I think it would be nice to provide a standard way to access the annotations of a parent section/structure

This can probably done by attaching it to the context, but I don't really know enough about what the sectioncontext is/does to do that reliably myself. I'll wait for Walrus's input.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Pull request adding a new feature.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants