validationErrors function

List<String> validationErrors(
  1. Program program
)

The validation errors for program (empty ⇒ valid). Mirrors the checks the native ball validate verb historically inlined.

Implementation

List<String> validationErrors(Program program) {
  final errors = <String>[];

  if (program.entryModule.isEmpty) {
    errors.add('Missing entry_module');
  }
  if (program.entryFunction.isEmpty) {
    errors.add('Missing entry_function');
  }

  if (program.entryModule.isNotEmpty && program.entryFunction.isNotEmpty) {
    Module? entryMod;
    for (final m in program.modules) {
      if (m.name == program.entryModule) {
        entryMod = m;
        break;
      }
    }
    if (entryMod == null) {
      errors.add('Entry module "${program.entryModule}" not found in modules');
    } else {
      FunctionDefinition? entryFunc;
      for (final f in entryMod.functions) {
        if (f.name == program.entryFunction) {
          entryFunc = f;
          break;
        }
      }
      if (entryFunc == null) {
        errors.add(
          'Entry function "${program.entryFunction}" not found '
          'in module "${program.entryModule}"',
        );
      }
    }
  }

  for (var i = 0; i < program.modules.length; i++) {
    final m = program.modules[i];
    if (m.name.isEmpty) {
      errors.add('Module at index $i has no name');
    }
  }

  final seen = <String>[];
  for (final m in program.modules) {
    if (m.name.isNotEmpty) {
      if (seen.contains(m.name)) {
        errors.add('Duplicate module name: "${m.name}"');
      } else {
        seen.add(m.name);
      }
    }
  }

  for (final m in program.modules) {
    for (final f in m.functions) {
      if (!f.isBase && !f.hasBody() && !f.hasMetadata()) {
        errors.add(
          '${m.name}.${f.name}: non-base function with no body or metadata',
        );
      }
    }
  }

  return errors;
}