mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Расширенные числовые типы
This commit is contained in:
parent
d737844913
commit
8a3719d67d
@ -5,4 +5,8 @@ public final class OperationIsNotSupportedException extends RuntimeException {
|
|||||||
public OperationIsNotSupportedException(Object operation) {
|
public OperationIsNotSupportedException(Object operation) {
|
||||||
super("Operation " + operation + " is not supported");
|
super("Operation " + operation + " is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OperationIsNotSupportedException(Object operation, String message) {
|
||||||
|
super("Operation " + operation + " is not supported " + message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,11 @@ public final class ArrayValue implements Value, Iterable<Value> {
|
|||||||
elements[index] = value;
|
elements[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int asInt() {
|
||||||
|
throw new TypeException("Cannot cast array to integer");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double asNumber() {
|
public double asNumber() {
|
||||||
throw new TypeException("Cannot cast array to number");
|
throw new TypeException("Cannot cast array to number");
|
||||||
|
@ -22,6 +22,11 @@ public final class FunctionValue implements Value {
|
|||||||
return Types.FUNCTION;
|
return Types.FUNCTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int asInt() {
|
||||||
|
throw new TypeException("Cannot cast function to integer");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double asNumber() {
|
public double asNumber() {
|
||||||
throw new TypeException("Cannot cast function to number");
|
throw new TypeException("Cannot cast function to number");
|
||||||
|
@ -44,6 +44,11 @@ public class MapValue implements Value, Iterable<Map.Entry<Value, Value>> {
|
|||||||
public void set(Value key, Value value) {
|
public void set(Value key, Value value) {
|
||||||
map.put(key, value);
|
map.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int asInt() {
|
||||||
|
throw new TypeException("Cannot cast map to integer");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double asNumber() {
|
public double asNumber() {
|
||||||
|
@ -6,6 +6,7 @@ package com.annimon.ownlang.lib;
|
|||||||
*/
|
*/
|
||||||
public final class NumberValue implements Value {
|
public final class NumberValue implements Value {
|
||||||
|
|
||||||
|
public static final NumberValue MINUS_ONE = new NumberValue(-1);
|
||||||
public static final NumberValue ZERO = new NumberValue(0);
|
public static final NumberValue ZERO = new NumberValue(0);
|
||||||
public static final NumberValue ONE = new NumberValue(1);
|
public static final NumberValue ONE = new NumberValue(1);
|
||||||
|
|
||||||
@ -13,9 +14,9 @@ public final class NumberValue implements Value {
|
|||||||
return b ? ONE : ZERO;
|
return b ? ONE : ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final double value;
|
private final Number value;
|
||||||
|
|
||||||
public NumberValue(double value) {
|
public NumberValue(Number value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,20 +25,53 @@ public final class NumberValue implements Value {
|
|||||||
return Types.NUMBER;
|
return Types.NUMBER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Number raw() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean asBoolean() {
|
||||||
|
return value.intValue() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte asByte() {
|
||||||
|
return value.byteValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public short asShort() {
|
||||||
|
return value.shortValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int asInt() {
|
||||||
|
return value.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long asLong() {
|
||||||
|
return value.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float asFloat() {
|
||||||
|
return value.floatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double asDouble() {
|
||||||
|
return value.doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double asNumber() {
|
public double asNumber() {
|
||||||
return value;
|
return value.doubleValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String asString() {
|
public String asString() {
|
||||||
return Double.toString(value);
|
return value.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int hash = 3;
|
int hash = 3;
|
||||||
hash = 71 * hash + (int) (Double.doubleToLongBits(this.value) ^ (Double.doubleToLongBits(this.value) >>> 32));
|
hash = 71 * hash + value.hashCode();
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,14 +81,33 @@ public final class NumberValue implements Value {
|
|||||||
if (obj == null) return false;
|
if (obj == null) return false;
|
||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
final NumberValue other = (NumberValue) obj;
|
final Number other = ((NumberValue) obj).value;
|
||||||
return Double.doubleToLongBits(this.value) == Double.doubleToLongBits(other.value);
|
if (value instanceof Double || other instanceof Double) {
|
||||||
|
return Double.compare(value.doubleValue(), other.doubleValue()) == 0;
|
||||||
|
}
|
||||||
|
if (value instanceof Float || other instanceof Float) {
|
||||||
|
return Float.compare(value.floatValue(), other.floatValue()) == 0;
|
||||||
|
}
|
||||||
|
if (value instanceof Long || other instanceof Long) {
|
||||||
|
return Long.compare(value.longValue(), other.longValue()) == 0;
|
||||||
|
}
|
||||||
|
return Integer.compare(value.intValue(), other.intValue()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Value o) {
|
public int compareTo(Value o) {
|
||||||
if (o.type() == Types.NUMBER) {
|
if (o.type() == Types.NUMBER) {
|
||||||
return Double.compare(value, ((NumberValue)o).value);
|
final Number other = ((NumberValue) o).value;
|
||||||
|
if (value instanceof Double || other instanceof Double) {
|
||||||
|
return Double.compare(value.doubleValue(), other.doubleValue());
|
||||||
|
}
|
||||||
|
if (value instanceof Float || other instanceof Float) {
|
||||||
|
return Float.compare(value.floatValue(), other.floatValue());
|
||||||
|
}
|
||||||
|
if (value instanceof Long || other instanceof Long) {
|
||||||
|
return Long.compare(value.longValue(), other.longValue());
|
||||||
|
}
|
||||||
|
return Integer.compare(value.intValue(), other.intValue());
|
||||||
}
|
}
|
||||||
return asString().compareTo(o.asString());
|
return asString().compareTo(o.asString());
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,15 @@ public final class StringValue implements Value {
|
|||||||
return Types.STRING;
|
return Types.STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int asInt() {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(value);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double asNumber() {
|
public double asNumber() {
|
||||||
try {
|
try {
|
||||||
|
@ -9,4 +9,14 @@ public final class Types {
|
|||||||
ARRAY = 3,
|
ARRAY = 3,
|
||||||
MAP = 4,
|
MAP = 4,
|
||||||
FUNCTION = 5;
|
FUNCTION = 5;
|
||||||
|
|
||||||
|
private static int FIRST = OBJECT, LAST = FUNCTION;
|
||||||
|
private static final String[] NAMES = {"object", "number", "string", "array", "map", "function"};
|
||||||
|
|
||||||
|
public static String typeToString(int type) {
|
||||||
|
if (FIRST <= type && type <= LAST) {
|
||||||
|
return NAMES[type];
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ package com.annimon.ownlang.lib;
|
|||||||
*/
|
*/
|
||||||
public interface Value extends Comparable<Value> {
|
public interface Value extends Comparable<Value> {
|
||||||
|
|
||||||
|
int asInt();
|
||||||
|
|
||||||
double asNumber();
|
double asNumber();
|
||||||
|
|
||||||
String asString();
|
String asString();
|
||||||
|
@ -22,8 +22,6 @@ import javax.swing.JPanel;
|
|||||||
*/
|
*/
|
||||||
public final class canvas implements Module {
|
public final class canvas implements Module {
|
||||||
|
|
||||||
private static final NumberValue MINUS_ONE = new NumberValue(-1);
|
|
||||||
|
|
||||||
private static JFrame frame;
|
private static JFrame frame;
|
||||||
private static CanvasPanel panel;
|
private static CanvasPanel panel;
|
||||||
private static Graphics2D graphics;
|
private static Graphics2D graphics;
|
||||||
@ -55,7 +53,7 @@ public final class canvas implements Module {
|
|||||||
Variables.set("VK_FIRE", new NumberValue(KeyEvent.VK_ENTER));
|
Variables.set("VK_FIRE", new NumberValue(KeyEvent.VK_ENTER));
|
||||||
Variables.set("VK_ESCAPE", new NumberValue(KeyEvent.VK_ESCAPE));
|
Variables.set("VK_ESCAPE", new NumberValue(KeyEvent.VK_ESCAPE));
|
||||||
|
|
||||||
lastKey = MINUS_ONE;
|
lastKey = NumberValue.MINUS_ONE;
|
||||||
mouseHover = new ArrayValue(new Value[] { NumberValue.ZERO, NumberValue.ZERO });
|
mouseHover = new ArrayValue(new Value[] { NumberValue.ZERO, NumberValue.ZERO });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,11 +89,7 @@ public final class canvas implements Module {
|
|||||||
private static Function intConsumer4Convert(IntConsumer4 consumer) {
|
private static Function intConsumer4Convert(IntConsumer4 consumer) {
|
||||||
return args -> {
|
return args -> {
|
||||||
if (args.length != 4) throw new ArgumentsMismatchException("Four args expected");
|
if (args.length != 4) throw new ArgumentsMismatchException("Four args expected");
|
||||||
int x = (int) args[0].asNumber();
|
consumer.accept(args[0].asInt(), args[1].asInt(), args[2].asInt(), args[3].asInt());
|
||||||
int y = (int) args[1].asNumber();
|
|
||||||
int w = (int) args[2].asNumber();
|
|
||||||
int h = (int) args[3].asNumber();
|
|
||||||
consumer.accept(x, y, w, h);
|
|
||||||
return NumberValue.ZERO;
|
return NumberValue.ZERO;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -116,7 +110,7 @@ public final class canvas implements Module {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void keyReleased(KeyEvent e) {
|
public void keyReleased(KeyEvent e) {
|
||||||
lastKey = MINUS_ONE;
|
lastKey = NumberValue.MINUS_ONE;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
addMouseMotionListener(new MouseMotionAdapter() {
|
addMouseMotionListener(new MouseMotionAdapter() {
|
||||||
@ -147,13 +141,13 @@ public final class canvas implements Module {
|
|||||||
title = args[0].asString();
|
title = args[0].asString();
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
width = (int) args[0].asNumber();
|
width = args[0].asInt();
|
||||||
height = (int) args[1].asNumber();
|
height = args[1].asInt();
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
title = args[0].asString();
|
title = args[0].asString();
|
||||||
width = (int) args[1].asNumber();
|
width = args[1].asInt();
|
||||||
height = (int) args[2].asNumber();
|
height = args[2].asInt();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
panel = new CanvasPanel(width, height);
|
panel = new CanvasPanel(width, height);
|
||||||
@ -188,8 +182,8 @@ public final class canvas implements Module {
|
|||||||
@Override
|
@Override
|
||||||
public Value execute(Value... args) {
|
public Value execute(Value... args) {
|
||||||
if (args.length != 3) throw new ArgumentsMismatchException("Three args expected");
|
if (args.length != 3) throw new ArgumentsMismatchException("Three args expected");
|
||||||
int x = (int) args[1].asNumber();
|
int x = args[1].asInt();
|
||||||
int y = (int) args[2].asNumber();
|
int y = args[2].asInt();
|
||||||
graphics.drawString(args[0].asString(), x, y);
|
graphics.drawString(args[0].asString(), x, y);
|
||||||
return NumberValue.ZERO;
|
return NumberValue.ZERO;
|
||||||
}
|
}
|
||||||
@ -219,12 +213,12 @@ public final class canvas implements Module {
|
|||||||
@Override
|
@Override
|
||||||
public Value execute(Value... args) {
|
public Value execute(Value... args) {
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
graphics.setColor(new Color((int) args[0].asNumber()));
|
graphics.setColor(new Color(args[0].asInt()));
|
||||||
return NumberValue.ZERO;
|
return NumberValue.ZERO;
|
||||||
}
|
}
|
||||||
int r = (int) args[0].asNumber();
|
int r = args[0].asInt();
|
||||||
int g = (int) args[1].asNumber();
|
int g = args[1].asInt();
|
||||||
int b = (int) args[2].asNumber();
|
int b = args[2].asInt();
|
||||||
graphics.setColor(new Color(r, g, b));
|
graphics.setColor(new Color(r, g, b));
|
||||||
return NumberValue.ZERO;
|
return NumberValue.ZERO;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ public final class files implements Module {
|
|||||||
}
|
}
|
||||||
return process(file, "r");
|
return process(file, "r");
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
return new NumberValue(-1);
|
return NumberValue.MINUS_ONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ public final class files implements Module {
|
|||||||
@Override
|
@Override
|
||||||
public Value execute(Value... args) {
|
public Value execute(Value... args) {
|
||||||
if (args.length < 1) throw new ArgumentsMismatchException("File descriptor expected");
|
if (args.length < 1) throw new ArgumentsMismatchException("File descriptor expected");
|
||||||
final int key = (int) args[0].asNumber();
|
final int key = args[0].asInt();
|
||||||
try {
|
try {
|
||||||
return execute(files.get(key), args);
|
return execute(files.get(key), args);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
@ -115,7 +115,7 @@ public final class files implements Module {
|
|||||||
private static class readBoolean extends FileFunction {
|
private static class readBoolean extends FileFunction {
|
||||||
@Override
|
@Override
|
||||||
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
||||||
return new NumberValue(fileInfo.dis.readBoolean() ? 1 : 0);
|
return NumberValue.fromBoolean(fileInfo.dis.readBoolean());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,8 +132,8 @@ public final class files implements Module {
|
|||||||
final ArrayValue array = (ArrayValue) args[1];
|
final ArrayValue array = (ArrayValue) args[1];
|
||||||
int offset = 0, length = array.size();
|
int offset = 0, length = array.size();
|
||||||
if (args.length > 3) {
|
if (args.length > 3) {
|
||||||
offset = (int) args[2].asNumber();
|
offset = args[2].asInt();
|
||||||
length = (int) args[3].asNumber();
|
length = args[3].asInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
final byte[] buffer = new byte[length];
|
final byte[] buffer = new byte[length];
|
||||||
@ -170,7 +170,7 @@ public final class files implements Module {
|
|||||||
private static class readChar extends FileFunction {
|
private static class readChar extends FileFunction {
|
||||||
@Override
|
@Override
|
||||||
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
||||||
return new NumberValue(fileInfo.dis.readChar());
|
return new NumberValue((short)fileInfo.dis.readChar());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +239,7 @@ public final class files implements Module {
|
|||||||
private static class writeBoolean extends FileFunction {
|
private static class writeBoolean extends FileFunction {
|
||||||
@Override
|
@Override
|
||||||
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
||||||
fileInfo.dos.writeBoolean(args[1].asNumber() != 0);
|
fileInfo.dos.writeBoolean(args[1].asInt() != 0);
|
||||||
return NumberValue.ONE;
|
return NumberValue.ONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,7 +247,7 @@ public final class files implements Module {
|
|||||||
private static class writeByte extends FileFunction {
|
private static class writeByte extends FileFunction {
|
||||||
@Override
|
@Override
|
||||||
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
||||||
fileInfo.dos.writeByte((byte) args[1].asNumber());
|
fileInfo.dos.writeByte((byte) args[1].asInt());
|
||||||
return NumberValue.ONE;
|
return NumberValue.ONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,7 +256,7 @@ public final class files implements Module {
|
|||||||
@Override
|
@Override
|
||||||
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
||||||
final char ch = (args[1].type() == Types.NUMBER)
|
final char ch = (args[1].type() == Types.NUMBER)
|
||||||
? ((char) args[1].asNumber())
|
? ((char) args[1].asInt())
|
||||||
: args[1].asString().charAt(0);
|
: args[1].asString().charAt(0);
|
||||||
fileInfo.dos.writeChar(ch);
|
fileInfo.dos.writeChar(ch);
|
||||||
return NumberValue.ONE;
|
return NumberValue.ONE;
|
||||||
@ -266,7 +266,7 @@ public final class files implements Module {
|
|||||||
private static class writeShort extends FileFunction {
|
private static class writeShort extends FileFunction {
|
||||||
@Override
|
@Override
|
||||||
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
||||||
fileInfo.dos.writeShort((short) args[1].asNumber());
|
fileInfo.dos.writeShort((short) args[1].asInt());
|
||||||
return NumberValue.ONE;
|
return NumberValue.ONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,7 +274,7 @@ public final class files implements Module {
|
|||||||
private static class writeInt extends FileFunction {
|
private static class writeInt extends FileFunction {
|
||||||
@Override
|
@Override
|
||||||
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
||||||
fileInfo.dos.writeInt((int) args[1].asNumber());
|
fileInfo.dos.writeInt(args[1].asInt());
|
||||||
return NumberValue.ONE;
|
return NumberValue.ONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ public final class http_http implements Function {
|
|||||||
|
|
||||||
private RequestBody getMapRequestBody(MapValue params, MapValue options) throws UnsupportedEncodingException {
|
private RequestBody getMapRequestBody(MapValue params, MapValue options) throws UnsupportedEncodingException {
|
||||||
final FormBody.Builder form = new FormBody.Builder();
|
final FormBody.Builder form = new FormBody.Builder();
|
||||||
final boolean alreadyEncoded = (options.containsKey(ENCODED_KEY) && options.get(ENCODED_KEY).asNumber() != 0);
|
final boolean alreadyEncoded = (options.containsKey(ENCODED_KEY) && options.get(ENCODED_KEY).asInt() != 0);
|
||||||
for (Map.Entry<Value, Value> param : params) {
|
for (Map.Entry<Value, Value> param : params) {
|
||||||
final String name = param.getKey().asString();
|
final String name = param.getKey().asString();
|
||||||
final String value = param.getValue().asString();
|
final String value = param.getValue().asString();
|
||||||
|
@ -30,7 +30,7 @@ public final class json_decode implements Function {
|
|||||||
return new StringValue((String) obj);
|
return new StringValue((String) obj);
|
||||||
}
|
}
|
||||||
if (obj instanceof Number) {
|
if (obj instanceof Number) {
|
||||||
return new NumberValue(((Number) obj).doubleValue());
|
return new NumberValue(((Number) obj));
|
||||||
}
|
}
|
||||||
if (obj instanceof Boolean) {
|
if (obj instanceof Boolean) {
|
||||||
return NumberValue.fromBoolean((Boolean) obj);
|
return NumberValue.fromBoolean((Boolean) obj);
|
||||||
|
@ -26,7 +26,7 @@ public final class json_encode implements Function {
|
|||||||
case Types.MAP:
|
case Types.MAP:
|
||||||
return process((MapValue) val);
|
return process((MapValue) val);
|
||||||
case Types.NUMBER:
|
case Types.NUMBER:
|
||||||
return val.asNumber();
|
return ((NumberValue) val).raw();
|
||||||
case Types.STRING:
|
case Types.STRING:
|
||||||
return val.asString();
|
return val.asString();
|
||||||
default:
|
default:
|
||||||
|
@ -10,8 +10,8 @@ public final class std_charat implements Function {
|
|||||||
if (args.length != 2) throw new ArgumentsMismatchException("Two arguments expected");
|
if (args.length != 2) throw new ArgumentsMismatchException("Two arguments expected");
|
||||||
|
|
||||||
final String input = args[0].asString();
|
final String input = args[0].asString();
|
||||||
final int index = (int) args[1].asNumber();
|
final int index = args[1].asInt();
|
||||||
|
|
||||||
return new NumberValue(input.charAt(index));
|
return new NumberValue((short)input.charAt(index));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,7 +11,7 @@ public final class std_indexof implements Function {
|
|||||||
|
|
||||||
final String input = args[0].asString();
|
final String input = args[0].asString();
|
||||||
final String what = args[1].asString();
|
final String what = args[1].asString();
|
||||||
final int index = (args.length == 3) ? ((int) args[2].asNumber()) : 0;
|
final int index = (args.length == 3) ? args[2].asInt() : 0;
|
||||||
|
|
||||||
return new NumberValue(input.indexOf(what, index));
|
return new NumberValue(input.indexOf(what, index));
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ public final class std_lastindexof implements Function {
|
|||||||
|
|
||||||
final String input = args[0].asString();
|
final String input = args[0].asString();
|
||||||
final String what = args[1].asString();
|
final String what = args[1].asString();
|
||||||
final int index = (args.length == 3) ? ((int) args[2].asNumber()) : 0;
|
final int index = (args.length == 3) ? args[2].asInt() : 0;
|
||||||
|
|
||||||
return new NumberValue(input.lastIndexOf(what, index));
|
return new NumberValue(input.lastIndexOf(what, index));
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ public final class std_newarray implements Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ArrayValue createArray(Value[] args, int index) {
|
private ArrayValue createArray(Value[] args, int index) {
|
||||||
final int size = (int) args[index].asNumber();
|
final int size = args[index].asInt();
|
||||||
final int last = args.length - 1;
|
final int last = args.length - 1;
|
||||||
ArrayValue array = new ArrayValue(size);
|
ArrayValue array = new ArrayValue(size);
|
||||||
if (index == last) {
|
if (index == last) {
|
||||||
|
@ -17,10 +17,10 @@ public final class std_rand implements Function {
|
|||||||
int from = 0;
|
int from = 0;
|
||||||
int to = 100;
|
int to = 100;
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
to = (int) args[0].asNumber();
|
to = args[0].asInt();
|
||||||
} else if (args.length == 2) {
|
} else if (args.length == 2) {
|
||||||
from = (int) args[0].asNumber();
|
from = args[0].asInt();
|
||||||
to = (int) args[1].asNumber();
|
to = args[1].asInt();
|
||||||
}
|
}
|
||||||
return new NumberValue(RND.nextInt(to - from) + from);
|
return new NumberValue(RND.nextInt(to - from) + from);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ public final class std_sort implements Function {
|
|||||||
throw new TypeException("Function expected in second argument");
|
throw new TypeException("Function expected in second argument");
|
||||||
}
|
}
|
||||||
final Function comparator = ((FunctionValue) args[1]).getValue();
|
final Function comparator = ((FunctionValue) args[1]).getValue();
|
||||||
Arrays.sort(elements, (o1, o2) -> (int) comparator.execute(o1, o2).asNumber());
|
Arrays.sort(elements, (o1, o2) -> comparator.execute(o1, o2).asInt());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentsMismatchException("Wrong number of arguments");
|
throw new ArgumentsMismatchException("Wrong number of arguments");
|
||||||
|
@ -11,7 +11,7 @@ public final class std_split implements Function {
|
|||||||
|
|
||||||
final String input = args[0].asString();
|
final String input = args[0].asString();
|
||||||
final String regex = args[1].asString();
|
final String regex = args[1].asString();
|
||||||
final int limit = (args.length == 3) ? ((int) args[2].asNumber()) : 0;
|
final int limit = (args.length == 3) ? args[2].asInt() : 0;
|
||||||
|
|
||||||
final String[] parts = input.split(regex, limit);
|
final String[] parts = input.split(regex, limit);
|
||||||
final ArrayValue result = new ArrayValue(parts.length);
|
final ArrayValue result = new ArrayValue(parts.length);
|
||||||
|
@ -12,7 +12,9 @@ public final class std_sprintf implements Function {
|
|||||||
final String format = args[0].asString();
|
final String format = args[0].asString();
|
||||||
final Object[] values = new Object[args.length - 1];
|
final Object[] values = new Object[args.length - 1];
|
||||||
for (int i = 1; i < args.length; i++) {
|
for (int i = 1; i < args.length; i++) {
|
||||||
values[i - 1] = (args[i].type() == Types.NUMBER) ? args[i].asNumber() : args[i].asString();
|
values[i - 1] = (args[i].type() == Types.NUMBER)
|
||||||
|
? ((NumberValue) args[i]).raw()
|
||||||
|
: args[i].asString();
|
||||||
}
|
}
|
||||||
return new StringValue(String.format(format, values));
|
return new StringValue(String.format(format, values));
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,13 @@ public final class std_substring implements Function {
|
|||||||
if (args.length < 2 || args.length > 3) throw new ArgumentsMismatchException("Two or three arguments expected");
|
if (args.length < 2 || args.length > 3) throw new ArgumentsMismatchException("Two or three arguments expected");
|
||||||
|
|
||||||
final String input = args[0].asString();
|
final String input = args[0].asString();
|
||||||
final int startIndex = (int) args[1].asNumber();
|
final int startIndex = args[1].asInt();
|
||||||
|
|
||||||
String result;
|
String result;
|
||||||
if (args.length == 2) {
|
if (args.length == 2) {
|
||||||
result = input.substring(startIndex);
|
result = input.substring(startIndex);
|
||||||
} else {
|
} else {
|
||||||
final int endIndex = (int) args[2].asNumber();
|
final int endIndex = args[2].asInt();
|
||||||
result = input.substring(startIndex, endIndex);
|
result = input.substring(startIndex, endIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ public final class std_tochar implements Function {
|
|||||||
public Value execute(Value... args) {
|
public Value execute(Value... args) {
|
||||||
if (args.length != 1) throw new ArgumentsMismatchException("One argument expected");
|
if (args.length != 1) throw new ArgumentsMismatchException("One argument expected");
|
||||||
|
|
||||||
return new StringValue(String.valueOf((char) args[0].asNumber()));
|
return new StringValue(String.valueOf((char) args[0].asInt()));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -45,7 +45,7 @@ public final class robot implements Module {
|
|||||||
Functions.set("mouseMove", (args) -> {
|
Functions.set("mouseMove", (args) -> {
|
||||||
if (args.length != 2) throw new ArgumentsMismatchException("Two arguments expected");
|
if (args.length != 2) throw new ArgumentsMismatchException("Two arguments expected");
|
||||||
try {
|
try {
|
||||||
awtRobot.mouseMove((int) args[0].asNumber(), (int) args[1].asNumber());
|
awtRobot.mouseMove(args[0].asInt(), args[1].asInt());
|
||||||
} catch (IllegalArgumentException iae) { }
|
} catch (IllegalArgumentException iae) { }
|
||||||
return NumberValue.ZERO;
|
return NumberValue.ZERO;
|
||||||
});
|
});
|
||||||
@ -89,7 +89,7 @@ public final class robot implements Module {
|
|||||||
return args -> {
|
return args -> {
|
||||||
if (args.length != 1) throw new ArgumentsMismatchException("One argument expected");
|
if (args.length != 1) throw new ArgumentsMismatchException("One argument expected");
|
||||||
try {
|
try {
|
||||||
consumer.accept((int) args[0].asNumber());
|
consumer.accept(args[0].asInt());
|
||||||
} catch (IllegalArgumentException iae) { }
|
} catch (IllegalArgumentException iae) { }
|
||||||
return NumberValue.ZERO;
|
return NumberValue.ZERO;
|
||||||
};
|
};
|
||||||
|
@ -20,5 +20,12 @@ public final class types implements Module {
|
|||||||
Functions.set("typeof", args -> new NumberValue(args[0].type()));
|
Functions.set("typeof", args -> new NumberValue(args[0].type()));
|
||||||
Functions.set("string", args -> new StringValue(args[0].asString()));
|
Functions.set("string", args -> new StringValue(args[0].asString()));
|
||||||
Functions.set("number", args -> new NumberValue(args[0].asNumber()));
|
Functions.set("number", args -> new NumberValue(args[0].asNumber()));
|
||||||
|
|
||||||
|
Functions.set("byte", args -> new NumberValue((byte)args[0].asInt()));
|
||||||
|
Functions.set("short", args -> new NumberValue((short)args[0].asInt()));
|
||||||
|
Functions.set("int", args -> new NumberValue(args[0].asInt()));
|
||||||
|
Functions.set("long", args -> new NumberValue((long)args[0].asNumber()));
|
||||||
|
Functions.set("float", args -> new NumberValue((float)args[0].asNumber()));
|
||||||
|
Functions.set("double", args -> new NumberValue(args[0].asNumber()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,12 +327,12 @@ public final class Parser {
|
|||||||
if (match(TokenType.NUMBER)) {
|
if (match(TokenType.NUMBER)) {
|
||||||
// case 0.5:
|
// case 0.5:
|
||||||
pattern = new MatchExpression.ConstantPattern(
|
pattern = new MatchExpression.ConstantPattern(
|
||||||
new NumberValue(Double.parseDouble(current.getText()))
|
new NumberValue(createNumber(current.getText(), 10))
|
||||||
);
|
);
|
||||||
} else if (match(TokenType.HEX_NUMBER)) {
|
} else if (match(TokenType.HEX_NUMBER)) {
|
||||||
// case #FF:
|
// case #FF:
|
||||||
pattern = new MatchExpression.ConstantPattern(
|
pattern = new MatchExpression.ConstantPattern(
|
||||||
new NumberValue(Long.parseLong(current.getText(), 16))
|
new NumberValue(createNumber(current.getText(), 16))
|
||||||
);
|
);
|
||||||
} else if (match(TokenType.TEXT)) {
|
} else if (match(TokenType.TEXT)) {
|
||||||
// case "text":
|
// case "text":
|
||||||
@ -703,10 +703,10 @@ public final class Parser {
|
|||||||
private Expression value() {
|
private Expression value() {
|
||||||
final Token current = get(0);
|
final Token current = get(0);
|
||||||
if (match(TokenType.NUMBER)) {
|
if (match(TokenType.NUMBER)) {
|
||||||
return new ValueExpression(Double.parseDouble(current.getText()));
|
return new ValueExpression(createNumber(current.getText(), 10));
|
||||||
}
|
}
|
||||||
if (match(TokenType.HEX_NUMBER)) {
|
if (match(TokenType.HEX_NUMBER)) {
|
||||||
return new ValueExpression(Long.parseLong(current.getText(), 16));
|
return new ValueExpression(createNumber(current.getText(), 16));
|
||||||
}
|
}
|
||||||
if (match(TokenType.TEXT)) {
|
if (match(TokenType.TEXT)) {
|
||||||
return new ValueExpression(current.getText());
|
return new ValueExpression(current.getText());
|
||||||
@ -714,6 +714,19 @@ public final class Parser {
|
|||||||
throw new ParseException("Unknown expression: " + current);
|
throw new ParseException("Unknown expression: " + current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Number createNumber(String text, int radix) {
|
||||||
|
// Double
|
||||||
|
if (text.contains(".")) {
|
||||||
|
return Double.parseDouble(text);
|
||||||
|
}
|
||||||
|
// Integer
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(text, radix);
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
return Long.parseLong(text, radix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Token consume(TokenType type) {
|
private Token consume(TokenType type) {
|
||||||
final Token current = get(0);
|
final Token current = get(0);
|
||||||
if (type != current.getType()) throw new ParseException("Token " + current + " doesn't match " + type);
|
if (type != current.getType()) throw new ParseException("Token " + current + " doesn't match " + type);
|
||||||
|
@ -54,70 +54,384 @@ public final class BinaryExpression implements Expression {
|
|||||||
public Value eval() {
|
public Value eval() {
|
||||||
final Value value1 = expr1.eval();
|
final Value value1 = expr1.eval();
|
||||||
final Value value2 = expr2.eval();
|
final Value value2 = expr2.eval();
|
||||||
|
switch (operation) {
|
||||||
switch (value1.type()) {
|
case ADD: return add(value1, value2);
|
||||||
case Types.STRING:
|
case SUBTRACT: return subtract(value1, value2);
|
||||||
return eval((StringValue) value1, value2);
|
case MULTIPLY: return multiply(value1, value2);
|
||||||
case Types.ARRAY:
|
case DIVIDE: return divide(value1, value2);
|
||||||
return eval((ArrayValue) value1, value2);
|
case REMAINDER: return remainder(value1, value2);
|
||||||
case Types.NUMBER:
|
case PUSH: return push(value1, value2);
|
||||||
|
case AND: return and(value1, value2);
|
||||||
|
case OR: return or(value1, value2);
|
||||||
|
case XOR: return xor(value1, value2);
|
||||||
|
case LSHIFT: return lshift(value1, value2);
|
||||||
|
case RSHIFT: return rshift(value1, value2);
|
||||||
|
case URSHIFT: return urshift(value1, value2);
|
||||||
default:
|
default:
|
||||||
return eval(value1, value2);
|
throw new OperationIsNotSupportedException(operation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Value eval(StringValue value1, Value value2) {
|
private Value add(Value value1, Value value2) {
|
||||||
final String string1 = value1.asString();
|
switch (value1.type()) {
|
||||||
switch (operation) {
|
case Types.NUMBER: return add((NumberValue) value1, value2);
|
||||||
case MULTIPLY: {
|
case Types.ARRAY: return ArrayValue.add((ArrayValue) value1, value2);
|
||||||
final int iterations = (int) value2.asNumber();
|
case Types.MAP: /* TODO: merge maps */
|
||||||
|
case Types.FUNCTION: /* TODO: combining functions */
|
||||||
|
case Types.STRING:
|
||||||
|
default:
|
||||||
|
// Concatenation strings
|
||||||
|
return new StringValue(value1.asString() + value2.asString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value add(NumberValue value1, Value value2) {
|
||||||
|
final Number number1 = value1.raw();
|
||||||
|
if (value2.type() == Types.NUMBER) {
|
||||||
|
// number1 + number2
|
||||||
|
final Number number2 = ((NumberValue) value2).raw();
|
||||||
|
if (number1 instanceof Double || number2 instanceof Double) {
|
||||||
|
return new NumberValue(number1.doubleValue() + number2.doubleValue());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Float || number2 instanceof Float) {
|
||||||
|
return new NumberValue(number1.floatValue() + number2.floatValue());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Long || number2 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() + number2.longValue());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() + number2.intValue());
|
||||||
|
}
|
||||||
|
// number1 + other
|
||||||
|
if (number1 instanceof Double) {
|
||||||
|
return new NumberValue(number1.doubleValue() + value2.asNumber());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Float) {
|
||||||
|
return new NumberValue(number1.floatValue() + value2.asNumber());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() + value2.asInt());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() + value2.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value subtract(Value value1, Value value2) {
|
||||||
|
switch (value1.type()) {
|
||||||
|
case Types.NUMBER: return subtract((NumberValue) value1, value2);
|
||||||
|
default:
|
||||||
|
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value subtract(NumberValue value1, Value value2) {
|
||||||
|
final Number number1 = value1.raw();
|
||||||
|
if (value2.type() == Types.NUMBER) {
|
||||||
|
// number1 - number2
|
||||||
|
final Number number2 = ((NumberValue) value2).raw();
|
||||||
|
if (number1 instanceof Double || number2 instanceof Double) {
|
||||||
|
return new NumberValue(number1.doubleValue() - number2.doubleValue());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Float || number2 instanceof Float) {
|
||||||
|
return new NumberValue(number1.floatValue() - number2.floatValue());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Long || number2 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() - number2.longValue());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() - number2.intValue());
|
||||||
|
}
|
||||||
|
// number1 - other
|
||||||
|
if (number1 instanceof Double) {
|
||||||
|
return new NumberValue(number1.doubleValue() - value2.asNumber());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Float) {
|
||||||
|
return new NumberValue(number1.floatValue() - value2.asNumber());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() - value2.asInt());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() - value2.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value multiply(Value value1, Value value2) {
|
||||||
|
switch (value1.type()) {
|
||||||
|
case Types.NUMBER: return multiply((NumberValue) value1, value2);
|
||||||
|
case Types.STRING: {
|
||||||
|
final String string1 = value1.asString();
|
||||||
|
final int iterations = value2.asInt();
|
||||||
final StringBuilder buffer = new StringBuilder();
|
final StringBuilder buffer = new StringBuilder();
|
||||||
for (int i = 0; i < iterations; i++) {
|
for (int i = 0; i < iterations; i++) {
|
||||||
buffer.append(string1);
|
buffer.append(string1);
|
||||||
}
|
}
|
||||||
return new StringValue(buffer.toString());
|
return new StringValue(buffer.toString());
|
||||||
}
|
}
|
||||||
case ADD:
|
|
||||||
default:
|
default:
|
||||||
return new StringValue(string1 + value2.asString());
|
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Value eval(ArrayValue value1, Value value2) {
|
private Value multiply(NumberValue value1, Value value2) {
|
||||||
switch (operation) {
|
final Number number1 = value1.raw();
|
||||||
case LSHIFT:
|
if (value2.type() == Types.NUMBER) {
|
||||||
|
// number1 * number2
|
||||||
|
final Number number2 = ((NumberValue) value2).raw();
|
||||||
|
if (number1 instanceof Double || number2 instanceof Double) {
|
||||||
|
return new NumberValue(number1.doubleValue() * number2.doubleValue());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Float || number2 instanceof Float) {
|
||||||
|
return new NumberValue(number1.floatValue() * number2.floatValue());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Long || number2 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() * number2.longValue());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() * number2.intValue());
|
||||||
|
}
|
||||||
|
// number1 * other
|
||||||
|
if (number1 instanceof Double) {
|
||||||
|
return new NumberValue(number1.doubleValue() * value2.asNumber());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Float) {
|
||||||
|
return new NumberValue(number1.floatValue() * value2.asNumber());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() * value2.asInt());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() * value2.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value divide(Value value1, Value value2) {
|
||||||
|
switch (value1.type()) {
|
||||||
|
case Types.NUMBER: return divide((NumberValue) value1, value2);
|
||||||
|
default:
|
||||||
|
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value divide(NumberValue value1, Value value2) {
|
||||||
|
final Number number1 = value1.raw();
|
||||||
|
if (value2.type() == Types.NUMBER) {
|
||||||
|
// number1 / number2
|
||||||
|
final Number number2 = ((NumberValue) value2).raw();
|
||||||
|
if (number1 instanceof Double || number2 instanceof Double) {
|
||||||
|
return new NumberValue(number1.doubleValue() / number2.doubleValue());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Float || number2 instanceof Float) {
|
||||||
|
return new NumberValue(number1.floatValue() / number2.floatValue());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Long || number2 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() / number2.longValue());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() / number2.intValue());
|
||||||
|
}
|
||||||
|
// number1 / other
|
||||||
|
if (number1 instanceof Double) {
|
||||||
|
return new NumberValue(number1.doubleValue() / value2.asNumber());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Float) {
|
||||||
|
return new NumberValue(number1.floatValue() / value2.asNumber());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() / value2.asInt());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() / value2.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value remainder(Value value1, Value value2) {
|
||||||
|
switch (value1.type()) {
|
||||||
|
case Types.NUMBER: return remainder((NumberValue) value1, value2);
|
||||||
|
default:
|
||||||
|
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value remainder(NumberValue value1, Value value2) {
|
||||||
|
final Number number1 = value1.raw();
|
||||||
|
if (value2.type() == Types.NUMBER) {
|
||||||
|
// number1 % number2
|
||||||
|
final Number number2 = ((NumberValue) value2).raw();
|
||||||
|
if (number1 instanceof Double || number2 instanceof Double) {
|
||||||
|
return new NumberValue(number1.doubleValue() % number2.doubleValue());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Float || number2 instanceof Float) {
|
||||||
|
return new NumberValue(number1.floatValue() % number2.floatValue());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Long || number2 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() % number2.longValue());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() % number2.intValue());
|
||||||
|
}
|
||||||
|
// number1 % other
|
||||||
|
if (number1 instanceof Double) {
|
||||||
|
return new NumberValue(number1.doubleValue() % value2.asNumber());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Float) {
|
||||||
|
return new NumberValue(number1.floatValue() % value2.asNumber());
|
||||||
|
}
|
||||||
|
if (number1 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() % value2.asInt());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() % value2.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value push(Value value1, Value value2) {
|
||||||
|
switch (value1.type()) {
|
||||||
|
case Types.ARRAY: return ArrayValue.add((ArrayValue) value1, value2);
|
||||||
|
default:
|
||||||
|
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value and(Value value1, Value value2) {
|
||||||
|
switch (value1.type()) {
|
||||||
|
case Types.NUMBER: return and((NumberValue) value1, value2);
|
||||||
|
default:
|
||||||
|
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value and(NumberValue value1, Value value2) {
|
||||||
|
final Number number1 = value1.raw();
|
||||||
|
if (value2.type() == Types.NUMBER) {
|
||||||
|
// number1 & number2
|
||||||
|
final Number number2 = ((NumberValue) value2).raw();
|
||||||
|
if (number1 instanceof Long || number2 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() & number2.longValue());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() & number2.intValue());
|
||||||
|
}
|
||||||
|
// number1 & other
|
||||||
|
if (number1 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() & value2.asInt());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() & value2.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value or(Value value1, Value value2) {
|
||||||
|
switch (value1.type()) {
|
||||||
|
case Types.NUMBER: return or((NumberValue) value1, value2);
|
||||||
|
default:
|
||||||
|
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value or(NumberValue value1, Value value2) {
|
||||||
|
final Number number1 = value1.raw();
|
||||||
|
if (value2.type() == Types.NUMBER) {
|
||||||
|
// number1 | number2
|
||||||
|
final Number number2 = ((NumberValue) value2).raw();
|
||||||
|
if (number1 instanceof Long || number2 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() | number2.longValue());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() | number2.intValue());
|
||||||
|
}
|
||||||
|
// number1 | other
|
||||||
|
if (number1 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() | value2.asInt());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() | value2.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value xor(Value value1, Value value2) {
|
||||||
|
switch (value1.type()) {
|
||||||
|
case Types.NUMBER: return xor((NumberValue) value1, value2);
|
||||||
|
default:
|
||||||
|
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value xor(NumberValue value1, Value value2) {
|
||||||
|
final Number number1 = value1.raw();
|
||||||
|
if (value2.type() == Types.NUMBER) {
|
||||||
|
// number1 ^ number2
|
||||||
|
final Number number2 = ((NumberValue) value2).raw();
|
||||||
|
if (number1 instanceof Long || number2 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() ^ number2.longValue());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() ^ number2.intValue());
|
||||||
|
}
|
||||||
|
// number1 ^ other
|
||||||
|
if (number1 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() ^ value2.asInt());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() ^ value2.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value lshift(Value value1, Value value2) {
|
||||||
|
switch (value1.type()) {
|
||||||
|
case Types.NUMBER: return lshift((NumberValue) value1, value2);
|
||||||
|
case Types.ARRAY: {
|
||||||
if (value2.type() != Types.ARRAY)
|
if (value2.type() != Types.ARRAY)
|
||||||
throw new TypeException("Cannot merge non array value to array");
|
throw new TypeException("Cannot merge non array value to array");
|
||||||
return ArrayValue.merge(value1, (ArrayValue) value2);
|
return ArrayValue.merge((ArrayValue) value1, (ArrayValue) value2);
|
||||||
case PUSH:
|
}
|
||||||
default:
|
default:
|
||||||
return ArrayValue.add(value1, value2);
|
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Value eval(Value value1, Value value2) {
|
private Value lshift(NumberValue value1, Value value2) {
|
||||||
final double number1 = value1.asNumber();
|
final Number number1 = value1.raw();
|
||||||
final double number2 = value2.asNumber();
|
if (value2.type() == Types.NUMBER) {
|
||||||
double result;
|
// number1 << number2
|
||||||
switch (operation) {
|
final Number number2 = ((NumberValue) value2).raw();
|
||||||
case ADD: result = number1 + number2; break;
|
if (number1 instanceof Long || number2 instanceof Long) {
|
||||||
case SUBTRACT: result = number1 - number2; break;
|
return new NumberValue(number1.longValue() << number2.longValue());
|
||||||
case MULTIPLY: result = number1 * number2; break;
|
}
|
||||||
case DIVIDE: result = number1 / number2; break;
|
return new NumberValue(number1.intValue() << number2.intValue());
|
||||||
case REMAINDER: result = number1 % number2; break;
|
|
||||||
|
|
||||||
// Bitwise
|
|
||||||
case AND: result = (int)number1 & (int)number2; break;
|
|
||||||
case XOR: result = (int)number1 ^ (int)number2; break;
|
|
||||||
case OR: result = (int)number1 | (int)number2; break;
|
|
||||||
case LSHIFT: result = (int)number1 << (int)number2; break;
|
|
||||||
case RSHIFT: result = (int)number1 >> (int)number2; break;
|
|
||||||
case URSHIFT: result = (int)number1 >>> (int)number2; break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new OperationIsNotSupportedException(operation);
|
|
||||||
}
|
}
|
||||||
return new NumberValue(result);
|
// number1 << other
|
||||||
|
if (number1 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() << value2.asInt());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() << value2.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value rshift(Value value1, Value value2) {
|
||||||
|
switch (value1.type()) {
|
||||||
|
case Types.NUMBER: return rshift((NumberValue) value1, value2);
|
||||||
|
default:
|
||||||
|
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value rshift(NumberValue value1, Value value2) {
|
||||||
|
final Number number1 = value1.raw();
|
||||||
|
if (value2.type() == Types.NUMBER) {
|
||||||
|
// number1 >> number2
|
||||||
|
final Number number2 = ((NumberValue) value2).raw();
|
||||||
|
if (number1 instanceof Long || number2 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() >> number2.longValue());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() >> number2.intValue());
|
||||||
|
}
|
||||||
|
// number1 >> other
|
||||||
|
if (number1 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() >> value2.asInt());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() >> value2.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value urshift(Value value1, Value value2) {
|
||||||
|
switch (value1.type()) {
|
||||||
|
case Types.NUMBER: return urshift((NumberValue) value1, value2);
|
||||||
|
default:
|
||||||
|
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value urshift(NumberValue value1, Value value2) {
|
||||||
|
final Number number1 = value1.raw();
|
||||||
|
if (value2.type() == Types.NUMBER) {
|
||||||
|
// number1 >>> number2
|
||||||
|
final Number number2 = ((NumberValue) value2).raw();
|
||||||
|
if (number1 instanceof Long || number2 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() >>> number2.longValue());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() >>> number2.intValue());
|
||||||
|
}
|
||||||
|
// number1 >>> other
|
||||||
|
if (number1 instanceof Long) {
|
||||||
|
return new NumberValue(number1.longValue() >>> value2.asInt());
|
||||||
|
}
|
||||||
|
return new NumberValue(number1.intValue() >>> value2.asInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -48,9 +48,9 @@ public final class ConditionalExpression implements Expression {
|
|||||||
final Value value1 = expr1.eval();
|
final Value value1 = expr1.eval();
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case AND: return NumberValue.fromBoolean(
|
case AND: return NumberValue.fromBoolean(
|
||||||
(value1.asNumber() != 0) && (expr2.eval().asNumber() != 0) );
|
(value1.asInt() != 0) && (expr2.eval().asInt() != 0) );
|
||||||
case OR: return NumberValue.fromBoolean(
|
case OR: return NumberValue.fromBoolean(
|
||||||
(value1.asNumber() != 0) || (expr2.eval().asNumber() != 0) );
|
(value1.asInt() != 0) || (expr2.eval().asInt() != 0) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ public final class ContainerAccessExpression implements Expression, Accessible {
|
|||||||
final Value lastIndex = lastIndex();
|
final Value lastIndex = lastIndex();
|
||||||
switch (container.type()) {
|
switch (container.type()) {
|
||||||
case Types.ARRAY:
|
case Types.ARRAY:
|
||||||
final int arrayIndex = (int) lastIndex.asNumber();
|
final int arrayIndex = lastIndex.asInt();
|
||||||
return ((ArrayValue) container).get(arrayIndex);
|
return ((ArrayValue) container).get(arrayIndex);
|
||||||
|
|
||||||
case Types.MAP:
|
case Types.MAP:
|
||||||
@ -46,7 +46,7 @@ public final class ContainerAccessExpression implements Expression, Accessible {
|
|||||||
final Value lastIndex = lastIndex();
|
final Value lastIndex = lastIndex();
|
||||||
switch (container.type()) {
|
switch (container.type()) {
|
||||||
case Types.ARRAY:
|
case Types.ARRAY:
|
||||||
final int arrayIndex = (int) lastIndex.asNumber();
|
final int arrayIndex = lastIndex.asInt();
|
||||||
((ArrayValue) container).set(arrayIndex, value);
|
((ArrayValue) container).set(arrayIndex, value);
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ public final class ContainerAccessExpression implements Expression, Accessible {
|
|||||||
final Value index = index(i);
|
final Value index = index(i);
|
||||||
switch (container.type()) {
|
switch (container.type()) {
|
||||||
case Types.ARRAY:
|
case Types.ARRAY:
|
||||||
final int arrayIndex = (int) index.asNumber();
|
final int arrayIndex = index.asInt();
|
||||||
container = ((ArrayValue) container).get(arrayIndex);
|
container = ((ArrayValue) container).get(arrayIndex);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ public final class DoWhileStatement implements Statement {
|
|||||||
// continue;
|
// continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (condition.eval().asNumber() != 0);
|
while (condition.eval().asInt() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,7 +20,7 @@ public final class ForStatement implements Statement {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
for (initialization.execute(); termination.eval().asNumber() != 0; increment.execute()) {
|
for (initialization.execute(); termination.eval().asInt() != 0; increment.execute()) {
|
||||||
try {
|
try {
|
||||||
statement.execute();
|
statement.execute();
|
||||||
} catch (BreakStatement bs) {
|
} catch (BreakStatement bs) {
|
||||||
|
@ -17,7 +17,7 @@ public final class IfStatement implements Statement {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
final double result = expression.eval().asNumber();
|
final int result = expression.eval().asInt();
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
ifStatement.execute();
|
ifStatement.execute();
|
||||||
} else if (elseStatement != null) {
|
} else if (elseStatement != null) {
|
||||||
|
@ -19,7 +19,7 @@ public final class TernaryExpression implements Expression {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value eval() {
|
public Value eval() {
|
||||||
if (condition.eval().asNumber() != 0) {
|
if (condition.eval().asInt() != 0) {
|
||||||
return trueExpr.eval();
|
return trueExpr.eval();
|
||||||
} else {
|
} else {
|
||||||
return falseExpr.eval();
|
return falseExpr.eval();
|
||||||
|
@ -2,6 +2,8 @@ package com.annimon.ownlang.parser.ast;
|
|||||||
|
|
||||||
import com.annimon.ownlang.exceptions.OperationIsNotSupportedException;
|
import com.annimon.ownlang.exceptions.OperationIsNotSupportedException;
|
||||||
import com.annimon.ownlang.lib.NumberValue;
|
import com.annimon.ownlang.lib.NumberValue;
|
||||||
|
import com.annimon.ownlang.lib.StringValue;
|
||||||
|
import com.annimon.ownlang.lib.Types;
|
||||||
import com.annimon.ownlang.lib.Value;
|
import com.annimon.ownlang.lib.Value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,38 +54,104 @@ public final class UnaryExpression implements Expression, Statement {
|
|||||||
switch (operation) {
|
switch (operation) {
|
||||||
case INCREMENT_PREFIX: {
|
case INCREMENT_PREFIX: {
|
||||||
if (expr1 instanceof Accessible) {
|
if (expr1 instanceof Accessible) {
|
||||||
return ((Accessible) expr1).set(new NumberValue(value.asNumber() + 1));
|
return ((Accessible) expr1).set(increment(value));
|
||||||
}
|
}
|
||||||
return new NumberValue(value.asNumber() + 1);
|
return increment(value);
|
||||||
}
|
}
|
||||||
case DECREMENT_PREFIX: {
|
case DECREMENT_PREFIX: {
|
||||||
if (expr1 instanceof Accessible) {
|
if (expr1 instanceof Accessible) {
|
||||||
return ((Accessible) expr1).set(new NumberValue(value.asNumber() - 1));
|
return ((Accessible) expr1).set(decrement(value));
|
||||||
}
|
}
|
||||||
return new NumberValue(value.asNumber() - 1);
|
return decrement(value);
|
||||||
}
|
}
|
||||||
case INCREMENT_POSTFIX: {
|
case INCREMENT_POSTFIX: {
|
||||||
if (expr1 instanceof Accessible) {
|
if (expr1 instanceof Accessible) {
|
||||||
((Accessible) expr1).set(new NumberValue(value.asNumber() + 1));
|
((Accessible) expr1).set(increment(value));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
return new NumberValue(value.asNumber() + 1);
|
return increment(value);
|
||||||
}
|
}
|
||||||
case DECREMENT_POSTFIX: {
|
case DECREMENT_POSTFIX: {
|
||||||
if (expr1 instanceof Accessible) {
|
if (expr1 instanceof Accessible) {
|
||||||
((Accessible) expr1).set(new NumberValue(value.asNumber() - 1));
|
((Accessible) expr1).set(decrement(value));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
return new NumberValue(value.asNumber() - 1);
|
return decrement(value);
|
||||||
}
|
}
|
||||||
case NEGATE: return new NumberValue(-value.asNumber());
|
case NEGATE: return negate(value);
|
||||||
case COMPLEMENT: return new NumberValue(~(int)value.asNumber());
|
case COMPLEMENT: return complement(value);
|
||||||
case NOT: return new NumberValue(value.asNumber() != 0 ? 0 : 1);
|
case NOT: return not(value);
|
||||||
default:
|
default:
|
||||||
throw new OperationIsNotSupportedException(operation);
|
throw new OperationIsNotSupportedException(operation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Value increment(Value value) {
|
||||||
|
if (value.type() == Types.NUMBER) {
|
||||||
|
final Number number = ((NumberValue) value).raw();
|
||||||
|
if (number instanceof Double) {
|
||||||
|
return new NumberValue(number.doubleValue() + 1);
|
||||||
|
}
|
||||||
|
if (number instanceof Float) {
|
||||||
|
return new NumberValue(number.floatValue() + 1);
|
||||||
|
}
|
||||||
|
if (number instanceof Long) {
|
||||||
|
return new NumberValue(number.longValue() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new NumberValue(value.asInt() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value decrement(Value value) {
|
||||||
|
if (value.type() == Types.NUMBER) {
|
||||||
|
final Number number = ((NumberValue) value).raw();
|
||||||
|
if (number instanceof Double) {
|
||||||
|
return new NumberValue(number.doubleValue() - 1);
|
||||||
|
}
|
||||||
|
if (number instanceof Float) {
|
||||||
|
return new NumberValue(number.floatValue() - 1);
|
||||||
|
}
|
||||||
|
if (number instanceof Long) {
|
||||||
|
return new NumberValue(number.longValue() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new NumberValue(value.asInt() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value negate(Value value) {
|
||||||
|
if (value.type() == Types.STRING) {
|
||||||
|
final StringBuilder sb = new StringBuilder(value.asString());
|
||||||
|
return new StringValue(sb.reverse().toString());
|
||||||
|
}
|
||||||
|
if (value.type() == Types.NUMBER) {
|
||||||
|
final Number number = ((NumberValue) value).raw();
|
||||||
|
if (number instanceof Double) {
|
||||||
|
return new NumberValue(-number.doubleValue());
|
||||||
|
}
|
||||||
|
if (number instanceof Float) {
|
||||||
|
return new NumberValue(-number.floatValue());
|
||||||
|
}
|
||||||
|
if (number instanceof Long) {
|
||||||
|
return new NumberValue(-number.longValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new NumberValue(-value.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value complement(Value value) {
|
||||||
|
if (value.type() == Types.NUMBER) {
|
||||||
|
final Number number = ((NumberValue) value).raw();
|
||||||
|
if (number instanceof Long) {
|
||||||
|
return new NumberValue(~number.longValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new NumberValue(~value.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value not(Value value) {
|
||||||
|
return NumberValue.fromBoolean(value.asInt() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(Visitor visitor) {
|
public void accept(Visitor visitor) {
|
||||||
visitor.visit(this);
|
visitor.visit(this);
|
||||||
@ -91,6 +159,12 @@ public final class UnaryExpression implements Expression, Statement {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("%s %s", operation, expr1);
|
switch (operation) {
|
||||||
|
case INCREMENT_POSTFIX:
|
||||||
|
case DECREMENT_POSTFIX:
|
||||||
|
return String.format("%s %s", expr1, operation);
|
||||||
|
default:
|
||||||
|
return String.format("%s %s", operation, expr1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ public final class ValueExpression implements Expression {
|
|||||||
|
|
||||||
public final Value value;
|
public final Value value;
|
||||||
|
|
||||||
public ValueExpression(double value) {
|
public ValueExpression(Number value) {
|
||||||
this.value = new NumberValue(value);
|
this.value = new NumberValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ public final class WhileStatement implements Statement {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
while (condition.eval().asNumber() != 0) {
|
while (condition.eval().asInt() != 0) {
|
||||||
try {
|
try {
|
||||||
statement.execute();
|
statement.execute();
|
||||||
} catch (BreakStatement bs) {
|
} catch (BreakStatement bs) {
|
||||||
|
Loading…
Reference in New Issue
Block a user