blob: 80fb4ae438d54c9c5d0768895f6f4ba3dc17ea4a (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
const std = @import("std");
const value = @import("../value.zig");
const Value = value.Value;
// Zig API
/// Checks for a Zisp fixnum.
pub fn check(v: Value) bool {
return v.isFixnum();
}
/// Asserts check().
pub fn assert(v: Value) void {
if (!check(v)) {
v.dump();
@panic("not fixnum");
}
}
// See detailed NaN packing docs for why the +/- 1.
pub const min = std.math.minInt(i52) + 1;
pub const max = std.math.maxInt(i52) - 1;
fn assertValidRange(int: i64) void {
if (int < min) {
std.debug.print("int too small for fixnum: {}\n", .{int});
@panic("int too small for fixnum");
}
if (int > max) {
std.debug.print("int too large for fixnum: {}\n", .{int});
@panic("int too large for fixnum");
}
}
fn packNegative(int: i64) Value {
return @bitCast(int);
}
fn unpackNegative(v: Value) i64 {
return @bitCast(v);
}
const positive_mask: u64 = 0xfff7ffffffffffff;
fn packPositive(int: i64) Value {
const uint: u64 = @bitCast(int);
return @bitCast(uint ^ positive_mask);
}
fn unpackPositive(v: Value) i64 {
const uint: u64 = @bitCast(v);
return @bitCast(uint ^ positive_mask);
}
pub fn pack(int: i64) Value {
assertValidRange(int);
if (int < 0) {
return packNegative(int);
} else {
return packPositive(int);
}
}
pub fn unpack(v: Value) i64 {
assert(v);
if (v.fixnum.negative) {
return unpackNegative(v);
} else {
return unpackPositive(v);
}
}
// Zisp API
pub fn pred(v: Value) Value {
return value.boole.pack(check(v));
}
pub fn add(v1: Value, v2: Value) Value {
const int1 = unpack(v1);
const int2 = unpack(v2);
return pack(int1 + int2);
}
|