From 6ffd67f23f70043613a06def4818fcd23c9c3848 Mon Sep 17 00:00:00 2001 From: JFronny Date: Fri, 15 Sep 2023 19:21:14 +0200 Subject: [PATCH] feat(muscript): Language versions --- .../gitlab/jfronny/muscript/StandardLib.java | 122 ++++++++++-------- .../jfronny/muscript/compiler/Lexer.java | 15 ++- .../muscript/compiler/MuScriptVersion.java | 11 ++ .../jfronny/muscript/compiler/Parser.java | 44 +++++-- .../muscript/compiler/VersionedComponent.java | 11 ++ 5 files changed, 139 insertions(+), 64 deletions(-) create mode 100644 muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/MuScriptVersion.java create mode 100644 muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/VersionedComponent.java diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/StandardLib.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/StandardLib.java index 27d5bb9..dea387c 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/StandardLib.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/StandardLib.java @@ -4,6 +4,7 @@ import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.ast.dynamic.Call; import io.gitlab.jfronny.muscript.ast.dynamic.Variable; import io.gitlab.jfronny.muscript.compiler.CodeLocation; +import io.gitlab.jfronny.muscript.compiler.MuScriptVersion; import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.*; import io.gitlab.jfronny.muscript.data.dynamic.additional.*; @@ -21,68 +22,83 @@ import static io.gitlab.jfronny.muscript.data.dynamic.additional.DFinal.of; public class StandardLib { private static final Random rnd = new Random(); + @Deprecated public static Scope createScope() { - return addTo(new Scope()); + return createScope(MuScriptVersion.DEFAULT); } + public static Scope createScope(MuScriptVersion version) { + return addTo(version, new Scope()); + } + + @Deprecated public static Scope addTo(Scope scope) { - return scope - .set("PI", Math.PI) - .set("E", Math.E) - .set("date", new DCallableObject(Map.of( - "today", new DDate(LocalDate::now) - ), DFinal.of(args -> { - // Constructor - if (args.size() == 1) return new DDate(() -> LocalDate.ofEpochDay(args.get(0).asNumber().getValue().longValue())); - if (args.size() != 3) throw new IllegalArgumentException("Expected 3 arguments for full date constructor"); - int a0 = args.get(0).asNumber().getValue().intValue(); - int a1 = args.get(1).asNumber().getValue().intValue(); - int a2 = args.get(2).asNumber().getValue().intValue(); - return new DDate(() -> LocalDate.of(a0, a1, a2)); - }, "date"))) - .set("time", new DCallableObject(Map.of( - "now", new DTime(LocalTime::now) - ), DFinal.of(args -> { - // Constructor - if (args.size() == 1) return new DTime(() -> LocalTime.ofSecondOfDay(args.get(0).asNumber().getValue().intValue())); - if (args.size() != 3) throw new IllegalArgumentException("Expected 3 arguments for full time constructor"); - int a0 = args.get(0).asNumber().getValue().intValue(); - int a1 = args.get(1).asNumber().getValue().intValue(); - int a2 = args.get(2).asNumber().getValue().intValue(); - return new DTime(() -> LocalTime.of(a0, a1, a2)); - }, "time"))) + return addTo(MuScriptVersion.DEFAULT, scope); + } - .set("round", StandardLib::round) - .set("floor", StandardLib::floor) - .set("ceil", StandardLib::ceil) - .set("abs", StandardLib::abs) - .set("random", StandardLib::random) + public static Scope addTo(MuScriptVersion version, Scope scope) { + if (version.contains(MuScriptVersion.V1)) { + scope + .set("PI", Math.PI) + .set("E", Math.E) + .set("date", new DCallableObject(Map.of( + "today", new DDate(LocalDate::now) + ), DFinal.of(args -> { + // Constructor + if (args.size() == 1) return new DDate(() -> LocalDate.ofEpochDay(args.get(0).asNumber().getValue().longValue())); + if (args.size() != 3) throw new IllegalArgumentException("Expected 3 arguments for full date constructor"); + int a0 = args.get(0).asNumber().getValue().intValue(); + int a1 = args.get(1).asNumber().getValue().intValue(); + int a2 = args.get(2).asNumber().getValue().intValue(); + return new DDate(() -> LocalDate.of(a0, a1, a2)); + }, "date"))) + .set("time", new DCallableObject(Map.of( + "now", new DTime(LocalTime::now) + ), DFinal.of(args -> { + // Constructor + if (args.size() == 1) return new DTime(() -> LocalTime.ofSecondOfDay(args.get(0).asNumber().getValue().intValue())); + if (args.size() != 3) throw new IllegalArgumentException("Expected 3 arguments for full time constructor"); + int a0 = args.get(0).asNumber().getValue().intValue(); + int a1 = args.get(1).asNumber().getValue().intValue(); + int a2 = args.get(2).asNumber().getValue().intValue(); + return new DTime(() -> LocalTime.of(a0, a1, a2)); + }, "time"))) - .set("toUpper", StandardLib::toUpper) - .set("toLower", StandardLib::toLower) - .set("contains", StandardLib::contains) - .set("replace", StandardLib::replace) + .set("round", StandardLib::round) + .set("floor", StandardLib::floor) + .set("ceil", StandardLib::ceil) + .set("abs", StandardLib::abs) + .set("random", StandardLib::random) - .set("listOf", StandardLib::listOf) - .set("len", StandardLib::len) - .set("isEmpty", StandardLib::isEmpty) - .set("concat", StandardLib::concat) - .set("filter", StandardLib::filter) - .set("allMatch", StandardLib::allMatch) - .set("anyMatch", StandardLib::anyMatch) - .set("map", StandardLib::map) - .set("flatMap", StandardLib::flatMap) - .set("fold", StandardLib::fold) - .set("forEach", StandardLib::forEach) - .set("toObject", StandardLib::toObject) + .set("toUpper", StandardLib::toUpper) + .set("toLower", StandardLib::toLower) + .set("contains", StandardLib::contains) + .set("replace", StandardLib::replace); + } + if (version.contains(MuScriptVersion.V2)) { + scope + .set("listOf", StandardLib::listOf) + .set("len", StandardLib::len) + .set("isEmpty", StandardLib::isEmpty) + .set("concat", StandardLib::concat) + .set("filter", StandardLib::filter) + .set("allMatch", StandardLib::allMatch) + .set("anyMatch", StandardLib::anyMatch) + .set("map", StandardLib::map) + .set("flatMap", StandardLib::flatMap) + .set("fold", StandardLib::fold) + .set("forEach", StandardLib::forEach) + .set("toObject", StandardLib::toObject) - .set("callableObject", StandardLib::callableObject) - .set("enum", StandardLib::enum_) - .set("keys", StandardLib::keys) - .set("values", StandardLib::values) + .set("callableObject", StandardLib::callableObject) + .set("enum", StandardLib::enum_) + .set("keys", StandardLib::keys) + .set("values", StandardLib::values) - .set("fail", StandardLib::fail) - .set("try", StandardLib::try_); + .set("fail", StandardLib::fail) + .set("try", StandardLib::try_); + } + return scope; } // Numbers diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Lexer.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Lexer.java index 7140b36..daca0e0 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Lexer.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Lexer.java @@ -5,7 +5,7 @@ import java.util.Set; import java.util.regex.Pattern; // Heavily inspired by starscript -public class Lexer { +public class Lexer extends VersionedComponent { public final String file; /** @@ -22,11 +22,22 @@ public class Lexer { public final String source; public int start, current; + @Deprecated public Lexer(String source) { - this(source, null); + this(MuScriptVersion.DEFAULT, source); } + @Deprecated public Lexer(String source, String file) { + this(MuScriptVersion.DEFAULT, source, file); + } + + public Lexer(MuScriptVersion version, String source) { + this(version, source, null); + } + + public Lexer(MuScriptVersion version, String source, String file) { + super(version); this.source = Objects.requireNonNull(source); this.file = file; } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/MuScriptVersion.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/MuScriptVersion.java new file mode 100644 index 0000000..1b0655d --- /dev/null +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/MuScriptVersion.java @@ -0,0 +1,11 @@ +package io.gitlab.jfronny.muscript.compiler; + +public enum MuScriptVersion { + V1, V2; + + public static final MuScriptVersion DEFAULT = V2; + + public boolean contains(MuScriptVersion version) { + return compareTo(version) >= 0; + } +} diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Parser.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Parser.java index 0f04a0a..1beadfb 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Parser.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Parser.java @@ -17,33 +17,58 @@ import org.jetbrains.annotations.Nullable; import java.util.*; -public class Parser { +public class Parser extends VersionedComponent { private final Lexer lexer; private final TokenData previous = new TokenData(); private final TokenData current = new TokenData(); + @Deprecated public static Expr parse(String source) { - return parse(source, null); + return parse(MuScriptVersion.DEFAULT, source); } + @Deprecated public static Expr parse(String source, String file) { - return new Parser(new Lexer(source, file)).parse().optimize(); + return parse(MuScriptVersion.DEFAULT, source, file); } + @Deprecated public static Script parseScript(String source) { - return parseScript(source, null); + return parseScript(MuScriptVersion.DEFAULT, source); } + @Deprecated public static Script parseScript(String source, String file) { - return new Parser(new Lexer(source, file)).parseScript().optimize(); + return parseScript(MuScriptVersion.DEFAULT, source, file); } + @Deprecated public static Script parseMultiScript(String startFile, SourceFS filesystem) { - return new Script(parseMultiScript(startFile, filesystem, new HashSet<>()).stream().flatMap(Script::stream).toList()); + return parseMultiScript(MuScriptVersion.DEFAULT, startFile, filesystem); } - private static List