From f839283edd65e32d2b89ab4c0b0d1e9bbe27c953 Mon Sep 17 00:00:00 2001 From: Aaro Koivukangas Date: Thu, 29 Jan 2026 14:54:14 +0200 Subject: [PATCH] Remove rust, embrace scala --- Dockerfile | 19 -- compiler/Cargo.lock | 75 ------ compiler/Cargo.toml | 10 - compiler/src/compiler/mod.rs | 8 - compiler/src/compiler/parser.rs | 31 --- compiler/src/compiler/tokenizer.rs | 351 ----------------------------- compiler/src/main.rs | 88 -------- 7 files changed, 582 deletions(-) delete mode 100644 Dockerfile delete mode 100644 compiler/Cargo.lock delete mode 100644 compiler/Cargo.toml delete mode 100644 compiler/src/compiler/mod.rs delete mode 100644 compiler/src/compiler/parser.rs delete mode 100644 compiler/src/compiler/tokenizer.rs delete mode 100644 compiler/src/main.rs diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 12f9717..0000000 --- a/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM rust:slim AS builder - -WORKDIR /app -COPY . . -WORKDIR /app/compiler - -RUN cargo build --release - -CMD ["cargo", "run", "--release"] - - -FROM debian:12-slim AS runner - -WORKDIR /app -COPY --from=builder /app/compiler/target/release/compiler . - -EXPOSE 3000 - -CMD ["./compiler", "serve", "''"] diff --git a/compiler/Cargo.lock b/compiler/Cargo.lock deleted file mode 100644 index 23e93a8..0000000 --- a/compiler/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "compiler" -version = "0.1.0" -dependencies = [ - "base64", - "json", - "lazy_static", - "regex", -] - -[[package]] -name = "json" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "regex" -version = "1.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml deleted file mode 100644 index d083abb..0000000 --- a/compiler/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "compiler" -version = "0.1.0" -edition = "2024" - -[dependencies] -base64 = "0.22.1" -json = "0.12.4" -lazy_static = "1.5.0" -regex = "1.12.2" diff --git a/compiler/src/compiler/mod.rs b/compiler/src/compiler/mod.rs deleted file mode 100644 index 20a111e..0000000 --- a/compiler/src/compiler/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod parser; -pub mod tokenizer; - -pub fn compile(code: &str) -> &str { - tokenizer::tokenizer(code); - println!("Code: {}", &code); - return code; -} diff --git a/compiler/src/compiler/parser.rs b/compiler/src/compiler/parser.rs deleted file mode 100644 index d005ee6..0000000 --- a/compiler/src/compiler/parser.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::compiler::tokenizer::Token; - -/* -* 1. Create structs for all token types -* 2. Make parse-function for ecah token types -* 3. General parse function -* 4. ??? -* 5. Profit -*/ - -enum ExpressionType { - IntLiteral, - Identifier, - BinaryOperator, -} - -// T should be equal to ExpressionType -struct Expression { - expr_type: ExpressionType, - value: T, -} - -struct BinaryOperator<'a, T, K> { - left: T, - right: K, - operator: &'a str, -} - -pub fn parser(tokens: Vec) { - return; -} diff --git a/compiler/src/compiler/tokenizer.rs b/compiler/src/compiler/tokenizer.rs deleted file mode 100644 index 4c4b8d5..0000000 --- a/compiler/src/compiler/tokenizer.rs +++ /dev/null @@ -1,351 +0,0 @@ -use lazy_static::lazy_static; -use regex::Regex; - -const WHITESPACE_REGEX_STR: &str = r"(\n|\r\n|\r|\\n|\ )"; -const COMMENT_REGEX_STR: &str = r"((\#|\/\/).*)"; -const SINGLE_CHAR_OPERATOR_STR: &str = r"([+\-\/*%])"; -const PUNCTUATION_STR: &str = r"([(){},;:])"; -const MULTICHAR_OPERATOR_STR: &str = r"([<>=!]=?)"; -const NUMBER_LITERAL_STR: &str = r"([0-9]+)"; -const IDENTIFIER_STR: &str = r"([a-zA-Z_][a-zA-Z_0-9]*)"; - -// TODO: implement the whole tokenizer without regex -lazy_static! { - // Damn, regex... - static ref TOKEN_RE: Regex = Regex::new(format!(r#"{WHITESPACE_REGEX_STR}|{COMMENT_REGEX_STR}|{PUNCTUATION_STR}|{SINGLE_CHAR_OPERATOR_STR}|{MULTICHAR_OPERATOR_STR}|{NUMBER_LITERAL_STR}|{IDENTIFIER_STR}"#).as_str()).unwrap(); - static ref WHITESPACE_RE: Regex = Regex::new(format!(r#"{WHITESPACE_REGEX_STR}"#).as_str()).unwrap(); - static ref OPERATOR_RE: Regex = Regex::new(format!(r#"{SINGLE_CHAR_OPERATOR_STR}|{MULTICHAR_OPERATOR_STR}"#).as_str()).unwrap(); - static ref PUNCTUATION_RE: Regex = Regex::new(format!(r#"{PUNCTUATION_STR}"#).as_str()).unwrap(); - static ref IDENTIFIER_RE: Regex = Regex::new(format!(r#"{IDENTIFIER_STR}"#).as_str()).unwrap(); -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct TokenLocation { - line: u64, - column: u64, -} - -pub struct DebugTokenLocation {} - -#[derive(Debug, PartialEq, Eq)] -pub enum TokenType { - Whitespace, - Comment, - Identifier, - IntLiteral, - Operator, - Punctuation, - Other, -} - -#[derive(Debug, Eq)] -pub struct Token<'a> { - location: TokenLocation, // TODO: Add DebugTokenLocation as an option for type - token_type: TokenType, - value: &'a str, -} - -// TODO: If Token.location is typeof DebugTokenLocation => return true; -// Helps with testing -impl<'a> PartialEq for Token<'a> { - fn eq(&self, other: &Token) -> bool { - // if (self.location == DebugTokenLocation || other.location == DebugTokenLocation) { - // return true; - // } - - if self.location == other.location - && self.value == other.value - && self.token_type == other.token_type - { - return true; - } - - return false; - } -} - -fn is_whitespace(token: &str) -> bool { - return WHITESPACE_RE.is_match(token); -} - -fn is_integer_literal(token: &str) -> bool { - return token.parse::().is_ok(); -} - -fn is_comment(token: &str) -> bool { - return token.starts_with("#") || token.starts_with("//"); -} - -// Whitespace, -// Comment, -// Identifier, -// IntLiteral, -// Operator, -// Punctuation, -// Other, - -fn is_operator(token: &str) -> bool { - return OPERATOR_RE.is_match(token); -} - -fn is_punctuation(token: &str) -> bool { - return PUNCTUATION_RE.is_match(token); -} - -fn is_identifier(token: &str) -> bool { - return IDENTIFIER_RE.is_match(token); -} - -fn parse_token_type(token: &str) -> TokenType { - if is_whitespace(token) { - return TokenType::Whitespace; - } - if is_integer_literal(token) { - return TokenType::IntLiteral; - } - if is_comment(token) { - return TokenType::Comment; - } - if is_operator(token) { - return TokenType::Operator; - } - if is_punctuation(token) { - return TokenType::Punctuation; - } - if is_identifier(token) { - return TokenType::Identifier; - } - return TokenType::Other; -} - -pub fn tokenizer(code: &str) -> Vec> { - println!("Doing regex things for {:?}", code); - - let mut tokens_vec: Vec = vec![]; - let mut current_pos = TokenLocation { column: 0, line: 0 }; - for mat in TOKEN_RE.find_iter(code) { - println!(); - let token = mat.as_str(); - if is_whitespace(token) { - match token { - "\n" | "\r\n" | "\r" => { - current_pos.column = 0; - current_pos.line += 1; - } - // This type cast can fail/truncate on 128-bit machines, still waiting for those :D - _ => current_pos.column += token.len() as u64, - } - continue; - } - - // Same as above about 128-bit machines - current_pos.column += token.len() as u64; - - let token_pos = current_pos; - let token_type = parse_token_type(token); - - let token_obj = Token { - location: token_pos, - token_type: token_type, - value: token, - }; - - tokens_vec.push(token_obj); - } - - let tokens: Vec<&str> = TOKEN_RE - .find_iter(code) - .map(|mat| { - // Add line number and location to token - let token = mat.as_str(); - println!("{token}"); - token - }) - .collect(); - println!("{tokens:?}"); - println!("{tokens_vec:?}"); - return tokens_vec; -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn single_integer_literals() { - let code = "143"; - let result = [Token { - location: TokenLocation { column: 3, line: 0 }, - token_type: TokenType::IntLiteral, - value: "143", - }]; - assert_eq!(tokenizer(code)[0], result[0]); - } - #[test] - fn multiple_integer_literals() { - let code = "532 125390"; - let result = [ - Token { - location: TokenLocation { column: 3, line: 0 }, - token_type: TokenType::IntLiteral, - value: "532", - }, - Token { - location: TokenLocation { - column: 10, - line: 0, - }, - token_type: TokenType::IntLiteral, - value: "125390", - }, - ]; - assert_eq!(tokenizer(code), result); - } - - #[test] - fn integer_literals_with_newline() { - let code = "123 \n3210\n\n50"; - let result = [ - Token { - location: TokenLocation { column: 3, line: 0 }, - token_type: TokenType::IntLiteral, - value: "123", - }, - Token { - location: TokenLocation { column: 4, line: 1 }, - token_type: TokenType::IntLiteral, - value: "3210", - }, - Token { - location: TokenLocation { column: 2, line: 3 }, - token_type: TokenType::IntLiteral, - value: "50", - }, - ]; - - assert_eq!(tokenizer(code), result); - } - - #[test] - fn operator_token_matching() { - let code = "1 >= 0 +2"; - let result = vec![ - Token { - location: TokenLocation { column: 1, line: 0 }, - token_type: TokenType::IntLiteral, - value: "1", - }, - Token { - location: TokenLocation { column: 4, line: 0 }, - token_type: TokenType::Operator, - value: ">=", - }, - Token { - location: TokenLocation { column: 6, line: 0 }, - token_type: TokenType::IntLiteral, - value: "0", - }, - Token { - location: TokenLocation { column: 8, line: 0 }, - token_type: TokenType::Operator, - value: "+", - }, - Token { - location: TokenLocation { column: 9, line: 0 }, - token_type: TokenType::IntLiteral, - value: "2", - }, - ]; - assert_eq!(tokenizer(code), result); - } - - #[test] - fn punctuation_token_matching() { - let code = "{1+1}: 0()"; - let result = vec![ - Token { - location: TokenLocation { column: 1, line: 0 }, - token_type: TokenType::Punctuation, - value: "{", - }, - Token { - location: TokenLocation { column: 2, line: 0 }, - token_type: TokenType::IntLiteral, - value: "1", - }, - Token { - location: TokenLocation { column: 3, line: 0 }, - token_type: TokenType::Operator, - value: "+", - }, - Token { - location: TokenLocation { column: 4, line: 0 }, - token_type: TokenType::IntLiteral, - value: "1", - }, - Token { - location: TokenLocation { column: 5, line: 0 }, - token_type: TokenType::Punctuation, - value: "}", - }, - Token { - location: TokenLocation { column: 6, line: 0 }, - token_type: TokenType::Punctuation, - value: ":", - }, - Token { - location: TokenLocation { column: 8, line: 0 }, - token_type: TokenType::IntLiteral, - value: "0", - }, - Token { - location: TokenLocation { column: 9, line: 0 }, - token_type: TokenType::Punctuation, - value: "(", - }, - Token { - location: TokenLocation { - column: 10, - line: 0, - }, - token_type: TokenType::Punctuation, - value: ")", - }, - ]; - assert_eq!(tokenizer(code), result); - } - - #[test] - fn comment_hashtag() { - let code = "# This is a comment :)"; - assert_eq!(tokenizer(code).len(), 0); - } - #[test] - fn comment_div() { - let code = "// This is a comment :)"; - assert_eq!(tokenizer(code).len(), 0); - } - - #[test] - fn math_operators() { - let code = "1 + 2 * 5"; - let tokens: Vec<&str> = tokenizer(code).iter().map(|token| token.value).collect(); - let result: Vec<&str> = vec!["1", "+", "2", "*", "5"]; - assert_eq!(tokens, result); - } - #[test] - fn identifiers_with_whitespace() { - let code = "if 3\nwhile"; - let tokens: Vec<&str> = tokenizer(code).iter().map(|token| token.value).collect(); - let compare: Vec<&str> = vec!["if", "3", "while"]; - assert_eq!(tokens, compare); - } - - #[test] - fn more_complex_comxinations() { - let code = "if a <= bee then print_int(123)"; - let tokens: Vec<&str> = tokenizer(code).iter().map(|token| token.value).collect(); - let compare: Vec<&str> = vec!["if", "a", "<=", "bee", "then", "print_int", "(", "123", ")"]; - assert_eq!(tokens, compare); - } -} diff --git a/compiler/src/main.rs b/compiler/src/main.rs deleted file mode 100644 index bba5cf1..0000000 --- a/compiler/src/main.rs +++ /dev/null @@ -1,88 +0,0 @@ -use base64::prelude::*; -use std::env; -use std::{ - io::{BufReader, prelude::*}, - net::{TcpListener, TcpStream}, -}; - -pub mod compiler; - -const PORT: &str = "3000"; -const HOST: &str = "0.0.0.0"; - -fn main() { - let args: Vec<_> = env::args().collect(); - if args.len() <= 2 { - println!("Too few arguments, try either `compile` or `serve`"); - println!("If using serve, just add something random as 2nd argument :D"); - return; - } - - match args[1].as_str() { - "compile" => { - let executable = compiler::compile(args[2].as_str()); - println!("Executable: {}", executable); - } - "serve" => { - let address = format!("{}:{}", HOST, PORT); - let listener = TcpListener::bind(&address).unwrap(); - - println!("Starting server at address {}", address); - - for stream in listener.incoming() { - let stream = stream.unwrap(); - - handle_connection(stream); - } - } - _ => { - println!("Incorrect usage!"); - } - } -} - -fn handle_connection(mut stream: TcpStream) { - let buf_reader = BufReader::new(&stream); - let http_request: Vec<_> = buf_reader - .lines() - .map(|result| result.unwrap()) - .take_while(|line| !line.is_empty()) - .collect(); - - let body = http_request.last().unwrap(); - - if body.is_empty() { - eprintln!("Empty body!"); - let response = "HTTP/1.1 404 NOT FOUND"; - stream.write_all(response.as_bytes()).unwrap(); - return; - } - - let json = json::parse(body).unwrap(); - let command = json["command"].as_str().unwrap(); - - println!("Request: {http_request:#?}"); - // println!("Body: {json:#?}"); - println!("Command: {command:#?}"); - - match command { - "ping" => { - println!("Pong!"); - let response = "{}"; - stream.write_all(response.as_bytes()).unwrap(); - } - "compile" => { - let code = json["code"].as_str().unwrap(); - let executable = compiler::compile(code); - let content = BASE64_STANDARD.encode(executable); - - let response = format!("{{\"program\": \"{}\"}}", content.as_str()); - println!("Response: {:?}", response); - stream.write_all(response.as_bytes()).unwrap(); - } - _ => { - let response = "HTTP/1.1 404 NOT FOUND"; - stream.write_all(response.as_bytes()).unwrap(); - } - } -}