///|
priv struct Source {
  chars : Array[Char]
  mut pos : Int
}

///|
fn Source::segment(self : Source) -> (String, Char) raise ParseError {
  let mut out = ""
  let mut quote = '\u0000'
  let mut level = 0
  while self.pos < self.chars.length() {
    let c = self.chars[self.pos]
    self.pos += 1
    if quote != '\u0000' {
      out += c.to_string()
      if c == '\\' && self.pos < self.chars.length() {
        out += self.chars[self.pos].to_string()
        self.pos += 1
      } else if c == quote {
        quote = '\u0000'
      }
      continue
    }
    if c == '"' || c == '\'' {
      quote = c
      out += c.to_string()
      continue
    }
    if c == '/' && self.pos < self.chars.length() && self.chars[self.pos] == '*' {
      self.pos += 1
      let mut closed = false
      while self.pos + 1 < self.chars.length() {
        if self.chars[self.pos] == '*' && self.chars[self.pos + 1] == '/' {
          self.pos += 2
          closed = true
          break
        }
        self.pos += 1
      }
      if !closed {
        raise Invalid("unterminated comment")
      }
      out += " "
      continue
    }
    if c == '#' && self.pos < self.chars.length() && self.chars[self.pos] == '{' {
      out += "#{"
      self.pos += 1
      let mut nesting = 1
      let mut q = '\u0000'
      while self.pos < self.chars.length() && nesting > 0 {
        let x = self.chars[self.pos]
        self.pos += 1
        out += x.to_string()
        if x == '\\' && self.pos < self.chars.length() {
          out += self.chars[self.pos].to_string()
          self.pos += 1
          continue
        }
        if q != '\u0000' {
          if x == q {
            q = '\u0000'
          }
        } else if x == '"' || x == '\'' {
          q = x
        } else if x == '{' {
          nesting += 1
        } else if x == '}' {
          nesting -= 1
        }
      }
      if nesting != 0 {
        raise Invalid("unterminated interpolation")
      }
      continue
    }
    if c == '/' &&
      self.pos < self.chars.length() &&
      self.chars[self.pos] == '/' &&
      level == 0 {
      while self.pos < self.chars.length() && self.chars[self.pos] != '\n' {
        self.pos += 1
      }
      out += " "
      continue
    }
    if c == '(' || c == '[' {
      level += 1
    }
    if c == ')' || c == ']' {
      level -= 1
      if level < 0 {
        raise Invalid("unbalanced value")
      }
    }
    if level == 0 && (c == ';' || c == '{' || c == '}') {
      return (out.trim().to_owned(), c)
    }
    out += c.to_string()
  }
  if quote != '\u0000' || level != 0 {
    raise Invalid("unterminated value")
  }
  (out.trim().to_owned(), '\u0000')
}