summaryrefslogtreecommitdiff
path: root/src/parser
diff options
context:
space:
mode:
authorZuhaitz <zuhaitz.zechhub@gmail.com>2026-01-25 22:36:29 +0000
committerGitHub <noreply@github.com>2026-01-25 22:36:29 +0000
commitdc69e7a19e86373ee117d56b3747ff56d1631e96 (patch)
tree1b94f1f43b98a26a9c153585568505bed95e60ec /src/parser
parentfa858115f6b9625065b2488aeee028fe2c7d60b2 (diff)
parent74a4469dfba9a63a57caabc65c4faa65b2a59308 (diff)
Merge pull request #127 from sureshkrishnan-ai/JsonType
fixed buffer overflow in vector. Added serialize and deserialize in j…
Diffstat (limited to 'src/parser')
-rw-r--r--src/parser/parser_core.c215
-rw-r--r--src/parser/parser_stmt.c24
2 files changed, 234 insertions, 5 deletions
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, ")); ");
}
}