bugfixes
This commit is contained in:
parent
2a8a7b347e
commit
88c99fbac1
13 changed files with 117 additions and 110 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -445,9 +445,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.90"
|
version = "2.0.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
|
checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
name = "talc-bin"
|
name = "talc-bin"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
rust-version = "1.81.0"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "talc"
|
name = "talc"
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
name = "talc-lang"
|
name = "talc-lang"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
rust-version = "1.81.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
num = { version = "0.4", features = [] }
|
num = { version = "0.4", features = [] }
|
||||||
|
|
|
@ -69,6 +69,7 @@ struct Compiler<'a> {
|
||||||
attrs: FuncAttrs,
|
attrs: FuncAttrs,
|
||||||
// variables
|
// variables
|
||||||
scope: HashMap<Symbol, VarKind>,
|
scope: HashMap<Symbol, VarKind>,
|
||||||
|
scope_count: usize,
|
||||||
shadowed: Vec<(Symbol, Option<VarKind>)>,
|
shadowed: Vec<(Symbol, Option<VarKind>)>,
|
||||||
closes: Vec<(Symbol, usize)>,
|
closes: Vec<(Symbol, usize)>,
|
||||||
local_count: usize,
|
local_count: usize,
|
||||||
|
@ -85,7 +86,16 @@ pub fn compile(expr: &Expr, name: Option<Symbol>) -> Result<Function> {
|
||||||
|
|
||||||
pub fn compile_repl(expr: &Expr, globals: &mut Vec<Symbol>) -> Result<Function> {
|
pub fn compile_repl(expr: &Expr, globals: &mut Vec<Symbol>) -> Result<Function> {
|
||||||
let mut comp = Compiler::new_repl(globals);
|
let mut comp = Compiler::new_repl(globals);
|
||||||
comp.expr(expr)?;
|
match &expr.kind {
|
||||||
|
ExprKind::Block(xs) => {
|
||||||
|
for x in &xs[0..xs.len() - 1] {
|
||||||
|
comp.expr(x)?;
|
||||||
|
comp.emit_discard();
|
||||||
|
}
|
||||||
|
comp.expr(&xs[xs.len() - 1])?;
|
||||||
|
}
|
||||||
|
_ => comp.expr(expr)?,
|
||||||
|
}
|
||||||
Ok(comp.finish_repl(globals))
|
Ok(comp.finish_repl(globals))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +109,7 @@ impl<'a> Default for Compiler<'a> {
|
||||||
chunk: Chunk::new(),
|
chunk: Chunk::new(),
|
||||||
attrs: FuncAttrs::default(),
|
attrs: FuncAttrs::default(),
|
||||||
scope,
|
scope,
|
||||||
|
scope_count: 0,
|
||||||
shadowed: Vec::new(),
|
shadowed: Vec::new(),
|
||||||
local_count: 1,
|
local_count: 1,
|
||||||
closes: Vec::new(),
|
closes: Vec::new(),
|
||||||
|
@ -286,10 +297,12 @@ impl<'a> Compiler<'a> {
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn begin_scope(&mut self) -> usize {
|
fn begin_scope(&mut self) -> usize {
|
||||||
|
self.scope_count += 1;
|
||||||
self.shadowed.len()
|
self.shadowed.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_scope(&mut self, scope: usize) {
|
fn end_scope(&mut self, scope: usize) {
|
||||||
|
self.scope_count -= 1;
|
||||||
let mut locals = 0;
|
let mut locals = 0;
|
||||||
while self.shadowed.len() > scope {
|
while self.shadowed.len() > scope {
|
||||||
let (name, var) = self.shadowed.pop().expect("scope bad");
|
let (name, var) = self.shadowed.pop().expect("scope bad");
|
||||||
|
@ -377,6 +390,9 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_global(&mut self, name: Symbol) {
|
fn declare_global(&mut self, name: Symbol) {
|
||||||
|
if self.scope.get(&name) == Some(&VarKind::Global) {
|
||||||
|
return
|
||||||
|
}
|
||||||
let shadowed = self.scope.insert(name, VarKind::Global);
|
let shadowed = self.scope.insert(name, VarKind::Global);
|
||||||
self.shadowed.push((name, shadowed));
|
self.shadowed.push((name, shadowed));
|
||||||
}
|
}
|
||||||
|
@ -403,7 +419,10 @@ impl<'a> Compiler<'a> {
|
||||||
ResolveOutcome::Var(VarKind::Global) => {
|
ResolveOutcome::Var(VarKind::Global) => {
|
||||||
self.emit(I::StoreGlobal(Arg24::from_symbol(name)));
|
self.emit(I::StoreGlobal(Arg24::from_symbol(name)));
|
||||||
}
|
}
|
||||||
ResolveOutcome::None if self.mode == CompilerMode::Repl => {
|
ResolveOutcome::None
|
||||||
|
if self.mode == CompilerMode::Repl && self.scope_count == 0 =>
|
||||||
|
{
|
||||||
|
self.declare_global(name);
|
||||||
self.emit(I::StoreGlobal(Arg24::from_symbol(name)));
|
self.emit(I::StoreGlobal(Arg24::from_symbol(name)));
|
||||||
}
|
}
|
||||||
ResolveOutcome::None => {
|
ResolveOutcome::None => {
|
||||||
|
|
|
@ -10,31 +10,23 @@ pub type Result<T> = std::result::Result<T, Exception>;
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Exception {
|
pub struct Exception {
|
||||||
pub ty: Symbol,
|
pub ty: Symbol,
|
||||||
pub msg: Option<Rc<LStr>>,
|
pub msg: Rc<LStr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Exception {
|
impl Exception {
|
||||||
pub fn new(ty: Symbol) -> Self {
|
pub fn new(ty: Symbol, msg: Rc<LStr>) -> Self {
|
||||||
Self { ty, msg: None }
|
Self { ty, msg }
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_msg(ty: Symbol, msg: Rc<LStr>) -> Self {
|
|
||||||
Self { ty, msg: Some(msg) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_table(table: &Rc<RefCell<HashMap<HashValue, Value>>>) -> Option<Self> {
|
pub fn from_table(table: &Rc<RefCell<HashMap<HashValue, Value>>>) -> Option<Self> {
|
||||||
let table = table.borrow();
|
let table = table.borrow();
|
||||||
let ty = table.get(&(*SYM_TYPE).into())?;
|
let ty = table.get(&(*SYM_TYPE).into())?;
|
||||||
if let Value::Symbol(ty) = ty {
|
let msg = table.get(&(*SYM_MSG).into())?;
|
||||||
let msg = table.get(&(*SYM_MSG).into());
|
if let (Value::Symbol(ty), Value::String(msg)) = (ty, msg) {
|
||||||
match msg {
|
Some(Self {
|
||||||
None => Some(Self { ty: *ty, msg: None }),
|
ty: *ty,
|
||||||
Some(Value::String(msg)) => Some(Self {
|
msg: msg.clone(),
|
||||||
ty: *ty,
|
})
|
||||||
msg: Some(msg.clone()),
|
|
||||||
}),
|
|
||||||
Some(_) => None,
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -43,27 +35,21 @@ impl Exception {
|
||||||
pub fn to_table(self) -> Rc<RefCell<HashMap<HashValue, Value>>> {
|
pub fn to_table(self) -> Rc<RefCell<HashMap<HashValue, Value>>> {
|
||||||
let mut table = HashMap::new();
|
let mut table = HashMap::new();
|
||||||
table.insert((*SYM_TYPE).into(), self.ty.into());
|
table.insert((*SYM_TYPE).into(), self.ty.into());
|
||||||
if let Some(msg) = self.msg {
|
table.insert((*SYM_MSG).into(), Value::String(self.msg));
|
||||||
table.insert((*SYM_MSG).into(), Value::String(msg));
|
|
||||||
}
|
|
||||||
Rc::new(RefCell::new(table))
|
Rc::new(RefCell::new(table))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Exception {
|
impl Display for Exception {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
if let Some(msg) = &self.msg {
|
write!(f, "{}: {}", self.ty.name(), self.msg)
|
||||||
write!(f, "{}: {}", self.ty.name(), msg)
|
|
||||||
} else {
|
|
||||||
write!(f, "{}", self.ty.name())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! exception {
|
macro_rules! exception {
|
||||||
($exc_ty:expr, $($t:tt)*) => {
|
($exc_ty:expr, $($t:tt)*) => {
|
||||||
$crate::exception::Exception::new_with_msg(
|
$crate::exception::Exception::new(
|
||||||
$exc_ty,
|
$exc_ty,
|
||||||
$crate::lstring::LString::from(
|
$crate::lstring::LString::from(
|
||||||
format!($($t)*)
|
format!($($t)*)
|
||||||
|
@ -73,9 +59,6 @@ macro_rules! exception {
|
||||||
($exc_ty:expr, $fstr:literal) => {
|
($exc_ty:expr, $fstr:literal) => {
|
||||||
$crate::exception::exception!($exc_ty, $fstr,)
|
$crate::exception::exception!($exc_ty, $fstr,)
|
||||||
};
|
};
|
||||||
($exc_ty:expr) => {
|
|
||||||
$crate::exception::Exception::new($exc_ty)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use exception;
|
pub use exception;
|
||||||
|
|
|
@ -205,6 +205,18 @@ impl<'s> Parser<'s> {
|
||||||
self.lexer.peek().unwrap().clone()
|
self.lexer.peek().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_symbol(tok: Token) -> Result<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(s)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_table_items(&mut self) -> Result<Vec<TableItem>> {
|
fn parse_table_items(&mut self) -> Result<Vec<TableItem>> {
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
|
@ -284,7 +296,7 @@ impl<'s> Parser<'s> {
|
||||||
fn parse_symbol_list(&mut self) -> Result<Vec<Symbol>> {
|
fn parse_symbol_list(&mut self) -> Result<Vec<Symbol>> {
|
||||||
let mut syms = Vec::new();
|
let mut syms = Vec::new();
|
||||||
while let Some(tok) = try_next!(self, T::Symbol) {
|
while let Some(tok) = try_next!(self, T::Symbol) {
|
||||||
syms.push(Symbol::get(tok.content));
|
syms.push(Self::parse_symbol(tok)?);
|
||||||
if try_next!(self, T::Comma).is_none() {
|
if try_next!(self, T::Comma).is_none() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -420,16 +432,8 @@ impl<'s> Parser<'s> {
|
||||||
Ok(E::Literal(s.into()).span(tok.span))
|
Ok(E::Literal(s.into()).span(tok.span))
|
||||||
}
|
}
|
||||||
T::Symbol => {
|
T::Symbol => {
|
||||||
let inner = &tok.content[1..];
|
let s = Self::parse_symbol(tok)?;
|
||||||
let s = match inner.chars().next() {
|
Ok(E::Literal(Value::from(s)).span(tok.span))
|
||||||
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::True => Ok(E::Literal(Value::Bool(true)).span(tok.span)),
|
||||||
T::False => Ok(E::Literal(Value::Bool(false)).span(tok.span)),
|
T::False => Ok(E::Literal(Value::Bool(false)).span(tok.span)),
|
||||||
|
@ -531,6 +535,28 @@ impl<'s> Parser<'s> {
|
||||||
Ok(lhs)
|
Ok(lhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_and(&mut self) -> Result<Expr> {
|
||||||
|
let mut lhs = self.parse_precedence(0)?;
|
||||||
|
let mut span = lhs.span;
|
||||||
|
while try_next!(self, T::And).is_some() {
|
||||||
|
let rhs = self.parse_precedence(0)?;
|
||||||
|
span += rhs.span;
|
||||||
|
lhs = E::And(b(lhs), b(rhs)).span(span);
|
||||||
|
}
|
||||||
|
Ok(lhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_or(&mut self) -> Result<Expr> {
|
||||||
|
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_lambda(&mut self) -> Result<Expr> {
|
fn parse_lambda(&mut self) -> Result<Expr> {
|
||||||
let tok = try_next!(self, T::Backslash | T::Amper);
|
let tok = try_next!(self, T::Backslash | T::Amper);
|
||||||
match tok {
|
match tok {
|
||||||
|
@ -555,7 +581,7 @@ impl<'s> Parser<'s> {
|
||||||
let body_span = body.span;
|
let body_span = body.span;
|
||||||
Ok(E::Lambda(args, b(body)).span(span + body_span))
|
Ok(E::Lambda(args, b(body)).span(span + body_span))
|
||||||
}
|
}
|
||||||
None => self.parse_precedence(0),
|
None => self.parse_or(),
|
||||||
_ => unreachable!("parse_lambda: guaranteed by try_next!"),
|
_ => unreachable!("parse_lambda: guaranteed by try_next!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -571,40 +597,8 @@ impl<'s> Parser<'s> {
|
||||||
Ok(lhs)
|
Ok(lhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_not(&mut self) -> Result<Expr> {
|
|
||||||
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<Expr> {
|
|
||||||
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<Expr> {
|
|
||||||
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<Expr> {
|
fn parse_assign(&mut self) -> Result<Expr> {
|
||||||
let lhs = self.parse_or()?;
|
let lhs = self.parse_pipeline()?;
|
||||||
let lhs_span = lhs.span;
|
let lhs_span = lhs.span;
|
||||||
if let Some(op) = self.peek()?.kind.assign_op() {
|
if let Some(op) = self.peek()?.kind.assign_op() {
|
||||||
let Some(lval) = LValue::from_expr(lhs) else {
|
let Some(lval) = LValue::from_expr(lhs) else {
|
||||||
|
|
|
@ -17,15 +17,19 @@ impl Value {
|
||||||
match (self, idx) {
|
match (self, idx) {
|
||||||
(V::List(l), V::Int(i)) => {
|
(V::List(l), V::Int(i)) => {
|
||||||
let l = l.borrow();
|
let l = l.borrow();
|
||||||
let Some(i) = i.to_usize() else {
|
let Some(i) = i.to_isize() else {
|
||||||
throw!(
|
throw!(
|
||||||
*SYM_INDEX_ERROR,
|
*SYM_INDEX_ERROR,
|
||||||
"index {i} out of bounds for list of length {}",
|
"index {i} out of bounds for list of length {}",
|
||||||
l.len()
|
l.len()
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
if i < l.len() {
|
let mut j = i;
|
||||||
Ok(l[i].clone())
|
if j < 0 {
|
||||||
|
j += l.len() as isize;
|
||||||
|
}
|
||||||
|
if (0..l.len() as isize).contains(&j) {
|
||||||
|
Ok(l[j as usize].clone())
|
||||||
} else {
|
} else {
|
||||||
throw!(
|
throw!(
|
||||||
*SYM_INDEX_ERROR,
|
*SYM_INDEX_ERROR,
|
||||||
|
@ -84,15 +88,19 @@ impl Value {
|
||||||
match (self, idx) {
|
match (self, idx) {
|
||||||
(V::List(l), V::Int(i)) => {
|
(V::List(l), V::Int(i)) => {
|
||||||
let mut l = l.borrow_mut();
|
let mut l = l.borrow_mut();
|
||||||
let Some(i) = i.to_usize() else {
|
let Some(i) = i.to_isize() else {
|
||||||
throw!(
|
throw!(
|
||||||
*SYM_INDEX_ERROR,
|
*SYM_INDEX_ERROR,
|
||||||
"index {i} out of bounds for list of length {}",
|
"index {i} out of bounds for list of length {}",
|
||||||
l.len()
|
l.len()
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
if i < l.len() {
|
let mut j = i;
|
||||||
l[i] = val;
|
if j < 0 {
|
||||||
|
j += l.len() as isize;
|
||||||
|
}
|
||||||
|
if (0..l.len() as isize).contains(&j) {
|
||||||
|
l[j as usize] = val;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
throw!(
|
throw!(
|
||||||
|
|
|
@ -28,15 +28,15 @@ impl Value {
|
||||||
Value::Bool(b) => *b,
|
Value::Bool(b) => *b,
|
||||||
Value::Range(r) => !r.is_empty(),
|
Value::Range(r) => !r.is_empty(),
|
||||||
Value::Int(n) => !n.is_zero(),
|
Value::Int(n) => !n.is_zero(),
|
||||||
Value::Float(x) => *x != 0.0 && !x.is_nan(),
|
Value::Float(x) => *x != 0.0,
|
||||||
Value::Ratio(r) => !r.is_zero(),
|
Value::Ratio(r) => !r.is_zero(),
|
||||||
Value::Complex(c) => !(c.re == 0.0 && c.im == 0.0 || c.is_nan()),
|
Value::Complex(c) => !c.is_zero(),
|
||||||
Value::String(s) => !s.is_empty(),
|
Value::String(s) => !s.is_empty(),
|
||||||
Value::List(l) => l.borrow().len() > 0,
|
Value::List(l) => !l.borrow().is_empty(),
|
||||||
|
Value::Table(t) => !t.borrow().is_empty(),
|
||||||
Value::Cell(v) => v.borrow().truthy(),
|
Value::Cell(v) => v.borrow().truthy(),
|
||||||
|
|
||||||
Value::Symbol(_)
|
Value::Symbol(_)
|
||||||
| Value::Table(_)
|
|
||||||
| Value::Function(_)
|
| Value::Function(_)
|
||||||
| Value::NativeFunc(_)
|
| Value::NativeFunc(_)
|
||||||
| Value::Native(_) => true,
|
| Value::Native(_) => true,
|
||||||
|
|
|
@ -258,7 +258,7 @@ impl Vm {
|
||||||
.interrupt
|
.interrupt
|
||||||
.fetch_and(false, std::sync::atomic::Ordering::Relaxed)
|
.fetch_and(false, std::sync::atomic::Ordering::Relaxed)
|
||||||
{
|
{
|
||||||
throw!(*SYM_INTERRUPTED)
|
throw!(*SYM_INTERRUPTED, "interrupted")
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
name = "talc-macros"
|
name = "talc-macros"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
rust-version = "1.68.2"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
name = "talc-std"
|
name = "talc-std"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
rust-version = "1.81.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
talc-lang = { path = "../talc-lang" }
|
talc-lang = { path = "../talc-lang" }
|
||||||
|
|
|
@ -8,27 +8,13 @@ use talc_macros::native_func;
|
||||||
|
|
||||||
use crate::unpack_args;
|
use crate::unpack_args;
|
||||||
|
|
||||||
#[native_func(1)]
|
#[native_func(2)]
|
||||||
pub fn throw(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
pub fn throw(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
let [_, arg] = unpack_args!(args);
|
let [_, ty, msg] = unpack_args!(args);
|
||||||
let exc = match arg {
|
let (Value::Symbol(ty), Value::String(msg)) = (ty, msg) else {
|
||||||
Value::Symbol(ty) => Exception::new(ty),
|
throw!(*SYM_TYPE_ERROR, "throw expected symbol and string")
|
||||||
Value::List(l) => match l.borrow().as_slice() {
|
|
||||||
[Value::Symbol(ty)] | [Value::Symbol(ty), Value::Nil] => Exception::new(*ty),
|
|
||||||
[Value::Symbol(ty), Value::String(s)] => {
|
|
||||||
Exception::new_with_msg(*ty, s.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)
|
Err(Exception::new(ty, msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[native_func(1)]
|
#[native_func(1)]
|
||||||
|
@ -38,9 +24,9 @@ pub fn rethrow(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
if let Some(e) = Exception::from_table(&table) {
|
if let Some(e) = Exception::from_table(&table) {
|
||||||
return Err(e)
|
return Err(e)
|
||||||
}
|
}
|
||||||
throw!(*SYM_VALUE_ERROR, "argument not a valid exception")
|
throw!(*SYM_VALUE_ERROR, "rethrow: argument not a valid exception")
|
||||||
}
|
}
|
||||||
throw!(*SYM_TYPE_ERROR, "argument not a valid exception")
|
throw!(*SYM_TYPE_ERROR, "rethrow expected table")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(vm: &mut Vm) {
|
pub fn load(vm: &mut Vm) {
|
||||||
|
|
|
@ -91,6 +91,7 @@ pub fn load(vm: &mut Vm) {
|
||||||
vm.set_global_name("arg", arg().into());
|
vm.set_global_name("arg", arg().into());
|
||||||
vm.set_global_name("abs", abs().into());
|
vm.set_global_name("abs", abs().into());
|
||||||
vm.set_global_name("abs_sq", abs_sq().into());
|
vm.set_global_name("abs_sq", abs_sq().into());
|
||||||
|
vm.set_global_name("conj", conj().into());
|
||||||
|
|
||||||
vm.set_global_name("sqrt", sqrt().into());
|
vm.set_global_name("sqrt", sqrt().into());
|
||||||
vm.set_global_name("cbrt", cbrt().into());
|
vm.set_global_name("cbrt", cbrt().into());
|
||||||
|
@ -516,6 +517,18 @@ pub fn abs_sq(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[native_func(1)]
|
||||||
|
pub fn conj(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
|
let [_, x] = unpack_args!(args);
|
||||||
|
match x {
|
||||||
|
Value::Int(_) => Ok(x),
|
||||||
|
Value::Ratio(_) => Ok(x),
|
||||||
|
Value::Float(_) => Ok(x),
|
||||||
|
Value::Complex(x) => Ok(Value::Complex(x.conj())),
|
||||||
|
x => throw!(*SYM_TYPE_ERROR, "conj expected numeric argument, got {x:#}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// continuous operations
|
// continuous operations
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in a new issue