all: re-apply C++ support

pull/4941/head
Uwe Krüger 2020-05-18 21:38:06 +02:00 committed by GitHub
parent 895cefe351
commit 2635be511f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 261 additions and 150 deletions

View File

@ -299,3 +299,20 @@ jobs:
./v -os windows -o /tmp/v_win.c cmd/v
x86_64-w64-mingw32-gcc /tmp/v_win.c -std=c99 -w -municode -o v_from_vc.exe
ls -lart v_from_vc.exe
ubuntu-c-plus-plus:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list; sudo apt-get update; sudo apt-get install --quiet -y postgresql libpq-dev libglfw3 libglfw3-dev libfreetype6-dev libssl-dev sqlite3 libsqlite3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev valgrind g++-9
- name: Build V
run: make -j4
- name: g++ version
run: g++-9 --version
- name: Running tests with g++
run: ./v -cc g++-9 test-fixed
- name: V self compilation with g++
run: ./v -cc g++-9 -o v2 cmd/v && ./v2 -cc g++-9 -o v3 cmd/v

View File

@ -16,11 +16,11 @@ const (
struct BenchedTests {
mut:
bench benchmark.Benchmark
oks int
fails int
test_suit_file string
step_func_name string
bench benchmark.Benchmark
}
// ///////////////////////////////////////////////////////////////////

View File

@ -55,15 +55,15 @@ const (
pub struct Benchmark {
pub mut:
bench_timer time.StopWatch
verbose bool
no_cstep bool
step_timer time.StopWatch
ntotal int
nok int
nfail int
nskip int
verbose bool
nexpected_steps int
cstep int
no_cstep bool
bok string
bfail string
}

View File

@ -19,10 +19,10 @@ pub mut:
fn __new_array(mylen int, cap int, elm_size int) array {
cap_ := if cap < mylen { mylen } else { cap }
arr := array{
len: mylen
cap: cap_
element_size: elm_size
data: vcalloc(cap_ * elm_size)
len: mylen
cap: cap_
}
return arr
}
@ -30,10 +30,10 @@ fn __new_array(mylen int, cap int, elm_size int) array {
fn __new_array_with_default(mylen int, cap int, elm_size int, val voidptr) array {
cap_ := if cap < mylen { mylen } else { cap }
arr := array{
len: mylen
cap: cap_
element_size: elm_size
data: vcalloc(cap_ * elm_size)
len: mylen
cap: cap_
}
if val != 0 {
for i in 0..arr.len {
@ -48,10 +48,10 @@ fn new_array_from_c_array(len, cap, elm_size int, c_array voidptr) array {
cap_ := if cap < len { len } else { cap }
arr := array{
len: len
cap: cap_
element_size: elm_size
data: vcalloc(cap_ * elm_size)
len: len
cap: cap_
}
// TODO Write all memory functions (like memcpy) in V
C.memcpy(arr.data, c_array, len * elm_size)
@ -61,10 +61,10 @@ fn new_array_from_c_array(len, cap, elm_size int, c_array voidptr) array {
// Private function, used by V (`nums := [1, 2, 3] !`)
fn new_array_from_c_array_no_alloc(len, cap, elm_size int, c_array voidptr) array {
arr := array{
len: len
cap: cap
element_size: elm_size
data: c_array
len: len
cap: cap
}
return arr
}
@ -98,10 +98,10 @@ pub fn (a array) repeat(count int) array {
size = a.element_size
}
arr := array{
len: count * a.len
cap: count * a.len
element_size: a.element_size
data: vcalloc(size)
len: count * a.len
cap: count * a.len
}
for i in 0..count {
C.memcpy(byteptr(arr.data) + i * a.len * a.element_size, byteptr(a.data), a.len * a.element_size)
@ -241,10 +241,10 @@ pub fn (a &array) clone() array {
size++
}
arr := array{
len: a.len
cap: a.cap
element_size: a.element_size
data: vcalloc(size)
len: a.len
cap: a.cap
}
C.memcpy(byteptr(arr.data), a.data, a.cap * a.element_size)
return arr
@ -312,10 +312,10 @@ pub fn (a array) reverse() array {
return a
}
arr := array{
len: a.len
cap: a.cap
element_size: a.element_size
data: vcalloc(a.cap * a.element_size)
len: a.len
cap: a.cap
}
for i in 0..a.len {
//C.memcpy(arr.data + i * arr.element_size, &a[a.len - 1 - i], arr.element_size)

View File

@ -116,7 +116,7 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
buf := [1000]byte
mut output := ''
for C.fgets(charptr(buf), 1000, f) != 0 {
output += tos(buf, vstrlen(buf))
output += tos(byteptr(buf), vstrlen(byteptr(buf)))
}
output = output.trim_space() + ':'
if C.pclose(f) != 0 {

View File

@ -12,7 +12,7 @@ fn C.free(ptr voidptr)
fn C.exit(code int)
fn C.qsort(voidptr, int, int, voidptr)
fn C.qsort(voidptr, int, int, qsort_callback_func)
fn C.sprintf(a ...voidptr) int

View File

@ -383,8 +383,8 @@ pub fn (c rune) str() string {
pub fn (c byte) str() string {
mut str := string{
len: 1
str: malloc(2)
len: 1
}
str.str[0] = c
str.str[1] = `\0`

View File

@ -4,21 +4,21 @@
module builtin
/*
struct Option2<T> {
data T
error string
ecode int
ok bool
is_none bool
error string
ecode int
data T
}
*/
struct Option {
data [400]byte
error string
ecode int
ok bool
is_none bool
error string
ecode int
data [400]byte
}
pub fn (o Option) str() string {
@ -46,18 +46,23 @@ fn opt_ok(data voidptr, size int) Option {
// used internally when returning `none`
fn opt_none() Option {
return Option{
ok: false
is_none: true
}
}
pub fn error(s string) Option {
return Option{
ok: false
is_none: false
error: s
}
}
pub fn error_with_code(s string, code int) Option {
return Option{
ok: false
is_none: false
error: s
ecode: code
}

View File

@ -31,10 +31,10 @@ pub mut:
struct mapnode {
mut:
keys [11]string // TODO: Should use `max_size`
values [11]voidptr // TODO: Should use `max_size`
children &voidptr
size int
keys [11]string // TODO: Should use `max_size`
values [11]voidptr // TODO: Should use `max_size`
}
fn new_sorted_map(n, value_bytes int) SortedMap { // TODO: Remove `n`

View File

@ -122,8 +122,8 @@ fn (a string) clone_static() string {
pub fn (a string) clone() string {
mut b := string{
len: a.len
str: malloc(a.len + 1)
len: a.len
}
for i in 0..a.len {
b.str[i] = a.str[i]
@ -399,8 +399,8 @@ fn (s string) ge(a string) bool {
fn (s string) add(a string) string {
new_len := a.len + s.len
mut res := string{
len: new_len
str: malloc(new_len + 1)
len: new_len
}
for j in 0..s.len {
res.str[j] = s.str[j]
@ -537,8 +537,8 @@ pub fn (s string) substr(start, end int) string {
}
len := end - start
mut res := string{
len: len
str: malloc(len + 1)
len: len
}
for i in 0..len {
res.str[i] = s.str[start + i]
@ -1284,8 +1284,8 @@ pub fn (s string) reverse() string {
return s
}
mut res := string{
len: s.len
str: malloc(s.len)
len: s.len
}
for i := s.len - 1; i >= 0; i-- {
res.str[s.len - i - 1] = s[i]

View File

@ -10,7 +10,8 @@ import math
#include <X11/Xlib.h>
// X11
struct C.Display{}
[typedef]
struct C.Display
[typedef]
struct C.Atom
@ -33,7 +34,7 @@ fn C.XCreateSimpleWindow(d &Display, root C.Window, x int, y int, width u32, hei
fn C.XOpenDisplay(name byteptr) &C.Display
fn C.XConvertSelection(d &Display, selection C.Atom, target C.Atom, property C.Atom, requestor Window, time int) int
fn C.XSync(d &Display, discard int) int
fn C.XGetWindowProperty(d &Display, w Window, property C.Atom, offset i64, length i64, delete int, req_type C.Atom, actual_type_return &C.Atom, actual_format_return &int, nitems &i64, bytes_after_return &i64, prop_return &byteptr) int
fn C.XGetWindowProperty(d &Display, w Window, property C.Atom, offset i64, length i64, delete int, req_type C.Atom, actual_type_return &C.Atom, actual_format_return &int, nitems &u64, bytes_after_return &u64, prop_return &byteptr) int
fn C.XDeleteProperty(d &Display, w Window, property C.Atom) int
fn C.DefaultScreen() int
fn C.RootWindow() voidptr
@ -46,10 +47,10 @@ fn todo_del(){}
[typedef]
struct C.XSelectionRequestEvent{
mut:
selection C.Atom
display &C.Display /* Display the event was read from */
owner C.Window
requestor C.Window
selection C.Atom
target C.Atom
property C.Atom
time int
@ -59,9 +60,9 @@ struct C.XSelectionRequestEvent{
struct C.XSelectionEvent{
mut:
@type int
selection C.Atom
display &C.Display /* Display the event was read from */
requestor C.Window
selection C.Atom
target C.Atom
property C.Atom
time int
@ -81,13 +82,13 @@ struct C.XDestroyWindowEvent {
}
[typedef]
struct C.XEvent{
union C.XEvent{
mut:
@type int
xdestroywindow C.XDestroyWindowEvent
xselectionclear C.XSelectionClearEvent
xselectionrequest C.XSelectionRequestEvent
xselection C.XSelectionEvent
xselectionclear C.XSelectionClearEvent
xdestroywindow C.XDestroyWindowEvent
}
const (
@ -287,7 +288,7 @@ fn (mut cb Clipboard) start_listener(){
if !cb.transmit_selection(&xse) {
xse.property = new_atom(C.None)
}
C.XSendEvent(cb.display, xse.requestor, 0, C.PropertyChangeMask, &xse)
C.XSendEvent(cb.display, xse.requestor, 0, C.PropertyChangeMask, voidptr(&xse))
C.XFlush(cb.display)
}
}
@ -340,8 +341,8 @@ fn (mut cb Clipboard) intern_atoms(){
fn read_property(d &C.Display, w C.Window, p C.Atom) Property {
actual_type := C.Atom(0)
actual_format := 0
nitems := 0
bytes_after := 0
nitems := u64(0)
bytes_after := u64(0)
ret := byteptr(0)
mut read_bytes := 1024
for {

View File

@ -75,6 +75,7 @@ pub fn (af []Flag) str() string {
pub struct FlagParser {
pub mut:
args []string // the arguments to be parsed
max_free_args int
flags []Flag // registered flags
application_name string
@ -82,7 +83,6 @@ pub struct FlagParser {
application_description string
min_free_args int
max_free_args int
args_description string
}

View File

@ -40,7 +40,7 @@ pub fn sum64_string(key string, seed u64) u64 {
[inline]
pub fn sum64(key []byte, seed u64) u64 {
return wyhash64(key.data, u64(key.len), seed)
return wyhash64(byteptr(key.data), u64(key.len), seed)
}
[inline]

View File

@ -6,10 +6,13 @@ module big
#flag @VROOT/thirdparty/bignum/bn.o
#include "bn.h"
pub struct Number {
[typedef]
struct C.bn {
array [32]u32
}
type Number = C.bn
fn C.bignum_init( n &Number )
fn C.bignum_from_int( n &Number, i u64 )
fn C.bignum_to_int( n &Number ) int

View File

@ -18,8 +18,8 @@ import strings
#flag darwin -I/usr/local/opt/openssl/include
#flag darwin -L/usr/local/opt/openssl/lib
#include <openssl/ssl.h>
struct C.SSL {
}
struct C.ssl_st
fn C.SSL_library_init()
@ -108,7 +108,7 @@ fn (req &Request) ssl_do(port int, method, host_name, path string) ?Response {
res = C.BIO_set_conn_hostname(web, addr.str)
if res != 1 {
}
ssl := &C.SSL(0)
ssl := &C.ssl_st(0)
C.BIO_get_ssl(web, &ssl)
if isnil(ssl) {
}

View File

@ -6,10 +6,11 @@ pub fn hostname() ?string {
mut name := [256]byte
// https://www.ietf.org/rfc/rfc1035.txt
// The host name is returned as a null-terminated string.
res := C.gethostname(&name, 256)
namebp := byteptr(name)
res := C.gethostname(namebp, 256)
if res != 0 {
return error('net.hostname: failed with $res')
}
return tos_clone(name)
return tos_clone(namebp)
}

View File

@ -15,6 +15,9 @@ mut:
s_addr int
}
struct C.sockaddr {
}
struct C.sockaddr_in {
mut:
sin_family int
@ -108,7 +111,9 @@ pub fn (s Socket) bind(port int) ?int {
addr.sin_port = C.htons(port)
addr.sin_addr.s_addr = C.htonl(C.INADDR_ANY)
size := 16 // sizeof(C.sockaddr_in)
res := C.bind(s.sockfd, &addr, size)
tmp := voidptr(&addr)
skaddr := &C.sockaddr(tmp)
res := C.bind(s.sockfd, skaddr, size)
if res < 0 {
return error('net.bind: failed with $res')
}
@ -165,7 +170,9 @@ pub fn (s Socket) accept() ?Socket {
}
addr := C.sockaddr_storage{}
size := 128 // sizeof(sockaddr_storage)
sockfd := C.accept(s.sockfd, &addr, &size)
tmp := voidptr(&addr)
skaddr := &C.sockaddr(tmp)
sockfd := C.accept(s.sockfd, skaddr, &size)
if sockfd < 0 {
return error('net.accept: failed with $sockfd')
}
@ -255,8 +262,8 @@ pub fn (s Socket) cread(buffer byteptr, buffersize int) int {
// Receive a message from the socket, and place it in a preallocated buffer buf,
// with maximum message size bufsize. Returns the length of the received message.
pub fn (s Socket) crecv(buffer byteptr, buffersize int) int {
return C.recv(s.sockfd, buffer, buffersize, 0)
pub fn (s Socket) crecv(buffer voidptr, buffersize int) int {
return C.recv(s.sockfd, byteptr(buffer), buffersize, 0)
}
// shutdown and close socket
@ -325,7 +332,8 @@ pub fn (s Socket) read_line() string {
break
}
}
line = tos_clone(buf)
bufbp := byteptr(buf)
line = tos_clone(bufbp)
if eol_idx > 0 {
// At this point, we are sure that recv returned valid data,
// that contains *at least* one line.
@ -357,7 +365,8 @@ pub fn (s Socket) read_all() string {
if n == 0 {
return res
}
res += tos_clone(buf)
bufbp := byteptr(buf)
res += tos_clone(bufbp)
}
return res
}
@ -365,6 +374,8 @@ pub fn (s Socket) read_all() string {
pub fn (s Socket) get_port() int {
mut addr := C.sockaddr_in{}
size := 16 // sizeof(sockaddr_in)
C.getsockname(s.sockfd, &addr, &size)
tmp := voidptr(&addr)
skaddr := &C.sockaddr(tmp)
C.getsockname(s.sockfd, skaddr, &size)
return C.ntohs(addr.sin_port)
}

View File

@ -84,6 +84,7 @@ pub fn open(path string) ?File {
*/
file := File{
cfile: C.fopen(charptr(path.str), 'rb')
fd: 0
opened: true
}
if isnil(file.cfile) {
@ -119,6 +120,7 @@ pub fn create(path string) ?File {
*/
file := File{
cfile: C.fopen(charptr(path.str), 'wb')
fd: 0
opened: true
}
if isnil(file.cfile) {
@ -207,7 +209,8 @@ pub fn exec(cmd string) ?Result {
buf := [4096]byte
mut res := strings.new_builder(1024)
for C.fgets(charptr(buf), 4096, f) != 0 {
res.write_bytes( buf, vstrlen(buf) )
bufbp := byteptr(buf)
res.write_bytes( bufbp, vstrlen(bufbp) )
}
soutput := res.str().trim_space()
//res.free()
@ -216,8 +219,8 @@ pub fn exec(cmd string) ?Result {
// return error(res)
// }
return Result{
output: soutput
exit_code: exit_code
output: soutput
}
}

View File

@ -664,7 +664,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
}
res.write(format_dec(d1,{positive: positive, pad_ch: pad_ch, len0: len0, sign_flag: sign, allign: allign}))
res.write(format_dec(d1,{pad_ch: pad_ch, len0: len0, len1: 0, positive: positive, sign_flag: sign, allign: allign}))
status = .reset_params
p_index++
i++
@ -707,7 +707,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
}
}
res.write(format_dec(d1,{positive: positive, pad_ch: pad_ch, len0: len0, sign_flag: sign, allign: allign}))
res.write(format_dec(d1,{pad_ch: pad_ch, len0: len0, len1: 0, positive: positive, sign_flag: sign, allign: allign}))
status = .reset_params
p_index++
i++
@ -755,7 +755,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
s = s.to_upper()
}
res.write(format_str(s,{pad_ch: pad_ch, len0: len0, allign: allign}))
res.write(format_str(s,{pad_ch: pad_ch, len0: len0, len1: 0, positive: true, sign_flag: false, allign: allign}))
status = .reset_params
p_index++
i++
@ -767,7 +767,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
x := *(&f64(pt[p_index]))
mut positive := x >= f64(0.0)
len1 = if len1 >= 0 { len1 } else { def_len1 }
s := format_fl(f64(x), {positive: positive, pad_ch: pad_ch, len0: len0, len1: len1, sign_flag: sign, allign: allign})
s := format_fl(f64(x), {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign})
res.write(if ch == `F` {s.to_upper()} else {s})
status = .reset_params
p_index++
@ -778,7 +778,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
x := *(&f64(pt[p_index]))
mut positive := x >= f64(0.0)
len1 = if len1 >= 0 { len1 } else { def_len1 }
s := format_es(f64(x), {positive: positive, pad_ch: pad_ch, len0: len0, len1: len1, sign_flag: sign, allign: allign})
s := format_es(f64(x), {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign})
res.write(if ch == `E` {s.to_upper()} else {s})
status = .reset_params
p_index++
@ -793,10 +793,10 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
if tx < 999_999.0 && tx >= 0.00001 {
//println("Here g format_fl [$tx]")
len1 = if len1 >= 0 { len1+1 } else { def_len1 }
s = format_fl(x, {positive: positive, pad_ch: pad_ch, len0: len0, len1: len1, sign_flag: sign, allign: allign, rm_tail_zero: true})
s = format_fl(x, {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign, rm_tail_zero: true})
} else {
len1 = if len1 >= 0 { len1+1 } else { def_len1 }
s = format_es(x, {positive: positive, pad_ch: pad_ch, len0: len0, len1: len1, sign_flag: sign, allign: allign, rm_tail_zero: true})
s = format_es(x, {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign, rm_tail_zero: true})
}
res.write(if ch == `G` {s.to_upper()} else {s})
status = .reset_params
@ -809,7 +809,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
else if ch == `s` {
s1 := *(&string(pt[p_index]))
pad_ch = ` `
res.write(format_str(s1, {pad_ch: pad_ch, len0: len0, allign: allign}))
res.write(format_str(s1, {pad_ch: pad_ch, len0: len0, len1: 0, positive: true, sign_flag: false, allign: allign}))
status = .reset_params
p_index++
i++

View File

@ -190,7 +190,7 @@ fn shift_right_128(v Uint128, shift int) u64 {
fn mul_shift_64(m u64, mul Uint128, shift int) u64 {
hihi, hilo := bits.mul_64(m, mul.hi)
lohi, _ := bits.mul_64(m, mul.lo)
mut sum := Uint128{hi: hihi, lo: lohi + hilo}
mut sum := Uint128{lo: lohi + hilo,hi: hihi}
if sum.lo < lohi {
sum.hi++ // overflow
}

View File

@ -16,6 +16,8 @@ pub fn new_builder(initial_size int) Builder {
return Builder{
//buf: make(0, initial_size)
buf: []byte{cap: initial_size}
str_calls: 0
len: 0
initial_size: initial_size
}
}

View File

@ -12,7 +12,7 @@ pub mut:
}
pub fn new_stopwatch() StopWatch {
return StopWatch{start: time.sys_mono_now()}
return StopWatch{pause_time: 0, start: time.sys_mono_now(), end: 0}
}
// start Starts the timer. If the timer was paused, restarts counting.

View File

@ -76,23 +76,18 @@ pub enum FormatDelimiter {
no_delimiter
}
// TODO: C.time_t. works in v2
type time_t voidptr
pub struct C.timeval {
tv_sec u64
tv_usec u64
}
fn C.localtime(int) &C.tm
fn C.time(int) time_t
fn C.localtime(t &C.time_t) &C.tm
fn C.time(t &C.time_t) C.time_t
// now returns current local time.
pub fn now() Time {
t := C.time(0)
mut now := &C.tm(0)
now = C.localtime(&t)
now := C.localtime(&t)
return convert_ctime(now)
}

View File

@ -4,12 +4,12 @@
module time
struct C.tm {
tm_year int
tm_mon int
tm_mday int
tm_hour int
tm_min int
tm_sec int
tm_min int
tm_hour int
tm_mday int
tm_mon int
tm_year int
}
fn C.timegm(&tm) time_t

View File

@ -306,6 +306,11 @@ fn (mut v Builder) cc() {
// add all flags (-I -l -L etc) not .o files
a << cflags.c_options_without_object_files()
a << libs
// For C++ we must be very tolerant
if guessed_compiler.contains('++') {
a << '-fpermissive'
a << '-w'
}
if v.pref.use_cache {
//vexe := pref.vexe_path()
@ -344,7 +349,7 @@ fn (mut v Builder) cc() {
if !v.pref.is_bare && v.pref.os == .js && os.user_os() == 'linux' {
linker_flags << '-lm'
}
args := a.join(' ') + linker_flags.join(' ')
args := a.join(' ') + ' ' + linker_flags.join(' ')
start:
todo()
// TODO remove

View File

@ -37,7 +37,9 @@ const (
'void',
'volatile',
'while',
'new'
'new',
'namespace',
'typename'
]
)
@ -363,7 +365,12 @@ typedef struct {
.alias {
parent := &g.table.types[typ.parent_idx]
styp := typ.name.replace('.', '__')
parent_styp := parent.name.replace('.', '__')
is_c_parent := parent.name.len > 2 && parent.name[0] == `C` && parent.name[1] == `.`
parent_styp := if is_c_parent {
'struct ' + parent.name[2..].replace('.', '__')
} else {
parent.name.replace('.', '__')
}
g.definitions.writeln('typedef $parent_styp $styp;')
}
.array {
@ -591,7 +598,13 @@ fn (mut g Gen) stmt(node ast.Stmt) {
// just remember `it`; main code will be generated in finish()
g.fn_main = it
} else {
if it.name == 'backtrace' || it.name == 'backtrace_symbols' || it.name == 'backtrace_symbols_fd' {
g.write('\n#ifndef __cplusplus\n')
}
g.gen_fn_decl(it)
if it.name == 'backtrace' || it.name == 'backtrace_symbols' || it.name == 'backtrace_symbols_fd' {
g.write('\n#endif\n')
}
}
g.fn_decl = keep_fn_decl
if skip {
@ -1210,9 +1223,9 @@ fn (mut g Gen) expr(node ast.Expr) {
// `string(x)` needs `tos()`, but not `&string(x)
// `tos(str, len)`, `tos2(str)`
if it.has_arg {
g.write('tos(')
g.write('tos((byteptr)')
} else {
g.write('tos2(')
g.write('tos2((byteptr)')
}
g.expr(it.expr)
expr_sym := g.table.get_type_symbol(it.expr_type)
@ -1286,17 +1299,17 @@ fn (mut g Gen) expr(node ast.Expr) {
value_typ_str := g.typ(it.value_type)
size := it.vals.len
if size > 0 {
g.write('new_map_init($size, sizeof($value_typ_str), (${key_typ_str}[$size]){')
g.write('new_map_init($size, sizeof($value_typ_str), _MOV((${key_typ_str}[$size]){')
for expr in it.keys {
g.expr(expr)
g.write(', ')
}
g.write('}, (${value_typ_str}[$size]){')
g.write('}), _MOV((${value_typ_str}[$size]){')
for expr in it.vals {
g.expr(expr)
g.write(', ')
}
g.write('})')
g.write('}))')
} else {
g.write('new_map_1(sizeof($value_typ_str))')
}
@ -1665,7 +1678,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
elem_type_str := g.typ(info.elem_type)
g.write('array_push(&')
g.expr(node.left)
g.write(', &($elem_type_str[]){ ')
g.write(', _MOV(($elem_type_str[]){ ')
elem_sym := g.table.get_type_symbol(info.elem_type)
if elem_sym.kind == .interface_ && node.right_type != info.elem_type {
g.interface_call(node.right_type, info.elem_type)
@ -1674,7 +1687,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
if elem_sym.kind == .interface_ && node.right_type != info.elem_type {
g.write(')')
}
g.write(' })')
g.write(' }))')
}
} else if (node.left_type == node.right_type) && node.left_type.is_float() && node.op in
[.eq, .ne] {
@ -1697,7 +1710,8 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
g.expr(node.right)
g.write(')')
} else if node.op in [.plus, .minus, .mul, .div, .mod] && (left_sym.name[0].is_capital() ||
left_sym.name.contains('.')) && left_sym.kind != .alias {
left_sym.name.contains('.')) && left_sym.kind != .alias ||
left_sym.kind == .alias && (left_sym.info as table.Alias).is_c {
// !left_sym.is_number() {
g.write(g.typ(node.left_type))
g.write('_')
@ -2009,7 +2023,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
}
*/
if need_wrapper {
g.write(', &($elem_type_str[]) { ')
g.write(', &($elem_type_str[]) { \n')
} else {
g.write(', &')
}
@ -2061,7 +2075,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
g.expr(node.left)
g.write(', ')
g.expr(node.index)
g.write(', &($elem_type_str[]) { ')
g.write(', &($elem_type_str[]) { \n')
} else {
/*
g.write('(*($elem_type_str*)map_get2(')
@ -2075,7 +2089,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
g.expr(node.left)
g.write(', ')
g.expr(node.index)
g.write(', &($elem_type_str[]){ $zero }))')
g.write(', &($elem_type_str[]){ $zero }))\n')
}
} else if sym.kind == .string && !node.left_type.is_ptr() {
g.write('string_at(')
@ -2237,9 +2251,18 @@ fn (mut g Gen) const_decl_init_later(name, val string, typ table.Type) {
g.inits.writeln('\t_const_$name = $val;')
}
fn (mut g Gen) go_back_out(n int) {
g.out.go_back(n)
}
fn (mut g Gen) struct_init(struct_init ast.StructInit) {
sym := g.table.get_type_symbol(struct_init.typ)
skip_init := ['strconv__ftoa__Uf32', 'strconv__ftoa__Uf64', 'strconv__Float64u', 'struct stat', 'struct addrinfo']
styp := g.typ(struct_init.typ)
if styp in skip_init {
g.go_back_out(3)
return
}
sym := g.table.get_type_symbol(struct_init.typ)
is_amp := g.is_amp
g.is_amp = false // reset the flag immediately so that other struct inits in this expr are handled correctly
if is_amp {
@ -2249,7 +2272,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
g.writeln('($styp){')
}
// mut fields := []string{}
mut inited_fields := []string{} // TODO this is done in checker, move to ast node
mut inited_fields := map[string]int // TODO this is done in checker, move to ast node
/*
if struct_init.fields.len == 0 && struct_init.exprs.len > 0 {
// Get fields for {a,b} short syntax. Fields array wasn't set in the parser.
@ -2261,33 +2284,63 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
}
*/
// User set fields
for _, field in struct_init.fields {
field_name := c_name(field.name)
inited_fields << field.name
g.write('\t.$field_name = ')
field_type_sym := g.table.get_type_symbol(field.typ)
mut cloned := false
if g.autofree && field_type_sym.kind in [.array, .string] {
g.write('/*clone1*/')
if g.gen_clone_assignment(field.expr, field_type_sym, false) {
cloned = true
mut initialized := false
for i, field in struct_init.fields {
inited_fields[field.name] = i
if sym.kind != .struct_ {
field_name := c_name(field.name)
g.write('\t.$field_name = ')
field_type_sym := g.table.get_type_symbol(field.typ)
mut cloned := false
if g.autofree && field_type_sym.kind in [.array, .string] {
g.write('/*clone1*/')
if g.gen_clone_assignment(field.expr, field_type_sym, false) {
cloned = true
}
}
}
if !cloned {
if field.expected_type.is_ptr() && !field.typ.is_ptr() && !field.typ.is_number() {
g.write('/* autoref */&')
if !cloned {
if field.expected_type.is_ptr() && !field.typ.is_ptr() && !field.typ.is_number() {
g.write('/* autoref */&')
}
g.expr_with_cast(field.expr, field.typ, field.expected_type)
}
g.expr_with_cast(field.expr, field.typ, field.expected_type)
g.writeln(',')
initialized = true
}
g.writeln(',')
}
// The rest of the fields are zeroed.
mut nr_info_fields := 0
if sym.kind == .struct_ {
info := sym.info as table.Struct
if info.is_union && struct_init.fields.len > 1 {
verror('union must not have more than 1 initializer')
}
nr_info_fields = info.fields.len
for field in info.fields {
if field.name in inited_fields {
sfield := struct_init.fields[inited_fields[field.name]]
field_name := c_name(sfield.name)
g.write('\t.$field_name = ')
field_type_sym := g.table.get_type_symbol(sfield.typ)
mut cloned := false
if g.autofree && field_type_sym.kind in [.array, .string] {
g.write('/*clone1*/')
if g.gen_clone_assignment(sfield.expr, field_type_sym, false) {
cloned = true
}
}
if !cloned {
if sfield.expected_type.is_ptr() && !sfield.typ.is_ptr() && !sfield.typ.is_number() {
g.write('/* autoref */&')
}
g.expr_with_cast(sfield.expr, sfield.typ, sfield.expected_type)
}
g.writeln(',')
initialized = true
continue
}
if info.is_union {
// unions thould have exactly one explicit initializer
continue
}
if field.typ.flag_is(.optional) {
@ -2302,11 +2355,12 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
g.write(g.type_default(field.typ))
}
g.writeln(',')
initialized = true
}
}
// if struct_init.fields.len == 0 && info.fields.len == 0 {
if struct_init.fields.len == 0 && nr_info_fields == 0 {
g.write('0')
if !initialized {
g.write('\n#ifndef __cplusplus\n0\n#endif\n')
}
g.write('}')
if is_amp {
@ -2322,21 +2376,22 @@ fn (mut g Gen) assoc(node ast.Assoc) {
}
styp := g.typ(node.typ)
g.writeln('($styp){')
mut inited_fields := map[string]int
for i, field in node.fields {
field_name := c_name(field)
g.write('\t.$field_name = ')
g.expr(node.exprs[i])
g.writeln(', ')
inited_fields[field] = i
}
// Copy the rest of the fields.
// Merge inited_fields in the rest of the fields.
sym := g.table.get_type_symbol(node.typ)
info := sym.info as table.Struct
for field in info.fields {
if field.name in node.fields {
continue
}
field_name := c_name(field.name)
g.writeln('\t.$field_name = ${node.var_name}.$field_name,')
if field.name in inited_fields {
g.write('\t.$field_name = ')
g.expr(node.exprs[inited_fields[field.name]])
g.writeln(', ')
} else {
g.writeln('\t.$field_name = ${node.var_name}.$field_name,')
}
}
g.write('}')
if g.is_amp {
@ -3422,19 +3477,19 @@ fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string {
fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp, str_fn_name string) {
mut convertor := ''
mut typename := ''
mut typename_ := ''
if sym.parent_idx in table.integer_type_idxs {
convertor = 'int'
typename = 'int'
typename_ = 'int'
} else if sym.parent_idx == table.f32_type_idx {
convertor = 'float'
typename = 'f32'
typename_ = 'f32'
} else if sym.parent_idx == table.f64_type_idx {
convertor = 'double'
typename = 'f64'
typename_ = 'f64'
} else if sym.parent_idx == table.bool_type_idx {
convertor = 'bool'
typename = 'bool'
typename_ = 'bool'
} else {
verror("could not generate string method for type \'${styp}\'")
}
@ -3443,7 +3498,7 @@ fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp, str_fn_name string) {
if convertor == 'bool' {
g.auto_str_funcs.writeln('\tstring tmp1 = string_add(tos_lit("${styp}("), (${convertor})it ? tos_lit("true") : tos_lit("false"));')
} else {
g.auto_str_funcs.writeln('\tstring tmp1 = string_add(tos_lit("${styp}("), tos3(${typename}_str((${convertor})it).str));')
g.auto_str_funcs.writeln('\tstring tmp1 = string_add(tos_lit("${styp}("), tos3(${typename_}_str((${convertor})it).str));')
}
g.auto_str_funcs.writeln('\tstring tmp2 = string_add(tmp1, tos_lit(")"));')
g.auto_str_funcs.writeln('\tstring_free(&tmp1);')
@ -3740,7 +3795,9 @@ fn (g &Gen) interface_table() string {
mut methods_struct_def := strings.new_builder(100)
methods_struct_def.writeln('$methods_struct_name {')
mut imethods := map[string]string{} // a map from speak -> _Speaker_speak_fn
for method in ityp.methods {
mut methodidx := map[string]int
for k, method in ityp.methods {
methodidx[method.name] = k
typ_name := '_${interface_name}_${method.name}_fn'
ret_styp := g.typ(method.return_type)
methods_typ_def.write('typedef $ret_styp (*$typ_name)(void* _')
@ -3786,7 +3843,14 @@ _Interface* I_${cctype}_to_Interface_${interface_name}_ptr(${cctype}* x) {
}')
methods_struct.writeln('\t{')
st_sym := g.table.get_type_symbol(st)
for method in st_sym.methods {
mut method := table.Fn{}
for _, m in ityp.methods {
for mm in st_sym.methods {
if mm.name == m.name {
method = mm
break
}
}
if method.name !in imethods {
// a method that is not part of the interface should be just skipped
continue
@ -3872,8 +3936,8 @@ fn (mut g Gen) array_init(it ast.ArrayInit) {
return
}
len := it.exprs.len
g.write('new_array_from_c_array($len, $len, sizeof($elem_type_str), ')
g.write('($elem_type_str[$len]){\n\t\t')
g.write('new_array_from_c_array($len, $len, sizeof($elem_type_str), _MOV(($elem_type_str[$len]){')
g.writeln('')
for i, expr in it.exprs {
if it.is_interface {
// sym := g.table.get_type_symbol(it.interface_types[i])
@ -3886,7 +3950,8 @@ fn (mut g Gen) array_init(it ast.ArrayInit) {
}
g.write(', ')
}
g.write('\n})')
g.writeln('')
g.write('}))')
}
// `ui.foo(button)` =>

View File

@ -391,9 +391,9 @@ typedef byte array_fixed_byte_300 [300];
typedef byte array_fixed_byte_400 [400];
#ifndef __cplusplus
#ifndef bool
typedef int bool;
#define true 1
#define false 0
typedef int bool;
#define true 1
#define false 0
#endif
#endif

View File

@ -618,7 +618,7 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
}
}
if !g.is_json_fn {
g.write('&/*qq*/')
g.write('(voidptr)&/*qq*/')
}
}
g.expr_with_cast(arg.expr, arg.typ, expected_type)

View File

@ -23,7 +23,7 @@ void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize,
}
// increase buffer (somewhat exponentially)
*memsize += (*memsize + *memsize) / 3 + guess;
*refbufp = realloc(*refbufp, *memsize);
*refbufp = (char*)realloc((void*)*refbufp, *memsize);
}
}
@ -31,7 +31,7 @@ string _STR(const char *fmt, int nfmts, ...) {
va_list argptr;
int memsize = 128;
int nbytes = 0;
char* buf = malloc(memsize);
char* buf = (char*)malloc(memsize);
va_start(argptr, nfmts);
for (int i=0; i<nfmts; i++) {
int k = strlen(fmt);
@ -80,12 +80,12 @@ string _STR(const char *fmt, int nfmts, ...) {
}
va_end(argptr);
buf[nbytes] = 0;
buf = realloc(buf, nbytes+1);
buf = (char*)realloc((void*)buf, nbytes+1);
#ifdef DEBUG_ALLOC
//puts('_STR:');
puts(buf);
#endif
return tos2(buf);
return tos2((byteptr)buf);
}
string _STR_TMP(const char *fmt, ...) {

View File

@ -1404,6 +1404,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
}
// type MyType int
parent_type := first_type
parent_name := p.table.get_type_symbol(parent_type).name
pid := parent_type.idx()
p.table.register_type_symbol(table.TypeSymbol{
kind: .alias
@ -1412,6 +1413,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
mod: p.mod
info: table.Alias{
foo: ''
is_c: parent_name.len > 2 && parent_name[0] == `C` && parent_name[1] == `.`
}
is_public: is_pub
})

View File

@ -575,6 +575,7 @@ pub:
pub struct Alias {
pub:
foo string
is_c bool
}
// NB: FExpr here is a actually an ast.Expr .

View File

@ -96,7 +96,7 @@ fn test_mut_struct() {
assert user.age == 19
}
fn mod_ptr(mut buf byteptr) {
fn mod_ptr(mut buf &byte) {
buf[0] = 77
}

View File

@ -5,9 +5,9 @@ module token
pub struct Position {
pub:
len int // length of the literal in the source
line_nr int // the line number in the source where the token occured
pos int // the position of the token in scanner text
len int // length of the literal in the source
}
pub fn (pos Position) str() string {
@ -24,8 +24,8 @@ pub fn (pos Position) extend(end Position) Position {
[inline]
pub fn (tok &Token) position() Position {
return Position{
len: tok.len
line_nr: tok.line_nr - 1
pos: tok.pos
len: tok.len
}
}