From 07fff6435181154d77ae3235a844f2da20d61de6 Mon Sep 17 00:00:00 2001 From: Alexheeeee Date: Tue, 10 Feb 2026 02:26:09 -0500 Subject: [PATCH] inherits, repeats, and name changes --- README.md | 40 +- examples/yaml_reader.cpp | 67 ++- lattice_files/ex.pals.yaml | 7 +- lattice_files/include.pals.yaml | 6 +- src/yaml_c_wrapper.cpp | 857 ++++++++++++++++++-------------- src/yaml_c_wrapper.h | 90 ++-- tests/test_yaml_c_wrapper.cpp | 837 ++++++++++++++++--------------- 7 files changed, 999 insertions(+), 905 deletions(-) diff --git a/README.md b/README.md index 7b936e5..2062938 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,10 @@ ## Introduction `yaml_c_wrapper.cpp` wraps `YAML::Node` into C objects so they can be part of a shared object library to interface with other languages - +Implemented components of lattice expansion: +include +inherits +repeat ## Usage In pals-cpp, run @@ -66,6 +39,5 @@ To run a specific test, run ctest --test-dir build -R "Test Name" ``` -## Issue -`yaml-cpp`'s cmake only requires cmake version 3.4, which is deprecated. Warnings must -be suppressed to run properly +## To Do +add test cases for lattice expansion diff --git a/examples/yaml_reader.cpp b/examples/yaml_reader.cpp index 9c5333b..548097d 100644 --- a/examples/yaml_reader.cpp +++ b/examples/yaml_reader.cpp @@ -1,24 +1,38 @@ -#include "../src/yaml_c_wrapper.h" #include +#include "../src/yaml_c_wrapper.h" + +// If file name is provided as a command line argument, this will print out the +// expanded contents of the file to the terminal, as well as to expand.pals.yaml. +// Otherwise, it will use the example file ex.pals.yaml -// See ex.pals.yaml for the example lattice file and expand.pals.yaml for the output of this file. +int main(int argc, char* argv[]) { + if (argc != 1) { + char* filename = argv[1]; + std::string path = "../lattice_files/"; + path += filename; + YAMLNodeHandle handle = parse_file(path.c_str()); -int main() { + lattice_expand(handle); + std::cout << "Printing out contents of file: " << filename << std::endl; + std::cout << yaml_to_string(handle) << std::endl; + write_file(handle, "../lattice_files/expand.pals.yaml"); + return 0; + } // reading a lattice from a yaml file - // allow files to be read in through command line, print back out - YAMLNodeHandle handle = yaml_parse_file("../lattice_files/ex.pals.yaml"); - // print out file name that was read in + YAMLNodeHandle handle = parse_file("../lattice_files/ex.pals.yaml"); + std::cout << "Printing out contents of file: " << "ex.pals.yaml" << std::endl; // printing to terminal std::cout << yaml_to_string(handle) << std::endl << std::endl; // type checking // prints "handle is of type sequence: 1", 1 meaning true - std::cout << "handle is of type sequence: " << (yaml_is_sequence(handle)) << "\n"; + std::cout << "handle is of type sequence: " << (is_sequence(handle)) + << "\n"; // accessing sequence - YAMLNodeHandle node = yaml_get_index(handle, 0); + YAMLNodeHandle node = get_index(handle, 0); /* prints - the first element is: + the first element is: thingB: kind: Sextupole */ @@ -26,29 +40,32 @@ int main() { // accessing map // prints "the value at key 'thingB' is: kind: Sextupole" - std::cout << "\nthe value at key 'thingB' is: " << yaml_to_string(yaml_get_key(node, "thingB")) << "\n"; + std::cout << "\nthe value at key 'thingB' is: " + << yaml_to_string(get_key(node, "thingB")) << "\n"; - // creating a new node that's a map - YAMLNodeHandle map = yaml_create_map(); - yaml_set_int(map, "first", 1); + // creating a new node that's a map + YAMLNodeHandle map = create_map(); + set_value_int(map, "apples", 5); // creating a new node that's a sequence - YAMLNodeHandle sequence = yaml_create_sequence(); - yaml_push_string(sequence, "magnet1"); - yaml_push_string(sequence, ""); - YAMLNodeHandle scalar = yaml_create_scalar(); - yaml_set_scalar_string(scalar, "magnet2"); - yaml_set_at_index(sequence, 1, scalar); + YAMLNodeHandle sequence = create_sequence(); + push_string(sequence, "magnet1"); + push_string(sequence, ""); + YAMLNodeHandle scalar = create_scalar(); + set_scalar_string(scalar, "magnet2"); + set_at_index(sequence, 1, scalar); // give sequence a name by putting it in a map: - YAMLNodeHandle magnets = yaml_create_map(); - yaml_set_node(magnets, "magnets", sequence); + YAMLNodeHandle magnets = create_map(); + set_value_node(magnets, "magnets", sequence); // adding new nodes to lattice - yaml_push_node(handle, map); - yaml_push_node(handle, magnets); + push_node(handle, map); + push_node(handle, magnets); - yaml_expand(handle); + // performing lattice expansion + lattice_expand(handle); // writing modified lattice file to expand.pals.yaml - yaml_write_file(handle, "../lattice_files/expand.pals.yaml"); + write_file(handle, "../lattice_files/expand.pals.yaml"); + return 0; } diff --git a/lattice_files/ex.pals.yaml b/lattice_files/ex.pals.yaml index 1261101..644df78 100644 --- a/lattice_files/ex.pals.yaml +++ b/lattice_files/ex.pals.yaml @@ -1,6 +1,5 @@ - thingB: kind: Sextupole - - inj_line: kind: BeamLine multipass: true @@ -16,3 +15,9 @@ - a_subline: # Item a_subline is repeated three times repeat: 3 - include: "include.pals.yaml" +- a_subline: + kind: BeamLine + line: + - a + - b + - c \ No newline at end of file diff --git a/lattice_files/include.pals.yaml b/lattice_files/include.pals.yaml index 84ec631..b9317a2 100644 --- a/lattice_files/include.pals.yaml +++ b/lattice_files/include.pals.yaml @@ -1,4 +1,4 @@ - line: - first: 1 - second: 2 - thrid: 3 \ No newline at end of file + - first: 1 + - second: 2 + - third: 3 \ No newline at end of file diff --git a/src/yaml_c_wrapper.cpp b/src/yaml_c_wrapper.cpp index 5047716..35f310a 100644 --- a/src/yaml_c_wrapper.cpp +++ b/src/yaml_c_wrapper.cpp @@ -1,45 +1,119 @@ #include -#include #include #include +#include +#include #if defined(_WIN32) - #define YAML_API extern "C" __declspec(dllexport) +#define YAML_API extern "C" __declspec(dllexport) #else - #define YAML_API extern "C" __attribute__((visibility("default"))) +#define YAML_API extern "C" __attribute__((visibility("default"))) #endif // ======= LATTICE EXPANSION UTILS -// === REPLACE === -YAML::Node replace_internal(YAML::Node name, std::map* seen) { - std::string str = name.as(); - if (seen->count(str)) { - return YAML::Clone(seen->at(str)); - } else { - return name; +/* +Inserts the elements in `line` into `seq` at `index` a `repeat` number of times. +The value at index will be rewritten by the first inserted element. For example, +if seq = [1,2,3,4,5], line = [a,b], index = 2, repeat = 3, calling the function +will output [1,2,a,b,a,b,a,b,4,5]. +*/ +YAML::Node repeat(YAML::Node line, YAML::Node seq, int index, int repeat) { + YAML::Node exp = YAML::Node(YAML::NodeType::Sequence); + for (int i = 0; i < index; i++) { + exp.push_back(YAML::Clone(seq[i])); + } + for (int i = 0; i < repeat; i++) { + for (int j = 0; j < line.size(); j++) { + exp.push_back(YAML::Clone(line[j])); + } } + for (int i = index + 1; i < seq.size(); i++) { + exp.push_back(YAML::Clone(seq[i])); + } + return exp; +} + +// recursively loops through the node to record all the elements and their +// corresponding parameters +void get_dict_helper(YAML::Node node, std::map* seen) { + if (node.IsSequence()) { + for (int i = 0; i < node.size(); i++) { + get_dict_helper(node[i], seen); + } + } else if (node.IsMap()) { + for (auto ele : node) { + // exclude key words from being stored + if (ele.first.as() == "include" || + ele.first.as() == "inherit" || + (ele.second.IsMap() && ele.second["repeat"])) { + continue; + } + seen->insert( + {ele.first.as(), YAML::Clone(ele.second)}); + get_dict_helper(ele.second, seen); + } + } +} + +std::map* get_dict(YAML::Node root) { + std::map* seen = + new std::map(); + ; + get_dict_helper(root, seen); + return seen; } // === EXPAND === -YAML::Node expand_internal(YAML::Node node, std::map* seen) { +YAML::Node expand_internal(YAML::Node node, + std::map* seen) { if (node.IsSequence()) { + bool modified = true; + while (modified) { + modified = false; + for (int i = 0; i < node.size(); i++) { + if (node[i].IsMap()) { + for (auto ele : node[i]) { + if (ele.second.IsMap() && ele.second["repeat"]) { + YAML::Node line = + (*seen)[ele.first.as()]["line"]; + node = repeat(line, node, i, + ele.second["repeat"].as()); + modified = true; + break; + } + } + if (modified) break; + } + } + } for (int i = 0; i < node.size(); i++) { node[i] = expand_internal(node[i], seen); } return node; - } else if (node.IsScalar()) { - return replace_internal(node, seen); } else if (node.IsMap()) { for (auto ele : node) { // will probably need to add better method of finding files if (ele.first.as() == "include") { - std::string str = ele.second.as(); - std::string filename = str.substr(0, str.length()); - node = YAML::LoadFile("../lattice_files/" + filename); + std::string filename = ele.second.as(); + YAML::Node seq = YAML::Node(YAML::NodeType::Sequence); + YAML::Node file = YAML::Node(YAML::NodeType::Map); + file["file"] = filename; + seq.push_back(file); + seq.push_back( + YAML::LoadFile("../lattice_files/" + filename)[0]); + + ele.first = "included"; + ele.second = seq; break; + } else if (ele.first.as() == "inherit") { + YAML::Node parent = (*seen)[ele.second.as()]; + for (auto ele : parent) { + node[ele.first.as()] = ele.second; + } + ele.first = "inherited"; } - seen->insert({ele.first.as(), ele.second}); - node[ele.first.as()] = expand_internal(ele.second, seen); + node[ele.first.as()] = + expand_internal(ele.second, seen); } return node; } else { @@ -48,398 +122,423 @@ YAML::Node expand_internal(YAML::Node node, std::map* s } extern "C" { - YAML_API typedef void* YAMLNodeHandle; - - // === CREATION/DELETION === - YAML_API YAMLNodeHandle yaml_create_node() { - return new YAML::Node(); - } - - YAML_API YAMLNodeHandle yaml_create_map() { - auto node = new YAML::Node(); - *node = YAML::Node(YAML::NodeType::Map); - return node; - } - - YAML_API YAMLNodeHandle yaml_create_sequence() { - auto node = new YAML::Node(); - *node = YAML::Node(YAML::NodeType::Sequence); - return node; +typedef void* YAMLNodeHandle; + +// === CREATION/DELETION === +YAML_API YAMLNodeHandle create_node() { return new YAML::Node(); } + +YAML_API YAMLNodeHandle create_map() { + auto node = new YAML::Node(); + *node = YAML::Node(YAML::NodeType::Map); + return node; +} + +YAML_API YAMLNodeHandle create_sequence() { + auto node = new YAML::Node(); + *node = YAML::Node(YAML::NodeType::Sequence); + return node; +} + +YAML_API YAMLNodeHandle create_scalar() { + auto node = new YAML::Node(); + *node = YAML::Node(YAML::NodeType::Scalar); + return node; +} + +YAML_API void delete_node(YAMLNodeHandle handle) { + delete static_cast(handle); +} + +// === PARSING === +YAML_API YAMLNodeHandle parse_string(const char* yaml_str) { + try { + return new YAML::Node(YAML::Load(yaml_str)); + } catch (...) { + return nullptr; } - - YAML_API YAMLNodeHandle yaml_create_scalar() { - auto node = new YAML::Node(); - *node = YAML::Node(YAML::NodeType::Scalar); - return node; +} + +YAML_API YAMLNodeHandle parse_file(const char* filename) { + try { + return new YAML::Node(YAML::LoadFile(filename)); + } catch (...) { + return nullptr; } +} - YAML_API void yaml_delete_node(YAMLNodeHandle handle) { - delete static_cast(handle); +// === TYPE CHECKS === +YAML_API bool is_scalar(YAMLNodeHandle handle) { + return static_cast(handle)->IsScalar(); +} + +YAML_API bool is_sequence(YAMLNodeHandle handle) { + return static_cast(handle)->IsSequence(); +} + +YAML_API bool is_map(YAMLNodeHandle handle) { + return static_cast(handle)->IsMap(); +} + +YAML_API bool is_null(YAMLNodeHandle handle) { + return static_cast(handle)->IsNull(); +} + +// === ACCESS === +// equivalent to map[key] +YAML_API YAMLNodeHandle get_key(YAMLNodeHandle handle, const char* key) { + auto node = static_cast(handle); + auto child = (*node)[key]; + if (!child.IsDefined()) { + return nullptr; + } + return new YAML::Node(child); +} + +YAML_API YAMLNodeHandle get_index(YAMLNodeHandle handle, int index) { + auto node = static_cast(handle); + if (index < 0 || index >= node->size()) { + return nullptr; } - - // === PARSING === - YAML_API YAMLNodeHandle yaml_parse(const char* yaml_str) { - try { - return new YAML::Node(YAML::Load(yaml_str)); - } catch (...) { - return nullptr; - } + return new YAML::Node((*node)[index]); +} + +YAML_API bool has_key(YAMLNodeHandle handle, const char* key) { + auto node = static_cast(handle); + return (*node)[key].IsDefined(); +} + +YAML_API int size(YAMLNodeHandle handle) { + return static_cast(handle)->size(); +} + +YAML_API char** get_keys(YAMLNodeHandle handle, int* out_count) { + auto node = static_cast(handle); + if (!node->IsMap()) { + *out_count = 0; + return nullptr; } - - YAML_API YAMLNodeHandle yaml_parse_file(const char* filename) { - try { - return new YAML::Node(YAML::LoadFile(filename)); - } catch (...) { - return nullptr; - } + + std::vector keys; + for (auto it = node->begin(); it != node->end(); ++it) { + keys.push_back(it->first.as()); } - - // === TYPE CHECKS === - YAML_API bool yaml_is_scalar(YAMLNodeHandle handle) { - return static_cast(handle)->IsScalar(); + + *out_count = keys.size(); + char** result = new char*[keys.size()]; + for (size_t i = 0; i < keys.size(); i++) { + result[i] = new char[keys[i].length() + 1]; + strcpy(result[i], keys[i].c_str()); } - - YAML_API bool yaml_is_sequence(YAMLNodeHandle handle) { - return static_cast(handle)->IsSequence(); + return result; +} + +// === CONVERT TO C TYPES (caller must free returned strings) === +YAML_API char* as_string(YAMLNodeHandle handle) { + try { + auto str = static_cast(handle)->as(); + char* result = new char[str.length() + 1]; + strcpy(result, str.c_str()); + return result; + } catch (...) { + return nullptr; } - - YAML_API bool yaml_is_map(YAMLNodeHandle handle) { - return static_cast(handle)->IsMap(); +} + +YAML_API int as_int(YAMLNodeHandle handle) { + try { + return static_cast(handle)->as(); + } catch (...) { + return 0; } - - YAML_API bool yaml_is_null(YAMLNodeHandle handle) { - return static_cast(handle)->IsNull(); +} + +YAML_API double as_float(YAMLNodeHandle handle) { + try { + return static_cast(handle)->as(); + } catch (...) { + return 0.0; } - - // === ACCESS === - YAML_API YAMLNodeHandle yaml_get_key(YAMLNodeHandle handle, const char* key) { - auto node = static_cast(handle); - auto child = (*node)[key]; - if (!child.IsDefined()) { - return nullptr; - } - return new YAML::Node(child); +} + +YAML_API bool as_bool(YAMLNodeHandle handle) { + try { + return static_cast(handle)->as(); + } catch (...) { + return false; } - - YAML_API YAMLNodeHandle yaml_get_index(YAMLNodeHandle handle, int index) { +} + +// === MODIFICATION === +YAML_API void set_value_string(YAMLNodeHandle handle, const char* key, + const char* value) { + auto node = static_cast(handle); + (*node)[key] = value; +} + +YAML_API void set_value_int(YAMLNodeHandle handle, const char* key, int value) { + auto node = static_cast(handle); + (*node)[key] = value; +} + +YAML_API void set_value_float(YAMLNodeHandle handle, const char* key, + double value) { + auto node = static_cast(handle); + (*node)[key] = value; +} + +YAML_API void set_value_bool(YAMLNodeHandle handle, const char* key, + bool value) { + auto node = static_cast(handle); + (*node)[key] = value; +} + +YAML_API void set_value_node(YAMLNodeHandle handle, const char* key, + YAMLNodeHandle value) { + auto node = static_cast(handle); + auto val_node = static_cast(value); + (*node)[key] = *val_node; +} + +YAML_API void set_scalar_string(YAMLNodeHandle handle, const char* value) { + if (handle == nullptr || value == nullptr) return; + auto node = static_cast(handle); + *node = value; +} + +YAML_API void set_scalar_int(YAMLNodeHandle handle, int value) { + if (handle == nullptr) return; + auto node = static_cast(handle); + *node = value; +} + +YAML_API void set_scalar_float(YAMLNodeHandle handle, double value) { + if (handle == nullptr) return; + auto node = static_cast(handle); + *node = value; +} + +YAML_API void set_scalar_bool(YAMLNodeHandle handle, bool value) { + if (handle == nullptr) return; + auto node = static_cast(handle); + *node = value; +} + +// Set node at index for sequences +YAML_API void set_at_index(YAMLNodeHandle handle, int index, + YAMLNodeHandle value) { + auto node = static_cast(handle); + auto val_node = static_cast(value); + (*node)[index] = *val_node; +} + +YAML_API void push_string(YAMLNodeHandle handle, const char* value) { + auto node = static_cast(handle); + node->push_back(value); +} + +YAML_API void push_int(YAMLNodeHandle handle, int value) { + auto node = static_cast(handle); + node->push_back(value); +} + +YAML_API void push_float(YAMLNodeHandle handle, double value) { + auto node = static_cast(handle); + node->push_back(value); +} + +YAML_API void push_node(YAMLNodeHandle handle, YAMLNodeHandle value) { + auto node = static_cast(handle); + auto val_node = static_cast(value); + node->push_back(*val_node); +} + +// === WRITE TO FILE WITH EMITTER === + +YAML_API bool write_file(YAMLNodeHandle handle, const char* filename) { + try { auto node = static_cast(handle); - if (index < 0 || index >= node->size()) { - return nullptr; + + std::ofstream fout(filename); + if (!fout.is_open()) { + return false; } - return new YAML::Node((*node)[index]); - } - - YAML_API bool yaml_has_key(YAMLNodeHandle handle, const char* key) { - auto node = static_cast(handle); - return (*node)[key].IsDefined(); - } - - YAML_API int yaml_size(YAMLNodeHandle handle) { - return static_cast(handle)->size(); + + YAML::Emitter out; + out << *node; + + fout << out.c_str(); + fout.close(); + return true; + } catch (...) { + return false; } +} - YAML_API char** yaml_get_keys(YAMLNodeHandle handle, int* out_count) { +// Write with emitter control (removed SetWrap) +YAML_API bool write_file_formatted(YAMLNodeHandle handle, const char* filename, + int indent, bool flow_maps, bool flow_seqs) { + try { auto node = static_cast(handle); - if (!node->IsMap()) { - *out_count = 0; - return nullptr; - } - - std::vector keys; - for (auto it = node->begin(); it != node->end(); ++it) { - keys.push_back(it->first.as()); - } - - *out_count = keys.size(); - char** result = new char*[keys.size()]; - for (size_t i = 0; i < keys.size(); i++) { - result[i] = new char[keys[i].length() + 1]; - strcpy(result[i], keys[i].c_str()); - } - return result; - } - - // === CONVERT TO C TYPES (caller must free returned strings) === - YAML_API char* yaml_as_string(YAMLNodeHandle handle) { - try { - auto str = static_cast(handle)->as(); - char* result = new char[str.length() + 1]; - strcpy(result, str.c_str()); - return result; - } catch (...) { - return nullptr; - } - } - - YAML_API int yaml_as_int(YAMLNodeHandle handle) { - try { - return static_cast(handle)->as(); - } catch (...) { - return 0; - } - } - - YAML_API double yaml_as_float(YAMLNodeHandle handle) { - try { - return static_cast(handle)->as(); - } catch (...) { - return 0.0; - } - } - - YAML_API bool yaml_as_bool(YAMLNodeHandle handle) { - try { - return static_cast(handle)->as(); - } catch (...) { + + std::ofstream fout(filename); + if (!fout.is_open()) { return false; } - } - - // === MODIFICATION === - YAML_API void yaml_set_string(YAMLNodeHandle handle, const char* key, const char* value) { - auto node = static_cast(handle); - (*node)[key] = value; - } - - YAML_API void yaml_set_int(YAMLNodeHandle handle, const char* key, int value) { - auto node = static_cast(handle); - (*node)[key] = value; - } - - YAML_API void yaml_set_float(YAMLNodeHandle handle, const char* key, double value) { - auto node = static_cast(handle); - (*node)[key] = value; - } - - YAML_API void yaml_set_bool(YAMLNodeHandle handle, const char* key, bool value) { - auto node = static_cast(handle); - (*node)[key] = value; - } - - YAML_API void yaml_set_node(YAMLNodeHandle handle, const char* key, YAMLNodeHandle value) { - auto node = static_cast(handle); - auto val_node = static_cast(value); - (*node)[key] = *val_node; - } - YAML_API void yaml_set_scalar_string(YAMLNodeHandle handle, const char* value) { - if (handle == nullptr || value == nullptr) return; - auto node = static_cast(handle); - *node = value; - } - - YAML_API void yaml_set_scalar_int(YAMLNodeHandle handle, int value) { - if (handle == nullptr) return; - auto node = static_cast(handle); - *node = value; - } - - YAML_API void yaml_set_scalar_float(YAMLNodeHandle handle, double value) { - if (handle == nullptr) return; - auto node = static_cast(handle); - *node = value; - } - - YAML_API void yaml_set_scalar_bool(YAMLNodeHandle handle, bool value) { - if (handle == nullptr) return; - auto node = static_cast(handle); - *node = value; - } - - // Set node at index for sequences - YAML_API void yaml_set_at_index(YAMLNodeHandle handle, int index, YAMLNodeHandle value) { - auto node = static_cast(handle); - auto val_node = static_cast(value); - (*node)[index] = *val_node; - } - - YAML_API void yaml_push_string(YAMLNodeHandle handle, const char* value) { - auto node = static_cast(handle); - node->push_back(value); - } - - YAML_API void yaml_push_int(YAMLNodeHandle handle, int value) { - auto node = static_cast(handle); - node->push_back(value); + YAML::Emitter out; + + // Set formatting options (only valid ones) + out.SetIndent(indent); + out.SetMapFormat(flow_maps ? YAML::Flow : YAML::Block); + out.SetSeqFormat(flow_seqs ? YAML::Flow : YAML::Block); + out.SetBoolFormat(YAML::TrueFalseBool); // true/false instead of yes/no + out.SetNullFormat(YAML::LowerNull); // null instead of ~ + out.SetStringFormat(YAML::Auto); // Auto-detect if quotes needed + + out << *node; + + fout << out.c_str(); + fout.close(); + return true; + } catch (...) { + return false; } - - YAML_API void yaml_push_float(YAMLNodeHandle handle, double value) { +} + +// Get YAML string with emitter +YAML_API char* yaml_emit(YAMLNodeHandle handle, int indent) { + try { auto node = static_cast(handle); - node->push_back(value); + + YAML::Emitter out; + out.SetIndent(indent); + out.SetBoolFormat(YAML::TrueFalseBool); + out.SetNullFormat(YAML::LowerNull); + out << *node; + + std::string str = out.c_str(); + char* result = new char[str.length() + 1]; + strcpy(result, str.c_str()); + return result; + } catch (...) { + return nullptr; } - - YAML_API void yaml_push_node(YAMLNodeHandle handle, YAMLNodeHandle value) { +} + +// Advanced version with all available options +YAML_API bool write_file_advanced( + YAMLNodeHandle handle, const char* filename, int indent, bool flow_maps, + bool flow_seqs, + int bool_format, // 0=YesNo, 1=TrueFalse, 2=OnOff + int null_format, // 0=Tilde (~), 1=Null (null), 2=NULL, 3=Null + int string_format) { // 0=Auto, 1=SingleQuoted, 2=DoubleQuoted, 3=Literal + try { auto node = static_cast(handle); - auto val_node = static_cast(value); - node->push_back(*val_node); - } - // === WRITE TO FILE WITH EMITTER === - - YAML_API bool yaml_write_file(YAMLNodeHandle handle, const char* filename) { - try { - auto node = static_cast(handle); - - std::ofstream fout(filename); - if (!fout.is_open()) { - return false; - } - - YAML::Emitter out; - out << *node; - - fout << out.c_str(); - fout.close(); - return true; - } catch (...) { + std::ofstream fout(filename); + if (!fout.is_open()) { return false; } - } - - // Write with emitter control (removed SetWrap) - YAML_API bool yaml_write_file_formatted(YAMLNodeHandle handle, const char* filename, - int indent, bool flow_maps, bool flow_seqs) { - try { - auto node = static_cast(handle); - - std::ofstream fout(filename); - if (!fout.is_open()) { - return false; - } - - YAML::Emitter out; - - // Set formatting options (only valid ones) - out.SetIndent(indent); - out.SetMapFormat(flow_maps ? YAML::Flow : YAML::Block); - out.SetSeqFormat(flow_seqs ? YAML::Flow : YAML::Block); - out.SetBoolFormat(YAML::TrueFalseBool); // true/false instead of yes/no - out.SetNullFormat(YAML::LowerNull); // null instead of ~ - out.SetStringFormat(YAML::Auto); // Auto-detect if quotes needed - - out << *node; - - fout << out.c_str(); - fout.close(); - return true; - } catch (...) { - return false; - } - } - - // Get YAML string with emitter - YAML_API char* yaml_emit(YAMLNodeHandle handle, int indent) { - try { - auto node = static_cast(handle); - - YAML::Emitter out; - out.SetIndent(indent); - out.SetBoolFormat(YAML::TrueFalseBool); - out.SetNullFormat(YAML::LowerNull); - out << *node; - - std::string str = out.c_str(); - char* result = new char[str.length() + 1]; - strcpy(result, str.c_str()); - return result; - } catch (...) { - return nullptr; - } - } - - // Advanced version with all available options - YAML_API bool yaml_write_file_advanced(YAMLNodeHandle handle, const char* filename, - int indent, - bool flow_maps, - bool flow_seqs, - int bool_format, // 0=YesNo, 1=TrueFalse, 2=OnOff - int null_format, // 0=Tilde (~), 1=Null (null), 2=NULL, 3=Null - int string_format) { // 0=Auto, 1=SingleQuoted, 2=DoubleQuoted, 3=Literal - try { - auto node = static_cast(handle); - - std::ofstream fout(filename); - if (!fout.is_open()) { - return false; - } - - YAML::Emitter out; - out.SetIndent(indent); - out.SetMapFormat(flow_maps ? YAML::Flow : YAML::Block); - out.SetSeqFormat(flow_seqs ? YAML::Flow : YAML::Block); - - // Boolean format - switch(bool_format) { - case 0: out.SetBoolFormat(YAML::YesNoBool); break; - case 1: out.SetBoolFormat(YAML::TrueFalseBool); break; - case 2: out.SetBoolFormat(YAML::OnOffBool); break; - default: out.SetBoolFormat(YAML::TrueFalseBool); - } - - // Null format - switch(null_format) { - case 0: out.SetNullFormat(YAML::TildeNull); break; // ~ - case 1: out.SetNullFormat(YAML::LowerNull); break; // null - case 2: out.SetNullFormat(YAML::UpperNull); break; // NULL - case 3: out.SetNullFormat(YAML::CamelNull); break; // Null - default: out.SetNullFormat(YAML::LowerNull); - } - - // String format - switch(string_format) { - case 0: out.SetStringFormat(YAML::Auto); break; - case 1: out.SetStringFormat(YAML::SingleQuoted); break; - case 2: out.SetStringFormat(YAML::DoubleQuoted); break; - case 3: out.SetStringFormat(YAML::Literal); break; - default: out.SetStringFormat(YAML::Auto); - } - - out << *node; - - fout << out.c_str(); - fout.close(); - return true; - } catch (...) { - return false; + + YAML::Emitter out; + out.SetIndent(indent); + out.SetMapFormat(flow_maps ? YAML::Flow : YAML::Block); + out.SetSeqFormat(flow_seqs ? YAML::Flow : YAML::Block); + + // Boolean format + switch (bool_format) { + case 0: + out.SetBoolFormat(YAML::YesNoBool); + break; + case 1: + out.SetBoolFormat(YAML::TrueFalseBool); + break; + case 2: + out.SetBoolFormat(YAML::OnOffBool); + break; + default: + out.SetBoolFormat(YAML::TrueFalseBool); } - } - - // === UTILITY === - YAML_API char* yaml_to_string(YAMLNodeHandle handle) { - try { - YAML::Emitter out; - out << *static_cast(handle); - std::string str = out.c_str(); - char* result = new char[str.length() + 1]; - strcpy(result, str.c_str()); - return result; - } catch (...) { - return nullptr; + + // Null format + switch (null_format) { + case 0: + out.SetNullFormat(YAML::TildeNull); + break; // ~ + case 1: + out.SetNullFormat(YAML::LowerNull); + break; // null + case 2: + out.SetNullFormat(YAML::UpperNull); + break; // NULL + case 3: + out.SetNullFormat(YAML::CamelNull); + break; // Null + default: + out.SetNullFormat(YAML::LowerNull); } - } - - // Helper to free strings allocated by this library - YAML_API void yaml_free_string(char* str) { - delete[] str; - } - YAML_API void yaml_free_keys(char** keys, int count) { - for (int i = 0; i < count; i++) { - delete[] keys[i]; + // String format + switch (string_format) { + case 0: + out.SetStringFormat(YAML::Auto); + break; + case 1: + out.SetStringFormat(YAML::SingleQuoted); + break; + case 2: + out.SetStringFormat(YAML::DoubleQuoted); + break; + case 3: + out.SetStringFormat(YAML::Literal); + break; + default: + out.SetStringFormat(YAML::Auto); } - delete[] keys; + + out << *node; + + fout << out.c_str(); + fout.close(); + return true; + } catch (...) { + return false; } - - - YAML_API YAMLNodeHandle yaml_clone(YAMLNodeHandle handle) { - return new YAML::Node(YAML::Clone(*static_cast(handle))); +} + +// === UTILITY === +YAML_API char* yaml_to_string(YAMLNodeHandle handle) { + try { + YAML::Emitter out; + out << *static_cast(handle); + std::string str = out.c_str(); + char* result = new char[str.length() + 1]; + strcpy(result, str.c_str()); + return result; + } catch (...) { + return nullptr; } - - // C interface for expand - handles the map internally - YAML_API YAMLNodeHandle yaml_expand(YAMLNodeHandle handle) { - auto node = static_cast(handle); - std::map seen; - YAML::Node result = expand_internal(*node, &seen); - return new YAML::Node(result); +} + +// Helper to free strings allocated by this library +YAML_API void yaml_free_string(char* str) { delete[] str; } + +YAML_API void yaml_free_keys(char** keys, int count) { + for (int i = 0; i < count; i++) { + delete[] keys[i]; } + delete[] keys; +} + +YAML_API YAMLNodeHandle yaml_clone(YAMLNodeHandle handle) { + return new YAML::Node(YAML::Clone(*static_cast(handle))); +} + +// C interface for expand - handles the map internally +YAML_API YAMLNodeHandle lattice_expand(YAMLNodeHandle handle) { + auto node = static_cast(handle); + std::map* seen = get_dict(*node); + YAML::Node result = expand_internal(*node, seen); + return new YAML::Node(result); +} } \ No newline at end of file diff --git a/src/yaml_c_wrapper.h b/src/yaml_c_wrapper.h index 319a9cb..40e7318 100644 --- a/src/yaml_c_wrapper.h +++ b/src/yaml_c_wrapper.h @@ -10,70 +10,72 @@ extern "C" { typedef void* YAMLNodeHandle; // === CREATION === -YAMLNodeHandle yaml_create_node(void); -YAMLNodeHandle yaml_create_map(void); -YAMLNodeHandle yaml_create_sequence(void); -YAMLNodeHandle yaml_create_scalar(); -void yaml_delete_node(YAMLNodeHandle handle); +YAMLNodeHandle create_node(void); +YAMLNodeHandle create_map(void); +YAMLNodeHandle create_sequence(void); +YAMLNodeHandle create_scalar(); +void delete_node(YAMLNodeHandle handle); // === PARSING === -YAMLNodeHandle yaml_parse(const char* yaml_str); -YAMLNodeHandle yaml_parse_file(const char* filename); +YAMLNodeHandle parse_string(const char* yaml_str); +YAMLNodeHandle parse_file(const char* filename); // === TYPE CHECKING === -bool yaml_is_scalar(YAMLNodeHandle handle); -bool yaml_is_sequence(YAMLNodeHandle handle); -bool yaml_is_map(YAMLNodeHandle handle); -bool yaml_is_null(YAMLNodeHandle handle); +bool is_scalar(YAMLNodeHandle handle); +bool is_sequence(YAMLNodeHandle handle); +bool is_map(YAMLNodeHandle handle); +bool is_null(YAMLNodeHandle handle); // === ACCESS === -YAMLNodeHandle yaml_get_key(YAMLNodeHandle handle, const char* key); -YAMLNodeHandle yaml_get_index(YAMLNodeHandle handle, int index); -bool yaml_has_key(YAMLNodeHandle handle, const char* key); -int yaml_size(YAMLNodeHandle handle); +YAMLNodeHandle get_key(YAMLNodeHandle handle, const char* key); +YAMLNodeHandle get_index(YAMLNodeHandle handle, int index); +bool has_key(YAMLNodeHandle handle, const char* key); +int size(YAMLNodeHandle handle); +char** get_keys(YAMLNodeHandle handle, int* out_count); +void yaml_free_keys(char** keys, int count); // === CONVERSION === -char* yaml_as_string(YAMLNodeHandle handle); -int yaml_as_int(YAMLNodeHandle handle); -double yaml_as_float(YAMLNodeHandle handle); -bool yaml_as_bool(YAMLNodeHandle handle); +char* as_string(YAMLNodeHandle handle); +int as_int(YAMLNodeHandle handle); +double as_float(YAMLNodeHandle handle); +bool as_bool(YAMLNodeHandle handle); void yaml_free_string(char* str); // === MODIFICATION === -void yaml_set_string(YAMLNodeHandle handle, const char* key, const char* value); -void yaml_set_int(YAMLNodeHandle handle, const char* key, int value); -void yaml_set_float(YAMLNodeHandle handle, const char* key, double value); -void yaml_set_bool(YAMLNodeHandle handle, const char* key, bool value); -void yaml_set_node(YAMLNodeHandle handle, const char* key, YAMLNodeHandle value); - -void yaml_set_scalar_string(YAMLNodeHandle handle, const char* value); -void yaml_set_scalar_int(YAMLNodeHandle handle, int value); -void yaml_set_scalar_float(YAMLNodeHandle handle, double value); -void yaml_set_scalar_bool(YAMLNodeHandle handle, bool value); - -void yaml_set_at_index(YAMLNodeHandle handle, int index, YAMLNodeHandle value) ; -void yaml_push_string(YAMLNodeHandle handle, const char* value); -void yaml_push_int(YAMLNodeHandle handle, int value); -void yaml_push_float(YAMLNodeHandle handle, double value); +void set_value_string(YAMLNodeHandle handle, const char* key, + const char* value); +void set_value_int(YAMLNodeHandle handle, const char* key, int value); +void set_value_float(YAMLNodeHandle handle, const char* key, double value); +void set_value_bool(YAMLNodeHandle handle, const char* key, bool value); +void set_value_node(YAMLNodeHandle handle, const char* key, + YAMLNodeHandle value); + +void set_scalar_string(YAMLNodeHandle handle, const char* value); +void set_scalar_int(YAMLNodeHandle handle, int value); +void set_scalar_float(YAMLNodeHandle handle, double value); +void set_scalar_bool(YAMLNodeHandle handle, bool value); + +void set_at_index(YAMLNodeHandle handle, int index, YAMLNodeHandle value); +void push_string(YAMLNodeHandle handle, const char* value); +void push_int(YAMLNodeHandle handle, int value); +void push_float(YAMLNodeHandle handle, double value); void yaml_push_bool(YAMLNodeHandle handle, bool value); -void yaml_push_node(YAMLNodeHandle handle, YAMLNodeHandle value); +void push_node(YAMLNodeHandle handle, YAMLNodeHandle value); // === UTILITY === char* yaml_to_string(YAMLNodeHandle handle); char* yaml_emit(YAMLNodeHandle handle, int indent); YAMLNodeHandle yaml_clone(YAMLNodeHandle handle); -YAMLNodeHandle yaml_expand(YAMLNodeHandle handle); +YAMLNodeHandle lattice_expand(YAMLNodeHandle handle); -bool yaml_write_file(YAMLNodeHandle handle, const char* filename); -bool yaml_write_file_formatted(YAMLNodeHandle handle, const char* filename, - int indent, bool flow_maps, bool flow_seqs); - -// === KEY UTILITIES === -char** yaml_get_keys(YAMLNodeHandle handle, int* out_count); -void yaml_free_keys(char** keys, int count); +bool write_file(YAMLNodeHandle handle, const char* filename); +bool write_file_formatted(YAMLNodeHandle handle, const char* filename, + int indent, bool flow_maps, bool flow_seqs); +bool write_file_advanced(YAMLNodeHandle handle, const char* filename, int indent, bool flow_maps, + bool flow_seqs, int bool_format, int null_format, int string_format); #ifdef __cplusplus } #endif -#endif // YAML_C_WRAPPER_H \ No newline at end of file +#endif // YAML_C_WRAPPER_H \ No newline at end of file diff --git a/tests/test_yaml_c_wrapper.cpp b/tests/test_yaml_c_wrapper.cpp index e3e54e9..2b8b669 100644 --- a/tests/test_yaml_c_wrapper.cpp +++ b/tests/test_yaml_c_wrapper.cpp @@ -1,10 +1,11 @@ #define CATCH_CONFIG_MAIN -#include #include -#include "../src/yaml_c_wrapper.h" +#include +#include #include #include -#include + +#include "../src/yaml_c_wrapper.h" using Catch::Approx; @@ -34,30 +35,30 @@ void cleanup_file(const std::string& filename) { TEST_CASE("YAML nodes can be created and deleted", "[creation]") { SECTION("Create empty node") { - YAMLNodeHandle node = yaml_create_node(); + YAMLNodeHandle node = create_node(); REQUIRE(node != nullptr); - yaml_delete_node(node); + delete_node(node); } - + SECTION("Create map node") { - YAMLNodeHandle map = yaml_create_map(); + YAMLNodeHandle map = create_map(); REQUIRE(map != nullptr); - REQUIRE(yaml_is_map(map)); - yaml_delete_node(map); + REQUIRE(is_map(map)); + delete_node(map); } - + SECTION("Create sequence node") { - YAMLNodeHandle seq = yaml_create_sequence(); + YAMLNodeHandle seq = create_sequence(); REQUIRE(seq != nullptr); - REQUIRE(yaml_is_sequence(seq)); - yaml_delete_node(seq); + REQUIRE(is_sequence(seq)); + delete_node(seq); } - + SECTION("Create scalar node") { - YAMLNodeHandle scalar = yaml_create_scalar(); + YAMLNodeHandle scalar = create_scalar(); REQUIRE(scalar != nullptr); - REQUIRE(yaml_is_scalar(scalar)); - yaml_delete_node(scalar); + REQUIRE(is_scalar(scalar)); + delete_node(scalar); } } @@ -68,47 +69,47 @@ TEST_CASE("YAML nodes can be created and deleted", "[creation]") { TEST_CASE("YAML can be parsed from strings", "[parsing]") { SECTION("Parse simple map") { const char* yaml = "key: value"; - YAMLNodeHandle node = yaml_parse(yaml); - + YAMLNodeHandle node = parse_string(yaml); + REQUIRE(node != nullptr); - REQUIRE(yaml_is_map(node)); - REQUIRE(yaml_has_key(node, "key")); - - yaml_delete_node(node); + REQUIRE(is_map(node)); + REQUIRE(has_key(node, "key")); + + delete_node(node); } - + SECTION("Parse sequence") { const char* yaml = "[a, b, c]"; - YAMLNodeHandle node = yaml_parse(yaml); - + YAMLNodeHandle node = parse_string(yaml); + REQUIRE(node != nullptr); - REQUIRE(yaml_is_sequence(node)); - REQUIRE(yaml_size(node) == 3); - - yaml_delete_node(node); + REQUIRE(is_sequence(node)); + REQUIRE(size(node) == 3); + + delete_node(node); } - + SECTION("Parse invalid YAML returns nullptr") { const char* invalid = "invalid: yaml: :"; - YAMLNodeHandle node = yaml_parse(invalid); - + YAMLNodeHandle node = parse_string(invalid); + REQUIRE(node == nullptr); } } TEST_CASE("YAML can be parsed from files", "[parsing][file]") { SECTION("Parse valid file") { - YAMLNodeHandle node = yaml_parse_file("../lattice_files/ex.pals.yaml"); - + YAMLNodeHandle node = parse_file("../lattice_files/ex.pals.yaml"); + REQUIRE(node != nullptr); - REQUIRE(yaml_is_sequence(node)); - REQUIRE(yaml_size(node) >= 2); - - yaml_delete_node(node); + REQUIRE(is_sequence(node)); + REQUIRE(size(node) >= 2); + + delete_node(node); } - + SECTION("Parse non-existent file returns nullptr") { - YAMLNodeHandle node = yaml_parse_file("nonexistent.pals.yaml"); + YAMLNodeHandle node = parse_file("nonexistent.pals.yaml"); REQUIRE(node == nullptr); } } @@ -119,33 +120,33 @@ TEST_CASE("YAML can be parsed from files", "[parsing][file]") { TEST_CASE("Node types can be checked", "[types]") { SECTION("Check scalar type") { - YAMLNodeHandle node = yaml_parse("value"); - REQUIRE(yaml_is_scalar(node)); - REQUIRE_FALSE(yaml_is_map(node)); - REQUIRE_FALSE(yaml_is_sequence(node)); - yaml_delete_node(node); + YAMLNodeHandle node = parse_string("value"); + REQUIRE(is_scalar(node)); + REQUIRE_FALSE(is_map(node)); + REQUIRE_FALSE(is_sequence(node)); + delete_node(node); } - + SECTION("Check map type") { - YAMLNodeHandle node = yaml_parse("key: value"); - REQUIRE(yaml_is_map(node)); - REQUIRE_FALSE(yaml_is_scalar(node)); - REQUIRE_FALSE(yaml_is_sequence(node)); - yaml_delete_node(node); + YAMLNodeHandle node = parse_string("key: value"); + REQUIRE(is_map(node)); + REQUIRE_FALSE(is_scalar(node)); + REQUIRE_FALSE(is_sequence(node)); + delete_node(node); } - + SECTION("Check sequence type") { - YAMLNodeHandle node = yaml_parse("[a, b, c]"); - REQUIRE(yaml_is_sequence(node)); - REQUIRE_FALSE(yaml_is_map(node)); - REQUIRE_FALSE(yaml_is_scalar(node)); - yaml_delete_node(node); + YAMLNodeHandle node = parse_string("[a, b, c]"); + REQUIRE(is_sequence(node)); + REQUIRE_FALSE(is_map(node)); + REQUIRE_FALSE(is_scalar(node)); + delete_node(node); } - + SECTION("Check null type") { - YAMLNodeHandle node = yaml_parse("null"); - REQUIRE(yaml_is_null(node)); - yaml_delete_node(node); + YAMLNodeHandle node = parse_string("null"); + REQUIRE(is_null(node)); + delete_node(node); } } @@ -155,82 +156,80 @@ TEST_CASE("Node types can be checked", "[types]") { TEST_CASE("Map keys can be accessed", "[access][map]") { const char* yaml = "name: test\nvalue: 42"; - YAMLNodeHandle node = yaml_parse(yaml); - + YAMLNodeHandle node = parse_string(yaml); + SECTION("Check key existence") { - REQUIRE(yaml_has_key(node, "name")); - REQUIRE(yaml_has_key(node, "value")); - REQUIRE_FALSE(yaml_has_key(node, "nonexistent")); + REQUIRE(has_key(node, "name")); + REQUIRE(has_key(node, "value")); + REQUIRE_FALSE(has_key(node, "nonexistent")); } - + SECTION("Get key value") { - YAMLNodeHandle name = yaml_get_key(node, "name"); + YAMLNodeHandle name = get_key(node, "name"); REQUIRE(name != nullptr); - - char* str = yaml_as_string(name); + + char* str = as_string(name); REQUIRE(std::string(str) == "test"); - + yaml_free_string(str); - yaml_delete_node(name); + delete_node(name); } - + SECTION("Get non-existent key returns nullptr") { - YAMLNodeHandle missing = yaml_get_key(node, "missing"); + YAMLNodeHandle missing = get_key(node, "missing"); REQUIRE(missing == nullptr); } - + SECTION("Get all keys") { int count; - char** keys = yaml_get_keys(node, &count); - + char** keys = get_keys(node, &count); + REQUIRE(count == 2); REQUIRE(keys != nullptr); - + bool has_name = false, has_value = false; for (int i = 0; i < count; i++) { if (std::string(keys[i]) == "name") has_name = true; if (std::string(keys[i]) == "value") has_value = true; } - + REQUIRE(has_name); REQUIRE(has_value); - + yaml_free_keys(keys, count); } - - yaml_delete_node(node); + + delete_node(node); } TEST_CASE("Sequence indices can be accessed", "[access][sequence]") { const char* yaml = "[apple, banana, cherry]"; - YAMLNodeHandle node = yaml_parse(yaml); - - SECTION("Check size") { - REQUIRE(yaml_size(node) == 3); - } - + YAMLNodeHandle node = parse_string(yaml); + + SECTION("Check size") { REQUIRE(size(node) == 3); } + SECTION("Access valid index") { - YAMLNodeHandle item = yaml_get_index(node, 1); + YAMLNodeHandle item = get_index(node, 1); REQUIRE(item != nullptr); - - char* str = yaml_as_string(item); + + char* str = as_string(item); REQUIRE(std::string(str) == "banana"); - + yaml_free_string(str); - yaml_delete_node(item); + delete_node(item); } - + SECTION("Access out of bounds index returns nullptr") { - YAMLNodeHandle item = yaml_get_index(node, 999); + YAMLNodeHandle item = get_index(node, 999); REQUIRE(item == nullptr); } - + SECTION("Access negative index returns nullptr") { - YAMLNodeHandle item = yaml_get_index(node, -1); + YAMLNodeHandle item = get_index(node, -1); REQUIRE(item == nullptr); } - - yaml_delete_node(node); + + delete_node(node); } // =========================================== @@ -239,53 +238,53 @@ TEST_CASE("Sequence indices can be accessed", "[access][sequence]") { TEST_CASE("Values can be converted to C types", "[conversion]") { SECTION("Convert to string") { - YAMLNodeHandle node = yaml_parse("test_value"); - char* str = yaml_as_string(node); - + YAMLNodeHandle node = parse_string("test_value"); + char* str = as_string(node); + REQUIRE(str != nullptr); REQUIRE(std::string(str) == "test_value"); - + yaml_free_string(str); - yaml_delete_node(node); + delete_node(node); } - + SECTION("Convert to int") { - YAMLNodeHandle node = yaml_parse("42"); - int val = yaml_as_int(node); - + YAMLNodeHandle node = parse_string("42"); + int val = as_int(node); + REQUIRE(val == 42); - - yaml_delete_node(node); + + delete_node(node); } - + SECTION("Convert to float") { - YAMLNodeHandle node = yaml_parse("3.14"); - double val = yaml_as_float(node); - + YAMLNodeHandle node = parse_string("3.14"); + double val = as_float(node); + REQUIRE(val == Approx(3.14)); - - yaml_delete_node(node); + + delete_node(node); } - + SECTION("Convert to bool") { - YAMLNodeHandle node_true = yaml_parse("true"); - YAMLNodeHandle node_false = yaml_parse("false"); - - REQUIRE(yaml_as_bool(node_true) == true); - REQUIRE(yaml_as_bool(node_false) == false); - - yaml_delete_node(node_true); - yaml_delete_node(node_false); - } - + YAMLNodeHandle node_true = parse_string("true"); + YAMLNodeHandle node_false = parse_string("false"); + + REQUIRE(as_bool(node_true) == true); + REQUIRE(as_bool(node_false) == false); + + delete_node(node_true); + delete_node(node_false); + } + SECTION("Invalid conversion returns default") { - YAMLNodeHandle node = yaml_parse("[a, b, c]"); - + YAMLNodeHandle node = parse_string("[a, b, c]"); + // Can't convert sequence to string - char* str = yaml_as_string(node); + char* str = as_string(node); REQUIRE(str == nullptr); - - yaml_delete_node(node); + + delete_node(node); } } @@ -294,62 +293,62 @@ TEST_CASE("Values can be converted to C types", "[conversion]") { // =========================================== TEST_CASE("Map values can be set", "[modification][map]") { - YAMLNodeHandle map = yaml_create_map(); - + YAMLNodeHandle map = create_map(); + SECTION("Set string value") { - yaml_set_string(map, "name", "test"); - REQUIRE(yaml_has_key(map, "name")); - - YAMLNodeHandle value = yaml_get_key(map, "name"); - char* str = yaml_as_string(value); + set_value_string(map, "name", "test"); + REQUIRE(has_key(map, "name")); + + YAMLNodeHandle value = get_key(map, "name"); + char* str = as_string(value); REQUIRE(std::string(str) == "test"); - + yaml_free_string(str); - yaml_delete_node(value); + delete_node(value); } - + SECTION("Set int value") { - yaml_set_int(map, "count", 42); - - YAMLNodeHandle value = yaml_get_key(map, "count"); - REQUIRE(yaml_as_int(value) == 42); - - yaml_delete_node(value); - } - + set_value_int(map, "count", 42); + + YAMLNodeHandle value = get_key(map, "count"); + REQUIRE(as_int(value) == 42); + + delete_node(value); + } + SECTION("Set float value") { - yaml_set_float(map, "pi", 3.14); - - YAMLNodeHandle value = yaml_get_key(map, "pi"); - REQUIRE(yaml_as_float(value) == Catch::Approx(3.14)); - - yaml_delete_node(value); - } - + set_value_float(map, "pi", 3.14); + + YAMLNodeHandle value = get_key(map, "pi"); + REQUIRE(as_float(value) == Catch::Approx(3.14)); + + delete_node(value); + } + SECTION("Set bool value") { - yaml_set_bool(map, "enabled", true); - - YAMLNodeHandle value = yaml_get_key(map, "enabled"); - REQUIRE(yaml_as_bool(value) == true); - - yaml_delete_node(value); - } - + set_value_bool(map, "enabled", true); + + YAMLNodeHandle value = get_key(map, "enabled"); + REQUIRE(as_bool(value) == true); + + delete_node(value); + } + SECTION("Set nested node") { - YAMLNodeHandle nested = yaml_create_map(); - yaml_set_string(nested, "inner", "value"); - - yaml_set_node(map, "nested", nested); - - REQUIRE(yaml_has_key(map, "nested")); - YAMLNodeHandle retrieved = yaml_get_key(map, "nested"); - REQUIRE(yaml_is_map(retrieved)); - - yaml_delete_node(retrieved); - yaml_delete_node(nested); - } - - yaml_delete_node(map); + YAMLNodeHandle nested = create_map(); + set_value_string(nested, "inner", "value"); + + set_value_node(map, "nested", nested); + + REQUIRE(has_key(map, "nested")); + YAMLNodeHandle retrieved = get_key(map, "nested"); + REQUIRE(is_map(retrieved)); + + delete_node(retrieved); + delete_node(nested); + } + + delete_node(map); } // =========================================== @@ -357,81 +356,81 @@ TEST_CASE("Map values can be set", "[modification][map]") { // =========================================== TEST_CASE("Sequence values can be pushed", "[modification][sequence]") { - YAMLNodeHandle seq = yaml_create_sequence(); - + YAMLNodeHandle seq = create_sequence(); + SECTION("Push string values") { - yaml_push_string(seq, "first"); - yaml_push_string(seq, "second"); - - REQUIRE(yaml_size(seq) == 2); - - YAMLNodeHandle item = yaml_get_index(seq, 1); - char* str = yaml_as_string(item); + push_string(seq, "first"); + push_string(seq, "second"); + + REQUIRE(size(seq) == 2); + + YAMLNodeHandle item = get_index(seq, 1); + char* str = as_string(item); REQUIRE(std::string(str) == "second"); - + yaml_free_string(str); - yaml_delete_node(item); + delete_node(item); } - + SECTION("Push int values") { - yaml_push_int(seq, 10); - yaml_push_int(seq, 20); - - REQUIRE(yaml_size(seq) == 2); - - YAMLNodeHandle item = yaml_get_index(seq, 0); - REQUIRE(yaml_as_int(item) == 10); - - yaml_delete_node(item); - } - + push_int(seq, 10); + push_int(seq, 20); + + REQUIRE(size(seq) == 2); + + YAMLNodeHandle item = get_index(seq, 0); + REQUIRE(as_int(item) == 10); + + delete_node(item); + } + SECTION("Push float values") { - yaml_push_float(seq, 1.1); - yaml_push_float(seq, 2.2); - - REQUIRE(yaml_size(seq) == 2); - - YAMLNodeHandle item = yaml_get_index(seq, 1); - REQUIRE(yaml_as_float(item) == Catch::Approx(2.2)); - - yaml_delete_node(item); - } - + push_float(seq, 1.1); + push_float(seq, 2.2); + + REQUIRE(size(seq) == 2); + + YAMLNodeHandle item = get_index(seq, 1); + REQUIRE(as_float(item) == Catch::Approx(2.2)); + + delete_node(item); + } + SECTION("Push node") { - YAMLNodeHandle node = yaml_create_map(); - yaml_set_string(node, "key", "value"); - - yaml_push_node(seq, node); - - REQUIRE(yaml_size(seq) == 1); - - YAMLNodeHandle retrieved = yaml_get_index(seq, 0); - REQUIRE(yaml_is_map(retrieved)); - - yaml_delete_node(retrieved); - yaml_delete_node(node); - } - - yaml_delete_node(seq); + YAMLNodeHandle node = create_map(); + set_value_string(node, "key", "value"); + + push_node(seq, node); + + REQUIRE(size(seq) == 1); + + YAMLNodeHandle retrieved = get_index(seq, 0); + REQUIRE(is_map(retrieved)); + + delete_node(retrieved); + delete_node(node); + } + + delete_node(seq); } TEST_CASE("Sequence values can be set at index", "[modification][sequence]") { - YAMLNodeHandle seq = yaml_parse("[a, b, c]"); - + YAMLNodeHandle seq = parse_string("[a, b, c]"); + SECTION("Set string at index") { - YAMLNodeHandle replacement = yaml_parse("replaced"); - yaml_set_at_index(seq, 1, replacement); - - YAMLNodeHandle item = yaml_get_index(seq, 1); - char* str = yaml_as_string(item); + YAMLNodeHandle replacement = parse_string("replaced"); + set_at_index(seq, 1, replacement); + + YAMLNodeHandle item = get_index(seq, 1); + char* str = as_string(item); REQUIRE(std::string(str) == "replaced"); - + yaml_free_string(str); - yaml_delete_node(item); - yaml_delete_node(replacement); + delete_node(item); + delete_node(replacement); } - - yaml_delete_node(seq); + + delete_node(seq); } // =========================================== @@ -440,41 +439,41 @@ TEST_CASE("Sequence values can be set at index", "[modification][sequence]") { TEST_CASE("Scalar values can be edited directly", "[modification][scalar]") { SECTION("Set scalar string") { - YAMLNodeHandle scalar = yaml_create_scalar(); - yaml_set_scalar_string(scalar, "new_value"); - - char* str = yaml_as_string(scalar); + YAMLNodeHandle scalar = create_scalar(); + set_scalar_string(scalar, "new_value"); + + char* str = as_string(scalar); REQUIRE(std::string(str) == "new_value"); - + yaml_free_string(str); - yaml_delete_node(scalar); + delete_node(scalar); } - + SECTION("Set scalar int") { - YAMLNodeHandle scalar = yaml_create_scalar(); - yaml_set_scalar_int(scalar, 99); - - REQUIRE(yaml_as_int(scalar) == 99); - - yaml_delete_node(scalar); - } - + YAMLNodeHandle scalar = create_scalar(); + set_scalar_int(scalar, 99); + + REQUIRE(as_int(scalar) == 99); + + delete_node(scalar); + } + SECTION("Set scalar float") { - YAMLNodeHandle scalar = yaml_create_scalar(); - yaml_set_scalar_float(scalar, 2.718); - - REQUIRE(yaml_as_float(scalar) == Catch::Approx(2.718)); - - yaml_delete_node(scalar); - } - + YAMLNodeHandle scalar = create_scalar(); + set_scalar_float(scalar, 2.718); + + REQUIRE(as_float(scalar) == Catch::Approx(2.718)); + + delete_node(scalar); + } + SECTION("Set scalar bool") { - YAMLNodeHandle scalar = yaml_create_scalar(); - yaml_set_scalar_bool(scalar, false); - - REQUIRE(yaml_as_bool(scalar) == false); - - yaml_delete_node(scalar); + YAMLNodeHandle scalar = create_scalar(); + set_scalar_bool(scalar, false); + + REQUIRE(as_bool(scalar) == false); + + delete_node(scalar); } } @@ -484,34 +483,34 @@ TEST_CASE("Scalar values can be edited directly", "[modification][scalar]") { TEST_CASE("YAML can be written to files", "[io][file]") { const char* test_file = "test_output.pals.yaml"; - + SECTION("Write simple map") { - YAMLNodeHandle map = yaml_create_map(); - yaml_set_string(map, "test", "value"); - yaml_set_int(map, "count", 5); - - REQUIRE(yaml_write_file(map, test_file)); - + YAMLNodeHandle map = create_map(); + set_value_string(map, "test", "value"); + set_value_int(map, "count", 5); + + REQUIRE(write_file(map, test_file)); + // Read back and verify - YAMLNodeHandle loaded = yaml_parse_file(test_file); + YAMLNodeHandle loaded = parse_file(test_file); REQUIRE(loaded != nullptr); - REQUIRE(yaml_has_key(loaded, "test")); - REQUIRE(yaml_has_key(loaded, "count")); - - yaml_delete_node(map); - yaml_delete_node(loaded); + REQUIRE(has_key(loaded, "test")); + REQUIRE(has_key(loaded, "count")); + + delete_node(map); + delete_node(loaded); cleanup_file(test_file); } - + SECTION("Write with formatting") { - YAMLNodeHandle seq = yaml_parse("[a, b, c]"); - - REQUIRE(yaml_write_file_formatted(seq, test_file, 4, false, true)); - + YAMLNodeHandle seq = parse_string("[a, b, c]"); + + REQUIRE(write_file_formatted(seq, test_file, 4, false, true)); + std::string content = read_file(test_file); - REQUIRE(content.find("[a, b, c]") != std::string::npos); // Flow style - - yaml_delete_node(seq); + REQUIRE(content.find("[a, b, c]") != std::string::npos); // Flow style + + delete_node(seq); cleanup_file(test_file); } } @@ -522,31 +521,31 @@ TEST_CASE("YAML can be written to files", "[io][file]") { TEST_CASE("YAML nodes can be converted to strings", "[conversion][string]") { SECTION("Convert map to string") { - YAMLNodeHandle map = yaml_create_map(); - yaml_set_string(map, "key", "value"); - + YAMLNodeHandle map = create_map(); + set_value_string(map, "key", "value"); + char* str = yaml_to_string(map); REQUIRE(str != nullptr); REQUIRE(std::string(str).find("key") != std::string::npos); REQUIRE(std::string(str).find("value") != std::string::npos); - + yaml_free_string(str); - yaml_delete_node(map); + delete_node(map); } - + SECTION("Emit with custom indent") { - YAMLNodeHandle map = yaml_create_map(); - yaml_set_string(map, "test", "val"); - + YAMLNodeHandle map = create_map(); + set_value_string(map, "test", "val"); + char* str2 = yaml_emit(map, 2); char* str4 = yaml_emit(map, 4); - + REQUIRE(str2 != nullptr); REQUIRE(str4 != nullptr); - + yaml_free_string(str2); yaml_free_string(str4); - yaml_delete_node(map); + delete_node(map); } } @@ -556,46 +555,46 @@ TEST_CASE("YAML nodes can be converted to strings", "[conversion][string]") { TEST_CASE("YAML nodes can be cloned", "[clone]") { SECTION("Clone simple map") { - YAMLNodeHandle original = yaml_create_map(); - yaml_set_string(original, "name", "original"); - + YAMLNodeHandle original = create_map(); + set_value_string(original, "name", "original"); + YAMLNodeHandle clone = yaml_clone(original); REQUIRE(clone != nullptr); - + // Modify clone - yaml_set_string(clone, "name", "modified"); - + set_value_string(clone, "name", "modified"); + // Verify original unchanged - YAMLNodeHandle orig_val = yaml_get_key(original, "name"); - char* orig_str = yaml_as_string(orig_val); + YAMLNodeHandle orig_val = get_key(original, "name"); + char* orig_str = as_string(orig_val); REQUIRE(std::string(orig_str) == "original"); - + // Verify clone changed - YAMLNodeHandle clone_val = yaml_get_key(clone, "name"); - char* clone_str = yaml_as_string(clone_val); + YAMLNodeHandle clone_val = get_key(clone, "name"); + char* clone_str = as_string(clone_val); REQUIRE(std::string(clone_str) == "modified"); - + yaml_free_string(orig_str); yaml_free_string(clone_str); - yaml_delete_node(orig_val); - yaml_delete_node(clone_val); - yaml_delete_node(original); - yaml_delete_node(clone); + delete_node(orig_val); + delete_node(clone_val); + delete_node(original); + delete_node(clone); } - + SECTION("Clone nested structure") { - YAMLNodeHandle original = yaml_parse("outer: {inner: value}"); + YAMLNodeHandle original = parse_string("outer: {inner: value}"); YAMLNodeHandle clone = yaml_clone(original); - + REQUIRE(clone != nullptr); - REQUIRE(yaml_is_map(clone)); - - YAMLNodeHandle outer = yaml_get_key(clone, "outer"); - REQUIRE(yaml_has_key(outer, "inner")); - - yaml_delete_node(outer); - yaml_delete_node(original); - yaml_delete_node(clone); + REQUIRE(is_map(clone)); + + YAMLNodeHandle outer = get_key(clone, "outer"); + REQUIRE(has_key(outer, "inner")); + + delete_node(outer); + delete_node(original); + delete_node(clone); } } @@ -604,74 +603,74 @@ TEST_CASE("YAML nodes can be cloned", "[clone]") { // =========================================== TEST_CASE("ex.pals.yaml has expected structure", "[ex.pals.yaml][structure]") { - YAMLNodeHandle root = yaml_parse_file("../lattice_files/ex.pals.yaml"); + YAMLNodeHandle root = parse_file("../lattice_files/ex.pals.yaml"); REQUIRE(root != nullptr); - + SECTION("Root is a sequence") { - REQUIRE(yaml_is_sequence(root)); - REQUIRE(yaml_size(root) >= 2); + REQUIRE(is_sequence(root)); + REQUIRE(size(root) >= 2); } - + SECTION("First element has thingB") { - YAMLNodeHandle first = yaml_get_index(root, 0); + YAMLNodeHandle first = get_index(root, 0); REQUIRE(first != nullptr); - REQUIRE(yaml_is_map(first)); - REQUIRE(yaml_has_key(first, "thingB")); - - YAMLNodeHandle thingB = yaml_get_key(first, "thingB"); - REQUIRE(yaml_is_map(thingB)); - REQUIRE(yaml_has_key(thingB, "kind")); - - YAMLNodeHandle kind = yaml_get_key(thingB, "kind"); - char* kind_str = yaml_as_string(kind); + REQUIRE(is_map(first)); + REQUIRE(has_key(first, "thingB")); + + YAMLNodeHandle thingB = get_key(first, "thingB"); + REQUIRE(is_map(thingB)); + REQUIRE(has_key(thingB, "kind")); + + YAMLNodeHandle kind = get_key(thingB, "kind"); + char* kind_str = as_string(kind); REQUIRE(std::string(kind_str) == "Sextupole"); - + yaml_free_string(kind_str); - yaml_delete_node(kind); - yaml_delete_node(thingB); - yaml_delete_node(first); + delete_node(kind); + delete_node(thingB); + delete_node(first); } - + SECTION("Second element has inj_line") { - YAMLNodeHandle second = yaml_get_index(root, 1); + YAMLNodeHandle second = get_index(root, 1); REQUIRE(second != nullptr); - REQUIRE(yaml_is_map(second)); - REQUIRE(yaml_has_key(second, "inj_line")); - - YAMLNodeHandle inj_line = yaml_get_key(second, "inj_line"); - REQUIRE(yaml_is_map(inj_line)); - REQUIRE(yaml_has_key(inj_line, "kind")); - REQUIRE(yaml_has_key(inj_line, "multipass")); - REQUIRE(yaml_has_key(inj_line, "line")); - - YAMLNodeHandle kind = yaml_get_key(inj_line, "kind"); - char* kind_str = yaml_as_string(kind); + REQUIRE(is_map(second)); + REQUIRE(has_key(second, "inj_line")); + + YAMLNodeHandle inj_line = get_key(second, "inj_line"); + REQUIRE(is_map(inj_line)); + REQUIRE(has_key(inj_line, "kind")); + REQUIRE(has_key(inj_line, "multipass")); + REQUIRE(has_key(inj_line, "line")); + + YAMLNodeHandle kind = get_key(inj_line, "kind"); + char* kind_str = as_string(kind); REQUIRE(std::string(kind_str) == "BeamLine"); - - YAMLNodeHandle multipass = yaml_get_key(inj_line, "multipass"); - REQUIRE(yaml_as_bool(multipass) == true); - + + YAMLNodeHandle multipass = get_key(inj_line, "multipass"); + REQUIRE(as_bool(multipass) == true); + yaml_free_string(kind_str); - yaml_delete_node(kind); - yaml_delete_node(multipass); - yaml_delete_node(inj_line); - yaml_delete_node(second); + delete_node(kind); + delete_node(multipass); + delete_node(inj_line); + delete_node(second); } - + SECTION("inj_line has line sequence") { - YAMLNodeHandle second = yaml_get_index(root, 1); - YAMLNodeHandle inj_line = yaml_get_key(second, "inj_line"); - YAMLNodeHandle line = yaml_get_key(inj_line, "line"); - - REQUIRE(yaml_is_sequence(line)); - REQUIRE(yaml_size(line) >= 3); - - yaml_delete_node(line); - yaml_delete_node(inj_line); - yaml_delete_node(second); - } - - yaml_delete_node(root); + YAMLNodeHandle second = get_index(root, 1); + YAMLNodeHandle inj_line = get_key(second, "inj_line"); + YAMLNodeHandle line = get_key(inj_line, "line"); + + REQUIRE(is_sequence(line)); + REQUIRE(size(line) >= 3); + + delete_node(line); + delete_node(inj_line); + delete_node(second); + } + + delete_node(root); } // =========================================== @@ -680,33 +679,33 @@ TEST_CASE("ex.pals.yaml has expected structure", "[ex.pals.yaml][structure]") { TEST_CASE("Memory is properly managed", "[memory]") { SECTION("Can safely delete nullptr") { - yaml_delete_node(nullptr); // Should not crash + delete_node(nullptr); // Should not crash } - + SECTION("Multiple operations don't leak") { for (int i = 0; i < 100; i++) { - YAMLNodeHandle node = yaml_create_map(); - yaml_set_int(node, "test", i); - + YAMLNodeHandle node = create_map(); + set_value_int(node, "test", i); + char* str = yaml_to_string(node); yaml_free_string(str); - - yaml_delete_node(node); + + delete_node(node); } // No assertion - just shouldn't crash or leak } - + SECTION("Complex structure cleanup") { - YAMLNodeHandle root = yaml_create_sequence(); - + YAMLNodeHandle root = create_sequence(); + for (int i = 0; i < 10; i++) { - YAMLNodeHandle map = yaml_create_map(); - yaml_set_int(map, "id", i); - yaml_push_node(root, map); - yaml_delete_node(map); // Safe after push_node copies + YAMLNodeHandle map = create_map(); + set_value_int(map, "id", i); + push_node(root, map); + delete_node(map); // Safe after push_node copies } - - yaml_delete_node(root); + + delete_node(root); } } @@ -716,30 +715,30 @@ TEST_CASE("Memory is properly managed", "[memory]") { TEST_CASE("Edge cases are handled correctly", "[edge_cases]") { SECTION("Empty map") { - YAMLNodeHandle map = yaml_create_map(); - REQUIRE(yaml_size(map) == 0); - + YAMLNodeHandle map = create_map(); + REQUIRE(size(map) == 0); + int count; - char** keys = yaml_get_keys(map, &count); + char** keys = get_keys(map, &count); REQUIRE(count == 0); - - yaml_delete_node(map); + + delete_node(map); } - + SECTION("Empty sequence") { - YAMLNodeHandle seq = yaml_create_sequence(); - REQUIRE(yaml_size(seq) == 0); - - YAMLNodeHandle item = yaml_get_index(seq, 0); + YAMLNodeHandle seq = create_sequence(); + REQUIRE(size(seq) == 0); + + YAMLNodeHandle item = get_index(seq, 0); REQUIRE(item == nullptr); - - yaml_delete_node(seq); + + delete_node(seq); } - + SECTION("Set scalar to nullptr is safe") { - YAMLNodeHandle scalar = yaml_create_scalar(); - yaml_set_scalar_string(nullptr, "test"); // Should not crash - yaml_set_scalar_string(scalar, nullptr); // Should not crash - yaml_delete_node(scalar); + YAMLNodeHandle scalar = create_scalar(); + set_scalar_string(nullptr, "test"); // Should not crash + set_scalar_string(scalar, nullptr); // Should not crash + delete_node(scalar); } }