diff --git a/format.sh b/format.sh new file mode 100755 index 0000000..f760505 --- /dev/null +++ b/format.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +cargo +nightly fmt diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..0a88f15 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,10 @@ +unstable_features = true + +hard_tabs = true +tab_spaces = 4 + +trailing_semicolon = false +trailing_comma = "Vertical" + +use_field_init_shorthand = true + diff --git a/talc-bin/src/helper.rs b/talc-bin/src/helper.rs index 90a821d..3c4a56b 100644 --- a/talc-bin/src/helper.rs +++ b/talc-bin/src/helper.rs @@ -1,7 +1,17 @@ use std::{borrow::Cow, cell::RefCell, rc::Rc}; -use rustyline::{completion::Completer, highlight::Highlighter, hint::Hinter, validate::{ValidationContext, ValidationResult, Validator}, Helper, Result}; -use talc_lang::{lstring::LStr, parser::{Lexer, Pos, Span, TokenKind}, Vm}; +use rustyline::{ + completion::Completer, + highlight::Highlighter, + hint::Hinter, + validate::{ValidationContext, ValidationResult, Validator}, + Helper, Result, +}; +use talc_lang::{ + lstring::LStr, + parser::{Lexer, Pos, Span, TokenKind}, + Vm, +}; pub struct TalcHelper { vm: Rc>, @@ -9,9 +19,7 @@ pub struct TalcHelper { impl TalcHelper { pub fn new(vm: Rc>) -> Self { - Self { - vm, - } + Self { vm } } } @@ -35,7 +43,11 @@ impl Completer for TalcHelper { } } let res: String = res.chars().rev().collect(); - let mut keys = self.vm.borrow().globals().keys() + let mut keys = self + .vm + .borrow() + .globals() + .keys() .map(|sym| sym.name()) .filter(|name| name.starts_with(LStr::from_str(&res))) .map(LStr::to_string) @@ -55,23 +67,27 @@ impl Highlighter for TalcHelper { let mut buf = String::new(); let mut last = Pos::new(); while let Some(Ok(token)) = lexer.next() { - if token.kind == TokenKind::Eof { break } + if token.kind == TokenKind::Eof { + break + } buf += Span::new(last, token.span.start).of(line); last = token.span.end; let format = match token.kind { - TokenKind::Nil - | TokenKind::True - | TokenKind::False + TokenKind::Nil + | TokenKind::True + | TokenKind::False | TokenKind::Integer - | TokenKind::Float - | TokenKind::Imaginary => "\x1b[93m", + | TokenKind::Float + | TokenKind::Imaginary => "\x1b[93m", TokenKind::String => "\x1b[92m", TokenKind::Symbol => "\x1b[96m", _ => "", }; - buf += format; + buf += format; buf += token.content; - if !format.is_empty() { buf += "\x1b[0m" } + if !format.is_empty() { + buf += "\x1b[0m" + } } buf += &line[(last.idx as usize)..]; Cow::Owned(buf) @@ -96,73 +112,92 @@ impl Highlighter for TalcHelper { impl Validator for TalcHelper { fn validate(&self, ctx: &mut ValidationContext) -> Result { - use TokenKind as K; + use TokenKind as K; let lexer = Lexer::new(ctx.input()); let mut delims = Vec::new(); let mut mismatch = None; for token in lexer { let token = match token { Ok(t) => t, - Err(e) => { - return Ok(ValidationResult::Invalid( - Some(format!(" {e}")))) - } + Err(e) => return Ok(ValidationResult::Invalid(Some(format!(" {e}")))), }; - let k = token.kind; - let s = token.span; + let k = token.kind; + let s = token.span; match k { - K::Eof => break, - K::LParen - | K::LBrack - | K::LBrace - | K::If - | K::While - | K::For - | K::Try - => delims.push(token.kind), + K::Eof => break, + K::LParen | K::LBrack | K::LBrace | K::If | K::While | K::For | K::Try => { + delims.push(token.kind) + } K::RParen => match delims.pop() { Some(K::LParen) => (), - v => { mismatch = Some((v, k, s)); break } + v => { + mismatch = Some((v, k, s)); + break + } }, K::RBrack => match delims.pop() { Some(K::LBrack) => (), - v => { mismatch = Some((v, k, s)); break } + v => { + mismatch = Some((v, k, s)); + break + } }, K::RBrace => match delims.pop() { Some(K::LBrace) => (), - v => { mismatch = Some((v, k, s)); break } + v => { + mismatch = Some((v, k, s)); + break + } }, K::Then => match delims.pop() { Some(K::If | K::Elif) => delims.push(k), - v => { mismatch = Some((v, k, s)); break } - } + v => { + mismatch = Some((v, k, s)); + break + } + }, K::Catch => match delims.pop() { Some(K::Try) => delims.push(k), - v => { mismatch = Some((v, k, s)); break } - } + v => { + mismatch = Some((v, k, s)); + break + } + }, K::Do => match delims.last().copied() { Some(K::While | K::For | K::Catch) => { delims.pop(); delims.push(k); - }, - _ => delims.push(k) + } + _ => delims.push(k), }, K::Elif | K::Else => match delims.pop() { Some(K::Then) => delims.push(k), - v => { mismatch = Some((v, k, s)); break } + v => { + mismatch = Some((v, k, s)); + break + } }, K::End => match delims.pop() { Some(K::Then | K::Else | K::Do | K::Try | K::Catch) => (), - v => { mismatch = Some((v, k, s)); break } + v => { + mismatch = Some((v, k, s)); + break + } }, _ => (), } } match mismatch { - Some((None, b, s)) => return Ok(ValidationResult::Invalid(Some( - format!(" found unmatched {b} at {s}")))), - Some((Some(a), b, s)) => return Ok(ValidationResult::Invalid(Some( - format!(" found {a} matched with {b} at {s}")))), + Some((None, b, s)) => { + return Ok(ValidationResult::Invalid(Some(format!( + " found unmatched {b} at {s}" + )))) + } + Some((Some(a), b, s)) => { + return Ok(ValidationResult::Invalid(Some(format!( + " found {a} matched with {b} at {s}" + )))) + } _ => (), } @@ -171,6 +206,5 @@ impl Validator for TalcHelper { } else { Ok(ValidationResult::Incomplete) } - } } diff --git a/talc-bin/src/main.rs b/talc-bin/src/main.rs index 50cc371..7647f3f 100644 --- a/talc-bin/src/main.rs +++ b/talc-bin/src/main.rs @@ -1,9 +1,9 @@ use clap::{ColorChoice, Parser}; -use talc_lang::{compiler::compile, parser, symbol::Symbol, value::function::disasm_recursive, Vm}; use std::{path::PathBuf, process::ExitCode, rc::Rc}; +use talc_lang::{compiler::compile, parser, symbol::Symbol, value::function::disasm_recursive, Vm}; -mod repl; mod helper; +mod repl; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -20,11 +20,11 @@ struct Args { disasm: bool, /// show disassembled bytecode - #[arg(short='H', long)] + #[arg(short = 'H', long)] histfile: Option, /// enable or disable color - #[arg(short, long, default_value="auto")] + #[arg(short, long, default_value = "auto")] color: ColorChoice, } @@ -37,7 +37,7 @@ fn exec(name: Symbol, src: &str, args: &Args) -> ExitCode { Err(e) => { eprintln!("Error: {e}"); return ExitCode::FAILURE - }, + } }; let func = Rc::new(compile(&ex, Some(name))); @@ -64,7 +64,7 @@ fn main() -> ExitCode { return repl::repl(&args) } - let file = args.file.as_ref().unwrap(); + let file = args.file.as_ref().unwrap(); match std::fs::read_to_string(file) { Ok(s) => exec(Symbol::get(file.as_os_str()), &s, &args), diff --git a/talc-bin/src/repl.rs b/talc-bin/src/repl.rs index 4847495..26acbc6 100644 --- a/talc-bin/src/repl.rs +++ b/talc-bin/src/repl.rs @@ -1,8 +1,18 @@ use std::{cell::RefCell, io::IsTerminal, process::ExitCode, rc::Rc}; use clap::ColorChoice; -use rustyline::{error::ReadlineError, history::{FileHistory, History}, ColorMode, Config, Editor}; -use talc_lang::{compiler::compile_repl, parser, symbol::Symbol, value::{function::disasm_recursive, Value}, Vm}; +use rustyline::{ + error::ReadlineError, + history::{FileHistory, History}, + ColorMode, Config, Editor, +}; +use talc_lang::{ + compiler::compile_repl, + parser, + symbol::Symbol, + value::{function::disasm_recursive, Value}, + Vm, +}; use crate::{helper::TalcHelper, Args}; @@ -30,7 +40,6 @@ impl ReplColors { } } - fn get_colmode(args: &Args) -> ColorMode { match args.color { ColorChoice::Auto => ColorMode::Enabled, @@ -45,7 +54,8 @@ pub fn init_rustyline(args: &Args) -> Result, Ex .color_mode(get_colmode(args)) .check_cursor_position(true) .completion_type(rustyline::CompletionType::List) - .max_history_size(4096).unwrap() + .max_history_size(4096) + .unwrap() .build(); let mut hist = FileHistory::default(); if let Some(f) = &args.histfile { @@ -60,12 +70,12 @@ pub fn init_rustyline(args: &Args) -> Result, Ex Err(ReadlineError::Io(e)) => { eprintln!("Error creating repl: {e}"); Err(ExitCode::FAILURE) - }, + } Err(ReadlineError::Errno(e)) => { eprintln!("Error creating repl: {e}"); Err(ExitCode::FAILURE) - }, - Err(_) => Err(ExitCode::SUCCESS) + } + Err(_) => Err(ExitCode::SUCCESS), } } @@ -117,7 +127,7 @@ pub fn repl(args: &Args) -> ExitCode { Err(e) => { eprintln!("{}Error:{} {e}", c.error, c.reset); continue - }, + } }; let ex = match parser::parse(&line) { @@ -125,7 +135,7 @@ pub fn repl(args: &Args) -> ExitCode { Err(e) => { eprintln!("{}Error:{} {e}", c.error, c.reset); continue - }, + } }; let (f, g) = compile_repl(&ex, &compiler_globals); @@ -154,4 +164,3 @@ pub fn repl(args: &Args) -> ExitCode { } } } - diff --git a/talc-lang/src/chunk.rs b/talc-lang/src/chunk.rs index a4b1945..d32e938 100644 --- a/talc-lang/src/chunk.rs +++ b/talc-lang/src/chunk.rs @@ -1,4 +1,8 @@ -use crate::{value::Value, parser::ast::{UnaryOp, BinaryOp}, symbol::Symbol}; +use crate::{ + parser::ast::{BinaryOp, UnaryOp}, + symbol::Symbol, + value::Value, +}; #[derive(Clone, Copy, Debug, Default)] pub struct Arg24([u8; 3]); @@ -13,14 +17,20 @@ impl Arg24 { #[inline] pub fn from_i32(n: i32) -> Self { - assert!((-0x80_0000..=0x7f_ffff).contains(&n), "value out of range for argument"); + assert!( + (-0x80_0000..=0x7f_ffff).contains(&n), + "value out of range for argument" + ); // can't panic: size of slice guaranteed Self(n.to_le_bytes()[0..3].try_into().unwrap()) } #[inline] pub fn from_i64(n: i64) -> Self { - assert!((-0x80_0000..=0x7f_ffff).contains(&n), "value out of range for argument"); + assert!( + (-0x80_0000..=0x7f_ffff).contains(&n), + "value out of range for argument" + ); // can't panic: size of slice guaranteed Self(n.to_le_bytes()[0..3].try_into().unwrap()) } @@ -64,7 +74,9 @@ impl From for i32 { fn from(v: Arg24) -> Self { let mut n = u32::from(v); // sign-extend - if n & 0x00_800000 != 0 { n |= 0xff_000000; } + if n & 0x00_800000 != 0 { + n |= 0xff_000000; + } n as i32 } } @@ -88,55 +100,55 @@ impl TryFrom for Symbol { #[derive(Clone, Copy, Debug, Default)] pub enum Instruction { #[default] - Nop, // do nothing + Nop, // do nothing - LoadLocal(Arg24), // push nth local onto stack - StoreLocal(Arg24), // pop stack into nth local - NewLocal, // pop stack into a new local - DropLocal(Arg24), // remove last n locals + LoadLocal(Arg24), // push nth local onto stack + StoreLocal(Arg24), // pop stack into nth local + NewLocal, // pop stack into a new local + DropLocal(Arg24), // remove last n locals - LoadGlobal(Arg24), // load global by id - StoreGlobal(Arg24), // store global by id + LoadGlobal(Arg24), // load global by id + StoreGlobal(Arg24), // store global by id - CloseOver(Arg24), // load nth local and convert to cell, write back a copy - Closure(Arg24), // load constant function and fill state from stack - LoadUpvalue(Arg24), // load - StoreUpvalue(Arg24), // store a cell from closure state to new local - ContinueUpvalue(Arg24), // - LoadClosedLocal(Arg24), // load through cell in nth local - StoreClosedLocal(Arg24), // store through cell in nth local + CloseOver(Arg24), // load nth local and convert to cell, write back a copy + Closure(Arg24), // load constant function and fill state from stack + LoadUpvalue(Arg24), // load + StoreUpvalue(Arg24), // store a cell from closure state to new local + ContinueUpvalue(Arg24), // + LoadClosedLocal(Arg24), // load through cell in nth local + StoreClosedLocal(Arg24), // store through cell in nth local - Const(Arg24), // push nth constant - Int(Arg24), // push integer - Symbol(Arg24), // push symbol - Bool(bool), // push boolean - Nil, // push nil + Const(Arg24), // push nth constant + Int(Arg24), // push integer + Symbol(Arg24), // push symbol + Bool(bool), // push boolean + Nil, // push nil Dup, - DupTwo, - Drop(Arg24), - Swap, - + DupTwo, + Drop(Arg24), + Swap, + UnaryOp(UnaryOp), BinaryOp(BinaryOp), NewList(u8), - GrowList(u8), + GrowList(u8), NewTable(u8), - GrowTable(u8), + GrowTable(u8), Index, - StoreIndex, + StoreIndex, Jump(Arg24), JumpTrue(Arg24), JumpFalse(Arg24), IterBegin, - IterTest(Arg24), + IterTest(Arg24), BeginTry(Arg24), - EndTry, + EndTry, Call(u8), Return, @@ -150,21 +162,30 @@ impl std::fmt::Display for Instruction { Self::StoreLocal(a) => write!(f, "store {}", usize::from(a)), Self::NewLocal => write!(f, "newlocal"), Self::DropLocal(n) => write!(f, "discardlocal {}", usize::from(n)), - Self::LoadGlobal(s) => write!(f, "loadglobal {}", - Symbol::try_from(s).expect("symbol does not exist").name()), - Self::StoreGlobal(s) => write!(f, "storeglobal {}", - Symbol::try_from(s).expect("symbol does not exist").name()), - Self::CloseOver(n) => write!(f, "closeover {}", usize::from(n)), - Self::Closure(c) => write!(f, "closure {}", usize::from(c)), - Self::LoadUpvalue(n) => write!(f, "load_upval {}", usize::from(n)), - Self::StoreUpvalue(n) => write!(f, "store_upval {}", usize::from(n)), - Self::ContinueUpvalue(n) => write!(f, "cont_upval {}", usize::from(n)), - Self::LoadClosedLocal(n) => write!(f, "load_closed {}", usize::from(n)), - Self::StoreClosedLocal(n) => write!(f, "store_closed {}", usize::from(n)), + Self::LoadGlobal(s) => write!( + f, + "loadglobal {}", + Symbol::try_from(s).expect("symbol does not exist").name() + ), + Self::StoreGlobal(s) => write!( + f, + "storeglobal {}", + Symbol::try_from(s).expect("symbol does not exist").name() + ), + Self::CloseOver(n) => write!(f, "closeover {}", usize::from(n)), + Self::Closure(c) => write!(f, "closure {}", usize::from(c)), + Self::LoadUpvalue(n) => write!(f, "load_upval {}", usize::from(n)), + Self::StoreUpvalue(n) => write!(f, "store_upval {}", usize::from(n)), + Self::ContinueUpvalue(n) => write!(f, "cont_upval {}", usize::from(n)), + Self::LoadClosedLocal(n) => write!(f, "load_closed {}", usize::from(n)), + Self::StoreClosedLocal(n) => write!(f, "store_closed {}", usize::from(n)), Self::Const(c) => write!(f, "const {}", usize::from(c)), Self::Int(i) => write!(f, "int {}", i64::from(i)), - Self::Symbol(s) => write!(f, "symbol {}", - Symbol::try_from(s).expect("symbol does not exist").name()), + Self::Symbol(s) => write!( + f, + "symbol {}", + Symbol::try_from(s).expect("symbol does not exist").name() + ), Self::Bool(b) => write!(f, "bool {b}"), Self::Nil => write!(f, "nil"), Self::Dup => write!(f, "dup"), @@ -217,19 +238,28 @@ impl Chunk { } pub fn add_const(&mut self, v: Value) -> usize { - assert!(self.consts.len() < 0xff_ffff, "too many constants in a chunk"); + assert!( + self.consts.len() < 0xff_ffff, + "too many constants in a chunk" + ); self.consts.push(v); self.consts.len() - 1 } pub fn add_instr(&mut self, i: Instruction) -> usize { - assert!(self.instrs.len() < 0xff_ffff, "too many instructions in a chunk"); + assert!( + self.instrs.len() < 0xff_ffff, + "too many instructions in a chunk" + ); self.instrs.push(i); self.instrs.len() - 1 } pub fn begin_try_table(&mut self, local_count: usize) -> (usize, TryTable) { - assert!(self.try_tables.len() < 0xff_ffff, "too many catch tables in a chunk"); + assert!( + self.try_tables.len() < 0xff_ffff, + "too many catch tables in a chunk" + ); let table = TryTable { catches: Vec::new(), local_count, @@ -242,5 +272,3 @@ impl Chunk { self.try_tables[idx] = table; } } - - diff --git a/talc-lang/src/compiler.rs b/talc-lang/src/compiler.rs index c6aaaee..541aa50 100644 --- a/talc-lang/src/compiler.rs +++ b/talc-lang/src/compiler.rs @@ -1,32 +1,36 @@ use std::collections::{BTreeMap, HashMap}; 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::chunk::{Instruction as I, Chunk, Arg24, Catch}; use crate::symbol::{Symbol, SYM_SELF}; use crate::value::function::{FuncAttrs, Function}; use crate::value::Value; enum ResolveOutcome { - Var(VarKind), - InParent, - None, + Var(VarKind), + InParent, + None, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum VarKind { - Local(usize), Closed(usize), Global + Local(usize), + Closed(usize), + Global, } #[derive(Debug, Clone)] pub struct Var { name: Symbol, - kind: VarKind, + kind: VarKind, } #[derive(Clone, Copy, PartialEq, Eq)] enum CompilerMode { - Function, Repl, Module, + Function, + Repl, + Module, } struct Compiler<'a> { @@ -34,19 +38,19 @@ struct Compiler<'a> { parent: Option<&'a Compiler<'a>>, chunk: Chunk, attrs: FuncAttrs, - scope: HashMap, - shadowed: Vec<(Symbol, Option)>, - closes: BTreeMap, - local_count: usize, + scope: HashMap, + shadowed: Vec<(Symbol, Option)>, + closes: BTreeMap, + local_count: usize, } -pub fn compile(expr: &Expr, name: Option) -> Function { +pub fn compile(expr: &Expr, name: Option) -> Function { let mut comp = Compiler::new_module(name, None); comp.expr(expr); comp.finish() } -pub fn compile_repl(expr: &Expr, globals: &[Symbol]) -> (Function, Vec) { +pub fn compile_repl(expr: &Expr, globals: &[Symbol]) -> (Function, Vec) { let mut comp = Compiler::new_repl(globals); comp.expr(expr); comp.finish_repl() @@ -54,20 +58,23 @@ pub fn compile_repl(expr: &Expr, globals: &[Symbol]) -> (Function, Vec) 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), - }); + let mut scope = HashMap::new(); + scope.insert( + *SYM_SELF, + Var { + name: *SYM_SELF, + kind: VarKind::Local(0), + }, + ); Self { mode: CompilerMode::Function, parent: None, chunk: Chunk::new(), - attrs: FuncAttrs::default(), - scope, - shadowed: Vec::new(), - local_count: 1, - closes: BTreeMap::new(), + attrs: FuncAttrs::default(), + scope, + shadowed: Vec::new(), + local_count: 1, + closes: BTreeMap::new(), } } } @@ -76,20 +83,23 @@ impl<'a> Compiler<'a> { fn new_repl(globals: &[Symbol]) -> Self { let mut new = Self { mode: CompilerMode::Repl, - attrs: FuncAttrs { arity: 0, name: Some(Symbol::get("")) }, + attrs: FuncAttrs { + arity: 0, + name: Some(Symbol::get("")), + }, ..Self::default() }; - for g in globals { - new.declare_global(*g); - } - new + for g in globals { + new.declare_global(*g); + } + new } fn new_module(name: Option, parent: Option<&'a Self>) -> Self { Self { mode: CompilerMode::Module, - attrs: FuncAttrs { arity: 0, name }, + attrs: FuncAttrs { arity: 0, name }, parent, ..Self::default() } @@ -98,13 +108,16 @@ impl<'a> Compiler<'a> { fn new_function(&'a self, name: Option, args: &[Symbol]) -> Self { let mut new = Self { mode: CompilerMode::Function, - attrs: FuncAttrs { arity: args.len(), name }, + attrs: FuncAttrs { + arity: args.len(), + name, + }, parent: Some(self), ..Self::default() }; for arg in args { - new.declare_local(*arg); + new.declare_local(*arg); } new @@ -112,26 +125,27 @@ impl<'a> Compiler<'a> { pub fn finish(mut self) -> Function { 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, BTreeMap) { self.emit(I::Return); - // TODO closure - ( - Function::new(Rc::new(self.chunk), self.attrs, self.closes.len()), - self.closes - ) + // TODO closure + ( + Function::new(Rc::new(self.chunk), self.attrs, self.closes.len()), + self.closes, + ) } pub fn finish_repl(mut self) -> (Function, Vec) { 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() + // 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(), ) } @@ -154,38 +168,44 @@ impl<'a> Compiler<'a> { // dup followed by store: remove the dup if instrs.len() >= 2 && matches!(instrs.get(instrs.len() - 2), Some(I::Dup)) - && matches!(instrs.last(), Some( - I::NewLocal | I::StoreLocal(_) | I::StoreGlobal(_) - | I::StoreClosedLocal(_) | I::StoreUpvalue(_) - )) - { + && matches!( + instrs.last(), + Some( + I::NewLocal + | I::StoreLocal(_) | I::StoreGlobal(_) + | I::StoreClosedLocal(_) + | I::StoreUpvalue(_) + ) + ) { // can't panic: checked that instrs.len() >= 2 let i = self.chunk.instrs.pop().unwrap(); self.chunk.instrs.pop().unwrap(); self.chunk.instrs.push(i); n -= 1; - continue; + continue } // final side-effectless instruction let poppable = matches!( instrs.last(), Some( - I::Dup | I::Const(_) | I::Int(_) - | I::Nil | I::Bool(_) | I::Symbol(_) - | I::LoadLocal(_) | I::LoadClosedLocal(_) - | I::LoadUpvalue(_) + I::Dup + | I::Const(_) | I::Int(_) + | I::Nil | I::Bool(_) + | I::Symbol(_) | I::LoadLocal(_) + | I::LoadClosedLocal(_) + | I::LoadUpvalue(_) ) ); if poppable { // can't panic: checked that instrs.last() was Some instrs.pop().unwrap(); n -= 1; - continue; + continue } // no more optimizations possible - break; + break } if n > 0 { self.emit(I::Drop(Arg24::from_usize(n))); @@ -200,181 +220,180 @@ impl<'a> Compiler<'a> { self.chunk.instrs[n] = new; } - #[must_use] + #[must_use] fn begin_scope(&mut self) -> usize { - self.shadowed.len() + self.shadowed.len() } fn end_scope(&mut self, scope: usize) { - let mut locals = 0; - while self.shadowed.len() > scope { - let (name, var) = self.shadowed.pop().expect("scope bad"); + let mut locals = 0; + while self.shadowed.len() > scope { + let (name, var) = self.shadowed.pop().expect("scope bad"); - if let Some(var) = var { - if var.kind != VarKind::Global { - locals += 1; - } - self.scope.insert(name, var); - } else { - self.scope.remove(&name); - } - } + if let Some(var) = var { + if var.kind != VarKind::Global { + locals += 1; + } + self.scope.insert(name, var); + } else { + self.scope.remove(&name); + } + } - if locals > 0 { - self.emit(I::DropLocal(Arg24::from_usize(locals))); - self.local_count -= locals; - } + if locals > 0 { + self.emit(I::DropLocal(Arg24::from_usize(locals))); + self.local_count -= locals; + } } - // // variables // - - fn resolve_name(&self, name: Symbol) -> ResolveOutcome { - if let Some(v) = self.scope.get(&name) { - return ResolveOutcome::Var(v.kind) - } - let Some(parent) = self.parent else { - return ResolveOutcome::None - }; - if let ResolveOutcome::None = parent.resolve_name(name) { - return ResolveOutcome::None - } - ResolveOutcome::InParent - } - fn load_var(&mut self, name: Symbol) { - match self.resolve_name(name) { - ResolveOutcome::Var(VarKind::Local(n)) => { - self.emit(I::LoadLocal(Arg24::from_usize(n))); - } - ResolveOutcome::Var(VarKind::Closed(n)) => { - self.emit(I::LoadClosedLocal(Arg24::from_usize(n))); - } - ResolveOutcome::InParent => { - let n = match self.closes.get(&name) { - Some(n) => *n, - None => { - let n = self.closes.len(); - self.closes.insert(name, n); - n - } - }; - self.emit(I::LoadUpvalue(Arg24::from_usize(n))); - } - ResolveOutcome::None | ResolveOutcome::Var(VarKind::Global) => { - self.emit(I::LoadGlobal(Arg24::from_symbol(name))); - } - } - } + fn resolve_name(&self, name: Symbol) -> ResolveOutcome { + if let Some(v) = self.scope.get(&name) { + return ResolveOutcome::Var(v.kind) + } + let Some(parent) = self.parent else { + return ResolveOutcome::None + }; + if let ResolveOutcome::None = parent.resolve_name(name) { + return ResolveOutcome::None + } + ResolveOutcome::InParent + } - fn declare_local(&mut self, name: Symbol) -> usize { - let local = Var { - name, - kind: VarKind::Local(self.local_count) - }; - self.local_count += 1; - let shadowed = self.scope.insert(name, local); - self.shadowed.push((name, shadowed)); - self.local_count - 1 - } + fn load_var(&mut self, name: Symbol) { + match self.resolve_name(name) { + ResolveOutcome::Var(VarKind::Local(n)) => { + self.emit(I::LoadLocal(Arg24::from_usize(n))); + } + ResolveOutcome::Var(VarKind::Closed(n)) => { + self.emit(I::LoadClosedLocal(Arg24::from_usize(n))); + } + ResolveOutcome::InParent => { + let n = match self.closes.get(&name) { + Some(n) => *n, + None => { + let n = self.closes.len(); + self.closes.insert(name, n); + n + } + }; + self.emit(I::LoadUpvalue(Arg24::from_usize(n))); + } + ResolveOutcome::None | ResolveOutcome::Var(VarKind::Global) => { + self.emit(I::LoadGlobal(Arg24::from_symbol(name))); + } + } + } - fn assign_local(&mut self, name: Symbol) -> usize { - let n = self.declare_local(name); - self.emit(I::NewLocal); - n - } + fn declare_local(&mut self, name: Symbol) -> usize { + let local = Var { + name, + kind: VarKind::Local(self.local_count), + }; + self.local_count += 1; + let shadowed = self.scope.insert(name, local); + self.shadowed.push((name, shadowed)); + self.local_count - 1 + } - fn assign_global(&mut self, name: Symbol) { - self.declare_global(name); - self.store_var(name); - } + fn assign_local(&mut self, name: Symbol) -> usize { + let n = self.declare_local(name); + self.emit(I::NewLocal); + n + } - fn declare_global(&mut self, name: Symbol) { - let global = Var { - name, - kind: VarKind::Global - }; - let shadowed = self.scope.insert(name, global); - self.shadowed.push((name, shadowed)); - } - - fn store_var(&mut self, name: Symbol) { - match self.resolve_name(name) { - ResolveOutcome::Var(VarKind::Local(n)) => { - self.emit(I::StoreLocal(Arg24::from_usize(n))); - } - ResolveOutcome::Var(VarKind::Closed(n)) => { - self.emit(I::StoreClosedLocal(Arg24::from_usize(n))); - } - ResolveOutcome::InParent => { - let n = match self.closes.get(&name) { - Some(n) => *n, - None => { - let n = self.closes.len(); - self.closes.insert(name, n); - n - } - }; - self.emit(I::StoreUpvalue(Arg24::from_usize(n))); - } - ResolveOutcome::Var(VarKind::Global) => { - self.emit(I::StoreGlobal(Arg24::from_symbol(name))); - } - ResolveOutcome::None if self.mode == CompilerMode::Repl => { - self.emit(I::StoreGlobal(Arg24::from_symbol(name))); - } - ResolveOutcome::None => { - self.assign_local(name); - } - } - } + fn assign_global(&mut self, name: Symbol) { + self.declare_global(name); + self.store_var(name); + } + fn declare_global(&mut self, name: Symbol) { + let global = Var { + name, + kind: VarKind::Global, + }; + let shadowed = self.scope.insert(name, global); + self.shadowed.push((name, shadowed)); + } + fn store_var(&mut self, name: Symbol) { + match self.resolve_name(name) { + ResolveOutcome::Var(VarKind::Local(n)) => { + self.emit(I::StoreLocal(Arg24::from_usize(n))); + } + ResolveOutcome::Var(VarKind::Closed(n)) => { + self.emit(I::StoreClosedLocal(Arg24::from_usize(n))); + } + ResolveOutcome::InParent => { + let n = match self.closes.get(&name) { + Some(n) => *n, + None => { + let n = self.closes.len(); + self.closes.insert(name, n); + n + } + }; + self.emit(I::StoreUpvalue(Arg24::from_usize(n))); + } + ResolveOutcome::Var(VarKind::Global) => { + self.emit(I::StoreGlobal(Arg24::from_symbol(name))); + } + ResolveOutcome::None if self.mode == CompilerMode::Repl => { + self.emit(I::StoreGlobal(Arg24::from_symbol(name))); + } + ResolveOutcome::None => { + self.assign_local(name); + } + } + } // // Expressions // fn expr(&mut self, e: &Expr) { - let Expr { kind, .. } = e; + let Expr { kind, .. } = e; match kind { - ExprKind::Block(xs) if xs.is_empty() => { self.emit(I::Nil); }, + ExprKind::Block(xs) if xs.is_empty() => { + self.emit(I::Nil); + } ExprKind::Block(xs) => { let scope = self.begin_scope(); - for x in &xs[0..xs.len()-1] { + for x in &xs[0..xs.len() - 1] { self.expr(x); self.emit_discard(1); } - self.expr(&xs[xs.len()-1]); + self.expr(&xs[xs.len() - 1]); self.end_scope(scope); - }, + } ExprKind::Literal(v) => self.expr_literal(v), ExprKind::Ident(ident) => self.load_var(*ident), ExprKind::UnaryOp(o, a) => { self.expr(a); self.emit(I::UnaryOp(*o)); - }, + } ExprKind::BinaryOp(o, a, b) => { self.expr(a); self.expr(b); self.emit(I::BinaryOp(*o)); - }, + } ExprKind::Assign(o, lv, a) => self.expr_assign(*o, lv, a), ExprKind::AssignVar(name, a) => { self.expr(a); self.emit(I::Dup); self.assign_local(*name); - }, + } ExprKind::AssignGlobal(name, a) => { self.expr(a); self.emit(I::Dup); self.assign_global(*name); - }, + } ExprKind::List(xs) if xs.is_empty() => { self.emit(I::NewList(0)); - }, + } ExprKind::List(xs) => { let mut first = true; for chunk in xs.chunks(16) { @@ -388,10 +407,10 @@ impl<'a> Compiler<'a> { self.emit(I::GrowList(chunk.len() as u8)); } } - }, + } ExprKind::Table(xs) if xs.is_empty() => { self.emit(I::NewTable(0)); - }, + } ExprKind::Table(xs) => { let mut first = true; for chunk in xs.chunks(8) { @@ -406,19 +425,19 @@ impl<'a> Compiler<'a> { self.emit(I::GrowTable(chunk.len() as u8)); } } - }, + } ExprKind::Index(ct, idx) => { self.expr(ct); self.expr(idx); self.emit(I::Index); - }, + } ExprKind::FnCall(f, args) => { self.expr(f); for a in args { self.expr(a); } self.emit(I::Call(args.len() as u8)); - }, + } ExprKind::AssocFnCall(o, f, args) => { self.expr(o); self.emit(I::Dup); @@ -429,17 +448,17 @@ impl<'a> Compiler<'a> { self.expr(a); } self.emit(I::Call((args.len() + 1) as u8)); - }, + } ExprKind::Return(e) => { self.expr(e); self.emit(I::Return); - }, + } ExprKind::Pipe(a, f) => { self.expr(a); self.expr(f); self.emit(I::Swap); self.emit(I::Call(1)); - }, + } ExprKind::Lambda(args, body) => self.expr_fndef(None, args, body), ExprKind::FnDef(name, args, body) => self.expr_fndef(*name, args, body), ExprKind::And(a, b) => { @@ -449,7 +468,7 @@ impl<'a> Compiler<'a> { self.emit_discard(1); self.expr(b); self.update_instr(j1, I::JumpFalse(Arg24::from_usize(self.ip()))); - }, + } ExprKind::Or(a, b) => { self.expr(a); self.emit(I::Dup); @@ -457,7 +476,7 @@ impl<'a> Compiler<'a> { self.emit_discard(1); self.expr(b); self.update_instr(j1, I::JumpTrue(Arg24::from_usize(self.ip()))); - }, + } ExprKind::If(cond, b1, b2) => { self.expr(cond); let j1 = self.emit(I::JumpFalse(Arg24::from_usize(0))); @@ -469,10 +488,8 @@ impl<'a> Compiler<'a> { } else { self.emit(I::Nil); } - self.update_instr(j2, - I::Jump(Arg24::from_usize(self.ip())) - ); - }, + self.update_instr(j2, I::Jump(Arg24::from_usize(self.ip()))); + } ExprKind::While(cond, body) => { let start = self.ip(); self.expr(cond); @@ -484,7 +501,7 @@ impl<'a> Compiler<'a> { self.update_instr(j1, I::JumpFalse(Arg24::from_usize(self.ip()))); self.emit(I::Nil); - }, + } ExprKind::For(name, iter, body) => self.expr_for(*name, iter, body), ExprKind::Try(body, catches) => self.expr_try(body, catches), } @@ -568,55 +585,60 @@ impl<'a> Compiler<'a> { let (func, closes) = inner.finish_inner(); let func_const = self.add_const(func.into()); - let num_closed = closes.len(); + let num_closed = closes.len(); - for (name, _) in closes { - 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); - }); - }, - ResolveOutcome::Var(VarKind::Closed(n)) => { - self.emit(I::LoadLocal(Arg24::from_usize(n))); - }, - ResolveOutcome::InParent => { - let n = self.closes.len(); - self.closes.insert(name, n); - self.emit(I::ContinueUpvalue(Arg24::from_usize(n))); - }, - ResolveOutcome::None | ResolveOutcome::Var(VarKind::Global) - => panic!("upvalue resolved to none or global"), - } - } + for (name, _) in closes { + 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); + }); + } + ResolveOutcome::Var(VarKind::Closed(n)) => { + self.emit(I::LoadLocal(Arg24::from_usize(n))); + } + ResolveOutcome::InParent => { + let n = self.closes.len(); + self.closes.insert(name, n); + self.emit(I::ContinueUpvalue(Arg24::from_usize(n))); + } + ResolveOutcome::None | ResolveOutcome::Var(VarKind::Global) => { + panic!("upvalue resolved to none or global") + } + } + } - if num_closed == 0 { - self.emit(I::Const(Arg24::from_usize(func_const))); - } else { - self.emit(I::Closure(Arg24::from_usize(func_const))); - } + if num_closed == 0 { + self.emit(I::Const(Arg24::from_usize(func_const))); + } else { + self.emit(I::Closure(Arg24::from_usize(func_const))); + } - if let Some(name) = name { - self.emit(I::Dup); - self.store_var(name); - } + if let Some(name) = name { + self.emit(I::Dup); + self.store_var(name); + } } fn expr_literal(&mut self, val: &Value) { match val { - Value::Nil - => { self.emit(I::Nil); }, - Value::Bool(b) - => { self.emit(I::Bool(*b)); }, - Value::Int(i) if (-0x80_0000..=0x7f_ffff).contains(i) - => { self.emit(I::Int(Arg24::from_i64(*i))); }, - Value::Symbol(s) - => { self.emit(I::Symbol(Arg24::from_symbol(*s))); }, + Value::Nil => { + self.emit(I::Nil); + } + Value::Bool(b) => { + self.emit(I::Bool(*b)); + } + Value::Int(i) if (-0x80_0000..=0x7f_ffff).contains(i) => { + self.emit(I::Int(Arg24::from_i64(*i))); + } + Value::Symbol(s) => { + self.emit(I::Symbol(Arg24::from_symbol(*s))); + } _ => { let n = self.add_const(val.clone()); self.emit(I::Const(Arg24::from_usize(n))); - }, + } } } @@ -626,20 +648,20 @@ impl<'a> Compiler<'a> { self.expr(a); self.emit(I::Dup); self.store_var(*i); - }, + } (LValueKind::Ident(i), Some(o)) => { self.load_var(*i); self.expr(a); self.emit(I::BinaryOp(o)); self.emit(I::Dup); self.store_var(*i); - }, + } (LValueKind::Index(ct, i), None) => { self.expr(ct); self.expr(i); self.expr(a); self.emit(I::StoreIndex); - }, + } (LValueKind::Index(ct, i), Some(o)) => { self.expr(ct); self.expr(i); @@ -648,8 +670,7 @@ impl<'a> Compiler<'a> { self.expr(a); self.emit(I::BinaryOp(o)); self.emit(I::StoreIndex); - }, + } } } - } diff --git a/talc-lang/src/exception.rs b/talc-lang/src/exception.rs index 4c8176f..98065dc 100644 --- a/talc-lang/src/exception.rs +++ b/talc-lang/src/exception.rs @@ -1,5 +1,9 @@ -use std::{rc::Rc, collections::HashMap, cell::RefCell, fmt::Display}; -use crate::{lstring::LStr, symbol::{Symbol, SYM_DATA, SYM_MSG, SYM_TYPE}, value::{HashValue, Value}}; +use crate::{ + lstring::LStr, + symbol::{Symbol, SYM_DATA, SYM_MSG, SYM_TYPE}, + value::{HashValue, Value}, +}; +use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc}; pub type Result = std::result::Result; @@ -12,19 +16,35 @@ pub struct Exception { impl Exception { pub fn new(ty: Symbol) -> Self { - Self { ty, msg: None, data: None } + Self { + ty, + msg: None, + data: None, + } } pub fn new_with_msg(ty: Symbol, msg: Rc) -> Self { - Self { ty, msg: Some(msg), data: None } + Self { + ty, + msg: Some(msg), + data: None, + } } pub fn new_with_data(ty: Symbol, data: Value) -> Self { - Self { ty, msg: None, data: Some(data) } + Self { + ty, + msg: None, + data: Some(data), + } } pub fn new_with_msg_data(ty: Symbol, msg: Rc, data: Value) -> Self { - Self { ty, msg: Some(msg), data: Some(data) } + Self { + ty, + msg: Some(msg), + data: Some(data), + } } pub fn from_table(table: &Rc>>) -> Option { @@ -102,6 +122,3 @@ macro_rules! throw { } pub use throw; - - - diff --git a/talc-lang/src/lib.rs b/talc-lang/src/lib.rs index 219db23..78f84a5 100644 --- a/talc-lang/src/lib.rs +++ b/talc-lang/src/lib.rs @@ -2,13 +2,13 @@ #![warn(clippy::semicolon_if_nothing_returned)] #![warn(clippy::allow_attributes)] -pub mod symbol; -pub mod parser; -pub mod value; -pub mod exception; pub mod chunk; pub mod compiler; +pub mod exception; pub mod lstring; +pub mod parser; +pub mod symbol; +pub mod value; mod vm; pub use vm::Vm; diff --git a/talc-lang/src/lstring.rs b/talc-lang/src/lstring.rs index 7398053..80325a0 100644 --- a/talc-lang/src/lstring.rs +++ b/talc-lang/src/lstring.rs @@ -1,4 +1,15 @@ -use std::{borrow::{Borrow, BorrowMut, Cow}, ffi::{OsStr, OsString}, fmt::{self, Write}, io, iter::{Copied, FusedIterator}, ops::{Add, AddAssign, Deref, DerefMut, Index, IndexMut}, rc::Rc, slice, str::Utf8Error, string::FromUtf8Error}; +use std::{ + borrow::{Borrow, BorrowMut, Cow}, + ffi::{OsStr, OsString}, + fmt::{self, Write}, + io, + iter::{Copied, FusedIterator}, + ops::{Add, AddAssign, Deref, DerefMut, Index, IndexMut}, + rc::Rc, + slice, + str::Utf8Error, + string::FromUtf8Error, +}; use unicode_ident::{is_xid_continue, is_xid_start}; @@ -28,7 +39,9 @@ fn is_continue(b: u8) -> bool { #[inline] fn calc_continue(mut ch: u32, bytes: &[u8]) -> Option { for b in bytes { - if !is_continue(*b) { return None } + if !is_continue(*b) { + return None + } ch = (ch << 6) | (b & 0x3f) as u32; } char::from_u32(ch) @@ -40,23 +53,29 @@ fn next_codepoint(bytes: &[u8]) -> Option<(&[u8], Result)> { match init { 0..=0x7f => return Some((&bytes[1..], Ok(init as char))), 0xc0..=0xdf => 'case: { - if bytes.len() < 2 { break 'case } + if bytes.len() < 2 { + break 'case + } let Some(ch) = calc_continue(init as u32 & 0x1f, &bytes[1..2]) else { - break 'case; + break 'case }; return Some((&bytes[2..], Ok(ch))) - }, + } 0xe0..=0xef => 'case: { - if bytes.len() < 3 { break 'case } + if bytes.len() < 3 { + break 'case + } let Some(ch) = calc_continue(init as u32 & 0x0f, &bytes[1..3]) else { - break 'case; + break 'case }; return Some((&bytes[3..], Ok(ch))) - }, + } 0xf0..=0xf7 => 'case: { - if bytes.len() < 4 { break 'case } + if bytes.len() < 4 { + break 'case + } let Some(ch) = calc_continue(init as u32 & 0x07, &bytes[1..4]) else { - break 'case; + break 'case }; return Some((&bytes[4..], Ok(ch))) } @@ -69,45 +88,55 @@ fn next_codepoint(bytes: &[u8]) -> Option<(&[u8], Result)> { #[inline] fn next_codepoint_back(bytes: &[u8]) -> Option<(&[u8], Result)> { let len = bytes.len(); - if len < 1 { return None } + if len < 1 { + return None + } - let last = bytes[len-1]; + let last = bytes[len - 1]; if (0..=0x7f).contains(&last) { - return Some((&bytes[..len-1], Ok(last as char))) + return Some((&bytes[..len - 1], Ok(last as char))) } 'case: { - if !is_continue(last) { break 'case } + if !is_continue(last) { + break 'case + } - if len < 2 { break 'case } - let b1 = bytes[len-2]; + if len < 2 { + break 'case + } + let b1 = bytes[len - 2]; if 0xe0 & b1 == 0xc0 { if let Some(ch) = calc_continue(b1 as u32 & 0x1f, &[last]) { - return Some((&bytes[..len-2], Ok(ch))) + return Some((&bytes[..len - 2], Ok(ch))) }; } else if !is_continue(b1) { break 'case } - if len < 3 { break 'case } - let b2 = bytes[len-3]; + if len < 3 { + break 'case + } + let b2 = bytes[len - 3]; if 0xf0 & b2 == 0xe0 { if let Some(ch) = calc_continue(b2 as u32 & 0x0f, &[b1, last]) { - return Some((&bytes[..len-3], Ok(ch))) + return Some((&bytes[..len - 3], Ok(ch))) }; } else if !is_continue(b2) { break 'case } - if len < 4 { break 'case } - let b3 = bytes[len-4]; + if len < 4 { + break 'case + } + let b3 = bytes[len - 4]; if 0xf8 & b3 == 0xf0 { if let Some(ch) = calc_continue(b3 as u32 & 0x07, &[b2, b1, last]) { - return Some((&bytes[..len-4], Ok(ch))) + return Some((&bytes[..len - 4], Ok(ch))) }; } } - Some((&bytes[..len-1], Err(last))) + Some((&bytes[..len - 1], Err(last))) } #[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -230,47 +259,69 @@ impl BorrowMut for LString { impl From for Vec { #[inline] - fn from(value: LString) -> Self { value.inner } + fn from(value: LString) -> Self { + value.inner + } } impl From> for LString { #[inline] - fn from(value: Vec) -> Self { Self { inner: value } } + fn from(value: Vec) -> Self { + Self { inner: value } + } } impl From for LString { #[inline] - fn from(value: String) -> Self { Self { inner: value.into_bytes() } } + fn from(value: String) -> Self { + Self { + inner: value.into_bytes(), + } + } } impl From for LString { #[inline] - fn from(value: OsString) -> Self { Self { inner: value.into_encoded_bytes() } } + fn from(value: OsString) -> Self { + Self { + inner: value.into_encoded_bytes(), + } + } } impl From<&LStr> for LString { #[inline] - fn from(value: &LStr) -> Self { value.to_owned() } + fn from(value: &LStr) -> Self { + value.to_owned() + } } impl From<&str> for LString { #[inline] - fn from(value: &str) -> Self { value.to_owned().into() } + fn from(value: &str) -> Self { + value.to_owned().into() + } } impl From<&[u8]> for LString { #[inline] - fn from(value: &[u8]) -> Self { value.to_owned().into() } + fn from(value: &[u8]) -> Self { + value.to_owned().into() + } } impl From<&[u8; N]> for LString { #[inline] - fn from(value: &[u8; N]) -> Self { value.as_slice().into() } + fn from(value: &[u8; N]) -> Self { + value.as_slice().into() + } } impl From<[u8; N]> for LString { #[inline] - fn from(value: [u8; N]) -> Self { value.as_slice().into() } + fn from(value: [u8; N]) -> Self { + value.as_slice().into() + } } impl From> for LString { @@ -278,7 +329,7 @@ impl From> for LString { fn from(value: Cow<'_, LStr>) -> Self { match value { Cow::Borrowed(b) => b.to_owned(), - Cow::Owned(o) => o + Cow::Owned(o) => o, } } } @@ -306,7 +357,9 @@ impl From> for LString { impl<'a> From<&'a LStr> for &'a [u8] { #[inline] - fn from(value: &'a LStr) -> Self { &value.inner } + fn from(value: &'a LStr) -> Self { + &value.inner + } } impl<'a> From<&'a [u8]> for &'a LStr { @@ -339,7 +392,9 @@ impl<'a> From<&'a OsStr> for &'a LStr { impl<'a> From<&'a mut LStr> for &'a mut [u8] { #[inline] - fn from(value: &'a mut LStr) -> Self { &mut value.inner } + fn from(value: &'a mut LStr) -> Self { + &mut value.inner + } } impl<'a> From<&'a mut [u8]> for &'a mut LStr { @@ -351,7 +406,9 @@ impl<'a> From<&'a mut [u8]> for &'a mut LStr { impl<'a> From<&'a LString> for &'a LStr { #[inline] - fn from(value: &'a LString) -> Self { value } + fn from(value: &'a LString) -> Self { + value + } } impl From<&LStr> for Rc { @@ -412,35 +469,35 @@ impl From for LString { impl FromIterator for LString { #[inline] - fn from_iter>(iter: I) -> Self { + fn from_iter>(iter: I) -> Self { String::from_iter(iter).into() } } impl FromIterator for LString { #[inline] - fn from_iter>(iter: T) -> Self { + fn from_iter>(iter: T) -> Self { Vec::from_iter(iter).into() } } impl Extend for LString { #[inline] - fn extend>(&mut self, iter: I) { + fn extend>(&mut self, iter: I) { self.inner.extend(iter); } } impl<'a> Extend<&'a u8> for LString { #[inline] - fn extend>(&mut self, iter: I) { + fn extend>(&mut self, iter: I) { self.inner.extend(iter); } } impl Extend for LString { #[inline] - fn extend>(&mut self, iter: I) { + fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); let (lo, _) = iter.size_hint(); self.reserve(lo); @@ -450,7 +507,7 @@ impl Extend for LString { impl<'a> Extend<&'a char> for LString { #[inline] - fn extend>(&mut self, iter: I) { + fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); let (lo, _) = iter.size_hint(); self.reserve(lo); @@ -468,7 +525,9 @@ impl io::Write for LString { Ok(buf.len()) } - fn flush(&mut self) -> io::Result<()> { Ok(()) } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } } //impl fmt::Write for LString { @@ -547,15 +606,25 @@ impl<'a> Iterator for Bytes<'a> { type Item = u8; #[inline] - fn next(&mut self) -> Option { self.0.next() } + fn next(&mut self) -> Option { + self.0.next() + } #[inline] - fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } #[inline] - fn count(self) -> usize { self.0.count() } + fn count(self) -> usize { + self.0.count() + } #[inline] - fn last(self) -> Option { self.0.last() } + fn last(self) -> Option { + self.0.last() + } #[inline] - fn nth(&mut self, n: usize) -> Option { self.0.nth(n) } + fn nth(&mut self, n: usize) -> Option { + self.0.nth(n) + } #[inline] fn all bool>(&mut self, f: F) -> bool { self.0.all(f) @@ -576,7 +645,9 @@ impl<'a> Iterator for Bytes<'a> { impl<'a> ExactSizeIterator for Bytes<'a> { #[inline] - fn len(&self) -> usize { self.0.len() } + fn len(&self) -> usize { + self.0.len() + } } impl<'a> FusedIterator for Bytes<'a> {} @@ -597,7 +668,7 @@ impl<'a> Iterator for LosslessChars<'a> { #[inline] fn size_hint(&self) -> (usize, Option) { let len = self.0.len(); - ((len + 3)/4, Some(len)) + ((len + 3) / 4, Some(len)) } } @@ -618,19 +689,19 @@ impl<'a> Iterator for LosslessCharsIndices<'a> { #[inline] fn next(&mut self) -> Option { let (new_bytes, res) = next_codepoint(self.0)?; - let index = self.1; + let index = self.1; self.0 = new_bytes; - match res { - Ok(c) => self.1 += c.len_utf8(), - Err(_) => self.1 += 1, - } + match res { + Ok(c) => self.1 += c.len_utf8(), + Err(_) => self.1 += 1, + } Some((index, res)) } #[inline] fn size_hint(&self) -> (usize, Option) { let len = self.0.len(); - ((len + 3)/4, Some(len)) + ((len + 3) / 4, Some(len)) } } @@ -638,15 +709,14 @@ impl<'a> DoubleEndedIterator for LosslessCharsIndices<'a> { fn next_back(&mut self) -> Option { let (new_bytes, res) = next_codepoint_back(self.0)?; self.0 = new_bytes; - match res { - Ok(c) => self.1 -= c.len_utf8(), - Err(_) => self.1 -= 1, - } + match res { + Ok(c) => self.1 -= c.len_utf8(), + Err(_) => self.1 -= 1, + } Some((self.1, res)) } } - #[derive(Clone)] pub struct Chars<'a>(LosslessChars<'a>); @@ -702,7 +772,7 @@ impl<'a> Iterator for CharsIndices<'a> { impl<'a> DoubleEndedIterator for CharsIndices<'a> { fn next_back(&mut self) -> Option { loop { - if let (index, Ok(c)) = self.0.next_back()? { + if let (index, Ok(c)) = self.0.next_back()? { return Some((index, c)) } } @@ -731,16 +801,24 @@ impl LStr { } #[inline] - pub const fn as_bytes(&self) -> &[u8] { &self.inner } + pub const fn as_bytes(&self) -> &[u8] { + &self.inner + } #[inline] - pub fn as_bytes_mut(&mut self) -> &mut [u8] { &mut self.inner } + pub fn as_bytes_mut(&mut self) -> &mut [u8] { + &mut self.inner + } #[inline] - pub fn byte_at(&self, n: usize) -> u8 { self.inner[n] } + pub fn byte_at(&self, n: usize) -> u8 { + self.inner[n] + } #[inline] - pub fn byte_get(&self, n: usize) -> Option { self.inner.get(n).copied() } + pub fn byte_get(&self, n: usize) -> Option { + self.inner.get(n).copied() + } #[inline] pub fn bytes(&self) -> Bytes { @@ -787,11 +865,13 @@ impl LStr { #[inline] pub fn to_os_str(&self) -> Cow { - #[cfg(unix)] { + #[cfg(unix)] + { use std::os::unix::ffi::OsStrExt; Cow::Borrowed(OsStr::from_bytes(self.as_bytes())) } - #[cfg(not(unix))] { + #[cfg(not(unix))] + { Cow::Owned(self.to_string().into()) } } @@ -862,18 +942,21 @@ impl LStr { self.as_bytes().ends_with(s.as_bytes()) } - pub fn strip_prefix(&self, prefix: &LStr) -> Option<&LStr> { - self.as_bytes().strip_prefix(prefix.as_bytes()).map(LStr::from_bytes) - } + pub fn strip_prefix(&self, prefix: &LStr) -> Option<&LStr> { + self.as_bytes() + .strip_prefix(prefix.as_bytes()) + .map(LStr::from_bytes) + } - pub fn strip_suffix(&self, suffix: &LStr) -> Option<&LStr> { - self.as_bytes().strip_suffix(suffix.as_bytes()).map(LStr::from_bytes) - } + pub fn strip_suffix(&self, suffix: &LStr) -> Option<&LStr> { + self.as_bytes() + .strip_suffix(suffix.as_bytes()) + .map(LStr::from_bytes) + } pub fn is_identifier(&self) -> bool { let mut chars = self.chars_lossless(); - let first = chars.next() - .is_some_and(|ch| ch.is_ok_and(is_xid_start)); + let first = chars.next().is_some_and(|ch| ch.is_ok_and(is_xid_start)); if !first { return false } @@ -899,11 +982,15 @@ impl AddAssign<&LStr> for LString { } impl Default for &LStr { - fn default() -> Self { [].as_ref().into() } + fn default() -> Self { + [].as_ref().into() + } } impl Default for &mut LStr { - fn default() -> Self { [].as_mut().into() } + fn default() -> Self { + [].as_mut().into() + } } macro_rules! impl_index { @@ -945,4 +1032,3 @@ impl_index!(std::ops::RangeInclusive); impl_index!(std::ops::RangeTo); impl_index!(std::ops::RangeToInclusive); impl_index!((std::ops::Bound, std::ops::Bound)); - diff --git a/talc-lang/src/parser/ast.rs b/talc-lang/src/parser/ast.rs index 3c9561f..d9cdec1 100644 --- a/talc-lang/src/parser/ast.rs +++ b/talc-lang/src/parser/ast.rs @@ -6,22 +6,41 @@ use super::Span; #[derive(Clone, Copy, Debug)] pub enum BinaryOp { - Add, Sub, Mul, Div, Mod, Pow, IntDiv, - Shr, Shl, BitAnd, BitXor, BitOr, - Eq, Ne, Gt, Lt, Ge, Le, - Concat, Append, - Range, RangeIncl, + Add, + Sub, + Mul, + Div, + Mod, + Pow, + IntDiv, + Shr, + Shl, + BitAnd, + BitXor, + BitOr, + Eq, + Ne, + Gt, + Lt, + Ge, + Le, + Concat, + Append, + Range, + RangeIncl, } #[derive(Clone, Copy, Debug)] pub enum UnaryOp { - Neg, Not, RangeEndless, + Neg, + Not, + RangeEndless, } #[derive(Debug)] pub struct Expr { - pub span: Span, - pub kind: ExprKind, + pub span: Span, + pub kind: ExprKind, } #[derive(Debug)] @@ -57,14 +76,14 @@ pub enum ExprKind { } impl ExprKind { - pub fn span(self, span: Span) -> Expr { - Expr { kind: self, span } - } + pub fn span(self, span: Span) -> Expr { + Expr { kind: self, span } + } } #[derive(Debug)] pub struct CatchBlock { - pub span: Span, + pub span: Span, pub name: Option, pub types: Option>, pub body: Expr, @@ -72,8 +91,8 @@ pub struct CatchBlock { #[derive(Debug)] pub struct LValue { - pub span: Span, - pub kind: LValueKind, + pub span: Span, + pub kind: LValueKind, } #[derive(Debug)] @@ -83,214 +102,213 @@ pub enum LValueKind { } impl LValueKind { - pub fn span(self, span: Span) -> LValue { - LValue { kind: self, span } - } + pub fn span(self, span: Span) -> LValue { + LValue { kind: self, span } + } } impl LValue { - pub fn from_expr(e: Expr) -> Option { - let Expr { span, kind } = e; - match kind { - ExprKind::Ident(i) => Some(LValueKind::Ident(i).span(span)), - ExprKind::Index(l, r) => Some(LValueKind::Index(l, r).span(span)), - _ => None, - } - } + pub fn from_expr(e: Expr) -> Option { + let Expr { span, kind } = e; + match kind { + ExprKind::Ident(i) => Some(LValueKind::Ident(i).span(span)), + ExprKind::Index(l, r) => Some(LValueKind::Index(l, r).span(span)), + _ => None, + } + } } impl CatchBlock { - pub fn write_to(&self, w: &mut impl fmt::Write, depth: usize) -> fmt::Result { - write!(w, "{0: >1$}catch", "", depth*2)?; - if let Some(name) = self.name { - write!(w, " ${}", name.name())?; - } - if let Some(types) = &self.types { - write!(w, ":")?; - for ty in types { - write!(w, " {}", ty.name())?; - } - } - writeln!(w)?; - self.body.write_to(w, depth + 1) - } + pub fn write_to(&self, w: &mut impl fmt::Write, depth: usize) -> fmt::Result { + write!(w, "{0: >1$}catch", "", depth * 2)?; + if let Some(name) = self.name { + write!(w, " ${}", name.name())?; + } + if let Some(types) = &self.types { + write!(w, ":")?; + for ty in types { + write!(w, " {}", ty.name())?; + } + } + writeln!(w)?; + self.body.write_to(w, depth + 1) + } } impl fmt::Display for CatchBlock { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.write_to(f, 0) - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.write_to(f, 0) + } } impl LValue { - pub fn write_to(&self, w: &mut impl fmt::Write, depth: usize) -> fmt::Result { - write!(w, "{0: >1$}", "", depth*2)?; - let depth = depth + 1; - match &self.kind { - LValueKind::Ident(n) => writeln!(w, "${}", n.name()), - LValueKind::Index(l, r) => { - writeln!(w, "index")?; - l.write_to(w, depth)?; - r.write_to(w, depth) - }, - } - } + pub fn write_to(&self, w: &mut impl fmt::Write, depth: usize) -> fmt::Result { + write!(w, "{0: >1$}", "", depth * 2)?; + let depth = depth + 1; + match &self.kind { + LValueKind::Ident(n) => writeln!(w, "${}", n.name()), + LValueKind::Index(l, r) => { + writeln!(w, "index")?; + l.write_to(w, depth)?; + r.write_to(w, depth) + } + } + } } impl fmt::Display for LValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.write_to(f, 0) - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.write_to(f, 0) + } } impl Expr { - pub fn write_to(&self, w: &mut impl fmt::Write, depth: usize) -> fmt::Result { - write!(w, "{0: >1$}", "", depth*2)?; - let depth = depth + 1; - match &self.kind { - ExprKind::Literal(val) => writeln!(w, "{val}"), - ExprKind::Ident(n) => writeln!(w, "${}", n.name()), - ExprKind::UnaryOp(op, e) => { - writeln!(w, "uop {op:?}")?; - e.write_to(w, depth) - }, - ExprKind::BinaryOp(op, l, r) => { - writeln!(w, "bop {op:?}")?; - l.write_to(w, depth)?; - r.write_to(w, depth) - }, - ExprKind::Assign(op, l, r) => { - if let Some(op) = op { - writeln!(w, "asgn {op:?}")?; - } else { - writeln!(w, "asgn =")?; - } - l.write_to(w, depth)?; - r.write_to(w, depth) - }, - ExprKind::AssignVar(l, r) => { - writeln!(w, "var {}", l.name())?; - r.write_to(w, depth) - }, - ExprKind::AssignGlobal(l, r) => { - writeln!(w, "global {}", l.name())?; - r.write_to(w, depth) - }, - ExprKind::FnDef(n, p, b) => { - if let Some(n) = n { - writeln!(w, "fndef ${}", n.name())?; - } else { - writeln!(w, "fndef anon")?; - } - for arg in p { - writeln!(w, " ${}", arg.name())?; - } - b.write_to(w, depth) - }, - ExprKind::Index(l, r) => { - writeln!(w, "index")?; - l.write_to(w, depth)?; - r.write_to(w, depth) - }, - ExprKind::FnCall(f, a) => { - writeln!(w, "call")?; - f.write_to(w, depth)?; - for arg in a { - arg.write_to(w, depth)?; - } - Ok(()) - }, - ExprKind::AssocFnCall(d, f, a) => { - writeln!(w, "assoc call {}", f.name())?; - d.write_to(w, depth)?; - for arg in a { - arg.write_to(w, depth)?; - } - Ok(()) - }, - ExprKind::Pipe(l, r) => { - writeln!(w, "pipe")?; - l.write_to(w, depth)?; - r.write_to(w, depth) - }, - ExprKind::Block(b) => { - writeln!(w, "block")?; - for e in b { - e.write_to(w, depth)?; - } - Ok(()) - }, - ExprKind::List(l) => { - writeln!(w, "list")?; - for e in l { - e.write_to(w, depth)?; - } - Ok(()) - }, - ExprKind::Table(t) => { - writeln!(w, "list")?; - for (k, v) in t { - k.write_to(w, depth)?; - v.write_to(w, depth)?; - } - Ok(()) - }, - ExprKind::Return(e) => { - writeln!(w, "return")?; - e.write_to(w, depth) - } - ExprKind::And(l, r) => { - writeln!(w, "and")?; - l.write_to(w, depth)?; - r.write_to(w, depth) - } - ExprKind::Or(l, r) => { - writeln!(w, "or")?; - l.write_to(w, depth)?; - r.write_to(w, depth) - } - ExprKind::If(c, b, e) => { - writeln!(w, "if")?; - c.write_to(w, depth)?; - b.write_to(w, depth)?; - if let Some(e) = e { - e.write_to(w, depth)?; - } - Ok(()) - } - ExprKind::While(c, b) => { - writeln!(w, "while")?; - c.write_to(w, depth)?; - b.write_to(w, depth) - } - ExprKind::For(v, i, b) => { - writeln!(w, "for {}", v.name())?; - i.write_to(w, depth)?; - b.write_to(w, depth) - } - ExprKind::Lambda(a, b) => { - write!(w, "lambda")?; - for arg in a { - write!(w, " {}", arg.name())?; - } - writeln!(w)?; - b.write_to(w, depth) - } - ExprKind::Try(t, c) => { - write!(w, "try")?; - t.write_to(w, depth)?; - for catch in c { - catch.write_to(w, depth)?; - } - Ok(()) - } - } - } + pub fn write_to(&self, w: &mut impl fmt::Write, depth: usize) -> fmt::Result { + write!(w, "{0: >1$}", "", depth * 2)?; + let depth = depth + 1; + match &self.kind { + ExprKind::Literal(val) => writeln!(w, "{val}"), + ExprKind::Ident(n) => writeln!(w, "${}", n.name()), + ExprKind::UnaryOp(op, e) => { + writeln!(w, "uop {op:?}")?; + e.write_to(w, depth) + } + ExprKind::BinaryOp(op, l, r) => { + writeln!(w, "bop {op:?}")?; + l.write_to(w, depth)?; + r.write_to(w, depth) + } + ExprKind::Assign(op, l, r) => { + if let Some(op) = op { + writeln!(w, "asgn {op:?}")?; + } else { + writeln!(w, "asgn =")?; + } + l.write_to(w, depth)?; + r.write_to(w, depth) + } + ExprKind::AssignVar(l, r) => { + writeln!(w, "var {}", l.name())?; + r.write_to(w, depth) + } + ExprKind::AssignGlobal(l, r) => { + writeln!(w, "global {}", l.name())?; + r.write_to(w, depth) + } + ExprKind::FnDef(n, p, b) => { + if let Some(n) = n { + writeln!(w, "fndef ${}", n.name())?; + } else { + writeln!(w, "fndef anon")?; + } + for arg in p { + writeln!(w, " ${}", arg.name())?; + } + b.write_to(w, depth) + } + ExprKind::Index(l, r) => { + writeln!(w, "index")?; + l.write_to(w, depth)?; + r.write_to(w, depth) + } + ExprKind::FnCall(f, a) => { + writeln!(w, "call")?; + f.write_to(w, depth)?; + for arg in a { + arg.write_to(w, depth)?; + } + Ok(()) + } + ExprKind::AssocFnCall(d, f, a) => { + writeln!(w, "assoc call {}", f.name())?; + d.write_to(w, depth)?; + for arg in a { + arg.write_to(w, depth)?; + } + Ok(()) + } + ExprKind::Pipe(l, r) => { + writeln!(w, "pipe")?; + l.write_to(w, depth)?; + r.write_to(w, depth) + } + ExprKind::Block(b) => { + writeln!(w, "block")?; + for e in b { + e.write_to(w, depth)?; + } + Ok(()) + } + ExprKind::List(l) => { + writeln!(w, "list")?; + for e in l { + e.write_to(w, depth)?; + } + Ok(()) + } + ExprKind::Table(t) => { + writeln!(w, "list")?; + for (k, v) in t { + k.write_to(w, depth)?; + v.write_to(w, depth)?; + } + Ok(()) + } + ExprKind::Return(e) => { + writeln!(w, "return")?; + e.write_to(w, depth) + } + ExprKind::And(l, r) => { + writeln!(w, "and")?; + l.write_to(w, depth)?; + r.write_to(w, depth) + } + ExprKind::Or(l, r) => { + writeln!(w, "or")?; + l.write_to(w, depth)?; + r.write_to(w, depth) + } + ExprKind::If(c, b, e) => { + writeln!(w, "if")?; + c.write_to(w, depth)?; + b.write_to(w, depth)?; + if let Some(e) = e { + e.write_to(w, depth)?; + } + Ok(()) + } + ExprKind::While(c, b) => { + writeln!(w, "while")?; + c.write_to(w, depth)?; + b.write_to(w, depth) + } + ExprKind::For(v, i, b) => { + writeln!(w, "for {}", v.name())?; + i.write_to(w, depth)?; + b.write_to(w, depth) + } + ExprKind::Lambda(a, b) => { + write!(w, "lambda")?; + for arg in a { + write!(w, " {}", arg.name())?; + } + writeln!(w)?; + b.write_to(w, depth) + } + ExprKind::Try(t, c) => { + write!(w, "try")?; + t.write_to(w, depth)?; + for catch in c { + catch.write_to(w, depth)?; + } + Ok(()) + } + } + } } impl fmt::Display for Expr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.write_to(f, 0) - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.write_to(f, 0) + } } - diff --git a/talc-lang/src/parser/lexer.rs b/talc-lang/src/parser/lexer.rs index 6f63021..e1b0158 100644 --- a/talc-lang/src/parser/lexer.rs +++ b/talc-lang/src/parser/lexer.rs @@ -8,568 +8,595 @@ type Result = std::result::Result; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum TokenKind { - Eof, - LineSeparator, + Eof, + LineSeparator, - Bang, - BangEqual, - HashAmper, - HashAmperEqual, - HashCaret, - HashCaretEqual, - HashPipe, - HashPipeEqual, - Dollar, - Percent, - PercentEqual, - Amper, - AmperEqual, - Star, - StarEqual, - Plus, - PlusPlus, - PlusPlusEqual, - PlusEqual, - Comma, - Minus, - MinusEqual, - Arrow, - Dot, - DotDot, - DotDotStar, - DotDotEqual, - Slash, - SlashSlash, - SlashSlashEqual, - SlashEqual, - Colon, - Less, - LessLess, - LessLessEqual, - LessEqual, - Equal, - EqualEqual, - Greater, - GreaterEqual, - GreaterGreater, - GreaterGreaterEqual, - LParen, - RParen, - LBrack, - RBrack, - LBrace, - RBrace, - Backslash, - Caret, - CaretEqual, - Pipe, + Bang, + BangEqual, + HashAmper, + HashAmperEqual, + HashCaret, + HashCaretEqual, + HashPipe, + HashPipeEqual, + Dollar, + Percent, + PercentEqual, + Amper, + AmperEqual, + Star, + StarEqual, + Plus, + PlusPlus, + PlusPlusEqual, + PlusEqual, + Comma, + Minus, + MinusEqual, + Arrow, + Dot, + DotDot, + DotDotStar, + DotDotEqual, + Slash, + SlashSlash, + SlashSlashEqual, + SlashEqual, + Colon, + Less, + LessLess, + LessLessEqual, + LessEqual, + Equal, + EqualEqual, + Greater, + GreaterEqual, + GreaterGreater, + GreaterGreaterEqual, + LParen, + RParen, + LBrack, + RBrack, + LBrace, + RBrace, + Backslash, + Caret, + CaretEqual, + Pipe, - Identifier, - Integer, - Float, - Imaginary, - String, - Symbol, - And, - Break, - Catch, - Continue, - Do, - Elif, - Else, - End, - False, - Fn, - For, - Global, - If, - In, - Nil, - Not, - Or, - Return, - Then, - True, - Try, - Var, - While, + Identifier, + Integer, + Float, + Imaginary, + String, + Symbol, + And, + Break, + Catch, + Continue, + Do, + Elif, + Else, + End, + False, + Fn, + For, + Global, + If, + In, + Nil, + Not, + Or, + Return, + Then, + True, + Try, + Var, + While, } use TokenKind as K; impl TokenKind { - pub fn name(self) -> &'static str { - match self { - K::Eof => "end of file", - K::LineSeparator => "line separator", - K::Bang => "'!'", - K::BangEqual => "'!='", - K::HashAmper => "'#&'", - K::HashAmperEqual => "'#&='", - K::HashCaret => "'#^'", - K::HashCaretEqual => "'#^='", - K::HashPipe => "'#|'", - K::HashPipeEqual => "'#|='", - K::Dollar => "'$'", - K::Percent => "'%'", - K::PercentEqual => "'%='", - K::Amper => "'&'", - K::AmperEqual => "'&='", - K::Star => "'*'", - K::StarEqual => "'*='", - K::Plus => "'+'", - K::PlusPlus => "'++'", - K::PlusPlusEqual => "'++='", - K::PlusEqual => "'+='", - K::Comma => "','", - K::Minus => "'-'", - K::MinusEqual => "'-='", - K::Arrow => "'=>'", - K::Dot => "'.'", - K::DotDot => "'..'", - K::DotDotStar => "'..*'", - K::DotDotEqual => "'..='", - K::Slash => "'/'", - K::SlashSlash => "'//'", - K::SlashSlashEqual => "'//='", - K::SlashEqual => "'/='", - K::Colon => "':'", - K::Less => "'<'", - K::LessLess => "'<<'", - K::LessLessEqual => "'<<='", - K::LessEqual => "'<='", - K::Equal => "'='", - K::EqualEqual => "'=='", - K::Greater => "'>'", - K::GreaterEqual => "'>='", - K::GreaterGreater => "'>>'", - K::GreaterGreaterEqual => "'>>='", - K::LParen => "'('", - K::RParen => "')'", - K::LBrack => "'['", - K::RBrack => "']'", - K::LBrace => "'{'", - K::RBrace => "'}'", - K::Backslash => "'\\'", - K::Caret => "'^'", - K::CaretEqual => "'^='", - K::Pipe => "'|'", - K::Identifier => "identifier", - K::Integer => "integer", - K::Float => "float", - K::Imaginary => "imaginary", - K::String => "string", - K::Symbol => "symbol", - K::And => "'and'", - K::Break => "'break'", - K::Catch => "'catch'", - K::Continue => "'continue'", - K::Do => "'do'", - K::Elif => "'elif'", - K::Else => "'else'", - K::End => "'end'", - K::False => "'false'", - K::Fn => "'fn'", - K::For => "'for'", - K::Global => "'global'", - K::If => "'if'", - K::In => "'in'", - K::Nil => "'nil'", - K::Not => "'not'", - K::Or => "'or'", - K::Return => "'return'", - K::Then => "'then'", - K::True => "'true'", - K::Try => "'try'", - K::Var => "'var'", - K::While => "'while'", - } - } + pub fn name(self) -> &'static str { + match self { + K::Eof => "end of file", + K::LineSeparator => "line separator", + K::Bang => "'!'", + K::BangEqual => "'!='", + K::HashAmper => "'#&'", + K::HashAmperEqual => "'#&='", + K::HashCaret => "'#^'", + K::HashCaretEqual => "'#^='", + K::HashPipe => "'#|'", + K::HashPipeEqual => "'#|='", + K::Dollar => "'$'", + K::Percent => "'%'", + K::PercentEqual => "'%='", + K::Amper => "'&'", + K::AmperEqual => "'&='", + K::Star => "'*'", + K::StarEqual => "'*='", + K::Plus => "'+'", + K::PlusPlus => "'++'", + K::PlusPlusEqual => "'++='", + K::PlusEqual => "'+='", + K::Comma => "','", + K::Minus => "'-'", + K::MinusEqual => "'-='", + K::Arrow => "'=>'", + K::Dot => "'.'", + K::DotDot => "'..'", + K::DotDotStar => "'..*'", + K::DotDotEqual => "'..='", + K::Slash => "'/'", + K::SlashSlash => "'//'", + K::SlashSlashEqual => "'//='", + K::SlashEqual => "'/='", + K::Colon => "':'", + K::Less => "'<'", + K::LessLess => "'<<'", + K::LessLessEqual => "'<<='", + K::LessEqual => "'<='", + K::Equal => "'='", + K::EqualEqual => "'=='", + K::Greater => "'>'", + K::GreaterEqual => "'>='", + K::GreaterGreater => "'>>'", + K::GreaterGreaterEqual => "'>>='", + K::LParen => "'('", + K::RParen => "')'", + K::LBrack => "'['", + K::RBrack => "']'", + K::LBrace => "'{'", + K::RBrace => "'}'", + K::Backslash => "'\\'", + K::Caret => "'^'", + K::CaretEqual => "'^='", + K::Pipe => "'|'", + K::Identifier => "identifier", + K::Integer => "integer", + K::Float => "float", + K::Imaginary => "imaginary", + K::String => "string", + K::Symbol => "symbol", + K::And => "'and'", + K::Break => "'break'", + K::Catch => "'catch'", + K::Continue => "'continue'", + K::Do => "'do'", + K::Elif => "'elif'", + K::Else => "'else'", + K::End => "'end'", + K::False => "'false'", + K::Fn => "'fn'", + K::For => "'for'", + K::Global => "'global'", + K::If => "'if'", + K::In => "'in'", + K::Nil => "'nil'", + K::Not => "'not'", + K::Or => "'or'", + K::Return => "'return'", + K::Then => "'then'", + K::True => "'true'", + K::Try => "'try'", + K::Var => "'var'", + K::While => "'while'", + } + } } impl fmt::Display for TokenKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.name()) - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.name()) + } } #[derive(Clone, Copy, Debug)] pub struct Token<'s> { - pub span: Span, - pub content: &'s str, - pub kind: TokenKind, + pub span: Span, + pub content: &'s str, + pub kind: TokenKind, } pub struct Lexer<'s> { - src: &'s str, - chars: Peekable>, - start_pos: Pos, - pos: Pos, + src: &'s str, + chars: Peekable>, + start_pos: Pos, + pos: Pos, } impl<'s> Lexer<'s> { - pub fn new(src: &'s str) -> Self { - Self { - src, - chars: src.chars().peekable(), - start_pos: Pos::new(), - pos: Pos::new(), - } - } + pub fn new(src: &'s str) -> Self { + Self { + src, + chars: src.chars().peekable(), + start_pos: Pos::new(), + pos: Pos::new(), + } + } - fn invalid_char(&self, c: char) -> ParserError { - let span = Span::new(self.pos, self.pos.advance(c)); - let msg = match c as u32 { - c @ 0x00..=0x7f => format!("invalid character (codepoint 0x{:2x})", c), - c => format!("invalid character (codepoint U+{:04x})", c), - }; - ParserError { span, msg } - } + fn invalid_char(&self, c: char) -> ParserError { + let span = Span::new(self.pos, self.pos.advance(c)); + let msg = match c as u32 { + c @ 0x00..=0x7f => format!("invalid character (codepoint 0x{:2x})", c), + c => format!("invalid character (codepoint U+{:04x})", c), + }; + ParserError { span, msg } + } - fn filter_char(&mut self, c: Option, advance: bool) -> Result { - match c { - Some(c) if c.is_control() && !matches!(c, '\n' | '\r' | '\t') => Err(self.invalid_char(c)), - Some(c) => { - if advance { self.pos = self.pos.advance(c); } - Ok(c) - }, - None => Ok('\0'), - } - } + fn filter_char(&mut self, c: Option, advance: bool) -> Result { + match c { + Some(c) if c.is_control() && !matches!(c, '\n' | '\r' | '\t') => { + Err(self.invalid_char(c)) + } + Some(c) => { + if advance { + self.pos = self.pos.advance(c); + } + Ok(c) + } + None => Ok('\0'), + } + } - fn peek(&mut self) -> Result { - let c = self.chars.peek().copied(); - self.filter_char(c, false) - } + fn peek(&mut self) -> Result { + let c = self.chars.peek().copied(); + self.filter_char(c, false) + } - fn peek_n(&mut self, n: usize) -> Option { - let chars = &self.src[(self.pos.idx as usize)..]; - chars.chars().nth(n) - } + fn peek_n(&mut self, n: usize) -> Option { + let chars = &self.src[(self.pos.idx as usize)..]; + chars.chars().nth(n) + } - fn next(&mut self) -> Result { - let c = self.chars.next(); - self.filter_char(c, true) - } + fn next(&mut self) -> Result { + let c = self.chars.next(); + self.filter_char(c, true) + } - fn and_peek(&mut self) -> Result { - self.next()?; self.peek() - } + fn and_peek(&mut self) -> Result { + self.next()?; + self.peek() + } - fn emit(&self, kind: TokenKind) -> Result> { - let span = Span::new(self.start_pos, self.pos); - Ok(Token { - span, - content: span.of(self.src), - kind, - }) - } + fn emit(&self, kind: TokenKind) -> Result> { + let span = Span::new(self.start_pos, self.pos); + Ok(Token { + span, + content: span.of(self.src), + kind, + }) + } - fn and_emit(&mut self, kind: TokenKind) -> Result> { - self.next()?; - self.emit(kind) - } + fn and_emit(&mut self, kind: TokenKind) -> Result> { + self.next()?; + self.emit(kind) + } - fn unexpected(&mut self) -> Result> { - let c = self.peek()?; - let span = Span::new(self.pos, self.pos.advance(c)); - let msg = match c { - '\0' => "unexpected end of file".to_owned(), - '\n' => "unexpected newline character".to_owned(), - '\t' => "unexpected tab character".to_owned(), - '\r' => "unexpected return character".to_owned(), - c => format!("unexpected character {c}"), - }; - Err(ParserError { span, msg }) - } + fn unexpected(&mut self) -> Result> { + let c = self.peek()?; + let span = Span::new(self.pos, self.pos.advance(c)); + let msg = match c { + '\0' => "unexpected end of file".to_owned(), + '\n' => "unexpected newline character".to_owned(), + '\t' => "unexpected tab character".to_owned(), + '\r' => "unexpected return character".to_owned(), + c => format!("unexpected character {c}"), + }; + Err(ParserError { span, msg }) + } - fn next_ident(&mut self) -> Result> { - self.next()?; - while is_xid_continue(self.peek()?) { - self.next()?; - } - let kind = match Span::new(self.start_pos, self.pos).of(self.src) { - "and" => K::And, - "break" => K::Break, - "catch" => K::Catch, - "continue" => K::Continue, - "do" => K::Do, - "elif" => K::Elif, - "else" => K::Else, - "end" => K::End, - "false" => K::False, - "fn" => K::Fn, - "for" => K::For, - "global" => K::Global, - "if" => K::If, - "in" => K::In, - "nil" => K::Nil, - "not" => K::Not, - "or" => K::Or, - "return" => K::Return, - "then" => K::Then, - "true" => K::True, - "try" => K::Try, - "var" => K::Var, - "while" => K::While, - _ => K::Identifier, - }; - self.emit(kind) - } + fn next_ident(&mut self) -> Result> { + self.next()?; + while is_xid_continue(self.peek()?) { + self.next()?; + } + let kind = match Span::new(self.start_pos, self.pos).of(self.src) { + "and" => K::And, + "break" => K::Break, + "catch" => K::Catch, + "continue" => K::Continue, + "do" => K::Do, + "elif" => K::Elif, + "else" => K::Else, + "end" => K::End, + "false" => K::False, + "fn" => K::Fn, + "for" => K::For, + "global" => K::Global, + "if" => K::If, + "in" => K::In, + "nil" => K::Nil, + "not" => K::Not, + "or" => K::Or, + "return" => K::Return, + "then" => K::Then, + "true" => K::True, + "try" => K::Try, + "var" => K::Var, + "while" => K::While, + _ => K::Identifier, + }; + self.emit(kind) + } - fn next_int_base(&mut self, radix: u32) -> Result> { - loop { - let c = self.peek()?; - if c == '_' || c.is_digit(radix) { - self.next()?; - } else if is_xid_start(c) { - return self.unexpected() - } else { - return self.emit(K::Integer) - } - } - } + fn next_int_base(&mut self, radix: u32) -> Result> { + loop { + let c = self.peek()?; + if c == '_' || c.is_digit(radix) { + self.next()?; + } else if is_xid_start(c) { + return self.unexpected() + } else { + return self.emit(K::Integer) + } + } + } - fn next_imag(&mut self) -> Result> { - self.next()?; - if is_xid_start(self.peek()?) { - self.unexpected() - } else { - self.emit(K::Imaginary) - } - } + fn next_imag(&mut self) -> Result> { + self.next()?; + if is_xid_start(self.peek()?) { + self.unexpected() + } else { + self.emit(K::Imaginary) + } + } - fn next_float(&mut self, mut has_e: bool) -> Result> { - while !has_e { - while matches!(self.peek()?, '_' | '0'..='9') { - self.next()?; - } - match self.peek()? { - 'e' => { self.next()?; has_e = true } - 'i' => return self.next_imag(), - c if is_xid_start(c) => return self.unexpected(), - _ => return self.emit(K::Float) - } - } - if matches!(self.peek()?, '+' | '-') { - self.next()?; - } - while matches!(self.peek()?, '_' | '0'..='9') { - self.next()?; - } - match self.peek()? { - 'i' => self.next_imag(), - c if is_xid_start(c) => self.unexpected(), - _ => self.emit(K::Float) - } - } + fn next_float(&mut self, mut has_e: bool) -> Result> { + while !has_e { + while matches!(self.peek()?, '_' | '0'..='9') { + self.next()?; + } + match self.peek()? { + 'e' => { + self.next()?; + has_e = true; + } + 'i' => return self.next_imag(), + c if is_xid_start(c) => return self.unexpected(), + _ => return self.emit(K::Float), + } + } + if matches!(self.peek()?, '+' | '-') { + self.next()?; + } + while matches!(self.peek()?, '_' | '0'..='9') { + self.next()?; + } + match self.peek()? { + 'i' => self.next_imag(), + c if is_xid_start(c) => self.unexpected(), + _ => self.emit(K::Float), + } + } - fn next_number(&mut self) -> Result> { - if self.next()? == '0' { - while self.peek()? == '_' { self.next()?; } - match self.peek()? { - 'x' => { self.next()?; return self.next_int_base(16) }, - 'o' => { self.next()?; return self.next_int_base(8) }, - 's' => { self.next()?; return self.next_int_base(6) }, - 'b' => { self.next()?; return self.next_int_base(2) }, - '0'..='9' | '.' | 'e' | 'i' => (), - c if is_xid_start(c) => return self.unexpected(), - _ => return self.emit(K::Integer) - } - } - while matches!(self.peek()?, '_' | '0'..='9') { - self.next()?; - } - match self.peek()? { - 'r' => todo!("arbitrary radix integer literals"), - 'e' => { self.next()?; self.next_float(true) }, - 'i' => self.next_imag(), - '.' => { - if self.peek_n(1) == Some('.') { - self.emit(K::Integer) - } else { - self.next()?; - self.next_float(false) - } - }, - c if is_xid_start(c) => self.unexpected(), - _ => self.emit(K::Integer) - } - } + fn next_number(&mut self) -> Result> { + if self.next()? == '0' { + while self.peek()? == '_' { + self.next()?; + } + match self.peek()? { + 'x' => { + self.next()?; + return self.next_int_base(16) + } + 'o' => { + self.next()?; + return self.next_int_base(8) + } + 's' => { + self.next()?; + return self.next_int_base(6) + } + 'b' => { + self.next()?; + return self.next_int_base(2) + } + '0'..='9' | '.' | 'e' | 'i' => (), + c if is_xid_start(c) => return self.unexpected(), + _ => return self.emit(K::Integer), + } + } + while matches!(self.peek()?, '_' | '0'..='9') { + self.next()?; + } + match self.peek()? { + 'r' => todo!("arbitrary radix integer literals"), + 'e' => { + self.next()?; + self.next_float(true) + } + 'i' => self.next_imag(), + '.' => { + if self.peek_n(1) == Some('.') { + self.emit(K::Integer) + } else { + self.next()?; + self.next_float(false) + } + } + c if is_xid_start(c) => self.unexpected(), + _ => self.emit(K::Integer), + } + } - fn next_string(&mut self) -> Result> { - let double_quote = self.next()? == '"'; - loop { - match self.next()? { - '\0' => return self.unexpected(), - '"' if double_quote => break, - '\'' if !double_quote => break, - '\\' if double_quote => { self.next()?; }, - _ => (), - } - } - self.emit(K::String) - } + fn next_string(&mut self) -> Result> { + let double_quote = self.next()? == '"'; + loop { + match self.next()? { + '\0' => return self.unexpected(), + '"' if double_quote => break, + '\'' if !double_quote => break, + '\\' if double_quote => { + self.next()?; + } + _ => (), + } + } + self.emit(K::String) + } - fn next_symbol(&mut self) -> Result> { - if matches!(self.peek()?, '\'' | '"') { - self.next_string()?; - } else { - self.next_ident()?; - } - self.emit(K::Symbol) - } + fn next_symbol(&mut self) -> Result> { + if matches!(self.peek()?, '\'' | '"') { + self.next_string()?; + } else { + self.next_ident()?; + } + self.emit(K::Symbol) + } - fn line_comment(&mut self) -> Result> { - while !matches!(self.peek()?, '\0' | '\n') { - self.next()?; - } - self.next_token() - } + fn line_comment(&mut self) -> Result> { + while !matches!(self.peek()?, '\0' | '\n') { + self.next()?; + } + self.next_token() + } - fn next_token(&mut self) -> Result> { - while matches!(self.peek()?, ' ' | '\t' | '\r') { - self.next()?; - } - self.start_pos = self.pos; - match self.peek()? { - // misc - '\0' => self.emit(K::Eof), - ';' | '\n' => self.and_emit(K::LineSeparator), - '(' => self.and_emit(K::LParen), - ')' => self.and_emit(K::RParen), - '{' => self.and_emit(K::LBrace), - '}' => self.and_emit(K::RBrace), - '[' => self.and_emit(K::LBrack), - ']' => self.and_emit(K::RBrack), - ',' => self.and_emit(K::Comma), - '$' => self.and_emit(K::Dollar), - '|' => self.and_emit(K::Pipe), - '\\' => match self.and_peek()? { - '\n' => { - self.next()?; - self.next_token() - } - _ => self.emit(K::Backslash), - } - // arithmetic - '+' => match self.and_peek()? { - '+' => match self.and_peek()? { - '=' => self.and_emit(K::PlusPlusEqual), - _ => self.emit(K::PlusPlus), - }, - '=' => self.and_emit(K::PlusEqual), - _ => self.emit(K::Plus), - }, - '-' => match self.and_peek()? { - '-' => self.line_comment(), - '=' => self.and_emit(K::MinusEqual), - '>' => self.and_emit(K::Arrow), - _ => self.emit(K::Minus), - }, - '*' => match self.and_peek()? { - '=' => self.and_emit(K::StarEqual), - _ => self.emit(K::Star), - }, - '/' => match self.and_peek()? { - '/' => match self.and_peek()? { - '=' => self.and_emit(K::SlashSlashEqual), - _ => self.emit(K::SlashSlash), - }, - '=' => self.and_emit(K::SlashEqual), - _ => self.emit(K::Slash), - }, - '%' => match self.and_peek()? { - '=' => self.and_emit(K::PercentEqual), - _ => self.emit(K::Percent), - }, - '^' => match self.and_peek()? { - '=' => self.and_emit(K::CaretEqual), - _ => self.emit(K::Caret), - }, - // logical - '#' => match self.and_peek()? { - '&' => match self.and_peek()? { - '=' => self.and_emit(K::HashAmperEqual), - _ => self.emit(K::HashAmper), - } - '^' => match self.and_peek()? { - '=' => self.and_emit(K::HashCaretEqual), - _ => self.emit(K::HashCaret), - } - '|' => match self.and_peek()? { - '=' => self.and_emit(K::HashPipeEqual), - _ => self.emit(K::HashPipe), - } - '!' => self.line_comment(), - _ => self.unexpected(), - }, - // lists - '!' => match self.and_peek()? { - '=' => self.and_emit(K::BangEqual), - _ => self.emit(K::Bang), - }, - '&' => match self.and_peek()? { - '=' => self.and_emit(K::AmperEqual), - _ => self.emit(K::Amper), - }, - // comparison - '<' => match self.and_peek()? { - '<' => match self.and_peek()? { - '=' => self.and_emit(K::LessLessEqual), - _ => self.emit(K::LessLess), - }, - '=' => self.and_emit(K::LessEqual), - _ => self.emit(K::Less), - }, - '>' => match self.and_peek()? { - '>' => match self.and_peek()? { - '=' => self.and_emit(K::GreaterGreaterEqual), - _ => self.emit(K::GreaterGreater), - }, - '=' => self.and_emit(K::GreaterEqual), - _ => self.emit(K::Greater), - }, - '=' => match self.and_peek()? { - '=' => self.and_emit(K::EqualEqual), - _ => self.emit(K::Equal), - }, - // range - '.' => match self.and_peek()? { - '.' => match self.and_peek()? { - '*' => self.and_emit(K::DotDotStar), - '=' => self.and_emit(K::DotDotEqual), - _ => self.emit(K::DotDot), - }, - _ => self.emit(K::Dot), - }, - ':' => match self.and_peek()? { - c if is_xid_start(c) || c == '"' || c == '\'' => self.next_symbol(), - _ => self.emit(K::Colon), - } - '0'..='9' => self.next_number(), - c if is_xid_start(c) => self.next_ident(), - '"' | '\'' => self.next_string(), - _ => self.unexpected(), - } - } + fn next_token(&mut self) -> Result> { + while matches!(self.peek()?, ' ' | '\t' | '\r') { + self.next()?; + } + self.start_pos = self.pos; + match self.peek()? { + // misc + '\0' => self.emit(K::Eof), + ';' | '\n' => self.and_emit(K::LineSeparator), + '(' => self.and_emit(K::LParen), + ')' => self.and_emit(K::RParen), + '{' => self.and_emit(K::LBrace), + '}' => self.and_emit(K::RBrace), + '[' => self.and_emit(K::LBrack), + ']' => self.and_emit(K::RBrack), + ',' => self.and_emit(K::Comma), + '$' => self.and_emit(K::Dollar), + '|' => self.and_emit(K::Pipe), + '\\' => match self.and_peek()? { + '\n' => { + self.next()?; + self.next_token() + } + _ => self.emit(K::Backslash), + }, + // arithmetic + '+' => match self.and_peek()? { + '+' => match self.and_peek()? { + '=' => self.and_emit(K::PlusPlusEqual), + _ => self.emit(K::PlusPlus), + }, + '=' => self.and_emit(K::PlusEqual), + _ => self.emit(K::Plus), + }, + '-' => match self.and_peek()? { + '-' => self.line_comment(), + '=' => self.and_emit(K::MinusEqual), + '>' => self.and_emit(K::Arrow), + _ => self.emit(K::Minus), + }, + '*' => match self.and_peek()? { + '=' => self.and_emit(K::StarEqual), + _ => self.emit(K::Star), + }, + '/' => match self.and_peek()? { + '/' => match self.and_peek()? { + '=' => self.and_emit(K::SlashSlashEqual), + _ => self.emit(K::SlashSlash), + }, + '=' => self.and_emit(K::SlashEqual), + _ => self.emit(K::Slash), + }, + '%' => match self.and_peek()? { + '=' => self.and_emit(K::PercentEqual), + _ => self.emit(K::Percent), + }, + '^' => match self.and_peek()? { + '=' => self.and_emit(K::CaretEqual), + _ => self.emit(K::Caret), + }, + // logical + '#' => match self.and_peek()? { + '&' => match self.and_peek()? { + '=' => self.and_emit(K::HashAmperEqual), + _ => self.emit(K::HashAmper), + }, + '^' => match self.and_peek()? { + '=' => self.and_emit(K::HashCaretEqual), + _ => self.emit(K::HashCaret), + }, + '|' => match self.and_peek()? { + '=' => self.and_emit(K::HashPipeEqual), + _ => self.emit(K::HashPipe), + }, + '!' => self.line_comment(), + _ => self.unexpected(), + }, + // lists + '!' => match self.and_peek()? { + '=' => self.and_emit(K::BangEqual), + _ => self.emit(K::Bang), + }, + '&' => match self.and_peek()? { + '=' => self.and_emit(K::AmperEqual), + _ => self.emit(K::Amper), + }, + // comparison + '<' => match self.and_peek()? { + '<' => match self.and_peek()? { + '=' => self.and_emit(K::LessLessEqual), + _ => self.emit(K::LessLess), + }, + '=' => self.and_emit(K::LessEqual), + _ => self.emit(K::Less), + }, + '>' => match self.and_peek()? { + '>' => match self.and_peek()? { + '=' => self.and_emit(K::GreaterGreaterEqual), + _ => self.emit(K::GreaterGreater), + }, + '=' => self.and_emit(K::GreaterEqual), + _ => self.emit(K::Greater), + }, + '=' => match self.and_peek()? { + '=' => self.and_emit(K::EqualEqual), + _ => self.emit(K::Equal), + }, + // range + '.' => match self.and_peek()? { + '.' => match self.and_peek()? { + '*' => self.and_emit(K::DotDotStar), + '=' => self.and_emit(K::DotDotEqual), + _ => self.emit(K::DotDot), + }, + _ => self.emit(K::Dot), + }, + ':' => match self.and_peek()? { + c if is_xid_start(c) || c == '"' || c == '\'' => self.next_symbol(), + _ => self.emit(K::Colon), + }, + '0'..='9' => self.next_number(), + c if is_xid_start(c) => self.next_ident(), + '"' | '\'' => self.next_string(), + _ => self.unexpected(), + } + } - pub fn tokens(mut self) -> Result>> { - let mut res = Vec::new(); - loop { - let t = self.next_token()?; - let k = t.kind; - res.push(t); - if k == TokenKind::Eof { - return Ok(res) - } - } - } + pub fn tokens(mut self) -> Result>> { + let mut res = Vec::new(); + loop { + let t = self.next_token()?; + let k = t.kind; + res.push(t); + if k == TokenKind::Eof { + return Ok(res) + } + } + } } impl<'s> Iterator for Lexer<'s> { - type Item = Result>; + type Item = Result>; - fn next(&mut self) -> Option { - Some(self.next_token()) - } + fn next(&mut self) -> Option { + Some(self.next_token()) + } } diff --git a/talc-lang/src/parser/parser.lalrpop.OLD b/talc-lang/src/parser/parser.lalrpop.OLD deleted file mode 100644 index ebcf19a..0000000 --- a/talc-lang/src/parser/parser.lalrpop.OLD +++ /dev/null @@ -1,443 +0,0 @@ -// vim: set syn=rust: -use std::rc::Rc; -use crate::ast::*; -use crate::value::Value; -use crate::symbol::Symbol; -use crate::parser_util::*; -use crate::lstring::LStr; -use crate::lstr; -use num_complex::Complex64; - -grammar; - -extern { - type Error = ParseError; - -} - -match { - // line separator (use \ to escape newlines) - r";|\n" => LineSeparator, - - // whitespace - r"[ \t\r]*" => {}, - r"\\\r?\n" => {}, - r"--[^\n]*" => {}, - - // kw literals - "true", - "false", - "nil", - // kw variables - "global", - "var", - // kw logic - "and", - "or", - "not", - // kw control flow - "begin", - "end", - "if", - "then", - "elif", - "else", - "while", - "for", - "do", - "in", - "continue", - "break", - "try", - "catch", - "return", -} else { - // identifiers - r"[a-zA-Z_][a-zA-Z0-9_]*" => TokIdentifier, - - // literals - r"0x[0-9A-Fa-f][0-9A-Fa-f_]*" => TokHexInteger, - r"[0-9][0-9_]*" => TokDecInteger, - r"0o[0-7][0-7]*" => TokOctInteger, - r"0s[0-5][0-5]*" => TokSexInteger, - r"0b[01][01_]*" => TokBinInteger, - - r"[0-9][0-9_]*([eE][-+]?[0-9_]*[0-9][0-9_]*i?|i)|([0-9][0-9_]*)?\.[0-9_]+([eE]_*[-+]?[0-9_]*[0-9][0-9_]*)?i?" => TokFloat, - - r#""([^\\"]|\\.)*""# => TokStringDouble, - r#"'[^']*'"# => TokStringSingle, - - r#":[a-zA-Z_][a-zA-Z0-9_]*"# => TokSymbolNone, - r#":'[^']*'"# => TokSymbolSingle, - r#":"([^\\"]|\\.)*""# => TokSymbolDouble, -} else { - // everything else - _ -} - -pub Block: Box> = { - LineSeparator* LineSeparator+)*> LineSeparator* => { - let v = xs.into_iter().chain(std::iter::once(x)).map(|x| *x).collect(); - return Box::new(Expr::Block(v)); - }, - LineSeparator* => Box::new(Expr::Block(Vec::new())), -} - - -Expr: Box> = { - "return" => Box::new(Expr::Return(e)), - Assign, -} - -// -// assignment -// - - -Assign: Box> = { - => Box::new(Expr::Assign(o, l, r)), - "var" "=" => Box::new(Expr::AssignVar(i, r)), - "global" "=" => Box::new(Expr::AssignGlobal(i, r)), - Or, -} - -LValue: Box> = { - => Box::new(LValue::Ident(<>)), - "!" => Box::new(LValue::Index(l, r)), - "." => Box::new(LValue::Index(l, Box::new(Expr::Literal(Value::Symbol(Symbol::get(r)))))), -} - -AssignOp: Option = { - "=" => None, - "+=" => Some(BinaryOp::Add), - "-=" => Some(BinaryOp::Sub), - "*=" => Some(BinaryOp::Mul), - "/=" => Some(BinaryOp::Div), - "%=" => Some(BinaryOp::Mod), - "^=" => Some(BinaryOp::Pow), - "++=" => Some(BinaryOp::Concat), - "&=" => Some(BinaryOp::Append), -} - -// -// logical ops -// - -// or -Or: Box> = { - "or" => Box::new(Expr::Or(l, r)), - And, -} - -// and -And: Box> = { - "and" => Box::new(Expr::And(l, r)), - UnaryNot, -} - -// not -UnaryNot: Box> = { - "not" => Box::new(Expr::UnaryOp(UnaryOp::Not, r)), - Pipe, -} - -// -// pipe -// - -Pipe: Box> = { - "|" => Box::new(Expr::Pipe(l, r)), - Lambda, -} - -// -// lambda -// - -Lambda: Box> = { - "\\" "->" => Box::new(Expr::Lambda(xs, e)), - ":" => Box::new(Expr::Lambda(vec![lstr!("$")], e)), - "::" => Box::new(Expr::Lambda(vec![lstr!("$"), lstr!("$$")], e)), - BinaryCompare, -} - -// -// operations -// - -// == != > < >= <= -BinaryCompare: Box> = { - => Box::new(Expr::BinaryOp(o, l, r)), - BinaryConcat, -} - -CompareOp: BinaryOp = { - "==" => BinaryOp::Eq, - "!=" => BinaryOp::Ne, - ">" => BinaryOp::Gt, - "<" => BinaryOp::Lt, - ">=" => BinaryOp::Ge, - "<=" => BinaryOp::Le, -} - - -// concat (++) -BinaryConcat: Box> = { - "++" => Box::new(Expr::BinaryOp(BinaryOp::Concat, l, r)), - BinaryAppend, -} - -// append ( & ) -BinaryAppend: Box> = { - "&" => Box::new(Expr::BinaryOp(BinaryOp::Append, l, r)), - BinaryRange, -} - - - -// .. ..= ..* -BinaryRange: Box> = { - => Box::new(Expr::BinaryOp(o, l, r)), - "..*" => Box::new(Expr::UnaryOp(UnaryOp::RangeEndless, l)), - BinaryBitOr, -} - -RangeOp: BinaryOp = { - ".." => BinaryOp::Range, - "..=" => BinaryOp::RangeIncl, -} -// #| -BinaryBitOr: Box> = { - "#|" => Box::new(Expr::BinaryOp(BinaryOp::BitOr, l, r)), - BinaryBitXor, -} - -// #^ -BinaryBitXor: Box> = { - "#^" => Box::new(Expr::BinaryOp(BinaryOp::BitXor, l, r)), - BinaryBitAnd, -} - -// #& -BinaryBitAnd: Box> = { - "#&" => Box::new(Expr::BinaryOp(BinaryOp::BitAnd, l, r)), - BinaryShift, -} - -// >> << -BinaryShift: Box> = { - => Box::new(Expr::BinaryOp(o, l, r)), - BinaryAdd, -} - -ShiftOp: BinaryOp = { - ">>" => BinaryOp::Shr, - "<<" => BinaryOp::Shl, -} - -// + - -BinaryAdd: Box> = { - => Box::new(Expr::BinaryOp(o, l, r)), - BinaryMul, -} - -AddOp: BinaryOp = { - "+" => BinaryOp::Add, - "-" => BinaryOp::Sub, -} - - -// * / % -BinaryMul: Box> = { - => Box::new(Expr::BinaryOp(o, l, r)), - UnaryMinus, -} - -MulOp: BinaryOp = { - "*" => BinaryOp::Mul, - "/" => BinaryOp::Div, - "//" => BinaryOp::IntDiv, - "%" => BinaryOp::Mod, -} - - -// unary- -UnaryMinus: Box> = { - "-" => Box::new(Expr::UnaryOp(UnaryOp::Neg, r)), - BinaryPow, -} - - -// power ( ^ ) -BinaryPow: Box> = { - "^" => Box::new(Expr::BinaryOp(BinaryOp::Pow, l, r)), - BinaryIndex, -} - - -// index ( ! ) -BinaryIndex: Box> = { - "!" => Box::new(Expr::Index(l, r)), - CallOrAccess, -} - -// unary- -UnaryMinus2: Box> = { - "-" => Box::new(Expr::UnaryOp(UnaryOp::Neg, r)), - CallOrAccess, -} - - -// -// things -// - -// function call -CallOrAccess: Box> = { - "(" ")" => Box::new(Expr::FnCall(l, args)), - "->" "(" ")" => Box::new(Expr::AssocFnCall(l, Symbol::get(r), args)), - "." => Box::new(Expr::Index(l, Box::new(Expr::Literal(Value::Symbol(Symbol::get(r)))))), - Term, -} - -// -// base -// - - -Term: Box> = { - Identifier => Box::new(Expr::Ident(<>)), - TermNotIdent, -} - -TermNotIdent: Box> = { - "(" ")" => <>, - "[" "]" => Box::new(Expr::List(<>)), - "{" "}" => Box::new(Expr::Table(<>)), - "$" => Box::new(Expr::Ident(lstr!("$"))), - "$$" => Box::new(Expr::Ident(lstr!("$$"))), - - "do" "end" => <>, - "if" => <>, - "while" "do" "end" - => Box::new(Expr::While(a, b)), - "for" "in" "do" "end" - => Box::new(Expr::For(v, a, b)), - "try" => { - ch.reverse(); - Box::new(Expr::Try(b, ch)) - }, - - Literal => Box::new(Expr::Literal(<>)), -} - -IfStmtChain: Box> = { - "then" "end" => Box::new(Expr::If(a, b, None)), - "then" "else" "end" => Box::new(Expr::If(a, b, Some(c))), - "then" "elif" => Box::new(Expr::If(a, b, Some(c))), -} - -CatchChain: Vec> = { - "catch" )?> "do" => { - - ch.push(CatchBlock { name, types: Some(types), body: *b }); - ch - }, - "catch" "*" )?> "do" => { - ch.push(CatchBlock { name, types: None, body: *b }); - ch - }, - "end" => Vec::new(), -} - -SymbolList: Vec = { - ",")*> => { - if let Some(x) = x { xs.push(x) }; - xs - }, -} - -ExprList: Vec> = { - ",")*> => { - let mut xs: Vec<_> = xs.into_iter().map(|x| *x).collect(); - if let Some(x) = x { xs.push(*x) }; - xs - } -} - -TableItems: Vec<(Expr<'input>, Expr<'input>)> = { - ",")*> => { - if let Some(x) = x { xs.push(x) }; - xs - } -} - -TableItem: (Expr<'input>, Expr<'input>) = { - "=" => (k, *v), -} - -TableKey: Expr<'input> = { - Identifier => Expr::Literal(Value::Symbol(Symbol::get(<>))), - TermNotIdent => *<>, -} - -IdentList: Vec<&'input LStr> = { - ",")*> - => { if let Some(x) = x { xs.push(x) }; xs } -} - -Identifier: &'input LStr = TokIdentifier => <>.into(); - - -// -// literals -// - -Literal: Value = { - TokDecInteger =>? parse_int(<>, 10) - .map(Value::Int) - .map_err(|e| ParseError::from(e).into()), - TokHexInteger =>? parse_int(&<>[2..], 16) - .map(Value::Int) - .map_err(|e| ParseError::from(e).into()), - TokOctInteger =>? parse_int(&<>[2..], 8) - .map(Value::Int) - .map_err(|e| ParseError::from(e).into()), - TokSexInteger =>? parse_int(&<>[2..], 6) - .map(Value::Int) - .map_err(|e| ParseError::from(e).into()), - TokBinInteger =>? parse_int(&<>[2..], 2) - .map(Value::Int) - .map_err(|e| ParseError::from(e).into()), - =>? { - if let Some(f) = f.strip_suffix('i') { - parse_float(f) - .map(|im| Value::Complex(Complex64::new(0.0, im))) - .map_err(|e| ParseError::from(e).into()) - } else { - parse_float(f) - .map(Value::Float) - .map_err(|e| ParseError::from(e).into()) - } - }, - StringLiteral => Value::String(<>), - SymbolLiteral => Value::Symbol(<>), - "true" => Value::Bool(true), - "false" => Value::Bool(false), - "nil" => Value::Nil, -} - -StringLiteral: Rc = { - TokStringSingle => LStr::from_str(&<>[1..<>.len()-1]).into(), - TokStringDouble =>? parse_str_escapes(&<>[1..<>.len()-1]) - .map(|s| s.into()) - .map_err(|e| ParseError::from(e).into()), -} - -SymbolLiteral: Symbol = { - TokSymbolNone => Symbol::get(&<>[1..]), - TokSymbolSingle => Symbol::get(&<>[2..<>.len()-1]), - TokSymbolDouble =>? parse_str_escapes(&<>[2..<>.len()-1]) - .map(|s| Symbol::get(&s)) - .map_err(|e| ParseError::from(e).into()), -} diff --git a/talc-lang/src/parser/parser.rs b/talc-lang/src/parser/parser.rs index 2e23211..ebef907 100644 --- a/talc-lang/src/parser/parser.rs +++ b/talc-lang/src/parser/parser.rs @@ -1,12 +1,18 @@ use std::iter::Peekable; +use crate::{ + symbol::{Symbol, SYM_DOLLAR_SIGN}, + value::Value, +}; -use crate::{symbol::{Symbol, SYM_DOLLAR_SIGN}, value::Value}; - -use super::{ast::{BinaryOp, CatchBlock, Expr, ExprKind, LValue, UnaryOp}, parse_float, parse_int_literal, parse_str_escapes, Lexer, ParserError, Span, SpanParserError, Token, TokenKind}; +use super::{ + ast::{BinaryOp, CatchBlock, Expr, ExprKind, LValue, UnaryOp}, + parse_float, parse_int_literal, parse_str_escapes, Lexer, ParserError, Span, SpanParserError, + Token, TokenKind, +}; use num_complex::Complex64; -use TokenKind as T; use ExprKind as E; +use TokenKind as T; type Result = std::result::Result; @@ -23,7 +29,7 @@ macro_rules! expect { macro_rules! expect_inner { ($e:expr, $($tok:path)|*) => { { - let mut s = format!("unexpected token {}, expected ", $e.name()) + let mut s = format!("unexpected token {}, expected ", $e.name()) + $($tok.name() + ", " +)* ""; s.truncate(s.len() - 2); s @@ -32,14 +38,13 @@ macro_rules! expect_inner { } macro_rules! try_next { - ($self:expr, $pat:pat) => {{ - let t = $self.peek()?; - match t.kind { - $pat => Some($self.next()?), - _ => None, - - } - }}; + ($self:expr, $pat:pat) => {{ + let t = $self.peek()?; + match t.kind { + $pat => Some($self.next()?), + _ => None, + } + }}; } macro_rules! throw { @@ -49,610 +54,611 @@ macro_rules! throw { } impl TokenKind { - pub fn assign_op(self) -> Option> { - Some(match self { - T::PlusPlusEqual => Some(BinaryOp::Concat), - T::AmperEqual => Some(BinaryOp::Append), - T::HashPipeEqual => Some(BinaryOp::BitOr), - T::HashCaretEqual => Some(BinaryOp::BitXor), - T::HashAmperEqual => Some(BinaryOp::BitAnd), - T::LessLessEqual => Some(BinaryOp::Shl), - T::GreaterGreaterEqual => Some(BinaryOp::Shr), - T::PlusEqual => Some(BinaryOp::Add), - T::MinusEqual => Some(BinaryOp::Sub), - T::StarEqual => Some(BinaryOp::Mul), - T::SlashEqual => Some(BinaryOp::Div), - T::SlashSlashEqual => Some(BinaryOp::IntDiv), - T::PercentEqual => Some(BinaryOp::Mod), - T::CaretEqual => Some(BinaryOp::Pow), - T::Equal => None, - _ => return None, - }) - } + pub fn assign_op(self) -> Option> { + Some(match self { + T::PlusPlusEqual => Some(BinaryOp::Concat), + T::AmperEqual => Some(BinaryOp::Append), + T::HashPipeEqual => Some(BinaryOp::BitOr), + T::HashCaretEqual => Some(BinaryOp::BitXor), + T::HashAmperEqual => Some(BinaryOp::BitAnd), + T::LessLessEqual => Some(BinaryOp::Shl), + T::GreaterGreaterEqual => Some(BinaryOp::Shr), + T::PlusEqual => Some(BinaryOp::Add), + T::MinusEqual => Some(BinaryOp::Sub), + T::StarEqual => Some(BinaryOp::Mul), + T::SlashEqual => Some(BinaryOp::Div), + T::SlashSlashEqual => Some(BinaryOp::IntDiv), + T::PercentEqual => Some(BinaryOp::Mod), + T::CaretEqual => Some(BinaryOp::Pow), + T::Equal => None, + _ => return None, + }) + } - pub fn binary_op(self) -> Option { - Some(match self { - T::EqualEqual => BinaryOp::Eq, - T::BangEqual => BinaryOp::Ne, - T::Greater => BinaryOp::Gt, - T::GreaterEqual => BinaryOp::Ge, - T::Less => BinaryOp::Lt, - T::LessEqual => BinaryOp::Le, - T::PlusPlus => BinaryOp::Concat, - T::Amper => BinaryOp::Append, - T::DotDot => BinaryOp::Range, - T::DotDotEqual => BinaryOp::RangeIncl, - T::HashPipe => BinaryOp::BitOr, - T::HashCaret => BinaryOp::BitXor, - T::HashAmper => BinaryOp::BitAnd, - T::LessLess => BinaryOp::Shl, - T::GreaterGreater => BinaryOp::Shr, - T::Plus => BinaryOp::Add, - T::Minus => BinaryOp::Sub, - T::Star => BinaryOp::Mul, - T::Slash => BinaryOp::Div, - T::SlashSlash => BinaryOp::IntDiv, - T::Percent => BinaryOp::Mod, - T::Caret => BinaryOp::Pow, - _ => return None, - }) - } + pub fn binary_op(self) -> Option { + Some(match self { + T::EqualEqual => BinaryOp::Eq, + T::BangEqual => BinaryOp::Ne, + T::Greater => BinaryOp::Gt, + T::GreaterEqual => BinaryOp::Ge, + T::Less => BinaryOp::Lt, + T::LessEqual => BinaryOp::Le, + T::PlusPlus => BinaryOp::Concat, + T::Amper => BinaryOp::Append, + T::DotDot => BinaryOp::Range, + T::DotDotEqual => BinaryOp::RangeIncl, + T::HashPipe => BinaryOp::BitOr, + T::HashCaret => BinaryOp::BitXor, + T::HashAmper => BinaryOp::BitAnd, + T::LessLess => BinaryOp::Shl, + T::GreaterGreater => BinaryOp::Shr, + T::Plus => BinaryOp::Add, + T::Minus => BinaryOp::Sub, + T::Star => BinaryOp::Mul, + T::Slash => BinaryOp::Div, + T::SlashSlash => BinaryOp::IntDiv, + T::Percent => BinaryOp::Mod, + T::Caret => BinaryOp::Pow, + _ => return None, + }) + } - pub fn unary_op(self) -> Option { - match self { - T::Minus => Some(UnaryOp::Neg), - T::Not => Some(UnaryOp::Not), - _ => None, - } - } + pub fn unary_op(self) -> Option { + match self { + T::Minus => Some(UnaryOp::Neg), + T::Not => Some(UnaryOp::Not), + _ => None, + } + } - pub fn postfix_unary_op(self) -> Option { - match self { - T::DotDotStar => Some(UnaryOp::RangeEndless), - _ => None, - } - } + pub fn postfix_unary_op(self) -> Option { + match self { + T::DotDotStar => Some(UnaryOp::RangeEndless), + _ => None, + } + } } impl UnaryOp { - pub fn precedence(self) -> u8 { - match self { - UnaryOp::Not => 0, - UnaryOp::RangeEndless => 40, - UnaryOp::Neg => 110, - } - } + pub fn precedence(self) -> u8 { + match self { + UnaryOp::Not => 0, + UnaryOp::RangeEndless => 40, + UnaryOp::Neg => 110, + } + } } impl BinaryOp { - pub fn precedence(self) -> (u8, u8) { - match self { - BinaryOp::Eq - | BinaryOp::Ne - | BinaryOp::Gt - | BinaryOp::Ge - | BinaryOp::Lt - | BinaryOp::Le => (10, 10), - BinaryOp::Concat => (20, 25), - BinaryOp::Append => (30, 35), - BinaryOp::Range - | BinaryOp::RangeIncl => (40, 40), - BinaryOp::BitOr => (50, 55), - BinaryOp::BitXor => (60, 65), - BinaryOp::BitAnd => (70, 75), - BinaryOp::Shl - | BinaryOp::Shr => (80, 85), - BinaryOp::Add - | BinaryOp::Sub => (90, 95), - BinaryOp::Mul - | BinaryOp::Div - | BinaryOp::IntDiv - | BinaryOp::Mod => (100, 105), - BinaryOp::Pow => (125, 120), - } - } + pub fn precedence(self) -> (u8, u8) { + match self { + BinaryOp::Eq + | BinaryOp::Ne + | BinaryOp::Gt + | BinaryOp::Ge + | BinaryOp::Lt + | BinaryOp::Le => (10, 10), + BinaryOp::Concat => (20, 25), + BinaryOp::Append => (30, 35), + BinaryOp::Range | BinaryOp::RangeIncl => (40, 40), + BinaryOp::BitOr => (50, 55), + BinaryOp::BitXor => (60, 65), + BinaryOp::BitAnd => (70, 75), + BinaryOp::Shl | BinaryOp::Shr => (80, 85), + BinaryOp::Add | BinaryOp::Sub => (90, 95), + BinaryOp::Mul | BinaryOp::Div | BinaryOp::IntDiv | BinaryOp::Mod => (100, 105), + BinaryOp::Pow => (125, 120), + } + } } #[inline(always)] fn b(t: T) -> Box { - Box::new(t) + Box::new(t) } impl TokenKind { - fn expr_first(self) -> bool { - matches!(self, - | T::Return - | T::Var - | T::Global - | T::Fn - | T::Not - | T::Backslash - | T::Colon - | T::Minus - | T::Identifier - | T::LParen - | T::LBrack - | T::LBrace - | T::Dollar - | T::Do - | T::If - | T::While - | T::For - | T::Try - | T::Integer - | T::Float - | T::Imaginary - | T::String - | T::Symbol - | T::True - | T::False - | T::Nil - ) - } + fn expr_first(self) -> bool { + matches!(self, |T::Return| T::Var + | T::Global + | T::Fn | T::Not + | T::Backslash + | T::Colon + | T::Minus + | T::Identifier + | T::LParen + | T::LBrack + | T::LBrace + | T::Dollar + | T::Do | T::If + | T::While + | T::For | T::Try + | T::Integer + | T::Float + | T::Imaginary + | T::String + | T::Symbol + | T::True | T::False + | T::Nil) + } } - struct Parser<'s> { - lexer: Peekable>, + lexer: Peekable>, } impl<'s> Parser<'s> { - fn new(src: &'s str) -> Self { - Self { lexer: Lexer::new(src).peekable() } - } + fn new(src: &'s str) -> Self { + Self { + lexer: Lexer::new(src).peekable(), + } + } - fn next(&mut self) -> Result> { - self.lexer.next().unwrap() - } + fn next(&mut self) -> Result> { + self.lexer.next().unwrap() + } - fn peek(&mut self) -> Result> { - self.lexer.peek().unwrap().clone() - } + fn peek(&mut self) -> Result> { + self.lexer.peek().unwrap().clone() + } + fn parse_table_items(&mut self) -> Result> { + let mut items = Vec::new(); + while self.peek()?.kind.expr_first() { + let key = if let Some(id) = try_next!(self, T::Identifier) { + E::Literal(Symbol::get(id.content).into()).span(id.span) + } else { + self.parse_term_not_ident()? + }; - fn parse_table_items(&mut self) -> Result> { - let mut items = Vec::new(); - while self.peek()?.kind.expr_first() { - let key = if let Some(id) = try_next!(self, T::Identifier) { - E::Literal(Symbol::get(id.content).into()).span(id.span) - } else { - self.parse_term_not_ident()? - }; + expect!(self, T::Equal); - expect!(self, T::Equal); + let value = self.parse_expr()?; - let value = self.parse_expr()?; + items.push((key, value)); - items.push((key, value)); + if try_next!(self, T::Comma).is_none() { + break + } + } + Ok(items) + } - if try_next!(self, T::Comma).is_none() { - break - } - } - Ok(items) - } + fn parse_expr_list(&mut self) -> Result> { + let mut exprs = Vec::new(); + while self.peek()?.kind.expr_first() { + exprs.push(self.parse_expr()?); + if try_next!(self, T::Comma).is_none() { + break + } + } + Ok(exprs) + } - fn parse_expr_list(&mut self) -> Result> { - let mut exprs = Vec::new(); - while self.peek()?.kind.expr_first() { - exprs.push(self.parse_expr()?); - if try_next!(self, T::Comma).is_none() { - break - } - } - Ok(exprs) - } + fn parse_ident_list(&mut self) -> Result> { + let mut idents = Vec::new(); + while let Some(tok) = try_next!(self, T::Identifier) { + idents.push(Symbol::get(tok.content)); + if try_next!(self, T::Comma).is_none() { + break + } + } + Ok(idents) + } - fn parse_ident_list(&mut self) -> Result> { - let mut idents = Vec::new(); - while let Some(tok) = try_next!(self, T::Identifier) { - idents.push(Symbol::get(tok.content)); - if try_next!(self, T::Comma).is_none() { - break - } - } - Ok(idents) - } + fn parse_symbol_list(&mut self) -> Result> { + let mut syms = Vec::new(); + while let Some(tok) = try_next!(self, T::Symbol) { + syms.push(Symbol::get(tok.content)); + if try_next!(self, T::Comma).is_none() { + break + } + } + Ok(syms) + } - fn parse_symbol_list(&mut self) -> Result> { - let mut syms = Vec::new(); - while let Some(tok) = try_next!(self, T::Symbol) { - syms.push(Symbol::get(tok.content)); - if try_next!(self, T::Comma).is_none() { - break - } - } - Ok(syms) - } + fn parse_catch_blocks(&mut self) -> Result<(Vec, Span)> { + let mut blocks = Vec::new(); + let mut outer_span = self.peek()?.span; + loop { + let tok = expect!(self, T::Catch | T::End); + if tok.kind == T::End { + break + } - fn parse_catch_blocks(&mut self) -> Result<(Vec, Span)> { - let mut blocks = Vec::new(); - let mut outer_span = self.peek()?.span; - loop { - let tok = expect!(self, T::Catch | T::End); - if tok.kind == T::End { break } + let types = match try_next!(self, T::Star) { + Some(_) => None, + None => Some(self.parse_symbol_list()?), + }; - let types = match try_next!(self, T::Star) { - Some(_) => None, - None => Some(self.parse_symbol_list()?) - }; + let name = match try_next!(self, T::In) { + Some(_) => Some(Symbol::get(expect!(self, T::Identifier).content)), + None => None, + }; - let name = match try_next!(self, T::In) { - Some(_) => Some(Symbol::get(expect!(self, T::Identifier).content)), - None => None, - }; + expect!(self, T::Do); + let body = self.parse_block()?; - expect!(self, T::Do); - let body = self.parse_block()?; - - let span = tok.span + body.span; - blocks.push(CatchBlock { span, name, types, body }); - outer_span += span; - } - Ok((blocks, outer_span)) - } + let span = tok.span + body.span; + blocks.push(CatchBlock { + span, + name, + types, + body, + }); + outer_span += span; + } + Ok((blocks, outer_span)) + } - fn parse_if_stmt_chain(&mut self) -> Result { - let cond = self.parse_expr()?; - expect!(self, T::Then); - let body = self.parse_block()?; - let tok = expect!(self, T::End | T::Else | T::Elif); - let span = cond.span + tok.span; - match tok.kind { - T::End => Ok(E::If(b(cond), b(body), None).span(span)), - T::Else => { - let else_body = self.parse_block()?; - expect!(self, T::End); - let span = span + else_body.span; - Ok(E::If(b(cond), b(body), Some(b(else_body))).span(span)) - } - T::Elif => { - let elif_body = self.parse_if_stmt_chain()?; - let span = span + elif_body.span; - Ok(E::If(b(cond), b(body), Some(b(elif_body))).span(span)) - } - _ => unreachable!("parse_if_stmt_chain: guaranteed by expect!") - } + fn parse_if_stmt_chain(&mut self) -> Result { + let cond = self.parse_expr()?; + expect!(self, T::Then); + let body = self.parse_block()?; + let tok = expect!(self, T::End | T::Else | T::Elif); + let span = cond.span + tok.span; + match tok.kind { + T::End => Ok(E::If(b(cond), b(body), None).span(span)), + T::Else => { + let else_body = self.parse_block()?; + expect!(self, T::End); + let span = span + else_body.span; + Ok(E::If(b(cond), b(body), Some(b(else_body))).span(span)) + } + T::Elif => { + let elif_body = self.parse_if_stmt_chain()?; + let span = span + elif_body.span; + Ok(E::If(b(cond), b(body), Some(b(elif_body))).span(span)) + } + _ => unreachable!("parse_if_stmt_chain: guaranteed by expect!"), + } + } - } + fn parse_term_not_ident(&mut self) -> Result { + let tok = self.next()?; + match tok.kind { + T::LParen => { + let e = self.parse_expr()?; + expect!(self, T::RParen); + Ok(e) + } + T::LBrack => { + let args = self.parse_expr_list()?; + let end = expect!(self, T::RBrack); + Ok(E::List(args).span(tok.span + end.span)) + } + T::LBrace => { + let args = self.parse_table_items()?; + let end = expect!(self, T::RBrace); + Ok(E::Table(args).span(tok.span + end.span)) + } + T::Dollar => Ok(E::Ident(*SYM_DOLLAR_SIGN).span(tok.span)), + T::Do => { + let b = self.parse_block()?; + expect!(self, T::End); + Ok(b) + } + T::If => self.parse_if_stmt_chain(), + T::While => { + let cond = self.parse_expr()?; + expect!(self, T::Do); + let body = self.parse_block()?; + let end = expect!(self, T::End); + let span = cond.span + end.span; + Ok(E::While(b(cond), b(body)).span(span)) + } + T::For => { + let var = expect!(self, T::Identifier); + expect!(self, T::In); + let iter = self.parse_expr()?; + expect!(self, T::Do); + let body = self.parse_block()?; + let end = expect!(self, T::End); + let span = var.span + end.span; + Ok(E::For(Symbol::get(var.content), b(iter), b(body)).span(span)) + } + T::Try => { + let body = self.parse_block()?; + let (catch, span) = self.parse_catch_blocks()?; + Ok(E::Try(b(body), catch).span(tok.span + span)) + } + T::Integer => { + let n = parse_int_literal(tok.content).span_err(tok.span)?; + Ok(E::Literal(n.into()).span(tok.span)) + } + T::Float => { + let x = parse_float(tok.content).span_err(tok.span)?; + Ok(E::Literal(x.into()).span(tok.span)) + } + T::Imaginary => { + let x = parse_float(&tok.content[..tok.content.len() - 1]).span_err(tok.span)?; + Ok(E::Literal(Complex64::new(0.0, x).into()).span(tok.span)) + } + T::String => { + let inner = &tok.content[1..tok.content.len() - 1]; + let s = if &tok.content[..1] == "\"" { + parse_str_escapes(inner).span_err(tok.span)? + } else { + inner.into() + }; + Ok(E::Literal(s.into()).span(tok.span)) + } + T::Symbol => { + let inner = &tok.content[1..]; + let s = match inner.chars().next() { + Some('\'') => Symbol::get(&inner[1..inner.len() - 1]), + Some('\"') => Symbol::get( + &parse_str_escapes(&inner[1..inner.len() - 1]).span_err(tok.span)?, + ), + _ => Symbol::get(inner), + }; + Ok(E::Literal(s.into()).span(tok.span)) + } + T::True => Ok(E::Literal(Value::Bool(true)).span(tok.span)), + T::False => Ok(E::Literal(Value::Bool(false)).span(tok.span)), + T::Nil => Ok(E::Literal(Value::Nil).span(tok.span)), + t => throw!( + tok.span, + "unexpected token {}, expected expression", + t.name() + ), + } + } - fn parse_term_not_ident(&mut self) -> Result { - let tok = self.next()?; - match tok.kind { - T::LParen => { - let e = self.parse_expr()?; - expect!(self, T::RParen); - Ok(e) - }, - T::LBrack => { - let args = self.parse_expr_list()?; - let end = expect!(self, T::RBrack); - Ok(E::List(args).span(tok.span + end.span)) - }, - T::LBrace => { - let args = self.parse_table_items()?; - let end = expect!(self, T::RBrace); - Ok(E::Table(args).span(tok.span + end.span)) - }, - T::Dollar => Ok(E::Ident(*SYM_DOLLAR_SIGN).span(tok.span)), - T::Do => { - let b = self.parse_block()?; - expect!(self, T::End); - Ok(b) - }, - T::If => self.parse_if_stmt_chain(), - T::While => { - let cond = self.parse_expr()?; - expect!(self, T::Do); - let body = self.parse_block()?; - let end = expect!(self, T::End); - let span = cond.span + end.span; - Ok(E::While(b(cond), b(body)).span(span)) - }, - T::For => { - let var = expect!(self, T::Identifier); - expect!(self, T::In); - let iter = self.parse_expr()?; - expect!(self, T::Do); - let body = self.parse_block()?; - let end = expect!(self, T::End); - let span = var.span + end.span; - Ok(E::For(Symbol::get(var.content), b(iter), b(body)).span(span)) - }, - T::Try => { - let body = self.parse_block()?; - let (catch, span) = self.parse_catch_blocks()?; - Ok(E::Try(b(body), catch).span(tok.span + span)) - }, - T::Integer => { - let n = parse_int_literal(tok.content) - .span_err(tok.span)?; - Ok(E::Literal(n.into()).span(tok.span)) - }, - T::Float => { - let x = parse_float(tok.content) - .span_err(tok.span)?; - Ok(E::Literal(x.into()).span(tok.span)) - }, - T::Imaginary => { - let x = parse_float(&tok.content[..tok.content.len()-1]) - .span_err(tok.span)?; - Ok(E::Literal(Complex64::new(0.0, x).into()).span(tok.span)) - }, - T::String => { - let inner = &tok.content[1..tok.content.len()-1]; - let s = if &tok.content[..1] == "\"" { - parse_str_escapes(inner).span_err(tok.span)? - } else { - inner.into() - }; - Ok(E::Literal(s.into()).span(tok.span)) - }, - T::Symbol => { - let inner = &tok.content[1..]; - let s = match inner.chars().next() { - Some('\'') => Symbol::get(&inner[1..inner.len()-1]), - Some('\"') => Symbol::get( - &parse_str_escapes(&inner[1..inner.len()-1]) - .span_err(tok.span)? - ), - _ => Symbol::get(inner), - }; - Ok(E::Literal(s.into()).span(tok.span)) - }, - T::True => Ok(E::Literal(Value::Bool(true)).span(tok.span)), - T::False => Ok(E::Literal(Value::Bool(false)).span(tok.span)), - T::Nil => Ok(E::Literal(Value::Nil).span(tok.span)), - t => throw!(tok.span, "unexpected token {}, expected expression", t.name()), - } - } + fn parse_term(&mut self) -> Result { + if let Some(tok) = try_next!(self, T::Identifier) { + Ok(E::Ident(Symbol::get(tok.content)).span(tok.span)) + } else { + self.parse_term_not_ident() + } + } - fn parse_term(&mut self) -> Result { - if let Some(tok) = try_next!(self, T::Identifier) { - Ok(E::Ident(Symbol::get(tok.content)).span(tok.span)) - } else { - self.parse_term_not_ident() - } - } + fn parse_access(&mut self) -> Result { + let mut lhs = self.parse_term()?; + loop { + let tok = try_next!(self, T::LParen | T::LBrack | T::Arrow | T::Dot); + match tok.map(|t| t.kind) { + Some(T::LParen) => { + let args = self.parse_expr_list()?; + let end = expect!(self, T::RParen); + let lhs_span = lhs.span; + lhs = E::FnCall(b(lhs), args).span(lhs_span + end.span); + } + Some(T::LBrack) => { + let idx = self.parse_expr()?; + let end = expect!(self, T::RBrack); + let lhs_span = lhs.span; + lhs = E::Index(b(lhs), b(idx)).span(lhs_span + end.span); + } + Some(T::Arrow) => { + let field = expect!(self, T::Identifier); + let symbol = Symbol::get(field.content); + expect!(self, T::LParen); + let args = self.parse_expr_list()?; + let end = expect!(self, T::RParen); + let lhs_span = lhs.span; + lhs = E::AssocFnCall(b(lhs), symbol, args).span(lhs_span + end.span); + } + Some(T::Dot) => { + let field = expect!(self, T::Identifier); + let symbol = Symbol::get(field.content); + let idx = E::Literal(symbol.into()).span(field.span); + let lhs_span = lhs.span; + lhs = E::Index(b(lhs), b(idx)).span(lhs_span + field.span); + } + None => break, + _ => unreachable!("parse_access: guaranteed by try_next!"), + } + } + Ok(lhs) + } - fn parse_access(&mut self) -> Result { - let mut lhs = self.parse_term()?; - loop { - let tok = try_next!(self, T::LParen | T::LBrack | T::Arrow | T::Dot); - match tok.map(|t| t.kind) { - Some(T::LParen) => { - let args = self.parse_expr_list()?; - let end = expect!(self, T::RParen); - let lhs_span = lhs.span; - lhs = E::FnCall(b(lhs), args).span(lhs_span + end.span); - } - Some(T::LBrack) => { - let idx = self.parse_expr()?; - let end = expect!(self, T::RBrack); - let lhs_span = lhs.span; - lhs = E::Index(b(lhs), b(idx)).span(lhs_span + end.span); - } - Some(T::Arrow) => { - let field = expect!(self, T::Identifier); - let symbol = Symbol::get(field.content); - expect!(self, T::LParen); - let args = self.parse_expr_list()?; - let end = expect!(self, T::RParen); - let lhs_span = lhs.span; - lhs = E::AssocFnCall(b(lhs), symbol, args).span(lhs_span + end.span); - } - Some(T::Dot) => { - let field = expect!(self, T::Identifier); - let symbol = Symbol::get(field.content); - let idx = E::Literal(symbol.into()).span(field.span); - let lhs_span = lhs.span; - lhs = E::Index(b(lhs), b(idx)).span(lhs_span + field.span); - } - None => break, - _ => unreachable!("parse_access: guaranteed by try_next!"), - } - } - Ok(lhs) - } + fn parse_precedence(&mut self, min_prec: u8) -> Result { + let mut lhs = if let Some(op) = self.peek()?.kind.unary_op() { + let tok = self.next()?; + let rhs = self.parse_precedence(op.precedence())?; + let span = tok.span + rhs.span; + E::UnaryOp(op, b(rhs)).span(span) + } else { + self.parse_access()? + }; + let mut span = lhs.span; - fn parse_precedence(&mut self, min_prec: u8) -> Result { - let mut lhs = if let Some(op) = self.peek()?.kind.unary_op() { - let tok = self.next()?; - let rhs = self.parse_precedence(op.precedence())?; - let span = tok.span + rhs.span; - E::UnaryOp(op, b(rhs)).span(span) - } else { - self.parse_access()? - }; - let mut span = lhs.span; + loop { + let tok = self.peek()?; + if let Some(op) = tok.kind.postfix_unary_op() { + if op.precedence() < min_prec { + break + } + self.next()?; + span += tok.span; + lhs = E::UnaryOp(op, b(lhs)).span(span); + continue + }; + let Some(op) = tok.kind.binary_op() else { + break + }; + let (lp, rp) = op.precedence(); + if lp < min_prec { + break + } - loop { - let tok = self.peek()?; - if let Some(op) = tok.kind.postfix_unary_op() { - if op.precedence() < min_prec { - break - } - self.next()?; - span += tok.span; - lhs = E::UnaryOp(op, b(lhs)).span(span); - continue - }; - let Some(op) = tok.kind.binary_op() else { - break - }; - let (lp, rp) = op.precedence(); - if lp < min_prec { - break - } + self.next()?; + let rhs = self.parse_precedence(rp)?; + span += rhs.span; - self.next()?; - let rhs = self.parse_precedence(rp)?; - span += rhs.span; + lhs = E::BinaryOp(op, Box::new(lhs), Box::new(rhs)).span(span); + } - lhs = E::BinaryOp(op, Box::new(lhs), Box::new(rhs)) - .span(span); - } + Ok(lhs) + } - Ok(lhs) - } + fn parse_lambda(&mut self) -> Result { + let tok = try_next!(self, T::Backslash | T::Colon); + match tok { + Some(Token { + kind: T::Backslash, + span, + .. + }) => { + let args = self.parse_ident_list()?; + expect!(self, T::Arrow); + 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, + span, + .. + }) => { + let args = vec![*SYM_DOLLAR_SIGN]; + let body = self.parse_lambda()?; + let body_span = body.span; + Ok(E::Lambda(args, b(body)).span(span + body_span)) + } + None => self.parse_precedence(0), + _ => unreachable!("parse_lambda: guaranteed by try_next!"), + } + } - fn parse_lambda(&mut self) -> Result { - let tok = try_next!(self, T::Backslash | T::Colon); - match tok { - Some(Token { kind: T::Backslash, span, .. }) => { - let args = self.parse_ident_list()?; - expect!(self, T::Arrow); - 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, span, .. }) => { - let args = vec![*SYM_DOLLAR_SIGN]; - let body = self.parse_lambda()?; - let body_span = body.span; - Ok(E::Lambda(args, b(body)).span(span + body_span)) - }, - None => self.parse_precedence(0), - _ => unreachable!("parse_lambda: guaranteed by try_next!"), - } - } + fn parse_pipeline(&mut self) -> Result { + let mut lhs = self.parse_lambda()?; + let mut span = lhs.span; + while try_next!(self, T::Pipe).is_some() { + let rhs = self.parse_lambda()?; + span += rhs.span; + lhs = E::Pipe(b(lhs), b(rhs)).span(span); + } + Ok(lhs) + } - fn parse_pipeline(&mut self) -> Result { - let mut lhs = self.parse_lambda()?; - let mut span = lhs.span; - while try_next!(self, T::Pipe).is_some() { - let rhs = self.parse_lambda()?; - span += rhs.span; - lhs = E::Pipe(b(lhs), b(rhs)).span(span); - } - Ok(lhs) - } + fn parse_not(&mut self) -> Result { + if let Some(tok) = try_next!(self, T::Not) { + let expr = self.parse_not()?; + let span = tok.span + expr.span; + Ok(E::UnaryOp(UnaryOp::Not, b(expr)).span(span)) + } else { + self.parse_pipeline() + } + } - fn parse_not(&mut self) -> Result { - if let Some(tok) = try_next!(self, T::Not) { - let expr = self.parse_not()?; - let span = tok.span + expr.span; - Ok(E::UnaryOp(UnaryOp::Not, b(expr)).span(span)) - } else { - self.parse_pipeline() - } - } + fn parse_and(&mut self) -> Result { + let mut lhs = self.parse_not()?; + let mut span = lhs.span; + while try_next!(self, T::And).is_some() { + let rhs = self.parse_not()?; + span += rhs.span; + lhs = E::And(b(lhs), b(rhs)).span(span); + } + Ok(lhs) + } - fn parse_and(&mut self) -> Result { - let mut lhs = self.parse_not()?; - let mut span = lhs.span; - while try_next!(self, T::And).is_some() { - let rhs = self.parse_not()?; - span += rhs.span; - lhs = E::And(b(lhs), b(rhs)).span(span); - } - Ok(lhs) - } + fn parse_or(&mut self) -> Result { + let mut lhs = self.parse_and()?; + let mut span = lhs.span; + while try_next!(self, T::Or).is_some() { + let rhs = self.parse_and()?; + span += rhs.span; + lhs = E::Or(b(lhs), b(rhs)).span(span); + } + Ok(lhs) + } - fn parse_or(&mut self) -> Result { - let mut lhs = self.parse_and()?; - let mut span = lhs.span; - while try_next!(self, T::Or).is_some() { - let rhs = self.parse_and()?; - span += rhs.span; - lhs = E::Or(b(lhs), b(rhs)).span(span); - } - Ok(lhs) - } + fn parse_assign(&mut self) -> Result { + let lhs = self.parse_or()?; + let lhs_span = lhs.span; + if let Some(op) = self.peek()?.kind.assign_op() { + let Some(lval) = LValue::from_expr(lhs) else { + throw!(lhs_span, "invalid lvalue for assingment") + }; + self.next()?; + let rhs = self.parse_decl()?; + let rhs_span = rhs.span; + Ok(E::Assign(op, b(lval), b(rhs)).span(lhs_span + rhs_span)) + } else { + Ok(lhs) + } + } - fn parse_assign(&mut self) -> Result { - let lhs = self.parse_or()?; - let lhs_span = lhs.span; - if let Some(op) = self.peek()?.kind.assign_op() { - let Some(lval) = LValue::from_expr(lhs) else { - throw!(lhs_span, "invalid lvalue for assingment") - }; - self.next()?; - let rhs = self.parse_decl()?; - let rhs_span = rhs.span; - Ok(E::Assign(op, b(lval), b(rhs)).span(lhs_span + rhs_span)) - } else { - Ok(lhs) - } - } + fn parse_var_decl(&mut self) -> Result { + let first = expect!(self, T::Var | T::Global); + let name = expect!(self, T::Identifier); + expect!(self, T::Equal); + let val = self.parse_decl()?; + let val_span = val.span; + let kind = if first.kind == T::Global { + E::AssignGlobal + } else { + E::AssignVar + }; + Ok(kind(Symbol::get(name.content), b(val)).span(first.span + val_span)) + } - fn parse_var_decl(&mut self) -> Result { - let first = expect!(self, T::Var | T::Global); - let name = expect!(self, T::Identifier); - expect!(self, T::Equal); - let val = self.parse_decl()?; - let val_span = val.span; - let kind = if first.kind == T::Global { E::AssignGlobal } else { E::AssignVar }; - Ok(kind(Symbol::get(name.content), b(val)) - .span(first.span + val_span)) - } + fn parse_fn_decl(&mut self) -> Result { + let tok_fn = expect!(self, T::Fn); + let name = try_next!(self, T::Identifier).map(|t| Symbol::get(t.content)); + expect!(self, T::LParen); + let args = self.parse_ident_list()?; + expect!(self, T::RParen); + match expect!(self, T::Do | T::Equal).kind { + T::Do => { + let content = self.parse_block()?; + let end = expect!(self, T::End); + Ok(E::FnDef(name, args, b(content)).span(tok_fn.span + end.span)) + } + T::Equal => { + let content = self.parse_expr()?; + let span = tok_fn.span + content.span; + Ok(E::FnDef(name, args, b(content)).span(span)) + } + _ => unreachable!("parse_fn_decl: guaranteed by try_next!"), + } + } - fn parse_fn_decl(&mut self) -> Result { - let tok_fn = expect!(self, T::Fn); - let name = try_next!(self, T::Identifier).map(|t| Symbol::get(t.content)); - expect!(self, T::LParen); - let args = self.parse_ident_list()?; - expect!(self, T::RParen); - match expect!(self, T::Do | T::Equal).kind { - T::Do => { - let content = self.parse_block()?; - let end = expect!(self, T::End); - Ok(E::FnDef(name, args, b(content)).span(tok_fn.span + end.span)) - }, - T::Equal => { - let content = self.parse_expr()?; - let span = tok_fn.span + content.span; - Ok(E::FnDef(name, args, b(content)).span(span)) - }, - _ => unreachable!("parse_fn_decl: guaranteed by try_next!"), - } + fn parse_decl(&mut self) -> Result { + match self.peek()?.kind { + T::Var | T::Global => self.parse_var_decl(), + T::Fn => self.parse_fn_decl(), + _ => self.parse_assign(), + } + } - - } + fn parse_expr(&mut self) -> Result { + if let Some(tok) = try_next!(self, T::Return) { + let expr = self.parse_decl()?; + let span = expr.span; + Ok(E::Return(b(expr)).span(tok.span + span)) + } else { + self.parse_decl() + } + } - fn parse_decl(&mut self) -> Result { - match self.peek()?.kind { - T::Var | T::Global => self.parse_var_decl(), - T::Fn => self.parse_fn_decl(), - _ => self.parse_assign(), - } - } + fn parse_block(&mut self) -> Result { + while try_next!(self, T::LineSeparator).is_some() {} - fn parse_expr(&mut self) -> Result { - if let Some(tok) = try_next!(self, T::Return) { - let expr = self.parse_decl()?; - let span = expr.span; - Ok(E::Return(b(expr)).span(tok.span + span)) - } else { - self.parse_decl() - } - } + let mut span = self.peek()?.span; + let mut exprs = Vec::new(); + while self.peek()?.kind.expr_first() { + let expr = self.parse_expr()?; + span += expr.span; + exprs.push(expr); - fn parse_block(&mut self) -> Result { - while try_next!(self, T::LineSeparator).is_some() {} + if try_next!(self, T::LineSeparator).is_none() { + break + } + while try_next!(self, T::LineSeparator).is_some() {} + } + Ok(E::Block(exprs).span(span)) + } - let mut span = self.peek()?.span; - let mut exprs = Vec::new(); - while self.peek()?.kind.expr_first() { - let expr = self.parse_expr()?; - span += expr.span; - exprs.push(expr); - - if try_next!(self, T::LineSeparator).is_none() { - break - } - while try_next!(self, T::LineSeparator).is_some() {} - } - Ok(E::Block(exprs).span(span)) - } - - fn parse(mut self) -> Result { - let block = self.parse_block()?; - expect!(self, T::Eof); - Ok(block) - } + fn parse(mut self) -> Result { + let block = self.parse_block()?; + expect!(self, T::Eof); + Ok(block) + } } pub fn parse(src: &str) -> Result { - Parser::new(src).parse() + Parser::new(src).parse() } diff --git a/talc-lang/src/parser/pos.rs b/talc-lang/src/parser/pos.rs index d8b637f..512f781 100644 --- a/talc-lang/src/parser/pos.rs +++ b/talc-lang/src/parser/pos.rs @@ -2,99 +2,108 @@ use std::fmt; #[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] pub struct Pos { - pub idx: u32, - pub line: u32, - pub col: u32, + pub idx: u32, + pub line: u32, + pub col: u32, } impl std::cmp::PartialOrd for Pos { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } } impl std::cmp::Ord for Pos { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.idx.cmp(&other.idx) - } + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.idx.cmp(&other.idx) + } } impl Pos { - pub const fn new() -> Pos { - Pos { idx: 0, line: 1, col: 1 } - } + pub const fn new() -> Pos { + Pos { + idx: 0, + line: 1, + col: 1, + } + } - #[must_use] - pub fn advance(self, c: char) -> Pos { - let idx = self.idx.checked_add(c.len_utf8() as u32) - .expect("source file contains more than u32::MAX chars"); - if c == '\n' { - Pos { - idx, - line: self.line + 1, - col: 1, - } - } else { - Pos { - idx, - line: self.line, - col: self.col + 1, - } - } - } + #[must_use] + pub fn advance(self, c: char) -> Pos { + let idx = self + .idx + .checked_add(c.len_utf8() as u32) + .expect("source file contains more than u32::MAX chars"); + if c == '\n' { + Pos { + idx, + line: self.line + 1, + col: 1, + } + } else { + Pos { + idx, + line: self.line, + col: self.col + 1, + } + } + } } impl fmt::Display for Pos { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}:{}", self.line, self.col) - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}:{}", self.line, self.col) + } } #[derive(Clone, Copy, Debug)] pub struct Span { - pub start: Pos, - pub end: Pos, + pub start: Pos, + pub end: Pos, } impl Span { - pub const fn new(start: Pos, end: Pos) -> Self { - if end.idx < start.idx { - Self { start: end, end: start } - } else { - Self { start, end } - } - } + pub const fn new(start: Pos, end: Pos) -> Self { + if end.idx < start.idx { + Self { + start: end, + end: start, + } + } else { + Self { start, end } + } + } - pub fn of<'a>(&self, s: &'a str) -> &'a str { - &s[(self.start.idx as usize)..(self.end.idx as usize)] - } + pub fn of<'a>(&self, s: &'a str) -> &'a str { + &s[(self.start.idx as usize)..(self.end.idx as usize)] + } } impl std::ops::Add for Span { - type Output = Span; + type Output = Span; - fn add(self, rhs: Self) -> Self::Output { - let start = self.start.min(rhs.start); - let end = self.end.max(rhs.end); - Self::new(start, end) - } + fn add(self, rhs: Self) -> Self::Output { + let start = self.start.min(rhs.start); + let end = self.end.max(rhs.end); + Self::new(start, end) + } } impl std::ops::AddAssign for Span { - fn add_assign(&mut self, rhs: Self) { - self.start = self.start.min(rhs.start); - self.end = self.end.max(rhs.end); - } + fn add_assign(&mut self, rhs: Self) { + self.start = self.start.min(rhs.start); + self.end = self.end.max(rhs.end); + } } impl From<(Pos, Pos)> for Span { - fn from((start, end): (Pos, Pos)) -> Self { - Self { start, end } - } + fn from((start, end): (Pos, Pos)) -> Self { + Self { start, end } + } } impl fmt::Display for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}-{}", self.start, self.end) - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}-{}", self.start, self.end) + } } diff --git a/talc-lang/src/parser/util.rs b/talc-lang/src/parser/util.rs index b0dd8c5..1f8cb31 100644 --- a/talc-lang/src/parser/util.rs +++ b/talc-lang/src/parser/util.rs @@ -1,5 +1,5 @@ use core::fmt; -use std::num::{ParseIntError, ParseFloatError}; +use std::num::{ParseFloatError, ParseIntError}; use thiserror::Error; @@ -9,26 +9,29 @@ use super::Span; #[derive(Clone, Debug, Error)] pub struct ParserError { - pub span: Span, - pub msg: String, + pub span: Span, + pub msg: String, } impl fmt::Display for ParserError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} | {}", self.span, self.msg) - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} | {}", self.span, self.msg) + } } pub trait SpanParserError { - type Output; - fn span_err(self, span: Span) -> Self::Output; + type Output; + fn span_err(self, span: Span) -> Self::Output; } impl SpanParserError for Result { - type Output = Result; - fn span_err(self, span: Span) -> Self::Output { - self.map_err(|e| ParserError { span, msg: e.to_string() }) - } + type Output = Result; + fn span_err(self, span: Span) -> Self::Output { + self.map_err(|e| ParserError { + span, + msg: e.to_string(), + }) + } } #[derive(Clone, Copy, Debug, Error)] @@ -56,26 +59,29 @@ pub fn parse_str_escapes(src: &str) -> Result { let mut chars = src.chars(); while let Some(c) = chars.next() { - if c != '\\' { s.push_char(c); continue } + if c != '\\' { + s.push_char(c); + continue + } let c = chars.next().ok_or(StrEscapeError::Eof)?; match c { '"' | '\'' | '\\' => s.push_char(c), - '0' => s.push_char('\0'), - 'a' => s.push_char('\x07'), - 'b' => s.push_char('\x08'), - 't' => s.push_char('\t'), - 'n' => s.push_char('\n'), - 'v' => s.push_char('\x0b'), - 'f' => s.push_char('\x0c'), - 'r' => s.push_char('\r'), - 'e' => s.push_char('\x1b'), + '0' => s.push_char('\0'), + 'a' => s.push_char('\x07'), + 'b' => s.push_char('\x08'), + 't' => s.push_char('\t'), + 'n' => s.push_char('\n'), + 'v' => s.push_char('\x0b'), + 'f' => s.push_char('\x0c'), + 'r' => s.push_char('\r'), + 'e' => s.push_char('\x1b'), 'x' => { let c = chars.next().ok_or(StrEscapeError::HexEof)?; 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); - }, + } 'u' => { let Some('{') = chars.next() else { return Err(StrEscapeError::MissingBrace) @@ -85,7 +91,9 @@ pub fn parse_str_escapes(src: &str) -> Result { let Some(c) = chars.next() else { return Err(StrEscapeError::UnicodeEof) }; - if c == '}' { break } + if c == '}' { + break + } if n > 0x10ffff { return Err(StrEscapeError::CodepointTooLarge) } @@ -93,8 +101,7 @@ pub fn parse_str_escapes(src: &str) -> Result { } let ch = char::from_u32(n).ok_or(StrEscapeError::InvalidCodepoint(n))?; s.push_char(ch); - - }, + } c => return Err(StrEscapeError::Invalid(c)), } } @@ -123,14 +130,14 @@ pub fn parse_int<'a, S: Into<&'a LStr>>(f: S, radix: u32) -> Result>(f: S) -> Result { - let f = f.into(); - match f.chars().nth(2) { - Some('x') => parse_int(&f[2..], 16), - Some('o') => parse_int(&f[2..], 8), - Some('s') => parse_int(&f[2..], 6), - Some('b') => parse_int(&f[2..], 2), - _ => parse_int(f, 10), - } + let f = f.into(); + match f.chars().nth(2) { + Some('x') => parse_int(&f[2..], 16), + Some('o') => parse_int(&f[2..], 8), + Some('s') => parse_int(&f[2..], 6), + Some('b') => parse_int(&f[2..], 2), + _ => parse_int(f, 10), + } } pub fn to_lstring_radix(n: i64, radix: u32, upper: bool) -> LString { @@ -151,14 +158,14 @@ pub fn to_lstring_radix(n: i64, radix: u32, upper: bool) -> LString { x /= radix as u64; let mut c = char::from_digit(m as u32, radix).unwrap(); - if upper { c.make_ascii_uppercase(); } + if upper { + c.make_ascii_uppercase(); + } result.push(c as u8); if x == 0 { - break; + break } } result[begin..].reverse(); LString::from(result) } - - diff --git a/talc-lang/src/symbol.rs b/talc-lang/src/symbol.rs index 4dca299..1f00035 100644 --- a/talc-lang/src/symbol.rs +++ b/talc-lang/src/symbol.rs @@ -1,17 +1,19 @@ -use std::{collections::HashMap, sync::{Mutex, OnceLock}}; +use std::{ + collections::HashMap, + sync::{Mutex, OnceLock}, +}; use lazy_static::lazy_static; #[derive(Default)] struct SymbolTable { names: Vec<&'static LStr>, - values: HashMap<&'static LStr, Symbol> + values: HashMap<&'static LStr, Symbol>, } lazy_static! { pub static ref SYM_SELF: Symbol = symbol!(self); pub static ref SYM_DOLLAR_SIGN: Symbol = symbol!("$"); - pub static ref SYM_NIL: Symbol = symbol!(nil); pub static ref SYM_BOOL: Symbol = symbol!(bool); pub static ref SYM_SYMBOL: Symbol = symbol!(symbol); @@ -26,13 +28,10 @@ lazy_static! { pub static ref SYM_TABLE: Symbol = symbol!(table); pub static ref SYM_FUNCTION: Symbol = symbol!(function); pub static ref SYM_NATIVE_FUNC: Symbol = symbol!(native_func); - pub static ref SYM_END_ITERATION: Symbol = symbol!(end_iteration); - pub static ref SYM_TYPE: Symbol = symbol!(type); pub static ref SYM_MSG: Symbol = symbol!(msg); pub static ref SYM_DATA: Symbol = symbol!(data); - pub static ref SYM_TYPE_ERROR: Symbol = symbol!(type_error); pub static ref SYM_VALUE_ERROR: Symbol = symbol!(value_error); pub static ref SYM_NAME_ERROR: Symbol = symbol!(name_error); @@ -110,7 +109,11 @@ impl Symbol { /// If the mutex storing the symbol table is poisoned pub fn name(self) -> &'static LStr { let table = get_table().lock().expect("couldn't lock symbol table"); - table.names.get(self.0 as usize).copied().expect("symbol does not exist") + table + .names + .get(self.0 as usize) + .copied() + .expect("symbol does not exist") } } @@ -127,4 +130,3 @@ macro_rules! symbol { pub use symbol; use crate::lstring::{LStr, LString}; - diff --git a/talc-lang/src/value/function.rs b/talc-lang/src/value/function.rs index 7ba0ae4..aa5fd54 100644 --- a/talc-lang/src/value/function.rs +++ b/talc-lang/src/value/function.rs @@ -1,31 +1,35 @@ use std::{cell::RefCell, rc::Rc}; -use crate::{chunk::Chunk, Vm, exception::Result, symbol::Symbol}; +use crate::{chunk::Chunk, exception::Result, symbol::Symbol, Vm}; -use super::{Value, CellValue}; +use super::{CellValue, Value}; #[derive(Clone, Copy, Debug, Default)] pub struct FuncAttrs { pub arity: usize, - pub name: Option, + pub name: Option, } #[derive(Debug, Clone)] pub struct Function { pub attrs: FuncAttrs, pub chunk: Rc, - pub state: Box<[CellValue]>, + pub state: Box<[CellValue]>, } impl Function { pub fn new(chunk: Rc, attrs: FuncAttrs, closes: usize) -> Self { - let v = Rc::new(RefCell::new(Value::Nil)); - let state = std::iter::repeat(v).take(closes).collect(); - Self::from_parts(chunk, attrs, state) + let v = Rc::new(RefCell::new(Value::Nil)); + let state = std::iter::repeat(v).take(closes).collect(); + Self::from_parts(chunk, attrs, state) } pub fn from_parts(chunk: Rc, attrs: FuncAttrs, state: Box<[CellValue]>) -> Self { - Self { chunk, attrs, state } + Self { + chunk, + attrs, + state, + } } } @@ -38,11 +42,20 @@ pub struct NativeFunc { impl NativeFunc { pub fn new(func: FnNative, arity: usize, name: Symbol) -> Self { - Self { func, attrs: FuncAttrs { arity, name: Some(name) } } + Self { + func, + attrs: FuncAttrs { + arity, + name: Some(name), + }, + } } pub fn new_anon(func: FnNative, arity: usize) -> Self { - Self { func, attrs: FuncAttrs { arity, name: None } } + Self { + func, + attrs: FuncAttrs { arity, name: None }, + } } } @@ -55,9 +68,7 @@ impl std::fmt::Debug for NativeFunc { } pub fn disasm_recursive(f: &Rc, w: &mut impl std::io::Write) -> std::io::Result<()> { - writeln!(w, "{} ({})", - Value::Function(f.clone()), - f.attrs.arity)?; + writeln!(w, "{} ({})", Value::Function(f.clone()), f.attrs.arity)?; if !f.chunk.consts.is_empty() { writeln!(w, "constants")?; for (i, c) in f.chunk.consts.iter().enumerate() { @@ -78,7 +89,9 @@ pub fn disasm_recursive(f: &Rc, w: &mut impl std::io::Write) -> std::i if let Some(types) = &catch.types { write!(w, "{:04} [", catch.addr)?; for (i, ty) in types.iter().enumerate() { - if i != 0 { write!(w, ", ")?; } + if i != 0 { + write!(w, ", ")?; + } write!(w, "{}", ty.name())?; } writeln!(w, "]")?; @@ -101,4 +114,3 @@ pub fn disasm_recursive(f: &Rc, w: &mut impl std::io::Write) -> std::i } Ok(()) } - diff --git a/talc-lang/src/value/index.rs b/talc-lang/src/value/index.rs index 6204806..b0720da 100644 --- a/talc-lang/src/value/index.rs +++ b/talc-lang/src/value/index.rs @@ -1,6 +1,11 @@ -use crate::{exception::{throw, Result}, symbol::{symbol, SYM_END_ITERATION, SYM_INDEX_ERROR, SYM_TYPE_ERROR}, value::function::NativeFunc, vmcalliter, Vm}; +use crate::{ + exception::{throw, Result}, + symbol::{symbol, SYM_END_ITERATION, SYM_INDEX_ERROR, SYM_TYPE_ERROR}, + value::function::NativeFunc, + vmcalliter, Vm, +}; -use super::{Value, range::RangeType}; +use super::{range::RangeType, Value}; impl Value { pub fn index(&self, idx: Self) -> Result { @@ -11,70 +16,93 @@ impl Value { if i >= 0 && (i as usize) < l.len() { Ok(l[i as usize].clone()) } else { - throw!(*SYM_INDEX_ERROR, "index {i} out of bounds for list of length {}", l.len()) + throw!( + *SYM_INDEX_ERROR, + "index {i} out of bounds for list of length {}", + l.len() + ) } - }, + } (V::Range(r), V::Int(i)) => { - if i >= 0 && ( - r.ty == RangeType::Endless - || i < r.stop - || (r.ty == RangeType::Closed && i == r.stop) - ) { + if i >= 0 + && (r.ty == RangeType::Endless + || i < r.stop || (r.ty == RangeType::Closed && i == r.stop)) + { Ok((r.start + i).into()) } else { throw!(*SYM_INDEX_ERROR, "index {i} out of bounds for range {self}") } - }, + } (V::Table(t), i) if i.hashable() => { let t = t.borrow(); let i = i.try_into()?; Ok(t.get(&i).cloned().unwrap_or(Value::Nil)) - }, + } (V::String(s), V::Range(r)) => { let slen = s.len(); match r.ty { RangeType::Open => { if r.start < 0 || r.start > slen as i64 { - throw!(*SYM_INDEX_ERROR, - "index {} out of bounds for string of length {}", r.stop, slen) + throw!( + *SYM_INDEX_ERROR, + "index {} out of bounds for string of length {}", + r.stop, + slen + ) } if r.stop < 0 || r.stop > slen as i64 { - throw!(*SYM_INDEX_ERROR, - "index {} out of bounds for string of length {}", r.stop, slen) + throw!( + *SYM_INDEX_ERROR, + "index {} out of bounds for string of length {}", + r.stop, + slen + ) } Ok(s[r.start as usize..r.stop as usize].into()) - }, + } RangeType::Closed => { if r.start < 0 || r.start > slen as i64 { - throw!(*SYM_INDEX_ERROR, - "index {} out of bounds for string of length {}", r.stop, slen) + throw!( + *SYM_INDEX_ERROR, + "index {} out of bounds for string of length {}", + r.stop, + slen + ) } if r.stop < 0 || r.stop >= slen as i64 { - throw!(*SYM_INDEX_ERROR, - "index {} out of bounds for string of length {}", r.stop, slen) + throw!( + *SYM_INDEX_ERROR, + "index {} out of bounds for string of length {}", + r.stop, + slen + ) } Ok(s[r.start as usize..=r.stop as usize].into()) - }, + } RangeType::Endless => { if r.start < 0 || r.start > slen as i64 { - throw!(*SYM_INDEX_ERROR, - "index {} out of bounds for string of length {}", r.stop, slen) + throw!( + *SYM_INDEX_ERROR, + "index {} out of bounds for string of length {}", + r.stop, + slen + ) } Ok(s[r.start as usize..].into()) - }, + } } - }, - (col, idx) => if let Ok(ii) = idx.clone().to_iter_function() { - let col = col.clone(); - let func = move |vm: &mut Vm, _| { - match vmcalliter!(vm; ii.clone())? { + } + (col, idx) => { + if let Ok(ii) = idx.clone().to_iter_function() { + let col = col.clone(); + let func = move |vm: &mut Vm, _| match vmcalliter!(vm; ii.clone())? { Some(i) => col.index(i), None => Ok(Value::from(*SYM_END_ITERATION)), - } - }; - Ok(NativeFunc::new(Box::new(func), 0, symbol!("index...")).into()) - } else { - throw!(*SYM_TYPE_ERROR, "cannot index {col:#} with {idx:#}") + }; + Ok(NativeFunc::new(Box::new(func), 0, symbol!("index...")).into()) + } else { + throw!(*SYM_TYPE_ERROR, "cannot index {col:#} with {idx:#}") + } } } } @@ -88,15 +116,19 @@ impl Value { l[i as usize] = val; Ok(()) } else { - throw!(*SYM_INDEX_ERROR, "index {i} out of bounds for list of length {}", l.len()) + throw!( + *SYM_INDEX_ERROR, + "index {i} out of bounds for list of length {}", + l.len() + ) } - }, + } (V::Table(t), i) if i.hashable() => { let mut t = t.borrow_mut(); let i = i.try_into()?; t.insert(i, val); Ok(()) - }, + } (V::List(t), V::Range(r)) => { let iter = val.to_iter_function()?; let mut vals = Vec::new(); @@ -107,53 +139,78 @@ impl Value { match r.ty { RangeType::Open => { if r.start < 0 || r.start > tm.len() as i64 { - throw!(*SYM_INDEX_ERROR, - "index {} out of bounds for list of length {}", r.stop, tm.len()) + throw!( + *SYM_INDEX_ERROR, + "index {} out of bounds for list of length {}", + r.stop, + tm.len() + ) } if r.stop < 0 || r.stop > tm.len() as i64 { - throw!(*SYM_INDEX_ERROR, - "index {} out of bounds for list of length {}", r.stop, tm.len()) + throw!( + *SYM_INDEX_ERROR, + "index {} out of bounds for list of length {}", + r.stop, + tm.len() + ) } let end = tm.split_off(r.stop as usize); tm.truncate(r.start as usize); tm.extend(vals.into_iter().chain(end)); - }, + } RangeType::Closed => { if r.start < 0 || r.start > tm.len() as i64 { - throw!(*SYM_INDEX_ERROR, - "index {} out of bounds for list of length {}", r.stop, tm.len()) + throw!( + *SYM_INDEX_ERROR, + "index {} out of bounds for list of length {}", + r.stop, + tm.len() + ) } if r.stop < 0 || r.stop >= tm.len() as i64 { - throw!(*SYM_INDEX_ERROR, - "index {} out of bounds for list of length {}", r.stop, tm.len()) + throw!( + *SYM_INDEX_ERROR, + "index {} out of bounds for list of length {}", + r.stop, + tm.len() + ) } let end = tm.split_off(r.stop as usize + 1); tm.truncate(r.start as usize); tm.extend(vals.into_iter().chain(end)); - }, + } RangeType::Endless => { if r.start < 0 || r.start > tm.len() as i64 { - throw!(*SYM_INDEX_ERROR, - "index {} out of bounds for list of length {}", r.stop, tm.len()) + throw!( + *SYM_INDEX_ERROR, + "index {} out of bounds for list of length {}", + r.stop, + tm.len() + ) } tm.truncate(r.start as usize); tm.extend(vals); - }, + } } Ok(()) - }, - (col, idx) => if let Ok(ii) = idx.clone().to_iter_function() { - let val = val.to_iter_function()?; - while let Some(i) = vmcalliter!(vm; ii.clone())? { - let Some(v) = vmcalliter!(vm; val.clone())? else { - throw!(*SYM_INDEX_ERROR, "not enough values provided for store index") - }; - col.store_index(vm, i, v)?; + } + (col, idx) => { + if let Ok(ii) = idx.clone().to_iter_function() { + let val = val.to_iter_function()?; + while let Some(i) = vmcalliter!(vm; ii.clone())? { + let Some(v) = vmcalliter!(vm; val.clone())? else { + throw!( + *SYM_INDEX_ERROR, + "not enough values provided for store index" + ) + }; + col.store_index(vm, i, v)?; + } + Ok(()) + } else { + throw!(*SYM_TYPE_ERROR, "cannot index {self:#} with {idx:#}") } - Ok(()) - } else { - throw!(*SYM_TYPE_ERROR, "cannot index {self:#} with {idx:#}") - }, + } } } } diff --git a/talc-lang/src/value/mod.rs b/talc-lang/src/value/mod.rs index 895d855..3821184 100644 --- a/talc-lang/src/value/mod.rs +++ b/talc-lang/src/value/mod.rs @@ -7,16 +7,19 @@ pub use num_complex::Complex64; use num_complex::ComplexFloat; pub use num_rational::Rational64; +use crate::exception::{throw, Exception}; use crate::lstring::{LStr, LString}; use crate::symbol::{Symbol, SYM_HASH_ERROR}; -use crate::exception::{Exception, throw}; -use self::{range::{Range, RangeType}, function::{Function, NativeFunc}}; +use self::{ + function::{Function, NativeFunc}, + range::{Range, RangeType}, +}; pub mod function; +pub mod index; pub mod ops; pub mod range; -pub mod index; type RcList = Rc>>; type RcTable = Rc>>; @@ -49,7 +52,12 @@ pub trait NativeValue: std::fmt::Debug + Any { fn get_type(&self) -> Symbol; fn as_any(&self) -> &dyn Any; - fn to_lstring(&self, w: &mut LString, _repr: bool, _recur: &mut Vec<*const ()>) -> io::Result<()> { + fn to_lstring( + &self, + w: &mut LString, + _repr: bool, + _recur: &mut Vec<*const ()>, + ) -> io::Result<()> { w.extend(b""); Ok(()) } @@ -63,7 +71,11 @@ pub trait NativeValue: std::fmt::Debug + Any { impl Display for Value { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let s = if f.alternate() { Cow::Owned(self.repr()) } else { self.str() }; + let s = if f.alternate() { + Cow::Owned(self.repr()) + } else { + self.str() + }; write!(f, "{s}") } } @@ -81,7 +93,12 @@ impl Value { table.into() } - pub fn write_to_lstring(&self, w: &mut LString, repr: bool, recur: &mut Vec<*const ()>) -> io::Result<()> { + pub fn write_to_lstring( + &self, + w: &mut LString, + repr: bool, + recur: &mut Vec<*const ()>, + ) -> io::Result<()> { use std::io::Write; match self { Self::Nil => write!(w, "nil"), @@ -95,10 +112,10 @@ impl Value { write!(w, "{name:?}")?; } Ok(()) - }, + } Self::Range(r) => match r.ty { - RangeType::Open => write!(w, "{}..{}", r.start, r.stop), - RangeType::Closed => write!(w, "{}..={}", r.start, r.stop), + RangeType::Open => write!(w, "{}..{}", r.start, r.stop), + RangeType::Closed => write!(w, "{}..={}", r.start, r.stop), RangeType::Endless => write!(w, "{}..*", r.start), }, Self::Int(i) => write!(w, "{i}"), @@ -110,50 +127,50 @@ impl Value { w.push_byte(b'+'); } write!(w, "{:?}i", z.im()) - }, + } Self::Cell(v) if repr => { - if recur.contains(&(v.as_ptr() as _)) { - return w.write_all(b"cell(...)") - } + if recur.contains(&(v.as_ptr() as _)) { + return w.write_all(b"cell(...)") + } w.write_all(b"cell(")?; - recur.push(v.as_ptr() as _); + recur.push(v.as_ptr() as _); v.borrow().write_to_lstring(w, repr, recur)?; - recur.pop(); + recur.pop(); w.write_all(b")") - }, + } Self::Cell(v) => { - if recur.contains(&(v.as_ptr() as _)) { - return w.write_all(b"cell(...)") - } - recur.push(v.as_ptr() as _); - v.borrow().write_to_lstring(w, true, recur)?; - recur.pop(); - Ok(()) - }, + if recur.contains(&(v.as_ptr() as _)) { + return w.write_all(b"cell(...)") + } + recur.push(v.as_ptr() as _); + v.borrow().write_to_lstring(w, true, recur)?; + recur.pop(); + Ok(()) + } Self::String(s) if repr => write!(w, "{s:?}"), Self::String(s) => w.write_all(s.as_bytes()), Self::List(l) => { - if recur.contains(&(l.as_ptr() as _)) { - return w.write_all(b"[...]") - } + if recur.contains(&(l.as_ptr() as _)) { + return w.write_all(b"[...]") + } w.write_all(b"[")?; - recur.push(l.as_ptr() as _); + recur.push(l.as_ptr() as _); for (i, item) in l.borrow().iter().enumerate() { if i != 0 { w.write_all(b", ")?; } item.write_to_lstring(w, true, recur)?; } - recur.pop(); + recur.pop(); w.write_all(b"]") - }, + } Self::Table(t) => { - if recur.contains(&(t.as_ptr() as _)) { - return w.write_all(b"{...}") - } + if recur.contains(&(t.as_ptr() as _)) { + return 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() { if i != 0 { w.write_all(b", ")?; @@ -162,36 +179,58 @@ impl Value { w.write_all(b" = ")?; v.write_to_lstring(w, true, recur)?; } - recur.pop(); + recur.pop(); w.write_all(b" }") - }, + } Self::Function(g) => { - if let Some(name) = g.attrs.name { - write!(w, "12x}>", - name.name(), g.attrs.arity, Rc::as_ptr(g) as usize) - } else { - write!(w, "12x}>", - g.attrs.arity, Rc::as_ptr(g) as usize) - } - } + if let Some(name) = g.attrs.name { + write!( + w, + "12x}>", + name.name(), + g.attrs.arity, + Rc::as_ptr(g) as usize + ) + } else { + write!( + w, + "12x}>", + g.attrs.arity, + Rc::as_ptr(g) as usize + ) + } + } Self::NativeFunc(g) => { - if let Some(name) = g.attrs.name { - write!(w, "12x}>", - name.name(), g.attrs.arity, Rc::as_ptr(g) as usize) - } else { - write!(w, "12x}>", - g.attrs.arity, Rc::as_ptr(g) as usize) - } - } + if let Some(name) = g.attrs.name { + write!( + w, + "12x}>", + name.name(), + g.attrs.arity, + Rc::as_ptr(g) as usize + ) + } else { + write!( + w, + "12x}>", + g.attrs.arity, + Rc::as_ptr(g) as usize + ) + } + } Self::Native(n) => n.to_lstring(w, repr, recur), } } - fn write_table_key_repr(&self, w: &mut LString, recur: &mut Vec<*const ()>) -> std::io::Result<()> { + fn write_table_key_repr( + &self, + w: &mut LString, + recur: &mut Vec<*const ()>, + ) -> std::io::Result<()> { match self { - Self::Nil | Self::Bool(_) - | Self::Int(_) | Self::String(_) - => self.write_to_lstring(w, true, recur), + Self::Nil | Self::Bool(_) | Self::Int(_) | Self::String(_) => { + self.write_to_lstring(w, true, recur) + } Self::Symbol(s) => { let name = s.name(); if name.is_identifier() { @@ -200,7 +239,7 @@ impl Value { } else { self.write_to_lstring(w, true, recur) } - }, + } _ => { w.push_byte(b'('); self.write_to_lstring(w, true, recur)?; @@ -215,16 +254,18 @@ impl Value { Cow::Borrowed(s) } else { let mut s = LString::new(); - let mut recur = Vec::new(); - self.write_to_lstring(&mut s, false, &mut recur).expect("write_to_lstring failed"); + let mut recur = Vec::new(); + self.write_to_lstring(&mut s, false, &mut recur) + .expect("write_to_lstring failed"); Cow::Owned(s) } } pub fn repr(&self) -> LString { let mut s = LString::new(); - let mut recur = Vec::new(); - self.write_to_lstring(&mut s, true, &mut recur).expect("write_to_lstring failed"); + let mut recur = Vec::new(); + self.write_to_lstring(&mut s, true, &mut recur) + .expect("write_to_lstring failed"); s } @@ -252,15 +293,19 @@ impl Value { pub fn hashable(&self) -> bool { matches!( self, - Value::Nil | Value::Bool(_) | Value::Symbol(_) - | Value::Int(_) | Value::Ratio(_) | Value::String(_) + Value::Nil + | Value::Bool(_) + | Value::Symbol(_) + | Value::Int(_) + | Value::Ratio(_) + | Value::String(_) ) } pub fn downcast_native(&self) -> Option<&T> { match self { Value::Native(n) => n.as_any().downcast_ref(), - _ => None + _ => None, } } } @@ -281,8 +326,12 @@ impl TryFrom for HashValue { } impl HashValue { - pub fn into_inner(self) -> Value { self.0 } - pub fn inner(&self) -> &Value { &self.0 } + pub fn into_inner(self) -> Value { + self.0 + } + pub fn inner(&self) -> &Value { + &self.0 + } } impl Hash for HashValue { @@ -303,39 +352,57 @@ impl Hash for HashValue { macro_rules! impl_from { ($ty:ty, $var:ident) => { impl From<$ty> for Value { - fn from(value: $ty) -> Self { Self::$var(value) } + fn from(value: $ty) -> Self { + Self::$var(value) + } } }; ($ty:ty, $var:ident, hash) => { impl From<$ty> for Value { - fn from(value: $ty) -> Self { Self::$var(value) } + fn from(value: $ty) -> Self { + Self::$var(value) + } } impl From<$ty> for HashValue { - fn from(value: $ty) -> Self { Self(Value::$var(value)) } + fn from(value: $ty) -> Self { + Self(Value::$var(value)) + } } }; ($ty:ty, $var:ident, rc) => { impl From<$ty> for Value { - fn from(value: $ty) -> Self { Self::$var(Rc::new(value)) } + fn from(value: $ty) -> Self { + Self::$var(Rc::new(value)) + } } impl From> for Value { - fn from(value: Rc<$ty>) -> Self { Self::$var(value) } + fn from(value: Rc<$ty>) -> Self { + Self::$var(value) + } } }; ($ty:ty, $var:ident, rcref) => { impl From<$ty> for Value { - fn from(value: $ty) -> Self { Self::$var(Rc::new(RefCell::new(value))) } + fn from(value: $ty) -> Self { + Self::$var(Rc::new(RefCell::new(value))) + } } impl From> for Value { - fn from(value: RefCell<$ty>) -> Self { Self::$var(Rc::new(value)) } + fn from(value: RefCell<$ty>) -> Self { + Self::$var(Rc::new(value)) + } } impl From>> for Value { - fn from(value: Rc>) -> Self { Self::$var(value) } + fn from(value: Rc>) -> Self { + Self::$var(value) + } } }; ($ty:ty, $var:ident, into) => { impl From<$ty> for Value { - fn from(value: $ty) -> Self { Self::$var(value.into()) } + fn from(value: $ty) -> Self { + Self::$var(value.into()) + } } }; } diff --git a/talc-lang/src/value/ops.rs b/talc-lang/src/value/ops.rs index 1af9597..05265b4 100644 --- a/talc-lang/src/value/ops.rs +++ b/talc-lang/src/value/ops.rs @@ -1,13 +1,27 @@ - -use std::{cell::RefCell, cmp::Ordering, ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Shl, Shr, Sub}, rc::Rc}; +use std::{ + cell::RefCell, + cmp::Ordering, + ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Shl, Shr, Sub}, + rc::Rc, +}; use num_complex::{Complex64, ComplexFloat}; use num_rational::Rational64; use num_traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Signed, Zero}; -use crate::{exception::{throw, Result}, lstring::LString, symbol::{symbol, SYM_END_ITERATION, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, value::range::RangeType, Vm}; +use crate::{ + exception::{throw, Result}, + lstring::LString, + symbol::{symbol, SYM_END_ITERATION, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, + value::range::RangeType, + Vm, +}; -use super::{function::{FuncAttrs, NativeFunc}, range::Range, HashValue, Value}; +use super::{ + function::{FuncAttrs, NativeFunc}, + range::Range, + HashValue, Value, +}; pub trait RatioExt { fn to_f64(&self) -> f64; @@ -33,9 +47,11 @@ impl Value { Value::List(l) => l.borrow().len() > 0, Value::Cell(v) => v.borrow().truthy(), - Value::Symbol(_) | Value::Table(_) - | Value::Function(_) | Value::NativeFunc(_) - | Value::Native(_) => true, + Value::Symbol(_) + | Value::Table(_) + | Value::Function(_) + | Value::NativeFunc(_) + | Value::Native(_) => true, } } } @@ -43,46 +59,48 @@ impl Value { pub fn promote(a: Value, b: Value) -> (Value, Value) { use Value as V; match (&a, &b) { - (V::Int(x), V::Ratio(..)) => (V::Ratio((*x).into()), b), - (V::Int(x), V::Float(..)) => (V::Float(*x as f64), b), - (V::Int(x), V::Complex(..)) => (V::Complex((*x as f64).into()), b), - (V::Ratio(x), V::Float(..)) => (V::Float(x.to_f64()), b), - (V::Ratio(x), V::Complex(..)) => (V::Complex(x.to_f64().into()), b), - (V::Float(x), V::Complex(..)) => (V::Complex(x.into()), b), - (V::Ratio(..), V::Int(y)) => (a, V::Ratio((*y).into())), - (V::Float(..), V::Int(y)) => (a, V::Float(*y as f64)), - (V::Complex(..), V::Int(y)) => (a, V::Complex((*y as f64).into())), - (V::Float(..), V::Ratio(y)) => (a, V::Float(y.to_f64())), - (V::Complex(..), V::Ratio(y)) => (a, V::Complex(y.to_f64().into())), - (V::Complex(..), V::Float(y)) => (a, V::Complex((*y).into())), + (V::Int(x), V::Ratio(..)) => (V::Ratio((*x).into()), b), + (V::Int(x), V::Float(..)) => (V::Float(*x as f64), b), + (V::Int(x), V::Complex(..)) => (V::Complex((*x as f64).into()), b), + (V::Ratio(x), V::Float(..)) => (V::Float(x.to_f64()), b), + (V::Ratio(x), V::Complex(..)) => (V::Complex(x.to_f64().into()), b), + (V::Float(x), V::Complex(..)) => (V::Complex(x.into()), b), + (V::Ratio(..), V::Int(y)) => (a, V::Ratio((*y).into())), + (V::Float(..), V::Int(y)) => (a, V::Float(*y as f64)), + (V::Complex(..), V::Int(y)) => (a, V::Complex((*y as f64).into())), + (V::Float(..), V::Ratio(y)) => (a, V::Float(y.to_f64())), + (V::Complex(..), V::Ratio(y)) => (a, V::Complex(y.to_f64().into())), + (V::Complex(..), V::Float(y)) => (a, V::Complex((*y).into())), _ => (a, b), } } - //////////////////////// // unary arithmetic // //////////////////////// - impl Neg for Value { type Output = Result; fn neg(self) -> Self::Output { use Value as V; match self { - V::Int(x) => if let Some(x) = x.checked_neg() { - Ok(V::Int(x)) - } else { - throw!(*SYM_VALUE_ERROR, "overflow when negating {self}") - }, - V::Ratio(x) => if let Some(x) = Rational64::ZERO.checked_sub(&x) { - Ok(V::Ratio(x)) - } else { - throw!(*SYM_VALUE_ERROR, "overflow when negating {self}") - } + V::Int(x) => { + if let Some(x) = x.checked_neg() { + Ok(V::Int(x)) + } else { + throw!(*SYM_VALUE_ERROR, "overflow when negating {self}") + } + } + V::Ratio(x) => { + if let Some(x) = Rational64::ZERO.checked_sub(&x) { + Ok(V::Ratio(x)) + } else { + throw!(*SYM_VALUE_ERROR, "overflow when negating {self}") + } + } V::Float(x) => Ok(V::Float(-x)), V::Complex(x) => Ok(V::Complex(-x)), - a => throw!(*SYM_TYPE_ERROR, "cannot negate {a:#}") + a => throw!(*SYM_TYPE_ERROR, "cannot negate {a:#}"), } } } @@ -91,32 +109,40 @@ impl Value { pub fn abs(self) -> Result { use Value as V; match self { - V::Int(x) => if let Some(x) = x.checked_abs() { - Ok(V::Int(x)) - } else { - throw!(*SYM_VALUE_ERROR, "overflow when finding absolute value of {self}") - }, - V::Ratio(x) => if let Some((x, _)) = ratio_checked_absign(&x) { - Ok(V::Ratio(x)) - } else { - throw!(*SYM_VALUE_ERROR, "overflow when finding absolute value of {self}") - } + V::Int(x) => { + if let Some(x) = x.checked_abs() { + Ok(V::Int(x)) + } else { + throw!( + *SYM_VALUE_ERROR, + "overflow when finding absolute value of {self}" + ) + } + } + V::Ratio(x) => { + if let Some((x, _)) = ratio_checked_absign(&x) { + Ok(V::Ratio(x)) + } else { + throw!( + *SYM_VALUE_ERROR, + "overflow when finding absolute value of {self}" + ) + } + } V::Float(x) => Ok(V::Float(x.abs())), V::Complex(x) => Ok(V::Float(x.norm())), - a => throw!(*SYM_TYPE_ERROR, "cannot negate {a:#}") + a => throw!(*SYM_TYPE_ERROR, "cannot negate {a:#}"), } } } - ///////////////////////// // binary arithmetic // ///////////////////////// - macro_rules! impl_value_arith { ($trait:ident, $name:ident, $checked:ident, $op:tt, $verb:literal) => { - + impl $trait for Value { type Output = Result; fn $name(self, rhs: Value) -> Self::Output { @@ -151,20 +177,23 @@ impl Div for Value { type Output = Result; fn div(self, rhs: Value) -> Self::Output { use Value as V; - let (a, b) = promote(self, rhs); + let (a, b) = promote(self, rhs); match (&a, &b) { (V::Int(_), V::Int(0)) => throw!(*SYM_VALUE_ERROR, "integer division by 0"), - (V::Int(x), V::Int(y)) => Ok(Value::Ratio((*x,*y).into())), - (V::Ratio(_), V::Ratio(r)) if r.is_zero() - => throw!(*SYM_VALUE_ERROR, "rational division by 0"), - (V::Ratio(x), V::Ratio(y)) => if let Some(v) = x.checked_div(y) { - Ok(V::Ratio(v)) - } else { - throw!(*SYM_VALUE_ERROR, "overflow when dividing {a} and {b}") - }, + (V::Int(x), V::Int(y)) => Ok(Value::Ratio((*x, *y).into())), + (V::Ratio(_), V::Ratio(r)) if r.is_zero() => { + throw!(*SYM_VALUE_ERROR, "rational division by 0") + } + (V::Ratio(x), V::Ratio(y)) => { + if let Some(v) = x.checked_div(y) { + Ok(V::Ratio(v)) + } else { + throw!(*SYM_VALUE_ERROR, "overflow when dividing {a} and {b}") + } + } (V::Float(x), V::Float(y)) => Ok(V::Float(x / y)), (V::Complex(x), V::Complex(y)) => Ok(V::Complex(x / y)), - (l, r) => throw!(*SYM_TYPE_ERROR, "cannot divide {l:#} and {r:#}") + (l, r) => throw!(*SYM_TYPE_ERROR, "cannot divide {l:#} and {r:#}"), } } } @@ -173,104 +202,115 @@ impl Div for Value { // modulo and integer division // /////////////////////////////////// - #[inline] fn ratio_checked_absign(r: &Rational64) -> Option<(Rational64, Rational64)> { - let a = if r.is_negative() { - Rational64::ZERO.checked_sub(r)? - } else { - *r - }; - Some((a, r.signum())) + let a = if r.is_negative() { + Rational64::ZERO.checked_sub(r)? + } else { + *r + }; + Some((a, r.signum())) } #[inline] fn ratio_checked_div_euclid(r1: &Rational64, r2: &Rational64) -> Option { - let (r2_abs, r2_sgn) = ratio_checked_absign(r2)?; - Some(r1.checked_div(&r2_abs)?.floor() * r2_sgn) + let (r2_abs, r2_sgn) = ratio_checked_absign(r2)?; + Some(r1.checked_div(&r2_abs)?.floor() * r2_sgn) } #[inline] fn ratio_checked_rem_euclid(r1: &Rational64, r2: &Rational64) -> Option { - let q = ratio_checked_div_euclid(r1, r2)?; - r1.checked_sub(&r2.checked_mul(&q)?) - + let q = ratio_checked_div_euclid(r1, r2)?; + r1.checked_sub(&r2.checked_mul(&q)?) } - impl Value { pub fn modulo(self, rhs: Value) -> Result { use Value as V; - let (a, b) = promote(self, rhs); + let (a, b) = promote(self, rhs); match (&a, &b) { (V::Int(_), V::Int(0)) => throw!(*SYM_VALUE_ERROR, "integer modulo by 0"), - (V::Int(x), V::Int(y)) => if let Some(v) = x.checked_rem_euclid(*y) { - Ok(V::Int(v)) - } else { - throw!(*SYM_VALUE_ERROR, "overflow when calculating {a} modulo {b}") - }, + (V::Int(x), V::Int(y)) => { + if let Some(v) = x.checked_rem_euclid(*y) { + Ok(V::Int(v)) + } else { + throw!(*SYM_VALUE_ERROR, "overflow when calculating {a} modulo {b}") + } + } - (V::Ratio(_), V::Ratio(y)) if y.is_zero() - => throw!(*SYM_VALUE_ERROR, "rational modulo by 0"), - (V::Ratio(x), V::Ratio(y)) => if let Some(v) = ratio_checked_rem_euclid(x, y) { - Ok(V::Ratio(v)) - } else { - throw!(*SYM_VALUE_ERROR, "overflow when calculating {a} modulo {b}") - } + (V::Ratio(_), V::Ratio(y)) if y.is_zero() => { + throw!(*SYM_VALUE_ERROR, "rational modulo by 0") + } + (V::Ratio(x), V::Ratio(y)) => { + if let Some(v) = ratio_checked_rem_euclid(x, y) { + Ok(V::Ratio(v)) + } else { + throw!(*SYM_VALUE_ERROR, "overflow when calculating {a} modulo {b}") + } + } (V::Float(x), V::Float(y)) => Ok(V::Float(x.rem_euclid(*y))), (V::Complex(x), V::Complex(y)) => { - let n = x / y; - let n = Complex64::new(n.re().floor(), n.im().floor()); - Ok(Value::Complex(x - n * y)) - } - (l, r) => throw!(*SYM_TYPE_ERROR, "cannot modulo {l:#} and {r:#}") + let n = x / y; + let n = Complex64::new(n.re().floor(), n.im().floor()); + Ok(Value::Complex(x - n * y)) + } + (l, r) => throw!(*SYM_TYPE_ERROR, "cannot modulo {l:#} and {r:#}"), } } pub fn int_div(self, rhs: Value) -> Result { use Value as V; - let (a, b) = promote(self, rhs); + let (a, b) = promote(self, rhs); match (&a, &b) { (V::Int(_), V::Int(0)) => throw!(*SYM_VALUE_ERROR, "integer divsion by 0"), - (V::Int(x), V::Int(y)) => if let Some(v) = x.checked_div_euclid(*y) { - Ok(V::Int(v)) - } else { - throw!(*SYM_VALUE_ERROR, "overflow when integer dividing {a} and {b}") - }, + (V::Int(x), V::Int(y)) => { + if let Some(v) = x.checked_div_euclid(*y) { + Ok(V::Int(v)) + } else { + throw!( + *SYM_VALUE_ERROR, + "overflow when integer dividing {a} and {b}" + ) + } + } - (V::Ratio(_), V::Ratio(y)) if y.is_zero() - => throw!(*SYM_VALUE_ERROR, "integer division by 0"), - (V::Ratio(x), V::Ratio(y)) => if let Some(v) = ratio_checked_div_euclid(x, y) { - Ok(V::Ratio(v)) - } else { - throw!(*SYM_VALUE_ERROR, "overflow when integer dividing {a} and {b}") - }, + (V::Ratio(_), V::Ratio(y)) if y.is_zero() => { + throw!(*SYM_VALUE_ERROR, "integer division by 0") + } + (V::Ratio(x), V::Ratio(y)) => { + if let Some(v) = ratio_checked_div_euclid(x, y) { + Ok(V::Ratio(v)) + } else { + throw!( + *SYM_VALUE_ERROR, + "overflow when integer dividing {a} and {b}" + ) + } + } (V::Float(x), V::Float(y)) => Ok(V::Float(x.div_euclid(*y))), (V::Complex(x), V::Complex(y)) => { - let n = x / y; - Ok(V::from(Complex64::new(n.re().floor(), n.im().floor()))) - } - (l, r) => throw!(*SYM_TYPE_ERROR, "cannot integer divide {l:#} and {r:#}") + let n = x / y; + Ok(V::from(Complex64::new(n.re().floor(), n.im().floor()))) + } + (l, r) => throw!(*SYM_TYPE_ERROR, "cannot integer divide {l:#} and {r:#}"), } } } - ////////////////////// // exponentiation // ////////////////////// - #[inline] fn ipow(n: i64, p: u64) -> Option { match (n, p) { (0, 0) => None, (0, _) => Some(0), (_, 0) => Some(1), - (1, _) => Some(1), - (-1, p) => (-1_i64).checked_pow((p % 2) as u32), + (1, _) => Some(1), + (-1, p) => (-1_i64).checked_pow((p % 2) as u32), (_, p) if p > u32::MAX as u64 => None, (n, p) => n.checked_pow(p as u32), } @@ -279,12 +319,12 @@ fn ipow(n: i64, p: u64) -> Option { #[inline] fn rpow(n: i64, d: i64, p: i64) -> Option<(i64, i64)> { match p { - i64::MIN => match (n, d) { - (0, _) => Some((0, 1)), - (1, 1) => Some((1, 1)), - (-1, 1) => Some((-1, 1)), - _ => None, - } + i64::MIN => match (n, d) { + (0, _) => Some((0, 1)), + (1, 1) => Some((1, 1)), + (-1, 1) => Some((-1, 1)), + _ => None, + }, 0.. => Some((ipow(n, p as u64)?, ipow(d, p as u64)?)), _ => Some((ipow(d, (-p) as u64)?, ipow(n, (-p) as u64)?)), } @@ -294,45 +334,54 @@ impl Value { pub fn pow(self, rhs: Value) -> Result { use Value as V; if let (V::Ratio(x), V::Int(y)) = (&self, &rhs) { - if x.is_zero() && *y == 0 { - throw!(*SYM_VALUE_ERROR, "rational zero to integer zero power") - } - let Some(v) = rpow(*(*x).numer(), *(*x).denom(), *y) else { - throw!(*SYM_VALUE_ERROR, "overflow when raising {self} to the power {rhs}") - }; + if x.is_zero() && *y == 0 { + throw!(*SYM_VALUE_ERROR, "rational zero to integer zero power") + } + let Some(v) = rpow(*(*x).numer(), *(*x).denom(), *y) else { + throw!( + *SYM_VALUE_ERROR, + "overflow when raising {self} to the power {rhs}" + ) + }; return Ok(V::Ratio(v.into())) } - let (a, b) = promote(self, rhs); + let (a, b) = promote(self, rhs); match (&a, &b) { - (V::Int(0), V::Int(0)) - => throw!(*SYM_VALUE_ERROR, "integer zero to integer zero power"), - (V::Int(x), V::Int(y @ 0..)) => if let Some(v) = ipow(*x, *y as u64) { - Ok(V::Int(v)) - } else { - throw!(*SYM_VALUE_ERROR, "overflow when raising {a} to the power {b}") - }, - (V::Int(x), V::Int(y)) => if let Some(v) = rpow(*x, 1, *y) { - Ok(V::Ratio(v.into())) - } else { - throw!(*SYM_VALUE_ERROR, "overflow when raising {a} to the power {b}") - }, - (V::Ratio(x), V::Ratio(y)) - => Ok(V::Float(x.to_f64().powf(y.to_f64()))), - (V::Float(x), V::Float(y)) - => Ok(V::Float(x.powf(*y))), - (V::Complex(x), V::Complex(y)) - => Ok(V::Complex(x.powc(*y))), - (l, r) => throw!(*SYM_TYPE_ERROR, "cannot exponentiate {l:#} and {r:#}") + (V::Int(0), V::Int(0)) => { + throw!(*SYM_VALUE_ERROR, "integer zero to integer zero power") + } + (V::Int(x), V::Int(y @ 0..)) => { + if let Some(v) = ipow(*x, *y as u64) { + Ok(V::Int(v)) + } else { + throw!( + *SYM_VALUE_ERROR, + "overflow when raising {a} to the power {b}" + ) + } + } + (V::Int(x), V::Int(y)) => { + if let Some(v) = rpow(*x, 1, *y) { + Ok(V::Ratio(v.into())) + } else { + throw!( + *SYM_VALUE_ERROR, + "overflow when raising {a} to the power {b}" + ) + } + } + (V::Ratio(x), V::Ratio(y)) => Ok(V::Float(x.to_f64().powf(y.to_f64()))), + (V::Float(x), V::Float(y)) => Ok(V::Float(x.powf(*y))), + (V::Complex(x), V::Complex(y)) => Ok(V::Complex(x.powc(*y))), + (l, r) => throw!(*SYM_TYPE_ERROR, "cannot exponentiate {l:#} and {r:#}"), } } } - ////////////////////////// // Bitwise operations // ////////////////////////// - impl Shl for Value { type Output = Result; @@ -340,7 +389,7 @@ impl Shl for Value { use Value as V; match (self, rhs) { (V::Int(a), V::Int(b)) => Ok(Value::Int(((a as u64) << b as u64) 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:#}"), } } } @@ -352,7 +401,7 @@ impl Shr for Value { use Value as V; match (self, rhs) { (V::Int(a), V::Int(b)) => Ok(Value::Int((a as u64 >> b as u64) 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:#}"), } } } @@ -364,7 +413,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 shift {l:#} right by {r:#}"), } } } @@ -376,7 +425,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 shift {l:#} right by {r:#}"), } } } @@ -388,47 +437,46 @@ 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 shift {l:#} right by {r:#}"), } } } - ///////////////////////////// // Equality and ordering // ///////////////////////////// - impl PartialEq for Value { fn eq(&self, other: &Self) -> bool { - use Value as V; use super::range::RangeType as Rty; + use Value as V; match (self, other) { - (V::Nil, V::Nil) => true, - (V::Bool(a), V::Bool(b)) => a == b, - (V::Int(a), V::Int(b)) => *a == *b, - (V::Ratio(a), V::Ratio(b)) => *a == *b, - (V::Float(a), V::Float(b)) => *a == *b, + (V::Nil, V::Nil) => true, + (V::Bool(a), V::Bool(b)) => a == b, + (V::Int(a), V::Int(b)) => *a == *b, + (V::Ratio(a), V::Ratio(b)) => *a == *b, + (V::Float(a), V::Float(b)) => *a == *b, (V::Complex(a), V::Complex(b)) => *a == *b, - (V::Int(a), V::Ratio(b)) => Rational64::from(*a) == *b, - (V::Ratio(a), V::Int(b)) => *a == Rational64::from(*b), - (V::Int(a), V::Float(b)) => *a as f64 == *b, - (V::Float(a), V::Int(b)) => *a == *b as f64, - (V::Int(a), V::Complex(b)) => Complex64::from(*a as f64) == *b, + (V::Int(a), V::Ratio(b)) => Rational64::from(*a) == *b, + (V::Ratio(a), V::Int(b)) => *a == Rational64::from(*b), + (V::Int(a), V::Float(b)) => *a as f64 == *b, + (V::Float(a), V::Int(b)) => *a == *b as f64, + (V::Int(a), V::Complex(b)) => Complex64::from(*a as f64) == *b, (V::Complex(a), V::Int(b)) => *a == Complex64::from(*b as f64), - (V::Ratio(a), V::Float(b)) => a.to_f64() == *b, - (V::Float(a), V::Ratio(b)) => *a == b.to_f64(), - (V::Ratio(a), V::Complex(b)) => Complex64::from(a.to_f64()) == *b, + (V::Ratio(a), V::Float(b)) => a.to_f64() == *b, + (V::Float(a), V::Ratio(b)) => *a == b.to_f64(), + (V::Ratio(a), V::Complex(b)) => Complex64::from(a.to_f64()) == *b, (V::Complex(a), V::Ratio(b)) => *a == Complex64::from(b.to_f64()), - (V::Float(a), V::Complex(b)) => Complex64::from(*a) == *b, + (V::Float(a), V::Complex(b)) => Complex64::from(*a) == *b, (V::Complex(a), V::Float(b)) => *a == Complex64::from(*b), - (V::String(a), V::String(b)) => *a == *b, - (V::List(a), V::List(b)) => *a.borrow() == *b.borrow(), - (V::Symbol(a), V::Symbol(b)) => a == b, - (V::Cell(a), V::Cell(b)) => *a.borrow() == *b.borrow(), - (V::Range(a), V::Range(b)) => match (a.ty, b.ty) { - (Rty::Open, Rty::Open) - | (Rty::Closed, Rty::Closed) => a.start == b.start && a.stop == b.stop, + (V::String(a), V::String(b)) => *a == *b, + (V::List(a), V::List(b)) => *a.borrow() == *b.borrow(), + (V::Symbol(a), V::Symbol(b)) => a == b, + (V::Cell(a), V::Cell(b)) => *a.borrow() == *b.borrow(), + (V::Range(a), V::Range(b)) => match (a.ty, b.ty) { + (Rty::Open, Rty::Open) | (Rty::Closed, Rty::Closed) => { + a.start == b.start && a.stop == b.stop + } (Rty::Open, Rty::Closed) => a.start == b.start && a.stop == b.stop - 1, (Rty::Closed, Rty::Open) => a.start == b.start && a.stop - 1 == b.stop, (Rty::Endless, Rty::Endless) => a.start == b.start, @@ -464,12 +512,10 @@ impl PartialOrd for Value { } } - //////////// // misc // //////////// - impl Value { pub fn val_cmp(&self, other: &Self) -> Result { match self.partial_cmp(other) { @@ -485,7 +531,7 @@ impl Value { let mut l = l1.borrow().clone(); l.extend_from_slice(&l2.borrow()); Ok(l.into()) - }, + } (V::String(s1), V::String(s2)) => { let mut s: LString = s1.as_ref().to_owned(); s.push_lstr(s2); @@ -507,23 +553,40 @@ impl Value { let mut l = list.borrow().clone(); l.push(val); Ok(l.into()) - }, + } lhs => throw!(*SYM_TYPE_ERROR, "cannot append to {lhs:#}"), } } pub fn range(&self, other: &Self, closed: bool) -> Result { if let (Value::Int(start), Value::Int(stop)) = (self, other) { - let ty = if closed { RangeType::Closed } else { RangeType::Open }; - Ok(Range { start: *start, stop: *stop, ty }.into()) + let ty = if closed { + RangeType::Closed + } else { + RangeType::Open + }; + Ok(Range { + start: *start, + stop: *stop, + ty, + } + .into()) } else { - throw!(*SYM_TYPE_ERROR, "cannot create range between {self:#} and {other:#}") + throw!( + *SYM_TYPE_ERROR, + "cannot create range between {self:#} and {other:#}" + ) } } pub fn range_endless(&self) -> Result { if let Value::Int(start) = self { - Ok(Range { start: *start, stop: 0, ty: RangeType::Endless }.into()) + Ok(Range { + start: *start, + stop: 0, + ty: RangeType::Endless, + } + .into()) } else { throw!(*SYM_TYPE_ERROR, "cannot create endless range from {self:#}") } @@ -543,7 +606,7 @@ impl Value { pub fn iter_pack(v: Option) -> Self { match v { Some(v) => v, - None => Value::from(*SYM_END_ITERATION) + None => Value::from(*SYM_END_ITERATION), } } @@ -553,11 +616,12 @@ impl Value { Self::Range(range) => { let range_iter = RefCell::new(range.into_iter()); let f = move |_: &mut Vm, _: Vec| -> Result { - Ok(Value::iter_pack(range_iter.borrow_mut().next() - .map(Value::from))) + Ok(Value::iter_pack( + range_iter.borrow_mut().next().map(Value::from), + )) }; Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[range]")).into()) - }, + } Self::String(s) => { let byte_pos = RefCell::new(0); let f = move |_: &mut Vm, _: Vec| -> Result { @@ -570,7 +634,7 @@ impl Value { } }; Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[string]")).into()) - }, + } Self::List(list) => { let idx = RefCell::new(0); let f = move |_: &mut Vm, _: Vec| -> Result { @@ -583,16 +647,17 @@ impl Value { } }; Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[list]")).into()) - }, + } Self::Table(table) => { let keys: Vec = table.borrow().keys().cloned().collect(); let keys = RefCell::new(keys.into_iter()); let f = move |_: &mut Vm, _: Vec| -> Result { - Ok(Value::iter_pack(keys.borrow_mut().next() - .map(HashValue::into_inner))) + Ok(Value::iter_pack( + keys.borrow_mut().next().map(HashValue::into_inner), + )) }; Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[table]")).into()) - }, + } _ => throw!(*SYM_TYPE_ERROR, "cannot iterate {self:#}"), } } diff --git a/talc-lang/src/value/range.rs b/talc-lang/src/value/range.rs index 6974244..a6afa49 100644 --- a/talc-lang/src/value/range.rs +++ b/talc-lang/src/value/range.rs @@ -1,7 +1,8 @@ - #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum RangeType { - Open, Closed, Endless, + Open, + Closed, + Endless, } #[derive(Clone, Copy, Debug)] @@ -31,7 +32,7 @@ impl Range { impl IntoIterator for Range { type Item = i64; - type IntoIter = Box>; + type IntoIter = Box>; fn into_iter(self) -> Self::IntoIter { match self.ty { RangeType::Open => Box::new(self.start..self.stop), @@ -40,5 +41,3 @@ impl IntoIterator for Range { } } } - - diff --git a/talc-lang/src/vm.rs b/talc-lang/src/vm.rs index c4ebfc6..1575008 100644 --- a/talc-lang/src/vm.rs +++ b/talc-lang/src/vm.rs @@ -1,8 +1,26 @@ -use std::{cmp::Ordering, collections::HashMap, rc::Rc, sync::{atomic::AtomicBool, Arc}}; +use std::{ + cmp::Ordering, + collections::HashMap, + rc::Rc, + sync::{atomic::AtomicBool, Arc}, +}; -use crate::{parser::ast::{BinaryOp, UnaryOp}, chunk::Instruction, exception::{throw, Exception, Result}, lstring::LStr, symbol::{Symbol, SYM_CALL_STACK_OVERFLOW, SYM_INTERRUPTED, SYM_NAME_ERROR, SYM_TYPE_ERROR}, value::{function::{FuncAttrs, Function, NativeFunc}, Value}}; +use crate::{ + chunk::Instruction, + exception::{throw, Exception, Result}, + lstring::LStr, + parser::ast::{BinaryOp, UnaryOp}, + symbol::{Symbol, SYM_CALL_STACK_OVERFLOW, SYM_INTERRUPTED, SYM_NAME_ERROR, SYM_TYPE_ERROR}, + value::{ + function::{FuncAttrs, Function, NativeFunc}, + Value, + }, +}; -struct TryFrame { idx: usize, stack_len: usize } +struct TryFrame { + idx: usize, + stack_len: usize, +} struct CallFrame { func: Rc, @@ -78,25 +96,28 @@ fn get_call_outcome(args: Vec) -> Result { throw!(*SYM_TYPE_ERROR, "cannot call non-function {f:#}") }; let argc = args.len() - 1; - match argc.cmp(&attrs.arity) { - Ordering::Equal => Ok(CallOutcome::Call(args)), - Ordering::Greater => throw!(*SYM_TYPE_ERROR, "too many arguments for function"), - Ordering::Less => { - let remaining = attrs.arity - argc; - let f = f.clone(); - let nf = move |vm: &mut Vm, inner_args: Vec| { - let mut ia = inner_args.into_iter(); - ia.next(); - let args: Vec = args.clone().into_iter().chain(ia).collect(); - vm.call_value(f.clone(), args) - }; - let nf = NativeFunc { - attrs: FuncAttrs { arity: remaining, name: None }, - func: Box::new(nf), - }; - Ok(CallOutcome::Partial(nf.into())) - } - } + match argc.cmp(&attrs.arity) { + Ordering::Equal => Ok(CallOutcome::Call(args)), + Ordering::Greater => throw!(*SYM_TYPE_ERROR, "too many arguments for function"), + Ordering::Less => { + let remaining = attrs.arity - argc; + let f = f.clone(); + let nf = move |vm: &mut Vm, inner_args: Vec| { + let mut ia = inner_args.into_iter(); + ia.next(); + let args: Vec = args.clone().into_iter().chain(ia).collect(); + vm.call_value(f.clone(), args) + }; + let nf = NativeFunc { + attrs: FuncAttrs { + arity: remaining, + name: None, + }, + func: Box::new(nf), + }; + Ok(CallOutcome::Partial(nf.into())) + } + } } impl Vm { @@ -119,7 +140,9 @@ impl Vm { } pub fn set_global_name<'a, S>(&mut self, name: S, val: Value) - where S: Into<&'a LStr> { + where + S: Into<&'a LStr>, + { self.globals.insert(Symbol::get(name.into()), val); } @@ -138,8 +161,8 @@ impl Vm { CallOutcome::Call(args) => match value { Value::Function(f) => self.run_function(f, args), Value::NativeFunc(f) => (f.func)(self, args), - _ => unreachable!("already verified by calling get_call_type") - } + _ => unreachable!("already verified by calling get_call_type"), + }, } } @@ -175,7 +198,7 @@ impl Vm { while let Some(try_frame) = frame.try_frames.pop() { let table = &frame.func.chunk.try_tables[try_frame.idx]; for catch in &table.catches { - if catch.types.is_none() || catch.types.as_ref().unwrap().contains(&exc.ty) { + if catch.types.is_none() || catch.types.as_ref().unwrap().contains(&exc.ty) { frame.ip = catch.addr; frame.locals.truncate(table.local_count); self.stack.truncate(try_frame.stack_len); @@ -209,7 +232,10 @@ impl Vm { } fn check_interrupt(&mut self) -> Result<()> { - if self.interrupt.fetch_and(false, std::sync::atomic::Ordering::Relaxed) { + if self + .interrupt + .fetch_and(false, std::sync::atomic::Ordering::Relaxed) + { throw!(*SYM_INTERRUPTED) } Ok(()) @@ -222,17 +248,13 @@ impl Vm { // do nothing I::Nop => (), // [] -> [locals[n]] - I::LoadLocal(n) - => self.push(frame.locals[usize::from(n)].clone()), + I::LoadLocal(n) => self.push(frame.locals[usize::from(n)].clone()), // [x] -> [], locals[n] = x - I::StoreLocal(n) - => frame.locals[usize::from(n)] = self.pop(), + I::StoreLocal(n) => frame.locals[usize::from(n)] = self.pop(), // [x] -> [], locals.push(x) - I::NewLocal - => frame.locals.push(self.pop()), + I::NewLocal => frame.locals.push(self.pop()), // locals.pop_n(n) - I::DropLocal(n) - => frame.locals.truncate(frame.locals.len() - usize::from(n)), + I::DropLocal(n) => frame.locals.truncate(frame.locals.len() - usize::from(n)), // [] -> [globals[s]] I::LoadGlobal(s) => { let sym = unsafe { s.to_symbol_unchecked() }; @@ -241,65 +263,67 @@ impl Vm { None => throw!(*SYM_NAME_ERROR, "undefined global {}", sym.name()), }; self.push(v); - }, + } // [x] -> [], globals[s] = x I::StoreGlobal(s) => { let sym = unsafe { s.to_symbol_unchecked() }; let v = self.pop(); self.globals.insert(sym, v); - }, - I::CloseOver(n) => { - let n = usize::from(n); - let v = std::mem::replace(&mut frame.locals[n], Value::Nil); - let v = v.to_cell(); - frame.locals[n] = v.clone(); - self.push(v); - }, - I::Closure(n) => { - let f = frame.func.chunk.consts[usize::from(n)].clone(); - let Value::Function(f) = f else { - panic!("attempt to build closure from non-closure constant") - }; - let mut f = f.as_ref().clone(); + } + I::CloseOver(n) => { + let n = usize::from(n); + let v = std::mem::replace(&mut frame.locals[n], Value::Nil); + let v = v.to_cell(); + frame.locals[n] = v.clone(); + self.push(v); + } + I::Closure(n) => { + let f = frame.func.chunk.consts[usize::from(n)].clone(); + let Value::Function(f) = f else { + panic!("attempt to build closure from non-closure constant") + }; + let mut f = f.as_ref().clone(); - let captured: Vec<_> = self.pop_n(f.state.len()).into_iter() - .map(|v| { - let Value::Cell(v) = v else { - panic!("attempt to build closure from non-cell local"); - }; - v - }).collect(); + let captured: Vec<_> = self + .pop_n(f.state.len()) + .into_iter() + .map(|v| { + let Value::Cell(v) = v else { + panic!("attempt to build closure from non-cell local"); + }; + v + }) + .collect(); - f.state = captured.into_boxed_slice(); - self.push(f.into()); - }, - I::LoadUpvalue(n) => { - let v = frame.func.state[usize::from(n)].clone(); - self.push(v.borrow().clone()); - }, - I::StoreUpvalue(n) => { - let v = frame.func.state[usize::from(n)].clone(); - *v.borrow_mut() = self.pop(); - }, - I::ContinueUpvalue(n) => { - let v = frame.func.state[usize::from(n)].clone(); - self.push(Value::Cell(v)); - }, - I::LoadClosedLocal(n) => { - let Value::Cell(c) = &frame.locals[usize::from(n)] else { - panic!("attempt to load from closed non-cell local"); - }; + f.state = captured.into_boxed_slice(); + self.push(f.into()); + } + I::LoadUpvalue(n) => { + let v = frame.func.state[usize::from(n)].clone(); + self.push(v.borrow().clone()); + } + I::StoreUpvalue(n) => { + let v = frame.func.state[usize::from(n)].clone(); + *v.borrow_mut() = self.pop(); + } + I::ContinueUpvalue(n) => { + let v = frame.func.state[usize::from(n)].clone(); + self.push(Value::Cell(v)); + } + I::LoadClosedLocal(n) => { + let Value::Cell(c) = &frame.locals[usize::from(n)] else { + panic!("attempt to load from closed non-cell local"); + }; self.push(c.borrow().clone()); - }, - I::StoreClosedLocal(n) => { - let Value::Cell(c) = &frame.locals[usize::from(n)] else { - panic!("attempt to store to closed non-cell local"); - }; - *c.borrow_mut() = self.pop(); - }, + } + I::StoreClosedLocal(n) => { + let Value::Cell(c) = &frame.locals[usize::from(n)] else { + panic!("attempt to store to closed non-cell local"); + }; + *c.borrow_mut() = self.pop(); + } // [] -> [consts[n]] - I::Const(n) - => self.push(frame.func.chunk.consts[usize::from(n)].clone()), + I::Const(n) => self.push(frame.func.chunk.consts[usize::from(n)].clone()), // [] -> [nil] I::Nil => self.push(Value::Nil), // [] -> [b] @@ -308,7 +332,7 @@ impl Vm { I::Symbol(s) => { let sym = unsafe { Symbol::from_id_unchecked(u32::from(s)) }; self.push(Value::Symbol(sym)); - }, + } // [] -> [n] I::Int(n) => self.push(Value::Int(i64::from(n))), // [x] -> [x,x] @@ -317,38 +341,44 @@ impl Vm { I::DupTwo => { self.push(self.stack[self.stack.len() - 2].clone()); self.push(self.stack[self.stack.len() - 2].clone()); - }, + } // [a0,a1...an] -> [] - I::Drop(n) => for _ in 0..u32::from(n) { self.pop(); }, + I::Drop(n) => { + for _ in 0..u32::from(n) { + self.pop(); + } + } // [x,y] -> [y,x] I::Swap => { let len = self.stack.len(); self.stack.swap(len - 1, len - 2); - }, + } // [x,y] -> [y op x] I::BinaryOp(op) => { let b = self.pop(); let a = self.pop(); self.push(binary_op(op, a, b)?); - }, + } // [x] -> [op x] I::UnaryOp(op) => { let a = self.pop(); self.push(unary_op(op, a)?); - }, + } // [a0,a1...an] -.> [[a0,a1...an]] I::NewList(n) => { let list = self.pop_n(n as usize); self.push(list.into()); - }, + } // [l,a0,a1...an] -.> [l ++ [a0,a1...an]] I::GrowList(n) => { let ext = self.pop_n(n as usize); let list = self.pop(); - let Value::List(list) = list else { panic!("not a list") }; + let Value::List(list) = list else { + panic!("not a list") + }; list.borrow_mut().extend(ext); self.push(Value::List(list)); - }, + } // [k0,v0...kn,vn] -.> [{k0=v0...kn=vn}] I::NewTable(n) => { let mut table = HashMap::new(); @@ -358,12 +388,14 @@ impl Vm { table.insert(k.try_into()?, v); } self.push(table.into()); - }, + } // [t,k0,v0...kn,vn] -> [t ++ {k0=v0...kn=vn}] I::GrowTable(n) => { let mut ext = self.pop_n(2 * n as usize); let table = self.pop(); - let Value::Table(table) = table else { panic!("not a table") }; + let Value::Table(table) = table else { + panic!("not a table") + }; let mut table_ref = table.borrow_mut(); for _ in 0..n { // can't panic: pop_n checked that ext would have len 2*n @@ -373,13 +405,13 @@ impl Vm { } drop(table_ref); self.push(Value::Table(table)); - }, + } // [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 I::StoreIndex => { let v = self.pop(); @@ -387,27 +419,31 @@ impl Vm { let ct = self.pop(); ct.store_index(self, idx, v.clone())?; self.push(v); - }, + } // ip = n I::Jump(n) => { self.check_interrupt()?; frame.ip = usize::from(n); - }, + } // [v] ->, [], if v then ip = n - I::JumpTrue(n) => if self.pop().truthy() { - self.check_interrupt()?; - frame.ip = usize::from(n); - }, + I::JumpTrue(n) => { + if self.pop().truthy() { + self.check_interrupt()?; + frame.ip = usize::from(n); + } + } // [v] ->, [], if not v then ip = n - I::JumpFalse(n) => if !self.pop().truthy() { - self.check_interrupt()?; - frame.ip = usize::from(n); - }, + I::JumpFalse(n) => { + if !self.pop().truthy() { + self.check_interrupt()?; + frame.ip = usize::from(n); + } + } // [v] -> [iter(v)] I::IterBegin => { let iter = self.pop().to_iter_function()?; self.push(iter); - }, + } // [i,cell(v)] -> [i,v] // [i,nil] -> [], ip = n I::IterTest(n) => { @@ -417,19 +453,19 @@ impl Vm { self.pop(); frame.ip = usize::from(n); } - }, + } // try_frames.push(t, stack.len()) I::BeginTry(t) => { let tryframe = TryFrame { idx: usize::from(t), - stack_len: self.stack.len() + stack_len: self.stack.len(), }; frame.try_frames.push(tryframe); - }, + } // try_frames.pop() I::EndTry => { frame.try_frames.pop().expect("no try to pop"); - }, + } // [f,a0,a1...an] -> [f(a0,a1...an)] I::Call(n) => { let n = usize::from(n); @@ -471,7 +507,6 @@ impl Vm { self.push(res); } else if let Value::Function(func) = &args[0] { - if self.call_stack.len() + 1 >= self.stack_max { throw!(*SYM_CALL_STACK_OVERFLOW, "call stack overflow") } @@ -482,22 +517,18 @@ impl Vm { } else { unreachable!("already verified by calling get_call_type"); } - }, + } // [v] -> [], return v - I::Return if frame.root => { - return Ok(Some(self.pop())); - }, + I::Return if frame.root => return Ok(Some(self.pop())), // [v] -> [], return v I::Return => { self.check_interrupt()?; *frame = self.call_stack.pop().expect("no root frame"); - }, + } } Ok(None) } - - } #[macro_export] diff --git a/talc-macros/src/lib.rs b/talc-macros/src/lib.rs index 3d701d7..065ef4c 100644 --- a/talc-macros/src/lib.rs +++ b/talc-macros/src/lib.rs @@ -4,5 +4,5 @@ mod native_func; #[proc_macro_attribute] pub fn native_func(input: TokenStream, annotated_item: TokenStream) -> TokenStream { - native_func::native_func(input, annotated_item) + native_func::native_func(input, annotated_item) } diff --git a/talc-macros/src/native_func.rs b/talc-macros/src/native_func.rs index f3506f4..a6e0758 100644 --- a/talc-macros/src/native_func.rs +++ b/talc-macros/src/native_func.rs @@ -1,22 +1,25 @@ use proc_macro::TokenStream; -use syn::{parse::Parse, parse_macro_input, Token}; use quote::{quote, ToTokens}; +use syn::{parse::Parse, parse_macro_input, Token}; struct NativeFuncArgs { arity: syn::LitInt, - name: Option, + name: Option, } impl Parse for NativeFuncArgs { fn parse(input: syn::parse::ParseStream) -> syn::Result { let arity = input.parse()?; - let t: Option = input.parse()?; - if t.is_some() { - let name = input.parse()?; - Ok(Self { arity, name: Some(name) }) - } else { - Ok(Self { arity, name: None }) - } + let t: Option = input.parse()?; + if t.is_some() { + let name = input.parse()?; + Ok(Self { + arity, + name: Some(name), + }) + } else { + Ok(Self { arity, name: None }) + } } } @@ -34,14 +37,17 @@ pub fn native_func(input: TokenStream, annotated_item: TokenStream) -> TokenStre let arity = args.arity; let talc_name = match args.name { - Some(n) => n.to_token_stream(), - None => name.to_token_stream(), - }; + Some(n) => n.to_token_stream(), + None => name.to_token_stream(), + }; assert!(itemfn.sig.constness.is_none(), "item must not be const"); assert!(itemfn.sig.asyncness.is_none(), "item must not be async"); assert!(itemfn.sig.unsafety.is_none(), "item must not be unsafe"); - assert!(itemfn.sig.abi.is_none(), "item must not contain an ABI specifier"); + assert!( + itemfn.sig.abi.is_none(), + "item must not contain an ABI specifier" + ); assert!(itemfn.sig.variadic.is_none(), "item must not be variadic"); let expanded = quote! { @@ -49,7 +55,7 @@ pub fn native_func(input: TokenStream, annotated_item: TokenStream) -> TokenStre ::talc_lang::value::function::NativeFunc { attrs: ::talc_lang::value::function::FuncAttrs{ arity: #arity, - name: Some(::talc_lang::symbol::symbol!(#talc_name)) + name: Some(::talc_lang::symbol::symbol!(#talc_name)) }, func: Box::new(|#inputs| #output #block) } diff --git a/talc-std/src/collection.rs b/talc-std/src/collection.rs index ff86fa4..445030b 100644 --- a/talc-std/src/collection.rs +++ b/talc-std/src/collection.rs @@ -1,11 +1,16 @@ use std::cmp::Ordering; -use talc_lang::{exception::{exception, Result}, symbol::{symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{function::NativeFunc, Value}, vmcall, Vm}; +use talc_lang::{ + exception::{exception, Result}, + symbol::{symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, + throw, + value::{function::NativeFunc, Value}, + vmcall, Vm, +}; use talc_macros::native_func; use crate::unpack_args; - pub fn load(vm: &mut Vm) { vm.set_global_name("push", push().into()); vm.set_global_name("pop", pop().into()); @@ -55,7 +60,10 @@ pub fn clear(_: &mut Vm, args: Vec) -> Result { match &col { Value::List(list) => list.borrow_mut().clear(), Value::Table(table) => table.borrow_mut().clear(), - _ => throw!(*SYM_TYPE_ERROR, "clear expected list or table, found {col:#}") + _ => throw!( + *SYM_TYPE_ERROR, + "clear expected list or table, found {col:#}" + ), } Ok(col) } @@ -63,7 +71,10 @@ pub fn clear(_: &mut Vm, args: Vec) -> Result { fn call_comparison(vm: &mut Vm, by: Value, l: Value, r: Value) -> Result { let ord = vmcall!(vm; by, l, r)?; let Value::Int(ord) = ord else { - throw!(*SYM_TYPE_ERROR, "comparison function should return an integer") + throw!( + *SYM_TYPE_ERROR, + "comparison function should return an integer" + ) }; Ok(ord) } @@ -82,14 +93,14 @@ fn partition(vals: &mut [Value]) -> (usize, usize) { vals.swap(eq, lt); lt += 1; eq += 1; - }, + } Some(Ordering::Greater) => { vals.swap(eq, gt); gt -= 1; - }, + } Some(Ordering::Equal) | None => { eq += 1; - }, + } } } @@ -110,14 +121,14 @@ fn partition_by(vals: &mut [Value], by: &Value, vm: &mut Vm) -> Result<(usize, u vals.swap(eq, lt); lt += 1; eq += 1; - }, + } 1.. => { vals.swap(eq, gt); gt -= 1; - }, + } 0 => { eq += 1; - }, + } } } @@ -127,8 +138,8 @@ fn partition_by(vals: &mut [Value], by: &Value, vm: &mut Vm) -> Result<(usize, u fn insertion(vals: &mut [Value]) { for i in 0..vals.len() { let mut j = i; - while j > 0 && vals[j-1] > vals[j] { - vals.swap(j, j-1); + while j > 0 && vals[j - 1] > vals[j] { + vals.swap(j, j - 1); j -= 1; } } @@ -138,11 +149,11 @@ fn insertion_by(vals: &mut [Value], by: &Value, vm: &mut Vm) -> Result<()> { for i in 0..vals.len() { let mut j = i; while j > 0 { - let ord = call_comparison(vm, by.clone(), vals[j-1].clone(), vals[j].clone())?; + let ord = call_comparison(vm, by.clone(), vals[j - 1].clone(), vals[j].clone())?; if ord <= 0 { - break; + break } - vals.swap(j, j-1); + vals.swap(j, j - 1); j -= 1; } } @@ -165,7 +176,7 @@ fn sort_inner(vals: &mut [Value], by: Option<&Value>, vm: &mut Vm) -> Result<()> None => partition(vals), }; sort_inner(&mut vals[..lt], by, vm)?; - sort_inner(&mut vals[(gt+1)..], by, vm) + sort_inner(&mut vals[(gt + 1)..], by, vm) } #[native_func(1)] @@ -202,7 +213,10 @@ pub fn sort_key(vm: &mut Vm, args: Vec) -> Result { Some(Ordering::Greater) => Ok(Value::Int(1)), Some(Ordering::Equal) => Ok(Value::Int(0)), Some(Ordering::Less) => Ok(Value::Int(-1)), - None => throw!(*SYM_VALUE_ERROR, "values returned from sort key were incomparable"), + None => throw!( + *SYM_VALUE_ERROR, + "values returned from sort key were incomparable" + ), } }; let nf = NativeFunc::new(Box::new(f), 2, symbol!("inner[sort_key]")).into(); @@ -212,32 +226,32 @@ pub fn sort_key(vm: &mut Vm, args: Vec) -> Result { #[native_func(2)] pub fn pair(_: &mut Vm, args: Vec) -> Result { - let [_, x, y] = unpack_args!(args); - Ok(vec![x, y].into()) + let [_, x, y] = unpack_args!(args); + Ok(vec![x, y].into()) } #[native_func(1)] pub fn fst(_: &mut Vm, args: Vec) -> Result { - let [_, l] = unpack_args!(args); - let Value::List(l) = l else { - throw!(*SYM_TYPE_ERROR, "fst: expected list") - }; - let l = l.borrow(); - let [x, _] = l.as_slice() else { - throw!(*SYM_VALUE_ERROR, "fst: list must have length 2") - }; - Ok(x.clone()) + let [_, l] = unpack_args!(args); + let Value::List(l) = l else { + throw!(*SYM_TYPE_ERROR, "fst: expected list") + }; + let l = l.borrow(); + let [x, _] = l.as_slice() else { + throw!(*SYM_VALUE_ERROR, "fst: list must have length 2") + }; + Ok(x.clone()) } #[native_func(1)] pub fn snd(_: &mut Vm, args: Vec) -> Result { - let [_, l] = unpack_args!(args); - let Value::List(l) = l else { - throw!(*SYM_TYPE_ERROR, "snd: expected list") - }; - let l = l.borrow(); - let [_, y] = l.as_slice() else { - throw!(*SYM_VALUE_ERROR, "snd: list must have length 2") - }; - Ok(y.clone()) + let [_, l] = unpack_args!(args); + let Value::List(l) = l else { + throw!(*SYM_TYPE_ERROR, "snd: expected list") + }; + let l = l.borrow(); + let [_, y] = l.as_slice() else { + throw!(*SYM_VALUE_ERROR, "snd: list must have length 2") + }; + Ok(y.clone()) } diff --git a/talc-std/src/exception.rs b/talc-std/src/exception.rs index 270987c..9fec58e 100644 --- a/talc-std/src/exception.rs +++ b/talc-std/src/exception.rs @@ -1,4 +1,9 @@ -use talc_lang::{exception::{throw, Exception, Result}, symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, value::Value, Vm}; +use talc_lang::{ + exception::{throw, Exception, Result}, + symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, + value::Value, + Vm, +}; use talc_macros::native_func; use crate::unpack_args; @@ -6,23 +11,24 @@ use crate::unpack_args; #[native_func(1)] pub fn throw(_: &mut Vm, args: Vec) -> Result { let [_, arg] = unpack_args!(args); - let exc = match arg { - Value::Symbol(ty) => Exception::new(ty), - Value::List(l) => match l.borrow().as_slice() { - [Value::Symbol(ty)] | [Value::Symbol(ty), Value::Nil] - => Exception::new(*ty), - [Value::Symbol(ty), Value::Nil, data] - => Exception::new_with_data(*ty, data.clone()), - [Value::Symbol(ty), Value::String(s)] - => Exception::new_with_msg(*ty, s.clone()), - [Value::Symbol(ty), Value::String(s), data] - => Exception::new_with_msg_data(*ty, s.clone(), data.clone()), - [] | [_] | [_,_] | [_,_,_] => throw!(*SYM_TYPE_ERROR, "wrong argument for throw"), - [_,_,_,_,..] => throw!(*SYM_VALUE_ERROR, "too many elements in list argument for throw"), - } - _ => throw!(*SYM_TYPE_ERROR, "throw expected symbol or list"), - }; - Err(exc) + let exc = match arg { + Value::Symbol(ty) => Exception::new(ty), + Value::List(l) => match l.borrow().as_slice() { + [Value::Symbol(ty)] | [Value::Symbol(ty), Value::Nil] => Exception::new(*ty), + [Value::Symbol(ty), Value::Nil, data] => Exception::new_with_data(*ty, data.clone()), + [Value::Symbol(ty), Value::String(s)] => Exception::new_with_msg(*ty, s.clone()), + [Value::Symbol(ty), Value::String(s), data] => { + Exception::new_with_msg_data(*ty, s.clone(), data.clone()) + } + [] | [_] | [_, _] | [_, _, _] => throw!(*SYM_TYPE_ERROR, "wrong argument for throw"), + [_, _, _, _, ..] => throw!( + *SYM_VALUE_ERROR, + "too many elements in list argument for throw" + ), + }, + _ => throw!(*SYM_TYPE_ERROR, "throw expected symbol or list"), + }; + Err(exc) } #[native_func(1)] @@ -32,7 +38,7 @@ pub fn rethrow(_: &mut Vm, args: Vec) -> Result { if let Some(e) = Exception::from_table(&table) { return Err(e) } - throw!(*SYM_VALUE_ERROR, "argument not a valid exception") + throw!(*SYM_VALUE_ERROR, "argument not a valid exception") } throw!(*SYM_TYPE_ERROR, "argument not a valid exception") } diff --git a/talc-std/src/file.rs b/talc-std/src/file.rs index 93843b5..0a52c94 100644 --- a/talc-std/src/file.rs +++ b/talc-std/src/file.rs @@ -1,8 +1,24 @@ -use std::{cell::RefCell, collections::HashMap, fs::{File, OpenOptions}, io::{BufRead, BufReader, BufWriter, ErrorKind, IntoInnerError, Read, Write}, net::{TcpListener, TcpStream, ToSocketAddrs}, os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd}, process::{Child, Command, Stdio}, time::Duration}; +use std::{ + cell::RefCell, + collections::HashMap, + fs::{File, OpenOptions}, + io::{BufRead, BufReader, BufWriter, ErrorKind, IntoInnerError, Read, Write}, + net::{TcpListener, TcpStream, ToSocketAddrs}, + os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd}, + process::{Child, Command, Stdio}, + time::Duration, +}; -use talc_lang::{exception::Result, lstring::LString, symbol::{symbol, Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{function::NativeFunc, HashValue, NativeValue, Value}, Vm}; -use talc_macros::native_func; use lazy_static::lazy_static; +use talc_lang::{ + exception::Result, + lstring::LString, + symbol::{symbol, Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, + throw, + value::{function::NativeFunc, HashValue, NativeValue, Value}, + Vm, +}; +use talc_macros::native_func; use crate::{unpack_args, SYM_IO_ERROR}; @@ -10,7 +26,6 @@ type OpenOptFn = for<'a> fn(&'a mut OpenOptions, bool) -> &'a mut OpenOptions; lazy_static! { static ref SYM_STD_FILE: Symbol = Symbol::get("std.file"); static ref SYM_STD_PROCESS: Symbol = Symbol::get("std.process"); - static ref SYM_R: Symbol = Symbol::get("r"); static ref SYM_W: Symbol = Symbol::get("w"); static ref SYM_A: Symbol = Symbol::get("a"); @@ -18,7 +33,6 @@ lazy_static! { static ref SYM_C: Symbol = Symbol::get("c"); static ref SYM_N: Symbol = Symbol::get("n"); static ref SYM_U: Symbol = Symbol::get("u"); - static ref OPEN_OPT_MAP: HashMap = { let mut map = HashMap::new(); map.insert(*SYM_R, OpenOptions::read as OpenOptFn); @@ -29,21 +43,17 @@ lazy_static! { map.insert(*SYM_N, OpenOptions::create_new); map }; - static ref SYM_STDIN: Symbol = Symbol::get("stdin"); static ref SYM_STDOUT: Symbol = Symbol::get("stdout"); static ref SYM_STDERR: Symbol = Symbol::get("stderr"); static ref SYM_CD: Symbol = Symbol::get("cd"); static ref SYM_DELENV: Symbol = Symbol::get("delenv"); static ref SYM_ENV: Symbol = Symbol::get("env"); - static ref SYM_PROCESS: Symbol = Symbol::get("process"); - static ref SYM_INHERIT: Symbol = Symbol::get("inherit"); static ref SYM_PIPED: Symbol = Symbol::get("piped"); static ref SYM_NULL: Symbol = Symbol::get("null"); static ref SYM_ALL: Symbol = Symbol::get("all"); - } thread_local! { @@ -69,15 +79,23 @@ thread_local! { #[derive(Debug)] enum BufFile { - Buffered { r: BufReader, w: BufWriter }, - Unbuffered { f: File }, + Buffered { + r: BufReader, + w: BufWriter, + }, + Unbuffered { + f: File, + }, } impl BufFile { fn new(file: File, buffered: bool) -> std::io::Result { if buffered { let file2 = file.try_clone()?; - Ok(Self::Buffered { r: BufReader::new(file), w: BufWriter::new(file2) }) + Ok(Self::Buffered { + r: BufReader::new(file), + w: BufWriter::new(file2), + }) } else { Ok(Self::Unbuffered { f: file }) } @@ -92,8 +110,8 @@ impl BufFile { Self::Buffered { r, .. } => { let file = r.get_ref().try_clone()?; Self::new(file, true) - }, - Self::Unbuffered { f } => Ok(Self::Unbuffered { f: f.try_clone()? }) + } + Self::Unbuffered { f } => Ok(Self::Unbuffered { f: f.try_clone()? }), } } @@ -152,9 +170,18 @@ impl From for ValueFile { } impl NativeValue for ValueFile { - fn get_type(&self) -> Symbol { *SYM_STD_FILE } - fn as_any(&self) -> &dyn std::any::Any { self } - fn to_lstring(&self, w: &mut LString, _repr: bool, _recur: &mut Vec<*const ()>) -> std::io::Result<()> { + fn get_type(&self) -> Symbol { + *SYM_STD_FILE + } + fn as_any(&self) -> &dyn std::any::Any { + self + } + fn to_lstring( + &self, + w: &mut LString, + _repr: bool, + _recur: &mut Vec<*const ()>, + ) -> std::io::Result<()> { w.push_str(""); Ok(()) } @@ -170,9 +197,18 @@ impl From for ValueProcess { } impl NativeValue for ValueProcess { - fn get_type(&self) -> Symbol { *SYM_STD_PROCESS } - fn as_any(&self) -> &dyn std::any::Any { self } - fn to_lstring(&self, w: &mut LString, _repr: bool, _recur: &mut Vec<*const ()>) -> std::io::Result<()> { + fn get_type(&self) -> Symbol { + *SYM_STD_PROCESS + } + fn as_any(&self) -> &dyn std::any::Any { + self + } + fn to_lstring( + &self, + w: &mut LString, + _repr: bool, + _recur: &mut Vec<*const ()>, + ) -> std::io::Result<()> { let id = self.0.borrow().id(); write!(w, "") } @@ -201,7 +237,6 @@ pub fn load(vm: &mut Vm) { vm.set_global_name("process_id", process_id().into()); } - #[native_func(2)] pub fn open(_: &mut Vm, args: Vec) -> Result { let [_, path, opts] = unpack_args!(args); @@ -218,33 +253,35 @@ pub fn open(_: &mut Vm, args: Vec) -> Result { } else { match OPEN_OPT_MAP.get(&s) { Some(f) => f(&mut oo, true), - None => throw!(*SYM_VALUE_ERROR, "invalid option for open") + None => throw!(*SYM_VALUE_ERROR, "invalid option for open"), }; } - }, - Value::List(l) => for s in l.borrow().iter() { - let Value::Symbol(s) = s else { - throw!(*SYM_TYPE_ERROR, "invalid option for open") - }; - if *s == *SYM_U { - buffered = false; - } else { - match OPEN_OPT_MAP.get(s) { - Some(f) => f(&mut oo, true), - None => throw!(*SYM_VALUE_ERROR, "invalid option for open") + } + Value::List(l) => { + for s in l.borrow().iter() { + let Value::Symbol(s) = s else { + throw!(*SYM_TYPE_ERROR, "invalid option for open") }; + if *s == *SYM_U { + buffered = false; + } else { + match OPEN_OPT_MAP.get(s) { + Some(f) => f(&mut oo, true), + None => throw!(*SYM_VALUE_ERROR, "invalid option for open"), + }; + } } - }, + } Value::Nil => { oo.read(true).write(true); - }, - _ => throw!(*SYM_TYPE_ERROR, "invalid option for open") + } + _ => throw!(*SYM_TYPE_ERROR, "invalid option for open"), } match oo.open(path.to_os_str()) { Ok(f) => match BufFile::new(f, buffered) { Ok(bf) => Ok(ValueFile::from(bf).into()), Err(e) => throw!(*SYM_IO_ERROR, "{e}"), - } + }, Err(e) => throw!(*SYM_IO_ERROR, "{e}"), } } @@ -256,7 +293,10 @@ pub fn read(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_TYPE_ERROR, "read expected integer, got {nbytes:#}") }; let Ok(nbytes) = usize::try_from(nbytes) else { - throw!(*SYM_VALUE_ERROR, "number of bytes to read must be nonnegative") + throw!( + *SYM_VALUE_ERROR, + "number of bytes to read must be nonnegative" + ) }; let Some(file): Option<&ValueFile> = file.downcast_native() else { throw!(*SYM_TYPE_ERROR, "read expected file, got {file:#}") @@ -317,7 +357,7 @@ pub fn read_until(_: &mut Vm, args: Vec) -> Result { match read_until_impl(r, end.as_bytes()) { Ok(s) if s.is_empty() => Ok(Value::Nil), Ok(s) => Ok(s.into()), - Err(e) => throw!(*SYM_IO_ERROR, "{e}") + Err(e) => throw!(*SYM_IO_ERROR, "{e}"), } } else { throw!(*SYM_TYPE_ERROR, "read_until: file must be buffered") @@ -336,7 +376,7 @@ pub fn read_line(_: &mut Vm, args: Vec) -> Result { match r.read_until(b'\n', &mut buf) { Ok(0) => Ok(Value::Nil), Ok(_) => Ok(LString::from(buf).into()), - Err(e) => throw!(*SYM_IO_ERROR, "{e}") + Err(e) => throw!(*SYM_IO_ERROR, "{e}"), } } else { throw!(*SYM_VALUE_ERROR, "read_line: file must be buffered") @@ -404,7 +444,7 @@ pub fn tcp_connect(_: &mut Vm, args: Vec) -> Result { Ok(stream) => match BufFile::from_raw_fd(stream.into_raw_fd(), true) { Ok(bf) => Ok(ValueFile::from(bf).into()), Err(e) => throw!(*SYM_IO_ERROR, "{e}"), - } + }, Err(e) => throw!(*SYM_IO_ERROR, "{e}"), } } @@ -413,16 +453,26 @@ pub fn tcp_connect(_: &mut Vm, args: Vec) -> Result { pub fn tcp_connect_timeout(_: &mut Vm, args: Vec) -> Result { let [_, addr, timeout] = unpack_args!(args); let Value::String(addr) = addr else { - throw!(*SYM_TYPE_ERROR, "tcp_connect_timeout expected string, got {addr:#}") + throw!( + *SYM_TYPE_ERROR, + "tcp_connect_timeout expected string, got {addr:#}" + ) }; let Ok(addr) = addr.to_str() else { throw!(*SYM_VALUE_ERROR, "address must be valid UTF-8") }; let timeout = match timeout { Value::Int(n) if n >= 0 => Duration::from_secs(n as u64), - Value::Float(n) if n >= 0.0 && n <= Duration::MAX.as_secs_f64() => Duration::from_secs_f64(n), - Value::Int(_) | Value::Float(_) => throw!(*SYM_VALUE_ERROR, "tcp_connect_timeout: invalid timeout"), - _ => throw!(*SYM_TYPE_ERROR, "tcp_connect_timeout expected int or float, got {timeout:#}") + Value::Float(n) if n >= 0.0 && n <= Duration::MAX.as_secs_f64() => { + Duration::from_secs_f64(n) + } + Value::Int(_) | Value::Float(_) => { + throw!(*SYM_VALUE_ERROR, "tcp_connect_timeout: invalid timeout") + } + _ => throw!( + *SYM_TYPE_ERROR, + "tcp_connect_timeout expected int or float, got {timeout:#}" + ), }; let mut addrs = match addr.to_socket_addrs() { Ok(addrs) => addrs, @@ -435,24 +485,23 @@ pub fn tcp_connect_timeout(_: &mut Vm, args: Vec) -> Result { Ok(stream) => match BufFile::from_raw_fd(stream.into_raw_fd(), true) { Ok(bf) => Ok(ValueFile::from(bf).into()), Err(e) => throw!(*SYM_IO_ERROR, "{e}"), - } + }, Err(e) => throw!(*SYM_IO_ERROR, "{e}"), } } fn tcp_listen_inner(listener: TcpListener) -> Value { let listener = RefCell::new(listener); - let func = move |_: &mut Vm, _: Vec| { - match listener.borrow_mut().accept() { - Ok((stream, addr)) => match BufFile::from_raw_fd(stream.into_raw_fd(), true) { - Ok(bf) => Ok(vec![ - ValueFile::from(bf).into(), - LString::from(addr.to_string()).into() - ].into()), - Err(e) => throw!(*SYM_IO_ERROR, "{e}"), - } + let func = move |_: &mut Vm, _: Vec| match listener.borrow_mut().accept() { + Ok((stream, addr)) => match BufFile::from_raw_fd(stream.into_raw_fd(), true) { + Ok(bf) => Ok(vec![ + ValueFile::from(bf).into(), + LString::from(addr.to_string()).into(), + ] + .into()), Err(e) => throw!(*SYM_IO_ERROR, "{e}"), - } + }, + Err(e) => throw!(*SYM_IO_ERROR, "{e}"), }; NativeFunc::new(Box::new(func), 0, symbol!("inner[tcp_listen]")).into() } @@ -468,14 +517,12 @@ pub fn tcp_listen(_: &mut Vm, args: Vec) -> Result { }; match TcpListener::bind(addr) { Ok(listener) => { - let addr = listener.local_addr() + let addr = listener + .local_addr() .map(|a| LString::from(a.to_string()).into()) .unwrap_or(Value::Nil); - Ok(vec![ - tcp_listen_inner(listener), - addr, - ].into()) - }, + Ok(vec![tcp_listen_inner(listener), addr].into()) + } Err(e) => throw!(*SYM_IO_ERROR, "{e}"), } } @@ -499,24 +546,32 @@ fn spawn_opt_stdio( let f: &ValueFile = opt.downcast_native().unwrap(); let bf = match f.0.borrow().try_clone() { Ok(bf) => bf, - Err(e) => throw!(*SYM_IO_ERROR, "{e}") + Err(e) => throw!(*SYM_IO_ERROR, "{e}"), }; let fd = match bf.try_into_raw_fd() { Ok(fd) => fd, - Err(e) => throw!(*SYM_IO_ERROR, "{e}") + Err(e) => throw!(*SYM_IO_ERROR, "{e}"), }; let stdio = unsafe { Stdio::from_raw_fd(fd) }; func(proc, stdio) - }, - _ => throw!(*SYM_VALUE_ERROR, "{fname} stdio option expected :inherit, :piped, :null, or file, got {opt:#}") + } + _ => throw!( + *SYM_VALUE_ERROR, + "{fname} stdio option expected :inherit, :piped, :null, or file, got {opt:#}" + ), }; Ok(()) } fn spawn_opt_cd(fname: &str, proc: &mut Command, cd: &Value) -> Result<()> { - if let Value::Nil = cd { return Ok(()) } + if let Value::Nil = cd { + return Ok(()) + } let Value::String(cd) = cd else { - throw!(*SYM_TYPE_ERROR, "{fname} cd option expected string, got {cd:#}") + throw!( + *SYM_TYPE_ERROR, + "{fname} cd option expected string, got {cd:#}" + ) }; proc.current_dir(cd.to_os_str()); Ok(()) @@ -527,16 +582,22 @@ fn spawn_opt_delenv(fname: &str, proc: &mut Command, delenv: &Value) -> Result<( Value::Nil => (), Value::Symbol(s) if *s == *SYM_ALL => { proc.env_clear(); - }, - Value::List(l) => for e in l.borrow().iter() { - let Value::String(e) = e else { - throw!(*SYM_TYPE_ERROR, - "{fname} delenv option expected :all or list of strings, got {delenv:#}") - }; - proc.env_remove(e.to_os_str()); - }, - _ => throw!(*SYM_VALUE_ERROR, - "{fname} delenv option expected :all or list of strings, got {delenv:#}") + } + Value::List(l) => { + for e in l.borrow().iter() { + let Value::String(e) = e else { + throw!( + *SYM_TYPE_ERROR, + "{fname} delenv option expected :all or list of strings, got {delenv:#}" + ) + }; + proc.env_remove(e.to_os_str()); + } + } + _ => throw!( + *SYM_VALUE_ERROR, + "{fname} delenv option expected :all or list of strings, got {delenv:#}" + ), } Ok(()) } @@ -544,15 +605,21 @@ fn spawn_opt_delenv(fname: &str, proc: &mut Command, delenv: &Value) -> Result<( fn spawn_opt_env(fname: &str, proc: &mut Command, env: &Value) -> Result<()> { match env { Value::Nil => (), - Value::Table(t) => for (k, v) in t.borrow().iter() { - let Value::String(k) = k.inner() else { - throw!(*SYM_TYPE_ERROR, - "{fname} env option expected table with string keys, got {env:#}") - }; - proc.env(k.to_os_str(), v.str().to_os_str()); - }, - _ => throw!(*SYM_TYPE_ERROR, - "{fname} env option expected table with string keys, got {env:#}") + Value::Table(t) => { + for (k, v) in t.borrow().iter() { + let Value::String(k) = k.inner() else { + throw!( + *SYM_TYPE_ERROR, + "{fname} env option expected table with string keys, got {env:#}" + ) + }; + proc.env(k.to_os_str(), v.str().to_os_str()); + } + } + _ => throw!( + *SYM_TYPE_ERROR, + "{fname} env option expected table with string keys, got {env:#}" + ), } Ok(()) } @@ -560,7 +627,10 @@ fn spawn_opt_env(fname: &str, proc: &mut Command, env: &Value) -> Result<()> { fn spawn_inner(fname: &str, proc: &mut Command, opts: Value) -> Result { let (i, o, e) = match opts { Value::Native(ref n) if n.get_type() == *SYM_STD_FILE => { - throw!(*SYM_TYPE_ERROR, "{fname} options expected :inherit, :piped, :null, or table, got {opts:#}") + throw!( + *SYM_TYPE_ERROR, + "{fname} options expected :inherit, :piped, :null, or table, got {opts:#}" + ) } Value::Table(t) => { let t = t.borrow(); @@ -577,17 +647,20 @@ fn spawn_inner(fname: &str, proc: &mut Command, opts: Value) -> Result { spawn_opt_env(fname, proc, env)?; } - let i = t.get(&HashValue::from(*SYM_STDIN)) + let i = t + .get(&HashValue::from(*SYM_STDIN)) .cloned() .unwrap_or_else(|| Value::from(*SYM_INHERIT)); - let o = t.get(&HashValue::from(*SYM_STDOUT)) + let o = t + .get(&HashValue::from(*SYM_STDOUT)) .cloned() .unwrap_or_else(|| Value::from(*SYM_INHERIT)); - let e = t.get(&HashValue::from(*SYM_STDERR)) + let e = t + .get(&HashValue::from(*SYM_STDERR)) .cloned() .unwrap_or_else(|| Value::from(*SYM_INHERIT)); (i, o, e) - }, + } v => (v.clone(), v.clone(), v), }; @@ -621,7 +694,10 @@ fn spawn_inner(fname: &str, proc: &mut Command, opts: Value) -> Result { }; table.insert(HashValue::from(*SYM_STDERR), ValueFile::from(bf).into()); } - table.insert(HashValue::from(*SYM_PROCESS), ValueProcess::from(child).into()); + table.insert( + HashValue::from(*SYM_PROCESS), + ValueProcess::from(child).into(), + ); Ok(table.into()) } @@ -632,12 +708,18 @@ pub fn spawn(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_TYPE_ERROR, "spawn expected string, got {cmd:#}") }; let Value::List(args) = args else { - throw!(*SYM_TYPE_ERROR, "spawn expected list of strings, got {args:#}") + throw!( + *SYM_TYPE_ERROR, + "spawn expected list of strings, got {args:#}" + ) }; let mut proc = Command::new(cmd.to_os_str()); for arg in args.borrow().iter() { let Value::String(arg) = arg else { - throw!(*SYM_TYPE_ERROR, "spawn expected list of strings, got list containing {arg:#}") + throw!( + *SYM_TYPE_ERROR, + "spawn expected list of strings, got list containing {arg:#}" + ) }; proc.arg(arg.to_os_str()); } @@ -653,12 +735,10 @@ pub fn system(_: &mut Vm, args: Vec) -> Result { let mut proc; if cfg!(target_os = "windows") { proc = Command::new("cmd"); - proc.arg("/C") - .arg(cmd.to_os_str()) + proc.arg("/C").arg(cmd.to_os_str()) } else { proc = Command::new("sh"); - proc.arg("-c") - .arg(cmd.to_os_str()) + proc.arg("-c").arg(cmd.to_os_str()) }; spawn_inner("system", &mut proc, opts) } @@ -671,11 +751,10 @@ pub fn exit_code(_: &mut Vm, args: Vec) -> Result { }; let mut proc = proc.0.borrow_mut(); match proc.wait() { - Ok(code) => { - Ok(code.code() - .map(|c| Value::Int(c as i64)) - .unwrap_or_default()) - }, + Ok(code) => Ok(code + .code() + .map(|c| Value::Int(c as i64)) + .unwrap_or_default()), Err(e) => throw!(*SYM_IO_ERROR, "{e}"), } } @@ -689,4 +768,3 @@ pub fn process_id(_: &mut Vm, args: Vec) -> Result { let proc = proc.0.borrow(); Ok((proc.id() as i64).into()) } - diff --git a/talc-std/src/format.rs b/talc-std/src/format.rs index 83687b6..91f7436 100644 --- a/talc-std/src/format.rs +++ b/talc-std/src/format.rs @@ -1,414 +1,477 @@ use std::io::Write; -use talc_lang::{exception::{exception, Result}, lstring::{LStr, LString}, parser::{parse_int, to_lstring_radix}, symbol::SYM_TYPE_ERROR, throw, value::{Complex64, Rational64, Value}, Vm}; +use talc_lang::{ + exception::{exception, Result}, + lstring::{LStr, LString}, + parser::{parse_int, to_lstring_radix}, + symbol::SYM_TYPE_ERROR, + throw, + value::{Complex64, Rational64, Value}, + Vm, +}; use talc_macros::native_func; use crate::{unpack_args, SYM_FORMAT_ERROR}; #[derive(Clone, Copy, Debug)] enum FmtIndex { - Imm(usize), - Arg(usize), - NextArg, + Imm(usize), + Arg(usize), + NextArg, } #[derive(Clone, Copy, Debug)] enum Align { - Left, - Center, - Right, + Left, + Center, + Right, } #[derive(Clone, Copy, Debug, Default)] enum FmtType { - #[default] - Str, - Repr, - Hex(bool), - Oct, - Sex, - Bin, - Exp(bool), + #[default] + Str, + Repr, + Hex(bool), + Oct, + Sex, + Bin, + Exp(bool), } #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] enum FmtSign { - Plus, - Minus, - #[default] - None + Plus, + Minus, + #[default] + None, } // [idx][:[align][sign][width][.prec][ty]] #[derive(Clone, Copy, Debug, Default)] struct FmtCode { - arg_idx: Option, - align: Option<(Align, char)>, - sign: FmtSign, - width: Option, - prec: Option, - ty: FmtType, + arg_idx: Option, + align: Option<(Align, char)>, + sign: FmtSign, + width: Option, + prec: Option, + ty: FmtType, } struct FmtParser<'p> { - code: &'p LStr, - pos: usize, + code: &'p LStr, + pos: usize, } impl<'p> FmtParser<'p> { - fn new(code: &'p LStr) -> Self { - Self { - code, - pos: 0 - } - } + fn new(code: &'p LStr) -> Self { + Self { code, pos: 0 } + } - fn next(&mut self) -> Option { - let c = &self.code[self.pos..].chars().next()?; - self.pos += c.len_utf8(); - Some(*c) - } + fn next(&mut self) -> Option { + let c = &self.code[self.pos..].chars().next()?; + self.pos += c.len_utf8(); + Some(*c) + } - fn peek(&mut self) -> Option { - self.code[self.pos..].chars().next() - } + fn peek(&mut self) -> Option { + self.code[self.pos..].chars().next() + } - fn try_next(&mut self, chs: &[char]) -> Option { - if self.peek().is_some_and(|c| chs.contains(&c)) { - self.next() - } else { - None - } - } + fn try_next(&mut self, chs: &[char]) -> Option { + if self.peek().is_some_and(|c| chs.contains(&c)) { + self.next() + } else { + None + } + } - fn next_number_str(&mut self) -> &LStr { - let start = self.pos; - while matches!(self.peek(), Some('0'..='9' | '_')) { - self.next(); - } - &self.code[start..self.pos] - } + fn next_number_str(&mut self) -> &LStr { + let start = self.pos; + while matches!(self.peek(), Some('0'..='9' | '_')) { + self.next(); + } + &self.code[start..self.pos] + } - fn next_usize(&mut self) -> Result> { - let s = self.next_number_str(); - if s.is_empty() { return Ok(None) } - let Ok(i) = parse_int(s, 10) else { - throw!(*SYM_FORMAT_ERROR, - "code {{{}}}: invalid integer", self.code) - }; - if i < 0 { - throw!(*SYM_FORMAT_ERROR, - "code {{{}}}: integer may not be negative", self.code) - } - Ok(Some(i as usize)) - } + fn next_usize(&mut self) -> Result> { + let s = self.next_number_str(); + if s.is_empty() { + return Ok(None) + } + let Ok(i) = parse_int(s, 10) else { + throw!(*SYM_FORMAT_ERROR, "code {{{}}}: invalid integer", self.code) + }; + if i < 0 { + throw!( + *SYM_FORMAT_ERROR, + "code {{{}}}: integer may not be negative", + self.code + ) + } + Ok(Some(i as usize)) + } - fn next_fmt_index(&mut self) -> Result> { - let dollar = self.try_next(&['$']).is_some(); - let num = self.next_usize()?; - match (dollar, num) { - (true, None) => Ok(Some(FmtIndex::NextArg)), - (true, Some(n)) => Ok(Some(FmtIndex::Arg(n))), - (false, None) => Ok(None), - (false, Some(n)) => Ok(Some(FmtIndex::Imm(n))), - } - } + fn next_fmt_index(&mut self) -> Result> { + let dollar = self.try_next(&['$']).is_some(); + let num = self.next_usize()?; + match (dollar, num) { + (true, None) => Ok(Some(FmtIndex::NextArg)), + (true, Some(n)) => Ok(Some(FmtIndex::Arg(n))), + (false, None) => Ok(None), + (false, Some(n)) => Ok(Some(FmtIndex::Imm(n))), + } + } - fn next_align(&mut self) -> Result> { - let align = match self.peek() { - Some('<') => Align::Left, - Some('^') => Align::Center, - Some('>') => Align::Right, - _ => return Ok(None), - }; - self.next(); - let Some(c) = self.next() else { - throw!(*SYM_FORMAT_ERROR, - "code {{{}}}: alignment without fill character", self.code) - }; - Ok(Some((align, c))) - } + fn next_align(&mut self) -> Result> { + let align = match self.peek() { + Some('<') => Align::Left, + Some('^') => Align::Center, + Some('>') => Align::Right, + _ => return Ok(None), + }; + self.next(); + let Some(c) = self.next() else { + throw!( + *SYM_FORMAT_ERROR, + "code {{{}}}: alignment without fill character", + self.code + ) + }; + Ok(Some((align, c))) + } - fn next_sign(&mut self) -> FmtSign { - match self.try_next(&['+', '-']) { - Some('+') => FmtSign::Plus, - Some('-') => FmtSign::Minus, - _ => FmtSign::None, - } - } + fn next_sign(&mut self) -> FmtSign { + match self.try_next(&['+', '-']) { + Some('+') => FmtSign::Plus, + Some('-') => FmtSign::Minus, + _ => FmtSign::None, + } + } - fn next_type(&mut self) -> Result { - let ty = match self.peek() { - None => return Ok(FmtType::Str), - Some('?') => FmtType::Repr, - Some('x') => FmtType::Hex(false), - Some('X') => FmtType::Hex(true), - Some('o') => FmtType::Oct, - Some('s') => FmtType::Sex, - Some('b') => FmtType::Bin, - Some('e') => FmtType::Exp(false), - Some('E') => FmtType::Exp(true), - _ => throw!(*SYM_FORMAT_ERROR, - "code {{{}}}: invalid format type", self.code), - }; - self.next(); - Ok(ty) - } + fn next_type(&mut self) -> Result { + let ty = match self.peek() { + None => return Ok(FmtType::Str), + Some('?') => FmtType::Repr, + Some('x') => FmtType::Hex(false), + Some('X') => FmtType::Hex(true), + Some('o') => FmtType::Oct, + Some('s') => FmtType::Sex, + Some('b') => FmtType::Bin, + Some('e') => FmtType::Exp(false), + Some('E') => FmtType::Exp(true), + _ => throw!( + *SYM_FORMAT_ERROR, + "code {{{}}}: invalid format type", + self.code + ), + }; + self.next(); + Ok(ty) + } - fn next_code_end(&mut self) -> Result<()> { - match self.peek() { - Some(c) => throw!(*SYM_FORMAT_ERROR, - "code {{{}}}: expected end of code, found character '{}'", self.code, c), - None => Ok(()) - } - } + fn next_code_end(&mut self) -> Result<()> { + match self.peek() { + Some(c) => throw!( + *SYM_FORMAT_ERROR, + "code {{{}}}: expected end of code, found character '{}'", + self.code, + c + ), + None => Ok(()), + } + } - fn read_format(&mut self) -> Result { - let mut code = FmtCode { - arg_idx: self.next_usize()?, - ..FmtCode::default() - }; - if self.try_next(&[':']).is_none() { - self.next_code_end()?; - return Ok(code) - } - code.align = self.next_align()?; - code.sign = self.next_sign(); - code.width = self.next_fmt_index()?; - if self.try_next(&['.']).is_some() { - code.prec = self.next_fmt_index()?; - } - code.ty = self.next_type()?; - self.next_code_end()?; - Ok(code) - } + fn read_format(&mut self) -> Result { + let mut code = FmtCode { + arg_idx: self.next_usize()?, + ..FmtCode::default() + }; + if self.try_next(&[':']).is_none() { + self.next_code_end()?; + return Ok(code) + } + code.align = self.next_align()?; + code.sign = self.next_sign(); + code.width = self.next_fmt_index()?; + if self.try_next(&['.']).is_some() { + code.prec = self.next_fmt_index()?; + } + code.ty = self.next_type()?; + self.next_code_end()?; + Ok(code) + } } -fn get_arg<'a>(args: &'a [Value], n: Option, faidx: &mut usize) --> Result<&'a Value> { - let i = match n { - Some(n) => n, - None => { - let i = *faidx; - *faidx += 1; - i - } - }; - if i >= args.len() { - throw!(*SYM_FORMAT_ERROR, "missing arguments: expected at least {}", i+1) - } - Ok(&args[i]) +fn get_arg<'a>(args: &'a [Value], n: Option, faidx: &mut usize) -> Result<&'a Value> { + let i = match n { + Some(n) => n, + None => { + let i = *faidx; + *faidx += 1; + i + } + }; + if i >= args.len() { + throw!( + *SYM_FORMAT_ERROR, + "missing arguments: expected at least {}", + i + 1 + ) + } + Ok(&args[i]) } fn get_val(args: &[Value], i: FmtIndex, faidx: &mut usize) -> Result { - let v = match i { - FmtIndex::Imm(n) => return Ok(n), - FmtIndex::Arg(n) => get_arg(args, Some(n), faidx)?, - FmtIndex::NextArg => get_arg(args, None, faidx)?, - }; - let Value::Int(v) = v else { - throw!(*SYM_FORMAT_ERROR, "expected positive integer argument, found {v:#}") - }; - if *v < 0 { - throw!(*SYM_FORMAT_ERROR, "expected positive integer argument, found {v}") - } - Ok(*v as usize) + let v = match i { + FmtIndex::Imm(n) => return Ok(n), + FmtIndex::Arg(n) => get_arg(args, Some(n), faidx)?, + FmtIndex::NextArg => get_arg(args, None, faidx)?, + }; + let Value::Int(v) = v else { + throw!( + *SYM_FORMAT_ERROR, + "expected positive integer argument, found {v:#}" + ) + }; + if *v < 0 { + throw!( + *SYM_FORMAT_ERROR, + "expected positive integer argument, found {v}" + ) + } + Ok(*v as usize) } -fn format_float(f: f64, prec: Option, ty: FmtType, buf: &mut LString, ty_name: &str) -> Result<()> { - let res = match (prec, ty) { - (None, FmtType::Str) => write!(buf, "{}", Value::Float(f)), - (None, FmtType::Repr) => write!(buf, "{:#}", Value::Float(f)), - (None, FmtType::Exp(true)) => write!(buf, "{:E}", f), - (None, FmtType::Exp(false)) => write!(buf, "{:e}", f), - (Some(p), FmtType::Str) - | (Some(p), FmtType::Repr) => write!(buf, "{0:.1$}", f, p), - (Some(p), FmtType::Exp(true)) => write!(buf, "{0:.1$E}", f, p), - (Some(p), FmtType::Exp(false)) => write!(buf, "{0:.1$e}", f, p), - _ => throw!(*SYM_FORMAT_ERROR, "invalid format specifier for {ty_name}") - }; - res.map_err(|e| exception!(*SYM_FORMAT_ERROR, "{e}")) +fn format_float( + f: f64, + prec: Option, + ty: FmtType, + buf: &mut LString, + ty_name: &str, +) -> Result<()> { + let res = match (prec, ty) { + (None, FmtType::Str) => write!(buf, "{}", Value::Float(f)), + (None, FmtType::Repr) => write!(buf, "{:#}", Value::Float(f)), + (None, FmtType::Exp(true)) => write!(buf, "{:E}", f), + (None, FmtType::Exp(false)) => write!(buf, "{:e}", f), + (Some(p), FmtType::Str) | (Some(p), FmtType::Repr) => write!(buf, "{0:.1$}", f, p), + (Some(p), FmtType::Exp(true)) => write!(buf, "{0:.1$E}", f, p), + (Some(p), FmtType::Exp(false)) => write!(buf, "{0:.1$e}", f, p), + _ => throw!(*SYM_FORMAT_ERROR, "invalid format specifier for {ty_name}"), + }; + res.map_err(|e| exception!(*SYM_FORMAT_ERROR, "{e}")) } -fn format_complex(cx: Complex64, prec: Option, ty: FmtType, buf: &mut LString) -> Result<()> { - format_float(cx.re, prec, ty, buf, "complex")?; - if cx.im < 0.0 { - buf.push_char('-') - } else { - buf.push_char('+') - } - format_float(cx.im.abs(), prec, ty, buf, "complex")?; - Ok(()) +fn format_complex( + cx: Complex64, + prec: Option, + ty: FmtType, + buf: &mut LString, +) -> Result<()> { + format_float(cx.re, prec, ty, buf, "complex")?; + if cx.im < 0.0 { + buf.push_char('-') + } else { + buf.push_char('+') + } + format_float(cx.im.abs(), prec, ty, buf, "complex")?; + Ok(()) } -fn format_int(n: i64, prec: Option, ty: FmtType, buf: &mut LString, ty_name: &str) -> Result<()> { - if prec.is_some() { - throw!(*SYM_FORMAT_ERROR, "invalid format specifier for {ty_name}") - } - let res = match ty { - FmtType::Str => write!(buf, "{}", Value::Int(n)), - FmtType::Repr => write!(buf, "{:#}", Value::Int(n)), - FmtType::Hex(caps) => write!(buf, "{}", to_lstring_radix(n, 16, caps)), - FmtType::Oct => write!(buf, "{}", to_lstring_radix(n, 8, false)), - FmtType::Sex => write!(buf, "{}", to_lstring_radix(n, 6, false)), - FmtType::Bin => write!(buf, "{}", to_lstring_radix(n, 2, false)), - _ => throw!(*SYM_FORMAT_ERROR, "invalid format specifier for {ty_name}") - }; - res.map_err(|e| exception!(*SYM_FORMAT_ERROR, "{e}")) +fn format_int( + n: i64, + prec: Option, + ty: FmtType, + buf: &mut LString, + ty_name: &str, +) -> Result<()> { + if prec.is_some() { + throw!(*SYM_FORMAT_ERROR, "invalid format specifier for {ty_name}") + } + let res = match ty { + FmtType::Str => write!(buf, "{}", Value::Int(n)), + FmtType::Repr => write!(buf, "{:#}", Value::Int(n)), + FmtType::Hex(caps) => write!(buf, "{}", to_lstring_radix(n, 16, caps)), + FmtType::Oct => write!(buf, "{}", to_lstring_radix(n, 8, false)), + FmtType::Sex => write!(buf, "{}", to_lstring_radix(n, 6, false)), + FmtType::Bin => write!(buf, "{}", to_lstring_radix(n, 2, false)), + _ => throw!(*SYM_FORMAT_ERROR, "invalid format specifier for {ty_name}"), + }; + res.map_err(|e| exception!(*SYM_FORMAT_ERROR, "{e}")) } fn format_ratio(n: Rational64, prec: Option, ty: FmtType, buf: &mut LString) -> Result<()> { - format_int(*n.numer(), prec, ty, buf, "ratio")?; - buf.push_char('/'); - format_int(*n.denom(), prec, ty, buf, "ratio")?; - Ok(()) + format_int(*n.numer(), prec, ty, buf, "ratio")?; + buf.push_char('/'); + format_int(*n.denom(), prec, ty, buf, "ratio")?; + Ok(()) } fn format_value(v: &Value, prec: Option, ty: FmtType, buf: &mut LString) -> Result<()> { - if prec.is_some() { - throw!(*SYM_FORMAT_ERROR, "invalid format specifier for value") - } - let res = match ty { - FmtType::Str => write!(buf, "{}", v), - FmtType::Repr => write!(buf, "{:#}", v), - _ => throw!(*SYM_FORMAT_ERROR, "invalid format specifier for value") - }; - res.map_err(|e| exception!(*SYM_FORMAT_ERROR, "{e}")) + if prec.is_some() { + throw!(*SYM_FORMAT_ERROR, "invalid format specifier for value") + } + let res = match ty { + FmtType::Str => write!(buf, "{}", v), + FmtType::Repr => write!(buf, "{:#}", v), + _ => throw!(*SYM_FORMAT_ERROR, "invalid format specifier for value"), + }; + res.map_err(|e| exception!(*SYM_FORMAT_ERROR, "{e}")) } fn format_string(mut s: &LStr, prec: Option, ty: FmtType, buf: &mut LString) -> Result<()> { - if let Some(prec) = prec { - s = &s[..prec] - } - let res = match ty { - FmtType::Str => { buf.push_lstr(s); Ok(()) }, - FmtType::Repr => write!(buf, "{:?}", s), - _ => throw!(*SYM_FORMAT_ERROR, "invalid format specifier for string") - }; - res.map_err(|e| exception!(*SYM_FORMAT_ERROR, "{e}")) + if let Some(prec) = prec { + s = &s[..prec] + } + let res = match ty { + FmtType::Str => { + buf.push_lstr(s); + Ok(()) + } + FmtType::Repr => write!(buf, "{:?}", s), + _ => throw!(*SYM_FORMAT_ERROR, "invalid format specifier for string"), + }; + res.map_err(|e| exception!(*SYM_FORMAT_ERROR, "{e}")) } fn pad_str(n: usize, c: char, buf: &mut LString) { - for _ in 0..n { - buf.push_char(c) - } + for _ in 0..n { + buf.push_char(c) + } } -fn format_arg(args: &[Value], faidx: &mut usize, code: &LStr, res: &mut LString) --> Result<()> { - if !code.is_utf8() { - throw!(*SYM_FORMAT_ERROR, "code {{{}}}: code contains invalid UTF-8", code) - } - let fmtcode = FmtParser::new(code).read_format()?; +fn format_arg(args: &[Value], faidx: &mut usize, code: &LStr, res: &mut LString) -> Result<()> { + if !code.is_utf8() { + throw!( + *SYM_FORMAT_ERROR, + "code {{{}}}: code contains invalid UTF-8", + code + ) + } + let fmtcode = FmtParser::new(code).read_format()?; - let mut buf = LString::new(); - let fmt_arg = get_arg(args, fmtcode.arg_idx, faidx)?; - let prec_val = fmtcode.prec.map(|i| get_val(args, i, faidx)).transpose()?; - let width_val = fmtcode.width.map(|i| get_val(args, i, faidx)).transpose()?; + let mut buf = LString::new(); + let fmt_arg = get_arg(args, fmtcode.arg_idx, faidx)?; + let prec_val = fmtcode.prec.map(|i| get_val(args, i, faidx)).transpose()?; + let width_val = fmtcode.width.map(|i| get_val(args, i, faidx)).transpose()?; - match fmt_arg { - Value::Int(n) => format_int(*n, prec_val, fmtcode.ty, &mut buf, "integer")?, - Value::Ratio(n) => format_ratio(*n, prec_val, fmtcode.ty, &mut buf)?, - Value::Float(f) => format_float(*f, prec_val, fmtcode.ty, &mut buf, "float")?, - Value::Complex(n) => format_complex(*n, prec_val, fmtcode.ty, &mut buf)?, - Value::String(s) => format_string(s, prec_val, fmtcode.ty, &mut buf)?, - v => format_value(v, prec_val, fmtcode.ty, &mut buf)?, - } + match fmt_arg { + Value::Int(n) => format_int(*n, prec_val, fmtcode.ty, &mut buf, "integer")?, + Value::Ratio(n) => format_ratio(*n, prec_val, fmtcode.ty, &mut buf)?, + Value::Float(f) => format_float(*f, prec_val, fmtcode.ty, &mut buf, "float")?, + Value::Complex(n) => format_complex(*n, prec_val, fmtcode.ty, &mut buf)?, + Value::String(s) => format_string(s, prec_val, fmtcode.ty, &mut buf)?, + v => format_value(v, prec_val, fmtcode.ty, &mut buf)?, + } - let (sign, final_buf) = match fmtcode.sign { - FmtSign::Plus => match buf.byte_get(0) { - Some(b'+') => ("+", &buf[1..]), - Some(b'-') => ("-", &buf[1..]), - _ => ("+", &buf[..]), - } - FmtSign::Minus => match buf.byte_get(0) { - Some(b'-') => ("-", &buf[1..]), - _ => ("", &buf[..]), - } - FmtSign::None => ("", &buf[..]) - }; - res.push_str(sign); + let (sign, final_buf) = match fmtcode.sign { + FmtSign::Plus => match buf.byte_get(0) { + Some(b'+') => ("+", &buf[1..]), + Some(b'-') => ("-", &buf[1..]), + _ => ("+", &buf[..]), + }, + FmtSign::Minus => match buf.byte_get(0) { + Some(b'-') => ("-", &buf[1..]), + _ => ("", &buf[..]), + }, + FmtSign::None => ("", &buf[..]), + }; + res.push_str(sign); + if let Some(w) = width_val { + let w = w.saturating_sub(final_buf.len() + sign.len()); + match fmtcode.align { + Some((Align::Left, c)) => { + res.push_lstr(final_buf); + pad_str(w, c, res); + } + Some((Align::Center, c)) => { + pad_str((w + 1) / 2, c, res); + res.push_lstr(final_buf); + pad_str(w / 2, c, res); + } + Some((Align::Right, c)) => { + pad_str(w, c, res); + res.push_lstr(final_buf); + } + None => { + let c = if matches!( + fmt_arg, + Value::Int(_) | Value::Float(_) | Value::Ratio(_) | Value::Complex(_) + ) && fmtcode.sign != FmtSign::None + { + '0' + } else { + ' ' + }; + pad_str(w, c, res); + res.push_lstr(final_buf); + } + } + } else { + res.push_lstr(final_buf); + } - if let Some(w) = width_val { - let w = w.saturating_sub(final_buf.len() + sign.len()); - match fmtcode.align { - Some((Align::Left, c)) => { - res.push_lstr(final_buf); - pad_str(w, c, res); - } - Some((Align::Center, c)) => { - pad_str((w+1)/2, c, res); - res.push_lstr(final_buf); - pad_str(w/2, c, res); - } - Some((Align::Right, c)) => { - pad_str(w, c, res); - res.push_lstr(final_buf); - } - None => { - let c = if matches!(fmt_arg, - Value::Int(_) - | Value::Float(_) - | Value::Ratio(_) - | Value::Complex(_) - ) && fmtcode.sign != FmtSign::None { - '0' - } else { - ' ' - }; - pad_str(w, c, res); - res.push_lstr(final_buf); - } - } - } else { - res.push_lstr(final_buf); - } - - Ok(()) + Ok(()) } #[native_func(2, "fmt")] pub fn fmt_(_: &mut Vm, args: Vec) -> Result { let [_, fstr, fargs] = unpack_args!(args); let (Value::String(fstr), Value::List(fargs)) = (&fstr, &fargs) else { - throw!(*SYM_TYPE_ERROR, "format expected string and list, got {fstr:#} and {fargs:#}") + throw!( + *SYM_TYPE_ERROR, + "format expected string and list, got {fstr:#} and {fargs:#}" + ) }; let mut res = LString::new(); let mut faidx = 0; - let mut i = 0; - while i < fstr.len() { - let b = fstr.byte_at(i); - i += 1; - if b == b'}' { - let Some(b'}') = fstr.byte_get(i) else { - throw!(*SYM_FORMAT_ERROR, "unmatched closing brace at byte {}", i-1) - }; - i += 1; - res.push_byte(b); - } + let mut i = 0; + while i < fstr.len() { + let b = fstr.byte_at(i); + i += 1; + if b == b'}' { + let Some(b'}') = fstr.byte_get(i) else { + throw!( + *SYM_FORMAT_ERROR, + "unmatched closing brace at byte {}", + i - 1 + ) + }; + i += 1; + res.push_byte(b); + } if b != b'{' { res.push_byte(b); - continue - } - if i >= fstr.len() { - throw!(*SYM_FORMAT_ERROR, "unclosed format specifier at byte {}", i-1) - } - if let Some(b'{') = fstr.byte_get(i) { - i += 1; - res.push_byte(b); - continue - } - let start = i; - while i < fstr.len() && fstr.byte_at(i) != b'}' { - i += 1; - } - if i == fstr.len() { - throw!(*SYM_FORMAT_ERROR, "unclosed format specifier at byte {}", start-1) - } - let code = &fstr[start..i]; - i += 1; - format_arg(&fargs.borrow(), &mut faidx, code, &mut res)?; + continue + } + if i >= fstr.len() { + throw!( + *SYM_FORMAT_ERROR, + "unclosed format specifier at byte {}", + i - 1 + ) + } + if let Some(b'{') = fstr.byte_get(i) { + i += 1; + res.push_byte(b); + continue + } + let start = i; + while i < fstr.len() && fstr.byte_at(i) != b'}' { + i += 1; + } + if i == fstr.len() { + throw!( + *SYM_FORMAT_ERROR, + "unclosed format specifier at byte {}", + start - 1 + ) + } + let code = &fstr[start..i]; + i += 1; + format_arg(&fargs.borrow(), &mut faidx, code, &mut res)?; } Ok(res.into()) } @@ -416,4 +479,3 @@ pub fn fmt_(_: &mut Vm, args: Vec) -> Result { pub fn load(vm: &mut Vm) { vm.set_global_name("fmt", fmt_().into()); } - diff --git a/talc-std/src/io.rs b/talc-std/src/io.rs index b303a1c..5876930 100644 --- a/talc-std/src/io.rs +++ b/talc-std/src/io.rs @@ -1,6 +1,17 @@ -use std::{io::{BufRead, Write}, os::unix::ffi::OsStrExt, sync::Mutex, time::{SystemTime, UNIX_EPOCH}}; +use std::{ + io::{BufRead, Write}, + os::unix::ffi::OsStrExt, + sync::Mutex, + time::{SystemTime, UNIX_EPOCH}, +}; -use talc_lang::{exception::{throw, Result}, lstring::LString, symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, value::Value, vmcall, Vm}; +use talc_lang::{ + exception::{throw, Result}, + lstring::LString, + symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, + value::Value, + vmcall, Vm, +}; use talc_macros::native_func; use crate::{unpack_args, SYM_IO_ERROR}; @@ -45,14 +56,22 @@ pub fn readln(_: &mut Vm, _: Vec) -> Result { #[native_func(0)] pub fn time(_: &mut Vm, _: Vec) -> Result { - let time = SystemTime::now().duration_since(UNIX_EPOCH).expect("time went backwards"); + let time = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("time went backwards"); Ok(time.as_secs_f64().into()) } #[native_func(0)] pub fn time_ns(_: &mut Vm, _: Vec) -> Result { - 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()) + 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()) } #[native_func(1)] @@ -72,7 +91,10 @@ pub fn env(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_TYPE_ERROR, "env expected string, got {key:#}") }; if key.is_empty() || key.as_bytes().contains(&b'=') || key.as_bytes().contains(&0) { - throw!(*SYM_VALUE_ERROR, "environment variable must not be empty or contain an equals sign or null byte") + throw!( + *SYM_VALUE_ERROR, + "environment variable must not be empty or contain an equals sign or null byte" + ) } let val = std::env::var_os(key.to_os_str()); match val { @@ -88,19 +110,25 @@ pub fn setenv(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_TYPE_ERROR, "setenv expected string, got {key:#}") }; if key.is_empty() || key.as_bytes().contains(&b'=') || key.as_bytes().contains(&0) { - throw!(*SYM_VALUE_ERROR, "environment variable must not be empty or contain an equals sign or null byte") + throw!( + *SYM_VALUE_ERROR, + "environment variable must not be empty or contain an equals sign or null byte" + ) } let val = val.str(); if val.as_bytes().contains(&0) { - throw!(*SYM_VALUE_ERROR, "environment variable value must not contain a null byte") + throw!( + *SYM_VALUE_ERROR, + "environment variable value must not contain a null byte" + ) + } + { + let Ok(guard) = ENV_LOCK.lock() else { + throw!(*SYM_VALUE_ERROR, "failed to lock environemnt variables") + }; + unsafe { std::env::set_var(key.to_os_str(), val.to_os_str()) }; + drop(guard); } - { - let Ok(guard) = ENV_LOCK.lock() else { - throw!(*SYM_VALUE_ERROR, "failed to lock environemnt variables") - }; - unsafe { std::env::set_var(key.to_os_str(), val.to_os_str()) }; - drop(guard); - } Ok(Value::Nil) } @@ -111,19 +139,21 @@ pub fn delenv(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_TYPE_ERROR, "delenv expected string, got {key:#}") }; if key.is_empty() || key.as_bytes().contains(&b'=') || key.as_bytes().contains(&0) { - throw!(*SYM_VALUE_ERROR, "environment variable must not be empty or contain an equals sign or null byte") + throw!( + *SYM_VALUE_ERROR, + "environment variable must not be empty or contain an equals sign or null byte" + ) + } + { + let Ok(guard) = ENV_LOCK.lock() else { + throw!(*SYM_VALUE_ERROR, "failed to lock environemnt variables") + }; + unsafe { std::env::remove_var(key.to_os_str()) }; + drop(guard); } - { - let Ok(guard) = ENV_LOCK.lock() else { - throw!(*SYM_VALUE_ERROR, "failed to lock environemnt variables") - }; - unsafe { std::env::remove_var(key.to_os_str()) }; - drop(guard); - } Ok(Value::Nil) } - pub fn load(vm: &mut Vm) { vm.set_global_name("print", print().into()); vm.set_global_name("println", println().into()); diff --git a/talc-std/src/iter.rs b/talc-std/src/iter.rs index 68ed425..081a50d 100644 --- a/talc-std/src/iter.rs +++ b/talc-std/src/iter.rs @@ -1,6 +1,12 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc}; -use talc_lang::{exception::Result, symbol::{symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{function::NativeFunc, ops::RatioExt, range::RangeType, HashValue, Value}, vmcall, vmcalliter, Vm}; +use talc_lang::{ + exception::Result, + symbol::{symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, + throw, + value::{function::NativeFunc, ops::RatioExt, range::RangeType, HashValue, Value}, + vmcall, vmcalliter, Vm, +}; use talc_macros::native_func; use crate::unpack_args; @@ -95,9 +101,7 @@ pub fn once(_: &mut Vm, args: Vec) -> Result { let [_, val] = unpack_args!(args); let v = RefCell::new(Some(val)); - let f = move |_: &mut Vm, _| { - Ok(Value::iter_pack(v.borrow_mut().take())) - }; + let f = move |_: &mut Vm, _| Ok(Value::iter_pack(v.borrow_mut().take())); Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[once]")).into()) } @@ -105,9 +109,7 @@ pub fn once(_: &mut Vm, args: Vec) -> Result { pub fn forever(_: &mut Vm, args: Vec) -> Result { let [_, val] = unpack_args!(args); - let f = move |_: &mut Vm, _| { - Ok(val.clone()) - }; + let f = move |_: &mut Vm, _| Ok(val.clone()); Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[forever]")).into()) } @@ -115,18 +117,14 @@ pub fn forever(_: &mut Vm, args: Vec) -> Result { // chain iteration // - - #[native_func(2)] pub fn map(_: &mut Vm, args: Vec) -> Result { let [_, map, iter] = unpack_args!(args); let iter = iter.to_iter_function()?; - let f = move |vm: &mut Vm, _| { - match vmcalliter!(vm; iter.clone())? { - Some(val) => Ok(vmcall!(vm; map.clone(), val)?), - None => Ok(Value::iter_pack(None)), - } + let f = move |vm: &mut Vm, _| match vmcalliter!(vm; iter.clone())? { + Some(val) => Ok(vmcall!(vm; map.clone(), val)?), + None => Ok(Value::iter_pack(None)), }; Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[map]")).into()) } @@ -136,14 +134,12 @@ pub fn tee(_: &mut Vm, args: Vec) -> Result { let [_, tee, iter] = unpack_args!(args); let iter = iter.to_iter_function()?; - let f = move |vm: &mut Vm, _| { - match vmcalliter!(vm; iter.clone())? { - Some(val) => { - vmcall!(vm; tee.clone(), val.clone())?; - Ok(val) - } - None => Ok(Value::iter_pack(None)), + let f = move |vm: &mut Vm, _| match vmcalliter!(vm; iter.clone())? { + Some(val) => { + vmcall!(vm; tee.clone(), val.clone())?; + Ok(val) } + None => Ok(Value::iter_pack(None)), }; Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[tee]")).into()) } @@ -171,15 +167,13 @@ pub fn filter(_: &mut Vm, args: Vec) -> Result { let [_, filter, iter] = unpack_args!(args); let iter = iter.to_iter_function()?; - let f = move |vm: &mut Vm, _| { - loop { - let Some(next) = vmcalliter!(vm; iter.clone())? else { - return Ok(Value::iter_pack(None)) - }; - let res = vmcall!(vm; filter.clone(), next.clone())?; - if res.truthy() { - return Ok(next) - } + let f = move |vm: &mut Vm, _| loop { + let Some(next) = vmcalliter!(vm; iter.clone())? else { + return Ok(Value::iter_pack(None)) + }; + let res = vmcall!(vm; filter.clone(), next.clone())?; + if res.truthy() { + return Ok(next) } }; Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[filter]")).into()) @@ -192,7 +186,10 @@ pub fn take(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_TYPE_ERROR, "take expected integer, got {count:#}") }; let Ok(count) = count.try_into() else { - throw!(*SYM_VALUE_ERROR, "take expected nonnegative integer, got {count:#}") + throw!( + *SYM_VALUE_ERROR, + "take expected nonnegative integer, got {count:#}" + ) }; let iter = iter.to_iter_function()?; @@ -218,7 +215,10 @@ pub fn skip(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_TYPE_ERROR, "count expected integer, got {count:#}") }; let Ok(count) = count.try_into() else { - throw!(*SYM_VALUE_ERROR, "count expected nonnegative integer, got {count:#}") + throw!( + *SYM_VALUE_ERROR, + "count expected nonnegative integer, got {count:#}" + ) }; let iter = iter.to_iter_function()?; @@ -255,7 +255,6 @@ pub fn enumerate(_: &mut Vm, args: Vec) -> Result { Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[enumerate]")).into()) } - #[native_func(1)] pub fn cycle(_: &mut Vm, args: Vec) -> Result { let [_, iter] = unpack_args!(args); @@ -292,7 +291,10 @@ pub fn cycle(_: &mut Vm, args: Vec) -> Result { #[derive(Clone, Copy, Default)] enum Step { - First, Going, #[default] End, + First, + Going, + #[default] + End, } #[native_func(2)] @@ -303,7 +305,10 @@ pub fn step(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_TYPE_ERROR, "step expected integer, got {by:#}") }; if by <= 0 { - throw!(*SYM_VALUE_ERROR, "step expected positive integer, got {by:#}") + throw!( + *SYM_VALUE_ERROR, + "step expected positive integer, got {by:#}" + ) } let state = RefCell::new(Step::First); @@ -314,9 +319,9 @@ pub fn step(_: &mut Vm, args: Vec) -> Result { *state.borrow_mut() = Step::Going; } Ok(Value::iter_pack(res)) - }, + } Step::Going => { - for _ in 0..(by-1) { + for _ in 0..(by - 1) { if vmcall!(vm; iter.clone())? == Value::Nil { return Ok(Value::iter_pack(None)) } @@ -326,7 +331,7 @@ pub fn step(_: &mut Vm, args: Vec) -> Result { }; *state.borrow_mut() = Step::Going; Ok(x) - }, + } Step::End => Ok(Value::Nil), }; Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[step]")).into()) @@ -347,33 +352,30 @@ pub fn rev(_: &mut Vm, args: Vec) -> Result { *lst.borrow_mut() = Some(l); } Ok(Value::iter_pack(lst.borrow_mut().as_mut().unwrap().pop())) - }; Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[rev]")).into()) } - // // join // - #[native_func(2)] pub fn zip(_: &mut Vm, args: Vec) -> Result { let [_, i1, i2] = unpack_args!(args); - let i1 = i1.to_iter_function()?; - let i2 = i2.to_iter_function()?; + let i1 = i1.to_iter_function()?; + let i2 = i2.to_iter_function()?; let f = move |vm: &mut Vm, _| { let mut res = Vec::with_capacity(2); - match vmcalliter!(vm; i1.clone())? { - Some(v) => res.push(v), - None => return Ok(Value::iter_pack(None)), - }; - match vmcalliter!(vm; i2.clone())? { - Some(v) => res.push(v), - None => return Ok(Value::iter_pack(None)), - }; + match vmcalliter!(vm; i1.clone())? { + Some(v) => res.push(v), + None => return Ok(Value::iter_pack(None)), + }; + match vmcalliter!(vm; i2.clone())? { + Some(v) => res.push(v), + None => return Ok(Value::iter_pack(None)), + }; Ok(Value::from(res)) }; @@ -383,12 +385,14 @@ pub fn zip(_: &mut Vm, args: Vec) -> Result { #[native_func(1)] pub fn zipn(_: &mut Vm, args: Vec) -> Result { let [_, args] = unpack_args!(args); - let Value::List(args) = args else { + let Value::List(args) = args else { throw!(*SYM_TYPE_ERROR, "zipn expected list, got {args:#}") - }; - let iters = args.borrow().iter() - .map(|i| i.clone().to_iter_function()) - .collect::>>()?; + }; + let iters = args + .borrow() + .iter() + .map(|i| i.clone().to_iter_function()) + .collect::>>()?; let f = move |vm: &mut Vm, _| { let mut res = Vec::with_capacity(iters.len()); @@ -407,19 +411,19 @@ pub fn zipn(_: &mut Vm, args: Vec) -> Result { #[native_func(2)] pub fn alternate(_: &mut Vm, args: Vec) -> Result { let [_, i1, i2] = unpack_args!(args); - let i1 = i1.to_iter_function()?; - let i2 = i2.to_iter_function()?; + let i1 = i1.to_iter_function()?; + let i2 = i2.to_iter_function()?; let state = RefCell::new((false, false)); let f = move |vm: &mut Vm, _| { let mut s = state.borrow_mut(); if s.1 { - return Ok(Value::iter_pack(None)); + return Ok(Value::iter_pack(None)) } let n = s.0; s.0 = !s.0; drop(s); - let iter = if n { i1.clone() } else { i2.clone() }; + let iter = if n { i1.clone() } else { i2.clone() }; if let Some(v) = vmcalliter!(vm; iter)? { Ok(v) } else { @@ -434,18 +438,20 @@ pub fn alternate(_: &mut Vm, args: Vec) -> Result { #[native_func(1)] pub fn alternaten(_: &mut Vm, args: Vec) -> Result { let [_, args] = unpack_args!(args); - let Value::List(args) = args else { + let Value::List(args) = args else { throw!(*SYM_TYPE_ERROR, "alternaten expected list, got {args:#}") - }; - let iters = args.borrow().iter() - .map(|i| i.clone().to_iter_function()) - .collect::>>()?; + }; + let iters = args + .borrow() + .iter() + .map(|i| i.clone().to_iter_function()) + .collect::>>()?; let state = RefCell::new((0, false)); let f = move |vm: &mut Vm, _| { let mut s = state.borrow_mut(); if s.1 { - return Ok(Value::iter_pack(None)); + return Ok(Value::iter_pack(None)) } let n = s.0; s.0 = (s.0 + 1) % iters.len(); @@ -463,7 +469,11 @@ pub fn alternaten(_: &mut Vm, args: Vec) -> Result { #[derive(Default)] enum Intersperse { - Init, Waiting, HasNext(Value), #[default] End + Init, + Waiting, + HasNext(Value), + #[default] + End, } #[native_func(2)] @@ -472,38 +482,35 @@ pub fn intersperse(_: &mut Vm, args: Vec) -> Result { let iter = iter.to_iter_function()?; let state = RefCell::new(Intersperse::Init); - let f = move |vm: &mut Vm, _| { - match state.take() { - Intersperse::Init => { - if let Some(v) = vmcalliter!(vm; iter.clone())? { - *state.borrow_mut() = Intersperse::Waiting; - Ok(v) - } else { - *state.borrow_mut() = Intersperse::End; - Ok(Value::iter_pack(None)) - } - }, - Intersperse::Waiting => { - if let Some(v) = vmcalliter!(vm; iter.clone())? { - *state.borrow_mut() = Intersperse::HasNext(v); - Ok(val.clone()) - } else { - *state.borrow_mut() = Intersperse::End; - Ok(Value::iter_pack(None)) - } - }, - Intersperse::HasNext(v) => { + let f = move |vm: &mut Vm, _| match state.take() { + Intersperse::Init => { + if let Some(v) = vmcalliter!(vm; iter.clone())? { *state.borrow_mut() = Intersperse::Waiting; Ok(v) - }, - Intersperse::End => Ok(Value::iter_pack(None)), + } else { + *state.borrow_mut() = Intersperse::End; + Ok(Value::iter_pack(None)) + } } + Intersperse::Waiting => { + if let Some(v) = vmcalliter!(vm; iter.clone())? { + *state.borrow_mut() = Intersperse::HasNext(v); + Ok(val.clone()) + } else { + *state.borrow_mut() = Intersperse::End; + Ok(Value::iter_pack(None)) + } + } + Intersperse::HasNext(v) => { + *state.borrow_mut() = Intersperse::Waiting; + Ok(v) + } + Intersperse::End => Ok(Value::iter_pack(None)), }; Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[intersperse]")).into()) } - #[native_func(2)] pub fn chain(_: &mut Vm, args: Vec) -> Result { let [_, iter1, iter2] = unpack_args!(args); @@ -591,14 +598,10 @@ pub fn cartprod(_: &mut Vm, args: Vec) -> Result { Ok(NativeFunc::new(Box::new(f), 0, symbol!("iter[cart_prod]")).into()) } - - // // end iteration // - - #[native_func(1)] pub fn list(vm: &mut Vm, args: Vec) -> Result { let [_, iter] = unpack_args!(args); @@ -606,7 +609,7 @@ pub fn list(vm: &mut Vm, args: Vec) -> Result { let mut result = Vec::new(); while let Some(value) = vmcalliter!(vm; iter.clone())? { result.push(value); - }; + } Ok(result.into()) } @@ -617,16 +620,23 @@ pub fn table(vm: &mut Vm, args: Vec) -> Result { let mut result = HashMap::new(); while let Some(value) = vmcalliter!(vm; iter.clone())? { let Value::List(l) = value else { - throw!(*SYM_TYPE_ERROR, "table expected iterator to yield list, got {value:#}") + throw!( + *SYM_TYPE_ERROR, + "table expected iterator to yield list, got {value:#}" + ) }; let mut l = Rc::unwrap_or_clone(l).take(); - if l.len() != 2 { - throw!(*SYM_VALUE_ERROR, "table: iterator yielded list of length {} (expected 2)", l.len()) + if l.len() != 2 { + throw!( + *SYM_VALUE_ERROR, + "table: iterator yielded list of length {} (expected 2)", + l.len() + ) }; - let v = l.pop().unwrap(); - let k = l.pop().unwrap(); + let v = l.pop().unwrap(); + let k = l.pop().unwrap(); result.insert(k.try_into()?, v); - }; + } Ok(result.into()) } @@ -637,15 +647,16 @@ pub fn len(vm: &mut Vm, args: Vec) -> Result { 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::Range(r) if r.ty != RangeType::Endless - => return Ok((r.len().unwrap() as i64).into()), + Value::Range(r) if r.ty != RangeType::Endless => { + return Ok((r.len().unwrap() as i64).into()) + } _ => (), } let iter = value.to_iter_function()?; let mut len = 0; while vmcalliter!(vm; iter.clone())?.is_some() { len += 1; - }; + } Ok(len.into()) } @@ -764,8 +775,10 @@ pub fn contains(vm: &mut Vm, args: Vec) -> Result { for _ in 0.. { match vmcalliter!(vm; iter.clone())? { None => return Ok(Value::Nil), - Some(v) => if v == val { - return Ok(true.into()) + Some(v) => { + if v == val { + return Ok(true.into()) + } } } } @@ -780,8 +793,10 @@ pub fn index_of(vm: &mut Vm, args: Vec) -> Result { for i in 0.. { match vmcalliter!(vm; iter.clone())? { None => return Ok(Value::Nil), - Some(v) => if v == val { - return Ok(i.into()) + Some(v) => { + if v == val { + return Ok(i.into()) + } } } } @@ -796,8 +811,10 @@ pub fn index_if(vm: &mut Vm, args: Vec) -> Result { for i in 0.. { match vmcalliter!(vm; iter.clone())? { None => return Ok(Value::Nil), - Some(v) => if vmcall!(vm; func.clone(), v)?.truthy() { - return Ok(i.into()) + Some(v) => { + if vmcall!(vm; func.clone(), v)?.truthy() { + return Ok(i.into()) + } } } } @@ -844,25 +861,25 @@ pub fn mean(vm: &mut Vm, args: Vec) -> Result { let iter = iter.to_iter_function()?; let mut sum = Value::Float(0.0); - let mut count = Value::Int(0); + let mut count = Value::Int(0); while let Some(value) = vmcalliter!(vm; iter.clone())? { sum = (sum + value)?; - count = (count + Value::from(1))?; + count = (count + Value::from(1))?; } sum / count } fn variance_inner(vm: &mut Vm, iter: Value, pop: bool) -> Result { let mut m = Value::Float(0.0); - let mut s = Value::Float(0.0); - let mut k = 1; + let mut s = Value::Float(0.0); + let mut k = 1; while let Some(value) = vmcalliter!(vm; iter.clone())? { - let old_m = m.clone(); - m = (m.clone() + ((value.clone() - m.clone())?/Value::Int(k))?)?; - s = (s + ((value.clone() - m.clone())?*(value - old_m)?)?)?; - k += 1; + let old_m = m.clone(); + m = (m.clone() + ((value.clone() - m.clone())? / Value::Int(k))?)?; + s = (s + ((value.clone() - m.clone())? * (value - old_m)?)?)?; + k += 1; } - s / Value::Int(k - if pop { 1 } else { 2 }) + s / Value::Int(k - if pop { 1 } else { 2 }) } #[native_func(1)] @@ -870,7 +887,7 @@ pub fn variance(vm: &mut Vm, args: Vec) -> Result { let [_, iter] = unpack_args!(args); let iter = iter.to_iter_function()?; - variance_inner(vm, iter, false) + variance_inner(vm, iter, false) } #[native_func(1)] @@ -878,14 +895,14 @@ pub fn stdev(vm: &mut Vm, args: Vec) -> Result { let [_, iter] = unpack_args!(args); let iter = iter.to_iter_function()?; - let v = variance_inner(vm, iter, false)?; - Ok(match v { - Value::Int(n) => Value::Float((n as f64).sqrt()), - Value::Float(f) => Value::Float(f.sqrt()), - Value::Ratio(r) => Value::Float(r.to_f64().sqrt()), - Value::Complex(c) => Value::Complex(c.sqrt()), - v => throw!(*SYM_TYPE_ERROR, "stdev: cannot square root {v:#}") - }) + let v = variance_inner(vm, iter, false)?; + Ok(match v { + Value::Int(n) => Value::Float((n as f64).sqrt()), + Value::Float(f) => Value::Float(f.sqrt()), + Value::Ratio(r) => Value::Float(r.to_f64().sqrt()), + Value::Complex(c) => Value::Complex(c.sqrt()), + v => throw!(*SYM_TYPE_ERROR, "stdev: cannot square root {v:#}"), + }) } #[native_func(1)] @@ -893,7 +910,7 @@ pub fn pvariance(vm: &mut Vm, args: Vec) -> Result { let [_, iter] = unpack_args!(args); let iter = iter.to_iter_function()?; - variance_inner(vm, iter, true) + variance_inner(vm, iter, true) } #[native_func(1)] @@ -901,14 +918,14 @@ pub fn pstdev(vm: &mut Vm, args: Vec) -> Result { let [_, iter] = unpack_args!(args); let iter = iter.to_iter_function()?; - let v = variance_inner(vm, iter, true)?; - Ok(match v { - Value::Int(n) => Value::Float((n as f64).sqrt()), - Value::Float(f) => Value::Float(f.sqrt()), - Value::Ratio(r) => Value::Float(r.to_f64().sqrt()), - Value::Complex(c) => Value::Complex(c.sqrt()), - v => throw!(*SYM_TYPE_ERROR, "stdev: cannot square root {v:#}") - }) + let v = variance_inner(vm, iter, true)?; + Ok(match v { + Value::Int(n) => Value::Float((n as f64).sqrt()), + Value::Float(f) => Value::Float(f.sqrt()), + Value::Ratio(r) => Value::Float(r.to_f64().sqrt()), + Value::Complex(c) => Value::Complex(c.sqrt()), + v => throw!(*SYM_TYPE_ERROR, "stdev: cannot square root {v:#}"), + }) } #[derive(PartialEq, PartialOrd)] @@ -917,9 +934,9 @@ impl std::cmp::Eq for OrdValue {} #[allow(clippy::derive_ord_xor_partial_ord)] impl std::cmp::Ord for OrdValue { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.partial_cmp(other).unwrap_or(std::cmp::Ordering::Less) - } + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.partial_cmp(other).unwrap_or(std::cmp::Ordering::Less) + } } #[native_func(1)] @@ -927,23 +944,22 @@ pub fn median(vm: &mut Vm, args: Vec) -> Result { let [_, iter] = unpack_args!(args); let iter = iter.to_iter_function()?; - let mut vals = Vec::new(); + let mut vals = Vec::new(); while let Some(value) = vmcalliter!(vm; iter.clone())? { - vals.push(OrdValue(value)); + vals.push(OrdValue(value)); + } + let count = vals.len(); + if count == 0 { + Ok(Value::Nil) + } else if count % 2 == 0 { + let (_, _, hi) = vals.select_nth_unstable(count / 2 - 1); + let (_, _, _) = hi.select_nth_unstable(0); + let m2 = vals.swap_remove(count / 2); + let m1 = vals.swap_remove(count / 2 - 1); + (m1.0 + m2.0)? / Value::Int(2) + } else { + let (_, _, _) = vals.select_nth_unstable(count / 2); + let m = vals.swap_remove(count / 2); + m.0 / Value::Int(1) } - let count = vals.len(); - if count == 0 { - Ok(Value::Nil) - } else if count % 2 == 0 { - let (_, _, hi) = vals.select_nth_unstable(count/2 - 1); - let (_, _, _) = hi.select_nth_unstable(0); - let m2 = vals.swap_remove(count/2); - let m1 = vals.swap_remove(count/2 - 1); - (m1.0 + m2.0)? / Value::Int(2) - } else { - let (_, _, _) = vals.select_nth_unstable(count/2); - let m = vals.swap_remove(count/2); - m.0 / Value::Int(1) - } } - diff --git a/talc-std/src/lib.rs b/talc-std/src/lib.rs index cf90b5f..1d3a8bb 100644 --- a/talc-std/src/lib.rs +++ b/talc-std/src/lib.rs @@ -1,19 +1,22 @@ #![allow(clippy::mutable_key_type)] -use talc_lang::{symbol::{symbol, Symbol}, Vm}; +use talc_lang::{ + symbol::{symbol, Symbol}, + Vm, +}; -pub mod value; +pub mod collection; +pub mod exception; +pub mod file; +pub mod format; pub mod io; pub mod iter; -pub mod exception; pub mod num; -pub mod collection; -pub mod string; -pub mod format; -pub mod file; -pub mod regex; -#[cfg(feature="random")] +#[cfg(feature = "random")] pub mod random; +pub mod regex; +pub mod string; +pub mod value; pub fn load_all(vm: &mut Vm) { value::load(vm); @@ -26,7 +29,7 @@ pub fn load_all(vm: &mut Vm) { format::load(vm); regex::load(vm); file::load(vm); - #[cfg(feature="random")] + #[cfg(feature = "random")] random::load(vm); } @@ -35,7 +38,6 @@ lazy_static::lazy_static! { pub static ref SYM_FORMAT_ERROR: Symbol = symbol!(format_error); } - macro_rules! unpack_args { ($e:expr) => { ($e).try_into().expect("bypassed arity check") diff --git a/talc-std/src/num.rs b/talc-std/src/num.rs index d7d1cca..4109826 100644 --- a/talc-std/src/num.rs +++ b/talc-std/src/num.rs @@ -1,7 +1,14 @@ use std::cmp::Ordering; use lazy_static::lazy_static; -use talc_lang::{exception::Result, parser::{parse_int, to_lstring_radix}, symbol::{Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{ops::RatioExt, Complex64, Value}, vmcalliter, Vm}; +use talc_lang::{ + exception::Result, + parser::{parse_int, to_lstring_radix}, + symbol::{Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, + throw, + value::{ops::RatioExt, Complex64, Value}, + vmcalliter, Vm, +}; use talc_macros::native_func; use crate::unpack_args; @@ -49,8 +56,8 @@ pub fn load(vm: &mut Vm) { vm.set_global_name("inf", (f64::INFINITY).into()); vm.set_global_name("NaN", (f64::NAN).into()); - vm.set_global_name("infi", Complex64::new(0.0,f64::INFINITY).into()); - vm.set_global_name("NaNi", Complex64::new(0.0,f64::NAN).into()); + vm.set_global_name("infi", Complex64::new(0.0, f64::INFINITY).into()); + vm.set_global_name("NaNi", Complex64::new(0.0, f64::NAN).into()); vm.set_global_name("bin", bin().into()); vm.set_global_name("sex", sex().into()); @@ -163,7 +170,10 @@ pub fn hex(_: &mut Vm, args: Vec) -> Result { pub fn to_radix(_: &mut Vm, args: Vec) -> Result { let [_, x, radix] = unpack_args!(args); let (Value::Int(x), Value::Int(radix)) = (&x, &radix) else { - throw!(*SYM_TYPE_ERROR, "to_radix expected integer arguments, got {x:#} and {radix:#}") + throw!( + *SYM_TYPE_ERROR, + "to_radix expected integer arguments, got {x:#} and {radix:#}" + ) }; if *radix < 2 || *radix > 36 { throw!(*SYM_VALUE_ERROR, "to_radix expected radix in range 0..=36") @@ -175,10 +185,16 @@ pub fn to_radix(_: &mut Vm, args: Vec) -> Result { pub fn to_radix_upper(_: &mut Vm, args: Vec) -> Result { let [_, x, radix] = unpack_args!(args); let (Value::Int(x), Value::Int(radix)) = (&x, &radix) else { - throw!(*SYM_TYPE_ERROR, "to_radix_upper expected integer arguments, got {x:#} and {radix:#}") + throw!( + *SYM_TYPE_ERROR, + "to_radix_upper expected integer arguments, got {x:#} and {radix:#}" + ) }; if *radix < 2 || *radix > 36 { - throw!(*SYM_VALUE_ERROR, "to_radix_upper expected radix in range 0..=36") + throw!( + *SYM_VALUE_ERROR, + "to_radix_upper expected radix in range 0..=36" + ) } Ok(to_lstring_radix(*x, *radix as u32, true).into()) } @@ -187,14 +203,23 @@ pub fn to_radix_upper(_: &mut Vm, args: Vec) -> Result { pub fn from_radix(_: &mut Vm, args: Vec) -> Result { let [_, s, radix] = unpack_args!(args); let (Value::String(s), Value::Int(radix)) = (&s, &radix) else { - throw!(*SYM_TYPE_ERROR, "from_radix expected string and integer arguments, got {s:#} and {radix:#}") + throw!( + *SYM_TYPE_ERROR, + "from_radix expected string and integer arguments, got {s:#} and {radix:#}" + ) }; if *radix < 2 || *radix > 36 { - throw!(*SYM_VALUE_ERROR, "from_radix expected radix in range 0..=36") + throw!( + *SYM_VALUE_ERROR, + "from_radix expected radix in range 0..=36" + ) } match parse_int(s.as_ref(), *radix as u32) { Ok(v) => Ok(v.into()), - Err(_) => throw!(*SYM_VALUE_ERROR, "string was not a valid integer in given radix"), + Err(_) => throw!( + *SYM_VALUE_ERROR, + "string was not a valid integer in given radix" + ), } } @@ -204,7 +229,9 @@ pub fn from_radix(_: &mut Vm, args: Vec) -> Result { fn isqrt_inner(mut n: i64) -> i64 { assert!(n >= 0, "isqrt input should be nonnegative"); - if n < 2 { return n } + if n < 2 { + return n + } let mut c = 0; let mut d = 1 << 62; @@ -217,8 +244,7 @@ fn isqrt_inner(mut n: i64) -> i64 { if n >= c + d { n -= c + d; c = (c >> 1) + d; - } - else { + } else { c >>= 1; } d >>= 2; @@ -242,23 +268,25 @@ pub fn gcd_inner(a: i64, b: i64) -> i64 { let z = az.min(bz); loop { - if a > b { + if a > b { std::mem::swap(&mut a, &mut b); } b -= a; if b == 0 { - return a << z; + return a << z } b >>= b.trailing_zeros(); } - } #[native_func(1)] pub fn isqrt(_: &mut Vm, args: Vec) -> Result { let [_, x] = unpack_args!(args); let Value::Int(x) = x else { - throw!(*SYM_TYPE_ERROR, "isqrt expected integer argument, got {x:#}") + throw!( + *SYM_TYPE_ERROR, + "isqrt expected integer argument, got {x:#}" + ) }; if x < 0 { throw!(*SYM_VALUE_ERROR, "isqrt: argument must be positive") @@ -266,12 +294,14 @@ pub fn isqrt(_: &mut Vm, args: Vec) -> Result { Ok(isqrt_inner(x).into()) } - #[native_func(1)] pub fn isprime(_: &mut Vm, args: Vec) -> Result { let [_, x] = unpack_args!(args); let Value::Int(x) = x else { - throw!(*SYM_TYPE_ERROR, "isprime expected integer argument, got {x:#}") + throw!( + *SYM_TYPE_ERROR, + "isprime expected integer argument, got {x:#}" + ) }; if x < 2 { return Ok(false.into()) @@ -286,9 +316,13 @@ pub fn isprime(_: &mut Vm, args: Vec) -> Result { } let lim = isqrt_inner(x); let mut i = 12; - while i <= lim+1 { - if x % (i - 1) == 0 { return Ok(false.into()) } - if x % (i + 1) == 0 { return Ok(false.into()) } + while i <= lim + 1 { + if x % (i - 1) == 0 { + return Ok(false.into()) + } + if x % (i + 1) == 0 { + return Ok(false.into()) + } i += 6; } Ok(true.into()) @@ -309,11 +343,11 @@ pub fn gcd(_: &mut Vm, args: Vec) -> Result { #[native_func(1)] pub fn gcdn(vm: &mut Vm, args: Vec) -> Result { let [_, args] = unpack_args!(args); - let args = args.to_iter_function()?; + let args = args.to_iter_function()?; - let mut g = 0; + let mut g = 0; - while let Some(a) = vmcalliter!(vm; args.clone())? { + while let Some(a) = vmcalliter!(vm; args.clone())? { let Value::Int(a) = a else { throw!(*SYM_TYPE_ERROR, "gcdn: cannot take gcd with {a:#}") }; @@ -333,41 +367,46 @@ pub fn lcm(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_TYPE_ERROR, "lcm expected integer argument, got {y:#}") }; let g = gcd_inner(x, y); - if g == 0 { - Ok(Value::from(0)) - } else { - (Value::from(x)/Value::from(g))? * Value::from(y) - } + if g == 0 { + Ok(Value::from(0)) + } else { + (Value::from(x) / Value::from(g))? * Value::from(y) + } } #[native_func(1)] pub fn lcmn(vm: &mut Vm, args: Vec) -> Result { let [_, args] = unpack_args!(args); - let args = args.to_iter_function()?; + let args = args.to_iter_function()?; - let mut l = 1; + let mut l = 1; - while let Some(a) = vmcalliter!(vm; args.clone())? { + while let Some(a) = vmcalliter!(vm; args.clone())? { let Value::Int(a) = a else { throw!(*SYM_TYPE_ERROR, "lcmn: cannot take lcm with {a:#}") }; let g = gcd_inner(l, a); - if g == 0 { return Ok(Value::from(0)) }; - let new_l = (Value::from(l).int_div(Value::from(g))? * Value::from(a))?; - let Value::Int(new_l) = new_l else { + if g == 0 { + return Ok(Value::from(0)) + }; + let new_l = (Value::from(l).int_div(Value::from(g))? * Value::from(a))?; + let Value::Int(new_l) = new_l else { unreachable!("int//int * int != int") - }; - l = new_l; + }; + l = new_l; } - Ok(Value::from(l)) + Ok(Value::from(l)) } #[native_func(1)] pub fn factors(_: &mut Vm, args: Vec) -> Result { let [_, x] = unpack_args!(args); let Value::Int(mut x) = x else { - throw!(*SYM_TYPE_ERROR, "factors expected integer argument, got {x:#}") + throw!( + *SYM_TYPE_ERROR, + "factors expected integer argument, got {x:#}" + ) }; let mut factors = Vec::new(); if x <= 1 { @@ -382,7 +421,7 @@ pub fn factors(_: &mut Vm, args: Vec) -> Result { factors.push(Value::Int(3)); } let mut i = 5; - while x >= i*i { + while x >= i * i { while x % i == 0 { x /= i; factors.push(Value::Int(i)); @@ -401,49 +440,53 @@ pub fn factors(_: &mut Vm, args: Vec) -> Result { } fn totient_prime(n: &mut u64, p: u64) -> u64 { - if *n % p != 0 { - return 1 - } - *n /= p; - let mut v = p - 1; - while *n % p == 0 { - *n /= p; - v *= p; - } - v + if *n % p != 0 { + return 1 + } + *n /= p; + let mut v = p - 1; + while *n % p == 0 { + *n /= p; + v *= p; + } + v } #[native_func(1)] pub fn totient(_: &mut Vm, args: Vec) -> Result { let [_, x] = unpack_args!(args); let Value::Int(x) = x else { - throw!(*SYM_TYPE_ERROR, "totient expected integer argument, got {x:#}") + throw!( + *SYM_TYPE_ERROR, + "totient expected integer argument, got {x:#}" + ) }; if x <= 1 { return Ok(1.into()) } - let mut x = x as u64; + let mut x = x as u64; let mut totient = 1; - if x & 1 == 0 { x >>= 1; } + if x & 1 == 0 { + x >>= 1; + } while x & 1 == 0 { x >>= 1; - totient <<= 1; + totient <<= 1; } - totient *= totient_prime(&mut x, 3); + totient *= totient_prime(&mut x, 3); let mut i = 5; - while x >= i*i { - totient *= totient_prime(&mut x, i); + while x >= i * i { + totient *= totient_prime(&mut x, i); i += 2; - totient *= totient_prime(&mut x, i); + totient *= totient_prime(&mut x, i); i += 4; } if x > 1 { - totient *= x - 1; + totient *= x - 1; } Ok((totient as i64).into()) } - // // numeric operations // @@ -451,21 +494,21 @@ pub fn totient(_: &mut Vm, args: Vec) -> Result { #[native_func(2)] pub fn min(_: &mut Vm, args: Vec) -> Result { let [_, x, y] = unpack_args!(args); - if y < x { - Ok(y) - } else { - Ok(x) - } + if y < x { + Ok(y) + } else { + Ok(x) + } } #[native_func(2)] pub fn max(_: &mut Vm, args: Vec) -> Result { let [_, x, y] = unpack_args!(args); - if y > x { - Ok(y) - } else { - Ok(x) - } + if y > x { + Ok(y) + } else { + Ok(x) + } } #[native_func(1)] @@ -533,7 +576,7 @@ pub fn sign(_: &mut Vm, args: Vec) -> Result { Ordering::Greater => Ok(Value::Ratio(1.into())), Ordering::Less => Ok(Value::Ratio((-1).into())), Ordering::Equal => Ok(Value::Ratio(0.into())), - } + }, x => throw!(*SYM_TYPE_ERROR, "sign expected real argument, got {x:#}"), } } @@ -542,7 +585,6 @@ pub fn sign(_: &mut Vm, args: Vec) -> Result { // floating-point operations // - #[native_func(1)] pub fn signum(_: &mut Vm, args: Vec) -> Result { let [_, x] = unpack_args!(args); @@ -557,7 +599,10 @@ pub fn classify(_: &mut Vm, args: Vec) -> Result { let [_, x] = unpack_args!(args); let x = to_floaty(x); let Value::Float(x) = x else { - throw!(*SYM_TYPE_ERROR, "classify expected real argument, got {x:#}") + throw!( + *SYM_TYPE_ERROR, + "classify expected real argument, got {x:#}" + ) }; Ok(match x.classify() { std::num::FpCategory::Nan => *SYM_NAN, @@ -565,7 +610,8 @@ pub fn classify(_: &mut Vm, args: Vec) -> Result { std::num::FpCategory::Zero => *SYM_ZERO, std::num::FpCategory::Subnormal => *SYM_SUBNORMAL, std::num::FpCategory::Normal => *SYM_NORMAL, - }.into()) + } + .into()) } #[native_func(1)] @@ -575,7 +621,10 @@ pub fn isnan(_: &mut Vm, args: Vec) -> Result { Value::Int(_) | Value::Ratio(_) => Ok(false.into()), Value::Float(x) => Ok(x.is_nan().into()), Value::Complex(z) => Ok(z.is_nan().into()), - v => throw!(*SYM_TYPE_ERROR, "isnan expected numeric argument, got {v:#}"), + v => throw!( + *SYM_TYPE_ERROR, + "isnan expected numeric argument, got {v:#}" + ), } } @@ -586,7 +635,10 @@ pub fn isfinite(_: &mut Vm, args: Vec) -> Result { Value::Int(_) | Value::Ratio(_) => Ok(true.into()), Value::Float(x) => Ok(x.is_finite().into()), Value::Complex(z) => Ok(z.is_finite().into()), - v => throw!(*SYM_TYPE_ERROR, "isfinite expected numeric argument, got {v:#}"), + v => throw!( + *SYM_TYPE_ERROR, + "isfinite expected numeric argument, got {v:#}" + ), } } @@ -597,7 +649,10 @@ pub fn isinfinite(_: &mut Vm, args: Vec) -> Result { Value::Int(_) | Value::Ratio(_) => Ok(false.into()), Value::Float(x) => Ok(x.is_infinite().into()), Value::Complex(z) => Ok(z.is_infinite().into()), - v => throw!(*SYM_TYPE_ERROR, "isinfinite expected numeric argument, got {v:#}"), + v => throw!( + *SYM_TYPE_ERROR, + "isinfinite expected numeric argument, got {v:#}" + ), } } @@ -605,7 +660,10 @@ pub fn isinfinite(_: &mut Vm, args: Vec) -> Result { pub fn float_to_bits(_: &mut Vm, args: Vec) -> Result { let [_, val] = unpack_args!(args); let Value::Float(f) = val else { - throw!(*SYM_TYPE_ERROR, "float_to_bits expected float argument, got {val:#}") + throw!( + *SYM_TYPE_ERROR, + "float_to_bits expected float argument, got {val:#}" + ) }; Ok(Value::Int(f.to_bits() as i64)) } @@ -614,25 +672,28 @@ pub fn float_to_bits(_: &mut Vm, args: Vec) -> Result { pub fn float_of_bits(_: &mut Vm, args: Vec) -> Result { let [_, val] = unpack_args!(args); let Value::Int(i) = val else { - throw!(*SYM_TYPE_ERROR, "float_of_bits expected integer argument, got {val:#}") + throw!( + *SYM_TYPE_ERROR, + "float_of_bits expected integer argument, got {val:#}" + ) }; Ok(Value::Float(f64::from_bits(i as u64))) } - - // // rational operations // - #[native_func(1)] pub fn numer(_: &mut Vm, args: Vec) -> Result { let [_, v] = unpack_args!(args); match v { Value::Int(x) => Ok(Value::Int(x)), Value::Ratio(x) => Ok(Value::Int(*x.numer())), - v => throw!(*SYM_TYPE_ERROR, "numer expected rational argument, got {v:#}"), + v => throw!( + *SYM_TYPE_ERROR, + "numer expected rational argument, got {v:#}" + ), } } @@ -642,7 +703,10 @@ pub fn denom(_: &mut Vm, args: Vec) -> Result { match v { Value::Int(_) => Ok(Value::Int(1)), Value::Ratio(x) => Ok(Value::Int(*x.denom())), - v => throw!(*SYM_TYPE_ERROR, "denom expected rational argument, got {v:#}"), + v => throw!( + *SYM_TYPE_ERROR, + "denom expected rational argument, got {v:#}" + ), } } @@ -650,8 +714,6 @@ pub fn denom(_: &mut Vm, args: Vec) -> Result { // complex operations // - - #[native_func(1)] pub fn re(_: &mut Vm, args: Vec) -> Result { let [_, v] = unpack_args!(args); @@ -688,7 +750,7 @@ pub fn arg(_: &mut Vm, args: Vec) -> Result { #[native_func(1)] pub fn abs(_: &mut Vm, args: Vec) -> Result { let [_, x] = unpack_args!(args); - x.abs() + x.abs() } #[native_func(1)] @@ -699,17 +761,17 @@ pub fn abs_sq(_: &mut Vm, args: Vec) -> Result { Value::Ratio(_) => x.clone() * x, Value::Float(_) => x.clone() * x, Value::Complex(x) => Ok(Value::Float(x.norm_sqr())), - x => throw!(*SYM_TYPE_ERROR, "abs_sq expected numeric argument, got {x:#}"), + x => throw!( + *SYM_TYPE_ERROR, + "abs_sq expected numeric argument, got {x:#}" + ), } } - - // // continuous operations // - macro_rules! float_func { ($name:ident) => { #[native_func(1)] @@ -718,8 +780,11 @@ macro_rules! float_func { match to_floaty(v) { Value::Float(x) => Ok(Value::Float(x.$name())), Value::Complex(z) => Ok(Value::Complex(z.$name())), - v => throw!(*SYM_TYPE_ERROR, - "{} expected numeric argument, got {v:#}", stringify!($name)), + v => throw!( + *SYM_TYPE_ERROR, + "{} expected numeric argument, got {v:#}", + stringify!($name) + ), } } }; @@ -750,10 +815,10 @@ float_func!(atanh); pub fn atan2(_: &mut Vm, args: Vec) -> Result { let [_, y, x] = unpack_args!(args); match (to_floaty(y), to_floaty(x)) { - (Value::Float(y), Value::Float(x)) - => Ok(Value::Float(x.atan2(y))), - (y,x) => throw!(*SYM_TYPE_ERROR, - "atan2 expected real arguments, got {y:#} and {x:#}"), + (Value::Float(y), Value::Float(x)) => Ok(Value::Float(x.atan2(y))), + (y, x) => throw!( + *SYM_TYPE_ERROR, + "atan2 expected real arguments, got {y:#} and {x:#}" + ), } } - diff --git a/talc-std/src/random.rs b/talc-std/src/random.rs index b3ccae0..e48a3b3 100644 --- a/talc-std/src/random.rs +++ b/talc-std/src/random.rs @@ -1,5 +1,11 @@ use rand::{seq::SliceRandom, Rng}; -use talc_lang::{exception::Result, symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{range::RangeType, Value}, vmcalliter, Vm}; +use talc_lang::{ + exception::Result, + symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, + throw, + value::{range::RangeType, Value}, + vmcalliter, Vm, +}; use talc_macros::native_func; use crate::unpack_args; @@ -21,11 +27,11 @@ pub fn rand_in(vm: &mut Vm, args: Vec) -> Result { match col { Value::List(l) => { let l = l.borrow(); - let Some(v) = l.choose(&mut rand::thread_rng()) else { + let Some(v) = l.choose(&mut rand::thread_rng()) else { throw!(*SYM_VALUE_ERROR, "rand_in: empty list") }; Ok(v.clone()) - }, + } Value::Table(t) => { let t = t.borrow(); if t.is_empty() { @@ -34,16 +40,14 @@ pub fn rand_in(vm: &mut Vm, args: Vec) -> Result { let i = rand::thread_rng().gen_range(0..t.len()); let key = t.keys().nth(i).unwrap(); Ok(key.clone().into_inner()) - }, + } Value::Range(r) => { if r.is_empty() { throw!(*SYM_VALUE_ERROR, "rand_in: empty range") } match r.ty { - RangeType::Open => Ok(Value::Int( - rand::thread_rng().gen_range(r.start..r.stop))), - RangeType::Closed => Ok(Value::Int( - rand::thread_rng().gen_range(r.start..=r.stop))), + RangeType::Open => Ok(Value::Int(rand::thread_rng().gen_range(r.start..r.stop))), + RangeType::Closed => Ok(Value::Int(rand::thread_rng().gen_range(r.start..=r.stop))), RangeType::Endless => throw!(*SYM_VALUE_ERROR, "rand_in: endless range"), } } diff --git a/talc-std/src/regex.rs b/talc-std/src/regex.rs index d5deff9..2c74310 100644 --- a/talc-std/src/regex.rs +++ b/talc-std/src/regex.rs @@ -1,9 +1,16 @@ use std::borrow::Cow; -use talc_lang::{exception::{exception, Result}, lstring::LString, symbol::{Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{NativeValue, Value}, Vm}; -use talc_macros::native_func; -use regex::{Captures, Match, Regex}; use lazy_static::lazy_static; +use regex::{Captures, Match, Regex}; +use talc_lang::{ + exception::{exception, Result}, + lstring::LString, + symbol::{Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, + throw, + value::{NativeValue, Value}, + Vm, +}; +use talc_macros::native_func; use crate::unpack_args; @@ -18,17 +25,30 @@ lazy_static! { pub struct ValueRegex(Regex); impl From for ValueRegex { - fn from(value: Regex) -> Self { Self(value) } + fn from(value: Regex) -> Self { + Self(value) + } } impl From for Regex { - fn from(value: ValueRegex) -> Self { value.0 } + fn from(value: ValueRegex) -> Self { + value.0 + } } impl NativeValue for ValueRegex { - fn get_type(&self) -> Symbol { *SYM_STD_REGEX } - fn as_any(&self) -> &dyn std::any::Any { self } - fn to_lstring(&self, w: &mut LString, repr: bool, _recur: &mut Vec<*const ()>) -> std::io::Result<()> { + fn get_type(&self) -> Symbol { + *SYM_STD_REGEX + } + fn as_any(&self) -> &dyn std::any::Any { + self + } + fn to_lstring( + &self, + w: &mut LString, + repr: bool, + _recur: &mut Vec<*const ()>, + ) -> std::io::Result<()> { use std::io::Write; if repr { write!(w, "/{}/", self.0) @@ -58,7 +78,10 @@ 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_STR).into(), LString::from(m.as_str().to_string()).into()); + t.insert( + (*SYM_STR).into(), + LString::from(m.as_str().to_string()).into(), + ); }) } @@ -78,22 +101,28 @@ fn regex_from<'a>(v: &'a Value, name: &str) -> Result> { Regex::new(s) .map(Cow::Owned) .map_err(|e| exception!(*SYM_VALUE_ERROR, "invalid regex: {e}")) - }, - Value::Native(n) if n.get_type() == *SYM_STD_REGEX => { - n.as_any().downcast_ref::() - .map(|vr| Cow::Borrowed(&vr.0)) - .ok_or_else(|| exception!( - *SYM_TYPE_ERROR, "{name} expected string or regex, got {v:#}")) - }, - _ => throw!(*SYM_TYPE_ERROR, "{name} expected string or regex, got {v:#}") + } + Value::Native(n) if n.get_type() == *SYM_STD_REGEX => n + .as_any() + .downcast_ref::() + .map(|vr| Cow::Borrowed(&vr.0)) + .ok_or_else(|| { + exception!( + *SYM_TYPE_ERROR, + "{name} expected string or regex, got {v:#}" + ) + }), + _ => throw!( + *SYM_TYPE_ERROR, + "{name} expected string or regex, got {v:#}" + ), } } #[native_func(1)] pub fn _regex(_: &mut Vm, args: Vec) -> Result { let [_, re] = unpack_args!(args); - regex_from(&re, "regex") - .map(|re| ValueRegex(re.into_owned()).into()) + regex_from(&re, "regex").map(|re| ValueRegex(re.into_owned()).into()) } #[native_func(2)] @@ -132,7 +161,11 @@ pub fn _match(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_VALUE_ERROR, "search string must be valid UTF-8") }; let re = regex_from(&re, "match")?; - Ok(re.find_iter(s).map(match_to_value).collect::>().into()) + Ok(re + .find_iter(s) + .map(match_to_value) + .collect::>() + .into()) } #[native_func(2)] @@ -158,7 +191,11 @@ pub fn captures(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_VALUE_ERROR, "search string must be valid UTF-8") }; let re = regex_from(&re, "captures")?; - Ok(re.captures_iter(s).map(captures_to_value).collect::>().into()) + Ok(re + .captures_iter(s) + .map(captures_to_value) + .collect::>() + .into()) } #[native_func(3)] @@ -168,7 +205,10 @@ pub fn replace_once(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_TYPE_ERROR, "replace_once expected string, got {s:#}") }; let Value::String(rep) = rep else { - throw!(*SYM_TYPE_ERROR, "replace_once expected string or function, got {rep:#}") + throw!( + *SYM_TYPE_ERROR, + "replace_once expected string or function, got {rep:#}" + ) }; let Ok(s) = s.to_str() else { throw!(*SYM_VALUE_ERROR, "search string must be valid UTF-8") @@ -187,7 +227,10 @@ pub fn replace(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_TYPE_ERROR, "replace expected string, got {s:#}") }; let Value::String(rep) = rep else { - throw!(*SYM_TYPE_ERROR, "replace expected string or function, got {rep:#}") + throw!( + *SYM_TYPE_ERROR, + "replace expected string or function, got {rep:#}" + ) }; let Ok(s) = s.to_str() else { throw!(*SYM_VALUE_ERROR, "search string must be valid UTF-8") @@ -212,7 +255,7 @@ pub fn split_once(_: &mut Vm, args: Vec) -> Result { let mut parts = re.splitn(s, 2); let (part1, part2) = ( LString::from(parts.next().unwrap_or_default()).into(), - LString::from(parts.next().unwrap_or_default()).into() + LString::from(parts.next().unwrap_or_default()).into(), ); Ok(vec![part1, part2].into()) } @@ -227,9 +270,6 @@ pub fn split(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_VALUE_ERROR, "string to split must be valid UTF-8") }; let re = regex_from(&re, "split")?; - let parts: Vec = re.split(s) - .map(|s| LString::from(s).into()) - .collect(); + let parts: Vec = re.split(s).map(|s| LString::from(s).into()).collect(); Ok(parts.into()) } - diff --git a/talc-std/src/string.rs b/talc-std/src/string.rs index 49f0ac3..2ee25b8 100644 --- a/talc-std/src/string.rs +++ b/talc-std/src/string.rs @@ -1,4 +1,11 @@ -use talc_lang::{exception::Result, lstring::LString, symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::Value, Vm}; +use talc_lang::{ + exception::Result, + lstring::LString, + symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, + throw, + value::Value, + Vm, +}; use talc_macros::native_func; use crate::unpack_args; @@ -54,7 +61,10 @@ pub fn chr(_: &mut Vm, args: Vec) -> Result { pub fn len_bytes(_: &mut Vm, args: Vec) -> Result { let [_, s] = unpack_args!(args); let Value::String(s) = s else { - throw!(*SYM_TYPE_ERROR, "len_bytes expected string argument, got {s:#}") + throw!( + *SYM_TYPE_ERROR, + "len_bytes expected string argument, got {s:#}" + ) }; Ok(Value::Int(s.len() as i64)) } @@ -92,8 +102,10 @@ pub fn starts_with(_: &mut Vm, args: Vec) -> Result { let res = match (d, pre) { (Value::List(d), Value::List(pre)) => d.borrow().starts_with(&pre.borrow()), (Value::String(d), Value::String(pre)) => d.starts_with(&pre), - (d, pre) => throw!(*SYM_TYPE_ERROR, - "starts_with expected two lists or strings, got {d:#} and {pre:#}") + (d, pre) => throw!( + *SYM_TYPE_ERROR, + "starts_with expected two lists or strings, got {d:#} and {pre:#}" + ), }; Ok(res.into()) } @@ -104,8 +116,10 @@ pub fn ends_with(_: &mut Vm, args: Vec) -> Result { let res = match (d, suf) { (Value::List(d), Value::List(suf)) => d.borrow().ends_with(&suf.borrow()), (Value::String(d), Value::String(suf)) => d.ends_with(&suf), - (d, suf) => throw!(*SYM_TYPE_ERROR, - "ends_with expected two lists or strings, got {d:#} and {suf:#}") + (d, suf) => throw!( + *SYM_TYPE_ERROR, + "ends_with expected two lists or strings, got {d:#} and {suf:#}" + ), }; Ok(res.into()) } @@ -114,7 +128,10 @@ pub fn ends_with(_: &mut Vm, args: Vec) -> Result { pub fn is_utf8(_: &mut Vm, args: Vec) -> Result { let [_, s] = unpack_args!(args); let Value::String(s) = s else { - throw!(*SYM_TYPE_ERROR, "is_utf8 expected string argument, got {s:#}") + throw!( + *SYM_TYPE_ERROR, + "is_utf8 expected string argument, got {s:#}" + ) }; Ok(s.is_utf8().into()) } @@ -123,7 +140,10 @@ pub fn is_utf8(_: &mut Vm, args: Vec) -> Result { pub fn to_utf8(_: &mut Vm, args: Vec) -> Result { let [_, s] = unpack_args!(args); let Value::String(s) = s else { - throw!(*SYM_TYPE_ERROR, "is_utf8 expected string argument, got {s:#}") + throw!( + *SYM_TYPE_ERROR, + "is_utf8 expected string argument, got {s:#}" + ) }; if s.is_utf8() { Ok(s.into()) @@ -136,7 +156,10 @@ pub fn to_utf8(_: &mut Vm, args: Vec) -> Result { pub fn to_utf8_lossy(_: &mut Vm, args: Vec) -> Result { let [_, s] = unpack_args!(args); let Value::String(s) = s else { - throw!(*SYM_TYPE_ERROR, "is_utf8 expected string argument, got {s:#}") + throw!( + *SYM_TYPE_ERROR, + "is_utf8 expected string argument, got {s:#}" + ) }; Ok(s.to_utf8_lossy().into()) } @@ -145,25 +168,37 @@ pub fn to_utf8_lossy(_: &mut Vm, args: Vec) -> Result { pub fn str_to_bytes(_: &mut Vm, args: Vec) -> Result { let [_, s] = unpack_args!(args); let Value::String(s) = s else { - throw!(*SYM_TYPE_ERROR, "str_to_bytes expected string argument, got {s:#}") + throw!( + *SYM_TYPE_ERROR, + "str_to_bytes expected string argument, got {s:#}" + ) }; Ok(s.as_bytes() - .iter() - .map(|v| (*v as i64).into()) - .collect::>() - .into()) + .iter() + .map(|v| (*v as i64).into()) + .collect::>() + .into()) } #[native_func(1)] pub fn str_of_bytes(_: &mut Vm, args: Vec) -> Result { let [_, b] = unpack_args!(args); let Value::List(b) = b else { - throw!(*SYM_TYPE_ERROR, "str_of_bytes expected list argument, got {b:#}") + throw!( + *SYM_TYPE_ERROR, + "str_of_bytes expected list argument, got {b:#}" + ) }; - let bytes: Vec = b.borrow().iter() + let bytes: Vec = b + .borrow() + .iter() .map(|v| match v { Value::Int(i) if (0..=255).contains(i) => Ok(*i as u8), - _ => throw!(*SYM_VALUE_ERROR, "str_of_bytes expected list of integers in 0..=255"), - }).collect::>>()?; + _ => throw!( + *SYM_VALUE_ERROR, + "str_of_bytes expected list of integers in 0..=255" + ), + }) + .collect::>>()?; Ok(LString::from(bytes).into()) } diff --git a/talc-std/src/value.rs b/talc-std/src/value.rs index 50b5a8e..ef79336 100644 --- a/talc-std/src/value.rs +++ b/talc-std/src/value.rs @@ -1,6 +1,14 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc}; -use talc_lang::{exception::{exception, Result}, lformat, parser::{parse_float, parse_int}, symbol::{symbol, Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, value::{ops::RatioExt, HashValue, Rational64, Value}, Vm}; +use talc_lang::{ + exception::{exception, Result}, + lformat, + parser::{parse_float, parse_int}, + symbol::{symbol, Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, + throw, + value::{ops::RatioExt, HashValue, Rational64, Value}, + Vm, +}; use talc_macros::native_func; use crate::unpack_args; @@ -34,7 +42,6 @@ pub fn load(vm: &mut Vm) { // types // - #[native_func(1, "type")] pub fn type_(_: &mut Vm, args: Vec) -> Result { let [_, val] = unpack_args!(args); @@ -74,59 +81,75 @@ pub fn as_(_: &mut Vm, args: Vec) -> Result { (Value::Ratio(x), b"complex") => Ok(Value::Complex(x.to_f64().into())), (Value::Float(x), b"int") => Ok(Value::Int(x as i64)), (Value::Float(x), b"ratio") => { - let r = Rational64::approximate_float(x) - .ok_or_else(|| exception!(*SYM_VALUE_ERROR, "float {x:?} could not be converted to ratio"))?; + let r = Rational64::approximate_float(x).ok_or_else(|| { + exception!( + *SYM_VALUE_ERROR, + "float {x:?} could not be converted to ratio" + ) + })?; Ok(Value::Ratio(r)) } (Value::Float(x), b"complex") => Ok(Value::Complex(x.into())), - (Value::String(s), b"int") - => parse_int(s.as_ref(), 10) + (Value::String(s), b"int") => parse_int(s.as_ref(), 10) .map(i64::into) .map_err(|_| exception!(*SYM_VALUE_ERROR, "could not parse {s:#} as integer")), - (Value::String(s), b"float") - => parse_float(s.as_ref()) + (Value::String(s), b"float") => parse_float(s.as_ref()) .map(f64::into) .map_err(|_| exception!(*SYM_VALUE_ERROR, "could not parse {s:#} as float")), - (v, _) => throw!(*SYM_TYPE_ERROR, - "cannot convert value of type {} to type {}", v.get_type().name(), ty.name()) + (v, _) => throw!( + *SYM_TYPE_ERROR, + "cannot convert value of type {} to type {}", + v.get_type().name(), + ty.name() + ), } } pub fn copy_inner(value: Value) -> Result { match value { - Value::Nil | Value::Bool(_) | Value::Symbol(_) - | Value::Int(_) | Value::Ratio(_) | Value::Float(_) - | Value::Complex(_) | Value::Range(_) | Value::String(_) - => Ok(value), + Value::Nil + | Value::Bool(_) + | Value::Symbol(_) + | Value::Int(_) + | Value::Ratio(_) + | Value::Float(_) + | Value::Complex(_) + | Value::Range(_) + | Value::String(_) => Ok(value), Value::Cell(c) => { let c = Rc::unwrap_or_clone(c).take(); let c = copy_inner(c)?; Ok(RefCell::new(c).into()) - }, + } Value::List(l) => { let l = Rc::unwrap_or_clone(l).take(); - let v: Result> = l.into_iter() - .map(copy_inner) - .collect(); + let v: Result> = l.into_iter().map(copy_inner).collect(); Ok(v?.into()) - }, + } Value::Table(t) => { let t = Rc::unwrap_or_clone(t).take(); - let v: Result> = t.into_iter() + let v: Result> = t + .into_iter() .map(|(k, v)| copy_inner(v).map(|v| (k, v))) .collect(); Ok(v?.into()) - }, + } Value::Native(ref n) => match n.copy_value()? { Some(x) => Ok(x), - None => throw!(*SYM_TYPE_ERROR, - "cannot copy value of type {}", value.get_type().name()) - } - _ => throw!(*SYM_TYPE_ERROR, - "cannot copy value of type {}", value.get_type().name()) + None => throw!( + *SYM_TYPE_ERROR, + "cannot copy value of type {}", + value.get_type().name() + ), + }, + _ => throw!( + *SYM_TYPE_ERROR, + "cannot copy value of type {}", + value.get_type().name() + ), } } @@ -140,7 +163,6 @@ pub fn copy(_: &mut Vm, args: Vec) -> Result { // strings // - #[native_func(1, "str")] pub fn str_(_: &mut Vm, args: Vec) -> Result { let [_, val] = unpack_args!(args); @@ -160,38 +182,37 @@ pub fn repr(_: &mut Vm, args: Vec) -> Result { #[native_func(1)] pub fn symbol_name(_: &mut Vm, args: Vec) -> Result { let [_, val] = unpack_args!(args); - let Value::Symbol(s) = val else { - throw!(*SYM_TYPE_ERROR, "symbol_name: expected symbol") - }; + let Value::Symbol(s) = val else { + throw!(*SYM_TYPE_ERROR, "symbol_name: expected symbol") + }; Ok(s.name().into()) } #[native_func(1)] pub fn symbol_of(_: &mut Vm, args: Vec) -> Result { let [_, val] = unpack_args!(args); - let Value::String(s) = val else { - throw!(*SYM_TYPE_ERROR, "symbol_of: expected string") - }; + let Value::String(s) = val else { + throw!(*SYM_TYPE_ERROR, "symbol_of: expected string") + }; Ok(Symbol::get(s.as_ref()).into()) } #[native_func(1)] pub fn symbol_exists(_: &mut Vm, args: Vec) -> Result { let [_, val] = unpack_args!(args); - let Value::String(s) = val else { - throw!(*SYM_TYPE_ERROR, "symbol_of: expected string") - }; + let Value::String(s) = val else { + throw!(*SYM_TYPE_ERROR, "symbol_of: expected string") + }; match Symbol::try_get(s.as_ref()) { - Some(s) => Ok(s.into()), - None => Ok(Value::Nil), - } + Some(s) => Ok(s.into()), + None => Ok(Value::Nil), + } } // // cells // - #[native_func(1)] pub fn cell(_: &mut Vm, args: Vec) -> Result { let [_, value] = unpack_args!(args); @@ -232,66 +253,78 @@ pub fn cell_take(_: &mut Vm, args: Vec) -> Result { #[native_func(1)] pub fn func_state(_: &mut Vm, args: Vec) -> Result { let [_, func] = unpack_args!(args); - match func { - Value::NativeFunc(_) => Ok(Value::Nil), - Value::Function(f) => { - let l: Vec = f.state.iter() - .map(|v| Value::Cell(v.clone())) - .collect(); - Ok(l.into()) - } - _ => throw!(*SYM_TYPE_ERROR, "closure_state: {func:#} is not a talc function") - } + match func { + Value::NativeFunc(_) => Ok(Value::Nil), + Value::Function(f) => { + let l: Vec = f.state.iter().map(|v| Value::Cell(v.clone())).collect(); + Ok(l.into()) + } + _ => throw!( + *SYM_TYPE_ERROR, + "closure_state: {func:#} is not a talc function" + ), + } } - #[native_func(1)] pub fn func_arity(_: &mut Vm, args: Vec) -> Result { let [_, func] = unpack_args!(args); - let Some(attrs) = func.func_attrs() else { + 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 as i64).into()) } #[native_func(1)] pub fn func_name(_: &mut Vm, args: Vec) -> Result { let [_, func] = unpack_args!(args); - let Some(attrs) = func.func_attrs() else { + let Some(attrs) = func.func_attrs() else { throw!(*SYM_TYPE_ERROR, "closure_state: {func:#} is not a function") }; - if let Some(name) = attrs.name { - Ok(name.into()) - } else { - Ok(Value::Nil) - } + if let Some(name) = attrs.name { + Ok(name.into()) + } else { + Ok(Value::Nil) + } } #[native_func(2)] pub fn apply(vm: &mut Vm, args: Vec) -> Result { let [_, func, lst] = unpack_args!(args); - if func.func_attrs().is_none() { - throw!(*SYM_TYPE_ERROR, "apply: first argument must be a function, found {func:#}") - } - let Value::List(l) = lst else { - throw!(*SYM_TYPE_ERROR, "apply: second argument must be a list, found {lst:#}") - }; - let mut args = l.borrow().clone(); - args.insert(0, func.clone()); - vm.call_value(func, args) + if func.func_attrs().is_none() { + throw!( + *SYM_TYPE_ERROR, + "apply: first argument must be a function, found {func:#}" + ) + } + let Value::List(l) = lst else { + throw!( + *SYM_TYPE_ERROR, + "apply: second argument must be a list, found {lst:#}" + ) + }; + let mut args = l.borrow().clone(); + args.insert(0, func.clone()); + vm.call_value(func, args) } #[native_func(1)] pub fn compile(_: &mut Vm, args: Vec) -> Result { let [_, src] = unpack_args!(args); - let Value::String(src) = src else { - throw!(*SYM_TYPE_ERROR, "compile: argument must be a string, found {src:#}") - }; - let src = src.to_str() - .map_err(|e| exception!(*SYM_VALUE_ERROR, "compile: argument must be valid unicode ({e})"))?; - let ast = talc_lang::parser::parse(src) - .map_err(|e| exception!(symbol!("parse_error"), "{e}"))?; - let func = talc_lang::compiler::compile(&ast, None); - Ok(func.into()) + let Value::String(src) = src else { + throw!( + *SYM_TYPE_ERROR, + "compile: argument must be a string, found {src:#}" + ) + }; + let src = src.to_str().map_err(|e| { + exception!( + *SYM_VALUE_ERROR, + "compile: argument must be valid unicode ({e})" + ) + })?; + let ast = + talc_lang::parser::parse(src).map_err(|e| exception!(symbol!("parse_error"), "{e}"))?; + let func = talc_lang::compiler::compile(&ast, None); + Ok(func.into()) } -