mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
compiler: map[string]pointer, ?pointer, fix []pointer
This commit is contained in:
parent
b76227b781
commit
28ecfb231d
@ -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() {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
@ -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] + ')"'
|
||||
|
@ -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) {
|
||||
|
@ -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(', (')
|
||||
|
@ -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..]
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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('*') {
|
||||
|
@ -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('*')
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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))')
|
||||
|
@ -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(',')
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user