use(require(“atomy”)) use(require(“grammar”))

parser(Parser):

%%:
  def(trim-leading(str, n)):
    unless(n > 0):
      return(str)

    str gsub!(r"\n {0,#{n}}", "\n")

  def(word(l, x)):
    w = Atomy Grammar AST Word new(x)
    w line = l
    w

%atomy = Atomy Grammar

rule(line): { current-line }
rule(column): { current-column }

rule(comment): "{-" in-multi

rule(in-multi): [
  /"[^\-\{\}]*"/ "-}"
  /"[^\-\{\}]*"/ "{-" in-multi /"[^\-\{\}]*"/ "-}"
  /"[^\-\{\}]*"/ /"[-{}]"/ in-multi
]

rule(content(s)): comment? c=(chunk(s) | escaped) comment? { c }

rule(insignificant): (<(/"[^\\\{\}]+"/)> | "\\" <(/"[\\\{\}]"/)>) {
  text
}

rule(chunk(s)): [
  l=(line) chunk=(insignificant+) c=((&"}" | comment)?) {
    text = chunk join

    when(c):
      text rstrip!

    trim-leading(text, s)

    Atomy Grammar AST StringLiteral new(text)
  }

  nested
]

rule(escaped): [
  l=(line) "\\" n=(%atomy(identifier)) as=(argument+) {
    `((~word(l, n))(~*as))
  }

  l=(line) "\\" n=(%atomy(identifier)) { word(l, n) }

  l=(line) "\\" "(" e=(%atomy(expression)) ")" { e }
]

rule(leading): [
  &(/"\n+"/ b=(column) /"\s+"/ a=(column)) { a - b }
  { 0 }
]

rule(nested):
  l=(line) "{" s=(leading) cs=(content(s)*) "}" {
    when(cs[0] is-a?(Atomy Grammar AST StringLiteral)):
      cs[0] value sub!(r"^\n", "")

    cs match:
      []: Atomy Grammar AST StringLiteral new("")
      [x]: x
      _: `[~*cs]
  }

rule(atomy): "[" e=(%atomy(expression)) "]" { e }

rule(argument): nested | atomy

rule(root):
  l=(line) cs=(content(0)*) !_ {
    setup = Array[]
    definitions = Array[]

    filter = [c]:
      c match:
        (`use(~_) | `require(~_)):
          setup << c
          'nil

        `(def(~x): ~*y):
          definitions << c
          'nil

        `let(~x, ~y):
          definitions << `(~x = ~y)
          'nil

        `[~*cs]:
          `[~*(cs map &filter)]

        _:
          c

    body = cs map &filter

    Atomy Grammar AST Sequence new([
      'use(require("atomy"))
      'use(require("anatomy/base"))

      `(do:
          ~*setup
          ~*definitions
          def(doc): decode(~*body))
    ])
  }

Parser singleton:

def(parse-string(str)):
  p = new(str)
  unless(p parse):
    p raise-error

  p result

def(parse-file(path)):
  File open(path, "r") [f]:
    parse-string(f read)