2020#include < fstream>
2121#include < nlohmann/json.hpp>
2222#include < spdlog/spdlog.h>
23- #include " parser/hawk/scoped_template_builder/scoped_template_builder .h"
23+ #include " lsp.pb .h"
2424#include " plugin_system/plugin_system.h"
2525
2626namespace aaltitoad ::hawk::huppaal {
27+ // TODO: Move the sections into a separate file each
28+ diagnostic json_error (const std::string& filepath, const std::string& err) {
29+ return {
30+ .identifier =" json_error" ,
31+ .title =" JSON error in file: " + filepath,
32+ .message =" unable to parse json: " + err,
33+ .description =" JSON model files must be of a specific format" , // TODO: jsomschema validation
34+ .severity =Severity::SEVERITY_ERROR
35+ };
36+ }
37+
38+ static diagnostic no_main{
39+ .identifier =" no_main" ,
40+ .title =" No main template" ,
41+ .message =" Could not find a template marked as \" main\" " ,
42+ .description =" A valid network of TTAs must have at least one template marked as the main template" ,
43+ .severity =Severity::SEVERITY_ERROR
44+ };
45+
46+ /* =============================== */
47+
48+ auto any_errors (const std::vector<Diagnostic>& ds) -> bool {
49+ for (auto & d : ds)
50+ if (d.severity () == Severity::SEVERITY_ERROR)
51+ return true ;
52+ return false ;
53+ }
54+
2755 auto huppaal_scanner::scan (compiler& ctx, const std::vector<std::string>& filepaths, const std::vector<std::string>& ignore_list) const noexcept -> std::expected<scanner::ok, error_t> {
28- return std::unexpected (error_t ({ctx.diag (not_implemented_yet ())}));
29- scoped_template_builder builder{};
56+ std::vector<Diagnostic> diagnostics{};
57+ std::vector<scanning::template_t > templates{};
58+ std::vector<std::string> extra_declarations{};
3059 for (const auto & filepath : filepaths) {
3160 for (const auto &entry: std::filesystem::directory_iterator (filepath)) {
3261 try {
@@ -42,18 +71,136 @@ namespace aaltitoad::hawk::huppaal {
4271 /* ignore_comments */ true );
4372 if (json_file.contains (" name" )) {
4473 spdlog::trace (" loading file {0}" , entry.path ().c_str ());
45- builder. add_template (json_file. get <tta_template>( ));
74+ templates. push_back ( scan_template (entry. path (), json_file ));
4675 } else if (json_file.contains (" parts" )) {
4776 spdlog::trace (" loading parts file {0}" , entry.path ().c_str ());
48- builder. add_global_symbols (json_file. at ( " parts " ). get <std::vector< part_t >>( ));
77+ extra_declarations. push_back ( scan_parts (json_file ));
4978 } else
5079 spdlog::trace (" ignoring file {0} (not a valid model file)" , entry.path ().c_str ());
5180 } catch (std::exception& e) {
5281 spdlog::error (" unable to parse json file {0}: {1}" , entry.path ().c_str (), e.what ());
53- throw ;
82+ diagnostics. push_back (ctx. get_diagnostic_factory (). without_context (). create_diagnostic ( json_error (entry. path (), e. what ()))) ;
5483 }
5584 }
5685 }
86+
87+ if (!extra_declarations.empty ()) {
88+ auto main = std::find_if (templates.begin (), templates.end (), [](const scanning::template_t & t) {
89+ return std::find_if (t.modifiers .begin (), t.modifiers .end (), [](const std::string& m) {
90+ return m == " main" ;
91+ }) != t.modifiers .end ();
92+ });
93+ if (main != templates.end ())
94+ main->declarations .insert (main->declarations .end (), extra_declarations.begin (), extra_declarations.end ());
95+ }
96+ return scanner::ok{
97+ .templates =templates,
98+ .diagnostics =diagnostics
99+ };
100+ }
101+
102+ auto scan_vertex (const nlohmann::json& t) -> scanning::vertex {
103+ std::string type{};
104+ std::vector<std::string> modifiers{};
105+ std::string tt = lower_case (t[" type" ]);
106+ if (tt == " normal" )
107+ type = " location" ;
108+ if (tt == " initial" ) {
109+ type = " location" ;
110+ modifiers.push_back (" initial" );
111+ }
112+ if (tt == " final" ) {
113+ type = " location" ;
114+ modifiers.push_back (" final" );
115+ }
116+ return scanning::vertex{
117+ .identifer =t[" id" ],
118+ .type =type,
119+ .modifiers =modifiers,
120+ .debug ={
121+ .name =t[" nickname" ],
122+ .position =position{
123+ .x =t[" x" ],
124+ .y =t[" y" ]
125+ }
126+ }
127+ };
128+ }
129+
130+ auto scan_edge (const nlohmann::json& t) -> scanning::edge {
131+ std::optional<std::string> guard{};
132+ if (t[" guard" ] != " " )
133+ guard = t[" guard" ];
134+ std::optional<std::string> update{};
135+ if (t[" update" ] != " " )
136+ guard = t[" update" ];
137+ return scanning::edge{
138+ .identifier =t[" uuid" ],
139+ .source =t[" source_location" ],
140+ .guard =guard,
141+ .update =update,
142+ .target =t[" target_location" ],
143+ .debug ={}
144+ };
145+ }
146+
147+ auto huppaal_scanner::scan_template (const std::string& filepath, const nlohmann::json& t) const -> scanning::template_t {
148+ std::vector<scanning::vertex> vertices{};
149+ for (auto & v : t[" vertices" ])
150+ vertices.push_back (scan_vertex (v));
151+ vertices.push_back (scan_vertex (t[" initial_location" ]));
152+ vertices.push_back (scan_vertex (t[" final_location" ]));
153+
154+ std::vector<scanning::edge> edges{};
155+ for (auto & e : t[" edges" ])
156+ edges.push_back (scan_edge (e));
157+
158+ std::vector<std::string> declarations{};
159+ declarations.push_back (t[" declarations" ]);
160+
161+ std::vector<std::string> modifiers{};
162+ if (t[" main" ].is_boolean () && t[" main" ] == true )
163+ modifiers.push_back (" main" );
164+
165+ return scanning::template_t {
166+ .identifier =ya::uuid_v4 (),
167+ .signature =t[" name" ],
168+ .declarations =declarations,
169+ .vertices =vertices,
170+ .edges =edges,
171+ .modifiers =modifiers,
172+ .debug ={
173+ .name =t[" name" ],
174+ .filepath =filepath
175+ }
176+ };
177+ }
178+
179+ auto scan_part (const nlohmann::json& p) -> std::string {
180+ std::string id = p[" ID" ];
181+ std::string type = lower_case (p[" Type" ]);
182+ if (p.contains (" ValueType" ))
183+ type = lower_case (p[" ValueType" ]);
184+ nlohmann::json initial_value{};
185+ if (type == " timer" )
186+ initial_value = 0 ;
187+ if (p.contains (" Value" ))
188+ initial_value = p[" Value" ];
189+
190+ // TODO: consider adding an "external/extern" keyword to expr.
191+ std::stringstream ss{};
192+ if (type == " timer" ) // TODO: https://github.com/sillydan1/expr/issues/21
193+ ss << " public " << type << " " << id << " := 0_ms ;" ;
194+ else
195+ ss << " public " << type << " " << id << " := " << initial_value << " ;" ;
196+ return ss.str ();
197+ }
198+
199+ auto huppaal_scanner::scan_parts (const nlohmann::json& t) const -> std::string {
200+ std::stringstream ss{};
201+ for (auto & p : t[" parts" ])
202+ ss << scan_part (p) << " \n " ;
203+ return ss.str ();
57204 }
58205
59206 auto huppaal_scanner::should_ignore (const std::filesystem::directory_entry& entry, const std::vector<std::string>& ignore_list) const -> bool {
@@ -109,7 +256,7 @@ extern "C" {
109256 }
110257
111258 const char * get_plugin_version () {
112- return " v1.1 .0" ;
259+ return " v2.0 .0" ;
113260 }
114261
115262 plugin_type get_plugin_type () {
0 commit comments