Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix restrict ptr translate #168

Merged
merged 12 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}