summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs255
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();
+ }
}