jsgen: start implementing remaining `expr`s and `stmt`s

pull/5015/head
spaceface777 2020-05-24 22:49:01 +02:00 committed by GitHub
parent fd4d28b7b6
commit 4189190bb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 539 additions and 266 deletions

View File

@ -4,7 +4,6 @@ import strings
import v.ast import v.ast
import v.table import v.table
import v.pref import v.pref
import term
import v.util import v.util
import v.depgraph import v.depgraph
@ -193,7 +192,6 @@ pub fn (g JsGen) hashes() string {
return res return res
} }
// 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)
@ -382,9 +380,6 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
g.stmt_start_pos = g.out.len g.stmt_start_pos = g.out.len
match node { match node {
ast.Module {
// TODO: Implement namespaces
}
ast.AssertStmt { ast.AssertStmt {
g.gen_assert_stmt(it) g.gen_assert_stmt(it)
} }
@ -401,12 +396,15 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
ast.BranchStmt { ast.BranchStmt {
g.gen_branch_stmt(it) g.gen_branch_stmt(it)
} }
ast.ConstDecl { ast.Comment {
g.gen_const_decl(it) // Skip: don't generate comments
} }
ast.CompIf { ast.CompIf {
// skip: JS has no compile time if // skip: JS has no compile time if
} }
ast.ConstDecl {
g.gen_const_decl(it)
}
ast.DeferStmt { ast.DeferStmt {
g.defer_stmts << *it g.defer_stmts << *it
} }
@ -434,6 +432,9 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
g.gen_for_stmt(it) g.gen_for_stmt(it)
g.writeln('') g.writeln('')
} }
ast.GlobalDecl {
// TODO
}
ast.GoStmt { ast.GoStmt {
g.gen_go_stmt(it) g.gen_go_stmt(it)
g.writeln('') g.writeln('')
@ -453,6 +454,9 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
ast.InterfaceDecl { ast.InterfaceDecl {
// TODO skip: interfaces not implemented yet // TODO skip: interfaces not implemented yet
} }
ast.Module {
// skip: namespacing implemented externally
}
ast.Return { ast.Return {
if g.defer_stmts.len > 0 { if g.defer_stmts.len > 0 {
g.gen_defer_stmts() g.gen_defer_stmts()
@ -468,20 +472,32 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
ast.UnsafeStmt { ast.UnsafeStmt {
g.stmts(it.stmts) g.stmts(it.stmts)
} }
/*
else { else {
verror('jsgen.stmt(): bad node ${typeof(node)}') verror('jsgen.stmt(): bad node ${typeof(node)}')
} }
*/
} }
} }
fn (mut g JsGen) expr(node ast.Expr) { fn (mut g JsGen) expr(node ast.Expr) {
match node { match node {
ast.AnonFn {
g.gen_fn_decl(it.decl)
}
ast.ArrayInit { ast.ArrayInit {
g.gen_array_init_expr(it) 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 { ast.AssignExpr {
g.gen_assign_expr(it) g.gen_assign_expr(it)
} }
ast.Assoc {
// TODO
}
ast.BoolLiteral { ast.BoolLiteral {
if it.val == true { if it.val == true {
g.write('true') g.write('true')
@ -489,11 +505,18 @@ fn (mut g JsGen) expr(node ast.Expr) {
g.write('false') 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 { ast.CharLiteral {
g.write("'$it.val'") g.write("'$it.val'")
} }
ast.CallExpr { ast.ConcatExpr {
g.gen_call_expr(it) // TODO
} }
ast.EnumVal { ast.EnumVal {
styp := g.typ(it.typ) styp := g.typ(it.typ)
@ -511,123 +534,74 @@ fn (mut g JsGen) expr(node ast.Expr) {
ast.IfGuardExpr { ast.IfGuardExpr {
// TODO no optionals yet // TODO no optionals yet
} }
ast.IntegerLiteral { ast.IndexExpr {
g.write(it.val) g.gen_index_expr(it)
} }
ast.InfixExpr { ast.InfixExpr {
g.expr(it.left) g.gen_infix_expr(it)
}
mut op := it.op.str() ast.IntegerLiteral {
// in js == is non-strict & === is strict, always do strict g.write(it.val)
if op == '==' { op = '===' }
else if op == '!=' { op = '!==' }
g.write(' $op ')
g.expr(it.right)
} }
ast.MapInit { ast.MapInit {
g.gen_map_init_expr(it) g.gen_map_init_expr(it)
} }
/* ast.MatchExpr {
ast.UnaryExpr { // TODO
g.expr(it.left)
g.write(' $it.op ')
} }
*/ ast.None {
// TODO
ast.StringLiteral {
g.write('"$it.val"')
} }
ast.StringInterLiteral { ast.OrExpr {
g.gen_string_inter_literal(it) // TODO
}
ast.ParExpr {
// TODO
} }
ast.PostfixExpr { ast.PostfixExpr {
g.expr(it.expr) g.expr(it.expr)
g.write(it.op.str()) g.write(it.op.str())
} }
ast.StructInit { ast.PrefixExpr {
// `user := User{name: 'Bob'}` // TODO
g.gen_struct_init(it) }
ast.RangeExpr {
// Only used in IndexExpr, requires index type info
} }
ast.SelectorExpr { ast.SelectorExpr {
g.gen_selector_expr(it) g.gen_selector_expr(it)
} }
ast.AnonFn { ast.SizeOf {
g.gen_anon_fn_decl(it) // 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 { 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) { fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) {
g.writeln('// assert') g.writeln('// assert')
g.write('if( ') 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) { fn (mut g JsGen) gen_attr(it ast.Attr) {
g.writeln('/* [$it.name] */') g.writeln('/* [$it.name] */')
} }
@ -807,8 +775,12 @@ fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
g.gen_method_decl(it) g.gen_method_decl(it)
} }
fn (mut g JsGen) gen_anon_fn_decl(it ast.AnonFn) { fn fn_has_go(it ast.FnDecl) bool {
g.gen_method_decl(it.decl) 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) { 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 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) { fn (mut g JsGen) gen_for_c_stmt(it ast.ForCStmt) {
g.inside_loop = true g.inside_loop = true
g.write('for (') g.write('for (')
@ -961,23 +950,6 @@ fn (mut g JsGen) gen_for_stmt(it ast.ForStmt) {
g.writeln('}') 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) { fn (mut g JsGen) gen_go_stmt(node ast.GoStmt) {
// x := node.call_expr as ast.CallEpxr // TODO // x := node.call_expr as ast.CallEpxr // TODO
match node.call_expr { 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) { fn (mut g JsGen) gen_import_stmt(it ast.Import) {
// key_typ_sym := g.table.get_type_symbol(it.key_type) mut imports := g.namespace_imports[g.namespace]
// value_typ_sym := g.table.get_type_symbol(it.value_type) imports[it.mod] = it.alias
// key_typ_str := key_typ_sym.name.replace('.', '__') g.namespace_imports[g.namespace] = imports
// 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_return_stmt(it ast.Return) { fn (mut g JsGen) gen_return_stmt(it ast.Return) {
g.write('return ')
if it.exprs.len == 0 { if it.exprs.len == 0 {
// Returns nothing // 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]) g.expr(it.exprs[0])
} else { } else {
// Multi return // Multi return
@ -1053,13 +1007,6 @@ fn (mut g JsGen) gen_return_stmt(it ast.Return) {
g.writeln(';') 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) { fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
g.writeln(g.doc.gen_fac_fn(node.fields)) g.writeln(g.doc.gen_fac_fn(node.fields))
g.write('function ${g.js_name(node.name)}({ ') 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) type_sym := g.table.get_type_symbol(it.typ)
name := type_sym.name if type_sym.kind != .array_fixed {
if it.fields.len == 0 { g.write('[')
g.write('new ${g.js_name(name)}({})') for i, expr in it.exprs {
} else { g.expr(expr)
g.writeln('new ${g.js_name(name)}({') if i < it.exprs.len - 1 {
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.write(', ')
} }
g.writeln('')
} }
g.dec_indent() g.write(']')
g.write('})') } else {}
}
} }
fn (mut g JsGen) gen_ident(node ast.Ident) { fn (mut g JsGen) gen_assign_expr(it ast.AssignExpr) {
if node.kind == .constant { g.expr(it.left)
// TODO: Handle const namespacing: only consts in the main module are handled rn g.write(' $it.op ')
g.write('_CONSTS.') g.expr(it.val)
}
name := g.js_name(node.name)
// TODO `is`
// TODO handle optionals
g.write(name)
} }
fn (mut g JsGen) gen_call_expr(it ast.CallExpr) { 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(')') g.write(')')
} }
fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) { fn (mut g JsGen) gen_ident(node ast.Ident) {
g.expr(it.expr) if node.kind == .constant {
g.write('.$it.field_name') // 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) { 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) { fn (mut g JsGen) gen_index_expr(it ast.IndexExpr) {
util.verror('jsgen error', s) // 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 { fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
mut has_go := false g.expr(it.left)
for stmt in it.stmts {
if stmt is ast.GoStmt { has_go = true } mut op := it.op.str()
} // in js == is non-strict & === is strict, always do strict
return has_go 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}"')
}
} }

View File

@ -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 {};
})();

View File

@ -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)

View File

@ -1,5 +1,5 @@
// V_COMMIT_HASH 74686d0 // V_COMMIT_HASH 0de70e8
// V_CURRENT_COMMIT_HASH 0d3f133 // V_CURRENT_COMMIT_HASH 4271eb4
// Generated by the V compiler // Generated by the V compiler
"use strict"; "use strict";
@ -11,51 +11,81 @@ const _CONSTS = Object.freeze({
v_super: "amazing keyword" v_super: "amazing keyword"
}); });
/* namespace: hello */ /** @namespace builtin */
const hello = (function () { const builtin = (function () {
class A { /**
/** * @param {any} s
* @param {{foo?: string}} values - values for this class fields * @returns {void}
* @constructor * @function
*/ */
constructor(values) { function println(s) {
this.foo = values.foo 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 () {
/**
* @param {{foo?: string}} values - values for this class fields
* @constructor
*/
function A({ foo = "" }) {
this.foo = foo
};
A.prototype = {
/** @type {string} - foo */
foo: "",
/** /**
* @param {string} s * @param {string} s
* @returns {void} * @returns {void}
* @function
*/ */
update(s) { update(s) {
const a = this; const a = this;
a.foo = s; a.foo = s;
} }
} };
class B { /**
/** * @param {{}} values - values for this class fields
* @param {{}} values - values for this class fields * @constructor
* @constructor */
*/ function B({ }) {
constructor(values) { };
} B.prototype = {
} };
const C = Object.freeze({ const C = Object.freeze({
}); });
/** /**
* @returns {string} * @returns {string}
* @function
*/ */
function v_debugger() { function v_debugger() {
const v = new B({ const v = new B({});
});
return "Hello"; return "Hello";
} }
/** /**
* @returns {string} * @returns {string}
* @function
*/ */
function excited() { function excited() {
return v_debugger() + "!"; return v_debugger() + "!";
@ -70,31 +100,39 @@ const hello = (function () {
}; };
})(); })();
/* namespace: main */ /** @namespace main */
const main = (function (hl) { const main = (function (hl) {
class Foo { /**
/** * @param {{a?: hl["A"]["prototype"]}} values - values for this class fields
* @param {{a?: hl["A"]["prototype"]}} values - values for this class fields * @constructor
* @constructor */
*/ function Foo({ a = {} }) {
constructor(values) { this.a = a
this.a = values.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
}
/**
* @param {{google?: number, amazon?: boolean, yahoo?: string}} values - values for this class fields
* @constructor
*/
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} * @returns {number}
* @function
*/ */
method() { method() {
const it = this; const it = this;
@ -112,7 +150,7 @@ const main = (function (hl) {
return 0; return 0;
} }
} };
const POSITION = Object.freeze({ const POSITION = Object.freeze({
go_back: 0, go_back: 0,
@ -123,6 +161,7 @@ const main = (function (hl) {
* @param {string} v_extends * @param {string} v_extends
* @param {number} v_instanceof * @param {number} v_instanceof
* @returns {void} * @returns {void}
* @function
*/ */
function v_class(v_extends, v_instanceof) { function v_class(v_extends, v_instanceof) {
/** @type {number} - v_delete */ /** @type {number} - v_delete */
@ -131,22 +170,20 @@ const main = (function (hl) {
/* program entry point */ /* program entry point */
(async function() { (async function() {
console.log("Hello from V.js!"); builtin.println("Hello from V.js!");
/** @type {number} - a */ /** @type {number} - a */
let a = 1; let a = 1;
a *= 2; a *= 2;
a += 3; a += 3;
console.log(a, " == 5"); builtin.println(a);
const b = new hl.A({ const b = new hl.A({});
});
b.update("an update"); b.update("an update");
console.log(b); builtin.println(b);
const c = new Foo({ const c = new Foo({
a: new hl.A({ a: new hl.A({})
})
}); });
c.a.update("another update"); c.a.update("another update");
console.log(c); builtin.println(c);
/** @type {string} - v */ /** @type {string} - v */
const v = "done"; const v = "done";
{ {
@ -198,11 +235,11 @@ const main = (function (hl) {
/** @type {(number: number) => void} - 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}`)); builtin.println(tos3(`number: ${number}`));
}; };
hl.v_debugger(); hl.v_debugger();
anon_consumer(hl.excited(), function (message) { anon_consumer(hl.excited(), function (message) {
console.log(message); builtin.println(message);
}); });
})(); })();
@ -210,6 +247,7 @@ const main = (function (hl) {
* @param {string} greeting * @param {string} greeting
* @param {(message: string) => void} anon * @param {(message: string) => void} anon
* @returns {void} * @returns {void}
* @function
*/ */
function anon_consumer(greeting, anon) { function anon_consumer(greeting, anon) {
anon(greeting); anon(greeting);
@ -219,6 +257,7 @@ const main = (function (hl) {
* @param {number} num * @param {number} num
* @param {string} def * @param {string} def
* @returns {void} * @returns {void}
* @function
*/ */
function async(num, def) { function async(num, def) {
} }
@ -230,6 +269,7 @@ const main = (function (hl) {
* @param {number} game_on * @param {number} game_on
* @param {...string} dummy * @param {...string} dummy
* @returns {[number, number]} * @returns {[number, number]}
* @function
*/ */
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) {
@ -246,8 +286,7 @@ const main = (function (hl) {
} }
/* module exports */ /* module exports */
return { return {};
};
})(hello); })(hello);

View File

@ -1,7 +1,6 @@
import hello as hl import hello as hl
fn JS.alert(arg string) fn JS.alert(arg string)
fn JS.console.log(arg string)
const ( const (
i_am_a_const = 21214 i_am_a_const = 21214
@ -29,20 +28,20 @@ fn class(extends string, instanceof int) {
fn main() { fn main() {
JS.console.log('Hello from V.js!') println('Hello from V.js!')
mut a := 1 mut a := 1
a *= 2 a *= 2
a += 3 a += 3
JS.console.log(a, ' == 5') // TODO: Handle string interpolation println(a) // TODO: Handle string interpolation
b := hl.A{} b := hl.A{}
b.update('an update') b.update('an update')
JS.console.log(b) println(b)
c := Foo{ hl.A{} } c := Foo{ hl.A{} }
c.a.update('another update') c.a.update('another update')
JS.console.log(c) println(c)
v := "done" v := "done"
{ {
@ -81,12 +80,12 @@ fn main() {
go async(0, "hello") go async(0, "hello")
fn_in_var := fn (number int) { fn_in_var := fn (number int) {
JS.console.log("number: $number") println("number: $number")
} }
hl.debugger() hl.debugger()
anon_consumer(hl.excited(), fn (message string) { anon_consumer(hl.excited(), fn (message string) {
JS.console.log(message) println(message)
}) })
} }