v/vlib/compiler/gen_js.v

249 lines
5.9 KiB
V

module compiler
import strings
const (
dot_ptr = '.'
)
fn (p mut Parser) gen_var_decl(name string, is_static bool) string {
p.gen('var $name /* typ */ = ')
mut typ := p.bool_expression()
if typ.starts_with('...') { typ = typ.right(3) }
or_else := p.tok == .key_orelse
//tmp := p.get_tmp()
if or_else {
//panic('optionals todo')
}
return typ
}
fn (p mut Parser) gen_fn_decl(f Fn, typ, _str_args string) {
mut str_args := ''
for i, arg in f.args {
str_args += ' /** @type { $arg.typ } **/ ' + arg.name
if i < f.args.len - 1 {
str_args += ', '
}
}
name := p.table.fn_gen_name(f)
if f.is_method {
p.genln('\n${f.receiver_typ}.prototype.${name} = function($str_args) {')
} else {
p.genln('/** @return { $typ } **/\nfunction $name($str_args) {')
}
}
fn (p mut Parser) gen_blank_identifier_assign() {
assign_error_tok_idx := p.token_idx
p.check_name()
p.check_space(.assign)
is_indexer := p.peek() == .lsbr
is_fn_call, next_expr := p.is_next_expr_fn_call()
p.bool_expression()
if !is_indexer && !is_fn_call {
p.error_with_token_index('assigning `$next_expr` to `_` is redundant', assign_error_tok_idx)
}
or_else := p.tok == .key_orelse
//tmp := p.get_tmp()
if or_else {
//panic('optionals todo')
}
}
fn types_to_c(types []Type, table &Table) string {
mut sb := strings.new_builder(10)
for t in types {
if t.cat != .union_ && t.cat != .struct_ {
continue
}
sb.write('\n/**\n')
sb.write('* @typedef { object } $t.name' + 'Type\n')
for field in t.fields {
sb.writeln('* @property { $field.typ' + '= } $field.name')
}
sb.writeln('**/\n')
sb.writeln('/** @type { function & $t.name' + 'Type } **/')
sb.writeln('var $t.name = function() {}')
}
return sb.str()
}
fn (p mut Parser) index_get(typ string, fn_ph int, cfg IndexCfg) {
p.cgen.cur_line = p.cgen.cur_line.replace(',', '[') + ']'
}
fn (table &Table) fn_gen_name(f &Fn) string {
mut name := f.name
if f.is_method {
name = name.replace(' ', '')
name = name.replace('*', '')
name = name.replace('+', 'plus')
name = name.replace('-', 'minus')
return name
}
// Avoid name conflicts (with things like abs(), print() etc).
// Generate b_abs(), b_print()
// TODO duplicate functionality
if f.mod == 'builtin' && f.name in CReserved {
return 'v_$name'
}
return name
}
fn (p mut Parser) gen_method_call(receiver_type, ftyp string, cgen_name string, receiver Var,method_ph int) {
//mut cgen_name := p.table.fn_gen_name(f)
//mut method_call := cgen_name + '('
p.gen('.' + cgen_name.all_after('_') + '(')
//p.cgen.set_placeholder(method_ph, '$cast kKE $method_call')
//return method_call
}
fn (p mut Parser) gen_array_at(typ string, is_arr0 bool, fn_ph int) {
p.gen('[')
}
fn (p mut Parser) gen_for_header(i, tmp, var_typ, val string) {
p.genln('for (var $i = 0; $i < ${tmp}.length; $i++) {')
if val == '_' { return }
p.genln('var $val = $tmp [$i];')
}
fn (p mut Parser) gen_for_range_header(i, range_end, tmp, var_type, val string) {
p.genln(';\nfor (var $i = $tmp; $i < $range_end; $i++) {')
if val == '_' { return }
p.genln('var /*$var_type*/ $val = $i;')
}
fn (p mut Parser) gen_for_str_header(i, tmp, var_typ, val string) {
p.genln('for (var $i = 0; $i < $tmp .length; $i ++) {')
if val == '_' { return }
p.genln('var $val = $tmp[$i];')
}
fn (p mut Parser) gen_for_map_header(i, tmp, var_typ, val, typ string) {
p.genln('for (var $i in $tmp) {')
if val == '_' { return }
p.genln('var $val = $tmp[$i];')
}
fn (p mut Parser) gen_for_varg_header(i, varg, var_typ, val string) {
p.genln('for (var $i = 0; $i < ${varg}.len; $i++) {')
if val == '_' { return }
p.genln('var $val = ${varg}.args[$i];')
}
fn (p mut Parser) gen_array_init(typ string, no_alloc bool, new_arr_ph int, nr_elems int) {
p.cgen.set_placeholder(new_arr_ph, '[')
p.gen(']')
}
fn (p mut Parser) gen_array_set(typ string, is_ptr, is_map bool,fn_ph, assign_pos int, is_cao bool) {
mut val := p.cgen.cur_line.right(assign_pos)
p.cgen.resetln(p.cgen.cur_line.left(assign_pos))
p.gen('] =')
cao_tmp := p.cgen.cur_line
if is_cao {
val = cao_tmp + val.all_before('=') + val.all_after('=')
}
p.gen(val)
}
// returns true in case of an early return
fn (p mut Parser) gen_struct_init(typ string, t Type) bool {
p.next()
p.check(.lcbr)
ptr := typ.contains('*')
if !ptr {
p.gen('{')
}
else {
// TODO tmp hack for 0 pointers init
// &User{!} ==> 0
if p.tok == .not {
p.next()
p.gen('}')
p.check(.rcbr)
return true
}
}
return false
}
fn (p mut Parser) gen_struct_field_init(field string) {
p.gen('$field : ')
}
fn (p mut Parser) gen_empty_map(typ string) {
p.gen('{}')
}
fn (p mut Parser) cast(typ string) string {
p.next()
pos := p.cgen.add_placeholder()
if p.tok == .rpar {
p.next()
}
p.check(.lpar)
p.bool_expression()
if typ == 'string' {
if p.tok == .comma {
p.check(.comma)
p.cgen.set_placeholder(pos, 'tos(')
//p.gen('tos(')
p.gen(', ')
p.expression()
p.gen(')')
}
}
p.check(.rpar)
return typ
}
fn type_default(typ string) string {
if typ.starts_with('array_') {
return '[]'
}
// Always set pointers to 0
if typ.ends_with('*') {
return '0'
}
// User struct defined in another module.
if typ.contains('__') {
return '{}'
}
// Default values for other types are not needed because of mandatory initialization
match typ {
'bool'{ return '0'}
'string'{ return 'tos("")'}
'i8'{ return '0'}
'i16'{ return '0'}
'i64'{ return '0'}
'u16'{ return '0'}
'u32'{ return '0'}
'u64'{ return '0'}
'byte'{ return '0'}
'int'{ return '0'}
'rune'{ return '0'}
'f32'{ return '0.0'}
'f64'{ return '0.0'}
'byteptr'{ return '0'}
'voidptr'{ return '0'}
}
return '{}'
}
fn (p mut Parser) gen_array_push(ph int, typ, expr_type, tmp, tmp_typ string) {
push_array := typ == expr_type
if push_array {
p.cgen.set_placeholder(ph, 'push(&' )
p.gen('), $tmp, $typ)')
} else {
p.check_types(expr_type, tmp_typ)
p.gen(')')
p.cgen.cur_line = p.cgen.cur_line.replace(',', '.push')
}
}