Расширенные числовые типы

This commit is contained in:
Victor 2016-02-18 12:35:20 +02:00
parent d737844913
commit 8a3719d67d
36 changed files with 624 additions and 127 deletions

View File

@ -5,4 +5,8 @@ public final class OperationIsNotSupportedException extends RuntimeException {
public OperationIsNotSupportedException(Object operation) {
super("Operation " + operation + " is not supported");
}
public OperationIsNotSupportedException(Object operation, String message) {
super("Operation " + operation + " is not supported " + message);
}
}

View File

@ -72,6 +72,11 @@ public final class ArrayValue implements Value, Iterable<Value> {
elements[index] = value;
}
@Override
public int asInt() {
throw new TypeException("Cannot cast array to integer");
}
@Override
public double asNumber() {
throw new TypeException("Cannot cast array to number");

View File

@ -22,6 +22,11 @@ public final class FunctionValue implements Value {
return Types.FUNCTION;
}
@Override
public int asInt() {
throw new TypeException("Cannot cast function to integer");
}
@Override
public double asNumber() {
throw new TypeException("Cannot cast function to number");

View File

@ -45,6 +45,11 @@ public class MapValue implements Value, Iterable<Map.Entry<Value, Value>> {
map.put(key, value);
}
@Override
public int asInt() {
throw new TypeException("Cannot cast map to integer");
}
@Override
public double asNumber() {
throw new TypeException("Cannot cast map to number");

View File

@ -6,6 +6,7 @@ package com.annimon.ownlang.lib;
*/
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 ONE = new NumberValue(1);
@ -13,9 +14,9 @@ public final class NumberValue implements Value {
return b ? ONE : ZERO;
}
private final double value;
private final Number value;
public NumberValue(double value) {
public NumberValue(Number value) {
this.value = value;
}
@ -24,20 +25,53 @@ public final class NumberValue implements Value {
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
public double asNumber() {
return value;
return value.doubleValue();
}
@Override
public String asString() {
return Double.toString(value);
return value.toString();
}
@Override
public int hashCode() {
int hash = 3;
hash = 71 * hash + (int) (Double.doubleToLongBits(this.value) ^ (Double.doubleToLongBits(this.value) >>> 32));
hash = 71 * hash + value.hashCode();
return hash;
}
@ -47,14 +81,33 @@ public final class NumberValue implements Value {
if (obj == null) return false;
if (getClass() != obj.getClass())
return false;
final NumberValue other = (NumberValue) obj;
return Double.doubleToLongBits(this.value) == Double.doubleToLongBits(other.value);
final Number other = ((NumberValue) obj).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
public int compareTo(Value o) {
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());
}

View File

@ -25,6 +25,15 @@ public final class StringValue implements Value {
return Types.STRING;
}
@Override
public int asInt() {
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return 0;
}
}
@Override
public double asNumber() {
try {

View File

@ -9,4 +9,14 @@ public final class Types {
ARRAY = 3,
MAP = 4,
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";
}
}

View File

@ -6,6 +6,8 @@ package com.annimon.ownlang.lib;
*/
public interface Value extends Comparable<Value> {
int asInt();
double asNumber();
String asString();

View File

@ -22,8 +22,6 @@ import javax.swing.JPanel;
*/
public final class canvas implements Module {
private static final NumberValue MINUS_ONE = new NumberValue(-1);
private static JFrame frame;
private static CanvasPanel panel;
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_ESCAPE", new NumberValue(KeyEvent.VK_ESCAPE));
lastKey = MINUS_ONE;
lastKey = NumberValue.MINUS_ONE;
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) {
return args -> {
if (args.length != 4) throw new ArgumentsMismatchException("Four args expected");
int x = (int) args[0].asNumber();
int y = (int) args[1].asNumber();
int w = (int) args[2].asNumber();
int h = (int) args[3].asNumber();
consumer.accept(x, y, w, h);
consumer.accept(args[0].asInt(), args[1].asInt(), args[2].asInt(), args[3].asInt());
return NumberValue.ZERO;
};
}
@ -116,7 +110,7 @@ public final class canvas implements Module {
}
@Override
public void keyReleased(KeyEvent e) {
lastKey = MINUS_ONE;
lastKey = NumberValue.MINUS_ONE;
}
});
addMouseMotionListener(new MouseMotionAdapter() {
@ -147,13 +141,13 @@ public final class canvas implements Module {
title = args[0].asString();
break;
case 2:
width = (int) args[0].asNumber();
height = (int) args[1].asNumber();
width = args[0].asInt();
height = args[1].asInt();
break;
case 3:
title = args[0].asString();
width = (int) args[1].asNumber();
height = (int) args[2].asNumber();
width = args[1].asInt();
height = args[2].asInt();
break;
}
panel = new CanvasPanel(width, height);
@ -188,8 +182,8 @@ public final class canvas implements Module {
@Override
public Value execute(Value... args) {
if (args.length != 3) throw new ArgumentsMismatchException("Three args expected");
int x = (int) args[1].asNumber();
int y = (int) args[2].asNumber();
int x = args[1].asInt();
int y = args[2].asInt();
graphics.drawString(args[0].asString(), x, y);
return NumberValue.ZERO;
}
@ -219,12 +213,12 @@ public final class canvas implements Module {
@Override
public Value execute(Value... args) {
if (args.length == 1) {
graphics.setColor(new Color((int) args[0].asNumber()));
graphics.setColor(new Color(args[0].asInt()));
return NumberValue.ZERO;
}
int r = (int) args[0].asNumber();
int g = (int) args[1].asNumber();
int b = (int) args[2].asNumber();
int r = args[0].asInt();
int g = args[1].asInt();
int b = args[2].asInt();
graphics.setColor(new Color(r, g, b));
return NumberValue.ZERO;
}

View File

@ -69,7 +69,7 @@ public final class files implements Module {
}
return process(file, "r");
} catch (IOException ioe) {
return new NumberValue(-1);
return NumberValue.MINUS_ONE;
}
}
@ -101,7 +101,7 @@ public final class files implements Module {
@Override
public Value execute(Value... args) {
if (args.length < 1) throw new ArgumentsMismatchException("File descriptor expected");
final int key = (int) args[0].asNumber();
final int key = args[0].asInt();
try {
return execute(files.get(key), args);
} catch (IOException ioe) {
@ -115,7 +115,7 @@ public final class files implements Module {
private static class readBoolean extends FileFunction {
@Override
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];
int offset = 0, length = array.size();
if (args.length > 3) {
offset = (int) args[2].asNumber();
length = (int) args[3].asNumber();
offset = args[2].asInt();
length = args[3].asInt();
}
final byte[] buffer = new byte[length];
@ -170,7 +170,7 @@ public final class files implements Module {
private static class readChar extends FileFunction {
@Override
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 {
@Override
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;
}
}
@ -247,7 +247,7 @@ public final class files implements Module {
private static class writeByte extends FileFunction {
@Override
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;
}
}
@ -256,7 +256,7 @@ public final class files implements Module {
@Override
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
final char ch = (args[1].type() == Types.NUMBER)
? ((char) args[1].asNumber())
? ((char) args[1].asInt())
: args[1].asString().charAt(0);
fileInfo.dos.writeChar(ch);
return NumberValue.ONE;
@ -266,7 +266,7 @@ public final class files implements Module {
private static class writeShort extends FileFunction {
@Override
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;
}
}
@ -274,7 +274,7 @@ public final class files implements Module {
private static class writeInt extends FileFunction {
@Override
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;
}
}

View File

@ -141,7 +141,7 @@ public final class http_http implements Function {
private RequestBody getMapRequestBody(MapValue params, MapValue options) throws UnsupportedEncodingException {
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) {
final String name = param.getKey().asString();
final String value = param.getValue().asString();

View File

@ -30,7 +30,7 @@ public final class json_decode implements Function {
return new StringValue((String) obj);
}
if (obj instanceof Number) {
return new NumberValue(((Number) obj).doubleValue());
return new NumberValue(((Number) obj));
}
if (obj instanceof Boolean) {
return NumberValue.fromBoolean((Boolean) obj);

View File

@ -26,7 +26,7 @@ public final class json_encode implements Function {
case Types.MAP:
return process((MapValue) val);
case Types.NUMBER:
return val.asNumber();
return ((NumberValue) val).raw();
case Types.STRING:
return val.asString();
default:

View File

@ -10,8 +10,8 @@ public final class std_charat implements Function {
if (args.length != 2) throw new ArgumentsMismatchException("Two arguments expected");
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));
}
}

View File

@ -11,7 +11,7 @@ public final class std_indexof implements Function {
final String input = args[0].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));
}

View File

@ -11,7 +11,7 @@ public final class std_lastindexof implements Function {
final String input = args[0].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));
}

View File

@ -13,7 +13,7 @@ public final class std_newarray implements Function {
}
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;
ArrayValue array = new ArrayValue(size);
if (index == last) {

View File

@ -17,10 +17,10 @@ public final class std_rand implements Function {
int from = 0;
int to = 100;
if (args.length == 1) {
to = (int) args[0].asNumber();
to = args[0].asInt();
} else if (args.length == 2) {
from = (int) args[0].asNumber();
to = (int) args[1].asNumber();
from = args[0].asInt();
to = args[1].asInt();
}
return new NumberValue(RND.nextInt(to - from) + from);
}

View File

@ -24,7 +24,7 @@ public final class std_sort implements Function {
throw new TypeException("Function expected in second argument");
}
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;
default:
throw new ArgumentsMismatchException("Wrong number of arguments");

View File

@ -11,7 +11,7 @@ public final class std_split implements Function {
final String input = args[0].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 ArrayValue result = new ArrayValue(parts.length);

View File

@ -12,7 +12,9 @@ public final class std_sprintf implements Function {
final String format = args[0].asString();
final Object[] values = new Object[args.length - 1];
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));
}

View File

@ -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");
final String input = args[0].asString();
final int startIndex = (int) args[1].asNumber();
final int startIndex = args[1].asInt();
String result;
if (args.length == 2) {
result = input.substring(startIndex);
} else {
final int endIndex = (int) args[2].asNumber();
final int endIndex = args[2].asInt();
result = input.substring(startIndex, endIndex);
}

View File

@ -9,6 +9,6 @@ public final class std_tochar implements Function {
public Value execute(Value... args) {
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()));
}
}

View File

@ -45,7 +45,7 @@ public final class robot implements Module {
Functions.set("mouseMove", (args) -> {
if (args.length != 2) throw new ArgumentsMismatchException("Two arguments expected");
try {
awtRobot.mouseMove((int) args[0].asNumber(), (int) args[1].asNumber());
awtRobot.mouseMove(args[0].asInt(), args[1].asInt());
} catch (IllegalArgumentException iae) { }
return NumberValue.ZERO;
});
@ -89,7 +89,7 @@ public final class robot implements Module {
return args -> {
if (args.length != 1) throw new ArgumentsMismatchException("One argument expected");
try {
consumer.accept((int) args[0].asNumber());
consumer.accept(args[0].asInt());
} catch (IllegalArgumentException iae) { }
return NumberValue.ZERO;
};

View File

@ -20,5 +20,12 @@ public final class types implements Module {
Functions.set("typeof", args -> new NumberValue(args[0].type()));
Functions.set("string", args -> new StringValue(args[0].asString()));
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()));
}
}

View File

@ -327,12 +327,12 @@ public final class Parser {
if (match(TokenType.NUMBER)) {
// case 0.5:
pattern = new MatchExpression.ConstantPattern(
new NumberValue(Double.parseDouble(current.getText()))
new NumberValue(createNumber(current.getText(), 10))
);
} else if (match(TokenType.HEX_NUMBER)) {
// case #FF:
pattern = new MatchExpression.ConstantPattern(
new NumberValue(Long.parseLong(current.getText(), 16))
new NumberValue(createNumber(current.getText(), 16))
);
} else if (match(TokenType.TEXT)) {
// case "text":
@ -703,10 +703,10 @@ public final class Parser {
private Expression value() {
final Token current = get(0);
if (match(TokenType.NUMBER)) {
return new ValueExpression(Double.parseDouble(current.getText()));
return new ValueExpression(createNumber(current.getText(), 10));
}
if (match(TokenType.HEX_NUMBER)) {
return new ValueExpression(Long.parseLong(current.getText(), 16));
return new ValueExpression(createNumber(current.getText(), 16));
}
if (match(TokenType.TEXT)) {
return new ValueExpression(current.getText());
@ -714,6 +714,19 @@ public final class Parser {
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) {
final Token current = get(0);
if (type != current.getType()) throw new ParseException("Token " + current + " doesn't match " + type);

View File

@ -54,70 +54,384 @@ public final class BinaryExpression implements Expression {
public Value eval() {
final Value value1 = expr1.eval();
final Value value2 = expr2.eval();
switch (value1.type()) {
case Types.STRING:
return eval((StringValue) value1, value2);
case Types.ARRAY:
return eval((ArrayValue) value1, value2);
case Types.NUMBER:
default:
return eval(value1, value2);
}
}
private Value eval(StringValue value1, Value value2) {
final String string1 = value1.asString();
switch (operation) {
case MULTIPLY: {
final int iterations = (int) value2.asNumber();
case ADD: return add(value1, value2);
case SUBTRACT: return subtract(value1, value2);
case MULTIPLY: return multiply(value1, value2);
case DIVIDE: return divide(value1, value2);
case REMAINDER: return remainder(value1, value2);
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:
throw new OperationIsNotSupportedException(operation);
}
}
private Value add(Value value1, Value value2) {
switch (value1.type()) {
case Types.NUMBER: return add((NumberValue) value1, value2);
case Types.ARRAY: return ArrayValue.add((ArrayValue) value1, value2);
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();
for (int i = 0; i < iterations; i++) {
buffer.append(string1);
}
return new StringValue(buffer.toString());
}
case ADD:
default:
return new StringValue(string1 + value2.asString());
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
}
}
private Value eval(ArrayValue value1, Value value2) {
switch (operation) {
case LSHIFT:
private Value multiply(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 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)
throw new TypeException("Cannot merge non array value to array");
return ArrayValue.merge(value1, (ArrayValue) value2);
case PUSH:
return ArrayValue.merge((ArrayValue) value1, (ArrayValue) value2);
}
default:
return ArrayValue.add(value1, value2);
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
}
}
private Value eval(Value value1, Value value2) {
final double number1 = value1.asNumber();
final double number2 = value2.asNumber();
double result;
switch (operation) {
case ADD: result = number1 + number2; break;
case SUBTRACT: result = number1 - number2; break;
case MULTIPLY: result = number1 * number2; break;
case DIVIDE: result = number1 / number2; break;
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;
private Value lshift(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 rshift(Value value1, Value value2) {
switch (value1.type()) {
case Types.NUMBER: return rshift((NumberValue) value1, value2);
default:
throw new OperationIsNotSupportedException(operation);
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
}
return new NumberValue(result);
}
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

View File

@ -48,9 +48,9 @@ public final class ConditionalExpression implements Expression {
final Value value1 = expr1.eval();
switch (operation) {
case AND: return NumberValue.fromBoolean(
(value1.asNumber() != 0) && (expr2.eval().asNumber() != 0) );
(value1.asInt() != 0) && (expr2.eval().asInt() != 0) );
case OR: return NumberValue.fromBoolean(
(value1.asNumber() != 0) || (expr2.eval().asNumber() != 0) );
(value1.asInt() != 0) || (expr2.eval().asInt() != 0) );
}

View File

@ -29,7 +29,7 @@ public final class ContainerAccessExpression implements Expression, Accessible {
final Value lastIndex = lastIndex();
switch (container.type()) {
case Types.ARRAY:
final int arrayIndex = (int) lastIndex.asNumber();
final int arrayIndex = lastIndex.asInt();
return ((ArrayValue) container).get(arrayIndex);
case Types.MAP:
@ -46,7 +46,7 @@ public final class ContainerAccessExpression implements Expression, Accessible {
final Value lastIndex = lastIndex();
switch (container.type()) {
case Types.ARRAY:
final int arrayIndex = (int) lastIndex.asNumber();
final int arrayIndex = lastIndex.asInt();
((ArrayValue) container).set(arrayIndex, value);
return value;
@ -66,7 +66,7 @@ public final class ContainerAccessExpression implements Expression, Accessible {
final Value index = index(i);
switch (container.type()) {
case Types.ARRAY:
final int arrayIndex = (int) index.asNumber();
final int arrayIndex = index.asInt();
container = ((ArrayValue) container).get(arrayIndex);
break;

View File

@ -25,7 +25,7 @@ public final class DoWhileStatement implements Statement {
// continue;
}
}
while (condition.eval().asNumber() != 0);
while (condition.eval().asInt() != 0);
}
@Override

View File

@ -20,7 +20,7 @@ public final class ForStatement implements Statement {
@Override
public void execute() {
for (initialization.execute(); termination.eval().asNumber() != 0; increment.execute()) {
for (initialization.execute(); termination.eval().asInt() != 0; increment.execute()) {
try {
statement.execute();
} catch (BreakStatement bs) {

View File

@ -17,7 +17,7 @@ public final class IfStatement implements Statement {
@Override
public void execute() {
final double result = expression.eval().asNumber();
final int result = expression.eval().asInt();
if (result != 0) {
ifStatement.execute();
} else if (elseStatement != null) {

View File

@ -19,7 +19,7 @@ public final class TernaryExpression implements Expression {
@Override
public Value eval() {
if (condition.eval().asNumber() != 0) {
if (condition.eval().asInt() != 0) {
return trueExpr.eval();
} else {
return falseExpr.eval();

View File

@ -2,6 +2,8 @@ package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.exceptions.OperationIsNotSupportedException;
import com.annimon.ownlang.lib.NumberValue;
import com.annimon.ownlang.lib.StringValue;
import com.annimon.ownlang.lib.Types;
import com.annimon.ownlang.lib.Value;
/**
@ -52,38 +54,104 @@ public final class UnaryExpression implements Expression, Statement {
switch (operation) {
case INCREMENT_PREFIX: {
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: {
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: {
if (expr1 instanceof Accessible) {
((Accessible) expr1).set(new NumberValue(value.asNumber() + 1));
((Accessible) expr1).set(increment(value));
return value;
}
return new NumberValue(value.asNumber() + 1);
return increment(value);
}
case DECREMENT_POSTFIX: {
if (expr1 instanceof Accessible) {
((Accessible) expr1).set(new NumberValue(value.asNumber() - 1));
((Accessible) expr1).set(decrement(value));
return value;
}
return new NumberValue(value.asNumber() - 1);
return decrement(value);
}
case NEGATE: return new NumberValue(-value.asNumber());
case COMPLEMENT: return new NumberValue(~(int)value.asNumber());
case NOT: return new NumberValue(value.asNumber() != 0 ? 0 : 1);
case NEGATE: return negate(value);
case COMPLEMENT: return complement(value);
case NOT: return not(value);
default:
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
public void accept(Visitor visitor) {
visitor.visit(this);
@ -91,6 +159,12 @@ public final class UnaryExpression implements Expression, Statement {
@Override
public String toString() {
switch (operation) {
case INCREMENT_POSTFIX:
case DECREMENT_POSTFIX:
return String.format("%s %s", expr1, operation);
default:
return String.format("%s %s", operation, expr1);
}
}
}

View File

@ -14,7 +14,7 @@ public final class ValueExpression implements Expression {
public final Value value;
public ValueExpression(double value) {
public ValueExpression(Number value) {
this.value = new NumberValue(value);
}

View File

@ -16,7 +16,7 @@ public final class WhileStatement implements Statement {
@Override
public void execute() {
while (condition.eval().asNumber() != 0) {
while (condition.eval().asInt() != 0) {
try {
statement.execute();
} catch (BreakStatement bs) {