js: restructure namespaces (#7170)

pull/7187/head
spaceface777 2020-12-07 18:36:22 +01:00 committed by GitHub
parent d38bca5958
commit 744a36ed71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 60 additions and 43 deletions

View File

@ -18,16 +18,23 @@ const (
'\t\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t\t'] '\t\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t\t']
) )
struct Namespace {
name string
mut:
out strings.Builder = strings.new_builder(128)
pub_vars []string
imports map[string]string
indent int
methods map[string][]ast.FnDecl
}
struct JsGen { struct JsGen {
table &table.Table table &table.Table
pref &pref.Preferences pref &pref.Preferences
mut: mut:
definitions strings.Builder definitions strings.Builder
out strings.Builder ns &Namespace
namespaces map[string]strings.Builder namespaces map[string]&Namespace
namespaces_pub map[string][]string
namespace_imports map[string]map[string]string
namespace string
doc &JsDoc doc &JsDoc
enable_doc bool enable_doc bool
file ast.File file ast.File
@ -35,8 +42,8 @@ mut:
inside_ternary bool inside_ternary bool
inside_loop bool inside_loop bool
inside_map_set bool // map.set(key, value) inside_map_set bool // map.set(key, value)
inside_builtin bool
is_test bool is_test bool
indents map[string]int // indentations mapped to namespaces
stmt_start_pos int stmt_start_pos int
defer_stmts []ast.DeferStmt defer_stmts []ast.DeferStmt
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0 fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
@ -48,13 +55,13 @@ mut:
pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string { pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string {
mut g := &JsGen{ mut g := &JsGen{
out: strings.new_builder(100)
definitions: strings.new_builder(100) definitions: strings.new_builder(100)
table: table table: table
pref: pref pref: pref
fn_decl: 0 fn_decl: 0
empty_line: true empty_line: true
doc: 0 doc: 0
ns: 0
enable_doc: true enable_doc: true
} }
g.doc = new_jsdoc(g) g.doc = new_jsdoc(g)
@ -96,7 +103,7 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
out += '/** @namespace $name */\n' out += '/** @namespace $name */\n'
} }
out += 'const $name = (function (' out += 'const $name = (function ('
imports := g.namespace_imports[node.name] imports := g.namespaces[node.name].imports
for i, key in imports.keys() { for i, key in imports.keys() {
if i > 0 { if i > 0 {
out += ', ' out += ', '
@ -105,20 +112,20 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
} }
out += ') {\n\t' out += ') {\n\t'
// private scope // private scope
out += g.namespaces[node.name].str().trim_space() out += g.namespaces[node.name].out.str().trim_space()
// public scope // public scope
out += '\n' out += '\n'
if g.enable_doc { if g.enable_doc {
out += '\n\t/* module exports */' out += '\n\t/* module exports */'
} }
out += '\n\treturn {' out += '\n\treturn {'
for i, pub_var in g.namespaces_pub[node.name] { for i, pub_var in g.namespaces[node.name].pub_vars {
out += '\n\t\t$pub_var' out += '\n\t\t$pub_var'
if i < g.namespaces_pub[node.name].len - 1 { if i < g.namespaces[node.name].pub_vars.len - 1 {
out += ',' out += ','
} }
} }
if g.namespaces_pub[node.name].len > 0 { if g.namespaces[node.name].pub_vars.len > 0 {
out += '\n\t' out += '\n\t'
} }
out += '};' out += '};'
@ -139,26 +146,27 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
return out return out
} }
pub fn (mut g JsGen) enter_namespace(n string) { pub fn (mut g JsGen) enter_namespace(name string) {
g.namespace = n if g.namespaces[name] == 0 {
if g.namespaces[g.namespace].len == 0 {
// create a new namespace // create a new namespace
g.out = strings.new_builder(100) ns := &Namespace{
g.indents[g.namespace] = 0 name: name
} else {
g.out = g.namespaces[g.namespace]
} }
g.namespaces[name] = ns
g.ns = ns
} else {
g.ns = g.namespaces[name]
}
g.inside_builtin = name == 'builtin'
} }
pub fn (mut g JsGen) escape_namespace() { pub fn (mut g JsGen) escape_namespace() {
g.namespaces[g.namespace] = g.out g.ns = 0
g.namespace = '' g.inside_builtin = false
} }
pub fn (mut g JsGen) push_pub_var(s string) { pub fn (mut g JsGen) push_pub_var(s string) {
mut arr := g.namespaces_pub[g.namespace] g.ns.pub_vars << g.js_name(s)
arr << g.js_name(s)
g.namespaces_pub[g.namespace] = arr
} }
pub fn (mut g JsGen) find_class_methods(stmts []ast.Stmt) { pub fn (mut g JsGen) find_class_methods(stmts []ast.Stmt) {
@ -311,7 +319,7 @@ fn (mut g JsGen) fn_typ(args []table.Param, return_type table.Type) string {
fn (mut g JsGen) struct_typ(s string) string { fn (mut g JsGen) struct_typ(s string) string {
ns := get_ns(s) ns := get_ns(s)
mut name := if ns == g.namespace { s.split('.').last() } else { g.get_alias(s) } mut name := if ns == g.ns.name { s.split('.').last() } else { g.get_alias(s) }
mut styp := '' mut styp := ''
for i, v in name.split('.') { for i, v in name.split('.') {
if i == 0 { if i == 0 {
@ -320,7 +328,7 @@ fn (mut g JsGen) struct_typ(s string) string {
styp += '["$v"]' styp += '["$v"]'
} }
} }
if ns in ['', g.namespace] { if ns in ['', g.ns.name] {
return styp return styp
} }
return styp + '["prototype"]' return styp + '["prototype"]'
@ -356,32 +364,46 @@ fn (mut g JsGen) to_js_typ_val(t table.Type) string {
return styp return styp
} }
[inline]
fn verror(msg string) {
eprintln('jsgen error: $msg')
exit(1)
}
[inline]
pub fn (mut g JsGen) gen_indent() { pub fn (mut g JsGen) gen_indent() {
if g.indents[g.namespace] > 0 && g.empty_line { if g.ns.indent > 0 && g.empty_line {
g.out.write(tabs[g.indents[g.namespace]]) g.ns.out.write(tabs[g.ns.indent])
} }
g.empty_line = false g.empty_line = false
} }
[inline]
pub fn (mut g JsGen) inc_indent() { pub fn (mut g JsGen) inc_indent() {
g.indents[g.namespace]++ g.ns.indent++
} }
[inline]
pub fn (mut g JsGen) dec_indent() { pub fn (mut g JsGen) dec_indent() {
g.indents[g.namespace]-- g.ns.indent--
} }
[inline]
pub fn (mut g JsGen) write(s string) { pub fn (mut g JsGen) write(s string) {
if g.ns == 0 { verror('g.write: not in a namespace') }
g.gen_indent() g.gen_indent()
g.out.write(s) g.ns.out.write(s)
} }
[inline]
pub fn (mut g JsGen) writeln(s string) { pub fn (mut g JsGen) writeln(s string) {
if g.ns == 0 { verror('g.writeln: not in a namespace') }
g.gen_indent() g.gen_indent()
g.out.writeln(s) g.ns.out.writeln(s)
g.empty_line = true g.empty_line = true
} }
[inline]
pub fn (mut g JsGen) new_tmp_var() string { pub fn (mut g JsGen) new_tmp_var() string {
g.tmp_count++ g.tmp_count++
return '_tmp$g.tmp_count' return '_tmp$g.tmp_count'
@ -391,9 +413,7 @@ pub fn (mut g JsGen) new_tmp_var() string {
// 'fn' => '' // 'fn' => ''
[inline] [inline]
fn get_ns(s string) string { fn get_ns(s string) string {
idx := s.last_index('.') or { idx := s.last_index('.') or { return '' }
return ''
}
return s.substr(0, idx) return s.substr(0, idx)
} }
@ -402,8 +422,7 @@ fn (mut g JsGen) get_alias(name string) string {
if ns == '' { if ns == '' {
return name return name
} }
imports := g.namespace_imports[g.namespace] alias := g.ns.imports[ns]
alias := imports[ns]
if alias == '' { if alias == '' {
return name return name
} }
@ -418,7 +437,7 @@ fn (mut g JsGen) js_name(name_ string) string {
is_js = true is_js = true
} }
ns := get_ns(name) ns := get_ns(name)
name = if ns == g.namespace { name.split('.').last() } else { g.get_alias(name) } name = if g.ns == 0 { name } else if ns == g.ns.name { name.split('.').last() } else { g.get_alias(name) }
mut parts := name.split('.') mut parts := name.split('.')
if !is_js { if !is_js {
for i, p in parts { for i, p in parts {
@ -439,7 +458,7 @@ fn (mut g JsGen) stmts(stmts []ast.Stmt) {
} }
fn (mut g JsGen) stmt(node ast.Stmt) { fn (mut g JsGen) stmt(node ast.Stmt) {
g.stmt_start_pos = g.out.len g.stmt_start_pos = g.ns.out.len
match node { match node {
ast.AssertStmt { ast.AssertStmt {
g.gen_assert_stmt(node) g.gen_assert_stmt(node)
@ -501,7 +520,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
g.gen_hash_stmt(node) g.gen_hash_stmt(node)
} }
ast.Import { ast.Import {
g.gen_import_stmt(node) g.ns.imports[node.mod] = node.alias
} }
ast.InterfaceDecl { ast.InterfaceDecl {
g.gen_interface_decl(node) g.gen_interface_decl(node)
@ -840,7 +859,7 @@ fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
// Struct methods are handled by class generation code. // Struct methods are handled by class generation code.
return return
} }
if g.namespace == 'builtin' { if g.inside_builtin {
g.builtin_fns << it.name g.builtin_fns << it.name
} }
g.gen_method_decl(it) g.gen_method_decl(it)
@ -1041,9 +1060,7 @@ fn (mut g JsGen) gen_go_stmt(node ast.GoStmt) {
} }
fn (mut g JsGen) gen_import_stmt(it ast.Import) { fn (mut g JsGen) gen_import_stmt(it ast.Import) {
mut imports := g.namespace_imports[g.namespace] g.ns.imports[it.mod] = it.alias
imports[it.mod] = it.alias
g.namespace_imports[g.namespace] = imports
} }
fn (mut g JsGen) gen_interface_decl(it ast.InterfaceDecl) { fn (mut g JsGen) gen_interface_decl(it ast.InterfaceDecl) {