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.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)
@ -206,7 +204,7 @@ pub fn (mut g JsGen) typ(t table.Type) string {
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'
// 'anon_fn_7_7_1' => '(a number, b number) => void'
if styp.starts_with('anon_') {
info := sym.info as table.FnType
mut res := '('
@ -352,7 +350,7 @@ fn (mut g JsGen) get_alias(name string) string {
if split.len > 1 {
imports := g.namespace_imports[g.namespace]
alias := imports[split[0]]
if alias != '' {
return alias + '.' + split[1..].join('.')
}
@ -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 }
}
return has_go
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}"')
}
}

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_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
}
/**
* @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
* @returns {void}
* @function
*/
update(s) {
const a = this;
a.foo = s;
}
}
};
class B {
/**
* @param {{}} values - values for this class fields
* @constructor
*/
constructor(values) {
}
}
/**
* @param {{}} values - values for this class fields
* @constructor
*/
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,37 +100,45 @@ 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
}
}
/**
* @param {{a?: hl["A"]["prototype"]}} values - values for this class fields
* @constructor
*/
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
}
/**
* @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}
* @function
*/
method() {
const it = this;
const ss = new Companies({
google: 2,
amazon: true,
google: 2,
amazon: true,
yahoo: "hello"
});
/** @type {[number, number]} */
@ -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);

View File

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