summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs6
-rw-r--r--src/parser.rs49
-rw-r--r--src/simple.rs58
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