diff options
author | JJ | 2023-11-08 09:47:51 +0000 |
---|---|---|
committer | JJ | 2023-11-08 09:47:51 +0000 |
commit | ce3e54ff8cb45af6e4f0becab5325c0abd02f1fb (patch) | |
tree | c1de76260304c5a2f04f8eab17f5792f991acb98 /src | |
parent | 201ce572671d335e54f0f62c3e380d169449fe53 (diff) |
compiler: write some helpers, reduce parser verbosity
Diffstat (limited to 'src')
-rw-r--r-- | src/frontend/parse.rs | 156 |
1 files changed, 76 insertions, 80 deletions
diff --git a/src/frontend/parse.rs b/src/frontend/parse.rs index 43de16e..62fe39f 100644 --- a/src/frontend/parse.rs +++ b/src/frontend/parse.rs @@ -7,7 +7,27 @@ use Token::*; use Literal::*; use Punctuation::*; -type Input = std::iter::Peekable<std::vec::IntoIter<Token>>; +struct Input(std::iter::Peekable<std::vec::IntoIter<Token>>); + +impl Input { + /// Map input.next() to return Results for use with the propagation operator + fn next(&mut self) -> Result<Token> { + self.0.next().ok_or("end of input".into()) + } + + /// Map input.peek() to return Results for use with the propagation operator + fn peek(&mut self) -> Result<&Token> { + self.0.peek().ok_or("end of input".into()) + } + + /// Asserts the next character to be a known token + fn then(&mut self, expected: Token) -> Result<()> { + match self.next()? { + token if expected == token => Ok(()), + token => Err(format!("expected token {} but found {}", expected, token).into()) + } + } +} #[derive(Clone, Copy)] struct State { @@ -26,7 +46,7 @@ impl State { /// Convert a basic TokenStream into an AbstractSyntaxTree pub fn astify(input: TokenStream, name: &str) -> Result<Expr> { - let mut input = input.into_iter().peekable(); + let mut input = Input(input.into_iter().peekable()); let body = parse_body(&mut input, State { depth: 0, step: 0 })?; Ok(Expr::Binding(Module{ id: name.to_string(), body })) } @@ -34,8 +54,8 @@ pub fn astify(input: TokenStream, name: &str) -> Result<Expr> { /// Parse a series of Exprs, for ex. the body of a function. fn parse_body(input: &mut Input, state: State) -> Result<Vec<Expr>> { let mut res = Vec::new(); - while input.peek() == Some(&Indent(state.depth)) { - input.next(); + while input.peek()? == &Indent(state.depth) { + input.next()?; res.push(parse_expr(input, state)?); } Ok(res) @@ -45,19 +65,18 @@ fn parse_body(input: &mut Input, state: State) -> Result<Vec<Expr>> { /// Block | Static | For | While | Loop | If | When | Try | Match fn parse_expr(input: &mut Input, state: State) -> Result<Expr> { use Keyword::*; - match input.next() { - Some(Key(word)) => match word { + match input.next()? { + Key(word) => match word { Pub => { - match input.next() { - Some(Key(word)) => match word { + match input.next()? { + Key(word) => match word { Const => parse_const(input, state, true), Func => parse_funcdecl(input, state, true), Type => parse_typedecl(input, state, true), Mod => parse_mod(input, state, true), _ => return Err("unrecognized keyword following pub".into()), } - Some(_) => return Err("unrecognized thing following pub".into()), - None => return Err("end of input".into()), + _ => return Err("unrecognized thing following pub".into()), } }, Let => parse_let(input, state), @@ -86,8 +105,8 @@ fn parse_expr(input: &mut Input, state: State) -> Result<Expr> { /// Annotation ::= (':' TypeDesc)? fn parse_annotation(input: &mut Input, state: State) -> Result<Option<Type>> { let mut kind = None; - if let Some(Sep(Colon)) = input.peek() { - input.next(); + if input.peek()? == &Sep(Colon) { + input.next()?; kind = Some(parse_type(input, state)?); } Ok(kind) @@ -96,9 +115,7 @@ fn parse_annotation(input: &mut Input, state: State) -> Result<Option<Type>> { fn parse_let(input: &mut Input, state: State) -> Result<Expr> { let id = parse_pattern(input, state)?; let kind = parse_annotation(input, state)?; - if input.next() != Some(Sep(Equals)) { - return Err("= not following binding".into()) - } + input.then(Sep(Equals))?; let value = Box::new(parse_expr(input, state)?); Ok(Expr::Binding(Let { id, kind, value })) } @@ -107,7 +124,7 @@ fn parse_var(input: &mut Input, state: State) -> Result<Expr> { let id = parse_pattern(input, state)?; let kind = parse_annotation(input, state)?; let mut value = None; - if input.next() != Some(Sep(Equals)) { + if input.next()? != Sep(Equals) { value = Some(Box::new(parse_expr(input, state)?)); } Ok(Expr::Binding(Var { id, kind, value })) @@ -116,9 +133,7 @@ fn parse_var(input: &mut Input, state: State) -> Result<Expr> { fn parse_const(input: &mut Input, state: State, public: bool) -> Result<Expr> { let id = parse_pattern(input, state)?; let kind = parse_annotation(input, state)?; - if input.next() != Some(Sep(Equals)) { - return Err("= not following binding".into()) - } + input.then(Sep(Equals))?; let value = Box::new(parse_expr(input, state)?); Ok(Expr::Binding(Const { public, id, kind, value })) } @@ -131,10 +146,10 @@ fn parse_typedecl(input: &mut Input, state: State, public: bool) -> Result<Expr> } /// Mod ::= 'pub'? 'mod' Ident ':' Body fn parse_mod(input: &mut Input, state: State, public: bool) -> Result<Expr> { - match input.next() { - Some(Word(id)) => { - match input.next() { - Some(Sep(Colon)) => { + match input.next()? { + Word(id) => { + match input.next()? { + Sep(Colon) => { let body = parse_body(input, state.indent())?; Ok(Expr::Binding(Module { id, body })) }, @@ -149,27 +164,25 @@ fn parse_mod(input: &mut Input, state: State, public: bool) -> Result<Expr> { fn parse_import(input: &mut Input, state: State, from_scope: bool) -> Result<Expr> { let mut from = None; if from_scope { - match input.next() { - Some(Word(id)) => from = Some(id), + match input.next()? { + Word(id) => from = Some(id), _ => return Err("identifier not following from keyword".into()) } - if input.next() != Some(Key(Keyword::Import)) { - return Err("expected import to follow from".into()) - } + input.then(Key(Keyword::Import))?; } todo!() } /// Block ::= 'block' Ident? ':' Body fn parse_block(input: &mut Input, state: State) -> Result<Expr> { // todo: body + offset - match input.next() { - Some(Sep(Colon)) => { + match input.next()? { + Sep(Colon) => { let id = None; let body = parse_body(input, state.indent())?; Ok(Expr::Control(Block { id, body })) }, - Some(Word(label)) => { - match input.next() { - Some(Sep(Colon)) => { + Word(label) => { + match input.next()? { + Sep(Colon) => { let id = Some(label); let body = parse_body(input, state.indent())?; Ok(Expr::Control(Block { id, body })) @@ -182,9 +195,7 @@ fn parse_block(input: &mut Input, state: State) -> Result<Expr> { // todo: body } /// Static ::= 'static' ':' Body fn parse_static(input: &mut Input, state: State) -> Result<Expr> { - if input.next() != Some(Sep(Colon)) { - return Err("colon must follow static invocation".into()); - } + input.then(Sep(Colon))?; let body = parse_body(input, state.indent())?; Ok(Expr::Control(Static { body })) } @@ -192,30 +203,22 @@ fn parse_static(input: &mut Input, state: State) -> Result<Expr> { /// For ::= 'for' Pattern 'in' Expr ':' Body fn parse_for(input: &mut Input, state: State) -> Result<Expr> { let binding = parse_pattern(input, state)?; - if input.next() != Some(Key(Keyword::In)) { - return Err("expected in keyword after for pattern".into()); - } + input.then(Key(Keyword::In))?; let range = Box::new(parse_expr(input, state)?); - if input.next() != Some(Sep(Colon)) { - return Err("expected colon after in expression".into()); - } + input.then(Sep(Colon))?; let body = parse_body(input, state.indent())?; Ok(Expr::Control(For { binding, range, body })) } /// While ::= 'while' Expr ':' Body fn parse_while(input: &mut Input, state: State) -> Result<Expr> { let cond = Box::new(parse_expr(input, state)?); - if input.next() != Some(Sep(Colon)) { - return Err("expected colon after while keyword".into()); - } + input.then(Sep(Colon))?; let body = parse_body(input, state.indent())?; Ok(Expr::Control(While { cond, body })) } /// Loop ::= 'loop' ':' Body fn parse_loop(input: &mut Input, state: State) -> Result<Expr> { - if input.next() != Some(Sep(Colon)) { - return Err("expected colon after loop keyword".into()); - } + input.then(Sep(Colon))?; let body = parse_body(input, state.indent())?; Ok(Expr::Control(Loop { body })) } @@ -224,13 +227,13 @@ fn parse_loop(input: &mut Input, state: State) -> Result<Expr> { fn parse_if(input: &mut Input, state: State) -> Result<Expr> { let mut branches = Vec::new(); branches.push(parse_cond_branch(input, state)?); - while input.peek() == Some(&Key(Keyword::Elif)) { - input.next(); + while input.peek()? == &Key(Keyword::Elif) { + input.next()?; branches.push(parse_cond_branch(input, state)?); } let mut else_body = None; - if input.peek() == Some(&Key(Keyword::Else)) { - input.next(); + if input.peek()? == &Key(Keyword::Else) { + input.next()?; else_body = Some(parse_body(input, state.indent())?); } Ok(Expr::Control(If { branches, else_body })) @@ -239,13 +242,13 @@ fn parse_if(input: &mut Input, state: State) -> Result<Expr> { fn parse_when(input: &mut Input, state: State) -> Result<Expr> { let mut branches = Vec::new(); branches.push(parse_cond_branch(input, state)?); - while input.peek() == Some(&Key(Keyword::Elif)) { - input.next(); + while input.peek()? == &Key(Keyword::Elif) { + input.next()?; branches.push(parse_cond_branch(input, state)?); } let mut else_body = None; - if input.peek() == Some(&Key(Keyword::Else)) { - input.next(); + if input.peek()? == &Key(Keyword::Else) { + input.next()?; else_body = Some(parse_body(input, state.indent())?); } let mut body = Vec::new(); @@ -255,21 +258,17 @@ fn parse_when(input: &mut Input, state: State) -> Result<Expr> { fn parse_cond_branch(input: &mut Input, state: State) -> Result<CondBranch> { todo!() } /// Try ::= 'try' ':' Body ('except' Ident (',' Ident)* ':' Body) ('finally' ':' Body)? fn parse_try(input: &mut Input, state: State) -> Result<Expr> { - if input.next() != Some(Sep(Colon)) { - return Err("expected colon after try keyword".into()); - } + input.then(Sep(Colon))?; let body = parse_body(input, state.indent())?; let catches = Vec::new(); - while input.peek() == Some(&Key(Keyword::Catch)) { - input.next(); + while input.peek()? == &Key(Keyword::Catch) { + input.next()?; todo!(); } let mut finally = None; - if input.peek() == Some(&Key(Keyword::Finally)) { - input.next(); - if input.next() != Some(Sep(Colon)) { - return Err("expected colon after try keyword".into()); - } + if input.peek()? == &Key(Keyword::Finally) { + input.next()?; + input.then(Sep(Colon))?; finally = Some(parse_body(input, state.indent())?); } Ok(Expr::Control(Try { body, catches, finally })) @@ -278,8 +277,8 @@ fn parse_try(input: &mut Input, state: State) -> Result<Expr> { fn parse_match(input: &mut Input, state: State) -> Result<Expr> { let item = parse_pattern(input, state)?; let mut branches = Vec::new(); - while input.peek() == Some(&Key(Keyword::Of)) { - input.next(); + while input.peek()? == &Key(Keyword::Of) { + input.next()?; todo!(); } Ok(Expr::Control(Match { item, branches })) @@ -293,10 +292,10 @@ fn parse_match(input: &mut Input, state: State) -> Result<Expr> { /// In particular: ref, ptr, mut, static, distinct must wrap their parameters in '[' ']' and all type declarations must be on one line. fn parse_type(input: &mut Input, state: State) -> Result<Type> { use Type::*; - match input.next() { - Some(Key(word)) => { - match input.peek() { // todo: check if the type is a special typeclass - Some(Sep(GenericLeftBracket)) => (), + match input.next()? { + Key(word) => { + match input.peek()? { // todo: check if the type is a special typeclass + Sep(GenericLeftBracket) => (), _ => todo!() // ref, ptr, mut, static, struct, tuple, enum, union, interface, concept } match word { @@ -313,9 +312,9 @@ fn parse_type(input: &mut Input, state: State) -> Result<Type> { _ => return Err("invalid keyword present in type!".into()) } }, - Some(Word(id)) => { + Word(id) => { let mut generics = Vec::new(); - if let Some(Sep(GenericLeftBracket)) = input.peek() { + if input.peek()? == &Sep(GenericLeftBracket) { generics = parse_generics(input, state)?; } Ok(Alias { id, generics }) @@ -339,13 +338,10 @@ fn parse_signature(input: &mut Input, state: State) -> Result<Sig> { todo!() } /// `WrappedType ::= Type | ('[' Type ']')` fn parse_wrapped_type(input: &mut Input, state: State) -> Result<Type> { - if let Some(Sep(GenericLeftBracket)) = input.next() { + if input.next()? == Sep(GenericLeftBracket) { let result = parse_type(input, state)?; - if let Some(Sep(GenericRightBracket)) = input.next() { - Ok(result) - } else { - Err("could not find closing generic bracket!".into()) - } + input.then(Sep(GenericRightBracket))?; + Ok(result) } else { parse_type(input, state) } |