struct Parser<'a> {
tokens: &'a [Token],
src: &'a str,
pos: usize,
}Expand description
Hand-written recursive-descent parser. Holds a borrow on the token slice and source string; produces AST nodes that own their data (so the parser’s lifetime doesn’t leak into downstream consumers).
Fields§
§tokens: &'a [Token]§src: &'a str§pos: usizeImplementations§
Source§impl<'a> Parser<'a>
impl<'a> Parser<'a>
fn new(tokens: &'a [Token], src: &'a str) -> Self
fn peek(&self) -> &Token
fn peek_at(&self, offset: usize) -> Option<&Token>
fn bump(&mut self) -> &Token
fn at(&self, kind: &TokenKind) -> bool
fn eat(&mut self, kind: &TokenKind) -> bool
fn expect(&mut self, kind: TokenKind, ctx: &str) -> Result<(), ParseError>
fn ident_text(&self, span: Span) -> &'a str
Sourcefn expect_ident(&mut self, ctx: &str) -> Result<(String, Span), ParseError>
fn expect_ident(&mut self, ctx: &str) -> Result<(String, Span), ParseError>
Consume the current token if it’s an Ident and return its text.
Errors with ctx in the message otherwise.
fn parse_translation_unit(&mut self) -> Result<TranslationUnit, ParseError>
Sourcefn is_function_signature(&self) -> bool
fn is_function_signature(&self) -> bool
Peek 3 tokens to decide if we’re looking at a function definition:
<type-ident> <name-ident> (. Doesn’t consume.
Sourcefn is_global_var_decl(&self) -> bool
fn is_global_var_decl(&self) -> bool
Top-level global var decl detection: <type-ident> <name-ident>
where the third token is not (. Doesn’t consume.
Sourcefn parse_global_var_decl(
&mut self,
items: &mut Vec<Item>,
) -> Result<(), ParseError>
fn parse_global_var_decl( &mut self, items: &mut Vec<Item>, ) -> Result<(), ParseError>
Parse [static] [const] <type> <name>[<array>] [= <init>] [, <name> ...] ;
and flatten the comma list into one Item::GlobalVar per name.
The qualifier flags propagate to every flattened variable.
fn parse_sampler_decl(&mut self) -> Result<Item, ParseError>
Sourcefn skip_braced_block(&mut self) -> Result<(), ParseError>
fn skip_braced_block(&mut self) -> Result<(), ParseError>
{ ... } skipper for opaque blocks (sampler_state, struct bodies in
the rare cases MD2 uses them). Caller positions us at {; we end
after the matching }.
fn parse_function_def(&mut self) -> Result<FunctionDef, ParseError>
fn parse_param(&mut self) -> Result<Param, ParseError>
Sourcefn parse_type(&mut self) -> Result<TypeRef, ParseError>
fn parse_type(&mut self) -> Result<TypeRef, ParseError>
<type-ident> — one identifier consumed. We do not look ahead for
matrix bracket syntax; HLSL spells matrices as compound idents
(float2x2, mat3x3).
fn parse_block(&mut self) -> Result<Block, ParseError>
fn parse_block_after_brace( &mut self, open_span: Span, ) -> Result<Block, ParseError>
Sourcefn parse_stmt_unit(&mut self, out: &mut Vec<Stmt>) -> Result<(), ParseError>
fn parse_stmt_unit(&mut self, out: &mut Vec<Stmt>) -> Result<(), ParseError>
Parse one syntactic statement unit and push the resulting Stmt(s)
onto out. Most kinds push exactly one statement, but two HLSL
idioms produce multiple:
- Multi-name declarations (
float a, b, c;) — one Stmt per name. - Comma-separated statements (
a += 1, b += 2;) — one Stmt per comma-separated assignment/expression.
The block parser calls this in a loop so the caller-side AST sees a flat statement list — convenient for downstream emitters that don’t care about source-line grouping.
Sourcefn parse_stmt(&mut self) -> Result<Stmt, ParseError>
fn parse_stmt(&mut self) -> Result<Stmt, ParseError>
Compatibility shim — many internal callsites (for-loop init, etc.)
still want a single Stmt. Calls [parse_stmt_unit] and pulls the
first emitted statement; subsequent statements (rare in those
contexts) are concatenated as a synthetic Stmt::Block so no
declared variables go missing.
Sourcefn parse_decl_or_expr_stmts(
&mut self,
out: &mut Vec<Stmt>,
) -> Result<(), ParseError>
fn parse_decl_or_expr_stmts( &mut self, out: &mut Vec<Stmt>, ) -> Result<(), ParseError>
The tricky dispatch: a statement starts with an Ident. Decide
between local decl (<type> <name>) and expression statement
(<expr>; or <lhs> [op]= <rhs>;).
Heuristic: if the lookahead is Ident Ident, it’s a decl. We also
allow the leading qualifier const for completeness even though MD2
rarely uses it locally.
Sourcefn parse_local_decl_tail(
&mut self,
out: &mut Vec<Stmt>,
) -> Result<(), ParseError>
fn parse_local_decl_tail( &mut self, out: &mut Vec<Stmt>, ) -> Result<(), ParseError>
Parse the rest of a local decl after the type+name lookahead
matched. Eats: <type> <name>[<dim>] [= <init>] [, <name>...] ;.
Pushes one Stmt::LocalDecl per name onto out.
Sourcefn parse_expr_or_assign_stmts(
&mut self,
out: &mut Vec<Stmt>,
) -> Result<(), ParseError>
fn parse_expr_or_assign_stmts( &mut self, out: &mut Vec<Stmt>, ) -> Result<(), ParseError>
Parse one or more comma-separated <expr> or <lhs> [op]= <rhs>
statements, terminated by ;. MD2 user shaders use the comma
form (a += 1, b += 2;) freely; we flatten into multiple
statements at parse time so downstream emitters don’t need to
understand the comma operator.