127 lines
2.7 KiB
V
127 lines
2.7 KiB
V
module c
|
|
|
|
import strings
|
|
|
|
const c_reserved_words = ['auto', 'break', 'case', 'char', 'const', 'continue', 'copy', 'default',
|
|
'do', 'double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'inline', 'int', 'long',
|
|
'register', 'restrict', 'return', 'short', 'signed', 'sizeof', 'static', 'struct', 'switch',
|
|
'typedef', 'union', 'unsigned', 'void', 'volatile', 'while']
|
|
|
|
fn c_name(name string) string {
|
|
if name.starts_with('C.') {
|
|
return name[2..]
|
|
}
|
|
if name == 'malloc' {
|
|
return 'v_malloc'
|
|
}
|
|
// The V builtin `exit` wraps `C.exit`; both lower to the C symbol `exit`.
|
|
// Rename the V function (and its call sites) to `v_exit` so its body's
|
|
// `C.exit(code)` call resolves to libc `exit` instead of recursing forever.
|
|
// `C.exit` itself is handled by the `C.` strip above, so it stays `exit`.
|
|
if name == 'exit' {
|
|
return 'v_exit'
|
|
}
|
|
if c_name_is_plain(name) {
|
|
if name in c_reserved_words {
|
|
return 'v_${name}'
|
|
}
|
|
return name
|
|
}
|
|
n := c_name_sanitize(name)
|
|
if n in c_reserved_words {
|
|
return 'v_${n}'
|
|
}
|
|
return n
|
|
}
|
|
|
|
fn c_name_sanitize(name string) string {
|
|
mut b := strings.new_builder(name.len + 8)
|
|
mut i := 0
|
|
for i < name.len {
|
|
c := name[i]
|
|
if c == `[` {
|
|
if i + 1 < name.len && name[i + 1] == `]` {
|
|
b.write_string('Array_')
|
|
i += 2
|
|
continue
|
|
}
|
|
b.write_u8(`_`)
|
|
} else if c == `]` {
|
|
i++
|
|
continue
|
|
} else if c == `.` {
|
|
if i + 1 < name.len {
|
|
next := name[i + 1]
|
|
if next == `-` {
|
|
b.write_string('__minus')
|
|
i += 2
|
|
continue
|
|
}
|
|
if next == `+` {
|
|
b.write_string('__plus')
|
|
i += 2
|
|
continue
|
|
}
|
|
if i + 2 < name.len {
|
|
op := name[i + 2]
|
|
if next == `=` && op == `=` {
|
|
b.write_string('__eq')
|
|
i += 3
|
|
continue
|
|
}
|
|
if next == `!` && op == `=` {
|
|
b.write_string('__ne')
|
|
i += 3
|
|
continue
|
|
}
|
|
if next == `<` && op == `=` {
|
|
b.write_string('__le')
|
|
i += 3
|
|
continue
|
|
}
|
|
if next == `>` && op == `=` {
|
|
b.write_string('__ge')
|
|
i += 3
|
|
continue
|
|
}
|
|
}
|
|
if next == `<` {
|
|
b.write_string('__lt')
|
|
i += 2
|
|
continue
|
|
}
|
|
if next == `>` {
|
|
b.write_string('__gt')
|
|
i += 2
|
|
continue
|
|
}
|
|
}
|
|
b.write_string('__')
|
|
} else if c == `&` {
|
|
b.write_string('ptr')
|
|
} else if c == `,` || c == ` ` {
|
|
b.write_u8(`_`)
|
|
} else {
|
|
b.write_u8(c)
|
|
}
|
|
i++
|
|
}
|
|
return b.str()
|
|
}
|
|
|
|
fn c_name_is_plain(name string) bool {
|
|
for i in 0 .. name.len {
|
|
c := name[i]
|
|
if (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) || (c >= `0` && c <= `9`) || c == `_` {
|
|
continue
|
|
}
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
fn c_escape(s string) string {
|
|
return s.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\t', '\\t').replace('\r',
|
|
'\\r')
|
|
}
|