module.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /**
  2. * Module System
  3. *
  4. * All registered modules are put in a global registry,
  5. * therefore module names are global identifiers,
  6. * two modules cannot have a same name.
  7. */
  8. let modules = {}
  9. class Module {
  10. constructor (name, exported) {
  11. assert(is(name, Types.String))
  12. assert(is(exported, Types.Hash))
  13. this.name = name
  14. this.exported = exported
  15. }
  16. has (name) {
  17. return has(name, this.exported)
  18. }
  19. get (name) {
  20. assert(is(name, Types.String))
  21. assert(this.has(name))
  22. return this.exported[name]
  23. }
  24. import_to (scope, name, alias) {
  25. assert(scope instanceof Scope)
  26. assert(is(name, Types.String))
  27. assert(is(alias, Types.String))
  28. ensure(!scope.has(alias), 'import_conflict', alias)
  29. scope.declare(alias, this.exported[name])
  30. }
  31. import_all_to (scope) {
  32. assert(scope instanceof Scope)
  33. let names = Object.keys(this.exported)
  34. for (let name of names) {
  35. ensure(!scope.has(name), 'import_conflict', name)
  36. }
  37. for (let name of names) {
  38. scope.declare(name, this.exported[name])
  39. }
  40. }
  41. get [Symbol.toStringTag] () {
  42. return "Module"
  43. }
  44. }
  45. Types.Module = $(x => x instanceof Module)
  46. function register_module (module_name, export_names, init) {
  47. assert(is(module_name, Types.String))
  48. assert(is(export_names, TypedList.of(Types.String)))
  49. assert(is(init, ES.Function))
  50. ensure(!has(module_name, modules), 'module_conflict', module_name)
  51. assert(typeof Global != 'undefined') // global scope should be created
  52. let scope = new Scope(Global)
  53. init(scope)
  54. let exported = {}
  55. foreach(export_names, name => {
  56. ensure(scope.has(name), 'missing_export', module_name, name)
  57. exported[name] = scope.lookup(name)
  58. })
  59. modules[module_name] = new Module(module_name, exported)
  60. }
  61. function register_simple_module (name, export_object) {
  62. assert(is(export_object, Types.Hash))
  63. let keys = Object.keys(export_object)
  64. register_module(name, keys, scope => {
  65. foreach(export_object, (name, value) => {
  66. scope.declare(name, value)
  67. })
  68. })
  69. }
  70. // ImportConfig: [NAME, ALIAS]
  71. let ImportConfig = Ins(Types.List, $(
  72. x => x.length == 2 && forall(x, y => is(y, Types.String))
  73. ))
  74. function import_module (scope, config) {
  75. // import MODULE
  76. assert(scope instanceof Scope)
  77. assert(is(config, ImportConfig))
  78. let [name, alias] = config
  79. ensure(has(name, modules), 'module_not_exist', name)
  80. ensure(!scope.has(alias), 'import_conflict_mod', name, alias)
  81. scope.declare(alias, modules[name])
  82. return Void
  83. }
  84. function import_names (scope, module_name, configs) {
  85. // import NAME1, NAME2, ... from MODULE
  86. assert(scope instanceof Scope)
  87. assert(is(module_name, Types.String))
  88. assert(is(configs, TypedList.of(ImportConfig)))
  89. ensure(has(module_name, modules), 'module_not_exist', module_name)
  90. let mod = modules[module_name]
  91. for (let config of configs) {
  92. let [_, alias] = config
  93. ensure(!scope.has(alias), 'import_conflict', alias)
  94. }
  95. for (let config of configs) {
  96. let [name, alias] = config
  97. mod.import_to(scope, name, alias)
  98. }
  99. return Void
  100. }
  101. function import_all (scope, module_name) {
  102. // import * from MODULE
  103. assert(scope instanceof Scope)
  104. assert(is(module_name, Types.String))
  105. ensure(has(module_name, modules), 'module_not_exist', module_name)
  106. modules[module_name].import_all_to(scope)
  107. return Void
  108. }