259 lines
6.2 KiB
V
259 lines
6.2 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
|
|
mut expr := p.lit
|
|
mut is_fn_call := p.peek() == .lpar
|
|
if !is_fn_call {
|
|
mut i := p.token_idx+1
|
|
for (p.tokens[i].tok == .dot || p.tokens[i].tok == .name) &&
|
|
p.tokens[i].lit != '_' {
|
|
expr += if p.tokens[i].tok == .dot { '.' } else { p.tokens[i].lit }
|
|
i++
|
|
}
|
|
is_fn_call = p.tokens[i].tok == .lpar
|
|
}
|
|
p.bool_expression()
|
|
if !is_indexer && !is_fn_call {
|
|
p.error_with_token_index('assigning `$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
|
|
switch typ {
|
|
case 'bool': return '0'
|
|
case 'string': return '""'
|
|
case 'i8': return '0'
|
|
case 'i16': return '0'
|
|
case 'i64': return '0'
|
|
case 'u16': return '0'
|
|
case 'u32': return '0'
|
|
case 'u64': return '0'
|
|
case 'byte': return '0'
|
|
case 'int': return '0'
|
|
case 'rune': return '0'
|
|
case 'f32': return '0.0'
|
|
case 'f64': return '0.0'
|
|
case 'byteptr': return '0'
|
|
case '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')
|
|
}
|
|
}
|
|
|