Совместимость с 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();
}
public interface VoidToLongFunction {
long apply();
}
public interface VoidToFloatFunction {
float apply();
}
@ -28,6 +32,10 @@ public final class Converters {
double apply();
}
public interface VoidToCharSequenceFunction {
CharSequence apply();
}
public interface VoidToStringFunction {
String apply();
}
@ -44,6 +52,14 @@ public final class Converters {
void apply(int i);
}
public interface IntToLongFunction {
long apply(int i);
}
public interface Int2ToVoidFunction {
void apply(int i1, int i2);
}
public interface Int4ToVoidFunction {
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);
}
public interface CharSequenceToVoidFunction {
void apply(CharSequence s);
}
public interface StringToVoidFunction {
void apply(String s);
}
@ -88,6 +108,10 @@ public final class Converters {
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) {
return new FunctionValue(args -> NumberValue.of(f.apply()));
}
@ -96,6 +120,10 @@ public final class Converters {
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) {
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) {
return new FunctionValue(args -> {
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) {
return new FunctionValue(args -> {
Arguments.check(1, args.length);

View File

@ -1,6 +1,8 @@
package com.annimon.ownlang.lib;
import com.annimon.ownlang.exceptions.TypeException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.Map;
import org.json.JSONArray;
@ -111,4 +113,17 @@ public final class ValueUtils {
}
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;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.Arguments;
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.ValueUtils;
public final class functional_chain implements Function {
@ -15,11 +13,7 @@ public final class functional_chain implements Function {
Value result = args[0];
for (int i = 1; i < args.length; i += 2) {
final Value arg = args[i];
if (arg.type() != Types.FUNCTION) {
throw new TypeException(arg.toString() + " is not a function");
}
final Function function = ((FunctionValue) arg).getValue();
final Function function = ValueUtils.consumeFunction(args[i], i);
result = function.execute(result, args[i+1]);
}
return result;

View File

@ -1,7 +1,13 @@
package com.annimon.ownlang.modules.functional;
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 {
@ -11,12 +17,8 @@ public final class functional_dropwhile implements Function {
if (args[0].type() != Types.ARRAY) {
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 Function predicate = ((FunctionValue) args[1]).getValue();
final Function predicate = ValueUtils.consumeFunction(args[1], 1);
return dropWhileArray((ArrayValue) container, predicate);
}

View File

@ -17,12 +17,8 @@ public final class functional_filter implements Function {
@Override
public Value execute(Value... args) {
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 Function predicate = ((FunctionValue) args[1]).getValue();
final Function predicate = ValueUtils.consumeFunction(args[1], 1);
if (container.type() == Types.ARRAY) {
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.ArrayValue;
import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.FunctionValue;
import com.annimon.ownlang.lib.MapValue;
import com.annimon.ownlang.lib.Types;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.ValueUtils;
import java.util.Map;
public final class functional_map implements Function {
@ -18,22 +18,13 @@ public final class functional_map implements Function {
final Value container = args[0];
if (container.type() == Types.ARRAY) {
if (args[1].type() != Types.FUNCTION) {
throw new TypeException("Function expected in second arg");
}
final Function mapper = ((FunctionValue) args[1]).getValue();
final Function mapper = ValueUtils.consumeFunction(args[1], 1);
return mapArray((ArrayValue) container, mapper);
}
if (container.type() == Types.MAP) {
if (args[1].type() != Types.FUNCTION) {
throw new TypeException("Function expected in second arg");
}
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();
final Function keyMapper = ValueUtils.consumeFunction(args[1], 1);
final Function valueMapper = ValueUtils.consumeFunction(args[2], 2);
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.ArrayValue;
import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.FunctionValue;
import com.annimon.ownlang.lib.MapValue;
import com.annimon.ownlang.lib.Types;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.ValueUtils;
import java.util.Map;
public final class functional_reduce implements Function {
@ -16,12 +16,9 @@ public final class functional_reduce implements Function {
public Value execute(Value... args) {
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 identity = args[1];
final Function accumulator = ((FunctionValue) args[2]).getValue();
final Function accumulator = ValueUtils.consumeFunction(args[2], 2);
if (container.type() == Types.ARRAY) {
Value result = identity;
final ArrayValue array = (ArrayValue) container;

View File

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

View File

@ -1,7 +1,11 @@
package com.annimon.ownlang.modules.std;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.*;
import com.annimon.ownlang.lib.Arguments;
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.LinkedBlockingQueue;
@ -10,9 +14,6 @@ public final class std_sync implements Function {
@Override
public Value execute(Value... args) {
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 Function synchronizer = (sArgs) -> {
@ -23,7 +24,7 @@ public final class std_sync implements Function {
}
return NumberValue.ZERO;
};
final Function callback = ((FunctionValue) args[0]).getValue();
final Function callback = ValueUtils.consumeFunction(args[0], 0);
callback.execute(new FunctionValue(synchronizer));
try {

View File

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

View File

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

View File

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