Skip to content

Commit 60000e5

Browse files
committed
Update bridge compiler to handle smarter number conversion and skript namespace primitives.
1 parent cf6a505 commit 60000e5

File tree

4 files changed

+129
-81
lines changed

4 files changed

+129
-81
lines changed

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

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import org.byteskript.skript.error.ScriptRuntimeError;
1010
import org.byteskript.skript.runtime.Skript;
11+
import org.byteskript.skript.runtime.internal.OperatorHandler;
1112
import org.byteskript.skript.runtime.type.AtomicVariable;
1213
import org.objectweb.asm.ClassWriter;
1314
import org.objectweb.asm.MethodVisitor;
@@ -61,7 +62,7 @@ public Class<?> createClass()
6162
final Class<?> parameter = parameters[i];
6263
visitor.visitVarInsn(20 + this.instructionOffset(argument), i);
6364
this.boxAtomic(visitor, parameter);
64-
visitor.visitTypeInsn(CHECKCAST, Type.getInternalName(this.getWrapperType(parameter)));
65+
visitor.visitTypeInsn(CHECKCAST, Type.getInternalName(this.getUnboxingType(parameter)));
6566
this.unbox(visitor, parameter);
6667
}
6768
this.invoke(visitor);
@@ -118,13 +119,23 @@ protected void doTypeConversion(MethodVisitor visitor, Class<?> from, Class<?> t
118119
} else visitor.visitTypeInsn(CHECKCAST, Type.getInternalName(to));
119120
}
120121

122+
protected Class<?> getUnboxingType(Class<?> primitive) {
123+
if (!primitive.isPrimitive()) return primitive;
124+
if (primitive == boolean.class) return Boolean.class;
125+
if (primitive == void.class) return Void.class;
126+
if (primitive == char.class) return Character.class;
127+
return Number.class;
128+
}
129+
121130
protected Class<?> getWrapperType(Class<?> primitive) {
131+
if (!primitive.isPrimitive()) return primitive;
122132
if (primitive == byte.class) return Byte.class;
123133
if (primitive == short.class) return Short.class;
124134
if (primitive == int.class) return Integer.class;
125135
if (primitive == long.class) return Long.class;
126136
if (primitive == float.class) return Float.class;
127137
if (primitive == double.class) return Double.class;
138+
if (primitive == char.class) return Character.class;
128139
if (primitive == boolean.class) return Boolean.class;
129140
if (primitive == void.class) return Void.class;
130141
return primitive;
@@ -138,20 +149,23 @@ protected void boxAtomic(MethodVisitor visitor, Class<?> parameter) {
138149
}
139150

140151
protected void unbox(MethodVisitor visitor, Class<?> parameter) {
152+
final String source = Type.getInternalName(OperatorHandler.class);
141153
if (parameter == byte.class)
142-
visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Byte.class), "byteValue", "()B", false);
154+
visitor.visitMethodInsn(INVOKESTATIC, source, "unboxB", "(Ljava/lang/Number;)B", false);
143155
if (parameter == short.class)
144-
visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Short.class), "shortValue", "()S", false);
156+
visitor.visitMethodInsn(INVOKESTATIC, source, "unboxS", "(Ljava/lang/Number;)S", false);
145157
if (parameter == int.class)
146-
visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Integer.class), "intValue", "()I", false);
158+
visitor.visitMethodInsn(INVOKESTATIC, source, "unboxI", "(Ljava/lang/Number;)I", false);
147159
if (parameter == long.class)
148-
visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Long.class), "longValue", "()J", false);
160+
visitor.visitMethodInsn(INVOKESTATIC, source, "unboxJ", "(Ljava/lang/Number;)J", false);
149161
if (parameter == float.class)
150-
visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Float.class), "floatValue", "()F", false);
162+
visitor.visitMethodInsn(INVOKESTATIC, source, "unboxF", "(Ljava/lang/Number;)F", false);
151163
if (parameter == double.class)
152-
visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Double.class), "doubleValue", "()D", false);
164+
visitor.visitMethodInsn(INVOKESTATIC, source, "unboxD", "(Ljava/lang/Number;)D", false);
153165
if (parameter == boolean.class)
154-
visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Boolean.class), "booleanValue", "()Z", false);
166+
visitor.visitMethodInsn(INVOKESTATIC, source, "unbox", "(Ljava/lang/Boolean;)Z", false);
167+
if (parameter == char.class)
168+
visitor.visitMethodInsn(INVOKESTATIC, source, "unbox", "(Ljava/lang/Character;)C", false);
155169
}
156170

157171
protected void box(MethodVisitor visitor, Class<?> value) {

src/main/java/org/byteskript/skript/runtime/internal/Bootstrapper.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,27 @@ private static String getDescriptor(final Type ret, final Type... params) {
6969
return builder.toString();
7070
}
7171

72+
private static Class<?> getClass(String name) throws ClassNotFoundException {
73+
return switch (name) {
74+
case "boolean" -> boolean.class;
75+
case "char" -> char.class;
76+
case "void" -> void.class;
77+
case "byte" -> byte.class;
78+
case "short" -> short.class;
79+
case "int" -> int.class;
80+
case "long" -> long.class;
81+
case "float" -> float.class;
82+
case "double" -> double.class;
83+
default -> Class.forName(name);
84+
};
85+
}
86+
7287
public static CallSite bootstrapFunction(MethodHandles.Lookup caller, String name, MethodType type, String source, Class<?> owner, String args)
7388
throws Exception {
7489
final org.objectweb.asm.Type[] types = org.objectweb.asm.Type.getArgumentTypes(args);
7590
final Class<?>[] arguments = new Class[types.length];
7691
for (int i = 0; i < types.length; i++) {
77-
arguments[i] = Class.forName(types[i].getClassName());
92+
arguments[i] = getClass(types[i].getClassName());
7893
}
7994
return Metafactory.createBridge(caller, name, type, source, owner, arguments);
8095
}

src/main/java/org/byteskript/skript/runtime/internal/OperatorHandler.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,49 @@
1111
import java.util.*;
1212
import java.util.regex.Pattern;
1313

14+
/**
15+
* Operator handler methods invoked by syntax internally.
16+
* <p>
17+
* The boxing methods are used for null=0 handling by the bridge compiler.
18+
*/
1419
public class OperatorHandler {
1520

21+
//region Unboxing
22+
public static byte unboxB(Number value) {
23+
return value.byteValue();
24+
}
25+
26+
public static short unboxS(Number value) {
27+
return value.shortValue();
28+
}
29+
30+
public static int unboxI(Number value) {
31+
if (value == null) return 0;
32+
return value.intValue();
33+
}
34+
35+
public static long unboxJ(Number value) {
36+
return value.longValue();
37+
}
38+
39+
public static float unboxF(Number value) {
40+
return value.floatValue();
41+
}
42+
43+
public static double unboxD(Number value) {
44+
return value.doubleValue();
45+
}
46+
47+
public static char unbox(Character value) {
48+
return value;
49+
}
50+
51+
public static boolean unbox(Boolean value) {
52+
return value;
53+
}
54+
//endregion
55+
56+
//region Generic
1657
public static String concat(String... strings) {
1758
final StringBuilder builder = new StringBuilder();
1859
for (String string : strings) {
@@ -33,6 +74,7 @@ public static Iterator<?> acquireIterator(Object thing) {
3374
if (thing == null) return Collections.emptyIterator();
3475
return Collections.singletonList(thing).iterator();
3576
}
77+
//endregion
3678

3779
//region Calculations
3880
public static Object add(Object a, Object b) {

src/main/java/skript.java

Lines changed: 49 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -11,82 +11,64 @@ public final class skript {
1111
//region Maths
1212

1313
//region Trigonometry
14-
public static double acos(Object object) {
15-
if (object == null) return 90;
16-
if (object instanceof Number number) return Math.toDegrees(Math.acos(number.doubleValue()));
17-
throw new ScriptRuntimeError("Unable to acos(" + object + ") - not a number.");
14+
public static double acos(double number) {
15+
if (number == 0) return 90;
16+
return Math.toDegrees(Math.acos(number));
1817
}
1918

20-
public static double asin(Object object) {
21-
if (object == null) return 0;
22-
if (object instanceof Number number) return Math.toDegrees(Math.asin(number.doubleValue()));
23-
throw new ScriptRuntimeError("Unable to asin(" + object + ") - not a number.");
19+
public static double asin(double number) {
20+
if (number == 0) return 0;
21+
return Math.toDegrees(Math.asin(number));
2422
}
2523

26-
public static double atan(Object object) {
27-
if (object == null) return 0;
28-
if (object instanceof Number number) return Math.toDegrees(Math.atan(number.doubleValue()));
29-
throw new ScriptRuntimeError("Unable to atan(" + object + ") - not a number.");
30-
}
31-
32-
public static double atan2(Object rawX, Object rawY) {
33-
double x, y;
34-
if (rawX == null) x = 0;
35-
else if (rawX instanceof Number number) x = number.doubleValue();
36-
else throw new ScriptRuntimeError("Unable to atan2(" + rawX + ") - not a number.");
37-
if (rawY == null) y = 0;
38-
else if (rawY instanceof Number number) y = number.doubleValue();
39-
else throw new ScriptRuntimeError("Unable to atan2(" + rawY + ") - not a number.");
24+
public static double atan(double number) {
25+
if (number == 0) return 0;
26+
return Math.toDegrees(Math.atan(number));
27+
}
28+
29+
public static double atan2(double x, double y) {
4030
return Math.toDegrees(Math.atan2(y, x));
4131
}
4232

43-
public static double cos(Object object) {
44-
if (object == null) return 1;
45-
if (object instanceof Number number) return Math.cos(Math.toRadians(number.doubleValue()));
46-
throw new ScriptRuntimeError("Unable to cos(" + object + ") - not a number.");
33+
public static double cos(double number) {
34+
if (number == 0) return 1;
35+
return Math.cos(Math.toRadians(number));
4736
}
4837

49-
public static double cosh(Object object) {
50-
if (object == null) return 1;
51-
if (object instanceof Number number) return Math.toDegrees(Math.cosh(Math.toRadians(number.doubleValue())));
52-
throw new ScriptRuntimeError("Unable to cosh(" + object + ") - not a number.");
38+
public static double cosh(double number) {
39+
if (number == 0) return 1;
40+
return Math.toDegrees(Math.cosh(Math.toRadians(number)));
5341
}
5442

55-
public static double sin(Object object) {
56-
if (object == null) return 0;
57-
if (object instanceof Number number) return Math.sin(Math.toRadians(number.doubleValue()));
58-
throw new ScriptRuntimeError("Unable to sin(" + object + ") - not a number.");
43+
public static double sin(double number) {
44+
if (number == 0) return 0;
45+
return Math.sin(Math.toRadians(number));
5946
}
6047

61-
public static double sinh(Object object) {
62-
if (object == null) return 0;
63-
if (object instanceof Number number) return Math.toDegrees(Math.sinh(Math.toRadians(number.doubleValue())));
64-
throw new ScriptRuntimeError("Unable to sinh(" + object + ") - not a number.");
48+
public static double sinh(double number) {
49+
if (number == 0) return 0;
50+
return Math.toDegrees(Math.sinh(Math.toRadians(number)));
6551
}
6652

67-
public static double tan(Object object) {
68-
if (object == null) return 0;
69-
if (object instanceof Number number) return Math.tan(Math.toRadians(number.doubleValue()));
70-
throw new ScriptRuntimeError("Unable to tan(" + object + ") - not a number.");
53+
public static double tan(double number) {
54+
if (number == 0) return 0;
55+
return Math.tan(Math.toRadians(number));
7156
}
7257

73-
public static double tanh(Object object) {
74-
if (object == null) return 0;
75-
if (object instanceof Number number) return Math.toDegrees(Math.tanh(Math.toRadians(number.doubleValue())));
76-
throw new ScriptRuntimeError("Unable to tanh(" + object + ") - not a number.");
58+
public static double tanh(double number) {
59+
if (number == 0) return 0;
60+
return Math.toDegrees(Math.tanh(Math.toRadians(number)));
7761
}
7862
//endregion
7963

80-
public static double to_degrees(Object object) {
81-
if (object == null) return 0;
82-
if (object instanceof Number number) return Math.toDegrees(number.doubleValue());
83-
throw new ScriptRuntimeError("Unable to to_degrees(" + object + ") - not a number.");
64+
public static double to_degrees(double number) {
65+
if (number == 0) return 0;
66+
return Math.toDegrees(number);
8467
}
8568

86-
public static double to_radians(Object object) {
87-
if (object == null) return 0;
88-
if (object instanceof Number number) return Math.toRadians(number.doubleValue());
89-
throw new ScriptRuntimeError("Unable to to_radians(" + object + ") - not a number.");
69+
public static double to_radians(double number) {
70+
if (number == 0) return 0;
71+
return Math.toRadians(number);
9072
}
9173

9274
public static Number abs(Object object) {
@@ -100,17 +82,16 @@ public static Number abs(Object object) {
10082
throw new ScriptRuntimeError("Unable to abs(" + object + ") - not a number.");
10183
}
10284

103-
public static double sqrt(Object object) {
104-
if (object == null) return 0;
105-
if (object instanceof Number number) return Math.sqrt(number.doubleValue());
106-
throw new ScriptRuntimeError("Unable to sqrt(" + object + ") - not a number.");
85+
public static double sqrt(double number) {
86+
if (number == 0) return 0;
87+
return Math.sqrt(number);
10788
}
10889

10990
public static double newton_root(Object object, Object accuracy) {
11091
if (object == null) return 0;
11192
final int times = (accuracy instanceof Number number) ? number.intValue() : 1;
11293
if (!(object instanceof Number number))
113-
throw new ScriptRuntimeError("Unable to sqrt(" + object + ") - not a number.");
94+
throw new ScriptRuntimeError("Unable to root(" + object + ") - not a number.");
11495
final double value = number.doubleValue();
11596
double result = Double.longBitsToDouble(((Double.doubleToLongBits(value) - (1L << 52)) >> 1) + (1L << 61));
11697
for (int i = 0; i < times; i++) {
@@ -119,23 +100,19 @@ public static double newton_root(Object object, Object accuracy) {
119100
return result;
120101
}
121102

122-
public static double ceil(Object object) {
123-
if (object == null) return 0;
124-
if (object instanceof Number number) return Math.ceil(number.doubleValue());
125-
throw new ScriptRuntimeError("Unable to ceil(" + object + ") - not a number.");
103+
public static double ceil(double number) {
104+
if (number == 0) return 0;
105+
return Math.ceil(number);
126106
}
127107

128-
public static double floor(Object object) {
129-
if (object == null) return 0;
130-
if (object instanceof Number number) return Math.floor(number.doubleValue());
131-
throw new ScriptRuntimeError("Unable to floor(" + object + ") - not a number.");
108+
public static double floor(double number) {
109+
if (number == 0) return 0;
110+
return Math.floor(number);
132111
}
133112

134-
public static long round(Object object) {
135-
if (object == null) return 0;
136-
if (object instanceof Float number) return Math.round(number.doubleValue());
137-
if (object instanceof Number number) return Math.round(number.doubleValue());
138-
throw new ScriptRuntimeError("Unable to round(" + object + ") - not a number.");
113+
public static int round(double number) {
114+
if (number == 0) return 0;
115+
return (int) Math.round(number);
139116
}
140117

141118
public static double ln(Object object) {

0 commit comments

Comments
 (0)