aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/parse.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/parse.rs')
-rw-r--r--src/frontend/parse.rs441
1 files changed, 349 insertions, 92 deletions
diff --git a/src/frontend/parse.rs b/src/frontend/parse.rs
index dba94ec..eee3911 100644
--- a/src/frontend/parse.rs
+++ b/src/frontend/parse.rs
@@ -1,13 +1,14 @@
+use multipeek::multipeek;
+
use crate::frontend::lex::*;
use crate::frontend::ast::*;
use crate::frontend::ast::Binding::*;
use crate::frontend::ast::Control::*;
-use crate::frontend::ast::Pattern::*;
use Token::*;
use Literal::*;
use Punctuation::*;
-struct Input(std::iter::Peekable<std::vec::IntoIter<Token>>);
+struct Input(multipeek::MultiPeek<std::vec::IntoIter<Token>>);
impl Input {
/// Map input.next() to return Results for use with the propagation operator
@@ -20,6 +21,10 @@ impl Input {
self.0.peek().ok_or("end of input".into())
}
+ fn peek_nth(&mut self, n: usize) -> Result<&Token> {
+ self.0.peek_nth(n).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()? {
@@ -31,7 +36,7 @@ impl Input {
/// Convert a basic TokenStream into an AbstractSyntaxTree
pub fn astify(input: TokenStream, name: &str) -> Result<Expr> {
- let mut input = Input(input.into_iter().peekable());
+ let mut input = Input(multipeek(input));
let body = parse_body(&mut input)?;
Ok(Expr::Binding(Module{ id: name.to_string(), body }))
}
@@ -44,14 +49,14 @@ fn parse_body(input: &mut Input) -> Result<Vec<Expr>> {
res.push(parse_expr(input)?);
return Ok(res);
}
- input.then(Sep(ScopeLeftBrace))?;
+ input.next()?;
while input.peek()? != &Sep(ScopeRightBrace) {
res.push(parse_expr(input)?);
if input.peek()? == &Sep(Semicolon) {
input.next()?;
}
}
- input.then(Sep(ScopeRightBrace))?;
+ input.next()?;
Ok(res)
}
@@ -65,7 +70,8 @@ fn parse_expr(input: &mut Input) -> Result<Expr> {
match input.next()? {
Key(word) => match word {
Const => parse_const(input, true),
- Func => parse_funcdecl(input, true),
+ Func => parse_func(input, true),
+ Macro => parse_macro(input, true),
Type => parse_typedecl(input, true),
Mod => parse_mod(input, true),
_ => return Err("unrecognized keyword following pub".into()),
@@ -76,11 +82,11 @@ fn parse_expr(input: &mut Input) -> Result<Expr> {
Let => parse_let(input),
Var => parse_var(input),
Const => parse_const(input, false),
- Func => parse_funcdecl(input, false),
+ Func => parse_func(input, false),
+ Macro => parse_macro(input, false),
Type => parse_typedecl(input, false),
Mod => parse_mod(input, false),
- From => parse_import(input, true), // todo: probably rework imports
- Import => parse_import(input, false),
+ Use => parse_use(input),
Block => parse_block(input),
Static => parse_static(input),
For => parse_for(input),
@@ -90,13 +96,13 @@ fn parse_expr(input: &mut Input) -> Result<Expr> {
When => parse_when(input),
Try => parse_try(input),
Match => parse_match(input),
- _ => return Err("invalid keyword starting expression".into()),
+ word => return Err(format!("attempting to parse {} out of context", word).into()),
},
_ => todo!(), // what can i do with this?? match line here
}
}
-/// Let ::= 'let' Pattern Annotation? '=' Expr
+/// `Let ::= 'let' Pattern Annotation? '=' Expr`
fn parse_let(input: &mut Input) -> Result<Expr> {
let id = parse_pattern(input)?;
let kind = parse_annotation(input)?;
@@ -105,7 +111,7 @@ fn parse_let(input: &mut Input) -> Result<Expr> {
Ok(Expr::Binding(Let { id, kind, value }))
}
-/// Var ::= 'var' Pattern Annotation? ('=' Expr)?
+/// `Var ::= 'var' Pattern Annotation? ('=' Expr)?`
fn parse_var(input: &mut Input) -> Result<Expr> {
let id = parse_pattern(input)?;
let kind = parse_annotation(input)?;
@@ -116,7 +122,7 @@ fn parse_var(input: &mut Input) -> Result<Expr> {
Ok(Expr::Binding(Var { id, kind, value }))
}
-/// Const ::= 'pub'? 'const' Pattern Annotation? '=' Expr
+/// `Const ::= 'pub'? 'const' Pattern Annotation? '=' Expr`
fn parse_const(input: &mut Input, public: bool) -> Result<Expr> {
let id = parse_pattern(input)?;
let kind = parse_annotation(input)?;
@@ -135,16 +141,119 @@ fn parse_annotation(input: &mut Input) -> Result<Option<Type>> {
Ok(kind)
}
-/// Func ::= 'pub'? 'func' Ident Generics? Parameters? (':' TypeDesc) '=' Body
-fn parse_funcdecl(input: &mut Input, public: bool) -> Result<Expr> { todo!() }
+/// `Func ::= 'pub'? 'func' Ident ('[' Parameters ']')? ('(' Parameters ')')? (':' TypeDesc) '=' Body`
+fn parse_func(input: &mut Input, public: bool) -> Result<Expr> {
+ let effect = None;
+ let id = parse_ident(input)?;
+ let mut generics = Vec::new();
+ if input.peek()? == &Sep(GenericLeftBracket) {
+ input.next()?;
+ generics = parse_parameters(input)?;
+ input.then(Sep(GenericRightBracket))?;
+ }
+ let mut parameters = Vec::new();
+ if input.peek()? == &Sep(FuncLeftParen) {
+ input.next()?; // todo: rewrite to map over an input
+ // let temp_parameters = parse_parameters(input)?;
+ // if temp_parameters.last().is_none() {
+ // return Err("expected a type annotation on the last function parameter".into());
+ // }
+ // parameters = parse_parameters(input)?.iter().map(|x| x).collect();
+ let mut stack = Vec::new();
+ let (id, kind) = parse_parameter(input)?;
+ if kind.is_some() {
+ parameters.push((id, kind.unwrap()));
+ } else {
+ stack.push(id);
+ }
+ while input.peek()? == &Sep(Comma) {
+ input.next()?;
+ let (id, kind) = parse_parameter(input)?;
+ stack.push(id);
+ if kind.is_some() {
+ for id in &stack {
+ parameters.push((id.clone(), kind.clone().unwrap()));
+ }
+ stack.clear();
+ }
+ }
+ if stack.len() != 0 {
+ return Err("expected a type annotation on the last function parameter".into());
+ }
+ input.then(Sep(FuncRightParen))?;
+ }
+ let mut kind = Type::Void;
+ if input.peek()? == &Sep(Colon) {
+ input.next()?;
+ kind = parse_type(input)?;
+ }
+ input.then(Sep(Equals))?;
+ let body = parse_body(input)?;
+ Ok(Expr::Binding(Func { public, effect, id, generics, parameters, kind, body }))
+}
-/// TypeDecl ::= 'pub'? 'type' Pattern Generics? '=' 'distinct'? 'ref'? TypeDesc
+/// `Macro ::= 'pub'? 'macro' Ident ('[' Paremeters ']')? ('(' Paremeters ')')? (':' TypeDesc) '=' Body`
+fn parse_macro(input: &mut Input, public: bool) -> Result<Expr> {
+ let id = parse_ident(input)?;
+ let mut generics = Vec::new();
+ if input.peek()? == &Sep(GenericLeftBracket) {
+ input.next()?;
+ generics = parse_parameters(input)?;
+ input.then(Sep(GenericRightBracket))?;
+ }
+ let mut parameters = Vec::new();
+ if input.peek()? == &Sep(FuncLeftParen) {
+ input.next()?;
+ parameters = parse_parameters(input)?;
+ input.then(Sep(FuncRightParen))?;
+ }
+ let mut kind = None;
+ if input.peek()? == &Sep(Colon) {
+ input.next()?;
+ kind = Some(parse_type(input)?);
+ }
+ input.then(Sep(Equals))?;
+ let body = parse_body(input)?;
+ Ok(Expr::Binding(Macro { public, id, generics, parameters, kind, body }))
+}
+
+/// `TypeDecl ::= 'pub'? 'type' Ident ('[' Parameters ']')? '=' Type
fn parse_typedecl(input: &mut Input, public: bool) -> Result<Expr> {
- let pattern = parse_pattern(input)?;
- todo!()
+ let id = parse_ident(input)?;
+ let mut generics = Vec::new();
+ if input.peek()? == &Sep(GenericLeftBracket) {
+ input.next()?;
+ generics = parse_parameters(input)?;
+ input.then(Sep(GenericRightBracket))?;
+ }
+ input.then(Sep(Equals))?;
+ let alias = parse_type(input)?;
+ Ok(Expr::Binding(TypeDecl { id, generics, alias }))
+}
+
+/// `Parameter ::= Ident (':' Type)?`
+fn parse_parameter(input: &mut Input) -> Result<(Id, Option<Type>)> {
+ let id = parse_ident(input)?;
+ let mut kind = None;
+ if input.peek()? == &Sep(Colon) {
+ input.next()?;
+ kind = Some(parse_type(input)?);
+ }
+ Ok((id, kind))
+}
+
+/// `Parameters ::= Parameter (',' Parameter)*
+fn parse_parameters(input: &mut Input) -> Result<Vec<(Id, Option<Type>)>> {
+ let mut res = Vec::new();
+ res.push(parse_parameter(input)?);
+ while input.peek()? == &Sep(Comma) {
+ input.next()?;
+ res.push(parse_parameter(input)?);
+ }
+ Ok(res)
}
-/// Mod ::= 'pub'? 'mod' Ident ':' Body
+/// `Mod ::= 'pub'? 'mod' Ident ':' Body`
fn parse_mod(input: &mut Input, public: bool) -> Result<Expr> {
match input.next()? {
Word(id) => {
@@ -160,21 +269,11 @@ fn parse_mod(input: &mut Input, public: bool) -> Result<Expr> {
}
}
-/// Import ::= ('from' Ident)? 'import' Ident (',' Ident)* ('as' Ident)?
-fn parse_import(input: &mut Input, from_scope: bool) -> Result<Expr> {
- let mut from = None;
- if from_scope {
- match input.next()? {
- Word(id) => from = Some(id),
- _ => return Err("identifier not following from keyword".into())
- }
- input.then(Key(Keyword::Import))?;
- }
- todo!()
-}
+/// `Use ::= 'use' Ident ('/' Ident)* ('/' (('[' Ident (',' Ident)* ']') | '*'))?`
+fn parse_use(input: &mut Input) -> Result<Expr> { todo!() }
-/// Block ::= 'block' Ident? ':' Body
-fn parse_block(input: &mut Input) -> Result<Expr> { // todo: body + offset
+/// `Block ::= 'block' Ident? ':' Body`
+fn parse_block(input: &mut Input) -> Result<Expr> {
match input.next()? {
Sep(Colon) => {
let id = None;
@@ -182,27 +281,23 @@ fn parse_block(input: &mut Input) -> Result<Expr> { // todo: body + offset
Ok(Expr::Control(Block { id, body }))
},
Word(label) => {
- match input.next()? {
- Sep(Colon) => {
- let id = Some(label);
- let body = parse_body(input)?;
- Ok(Expr::Control(Block { id, body }))
- },
- _ => return Err("unexpected token following block label".into()),
- }
+ input.then(Sep(Colon))?;
+ let id = Some(label);
+ let body = parse_body(input)?;
+ Ok(Expr::Control(Block { id, body }))
},
_ => return Err("unexpected thing following block keyword".into()),
}
}
-/// Static ::= 'static' ':' Body
+/// `Static ::= 'static' ':' Body`
fn parse_static(input: &mut Input) -> Result<Expr> {
input.then(Sep(Colon))?;
let body = parse_body(input)?;
Ok(Expr::Control(Static { body }))
}
-/// For ::= 'for' Pattern 'in' Expr ':' Body
+/// `For ::= 'for' Pattern 'in' Expr ':' Body`
fn parse_for(input: &mut Input) -> Result<Expr> {
let binding = parse_pattern(input)?;
input.then(Key(Keyword::In))?;
@@ -212,7 +307,7 @@ fn parse_for(input: &mut Input) -> Result<Expr> {
Ok(Expr::Control(For { binding, range, body }))
}
-/// While ::= 'while' Expr ':' Body
+/// `While ::= 'while' Expr ':' Body`
fn parse_while(input: &mut Input) -> Result<Expr> {
let cond = Box::new(parse_expr(input)?);
input.then(Sep(Colon))?;
@@ -220,14 +315,14 @@ fn parse_while(input: &mut Input) -> Result<Expr> {
Ok(Expr::Control(While { cond, body }))
}
-/// Loop ::= 'loop' ':' Body
+/// `Loop ::= 'loop' ':' Body`
fn parse_loop(input: &mut Input) -> Result<Expr> {
input.then(Sep(Colon))?;
let body = parse_body(input)?;
Ok(Expr::Control(Loop { body }))
}
-/// If ::= 'if' CondBranch ('elif' CondBranch)* ('else' ':' Body)?
+/// `If ::= 'if' CondBranch ('elif' CondBranch)* ('else' ':' Body)?`
fn parse_if(input: &mut Input) -> Result<Expr> {
let mut branches = Vec::new();
branches.push(parse_cond_branch(input)?);
@@ -243,7 +338,7 @@ fn parse_if(input: &mut Input) -> Result<Expr> {
Ok(Expr::Control(If { branches, else_body }))
}
-// When ::= 'when' CondBranch ('elif' CondBranch)* ('else' ':' Body)?
+/// `When ::= 'when' CondBranch ('elif' CondBranch)* ('else' ':' Body)?`
fn parse_when(input: &mut Input) -> Result<Expr> {
let mut branches = Vec::new();
branches.push(parse_cond_branch(input)?);
@@ -262,7 +357,7 @@ fn parse_when(input: &mut Input) -> Result<Expr> {
Ok(Expr::Control(Static { body }))
}
-/// CondBranch ::= Expr ':' Body
+/// `CondBranch ::= Expr ':' Body`
fn parse_cond_branch(input: &mut Input) -> Result<CondBranch> {
let cond = parse_expr(input)?;
input.then(Sep(Colon))?;
@@ -270,14 +365,22 @@ fn parse_cond_branch(input: &mut Input) -> Result<CondBranch> {
Ok(CondBranch { cond, body })
}
-/// Try ::= 'try' ':' Body ('except' Ident (',' Ident)* ':' Body) ('finally' ':' Body)?
+/// `Try ::= 'try' ':' Body ('except' Exception (',' Exception)* ':' Body) ('finally' ':' Body)?`
fn parse_try(input: &mut Input) -> Result<Expr> {
input.then(Sep(Colon))?;
let body = parse_body(input)?;
let mut catches = Vec::new();
while input.peek()? == &Key(Keyword::Catch) {
input.next()?;
- todo!();
+ let mut exceptions = Vec::new();
+ exceptions.push(parse_catch_exception(input)?);
+ while input.peek()? == &Sep(Comma) {
+ input.next()?;
+ exceptions.push(parse_catch_exception(input)?);
+ }
+ input.then(Sep(Colon))?;
+ let body = parse_body(input)?;
+ catches.push(CatchBranch { exceptions, body });
}
let mut finally = None;
if input.peek()? == &Key(Keyword::Finally) {
@@ -288,49 +391,72 @@ fn parse_try(input: &mut Input) -> Result<Expr> {
Ok(Expr::Control(Try { body, catches, finally }))
}
-/// Match ::= 'match' Expr ('of' Pattern (',' Pattern)* ('where' Expr)? ':' Body)+
+/// `Exception ::= Ident ('as' Ident)?`
+fn parse_catch_exception(input: &mut Input) -> Result<(Id, Option<Id>)> {
+ let id = parse_ident(input)?;
+ let mut alias = None;
+ if input.peek()? == &Key(Keyword::As) {
+ input.next()?;
+ alias = Some(parse_ident(input)?);
+ }
+ Ok((id, alias))
+}
+
+/// `Match ::= 'match' Expr ('of' Pattern (',' Pattern)* ('where' Expr)? ':' Body)+`
fn parse_match(input: &mut Input) -> Result<Expr> {
let item = parse_pattern(input)?; // fixme
let mut branches = Vec::new();
while input.peek()? == &Key(Keyword::Of) {
input.next()?;
- todo!();
+ let mut patterns = Vec::new();
+ patterns.push(parse_pattern(input)?);
+ while input.peek()? == &Sep(Comma) {
+ input.next()?;
+ patterns.push(parse_pattern(input)?);
+ }
+ let mut guard = None;
+ if input.peek()? == &Key(Keyword::Where) {
+ input.next()?;
+ guard = Some(parse_expr(input)?)
+ }
+ input.then(Sep(Colon))?;
+ let body = parse_body(input)?;
+ branches.push(MatchBranch { patterns, guard, body })
}
Ok(Expr::Control(Match { item, branches }))
}
-/// Type ::=
-/// ('ref' | 'ptr' | 'mut' | 'static' | 'struct' | 'tuple' | 'enum' | 'union' | 'interface' | 'concept') |
-/// ('ref' WrappedType) | ('ptr' WrappedType) | ('mut' WrappedType) | ('static' WrappedType) | ('distinct' WrappedType) |
-/// StructType | TupleType | EnumType | UnionType | InterfaceType
-/// The input stream must be normalized before attempting to parse types, because otherwise it's just a little bit hellish.
-/// In particular: ref, ptr, mut, static, distinct must wrap their parameters in '[' ']' and all type declarations must be on one line.
+/// `Type ::= (('distinct' | 'ref' | 'ptr' | 'mut' | 'static') BracketType?) |
+/// StructType | TupleType | EnumType | UnionType | InterfaceType`
+///
+/// The input stream must be normalized (i.e. all type declarations must be on one line)
+/// before attempting to parse types, because otherwise it's just a little bit hellish.
fn parse_type(input: &mut Input) -> Result<Type> {
use Type::*;
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 {
- Keyword::Distinct => Ok(Distinct(Box::new(parse_wrapped_type(input)?))),
- Keyword::Ref => Ok(Reference(Box::new(parse_wrapped_type(input)?))),
- Keyword::Ptr => Ok(Pointer(Box::new(parse_wrapped_type(input)?))),
- Keyword::Var => Ok(Mutable(Box::new(parse_wrapped_type(input)?))),
- Keyword::Const => Ok(Static(Box::new(parse_wrapped_type(input)?))),
- Keyword::Struct => parse_struct_type(input),
- Keyword::Tuple => parse_tuple_type(input),
- Keyword::Enum => parse_enum_type(input),
- Keyword::Union => parse_union_type(input),
- Keyword::Interface => parse_interface(input),
- _ => return Err("invalid keyword present in type!".into())
- }
+ Key(word) => match word {
+ Keyword::Distinct => Ok(Distinct(Box::new(parse_wrapped_type(input)?))),
+ Keyword::Ref => Ok(Reference(Box::new(parse_wrapped_type(input)?))),
+ Keyword::Ptr => Ok(Pointer(Box::new(parse_wrapped_type(input)?))),
+ Keyword::Mut => Ok(Mutable(Box::new(parse_wrapped_type(input)?))),
+ Keyword::Static => Ok(Static(Box::new(parse_wrapped_type(input)?))),
+ Keyword::Struct => parse_struct_type(input),
+ Keyword::Tuple => parse_tuple_type(input),
+ Keyword::Enum => parse_enum_type(input),
+ Keyword::Union => parse_union_type(input),
+ Keyword::Interface => parse_interface(input),
+ _ => return Err("invalid keyword present in type!".into())
},
Word(id) => {
let mut generics = Vec::new();
if input.peek()? == &Sep(GenericLeftBracket) {
- generics = parse_generics(input)?;
+ input.next()?;
+ generics.push(parse_type(input)?);
+ while input.peek()? == &Sep(Comma) {
+ input.next()?;
+ generics.push(parse_type(input)?);
+ }
+ input.then(Sep(GenericRightBracket))?;
}
Ok(Alias { id, generics })
},
@@ -338,18 +464,145 @@ fn parse_type(input: &mut Input) -> Result<Type> {
}
}
-/// `StructType ::= ('struct' '[' Ident ':' Type (',' Ident ':' Type)* ']'`
-fn parse_struct_type(input: &mut Input) -> Result<Type> { todo!() }
-/// `TupleType ::= 'tuple' '[' (Ident ':')? Type (',' (Ident ':')? Type)* ']'`
-fn parse_tuple_type(input: &mut Input) -> Result<Type> { todo!() }
-/// `EnumType ::= 'enum' '[' Ident ('=' Pattern)? (Ident ('=' Pattern)?)* ']'`
-fn parse_enum_type(input: &mut Input) -> Result<Type> { todo!() }
-/// `UnionType ::= 'union' '[' Ident (':' Type)? (',' Ident (':' Type)?)* ']'`
-fn parse_union_type(input: &mut Input) -> Result<Type> { todo!() }
-/// `Interface ::= 'interface' '[' Signature (',' Signature)* ']'`
-fn parse_interface(input: &mut Input) -> Result<Type> { todo!() }
-/// `Signature ::= Ident ('[' Ident (':' Type)? (',' Ident (':' Type)?)* ']')? ('(' Type (',' Type)* ')')? (':' Type)?`
-fn parse_signature(input: &mut Input) -> Result<Sig> { todo!() }
+/// `StructType ::= 'struct' ('[' Ident ':' Type (',' Ident ':' Type)* ']')?`
+fn parse_struct_type(input: &mut Input) -> Result<Type> {
+ let mut res = Vec::new();
+ if input.peek()? == &Sep(GenericLeftBracket) {
+ input.next()?;
+ res.push(parse_struct_field(input)?);
+ while input.peek()? == &Sep(Comma) {
+ input.next()?;
+ res.push(parse_struct_field(input)?);
+ }
+ input.then(Sep(GenericRightBracket))?;
+ }
+ Ok(Type::Struct(res))
+}
+
+fn parse_struct_field(input: &mut Input) -> Result<(Id, Box<Type>)> {
+ let id = parse_ident(input)?;
+ input.then(Sep(Colon))?;
+ let kind = Box::new(parse_type(input)?);
+ Ok((id, kind))
+}
+
+/// `TupleType ::= 'tuple' ('[' (Ident ':')? Type (',' (Ident ':')? Type)* ']')?`
+fn parse_tuple_type(input: &mut Input) -> Result<Type> {
+ let mut res = Vec::new();
+ if input.peek()? == &Sep(GenericLeftBracket) {
+ input.next()?;
+ res.push(parse_tuple_field(input)?);
+ while input.peek()? == &Sep(Comma) {
+ input.next()?;
+ res.push(parse_tuple_field(input)?);
+ }
+ input.then(Sep(GenericRightBracket))?;
+ }
+ Ok(Type::Tuple(res))
+}
+
+fn parse_tuple_field(input: &mut Input) -> Result<(Option<Id>, Box<Type>)> {
+ match input.peek()?.clone() { // huh???
+ Word(id) if input.peek_nth(1)? == &Sep(Colon) => {
+ input.next()?;
+ Ok((Some(id.to_string()), Box::new(parse_type(input)?)))
+ },
+ _ => Ok((None, Box::new(parse_type(input)?)))
+ }
+}
+
+/// `EnumType ::= 'enum' ('[' Ident ('=' Pattern)? (Ident ('=' Pattern)?)* ']')?`
+fn parse_enum_type(input: &mut Input) -> Result<Type> {
+ let mut res = Vec::new();
+ if input.peek()? == &Sep(GenericLeftBracket) {
+ input.next()?;
+ res.push(parse_enum_variant(input)?);
+ while input.peek()? == &Sep(Comma) {
+ input.next()?;
+ res.push(parse_enum_variant(input)?);
+ }
+ input.then(Sep(GenericRightBracket))?;
+ }
+ todo!()
+}
+
+fn parse_enum_variant(input: &mut Input) -> Result<(Id, Option<Pattern>)> {
+ let id = parse_ident(input)?;
+ let mut kind = None;
+ if input.peek()? == &Sep(Equals) {
+ input.next()?;
+ kind = Some(parse_pattern(input)?);
+ }
+ Ok((id, kind))
+}
+
+/// `UnionType ::= 'union' ('[' Ident (':' Type)? (',' Ident (':' Type)?)* ']')?`
+fn parse_union_type(input: &mut Input) -> Result<Type> {
+ let mut res = Vec::new();
+ if input.peek()? == &Sep(GenericLeftBracket) {
+ input.next()?;
+ res.push(parse_union_variant(input)?);
+ while input.peek()? == &Sep(Comma) {
+ input.next()?;
+ res.push(parse_union_variant(input)?);
+ }
+ input.then(Sep(GenericRightBracket))?;
+ }
+ Ok(Type::Union(res))
+}
+
+fn parse_union_variant(input: &mut Input) -> Result<(Id, Box<Type>)> {
+ let id = parse_ident(input)?;
+ let mut kind = Box::new(Type::Alias { id: "unit".to_string(), generics: Vec::new() });
+ if input.peek()? == &Sep(Colon) {
+ input.next()?;
+ kind = Box::new(parse_type(input)?);
+ }
+ Ok((id, kind))
+}
+
+/// `Interface ::= 'interface' ('[' Signature (',' Signature)* ']')?`
+fn parse_interface(input: &mut Input) -> Result<Type> {
+ let mut res = Vec::new();
+ if input.peek()? == &Sep(GenericLeftBracket) {
+ input.next()?;
+ res.push(parse_signature(input)?);
+ while input.peek()? == &Sep(Comma) {
+ input.next()?;
+ res.push(parse_signature(input)?);
+ }
+ input.then(Sep(GenericRightBracket))?;
+ }
+ Ok(Type::Interface(res))
+}
+
+/// `Signature ::= Ident ('[' Parameters ']')? ('(' Type (',' Type)* ')')? (':' Type)?`
+fn parse_signature(input: &mut Input) -> Result<Sig> {
+ let effect = None;
+ let id = parse_ident(input)?;
+ let mut generics = Vec::new();
+ if input.peek()? == &Sep(GenericLeftBracket) {
+ input.next()?;
+ generics = parse_parameters(input)?;
+ input.then(Sep(GenericRightBracket))?;
+ }
+ let mut parameters = Vec::new();
+ if input.peek()? == &Sep(FuncLeftParen) {
+ input.next()?;
+ parameters.push(parse_type(input)?);
+ if input.peek()? == &Sep(Comma) {
+ input.next()?;
+ parameters.push(parse_type(input)?);
+ }
+ input.then(Sep(FuncRightParen))?;
+ }
+ let mut kind = None;
+ if input.peek()? == &Sep(Colon) {
+ input.next()?;
+ kind = Some(parse_type(input)?);
+ }
+ Ok(Sig { effect, id, generics, parameters, kind })
+}
/// `WrappedType ::= Type | ('[' Type ']')`
fn parse_wrapped_type(input: &mut Input) -> Result<Type> {
@@ -362,11 +615,15 @@ fn parse_wrapped_type(input: &mut Input) -> Result<Type> {
}
}
-/// `GenericType ::= '[' Type (',' Type)* ']'`
-fn parse_generics(input: &mut Input) -> Result<Vec<Type>> { todo!() }
-
/// Pattern ::= Literal | Ident | '(' Pattern (',' Pattern)* ')' | Ident '(' Pattern (',' Pattern)* ')'
fn parse_pattern(input: &mut Input) -> Result<Pattern> { todo!() }
/// Literal ::= Char | String | Number | Float
fn parse_literal(input: &mut Input) -> Result<Pattern> { todo!() }
+
+fn parse_ident(input: &mut Input) -> Result<Id> {
+ match input.next()? {
+ Word(id) => Ok(id),
+ token => Err(format!("expected identifier but found token {}", token).into())
+ }
+}