Skip to content

Commit 292835e

Browse files
committed
Add set capability to functions and sections.
1 parent 49f5f00 commit 292835e

File tree

11 files changed

+155
-135
lines changed

11 files changed

+155
-135
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>org.byteskript</groupId>
88
<artifactId>byteskript</artifactId>
9-
<version>1.0.26</version>
9+
<version>1.0.27</version>
1010
<name>ByteSkript</name>
1111
<description>A compiled JVM implementation of the Skript language.</description>
1212

src/main/java/org/byteskript/skript/compiler/ElementTree.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ public void preCompile(Context context) { // Pre-compilation is (outer -> inner)
7070
if (compile && current instanceof Section section && !context.isSectionHeader())
7171
section.preCompileInline(context, match);
7272
else if (compile) current.preCompile(context, match);
73+
} catch (ScriptCompileError ex) {
74+
throw ex;
7375
} catch (Throwable ex) {
7476
throw new ScriptCompileError(context.lineNumber(), "Failure during pre-compilation of '" + current.name() + "'", ex);
7577
}
@@ -91,6 +93,8 @@ public void compile(Context context) { // Post-compilation is (inner -> outer)
9193
if (compile && current instanceof Section section && !context.isSectionHeader())
9294
section.compileInline(context, match);
9395
else if (compile) current.compile(context, match);
96+
} catch (ScriptCompileError ex) {
97+
throw ex;
9498
} catch (Throwable ex) {
9599
throw new ScriptCompileError(context.lineNumber(), "Failure during compilation of '" + current.name() + "'", ex);
96100
}

src/main/java/org/byteskript/skript/compiler/structure/LoopTree.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
import mx.kenzie.foundation.MethodBuilder;
1010
import org.byteskript.skript.api.SyntaxElement;
1111
import org.byteskript.skript.compiler.Context;
12-
import org.byteskript.skript.error.ScriptCompileError;
1312
import org.byteskript.skript.lang.syntax.flow.conditional.ElseIfSection;
1413
import org.byteskript.skript.lang.syntax.flow.conditional.ElseSection;
1514
import org.objectweb.asm.Label;
15+
import org.objectweb.asm.Opcodes;
1616

1717
public class LoopTree extends ProgrammaticSplitTree {
1818

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

31-
public Label getTop() {
32-
return top;
33-
}
34-
35-
public void setTop(Label next) {
36-
this.top = next;
37-
}
38-
3931
@Override
4032
public SectionMeta owner() {
4133
return owner;
@@ -57,13 +49,22 @@ public void branch(Context context) {
5749

5850
@Override
5951
public void close(Context context) {
60-
this.open = false;
6152
final MethodBuilder method = context.getMethod();
62-
if (method == null) throw new ScriptCompileError(context.lineNumber(), "Loop block left unclosed.");
53+
final Label top = this.getTop();
54+
method.writeCode((writer, visitor) -> visitor.visitJumpInsn(Opcodes.GOTO, top));
55+
this.open = false;
6356
method.writeCode(end.instruction());
6457
context.removeTree(this);
6558
}
6659

60+
public Label getTop() {
61+
return top;
62+
}
63+
64+
public void setTop(Label next) {
65+
this.top = next;
66+
}
67+
6768
@Override
6869
public boolean permit(SyntaxElement element) {
6970
return element instanceof ElseIfSection || element instanceof ElseSection;

src/main/java/org/byteskript/skript/compiler/structure/TestTree.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ public class TestTree extends ProgrammaticSplitTree {
1616

1717
private final SectionMeta owner;
1818
private final MultiLabel end = new MultiLabel();
19-
private boolean open;
2019
private final Label next = new Label();
20+
private boolean open;
2121

2222
public TestTree(SectionMeta owner) {
2323
this.owner = owner;

src/main/java/org/byteskript/skript/compiler/structure/TryCatchTree.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ public Label getStartTry() {
3535
return startTry;
3636
}
3737

38-
public Label getStartCatch() {
39-
return startCatch;
40-
}
41-
4238
@Override
4339
public SectionMeta owner() {
4440
return owner;
@@ -60,7 +56,18 @@ public void start(Context context) {
6056

6157
@Override
6258
public void branch(Context context) {
59+
final Label label = end.use();
60+
final Label next = this.getStartCatch();
6361
this.caught = true;
62+
final MethodBuilder method = context.getMethod();
63+
method.writeCode(((writer, visitor) -> {
64+
visitor.visitJumpInsn(Opcodes.GOTO, label);
65+
visitor.visitLabel(next);
66+
}));
67+
}
68+
69+
public Label getStartCatch() {
70+
return startCatch;
6471
}
6572

6673
@Override

src/main/java/org/byteskript/skript/lang/syntax/flow/error/CatchSection.java

Lines changed: 32 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,16 @@
66

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

9-
import mx.kenzie.foundation.MethodBuilder;
10-
import mx.kenzie.foundation.WriteInstruction;
119
import mx.kenzie.foundation.compiler.State;
1210
import org.byteskript.skript.api.note.Documentation;
1311
import org.byteskript.skript.api.syntax.Section;
1412
import org.byteskript.skript.compiler.*;
15-
import org.byteskript.skript.compiler.structure.PreVariable;
13+
import org.byteskript.skript.compiler.structure.ProgrammaticSplitTree;
1614
import org.byteskript.skript.compiler.structure.SectionMeta;
1715
import org.byteskript.skript.compiler.structure.TryCatchTree;
1816
import org.byteskript.skript.error.ScriptCompileError;
19-
import org.byteskript.skript.error.ScriptParseError;
2017
import org.byteskript.skript.lang.element.StandardElements;
2118
import org.byteskript.skript.lang.handler.StandardHandlers;
22-
import org.byteskript.skript.lang.syntax.variable.VariableExpression;
23-
import org.objectweb.asm.Label;
24-
import org.objectweb.asm.Opcodes;
2519

2620
@Documentation(
2721
name = "Catch",
@@ -45,18 +39,12 @@ public CatchSection() {
4539
@Override
4640
public Pattern.Match match(String thing, Context context) {
4741
if (!thing.startsWith("catch ")) return null;
48-
if (!thing.contains("{")) {
49-
context.getError().addHint(this, "The catch section needs to use a '{variable}'");
50-
return null;
51-
}
5242
return super.match(thing, context);
5343
}
5444

5545
@Override
5646
public void preCompile(Context context, Pattern.Match match) throws Throwable {
57-
final ElementTree holder = context.getLine().nested()[0];
58-
if (!(holder.current() instanceof VariableExpression))
59-
throw new ScriptParseError(context.lineNumber(), "The error must be a variable: 'catch {varname}'");
47+
final ElementTree holder = context.getCompileCurrent().nested()[0];
6048
holder.type = StandardHandlers.SET;
6149
holder.compile = false;
6250
}
@@ -65,30 +53,7 @@ public void preCompile(Context context, Pattern.Match match) throws Throwable {
6553
public void compile(Context context, Pattern.Match match) throws Throwable {
6654
if (!(context.getTree(context.getSection(1)) instanceof TryCatchTree tree))
6755
throw new ScriptCompileError(context.lineNumber(), "Catch used without preceding try-section.");
68-
final ElementTree holder = context.getLine().nested()[0];
69-
if (!(holder.current() instanceof VariableExpression))
70-
throw new ScriptParseError(context.lineNumber(), "The error must be a variable: 'catch {varname}'");
71-
final Label label = tree.getEnd().use();
72-
final Label next = tree.getStartCatch();
73-
final MethodBuilder method = context.getMethod();
74-
tree.branch(context);
75-
if (method == null) throw new ScriptCompileError(context.lineNumber(), "Try/catch used outside method.");
76-
context.getMethod().writeCode(((writer, visitor) -> {
77-
visitor.visitJumpInsn(Opcodes.GOTO, label);
78-
visitor.visitLabel(next);
79-
}));
80-
final int slot = context.slotOf(this.getHolderVariable(context, match));
81-
method.writeCode(WriteInstruction.storeObject(slot));
82-
context.setState(CompileState.CODE_BODY);
83-
}
84-
85-
private PreVariable getHolderVariable(Context context, Pattern.Match match) {
86-
final String pattern = match.groups()[0].trim();
87-
assert pattern.startsWith("{") && pattern.endsWith("}");
88-
final String name = pattern.substring(1, pattern.length() - 1);
89-
if (name.charAt(0) == '@' || name.charAt(0) == '_' || name.charAt(0) == '!')
90-
throw new ScriptCompileError(context.lineNumber(), "Holder variable must be a normal variable: '{var}'");
91-
return context.getVariable(name);
56+
this.compileTogether(context, match, tree);
9257
}
9358

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

10166
@Override
10267
public void onSectionExit(Context context, SectionMeta meta) {
103-
if (!(context.getTree(context.getSection()) instanceof TryCatchTree tree))
104-
throw new ScriptCompileError(context.lineNumber(), "Unable to balance try/catch flow tree.");
105-
context.setState(CompileState.CODE_BODY);
106-
tree.close(context);
68+
final ProgrammaticSplitTree current;
69+
if (context.getTree(context.getSection()) instanceof TryCatchTree found) current = found;
70+
else current = context.getCurrentTree();
71+
if (current instanceof TryCatchTree tree) {
72+
context.setState(CompileState.CODE_BODY);
73+
tree.close(context);
74+
}
10775
}
10876

10977
@Override
11078
public void compileInline(Context context, Pattern.Match match) throws Throwable {
111-
throw new ScriptCompileError(context.lineNumber(), "'Catch' must be used as section-header.");
79+
if (!(context.getTree(context.getSection(0)) instanceof TryCatchTree tree))
80+
throw new ScriptCompileError(context.lineNumber(), "Inline catch used without preceding try-section.");
81+
this.compileTogether(context, match, tree);
82+
tree.close(context);
83+
}
84+
85+
@Override
86+
public void preCompileInline(Context context, Pattern.Match match) throws Throwable {
87+
this.preCompile(context, match);
88+
}
89+
90+
public void compileTogether(Context context, Pattern.Match match, TryCatchTree tree) throws Throwable {
91+
final ElementTree holder = context.getCompileCurrent().nested()[0];
92+
tree.branch(context);
93+
store:
94+
{
95+
holder.type = StandardHandlers.SET;
96+
holder.compile = true;
97+
holder.preCompile(context);
98+
holder.compile(context);
99+
}
100+
context.setState(CompileState.CODE_BODY);
112101
}
113102

114103
}

src/main/java/org/byteskript/skript/lang/syntax/flow/loop/LoopInSection.java

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.byteskript.skript.lang.syntax.variable.VariableExpression;
2424
import org.byteskript.skript.runtime.internal.OperatorHandler;
2525
import org.objectweb.asm.Label;
26-
import org.objectweb.asm.Opcodes;
2726

2827
import java.util.Iterator;
2928

@@ -50,20 +49,12 @@ public LoopInSection() {
5049
public Pattern.Match match(String thing, Context context) {
5150
if (!thing.startsWith("loop ")) return null;
5251
if (!thing.contains(" in ")) return null;
53-
if (!thing.startsWith("loop {")) {
54-
context.getError().addHint(this, "This must use a variable: 'loop {xyz} in ...'");
55-
return null;
56-
}
57-
if (thing.charAt(6) == '@' || thing.charAt(6) == '_' || thing.charAt(6) == '!') {
58-
context.getError().addHint(this, "Holder variable must be a normal variable: '{var}'");
59-
return null;
60-
}
6152
return super.match(thing, context);
6253
}
6354

6455
@Override
6556
public void preCompile(Context context, Pattern.Match match) throws Throwable {
66-
final ElementTree holder = context.getLine().nested()[0];
57+
final ElementTree holder = context.getCompileCurrent().nested()[0];
6758
if (!(holder.current() instanceof VariableExpression))
6859
throw new ScriptParseError(context.lineNumber(), "The extracted element must be a variable.");
6960
holder.type = StandardHandlers.SET;
@@ -93,7 +84,6 @@ private void compileTogether(Context context, LoopTree tree, Pattern.Match match
9384
variable.internal = true;
9485
context.forceUnspecVariable(variable);
9586
final int slot = context.slotOf(variable);
96-
final int holder = context.slotOf(this.getHolderVariable(context, match));
9787
this.writeCall(method, OperatorHandler.class.getMethod("acquireIterator", Object.class), context);
9888
method.writeCode(WriteInstruction.storeObject(slot));
9989
final Label top = new Label();
@@ -106,7 +96,14 @@ private void compileTogether(Context context, LoopTree tree, Pattern.Match match
10696
method.writeCode((writer, visitor) -> visitor.visitJumpInsn(153, end));
10797
method.writeCode(WriteInstruction.loadObject(slot));
10898
method.writeCode(WriteInstruction.invokeInterface(Iterator.class.getMethod("next")));
109-
method.writeCode(WriteInstruction.storeObject(holder));
99+
store:
100+
{
101+
final ElementTree holder = context.getCompileCurrent().nested()[0];
102+
holder.type = StandardHandlers.SET;
103+
holder.compile = true;
104+
holder.preCompile(context);
105+
holder.compile(context);
106+
}
110107
context.setState(CompileState.CODE_BODY);
111108
}
112109

@@ -121,27 +118,24 @@ public void onSectionExit(Context context, SectionMeta meta) {
121118
final ProgrammaticSplitTree current;
122119
if (context.getTree(context.getSection()) instanceof LoopTree found) current = found;
123120
else current = context.getCurrentTree();
124-
if (!(current instanceof LoopTree tree))
125-
throw new ScriptCompileError(context.lineNumber(), "Unable to balance loop flow tree.");
126-
context.setState(CompileState.CODE_BODY);
127-
final MethodBuilder method = context.getMethod();
128-
final Label top = tree.getTop();
129-
method.writeCode((writer, visitor) -> visitor.visitJumpInsn(Opcodes.GOTO, top));
130-
tree.close(context);
121+
if (current instanceof LoopTree tree) {
122+
tree.close(context);
123+
context.setState(CompileState.CODE_BODY);
124+
}
131125
}
132126

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

140136
@Override
141137
public void preCompileInline(Context context, Pattern.Match match) throws Throwable {
142-
final ElementTree holder = context.getLine().nested()[0];
143-
if (!(holder.current() instanceof VariableExpression))
144-
throw new ScriptParseError(context.lineNumber(), "The extracted element must be a variable.");
138+
final ElementTree holder = context.getCompileCurrent().nested()[0];
145139
holder.type = StandardHandlers.SET;
146140
holder.compile = false;
147141
final LoopTree tree = new LoopTree(context.getSection());

src/main/java/org/byteskript/skript/lang/syntax/function/FunctionExpression.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88

99
import mx.kenzie.foundation.MethodBuilder;
1010
import mx.kenzie.foundation.Type;
11+
import mx.kenzie.foundation.WriteInstruction;
1112
import org.byteskript.skript.api.note.Documentation;
1213
import org.byteskript.skript.api.syntax.SimpleExpression;
1314
import org.byteskript.skript.compiler.*;
1415
import org.byteskript.skript.compiler.structure.Function;
1516
import org.byteskript.skript.lang.element.StandardElements;
17+
import org.byteskript.skript.lang.handler.StandardHandlers;
1618

1719
import java.util.ArrayList;
1820
import java.util.List;
@@ -91,7 +93,11 @@ public Type getReturnType() {
9193

9294
@Override
9395
public void preCompile(Context context, Pattern.Match match) throws Throwable {
94-
for (final ElementTree tree : context.getCompileCurrent().nested()) {
96+
final ElementTree[] trees = context.getCompileCurrent().nested();
97+
if (context.getHandlerMode() == StandardHandlers.SET) {
98+
if (trees.length > 0) trees[0].compile = false;
99+
}
100+
for (final ElementTree tree : trees) {
95101
tree.takeAtomic = true;
96102
}
97103
super.preCompile(context, match);
@@ -103,6 +109,7 @@ public void compile(Context context, Pattern.Match match) throws Throwable {
103109
final FunctionDetails details = match.meta();
104110
final Function function = context.getDefaultFunction(details.name, details.arguments);
105111
method.writeCode(function.invoke(context.getType().internalName()));
112+
if (!context.getHandlerMode().expectReturn()) method.writeCode(WriteInstruction.pop());
106113
}
107114

108115
private record FunctionDetails(String name, int arguments) {

0 commit comments

Comments
 (0)