Skip to content

Commit caeb92d

Browse files
committed
Adds initial support for lists.
1 parent c0521e5 commit caeb92d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+1746
-10
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,7 @@ tramp
7979
[._]ss[a-gi-z]
8080
[._]sw[a-p]
8181
/src/lsp/vscode-extension/vult_lsp_js.js
82+
/test/integration/serialization/vultin.o
83+
/test/integration/serialization/test_serialization_main.o
84+
/test/integration/serialization/test_serialization
85+
/test/integration/serialization/test_serialization.o

runtime/vultin.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,11 @@ int32_t first_array_element(CustomBuffer &buffer, int32_t index) {
331331
return next_object(buffer, index);
332332
}
333333

334+
int32_t get_array_count(CustomBuffer &buffer, int32_t index) {
335+
index = index + 4; // skip header (tag + size bytes)
336+
return deserialize_int(buffer, index);
337+
}
338+
334339
int32_t get_field(CustomBuffer &buffer, int32_t object, int32_t field) {
335340
int32_t index = object + 4; // Skip the header
336341
int32_t n = 0;
@@ -414,9 +419,9 @@ std::string deserialize_string(CustomBuffer &buffer, int32_t index) {
414419
// Check the tag
415420
if (read_byte(buffer, index) == STRING_TAG) {
416421
int32_t total_size = block_size(buffer, index);
417-
// String size = total_size - header(4) - tag(1) = total_size - 5
418-
// But we need to account for null terminator, so actual string length = total_size - 5 - 1
419-
int32_t string_length = total_size - 5 - 1;
422+
// total_size = header(4) + string_content + null_terminator(1)
423+
// string_length = total_size - 4 - 1 = total_size - 5
424+
int32_t string_length = total_size - 5;
420425

421426
if (string_length < 0) {
422427
buffer.error = true;

runtime/vultin.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ int32_t goto_data(CustomBuffer &buffer);
305305

306306
int32_t first_array_element(CustomBuffer &buffer, int32_t index);
307307

308+
int32_t get_array_count(CustomBuffer &buffer, int32_t index);
309+
308310
template <std::size_t SIZE, typename DATA>
309311
void serialize_data(CustomBuffer &buffer,
310312
int32_t (*serialize_type_descr_function)(CustomBuffer &, int32_t, std::array<bool, SIZE> &),

src/core/env.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,15 @@ let builtin_functions =
257257
; "samplerate", C.unit_real
258258
; "wrap_array", C.wrap_array
259259
; "length", C.str_length
260+
; "list_size", C.list_size
261+
; "list_append", C.list_append
262+
; "list_insert", C.list_insert
263+
; "list_remove", C.list_remove
264+
; "list_clear", C.list_clear
265+
; "list_reserve", C.list_reserve
266+
; "list_capacity", C.list_capacity
267+
; "list_get", C.list_get
268+
; "list_set", C.list_set
260269
]
261270
|> Map.of_list
262271

src/core/inference.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,8 @@ and exp ?(context = normal_context) ?(in_constant_context = false) (env : env) (
13021302
let env, e = exp ~context env e in
13031303
let env, index = exp ~context env index in
13041304
let t = C.unbound Loc.default in
1305-
unifyRaise e.loc (C.array ~fixed:false t) e.t;
1305+
(* Allow indexing on arrays and lists *)
1306+
unifyRaise e.loc (C.indexable t) e.t;
13061307
unifyRaise index.loc (C.int ~loc:Loc.default) index.t;
13071308
(* if the type is a builtin (a value) do not unify the constness *)
13081309
let () =

src/core/initializer.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ let rec initStatement (cstyle : cstyle) lhs rhs (t : type_) =
131131
let transfer = { s = StmtBind (lhs, rhs_temp); loc } in
132132
{ s = StmtBlock [ decl_array; decl; init; loop; transfer ]; loc }
133133
| { t = TArray (None, _); _ } -> failwith "initStatement: Array without size"
134+
| { t = TList _; loc; _ } ->
135+
(* Lists are initialized as empty - use EEmptyValue with list type *)
136+
let rhs = { e = EEmptyValue; t; loc } in
137+
{ s = StmtBind (lhs, rhs); loc }
134138

135139

136140
let customInitializerCall (custom_initializers : string Util.Maps.Map.t) name ectx void_type loc =

src/core/interpreter.ml

Lines changed: 150 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@ type dvalue =
3434
| DBool of bool
3535
| DString of string
3636
| DArray of dvalue array
37+
| DList of dvalue list ref (* Dynamic list with mutable reference *)
3738
| DStruct of dvalue array
3839

3940
(* Expression with resolved indices *)
4041
type iexp =
4142
| IEUnit
4243
| IEEmptyValue
44+
| IEEmptyList of type_ (* Empty list of the given element type *)
4345
| IEBool of bool
4446
| IEInt of int
4547
| IEReal of float
@@ -105,6 +107,16 @@ type iexp =
105107
(* Array/string functions *)
106108
| IEBuiltinSize of iexp
107109
| IEBuiltinLength of iexp
110+
(* List functions *)
111+
| IEBuiltinListSize of iexp
112+
| IEBuiltinListCapacity of iexp
113+
| IEBuiltinListAppend of iexp * iexp
114+
| IEBuiltinListInsert of iexp * iexp * iexp
115+
| IEBuiltinListRemove of iexp * iexp
116+
| IEBuiltinListClear of iexp
117+
| IEBuiltinListReserve of iexp * iexp
118+
| IEBuiltinListGet of iexp * iexp
119+
| IEBuiltinListSet of iexp * iexp * iexp
108120
| IEIndex of iexp * iexp
109121
| IEArray of iexp list
110122
| IECall of int * iexp list (* Function index and args *)
@@ -302,6 +314,7 @@ let rec printDvalue (dv : dvalue) : string =
302314
| DBool b -> string_of_bool b
303315
| DString s -> "\"" ^ s ^ "\""
304316
| DArray arr -> "[" ^ String.concat "; " (Array.to_list (Array.map printDvalue arr)) ^ "]"
317+
| DList list_ref -> "list[" ^ String.concat "; " (CCList.map printDvalue !list_ref) ^ "]"
305318
| DStruct arr ->
306319
"{" ^ String.concat "; " (Array.to_list (Array.mapi (fun i v -> string_of_int i ^ ":" ^ printDvalue v) arr)) ^ "}"
307320

@@ -341,6 +354,7 @@ let rec printIexp (ie : iexp) : string =
341354
match ie with
342355
| IEUnit -> "()"
343356
| IEEmptyValue -> "empty"
357+
| IEEmptyList _ -> "empty_list"
344358
| IEBool b -> string_of_bool b
345359
| IEInt i -> string_of_int i
346360
| IEReal f -> string_of_float f
@@ -408,6 +422,16 @@ let rec printIexp (ie : iexp) : string =
408422
(* Array/string functions *)
409423
| IEBuiltinSize e -> "size(" ^ printIexp e ^ ")"
410424
| IEBuiltinLength e -> "length(" ^ printIexp e ^ ")"
425+
(* List functions *)
426+
| IEBuiltinListSize e -> "list_size(" ^ printIexp e ^ ")"
427+
| IEBuiltinListCapacity e -> "list_capacity(" ^ printIexp e ^ ")"
428+
| IEBuiltinListAppend (l, v) -> "list_append(" ^ printIexp l ^ ", " ^ printIexp v ^ ")"
429+
| IEBuiltinListInsert (l, i, v) -> "list_insert(" ^ printIexp l ^ ", " ^ printIexp i ^ ", " ^ printIexp v ^ ")"
430+
| IEBuiltinListRemove (l, i) -> "list_remove(" ^ printIexp l ^ ", " ^ printIexp i ^ ")"
431+
| IEBuiltinListClear e -> "list_clear(" ^ printIexp e ^ ")"
432+
| IEBuiltinListReserve (l, n) -> "list_reserve(" ^ printIexp l ^ ", " ^ printIexp n ^ ")"
433+
| IEBuiltinListGet (l, i) -> "list_get(" ^ printIexp l ^ ", " ^ printIexp i ^ ")"
434+
| IEBuiltinListSet (l, i, v) -> "list_set(" ^ printIexp l ^ ", " ^ printIexp i ^ ", " ^ printIexp v ^ ")"
411435
| IEIndex (arr, idx) -> printIexp arr ^ "[" ^ printIexp idx ^ "]"
412436
| IEArray exprs -> "[" ^ String.concat "; " (CCList.map printIexp exprs) ^ "]"
413437
| IECall (func_idx, args) ->
@@ -498,7 +522,11 @@ let isInt16Type (typ : type_) : bool =
498522
let rec transformExp (ctx : transform_ctx) (exp : exp) : iexp =
499523
match exp.e with
500524
| EUnit -> IEUnit
501-
| EEmptyValue -> IEEmptyValue
525+
| EEmptyValue -> (
526+
(* Check if the empty value is for a list type *)
527+
match exp.t.t with
528+
| TList _ -> IEEmptyList exp.t
529+
| _ -> IEEmptyValue)
502530
| EBool b -> IEBool b
503531
| EInt i -> IEInt i
504532
| EReal f -> IEReal f
@@ -579,6 +607,16 @@ let rec transformExp (ctx : transform_ctx) (exp : exp) : iexp =
579607
(* Array/string functions *)
580608
| "size", [ arg ] -> IEBuiltinSize arg
581609
| "length", [ arg ] -> IEBuiltinLength arg
610+
(* List functions *)
611+
| "list_size", [ arg ] -> IEBuiltinListSize arg
612+
| "list_capacity", [ arg ] -> IEBuiltinListCapacity arg
613+
| "list_append", [ l; v ] -> IEBuiltinListAppend (l, v)
614+
| "list_insert", [ l; i; v ] -> IEBuiltinListInsert (l, i, v)
615+
| "list_remove", [ l; i ] -> IEBuiltinListRemove (l, i)
616+
| "list_clear", [ arg ] -> IEBuiltinListClear arg
617+
| "list_reserve", [ l; n ] -> IEBuiltinListReserve (l, n)
618+
| "list_get", [ l; i ] -> IEBuiltinListGet (l, i)
619+
| "list_set", [ l; i; v ] -> IEBuiltinListSet (l, i, v)
582620
(* External runtime functions *)
583621
| "push_block_header", args -> IECallExt ("push_block_header", args)
584622
| "push_int", args -> IECallExt ("push_int", args)
@@ -594,6 +632,7 @@ let rec transformExp (ctx : transform_ctx) (exp : exp) : iexp =
594632
| "deserialize_string", args -> IECallExt ("deserialize_string", args)
595633
| "search_type_description", args -> IECallExt ("search_type_description", args)
596634
| "first_array_element", args -> IECallExt ("first_array_element", args)
635+
| "get_array_count", args -> IECallExt ("get_array_count", args)
597636
| "next_object", args -> IECallExt ("next_object", args)
598637
(* Fall back to regular call for non-builtins *)
599638
| _ -> (
@@ -706,6 +745,7 @@ let rec evalConstantExpression (constants : dvalue array) (exp : iexp) : dvalue
706745
match exp with
707746
| IEUnit -> DVoid
708747
| IEEmptyValue -> DVoid
748+
| IEEmptyList _ -> DList (ref [])
709749
| IEBool b -> DBool b
710750
| IEInt i -> DInt i
711751
| IEReal f -> DReal f
@@ -844,8 +884,11 @@ let rec defaultValue (typ : type_) : dvalue =
844884
| TTuple types -> DArray (Array.of_list (CCList.map defaultValue types))
845885
| TEmptyType -> DVoid
846886
| TArray (None, _) -> error "Cannot create default value for unsized array"
887+
| TList _ -> DList (ref [])
847888

848889

890+
(* Empty mutable list *)
891+
849892
(* Sets up a function call on the runtime stack and returns the frame start offset *)
850893
let setupFunctionCall (stack : runtime_stack) (ifunc : ifunc_def) (args : dvalue list) : int =
851894
let frame_start = stack.sp in
@@ -877,7 +920,17 @@ let getArrayElement (ctx : call_context) (arr : dvalue) (idx : dvalue) : dvalue
877920
^ string_of_int (Array.length elems)
878921
^ " index = "
879922
^ string_of_int i)
880-
| _ -> error_with_context ctx "getArrayElement: Invalid array access. This is not an array"
923+
| DList list_ref, DInt i -> (
924+
match CCList.nth_opt !list_ref i with
925+
| Some v -> v
926+
| None ->
927+
error_with_context
928+
ctx
929+
("getArrayElement: List index out of bounds. size = "
930+
^ string_of_int (CCList.length !list_ref)
931+
^ " index = "
932+
^ string_of_int i))
933+
| _ -> error_with_context ctx "getArrayElement: Invalid array access. This is not an array or list"
881934

882935

883936
(* Retrieves a member from a struct using a member index *)
@@ -1084,7 +1137,17 @@ and assignIlvalue : call_context -> iprog -> runtime_stack -> int -> ilexp -> dv
10841137
let array_val = evalIlexpAsRvalue ctx prog stack frame_start e in
10851138
match array_val, idx_val with
10861139
| DArray arr, DInt i when i >= 0 && i < Array.length arr -> arr.(i) <- val_
1087-
| _ -> error_with_context ctx "Invalid array assignment")
1140+
| DList list_ref, DInt i ->
1141+
let old_list = !list_ref in
1142+
let len = CCList.length old_list in
1143+
if i >= 0 && i < len then
1144+
let before, after = CCList.take_drop i old_list in
1145+
match after with
1146+
| _ :: rest -> list_ref := before @ [ val_ ] @ rest
1147+
| [] -> error_with_context ctx "List index out of bounds for assignment"
1148+
else
1149+
error_with_context ctx ("List index out of bounds: index = " ^ string_of_int i ^ " size = " ^ string_of_int len)
1150+
| _ -> error_with_context ctx "Invalid array or list assignment")
10881151
| ILTuple lexps -> (
10891152
match val_ with
10901153
| DArray vals when Array.length vals = CCList.length lexps ->
@@ -1123,6 +1186,7 @@ and evalIexp (ctx : call_context) (prog : iprog) (stack : runtime_stack) (frame_
11231186
match exp with
11241187
| IEUnit -> DVoid
11251188
| IEEmptyValue -> DVoid
1189+
| IEEmptyList _ -> DList (ref [])
11261190
| IEBool b -> DBool b
11271191
| IEInt i -> DInt i
11281192
| IEReal f -> DReal f
@@ -1390,6 +1454,89 @@ and evalIexp (ctx : call_context) (prog : iprog) (stack : runtime_stack) (frame_
13901454
match evalIexp ctx prog stack frame_start e with
13911455
| DString s -> DInt (String.length s)
13921456
| _ -> error_with_context ctx "Type mismatch in length - expected string")
1457+
(* List functions *)
1458+
| IEBuiltinListSize e -> (
1459+
match evalIexp ctx prog stack frame_start e with
1460+
| DArray arr -> DInt (Array.length arr)
1461+
| DList list_ref -> DInt (CCList.length !list_ref)
1462+
| _ -> error_with_context ctx "Type mismatch in list_size - expected list")
1463+
| IEBuiltinListCapacity e -> (
1464+
(* Lists in the interpreter don't have a separate capacity, return size *)
1465+
match evalIexp ctx prog stack frame_start e with
1466+
| DArray arr -> DInt (Array.length arr)
1467+
| DList list_ref -> DInt (CCList.length !list_ref)
1468+
| _ -> error_with_context ctx "Type mismatch in list_capacity - expected list")
1469+
| IEBuiltinListAppend (l, v) -> (
1470+
let list_val = evalIexp ctx prog stack frame_start l in
1471+
let new_val = evalIexp ctx prog stack frame_start v in
1472+
match list_val with
1473+
| DList list_ref ->
1474+
list_ref := !list_ref @ [ new_val ];
1475+
DVoid
1476+
| _ -> error_with_context ctx "list_append requires list type")
1477+
| IEBuiltinListInsert (l, i, v) -> (
1478+
let list_val = evalIexp ctx prog stack frame_start l in
1479+
let idx = evalIexp ctx prog stack frame_start i in
1480+
let new_val = evalIexp ctx prog stack frame_start v in
1481+
match list_val, idx with
1482+
| DList list_ref, DInt index ->
1483+
let before, after = CCList.take_drop index !list_ref in
1484+
list_ref := before @ [ new_val ] @ after;
1485+
DVoid
1486+
| _ -> error_with_context ctx "list_insert: invalid arguments")
1487+
| IEBuiltinListRemove (l, i) -> (
1488+
let list_val = evalIexp ctx prog stack frame_start l in
1489+
let idx = evalIexp ctx prog stack frame_start i in
1490+
match list_val, idx with
1491+
| DList list_ref, DInt index ->
1492+
let before, after = CCList.take_drop index !list_ref in
1493+
list_ref := before @ CCList.drop 1 after;
1494+
DVoid
1495+
| _ -> error_with_context ctx "list_remove: invalid arguments")
1496+
| IEBuiltinListClear l -> (
1497+
match evalIexp ctx prog stack frame_start l with
1498+
| DList list_ref ->
1499+
list_ref := [];
1500+
DVoid
1501+
| _ -> error_with_context ctx "list_clear requires list type")
1502+
| IEBuiltinListReserve _ ->
1503+
(* Reserve is a hint, we can safely ignore it and return unit *)
1504+
DVoid
1505+
| IEBuiltinListGet (l, i) -> (
1506+
let list_val = evalIexp ctx prog stack frame_start l in
1507+
let idx = evalIexp ctx prog stack frame_start i in
1508+
match list_val, idx with
1509+
| DList list_ref, DInt index -> (
1510+
match CCList.nth_opt !list_ref index with
1511+
| Some v -> v
1512+
| None ->
1513+
error_with_context
1514+
ctx
1515+
("list_get: index out of bounds. size = "
1516+
^ string_of_int (CCList.length !list_ref)
1517+
^ " index = "
1518+
^ string_of_int index))
1519+
| _ -> error_with_context ctx "list_get: invalid arguments")
1520+
| IEBuiltinListSet (l, i, v) -> (
1521+
let list_val = evalIexp ctx prog stack frame_start l in
1522+
let idx = evalIexp ctx prog stack frame_start i in
1523+
let new_val = evalIexp ctx prog stack frame_start v in
1524+
match list_val, idx with
1525+
| DList list_ref, DInt index ->
1526+
let old_list = !list_ref in
1527+
let len = CCList.length old_list in
1528+
if index >= 0 && index < len then
1529+
let before, after = CCList.take_drop index old_list in
1530+
match after with
1531+
| _ :: rest ->
1532+
list_ref := before @ [ new_val ] @ rest;
1533+
DVoid
1534+
| [] -> error_with_context ctx "list_set: index out of bounds"
1535+
else
1536+
error_with_context
1537+
ctx
1538+
("list_set: index out of bounds. size = " ^ string_of_int len ^ " index = " ^ string_of_int index)
1539+
| _ -> error_with_context ctx "list_set: invalid arguments")
13931540
| IEIndex (e, index) ->
13941541
let arr_val = evalIexp ctx prog stack frame_start e in
13951542
let idx_val = evalIexp ctx prog stack frame_start index in

src/core/mapper.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,12 @@ let rec type_ (mapper : ('env, 'data) mapper) (env : 'env) (state : 'data state)
277277
apply mapper.type_ env state t
278278
else
279279
apply mapper.type_ env state { t = TArray (dim, t1'); const; loc }
280+
| { t = TList t1; const; _ } ->
281+
let state, t1' = type_ mapper sub_env state t1 in
282+
if t1' == t1 then
283+
apply mapper.type_ env state t
284+
else
285+
apply mapper.type_ env state { t = TList t1'; const; loc }
280286
| { t = TTuple elems; const; _ } ->
281287
let state, elems' = (mapper_list type_) mapper sub_env state elems in
282288
if elems' == elems then

src/core/prog.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ type type_d_ =
3737
| TBool
3838
| TFix16
3939
| TArray of int option * type_
40+
| TList of type_ (* Dynamic list type, like std::vector *)
4041
| TStruct of struct_descr
4142
| TTuple of type_ list
4243
| TEmptyType
@@ -218,6 +219,9 @@ module Print = struct
218219
| TArray (None, t) ->
219220
let t = print_type_ t in
220221
prefix {%pla|<#t#>[:]|}
222+
| TList t ->
223+
let t = print_type_ t in
224+
prefix {%pla|list(<#t#>)|}
221225
| TStruct { path; _ } -> prefix {%pla|struct <#path#s>|}
222226
| TTuple elems ->
223227
let elems = Pla.map_sep Pla.commaspace print_type_ elems in
@@ -469,6 +473,8 @@ module C = struct
469473

470474
let array_t ?dim t = { t = TArray (dim, t); loc = Loc.default; const = false }
471475

476+
let list_t t = { t = TList t; loc = Loc.default; const = false }
477+
472478
let ereal ?(loc = Loc.default) i = { e = EReal i; t = real_t; loc }
473479

474480
let efix16 ?(loc = Loc.default) i = { e = EFixed i; t = fix16_t; loc }

0 commit comments

Comments
 (0)