179 lines
4.3 KiB
Zig
179 lines
4.3 KiB
Zig
const std = @import("std");
|
|
const debug = std.debug;
|
|
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
const Obj = @import("./object.zig").Obj;
|
|
const ZloxAllocator = @import("./memory.zig").ZloxAllocator;
|
|
|
|
pub const ValueType = enum {
|
|
Bool,
|
|
Nil,
|
|
Number,
|
|
Obj,
|
|
};
|
|
|
|
pub const Value = struct {
|
|
value_type: ValueType,
|
|
as: union {
|
|
boolean: bool,
|
|
number: f64,
|
|
obj: *Obj,
|
|
},
|
|
|
|
pub fn bool_val(value: bool) Value {
|
|
return Value{
|
|
.value_type = ValueType.Bool,
|
|
.as = .{
|
|
.boolean = value,
|
|
},
|
|
};
|
|
}
|
|
|
|
pub fn nil_val() Value {
|
|
return Value{
|
|
.value_type = ValueType.Nil,
|
|
.as = .{
|
|
.boolean = false,
|
|
},
|
|
};
|
|
}
|
|
|
|
pub fn number_val(value: f64) Value {
|
|
return Value{
|
|
.value_type = ValueType.Number,
|
|
.as = .{
|
|
.number = value,
|
|
},
|
|
};
|
|
}
|
|
|
|
pub fn obj_val(obj: *Obj) Value {
|
|
return Value{
|
|
.value_type = ValueType.Obj,
|
|
.as = .{
|
|
.obj = obj,
|
|
},
|
|
};
|
|
}
|
|
|
|
pub fn as_bool(self: Value) bool {
|
|
return self.as.boolean;
|
|
}
|
|
|
|
pub fn as_number(self: Value) f64 {
|
|
return self.as.number;
|
|
}
|
|
|
|
pub fn as_obj(self: Value) *Obj {
|
|
return self.as.obj;
|
|
}
|
|
|
|
pub fn as_string(self: Value) *Obj.String {
|
|
const obj: *Obj.String = self.as_obj().as_string();
|
|
|
|
return obj;
|
|
}
|
|
|
|
pub fn as_cstring(self: Value) []const u8 {
|
|
const obj: *Obj.String = self.as_obj().as_string();
|
|
|
|
return obj.chars;
|
|
}
|
|
|
|
pub fn is_bool(self: Value) bool {
|
|
return self.value_type == ValueType.Bool;
|
|
}
|
|
|
|
pub fn is_number(self: Value) bool {
|
|
return self.value_type == ValueType.Number;
|
|
}
|
|
|
|
pub fn is_nil(self: Value) bool {
|
|
return self.value_type == ValueType.Nil;
|
|
}
|
|
|
|
pub fn is_obj(self: Value) bool {
|
|
return self.value_type == ValueType.Obj;
|
|
}
|
|
|
|
pub fn is_string(self: Value) bool {
|
|
return self.is_obj() and self.as_obj().is_string();
|
|
}
|
|
|
|
pub fn is_falsey(self: Value) bool {
|
|
return self.is_nil() or (self.is_bool() and !self.as_bool());
|
|
}
|
|
|
|
pub fn equals(self: Value, other: Value) bool {
|
|
if (self.value_type != other.value_type) {
|
|
return false;
|
|
}
|
|
|
|
return switch (self.value_type) {
|
|
ValueType.Nil => true,
|
|
ValueType.Bool => self.as_bool() == other.as_bool(),
|
|
ValueType.Number => self.as_number() == other.as_number(),
|
|
ValueType.Obj => self.as_obj() == other.as_obj(),
|
|
};
|
|
}
|
|
|
|
pub fn print(self: Value) void {
|
|
switch (self.value_type) {
|
|
ValueType.Nil => debug.print("nil", .{}),
|
|
ValueType.Bool => debug.print("{any}", .{self.as_bool()}),
|
|
ValueType.Number => debug.print("{d}", .{self.as_number()}),
|
|
ValueType.Obj => self.as_obj().print(),
|
|
}
|
|
}
|
|
|
|
pub fn type_print(self: Value) void {
|
|
switch (self.value_type) {
|
|
ValueType.Nil => debug.print("(nil)", .{}),
|
|
ValueType.Bool => debug.print("(bool)", .{}),
|
|
ValueType.Number => debug.print("(number)", .{}),
|
|
ValueType.Obj => debug.print("(obj)", .{}),
|
|
}
|
|
|
|
debug.print(" ", .{});
|
|
self.print();
|
|
}
|
|
};
|
|
|
|
pub const ValueArray = struct {
|
|
allocator: Allocator,
|
|
capacity: usize,
|
|
count: usize,
|
|
values: []Value,
|
|
|
|
pub fn new(allocator: Allocator) ValueArray {
|
|
return ValueArray{
|
|
.allocator = allocator,
|
|
.capacity = 0,
|
|
.count = 0,
|
|
.values = &.{},
|
|
};
|
|
}
|
|
|
|
pub fn write(self: *ValueArray, value: Value) !void {
|
|
if (self.capacity < self.count + 1) {
|
|
const old_capacity = self.capacity;
|
|
self.capacity = ZloxAllocator.grow_capacity(old_capacity);
|
|
self.values = try self.allocator.realloc(self.values, self.capacity);
|
|
}
|
|
|
|
self.values[self.count] = value;
|
|
self.count += 1;
|
|
}
|
|
|
|
pub fn destroy(self: *ValueArray) void {
|
|
if (self.capacity > 0) {
|
|
self.allocator.free(self.values);
|
|
}
|
|
}
|
|
};
|
|
|
|
pub fn print_value(value: Value) void {
|
|
value.print();
|
|
}
|