parse struct-binding blocks

This commit is contained in:
Michael Sippel 2024-05-14 09:56:19 +02:00
parent 34a129d101
commit 34e3d3a231
Signed by: senvas
GPG key ID: F96CF119C34B64A6
2 changed files with 216 additions and 19 deletions

View file

@ -219,7 +219,7 @@ where
} }
LexerState::TypeTerm(s) => { LexerState::TypeTerm(s) => {
if *c == '=' || *c == '.' { if *c == '=' || *c == '.' || *c == '↦' || *c == ';' {
if let Some(token) = state.clone().into_token() { if let Some(token) = state.clone().into_token() {
return Some((region, Ok(token))); return Some((region, Ok(token)));
} }

View file

@ -9,12 +9,13 @@ use {
}, },
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq)]
pub enum ParseError { pub enum ParseError {
LexError(LexError), LexError(LexError),
UnexpectedClose, UnexpectedClose,
UnexpectedEnd, UnexpectedEnd,
UnexpectedToken, UnexpectedToken,
TypeParseError(laddertypes::parser::ParseError)
} }
pub fn parse_expect<It>( pub fn parse_expect<It>(
@ -37,6 +38,8 @@ where
} }
} }
/* parse symbol name
*/
pub fn parse_symbol<It>(tokens: &mut Peekable<LTIRLexer<It>>) -> Result<String, ParseError> pub fn parse_symbol<It>(tokens: &mut Peekable<LTIRLexer<It>>) -> Result<String, ParseError>
where where
It: Iterator<Item = char>, It: Iterator<Item = char>,
@ -49,10 +52,13 @@ where
} }
} }
/* parse an optional type annotation
* `: T`
*/
pub fn parse_type_tag<It>( pub fn parse_type_tag<It>(
typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>, typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>,
tokens: &mut Peekable<LTIRLexer<It>>, tokens: &mut Peekable<LTIRLexer<It>>,
) -> Option<TypeTag> ) -> Result<Option<laddertypes::TypeTerm>, ParseError>
where where
It: Iterator<Item = char>, It: Iterator<Item = char>,
{ {
@ -61,17 +67,110 @@ where
Ok(LTIRToken::AssignType(typeterm_str)) => { Ok(LTIRToken::AssignType(typeterm_str)) => {
tokens.next(); tokens.next();
match typectx.write().unwrap().parse(typeterm_str.as_str()) { match typectx.write().unwrap().parse(typeterm_str.as_str()) {
Ok(typeterm) => Some(Ok(typeterm)), Ok(typeterm) => Ok(Some(typeterm)),
Err(parse_error) => Some(Err(TypeError::ParseError(parse_error))), Err(parse_error) => Err(ParseError::TypeParseError(parse_error)),
} }
} }
_ => None, _ => Ok(None),
} }
} else { } else {
None Ok(None)
} }
} }
#[derive(Debug, PartialEq, Eq)]
pub enum VariableBinding {
Atomic {
symbol: String,
typtag: Option<laddertypes::TypeTerm>
},
Struct {
members: Vec< VariableBinding >,
typtag: Option<laddertypes::TypeTerm>
}
}
impl VariableBinding {
pub fn flatten(self) -> Vec<(String, Option<laddertypes::TypeTerm>)> {
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<It>(
typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>,
tokens: &mut Peekable<LTIRLexer<It>>,
) -> Result< VariableBinding, ParseError>
where It: Iterator<Item = char>
{
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<It>(
typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>,
tokens: &mut Peekable<LTIRLexer<It>>,
) -> Result< Vec<VariableBinding>, ParseError>
where
It: Iterator<Item = char>,
{
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<It>( pub fn parse_statement<It>(
typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>, typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>,
tokens: &mut Peekable<LTIRLexer<It>>, tokens: &mut Peekable<LTIRLexer<It>>,
@ -98,13 +197,19 @@ where
"let" => { "let" => {
tokens.next(); tokens.next();
let name = parse_symbol(tokens)?; 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 _ = parse_expect(tokens, LTIRToken::AssignValue);
let val_expr = parse_expr(typectx, tokens)?; let val_expr = parse_expr(typectx, tokens)?;
let _ = parse_expect(tokens, LTIRToken::StatementSep)?; let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
Ok(Statement::LetAssign { Ok(Statement::LetAssign {
typ, typ: match typ {
Some(t) => Some(Ok(t)),
None => None
},
var_id: name, var_id: name,
val_expr, val_expr,
}) })
@ -116,7 +221,7 @@ where
let _ = parse_expect(tokens, LTIRToken::ExprClose)?; let _ = parse_expect(tokens, LTIRToken::ExprClose)?;
Ok(Statement::WhileLoop { Ok(Statement::WhileLoop {
condition: cond, condition: cond,
body: parse_block(typectx, tokens)?, body: parse_statement_block(typectx, tokens)?,
}) })
} }
"return" => { "return" => {
@ -144,7 +249,7 @@ where
} }
} }
pub fn parse_block<It>( pub fn parse_statement_block<It>(
typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>, typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>,
tokens: &mut Peekable<LTIRLexer<It>>, tokens: &mut Peekable<LTIRLexer<It>>,
) -> Result<Vec<Statement>, ParseError> ) -> Result<Vec<Statement>, ParseError>
@ -203,16 +308,12 @@ where
if children.len() == 0 { if children.len() == 0 {
tokens.next(); tokens.next();
let mut args = Vec::new(); let mut variable_bindings = parse_binding_expr(typectx, tokens)?;
while let Some((region, Ok(LTIRToken::Symbol(_)))) = tokens.peek() {
args.push((parse_symbol(tokens)?, parse_type_tag(typectx, tokens)));
}
let _ = parse_expect(tokens, LTIRToken::LambdaBody); let _ = parse_expect(tokens, LTIRToken::LambdaBody);
let body = parse_expr(typectx, tokens)?; let body = parse_expr(typectx, tokens)?;
return Ok(LTExpr::Abstraction { 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), body: Box::new(body),
}); });
} else { } else {
@ -236,7 +337,7 @@ where
break; break;
} }
Ok(LTIRToken::BlockOpen) => { Ok(LTIRToken::BlockOpen) => {
children.push(LTExpr::block(parse_block(typectx, tokens)?)); children.push(LTExpr::block(parse_statement_block(typectx, tokens)?));
} }
Ok(LTIRToken::BlockClose) => { Ok(LTIRToken::BlockClose) => {
break; break;
@ -250,7 +351,7 @@ where
let _ = parse_expect(tokens, LTIRToken::ExprOpen)?; let _ = parse_expect(tokens, LTIRToken::ExprOpen)?;
let cond = parse_expr(typectx, tokens)?; let cond = parse_expr(typectx, tokens)?;
let _ = parse_expect(tokens, LTIRToken::ExprClose)?; 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![]); let mut else_expr = LTExpr::block(vec![]);
if let Some((region, peektok)) = tokens.peek() { if let Some((region, peektok)) = tokens.peek() {
@ -292,3 +393,99 @@ where
Err(ParseError::UnexpectedEnd) 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)
})
);
}
}