changes
This commit is contained in:
parent
2b116296bc
commit
d0eedfd810
33 changed files with 159 additions and 142 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
members = ["talc-lang", "talc-bin", "talc-std", "talc-macros"]
|
||||
resolver = "2"
|
||||
|
||||
[profile.release]
|
||||
|
||||
[profile.release-opt]
|
||||
inherits = "release"
|
||||
lto = "fat"
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
## installation
|
||||
|
||||
```sh
|
||||
cargo install --profile release-lto --path talc-bin
|
||||
cargo install --profile release-opt --path talc-bin
|
||||
```
|
||||
|
|
|
@ -10,7 +10,7 @@ use rustyline::{
|
|||
use talc_lang::{
|
||||
lstring::LStr,
|
||||
parser::{Lexer, Pos, Span, TokenKind},
|
||||
Vm,
|
||||
vm::Vm,
|
||||
};
|
||||
|
||||
pub struct TalcHelper {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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<Symbol, Var>,
|
||||
shadowed: Vec<(Symbol, Option<Var>)>,
|
||||
scope: HashMap<Symbol, VarKind>,
|
||||
shadowed: Vec<(Symbol, Option<VarKind>)>,
|
||||
closes: Vec<(Symbol, usize)>,
|
||||
local_count: usize,
|
||||
// break and continue
|
||||
|
@ -87,22 +81,16 @@ pub fn compile(expr: &Expr, name: Option<Symbol>) -> Result<Function> {
|
|||
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);
|
||||
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("<repl>")),
|
||||
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<Symbol>) {
|
||||
fn finish_repl(mut self, globals: &mut Vec<Symbol>) -> 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)));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ pub enum BinaryOp {
|
|||
pub enum UnaryOp {
|
||||
Neg,
|
||||
Not,
|
||||
BitNot,
|
||||
RangeEndless,
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -54,7 +54,7 @@ macro_rules! throw {
|
|||
}
|
||||
|
||||
impl TokenKind {
|
||||
pub fn assign_op(self) -> Option<Option<BinaryOp>> {
|
||||
fn assign_op(self) -> Option<Option<BinaryOp>> {
|
||||
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<BinaryOp> {
|
||||
fn binary_op(self) -> Option<BinaryOp> {
|
||||
Some(match self {
|
||||
T::EqualEqual => BinaryOp::Eq,
|
||||
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 {
|
||||
T::Minus => Some(UnaryOp::Neg),
|
||||
T::Not => Some(UnaryOp::Not),
|
||||
T::Tilde => Some(UnaryOp::BitNot),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn postfix_unary_op(self) -> Option<UnaryOp> {
|
||||
fn postfix_unary_op(self) -> Option<UnaryOp> {
|
||||
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<Expr> {
|
||||
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,
|
||||
..
|
||||
}) => {
|
||||
|
|
|
@ -12,6 +12,7 @@ struct SymbolTable {
|
|||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SYM_REPL: Symbol = symbol!("<repl>");
|
||||
pub static ref SYM_SELF: Symbol = symbol!(self);
|
||||
pub static ref SYM_DOLLAR_SIGN: Symbol = symbol!("$");
|
||||
pub static ref SYM_NIL: Symbol = symbol!(nil);
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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)) => {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<Value> 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<Value> 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<Value> 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<Value> 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<Value> 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<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:#}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Value> {
|
|||
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();
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use talc_lang::{
|
|||
symbol::SYM_TYPE_ERROR,
|
||||
throw,
|
||||
value::{Complex64, Rational64, Value},
|
||||
Vm,
|
||||
vm::Vm,
|
||||
};
|
||||
use talc_macros::native_func;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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! {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue