Skip to content

Rewrite Custom Syntax#165

Open
UnderscoreTud wants to merge 56 commits into
2.xfrom
feature/custom-syntax-rewrite
Open

Rewrite Custom Syntax#165
UnderscoreTud wants to merge 56 commits into
2.xfrom
feature/custom-syntax-rewrite

Conversation

@UnderscoreTud

@UnderscoreTud UnderscoreTud commented Feb 6, 2026

Copy link
Copy Markdown
Member

Problem

The current custom syntax implementation is built on very old Skript API, when modifying syntax registries at runtime wasn't natively supported. This led to code relying on hacky methods and workarounds to achieve this type of behavior, as a byproduct, the codebase for this system was extremely hard to follow, fragmented and difficult to maintain.

Solution

Rewrite the custom syntax system from the ground up to use the registration API, significantly improving its readability, maintainability and consistency.

Testing Completed

Manual testing

Supporting Information

This rewrite should not introduce any user-facing breaking changes

Review Notice

If you are reviewing this pull request, I suggest starting from the org.skriptlang.reflect.syntax.custom.shared package, as everything is built on top of the base classes found there.


Completes: none
Related: none
AI assistance: none

# Conflicts:
#	build.gradle
#	src/main/java/com/btk5h/skriptmirror/ParseOrderWorkarounds.java
#	src/main/java/com/btk5h/skriptmirror/SkriptMirror.java
#	src/main/java/com/btk5h/skriptmirror/skript/custom/ExprExpression.java
#	src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseTags.java
#	src/main/java/com/btk5h/skriptmirror/skript/custom/ExprRawExpression.java
#	src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaCall.java
#	src/main/java/org/skriptlang/reflect/syntax/custom/event/EventValuesEntryData.java
#	src/main/java/org/skriptlang/reflect/syntax/custom/expression/ChangerEntryData.java
#	src/main/java/org/skriptlang/reflect/syntax/event/elements/CustomEvent.java
#	src/main/java/org/skriptlang/reflect/syntax/event/elements/EffCallEvent.java
#	src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprCustomEvent.java
#	src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprCustomEventValue.java
#	src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprEventData.java
#	src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprReplacedEventValue.java
#	src/main/java/org/skriptlang/reflect/syntax/event/elements/StructCustomEvent.java
#	src/main/java/org/skriptlang/reflect/syntax/expression/elements/ExprChangeValue.java
#	src/main/java/org/skriptlang/reflect/syntax/expression/elements/StructCustomExpression.java
@UnderscoreTud UnderscoreTud added the enhancement New feature or request label Feb 6, 2026

@sovdeeth sovdeeth left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I haven't looked through super closely but this seems fantastic from skimming it
No glaring issues (except the lack of docs annotations!)
origins and priorities should probably be handled automatically for the most part (may want to use an origin-applying registry)
The logic for the custom events looks great, good usage of ERS

@APickledWalrus APickledWalrus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Truly excellent work!

I'm going to ask that you add Documentation annotations for all of these elements. It would be nice to include skript-reflect on the new docs website 🙂

Side question: Shouldn't the new package be something like org.skriptlang.skriptreflect? (akin to org.skriptlang.skriptworldguard). I feel like the organization is a bit odd in general too. I think it might make sense to have a single subpackage like elements with further subpackages java, syntax, etc.

Comment thread src/main/java/com/btk5h/skriptmirror/ParseOrderWorkarounds.java
Comment thread src/main/java/com/btk5h/skriptmirror/SkriptMirror.java Outdated

@APickledWalrus APickledWalrus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks great. Just about ready!

...but docs 🥺

Comment thread src/main/java/org/skriptlang/reflect/syntax/custom/condition/CustomCondition.java Outdated
public static void register(SyntaxRegistry registry) {
registry.register(SyntaxRegistry.EXPRESSION, SyntaxInfo.Expression.builder(ExprParseTags.class, String.class)
.supplier(ExprParseTags::new)
.addPattern("[the] [parse[r]] tags")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
.addPattern("[the] [parse[r]] tags")
.addPattern("[the] [:parse[r]] tags")

Forgot this

return getNext();

Object locals = Variables.copyLocalVariables(effectEvent.getDirectEvent());
new Thread(() -> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What's this doing or what's the purpose?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

honestly not sure, i just ported it from the old custom effect logic. im guessing its a way to preserve local variables in async effects?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So this is to restore local variables for delays effects when re-starting the code after the effect call, but it ends up with a memory leak if the user never calls continue.

What we should do instead is store the localvariables in the EffectTriggerEvent and use Variables.withLocalVariables when walking next in setContinue

Variables.setLocalVariables(effectEvent.getDirectEvent(), locals);
} catch (InterruptedException ignored) {}
}).start();
return null;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Delayed effects do not ever run the code after them, if you don't continue. Is this intended? I think it should either have an implicit continue if it reaches the end without continue, or have an error of some sort.

> test-reflect
[19:20:57 INFO]: 1
[19:20:57 INFO]: a
[19:20:57 INFO]: b
effect run after this please:
    trigger:
        broadcast "a"
        delay the effect
        broadcast "b"

command test-reflecT:
    trigger:
        broadcast "1"
        run after this please
        broadcast "2"

return getNext();

Object locals = Variables.copyLocalVariables(effectEvent.getDirectEvent());
new Thread(() -> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So this is to restore local variables for delays effects when re-starting the code after the effect call, but it ends up with a memory leak if the user never calls continue.

What we should do instead is store the localvariables in the EffectTriggerEvent and use Variables.withLocalVariables when walking next in setContinue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants