;;;;;;;;;;;
;; Lexer ;;
;;;;;;;;;;;

;; Visible characters
visible = ascii-visible / unicode-visible
visible-nonquote = ascii-visible-nonquote unicode-visible

;; Whitespace
newline = ascii-nl / unicode-nl
space = ascii-space / unicode-space
whitespace = space / newline

;; Letters
alpha = ascii-alpha / unicode-alpha

;; Numbers
digit = ascii-digit / unicode-digit
number = digit / unicode-num

;; Comments
comment = "//" *(space / visible) newline
empty = *whitespace [comment empty]
emptytoeol = [*space (comment / newline) emptytoeol]

;; C identifiers
ascii-nondigit = ascii-alpha / "_"
c-identifier = ascii-nondigit *(ascii-nondigit / ascii-digit)

;; Smudge identifiers
idchar = alpha / number / "-" / "_"
unquoted = 1*idchar
quoted = DQUOTE 1*(whitespace / visible-nonquote) DQUOTE
identifier = (unquoted / quoted) ; empty
foreign-identifier = "@" c-identifier ; empty

;; Smudge pragmas
pragma = "#" command [1*space argument] *space newline
command = 1*idchar
argument = 1*visible *[1*space 1*visible]

;; Smudge symbols
; The uses of 'empty'/'space' below (and above in identifier) are not needed in
; the lexer implementation, but they must be added back in for the productions
; to be used as generators.
start-sigil = "*" ; empty
comma = "," ; empty
dot = "." ; empty
state-machine-begin = "{" ; empty
state-machine-end   = "}" ; empty
state-begin = "[" ; empty
state-end   = "]" ; empty
arrow-empty = ; space
              "-->" ; empty
dash-empty = ; space
             "--" ; empty
become-empty = ; space
               "~~>" ; empty
dash-begin = ; space
             "-(" ; empty
arrow-end = ")->" ; empty
dash-end = ")-" ; empty
become-begin = ; space
               "~(" ; empty
become-end = ")~>" ; empty
enter-exit-begin = ; space
                   "(" ; empty
enter-exit-end   = ")" ; empty

;; Smudge lexing
token = start-sigil / comma / dot
      / state-machine-begin / state-machine-end / state-begin / state-end
      / arrow-empty / dash-empty / become-empty
      / dash-begin / arrow-end / dash-end / become-begin / become-end
      / enter-exit-begin / enter-exit-end
      / identifier / foreign-identifier
smudge-file = *(emptytoeol pragma) empty *(token empty)
