// compare_aot.ce — compile a .ce/.cm file via both paths and compare results
//
// Usage:
//   cell --dev compare_aot.ce <file.ce>

var build = use('build')
var fd_mod = use('fd')
var os = use('os')
var json = use('json')
var time = use('time')

var show = function(v) {
  if (v == null) return "null"
  return json.encode(v)
}

if (length(args) < 1) {
  print('usage: cell --dev compare_aot.ce <file>')
  return
}

var file = args[0]
if (!fd_mod.is_file(file)) {
  if (!ends_with(file, '.ce') && fd_mod.is_file(file + '.ce'))
    file = file + '.ce'
  else if (!ends_with(file, '.cm') && fd_mod.is_file(file + '.cm'))
    file = file + '.cm'
  else {
    print('file not found: ' + file)
    return
  }
}

var abs = fd_mod.realpath(file)

// Shared compilation front-end
var tokenize = use('tokenize')
var parse_mod = use('parse')
var fold = use('fold')
var mcode_mod = use('mcode')
var streamline_mod = use('streamline')

var t0 = time.number()
var src = text(fd_mod.slurp(abs))
var t1 = time.number()
var tok = tokenize(src, abs)
var t2 = time.number()
var ast = parse_mod(tok.tokens, src, abs, tokenize)
var t3 = time.number()
var folded = fold(ast)
var t4 = time.number()
var compiled = mcode_mod(folded)
var t5 = time.number()
var optimized = streamline_mod(compiled)
var t6 = time.number()

print('--- front-end timing ---')
print('  read:       ' + text(t1 - t0) + 's')
print('  tokenize:   ' + text(t2 - t1) + 's')
print('  parse:      ' + text(t3 - t2) + 's')
print('  fold:       ' + text(t4 - t3) + 's')
print('  mcode:      ' + text(t5 - t4) + 's')
print('  streamline: ' + text(t6 - t5) + 's')
print('  total:      ' + text(t6 - t0) + 's')

// Shared env for both paths — only non-intrinsic runtime functions.
// Intrinsics (starts_with, ends_with, logical, some, every, etc.) live on
// the stoned global and are found via GETINTRINSIC/cell_rt_get_intrinsic.
var env = stone({
  log: log,
  fallback: fallback,
  parallel: parallel,
  race: race,
  sequence: sequence,
  use
})

// --- Interpreted (mach VM) ---
var result_interp = null
var interp_ok = false
var run_interp = function() {
  print('--- interpreted ---')
  var mcode_json = json.encode(optimized)
  var mach_blob = mach_compile_mcode_bin(abs, mcode_json)
  result_interp = mach_load(mach_blob, env)
  interp_ok = true
  print('result: ' + show(result_interp))
} disruption {
  interp_ok = true
  print('(disruption escaped from interpreted run)')
}
run_interp()

// --- Native (AOT via QBE) ---
var result_native = null
var native_ok = false
var run_native = function() {
  print('\n--- native ---')
  var dylib_path = build.compile_native_ir(optimized, abs, null)
  print('dylib: ' + dylib_path)
  var handle = os.dylib_open(dylib_path)
  if (!handle) {
    print('failed to open dylib')
    return
  }
  result_native = os.native_module_load(handle, env)
  native_ok = true
  print('result: ' + show(result_native))
} disruption {
  native_ok = true
  print('(disruption escaped from native run)')
}
run_native()

// --- Comparison ---
print('\n--- comparison ---')
var s_interp = show(result_interp)
var s_native = show(result_native)
if (interp_ok && native_ok) {
  if (s_interp == s_native) {
    print('MATCH')
  } else {
    print('MISMATCH')
    print('  interp: ' + s_interp)
    print('  native: ' + s_native)
  }
} else {
  if (!interp_ok) print('interpreted run failed')
  if (!native_ok) print('native run failed')
}
