// ir_report.ce — optimizer flight recorder CLI
//
// Usage: ./cell --core . ir_report.ce [options] <file.cm|file.ce>
//
// Options:
//   --summary       Per-pass JSON summaries (default)
//   --events        Include rewrite events
//   --types         Include type deltas
//   --ir-before=PASS  Print canonical IR before PASS
//   --ir-after=PASS   Print canonical IR after PASS
//   --ir-all        Print canonical IR before/after every pass
//   --full          Everything (summary + events + types + ir-all)

var fd = use("fd")
var json = use("json")
var tokenize = use("tokenize")
var parse = use("parse")
var fold = use("fold")
var mcode = use("mcode")
var streamline = use("streamline")
var ir_stats = use("ir_stats")

// --- Parse arguments ---

var filename = null
var opt_events = false
var opt_types = false
var opt_ir_before = null
var opt_ir_after = null
var opt_ir_all = false
var i = 0
var arg = null
var p = null
var e = null
var td = null

while (i < length(args)) {
  arg = args[i]
  if (arg == "--events") {
    opt_events = true
  } else if (arg == "--types") {
    opt_types = true
  } else if (arg == "--ir-all") {
    opt_ir_all = true
  } else if (arg == "--full") {
    opt_events = true
    opt_types = true
    opt_ir_all = true
  } else if (arg == "--summary") {
    // default, no-op
  } else if (starts_with(arg, "--ir-before=")) {
    opt_ir_before = text(arg, 12)
  } else if (starts_with(arg, "--ir-after=")) {
    opt_ir_after = text(arg, 11)
  } else if (!starts_with(arg, "--")) {
    filename = arg
  } else {
    print(`unknown option: ${arg}\n`)
    print("usage: cell --core . ir_report.ce [options] <file>\n")
    $stop()
  }
  i = i + 1
}

if (filename == null) {
  print("usage: cell --core . ir_report.ce [options] <file.cm|file.ce>\n")
  print("  --summary        per-pass JSON summaries (default)\n")
  print("  --events         include rewrite events\n")
  print("  --types          include type deltas\n")
  print("  --ir-before=PASS print canonical IR before PASS\n")
  print("  --ir-after=PASS  print canonical IR after PASS\n")
  print("  --ir-all         print canonical IR before/after every pass\n")
  print("  --full           everything\n")
  $stop()
}

// --- Compile ---

var src = text(fd.slurp(filename))
var tok = tokenize(src, filename)
var ast = parse(tok.tokens, src, filename, tokenize)
var folded = fold(ast)
var compiled = mcode(folded)

// --- Determine which passes need IR snapshots ---

var need_snapshots = opt_ir_all || opt_ir_before != null || opt_ir_after != null

// Deep copy for before snapshot if we need IR printing
var before_ir = null
if (need_snapshots) {
  before_ir = json.decode(json.encode(compiled))
}

// --- Set up log ---

var log = {
  passes: [],
  events: null,
  type_deltas: null
}

if (opt_events) {
  log.events = []
}
if (opt_types) {
  log.type_deltas = []
}

// --- Run optimizer ---

var optimized = streamline(compiled, log)

// --- Output ---

var emit = function(obj) {
  print(json.encode(obj))
  print("\n")
}

// Pass summaries (always)
i = 0
while (i < length(log.passes)) {
  p = log.passes[i]
  p.type = "pass"
  emit(p)
  i = i + 1
}

// Rewrite events
if (opt_events && log.events != null) {
  i = 0
  while (i < length(log.events)) {
    e = log.events[i]
    e.type = "event"
    emit(e)
    i = i + 1
  }
}

// Type deltas
if (opt_types && log.type_deltas != null) {
  i = 0
  while (i < length(log.type_deltas)) {
    td = log.type_deltas[i]
    td.type = "types"
    emit(td)
    i = i + 1
  }
}

// --- Canonical IR printing ---

var print_ir = function(ir_obj, when_label, pass_name) {
  var fname = null
  var fi = 0
  var func = null
  if (ir_obj.main != null) {
    fname = ir_obj.name != null ? ir_obj.name : "<main>"
    emit({
      type: "ir",
      when: when_label,
      pass: pass_name,
      fn: fname,
      text: ir_stats.canonical_ir(ir_obj.main, fname, {show_nops: true})
    })
  }
  if (ir_obj.functions != null) {
    fi = 0
    while (fi < length(ir_obj.functions)) {
      func = ir_obj.functions[fi]
      fname = func.name != null ? func.name : `<func_${text(fi)}>`
      emit({
        type: "ir",
        when: when_label,
        pass: pass_name,
        fn: fname,
        text: ir_stats.canonical_ir(func, fname, {show_nops: true})
      })
      fi = fi + 1
    }
  }
  return null
}

if (need_snapshots) {
  if (opt_ir_all) {
    print_ir(before_ir, "before", "all")
    print_ir(optimized, "after", "all")
  } else {
    if (opt_ir_before != null) {
      print_ir(before_ir, "before", opt_ir_before)
    }
    if (opt_ir_after != null) {
      print_ir(optimized, "after", opt_ir_after)
    }
  }
}

$stop()
