487 lines
17 KiB
Rust
487 lines
17 KiB
Rust
use {
|
|
crate::{
|
|
expr::{LTExpr, Statement, TypeError, TypeTag},
|
|
lexer::{LTIRLexer, LTIRToken, LexError, InputRegionTag},
|
|
},
|
|
std::{
|
|
iter::Peekable,
|
|
sync::{Arc, RwLock},
|
|
},
|
|
};
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub enum ParseError {
|
|
LexError(LexError),
|
|
UnexpectedClose,
|
|
UnexpectedEnd,
|
|
UnexpectedToken,
|
|
TypeParseError(laddertypes::parser::ParseError)
|
|
}
|
|
|
|
pub fn parse_expect<It>(
|
|
tokens: &mut Peekable<It>,
|
|
expected_token: LTIRToken,
|
|
) -> Result<(), (InputRegionTag, ParseError)>
|
|
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
|
{
|
|
match tokens.next() {
|
|
Some((region, Ok(t))) => {
|
|
if t == expected_token {
|
|
Ok(())
|
|
} else {
|
|
Err((region, ParseError::UnexpectedToken))
|
|
}
|
|
}
|
|
Some((region, Err(err))) => Err((region, ParseError::LexError(err))),
|
|
None => Err((InputRegionTag::default(), ParseError::UnexpectedEnd)),
|
|
}
|
|
}
|
|
|
|
/* parse symbol name
|
|
*/
|
|
pub fn parse_symbol<It>(tokens: &mut Peekable<It>) -> Result<String, (InputRegionTag, ParseError)>
|
|
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
|
{
|
|
match tokens.next() {
|
|
Some((region, Ok(LTIRToken::Symbol(name)))) => Ok(name),
|
|
Some((region, Ok(_))) => Err((region, ParseError::UnexpectedToken)),
|
|
Some((region, Err(err))) => Err((region, ParseError::LexError(err))),
|
|
None => Err((InputRegionTag::default(), ParseError::UnexpectedEnd)),
|
|
}
|
|
}
|
|
|
|
/* parse an optional type annotation
|
|
* `: T`
|
|
*/
|
|
pub fn parse_type_tag<It>(
|
|
typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>,
|
|
tokens: &mut Peekable<It>,
|
|
) -> Result<Option<laddertypes::TypeTerm>, (InputRegionTag, ParseError)>
|
|
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
|
{
|
|
let peek = { tokens.peek().cloned() };
|
|
if let Some((region, peektok)) = peek {
|
|
match peektok {
|
|
Ok(LTIRToken::AssignType(typeterm_str)) => {
|
|
tokens.next();
|
|
match typectx.write().unwrap().parse(typeterm_str.as_str()) {
|
|
Ok(typeterm) => Ok(Some(typeterm)),
|
|
Err(parse_error) => Err((region, ParseError::TypeParseError(parse_error))),
|
|
}
|
|
}
|
|
_ => Ok(None),
|
|
}
|
|
} else {
|
|
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<It>,
|
|
) -> Result< VariableBinding, (InputRegionTag, ParseError)>
|
|
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
|
{
|
|
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((*region, ParseError::LexError(err.clone()))),
|
|
_ => Err((*region, ParseError::UnexpectedToken))
|
|
}
|
|
} else {
|
|
Err((InputRegionTag::default(), 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<It>,
|
|
) -> Result< Vec<VariableBinding>, (InputRegionTag, ParseError)>
|
|
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
|
{
|
|
let mut last_region = InputRegionTag::default();
|
|
|
|
let _ = parse_expect(tokens, LTIRToken::BlockOpen)?;
|
|
|
|
let mut bindings = Vec::new();
|
|
while let Some((region, peektok)) = tokens.peek() {
|
|
last_region = *region;
|
|
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((last_region, ParseError::LexError(err.clone())));
|
|
}
|
|
}
|
|
}
|
|
|
|
Err((last_region, ParseError::UnexpectedEnd))
|
|
}
|
|
|
|
pub fn parse_statement<It>(
|
|
typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>,
|
|
tokens: &mut Peekable<It>,
|
|
) -> Result<crate::expr::Statement, (InputRegionTag, ParseError)>
|
|
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
|
{
|
|
if let Some((region, peektok)) = tokens.peek() {
|
|
match peektok {
|
|
Ok(LTIRToken::Symbol(sym)) => {
|
|
match sym.as_str() {
|
|
"!" => {
|
|
tokens.next();
|
|
// todo accept address-expression instead of symbol
|
|
let name = parse_symbol(tokens)?;
|
|
let val_expr = parse_expr(typectx, tokens)?;
|
|
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
|
|
|
Ok(Statement::Assignment {
|
|
var_id: name,
|
|
val_expr,
|
|
})
|
|
}
|
|
"let" => {
|
|
tokens.next();
|
|
let name = parse_symbol(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: match typ {
|
|
Some(t) => Some(Ok(t)),
|
|
None => None
|
|
},
|
|
var_id: name,
|
|
val_expr,
|
|
})
|
|
}
|
|
"while" => {
|
|
tokens.next();
|
|
let _ = parse_expect(tokens, LTIRToken::ExprOpen)?;
|
|
let cond = parse_expr(typectx, tokens)?;
|
|
let _ = parse_expect(tokens, LTIRToken::ExprClose)?;
|
|
Ok(Statement::WhileLoop {
|
|
condition: cond,
|
|
body: parse_statement_block(typectx, tokens)?,
|
|
})
|
|
}
|
|
"return" => {
|
|
tokens.next();
|
|
let expr = parse_expr(typectx, tokens)?;
|
|
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
|
Ok(Statement::Return(parse_expr(typectx, tokens)?))
|
|
}
|
|
_ => {
|
|
let expr = parse_expr(typectx, tokens)?;
|
|
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
|
Ok(Statement::Expr(expr))
|
|
}
|
|
}
|
|
}
|
|
Ok(_) => {
|
|
let expr = parse_expr(typectx, tokens)?;
|
|
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
|
Ok(Statement::Expr(expr))
|
|
}
|
|
Err(err) => Err((*region, ParseError::LexError(err.clone()))),
|
|
}
|
|
} else {
|
|
Err((InputRegionTag::default(), ParseError::UnexpectedEnd))
|
|
}
|
|
}
|
|
|
|
pub fn parse_statement_block<It>(
|
|
typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>,
|
|
tokens: &mut Peekable<It>,
|
|
) -> Result<Vec<Statement>, (InputRegionTag, ParseError)>
|
|
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
|
{
|
|
let _ = parse_expect(tokens, LTIRToken::BlockOpen)?;
|
|
|
|
let mut statements = Vec::new();
|
|
while let Some((region, peektok)) = tokens.peek() {
|
|
match peektok {
|
|
Ok(LTIRToken::BlockClose) => {
|
|
tokens.next();
|
|
return Ok(statements);
|
|
}
|
|
Ok(_) => {
|
|
statements.push(parse_statement(typectx, tokens)?);
|
|
}
|
|
Err(err) => {
|
|
return Err((*region, ParseError::LexError(err.clone())));
|
|
}
|
|
}
|
|
}
|
|
|
|
Err((InputRegionTag::default(), ParseError::UnexpectedEnd))
|
|
}
|
|
|
|
pub fn parse_atom<It>(
|
|
tokens: &mut Peekable<It>,
|
|
) -> Result<crate::expr::LTExpr, (InputRegionTag, ParseError)>
|
|
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
|
{
|
|
match tokens.next() {
|
|
Some((region, Ok(LTIRToken::Symbol(sym)))) => Ok(LTExpr::symbol(sym.as_str())),
|
|
Some((region, Ok(LTIRToken::Char(c)))) => Ok(LTExpr::lit_uint(c as u64)),
|
|
Some((region, Ok(LTIRToken::Num(n)))) => Ok(LTExpr::lit_uint(n as u64)),
|
|
Some((region, Ok(_))) => Err((region, ParseError::UnexpectedToken)),
|
|
Some((region, Err(err))) => Err((region, ParseError::LexError(err))),
|
|
None => Err((InputRegionTag::default(), ParseError::UnexpectedEnd)),
|
|
}
|
|
}
|
|
|
|
pub fn parse_expr<It>(
|
|
typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>,
|
|
tokens: &mut Peekable<It>,
|
|
) -> Result<crate::expr::LTExpr, (InputRegionTag, ParseError)>
|
|
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
|
{
|
|
let mut children = Vec::new();
|
|
|
|
while let Some((region, tok)) = tokens.peek() {
|
|
match tok {
|
|
Ok(LTIRToken::Lambda) => {
|
|
if children.len() == 0 {
|
|
tokens.next();
|
|
|
|
let mut variable_bindings = parse_binding_expr(typectx, tokens)?;
|
|
let _ = parse_expect(tokens, LTIRToken::MapsTo);
|
|
let body = parse_expr(typectx, tokens)?;
|
|
|
|
return Ok(LTExpr::Abstraction {
|
|
args: variable_bindings.flatten().into_iter().map(|(s,t)| (s,t.map(|t|Ok(t))) ).collect(),
|
|
body: Box::new(body),
|
|
});
|
|
} else {
|
|
return Err((*region, ParseError::UnexpectedToken));
|
|
}
|
|
}
|
|
Ok(LTIRToken::ExprOpen) => {
|
|
tokens.next();
|
|
while let Some((region, peektok)) = tokens.peek() {
|
|
match peektok {
|
|
Ok(LTIRToken::ExprClose) => {
|
|
tokens.next();
|
|
break;
|
|
}
|
|
_ => {}
|
|
}
|
|
children.push(parse_expr(typectx, tokens)?);
|
|
}
|
|
}
|
|
Ok(LTIRToken::ExprClose) => {
|
|
break;
|
|
}
|
|
Ok(LTIRToken::BlockOpen) => {
|
|
children.push(LTExpr::block(parse_statement_block(typectx, tokens)?));
|
|
}
|
|
Ok(LTIRToken::BlockClose) => {
|
|
break;
|
|
}
|
|
Ok(LTIRToken::StatementSep) => {
|
|
break;
|
|
}
|
|
Ok(LTIRToken::Symbol(name)) => match name.as_str() {
|
|
"if" => {
|
|
tokens.next();
|
|
let _ = parse_expect(tokens, LTIRToken::ExprOpen)?;
|
|
let cond = parse_expr(typectx, tokens)?;
|
|
let _ = parse_expect(tokens, LTIRToken::ExprClose)?;
|
|
let if_expr = LTExpr::block(parse_statement_block(typectx, tokens)?);
|
|
let mut else_expr = LTExpr::block(vec![]);
|
|
|
|
if let Some((region, peektok)) = tokens.peek() {
|
|
if let Ok(LTIRToken::Symbol(name)) = peektok {
|
|
if name == "else" {
|
|
tokens.next();
|
|
else_expr = parse_expr(typectx, tokens)?;
|
|
}
|
|
}
|
|
}
|
|
|
|
children.push(LTExpr::Branch {
|
|
condition: Box::new(cond),
|
|
if_expr: Box::new(if_expr),
|
|
else_expr: Box::new(else_expr),
|
|
});
|
|
}
|
|
name => {
|
|
children.push(parse_atom(tokens)?);
|
|
}
|
|
},
|
|
Ok(atom) => {
|
|
children.push(parse_atom(tokens)?);
|
|
}
|
|
Err(err) => {
|
|
return Err((*region, ParseError::LexError(err.clone())));
|
|
}
|
|
}
|
|
}
|
|
|
|
if children.len() > 0 {
|
|
let head = children.remove(0);
|
|
Ok(LTExpr::Application {
|
|
typ: None,
|
|
head: Box::new(head),
|
|
body: children,
|
|
})
|
|
} else {
|
|
Err((InputRegionTag::default(), 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)
|
|
})
|
|
);
|
|
}
|
|
}
|