parse struct-binding blocks
This commit is contained in:
parent
34a129d101
commit
34e3d3a231
2 changed files with 216 additions and 19 deletions
|
@ -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)));
|
||||
}
|
||||
|
|
233
src/parser.rs
233
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<It>(
|
||||
|
@ -37,6 +38,8 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/* parse symbol name
|
||||
*/
|
||||
pub fn parse_symbol<It>(tokens: &mut Peekable<LTIRLexer<It>>) -> Result<String, ParseError>
|
||||
where
|
||||
It: Iterator<Item = char>,
|
||||
|
@ -49,10 +52,13 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/* parse an optional type annotation
|
||||
* `: T`
|
||||
*/
|
||||
pub fn parse_type_tag<It>(
|
||||
typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>,
|
||||
tokens: &mut Peekable<LTIRLexer<It>>,
|
||||
) -> Option<TypeTag>
|
||||
) -> Result<Option<laddertypes::TypeTerm>, ParseError>
|
||||
where
|
||||
It: Iterator<Item = char>,
|
||||
{
|
||||
|
@ -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<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>(
|
||||
typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>,
|
||||
tokens: &mut Peekable<LTIRLexer<It>>,
|
||||
|
@ -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<It>(
|
||||
pub fn parse_statement_block<It>(
|
||||
typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>,
|
||||
tokens: &mut Peekable<LTIRLexer<It>>,
|
||||
) -> Result<Vec<Statement>, 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)
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue