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

as2js  0.1.14
AlexScript to JavaScript
compiler_package.cpp
Go to the documentation of this file.
1 /* lib/compiler_package.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 "as2js/compiler.h"
35 
36 #include "as2js/exceptions.h"
37 #include "as2js/message.h"
38 #include "as2js/parser.h"
39 
40 // private classes
41 #include "db.h"
42 #include "rc.h"
43 
44 #include <algorithm>
45 
46 #include <dirent.h>
47 #include <cstring>
48 
49 
50 namespace as2js
51 {
52 
53 
54 namespace
55 {
56 
57 
58 // The following globals are read only once and you can compile
59 // many times without having to reload them.
60 //
61 // the resource file information
62 //
64 
65 // the global imports (those which are automatic and
66 // define the intrinsic functions and types of the language)
67 //
69 
70 // the system imports (this is specific to the system you
71 // are using this compiler for; it defines the system)
72 //
74 
75 // the native imports (this is specific to your system
76 // environment, it defines objects in your environment)
77 //
79 
80 // the database handling all the packages and their name
81 // so we can quickly find which package to import when
82 // a given name is used
83 //
85 
86 // whether the database was loaded (true) or not (false)
87 //
88 bool g_db_loaded = false;
89 
90 // Search for a named element:
91 // <package name>{.<package name>}.<class, function, variable name>
92 // TODO: add support for '*' in <package name>
93 Database::Element::pointer_t find_element(String const& package_name, String const& element_name, char const *type)
94 {
95  Database::package_vector_t packages(g_db->find_packages(package_name));
96  for(auto pt(packages.begin()); pt != packages.end(); ++pt)
97  {
98  Database::element_vector_t elements((*pt)->find_elements(element_name));
99  for(auto et(elements.begin()); et != elements.end(); ++et)
100  {
101  if(!type
102  || (*et)->get_type() == type)
103  {
104  return *et;
105  }
106  }
107  }
108 
110 }
111 
112 
113 void add_element(String const& package_name, String const& element_name, Node::pointer_t element, char const *type)
114 {
115  Database::Package::pointer_t p(g_db->add_package(package_name));
116  Database::Element::pointer_t e(p->add_element(element_name));
117  e->set_type(type);
118  e->set_filename(element->get_position().get_filename());
119  e->set_line(element->get_position().get_line());
120 }
121 
122 
123 }
124 // no name namespace
125 
126 
127 
128 
129 
130 
131 
135 String Compiler::get_package_filename(char const *package_info)
136 {
137  for(int cnt(0); *package_info != '\0';)
138  {
139  ++package_info;
140  if(package_info[-1] == ' ')
141  {
142  ++cnt;
143  if(cnt >= 3)
144  {
145  break;
146  }
147  }
148  }
149  if(*package_info != '"')
150  {
151  return "";
152  }
153  ++package_info;
154  char const *name = package_info;
155  while(*package_info != '"' && *package_info != '\0')
156  {
157  ++package_info;
158  }
159 
160  String result;
161  result.from_utf8(name, package_info - name);
162 
163  return result;
164 }
165 
166 
186 bool Compiler::find_module(String const& filename, Node::pointer_t& result)
187 {
188  // module already loaded?
189  module_map_t::const_iterator existing_module(f_modules.find(filename));
190  if(existing_module != f_modules.end())
191  {
192  result = existing_module->second;
193  return true;
194  }
195 
196  // we could not find this module, try to load it
197  Input::pointer_t in;
199  {
200  in = f_input_retriever->retrieve(filename);
201  }
202  if(!in)
203  {
204  in.reset(new FileInput());
205  // 'in' is just a 'class Input' so we need to cast
206  if(!static_cast<FileInput&>(*in).open(filename))
207  {
209  msg << "cannot open module file \"" << filename << "\".";
210  throw exception_exit(1, "cannot open module file");
211  }
212  }
213 
214  // Parse the file in result
215  Parser::pointer_t parser(new Parser(in, f_options));
216  result = parser->parse();
217  parser.reset();
218 
219 #if 0
220 //std::cerr << "+++++\n \"" << filename << "\" module:\n" << *result << "\n+++++\n";
221 std::cerr << "+++++++++++++++++++++++++++ Loading \"" << filename << "\" +++++++++++++++++++++++++++++++\n";
222 #endif
223 
224  if(!result)
225  {
227  msg << "could not compile module file \"" << filename << "\".";
228  throw exception_exit(1, "could not compile module file");
229  }
230 
231  // save the newly loaded module
232  f_modules[filename] = result;
233 
234  return true;
235 }
236 
237 
238 
258 Node::pointer_t Compiler::load_module(char const *module, char const *file)
259 {
260  // create the path to the module
261  String path(g_rc.get_scripts());
262  path += "/";
263  path += module;
264  path += "/";
265  path += file;
266 
267  Node::pointer_t result;
268  find_module(path, result);
269  return result;
270 }
271 
272 
273 
274 
275 void Compiler::find_packages_add_database_entry(String const & package_name, Node::pointer_t & element, char const * type)
276 {
277  // here, we totally ignore internal, private
278  // and false entries right away
282  {
283  return;
284  }
285 
286  add_element(package_name, element->get_string(), element, type);
287 }
288 
289 
290 
291 // This function searches a list of directives for class, functions
292 // and variables which are defined in a package. Their names are
293 // then saved in the import database for fast search.
295 {
296  size_t const max_children(package->get_children_size());
297  for(size_t idx = 0; idx < max_children; ++idx)
298  {
299  Node::pointer_t child(package->get_child(idx));
300  if(child->get_type() == Node::node_t::NODE_DIRECTIVE_LIST)
301  {
302  find_packages_save_package_elements(child, package_name); // recursive
303  }
304  else if(child->get_type() == Node::node_t::NODE_CLASS)
305  {
307  package_name,
308  child,
309  "class"
310  );
311  }
312  else if(child->get_type() == Node::node_t::NODE_FUNCTION)
313  {
314  // we do not save prototypes, that is tested later
315  char const * type;
316  if(child->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_GETTER))
317  {
318  type = "getter";
319  }
320  else if(child->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_SETTER))
321  {
322  type = "setter";
323  }
324  else
325  {
326  type = "function";
327  }
329  package_name,
330  child,
331  type
332  );
333  }
334  else if(child->get_type() == Node::node_t::NODE_VAR)
335  {
336  size_t const vcnt(child->get_children_size());
337  for(size_t v(0); v < vcnt; ++v)
338  {
339  Node::pointer_t variable_node(child->get_child(v));
340  // we do not save the variable type,
341  // it would not help resolution
343  package_name,
344  variable_node,
345  "variable"
346  );
347  }
348  }
349  else if(child->get_type() == Node::node_t::NODE_PACKAGE)
350  {
351  // sub packages
352  Node::pointer_t list(child->get_child(0));
353  String name(package_name);
354  name += ".";
355  name += child->get_string();
356  find_packages_save_package_elements(list, name); // recursive
357  }
358  }
359 }
360 
361 
362 // this function searches the tree for packages (it stops at classes,
363 // functions, and other such blocks)
365 {
366  size_t const max_children(list->get_children_size());
367  for(size_t idx(0); idx < max_children; ++idx)
368  {
369  Node::pointer_t child(list->get_child(idx));
370  if(child->get_type() == Node::node_t::NODE_DIRECTIVE_LIST)
371  {
373  }
374  else if(child->get_type() == Node::node_t::NODE_PACKAGE)
375  {
376  // Found a package! Save all the functions
377  // variables and classes in the database
378  // if not there yet.
379  Node::pointer_t directive_list_node(child->get_child(0));
380  find_packages_save_package_elements(directive_list_node, child->get_string());
381  }
382  }
383 }
384 
385 
387 {
388  if(program_node->get_type() != Node::node_t::NODE_PROGRAM)
389  {
390  return;
391  }
392 
393  find_packages_directive_list(program_node);
394 }
395 
396 
397 void Compiler::load_internal_packages(char const *module)
398 {
399  // TODO: create sub-class to handle the directory
400 
401  std::string path(g_rc.get_scripts().to_utf8());
402  path += "/";
403  path += module;
404  DIR *dir(opendir(path.c_str()));
405  if(dir == nullptr)
406  {
407  // could not read this directory
408  Position pos;
409  pos.set_filename(path);
411  msg << "cannot read directory \"" << path << "\".\n";
412  throw exception_exit(1, "cannot read directory");
413  }
414 
415  for(;;)
416  {
417  struct dirent *ent(readdir(dir));
418  if(!ent)
419  {
420  // no more files in directory
421  break;
422  }
423  char const *s = ent->d_name;
424  char const *e = nullptr; // extension position
425  while(*s != '\0')
426  {
427  if(*s == '.')
428  {
429  e = s;
430  }
431  s++;
432  }
433  // only interested by .js files except
434  // the as2js_init.js file
435  if(e == nullptr || strcmp(e, ".js") != 0
436  || strcmp(ent->d_name, "as2js_init.js") == 0)
437  {
438  continue;
439  }
440  // we got a file of interest
441  // TODO: we want to keep this package in RAM since
442  // we already parsed it!
443  Node::pointer_t p(load_module(module, ent->d_name));
444  // now we can search the package in the actual code
445  find_packages(p);
446  }
447 
448  // avoid leaks
449  closedir(dir);
450 }
451 
452 
454 {
455  // If we have the IMPLEMENTS flag set, then we must make sure
456  // that the corresponding package is compiled.
457  if(!import_node->get_flag(Node::flag_t::NODE_IMPORT_FLAG_IMPLEMENTS))
458  {
459  return;
460  }
461 
462  // find the package
463  Node::pointer_t package;
464 
465  // search in this program
466  package = find_package(f_program, import_node->get_string());
467  if(!package)
468  {
469  // not in this program, search externals
470  Node::pointer_t program_node;
471  String any_name("*");
472  if(find_external_package(import_node, any_name, program_node))
473  {
474  // got externals, search those now
475  package = find_package(program_node, import_node->get_string());
476  }
477  if(!package)
478  {
480  msg << "cannot find package '" << import_node->get_string() << "'.";
481  return;
482  }
483  }
484 
485  // make sure it is compiled (once)
486  bool const was_referenced(package->get_flag(Node::flag_t::NODE_PACKAGE_FLAG_REFERENCED));
487  package->set_flag(Node::flag_t::NODE_PACKAGE_FLAG_REFERENCED, true);
488  if(!was_referenced)
489  {
490  directive_list(package);
491  }
492 }
493 
494 
495 
496 
497 
498 
500 {
501  NodeLock ln(list);
502  size_t const max_children(list->get_children_size());
503  for(size_t idx(0); idx < max_children; ++idx)
504  {
505  Node::pointer_t child(list->get_child(idx));
506  if(child->get_type() == Node::node_t::NODE_DIRECTIVE_LIST)
507  {
508  Node::pointer_t package(find_package(child, name)); // recursive
509  if(package)
510  {
511  return package;
512  }
513  }
514  else if(child->get_type() == Node::node_t::NODE_PACKAGE)
515  {
516  if(child->get_string() == name)
517  {
518  // found it!
519  return child;
520  }
521  }
522  }
523 
524  // not found
525  return Node::pointer_t();
526 }
527 
528 
529 bool Compiler::find_external_package(Node::pointer_t import_node, String const& name, Node::pointer_t& program_node)
530 {
531  // search a package which has an element named 'name'
532  // and has a name which match the identifier specified in 'import'
533  Database::Element::pointer_t e(find_element(import_node->get_string(), name, nullptr));
534  if(!e)
535  {
536  // not found!
537  return false;
538  }
539 
540  String const filename(e->get_filename());
541 
542  // found it, lets get a node for it
543  find_module(filename, program_node);
544 
545  // at this time this will not happen because if the find_module()
546  // function fails, it throws exception_exit(1, ...);
547  if(!program_node)
548  {
549  return false;
550  }
551 
552  return true;
553 }
554 
555 
556 bool Compiler::check_import(Node::pointer_t& import_node, Node::pointer_t& resolution, String const& name, Node::pointer_t params, int search_flags)
557 {
558  // search for a package within this program
559  // (I am not too sure, but according to the spec. you can very well
560  // have a package within any script file)
561  if(find_package_item(f_program, import_node, resolution, name, params, search_flags))
562  {
563  return true;
564  }
565 
566  Node::pointer_t program_node;
567  if(!find_external_package(import_node, name, program_node))
568  {
569  return false;
570  }
571 
572  return find_package_item(program_node, import_node, resolution, name, params, search_flags | SEARCH_FLAG_PACKAGE_MUST_EXIST);
573 }
574 
575 
576 bool Compiler::find_package_item(Node::pointer_t program_node, Node::pointer_t import_node, Node::pointer_t& resolution, String const& name, Node::pointer_t params, int const search_flags)
577 {
578  Node::pointer_t package_node(find_package(program_node, import_node->get_string()));
579 
580  if(!package_node)
581  {
582  if((search_flags & SEARCH_FLAG_PACKAGE_MUST_EXIST) != 0)
583  {
584  // this is a bad error! we should always find the
585  // packages in this case (i.e. when looking using the
586  // database.)
588  msg << "cannot find package '" << import_node->get_string() << "' in any of the previously registered packages.";
589  throw exception_exit(1, "cannot find package");
590  }
591  return false;
592  }
593 
594  if(package_node->get_children_size() == 0)
595  {
596  return false;
597  }
598 
599  // setup labels (only the first time around)
600  if(!package_node->get_flag(Node::flag_t::NODE_PACKAGE_FLAG_FOUND_LABELS))
601  {
602  package_node->set_flag(Node::flag_t::NODE_PACKAGE_FLAG_FOUND_LABELS, true);
603  Node::pointer_t child(package_node->get_child(0));
604  find_labels(package_node, child);
605  }
606 
607  // search the name of the class/function/variable we're
608  // searching for in this package:
609 
610  // TODO: Hmmm... could we have the actual node instead?
611  Node::pointer_t id(package_node->create_replacement(Node::node_t::NODE_IDENTIFIER));
612  id->set_string(name);
613 
614  int funcs = 0;
615  if(!find_field(package_node, id, funcs, resolution, params, search_flags))
616  {
617  return false;
618  }
619 
620  // TODO: Can we have an empty resolution here?!
621  if(resolution)
622  {
624  {
625  // it is private, we cannot use this item
626  // from outside whether it is in the
627  // package or a sub-class
628  return false;
629  }
630 
632  {
633  // it is internal we can only use it from
634  // another package
635  Node::pointer_t parent(import_node);
636  for(;;)
637  {
638  parent = parent->get_parent();
639  if(!parent)
640  {
641  return false;
642  }
643  if(parent->get_type() == Node::node_t::NODE_PACKAGE)
644  {
645  // found the package mark
646  break;
647  }
648  if(parent->get_type() == Node::node_t::NODE_ROOT
649  || parent->get_type() == Node::node_t::NODE_PROGRAM)
650  {
651  return false;
652  }
653  }
654  }
655  }
656 
657  // make sure it is compiled (once)
658  bool const was_referenced(package_node->get_flag(Node::flag_t::NODE_PACKAGE_FLAG_REFERENCED));
659  package_node->set_flag(Node::flag_t::NODE_PACKAGE_FLAG_REFERENCED, true);
660  if(!was_referenced)
661  {
662  directive_list(package_node);
663  }
664 
665  return true;
666 }
667 
668 
670 {
671  if(!g_native_import)
672  {
673  // read the resource file
674  g_rc.init_rc(static_cast<bool>(f_input_retriever));
675 
676  // TBD: at this point we only have native scripts
677  // we need browser scripts, for sure...
678  // and possibly some definitions of extensions such as jQuery
679  // however, at this point we do not have a global or system
680  // set of modules
681  //g_global_import = load_module("global", "as_init.js");
682  //g_system_import = load_module("system", "as_init.js");
683  g_native_import = load_module("native", "as_init.js");
684  }
685 
686  if(!g_db)
687  {
688  g_db.reset(new Database);
689  }
690  if(!g_db->load(g_rc.get_db()))
691  {
693  msg << "Failed reading the compiler database. You may need to delete it and try again or fix the resource file to point to the right file.";
694  return;
695  }
696 
697  if(!g_db_loaded)
698  {
699  g_db_loaded = true;
700 
701  // global defines the basic JavaScript classes such
702  // as Object and String.
703  //load_internal_packages("global");
704 
705  // the system defines Browser classes such as XMLNode
706  //load_internal_packages("system");
707 
708  // the ECMAScript low level definitions
709  load_internal_packages("native");
710 
711  // this saves the internal packages info for fast query
712  // on next invocations
713  g_db->save();
714  }
715 }
716 
717 
718 bool Compiler::check_name(Node::pointer_t list, int idx, Node::pointer_t& resolution, Node::pointer_t id, Node::pointer_t params, int const search_flags)
719 {
720  if(static_cast<size_t>(idx) >= list->get_children_size())
721  {
722  throw exception_internal_error(std::string("Compiler::check_name() index too large for this list."));
723  }
724 
725  Node::pointer_t child(list->get_child(idx));
726 
727  // turned off?
728  //if(get_attribute(child, Node::attribute_t::NODE_ATTR_FALSE))
729  //{
730  // return false;
731  //}
732 
733  bool result = false;
734 //std::cerr << " +--> compiler_package.cpp: check_name() processing a child node type: \"" << child->get_type_name() << "\" ";
735 //if(child->get_type() == Node::node_t::NODE_CLASS
736 //|| child->get_type() == Node::node_t::NODE_PACKAGE
737 //|| child->get_type() == Node::node_t::NODE_IMPORT
738 //|| child->get_type() == Node::node_t::NODE_ENUM
739 //|| child->get_type() == Node::node_t::NODE_FUNCTION)
740 //{
741 // std::cerr << " \"" << child->get_string() << "\"";
742 //}
743 //std::cerr << "\n";
744  switch(child->get_type())
745  {
746  case Node::node_t::NODE_VAR: // a VAR is composed of VARIABLEs
747  {
748  NodeLock ln(child);
749  size_t const max_children(child->get_children_size());
750  for(size_t j(0); j < max_children; ++j)
751  {
752  Node::pointer_t variable_node(child->get_child(j));
753  if(variable_node->get_string() == id->get_string())
754  {
755  // that is a variable!
756  // make sure it was parsed
757  if((search_flags & SEARCH_FLAG_NO_PARSING) == 0)
758  {
759  variable(variable_node, false);
760  }
761  if(params)
762  {
763  // check whether we are in a call
764  // because if we are the resolution
765  // is the "()" operator instead
766  }
767  resolution = variable_node;
768  result = true;
769  break;
770  }
771  }
772  }
773  break;
774 
776 //std::cerr << " +--> param = " << child->get_string() << " against " << id->get_string() << "\n";
777  if(child->get_string() == id->get_string())
778  {
779  resolution = child;
780  resolution->set_flag(Node::flag_t::NODE_PARAM_FLAG_REFERENCED, true);
781  return true;
782  }
783  break;
784 
786 //std::cerr << " +--> name = " << child->get_string() << "\n";
787  {
788  Node::pointer_t the_class;
789  if(is_constructor(child, the_class))
790  {
791  // this is a special case as the function name is the same
792  // as the class name and the type resolution is thus the
793  // class and not the function and we have to catch this
794  // special case otherwise we get a never ending loop
795  if(the_class->get_string() == id->get_string())
796  {
797  // just in case we replace the child pointer so we
798  // avoid potential side effects of having a function
799  // declaration in the child pointer
800  child = the_class;
801  resolution = the_class;
802  result = true;
803 //std::cerr << " +--> this was a class! => " << child->get_string() << "\n";
804  }
805  }
806  else
807  {
808  result = check_function(child, resolution, id->get_string(), params, search_flags);
809  }
810  }
811  break;
812 
815  if(child->get_string() == id->get_string())
816  {
817  // That is a class name! (good for a typedef, etc.)
818  resolution = child;
819  Node::pointer_t type(resolution->get_type_node());
820 //std::cerr << " +--> so we got a type of CLASS or INTERFACE for " << id->get_string()
821 // << " ... [" << (type ? "has a current type ptr" : "no current type ptr") << "]\n";
822  if(!type)
823  {
824  // A class (interface) represents itself as far as type goes (TBD)
825  resolution->set_type_node(child);
826  }
827  resolution->set_flag(Node::flag_t::NODE_IDENTIFIER_FLAG_TYPED, true);
828  result = true;
829  }
830  break;
831 
833  {
834  // first we check whether the name of the enum is what
835  // is being referenced (i.e. the type)
836  if(child->get_string() == id->get_string())
837  {
838  resolution = child;
839  resolution->set_flag(Node::flag_t::NODE_ENUM_FLAG_INUSE, true);
840  return true;
841  }
842 
843  // inside an enum we have references to other
844  // identifiers of that enum and these need to be
845  // checked here
846  size_t const max(child->get_children_size());
847  for(size_t j(0); j < max; ++j)
848  {
849  Node::pointer_t entry(child->get_child(j));
850  if(entry->get_type() == Node::node_t::NODE_VARIABLE)
851  {
852  if(entry->get_string() == id->get_string())
853  {
854  // this cannot be a function, right? so the following
855  // call is probably not really useful
856  resolution = entry;
857  resolution->set_flag(Node::flag_t::NODE_VARIABLE_FLAG_INUSE, true);
858  return true;
859  }
860  }
861  }
862  }
863  break;
864 
866  if(child->get_string() == id->get_string())
867  {
868  // That is a package... we have to see packages
869  // like classes, to search for more, you need
870  // to search inside this package and none other.
871  resolution = child;
872  return true;
873  }
874 #if 0
875  // TODO: auto-import? this works, but I do not think we
876  // want an automatic import of even internal packages?
877  // do we?
878  //
879  // At this point I would say that we do for the
880  // internal packages only. That being said, the
881  // Google closure compiler does that for all
882  // browser related declarations.
883  //
884  // if it is not the package itself, it could be an
885  // element inside the package
886  {
887  int funcs(0);
888  if(!find_field(child, id, funcs, resolution, params, search_flags))
889  {
890  break;
891  }
892  }
893  result = true;
894 //std::cerr << "Found inside package! [" << id->get_string() << "]\n";
895  if(!child->get_flag(Node::flag_t::NODE_PACKAGE_FLAG_REFERENCED))
896  {
897 //std::cerr << "Compile package now!\n";
898  directive_list(child);
900  }
901 #endif
902  break;
903 
905  return check_import(child, resolution, id->get_string(), params, search_flags);
906 
907  default:
908  // ignore anything else for now
909  break;
910 
911  }
912 
913  if(!result)
914  {
915  return false;
916  }
917 
918  if(!resolution)
919  {
920  // this is kind of bad since we cannot test for
921  // the scope...
922  return true;
923  }
924 
925 //std::cerr << " +--> yeah! resolved ID " << reinterpret_cast<long *>(resolution.get()) << "\n";
926 //std::cerr << " +--> check_name(): private?\n";
928  {
929 //std::cerr << " +--> check_name(): resolved private...\n";
930  // Note that an interface and a package
931  // can also have private members
932  Node::pointer_t the_resolution_class(class_of_member(resolution));
933  if(!the_resolution_class)
934  {
936  resolution.reset();
937  return false;
938  }
939  if(the_resolution_class->get_type() == Node::node_t::NODE_PACKAGE)
940  {
942  resolution.reset();
943  return false;
944  }
945  if(the_resolution_class->get_type() != Node::node_t::NODE_CLASS
946  && the_resolution_class->get_type() != Node::node_t::NODE_INTERFACE)
947  {
949  resolution.reset();
950  return false;
951  }
952  Node::pointer_t the_id_class(class_of_member(id));
953  if(!the_id_class)
954  {
956  resolution.reset();
957  return false;
958  }
959  if(the_id_class != the_resolution_class)
960  {
962  resolution.reset();
963  return false;
964  }
965  }
966 
968  {
969 //std::cerr << " +--> check_name(): resolved protected...\n";
970  // Note that an interface can also have protected members
971  Node::pointer_t the_super_class;
972  if(!are_objects_derived_from_one_another(id, resolution, the_super_class))
973  {
974  if(the_super_class
975  && the_super_class->get_type() != Node::node_t::NODE_CLASS
976  && the_super_class->get_type() != Node::node_t::NODE_INTERFACE)
977  {
979  }
980  else
981  {
983  }
984  resolution.reset();
985  return false;
986  }
987  }
988 
989  if(child->get_type() == Node::node_t::NODE_FUNCTION && params)
990  {
991 std::cerr << " +--> check_name(): resolved function...\n";
992  if(check_function_with_params(child, params) < 0)
993  {
994  resolution.reset();
995  return false;
996  }
997  }
998 
999  return true;
1000 }
1001 
1002 
1003 void Compiler::resolve_internal_type(Node::pointer_t parent, char const *type, Node::pointer_t& resolution)
1004 {
1005  // create a temporary identifier
1006  Node::pointer_t id(parent->create_replacement(Node::node_t::NODE_IDENTIFIER));
1007  id->set_string(type);
1008 
1009  // TBD: identifier ever needs a parent?!
1010  //int const idx(parent->get_children_size());
1011 //std::cerr << "Do some invalid append now?\n";
1012  //parent->append_child(id);
1013 //std::cerr << "Done the invalid append?!\n";
1014 
1015  // search for the identifier which is an internal type name
1016  bool r;
1017  {
1018  // TODO: we should be able to start the search from the native
1019  // definitions since this is only used for native types
1020  // (i.e. Object, Boolean, etc.)
1021  NodeLock ln(parent);
1022  r = resolve_name(parent, id, resolution, Node::pointer_t(), 0);
1023  }
1024 
1025  // get rid of the temporary identifier
1026  //parent->delete_child(idx);
1027 
1028  if(!r)
1029  {
1030  // if the compiler cannot find an internal type, that is really bad!
1032  msg << "cannot find internal type \"" << type << "\".";
1033  throw exception_exit(1, "cannot find internal type");
1034  }
1035 
1036  return;
1037 }
1038 
1039 
1041  Node::pointer_t list,
1042  Node::pointer_t id,
1043  Node::pointer_t& resolution,
1044  Node::pointer_t params,
1045  int const search_flags
1046  )
1047 {
1048 //std::cerr << " +++ resolve_name()\n";
1049  RestoreFlags restore_flags(this);
1050 
1051  // just in case the caller is reusing the same node
1052  resolution.reset();
1053 
1054  // resolution may includes a member (a.b) and the resolution is the
1055  // last field name
1056  Node::node_t id_type(id->get_type());
1057  if(id_type == Node::node_t::NODE_MEMBER)
1058  {
1059  if(id->get_children_size() != 2)
1060  {
1061  throw exception_internal_error(std::string("compiler_package:Compiler::resolve_name() called with a MEMBER which does not have exactly two children."));
1062  }
1063  // child 0 is the variable name, child 1 is the field name
1064  Node::pointer_t name(id->get_child(0));
1065  if(!resolve_name(list, name, resolution, params, search_flags)) // recursive
1066  {
1067  // we could not find 'name' so we are hosed anyway
1068  // the callee should already have generated an error
1069  return false;
1070  }
1071  list = resolution;
1072  resolution.reset();
1073  id = id->get_child(1);
1074  id_type = id->get_type();
1075  }
1076 
1077  // in some cases we may want to resolve a name specified in a string
1078  // (i.e. test["me"])
1079  if(id_type != Node::node_t::NODE_IDENTIFIER
1080  && id_type != Node::node_t::NODE_VIDENTIFIER
1081  && id_type != Node::node_t::NODE_STRING)
1082  {
1083  throw exception_internal_error(std::string("compiler_package:Compiler::resolve_name() was called with an 'identifier node' which is not a NODE_[V]IDENTIFIER or NODE_STRING, it is ") + id->get_type_name());
1084  }
1085 
1086  // already typed?
1087  {
1088  Node::pointer_t type(id->get_type_node());
1089  if(type)
1090  {
1091  resolution = type;
1092  return true;
1093  }
1094  }
1095 
1096  //
1097  // Search for the parent list of directives; in that list, search
1098  // for the identifier; if not found, try again with the parent
1099  // of that list of directives (unless we find an import in which
1100  // case we first try the import)
1101  //
1102  // Note that the currently effective with()'s and use namespace's
1103  // are defined in the f_scope variable. This is used here to know
1104  // whether the name matches an entry or not.
1105  //
1106 
1107  // a list of functions whenever the name resolves to a function
1108  int funcs(0);
1109 
1110  Node::pointer_t parent(list->get_parent());
1111  if(parent->get_type() == Node::node_t::NODE_WITH)
1112  {
1113  // we are currently defining the WITH object, skip the
1114  // WITH itself!
1115  list = parent;
1116  }
1117  int module(0); // 0 is user module being compiled
1118  for(;;)
1119  {
1120  // we will start searching at this offset; first backward
1121  // and then forward
1122  size_t offset(0);
1123 
1124  // This function should never be called from program()
1125  // also, 'id' cannot be a directive list (it has to be an
1126  // identifier, a member or a string!)
1127  //
1128  // For these reasons, we can start the following loop with
1129  // a get_parent() in all cases.
1130  //
1131  if(module == 0)
1132  {
1133  // when we were inside the function parameter
1134  // list we do not want to check out the function
1135  // otherwise we could have a forward search of
1136  // the parameters which we disallow (only backward
1137  // search is allowed in that list)
1138  if(list->get_type() == Node::node_t::NODE_PARAMETERS)
1139  {
1140  list = list->get_parent();
1141  if(!list)
1142  {
1143  throw exception_internal_error("compiler_package:Compiler::resolve_name() got a NULL parent without finding NODE_ROOT first (NODE_PARAMETERS).");
1144  }
1145  }
1146 
1147  for(bool more(true); more; )
1148  {
1149  offset = list->get_offset();
1150  list = list->get_parent();
1151  if(!list)
1152  {
1153  throw exception_internal_error("compiler_package:Compiler::resolve_name() got a nullptr parent without finding NODE_ROOT first.");
1154  }
1155  switch(list->get_type())
1156  {
1158  throw exception_internal_error("compiler_package:Compiler::resolve_name() found the NODE_ROOT while searching for a parent.");
1159 
1162  list = list->get_parent();
1163  if(!list)
1164  {
1165  throw exception_internal_error("compiler_package:Compiler::resolve_name() got a nullptr parent without finding NODE_ROOT first (NODE_EXTENDS/NODE_IMPLEMENTS).");
1166  }
1167  break;
1168 
1172  //case Node::node_t::NODE_PACKAGE: -- not necessary, the first item is a NODE_DIRECTIVE_LIST
1180  more = false;
1181  break;
1182 
1183  default:
1184  break;
1185 
1186  }
1187  }
1188  }
1189 
1190  if(list->get_type() == Node::node_t::NODE_PROGRAM
1191  || module != 0)
1192  {
1193  // not resolved
1194  switch(module)
1195  {
1196  case 0:
1197  module = 1;
1198  if(g_global_import
1199  && g_global_import->get_children_size() > 0)
1200  {
1201  list = g_global_import->get_child(0);
1202  break;
1203  }
1204 #if __cplusplus >= 201700
1205  [[fallthrough]];
1206 #endif
1207  case 1:
1208  module = 2;
1209  if(g_system_import
1210  && g_system_import->get_children_size() > 0)
1211  {
1212  list = g_system_import->get_child(0);
1213  break;
1214  }
1215 #if __cplusplus >= 201700
1216  [[fallthrough]];
1217 #endif
1218  case 2:
1219  module = 3;
1220  if(g_native_import
1221  && g_native_import->get_children_size() > 0)
1222  {
1223  list = g_native_import->get_child(0);
1224  break;
1225  }
1226 #if __cplusplus >= 201700
1227  [[fallthrough]];
1228 #endif
1229  case 3:
1230  // no more default list of directives...
1231  module = 4;
1232  break;
1233 
1234  }
1235  offset = 0;
1236  }
1237  if(module == 4)
1238  {
1239  // did not find a variable and such, but
1240  // we may have found a function (see below
1241  // after the forever loop breaking here)
1242  break;
1243  }
1244 
1245  NodeLock ln(list);
1246  size_t const max_children(list->get_children_size());
1247  switch(list->get_type())
1248  {
1250  {
1251  // okay! we have got a list of directives
1252  // backward loop up first since in 99% of cases that
1253  // will be enough...
1254  if(offset >= max_children)
1255  {
1256  throw exception_internal_error("somehow an offset is out of range");
1257  }
1258  size_t idx(offset);
1259  while(idx > 0)
1260  {
1261  idx--;
1262  if(check_name(list, idx, resolution, id, params, search_flags))
1263  {
1264  if(funcs_name(funcs, resolution))
1265  {
1266  return true;
1267  }
1268  }
1269  }
1270 
1271  // forward look up is also available in ECMAScript...
1272  // (necessary in case function A calls function B
1273  // and function B calls function A).
1274  for(idx = offset; idx < max_children; ++idx)
1275  {
1276  if(check_name(list, idx, resolution, id, params, search_flags))
1277  {
1278  // TODO: if it is a variable it needs
1279  // to be a constant...
1280  if(funcs_name(funcs, resolution))
1281  {
1282  return true;
1283  }
1284  }
1285  }
1286  }
1287  break;
1288 
1290  {
1291  // the first member of a for can include variable
1292  // definitions
1293  if(max_children > 0 && check_name(list, 0, resolution, id, params, search_flags))
1294  {
1295  if(funcs_name(funcs, resolution))
1296  {
1297  return true;
1298  }
1299  }
1300  }
1301  break;
1302 
1303 #if 0
1305  // From inside a package, we have an implicit
1306  // IMPORT <package name>;
1307  //
1308  // This is required to enable a multiple files
1309  // package definition which ease the development
1310  // of really large packages.
1311  if(check_import(list, resolution, id->get_string(), params, search_flags))
1312  {
1313  return true;
1314  }
1315  break;
1316 #endif
1317 
1319  {
1320  if(max_children != 2)
1321  {
1322  break;
1323  }
1324  // ha! we found a valid WITH instruction, let's
1325  // search for this name in the corresponding
1326  // object type instead (i.e. a field of the object)
1327  Node::pointer_t type(list->get_child(0));
1328  if(type)
1329  {
1330  Node::pointer_t link(type->get_instance());
1331  if(link)
1332  {
1333  if(resolve_field(link, id, resolution, params, search_flags))
1334  {
1335  // Mark this identifier as a
1336  // reference to a WITH object
1337  id->set_flag(Node::flag_t::NODE_IDENTIFIER_FLAG_WITH, true);
1338 
1339  // TODO: we certainly want to compare
1340  // all the field functions and the
1341  // other functions... at this time,
1342  // err if we get a field function
1343  // and others are ignored!
1344  if(funcs != 0)
1345  {
1346  throw exception_internal_error("at this time we do not support functions here (under a with)");
1347  }
1348  return true;
1349  }
1350  }
1351  }
1352  }
1353  break;
1354 
1356  {
1357  // if identifier is marked as a type, then skip testing
1358  // the function parameters since those cannot be type
1359  // declarations
1360  if(!id->get_attribute(Node::attribute_t::NODE_ATTR_TYPE))
1361  {
1362  // search the list of parameters for a corresponding name
1363  for(size_t idx(0); idx < max_children; ++idx)
1364  {
1365  Node::pointer_t parameters_node(list->get_child(idx));
1366  if(parameters_node->get_type() == Node::node_t::NODE_PARAMETERS)
1367  {
1368  NodeLock parameters_ln(parameters_node);
1369  size_t const cnt(parameters_node->get_children_size());
1370  for(size_t j(0); j < cnt; ++j)
1371  {
1372  if(check_name(parameters_node, j, resolution, id, params, search_flags))
1373  {
1374  if(funcs_name(funcs, resolution))
1375  {
1376  return true;
1377  }
1378  }
1379  }
1380  break;
1381  }
1382  }
1383  }
1384  }
1385  break;
1386 
1388  {
1389  // Wow! I cannot believe I am implementing this...
1390  // So we will be able to reference the previous
1391  // parameters in the default value of the following
1392  // parameters; and that makes sense, it is available
1393  // in C++ templates, right?!
1394  // And guess what, that is just this little loop.
1395  // That is it. Big deal, hey?! 8-)
1396  if(offset >= max_children)
1397  {
1398  throw exception_internal_error("somehow an offset is out of range");
1399  }
1400  size_t idx(offset);
1401  while(idx > 0)
1402  {
1403  idx--;
1404  if(check_name(list, idx, resolution, id, params, search_flags))
1405  {
1406  if(funcs_name(funcs, resolution))
1407  {
1408  return true;
1409  }
1410  }
1411  }
1412  }
1413  break;
1414 
1416  {
1417  // a catch can have a parameter of its own
1418  Node::pointer_t parameters_node(list->get_child(0));
1419  if(parameters_node->get_children_size() > 0)
1420  {
1421  if(check_name(parameters_node, 0, resolution, id, params, search_flags))
1422  {
1423  if(funcs_name(funcs, resolution))
1424  {
1425  return true;
1426  }
1427  }
1428  }
1429  }
1430  break;
1431 
1433  // first we check whether the name of the enum is what
1434  // is being referenced (i.e. the type)
1435  if(id->get_string() == list->get_string())
1436  {
1437  resolution = list;
1438  resolution->set_flag(Node::flag_t::NODE_ENUM_FLAG_INUSE, true);
1439  return true;
1440  }
1441 
1442  // inside an enum we have references to other
1443  // identifiers of that enum and these need to be
1444  // checked here
1445  //
1446  // And note that these are not in any way affected
1447  // by scope attributes
1448  for(size_t idx(0); idx < max_children; ++idx)
1449  {
1450  Node::pointer_t entry(list->get_child(idx));
1451  if(entry->get_type() == Node::node_t::NODE_VARIABLE)
1452  {
1453  if(id->get_string() == entry->get_string())
1454  {
1455  // this cannot be a function, right? so the following
1456  // call is probably not really useful
1457  resolution = entry;
1458  if(funcs_name(funcs, resolution))
1459  {
1460  resolution->set_flag(Node::flag_t::NODE_VARIABLE_FLAG_INUSE, true);
1461  return true;
1462  }
1463  }
1464  }
1465  // else -- probably a NODE_TYPE
1466  }
1467  break;
1468 
1471  // // if the ID is a type and the name is the same as the
1472  // // class name, then we are found what we were looking for
1473  // if(id->get_attribute(Node::attribute_t::NODE_ATTR_TYPE)
1474  // && id->get_string() == list->get_string())
1475  // {
1476  // resolution = list;
1477  // return true;
1478  // }
1479  // We want to search the extends and implements declarations as well
1480  if(find_in_extends(list, id, funcs, resolution, params, search_flags))
1481  {
1482  if(funcs_name(funcs, resolution))
1483  {
1484  return true;
1485  }
1486  }
1487  break;
1488 
1489  default:
1490  // this could happen if our tree was to change and we do not
1491  // properly update this function
1492  throw exception_internal_error("compiler_package: unhandled type in Compiler::resolve_name()");
1493 
1494  }
1495  }
1496 
1497  resolution.reset();
1498 
1499  if(funcs != 0)
1500  {
1501  if(select_best_func(params, resolution))
1502  {
1503  return true;
1504  }
1505  }
1506 
1507  print_search_errors(id);
1508 
1509  return false;
1510 }
1511 
1512 
1513 }
1514 // namespace as2js
1515 
1516 // vim: ts=4 sw=4 et
void init_rc(bool const accept_if_missing)
Find the resource file.
Definition: rc.cpp:117
bool resolve_field(Node::pointer_t object, Node::pointer_t field, Node::pointer_t &resolution, Node::pointer_t params, int const search_flags)
bool is_constructor(Node::pointer_t func, Node::pointer_t &the_class)
Check whether a function is a constructor.
std::string to_utf8() const
Convert a string to UTF-8 and return the result.
Definition: string.cpp:1343
search_error_t f_err_flags
Definition: compiler.h:230
void find_packages_save_package_elements(Node::pointer_t package, String const &package_name)
bool get_attribute(Node::pointer_t node, Node::attribute_t const a)
Node::pointer_t find_package(Node::pointer_t list, String const &name)
void import(Node::pointer_t &import)
void variable(Node::pointer_t variable_node, bool side_effects_only)
std::shared_ptr< Element > pointer_t
Definition: db.h:68
bool funcs_name(int &funcs, Node::pointer_t resolution, bool const increment=true)
std::shared_ptr< Input > pointer_t
Definition: stream.h:152
Node::pointer_t load_module(char const *module, char const *file)
Load a module as specified by module and file.
static search_error_t const SEARCH_ERROR_WRONG_PROTECTED
Definition: compiler.h:84
void load_internal_packages(char const *module)
bool select_best_func(Node::pointer_t params, Node::pointer_t &resolution)
One or more function was found, select the best one.
std::shared_ptr< Package > pointer_t
Definition: db.h:95
bool check_function(Node::pointer_t function_node, Node::pointer_t &resolution, String const &name, Node::pointer_t params, int const search_flags)
int check_function_with_params(Node::pointer_t function_node, Node::pointer_t params)
std::vector< Package::pointer_t > package_vector_t
Definition: db.h:112
static search_error_t const SEARCH_ERROR_PROTECTED
Definition: compiler.h:81
Node::pointer_t f_program
Definition: compiler.h:228
static search_flag_t const SEARCH_FLAG_NO_PARSING
Definition: compiler.h:88
void find_packages(Node::pointer_t program)
std::shared_ptr< Database > pointer_t
Definition: db.h:63
bool find_package_item(Node::pointer_t program, Node::pointer_t import, Node::pointer_t &resolution, String const &name, Node::pointer_t params, int const search_flags)
void find_labels(Node::pointer_t function, Node::pointer_t node)
std::shared_ptr< Node > pointer_t
Definition: node.h:67
Options::pointer_t f_options
Definition: compiler.h:227
String const & get_db() const
Definition: rc.cpp:228
InputRetriever::pointer_t f_input_retriever
Definition: compiler.h:229
void find_packages_directive_list(Node::pointer_t list)
conversion_result_t from_utf8(char const *str, int len=-1)
Copy a UTF-8 string to this String.
Definition: string.cpp:792
bool find_in_extends(Node::pointer_t link, Node::pointer_t field, int &funcs, Node::pointer_t &resolution, Node::pointer_t params, int const search_flags)
static search_error_t const SEARCH_ERROR_PRIVATE
Definition: compiler.h:80
bool check_import(Node::pointer_t &child, Node::pointer_t &resolution, String const &name, Node::pointer_t params, int const search_flags)
void add_element(String const &package_name, String const &element_name, Node::pointer_t element, char const *type)
Node::pointer_t class_of_member(Node::pointer_t parent)
Search for a class or interface node.
static search_error_t const SEARCH_ERROR_WRONG_PRIVATE
Definition: compiler.h:83
Node::pointer_t directive_list(Node::pointer_t directive_list)
static search_flag_t const SEARCH_FLAG_PACKAGE_MUST_EXIST
Definition: compiler.h:91
void find_packages_add_database_entry(String const &package_name, Node::pointer_t &element, char const *type)
bool find_module(String const &filename, Node::pointer_t &result)
Find a module, load it if necessary.
Definition: rc.h:44
Database::Element::pointer_t find_element(String const &package_name, String const &element_name, char const *type)
void print_search_errors(const Node::pointer_t name)
The AlexScript to JavaScript namespace.
Definition: compiler.cpp:37
std::shared_ptr< Parser > pointer_t
Definition: parser.h:69
module_map_t f_modules
Definition: compiler.h:232
void resolve_internal_type(Node::pointer_t parent, char const *type, Node::pointer_t &resolution)
String const & get_scripts() const
Definition: rc.cpp:222
bool find_external_package(Node::pointer_t import, String const &name, Node::pointer_t &program_node)
String get_package_filename(char const *package_info)
Get the filename of a package.
bool resolve_name(Node::pointer_t list, Node::pointer_t id, Node::pointer_t &resolution, Node::pointer_t params, int const search_flags)
std::vector< Element::pointer_t > element_vector_t
Definition: db.h:90
bool are_objects_derived_from_one_another(Node::pointer_t derived_class, Node::pointer_t super_class, Node::pointer_t &the_super_class)
Check whether derived_class is extending super_class.
bool find_field(Node::pointer_t link, Node::pointer_t field, int &funcs, Node::pointer_t &resolution, Node::pointer_t params, int const search_flags)
void set_filename(String const &filename)
Set the filename being read.
Definition: position.cpp:52
static search_error_t const SEARCH_ERROR_PRIVATE_PACKAGE
Definition: compiler.h:85
bool check_name(Node::pointer_t list, int idx, Node::pointer_t &resolution, Node::pointer_t id, Node::pointer_t params, int const search_flags)

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