15 const boost::filesystem::path& fullName,
GraphModule** toFill) {
18 auto resCtx = res.
addScopedContext({{
"Loading Module Name", fullName.string()},
23 if (toFill !=
nullptr) { *toFill = createdModule; }
27 auto iter = input.find(
"has_c_support");
28 if (iter == input.end()) {
29 res.
addEntry(
"EUKN",
"No has_c_support section in module JSON, assuming none", {});
32 if (!iter->is_boolean()) {
33 res.
addEntry(
"EUKN",
"has_c_support section in module JSON isn't a bool",
34 {{
"Actual Data", *iter}});
38 createdModule->setCEnabled(*iter);
43 auto iter = input.find(
"dependencies");
44 if (iter == input.end()) {
45 res.
addEntry(
"E38",
"No dependencies element in module", {});
48 if (!iter->is_array()) {
49 res.
addEntry(
"E39",
"dependencies element isn't an array", {});
53 for (
const auto& dep : *iter) {
54 if (!dep.is_string()) {
55 res.
addEntry(
"E40",
"dependency isn't a string", {{
"Actual Data", dep}});
59 std::string depName = dep;
60 res += createdModule->addDependency(depName);
62 if (!res) {
return res; }
68 auto iter = input.find(
"types");
69 if (iter == input.end() || !iter->is_object()) {
70 res.
addEntry(
"EUKN",
"No types object in module", {});
75 for (
auto tyIter = iter->begin(); tyIter != iter->end(); ++tyIter) {
76 createdModule->getOrCreateStruct(tyIter.key());
79 for (
auto tyIter = iter->begin(); tyIter != iter->end(); ++tyIter) {
86 auto iter = input.find(
"graphs");
87 if (iter == input.end()) {
88 res.
addEntry(
"E41",
"no graphs element in module", {});
91 if (!iter->is_array()) {
92 res.
addEntry(
"E42",
"graph element isn't an array", {{
"Actual Data", *iter}});
96 std::vector<GraphFunction*> functions;
97 functions.resize(iter->size());
101 for (
const auto& graph : *iter) {
107 if (!res) {
return res; }
111 for (
const auto& graph : *iter) {
125 if (!input.is_object()) {
126 res.
addEntry(
"E1",
"Graph json isn't a JSON object", {});
130 if (input.find(
"type") == input.end() || !input[
"type"].is_string()) {
131 res.
addEntry(
"E2", R
"(JSON in graph doesn't have a "type" element)", 132 {{"Module Name", createInside.
fullName()}});
135 if (input[
"type"] !=
"function") {
136 res.
addEntry(
"E3",
"JSON in graph doesn't have a function type",
137 {{
"Module Name", createInside.
fullName()}});
141 if (input.find(
"name") == input.end() || !input[
"name"].is_string()) {
142 res.
addEntry(
"E4",
"JSON in graph doesn't have a name parameter",
143 {{
"Module Name", createInside.
fullName()}});
146 std::string name = input[
"name"];
149 if (input.find(
"description") == input.end() || !input[
"description"].is_string()) {
150 res.
addEntry(
"E50",
"JSON in graph doesn't have a description string",
151 {{
"Function Name", name}, {
"Module Name", createInside.
fullName()}});
154 std::string description = input[
"description"];
156 if (input.find(
"data_inputs") == input.end() || !input[
"data_inputs"].is_array()) {
157 res.
addEntry(
"E43",
"JSON in graph doesn't have an data_inputs array", {});
161 std::vector<NamedDataType> datainputs;
162 for (
auto param : input[
"data_inputs"]) {
163 std::string docString, qualifiedType;
166 std::string moduleName, name;
172 if (!res) {
return res; }
174 datainputs.emplace_back(docString, ty);
177 if (input.find(
"data_outputs") == input.end() || !input[
"data_outputs"].is_array()) {
178 res.
addEntry(
"E44",
"JSON in graph doesn't have an data_outputs array", {});
182 std::vector<NamedDataType> dataoutputs;
183 for (
auto param : input[
"data_outputs"]) {
184 std::string docString, qualifiedType;
187 std::string moduleName, name;
193 if (!res) {
return res; }
195 dataoutputs.emplace_back(docString, ty);
199 if (input.find(
"exec_inputs") == input.end() || !input[
"exec_inputs"].is_array()) {
200 res.
addEntry(
"E48",
"JSON in graph doesn't have an exec_inputs array", {});
204 std::vector<std::string> execinputs;
205 for (
const auto& param : input[
"exec_inputs"]) {
206 std::string name = param;
208 execinputs.emplace_back(name);
211 if (input.find(
"exec_outputs") == input.end() || !input[
"exec_outputs"].is_array()) {
212 res.
addEntry(
"E49",
"JSON in graph doesn't have an data_outputs array", {});
216 std::vector<std::string> execoutputs;
217 for (
const auto& param : input[
"exec_outputs"]) {
218 std::string name = param;
220 execoutputs.emplace_back(name);
227 if (toFill !=
nullptr) { *toFill = created; }
236 if (input.find(
"local_variables") == input.end() || !input[
"local_variables"].is_object()) {
237 res.
addEntry(
"E45",
"JSON in graph doesn't have a local_variables object", {});
242 for (
auto localiter = input[
"local_variables"].begin();
243 localiter != input[
"local_variables"].end(); ++localiter) {
244 std::string localName = localiter.key();
246 if (!localiter.value().is_string()) {
247 res.
addEntry(
"E46",
"Local variable vaue in json wasn't a string",
248 {{
"Given local variable json", localiter.value()}});
254 std::string qualifiedType = localiter.value();
256 std::string moduleName, typeName;
262 if (!res) {
continue; }
268 if (input.find(
"nodes") == input.end() || !input[
"nodes"].is_object()) {
269 res.
addEntry(
"E5",
"JSON in graph doesn't have nodes object", {});
273 for (
auto nodeiter = input[
"nodes"].begin(); nodeiter != input[
"nodes"].end(); ++nodeiter) {
274 auto node = nodeiter.value();
275 std::string nodeid = nodeiter.key();
276 if (node.find(
"type") == node.end() || !node.find(
"type")->is_string()) {
277 res.
addEntry(
"E6", R
"(Node doesn't have a "type" string)", {{"Node ID", nodeid}});
280 std::string fullType = node[
"type"];
281 std::string moduleName, typeName;
284 if (moduleName.empty() || typeName.empty()) {
285 res.
addEntry(
"E7",
"Incorrect qualified module name (should be module:type)",
286 {{
"Node ID", nodeid}, {
"Requested Qualified Name", fullType}});
290 if (node.find(
"data") == node.end()) {
291 res.
addEntry(
"E9",
"Node doens't have a data section", {{
"Node ID", nodeid}});
295 std::unique_ptr<NodeType> nodeType;
298 if (!res) {
continue; }
300 auto testIter = node.find(
"location");
301 if (testIter == node.end()) {
302 res.
addEntry(
"E12",
"Node doesn't have a location.", {{
"Node ID", nodeid}});
307 if (!testIter.value().is_array()) {
308 res.
addEntry(
"E10",
"Node doesn't have a location that is an array.",
309 {{
"Node ID", nodeid}});
313 if (testIter.value().size() != 2) {
314 res.
addEntry(
"E11",
"Node doesn't have a location that is an array of size 2.",
315 {{
"Node ID", nodeid}});
320 auto uuidNodeID = boost::uuids::string_generator()(nodeid);
322 createInside.
insertNode(std::move(nodeType), node[
"location"][0], node[
"location"][1],
324 }
catch (std::exception& e) {
325 res.
addEntry(
"E51",
"Invalid UUID string", {{
"string", nodeid}});
331 auto connIter = input.find(
"connections");
332 if (connIter == input.end() || !connIter->is_array()) {
333 res.
addEntry(
"E13",
"No connections array in function", {});
338 for (
auto& connection : input[
"connections"]) {
339 if (connection.find(
"type") == connection.end() ||
340 !connection.find(
"type")->is_string()) {
341 res.
addEntry(
"E14",
"No type string in connection", {{
"connectionid", connID}});
346 std::string type = connection[
"type"];
347 bool isData = type ==
"data";
349 if (!isData && type !=
"exec") {
350 res.
addEntry(
"E15",
"Unrecognized connection type",
351 {{
"connectionid", connID}, {
"Found Type", type}});
357 if (connection.find(
"input") == connection.end()) {
358 res.
addEntry(
"E16",
"No input element in connection", {{
"connectionid", connID}});
363 if (!connection.find(
"input")->is_array() || connection.find(
"input")->size() != 2 ||
364 !connection.find(
"input")->operator[](0).is_string() ||
365 !connection.find(
"input")->operator[](1).is_number_integer()) {
368 "Incorrect connection input format, must be an array of of a string (node id) " 369 "and int (connection id)",
370 {{
"connectionid", connID}, {
"Requested Type", *connection.find(
"input")}});
375 std::string InputNodeID = connection[
"input"][0];
377 boost::uuids::uuid InputNodeIDUUID;
379 InputNodeIDUUID = boost::uuids::string_generator()(InputNodeID);
380 }
catch (std::exception&) {
381 res.
addEntry(
"EUKN",
"Invalid UUID string in connection",
382 {{
"string", InputNodeID}});
387 int InputConnectionID = connection[
"input"][1];
389 if (connection.find(
"output") == connection.end()) {
390 res.
addEntry(
"E18",
"No output element in connection", {{
"connectionid", connID}});
395 if (!connection.find(
"output")->is_array() || connection.find(
"output")->size() != 2 ||
396 !connection.find(
"output")->operator[](0).is_string() ||
397 !connection.find(
"output")->operator[](1).is_number_integer()) {
400 "Incorrect connection output format, must be an array of a string (node id) " 401 "and int (connection id)",
402 {{
"connectionid", connID}, {
"Requested Type", *connection.find(
"output")}});
406 std::string OutputNodeID = connection[
"output"][0];
408 boost::uuids::uuid OutputNodeIDUUID;
410 OutputNodeIDUUID = boost::uuids::string_generator()(OutputNodeID);
411 }
catch (std::exception&) {
412 res.
addEntry(
"EUKN",
"Invalid UUID string in connection",
413 {{
"string", OutputNodeID}});
418 int OutputConnectionID = connection[
"output"][1];
421 if (createInside.
nodes().find(InputNodeIDUUID) == createInside.
nodes().end()) {
422 res.
addEntry(
"E20",
"Input node for connection doesn't exist",
423 {{
"connectionid", connID}, {
"Requested Node", InputNodeID}});
427 if (createInside.
nodes().find(OutputNodeIDUUID) == createInside.
nodes().end()) {
428 res.
addEntry(
"E21",
"Output node for connection doesn't exist",
429 {{
"connectionid", connID}, {
"Requested Node", OutputNodeID}});
437 res +=
connectData(*createInside.
nodes()[InputNodeIDUUID], InputConnectionID,
438 *createInside.
nodes()[OutputNodeIDUUID], OutputConnectionID);
440 res +=
connectExec(*createInside.
nodes()[InputNodeIDUUID], InputConnectionID,
441 *createInside.
nodes()[OutputNodeIDUUID], OutputConnectionID);
454 if (!input.is_array()) {
455 res.
addEntry(
"EUKN",
"Graph Struct json has to be an array", {{
"Given JSON", input}});
460 if (toFill !=
nullptr) { *toFill = createdStruct; }
462 for (
const auto& str : input) {
463 if (!str.is_object()) {
464 res.
addEntry(
"EUKN",
"Graph Struct entry must be an object", {{
"Given JSON", str}});
468 if (str.size() != 1) {
469 res.
addEntry(
"EUKN",
"Graph Struct entry must have size of 1", {{
"Size", str.size()}});
473 std::string docstring, qualifiedType;
477 std::string typeModuleName, typeName;
478 std::tie(typeModuleName, typeName) =
parseColonPair(qualifiedType);
483 if (!res) {
continue; }
485 createdStruct->addType(ty, docstring, createdStruct->types().size());
492 if (!
object.is_object()) {
return {}; }
494 auto iter =
object.begin();
495 if (iter ==
object.end()) {
return {}; }
497 std::string key = iter.key();
498 std::string val = iter.value();
502 if (iter !=
object.end()) {
return {}; }
Result jsonToGraphStruct(GraphModule &mod, boost::string_view name, const nlohmann::json &input, GraphStruct **toFill=nullptr)
Load a GraphStruct from json.
this is an AST-like representation of a function in a graph It is used for IDE-like behavior...
void addEntry(const char *ec, const char *overview, nlohmann::json data)
Add a entry to the result, either a warning or an error.
Result nodeTypeFromModule(const boost::filesystem::path &moduleName, boost::string_view typeName, const nlohmann::json &data, std::unique_ptr< NodeType > *toFill) noexcept
Gets a NodeType from the JSON and name.
A class holding a compound type defined in a GraphModule.
std::pair< std::string, std::string > parseColonPair(const std::string &in)
Parse a colonated pair Example: lang:i32 would turn into {lang, i32}.
Result insertNode(std::unique_ptr< NodeType > type, float x, float y, boost::uuids::uuid id=boost::uuids::random_generator()(), NodeInstance **toFill=nullptr)
Add a node to the graph.
Defines the Result class and related functions.
Context & context() const
Get the context.
boost::filesystem::path workspacePath() const
Get the workspace path of the Context.
void setDescription(std::string newDesc)
Set the description of the function.
Result jsonToGraphModule(Context &createInside, const nlohmann::json &input, const boost::filesystem::path &fullName, GraphModule **toFill=nullptr)
Load a GraphModule from json.
GraphFunction * getOrCreateFunction(std::string name, std::vector< NamedDataType > dataIns, std::vector< NamedDataType > dataOuts, std::vector< std::string > execIns, std::vector< std::string > execOuts, bool *inserted=nullptr)
Create a new function if it does't already exist.
std::string fullName() const
Get the full name of the module.
ScopedContext addScopedContext(const nlohmann::json &data)
Add a context with a scope Example usage: chi::Result res; res.contextJson(); // returns {} { aut...
The class that handles the loading, creation, storing, and compilation of modules It also stores a LL...
Result connectData(NodeInstance &lhs, size_t lhsConnID, NodeInstance &rhs, size_t rhsConnID)
Connects two nodes' data connections.
GraphStruct * getOrCreateStruct(std::string name, bool *inserted=nullptr)
Create a new struct in the module.
Result connectExec(NodeInstance &lhs, size_t lhsConnID, NodeInstance &rhs, size_t rhsConnID)
Connects two nodes' exec connections.
std::unordered_map< boost::uuids::uuid, std::unique_ptr< NodeInstance > > & nodes()
Get the nodes in the function Usually called by connectData or connectExec or GraphFunction.
Defines the NodeType class.
Result jsonToGraphFunction(GraphFunction &createInside, const nlohmann::json &input)
Load a GraphFunction–must already exist (use createGraphFunctionDeclarationFromJson) ...
Result typeFromModule(const boost::filesystem::path &module, boost::string_view name, DataType *toFill) noexcept
Gets a DataType from a module.
Module that holds graph functions.
Defines the GraphModule class.
The namespace where chigraph lives.
Context & context() const
Get the Context that this module belongs to.
Defines the Context class and related functions.
A type of data Loose wrapper around llvm::Type*, except it knows which ChiModule it's in and it embed...
GraphModule * newGraphModule(const boost::filesystem::path &fullName)
Create a new GraphModule with the given full name.
The result object, used for identifiying errors with good diagnostics.
std::pair< std::string, std::string > parseObjectPair(const nlohmann::json &object)
Parse something that looks like: {"hello": "there"} into {"hello", "there"}.
Declares the GraphFunction class.
NamedDataType getOrCreateLocalVariable(std::string name, DataType type, bool *inserted=nullptr)
Create a new local varaible in the module.
Defines the NodeInstance class and related functions.
Define deserialization functions.
Result createGraphFunctionDeclarationFromJson(GraphModule &createInside, const nlohmann::json &input, GraphFunction **toFill=nullptr)
Create a forward declaration of a function in a module with an empty graph.