js: restructure namespaces (#7170)
parent
d38bca5958
commit
744a36ed71
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue