SPACE = _{" "|"\t"}
SPACES = _{SPACE*}
// Tags
TAG_OPEN = _{"<<"}
TAG_CLOSE = _{">>"}
// Keywords
SOLUTION = _{"solution"}
PLACEHOLDER = _{"placeholder"}
// Comment and markup definitions
COMMENT_SYMBOLS = _{"#"|"//"}
COMMENT_DEF = _{COMMENT_SYMBOLS}
MARKUP = _{COMMENT_DEF ~ "|"}
REGULAR_COMMENT = _{COMMENT_DEF ~ !"|"}
// Captures any single line string
ident = {(ASCII_ALPHANUMERIC | "_")+}
str = {(!NEWLINE ~ ANY)*}
str_anon = _{(!NEWLINE ~ ANY)*}
// Source code elements
comment_space = {SPACES}
source_comment = {comment_space ~ REGULAR_COMMENT ~ SPACES ~ str}
source_code = {(!(NEWLINE|MARKUP) ~ ANY)*}
source_code_block = @{((source_comment | source_code) ~ NEWLINE)+}
source_comment_block = {(source_comment ~ NEWLINE)+}
// Code block definitions
code_block = {SPACES ~ code_block_def ~ NEWLINE ~ solution ~ (code_block_placeholder ~ NEWLINE ~ placeholder)? ~ code_block_end }
code_block_def = _{ MARKUP ~ SPACES ~ SOLUTION ~ SPACES ~ TAG_OPEN ~ SPACES}
code_block_end = _{ SPACES ~ MARKUP ~ SPACES ~ TAG_CLOSE ~ SPACES }
code_block_placeholder = _{ SPACES ~ MARKUP ~ SPACES ~ PLACEHOLDER ~ SPACES }
// Solution and placeholder definitions
solution = {(source_code_block)*}
placeholder = {(source_comment_block)*}
meta = {SPACES ~ MARKUP ~ SPACES ~ meta_inner ~ SPACES}
meta_inner = _{custom}
custom = {ident ~ ":" ~ SPACES ~ value}
key = {str}
value = {str_anon}
// Top level glue
top_level = _{SPACES ~ (code_block ~ NEWLINE| meta ~ NEWLINE | source_code_block )}
src = {top_level+}
doc = _{src ~ EOI}