diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 6 | ||||
-rw-r--r-- | src/parser.rs | 49 | ||||
-rw-r--r-- | src/simple.rs | 58 |
3 files changed, 59 insertions, 54 deletions
diff --git a/src/main.rs b/src/main.rs index bff203b..2a44397 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,7 @@ fn main() { input.clear(); stdin().read_line(&mut input).unwrap(); - match simple::infer(Context::new(), parser::parse(&input)) { + match simple::infer(Context::new(), parser::parse_lambda(&input).unwrap()) { Ok(term) => println!("infers! {:?}", term), Err(e) => println!("{:?}", e), } @@ -36,7 +36,7 @@ fn main() { let kind = simple::infer(Context::new(), parser::parse(&input)); match kind { Ok(kind) => { - match simple::check(Context::new(), parser::parse(&input), kind) { + match simple::check(Context::new(), parser::parse_lambda(&input).unwrap(), kind) { Ok(_) => println!("checks!"), Err(e) => println!("{:?}", e), } @@ -51,7 +51,7 @@ fn main() { input.clear(); stdin().read_line(&mut input).unwrap(); - match simple::execute(Context::new(), parser::parse(&input)) { + match simple::execute(Context::new(), parser::parse_lambda(&input).unwrap()) { Ok(term) => println!("{:?}", term), Err(e) => println!("{:?}", e) } diff --git a/src/parser.rs b/src/parser.rs index edf906e..79e9ec8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,13 +2,31 @@ use crate::ast::*; // (λx:T.y): T z pub fn parse(input: &str) -> Expression { - return parse_str(input).expect("invalid expression"); + match parse_lambda(input) { + Ok(expr) => return expr, + Err(e) => println!("invalid expression! {:?}", e) + } + return Expression::Constant { term: Term { val: 0, kind: Type::Empty } }; +} + +/// Parses a Nim-like language into an AST. +pub fn parse_file(path: &str) -> Vec<Expression> { + match std::fs::read_to_string(path) { + Ok(file) => match lex(&file) { + Ok(input) => match parse_lang(&input) { + Ok(expr) => return expr, + Err(e) => println!("failed to parse file! {:?}", e), + }, + Err(e) => println!("failed to lex file! {:?}", e), + }, + Err(e) => println!("failed to read file! {:?}", e), + } + return Vec::new(); } /// Parses a lambda-calculus-like language into an AST. -pub fn parse_str(input: &str) -> Result<Expression, peg::error::ParseError<peg::str::LineCol>> { - // this is kinda awful - // i miss my nim pegs +pub fn parse_lambda(input: &str) -> Result<Expression, peg::error::ParseError<peg::str::LineCol>> { + // this is kinda awful, i miss my simple nim pegs peg::parser!{ grammar lambda() for str { rule identifier() -> String @@ -86,21 +104,12 @@ pub fn parse_str(input: &str) -> Result<Expression, peg::error::ParseError<peg:: = expression() ** ("\n"+) } } - // assert_eq!(lambda::expression("(λx:bool.x)").unwrap(), lambda::expression("(λx: bool . x)").unwrap()); - return lambda::expression(input.trim()); } -/// Parses a Nim-like language into an AST. -#[allow(unused_variables)] -pub fn parse_file(path: &str) -> Vec<Expression> { - todo!(); -} - /// Converts a whitespace-indented language into a regular bracketed language for matching with PEGs /// Then, tokens are known to be separated by [\n ]+ (except strings. problem for later.) pub fn lex(input: &str) -> Result<String, &'static str> { - #[derive(Eq, PartialEq)] enum Previous { Start, @@ -119,6 +128,7 @@ pub fn lex(input: &str) -> Result<String, &'static str> { let mut buffer = String::new(); let mut result = String::new(); + // wow lexers are hard for c in input.chars() { match c { '\n' => { @@ -146,7 +156,7 @@ pub fn lex(input: &str) -> Result<String, &'static str> { } state.level -= indent_size; result.push('\n'); - result.push_str(" ".repeat(state.level).as_str()); + result.push_str(&" ".repeat(state.level)); result.push('}'); state.previous = Previous::Block; } @@ -155,7 +165,7 @@ pub fn lex(input: &str) -> Result<String, &'static str> { return Err("unknown indentation error"); } - result.push_str(" ".repeat(state.count).as_str()); + result.push_str(&" ".repeat(state.count)); result.push_str(&buffer); state.count = 0; @@ -180,8 +190,15 @@ pub fn lex(input: &str) -> Result<String, &'static str> { while state.level != 0 { state.level -= 2; result.push('\n'); - result.push_str(" ".repeat(state.level).as_str()); + result.push_str(&" ".repeat(state.level)); result.push('}'); } return Ok(result); } + +/// Parses a simple language with bracket-based indentation and end-of-term semicolons. +/// The lex() function can turn an indentation-based language into a language recognizable by this. +#[allow(unused_variables)] +pub fn parse_lang(input: &str) -> Result<Vec<Expression>, peg::error::ParseError<peg::str::LineCol>> { + todo!(); +} diff --git a/src/simple.rs b/src/simple.rs index 4419680..22708a4 100644 --- a/src/simple.rs +++ b/src/simple.rs @@ -8,32 +8,25 @@ pub fn check(context: Context, expression: Expression, target: Type) -> Result<( match expression { Expression::Annotation { expr, kind } => Err(("attempting to typecheck an annotation", context, target)), // Bt-CheckInfer - Expression::Constant { term } => { - if term.kind == target { - Ok(()) - } else { - Err(("constant is of wrong type", context, target)) - } + Expression::Constant { term } => match term.kind == target { + true => Ok(()), + false => Err(("constant is of wrong type", context, target)) }, // Bt-CheckInfer - Expression::Variable { id } => { - // in the future: extend to closures? nah probably not - match context.get(&id) { - Some(term) if term.kind == target => Ok(()), - Some(_) => Err(("variable is of wrong type", context, target)), - None => Err(("failed to find variable in context", context, target)) - } + // in the future: extend to closures? nah probably not + Expression::Variable { id } => match context.get(&id) { + Some(term) if term.kind == target => Ok(()), + Some(_) => Err(("variable is of wrong type", context, target)), + None => Err(("failed to find variable in context", context, target)) }, // Bt-Abs - Expression::Abstraction { param, func } => { - match target { - Type::Function { from, to } => { - let mut context = context; - context.insert(param, Term { val: 0, kind: *from }); // hack - return check(context, *func, *to); - }, - _ => Err(("attempting to check an abstraction with a non-function type", context, target)) - } + Expression::Abstraction { param, func } => match target { + Type::Function { from, to } => { + let mut context = context; + context.insert(param, Term { val: 0, kind: *from }); // hack + return check(context, *func, *to); + }, + _ => Err(("attempting to check an abstraction with a non-function type", context, target)) }, Expression::Application { func, arg } => Err(("attempting to check an application", context, target)), // T-If @@ -54,21 +47,16 @@ pub fn infer(context: Context, expression: Expression) -> Result<Type, (&'static // Bt-True / Bt-False / etc Expression::Constant { term } => Ok(term.kind), // Bt-Var - Expression::Variable { id } => { - match context.get(&id) { - Some(term) => Ok(term.clone().kind), - None => Err(("failed to find variable in context", context, Type::Empty)) - } + Expression::Variable { id } => match context.get(&id) { + Some(term) => Ok(term.clone().kind), + None => Err(("failed to find variable in context", context, Type::Empty)) }, // Bt-App - Expression::Application { func, arg } => { - let expr = infer(context.clone(), *func)?; - match expr { - Type::Function { from, to } => { - check(context, *arg, *from).map(|x| *to) - }, - _ => Err(("application abstraction is not a function type", context, Type::Empty)) - } + Expression::Application { func, arg } => match infer(context.clone(), *func)? { + Type::Function { from, to } => { + check(context, *arg, *from).map(|x| *to) + }, + _ => Err(("application abstraction is not a function type", context, Type::Empty)) }, Expression::Abstraction { param, func } => Err(("attempting to infer from an abstraction", context, Type::Empty)), // idk |