aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJJ2023-11-08 09:47:51 +0000
committerJJ2023-11-08 09:47:51 +0000
commitce3e54ff8cb45af6e4f0becab5325c0abd02f1fb (patch)
treec1de76260304c5a2f04f8eab17f5792f991acb98
parent201ce572671d335e54f0f62c3e380d169449fe53 (diff)
compiler: write some helpers, reduce parser verbosity
-rw-r--r--src/frontend/parse.rs156
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)
}