diff --git a/src/ast_compiler.rs b/src/ast_compiler.rs index d09555b..fd16802 100644 --- a/src/ast_compiler.rs +++ b/src/ast_compiler.rs @@ -14,9 +14,9 @@ use crate::tokens::TokenType::{ }; use crate::tokens::{Token, TokenType}; use crate::value::Value; +use crate::{Expr, Stmt, SymbolTable}; use log::debug; use std::collections::HashMap; -use crate::{Expr, Stmt, SymbolTable}; pub fn compile( path: Option<&str>, @@ -109,7 +109,7 @@ impl AstCompiler { Err(self.raise(UnexpectedIndent(indent_on_line, expected_indent))) } else if indent_on_line < expected_indent { self.indent.pop(); - return Ok(None); + Ok(None) } else { Ok(Some(self.declaration(symbol_table)?)) } @@ -139,13 +139,13 @@ impl AstCompiler { } fn guard_if_expr(&mut self, symbol_table: &mut SymbolTable) -> Expr { - while !self.check(&SingleRightArrow) { - if self.match_token(&[Slash]) { - return self.path_guard_expr(); + if !self.check(&SingleRightArrow) { + return if self.match_token(&[Slash]) { + self.path_guard_expr() } else if self.match_token(&[TokenType::Question]) { - return self.query_guard_expr(symbol_table); + self.query_guard_expr(symbol_table) } else { - return Err(self.raise(Expected("-> or ?"))); + Err(self.raise(Expected("-> or ?"))) } } Ok(Stop { @@ -408,7 +408,7 @@ impl AstCompiler { mut expr: Expression, symbol_table: &mut SymbolTable, ) -> Expr { - while self.match_token(&types) { + while self.match_token(types) { let operator = self.previous().clone(); let right = self.comparison(symbol_table)?; expr = Expression::Binary { @@ -431,8 +431,7 @@ impl AstCompiler { right: Box::new(right), }) } else { - let expr = self.get(symbol_table); - expr + self.get(symbol_table) } } @@ -541,7 +540,7 @@ impl AstCompiler { line: self.peek().line, literaltype: Integer, value: Value::U32( - u32::from_str_radix(&self.previous().lexeme.trim_start_matches("0x"), 16) + u32::from_str_radix(self.previous().lexeme.trim_start_matches("0x"), 16) .map_err(|e| self.raise(ParseError(format!("{:?}", e))))?, ), } @@ -550,7 +549,7 @@ impl AstCompiler { line: self.peek().line, literaltype: Integer, value: Value::U64( - u64::from_str_radix(&self.previous().lexeme.trim_start_matches("0x"), 16) + u64::from_str_radix(self.previous().lexeme.trim_start_matches("0x"), 16) .map_err(|e| self.raise(ParseError(format!("{:?}", e))))?, ), } @@ -747,7 +746,7 @@ impl AstCompiler { if !self.is_at_end() { self.current += 1; } - &self.previous() + self.previous() } fn is_at_end(&self) -> bool { diff --git a/src/builtins/builtin_functions.rs b/src/builtins/builtin_functions.rs deleted file mode 100644 index 7851127..0000000 --- a/src/builtins/builtin_functions.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::value::Value; -use std::collections::HashMap; -use std::sync::LazyLock; -use crate::builtins::string::string_methods; -use crate::errors::RuntimeError; - -pub(crate) type MethodFn = fn(Value, Vec) -> Result; -pub(crate) type MethodMap = HashMap; -pub(crate) type MethodTable = HashMap; - -const METHODS: LazyLock = LazyLock::new(|| { - let mut table: MethodTable = HashMap::new(); - table.insert("string".to_string(), string_methods()); - table -}); - -pub(crate) fn insert(m: &mut MethodMap, name: &str, method: MethodFn) { - m.insert(name.to_string(), method); -} - -pub fn call_builtin( - type_name: &str, - method_name: &str, - self_val: Value, - args: Vec, -) -> Result { - METHODS - .get(type_name) - .and_then(|methods| methods.get(method_name)) - .ok_or_else(|| RuntimeError::FunctionNotFound(format!("{}.{}",type_name, method_name)))? - (self_val, args) -} - diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 5d47111..7a80f53 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -1,2 +1,35 @@ -pub mod builtin_functions; -mod string; \ No newline at end of file +mod string; + +use crate::value::Value; +use std::collections::HashMap; +use std::sync::LazyLock; +use crate::builtins::string::string_methods; +use crate::errors::RuntimeError; + +pub(crate) type MethodFn = fn(Value, Vec) -> Result; +pub(crate) type MethodMap = HashMap; +pub(crate) type MethodTable = HashMap; + +static METHODS: LazyLock = LazyLock::new(|| { + let mut table: MethodTable = HashMap::new(); + table.insert("string".to_string(), string_methods()); + table +}); + +pub(crate) fn insert(m: &mut MethodMap, name: &str, method: MethodFn) { + m.insert(name.to_string(), method); +} + +pub fn call( + type_name: &str, + method_name: &str, + self_val: Value, + args: Vec, +) -> Result { + METHODS + .get(type_name) + .and_then(|methods| methods.get(method_name)) + .ok_or_else(|| RuntimeError::FunctionNotFound(format!("{}.{}",type_name, method_name)))? + (self_val, args) +} + diff --git a/src/builtins/string.rs b/src/builtins/string.rs index a036576..0914f08 100644 --- a/src/builtins/string.rs +++ b/src/builtins/string.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use crate::builtins::builtin_functions::{insert, MethodMap}; +use crate::builtins::{insert, MethodMap}; use crate::errors::RuntimeError; use crate::value::Value; diff --git a/src/bytecode_compiler.rs b/src/bytecode_compiler.rs index a009896..577f9d9 100644 --- a/src/bytecode_compiler.rs +++ b/src/bytecode_compiler.rs @@ -168,7 +168,7 @@ impl Compiler { } => { let name_index = self .chunk - .find_constant(&name) + .find_constant(name) .unwrap_or_else(|| self.chunk.add_constant(Value::String(name.to_string()))); let function = symbols.get(name); match function { @@ -207,7 +207,7 @@ impl Compiler { .find_constant(&receiver_type) .unwrap_or_else(|| self.chunk.add_constant(Value::String(receiver_type))); - let name_index = self.chunk.find_constant(&method_name).unwrap_or_else(|| { + let name_index = self.chunk.find_constant(method_name).unwrap_or_else(|| { self.chunk .add_constant(Value::String(method_name.to_string())) }); diff --git a/src/chunk.rs b/src/chunk.rs index 4c3a98d..01bc33a 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -1,13 +1,13 @@ -use std::collections::HashMap; use crate::ast_compiler::Parameter; use crate::tokens::TokenType; use crate::value::Value; use crate::vm::{ OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_F32, - OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_STRING, OP_DEFINE, OP_DIVIDE, OP_EQUAL, - OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_NEGATE, OP_NOT, - OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, OP_DEF_MAP, + OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_MAP, OP_DEF_STRING, OP_DEFINE, + OP_DIVIDE, OP_EQUAL, OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, + OP_NEGATE, OP_NOT, OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, }; +use std::collections::HashMap; #[derive(Debug, Clone)] pub struct Chunk { @@ -17,16 +17,16 @@ pub struct Chunk { lines: Vec, pub(crate) object_defs: HashMap>, pub(crate) function_parameters: Vec, - pub vars: Vec<(TokenType, String)> + pub vars: Vec<(TokenType, String)>, } impl Chunk { pub(crate) fn find_constant(&self, p0: &String) -> Option { for (i, constant) in self.constants.iter().enumerate() { - if let Value::String(s) = constant { - if s == p0 { - return Some(i); - } + if let Value::String(s) = constant + && s == p0 + { + return Some(i); } } None @@ -42,7 +42,7 @@ impl Chunk { lines: vec![], object_defs: HashMap::new(), function_parameters: vec![], - vars: vec![] + vars: vec![], } } @@ -61,7 +61,7 @@ impl Chunk { self.vars.len() - 1 } - pub (crate) fn add_object_def(&mut self, name: &str, fields: &[Parameter]){ + pub(crate) fn add_object_def(&mut self, name: &str, fields: &[Parameter]) { self.object_defs.insert(name.to_string(), fields.to_vec()); } diff --git a/src/file_watch.rs b/src/file_watch.rs index fbe5971..e2cc1f0 100644 --- a/src/file_watch.rs +++ b/src/file_watch.rs @@ -36,7 +36,7 @@ pub fn start_watch_daemon(source: &str, registry: Arc ONE_SEC { diff --git a/src/lib.rs b/src/lib.rs index 719846e..a6237ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,12 +4,8 @@ use crate::errors::CrudLangError::Platform; use crate::errors::{CompilerErrorAtLine, CrudLangError}; use crate::scanner::scan; use crate::symbol_builder::Symbol; -use crate::value::Value; -use crate::vm::interpret; -use arc_swap::ArcSwap; use std::collections::HashMap; use std::fs; -use std::sync::Arc; use walkdir::WalkDir; pub mod ast_compiler; @@ -89,13 +85,13 @@ pub fn compile(src: &str) -> Result, CrudLangError> { } #[cfg(test)] -pub(crate) fn run(src: &str) -> Result { - let tokens = scan(src)?; - let mut symbol_table = HashMap::new(); - let ast = ast_compiler::compile(None, tokens, &mut symbol_table)?; - symbol_builder::build("", &ast, &mut symbol_table); - let mut registry = HashMap::new(); - bytecode_compiler::compile(None, &ast, &symbol_table, &mut registry)?; - let registry = ArcSwap::from(Arc::new(registry)); - interpret(registry.load(), "main").map_err(CrudLangError::from) +pub(crate) fn run(src: &str) -> Result { + let tokens = scan(src)?; + let mut symbol_table = HashMap::new(); + let ast = ast_compiler::compile(None, tokens, &mut symbol_table)?; + symbol_builder::build("", &ast, &mut symbol_table); + let mut registry = HashMap::new(); + bytecode_compiler::compile(None, &ast, &symbol_table, &mut registry)?; + let registry = arc_swap::ArcSwap::from(std::sync::Arc::new(registry)); + vm::interpret(registry.load(), "main").map_err(CrudLangError::from) } diff --git a/src/main.rs b/src/main.rs index db2e12f..e457c1a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,14 +5,12 @@ use axum::{Json, Router}; use clap::Parser; use crudlang::chunk::Chunk; use crudlang::errors::CrudLangError; -use crudlang::errors::CrudLangError::Platform; use crudlang::vm::interpret_async; use crudlang::{compile_sourcedir, map_underlying}; -use notify::Watcher; use std::collections::HashMap; use std::sync::Arc; use arc_swap::ArcSwap; -use log::{debug, info}; +use log::info; /// A simple CLI tool to greet users #[derive(Parser, Debug)] diff --git a/src/repl.rs b/src/repl.rs index 480c693..bf888c1 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -27,7 +27,7 @@ pub fn start(registry: Arc>>) -> Result<(), CrudL _ => { let registry_copy = registry.load().clone(); let mut registry_copy = registry_copy.deref().clone(); - match recompile(&input, &mut registry_copy){ + match recompile(input, &mut registry_copy){ Ok(_)=> { registry.store(Arc::new(registry_copy)); diff --git a/src/scanner.rs b/src/scanner.rs index f44fe29..57340ac 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -141,7 +141,7 @@ impl Scanner { _ => { if c == '0' && self.peek() == 'x' { self.hex_number()?; - } else if is_digit(c) { + } else if c.is_ascii_digit() { self.number(); } else if is_alpha(c) { self.identifier(); @@ -167,7 +167,7 @@ impl Scanner { fn hex_number(&mut self) -> Result<(), CompilerErrorAtLine> { self.advance(); self.advance(); - while is_digit(self.peek()) || is_alpha(self.peek()) { + while self.peek().is_ascii_hexdigit() { self.advance(); } let value: String = self.chars[self.start..self.current].iter().collect(); @@ -182,11 +182,11 @@ impl Scanner { } fn number(&mut self) { - while is_digit(self.peek()) { + while self.peek().is_ascii_digit() { self.advance(); } let mut has_dot = false; - if self.peek() == '.' && is_digit(self.peek_next()) { + if self.peek() == '.' && self.peek_next().is_ascii_digit() { has_dot = true; self.advance(); } @@ -269,9 +269,7 @@ impl Scanner { } fn match_next(&mut self, expected: char) -> bool { - if self.is_at_end() { - false - } else if self.chars[self.current] != expected { + if self.is_at_end() || self.chars[self.current] != expected{ false } else { self.current += 1; @@ -306,20 +304,19 @@ struct Scanner { new_line: bool, } -fn is_digit(c: char) -> bool { - c >= '0' && c <= '9' -} fn is_digit_or_scientific(c: char) -> bool { - is_digit(c) || c == 'e' || c == 'E' + c.is_ascii_digit() || c == 'e' || c == 'E' } fn is_alphanumeric(c: char) -> bool { - is_alpha(c) || is_digit(c) + is_alpha(c) || c.is_ascii_digit() } fn is_alpha(c: char) -> bool { - (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$' + // (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$' + // ('a'..='z').contains(&c) || ('A'..='Z').contains(&c) || c == '_' || c == '$' + c.is_ascii_lowercase() || c.is_ascii_uppercase() || c == '_' || c == '$' } #[cfg(test)] diff --git a/src/symbol_builder.rs b/src/symbol_builder.rs index abda27a..7d9d617 100644 --- a/src/symbol_builder.rs +++ b/src/symbol_builder.rs @@ -70,31 +70,6 @@ pub fn build(path: &str, ast: &[Statement], symbols: &mut HashMap, -) -> Result<(), CompilerError> { - for statement in ast { - match statement { - Statement::VarStmt { - name, - var_type, - initializer, - } => { - let inferred_type = infer_type(initializer, symbols); - let calculated_type = calculate_type(var_type, &inferred_type)?; - let entry = symbols.get_mut(&format!("{}.{}", path, name.lexeme)); - if let Some(Symbol::Variable { var_type, .. }) = entry { - *var_type = calculated_type; - } - } - _ => {} - } - } - Ok(()) -} - pub fn calculate_type( declared_type: &TokenType, inferred_type: &TokenType, @@ -157,42 +132,40 @@ pub fn infer_type(expr: &Expression, symbols: &HashMap) -> Token Integer => I64, _ => left_type, } + } else if let Plus = operator.token_type { + // includes string concatenation with numbers + // followed by type coercion to 64 bits for numeric types + debug!("coerce {} : {}", left_type, right_type); + match (left_type, right_type) { + (_, StringType) => StringType, + (StringType, _) => StringType, + (FloatingPoint, _) => F64, + (Integer, FloatingPoint) => F64, + (Integer, _) => I64, + (I64, Integer) => I64, + (F64, _) => F64, + (U64, U32) => U64, + (I64, I32) => I64, + // could add a date and a duration. future work + // could add a List and a value. also future work + // could add a Map and a tuple. Will I add tuple types? Future work! + _ => panic!("Unexpected coercion"), + } + // could have done some fall through here, but this will fail less gracefully, + // so if my thinking is wrong or incomplete it will panic } else { - if let Plus = operator.token_type { - // includes string concatenation with numbers - // followed by type coercion to 64 bits for numeric types - debug!("coerce {} : {}", left_type, right_type); - match (left_type, right_type) { - (_, StringType) => StringType, - (StringType, _) => StringType, - (FloatingPoint, _) => F64, - (Integer, FloatingPoint) => F64, - (Integer, _) => I64, - (I64, Integer) => I64, - (F64, _) => F64, - (U64, U32) => U64, - (I64, I32) => I64, - // could add a date and a duration. future work - // could add a List and a value. also future work - // could add a Map and a tuple. Will I add tuple types? Future work! - _ => panic!("Unexpected coercion"), - } - // could have done some fall through here, but this will fail less gracefully, - // so if my thinking is wrong or incomplete it will panic - } else { - // type coercion to 64 bits for numeric types - debug!("coerce {} : {}", left_type, right_type); - match (left_type, right_type) { - (FloatingPoint, _) => F64, - (Integer, FloatingPoint) => F64, - (Integer, I64) => I64, - (I64, FloatingPoint) => F64, - (F64, _) => F64, - (U64, U32) => U64, - (I64, I32) => I64, - (I64, Integer) => I64, - _ => panic!("Unexpected coercion"), - } + // type coercion to 64 bits for numeric types + debug!("coerce {} : {}", left_type, right_type); + match (left_type, right_type) { + (FloatingPoint, _) => F64, + (Integer, FloatingPoint) => F64, + (Integer, I64) => I64, + (I64, FloatingPoint) => F64, + (F64, _) => F64, + (U64, U32) => U64, + (I64, I32) => I64, + (I64, Integer) => I64, + _ => panic!("Unexpected coercion"), } } } diff --git a/src/vm.rs b/src/vm.rs index 077d146..78b315a 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -7,7 +7,6 @@ use arc_swap::Guard; use std::collections::HashMap; use std::sync::Arc; use tracing::debug; -use crate::builtins::builtin_functions::call_builtin; pub struct Vm { ip: usize, @@ -206,17 +205,14 @@ impl Vm { let receiver_type_name = chunk.constants[function_type_index].to_string(); let receiver = self.pop(); - let num_args = self.read(chunk); - let mut args = vec![]; for _ in 0..num_args { let arg = self.pop(); args.push(arg); } args.reverse(); - - let return_value = call_builtin(&receiver_type_name, &function_name, receiver, args)?; + let return_value = crate::builtins::call(&receiver_type_name, &function_name, receiver, args)?; self.push(return_value); } OP_CALL => {