/// MoonBit Prolog — a Prolog interpreter REPL built on `moonbitlang/async`
/// stdio, so the same source runs on the wasm and native backends.
///
/// Facts, rules and queries end with `.` and may span several lines.
/// Type `halt.` to quit. When stdin is piped, every solution of each query
/// is printed automatically.
///
/// This package is the one `moonx bobzhang/prolog` executes.

/// Flush the text captured by `write/1` & friends to stdout.
fn flush_output(ctx : @lib.Ctx) -> Unit {
  let out = ctx.take_output()
  if out.length() > 0 {
    // Drop trailing newlines: println adds its own.
    let mut n = out.length()
    while n > 0 && out[n - 1].to_int() == 10 {
      n = n - 1
    }
    let mut text = ""
    let mut i = 0
    while i < n {
      text = text + Int::unsafe_to_char(out[i].to_int()).to_string()
      i = i + 1
    }
    println(text)
  }
}

async fn main {
  let ctx = @lib.Ctx::new()
  let mut buf = ""
  while true {
    match @stdio.stdin.read_until("\n") {
      None => {
        flush_output(ctx)
        return
      }
      Some(line) => buf = buf + line
    }
    let stripped = @lib.strip_comments(buf)
    let t = @lib.trim(stripped)
    if t.length() == 0 {
      buf = ""
      continue
    }
    if t[t.length() - 1].to_int() == 46 {
      let on_solution = fn(_s : Array[Option[@lib.Term]], qvars : Array[(String, Int)]) -> Bool {
        flush_output(ctx)
        println("")
        if qvars.length() == 0 {
          println("true.")
        } else {
          for pair in qvars {
            let (name, id) = pair
            println("\{name} = \{@lib.pretty(_s, @lib.Var(id))}")
          }
        }
        true
      }
      let r = ctx.submit(t, on_solution)
      flush_output(ctx)
      match r {
        Fact => ()
        Halt => return
        SyntaxError => println("Syntax error")
        Query(_, stopped) => if !stopped { println(""); println("false.") }
      }
      buf = ""
    }
    continue
  }
  ()
}