diff options
| author | Zuhaitz <zuhaitz.zechhub@gmail.com> | 2026-01-25 22:36:29 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-25 22:36:29 +0000 |
| commit | dc69e7a19e86373ee117d56b3747ff56d1631e96 (patch) | |
| tree | 1b94f1f43b98a26a9c153585568505bed95e60ec /src | |
| parent | fa858115f6b9625065b2488aeee028fe2c7d60b2 (diff) | |
| parent | 74a4469dfba9a63a57caabc65c4faa65b2a59308 (diff) | |
Merge pull request #127 from sureshkrishnan-ai/JsonType
fixed buffer overflow in vector. Added serialize and deserialize in j…
Diffstat (limited to 'src')
| -rw-r--r-- | src/codegen/codegen_decl.c | 13 | ||||
| -rw-r--r-- | src/codegen/codegen_stmt.c | 2 | ||||
| -rw-r--r-- | src/parser/parser_core.c | 215 | ||||
| -rw-r--r-- | src/parser/parser_stmt.c | 24 |
4 files changed, 245 insertions, 9 deletions
diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c index d525963..e5d73a0 100644 --- a/src/codegen/codegen_decl.c +++ b/src/codegen/codegen_decl.c @@ -22,13 +22,15 @@ static void emit_freestanding_preamble(FILE *out) "uint64_t\n", out); fputs("#define F32 float\n#define F64 double\n", out); - fputs("#define _z_str(x) _Generic((x), _Bool: \"%d\", char: \"%c\", " + fputs("static inline const char* _z_bool_str(_Bool b) { return b ? \"true\" : \"false\"; }\n", out); + fputs("#define _z_str(x) _Generic((x), _Bool: \"%s\", char: \"%c\", " "signed char: \"%c\", unsigned char: \"%u\", short: \"%d\", " "unsigned short: \"%u\", int: \"%d\", unsigned int: \"%u\", " "long: \"%ld\", unsigned long: \"%lu\", long long: \"%lld\", " "unsigned long long: \"%llu\", float: \"%f\", double: \"%f\", " "char*: \"%s\", void*: \"%p\")\n", out); + fputs("#define _z_arg(x) _Generic((x), _Bool: _z_bool_str(x), default: (x))\n", out); fputs("typedef struct { void *func; void *ctx; } z_closure_T;\n", out); fputs("__attribute__((weak)) void* z_malloc(usize sz) { return NULL; }\n", out); @@ -62,7 +64,10 @@ void emit_preamble(ParserContext *ctx, FILE *out) fputs("#define ZC_AUTO auto\n", out); fputs("#define ZC_CAST(T, x) static_cast<T>(x)\n", out); // C++ _z_str via overloads - fputs("inline const char* _z_str(bool) { return \"%d\"; }\n", out); + fputs("inline const char* _z_bool_str(bool b) { return b ? \"true\" : \"false\"; }\n", out); + fputs("inline const char* _z_str(bool) { return \"%s\"; }\n", out); + fputs("inline const char* _z_arg(bool b) { return _z_bool_str(b); }\n", out); + fputs("template<typename T> inline T _z_arg(T x) { return x; }\n", out); fputs("inline const char* _z_str(char) { return \"%c\"; }\n", out); fputs("inline const char* _z_str(int) { return \"%d\"; }\n", out); fputs("inline const char* _z_str(unsigned int) { return \"%u\"; }\n", out); @@ -82,13 +87,15 @@ void emit_preamble(ParserContext *ctx, FILE *out) fputs("#define ZC_AUTO __auto_type\n", out); fputs("#define ZC_CAST(T, x) ((T)(x))\n", out); fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out); - fputs("#define _z_str(x) _Generic((x), _Bool: \"%d\", char: \"%c\", " + fputs("static inline const char* _z_bool_str(_Bool b) { return b ? \"true\" : \"false\"; }\n", out); + fputs("#define _z_str(x) _Generic((x), _Bool: \"%s\", char: \"%c\", " "signed char: \"%c\", unsigned char: \"%u\", short: \"%d\", " "unsigned short: \"%u\", int: \"%d\", unsigned int: \"%u\", " "long: \"%ld\", unsigned long: \"%lu\", long long: \"%lld\", " "unsigned long long: \"%llu\", float: \"%f\", double: \"%f\", " "char*: \"%s\", void*: \"%p\")\n", out); + fputs("#define _z_arg(x) _Generic((x), _Bool: _z_bool_str(x), default: (x))\n", out); } fputs("typedef size_t usize;\ntypedef char* string;\n", out); diff --git a/src/codegen/codegen_stmt.c b/src/codegen/codegen_stmt.c index ff8ea46..cba55b4 100644 --- a/src/codegen/codegen_stmt.c +++ b/src/codegen/codegen_stmt.c @@ -1519,7 +1519,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) emit_auto_type(ctx, node->repl_print.expr, node->token, out); fprintf(out, " _zval = ("); codegen_expression(ctx, node->repl_print.expr, out); - fprintf(out, "); fprintf(stdout, _z_str(_zval), _zval); fprintf(stdout, " + fprintf(out, "); fprintf(stdout, _z_str(_zval), _z_arg(_zval)); fprintf(stdout, " "\"\\n\"); }\n"); break; } diff --git a/src/parser/parser_core.c b/src/parser/parser_core.c index 7e182e2..5e685d7 100644 --- a/src/parser/parser_core.c +++ b/src/parser/parser_core.c @@ -637,6 +637,221 @@ static ASTNode *generate_derive_impls(ParserContext *ctx, ASTNode *strct, char * code = xmalloc(1024); sprintf(code, "impl Copy for %s {}", name); } + else if (0 == strcmp(trait, "FromJson")) + { + // Generate from_json(j: JsonValue*) -> Result<StructName> + // Only works for structs (not enums) + if (strct->type != NODE_STRUCT) + { + zwarn_at(strct->token, "@derive(FromJson) only works on structs"); + continue; + } + + char body[8192]; + body[0] = 0; + + // Track Vec<String> fields for forget calls + char *vec_fields[32]; + int vec_field_count = 0; + + // Build field assignments + ASTNode *f = strct->strct.fields; + while (f) + { + if (f->type == NODE_FIELD) + { + char *fn = f->field.name; + char *ft = f->field.type; + char assign[2048]; + + if (!fn || !ft) + { + f = f->next; + continue; + } + + // Map types to appropriate get_* calls + if (strcmp(ft, "int") == 0) + { + sprintf(assign, "let _f_%s = (*j).get_int(\"%s\").unwrap_or(0);\n", fn, fn); + } + else if (strcmp(ft, "double") == 0) + { + sprintf(assign, "let _f_%s = (*j).get_float(\"%s\").unwrap_or(0.0);\n", fn, fn); + } + else if (strcmp(ft, "bool") == 0) + { + sprintf(assign, "let _f_%s = (*j).get_bool(\"%s\").unwrap_or(false);\n", fn, fn); + } + else if (strcmp(ft, "char*") == 0) + { + sprintf(assign, "let _f_%s = (*j).get_string(\"%s\").unwrap_or(\"\");\n", fn, fn); + } + else if (strcmp(ft, "String") == 0) + { + sprintf(assign, "let _f_%s = String::new((*j).get_string(\"%s\").unwrap_or(\"\"));\n", fn, fn); + } + else if (ft && strstr(ft, "Vec") && strstr(ft, "String")) + { + // Track this field for forget() call later + if (vec_field_count < 32) + { + vec_fields[vec_field_count++] = fn; + } + sprintf(assign, + "let _f_%s = Vec<String>::new();\n" + "let _arr_%s = (*j).get_array(\"%s\");\n" + "if _arr_%s.is_some() {\n" + " let _a_%s = _arr_%s.unwrap();\n" + " for let _i_%s: usize = 0; _i_%s < _a_%s.len(); _i_%s = _i_%s + 1 {\n" + " let _item_%s = _a_%s.at(_i_%s);\n" + " if _item_%s.is_some() {\n" + " let _str_%s = (*_item_%s.unwrap()).as_string();\n" + " if _str_%s.is_some() {\n" + " let _s_%s = String::new(_str_%s.unwrap());\n" + " _f_%s.push(_s_%s); _s_%s.forget();\n" + " }\n" + " }\n" + " }\n" + "}\n", + fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn); + } + else + { + // Nested struct: call NestedType::from_json recursively + sprintf(assign, + "let _opt_%s = (*j).get(\"%s\");\n" + "let _f_%s: %s;\n" + "if _opt_%s.is_some() { _f_%s = %s::from_json(_opt_%s.unwrap()).unwrap(); }\n", + fn, fn, fn, ft, fn, fn, ft, fn); + } + strcat(body, assign); + } + f = f->next; + } + + // Build struct initialization + strcat(body, "return Result<"); + strcat(body, name); + strcat(body, ">::Ok("); + strcat(body, name); + strcat(body, " { "); + + f = strct->strct.fields; + int first = 1; + while (f) + { + if (f->type == NODE_FIELD) + { + if (!first) strcat(body, ", "); + char init[128]; + // Check if this is a Vec<String> field - clone it to avoid double-free + int is_vec_field = 0; + for (int vi = 0; vi < vec_field_count; vi++) + { + if (strcmp(vec_fields[vi], f->field.name) == 0) + { + is_vec_field = 1; + break; + } + } + if (is_vec_field) + { + sprintf(init, "%s: _f_%s.clone()", f->field.name, f->field.name); + } + else + { + sprintf(init, "%s: _f_%s", f->field.name, f->field.name); + } + strcat(body, init); + first = 0; + } + f = f->next; + } + strcat(body, " }); "); + + code = xmalloc(8192 + 1024); + sprintf(code, + "impl %s { fn from_json(j: JsonValue*) -> Result<%s> { %s } }", + name, name, body); + } + else if (0 == strcmp(trait, "ToJson")) + { + // Generate to_json(self) -> JsonValue + // Only works for structs (not enums) + if (strct->type != NODE_STRUCT) + { + zwarn_at(strct->token, "@derive(ToJson) only works on structs"); + continue; + } + + char body[8192]; + strcpy(body, "let _obj = JsonValue::object();\n"); + + ASTNode *f = strct->strct.fields; + while (f) + { + if (f->type == NODE_FIELD) + { + char *fn = f->field.name; + char *ft = f->field.type; + char set_call[2048]; + + if (!fn || !ft) + { + f = f->next; + continue; + } + + if (strcmp(ft, "int") == 0) + { + sprintf(set_call, "_obj.set(\"%s\", JsonValue::number((double)self.%s));\n", fn, fn); + } + else if (strcmp(ft, "double") == 0) + { + sprintf(set_call, "_obj.set(\"%s\", JsonValue::number(self.%s));\n", fn, fn); + } + else if (strcmp(ft, "bool") == 0) + { + sprintf(set_call, "_obj.set(\"%s\", JsonValue::bool(self.%s));\n", fn, fn); + } + else if (strcmp(ft, "char*") == 0) + { + sprintf(set_call, "_obj.set(\"%s\", JsonValue::string(self.%s));\n", fn, fn); + } + else if (strcmp(ft, "String") == 0) + { + sprintf(set_call, "_obj.set(\"%s\", JsonValue::string(self.%s.c_str()));\n", fn, fn); + } + else if (ft && strstr(ft, "Vec") && strstr(ft, "String")) + { + sprintf(set_call, + "let _arr_%s = JsonValue::array();\n" + "for let _i_%s: usize = 0; _i_%s < self.%s.length(); _i_%s = _i_%s + 1 {\n" + " _arr_%s.push(JsonValue::string(self.%s.get(_i_%s).c_str()));\n" + "}\n" + "_obj.set(\"%s\", _arr_%s);\n", + fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn); + } + else + { + // Nested struct: call to_json recursively + sprintf(set_call, + "_obj.set(\"%s\", self.%s.to_json());\n", + fn, fn); + } + strcat(body, set_call); + } + f = f->next; + } + + strcat(body, "return _obj;"); + + code = xmalloc(8192 + 1024); + sprintf(code, + "impl %s { fn to_json(self) -> JsonValue { %s } }", + name, body); + } if (code) { diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c index 9782a26..21d36eb 100644 --- a/src/parser/parser_stmt.c +++ b/src/parser/parser_stmt.c @@ -1595,10 +1595,15 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, Type *t = expr_node ? expr_node->type_info : NULL; char *inferred_type = t ? type_to_string(t) : find_symbol_type(ctx, clean_expr); + int is_bool = 0; if (inferred_type) { - if (strcmp(inferred_type, "int") == 0 || strcmp(inferred_type, "i32") == 0 || - strcmp(inferred_type, "bool") == 0) + if (strcmp(inferred_type, "bool") == 0) + { + format_spec = "%s"; + is_bool = 1; + } + else if (strcmp(inferred_type, "int") == 0 || strcmp(inferred_type, "i32") == 0) { format_spec = "%d"; } @@ -1661,7 +1666,16 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, strcat(gen, buf); strcat(gen, format_spec); strcat(gen, "\", "); - strcat(gen, rw_expr); + if (is_bool) + { + strcat(gen, "_z_bool_str("); + strcat(gen, rw_expr); + strcat(gen, ")"); + } + else + { + strcat(gen, rw_expr); + } strcat(gen, "); "); } else @@ -1671,9 +1685,9 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, sprintf(buf, "fprintf(%s, _z_str(", target); strcat(gen, buf); strcat(gen, rw_expr); - strcat(gen, "), "); + strcat(gen, "), _z_arg("); strcat(gen, rw_expr); - strcat(gen, "); "); + strcat(gen, ")); "); } } |
