// BEGIN of GENERIC RULES
// insignificant whitespace, not repeated
ws = _{ " " | "\t" }
meta_attr_key = ${ "name" | "version" | "precompiler" }
meta_attr_value = ${ string | char+}
meta_key_pair = @{ meta_attr_key ~ arg_ws? ~ "=" ~ arg_ws? ~ meta_attr_value }
meta_comment = @{ "--" ~ ws* ~ (!NEWLINE ~ meta_key_pair)* }
meta_comment_line = _{ ws* ~ meta_comment ~ NEWLINE? }
comment = @{ "#" ~ (!NEWLINE ~ ANY)* }
comment_line = _{ ws* ~ comment ~ NEWLINE? }
empty_line = @{ ws* ~ NEWLINE }
double_quoted_string = _{ "\"" ~ inner ~ "\"" }
inner = @{ (!("\"" | "\\" | "\u{0000}" | "\u{001F}") ~ ANY)* ~ (escape ~ inner)? }
escape = @{ "\\" ~ ("b" | "t" | "n" | "f" | "r" | "\"" | "\\" | "'" | unicode | NEWLINE)? }
unicode = @{ "u" ~ ASCII_HEX_DIGIT{4} | "U" ~ ASCII_HEX_DIGIT{8} }
single_quoted_string = _{ "'" ~ single_quoted_inner ~ "'" }
single_quoted_inner = @{ (!("'" | "\\" | "\u{0000}" | "\u{001F}") ~ ANY)* ~ (escape ~ single_quoted_inner)? }
string = ${ single_quoted_string | double_quoted_string }
// a line continuation, allowing an instruction to continue onto a new line
line_continuation = _{ "\\" ~ ws* ~ NEWLINE }
// whitespace that may appear between instruction arguments
// this allows instructions to expand past a newline if escaped
arg_ws = _{ (ws | line_continuation ~ (comment_line | empty_line)*)+ }
// like arg_ws, but where whitespace is optional
arg_ws_maybe = _{ (ws | line_continuation ~ (comment_line | empty_line)*)* }
// continues consuming input beyond a newline, if the newline is preceeded by an
// escape (\)
// these tokens need to be preserved in the final tree so they can be handled
// appropraitely; pest's ignore rules aren't sufficient for our needs
any_content = @{
(
!NEWLINE ~
!line_continuation ~
ANY
)+
}
any_breakable = ${
(
// can be any comment string (no line continuation required)
comment_line ~ any_breakable?
) | (
// ... OR some piece of content, requiring a continuation EXCEPT on the
// final line
any_content ~ (line_continuation ~ any_breakable)?
)
}
// consumes any character until the end of the line
any_eol = _{ (!NEWLINE ~ ANY)* }
// consumes all characters until the next whitespace
until_whitespace = _{ (!(NEWLINE | EOI | arg_ws) ~ ANY)+ }
// consumes identifier characters until the next whitespace
identifier_whitespace = _{ (!ws ~ (ASCII_ALPHANUMERIC | "_" | "-"))+ }
// consumes until whitespace or = (for key in key=value pairs)
any_equals = _{ (!(NEWLINE | ws | "=") ~ ANY)+ }
// END of GENERIC RULES
commands = _{
(
from |
add |
modify |
remove
) ~ NEWLINE?
}
from = { ^"from" ~ ws* ~ from_said}
add = { ^"add" ~ arg_ws* ~ oca_object }
modify = { ^"modify" ~ char+ }
remove = { ^"remove" ~ arg_ws* ~ remove_oca_object }
SCRIPTS = { ADLAM | AHOM | ANATOLIAN_HIEROGLYPHS | ARABIC | ARMENIAN | AVESTAN
| BALINESE | BAMUM | BASSA_VAH | BATAK | BENGALI | BHAIKSUKI | BOPOMOFO |
BRAHMI | BRAILLE | BUGINESE | BUHID | CANADIAN_ABORIGINAL | CARIAN |
CAUCASIAN_ALBANIAN | CHAKMA | CHAM | CHEROKEE | CHORASMIAN | COPTIC |
CUNEIFORM | CYPRIOT | CYPRO_MINOAN | CYRILLIC | DESERET | DEVANAGARI |
DIVES_AKURU | DOGRA | DUPLOYAN | EGYPTIAN_HIEROGLYPHS | ELBASAN | ELYMAIC |
ETHIOPIC | GEORGIAN | GLAGOLITIC | GOTHIC | GRANTHA | GREEK | GUJARATI |
GUNJALA_GONDI | GURMUKHI | HAN | HANGUL | HANIFI_ROHINGYA | HANUNOO | HATRAN |
HEBREW | HIRAGANA | IMPERIAL_ARAMAIC | INHERITED | INSCRIPTIONAL_PAHLAVI |
INSCRIPTIONAL_PARTHIAN | JAVANESE | KAITHI | KANNADA | KATAKANA | KAWI |
KAYAH_LI | KHAROSHTHI | KHITAN_SMALL_SCRIPT | KHMER | KHOJKI | KHUDAWADI | LAO
| LATIN | LEPCHA | LIMBU | LINEAR_A | LINEAR_B | LISU | LYCIAN | LYDIAN |
MAHAJANI | MAKASAR | MALAYALAM | MANDAIC | MANICHAEAN | MARCHEN | MASARAM_GONDI
| MEDEFAIDRIN | MEETEI_MAYEK | MENDE_KIKAKUI | MEROITIC_CURSIVE |
MEROITIC_HIEROGLYPHS | MIAO | MODI | MONGOLIAN | MRO | MULTANI | MYANMAR |
NABATAEAN | NAG_MUNDARI | NANDINAGARI | NEW_TAI_LUE | NEWA | NKO | NUSHU |
NYIAKENG_PUACHUE_HMONG | OGHAM | OL_CHIKI | OLD_HUNGARIAN | OLD_ITALIC |
OLD_NORTH_ARABIAN | OLD_PERMIC | OLD_PERSIAN | OLD_SOGDIAN | OLD_SOUTH_ARABIAN
| OLD_TURKIC | OLD_UYGHUR | ORIYA | OSAGE | OSMANYA | PAHAWH_HMONG | PALMYRENE
| PAU_CIN_HAU | PHAGS_PA | PHOENICIAN | PSALTER_PAHLAVI | REJANG | RUNIC |
SAMARITAN | SAURASHTRA | SHARADA | SHAVIAN | SIDDHAM | SIGNWRITING | SINHALA |
SOGDIAN | SORA_SOMPENG | SOYOMBO | SUNDANESE | SYLOTI_NAGRI | SYRIAC | TAGALOG
| TAGBANWA | TAI_LE | TAI_THAM | TAI_VIET | TAKRI | TAMIL | TANGSA | TANGUT |
TELUGU | THAANA | THAI | TIBETAN | TIFINAGH | TIRHUTA | TOTO | UGARITIC | VAI |
VITHKUQI | WANCHO | WARANG_CITI | YEZIDI | YI | ZANABAZAR_SQUARE }
char = { LETTER | NUMBER | "." | "-" | "_" | "/" | ":" | SCRIPTS }
from_said = { ws* ~ char+ }
oca_object = _{
(
meta |
label |
attribute |
classification |
information |
unit |
character_encoding |
character_encoding_props |
format |
conformance |
conditional |
cardinality |
entry_code |
entry |
link |
attribute_framing |
flagged_attrs
)
}
remove_oca_object = _{
(
remove_meta |
remove_label |
remove_attribute |
remove_classification |
information |
unit |
character_encoding |
character_encoding_props |
format |
conformance |
conditional |
cardinality |
entry_code |
entry |
link |
attribute_framing |
flagged_attrs
)
}
attrs_key = _{ ^"attrs" ~ arg_ws}
props_key = _{ ^"props" ~ arg_ws}
label = { ^"label" ~ arg_ws ~ lang ~ arg_ws ~ attrs_key ~ attr_key_pairs }
meta = { ^"meta" ~ arg_ws ~ lang ~ arg_ws ~ props_key ~ prop_key_pairs }
information = {^"information" ~ arg_ws ~ lang ~ arg_ws ~ attrs_key ~ attr_key_pairs}
character_encoding = {^"character_encoding" ~ arg_ws ~ attrs_key ~ attr_key_pairs}
character_encoding_props = {^"character_encoding" ~ arg_ws ~ props_key ~ prop_key_pairs}
format = {^"format" ~ arg_ws ~ attrs_key ~ attr_key_pairs}
conformance = {^"conformance" ~ arg_ws ~ attrs_key ~ attr_key_pairs}
conditional = {^"condition" ~ arg_ws ~ attrs_key ~ attr_key_pairs}
cardinality = {^"cardinality" ~ arg_ws ~ attrs_key ~ attr_key_pairs}
entry_code = {^"entry_code" ~ arg_ws ~ attrs_key ~ attr_entry_code_key_pairs}
entry = {^"entry" ~ arg_ws ~ lang ~ arg_ws ~ attrs_key ~ attr_entry_key_pairs}
unit = {^"unit" ~ arg_ws ~ attrs_key ~ unit_attr_key_pairs}
link = {^"link" ~ arg_ws ~ reference_type ~ arg_ws ~ attrs_key ~ attr_key_pairs}
attribute_framing = {^"attr_framing" ~ arg_ws ~ framing_metadata ~ arg_ws ~ attrs_key ~ attr_framing_key_pairs+}
framing_metadata_key = ${ "id" | "label" | "location" | "version" }
framing_metadata_value = ${ string | char+ }
framing_metadata_pair = @{ framing_metadata_key ~ arg_ws? ~ "=" ~ arg_ws? ~ framing_metadata_value }
framing_metadata = { framing_metadata_pair ~ (arg_ws ~ framing_metadata_pair)* }
attr_framing_key_pair = @{ attr_key ~ arg_ws? ~ "=" ~ arg_ws? ~ json_object }
attr_framing_key_pairs = ${ arg_ws* ~ attr_framing_key_pair ~ (arg_ws | NEWLINE)? }
url = ${ string }
json_key = ${ string }
json_value = ${ string | url | json_object }
json_pair = ${ json_key ~ arg_ws* ~ ":" ~ (arg_ws | NEWLINE)? ~ json_value ~ (arg_ws? ~ "," ~ (arg_ws | NEWLINE)?)? }
json_object = ${ "{" ~ ((arg_ws | NEWLINE)? ~ arg_ws* ~ json_pair ~ (arg_ws | NEWLINE)?)+ ~ arg_ws* ~ "}" }
flagged_attrs = {^"flagged_attributes" ~ arg_ws ~ list_value}
classification = { ^"classification" ~ arg_ws ~ classification_value}
remove_classification = { ^"classification"}
classification_value = { string | char+}
//overlay_args = { ws* ~ ANY* }
attribute = { ^"attribute" ~ attr_pairs+ }
remove_attribute = { ^"attribute" ~ (arg_ws ~ attr_key)* }
remove_meta = { ^"meta" ~ arg_ws ~ lang ~ (arg_ws ~ props_key ~ prop_key+)? }
remove_label = { ^"label" ~ arg_ws ~ lang ~ (arg_ws ~ attrs_key ~ attr_key+)? }
attr_key = ${ (ASCII_ALPHANUMERIC | "-" | "_" | ".")+ }
prop_key = ${ (ASCII_ALPHANUMERIC | "-" | "_")+ }
key_value = ${ string | char+}
key_pair = @{ attr_key ~ arg_ws? ~ "=" ~ arg_ws? ~ key_value }
attr_key_pairs = ${ (arg_ws? ~ key_pair ~ arg_ws?)+ }
prop_key_pairs = ${ (arg_ws? ~ key_pair ~ arg_ws?)+ }
unit_char = ${ !" " ~ !NEWLINE ~ ANY }
unit_value = ${ string | unit_char+ }
unit_key_pair = @{ attr_key ~ arg_ws? ~ "=" ~ arg_ws? ~ unit_value }
unit_attr_key_pairs = ${ (arg_ws? ~ unit_key_pair ~ arg_ws?)+ }
entry_code_list = { "[" ~ "]" | "[" ~ string ~ ("," ~ " "* ~ string)* ~ "]" }
entry_code_object = { "{" ~ "}" | "{" ~ " "* ~ entry_code_key_value_pair ~ ("," ~ " "* ~ entry_code_key_value_pair)* ~ " "* ~ "}" }
entry_code_group_key = ${ string }
entry_code_key_value_pair = { entry_code_group_key ~ ":" ~ " "* ~ entry_code_list }
entry_code_key_value = { key_value | entry_code_list | entry_code_object }
entry_code_key_pair = ${ attr_key ~ "=" ~ entry_code_key_value }
attr_entry_code_key_pairs = ${ (arg_ws? ~ entry_code_key_pair ~ arg_ws?)+ }
entry_value = ${ string }
entry_key = ${ string }
entry_object = { "{" ~ "}" | "{" ~ " "* ~ entry_key_value_pair ~ ("," ~ " "* ~ entry_key_value_pair)* ~ " "* ~ "}" }
entry_key_value = { key_value | entry_object }
entry_key_value_pair = { entry_key ~ ":" ~ " "* ~ entry_value }
entry_key_pair = ${ attr_key ~ "=" ~ entry_key_value }
attr_entry_key_pairs = ${ (arg_ws? ~ entry_key_pair ~ arg_ws?)+ }
list_value = ${ (arg_ws? ~ key_value ~ arg_ws?)+ }
unit_system = ${ (ASCII_ALPHANUMERIC | "-" | "_")+ }
base_attr_type = @{ ("Text" |
"Numeric" |
"Boolean" |
"Binary" |
"DateTime" )}
array_attr_type = ${( "Array["~ arg_ws? ~ (base_attr_type | reference_type | array_attr_type ) ~ arg_ws? ~"]" )}
reference_type = _{ ref_said | ref_alias }
alias = @{ char+ }
said = @{ char+ }
refs = _{^"refs:"}
refn = _{^"refn:"}
ref_said = _{ refs ~ said}
ref_alias = _{ refn ~ alias }
_attr_type = ${ base_attr_type | array_attr_type | ref_said | ref_alias }
attr_pair = @{attr_key ~ arg_ws? ~ "=" ~ arg_ws? ~ _attr_type}
attr_pairs = ${ (arg_ws ~ attr_pair)+}
lang = ${ ASCII_ALPHA{2} ~ ("-" ~ ASCII_ALPHA{2})? }
file = {
SOI ~
(empty_line | meta_comment_line | comment_line | commands)*
~ EOI
}