module generator

import (
  std.alloc
  std.collections
  std.strings
)

let Value = type union(@auto) {
  String(str),
  Number(i64),
  Boolean(bool),
}

let Field = type struct {
  key: str,
  value: Value,
}

let Document = type struct {
  fields: std.collections.DynamicArray(Field),
  body: str,
}

let Context = type struct {
  fields: std.collections.DynamicArray(Field),
}

let Engine = type struct {
  allocator: *mut dyn std.alloc.Allocator,
  root: str,
  output: str,
  error: *mut std.strings.StringBuilder,
}

let Stop = type enum {
  Eof,
  Else,
  EndIf,
  Error,
}

let append_text(builder: *mut std.strings.StringBuilder, value: str): bool =
  builder.append(value.([]u8))

let fail(engine: *mut Engine, message: str): bool {
  if engine.error.count == 0 {
    _ = append_text(engine.error, message)
  }
  return false
}

let fail_path(engine: *mut Engine, message: str, path: str): bool {
  if engine.error.count == 0 {
    _ = append_text(engine.error, message)
    _ = append_text(engine.error, path)
  }
  return false
}

let find_field(fields: []Field, key: str): (Value, bool) {
  for field in fields @reversed {
    if field.key.eq(key) { return field.value, true }
  }
  return .String(""), false
}

let set_field(context: *mut Context, field: Field): bool {
  for existing.&mut in context.fields.as_mut_slice() {
    if existing.key.eq(field.key) {
      existing.* = field
      return true
    }
  }
  return context.fields.append(field)
}

let copy_context(
  allocator: *mut dyn std.alloc.Allocator,
  source: *Context,
): (Context, bool) {
  let fields, ok = source.fields.duplicate()
  if !ok {
    return .{ fields=std.collections.DynamicArray(Field).init(allocator) }, false
  }
  return .{ fields=fields }, true
}