This commit is contained in:
trimill 2024-11-14 14:16:33 -05:00
parent 2b116296bc
commit d0eedfd810
33 changed files with 159 additions and 142 deletions

12
Cargo.lock generated
View file

@ -55,9 +55,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.20" version = "4.5.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -65,9 +65,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.20" version = "4.5.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"clap_lex", "clap_lex",
@ -87,9 +87,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.7.2" version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
[[package]] [[package]]
name = "clipboard-win" name = "clipboard-win"

View file

@ -2,8 +2,6 @@
members = ["talc-lang", "talc-bin", "talc-std", "talc-macros"] members = ["talc-lang", "talc-bin", "talc-std", "talc-macros"]
resolver = "2" resolver = "2"
[profile.release]
[profile.release-opt] [profile.release-opt]
inherits = "release" inherits = "release"
lto = "fat" lto = "fat"

View file

@ -3,5 +3,5 @@
## installation ## installation
```sh ```sh
cargo install --profile release-lto --path talc-bin cargo install --profile release-opt --path talc-bin
``` ```

View file

@ -10,7 +10,7 @@ use rustyline::{
use talc_lang::{ use talc_lang::{
lstring::LStr, lstring::LStr,
parser::{Lexer, Pos, Span, TokenKind}, parser::{Lexer, Pos, Span, TokenKind},
Vm, vm::Vm,
}; };
pub struct TalcHelper { pub struct TalcHelper {

View file

@ -3,10 +3,11 @@ use std::{path::PathBuf, process::ExitCode, rc::Rc};
use talc_lang::{ use talc_lang::{
compiler::compile, compiler::compile,
lstring::LString, lstring::LString,
optimize, parser, serial, optimize::optimize,
parser, serial,
symbol::Symbol, symbol::Symbol,
value::{function::disasm_recursive, Value}, value::{function::disasm_recursive, Value},
Vm, vm::Vm,
}; };
mod helper; mod helper;

View file

@ -8,10 +8,12 @@ use rustyline::{
}; };
use talc_lang::{ use talc_lang::{
compiler::compile_repl, compiler::compile_repl,
lstr, optimize, parser, lstr,
optimize::optimize,
parser,
symbol::{symbol, Symbol}, symbol::{symbol, Symbol},
value::{function::disasm_recursive, Value}, value::{function::disasm_recursive, Value},
Vm, vm::Vm,
}; };
use crate::{helper::TalcHelper, Args}; use crate::{helper::TalcHelper, Args};
@ -117,17 +119,14 @@ fn exec_line(
eprintln!("{}", ex); eprintln!("{}", ex);
} }
let (f, g) = match compile_repl(&ex, globals) { let func = match compile_repl(&ex, globals) {
Ok(pair) => pair, Ok(f) => Rc::new(f),
Err(e) => { Err(e) => {
eprintln!("{}Error:{} {e}", c.error, c.reset); eprintln!("{}Error:{} {e}", c.error, c.reset);
return return
} }
}; };
*globals = g;
let func = Rc::new(f);
if args.disasm { if args.disasm {
if let Err(e) = disasm_recursive(&func, &mut std::io::stderr()) { if let Err(e) = disasm_recursive(&func, &mut std::io::stderr()) {
eprintln!("{}Error:{} {e}", c.error, c.reset); eprintln!("{}Error:{} {e}", c.error, c.reset);

View file

@ -9,5 +9,3 @@ num-rational = { version = "0.4", default-features = false, features = [] }
num-traits = "0.2" num-traits = "0.2"
lazy_static = "1.5" lazy_static = "1.5"
unicode-ident = "1.0" unicode-ident = "1.0"
[build-dependencies]

View file

@ -5,7 +5,7 @@ use std::rc::Rc;
use crate::chunk::{Arg24, Catch, Chunk, Instruction as I}; use crate::chunk::{Arg24, Catch, Chunk, Instruction as I};
use crate::parser::ast::{BinaryOp, CatchBlock, Expr, ExprKind, LValue, LValueKind}; use crate::parser::ast::{BinaryOp, CatchBlock, Expr, ExprKind, LValue, LValueKind};
use crate::parser::Pos; use crate::parser::Pos;
use crate::symbol::{Symbol, SYM_SELF}; use crate::symbol::{Symbol, SYM_REPL, SYM_SELF};
use crate::throw; use crate::throw;
use crate::value::function::{FuncAttrs, Function}; use crate::value::function::{FuncAttrs, Function};
use crate::value::Value; use crate::value::Value;
@ -39,18 +39,12 @@ enum ResolveOutcome {
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum VarKind { enum VarKind {
Local(usize), Local(usize),
Closed(usize), Closed(usize),
Global, Global,
} }
#[derive(Debug, Clone)]
pub struct Var {
name: Symbol,
kind: VarKind,
}
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
enum CompilerMode { enum CompilerMode {
Function, Function,
@ -72,8 +66,8 @@ struct Compiler<'a> {
chunk: Chunk, chunk: Chunk,
attrs: FuncAttrs, attrs: FuncAttrs,
// variables // variables
scope: HashMap<Symbol, Var>, scope: HashMap<Symbol, VarKind>,
shadowed: Vec<(Symbol, Option<Var>)>, shadowed: Vec<(Symbol, Option<VarKind>)>,
closes: Vec<(Symbol, usize)>, closes: Vec<(Symbol, usize)>,
local_count: usize, local_count: usize,
// break and continue // break and continue
@ -87,22 +81,16 @@ pub fn compile(expr: &Expr, name: Option<Symbol>) -> Result<Function> {
Ok(comp.finish()) Ok(comp.finish())
} }
pub fn compile_repl(expr: &Expr, globals: &[Symbol]) -> Result<(Function, Vec<Symbol>)> { pub fn compile_repl(expr: &Expr, globals: &mut Vec<Symbol>) -> Result<Function> {
let mut comp = Compiler::new_repl(globals); let mut comp = Compiler::new_repl(globals);
comp.expr(expr)?; comp.expr(expr)?;
Ok(comp.finish_repl()) Ok(comp.finish_repl(globals))
} }
impl<'a> Default for Compiler<'a> { impl<'a> Default for Compiler<'a> {
fn default() -> Self { fn default() -> Self {
let mut scope = HashMap::new(); let mut scope = HashMap::new();
scope.insert( scope.insert(*SYM_SELF, VarKind::Local(0));
*SYM_SELF,
Var {
name: *SYM_SELF,
kind: VarKind::Local(0),
},
);
Self { Self {
mode: CompilerMode::Function, mode: CompilerMode::Function,
parent: None, parent: None,
@ -124,7 +112,7 @@ impl<'a> Compiler<'a> {
mode: CompilerMode::Repl, mode: CompilerMode::Repl,
attrs: FuncAttrs { attrs: FuncAttrs {
arity: 0, arity: 0,
name: Some(Symbol::get("<repl>")), name: Some(*SYM_REPL),
}, },
..Self::default() ..Self::default()
}; };
@ -162,30 +150,29 @@ impl<'a> Compiler<'a> {
new new
} }
pub fn finish(mut self) -> Function { fn finish(mut self) -> Function {
self.emit(I::Return); self.emit(I::Return);
Function::new(Rc::new(self.chunk), self.attrs, self.closes.len()) 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); self.emit(I::Return);
// TODO closure
( (
Function::new(Rc::new(self.chunk), self.attrs, self.closes.len()), Function::new(Rc::new(self.chunk), self.attrs, self.closes.len()),
self.closes, self.closes,
) )
} }
pub fn finish_repl(mut self) -> (Function, Vec<Symbol>) { fn finish_repl(mut self, globals: &mut Vec<Symbol>) -> Function {
self.emit(I::Return); self.emit(I::Return);
(
// TODO closure globals.clear();
Function::new(Rc::new(self.chunk), self.attrs, self.closes.len()), for (name, kind) in self.scope.iter() {
self.scope if *kind == VarKind::Global {
.into_iter() globals.push(*name);
.filter_map(|(_, v)| (v.kind == VarKind::Global).then_some(v.name)) }
.collect(), }
) 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"); let (name, var) = self.shadowed.pop().expect("scope bad");
if let Some(in_var) = self.scope.get(&name) { if let Some(in_var) = self.scope.get(&name) {
if in_var.kind != VarKind::Global { if *in_var != VarKind::Global {
locals += 1; locals += 1;
} }
} }
@ -329,8 +316,8 @@ impl<'a> Compiler<'a> {
// //
fn resolve_name(&self, name: Symbol) -> ResolveOutcome { fn resolve_name(&self, name: Symbol) -> ResolveOutcome {
if let Some(v) = self.scope.get(&name) { if let Some(kind) = self.scope.get(&name) {
return ResolveOutcome::Var(v.kind) return ResolveOutcome::Var(*kind)
} }
let Some(parent) = self.parent else { let Some(parent) = self.parent else {
return ResolveOutcome::None return ResolveOutcome::None
@ -369,10 +356,7 @@ impl<'a> Compiler<'a> {
} }
fn declare_local(&mut self, name: Symbol) -> usize { fn declare_local(&mut self, name: Symbol) -> usize {
let local = Var { let local = VarKind::Local(self.local_count);
name,
kind: VarKind::Local(self.local_count),
};
self.local_count += 1; self.local_count += 1;
let shadowed = self.scope.insert(name, local); let shadowed = self.scope.insert(name, local);
self.shadowed.push((name, shadowed)); self.shadowed.push((name, shadowed));
@ -391,11 +375,7 @@ impl<'a> Compiler<'a> {
} }
fn declare_global(&mut self, name: Symbol) { fn declare_global(&mut self, name: Symbol) {
let global = Var { let shadowed = self.scope.insert(name, VarKind::Global);
name,
kind: VarKind::Global,
};
let shadowed = self.scope.insert(name, global);
self.shadowed.push((name, shadowed)); self.shadowed.push((name, shadowed));
} }
@ -752,9 +732,7 @@ impl<'a> Compiler<'a> {
match self.resolve_name(name) { match self.resolve_name(name) {
ResolveOutcome::Var(VarKind::Local(n)) => { ResolveOutcome::Var(VarKind::Local(n)) => {
self.emit(I::CloseOver(Arg24::from_usize(n))); self.emit(I::CloseOver(Arg24::from_usize(n)));
self.scope.entry(name).and_modify(|v| { self.scope.insert(name, VarKind::Closed(n));
v.kind = VarKind::Closed(n);
});
} }
ResolveOutcome::Var(VarKind::Closed(n)) => { ResolveOutcome::Var(VarKind::Closed(n)) => {
self.emit(I::LoadLocal(Arg24::from_usize(n))); self.emit(I::LoadLocal(Arg24::from_usize(n)));

View file

@ -8,12 +8,9 @@ pub mod chunk;
pub mod compiler; pub mod compiler;
pub mod exception; pub mod exception;
pub mod lstring; pub mod lstring;
mod optimize; pub mod optimize;
pub use optimize::optimize;
pub mod parser; pub mod parser;
pub mod serial; pub mod serial;
pub mod symbol; pub mod symbol;
pub mod value; pub mod value;
pub mod vm;
mod vm;
pub use vm::Vm;

View file

@ -27,12 +27,12 @@ struct OptState {
impl OptState { impl OptState {
#[inline] #[inline]
pub const fn empty() -> Self { const fn empty() -> Self {
Self { ret: false } Self { ret: false }
} }
#[inline] #[inline]
pub const fn ret(ret: bool) -> Self { const fn ret(ret: bool) -> Self {
Self { ret } 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 { match &mut e.kind {
LValueKind::Ident(_) => (), LValueKind::Ident(_) => (),
LValueKind::Index(l, r) => { 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); optimize_ex(&mut e.body);
} }

View file

@ -34,6 +34,7 @@ pub enum BinaryOp {
pub enum UnaryOp { pub enum UnaryOp {
Neg, Neg,
Not, Not,
BitNot,
RangeEndless, RangeEndless,
} }

View file

@ -11,7 +11,7 @@ pub enum TokenKind {
Eof, Eof,
LineSeparator, LineSeparator,
Bang, Tilde,
BangEqual, BangEqual,
HashAmper, HashAmper,
HashAmperEqual, HashAmperEqual,
@ -42,7 +42,6 @@ pub enum TokenKind {
SlashSlash, SlashSlash,
SlashSlashEqual, SlashSlashEqual,
SlashEqual, SlashEqual,
Colon,
Less, Less,
LessLess, LessLess,
LessLessEqual, LessLessEqual,
@ -101,7 +100,7 @@ impl TokenKind {
match self { match self {
K::Eof => "end of file", K::Eof => "end of file",
K::LineSeparator => "line separator", K::LineSeparator => "line separator",
K::Bang => "'!'", K::Tilde => "'~'",
K::BangEqual => "'!='", K::BangEqual => "'!='",
K::HashAmper => "'#&'", K::HashAmper => "'#&'",
K::HashAmperEqual => "'#&='", K::HashAmperEqual => "'#&='",
@ -123,7 +122,7 @@ impl TokenKind {
K::Comma => "','", K::Comma => "','",
K::Minus => "'-'", K::Minus => "'-'",
K::MinusEqual => "'-='", K::MinusEqual => "'-='",
K::Arrow => "'=>'", K::Arrow => "'->'",
K::Dot => "'.'", K::Dot => "'.'",
K::DotDot => "'..'", K::DotDot => "'..'",
K::DotDotStar => "'..*'", K::DotDotStar => "'..*'",
@ -132,7 +131,6 @@ impl TokenKind {
K::SlashSlash => "'//'", K::SlashSlash => "'//'",
K::SlashSlashEqual => "'//='", K::SlashSlashEqual => "'//='",
K::SlashEqual => "'/='", K::SlashEqual => "'/='",
K::Colon => "':'",
K::Less => "'<'", K::Less => "'<'",
K::LessLess => "'<<'", K::LessLess => "'<<'",
K::LessLessEqual => "'<<='", K::LessLessEqual => "'<<='",
@ -526,11 +524,12 @@ impl<'s> Lexer<'s> {
'!' => self.line_comment(), '!' => self.line_comment(),
_ => self.unexpected(), _ => self.unexpected(),
}, },
// lists '~' => self.and_emit(K::Tilde),
'!' => match self.and_peek()? { '!' => match self.and_peek()? {
'=' => self.and_emit(K::BangEqual), '=' => self.and_emit(K::BangEqual),
_ => self.emit(K::Bang), _ => self.unexpected(),
}, },
// lists
'&' => match self.and_peek()? { '&' => match self.and_peek()? {
'=' => self.and_emit(K::AmperEqual), '=' => self.and_emit(K::AmperEqual),
_ => self.emit(K::Amper), _ => self.emit(K::Amper),
@ -569,7 +568,7 @@ impl<'s> Lexer<'s> {
c if is_xid_start(c) || c == '_' || c == '"' || c == '\'' => { c if is_xid_start(c) || c == '_' || c == '"' || c == '\'' => {
self.next_symbol() self.next_symbol()
} }
_ => self.emit(K::Colon), _ => self.unexpected(),
}, },
'0'..='9' => self.next_number(), '0'..='9' => self.next_number(),
c if c == '_' || is_xid_start(c) => self.next_ident(), c if c == '_' || is_xid_start(c) => self.next_ident(),

View file

@ -54,7 +54,7 @@ macro_rules! throw {
} }
impl TokenKind { impl TokenKind {
pub fn assign_op(self) -> Option<Option<BinaryOp>> { fn assign_op(self) -> Option<Option<BinaryOp>> {
Some(match self { Some(match self {
T::PlusPlusEqual => Some(BinaryOp::Concat), T::PlusPlusEqual => Some(BinaryOp::Concat),
T::AmperEqual => Some(BinaryOp::Append), T::AmperEqual => Some(BinaryOp::Append),
@ -75,7 +75,7 @@ impl TokenKind {
}) })
} }
pub fn binary_op(self) -> Option<BinaryOp> { fn binary_op(self) -> Option<BinaryOp> {
Some(match self { Some(match self {
T::EqualEqual => BinaryOp::Eq, T::EqualEqual => BinaryOp::Eq,
T::BangEqual => BinaryOp::Ne, T::BangEqual => BinaryOp::Ne,
@ -103,15 +103,16 @@ impl TokenKind {
}) })
} }
pub fn unary_op(self) -> Option<UnaryOp> { fn unary_op(self) -> Option<UnaryOp> {
match self { match self {
T::Minus => Some(UnaryOp::Neg), T::Minus => Some(UnaryOp::Neg),
T::Not => Some(UnaryOp::Not), T::Not => Some(UnaryOp::Not),
T::Tilde => Some(UnaryOp::BitNot),
_ => None, _ => None,
} }
} }
pub fn postfix_unary_op(self) -> Option<UnaryOp> { fn postfix_unary_op(self) -> Option<UnaryOp> {
match self { match self {
T::DotDotStar => Some(UnaryOp::RangeEndless), T::DotDotStar => Some(UnaryOp::RangeEndless),
_ => None, _ => None,
@ -120,17 +121,17 @@ impl TokenKind {
} }
impl UnaryOp { impl UnaryOp {
pub fn precedence(self) -> u8 { fn precedence(self) -> u8 {
match self { match self {
UnaryOp::Not => 0, UnaryOp::Not => 0,
UnaryOp::RangeEndless => 40, UnaryOp::RangeEndless => 40,
UnaryOp::Neg => 110, UnaryOp::Neg | UnaryOp::BitNot => 110,
} }
} }
} }
impl BinaryOp { impl BinaryOp {
pub fn precedence(self) -> (u8, u8) { fn precedence(self) -> (u8, u8) {
match self { match self {
BinaryOp::Eq BinaryOp::Eq
| BinaryOp::Ne | BinaryOp::Ne
@ -166,8 +167,8 @@ impl TokenKind {
| T::Break | T::Var | T::Break | T::Var
| T::Global | T::Fn | T::Global | T::Fn
| T::Not | T::Backslash | T::Not | T::Backslash
| T::Colon | T::Minus | T::Amper | T::Minus
| T::Identifier | T::Tilde | T::Identifier
| T::LParen | T::LBrack | T::LParen | T::LBrack
| T::LBrace | T::Dollar | T::LBrace | T::Dollar
| T::Do | T::If | T::Do | T::If
@ -494,7 +495,7 @@ impl<'s> Parser<'s> {
} }
fn parse_lambda(&mut self) -> Result<Expr> { fn parse_lambda(&mut self) -> Result<Expr> {
let tok = try_next!(self, T::Backslash | T::Colon); let tok = try_next!(self, T::Backslash | T::Amper);
match tok { match tok {
Some(Token { Some(Token {
kind: T::Backslash, kind: T::Backslash,
@ -502,13 +503,13 @@ impl<'s> Parser<'s> {
.. ..
}) => { }) => {
let args = self.parse_ident_list()?; let args = self.parse_ident_list()?;
expect!(self, T::Arrow); expect!(self, T::Dot);
let body = self.parse_lambda()?; let body = self.parse_lambda()?;
let body_span = body.span; let body_span = body.span;
Ok(E::Lambda(args, b(body)).span(span + body_span)) Ok(E::Lambda(args, b(body)).span(span + body_span))
} }
Some(Token { Some(Token {
kind: T::Colon, kind: T::Amper,
span, span,
.. ..
}) => { }) => {

View file

@ -12,6 +12,7 @@ struct SymbolTable {
} }
lazy_static! { lazy_static! {
pub static ref SYM_REPL: Symbol = symbol!("<repl>");
pub static ref SYM_SELF: Symbol = symbol!(self); pub static ref SYM_SELF: Symbol = symbol!(self);
pub static ref SYM_DOLLAR_SIGN: Symbol = symbol!("$"); pub static ref SYM_DOLLAR_SIGN: Symbol = symbol!("$");
pub static ref SYM_NIL: Symbol = symbol!(nil); pub static ref SYM_NIL: Symbol = symbol!(nil);

View file

@ -1,6 +1,6 @@
use std::{cell::RefCell, rc::Rc}; 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}; use super::{CellValue, Value};

View file

@ -2,7 +2,8 @@ use crate::{
exception::{throw, Result}, exception::{throw, Result},
symbol::{symbol, SYM_END_ITERATION, SYM_INDEX_ERROR, SYM_TYPE_ERROR}, symbol::{symbol, SYM_END_ITERATION, SYM_INDEX_ERROR, SYM_TYPE_ERROR},
value::function::NativeFunc, value::function::NativeFunc,
vmcalliter, Vm, vm::Vm,
vmcalliter,
}; };
use super::{range::RangeType, Value}; use super::{range::RangeType, Value};
@ -126,7 +127,11 @@ impl Value {
(V::Table(t), i) if i.hashable() => { (V::Table(t), i) if i.hashable() => {
let mut t = t.borrow_mut(); let mut t = t.borrow_mut();
let i = i.try_into()?; let i = i.try_into()?;
if val == Value::Nil {
t.remove(&i);
} else {
t.insert(i, val); t.insert(i, val);
}
Ok(()) Ok(())
} }
(V::List(t), V::Range(r)) => { (V::List(t), V::Range(r)) => {

View file

@ -169,6 +169,9 @@ impl Value {
if recur.contains(&(t.as_ptr() as _)) { if recur.contains(&(t.as_ptr() as _)) {
return w.write_all(b"{...}") return w.write_all(b"{...}")
} }
if t.borrow().len() == 0 {
return w.write_all(b"{}")
}
w.write_all(b"{ ")?; w.write_all(b"{ ")?;
recur.push(t.as_ptr() as _); recur.push(t.as_ptr() as _);
for (i, (k, v)) in t.borrow().iter().enumerate() { for (i, (k, v)) in t.borrow().iter().enumerate() {
@ -176,7 +179,7 @@ impl Value {
w.write_all(b", ")?; w.write_all(b", ")?;
} }
k.0.write_table_key_repr(w, recur)?; k.0.write_table_key_repr(w, recur)?;
w.write_all(b" = ")?; w.write_all(b"=")?;
v.write_to_lstring(w, true, recur)?; v.write_to_lstring(w, true, recur)?;
} }
recur.pop(); recur.pop();

View file

@ -1,7 +1,7 @@
use std::{ use std::{
cell::RefCell, cell::RefCell,
cmp::Ordering, 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, rc::Rc,
}; };
@ -14,7 +14,7 @@ use crate::{
lstring::LString, lstring::LString,
symbol::{symbol, SYM_END_ITERATION, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, symbol::{symbol, SYM_END_ITERATION, SYM_TYPE_ERROR, SYM_VALUE_ERROR},
value::range::RangeType, value::range::RangeType,
Vm, vm::Vm,
}; };
use super::{ use super::{
@ -388,7 +388,9 @@ impl Shl<Value> for Value {
fn shl(self, rhs: Value) -> Self::Output { fn shl(self, rhs: Value) -> Self::Output {
use Value as V; use Value as V;
match (self, rhs) { 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:#}"), (l, r) => throw!(*SYM_TYPE_ERROR, "cannot shift {l:#} left by {r:#}"),
} }
} }
@ -400,7 +402,9 @@ impl Shr<Value> for Value {
fn shr(self, rhs: Value) -> Self::Output { fn shr(self, rhs: Value) -> Self::Output {
use Value as V; use Value as V;
match (self, rhs) { 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:#}"), (l, r) => throw!(*SYM_TYPE_ERROR, "cannot shift {l:#} right by {r:#}"),
} }
} }
@ -413,7 +417,7 @@ impl BitAnd<Value> for Value {
use Value as V; use Value as V;
match (self, rhs) { match (self, rhs) {
(V::Int(a), V::Int(b)) => Ok(Value::Int(a & b)), (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<Value> for Value {
use Value as V; use Value as V;
match (self, rhs) { match (self, rhs) {
(V::Int(a), V::Int(b)) => Ok(Value::Int(a ^ b)), (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<Value> for Value {
use Value as V; use Value as V;
match (self, rhs) { match (self, rhs) {
(V::Int(a), V::Int(b)) => Ok(Value::Int(a | b)), (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<Value>;
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:#}"),
} }
} }
} }

View file

@ -1,6 +1,7 @@
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::HashMap, collections::HashMap,
ops::Not,
rc::Rc, rc::Rc,
sync::{atomic::AtomicBool, Arc}, sync::{atomic::AtomicBool, Arc},
}; };
@ -84,6 +85,7 @@ pub fn unary_op(o: UnaryOp, a: Value) -> Result<Value> {
match o { match o {
UnaryOp::Neg => -a, UnaryOp::Neg => -a,
UnaryOp::Not => Ok(Value::Bool(!a.truthy())), UnaryOp::Not => Ok(Value::Bool(!a.truthy())),
UnaryOp::BitNot => a.not(),
UnaryOp::RangeEndless => a.range_endless(), UnaryOp::RangeEndless => a.range_endless(),
} }
} }
@ -243,7 +245,7 @@ impl Vm {
res res
} }
fn check_interrupt(&mut self) -> Result<()> { pub fn check_interrupt(&mut self) -> Result<()> {
if self if self
.interrupt .interrupt
.fetch_and(false, std::sync::atomic::Ordering::Relaxed) .fetch_and(false, std::sync::atomic::Ordering::Relaxed)
@ -399,8 +401,12 @@ impl Vm {
for _ in 0..n { for _ in 0..n {
let v = self.pop(); let v = self.pop();
let k = self.pop(); let k = self.pop();
if v == Value::Nil {
table.remove(&k.try_into()?);
} else {
table.insert(k.try_into()?, v); table.insert(k.try_into()?, v);
} }
}
self.push(table.into()); self.push(table.into());
} }
// [t,k0,v0...kn,vn] -> [t ++ {k0=v0...kn=vn}] // [t,k0,v0...kn,vn] -> [t ++ {k0=v0...kn=vn}]
@ -415,18 +421,22 @@ impl Vm {
// can't panic: pop_n checked that ext would have len 2*n // can't panic: pop_n checked that ext would have len 2*n
let v = ext.pop().unwrap(); let v = ext.pop().unwrap();
let k = ext.pop().unwrap(); let k = ext.pop().unwrap();
if v == Value::Nil {
table_ref.remove(&k.try_into()?);
} else {
table_ref.insert(k.try_into()?, v); table_ref.insert(k.try_into()?, v);
} }
}
drop(table_ref); drop(table_ref);
self.push(Value::Table(table)); self.push(Value::Table(table));
} }
// [ct, idx] -> [ct!idx] // [ct, idx] -> [ct[idx]]
I::Index => { I::Index => {
let idx = self.pop(); let idx = self.pop();
let ct = self.pop(); let ct = self.pop();
self.push(ct.index(idx)?); self.push(ct.index(idx)?);
} }
// [ct, idx, v] -> [v], ct!idx = v // [ct, idx, v] -> [v], ct[idx] = v
I::StoreIndex => { I::StoreIndex => {
let v = self.pop(); let v = self.pop();
let idx = self.pop(); let idx = self.pop();

View file

@ -1,6 +1,6 @@
use std::rc::Rc; 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) { fn assert_eval(src: &str, value: Value) {
let mut ex = parser::parse(src).expect(&format!("failed to parse expression")); let mut ex = parser::parse(src).expect(&format!("failed to parse expression"));
@ -88,7 +88,7 @@ fn closures() {
assert_eval( assert_eval(
" "
var x = 2 var x = 2
next = \\-> do x = x * 2 + 1 end next = \\. do x = x * 2 + 1 end
next() + next() + next() next() + next() + next()
", ",
Value::Int(5 + 11 + 23), Value::Int(5 + 11 + 23),

View file

@ -7,9 +7,10 @@ edition = "2021"
talc-lang = { path = "../talc-lang" } talc-lang = { path = "../talc-lang" }
talc-macros = { path = "../talc-macros" } talc-macros = { path = "../talc-macros" }
lazy_static = "1.5" lazy_static = "1.5"
regex = "1.11" regex = { version = "1.11", optional = true }
rand = { version = "0.8", optional = true } rand = { version = "0.8", optional = true }
[features] [features]
default = ["random"] default = ["rand", "regex"]
random = ["dep:rand"] rand = ["dep:rand"]
regex = ["dep:regex"]

View file

@ -5,7 +5,8 @@ use talc_lang::{
symbol::{symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, symbol::{symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR},
throw, throw,
value::{function::NativeFunc, Value}, value::{function::NativeFunc, Value},
vmcall, Vm, vm::Vm,
vmcall,
}; };
use talc_macros::native_func; use talc_macros::native_func;

View file

@ -2,7 +2,7 @@ use talc_lang::{
exception::{throw, Exception, Result}, exception::{throw, Exception, Result},
symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR},
value::Value, value::Value,
Vm, vm::Vm,
}; };
use talc_macros::native_func; use talc_macros::native_func;

View file

@ -16,7 +16,7 @@ use talc_lang::{
symbol::{symbol, Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, symbol::{symbol, Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR},
throw, throw,
value::{function::NativeFunc, HashValue, NativeValue, Value}, value::{function::NativeFunc, HashValue, NativeValue, Value},
Vm, vm::Vm,
}; };
use talc_macros::native_func; use talc_macros::native_func;

View file

@ -7,7 +7,7 @@ use talc_lang::{
symbol::SYM_TYPE_ERROR, symbol::SYM_TYPE_ERROR,
throw, throw,
value::{Complex64, Rational64, Value}, value::{Complex64, Rational64, Value},
Vm, vm::Vm,
}; };
use talc_macros::native_func; use talc_macros::native_func;

View file

@ -10,7 +10,8 @@ use talc_lang::{
lstring::LString, lstring::LString,
symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR},
value::Value, value::Value,
vmcall, Vm, vm::Vm,
vmcall,
}; };
use talc_macros::native_func; use talc_macros::native_func;

View file

@ -5,7 +5,8 @@ use talc_lang::{
symbol::{symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, symbol::{symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR},
throw, throw,
value::{function::NativeFunc, ops::RatioExt, range::RangeType, HashValue, Value}, value::{function::NativeFunc, ops::RatioExt, range::RangeType, HashValue, Value},
vmcall, vmcalliter, Vm, vm::Vm,
vmcall, vmcalliter,
}; };
use talc_macros::native_func; use talc_macros::native_func;

View file

@ -2,7 +2,7 @@
use talc_lang::{ use talc_lang::{
symbol::{symbol, Symbol}, symbol::{symbol, Symbol},
Vm, vm::Vm,
}; };
pub mod collection; pub mod collection;
@ -12,25 +12,29 @@ pub mod format;
pub mod io; pub mod io;
pub mod iter; pub mod iter;
pub mod num; pub mod num;
#[cfg(feature = "random")]
pub mod random;
pub mod regex;
pub mod string; pub mod string;
pub mod value; pub mod value;
#[cfg(feature = "rand")]
pub mod random;
#[cfg(feature = "regex")]
pub mod regex;
pub fn load_all(vm: &mut Vm) { pub fn load_all(vm: &mut Vm) {
value::load(vm);
exception::load(vm);
iter::load(vm);
collection::load(vm); collection::load(vm);
num::load(vm); exception::load(vm);
io::load(vm);
string::load(vm);
format::load(vm);
regex::load(vm);
file::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); random::load(vm);
#[cfg(feature = "regex")]
regex::load(vm);
} }
lazy_static::lazy_static! { lazy_static::lazy_static! {

View file

@ -7,7 +7,8 @@ use talc_lang::{
symbol::{Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, symbol::{Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR},
throw, throw,
value::{ops::RatioExt, Complex64, Value}, value::{ops::RatioExt, Complex64, Value},
vmcalliter, Vm, vm::Vm,
vmcalliter,
}; };
use talc_macros::native_func; use talc_macros::native_func;

View file

@ -4,7 +4,8 @@ use talc_lang::{
symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR},
throw, throw,
value::{range::RangeType, Value}, value::{range::RangeType, Value},
vmcalliter, Vm, vm::Vm,
vmcalliter,
}; };
use talc_macros::native_func; use talc_macros::native_func;

View file

@ -8,7 +8,7 @@ use talc_lang::{
symbol::{Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, symbol::{Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR},
throw, throw,
value::{NativeValue, Value}, value::{NativeValue, Value},
Vm, vm::Vm,
}; };
use talc_macros::native_func; use talc_macros::native_func;

View file

@ -4,7 +4,7 @@ use talc_lang::{
symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR},
throw, throw,
value::Value, value::Value,
Vm, vm::Vm,
}; };
use talc_macros::native_func; use talc_macros::native_func;

View file

@ -7,7 +7,7 @@ use talc_lang::{
symbol::{symbol, Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, symbol::{symbol, Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR},
throw, throw,
value::{ops::RatioExt, HashValue, Rational64, Value}, value::{ops::RatioExt, HashValue, Rational64, Value},
Vm, vm::Vm,
}; };
use talc_macros::native_func; use talc_macros::native_func;