Skip to content
Snippets Groups Projects
Commit 15725c02 authored by Stephen D's avatar Stephen D
Browse files

parser

parent ea0f5e9a
No related branches found
No related tags found
No related merge requests found
#[derive(Debug)]
pub enum Expr {
Lambda(Box<Expr>),
Abs(Box<Expr>),
App(Box<Expr>, Box<Expr>),
Var(usize),
DefinitionName(String),
}
use parser::Parser;
use scanner::Scanner;
mod expr;
mod parser;
mod scanner;
mod token;
......@@ -14,7 +17,15 @@ $true = λtf.t
",
);
for t in scanner.scan_tokens().unwrap() {
dbg!(t.token_type);
let tokens = scanner.scan_tokens().unwrap();
for t in &tokens {
println!("{} {:?}", t.line, t.token_type);
}
let mut parser = Parser::new(tokens);
let (funcs, main) = parser.parse().unwrap();
dbg!(funcs);
dbg!(main);
}
use std::collections::HashMap;
use crate::{
expr::Expr,
token::{Token, TokenType},
};
pub struct Parser {
tokens: Vec<Token>,
current: usize,
env: Vec<char>,
}
impl Parser {
pub fn new(tokens: Vec<Token>) -> Self {
Self {
tokens,
current: 0,
env: vec![],
}
}
pub fn parse(&mut self) -> Option<(HashMap<String, Expr>, Expr)> {
let mut definitions = HashMap::new();
let mut main_expr = None;
while !self.is_at_end() {
let t = self.peek().token_type.clone();
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);
}
// main expr
_ => {
let expr = self.expr()?;
if main_expr.is_some() {
self.print_error("Duplicate primary expression");
return None;
}
main_expr = Some(expr);
}
}
}
match main_expr {
Some(expr) => Some((definitions, expr)),
None => {
self.print_error("Missing primary expression");
None
}
}
}
fn expr(&mut self) -> Option<Expr> {
match &self.peek().token_type {
TokenType::Lambda => self.abstraction(),
TokenType::DefinitionName(name) => {
let name = name.clone();
self.advance();
Some(Expr::DefinitionName(name))
}
TokenType::LeftParen => self.application(),
TokenType::Variable(c) => {
let c = *c;
self.advance();
Some(Expr::Var(self.find_variable(c)?))
}
_ => {
self.print_error(
"Unexpected token. Expected one of 'λ', '/', '\\', '$', '(', or a variable",
);
None
}
}
}
fn abstraction(&mut self) -> Option<Expr> {
self.advance(); // consume lambda
let mut abs_count = 0;
while let TokenType::Variable(v) = self.peek().token_type {
self.env.push(v);
abs_count += 1;
self.advance();
}
if self.advance().token_type != TokenType::Period {
self.print_error("Expected '.' after abstraction variable definitions");
return None;
}
let mut expr = self.expr()?;
for _ in 0..abs_count {
self.env.pop().unwrap();
expr = Expr::Lambda(Box::new(expr));
}
Some(expr)
}
fn application(&mut self) -> Option<Expr> {
self.advance(); // consume left paren
let left = self.expr()?;
let right = self.expr()?;
dbg!(&left, &right);
dbg!(&self.peek().token_type);
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> {
let ret = self
.env
.iter()
.enumerate()
.find(|(_, x)| **x == name)
.map(|(i, _)| i);
match ret {
Some(x) => Some(x),
None => {
self.print_error(&format!("Unknown variable '{}'.", name));
None
}
}
}
fn peek(&self) -> &Token {
&self.tokens[self.current]
}
fn peek_next(&self) -> &TokenType {
if self.current + 1 == self.tokens.len() {
&TokenType::NoToken
} else {
&self.tokens[self.current + 1].token_type
}
}
fn advance(&mut self) -> &Token {
let t = &self.tokens[self.current];
self.current += 1;
t
}
fn is_at_end(&self) -> bool {
self.tokens.len() == self.current
}
fn print_error(&self, err: &str) {
eprintln!("Error on line [{}]: {err}", self.peek().line);
}
}
......@@ -26,9 +26,6 @@ impl Scanner {
self.scan_token()?;
}
self.tokens
.push(Token::new(TokenType::Eof, "".to_string(), self.line));
Ok(self.tokens)
}
......@@ -45,7 +42,7 @@ impl Scanner {
'\\' | '/' | 'λ' => Lambda,
_ if c.is_alphabetic() => Variable(c),
'$' => {
self.function()?;
self.definition()?;
NoToken
}
......@@ -59,7 +56,7 @@ impl Scanner {
}
_ => {
self.print_error(&format!("Unexpected character `{}`.", c));
self.print_error(&format!("Unexpected character '{}'.", c));
return Err(());
}
......@@ -70,7 +67,7 @@ impl Scanner {
Ok(())
}
fn function(&mut self) -> Result<(), ()> {
fn definition(&mut self) -> Result<(), ()> {
while self.peek().is_alphanumeric() {
self.advance();
}
......@@ -81,7 +78,7 @@ impl Scanner {
return Err(());
}
self.add_token(TokenType::Function(
self.add_token(TokenType::DefinitionName(
self.chars[(self.start + 1)..self.current].iter().collect(),
));
......
#[derive(PartialEq, Eq, Debug)]
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TokenType {
Variable(char),
Function(String),
DefinitionName(String),
Lambda,
Period,
Equals,
Eof,
LeftParen,
RightParen,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment