feat(muscript): Language versions
This commit is contained in:
parent
e84f8adc88
commit
6ffd67f23f
@ -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.Call;
|
||||||
import io.gitlab.jfronny.muscript.ast.dynamic.Variable;
|
import io.gitlab.jfronny.muscript.ast.dynamic.Variable;
|
||||||
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
|
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.Scope;
|
||||||
import io.gitlab.jfronny.muscript.data.dynamic.*;
|
import io.gitlab.jfronny.muscript.data.dynamic.*;
|
||||||
import io.gitlab.jfronny.muscript.data.dynamic.additional.*;
|
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 {
|
public class StandardLib {
|
||||||
private static final Random rnd = new Random();
|
private static final Random rnd = new Random();
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static Scope createScope() {
|
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) {
|
public static Scope addTo(Scope scope) {
|
||||||
return scope
|
return addTo(MuScriptVersion.DEFAULT, 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("round", StandardLib::round)
|
public static Scope addTo(MuScriptVersion version, Scope scope) {
|
||||||
.set("floor", StandardLib::floor)
|
if (version.contains(MuScriptVersion.V1)) {
|
||||||
.set("ceil", StandardLib::ceil)
|
scope
|
||||||
.set("abs", StandardLib::abs)
|
.set("PI", Math.PI)
|
||||||
.set("random", StandardLib::random)
|
.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("round", StandardLib::round)
|
||||||
.set("toLower", StandardLib::toLower)
|
.set("floor", StandardLib::floor)
|
||||||
.set("contains", StandardLib::contains)
|
.set("ceil", StandardLib::ceil)
|
||||||
.set("replace", StandardLib::replace)
|
.set("abs", StandardLib::abs)
|
||||||
|
.set("random", StandardLib::random)
|
||||||
|
|
||||||
.set("listOf", StandardLib::listOf)
|
.set("toUpper", StandardLib::toUpper)
|
||||||
.set("len", StandardLib::len)
|
.set("toLower", StandardLib::toLower)
|
||||||
.set("isEmpty", StandardLib::isEmpty)
|
.set("contains", StandardLib::contains)
|
||||||
.set("concat", StandardLib::concat)
|
.set("replace", StandardLib::replace);
|
||||||
.set("filter", StandardLib::filter)
|
}
|
||||||
.set("allMatch", StandardLib::allMatch)
|
if (version.contains(MuScriptVersion.V2)) {
|
||||||
.set("anyMatch", StandardLib::anyMatch)
|
scope
|
||||||
.set("map", StandardLib::map)
|
.set("listOf", StandardLib::listOf)
|
||||||
.set("flatMap", StandardLib::flatMap)
|
.set("len", StandardLib::len)
|
||||||
.set("fold", StandardLib::fold)
|
.set("isEmpty", StandardLib::isEmpty)
|
||||||
.set("forEach", StandardLib::forEach)
|
.set("concat", StandardLib::concat)
|
||||||
.set("toObject", StandardLib::toObject)
|
.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("callableObject", StandardLib::callableObject)
|
||||||
.set("enum", StandardLib::enum_)
|
.set("enum", StandardLib::enum_)
|
||||||
.set("keys", StandardLib::keys)
|
.set("keys", StandardLib::keys)
|
||||||
.set("values", StandardLib::values)
|
.set("values", StandardLib::values)
|
||||||
|
|
||||||
.set("fail", StandardLib::fail)
|
.set("fail", StandardLib::fail)
|
||||||
.set("try", StandardLib::try_);
|
.set("try", StandardLib::try_);
|
||||||
|
}
|
||||||
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Numbers
|
// Numbers
|
||||||
|
@ -5,7 +5,7 @@ import java.util.Set;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
// Heavily inspired by starscript
|
// Heavily inspired by starscript
|
||||||
public class Lexer {
|
public class Lexer extends VersionedComponent {
|
||||||
public final String file;
|
public final String file;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,11 +22,22 @@ public class Lexer {
|
|||||||
public final String source;
|
public final String source;
|
||||||
public int start, current;
|
public int start, current;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public Lexer(String source) {
|
public Lexer(String source) {
|
||||||
this(source, null);
|
this(MuScriptVersion.DEFAULT, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public Lexer(String source, String file) {
|
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.source = Objects.requireNonNull(source);
|
||||||
this.file = file;
|
this.file = file;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -17,33 +17,58 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class Parser {
|
public class Parser extends VersionedComponent {
|
||||||
private final Lexer lexer;
|
private final Lexer lexer;
|
||||||
|
|
||||||
private final TokenData previous = new TokenData();
|
private final TokenData previous = new TokenData();
|
||||||
private final TokenData current = new TokenData();
|
private final TokenData current = new TokenData();
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static Expr<?> parse(String source) {
|
public static Expr<?> parse(String source) {
|
||||||
return parse(source, null);
|
return parse(MuScriptVersion.DEFAULT, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static Expr<?> parse(String source, String file) {
|
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) {
|
public static Script parseScript(String source) {
|
||||||
return parseScript(source, null);
|
return parseScript(MuScriptVersion.DEFAULT, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static Script parseScript(String source, String file) {
|
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) {
|
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<Script> parseMultiScript(String startFile, SourceFS filesystem, Set<String> alreadyIncluded) {
|
public static Expr<?> parse(MuScriptVersion version, String source) {
|
||||||
|
return parse(version, source, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Expr<?> parse(MuScriptVersion version, String source, String file) {
|
||||||
|
return new Parser(new Lexer(version, source, file)).parse().optimize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Script parseScript(MuScriptVersion version, String source) {
|
||||||
|
return parseScript(version, source, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Script parseScript(MuScriptVersion version, String source, String file) {
|
||||||
|
return new Parser(new Lexer(version, source, file)).parseScript().optimize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Script parseMultiScript(MuScriptVersion version, String startFile, SourceFS filesystem) {
|
||||||
|
return new Script(parseMultiScript(version, startFile, filesystem, new HashSet<>()).stream().flatMap(Script::stream).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Script> parseMultiScript(MuScriptVersion version, String startFile, SourceFS filesystem, Set<String> alreadyIncluded) {
|
||||||
alreadyIncluded.add(startFile);
|
alreadyIncluded.add(startFile);
|
||||||
boolean isIncludes = true;
|
boolean isIncludes = true;
|
||||||
StringBuilder src = new StringBuilder();
|
StringBuilder src = new StringBuilder();
|
||||||
@ -59,7 +84,7 @@ public class Parser {
|
|||||||
String file = s.substring(includePrefix.length());
|
String file = s.substring(includePrefix.length());
|
||||||
src.append("// include ").append(file).append("\n");
|
src.append("// include ").append(file).append("\n");
|
||||||
if (!alreadyIncluded.contains(file)) {
|
if (!alreadyIncluded.contains(file)) {
|
||||||
includes.addAll(parseMultiScript(file, filesystem, alreadyIncluded));
|
includes.addAll(parseMultiScript(version, file, filesystem, alreadyIncluded));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new ParseException(PrettyPrintError.builder()
|
throw new ParseException(PrettyPrintError.builder()
|
||||||
@ -77,6 +102,7 @@ public class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Parser(Lexer lexer) {
|
public Parser(Lexer lexer) {
|
||||||
|
super(lexer.version);
|
||||||
this.lexer = lexer;
|
this.lexer = lexer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +115,7 @@ public class Parser {
|
|||||||
public Expr<?> parse() {
|
public Expr<?> parse() {
|
||||||
advance();
|
advance();
|
||||||
Expr<?> expr = expression();
|
Expr<?> expr = expression();
|
||||||
if (!isAtEnd())
|
if (!isAtEnd() && version.contains(MuScriptVersion.V2))
|
||||||
throw new ParseException(PrettyPrintError.builder(lexer.location()).setMessage("Unexpected element after end of expression").build());
|
throw new ParseException(PrettyPrintError.builder(lexer.location()).setMessage("Unexpected element after end of expression").build());
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package io.gitlab.jfronny.muscript.compiler;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public abstract class VersionedComponent {
|
||||||
|
protected final MuScriptVersion version;
|
||||||
|
|
||||||
|
public VersionedComponent(MuScriptVersion version) {
|
||||||
|
this.version = Objects.requireNonNull(version);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user