// Moved from apps/selfhost-compiler/boxes/parser/scan/parser_string_scan_box.hako
// ParserStringScanBox — string literal scanner (escape-aware)
// Responsibility: read a Ny string literal starting at index i (i points to '"').
// Returns: "<content>@<pos>" where <pos> is the index after the closing quote.
// Notes: pure string scanning; no external deps.

using lang.compiler.parser.scan.parser_common_utils_box as ParserCommonUtilsBox

static box ParserStringScanBox {
  // Generic scanner with quote abstraction (quote is "\"" or "'")
  scan_with_quote(src, i, quote) {
    if src == null { return "@" + ParserCommonUtilsBox.i2s(i) }
    local n = src.length()
    local j = i
    if j >= n || src.substring(j, j+1) != quote { return "@" + ParserCommonUtilsBox.i2s(i) }
    j = j + 1
    local out = ""
    local guard = 0
    local max = 200000
    loop(j < n) {
      if guard > max { break } else { guard = guard + 1 }
      local ch = src.substring(j, j+1)

      // End of string: found matching quote
      if ch == quote {
        j = j + 1
        return out + "@" + ParserCommonUtilsBox.i2s(j)
      }

      // Escape sequence
      if ch == "\\" && j + 1 < n {
        local nx = src.substring(j+1, j+2)

        // Decode escape
        if nx == "\\" {
          out = out + "\\"
          j = j + 2
          continue
        }
        if nx == "\"" {
          out = out + "\""
          j = j + 2
          continue
        }
        if nx == "'" {
          out = out + "'"
          j = j + 2
          continue
        }
        if nx == "/" {
          out = out + "/"
          j = j + 2
          continue
        }
        if nx == "b" {
          // Backspace (0x08) - for MVP, skip (empty string)
          out = out + ""
          j = j + 2
          continue
        }
        if nx == "f" {
          // Form feed (0x0C) - for MVP, skip (empty string)
          out = out + ""
          j = j + 2
          continue
        }
        if nx == "n" {
          out = out + "\n"
          j = j + 2
          continue
        }
        if nx == "r" {
          // FIX: \r should be CR (0x0D), not LF (0x0A)
          // Keep as "\r" literal for MVP
          out = out + "\r"
          j = j + 2
          continue
        }
        if nx == "t" {
          out = out + "\t"
          j = j + 2
          continue
        }
        if nx == "u" && j + 5 < n {
          // \uXXXX: MVP - concatenate as-is (6 chars)
          out = out + src.substring(j, j+6)
          j = j + 6
          continue
        }
        // Unknown escape: tolerate (keep backslash + char)
        out = out + "\\" + nx
        j = j + 2
        continue
      }

      out = out + ch
      j = j + 1
    }
    // if unterminated, return what we have and the last pos to avoid infinite loops
    return out + "@" + ParserCommonUtilsBox.i2s(j)
  }

  // Existing: backward-compatible wrapper
  scan(src, i) {
    return me.scan_with_quote(src, i, "\"")
  }
}

