// streamline.ce — run the full compile + optimize pipeline
//
// Usage:
//   pit streamline <file>              Full optimized IR as JSON (default)
//   pit streamline --stats <file>      Summary stats per function
//   pit streamline --ir <file>         Human-readable IR
//   pit streamline --check <file>      Warnings only (e.g. high slot count)

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 show_stats = false
var show_ir = false
var show_check = false
var filename = null
var i = 0

for (i = 0; i < length(args); i++) {
  if (args[i] == '--stats') {
    show_stats = true
  } else if (args[i] == '--ir') {
    show_ir = true
  } else if (args[i] == '--check') {
    show_check = true
  } else if (!starts_with(args[i], '-')) {
    filename = args[i]
  }
}

if (!filename) {
  print("usage: pit streamline [--stats] [--ir] [--check] <file>")
  $stop()
}

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

// Deep copy for before snapshot (needed by --stats)
var before = null
if (show_stats) {
  before = json.decode(json.encode(compiled))
}

var optimized = streamline(compiled)

// If no flags, default to full JSON output
if (!show_stats && !show_ir && !show_check) {
  print(json.encode(optimized, true))
  $stop()
}

// --- Helpers ---

var ir_stats = use("ir_stats")

var pad_right = function(s, w) {
  var r = s
  while (length(r) < w) {
    r = r + " "
  }
  return r
}

var count_nops = function(func) {
  var instrs = func.instructions
  var nops = 0
  var i = 0
  if (instrs == null) return 0
  while (i < length(instrs)) {
    if (is_text(instrs[i]) && starts_with(instrs[i], "_nop_")) {
      nops = nops + 1
    }
    i = i + 1
  }
  return nops
}

var print_func_stats = function(func, before_func, name) {
  var nr_args = func.nr_args != null ? func.nr_args : 0
  var nr_slots = func.nr_slots != null ? func.nr_slots : 0
  var nr_close = func.nr_close_slots != null ? func.nr_close_slots : 0
  var stats = ir_stats.detailed_stats(func)
  var nops = count_nops(func)
  var before_stats = before_func ? ir_stats.detailed_stats(before_func) : null
  var before_total = before_stats ? before_stats.instr : stats.instr

  print(`  ${name}`)
  print(`    args=${text(nr_args)}  slots=${text(nr_slots)}  close_slots=${text(nr_close)}`)
  print(`    instructions: ${text(stats.instr)} total, ${text(nops)} nops eliminated`)
  if (before_stats) {
    print(`    before: ${text(before_total)}  after: ${text(stats.instr - nops)}`)
  }
  print(`    load=${text(stats.load)} store=${text(stats.store)} branch=${text(stats.branch)} call=${text(stats.call)}`)
  print(`    guard=${text(stats.guard)} arith=${text(stats.arith)} move=${text(stats.move)} const=${text(stats.const)}`)

  if (nr_slots > 200) {
    print(`    WARNING: nr_slots=${text(nr_slots)} approaching 255 limit`)
  }
}

var print_func_ir = function(func, name) {
  var ir_text = ir_stats.canonical_ir(func, name, {show_nops: true})
  print(ir_text)
}

var check_func = function(func, name) {
  var nr_slots = func.nr_slots != null ? func.nr_slots : 0
  if (nr_slots > 200) {
    print(`WARNING: ${name} has ${text(nr_slots)} slots (approaching 255 limit)`)
  }
}

// --- Process functions ---

var main_name = optimized.name != null ? optimized.name : "<main>"
var fi = 0
var func = null
var bfunc = null
var fname = null

if (show_stats) {
  print(`\n--- Stats for ${filename} ---`)
}

// Main function
if (optimized.main != null) {
  if (show_stats) {
    print_func_stats(optimized.main, before ? before.main : null, main_name)
  }
  if (show_ir) {
    print_func_ir(optimized.main, main_name)
  }
  if (show_check) {
    check_func(optimized.main, main_name)
  }
}

// Sub-functions
if (optimized.functions != null) {
  fi = 0
  while (fi < length(optimized.functions)) {
    func = optimized.functions[fi]
    bfunc = before ? before.functions[fi] : null
    fname = func.name != null ? func.name : `<func_${text(fi)}>`

    if (show_stats) {
      print_func_stats(func, bfunc, fname)
    }
    if (show_ir) {
      print_func_ir(func, fname)
    }
    if (show_check) {
      check_func(func, fname)
    }
    fi = fi + 1
  }
}

if (show_stats) {
  print('---')
}

$stop()
