2019-12-08 23:07:41 +03:00
|
|
|
const std = @import("std");
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
const Allocator = std.heap.c_allocator;
|
2019-12-08 23:07:41 +03:00
|
|
|
|
|
|
|
const MalType = @import("types.zig").MalType;
|
|
|
|
const printer = @import("printer.zig");
|
|
|
|
const reader = @import("reader.zig");
|
2024-09-19 00:52:55 +03:00
|
|
|
const getline_prompt = @import("readline.zig").getline;
|
|
|
|
const string_eql = std.hash_map.eqlString;
|
2019-12-08 23:07:41 +03:00
|
|
|
|
|
|
|
const MalError = @import("error.zig").MalError;
|
|
|
|
|
|
|
|
const hmap = @import("hmap.zig");
|
|
|
|
|
|
|
|
const MalLinkedList = @import("linked_list.zig").MalLinkedList;
|
|
|
|
const MalHashMap = @import("hmap.zig").MalHashMap;
|
2024-09-19 00:52:55 +03:00
|
|
|
|
|
|
|
// Set by the step file at startup.
|
|
|
|
pub var apply_function: *const fn(f: MalType, args: []*MalType) MalError!*MalType = undefined;
|
2019-12-08 23:07:41 +03:00
|
|
|
|
|
|
|
const safeAdd = @import("std").math.add;
|
|
|
|
const safeSub = @import("std").math.sub;
|
|
|
|
const safeMul = @import("std").math.mul;
|
|
|
|
const safeDivFloor = @import("std").math.divFloor;
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
const stdout_file = std.io.getStdOut();
|
|
|
|
const throw = @import("error.zig").throw;
|
|
|
|
|
|
|
|
fn int_plus(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
2019-12-08 23:07:41 +03:00
|
|
|
const x = try a1.as_int();
|
|
|
|
const y = try a2.as_int();
|
2024-09-19 00:52:55 +03:00
|
|
|
const res = try safeAdd(i64, x, y);
|
|
|
|
return MalType.new_int(res);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn int_minus(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
2019-12-08 23:07:41 +03:00
|
|
|
const x = try a1.as_int();
|
|
|
|
const y = try a2.as_int();
|
2024-09-19 00:52:55 +03:00
|
|
|
const res = try safeSub(i64, x, y);
|
|
|
|
return MalType.new_int(res);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn int_mult(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
2019-12-08 23:07:41 +03:00
|
|
|
const x = try a1.as_int();
|
|
|
|
const y = try a2.as_int();
|
2024-09-19 00:52:55 +03:00
|
|
|
const res = try safeMul(i64, x, y);
|
|
|
|
return MalType.new_int(res);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn int_div(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
2019-12-08 23:07:41 +03:00
|
|
|
const x = try a1.as_int();
|
|
|
|
const y = try a2.as_int();
|
2024-09-19 00:52:55 +03:00
|
|
|
const res = try safeDivFloor(i64, x, y);
|
|
|
|
return MalType.new_int(res);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn int_lt(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
|
|
|
return MalType.new_bool((try a1.as_int()) < (try a2.as_int()));
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn int_leq(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
|
|
|
return MalType.new_bool((try a1.as_int()) <= (try a2.as_int()));
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn int_gt(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
|
|
|
return MalType.new_bool((try a1.as_int()) > (try a2.as_int()));
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn int_geq(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
|
|
|
return MalType.new_bool((try a1.as_int()) >= (try a2.as_int()));
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn _linked_list_equality(l1: []const *MalType, l2:[]const *MalType) bool {
|
|
|
|
if(l1.len != l2.len) return false;
|
|
|
|
for(l1, l2) |m1, m2| {
|
|
|
|
if(! _equality(m1.*, m2.*)) {
|
2019-12-08 23:07:41 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn _hashmap_equality(h1: MalHashMap, h2: MalHashMap) bool {
|
2019-12-08 23:07:41 +03:00
|
|
|
if(h1.count() != h2.count()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
var iterator = h1.iterator();
|
2024-09-19 00:52:55 +03:00
|
|
|
while(iterator.next()) |pair| {
|
|
|
|
const optional_val = h2.get(pair.key_ptr.*);
|
2019-12-08 23:07:41 +03:00
|
|
|
if(optional_val) |val| {
|
2024-09-19 00:52:55 +03:00
|
|
|
const el_cmp = _equality(pair.value_ptr.*.*, val.*);
|
|
|
|
if(! el_cmp) {
|
2019-12-08 23:07:41 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn equality(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
|
|
|
return MalType.new_bool(_equality(a1.*, a2.*));
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn _equality(a1: MalType, a2: MalType) bool {
|
|
|
|
switch(a1) {
|
|
|
|
.Nil => {
|
|
|
|
switch(a2) {
|
|
|
|
.Nil => return true,
|
|
|
|
else => return false,
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
},
|
2024-09-19 00:52:55 +03:00
|
|
|
.False => {
|
|
|
|
switch(a2) {
|
|
|
|
.False => return true,
|
|
|
|
else => return false,
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
},
|
2024-09-19 00:52:55 +03:00
|
|
|
.True => {
|
|
|
|
switch(a2) {
|
|
|
|
.True => return true,
|
|
|
|
else => return false,
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
},
|
2024-09-19 00:52:55 +03:00
|
|
|
.Int => |l1| {
|
|
|
|
switch(a2) {
|
|
|
|
.Int => |l2| return l1.data == l2.data,
|
|
|
|
else => return false,
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
},
|
|
|
|
.String => |s1| {
|
2024-09-19 00:52:55 +03:00
|
|
|
switch(a2) {
|
|
|
|
.String => |s2| return string_eql(s1.data, s2.data),
|
|
|
|
else => return false,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
.Symbol => |s1| {
|
|
|
|
switch(a2) {
|
|
|
|
.Symbol => |s2| return string_eql(s1.data, s2.data),
|
|
|
|
else => return false,
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
},
|
2024-09-19 00:52:55 +03:00
|
|
|
.Keyword => |s1| {
|
|
|
|
switch(a2) {
|
|
|
|
.Keyword => |s2| return string_eql(s1.data, s2.data),
|
|
|
|
else => return false,
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
},
|
2024-09-19 00:52:55 +03:00
|
|
|
.List, .Vector => |l1| {
|
|
|
|
switch(a2) {
|
|
|
|
.List, .Vector => |l2| return _linked_list_equality(
|
|
|
|
l1.data.items, l2.data.items),
|
|
|
|
else => return false,
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
},
|
|
|
|
.HashMap => |h1| {
|
2024-09-19 00:52:55 +03:00
|
|
|
switch(a2) {
|
|
|
|
.HashMap => |h2| return _hashmap_equality(h1.data, h2.data),
|
|
|
|
else => return false,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
else => {
|
|
|
|
return false;
|
2019-12-08 23:07:41 +03:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn list(args: []*MalType) !*MalType {
|
|
|
|
const new_mal = try MalType.new_list();
|
|
|
|
errdefer new_mal.decref();
|
|
|
|
for(args) |x| {
|
|
|
|
try new_mal.List.data.append(Allocator, x);
|
|
|
|
x.incref();
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
return new_mal;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn vector(args: []*MalType) !*MalType {
|
|
|
|
const new_mal = try MalType.new_vector();
|
|
|
|
errdefer new_mal.decref();
|
|
|
|
for(args) |x| {
|
|
|
|
try new_mal.Vector.data.append(Allocator, x);
|
|
|
|
x.incref();
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
return new_mal;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn map(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const func_mal = args[0];
|
|
|
|
const args_mal = args[1];
|
|
|
|
var to_map_ll = try args_mal.as_slice();
|
|
|
|
const new_list = try MalType.new_list();
|
|
|
|
errdefer new_list.decref();
|
|
|
|
for(0..to_map_ll.len) |i| {
|
|
|
|
const new_mal = try apply_function(func_mal.*, to_map_ll[i..i+1]);
|
|
|
|
try new_list.List.data.append(Allocator, new_mal);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
return new_list;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_list(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
return switch(a1.*) {
|
|
|
|
.List => &MalType.TRUE,
|
|
|
|
else => &MalType.FALSE,
|
|
|
|
};
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_vector(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
return switch(a1.*) {
|
|
|
|
.Vector => &MalType.TRUE,
|
|
|
|
else => &MalType.FALSE,
|
|
|
|
};
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_string(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
return switch(a1.*) {
|
|
|
|
.String => &MalType.TRUE,
|
|
|
|
else => &MalType.FALSE,
|
|
|
|
};
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_number(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
return switch(a1.*) {
|
|
|
|
.Int => &MalType.TRUE,
|
|
|
|
else => &MalType.FALSE,
|
|
|
|
};
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_fn(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const is_function = switch(a1.*) {
|
|
|
|
.FnCore => true,
|
|
|
|
.Func => |func_data| ! func_data.is_macro,
|
2019-12-08 23:07:41 +03:00
|
|
|
else => false,
|
|
|
|
};
|
2024-09-19 00:52:55 +03:00
|
|
|
return MalType.new_bool(is_function);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_macro(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const is_func_and_macro = switch(a1.*) {
|
2019-12-08 23:07:41 +03:00
|
|
|
.Func => |data| data.is_macro,
|
|
|
|
else => false,
|
|
|
|
};
|
2024-09-19 00:52:55 +03:00
|
|
|
return MalType.new_bool(is_func_and_macro);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn empty(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const slice = try a1.as_slice();
|
|
|
|
return MalType.new_bool(slice.len == 0);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn prn(args: []*MalType) MalError!*MalType {
|
2019-12-08 23:07:41 +03:00
|
|
|
const s = try printer.print_mal_to_string(args, true, true);
|
2024-09-19 00:52:55 +03:00
|
|
|
defer Allocator.free(s);
|
|
|
|
try stdout_file.writeAll(s);
|
|
|
|
try stdout_file.writeAll("\n");
|
|
|
|
const mal = &MalType.NIL;
|
2019-12-08 23:07:41 +03:00
|
|
|
return mal;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn println(args: []*MalType) !*MalType {
|
2019-12-08 23:07:41 +03:00
|
|
|
const s = try printer.print_mal_to_string(args, false, true);
|
2024-09-19 00:52:55 +03:00
|
|
|
defer Allocator.free(s);
|
|
|
|
try stdout_file.writeAll(s);
|
|
|
|
try stdout_file.writeAll("\n");
|
|
|
|
const mal = &MalType.NIL;
|
2019-12-08 23:07:41 +03:00
|
|
|
return mal;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn str(args: []*MalType) !*MalType {
|
|
|
|
const items = try printer.print_mal_to_string(args, false, false);
|
|
|
|
return MalType.new_string(items, false);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn pr_str(args: []*MalType) !*MalType {
|
2019-12-08 23:07:41 +03:00
|
|
|
const s = try printer.print_mal_to_string(args, true, true);
|
2024-09-19 00:52:55 +03:00
|
|
|
return MalType.new_string(s, false);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn slurp(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const path = try a1.as_string();
|
|
|
|
const dir = std.fs.cwd();
|
|
|
|
const items = try dir.readFileAlloc(Allocator, path, 10000);
|
|
|
|
return MalType.new_string(items, false);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn atom(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const result = try MalType.new_atom(a1);
|
|
|
|
a1.incref();
|
|
|
|
return result;
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_atom(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
return switch(args[0].*) {
|
|
|
|
.Atom => &MalType.TRUE,
|
|
|
|
else => &MalType.FALSE,
|
|
|
|
};
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn deref(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
switch(a1.*) {
|
|
|
|
.Atom => |atom_val| {
|
|
|
|
atom_val.data.incref();
|
|
|
|
return atom_val.data;
|
|
|
|
},
|
|
|
|
else => return MalError.TypeError,
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn atom_reset(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
|
|
|
switch(a1.*) {
|
2019-12-08 23:07:41 +03:00
|
|
|
.Atom => |*atom_val| {
|
2024-09-19 00:52:55 +03:00
|
|
|
atom_val.data.decref();
|
|
|
|
atom_val.data = a2;
|
|
|
|
// incref for the atom and for the result
|
|
|
|
a2.incref();
|
|
|
|
a2.incref();
|
|
|
|
return a2;
|
2019-12-08 23:07:41 +03:00
|
|
|
},
|
|
|
|
else => return MalError.TypeError,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn atom_swap(args: []*MalType) !*MalType {
|
2019-12-08 23:07:41 +03:00
|
|
|
const n = args.len;
|
|
|
|
if(n < 2) return MalError.ArgError;
|
2024-09-19 00:52:55 +03:00
|
|
|
|
|
|
|
const atom_val = switch(args[0].*) {
|
|
|
|
.Atom => |*a| a,
|
|
|
|
else => return MalError.TypeError,
|
|
|
|
};
|
|
|
|
|
|
|
|
var new_args = try Allocator.alloc(*MalType, args.len - 1);
|
|
|
|
defer Allocator.free(new_args);
|
|
|
|
var i:usize = 0;
|
|
|
|
new_args[i] = atom_val.data; i+=1;
|
|
|
|
for(args[2..args.len]) |x| {
|
|
|
|
new_args[i] = x;
|
2019-12-08 23:07:41 +03:00
|
|
|
i += 1;
|
|
|
|
}
|
2024-09-19 00:52:55 +03:00
|
|
|
std.debug.assert(i == new_args.len);
|
|
|
|
|
|
|
|
const new_mal = try apply_function(args[1].*, new_args);
|
|
|
|
atom_val.data.decref(); // after the computation
|
|
|
|
atom_val.data = new_mal;
|
|
|
|
new_mal.incref();
|
2019-12-08 23:07:41 +03:00
|
|
|
return new_mal;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn vec(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
switch(a1.*) {
|
|
|
|
.List => |l| {
|
|
|
|
const result = try MalType.new_vector();
|
|
|
|
errdefer result.decref();
|
|
|
|
for(l.data.items) |x| {
|
|
|
|
try result.Vector.data.append(Allocator, x);
|
|
|
|
x.incref();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
},
|
|
|
|
.Vector => {
|
|
|
|
a1.incref();
|
|
|
|
return a1;
|
|
|
|
},
|
|
|
|
else => return MalError.TypeError,
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn cons(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
|
|
|
const old_ll = try a2.as_slice();
|
|
|
|
const new_list = try MalType.new_list();
|
|
|
|
errdefer new_list.decref();
|
|
|
|
try new_list.List.data.append(Allocator, a1);
|
|
|
|
a1.incref();
|
|
|
|
for(old_ll) |x| {
|
|
|
|
try new_list.List.data.append(Allocator, x);
|
|
|
|
x.incref();
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
2024-09-19 00:52:55 +03:00
|
|
|
return new_list;
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
pub fn concat(args: []*MalType) !*MalType {
|
|
|
|
const new_mal = try MalType.new_list();
|
|
|
|
errdefer new_mal.decref();
|
|
|
|
for(args) |x| {
|
|
|
|
for(try x.as_slice()) |y| {
|
|
|
|
try new_mal.List.data.append(Allocator, y);
|
|
|
|
y.incref();
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
return new_mal;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn rest(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const new_mal = try MalType.new_list();
|
|
|
|
errdefer new_mal.decref();
|
|
|
|
switch(a1.*) {
|
|
|
|
.List, .Vector => |l| {
|
|
|
|
const old_list = l.data.items;
|
|
|
|
if(old_list.len != 0) {
|
|
|
|
for(l.data.items[1..]) |x| {
|
|
|
|
try new_mal.List.data.append(Allocator, x);
|
|
|
|
x.incref();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
.Nil => { },
|
2019-12-08 23:07:41 +03:00
|
|
|
else => return MalError.TypeError,
|
|
|
|
}
|
|
|
|
return new_mal;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn nth(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
|
|
|
const l = try a1.as_slice();
|
|
|
|
const i = try a2.as_int();
|
|
|
|
const pos: usize = @intCast(i);
|
|
|
|
if(pos < 0 or l.len <= pos) {
|
2019-12-08 23:07:41 +03:00
|
|
|
return MalError.OutOfBounds;
|
|
|
|
}
|
2024-09-19 00:52:55 +03:00
|
|
|
const result = l[pos];
|
|
|
|
result.incref();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn first(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
switch(a1.*) {
|
|
|
|
.List, .Vector => |l| {
|
|
|
|
if(l.data.items.len == 0) return &MalType.NIL;
|
|
|
|
const result = l.data.items[0];
|
|
|
|
result.incref();
|
|
|
|
return result;
|
|
|
|
},
|
|
|
|
.Nil => return &MalType.NIL,
|
|
|
|
else => return MalError.TypeError,
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_nil(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
return switch(a1.*) {
|
|
|
|
.Nil => &MalType.TRUE,
|
|
|
|
else => &MalType.FALSE,
|
2019-12-08 23:07:41 +03:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_true(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
return switch(a1.*) {
|
|
|
|
.True => &MalType.TRUE,
|
|
|
|
else => &MalType.FALSE,
|
2019-12-08 23:07:41 +03:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_false(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
return switch(a1.*) {
|
|
|
|
.False => &MalType.TRUE,
|
|
|
|
else => &MalType.FALSE,
|
|
|
|
};
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_symbol(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
return switch(a1.*) {
|
|
|
|
.Symbol => &MalType.TRUE,
|
|
|
|
else => &MalType.FALSE,
|
|
|
|
};
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_keyword(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
return switch(a1.*) {
|
|
|
|
.Keyword => &MalType.TRUE,
|
|
|
|
else => &MalType.FALSE,
|
|
|
|
};
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_map(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
return switch(a1.*) {
|
|
|
|
.HashMap => &MalType.TRUE,
|
|
|
|
else => &MalType.FALSE,
|
|
|
|
};
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn is_sequential(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
return switch(a1.*) {
|
|
|
|
.List, .Vector => &MalType.TRUE,
|
|
|
|
else => &MalType.FALSE,
|
|
|
|
};
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn symbol(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const string = try a1.as_string();
|
|
|
|
return MalType.new_symbol(string, true);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
pub fn hash_map(args: []*MalType) !*MalType {
|
|
|
|
const new_mal = try MalType.new_hashmap();
|
|
|
|
errdefer new_mal.decref();
|
|
|
|
try hmap.map_insert_from_kvs(&new_mal.HashMap.data, args);
|
2019-12-08 23:07:41 +03:00
|
|
|
return new_mal;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
pub fn hash_map_assoc(args: []*MalType) !*MalType {
|
|
|
|
if(args.len < 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const new_mal = try MalType.new_hashmap();
|
|
|
|
errdefer new_mal.decref();
|
|
|
|
const base_hmap = try a1.as_map();
|
|
|
|
try hmap.map_insert_from_map(&new_mal.HashMap.data, base_hmap);
|
|
|
|
try hmap.map_insert_from_kvs(&new_mal.HashMap.data, args[1..]);
|
2019-12-08 23:07:41 +03:00
|
|
|
return new_mal;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
pub fn hash_map_dissoc(args: []*MalType) !*MalType {
|
|
|
|
if(args.len < 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const new_mal = try MalType.new_hashmap();
|
|
|
|
errdefer new_mal.decref();
|
|
|
|
const base_hmap = try a1.as_map();
|
|
|
|
try hmap.map_insert_from_map(&new_mal.HashMap.data, base_hmap);
|
|
|
|
for(args[1..]) |k| {
|
|
|
|
switch(k.*) {
|
|
|
|
.Keyword, .String => {
|
|
|
|
if(new_mal.HashMap.data.fetchRemove(k)) |old| {
|
|
|
|
old.key.decref();
|
|
|
|
old.value.decref();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
else => return MalError.TypeError,
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
return new_mal;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn hash_map_get(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
|
|
|
const hm = switch(a1.*) {
|
|
|
|
.HashMap => |m| m.data,
|
|
|
|
.Nil => return &MalType.NIL,
|
2019-12-08 23:07:41 +03:00
|
|
|
else => return MalError.TypeError,
|
|
|
|
};
|
2024-09-19 00:52:55 +03:00
|
|
|
switch(a2.*) {
|
|
|
|
.Keyword, .String => {},
|
|
|
|
else => return MalError.TypeError,
|
|
|
|
}
|
|
|
|
if(hm.get(a2)) |value| {
|
|
|
|
value.incref();
|
|
|
|
return value;
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
2024-09-19 00:52:55 +03:00
|
|
|
return &MalType.NIL;
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn hash_map_contains(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
|
|
|
switch(a2.*) {
|
|
|
|
.Keyword, .String => {
|
|
|
|
const hm = try a1.as_map();
|
|
|
|
return MalType.new_bool(hm.contains(a2));
|
|
|
|
},
|
2019-12-08 23:07:41 +03:00
|
|
|
else => return MalError.TypeError,
|
2024-09-19 00:52:55 +03:00
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn hash_map_keys(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const hm = try a1.as_map();
|
|
|
|
const new_mal = try MalType.new_list();
|
|
|
|
errdefer new_mal.decref();
|
|
|
|
var iterator = hm.keyIterator();
|
|
|
|
while(iterator.next()) |key_mal| {
|
|
|
|
try new_mal.List.data.append(Allocator, key_mal.*);
|
|
|
|
key_mal.*.incref();
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
return new_mal;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn hash_map_vals(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const hm = try a1.as_map();
|
|
|
|
const new_mal = try MalType.new_list();
|
|
|
|
errdefer new_mal.decref();
|
|
|
|
var iterator = hm.valueIterator();
|
|
|
|
while(iterator.next()) |val| {
|
|
|
|
try new_mal.List.data.append(Allocator, val.*);
|
|
|
|
val.*.incref();
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
return new_mal;
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn sequence_length(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const len = switch(a1.*) {
|
|
|
|
.List, .Vector => |l| l.data.items.len,
|
|
|
|
.String => |s| s.data.len,
|
2019-12-08 23:07:41 +03:00
|
|
|
.Nil => 0,
|
|
|
|
else => return MalError.TypeError,
|
|
|
|
};
|
2024-09-19 00:52:55 +03:00
|
|
|
return MalType.new_int(@intCast(len));
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn keyword(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
switch(a1.*) {
|
|
|
|
.String => |s| {
|
|
|
|
return MalType.new_keyword(s.data, true);
|
|
|
|
},
|
|
|
|
.Keyword => {
|
|
|
|
a1.incref();
|
|
|
|
return a1;
|
|
|
|
},
|
2019-12-08 23:07:41 +03:00
|
|
|
else => return MalError.TypeError,
|
2024-09-19 00:52:55 +03:00
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn core_readline(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
2019-12-08 23:07:41 +03:00
|
|
|
const prompt = try a1.as_string();
|
2024-09-19 00:52:55 +03:00
|
|
|
const optional_read_line = try getline_prompt(prompt);
|
2019-12-08 23:07:41 +03:00
|
|
|
if(optional_read_line) |read_line| {
|
2024-09-19 00:52:55 +03:00
|
|
|
return MalType.new_string(read_line, false);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
2024-09-19 00:52:55 +03:00
|
|
|
return &MalType.NIL;
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn time_ms(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 0) return MalError.ArgError;
|
|
|
|
const itime = std.time.milliTimestamp();
|
|
|
|
return try MalType.new_int(@intCast(itime));
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn meta(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const result = switch(a1.*) {
|
|
|
|
.List, .Vector => |l| l.metadata,
|
|
|
|
.FnCore => |l| l.metadata,
|
|
|
|
.Func => |l| l.metadata,
|
|
|
|
.HashMap => |l| l.metadata,
|
|
|
|
else => return MalError.TypeError,
|
|
|
|
};
|
|
|
|
result.incref();
|
|
|
|
return result;
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn with_meta(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const a2 = args[1];
|
|
|
|
switch(a1.*) {
|
|
|
|
.List => |l| {
|
|
|
|
const new_mal = try MalType.new_list();
|
|
|
|
errdefer new_mal.decref();
|
|
|
|
for(l.data.items) |x| {
|
|
|
|
try new_mal.List.data.append(Allocator, x);
|
|
|
|
x.incref();
|
|
|
|
}
|
|
|
|
new_mal.List.metadata = a2;
|
|
|
|
a2.incref();
|
|
|
|
return new_mal;
|
|
|
|
},
|
|
|
|
.Vector => |l| {
|
|
|
|
const new_mal = try MalType.new_vector();
|
|
|
|
errdefer new_mal.decref();
|
|
|
|
for(l.data.items) |x| {
|
|
|
|
try new_mal.Vector.data.append(Allocator, x);
|
|
|
|
x.incref();
|
|
|
|
}
|
|
|
|
new_mal.Vector.metadata = a2;
|
|
|
|
a2.incref();
|
|
|
|
return new_mal;
|
|
|
|
},
|
|
|
|
.FnCore => |l| {
|
|
|
|
const new_mal = try MalType.newFnCore(l.data);
|
|
|
|
new_mal.FnCore.metadata = a2;
|
|
|
|
a2.incref();
|
|
|
|
return new_mal;
|
|
|
|
},
|
|
|
|
.Func => |l| {
|
|
|
|
const new_mal = try MalType.newFunc(l.arg_list, l.body,
|
|
|
|
l.environment);
|
|
|
|
l.arg_list.incref();
|
|
|
|
l.body.incref();
|
|
|
|
l.environment.incref();
|
|
|
|
new_mal.Func.metadata = a2;
|
|
|
|
a2.incref();
|
|
|
|
return new_mal;
|
|
|
|
},
|
|
|
|
.HashMap => |l| {
|
|
|
|
const new_mal = try MalType.new_hashmap();
|
|
|
|
errdefer new_mal.decref();
|
|
|
|
try hmap.map_insert_from_map(&new_mal.HashMap.data, l.data);
|
|
|
|
new_mal.HashMap.metadata = a2;
|
|
|
|
a2.incref();
|
|
|
|
return new_mal;
|
|
|
|
},
|
|
|
|
else => return MalError.TypeError,
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn seq(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
switch(a1.*) {
|
2019-12-08 23:07:41 +03:00
|
|
|
.List => |l| {
|
2024-09-19 00:52:55 +03:00
|
|
|
if(l.data.items.len == 0) return &MalType.NIL;
|
|
|
|
a1.incref();
|
|
|
|
return a1;
|
2019-12-08 23:07:41 +03:00
|
|
|
},
|
2024-09-19 00:52:55 +03:00
|
|
|
.Vector => |l| {
|
|
|
|
if(l.data.items.len == 0) return &MalType.NIL;
|
|
|
|
const mal_copy = try MalType.new_list();
|
|
|
|
errdefer mal_copy.decref();
|
|
|
|
for(l.data.items) |x| {
|
|
|
|
try mal_copy.List.data.append(Allocator, x);
|
|
|
|
x.incref();
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
return mal_copy;
|
|
|
|
},
|
|
|
|
.String => |s| {
|
2024-09-19 00:52:55 +03:00
|
|
|
if(s.data.len == 0) return &MalType.NIL;
|
|
|
|
const new_list = try MalType.new_list();
|
|
|
|
errdefer new_list.decref();
|
|
|
|
for(s.data) |x| {
|
|
|
|
const one_char = try Allocator.alloc(u8, 1);
|
|
|
|
one_char[0] = x;
|
|
|
|
const new_char = try MalType.new_string(one_char, false);
|
|
|
|
errdefer new_char.decref();
|
|
|
|
try new_list.List.data.append(Allocator, new_char);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
return new_list;
|
|
|
|
},
|
|
|
|
.Nil => {
|
2024-09-19 00:52:55 +03:00
|
|
|
return &MalType.NIL;
|
2019-12-08 23:07:41 +03:00
|
|
|
},
|
|
|
|
else => {
|
|
|
|
return MalError.TypeError;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
pub fn conj(args: []*MalType) !*MalType {
|
|
|
|
if(args.len == 0) return MalError.ArgError;
|
|
|
|
const container = args[0];
|
|
|
|
switch(container.*) {
|
|
|
|
.List => |l| {
|
|
|
|
const return_mal = try MalType.new_list();
|
|
|
|
errdefer return_mal.decref();
|
|
|
|
for(1..args.len) |j| {
|
|
|
|
const new_item = args[args.len-j];
|
|
|
|
try return_mal.List.data.append(Allocator, new_item);
|
|
|
|
new_item.incref();
|
|
|
|
}
|
|
|
|
for(l.data.items) |x| {
|
|
|
|
try return_mal.List.data.append(Allocator, x);
|
|
|
|
x.incref();
|
|
|
|
}
|
|
|
|
return return_mal;
|
|
|
|
},
|
|
|
|
.Vector => |l|{
|
|
|
|
const return_mal = try MalType.new_vector();
|
|
|
|
errdefer return_mal.decref();
|
|
|
|
for(l.data.items) |x| {
|
|
|
|
try return_mal.Vector.data.append(Allocator, x);
|
|
|
|
x.incref();
|
|
|
|
}
|
|
|
|
for(args[1..]) |x| {
|
|
|
|
try return_mal.Vector.data.append(Allocator, x);
|
|
|
|
x.incref();
|
|
|
|
}
|
|
|
|
return return_mal;
|
|
|
|
},
|
2019-12-08 23:07:41 +03:00
|
|
|
else => return MalError.ArgError,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
fn read_string(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
2019-12-08 23:07:41 +03:00
|
|
|
const str_to_eval = try a1.as_string();
|
|
|
|
var read = try reader.read_str(str_to_eval);
|
2024-09-19 00:52:55 +03:00
|
|
|
return reader.read_form(&read);
|
2019-12-08 23:07:41 +03:00
|
|
|
}
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
pub fn do_apply(args: []*MalType) !*MalType {
|
|
|
|
if(args.len < 2) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
const last = args[args.len - 1];
|
|
|
|
const more_args = try last.as_slice();
|
|
|
|
var fargs = try Allocator.alloc(*MalType, args.len + more_args.len - 2);
|
|
|
|
defer Allocator.free(fargs);
|
|
|
|
var i:usize = 0;
|
|
|
|
for(args[1..args.len-1]) |x| { fargs[i] = x; i+=1; }
|
|
|
|
for(more_args) |x| { fargs[i] = x; i+=1; }
|
|
|
|
std.debug.assert(i == fargs.len);
|
|
|
|
return apply_function(a1.*, fargs);
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
pub fn core_throw(args: []*MalType) !*MalType {
|
|
|
|
if(args.len != 1) return MalError.ArgError;
|
|
|
|
const a1 = args[0];
|
|
|
|
return throw(a1);
|
|
|
|
}
|
2019-12-08 23:07:41 +03:00
|
|
|
|
|
|
|
pub const CorePair = struct {
|
|
|
|
name: []const u8,
|
2024-09-19 00:52:55 +03:00
|
|
|
func: *const fn(args: []*MalType) MalError!*MalType,
|
2019-12-08 23:07:41 +03:00
|
|
|
};
|
|
|
|
|
2024-09-19 00:52:55 +03:00
|
|
|
pub const core_namespace = [_]CorePair {
|
|
|
|
.{ .name = "+", .func = &int_plus },
|
|
|
|
.{ .name = "-", .func = &int_minus },
|
|
|
|
.{ .name = "*", .func = &int_mult },
|
|
|
|
.{ .name = "/", .func = &int_div },
|
|
|
|
.{ .name = "<", .func = &int_lt },
|
|
|
|
.{ .name = "<=", .func = &int_leq },
|
|
|
|
.{ .name = ">", .func = &int_gt },
|
|
|
|
.{ .name = ">=", .func = &int_geq },
|
|
|
|
.{ .name = "=", .func = &equality },
|
|
|
|
.{ .name = "list?", .func = &is_list },
|
|
|
|
.{ .name = "vector?", .func = &is_vector },
|
|
|
|
.{ .name = "count", .func = &sequence_length },
|
|
|
|
.{ .name = "list", .func = &list, },
|
|
|
|
.{ .name = "vector", .func = &vector, },
|
|
|
|
.{ .name = "map", .func = &map },
|
|
|
|
.{ .name = "empty?", .func = &empty },
|
|
|
|
.{ .name = "prn", .func = &prn },
|
|
|
|
.{ .name = "println", .func = &println },
|
|
|
|
.{ .name = "pr-str", .func = &pr_str },
|
|
|
|
.{ .name = "str", .func = &str },
|
|
|
|
.{ .name = "slurp", .func = &slurp },
|
|
|
|
.{ .name = "atom", .func = &atom },
|
|
|
|
.{ .name = "atom?", .func = &is_atom },
|
|
|
|
.{ .name = "deref", .func = &deref },
|
|
|
|
.{ .name = "reset!", .func = &atom_reset },
|
|
|
|
.{ .name = "swap!", .func = &atom_swap },
|
|
|
|
.{ .name = "vec", .func = &vec },
|
|
|
|
.{ .name = "cons", .func = &cons },
|
|
|
|
.{ .name = "concat", .func = &concat },
|
|
|
|
.{ .name = "rest", .func = &rest },
|
|
|
|
.{ .name = "nth", .func = &nth },
|
|
|
|
.{ .name = "first", .func = &first },
|
|
|
|
.{ .name = "nil?", .func = &is_nil },
|
|
|
|
.{ .name = "true?", .func = &is_true },
|
|
|
|
.{ .name = "false?", .func = &is_false },
|
|
|
|
.{ .name = "symbol", .func = &symbol },
|
|
|
|
.{ .name = "symbol?", .func = &is_symbol },
|
|
|
|
.{ .name = "keyword?", .func = &is_keyword },
|
|
|
|
.{ .name = "map?", .func = &is_map },
|
|
|
|
.{ .name = "sequential?", .func = &is_sequential },
|
|
|
|
.{ .name = "apply", .func = &do_apply },
|
|
|
|
.{ .name = "hash-map", .func = &hash_map },
|
|
|
|
.{ .name = "assoc", .func = &hash_map_assoc },
|
|
|
|
.{ .name = "dissoc", .func = &hash_map_dissoc },
|
|
|
|
.{ .name = "get", .func = &hash_map_get },
|
|
|
|
.{ .name = "contains?", .func = &hash_map_contains },
|
|
|
|
.{ .name = "keys", .func = &hash_map_keys },
|
|
|
|
.{ .name = "vals", .func = &hash_map_vals },
|
|
|
|
.{ .name = "keyword", .func = &keyword },
|
|
|
|
.{ .name = "read-string", .func = &read_string },
|
|
|
|
.{ .name = "readline", .func = &core_readline },
|
|
|
|
.{ .name = "time-ms", .func = &time_ms },
|
|
|
|
.{ .name = "meta", .func = &meta },
|
|
|
|
.{ .name = "with-meta", .func = &with_meta },
|
|
|
|
.{ .name = "fn?", .func = &is_fn },
|
|
|
|
.{ .name = "string?", .func = &is_string },
|
|
|
|
.{ .name = "number?", .func = &is_number },
|
|
|
|
.{ .name = "macro?", .func = &is_macro },
|
|
|
|
.{ .name = "seq", .func = &seq },
|
|
|
|
.{ .name = "conj", .func = &conj },
|
|
|
|
.{ .name = "throw", .func = &core_throw },
|
2019-12-08 23:07:41 +03:00
|
|
|
};
|