compiler: map[string]pointer, ?pointer, fix []pointer

pull/3182/head
れもん 2019-12-22 07:44:16 +09:00 committed by Alexander Medvednikov
parent b76227b781
commit 28ecfb231d
14 changed files with 98 additions and 48 deletions

View File

@ -4,7 +4,7 @@ const (
)
fn test_pointer() {
mut arr := []*int
mut arr := []&int
a := 1
b := 2
c := 3
@ -14,6 +14,10 @@ fn test_pointer() {
assert *arr[0] == 1
arr[1] = &c
assert *arr[1] == 3
mut d_arr := [arr] // [][]&int
d_arr << arr
assert *d_arr[0][1] == 3
assert *d_arr[1][0] == 1
}
fn test_ints() {

View File

@ -132,13 +132,13 @@ fn test_various_map_value() {
m13['test'] = rune(0)
assert m13['test'] == rune(0)
//mut m14 := map[string]voidptr
//m14['test'] = voidptr(0)
//assert m14['test'] == voidptr(0)
mut m14 := map[string]voidptr
m14['test'] = voidptr(0)
assert m14['test'] == voidptr(0)
//mut m15 := map[string]byteptr
//m15['test'] = byteptr(0)
//assert m15['test'] == byteptr(0)
mut m15 := map[string]byteptr
m15['test'] = byteptr(0)
assert m15['test'] == byteptr(0)
mut m16 := map[string]i64
m16['test'] = i64(0)
@ -147,6 +147,10 @@ fn test_various_map_value() {
mut m17 := map[string]u64
m17['test'] = u64(0)
assert m17['test'] == u64(0)
mut m18 := map[string]&int
m18['test'] = &int(0)
assert m18['test'] == &int(0)
}

View File

@ -191,7 +191,7 @@ fn (p mut Parser) print_error_context() {
fn normalized_error(s string) string {
// Print `[]int` instead of `array_int` in errors
mut res := s.replace('array_', '[]').replace('__', '.').replace('Option_', '?').replace('main.', '')
mut res := s.replace('array_', '[]').replace('__', '.').replace('Option_', '?').replace('main.', '').replace('ptr_', '&')
if res.contains('_V_MulRet_') {
res = res.replace('_V_MulRet_', '(').replace('_V_', ', ')
res = res[..res.len - 1] + ')"'

View File

@ -321,7 +321,7 @@ fn (p mut Parser) gen_array_str(typ Type) {
is_public: true
receiver_typ: typ.name
})
elm_type := typ.name[6..]
elm_type := parse_pointer(typ.name[6..])
elm_type2 := p.table.find_type(elm_type)
is_array := elm_type.starts_with('array_')
if is_array {
@ -416,7 +416,7 @@ fn (p mut Parser) gen_array_filter(str_typ string, method_ph int) {
}
array_int b = tmp2;
*/
val_type := str_typ[6..]
val_type := parse_pointer(str_typ[6..])
p.open_scope()
p.register_var(Var{
name: 'it'
@ -456,7 +456,7 @@ fn (p mut Parser) gen_array_map(str_typ string, method_ph int) string {
}
array_int b = tmp2;
*/
val_type := str_typ[6..]
val_type := parse_pointer(str_typ[6..])
p.open_scope()
p.register_var(Var{
name: 'it'
@ -477,7 +477,7 @@ fn (p mut Parser) gen_array_map(str_typ string, method_ph int) string {
p.gen(tmp) // TODO why does this `gen()` work?
p.check(.rpar)
p.close_scope()
return 'array_' + map_type
return 'array_' + stringify_pointer(map_type)
}
fn (p mut Parser) comptime_if_block(name string) {

View File

@ -413,7 +413,7 @@ fn (p mut Parser) name_expr() string {
f.typ = p.gen_handle_option_or_else(f.typ, '', fn_call_ph)
}
else if !p.is_var_decl && !is_or_else && !p.inside_return_expr && f.typ.starts_with('Option_') {
opt_type := f.typ[7..]
opt_type := f.typ[7..].replace('ptr_', '&')
p.error('unhandled option type: `?$opt_type`')
}
// dot after a function call: `get_user().age`
@ -450,7 +450,7 @@ fn (p mut Parser) expression() string {
// a << 7 => int tmp = 7; array_push(&a, &tmp);
// _PUSH(&a, expression(), tmp, string)
tmp := p.get_tmp()
tmp_typ := typ[6..].replace('_ptr', '*') // skip "array_"
tmp_typ := parse_pointer(typ[6..]) // skip "array_"
p.check_space(.left_shift)
// Get the value we are pushing
p.gen(', (')

View File

@ -1353,7 +1353,7 @@ fn (p mut Parser) extract_type_inst(f &Fn, args_ []string) TypeInst {
// replace a generic type using TypeInst
fn replace_generic_type(gen_type string, ti &TypeInst) string {
mut typ := gen_type.replace('map_', '').replace('varg_', '').trim_right('*')
mut typ := gen_type.replace('map_', '').replace('varg_', '').trim_right('*').replace('ptr_', '')
for typ.starts_with('array_') {
typ = typ[6..]
}

View File

@ -92,12 +92,12 @@ fn (p mut Parser) for_st() {
p.gen_for_varg_header(i, expr, typ, val)
}
else if is_arr {
typ = typ[6..].replace('_ptr', '*')
typ = parse_pointer(typ[6..])
p.gen_for_header(i, tmp, typ, val)
}
else if is_map {
i_var_type = 'string'
typ = typ[4..]
typ = parse_pointer(typ[4..])
p.gen_for_map_header(i, tmp, typ, val, typ)
}
else if is_str {
@ -178,7 +178,7 @@ fn (p mut Parser) for_st() {
p.gen_for_range_header(i, range_end, tmp, typ, val)
}
else if is_arr {
typ = typ[6..].replace('_ptr', '*') // all after `array_`
typ = parse_pointer(typ[6..]) // all after `array_`
p.gen_for_header(i, tmp, typ, val)
}
else if is_str {

View File

@ -96,7 +96,7 @@ fn (p mut Parser) gen_handle_option_or_else(_typ, name string, fn_call_ph int) s
is_assign := name.len > 0
tmp := p.get_tmp()
p.cgen.set_placeholder(fn_call_ph, '$typ $tmp = ')
typ = typ[7..]
typ = parse_pointer(typ[7..])
p.genln(';')
or_tok_idx := p.token_idx
p.check(.key_orelse)
@ -324,7 +324,7 @@ fn (p mut Parser) gen_method_call(receiver &Var, receiver_type string, cgen_name
if ftyp == 'void*' {
if receiver_type.starts_with('array_') {
// array_int => int
cast = receiver_type.all_after('array_')
cast = parse_pointer(receiver_type.all_after('array_'))
cast = '*($cast*) '
}
else {
@ -611,7 +611,7 @@ fn (p mut Parser) cast(typ string) {
fn type_default(typ string) string {
if typ.starts_with('array_') {
return 'new_array(0, 1, sizeof( ${typ[6..]} ))'
return 'new_array(0, 1, sizeof( ${parse_pointer(typ[6..])} ))'
}
// Always set pointers to 0
if typ.ends_with('*') {

View File

@ -102,7 +102,7 @@ fn (p mut Parser) get_type2() Type {
p.error('maps only support string keys for now')
}
p.check(.rsbr)
val_type := p.get_type() // p.check_name()
val_type := stringify_pointer(p.get_type()) // p.check_name()
typ = 'map_$val_type'
p.register_map(typ)
return Type{
@ -190,6 +190,7 @@ fn (p mut Parser) get_type2() Type {
if arr_level > 0 {
// p.log('ARR TYPE="$typ" run=$p.pass')
// We come across "[]User" etc ?
typ = stringify_pointer(typ)
for i := 0; i < arr_level; i++ {
typ = 'array_$typ'
}
@ -197,6 +198,7 @@ fn (p mut Parser) get_type2() Type {
}
p.next()
if is_question {
typ = stringify_pointer(typ)
typ = 'Option_$typ'
p.table.register_type_with_parent(typ, 'Option')
}
@ -223,3 +225,21 @@ fn (p mut Parser) get_type2() Type {
}
}
fn parse_pointer(_typ string) string {
if !_typ.starts_with('ptr_') {
return _typ
}
mut typ := _typ.clone()
for typ.starts_with('ptr_') {
typ = typ[4..] + '*'
}
return typ
}
fn stringify_pointer(typ string) string {
if !typ.ends_with('*') {
return typ
}
count := typ.count('*')
return 'ptr_'.repeat(count) + typ.trim_right('*')
}

View File

@ -215,7 +215,7 @@ fn (p mut Parser) if_statement(is_expr bool, elif_depth int) string {
p.error('`if x := opt() {` syntax requires a function that returns an optional value')
}
p.is_var_decl = false
typ := option_type[7..]
typ := parse_pointer(option_type[7..])
// Option_User tmp = get_user(1);
// if (tmp.ok) {
// User user = *(User*)tmp.data;

View File

@ -1019,7 +1019,7 @@ fn (p mut Parser) get_type() string {
}
p.check(.rsbr)
val_type := p.get_type() // p.check_name()
typ = 'map_$val_type'
typ = 'map_${stringify_pointer(val_type)}'
p.register_map(typ)
return typ
}
@ -1123,13 +1123,13 @@ fn (p mut Parser) get_type() string {
// p.log('ARR TYPE="$typ" run=$p.pass')
// We come across "[]User" etc ?
for i := 0; i < arr_level; i++ {
typ = 'array_$typ'
typ = 'array_${stringify_pointer(typ)}'
}
p.register_array(typ)
}
p.next()
if is_question {
typ = 'Option_$typ'
typ = 'Option_${stringify_pointer(typ)}'
p.table.register_type_with_parent(typ, 'Option')
}
// Because the code uses * to see if it's a pointer
@ -1511,13 +1511,13 @@ fn ($v.name mut $v.typ) ${p.cur_fn.name}(...) {
p.error_with_token_index('${fn_name}() $err_used_as_value', p.token_idx - 2)
}
// Allow `num = 4` where `num` is an `?int`
if p.assigned_type.starts_with('Option_') && expr_type == p.assigned_type['Option_'.len..] {
if p.assigned_type.starts_with('Option_') && expr_type == parse_pointer(p.assigned_type['Option_'.len..]) {
expr := p.cgen.cur_line[pos..]
left := p.cgen.cur_line[..pos]
typ := expr_type.replace('Option_', '')
typ := parse_pointer(expr_type.replace('Option_', ''))
p.cgen.resetln(left + 'opt_ok(($typ[]){ $expr }, sizeof($typ))')
}
else if expr_type.starts_with('Option_') && p.assigned_type == expr_type['Option_'.len..] && p.tok == .key_orelse {
else if expr_type.starts_with('Option_') && p.assigned_type == parse_pointer(expr_type['Option_'.len..]) && p.tok == .key_orelse {
line := p.cgen.cur_line
vname := line[..pos].replace('=', '') // TODO cgen line hack
if idx:=line.index('='){
@ -1976,7 +1976,7 @@ fn (p mut Parser) dot(str_typ_ string, method_ph int) string {
}
if !typ.is_c && !p.is_c_fn_call && !has_field && !has_method && !p.first_pass() {
if typ.name.starts_with('Option_') {
opt_type := typ.name[7..]
opt_type := typ.name[7..].replace('ptr_', '&')
p.error('unhandled option type: `?$opt_type`')
}
// println('error in dot():')
@ -2064,7 +2064,7 @@ pub:
method.typ = p.gen_handle_option_or_else(method.typ, '', method_ph)
}
else if !p.is_var_decl && !is_or_else && !p.inside_return_expr && method.typ.starts_with('Option_') {
opt_type := method.typ[7..]
opt_type := method.typ[7..].replace('ptr_', '&')
p.error('unhandled option type: `?$opt_type`')
}
// Methods returning `array` should return `array_string` etc
@ -2073,7 +2073,7 @@ pub:
}
// Array methods returning `voidptr` (like `last()`) should return element type
if method.typ == 'void*' && typ.name.starts_with('array_') {
return typ.name[6..]
return parse_pointer(typ.name[6..])
}
// if false && p.tok == .lsbr {
// if is_indexer {
@ -2177,7 +2177,7 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
}
if is_arr {
if is_arr0 {
typ = typ[6..].replace('_ptr', '*')
typ = parse_pointer(typ[6..])
}
p.gen_array_at(typ, is_arr0, fn_ph)
}
@ -2187,6 +2187,7 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
// can only do that later once we know whether there's an "=" or not
if is_map {
typ = typ.replace('map_', '')
typ = parse_pointer(typ)
if typ == 'map' {
typ = 'void*'
}
@ -2212,7 +2213,7 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
}
if p.tok == .dotdot {
if is_arr {
typ = 'array_' + typ
typ = 'array_' + stringify_pointer(typ)
}
else if is_str {
typ = 'string'
@ -2292,7 +2293,7 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
// }
// `m[key]`. no =, just a getter
else if (is_map || is_arr || (is_str && !p.builtin_mod)) && is_indexer {
typ = typ.replace('_ptr', '*')
typ = parse_pointer(typ)
p.index_get(typ, fn_ph, IndexConfig{
is_arr: is_arr
is_map: is_map
@ -2349,7 +2350,7 @@ fn (p mut Parser) indot_expr() string {
if !is_arr && !is_map {
p.error('`in` requires an array/map')
}
if is_arr && arr_typ[6..] != typ {
if is_arr && parse_pointer(arr_typ[6..]) != typ {
p.error('bad element type: `$typ` in `$arr_typ`')
}
if is_map && typ != 'string' {
@ -2471,7 +2472,7 @@ fn (p mut Parser) map_init() string {
p.fgen_nl()
}
p.gen('new_map_init($i, sizeof($val_type), ' + '(string[$i]){ $keys_gen }, ($val_type [$i]){ $vals_gen } )')
typ := 'map_$val_type'
typ := 'map_${stringify_pointer(val_type)}'
p.register_map(typ)
return typ
}
@ -2486,7 +2487,7 @@ fn (p mut Parser) map_init() string {
// if !p.table.known_type(val_type) {
// p.error('map init unknown type "$val_type"')
// }
typ := 'map_$val_type'
typ := 'map_${stringify_pointer(val_type)}'
p.register_map(typ)
p.gen('new_map(1, sizeof($val_type))')
if p.tok == .lcbr {
@ -2593,16 +2594,17 @@ fn (p mut Parser) array_init() string {
p.check(.rsbr)
// type after `]`? (e.g. "[]string")
exp_array := p.expected_type.starts_with('array_')
if p.tok != .name && p.tok != .mul && p.tok != .lsbr && i == 0 && !exp_array {
if p.tok != .name && p.tok != .mul && p.tok != .lsbr && p.tok != .amp && i == 0 && !exp_array {
p.error('specify array type: `[]typ` instead of `[]`')
}
if i == 0 && (p.tok == .name || p.tok == .mul) && p.tokens[p.token_idx - 2].line_nr == p.tokens[p.token_idx - 1].line_nr {
if i == 0 && (p.tok == .name || p.tok == .mul || p.tok == .amp) && p.tokens[p.token_idx - 2].line_nr == p.tokens[p.token_idx - 1].line_nr {
// TODO
// vals.len == 0 {
if exp_array {
p.error('no need to specify the full array type here, use `[]` instead of `[]${p.expected_type[6..]}`')
type_expected := p.expected_type[6..].replace('ptr_', '&')
p.error('no need to specify the full array type here, use `[]` instead of `[]$type_expected`')
}
typ = p.get_type().replace('*', '_ptr')
typ = p.get_type()
}
else if exp_array && i == 0 {
// allow `known_array = []`
@ -2633,9 +2635,9 @@ fn (p mut Parser) array_init() string {
// if ptr {
// typ += '_ptr"
// }
real := typ.replace('_ptr', '*')
real := parse_pointer(typ)
p.gen_array_init(real, no_alloc, new_arr_ph, i)
typ = 'array_$typ'
typ = 'array_${stringify_pointer(typ)}'
p.register_array(typ)
return typ
}
@ -2749,10 +2751,10 @@ fn (p mut Parser) return_st() {
// Automatically wrap an object inside an option if the function
// returns an option:
// `return val` => `return opt_ok(val)`
if p.cur_fn.typ.ends_with(expr_type) && !is_none && p.cur_fn.typ.starts_with('Option_') {
if p.cur_fn.typ.ends_with(stringify_pointer(expr_type)) && !is_none && p.cur_fn.typ.starts_with('Option_') {
tmp := p.get_tmp()
ret := p.cgen.cur_line[ph..]
typ := expr_type.replace('Option_', '')
typ := parse_pointer(expr_type.replace('Option_', ''))
p.cgen.resetln('$expr_type $tmp = OPTION_CAST($expr_type)($ret);')
p.genln(deferred_text)
p.gen('return opt_ok(&$tmp, sizeof($typ))')

View File

@ -428,7 +428,7 @@ fn (p mut Parser) struct_init(typ_ string) string {
// init map fields
if field_typ.starts_with('map_') {
p.gen_struct_field_init(sanitized_name)
p.gen_empty_map(field_typ[4..])
p.gen_empty_map(parse_pointer(field_typ[4..]))
inited_fields << sanitized_name
if i != t.fields.len - 1 {
p.gen(',')

View File

@ -679,7 +679,7 @@ fn (p mut Parser) check_types2(got_, expected_ string, throw bool) bool {
return true
}
// Expected type "Option_os__File", got "os__File"
if expected.starts_with('Option_') && expected.ends_with(got) {
if expected.starts_with('Option_') && expected.ends_with(stringify_pointer(got)) {
return true
}
// NsColor* return 0

View File

@ -124,3 +124,23 @@ fn test_opt_field() {
val := t.opt or { return }
assert val == 5
}
fn opt_ptr(a &int) ?&int {
if isnil(a) {
return none
}
return a
}
fn test_opt_ptr() {
a := 3
r1 := opt_ptr(&a) or {
&int(0)
}
assert r1 == &a
r2 := opt_ptr(&int(0)) or {
return
}
println('`$r2` should be none')
assert false
}