jsgen: class -> factory
parent
1633675c11
commit
f2ea8ca62c
|
@ -7,10 +7,10 @@ module builtin
|
||||||
fn JS.console.log(arg ...string)
|
fn JS.console.log(arg ...string)
|
||||||
fn JS.process.stdout.write(arg string)
|
fn JS.process.stdout.write(arg string)
|
||||||
|
|
||||||
pub fn println(s string) {
|
pub fn println(s any) {
|
||||||
JS.console.log(s)
|
JS.console.log(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print(s string) {
|
pub fn print(s any) {
|
||||||
JS.process.stdout.write(s)
|
JS.process.stdout.write(s)
|
||||||
}
|
}
|
|
@ -17,6 +17,9 @@ const (
|
||||||
'var', 'void', 'while', 'with', 'yield']
|
'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']
|
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']
|
builtin_globals = ['println', 'print']
|
||||||
|
type_values = {
|
||||||
|
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
struct JsGen {
|
struct JsGen {
|
||||||
|
@ -115,7 +118,8 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
for pub_var in g.namespaces_pub[node.name] {
|
for pub_var in g.namespaces_pub[node.name] {
|
||||||
out += '\n\t\t$pub_var,'
|
out += '\n\t\t$pub_var,'
|
||||||
}
|
}
|
||||||
out += '\n\t};'
|
if g.namespaces_pub[node.name].len > 0 { out += '\n\t' }
|
||||||
|
out += '};'
|
||||||
out += '\n})('
|
out += '\n})('
|
||||||
for i, key in imports.keys() {
|
for i, key in imports.keys() {
|
||||||
if i > 0 { out += ', ' }
|
if i > 0 { out += ', ' }
|
||||||
|
@ -242,7 +246,7 @@ fn (mut g JsGen) to_js_typ(typ string) string {
|
||||||
styp = g.to_js_typ(typ.replace('array_', '')) + '[]'
|
styp = g.to_js_typ(typ.replace('array_', '')) + '[]'
|
||||||
} else if typ.starts_with('map_') {
|
} else if typ.starts_with('map_') {
|
||||||
tokens := typ.split('_')
|
tokens := typ.split('_')
|
||||||
styp = 'Map<${tokens[1]}, ${tokens[2]}>'
|
styp = 'Map<${g.to_js_typ(tokens[1])}, ${g.to_js_typ(tokens[2])}>'
|
||||||
} else {
|
} else {
|
||||||
styp = typ
|
styp = typ
|
||||||
}
|
}
|
||||||
|
@ -259,6 +263,42 @@ fn (mut g JsGen) to_js_typ(typ string) string {
|
||||||
return styp
|
return styp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) to_js_typ_val(typ string) string {
|
||||||
|
mut styp := ''
|
||||||
|
match typ {
|
||||||
|
'number' {
|
||||||
|
styp = '0'
|
||||||
|
}
|
||||||
|
'boolean' {
|
||||||
|
styp = 'false'
|
||||||
|
}
|
||||||
|
'Object' {
|
||||||
|
styp = '{}'
|
||||||
|
}
|
||||||
|
'string' {
|
||||||
|
styp = '""'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if typ.starts_with('Map') {
|
||||||
|
styp = 'new Map()'
|
||||||
|
} else if typ.ends_with('[]') {
|
||||||
|
styp = '[]'
|
||||||
|
} else {
|
||||||
|
styp = '{}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ns.export => ns["export"]
|
||||||
|
for i, v in styp.split('.') {
|
||||||
|
if i == 0 {
|
||||||
|
styp = v
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
styp += '["$v"]'
|
||||||
|
}
|
||||||
|
return styp
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (g &JsGen) save() {}
|
pub fn (g &JsGen) save() {}
|
||||||
|
|
||||||
pub fn (mut g JsGen) gen_indent() {
|
pub fn (mut g JsGen) gen_indent() {
|
||||||
|
@ -828,7 +868,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
||||||
if is_main {
|
if is_main {
|
||||||
g.write(')();')
|
g.write(')();')
|
||||||
}
|
}
|
||||||
if !it.is_anon {
|
if !it.is_anon && !it.is_method {
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1021,27 +1061,44 @@ fn (mut g JsGen) enum_expr(node ast.Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
||||||
g.writeln('class ${g.js_name(node.name)} {')
|
g.writeln(g.doc.gen_fac_fn(node.fields))
|
||||||
g.inc_indent()
|
g.write('function ${g.js_name(node.name)}({ ')
|
||||||
g.writeln(g.doc.gen_ctor(node.fields))
|
for i, field in node.fields {
|
||||||
g.writeln('constructor(values) {')
|
g.write('$field.name = ')
|
||||||
|
if field.has_default_expr {
|
||||||
|
g.expr(field.default_expr)
|
||||||
|
} else {
|
||||||
|
g.write('${g.to_js_typ_val(g.typ(field.typ))}')
|
||||||
|
}
|
||||||
|
if i < node.fields.len - 1 { g.write(', ') }
|
||||||
|
}
|
||||||
|
g.writeln(' }) {')
|
||||||
g.inc_indent()
|
g.inc_indent()
|
||||||
for field in node.fields {
|
for field in node.fields {
|
||||||
// TODO: Generate default struct init values
|
g.writeln('this.$field.name = $field.name')
|
||||||
g.writeln('this.$field.name = values.$field.name')
|
|
||||||
}
|
}
|
||||||
g.dec_indent()
|
g.dec_indent()
|
||||||
g.writeln('}')
|
g.writeln('};')
|
||||||
|
|
||||||
|
g.writeln('${g.js_name(node.name)}.prototype = {')
|
||||||
|
g.inc_indent()
|
||||||
|
|
||||||
fns := g.method_fn_decls[node.name]
|
fns := g.method_fn_decls[node.name]
|
||||||
for cfn in fns {
|
|
||||||
|
for i, field in node.fields {
|
||||||
|
g.writeln(g.doc.gen_typ(g.typ(field.typ), field.name))
|
||||||
|
g.write('$field.name: ${g.to_js_typ_val(g.typ(field.typ))}')
|
||||||
|
if i < node.fields.len - 1 || fns.len > 0 { g.writeln(',') } else { g.writeln('') }
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, cfn in fns {
|
||||||
// TODO: Move cast to the entire array whenever it's possible
|
// TODO: Move cast to the entire array whenever it's possible
|
||||||
it := cfn as ast.FnDecl
|
it := cfn as ast.FnDecl
|
||||||
g.writeln('')
|
|
||||||
g.gen_method_decl(it)
|
g.gen_method_decl(it)
|
||||||
|
if i < fns.len - 1 { g.writeln(',') } else { g.writeln('') }
|
||||||
}
|
}
|
||||||
g.dec_indent()
|
g.dec_indent()
|
||||||
g.writeln('}\n')
|
g.writeln('};\n')
|
||||||
if node.is_pub {
|
if node.is_pub {
|
||||||
g.push_pub_var(node.name)
|
g.push_pub_var(node.name)
|
||||||
}
|
}
|
||||||
|
@ -1050,18 +1107,22 @@ 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_struct_init(it ast.StructInit) {
|
||||||
type_sym := g.table.get_type_symbol(it.typ)
|
type_sym := g.table.get_type_symbol(it.typ)
|
||||||
name := type_sym.name
|
name := type_sym.name
|
||||||
g.writeln('new ${g.js_name(name)}({')
|
if it.fields.len == 0 {
|
||||||
g.inc_indent()
|
g.write('new ${g.js_name(name)}({})')
|
||||||
for i, field in it.fields {
|
} else {
|
||||||
g.write('$field.name: ')
|
g.writeln('new ${g.js_name(name)}({')
|
||||||
g.expr(field.expr)
|
g.inc_indent()
|
||||||
if i < it.fields.len - 1 {
|
for i, field in it.fields {
|
||||||
g.write(', ')
|
g.write('$field.name: ')
|
||||||
|
g.expr(field.expr)
|
||||||
|
if i < it.fields.len - 1 {
|
||||||
|
g.write(', ')
|
||||||
|
}
|
||||||
|
g.writeln('')
|
||||||
}
|
}
|
||||||
g.writeln('')
|
g.dec_indent()
|
||||||
|
g.write('})')
|
||||||
}
|
}
|
||||||
g.dec_indent()
|
|
||||||
g.write('})')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_ident(node ast.Ident) {
|
fn (mut g JsGen) gen_ident(node ast.Ident) {
|
||||||
|
|
|
@ -53,7 +53,7 @@ fn (mut d JsDoc) gen_typ(typ, name string) string {
|
||||||
return d.out.str()
|
return d.out.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut d JsDoc) gen_ctor(fields []ast.StructField) string {
|
fn (mut d JsDoc) gen_fac_fn(fields []ast.StructField) string {
|
||||||
d.reset()
|
d.reset()
|
||||||
d.writeln('/**')
|
d.writeln('/**')
|
||||||
d.write(' * @param {{')
|
d.write(' * @param {{')
|
||||||
|
@ -62,9 +62,7 @@ fn (mut d JsDoc) gen_ctor(fields []ast.StructField) string {
|
||||||
// so all struct members don't have to be initialized.
|
// so all struct members don't have to be initialized.
|
||||||
// TODO: Actually generate default struct init values :P
|
// TODO: Actually generate default struct init values :P
|
||||||
d.write('$field.name?: ${d.gen.typ(field.typ)}')
|
d.write('$field.name?: ${d.gen.typ(field.typ)}')
|
||||||
if i < fields.len - 1 {
|
if i < fields.len - 1 { d.write(', ') }
|
||||||
d.write(', ')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
d.writeln('}} values - values for this class fields')
|
d.writeln('}} values - values for this class fields')
|
||||||
d.writeln(' * @constructor')
|
d.writeln(' * @constructor')
|
||||||
|
@ -93,6 +91,7 @@ fn (mut d JsDoc) gen_fn(it ast.FnDecl) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.writeln(' * @returns {$type_name}')
|
d.writeln(' * @returns {$type_name}')
|
||||||
|
d.writeln(' * @function')
|
||||||
d.write('*/')
|
d.write('*/')
|
||||||
return d.out.str()
|
return d.out.str()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
// V_COMMIT_HASH 7e55261
|
||||||
|
// V_CURRENT_COMMIT_HASH 79b1f27
|
||||||
|
// 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 {{value?: number, test?: Map<string, number>, hello?: number[]}} values - values for this class fields
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function Int({ value = 0, test = new Map(), hello = [] }) {
|
||||||
|
this.value = value
|
||||||
|
this.test = test
|
||||||
|
this.hello = hello
|
||||||
|
};
|
||||||
|
Int.prototype = {
|
||||||
|
/** @type {number} - value */
|
||||||
|
value: 0,
|
||||||
|
/** @type {Map<string, number>} - test */
|
||||||
|
test: new Map(),
|
||||||
|
/** @type {number[]} - hello */
|
||||||
|
hello: [],
|
||||||
|
/**
|
||||||
|
* @param {number} value
|
||||||
|
* @returns {void}
|
||||||
|
* @function
|
||||||
|
*/
|
||||||
|
add(value) {
|
||||||
|
const i = this;
|
||||||
|
i.value += value;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @returns {number}
|
||||||
|
* @function
|
||||||
|
*/
|
||||||
|
get() {
|
||||||
|
const i = this;
|
||||||
|
return i.value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* program entry point */
|
||||||
|
(function() {
|
||||||
|
const a = new Int({
|
||||||
|
value: 10
|
||||||
|
});
|
||||||
|
a.add(5);
|
||||||
|
builtin.println(a);
|
||||||
|
const b = new Int({});
|
||||||
|
b.add(10);
|
||||||
|
builtin.println(b.get());
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* module exports */
|
||||||
|
return {};
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
module main
|
||||||
|
|
||||||
|
struct Int {
|
||||||
|
mut:
|
||||||
|
value int
|
||||||
|
test map[string]int
|
||||||
|
hello []int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut i Int) add(value int) {
|
||||||
|
i.value += value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (i Int) get() int {
|
||||||
|
return i.value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
a := Int { value: 10 }
|
||||||
|
a.add(5)
|
||||||
|
println(a) // 15
|
||||||
|
|
||||||
|
b := Int{}
|
||||||
|
b.add(10)
|
||||||
|
println(b.get()) // 10
|
||||||
|
}
|
Loading…
Reference in New Issue