1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

parser: multi-level pointers

This commit is contained in:
BigBlack 2019-11-11 23:43:22 +08:00 committed by Alexander Medvednikov
parent de5b4f0497
commit 0ab09a57f7
5 changed files with 66 additions and 18 deletions

View File

@ -123,6 +123,13 @@ pub fn (s string) cstr() byteptr {
return clone.str return clone.str
} }
*/ */
pub fn (s string) replace_once(rep, with string) string {
index := s.index(rep)
if index != -1 {
return s.substr(0,index) + with + s.substr(index + rep.len, s.len)
}
return s
}
pub fn (s string) replace(rep, with string) string { pub fn (s string) replace(rep, with string) string {
if s.len == 0 || rep.len == 0 { if s.len == 0 || rep.len == 0 {

View File

@ -133,9 +133,19 @@ fn (p mut Parser) name_expr() string {
// amp // amp
ptr := p.tok == .amp ptr := p.tok == .amp
deref := p.tok == .mul deref := p.tok == .mul
if ptr || deref { mut mul_nr := 0
p.next() mut deref_nr := 0
} for {
if p.tok == .amp {
mul_nr++
}else if p.tok == .mul {
deref_nr++
}else {
break
}
p.next()
}
mut name := p.lit mut name := p.lit
// Raw string (`s := r'hello \n ') // Raw string (`s := r'hello \n ')
if name == 'r' && p.peek() == .str { if name == 'r' && p.peek() == .str {
@ -176,7 +186,7 @@ fn (p mut Parser) name_expr() string {
// Variable, checked before modules, so that module shadowing is allowed: // Variable, checked before modules, so that module shadowing is allowed:
// `gg = gg.newcontext(); gg.draw_rect(...)` // `gg = gg.newcontext(); gg.draw_rect(...)`
if p.known_var_check_new_var(name) { if p.known_var_check_new_var(name) {
return p.get_var_type(name, ptr, deref) return p.get_var_type(name, ptr, deref_nr)
} }
// Module? // Module?
if p.peek() == .dot && (name == p.mod || if p.peek() == .dot && (name == p.mod ||
@ -204,7 +214,7 @@ fn (p mut Parser) name_expr() string {
} }
// re-check // re-check
if p.known_var_check_new_var(name) { if p.known_var_check_new_var(name) {
return p.get_var_type(name, ptr, deref) return p.get_var_type(name, ptr, deref_nr)
} }
// if known_type || is_c_struct_init || (p.first_pass() && p.peek() == .lcbr) { // if known_type || is_c_struct_init || (p.first_pass() && p.peek() == .lcbr) {
@ -213,10 +223,10 @@ fn (p mut Parser) name_expr() string {
// cast expression: float(5), byte(0), (*int)(ptr) etc // cast expression: float(5), byte(0), (*int)(ptr) etc
if !is_c && ( p.peek() == .lpar || (deref && p.peek() == .rpar) ) { if !is_c && ( p.peek() == .lpar || (deref && p.peek() == .rpar) ) {
if deref { if deref {
name += '*' name += '*'.repeat(deref_nr )
} }
else if ptr { else if ptr {
name += '*' name += '*'.repeat(mul_nr)
} }
p.gen('(') p.gen('(')
mut typ := name mut typ := name
@ -405,7 +415,7 @@ fn (p mut Parser) expression() string {
if typ == 'bool' { if typ == 'bool' {
p.error('operator ${p.tok.str()} not defined on bool ') p.error('operator ${p.tok.str()} not defined on bool ')
} }
is_num := typ == 'void*' || typ == 'byte*' || is_number_type(typ) is_num := typ.contains('*') || is_number_type(typ)
p.check_space(p.tok) p.check_space(p.tok)
if is_str && tok_op == .plus && !p.is_js { if is_str && tok_op == .plus && !p.is_js {
p.cgen.set_placeholder(ph, 'string_add(') p.cgen.set_placeholder(ph, 'string_add(')
@ -421,7 +431,9 @@ fn (p mut Parser) expression() string {
// Msvc errors on void* pointer arithmatic // Msvc errors on void* pointer arithmatic
// ... So cast to byte* and then do the add // ... So cast to byte* and then do the add
p.cgen.set_placeholder(ph, '(byte*)') p.cgen.set_placeholder(ph, '(byte*)')
} }else if typ.contains('*') {
p.cgen.set_placeholder(ph, '($typ)')
}
p.gen(tok_op.str()) p.gen(tok_op.str())
} }
// Vec + Vec // Vec + Vec

View File

@ -1461,7 +1461,7 @@ fn (p mut Parser) get_struct_type(name_ string, is_c bool, is_ptr bool) string {
return p.struct_init(name) return p.struct_init(name)
} }
fn (p mut Parser) get_var_type(name string, is_ptr bool, is_deref bool) string { fn (p mut Parser) get_var_type(name string, is_ptr bool, deref_nr int) string {
v := p.find_var_check_new_var(name) or { return "" } v := p.find_var_check_new_var(name) or { return "" }
if name == '_' { if name == '_' {
p.error('cannot use `_` as value') p.error('cannot use `_` as value')
@ -1469,9 +1469,11 @@ fn (p mut Parser) get_var_type(name string, is_ptr bool, is_deref bool) string {
if is_ptr { if is_ptr {
p.gen('&') p.gen('&')
} }
else if is_deref { else if deref_nr > 0 {
p.gen('*') for _ in 0..deref_nr {
} p.gen('*')
}
}
if p.pref.autofree && v.typ == 'string' && v.is_arg && if p.pref.autofree && v.typ == 'string' && v.is_arg &&
p.assigned_type == 'string' { p.assigned_type == 'string' {
p.warn('setting moved ' + v.typ) p.warn('setting moved ' + v.typ)
@ -1479,7 +1481,7 @@ fn (p mut Parser) get_var_type(name string, is_ptr bool, is_deref bool) string {
} }
mut typ := p.var_expr(v) mut typ := p.var_expr(v)
// *var // *var
if is_deref { if deref_nr > 0 {
/* /*
if !p.inside_unsafe { if !p.inside_unsafe {
p.error('dereferencing can only be done inside an `unsafe` block') p.error('dereferencing can only be done inside an `unsafe` block')
@ -1489,8 +1491,11 @@ fn (p mut Parser) get_var_type(name string, is_ptr bool, is_deref bool) string {
println('name="$name", t=$v.typ') println('name="$name", t=$v.typ')
p.error('dereferencing requires a pointer, but got `$typ`') p.error('dereferencing requires a pointer, but got `$typ`')
} }
typ = typ.replace('ptr', '')// TODO for _ in 0..deref_nr {
typ = typ.replace('*', '')// TODO typ = typ.replace_once('ptr', '')// TODO
typ = typ.replace_once('*', '')// TODO
}
} }
// &var // &var
else if is_ptr { else if is_ptr {

View File

@ -334,7 +334,7 @@ fn (table &Table) known_type(typ_ string) bool {
mut typ := typ_ mut typ := typ_
// 'byte*' => look up 'byte', but don't mess up fns // 'byte*' => look up 'byte', but don't mess up fns
if typ.ends_with('*') && !typ.contains(' ') { if typ.ends_with('*') && !typ.contains(' ') {
typ = typ[..typ.len - 1] typ = typ.replace('*', '')
} }
t := table.typesmap[typ] t := table.typesmap[typ]
return t.name.len > 0 && !t.is_placeholder return t.name.len > 0 && !t.is_placeholder
@ -558,7 +558,7 @@ fn (p &Parser) find_type(name string) Type {
fn (t &Table) find_type(name_ string) Type { fn (t &Table) find_type(name_ string) Type {
mut name := name_ mut name := name_
if name.ends_with('*') && !name.contains(' ') { if name.ends_with('*') && !name.contains(' ') {
name = name[..name.len - 1] name = name.replace('*', '')
} }
if !(name in t.typesmap) { if !(name in t.typesmap) {
//println('ret Type') //println('ret Type')

View File

@ -0,0 +1,24 @@
fn test_pointer_arithmetic() {
arr := [1,2,3,4]
unsafe {
mut parr := *int(arr.data)
parr += 1
assert 2 == *parr
}
}
fn test_multi_level_pointer_dereferencing() {
n := 100
pn := &n
ppn := &pn
unsafe {
mut pppn := &ppn
***pppn = 300
pppa := ***int(pppn)
assert 300 == ***pppa
}
assert n == 300 // updated by the unsafe pointer manipulation
}