mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Совместимость с Android-версией
This commit is contained in:
parent
8a000cd6c2
commit
3a21089d4e
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)));
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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()) {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user