jsgen: start implementing remaining `expr`s and `stmt`s
parent
fd4d28b7b6
commit
4189190bb8
|
@ -4,7 +4,6 @@ import strings
|
|||
import v.ast
|
||||
import v.table
|
||||
import v.pref
|
||||
import term
|
||||
import v.util
|
||||
import v.depgraph
|
||||
|
||||
|
@ -193,7 +192,6 @@ pub fn (g JsGen) hashes() string {
|
|||
return res
|
||||
}
|
||||
|
||||
|
||||
// V type to JS type
|
||||
pub fn (mut g JsGen) typ(t table.Type) string {
|
||||
sym := g.table.get_type_symbol(t)
|
||||
|
@ -382,9 +380,6 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||
g.stmt_start_pos = g.out.len
|
||||
|
||||
match node {
|
||||
ast.Module {
|
||||
// TODO: Implement namespaces
|
||||
}
|
||||
ast.AssertStmt {
|
||||
g.gen_assert_stmt(it)
|
||||
}
|
||||
|
@ -401,12 +396,15 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||
ast.BranchStmt {
|
||||
g.gen_branch_stmt(it)
|
||||
}
|
||||
ast.ConstDecl {
|
||||
g.gen_const_decl(it)
|
||||
ast.Comment {
|
||||
// Skip: don't generate comments
|
||||
}
|
||||
ast.CompIf {
|
||||
// skip: JS has no compile time if
|
||||
}
|
||||
ast.ConstDecl {
|
||||
g.gen_const_decl(it)
|
||||
}
|
||||
ast.DeferStmt {
|
||||
g.defer_stmts << *it
|
||||
}
|
||||
|
@ -434,6 +432,9 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||
g.gen_for_stmt(it)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.GlobalDecl {
|
||||
// TODO
|
||||
}
|
||||
ast.GoStmt {
|
||||
g.gen_go_stmt(it)
|
||||
g.writeln('')
|
||||
|
@ -453,6 +454,9 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||
ast.InterfaceDecl {
|
||||
// TODO skip: interfaces not implemented yet
|
||||
}
|
||||
ast.Module {
|
||||
// skip: namespacing implemented externally
|
||||
}
|
||||
ast.Return {
|
||||
if g.defer_stmts.len > 0 {
|
||||
g.gen_defer_stmts()
|
||||
|
@ -468,20 +472,32 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||
ast.UnsafeStmt {
|
||||
g.stmts(it.stmts)
|
||||
}
|
||||
/*
|
||||
else {
|
||||
verror('jsgen.stmt(): bad node ${typeof(node)}')
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) expr(node ast.Expr) {
|
||||
match node {
|
||||
ast.AnonFn {
|
||||
g.gen_fn_decl(it.decl)
|
||||
}
|
||||
ast.ArrayInit {
|
||||
g.gen_array_init_expr(it)
|
||||
}
|
||||
ast.AsCast {
|
||||
// skip: JS has no types, so no need to cast
|
||||
// TODO: Is jsdoc needed here for TS support?
|
||||
}
|
||||
ast.AssignExpr {
|
||||
g.gen_assign_expr(it)
|
||||
}
|
||||
ast.Assoc {
|
||||
// TODO
|
||||
}
|
||||
ast.BoolLiteral {
|
||||
if it.val == true {
|
||||
g.write('true')
|
||||
|
@ -489,11 +505,18 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
g.write('false')
|
||||
}
|
||||
}
|
||||
ast.CallExpr {
|
||||
g.gen_call_expr(it)
|
||||
}
|
||||
ast.CastExpr {
|
||||
// skip: JS has no types, so no need to cast
|
||||
// TODO: Check if jsdoc is needed for TS support
|
||||
}
|
||||
ast.CharLiteral {
|
||||
g.write("'$it.val'")
|
||||
}
|
||||
ast.CallExpr {
|
||||
g.gen_call_expr(it)
|
||||
ast.ConcatExpr {
|
||||
// TODO
|
||||
}
|
||||
ast.EnumVal {
|
||||
styp := g.typ(it.typ)
|
||||
|
@ -511,123 +534,74 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
ast.IfGuardExpr {
|
||||
// TODO no optionals yet
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
g.write(it.val)
|
||||
ast.IndexExpr {
|
||||
g.gen_index_expr(it)
|
||||
}
|
||||
ast.InfixExpr {
|
||||
g.expr(it.left)
|
||||
|
||||
mut op := it.op.str()
|
||||
// in js == is non-strict & === is strict, always do strict
|
||||
if op == '==' { op = '===' }
|
||||
else if op == '!=' { op = '!==' }
|
||||
|
||||
g.write(' $op ')
|
||||
g.expr(it.right)
|
||||
g.gen_infix_expr(it)
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
g.write(it.val)
|
||||
}
|
||||
ast.MapInit {
|
||||
g.gen_map_init_expr(it)
|
||||
}
|
||||
/*
|
||||
ast.UnaryExpr {
|
||||
g.expr(it.left)
|
||||
g.write(' $it.op ')
|
||||
ast.MatchExpr {
|
||||
// TODO
|
||||
}
|
||||
*/
|
||||
|
||||
ast.StringLiteral {
|
||||
g.write('"$it.val"')
|
||||
ast.None {
|
||||
// TODO
|
||||
}
|
||||
ast.StringInterLiteral {
|
||||
g.gen_string_inter_literal(it)
|
||||
ast.OrExpr {
|
||||
// TODO
|
||||
}
|
||||
ast.ParExpr {
|
||||
// TODO
|
||||
}
|
||||
ast.PostfixExpr {
|
||||
g.expr(it.expr)
|
||||
g.write(it.op.str())
|
||||
}
|
||||
ast.StructInit {
|
||||
// `user := User{name: 'Bob'}`
|
||||
g.gen_struct_init(it)
|
||||
ast.PrefixExpr {
|
||||
// TODO
|
||||
}
|
||||
ast.RangeExpr {
|
||||
// Only used in IndexExpr, requires index type info
|
||||
}
|
||||
ast.SelectorExpr {
|
||||
g.gen_selector_expr(it)
|
||||
}
|
||||
ast.AnonFn {
|
||||
g.gen_anon_fn_decl(it)
|
||||
ast.SizeOf {
|
||||
// TODO
|
||||
}
|
||||
ast.StringInterLiteral {
|
||||
g.gen_string_inter_literal(it)
|
||||
}
|
||||
ast.StringLiteral {
|
||||
g.write('"$it.val"')
|
||||
}
|
||||
ast.StructInit {
|
||||
// `user := User{name: 'Bob'}`
|
||||
g.gen_struct_init(it)
|
||||
}
|
||||
ast.Type {
|
||||
// skip: JS has no types
|
||||
// TODO maybe?
|
||||
}
|
||||
ast.TypeOf {
|
||||
g.gen_typeof_expr(it)
|
||||
// TODO: Should this print the V type or the JS type?
|
||||
}
|
||||
/*
|
||||
else {
|
||||
println(term.red('jsgen.expr(): bad node "${typeof(node)}"'))
|
||||
println(term.red('jsgen.expr(): unhandled node "${typeof(node)}"'))
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) {
|
||||
g.write('tos3(`')
|
||||
for i, val in it.vals {
|
||||
escaped_val := val.replace_each(['`', '\`', '\r\n', '\n'])
|
||||
g.write(escaped_val)
|
||||
if i >= it.exprs.len {
|
||||
continue
|
||||
}
|
||||
expr := it.exprs[i]
|
||||
sfmt := it.expr_fmts[i]
|
||||
g.write('\${')
|
||||
if sfmt.len > 0 {
|
||||
fspec := sfmt[sfmt.len - 1]
|
||||
if fspec == `s` && it.expr_types[i] == table.string_type {
|
||||
g.expr(expr)
|
||||
g.write('.str')
|
||||
} else {
|
||||
g.expr(expr)
|
||||
}
|
||||
} else if it.expr_types[i] == table.string_type {
|
||||
// `name.str`
|
||||
g.expr(expr)
|
||||
g.write('.str')
|
||||
} else if it.expr_types[i] == table.bool_type {
|
||||
// `expr ? "true" : "false"`
|
||||
g.expr(expr)
|
||||
g.write(' ? "true" : "false"')
|
||||
} else {
|
||||
sym := g.table.get_type_symbol(it.expr_types[i])
|
||||
|
||||
match sym.kind {
|
||||
.struct_ {
|
||||
g.expr(expr)
|
||||
if sym.has_method('str') {
|
||||
g.write('.str()')
|
||||
}
|
||||
}
|
||||
else {
|
||||
g.expr(expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
g.write('}')
|
||||
}
|
||||
g.write('`)')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_import_stmt(it ast.Import) {
|
||||
mut imports := g.namespace_imports[g.namespace]
|
||||
imports[it.mod] = it.alias
|
||||
g.namespace_imports[g.namespace] = imports
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) {
|
||||
type_sym := g.table.get_type_symbol(it.typ)
|
||||
if type_sym.kind != .array_fixed {
|
||||
g.write('[')
|
||||
for i, expr in it.exprs {
|
||||
g.expr(expr)
|
||||
if i < it.exprs.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
g.write(']')
|
||||
} else {}
|
||||
}
|
||||
|
||||
// TODO
|
||||
fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) {
|
||||
g.writeln('// assert')
|
||||
g.write('if( ')
|
||||
|
@ -713,12 +687,6 @@ 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) {
|
||||
g.writeln('/* [$it.name] */')
|
||||
}
|
||||
|
@ -807,8 +775,12 @@ fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
|
|||
g.gen_method_decl(it)
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_anon_fn_decl(it ast.AnonFn) {
|
||||
g.gen_method_decl(it.decl)
|
||||
fn fn_has_go(it ast.FnDecl) bool {
|
||||
mut has_go := false
|
||||
for stmt in it.stmts {
|
||||
if stmt is ast.GoStmt { has_go = true }
|
||||
}
|
||||
return has_go
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
||||
|
@ -875,6 +847,23 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
|||
g.fn_decl = 0
|
||||
}
|
||||
|
||||
fn (mut g JsGen) fn_args(args []table.Arg, is_variadic bool) {
|
||||
// no_names := args.len > 0 && args[0].name == 'arg_1'
|
||||
for i, arg in args {
|
||||
name := g.js_name(arg.name)
|
||||
is_varg := i == args.len - 1 && is_variadic
|
||||
if is_varg {
|
||||
g.write('...$name')
|
||||
} else {
|
||||
g.write(name)
|
||||
}
|
||||
// if its not the last argument
|
||||
if i < args.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_for_c_stmt(it ast.ForCStmt) {
|
||||
g.inside_loop = true
|
||||
g.write('for (')
|
||||
|
@ -961,23 +950,6 @@ fn (mut g JsGen) gen_for_stmt(it ast.ForStmt) {
|
|||
g.writeln('}')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) fn_args(args []table.Arg, is_variadic bool) {
|
||||
// no_names := args.len > 0 && args[0].name == 'arg_1'
|
||||
for i, arg in args {
|
||||
name := g.js_name(arg.name)
|
||||
is_varg := i == args.len - 1 && is_variadic
|
||||
if is_varg {
|
||||
g.write('...$name')
|
||||
} else {
|
||||
g.write(name)
|
||||
}
|
||||
// if its not the last argument
|
||||
if i < args.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_go_stmt(node ast.GoStmt) {
|
||||
// x := node.call_expr as ast.CallEpxr // TODO
|
||||
match node.call_expr {
|
||||
|
@ -1005,39 +977,21 @@ fn (mut g JsGen) gen_go_stmt(node ast.GoStmt) {
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) {
|
||||
// key_typ_sym := g.table.get_type_symbol(it.key_type)
|
||||
// value_typ_sym := g.table.get_type_symbol(it.value_type)
|
||||
// key_typ_str := key_typ_sym.name.replace('.', '__')
|
||||
// value_typ_str := value_typ_sym.name.replace('.', '__')
|
||||
if it.vals.len > 0 {
|
||||
g.writeln('new Map([')
|
||||
g.inc_indent()
|
||||
for i, key in it.keys {
|
||||
val := it.vals[i]
|
||||
g.write('[')
|
||||
g.expr(key)
|
||||
g.write(', ')
|
||||
g.expr(val)
|
||||
g.write(']')
|
||||
if i < it.keys.len - 1 {
|
||||
g.write(',')
|
||||
}
|
||||
g.writeln('')
|
||||
}
|
||||
g.dec_indent()
|
||||
g.write('])')
|
||||
} else {
|
||||
g.write('new Map()')
|
||||
}
|
||||
fn (mut g JsGen) gen_import_stmt(it ast.Import) {
|
||||
mut imports := g.namespace_imports[g.namespace]
|
||||
imports[it.mod] = it.alias
|
||||
g.namespace_imports[g.namespace] = imports
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_return_stmt(it ast.Return) {
|
||||
g.write('return ')
|
||||
|
||||
if it.exprs.len == 0 {
|
||||
// Returns nothing
|
||||
} else if it.exprs.len == 1 {
|
||||
g.write('return;')
|
||||
return
|
||||
}
|
||||
|
||||
g.write('return ')
|
||||
if it.exprs.len == 1 {
|
||||
g.expr(it.exprs[0])
|
||||
} else {
|
||||
// Multi return
|
||||
|
@ -1053,13 +1007,6 @@ fn (mut g JsGen) gen_return_stmt(it ast.Return) {
|
|||
g.writeln(';')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) enum_expr(node ast.Expr) {
|
||||
match node {
|
||||
ast.EnumVal { g.write(it.val) }
|
||||
else { g.expr(node) }
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
||||
g.writeln(g.doc.gen_fac_fn(node.fields))
|
||||
g.write('function ${g.js_name(node.name)}({ ')
|
||||
|
@ -1104,37 +1051,24 @@ 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_array_init_expr(it ast.ArrayInit) {
|
||||
type_sym := g.table.get_type_symbol(it.typ)
|
||||
name := type_sym.name
|
||||
if it.fields.len == 0 {
|
||||
g.write('new ${g.js_name(name)}({})')
|
||||
} else {
|
||||
g.writeln('new ${g.js_name(name)}({')
|
||||
g.inc_indent()
|
||||
for i, field in it.fields {
|
||||
g.write('$field.name: ')
|
||||
g.expr(field.expr)
|
||||
if i < it.fields.len - 1 {
|
||||
if type_sym.kind != .array_fixed {
|
||||
g.write('[')
|
||||
for i, expr in it.exprs {
|
||||
g.expr(expr)
|
||||
if i < it.exprs.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
g.writeln('')
|
||||
}
|
||||
g.dec_indent()
|
||||
g.write('})')
|
||||
}
|
||||
g.write(']')
|
||||
} else {}
|
||||
}
|
||||
|
||||
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
|
||||
g.write(name)
|
||||
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_call_expr(it ast.CallExpr) {
|
||||
|
@ -1163,9 +1097,16 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
|||
g.write(')')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) {
|
||||
g.expr(it.expr)
|
||||
g.write('.$it.field_name')
|
||||
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
|
||||
g.write(name)
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||
|
@ -1223,14 +1164,172 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
|||
}
|
||||
}
|
||||
|
||||
fn verror(s string) {
|
||||
util.verror('jsgen error', s)
|
||||
fn (mut g JsGen) gen_index_expr(it ast.IndexExpr) {
|
||||
// TODO: Handle splice setting if it's implemented
|
||||
if it.index is ast.RangeExpr {
|
||||
range := it.index as ast.RangeExpr
|
||||
g.expr(it.left)
|
||||
g.write('.slice(')
|
||||
if range.has_low {
|
||||
g.expr(range.low)
|
||||
} else {
|
||||
g.write('0')
|
||||
}
|
||||
g.write(', ')
|
||||
if range.has_high {
|
||||
g.expr(range.high)
|
||||
} else {
|
||||
g.expr(it.left)
|
||||
g.write('.length')
|
||||
}
|
||||
g.write(')')
|
||||
} else {
|
||||
// TODO Does this work in all cases?
|
||||
g.expr(it.left)
|
||||
g.write('[')
|
||||
g.expr(it.index)
|
||||
g.write(']')
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_has_go(it ast.FnDecl) bool {
|
||||
mut has_go := false
|
||||
for stmt in it.stmts {
|
||||
if stmt is ast.GoStmt { has_go = true }
|
||||
fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
||||
g.expr(it.left)
|
||||
|
||||
mut op := it.op.str()
|
||||
// in js == is non-strict & === is strict, always do strict
|
||||
if op == '==' { op = '===' }
|
||||
else if op == '!=' { op = '!==' }
|
||||
|
||||
g.write(' $op ')
|
||||
g.expr(it.right)
|
||||
}
|
||||
|
||||
|
||||
fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) {
|
||||
// key_typ_sym := g.table.get_type_symbol(it.key_type)
|
||||
// value_typ_sym := g.table.get_type_symbol(it.value_type)
|
||||
// key_typ_str := key_typ_sym.name.replace('.', '__')
|
||||
// value_typ_str := value_typ_sym.name.replace('.', '__')
|
||||
if it.vals.len > 0 {
|
||||
g.writeln('new Map([')
|
||||
g.inc_indent()
|
||||
for i, key in it.keys {
|
||||
val := it.vals[i]
|
||||
g.write('[')
|
||||
g.expr(key)
|
||||
g.write(', ')
|
||||
g.expr(val)
|
||||
g.write(']')
|
||||
if i < it.keys.len - 1 {
|
||||
g.write(',')
|
||||
}
|
||||
g.writeln('')
|
||||
}
|
||||
g.dec_indent()
|
||||
g.write('])')
|
||||
} else {
|
||||
g.write('new Map()')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) {
|
||||
g.expr(it.expr)
|
||||
g.write('.$it.field_name')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) {
|
||||
// TODO Implement `tos3`
|
||||
g.write('tos3(`')
|
||||
for i, val in it.vals {
|
||||
escaped_val := val.replace_each(['`', '\`', '\r\n', '\n'])
|
||||
g.write(escaped_val)
|
||||
if i >= it.exprs.len {
|
||||
continue
|
||||
}
|
||||
expr := it.exprs[i]
|
||||
sfmt := it.expr_fmts[i]
|
||||
g.write('\${')
|
||||
if sfmt.len > 0 {
|
||||
fspec := sfmt[sfmt.len - 1]
|
||||
if fspec == `s` && it.expr_types[i] == table.string_type {
|
||||
g.expr(expr)
|
||||
g.write('.str')
|
||||
} else {
|
||||
g.expr(expr)
|
||||
}
|
||||
} else if it.expr_types[i] == table.string_type {
|
||||
// `name.str`
|
||||
g.expr(expr)
|
||||
g.write('.str')
|
||||
} else if it.expr_types[i] == table.bool_type {
|
||||
// `expr ? "true" : "false"`
|
||||
g.expr(expr)
|
||||
g.write(' ? "true" : "false"')
|
||||
} else {
|
||||
sym := g.table.get_type_symbol(it.expr_types[i])
|
||||
|
||||
match sym.kind {
|
||||
.struct_ {
|
||||
g.expr(expr)
|
||||
if sym.has_method('str') {
|
||||
g.write('.str()')
|
||||
}
|
||||
}
|
||||
else {
|
||||
g.expr(expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
g.write('}')
|
||||
}
|
||||
g.write('`)')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_struct_init(it ast.StructInit) {
|
||||
type_sym := g.table.get_type_symbol(it.typ)
|
||||
name := type_sym.name
|
||||
if it.fields.len == 0 {
|
||||
g.write('new ${g.js_name(name)}({})')
|
||||
} else {
|
||||
g.writeln('new ${g.js_name(name)}({')
|
||||
g.inc_indent()
|
||||
for i, field in it.fields {
|
||||
g.write('$field.name: ')
|
||||
g.expr(field.expr)
|
||||
if i < it.fields.len - 1 {
|
||||
g.write(',')
|
||||
}
|
||||
g.writeln('')
|
||||
}
|
||||
g.dec_indent()
|
||||
g.write('})')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_typeof_expr(it ast.TypeOf) {
|
||||
sym := g.table.get_type_symbol(it.expr_type)
|
||||
if sym.kind == .sum_type {
|
||||
// TODO: JS sumtypes not implemented yet
|
||||
} else if sym.kind == .array_fixed {
|
||||
fixed_info := sym.info as table.ArrayFixed
|
||||
typ_name := g.table.get_type_name(fixed_info.elem_type)
|
||||
g.write('"[$fixed_info.size]${typ_name}"')
|
||||
} else if sym.kind == .function {
|
||||
info := sym.info as table.FnType
|
||||
fn_info := info.func
|
||||
mut repr := 'fn ('
|
||||
for i, arg in fn_info.args {
|
||||
if i > 0 {
|
||||
repr += ', '
|
||||
}
|
||||
repr += g.table.get_type_name(arg.typ)
|
||||
}
|
||||
repr += ')'
|
||||
if fn_info.return_type != table.void_type {
|
||||
repr += ' ${g.table.get_type_name(fn_info.return_type)}'
|
||||
}
|
||||
g.write('"$repr"')
|
||||
} else {
|
||||
g.write('"${sym.name}"')
|
||||
}
|
||||
return has_go
|
||||
}
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
// V_COMMIT_HASH 0de70e8
|
||||
// V_CURRENT_COMMIT_HASH 4271eb4
|
||||
// Generated by the V compiler
|
||||
|
||||
"use strict";
|
||||
|
||||
/** @namespace builtin */
|
||||
const builtin = (function () {
|
||||
/**
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function println(s) {
|
||||
console.log(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function print(s) {
|
||||
process.stdout.write(s);
|
||||
}
|
||||
|
||||
/* module exports */
|
||||
return {
|
||||
println,
|
||||
print,
|
||||
};
|
||||
})();
|
||||
|
||||
/** @namespace main */
|
||||
const main = (function () {
|
||||
/**
|
||||
* @param {...number} args
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function variadic(...args) {
|
||||
builtin.println(args);
|
||||
builtin.println(args[0]);
|
||||
builtin.println(args[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function vararg_test() {
|
||||
variadic(1, 2, 3);
|
||||
}
|
||||
|
||||
/* program entry point */
|
||||
(function() {
|
||||
vararg_test();
|
||||
/** @type {string[]} - arr1 */
|
||||
const arr1 = ["Hello", "JS", "Backend"];
|
||||
/** @type {number[]} - arr2 */
|
||||
let arr2 = [1, 2, 3, 4, 5];
|
||||
/** @type {string[]} - slice1 */
|
||||
const slice1 = arr1.slice(1, 3);
|
||||
/** @type {number[]} - slice2 */
|
||||
const slice2 = arr2.slice(0, 3);
|
||||
/** @type {number[]} - slice3 */
|
||||
const slice3 = arr2.slice(3, arr2.length);
|
||||
/** @type {string} - idx1 */
|
||||
const idx1 = slice1[1];
|
||||
arr2[0] = 1;
|
||||
arr2[0 + 1] = 2;
|
||||
builtin.println(arr2);
|
||||
/** @type {string} - slice4 */
|
||||
const slice4 = idx1.slice(0, 4);
|
||||
builtin.println(slice4);
|
||||
/** @type {byte} - idx2 */
|
||||
const idx2 = slice4[0];
|
||||
/** @type {Map<string, string>} - m */
|
||||
let m = new Map();
|
||||
/** @type {string} - key */
|
||||
const key = "key";
|
||||
m[key] = "value";
|
||||
/** @type {string} - val */
|
||||
const val = m["key"];
|
||||
builtin.println(val);
|
||||
})();
|
||||
|
||||
/* module exports */
|
||||
return {};
|
||||
})();
|
||||
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
fn variadic(args ...int) {
|
||||
println(args)
|
||||
println(args[0])
|
||||
println(args[1])
|
||||
}
|
||||
|
||||
fn vararg_test() {
|
||||
variadic(1, 2, 3)
|
||||
}
|
||||
|
||||
vararg_test()
|
||||
|
||||
arr1 := ['Hello', 'JS', 'Backend']
|
||||
mut arr2 := [1, 2, 3, 4, 5]
|
||||
|
||||
// Array slices
|
||||
slice1 := arr1[1..3]
|
||||
slice2 := arr2[..3]
|
||||
slice3 := arr2[3..]
|
||||
|
||||
// Array indexes
|
||||
idx1 := slice1[1]
|
||||
arr2[0] = 1
|
||||
arr2[0 + 1] = 2
|
||||
println(arr2)
|
||||
|
||||
// String slices
|
||||
slice4 := idx1[..4]
|
||||
println(slice4) // 'Back'
|
||||
|
||||
// String indexes
|
||||
idx2 := slice4[0]
|
||||
|
||||
// TODO: This does not work for now
|
||||
// arr2[0..1] = arr2[3..4]
|
||||
// println(arr2)
|
||||
|
||||
|
||||
// Maps
|
||||
mut m := map[string]string
|
||||
key := 'key'
|
||||
m[key] = 'value'
|
||||
val := m['key']
|
||||
println(val)
|
|
@ -1,5 +1,5 @@
|
|||
// V_COMMIT_HASH 74686d0
|
||||
// V_CURRENT_COMMIT_HASH 0d3f133
|
||||
// V_COMMIT_HASH 0de70e8
|
||||
// V_CURRENT_COMMIT_HASH 4271eb4
|
||||
// Generated by the V compiler
|
||||
|
||||
"use strict";
|
||||
|
@ -11,51 +11,81 @@ const _CONSTS = Object.freeze({
|
|||
v_super: "amazing keyword"
|
||||
});
|
||||
|
||||
/* namespace: hello */
|
||||
/** @namespace builtin */
|
||||
const builtin = (function () {
|
||||
/**
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function println(s) {
|
||||
console.log(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function print(s) {
|
||||
process.stdout.write(s);
|
||||
}
|
||||
|
||||
/* module exports */
|
||||
return {
|
||||
println,
|
||||
print,
|
||||
};
|
||||
})();
|
||||
|
||||
/** @namespace hello */
|
||||
const hello = (function () {
|
||||
class A {
|
||||
/**
|
||||
* @param {{foo?: string}} values - values for this class fields
|
||||
* @constructor
|
||||
*/
|
||||
constructor(values) {
|
||||
this.foo = values.foo
|
||||
}
|
||||
|
||||
function A({ foo = "" }) {
|
||||
this.foo = foo
|
||||
};
|
||||
A.prototype = {
|
||||
/** @type {string} - foo */
|
||||
foo: "",
|
||||
/**
|
||||
* @param {string} s
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
update(s) {
|
||||
const a = this;
|
||||
a.foo = s;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class B {
|
||||
/**
|
||||
* @param {{}} values - values for this class fields
|
||||
* @constructor
|
||||
*/
|
||||
constructor(values) {
|
||||
}
|
||||
}
|
||||
function B({ }) {
|
||||
};
|
||||
B.prototype = {
|
||||
};
|
||||
|
||||
const C = Object.freeze({
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
* @function
|
||||
*/
|
||||
function v_debugger() {
|
||||
const v = new B({
|
||||
});
|
||||
const v = new B({});
|
||||
return "Hello";
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
* @function
|
||||
*/
|
||||
function excited() {
|
||||
return v_debugger() + "!";
|
||||
|
@ -70,31 +100,39 @@ const hello = (function () {
|
|||
};
|
||||
})();
|
||||
|
||||
/* namespace: main */
|
||||
/** @namespace main */
|
||||
const main = (function (hl) {
|
||||
class Foo {
|
||||
/**
|
||||
* @param {{a?: hl["A"]["prototype"]}} values - values for this class fields
|
||||
* @constructor
|
||||
*/
|
||||
constructor(values) {
|
||||
this.a = values.a
|
||||
}
|
||||
}
|
||||
function Foo({ a = {} }) {
|
||||
this.a = a
|
||||
};
|
||||
Foo.prototype = {
|
||||
/** @type {hl["A"]["prototype"]} - a */
|
||||
a: {}
|
||||
};
|
||||
|
||||
class Companies {
|
||||
/**
|
||||
* @param {{google?: number, amazon?: boolean, yahoo?: string}} values - values for this class fields
|
||||
* @constructor
|
||||
*/
|
||||
constructor(values) {
|
||||
this.google = values.google
|
||||
this.amazon = values.amazon
|
||||
this.yahoo = values.yahoo
|
||||
}
|
||||
|
||||
function Companies({ google = 0, amazon = false, yahoo = "" }) {
|
||||
this.google = google
|
||||
this.amazon = amazon
|
||||
this.yahoo = yahoo
|
||||
};
|
||||
Companies.prototype = {
|
||||
/** @type {number} - google */
|
||||
google: 0,
|
||||
/** @type {boolean} - amazon */
|
||||
amazon: false,
|
||||
/** @type {string} - yahoo */
|
||||
yahoo: "",
|
||||
/**
|
||||
* @returns {number}
|
||||
* @function
|
||||
*/
|
||||
method() {
|
||||
const it = this;
|
||||
|
@ -112,7 +150,7 @@ const main = (function (hl) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const POSITION = Object.freeze({
|
||||
go_back: 0,
|
||||
|
@ -123,6 +161,7 @@ const main = (function (hl) {
|
|||
* @param {string} v_extends
|
||||
* @param {number} v_instanceof
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function v_class(v_extends, v_instanceof) {
|
||||
/** @type {number} - v_delete */
|
||||
|
@ -131,22 +170,20 @@ const main = (function (hl) {
|
|||
|
||||
/* program entry point */
|
||||
(async function() {
|
||||
console.log("Hello from V.js!");
|
||||
builtin.println("Hello from V.js!");
|
||||
/** @type {number} - a */
|
||||
let a = 1;
|
||||
a *= 2;
|
||||
a += 3;
|
||||
console.log(a, " == 5");
|
||||
const b = new hl.A({
|
||||
});
|
||||
builtin.println(a);
|
||||
const b = new hl.A({});
|
||||
b.update("an update");
|
||||
console.log(b);
|
||||
builtin.println(b);
|
||||
const c = new Foo({
|
||||
a: new hl.A({
|
||||
})
|
||||
a: new hl.A({})
|
||||
});
|
||||
c.a.update("another update");
|
||||
console.log(c);
|
||||
builtin.println(c);
|
||||
/** @type {string} - v */
|
||||
const v = "done";
|
||||
{
|
||||
|
@ -198,11 +235,11 @@ const main = (function (hl) {
|
|||
|
||||
/** @type {(number: number) => void} - fn_in_var */
|
||||
const fn_in_var = function (number) {
|
||||
console.log(tos3(`number: ${number}`));
|
||||
builtin.println(tos3(`number: ${number}`));
|
||||
};
|
||||
hl.v_debugger();
|
||||
anon_consumer(hl.excited(), function (message) {
|
||||
console.log(message);
|
||||
builtin.println(message);
|
||||
});
|
||||
})();
|
||||
|
||||
|
@ -210,6 +247,7 @@ const main = (function (hl) {
|
|||
* @param {string} greeting
|
||||
* @param {(message: string) => void} anon
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function anon_consumer(greeting, anon) {
|
||||
anon(greeting);
|
||||
|
@ -219,6 +257,7 @@ const main = (function (hl) {
|
|||
* @param {number} num
|
||||
* @param {string} def
|
||||
* @returns {void}
|
||||
* @function
|
||||
*/
|
||||
function async(num, def) {
|
||||
}
|
||||
|
@ -230,6 +269,7 @@ const main = (function (hl) {
|
|||
* @param {number} game_on
|
||||
* @param {...string} dummy
|
||||
* @returns {[number, number]}
|
||||
* @function
|
||||
*/
|
||||
function hello(game_on, ...dummy) {
|
||||
for (let _tmp2 = 0; _tmp2 < dummy.length; ++_tmp2) {
|
||||
|
@ -246,8 +286,7 @@ const main = (function (hl) {
|
|||
}
|
||||
|
||||
/* module exports */
|
||||
return {
|
||||
};
|
||||
return {};
|
||||
})(hello);
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import hello as hl
|
||||
|
||||
fn JS.alert(arg string)
|
||||
fn JS.console.log(arg string)
|
||||
|
||||
const (
|
||||
i_am_a_const = 21214
|
||||
|
@ -29,20 +28,20 @@ fn class(extends string, instanceof int) {
|
|||
|
||||
|
||||
fn main() {
|
||||
JS.console.log('Hello from V.js!')
|
||||
println('Hello from V.js!')
|
||||
|
||||
mut a := 1
|
||||
a *= 2
|
||||
a += 3
|
||||
JS.console.log(a, ' == 5') // TODO: Handle string interpolation
|
||||
println(a) // TODO: Handle string interpolation
|
||||
|
||||
b := hl.A{}
|
||||
b.update('an update')
|
||||
JS.console.log(b)
|
||||
println(b)
|
||||
|
||||
c := Foo{ hl.A{} }
|
||||
c.a.update('another update')
|
||||
JS.console.log(c)
|
||||
println(c)
|
||||
|
||||
v := "done"
|
||||
{
|
||||
|
@ -81,12 +80,12 @@ fn main() {
|
|||
go async(0, "hello")
|
||||
|
||||
fn_in_var := fn (number int) {
|
||||
JS.console.log("number: $number")
|
||||
println("number: $number")
|
||||
}
|
||||
|
||||
hl.debugger()
|
||||
anon_consumer(hl.excited(), fn (message string) {
|
||||
JS.console.log(message)
|
||||
println(message)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue