public Value invoke(Value... values) {
        Type t = Type.match(type.toString());

        if (values.length != params.length) {
            throw new IllegalArgumentException("Wrong number of values for parameters.");
        }

        for (int i = 0; i < values.length && i < params.length; i++) {
            Parameter p = params[i];
            Value v = values[i];

            if (p.getType() != v.getType()) {
                throw new IllegalStateException("Parameter " + p.getName() + " should be " + p.getType() + ". Got " + v.getType());
            }

            addVariable(new Variable(this, p.getType(), p.getName(), v.getValue()));
        }

        for (Block b : getSubBlocks()) {
            b.run();

            if (returnValue != null) {
                break;
            }
        }

        if (returnValue == null && t != BuiltInType.VOID) {
            throw new IllegalStateException("Expected return value, got none.");
        }

        Value localReturnValue = returnValue;
        returnValue = null;
        return localReturnValue;
    }