diff options
| author | Elizabeth Alexander Hunt <me@liz.coffee> | 2026-08-11 07:23:07 -0700 |
|---|---|---|
| committer | Elizabeth Alexander Hunt <me@liz.coffee> | 2026-08-11 07:23:07 -0700 |
| commit | b5cb9f472d9b19d762aac91116b266f90404b9ca (patch) | |
| tree | 6685dbf39890a4db364df75f8510101e1449f120 /src | |
| parent | fc2844ae88c85f082b47630b92a55bca3ff285b1 (diff) | |
| download | gock-b5cb9f472d9b19d762aac91116b266f90404b9ca.tar.gz gock-b5cb9f472d9b19d762aac91116b266f90404b9ca.zip | |
Parsin
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 255 |
1 files changed, 240 insertions, 15 deletions
diff --git a/src/main.rs b/src/main.rs index 7ec318a..5018b43 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] enum TokenType { Lparen, Rparen, @@ -6,18 +6,22 @@ enum TokenType { Rbrace, Lbracket, Rbracket, + Arrow, + Comma, + Equals, + Semicolon, Colon, Identifier(String), Eof, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] struct Blame { line: usize, char: usize, } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] struct Token { token: TokenType, blame: Blame, @@ -36,7 +40,7 @@ impl Lexer { tokens.push(Token { token: TokenType::Eof, blame: Blame { - line: tokens.len(), + line: program.lines().count(), char: 0, }, }); @@ -59,6 +63,7 @@ impl Lexer { }; for (i, c) in text.char_indices() { + let lookahead = text.chars().nth(i.saturating_add(1)); let singlechar = match c { '(' => Some(TokenType::Lparen), ')' => Some(TokenType::Rparen), @@ -67,6 +72,12 @@ impl Lexer { '{' => Some(TokenType::Lbrace), '}' => Some(TokenType::Rbrace), ':' => Some(TokenType::Colon), + ';' => Some(TokenType::Semicolon), + '-' => { + Some(TokenType::Arrow).take_if(|_| lookahead.filter(|it| *it == '>').is_some()) + } + ',' => Some(TokenType::Comma), + '=' => Some(TokenType::Equals), _ => None, }; @@ -109,16 +120,182 @@ type Identifier = String; struct Binding { name: Identifier, - arg_type: Option<SimpleType>, + arg_type: Option<Box<TypeDeclaration>>, +} + +struct TypeDeclaration { + base_type: Option<Identifier>, + arrow: Option<Box<(TypeDeclaration, TypeDeclaration)>>, +} + +struct Assignment { + binding: Binding, + computation: Computation, +} + +struct Arguments { + args_list: Vec<Identifier>, +} + +struct Abstraction { + arguments: Arguments, + body: Box<Computation>, +} + +struct Application { + apply: Option<(Box<Computation>, Box<Computation>)>, +} + +struct Computation { + application: Option<Application>, + abstraction: Option<Abstraction>, + identifier: Option<Identifier>, +} + +struct LetStatement { + assignments: Vec<Assignment>, } enum ASTNode { - Abstraction { - binding: Binding, - body: Box<ASTNode>, - }, - Application((Box<ASTNode>, Box<ASTNode>)), - Identifier(Identifier), + Binding(Binding), + TypeDeclaration(TypeDeclaration), + Assignment(Assignment), + Arguments(Arguments), + Abstraction(Abstraction), + Application(Application), + Computation(Computation), + LetStatement(LetStatement), +} + +struct Parser { + position: usize, + tokens: Vec<Token>, +} + +#[derive(Debug)] +enum ParsingFailure { + Blame(Blame, String), + PastTokens, +} + +impl Parser { + fn peek(&mut self) -> Option<&Token> { + return self.tokens.get(self.position + 1); + } + + fn consume_if_and_map<T>( + &mut self, + f: fn(&Token) -> Option<T>, + msg: String, + ) -> Result<T, ParsingFailure> { + if self.position == self.tokens.len() { + return Result::Err(ParsingFailure::PastTokens); + } + let val = f(&self.tokens[self.position]); + if val.is_some() { + self.position += 1; + return Result::Ok(val.unwrap()); //&self.tokens[self.position - 1]); + } + return Result::Err(ParsingFailure::Blame(self.tokens[self.position].blame, msg)); + } + + fn consume_if_match( + &mut self, + f: fn(&Token) -> bool, + msg: String, + ) -> Result<&Token, ParsingFailure> { + if self.position == self.tokens.len() { + return Result::Err(ParsingFailure::PastTokens); + } + if f(&self.tokens[self.position]) { + self.position += 1; + return Result::Ok(&self.tokens[self.position - 1]); + } + return Result::Err(ParsingFailure::Blame(self.tokens[self.position].blame, msg)); + } + + fn consume_if_match_nomsg(&mut self, f: fn(&Token) -> bool) -> Result<&Token, ParsingFailure> { + return self.consume_if_match(f, String::from("Unexpected error")); + } + + fn parse_type_declaration(&mut self) -> Result<TypeDeclaration, ParsingFailure> {} + + fn parse_binding(&mut self) -> Result<Binding, ParsingFailure> { + return self + .consume_if_and_map( + |it| match ((*it).token).clone() { + // unfortunately, gotta clone to make the borrow checker happy. maybe i'll come back to this :3 + TokenType::Identifier(name) => Some(name), + _ => None, + }, + String::from("Expected identifier"), + ) + .and_then(|name| { + let val = self.consume_if_match_nomsg(|it| (*it).token == TokenType::Colon); + if val.is_ok() { + let blame = val.unwrap().blame; + if let Ok(type_decl) = self.parse_type_declaration() { + return Ok(Binding { + name, + arg_type: Some(Box::new(type_decl)), + }); + } + return Err(ParsingFailure::Blame( + blame, + String::from("Expected type declaration"), + )); + } + return Ok(Binding { + name, + arg_type: None, + }); + }); + } + + fn parse_assignment(&mut self) -> Result<Assignment, ParsingFailure> { + let binding = self.parse_binding(); + if binding.is_ok() + && let Ok(ok) = self.consume_if_match( + |it| (*it).token == TokenType::Equals, + String::from("Expected equals after binding"), + ) + { + return Ok(Assignment { + binding: binding.unwrap(), + computation: self.parse_computation(), + }); + } + return Err(); + // + // if (self.consume_if_matches(|it| (*it).token == TokenType::Colon)) { + // type_declaration = self.parse_type_declaration(); + // } + // self.consume_if_matches(|it| (*it)) + // //return self.consume_if_matches(|it| match (*it) + } + + fn parse_let_statement(&mut self) -> Result<&LetStatement, ParsingFailure> { + self.consume_if_match_nomsg(|it| (*it).token == TokenType::Identifier(String::from("let"))); + + let assignments: Vec<&Assignment> = Vec::new(); + let assignment = self.parse_assignment(); + self.consume_if_match_nomsg(|it| (*it).token == TokenType::Semicolon); + } + + fn parse(&mut self) -> Result<ASTNode, ParsingFailure> { + let consume = |args| {}; + + // let program: LetStatement = self.parseLetStatement(); + } + + fn new(tokens: Vec<Token>) -> Parser { + return Parser { + position: 0, + tokens, + }; + + } + // fn new() -> Parser {} } pub enum StepResult<T> { @@ -164,9 +341,7 @@ impl<T> Environment<'_, T> { } } -fn main() { - println!("Hello, world!"); -} +fn main() {} #[cfg(test)] mod tests { @@ -181,10 +356,60 @@ mod tests { let env = Environment::root(ident.clone(), &val); assert_eq!(env.get(ident.clone()), Some(&val)); let env2 = env.add(ident2.clone(), &val2); - assert_eq!(env2.get(ident.clone()), Some(&val2)); + assert_eq!(env2.get(ident2.clone()), Some(&val2)); let env3 = env2.add(ident.clone(), &val3); assert_eq!(env3.get(ident2.clone()), Some(&val2)); assert_eq!(env3.get(ident.clone()), Some(&val3)); assert_eq!(env.get(ident.clone()), Some(&val)); } + + #[test] + fn test_lex() { + let prog = "let identity: ((Int) \n-> (Int)) = [a] { a };"; + let analysis = Lexer::analyze(prog); + assert_eq!( + analysis[0], + Token { + token: TokenType::Identifier(String::from("let")), + blame: Blame { line: 0, char: 0 } + } + ); + assert_eq!( + analysis[1], + Token { + token: TokenType::Identifier(String::from("identity")), + blame: Blame { line: 0, char: 4 } + } + ); + assert_eq!( + analysis[2], + Token { + token: TokenType::Colon, + blame: Blame { line: 0, char: 12 } + } + ); + assert_eq!( + analysis[7], + Token { + token: TokenType::Arrow, + blame: Blame { line: 1, char: 0 } + } + ); + assert_eq!( + analysis[21], + Token { + token: TokenType::Eof, + blame: Blame { line: 2, char: 0 } + } + ); + } + + #[test] + fn test_parse() { + let prog = "let Identity: ((Int) -> (Int)) = [a] { a };"; + let tokens = Lexer::analyze(prog); + let mut parser = Parser::new(tokens); + let ast = parser.parse().ok(); + ast.unwrap(); + } } |
