Совместимость с Android-версией

This commit is contained in:
Victor 2019-01-13 21:52:07 +02:00
parent 8a000cd6c2
commit 3a21089d4e
13 changed files with 120 additions and 69 deletions

View File

@ -20,6 +20,10 @@ public final class Converters {
int apply(); int apply();
} }
public interface VoidToLongFunction {
long apply();
}
public interface VoidToFloatFunction { public interface VoidToFloatFunction {
float apply(); float apply();
} }
@ -28,6 +32,10 @@ public final class Converters {
double apply(); double apply();
} }
public interface VoidToCharSequenceFunction {
CharSequence apply();
}
public interface VoidToStringFunction { public interface VoidToStringFunction {
String apply(); String apply();
} }
@ -44,6 +52,14 @@ public final class Converters {
void apply(int i); void apply(int i);
} }
public interface IntToLongFunction {
long apply(int i);
}
public interface Int2ToVoidFunction {
void apply(int i1, int i2);
}
public interface Int4ToVoidFunction { public interface Int4ToVoidFunction {
void apply(int i1, int i2, int i3, int i4); void apply(int i1, int i2, int i3, int i4);
} }
@ -68,6 +84,10 @@ public final class Converters {
void apply(double d1, double d2, double d3, double d4); void apply(double d1, double d2, double d3, double d4);
} }
public interface CharSequenceToVoidFunction {
void apply(CharSequence s);
}
public interface StringToVoidFunction { public interface StringToVoidFunction {
void apply(String s); void apply(String s);
} }
@ -88,6 +108,10 @@ public final class Converters {
return new FunctionValue(args -> NumberValue.of(f.apply())); return new FunctionValue(args -> NumberValue.of(f.apply()));
} }
public static FunctionValue voidToLong(VoidToLongFunction f) {
return new FunctionValue(args -> NumberValue.of(f.apply()));
}
public static FunctionValue voidToFloat(VoidToFloatFunction f) { public static FunctionValue voidToFloat(VoidToFloatFunction f) {
return new FunctionValue(args -> NumberValue.of(f.apply())); return new FunctionValue(args -> NumberValue.of(f.apply()));
} }
@ -96,6 +120,10 @@ public final class Converters {
return new FunctionValue(args -> NumberValue.of(f.apply())); return new FunctionValue(args -> NumberValue.of(f.apply()));
} }
public static FunctionValue voidToCharSequence(VoidToCharSequenceFunction f) {
return new FunctionValue(args -> new StringValue(f.apply().toString()));
}
public static FunctionValue voidToString(VoidToStringFunction f) { public static FunctionValue voidToString(VoidToStringFunction f) {
return new FunctionValue(args -> new StringValue(f.apply())); return new FunctionValue(args -> new StringValue(f.apply()));
} }
@ -131,6 +159,22 @@ public final class Converters {
}); });
} }
public static FunctionValue intToLong(IntToLongFunction f) {
return new FunctionValue(args -> {
Arguments.check(1, args.length);
return NumberValue.of(f.apply(args[0].asInt()));
});
}
public static FunctionValue int2ToVoid(Int2ToVoidFunction f) {
return new FunctionValue(args -> {
Arguments.check(4, args.length);
f.apply(args[0].asInt(),
args[1].asInt());
return NumberValue.ZERO;
});
}
public static FunctionValue int4ToVoid(Int4ToVoidFunction f) { public static FunctionValue int4ToVoid(Int4ToVoidFunction f) {
return new FunctionValue(args -> { return new FunctionValue(args -> {
Arguments.check(4, args.length); Arguments.check(4, args.length);
@ -186,6 +230,23 @@ public final class Converters {
}); });
} }
public static FunctionValue charSequenceToVoid(CharSequenceToVoidFunction f) {
return charSequenceToVoid(f, false);
}
public static FunctionValue charSequenceToVoid(CharSequenceToVoidFunction f, boolean emptyAsNull) {
return new FunctionValue(args -> {
Arguments.check(1, args.length);
final String text = args[0].asString();
if (emptyAsNull && (text != null) && (text.isEmpty())) {
f.apply(null);
} else {
f.apply(text);
}
return NumberValue.ZERO;
});
}
public static FunctionValue stringToVoid(StringToVoidFunction f) { public static FunctionValue stringToVoid(StringToVoidFunction f) {
return new FunctionValue(args -> { return new FunctionValue(args -> {
Arguments.check(1, args.length); Arguments.check(1, args.length);

View File

@ -1,6 +1,8 @@
package com.annimon.ownlang.lib; package com.annimon.ownlang.lib;
import com.annimon.ownlang.exceptions.TypeException; import com.annimon.ownlang.exceptions.TypeException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import org.json.JSONArray; import org.json.JSONArray;
@ -111,4 +113,17 @@ public final class ValueUtils {
} }
return ((FunctionValue) value).getValue(); return ((FunctionValue) value).getValue();
} }
public static <T extends Number> MapValue collectNumberConstants(Class<?> clazz, Class<T> type) {
MapValue result = new MapValue(20);
for (Field field : clazz.getDeclaredFields()) {
if (!Modifier.isStatic(field.getModifiers())) continue;
if (!field.getType().equals(type)) continue;
try {
result.set(field.getName(), NumberValue.of((T) field.get(type)));
} catch (IllegalAccessException ignore) {
}
}
return result;
}
} }

View File

@ -1,11 +1,9 @@
package com.annimon.ownlang.modules.functional; package com.annimon.ownlang.modules.functional;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.Arguments; import com.annimon.ownlang.lib.Arguments;
import com.annimon.ownlang.lib.Function; import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.FunctionValue;
import com.annimon.ownlang.lib.Types;
import com.annimon.ownlang.lib.Value; import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.ValueUtils;
public final class functional_chain implements Function { public final class functional_chain implements Function {
@ -15,11 +13,7 @@ public final class functional_chain implements Function {
Value result = args[0]; Value result = args[0];
for (int i = 1; i < args.length; i += 2) { for (int i = 1; i < args.length; i += 2) {
final Value arg = args[i]; final Function function = ValueUtils.consumeFunction(args[i], i);
if (arg.type() != Types.FUNCTION) {
throw new TypeException(arg.toString() + " is not a function");
}
final Function function = ((FunctionValue) arg).getValue();
result = function.execute(result, args[i+1]); result = function.execute(result, args[i+1]);
} }
return result; return result;

View File

@ -1,7 +1,13 @@
package com.annimon.ownlang.modules.functional; package com.annimon.ownlang.modules.functional;
import com.annimon.ownlang.exceptions.TypeException; import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.*; import com.annimon.ownlang.lib.Arguments;
import com.annimon.ownlang.lib.ArrayValue;
import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.NumberValue;
import com.annimon.ownlang.lib.Types;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.ValueUtils;
public final class functional_dropwhile implements Function { public final class functional_dropwhile implements Function {
@ -11,12 +17,8 @@ public final class functional_dropwhile implements Function {
if (args[0].type() != Types.ARRAY) { if (args[0].type() != Types.ARRAY) {
throw new TypeException("Array expected in first argument"); throw new TypeException("Array expected in first argument");
} }
if (args[1].type() != Types.FUNCTION) {
throw new TypeException("Function expected in second argument");
}
final Value container = args[0]; final Value container = args[0];
final Function predicate = ((FunctionValue) args[1]).getValue(); final Function predicate = ValueUtils.consumeFunction(args[1], 1);
return dropWhileArray((ArrayValue) container, predicate); return dropWhileArray((ArrayValue) container, predicate);
} }

View File

@ -17,12 +17,8 @@ public final class functional_filter implements Function {
@Override @Override
public Value execute(Value... args) { public Value execute(Value... args) {
Arguments.check(2, args.length); Arguments.check(2, args.length);
if (args[1].type() != Types.FUNCTION) {
throw new TypeException("Function expected in second argument");
}
final Value container = args[0]; final Value container = args[0];
final Function predicate = ((FunctionValue) args[1]).getValue(); final Function predicate = ValueUtils.consumeFunction(args[1], 1);
if (container.type() == Types.ARRAY) { if (container.type() == Types.ARRAY) {
return filterArray((ArrayValue) container, predicate, takeWhile); return filterArray((ArrayValue) container, predicate, takeWhile);
} }

View File

@ -4,10 +4,10 @@ import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.Arguments; import com.annimon.ownlang.lib.Arguments;
import com.annimon.ownlang.lib.ArrayValue; import com.annimon.ownlang.lib.ArrayValue;
import com.annimon.ownlang.lib.Function; import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.FunctionValue;
import com.annimon.ownlang.lib.MapValue; import com.annimon.ownlang.lib.MapValue;
import com.annimon.ownlang.lib.Types; import com.annimon.ownlang.lib.Types;
import com.annimon.ownlang.lib.Value; import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.ValueUtils;
import java.util.Map; import java.util.Map;
public final class functional_map implements Function { public final class functional_map implements Function {
@ -18,22 +18,13 @@ public final class functional_map implements Function {
final Value container = args[0]; final Value container = args[0];
if (container.type() == Types.ARRAY) { if (container.type() == Types.ARRAY) {
if (args[1].type() != Types.FUNCTION) { final Function mapper = ValueUtils.consumeFunction(args[1], 1);
throw new TypeException("Function expected in second arg");
}
final Function mapper = ((FunctionValue) args[1]).getValue();
return mapArray((ArrayValue) container, mapper); return mapArray((ArrayValue) container, mapper);
} }
if (container.type() == Types.MAP) { if (container.type() == Types.MAP) {
if (args[1].type() != Types.FUNCTION) { final Function keyMapper = ValueUtils.consumeFunction(args[1], 1);
throw new TypeException("Function expected in second arg"); final Function valueMapper = ValueUtils.consumeFunction(args[2], 2);
}
if (args[2].type() != Types.FUNCTION) {
throw new TypeException("Function expected in third arg");
}
final Function keyMapper = ((FunctionValue) args[1]).getValue();
final Function valueMapper = ((FunctionValue) args[2]).getValue();
return mapMap((MapValue) container, keyMapper, valueMapper); return mapMap((MapValue) container, keyMapper, valueMapper);
} }

View File

@ -4,10 +4,10 @@ import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.Arguments; import com.annimon.ownlang.lib.Arguments;
import com.annimon.ownlang.lib.ArrayValue; import com.annimon.ownlang.lib.ArrayValue;
import com.annimon.ownlang.lib.Function; import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.FunctionValue;
import com.annimon.ownlang.lib.MapValue; import com.annimon.ownlang.lib.MapValue;
import com.annimon.ownlang.lib.Types; import com.annimon.ownlang.lib.Types;
import com.annimon.ownlang.lib.Value; import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.ValueUtils;
import java.util.Map; import java.util.Map;
public final class functional_reduce implements Function { public final class functional_reduce implements Function {
@ -16,12 +16,9 @@ public final class functional_reduce implements Function {
public Value execute(Value... args) { public Value execute(Value... args) {
Arguments.check(3, args.length); Arguments.check(3, args.length);
if (args[2].type() != Types.FUNCTION) {
throw new TypeException("Function expected in third argument");
}
final Value container = args[0]; final Value container = args[0];
final Value identity = args[1]; final Value identity = args[1];
final Function accumulator = ((FunctionValue) args[2]).getValue(); final Function accumulator = ValueUtils.consumeFunction(args[2], 2);
if (container.type() == Types.ARRAY) { if (container.type() == Types.ARRAY) {
Value result = identity; Value result = identity;
final ArrayValue array = (ArrayValue) container; final ArrayValue array = (ArrayValue) container;

View File

@ -15,8 +15,9 @@ public final class functional_sortby implements Function {
public Value execute(Value... args) { public Value execute(Value... args) {
Arguments.check(2, args.length); Arguments.check(2, args.length);
if (args[0].type() != Types.ARRAY) { if (args[0].type() != Types.ARRAY) {
throw new TypeException("Array expected in first argument"); throw new TypeException("Array expected at first argument");
} }
final Value[] elements = ((ArrayValue) args[0]).getCopyElements(); final Value[] elements = ((ArrayValue) args[0]).getCopyElements();
final Function function = ValueUtils.consumeFunction(args[1], 1); final Function function = ValueUtils.consumeFunction(args[1], 1);
Arrays.sort(elements, (o1, o2) -> function.execute(o1).compareTo(function.execute(o2))); Arrays.sort(elements, (o1, o2) -> function.execute(o1).compareTo(function.execute(o2)));

View File

@ -96,10 +96,7 @@ public final class functional_stream implements Function {
Arrays.sort(elements); Arrays.sort(elements);
break; break;
case 1: case 1:
if (args[0].type() != Types.FUNCTION) { final Function comparator = ValueUtils.consumeFunction(args[0], 0);
throw new TypeException("Function expected in second argument");
}
final Function comparator = ((FunctionValue) args[0]).getValue();
Arrays.sort(elements, (o1, o2) -> comparator.execute(o1, o2).asInt()); Arrays.sort(elements, (o1, o2) -> comparator.execute(o1, o2).asInt());
break; break;
default: default:
@ -111,10 +108,7 @@ public final class functional_stream implements Function {
private Value custom(Value... args) { private Value custom(Value... args) {
Arguments.check(1, args.length); Arguments.check(1, args.length);
if (args[0].type() != Types.FUNCTION) { final Function f = ValueUtils.consumeFunction(args[0], 0);
throw new TypeException("Function expected in first argument");
}
final Function f = ((FunctionValue) args[0]).getValue();
final Value result = f.execute(container); final Value result = f.execute(container);
if (result.type() == Types.ARRAY) { if (result.type() == Types.ARRAY) {
return new StreamValue((ArrayValue) result); return new StreamValue((ArrayValue) result);

View File

@ -1,7 +1,11 @@
package com.annimon.ownlang.modules.std; package com.annimon.ownlang.modules.std;
import com.annimon.ownlang.exceptions.TypeException; import com.annimon.ownlang.lib.Arguments;
import com.annimon.ownlang.lib.*; import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.FunctionValue;
import com.annimon.ownlang.lib.NumberValue;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.ValueUtils;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
@ -10,9 +14,6 @@ public final class std_sync implements Function {
@Override @Override
public Value execute(Value... args) { public Value execute(Value... args) {
Arguments.check(1, args.length); Arguments.check(1, args.length);
if (args[0].type() != Types.FUNCTION) {
throw new TypeException(args[0].toString() + " is not a function");
}
final BlockingQueue<Value> queue = new LinkedBlockingQueue<>(2); final BlockingQueue<Value> queue = new LinkedBlockingQueue<>(2);
final Function synchronizer = (sArgs) -> { final Function synchronizer = (sArgs) -> {
@ -23,7 +24,7 @@ public final class std_sync implements Function {
} }
return NumberValue.ZERO; return NumberValue.ZERO;
}; };
final Function callback = ((FunctionValue) args[0]).getValue(); final Function callback = ValueUtils.consumeFunction(args[0], 0);
callback.execute(new FunctionValue(synchronizer)); callback.execute(new FunctionValue(synchronizer));
try { try {

View File

@ -1,6 +1,5 @@
package com.annimon.ownlang.modules.std; package com.annimon.ownlang.modules.std;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.*; import com.annimon.ownlang.lib.*;
public final class std_try implements Function { public final class std_try implements Function {
@ -8,11 +7,8 @@ public final class std_try implements Function {
@Override @Override
public Value execute(Value... args) { public Value execute(Value... args) {
Arguments.checkOrOr(1, 2, args.length); Arguments.checkOrOr(1, 2, args.length);
if (args[0].type() != Types.FUNCTION) {
throw new TypeException(args[0].toString() + " is not a function");
}
try { try {
return ((FunctionValue) args[0]).getValue().execute(); return ValueUtils.consumeFunction(args[0], 0).execute();
} catch (Exception ex) { } catch (Exception ex) {
if (args.length == 2) { if (args.length == 2) {
switch (args[1].type()) { switch (args[1].type()) {

View File

@ -137,7 +137,7 @@ public final class Lexer {
else if (current == '"') tokenizeText(); else if (current == '"') tokenizeText();
else if (current == '#') { else if (current == '#') {
next(); next();
tokenizeHexNumber(); tokenizeHexNumber(1);
} }
else if (OPERATOR_CHARS.indexOf(current) != -1) { else if (OPERATOR_CHARS.indexOf(current) != -1) {
tokenizeOperator(); tokenizeOperator();
@ -155,7 +155,7 @@ public final class Lexer {
if (current == '0' && (peek(1) == 'x' || (peek(1) == 'X'))) { if (current == '0' && (peek(1) == 'x' || (peek(1) == 'X'))) {
next(); next();
next(); next();
tokenizeHexNumber(); tokenizeHexNumber(2);
return; return;
} }
while (true) { while (true) {
@ -170,7 +170,7 @@ public final class Lexer {
addToken(TokenType.NUMBER, buffer.toString()); addToken(TokenType.NUMBER, buffer.toString());
} }
private void tokenizeHexNumber() { private void tokenizeHexNumber(int skipped) {
clearBuffer(); clearBuffer();
char current = peek(0); char current = peek(0);
while (isHexNumber(current) || (current == '_')) { while (isHexNumber(current) || (current == '_')) {
@ -180,7 +180,8 @@ public final class Lexer {
} }
current = next(); current = next();
} }
if (buffer.length() > 0) { final int length = buffer.length();
if (length > 0) {
addToken(TokenType.HEX_NUMBER, buffer.toString()); addToken(TokenType.HEX_NUMBER, buffer.toString());
} }
} }

View File

@ -315,7 +315,9 @@ public final class Parser {
} }
if (lookMatch(0, TokenType.DOT)) { if (lookMatch(0, TokenType.DOT)) {
final List<Expression> indices = variableSuffix(); final List<Expression> indices = variableSuffix();
if (indices.isEmpty()) return expr; if (indices == null || indices.isEmpty()) {
return expr;
}
if (lookMatch(0, TokenType.LPAREN)) { if (lookMatch(0, TokenType.LPAREN)) {
// next function call // next function call
@ -452,7 +454,7 @@ public final class Parser {
// x[0].prop += ... // x[0].prop += ...
final int position = pos; final int position = pos;
final Expression targetExpr = qualifiedName(); final Expression targetExpr = qualifiedName();
if (!(targetExpr instanceof Accessible)) { if ((targetExpr == null) || !(targetExpr instanceof Accessible)) {
pos = position; pos = position;
return null; return null;
} }
@ -759,7 +761,7 @@ public final class Parser {
if (!match(TokenType.WORD)) return null; if (!match(TokenType.WORD)) return null;
final List<Expression> indices = variableSuffix(); final List<Expression> indices = variableSuffix();
if (indices.isEmpty()) { if (indices == null || indices.isEmpty()) {
return new VariableExpression(current.getText()); return new VariableExpression(current.getText());
} }
return new ContainerAccessExpression(current.getText(), indices); return new ContainerAccessExpression(current.getText(), indices);
@ -768,7 +770,7 @@ public final class Parser {
private List<Expression> variableSuffix() { private List<Expression> variableSuffix() {
// .key1.arr1[expr1][expr2].key2 // .key1.arr1[expr1][expr2].key2
if (!lookMatch(0, TokenType.DOT) && !lookMatch(0, TokenType.LBRACKET)) { if (!lookMatch(0, TokenType.DOT) && !lookMatch(0, TokenType.LBRACKET)) {
return Collections.emptyList(); return null;
} }
final List<Expression> indices = new ArrayList<>(); final List<Expression> indices = new ArrayList<>();
while (lookMatch(0, TokenType.DOT) || lookMatch(0, TokenType.LBRACKET)) { while (lookMatch(0, TokenType.DOT) || lookMatch(0, TokenType.LBRACKET)) {
@ -805,7 +807,7 @@ public final class Parser {
))); )));
} }
final List<Expression> indices = variableSuffix(); final List<Expression> indices = variableSuffix();
if (indices.isEmpty()) { if (indices == null || indices.isEmpty()) {
return strExpr; return strExpr;
} }
return new ContainerAccessExpression(strExpr, indices); return new ContainerAccessExpression(strExpr, indices);