Расширенные исключения

This commit is contained in:
Victor 2016-01-19 13:38:56 +02:00
parent 5970d20a61
commit b194a7b9b9
36 changed files with 209 additions and 58 deletions

View File

@ -0,0 +1,11 @@
package com.annimon.ownlang.exceptions;
public final class ArgumentsMismatchException extends RuntimeException {
public ArgumentsMismatchException() {
}
public ArgumentsMismatchException(String message) {
super(message);
}
}

View File

@ -1,4 +1,4 @@
package com.annimon.ownlang.parser;
package com.annimon.ownlang.exceptions;
/**
*

View File

@ -0,0 +1,8 @@
package com.annimon.ownlang.exceptions;
public final class OperationIsNotSupportedException extends RuntimeException {
public OperationIsNotSupportedException(Object operation) {
super("Operation " + operation + " is not supported");
}
}

View File

@ -1,4 +1,4 @@
package com.annimon.ownlang.parser;
package com.annimon.ownlang.exceptions;
/**
*

View File

@ -0,0 +1,11 @@
package com.annimon.ownlang.exceptions;
public final class PatternMatchingException extends RuntimeException {
public PatternMatchingException() {
}
public PatternMatchingException(String message) {
super(message);
}
}

View File

@ -0,0 +1,8 @@
package com.annimon.ownlang.exceptions;
public final class TypeException extends RuntimeException {
public TypeException(String message) {
super(message);
}
}

View File

@ -0,0 +1,15 @@
package com.annimon.ownlang.exceptions;
public final class UnknownFunctionException extends RuntimeException {
private final String functionName;
public UnknownFunctionException(String name) {
super("Unknown function " + name);
this.functionName = name;
}
public String getFunctionName() {
return functionName;
}
}

View File

@ -0,0 +1,15 @@
package com.annimon.ownlang.exceptions;
public final class VariableDoesNotExistsException extends RuntimeException {
private final String variable;
public VariableDoesNotExistsException(String variable) {
super("Variable " + variable + " does not exists");
this.variable = variable;
}
public String getVariable() {
return variable;
}
}

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.lib;
import com.annimon.ownlang.exceptions.TypeException;
import java.util.Arrays;
import java.util.Iterator;
@ -61,7 +62,7 @@ public final class ArrayValue implements Value, Iterable<Value> {
@Override
public double asNumber() {
throw new RuntimeException("Cannot cast array to number");
throw new TypeException("Cannot cast array to number");
}
@Override

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.lib;
import com.annimon.ownlang.exceptions.TypeException;
import java.util.Objects;
/**
@ -23,7 +24,7 @@ public final class FunctionValue implements Value {
@Override
public double asNumber() {
throw new RuntimeException("Cannot cast function to number");
throw new TypeException("Cannot cast function to number");
}
@Override

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.lib;
import com.annimon.ownlang.exceptions.UnknownFunctionException;
import java.util.HashMap;
import java.util.Map;
@ -20,7 +21,7 @@ public final class Functions {
}
public static Function get(String key) {
if (!isExists(key)) throw new RuntimeException("Unknown function " + key);
if (!isExists(key)) throw new UnknownFunctionException(key);
return functions.get(key);
}

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.lib;
import com.annimon.ownlang.exceptions.TypeException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@ -46,7 +47,7 @@ public class MapValue implements Value, Iterable<Map.Entry<Value, Value>> {
@Override
public double asNumber() {
throw new RuntimeException("Cannot cast map to number");
throw new TypeException("Cannot cast map to number");
}
@Override

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.lib;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.parser.ast.ReturnStatement;
import com.annimon.ownlang.parser.ast.Statement;
import java.util.List;
@ -30,7 +31,7 @@ public final class UserDefinedFunction implements Function {
@Override
public Value execute(Value... values) {
final int size = values.length;
if (size != getArgsCount()) throw new RuntimeException("Args count mismatch");
if (size != getArgsCount()) throw new ArgumentsMismatchException("Arguments count mismatch");
try {
Variables.push();

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.lib.modules;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.lib.*;
import java.awt.Color;
import java.awt.Dimension;
@ -89,7 +90,7 @@ public final class canvas implements Module {
private static Function intConsumer4Convert(IntConsumer4 consumer) {
return args -> {
if (args.length != 4) throw new RuntimeException("Four args expected");
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();
@ -186,7 +187,7 @@ public final class canvas implements Module {
@Override
public Value execute(Value... args) {
if (args.length != 3) throw new RuntimeException("Three args expected");
if (args.length != 3) throw new ArgumentsMismatchException("Three args expected");
int x = (int) args[1].asNumber();
int y = (int) args[2].asNumber();
graphics.drawString(args[0].asString(), x, y);

View File

@ -0,0 +1,55 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.lib.*;
import java.util.Map;
public final class functional_map implements Function {
@Override
public Value execute(Value... args) {
if (args.length < 2) throw new RuntimeException("At least two args expected");
final Value container = args[0];
if (container.type() == Types.ARRAY) {
if (args[1].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in second arg");
}
final Function mapper = ((FunctionValue) args[1]).getValue();
return mapArray((ArrayValue) container, mapper);
}
if (container.type() == Types.MAP) {
if (args[1].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in second arg");
}
if (args[2].type() != Types.FUNCTION) {
throw new RuntimeException("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);
}
throw new RuntimeException("Invalid first argument. Array or map exprected");
}
private Value mapArray(ArrayValue array, Function mapper) {
final int size = array.size();
final ArrayValue result = new ArrayValue(size);
for (int i = 0; i < size; i++) {
result.set(i, mapper.execute(array.get(i)));
}
return result;
}
private Value mapMap(MapValue map, Function keyMapper, Function valueMapper) {
final MapValue result = new MapValue(map.size());
for (Map.Entry<Value, Value> element : map) {
final Value newKey = keyMapper.execute(element.getKey());
final Value newValue = valueMapper.execute(element.getValue());
result.set(newKey, newValue);
}
return result;
}
}

View File

@ -1,5 +1,7 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.*;
import java.util.ArrayList;
import java.util.List;
@ -10,10 +12,10 @@ public final class functional_filter implements Function {
@Override
public Value execute(Value... args) {
if (args.length < 2) throw new RuntimeException("At least two args expected");
if (args.length < 2) throw new ArgumentsMismatchException("At least two args expected");
if (args[1].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in second arg");
throw new TypeException("Function expected in second arg");
}
final Value container = args[0];
final Function consumer = ((FunctionValue) args[1]).getValue();
@ -25,7 +27,7 @@ public final class functional_filter implements Function {
return filterMap((MapValue) container, consumer);
}
throw new RuntimeException("Invalid first argument. Array or map exprected");
throw new TypeException("Invalid first argument. Array or map exprected");
}
private Value filterArray(ArrayValue array, Function predicate) {

View File

@ -1,5 +1,7 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.*;
import java.util.Map;
@ -8,10 +10,10 @@ public final class functional_foreach implements Function {
@Override
public Value execute(Value... args) {
if (args.length != 2) throw new RuntimeException("Two args expected");
if (args.length != 2) throw new ArgumentsMismatchException("Two args expected");
if (args[1].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in second arg");
throw new TypeException("Function expected in second arg");
}
final Value container = args[0];
final Function consumer = ((FunctionValue) args[1]).getValue();
@ -29,6 +31,6 @@ public final class functional_foreach implements Function {
}
return NumberValue.ZERO;
}
throw new RuntimeException("Invalid first argument. Array or map exprected");
throw new TypeException("Invalid first argument. Array or map exprected");
}
}

View File

@ -1,5 +1,7 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.*;
import java.util.Map;
@ -8,12 +10,12 @@ public final class functional_map implements Function {
@Override
public Value execute(Value... args) {
if (args.length < 2) throw new RuntimeException("At least two args expected");
if (args.length < 2) throw new ArgumentsMismatchException("At least two args expected");
final Value container = args[0];
if (container.type() == Types.ARRAY) {
if (args[1].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in second arg");
throw new TypeException("Function expected in second arg");
}
final Function mapper = ((FunctionValue) args[1]).getValue();
return mapArray((ArrayValue) container, mapper);
@ -21,17 +23,17 @@ public final class functional_map implements Function {
if (container.type() == Types.MAP) {
if (args[1].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in second arg");
throw new TypeException("Function expected in second arg");
}
if (args[2].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in third arg");
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);
}
throw new RuntimeException("Invalid first argument. Array or map exprected");
throw new TypeException("Invalid first argument. Array or map exprected");
}
private Value mapArray(ArrayValue array, Function mapper) {

View File

@ -1,5 +1,7 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.*;
import java.util.Map;
@ -8,10 +10,10 @@ public final class functional_reduce implements Function {
@Override
public Value execute(Value... args) {
if (args.length != 3) throw new RuntimeException("Three args expected");
if (args.length != 3) throw new ArgumentsMismatchException("Three args expected");
if (args[2].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in third arg");
throw new TypeException("Function expected in third arg");
}
final Value container = args[0];
final Value identity = args[1];
@ -32,6 +34,6 @@ public final class functional_reduce implements Function {
}
return result;
}
throw new RuntimeException("Invalid first argument. Array or map exprected");
throw new TypeException("Invalid first argument. Array or map exprected");
}
}

View File

@ -1,5 +1,7 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.*;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@ -49,7 +51,7 @@ public final class http_http implements Function {
case 4: // http(url, method, params, callback)
if (args[3].type() != Types.FUNCTION) {
throw new RuntimeException("Fourth arg must be a function callback");
throw new TypeException("Fourth arg must be a function callback");
}
url = args[0].asString();
method = args[1].asString();
@ -57,17 +59,17 @@ public final class http_http implements Function {
case 5: // http(url, method, params, headerParams, callback)
if (args[3].type() != Types.MAP) {
throw new RuntimeException("Third arg must be a map");
throw new TypeException("Third arg must be a map");
}
if (args[4].type() != Types.FUNCTION) {
throw new RuntimeException("Fifth arg must be a function callback");
throw new TypeException("Fifth arg must be a function callback");
}
url = args[0].asString();
method = args[1].asString();
return process(url, method, args[2], (MapValue) args[3], (FunctionValue) args[4]);
default:
throw new RuntimeException("Wrong number of arguments");
throw new ArgumentsMismatchException("Wrong number of arguments");
}
}

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.StringValue;
import com.annimon.ownlang.lib.Value;
@ -10,7 +11,7 @@ public final class http_urlencode implements Function {
@Override
public Value execute(Value... args) {
if (args.length == 0) throw new RuntimeException("At least one arg expected");
if (args.length == 0) throw new ArgumentsMismatchException("At least one arg expected");
String charset = "UTF-8";
if (args.length >= 2) {

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.lib.*;
import java.util.Iterator;
import org.json.*;
@ -8,7 +9,7 @@ public final class json_decode implements Function {
@Override
public Value execute(Value... args) {
if (args.length != 1) throw new RuntimeException("One argument expected");
if (args.length != 1) throw new ArgumentsMismatchException("One argument expected");
try {
final String jsonRaw = args[0].asString();
final Object root = new JSONTokener(jsonRaw).nextValue();

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.lib.*;
import java.util.Map;
import org.json.*;
@ -8,7 +9,7 @@ public final class json_encode implements Function {
@Override
public Value execute(Value... args) {
if (args.length != 1) throw new RuntimeException("One argument expected");
if (args.length != 1) throw new ArgumentsMismatchException("One argument expected");
try {
final Object root = process(args[0]);
final String jsonRaw = JSONObject.valueToString(root);

View File

@ -1,5 +1,7 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.*;
import java.util.Map;
@ -8,9 +10,9 @@ public final class std_foreach implements Function {
@Override
public Value execute(Value... args) {
if (args.length != 2) return NumberValue.ZERO;
if (args.length != 2) throw new ArgumentsMismatchException("Two arguments expected");
if (args[1].type() != Types.FUNCTION) return NumberValue.ZERO;
if (args[1].type() != Types.FUNCTION) throw new TypeException("Second arg must be a function");
final Function function = ((FunctionValue) args[1]).getValue();
final Value container = args[0];
if (container.type() == Types.ARRAY) {
@ -27,6 +29,6 @@ public final class std_foreach implements Function {
}
return NumberValue.ZERO;
}
return NumberValue.ZERO;
throw new TypeException("First arg must be an array or map");
}
}

View File

@ -1,12 +1,13 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.lib.*;
public final class std_length implements Function {
@Override
public Value execute(Value... args) {
if (args.length == 0) throw new RuntimeException("At least one arg expected");
if (args.length == 0) throw new ArgumentsMismatchException("At least one arg expected");
final Value val = args[0];
int length;

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.NumberValue;
import com.annimon.ownlang.lib.Value;
@ -8,13 +9,13 @@ public final class std_sleep implements Function {
@Override
public Value execute(Value... args) {
if (args.length == 1) {
if (args.length != 1) throw new ArgumentsMismatchException("One argument expected");
try {
Thread.sleep((long) args[0].asNumber());
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
return NumberValue.ZERO;
}
}

View File

@ -1,11 +1,7 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.FunctionValue;
import com.annimon.ownlang.lib.Functions;
import com.annimon.ownlang.lib.NumberValue;
import com.annimon.ownlang.lib.Types;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.lib.*;
public final class std_thread implements Function {
@ -13,7 +9,7 @@ public final class std_thread implements Function {
public Value execute(Value... args) {
// Создаём новый поток и передаём параметры, если есть.
// Функция может передаваться как напрямую, так и по имени
if (args.length == 0) throw new RuntimeException("At least one arg expected");
if (args.length == 0) throw new ArgumentsMismatchException("At least one arg expected");
Function body;
if (args[0].type() == Types.FUNCTION) {

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.lib.modules;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
import com.annimon.ownlang.lib.*;
import java.util.function.DoubleBinaryOperator;
import java.util.function.DoubleFunction;
@ -57,14 +58,14 @@ public final class math implements Module {
private static Function functionConvert(DoubleUnaryOperator op) {
return args -> {
if (args.length != 1) throw new RuntimeException("One arg expected");
if (args.length != 1) throw new ArgumentsMismatchException("One arg expected");
return doubleToNumber.apply(op.applyAsDouble(args[0].asNumber()));
};
}
private static Function biFunctionConvert(DoubleBinaryOperator op) {
return args -> {
if (args.length != 2) throw new RuntimeException("Two args expected");
if (args.length != 2) throw new ArgumentsMismatchException("Two args expected");
return doubleToNumber.apply(op.applyAsDouble(args[0].asNumber(), args[1].asNumber()));
};
}

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.parser;
import com.annimon.ownlang.exceptions.LexerException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.parser;
import com.annimon.ownlang.exceptions.ParseException;
import com.annimon.ownlang.lib.NumberValue;
import com.annimon.ownlang.lib.StringValue;
import com.annimon.ownlang.lib.UserDefinedFunction;

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.*;
import java.util.List;
@ -56,14 +57,14 @@ public final class ArrayAccessExpression implements Expression {
private ArrayValue consumeArray(Value value) {
if (value.type() != Types.ARRAY) {
throw new RuntimeException("Array expected");
throw new TypeException("Array expected");
}
return (ArrayValue) value;
}
public MapValue consumeMap(Value value) {
if (value.type() != Types.MAP) {
throw new RuntimeException("Map expected");
throw new TypeException("Map expected");
}
return (MapValue) value;
}

View File

@ -1,5 +1,7 @@
package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.exceptions.OperationIsNotSupportedException;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.ArrayValue;
import com.annimon.ownlang.lib.NumberValue;
import com.annimon.ownlang.lib.StringValue;
@ -85,7 +87,7 @@ public final class BinaryExpression implements Expression {
switch (operation) {
case LSHIFT:
if (value2.type() != Types.ARRAY)
throw new RuntimeException("Cannot merge non array value to array");
throw new TypeException("Cannot merge non array value to array");
return ArrayValue.merge(value1, (ArrayValue) value2);
case PUSH:
default:
@ -113,7 +115,7 @@ public final class BinaryExpression implements Expression {
case URSHIFT: result = (int)number1 >>> (int)number2; break;
default:
throw new RuntimeException("Operation " + operation + " is not supported");
throw new OperationIsNotSupportedException(operation);
}
return new NumberValue(result);
}

View File

@ -1,7 +1,7 @@
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;
@ -76,7 +76,7 @@ public final class ConditionalExpression implements Expression {
case GTEQ: result = number1 >= number2; break;
default:
throw new RuntimeException("Operation " + operation + " is not supported");
throw new OperationIsNotSupportedException(operation);
}
return NumberValue.fromBoolean(result);
}

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.exceptions.PatternMatchingException;
import com.annimon.ownlang.lib.NumberValue;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.Variables;
@ -48,7 +49,7 @@ public final class MatchExpression implements Expression {
}
}
}
throw new RuntimeException("No pattern were matched");
throw new PatternMatchingException("No pattern were matched");
}
private boolean match(Value value, Value constant) {

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.exceptions.OperationIsNotSupportedException;
import com.annimon.ownlang.lib.NumberValue;
import com.annimon.ownlang.lib.Value;
@ -44,7 +45,7 @@ public final class UnaryExpression implements Expression {
case COMPLEMENT: return new NumberValue(~(int)value.asNumber());
case NOT: return new NumberValue(value.asNumber() != 0 ? 0 : 1);
default:
throw new RuntimeException("Operation " + operation + " is not supported");
throw new OperationIsNotSupportedException(operation);
}
}

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.exceptions.VariableDoesNotExistsException;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.Variables;
@ -17,7 +18,7 @@ public final class VariableExpression implements Expression {
@Override
public Value eval() {
if (!Variables.isExists(name)) throw new RuntimeException("Variable does not exists: " + name);
if (!Variables.isExists(name)) throw new VariableDoesNotExistsException(name);
return Variables.get(name);
}