From 34e3d3a23132e0530939288a9d19dbf377662c7b Mon Sep 17 00:00:00 2001 From: Michael Sippel Date: Tue, 14 May 2024 09:56:19 +0200 Subject: [PATCH] parse struct-binding blocks --- src/lexer.rs | 2 +- src/parser.rs | 233 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 216 insertions(+), 19 deletions(-) diff --git a/src/lexer.rs b/src/lexer.rs index fe0677d..4295abc 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -219,7 +219,7 @@ where } LexerState::TypeTerm(s) => { - if *c == '=' || *c == '.' { + if *c == '=' || *c == '.' || *c == '↦' || *c == ';' { if let Some(token) = state.clone().into_token() { return Some((region, Ok(token))); } diff --git a/src/parser.rs b/src/parser.rs index 57ebf31..c9faba1 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -9,12 +9,13 @@ use { }, }; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub enum ParseError { LexError(LexError), UnexpectedClose, UnexpectedEnd, UnexpectedToken, + TypeParseError(laddertypes::parser::ParseError) } pub fn parse_expect( @@ -37,6 +38,8 @@ where } } +/* parse symbol name + */ pub fn parse_symbol(tokens: &mut Peekable>) -> Result where It: Iterator, @@ -49,10 +52,13 @@ where } } +/* parse an optional type annotation + * `: T` + */ pub fn parse_type_tag( typectx: &Arc>, tokens: &mut Peekable>, -) -> Option +) -> Result, ParseError> where It: Iterator, { @@ -61,17 +67,110 @@ where Ok(LTIRToken::AssignType(typeterm_str)) => { tokens.next(); match typectx.write().unwrap().parse(typeterm_str.as_str()) { - Ok(typeterm) => Some(Ok(typeterm)), - Err(parse_error) => Some(Err(TypeError::ParseError(parse_error))), + Ok(typeterm) => Ok(Some(typeterm)), + Err(parse_error) => Err(ParseError::TypeParseError(parse_error)), } } - _ => None, + _ => Ok(None), } } else { - None + Ok(None) } } +#[derive(Debug, PartialEq, Eq)] +pub enum VariableBinding { + Atomic { + symbol: String, + typtag: Option + }, + Struct { + members: Vec< VariableBinding >, + typtag: Option + } +} + +impl VariableBinding { + pub fn flatten(self) -> Vec<(String, Option)> { + match self { + VariableBinding::Atomic{ symbol, typtag } => + vec![ (symbol, typtag) ], + VariableBinding::Struct{ members, typtag } => + members + .into_iter() + .map(|a| a.flatten().into_iter()) + .flatten() + .collect() + } + } +} + +/* parse a symbol binding of the form + * `x` + * or `x : T` + */ +pub fn parse_binding_expr( + typectx: &Arc>, + tokens: &mut Peekable>, +) -> Result< VariableBinding, ParseError> +where It: Iterator +{ + if let Some((region, peektok)) = tokens.peek().clone() { + match peektok { + Ok(LTIRToken::BlockOpen) => { + Ok(VariableBinding::Struct { + members: parse_binding_block(typectx, tokens)?, + typtag: parse_type_tag(typectx, tokens)? + }) + } + Ok(LTIRToken::Symbol(_)) => { + Ok(VariableBinding::Atomic{ + symbol: parse_symbol(tokens)?, + typtag: parse_type_tag(typectx, tokens)? + }) + } + Err(err) => Err(ParseError::LexError(err.clone())), + _ => Err(ParseError::UnexpectedToken) + } + } else { + Err(ParseError::UnexpectedEnd) + } +} + +/* parse a block of symbol bidnings + * `{ x:T; y:U; ... }` + */ +pub fn parse_binding_block( + typectx: &Arc>, + tokens: &mut Peekable>, +) -> Result< Vec, ParseError> +where + It: Iterator, +{ + let _ = parse_expect(tokens, LTIRToken::BlockOpen)?; + + let mut bindings = Vec::new(); + while let Some((region, peektok)) = tokens.peek() { + match peektok { + Ok(LTIRToken::BlockClose) => { + tokens.next(); + return Ok(bindings); + } + Ok(LTIRToken::StatementSep) => { + tokens.next(); + } + Ok(_) => { + bindings.push(parse_binding_expr(typectx, tokens)?); + } + Err(err) => { + return Err(ParseError::LexError(err.clone())); + } + } + } + + Err(ParseError::UnexpectedEnd) +} + pub fn parse_statement( typectx: &Arc>, tokens: &mut Peekable>, @@ -98,13 +197,19 @@ where "let" => { tokens.next(); let name = parse_symbol(tokens)?; - let typ = parse_type_tag(typectx, tokens); + let typ = parse_type_tag(typectx, tokens)?; + /* todo + let mut variable_bindings = parse_binding_expr(typectx, tokens)?; + */ let _ = parse_expect(tokens, LTIRToken::AssignValue); let val_expr = parse_expr(typectx, tokens)?; let _ = parse_expect(tokens, LTIRToken::StatementSep)?; Ok(Statement::LetAssign { - typ, + typ: match typ { + Some(t) => Some(Ok(t)), + None => None + }, var_id: name, val_expr, }) @@ -116,7 +221,7 @@ where let _ = parse_expect(tokens, LTIRToken::ExprClose)?; Ok(Statement::WhileLoop { condition: cond, - body: parse_block(typectx, tokens)?, + body: parse_statement_block(typectx, tokens)?, }) } "return" => { @@ -144,7 +249,7 @@ where } } -pub fn parse_block( +pub fn parse_statement_block( typectx: &Arc>, tokens: &mut Peekable>, ) -> Result, ParseError> @@ -203,16 +308,12 @@ where if children.len() == 0 { tokens.next(); - let mut args = Vec::new(); - while let Some((region, Ok(LTIRToken::Symbol(_)))) = tokens.peek() { - args.push((parse_symbol(tokens)?, parse_type_tag(typectx, tokens))); - } - + let mut variable_bindings = parse_binding_expr(typectx, tokens)?; let _ = parse_expect(tokens, LTIRToken::LambdaBody); let body = parse_expr(typectx, tokens)?; return Ok(LTExpr::Abstraction { - args, + args: variable_bindings.flatten().into_iter().map(|(s,t)| (s,t.map(|t|Ok(t))) ).collect(), body: Box::new(body), }); } else { @@ -236,7 +337,7 @@ where break; } Ok(LTIRToken::BlockOpen) => { - children.push(LTExpr::block(parse_block(typectx, tokens)?)); + children.push(LTExpr::block(parse_statement_block(typectx, tokens)?)); } Ok(LTIRToken::BlockClose) => { break; @@ -250,7 +351,7 @@ where let _ = parse_expect(tokens, LTIRToken::ExprOpen)?; let cond = parse_expr(typectx, tokens)?; let _ = parse_expect(tokens, LTIRToken::ExprClose)?; - let if_expr = LTExpr::block(parse_block(typectx, tokens)?); + let if_expr = LTExpr::block(parse_statement_block(typectx, tokens)?); let mut else_expr = LTExpr::block(vec![]); if let Some((region, peektok)) = tokens.peek() { @@ -292,3 +393,99 @@ where Err(ParseError::UnexpectedEnd) } } + + + +mod tests { + use std::sync::{Arc, RwLock}; + + #[test] + fn test_parse_atomic_binding() { + let mut lexer = crate::lexer::LTIRLexer::from("x".chars()).peekable(); + let typectx = Arc::new(RwLock::new(laddertypes::dict::TypeDict::new())); + let bindings = crate::parser::parse_binding_expr( &typectx, &mut lexer ); + + assert_eq!( + bindings, + Ok(crate::parser::VariableBinding::Atomic{ + symbol: "x".into(), + typtag: None + }) + ); + } + + #[test] + fn test_parse_typed_atomic_binding() { + let mut lexer = crate::lexer::LTIRLexer::from("x:T".chars()).peekable(); + let typectx = Arc::new(RwLock::new(laddertypes::dict::TypeDict::new())); + let bindings = crate::parser::parse_binding_expr( &typectx, &mut lexer ); + + assert_eq!( + bindings, + Ok(crate::parser::VariableBinding::Atomic{ + symbol: "x".into(), + typtag: Some(typectx.write().unwrap().parse("T").unwrap()) + }) + ); + } + + #[test] + fn test_parse_struct_binding() { + let mut lexer = crate::lexer::LTIRLexer::from("{x y}".chars()).peekable(); + let typectx = Arc::new(RwLock::new(laddertypes::dict::TypeDict::new())); + let bindings = crate::parser::parse_binding_expr( &typectx, &mut lexer ); + + assert_eq!( + bindings, + Ok(crate::parser::VariableBinding::Struct{ + members: vec![ + crate::parser::VariableBinding::Atomic{ symbol: "x".into(), typtag: None }, + crate::parser::VariableBinding::Atomic{ symbol: "y".into(), typtag: None } + ], + typtag: None + }) + ); + } + + #[test] + fn test_parse_typed_struct_binding1() { + let mut lexer = crate::lexer::LTIRLexer::from("{x y}:T".chars()).peekable(); + let typectx = Arc::new(RwLock::new(laddertypes::dict::TypeDict::new())); + let bindings = crate::parser::parse_binding_expr( &typectx, &mut lexer ); + + assert_eq!( + bindings, + Ok(crate::parser::VariableBinding::Struct{ + members: vec![ + crate::parser::VariableBinding::Atomic{ symbol: "x".into(), typtag: None }, + crate::parser::VariableBinding::Atomic{ symbol: "y".into(), typtag: None } + ], + typtag: Some(typectx.write().unwrap().parse("T").unwrap()) + }) + ); + } + + #[test] + fn test_parse_typed_struct_binding2() { + let mut lexer = crate::lexer::LTIRLexer::from("{x:U; y}:T".chars()).peekable(); + let typectx = Arc::new(RwLock::new(laddertypes::dict::TypeDict::new())); + let bindings = crate::parser::parse_binding_expr( &typectx, &mut lexer ); + + let type_u = typectx.write().unwrap().parse("U").unwrap(); + let type_t = typectx.write().unwrap().parse("T").unwrap(); + + assert_eq!( + bindings, + Ok(crate::parser::VariableBinding::Struct{ + members: vec![ + crate::parser::VariableBinding::Atomic{ + symbol: "x".into(), + typtag: Some(type_u) + }, + crate::parser::VariableBinding::Atomic{ symbol: "y".into(), typtag: None } + ], + typtag: Some(type_t) + }) + ); + } +}