summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Alexander Hunt <me@liz.coffee>2026-08-12 09:23:46 -0700
committerElizabeth Alexander Hunt <me@liz.coffee>2026-08-12 09:23:46 -0700
commit0e03b779e48cf7c96b6fc351c1f4b3ed7a76d01c (patch)
tree9b7b32ec7e953014826bdea31dc14f08e321f30b
parentb5cb9f472d9b19d762aac91116b266f90404b9ca (diff)
downloadgock-0e03b779e48cf7c96b6fc351c1f4b3ed7a76d01c.tar.gz
gock-0e03b779e48cf7c96b6fc351c1f4b3ed7a76d01c.zip
Check
-rw-r--r--grammar.txt12
-rw-r--r--src/main.rs173
2 files changed, 109 insertions, 76 deletions
diff --git a/grammar.txt b/grammar.txt
index ec9fa9c..f3de822 100644
--- a/grammar.txt
+++ b/grammar.txt
@@ -2,7 +2,17 @@ let x = 2;
y = 3; in
(x y)
-let x: (Int) =
+// If all functions are curried, can I do something like this?
+let f: (((Int) -> (Int)) -> Int) = [a, b, c = (((if 1) a) b)] { (plus ((plus a) b) c) }; in
+
+let x: (Int);
+ y: (Int) = { x };
+ z = x; in
+ x = 2
+ y()
+
+
+
let y: (Int) = { x }; in
y;
y: (Int) = 3;
diff --git a/src/main.rs b/src/main.rs
index 5018b43..660a835 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -120,12 +120,12 @@ type Identifier = String;
struct Binding {
name: Identifier,
- arg_type: Option<Box<TypeDeclaration>>,
+ arg_type: Option<Box<TypeDeclaration>>, // TODO: Gradual typing!
}
-struct TypeDeclaration {
- base_type: Option<Identifier>,
- arrow: Option<Box<(TypeDeclaration, TypeDeclaration)>>,
+enum TypeDeclaration {
+ BaseType(Identifier),
+ Arrow(Box<(TypeDeclaration, TypeDeclaration)>),
}
struct Assignment {
@@ -133,34 +133,26 @@ struct Assignment {
computation: Computation,
}
-struct Arguments {
- args_list: Vec<Identifier>,
-}
-
struct Abstraction {
- arguments: Arguments,
+ arguments: Vec<Binding>,
body: Box<Computation>,
}
struct Application {
- apply: Option<(Box<Computation>, Box<Computation>)>,
-}
-
-struct Computation {
- application: Option<Application>,
- abstraction: Option<Abstraction>,
- identifier: Option<Identifier>,
+ apply: Box<(Computation, Computation)>,
}
-struct LetStatement {
- assignments: Vec<Assignment>,
+enum Computation {
+ Application(Application),
+ Abstraction(Abstraction),
+ Identifier(Identifier),
+ LetStatement(LetStatement), // TODO: I think we can flatten these to just a long Abstraction
}
enum ASTNode {
Binding(Binding),
TypeDeclaration(TypeDeclaration),
Assignment(Assignment),
- Arguments(Arguments),
Abstraction(Abstraction),
Application(Application),
Computation(Computation),
@@ -179,8 +171,11 @@ enum ParsingFailure {
}
impl Parser {
- fn peek(&mut self) -> Option<&Token> {
- return self.tokens.get(self.position + 1);
+ fn peek(&mut self) -> Result<&Token, ParsingFailure> {
+ return self
+ .tokens
+ .get(self.position + 1)
+ .ok_or(ParsingFailure::PastTokens);
}
fn consume_if_and_map<T>(
@@ -194,7 +189,7 @@ impl Parser {
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::Ok(val.unwrap());
}
return Result::Err(ParsingFailure::Blame(self.tokens[self.position].blame, msg));
}
@@ -221,71 +216,100 @@ impl Parser {
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"),
- ));
- }
+ let name = 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"),
+ )?;
+
+ 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: None,
+ 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)
+ let binding = self.parse_binding()?;
+ let _ = self.consume_if_match(
+ |it| (*it).token == TokenType::Equals,
+ String::from("Expected equals after binding"),
+ )?;
+
+ return Ok(Assignment {
+ binding,
+ computation: self.parse_computation()?,
+ });
}
- fn parse_let_statement(&mut self) -> Result<&LetStatement, ParsingFailure> {
+ fn parse_let_statement(&mut self) -> Result<LetStatement, ParsingFailure> {
self.consume_if_match_nomsg(|it| (*it).token == TokenType::Identifier(String::from("let")));
+ let mut assignments: Vec<Assignment> = Vec::new();
+ loop {
+ if let Ok(_done) = self.consume_if_match_nomsg(|it| {
+ (*it).token == TokenType::Identifier(String::from("in"))
+ }) {
+ let body = self.parse_computation()?;
+
+ return Ok(LetStatement { assignments });
+ }
+ let assignment = self.parse_assignment()?;
+ self.consume_if_match_nomsg(|it| (*it).token == TokenType::Semicolon)?;
+ assignments.push(assignment);
+ }
+ }
- let assignments: Vec<&Assignment> = Vec::new();
- let assignment = self.parse_assignment();
- self.consume_if_match_nomsg(|it| (*it).token == TokenType::Semicolon);
+ fn parse_abstraction(&mut self) -> Result<Abstraction, ParsingFailure> {
+ self.consume_if_match_nomsg(|it| (*it).token == TokenType::Lbracket)?;
+ let mut arguments: Vec<Binding> = Vec::new();
+ loop {
+ if let Ok(_done) = self.consume_if_match_nomsg(|it| (*it).token == TokenType::Rbracket)
+ {
+ return Ok(Abstraction {
+ arguments,
+ body: Box::new(self.parse_computation()?),
+ });
+ }
+ arguments.push(self.parse_binding()?);
+ self.consume_if_match_nomsg(|it| (*it).token == TokenType::Comma);
+ }
}
- fn parse(&mut self) -> Result<ASTNode, ParsingFailure> {
- let consume = |args| {};
+ fn parse_application(&mut self) -> Result<Application, ParsingFailure> {
+ self.consume_if_match_nomsg(|it| (*it).token == TokenType::Lparen)?;
+ let left = self.parse_computation()?;
+ let right = self.parse_computation()?;
+ self.consume_if_match_nomsg(|it| (*it).token == TokenType::Rparen)?;
+ return Ok(Application {
+ apply: Box::new((left, right)),
+ });
+ }
- // let program: LetStatement = self.parseLetStatement();
+ fn parse_computation(&mut self) -> Result<Computation, ParsingFailure> {
+ let next = *(self.peek()?);
+ match next.token {
+ TokenType::Identifier(identifier) => {
+ Computation::LetStatement(self.parse_let_statement()?)
+ }
+ TokenType::Lbrace => Computation::Abstraction(self.parse_abstraction()?),
+ TokenType::Lparen => Computation::Application(self.parse_application()?),
+ };
}
fn new(tokens: Vec<Token>) -> Parser {
@@ -293,7 +317,6 @@ impl Parser {
position: 0,
tokens,
};
-
}
// fn new() -> Parser {}
}