mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
js: imports and anon_fn
This commit is contained in:
parent
1a990407c7
commit
88e6d987d6
@ -6,6 +6,7 @@ import v.table
|
|||||||
import v.pref
|
import v.pref
|
||||||
import term
|
import term
|
||||||
import v.util
|
import v.util
|
||||||
|
import v.depgraph
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// https://ecma-international.org/ecma-262/#sec-reserved-words
|
// https://ecma-international.org/ecma-262/#sec-reserved-words
|
||||||
@ -22,24 +23,25 @@ struct JsGen {
|
|||||||
definitions strings.Builder
|
definitions strings.Builder
|
||||||
pref &pref.Preferences
|
pref &pref.Preferences
|
||||||
mut:
|
mut:
|
||||||
out strings.Builder
|
out strings.Builder
|
||||||
namespaces map[string]strings.Builder
|
namespaces map[string]strings.Builder
|
||||||
namespaces_pub map[string][]string
|
namespaces_pub map[string][]string
|
||||||
namespace string
|
namespace_imports map[string]map[string]string
|
||||||
doc &JsDoc
|
namespace string
|
||||||
constants strings.Builder // all global V constants
|
doc &JsDoc
|
||||||
file ast.File
|
constants strings.Builder // all global V constants
|
||||||
tmp_count int
|
file ast.File
|
||||||
inside_ternary bool
|
tmp_count int
|
||||||
inside_loop bool
|
inside_ternary bool
|
||||||
is_test bool
|
inside_loop bool
|
||||||
indents map[string]int // indentations mapped to namespaces
|
is_test bool
|
||||||
stmt_start_pos int
|
indents map[string]int // indentations mapped to namespaces
|
||||||
defer_stmts []ast.DeferStmt
|
stmt_start_pos int
|
||||||
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
defer_stmts []ast.DeferStmt
|
||||||
str_types []string // types that need automatic str() generation
|
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
||||||
method_fn_decls map[string][]ast.Stmt
|
str_types []string // types that need automatic str() generation
|
||||||
empty_line bool
|
method_fn_decls map[string][]ast.Stmt
|
||||||
|
empty_line bool
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
@ -56,6 +58,8 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||||||
g.doc = new_jsdoc(g)
|
g.doc = new_jsdoc(g)
|
||||||
g.init()
|
g.init()
|
||||||
|
|
||||||
|
mut graph := depgraph.new_dep_graph()
|
||||||
|
|
||||||
// Get class methods
|
// Get class methods
|
||||||
for file in files {
|
for file in files {
|
||||||
g.file = file
|
g.file = file
|
||||||
@ -69,24 +73,48 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||||||
g.file = file
|
g.file = file
|
||||||
g.enter_namespace(g.file.mod.name)
|
g.enter_namespace(g.file.mod.name)
|
||||||
g.is_test = g.file.path.ends_with('_test.v')
|
g.is_test = g.file.path.ends_with('_test.v')
|
||||||
|
|
||||||
|
// store imports
|
||||||
|
mut imports := []string{}
|
||||||
|
for imp in g.file.imports {
|
||||||
|
imports << imp.mod
|
||||||
|
}
|
||||||
|
graph.add(g.file.mod.name, imports)
|
||||||
|
|
||||||
g.stmts(file.stmts)
|
g.stmts(file.stmts)
|
||||||
// store the current namespace
|
// store the current namespace
|
||||||
g.escape_namespace()
|
g.escape_namespace()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolve imports
|
||||||
|
deps_resolved := graph.resolve()
|
||||||
|
|
||||||
g.finish()
|
g.finish()
|
||||||
mut out := g.hashes() + g.definitions.str() + g.constants.str()
|
mut out := g.hashes() + g.definitions.str() + g.constants.str()
|
||||||
for key in g.namespaces.keys() {
|
for node in deps_resolved.nodes {
|
||||||
out += '/* namespace: $key */\n'
|
out += '\n/* namespace: $node.name */\n'
|
||||||
|
out += 'const $node.name = (function ('
|
||||||
|
imports := g.namespace_imports[node.name]
|
||||||
|
for i, key in imports.keys() {
|
||||||
|
if i > 0 { out += ', ' }
|
||||||
|
out += imports[key]
|
||||||
|
}
|
||||||
|
out += ') {'
|
||||||
// private scope
|
// private scope
|
||||||
out += g.namespaces[key].str()
|
out += g.namespaces[node.name].str()
|
||||||
// public scope
|
// public scope
|
||||||
out += '\n\t/* module exports */'
|
out += '\n\t/* module exports */'
|
||||||
out += '\n\treturn {'
|
out += '\n\treturn {'
|
||||||
for pub_var in g.namespaces_pub[key] {
|
for pub_var in g.namespaces_pub[node.name] {
|
||||||
out += '\n\t\t$pub_var,'
|
out += '\n\t\t$pub_var,'
|
||||||
}
|
}
|
||||||
out += '\n\t};'
|
out += '\n\t};'
|
||||||
out += '\n})();'
|
out += '\n})('
|
||||||
|
for i, key in imports.keys() {
|
||||||
|
if i > 0 { out += ', ' }
|
||||||
|
out += key
|
||||||
|
}
|
||||||
|
out += ');'
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
@ -97,7 +125,6 @@ pub fn (mut g JsGen) enter_namespace(n string) {
|
|||||||
// create a new namespace
|
// create a new namespace
|
||||||
g.out = strings.new_builder(100)
|
g.out = strings.new_builder(100)
|
||||||
g.indents[g.namespace] = 0
|
g.indents[g.namespace] = 0
|
||||||
g.out.writeln('const $n = (function () {')
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
g.out = g.namespaces[g.namespace]
|
g.out = g.namespaces[g.namespace]
|
||||||
@ -110,7 +137,9 @@ pub fn (mut g JsGen) escape_namespace() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g JsGen) push_pub_var(s string) {
|
pub fn (mut g JsGen) push_pub_var(s string) {
|
||||||
g.namespaces_pub[g.namespace] << s
|
mut arr := g.namespaces_pub[g.namespace]
|
||||||
|
arr << 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) {
|
||||||
@ -316,7 +345,9 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||||||
ast.HashStmt {
|
ast.HashStmt {
|
||||||
// skip: nothing with # in JS
|
// skip: nothing with # in JS
|
||||||
}
|
}
|
||||||
ast.Import {}
|
ast.Import {
|
||||||
|
g.gen_import_stmt(it)
|
||||||
|
}
|
||||||
ast.InterfaceDecl {
|
ast.InterfaceDecl {
|
||||||
// TODO skip: interfaces not implemented yet
|
// TODO skip: interfaces not implemented yet
|
||||||
}
|
}
|
||||||
@ -358,7 +389,24 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||||||
g.write("'$it.val'")
|
g.write("'$it.val'")
|
||||||
}
|
}
|
||||||
ast.CallExpr {
|
ast.CallExpr {
|
||||||
name := if it.name.starts_with('JS.') { it.name[3..] } else { it.name }
|
mut name := ""
|
||||||
|
if it.name.starts_with('JS.') {
|
||||||
|
name = it.name[3..]
|
||||||
|
} else {
|
||||||
|
name = it.name
|
||||||
|
// TODO: Ugly fix until `it.is_method` and `it.left` gets fixed.
|
||||||
|
// `it.left` should be the name of the module in this case.
|
||||||
|
// TODO: This should be in `if it.is_method` instead but is_method seems to be broken.
|
||||||
|
dot_idx := name.index('.') or {-1} // is there a way to do `if optional()`?
|
||||||
|
if dot_idx > -1 {
|
||||||
|
split := name.split('.')
|
||||||
|
imports := g.namespace_imports[g.namespace]
|
||||||
|
alias := imports[split.first()]
|
||||||
|
if alias != "" {
|
||||||
|
name = alias + "." + split[1..].join(".")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
g.expr(it.left)
|
g.expr(it.left)
|
||||||
if it.is_method {
|
if it.is_method {
|
||||||
// example: foo.bar.baz()
|
// example: foo.bar.baz()
|
||||||
@ -430,6 +478,9 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||||||
ast.SelectorExpr {
|
ast.SelectorExpr {
|
||||||
g.gen_selector_expr(it)
|
g.gen_selector_expr(it)
|
||||||
}
|
}
|
||||||
|
ast.AnonFn {
|
||||||
|
g.gen_anon_fn_decl(it)
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
println(term.red('jsgen.expr(): bad node "${typeof(node)}"'))
|
println(term.red('jsgen.expr(): bad node "${typeof(node)}"'))
|
||||||
}
|
}
|
||||||
@ -483,6 +534,12 @@ fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) {
|
|||||||
g.write('`)')
|
g.write('`)')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) gen_import_stmt(it ast.Import) {
|
||||||
|
mut imports := g.namespace_imports[g.namespace]
|
||||||
|
imports[it.mod] = it.alias
|
||||||
|
g.namespace_imports[g.namespace] = imports
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) {
|
fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) {
|
||||||
type_sym := g.table.get_type_symbol(it.typ)
|
type_sym := g.table.get_type_symbol(it.typ)
|
||||||
if type_sym.kind != .array_fixed {
|
if type_sym.kind != .array_fixed {
|
||||||
@ -627,6 +684,7 @@ fn (mut g JsGen) gen_defer_stmts() {
|
|||||||
for defer_stmt in g.defer_stmts {
|
for defer_stmt in g.defer_stmts {
|
||||||
g.stmts(defer_stmt.stmts)
|
g.stmts(defer_stmt.stmts)
|
||||||
}
|
}
|
||||||
|
g.defer_stmts = []
|
||||||
g.writeln('})();')
|
g.writeln('})();')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -679,6 +737,10 @@ fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
|
|||||||
g.gen_method_decl(it)
|
g.gen_method_decl(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) gen_anon_fn_decl(it ast.AnonFn) {
|
||||||
|
g.gen_method_decl(it.decl)
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
||||||
g.fn_decl = &it
|
g.fn_decl = &it
|
||||||
has_go := fn_has_go(it)
|
has_go := fn_has_go(it)
|
||||||
@ -691,8 +753,10 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
|||||||
g.write('async ')
|
g.write('async ')
|
||||||
}
|
}
|
||||||
g.write('function(')
|
g.write('function(')
|
||||||
|
} else if it.is_anon {
|
||||||
|
g.write('function (')
|
||||||
} else {
|
} else {
|
||||||
mut name := js_name(it.name)
|
mut name := js_name(it.name.split('.').last())
|
||||||
c := name[0]
|
c := name[0]
|
||||||
if c in [`+`, `-`, `*`, `/`] {
|
if c in [`+`, `-`, `*`, `/`] {
|
||||||
name = util.replace_op(name)
|
name = util.replace_op(name)
|
||||||
@ -734,7 +798,9 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
|||||||
if is_main {
|
if is_main {
|
||||||
g.write(')();')
|
g.write(')();')
|
||||||
}
|
}
|
||||||
g.writeln('')
|
if !it.is_anon {
|
||||||
|
g.writeln('')
|
||||||
|
}
|
||||||
|
|
||||||
g.fn_decl = 0
|
g.fn_decl = 0
|
||||||
}
|
}
|
||||||
@ -989,7 +1055,6 @@ fn (mut g JsGen) gen_ident(node ast.Ident) {
|
|||||||
g.write('CONSTANTS.')
|
g.write('CONSTANTS.')
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO js_name
|
|
||||||
name := js_name(node.name)
|
name := js_name(node.name)
|
||||||
// TODO `is`
|
// TODO `is`
|
||||||
// TODO handle optionals
|
// TODO handle optionals
|
||||||
|
9
vlib/v/gen/js/tests/hello/hello.v
Normal file
9
vlib/v/gen/js/tests/hello/hello.v
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module hello
|
||||||
|
|
||||||
|
pub fn standard() string {
|
||||||
|
return "Hello"
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn excited() string {
|
||||||
|
return standard() + "!"
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
// V_COMMIT_HASH 04744a5
|
// V_COMMIT_HASH d697b28
|
||||||
// V_CURRENT_COMMIT_HASH 04744a5
|
// V_CURRENT_COMMIT_HASH 11c06ec
|
||||||
|
|
||||||
// Generated by the V compiler
|
// Generated by the V compiler
|
||||||
"use strict";
|
"use strict";
|
||||||
@ -11,9 +11,31 @@ const CONSTANTS = Object.freeze({
|
|||||||
v_super: "amazing keyword"
|
v_super: "amazing keyword"
|
||||||
});
|
});
|
||||||
|
|
||||||
/* namespace: main */
|
|
||||||
const main = (function () {
|
/* namespace: hello */
|
||||||
|
const hello = (function () { /**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function standard() {
|
||||||
|
return "Hello";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function excited() {
|
||||||
|
return hello.standard() + "!";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* module exports */
|
||||||
|
return {
|
||||||
|
standard,
|
||||||
|
excited,
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
/* namespace: main */
|
||||||
|
const main = (function (greeting) {
|
||||||
|
|
||||||
class Companies {
|
class Companies {
|
||||||
/**
|
/**
|
||||||
@ -113,8 +135,24 @@ class Companies {
|
|||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** @type {anon_1011_7_1} - fn_in_var */
|
||||||
|
const fn_in_var = function (number) {
|
||||||
|
console.log(tos3(`number: ${number}`));
|
||||||
|
};
|
||||||
|
anon_consumer(greeting.excited(), function (message) {
|
||||||
|
console.log(message);
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} greeting
|
||||||
|
* @param {anon_fn_18_1} anon
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
function anon_consumer(greeting, anon) {
|
||||||
|
anon(greeting);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} num
|
* @param {number} num
|
||||||
* @param {string} def
|
* @param {string} def
|
||||||
@ -148,4 +186,4 @@ class Companies {
|
|||||||
/* module exports */
|
/* module exports */
|
||||||
return {
|
return {
|
||||||
};
|
};
|
||||||
})();
|
})(hello);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import hello as greeting
|
||||||
|
|
||||||
fn JS.alert(arg string)
|
fn JS.alert(arg string)
|
||||||
fn JS.console.log(arg string)
|
fn JS.console.log(arg string)
|
||||||
|
|
||||||
@ -60,6 +62,18 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
go async(0, "hello")
|
go async(0, "hello")
|
||||||
|
|
||||||
|
fn_in_var := fn (number int) {
|
||||||
|
JS.console.log("number: $number")
|
||||||
|
}
|
||||||
|
|
||||||
|
anon_consumer(greeting.excited(), fn (message string) {
|
||||||
|
JS.console.log(message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn anon_consumer (greeting string, anon fn(message string)) {
|
||||||
|
anon(greeting)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn async(num int, def string) {}
|
fn async(num int, def string) {}
|
||||||
|
Loading…
Reference in New Issue
Block a user