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:
parent
de5b4f0497
commit
0ab09a57f7
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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')
|
||||||
|
24
vlib/compiler/tests/pointers_test.v
Normal file
24
vlib/compiler/tests/pointers_test.v
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user