the “sn” config file format
short for “string notation”. Read this for some of the design thoughts.
Currently exists in a half-finished recursive descent form in season2 but the fancy features are unused, I’m not confident enough to deploy the whole thing in a real mod
lexing
Part of what makes sn weird is that it has unquoted raw strings and whitespace is permitted inside them. The complexity for that lives in the lexer.
Normal tokens are {: LCURLY, }: RCURLY, [: LBRACK, ]: RBRACK, =: EQ, ,: COMMA, NEWLINE, and EOF. There is additionally a STRING token, tokenizable in two different ways:
- STRING (quoted)
- The usual. TODO remember the details.
- Main difference is that backslash-n and backslash-(literal newline) both work.
- STRING (unquoted)
- Beginning is marked by any non-token, non-horizontal-whitespace, non-quote character.
- End is marked by any token or quote character.
- Whitespace is trimmed.
- No escape sequences permitted.
TODO how did commas work again, I think in the recursive-descent parser they were “parsed as whitespace” but only in arrays
parsing
Pretend this is well-specified.
Value ::= STRING | Obj | Array
Delim ::= COMMA | NEWLINE | EOF
Obj ::= LCURLY Delim* ObjValues? RCURLY
ObjValues ::= STRING EQ Value? Delim* (Delim ObjValues)?
Array ::= LBRACK Delim* ArrayItems? RBRACK
ArrayItems ::= Value Delim* (Delim ArrayItems)?
File ::= Delim* ObjValues?
It’s awfully generous with delimiters.
In objvalues, if a value isn’t parsed it’s treated as "". This allows “blanking out” options to set them to the empty string (todo finetune this rule?)
The key, =, and value have to be on the same line. I might allow NEWLINE* before the equal sign but it can’t go after because of the “blanking out” rule
Parsing without a “parser generator” is straightforward but maybe a little awkward
- parse
STRING EQ - if the next token is a
DelimorRCURLY, treat the value as"", otherwise parse a value - eat
Delim*and keep track of how many times the star matched - if the next token is
RCURLY, break - else if the star matched at least one newline, loop
- else report an unexpected token
Two STRINGs can never be adjacent in this grammar
TODO: consider ObjValues ::= STRING (EQ Value | Obj | Array) ..., making the equal-sign optional if you’re defining an object or array. Sub-blocks look nice with this scheme (it’s groovy-ish) but could be error-prone.
blanking out rule
It’s impossible to support both of these:
the “i want a linebreak before my long message”
motd = {
message =
"Hello welcome to my server"
subtitle =
"Enjoy your stay! Visit our website..."
}
the “remove options by erasing their value”
filters {
animal =
vegetable =
mineral =
"dealer's choice" =
}