jsgen: class -> factory
							parent
							
								
									1633675c11
								
							
						
					
					
						commit
						f2ea8ca62c
					
				|  | @ -7,10 +7,10 @@ module builtin | |||
| fn JS.console.log(arg ...string) | ||||
| fn JS.process.stdout.write(arg string) | ||||
| 
 | ||||
| pub fn println(s string) { | ||||
| pub fn println(s any) { | ||||
| 	JS.console.log(s) | ||||
| } | ||||
| 
 | ||||
| pub fn print(s string) { | ||||
| pub fn print(s any) { | ||||
| 	JS.process.stdout.write(s) | ||||
| } | ||||
|  | @ -17,6 +17,9 @@ const ( | |||
| 		'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 { | ||||
|  | @ -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] { | ||||
| 			out += '\n\t\t$pub_var,' | ||||
| 		} | ||||
| 		out += '\n\t};' | ||||
| 		if g.namespaces_pub[node.name].len > 0 { out += '\n\t' } | ||||
| 		out += '};' | ||||
| 		out += '\n})(' | ||||
| 		for i, key in imports.keys() { | ||||
| 			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_', '')) + '[]' | ||||
| 			} else if typ.starts_with('map_') { | ||||
| 				tokens := typ.split('_') | ||||
| 				styp = 'Map<${tokens[1]}, ${tokens[2]}>' | ||||
| 				styp = 'Map<${g.to_js_typ(tokens[1])}, ${g.to_js_typ(tokens[2])}>' | ||||
| 			} else { | ||||
| 				styp = typ | ||||
| 			} | ||||
|  | @ -259,6 +263,42 @@ fn (mut g JsGen) to_js_typ(typ string) string { | |||
| 	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 (mut g JsGen) gen_indent() { | ||||
|  | @ -828,7 +868,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) { | |||
| 	if is_main { | ||||
| 		g.write(')();') | ||||
| 	} | ||||
| 	if !it.is_anon { | ||||
| 	if !it.is_anon && !it.is_method { | ||||
| 		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) { | ||||
| 	g.writeln('class ${g.js_name(node.name)} {') | ||||
| 	g.inc_indent() | ||||
| 	g.writeln(g.doc.gen_ctor(node.fields)) | ||||
| 	g.writeln('constructor(values) {') | ||||
| 	g.writeln(g.doc.gen_fac_fn(node.fields)) | ||||
| 	g.write('function ${g.js_name(node.name)}({ ') | ||||
| 	for i, field in node.fields { | ||||
| 		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() | ||||
| 	for field in node.fields { | ||||
| 		// TODO: Generate default struct init values
 | ||||
| 		g.writeln('this.$field.name = values.$field.name') | ||||
| 		g.writeln('this.$field.name = $field.name') | ||||
| 	} | ||||
| 	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] | ||||
| 	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
 | ||||
| 		it := cfn as ast.FnDecl | ||||
| 		g.writeln('') | ||||
| 		g.gen_method_decl(it) | ||||
| 		if i < fns.len - 1 { g.writeln(',') } else { g.writeln('') } | ||||
| 	} | ||||
| 	g.dec_indent() | ||||
| 	g.writeln('}\n') | ||||
| 	g.writeln('};\n') | ||||
| 	if node.is_pub { | ||||
| 		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) { | ||||
| 	type_sym := g.table.get_type_symbol(it.typ) | ||||
| 	name := type_sym.name | ||||
| 	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(', ') | ||||
| 	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.writeln('') | ||||
| 		g.dec_indent() | ||||
| 		g.write('})') | ||||
| 	} | ||||
| 	g.dec_indent() | ||||
| 	g.write('})') | ||||
| } | ||||
| 
 | ||||
| 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() | ||||
| } | ||||
| 
 | ||||
| fn (mut d JsDoc) gen_ctor(fields []ast.StructField) string { | ||||
| fn (mut d JsDoc) gen_fac_fn(fields []ast.StructField) string { | ||||
| 	d.reset() | ||||
| 	d.writeln('/**') | ||||
| 	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.
 | ||||
| 		// TODO: Actually generate default struct init values :P
 | ||||
| 		d.write('$field.name?: ${d.gen.typ(field.typ)}') | ||||
| 		if i < fields.len - 1 { | ||||
| 			d.write(', ') | ||||
| 		} | ||||
| 		if i < fields.len - 1 { d.write(', ') } | ||||
| 	} | ||||
| 	d.writeln('}} values - values for this class fields') | ||||
| 	d.writeln(' * @constructor') | ||||
|  | @ -93,6 +91,7 @@ fn (mut d JsDoc) gen_fn(it ast.FnDecl) string { | |||
| 		} | ||||
| 	} | ||||
| 	d.writeln(' * @returns {$type_name}') | ||||
| 	d.writeln(' * @function') | ||||
| 	d.write('*/') | ||||
| 	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