Repository navigation
Expand file tree
/
Copy pathtutorial.cpp
More file actions
113 lines (101 loc) · 5.84 KB
/
Copy pathtutorial.cpp
File metadata and controls
113 lines (101 loc) · 5.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// SysML v2 SDK, C++: a first walk through a model.
//
// Build and run from the repository root (header-only, C++17):
//
// g++ -std=c++17 -I cpp/include -I vendor examples/cpp/tutorial.cpp -o examples/cpp/tutorial
// examples/cpp/tutorial reads examples/vehicle.full.json
// examples/cpp/tutorial --toolkit reads examples/vehicle.sysml through the SysML Toolkit
//
// (On Windows with MinGW add -static.) The payload is a full-form interchange export any SysML v2
// tool can produce; this one came from the SysML Toolkit. Its references into the standard library
// resolve against the library as JSON, published with each SDK release. In this repository both
// are generated by `python tools/export_example.py --library <sysml.library>`. The SysML Toolkit
// path loads the binding library at run time (build abi/ first).
//
// Everything is named as in the OMG specification. Properties are read through getters, `get` +
// the specification name: getOwnedMember(), getQualifiedName(), getIsAbstract(). Operations keep
// their specification names: effectiveName(), specializes(...). Elements are value types over a
// shared model; `is_a<T>()` asks the metaclass question and `as<T>()` converts, throwing
// wrong_kind if the answer is no.
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <sysml/sdk.hpp>
#include <sysml/classes.g.hpp>
#include <sysml/toolkit.hpp>
using namespace sysml;
static std::string read_file(const char* path) {
std::ifstream in(path, std::ios::binary);
if (!in) throw std::runtime_error(std::string("cannot open ") + path + " (run from the repository root)");
std::stringstream ss;
ss << in.rdbuf();
return ss.str();
}
int main(int argc, char** argv) {
const bool toolkit = argc > 1 && std::string(argv[1]) == "--toolkit";
Model model = toolkit ? Model::from_backend(ToolkitBackend::open({"examples/vehicle.sysml"}))
: Model::from_full_json(read_file("examples/vehicle.full.json"),
PayloadLibrary::parse(read_file("examples/sysml.library.full.json")));
// 1. Find an element by its qualified name, and confirm what it is.
auto vehicle = model.resolve("Vehicles::Vehicle").value().as<PartDefinition>();
std::cout << vehicle.getQualifiedName().value() << " is a " << vehicle.metaclass_name() << "\n";
// 2. The generated structs are the metaclass hierarchy.
auto vehicles = model.resolve("Vehicles").value().as<Namespace>();
std::cout << "definitions:";
for (const Element& m : vehicles.getOwnedMember())
if (m.is_a<Definition>()) std::cout << " " << m.as<Definition>().getDeclaredName().value_or("?");
std::cout << "\n";
// 3. Walk a definition's features and their declared types.
std::cout << "\nfeatures of " << vehicle.getDeclaredName().value() << ":\n";
for (const Feature& f : vehicle.getOwnedFeature()) {
std::string types;
try {
for (const Type& t : f.getType()) types += (types.empty() ? "" : ", ") + t.getDeclaredName().value_or("?");
if (types.empty()) types = "untyped";
} catch (const not_implemented_in_toolkit& e) { // the SysML Toolkit cannot vouch for this value yet
types = std::string("(") + e.what() + ")";
}
std::cout << " " << std::left << std::setw(16) << f.metaclass_name()
<< std::setw(10) << f.getDeclaredName().value_or("(unnamed)") << " : " << types << "\n";
}
// 4. Documentation is a member like any other.
for (const Documentation& doc : vehicle.getDocumentation())
std::cout << "\ndoc: " << doc.getBody().value_or("") << "\n";
// 5. A usage and the definition it is typed by.
auto my_car = model.resolve("Vehicles::myCar").value().as<PartUsage>();
try {
const std::string typed_by = my_car.getType().front().getQualifiedName().value(); // read before printing
std::cout << "\n" << my_car.getQualifiedName().value() << " is typed by " << typed_by << "\n";
} catch (const not_implemented_in_toolkit& e) {
std::cout << "\n" << my_car.getQualifiedName().value() << ": " << e.what() << "\n";
}
// 6. Inheritance. Through the SysML Toolkit, inherited features are computed. A payload holds
// what the exporting tool wrote: this file was exported at the closure level, so it has them
// too; an export by the SysML Toolkit's command-line tool would list the owned side only.
// With the standard library, every part also inherits the library's features (`self`,
// `start`, ...); getIsLibraryElement() tells them apart.
auto sports = model.resolve("Vehicles::SportsCar").value().as<PartDefinition>();
std::string inherited;
try {
std::size_t count = 0;
for (const Feature& f : sports.getInheritedFeature())
if (f.getIsLibraryElement() != true) ++count;
inherited = std::to_string(count);
} catch (const not_implemented_in_toolkit& e) {
inherited = std::string("(") + e.what() + ")";
}
std::cout << "\n" << sports.getDeclaredName().value() << " owns " << sports.getOwnedFeature().size()
<< " features; inherited: " << inherited << "\n";
// 7. Honest refusal. Through the SysML Toolkit, a member it cannot vouch for yet says so
// instead of answering, as the reads above show where it does. Through a payload there is
// nobody to say so: the file holds what the exporting tool wrote.
try {
std::string defs;
for (const PartDefinition& d : my_car.getPartDefinition()) defs += (defs.empty() ? "" : ", ") + d.getQualifiedName().value_or("?");
std::cout << "\npartDefinition of myCar: " << defs << "\n";
} catch (const not_implemented_in_toolkit& e) {
std::cout << "\nnot answered by the SysML Toolkit, and it says so: " << e.what() << "\n";
}
return 0;
}