Repository: apple/pkl
File: pkl-core/src/main/java/org/pkl/core/EvaluatorImpl.java (Java)

Code before:
          var output = (VmTyped) VmUtils.readMember(module, Identifier.OUTPUT);
          return VmUtils.readTextProperty(output);
        });
  }

  @Override
  public Object evaluateOutputValue(ModuleSource moduleSource) {
    return doEvaluate(
        moduleSource,
        (module) -> {
          var output = (VmTyped) VmUtils.readMember(module, Identifier.OUTPUT);
          var value = VmUtils.readMember(output, Identifier.VALUE);
          if (value instanceof VmValue vmValue) {
            vmValue.force(false);
            return vmValue.export();
          }
          return value;
        });
  }

  @Override
  public Map<String, FileOutput> evaluateOutputFiles(ModuleSource moduleSource) {
    return doEvaluate(
        moduleSource,
        (module) -> {
          var output = (VmTyped) VmUtils.readMember(module, Identifier.OUTPUT);
          var filesOrNull = VmUtils.readMember(output, Identifier.FILES);
          if (filesOrNull instanceof VmNull) {
            return Map.of();
          }
          var files = (VmMapping) filesOrNull;
          var result = new LinkedHashMap<String, FileOutput>();
          files.forceAndIterateMemberValues(
              (key, member, value) -> {
                assert member.isEntry();
                result.put((String) key, new FileOutputImpl(this, (VmTyped) value));
                return true;
              });
          return result;
        });
  }

  @Override
  public Object evaluateExpression(ModuleSource moduleSource, String expression) {
    // optimization: if the expression is `output.text` or `output.value` (the common cases), read
    // members directly instead of creating new truffle nodes.
    if (expression.equals("output.text")) {
      return evaluateOutputText(moduleSource);
    }
    if (expression.equals("output.value")) {
      return evaluateOutputValue(moduleSource);

Review comment (suggestion):
Sorry, my suggestion needs reformatting:

```suggestion
    if (value instanceof VmTyped typedOutput
        && typedOutput.getVmClass().getPClassInfo() == PClassInfo.ModuleOutput) {
      return typedOutput;
    }
```

Code after:
          var output = readModuleOutput(module);
          return VmUtils.readTextProperty(output);
        });
  }

  @Override
  public Object evaluateOutputValue(ModuleSource moduleSource) {
    return doEvaluate(
        moduleSource,
        (module) -> {
          var output = readModuleOutput(module);
          var value = VmUtils.readMember(output, Identifier.VALUE);
          if (value instanceof VmValue vmValue) {
            vmValue.force(false);
            return vmValue.export();
          }
          return value;
        });
  }

  @Override
  public Map<String, FileOutput> evaluateOutputFiles(ModuleSource moduleSource) {
    return doEvaluate(
        moduleSource,
        (module) -> {
          var output = readModuleOutput(module);
          var filesOrNull = VmUtils.readMember(output, Identifier.FILES);
          if (filesOrNull instanceof VmNull) {
            return Map.of();
          }
          var files = (VmMapping) filesOrNull;
          var result = new LinkedHashMap<String, FileOutput>();
          files.forceAndIterateMemberValues(
              (key, member, value) -> {
                assert member.isEntry();
                result.put((String) key, new FileOutputImpl(this, (VmTyped) value));
                return true;
              });
          return result;
        });
  }

  @Override
  public Object evaluateExpression(ModuleSource moduleSource, String expression) {
    // optimization: if the expression is `output.text` or `output.value` (the common cases), read
    // members directly instead of creating new truffle nodes.
    if (expression.equals("output.text")) {
      return evaluateOutputText(moduleSource);
    }
    if (expression.equals("output.value")) {
      return evaluateOutputValue(moduleSource);