///|
fn normal(
name : String,
func : (FixedArray[Value]) -> Value raise SchemeException,
) -> (Symbol, Value) {
let name = Symbol::of(name)
(name, Primitive(Normal(name~, func)))
}
///|
fn special(p : Primitive) -> (Symbol, Value) {
(p.name(), Primitive(p))
}
///|
fn fold_args_d(
args : FixedArray[Value],
i : Int,
init : Double,
fdd : (Double, Double) -> Double,
) -> Value raise SchemeException {
let mut accd = init
for i in i.. x.to_double()
Double(x) => x
_ => raise TypeError(i)
},
)
}
Double(accd)
}
///|
fn fold_args_i(
args : FixedArray[Value],
i : Int,
init : Int,
fii : (Int, Int) -> Int,
fdd : (Double, Double) -> Double,
) -> Value raise SchemeException {
let mut acci = init
for i in i.. acci = fii(acci, x)
Double(x) =>
return fold_args_d(args, i + 1, fdd(acci.to_double(), x), fdd)
_ => raise TypeError(i)
}
}
Int(acci)
}
///|
/// `number?`
///
/// `+`, `-`, `*`, `/`
///
/// `=`, `>`, `<`
pub let number_primitive : ReadOnlyArray[(Symbol, Value)] = [
normal("number?", args => {
match args {
[Int(_) | Double(_)] => True
[_] => False
_ => raise ArgumentCount
}
}),
normal("=", args => {
match args {
[Int(a), Int(b)] => Value::bool(a == b)
[Double(a), Double(b)] => Value::bool(a == b)
[Double(a), Int(b)] => Value::bool(a == b.to_double())
[Int(a), Double(b)] => Value::bool(a.to_double() == b)
[Int(_) | Double(_), _] => raise TypeError(1)
[_, _] => raise TypeError(0)
_ => raise ArgumentCount
}
}),
normal(">", args => {
match args {
[Int(a), Int(b)] => Value::bool(a > b)
[Double(a), Double(b)] => Value::bool(a > b)
[Double(a), Int(b)] => Value::bool(a > b.to_double())
[Int(a), Double(b)] => Value::bool(a.to_double() > b)
[Int(_) | Double(_), _] => raise TypeError(1)
[_, _] => raise TypeError(0)
_ => raise ArgumentCount
}
}),
normal("<", args => {
match args {
[Int(a), Int(b)] => Value::bool(a < b)
[Double(a), Double(b)] => Value::bool(a < b)
[Double(a), Int(b)] => Value::bool(a < b.to_double())
[Int(a), Double(b)] => Value::bool(a.to_double() < b)
[Int(_) | Double(_), _] => raise TypeError(1)
[_, _] => raise TypeError(0)
_ => raise ArgumentCount
}
}),
normal("+", args => fold_args_i(args, 0, 0, Int::add, Double::add)),
normal("-", args => {
match args {
[] => raise ArgumentCount
[Int(arg0)] => Int(Int::neg(arg0))
[Double(arg0)] => Double(Double::neg(arg0))
[Int(arg0), ..] => fold_args_i(args, 1, arg0, Int::sub, Double::sub)
[Double(arg0), ..] => fold_args_d(args, 1, arg0, Double::sub)
_ => raise TypeError(0)
}
}),
normal("*", args => fold_args_i(args, 0, 1, Int::mul, Double::mul)),
normal("/", args => {
match args {
[] => raise ArgumentCount
[Int(arg0)] => Int(Int::div(1, arg0))
[Double(arg0)] => Double(Double::div(1, arg0))
[Int(arg0), ..] => fold_args_i(args, 1, arg0, Int::div, Double::div)
[Double(arg0), ..] => fold_args_d(args, 1, arg0, Double::div)
_ => raise TypeError(0)
}
}),
]
///|
/// `cons`, `car`, `cdr`
///
/// `null?`, `pair?`
pub let pair_primitive : ReadOnlyArray[(Symbol, Value)] = [
normal("car", args => {
match args {
[Pair(l, _)] => l
[_] => raise TypeError(0)
_ => raise ArgumentCount
}
}),
normal("cdr", args => {
match args {
[Pair(_, r)] => r
[_] => raise TypeError(0)
_ => raise ArgumentCount
}
}),
normal("null?", args => {
match args {
[Nil] => True
[_] => False
_ => raise ArgumentCount
}
}),
normal("pair?", args => {
match args {
[Pair(_)] => True
[_] => False
_ => raise ArgumentCount
}
}),
normal("cons", args => {
match args {
[l, r] => Pair(l, r)
_ => raise ArgumentCount
}
}),
normal("list", args => Value::list(args)),
]
///|
/// `string?`, `string-append`, `string->symbol`
///
/// `symbol->string`, `number->string`, `value->string`
pub let string_primitive : ReadOnlyArray[(Symbol, Value)] = [
normal("string?", args => {
match args {
[String(_)] => True
[_] => False
_ => raise ArgumentCount
}
}),
normal("string->symbol", args => {
match args {
[String(s)] => Value::symbol(s)
[_] => raise TypeError(0)
_ => raise ArgumentCount
}
}),
normal("symbol->string", args => {
match args {
[Symbol(x)] => String(x.to_string())
[_] => raise TypeError(0)
_ => raise ArgumentCount
}
}),
normal("number->string", args => {
match args {
[Int(x)] => String(x.to_string())
[Double(x)] => String(x.to_string())
[_] => raise TypeError(0)
_ => raise ArgumentCount
}
}),
normal("value->string", args => {
match args {
[v] => String(v.to_string())
_ => raise ArgumentCount
}
}),
normal("string-append", args => {
let b = StringBuilder::new()
for i, v in args {
guard v is String(str) else { raise TypeError(i) }
b.write_string(str)
}
String(b.to_string())
}),
]
///|
/// `vector`, `vector?`, `make-vector`, `vector-length`
///
/// `vector-ref`, `vector-set!`
pub let vector_primitive : ReadOnlyArray[(Symbol, Value)] = [
normal("vector?", args => {
match args {
[Vector(_)] => True
[_] => False
_ => raise ArgumentCount
}
}),
normal("vector-length", args => {
match args {
[Vector(v)] => Int(v.length())
[_] => raise TypeError(0)
_ => raise ArgumentCount
}
}),
normal("vector-ref", args => {
match args {
[Vector(v), Int(i)] => {
guard 0 <= i && i < v.length() else { raise InvalidArgument(1) }
v.unsafe_get(i)
}
[Vector(_), _] => raise InvalidArgument(1)
[_, _] => raise TypeError(0)
_ => raise ArgumentCount
}
}),
normal("vector-set!", args => {
match args {
[Vector(v), Int(i), x] => {
guard 0 <= i && i < v.length() else { raise InvalidArgument(1) }
v[i] = x
Value::default()
}
[Vector(_), _, _] => raise InvalidArgument(1)
[_, _, _] => raise TypeError(0)
_ => raise ArgumentCount
}
}),
normal("vector", args => Vector(args)),
normal("make-vector", args => {
match args {
[n] => {
guard n is Int(n) else { raise TypeError(0) }
guard n >= 0 else { raise InvalidArgument(0) }
Vector(FixedArray::make(n, Int(0)))
}
[n, init] => {
guard n is Int(n) else { raise TypeError(0) }
guard n >= 0 else { raise InvalidArgument(0) }
Vector(FixedArray::make(n, init))
}
_ => raise ArgumentCount
}
}),
]
///|
/// `eq?`, `procedure?`, `symbol?`
///
/// `call/cc`, `apply`
pub let other_primitive : ReadOnlyArray[(Symbol, Value)] = [
normal("symbol?", args => {
match args {
[Symbol(_)] => True
[_] => False
_ => raise ArgumentCount
}
}),
normal("procedure?", args => {
match args {
[Primitive(_) | Closure(_) | Continuation(_)] => True
[_] => False
_ => raise ArgumentCount
}
}),
normal("eq?", args => {
match args {
[a, b] => Value::bool(a.eq(b))
_ => raise ArgumentCount
}
}),
special(CallCC),
special(Apply),
]
///|
pub let all_base_primitive : ReadOnlyArray[(Symbol, Value)] = [|
..number_primitive, ..pair_primitive, ..string_primitive, ..vector_primitive,
..other_primitive,
|]
|> ReadOnlyArray::from_iter