2019-10-13 15:37:43 +02:00
|
|
|
module compiler
|
2019-09-14 22:48:30 +02:00
|
|
|
|
|
|
|
import strings
|
|
|
|
|
|
|
|
const (
|
|
|
|
dot_ptr = '.'
|
|
|
|
)
|
|
|
|
|
|
|
|
fn (p mut Parser) gen_var_decl(name string, is_static bool) string {
|
|
|
|
p.gen('var $name /* typ */ = ')
|
2019-09-30 16:11:12 +02:00
|
|
|
mut typ := p.bool_expression()
|
2019-10-27 08:03:15 +01:00
|
|
|
if typ.starts_with('...') { typ = typ[3..] }
|
2019-09-14 22:48:30 +02:00
|
|
|
or_else := p.tok == .key_orelse
|
|
|
|
if or_else {
|
2019-10-31 11:49:57 +01:00
|
|
|
// return p.gen_handle_option_or_else(typ, name, pos)
|
2019-09-14 22:48:30 +02:00
|
|
|
}
|
|
|
|
return typ
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (p mut Parser) gen_fn_decl(f Fn, typ, _str_args string) {
|
|
|
|
mut str_args := ''
|
|
|
|
for i, arg in f.args {
|
2019-09-18 23:03:54 +02:00
|
|
|
str_args += ' /** @type { $arg.typ } **/ ' + arg.name
|
2019-09-14 22:48:30 +02:00
|
|
|
if i < f.args.len - 1 {
|
|
|
|
str_args += ', '
|
|
|
|
}
|
|
|
|
}
|
|
|
|
name := p.table.fn_gen_name(f)
|
|
|
|
if f.is_method {
|
2019-10-25 21:09:23 +02:00
|
|
|
//p.genln('\n${f.receiver_typ}.prototype.${name} = function($str_args) {')
|
|
|
|
p.genln('function ${f.receiver_typ}_$name($str_args) {')
|
2019-09-14 22:48:30 +02:00
|
|
|
} else {
|
2019-09-18 23:03:54 +02:00
|
|
|
p.genln('/** @return { $typ } **/\nfunction $name($str_args) {')
|
2019-09-14 22:48:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-25 13:53:44 +02:00
|
|
|
fn (p mut Parser) gen_blank_identifier_assign() {
|
2019-10-01 14:40:11 +02:00
|
|
|
assign_error_tok_idx := p.token_idx
|
2019-09-26 13:09:59 +02:00
|
|
|
p.check_name()
|
|
|
|
p.check_space(.assign)
|
2019-10-01 14:40:11 +02:00
|
|
|
is_indexer := p.peek() == .lsbr
|
2019-11-04 12:35:10 +01:00
|
|
|
is_fn_call, next_expr := p.is_expr_fn_call(p.token_idx)
|
2019-10-18 23:00:47 +02:00
|
|
|
p.bool_expression()
|
2019-10-01 14:40:11 +02:00
|
|
|
if !is_indexer && !is_fn_call {
|
2019-10-20 11:24:12 +02:00
|
|
|
p.error_with_token_index('assigning `$next_expr` to `_` is redundant', assign_error_tok_idx)
|
2019-10-01 14:40:11 +02:00
|
|
|
}
|
2019-09-25 13:53:44 +02:00
|
|
|
or_else := p.tok == .key_orelse
|
|
|
|
if or_else {
|
2019-10-31 11:49:57 +01:00
|
|
|
// return p.gen_handle_option_or_else(typ, '', pos)
|
2019-09-25 13:53:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-31 11:49:57 +01:00
|
|
|
// TODO: optionals
|
|
|
|
fn (p mut Parser) gen_handle_option_or_else(_typ, name string, fn_call_ph int) string {
|
|
|
|
return _typ
|
|
|
|
}
|
|
|
|
|
2019-09-14 22:48:30 +02:00
|
|
|
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
|
|
|
|
}
|
2019-09-18 23:03:54 +02:00
|
|
|
sb.write('\n/**\n')
|
|
|
|
sb.write('* @typedef { object } $t.name' + 'Type\n')
|
2019-09-14 22:48:30 +02:00
|
|
|
for field in t.fields {
|
2019-09-18 23:03:54 +02:00
|
|
|
sb.writeln('* @property { $field.typ' + '= } $field.name')
|
2019-09-14 22:48:30 +02:00
|
|
|
}
|
2019-09-18 23:03:54 +02:00
|
|
|
sb.writeln('**/\n')
|
|
|
|
sb.writeln('/** @type { function & $t.name' + 'Type } **/')
|
|
|
|
sb.writeln('var $t.name = function() {}')
|
2019-09-14 22:48:30 +02:00
|
|
|
}
|
|
|
|
return sb.str()
|
|
|
|
}
|
|
|
|
|
2019-10-26 20:58:26 +02:00
|
|
|
fn (p mut Parser) index_get(typ string, fn_ph int, cfg IndexConfig) {
|
2019-09-14 22:48:30 +02:00
|
|
|
p.cgen.cur_line = p.cgen.cur_line.replace(',', '[') + ']'
|
|
|
|
}
|
|
|
|
|
2019-09-17 12:37:25 +02:00
|
|
|
fn (table &Table) fn_gen_name(f &Fn) string {
|
2019-09-14 22:48:30 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-10-25 20:57:32 +02:00
|
|
|
//fn (p mut Parser) gen_method_call(receiver &Var, receiver_type string,
|
|
|
|
//ftyp string, cgen_name string, receiver Var,method_ph int)
|
|
|
|
fn (p mut Parser) gen_method_call(receiver &Var, receiver_type string,
|
|
|
|
cgen_name string, ftyp string, method_ph int)
|
2019-10-25 16:54:34 +02:00
|
|
|
{
|
2019-10-25 20:57:32 +02:00
|
|
|
// TODO js methods have been broken from the start
|
|
|
|
|
2019-09-14 22:48:30 +02:00
|
|
|
//mut cgen_name := p.table.fn_gen_name(f)
|
|
|
|
//mut method_call := cgen_name + '('
|
2019-10-25 21:09:23 +02:00
|
|
|
//p.gen('/*2*/.' + cgen_name.all_after('_') + '(')
|
|
|
|
t := receiver_type.replace('*', '')
|
|
|
|
p.cgen.set_placeholder(method_ph, '${t}_$cgen_name(')
|
2019-09-14 22:48:30 +02:00
|
|
|
//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++) {')
|
2019-09-28 18:53:56 +02:00
|
|
|
if val == '_' { return }
|
2019-09-14 22:48:30 +02:00
|
|
|
p.genln('var $val = $tmp [$i];')
|
|
|
|
}
|
|
|
|
|
2019-09-17 21:16:16 +02:00
|
|
|
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++) {')
|
2019-09-28 18:53:56 +02:00
|
|
|
if val == '_' { return }
|
2019-09-17 21:16:16 +02:00
|
|
|
p.genln('var /*$var_type*/ $val = $i;')
|
|
|
|
}
|
|
|
|
|
2019-09-14 22:48:30 +02:00
|
|
|
fn (p mut Parser) gen_for_str_header(i, tmp, var_typ, val string) {
|
|
|
|
p.genln('for (var $i = 0; $i < $tmp .length; $i ++) {')
|
2019-09-28 18:53:56 +02:00
|
|
|
if val == '_' { return }
|
2019-09-14 22:48:30 +02:00
|
|
|
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) {')
|
2019-09-28 18:53:56 +02:00
|
|
|
if val == '_' { return }
|
2019-09-14 22:48:30 +02:00
|
|
|
p.genln('var $val = $tmp[$i];')
|
|
|
|
}
|
|
|
|
|
2019-09-30 16:11:12 +02:00
|
|
|
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];')
|
|
|
|
}
|
|
|
|
|
2019-09-14 22:48:30 +02:00
|
|
|
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) {
|
2019-10-27 08:03:15 +01:00
|
|
|
mut val := p.cgen.cur_line[assign_pos..]
|
|
|
|
p.cgen.resetln(p.cgen.cur_line[..assign_pos])
|
2019-09-14 22:48:30 +02:00
|
|
|
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
|
2019-12-21 01:53:58 +01:00
|
|
|
fn (p mut Parser) gen_struct_init(typ string, t &Type) bool {
|
2019-09-14 22:48:30 +02:00
|
|
|
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
|
2019-10-25 10:24:34 +02:00
|
|
|
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'}
|
2019-09-14 22:48:30 +02:00
|
|
|
}
|
|
|
|
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')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|