summaryrefslogtreecommitdiff
path: root/src/libzisp/value/fixnum.zig
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);
}