summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorElizabeth Alexander Hunt <me@liz.coffee>2026-08-03 09:18:06 -0700
committerElizabeth Alexander Hunt <me@liz.coffee>2026-08-03 09:18:06 -0700
commitfc2844ae88c85f082b47630b92a55bca3ff285b1 (patch)
tree4a6cca7892459ece38bf72b61352d4fc1bb239e0 /src/main.rs
downloadgock-fc2844ae88c85f082b47630b92a55bca3ff285b1.tar.gz
gock-fc2844ae88c85f082b47630b92a55bca3ff285b1.zip
Init
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..7ec318a
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,190 @@
+#[derive(Debug, Clone, PartialEq)]
+enum TokenType {
+ Lparen,
+ Rparen,
+ Lbrace,
+ Rbrace,
+ Lbracket,
+ Rbracket,
+ Colon,
+ Identifier(String),
+ Eof,
+}
+
+#[derive(Debug, Clone, Copy)]
+struct Blame {
+ line: usize,
+ char: usize,
+}
+
+#[derive(Debug)]
+struct Token {
+ token: TokenType,
+ blame: Blame,
+}
+
+struct Lexer;
+
+impl Lexer {
+ pub fn analyze(program: &str) -> Vec<Token> {
+ let mut tokens: Vec<Token> = program
+ .lines()
+ .enumerate()
+ .flat_map(|(line, text)| Self::lex_line(line, text))
+ .collect();
+
+ tokens.push(Token {
+ token: TokenType::Eof,
+ blame: Blame {
+ line: tokens.len(),
+ char: 0,
+ },
+ });
+ tokens
+ }
+
+ fn lex_line(line: usize, text: &str) -> Vec<Token> {
+ let mut tokens = Vec::new();
+ let mut ident_start: Option<usize> = None;
+
+ let flush = |tokens: &mut Vec<Token>, ident_start: &mut Option<usize>, end: usize| {
+ if let Some(start) = ident_start.take() {
+ if end > start {
+ tokens.push(Token {
+ token: TokenType::Identifier(text[start..end].to_string()),
+ blame: Blame { line, char: start },
+ });
+ }
+ }
+ };
+
+ for (i, c) in text.char_indices() {
+ let singlechar = match c {
+ '(' => Some(TokenType::Lparen),
+ ')' => Some(TokenType::Rparen),
+ '[' => Some(TokenType::Lbracket),
+ ']' => Some(TokenType::Rbracket),
+ '{' => Some(TokenType::Lbrace),
+ '}' => Some(TokenType::Rbrace),
+ ':' => Some(TokenType::Colon),
+ _ => None,
+ };
+
+ if c == ' ' || c == '\t' {
+ flush(&mut tokens, &mut ident_start, i);
+ continue;
+ }
+
+ if let Some(tt) = singlechar {
+ flush(&mut tokens, &mut ident_start, i);
+ tokens.push(Token {
+ token: tt,
+ blame: Blame { line, char: i },
+ });
+ continue;
+ }
+
+ if ident_start.is_none() {
+ ident_start = Some(i);
+ }
+ }
+
+ flush(&mut tokens, &mut ident_start, text.len());
+ tokens
+ }
+}
+
+enum Atomic {
+ Unit,
+ Bool,
+ Int,
+}
+
+enum SimpleType {
+ Arrow((Box<SimpleType>, Box<SimpleType>)),
+ Atom(Atomic),
+}
+
+type Identifier = String;
+
+struct Binding {
+ name: Identifier,
+ arg_type: Option<SimpleType>,
+}
+
+enum ASTNode {
+ Abstraction {
+ binding: Binding,
+ body: Box<ASTNode>,
+ },
+ Application((Box<ASTNode>, Box<ASTNode>)),
+ Identifier(Identifier),
+}
+
+pub enum StepResult<T> {
+ Terminal(T),
+ Continue,
+}
+
+pub trait Steppable<T> {
+ fn small_step(&mut self) -> StepResult<T>;
+}
+
+pub struct Environment<'a, T> {
+ parent_scope: Option<&'a Environment<'a, T>>,
+ capture: Identifier,
+ substitution: &'a T,
+}
+
+impl<T> Environment<'_, T> {
+ fn add<'a>(&'a self, identifier: Identifier, substitution: &'a T) -> Environment<'a, T> {
+ return Environment {
+ parent_scope: Some(&self),
+ capture: identifier,
+ substitution: substitution,
+ };
+ }
+
+ fn get<'a>(&'a self, identifier: Identifier) -> Option<&'a T> {
+ if *identifier == *(self.capture) {
+ return Some(self.substitution);
+ }
+ return match self.parent_scope {
+ Some(scope) => (*scope).get(identifier),
+ None => None,
+ };
+ }
+
+ fn root<'a>(identifier: Identifier, substitution: &'a T) -> Environment<'a, T> {
+ return Environment {
+ parent_scope: None,
+ capture: identifier,
+ substitution: substitution,
+ };
+ }
+}
+
+fn main() {
+ println!("Hello, world!");
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ #[test]
+ fn test_env() {
+ let ident = Identifier::from("ident");
+ let ident2 = Identifier::from("ident2");
+ let val: i32 = 1;
+ let val2: i32 = 2;
+ let val3: i32 = 3;
+ 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));
+ 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));
+ }
+}