Skip to content

Instantly share code, notes, and snippets.

@brecert
Created February 22, 2024 02:17
Show Gist options
  • Save brecert/ba53096765bfa3d1c788a9b0fc41a5dd to your computer and use it in GitHub Desktop.
Save brecert/ba53096765bfa3d1c788a9b0fc41a5dd to your computer and use it in GitHub Desktop.
ubjson.hexpat
#pragma author bree
#pragma description UBJSON ( Universal Binary JSON) format
#pragma MIME application/ubjson
#pragma endian big
#include <std/io.pat>
#include <std/mem.pat>
#include <std/string.pat>
namespace util {
fn warn(str fmt, auto ... args) {
str message = builtin::std::format(fmt, args);
str warn = std::format("$[{:#04x}] WARN: {}", $, message);
return std::print(warn);
};
fn error(str fmt, auto ... args) {
str message = builtin::std::format(fmt, args);
str error = std::format("$[{:#04x}] ERROR: {}", $, message);
return std::error(error);
};
fn debug(str fmt, auto ... args) {
str message = builtin::std::format(fmt, args);
str debug = std::format("$[{:#04x}] DEBUG: {}", $, message);
return std::print(debug);
};
fn assert(bool condition, str fmt, auto ... args) {
if (!condition) {
str message = builtin::std::format(fmt, args);
str error = std::format("$[{:#04x}] ERROR(assert): {}", $, message);
return std::error(error);
}
};
struct Lit<Type, auto ExpectedValue> {
Type value;
util::assert(value == ExpectedValue, "Expected \"{}\", got \"{}\"", ExpectedValue, value);
} [[sealed, format("util::impl::format_lit"), hidden]];
struct DebugBytes<auto Size> {
if (DISPLAY_DEBUG_BYTES) {
u8 debug_bytes[Size] @ $ [[sealed, color("ffffff")]];
}
};
namespace impl {
fn format_lit(ref auto object) {
return object.value;
};
}
}
fn read_u8() {
return std::mem::read_unsigned($, 1, std::mem::Endian::Big);
};
// START
using IntNum;
using Array;
using Object;
using String;
using HighPrecisionNumber;
enum Marker : u8 {
Null = 'Z',
NoOp = 'N',
True = 'T',
False = 'F',
Int8 = 'i',
UInt8 = 'U',
Int16 = 'I',
Int32 = 'l',
Int64 = 'L',
Float32 = 'd',
Float64 = 'D',
HighPrecisionNumber = 'H',
Char = 'C',
String = 'S',
Array = '[',
ArrayEnd = ']',
Object = '{',
ObjectEnd = '}',
};
struct Value {
Marker type;
match (type) {
(Marker::Int8): s8 value;
(Marker::UInt8): u8 value;
(Marker::Int16): s16 value;
(Marker::Int32): s32 value;
(Marker::Int64): s64 value;
(Marker::Float32): float value;
(Marker::Float64): double value;
(Marker::HighPrecisionNumber): HighPrecisionNumber value;
(Marker::Char): char value;
(Marker::String): String value;
(Marker::Array): Array value;
(Marker::Object): Object value;
}
} [[transform("transform_value"), inline]];
fn transform_value(ref auto object) {
return object.value;
};
fn transform_values(ref auto object) {
return object.values;
};
struct TypedPair<Type> {
String name;
Type value;
};
struct Pair {
String name;
Value value;
};
struct Array {
match (read_u8()) {
('#'): {
util::Lit<u8, '#'>;
IntNum count;
Value values[count];
}
('$'): {
util::Lit<u8, '$'>;
Marker type;
util::Lit<u8, '#'>;
IntNum count;
match (type) {
(Marker::Int8): s8 values[count.num];
(Marker::UInt8): u8 values[count.num];
(Marker::Int16): s16 values[count.num];
(Marker::Int32): s32 values[count.num];
(Marker::Int64): s64 values[count.num];
(Marker::Float32): float values[count.num];
(Marker::Float64): double values[count.num];
(Marker::HighPrecisionNumber): HighPrecisionNumber values[count.num];
(Marker::Char): char values[count.num];
(Marker::String): String values[count.num];
(Marker::Array): Array values[count.num];
(Marker::Object): Object values[count.num];
}
}
(_): {
Value values[while(read_u8() != Marker::ArrayEnd)];
util::Lit<u8, Marker::ArrayEnd>;
}
}
} [[transform("transform_values")]];
struct Object {
match (read_u8()) {
('#'): {
util::Lit<u8, '#'>;
IntNum count;
Pair values[count];
}
('$'): {
util::Lit<u8, '$'>;
Marker type;
util::Lit<u8, '#'>;
IntNum count;
match (TypeMarker) {
(Marker::Int8): TypedPair<s8> values[count.num];
(Marker::UInt8): TypedPair<u8> values[count.num];
(Marker::Int16): TypedPair<s16> values[count.num];
(Marker::Int32): TypedPair<s32> values[count.num];
(Marker::Int64): TypedPair<s64> values[count.num];
(Marker::Float32): TypedPair<float> values[count.num];
(Marker::Float64): TypedPair<double> values[count.num];
(Marker::HighPrecisionNumber): TypedPair<HighPrecisionNumber> values[count.num];
(Marker::Char): TypedPair<char> values[count.num];
(Marker::String): TypedPair<String> values[count.num];
(Marker::Array): TypedPair<Array> values[count.num];
(Marker::Object): TypedPair<Object> values[count.num];
}
}
(_): {
Pair values[while(read_u8() != Marker::ObjectEnd)];
util::Lit<u8, Marker::ObjectEnd>;
}
}
} [[transform("transform_values"), inline]];
struct IntNum {
Value value [[inline]];
match (value.type) {
(Marker::Int8 | Marker::UInt8 | Marker::Int16 | Marker::Int32 | Marker::Int64): {}
(_): util::error("int num must be of type uint8, int8, int16, int32, or int64. not {}", value.type);
}
u128 num = value.value [[export]];
} [[sealed, transform("transform_value"), format("transform_value")]];
struct String {
IntNum size;
char data[size.num];
} [[sealed, format("format_string")]];
fn format_string(auto string) {
return string.data;
};
struct HighPrecisionNumber {
String value;
};
Value document @ 0x00;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment