Search in sources :

Example 1 with Accessor

use of io.github.wysohn.triggerreactor.core.script.wrapper.Accessor in project TriggerReactor by wysohn.

the class Interpreter method unwrapVariable.

private Token unwrapVariable(Token varToken) throws InterpreterException {
    if (varToken.type == Type.ID) {
        Object var = vars.get(varToken.value);
        return parseValue(var);
    } else if (varToken.type == Type.GID) {
        return convertValue(gvars, varToken);
    } else if (varToken.type == Type.ACCESS) {
        Accessor accessor = (Accessor) varToken.value;
        Object var;
        try {
            var = accessor.evaluateTarget();
        } catch (NoSuchFieldException e) {
            throw new InterpreterException("Unknown field " + accessor, e);
        } catch (Exception e) {
            throw new InterpreterException("Unknown error " + e.getMessage(), e);
        }
        return parseValue(var);
    } else {
        throw new InterpreterException("Unresolved id " + varToken);
    }
}
Also used : IScriptObject(io.github.wysohn.triggerreactor.core.script.wrapper.IScriptObject) Accessor(io.github.wysohn.triggerreactor.core.script.wrapper.Accessor)

Example 2 with Accessor

use of io.github.wysohn.triggerreactor.core.script.wrapper.Accessor in project TriggerReactor by wysohn.

the class Interpreter method interpret.

/**
 * @param node
 * @return return codes in Executor. null if execution continues.
 * @throws InterpreterException
 */
private Integer interpret(Node node) throws InterpreterException {
    try {
        if (interrupter != null && interrupter.onNodeProcess(node)) {
            return Executor.STOP;
        }
        if (node.getToken().type == Type.BODY || "IF".equals(node.getToken().value) || "ELSEIF".equals(node.getToken().value) || "WHILE".equals(node.getToken().value)) {
            return null;
        } else if (node.getToken().type == Type.EXECUTOR) {
            String command = (String) node.getToken().value;
            Object[] args = new Object[node.getChildren().size()];
            for (int i = args.length - 1; i >= 0; i--) {
                Token argument = stack.pop();
                if (isVariable(argument)) {
                    argument = unwrapVariable(argument);
                }
                args[i] = argument.value;
            }
            if (interrupter != null && interrupter.onCommand(context, command, args)) {
                return null;
            } else {
                if (!executorMap.containsKey(command))
                    throw new InterpreterException("No executor named #" + command + " found!");
                return executorMap.get(command).execute(sync, context, args);
            }
        } else if (node.getToken().type == Type.PLACEHOLDER) {
            String placeholderName = (String) node.getToken().value;
            Object[] args = new Object[node.getChildren().size()];
            for (int i = args.length - 1; i >= 0; i--) {
                Token argument = stack.pop();
                if (isVariable(argument)) {
                    argument = unwrapVariable(argument);
                }
                args[i] = argument.value;
            }
            if (!placeholderMap.containsKey(placeholderName))
                throw new InterpreterException("No placeholder named $" + placeholderName + " found!");
            Object replaced = placeholderMap.get(placeholderName).parse(context, args);
            if (replaced == null) {
                replaced = "$" + placeholderName;
            }
            if (replaced instanceof Number) {
                double d = ((Number) replaced).doubleValue();
                if (d % 1 == 0) {
                    // whole number
                    stack.push(new Token(Type.INTEGER, (int) d));
                } else {
                    stack.push(new Token(Type.DECIMAL, d));
                }
            } else {
                stack.push(new Token(Type.EPS, replaced));
            }
        } else if (node.getToken().type == Type.OPERATOR_A) {
            Token right = stack.pop();
            Token left = stack.pop();
            if (isVariable(right)) {
                right = unwrapVariable(right);
            }
            if (isVariable(left)) {
                left = unwrapVariable(left);
            }
            switch((String) node.getToken().value) {
                case "+":
                    if (left.type == Type.STRING || right.type == Type.STRING) {
                        stack.push(new Token(Type.STRING, String.valueOf(left.value) + String.valueOf(right.value)));
                    } else {
                        if (left.isInt() && right.isInt()) {
                            int leftVal = left.toInt(), rightVal = right.toInt();
                            stack.push(new Token(left.isInt() && right.isInt() ? Type.INTEGER : Type.DECIMAL, leftVal + rightVal));
                        } else {
                            double leftVal = left.isInt() ? left.toInt() : left.toDouble();
                            double rightVal = right.isInt() ? right.toInt() : right.toDouble();
                            stack.push(new Token(left.isInt() && right.isInt() ? Type.INTEGER : Type.DECIMAL, leftVal + rightVal));
                        }
                    }
                    break;
                case "-":
                    if (left.isInt() && right.isInt()) {
                        int leftVal = left.toInt(), rightVal = right.toInt();
                        stack.push(new Token(left.isInt() && right.isInt() ? Type.INTEGER : Type.DECIMAL, leftVal - rightVal));
                    } else {
                        double leftVal = left.isInt() ? left.toInt() : left.toDouble();
                        double rightVal = right.isInt() ? right.toInt() : right.toDouble();
                        stack.push(new Token(left.isInt() && right.isInt() ? Type.INTEGER : Type.DECIMAL, leftVal - rightVal));
                    }
                    break;
                case "*":
                    if (left.isInt() && right.isInt()) {
                        int leftVal = left.toInt(), rightVal = right.toInt();
                        stack.push(new Token(left.isInt() && right.isInt() ? Type.INTEGER : Type.DECIMAL, leftVal * rightVal));
                    } else {
                        double leftVal = left.isInt() ? left.toInt() : left.toDouble();
                        double rightVal = right.isInt() ? right.toInt() : right.toDouble();
                        stack.push(new Token(left.isInt() && right.isInt() ? Type.INTEGER : Type.DECIMAL, leftVal * rightVal));
                    }
                    break;
                case "/":
                    if (left.isInt() && right.isInt()) {
                        int leftVal = left.toInt(), rightVal = right.toInt();
                        stack.push(new Token(left.isInt() && right.isInt() ? Type.INTEGER : Type.DECIMAL, leftVal / rightVal));
                    } else {
                        double leftVal = left.isInt() ? left.toInt() : left.toDouble();
                        double rightVal = right.isInt() ? right.toInt() : right.toDouble();
                        stack.push(new Token(left.isInt() && right.isInt() ? Type.INTEGER : Type.DECIMAL, leftVal / rightVal));
                    }
                    break;
                case "%":
                    if (left.isInt() && right.isInt()) {
                        int leftVal = left.toInt(), rightVal = right.toInt();
                        stack.push(new Token(left.isInt() && right.isInt() ? Type.INTEGER : Type.DECIMAL, leftVal % rightVal));
                    } else {
                        double leftVal = left.isInt() ? left.toInt() : left.toDouble();
                        double rightVal = right.isInt() ? right.toInt() : right.toDouble();
                        stack.push(new Token(left.isInt() && right.isInt() ? Type.INTEGER : Type.DECIMAL, leftVal % rightVal));
                    }
                    break;
                default:
                    throw new InterpreterException("Cannot interpret the unknown operator " + node.getToken().value);
            }
        } else if (node.getToken().type == Type.UNARYMINUS) {
            Token value = stack.pop();
            if (isVariable(value)) {
                value = unwrapVariable(value);
            }
            if (!value.isNumeric())
                throw new InterpreterException("Cannot do unary minus operation for non-numeric value " + value);
            stack.push(value.isInt() ? new Token(Type.INTEGER, -value.toInt(), value.row, value.col) : new Token(Type.DECIMAL, -value.toDouble(), value.row, value.col));
        } else if (node.getToken().type == Type.OPERATOR_L) {
            if ("!".equals(node.getToken().value)) {
                Token boolval = stack.pop();
                if (isVariable(boolval)) {
                    boolval = unwrapVariable(boolval);
                }
                if (boolval.type == Type.NULLVALUE) {
                    // treat null as false
                    stack.push(new Token(Type.BOOLEAN, true));
                } else if (boolval.isBoolean()) {
                    stack.push(new Token(Type.BOOLEAN, !boolval.toBoolean()));
                } else if (boolval.isDouble()) {
                    stack.push(new Token(Type.BOOLEAN, boolval.toDouble() == 0.0));
                } else if (boolval.isInt()) {
                    stack.push(new Token(Type.BOOLEAN, boolval.toInt() == 0));
                } else {
                    throw new InterpreterException("Cannot negate non-boolean value " + boolval);
                }
            } else {
                Token right = stack.pop();
                Token left = stack.pop();
                if (isVariable(right)) {
                    right = unwrapVariable(right);
                }
                if (isVariable(left)) {
                    left = unwrapVariable(left);
                }
                switch((String) node.getToken().value) {
                    case "<":
                        if (!left.isNumeric() || !right.isNumeric())
                            throw new InterpreterException("Only numeric values can be compared!");
                        stack.push(new Token(Type.BOOLEAN, (left.isInt() ? left.toInt() : left.toDouble()) < (right.isInt() ? right.toInt() : right.toDouble())));
                        break;
                    case ">":
                        if (!left.isNumeric() || !right.isNumeric())
                            throw new InterpreterException("Only numeric values can be compared!");
                        stack.push(new Token(Type.BOOLEAN, (left.isInt() ? left.toInt() : left.toDouble()) > (right.isInt() ? right.toInt() : right.toDouble())));
                        break;
                    case "<=":
                        if (!left.isNumeric() || !right.isNumeric())
                            throw new InterpreterException("Only numeric values can be compared!");
                        stack.push(new Token(Type.BOOLEAN, (left.isInt() ? left.toInt() : left.toDouble()) <= (right.isInt() ? right.toInt() : right.toDouble())));
                        break;
                    case ">=":
                        if (!left.isNumeric() || !right.isNumeric())
                            throw new InterpreterException("Only numeric values can be compared!");
                        stack.push(new Token(Type.BOOLEAN, (left.isInt() ? left.toInt() : left.toDouble()) >= (right.isInt() ? right.toInt() : right.toDouble())));
                        break;
                    case "==":
                        if (right.type == Type.NULLVALUE) {
                            stack.push(new Token(Type.BOOLEAN, left.value == null));
                        } else {
                            stack.push(new Token(Type.BOOLEAN, left.value.equals(right.value)));
                        }
                        break;
                    case "!=":
                        if (right.type == Type.NULLVALUE) {
                            stack.push(new Token(Type.BOOLEAN, left.value != null));
                        } else {
                            stack.push(new Token(Type.BOOLEAN, !left.value.equals(right.value)));
                        }
                        break;
                    case "&&":
                        stack.push(new Token(Type.BOOLEAN, left.toBoolean() && right.toBoolean()));
                        break;
                    case "||":
                        stack.push(new Token(Type.BOOLEAN, left.toBoolean() || right.toBoolean()));
                        break;
                }
            }
        } else if (node.getToken().type == Type.OPERATOR) {
            Token right, left;
            switch((String) node.getToken().value) {
                case "=":
                    right = stack.pop();
                    left = stack.pop();
                    assignValue(left, right);
                    break;
                case ".":
                    right = stack.pop();
                    // function call
                    if (right.type == Type.CALL) {
                        Object[] args = new Object[callArgsSize];
                        for (int i = callArgsSize - 1; i >= 0; i--) {
                            Token argument = stack.pop();
                            if (isVariable(argument)) {
                                argument = unwrapVariable(argument);
                            }
                            args[i] = argument.value;
                        }
                        callArgsSize = 0;
                        left = stack.pop();
                        if (left.type == Type.THIS) {
                            callFunction(new Token(Type.OBJECT, right.value), new Token(Type.OBJECT, selfReference), args);
                        } else {
                            Token temp = left;
                            if (isVariable(left)) {
                                left = unwrapVariable(left);
                            }
                            if (left.getType() == Type.NULLVALUE) {
                                throw new InterpreterException("Could not access " + temp + " because it doesn't exist!");
                            }
                            if (left.isObject()) {
                                callFunction(right, left, args);
                            } else {
                                Accessor accessor = (Accessor) left.value;
                                Object var;
                                try {
                                    var = accessor.evaluateTarget();
                                } catch (NoSuchFieldException e) {
                                    throw new InterpreterException("Unknown field " + accessor, e);
                                } catch (Exception e) {
                                    throw new InterpreterException("Unknown error " + e.getMessage(), e);
                                }
                                callFunction(right, new Token(Type.EPS, var), args);
                            }
                        }
                    } else // field access
                    {
                        left = stack.pop();
                        if (left.type == Type.THIS) {
                            stack.push(right);
                        } else {
                            Token temp = left;
                            if (isVariable(left)) {
                                left = unwrapVariable(left);
                            }
                            if (left.getType() == Type.NULLVALUE) {
                                throw new InterpreterException("Could not access " + temp + " because it doesn't exist!");
                            }
                            if (left.isObject() || left.isArray()) {
                                stack.push(new Token(Type.ACCESS, new Accessor(left.value, (String) right.value)));
                            } else {
                                Accessor accessor = (Accessor) left.value;
                                Object var;
                                try {
                                    var = accessor.evaluateTarget();
                                } catch (NoSuchFieldException e) {
                                    throw new InterpreterException("Unknown field " + accessor, e);
                                } catch (Exception e) {
                                    throw new InterpreterException("Unknown error " + e.getMessage(), e);
                                }
                                stack.push(new Token(Type.ACCESS, new Accessor(var, (String) right.value)));
                            }
                        }
                    }
                    break;
            }
        } else if (node.getToken().type == Type.ARRAYACCESS) {
            Token right = stack.pop();
            Token left = stack.pop();
            if (isVariable(left)) {
                left = unwrapVariable(left);
            }
            if (isVariable(right)) {
                right = unwrapVariable(right);
            }
            if (!left.isArray())
                throw new InterpreterException(left + " is not an array!");
            if (!right.isInt())
                throw new InterpreterException(right + " is not a valid index for array!");
            stack.push(new Token(Type.ACCESS, new Accessor(left.value, (Integer) right.value)));
        } else if (node.getToken().type == Type.THIS) {
            stack.push(node.getToken());
        } else if (node.getToken().type == Type.ID) {
            stack.push(node.getToken());
        } else if (node.getToken().type == Type.GID) {
            Token keyToken = stack.pop();
            if (isVariable(keyToken)) {
                keyToken = unwrapVariable(keyToken);
            }
            if (keyToken.getType() != Type.STRING) {
                throw new InterpreterException(keyToken + " is not a valid global variable id.");
            }
            stack.push(new Token(Type.GID, keyToken.value));
        } else if (node.getToken().type == Type.CALL) {
            stack.push(node.getToken());
            callArgsSize = node.getChildren().size();
        } else if (node.getToken().type == Type.STRING) {
            stack.push(new Token(node.getToken().type, node.getToken().value));
        } else if (node.getToken().type == Type.INTEGER) {
            stack.push(new Token(node.getToken().type, Integer.parseInt((String) node.getToken().value)));
        } else if (node.getToken().type == Type.DECIMAL) {
            stack.push(new Token(node.getToken().type, Double.parseDouble((String) node.getToken().value)));
        } else if (node.getToken().type == Type.BOOLEAN) {
            stack.push(new Token(node.getToken().type, Boolean.parseBoolean((String) node.getToken().value)));
        } else if (node.getToken().type == Type.EPS) {
            stack.push(new Token(node.getToken().type, node.getToken().value));
        } else if (node.getToken().type == Type.NULLVALUE) {
            stack.push(new Token(node.getToken().type, null));
        } else {
            throw new InterpreterException("Cannot interpret the unknown node " + node.getToken().type.name());
        }
    } catch (Exception e) {
        throw new InterpreterException("Error occured while processing Node " + node, e);
    }
    return null;
}
Also used : Token(io.github.wysohn.triggerreactor.core.script.Token) IScriptObject(io.github.wysohn.triggerreactor.core.script.wrapper.IScriptObject) Accessor(io.github.wysohn.triggerreactor.core.script.wrapper.Accessor)

Aggregations

Accessor (io.github.wysohn.triggerreactor.core.script.wrapper.Accessor)2 IScriptObject (io.github.wysohn.triggerreactor.core.script.wrapper.IScriptObject)2 Token (io.github.wysohn.triggerreactor.core.script.Token)1