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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ariadne"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7080ae01b2f0c312065d4914cd0f0de045eb8832e9415b355106a6cff3073cb4"
|
||||
dependencies = [
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "beef"
|
||||
version = "0.5.1"
|
||||
|
|
@ -81,6 +90,7 @@ dependencies = [
|
|||
name = "lambda-calculus"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ariadne",
|
||||
"chumsky",
|
||||
"logos",
|
||||
]
|
||||
|
|
@ -188,3 +198,9 @@ name = "wasi"
|
|||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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
|
||||
|
||||
[dependencies]
|
||||
ariadne = "0.1.3"
|
||||
chumsky = "0.7.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;
|
||||
|
||||
mod lexer {
|
||||
use logos::Logos;
|
||||
use std::fmt::Formatter;
|
||||
|
||||
#[derive(Logos, Clone, Eq, PartialEq, Hash)]
|
||||
#[derive(Logos, Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum Token<'a> {
|
||||
#[token("λ")]
|
||||
Lambda,
|
||||
|
|
@ -27,56 +30,138 @@ mod lexer {
|
|||
#[regex(r"[ \t\r\n]+", logos::skip)]
|
||||
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 {
|
||||
use crate::lexer::Token;
|
||||
use chumsky::prelude::*;
|
||||
|
||||
enum Expr {
|
||||
#[derive(Debug)]
|
||||
pub enum Expr {
|
||||
Name(String),
|
||||
Application {
|
||||
function: Box<Expr>,
|
||||
argument: Box<Expr>,
|
||||
},
|
||||
Abstraction {
|
||||
args: Vec<String>,
|
||||
body: Expr,
|
||||
args: Vec<char>,
|
||||
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| {
|
||||
let variable = filter_map(|span, token| match token {
|
||||
Token::Ident(name) => Ok(Expr::Name(name.to_string())),
|
||||
let ident = filter_map(|span, token| match token {
|
||||
Token::Ident(ident) => Ok(ident.to_string()),
|
||||
_ => Err(Simple::expected_input_found(span, [], Some(token))),
|
||||
})
|
||||
.labelled("variable");
|
||||
.labelled("ident");
|
||||
|
||||
let abstraction = just(Token::Lambda)
|
||||
.ignore_then(variable)
|
||||
.then(Token::Dot)
|
||||
.then(expr.clone());
|
||||
.ignore_then(ident)
|
||||
.then_ignore(just(Token::Dot))
|
||||
.then(expr)
|
||||
.map(|(args, body)| Expr::Abstraction {
|
||||
args: args.chars().collect(),
|
||||
body: Box::new(body),
|
||||
})
|
||||
.labelled("abstraction");
|
||||
|
||||
let application = just(expr).then(expr.clone());
|
||||
|
||||
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!()
|
||||
abstraction
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
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