Skip to content

Commit

Permalink
Add set capability to functions and sections.
Browse files Browse the repository at this point in the history
  • Loading branch information
Moderocky committed Mar 21, 2022
1 parent 49f5f00 commit 292835e
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 135 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>org.byteskript</groupId>
<artifactId>byteskript</artifactId>
<version>1.0.26</version>
<version>1.0.27</version>
<name>ByteSkript</name>
<description>A compiled JVM implementation of the Skript language.</description>

Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/byteskript/skript/compiler/ElementTree.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public void preCompile(Context context) { // Pre-compilation is (outer -> inner)
if (compile && current instanceof Section section && !context.isSectionHeader())
section.preCompileInline(context, match);
else if (compile) current.preCompile(context, match);
} catch (ScriptCompileError ex) {
throw ex;
} catch (Throwable ex) {
throw new ScriptCompileError(context.lineNumber(), "Failure during pre-compilation of '" + current.name() + "'", ex);
}
Expand All @@ -91,6 +93,8 @@ public void compile(Context context) { // Post-compilation is (inner -> outer)
if (compile && current instanceof Section section && !context.isSectionHeader())
section.compileInline(context, match);
else if (compile) current.compile(context, match);
} catch (ScriptCompileError ex) {
throw ex;
} catch (Throwable ex) {
throw new ScriptCompileError(context.lineNumber(), "Failure during compilation of '" + current.name() + "'", ex);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
import mx.kenzie.foundation.MethodBuilder;
import org.byteskript.skript.api.SyntaxElement;
import org.byteskript.skript.compiler.Context;
import org.byteskript.skript.error.ScriptCompileError;
import org.byteskript.skript.lang.syntax.flow.conditional.ElseIfSection;
import org.byteskript.skript.lang.syntax.flow.conditional.ElseSection;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;

public class LoopTree extends ProgrammaticSplitTree {

Expand All @@ -28,14 +28,6 @@ public LoopTree(SectionMeta owner) {
this.end = new MultiLabel();
}

public Label getTop() {
return top;
}

public void setTop(Label next) {
this.top = next;
}

@Override
public SectionMeta owner() {
return owner;
Expand All @@ -57,13 +49,22 @@ public void branch(Context context) {

@Override
public void close(Context context) {
this.open = false;
final MethodBuilder method = context.getMethod();
if (method == null) throw new ScriptCompileError(context.lineNumber(), "Loop block left unclosed.");
final Label top = this.getTop();
method.writeCode((writer, visitor) -> visitor.visitJumpInsn(Opcodes.GOTO, top));
this.open = false;
method.writeCode(end.instruction());
context.removeTree(this);
}

public Label getTop() {
return top;
}

public void setTop(Label next) {
this.top = next;
}

@Override
public boolean permit(SyntaxElement element) {
return element instanceof ElseIfSection || element instanceof ElseSection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public class TestTree extends ProgrammaticSplitTree {

private final SectionMeta owner;
private final MultiLabel end = new MultiLabel();
private boolean open;
private final Label next = new Label();
private boolean open;

public TestTree(SectionMeta owner) {
this.owner = owner;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ public Label getStartTry() {
return startTry;
}

public Label getStartCatch() {
return startCatch;
}

@Override
public SectionMeta owner() {
return owner;
Expand All @@ -60,7 +56,18 @@ public void start(Context context) {

@Override
public void branch(Context context) {
final Label label = end.use();
final Label next = this.getStartCatch();
this.caught = true;
final MethodBuilder method = context.getMethod();
method.writeCode(((writer, visitor) -> {
visitor.visitJumpInsn(Opcodes.GOTO, label);
visitor.visitLabel(next);
}));
}

public Label getStartCatch() {
return startCatch;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,16 @@

package org.byteskript.skript.lang.syntax.flow.error;

import mx.kenzie.foundation.MethodBuilder;
import mx.kenzie.foundation.WriteInstruction;
import mx.kenzie.foundation.compiler.State;
import org.byteskript.skript.api.note.Documentation;
import org.byteskript.skript.api.syntax.Section;
import org.byteskript.skript.compiler.*;
import org.byteskript.skript.compiler.structure.PreVariable;
import org.byteskript.skript.compiler.structure.ProgrammaticSplitTree;
import org.byteskript.skript.compiler.structure.SectionMeta;
import org.byteskript.skript.compiler.structure.TryCatchTree;
import org.byteskript.skript.error.ScriptCompileError;
import org.byteskript.skript.error.ScriptParseError;
import org.byteskript.skript.lang.element.StandardElements;
import org.byteskript.skript.lang.handler.StandardHandlers;
import org.byteskript.skript.lang.syntax.variable.VariableExpression;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;

@Documentation(
name = "Catch",
Expand All @@ -45,18 +39,12 @@ public CatchSection() {
@Override
public Pattern.Match match(String thing, Context context) {
if (!thing.startsWith("catch ")) return null;
if (!thing.contains("{")) {
context.getError().addHint(this, "The catch section needs to use a '{variable}'");
return null;
}
return super.match(thing, context);
}

@Override
public void preCompile(Context context, Pattern.Match match) throws Throwable {
final ElementTree holder = context.getLine().nested()[0];
if (!(holder.current() instanceof VariableExpression))
throw new ScriptParseError(context.lineNumber(), "The error must be a variable: 'catch {varname}'");
final ElementTree holder = context.getCompileCurrent().nested()[0];
holder.type = StandardHandlers.SET;
holder.compile = false;
}
Expand All @@ -65,30 +53,7 @@ public void preCompile(Context context, Pattern.Match match) throws Throwable {
public void compile(Context context, Pattern.Match match) throws Throwable {
if (!(context.getTree(context.getSection(1)) instanceof TryCatchTree tree))
throw new ScriptCompileError(context.lineNumber(), "Catch used without preceding try-section.");
final ElementTree holder = context.getLine().nested()[0];
if (!(holder.current() instanceof VariableExpression))
throw new ScriptParseError(context.lineNumber(), "The error must be a variable: 'catch {varname}'");
final Label label = tree.getEnd().use();
final Label next = tree.getStartCatch();
final MethodBuilder method = context.getMethod();
tree.branch(context);
if (method == null) throw new ScriptCompileError(context.lineNumber(), "Try/catch used outside method.");
context.getMethod().writeCode(((writer, visitor) -> {
visitor.visitJumpInsn(Opcodes.GOTO, label);
visitor.visitLabel(next);
}));
final int slot = context.slotOf(this.getHolderVariable(context, match));
method.writeCode(WriteInstruction.storeObject(slot));
context.setState(CompileState.CODE_BODY);
}

private PreVariable getHolderVariable(Context context, Pattern.Match match) {
final String pattern = match.groups()[0].trim();
assert pattern.startsWith("{") && pattern.endsWith("}");
final String name = pattern.substring(1, pattern.length() - 1);
if (name.charAt(0) == '@' || name.charAt(0) == '_' || name.charAt(0) == '!')
throw new ScriptCompileError(context.lineNumber(), "Holder variable must be a normal variable: '{var}'");
return context.getVariable(name);
this.compileTogether(context, match, tree);
}

@Override
Expand All @@ -100,15 +65,39 @@ public boolean allowedIn(State state, Context context) {

@Override
public void onSectionExit(Context context, SectionMeta meta) {
if (!(context.getTree(context.getSection()) instanceof TryCatchTree tree))
throw new ScriptCompileError(context.lineNumber(), "Unable to balance try/catch flow tree.");
context.setState(CompileState.CODE_BODY);
tree.close(context);
final ProgrammaticSplitTree current;
if (context.getTree(context.getSection()) instanceof TryCatchTree found) current = found;
else current = context.getCurrentTree();
if (current instanceof TryCatchTree tree) {
context.setState(CompileState.CODE_BODY);
tree.close(context);
}
}

@Override
public void compileInline(Context context, Pattern.Match match) throws Throwable {
throw new ScriptCompileError(context.lineNumber(), "'Catch' must be used as section-header.");
if (!(context.getTree(context.getSection(0)) instanceof TryCatchTree tree))
throw new ScriptCompileError(context.lineNumber(), "Inline catch used without preceding try-section.");
this.compileTogether(context, match, tree);
tree.close(context);
}

@Override
public void preCompileInline(Context context, Pattern.Match match) throws Throwable {
this.preCompile(context, match);
}

public void compileTogether(Context context, Pattern.Match match, TryCatchTree tree) throws Throwable {
final ElementTree holder = context.getCompileCurrent().nested()[0];
tree.branch(context);
store:
{
holder.type = StandardHandlers.SET;
holder.compile = true;
holder.preCompile(context);
holder.compile(context);
}
context.setState(CompileState.CODE_BODY);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import org.byteskript.skript.lang.syntax.variable.VariableExpression;
import org.byteskript.skript.runtime.internal.OperatorHandler;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;

import java.util.Iterator;

Expand All @@ -50,20 +49,12 @@ public LoopInSection() {
public Pattern.Match match(String thing, Context context) {
if (!thing.startsWith("loop ")) return null;
if (!thing.contains(" in ")) return null;
if (!thing.startsWith("loop {")) {
context.getError().addHint(this, "This must use a variable: 'loop {xyz} in ...'");
return null;
}
if (thing.charAt(6) == '@' || thing.charAt(6) == '_' || thing.charAt(6) == '!') {
context.getError().addHint(this, "Holder variable must be a normal variable: '{var}'");
return null;
}
return super.match(thing, context);
}

@Override
public void preCompile(Context context, Pattern.Match match) throws Throwable {
final ElementTree holder = context.getLine().nested()[0];
final ElementTree holder = context.getCompileCurrent().nested()[0];
if (!(holder.current() instanceof VariableExpression))
throw new ScriptParseError(context.lineNumber(), "The extracted element must be a variable.");
holder.type = StandardHandlers.SET;
Expand Down Expand Up @@ -93,7 +84,6 @@ private void compileTogether(Context context, LoopTree tree, Pattern.Match match
variable.internal = true;
context.forceUnspecVariable(variable);
final int slot = context.slotOf(variable);
final int holder = context.slotOf(this.getHolderVariable(context, match));
this.writeCall(method, OperatorHandler.class.getMethod("acquireIterator", Object.class), context);
method.writeCode(WriteInstruction.storeObject(slot));
final Label top = new Label();
Expand All @@ -106,7 +96,14 @@ private void compileTogether(Context context, LoopTree tree, Pattern.Match match
method.writeCode((writer, visitor) -> visitor.visitJumpInsn(153, end));
method.writeCode(WriteInstruction.loadObject(slot));
method.writeCode(WriteInstruction.invokeInterface(Iterator.class.getMethod("next")));
method.writeCode(WriteInstruction.storeObject(holder));
store:
{
final ElementTree holder = context.getCompileCurrent().nested()[0];
holder.type = StandardHandlers.SET;
holder.compile = true;
holder.preCompile(context);
holder.compile(context);
}
context.setState(CompileState.CODE_BODY);
}

Expand All @@ -121,27 +118,24 @@ public void onSectionExit(Context context, SectionMeta meta) {
final ProgrammaticSplitTree current;
if (context.getTree(context.getSection()) instanceof LoopTree found) current = found;
else current = context.getCurrentTree();
if (!(current instanceof LoopTree tree))
throw new ScriptCompileError(context.lineNumber(), "Unable to balance loop flow tree.");
context.setState(CompileState.CODE_BODY);
final MethodBuilder method = context.getMethod();
final Label top = tree.getTop();
method.writeCode((writer, visitor) -> visitor.visitJumpInsn(Opcodes.GOTO, top));
tree.close(context);
if (current instanceof LoopTree tree) {
tree.close(context);
context.setState(CompileState.CODE_BODY);
}
}

@Override
public void compileInline(Context context, Pattern.Match match) throws Throwable {
if (!(context.getTree(context.getSection()) instanceof LoopTree tree))
throw new ScriptCompileError(context.lineNumber(), "Illegal mid-statement flow break.");
this.compileTogether(context, tree, match);
tree.close(context);
context.setState(CompileState.CODE_BODY);
}

@Override
public void preCompileInline(Context context, Pattern.Match match) throws Throwable {
final ElementTree holder = context.getLine().nested()[0];
if (!(holder.current() instanceof VariableExpression))
throw new ScriptParseError(context.lineNumber(), "The extracted element must be a variable.");
final ElementTree holder = context.getCompileCurrent().nested()[0];
holder.type = StandardHandlers.SET;
holder.compile = false;
final LoopTree tree = new LoopTree(context.getSection());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@

import mx.kenzie.foundation.MethodBuilder;
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.compiler.*;
import org.byteskript.skript.compiler.structure.Function;
import org.byteskript.skript.lang.element.StandardElements;
import org.byteskript.skript.lang.handler.StandardHandlers;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -91,7 +93,11 @@ public Type getReturnType() {

@Override
public void preCompile(Context context, Pattern.Match match) throws Throwable {
for (final ElementTree tree : context.getCompileCurrent().nested()) {
final ElementTree[] trees = context.getCompileCurrent().nested();
if (context.getHandlerMode() == StandardHandlers.SET) {
if (trees.length > 0) trees[0].compile = false;
}
for (final ElementTree tree : trees) {
tree.takeAtomic = true;
}
super.preCompile(context, match);
Expand All @@ -103,6 +109,7 @@ public void compile(Context context, Pattern.Match match) throws Throwable {
final FunctionDetails details = match.meta();
final Function function = context.getDefaultFunction(details.name, details.arguments);
method.writeCode(function.invoke(context.getType().internalName()));
if (!context.getHandlerMode().expectReturn()) method.writeCode(WriteInstruction.pop());
}

private record FunctionDetails(String name, int arguments) {
Expand Down
Loading

0 comments on commit 292835e

Please sign in to comment.