From c713c36d7c86cb435181500cda3d376aace6a986 Mon Sep 17 00:00:00 2001 From: Stephen D <webmaster@scd31.com> Date: Tue, 11 Mar 2025 12:55:21 -0400 Subject: [PATCH] parsing works??? --- src/expr.rs | 20 +++++++- src/flatten.rs | 2 +- src/main.rs | 18 ++++--- src/parser.rs | 125 +++++++++++++++++++++++++++++++------------------ src/scanner.rs | 3 ++ src/stmt.rs | 6 +++ src/token.rs | 2 + 7 files changed, 120 insertions(+), 56 deletions(-) create mode 100644 src/stmt.rs diff --git a/src/expr.rs b/src/expr.rs index 42eef34..eed7c65 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + use bitvec::{order::Msb0, vec::BitVec}; #[derive(Debug)] @@ -16,7 +18,7 @@ pub enum FlattenedExpr { } impl FlattenedExpr { - pub fn to_blc(self, bv: &mut BitVec<u8, Msb0>) { + pub fn to_blc(&self, bv: &mut BitVec<u8, Msb0>) { match self { FlattenedExpr::Abs(expr) => { bv.push(false); @@ -32,7 +34,7 @@ impl FlattenedExpr { right.to_blc(bv); } FlattenedExpr::Var(x) => { - for _ in 0..=x { + for _ in 0..=*x { bv.push(true); } @@ -41,3 +43,17 @@ impl FlattenedExpr { } } } + +impl Display for FlattenedExpr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + FlattenedExpr::Abs(expr) => { + write!(f, "λ{}", expr)?; + } + FlattenedExpr::App(left, right) => write!(f, "[{} {}]", left, right)?, + FlattenedExpr::Var(var) => write!(f, "{var}")?, + } + + Ok(()) + } +} diff --git a/src/flatten.rs b/src/flatten.rs index 53e5432..7d51539 100644 --- a/src/flatten.rs +++ b/src/flatten.rs @@ -12,7 +12,7 @@ impl Flattener { } pub fn flatten(&mut self, main: &Expr) -> Option<FlattenedExpr> { - self.flatten_expr(&main, HashSet::new()) + self.flatten_expr(main, HashSet::new()) } fn flatten_expr<'a>( diff --git a/src/main.rs b/src/main.rs index 45cec78..bc62b3c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,17 +7,21 @@ mod expr; mod flatten; mod parser; mod scanner; +mod stmt; mod token; fn main() { let scanner = Scanner::new( " -$false=λtf.f -$omega=λa. (a a) + $false=λtf.f; + $omega=λa. (a a); -λa.a($omega(λbcde.d(bb)(λf.fce)))$false -", + (λa.a($omega(λbcde.d(bb)(λf.fce)))$false); + #(λabc.cb(ab)); + #(λabc.cba); + ", + // "((λab.ba)(λa.a))", ); let tokens = scanner.scan_tokens().unwrap(); @@ -28,12 +32,12 @@ $omega=λa. (a a) let mut flattener = Flattener::new(funcs); let flat = flattener.flatten(&main).unwrap(); - dbg!(&flat); + println!("{flat}"); - let mut bv = BitVec::new(); + /*let mut bv = BitVec::new(); flat.to_blc(&mut bv); for x in bv.as_raw_slice() { print!("{}", *x as char); - } + }*/ } diff --git a/src/parser.rs b/src/parser.rs index 576b45f..035258c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use crate::{ expr::Expr, + stmt::Stmt, token::{Token, TokenType}, }; @@ -24,36 +25,14 @@ impl Parser { let mut definitions = HashMap::new(); let mut main_expr = None; while !self.is_at_end() { - let t = self.peek().token_type.clone(); + let stmt = self.stmt()?; - match t { - TokenType::DefinitionName(name) => { - self.advance(); // consume definition name - - // function expr - - if self.peek().token_type != TokenType::Equals { - self.print_error("Expected '=' after definition name"); - - return None; - } - - self.advance(); // consume equals - - let definition = self.expr()?; - - if definitions.contains_key(&name) { - self.print_error(&format!("Duplicate definition for ${}", name)); - return None; - } - - definitions.insert(name, definition); + match stmt { + Stmt::Definition(name, expr) => { + definitions.insert(name, expr); } - // main expr - _ => { - let expr = self.expr()?; - + Stmt::Main(expr) => { if main_expr.is_some() { self.print_error("Duplicate primary expression"); return None; @@ -74,7 +53,51 @@ impl Parser { } } + fn stmt(&mut self) -> Option<Stmt> { + let stmt = if *self.peek_next() == TokenType::Equals { + // definition + let TokenType::DefinitionName(name) = &self.advance().token_type else { + self.print_error("Expected definition name before '='"); + return None; + }; + + let name = name.clone(); + + // consume = + self.advance(); + + let expr = self.expr()?; + + Stmt::Definition(name, expr) + } else { + Stmt::Main(self.expr()?) + }; + + // consume semicolon + if self.peek().token_type != TokenType::Semicolon { + self.print_error("Expected ';' after statement"); + return None; + } + + self.advance(); + + Some(stmt) + } + fn expr(&mut self) -> Option<Expr> { + let mut expr = self.expr_once()?; + + dbg!(&expr); + + while !self.is_at_end_of_expr() { + let right = self.expr_once()?; + expr = Expr::App(Box::new(expr), Box::new(right)); + } + + Some(expr) + } + + fn expr_once(&mut self) -> Option<Expr> { match &self.peek().token_type { TokenType::Lambda => self.abstraction(), @@ -85,7 +108,22 @@ impl Parser { Some(Expr::DefinitionName(name)) } - TokenType::LeftParen => self.application(), + TokenType::LeftParen => { + self.advance(); // consume ( + + let expr = self.expr()?; + + dbg!(&self.peek().token_type); + + if self.peek().token_type != TokenType::RightParen { + self.print_error("Expected ')'"); + return None; + } + + self.advance(); // consume ) + + Some(expr) + } TokenType::Variable(c) => { let c = *c; @@ -95,6 +133,8 @@ impl Parser { } _ => { + dbg!(&self.peek().token_type); + self.print_error( "Unexpected token. Expected one of 'λ', '/', '\\', '$', '(', or a variable", ); @@ -128,23 +168,9 @@ impl Parser { Some(expr) } - fn application(&mut self) -> Option<Expr> { - self.advance(); // consume left paren - - let left = self.expr()?; - let right = self.expr()?; - - if self.peek().token_type != TokenType::RightParen { - self.print_error("Expected ')' after application"); - return None; - } - - self.advance(); // consume right paren - - Some(Expr::App(Box::new(left), Box::new(right))) - } - fn find_variable(&self, name: char) -> Option<usize> { + dbg!(name, &self.env); + let ret = self .env .iter() @@ -153,7 +179,7 @@ impl Parser { .map(|(i, _)| i); match ret { - Some(x) => Some(x), + Some(x) => Some(self.env.len() - x - 1), None => { self.print_error(&format!("Unknown variable '{}'.", name)); @@ -182,7 +208,14 @@ impl Parser { } fn is_at_end(&self) -> bool { - self.tokens.len() == self.current + self.peek().token_type == TokenType::Eof + } + + fn is_at_end_of_expr(&self) -> bool { + let tt = &self.peek().token_type; + + // end of expr can be ), $, or end of file + matches!(tt, TokenType::RightParen | TokenType::Semicolon) } fn print_error(&self, err: &str) { diff --git a/src/scanner.rs b/src/scanner.rs index 20fc7b3..94a5581 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -26,6 +26,8 @@ impl Scanner { self.scan_token()?; } + self.add_token(TokenType::Eof); + Ok(self.tokens) } @@ -38,6 +40,7 @@ impl Scanner { ')' => RightParen, '.' => Period, '=' => Equals, + ';' => Semicolon, ' ' | '\r' | '\n' | '\t' => NoToken, '\\' | '/' | 'λ' => Lambda, _ if c.is_alphabetic() => Variable(c), diff --git a/src/stmt.rs b/src/stmt.rs new file mode 100644 index 0000000..609f829 --- /dev/null +++ b/src/stmt.rs @@ -0,0 +1,6 @@ +use crate::expr::Expr; + +pub enum Stmt { + Main(Expr), + Definition(String, Expr), +} diff --git a/src/token.rs b/src/token.rs index 8e2cd83..9f51ce2 100644 --- a/src/token.rs +++ b/src/token.rs @@ -6,10 +6,12 @@ pub enum TokenType { Period, Equals, + Semicolon, LeftParen, RightParen, + Eof, NoToken, } -- GitLab