jsgen: many fixes and updates
parent
a0ed1e2878
commit
dd534fde57
|
@ -19,29 +19,30 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
struct JsGen {
|
struct JsGen {
|
||||||
table &table.Table
|
table &table.Table
|
||||||
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_imports map[string]map[string]string
|
namespace_imports map[string]map[string]string
|
||||||
namespace string
|
namespace string
|
||||||
doc &JsDoc
|
doc &JsDoc
|
||||||
constants strings.Builder // all global V constants
|
enable_doc bool
|
||||||
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 {
|
||||||
|
@ -54,8 +55,13 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
fn_decl: 0
|
fn_decl: 0
|
||||||
empty_line: true
|
empty_line: true
|
||||||
doc: 0
|
doc: 0
|
||||||
|
enable_doc: true
|
||||||
}
|
}
|
||||||
g.doc = new_jsdoc(g)
|
g.doc = new_jsdoc(g)
|
||||||
|
// TODO: Add '[-no]-jsdoc' flag
|
||||||
|
if pref.is_prod {
|
||||||
|
g.enable_doc = false
|
||||||
|
}
|
||||||
g.init()
|
g.init()
|
||||||
|
|
||||||
mut graph := depgraph.new_dep_graph()
|
mut graph := depgraph.new_dep_graph()
|
||||||
|
@ -92,18 +98,18 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
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 node in deps_resolved.nodes {
|
for node in deps_resolved.nodes {
|
||||||
out += '\n/* namespace: $node.name */\n'
|
out += '/* namespace: $node.name */\n'
|
||||||
out += 'const $node.name = (function ('
|
out += 'const $node.name = (function ('
|
||||||
imports := g.namespace_imports[node.name]
|
imports := g.namespace_imports[node.name]
|
||||||
for i, key in imports.keys() {
|
for i, key in imports.keys() {
|
||||||
if i > 0 { out += ', ' }
|
if i > 0 { out += ', ' }
|
||||||
out += imports[key]
|
out += imports[key]
|
||||||
}
|
}
|
||||||
out += ') {'
|
out += ') {\n\t'
|
||||||
// private scope
|
// private scope
|
||||||
out += g.namespaces[node.name].str()
|
out += g.namespaces[node.name].str().trim_space()
|
||||||
// public scope
|
// public scope
|
||||||
out += '\n\t/* module exports */'
|
out += '\n\n\t/* module exports */'
|
||||||
out += '\n\treturn {'
|
out += '\n\treturn {'
|
||||||
for pub_var in g.namespaces_pub[node.name] {
|
for pub_var in g.namespaces_pub[node.name] {
|
||||||
out += '\n\t\t$pub_var,'
|
out += '\n\t\t$pub_var,'
|
||||||
|
@ -114,7 +120,7 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
if i > 0 { out += ', ' }
|
if i > 0 { out += ', ' }
|
||||||
out += key
|
out += key
|
||||||
}
|
}
|
||||||
out += ');'
|
out += ');\n\n'
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
@ -125,20 +131,19 @@ 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
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
g.out = g.namespaces[g.namespace]
|
g.out = g.namespaces[g.namespace]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g JsGen) escape_namespace() {
|
pub fn (mut g JsGen) escape_namespace() {
|
||||||
g.namespaces[g.namespace] = g.out
|
g.namespaces[g.namespace] = g.out
|
||||||
g.namespace = ""
|
g.namespace = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
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]
|
mut arr := g.namespaces_pub[g.namespace]
|
||||||
arr << s
|
arr << g.js_name(s)
|
||||||
g.namespaces_pub[g.namespace] = arr
|
g.namespaces_pub[g.namespace] = arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +153,7 @@ pub fn (mut g JsGen) find_class_methods(stmts []ast.Stmt) {
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
if it.is_method {
|
if it.is_method {
|
||||||
// Found struct method, store it to be generated along with the class.
|
// Found struct method, store it to be generated along with the class.
|
||||||
class_name := g.table.get_type_symbol(it.receiver.typ).name
|
class_name := g.table.get_type_name(it.receiver.typ)
|
||||||
// Workaround until `map[key] << val` works.
|
// Workaround until `map[key] << val` works.
|
||||||
mut arr := g.method_fn_decls[class_name]
|
mut arr := g.method_fn_decls[class_name]
|
||||||
arr << stmt
|
arr << stmt
|
||||||
|
@ -161,7 +166,7 @@ pub fn (mut g JsGen) find_class_methods(stmts []ast.Stmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g JsGen) init() {
|
pub fn (mut g JsGen) init() {
|
||||||
g.definitions.writeln('// Generated by the V compiler')
|
g.definitions.writeln('// Generated by the V compiler\n')
|
||||||
g.definitions.writeln('"use strict";')
|
g.definitions.writeln('"use strict";')
|
||||||
g.definitions.writeln('')
|
g.definitions.writeln('')
|
||||||
}
|
}
|
||||||
|
@ -170,7 +175,7 @@ pub fn (mut g JsGen) finish() {
|
||||||
if g.constants.len > 0 {
|
if g.constants.len > 0 {
|
||||||
constants := g.constants.str()
|
constants := g.constants.str()
|
||||||
g.constants = strings.new_builder(100)
|
g.constants = strings.new_builder(100)
|
||||||
g.constants.writeln('const CONSTANTS = Object.freeze({')
|
g.constants.writeln('const _CONSTS = Object.freeze({')
|
||||||
g.constants.write(constants)
|
g.constants.write(constants)
|
||||||
g.constants.writeln('});')
|
g.constants.writeln('});')
|
||||||
g.constants.writeln('')
|
g.constants.writeln('')
|
||||||
|
@ -179,7 +184,7 @@ pub fn (mut g JsGen) finish() {
|
||||||
|
|
||||||
pub fn (g JsGen) hashes() string {
|
pub fn (g JsGen) hashes() string {
|
||||||
mut res := '// V_COMMIT_HASH ${util.vhash()}\n'
|
mut res := '// V_COMMIT_HASH ${util.vhash()}\n'
|
||||||
res += '// V_CURRENT_COMMIT_HASH ${util.githash(g.pref.building_v)}\n\n'
|
res += '// V_CURRENT_COMMIT_HASH ${util.githash(g.pref.building_v)}\n'
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,9 +192,28 @@ pub fn (g JsGen) hashes() string {
|
||||||
// V type to JS type
|
// V type to JS type
|
||||||
pub fn (mut g JsGen) typ(t table.Type) string {
|
pub fn (mut g JsGen) typ(t table.Type) string {
|
||||||
sym := g.table.get_type_symbol(t)
|
sym := g.table.get_type_symbol(t)
|
||||||
mut styp := sym.name.replace('.', '__')
|
mut styp := sym.name
|
||||||
if styp.starts_with('JS__') {
|
if styp.starts_with('JS.') {
|
||||||
styp = styp[4..]
|
styp = styp[3..]
|
||||||
|
}
|
||||||
|
// 'multi_return_int_int' => '[number, number]'
|
||||||
|
if styp.starts_with('multi_return_') {
|
||||||
|
tokens := styp.replace('multi_return_', '').split('_')
|
||||||
|
return '[' + tokens.map(g.to_js_typ(it)).join(', ') + ']'
|
||||||
|
}
|
||||||
|
// 'anon_fn_7_7_1' => '(a number, b number) => void'
|
||||||
|
if styp.starts_with('anon_') {
|
||||||
|
info := sym.info as table.FnType
|
||||||
|
mut res := '('
|
||||||
|
for i, arg in info.func.args {
|
||||||
|
res += '$arg.name: ${g.typ(arg.typ)}'
|
||||||
|
if i < info.func.args.len - 1 { res += ', ' }
|
||||||
|
}
|
||||||
|
return res + ') => ' + g.typ(info.func.return_type)
|
||||||
|
}
|
||||||
|
// Struct instance => ns["class"]["prototype"]
|
||||||
|
if sym.kind == .struct_ {
|
||||||
|
return g.to_js_typ(styp) + '["prototype"]'
|
||||||
}
|
}
|
||||||
return g.to_js_typ(styp)
|
return g.to_js_typ(styp)
|
||||||
}
|
}
|
||||||
|
@ -223,6 +247,14 @@ fn (mut g JsGen) to_js_typ(typ string) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ns.export => ns["export"]
|
||||||
|
for i, v in styp.split('.') {
|
||||||
|
if i == 0 {
|
||||||
|
styp = v
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
styp += '["$v"]'
|
||||||
|
}
|
||||||
return styp
|
return styp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,13 +291,42 @@ pub fn (mut g JsGen) new_tmp_var() string {
|
||||||
return '_tmp$g.tmp_count'
|
return '_tmp$g.tmp_count'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 'mod1.mod2.fn' => 'mod1.mod2'
|
||||||
|
// 'fn' => ''
|
||||||
[inline]
|
[inline]
|
||||||
fn js_name(name string) string {
|
fn get_ns(s string) string {
|
||||||
// name := name_.replace('.', '__')
|
parts := s.split('.')
|
||||||
if name in js_reserved {
|
mut res := ''
|
||||||
return 'v_$name'
|
for i, p in parts {
|
||||||
|
if i == parts.len - 1 { break } // Last part (fn/struct/var name): skip
|
||||||
|
res += p
|
||||||
|
if i < parts.len - 2 { res += '.' } // Avoid trailing dot
|
||||||
}
|
}
|
||||||
return name
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) get_alias(name string) string {
|
||||||
|
// TODO: This is a hack; find a better way to do this
|
||||||
|
split := name.split('.')
|
||||||
|
if split.len > 1 {
|
||||||
|
imports := g.namespace_imports[g.namespace]
|
||||||
|
alias := imports[split[0]]
|
||||||
|
|
||||||
|
if alias != '' {
|
||||||
|
return alias + '.' + split[1..].join('.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name // No dot == no alias
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) js_name(name_ string) string {
|
||||||
|
ns := get_ns(name_)
|
||||||
|
mut name := if ns == g.namespace { name_.split('.').last() } else { g.get_alias(name_) }
|
||||||
|
mut parts := name.split('.')
|
||||||
|
for i, p in parts {
|
||||||
|
if p in js_reserved { parts[i] = 'v_$p' }
|
||||||
|
}
|
||||||
|
return parts.join('.')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) stmts(stmts []ast.Stmt) {
|
fn (mut g JsGen) stmts(stmts []ast.Stmt) {
|
||||||
|
@ -337,7 +398,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
}
|
}
|
||||||
ast.GotoLabel {
|
ast.GotoLabel {
|
||||||
g.writeln('${js_name(it.name)}:')
|
g.writeln('${g.js_name(it.name)}:')
|
||||||
}
|
}
|
||||||
ast.GotoStmt {
|
ast.GotoStmt {
|
||||||
// skip: JS has no goto
|
// skip: JS has no goto
|
||||||
|
@ -377,11 +438,13 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
ast.ArrayInit {
|
ast.ArrayInit {
|
||||||
g.gen_array_init_expr(it)
|
g.gen_array_init_expr(it)
|
||||||
}
|
}
|
||||||
|
ast.AssignExpr {
|
||||||
|
g.gen_assign_expr(it)
|
||||||
|
}
|
||||||
ast.BoolLiteral {
|
ast.BoolLiteral {
|
||||||
if it.val == true {
|
if it.val == true {
|
||||||
g.write('true')
|
g.write('true')
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
g.write('false')
|
g.write('false')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,30 +452,18 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
g.write("'$it.val'")
|
g.write("'$it.val'")
|
||||||
}
|
}
|
||||||
ast.CallExpr {
|
ast.CallExpr {
|
||||||
mut name := ""
|
mut name := ''
|
||||||
if it.name.starts_with('JS.') {
|
if it.name.starts_with('JS.') {
|
||||||
name = it.name[3..]
|
name = it.name[3..]
|
||||||
} else {
|
} else {
|
||||||
name = it.name
|
name = g.js_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()
|
||||||
g.write('.')
|
g.write('.')
|
||||||
}
|
}
|
||||||
g.write('${js_name(name)}(')
|
g.write('${g.js_name(name)}(')
|
||||||
for i, arg in it.args {
|
for i, arg in it.args {
|
||||||
g.expr(arg.expr)
|
g.expr(arg.expr)
|
||||||
if i != it.args.len - 1 {
|
if i != it.args.len - 1 {
|
||||||
|
@ -479,8 +530,8 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
g.gen_selector_expr(it)
|
g.gen_selector_expr(it)
|
||||||
}
|
}
|
||||||
ast.AnonFn {
|
ast.AnonFn {
|
||||||
g.gen_anon_fn_decl(it)
|
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)}"'))
|
||||||
}
|
}
|
||||||
|
@ -514,7 +565,7 @@ fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) {
|
||||||
// `expr ? "true" : "false"`
|
// `expr ? "true" : "false"`
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(' ? "true" : "false"')
|
g.write(' ? "true" : "false"')
|
||||||
} else {
|
} else {
|
||||||
sym := g.table.get_type_symbol(it.expr_types[i])
|
sym := g.table.get_type_symbol(it.expr_types[i])
|
||||||
|
|
||||||
match sym.kind {
|
match sym.kind {
|
||||||
|
@ -538,7 +589,7 @@ fn (mut g JsGen) gen_import_stmt(it ast.Import) {
|
||||||
mut imports := g.namespace_imports[g.namespace]
|
mut imports := g.namespace_imports[g.namespace]
|
||||||
imports[it.mod] = it.alias
|
imports[it.mod] = it.alias
|
||||||
g.namespace_imports[g.namespace] = imports
|
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)
|
||||||
|
@ -589,7 +640,7 @@ fn (mut g JsGen) gen_assign_stmt(it ast.AssignStmt) {
|
||||||
styp := g.typ(ident_var_info.typ)
|
styp := g.typ(ident_var_info.typ)
|
||||||
jsdoc.write(styp)
|
jsdoc.write(styp)
|
||||||
|
|
||||||
stmt.write(js_name(ident.name))
|
stmt.write(g.js_name(ident.name))
|
||||||
|
|
||||||
if i < it.left.len - 1 {
|
if i < it.left.len - 1 {
|
||||||
jsdoc.write(', ')
|
jsdoc.write(', ')
|
||||||
|
@ -602,23 +653,19 @@ fn (mut g JsGen) gen_assign_stmt(it ast.AssignStmt) {
|
||||||
g.write(stmt.str())
|
g.write(stmt.str())
|
||||||
g.expr(it.right[0])
|
g.expr(it.right[0])
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// `a := 1` | `a,b := 1,2`
|
// `a := 1` | `a,b := 1,2`
|
||||||
for i, ident in it.left {
|
for i, ident in it.left {
|
||||||
val := it.right[i]
|
val := it.right[i]
|
||||||
ident_var_info := ident.var_info()
|
ident_var_info := ident.var_info()
|
||||||
mut styp := g.typ(ident_var_info.typ)
|
mut styp := g.typ(ident_var_info.typ)
|
||||||
|
|
||||||
match val {
|
if val is ast.EnumVal {
|
||||||
ast.EnumVal {
|
// we want the type of the enum value not the enum
|
||||||
// we want the type of the enum value not the enum
|
styp = 'number'
|
||||||
styp = 'number'
|
} else if val is ast.StructInit {
|
||||||
}
|
// no need to print jsdoc for structs
|
||||||
ast.StructInit {
|
styp = ''
|
||||||
// no need to print jsdoc for structs
|
|
||||||
styp = ''
|
|
||||||
} else {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !g.inside_loop && styp.len > 0 {
|
if !g.inside_loop && styp.len > 0 {
|
||||||
|
@ -631,11 +678,11 @@ fn (mut g JsGen) gen_assign_stmt(it ast.AssignStmt) {
|
||||||
g.write('const ')
|
g.write('const ')
|
||||||
}
|
}
|
||||||
|
|
||||||
g.write('${js_name(ident.name)} = ')
|
g.write('${g.js_name(ident.name)} = ')
|
||||||
g.expr(val)
|
g.expr(val)
|
||||||
|
|
||||||
if g.inside_loop {
|
if g.inside_loop {
|
||||||
g.write("; ")
|
g.write('; ')
|
||||||
} else {
|
} else {
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
}
|
}
|
||||||
|
@ -643,6 +690,12 @@ fn (mut g JsGen) gen_assign_stmt(it ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) gen_assign_expr(it ast.AssignExpr) {
|
||||||
|
g.expr(it.left)
|
||||||
|
g.write(' $it.op ')
|
||||||
|
g.expr(it.val)
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_attr(it ast.Attr) {
|
fn (mut g JsGen) gen_attr(it ast.Attr) {
|
||||||
g.writeln('/* [$it.name] */')
|
g.writeln('/* [$it.name] */')
|
||||||
}
|
}
|
||||||
|
@ -667,11 +720,13 @@ fn (mut g JsGen) gen_const_decl(it ast.ConstDecl) {
|
||||||
g.expr(field.expr)
|
g.expr(field.expr)
|
||||||
val := g.out.after(pos)
|
val := g.out.after(pos)
|
||||||
g.out.go_back(val.len)
|
g.out.go_back(val.len)
|
||||||
typ := g.typ(field.typ)
|
if g.enable_doc {
|
||||||
|
typ := g.typ(field.typ)
|
||||||
|
g.constants.write('\t')
|
||||||
|
g.constants.writeln(g.doc.gen_typ(typ, field.name))
|
||||||
|
}
|
||||||
g.constants.write('\t')
|
g.constants.write('\t')
|
||||||
g.constants.writeln(g.doc.gen_typ(typ, field.name))
|
g.constants.write('${g.js_name(field.name)}: $val')
|
||||||
g.constants.write('\t')
|
|
||||||
g.constants.write('${js_name(field.name)}: $val')
|
|
||||||
if i < it.fields.len - 1 {
|
if i < it.fields.len - 1 {
|
||||||
g.constants.writeln(',')
|
g.constants.writeln(',')
|
||||||
}
|
}
|
||||||
|
@ -689,7 +744,7 @@ fn (mut g JsGen) gen_defer_stmts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_enum_decl(it ast.EnumDecl) {
|
fn (mut g JsGen) gen_enum_decl(it ast.EnumDecl) {
|
||||||
g.writeln('const ${js_name(it.name)} = Object.freeze({')
|
g.writeln('const ${g.js_name(it.name)} = Object.freeze({')
|
||||||
g.inc_indent()
|
g.inc_indent()
|
||||||
for i, field in it.fields {
|
for i, field in it.fields {
|
||||||
g.write('$field.name: ')
|
g.write('$field.name: ')
|
||||||
|
@ -714,16 +769,8 @@ fn (mut g JsGen) gen_enum_decl(it ast.EnumDecl) {
|
||||||
fn (mut g JsGen) gen_expr_stmt(it ast.ExprStmt) {
|
fn (mut g JsGen) gen_expr_stmt(it ast.ExprStmt) {
|
||||||
g.expr(it.expr)
|
g.expr(it.expr)
|
||||||
expr := it.expr
|
expr := it.expr
|
||||||
match expr {
|
if expr is ast.IfExpr { } // no ; after an if expression
|
||||||
ast.IfExpr {
|
else if !g.inside_ternary { g.writeln(';') }
|
||||||
// no ; after an if expression
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if !g.inside_ternary {
|
|
||||||
g.writeln(';')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
|
fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
|
||||||
|
@ -738,8 +785,8 @@ fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_anon_fn_decl(it ast.AnonFn) {
|
fn (mut g JsGen) gen_anon_fn_decl(it ast.AnonFn) {
|
||||||
g.gen_method_decl(it.decl)
|
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
|
||||||
|
@ -756,7 +803,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
||||||
} else if it.is_anon {
|
} else if it.is_anon {
|
||||||
g.write('function (')
|
g.write('function (')
|
||||||
} else {
|
} else {
|
||||||
mut name := js_name(it.name.split('.').last())
|
mut name := g.js_name(it.name)
|
||||||
c := name[0]
|
c := name[0]
|
||||||
if c in [`+`, `-`, `*`, `/`] {
|
if c in [`+`, `-`, `*`, `/`] {
|
||||||
name = util.replace_op(name)
|
name = util.replace_op(name)
|
||||||
|
@ -775,7 +822,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
||||||
}
|
}
|
||||||
g.write('${name}(')
|
g.write('${name}(')
|
||||||
|
|
||||||
if it.is_pub {
|
if it.is_pub && !it.is_method {
|
||||||
g.push_pub_var(name)
|
g.push_pub_var(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -894,7 +941,7 @@ fn (mut g JsGen) gen_for_stmt(it ast.ForStmt) {
|
||||||
fn (mut g JsGen) fn_args(args []table.Arg, is_variadic bool) {
|
fn (mut g JsGen) fn_args(args []table.Arg, is_variadic bool) {
|
||||||
// no_names := args.len > 0 && args[0].name == 'arg_1'
|
// no_names := args.len > 0 && args[0].name == 'arg_1'
|
||||||
for i, arg in args {
|
for i, arg in args {
|
||||||
name := js_name(arg.name)
|
name := g.js_name(arg.name)
|
||||||
is_varg := i == args.len - 1 && is_variadic
|
is_varg := i == args.len - 1 && is_variadic
|
||||||
if is_varg {
|
if is_varg {
|
||||||
g.write('...$name')
|
g.write('...$name')
|
||||||
|
@ -931,7 +978,7 @@ fn (mut g JsGen) gen_go_stmt(node ast.GoStmt) {
|
||||||
g.dec_indent()
|
g.dec_indent()
|
||||||
g.writeln('});')
|
g.writeln('});')
|
||||||
}
|
}
|
||||||
else { }
|
else {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -965,14 +1012,12 @@ fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) {
|
||||||
fn (mut g JsGen) gen_return_stmt(it ast.Return) {
|
fn (mut g JsGen) gen_return_stmt(it ast.Return) {
|
||||||
g.write('return ')
|
g.write('return ')
|
||||||
|
|
||||||
if g.fn_decl.name == 'main' {
|
if it.exprs.len == 0 {
|
||||||
// we can't return anything in main
|
// Returns nothing
|
||||||
g.writeln('void;')
|
} else if it.exprs.len == 1 {
|
||||||
return
|
g.expr(it.exprs[0])
|
||||||
}
|
} else {
|
||||||
|
// Multi return
|
||||||
// multiple returns
|
|
||||||
if it.exprs.len > 1 {
|
|
||||||
g.write('[')
|
g.write('[')
|
||||||
for i, expr in it.exprs {
|
for i, expr in it.exprs {
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
|
@ -982,53 +1027,38 @@ fn (mut g JsGen) gen_return_stmt(it ast.Return) {
|
||||||
}
|
}
|
||||||
g.write(']')
|
g.write(']')
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
g.expr(it.exprs[0])
|
|
||||||
}
|
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) enum_expr(node ast.Expr) {
|
fn (mut g JsGen) enum_expr(node ast.Expr) {
|
||||||
match node {
|
match node {
|
||||||
ast.EnumVal {
|
ast.EnumVal { g.write(it.val) }
|
||||||
g.write(it.val)
|
else { g.expr(node) }
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.expr(node)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
||||||
g.writeln('class ${js_name(node.name)} {')
|
g.writeln('class ${g.js_name(node.name)} {')
|
||||||
g.inc_indent()
|
g.inc_indent()
|
||||||
g.writeln(g.doc.gen_ctor(node.fields))
|
g.writeln(g.doc.gen_ctor(node.fields))
|
||||||
g.writeln('constructor(values) {')
|
g.writeln('constructor(values) {')
|
||||||
g.inc_indent()
|
g.inc_indent()
|
||||||
for field in node.fields {
|
for field in node.fields {
|
||||||
g.writeln('this.$field.name = values.$field.name')
|
// TODO: Generate default struct init values
|
||||||
|
g.writeln('this.$field.name = values.$field.name')
|
||||||
}
|
}
|
||||||
g.dec_indent()
|
g.dec_indent()
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
g.writeln('')
|
|
||||||
|
|
||||||
fns := g.method_fn_decls[node.name]
|
fns := g.method_fn_decls[node.name]
|
||||||
for cfn in fns {
|
for cfn in fns {
|
||||||
// TODO: Fix this hack for type conversion
|
// TODO: Move cast to the entire array whenever it's possible
|
||||||
// Directly converting to FnDecl gives
|
it := cfn as ast.FnDecl
|
||||||
// error: conversion to non-scalar type requested
|
g.writeln('')
|
||||||
match cfn {
|
g.gen_method_decl(it)
|
||||||
ast.FnDecl {
|
|
||||||
g.gen_method_decl(it)
|
|
||||||
}
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g.dec_indent()
|
g.dec_indent()
|
||||||
g.writeln('}')
|
g.writeln('}\n')
|
||||||
|
|
||||||
if node.is_pub {
|
if node.is_pub {
|
||||||
g.push_pub_var(node.name)
|
g.push_pub_var(node.name)
|
||||||
}
|
}
|
||||||
|
@ -1036,7 +1066,8 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
||||||
|
|
||||||
fn (mut g JsGen) gen_struct_init(it ast.StructInit) {
|
fn (mut g JsGen) gen_struct_init(it ast.StructInit) {
|
||||||
type_sym := g.table.get_type_symbol(it.typ)
|
type_sym := g.table.get_type_symbol(it.typ)
|
||||||
g.writeln('new ${type_sym.name}({')
|
name := type_sym.name
|
||||||
|
g.writeln('new ${g.js_name(name)}({')
|
||||||
g.inc_indent()
|
g.inc_indent()
|
||||||
for i, field in it.fields {
|
for i, field in it.fields {
|
||||||
g.write('$field.name: ')
|
g.write('$field.name: ')
|
||||||
|
@ -1052,10 +1083,11 @@ fn (mut g JsGen) gen_struct_init(it ast.StructInit) {
|
||||||
|
|
||||||
fn (mut g JsGen) gen_ident(node ast.Ident) {
|
fn (mut g JsGen) gen_ident(node ast.Ident) {
|
||||||
if node.kind == .constant {
|
if node.kind == .constant {
|
||||||
g.write('CONSTANTS.')
|
// TODO: Handle const namespacing: only consts in the main module are handled rn
|
||||||
|
g.write('_CONSTS.')
|
||||||
}
|
}
|
||||||
|
|
||||||
name := js_name(node.name)
|
name := g.js_name(node.name)
|
||||||
// TODO `is`
|
// TODO `is`
|
||||||
// TODO handle optionals
|
// TODO handle optionals
|
||||||
g.write(name)
|
g.write(name)
|
||||||
|
@ -1087,7 +1119,7 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||||
g.inside_ternary = false
|
g.inside_ternary = false
|
||||||
g.write(')')
|
g.write(')')
|
||||||
} else {
|
} else {
|
||||||
//mut is_guard = false
|
// mut is_guard = false
|
||||||
for i, branch in node.branches {
|
for i, branch in node.branches {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
match branch.cond {
|
match branch.cond {
|
||||||
|
@ -1109,7 +1141,7 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||||
//g.writeln('} if (!$guard_ok) { /* else */')
|
//g.writeln('} if (!$guard_ok) { /* else */')
|
||||||
} else { */
|
} else { */
|
||||||
g.writeln('} else {')
|
g.writeln('} else {')
|
||||||
//}
|
// }
|
||||||
}
|
}
|
||||||
g.stmts(branch.stmts)
|
g.stmts(branch.stmts)
|
||||||
}
|
}
|
||||||
|
@ -1128,11 +1160,7 @@ fn verror(s string) {
|
||||||
fn fn_has_go(it ast.FnDecl) bool {
|
fn fn_has_go(it ast.FnDecl) bool {
|
||||||
mut has_go := false
|
mut has_go := false
|
||||||
for stmt in it.stmts {
|
for stmt in it.stmts {
|
||||||
match stmt {
|
if stmt is ast.GoStmt { has_go = true }
|
||||||
ast.GoStmt {
|
|
||||||
has_go = true
|
|
||||||
} else {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return has_go
|
return has_go
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,13 @@ fn (mut d JsDoc) gen_indent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut d JsDoc) write(s string) {
|
fn (mut d JsDoc) write(s string) {
|
||||||
|
if !d.gen.enable_doc { return }
|
||||||
d.gen_indent()
|
d.gen_indent()
|
||||||
d.out.write(s)
|
d.out.write(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut d JsDoc) writeln(s string) {
|
fn (mut d JsDoc) writeln(s string) {
|
||||||
|
if !d.gen.enable_doc { return }
|
||||||
d.gen_indent()
|
d.gen_indent()
|
||||||
d.out.writeln(s)
|
d.out.writeln(s)
|
||||||
d.empty_line = true
|
d.empty_line = true
|
||||||
|
@ -45,7 +47,7 @@ fn (mut d JsDoc) gen_typ(typ, name string) string {
|
||||||
d.write('/**')
|
d.write('/**')
|
||||||
d.write(' @type {$typ}')
|
d.write(' @type {$typ}')
|
||||||
if name.len > 0 {
|
if name.len > 0 {
|
||||||
d.write(' - ${js_name(name)}')
|
d.write(' - ${d.gen.js_name(name)}')
|
||||||
}
|
}
|
||||||
d.write(' */')
|
d.write(' */')
|
||||||
return d.out.str()
|
return d.out.str()
|
||||||
|
@ -54,15 +56,18 @@ fn (mut d JsDoc) gen_typ(typ, name string) string {
|
||||||
fn (mut d JsDoc) gen_ctor(fields []ast.StructField) string {
|
fn (mut d JsDoc) gen_ctor(fields []ast.StructField) string {
|
||||||
d.reset()
|
d.reset()
|
||||||
d.writeln('/**')
|
d.writeln('/**')
|
||||||
d.write('* @param {{')
|
d.write(' * @param {{')
|
||||||
for i, field in fields {
|
for i, field in fields {
|
||||||
d.write('$field.name: ${d.gen.typ(field.typ)}')
|
// Marked as optional: structs have default default values,
|
||||||
|
// so all struct members don't have to be initialized.
|
||||||
|
// TODO: Actually generate default struct init values :P
|
||||||
|
d.write('$field.name?: ${d.gen.typ(field.typ)}')
|
||||||
if i < fields.len - 1 {
|
if i < fields.len - 1 {
|
||||||
d.write(', ')
|
d.write(', ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.writeln('}} values - values for this class fields')
|
d.writeln('}} values - values for this class fields')
|
||||||
d.writeln('* @constructor')
|
d.writeln(' * @constructor')
|
||||||
d.write('*/')
|
d.write('*/')
|
||||||
return d.out.str()
|
return d.out.str()
|
||||||
}
|
}
|
||||||
|
@ -71,20 +76,23 @@ fn (mut d JsDoc) gen_fn(it ast.FnDecl) string {
|
||||||
d.reset()
|
d.reset()
|
||||||
type_name := d.gen.typ(it.return_type)
|
type_name := d.gen.typ(it.return_type)
|
||||||
d.writeln('/**')
|
d.writeln('/**')
|
||||||
|
if it.is_deprecated {
|
||||||
|
d.writeln(' * @deprecated')
|
||||||
|
}
|
||||||
for i, arg in it.args {
|
for i, arg in it.args {
|
||||||
if it.is_method && i == 0 {
|
if it.is_method && i == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
arg_type_name := d.gen.typ(arg.typ)
|
arg_type_name := d.gen.typ(arg.typ)
|
||||||
is_varg := i == it.args.len - 1 && it.is_variadic
|
is_varg := i == it.args.len - 1 && it.is_variadic
|
||||||
name := js_name(arg.name)
|
name := d.gen.js_name(arg.name)
|
||||||
if is_varg {
|
if is_varg {
|
||||||
d.writeln('* @param {...$arg_type_name} $name')
|
d.writeln(' * @param {...$arg_type_name} $name')
|
||||||
} else {
|
} else {
|
||||||
d.writeln('* @param {$arg_type_name} $name')
|
d.writeln(' * @param {$arg_type_name} $name')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.writeln('* @return {$type_name}')
|
d.writeln(' * @returns {$type_name}')
|
||||||
d.write('*/')
|
d.write('*/')
|
||||||
return d.out.str()
|
return d.out.str()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
module hello1
|
||||||
|
|
||||||
|
// Unused for now: nested modules do not work yet
|
||||||
|
|
||||||
|
pub fn nested() string {
|
||||||
|
return 'Nested'
|
||||||
|
}
|
|
@ -1,9 +1,30 @@
|
||||||
module hello
|
module hello
|
||||||
|
|
||||||
pub fn standard() string {
|
// TODO: Fix const namespacing, uncomment once it works
|
||||||
return "Hello"
|
/*
|
||||||
|
pub const (
|
||||||
|
hello = 'Hello'
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub struct A {
|
||||||
|
pub mut:
|
||||||
|
foo string
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut a A) update(s string) {
|
||||||
|
a.foo = s
|
||||||
|
}
|
||||||
|
|
||||||
|
struct B {}
|
||||||
|
|
||||||
|
pub enum C {}
|
||||||
|
|
||||||
|
pub fn debugger() string {
|
||||||
|
v := B{}
|
||||||
|
return 'Hello'
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn excited() string {
|
pub fn excited() string {
|
||||||
return standard() + "!"
|
return debugger() + "!"
|
||||||
}
|
}
|
|
@ -1,46 +1,91 @@
|
||||||
// V_COMMIT_HASH d697b28
|
// V_COMMIT_HASH 74686d0
|
||||||
// V_CURRENT_COMMIT_HASH 11c06ec
|
// V_CURRENT_COMMIT_HASH 577d252
|
||||||
|
|
||||||
// Generated by the V compiler
|
// Generated by the V compiler
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const CONSTANTS = Object.freeze({
|
const _CONSTS = Object.freeze({
|
||||||
/** @type {number} - i_am_a_const */
|
/** @type {number} - i_am_a_const */
|
||||||
i_am_a_const: 21214,
|
i_am_a_const: 21214,
|
||||||
/** @type {string} - v_super */
|
/** @type {string} - v_super */
|
||||||
v_super: "amazing keyword"
|
v_super: "amazing keyword"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/* namespace: hello */
|
/* namespace: hello */
|
||||||
const hello = (function () { /**
|
const hello = (function () {
|
||||||
* @return {string}
|
class A {
|
||||||
|
/**
|
||||||
|
* @param {{foo?: string}} values - values for this class fields
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
constructor(values) {
|
||||||
|
this.foo = values.foo
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} s
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
update(s) {
|
||||||
|
const a = this;
|
||||||
|
a.foo = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class B {
|
||||||
|
/**
|
||||||
|
* @param {{}} values - values for this class fields
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
constructor(values) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const C = Object.freeze({
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function standard() {
|
function v_debugger() {
|
||||||
|
const v = new B({
|
||||||
|
});
|
||||||
return "Hello";
|
return "Hello";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function excited() {
|
function excited() {
|
||||||
return hello.standard() + "!";
|
return v_debugger() + "!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* module exports */
|
/* module exports */
|
||||||
return {
|
return {
|
||||||
standard,
|
A,
|
||||||
|
C,
|
||||||
|
v_debugger,
|
||||||
excited,
|
excited,
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
/* namespace: main */
|
|
||||||
const main = (function (greeting) {
|
|
||||||
|
|
||||||
class Companies {
|
/* namespace: main */
|
||||||
|
const main = (function (hl) {
|
||||||
|
class Foo {
|
||||||
/**
|
/**
|
||||||
* @param {{google: number, amazon: boolean, yahoo: string}} values - values for this class fields
|
* @param {{a?: hello["A"]["prototype"]}} values - values for this class fields
|
||||||
* @constructor
|
* @constructor
|
||||||
|
*/
|
||||||
|
constructor(values) {
|
||||||
|
this.a = values.a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Companies {
|
||||||
|
/**
|
||||||
|
* @param {{google?: number, amazon?: boolean, yahoo?: string}} values - values for this class fields
|
||||||
|
* @constructor
|
||||||
*/
|
*/
|
||||||
constructor(values) {
|
constructor(values) {
|
||||||
this.google = values.google
|
this.google = values.google
|
||||||
|
@ -49,7 +94,7 @@ class Companies {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
method() {
|
method() {
|
||||||
const it = this;
|
const it = this;
|
||||||
|
@ -68,15 +113,16 @@ class Companies {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const POSITION = Object.freeze({
|
const POSITION = Object.freeze({
|
||||||
go_back: 0,
|
go_back: 0,
|
||||||
dont_go_back: 1,
|
dont_go_back: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} v_extends
|
* @param {string} v_extends
|
||||||
* @param {number} v_instanceof
|
* @param {number} v_instanceof
|
||||||
* @return {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function v_class(v_extends, v_instanceof) {
|
function v_class(v_extends, v_instanceof) {
|
||||||
/** @type {number} - v_delete */
|
/** @type {number} - v_delete */
|
||||||
|
@ -86,6 +132,21 @@ class Companies {
|
||||||
/* program entry point */
|
/* program entry point */
|
||||||
(async function() {
|
(async function() {
|
||||||
console.log("Hello from V.js!");
|
console.log("Hello from V.js!");
|
||||||
|
/** @type {number} - a */
|
||||||
|
let a = 1;
|
||||||
|
a *= 2;
|
||||||
|
a += 3;
|
||||||
|
console.log(a, " == 5");
|
||||||
|
const b = new hl.A({
|
||||||
|
});
|
||||||
|
b.update("an update");
|
||||||
|
console.log(b);
|
||||||
|
const c = new Foo({
|
||||||
|
a: new hl.A({
|
||||||
|
})
|
||||||
|
});
|
||||||
|
c.a.update("another update");
|
||||||
|
console.log(c);
|
||||||
/** @type {string} - v */
|
/** @type {string} - v */
|
||||||
const v = "done";
|
const v = "done";
|
||||||
{
|
{
|
||||||
|
@ -96,14 +157,14 @@ class Companies {
|
||||||
/** @type {number} - pos */
|
/** @type {number} - pos */
|
||||||
const pos = POSITION.go_back;
|
const pos = POSITION.go_back;
|
||||||
/** @type {string} - v_debugger */
|
/** @type {string} - v_debugger */
|
||||||
const v_debugger = "JS keyword";
|
const v_debugger = "JS keywords";
|
||||||
/** @type {string} - v_await */
|
/** @type {string} - v_await */
|
||||||
const v_await = CONSTANTS.v_super + v_debugger;
|
const v_await = _CONSTS.v_super + ": " + v_debugger;
|
||||||
/** @type {string} - v_finally */
|
/** @type {string} - v_finally */
|
||||||
let v_finally = "implemented";
|
let v_finally = "implemented";
|
||||||
console.log(v_await, v_finally);
|
console.log(v_await, v_finally);
|
||||||
/** @type {number} - dun */
|
/** @type {number} - dun */
|
||||||
const dun = CONSTANTS.i_am_a_const * 20;
|
const dun = _CONSTS.i_am_a_const * 20;
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +178,7 @@ class Companies {
|
||||||
/** @type {number[]} - arr */
|
/** @type {number[]} - arr */
|
||||||
const arr = [1, 2, 3, 4, 5];
|
const arr = [1, 2, 3, 4, 5];
|
||||||
for (let _tmp1 = 0; _tmp1 < arr.length; ++_tmp1) {
|
for (let _tmp1 = 0; _tmp1 < arr.length; ++_tmp1) {
|
||||||
let a = arr[_tmp1];
|
let i = arr[_tmp1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {Map<string, string>} - ma */
|
/** @type {Map<string, string>} - ma */
|
||||||
|
@ -135,37 +196,40 @@ class Companies {
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
/** @type {anon_1011_7_1} - fn_in_var */
|
/** @type {(number: number) => void} - fn_in_var */
|
||||||
const fn_in_var = function (number) {
|
const fn_in_var = function (number) {
|
||||||
console.log(tos3(`number: ${number}`));
|
console.log(tos3(`number: ${number}`));
|
||||||
};
|
};
|
||||||
anon_consumer(greeting.excited(), function (message) {
|
hl.v_debugger();
|
||||||
|
anon_consumer(hl.excited(), function (message) {
|
||||||
console.log(message);
|
console.log(message);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} greeting
|
* @param {string} greeting
|
||||||
* @param {anon_fn_18_1} anon
|
* @param {(message: string) => void} anon
|
||||||
* @return {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function anon_consumer(greeting, anon) {
|
function anon_consumer(greeting, anon) {
|
||||||
anon(greeting);
|
anon(greeting);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} num
|
* @param {number} num
|
||||||
* @param {string} def
|
* @param {string} def
|
||||||
* @return {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function async(num, def) {
|
function async(num, def) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* [inline] */
|
/* [inline] */
|
||||||
|
/* [deprecated] */
|
||||||
/**
|
/**
|
||||||
* @param {number} game_on
|
* @deprecated
|
||||||
* @param {...string} dummy
|
* @param {number} game_on
|
||||||
* @return {multi_return_int_int}
|
* @param {...string} dummy
|
||||||
|
* @returns {[number, number]}
|
||||||
*/
|
*/
|
||||||
function hello(game_on, ...dummy) {
|
function hello(game_on, ...dummy) {
|
||||||
for (let _tmp2 = 0; _tmp2 < dummy.length; ++_tmp2) {
|
for (let _tmp2 = 0; _tmp2 < dummy.length; ++_tmp2) {
|
||||||
|
@ -181,9 +245,9 @@ class Companies {
|
||||||
return [game_on + 2, 221];
|
return [game_on + 2, 221];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* module exports */
|
/* module exports */
|
||||||
return {
|
return {
|
||||||
};
|
};
|
||||||
})(hello);
|
})(hello);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import hello as greeting
|
import hello as hl
|
||||||
|
|
||||||
fn JS.alert(arg string)
|
fn JS.alert(arg string)
|
||||||
fn JS.console.log(arg string)
|
fn JS.console.log(arg string)
|
||||||
|
@ -8,6 +8,10 @@ const (
|
||||||
super = 'amazing keyword'
|
super = 'amazing keyword'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
a hl.A
|
||||||
|
}
|
||||||
|
|
||||||
struct Companies {
|
struct Companies {
|
||||||
google int
|
google int
|
||||||
amazon bool
|
amazon bool
|
||||||
|
@ -27,6 +31,19 @@ fn class(extends string, instanceof int) {
|
||||||
fn main() {
|
fn main() {
|
||||||
JS.console.log('Hello from V.js!')
|
JS.console.log('Hello from V.js!')
|
||||||
|
|
||||||
|
mut a := 1
|
||||||
|
a *= 2
|
||||||
|
a += 3
|
||||||
|
JS.console.log(a, ' == 5') // TODO: Handle string interpolation
|
||||||
|
|
||||||
|
b := hl.A{}
|
||||||
|
b.update('an update')
|
||||||
|
JS.console.log(b)
|
||||||
|
|
||||||
|
c := Foo{ hl.A{} }
|
||||||
|
c.a.update('another update')
|
||||||
|
JS.console.log(c)
|
||||||
|
|
||||||
v := "done"
|
v := "done"
|
||||||
{
|
{
|
||||||
_ := "block"
|
_ := "block"
|
||||||
|
@ -34,9 +51,9 @@ fn main() {
|
||||||
|
|
||||||
pos := POSITION.go_back
|
pos := POSITION.go_back
|
||||||
|
|
||||||
debugger := 'JS keyword'
|
debugger := 'JS keywords'
|
||||||
// TODO: Implement interpolation
|
// TODO: Implement interpolation
|
||||||
await := super + debugger
|
await := super + ': ' + debugger
|
||||||
mut finally := 'implemented'
|
mut finally := 'implemented'
|
||||||
|
|
||||||
JS.console.log(await, finally)
|
JS.console.log(await, finally)
|
||||||
|
@ -50,7 +67,7 @@ fn main() {
|
||||||
for x in 1..10 {}
|
for x in 1..10 {}
|
||||||
|
|
||||||
arr := [1,2,3,4,5]
|
arr := [1,2,3,4,5]
|
||||||
for a in arr {}
|
for i in arr {}
|
||||||
|
|
||||||
ma := {
|
ma := {
|
||||||
'str': "done"
|
'str': "done"
|
||||||
|
@ -67,7 +84,8 @@ fn main() {
|
||||||
JS.console.log("number: $number")
|
JS.console.log("number: $number")
|
||||||
}
|
}
|
||||||
|
|
||||||
anon_consumer(greeting.excited(), fn (message string) {
|
hl.debugger()
|
||||||
|
anon_consumer(hl.excited(), fn (message string) {
|
||||||
JS.console.log(message)
|
JS.console.log(message)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -79,6 +97,7 @@ fn anon_consumer (greeting string, anon fn(message string)) {
|
||||||
fn async(num int, def string) {}
|
fn async(num int, def string) {}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
|
[deprecated]
|
||||||
fn hello(game_on int, dummy ...string) (int, int) {
|
fn hello(game_on int, dummy ...string) (int, int) {
|
||||||
defer {
|
defer {
|
||||||
do := "not"
|
do := "not"
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
// V_COMMIT_HASH 74686d0
|
||||||
|
// V_CURRENT_COMMIT_HASH 577d252
|
||||||
|
// Generated by the V compiler
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/* namespace: hello */
|
||||||
|
const hello = (function () {
|
||||||
|
class A {
|
||||||
|
/**
|
||||||
|
* @param {{foo?: string}} values - values for this class fields
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
constructor(values) {
|
||||||
|
this.foo = values.foo
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} s
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
update(s) {
|
||||||
|
const a = this;
|
||||||
|
a.foo = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class B {
|
||||||
|
/**
|
||||||
|
* @param {{}} values - values for this class fields
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
constructor(values) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const C = Object.freeze({
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function v_debugger() {
|
||||||
|
const v = new B({
|
||||||
|
});
|
||||||
|
return "Hello";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function excited() {
|
||||||
|
return v_debugger() + "!";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* module exports */
|
||||||
|
return {
|
||||||
|
A,
|
||||||
|
C,
|
||||||
|
v_debugger,
|
||||||
|
excited,
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* namespace: main */
|
||||||
|
const main = (function (hello) {
|
||||||
|
class D {
|
||||||
|
/**
|
||||||
|
* @param {{a?: hello["A"]["prototype"]}} values - values for this class fields
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
constructor(values) {
|
||||||
|
this.a = values.a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {hello["A"]["prototype"]} arg
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function struct_arg(arg) {
|
||||||
|
console.log(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* program entry point */
|
||||||
|
(function() {
|
||||||
|
struct_arg(new hello.A({
|
||||||
|
foo: "hello"
|
||||||
|
}));
|
||||||
|
/** @type {number} - a */
|
||||||
|
let a = 1;
|
||||||
|
a += 2;
|
||||||
|
console.log(a);
|
||||||
|
const b = new hello.A({
|
||||||
|
});
|
||||||
|
console.log(b);
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* module exports */
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
})(hello);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import hello
|
||||||
|
// import hello.hello1
|
||||||
|
// TODO: Uncomment once nested modules work
|
||||||
|
|
||||||
|
fn JS.console.log()
|
||||||
|
|
||||||
|
struct D {
|
||||||
|
a hello.A
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_arg (arg hello.A) {
|
||||||
|
JS.console.log(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
struct_arg(hello.A{ 'hello' })
|
||||||
|
|
||||||
|
mut a := 1
|
||||||
|
a += 2
|
||||||
|
JS.console.log(a)
|
||||||
|
b := hello.A{}
|
||||||
|
JS.console.log(b)
|
||||||
|
// hello1.nested()
|
||||||
|
}
|
Loading…
Reference in New Issue