2020-01-23 21:04:46 +01:00
|
|
|
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
2019-06-23 04:21:30 +02:00
|
|
|
// Use of this source code is governed by an MIT license
|
|
|
|
// that can be found in the LICENSE file.
|
2019-10-13 15:37:43 +02:00
|
|
|
module compiler
|
2019-06-22 20:20:28 +02:00
|
|
|
|
2019-12-23 11:09:22 +01:00
|
|
|
import (
|
|
|
|
os
|
|
|
|
strings
|
|
|
|
filepath
|
|
|
|
)
|
2019-07-12 07:37:54 +02:00
|
|
|
|
2019-06-22 20:20:28 +02:00
|
|
|
struct CGen {
|
2019-12-19 21:36:18 +01:00
|
|
|
out os.File
|
|
|
|
out_path string
|
|
|
|
// types []string
|
|
|
|
thread_fns []string
|
|
|
|
// buf strings.Builder
|
|
|
|
is_user bool
|
2019-08-30 19:19:06 +02:00
|
|
|
mut:
|
2019-12-19 21:36:18 +01:00
|
|
|
lines []string
|
|
|
|
lines_extra []string
|
|
|
|
typedefs []string
|
|
|
|
type_aliases []string
|
|
|
|
includes []string
|
|
|
|
thread_args []string
|
|
|
|
consts []string
|
|
|
|
const_defines []string
|
|
|
|
fns []string
|
|
|
|
so_fns []string
|
|
|
|
consts_init []string
|
|
|
|
pass Pass
|
2019-07-26 16:45:16 +02:00
|
|
|
nogen bool
|
2019-12-19 21:36:18 +01:00
|
|
|
prev_tmps []string
|
2019-07-26 16:45:16 +02:00
|
|
|
tmp_line string
|
|
|
|
cur_line string
|
|
|
|
prev_line string
|
|
|
|
is_tmp bool
|
|
|
|
fn_main string
|
|
|
|
stash string
|
|
|
|
file string
|
|
|
|
line int
|
|
|
|
line_directives bool
|
2019-12-19 21:36:18 +01:00
|
|
|
cut_pos int
|
2019-06-22 20:20:28 +02:00
|
|
|
}
|
|
|
|
|
2020-02-09 10:08:04 +01:00
|
|
|
pub fn new_cgen(out_name_c string) &CGen {
|
2019-08-23 10:42:48 +02:00
|
|
|
path := out_name_c
|
2019-12-19 21:36:18 +01:00
|
|
|
out := os.create(path)or{
|
2019-08-28 16:35:44 +02:00
|
|
|
println('failed to create $path')
|
2019-12-19 21:36:18 +01:00
|
|
|
return &CGen{
|
|
|
|
}
|
2019-08-28 16:35:44 +02:00
|
|
|
}
|
2019-12-19 21:36:18 +01:00
|
|
|
gen := &CGen{
|
2019-08-28 16:35:44 +02:00
|
|
|
out_path: path
|
|
|
|
out: out
|
2019-12-19 21:36:18 +01:00
|
|
|
// buf: strings.new_builder(10000)
|
2019-12-31 19:53:15 +01:00
|
|
|
|
2019-10-09 22:38:33 +02:00
|
|
|
lines: make(0, 1000, sizeof(string))
|
2019-06-22 20:20:28 +02:00
|
|
|
}
|
|
|
|
return gen
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (g mut CGen) genln(s string) {
|
2019-07-29 18:21:36 +02:00
|
|
|
if g.nogen || g.pass != .main {
|
2019-06-22 20:20:28 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if g.is_tmp {
|
|
|
|
g.tmp_line = '$g.tmp_line $s\n'
|
|
|
|
return
|
|
|
|
}
|
|
|
|
g.cur_line = '$g.cur_line $s'
|
|
|
|
if g.cur_line != '' {
|
2019-07-26 16:45:16 +02:00
|
|
|
if g.line_directives && g.cur_line.trim_space() != '' {
|
2019-10-11 23:04:42 +02:00
|
|
|
if g.file.len > 0 && g.line > 0 {
|
|
|
|
g.lines << '\n#line $g.line "$g.file"'
|
|
|
|
}
|
2019-07-26 16:45:16 +02:00
|
|
|
}
|
2019-06-22 20:20:28 +02:00
|
|
|
g.lines << g.cur_line
|
|
|
|
g.prev_line = g.cur_line
|
|
|
|
g.cur_line = ''
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-11 18:43:13 +01:00
|
|
|
// same as `set_placeholder(0, s)`, but faster
|
|
|
|
fn (g mut CGen) prepend_to_statement(s string) {
|
|
|
|
if g.is_tmp {
|
|
|
|
g.tmp_line = s + g.tmp_line
|
|
|
|
return
|
|
|
|
}
|
|
|
|
g.lines << s
|
|
|
|
g.prev_line = g.cur_line
|
|
|
|
}
|
|
|
|
|
2019-06-22 20:20:28 +02:00
|
|
|
fn (g mut CGen) gen(s string) {
|
2019-07-29 18:21:36 +02:00
|
|
|
if g.nogen || g.pass != .main {
|
2019-06-22 20:20:28 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if g.is_tmp {
|
|
|
|
g.tmp_line = '$g.tmp_line $s'
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
g.cur_line = '$g.cur_line $s'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-18 20:21:23 +02:00
|
|
|
fn (g mut CGen) resetln(s string) {
|
2019-07-29 18:21:36 +02:00
|
|
|
if g.nogen || g.pass != .main {
|
2019-07-18 20:21:23 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if g.is_tmp {
|
|
|
|
g.tmp_line = s
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
g.cur_line = s
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-22 20:20:28 +02:00
|
|
|
fn (g mut CGen) save() {
|
|
|
|
s := g.lines.join('\n')
|
2019-06-30 16:11:55 +02:00
|
|
|
g.out.writeln(s)
|
2019-11-29 14:46:43 +01:00
|
|
|
g.out.writeln(g.lines_extra.join('\n'))
|
2019-06-22 20:20:28 +02:00
|
|
|
g.out.close()
|
|
|
|
}
|
|
|
|
|
2019-11-11 04:06:49 +01:00
|
|
|
// returns expression's type, and entire expression's string representation)
|
2019-12-19 21:36:18 +01:00
|
|
|
fn (p mut Parser) tmp_expr() (string,string) {
|
2019-11-11 03:22:34 +01:00
|
|
|
// former start_tmp()
|
|
|
|
if p.cgen.is_tmp {
|
|
|
|
p.cgen.prev_tmps << p.cgen.tmp_line
|
2019-06-22 20:20:28 +02:00
|
|
|
}
|
|
|
|
// kg.tmp_lines_pos++
|
2019-11-11 03:22:34 +01:00
|
|
|
p.cgen.tmp_line = ''
|
|
|
|
p.cgen.is_tmp = true
|
|
|
|
//
|
|
|
|
typ := p.bool_expression()
|
|
|
|
res := p.cgen.tmp_line
|
|
|
|
if p.cgen.prev_tmps.len > 0 {
|
|
|
|
p.cgen.tmp_line = p.cgen.prev_tmps.last()
|
2019-12-19 21:36:18 +01:00
|
|
|
p.cgen.prev_tmps = p.cgen.prev_tmps[0..p.cgen.prev_tmps.len - 1]
|
|
|
|
}
|
|
|
|
else {
|
2019-11-11 03:22:34 +01:00
|
|
|
p.cgen.tmp_line = ''
|
|
|
|
p.cgen.is_tmp = false
|
2019-10-28 21:50:58 +01:00
|
|
|
}
|
2019-12-19 21:36:18 +01:00
|
|
|
return typ,res
|
2019-06-22 20:20:28 +02:00
|
|
|
}
|
|
|
|
|
2019-09-17 12:09:58 +02:00
|
|
|
fn (g &CGen) add_placeholder() int {
|
2019-06-22 20:20:28 +02:00
|
|
|
if g.is_tmp {
|
|
|
|
return g.tmp_line.len
|
|
|
|
}
|
|
|
|
return g.cur_line.len
|
|
|
|
}
|
|
|
|
|
2019-08-13 13:50:19 +02:00
|
|
|
fn (g mut CGen) start_cut() {
|
2019-08-28 16:35:44 +02:00
|
|
|
g.cut_pos = g.add_placeholder()
|
|
|
|
}
|
2019-08-13 13:50:19 +02:00
|
|
|
|
|
|
|
fn (g mut CGen) cut() string {
|
2019-08-28 16:35:44 +02:00
|
|
|
pos := g.cut_pos
|
|
|
|
g.cut_pos = 0
|
2019-08-13 13:50:19 +02:00
|
|
|
if g.is_tmp {
|
2019-10-27 08:03:15 +01:00
|
|
|
res := g.tmp_line[pos..]
|
|
|
|
g.tmp_line = g.tmp_line[..pos]
|
2019-08-28 16:35:44 +02:00
|
|
|
return res
|
2019-08-13 13:50:19 +02:00
|
|
|
}
|
2019-10-27 08:03:15 +01:00
|
|
|
res := g.cur_line[pos..]
|
|
|
|
g.cur_line = g.cur_line[..pos]
|
2019-08-28 16:35:44 +02:00
|
|
|
return res
|
|
|
|
}
|
2019-08-13 13:50:19 +02:00
|
|
|
|
2019-06-22 20:20:28 +02:00
|
|
|
fn (g mut CGen) set_placeholder(pos int, val string) {
|
2019-07-29 18:21:36 +02:00
|
|
|
if g.nogen || g.pass != .main {
|
2019-06-22 20:20:28 +02:00
|
|
|
return
|
|
|
|
}
|
2019-12-19 21:36:18 +01:00
|
|
|
// if pos == 0 {
|
|
|
|
// g.prepend_to_statement(val)
|
|
|
|
// return
|
|
|
|
// }
|
2019-06-22 20:20:28 +02:00
|
|
|
// g.lines.set(pos, val)
|
|
|
|
if g.is_tmp {
|
2019-10-27 08:03:15 +01:00
|
|
|
left := g.tmp_line[..pos]
|
|
|
|
right := g.tmp_line[pos..]
|
2019-06-22 20:20:28 +02:00
|
|
|
g.tmp_line = '${left}${val}${right}'
|
|
|
|
return
|
|
|
|
}
|
2019-10-27 08:03:15 +01:00
|
|
|
left := g.cur_line[..pos]
|
|
|
|
right := g.cur_line[pos..]
|
2019-06-22 20:20:28 +02:00
|
|
|
g.cur_line = '${left}${val}${right}'
|
|
|
|
// g.genln('')
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (g mut CGen) insert_before(val string) {
|
2019-10-07 00:31:01 +02:00
|
|
|
if g.nogen {
|
|
|
|
return
|
2019-12-06 00:38:35 +01:00
|
|
|
}
|
2019-08-28 16:35:44 +02:00
|
|
|
prev := g.lines[g.lines.len - 1]
|
|
|
|
g.lines[g.lines.len - 1] = '$prev \n $val \n'
|
2019-06-22 20:20:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn (g mut CGen) register_thread_fn(wrapper_name, wrapper_text, struct_text string) {
|
|
|
|
for arg in g.thread_args {
|
|
|
|
if arg.contains(wrapper_name) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g.thread_args << struct_text
|
|
|
|
g.thread_args << wrapper_text
|
|
|
|
}
|
|
|
|
|
2019-09-17 12:09:58 +02:00
|
|
|
fn (v &V) prof_counters() string {
|
2019-12-06 13:24:53 +01:00
|
|
|
res := []string
|
2019-06-22 20:20:28 +02:00
|
|
|
// Global fns
|
2019-12-19 21:36:18 +01:00
|
|
|
// for f in c.table.fns {
|
|
|
|
// res << 'double ${c.table.cgen_name(f)}_time;'
|
|
|
|
// }
|
2019-06-22 20:20:28 +02:00
|
|
|
// Methods
|
2019-09-01 13:31:43 +02:00
|
|
|
/*
|
2019-06-22 20:20:28 +02:00
|
|
|
for typ in c.table.types {
|
|
|
|
// println('')
|
|
|
|
for f in typ.methods {
|
|
|
|
// res << f.cgen_name()
|
|
|
|
res << 'double ${c.table.cgen_name(f)}_time;'
|
|
|
|
// println(f.cgen_name())
|
|
|
|
}
|
|
|
|
}
|
2019-09-01 13:31:43 +02:00
|
|
|
*/
|
2019-12-19 21:36:18 +01:00
|
|
|
|
2019-06-22 20:20:28 +02:00
|
|
|
return res.join(';\n')
|
|
|
|
}
|
|
|
|
|
2019-09-17 12:09:58 +02:00
|
|
|
fn (p &Parser) print_prof_counters() string {
|
2019-12-06 13:24:53 +01:00
|
|
|
res := []string
|
2019-06-22 20:20:28 +02:00
|
|
|
// Global fns
|
2019-12-19 21:36:18 +01:00
|
|
|
// for f in p.table.fns {
|
|
|
|
// counter := '${p.table.cgen_name(f)}_time'
|
|
|
|
// res << 'if ($counter) printf("%%f : $f.name \\n", $counter);'
|
|
|
|
// }
|
2019-06-22 20:20:28 +02:00
|
|
|
// Methods
|
2019-09-01 13:31:43 +02:00
|
|
|
/*
|
2019-06-22 20:20:28 +02:00
|
|
|
for typ in p.table.types {
|
|
|
|
// println('')
|
|
|
|
for f in typ.methods {
|
|
|
|
counter := '${p.table.cgen_name(f)}_time'
|
|
|
|
res << 'if ($counter) printf("%%f : ${p.table.cgen_name(f)} \\n", $counter);'
|
|
|
|
// res << 'if ($counter) printf("$f.name : %%f\\n", $counter);'
|
|
|
|
// res << f.cgen_name()
|
|
|
|
// res << 'double ${f.cgen_name()}_time;'
|
|
|
|
// println(f.cgen_name())
|
|
|
|
}
|
|
|
|
}
|
2019-09-01 13:31:43 +02:00
|
|
|
*/
|
2019-12-19 21:36:18 +01:00
|
|
|
|
2019-06-22 20:20:28 +02:00
|
|
|
return res.join(';\n')
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (p mut Parser) gen_typedef(s string) {
|
2019-07-29 18:21:36 +02:00
|
|
|
if !p.first_pass() {
|
2019-06-22 20:20:28 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
p.cgen.typedefs << s
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (p mut Parser) gen_type_alias(s string) {
|
2019-07-29 18:21:36 +02:00
|
|
|
if !p.first_pass() {
|
2019-06-22 20:20:28 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
p.cgen.type_aliases << s
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (g mut CGen) add_to_main(s string) {
|
|
|
|
g.fn_main = g.fn_main + s
|
|
|
|
}
|
|
|
|
|
2020-02-09 10:08:04 +01:00
|
|
|
fn (v &V) build_thirdparty_obj_file(path string, moduleflags []CFlag) {
|
2019-09-06 14:12:04 +02:00
|
|
|
obj_path := os.realpath(path)
|
2019-12-04 21:03:12 +01:00
|
|
|
if os.exists(obj_path) {
|
2019-08-28 16:35:44 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
println('$obj_path not found, building it...')
|
2019-12-23 11:09:22 +01:00
|
|
|
parent := filepath.dir(obj_path)
|
2019-12-19 21:36:18 +01:00
|
|
|
files := os.ls(parent)or{
|
|
|
|
panic(err)
|
|
|
|
}
|
2019-08-28 16:35:44 +02:00
|
|
|
mut cfiles := ''
|
2019-07-10 13:27:35 +02:00
|
|
|
for file in files {
|
2019-08-28 16:35:44 +02:00
|
|
|
if file.ends_with('.c') {
|
2019-12-19 21:36:18 +01:00
|
|
|
cfiles += '"' + os.realpath(parent + os.path_separator + file) + '" '
|
2019-08-28 16:35:44 +02:00
|
|
|
}
|
|
|
|
}
|
2019-09-22 23:51:59 +02:00
|
|
|
btarget := moduleflags.c_options_before_target()
|
|
|
|
atarget := moduleflags.c_options_after_target()
|
2020-02-09 10:08:04 +01:00
|
|
|
cmd := '$v.pref.ccompiler $v.pref.third_party_option $btarget -c -o "$obj_path" $cfiles $atarget '
|
2019-12-19 21:36:18 +01:00
|
|
|
res := os.exec(cmd)or{
|
2019-09-03 15:09:43 +02:00
|
|
|
println('failed thirdparty object build cmd: $cmd')
|
2019-09-23 23:40:34 +02:00
|
|
|
verror(err)
|
2019-08-29 02:30:17 +02:00
|
|
|
return
|
2019-08-08 07:30:05 +02:00
|
|
|
}
|
2019-10-28 10:43:57 +01:00
|
|
|
if res.exit_code != 0 {
|
|
|
|
println('failed thirdparty object build cmd: $cmd')
|
|
|
|
verror(res.output)
|
|
|
|
return
|
|
|
|
}
|
2019-08-28 16:35:44 +02:00
|
|
|
println(res.output)
|
|
|
|
}
|
2019-07-10 13:27:35 +02:00
|
|
|
|
2019-08-28 16:35:44 +02:00
|
|
|
fn os_name_to_ifdef(name string) string {
|
2019-10-24 18:19:03 +02:00
|
|
|
match name {
|
2019-12-19 21:36:18 +01:00
|
|
|
'windows' {
|
|
|
|
return '_WIN32'
|
|
|
|
}
|
|
|
|
'mac' {
|
|
|
|
return '__APPLE__'
|
|
|
|
}
|
|
|
|
'macos' {
|
|
|
|
return '__APPLE__'
|
|
|
|
}
|
|
|
|
'linux' {
|
|
|
|
return '__linux__'
|
|
|
|
}
|
|
|
|
'freebsd' {
|
|
|
|
return '__FreeBSD__'
|
|
|
|
}
|
|
|
|
'openbsd' {
|
|
|
|
return '__OpenBSD__'
|
|
|
|
}
|
|
|
|
'netbsd' {
|
|
|
|
return '__NetBSD__'
|
|
|
|
}
|
|
|
|
'dragonfly' {
|
|
|
|
return '__DragonFly__'
|
|
|
|
}
|
|
|
|
'msvc' {
|
|
|
|
return '_MSC_VER'
|
|
|
|
}
|
|
|
|
'android' {
|
2020-01-13 00:20:13 +01:00
|
|
|
return '__ANDROID__'
|
2019-12-19 21:36:18 +01:00
|
|
|
}
|
|
|
|
'js' {
|
|
|
|
return '_VJS'
|
|
|
|
}
|
|
|
|
'solaris' {
|
|
|
|
return '__sun'
|
|
|
|
}
|
|
|
|
'haiku' {
|
|
|
|
return '__haiku__'
|
|
|
|
}
|
2019-12-31 19:53:15 +01:00
|
|
|
'linux_or_macos' {
|
|
|
|
return ''
|
|
|
|
}
|
2019-12-19 21:36:18 +01:00
|
|
|
else {
|
|
|
|
verror('bad os ifdef name "$name"')
|
|
|
|
}}
|
|
|
|
// verror('bad os ifdef name "$name"')
|
2019-08-29 02:30:17 +02:00
|
|
|
return ''
|
2019-08-28 16:35:44 +02:00
|
|
|
}
|
2019-08-13 13:50:19 +02:00
|
|
|
|
2019-12-23 11:09:00 +01:00
|
|
|
fn (v &V) platform_postfix_to_ifdefguard(name string) string {
|
|
|
|
if name.starts_with('custom '){
|
|
|
|
cdefine := name.replace('custom ','')
|
|
|
|
return '#ifdef CUSTOM_DEFINE_${cdefine}'
|
|
|
|
}
|
2019-10-23 07:18:44 +02:00
|
|
|
s := match name {
|
2019-12-19 21:36:18 +01:00
|
|
|
'.v'{
|
2019-10-23 07:18:44 +02:00
|
|
|
''
|
2019-12-19 21:36:18 +01:00
|
|
|
} // no guard needed
|
2019-12-19 22:29:37 +01:00
|
|
|
'_win.v', '_windows.v'{
|
2019-12-19 21:36:18 +01:00
|
|
|
'#ifdef _WIN32'
|
2019-10-23 07:18:44 +02:00
|
|
|
}
|
2019-12-19 21:36:18 +01:00
|
|
|
'_nix.v'{
|
|
|
|
'#ifndef _WIN32'
|
|
|
|
}
|
2019-12-19 22:29:37 +01:00
|
|
|
'_lin.v', '_linux.v'{
|
2019-12-19 21:36:18 +01:00
|
|
|
'#ifdef __linux__'
|
|
|
|
}
|
2019-12-19 22:29:37 +01:00
|
|
|
'_mac.v', '_darwin.v'{
|
2019-12-19 21:36:18 +01:00
|
|
|
'#ifdef __APPLE__'
|
|
|
|
}
|
2019-12-19 22:29:37 +01:00
|
|
|
'_bsd.v', '_freebsd.v '{
|
2019-12-19 21:36:18 +01:00
|
|
|
'#ifdef __FreeBSD__'
|
|
|
|
}
|
|
|
|
'_solaris.v'{
|
|
|
|
'#ifdef __sun'
|
|
|
|
}
|
|
|
|
'_haiku.v'{
|
|
|
|
'#ifdef __haiku__'
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// verror('bad platform_postfix "$name"')
|
|
|
|
// TODO
|
|
|
|
''}}
|
2019-10-23 07:18:44 +02:00
|
|
|
if s == '' {
|
|
|
|
verror('bad platform_postfix "$name"')
|
2019-12-06 00:38:35 +01:00
|
|
|
}
|
2019-10-23 07:18:44 +02:00
|
|
|
return s
|
2019-08-13 13:50:19 +02:00
|
|
|
}
|
|
|
|
|
2019-08-28 16:35:44 +02:00
|
|
|
// C struct definitions, ordered
|
2019-08-29 00:52:32 +02:00
|
|
|
// Sort the types, make sure types that are referenced by other types
|
|
|
|
// are added before them.
|
2019-09-17 12:09:58 +02:00
|
|
|
fn (v &V) type_definitions() string {
|
2019-09-04 18:49:53 +02:00
|
|
|
mut types := []Type // structs that need to be sorted
|
|
|
|
mut builtin_types := []Type // builtin types
|
2019-09-01 13:31:43 +02:00
|
|
|
// builtin types need to be on top
|
|
|
|
builtins := ['string', 'array', 'map', 'Option']
|
|
|
|
for builtin in builtins {
|
|
|
|
typ := v.table.typesmap[builtin]
|
|
|
|
builtin_types << typ
|
|
|
|
}
|
2019-09-04 18:49:53 +02:00
|
|
|
// everything except builtin will get sorted
|
|
|
|
for t_name, t in v.table.typesmap {
|
2019-12-21 01:53:58 +01:00
|
|
|
if t_name in builtins || t.is_generic {
|
2019-08-29 00:52:32 +02:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
types << t
|
2019-08-28 16:35:44 +02:00
|
|
|
}
|
2019-09-04 18:49:53 +02:00
|
|
|
// sort structs
|
|
|
|
types_sorted := sort_structs(types)
|
2019-08-28 16:35:44 +02:00
|
|
|
// Generate C code
|
2019-12-19 21:36:18 +01:00
|
|
|
res := types_to_c(builtin_types, v.table) + '\n//----\n' + types_to_c(types_sorted, v.table)
|
2019-09-17 21:41:58 +02:00
|
|
|
return res
|
2019-08-29 00:52:32 +02:00
|
|
|
}
|
2019-12-06 00:38:35 +01:00
|
|
|
|
2019-09-03 18:11:21 +02:00
|
|
|
// sort structs by dependant fields
|
2019-09-04 09:35:08 +02:00
|
|
|
fn sort_structs(types []Type) []Type {
|
|
|
|
mut dep_graph := new_dep_graph()
|
|
|
|
// types name list
|
2019-09-03 18:11:21 +02:00
|
|
|
mut type_names := []string
|
2019-12-12 11:51:05 +01:00
|
|
|
for typ in types {
|
|
|
|
type_names << typ.name
|
2019-09-03 18:11:21 +02:00
|
|
|
}
|
|
|
|
// loop over types
|
2019-09-04 09:35:08 +02:00
|
|
|
for t in types {
|
2019-09-03 18:11:21 +02:00
|
|
|
// create list of deps
|
2019-09-04 09:35:08 +02:00
|
|
|
mut field_deps := []string
|
2019-09-03 18:11:21 +02:00
|
|
|
for field in t.fields {
|
2019-12-12 11:51:05 +01:00
|
|
|
// Need to handle fixed size arrays as well (`[10]Point`)
|
2019-12-19 21:36:18 +01:00
|
|
|
ft := if field.typ.starts_with('[') { field.typ.all_after(']') } else { field.typ }
|
2019-09-04 09:35:08 +02:00
|
|
|
// skip if not in types list or already in deps
|
2019-12-12 11:51:05 +01:00
|
|
|
if !(ft in type_names) || ft in field_deps {
|
2019-09-03 18:11:21 +02:00
|
|
|
continue
|
|
|
|
}
|
2019-12-19 21:36:18 +01:00
|
|
|
field_deps << ft // field.typ
|
2019-09-03 18:11:21 +02:00
|
|
|
}
|
|
|
|
// add type and dependant types to graph
|
2019-09-04 09:35:08 +02:00
|
|
|
dep_graph.add(t.name, field_deps)
|
|
|
|
}
|
|
|
|
// sort graph
|
|
|
|
dep_graph_sorted := dep_graph.resolve()
|
|
|
|
if !dep_graph_sorted.acyclic {
|
2019-12-19 21:36:18 +01:00
|
|
|
verror('cgen.sort_structs(): the following structs form a dependency cycle:\n' + dep_graph_sorted.display_cycles() + '\nyou can solve this by making one or both of the dependant struct fields references, eg: field &MyStruct' + '\nif you feel this is an error, please create a new issue here: https://github.com/vlang/v/issues and tag @joe-conigliaro')
|
2019-09-04 09:35:08 +02:00
|
|
|
}
|
|
|
|
// sort types
|
|
|
|
mut types_sorted := []Type
|
|
|
|
for node in dep_graph_sorted.nodes {
|
|
|
|
for t in types {
|
2019-09-03 18:11:21 +02:00
|
|
|
if t.name == node.name {
|
2019-09-04 09:35:08 +02:00
|
|
|
types_sorted << t
|
2019-08-29 00:52:32 +02:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-09-04 09:35:08 +02:00
|
|
|
return types_sorted
|
2019-08-29 00:52:32 +02:00
|
|
|
}
|
2019-11-08 04:03:06 +01:00
|
|
|
|
2019-11-08 05:43:44 +01:00
|
|
|
// Generates interface table and interface indexes
|
2019-11-08 04:03:06 +01:00
|
|
|
fn (v &V) interface_table() string {
|
2019-12-19 21:36:18 +01:00
|
|
|
mut sb := strings.new_builder(100)
|
|
|
|
for _, t in v.table.typesmap {
|
|
|
|
if t.cat != .interface_ {
|
|
|
|
continue
|
|
|
|
}
|
2019-12-20 21:06:11 +01:00
|
|
|
interface_name := t.name
|
2019-12-19 21:36:18 +01:00
|
|
|
mut methods := ''
|
|
|
|
sb.writeln('// NR methods = $t.gen_types.len')
|
|
|
|
for i, gen_type in t.gen_types {
|
2019-12-20 21:06:11 +01:00
|
|
|
gen_concrete_type_name := gen_type.replace('*', '')
|
|
|
|
methods += '{\n'
|
2019-12-19 21:36:18 +01:00
|
|
|
for j, method in t.methods {
|
|
|
|
// Cat_speak
|
2019-12-20 21:06:11 +01:00
|
|
|
methods += ' (void*) ${gen_concrete_type_name}_${method.name}'
|
2019-12-19 21:36:18 +01:00
|
|
|
if j < t.methods.len - 1 {
|
2019-12-20 21:06:11 +01:00
|
|
|
methods += ', \n'
|
2019-12-19 21:36:18 +01:00
|
|
|
}
|
|
|
|
}
|
2019-12-20 21:06:11 +01:00
|
|
|
methods += '\n},\n\n'
|
2019-12-21 22:54:37 +01:00
|
|
|
// Speaker_Cat_index = 0
|
|
|
|
concrete_type_name := gen_type.replace('*', '_ptr')
|
2019-12-20 21:06:11 +01:00
|
|
|
sb.writeln('int _${interface_name}_${concrete_type_name}_index = $i;')
|
2019-12-19 21:36:18 +01:00
|
|
|
}
|
|
|
|
if t.gen_types.len > 0 {
|
|
|
|
// methods = '{TCCSKIP(0)}'
|
|
|
|
// }
|
2019-12-20 21:06:11 +01:00
|
|
|
sb.writeln('void* (* ${interface_name}_name_table[][$t.methods.len]) = ' + '{ \n $methods \n }; ')
|
2019-12-21 22:54:37 +01:00
|
|
|
}
|
|
|
|
else {
|
2019-12-20 21:06:11 +01:00
|
|
|
// The line below is needed so that C compilation succeeds,
|
|
|
|
// even if no interface methods are called.
|
|
|
|
// See https://github.com/zenith391/vgtk3/issues/7
|
|
|
|
sb.writeln('void* (* ${interface_name}_name_table[][1]) = ' + '{ {NULL} }; ')
|
2019-12-19 21:36:18 +01:00
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return sb.str()
|
2019-11-08 04:03:06 +01:00
|
|
|
}
|
|
|
|
|