diff --git a/CMakeLists.txt b/CMakeLists.txt index 18d256e..b18c824 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,8 @@ target_link_libraries(r2c -lm) #add_executable(l2t0 src/l2/tests/data_structures/t0.c) #add_executable(l2t1 src/l2/tests/data_structures/t1.c) +add_executable(l2_t_parsing src/l2/tests/t_parsing.c) + add_executable(l2_tex_gen src/l2/anne/codegen.c) target_link_libraries(l2_tex_gen -lm -lpng) diff --git a/src/l1/anne/liza.h b/src/l1/anne/liza.h index f312982..2162374 100644 --- a/src/l1/anne/liza.h +++ b/src/l1/anne/liza.h @@ -9,13 +9,13 @@ void generate_liza_l1_headers() { mkdir_nofail("l1/eve/liza"); // todo: continue OptionT + util_templates_instantiation_options refactoring from here generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){ - .T = cstr("BoxLizaSound"), .vec = true}); + .T = cstr("BoxLizaSound"), .vec = true}, false); generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){ - .T = cstr("PlayingSound"), .vec_extended = true}); + .T = cstr("PlayingSound"), .vec_extended = true}, false); generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){ - .T = cstr("BoxLizaInstrument"), .vec = true}); + .T = cstr("BoxLizaInstrument"), .vec = true}, false); generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){ - .T = cstr("MyInstrument"), .vec = true}); + .T = cstr("MyInstrument"), .vec = true}, false); } #endif \ No newline at end of file diff --git a/src/l1/anne/lucy.h b/src/l1/anne/lucy.h index 73334e0..4ecebd9 100644 --- a/src/l1/anne/lucy.h +++ b/src/l1/anne/lucy.h @@ -17,7 +17,7 @@ void generate_l1_lucy_headers(){ generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){ .T = cstr("LucyPositionedStagingGlyph"), .vec = true, .sort = true, - }); + }, false); } #endif \ No newline at end of file diff --git a/src/l1/anne/margaret/margaret_misc.h b/src/l1/anne/margaret/margaret_misc.h index 1deb47e..1769288 100644 --- a/src/l1/anne/margaret/margaret_misc.h +++ b/src/l1/anne/margaret/margaret_misc.h @@ -11,7 +11,7 @@ void generate_margaret_eve_for_vulkan_utils() { mkdir_nofail("l1/eve/margaret"); generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){ .T = cstr("MargaretScoredPhysicalDevice"), .t_primitive = true, .vec = true, .sort = true - }); + }, false); /* For l2/margaret/{ vulkan_img_claire.h , vulkan_buffer_claire.h } */ generate_eve_span_company_for_primitive(l, ns, cstr("MargaretIAFreeSegment"), true, false); diff --git a/src/l1/anne/marie.h b/src/l1/anne/marie.h index 6e9d51c..97faff9 100644 --- a/src/l1/anne/marie.h +++ b/src/l1/anne/marie.h @@ -12,7 +12,6 @@ void generate_l1_headers_for_marie() { generate_eve_span_company_for_primitive(l, ns, cstr("MarieTriangleAttr"), true, false); /* shape_geom */ generate_eve_span_company_for_primitive(l, ns, cstr("MarieEarCuttingTriangulVertState"), true, false); - generate_eve_span_company_for_primitive(l, ns, cstr("MarieHoleConnectTriangStackFrame"), true, false); generate_eve_span_company_for_primitive(l, ns, cstr("MarieHoleAndVertexId"), true, false); generate_eve_span_company_for_non_primitive_clonable(l, ns, cstr("VecMarieHoleAndVertexId"), true, false); generate_eve_span_company_for_non_primitive_clonable(l, ns, cstr("VecVecMarieHoleAndVertexId"), true, false); diff --git a/src/l1/anne/some_tests.h b/src/l1/anne/some_tests.h index 62fc438..063ea60 100644 --- a/src/l1/anne/some_tests.h +++ b/src/l1/anne/some_tests.h @@ -17,7 +17,7 @@ void generate_headers_for_r0_r1_r2_r3() { SpanU8 ns = cstr("r2"); generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){ .T = cstr("PlayingSound"), .vec_extended = true - }); + }, false); } mkdir_nofail("l1/eve/ds_test"); { /* This structure is needed for testing purposes only */ diff --git a/src/l1/anne/util_temp_very_base.h b/src/l1/anne/util_temp_very_base.h index f510c23..a0468be 100644 --- a/src/l1/anne/util_temp_very_base.h +++ b/src/l1/anne/util_temp_very_base.h @@ -67,6 +67,13 @@ void generate_util_temp_very_base_headers() { cstr("#include \"../../gen/l1/pixel_masses.h\"\n"), true, false); generate_guarded_span_company_for_primitive(l, ns, cstr("KVPU64ToU64"), cstr(""), true, false); + + /* Currently not clonable, because I forgot to implement clone for rbtree. todo: do this */ + generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){ + .T = cstr("Json"), .t_clonable = false, .vec = true, .skip_declaration_gen = true}, true); + + generate_Option_templ_inst_eve_header(l, ns, + (option_template_instantiation_op){.T = cstr("Json"), .t_clonable = false}); } #endif \ No newline at end of file diff --git a/src/l1/codegen/util_template_inst.h b/src/l1/codegen/util_template_inst.h index 8c6eac8..79ddc94 100644 --- a/src/l1/codegen/util_template_inst.h +++ b/src/l1/codegen/util_template_inst.h @@ -4,21 +4,30 @@ #include "codegen.h" // todo: add macro that iterates over vector +// todo: add _less_ method +// todo: rewrite this crap -/* if !primitive, requires methods T_drop, and, if also clonable, requires method T_clone */ -NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive, bool clonable) { - VecU8 g_VecT = VecU8_fmt("Vec%s", T); - SpanU8 VecT = VecU8_to_span(&g_VecT); - VecU8 res = VecU8_fmt( - "typedef struct {\n" +NODISCARD VecU8 generate_VecT_struct(SpanU8 T, bool skip_declaration_gen){ + VecU8 res = VecU8_new(); + if (!skip_declaration_gen) { + VecU8_append_vec(&res, VecU8_fmt("typedef struct Vec%s Vec%s;\n\n", T, T)); + } + VecU8_append_vec(&res, VecU8_fmt( + "struct Vec%s {\n" SPACE "%s* buf;\n" SPACE "size_t len;\n" SPACE "size_t capacity;\n" - "} %s;\n\n", T, VecT); + "};\n\n", T, T)); + return res; +} - VecU8_append_vec(&res, VecU8_fmt("#define %s_new() ((%s){ 0 })\n\n", VecT, VecT)); +/* if !primitive, requires methods T_drop, and, if also clonable, requires method T_clone */ +NODISCARD VecU8 generate_VecT_base_methods(SpanU8 T, bool primitive, bool clonable) { + VecU8 res = VecU8_new(); - VecU8_append_vec(&res, VecU8_fmt("void %s_drop(%s self) {\n", VecT, VecT)); + VecU8_append_vec(&res, VecU8_fmt("#define Vec%s_new() ((Vec%s){ 0 })\n\n", T, T)); + + VecU8_append_vec(&res, VecU8_fmt("void Vec%s_drop(Vec%s self) {\n", T, T)); if (!primitive) { VecU8_append_vec(&res, VecU8_fmt( SPACE "for (size_t i = 0; i < self.len; i++) \n" @@ -29,12 +38,12 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive, "}\n\n")); VecU8_append_vec(&res, VecU8_fmt( - "NODISCARD %s %s_new_reserved(size_t n) {\n" - SPACE "return (%s){ .buf = (%s*)safe_calloc(n, sizeof(%s)), .len = 0, .capacity = n };\n" - "}\n\n", VecT, VecT, VecT, T, T)); + "NODISCARD Vec%s Vec%s_new_reserved(size_t n) {\n" + SPACE "return (Vec%s){ .buf = (%s*)safe_calloc(n, sizeof(%s)), .len = 0, .capacity = n };\n" + "}\n\n", T, T, T, T, T)); VecU8_append_vec(&res, VecU8_fmt( - "void %s_append(%s* self, %s el) {\n" /* VecT, VecT, T */ + "void Vec%s_append(Vec%s* self, %s el) {\n" /* T, T, T */ SPACE "size_t new_length = self->len + 1;\n" SPACE "if (new_length > self->capacity) {\n" SPACE SPACE "size_t new_capacity = Vec_get_new_capacity(self->capacity, new_length);\n" @@ -43,26 +52,26 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive, SPACE "}\n" SPACE "self->buf[self->len] = el;\n" SPACE "self->len = new_length;\n" - "}\n\n", VecT, VecT, T, T, T)); + "}\n\n", T, T, T, T, T)); VecU8_append_vec(&res, VecU8_fmt( - "%s* %s_mat(%s* self, size_t i) {\n" + "%s* Vec%s_mat(Vec%s* self, size_t i) {\n" SPACE "assert(i < self->len);\n" SPACE "return &self->buf[i];\n" - "}\n\n", T, VecT, VecT)); + "}\n\n", T, T, T)); VecU8_append_vec(&res, VecU8_fmt( - "const %s* %s_at(const %s* self, size_t i) {\n" + "const %s* Vec%s_at(const Vec%s* self, size_t i) {\n" SPACE "assert(i < self->len);\n" SPACE "return &self->buf[i];\n" - "}\n\n", T, VecT, VecT)); + "}\n\n", T, T, T)); VecU8_append_vec(&res, VecU8_fmt( - "void %s_sink(%s* self, size_t new_len) {\n" /* VecT, VecT */ + "void Vec%s_sink(Vec%s* self, size_t new_len) {\n" /* T, T */ SPACE "assert(new_len <= self->len);\n" "%v" /* dropping */ SPACE "self->len = new_len;\n" - "}\n\n", VecT, VecT, + "}\n\n", T, T, primitive ? vcstr("") : VecU8_fmt( SPACE "for (size_t i = new_len; i < self->len; i++)\n" SPACE SPACE "%s_drop(self->buf[i]);\n", /* T */ @@ -70,9 +79,10 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive, if (clonable) { VecU8_append_vec(&res, VecU8_fmt( - "NODISCARD %s %s_clone(const %s* self) {\n" /* VecT, VecT, VecT */ - SPACE "%s res = (%s){.buf = (%s*)safe_calloc(self->len, sizeof(%s)), .len = self->len, .capacity = self->len};\n", - VecT, VecT, VecT, VecT, VecT, T, T)); + "NODISCARD Vec%s Vec%s_clone(const Vec%s* self) {\n" /* T, T, T */ + SPACE "Vec%s res = (Vec%s){.buf = (%s*)safe_calloc(self->len, sizeof(%s)),\n" /* T, T, T, T */ + SPACE SPACE ".len = self->len, .capacity = self->len};\n", + T, T, T, T, T, T, T)); if (primitive) { VecU8_append_vec(&res, VecU8_fmt(SPACE "memcpy(res.buf, self->buf, self->len * sizeof(%s));\n", T)); } else { @@ -84,7 +94,7 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive, } VecU8_append_vec(&res, VecU8_fmt( - "void %s_append_vec(%s* self, %s b) {\n" /* VecT, VecT, VecT */ + "void Vec%s_append_vec(Vec%s* self, Vec%s b) {\n" /* T, T, T */ SPACE "size_t new_length = self->len + b.len;\n" SPACE "if (new_length > self->capacity) {\n" SPACE SPACE "size_t new_capacity = Vec_get_new_capacity(self->capacity, new_length);\n" @@ -96,17 +106,16 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive, SPACE "}\n" SPACE "self->len = new_length;\n" SPACE "free(b.buf);\n" - "}\n\n", VecT, VecT, VecT, T, T)); + "}\n\n", T, T, T, T, T)); if (primitive) { VecU8_append_vec(&res, VecU8_fmt( - "NODISCARD %s %s_new_zeroinit(size_t len) {\n" /* VecT, VecT*/ - SPACE "return (%s){.buf = (%s*)safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" /* VecT, T, T */ + "NODISCARD Vec%s Vec%s_new_zeroinit(size_t len) {\n" /* T, T */ + SPACE "return (Vec%s){.buf = (%s*)safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" /* T, T, T */ "}\n\n", - VecT, VecT, VecT, T, T)); + T, T, T, T, T)); } - VecU8_drop(g_VecT); // VecT invalidated too return res; } @@ -229,13 +238,16 @@ void codegen_append_some_span_equal_method(VecU8* res, SpanU8 SpanT) { "}\n\n", SpanT, SpanT, SpanT, SpanT)); } -/* helper function. (SpanT, mod) is either (SpanT "const ") or (MutSpanT, "") */ -void codegen_append_some_span_struct(VecU8* res, SpanU8 T, SpanU8 SpanT, SpanU8 mod) { +/* Helper function. (span_mod, mod) is in {("", "const "), ("Mut", "")} */ +void codegen_append_some_span_struct(VecU8* res, SpanU8 T, SpanU8 span_mod, SpanU8 mod, bool skip_declaration_gen) { + if (!skip_declaration_gen) { + VecU8_append_vec(res, VecU8_fmt("typedef struct %sSpan%s %sSpan%s;\n\n", span_mod, T, span_mod, T)); + } VecU8_append_vec(res, VecU8_fmt( - "typedef struct {\n" - SPACE "%s%s* data;\n" + "struct %sSpan%s {\n" /* span_mod, T */ + SPACE "%s%s* data;\n" /* mod, T */ SPACE "size_t len;\n" - "} %s;\n\n", mod, T, SpanT)); + "};\n\n", span_mod, T, mod, T)); } /* helper function. (SpanT, mod) is either (SpanT "const ") or (MutSpanT, "") */ @@ -257,11 +269,19 @@ void codegen_append_some_span_span_method(VecU8* res, SpanU8 SpanT) { "}\n\n", SpanT, SpanT, SpanT, SpanT)); } +NODISCARD VecU8 generate_SpanT_structures(SpanU8 T, bool add_mutable, bool skip_declaration_gen){ + VecU8 res = VecU8_new(); + codegen_append_some_span_struct(&res, T, cstr(""), cstr("const "), skip_declaration_gen); + if (add_mutable) + codegen_append_some_span_struct(&res, T, cstr("Mut"), cstr(""), skip_declaration_gen); + return res; +} + /* T must be sized. Option `add_sort` requires option `add_mutable` and method T_less * add_mutable option generates MutSpanT. * add_equal option generates equal method. add_extended option generated extended methods */ -NODISCARD VecU8 generate_SpanT_struct_and_methods( +NODISCARD VecU8 generate_SpanT_base_methods( SpanU8 T, bool integer, bool add_mutable, bool add_equal, bool add_extended ) { VecU8 g_SpanT = VecU8_fmt("Span%s", T); @@ -270,9 +290,6 @@ NODISCARD VecU8 generate_SpanT_struct_and_methods( SpanU8 MutSpanT = VecU8_to_span(&g_MutSpanT); VecU8 res = VecU8_new(); - codegen_append_some_span_struct(&res, T, SpanT, cstr("const ")); - if (add_mutable) - codegen_append_some_span_struct(&res, T, MutSpanT, cstr("")); if (add_equal) { codegen_append_some_span_equal_method(&res, SpanT); if (add_mutable) @@ -426,6 +443,8 @@ typedef struct { bool sort; bool collab_vec_span; bool collab_vec_span_extended; + + bool skip_declaration_gen; } util_templates_instantiation_options; void util_templates_instantiation_options_fix(util_templates_instantiation_options* op) { @@ -453,37 +472,50 @@ void util_templates_instantiation_options_fix(util_templates_instantiation_optio assert(!op->t_primitive || op->t_clonable); } -NODISCARD VecU8 generate_util_templates_instantiation(util_templates_instantiation_options op) { +NODISCARD VecU8 generate_util_templates_instantiation(util_templates_instantiation_options op, + bool generate_structures, bool generate_methods) { VecU8 res = VecU8_new(); util_templates_instantiation_options_fix(&op); - if (op.vec) { - VecU8_append_vec(&res, generate_VecT_struct_and_base_methods(op.T, op.t_primitive, op.t_clonable)); + + if (generate_structures) { + if (op.vec) { + VecU8_append_vec(&res, generate_VecT_struct(op.T, op.skip_declaration_gen)); + } + if (op.span) { + VecU8_append_vec(&res, generate_SpanT_structures(op.T, op.mut_span, op.skip_declaration_gen)); + } } - if (op.vec_extended) { - assert(op.vec); - VecU8_append_vec(&res, generate_VecT_trivmove_extended_methods(op.T, op.t_primitive, op.t_clonable)); - } - if (op.vec_equal) { - assert(op.vec); - VecU8_append_vec(&res, generate_VecT_equal_method(op.T, op.t_integer)); - } - if (op.vec_new_of_size) { - assert(op.vec); - VecU8_append_vec(&res, generate_VecT_new_of_size_method(op.T)); - } - if (op.span) { - VecU8_append_vec(&res, generate_SpanT_struct_and_methods(op.T, op.t_integer, op.mut_span, false, op.span_extended)); - } - if (op.sort) { - VecU8_append_vec(&res, generate_span_company_sort_methods(op.T, op.t_integer, op.mut_span, op.vec)); - } - if (op.collab_vec_span) { - assert(op.vec && op.span); - VecU8_append_vec(&res, generate_SpanT_VecT_trivmove_collab(op.T, op.t_primitive, op.t_clonable, op.mut_span, op.collab_vec_span_extended)); + if (generate_methods) { + if (op.vec) { + VecU8_append_vec(&res, generate_VecT_base_methods(op.T, op.t_primitive, op.t_clonable)); + } + if (op.vec_extended) { + assert(op.vec); + VecU8_append_vec(&res, generate_VecT_trivmove_extended_methods(op.T, op.t_primitive, op.t_clonable)); + } + if (op.vec_equal) { + assert(op.vec); + VecU8_append_vec(&res, generate_VecT_equal_method(op.T, op.t_integer)); + } + if (op.vec_new_of_size) { + assert(op.vec); + VecU8_append_vec(&res, generate_VecT_new_of_size_method(op.T)); + } + if (op.span) { + VecU8_append_vec(&res, generate_SpanT_base_methods(op.T, op.t_integer, op.mut_span, false, op.span_extended)); + } + if (op.sort) { + VecU8_append_vec(&res, generate_span_company_sort_methods(op.T, op.t_integer, op.mut_span, op.vec)); + } + if (op.collab_vec_span) { + assert(op.vec && op.span); + VecU8_append_vec(&res, generate_SpanT_VecT_trivmove_collab(op.T, op.t_primitive, op.t_clonable, op.mut_span, op.collab_vec_span_extended)); + } } return res; } +/* Does not include .h postfix. .h postfix and `path` prefix have to be added by someone else */ NODISCARD VecU8 util_templates_instantiation_get_appropriate_filename(util_templates_instantiation_options op) { util_templates_instantiation_options_fix(&op); return VecU8_fmt("%s%s%s""%s%s", @@ -491,38 +523,49 @@ NODISCARD VecU8 util_templates_instantiation_get_appropriate_filename(util_templ (int)op.vec + (int)op.span > 1 ? cstr("_") : cstr(""), op.T); } -void generate_util_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, util_templates_instantiation_options op) { - generate_SOME_templ_inst_eve_header(layer, bonus_ns, generate_util_templates_instantiation(op), - util_templates_instantiation_get_appropriate_filename(op)); +void generate_util_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, util_templates_instantiation_options op, + bool separate_struct_and_methods) { + if (separate_struct_and_methods) { + VecU8 name_for_structures = VecU8_fmt("%v_struct", util_templates_instantiation_get_appropriate_filename(op)); + VecU8 name_for_methods = VecU8_fmt("%v_methods", util_templates_instantiation_get_appropriate_filename(op)); + generate_SOME_templ_inst_eve_header(layer, bonus_ns, generate_util_templates_instantiation(op, true, false), + name_for_structures); + generate_SOME_templ_inst_eve_header(layer, bonus_ns, generate_util_templates_instantiation(op, false, true), + name_for_methods); + } else { + generate_SOME_templ_inst_eve_header(layer, bonus_ns, generate_util_templates_instantiation(op, true, true), + util_templates_instantiation_get_appropriate_filename(op)); + } } void generate_eve_span_company_for_primitive(SpanU8 layer, SpanU8 ns, SpanU8 T, bool with_vector, bool with_span) { generate_util_templ_inst_eve_header(layer, ns, (util_templates_instantiation_options){ .T = T, .t_primitive = true, .vec = with_vector, .span = with_span, .collab_vec_span = with_vector && with_span - }); + }, false); } void generate_eve_span_company_for_non_primitive_clonable(SpanU8 layer, SpanU8 ns, SpanU8 T, bool with_vector, bool with_span) { generate_util_templ_inst_eve_header(layer, ns, (util_templates_instantiation_options){ .T = T, .t_clonable = true, .vec = with_vector, .span = with_span, .collab_vec_span = with_vector && with_span - }); + }, false); } void generate_eve_span_company_for_non_primitive_non_clonable(SpanU8 layer, SpanU8 ns, SpanU8 T, bool with_vector, bool with_span) { generate_util_templ_inst_eve_header(layer, ns, (util_templates_instantiation_options){ .T = T, .vec = with_vector, .span = with_span, .collab_vec_span = with_vector && with_span - }); + }, false); } + void generate_util_templ_inst_guarded_header( SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, util_templates_instantiation_options op ) { generate_SOME_templ_inst_guarded_header(layer, bonus_ns, VecU8_fmt("%v%s\n", codegen_include_relative_to_root(bonus_ns, cstr("src/l1/core/util.h")), dependencies), - generate_util_templates_instantiation(op), util_templates_instantiation_get_appropriate_filename(op)); + generate_util_templates_instantiation(op, true, true), util_templates_instantiation_get_appropriate_filename(op)); } void generate_guarded_span_company_for_primitive( @@ -552,6 +595,7 @@ void generate_guarded_span_company_for_non_primitive_non_clonable( }); } + NODISCARD VecU8 get_ResultType_inst_name(SpanU8 OkT, SpanU8 ErrT){ bool ok_t_void = OkT.len == 0; bool err_t_void = ErrT.len == 0; diff --git a/src/l1/core/VecU8_as_str.h b/src/l1/core/VecU8_as_str.h index 563a95b..4ed346e 100644 --- a/src/l1/core/VecU8_as_str.h +++ b/src/l1/core/VecU8_as_str.h @@ -102,6 +102,12 @@ void S64_stringification_into_buf(S64 x, VecU8* targ){ } } +VecU8 S64_stringification(S64 x){ + VecU8 res = VecU8_new(); + S64_stringification_into_buf(x, &res); + return res; +} + size_t U64_stringification_get_length(U64 x){ if (x == 0) return 1; @@ -135,6 +141,12 @@ void U64_stringification_into_buf(U64 x, VecU8* targ){ } } +VecU8 U64_stringification(U64 x){ + VecU8 res = VecU8_new(); + U64_stringification_into_buf(x, &res); + return res; +} + /* %s - SpanU8 * %v - VecU8 * %u - U64 @@ -253,11 +265,78 @@ U32 SpanU8_decode_as_utf8(SpanU8* rem){ } bool SpanU8_is_prefix(SpanU8 a, SpanU8 str){ - return str.len >= a.len && SpanU8_cont_equal(a, (SpanU8){str.data, a.len}); + if (str.len < a.len) + return false; + for (size_t i = 0; i < a.len; i++) { + if (a.data[i] != str.data[i]) { + return false; + } + } + return true; } bool SpanU8_is_postfix(SpanU8 a, SpanU8 str){ - return str.len >= a.len && SpanU8_cont_equal(a, (SpanU8){str.data + str.len - a.len, a.len}); + if (str.len < a.len) + return false; + for (size_t i = 0; i < a.len; i++) { + if (a.data[i] != str.data[str.len - a.len + i]) { + return false; + } + } + return true; +} + + +// todo: automatically generate such methods for vectors of nice types +bool SpanU8_less_SpanU8(SpanU8 a, SpanU8 b){ + size_t i = 0; + while (i < a.len && i < b.len) { + if (a.data[i] < b.data[i]) + return true; + if (b.data[i] < a.data[i]) + return false; + i++; + } + /* If i < b->len, then a is eigen-prefix of b, which means a < b + * Or... i < a->len, and this means b is eigen-prefix of a => a > b + * Or... a == b . Here we also return false */ + return i < b.len; +} + +bool VecU8_less_VecU8(const VecU8* a, const VecU8* b){ + return SpanU8_less_SpanU8(VecU8_to_span(a), VecU8_to_span(b)); +} + +char digit_to_big_hex(U32 d){ + assert(d < 16); + return d >= 10 ? (char)('A' + d - 10) : (char)('0' + d); +} + +char digit_to_small_hex(U32 d){ + assert(d < 16); + return d >= 10 ? (char)('a' + d - 10) : (char)('0' + d); +} + +static_assert(0b11000000 == 0xC0 && 0b10000000 == 0x80 && 0b00111111 == 0x3F, "asdasda"); + +/* Some bytes (encoding codepoint U) will be appended to str. Utf-8 works only with codepoints below (1u << 24) */ +void VecU8_encode_as_utf8(VecU8* str, U32 U){ + if (U < (1u << 7)) { + VecU8_append(str, (U8)U); + } else if (U < (1u << 11)) { + VecU8_append_span(str, (SpanU8){(U8[]){ + 0xC0 | (U8)(U >> 6), 0x80 | (U8)(U & 0x3F) + }, 2}); + } else if (U < (1u << 17)) { + VecU8_append_span(str, (SpanU8){(U8[]){ + 0xC0 | (U8)(U >> 12), 0x80 | (U8)((U >> 6) & 0x3F), (U8)(U & 0x3F) + }, 3}); + } else { + /* U < (1u << 24) */ + VecU8_append_span(str, (SpanU8){(U8[]){ + 0xC0 | (U8)(U >> 18), 0x80 | (U8)((U >> 12) & 0x3F), 0x80 | (U8)((U >> 6) & 0x3F), (U8)(U & 0x3F) + }, 4}); + } } #endif diff --git a/src/l1_5/anne/l1_5_templ_very_base.h b/src/l1_5/anne/l1_5_templ_very_base.h index 9df1617..d5810a3 100644 --- a/src/l1_5/anne/l1_5_templ_very_base.h +++ b/src/l1_5/anne/l1_5_templ_very_base.h @@ -17,9 +17,16 @@ void generate_l1_5_template_instantiation_for_base_types(){ generate_rbtree_Set_templ_inst_guarded_header(l, ns, cstr(""), (set_instantiation_op){ .T = cstr("S64"), .t_integer = true }, true); - // todo: move vector declaration HERE + // todo: move vector declaration HERE (might wait) generate_buf_rbtree_Map_templ_inst_guarded_header(l, ns, cstr("#include \"../../gen/l1/VecKVPU64ToU64.h\"\n"), (map_instantiation_op){.K = cstr("U64"), .k_integer = true, .V = cstr("U64"), .v_integer = true,}); + + // todo: implement recursion for heap-allocated red-black tree, to make json dictionary clonable + generate_rbtree_Map_templ_inst_eve_header(l, ns, (map_instantiation_op){ + .K = cstr("VecU8"), .k_clonable = true, + .V = cstr("Json"), .v_clonable = false, + .skip_declaration_gen = true, + }, false, true); } #endif diff --git a/src/l1_5/anne/lucy.h b/src/l1_5/anne/lucy.h index ebd85ce..0c60aa5 100644 --- a/src/l1_5/anne/lucy.h +++ b/src/l1_5/anne/lucy.h @@ -9,7 +9,7 @@ void generate_l1_5_lucy_headers(){ generate_buf_rbtree_Map_templ_inst_eve_header(l, ns, (map_instantiation_op){ .K = cstr("U32"), .k_integer = true, .V = cstr("LucyStoredGlyph"), .v_primitive = true}); generate_rbtree_Map_templ_inst_eve_header(l, ns, (map_instantiation_op){ - .K = cstr("U32"), .k_integer = true, .V = cstr("LucyFaceFixedSize")}, true); + .K = cstr("U32"), .k_integer = true, .V = cstr("LucyFaceFixedSize")}, true, false); } diff --git a/src/l1_5/codegen/all_set_map_templ_util_inst.h b/src/l1_5/codegen/all_set_map_templ_util_inst.h index d07ad0c..e999a52 100644 --- a/src/l1_5/codegen/all_set_map_templ_util_inst.h +++ b/src/l1_5/codegen/all_set_map_templ_util_inst.h @@ -46,6 +46,7 @@ typedef struct { bool at, mat; bool pop, pop_substitute; + bool skip_declaration_gen; } map_instantiation_op; void map_instantiation_op_fix(map_instantiation_op* self){ @@ -67,7 +68,7 @@ void map_instantiation_op_fix(map_instantiation_op* self){ /* --- Sharing is caring --- */ -/* Assuming A nd B are passed as intended */ +/* Assuming A and B are passed as intended */ NODISCARD VecU8 codegen_rbtree_map__less(map_instantiation_op op, VecU8 A, VecU8 B){ if (op.guest_data_T.len > 0) { assert(op.alternative_less.len > 0); @@ -77,7 +78,7 @@ NODISCARD VecU8 codegen_rbtree_map__less(map_instantiation_op op, VecU8 A, VecU8 return VecU8_fmt("%s(%v, %v)", op.alternative_less, A, B); if (op.k_integer) return VecU8_fmt("%v < %v", A, B); - return VecU8_fmt("%s_less_%s(%v %v)", op.K, op.K, A, B); + return VecU8_fmt("%s_less_%s(%v, %v)", op.K, op.K, A, B); } NODISCARD VecU8 codegen_rbtree_map__exp_passing_key_val(map_instantiation_op op){ diff --git a/src/l1_5/codegen/buff_rbtree_set_map_template_inst.h b/src/l1_5/codegen/buff_rbtree_set_map_template_inst.h index 20d6f3d..872ece6 100644 --- a/src/l1_5/codegen/buff_rbtree_set_map_template_inst.h +++ b/src/l1_5/codegen/buff_rbtree_set_map_template_inst.h @@ -18,14 +18,18 @@ NODISCARD VecU8 codegen_buf_rbtree_map__exp_passing_cur_key(map_instantiation_op void codegen_append_buff_rbtree_map__structure_and_simplest_methods( VecU8* res, map_instantiation_op op, SpanU8 set, SpanU8 TT ){ + if (!op.skip_declaration_gen) { + VecU8_append_vec(res, VecU8_fmt("typedef struct %s %s;\n\n", set, set)); + } + VecU8_append_vec(res, VecU8_fmt( - "typedef struct {\n" + "struct %s{\n" SPACE "VecBufRBTreeNode tree;\n" SPACE "U64 root;\n" SPACE "Vec%s el;\n" "%v" - "} %s;\n\n", - TT, op.guest_data_T.len > 0 ? VecU8_fmt(SPACE "%s guest;\n", op.guest_data_T) : vcstr(""), set)); + "};\n\n", + set, TT, op.guest_data_T.len > 0 ? VecU8_fmt(SPACE "%s guest;\n", op.guest_data_T) : vcstr(""))); if (op.guest_data_T.len > 0) { VecU8_append_vec(res, VecU8_fmt( diff --git a/src/l1_5/codegen/rbtree_set_map_template_inst.h b/src/l1_5/codegen/rbtree_set_map_template_inst.h index 68028db..4eb71a1 100644 --- a/src/l1_5/codegen/rbtree_set_map_template_inst.h +++ b/src/l1_5/codegen/rbtree_set_map_template_inst.h @@ -28,18 +28,22 @@ NODISCARD VecU8 codegen_rbtree_map__exp_passing_cur_key(map_instantiation_op op) return VecU8_fmt("%s" "((%v*)cur)->key", op.k_integer ? cstr("") : cstr("&"), codegen_rbtree__node_struct_name(op)); } -void codegen_append_rbtree_map__structure_and_simplest_methods( - VecU8* res, map_instantiation_op op, SpanU8 set, SpanU8 TT - ){ +void codegen_append_rbtree_map__structure(VecU8* res, map_instantiation_op op, SpanU8 set){ + if (!op.skip_declaration_gen) { + VecU8_append_vec(res, VecU8_fmt("typedef struct %s %s;\n\n", set, set)); + } + VecU8_append_vec(res, VecU8_fmt( - "typedef struct {\n" + "struct %s {\n" SPACE "RBTreeNode* root;\n" SPACE "RBTreeNode* NIL;\n" "%v" /* "" / guest field */ - "} %s;\n\n", - op.guest_data_T.len == 0 ? vcstr("") : VecU8_fmt("%s guest;\n", op.guest_data_T), - set)); + "};\n\n", + set, + op.guest_data_T.len == 0 ? vcstr("") : VecU8_fmt("%s guest;\n", op.guest_data_T))); +} +void codegen_append_rbtree_map__simplest_methods(VecU8* res, map_instantiation_op op, SpanU8 set, SpanU8 TT){ VecU8_append_vec(res, VecU8_fmt( "NODISCARD %s %s_new(" "%v" ") {\n" /* set, set, "" / GT guest */ /* Only color field initialization is important (should be 0) */ @@ -290,6 +294,12 @@ void codegen_append_rbtree_map__structure_and_simplest_methods( "}\n\n", set, set, codegen_rbtree_map__taking_ref_k_argument(op), TT, set, set)); + + VecU8_append_vec(res, VecU8_fmt( + "bool %s_empty(const %s* self){\n" /* set, set */ + SPACE "return self->root == self->NIL;\n" + "}\n\n", + set, set)); } @@ -312,7 +322,8 @@ NODISCARD VecU8 generate_rbtree_Set_template_instantiation(set_instantiation_op VecU8 set_g = get_name_of_rbtree_set_structure(op); if (generate_node_struct) VecU8_append_vec(&res, codegen_rbtree__node_structure(map_op)); - codegen_append_rbtree_map__structure_and_simplest_methods(&res, map_op, VecU8_to_span(&set_g), op.T); + codegen_append_rbtree_map__structure(&res, map_op, VecU8_to_span(&set_g)); + codegen_append_rbtree_map__simplest_methods(&res, map_op, VecU8_to_span(&set_g), op.T); VecU8_drop(set_g); return res; } @@ -340,7 +351,8 @@ NODISCARD VecU8 get_name_of_rbtree_map_structure(map_instantiation_op op){ return VecU8_fmt("RBTree_Map%sTo%s", op.K, op.V); } -NODISCARD VecU8 generate_rbtree_Map_template_instantiation(map_instantiation_op op, bool generate_node_struct){ +NODISCARD VecU8 generate_rbtree_Map_template_instantiation(map_instantiation_op op, bool generate_node_struct, + bool generate_map_struct, bool generate_methods){ map_instantiation_op_fix(&op); VecU8 res = VecU8_new(); @@ -351,73 +363,89 @@ NODISCARD VecU8 generate_rbtree_Map_template_instantiation(map_instantiation_op if (generate_node_struct) VecU8_append_vec(&res, codegen_rbtree__node_structure(op)); - codegen_append_rbtree_map__structure_and_simplest_methods(&res, op, map, kvp); + if (generate_map_struct) + codegen_append_rbtree_map__structure(&res, op, map); + if (generate_methods) { + codegen_append_rbtree_map__simplest_methods(&res, op, map, kvp); - if (op.pop_substitute) { - VecU8_append_vec(&res, VecU8_fmt( - "%s" "Option%s %s_pop_substitute(%s* self, %s key, %s value) {\n" /* "" / NODISCARD , op.V, map, map, op.K, op.V */ - /* Using unsafe method with conditional ownership transfer */ - SPACE "RBTreeNode_%s* col = %s_try_insert(self, key, value);\n" /* kvp, map */ - SPACE "if (col == NULL) {\n" - SPACE SPACE "return None_%s();\n" /* op.V */ - SPACE "} else {\n" - "%v" /* "" / dropping col->key */ - SPACE SPACE "%s saved = col->value;\n" /* op.V */ - SPACE SPACE "col->key = key;\n" - SPACE SPACE "col->value = value;\n" - SPACE SPACE "return Some_%s(saved);\n" /* op.V */ - SPACE "}\n" - "}\n\n", - op.v_primitive ? cstr("") : cstr("NODISCARD "), op.V, map, map, op.K, op.V, - kvp, map, op.V, - op.k_primitive ? vcstr("") : VecU8_fmt(SPACE SPACE"%s_drop(col->key);\n", op.K), - op.V, op.V)); + if (op.pop_substitute) { + VecU8_append_vec(&res, VecU8_fmt( + "%s" "Option%s %s_pop_substitute(%s* self, %s key, %s value) {\n" /* "" / NODISCARD , op.V, map, map, op.K, op.V */ + /* Using unsafe method with conditional ownership transfer */ + SPACE "RBTreeNode_%s* col = %s_try_insert(self, key, value);\n" /* kvp, map */ + SPACE "if (col == NULL) {\n" + SPACE SPACE "return None_%s();\n" /* op.V */ + SPACE "} else {\n" + "%v" /* "" / dropping col->key */ + SPACE SPACE "%s saved = col->value;\n" /* op.V */ + SPACE SPACE "col->key = key;\n" + SPACE SPACE "col->value = value;\n" + SPACE SPACE "return Some_%s(saved);\n" /* op.V */ + SPACE "}\n" + "}\n\n", + op.v_primitive ? cstr("") : cstr("NODISCARD "), op.V, map, map, op.K, op.V, + kvp, map, op.V, + op.k_primitive ? vcstr("") : VecU8_fmt(SPACE SPACE"%s_drop(col->key);\n", op.K), + op.V, op.V)); + } + if (!op.v_primitive) { + VecU8_append_vec(&res, VecU8_fmt( + "bool %s_erase_substitute(%s* self, %s key, %s value) {\n" /* map, map, op.K, op.V */ + SPACE "RBTreeNode_%s* col = %s_try_insert(self, key, value);\n" /* kvp, map */ + SPACE "if (col == NULL)\n" + SPACE SPACE "return true;\n" + "%v" "%v" /* "" / op.K_drop(col->key), "" / op.V_drop(col->value) */ + SPACE "col->key = key;\n" + SPACE "col->value = value;\n" + SPACE "return false;\n" + "}\n\n", + map, map, op.K, op.V, kvp, map, + op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(col->key);\n", op.K), + op.v_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(col->value);\n", op.V))); + } + + if (op.pop){ + // todo: write _pop_by_it + + // todo: rewrite pop using _pop_by_it + VecU8_append_vec(&res, VecU8_fmt( + "Option%s %s_pop(%s* self, %v key) {\n" /* op.V, map, map, taking_ref_k_argument */ + SPACE "RBTreeNode_%s* v = %s_find(self, key);\n" /* kvp, map */ + SPACE "if (v == NULL)\n" + SPACE SPACE "return None_%s();\n" /* op.V */ + "%v" /* "" / op.K_drop(v->key) */ + "%s saved = v->value;\n" /* op.V */ + SPACE "RBTree_erase_empty_by_iter(&self->root, self->NIL, (RBTreeNode*)v);\n" + SPACE "free(v);\n" + SPACE "return Some_%s(saved);\n" /* op.V */ + "}\n\n", + op.V, map, map, codegen_rbtree_map__taking_ref_k_argument(op), + kvp, map, op.V, + op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(v->key);\n", op.K), + op.V, op.V)); + } + // todo: write generator for methods _at and _mat } - if (!op.v_primitive) { - VecU8_append_vec(&res, VecU8_fmt( - "bool %s_erase_substitute(%s* self, %s key, %s value) {\n" /* map, map, op.K, op.V */ - SPACE "RBTreeNode_%s* col = %s_try_insert(self, key, value);\n" /* kvp, map */ - SPACE "if (col == NULL)\n" - SPACE SPACE "return true;\n" - "%v" "%v" /* "" / op.K_drop(col->key), "" / op.V_drop(col->value) */ - SPACE "col->key = key;\n" - SPACE "col->value = value;\n" - SPACE "return false;\n" - "}\n\n", - map, map, op.K, op.V, kvp, map, - op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(col->key);\n", op.K), - op.v_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(col->value);\n", op.V))); - } - - if (op.pop){ - // todo: write _pop_by_it - - // todo: rewrite pop using _pop_by_it - VecU8_append_vec(&res, VecU8_fmt( - "Option%s %s_pop(%s* self, %v key) {\n" /* op.V, map, map, taking_ref_k_argument */ - SPACE "RBTreeNode_%s* v = %s_find(self, key);\n" /* kvp, map */ - SPACE "if (v == NULL)\n" - SPACE SPACE "return None_%s();\n" /* op.V */ - "%v" /* "" / op.K_drop(v->key) */ - "%s saved = v->value;\n" /* op.V */ - SPACE "RBTree_erase_empty_by_iter(&self->root, self->NIL, (RBTreeNode*)v);\n" - SPACE "free(v);\n" - SPACE "return Some_%s(saved);\n" /* op.V */ - "}\n\n", - op.V, map, map, codegen_rbtree_map__taking_ref_k_argument(op), - kvp, map, op.V, - op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(v->key);\n", op.K), - op.V, op.V)); - } - // todo: write generator for methods _at and _mat - return res; } void generate_rbtree_Map_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, map_instantiation_op op, - bool generate_node_struct) { - generate_SOME_templ_inst_eve_header(layer, bonus_ns, - generate_rbtree_Map_template_instantiation(op, generate_node_struct), get_name_of_rbtree_map_structure(op)); + bool generate_node_struct, bool separate_struct_and_methods) { + if (separate_struct_and_methods) { + assert(!generate_node_struct); + VecU8 name_for_struct = VecU8_fmt("%v_struct", get_name_of_rbtree_map_structure(op)); + VecU8 name_for_method = VecU8_fmt("%v_method", get_name_of_rbtree_map_structure(op)); + generate_SOME_templ_inst_eve_header(layer, bonus_ns, + generate_rbtree_Map_template_instantiation(op, false, true, false), + name_for_struct); + generate_SOME_templ_inst_eve_header(layer, bonus_ns, + generate_rbtree_Map_template_instantiation(op, false, false, true), + name_for_method); + } else { + generate_SOME_templ_inst_eve_header(layer, bonus_ns, + generate_rbtree_Map_template_instantiation(op, generate_node_struct, true, true), + get_name_of_rbtree_map_structure(op)); + } } void generate_rbtree_Map_templ_inst_guarded_header( @@ -426,8 +454,8 @@ void generate_rbtree_Map_templ_inst_guarded_header( VecU8 all_dependencies = VecU8_fmt("%v%s", codegen_include_relative_to_root(bonus_ns, cstr("src/l1_5/core/rb_tree_node.h")), dependencies); generate_SOME_templ_inst_guarded_header(layer, bonus_ns, all_dependencies, - generate_rbtree_Map_template_instantiation(op, generate_node_struct), get_name_of_rbtree_map_structure(op)); + generate_rbtree_Map_template_instantiation(op, generate_node_struct, true, true), + get_name_of_rbtree_map_structure(op)); } - #endif diff --git a/src/l1_5/core/parsing_string.h b/src/l1_5/core/parsing_string.h index 7c090e9..8780817 100644 --- a/src/l1_5/core/parsing_string.h +++ b/src/l1_5/core/parsing_string.h @@ -4,17 +4,6 @@ #include "../../l1/core/VecU8_as_str.h" #include -void SpanU8_parsing_expect_char(SpanU8* rem, char ch){ - if (rem->len == 0) { - abortf("Unexpected EOF. Syntax error\n"); - } - if (*rem->data != (U8)ch) { - abortf("Expected %d, got %d. Syntax error\n", (int)(*rem->data), (int)ch); - } - rem->data++; - rem->len--; -} - /* if `expected` is prefix of `rem`, `rem` will be advanced by |`expected`| and true will be returned. * Otherwise false is returned and `rem` is untouched */ bool SpanU8_parsing_try_read_prefix(SpanU8* rem, SpanU8 expected){ @@ -29,13 +18,18 @@ bool SpanU8_parsing_try_read_prefix(SpanU8* rem, SpanU8 expected){ return false; } +void SpanU8_parsing_skip_char(SpanU8* rem){ + assert(rem->len > 0); + rem->data++; + rem->len--; +} + bool SpanU8_parsing_try_read_char(SpanU8* rem, char ch){ if (rem->len == 0) { return false; } if (rem->data[0] == (U8)ch) { - rem->data++; - rem->len--; + SpanU8_parsing_skip_char(rem); return true; } return false; @@ -50,19 +44,13 @@ void SpanU8_parsing_skip_entire_line(SpanU8* rem){ } } -void SpanU8_parsing_skip_char(SpanU8* rem){ - assert(rem->len > 0); - rem->data++; - rem->len--; -} - bool SpanU8_parsing_is_char_ahead(SpanU8* rem, char ch){ return rem->len > 0 ? rem->data[0] == (U8)ch : false; } /* Time to learn how to read integers */ -/* returns positive on error, returns 0 on success */ +/* Returns positive on error, 0 on success, rem_ret is untouched on error */ int SpanU8_read_U64(SpanU8* rem_ret, U64* res_ret){ SpanU8 rem = *rem_ret; U64 x = 0; @@ -102,6 +90,7 @@ U64 SpanU64_expect_read_U64(SpanU8* rem){ return x; } +/* Returns positive on error, 0 on success, rem_ret is untouched on error */ int SpanU8_read_S64(SpanU8* rem_ret, S64* ret){ SpanU8 rem = *rem_ret; U64 x = 0; @@ -156,7 +145,7 @@ int SpanU8_read_S64(SpanU8* rem_ret, S64* ret){ } -/* returns positive int on error, 0 on success */ +/* returns positive int on error, 0 on success, rem_ret is untouched on error */ int SpanU8_read_float(SpanU8* rem_ret, float* res_ret){ SpanU8 rem = *rem_ret; @@ -187,8 +176,10 @@ int SpanU8_read_float(SpanU8* rem_ret, float* res_ret){ res = (res * 10 + d); } saw_digit = true; - } else if (ch == 'e') { + } else if (ch == 'e' || ch == 'E') { SpanU8_parsing_skip_char(&rem); + if (SpanU8_parsing_is_char_ahead(&rem, '+')) + SpanU8_parsing_skip_char(&rem); S64 exp; int ret = SpanU8_read_S64(&rem, &exp); if (ret) @@ -227,4 +218,41 @@ float SpanU8_expect_read_float(SpanU8* rem){ return x; } +void SpanU8_parsing_skip_spaces(SpanU8* rem){ + while (rem->len) { + U8 ch = *rem->data; + if (!(ch == '\t' || ch == ' ' || ch == '\n' || ch == '\r')) + break; + SpanU8_parsing_skip_char(rem); + } +} + +bool is_hex_char(char ch){ + return ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F'); +} + +static_assert('a' > 'A', "ASCII check"); +static_assert('A' > '0', "ASCII check"); + +U32 char_to_hex_digit(char ch){ + if (ch >= 'a') + return ch - 'a' + 10; + if (ch >= 'A') + return ch - 'A' + 10; + return ch - '0'; +} + +/* Should return true on success */ +bool SpanU8_parsing_try_read_hex_digit(SpanU8* rem, U32* ret){ + if (rem->len == 0) + return false; + char ch = (char)rem->data[0]; + if (is_hex_char(ch)) { + *ret = char_to_hex_digit(ch); + SpanU8_parsing_skip_char(rem); + return true; + } + return false; +} + #endif diff --git a/src/l2/anne/r4.h b/src/l2/anne/r4.h index a264477..3d9c779 100644 --- a/src/l2/anne/r4.h +++ b/src/l2/anne/r4.h @@ -895,19 +895,19 @@ VecVecs64vec2 generate_funny_polygon(){ /* We are on l2 */ int gen_assets_for_r4() { - // mkdir_nofail("l2/models"); - // mkdir_nofail("l2/textures"); - // mkdir_nofail("l2/textures/r4"); - // r4_asset_gen_generic_mesh_one_fourth_of_a_cylinder_2(10, 2, 6); - // alice_write_shiny_mesh_to_file(generate_shiny_cube((vec3){0.6f, 0.6f, 0.7f}), vcstr("l2/models/cube.AliceShinyMesh")); - // alice_write_shiny_mesh_to_file(generate_shiny_lamp(0.3f, 0.13f, 0.19f), vcstr("l2/models/lamp.AliceShinyMesh")); - // r4_asset_gen_generic_mesh_quad(10, 10, vcstr("l2/models/quad.AliceGenericMesh")); - // r4_asset_gen_generic_mesh_cylinder(200, 0.4f, 0.17f, 30, vcstr("l2/models/puck.AliceGenericMesh"), - // vcstr("l2/textures/puck_TEMPLATE.png"), vcstr("l2/textures/puck_NORMAL.png")); - // r4_asset_gen_generic_mesh_cylinder(100, 0.04f, 1.5f, 4, vcstr("l2/models/stick.AliceGenericMesh"), - // vcstr("l2/textures/stick_TEMPLATE.png"), vcstr("l2/textures/stick_NORMAL.png")); - // r4_generate_flat_normal_map(vcstr("l2/textures/flat_NORMAL.png")); - // generate_single_pixel_gray_tex(vcstr("l2/textures/no_SPECULAR.png"), 0); + mkdir_nofail("l2/models"); + mkdir_nofail("l2/textures"); + mkdir_nofail("l2/textures/r4"); + r4_asset_gen_generic_mesh_one_fourth_of_a_cylinder_2(10, 2, 6); + alice_write_shiny_mesh_to_file(generate_shiny_cube((vec3){0.6f, 0.6f, 0.7f}), vcstr("l2/models/cube.AliceShinyMesh")); + alice_write_shiny_mesh_to_file(generate_shiny_lamp(0.3f, 0.13f, 0.19f), vcstr("l2/models/lamp.AliceShinyMesh")); + r4_asset_gen_generic_mesh_quad(10, 10, vcstr("l2/models/quad.AliceGenericMesh")); + r4_asset_gen_generic_mesh_cylinder(200, 0.4f, 0.17f, 30, vcstr("l2/models/puck.AliceGenericMesh"), + vcstr("l2/textures/puck_TEMPLATE.png"), vcstr("l2/textures/puck_NORMAL.png")); + r4_asset_gen_generic_mesh_cylinder(100, 0.04f, 1.5f, 4, vcstr("l2/models/stick.AliceGenericMesh"), + vcstr("l2/textures/stick_TEMPLATE.png"), vcstr("l2/textures/stick_NORMAL.png")); + r4_generate_flat_normal_map(vcstr("l2/textures/flat_NORMAL.png")); + generate_single_pixel_gray_tex(vcstr("l2/textures/no_SPECULAR.png"), 0); { /* Just a test */ VecVecs64vec2 P = generate_funny_polygon(); r4_asset_gen_generic_mesh_horizontal_polygon(&P, (mat3x2){.x.x = 1, .y.y = 1}, diff --git a/src/l2/core/json.h b/src/l2/core/json.h new file mode 100644 index 0000000..82b4209 --- /dev/null +++ b/src/l2/core/json.h @@ -0,0 +1,95 @@ +#ifndef prototype1_src_l2_core_json_h +#define prototype1_src_l2_core_json_h + +#include "../../l1/core/VecU8_as_str.h" +#include "../../l1_5/core/rb_tree_node.h" + +typedef struct Json Json; + +typedef struct VecJson VecJson; +typedef struct RBTree_MapVecU8ToJson RBTree_MapVecU8ToJson; + +#include "../../../gen/l1/eve/VecJson_struct.h" +#include "../../../gen/l1_5/eve/RBTree_MapVecU8ToJson_struct.h" + +typedef enum { + Json_integer, + Json_float, + Json_dict, + Json_arr, + Json_str, + Json_false, + Json_true, + Json_none, +} Json_variant; + +struct Json{ + Json_variant variant; + union { + S64 integer; + float float_num; + RBTree_MapVecU8ToJson dict; + VecJson arr; + VecU8 str; + }; +}; + +typedef struct RBTreeNode_KVPVecU8ToJson { + RBTreeNode base; + VecU8 key; + Json value; +} RBTreeNode_KVPVecU8ToJson; + +/* Pulling declarations of methods, defined below */ +void VecJson_drop(VecJson self); +void RBTree_MapVecU8ToJson_drop(RBTree_MapVecU8ToJson self); + +void Json_drop(Json self) { + if (self.variant == Json_str) { + VecU8_drop(self.str); + } else if (self.variant == Json_arr) { + VecJson_drop(self.arr); + } else if (self.variant == Json_dict) { + RBTree_MapVecU8ToJson_drop(self.dict); + } +} + +#include "../../../gen/l1/eve/VecJson_methods.h" +#include "../../../gen/l1_5/eve/RBTree_MapVecU8ToJson_method.h" + +Json Json_from_float(float x){ + return (Json){.variant = Json_float, .float_num = x}; +} + +Json Json_from_int(S64 x){ + return (Json){.variant = Json_float, .integer = x}; +} + +Json Json_from_VecU8(VecU8 x){ + return (Json){.variant = Json_str, .str = x}; +} + +Json Json_from_SpanU8(SpanU8 x){ + return (Json){.variant = Json_str, .str = VecU8_from_span(x)}; +} + +Json Json_from_bool(bool x){ + return (Json){.variant = x ? Json_true : Json_false}; +} + +const Json Json_None = ((Json){.variant = Json_none}); +const Json Json_True = ((Json){.variant = Json_true}); +const Json Json_False = ((Json){.variant = Json_false}); + +Json Json_from_VecJson(VecJson arr){ + return (Json){.variant = Json_arr, .arr = arr}; +} + +Json Json_from_MapVecU8ToJson(RBTree_MapVecU8ToJson dict){ + return (Json){.variant = Json_dict, .dict = dict}; +} + +// Bonus +#include "../../../gen/l1/eve/OptionJson.h" + +#endif \ No newline at end of file diff --git a/src/l2/core/json_encoded.h b/src/l2/core/json_encoded.h new file mode 100644 index 0000000..156a875 --- /dev/null +++ b/src/l2/core/json_encoded.h @@ -0,0 +1,278 @@ +#ifndef prototype1_src_l2_core_json_encoded_h +#define prototype1_src_l2_core_json_encoded_h + +#include "../../l1_5/core/parsing_string.h" +#include "json.h" + +void json_encoding_append_utf16(VecU8* res, U8 codepoint){ + assert(codepoint < 32); + VecU8_append_span(res, cstr("\\u00")); + VecU8_append(res, digit_to_big_hex(codepoint >> 4)); + VecU8_append(res, digit_to_big_hex(codepoint & 0xF)); +} + +/* Str is being encoded as JSON string literal */ +void json_encoding_append_string(VecU8* res, const VecU8* str){ + VecU8_append(res, '"'); + for (size_t i = 0; i < str->len; i++) { + U8 ch = str->buf[i]; + if (ch == '\t') { + VecU8_append_span(res, cstr("\\t")); + } else if (ch == '\n') { + VecU8_append_span(res, cstr("\\n")); + } else if (ch == '\r') { + VecU8_append_span(res, cstr("\\r")); + } else if (ch <= 31) { + json_encoding_append_utf16(res, ch); + } else if (ch == '\"') { + VecU8_append_span(res, cstr("\\\"")); + } else if (ch == '\\') { + VecU8_append_span(res, cstr("\\\\")); + } else { + VecU8_append(res, ch); + } + } + VecU8_append(res, '"'); +} + +/* No prettyprinting */ +void json_encoding_append_to_str(const Json* obj, VecU8* res){ + if (obj->variant == Json_false) { + VecU8_append_span(res, cstr("false")); + } else if (obj->variant == Json_true) { + VecU8_append_span(res, cstr("true")); + } else if (obj->variant == Json_none) { + VecU8_append_span(res, cstr("none")); + } else if (obj->variant == Json_integer) { + S64_stringification_into_buf(obj->integer, res); + } else if (obj->variant == Json_float) { + VecU8_append_vec(res, VecU8_format("%f", obj->float_num)); + } else if (obj->variant == Json_str) { + json_encoding_append_string(res, &obj->str); + } else if (obj->variant == Json_arr) { + VecU8_append(res, '['); + const VecJson* arr = &obj->arr; + for (size_t i = 0; i < arr->len; i++) { + if (i) { + VecU8_append_span(res, cstr(", ")); + } + json_encoding_append_to_str(&arr->buf[i], res); + } + VecU8_append(res, ']'); + } else if (obj->variant == Json_dict) { + VecU8_append(res, '{'); + bool was = false; + for (RBTreeNode_KVPVecU8ToJson* it = RBTree_MapVecU8ToJson_find_min(&obj->dict); it;) { + if (was) { + VecU8_append_span(res, cstr(", ")); + } + json_encoding_append_string(res, &it->key); + VecU8_append_span(res, cstr(": ")); + json_encoding_append_to_str(&it->value, res); + was = true; + it = RBTree_MapVecU8ToJson_find_next(&obj->dict, it); + } + VecU8_append(res, '}'); + } +} + +/* json depth is w => Required stack depth is w frames */ +VecU8 json_encode(const Json* obj){ + VecU8 res = VecU8_new(); + json_encoding_append_to_str(obj, &res); + return res; +} + +/* Kids had their fun with json encoding. Now it's time for adults to enjoy some parsing */ + + + +OptionJson json_decoding_h_no_spaces(SpanU8* rem, U32 depth_rem); + +OptionJson json_decoding_h(SpanU8* rem, U32 depth_rem){ + SpanU8_parsing_skip_spaces(rem); + OptionJson x = json_decoding_h_no_spaces(rem, depth_rem); + SpanU8_parsing_skip_spaces(rem); + return x; +} + +/* Returns positive on error, 0 on success */ +int json_decoding_parse_string(SpanU8* rem, VecU8* ret_str){ + if (!SpanU8_parsing_try_read_char(rem, '\"')) { + return 1; + } + VecU8 res = VecU8_new(); + U16 prev_high_surrogate = 0; + while (true) { + if (rem->len == 0) { + VecU8_drop(res); + return 1; + } + U8 ch = rem->data[0]; + SpanU8_parsing_skip_char(rem); + if (ch == '\"') { + *ret_str = res; + return 0; + } + if (ch == '\\') { + if (rem->len == 0) { + VecU8_drop(res); + return 2; + } + ch = rem->data[0]; + SpanU8_parsing_skip_char(rem); + if (ch == '\"' || ch == '\\' || ch == '/') { + VecU8_append(&res, ch); + } else if (ch == 'b') { + VecU8_append(&res, '\b'); + } else if (ch == 'f') { + VecU8_append(&res, '\f'); + } else if (ch == 'n') { + VecU8_append(&res, '\b'); + } else if (ch == 'r') { + VecU8_append(&res, '\r'); + } else if (ch == 't') { + VecU8_append(&res, '\t'); + } else if (ch == 'u') { + U16 cur_word = 0; + for (int i = 0; i < 4; i++) { + U32 d; + if (!SpanU8_parsing_try_read_hex_digit(rem, &d)) { + VecU8_drop(res); + return 3; + } + cur_word = (cur_word << 4) | (U16)d; + } + if (0xDC00 <= cur_word && cur_word < 0xE000) { + /* Low surrogate pair */ + if (prev_high_surrogate == 0) { + VecU8_drop(res); + return 4; + } + U32 U = (U32)0x10000 + ((U32)(prev_high_surrogate - 0xD800) << 10) + (U32)(cur_word - 0xDC00); + VecU8_encode_as_utf8(&res, U); + prev_high_surrogate = 0; + } else if (0xD800 <= cur_word && cur_word < 0xDC00) { + /* High surrogate pair */ + prev_high_surrogate = cur_word; + } else { + prev_high_surrogate = 0; + VecU8_encode_as_utf8(&res, (U32)cur_word); + } + } else { + VecU8_drop(res); + return 5; + } + } else { + /* We ignore illegal characters in string literals */ + VecU8_append(&res, ch); + } + } +} + +OptionJson json_decoding_h_no_spaces(SpanU8* rem, U32 depth_rem){ + if (depth_rem == 0) { + return None_Json(); + } + float fl_value; + int fl_code = SpanU8_read_float(rem, &fl_value); + if (fl_code == 0) + return Some_Json(Json_from_float(fl_value)); + S64 int_value; + int int_code = SpanU8_read_S64(rem, &int_value); + if (int_code == 0) + return Some_Json(Json_from_int(int_value)); + bool false_code = SpanU8_parsing_try_read_prefix(rem, cstr("false")); + if (false_code) + return Some_Json(Json_False); + bool true_code = SpanU8_parsing_try_read_prefix(rem, cstr("true")); + if (true_code) + return Some_Json(Json_True); + bool none_code = SpanU8_parsing_try_read_prefix(rem, cstr("none")); + if (none_code) + return Some_Json(Json_None); + if (SpanU8_parsing_is_char_ahead(rem, '\"')) { + VecU8 str; + int str_code = json_decoding_parse_string(rem, &str); + if (str_code) { + /* str is uninitialized on error */ + return None_Json(); + } + /* In case of success, str starts owning a VecU8 */ + return Some_Json(Json_from_VecU8(str)); + } + if (SpanU8_parsing_try_read_char(rem, '[')) { + SpanU8_parsing_skip_spaces(rem); + VecJson arr = VecJson_new(); + while (true) { + if (SpanU8_parsing_try_read_char(rem, ']')) { + return Some_Json(Json_from_VecJson(arr)); + } + if (arr.len > 0) { + if (!SpanU8_parsing_try_read_char(rem, ',')) { + VecJson_drop(arr); + return None_Json(); + } + } + OptionJson x = json_decoding_h(rem, depth_rem - 1); + if (x.variant == Option_None) { + VecJson_drop(arr); + return None_Json(); + } + VecJson_append(&arr, x.some); + } + } + if (SpanU8_parsing_try_read_char(rem, '{')) { + SpanU8_parsing_skip_spaces(rem); + RBTree_MapVecU8ToJson dict = RBTree_MapVecU8ToJson_new(); + while (true) { + if (SpanU8_parsing_try_read_char(rem, '}')) { + return Some_Json(Json_from_MapVecU8ToJson(dict)); + } + // todo: add _empty method to rb tree map + if (!RBTree_MapVecU8ToJson_empty(&dict)) { + if (!SpanU8_parsing_try_read_char(rem, ',')) { + RBTree_MapVecU8ToJson_drop(dict); + return None_Json(); + } + VecU8 key; + int key_code = json_decoding_parse_string(rem, &key); + if (key_code) { + RBTree_MapVecU8ToJson_drop(dict); + return None_Json(); + } + SpanU8_parsing_skip_spaces(rem); + if (!SpanU8_parsing_try_read_char(rem, ':')) { + RBTree_MapVecU8ToJson_drop(dict); + VecU8_drop(key); + return None_Json(); + } + OptionJson x = json_decoding_h(rem, depth_rem - 1); + if (x.variant == Option_None) { + RBTree_MapVecU8ToJson_drop(dict); + VecU8_drop(key); + return None_Json(); + } + bool iret = RBTree_MapVecU8ToJson_insert(&dict, key, x.some); + if (!iret) { + /* Two elements of dictionary share the same key. Very illegal */ + RBTree_MapVecU8ToJson_drop(dict); + return None_Json(); + } + } + } + } + return None_Json(); +} + +/* Given depth_allowed=w, maximum of w frames will be used on stack and the returned Json object will + * have a maximum depth of w */ +OptionJson json_decode(SpanU8 text, U32 depth_allowed){ + OptionJson x = json_decoding_h(&text, depth_allowed); + if (x.variant == Option_Some && text.len > 0) { + return None_Json(); + } + return x; +} + +#endif \ No newline at end of file diff --git a/src/l2/marie/shape_geom.h b/src/l2/marie/shape_geom.h index 200f777..5136363 100644 --- a/src/l2/marie/shape_geom.h +++ b/src/l2/marie/shape_geom.h @@ -137,17 +137,6 @@ VecU64 marie_polygon_ear_cutting_triangulation(Spans64vec2 P){ return triangles; } -/* Recursion is dead. Recursion remains dead. And we have killed it. - * Used in hole-connecting triangulation algorithm */ -typedef struct { - U64 hole_id; - U64 vertex_in_hole_id; - U64 progress; - U64 progress_in_starting_vertex; -} MarieHoleConnectTriangStackFrame; - -#include "../../../gen/l1/eve/marie/VecMarieHoleConnectTriangStackFrame.h" - /* Used in hole-connecting triangulation algorithm */ typedef struct{ U64 hole_id; diff --git a/src/l2/tests/t_parsing.c b/src/l2/tests/t_parsing.c new file mode 100644 index 0000000..80221ad --- /dev/null +++ b/src/l2/tests/t_parsing.c @@ -0,0 +1,6 @@ +#include "../core/json_encoded.h" + +int main(){ + + return 0; +} diff --git a/src/l3/r4/r4.c b/src/l3/r4/r4.c index 980c917..bbc6d5e 100644 --- a/src/l3/r4/r4.c +++ b/src/l3/r4/r4.c @@ -1,3 +1,4 @@ +#include "../../l2/core/json.h" #include "../../l2/allie/allie.c" AliceGenericMeshPath AliceGenericMeshPath_for_log(SpanU8 root_dir, U64 w, U64 r, U64 k) {