diff --git a/cyberiadamlpp.cpp b/cyberiadamlpp.cpp index 543911a..66622a8 100644 --- a/cyberiadamlpp.cpp +++ b/cyberiadamlpp.cpp @@ -107,6 +107,7 @@ CyberiadaNode* Element::to_node() const case elementInitial: node->type = cybNodeInitial; break; case elementFinal: node->type = cybNodeFinal; break; case elementChoice: node->type = cybNodeChoice; break; + case elementTerminate: node->type = cybNodeTerminate; break; default: std::cerr << id << " " << type << std::endl; CYB_ASSERT(false); @@ -131,6 +132,7 @@ std::ostream& Element::dump(std::ostream& os) const case elementInitial: type_str = "Initial"; break; case elementFinal: type_str = "Final"; break; case elementChoice: type_str = "Choice"; break; + case elementTerminate: type_str = "Terminate"; break; case elementTransition: type_str = "Transition"; break; default: CYB_ASSERT(false); @@ -508,9 +510,11 @@ Vertex::Vertex(Element* _parent, ElementType _type, const ID& _id, const Name& _ std::ostream& Vertex::dump(std::ostream& os) const { + Element::dump(os); if (has_geometry()) { os << ", geometry: " << geometry_point; } + os << "}"; return os; } @@ -728,7 +732,8 @@ std::list ElementCollection::get_vertexes() const elementCompositeState, elementInitial, elementFinal, - elementChoice }; + elementChoice, + elementTerminate}; std::list result; ConstElementList vertexes = find_elements_by_types(types); for (ConstElementList::const_iterator i = vertexes.begin(); i != vertexes.end(); i++) { @@ -745,7 +750,8 @@ std::list ElementCollection::get_vertexes() elementCompositeState, elementInitial, elementFinal, - elementChoice }; + elementChoice, + elementTerminate}; std::list result; ElementList vertexes = find_elements_by_types(types); for (ElementList::const_iterator i = vertexes.begin(); i != vertexes.end(); i++) { @@ -853,12 +859,18 @@ InitialPseudostate::InitialPseudostate(Element* _parent, const ID& _id, const Na { } -std::ostream& InitialPseudostate::dump(std::ostream& os) const +// ----------------------------------------------------------------------------- +// Terminate pseudostate +// ----------------------------------------------------------------------------- + +TerminatePseudostate::TerminatePseudostate(Element* _parent, const ID& _id, const Point& p): + Pseudostate(_parent, elementTerminate, _id, p) +{ +} + +TerminatePseudostate::TerminatePseudostate(Element* _parent, const ID& _id, const Name& _name, const Point& p): + Pseudostate(_parent, elementTerminate, _id, _name, p) { - Element::dump(os); - Vertex::dump(os); - os << "}"; - return os; } // ----------------------------------------------------------------------------- @@ -914,14 +926,6 @@ FinalState::FinalState(Element* _parent, const ID& _id, const Name& _name, const { } -std::ostream& FinalState::dump(std::ostream& os) const -{ - Element::dump(os); - Vertex::dump(os); - os << "}"; - return os; -} - // ----------------------------------------------------------------------------- // State // ----------------------------------------------------------------------------- @@ -1333,6 +1337,36 @@ ChoicePseudostate* Document::new_choice(ElementCollection* _parent, const ID& _i return choice; } +TerminatePseudostate* Document::new_terminate(ElementCollection* _parent, const Point& p) +{ + check_parent_element(_parent); + + TerminatePseudostate* term = new TerminatePseudostate(_parent, generate_vertex_id(_parent), p); + _parent->add_element(term); + return term; +} + +TerminatePseudostate* Document::new_terminate(ElementCollection* _parent, const Name& _name, const Point& p) +{ + check_parent_element(_parent); + check_nonempty_string(_name); + + TerminatePseudostate* term = new TerminatePseudostate(_parent, generate_vertex_id(_parent), _name, p); + _parent->add_element(term); + return term; +} + +TerminatePseudostate* Document::new_terminate(ElementCollection* _parent, const ID& _id, const Name& _name, const Point& p) +{ + check_parent_element(_parent); + check_nonempty_string(_name); + check_id_uniqueness(_id); + + TerminatePseudostate* term = new TerminatePseudostate(_parent, _id, _name, p); + _parent->add_element(term); + return term; +} + Transition* Document::new_transition(StateMachine* sm, Element* source, Element* target, const Action& action, const Polyline& pl, const Point& sp, const Point& tp, @@ -1553,6 +1587,7 @@ void Document::check_transition_source(const Element* element) const element->get_type() == elementComment || element->get_type() == elementFormalComment || element->get_type() == elementFinal || + element->get_type() == elementTerminate || element->get_type() == elementTransition) { throw ParametersException("Bad source for transition"); } @@ -1698,6 +1733,15 @@ void Document::import_nodes_recursively(ElementCollection* collection, Cyberiada break; + case cybNodeTerminate: + if (n->title) { + element = new TerminatePseudostate(collection, n->id, n->title, point); + } else { + element = new TerminatePseudostate(collection, n->id, point); + } + + break; + case cybNodeFinal: if (n->title) { element = new FinalState(collection, n->id, n->title, point); diff --git a/cyberiadamlpp.h b/cyberiadamlpp.h index e1d95bc..b4eafba 100644 --- a/cyberiadamlpp.h +++ b/cyberiadamlpp.h @@ -49,6 +49,7 @@ namespace Cyberiada { elementInitial, // initial pseudostate elementFinal, // final state elementChoice, // choice pseudostate + elementTerminate, // terminate pseudostate elementTransition // transition }; @@ -329,9 +330,6 @@ namespace Cyberiada { public: InitialPseudostate(Element* parent, const ID& id, const Point& p = Point()); InitialPseudostate(Element* parent, const ID& id, const Name& name, const Point& p = Point()); - - protected: - virtual std::ostream& dump(std::ostream& os) const; }; // ----------------------------------------------------------------------------- @@ -359,6 +357,15 @@ namespace Cyberiada { Color color; }; +// ----------------------------------------------------------------------------- +// Initial pseudostate +// ----------------------------------------------------------------------------- + class TerminatePseudostate: public Pseudostate { + public: + TerminatePseudostate(Element* parent, const ID& id, const Point& p = Point()); + TerminatePseudostate(Element* parent, const ID& id, const Name& name, const Point& p = Point()); + }; + // ----------------------------------------------------------------------------- // Final state // ----------------------------------------------------------------------------- @@ -366,10 +373,6 @@ namespace Cyberiada { public: FinalState(Element* parent, const ID& id, const Point& point = Point()); FinalState(Element* parent, const ID& id, const Name& name, const Point& point = Point()); - - protected: - - virtual std::ostream& dump(std::ostream& os) const; }; // ----------------------------------------------------------------------------- @@ -547,8 +550,8 @@ namespace Cyberiada { State* new_state(ElementCollection* parent, const ID& id, const String& state_name, const Rect& r = Rect(), const Color& color = Color()); InitialPseudostate* new_initial(ElementCollection* parent, const Point& p = Point()); - InitialPseudostate* new_initial(ElementCollection* parent, const Name& initial_name, const Point& p = Point()); - InitialPseudostate* new_initial(ElementCollection* parent, const ID& id, const Name& initial_name, const Point& p = Point()); + InitialPseudostate* new_initial(ElementCollection* parent, const Name& name, const Point& p = Point()); + InitialPseudostate* new_initial(ElementCollection* parent, const ID& id, const Name& name, const Point& p = Point()); FinalState* new_final(ElementCollection* parent, const Point& point = Point()); FinalState* new_final(ElementCollection* parent, const Name& name, const Point& point = Point()); FinalState* new_final(ElementCollection* parent, const ID& id, const Name& name, const Point& point = Point()); @@ -558,6 +561,9 @@ namespace Cyberiada { const Rect& r = Rect(), const Color& color = Color()); ChoicePseudostate* new_choice(ElementCollection* parent, const ID& id, const Name& name, const Rect& r = Rect(), const Color& color = Color()); + TerminatePseudostate* new_terminate(ElementCollection* parent, const Point& p = Point()); + TerminatePseudostate* new_terminate(ElementCollection* parent, const Name& name, const Point& p = Point()); + TerminatePseudostate* new_terminate(ElementCollection* parent, const ID& id, const Name& name, const Point& p = Point()); Transition* new_transition(StateMachine* sm, Element* source, Element* target, const Action& action, const Polyline& pl = Polyline(), const Point& sp = Point(), const Point& tp = Point(), diff --git a/tests/15-output.graphml b/tests/15-output.graphml new file mode 100644 index 0000000..77c79a0 --- /dev/null +++ b/tests/15-output.graphml @@ -0,0 +1,50 @@ + + + Cyberiada-GraphML-1.0 + + + + + + + + + + + + + + + + + + + + + + SM + + formal + CGML_META + standardVersion/ 1.0 + +transitionOrder/ transitionFirst + +eventPropagation/ block + + + + + terminate + + + State + + + terminate + Local term + + + + + diff --git a/tests/15-output.txt b/tests/15-output.txt new file mode 100644 index 0000000..796926d --- /dev/null +++ b/tests/15-output.txt @@ -0,0 +1 @@ +Document: {id: '', name: '', format: 'Cyberiada-GraphML-1.0', meta: {standard version: '1.0', transition order: transition first, event propagation: block events}, elements: {State Machine: {id: 'G0', name: 'SM', elements: {Terminate: {id: 'n0'}, Composite State: {id: 'n1', name: 'State', elements: {Terminate: {id: 'n1::n0', name: 'Local term'}}}}}} diff --git a/tests/15-terminate.cpp b/tests/15-terminate.cpp new file mode 100644 index 0000000..b0e2da4 --- /dev/null +++ b/tests/15-terminate.cpp @@ -0,0 +1,57 @@ +/* ----------------------------------------------------------------------------- + * The Cyberiada GraphML C++ library implemention + * + * The test + * + * Copyright (C) 2024 Alexey Fedoseev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/ + * ----------------------------------------------------------------------------- */ + +#include +#include "cyberiadamlpp.h" +#include "testutils.h" + +using namespace Cyberiada; +using namespace std; + +int main(int argc, char** argv) +{ + Document d; + + StateMachine* sm = d.new_state_machine("SM"); + + d.new_terminate(sm); + try { + // check id uniqueness + d.new_terminate(sm, "n0", "name"); + } catch (const Cyberiada::ParametersException&){ + } + try { + // check non-empty name + d.new_terminate(sm, ""); + } catch (const Cyberiada::ParametersException&){ + } + + State* parent = d.new_state(sm, "State"); + d.new_terminate(parent, "Local term"); + + try { + cout << d << endl; + d.save(string(argv[0]) + ".graphml", formatCyberiada10); + } catch (const Cyberiada::Exception&) { + return 1; + } + return 0; +}