pub struct Parser<'a> { /* private fields */ }Expand description
Parser for Nash source code.
Combines the arena allocator with parsing state for a unified API. All parsed AST nodes are allocated in the provided bump arena.
The source bytes should already be allocated in the arena (via bump.alloc_str),
so all string slices in the resulting AST share the 'a lifetime.
Implementations§
Source§impl<'a> Parser<'a>
impl<'a> Parser<'a>
Sourcepub fn infix_decl(&mut self) -> Result<&'a Located<Infix<'a>>, ModuleErr<'a>>
pub fn infix_decl(&mut self) -> Result<&'a Located<Infix<'a>>, ModuleErr<'a>>
Parse an infix declaration.
Parses: infix left 6 (|>) = apR
Mirrors Elm’s infix_:
infix_ :: Parser E.Module (A.Located Src.Infix)
infix_ =
do start <- getPosition
Keyword.infix_ err
Space.chompAndCheckIndent _err err
associativity <- oneOf err [ left, right, non ]
Space.chompAndCheckIndent _err err
precedence <- Number.precedence err
Space.chompAndCheckIndent _err err
word1 0x28 {-(-} err
op <- Symbol.operator err _err
word1 0x29 {-)-} err
Space.chompAndCheckIndent _err err
word1 0x3D {-=-} err
Space.chompAndCheckIndent _err err
name <- Var.lower err
end <- getPosition
Space.chomp _err
Space.checkFreshLine err
return (A.at start end (Src.Infix op associativity precedence name))Source§impl<'a> Parser<'a>
impl<'a> Parser<'a>
Sourcepub fn declaration(&mut self) -> Result<(Decl<'a>, Position), Decl<'a>>
pub fn declaration(&mut self) -> Result<(Decl<'a>, Position), Decl<'a>>
Parse a single declaration.
Mirrors Elm’s declaration:
declaration :: Space.Parser E.Decl Decl
declaration =
do maybeDocs <- chompDocComment
start <- getPosition
oneOf E.DeclStart
[ typeDecl maybeDocs start
, portDecl maybeDocs -- skipped in Nash
, valueDecl maybeDocs start
]Source§impl<'a> Parser<'a>
impl<'a> Parser<'a>
Sourcepub fn expression(
&mut self,
) -> Result<(&'a Located<Expr<'a>>, Position), Expr<'a>>
pub fn expression( &mut self, ) -> Result<(&'a Located<Expr<'a>>, Position), Expr<'a>>
Parse a full expression, returning the expression and end position.
Mirrors Elm’s expression:
expression =
do start <- getPosition
oneOf E.Start
[ let_ start
, if_ start
, case_ start
, function start
, do expr <- possiblyNegativeTerm start
...
]Currently implements: lambda, possiblyNegativeTerm + function application. TODO: let, if, case, operators
Source§impl<'a> Parser<'a>
impl<'a> Parser<'a>
Sourcepub fn keyword_if<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_if<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the if keyword.
Mirrors Elm’s Keyword.if_.
Sourcepub fn keyword_then<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_then<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the then keyword.
Mirrors Elm’s Keyword.then_.
Sourcepub fn keyword_else<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_else<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the else keyword.
Mirrors Elm’s Keyword.else_.
Sourcepub fn keyword_case<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_case<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the case keyword.
Mirrors Elm’s Keyword.case_.
Sourcepub fn keyword_of<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_of<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the of keyword.
Mirrors Elm’s Keyword.of_.
Sourcepub fn keyword_let<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_let<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the let keyword.
Mirrors Elm’s Keyword.let_.
Sourcepub fn keyword_in<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_in<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the in keyword.
Mirrors Elm’s Keyword.in_.
Sourcepub fn keyword_type<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_type<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the type keyword.
Mirrors Elm’s Keyword.type_.
Sourcepub fn keyword_alias<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_alias<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the alias keyword.
Mirrors Elm’s Keyword.alias_.
Sourcepub fn keyword_infix<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_infix<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the infix keyword.
Mirrors Elm’s Keyword.infix_.
Sourcepub fn keyword_left<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_left<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the left keyword (for infix associativity).
Mirrors Elm’s Keyword.left_.
Sourcepub fn keyword_right<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_right<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the right keyword (for infix associativity).
Mirrors Elm’s Keyword.right_.
Sourcepub fn keyword_non<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_non<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the non keyword (for infix associativity).
Mirrors Elm’s Keyword.non_.
Sourcepub fn keyword_import<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_import<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the import keyword.
Mirrors Elm’s Keyword.import_.
Sourcepub fn keyword_as<E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn keyword_as<E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse the as keyword.
Mirrors Elm’s Keyword.as_.
Source§impl<'a> Parser<'a>
impl<'a> Parser<'a>
Sourcepub fn module_header(
&mut self,
) -> Result<(&'a Located<&'a str>, &'a Located<Exposing<'a>>), Module<'a>>
pub fn module_header( &mut self, ) -> Result<(&'a Located<&'a str>, &'a Located<Exposing<'a>>), Module<'a>>
Parse a module header.
Mirrors Elm’s chompHeader (simplified - no port/effect modules):
module_header = 'module' module_name 'exposing' exposing_listReturns the module name and exports as a tuple.
Source§impl<'a> Parser<'a>
impl<'a> Parser<'a>
Sourcepub fn number_literal<E>(
&mut self,
to_expectation: impl FnOnce(Row, Col) -> E,
to_error: impl FnOnce(Number, Row, Col) -> E,
) -> Result<i128, E>
pub fn number_literal<E>( &mut self, to_expectation: impl FnOnce(Row, Col) -> E, to_error: impl FnOnce(Number, Row, Col) -> E, ) -> Result<i128, E>
Parse an integer literal with custom error constructors.
Mirrors Elm’s Number.number:
number :: (Row -> Col -> x) -> (E.Number -> Row -> Col -> x) -> Parser x NumberTakes two error constructors:
to_expectation: called when no digit is found (empty error, no input consumed)to_error: called when parsing fails after consuming input
Handles:
- Decimal integers:
42,123 - Hex integers:
0xFF,0x1A2B
§Example
// From expression parsing:
self.number_literal(error::Expr::Start, error::Expr::Number)Source§impl<'a> Parser<'a>
impl<'a> Parser<'a>
Sourcepub fn pattern_term(&mut self) -> Result<&'a Located<Pattern<'a>>, Pattern<'a>>
pub fn pattern_term(&mut self) -> Result<&'a Located<Pattern<'a>>, Pattern<'a>>
Parse an atomic pattern (no cons, as, or ctor args).
Mirrors Elm’s Pattern.term:
term =
do start <- getPosition
oneOf E.PStart
[ record start
, tuple start
, list start
, termHelp start
]Sourcepub fn pattern_expr(
&mut self,
) -> Result<(&'a Located<Pattern<'a>>, Position), Pattern<'a>>
pub fn pattern_expr( &mut self, ) -> Result<(&'a Located<Pattern<'a>>, Position), Pattern<'a>>
Parse a full pattern expression including cons (::), as-patterns, and ctor with args.
Returns (pattern, end) where end is the position at the end of the pattern
(before any trailing whitespace was chomped). This is important for indent checking.
Mirrors Elm’s Pattern.expression:
expression :: Space.Parser E.Pattern Src.Pattern
expression =
do start <- getPosition
ePart <- exprPart
exprHelp start [] ePartSource§impl<'a> Parser<'a>
impl<'a> Parser<'a>
Sourcepub fn chomp<E>(
&mut self,
to_error: impl FnOnce(Space, Row, Col) -> E,
) -> Result<(), E>
pub fn chomp<E>( &mut self, to_error: impl FnOnce(Space, Row, Col) -> E, ) -> Result<(), E>
Consume whitespace and comments.
Returns an error if tabs or unclosed comments are found.
Mirrors Elm’s Space.chomp.
Sourcepub fn chomp_and_check_indent<E>(
&mut self,
to_space_error: impl FnOnce(Space, Row, Col) -> E,
to_indent_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn chomp_and_check_indent<E>( &mut self, to_space_error: impl FnOnce(Space, Row, Col) -> E, to_indent_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Consume whitespace and check that we’re indented past the current indent level.
Mirrors Elm’s Space.chompAndCheckIndent.
Sourcepub fn check_indent<E>(
&self,
end_row: Row,
end_col: Col,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn check_indent<E>( &self, end_row: Row, end_col: Col, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Check that current column is greater than indent level.
Called after a chomp to verify indentation.
Mirrors Elm’s Space.checkIndent.
Note: Uses end_col for the indent check (not current position),
matching Elm’s behavior where the position is passed explicitly.
Sourcepub fn check_aligned<E>(
&self,
to_error: impl FnOnce(u16, Row, Col) -> E,
) -> Result<(), E>
pub fn check_aligned<E>( &self, to_error: impl FnOnce(u16, Row, Col) -> E, ) -> Result<(), E>
Check that current column equals indent level (for alignment).
Mirrors Elm’s Space.checkAligned.
Source§impl<'a> Parser<'a>
impl<'a> Parser<'a>
Sourcepub fn string_literal<E>(
&mut self,
to_expectation: impl FnOnce(Row, Col) -> E,
to_error: impl FnOnce(StringError, Row, Col) -> E,
) -> Result<&'a str, E>
pub fn string_literal<E>( &mut self, to_expectation: impl FnOnce(Row, Col) -> E, to_error: impl FnOnce(StringError, Row, Col) -> E, ) -> Result<&'a str, E>
Parse a string literal with custom error constructors.
Mirrors Elm’s String.string:
string :: (Row -> Col -> x) -> (E.String -> Row -> Col -> x) -> Parser x ES.StringHandles both single-line ("...") and multi-line ("""...""") strings.
Source§impl<'a> Parser<'a>
impl<'a> Parser<'a>
Sourcepub fn type_expr(
&mut self,
) -> Result<(&'a Located<Type<'a>>, Position), Type<'a>>
pub fn type_expr( &mut self, ) -> Result<(&'a Located<Type<'a>>, Position), Type<'a>>
Parse a type expression including function arrows.
Returns (type, end) where end is the position at end of type (before any chomp).
Mirrors Elm’s Type.expression:
expression :: Space.Parser E.Type Src.Type
expression =
do start <- getPosition
term1@(tipe1, end1) <- oneOf E.TStart [ app start, term... ]
oneOfWithFallback [ arrow... ] term1Source§impl<'a> Parser<'a>
impl<'a> Parser<'a>
Sourcepub fn new(bump: &'a Bump, src: &'a [u8]) -> Self
pub fn new(bump: &'a Bump, src: &'a [u8]) -> Self
Create a new parser for the given source bytes.
The source should already be allocated in the arena.
Sourcepub fn get_position(&self) -> Position
pub fn get_position(&self) -> Position
Get the current position as a Position.
Sourcepub fn add_end<T>(&self, start: Position, value: T) -> &'a Located<T>
pub fn add_end<T>(&self, start: Position, value: T) -> &'a Located<T>
Create a Located value spanning from start to the current position,
allocated directly in the arena.
Sourcepub fn set_indent(&mut self, indent: u16)
pub fn set_indent(&mut self, indent: u16)
Set the indentation level.
Sourcepub fn with_indent<T, E>(
&mut self,
parser: impl FnOnce(&mut Self) -> Result<T, E>,
) -> Result<T, E>
pub fn with_indent<T, E>( &mut self, parser: impl FnOnce(&mut Self) -> Result<T, E>, ) -> Result<T, E>
Run a parser with the current column as the indent level, then restore the old indent level.
Mirrors Elm’s withIndent:
withIndent (Parser parser) =
Parser $ \(State src pos end oldIndent row col) cok eok cerr eerr ->
let
cok' a (State s p e _ r c) = cok a (State s p e oldIndent r c)
eok' a (State s p e _ r c) = eok a (State s p e oldIndent r c)
in
parser (State src pos end col row col) cok' eok' cerr eerrSourcepub fn with_backset_indent<T, E>(
&mut self,
backset: u16,
parser: impl FnOnce(&mut Self) -> Result<T, E>,
) -> Result<T, E>
pub fn with_backset_indent<T, E>( &mut self, backset: u16, parser: impl FnOnce(&mut Self) -> Result<T, E>, ) -> Result<T, E>
Run a parser with indent set to (current column - backset), then restore the old indent level.
Mirrors Elm’s withBacksetIndent:
withBacksetIndent backset (Parser parser) =
Parser $ \(State src pos end oldIndent row col) cok eok cerr eerr ->
parser (State src pos end (col - backset) row col) ...Sourcepub fn one_of<T, E>(
&mut self,
to_error: impl FnOnce(Row, Col) -> E,
parsers: Vec<Box<dyn FnOnce(&mut Self) -> Result<T, E> + '_>>,
) -> Result<T, E>
pub fn one_of<T, E>( &mut self, to_error: impl FnOnce(Row, Col) -> E, parsers: Vec<Box<dyn FnOnce(&mut Self) -> Result<T, E> + '_>>, ) -> Result<T, E>
Try multiple parsers in order, returning the first success.
Mirrors Elm’s oneOf:
oneOf :: (Row -> Col -> x) -> [Parser x a] -> Parser x aKey semantics:
- If a parser fails without consuming input, try the next one
- If a parser fails after consuming input, propagate the error (committed)
- If all parsers fail without consuming, call
to_error(row, col)
§Example
parser.one_of(
error::Expr::Start,
vec![
Box::new(|p: &mut Parser| p.string(start)),
Box::new(|p| p.number(start)),
],
)Sourcepub fn one_of_with_fallback<T, E>(
&mut self,
parsers: Vec<Box<dyn FnOnce(&mut Self) -> Result<T, E> + '_>>,
fallback: T,
) -> Result<T, E>
pub fn one_of_with_fallback<T, E>( &mut self, parsers: Vec<Box<dyn FnOnce(&mut Self) -> Result<T, E> + '_>>, fallback: T, ) -> Result<T, E>
Like one_of but returns a fallback value if nothing matches.
Mirrors Elm’s oneOfWithFallback:
oneOfWithFallback :: [Parser x a] -> a -> Parser x aSourcepub fn in_context<T, StartErr, BodyErr, ContextErr>(
&mut self,
add_context: impl FnOnce(&'a Bump, BodyErr, Row, Col) -> ContextErr,
start_parser: impl FnOnce(&mut Self) -> Result<(), StartErr>,
body_parser: impl FnOnce(&mut Self) -> Result<T, BodyErr>,
) -> Result<T, ContextErr>where
StartErr: Into<ContextErr>,
pub fn in_context<T, StartErr, BodyErr, ContextErr>(
&mut self,
add_context: impl FnOnce(&'a Bump, BodyErr, Row, Col) -> ContextErr,
start_parser: impl FnOnce(&mut Self) -> Result<(), StartErr>,
body_parser: impl FnOnce(&mut Self) -> Result<T, BodyErr>,
) -> Result<T, ContextErr>where
StartErr: Into<ContextErr>,
Parse with error context wrapping.
Mirrors Elm’s inContext:
inContext :: (x -> Row -> Col -> y) -> Parser y start -> Parser x a -> Parser y a- Saves the starting position
- Runs
start_parser- if it fails without consuming, returns that error - If start succeeds, runs
body_parser - If body fails, wraps the error using
add_contextat the original position
The add_context closure receives the bump allocator so it can allocate wrapped errors.
This is used to provide better error context, e.g., “error in list expression”.
Sourcepub fn specialize<T, InnerErr, OuterErr>(
&mut self,
add_context: impl FnOnce(&'a Bump, InnerErr, Row, Col) -> OuterErr,
parser: impl FnOnce(&mut Self) -> Result<T, InnerErr>,
) -> Result<T, OuterErr>
pub fn specialize<T, InnerErr, OuterErr>( &mut self, add_context: impl FnOnce(&'a Bump, InnerErr, Row, Col) -> OuterErr, parser: impl FnOnce(&mut Self) -> Result<T, InnerErr>, ) -> Result<T, OuterErr>
Transform errors from one type to another with position context.
Mirrors Elm’s specialize:
specialize :: (x -> Row -> Col -> y) -> Parser x a -> Parser y aRuns the parser and wraps any error with the context at the starting position.
The add_context closure receives the bump allocator so it can allocate wrapped errors.
Sourcepub fn word1<E>(
&mut self,
expected: u8,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn word1<E>( &mut self, expected: u8, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse a single expected byte.
Mirrors Elm’s word1:
word1 :: Word8 -> (Row -> Col -> x) -> Parser x ()Returns Ok(()) and advances if the byte matches.
Returns Err without consuming if it doesn’t match.
Sourcepub fn word2<E>(
&mut self,
b1: u8,
b2: u8,
to_error: impl FnOnce(Row, Col) -> E,
) -> Result<(), E>
pub fn word2<E>( &mut self, b1: u8, b2: u8, to_error: impl FnOnce(Row, Col) -> E, ) -> Result<(), E>
Parse two expected consecutive bytes.
Mirrors Elm’s word2:
word2 :: Word8 -> Word8 -> (Row -> Col -> x) -> Parser x ()Sourcepub fn peek_at(&self, offset: usize) -> Option<u8>
pub fn peek_at(&self, offset: usize) -> Option<u8>
Peek at a byte at the given offset from current position.
Sourcepub fn advance_by(&mut self, n: usize)
pub fn advance_by(&mut self, n: usize)
Advance by n bytes, tracking newlines.
Sourcepub fn alloc_slice_copy<T: Copy>(&self, slice: &[T]) -> &'a [T]
pub fn alloc_slice_copy<T: Copy>(&self, slice: &[T]) -> &'a [T]
Allocate a slice in the arena by copying.