// Path: app/src/main/java/com/annimon/hotarufx/exceptions/FunctionNotFoundException.java
// public class FunctionNotFoundException extends HotaruRuntimeException {
// 
//     public FunctionNotFoundException(String name, SourcePosition start, SourcePosition end) {
//         super("Function " + name + " does not exists", start, end);
//     }
// }
// 
// Path: app/src/main/java/com/annimon/hotarufx/exceptions/TypeException.java
// public class TypeException extends HotaruRuntimeException {
// 
//     public TypeException(String message) {
//         super(message);
//     }
// 
//     public TypeException(String message, SourcePosition start, SourcePosition end) {
//         super(message, start, end);
//     }
// }
// 
// Path: app/src/main/java/com/annimon/hotarufx/exceptions/VariableNotFoundException.java
// public class VariableNotFoundException extends HotaruRuntimeException {
// 
//     public VariableNotFoundException(String variable, SourcePosition start, SourcePosition end) {
//         super("Variable " + variable + " does not exists", start, end);
//     }
// }


import com.annimon.hotarufx.exceptions.FunctionNotFoundException;
import com.annimon.hotarufx.exceptions.TypeException;
import com.annimon.hotarufx.exceptions.VariableNotFoundException;
import com.annimon.hotarufx.lib.*;
import com.annimon.hotarufx.parser.ast.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
        switch (value.type()) {
            case Types.FUNCTION:
                function = ((FunctionValue) value).getValue();
                break;
            default:
                final var functionName = value.asString();
                function = context.functions().get(functionName);
                if (function == null)
                    throw new FunctionNotFoundException(functionName, node.start(), node.end());
                break;
        }
        final var args = node.arguments.stream()
                .map(n -> n.accept(this, context))
                .toArray(Value[]::new);
        return function.execute(args);
    }

    @Override
    public Value visit(MapNode node, Context context) {
        Map<String, Value> map = new HashMap<>(node.elements.size());
        for (Map.Entry<String, Node> entry : node.elements.entrySet()) {
            map.put(entry.getKey(), entry.getValue().accept(this, context));
        }
        return new MapValue(map);
    }

    @Override
    public Value visit(PropertyNode node, Context context) {
        final var value = node.node.accept(this, context);
        if (value.type() != Types.NODE) {
// Path: app/src/main/java/com/annimon/hotarufx/exceptions/FunctionNotFoundException.java
// public class FunctionNotFoundException extends HotaruRuntimeException {
// 
//     public FunctionNotFoundException(String name, SourcePosition start, SourcePosition end) {
//         super("Function " + name + " does not exists", start, end);
//     }
// }
// 
// Path: app/src/main/java/com/annimon/hotarufx/exceptions/TypeException.java
// public class TypeException extends HotaruRuntimeException {
// 
//     public TypeException(String message) {
//         super(message);
//     }
// 
//     public TypeException(String message, SourcePosition start, SourcePosition end) {
//         super(message, start, end);
//     }
// }
// 
// Path: app/src/main/java/com/annimon/hotarufx/exceptions/VariableNotFoundException.java
// public class VariableNotFoundException extends HotaruRuntimeException {
// 
//     public VariableNotFoundException(String variable, SourcePosition start, SourcePosition end) {
//         super("Variable " + variable + " does not exists", start, end);
//     }
// }


// Path: app/src/main/java/com/annimon/hotarufx/parser/visitors/InterpreterVisitor.java
import com.annimon.hotarufx.exceptions.FunctionNotFoundException;
import com.annimon.hotarufx.exceptions.TypeException;
import com.annimon.hotarufx.exceptions.VariableNotFoundException;
import com.annimon.hotarufx.lib.*;
import com.annimon.hotarufx.parser.ast.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;

        switch (value.type()) {
            case Types.FUNCTION:
                function = ((FunctionValue) value).getValue();
                break;
            default:
                final var functionName = value.asString();
                function = context.functions().get(functionName);
                if (function == null)
                    throw new FunctionNotFoundException(functionName, node.start(), node.end());
                break;
        }
        final var args = node.arguments.stream()
                .map(n -> n.accept(this, context))
                .toArray(Value[]::new);
        return function.execute(args);
    }

    @Override
    public Value visit(MapNode node, Context context) {
        Map<String, Value> map = new HashMap<>(node.elements.size());
        for (Map.Entry<String, Node> entry : node.elements.entrySet()) {
            map.put(entry.getKey(), entry.getValue().accept(this, context));
        }
        return new MapValue(map);
    }

    @Override
    public Value visit(PropertyNode node, Context context) {
        final var value = node.node.accept(this, context);
        if (value.type() != Types.NODE) {
            throw new TypeException("Node value expected");