mtparser/parser
Stages 2+3: classify each line, then parse command arguments.
Reading model (terminology per the official docs):
- The ROUTING UNIT is the statement’s first segment. It is read BY each
statement parser (
read_unit) for its own needs, not pre-read by the caller:--lines end at the newline (comment-mode path in mysqltest.cc), bare lines end at the delimiter. - Each statement owns its full extent. Simple statements (echo, SQL,
cat_file, assert) end with the routing unit; block statements extend
via their own TERMINATOR — the close marker for append_file (and
write_file/perl later),
}for if/while — read by the statement’s own parser. - Command parsers strictly parse their own arguments (tokenization, escapes, evaluation, quote rules are command grammar); the caller only peeks the first word for routing.
parse_statement is the single hub:
- blank → no statement (blank lines are skipped in the main loop)
#…→Comment--prefix → parse the dash command (parse_dash_command_statement) in endline-delimiter mode; a--line IS a command, so unknown names are real errors here- anything else → route by the first word (
parse_command_statement); an unknown bare statement is just a query (parse_sql_statement). Errors from known commands are real errors in both forms.
Types
Parser state, threaded explicitly through the loop.
next_endline_as_delimiter reflects the -- prefix: while a --
command’s routing unit is being read, the endline (a newline, or the end
of file for a final line without one) acts as its delimiter (“A --
command is terminated by a newline, regardless of how many delimiters it
contains”). The flag is one-shot: set by parse_dash_command_statement,
consumed by the one-line read in read_unit — reaching the endline
consumes it, whoever reads there.
pub type ParserState {
ParserState(delimiter: String, next_endline_as_delimiter: Bool)
}
Constructors
-
ParserState(delimiter: String, next_endline_as_delimiter: Bool)
Values
pub fn parse_expr(
input: String,
base_offset: Int,
) -> Result(ast.Expr, Nil)
Parse a condition expression. input is the argument text (e.g. "(1)"),
base_offset the byte offset of its first byte in the source.
pub fn parse_interpolated_text(
text: String,
) -> List(ast.TextPart)
Parse with base byte offset 0.
pub fn parse_interpolated_text_with_offset(
text: String,
base_offset: Int,
) -> List(ast.TextPart)
Parse, adding base_offset to every part’s span offset.
Scanning rules:
\$→ literal$$followed by a digit → register variable$0-$9(mysqltest.cc var_get routes digits to var_reg; a single-character name)$followed by[a-zA-Z_]then[a-zA-Z0-9_]*→ variable reference (mysqltest.cc my_isvar = alnum | ‘_’ — a-ENDS the name, so$i-1is$ifollowed by the literal-1)$followed by anything else (or end of text) → literal$- everything else accumulates into literals
pub fn parse_statements(
all: List(ast.Line),
) -> Result(
#(List(ast.Statement), ParserState),
error.ParserError,
)
Parse all lines into statements.