• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daisytuner / sdfglib / 17907460602

22 Sep 2025 07:08AM UTC coverage: 60.192% (-0.5%) from 60.653%
17907460602

Pull #233

github

web-flow
Merge 07c7b1d2f into c3f4f7063
Pull Request #233: adds constant returns with type and extends API

60 of 184 new or added lines in 10 files covered. (32.61%)

19 existing lines in 5 files now uncovered.

9514 of 15806 relevant lines covered (60.19%)

105.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.0
/src/serializer/json_serializer.cpp
1
#include "sdfg/serializer/json_serializer.h"
2

3
#include <cassert>
4
#include <memory>
5
#include <unordered_map>
6
#include <utility>
7
#include <vector>
8

9
#include "sdfg/data_flow/library_nodes/barrier_local_node.h"
10
#include "sdfg/data_flow/library_nodes/call_node.h"
11
#include "sdfg/data_flow/library_nodes/math/math.h"
12
#include "sdfg/data_flow/library_nodes/metadata_node.h"
13
#include "sdfg/data_flow/library_nodes/stdlib/stdlib.h"
14

15
#include "sdfg/builder/structured_sdfg_builder.h"
16
#include "sdfg/data_flow/library_node.h"
17
#include "sdfg/element.h"
18
#include "sdfg/structured_control_flow/block.h"
19
#include "sdfg/structured_control_flow/for.h"
20
#include "sdfg/structured_control_flow/if_else.h"
21
#include "sdfg/structured_control_flow/map.h"
22
#include "sdfg/structured_control_flow/return.h"
23
#include "sdfg/structured_control_flow/sequence.h"
24
#include "sdfg/structured_control_flow/while.h"
25
#include "sdfg/structured_sdfg.h"
26
#include "sdfg/symbolic/symbolic.h"
27
#include "sdfg/types/function.h"
28
#include "sdfg/types/scalar.h"
29
#include "sdfg/types/type.h"
30
#include "symengine/expression.h"
31
#include "symengine/logic.h"
32
#include "symengine/symengine_rcp.h"
33

34
namespace sdfg {
35
namespace serializer {
36

37
FunctionType function_type_from_string(const std::string& str) {
5✔
38
    if (str == FunctionType_CPU.value()) {
5✔
39
        return FunctionType_CPU;
5✔
40
    } else if (str == FunctionType_NV_GLOBAL.value()) {
×
41
        return FunctionType_NV_GLOBAL;
×
42
    }
43

44
    return FunctionType(str);
×
45
}
5✔
46

47
types::StorageType storage_type_from_string(const std::string& str) {
46✔
48
    if (str == types::StorageType_CPU_Heap.value()) {
46✔
49
        return types::StorageType_CPU_Heap;
×
50
    } else if (str == types::StorageType_CPU_Stack.value()) {
46✔
51
        return types::StorageType_CPU_Stack;
46✔
52
    } else if (str == types::StorageType_NV_Global.value()) {
×
53
        return types::StorageType_NV_Global;
×
54
    } else if (str == types::StorageType_NV_Shared.value()) {
×
55
        return types::StorageType_NV_Shared;
×
56
    } else if (str == types::StorageType_NV_Constant.value()) {
×
57
        return types::StorageType_NV_Constant;
×
58
    } else if (str == types::StorageType_NV_Generic.value()) {
×
59
        return types::StorageType_NV_Generic;
×
60
    }
61

62
    return types::StorageType(str);
×
63
}
46✔
64

65
/*
66
 * * JSONSerializer class
67
 * * Serialization logic
68
 */
69

70
nlohmann::json JSONSerializer::serialize(const sdfg::StructuredSDFG& sdfg) {
5✔
71
    nlohmann::json j;
5✔
72

73
    j["name"] = sdfg.name();
5✔
74
    j["element_counter"] = sdfg.element_counter();
5✔
75
    j["type"] = std::string(sdfg.type().value());
5✔
76

77
    nlohmann::json return_type_json;
5✔
78
    type_to_json(return_type_json, sdfg.return_type());
5✔
79
    j["return_type"] = return_type_json;
5✔
80

81
    j["structures"] = nlohmann::json::array();
5✔
82
    for (const auto& structure_name : sdfg.structures()) {
6✔
83
        const auto& structure = sdfg.structure(structure_name);
1✔
84
        nlohmann::json structure_json;
1✔
85
        structure_definition_to_json(structure_json, structure);
1✔
86
        j["structures"].push_back(structure_json);
1✔
87
    }
1✔
88

89
    j["containers"] = nlohmann::json::object();
5✔
90
    for (const auto& container : sdfg.containers()) {
17✔
91
        nlohmann::json desc;
12✔
92
        type_to_json(desc, sdfg.type(container));
12✔
93
        j["containers"][container] = desc;
12✔
94
    }
12✔
95

96
    j["arguments"] = nlohmann::json::array();
5✔
97
    for (const auto& argument : sdfg.arguments()) {
8✔
98
        j["arguments"].push_back(argument);
3✔
99
    }
100

101
    j["externals"] = nlohmann::json::array();
5✔
102
    for (const auto& external : sdfg.externals()) {
9✔
103
        nlohmann::json external_json;
4✔
104
        external_json["name"] = external;
4✔
105
        external_json["linkage_type"] = sdfg.linkage_type(external);
4✔
106
        j["externals"].push_back(external_json);
4✔
107
    }
4✔
108

109
    j["metadata"] = nlohmann::json::object();
5✔
110
    for (const auto& entry : sdfg.metadata()) {
6✔
111
        j["metadata"][entry.first] = entry.second;
1✔
112
    }
113

114
    // Walk the SDFG
115
    nlohmann::json root_json;
5✔
116
    sequence_to_json(root_json, sdfg.root());
5✔
117
    j["root"] = root_json;
5✔
118

119
    return j;
5✔
120
}
5✔
121

122
void JSONSerializer::dataflow_to_json(nlohmann::json& j, const data_flow::DataFlowGraph& dataflow) {
21✔
123
    j["type"] = "dataflow";
21✔
124
    j["nodes"] = nlohmann::json::array();
21✔
125
    j["edges"] = nlohmann::json::array();
21✔
126

127
    for (auto& node : dataflow.nodes()) {
41✔
128
        nlohmann::json node_json;
20✔
129
        node_json["element_id"] = node.element_id();
20✔
130

131
        node_json["debug_info"] = nlohmann::json::object();
20✔
132
        debug_info_to_json(node_json["debug_info"], node.debug_info());
20✔
133

134
        if (auto tasklet = dynamic_cast<const data_flow::Tasklet*>(&node)) {
20✔
135
            node_json["type"] = "tasklet";
5✔
136
            node_json["code"] = tasklet->code();
5✔
137
            node_json["inputs"] = nlohmann::json::array();
5✔
138
            for (auto& input : tasklet->inputs()) {
15✔
139
                node_json["inputs"].push_back(input);
10✔
140
            }
141
            node_json["output"] = tasklet->output();
5✔
142
        } else if (auto lib_node = dynamic_cast<const data_flow::LibraryNode*>(&node)) {
20✔
143
            node_json["type"] = "library_node";
×
144
            node_json["implementation_type"] = std::string(lib_node->implementation_type().value());
×
145
            auto serializer_fn =
146
                LibraryNodeSerializerRegistry::instance().get_library_node_serializer(lib_node->code().value());
×
147
            if (serializer_fn == nullptr) {
×
148
                throw std::runtime_error("Unknown library node code: " + std::string(lib_node->code().value()));
×
149
            }
150
            auto serializer = serializer_fn();
×
151
            auto lib_node_json = serializer->serialize(*lib_node);
×
152
            node_json.merge_patch(lib_node_json);
×
153
        } else if (auto code_node = dynamic_cast<const data_flow::ConstantNode*>(&node)) {
15✔
154
            node_json["type"] = "constant_node";
×
155
            node_json["data"] = code_node->data();
×
156

157
            nlohmann::json type_json;
×
158
            type_to_json(type_json, code_node->type());
×
159
            node_json["data_type"] = type_json;
×
160
        } else if (auto code_node = dynamic_cast<const data_flow::AccessNode*>(&node)) {
15✔
161
            node_json["type"] = "access_node";
15✔
162
            node_json["data"] = code_node->data();
15✔
163
        } else {
15✔
164
            throw std::runtime_error("Unknown node type");
×
165
        }
166

167
        j["nodes"].push_back(node_json);
20✔
168
    }
20✔
169

170
    for (auto& edge : dataflow.edges()) {
36✔
171
        nlohmann::json edge_json;
15✔
172
        edge_json["element_id"] = edge.element_id();
15✔
173

174
        edge_json["debug_info"] = nlohmann::json::object();
15✔
175
        debug_info_to_json(edge_json["debug_info"], edge.debug_info());
15✔
176

177
        edge_json["src"] = edge.src().element_id();
15✔
178
        edge_json["dst"] = edge.dst().element_id();
15✔
179

180
        edge_json["src_conn"] = edge.src_conn();
15✔
181
        edge_json["dst_conn"] = edge.dst_conn();
15✔
182

183
        edge_json["subset"] = nlohmann::json::array();
15✔
184
        for (auto& subset : edge.subset()) {
21✔
185
            edge_json["subset"].push_back(expression(subset));
6✔
186
        }
187

188
        nlohmann::json base_type_json;
15✔
189
        type_to_json(base_type_json, edge.base_type());
15✔
190
        edge_json["base_type"] = base_type_json;
15✔
191

192
        j["edges"].push_back(edge_json);
15✔
193
    }
15✔
194
}
21✔
195

196
void JSONSerializer::block_to_json(nlohmann::json& j, const structured_control_flow::Block& block) {
19✔
197
    j["type"] = "block";
19✔
198
    j["element_id"] = block.element_id();
19✔
199

200
    j["debug_info"] = nlohmann::json::object();
19✔
201
    debug_info_to_json(j["debug_info"], block.debug_info());
19✔
202

203
    nlohmann::json dataflow_json;
19✔
204
    dataflow_to_json(dataflow_json, block.dataflow());
19✔
205
    j["dataflow"] = dataflow_json;
19✔
206
}
19✔
207

208
void JSONSerializer::for_to_json(nlohmann::json& j, const structured_control_flow::For& for_node) {
2✔
209
    j["type"] = "for";
2✔
210
    j["element_id"] = for_node.element_id();
2✔
211

212
    j["debug_info"] = nlohmann::json::object();
2✔
213
    debug_info_to_json(j["debug_info"], for_node.debug_info());
2✔
214

215
    j["indvar"] = expression(for_node.indvar());
2✔
216
    j["init"] = expression(for_node.init());
2✔
217
    j["condition"] = expression(for_node.condition());
2✔
218
    j["update"] = expression(for_node.update());
2✔
219

220
    nlohmann::json body_json;
2✔
221
    sequence_to_json(body_json, for_node.root());
2✔
222
    j["root"] = body_json;
2✔
223
}
2✔
224

225
void JSONSerializer::if_else_to_json(nlohmann::json& j, const structured_control_flow::IfElse& if_else_node) {
2✔
226
    j["type"] = "if_else";
2✔
227
    j["element_id"] = if_else_node.element_id();
2✔
228

229
    j["debug_info"] = nlohmann::json::object();
2✔
230
    debug_info_to_json(j["debug_info"], if_else_node.debug_info());
2✔
231

232
    j["branches"] = nlohmann::json::array();
2✔
233
    for (size_t i = 0; i < if_else_node.size(); i++) {
6✔
234
        nlohmann::json branch_json;
4✔
235
        branch_json["condition"] = expression(if_else_node.at(i).second);
4✔
236
        nlohmann::json body_json;
4✔
237
        sequence_to_json(body_json, if_else_node.at(i).first);
4✔
238
        branch_json["root"] = body_json;
4✔
239
        j["branches"].push_back(branch_json);
4✔
240
    }
4✔
241
}
2✔
242

243
void JSONSerializer::while_node_to_json(nlohmann::json& j, const structured_control_flow::While& while_node) {
5✔
244
    j["type"] = "while";
5✔
245
    j["element_id"] = while_node.element_id();
5✔
246

247
    j["debug_info"] = nlohmann::json::object();
5✔
248
    debug_info_to_json(j["debug_info"], while_node.debug_info());
5✔
249

250
    nlohmann::json body_json;
5✔
251
    sequence_to_json(body_json, while_node.root());
5✔
252
    j["root"] = body_json;
5✔
253
}
5✔
254

255
void JSONSerializer::break_node_to_json(nlohmann::json& j, const structured_control_flow::Break& break_node) {
2✔
256
    j["type"] = "break";
2✔
257
    j["element_id"] = break_node.element_id();
2✔
258

259
    j["debug_info"] = nlohmann::json::object();
2✔
260
    debug_info_to_json(j["debug_info"], break_node.debug_info());
2✔
261
}
2✔
262

263
void JSONSerializer::continue_node_to_json(nlohmann::json& j, const structured_control_flow::Continue& continue_node) {
2✔
264
    j["type"] = "continue";
2✔
265
    j["element_id"] = continue_node.element_id();
2✔
266

267
    j["debug_info"] = nlohmann::json::object();
2✔
268
    debug_info_to_json(j["debug_info"], continue_node.debug_info());
2✔
269
}
2✔
270

271
void JSONSerializer::map_to_json(nlohmann::json& j, const structured_control_flow::Map& map_node) {
2✔
272
    j["type"] = "map";
2✔
273
    j["element_id"] = map_node.element_id();
2✔
274

275
    j["debug_info"] = nlohmann::json::object();
2✔
276
    debug_info_to_json(j["debug_info"], map_node.debug_info());
2✔
277

278
    j["indvar"] = expression(map_node.indvar());
2✔
279
    j["init"] = expression(map_node.init());
2✔
280
    j["condition"] = expression(map_node.condition());
2✔
281
    j["update"] = expression(map_node.update());
2✔
282

283
    j["schedule_type"] = nlohmann::json::object();
2✔
284
    schedule_type_to_json(j["schedule_type"], map_node.schedule_type());
2✔
285

286
    nlohmann::json body_json;
2✔
287
    sequence_to_json(body_json, map_node.root());
2✔
288
    j["root"] = body_json;
2✔
289
}
2✔
290

291
void JSONSerializer::return_node_to_json(nlohmann::json& j, const structured_control_flow::Return& return_node) {
2✔
292
    j["type"] = "return";
2✔
293
    j["element_id"] = return_node.element_id();
2✔
294
    j["data"] = return_node.data();
2✔
295
    j["unreachable"] = return_node.unreachable();
2✔
296

297
    if (return_node.is_constant()) {
2✔
NEW
298
        nlohmann::json type_json;
×
NEW
299
        type_to_json(type_json, return_node.type());
×
NEW
300
        j["data_type"] = type_json;
×
NEW
301
    }
×
302

303
    j["debug_info"] = nlohmann::json::object();
2✔
304
    debug_info_to_json(j["debug_info"], return_node.debug_info());
2✔
305
}
2✔
306

307
void JSONSerializer::sequence_to_json(nlohmann::json& j, const structured_control_flow::Sequence& sequence) {
21✔
308
    j["type"] = "sequence";
21✔
309
    j["element_id"] = sequence.element_id();
21✔
310

311
    j["debug_info"] = nlohmann::json::object();
21✔
312
    debug_info_to_json(j["debug_info"], sequence.debug_info());
21✔
313

314
    j["children"] = nlohmann::json::array();
21✔
315
    j["transitions"] = nlohmann::json::array();
21✔
316

317
    for (size_t i = 0; i < sequence.size(); i++) {
42✔
318
        nlohmann::json child_json;
21✔
319
        auto& child = sequence.at(i).first;
21✔
320
        auto& transition = sequence.at(i).second;
21✔
321

322
        if (auto block = dynamic_cast<const structured_control_flow::Block*>(&child)) {
21✔
323
            block_to_json(child_json, *block);
17✔
324
        } else if (auto for_node = dynamic_cast<const structured_control_flow::For*>(&child)) {
21✔
325
            for_to_json(child_json, *for_node);
×
326
        } else if (auto sequence_node = dynamic_cast<const structured_control_flow::Sequence*>(&child)) {
4✔
327
            sequence_to_json(child_json, *sequence_node);
×
328
        } else if (auto condition_node = dynamic_cast<const structured_control_flow::IfElse*>(&child)) {
4✔
329
            if_else_to_json(child_json, *condition_node);
×
330
        } else if (auto while_node = dynamic_cast<const structured_control_flow::While*>(&child)) {
4✔
331
            while_node_to_json(child_json, *while_node);
×
332
        } else if (auto return_node = dynamic_cast<const structured_control_flow::Return*>(&child)) {
4✔
333
            return_node_to_json(child_json, *return_node);
×
334
        } else if (auto break_node = dynamic_cast<const structured_control_flow::Break*>(&child)) {
4✔
335
            break_node_to_json(child_json, *break_node);
2✔
336
        } else if (auto continue_node = dynamic_cast<const structured_control_flow::Continue*>(&child)) {
4✔
337
            continue_node_to_json(child_json, *continue_node);
2✔
338
        } else if (auto map_node = dynamic_cast<const structured_control_flow::Map*>(&child)) {
2✔
339
            map_to_json(child_json, *map_node);
×
340
        } else {
×
341
            throw std::runtime_error("Unknown child type");
×
342
        }
343

344
        j["children"].push_back(child_json);
21✔
345

346
        // Add transition information
347
        nlohmann::json transition_json;
21✔
348
        transition_json["type"] = "transition";
21✔
349
        transition_json["element_id"] = transition.element_id();
21✔
350

351
        transition_json["debug_info"] = nlohmann::json::object();
21✔
352
        debug_info_to_json(transition_json["debug_info"], transition.debug_info());
21✔
353

354
        transition_json["assignments"] = nlohmann::json::array();
21✔
355
        for (const auto& assignment : transition.assignments()) {
24✔
356
            nlohmann::json assignment_json;
3✔
357
            assignment_json["symbol"] = expression(assignment.first);
3✔
358
            assignment_json["expression"] = expression(assignment.second);
3✔
359
            transition_json["assignments"].push_back(assignment_json);
3✔
360
        }
3✔
361

362
        j["transitions"].push_back(transition_json);
21✔
363
    }
21✔
364
}
21✔
365

366
void JSONSerializer::type_to_json(nlohmann::json& j, const types::IType& type) {
60✔
367
    if (auto scalar_type = dynamic_cast<const types::Scalar*>(&type)) {
60✔
368
        j["type"] = "scalar";
43✔
369
        j["primitive_type"] = scalar_type->primitive_type();
43✔
370
        j["storage_type"] = std::string(scalar_type->storage_type().value());
43✔
371
        j["initializer"] = scalar_type->initializer();
43✔
372
        j["alignment"] = scalar_type->alignment();
43✔
373
    } else if (auto array_type = dynamic_cast<const types::Array*>(&type)) {
60✔
374
        j["type"] = "array";
3✔
375
        nlohmann::json element_type_json;
3✔
376
        type_to_json(element_type_json, array_type->element_type());
3✔
377
        j["element_type"] = element_type_json;
3✔
378
        j["num_elements"] = expression(array_type->num_elements());
3✔
379
        j["storage_type"] = std::string(array_type->storage_type().value());
3✔
380
        j["initializer"] = array_type->initializer();
3✔
381
        j["alignment"] = array_type->alignment();
3✔
382
    } else if (auto pointer_type = dynamic_cast<const types::Pointer*>(&type)) {
17✔
383
        j["type"] = "pointer";
9✔
384
        if (pointer_type->has_pointee_type()) {
9✔
385
            nlohmann::json pointee_type_json;
8✔
386
            type_to_json(pointee_type_json, pointer_type->pointee_type());
8✔
387
            j["pointee_type"] = pointee_type_json;
8✔
388
        }
8✔
389
        j["storage_type"] = std::string(pointer_type->storage_type().value());
9✔
390
        j["initializer"] = pointer_type->initializer();
9✔
391
        j["alignment"] = pointer_type->alignment();
9✔
392
    } else if (auto structure_type = dynamic_cast<const types::Structure*>(&type)) {
14✔
393
        j["type"] = "structure";
3✔
394
        j["name"] = structure_type->name();
3✔
395
        j["storage_type"] = std::string(structure_type->storage_type().value());
3✔
396
        j["initializer"] = structure_type->initializer();
3✔
397
        j["alignment"] = structure_type->alignment();
3✔
398
    } else if (auto function_type = dynamic_cast<const types::Function*>(&type)) {
5✔
399
        j["type"] = "function";
2✔
400
        nlohmann::json return_type_json;
2✔
401
        type_to_json(return_type_json, function_type->return_type());
2✔
402
        j["return_type"] = return_type_json;
2✔
403
        j["params"] = nlohmann::json::array();
2✔
404
        for (size_t i = 0; i < function_type->num_params(); i++) {
5✔
405
            nlohmann::json param_json;
3✔
406
            type_to_json(param_json, function_type->param_type(symbolic::integer(i)));
3✔
407
            j["params"].push_back(param_json);
3✔
408
        }
3✔
409
        j["is_var_arg"] = function_type->is_var_arg();
2✔
410
        j["storage_type"] = std::string(function_type->storage_type().value());
2✔
411
        j["initializer"] = function_type->initializer();
2✔
412
        j["alignment"] = function_type->alignment();
2✔
413
    } else {
2✔
414
        throw std::runtime_error("Unknown type");
×
415
    }
416
}
60✔
417

418
void JSONSerializer::structure_definition_to_json(nlohmann::json& j, const types::StructureDefinition& definition) {
2✔
419
    j["name"] = definition.name();
2✔
420
    j["members"] = nlohmann::json::array();
2✔
421
    for (size_t i = 0; i < definition.num_members(); i++) {
4✔
422
        nlohmann::json member_json;
2✔
423
        type_to_json(member_json, definition.member_type(symbolic::integer(i)));
2✔
424
        j["members"].push_back(member_json);
2✔
425
    }
2✔
426
    j["is_packed"] = definition.is_packed();
2✔
427
}
2✔
428

429
void JSONSerializer::debug_info_to_json(nlohmann::json& j, const DebugInfo& debug_info) {
113✔
430
    j["has"] = debug_info.has();
113✔
431
    j["filename"] = debug_info.filename();
113✔
432
    j["function"] = debug_info.function();
113✔
433
    j["start_line"] = debug_info.start_line();
113✔
434
    j["start_column"] = debug_info.start_column();
113✔
435
    j["end_line"] = debug_info.end_line();
113✔
436
    j["end_column"] = debug_info.end_column();
113✔
437
}
113✔
438

439
void JSONSerializer::schedule_type_to_json(nlohmann::json& j, const ScheduleType& schedule_type) {
3✔
440
    j["value"] = schedule_type.value();
3✔
441
    j["properties"] = nlohmann::json::object();
3✔
442
    for (const auto& prop : schedule_type.properties()) {
4✔
443
        j["properties"][prop.first] = prop.second;
1✔
444
    }
445
}
3✔
446

447
/*
448
 * * Deserialization logic
449
 */
450

451
std::unique_ptr<StructuredSDFG> JSONSerializer::deserialize(nlohmann::json& j) {
5✔
452
    assert(j.contains("name"));
5✔
453
    assert(j["name"].is_string());
5✔
454
    assert(j.contains("type"));
5✔
455
    assert(j["type"].is_string());
5✔
456
    assert(j.contains("element_counter"));
5✔
457
    assert(j["element_counter"].is_number_integer());
5✔
458

459
    std::unique_ptr<types::IType> return_type;
5✔
460
    if (j.contains("return_type")) {
5✔
461
        return_type = json_to_type(j["return_type"]);
5✔
462
    } else {
5✔
463
        return_type = std::make_unique<types::Scalar>(types::PrimitiveType::Void);
×
464
    }
465

466
    FunctionType function_type = function_type_from_string(j["type"].get<std::string>());
5✔
467
    builder::StructuredSDFGBuilder builder(j["name"], function_type, *return_type);
5✔
468

469
    size_t element_counter = j["element_counter"];
5✔
470
    builder.set_element_counter(element_counter);
5✔
471

472
    // deserialize structures
473
    assert(j.contains("structures"));
5✔
474
    assert(j["structures"].is_array());
5✔
475
    for (const auto& structure : j["structures"]) {
6✔
476
        assert(structure.contains("name"));
1✔
477
        assert(structure["name"].is_string());
1✔
478
        json_to_structure_definition(structure, builder);
1✔
479
    }
480

481
    nlohmann::json& containers = j["containers"];
5✔
482

483
    // deserialize externals
484
    for (const auto& external : j["externals"]) {
9✔
485
        assert(external.contains("name"));
4✔
486
        assert(external["name"].is_string());
4✔
487
        assert(external.contains("linkage_type"));
4✔
488
        assert(external["linkage_type"].is_number_integer());
4✔
489
        auto& type_desc = containers.at(external["name"].get<std::string>());
4✔
490
        auto type = json_to_type(type_desc);
4✔
491
        builder.add_external(external["name"], *type, LinkageType(external["linkage_type"]));
4✔
492
    }
4✔
493

494
    // deserialize arguments
495
    for (const auto& name : j["arguments"]) {
8✔
496
        auto& type_desc = containers.at(name.get<std::string>());
3✔
497
        auto type = json_to_type(type_desc);
3✔
498
        builder.add_container(name, *type, true, false);
3✔
499
    }
3✔
500

501
    // deserialize transients
502
    for (const auto& entry : containers.items()) {
17✔
503
        if (builder.subject().is_argument(entry.key())) {
12✔
504
            continue;
3✔
505
        }
506
        if (builder.subject().is_external(entry.key())) {
9✔
507
            continue;
4✔
508
        }
509
        auto type = json_to_type(entry.value());
5✔
510
        builder.add_container(entry.key(), *type, false, false);
5✔
511
    }
5✔
512

513
    // deserialize root node
514
    assert(j.contains("root"));
5✔
515
    auto& root = builder.subject().root();
5✔
516
    json_to_sequence(j["root"], builder, root);
5✔
517

518
    // deserialize metadata
519
    assert(j.contains("metadata"));
5✔
520
    assert(j["metadata"].is_object());
5✔
521
    for (const auto& entry : j["metadata"].items()) {
6✔
522
        builder.subject().add_metadata(entry.key(), entry.value());
1✔
523
    }
524

525
    builder.set_element_counter(element_counter);
5✔
526

527
    return builder.move();
5✔
528
}
5✔
529

530
void JSONSerializer::json_to_structure_definition(const nlohmann::json& j, builder::StructuredSDFGBuilder& builder) {
2✔
531
    assert(j.contains("name"));
2✔
532
    assert(j["name"].is_string());
2✔
533
    assert(j.contains("members"));
2✔
534
    assert(j["members"].is_array());
2✔
535
    assert(j.contains("is_packed"));
2✔
536
    assert(j["is_packed"].is_boolean());
2✔
537
    auto is_packed = j["is_packed"];
2✔
538
    auto& definition = builder.add_structure(j["name"], is_packed);
2✔
539
    for (const auto& member : j["members"]) {
4✔
540
        nlohmann::json member_json;
2✔
541
        auto member_type = json_to_type(member);
2✔
542
        definition.add_member(*member_type);
2✔
543
    }
2✔
544
}
2✔
545

546
std::vector<std::pair<std::string, types::Scalar>> JSONSerializer::json_to_arguments(const nlohmann::json& j) {
×
547
    std::vector<std::pair<std::string, types::Scalar>> arguments;
×
548
    for (const auto& argument : j) {
×
549
        assert(argument.contains("name"));
×
550
        assert(argument["name"].is_string());
×
551
        assert(argument.contains("type"));
×
552
        assert(argument["type"].is_object());
×
553
        std::string name = argument["name"];
×
554
        auto type = json_to_type(argument["type"]);
×
555
        arguments.emplace_back(name, *dynamic_cast<types::Scalar*>(type.get()));
×
556
    }
×
557
    return arguments;
×
558
}
×
559

560
void JSONSerializer::json_to_dataflow(
11✔
561
    const nlohmann::json& j, builder::StructuredSDFGBuilder& builder, structured_control_flow::Block& parent
562
) {
563
    std::unordered_map<size_t, data_flow::DataFlowNode&> nodes_map;
11✔
564

565
    assert(j.contains("nodes"));
11✔
566
    assert(j["nodes"].is_array());
11✔
567
    for (const auto& node : j["nodes"]) {
27✔
568
        assert(node.contains("type"));
16✔
569
        assert(node["type"].is_string());
16✔
570
        assert(node.contains("element_id"));
16✔
571
        assert(node["element_id"].is_number_integer());
16✔
572
        std::string type = node["type"];
16✔
573
        if (type == "tasklet") {
16✔
574
            assert(node.contains("code"));
4✔
575
            assert(node["code"].is_number_integer());
4✔
576
            assert(node.contains("inputs"));
4✔
577
            assert(node["inputs"].is_array());
4✔
578
            assert(node.contains("output"));
4✔
579
            assert(node["output"].is_string());
4✔
580
            auto inputs = node["inputs"].get<std::vector<std::string>>();
4✔
581

582
            auto& tasklet =
4✔
583
                builder
8✔
584
                    .add_tasklet(parent, node["code"], node["output"], inputs, json_to_debug_info(node["debug_info"]));
4✔
585
            tasklet.element_id_ = node["element_id"];
4✔
586
            nodes_map.insert({node["element_id"], tasklet});
4✔
587
        } else if (type == "library_node") {
16✔
588
            assert(node.contains("code"));
×
589
            data_flow::LibraryNodeCode code(node["code"].get<std::string>());
×
590

591
            auto serializer_fn = LibraryNodeSerializerRegistry::instance().get_library_node_serializer(code.value());
×
592
            if (serializer_fn == nullptr) {
×
593
                throw std::runtime_error("Unknown library node code: " + std::string(code.value()));
×
594
            }
595
            auto serializer = serializer_fn();
×
596
            auto& lib_node = serializer->deserialize(node, builder, parent);
×
597
            lib_node.implementation_type() =
×
598
                data_flow::ImplementationType(node["implementation_type"].get<std::string>());
×
599
            lib_node.element_id_ = node["element_id"];
×
600
            nodes_map.insert({node["element_id"], lib_node});
×
601
        } else if (type == "access_node") {
12✔
602
            assert(node.contains("data"));
12✔
603
            auto& access_node = builder.add_access(parent, node["data"], json_to_debug_info(node["debug_info"]));
12✔
604
            access_node.element_id_ = node["element_id"];
12✔
605
            nodes_map.insert({node["element_id"], access_node});
12✔
606
        } else if (type == "constant_node") {
12✔
607
            assert(node.contains("data"));
×
608
            assert(node.contains("data_type"));
×
609

610
            auto type = json_to_type(node["data_type"]);
×
611

612
            auto& constant_node =
×
613
                builder.add_constant(parent, node["data"], *type, json_to_debug_info(node["debug_info"]));
×
614
            constant_node.element_id_ = node["element_id"];
×
615
            nodes_map.insert({node["element_id"], constant_node});
×
616
        } else {
×
617
            throw std::runtime_error("Unknown node type");
×
618
        }
619
    }
16✔
620

621
    assert(j.contains("edges"));
11✔
622
    assert(j["edges"].is_array());
11✔
623
    for (const auto& edge : j["edges"]) {
23✔
624
        assert(edge.contains("src"));
12✔
625
        assert(edge["src"].is_number_integer());
12✔
626
        assert(edge.contains("dst"));
12✔
627
        assert(edge["dst"].is_number_integer());
12✔
628
        assert(edge.contains("src_conn"));
12✔
629
        assert(edge["src_conn"].is_string());
12✔
630
        assert(edge.contains("dst_conn"));
12✔
631
        assert(edge["dst_conn"].is_string());
12✔
632
        assert(edge.contains("subset"));
12✔
633
        assert(edge["subset"].is_array());
12✔
634

635
        assert(nodes_map.find(edge["src"]) != nodes_map.end());
12✔
636
        assert(nodes_map.find(edge["dst"]) != nodes_map.end());
12✔
637
        auto& source = nodes_map.at(edge["src"]);
12✔
638
        auto& target = nodes_map.at(edge["dst"]);
12✔
639

640
        auto base_type = json_to_type(edge["base_type"]);
12✔
641

642
        assert(edge.contains("subset"));
12✔
643
        assert(edge["subset"].is_array());
12✔
644
        std::vector<symbolic::Expression> subset;
12✔
645
        for (const auto& subset_ : edge["subset"]) {
16✔
646
            assert(subset_.is_string());
4✔
647
            std::string subset_str = subset_;
4✔
648
            auto expr = symbolic::parse(subset_str);
4✔
649
            subset.push_back(expr);
4✔
650
        }
4✔
651
        auto& memlet = builder.add_memlet(
24✔
652
            parent,
12✔
653
            source,
12✔
654
            edge["src_conn"],
12✔
655
            target,
12✔
656
            edge["dst_conn"],
12✔
657
            subset,
658
            *base_type,
12✔
659
            json_to_debug_info(edge["debug_info"])
12✔
660
        );
661
        memlet.element_id_ = edge["element_id"];
12✔
662
    }
12✔
663
}
11✔
664

665
void JSONSerializer::json_to_sequence(
14✔
666
    const nlohmann::json& j, builder::StructuredSDFGBuilder& builder, structured_control_flow::Sequence& sequence
667
) {
668
    assert(j.contains("type"));
14✔
669
    assert(j["type"].is_string());
14✔
670
    assert(j.contains("children"));
14✔
671
    assert(j["children"].is_array());
14✔
672
    assert(j.contains("transitions"));
14✔
673
    assert(j["transitions"].is_array());
14✔
674
    assert(j["transitions"].size() == j["children"].size());
14✔
675

676
    sequence.element_id_ = j["element_id"];
14✔
677
    sequence.debug_info_ = json_to_debug_info(j["debug_info"]);
14✔
678

679
    std::string type = j["type"];
14✔
680
    if (type == "sequence") {
14✔
681
        for (size_t i = 0; i < j["children"].size(); i++) {
25✔
682
            auto& child = j["children"][i];
11✔
683
            auto& transition = j["transitions"][i];
11✔
684
            assert(child.contains("type"));
11✔
685
            assert(child["type"].is_string());
11✔
686

687
            assert(transition.contains("type"));
11✔
688
            assert(transition["type"].is_string());
11✔
689
            assert(transition.contains("assignments"));
11✔
690
            assert(transition["assignments"].is_array());
11✔
691
            control_flow::Assignments assignments;
11✔
692
            for (const auto& assignment : transition["assignments"]) {
13✔
693
                assert(assignment.contains("symbol"));
2✔
694
                assert(assignment["symbol"].is_string());
2✔
695
                assert(assignment.contains("expression"));
2✔
696
                assert(assignment["expression"].is_string());
2✔
697
                auto expr = symbolic::parse(assignment["expression"].get<std::string>());
2✔
698
                assignments.insert({symbolic::symbol(assignment["symbol"]), expr});
2✔
699
            }
2✔
700

701
            if (child["type"] == "block") {
11✔
702
                json_to_block_node(child, builder, sequence, assignments);
9✔
703
            } else if (child["type"] == "for") {
11✔
704
                json_to_for_node(child, builder, sequence, assignments);
×
705
            } else if (child["type"] == "if_else") {
2✔
706
                json_to_if_else_node(child, builder, sequence, assignments);
×
707
            } else if (child["type"] == "while") {
2✔
708
                json_to_while_node(child, builder, sequence, assignments);
×
709
            } else if (child["type"] == "break") {
2✔
710
                json_to_break_node(child, builder, sequence, assignments);
1✔
711
            } else if (child["type"] == "continue") {
2✔
712
                json_to_continue_node(child, builder, sequence, assignments);
1✔
713
            } else if (child["type"] == "return") {
1✔
714
                json_to_return_node(child, builder, sequence, assignments);
×
715
            } else if (child["type"] == "map") {
×
716
                json_to_map_node(child, builder, sequence, assignments);
×
717
            } else if (child["type"] == "sequence") {
×
718
                auto& subseq = builder.add_sequence(sequence, assignments, json_to_debug_info(child["debug_info"]));
×
719
                json_to_sequence(child, builder, subseq);
×
720
            } else {
×
721
                throw std::runtime_error("Unknown child type");
×
722
            }
723

724
            sequence.at(i).second.debug_info_ = json_to_debug_info(transition["debug_info"]);
11✔
725
            sequence.at(i).second.element_id_ = transition["element_id"];
11✔
726
        }
11✔
727
    } else {
14✔
728
        throw std::runtime_error("expected sequence type");
×
729
    }
730
}
14✔
731

732
void JSONSerializer::json_to_block_node(
10✔
733
    const nlohmann::json& j,
734
    builder::StructuredSDFGBuilder& builder,
735
    structured_control_flow::Sequence& parent,
736
    control_flow::Assignments& assignments
737
) {
738
    assert(j.contains("type"));
10✔
739
    assert(j["type"].is_string());
10✔
740
    assert(j.contains("dataflow"));
10✔
741
    assert(j["dataflow"].is_object());
10✔
742
    auto& block = builder.add_block(parent, assignments, json_to_debug_info(j["debug_info"]));
10✔
743
    block.element_id_ = j["element_id"];
10✔
744
    assert(j["dataflow"].contains("type"));
10✔
745
    assert(j["dataflow"]["type"].is_string());
10✔
746
    std::string type = j["dataflow"]["type"];
10✔
747
    if (type == "dataflow") {
10✔
748
        json_to_dataflow(j["dataflow"], builder, block);
10✔
749
    } else {
10✔
750
        throw std::runtime_error("Unknown dataflow type");
×
751
    }
752
}
10✔
753

754
void JSONSerializer::json_to_for_node(
1✔
755
    const nlohmann::json& j,
756
    builder::StructuredSDFGBuilder& builder,
757
    structured_control_flow::Sequence& parent,
758
    control_flow::Assignments& assignments
759
) {
760
    assert(j.contains("type"));
1✔
761
    assert(j["type"].is_string());
1✔
762
    assert(j.contains("indvar"));
1✔
763
    assert(j["indvar"].is_string());
1✔
764
    assert(j.contains("init"));
1✔
765
    assert(j["init"].is_string());
1✔
766
    assert(j.contains("condition"));
1✔
767
    assert(j["condition"].is_string());
1✔
768
    assert(j.contains("update"));
1✔
769
    assert(j["update"].is_string());
1✔
770
    assert(j.contains("root"));
1✔
771
    assert(j["root"].is_object());
1✔
772

773
    symbolic::Symbol indvar = symbolic::symbol(j["indvar"]);
1✔
774
    auto init = symbolic::parse(j["init"].get<std::string>());
1✔
775
    auto update = symbolic::parse(j["update"].get<std::string>());
1✔
776

777
    auto condition_expr = symbolic::parse(j["condition"].get<std::string>());
1✔
778
    symbolic::Condition condition = SymEngine::rcp_dynamic_cast<const SymEngine::Boolean>(condition_expr);
1✔
779
    if (condition.is_null()) {
1✔
780
        throw InvalidSDFGException("For loop condition is not a boolean expression");
×
781
    }
782

783
    auto& for_node =
1✔
784
        builder.add_for(parent, indvar, condition, init, update, assignments, json_to_debug_info(j["debug_info"]));
1✔
785
    for_node.element_id_ = j["element_id"];
1✔
786

787
    assert(j["root"].contains("type"));
1✔
788
    assert(j["root"]["type"].is_string());
1✔
789
    assert(j["root"]["type"] == "sequence");
1✔
790
    json_to_sequence(j["root"], builder, for_node.root());
1✔
791
}
1✔
792

793
void JSONSerializer::json_to_if_else_node(
1✔
794
    const nlohmann::json& j,
795
    builder::StructuredSDFGBuilder& builder,
796
    structured_control_flow::Sequence& parent,
797
    control_flow::Assignments& assignments
798
) {
799
    assert(j.contains("type"));
1✔
800
    assert(j["type"].is_string());
1✔
801
    assert(j["type"] == "if_else");
1✔
802
    assert(j.contains("branches"));
1✔
803
    assert(j["branches"].is_array());
1✔
804
    auto& if_else_node = builder.add_if_else(parent, assignments, json_to_debug_info(j["debug_info"]));
1✔
805
    if_else_node.element_id_ = j["element_id"];
1✔
806
    for (const auto& branch : j["branches"]) {
3✔
807
        assert(branch.contains("condition"));
2✔
808
        assert(branch["condition"].is_string());
2✔
809
        assert(branch.contains("root"));
2✔
810
        assert(branch["root"].is_object());
2✔
811

812
        auto condition_expr = symbolic::parse(branch["condition"].get<std::string>());
2✔
813
        symbolic::Condition condition = SymEngine::rcp_dynamic_cast<const SymEngine::Boolean>(condition_expr);
2✔
814
        if (condition.is_null()) {
2✔
815
            throw InvalidSDFGException("If condition is not a boolean expression");
×
816
        }
817
        auto& branch_node = builder.add_case(if_else_node, condition);
2✔
818
        assert(branch["root"].contains("type"));
2✔
819
        assert(branch["root"]["type"].is_string());
2✔
820
        std::string type = branch["root"]["type"];
2✔
821
        if (type == "sequence") {
2✔
822
            json_to_sequence(branch["root"], builder, branch_node);
2✔
823
        } else {
2✔
824
            throw std::runtime_error("Unknown child type");
×
825
        }
826
    }
2✔
827
}
1✔
828

829
void JSONSerializer::json_to_while_node(
3✔
830
    const nlohmann::json& j,
831
    builder::StructuredSDFGBuilder& builder,
832
    structured_control_flow::Sequence& parent,
833
    control_flow::Assignments& assignments
834
) {
835
    assert(j.contains("type"));
3✔
836
    assert(j["type"].is_string());
3✔
837
    assert(j["type"] == "while");
3✔
838
    assert(j.contains("root"));
3✔
839
    assert(j["root"].is_object());
3✔
840

841
    auto& while_node = builder.add_while(parent, assignments, json_to_debug_info(j["debug_info"]));
3✔
842
    while_node.element_id_ = j["element_id"];
3✔
843

844
    assert(j["root"]["type"] == "sequence");
3✔
845
    json_to_sequence(j["root"], builder, while_node.root());
3✔
846
}
3✔
847

848
void JSONSerializer::json_to_break_node(
1✔
849
    const nlohmann::json& j,
850
    builder::StructuredSDFGBuilder& builder,
851
    structured_control_flow::Sequence& parent,
852
    control_flow::Assignments& assignments
853
) {
854
    assert(j.contains("type"));
1✔
855
    assert(j["type"].is_string());
1✔
856
    assert(j["type"] == "break");
1✔
857
    auto& node = builder.add_break(parent, assignments, json_to_debug_info(j["debug_info"]));
1✔
858
    node.element_id_ = j["element_id"];
1✔
859
}
1✔
860

861
void JSONSerializer::json_to_continue_node(
1✔
862
    const nlohmann::json& j,
863
    builder::StructuredSDFGBuilder& builder,
864
    structured_control_flow::Sequence& parent,
865
    control_flow::Assignments& assignments
866
) {
867
    assert(j.contains("type"));
1✔
868
    assert(j["type"].is_string());
1✔
869
    assert(j["type"] == "continue");
1✔
870
    auto& node = builder.add_continue(parent, assignments, json_to_debug_info(j["debug_info"]));
1✔
871
    node.element_id_ = j["element_id"];
1✔
872
}
1✔
873

874
void JSONSerializer::json_to_map_node(
1✔
875
    const nlohmann::json& j,
876
    builder::StructuredSDFGBuilder& builder,
877
    structured_control_flow::Sequence& parent,
878
    control_flow::Assignments& assignments
879
) {
880
    assert(j.contains("type"));
1✔
881
    assert(j["type"].is_string());
1✔
882
    assert(j["type"] == "map");
1✔
883
    assert(j.contains("indvar"));
1✔
884
    assert(j["indvar"].is_string());
1✔
885
    assert(j.contains("init"));
1✔
886
    assert(j["init"].is_string());
1✔
887
    assert(j.contains("condition"));
1✔
888
    assert(j["condition"].is_string());
1✔
889
    assert(j.contains("update"));
1✔
890
    assert(j["update"].is_string());
1✔
891
    assert(j.contains("root"));
1✔
892
    assert(j["root"].is_object());
1✔
893
    assert(j.contains("schedule_type"));
1✔
894
    assert(j["schedule_type"].is_object());
1✔
895

896
    structured_control_flow::ScheduleType schedule_type = json_to_schedule_type(j["schedule_type"]);
1✔
897

898
    symbolic::Symbol indvar = symbolic::symbol(j["indvar"]);
1✔
899
    auto init = symbolic::parse(j["init"].get<std::string>());
1✔
900
    auto update = symbolic::parse(j["update"].get<std::string>());
1✔
901
    auto condition_expr = symbolic::parse(j["condition"].get<std::string>());
1✔
902
    symbolic::Condition condition = SymEngine::rcp_dynamic_cast<const SymEngine::Boolean>(condition_expr);
1✔
903
    if (condition.is_null()) {
1✔
904
        throw InvalidSDFGException("Map condition is not a boolean expression");
×
905
    }
906

907
    auto& map_node = builder.add_map(
2✔
908
        parent, indvar, condition, init, update, schedule_type, assignments, json_to_debug_info(j["debug_info"])
1✔
909
    );
910
    map_node.element_id_ = j["element_id"];
1✔
911

912
    assert(j["root"].contains("type"));
1✔
913
    assert(j["root"]["type"].is_string());
1✔
914
    assert(j["root"]["type"] == "sequence");
1✔
915
    json_to_sequence(j["root"], builder, map_node.root());
1✔
916
}
1✔
917

918
void JSONSerializer::json_to_return_node(
1✔
919
    const nlohmann::json& j,
920
    builder::StructuredSDFGBuilder& builder,
921
    structured_control_flow::Sequence& parent,
922
    control_flow::Assignments& assignments
923
) {
924
    assert(j.contains("type"));
1✔
925
    assert(j["type"].is_string());
1✔
926
    assert(j["type"] == "return");
1✔
927

928
    std::string data = j["data"];
1✔
929
    bool unreachable = j["unreachable"];
1✔
930
    std::unique_ptr<types::IType> data_type = nullptr;
1✔
931
    if (j.contains("data_type")) {
1✔
NEW
932
        data_type = json_to_type(j["data_type"]);
×
UNCOV
933
    }
×
934

935
    if (unreachable) {
1✔
NEW
936
        auto& node = builder.add_unreachable(parent, assignments, json_to_debug_info(j["debug_info"]));
×
NEW
937
        node.element_id_ = j["element_id"];
×
938
    } else if (data_type == nullptr) {
1✔
939
        auto& node = builder.add_return(parent, data, assignments, json_to_debug_info(j["debug_info"]));
1✔
940
        node.element_id_ = j["element_id"];
1✔
941
    } else {
1✔
NEW
942
        auto& node =
×
NEW
943
            builder.add_constant_return(parent, data, *data_type, assignments, json_to_debug_info(j["debug_info"]));
×
NEW
944
        node.element_id_ = j["element_id"];
×
945
    }
946
}
1✔
947

948
std::unique_ptr<types::IType> JSONSerializer::json_to_type(const nlohmann::json& j) {
46✔
949
    if (j.contains("type")) {
46✔
950
        if (j["type"] == "scalar") {
46✔
951
            // Deserialize scalar type
952
            assert(j.contains("primitive_type"));
35✔
953
            types::PrimitiveType primitive_type = j["primitive_type"];
35✔
954
            assert(j.contains("storage_type"));
35✔
955
            types::StorageType storage_type = storage_type_from_string(j["storage_type"].get<std::string>());
35✔
956
            assert(j.contains("initializer"));
35✔
957
            std::string initializer = j["initializer"];
35✔
958
            assert(j.contains("alignment"));
35✔
959
            size_t alignment = j["alignment"];
35✔
960
            return std::make_unique<types::Scalar>(storage_type, alignment, initializer, primitive_type);
35✔
961
        } else if (j["type"] == "array") {
46✔
962
            // Deserialize array type
963
            assert(j.contains("element_type"));
2✔
964
            std::unique_ptr<types::IType> member_type = json_to_type(j["element_type"]);
2✔
965
            assert(j.contains("num_elements"));
2✔
966
            std::string num_elements_str = j["num_elements"];
2✔
967
            // Convert num_elements_str to symbolic::Expression
968
            auto num_elements = symbolic::parse(num_elements_str);
2✔
969
            assert(j.contains("storage_type"));
2✔
970
            types::StorageType storage_type = storage_type_from_string(j["storage_type"].get<std::string>());
2✔
971
            assert(j.contains("initializer"));
2✔
972
            std::string initializer = j["initializer"];
2✔
973
            assert(j.contains("alignment"));
2✔
974
            size_t alignment = j["alignment"];
2✔
975
            return std::make_unique<types::Array>(storage_type, alignment, initializer, *member_type, num_elements);
2✔
976
        } else if (j["type"] == "pointer") {
11✔
977
            // Deserialize pointer type
978
            std::optional<std::unique_ptr<types::IType>> pointee_type;
6✔
979
            if (j.contains("pointee_type")) {
6✔
980
                assert(j.contains("pointee_type"));
5✔
981
                pointee_type = json_to_type(j["pointee_type"]);
5✔
982
            } else {
5✔
983
                pointee_type = std::nullopt;
1✔
984
            }
985
            assert(j.contains("storage_type"));
6✔
986
            types::StorageType storage_type = storage_type_from_string(j["storage_type"].get<std::string>());
6✔
987
            assert(j.contains("initializer"));
6✔
988
            std::string initializer = j["initializer"];
6✔
989
            assert(j.contains("alignment"));
6✔
990
            size_t alignment = j["alignment"];
6✔
991
            if (pointee_type.has_value()) {
6✔
992
                return std::make_unique<types::Pointer>(storage_type, alignment, initializer, *pointee_type.value());
5✔
993
            } else {
994
                return std::make_unique<types::Pointer>(storage_type, alignment, initializer);
1✔
995
            }
996
        } else if (j["type"] == "structure") {
9✔
997
            // Deserialize structure type
998
            assert(j.contains("name"));
2✔
999
            std::string name = j["name"];
2✔
1000
            assert(j.contains("storage_type"));
2✔
1001
            types::StorageType storage_type = storage_type_from_string(j["storage_type"].get<std::string>());
2✔
1002
            assert(j.contains("initializer"));
2✔
1003
            std::string initializer = j["initializer"];
2✔
1004
            assert(j.contains("alignment"));
2✔
1005
            size_t alignment = j["alignment"];
2✔
1006
            return std::make_unique<types::Structure>(storage_type, alignment, initializer, name);
2✔
1007
        } else if (j["type"] == "function") {
3✔
1008
            // Deserialize function type
1009
            assert(j.contains("return_type"));
1✔
1010
            std::unique_ptr<types::IType> return_type = json_to_type(j["return_type"]);
1✔
1011
            assert(j.contains("params"));
1✔
1012
            std::vector<std::unique_ptr<types::IType>> params;
1✔
1013
            for (const auto& param : j["params"]) {
3✔
1014
                params.push_back(json_to_type(param));
2✔
1015
            }
1016
            assert(j.contains("is_var_arg"));
1✔
1017
            bool is_var_arg = j["is_var_arg"];
1✔
1018
            assert(j.contains("storage_type"));
1✔
1019
            types::StorageType storage_type = storage_type_from_string(j["storage_type"].get<std::string>());
1✔
1020
            assert(j.contains("initializer"));
1✔
1021
            std::string initializer = j["initializer"];
1✔
1022
            assert(j.contains("alignment"));
1✔
1023
            size_t alignment = j["alignment"];
1✔
1024
            auto function =
1025
                std::make_unique<types::Function>(storage_type, alignment, initializer, *return_type, is_var_arg);
1✔
1026
            for (const auto& param : params) {
3✔
1027
                function->add_param(*param);
2✔
1028
            }
1029
            return function->clone();
1✔
1030

1031
        } else {
1✔
1032
            throw std::runtime_error("Unknown type");
×
1033
        }
1034
    } else {
1035
        throw std::runtime_error("Type not found");
×
1036
    }
1037
}
46✔
1038

1039
DebugInfo JSONSerializer::json_to_debug_info(const nlohmann::json& j) {
72✔
1040
    assert(j.contains("has"));
72✔
1041
    assert(j["has"].is_boolean());
72✔
1042
    if (!j["has"]) {
72✔
1043
        return DebugInfo();
72✔
1044
    }
1045
    assert(j.contains("filename"));
×
1046
    assert(j["filename"].is_string());
×
1047
    std::string filename = j["filename"];
×
1048
    assert(j.contains("function"));
×
1049
    assert(j["function"].is_string());
×
1050
    std::string function = j["function"];
×
1051
    assert(j.contains("start_line"));
×
1052
    assert(j["start_line"].is_number_integer());
×
1053
    size_t start_line = j["start_line"];
×
1054
    assert(j.contains("start_column"));
×
1055
    assert(j["start_column"].is_number_integer());
×
1056
    size_t start_column = j["start_column"];
×
1057
    assert(j.contains("end_line"));
×
1058
    assert(j["end_line"].is_number_integer());
×
1059
    size_t end_line = j["end_line"];
×
1060
    assert(j.contains("end_column"));
×
1061
    assert(j["end_column"].is_number_integer());
×
1062
    size_t end_column = j["end_column"];
×
1063
    return DebugInfo(filename, function, start_line, start_column, end_line, end_column);
×
1064
}
72✔
1065

1066
ScheduleType JSONSerializer::json_to_schedule_type(const nlohmann::json& j) {
2✔
1067
    assert(j.contains("value"));
2✔
1068
    assert(j["value"].is_string());
2✔
1069
    assert(j.contains("properties"));
2✔
1070
    assert(j["properties"].is_object());
2✔
1071
    ScheduleType schedule_type(j["value"].get<std::string>());
2✔
1072
    for (const auto& [key, value] : j["properties"].items()) {
4✔
1073
        assert(value.is_string());
1✔
1074
        schedule_type.set_property(key, value.get<std::string>());
1✔
1075
    }
1076
    return schedule_type;
2✔
1077
}
2✔
1078

1079
std::string JSONSerializer::expression(const symbolic::Expression expr) {
37✔
1080
    JSONSymbolicPrinter printer;
37✔
1081
    return printer.apply(expr);
37✔
1082
};
37✔
1083

1084
void JSONSymbolicPrinter::bvisit(const SymEngine::Equality& x) {
×
1085
    str_ = apply(x.get_args()[0]) + " == " + apply(x.get_args()[1]);
×
1086
    str_ = parenthesize(str_);
×
1087
};
×
1088

1089
void JSONSymbolicPrinter::bvisit(const SymEngine::Unequality& x) {
×
1090
    str_ = apply(x.get_args()[0]) + " != " + apply(x.get_args()[1]);
×
1091
    str_ = parenthesize(str_);
×
1092
};
×
1093

1094
void JSONSymbolicPrinter::bvisit(const SymEngine::LessThan& x) {
×
1095
    str_ = apply(x.get_args()[0]) + " <= " + apply(x.get_args()[1]);
×
1096
    str_ = parenthesize(str_);
×
1097
};
×
1098

1099
void JSONSymbolicPrinter::bvisit(const SymEngine::StrictLessThan& x) {
4✔
1100
    str_ = apply(x.get_args()[0]) + " < " + apply(x.get_args()[1]);
4✔
1101
    str_ = parenthesize(str_);
4✔
1102
};
4✔
1103

1104
void JSONSymbolicPrinter::bvisit(const SymEngine::Min& x) {
×
1105
    std::ostringstream s;
×
1106
    auto container = x.get_args();
×
1107
    if (container.size() == 1) {
×
1108
        s << apply(*container.begin());
×
1109
    } else {
×
1110
        s << "min(";
×
1111
        s << apply(*container.begin());
×
1112

1113
        // Recursively apply __daisy_min to the arguments
1114
        SymEngine::vec_basic subargs;
×
1115
        for (auto it = ++(container.begin()); it != container.end(); ++it) {
×
1116
            subargs.push_back(*it);
×
1117
        }
×
1118
        auto submin = SymEngine::min(subargs);
×
1119
        s << ", " << apply(submin);
×
1120

1121
        s << ")";
×
1122
    }
×
1123

1124
    str_ = s.str();
×
1125
};
×
1126

1127
void JSONSymbolicPrinter::bvisit(const SymEngine::Max& x) {
×
1128
    std::ostringstream s;
×
1129
    auto container = x.get_args();
×
1130
    if (container.size() == 1) {
×
1131
        s << apply(*container.begin());
×
1132
    } else {
×
1133
        s << "max(";
×
1134
        s << apply(*container.begin());
×
1135

1136
        // Recursively apply __daisy_max to the arguments
1137
        SymEngine::vec_basic subargs;
×
1138
        for (auto it = ++(container.begin()); it != container.end(); ++it) {
×
1139
            subargs.push_back(*it);
×
1140
        }
×
1141
        auto submax = SymEngine::max(subargs);
×
1142
        s << ", " << apply(submax);
×
1143

1144
        s << ")";
×
1145
    }
×
1146

1147
    str_ = s.str();
×
1148
};
×
1149

1150
void LibraryNodeSerializerRegistry::
1151
    register_library_node_serializer(std::string library_node_code, LibraryNodeSerializerFn fn) {
34✔
1152
    std::lock_guard<std::mutex> lock(mutex_);
34✔
1153
    if (factory_map_.find(library_node_code) != factory_map_.end()) {
34✔
1154
        throw std::runtime_error(
×
1155
            "Library node serializer already registered for library node code: " + std::string(library_node_code)
×
1156
        );
1157
    }
1158
    factory_map_[library_node_code] = std::move(fn);
34✔
1159
}
34✔
1160

1161
LibraryNodeSerializerFn LibraryNodeSerializerRegistry::get_library_node_serializer(std::string library_node_code) {
1✔
1162
    auto it = factory_map_.find(library_node_code);
1✔
1163
    if (it != factory_map_.end()) {
1✔
1164
        return it->second;
1✔
1165
    }
1166
    return nullptr;
×
1167
}
1✔
1168

1169
size_t LibraryNodeSerializerRegistry::size() const { return factory_map_.size(); }
×
1170

1171
void register_default_serializers() {
2✔
1172
    // stdlib
1173
    LibraryNodeSerializerRegistry::instance()
2✔
1174
        .register_library_node_serializer(stdlib::LibraryNodeType_Alloca.value(), []() {
2✔
1175
            return std::make_unique<stdlib::AllocaNodeSerializer>();
×
1176
        });
1177
    LibraryNodeSerializerRegistry::instance()
2✔
1178
        .register_library_node_serializer(stdlib::LibraryNodeType_Calloc.value(), []() {
2✔
1179
            return std::make_unique<stdlib::CallocNodeSerializer>();
×
1180
        });
1181
    LibraryNodeSerializerRegistry::instance()
2✔
1182
        .register_library_node_serializer(stdlib::LibraryNodeType_Fprintf.value(), []() {
2✔
1183
            return std::make_unique<stdlib::FprintfNodeSerializer>();
×
1184
        });
1185
    LibraryNodeSerializerRegistry::instance()
2✔
1186
        .register_library_node_serializer(stdlib::LibraryNodeType_Fputc.value(), []() {
2✔
1187
            return std::make_unique<stdlib::FputcNodeSerializer>();
×
1188
        });
1189
    LibraryNodeSerializerRegistry::instance()
2✔
1190
        .register_library_node_serializer(stdlib::LibraryNodeType_Free.value(), []() {
2✔
1191
            return std::make_unique<stdlib::FreeNodeSerializer>();
×
1192
        });
1193
    LibraryNodeSerializerRegistry::instance()
2✔
1194
        .register_library_node_serializer(stdlib::LibraryNodeType_FWrite.value(), []() {
2✔
1195
            return std::make_unique<stdlib::FWriteNodeSerializer>();
×
1196
        });
1197
    LibraryNodeSerializerRegistry::instance()
2✔
1198
        .register_library_node_serializer(stdlib::LibraryNodeType_Malloc.value(), []() {
2✔
1199
            return std::make_unique<stdlib::MallocNodeSerializer>();
×
1200
        });
1201
    LibraryNodeSerializerRegistry::instance()
2✔
1202
        .register_library_node_serializer(stdlib::LibraryNodeType_Memcpy.value(), []() {
2✔
1203
            return std::make_unique<stdlib::MemcpyNodeSerializer>();
×
1204
        });
1205
    LibraryNodeSerializerRegistry::instance()
2✔
1206
        .register_library_node_serializer(stdlib::LibraryNodeType_Memmove.value(), []() {
2✔
1207
            return std::make_unique<stdlib::MemmoveNodeSerializer>();
×
1208
        });
1209
    LibraryNodeSerializerRegistry::instance()
2✔
1210
        .register_library_node_serializer(stdlib::LibraryNodeType_Memset.value(), []() {
2✔
1211
            return std::make_unique<stdlib::MemsetNodeSerializer>();
×
1212
        });
1213
    LibraryNodeSerializerRegistry::instance()
2✔
1214
        .register_library_node_serializer(stdlib::LibraryNodeType_Rand.value(), []() {
2✔
1215
            return std::make_unique<stdlib::RandNodeSerializer>();
×
1216
        });
1217
    LibraryNodeSerializerRegistry::instance()
2✔
1218
        .register_library_node_serializer(stdlib::LibraryNodeType_Srand.value(), []() {
2✔
1219
            return std::make_unique<stdlib::SrandNodeSerializer>();
×
1220
        });
1221

1222
    // Metadata
1223
    LibraryNodeSerializerRegistry::instance()
2✔
1224
        .register_library_node_serializer(data_flow::LibraryNodeType_Metadata.value(), []() {
2✔
1225
            return std::make_unique<data_flow::MetadataNodeSerializer>();
×
1226
        });
1227

1228
    // Barrier
1229
    LibraryNodeSerializerRegistry::instance()
2✔
1230
        .register_library_node_serializer(data_flow::LibraryNodeType_BarrierLocal.value(), []() {
3✔
1231
            return std::make_unique<data_flow::BarrierLocalNodeSerializer>();
1✔
1232
        });
1233

1234
    // Barrier
1235
    LibraryNodeSerializerRegistry::instance()
2✔
1236
        .register_library_node_serializer(data_flow::LibraryNodeType_Call.value(), []() {
2✔
1237
            return std::make_unique<data_flow::CallNodeSerializer>();
×
1238
        });
1239

1240
    // ML
1241
    // LibraryNodeSerializerRegistry::instance()
1242
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Abs.value(), []() {
1243
    //         return std::make_unique<math::ml::AbsNodeSerializer>();
1244
    //     });
1245
    // LibraryNodeSerializerRegistry::instance()
1246
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Add.value(), []() {
1247
    //         return std::make_unique<math::ml::AddNodeSerializer>();
1248
    //     });
1249
    // LibraryNodeSerializerRegistry::instance()
1250
    //     .register_library_node_serializer(math::ml::LibraryNodeType_BatchNormalization.value(), []() {
1251
    //         return std::make_unique<math::ml::BatchNormalizationNodeSerializer>();
1252
    //     });
1253
    // LibraryNodeSerializerRegistry::instance()
1254
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Clip.value(), []() {
1255
    //         return std::make_unique<math::ml::ClipNodeSerializer>();
1256
    //     });
1257
    // LibraryNodeSerializerRegistry::instance()
1258
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Conv.value(), []() {
1259
    //         return std::make_unique<math::ml::ConvNodeSerializer>();
1260
    //     });
1261
    // LibraryNodeSerializerRegistry::instance()
1262
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Div.value(), []() {
1263
    //         return std::make_unique<math::ml::DivNodeSerializer>();
1264
    //     });
1265
    // LibraryNodeSerializerRegistry::instance()
1266
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Dropout.value(), []() {
1267
    //         return std::make_unique<math::ml::DropoutSerializer>();
1268
    //     });
1269
    // LibraryNodeSerializerRegistry::instance()
1270
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Elu.value(), []() {
1271
    //         return std::make_unique<math::ml::EluNodeSerializer>();
1272
    //     });
1273
    // LibraryNodeSerializerRegistry::instance()
1274
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Erf.value(), []() {
1275
    //         return std::make_unique<math::ml::ErfNodeSerializer>();
1276
    //     });
1277
    // LibraryNodeSerializerRegistry::instance()
1278
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Gemm.value(), []() {
1279
    //         return std::make_unique<math::ml::GemmNodeSerializer>();
1280
    //     });
1281
    // LibraryNodeSerializerRegistry::instance()
1282
    //     .register_library_node_serializer(math::ml::LibraryNodeType_HardSigmoid.value(), []() {
1283
    //         return std::make_unique<math::ml::HardSigmoidNodeSerializer>();
1284
    //     });
1285
    // LibraryNodeSerializerRegistry::instance()
1286
    //     .register_library_node_serializer(math::ml::LibraryNodeType_LayerNormalization.value(), []() {
1287
    //         return std::make_unique<math::ml::LayerNormalizationNodeSerializer>();
1288
    //     });
1289
    // LibraryNodeSerializerRegistry::instance()
1290
    //     .register_library_node_serializer(math::ml::LibraryNodeType_LeakyReLU.value(), []() {
1291
    //         return std::make_unique<math::ml::LeakyReLUNodeSerializer>();
1292
    //     });
1293
    // LibraryNodeSerializerRegistry::instance()
1294
    //     .register_library_node_serializer(math::ml::LibraryNodeType_LogSoftmax.value(), []() {
1295
    //         return std::make_unique<math::ml::LogSoftmaxNodeSerializer>();
1296
    //     });
1297
    // LibraryNodeSerializerRegistry::instance()
1298
    //     .register_library_node_serializer(math::ml::LibraryNodeType_MatMul.value(), []() {
1299
    //         return std::make_unique<math::ml::MatMulNodeSerializer>();
1300
    //     });
1301
    // LibraryNodeSerializerRegistry::instance()
1302
    //     .register_library_node_serializer(math::ml::LibraryNodeType_MaxPool.value(), []() {
1303
    //         return std::make_unique<math::ml::MaxPoolNodeSerializer>();
1304
    //     });
1305
    // LibraryNodeSerializerRegistry::instance()
1306
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Mul.value(), []() {
1307
    //         return std::make_unique<math::ml::MulNodeSerializer>();
1308
    //     });
1309
    // LibraryNodeSerializerRegistry::instance()
1310
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Pow.value(), []() {
1311
    //         return std::make_unique<math::ml::PowNodeSerializer>();
1312
    //     });
1313
    // LibraryNodeSerializerRegistry::instance()
1314
    //     .register_library_node_serializer(math::ml::LibraryNodeType_ReduceMean.value(), []() {
1315
    //         return std::make_unique<math::ml::ReduceMeanNodeSerializer>();
1316
    //     });
1317
    // LibraryNodeSerializerRegistry::instance()
1318
    //     .register_library_node_serializer(math::ml::LibraryNodeType_ReLU.value(), []() {
1319
    //         return std::make_unique<math::ml::ReLUNodeSerializer>();
1320
    //     });
1321
    // LibraryNodeSerializerRegistry::instance()
1322
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Sigmoid.value(), []() {
1323
    //         return std::make_unique<math::ml::SigmoidNodeSerializer>();
1324
    //     });
1325
    // LibraryNodeSerializerRegistry::instance()
1326
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Softmax.value(), []() {
1327
    //         return std::make_unique<math::ml::SoftmaxNodeSerializer>();
1328
    //     });
1329
    // LibraryNodeSerializerRegistry::instance()
1330
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Sqrt.value(), []() {
1331
    //         return std::make_unique<math::ml::SqrtNodeSerializer>();
1332
    //     });
1333
    // LibraryNodeSerializerRegistry::instance()
1334
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Sub.value(), []() {
1335
    //         return std::make_unique<math::ml::SubNodeSerializer>();
1336
    //     });
1337
    // LibraryNodeSerializerRegistry::instance()
1338
    //     .register_library_node_serializer(math::ml::LibraryNodeType_Tanh.value(), []() {
1339
    //         return std::make_unique<math::ml::TanhNodeSerializer>();
1340
    //     });
1341

1342
    // BLAS
1343
    LibraryNodeSerializerRegistry::instance()
2✔
1344
        .register_library_node_serializer(math::blas::LibraryNodeType_DOT.value(), []() {
2✔
1345
            return std::make_unique<math::blas::DotNodeSerializer>();
×
1346
        });
1347
    LibraryNodeSerializerRegistry::instance()
2✔
1348
        .register_library_node_serializer(math::blas::LibraryNodeType_GEMM.value(), []() {
2✔
1349
            return std::make_unique<math::blas::GEMMNodeSerializer>();
×
1350
        });
1351
}
2✔
1352

1353
} // namespace serializer
1354
} // namespace sdfg
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc