all clippys done

This commit is contained in:
Shautvast 2025-11-11 13:12:38 +01:00
parent 07b7dd0337
commit 0e919983bd
13 changed files with 117 additions and 158 deletions

View file

@ -14,9 +14,9 @@ use crate::tokens::TokenType::{
}; };
use crate::tokens::{Token, TokenType}; use crate::tokens::{Token, TokenType};
use crate::value::Value; use crate::value::Value;
use crate::{Expr, Stmt, SymbolTable};
use log::debug; use log::debug;
use std::collections::HashMap; use std::collections::HashMap;
use crate::{Expr, Stmt, SymbolTable};
pub fn compile( pub fn compile(
path: Option<&str>, path: Option<&str>,
@ -109,7 +109,7 @@ impl AstCompiler {
Err(self.raise(UnexpectedIndent(indent_on_line, expected_indent))) Err(self.raise(UnexpectedIndent(indent_on_line, expected_indent)))
} else if indent_on_line < expected_indent { } else if indent_on_line < expected_indent {
self.indent.pop(); self.indent.pop();
return Ok(None); Ok(None)
} else { } else {
Ok(Some(self.declaration(symbol_table)?)) Ok(Some(self.declaration(symbol_table)?))
} }
@ -139,13 +139,13 @@ impl AstCompiler {
} }
fn guard_if_expr(&mut self, symbol_table: &mut SymbolTable) -> Expr { fn guard_if_expr(&mut self, symbol_table: &mut SymbolTable) -> Expr {
while !self.check(&SingleRightArrow) { if !self.check(&SingleRightArrow) {
if self.match_token(&[Slash]) { return if self.match_token(&[Slash]) {
return self.path_guard_expr(); self.path_guard_expr()
} else if self.match_token(&[TokenType::Question]) { } else if self.match_token(&[TokenType::Question]) {
return self.query_guard_expr(symbol_table); self.query_guard_expr(symbol_table)
} else { } else {
return Err(self.raise(Expected("-> or ?"))); Err(self.raise(Expected("-> or ?")))
} }
} }
Ok(Stop { Ok(Stop {
@ -408,7 +408,7 @@ impl AstCompiler {
mut expr: Expression, mut expr: Expression,
symbol_table: &mut SymbolTable, symbol_table: &mut SymbolTable,
) -> Expr { ) -> Expr {
while self.match_token(&types) { while self.match_token(types) {
let operator = self.previous().clone(); let operator = self.previous().clone();
let right = self.comparison(symbol_table)?; let right = self.comparison(symbol_table)?;
expr = Expression::Binary { expr = Expression::Binary {
@ -431,8 +431,7 @@ impl AstCompiler {
right: Box::new(right), right: Box::new(right),
}) })
} else { } else {
let expr = self.get(symbol_table); self.get(symbol_table)
expr
} }
} }
@ -541,7 +540,7 @@ impl AstCompiler {
line: self.peek().line, line: self.peek().line,
literaltype: Integer, literaltype: Integer,
value: Value::U32( 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))))?, .map_err(|e| self.raise(ParseError(format!("{:?}", e))))?,
), ),
} }
@ -550,7 +549,7 @@ impl AstCompiler {
line: self.peek().line, line: self.peek().line,
literaltype: Integer, literaltype: Integer,
value: Value::U64( 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))))?, .map_err(|e| self.raise(ParseError(format!("{:?}", e))))?,
), ),
} }
@ -747,7 +746,7 @@ impl AstCompiler {
if !self.is_at_end() { if !self.is_at_end() {
self.current += 1; self.current += 1;
} }
&self.previous() self.previous()
} }
fn is_at_end(&self) -> bool { fn is_at_end(&self) -> bool {

View file

@ -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<Value>) -> Result<Value, RuntimeError>;
pub(crate) type MethodMap = HashMap<String, MethodFn>;
pub(crate) type MethodTable = HashMap<String, MethodMap>;
const METHODS: LazyLock<MethodTable> = 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<Value>,
) -> Result<Value, RuntimeError> {
METHODS
.get(type_name)
.and_then(|methods| methods.get(method_name))
.ok_or_else(|| RuntimeError::FunctionNotFound(format!("{}.{}",type_name, method_name)))?
(self_val, args)
}

View file

@ -1,2 +1,35 @@
pub mod builtin_functions;
mod string; 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<Value>) -> Result<Value, RuntimeError>;
pub(crate) type MethodMap = HashMap<String, MethodFn>;
pub(crate) type MethodTable = HashMap<String, MethodMap>;
static METHODS: LazyLock<MethodTable> = 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<Value>,
) -> Result<Value, RuntimeError> {
METHODS
.get(type_name)
.and_then(|methods| methods.get(method_name))
.ok_or_else(|| RuntimeError::FunctionNotFound(format!("{}.{}",type_name, method_name)))?
(self_val, args)
}

View file

@ -1,5 +1,5 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::builtins::builtin_functions::{insert, MethodMap}; use crate::builtins::{insert, MethodMap};
use crate::errors::RuntimeError; use crate::errors::RuntimeError;
use crate::value::Value; use crate::value::Value;

View file

@ -168,7 +168,7 @@ impl Compiler {
} => { } => {
let name_index = self let name_index = self
.chunk .chunk
.find_constant(&name) .find_constant(name)
.unwrap_or_else(|| self.chunk.add_constant(Value::String(name.to_string()))); .unwrap_or_else(|| self.chunk.add_constant(Value::String(name.to_string())));
let function = symbols.get(name); let function = symbols.get(name);
match function { match function {
@ -207,7 +207,7 @@ impl Compiler {
.find_constant(&receiver_type) .find_constant(&receiver_type)
.unwrap_or_else(|| self.chunk.add_constant(Value::String(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 self.chunk
.add_constant(Value::String(method_name.to_string())) .add_constant(Value::String(method_name.to_string()))
}); });

View file

@ -1,13 +1,13 @@
use std::collections::HashMap;
use crate::ast_compiler::Parameter; use crate::ast_compiler::Parameter;
use crate::tokens::TokenType; use crate::tokens::TokenType;
use crate::value::Value; use crate::value::Value;
use crate::vm::{ use crate::vm::{
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_F32, 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_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_MAP, OP_DEF_STRING, OP_DEFINE,
OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_DIVIDE, OP_EQUAL, OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY,
OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, OP_DEF_MAP, OP_NEGATE, OP_NOT, OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT,
}; };
use std::collections::HashMap;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Chunk { pub struct Chunk {
@ -17,16 +17,16 @@ pub struct Chunk {
lines: Vec<usize>, lines: Vec<usize>,
pub(crate) object_defs: HashMap<String, Vec<Parameter>>, pub(crate) object_defs: HashMap<String, Vec<Parameter>>,
pub(crate) function_parameters: Vec<Parameter>, pub(crate) function_parameters: Vec<Parameter>,
pub vars: Vec<(TokenType, String)> pub vars: Vec<(TokenType, String)>,
} }
impl Chunk { impl Chunk {
pub(crate) fn find_constant(&self, p0: &String) -> Option<usize> { pub(crate) fn find_constant(&self, p0: &String) -> Option<usize> {
for (i, constant) in self.constants.iter().enumerate() { for (i, constant) in self.constants.iter().enumerate() {
if let Value::String(s) = constant { if let Value::String(s) = constant
if s == p0 { && s == p0
return Some(i); {
} return Some(i);
} }
} }
None None
@ -42,7 +42,7 @@ impl Chunk {
lines: vec![], lines: vec![],
object_defs: HashMap::new(), object_defs: HashMap::new(),
function_parameters: vec![], function_parameters: vec![],
vars: vec![] vars: vec![],
} }
} }
@ -61,7 +61,7 @@ impl Chunk {
self.vars.len() - 1 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()); self.object_defs.insert(name.to_string(), fields.to_vec());
} }

View file

@ -36,7 +36,7 @@ pub fn start_watch_daemon(source: &str, registry: Arc<ArcSwap<HashMap<String, Ch
let start = SystemTime::now(); let start = SystemTime::now();
loop { loop {
thread::sleep(Duration::from_millis(50)); thread::sleep(Duration::from_millis(50));
if let Ok(_) = rx.recv() { if rx.recv().is_ok() {
file_changed = true; file_changed = true;
} }
if file_changed && SystemTime::now().duration_since(start).unwrap() > ONE_SEC { if file_changed && SystemTime::now().duration_since(start).unwrap() > ONE_SEC {

View file

@ -4,12 +4,8 @@ use crate::errors::CrudLangError::Platform;
use crate::errors::{CompilerErrorAtLine, CrudLangError}; use crate::errors::{CompilerErrorAtLine, CrudLangError};
use crate::scanner::scan; use crate::scanner::scan;
use crate::symbol_builder::Symbol; use crate::symbol_builder::Symbol;
use crate::value::Value;
use crate::vm::interpret;
use arc_swap::ArcSwap;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::fs;
use std::sync::Arc;
use walkdir::WalkDir; use walkdir::WalkDir;
pub mod ast_compiler; pub mod ast_compiler;
@ -89,13 +85,13 @@ pub fn compile(src: &str) -> Result<HashMap<String, Chunk>, CrudLangError> {
} }
#[cfg(test)] #[cfg(test)]
pub(crate) fn run(src: &str) -> Result<Value, CrudLangError> { pub(crate) fn run(src: &str) -> Result<value::Value, CrudLangError> {
let tokens = scan(src)?; let tokens = scan(src)?;
let mut symbol_table = HashMap::new(); let mut symbol_table = HashMap::new();
let ast = ast_compiler::compile(None, tokens, &mut symbol_table)?; let ast = ast_compiler::compile(None, tokens, &mut symbol_table)?;
symbol_builder::build("", &ast, &mut symbol_table); symbol_builder::build("", &ast, &mut symbol_table);
let mut registry = HashMap::new(); let mut registry = HashMap::new();
bytecode_compiler::compile(None, &ast, &symbol_table, &mut registry)?; bytecode_compiler::compile(None, &ast, &symbol_table, &mut registry)?;
let registry = ArcSwap::from(Arc::new(registry)); let registry = arc_swap::ArcSwap::from(std::sync::Arc::new(registry));
interpret(registry.load(), "main").map_err(CrudLangError::from) vm::interpret(registry.load(), "main").map_err(CrudLangError::from)
} }

View file

@ -5,14 +5,12 @@ use axum::{Json, Router};
use clap::Parser; use clap::Parser;
use crudlang::chunk::Chunk; use crudlang::chunk::Chunk;
use crudlang::errors::CrudLangError; use crudlang::errors::CrudLangError;
use crudlang::errors::CrudLangError::Platform;
use crudlang::vm::interpret_async; use crudlang::vm::interpret_async;
use crudlang::{compile_sourcedir, map_underlying}; use crudlang::{compile_sourcedir, map_underlying};
use notify::Watcher;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use log::{debug, info}; use log::info;
/// A simple CLI tool to greet users /// A simple CLI tool to greet users
#[derive(Parser, Debug)] #[derive(Parser, Debug)]

View file

@ -27,7 +27,7 @@ pub fn start(registry: Arc<ArcSwap<HashMap<String, Chunk>>>) -> Result<(), CrudL
_ => { _ => {
let registry_copy = registry.load().clone(); let registry_copy = registry.load().clone();
let mut registry_copy = registry_copy.deref().clone(); let mut registry_copy = registry_copy.deref().clone();
match recompile(&input, &mut registry_copy){ match recompile(input, &mut registry_copy){
Ok(_)=> { Ok(_)=> {
registry.store(Arc::new(registry_copy)); registry.store(Arc::new(registry_copy));

View file

@ -141,7 +141,7 @@ impl Scanner {
_ => { _ => {
if c == '0' && self.peek() == 'x' { if c == '0' && self.peek() == 'x' {
self.hex_number()?; self.hex_number()?;
} else if is_digit(c) { } else if c.is_ascii_digit() {
self.number(); self.number();
} else if is_alpha(c) { } else if is_alpha(c) {
self.identifier(); self.identifier();
@ -167,7 +167,7 @@ impl Scanner {
fn hex_number(&mut self) -> Result<(), CompilerErrorAtLine> { fn hex_number(&mut self) -> Result<(), CompilerErrorAtLine> {
self.advance(); self.advance();
self.advance(); self.advance();
while is_digit(self.peek()) || is_alpha(self.peek()) { while self.peek().is_ascii_hexdigit() {
self.advance(); self.advance();
} }
let value: String = self.chars[self.start..self.current].iter().collect(); let value: String = self.chars[self.start..self.current].iter().collect();
@ -182,11 +182,11 @@ impl Scanner {
} }
fn number(&mut self) { fn number(&mut self) {
while is_digit(self.peek()) { while self.peek().is_ascii_digit() {
self.advance(); self.advance();
} }
let mut has_dot = false; 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; has_dot = true;
self.advance(); self.advance();
} }
@ -269,9 +269,7 @@ impl Scanner {
} }
fn match_next(&mut self, expected: char) -> bool { fn match_next(&mut self, expected: char) -> bool {
if self.is_at_end() { if self.is_at_end() || self.chars[self.current] != expected{
false
} else if self.chars[self.current] != expected {
false false
} else { } else {
self.current += 1; self.current += 1;
@ -306,20 +304,19 @@ struct Scanner {
new_line: bool, new_line: bool,
} }
fn is_digit(c: char) -> bool {
c >= '0' && c <= '9'
}
fn is_digit_or_scientific(c: char) -> bool { 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 { 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 { 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)] #[cfg(test)]

View file

@ -70,31 +70,6 @@ pub fn build(path: &str, ast: &[Statement], symbols: &mut HashMap<String, Symbol
} }
} }
pub fn _add_types(
path: &str,
ast: &[Statement],
symbols: &mut HashMap<String, Symbol>,
) -> 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( pub fn calculate_type(
declared_type: &TokenType, declared_type: &TokenType,
inferred_type: &TokenType, inferred_type: &TokenType,
@ -157,42 +132,40 @@ pub fn infer_type(expr: &Expression, symbols: &HashMap<String, Symbol>) -> Token
Integer => I64, Integer => I64,
_ => left_type, _ => 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 { } else {
if let Plus = operator.token_type { // type coercion to 64 bits for numeric types
// includes string concatenation with numbers debug!("coerce {} : {}", left_type, right_type);
// followed by type coercion to 64 bits for numeric types match (left_type, right_type) {
debug!("coerce {} : {}", left_type, right_type); (FloatingPoint, _) => F64,
match (left_type, right_type) { (Integer, FloatingPoint) => F64,
(_, StringType) => StringType, (Integer, I64) => I64,
(StringType, _) => StringType, (I64, FloatingPoint) => F64,
(FloatingPoint, _) => F64, (F64, _) => F64,
(Integer, FloatingPoint) => F64, (U64, U32) => U64,
(Integer, _) => I64, (I64, I32) => I64,
(I64, Integer) => I64, (I64, Integer) => I64,
(F64, _) => F64, _ => panic!("Unexpected coercion"),
(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"),
}
} }
} }
} }

View file

@ -7,7 +7,6 @@ use arc_swap::Guard;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use tracing::debug; use tracing::debug;
use crate::builtins::builtin_functions::call_builtin;
pub struct Vm { pub struct Vm {
ip: usize, ip: usize,
@ -206,17 +205,14 @@ impl Vm {
let receiver_type_name = chunk.constants[function_type_index].to_string(); let receiver_type_name = chunk.constants[function_type_index].to_string();
let receiver = self.pop(); let receiver = self.pop();
let num_args = self.read(chunk); let num_args = self.read(chunk);
let mut args = vec![]; let mut args = vec![];
for _ in 0..num_args { for _ in 0..num_args {
let arg = self.pop(); let arg = self.pop();
args.push(arg); args.push(arg);
} }
args.reverse(); args.reverse();
let return_value = crate::builtins::call(&receiver_type_name, &function_name, receiver, args)?;
let return_value = call_builtin(&receiver_type_name, &function_name, receiver, args)?;
self.push(return_value); self.push(return_value);
} }
OP_CALL => { OP_CALL => {