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) => {
|
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)));
|
||||||
}
|
}
|
||||||
|
|
233
src/parser.rs
233
src/parser.rs
|
@ -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)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue