From d0eedfd8102230ab6d4ae1c3614244f4300aa12d Mon Sep 17 00:00:00 2001 From: trimill Date: Thu, 14 Nov 2024 14:16:33 -0500 Subject: [PATCH] changes --- Cargo.lock | 12 +++--- Cargo.toml | 2 - README.md | 2 +- talc-bin/src/helper.rs | 2 +- talc-bin/src/main.rs | 5 ++- talc-bin/src/repl.rs | 13 +++--- talc-lang/Cargo.toml | 2 - talc-lang/src/compiler.rs | 72 ++++++++++++--------------------- talc-lang/src/lib.rs | 7 +--- talc-lang/src/optimize.rs | 8 ++-- talc-lang/src/parser/ast.rs | 1 + talc-lang/src/parser/lexer.rs | 15 ++++--- talc-lang/src/parser/parser.rs | 25 ++++++------ talc-lang/src/symbol.rs | 1 + talc-lang/src/value/function.rs | 2 +- talc-lang/src/value/index.rs | 9 ++++- talc-lang/src/value/mod.rs | 5 ++- talc-lang/src/value/ops.rs | 30 ++++++++++---- talc-lang/src/vm.rs | 20 ++++++--- talc-lang/tests/vm.rs | 4 +- talc-std/Cargo.toml | 7 ++-- talc-std/src/collection.rs | 3 +- talc-std/src/exception.rs | 2 +- talc-std/src/file.rs | 2 +- talc-std/src/format.rs | 2 +- talc-std/src/io.rs | 3 +- talc-std/src/iter.rs | 3 +- talc-std/src/lib.rs | 30 ++++++++------ talc-std/src/num.rs | 3 +- talc-std/src/random.rs | 3 +- talc-std/src/regex.rs | 2 +- talc-std/src/string.rs | 2 +- talc-std/src/value.rs | 2 +- 33 files changed, 159 insertions(+), 142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 637c51f..0250c84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,9 +55,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -65,9 +65,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstyle", "clap_lex", @@ -87,9 +87,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "clipboard-win" diff --git a/Cargo.toml b/Cargo.toml index 01d4c64..dbc4fa2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,8 +2,6 @@ members = ["talc-lang", "talc-bin", "talc-std", "talc-macros"] resolver = "2" -[profile.release] - [profile.release-opt] inherits = "release" lto = "fat" diff --git a/README.md b/README.md index ae5dd08..4dfec79 100644 --- a/README.md +++ b/README.md @@ -3,5 +3,5 @@ ## installation ```sh -cargo install --profile release-lto --path talc-bin +cargo install --profile release-opt --path talc-bin ``` diff --git a/talc-bin/src/helper.rs b/talc-bin/src/helper.rs index 3c4a56b..07f811d 100644 --- a/talc-bin/src/helper.rs +++ b/talc-bin/src/helper.rs @@ -10,7 +10,7 @@ use rustyline::{ use talc_lang::{ lstring::LStr, parser::{Lexer, Pos, Span, TokenKind}, - Vm, + vm::Vm, }; pub struct TalcHelper { diff --git a/talc-bin/src/main.rs b/talc-bin/src/main.rs index 53e0b1f..7b34596 100644 --- a/talc-bin/src/main.rs +++ b/talc-bin/src/main.rs @@ -3,10 +3,11 @@ use std::{path::PathBuf, process::ExitCode, rc::Rc}; use talc_lang::{ compiler::compile, lstring::LString, - optimize, parser, serial, + optimize::optimize, + parser, serial, symbol::Symbol, value::{function::disasm_recursive, Value}, - Vm, + vm::Vm, }; mod helper; diff --git a/talc-bin/src/repl.rs b/talc-bin/src/repl.rs index 07d3f86..e974d2d 100644 --- a/talc-bin/src/repl.rs +++ b/talc-bin/src/repl.rs @@ -8,10 +8,12 @@ use rustyline::{ }; use talc_lang::{ compiler::compile_repl, - lstr, optimize, parser, + lstr, + optimize::optimize, + parser, symbol::{symbol, Symbol}, value::{function::disasm_recursive, Value}, - Vm, + vm::Vm, }; use crate::{helper::TalcHelper, Args}; @@ -117,17 +119,14 @@ fn exec_line( eprintln!("{}", ex); } - let (f, g) = match compile_repl(&ex, globals) { - Ok(pair) => pair, + let func = match compile_repl(&ex, globals) { + Ok(f) => Rc::new(f), Err(e) => { eprintln!("{}Error:{} {e}", c.error, c.reset); return } }; - *globals = g; - let func = Rc::new(f); - if args.disasm { if let Err(e) = disasm_recursive(&func, &mut std::io::stderr()) { eprintln!("{}Error:{} {e}", c.error, c.reset); diff --git a/talc-lang/Cargo.toml b/talc-lang/Cargo.toml index ec41ef7..2ddd4c8 100644 --- a/talc-lang/Cargo.toml +++ b/talc-lang/Cargo.toml @@ -9,5 +9,3 @@ num-rational = { version = "0.4", default-features = false, features = [] } num-traits = "0.2" lazy_static = "1.5" unicode-ident = "1.0" - -[build-dependencies] diff --git a/talc-lang/src/compiler.rs b/talc-lang/src/compiler.rs index 873be72..a2516e3 100644 --- a/talc-lang/src/compiler.rs +++ b/talc-lang/src/compiler.rs @@ -5,7 +5,7 @@ use std::rc::Rc; use crate::chunk::{Arg24, Catch, Chunk, Instruction as I}; use crate::parser::ast::{BinaryOp, CatchBlock, Expr, ExprKind, LValue, LValueKind}; use crate::parser::Pos; -use crate::symbol::{Symbol, SYM_SELF}; +use crate::symbol::{Symbol, SYM_REPL, SYM_SELF}; use crate::throw; use crate::value::function::{FuncAttrs, Function}; use crate::value::Value; @@ -39,18 +39,12 @@ enum ResolveOutcome { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum VarKind { +enum VarKind { Local(usize), Closed(usize), Global, } -#[derive(Debug, Clone)] -pub struct Var { - name: Symbol, - kind: VarKind, -} - #[derive(Clone, Copy, PartialEq, Eq)] enum CompilerMode { Function, @@ -72,8 +66,8 @@ struct Compiler<'a> { chunk: Chunk, attrs: FuncAttrs, // variables - scope: HashMap, - shadowed: Vec<(Symbol, Option)>, + scope: HashMap, + shadowed: Vec<(Symbol, Option)>, closes: Vec<(Symbol, usize)>, local_count: usize, // break and continue @@ -87,22 +81,16 @@ pub fn compile(expr: &Expr, name: Option) -> Result { Ok(comp.finish()) } -pub fn compile_repl(expr: &Expr, globals: &[Symbol]) -> Result<(Function, Vec)> { +pub fn compile_repl(expr: &Expr, globals: &mut Vec) -> Result { let mut comp = Compiler::new_repl(globals); comp.expr(expr)?; - Ok(comp.finish_repl()) + Ok(comp.finish_repl(globals)) } impl<'a> Default for Compiler<'a> { fn default() -> Self { let mut scope = HashMap::new(); - scope.insert( - *SYM_SELF, - Var { - name: *SYM_SELF, - kind: VarKind::Local(0), - }, - ); + scope.insert(*SYM_SELF, VarKind::Local(0)); Self { mode: CompilerMode::Function, parent: None, @@ -124,7 +112,7 @@ impl<'a> Compiler<'a> { mode: CompilerMode::Repl, attrs: FuncAttrs { arity: 0, - name: Some(Symbol::get("")), + name: Some(*SYM_REPL), }, ..Self::default() }; @@ -162,30 +150,29 @@ impl<'a> Compiler<'a> { new } - pub fn finish(mut self) -> Function { + fn finish(mut self) -> Function { self.emit(I::Return); Function::new(Rc::new(self.chunk), self.attrs, self.closes.len()) } - pub fn finish_inner(mut self) -> (Function, Vec<(Symbol, usize)>) { + fn finish_inner(mut self) -> (Function, Vec<(Symbol, usize)>) { self.emit(I::Return); - // TODO closure ( Function::new(Rc::new(self.chunk), self.attrs, self.closes.len()), self.closes, ) } - pub fn finish_repl(mut self) -> (Function, Vec) { + fn finish_repl(mut self, globals: &mut Vec) -> Function { self.emit(I::Return); - ( - // TODO closure - Function::new(Rc::new(self.chunk), self.attrs, self.closes.len()), - self.scope - .into_iter() - .filter_map(|(_, v)| (v.kind == VarKind::Global).then_some(v.name)) - .collect(), - ) + + globals.clear(); + for (name, kind) in self.scope.iter() { + if *kind == VarKind::Global { + globals.push(*name); + } + } + Function::new(Rc::new(self.chunk), self.attrs, self.closes.len()) } // @@ -306,7 +293,7 @@ impl<'a> Compiler<'a> { let (name, var) = self.shadowed.pop().expect("scope bad"); if let Some(in_var) = self.scope.get(&name) { - if in_var.kind != VarKind::Global { + if *in_var != VarKind::Global { locals += 1; } } @@ -329,8 +316,8 @@ impl<'a> Compiler<'a> { // fn resolve_name(&self, name: Symbol) -> ResolveOutcome { - if let Some(v) = self.scope.get(&name) { - return ResolveOutcome::Var(v.kind) + if let Some(kind) = self.scope.get(&name) { + return ResolveOutcome::Var(*kind) } let Some(parent) = self.parent else { return ResolveOutcome::None @@ -369,10 +356,7 @@ impl<'a> Compiler<'a> { } fn declare_local(&mut self, name: Symbol) -> usize { - let local = Var { - name, - kind: VarKind::Local(self.local_count), - }; + let local = VarKind::Local(self.local_count); self.local_count += 1; let shadowed = self.scope.insert(name, local); self.shadowed.push((name, shadowed)); @@ -391,11 +375,7 @@ impl<'a> Compiler<'a> { } fn declare_global(&mut self, name: Symbol) { - let global = Var { - name, - kind: VarKind::Global, - }; - let shadowed = self.scope.insert(name, global); + let shadowed = self.scope.insert(name, VarKind::Global); self.shadowed.push((name, shadowed)); } @@ -752,9 +732,7 @@ impl<'a> Compiler<'a> { match self.resolve_name(name) { ResolveOutcome::Var(VarKind::Local(n)) => { self.emit(I::CloseOver(Arg24::from_usize(n))); - self.scope.entry(name).and_modify(|v| { - v.kind = VarKind::Closed(n); - }); + self.scope.insert(name, VarKind::Closed(n)); } ResolveOutcome::Var(VarKind::Closed(n)) => { self.emit(I::LoadLocal(Arg24::from_usize(n))); diff --git a/talc-lang/src/lib.rs b/talc-lang/src/lib.rs index ff3a7e9..0d044f6 100644 --- a/talc-lang/src/lib.rs +++ b/talc-lang/src/lib.rs @@ -8,12 +8,9 @@ pub mod chunk; pub mod compiler; pub mod exception; pub mod lstring; -mod optimize; -pub use optimize::optimize; +pub mod optimize; pub mod parser; pub mod serial; pub mod symbol; pub mod value; - -mod vm; -pub use vm::Vm; +pub mod vm; diff --git a/talc-lang/src/optimize.rs b/talc-lang/src/optimize.rs index a43d2bb..1097d49 100644 --- a/talc-lang/src/optimize.rs +++ b/talc-lang/src/optimize.rs @@ -27,12 +27,12 @@ struct OptState { impl OptState { #[inline] - pub const fn empty() -> Self { + const fn empty() -> Self { Self { ret: false } } #[inline] - pub const fn ret(ret: bool) -> Self { + const fn ret(ret: bool) -> Self { Self { ret } } } @@ -214,7 +214,7 @@ fn optimize_ex_with(expr: &mut Expr, state: OptState) { } } -pub fn optimize_lv(e: &mut LValue) { +fn optimize_lv(e: &mut LValue) { match &mut e.kind { LValueKind::Ident(_) => (), LValueKind::Index(l, r) => { @@ -224,6 +224,6 @@ pub fn optimize_lv(e: &mut LValue) { } } -pub fn optimize_cb(e: &mut CatchBlock) { +fn optimize_cb(e: &mut CatchBlock) { optimize_ex(&mut e.body); } diff --git a/talc-lang/src/parser/ast.rs b/talc-lang/src/parser/ast.rs index 1ea684f..f25ce49 100644 --- a/talc-lang/src/parser/ast.rs +++ b/talc-lang/src/parser/ast.rs @@ -34,6 +34,7 @@ pub enum BinaryOp { pub enum UnaryOp { Neg, Not, + BitNot, RangeEndless, } diff --git a/talc-lang/src/parser/lexer.rs b/talc-lang/src/parser/lexer.rs index ecc178b..a85578d 100644 --- a/talc-lang/src/parser/lexer.rs +++ b/talc-lang/src/parser/lexer.rs @@ -11,7 +11,7 @@ pub enum TokenKind { Eof, LineSeparator, - Bang, + Tilde, BangEqual, HashAmper, HashAmperEqual, @@ -42,7 +42,6 @@ pub enum TokenKind { SlashSlash, SlashSlashEqual, SlashEqual, - Colon, Less, LessLess, LessLessEqual, @@ -101,7 +100,7 @@ impl TokenKind { match self { K::Eof => "end of file", K::LineSeparator => "line separator", - K::Bang => "'!'", + K::Tilde => "'~'", K::BangEqual => "'!='", K::HashAmper => "'#&'", K::HashAmperEqual => "'#&='", @@ -123,7 +122,7 @@ impl TokenKind { K::Comma => "','", K::Minus => "'-'", K::MinusEqual => "'-='", - K::Arrow => "'=>'", + K::Arrow => "'->'", K::Dot => "'.'", K::DotDot => "'..'", K::DotDotStar => "'..*'", @@ -132,7 +131,6 @@ impl TokenKind { K::SlashSlash => "'//'", K::SlashSlashEqual => "'//='", K::SlashEqual => "'/='", - K::Colon => "':'", K::Less => "'<'", K::LessLess => "'<<'", K::LessLessEqual => "'<<='", @@ -526,11 +524,12 @@ impl<'s> Lexer<'s> { '!' => self.line_comment(), _ => self.unexpected(), }, - // lists + '~' => self.and_emit(K::Tilde), '!' => match self.and_peek()? { '=' => self.and_emit(K::BangEqual), - _ => self.emit(K::Bang), + _ => self.unexpected(), }, + // lists '&' => match self.and_peek()? { '=' => self.and_emit(K::AmperEqual), _ => self.emit(K::Amper), @@ -569,7 +568,7 @@ impl<'s> Lexer<'s> { c if is_xid_start(c) || c == '_' || c == '"' || c == '\'' => { self.next_symbol() } - _ => self.emit(K::Colon), + _ => self.unexpected(), }, '0'..='9' => self.next_number(), c if c == '_' || is_xid_start(c) => self.next_ident(), diff --git a/talc-lang/src/parser/parser.rs b/talc-lang/src/parser/parser.rs index fc89322..708ac81 100644 --- a/talc-lang/src/parser/parser.rs +++ b/talc-lang/src/parser/parser.rs @@ -54,7 +54,7 @@ macro_rules! throw { } impl TokenKind { - pub fn assign_op(self) -> Option> { + fn assign_op(self) -> Option> { Some(match self { T::PlusPlusEqual => Some(BinaryOp::Concat), T::AmperEqual => Some(BinaryOp::Append), @@ -75,7 +75,7 @@ impl TokenKind { }) } - pub fn binary_op(self) -> Option { + fn binary_op(self) -> Option { Some(match self { T::EqualEqual => BinaryOp::Eq, T::BangEqual => BinaryOp::Ne, @@ -103,15 +103,16 @@ impl TokenKind { }) } - pub fn unary_op(self) -> Option { + fn unary_op(self) -> Option { match self { T::Minus => Some(UnaryOp::Neg), T::Not => Some(UnaryOp::Not), + T::Tilde => Some(UnaryOp::BitNot), _ => None, } } - pub fn postfix_unary_op(self) -> Option { + fn postfix_unary_op(self) -> Option { match self { T::DotDotStar => Some(UnaryOp::RangeEndless), _ => None, @@ -120,17 +121,17 @@ impl TokenKind { } impl UnaryOp { - pub fn precedence(self) -> u8 { + fn precedence(self) -> u8 { match self { UnaryOp::Not => 0, UnaryOp::RangeEndless => 40, - UnaryOp::Neg => 110, + UnaryOp::Neg | UnaryOp::BitNot => 110, } } } impl BinaryOp { - pub fn precedence(self) -> (u8, u8) { + fn precedence(self) -> (u8, u8) { match self { BinaryOp::Eq | BinaryOp::Ne @@ -166,8 +167,8 @@ impl TokenKind { | T::Break | T::Var | T::Global | T::Fn | T::Not | T::Backslash - | T::Colon | T::Minus - | T::Identifier + | T::Amper | T::Minus + | T::Tilde | T::Identifier | T::LParen | T::LBrack | T::LBrace | T::Dollar | T::Do | T::If @@ -494,7 +495,7 @@ impl<'s> Parser<'s> { } fn parse_lambda(&mut self) -> Result { - let tok = try_next!(self, T::Backslash | T::Colon); + let tok = try_next!(self, T::Backslash | T::Amper); match tok { Some(Token { kind: T::Backslash, @@ -502,13 +503,13 @@ impl<'s> Parser<'s> { .. }) => { let args = self.parse_ident_list()?; - expect!(self, T::Arrow); + expect!(self, T::Dot); let body = self.parse_lambda()?; let body_span = body.span; Ok(E::Lambda(args, b(body)).span(span + body_span)) } Some(Token { - kind: T::Colon, + kind: T::Amper, span, .. }) => { diff --git a/talc-lang/src/symbol.rs b/talc-lang/src/symbol.rs index 8fe021e..abb266b 100644 --- a/talc-lang/src/symbol.rs +++ b/talc-lang/src/symbol.rs @@ -12,6 +12,7 @@ struct SymbolTable { } lazy_static! { + pub static ref SYM_REPL: Symbol = symbol!(""); pub static ref SYM_SELF: Symbol = symbol!(self); pub static ref SYM_DOLLAR_SIGN: Symbol = symbol!("$"); pub static ref SYM_NIL: Symbol = symbol!(nil); diff --git a/talc-lang/src/value/function.rs b/talc-lang/src/value/function.rs index 2d8c85f..970a941 100644 --- a/talc-lang/src/value/function.rs +++ b/talc-lang/src/value/function.rs @@ -1,6 +1,6 @@ use std::{cell::RefCell, rc::Rc}; -use crate::{chunk::Chunk, exception::Result, symbol::Symbol, Vm}; +use crate::{chunk::Chunk, exception::Result, symbol::Symbol, vm::Vm}; use super::{CellValue, Value}; diff --git a/talc-lang/src/value/index.rs b/talc-lang/src/value/index.rs index b0720da..98184ff 100644 --- a/talc-lang/src/value/index.rs +++ b/talc-lang/src/value/index.rs @@ -2,7 +2,8 @@ use crate::{ exception::{throw, Result}, symbol::{symbol, SYM_END_ITERATION, SYM_INDEX_ERROR, SYM_TYPE_ERROR}, value::function::NativeFunc, - vmcalliter, Vm, + vm::Vm, + vmcalliter, }; use super::{range::RangeType, Value}; @@ -126,7 +127,11 @@ impl Value { (V::Table(t), i) if i.hashable() => { let mut t = t.borrow_mut(); let i = i.try_into()?; - t.insert(i, val); + if val == Value::Nil { + t.remove(&i); + } else { + t.insert(i, val); + } Ok(()) } (V::List(t), V::Range(r)) => { diff --git a/talc-lang/src/value/mod.rs b/talc-lang/src/value/mod.rs index 3821184..33a1b4c 100644 --- a/talc-lang/src/value/mod.rs +++ b/talc-lang/src/value/mod.rs @@ -169,6 +169,9 @@ impl Value { if recur.contains(&(t.as_ptr() as _)) { return w.write_all(b"{...}") } + if t.borrow().len() == 0 { + return w.write_all(b"{}") + } w.write_all(b"{ ")?; recur.push(t.as_ptr() as _); for (i, (k, v)) in t.borrow().iter().enumerate() { @@ -176,7 +179,7 @@ impl Value { w.write_all(b", ")?; } k.0.write_table_key_repr(w, recur)?; - w.write_all(b" = ")?; + w.write_all(b"=")?; v.write_to_lstring(w, true, recur)?; } recur.pop(); diff --git a/talc-lang/src/value/ops.rs b/talc-lang/src/value/ops.rs index 05265b4..421eea2 100644 --- a/talc-lang/src/value/ops.rs +++ b/talc-lang/src/value/ops.rs @@ -1,7 +1,7 @@ use std::{ cell::RefCell, cmp::Ordering, - ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Shl, Shr, Sub}, + ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub}, rc::Rc, }; @@ -14,7 +14,7 @@ use crate::{ lstring::LString, symbol::{symbol, SYM_END_ITERATION, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, value::range::RangeType, - Vm, + vm::Vm, }; use super::{ @@ -388,7 +388,9 @@ impl Shl for Value { fn shl(self, rhs: Value) -> Self::Output { use Value as V; match (self, rhs) { - (V::Int(a), V::Int(b)) => Ok(Value::Int(((a as u64) << b as u64) as i64)), + (V::Int(a), V::Int(b)) => { + Ok(Value::Int((a as u64).wrapping_shl(b as u32) as i64)) + } (l, r) => throw!(*SYM_TYPE_ERROR, "cannot shift {l:#} left by {r:#}"), } } @@ -400,7 +402,9 @@ impl Shr for Value { fn shr(self, rhs: Value) -> Self::Output { use Value as V; match (self, rhs) { - (V::Int(a), V::Int(b)) => Ok(Value::Int((a as u64 >> b as u64) as i64)), + (V::Int(a), V::Int(b)) => { + Ok(Value::Int((a as u64).wrapping_shr(b as u32) as i64)) + } (l, r) => throw!(*SYM_TYPE_ERROR, "cannot shift {l:#} right by {r:#}"), } } @@ -413,7 +417,7 @@ impl BitAnd for Value { use Value as V; match (self, rhs) { (V::Int(a), V::Int(b)) => Ok(Value::Int(a & b)), - (l, r) => throw!(*SYM_TYPE_ERROR, "cannot shift {l:#} right by {r:#}"), + (l, r) => throw!(*SYM_TYPE_ERROR, "cannot bitwise and {l:#} and {r:#}"), } } } @@ -425,7 +429,7 @@ impl BitXor for Value { use Value as V; match (self, rhs) { (V::Int(a), V::Int(b)) => Ok(Value::Int(a ^ b)), - (l, r) => throw!(*SYM_TYPE_ERROR, "cannot shift {l:#} right by {r:#}"), + (l, r) => throw!(*SYM_TYPE_ERROR, "cannot bitwise xor {l:#} and {r:#}"), } } } @@ -437,7 +441,19 @@ impl BitOr for Value { use Value as V; match (self, rhs) { (V::Int(a), V::Int(b)) => Ok(Value::Int(a | b)), - (l, r) => throw!(*SYM_TYPE_ERROR, "cannot shift {l:#} right by {r:#}"), + (l, r) => throw!(*SYM_TYPE_ERROR, "cannot bitwise or {l:#} and {r:#}"), + } + } +} + +impl Not for Value { + type Output = Result; + + fn not(self) -> Self::Output { + use Value as V; + match self { + V::Int(a) => Ok(Value::Int(!a)), + v => throw!(*SYM_TYPE_ERROR, "cannot bitwise not {v:#}"), } } } diff --git a/talc-lang/src/vm.rs b/talc-lang/src/vm.rs index a9a6593..5d93251 100644 --- a/talc-lang/src/vm.rs +++ b/talc-lang/src/vm.rs @@ -1,6 +1,7 @@ use std::{ cmp::Ordering, collections::HashMap, + ops::Not, rc::Rc, sync::{atomic::AtomicBool, Arc}, }; @@ -84,6 +85,7 @@ pub fn unary_op(o: UnaryOp, a: Value) -> Result { match o { UnaryOp::Neg => -a, UnaryOp::Not => Ok(Value::Bool(!a.truthy())), + UnaryOp::BitNot => a.not(), UnaryOp::RangeEndless => a.range_endless(), } } @@ -243,7 +245,7 @@ impl Vm { res } - fn check_interrupt(&mut self) -> Result<()> { + pub fn check_interrupt(&mut self) -> Result<()> { if self .interrupt .fetch_and(false, std::sync::atomic::Ordering::Relaxed) @@ -399,7 +401,11 @@ impl Vm { for _ in 0..n { let v = self.pop(); let k = self.pop(); - table.insert(k.try_into()?, v); + if v == Value::Nil { + table.remove(&k.try_into()?); + } else { + table.insert(k.try_into()?, v); + } } self.push(table.into()); } @@ -415,18 +421,22 @@ impl Vm { // can't panic: pop_n checked that ext would have len 2*n let v = ext.pop().unwrap(); let k = ext.pop().unwrap(); - table_ref.insert(k.try_into()?, v); + if v == Value::Nil { + table_ref.remove(&k.try_into()?); + } else { + table_ref.insert(k.try_into()?, v); + } } drop(table_ref); self.push(Value::Table(table)); } - // [ct, idx] -> [ct!idx] + // [ct, idx] -> [ct[idx]] I::Index => { let idx = self.pop(); let ct = self.pop(); self.push(ct.index(idx)?); } - // [ct, idx, v] -> [v], ct!idx = v + // [ct, idx, v] -> [v], ct[idx] = v I::StoreIndex => { let v = self.pop(); let idx = self.pop(); diff --git a/talc-lang/tests/vm.rs b/talc-lang/tests/vm.rs index b5c1283..75f3a27 100644 --- a/talc-lang/tests/vm.rs +++ b/talc-lang/tests/vm.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use talc_lang::{compiler::compile, optimize, parser, value::Value, Vm}; +use talc_lang::{compiler::compile, optimize::optimize, parser, value::Value, vm::Vm}; fn assert_eval(src: &str, value: Value) { let mut ex = parser::parse(src).expect(&format!("failed to parse expression")); @@ -88,7 +88,7 @@ fn closures() { assert_eval( " var x = 2 - next = \\-> do x = x * 2 + 1 end + next = \\. do x = x * 2 + 1 end next() + next() + next() ", Value::Int(5 + 11 + 23), diff --git a/talc-std/Cargo.toml b/talc-std/Cargo.toml index 881e8a1..bfafd4d 100644 --- a/talc-std/Cargo.toml +++ b/talc-std/Cargo.toml @@ -7,9 +7,10 @@ edition = "2021" talc-lang = { path = "../talc-lang" } talc-macros = { path = "../talc-macros" } lazy_static = "1.5" -regex = "1.11" +regex = { version = "1.11", optional = true } rand = { version = "0.8", optional = true } [features] -default = ["random"] -random = ["dep:rand"] +default = ["rand", "regex"] +rand = ["dep:rand"] +regex = ["dep:regex"] diff --git a/talc-std/src/collection.rs b/talc-std/src/collection.rs index db02366..985cdbc 100644 --- a/talc-std/src/collection.rs +++ b/talc-std/src/collection.rs @@ -5,7 +5,8 @@ use talc_lang::{ symbol::{symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{function::NativeFunc, Value}, - vmcall, Vm, + vm::Vm, + vmcall, }; use talc_macros::native_func; diff --git a/talc-std/src/exception.rs b/talc-std/src/exception.rs index 98ea0f7..a6e9bfd 100644 --- a/talc-std/src/exception.rs +++ b/talc-std/src/exception.rs @@ -2,7 +2,7 @@ use talc_lang::{ exception::{throw, Exception, Result}, symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, value::Value, - Vm, + vm::Vm, }; use talc_macros::native_func; diff --git a/talc-std/src/file.rs b/talc-std/src/file.rs index ee3ba62..6d89ce2 100644 --- a/talc-std/src/file.rs +++ b/talc-std/src/file.rs @@ -16,7 +16,7 @@ use talc_lang::{ symbol::{symbol, Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{function::NativeFunc, HashValue, NativeValue, Value}, - Vm, + vm::Vm, }; use talc_macros::native_func; diff --git a/talc-std/src/format.rs b/talc-std/src/format.rs index afc9829..3f6f9ab 100644 --- a/talc-std/src/format.rs +++ b/talc-std/src/format.rs @@ -7,7 +7,7 @@ use talc_lang::{ symbol::SYM_TYPE_ERROR, throw, value::{Complex64, Rational64, Value}, - Vm, + vm::Vm, }; use talc_macros::native_func; diff --git a/talc-std/src/io.rs b/talc-std/src/io.rs index 8a047ae..f63e559 100644 --- a/talc-std/src/io.rs +++ b/talc-std/src/io.rs @@ -10,7 +10,8 @@ use talc_lang::{ lstring::LString, symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, value::Value, - vmcall, Vm, + vm::Vm, + vmcall, }; use talc_macros::native_func; diff --git a/talc-std/src/iter.rs b/talc-std/src/iter.rs index 081a50d..26e3adc 100644 --- a/talc-std/src/iter.rs +++ b/talc-std/src/iter.rs @@ -5,7 +5,8 @@ use talc_lang::{ symbol::{symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{function::NativeFunc, ops::RatioExt, range::RangeType, HashValue, Value}, - vmcall, vmcalliter, Vm, + vm::Vm, + vmcall, vmcalliter, }; use talc_macros::native_func; diff --git a/talc-std/src/lib.rs b/talc-std/src/lib.rs index 1d3a8bb..7195381 100644 --- a/talc-std/src/lib.rs +++ b/talc-std/src/lib.rs @@ -2,7 +2,7 @@ use talc_lang::{ symbol::{symbol, Symbol}, - Vm, + vm::Vm, }; pub mod collection; @@ -12,25 +12,29 @@ pub mod format; pub mod io; pub mod iter; pub mod num; -#[cfg(feature = "random")] -pub mod random; -pub mod regex; pub mod string; pub mod value; +#[cfg(feature = "rand")] +pub mod random; +#[cfg(feature = "regex")] +pub mod regex; + pub fn load_all(vm: &mut Vm) { - value::load(vm); - exception::load(vm); - iter::load(vm); collection::load(vm); - num::load(vm); - io::load(vm); - string::load(vm); - format::load(vm); - regex::load(vm); + exception::load(vm); file::load(vm); - #[cfg(feature = "random")] + format::load(vm); + io::load(vm); + iter::load(vm); + num::load(vm); + string::load(vm); + value::load(vm); + + #[cfg(feature = "rand")] random::load(vm); + #[cfg(feature = "regex")] + regex::load(vm); } lazy_static::lazy_static! { diff --git a/talc-std/src/num.rs b/talc-std/src/num.rs index 4109826..f33155e 100644 --- a/talc-std/src/num.rs +++ b/talc-std/src/num.rs @@ -7,7 +7,8 @@ use talc_lang::{ symbol::{Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{ops::RatioExt, Complex64, Value}, - vmcalliter, Vm, + vm::Vm, + vmcalliter, }; use talc_macros::native_func; diff --git a/talc-std/src/random.rs b/talc-std/src/random.rs index 72f1826..6ead898 100644 --- a/talc-std/src/random.rs +++ b/talc-std/src/random.rs @@ -4,7 +4,8 @@ use talc_lang::{ symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{range::RangeType, Value}, - vmcalliter, Vm, + vm::Vm, + vmcalliter, }; use talc_macros::native_func; diff --git a/talc-std/src/regex.rs b/talc-std/src/regex.rs index 2c74310..48ddead 100644 --- a/talc-std/src/regex.rs +++ b/talc-std/src/regex.rs @@ -8,7 +8,7 @@ use talc_lang::{ symbol::{Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{NativeValue, Value}, - Vm, + vm::Vm, }; use talc_macros::native_func; diff --git a/talc-std/src/string.rs b/talc-std/src/string.rs index 4304d11..6efa92c 100644 --- a/talc-std/src/string.rs +++ b/talc-std/src/string.rs @@ -4,7 +4,7 @@ use talc_lang::{ symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::Value, - Vm, + vm::Vm, }; use talc_macros::native_func; diff --git a/talc-std/src/value.rs b/talc-std/src/value.rs index e509b78..a6c7f32 100644 --- a/talc-std/src/value.rs +++ b/talc-std/src/value.rs @@ -7,7 +7,7 @@ use talc_lang::{ symbol::{symbol, Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{ops::RatioExt, HashValue, Rational64, Value}, - Vm, + vm::Vm, }; use talc_macros::native_func;