jsgen: fixes and improvements
parent
ddd83f1fc6
commit
a02aff9126
|
@ -4,13 +4,40 @@
|
|||
|
||||
module builtin
|
||||
|
||||
fn JS.console.log(arg ...string)
|
||||
fn JS.process.stdout.write(arg string)
|
||||
|
||||
pub fn println(s any) {
|
||||
JS.console.log(s)
|
||||
}
|
||||
|
||||
pub fn print(s any) {
|
||||
JS.process.stdout.write(s)
|
||||
// TODO
|
||||
// $if js.node {
|
||||
JS.process.stdout.write(s)
|
||||
// } $else {
|
||||
// panic('Cannot `print` in a browser, use `println` instead')
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn eprintln(s any) {
|
||||
JS.console.error(s)
|
||||
}
|
||||
|
||||
pub fn eprint(s any) {
|
||||
// TODO
|
||||
// $if js.node {
|
||||
JS.process.stderr.write(s)
|
||||
// } $else {
|
||||
// panic('Cannot `eprint` in a browser, use `eprintln` instead')
|
||||
// }
|
||||
}
|
||||
|
||||
// Exits the process in node, and halts execution in the browser
|
||||
// because `process.exit` is undefined. Workaround for not having
|
||||
// a 'real' way to exit in the browser.
|
||||
pub fn exit(c int) {
|
||||
JS.process.exit(c)
|
||||
}
|
||||
|
||||
pub fn panic(s string) {
|
||||
eprintln('V panic: $s')
|
||||
exit(1)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// This file contains JS functions present in both node and the browser.
|
||||
// They have been ported from their TypeScript definitions.
|
||||
|
||||
module builtin
|
||||
|
||||
// Top level functions
|
||||
fn JS.eval(string) any
|
||||
fn JS.parseInt(string, f64) f64
|
||||
fn JS.parseFloat(string) f64
|
||||
fn JS.isNaN(f64) bool
|
||||
fn JS.isFinite(f64) bool
|
||||
fn JS.decodeURI(string) string
|
||||
fn JS.decodeURIComponent(string) string
|
||||
fn JS.encodeURI(string) string
|
||||
type EncodeURIComponentArg = string | f64 | bool
|
||||
fn JS.encodeURIComponent(EncodeURIComponentArg) string
|
||||
fn JS.escape(string) string
|
||||
fn JS.unescape(string) string
|
||||
|
||||
// console
|
||||
fn JS.console.assert(bool, ...any)
|
||||
fn JS.console.clear()
|
||||
fn JS.console.count(string)
|
||||
fn JS.console.countReset(string)
|
||||
fn JS.console.debug(...any)
|
||||
fn JS.console.dir(any, any)
|
||||
fn JS.console.dirxml(...any)
|
||||
fn JS.console.error(...any)
|
||||
fn JS.console.exception(string, ...any)
|
||||
fn JS.console.group(...any)
|
||||
fn JS.console.groupCollapsed(...any)
|
||||
fn JS.console.groupEnd()
|
||||
fn JS.console.info(...any)
|
||||
fn JS.console.log(...any)
|
||||
fn JS.console.table(any, []string)
|
||||
fn JS.console.time(string)
|
||||
fn JS.console.timeEnd(string)
|
||||
fn JS.console.timeLog(string, ...any)
|
||||
fn JS.console.timeStamp(string)
|
||||
fn JS.console.trace(...any)
|
||||
fn JS.console.warn(...any)
|
||||
|
||||
// Math
|
||||
fn JS.Math.abs(f64) f64
|
||||
fn JS.Math.acos(f64) f64
|
||||
fn JS.Math.asin(f64) f64
|
||||
fn JS.Math.atan(f64) f64
|
||||
fn JS.Math.atan2(f64, f64) f64
|
||||
fn JS.Math.ceil(f64) f64
|
||||
fn JS.Math.cos(f64) f64
|
||||
fn JS.Math.exp(f64) f64
|
||||
fn JS.Math.floor(f64) f64
|
||||
fn JS.Math.log(f64) f64
|
||||
fn JS.Math.max(...f64) f64
|
||||
fn JS.Math.min(...f64) f64
|
||||
fn JS.Math.pow(f64, f64) f64
|
||||
fn JS.Math.random() f64
|
||||
fn JS.Math.round(f64) f64
|
||||
fn JS.Math.sin(f64) f64
|
||||
fn JS.Math.sqrt(f64) f64
|
||||
fn JS.Math.tan(f64) f64
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// This file contains JS functions only present in the browser.
|
||||
// They have been ported from their TypeScript definitions.
|
||||
|
||||
module builtin
|
||||
|
||||
// Window
|
||||
fn JS.atob(string) string
|
||||
fn JS.btoa(string) string
|
||||
fn JS.clearInterval(int)
|
||||
fn JS.clearTimeout(int)
|
||||
|
||||
// fn JS.createImageBitmap(ImageBitmapSource, ImageBitmapOptions) Promise<ImageBitmap>
|
||||
// fn JS.createImageBitmap(ImageBitmapSource, int, int, int, int, ImageBitmapOptions) Promise<ImageBitmap>
|
||||
|
||||
// TODO: js async attribute
|
||||
// [js_async]
|
||||
// fn JS.fetch(RequestInfo, RequestInit) Promise<Response>
|
||||
fn JS.queueMicrotask(fn())
|
||||
fn JS.setInterval(any, int, ...any) int
|
||||
fn JS.setTimeout(any, int, ...any) int
|
||||
|
||||
fn JS.alert(any)
|
||||
fn JS.blur()
|
||||
fn JS.captureEvents()
|
||||
fn JS.close()
|
||||
fn JS.confirm(string) bool
|
||||
// fn JS.departFocus(NavigationReason, FocusNavigationOrigin)
|
||||
fn JS.focus()
|
||||
// fn JS.getComputedStyle(Element, string | null) CSSStyleDeclaration
|
||||
// fn JS.getMatchedCSSRules(Element, string | null) CSSRuleList
|
||||
// fn JS.getSelection() Selection | null
|
||||
// fn JS.matchMedia(string) MediaQueryList
|
||||
fn JS.moveBy(int, int)
|
||||
fn JS.moveTo(int, int)
|
||||
fn JS.msWriteProfilerMark(string)
|
||||
// fn JS.open(string, string, string, bool) ?Window
|
||||
// fn JS.postMessage(any, string, []Transferable)
|
||||
fn JS.print()
|
||||
fn JS.prompt(string, string) ?string
|
||||
fn JS.releaseEvents()
|
||||
fn JS.resizeBy(int, int)
|
||||
fn JS.resizeTo(int, int)
|
||||
// fn JS.scroll(ScrollToOptions)
|
||||
fn JS.scroll(int, int)
|
||||
//fn JS.scrollBy(ScrollToOptions)
|
||||
fn JS.scrollBy(int, int)
|
||||
// fn JS.scrollTo(ScrollToOptions)
|
||||
fn JS.scrollTo(int, int)
|
||||
fn JS.stop()
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// This file contains JS functions only present in node.js.
|
||||
// They have been ported from their TypeScript definitions.
|
||||
|
||||
module builtin
|
||||
|
||||
fn JS.process.exit(int)
|
||||
fn JS.process.stdout.write(string) bool
|
||||
fn JS.process.stdout.writeln(string) bool
|
||||
fn JS.process.stderr.write(string) bool
|
||||
fn JS.process.stderr.writeln(string) bool
|
|
@ -15,10 +15,6 @@ const (
|
|||
'protected', 'public', 'return', 'static', 'super', 'switch', 'this', 'throw', 'try', 'typeof',
|
||||
'var', 'void', 'while', 'with', 'yield']
|
||||
tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t']
|
||||
builtin_globals = ['println', 'print']
|
||||
type_values = {
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
struct JsGen {
|
||||
|
@ -44,7 +40,8 @@ mut:
|
|||
defer_stmts []ast.DeferStmt
|
||||
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
||||
str_types []string // types that need automatic str() generation
|
||||
method_fn_decls map[string][]ast.Stmt
|
||||
method_fn_decls map[string][]ast.FnDecl
|
||||
builtin_fns []string // Functions defined in `builtin`
|
||||
empty_line bool
|
||||
}
|
||||
|
||||
|
@ -99,7 +96,7 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
|
||||
mut out := g.hashes() + g.definitions.str()
|
||||
for node in deps_resolved.nodes {
|
||||
name := g.js_name(node.name)
|
||||
name := g.js_name(node.name).replace('.', '_')
|
||||
if g.enable_doc {
|
||||
out += '/** @namespace $name */\n'
|
||||
}
|
||||
|
@ -127,7 +124,7 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
out += '\n})('
|
||||
for i, key in imports.keys() {
|
||||
if i > 0 { out += ', ' }
|
||||
out += key
|
||||
out += key.replace('.', '_')
|
||||
}
|
||||
out += ');\n\n'
|
||||
}
|
||||
|
@ -225,7 +222,7 @@ pub fn (mut g JsGen) typ(t table.Type) string {
|
|||
}
|
||||
.array_fixed {
|
||||
info := sym.info as table.ArrayFixed
|
||||
styp = g.array_fixed_typ(info.elem_type) or { g.typ(info.elem_type) + '[]' }
|
||||
styp = g.typ(info.elem_type) + '[]'
|
||||
}
|
||||
// 'map[string]int' => 'Map<string, number>'
|
||||
.map {
|
||||
|
@ -266,16 +263,10 @@ pub fn (mut g JsGen) typ(t table.Type) string {
|
|||
// '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)
|
||||
styp = g.fn_typ(info.func.args, info.func.return_type)
|
||||
}
|
||||
.interface_ {
|
||||
// TODO: Implement interfaces
|
||||
styp = 'interface'
|
||||
styp = g.js_name(sym.name)
|
||||
}
|
||||
}
|
||||
/* else {
|
||||
|
@ -286,6 +277,16 @@ pub fn (mut g JsGen) typ(t table.Type) string {
|
|||
return styp
|
||||
}
|
||||
|
||||
fn (mut g JsGen) fn_typ(args []table.Arg, return_type table.Type) string {
|
||||
mut res := '('
|
||||
for i, arg in args {
|
||||
res += '$arg.name: ${g.typ(arg.typ)}'
|
||||
if i < args.len - 1 { res += ', ' }
|
||||
}
|
||||
return res + ') => ' + g.typ(return_type)
|
||||
|
||||
}
|
||||
|
||||
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) }
|
||||
|
@ -329,23 +330,6 @@ fn (mut g JsGen) to_js_typ_val(t table.Type) string {
|
|||
return styp
|
||||
}
|
||||
|
||||
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 {
|
||||
g.out.write(tabs[g.indents[g.namespace]])
|
||||
|
@ -456,7 +440,6 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||
ast.FnDecl {
|
||||
g.fn_decl = it
|
||||
g.gen_fn_decl(it)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.ForCStmt {
|
||||
g.gen_for_c_stmt(it)
|
||||
|
@ -490,7 +473,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||
g.gen_import_stmt(it)
|
||||
}
|
||||
ast.InterfaceDecl {
|
||||
// TODO skip: interfaces not implemented yet
|
||||
g.gen_interface_decl(it)
|
||||
}
|
||||
ast.Module {
|
||||
// skip: namespacing implemented externally
|
||||
|
@ -541,8 +524,9 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
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
|
||||
// JS has no types, so no need to cast
|
||||
// Just write the expression inside
|
||||
g.expr(it.expr)
|
||||
}
|
||||
ast.CharLiteral {
|
||||
g.write("'$it.val'")
|
||||
|
@ -589,14 +573,21 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
// TODO
|
||||
}
|
||||
ast.ParExpr {
|
||||
// TODO
|
||||
g.write('(')
|
||||
g.expr(it.expr)
|
||||
g.write(')')
|
||||
}
|
||||
ast.PostfixExpr {
|
||||
g.expr(it.expr)
|
||||
g.write(it.op.str())
|
||||
}
|
||||
ast.PrefixExpr {
|
||||
// TODO
|
||||
if it.op in [.amp, .mul] {
|
||||
// C pointers/references: ignore them
|
||||
} else {
|
||||
g.write(it.op.str())
|
||||
}
|
||||
g.expr(it.right)
|
||||
}
|
||||
ast.RangeExpr {
|
||||
// Only used in IndexExpr, requires index type info
|
||||
|
@ -649,8 +640,8 @@ fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) {
|
|||
g.write('if( ')
|
||||
g.expr(a.expr)
|
||||
g.write(' ) {')
|
||||
s_assertion := a.expr.str().replace('"', "\'")
|
||||
mut mod_path := g.file.path
|
||||
s_assertion := a.expr.str().replace('"', "'")
|
||||
mut mod_path := g.file.path.replace('\\', '\\\\')
|
||||
if g.is_test {
|
||||
g.writeln(' g_test_oks++;')
|
||||
g.writeln(' cb_assertion_ok("${mod_path}", ${a.pos.line_nr+1}, "assert ${s_assertion}", "${g.fn_decl.name}()" );')
|
||||
|
@ -662,8 +653,10 @@ fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) {
|
|||
return
|
||||
}
|
||||
g.writeln('} else {')
|
||||
g.writeln(' eprintln("${mod_path}:${a.pos.line_nr+1}: FAIL: fn ${g.fn_decl.name}(): assert $s_assertion");')
|
||||
g.writeln(' exit(1);')
|
||||
g.inc_indent()
|
||||
g.writeln('builtin.eprintln("${mod_path}:${a.pos.line_nr+1}: FAIL: fn ${g.fn_decl.name}(): assert $s_assertion");')
|
||||
g.writeln('builtin.exit(1);')
|
||||
g.dec_indent()
|
||||
g.writeln('}')
|
||||
}
|
||||
|
||||
|
@ -795,18 +788,16 @@ fn (mut g JsGen) gen_enum_decl(it ast.EnumDecl) {
|
|||
|
||||
fn (mut g JsGen) gen_expr_stmt(it ast.ExprStmt) {
|
||||
g.expr(it.expr)
|
||||
expr := it.expr
|
||||
if expr is ast.IfExpr { } // no ; after an if expression
|
||||
else if !g.inside_ternary && !it.is_expr { g.writeln(';') }
|
||||
if !it.is_expr && it.expr !is ast.IfExpr && !g.inside_ternary { g.writeln(';') }
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
|
||||
if it.is_method {
|
||||
if it.no_body || it.is_method {
|
||||
// Struct methods are handled by class generation code.
|
||||
return
|
||||
}
|
||||
if it.no_body {
|
||||
return
|
||||
if g.namespace == 'builtin' {
|
||||
g.builtin_fns << it.name
|
||||
}
|
||||
g.gen_method_decl(it)
|
||||
}
|
||||
|
@ -877,7 +868,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
|||
g.write(')();')
|
||||
}
|
||||
if !it.is_anon && !it.is_method {
|
||||
g.writeln('')
|
||||
g.writeln('\n')
|
||||
}
|
||||
|
||||
g.fn_decl = voidptr(0)
|
||||
|
@ -1012,6 +1003,17 @@ fn (mut g JsGen) gen_import_stmt(it ast.Import) {
|
|||
g.namespace_imports[g.namespace] = imports
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_interface_decl(it ast.InterfaceDecl) {
|
||||
// JS is dynamically typed, so we don't need any codegen at all
|
||||
// We just need the JSDoc so TypeScript type checking works
|
||||
g.doc.gen_interface(it)
|
||||
|
||||
// This is a hack to make the interface's type accessible outside its namespace
|
||||
// TODO: interfaces are always `pub`?
|
||||
name := g.js_name(it.name)
|
||||
g.push_pub_var('/** @type $name */\n\t\t$name: undefined')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_return_stmt(it ast.Return) {
|
||||
if it.exprs.len == 0 {
|
||||
// Returns nothing
|
||||
|
@ -1022,16 +1024,8 @@ fn (mut g JsGen) gen_return_stmt(it ast.Return) {
|
|||
g.write('return ')
|
||||
if it.exprs.len == 1 {
|
||||
g.expr(it.exprs[0])
|
||||
} else {
|
||||
// Multi return
|
||||
g.write('[')
|
||||
for i, expr in it.exprs {
|
||||
g.expr(expr)
|
||||
if i < it.exprs.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
g.write(']')
|
||||
} else { // Multi return
|
||||
g.gen_array_init_values(it.exprs)
|
||||
}
|
||||
g.writeln(';')
|
||||
}
|
||||
|
@ -1073,9 +1067,7 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
|||
}
|
||||
|
||||
for i, cfn in fns {
|
||||
// TODO: Move cast to the entire array whenever it's possible
|
||||
it := cfn as ast.FnDecl
|
||||
g.gen_method_decl(it)
|
||||
g.gen_method_decl(cfn)
|
||||
if i < fns.len - 1 { g.writeln(',') } else { g.writeln('') }
|
||||
}
|
||||
g.dec_indent()
|
||||
|
@ -1086,17 +1078,50 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
|||
}
|
||||
|
||||
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(', ')
|
||||
}
|
||||
// NB: Fixed arrays and regular arrays are handled the same, since fixed arrays:
|
||||
// 1) Are only available for number types
|
||||
// 2) Give the code unnecessary complexity
|
||||
// 3) Have several limitations like missing most `Array.prototype` methods
|
||||
// 4) Modern engines can optimize regular arrays into typed arrays anyways,
|
||||
// offering similar performance
|
||||
if it.has_len {
|
||||
t1 := g.new_tmp_var()
|
||||
t2 := g.new_tmp_var()
|
||||
g.writeln('(function() {')
|
||||
g.inc_indent()
|
||||
g.writeln('const $t1 = [];')
|
||||
g.write('for (let $t2 = 0; $t2 < ')
|
||||
g.expr(it.len_expr)
|
||||
g.writeln('; $t2++) {')
|
||||
g.inc_indent()
|
||||
g.write('${t1}.push(')
|
||||
if it.has_default {
|
||||
g.expr(it.default_expr)
|
||||
} else {
|
||||
// Fill the array with the default values for its type
|
||||
t := g.to_js_typ_val(it.elem_type)
|
||||
g.write(t)
|
||||
}
|
||||
g.write(']')
|
||||
} else {}
|
||||
g.writeln(');')
|
||||
g.dec_indent()
|
||||
g.writeln('};')
|
||||
g.writeln('return $t1;')
|
||||
g.dec_indent()
|
||||
g.write('})()')
|
||||
} else {
|
||||
g.gen_array_init_values(it.exprs)
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_array_init_values(exprs []ast.Expr) {
|
||||
g.write('[')
|
||||
for i, expr in exprs {
|
||||
g.expr(expr)
|
||||
if i < exprs.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
g.write(']')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
||||
|
@ -1143,7 +1168,7 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
|||
return
|
||||
}
|
||||
} else {
|
||||
if name in builtin_globals {
|
||||
if name in g.builtin_fns {
|
||||
g.write('builtin.')
|
||||
}
|
||||
}
|
||||
|
@ -1281,19 +1306,19 @@ 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] {
|
||||
} else if r_sym.kind in [.array, .map, .string] && 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('/*')
|
||||
} else if it.op in [.key_is, .not_is] { // foo is Foo
|
||||
if it.op == .not_is { g.write('!(') }
|
||||
g.expr(it.left)
|
||||
g.write(' is $r_sym.name')
|
||||
g.write('*/0')
|
||||
// TODO
|
||||
g.write(' instanceof ')
|
||||
g.write(g.typ(it.right_type))
|
||||
if it.op == .not_is { g.write(')') }
|
||||
} else {
|
||||
g.expr(it.left)
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ fn (mut d JsDoc) gen_fn(it ast.FnDecl) {
|
|||
d.writeln(' * @deprecated')
|
||||
}
|
||||
for i, arg in it.args {
|
||||
if it.is_method && i == 0 {
|
||||
if (it.is_method || it.receiver.typ == 0) && i == 0 {
|
||||
continue
|
||||
}
|
||||
arg_type_name := d.gen.typ(arg.typ)
|
||||
|
@ -74,3 +74,17 @@ fn (mut d JsDoc) gen_fn(it ast.FnDecl) {
|
|||
d.writeln(' * @returns {$type_name}')
|
||||
d.writeln('*/')
|
||||
}
|
||||
|
||||
fn (mut d JsDoc) gen_interface(it ast.InterfaceDecl) {
|
||||
name := d.gen.js_name(it.name)
|
||||
d.writeln('/**')
|
||||
d.writeln(' * @interface $name')
|
||||
d.writeln(' * @typedef $name')
|
||||
for method in it.methods {
|
||||
// Skip receiver
|
||||
typ := d.gen.fn_typ(method.args[1..], method.return_type)
|
||||
method_name := d.gen.js_name(method.name)
|
||||
d.writeln(' * @property {$typ} $method_name')
|
||||
}
|
||||
d.writeln(' */\n')
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import os
|
||||
|
||||
const (
|
||||
test_dir = 'vlib/v/gen/js/tests/'
|
||||
output_dir = '_js_tests/'
|
||||
v_options = '-b js -w'
|
||||
)
|
||||
|
||||
fn test_example_compilation() {
|
||||
vexe := os.getenv('VEXE')
|
||||
os.chdir(os.dir(vexe))
|
||||
|
||||
os.mkdir_all(output_dir)
|
||||
|
||||
files := find_test_files()
|
||||
for file in files {
|
||||
path := os.join_path(test_dir, file)
|
||||
println('Testing $file')
|
||||
|
||||
v_code := os.system('$vexe $v_options -o ${output_dir}${file}.js $path')
|
||||
if v_code != 0 { assert false } // Compilation failed
|
||||
|
||||
js_code := os.system('node ${output_dir}${file}.js')
|
||||
if js_code != 0 { assert false } // Running failed
|
||||
}
|
||||
|
||||
os.rmdir_all(output_dir)
|
||||
}
|
||||
|
||||
fn find_test_files() []string {
|
||||
files := os.ls(test_dir) or { panic(err) }
|
||||
// The life example never exits, so tests would hang with it, skip
|
||||
mut tests := files.filter(it.ends_with('.v')).filter(it != 'life.v')
|
||||
tests.sort()
|
||||
return tests
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
*.js
|
|
@ -1,174 +0,0 @@
|
|||
// V_COMMIT_HASH 8a24d7d
|
||||
// V_CURRENT_COMMIT_HASH 6f886dc
|
||||
// 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 main */
|
||||
const main = (function () {
|
||||
/**
|
||||
* @function
|
||||
* @param {string} s
|
||||
* @returns {string}
|
||||
*/
|
||||
function map_cb(s) {
|
||||
return `CB: ${s}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {number} n
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function filter_cb(n) {
|
||||
return n < 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {...number} args
|
||||
* @returns {void}
|
||||
*/
|
||||
function variadic(...args) {
|
||||
builtin.println(args);
|
||||
builtin.println(args[0]);
|
||||
builtin.println(args[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function vararg_test() {
|
||||
variadic(1, 2, 3);
|
||||
}
|
||||
|
||||
/* program entry point */
|
||||
(function() {
|
||||
vararg_test();
|
||||
/** @type {string[]} */
|
||||
const arr1 = ["Hello", "JS", "Backend"];
|
||||
/** @type {number[]} */
|
||||
let arr2 = [1, 2, 3, 4, 5];
|
||||
/** @type {string[]} */
|
||||
const slice1 = arr1.slice(1, 3);
|
||||
/** @type {number[]} */
|
||||
const slice2 = arr2.slice(0, 3);
|
||||
/** @type {number[]} */
|
||||
const slice3 = arr2.slice(3, arr2.length);
|
||||
/** @type {string} */
|
||||
const idx1 = slice1[1];
|
||||
arr2[0] = 1;
|
||||
arr2[0 + 1] = 2;
|
||||
builtin.println(arr2);
|
||||
arr2.push(6);
|
||||
arr2.push(...[7, 8, 9]);
|
||||
builtin.println(arr2);
|
||||
builtin.println("\n\n");
|
||||
/** @type {string} */
|
||||
let slice4 = idx1.slice(0, 4);
|
||||
builtin.print("Back\t=> ");
|
||||
builtin.println(slice4);
|
||||
/** @type {number} */
|
||||
const idx2 = slice4.charCodeAt(0);
|
||||
builtin.print("66\t=> ");
|
||||
builtin.println(idx2);
|
||||
/** @type {Map<string, string>} */
|
||||
let m = new Map();
|
||||
/** @type {string} */
|
||||
const key = "key";
|
||||
m.set(key, "value");
|
||||
/** @type {string} */
|
||||
const val = m.get("key");
|
||||
builtin.print("value\t=> ");
|
||||
builtin.println(val);
|
||||
builtin.print("true\t=> ");
|
||||
builtin.println(arr1.includes("JS"));
|
||||
builtin.print("false\t=> ");
|
||||
builtin.println(!(arr2.includes(3)));
|
||||
builtin.print("true\t=> ");
|
||||
builtin.println(m.has("key"));
|
||||
builtin.print("true\t=> ");
|
||||
builtin.println(!(m.has("badkey")));
|
||||
for (let _tmp1 = 0; _tmp1 < arr1.length; ++_tmp1) {
|
||||
}
|
||||
|
||||
builtin.println("0 to 8\t=>");
|
||||
for (let i = 0; i < arr2.length; ++i) {
|
||||
builtin.println(i);
|
||||
}
|
||||
|
||||
builtin.println("\n\n4 to 5\t=> ");
|
||||
for (let _tmp2 = 0; _tmp2 < slice3.length; ++_tmp2) {
|
||||
const v = slice3[_tmp2];
|
||||
builtin.println(v);
|
||||
}
|
||||
|
||||
/** @type {string[]} */
|
||||
const a = arr1.map(it => `VAL: ${it}`);
|
||||
/** @type {string[]} */
|
||||
const b = arr1.map(map_cb);
|
||||
/** @type {string[]} */
|
||||
const c = arr1.map(it => map_cb(it));
|
||||
/** @type {string[]} */
|
||||
const d = arr1.map(function (a) {
|
||||
const _tmp3 = a;
|
||||
return `ANON: ${a}`;
|
||||
});
|
||||
/** @type {number[]} */
|
||||
const e = arr1.map(it => 456);
|
||||
builtin.println(a);
|
||||
builtin.println(b);
|
||||
builtin.println(c);
|
||||
builtin.println(d);
|
||||
builtin.println(e);
|
||||
builtin.println("\n\n");
|
||||
/** @type {number[]} */
|
||||
const aa = arr2.filter(it => it < 4);
|
||||
/** @type {number[]} */
|
||||
const bb = arr2.filter(filter_cb);
|
||||
/** @type {number[]} */
|
||||
const cc = arr2.filter(it => filter_cb(it));
|
||||
/** @type {number[]} */
|
||||
const dd = arr2.filter(function (a) {
|
||||
const _tmp4 = a;
|
||||
return a < 4;
|
||||
});
|
||||
builtin.println(aa);
|
||||
builtin.println(bb);
|
||||
builtin.println(cc);
|
||||
builtin.println(dd);
|
||||
})();
|
||||
|
||||
/* module exports */
|
||||
return {};
|
||||
})();
|
||||
|
||||
|
|
@ -66,6 +66,8 @@ print('true\t=> ')
|
|||
println('key' in m)
|
||||
print('true\t=> ')
|
||||
println('badkey' !in m)
|
||||
print('true\t=> ')
|
||||
println('o' in 'hello')
|
||||
|
||||
// for in
|
||||
for _ in arr1 {}
|
||||
|
@ -103,3 +105,16 @@ println(aa)
|
|||
println(bb)
|
||||
println(cc)
|
||||
println(dd)
|
||||
|
||||
// fixed arrays: implemented as normal arrays
|
||||
f1 := [1, 2, 3, 4, 5]!!
|
||||
mut f2 := [8]f32
|
||||
f2[0] = f32(1.23)
|
||||
f3 := ['foo', 'bar']!!
|
||||
f4 := [u64(0xffffffffffffffff), 0xdeadface]!!
|
||||
|
||||
println('
|
||||
$f1
|
||||
$f2
|
||||
$f3
|
||||
$f4')
|
||||
|
|
|
@ -1,139 +0,0 @@
|
|||
// 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);
|
||||
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
module hello
|
||||
|
||||
import hello.hello1
|
||||
|
||||
pub const (
|
||||
hello = 'Hello'
|
||||
)
|
||||
|
@ -27,5 +29,5 @@ pub fn debugger() string {
|
|||
}
|
||||
|
||||
pub fn excited() string {
|
||||
return debugger() + "!"
|
||||
return "$hello1.nested() $debugger()!"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
module hello1
|
||||
|
||||
// Unused for now: nested modules do not work yet
|
||||
|
||||
pub fn nested() string {
|
||||
return 'Nested'
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
struct Dog {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
struct Cat {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
interface Animal {
|
||||
say(s string)
|
||||
greet() int
|
||||
}
|
||||
|
||||
fn (d Dog) say(s string) { println('Dog $d.name: "$s"') }
|
||||
fn (c Cat) say(s string) { println('Cat $c.name: "$s"') }
|
||||
|
||||
fn (d Dog) greet() int { d.say('Hello!') return d.age }
|
||||
fn (c Cat) greet() int { c.say('Hello!') return c.age }
|
||||
|
||||
fn use(a Animal) {
|
||||
if a is Dog { println('dog') }
|
||||
else if a is Cat { println('cat') }
|
||||
else { println('its a bug!') }
|
||||
}
|
||||
|
||||
use(Dog{ 'Doggo', 5 })
|
||||
use(Cat{ 'Nyancat', 6 })
|
|
@ -1,260 +0,0 @@
|
|||
// V_COMMIT_HASH 8a24d7d
|
||||
// V_CURRENT_COMMIT_HASH 123d788
|
||||
// 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 main */
|
||||
const main = (function () {
|
||||
/**
|
||||
* @function
|
||||
* @param {string} s1
|
||||
* @param {string} s2
|
||||
* @returns {void}
|
||||
*/
|
||||
function test_fn(s1, s2) {
|
||||
builtin.print((s1 === s2 ? "true" : "false"));
|
||||
builtin.print("\t=> ");
|
||||
builtin.println(`"${s1}", "${s2}"`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function simple_string_interpolation() {
|
||||
/** @type {string} */
|
||||
const a = "Hello";
|
||||
/** @type {string} */
|
||||
const b = "World";
|
||||
/** @type {string} */
|
||||
const res = `${a} ${b}`;
|
||||
test_fn(res, "Hello World");
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function mixed_string_interpolation() {
|
||||
/** @type {number} */
|
||||
const num = 7;
|
||||
/** @type {string} */
|
||||
const str = "abc";
|
||||
/** @type {string} */
|
||||
const s1 = `number=${num}`;
|
||||
test_fn(s1, "number=7");
|
||||
/** @type {string} */
|
||||
const s2 = `string=${str}`;
|
||||
test_fn(s2, "string=abc");
|
||||
/** @type {string} */
|
||||
const s3 = `a: ${num} | b: ${str}`;
|
||||
test_fn(s3, "a: 7 | b: abc");
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function formatted_string_interpolation() {
|
||||
/** @type {string} */
|
||||
const x = "abc";
|
||||
/** @type {string} */
|
||||
const axb = `a:${x}:b`;
|
||||
test_fn(axb, "a:abc:b");
|
||||
/** @type {string} */
|
||||
const x_10 = `a:${x}:b`;
|
||||
/** @type {string} */
|
||||
const x10_ = `a:${x}:b`;
|
||||
test_fn(x_10, "a: abc:b");
|
||||
test_fn(x10_, "a:abc :b");
|
||||
/** @type {number} */
|
||||
const i = 23;
|
||||
/** @type {string} */
|
||||
const si_right = `${i}`;
|
||||
/** @type {string} */
|
||||
const si__left = `${i}`;
|
||||
test_fn(si_right, " 23");
|
||||
test_fn(si__left, "23 ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function implicit_str() {
|
||||
/** @type {number} */
|
||||
const i = 42;
|
||||
test_fn(`int ${i}`, "int 42");
|
||||
test_fn(`${i}`, "42");
|
||||
/** @type {boolean} */
|
||||
const check = `${i}` === "42";
|
||||
/** @type {string} */
|
||||
const text = `${i}` + "42";
|
||||
test_fn(text, "4242");
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function string_interpolation_percent_escaping() {
|
||||
/** @type {string} */
|
||||
const test = "hello";
|
||||
/** @type {string} */
|
||||
const hello = "world";
|
||||
/** @type {string} */
|
||||
const x = `%.*s${hello}${test} |${hello}|`;
|
||||
test_fn(x, "%.*sworldhello |world |");
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function string_interpolation_string_prefix() {
|
||||
/** @type {string} */
|
||||
const r = "r";
|
||||
/** @type {string} */
|
||||
const rr = `${r}${r}`;
|
||||
test_fn(rr, "rr");
|
||||
/** @type {string} */
|
||||
const c = "c";
|
||||
/** @type {string} */
|
||||
const cc = `${c}${c}`;
|
||||
test_fn(cc, "cc");
|
||||
/** @type {string} */
|
||||
const js = "js";
|
||||
/** @type {string} */
|
||||
const jsjs = `${js}${js}`;
|
||||
test_fn(jsjs, "jsjs");
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function interpolation_string_prefix_expr() {
|
||||
/** @type {number} */
|
||||
const r = 1;
|
||||
/** @type {number} */
|
||||
const c = 2;
|
||||
/** @type {number} */
|
||||
const js = 1;
|
||||
test_fn(`>${3 + r}<`, ">4<");
|
||||
test_fn(`${r === js} ${js}`, "true 1");
|
||||
test_fn(`>${js + c} ${js + r === c}<`, ">3 true<");
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function utf8_string_interpolation() {
|
||||
/** @type {string} */
|
||||
const a = "à-côté";
|
||||
/** @type {string} */
|
||||
const st = "Sträßle";
|
||||
/** @type {string} */
|
||||
const m = "10€";
|
||||
test_fn(`${a} ${st} ${m}`, "à-côté Sträßle 10€");
|
||||
/** @type {string} */
|
||||
const zz = `>${a}< >${st}< >${m}<-`;
|
||||
/** @type {string} */
|
||||
const zz_expected = "> à-côté< >Sträßle < > 10€<-";
|
||||
test_fn(zz, zz_expected);
|
||||
/** @type {string} */
|
||||
const e = "€";
|
||||
test_fn(`100.00 ${e}`, "100.00 €");
|
||||
/** @type {string} */
|
||||
const m2 = "Москва́";
|
||||
/** @type {string} */
|
||||
const d = "Antonín Dvořák";
|
||||
test_fn(`:${m2}:${d}:`, ": Москва́:Antonín Dvořák :");
|
||||
/** @type {string} */
|
||||
const g = "Πελοπόννησος";
|
||||
test_fn(`>${g}<`, ">Πελοπόννησος <");
|
||||
}
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {{v1?: number, v2?: number}} init
|
||||
*/
|
||||
function Sss({ v1 = 0, v2 = 0 }) {
|
||||
this.v1 = v1
|
||||
this.v2 = v2
|
||||
};
|
||||
Sss.prototype = {
|
||||
/** @type {number} */
|
||||
v1: 0,
|
||||
/** @type {number} */
|
||||
v2: 0,
|
||||
/**
|
||||
* @function
|
||||
* @returns {string}
|
||||
*/
|
||||
str() {
|
||||
const s = this;
|
||||
return `[${s.v1}, ${s.v2}]`;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function string_interpolation_str_evaluation() {
|
||||
/** @type {Sss} */
|
||||
let x = new Sss({
|
||||
v1: 17,
|
||||
v2: 13.455893
|
||||
});
|
||||
test_fn(`${x.str()}`, "[17, 13.456]");
|
||||
}
|
||||
|
||||
/* program entry point */
|
||||
(function() {
|
||||
simple_string_interpolation();
|
||||
mixed_string_interpolation();
|
||||
formatted_string_interpolation();
|
||||
implicit_str();
|
||||
string_interpolation_percent_escaping();
|
||||
string_interpolation_string_prefix();
|
||||
interpolation_string_prefix_expr();
|
||||
utf8_string_interpolation();
|
||||
string_interpolation_str_evaluation();
|
||||
})();
|
||||
|
||||
/* module exports */
|
||||
return {};
|
||||
})();
|
||||
|
||||
|
|
@ -1,313 +0,0 @@
|
|||
// V_COMMIT_HASH 8a24d7d
|
||||
// V_CURRENT_COMMIT_HASH 123d788
|
||||
// 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 (hl) {
|
||||
/** @constant {number} */
|
||||
const i_am_a_const = 21214;
|
||||
/** @constant {string} */
|
||||
const v_super = "amazing keyword";
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {{a?: hl["Aaa"]["prototype"]}} init
|
||||
*/
|
||||
function Foo({ a = new hl.Aaa({}) }) {
|
||||
this.a = a
|
||||
};
|
||||
Foo.prototype = {
|
||||
/** @type {hl["Aaa"]["prototype"]} */
|
||||
a: new hl.Aaa({})
|
||||
};
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {{google?: number, amazon?: boolean, yahoo?: string}} init
|
||||
*/
|
||||
function Companies({ google = 0, amazon = false, yahoo = "" }) {
|
||||
this.google = google
|
||||
this.amazon = amazon
|
||||
this.yahoo = yahoo
|
||||
};
|
||||
Companies.prototype = {
|
||||
/** @type {number} */
|
||||
google: 0,
|
||||
/** @type {boolean} */
|
||||
amazon: false,
|
||||
/** @type {string} */
|
||||
yahoo: "",
|
||||
/**
|
||||
* @function
|
||||
* @returns {number}
|
||||
*/
|
||||
method() {
|
||||
const it = this;
|
||||
/** @type {Companies} */
|
||||
const ss = new Companies({
|
||||
google: 2,
|
||||
amazon: true,
|
||||
yahoo: "hello"
|
||||
});
|
||||
const [a, b] = hello(2, "google", "not google");
|
||||
/** @type {string} */
|
||||
const glue = (a > 2 ? "more_glue" : a > 5 ? "more glueee" : "less glue");
|
||||
if (a !== 2) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/** @enum {number} */
|
||||
const POSITION = {
|
||||
go_back: 0,
|
||||
dont_go_back: 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {string} v_extends
|
||||
* @param {number} v_instanceof
|
||||
* @returns {void}
|
||||
*/
|
||||
function v_class(v_extends, v_instanceof) {
|
||||
/** @type {number} */
|
||||
const v_delete = v_instanceof;
|
||||
const _tmp1 = v_delete;
|
||||
}
|
||||
|
||||
/* program entry point */
|
||||
(async function() {
|
||||
builtin.println("Hello from V.js!");
|
||||
builtin.println(Math.atan2(1, 0));
|
||||
/** @type {number} */
|
||||
let a = 1;
|
||||
a *= 2;
|
||||
a += 3;
|
||||
builtin.println(a);
|
||||
/** @type {hl["Aaa"]["prototype"]} */
|
||||
let b = new hl.Aaa({});
|
||||
b.update("an update");
|
||||
builtin.println(b);
|
||||
/** @type {Foo} */
|
||||
let c = new Foo({
|
||||
a: new hl.Aaa({})
|
||||
});
|
||||
c.a.update("another update");
|
||||
builtin.println(c);
|
||||
const _tmp2 = "done";
|
||||
{
|
||||
const _tmp3 = "block";
|
||||
}
|
||||
|
||||
const _tmp4 = POSITION.go_back;
|
||||
const _tmp5 = hl.Ccc.a;
|
||||
/** @type {string} */
|
||||
const v_debugger = "JS keywords";
|
||||
/** @type {string} */
|
||||
const v_await = `${v_super}: ${v_debugger}`;
|
||||
/** @type {string} */
|
||||
let v_finally = "implemented";
|
||||
builtin.println(`${v_await} ${v_finally}`);
|
||||
/** @type {number} */
|
||||
const dun = i_am_a_const * 20;
|
||||
/** @type {string} */
|
||||
const dunn = hl.hello;
|
||||
for (let i = 0; i < 10; i++) {
|
||||
}
|
||||
|
||||
for (let i = 0; i < "hello".length; ++i) {
|
||||
const x = "hello"[i];
|
||||
}
|
||||
|
||||
for (let x = 1; x < 10; ++x) {
|
||||
}
|
||||
|
||||
/** @type {number[]} */
|
||||
const arr = [1, 2, 3, 4, 5];
|
||||
for (let _tmp6 = 0; _tmp6 < arr.length; ++_tmp6) {
|
||||
const i = arr[_tmp6];
|
||||
}
|
||||
|
||||
/** @type {Map<string, string>} */
|
||||
const ma = new Map([
|
||||
["str", "done"],
|
||||
["ddo", "baba"]
|
||||
]);
|
||||
for (let [m, n] of ma) {
|
||||
/** @type {string} */
|
||||
const iss = m;
|
||||
}
|
||||
|
||||
await new Promise(function(resolve){
|
||||
async(0, "hello");
|
||||
resolve();
|
||||
});
|
||||
|
||||
/** @type {(number: number) => void} */
|
||||
const fn_in_var = function (number) {
|
||||
builtin.println(`number: ${number}`);
|
||||
};
|
||||
hl.v_debugger();
|
||||
anon_consumer(hl.excited(), function (message) {
|
||||
builtin.println(message);
|
||||
});
|
||||
hl.raw_js_log();
|
||||
})();
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {string} greeting
|
||||
* @param {(message: string) => void} anon
|
||||
* @returns {void}
|
||||
*/
|
||||
function anon_consumer(greeting, anon) {
|
||||
anon(greeting);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {number} num
|
||||
* @param {string} def
|
||||
* @returns {void}
|
||||
*/
|
||||
function async(num, def) {
|
||||
}
|
||||
|
||||
/* [inline] */
|
||||
/* [deprecated] */
|
||||
/**
|
||||
* @function
|
||||
* @deprecated
|
||||
* @param {number} game_on
|
||||
* @param {...string} dummy
|
||||
* @returns {[number, number]}
|
||||
*/
|
||||
function hello(game_on, ...dummy) {
|
||||
for (let _tmp7 = 0; _tmp7 < dummy.length; ++_tmp7) {
|
||||
const dd = dummy[_tmp7];
|
||||
/** @type {string} */
|
||||
const l = dd;
|
||||
}
|
||||
|
||||
(function defer() {
|
||||
/** @type {string} */
|
||||
const v_do = "not";
|
||||
})();
|
||||
return [game_on + 2, 221];
|
||||
}
|
||||
|
||||
/* module exports */
|
||||
return {};
|
||||
})(hello);
|
||||
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
import hello as hl
|
||||
|
||||
fn JS.alert(arg string)
|
||||
fn JS.Math.atan2(f64, f64) f64
|
||||
import hello.hello1 as hl1
|
||||
|
||||
const (
|
||||
i_am_a_const = 21214
|
||||
|
@ -64,6 +62,7 @@ fn main() {
|
|||
|
||||
dun := i_am_a_const * 20
|
||||
dunn := hl.hello // External constant
|
||||
_ = hl1.nested()
|
||||
|
||||
for i := 0; i < 10; i++ {}
|
||||
|
||||
|
@ -79,6 +78,7 @@ fn main() {
|
|||
'ddo': "baba"
|
||||
}
|
||||
|
||||
// panic('foo')
|
||||
for m, n in ma {
|
||||
iss := m
|
||||
}
|
||||
|
|
|
@ -1,204 +0,0 @@
|
|||
// 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 main */
|
||||
const main = (function () {
|
||||
/**
|
||||
* @function
|
||||
* @returns {void}
|
||||
*/
|
||||
function clear() {
|
||||
console.clear();
|
||||
}
|
||||
|
||||
/** @constant {number} */
|
||||
const w = 30;
|
||||
/** @constant {number} */
|
||||
const h = 30;
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {boolean[][]} game
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function get(game, x, y) {
|
||||
if (y < 0 || x < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (y >= h || x >= w) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return game[y][x];
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {boolean[][]} game
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @returns {number}
|
||||
*/
|
||||
function neighbours(game, x, y) {
|
||||
/** @type {number} */
|
||||
let count = 0;
|
||||
if (get(game, x - 1, y - 1)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (get(game, x, y - 1)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (get(game, x + 1, y - 1)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (get(game, x - 1, y)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (get(game, x + 1, y)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (get(game, x - 1, y + 1)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (get(game, x, y + 1)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (get(game, x + 1, y + 1)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {boolean[][]} game
|
||||
* @returns {boolean[][]}
|
||||
*/
|
||||
function step(game) {
|
||||
/** @type {boolean[][]} */
|
||||
let new_game = [[]];
|
||||
for (let y = 0; y < game.length; ++y) {
|
||||
let row = game[y];
|
||||
/** @type {boolean[]} */
|
||||
let new_row = [];
|
||||
new_game[y] = new_row;
|
||||
for (let x = 0; x < row.length; ++x) {
|
||||
let cell = row[x];
|
||||
/** @type {number} */
|
||||
const count = neighbours(game, x, y);
|
||||
new_row[x] = cell && count === 2 || count === 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new_game;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {boolean[]} row
|
||||
* @returns {string}
|
||||
*/
|
||||
function row_str(row) {
|
||||
/** @type {string} */
|
||||
let str = "";
|
||||
for (let _tmp1 = 0; _tmp1 < row.length; ++_tmp1) {
|
||||
let cell = row[_tmp1];
|
||||
if (cell) {
|
||||
str += "◼ ";
|
||||
} else {
|
||||
str += "◻ ";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {boolean[][]} game
|
||||
* @returns {void}
|
||||
*/
|
||||
function show(game) {
|
||||
clear();
|
||||
for (let _tmp2 = 0; _tmp2 < game.length; ++_tmp2) {
|
||||
let row = game[_tmp2];
|
||||
builtin.println(row_str(row));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* program entry point */
|
||||
(function() {
|
||||
/** @type {boolean[][]} */
|
||||
let game = [[]];
|
||||
for (let y = 0; y < h; ++y) {
|
||||
/** @type {boolean[]} */
|
||||
let row = [];
|
||||
for (let x = 0; x < w; ++x) {
|
||||
row[x] = false;
|
||||
}
|
||||
|
||||
game[y] = row;
|
||||
}
|
||||
|
||||
game[11][15] = true;
|
||||
game[11][16] = true;
|
||||
game[12][16] = true;
|
||||
game[10][21] = true;
|
||||
game[12][20] = true;
|
||||
game[12][21] = true;
|
||||
game[12][22] = true;
|
||||
setInterval(function () {
|
||||
show(game);
|
||||
game = step(game);
|
||||
}, 500);
|
||||
})();
|
||||
|
||||
/* module exports */
|
||||
return {};
|
||||
})();
|
||||
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
fn JS.setInterval(f fn (), ms int)
|
||||
fn JS.console.clear()
|
||||
fn clear() { JS.console.clear() }
|
||||
|
||||
const (w = 30 h = 30)
|
||||
|
@ -25,13 +23,13 @@ fn neighbours(game [][]bool, x int, y int) int {
|
|||
}
|
||||
|
||||
fn step(game [][]bool) [][]bool {
|
||||
mut new_game := [[]bool{}]
|
||||
mut new_game := [][]bool{}
|
||||
for y, row in game {
|
||||
mut new_row := []bool{}
|
||||
new_game[y] = new_row
|
||||
for x, cell in row {
|
||||
count := neighbours(game, x, y)
|
||||
new_row[x] = cell && count == 2 || count == 3 // TODO: count in [2, 3]
|
||||
new_row[x] = (cell && count in [2, 3]) || count == 3
|
||||
}
|
||||
}
|
||||
return new_game
|
||||
|
@ -53,15 +51,7 @@ fn show(game [][]bool) {
|
|||
}
|
||||
}
|
||||
|
||||
mut game := [[]bool{}]
|
||||
|
||||
for y in 0..h {
|
||||
mut row := []bool{}
|
||||
for x in 0..w {
|
||||
row[x] = false
|
||||
}
|
||||
game[y] = row
|
||||
}
|
||||
mut game := [][]bool{ len: h, init: []bool{ len: w } }
|
||||
|
||||
game[11][15] = true
|
||||
game[11][16] = true
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
// 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 main */
|
||||
const main = (function () {
|
||||
/* program entry point */
|
||||
(function() {
|
||||
builtin.println("hello world");
|
||||
})();
|
||||
|
||||
/* module exports */
|
||||
return {};
|
||||
})();
|
||||
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
// 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 main */
|
||||
const main = (function () {
|
||||
/**
|
||||
* @constructor
|
||||
* @param {{value?: number, test?: Map<string, number>, hello?: number[]}} init
|
||||
*/
|
||||
function Int({ value = 0, test = new Map(), hello = [] }) {
|
||||
this.value = value
|
||||
this.test = test
|
||||
this.hello = hello
|
||||
};
|
||||
Int.prototype = {
|
||||
/** @type {number} */
|
||||
value: 0,
|
||||
/** @type {Map<string, number>} */
|
||||
test: new Map(),
|
||||
/** @type {number[]} */
|
||||
hello: [],
|
||||
/**
|
||||
* @function
|
||||
* @param {number} value
|
||||
* @returns {void}
|
||||
*/
|
||||
add(value) {
|
||||
const i = this;
|
||||
i.value += value;
|
||||
},
|
||||
/**
|
||||
* @function
|
||||
* @returns {number}
|
||||
*/
|
||||
get() {
|
||||
const i = this;
|
||||
return i.value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
return {};
|
||||
})();
|
||||
|
||||
|
|
@ -23,11 +23,11 @@ struct Config {
|
|||
fn use_config(c Config) {}
|
||||
|
||||
fn main() {
|
||||
a := Int { value: 10 }
|
||||
mut a := Int { value: 10 }
|
||||
a.add(5)
|
||||
println(a) // 15
|
||||
|
||||
b := Int{}
|
||||
mut b := Int{}
|
||||
b.add(10)
|
||||
println(b.get()) // 10
|
||||
|
||||
|
|
|
@ -355,7 +355,7 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool) {
|
|||
mut args := []table.Arg{}
|
||||
mut is_variadic := false
|
||||
// `int, int, string` (no names, just types)
|
||||
types_only := p.tok.kind in [.amp, .ellipsis] || (p.peek_tok.kind == .comma && p.table.known_type(p.tok.lit)) ||
|
||||
types_only := p.tok.kind in [.amp, .ellipsis, .key_fn] || (p.peek_tok.kind == .comma && p.table.known_type(p.tok.lit)) ||
|
||||
p.peek_tok.kind == .rpar
|
||||
// TODO copy pasta, merge 2 branches
|
||||
if types_only {
|
||||
|
|
Loading…
Reference in New Issue