From 3851012eeb1420bef0db7cd3e9a76affdb6145b9 Mon Sep 17 00:00:00 2001 From: JJ Date: Wed, 8 Nov 2023 13:18:08 -0800 Subject: compiler: progress. parse most of the hard things. --- src/frontend/ast.rs | 35 ++-- src/frontend/lex.rs | 20 +-- src/frontend/parse.rs | 441 +++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 380 insertions(+), 116 deletions(-) (limited to 'src/frontend') diff --git a/src/frontend/ast.rs b/src/frontend/ast.rs index ed7a01a..ed44712 100644 --- a/src/frontend/ast.rs +++ b/src/frontend/ast.rs @@ -2,6 +2,7 @@ pub type Id = String; /// Puck's fundamental types. +#[derive(Clone, PartialEq)] pub enum Type { Void, Never, Integer, Float, String, // char et al are defined later @@ -12,10 +13,7 @@ pub enum Type { Struct(Vec<(Id, Box)>), Tuple(Vec<(Option, Box)>), Union(Vec<(Id, Box)>), - Interface { - funcs: Vec, - for_type: Option>, - }, + Interface(Vec), Array{size: usize, kind: Box}, List(Box), Slice(Box), // todo: plus ownership @@ -31,12 +29,13 @@ pub enum Type { } /// Function signatures. +#[derive(Clone, PartialEq)] pub struct Sig { - effect: Option, - id: Id, - generics: Vec<(Id, Option)>, - params: Vec, - result: Option + pub effect: Option, + pub id: Id, + pub generics: Vec<(Id, Option)>, + pub parameters: Vec, + pub kind: Option } /// Patterns are recognizable given zero context. @@ -69,16 +68,24 @@ pub enum Binding { kind: Option, value: Box }, - FuncDecl { + Func { public: bool, effect: Option, id: Id, generics: Vec<(Id, Option)>, // id, kind - params: Vec<(Id, Type)>, // id, kind + parameters: Vec<(Id, Type)>, // id, kind kind: Type, body: Vec }, - TypeDecl { id: Id, generics: Vec, alias: Type }, + Macro { + public: bool, + id: Id, + generics: Vec<(Id, Option)>, // id, kind + parameters: Vec<(Id, Option)>, // id, kind + kind: Option, + body: Vec + }, + TypeDecl { id: Id, generics: Vec<(Id, Option)>, alias: Type }, Import { from: Option, imports: Vec, alias: Option }, Module { id: Id, body: Vec }, } @@ -107,8 +114,8 @@ pub enum Control { } pub struct CondBranch { pub cond: Expr, pub body: Vec } -pub struct CatchBranch { pub exceptions: Vec, pub binding: Option, pub body: Vec } -pub struct MatchBranch { pub pattern: Pattern, pub guard: Option, pub body: Vec } +pub struct CatchBranch { pub exceptions: Vec<(Id, Option)>, pub body: Vec } +pub struct MatchBranch { pub patterns: Vec, pub guard: Option, pub body: Vec } /// Expressions are either Patterns, Bindings, or Control flow constructs. pub enum Expr { diff --git a/src/frontend/lex.rs b/src/frontend/lex.rs index a51b21d..67c4ae3 100644 --- a/src/frontend/lex.rs +++ b/src/frontend/lex.rs @@ -54,15 +54,15 @@ pub enum Literal { pub enum Keyword { Pub, Let, Var, Const, Func, Macro, Type, - Mod, From, Import, + Mod, Use, As, For, While, Loop, Block, Static, - If, When, Elif, Else, Match, + If, When, Elif, Else, Match, Where, Try, Catch, Finally, Struct, Tuple, Enum, Union, Interface, Distinct, Ref, Ptr, Mut, Break, Continue, Return, - In, Is, Of, As, + In, Is, Of, } /// All punctuation recognized by the lexer. @@ -272,9 +272,9 @@ pub fn tokenize(input: &str) -> Result { "func" => res.push(Key(Func)), "macro" => res.push(Key(Macro)), "type" => res.push(Key(Type)), - "mod" => res.push(Key(Mod)), - "from" => res.push(Key(From)), - "import" => res.push(Key(Import)), + "mod" => res.push(Key(Mod)), + "use" => res.push(Key(Use)), + "as" => res.push(Key(As)), "for" => res.push(Key(For)), "while" => res.push(Key(While)), "loop" => res.push(Key(Loop)), @@ -285,6 +285,7 @@ pub fn tokenize(input: &str) -> Result { "elif" => res.push(Key(Elif)), "else" => res.push(Key(Else)), "match" => res.push(Key(Match)), + "where" => res.push(Key(Where)), "try" => res.push(Key(Try)), "catch" => res.push(Key(Catch)), "finally" => res.push(Key(Finally)), @@ -303,7 +304,6 @@ pub fn tokenize(input: &str) -> Result { "in" => res.push(Key(In)), "is" => res.push(Key(Is)), "of" => res.push(Key(Of)), - "as" => res.push(Key(As)), _ => res.push(Word(String::from(&buf))) } match x { // () and [] denote both parameters/generics and tuples/arrays @@ -470,8 +470,8 @@ impl std::fmt::Display for Keyword { Macro => write!(f, "macro"), Type => write!(f, "type"), Mod => write!(f, "mod"), - From => write!(f, "from"), - Import => write!(f, "import"), + Use => write!(f, "use"), + As => write!(f, "as"), For => write!(f, "for"), While => write!(f, "while"), Loop => write!(f, "loop"), @@ -482,6 +482,7 @@ impl std::fmt::Display for Keyword { Elif => write!(f, "elif"), Else => write!(f, "else"), Match => write!(f, "match"), + Where => write!(f, "where"), Try => write!(f, "try"), Catch => write!(f, "catch"), Finally => write!(f, "finally"), @@ -500,7 +501,6 @@ impl std::fmt::Display for Keyword { In => write!(f, "in"), Is => write!(f, "is"), Of => write!(f, "of"), - As => write!(f, "as"), } } } 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>); +struct Input(multipeek::MultiPeek>); 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 { - 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> { 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 { 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 { 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 { 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 { let id = parse_pattern(input)?; let kind = parse_annotation(input)?; @@ -105,7 +111,7 @@ fn parse_let(input: &mut Input) -> Result { Ok(Expr::Binding(Let { id, kind, value })) } -/// Var ::= 'var' Pattern Annotation? ('=' Expr)? +/// `Var ::= 'var' Pattern Annotation? ('=' Expr)?` fn parse_var(input: &mut Input) -> Result { let id = parse_pattern(input)?; let kind = parse_annotation(input)?; @@ -116,7 +122,7 @@ fn parse_var(input: &mut Input) -> Result { 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 { let id = parse_pattern(input)?; let kind = parse_annotation(input)?; @@ -135,16 +141,119 @@ fn parse_annotation(input: &mut Input) -> Result> { Ok(kind) } -/// Func ::= 'pub'? 'func' Ident Generics? Parameters? (':' TypeDesc) '=' Body -fn parse_funcdecl(input: &mut Input, public: bool) -> Result { todo!() } +/// `Func ::= 'pub'? 'func' Ident ('[' Parameters ']')? ('(' Parameters ')')? (':' TypeDesc) '=' Body` +fn parse_func(input: &mut Input, public: bool) -> Result { + 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 { + 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 { - 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)> { + 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)>> { + 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 { match input.next()? { Word(id) => { @@ -160,21 +269,11 @@ fn parse_mod(input: &mut Input, public: bool) -> Result { } } -/// Import ::= ('from' Ident)? 'import' Ident (',' Ident)* ('as' Ident)? -fn parse_import(input: &mut Input, from_scope: bool) -> Result { - 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 { todo!() } -/// Block ::= 'block' Ident? ':' Body -fn parse_block(input: &mut Input) -> Result { // todo: body + offset +/// `Block ::= 'block' Ident? ':' Body` +fn parse_block(input: &mut Input) -> Result { match input.next()? { Sep(Colon) => { let id = None; @@ -182,27 +281,23 @@ fn parse_block(input: &mut Input) -> Result { // 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 { 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 { let binding = parse_pattern(input)?; input.then(Key(Keyword::In))?; @@ -212,7 +307,7 @@ fn parse_for(input: &mut Input) -> Result { Ok(Expr::Control(For { binding, range, body })) } -/// While ::= 'while' Expr ':' Body +/// `While ::= 'while' Expr ':' Body` fn parse_while(input: &mut Input) -> Result { let cond = Box::new(parse_expr(input)?); input.then(Sep(Colon))?; @@ -220,14 +315,14 @@ fn parse_while(input: &mut Input) -> Result { Ok(Expr::Control(While { cond, body })) } -/// Loop ::= 'loop' ':' Body +/// `Loop ::= 'loop' ':' Body` fn parse_loop(input: &mut Input) -> Result { 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 { let mut branches = Vec::new(); branches.push(parse_cond_branch(input)?); @@ -243,7 +338,7 @@ fn parse_if(input: &mut Input) -> Result { 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 { let mut branches = Vec::new(); branches.push(parse_cond_branch(input)?); @@ -262,7 +357,7 @@ fn parse_when(input: &mut Input) -> Result { Ok(Expr::Control(Static { body })) } -/// CondBranch ::= Expr ':' Body +/// `CondBranch ::= Expr ':' Body` fn parse_cond_branch(input: &mut Input) -> Result { let cond = parse_expr(input)?; input.then(Sep(Colon))?; @@ -270,14 +365,22 @@ fn parse_cond_branch(input: &mut Input) -> Result { 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 { 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 { 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)> { + 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 { 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 { 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 { } } -/// `StructType ::= ('struct' '[' Ident ':' Type (',' Ident ':' Type)* ']'` -fn parse_struct_type(input: &mut Input) -> Result { todo!() } -/// `TupleType ::= 'tuple' '[' (Ident ':')? Type (',' (Ident ':')? Type)* ']'` -fn parse_tuple_type(input: &mut Input) -> Result { todo!() } -/// `EnumType ::= 'enum' '[' Ident ('=' Pattern)? (Ident ('=' Pattern)?)* ']'` -fn parse_enum_type(input: &mut Input) -> Result { todo!() } -/// `UnionType ::= 'union' '[' Ident (':' Type)? (',' Ident (':' Type)?)* ']'` -fn parse_union_type(input: &mut Input) -> Result { todo!() } -/// `Interface ::= 'interface' '[' Signature (',' Signature)* ']'` -fn parse_interface(input: &mut Input) -> Result { todo!() } -/// `Signature ::= Ident ('[' Ident (':' Type)? (',' Ident (':' Type)?)* ']')? ('(' Type (',' Type)* ')')? (':' Type)?` -fn parse_signature(input: &mut Input) -> Result { todo!() } +/// `StructType ::= 'struct' ('[' Ident ':' Type (',' Ident ':' Type)* ']')?` +fn parse_struct_type(input: &mut Input) -> Result { + 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)> { + 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 { + 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, Box)> { + 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 { + 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)> { + 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 { + 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)> { + 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 { + 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 { + 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 { @@ -362,11 +615,15 @@ fn parse_wrapped_type(input: &mut Input) -> Result { } } -/// `GenericType ::= '[' Type (',' Type)* ']'` -fn parse_generics(input: &mut Input) -> Result> { todo!() } - /// Pattern ::= Literal | Ident | '(' Pattern (',' Pattern)* ')' | Ident '(' Pattern (',' Pattern)* ')' fn parse_pattern(input: &mut Input) -> Result { todo!() } /// Literal ::= Char | String | Number | Float fn parse_literal(input: &mut Input) -> Result { todo!() } + +fn parse_ident(input: &mut Input) -> Result { + match input.next()? { + Word(id) => Ok(id), + token => Err(format!("expected identifier but found token {}", token).into()) + } +} -- cgit v1.2.3-70-g09d2