2023-10-08 21:40:44 +02:00
|
|
|
const std = @import("std");
|
|
|
|
|
2023-11-24 03:22:15 +01:00
|
|
|
pub const NumeralTag = enum
|
|
|
|
{
|
|
|
|
Integer,
|
|
|
|
Float,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub fn isFloatExactInt(value: f64) bool
|
|
|
|
{
|
|
|
|
return value == 0 or (std.math.isNormal(value) and @floor(value) == value);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub const Numeral = union(NumeralTag)
|
2023-09-15 11:07:50 +02:00
|
|
|
{
|
|
|
|
Integer: i64,
|
|
|
|
Float: f64,
|
2023-11-24 03:22:15 +01:00
|
|
|
|
|
|
|
pub fn rawEqual(self: Numeral, other: Numeral) bool
|
|
|
|
{
|
|
|
|
if(@as(NumeralTag, self) == @as(NumeralTag, other))
|
|
|
|
{
|
|
|
|
switch(self)
|
|
|
|
{
|
|
|
|
.Float => |value| return value == other.Float,
|
|
|
|
.Integer => |value| return value == other.Integer,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Other is the respective other type
|
|
|
|
switch(self)
|
|
|
|
{
|
|
|
|
.Float => |value|
|
|
|
|
{
|
|
|
|
return isFloatExactInt(value) and @as(u64, @intFromFloat(value)) == other.Integer;
|
|
|
|
},
|
|
|
|
.Integer => |value|
|
|
|
|
{
|
|
|
|
return isFloatExactInt(other.Float) and @as(u64, @intFromFloat(other.Float)) == value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
test "float int equality"
|
|
|
|
{
|
|
|
|
const a = Numeral { .Float = 12.0 };
|
|
|
|
const b = Numeral { .Integer = 12 };
|
|
|
|
try std.testing.expect(a.rawEqual(b));
|
|
|
|
try std.testing.expect(b.rawEqual(a));
|
|
|
|
try std.testing.expect(a.rawEqual(a));
|
|
|
|
try std.testing.expect(b.rawEqual(b));
|
|
|
|
const c = Numeral { .Float = (0.2 + 0.1) * 10.0 };
|
|
|
|
const d = Numeral { .Integer = 3 };
|
|
|
|
try std.testing.expect(c.rawEqual(d));
|
|
|
|
try std.testing.expect(d.rawEqual(c));
|
|
|
|
try std.testing.expect(c.rawEqual(c));
|
|
|
|
try std.testing.expect(d.rawEqual(d));
|
|
|
|
const e = Numeral { .Float = 3.2 };
|
|
|
|
try std.testing.expect(!a.rawEqual(e));
|
|
|
|
try std.testing.expect(!b.rawEqual(e));
|
|
|
|
try std.testing.expect(!c.rawEqual(e));
|
|
|
|
try std.testing.expect(!d.rawEqual(e));
|
|
|
|
try std.testing.expect(!e.rawEqual(a));
|
|
|
|
try std.testing.expect(!e.rawEqual(b));
|
|
|
|
try std.testing.expect(!e.rawEqual(c));
|
|
|
|
try std.testing.expect(!e.rawEqual(d));
|
|
|
|
}
|
|
|
|
|
|
|
|
pub const TableEntry = struct
|
|
|
|
{
|
|
|
|
key: Value,
|
|
|
|
value: Value,
|
2023-09-15 11:07:50 +02:00
|
|
|
};
|
2023-11-24 03:22:15 +01:00
|
|
|
|
2023-10-08 21:40:44 +02:00
|
|
|
pub const Table = struct
|
|
|
|
{
|
2023-11-24 03:22:15 +01:00
|
|
|
entries: std.ArrayList(TableEntry),
|
2023-10-08 21:40:44 +02:00
|
|
|
|
2023-11-24 03:22:15 +01:00
|
|
|
pub fn get(self: Table, key: Value) Value
|
2023-10-08 21:40:44 +02:00
|
|
|
{
|
2023-11-24 03:22:15 +01:00
|
|
|
if(@as(ValueTag, key) == ValueTag.Nil)
|
|
|
|
{
|
|
|
|
return Value.Nil;
|
|
|
|
}
|
|
|
|
for (self.entries.items) |entry|
|
|
|
|
{
|
|
|
|
if(entry.key.rawEqual(key))
|
|
|
|
{
|
|
|
|
return entry.value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Value.Nil;
|
2023-10-08 21:40:44 +02:00
|
|
|
}
|
2023-11-24 03:22:15 +01:00
|
|
|
};
|
2023-10-08 21:40:44 +02:00
|
|
|
|
2023-11-24 03:22:15 +01:00
|
|
|
pub const ValueTag = enum
|
|
|
|
{
|
|
|
|
Nil,
|
|
|
|
Bool,
|
|
|
|
Numeral,
|
|
|
|
String,
|
|
|
|
Table,
|
2023-10-08 21:40:44 +02:00
|
|
|
};
|
2023-11-24 03:22:15 +01:00
|
|
|
pub const Value = union(ValueTag)
|
2023-10-08 21:40:44 +02:00
|
|
|
{
|
|
|
|
Nil,
|
|
|
|
Bool: bool,
|
|
|
|
Numeral: Numeral,
|
2023-11-17 01:37:29 +01:00
|
|
|
String: []const u8,
|
2023-10-08 21:40:44 +02:00
|
|
|
Table: *Table,
|
2023-11-24 03:22:15 +01:00
|
|
|
|
|
|
|
pub fn rawEqual(self: Value, other: Value) bool
|
|
|
|
{
|
|
|
|
if(@as(ValueTag, self) != @as(ValueTag, other))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
switch(self)
|
|
|
|
{
|
|
|
|
.Nil => return true,
|
|
|
|
.Bool => |value| return value == other.Bool,
|
|
|
|
.Numeral => |value| return value.rawEqual(other.Numeral),
|
|
|
|
.String => |value| return std.mem.eql(u8, value, other.String),
|
|
|
|
.Table => |value| return value == other.Table,
|
|
|
|
}
|
|
|
|
}
|
2023-10-08 21:40:44 +02:00
|
|
|
};
|
|
|
|
|
2023-11-24 03:22:15 +01:00
|
|
|
test "Value equalities"
|
|
|
|
{
|
|
|
|
const a = Value { .Bool = true };
|
|
|
|
const b = Value { .Numeral = Numeral { .Integer = 1 } };
|
|
|
|
// true != 1
|
|
|
|
try std.testing.expect(!a.rawEqual(b));
|
|
|
|
// 1 != true
|
|
|
|
try std.testing.expect(!b.rawEqual(a));
|
|
|
|
const c = Value { .Bool = false };
|
|
|
|
// true != false
|
|
|
|
try std.testing.expect(!a.rawEqual(c));
|
|
|
|
// false!= true
|
|
|
|
try std.testing.expect(!c.rawEqual(a));
|
|
|
|
const d = Value { .Bool = true };
|
|
|
|
// true == true
|
|
|
|
try std.testing.expect(a.rawEqual(d));
|
|
|
|
// true == true
|
|
|
|
try std.testing.expect(d.rawEqual(a));
|
|
|
|
const e = Value { .String = "foo" };
|
|
|
|
const f = Value { .String = "bar" };
|
|
|
|
// foo != bar
|
|
|
|
try std.testing.expect(!e.rawEqual(f));
|
|
|
|
// bar != foo
|
|
|
|
try std.testing.expect(!f.rawEqual(e));
|
|
|
|
const g = Value { .String = "foo" };
|
|
|
|
// foo != foo
|
|
|
|
try std.testing.expect(e.rawEqual(g));
|
|
|
|
// foo != foo
|
|
|
|
try std.testing.expect(g.rawEqual(e));
|
|
|
|
var table = Table { .entries = std.ArrayList(TableEntry).init(std.testing.allocator) };
|
|
|
|
const h = Value { .Table = &table };
|
|
|
|
var table2 = Table { .entries = std.ArrayList(TableEntry).init(std.testing.allocator) };
|
|
|
|
const i = Value { .Table = &table2 };
|
|
|
|
const j = Value { .Table = &table2 };
|
|
|
|
|
|
|
|
try std.testing.expect(h.rawEqual(h));
|
|
|
|
try std.testing.expect(i.rawEqual(i));
|
|
|
|
try std.testing.expect(!h.rawEqual(i));
|
|
|
|
try std.testing.expect(!i.rawEqual(h));
|
|
|
|
try std.testing.expect(i.rawEqual(j));
|
|
|
|
try std.testing.expect(!h.rawEqual(j));
|
|
|
|
}
|
|
|
|
|
2023-10-08 21:40:44 +02:00
|
|
|
pub const CodeRegion = struct
|
|
|
|
{
|
|
|
|
start: ?CodeLocation,
|
|
|
|
length: usize,
|
|
|
|
};
|
|
|
|
pub const CodeLocation = struct
|
|
|
|
{
|
|
|
|
line: usize,
|
|
|
|
col: usize,
|
|
|
|
};
|