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,6 +1107,9 @@ 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 | ||||||
|  | 	if it.fields.len == 0 { | ||||||
|  | 		g.write('new ${g.js_name(name)}({})') | ||||||
|  | 	} else { | ||||||
| 		g.writeln('new ${g.js_name(name)}({') | 		g.writeln('new ${g.js_name(name)}({') | ||||||
| 		g.inc_indent() | 		g.inc_indent() | ||||||
| 		for i, field in it.fields { | 		for i, field in it.fields { | ||||||
|  | @ -1062,6 +1122,7 @@ fn (mut g JsGen) gen_struct_init(it ast.StructInit) { | ||||||
| 		} | 		} | ||||||
| 		g.dec_indent() | 		g.dec_indent() | ||||||
| 		g.write('})') | 		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