fixes
This commit is contained in:
parent
a3001106ab
commit
e7716d038e
25 changed files with 107 additions and 364 deletions
70
Cargo.lock
generated
70
Cargo.lock
generated
|
@ -25,9 +25,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
|
@ -55,9 +55,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.23"
|
||||
version = "4.5.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
|
||||
checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -65,9 +65,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.23"
|
||||
version = "4.5.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
|
||||
checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
|
@ -75,9 +75,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.18"
|
||||
version = "4.5.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
||||
checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
|
@ -173,9 +173,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.76"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
|
@ -195,15 +195,15 @@ checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
|||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
|
@ -323,9 +323,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.92"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -410,9 +410,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.42"
|
||||
version = "0.38.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
|
||||
checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
|
@ -421,6 +421,12 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
|
||||
|
||||
[[package]]
|
||||
name = "rustyline"
|
||||
version = "15.0.0"
|
||||
|
@ -451,9 +457,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.95"
|
||||
version = "2.0.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
|
||||
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -543,20 +549,21 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.99"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.99"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
|
@ -568,9 +575,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.99"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -578,9 +585,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.99"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -591,9 +598,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.99"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
members = ["talc-lang", "talc-bin", "talc-std", "talc-macros", "talc-web"]
|
||||
resolver = "2"
|
||||
|
||||
|
||||
[workspace.lints.clippy]
|
||||
semicolon_if_nothing_returned = "warn"
|
||||
allow_attributes = "warn"
|
||||
|
@ -18,6 +17,8 @@ manual_assert = "warn"
|
|||
needless_pass_by_value = "warn"
|
||||
unnested_or_patterns = "warn"
|
||||
redundant_else = "warn"
|
||||
cast_possible_wrap = "warn"
|
||||
cast_possible_truncation = "warn"
|
||||
|
||||
|
||||
[profile.release-opt]
|
||||
|
|
|
@ -14,7 +14,7 @@ path = "src/main.rs"
|
|||
[dependencies]
|
||||
talc-lang = { path = "../talc-lang" }
|
||||
talc-std = { path = "../talc-std" }
|
||||
rustyline = "15.0"
|
||||
clap = { version = "4.5", features = ["std", "help", "usage", "derive", "error-context"], default-features = false }
|
||||
ctrlc = "3.4"
|
||||
lazy_static = "1.5"
|
||||
rustyline = "15"
|
||||
clap = { version = "4", features = ["std", "help", "usage", "derive", "error-context"], default-features = false }
|
||||
ctrlc = "3"
|
||||
lazy_static = "1"
|
||||
|
|
|
@ -53,7 +53,7 @@ impl Completer for TalcHelper {
|
|||
.map(LStr::to_string)
|
||||
.collect::<Vec<String>>();
|
||||
keys.sort();
|
||||
Ok((pos - res.as_bytes().len(), keys))
|
||||
Ok((pos - res.len(), keys))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ use talc_lang::{
|
|||
optimize::optimize,
|
||||
parser,
|
||||
prelude::*,
|
||||
serial,
|
||||
symbol::Symbol,
|
||||
value::{function::disasm_recursive, Value},
|
||||
vm::Vm,
|
||||
|
@ -30,10 +29,6 @@ struct Args {
|
|||
#[arg(short = 'a', long)]
|
||||
show_ast: bool,
|
||||
|
||||
/// Compile to a bytecode file
|
||||
#[arg(short, long)]
|
||||
compile: Option<PathBuf>,
|
||||
|
||||
/// Don't apply optimizations
|
||||
#[arg(long)]
|
||||
no_opt: bool,
|
||||
|
@ -86,26 +81,6 @@ fn exec(name: Symbol, src: &str, args: &Args) -> ExitCode {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(path) = &args.compile {
|
||||
let f = std::fs::File::options()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.create(true)
|
||||
.open(path);
|
||||
let mut w = match f {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
eprintln!("Error opening output file: {e}");
|
||||
return ExitCode::FAILURE
|
||||
}
|
||||
};
|
||||
if let Err(e) = serial::write_program(&mut w, &func) {
|
||||
eprintln!("Error writing bytecode: {e}");
|
||||
return ExitCode::FAILURE
|
||||
}
|
||||
return ExitCode::SUCCESS
|
||||
}
|
||||
|
||||
let res = vm.run_function(func.clone(), vec![func.into()]);
|
||||
|
||||
match res {
|
||||
|
@ -114,7 +89,7 @@ fn exec(name: Symbol, src: &str, args: &Args) -> ExitCode {
|
|||
ExitCode::FAILURE
|
||||
}
|
||||
Ok(Value::Bool(false)) => ExitCode::FAILURE,
|
||||
Ok(Value::Int(n)) => ExitCode::from(n.to_u64().unwrap_or(1) as u8),
|
||||
Ok(Value::Int(n)) => ExitCode::from(n.to_u64().unwrap_or(1).to_le_bytes()[0]),
|
||||
_ => ExitCode::SUCCESS,
|
||||
}
|
||||
}
|
||||
|
@ -123,10 +98,6 @@ fn main() -> ExitCode {
|
|||
let args = Args::parse();
|
||||
|
||||
if args.repl || args.args.is_empty() {
|
||||
if args.compile.is_some() {
|
||||
eprintln!("Error: cannot compile in REPL mode");
|
||||
return ExitCode::FAILURE
|
||||
}
|
||||
return repl::repl(&args)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,5 +9,5 @@ workspace = true
|
|||
|
||||
[dependencies]
|
||||
num = "0.4"
|
||||
lazy_static = "1.5"
|
||||
unicode-ident = "1.0"
|
||||
lazy_static = "1"
|
||||
unicode-ident = "1"
|
||||
|
|
|
@ -71,6 +71,7 @@ impl From<Arg24> for usize {
|
|||
|
||||
impl From<Arg24> for i32 {
|
||||
#[inline]
|
||||
#[expect(clippy::cast_possible_wrap)]
|
||||
fn from(v: Arg24) -> Self {
|
||||
let mut n = u32::from(v);
|
||||
// sign-extend
|
||||
|
@ -252,7 +253,7 @@ impl Chunk {
|
|||
}
|
||||
|
||||
pub fn set_line(&mut self, line: u32) {
|
||||
let instr = self.instrs.len() as u32;
|
||||
let instr = u32::try_from(self.instrs.len()).expect("chunk too big");
|
||||
if let Some((i, l)) = self.lines.last_mut() {
|
||||
if *i == instr {
|
||||
*l = line;
|
||||
|
|
|
@ -483,20 +483,29 @@ impl<'a> Compiler<'a> {
|
|||
self.emit(I::Index);
|
||||
}
|
||||
ExprKind::FnCall(f, args) => {
|
||||
let Ok(argc) = u8::try_from(args.len()) else {
|
||||
throw!(span.start, "too many arguments to function (max 255)")
|
||||
};
|
||||
self.expr(f)?;
|
||||
for a in args {
|
||||
self.expr(a)?;
|
||||
}
|
||||
self.emit(I::Call(args.len() as u8));
|
||||
self.emit(I::Call(argc));
|
||||
}
|
||||
ExprKind::TailCall(f, args) => {
|
||||
let Ok(argc) = u8::try_from(args.len()) else {
|
||||
throw!(span.start, "too many arguments to function (max 255)")
|
||||
};
|
||||
self.expr(f)?;
|
||||
for a in args {
|
||||
self.expr(a)?;
|
||||
}
|
||||
self.emit(I::Tail(args.len() as u8));
|
||||
self.emit(I::Tail(argc));
|
||||
}
|
||||
ExprKind::AssocFnCall(o, f, args) => {
|
||||
let Ok(argc) = u8::try_from(args.len() + 1) else {
|
||||
throw!(span.start, "too many arguments to function (max 254)")
|
||||
};
|
||||
self.expr(o)?;
|
||||
self.emit(I::Dup);
|
||||
self.emit(I::Symbol(Arg24::from_symbol(*f)));
|
||||
|
@ -505,9 +514,12 @@ impl<'a> Compiler<'a> {
|
|||
for a in args {
|
||||
self.expr(a)?;
|
||||
}
|
||||
self.emit(I::Call((args.len() + 1) as u8));
|
||||
self.emit(I::Call(argc));
|
||||
}
|
||||
ExprKind::AssocTailCall(o, f, args) => {
|
||||
let Ok(argc) = u8::try_from(args.len() + 1) else {
|
||||
throw!(span.start, "too many arguments to function (max 254)")
|
||||
};
|
||||
self.expr(o)?;
|
||||
self.emit(I::Dup);
|
||||
self.emit(I::Symbol(Arg24::from_symbol(*f)));
|
||||
|
@ -516,7 +528,7 @@ impl<'a> Compiler<'a> {
|
|||
for a in args {
|
||||
self.expr(a)?;
|
||||
}
|
||||
self.emit(I::Tail((args.len() + 1) as u8));
|
||||
self.emit(I::Tail(argc));
|
||||
}
|
||||
ExprKind::Return(e) => {
|
||||
if let Some(e) = e {
|
||||
|
@ -587,15 +599,15 @@ impl<'a> Compiler<'a> {
|
|||
self.emit(I::NewList(0));
|
||||
return Ok(())
|
||||
}
|
||||
fn finish_chunk(c: &mut Compiler, len: &mut usize, first: &mut bool) {
|
||||
fn finish_chunk(c: &mut Compiler, len: &mut u8, first: &mut bool) {
|
||||
if *first {
|
||||
c.emit(I::NewList(*len as u8));
|
||||
c.emit(I::NewList(*len));
|
||||
*first = false;
|
||||
} else {
|
||||
if *len == 0 {
|
||||
return
|
||||
}
|
||||
c.emit(I::GrowList(*len as u8));
|
||||
c.emit(I::GrowList(*len));
|
||||
}
|
||||
*len = 0;
|
||||
}
|
||||
|
@ -625,15 +637,15 @@ impl<'a> Compiler<'a> {
|
|||
self.emit(I::NewTable(0));
|
||||
return Ok(())
|
||||
}
|
||||
fn finish_chunk(c: &mut Compiler, len: &mut usize, first: &mut bool) {
|
||||
fn finish_chunk(c: &mut Compiler, len: &mut u8, first: &mut bool) {
|
||||
if *first {
|
||||
c.emit(I::NewTable(*len as u8));
|
||||
c.emit(I::NewTable(*len));
|
||||
*first = false;
|
||||
} else {
|
||||
if *len == 0 {
|
||||
return
|
||||
}
|
||||
c.emit(I::GrowTable(*len as u8));
|
||||
c.emit(I::GrowTable(*len));
|
||||
}
|
||||
*len = 0;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ pub mod number;
|
|||
pub mod ops;
|
||||
pub mod optimize;
|
||||
pub mod parser;
|
||||
pub mod serial;
|
||||
pub mod symbol;
|
||||
pub mod value;
|
||||
pub mod vm;
|
||||
|
|
|
@ -32,7 +32,7 @@ impl Pos {
|
|||
pub fn advance(self, c: char) -> Pos {
|
||||
let idx = self
|
||||
.idx
|
||||
.checked_add(c.len_utf8() as u32)
|
||||
.checked_add(u32::try_from(c.len_utf8()).expect("character too long??"))
|
||||
.expect("source file contains more than u32::MAX chars");
|
||||
if c == '\n' {
|
||||
Pos {
|
||||
|
|
|
@ -101,7 +101,7 @@ pub fn parse_str_escapes(src: &str) -> Result<LString, StrEscapeError> {
|
|||
let n1 = c.to_digit(16).ok_or(StrEscapeError::InvalidHex(c))?;
|
||||
let c = chars.next().ok_or(StrEscapeError::HexEof)?;
|
||||
let n2 = c.to_digit(16).ok_or(StrEscapeError::InvalidHex(c))?;
|
||||
s.push_byte((n1 * 16 + n2) as u8);
|
||||
s.push_byte(u8::try_from(n1 * 16 + n2).expect("hex too large?"));
|
||||
}
|
||||
'u' => {
|
||||
let Some('{') = chars.next() else {
|
||||
|
|
|
@ -1,251 +0,0 @@
|
|||
use std::fmt;
|
||||
use std::io::{self, Write};
|
||||
|
||||
use num::{bigint::Sign, BigInt};
|
||||
|
||||
use crate::{
|
||||
chunk::{Chunk, Instruction, TryTable},
|
||||
lstring::LStr,
|
||||
number::Int,
|
||||
prelude::*,
|
||||
symbol::Symbol,
|
||||
value::{function::Function, Value},
|
||||
};
|
||||
|
||||
const MAGIC: [u8; 8] = *b"\x7fTALC\0\0\0";
|
||||
const VERSION: u32 = 1;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SerialError {
|
||||
Io(io::Error),
|
||||
Serial(String),
|
||||
}
|
||||
|
||||
impl std::error::Error for SerialError {}
|
||||
|
||||
impl fmt::Display for SerialError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
SerialError::Io(e) => e.fmt(f),
|
||||
SerialError::Serial(e) => e.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Result<T> = std::result::Result<T, SerialError>;
|
||||
|
||||
impl From<io::Error> for SerialError {
|
||||
fn from(value: io::Error) -> Self {
|
||||
Self::Io(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for SerialError {
|
||||
fn from(value: String) -> Self {
|
||||
Self::Serial(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for SerialError {
|
||||
fn from(value: &str) -> Self {
|
||||
Self::Serial(value.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_program(w: &mut impl Write, prog: &Function) -> Result<()> {
|
||||
ProgramWriter::new(w).write_program(prog)
|
||||
}
|
||||
|
||||
struct ProgramWriter<'w, W: Write> {
|
||||
w: &'w mut W,
|
||||
}
|
||||
|
||||
impl<'w, W: Write> ProgramWriter<'w, W> {
|
||||
fn new(w: &'w mut W) -> Self {
|
||||
Self { w }
|
||||
}
|
||||
|
||||
fn write_program(&mut self, prog: &Function) -> Result<()> {
|
||||
self.w.write_all(&MAGIC)?;
|
||||
self.w.write_all(&VERSION.to_le_bytes())?;
|
||||
self.write_function(prog)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_function(&mut self, func: &Function) -> Result<()> {
|
||||
self.write_bool(func.attrs.name.is_some())?;
|
||||
if let Some(name) = func.attrs.name {
|
||||
self.write_sym(name)?;
|
||||
}
|
||||
self.write_u32(func.attrs.arity as u32)?;
|
||||
self.write_u32(func.state.len() as u32)?;
|
||||
self.write_chunk(&func.chunk)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_chunk(&mut self, chunk: &Chunk) -> Result<()> {
|
||||
self.write_u32(chunk.consts.len() as u32)?;
|
||||
self.write_u32(chunk.instrs.len() as u32)?;
|
||||
self.write_u32(chunk.try_tables.len() as u32)?;
|
||||
|
||||
for c in &chunk.consts {
|
||||
self.write_value(c)?;
|
||||
}
|
||||
for i in &chunk.instrs {
|
||||
self.write_instr(*i)?;
|
||||
}
|
||||
for t in &chunk.try_tables {
|
||||
self.write_try_table(t)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_value(&mut self, val: &Value) -> Result<()> {
|
||||
match val {
|
||||
Value::Nil => self.write_u8(0),
|
||||
Value::Bool(b) => {
|
||||
self.write_u8(1)?;
|
||||
self.write_bool(*b)
|
||||
}
|
||||
Value::Symbol(sym) => {
|
||||
self.write_u8(2)?;
|
||||
self.write_sym(*sym)
|
||||
}
|
||||
Value::Int(n) => {
|
||||
self.write_u8(3)?;
|
||||
self.write_int(n.clone())
|
||||
}
|
||||
Value::Ratio(r) => {
|
||||
self.write_u8(4)?;
|
||||
self.write_int(Int::from(r.numer().clone()))?;
|
||||
self.write_int(Int::from(r.denom().clone()))
|
||||
}
|
||||
Value::Float(f) => {
|
||||
self.write_u8(5)?;
|
||||
self.write_f64(*f)
|
||||
}
|
||||
Value::Complex(z) => {
|
||||
self.write_u8(6)?;
|
||||
self.write_f64(z.re)?;
|
||||
self.write_f64(z.im)
|
||||
}
|
||||
Value::Range(r) => {
|
||||
self.write_u8(7)?;
|
||||
if let Some(s) = &r.start {
|
||||
self.write_u8(1)?;
|
||||
self.write_int(s.into())?;
|
||||
} else {
|
||||
self.write_u8(0)?;
|
||||
}
|
||||
if let Some(e) = &r.end {
|
||||
self.write_u8(1)?;
|
||||
self.write_int(e.into())?;
|
||||
} else {
|
||||
self.write_u8(0)?;
|
||||
}
|
||||
self.write_bool(r.inclusive)
|
||||
}
|
||||
Value::String(s) => {
|
||||
self.write_u8(8)?;
|
||||
self.write_str(s)
|
||||
}
|
||||
Value::Function(func) => {
|
||||
self.write_u8(9)?;
|
||||
self.write_function(func)
|
||||
}
|
||||
Value::Cell(_)
|
||||
| Value::List(_)
|
||||
| Value::Table(_)
|
||||
| Value::NativeFunc(_)
|
||||
| Value::Native(_) => Err(format!(
|
||||
"cannot serialize value of type {}",
|
||||
val.get_type().name()
|
||||
)
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_instr(&mut self, i: Instruction) -> Result<()> {
|
||||
let n: u32 = unsafe { std::mem::transmute(i) };
|
||||
self.write_u32(n)
|
||||
}
|
||||
|
||||
fn write_try_table(&mut self, t: &TryTable) -> Result<()> {
|
||||
self.write_u32(t.local_count as u32)?;
|
||||
self.write_u32(t.catches.len() as u32)?;
|
||||
for catch in &t.catches {
|
||||
self.write_u32(catch.addr as u32)?;
|
||||
self.write_bool(catch.types.is_some())?;
|
||||
if let Some(tys) = &catch.types {
|
||||
self.write_u32(tys.len() as u32)?;
|
||||
for ty in tys {
|
||||
self.write_sym(*ty)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_sym(&mut self, sym: Symbol) -> Result<()> {
|
||||
self.write_str(sym.name())
|
||||
}
|
||||
|
||||
fn write_str(&mut self, s: &LStr) -> Result<()> {
|
||||
let Ok(n) = s.len().try_into() else {
|
||||
return Err("string to long to serialize".into())
|
||||
};
|
||||
self.write_u32(n)?;
|
||||
self.w.write_all(s.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_f64(&mut self, x: f64) -> Result<()> {
|
||||
self.w.write_all(&x.to_le_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_int(&mut self, n: Int) -> Result<()> {
|
||||
if let Some(i) = n.to_i64() {
|
||||
self.write_u8(0x80)?;
|
||||
self.write_i64(i)
|
||||
} else {
|
||||
let big = BigInt::from(n);
|
||||
let (sign, digits) = big.to_u64_digits();
|
||||
match sign {
|
||||
Sign::Minus => self.write_u8(0xff)?,
|
||||
Sign::NoSign => self.write_u8(0x00)?,
|
||||
Sign::Plus => self.write_u8(0x01)?,
|
||||
}
|
||||
self.write_u32(digits.len() as u32)?;
|
||||
for digit in digits {
|
||||
self.write_u64(digit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_i64(&mut self, n: i64) -> Result<()> {
|
||||
self.w.write_all(&n.to_le_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_u64(&mut self, n: u64) -> Result<()> {
|
||||
self.w.write_all(&n.to_le_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_u32(&mut self, n: u32) -> Result<()> {
|
||||
self.w.write_all(&n.to_le_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_u8(&mut self, n: u8) -> Result<()> {
|
||||
self.w.write_all(&[n])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_bool(&mut self, n: bool) -> Result<()> {
|
||||
self.w.write_all(&[n as u8])?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -76,7 +76,7 @@ impl Symbol {
|
|||
let symno = table.names.len();
|
||||
assert!(symno <= MAX_SYMBOL, "too many symbols");
|
||||
|
||||
let sym = Symbol(symno as u32);
|
||||
let sym = Symbol(u32::try_from(symno).expect("too many symbols"));
|
||||
let name = LString::leak(name.to_owned());
|
||||
|
||||
table.names.push(name);
|
||||
|
|
|
@ -25,11 +25,12 @@ impl Value {
|
|||
)
|
||||
};
|
||||
let mut j = i;
|
||||
let len = isize::try_from(l.len()).expect("list too big");
|
||||
if j < 0 {
|
||||
j += l.len() as isize;
|
||||
j += len;
|
||||
}
|
||||
if (0..l.len() as isize).contains(&j) {
|
||||
Ok(l[j as usize].clone())
|
||||
if (0..len).contains(&j) {
|
||||
Ok(l[usize::try_from(j).expect("checked not negative")].clone())
|
||||
} else {
|
||||
throw!(
|
||||
*SYM_INDEX_ERROR,
|
||||
|
@ -96,11 +97,12 @@ impl Value {
|
|||
)
|
||||
};
|
||||
let mut j = i;
|
||||
let len = isize::try_from(l.len()).expect("list too big");
|
||||
if j < 0 {
|
||||
j += l.len() as isize;
|
||||
j += len;
|
||||
}
|
||||
if (0..l.len() as isize).contains(&j) {
|
||||
l[j as usize] = val;
|
||||
if (0..len).contains(&j) {
|
||||
l[usize::try_from(j).expect("checked not negative")] = val;
|
||||
Ok(())
|
||||
} else {
|
||||
throw!(
|
||||
|
|
|
@ -218,6 +218,7 @@ impl Vm {
|
|||
mut exc: Exception,
|
||||
) -> Result<()> {
|
||||
loop {
|
||||
#[expect(clippy::cast_possible_truncation)]
|
||||
let line = frame.func.chunk.get_line(frame.ip as u32);
|
||||
exc.add_trace(line, frame.func.attrs.name);
|
||||
while let Some(try_frame) = frame.try_frames.pop() {
|
||||
|
|
|
@ -11,5 +11,5 @@ workspace = true
|
|||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "2.0", features = ["full"] }
|
||||
quote = "1.0"
|
||||
syn = { version = "2", features = ["full"] }
|
||||
quote = "1"
|
||||
|
|
|
@ -10,9 +10,9 @@ workspace = true
|
|||
[dependencies]
|
||||
talc-lang = { path = "../talc-lang" }
|
||||
talc-macros = { path = "../talc-macros" }
|
||||
lazy_static = "1.5"
|
||||
lazy_static = "1"
|
||||
num-bigint = { version = "0.4", features = ["rand"], optional = true }
|
||||
regex = { version = "1.11", optional = true }
|
||||
regex = { version = "1", optional = true }
|
||||
rand = { version = "0.8", optional = true }
|
||||
|
||||
[features]
|
||||
|
|
|
@ -502,10 +502,10 @@ pub fn popcnt(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
if n.is_negative() {
|
||||
// count_zeros always succeeds on negative numbers
|
||||
let z = n.count_zeros().unwrap();
|
||||
Ok(Value::from(-(z as i64)))
|
||||
Ok(Value::from(-Int::from(z)))
|
||||
} else {
|
||||
// count_ones always succeeds on nonnegative numbers
|
||||
let z = n.count_ones().unwrap();
|
||||
Ok(Value::from(z as i64))
|
||||
Ok(Value::from(z))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,11 +95,7 @@ pub fn time_ns(_: &mut Vm, _: Vec<Value>) -> Result<Value> {
|
|||
let time = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("time went backwards");
|
||||
Ok(vec![
|
||||
(time.as_secs() as i64).into(),
|
||||
(time.subsec_nanos() as i64).into(),
|
||||
]
|
||||
.into())
|
||||
Ok(vec![time.as_secs().into(), time.subsec_nanos().into()].into())
|
||||
}
|
||||
|
||||
#[native_func(1)]
|
||||
|
@ -210,7 +206,7 @@ pub fn arg(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
#[native_func(0)]
|
||||
pub fn argc(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||
let [_] = unpack_args!(args);
|
||||
Ok(Value::from(vm.args().len() as i64))
|
||||
Ok(Value::from(vm.args().len()))
|
||||
}
|
||||
|
||||
#[native_func(0)]
|
||||
|
|
|
@ -647,9 +647,9 @@ pub fn table(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
pub fn len(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||
let [_, value] = unpack_args!(args);
|
||||
match value {
|
||||
Value::String(s) => return Ok((s.chars().count() as i64).into()),
|
||||
Value::List(l) => return Ok((l.borrow().len() as i64).into()),
|
||||
Value::Table(t) => return Ok((t.borrow().len() as i64).into()),
|
||||
Value::String(s) => return Ok((s.chars().count()).into()),
|
||||
Value::List(l) => return Ok((l.borrow().len()).into()),
|
||||
Value::Table(t) => return Ok((t.borrow().len()).into()),
|
||||
Value::Range(ref r) => {
|
||||
if let Some(len) = r.len() {
|
||||
return Ok(len.into())
|
||||
|
|
|
@ -76,8 +76,8 @@ pub fn load(vm: &mut Vm) {
|
|||
|
||||
fn match_to_value(m: Match) -> Value {
|
||||
Value::new_table(|t| {
|
||||
t.insert((*SYM_START).into(), (m.start() as i64).into());
|
||||
t.insert((*SYM_END).into(), (m.end() as i64).into());
|
||||
t.insert((*SYM_START).into(), m.start().into());
|
||||
t.insert((*SYM_END).into(), m.end().into());
|
||||
t.insert(
|
||||
(*SYM_STR).into(),
|
||||
LString::from(m.as_str().to_string()).into(),
|
||||
|
|
|
@ -41,7 +41,7 @@ pub fn ord(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
if chars.next().is_some() {
|
||||
throw!(*SYM_VALUE_ERROR, "argument to ord must have length 1")
|
||||
};
|
||||
Ok(Value::from(c as u32 as i64))
|
||||
Ok(Value::from(c as u32))
|
||||
}
|
||||
|
||||
#[native_func(1)]
|
||||
|
@ -68,7 +68,7 @@ pub fn len_bytes(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
"len_bytes expected string argument, got {s:#}"
|
||||
)
|
||||
};
|
||||
Ok(Value::from(s.len() as i64))
|
||||
Ok(Value::from(s.len()))
|
||||
}
|
||||
|
||||
#[native_func(1)]
|
||||
|
|
|
@ -275,7 +275,7 @@ pub fn func_arity(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
let Some(attrs) = func.func_attrs() else {
|
||||
throw!(*SYM_TYPE_ERROR, "closure_state: {func:#} is not a function")
|
||||
};
|
||||
Ok((attrs.arity as i64).into())
|
||||
Ok(attrs.arity.into())
|
||||
}
|
||||
|
||||
#[native_func(1)]
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
name = "talc-web"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.81.0"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
|
|
@ -119,15 +119,15 @@ function handleCtrlKey(event) {
|
|||
}
|
||||
|
||||
function keyPressed(event) {
|
||||
if (event.key === "Enter" && !event.shiftKey) {
|
||||
if (event.key === "Enter" && !event.shiftKey && !event.altKey) {
|
||||
event.preventDefault();
|
||||
execLine()
|
||||
} else if (event.ctrlKey) {
|
||||
} else if (event.ctrlKey && !event.altKey) {
|
||||
handleCtrlKey(event);
|
||||
} else if (event.key === "ArrowUp") {
|
||||
} else if (event.key === "ArrowUp" && !event.altKey) {
|
||||
event.preventDefault();
|
||||
prevHistory();
|
||||
} else if (event.key === "ArrowDown") {
|
||||
} else if (event.key === "ArrowDown" && !event.altKey) {
|
||||
event.preventDefault();
|
||||
nextHistory();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue