as2js: /home/snapwebsites/snapcpp/contrib/as2js/lib/db.cpp Source File

as2js  0.1.14
AlexScript to JavaScript
db.cpp
Go to the documentation of this file.
1 /* lib/db.cpp
2 
3 Copyright (c) 2005-2019 Made to Order Software Corp. All Rights Reserved
4 
6 
7 Permission is hereby granted, free of charge, to any
8 person obtaining a copy of this software and
9 associated documentation files (the "Software"), to
10 deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom
14 the Software is furnished to do so, subject to the
15 following conditions:
16 
17 The above copyright notice and this permission notice
18 shall be included in all copies or substantial
19 portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
23 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31 
32 */
33 
34 #include "db.h" // 100% private header
35 
36 #include "as2js/exceptions.h"
37 #include "as2js/message.h"
38 
39 
40 namespace as2js
41 {
42 
43 
44 
45 
46 
48  : f_element_name(element_name)
49  //, f_type("") -- auto-init
50  //, f_filename("") -- auto-init
51  //, f_line(1) -- auto-init
52  , f_element(element)
53 {
54  // verify the type, but we already tested before creating this object
55  JSON::JSONValue::type_t type(f_element->get_type());
57  {
58  throw exception_internal_error("an element cannot be created with a JSON value which has a type other than Object");
59  }
60 
61  // we got a valid database element object
62  JSON::JSONValue::object_t const& obj(f_element->get_object());
63  for(JSON::JSONValue::object_t::const_iterator it(obj.begin()); it != obj.end(); ++it)
64  {
65  JSON::JSONValue::type_t const sub_type(it->second->get_type());
66  String const field_name(it->first);
67  if(field_name == "type")
68  {
70  {
72  msg << "The type of an element in the database has to be a string.";
73  }
74  else
75  {
76  f_type = it->second->get_string();
77  }
78  }
79  else if(field_name == "filename")
80  {
82  {
84  msg << "The filename of an element in the database has to be a string.";
85  }
86  else
87  {
88  f_filename = it->second->get_string();
89  }
90  }
91  else if(field_name == "line")
92  {
94  {
96  msg << "The line of an element in the database has to be an integer.";
97  }
98  else
99  {
100  f_line = static_cast<Position::counter_t>(it->second->get_int64().get());
101  }
102  }
103  // else -- TBD: should we err on unknown fields?
104  }
105 }
106 
107 
109 {
110  f_type = type;
111  f_element->set_member("type", JSON::JSONValue::pointer_t(new JSON::JSONValue(f_element->get_position(), f_type)));
112 }
113 
114 
116 {
117  f_filename = filename;
118  f_element->set_member("filename", JSON::JSONValue::pointer_t(new JSON::JSONValue(f_element->get_position(), f_filename)));
119 }
120 
121 
123 {
124  f_line = line;
125  Int64 integer(f_line);
126  f_element->set_member("line", JSON::JSONValue::pointer_t(new JSON::JSONValue(f_element->get_position(), integer)));
127 }
128 
129 
131 {
132  return f_element_name;
133 }
134 
135 
137 {
138  return f_type;
139 }
140 
141 
143 {
144  return f_filename;
145 }
146 
147 
149 {
150  return f_line;
151 }
152 
153 
154 
155 
156 
157 
158 
160  : f_package_name(package_name)
161  , f_package(package)
162 {
163  // verify the type, but we already tested before creatin this object
164  JSON::JSONValue::type_t type(f_package->get_type());
166  {
167  throw exception_internal_error("a package cannot be created with a JSON value which has a type other than Object");
168  }
169 
170  // we got a valid database package object
171  JSON::JSONValue::object_t const& obj(f_package->get_object());
172  for(JSON::JSONValue::object_t::const_iterator it(obj.begin()); it != obj.end(); ++it)
173  {
174  // the only type of value that we expect are objects within the
175  // main object; each one represents a package
176  JSON::JSONValue::type_t const sub_type(it->second->get_type());
178  {
180  msg << "A database is expected to be an object of object packages composed of object elements.";
181  }
182  else
183  {
184  String element_name(it->first);
185  Element::pointer_t e(new Element(element_name, it->second));
186  f_elements[element_name] = e;
187  }
188  }
189 }
190 
191 
193 {
194  return f_package_name;
195 }
196 
197 
199 {
200  element_vector_t found;
201  for(auto it(f_elements.begin()); it != f_elements.end(); ++it)
202  {
203  if(match_pattern(it->first, pattern))
204  {
205  found.push_back(it->second);
206  }
207  }
208  return found;
209 }
210 
211 
213 {
214  auto it(f_elements.find(element_name));
215  if(it == f_elements.end())
216  {
217  return Element::pointer_t();
218  }
219  // it exists
220  return it->second;
221 }
222 
223 
225 {
226  auto e(get_element(element_name));
227  if(!e)
228  {
229  // some default position object to attach to the new objects
230  Position pos(f_package->get_position());
231 
232  JSON::JSONValue::object_t obj_element;
233  JSON::JSONValue::pointer_t new_element(new JSON::JSONValue(pos, obj_element));
234  e.reset(new Element(element_name, new_element));
235  f_elements[element_name] = e;
236 
237  f_package->set_member(element_name, new_element);
238  }
239  return e;
240 }
241 
242 
243 
244 
245 
246 
247 bool Database::load(String const& filename)
248 {
249  if(f_json)
250  {
251  // already loaded
252  return f_value.operator bool ();
253  }
254  f_filename = filename;
255  f_json.reset(new JSON);
256 
257  // test whether the file exists
259  if(!in->open(filename))
260  {
261  // no db yet... it is okay
262  Position pos;
263  pos.set_filename(filename);
264  JSON::JSONValue::object_t obj_database;
265  f_value.reset(new JSON::JSONValue(pos, obj_database));
266  f_json->set_value(f_value);
267  return true;
268  }
269 
270  // there is a db, load it
271  f_value = f_json->parse(in);
272  if(!f_value)
273  {
274  return false;
275  }
276 
277  JSON::JSONValue::type_t type(f_value->get_type());
278 
279  // a 'null' is acceptable, it means the database is currently empty
281  {
282  return true;
283  }
284 
286  {
287  Position pos;
288  pos.set_filename(filename);
290  msg << "A database must be defined as a JSON object, or set to 'null'.";
291  return false;
292  }
293 
294  // we found the database object
295  // typedef std::map<String, JSONValue::pointer_t> object_t;
296  JSON::JSONValue::object_t const& obj(f_value->get_object());
297  for(JSON::JSONValue::object_t::const_iterator it(obj.begin()); it != obj.end(); ++it)
298  {
299  // the only type of value that we expect are objects within the
300  // main object; each one represents a package
301  JSON::JSONValue::type_t sub_type(it->second->get_type());
303  {
304  Position pos;
305  pos.set_filename(filename);
307  msg << "A database is expected to be an object of object packages composed of elements.";
308  return false;
309  }
310 
311  String package_name(it->first);
312  Package::pointer_t p(new Package(package_name, it->second));
313  f_packages[package_name] = p;
314  }
315 
316  return true;
317 }
318 
319 
320 
321 void Database::save() const
322 {
323  // if it has been loaded, save it
324  if(f_json)
325  {
326  String const header("// Database used by the AS2JS Compiler (as2js)\n"
327  "//\n"
328  "// DO NOT EDIT UNLESS YOU KNOW WHAT YOU ARE DOING\n"
329  "// If you have a problem because of the database, just delete the file\n"
330  "// and the compiler will re-generate it.\n"
331  "//\n"
332  "// Copyright (c) 2005-2019 Made to Order Software Corp. All Rights Reserved.\n"
333  "// This file is written in UTF-8\n"
334  "// You can safely modify it with an editor supporting UTF-8\n"
335  "// The format is JSON:\n"
336  "//\n"
337  "// {\n"
338  "// \"package_name\": {\n"
339  "// \"element_name\": {\n"
340  "// \"filename\": \"<full path filename>\",\n"
341  "// \"line\": <line number>,\n"
342  "// \"type\": \"<type name>\"\n"
343  "// },\n"
344  "// <...other elements...>\n"
345  "// },\n"
346  "// <...other packages...>\n"
347  "// }\n"
348  "//");
349  f_json->save(f_filename, header);
350  }
351 }
352 
353 
355 {
356  package_vector_t found;
357  for(auto it(f_packages.begin()); it != f_packages.end(); ++it)
358  {
359  if(match_pattern(it->first, pattern))
360  {
361  found.push_back(it->second);
362  }
363  }
364  return found;
365 }
366 
367 
369 {
370  auto p(f_packages.find(package_name));
371  if(p == f_packages.end())
372  {
374  }
375  return p->second;
376 }
377 
378 
380 {
381  auto p(get_package(package_name));
382  if(!p)
383  {
384  if(!f_json)
385  {
386  throw exception_internal_error("attempting to add a package to the database before the database was loaded");
387  }
388 
389  // some default position object to attach to the new objects
390  Position pos;
392 
393  // create the database object if not there yet
394  if(!f_value)
395  {
396  JSON::JSONValue::object_t obj_database;
397  f_value.reset(new JSON::JSONValue(pos, obj_database));
398  f_json->set_value(f_value);
399  }
400 
401  JSON::JSONValue::object_t obj_package;
402  JSON::JSONValue::pointer_t new_package(new JSON::JSONValue(pos, obj_package));
403  p.reset(new Package(package_name, new_package));
404  f_packages[package_name] = p;
405 
406  f_value->set_member(package_name, new_package);
407  }
408  return p;
409 }
410 
411 
412 bool Database::match_pattern(String const& name, String const& pattern)
413 {
414  struct for_sub_function
415  {
416  static bool do_match(as_char_t const *name, as_char_t const *pattern)
417  {
418  for(; *pattern != '\0'; ++pattern, ++name)
419  {
420  if(*pattern == '*')
421  {
422  // quick optimization, remove all the '*' if there are
423  // multiple (although that should probably be an error!)
424  do
425  {
426  ++pattern;
427  }
428  while(*pattern == '*');
429  if(*pattern == '\0')
430  {
431  return true;
432  }
433  while(*name != '\0')
434  {
435  if(do_match(name, pattern)) // recursive call
436  {
437  return true;
438  }
439  ++name;
440  }
441  return false;
442  }
443  if(*name != *pattern)
444  {
445  return false;
446  }
447  }
448 
449  // end of name and pattern must match if you did not
450  // end the pattern with an asterisk
451  return *name == '\0';
452  }
453  };
454 
455  // we want to use a recursive function and use bare pointers
456  // because it really simplifies the algorithm...
457  return for_sub_function::do_match(name.c_str(), pattern.c_str());
458 }
459 
460 
461 
462 
463 }
464 // namespace as2js
465 
466 // vim: ts=4 sw=4 et
int32_t as_char_t
Definition: string.h:47
JSON::JSONValue::pointer_t f_package
Definition: db.h:108
package_map_t f_packages
Definition: db.h:128
bool load(String const &filename)
Definition: db.cpp:247
String const f_element_name
Definition: db.h:82
std::map< String, JSONValue::pointer_t > object_t
Definition: json.h:73
JSON::JSONValue::pointer_t f_value
Definition: db.h:126
std::shared_ptr< Element > pointer_t
Definition: db.h:68
Package::pointer_t get_package(String const &package_name) const
Definition: db.cpp:368
void set_type(String const &type)
Definition: db.cpp:108
void set_filename(String const &filename)
Definition: db.cpp:115
JSON::pointer_t f_json
Definition: db.h:125
String f_filename
Definition: db.h:124
std::shared_ptr< Package > pointer_t
Definition: db.h:95
Element::pointer_t get_element(String const &element_name) const
Definition: db.cpp:212
String get_type() const
Definition: db.cpp:136
std::vector< Package::pointer_t > package_vector_t
Definition: db.h:112
Element(String const &element_name, JSON::JSONValue::pointer_t element)
Definition: db.cpp:47
String get_filename() const
Definition: db.cpp:142
void set_line(Position::counter_t line)
Definition: db.cpp:122
int32_t counter_t
Definition: position.h:47
String get_element_name() const
Definition: db.cpp:130
Element::pointer_t add_element(String const &element_name)
Definition: db.cpp:224
String const f_package_name
Definition: db.h:106
JSON::JSONValue::pointer_t f_element
Definition: db.h:87
std::shared_ptr< JSONValue > pointer_t
Definition: json.h:71
static bool match_pattern(String const &name, String const &pattern)
Definition: db.cpp:412
String get_package_name() const
Definition: db.cpp:192
String f_filename
Definition: db.h:84
The AlexScript to JavaScript namespace.
Definition: compiler.cpp:37
void save() const
Definition: db.cpp:321
Package(String const &package_name, JSON::JSONValue::pointer_t package)
Definition: db.cpp:159
std::shared_ptr< FileInput > pointer_t
Definition: stream.h:202
element_map_t f_elements
Definition: db.h:109
Package::pointer_t add_package(String const &package_name)
Definition: db.cpp:379
Position::counter_t get_line() const
Definition: db.cpp:148
std::vector< Element::pointer_t > element_vector_t
Definition: db.h:90
element_vector_t find_elements(String const &pattern) const
Definition: db.cpp:198
package_vector_t find_packages(String const &pattern) const
Definition: db.cpp:354
void set_filename(String const &filename)
Set the filename being read.
Definition: position.cpp:52
Position::counter_t f_line
Definition: db.h:85

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.

Syndicate content

Snap! Websites
An Open Source CMS System in C++

Contact Us Directly