Git Product home page Git Product logo

skript-parser's Introduction

skript-parser

What is Skript?

Skript is a Spigot plugin for Minecraft servers, created by Njol back in 2011. The aim of Skript has been to act as an easy hands-on solution for Minecraft server modification. Plugin development often requires a lot of time to learn and become proficient with Java, that is if you don't just pay someone else to do it for you. Skript code is interpreted from plaintext side, and can be loaded and reloaded on the fly in-game, without any need to compile and build.

Valid Skript code looks like this:

on right click on dirt:
    if the player is holding seeds:
        set the clicked block to grass
    else if the player is holding any mushroom:
        set the clicked block to mycelium

Even if you have never written a single line of code in your entire life, what this small script does should be very clear to you. Such is the Skript language's purpose. This is especially valuable in a Minecraft environment because Java is a notoriously verbose and bulky language to program in. However, the Skript plugin has some glaring flaws.

The problem with the Skript plugin

To put it bluntly, it's quite the mess. Skript was created by Njol as a small hobby project that grew massively thereafter. Unfortunately as more and more features were tacked on the existing ones, some general design issues persisted and even worsened. As it is, Skript is riddled with some bad programming design, such as, but not limited to, spaghetti code, inelegant control flow, a wasteful parsing process, and so on and so forth. It is also tightly-coupled with the Spigot API, meaning that not only can Skript only be used on a Minecraft server running Spigot, but it's very hard (and not really worth it, anyway) to remove all the Spigot-related elements from the codebase. This makes Skript's code essentially useless outside of a Spigot Minecraft server.

The aim of this project

The main aim is to provide a better, easier to understand and more flexible implementation of the Skript language. This implies, to a yet indeterminate extent, an overhaul of the API present in the Skript plugin. A standalone CLI implementation can be found at skript-cli. It works not only as a simple, bare-bones implementation of the language, but also as a proof-of-concept that demonstrates how this project's code can be repurposed for many different environments, not just Minecraft.

Repository structure

This repository currently contains two main branches :

  • master : this branch contains a proof-of-concept implementation of the parser, that compiles to an executable JAR file.
  • skript-library : this branch contains no implementations, and its purpose is to be used as a base library for any skript-parser-related projects.

Contributing

External contributions are extremely welcome, as I (Syst3ms, owner of the repository) and other contributors don't have enough time to contribute to the repository regularly. Adding features is obviously amazing, but smaller things such as cleaning up the code and adding documentation can go a long way for the project. If you want to start contributing, simply clone the Git repository and start working from here. I recommend using IntelliJ IDEA, it's my IDE of choice, and some annotations are only properly understood and handled by it.

skript-parser's People

Contributors

apickledwalrus avatar baefell avatar bensku avatar itsthesky avatar mwexim avatar nicofisi avatar olyno avatar romitou avatar skylyxx avatar syst3ms avatar thelimeglass avatar weeskybdw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

skript-parser's Issues

Bug: Multiple "#" on the same lines don't parse correctly

Hey! I just installed Skript-parser and tested it. I wanted to have a sample script to start, so I downloaded the one linked in this release note: https://github.com/SkriptLang/skript-parser/releases (https://gist.github.com/Blueyescat/8793eecf545088bf78007a18f19a2013)
(It generated multiple errors so I'll create an issue per error/problem)

Anyway, in this file there are lines full of "#" to delimitate a section I guess, but one of them is not parse correctly, I get the following error:

[18:53:39] ERROR: Conditionals are not allowed in this section (line 43: "", test.sk)

I also create an error on the next line:

[18:53:39] ERROR: An 'else if' must be placed after an 'if' (line 44: "", test.sk)

I think it will be worth mentioning the next line is neither an if nor an else if... Just a blank line.

All the other lines with plenty of "#" are parsed correctly and don't create errors.

About inline conditions

I just took a look at the (pretty old) inline conditions code.
For those who don't know, inline conditions are basically conditions that don't require indentation on the next line and they can be written as effects:

if 5 is more than 3:
    print "True!"
# Can be written as:
continue if 5 is more than 3
print "True!"

Now there are 2 core problems with this feature that need to be revisioned:

  1. The syntax itself is very cumbersome and almost 'too much' to write. The main thing is to consider using this over all those indented if-statements. This is of course debatable but should be considered at least (maybe by putting a low priority).
  2. There is this whole parsing for inline conditions using an InlineCondition class, which can just be done in a simple Effect class if I'm not mistaken. The implementation would be very similar to the current EffWait class, overriding the walk() method.

Maybe I'm overlooking something, but I think this was just something people 'forgot' about and therefore never optimized, but with the new API features this can be easily improved.

Gradle Actions

I think it would be useful to set up a GitHub action to build and provide a skript-parser artifact.

This could surely be useful to check everyone's commits and also for users who don't want to build themselves.

API Feature Proposal : Skript Lambda API

This document aims to present an API feature that would be desirable to have working in the foreseeable future : a Skript Lambda API. I will detail what such an API would allow to do, as well as specify a desired implementation, detailing each new class and its methods.

What for?

This API's purpose would be to grant API users an easy way to use lines of code as though they were simple lambdas/functions. Such an API would make potential features like functions, as well as any other feature based on some sort of functional programming (mapping and filtering operations, lazy sequences, etc), far easier to implement.

Specification description

Here I will detail my proposed implementation for the feature. That is, the classes that are added, the methods they have, how each one is meant to function, and how all features interact with one another.

  • Class SkriptFunction<S extends ReturnSection<T>, T>

    • Note that unlike classes like Function<F, T> or Consumer<T>, this class has state. The reason why should become clear later in this document.
    • Generic arguments :
      • S : the ReturnSection this function is based on
      • T : the return type of this function
    • Methods :
      • apply(TriggerContext, S, Object[]): T[]
        • Computes the result of this function, using a TriggerContext, the section this function is based on, and an array of arguments.
      • static create(FileSection, Class<? extends T>, boolean): SkriptFunction<S, T> :
        • Creates a SkriptFunction based on the given FileSection, a return type, and whether that return type is single or not.
        • Uses SkriptFunctionBuilder internally
      • static builder(FileSection, Class<? extends T>, boolean): SkriptFunctionBuilder<S, T>
        • Creates a SkriptFunctionBuilder with the provided parameters.
  • Class SkriptFunctionBuilder<S extends ReturnSection<T>, T> :

    • A builder object used to construct more complex SkriptFunctions.
    • Its generic arguments are the same as SkriptFunction's.
    • Constructors :
      • All constructors should be package-private, only to be accessed by SkriptFunction.builder.
    • Methods :
      • setStarterFunction(Function<S, Optional<? extends Statement>>) : SkriptFunctionBuilder<S, T>
        • Defines the "starter function" for this SkriptFunction. Its behavior is described below.
      • setStepFunction(BiFunction<S, Statement, Optional<T[]>>) : SkriptFunctionBuilder<S, T>
        • Defines the "step function" for this SkriptFunction. Its behavior is described below
      • setFinisherFunction(BiConsumer<S, Statement>) : SkriptFunctionBuilder<S, T>
        • Defines the "finisher function" for this SkriptFunction. Its behavior is described below.
      • build() : SkriptFunction<S, T>
        • Builds the SkriptFunction.

The purpose of the starter, step and finishing functions is to allow more complex behavior than just a simple function (i.e, in go arguments, out goes a return value using the return effect). When executing SkriptFunction#apply, they should behave as such :

  1. First, the starter function is ran with the S parameter as input. It should return an Optional describing the Statement starting point for this SkriptFunction, or an empty Optional if nothing should be run. By default, this should return the first element of the said section.
  2. Then, the function should walk along the lines of code. At every step, the statement that was just walked (not the result of walk() itself, what it was called on) and the scope sec are passed to the step function. This function should return an empty Optional if the execution is to continue, and otherwise an Optional containing the values to return. By default, this should return an empty optional if sec.getReturned() is empty, and if it isn't, return the result of sec.getReturned(). The getReturned function will be further described later, when describing the ReturnSection<T> and ArgumentSection classes
  3. Finally, just before returning, the finisher function is called with the scope and the next statement that would have been ran if execution continued, or null if there is no such statement. If the step function returned a nonempty Optional, this next statement would be the result of invoking walk() on the statement that was passed to the step function. By default, this shouldn't do anything.

After describing SkriptFunctions, with a return value, we shall discuss SkriptConsumers, without return values.

  • Class SkriptConsumer<S extends ArgumentSection>

    • Generic arguments :
      • S : the ArgumentSection this function is based on
    • Methods :
      • run(TriggerContext, S, Object[]): void
        • Runs this function, using a TriggerContext, the section this function is based on, and an array of arguments.
      • static create(FileSection): SkriptConsumer<S> :
        • Creates a SkriptConsumer based on the given FileSection.
        • Uses SkriptConsumerBuilder internally
      • static builder(FileSection): SkriptConsumerBuilder<S>
        • Creates a SkriptConsumerBuilder with the provided parameters.
  • Class SkriptConsumerBuilder<S extends ArgumentSection> :

    • A builder object used to construct more complex SkriptConsumers.
    • Its generic arguments are the same as SkriptConsumer's.
    • Constructors :
      • All constructors should be package-private, only to be accessed by SkriptConsumer.builder.
    • Methods :
      • setStarterFunction(Function<S, Optional<? extends Statement>>) : SkriptConsumerBuilder<S>
        • Defines the "starter function" for this SkriptConsumer. Its behavior is described below.
      • setStepFunction(BiPredicate<S, Statement>) : SkriptConsumerBuilder<S>
        • Defines the "step predicate" for this SkriptConsumer. Its behavior is described below
      • setFinisherFunction(BiConsumer<S, Statement>) : SkriptConsumerBuilder<S, T>
        • Defines the "finisher function" for this SkriptConsumer. Its behavior is described below.
      • build() : SkriptConsumer<S>
        • Builds the SkriptConsumer.

SkriptConsumer works in a similar manner to SkriptFunction, but differences are caused by the lack of a return value. When executing SkriptConsumer#run, the starter function and the step predicate should behave as such :

  1. The starter function works exactly like in SkriptFunction.
  2. Then, the function should walk along the lines of code. At every step, the statement that was just walked (not the result of walk() itself, what it was called on) and the scope sec are passed to the step predicate. If the predicate returns true, execution stops.
  3. Finally, the finisher function works just as in SkriptFunction as well.

Now, we will describe the ReturnSection<T> and ArgumentSection classes, used by the above two classes.

  • Abstract Class ArgumentSection extends CodeSection :

    • Methods :
      • getArguments() : Object[]
        • Returns an array of the arguments that this section provides. This should return the parameter of setArguments below. If setArguments isn't called, this should return an empty array.
      • setArguments(Object[]) : void
        • Sets the arguments that should be returned by getArguments(). This should be called on the section at the start of the execution of both SkriptFunction#apply and SkriptConsumer#run with the provided arguments parameter.
        • This may be package-private instead if it doesn't cause any issues.
  • Abstract Class ReturnSection<T> extends ArgumentSection:

    • Methods :
      • getReturned(): Optional<T[]>
        • Returns an Optional describing the values returned by the code inside the section. This should also return the result of setReturned below, wrapped in an Optional. If setReturned isn't called, this should return an empty Optional. By default, this is what should be called inside the step function of a SkriptFunction to see if values have been returned thus far.
      • setReturned(T[]) : void
        • Sets the returned values that should be returned by getReturned(). This should be called by the default implementation of EffReturn.
      • getReturnType() : Class<? extends T>
        • Returns the returned type of this section.
      • isSingle() : boolean
        • Returns the number of the values returned in this section.

The above two classes are just extensions of CodeSection that classes which want to use the functionality of SkriptFunction or SkriptConsumer must implement. ArgumentSection is used to carry argument information for use by syntaxes such as SectionValues ; it is used in both SkriptFunction and SkriptConsumer. ReturnSection extends ArgumentSection, but is specific to SkriptFunction. It carries information about the values returned by a given code block, and is made to be accessed by effects such as EffReturn.

We have now described all of the API that is to be implemented section-side. Now we will describe the API on the expression side. The working order of the API is predicated upon the proper interaction of these two sides.

  • Abstract Class SectionValue<S extends ArgumentSection, T> implements Expression<T>
    • Methods :
      • getSection() : Optional<? extends S>
        • Returns an Optional describing the section associated with this SectionValue ; akin to getOwner() of PropertyExpression.
      • setSection(S) : void
        • Sets the section associated with this Section value ; akin to setOwner() of PropertyExpression.
      • abstract getSectionValues(S, TriggerContext): T[]
        • Gets the values of this SectionValue, using the associated section as a parameter.
    • Implementation details :
      • This class should override getValues() in a way similar to PropertyExpression.

A SectionValue is an Expression that depends on a given section, either by exposing some info about the section itself in the form of an expression, or by representing arguments passed to either SkriptFunction#apply or SkriptConsumer#run in the form of an Object array.

Implementations of this class are expected to make full use of ArgumentSection#getArguments and of the new utility methods in Expression, described below :

  • static <S extends CodeSection> getMatchingSections(ParserState, Class<? extends S>) : List<? extends S>
    • Returns all of the current sections that are of the provided Class.
  • static <S extends CodeSection> getLinkedSection(ParserState, Class<? extends S>, TBD) : Optional<? extends S>
    • Returns the section of the given Class that should be linked to the calling syntax (note : obviously there's nothing forbidden about calling this method in other contexts, calling it inside SectionValue is simply the intended usage), according to the selector of a type TBD. We have thought of two potential solutions for this selector type :
      1. BiPredicate<? super S, Integer> : takes in the section to be tested as well as its index among the current matching sections (as per the ordering defined by ParserState#getCurrentSections). If this returns true, the section is used. This is a simple way to implement it, but it might prove too restrictive.
      2. Function<? super List<? extends S>, Optional<? extends S>> : takes in the list of all matching sections (in the previously described order), and returns an Optional describing the matching section, or an empty Optional if there is none. This is more complex, but more flexible as well.
  • static <S extends CodeSection> getLinkedSection(ParserState, Class<? extends S>) : Optional<? extends S>
    • Returns the section of the given Class that should be linked to the calling syntax. This should call getLinkedSection(ParserState, Class<? extends S>, TBD) in such a way that the first section is always picked regardless. For each possible type of the TBD argument, it can be done in the following ways, respectively :
      1. In the case of BiPredicate<? super S, Integer>, it should always return true.
      2. In the case of Function<? super List<? extends S>, Optional<? extends S>>, it should always return an Optional describing the first element of the list, or an empty Optional if the list is empty.
  • static checkFinishing(CodeSection, Predicate<? super Statement>, SkriptLogger, boolean) : boolean
    • Returns whether the code inside of the provided CodeSection always ends in a Statement matching the given Predicate. When the result is false, the provided logger should contain error messages describing the reason. The boolean parameter determines whether the logger should contain warnings about "unreachable code" or not. The primary use case for this method is checking whether a given section of code ends with a return (or otherwise halting) statement in every case.

Thank you for taking the time to read this suggestion.

[0.1.x] Syntax that needs to be implemented

I am creating this list for others to see which syntax should be implemented but isn't already. This is the syntax that's present in vanilla Skript, but not yet in the skript-parser project. All Minecraft-related syntax is obviously skipped.
Furthermore, I added a section for syntax that is not available in vanilla Skript, but could be useful to have in this project. All those syntaxes are subject-to-change and open for debate.
If you want to implement any of these syntaxes, just fork the project and make a pull request. You should always look at how Skript implements the given syntax, and then adapt it to this project. Note that almost every syntax in vanilla Skript is very old and unoptimised and that with the fantastic tools this project gives you, you can easily simplify the implementation.

Vanilla syntax

General

  • Line break expression (currently not necessary)
  • Script name expression (not high priority)
  • Shutdown effect
  • Filter expression
  • Map expression (map a function on a list of objects)
  • Loop N times section (just add this to current SecLoop file)

Dates

  • Formatted time expression
  • Time since expression -> duration since a given date

Strings

  • Hashed string expression
  • String is empty condition
  • Number of characters expression -> number of upper-/lowercase characters, see here
  • Replace all effect + expression (leave this one open please, updated one from 2.5 preferably)
  • Subtext expression

Lists

  • Indices of list expression -> see here
  • Reversed list, shuffled list, sorted list expressions
  • N random elements out of list expression (just add this to current ExprElement file)

New syntax

General

  • When something event
  • Escape effects (from SkQuery)
  • Wait while (from MundoSK, just add this to current EffWait file)

Classes

  • This would make the parse as expression possible
  • Class type (or Type<?> is also possible)
  • Parse as expression

Time

  • Time is basically the time in hours and minutes, like HH::mm (for example 16:34h or 11:13 PM)
  • Time type
  • Date to time converter
  • At time event

Strings

  • Character at index expression (from SkQuery)

Numbers

  • Is divisible and is prime conditions (from SkQuery)
  • Nth prime expression (from SkQuery, no priority)
  • Number conversion to roman numbers, hex, binary and others expressions

Future syntax

All the syntax below has no priority and should not be implemented unless the majority of above-defined syntaxes have been implemented. Discussion about these syntaxes below is appreciated and suggestions are welcome.

General

  • Switch/case sections (not certain)

Colors

  • Currently being worked on, so try to implement other syntaxes first.
  • Color support and parsing as HEX and default colours (like red, blue, yellow, green, ...)
  • Color support in strings (like "Normal <blue>Blue!. This would need some changes to how strings are parsed, but I have some ideas for this)
  • Hex to RGB and vice-versa expressions
  • RGB creation expression (I don't want parsing for this, just an expression)

Regex

  • Match condition
  • Regex replace, split, join and others expressions

Queue

  • Queues should not be a separate type, but rather a utility used with lists
  • Peak/Poll expressions/effects
  • Offer effect

If you have any suggestions or requests for changes, just leave a comment and I'll update this list as soon as possible. Everything, except the Vanilla syntax section, is very subject-to-change.
I hope this makes the current missing syntax elements clear as I wanted to list them here in favour of the recent road map that was created. This road map stated that it wanted to add all the missing syntax from Skript to this project in two months. We won't make the deadline (which is not a big deal), but at least new developers and contributors know how they can help this project out!

Issue when printing a VariableString

image

on skin init:
    set {_} to skin from username "bill"
    print "%skin from username ""%event-player%""%"
    set event-player's skin to {_}

The 2nd and 4th line work properly, but it appears skript-parser has a problem with the 3rd line, and I'm unsure how to solve it myself at the moment.

Regex containing square brackets kills regex pattern

When using <(\\d*1)st|(\\d*2)nd|(\\d*3)rd|(\\d*[4-90])th> The error printed was ERROR: Unmatched angle bracket (index 6) : '<(\d*1)st'
My guess is that the parser is not properly making it to the [4-90] due to the brackets thinking it's an optional. When it hasn't even closed the regex pattern yet with >

Test of expression "Today at" fail

👋
i was working on #119 (yes the PR isn't dead lol) and a new test error was throw to me by skript-parser. Test who throw the error is ExprDateTodayAt. After a bit of tests, it appear that it do this only between 0:00 and 1:00 (12am and 1am)

How to reproduct:
set your computer hour to 0:35 for example
run unit tests (gradlew test)

skript-parser version: from master branch
Java version: 11.8.0
Error:

SyntaxParserTest > syntaxTest() > expressions > io.github.syst3ms.skriptparser.parsing.SyntaxParserTest.syntaxTest()[2][26] FAILED
    java.lang.AssertionError: Days of {now} and {today} are not equal: 24 != 25 (respectively) (ExprDateTodayAt.txt)
        at io.github.syst3ms.skriptparser.syntax.EffAssert.lambda$execute$1(EffAssert.java:71)
        at java.base/java.util.Optional.ifPresent(Optional.java:183)
        at io.github.syst3ms.skriptparser.syntax.EffAssert.execute(EffAssert.java:71)
        at io.github.syst3ms.skriptparser.lang.Effect.run(Effect.java:14)
        at io.github.syst3ms.skriptparser.lang.Statement.walk(Statement.java:72)
        at io.github.syst3ms.skriptparser.lang.Statement.lambda$runAll$0(Statement.java:92)
        at java.base/java.util.Optional.flatMap(Optional.java:294)
        at io.github.syst3ms.skriptparser.lang.Statement.runAll(Statement.java:92)
        at io.github.syst3ms.skriptparser.TestAddon.finishedLoading(TestAddon.java:31)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
        at io.github.syst3ms.skriptparser.parsing.SyntaxParserTest.lambda$syntaxTest$4(SyntaxParserTest.java:62)

Edit: this seem to be a know bug, according to the test code. No way to fix that ?

Feature: CondExprAndOr (|| and && signs)

Type of Feature
Conditional Expression

Name
CondExprAndOr

Explanations
a conditional expression wich allow us to use || (or) and && (and) in a condition to make multiple conditions

Exemples
if {e} == 1 && {f} == 2 (if e is equal to 1 and f is equal to 2)
if {e} == 1 || {f} == 2 (if e is equal to 1 or f is equal to 2)

Attack Cooldown.

Add a way to get attack cooldown. E.G.:

on any move:
  set {_a} to player's attack cooldown
  send "§eCooldown: %{_a}%"

0 = not recharged, 1 = fully recharged.
And, if it is possible, allowing numbers greater than 1 would be cool too!
E.G.: 2 = fully charged 2 times.

Add unit tests

The project continues to move forward, with occasional pull requests that can potentially break code, and there is still NO test that hasn't been created.
So it would be important to create unit tests to test all the features and avoid breaking things.

Every syntax added (events, effects....) must have tests to avoid having problems with other syntaxes.

[bug] Or and And words don't make their jobs

Description

Recently I saw when working on #22 that the and and or operators didn't work correctly sometimes.

Expected

Should be false: true
Should be true: true
Should be false: false
Should be false: false
Should be true: true
Should be true: true
Should be true: false
Should be false: false

Code:

on script load:
    set {_x} to true and false
    print "Should be false: %{_x}%"
    set {_x} to true and true
    print "Should be true: %{_x}%"
    set {_x} to false and false
    print "Should be false: %{_x}%"
    set {_x} to false and true
    print "Should be false: %{_x}%"
    set {_x} to true or false
    print "Should be true: %{_x}%"
    set {_x} to true or true
    print "Should be true: %{_x}%"
    set {_x} to false or true
    print "Should be true: %{_x}%"
    set {_x} to false or false
    print "Should be false: %{_x}%"

It's good to note using operators as && instead of and it works perfectly. No errors, simply wrong results.

Optional List in SectionConfiguration throws NullPointerException

//SkriptEvent
private final SectionConfiguration configuration = new SectionConfiguration.Builder().addOptionalList("aliases").build();
@Override
public List<Statement> loadSection(FileSection section, ParserState parserState, SkriptLogger logger) {
	configuration.loadConfiguration(null, section, parserState, logger);
	Optional.ofNullable(configuration.getStringList("aliases")).ifPresent(list -> Arrays.stream(list).forEach(aliases -> this.aliases.add(aliases)));
	return configuration.getSection("trigger").getItems();
}

Then when calling:

@Override
public List<Statement> loadSection(FileSection section, ParserState parserState, SkriptLogger logger) {
	Optional.ofNullable(configuration.getStringList("aliases"))
       		.ifPresent(list -> Arrays.stream(list).forEach(aliases -> this.aliases.add(aliases)));
}
command /test:
	#aliases: no aliases node
	trigger:
		broadcast "testing"

Throws this:

[Server thread/ERROR] #!#! Caused by: java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "result" is null
[Server thread/ERROR] #!#!     at io.github.syst3ms.skriptparser.lang.entries.SectionConfiguration.getValue(SectionConfiguration.java:135)
[Server thread/ERROR] #!#!     at io.github.syst3ms.skriptparser.lang.entries.SectionConfiguration.getStringList(SectionConfiguration.java:145)

Issue with the #toString(Object...) while registering a new type.

To start off, this is probably my fault, but I could not find my error by any means, so here we go.

Recently, while registering a new type, doing as follows:

registration.newType(Guild.class, "guild", "guild@s")
				.toStringFunction(Guild::getName)
				.register();

I stumbled onto a weird issue. Whenever I do this in my scripts: "%<guild-object-here>%", it returns the string using the Object#toString() function, which is default when the #toStringFunction() is not specified. Here's the weird part: as you can see, I did specify it.

So I started looking around, seeing how things were handled. I tried both these methods to debug:
System.out.println(TypeManager.getByExactName("guild").getToStringFunction().apply(guilds.get(0))
System.out.println(TypeManager.toString(guilds.toArray()));
The first one returns the string by invoking the Guild#getName() method, which implies the registering worked.
But the second one (the one VariableString uses as well!) returns it by invoking the #toString() method.

Is this an issue or simply my error? Because the other types I registered in my addon were doing fine.

Error when write only "<" in a string

Skript-parser version: build from master branch
JDK version: 11.0.8

Problem: if we use a string with < as only character, skript-parser will try to parse it as an expression and not as a character.

Code for reproduct:

on script load:
	print "<"

How to bypass the bug: escape the character, like this -> \<

Naming Conventions

I was browsing the project the other day and noticed something. Since we apparently are going to expand this further, I think we should focus on consistency and naming as well.

Currently, Expressions and Effects follow the Syntax naming rule, for example ExprAmount and EffPrint. We should consider the following:

  • Events should use this convention as well, for example EvtScriptLoad. This is because that class REGISTERS event syntax.
  • Contexts on the other hand should stay the same, like Bukkit Events. This is because they hold INFORMATION about an event. You could do something like CtxScriptLoad, but I personally think the first is better.
  • Lastly, there is an argument to create a custom ‘sections’ package that registers all the sections. Currently, all sections are registered in the ‘lang’ package, but as we will add more sections (think of async and wait sections for example), this will clog that package imo with unnecessary files. We could move all sections to a new package except for the Condional class, because what they essentially do is REGISTER a section.
  • We could then add naming conventions for these as well, like SectWhile, but I don’t know if this is necessary. It may turn out better to keep consistency.

I’d like to make a sort of discussion about this and gather some opinions, before we actually start releasing new content.

about the readme

not really an issue here, but your preferred way of contact has you refusing attempts at contact

Future of skript-parser

Future of skript-parser

Overview

The skript-parser project was created to improve the current Skript parser.

Here is a simple roadmap to guide current and future contributors throughout the project

Based on the big spots of the initial Skript project (SkriptLang/Skript#121):

  • Sane addon API, and documentation for it.
  • Skript-to-JVM compiler, which generates classes from parsed scripts and possibly exports them
  • Optimized variable storage

With regard to this project directly:

  • Having a high-performance module system to extend the skript-parser
  • Being able to execute a script via a CLI
  • Have a more complex and efficient variable system with memory management.

Roadmap

Here is the proposed roadmap:

Duration Activity Releases
2 months Dev Work
Implement all existing Skript syntax that does not require Minecraft (example: amount of %objects%)
/
2 months Dev Work
Add a testing system like the current Skript project
/
2 months Dev Work
Create a CLI in order to execute scripts in an efficient way
0.1.0
1 month Quality & Stability
Fix parser & CLI issues
0.2.0
3 months Dev Work
Rework the system of variables to make it much more efficient
0.3.0
1 month Quality & Stability
Fix potential variables issues
0.4.0
4 months Dev Work
Having a high-performance module system to extend the skript-parser
0.5.0
1 month Quality & Stability
Fix potential modules system issues
0.6.0
2 months Quality & Stability
Full documentation
1.0.0
6 months Dev Work
Skript-to-JVM compiler
2.0.0
2 months Quality & Stability
Fix potential issues with JVM compiler
2.1.0

Total duration: planned on 26 months, September 2022

To note: All these dates are only approximate and may change depending on the speed of the project and its contributors. Please do not take them for granted, but only as a guide.

skript-parser projects

If we have projects created with the new parser, it will be easier to see our progress. Here are some interesting projects to do:

  • Web server: make a website with skript-parser
  • Desktop app: make a desktop app using GUI
  • Mobile app: make an android mobile app with skript-parser

To note: These are only project ideas. The goal is not to push them to the maximum but only to see the skills that skript-parser possesses.

Bug: Parser very commonly can't parse skript.

This seems more common on longer skripts. The skripts do usually eventually parse after a few reloads and whatnot, but its annoying to wait over a minute to parse and it decides to break.

Parse mark with groups doesn't work.

When using [:(example|something|else)] in a pattern and collecting with ParseContext#getMarks the marks return a list with index 0 as (example|something|else) and not the used pattern like example or something

Modularizing skript-parser

Roadmap to modularize skript-parser

1. Lexical modules

  • Lexical structure manipulation
    • Allow addons to hook into this process and change it
    • Possible rework of FileElement and FileSection
    • Rework comment parsing
    • Refactor/restructure this process to be more optimized and user-friendly (StructureParser?)

2. Registration modules

  • Annotation registrations?
    • Remove/rework SkriptRegistration class completely (as it is pure convenience either way)
  • Enum registrations
  • Overriding elements easily

3. Parsing and SyntaxElement modules

  • Control flow improvements
    • Rework of Finishing, SelfRegistrable and Continuable
    • Rework of ArgumentSections and iterative sections
    • Exiting function (perhaps instead of SelfRegistrable?)
  • Native Async support
    • AsyncEffect and AsyncSection, perhaps AsyncExpression
    • Rework all async events and effects to be safe, reliable and optimizable
  • Operators
    • Defined by context and type parameters (nothing else)
    • Overriding system to override certain contexts with other type parameters
    • Somehow link ContextValue and Operator functionality (although this is probably not necessary)
  • Pre- and post-parsing triggers (although this might take it too far)
    • Make a new parsing chain with priority queue (for example, when parsing an expression, first parse as a list, then as a variable, then as registered expression, then as context value)
    • Allow addons to hook into this system
  • Rework tags
    • Rework tag registration, parsing and matching/initialization completely
    • More customizability, while adding some sort of pattern to it.
    • Make them completely independent of VariableString and require a specific call to apply them.

New issue with optional groups in patterns

Note: I never had this issue before. It wasn't until the latest 2 commits (where there are changes to CompoundElement and PatternParser) that I encountered this issue.

When you create a pattern like login with [[the] token] %string%, using the following syntax in your scripts will yield different results:

  • login with "test" -> works fine
  • login with token "test" -> cant understand expression 'token "test"'

I removed the changes to CompoundElement (not the ones from PatternParser since they have nothing to do with it) and both syntaxes work fine.

Maybe consider an alternative solution to the problem. I never quite understood what was fixed in that file, stating that the commit fixed 'critical issues'.

Error with certain pattern syntax.

I just encountered this issue while creating a new effect. As far as I know, this is a parser issue that probably should get fixed.

I essentially created a new effect with the following syntax:
shutdown [[the] current bot]

When you use the following syntax in your scripts, apart from each other, you get a weird result.
shutdown the current bot
shutdown
The first one works fine, but the second one throws an IndexOutOfBoundException (because TextElement.java:41 uses String#charAt() with a wrong index).

I then changed the syntax to:
shutdown[ [the] current bot] (Note: the space now is optional as well)
This syntax worked fine for both usages. Normally, the parser handles whitespaces next to optional groups, but I think in this particular use-case, it did something wrong/skipped it, resulting in this.

A (possible?) side effect of the Optional API on numbers

I may be totally mistaking because I've never code a single Java line, but I saw that recently the Optional API was implemented.
When I tested this script, I saw this little problem that may be due to the optional API.

	set {x} to phi
	print "{x} = %{x}%"
	{x} += 3
	print "^ increased by 3: %{x}%"

The first part (setting x to phi) worked properly, with the decimals being limited to 10 (it printed {x} = 1.6180339887)
But the second part is a different story. The output is

^ increased by 3: Optional[4.61803398874989484820458683436563811772030917980576286213544862270526046281890244970720720418939113748475408807538689175212663386222353693179318006076672635443338908659593958290563832266131992829026788067520876689250171169620703222104321626954862629631361443814975870122034080588795445474924618569536486444924104432077134494704956584678850987433944221254487706647809158846074998871240076521705751797883416625624940758906970400028121042762177111777805315317141011704666599146697987317613560067087480710131795236894275219484353056783002287856997829778347845878228911097625003026961561700250464338243776486102838312683303724292675263116533924731671112115881863851331620384005222165791286675294654906811317159934323597349498509040947621322298101726107059611645629909816290555208524790352406020172799747175342777592778625619432082750513121815628551222480939471234145170223735805772786160086883829523045926478780178899219902707769038953219681986151437803149974110692608867429622675756052317277752035361393621076738937645560606059216589466759551900400555908950229530942312482355212212415444006470340565734797663972394949946584578873039623090375033993856210242369025138680414577995698122445747178034173126453220416397232134044449487302315417676893752103068737880344170093954409627955898678723209512426893557309704509595684401755519881921802064052905518934947592600734852282101088194644544222318891319294689622002]

First there are wayyyy to many decimals, and second I don't think I should see "Optional[]" part.

As I said this might not be related to the optional API, but it really seems to.

EDIT: I forgot to mention thatI'm using the latest nightly build of Skript-parser. I downloaded it here: https://github.com/SkriptLang/skript-parser/actions/runs/233965848
And I've just download the JDK (14.0.1 iirc), on macOS 10.15.6.

Way to make a sort of 'entry' + Validator for Elements

Hello!
With Skript v2, we got a useful object called SectionValidator, here to validate a bunch of Node (skript-parser consider them as Element if I'm not wrong)
We were able to test an entire SectionNode for the validator, and check for potential sections (same thing as here) and entries. Here's go my second point:
Entry would be such as condition, but followed by the string we want, example:

entryname: value

It could be used for deep configuration, such as (example):

define webserver: # A SkriptEvent
	port: XXX # Entry
	on request: # Section
		# </>

Defined by the SectionValidator:

new SectionValidator()
    .addEntry("port", false) // Optional ?
    .addSection("on request", false); // Optional ?

What do you think about that?

[0.2.x] Future version plans

It's a bit early, but since we're coming closer at implementing all necessary syntax, I wanted to make this issue to already discuss future version changes.

The road-map states that this version is mainly to fix bugs that would have appeared after 0.1. I'm going to add some things to that. Version 0.3 will probably change a lot, so that's why we have to prepare our development for that version in advance.

General

These contain some of the general plans that are kept for version 0.2. These plans are stationary and won't probably be moved to a later version since they're needed in order to ensure a better environment for contributors later on.

  • Operator system: @Syst3ms came up with this idea. Basically allows you to add certain operators bound to a context. When a certain context is called, the correct operator will be applied.
    • E.g. the plus-operator can now only be applied to numbers, but this overloading system would allow things like String concatenation and more.
  • String literals changes: the parsing of the current VariableString is very cumbersome, in a way that it doesn't allow things like double quotes inside the string and more. These limitations should probably be enhanced.
  • Improve Duration parsing and several other types.
  • SectionContext implementation
  • Better Converter and Comparator implementation.
  • Extended support for or-lists in conditions.
  • Wider implementation of tags. The current implementation is there as a placeholder, but it would be nice if we extended this feature more.
  • The start of a wiki. This wiki should not contain all information, but I think it's important we attract some new contributors (possibly from the main Skript project) and guide them through. This would give the development of this project a boost since it now is kind of falling apart again due to our own responsibilities in private life.
    The current issue with this as well is that all code reviewal relies on Systems. For syntax classes, this is debatable, since I and Olyno both have the knowledge to review and merge these PRs ourselves. But when it comes to entirely new features and utility classes, a review of Systems is often required. If we get more people in this project, this can maybe change.
  • (Extension of the CLI)

These changes will all lead up to version 0.3, where we'll change the whole variable system and possibly add a runtime error-management to the language. These features are currently in debate.

Comparator conditions (>, <, =) don't work

I just installed Skript-parser and tested it. I wanted to have a sample script to start, so I downloaded the one linked in this release note: https://github.com/SkriptLang/skript-parser/releases (https://gist.github.com/Blueyescat/8793eecf545088bf78007a18f19a2013)

I'm using the latest nightly build of Skript-parser. I downloaded it here: https://github.com/SkriptLang/skript-parser/actions/runs/233965848
And I've just download the JDK (14.0.1 iirc), on macOS 10.15.6.

The problem is in this code:

on script load:	
	set {_numbers::*} to 32.19, 11.81, 12 and 1.6
	loop {_numbers::*}:
		print "a: %loop-number%"
		if loop-number > 12:
			print "b: > 12"
			set {_text} to "adding to >12 list"
			add loop-number to {_>12::*}
		if loop-number < 12:
			print "c: < 12"
			set {_text} to "adding to <12 list"
			add loop-number to {_<12::*}
		if loop-number = 12:
			print "d: = 12"
		print "%loop-number%, greater than 12: %whether loop-value is greater than 12% (%{_text}%)"
	print "Numbers that is greater than 12: %{_>12::*}%"
	print "Numbers that is smaller than 12: %{_<12::*}%"
	remove {_>12::*} and {_<12::*} from {_numbers::*}
	print "Not both: %{_numbers::*}%"

The output is:

[19:31:32] ERROR: Conditionals are not allowed in this section (line 5: "if loop-number > 12", test.sk)
[19:31:32] ERROR: Conditionals are not allowed in this section (line 6: "print "b: > 12"", test.sk)
[19:31:32] ERROR: Conditionals are not allowed in this section (line 7: "set {_text} to "adding to >12 list"", test.sk)
a: 32.19
32.19, greater than 12: true (<empty>)
a: 11.81
11.81, greater than 12: false (<empty>)
a: 12
12, greater than 12: false (<empty>)
a: 1.6
1.6, greater than 12: false (<empty>)
Numbers that is greater than 12: <empty>
Numbers that is smaller than 12: <empty>
Not both: 32.19, 11.81, 12 and 1.6

As you can see it won't parse conditions, which results in an incorrect output...
It should definitely parse conditions here...

[enhancement] - Specials chars errors

Description

When using a syntax including special chars (e.g %boolean% || %boolean%) we need to put a \\ before each as %boolean% \\|\\| %boolean% else we get a ArrayBoundException.

Expected

Maybe add a specific error for that to be able to localize this kind of issue faster.

Bug: absolute value of exp not working properly

Hey! I just installed Skript-parser and tested it. I wanted to have a sample script to start, so I downloaded the one linked in this release note: https://github.com/SkriptLang/skript-parser/releases (https://gist.github.com/Blueyescat/8793eecf545088bf78007a18f19a2013)

This script generated the following errors:

[18:53:39] ERROR: No expression matching ''abs e' was found (line 15: "print "absolute of e = %abs e% (= %|e|%)"", test.sk)
[18:53:39] ERROR: No expression matching ''abs e' was found (line 16: "if abs e = |e|", test.sk)

The code is (lines 15, 16 and 17):

	print "absolute of e = %abs e% (= %|e|%)"
	if abs e = |e|:
		print "yeah 'abs e' = '|e|'"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.