mirror of
https://github.com/Noratrieb/lambda-calculus.git
synced 2026-01-14 15:25:05 +01:00
uh
This commit is contained in:
parent
731974ef45
commit
f42a8d3da1
4 changed files with 133 additions and 28 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
|
@ -11,6 +11,15 @@ dependencies = [
|
||||||
"const-random",
|
"const-random",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ariadne"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7080ae01b2f0c312065d4914cd0f0de045eb8832e9415b355106a6cff3073cb4"
|
||||||
|
dependencies = [
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "beef"
|
name = "beef"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
@ -81,6 +90,7 @@ dependencies = [
|
||||||
name = "lambda-calculus"
|
name = "lambda-calculus"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ariadne",
|
||||||
"chumsky",
|
"chumsky",
|
||||||
"logos",
|
"logos",
|
||||||
]
|
]
|
||||||
|
|
@ -188,3 +198,9 @@ name = "wasi"
|
||||||
version = "0.10.2+wasi-snapshot-preview1"
|
version = "0.10.2+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71"
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,6 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
ariadne = "0.1.3"
|
||||||
chumsky = "0.7.0"
|
chumsky = "0.7.0"
|
||||||
logos = "0.12.0"
|
logos = "0.12.0"
|
||||||
|
|
|
||||||
139
src/lib.rs
139
src/lib.rs
|
|
@ -1,9 +1,12 @@
|
||||||
|
use ariadne::{Color, Fmt, Label, Report, ReportKind, Source};
|
||||||
|
use chumsky::{Parser, Stream};
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
|
|
||||||
mod lexer {
|
mod lexer {
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
|
||||||
#[derive(Logos, Clone, Eq, PartialEq, Hash)]
|
#[derive(Logos, Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum Token<'a> {
|
pub enum Token<'a> {
|
||||||
#[token("λ")]
|
#[token("λ")]
|
||||||
Lambda,
|
Lambda,
|
||||||
|
|
@ -27,56 +30,138 @@ mod lexer {
|
||||||
#[regex(r"[ \t\r\n]+", logos::skip)]
|
#[regex(r"[ \t\r\n]+", logos::skip)]
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Token<'_> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Token::Lambda => write!(f, "λ"),
|
||||||
|
Token::Dot => write!(f, "."),
|
||||||
|
Token::Binding => write!(f, ":="),
|
||||||
|
Token::ParenO => write!(f, "("),
|
||||||
|
Token::ParenC => write!(f, ")"),
|
||||||
|
Token::Ident(ident) => write!(f, "{}", ident),
|
||||||
|
Token::Error => write!(f, "[error]"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod parser {
|
mod parser {
|
||||||
use crate::lexer::Token;
|
use crate::lexer::Token;
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
enum Expr {
|
#[derive(Debug)]
|
||||||
|
pub enum Expr {
|
||||||
Name(String),
|
Name(String),
|
||||||
Application {
|
Application {
|
||||||
function: Box<Expr>,
|
function: Box<Expr>,
|
||||||
argument: Box<Expr>,
|
argument: Box<Expr>,
|
||||||
},
|
},
|
||||||
Abstraction {
|
Abstraction {
|
||||||
args: Vec<String>,
|
args: Vec<char>,
|
||||||
body: Expr,
|
body: Box<Expr>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_parser<'a>() -> impl Parser<Token<'a>, Spanned<Expr>, Error = Simple<Token<'a>>> + Clone
|
pub fn expr_parser<'a>() -> impl Parser<Token<'a>, Expr, Error = Simple<Token<'a>>> + Clone {
|
||||||
{
|
|
||||||
recursive(|expr| {
|
recursive(|expr| {
|
||||||
let variable = filter_map(|span, token| match token {
|
let ident = filter_map(|span, token| match token {
|
||||||
Token::Ident(name) => Ok(Expr::Name(name.to_string())),
|
Token::Ident(ident) => Ok(ident.to_string()),
|
||||||
_ => Err(Simple::expected_input_found(span, [], Some(token))),
|
_ => Err(Simple::expected_input_found(span, [], Some(token))),
|
||||||
})
|
})
|
||||||
.labelled("variable");
|
.labelled("ident");
|
||||||
|
|
||||||
let abstraction = just(Token::Lambda)
|
let abstraction = just(Token::Lambda)
|
||||||
.ignore_then(variable)
|
.ignore_then(ident)
|
||||||
.then(Token::Dot)
|
.then_ignore(just(Token::Dot))
|
||||||
.then(expr.clone());
|
.then(expr)
|
||||||
|
.map(|(args, body)| Expr::Abstraction {
|
||||||
|
args: args.chars().collect(),
|
||||||
|
body: Box::new(body),
|
||||||
|
})
|
||||||
|
.labelled("abstraction");
|
||||||
|
|
||||||
let application = just(expr).then(expr.clone());
|
abstraction
|
||||||
|
|
||||||
let atom = variable
|
|
||||||
.or(expr.delimited_by(Token::ParenO, Token::ParenC))
|
|
||||||
.or(abstraction)
|
|
||||||
.or(application);
|
|
||||||
|
|
||||||
let binding = just(variable)
|
|
||||||
.then_ignore(Token::Binding)
|
|
||||||
.then(expr.clone());
|
|
||||||
|
|
||||||
let statement = just(expr.clone()).or(binding);
|
|
||||||
|
|
||||||
todo!()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(input: &str) {
|
pub fn run(input: &str) {
|
||||||
let mut lex = lexer::Token::lexer(input);
|
let mut lexer = lexer::Token::lexer(input);
|
||||||
|
let length = lexer.source().len();
|
||||||
|
|
||||||
|
match parser::expr_parser().parse(Stream::from_iter(length..length + 1, lexer.spanned())) {
|
||||||
|
Ok(ast) => println!("parsed: {ast:#?}"),
|
||||||
|
Err(errs) => errs
|
||||||
|
.into_iter()
|
||||||
|
.map(|e| e.map(|c| c.to_string()))
|
||||||
|
.for_each(|e| {
|
||||||
|
let report = Report::build(ReportKind::Error, (), e.span().start);
|
||||||
|
|
||||||
|
let report = match e.reason() {
|
||||||
|
chumsky::error::SimpleReason::Unclosed { span, delimiter } => report
|
||||||
|
.with_message(format!(
|
||||||
|
"Unclosed delimiter {}",
|
||||||
|
delimiter.fg(Color::Yellow)
|
||||||
|
))
|
||||||
|
.with_label(
|
||||||
|
Label::new(span.clone())
|
||||||
|
.with_message(format!(
|
||||||
|
"Unclosed delimiter {}",
|
||||||
|
delimiter.fg(Color::Yellow)
|
||||||
|
))
|
||||||
|
.with_color(Color::Yellow),
|
||||||
|
)
|
||||||
|
.with_label(
|
||||||
|
Label::new(e.span())
|
||||||
|
.with_message(format!(
|
||||||
|
"Must be closed before this {}",
|
||||||
|
e.found()
|
||||||
|
.unwrap_or(&"end of file".to_string())
|
||||||
|
.fg(Color::Red)
|
||||||
|
))
|
||||||
|
.with_color(Color::Red),
|
||||||
|
),
|
||||||
|
chumsky::error::SimpleReason::Unexpected => report
|
||||||
|
.with_message(format!(
|
||||||
|
"{}, expected {}",
|
||||||
|
if e.found().is_some() {
|
||||||
|
"Unexpected token in input"
|
||||||
|
} else {
|
||||||
|
"Unexpected end of input"
|
||||||
|
},
|
||||||
|
if e.expected().len() == 0 {
|
||||||
|
"something else".to_string()
|
||||||
|
} else {
|
||||||
|
e.expected()
|
||||||
|
.map(|expected| match expected {
|
||||||
|
Some(expected) => expected.to_string(),
|
||||||
|
None => "end of input".to_string(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
}
|
||||||
|
))
|
||||||
|
.with_label(
|
||||||
|
Label::new(e.span())
|
||||||
|
.with_message(format!(
|
||||||
|
"Unexpected token {}",
|
||||||
|
e.found()
|
||||||
|
.unwrap_or(&"end of file".to_string())
|
||||||
|
.fg(Color::Red)
|
||||||
|
))
|
||||||
|
.with_color(Color::Red),
|
||||||
|
),
|
||||||
|
chumsky::error::SimpleReason::Custom(msg) => {
|
||||||
|
report.with_message(msg).with_label(
|
||||||
|
Label::new(e.span())
|
||||||
|
.with_message(format!("{}", msg.fg(Color::Red)))
|
||||||
|
.with_color(Color::Red),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
report.finish().print(Source::from(input)).unwrap();
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
lambda_calculus::run("hello");
|
lambda_calculus::run("λa.a");
|
||||||
|
// lambda_calculus::run("λa.a");
|
||||||
|
// lambda_calculus::run("λab.a");
|
||||||
|
// lambda_calculus::run("U := λab.a");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue