Skip to content

Commit

Permalink
fix restrict ptr translate (#168)
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp authored Feb 11, 2024
1 parent a64056c commit 23fe665
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 19 deletions.
70 changes: 53 additions & 17 deletions src/c2v.v
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ const builtin_fn_names = ['fopen', 'puts', 'fflush', 'printf', 'memset', 'atoi',
'isspace', 'strncmp', 'malloc', 'close', 'open', 'lseek', 'fseek', 'fgets', 'rewind', 'write',
'calloc', 'setenv', 'gets', 'abs', 'sqrt', 'erfl', 'fprintf', 'snprintf', 'exit', '__stderrp',
'fwrite', 'scanf', 'sscanf', 'strrchr', 'strchr', 'div', 'free', 'memcmp', 'memmove', 'vsnprintf',
'rintf', 'rint', 'bsearch', 'qsort']
'rintf', 'rint', 'bsearch', 'qsort', '__stdinp', '__stdoutp', '__stderrp']

const c_known_fn_names = ['getline']

const c_known_var_names = ['stdin', 'stdout', 'stderr', '__stdinp', '__stdoutp', '__stderrp']

const builtin_type_names = ['ldiv_t', '__float2', '__double2', 'exception', 'double_t']

Expand Down Expand Up @@ -79,6 +83,7 @@ mut:
enum_vals map[string][]string // enum_vals['Color'] = ['green', 'blue'], for converting C globals to enum values
structs map[string]Struct // for correct `Foo{field:..., field2:...}` (implicit value init expr is 0, so un-initied fields are just skipped with 0s)
fns []string // to avoid dups
extern_fns []string // extern C fns
outv string
cur_file string
consts []string
Expand Down Expand Up @@ -412,6 +417,7 @@ fn (mut c C2V) fn_decl(mut node Node, gen_types string) {
} else {
typ = convert_type(typ).name
}

if typ.contains('...') {
c.gen('F')
}
Expand Down Expand Up @@ -487,7 +493,12 @@ fn (mut c C2V) fn_decl(mut node Node, gen_types string) {
c.genln("[c:'${name}']")
}
name = lower
c.genln('fn ${name}(${str_args}) ${typ}')
if name in c_known_fn_names {
c.genln('fn C.${name}(${str_args}) ${typ}')
c.extern_fns << name
} else {
c.genln('fn ${name}(${str_args}) ${typ}')
}
}
c.genln('')
vprintln('END OF FN DECL ast line=${c.line_i}')
Expand All @@ -501,20 +512,37 @@ fn (c &C2V) fn_params(mut node Node) []string {
println(add_place_data_to_error(err))
continue
}

arg_typ := convert_type(param.ast_type.qualified)

mut param_name := param.name
mut arg_typ_name := arg_typ.name

if arg_typ.name.contains('...') {
vprintln('vararg: ' + arg_typ.name)
} else if arg_typ.name.ends_with('*restrict') {
arg_typ_name = fix_restrict_name(arg_typ_name)
arg_typ_name = convert_type(arg_typ_name.trim_right('restrict')).name
}
mut param_name := filter_name(param.name).to_lower().all_after_last('c.')
param_name = filter_name(param_name, false).to_lower().all_after_last('c.')
if param_name == '' {
param_name = 'arg${i}'
}
str_args << '${param_name} ${arg_typ.name}'
str_args << '${param_name} ${arg_typ_name}'
}
return str_args
}

// handles '__linep char **restrict' param stuff
fn fix_restrict_name(arg_typ_name string) string {
mut typ_name := arg_typ_name

if typ_name.replace(' ', '').contains('Char*') || typ_name.replace(' ', '').contains('Size_t') {
typ_name = typ_name.to_lower()
}

return typ_name
}

// converts a C type to a V type
fn convert_type(typ_ string) Type {
mut typ := typ_
Expand Down Expand Up @@ -691,7 +719,7 @@ fn convert_type(typ_ string) Type {
'size_t' {
'usize'
}
'ptrdiff_t' {
'ptrdiff_t', 'ssize_t', '__ssize_t' {
'isize'
}
'boolean', '_Bool', 'Bool', 'bool (int)', 'bool' {
Expand Down Expand Up @@ -788,7 +816,7 @@ fn (mut c C2V) enum_decl(mut node Node) {
}
mut vals := c.enum_vals[enum_name]
for i, mut child in node.inner {
name := filter_name(child.name.to_lower())
name := filter_name(child.name.to_lower(), false)
vals << name
mut has_anon_generated := false
// empty enum means it's just a list of #define'ed consts
Expand Down Expand Up @@ -1305,7 +1333,7 @@ fn (mut c C2V) var_decl(mut decl_stmt Node) {
// cinit means we have an initialization together with var declaration:
// `int a = 0;`
cinit := var_decl.initialization_type == 'c'
name := filter_name(var_decl.name).to_lower()
name := filter_name(var_decl.name, true).to_lower()
typ_ := convert_type(var_decl.ast_type.qualified)
if typ_.is_static {
c.gen('static ')
Expand Down Expand Up @@ -1346,7 +1374,7 @@ fn (mut c C2V) var_decl(mut decl_stmt Node) {
def = '0'
} else if typ == 'i64' {
def = 'i64(0)'
} else if typ in ['ptrdiff_t', 'isize'] {
} else if typ in ['ptrdiff_t', 'isize', 'ssize_t'] {
def = 'isize(0)'
} else if typ == 'bool' {
def = 'false'
Expand Down Expand Up @@ -1402,7 +1430,7 @@ fn (mut c C2V) global_var_decl(mut var_decl Node) {
vprintln('\nglobal name=${var_decl.name} typ=${var_decl.ast_type.qualified}')
vprintln(var_decl.str())

name := filter_name(var_decl.name)
name := filter_name(var_decl.name, true)

if var_decl.ast_type.qualified.starts_with('[]') {
return
Expand Down Expand Up @@ -1537,7 +1565,7 @@ unique name')

// `"red"` => `"Color"`
fn (c &C2V) enum_val_to_enum_name(enum_val string) string {
filtered_enum_val := filter_name(enum_val)
filtered_enum_val := filter_name(enum_val, false)
for enum_name, vals in c.enum_vals {
if filtered_enum_val in vals {
return enum_name
Expand Down Expand Up @@ -1722,9 +1750,9 @@ fn (mut c C2V) expr(_node &Node) string {
c.expr(expr)
field = field.replace('->', '')
if field.starts_with('.') {
field = filter_name(field[1..])
field = filter_name(field[1..], false)
} else {
field = filter_name(field)
field = filter_name(field, false)
}
c.gen('.${field}')
}
Expand Down Expand Up @@ -1887,6 +1915,9 @@ fn (mut c C2V) name_expr(node &Node) {
// vals:
// ["int", "EnumConstant", "MT_SPAWNFIRE", "int"]
is_enum_val := node.ref_declaration.kind == .enum_constant_decl
is_func_call := node.ref_declaration.kind == .function_decl

mut name := node.ref_declaration.name

if is_enum_val {
enum_val := node.ref_declaration.name.to_lower()
Expand Down Expand Up @@ -1914,10 +1945,12 @@ fn (mut c C2V) name_expr(node &Node) {

c.gen('.')
}
} else if is_func_call {
if name in c.extern_fns {
name = 'C.${name}'
}
}

mut name := node.ref_declaration.name

if name !in c.consts && name !in c.globals {
// Functions and variables are all lowercase in V
name = name.to_lower()
Expand All @@ -1926,7 +1959,7 @@ fn (mut c C2V) name_expr(node &Node) {
}
}

c.gen(filter_name(name))
c.gen(filter_name(name, node.ref_declaration.kind == .var_decl))
if is_enum_val && c.inside_array_index {
c.gen(')')
}
Expand Down Expand Up @@ -2008,11 +2041,14 @@ fn (mut c C2V) init_list_expr(mut node Node) {
}
}

fn filter_name(name string) string {
fn filter_name(name string, ignore_builtin bool) string {
if name in v_keywords {
return '${name}_'
}
if name in builtin_fn_names {
if ignore_builtin && name !in c_known_var_names {
return name
}
return 'C.' + name
}
if name == 'FILE' {
Expand Down
4 changes: 2 additions & 2 deletions src/struct.v
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn (mut c C2V) record_decl(node &Node) {
continue
}
field_type := convert_type(field.ast_type.qualified)
field_name := filter_name(field.name).uncapitalize()
field_name := filter_name(field.name, false).uncapitalize()
mut field_type_name := field_type.name

// Handle anon structs, the anonymous struct has just been defined above, use its definition
Expand Down Expand Up @@ -101,7 +101,7 @@ fn (mut c C2V) anon_struct_field_type(node &Node) string {
continue
}
field_type := convert_type(field.ast_type.qualified)
field_name := filter_name(field.name)
field_name := filter_name(field.name, false)
sb.write_string('\t${field_name} ${field_type.name}\n')
}
sb.write_string('}\n')
Expand Down
19 changes: 19 additions & 0 deletions tests/22.getline_linux.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <stdio.h>
#include <stdlib.h>

int main() {
char *input = NULL;
size_t len = 0;
ssize_t read;
printf("Enter text (Ctrl+D to quit):\n");
read = getline(&input, &len, stdin);

if (read != -1) {
printf("Entered: %s", input);
} else {
printf("error reading input\n");
}

free(input);
return 0;
}
42 changes: 42 additions & 0 deletions tests/22.getline_linux.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@[translated]
module main

fn C.getline(__lineptr &&u8, __n &usize, __stream &C.FILE) isize

struct Lldiv_t {
quot i64
rem i64
}

struct Random_data {
fptr &int
rptr &int
state &int
rand_type int
rand_deg int
rand_sep int
end_ptr &int
}

struct Drand48_data {
__x [3]u16
__old_x [3]u16
__c u16
__init u16
__a i64
}

fn main() {
input := (unsafe { nil })
len := 0
read := isize(0)
C.printf(c'Enter text (Ctrl+D to quit):\n')
read = C.getline(&input, &len, C.stdin)
if read != -1 {
C.printf(c'Entered: %s', input)
} else {
C.printf(c'error reading input\n')
}
C.free(input)
return
}
19 changes: 19 additions & 0 deletions tests/22.getline_macos.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <stdio.h>
#include <stdlib.h>

int main() {
char *input = NULL;
size_t len = 0;
ssize_t read;
printf("Enter text (Ctrl+D to quit):\n");
read = getline(&input, &len, stdin);

if (read != -1) {
printf("Entered: %s", input);
} else {
printf("error reading input\n");
}

free(input);
return 0;
}
24 changes: 24 additions & 0 deletions tests/22.getline_macos.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@[translated]
module main

fn C.getline(__linep &&u8, __linecapp &usize, __stream &C.FILE) isize

struct Lldiv_t {
quot i64
rem i64
}

fn main() {
input := (unsafe { nil })
len := 0
read := isize(0)
C.printf(c'Enter text (Ctrl+D to quit):\n')
read = C.getline(&input, &len, C.__stdinp)
if read != -1 {
C.printf(c'Entered: %s', input)
} else {
C.printf(c'error reading input\n')
}
C.free(input)
return
}

0 comments on commit 23fe665

Please sign in to comment.