jsgen: more fixes and improvements
parent
d7bb887c2a
commit
11e6734912
|
@ -33,11 +33,11 @@ mut:
|
|||
namespace string
|
||||
doc &JsDoc
|
||||
enable_doc bool
|
||||
constants strings.Builder // all global V constants
|
||||
file ast.File
|
||||
tmp_count int
|
||||
inside_ternary bool
|
||||
inside_loop bool
|
||||
inside_map_set bool // map.set(key, value)
|
||||
is_test bool
|
||||
indents map[string]int // indentations mapped to namespaces
|
||||
stmt_start_pos int
|
||||
|
@ -52,7 +52,6 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
mut g := &JsGen{
|
||||
out: strings.new_builder(100)
|
||||
definitions: strings.new_builder(100)
|
||||
constants: strings.new_builder(100)
|
||||
table: table
|
||||
pref: pref
|
||||
fn_decl: 0
|
||||
|
@ -98,11 +97,13 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
// resolve imports
|
||||
deps_resolved := graph.resolve()
|
||||
|
||||
g.finish()
|
||||
mut out := g.hashes() + g.definitions.str() + g.constants.str()
|
||||
mut out := g.hashes() + g.definitions.str()
|
||||
for node in deps_resolved.nodes {
|
||||
out += g.doc.gen_namespace(node.name)
|
||||
out += 'const $node.name = (function ('
|
||||
name := g.js_name(node.name)
|
||||
if g.enable_doc {
|
||||
out += '/** @namespace $name */\n'
|
||||
}
|
||||
out += 'const $name = (function ('
|
||||
imports := g.namespace_imports[node.name]
|
||||
for i, key in imports.keys() {
|
||||
if i > 0 { out += ', ' }
|
||||
|
@ -112,7 +113,10 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
// private scope
|
||||
out += g.namespaces[node.name].str().trim_space()
|
||||
// public scope
|
||||
out += '\n\n\t/* module exports */'
|
||||
out += '\n'
|
||||
if g.enable_doc {
|
||||
out += '\n\t/* module exports */'
|
||||
}
|
||||
out += '\n\treturn {'
|
||||
for pub_var in g.namespaces_pub[node.name] {
|
||||
out += '\n\t\t$pub_var,'
|
||||
|
@ -175,17 +179,6 @@ pub fn (mut g JsGen) init() {
|
|||
g.definitions.writeln('')
|
||||
}
|
||||
|
||||
pub fn (mut g JsGen) finish() {
|
||||
if g.constants.len > 0 {
|
||||
constants := g.constants.str()
|
||||
g.constants = strings.new_builder(100)
|
||||
g.constants.writeln('const _CONSTS = Object.freeze({')
|
||||
g.constants.write(constants)
|
||||
g.constants.writeln('});')
|
||||
g.constants.writeln('')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (g JsGen) hashes() string {
|
||||
mut res := '// V_COMMIT_HASH ${util.vhash()}\n'
|
||||
res += '// V_CURRENT_COMMIT_HASH ${util.githash(g.pref.building_v)}\n'
|
||||
|
@ -195,109 +188,162 @@ pub fn (g JsGen) hashes() string {
|
|||
// V type to JS type
|
||||
pub fn (mut g JsGen) typ(t table.Type) string {
|
||||
sym := g.table.get_type_symbol(t)
|
||||
mut styp := sym.name
|
||||
if styp.starts_with('JS.') {
|
||||
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_ && get_ns(styp).len > 0 {
|
||||
return g.to_js_typ(g.get_alias(styp)) + '["prototype"]'
|
||||
}
|
||||
return g.to_js_typ(styp)
|
||||
}
|
||||
|
||||
fn (mut g JsGen) to_js_typ(typ string) string {
|
||||
mut styp := ''
|
||||
match typ {
|
||||
'int' {
|
||||
|
||||
match sym.kind {
|
||||
.placeholder {
|
||||
// This should never happen: means checker bug
|
||||
styp = 'any'
|
||||
}
|
||||
.void {
|
||||
styp = 'void'
|
||||
}
|
||||
.voidptr {
|
||||
styp = 'any'
|
||||
}
|
||||
.byteptr, .charptr {
|
||||
styp = 'string'
|
||||
}
|
||||
.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64, .f32, .f64, .any_int, .any_float, .size_t {
|
||||
// TODO: Should u64 and i64 use BigInt rather than number?
|
||||
styp = 'number'
|
||||
}
|
||||
'bool' {
|
||||
.bool {
|
||||
styp = 'boolean'
|
||||
}
|
||||
'voidptr' {
|
||||
styp = 'Object'
|
||||
.none_ {
|
||||
styp = 'undefined'
|
||||
}
|
||||
'byteptr' {
|
||||
.string, .ustring, .char {
|
||||
styp = 'string'
|
||||
}
|
||||
'charptr' {
|
||||
styp = 'string'
|
||||
// 'array_array_int' => 'number[][]'
|
||||
.array {
|
||||
info := sym.info as table.Array
|
||||
styp = g.typ(info.elem_type) + '[]'
|
||||
}
|
||||
else {
|
||||
if typ.starts_with('array_') {
|
||||
styp = g.to_js_typ(typ.replace('array_', '')) + '[]'
|
||||
} else if typ.starts_with('map_') {
|
||||
tokens := typ.split('_')
|
||||
styp = 'Map<${g.to_js_typ(tokens[1])}, ${g.to_js_typ(tokens[2])}>'
|
||||
} else {
|
||||
styp = typ
|
||||
.array_fixed {
|
||||
info := sym.info as table.ArrayFixed
|
||||
styp = g.array_fixed_typ(info.elem_type) or { g.typ(info.elem_type) + '[]' }
|
||||
}
|
||||
// 'map[string]int' => 'Map<string, number>'
|
||||
.map {
|
||||
info := sym.info as table.Map
|
||||
key := g.typ(info.key_type)
|
||||
val := g.typ(info.value_type)
|
||||
styp = 'Map<$key, $val>'
|
||||
}
|
||||
.any {
|
||||
styp = 'any'
|
||||
}
|
||||
// ns.Foo => alias["Foo"]["prototype"]
|
||||
.struct_ {
|
||||
styp = g.struct_typ(sym.name)
|
||||
}
|
||||
// 'multi_return_int_int' => '[number, number]'
|
||||
.multi_return {
|
||||
info := sym.info as table.MultiReturn
|
||||
types := info.types.map(g.typ(it))
|
||||
joined := types.join(', ')
|
||||
styp = '[$joined]'
|
||||
}
|
||||
.sum_type {
|
||||
// TODO: Implement sumtypes
|
||||
styp = 'sym_type'
|
||||
}
|
||||
.alias {
|
||||
// TODO: Implement aliases
|
||||
styp = 'alias'
|
||||
}
|
||||
.enum_ {
|
||||
// NB: We could declare them as TypeScript enums but TS doesn't like
|
||||
// our namespacing so these break if declared in a different module.
|
||||
// Until this is fixed, We need to use the type of an enum's members
|
||||
// rather than the enum itself, and this can only be 'number' for now
|
||||
styp = 'number'
|
||||
}
|
||||
// 'anon_fn_7_7_1' => '(a number, b number) => void'
|
||||
.function {
|
||||
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 += ', ' }
|
||||
}
|
||||
styp = res + ') => ' + g.typ(info.func.return_type)
|
||||
}
|
||||
}
|
||||
// ns.export => ns["export"]
|
||||
for i, v in styp.split('.') {
|
||||
if i == 0 {
|
||||
styp = v
|
||||
continue
|
||||
.interface_ {
|
||||
// TODO: Implement interfaces
|
||||
styp = 'interface'
|
||||
}
|
||||
styp += '["$v"]'
|
||||
/* else {
|
||||
println('jsgen.typ: Unhandled type $t')
|
||||
styp = sym.name
|
||||
} */
|
||||
}
|
||||
if styp.starts_with('JS.') { return styp[3..] }
|
||||
return styp
|
||||
}
|
||||
|
||||
fn (mut g JsGen) to_js_typ_val(typ string) string {
|
||||
fn (mut g JsGen) struct_typ(s string) string {
|
||||
ns := get_ns(s)
|
||||
mut name := if ns == g.namespace { s.split('.').last() } else { g.get_alias(s) }
|
||||
mut styp := ''
|
||||
match typ {
|
||||
'number' {
|
||||
for i, v in name.split('.') {
|
||||
if i == 0 { styp = v }
|
||||
else { styp += '["$v"]' }
|
||||
}
|
||||
if ns in ['', g.namespace] { return styp }
|
||||
return styp + '["prototype"]'
|
||||
}
|
||||
|
||||
fn (mut g JsGen) to_js_typ_val(t table.Type) string {
|
||||
sym := g.table.get_type_symbol(t)
|
||||
mut styp := ''
|
||||
|
||||
match sym.kind {
|
||||
.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64, .f32, .f64, .any_int, .any_float, .size_t {
|
||||
styp = '0'
|
||||
}
|
||||
'boolean' {
|
||||
.bool {
|
||||
styp = 'false'
|
||||
}
|
||||
'Object' {
|
||||
styp = '{}'
|
||||
}
|
||||
'string' {
|
||||
.string {
|
||||
styp = '""'
|
||||
}
|
||||
.map {
|
||||
styp = 'new Map()'
|
||||
}
|
||||
.array {
|
||||
styp = '[]'
|
||||
}
|
||||
.struct_ {
|
||||
styp = 'new ${g.js_name(sym.name)}({})'
|
||||
}
|
||||
else {
|
||||
if typ.starts_with('Map') {
|
||||
styp = 'new Map()'
|
||||
} else if typ.ends_with('[]') {
|
||||
styp = '[]'
|
||||
} else {
|
||||
styp = '{}'
|
||||
}
|
||||
// TODO
|
||||
styp = 'undefined'
|
||||
}
|
||||
}
|
||||
// ns.export => ns["export"]
|
||||
for i, v in styp.split('.') {
|
||||
if i == 0 {
|
||||
styp = v
|
||||
continue
|
||||
}
|
||||
styp += '["$v"]'
|
||||
}
|
||||
return styp
|
||||
}
|
||||
|
||||
pub fn (g &JsGen) save() {}
|
||||
fn (mut g JsGen) array_fixed_typ(t table.Type) ?string {
|
||||
sym := g.table.get_type_symbol(t)
|
||||
match sym.kind {
|
||||
.i8 { return 'Int8Array' }
|
||||
.i16 { return 'Int16Array' }
|
||||
.int { return 'Int32Array' }
|
||||
.i64 { return 'BigInt64Array' }
|
||||
.byte { return 'Uint8Array' }
|
||||
.u16 { return 'Uint16Array' }
|
||||
.u32 { return 'Uint32Array' }
|
||||
.u64 { return 'BigUint64Array' }
|
||||
.f32 { return 'Float32Array' }
|
||||
.f64 { return 'Float64Array' }
|
||||
else { return none }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut g JsGen) gen_indent() {
|
||||
if g.indents[g.namespace] > 0 && g.empty_line {
|
||||
|
@ -334,28 +380,19 @@ pub fn (mut g JsGen) new_tmp_var() string {
|
|||
// 'fn' => ''
|
||||
[inline]
|
||||
fn get_ns(s string) string {
|
||||
parts := s.split('.')
|
||||
mut res := ''
|
||||
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 res
|
||||
idx := s.last_index('.') or { return '' }
|
||||
return s.substr(0, idx)
|
||||
}
|
||||
|
||||
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]]
|
||||
ns := get_ns(name)
|
||||
if ns == '' { return name }
|
||||
|
||||
if alias != '' {
|
||||
return alias + '.' + split[1..].join('.')
|
||||
}
|
||||
}
|
||||
return name // No dot == no alias
|
||||
imports := g.namespace_imports[g.namespace]
|
||||
alias := imports[ns]
|
||||
if alias == '' { return name }
|
||||
|
||||
return alias + '.' + name.split('.').last()
|
||||
}
|
||||
|
||||
fn (mut g JsGen) js_name(name_ string) string {
|
||||
|
@ -519,7 +556,8 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
// TODO
|
||||
}
|
||||
ast.EnumVal {
|
||||
styp := g.typ(it.typ)
|
||||
sym := g.table.get_type_symbol(it.typ)
|
||||
styp := g.js_name(sym.name)
|
||||
g.write('${styp}.${it.val}')
|
||||
}
|
||||
ast.FloatLiteral {
|
||||
|
@ -631,26 +669,14 @@ fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) {
|
|||
fn (mut g JsGen) gen_assign_stmt(it ast.AssignStmt) {
|
||||
if it.left.len > it.right.len {
|
||||
// multi return
|
||||
jsdoc := strings.new_builder(50)
|
||||
jsdoc.write('[')
|
||||
stmt := strings.new_builder(50)
|
||||
stmt.write('const [')
|
||||
g.write('const [')
|
||||
for i, ident in it.left {
|
||||
ident_var_info := ident.var_info()
|
||||
styp := g.typ(ident_var_info.typ)
|
||||
jsdoc.write(styp)
|
||||
|
||||
stmt.write(g.js_name(ident.name))
|
||||
|
||||
g.write(g.js_name(ident.name))
|
||||
if i < it.left.len - 1 {
|
||||
jsdoc.write(', ')
|
||||
stmt.write(', ')
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
jsdoc.write(']')
|
||||
stmt.write('] = ')
|
||||
g.writeln(g.doc.gen_typ(jsdoc.str(), ''))
|
||||
g.write(stmt.str())
|
||||
g.write('] = ')
|
||||
g.expr(it.right[0])
|
||||
g.writeln(';')
|
||||
} else {
|
||||
|
@ -660,16 +686,8 @@ fn (mut g JsGen) gen_assign_stmt(it ast.AssignStmt) {
|
|||
ident_var_info := ident.var_info()
|
||||
mut styp := g.typ(ident_var_info.typ)
|
||||
|
||||
if val is ast.EnumVal {
|
||||
// we want the type of the enum value not the enum
|
||||
styp = 'number'
|
||||
} else if val is ast.StructInit {
|
||||
// no need to print jsdoc for structs
|
||||
styp = ''
|
||||
}
|
||||
|
||||
if !g.inside_loop && styp.len > 0 {
|
||||
g.writeln(g.doc.gen_typ(styp, ident.name))
|
||||
g.doc.gen_typ(styp)
|
||||
}
|
||||
|
||||
if g.inside_loop || ident.is_mut {
|
||||
|
@ -707,25 +725,16 @@ fn (mut g JsGen) gen_branch_stmt(it ast.BranchStmt) {
|
|||
}
|
||||
|
||||
fn (mut g JsGen) gen_const_decl(it ast.ConstDecl) {
|
||||
// old_indent := g.indents[g.namespace]
|
||||
for i, field in it.fields {
|
||||
// TODO hack. Cut the generated value and paste it into definitions.
|
||||
pos := g.out.len
|
||||
for field in it.fields {
|
||||
g.doc.gen_const(g.typ(field.typ))
|
||||
|
||||
if field.is_pub { g.push_pub_var(field.name) }
|
||||
|
||||
g.write('const ${g.js_name(field.name)} = ')
|
||||
g.expr(field.expr)
|
||||
val := g.out.after(pos)
|
||||
g.out.go_back(val.len)
|
||||
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('${g.js_name(field.name)}: $val')
|
||||
if i < it.fields.len - 1 {
|
||||
g.constants.writeln(',')
|
||||
}
|
||||
g.writeln(';')
|
||||
}
|
||||
g.constants.writeln('')
|
||||
g.writeln('')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_defer_stmts() {
|
||||
|
@ -738,23 +747,20 @@ fn (mut g JsGen) gen_defer_stmts() {
|
|||
}
|
||||
|
||||
fn (mut g JsGen) gen_enum_decl(it ast.EnumDecl) {
|
||||
g.writeln('const ${g.js_name(it.name)} = Object.freeze({')
|
||||
g.doc.gen_enum()
|
||||
g.writeln('const ${g.js_name(it.name)} = {')
|
||||
g.inc_indent()
|
||||
for i, field in it.fields {
|
||||
mut i := 0
|
||||
for field in it.fields {
|
||||
g.write('$field.name: ')
|
||||
if field.has_expr {
|
||||
pos := g.out.len
|
||||
g.expr(field.expr)
|
||||
expr_str := g.out.after(pos)
|
||||
g.out.go_back(expr_str.len)
|
||||
g.write('$expr_str')
|
||||
} else {
|
||||
g.write('$i')
|
||||
if field.has_expr && field.expr is ast.IntegerLiteral {
|
||||
e := field.expr as ast.IntegerLiteral
|
||||
i = e.val.int()
|
||||
}
|
||||
g.writeln(',')
|
||||
g.writeln('${i++},')
|
||||
}
|
||||
g.dec_indent()
|
||||
g.writeln('});')
|
||||
g.writeln('};')
|
||||
if it.is_pub {
|
||||
g.push_pub_var(it.name)
|
||||
}
|
||||
|
@ -810,7 +816,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
|||
// type_name := g.typ(it.return_type)
|
||||
|
||||
// generate jsdoc for the function
|
||||
g.writeln(g.doc.gen_fn(it))
|
||||
g.doc.gen_fn(it)
|
||||
|
||||
if has_go {
|
||||
g.write('async ')
|
||||
|
@ -1015,14 +1021,14 @@ fn (mut g JsGen) gen_hash_stmt(it ast.HashStmt) {
|
|||
}
|
||||
|
||||
fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
||||
g.writeln(g.doc.gen_fac_fn(node.fields))
|
||||
g.doc.gen_fac_fn(node.fields)
|
||||
g.write('function ${g.js_name(node.name)}({ ')
|
||||
for i, field in node.fields {
|
||||
g.write('$field.name = ')
|
||||
if field.has_default_expr {
|
||||
g.expr(field.default_expr)
|
||||
} else {
|
||||
g.write('${g.to_js_typ_val(g.typ(field.typ))}')
|
||||
g.write('${g.to_js_typ_val(field.typ)}')
|
||||
}
|
||||
if i < node.fields.len - 1 { g.write(', ') }
|
||||
}
|
||||
|
@ -1040,8 +1046,9 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
|||
fns := g.method_fn_decls[node.name]
|
||||
|
||||
for i, field in node.fields {
|
||||
g.writeln(g.doc.gen_typ(g.typ(field.typ), field.name))
|
||||
g.write('$field.name: ${g.to_js_typ_val(g.typ(field.typ))}')
|
||||
typ := g.typ(field.typ)
|
||||
g.doc.gen_typ(typ)
|
||||
g.write('$field.name: ${g.to_js_typ_val(field.typ)}')
|
||||
if i < node.fields.len - 1 || fns.len > 0 { g.writeln(',') } else { g.writeln('') }
|
||||
}
|
||||
|
||||
|
@ -1074,8 +1081,15 @@ fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) {
|
|||
|
||||
fn (mut g JsGen) gen_assign_expr(it ast.AssignExpr) {
|
||||
g.expr(it.left)
|
||||
g.write(' $it.op ')
|
||||
g.expr(it.val)
|
||||
if g.inside_map_set && it.op == .assign {
|
||||
g.inside_map_set = false
|
||||
g.write(', ')
|
||||
g.expr(it.val)
|
||||
g.write(')')
|
||||
} else {
|
||||
g.write(' $it.op ')
|
||||
g.expr(it.val)
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
||||
|
@ -1105,11 +1119,6 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
|||
}
|
||||
|
||||
fn (mut g JsGen) gen_ident(node ast.Ident) {
|
||||
if node.kind == .constant {
|
||||
// TODO: Handle const namespacing: only consts in the main module are handled rn
|
||||
g.write('_CONSTS.')
|
||||
}
|
||||
|
||||
name := g.js_name(node.name)
|
||||
// TODO `is`
|
||||
// TODO handle optionals
|
||||
|
@ -1172,6 +1181,7 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
|||
}
|
||||
|
||||
fn (mut g JsGen) gen_index_expr(it ast.IndexExpr) {
|
||||
left_typ := g.table.get_type_symbol(it.left_type)
|
||||
// TODO: Handle splice setting if it's implemented
|
||||
if it.index is ast.RangeExpr {
|
||||
range := it.index as ast.RangeExpr
|
||||
|
@ -1190,8 +1200,28 @@ fn (mut g JsGen) gen_index_expr(it ast.IndexExpr) {
|
|||
g.write('.length')
|
||||
}
|
||||
g.write(')')
|
||||
} else if left_typ.kind == .map {
|
||||
g.expr(it.left)
|
||||
if it.is_setter {
|
||||
g.inside_map_set = true
|
||||
g.write('.set(')
|
||||
} else {
|
||||
g.write('.get(')
|
||||
}
|
||||
g.expr(it.index)
|
||||
if !it.is_setter { g.write(')') }
|
||||
} else if left_typ.kind == .string {
|
||||
if it.is_setter {
|
||||
// TODO: What's the best way to do this?
|
||||
// 'string'[3] = `o`
|
||||
} else {
|
||||
g.expr(it.left)
|
||||
g.write('.charCodeAt(')
|
||||
g.expr(it.index)
|
||||
g.write(')')
|
||||
}
|
||||
} else {
|
||||
// TODO Does this work in all cases?
|
||||
// TODO Does this cover all cases?
|
||||
g.expr(it.left)
|
||||
g.write('[')
|
||||
g.expr(it.index)
|
||||
|
@ -1209,6 +1239,13 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
|||
if r_sym.kind == .array { g.write('...') } // arr << [1, 2]
|
||||
g.expr(it.right)
|
||||
g.write(')')
|
||||
} else if r_sym.kind in [.array, .map] && it.op in [.key_in, .not_in] {
|
||||
if it.op == .not_in { g.write('!(') }
|
||||
g.expr(it.right)
|
||||
g.write(if r_sym.kind == .map { '.has(' } else { '.includes(' })
|
||||
g.expr(it.left)
|
||||
g.write(')')
|
||||
if it.op == .not_in { g.write(')') }
|
||||
} else if it.op == .key_is { // foo is Foo
|
||||
g.write('/*')
|
||||
g.expr(it.left)
|
||||
|
|
|
@ -1,79 +1,59 @@
|
|||
module js
|
||||
|
||||
import strings
|
||||
import v.ast
|
||||
|
||||
struct JsDoc {
|
||||
gen &JsGen
|
||||
mut:
|
||||
out strings.Builder
|
||||
empty_line bool
|
||||
}
|
||||
|
||||
fn new_jsdoc(gen &JsGen) &JsDoc {
|
||||
return &JsDoc{
|
||||
out: strings.new_builder(20)
|
||||
gen: gen
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut d JsDoc) gen_indent() {
|
||||
if d.gen.indents[d.gen.namespace] > 0 && d.empty_line {
|
||||
d.out.write(tabs[d.gen.indents[d.gen.namespace]])
|
||||
}
|
||||
d.empty_line = false
|
||||
}
|
||||
|
||||
fn (mut d JsDoc) write(s string) {
|
||||
if !d.gen.enable_doc { return }
|
||||
d.gen_indent()
|
||||
d.out.write(s)
|
||||
d.gen.write(s)
|
||||
}
|
||||
|
||||
fn (mut d JsDoc) writeln(s string) {
|
||||
if !d.gen.enable_doc { return }
|
||||
d.gen_indent()
|
||||
d.out.writeln(s)
|
||||
d.empty_line = true
|
||||
d.gen.writeln(s)
|
||||
}
|
||||
|
||||
fn (mut d JsDoc) reset() {
|
||||
d.out = strings.new_builder(20)
|
||||
d.empty_line = false
|
||||
fn (mut d JsDoc) gen_typ(typ string) {
|
||||
d.writeln('/** @type {$typ} */')
|
||||
}
|
||||
|
||||
fn (mut d JsDoc) gen_typ(typ, name string) string {
|
||||
d.reset()
|
||||
d.write('/**')
|
||||
d.write(' @type {$typ}')
|
||||
if name.len > 0 {
|
||||
d.write(' - ${d.gen.js_name(name)}')
|
||||
}
|
||||
d.write(' */')
|
||||
return d.out.str()
|
||||
fn (mut d JsDoc) gen_const(typ string) {
|
||||
d.writeln('/** @constant {$typ} */')
|
||||
}
|
||||
|
||||
fn (mut d JsDoc) gen_fac_fn(fields []ast.StructField) string {
|
||||
d.reset()
|
||||
fn (mut d JsDoc) gen_enum() {
|
||||
// Enum values can only be ints for now
|
||||
typ := 'number'
|
||||
d.writeln('/** @enum {$typ} */')
|
||||
}
|
||||
|
||||
fn (mut d JsDoc) gen_fac_fn(fields []ast.StructField) {
|
||||
d.writeln('/**')
|
||||
d.writeln(' * @constructor')
|
||||
d.write(' * @param {{')
|
||||
for i, field in fields {
|
||||
// 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 { d.write(', ') }
|
||||
}
|
||||
d.writeln('}} values - values for this class fields')
|
||||
d.writeln(' * @constructor')
|
||||
d.write('*/')
|
||||
return d.out.str()
|
||||
d.writeln('}} init')
|
||||
d.writeln('*/')
|
||||
}
|
||||
|
||||
fn (mut d JsDoc) gen_fn(it ast.FnDecl) string {
|
||||
d.reset()
|
||||
fn (mut d JsDoc) gen_fn(it ast.FnDecl) {
|
||||
type_name := d.gen.typ(it.return_type)
|
||||
d.writeln('/**')
|
||||
d.writeln(' * @function')
|
||||
if it.is_deprecated {
|
||||
d.writeln(' * @deprecated')
|
||||
}
|
||||
|
@ -91,13 +71,5 @@ fn (mut d JsDoc) gen_fn(it ast.FnDecl) string {
|
|||
}
|
||||
}
|
||||
d.writeln(' * @returns {$type_name}')
|
||||
d.writeln(' * @function')
|
||||
d.write('*/')
|
||||
return d.out.str()
|
||||
}
|
||||
|
||||
fn (mut d JsDoc) gen_namespace(ns string) string {
|
||||
d.reset()
|
||||
d.writeln('/** @namespace ${ns} */')
|
||||
return d.out.str()
|
||||
d.writeln('*/')
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// V_COMMIT_HASH 0de70e8
|
||||
// V_CURRENT_COMMIT_HASH 2eac2a5
|
||||
// V_COMMIT_HASH 2943bdc
|
||||
// V_CURRENT_COMMIT_HASH ad5deef
|
||||
// Generated by the V compiler
|
||||
|
||||
"use strict";
|
||||
|
@ -7,18 +7,18 @@
|
|||
/** @namespace builtin */
|
||||
const builtin = (function () {
|
||||
/**
|
||||
* @function
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function println(s) {
|
||||
console.log(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function print(s) {
|
||||
process.stdout.write(s);
|
||||
|
@ -34,9 +34,9 @@ const builtin = (function () {
|
|||
/** @namespace main */
|
||||
const main = (function () {
|
||||
/**
|
||||
* @function
|
||||
* @param {...number} args
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function variadic(...args) {
|
||||
builtin.println(args);
|
||||
|
@ -45,8 +45,8 @@ const main = (function () {
|
|||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function vararg_test() {
|
||||
variadic(1, 2, 3);
|
||||
|
@ -55,17 +55,17 @@ const main = (function () {
|
|||
/* program entry point */
|
||||
(function() {
|
||||
vararg_test();
|
||||
/** @type {string[]} - arr1 */
|
||||
/** @type {string[]} */
|
||||
const arr1 = ["Hello", "JS", "Backend"];
|
||||
/** @type {number[]} - arr2 */
|
||||
/** @type {number[]} */
|
||||
let arr2 = [1, 2, 3, 4, 5];
|
||||
/** @type {string[]} - slice1 */
|
||||
/** @type {string[]} */
|
||||
const slice1 = arr1.slice(1, 3);
|
||||
/** @type {number[]} - slice2 */
|
||||
/** @type {number[]} */
|
||||
const slice2 = arr2.slice(0, 3);
|
||||
/** @type {number[]} - slice3 */
|
||||
/** @type {number[]} */
|
||||
const slice3 = arr2.slice(3, arr2.length);
|
||||
/** @type {string} - idx1 */
|
||||
/** @type {string} */
|
||||
const idx1 = slice1[1];
|
||||
arr2[0] = 1;
|
||||
arr2[0 + 1] = 2;
|
||||
|
@ -73,19 +73,24 @@ const main = (function () {
|
|||
arr2.push(6);
|
||||
arr2.push(...[7, 8, 9]);
|
||||
builtin.println(arr2);
|
||||
/** @type {string} - slice4 */
|
||||
const slice4 = idx1.slice(0, 4);
|
||||
/** @type {string} */
|
||||
let slice4 = idx1.slice(0, 4);
|
||||
builtin.println(slice4);
|
||||
/** @type {byte} - idx2 */
|
||||
const idx2 = slice4[0];
|
||||
/** @type {Map<string, string>} - m */
|
||||
/** @type {number} */
|
||||
const idx2 = slice4.charCodeAt(0);
|
||||
builtin.println(idx2);
|
||||
/** @type {Map<string, string>} */
|
||||
let m = new Map();
|
||||
/** @type {string} - key */
|
||||
/** @type {string} */
|
||||
const key = "key";
|
||||
m[key] = "value";
|
||||
/** @type {string} - val */
|
||||
const val = m["key"];
|
||||
m.set(key, "value");
|
||||
/** @type {string} */
|
||||
const val = m.get("key");
|
||||
builtin.println(val);
|
||||
builtin.println(arr1.includes("JS"));
|
||||
builtin.println(!(arr2.includes(3)));
|
||||
builtin.println(m.has("key"));
|
||||
builtin.println(!(m.has("badkey")));
|
||||
})();
|
||||
|
||||
/* module exports */
|
||||
|
|
|
@ -34,15 +34,24 @@ arr2 << [7, 8, 9]
|
|||
println(arr2)
|
||||
|
||||
// String slices
|
||||
slice4 := idx1[..4]
|
||||
mut slice4 := idx1[..4]
|
||||
println(slice4) // 'Back'
|
||||
|
||||
// String indexes
|
||||
idx2 := slice4[0]
|
||||
println(idx2)
|
||||
// TODO:
|
||||
// slice4[3] = `c`
|
||||
|
||||
// Maps
|
||||
mut m := map[string]string
|
||||
key := 'key'
|
||||
m[key] = 'value'
|
||||
val := m['key']
|
||||
println(val)
|
||||
println(val)
|
||||
|
||||
// 'in' / '!in'
|
||||
println('JS' in arr1)
|
||||
println(3 !in arr2)
|
||||
println('key' in m)
|
||||
println('badkey' !in m)
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
// V_COMMIT_HASH 2943bdc
|
||||
// V_CURRENT_COMMIT_HASH ad5deef
|
||||
// Generated by the V compiler
|
||||
|
||||
"use strict";
|
||||
|
||||
/** @namespace builtin */
|
||||
const builtin = (function () {
|
||||
/**
|
||||
* @function
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
*/
|
||||
function println(s) {
|
||||
console.log(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
*/
|
||||
function print(s) {
|
||||
process.stdout.write(s);
|
||||
}
|
||||
|
||||
/* module exports */
|
||||
return {
|
||||
println,
|
||||
print,
|
||||
};
|
||||
})();
|
||||
|
||||
/** @namespace hello */
|
||||
const hello = (function () {
|
||||
/**
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function raw_js_log() {
|
||||
console.log('hello')
|
||||
}
|
||||
|
||||
/** @constant {string} */
|
||||
const hello = "Hello";
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {{foo?: string}} init
|
||||
*/
|
||||
function Aaa({ foo = "" }) {
|
||||
this.foo = foo
|
||||
};
|
||||
Aaa.prototype = {
|
||||
/** @type {string} */
|
||||
foo: "",
|
||||
/**
|
||||
* @function
|
||||
* @param {string} s
|
||||
* @returns {void}
|
||||
*/
|
||||
update(s) {
|
||||
const a = this;
|
||||
a.foo = s;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {{}} init
|
||||
*/
|
||||
function Bbb({ }) {
|
||||
};
|
||||
Bbb.prototype = {
|
||||
};
|
||||
|
||||
/** @enum {number} */
|
||||
const Ccc = {
|
||||
a: 0,
|
||||
b: 5,
|
||||
c: 6,
|
||||
};
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @returns {string}
|
||||
*/
|
||||
function v_debugger() {
|
||||
/** @type {Bbb} */
|
||||
const v = new Bbb({});
|
||||
return hello;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @returns {string}
|
||||
*/
|
||||
function excited() {
|
||||
return v_debugger() + "!";
|
||||
}
|
||||
|
||||
/* module exports */
|
||||
return {
|
||||
raw_js_log,
|
||||
Aaa,
|
||||
Ccc,
|
||||
v_debugger,
|
||||
excited,
|
||||
};
|
||||
})();
|
||||
|
||||
/** @namespace main */
|
||||
const main = (function (hello) {
|
||||
/** @enum {number} */
|
||||
const Test = {
|
||||
foo: 2,
|
||||
bar: 5,
|
||||
baz: 6,
|
||||
};
|
||||
|
||||
/* program entry point */
|
||||
(function() {
|
||||
/** @type {number} */
|
||||
let a = hello.Ccc.a;
|
||||
a = hello.Ccc.b;
|
||||
a = hello.Ccc.c;
|
||||
builtin.println(a);
|
||||
/** @type {number} */
|
||||
let b = Test.foo;
|
||||
b = Test.bar;
|
||||
builtin.println(b);
|
||||
})();
|
||||
|
||||
/* module exports */
|
||||
return {};
|
||||
})(hello);
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import hello
|
||||
|
||||
enum Test {
|
||||
foo = 2
|
||||
bar = 5
|
||||
baz
|
||||
}
|
||||
|
||||
mut a := hello.Ccc.a
|
||||
a = .b
|
||||
a = .c
|
||||
println(a)
|
||||
|
||||
|
||||
mut b := Test.foo
|
||||
b = .bar
|
||||
println(b)
|
|
@ -1,11 +1,8 @@
|
|||
module hello
|
||||
|
||||
// TODO: Fix const namespacing, uncomment once it works
|
||||
/*
|
||||
pub const (
|
||||
hello = 'Hello'
|
||||
)
|
||||
*/
|
||||
|
||||
pub struct Aaa {
|
||||
pub mut:
|
||||
|
@ -18,11 +15,15 @@ pub fn (mut a Aaa) update(s string) {
|
|||
|
||||
struct Bbb {}
|
||||
|
||||
pub enum Ccc {}
|
||||
pub enum Ccc {
|
||||
a
|
||||
b = 5
|
||||
c
|
||||
}
|
||||
|
||||
pub fn debugger() string {
|
||||
v := Bbb{}
|
||||
return 'Hello'
|
||||
return hello
|
||||
}
|
||||
|
||||
pub fn excited() string {
|
||||
|
|
|
@ -1,31 +1,24 @@
|
|||
// V_COMMIT_HASH 5423a15
|
||||
// V_CURRENT_COMMIT_HASH 941404d
|
||||
// V_COMMIT_HASH 2943bdc
|
||||
// V_CURRENT_COMMIT_HASH ad5deef
|
||||
// Generated by the V compiler
|
||||
|
||||
"use strict";
|
||||
|
||||
const _CONSTS = Object.freeze({
|
||||
/** @type {number} - i_am_a_const */
|
||||
i_am_a_const: 21214,
|
||||
/** @type {string} - v_super */
|
||||
v_super: "amazing keyword"
|
||||
});
|
||||
|
||||
/** @namespace builtin */
|
||||
const builtin = (function () {
|
||||
/**
|
||||
* @function
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function println(s) {
|
||||
console.log(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function print(s) {
|
||||
process.stdout.write(s);
|
||||
|
@ -41,27 +34,30 @@ const builtin = (function () {
|
|||
/** @namespace hello */
|
||||
const hello = (function () {
|
||||
/**
|
||||
* @returns {void}
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function raw_js_log() {
|
||||
console.log('hello')
|
||||
}
|
||||
|
||||
/** @constant {string} */
|
||||
const hello = "Hello";
|
||||
|
||||
/**
|
||||
* @param {{foo?: string}} values - values for this class fields
|
||||
* @constructor
|
||||
* @param {{foo?: string}} init
|
||||
*/
|
||||
function Aaa({ foo = "" }) {
|
||||
this.foo = foo
|
||||
};
|
||||
Aaa.prototype = {
|
||||
/** @type {string} - foo */
|
||||
/** @type {string} */
|
||||
foo: "",
|
||||
/**
|
||||
* @function
|
||||
* @param {string} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
update(s) {
|
||||
const a = this;
|
||||
|
@ -71,29 +67,34 @@ const hello = (function () {
|
|||
|
||||
|
||||
/**
|
||||
* @param {{}} values - values for this class fields
|
||||
* @constructor
|
||||
* @param {{}} init
|
||||
*/
|
||||
function Bbb({ }) {
|
||||
};
|
||||
Bbb.prototype = {
|
||||
};
|
||||
|
||||
const Ccc = Object.freeze({
|
||||
});
|
||||
/** @enum {number} */
|
||||
const Ccc = {
|
||||
a: 0,
|
||||
b: 5,
|
||||
c: 6,
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
* @function
|
||||
* @returns {string}
|
||||
*/
|
||||
function v_debugger() {
|
||||
/** @type {Bbb} */
|
||||
const v = new Bbb({});
|
||||
return "Hello";
|
||||
return hello;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
* @function
|
||||
* @returns {string}
|
||||
*/
|
||||
function excited() {
|
||||
return v_debugger() + "!";
|
||||
|
@ -111,21 +112,26 @@ const hello = (function () {
|
|||
|
||||
/** @namespace main */
|
||||
const main = (function (hl) {
|
||||
/** @constant {number} */
|
||||
const i_am_a_const = 21214;
|
||||
/** @constant {string} */
|
||||
const v_super = "amazing keyword";
|
||||
|
||||
/**
|
||||
* @param {{a?: hl["Aaa"]["prototype"]}} values - values for this class fields
|
||||
* @constructor
|
||||
* @param {{a?: hl["Aaa"]["prototype"]}} init
|
||||
*/
|
||||
function Foo({ a = {} }) {
|
||||
function Foo({ a = new hl.Aaa({}) }) {
|
||||
this.a = a
|
||||
};
|
||||
Foo.prototype = {
|
||||
/** @type {hl["Aaa"]["prototype"]} - a */
|
||||
a: {}
|
||||
/** @type {hl["Aaa"]["prototype"]} */
|
||||
a: new hl.Aaa({})
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {{google?: number, amazon?: boolean, yahoo?: string}} values - values for this class fields
|
||||
* @constructor
|
||||
* @param {{google?: number, amazon?: boolean, yahoo?: string}} init
|
||||
*/
|
||||
function Companies({ google = 0, amazon = false, yahoo = "" }) {
|
||||
this.google = google
|
||||
|
@ -133,26 +139,26 @@ const main = (function (hl) {
|
|||
this.yahoo = yahoo
|
||||
};
|
||||
Companies.prototype = {
|
||||
/** @type {number} - google */
|
||||
/** @type {number} */
|
||||
google: 0,
|
||||
/** @type {boolean} - amazon */
|
||||
/** @type {boolean} */
|
||||
amazon: false,
|
||||
/** @type {string} - yahoo */
|
||||
/** @type {string} */
|
||||
yahoo: "",
|
||||
/**
|
||||
* @returns {number}
|
||||
* @function
|
||||
* @returns {number}
|
||||
*/
|
||||
method() {
|
||||
const it = this;
|
||||
/** @type {Companies} */
|
||||
const ss = new Companies({
|
||||
google: 2,
|
||||
amazon: true,
|
||||
yahoo: "hello"
|
||||
});
|
||||
/** @type {[number, number]} */
|
||||
const [a, b] = hello(2, "google", "not google");
|
||||
/** @type {string} - glue */
|
||||
/** @type {string} */
|
||||
const glue = (a > 2 ? "more_glue" : a > 5 ? "more glueee" : "less glue");
|
||||
if (a !== 2) {
|
||||
}
|
||||
|
@ -161,56 +167,63 @@ const main = (function (hl) {
|
|||
}
|
||||
};
|
||||
|
||||
const POSITION = Object.freeze({
|
||||
/** @enum {number} */
|
||||
const POSITION = {
|
||||
go_back: 0,
|
||||
dont_go_back: 1,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {string} v_extends
|
||||
* @param {number} v_instanceof
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function v_class(v_extends, v_instanceof) {
|
||||
/** @type {number} - v_delete */
|
||||
/** @type {number} */
|
||||
const v_delete = v_instanceof;
|
||||
}
|
||||
|
||||
/* program entry point */
|
||||
(async function() {
|
||||
builtin.println("Hello from V.js!");
|
||||
/** @type {number} - a */
|
||||
/** @type {number} */
|
||||
let a = 1;
|
||||
a *= 2;
|
||||
a += 3;
|
||||
builtin.println(a);
|
||||
/** @type {hl["Aaa"]["prototype"]} */
|
||||
const b = new hl.Aaa({});
|
||||
b.update("an update");
|
||||
builtin.println(b);
|
||||
/** @type {Foo} */
|
||||
const c = new Foo({
|
||||
a: new hl.Aaa({})
|
||||
});
|
||||
c.a.update("another update");
|
||||
builtin.println(c);
|
||||
/** @type {string} - v */
|
||||
/** @type {string} */
|
||||
const v = "done";
|
||||
{
|
||||
/** @type {string} - _ */
|
||||
/** @type {string} */
|
||||
const _ = "block";
|
||||
}
|
||||
|
||||
/** @type {number} - pos */
|
||||
/** @type {number} */
|
||||
const pos = POSITION.go_back;
|
||||
/** @type {string} - v_debugger */
|
||||
/** @type {number} */
|
||||
const enum2 = hl.Ccc.a;
|
||||
/** @type {string} */
|
||||
const v_debugger = "JS keywords";
|
||||
/** @type {string} - v_await */
|
||||
const v_await = _CONSTS.v_super + ": " + v_debugger;
|
||||
/** @type {string} - v_finally */
|
||||
/** @type {string} */
|
||||
const v_await = v_super + ": " + v_debugger;
|
||||
/** @type {string} */
|
||||
let v_finally = "implemented";
|
||||
console.log(v_await, v_finally);
|
||||
/** @type {number} - dun */
|
||||
const dun = _CONSTS.i_am_a_const * 20;
|
||||
/** @type {number} */
|
||||
const dun = i_am_a_const * 20;
|
||||
/** @type {string} */
|
||||
const dunn = hl.hello;
|
||||
for (let i = 0; i < 10; i++) {
|
||||
}
|
||||
|
||||
|
@ -221,19 +234,19 @@ const main = (function (hl) {
|
|||
for (let x = 1; x < 10; ++x) {
|
||||
}
|
||||
|
||||
/** @type {number[]} - arr */
|
||||
/** @type {number[]} */
|
||||
const arr = [1, 2, 3, 4, 5];
|
||||
for (let _tmp1 = 0; _tmp1 < arr.length; ++_tmp1) {
|
||||
let i = arr[_tmp1];
|
||||
}
|
||||
|
||||
/** @type {Map<string, string>} - ma */
|
||||
/** @type {Map<string, string>} */
|
||||
const ma = new Map([
|
||||
["str", "done"],
|
||||
["ddo", "baba"]
|
||||
]);
|
||||
for (let [m, n] of ma) {
|
||||
/** @type {string} - iss */
|
||||
/** @type {string} */
|
||||
const iss = m;
|
||||
}
|
||||
|
||||
|
@ -242,7 +255,7 @@ const main = (function (hl) {
|
|||
resolve();
|
||||
});
|
||||
|
||||
/** @type {(number: number) => void} - fn_in_var */
|
||||
/** @type {(number: number) => void} */
|
||||
const fn_in_var = function (number) {
|
||||
builtin.println(tos3(`number: ${number}`));
|
||||
};
|
||||
|
@ -254,20 +267,20 @@ const main = (function (hl) {
|
|||
})();
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {string} greeting
|
||||
* @param {(message: string) => void} anon
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function anon_consumer(greeting, anon) {
|
||||
anon(greeting);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {number} num
|
||||
* @param {string} def
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function async(num, def) {
|
||||
}
|
||||
|
@ -275,21 +288,21 @@ const main = (function (hl) {
|
|||
/* [inline] */
|
||||
/* [deprecated] */
|
||||
/**
|
||||
* @function
|
||||
* @deprecated
|
||||
* @param {number} game_on
|
||||
* @param {...string} dummy
|
||||
* @returns {[number, number]}
|
||||
* @function
|
||||
*/
|
||||
function hello(game_on, ...dummy) {
|
||||
for (let _tmp2 = 0; _tmp2 < dummy.length; ++_tmp2) {
|
||||
let dd = dummy[_tmp2];
|
||||
/** @type {string} - l */
|
||||
/** @type {string} */
|
||||
const l = dd;
|
||||
}
|
||||
|
||||
(function defer() {
|
||||
/** @type {string} - v_do */
|
||||
/** @type {string} */
|
||||
const v_do = "not";
|
||||
})();
|
||||
return [game_on + 2, 221];
|
||||
|
|
|
@ -49,6 +49,7 @@ fn main() {
|
|||
}
|
||||
|
||||
pos := POSITION.go_back
|
||||
enum2 := hl.Ccc.a
|
||||
|
||||
debugger := 'JS keywords'
|
||||
// TODO: Implement interpolation
|
||||
|
@ -58,6 +59,7 @@ fn main() {
|
|||
JS.console.log(await, finally)
|
||||
|
||||
dun := i_am_a_const * 20
|
||||
dunn := hl.hello // External constant
|
||||
|
||||
for i := 0; i < 10; i++ {}
|
||||
|
||||
|
|
|
@ -1,31 +1,24 @@
|
|||
// V_COMMIT_HASH 0de70e8
|
||||
// V_CURRENT_COMMIT_HASH 1c2dbea
|
||||
// V_COMMIT_HASH 2943bdc
|
||||
// V_CURRENT_COMMIT_HASH ad5deef
|
||||
// Generated by the V compiler
|
||||
|
||||
"use strict";
|
||||
|
||||
const _CONSTS = Object.freeze({
|
||||
/** @type {number} - w */
|
||||
w: 30,
|
||||
/** @type {number} - h */
|
||||
h: 30
|
||||
});
|
||||
|
||||
/** @namespace builtin */
|
||||
const builtin = (function () {
|
||||
/**
|
||||
* @function
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function println(s) {
|
||||
console.log(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function print(s) {
|
||||
process.stdout.write(s);
|
||||
|
@ -41,26 +34,31 @@ const builtin = (function () {
|
|||
/** @namespace main */
|
||||
const main = (function () {
|
||||
/**
|
||||
* @returns {void}
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function clear() {
|
||||
console.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean[]} game
|
||||
/** @constant {number} */
|
||||
const w = 30;
|
||||
/** @constant {number} */
|
||||
const h = 30;
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {boolean[][]} game
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @returns {boolean}
|
||||
* @function
|
||||
*/
|
||||
function get(game, x, y) {
|
||||
if (y < 0 || x < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (y >= _CONSTS.h || x >= _CONSTS.w) {
|
||||
if (y >= h || x >= w) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -68,14 +66,14 @@ const main = (function () {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {boolean[]} game
|
||||
* @function
|
||||
* @param {boolean[][]} game
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @returns {number}
|
||||
* @function
|
||||
*/
|
||||
function neighbours(game, x, y) {
|
||||
/** @type {number} - count */
|
||||
/** @type {number} */
|
||||
let count = 0;
|
||||
if (get(game, x - 1, y - 1)) {
|
||||
count++;
|
||||
|
@ -113,21 +111,21 @@ const main = (function () {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {boolean[]} game
|
||||
* @returns {boolean[]}
|
||||
* @function
|
||||
* @param {boolean[][]} game
|
||||
* @returns {boolean[][]}
|
||||
*/
|
||||
function step(game) {
|
||||
/** @type {boolean[]} - new_game */
|
||||
/** @type {boolean[][]} */
|
||||
let new_game = [[]];
|
||||
for (let y = 0; y < game.length; ++y) {
|
||||
let row = game[y];
|
||||
/** @type {boolean[]} - new_row */
|
||||
/** @type {boolean[]} */
|
||||
let new_row = [];
|
||||
new_game[y] = new_row;
|
||||
for (let x = 0; x < row.length; ++x) {
|
||||
let cell = row[x];
|
||||
/** @type {number} - count */
|
||||
/** @type {number} */
|
||||
const count = neighbours(game, x, y);
|
||||
new_row[x] = cell && count === 2 || count === 3;
|
||||
}
|
||||
|
@ -138,12 +136,12 @@ const main = (function () {
|
|||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {boolean[]} row
|
||||
* @returns {string}
|
||||
* @function
|
||||
*/
|
||||
function row_str(row) {
|
||||
/** @type {string} - str */
|
||||
/** @type {string} */
|
||||
let str = "";
|
||||
for (let _tmp1 = 0; _tmp1 < row.length; ++_tmp1) {
|
||||
let cell = row[_tmp1];
|
||||
|
@ -159,9 +157,9 @@ const main = (function () {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {boolean[]} game
|
||||
* @returns {void}
|
||||
* @function
|
||||
* @param {boolean[][]} game
|
||||
* @returns {void}
|
||||
*/
|
||||
function show(game) {
|
||||
clear();
|
||||
|
@ -174,12 +172,12 @@ const main = (function () {
|
|||
|
||||
/* program entry point */
|
||||
(function() {
|
||||
/** @type {boolean[]} - game */
|
||||
/** @type {boolean[][]} */
|
||||
let game = [[]];
|
||||
for (let y = 0; y < _CONSTS.h; ++y) {
|
||||
/** @type {boolean[]} - row */
|
||||
for (let y = 0; y < h; ++y) {
|
||||
/** @type {boolean[]} */
|
||||
let row = [];
|
||||
for (let x = 0; x < _CONSTS.w; ++x) {
|
||||
for (let x = 0; x < w; ++x) {
|
||||
row[x] = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
// V_COMMIT_HASH 0de70e8
|
||||
// V_CURRENT_COMMIT_HASH 0de70e8
|
||||
// V_COMMIT_HASH 2943bdc
|
||||
// V_CURRENT_COMMIT_HASH ad5deef
|
||||
// Generated by the V compiler
|
||||
|
||||
"use strict";
|
||||
|
||||
/* namespace: builtin */
|
||||
/** @namespace builtin */
|
||||
const builtin = (function () {
|
||||
/**
|
||||
* @param {string} s
|
||||
* @function
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
*/
|
||||
function println(s) {
|
||||
|
@ -15,7 +16,8 @@ const builtin = (function () {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
* @function
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
*/
|
||||
function print(s) {
|
||||
|
@ -29,7 +31,7 @@ const builtin = (function () {
|
|||
};
|
||||
})();
|
||||
|
||||
/* namespace: main */
|
||||
/** @namespace main */
|
||||
const main = (function () {
|
||||
/* program entry point */
|
||||
(function() {
|
||||
|
@ -37,8 +39,7 @@ const main = (function () {
|
|||
})();
|
||||
|
||||
/* module exports */
|
||||
return {
|
||||
};
|
||||
return {};
|
||||
})();
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// V_COMMIT_HASH 7e55261
|
||||
// V_CURRENT_COMMIT_HASH 79b1f27
|
||||
// V_COMMIT_HASH 2943bdc
|
||||
// V_CURRENT_COMMIT_HASH ad5deef
|
||||
// Generated by the V compiler
|
||||
|
||||
"use strict";
|
||||
|
@ -7,18 +7,18 @@
|
|||
/** @namespace builtin */
|
||||
const builtin = (function () {
|
||||
/**
|
||||
* @function
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function println(s) {
|
||||
console.log(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function print(s) {
|
||||
process.stdout.write(s);
|
||||
|
@ -34,8 +34,8 @@ const builtin = (function () {
|
|||
/** @namespace main */
|
||||
const main = (function () {
|
||||
/**
|
||||
* @param {{value?: number, test?: Map<string, number>, hello?: number[]}} values - values for this class fields
|
||||
* @constructor
|
||||
* @param {{value?: number, test?: Map<string, number>, hello?: number[]}} init
|
||||
*/
|
||||
function Int({ value = 0, test = new Map(), hello = [] }) {
|
||||
this.value = value
|
||||
|
@ -43,24 +43,24 @@ const main = (function () {
|
|||
this.hello = hello
|
||||
};
|
||||
Int.prototype = {
|
||||
/** @type {number} - value */
|
||||
/** @type {number} */
|
||||
value: 0,
|
||||
/** @type {Map<string, number>} - test */
|
||||
/** @type {Map<string, number>} */
|
||||
test: new Map(),
|
||||
/** @type {number[]} - hello */
|
||||
/** @type {number[]} */
|
||||
hello: [],
|
||||
/**
|
||||
* @function
|
||||
* @param {number} value
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
add(value) {
|
||||
const i = this;
|
||||
i.value += value;
|
||||
},
|
||||
/**
|
||||
* @returns {number}
|
||||
* @function
|
||||
* @returns {number}
|
||||
*/
|
||||
get() {
|
||||
const i = this;
|
||||
|
@ -70,16 +70,49 @@ const main = (function () {
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {{foo?: number, bar?: string}} init
|
||||
*/
|
||||
function Config({ foo = 0, bar = "" }) {
|
||||
this.foo = foo
|
||||
this.bar = bar
|
||||
};
|
||||
Config.prototype = {
|
||||
/** @type {number} */
|
||||
foo: 0,
|
||||
/** @type {string} */
|
||||
bar: ""
|
||||
};
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Config} c
|
||||
* @returns {void}
|
||||
*/
|
||||
function use_config(c) {
|
||||
}
|
||||
|
||||
/* program entry point */
|
||||
(function() {
|
||||
/** @type {Int} */
|
||||
const a = new Int({
|
||||
value: 10
|
||||
});
|
||||
a.add(5);
|
||||
builtin.println(a);
|
||||
/** @type {Int} */
|
||||
const b = new Int({});
|
||||
b.add(10);
|
||||
builtin.println(b.get());
|
||||
use_config(new Config({
|
||||
foo: 2,
|
||||
bar: "bar"
|
||||
}));
|
||||
use_config(new Config({
|
||||
foo: 2,
|
||||
bar: "bar"
|
||||
}));
|
||||
})();
|
||||
|
||||
/* module exports */
|
||||
|
|
|
@ -15,6 +15,13 @@ fn (i Int) get() int {
|
|||
return i.value
|
||||
}
|
||||
|
||||
struct Config {
|
||||
foo int
|
||||
bar string
|
||||
}
|
||||
|
||||
fn use_config(c Config) {}
|
||||
|
||||
fn main() {
|
||||
a := Int { value: 10 }
|
||||
a.add(5)
|
||||
|
@ -23,4 +30,7 @@ fn main() {
|
|||
b := Int{}
|
||||
b.add(10)
|
||||
println(b.get()) // 10
|
||||
|
||||
use_config(Config{ 2, 'bar' })
|
||||
use_config(foo: 2, bar: 'bar')
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue