From 32a07413d4606f16b2b629b9f9dd00ab9de55ef9 Mon Sep 17 00:00:00 2001 From: Moderocky Date: Thu, 10 Mar 2022 08:24:59 +0000 Subject: [PATCH] Correct type expression and improve debug mode. --- docs/index.html | 2 +- .../skript/api/syntax/ExtractedSection.java | 4 +- .../skript/compiler/DebugSkriptCompiler.java | 5 + .../skript/compiler/FileContext.java | 18 ++- .../skript/compiler/SimpleSkriptCompiler.java | 8 +- .../lang/syntax/type/TypeExpression.java | 27 +++- .../skript/runtime/config/ConfigMap.java | 122 +++++++++--------- .../org/byteskript/skript/test/FlowTest.java | 1 + src/test/resources/flow.bsk | 9 ++ 9 files changed, 125 insertions(+), 71 deletions(-) diff --git a/docs/index.html b/docs/index.html index ce2defd..e179685 100644 --- a/docs/index.html +++ b/docs/index.html @@ -32,7 +32,7 @@

Package Index

-

Package


org.byteskript.skript.api
Class ModifiableLibrary
Record Document
Record PropertyHandler
Abstract Class Event
Interface Flag
Interface HandlerType
Interface LanguageElement
Interface Library
Interface Referent
Interface SyntaxElement

org.byteskript.skript.api.automatic
Class GeneratedEntryNode
Class GeneratedEffect
Class GeneratedEntrySection
Class GeneratedEventHolder
Class GeneratedExpression

org.byteskript.skript.api.note
Annotation Documentation
Annotation Effect
Annotation EntryNode
Annotation EntrySection
Annotation Event
Annotation EventValue
Annotation Expression
Annotation ForceBridge
Annotation ForceExtract
Annotation ForceInline
Annotation Property
Annotation SkriptType

org.byteskript.skript.api.syntax
Abstract Class ComplexExpression
Abstract Class Condition
Abstract Class ControlEffect
Abstract Class Effect
Abstract Class Element
Abstract Class EventHolder
Abstract Class EventValueExpression
Abstract Class ExtractedSection
Abstract Class InnerModifyExpression
Abstract Class Literal
Abstract Class Member
Abstract Class RelationalExpression
Abstract Class Section
Abstract Class SectionEntry
Abstract Class SimpleEntry
Abstract Class SimpleExpression
Abstract Class TriggerHolder

org.byteskript.skript.runtime
Class SkriptMirror
Class RuntimeClassLoader
Class Script
Class Skript

org.byteskript.skript.runtime.internal
Class GlobalVariableMap
Class LibraryClassLoader
Class Member
Class Metafactory
Class Bootstrapper
Abstract Class CompiledScript
Interface ModifiableCompiler
Annotation CompilerDependent
Annotation ThreadSpecific

org.byteskript.skript.runtime.threading
Class AirlockQueue
Class OperationController
Class ScriptExceptionHandler
Class ScriptFinishFuture
Class ScriptThread
Class SkriptThreadProvider
Interface ScriptRunner

org.byteskript.skript.runtime.type
Class AtomicVariable
Class DataList
Class DataMap
+

Package

diff --git a/src/main/java/org/byteskript/skript/api/syntax/ExtractedSection.java b/src/main/java/org/byteskript/skript/api/syntax/ExtractedSection.java index b816f21..239de65 100644 --- a/src/main/java/org/byteskript/skript/api/syntax/ExtractedSection.java +++ b/src/main/java/org/byteskript/skript/api/syntax/ExtractedSection.java @@ -35,7 +35,9 @@ public void compile(Context context, Pattern.Match match) throws Throwable { @Override public void onSectionExit(Context context, SectionMeta meta) { - final ProgrammaticSplitTree current = context.getCurrentTree(); + final ProgrammaticSplitTree current; + if (context.getTree(context.getSection()) instanceof ExtractionTree found) current = found; + else current = context.getCurrentTree(); if (!(current instanceof ExtractionTree tree)) throw new ScriptCompileError(context.lineNumber(), "Unable to close section flow tree."); context.setState(CompileState.CODE_BODY); diff --git a/src/main/java/org/byteskript/skript/compiler/DebugSkriptCompiler.java b/src/main/java/org/byteskript/skript/compiler/DebugSkriptCompiler.java index 0971dd5..b51d5f9 100644 --- a/src/main/java/org/byteskript/skript/compiler/DebugSkriptCompiler.java +++ b/src/main/java/org/byteskript/skript/compiler/DebugSkriptCompiler.java @@ -56,6 +56,11 @@ public PostCompileClass[] compile(String source, Type path) { return super.compile(source, path); } + @Override + protected FileContext createContext(Type path) { + return new FileContext(path, 0); + } + protected void debug(ElementTree tree, FileContext context) { try { this.controller.write("\n"); diff --git a/src/main/java/org/byteskript/skript/compiler/FileContext.java b/src/main/java/org/byteskript/skript/compiler/FileContext.java index 1373dfd..1fa4616 100644 --- a/src/main/java/org/byteskript/skript/compiler/FileContext.java +++ b/src/main/java/org/byteskript/skript/compiler/FileContext.java @@ -47,6 +47,10 @@ public class FileContext extends Context { private HandlerType mode = StandardHandlers.GET; public FileContext(Type type) { + this(type, -1); + } + + public FileContext(Type type, int computation) { this.type = type; this.state = CompileState.ROOT; this.writer = new ClassBuilder(type, SkriptLangSpec.JAVA_VERSION) @@ -55,7 +59,7 @@ public FileContext(Type type) { .setSuperclass(CompiledScript.class); this.addSkriptFunctions(); this.registerType("none", new Type(void.class)); // special overridden case -// writer.setComputation(1); // todo + if (computation > -1) writer.setComputation(computation); } private void addSkriptFunctions() { @@ -85,7 +89,17 @@ public PostCompileClass[] compile() { final List classes = new ArrayList<>(); classes.add(new PostCompileClass(writer.compile(), writer.getName(), writer.getInternalName())); for (ClassBuilder builder : writer.getSuppressed()) { - classes.add(new PostCompileClass(builder.compile(), builder.getName(), builder.getInternalName())); + try { + classes.add(new PostCompileClass(builder.compile(), builder.getName(), builder.getInternalName())); + } catch (ArrayIndexOutOfBoundsException ex) { + if (ex.getStackTrace()[0].getClassName().endsWith("Frame")) { + throw new ScriptCompileError(-1, """ + Error during assembly phase. + This error cannot be directly triaged, but likely comes from a malformed syntax (in which case the library-maintainer needs to fix it.) + Experienced developers may check the `debug` output to see where the stack calculation error is. + """); + } + } } return classes.toArray(new PostCompileClass[0]); } diff --git a/src/main/java/org/byteskript/skript/compiler/SimpleSkriptCompiler.java b/src/main/java/org/byteskript/skript/compiler/SimpleSkriptCompiler.java index 4c9b47a..aa65d32 100644 --- a/src/main/java/org/byteskript/skript/compiler/SimpleSkriptCompiler.java +++ b/src/main/java/org/byteskript/skript/compiler/SimpleSkriptCompiler.java @@ -299,7 +299,7 @@ public boolean removeLibrary(Library library) { @Override public PostCompileClass[] compile(InputStream stream, Type path) { - final FileContext context = new FileContext(path); + final FileContext context = this.createContext(path); context.libraries.addAll(libraries); for (final Library library : libraries) { for (final Type type : library.getTypes()) context.registerType(type); @@ -325,7 +325,7 @@ public PostCompileClass[] compile(InputStream source, String path) { @Override public PostCompileClass[] compile(String source, Type path) { - final FileContext context = new FileContext(path); + final FileContext context = this.createContext(path); context.libraries.addAll(libraries); for (final Library library : libraries) { for (final Type type : library.getTypes()) context.registerType(type); @@ -351,6 +351,10 @@ public SimpleSkriptCompiler clone() { return compiler; } + protected FileContext createContext(Type path) { + return new FileContext(path); + } + private void compileLine(FileContext context, String stripped) { if (context.getMethod() != null) { context.getMethod().writeCode(WriteInstruction.lineNumber(context.lineNumber)); diff --git a/src/main/java/org/byteskript/skript/lang/syntax/type/TypeExpression.java b/src/main/java/org/byteskript/skript/lang/syntax/type/TypeExpression.java index f4ba0ca..ec7cf71 100644 --- a/src/main/java/org/byteskript/skript/lang/syntax/type/TypeExpression.java +++ b/src/main/java/org/byteskript/skript/lang/syntax/type/TypeExpression.java @@ -10,7 +10,7 @@ import mx.kenzie.foundation.Type; import mx.kenzie.foundation.WriteInstruction; import org.byteskript.skript.api.note.Documentation; -import org.byteskript.skript.api.syntax.SimpleExpression; +import org.byteskript.skript.api.syntax.Literal; import org.byteskript.skript.compiler.CommonTypes; import org.byteskript.skript.compiler.Context; import org.byteskript.skript.compiler.Pattern; @@ -36,17 +36,14 @@ Gets the (class) handle for a type, using its fully-qualified name. """ } ) -public class TypeExpression extends SimpleExpression { +public class TypeExpression extends Literal> { + + private final java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("^\\p{javaJavaIdentifierStart}[\\p{javaJavaIdentifierPart}./]+$"); public TypeExpression() { super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "type"); } - @Override - public Type getReturnType() { - return CommonTypes.CLASS; - } - @Override public void compile(Context context, Pattern.Match match) throws Throwable { final MethodBuilder method = context.getMethod(); @@ -54,8 +51,19 @@ public void compile(Context context, Pattern.Match match) throws Throwable { method.writeCode(WriteInstruction.loadClassConstant(match.meta())); } + @Override + public Class parse(String input) { + try { + return Class.forName(input.replace('/', '.')); + } catch (ClassNotFoundException e) { + return null; + } + } + @Override public Pattern.Match match(String thing, Context context) { + if (thing.contains("\"")) return null; + if (!pattern.matcher(thing).matches()) return null; final Type type = this.getType(thing, context); if (type == null) return null; final Matcher matcher = Pattern.fakeMatcher(thing); @@ -67,6 +75,11 @@ public boolean allowAsInputFor(Type type) { return CommonTypes.CLASS.equals(type) || CommonTypes.TYPE.equals(type) || CommonTypes.OBJECT.equals(type); } + @Override + public Type getReturnType() { + return CommonTypes.CLASS; + } + public Type getType(String string, Context context) { for (final Map.Entry entry : context.getTypeMap().entrySet()) { if (!entry.getKey().toLowerCase(Locale.ROOT).equals(string.toLowerCase(Locale.ROOT))) continue; diff --git a/src/main/java/org/byteskript/skript/runtime/config/ConfigMap.java b/src/main/java/org/byteskript/skript/runtime/config/ConfigMap.java index 4828f49..fcd878e 100644 --- a/src/main/java/org/byteskript/skript/runtime/config/ConfigMap.java +++ b/src/main/java/org/byteskript/skript/runtime/config/ConfigMap.java @@ -41,64 +41,6 @@ public ConfigMap(File file) throws IOException { } } - protected void readLines(InputStreamController controller) { - final AtomicBoolean comment = new AtomicBoolean(false); - for (final String thing : controller.lines()) { - final String line = this.stripLine(thing, comment); - if (line.isEmpty()) continue; - final int index = line.indexOf(':'); - if (index < 0) continue; - final ConfigEntry entry = new ConfigEntry(); - entry.comments = comments.toArray(new String[0]); - entry.key = line.substring(0, index).trim(); - entry.value = line.substring(index + 1).trim(); - this.put(entry); - this.comments.clear(); - } - - } - - protected String stripLine(final String old, AtomicBoolean comment) { - String line = old; - boolean started = false; - do { - if (!comment.get()) { - if (line.contains("//")) { - final String string = line.substring(line.indexOf("//") + 2).trim(); - line = line.substring(0, line.indexOf("//")); // keep first part of line - this.comments.add(string); - } - if (line.contains("/*")) { - started = true; - comment.set(true); - final String string = line.substring(line.indexOf("/*") + 2); - line = line.substring(0, line.indexOf("/*")); // first part of line not in comment - this.current.append(string); - } - } - if (comment.get()) { - if (line.contains("*/")) { - if (!started) this.current.append(System.lineSeparator()); - final String string = line.substring(0, line.indexOf("*/")); - line = line.substring(line.indexOf("*/") + 2); // keep last part of line - this.current.append(string); - this.comments.add(current.toString().trim()); - this.current = new StringBuilder(); - comment.set(false); - } else { - if (!started) this.current.append(System.lineSeparator()); - this.current.append(line); - line = ""; // inside a commented block - } - } - } while (line.contains("/*") || line.contains("*/") || line.contains("//")); - return line.trim(); // for now just trim lines, no indented areas - } - - public ConfigEntry put(ConfigEntry value) { - return super.put(value.key, value); - } - public ConfigMap(InputStream stream) throws IOException { this.file = null; try (final InputStreamController controller = Stream.controller(stream)) { @@ -164,6 +106,70 @@ public static void deleteMapValue(Object key, Object target) { set(key + "", map, null); } + protected void readLines(InputStreamController controller) { + final AtomicBoolean comment = new AtomicBoolean(false); + for (final String thing : controller.lines()) { + final String line = this.stripLine(thing, comment); + if (line.isEmpty()) continue; + final int index = this.findSplitter(line, 0); + if (index < 0) continue; + final ConfigEntry entry = new ConfigEntry(); + entry.comments = comments.toArray(new String[0]); + entry.key = line.substring(0, index).trim(); + entry.value = line.substring(index + 1).trim(); + this.put(entry); + this.comments.clear(); + } + } + + private int findSplitter(String line, int from) { + final int index = line.indexOf(':', from); + if (index < 1) return -1; // illegal :line + if (line.charAt(index - 1) != '\\') return index; + return this.findSplitter(line, index); // ke\:y: value + } + + protected String stripLine(final String old, AtomicBoolean comment) { + String line = old; + boolean started = false; + do { + if (!comment.get()) { + if (line.contains("//")) { + final String string = line.substring(line.indexOf("//") + 2).trim(); + line = line.substring(0, line.indexOf("//")); // keep first part of line + this.comments.add(string); + } + if (line.contains("/*")) { + started = true; + comment.set(true); + final String string = line.substring(line.indexOf("/*") + 2); + line = line.substring(0, line.indexOf("/*")); // first part of line not in comment + this.current.append(string); + } + } + if (comment.get()) { + if (line.contains("*/")) { + if (!started) this.current.append(System.lineSeparator()); + final String string = line.substring(0, line.indexOf("*/")); + line = line.substring(line.indexOf("*/") + 2); // keep last part of line + this.current.append(string); + this.comments.add(current.toString().trim()); + this.current = new StringBuilder(); + comment.set(false); + } else { + if (!started) this.current.append(System.lineSeparator()); + this.current.append(line); + line = ""; // inside a commented block + } + } + } while (line.contains("/*") || line.contains("*/") || line.contains("//")); + return line.trim(); // for now just trim lines, no indented areas + } + + public ConfigEntry put(ConfigEntry value) { + return super.put(value.key, value); + } + public void delete() { if (file == null) return; this.file.delete(); diff --git a/src/test/java/org/byteskript/skript/test/FlowTest.java b/src/test/java/org/byteskript/skript/test/FlowTest.java index 2096e48..b591bd3 100644 --- a/src/test/java/org/byteskript/skript/test/FlowTest.java +++ b/src/test/java/org/byteskript/skript/test/FlowTest.java @@ -22,6 +22,7 @@ public class FlowTest extends SkriptTest { public static void start() throws Throwable { final PostCompileClass cls = skript.compileScript(FlowTest.class.getClassLoader() .getResourceAsStream("flow.bsk"), "skript.flow"); + debug(cls); //todo script = skript.loadScript(cls); } diff --git a/src/test/resources/flow.bsk b/src/test/resources/flow.bsk index c14be42..af6b8a0 100644 --- a/src/test/resources/flow.bsk +++ b/src/test/resources/flow.bsk @@ -97,6 +97,15 @@ function while_flow: while {count} is less than 10: set {count} to {count} + 1 assert {count} is 10: "While loop failed to count properly." + set {var} to a new runnable: + set {count} to 0 + while {count} < 10: + set {phase} to {count} as a string + set {tag} to "a" + {phase} + assert {tag} is a string + set {count} to {count} + 1 + assert true is true // todo - currently un-fixable + run {var} return "ended" function test_run: