@@ -1183,6 +1183,20 @@ static void ser_expr(JsonBuf* jb, SerCtx* ctx, Interpreter* interp, Expr* expr)
11831183 jb_append_char (jb , '}' );
11841184 return ;
11851185 }
1186+ case EXPR_TYPED_IDENT : {
1187+ jb_append_char (jb , '{' );
1188+ bool first = true;
1189+ json_obj_field (jb , & first , "n" );
1190+ jb_append_json_string (jb , "TypedIdentifier" );
1191+ json_obj_field (jb , & first , "loc" );
1192+ ser_loc (jb , expr -> line , expr -> column );
1193+ json_obj_field (jb , & first , "decl_type" );
1194+ jb_append_json_string (jb , decl_type_name (expr -> as .typed_ident .decl_type ));
1195+ json_obj_field (jb , & first , "name" );
1196+ jb_append_json_string (jb , expr -> as .typed_ident .name ? expr -> as .typed_ident .name : "" );
1197+ jb_append_char (jb , '}' );
1198+ return ;
1199+ }
11861200 case EXPR_PTR : {
11871201 jb_append_char (jb , '{' );
11881202 bool first = true;
@@ -2039,6 +2053,13 @@ static Expr* deser_expr(JsonValue* obj, UnserCtx* ctx, Interpreter* interp, cons
20392053 const char * s = (nm && nm -> type == JSON_STR ) ? nm -> as .str : "" ;
20402054 return expr_ident (strdup (s ), line , col );
20412055 }
2056+ if (strcmp (name , "TypedIdentifier" ) == 0 ) {
2057+ JsonValue * typev = json_obj_get (obj , "decl_type" );
2058+ JsonValue * nm = json_obj_get (obj , "name" );
2059+ const char * t = (typev && typev -> type == JSON_STR ) ? typev -> as .str : "" ;
2060+ const char * s = (nm && nm -> type == JSON_STR ) ? nm -> as .str : "" ;
2061+ return expr_typed_ident (decl_type_from_name (t ), strdup (s ), line , col );
2062+ }
20422063 if (strcmp (name , "PointerExpression" ) == 0 ) {
20432064 JsonValue * nm = json_obj_get (obj , "target" );
20442065 const char * s = (nm && nm -> type == JSON_STR ) ? nm -> as .str : "" ;
@@ -6163,6 +6184,52 @@ static Value builtin_assign(Interpreter* interp, Value* args, int argc, Expr** a
61636184
61646185 Value rhs = args [1 ];
61656186
6187+ if (target -> type == EXPR_TYPED_IDENT ) {
6188+ const char * name = target -> as .typed_ident .name ;
6189+ DeclType expected = target -> as .typed_ident .decl_type ;
6190+ DeclType actual ;
6191+
6192+ switch (rhs .type ) {
6193+ case VAL_INT : actual = TYPE_INT ; break ;
6194+ case VAL_FLT : actual = TYPE_FLT ; break ;
6195+ case VAL_STR : actual = TYPE_STR ; break ;
6196+ case VAL_TNS : actual = TYPE_TNS ; break ;
6197+ case VAL_MAP : actual = TYPE_MAP ; break ;
6198+ case VAL_FUNC : actual = TYPE_FUNC ; break ;
6199+ case VAL_THR : actual = TYPE_THR ; break ;
6200+ default : actual = TYPE_UNKNOWN ; break ;
6201+ }
6202+
6203+ if (expected != actual ) {
6204+ char buf [128 ];
6205+ snprintf (buf , sizeof (buf ), "Type mismatch: expected %s but got %s" ,
6206+ decl_type_name (expected ), value_type_name (rhs ));
6207+ RUNTIME_ERROR (interp , buf , line , col );
6208+ }
6209+
6210+ EnvEntry * existing = env_get_entry (env , name );
6211+ if (existing && existing -> decl_type != expected ) {
6212+ char buf [128 ];
6213+ snprintf (buf , sizeof (buf ), "Type mismatch: expected %s but got %s" ,
6214+ decl_type_name (existing -> decl_type ), decl_type_name (expected ));
6215+ RUNTIME_ERROR (interp , buf , line , col );
6216+ }
6217+
6218+ Env * assign_env = env ;
6219+ if (!interp -> isolate_env_writes && !existing && env -> parent ) {
6220+ assign_env = env -> parent ;
6221+ }
6222+ if (!existing ) {
6223+ env_define (assign_env , name , expected );
6224+ }
6225+ if (!env_assign (assign_env , name , rhs , expected , true)) {
6226+ char buf [256 ];
6227+ snprintf (buf , sizeof (buf ), "ASSIGN: cannot assign to target '%s'" , name );
6228+ RUNTIME_ERROR (interp , buf , line , col );
6229+ }
6230+ return value_copy (rhs );
6231+ }
6232+
61666233 // Identifier target
61676234 if (target -> type == EXPR_IDENT ) {
61686235 const char * name = target -> as .ident ;
0 commit comments