2019-12-30 08:30:24 +01:00
|
|
|
module gen
|
2019-12-24 18:54:43 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
strings
|
2019-12-27 05:43:17 +01:00
|
|
|
v.ast
|
2020-01-02 20:09:15 +01:00
|
|
|
v.table
|
2020-03-05 23:27:21 +01:00
|
|
|
v.depgraph
|
2019-12-29 08:51:55 +01:00
|
|
|
term
|
2019-12-24 18:54:43 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
struct Gen {
|
2020-01-02 08:30:15 +01:00
|
|
|
out strings.Builder
|
2020-03-04 17:08:28 +01:00
|
|
|
typedefs strings.Builder
|
2020-01-02 08:30:15 +01:00
|
|
|
definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
2020-01-02 20:09:15 +01:00
|
|
|
table &table.Table
|
2020-01-07 12:10:07 +01:00
|
|
|
mut:
|
|
|
|
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
2020-02-18 03:17:21 +01:00
|
|
|
tmp_count int
|
2019-12-24 18:54:43 +01:00
|
|
|
}
|
|
|
|
|
2020-01-02 20:09:15 +01:00
|
|
|
pub fn cgen(files []ast.File, table &table.Table) string {
|
2020-03-04 17:08:28 +01:00
|
|
|
println('start cgen2')
|
2019-12-28 11:02:06 +01:00
|
|
|
mut g := Gen{
|
|
|
|
out: strings.new_builder(100)
|
2020-03-04 17:08:28 +01:00
|
|
|
typedefs: strings.new_builder(100)
|
2020-01-02 08:30:15 +01:00
|
|
|
definitions: strings.new_builder(100)
|
2020-01-02 20:09:15 +01:00
|
|
|
table: table
|
2020-01-07 12:10:07 +01:00
|
|
|
fn_decl: 0
|
2019-12-28 11:02:06 +01:00
|
|
|
}
|
2020-03-04 17:08:28 +01:00
|
|
|
g.init()
|
2019-12-30 12:10:46 +01:00
|
|
|
for file in files {
|
2020-02-17 22:50:04 +01:00
|
|
|
g.stmts(file.stmts)
|
2019-12-24 18:54:43 +01:00
|
|
|
}
|
2020-03-04 17:08:28 +01:00
|
|
|
return g.typedefs.str() + g.definitions.str() + g.out.str()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn (g mut Gen) init() {
|
|
|
|
g.definitions.writeln('// Generated by the V compiler')
|
|
|
|
g.definitions.writeln('#include <inttypes.h>') // int64_t etc
|
|
|
|
g.definitions.writeln(c_builtin_types)
|
|
|
|
g.definitions.writeln(c_headers)
|
2020-03-06 13:43:22 +01:00
|
|
|
g.write_array_types()
|
2020-03-05 23:27:21 +01:00
|
|
|
g.write_sorted_types()
|
|
|
|
g.write_multi_return_types()
|
2020-03-06 12:06:41 +01:00
|
|
|
g.definitions.writeln('// end of definitions #endif')
|
2020-03-05 23:27:21 +01:00
|
|
|
}
|
|
|
|
|
2020-03-06 13:43:22 +01:00
|
|
|
// V type to C type
|
2020-03-06 22:36:51 +01:00
|
|
|
pub fn (g &Gen) typ(t table.Type) string {
|
|
|
|
nr_muls := table.type_nr_muls(t)
|
|
|
|
sym := g.table.get_type_symbol(t)
|
|
|
|
mut styp := sym.name.replace_each(['.', '__'])
|
|
|
|
if nr_muls > 0 {
|
|
|
|
styp += strings.repeat(`*`, nr_muls)
|
|
|
|
}
|
|
|
|
return styp
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
pub fn (g &Gen) styp(t string) string {
|
2020-03-06 13:43:22 +01:00
|
|
|
return t.replace_each(['.', '__'])
|
|
|
|
}
|
2020-03-06 22:36:51 +01:00
|
|
|
*/
|
|
|
|
|
2020-03-06 13:43:22 +01:00
|
|
|
|
|
|
|
pub fn (g mut Gen) write_array_types() {
|
|
|
|
for typ in g.table.types {
|
|
|
|
if typ.kind != .array {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
styp := typ.name.replace('.', '__')
|
|
|
|
g.definitions.writeln('typedef array $styp;')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-05 23:27:21 +01:00
|
|
|
pub fn (g mut Gen) write_multi_return_types() {
|
2020-03-04 20:17:29 +01:00
|
|
|
g.definitions.writeln('// multi return structs')
|
|
|
|
for typ in g.table.types {
|
|
|
|
// sym := g.table.get_type_symbol(typ)
|
|
|
|
if typ.kind != .multi_return {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
name := typ.name.replace('.', '__')
|
|
|
|
info := typ.info as table.MultiReturn
|
|
|
|
g.definitions.writeln('typedef struct {')
|
|
|
|
// TODO copy pasta StructDecl
|
|
|
|
// for field in struct_info.fields {
|
|
|
|
for i, mr_typ in info.types {
|
|
|
|
field_type_sym := g.table.get_type_symbol(mr_typ)
|
|
|
|
type_name := field_type_sym.name.replace('.', '__')
|
2020-03-05 00:43:02 +01:00
|
|
|
g.definitions.writeln('\t$type_name arg${i};')
|
2020-03-04 20:17:29 +01:00
|
|
|
}
|
|
|
|
g.definitions.writeln('} $name;\n')
|
|
|
|
// g.typedefs.writeln('typedef struct $name $name;')
|
|
|
|
}
|
2019-12-24 18:54:43 +01:00
|
|
|
}
|
|
|
|
|
2019-12-28 11:02:06 +01:00
|
|
|
pub fn (g &Gen) save() {}
|
2019-12-24 18:54:43 +01:00
|
|
|
|
|
|
|
pub fn (g mut Gen) write(s string) {
|
|
|
|
g.out.write(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn (g mut Gen) writeln(s string) {
|
|
|
|
g.out.writeln(s)
|
|
|
|
}
|
|
|
|
|
2020-02-18 03:17:21 +01:00
|
|
|
pub fn (g mut Gen) new_tmp_var() string {
|
|
|
|
g.tmp_count++
|
|
|
|
return 'tmp$g.tmp_count'
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn (g mut Gen) reset_tmp_count() {
|
|
|
|
g.tmp_count = 0
|
|
|
|
}
|
|
|
|
|
2020-02-07 14:49:14 +01:00
|
|
|
fn (g mut Gen) stmts(stmts []ast.Stmt) {
|
|
|
|
for stmt in stmts {
|
|
|
|
g.stmt(stmt)
|
|
|
|
g.writeln('')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-28 14:11:05 +01:00
|
|
|
fn (g mut Gen) stmt(node ast.Stmt) {
|
2020-01-06 16:13:12 +01:00
|
|
|
// println('cgen.stmt()')
|
|
|
|
// g.writeln('//// stmt start')
|
2019-12-28 14:11:05 +01:00
|
|
|
match node {
|
2020-03-02 18:43:41 +01:00
|
|
|
ast.AssignStmt {
|
|
|
|
// ident0 := it.left[0]
|
|
|
|
// info0 := ident0.var_info()
|
|
|
|
// for i, ident in it.left {
|
|
|
|
// info := ident.var_info()
|
|
|
|
// if info0.typ.typ.kind == .multi_return {
|
|
|
|
// if i == 0 {
|
|
|
|
// g.write('$info.typ.typ.name $ident.name = ')
|
|
|
|
// g.expr(it.right[0])
|
|
|
|
// } else {
|
|
|
|
// arg_no := i-1
|
|
|
|
// g.write('$info.typ.typ.name $ident.name = $ident0.name->arg[$arg_no]')
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// g.writeln(';')
|
|
|
|
// }
|
2020-03-04 15:48:43 +01:00
|
|
|
g.write('') // /*assign*/')
|
2020-03-02 18:43:41 +01:00
|
|
|
}
|
|
|
|
ast.AssertStmt {
|
2020-03-04 15:48:43 +01:00
|
|
|
g.write('// assert')
|
2020-03-02 18:43:41 +01:00
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
ast.Attr {
|
2020-03-05 00:43:02 +01:00
|
|
|
g.writeln('//[$it.name]')
|
2020-03-02 18:43:41 +01:00
|
|
|
}
|
|
|
|
ast.BranchStmt {
|
|
|
|
// continue or break
|
2020-03-05 00:43:02 +01:00
|
|
|
g.write(it.tok.kind.str())
|
|
|
|
g.writeln(';')
|
2020-03-02 18:43:41 +01:00
|
|
|
}
|
2020-02-03 07:02:54 +01:00
|
|
|
ast.ConstDecl {
|
2020-03-06 14:03:35 +01:00
|
|
|
g.const_decl(it)
|
2020-02-03 07:02:54 +01:00
|
|
|
}
|
2020-03-02 18:43:41 +01:00
|
|
|
ast.CompIf {
|
|
|
|
// TODO
|
2020-03-05 00:43:02 +01:00
|
|
|
g.writeln('//#ifdef ')
|
2020-03-02 18:43:41 +01:00
|
|
|
g.expr(it.cond)
|
|
|
|
g.stmts(it.stmts)
|
2020-03-05 00:43:02 +01:00
|
|
|
g.writeln('//#endif')
|
2020-03-02 18:43:41 +01:00
|
|
|
}
|
2020-03-04 15:48:43 +01:00
|
|
|
ast.DeferStmt {
|
|
|
|
g.writeln('// defer')
|
|
|
|
}
|
2020-02-25 11:52:41 +01:00
|
|
|
ast.EnumDecl {
|
2020-02-25 13:30:43 +01:00
|
|
|
g.writeln('typedef enum {')
|
2020-02-25 11:52:41 +01:00
|
|
|
for i, val in it.vals {
|
|
|
|
g.writeln('\t${it.name}_$val, // $i')
|
|
|
|
}
|
2020-02-25 13:30:43 +01:00
|
|
|
g.writeln('} $it.name;')
|
2020-02-25 11:52:41 +01:00
|
|
|
}
|
2020-03-02 18:43:41 +01:00
|
|
|
ast.ExprStmt {
|
|
|
|
g.expr(it.expr)
|
|
|
|
match it.expr {
|
|
|
|
// no ; after an if expression
|
|
|
|
ast.IfExpr {}
|
|
|
|
else {
|
|
|
|
g.writeln(';')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-28 14:11:05 +01:00
|
|
|
ast.FnDecl {
|
2020-02-03 11:13:36 +01:00
|
|
|
g.fn_decl = it // &it
|
2020-03-06 17:05:58 +01:00
|
|
|
g.gen_fn_decl(it)
|
2019-12-28 14:11:05 +01:00
|
|
|
}
|
2020-03-02 18:43:41 +01:00
|
|
|
ast.ForCStmt {
|
|
|
|
g.write('for (')
|
|
|
|
g.stmt(it.init)
|
|
|
|
// g.write('; ')
|
|
|
|
g.expr(it.cond)
|
|
|
|
g.write('; ')
|
2020-03-05 01:20:36 +01:00
|
|
|
// g.stmt(it.inc)
|
2020-03-05 00:43:02 +01:00
|
|
|
g.expr(it.inc)
|
2020-03-02 18:43:41 +01:00
|
|
|
g.writeln(') {')
|
|
|
|
for stmt in it.stmts {
|
|
|
|
g.stmt(stmt)
|
|
|
|
}
|
|
|
|
g.writeln('}')
|
|
|
|
}
|
|
|
|
ast.ForInStmt {
|
2020-03-05 00:43:02 +01:00
|
|
|
if it.is_range {
|
|
|
|
i := g.new_tmp_var()
|
|
|
|
g.write('for (int $i = ')
|
|
|
|
g.expr(it.cond)
|
|
|
|
g.write('; $i < ')
|
|
|
|
g.expr(it.high)
|
|
|
|
g.writeln('; $i++) { ')
|
|
|
|
// g.stmts(it.stmts) TODO
|
|
|
|
g.writeln('}')
|
|
|
|
}
|
2020-03-02 18:43:41 +01:00
|
|
|
}
|
|
|
|
ast.ForStmt {
|
|
|
|
g.write('while (')
|
|
|
|
g.expr(it.cond)
|
|
|
|
g.writeln(') {')
|
|
|
|
for stmt in it.stmts {
|
|
|
|
g.stmt(stmt)
|
|
|
|
}
|
|
|
|
g.writeln('}')
|
|
|
|
}
|
|
|
|
ast.GlobalDecl {
|
2020-03-06 22:36:51 +01:00
|
|
|
styp := g.typ(it.typ)
|
2020-03-06 16:31:40 +01:00
|
|
|
g.definitions.writeln('$styp $it.name; // global')
|
2020-03-02 18:43:41 +01:00
|
|
|
}
|
2020-03-04 15:48:43 +01:00
|
|
|
ast.GotoLabel {
|
|
|
|
g.writeln('$it.name:')
|
|
|
|
}
|
2020-03-02 18:43:41 +01:00
|
|
|
ast.HashStmt {
|
2020-03-05 00:43:02 +01:00
|
|
|
// #include etc
|
|
|
|
g.writeln('#$it.val')
|
2020-03-02 18:43:41 +01:00
|
|
|
}
|
|
|
|
ast.Import {}
|
2019-12-28 14:11:05 +01:00
|
|
|
ast.Return {
|
2020-01-22 21:34:38 +01:00
|
|
|
g.write('return')
|
2020-01-07 12:10:07 +01:00
|
|
|
// multiple returns
|
|
|
|
if it.exprs.len > 1 {
|
2020-02-10 08:32:08 +01:00
|
|
|
type_sym := g.table.get_type_symbol(g.fn_decl.typ)
|
|
|
|
g.write(' ($type_sym.name){')
|
2020-01-07 12:10:07 +01:00
|
|
|
for i, expr in it.exprs {
|
|
|
|
g.write('.arg$i=')
|
|
|
|
g.expr(expr)
|
|
|
|
if i < it.exprs.len - 1 {
|
|
|
|
g.write(',')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g.write('}')
|
|
|
|
}
|
|
|
|
// normal return
|
2020-01-22 21:34:38 +01:00
|
|
|
else if it.exprs.len == 1 {
|
|
|
|
g.write(' ')
|
2020-01-07 12:10:07 +01:00
|
|
|
g.expr(it.exprs[0])
|
|
|
|
}
|
2019-12-28 14:11:05 +01:00
|
|
|
g.writeln(';')
|
|
|
|
}
|
2019-12-30 06:16:59 +01:00
|
|
|
ast.StructDecl {
|
2020-03-04 20:17:29 +01:00
|
|
|
name := it.name.replace('.', '__')
|
2020-03-05 23:27:21 +01:00
|
|
|
// g.writeln('typedef struct {')
|
|
|
|
// for field in it.fields {
|
|
|
|
// field_type_sym := g.table.get_type_symbol(field.typ)
|
|
|
|
// g.writeln('\t$field_type_sym.name $field.name;')
|
|
|
|
// }
|
|
|
|
// g.writeln('} $name;')
|
2020-03-04 17:08:28 +01:00
|
|
|
g.typedefs.writeln('typedef struct $name $name;')
|
2019-12-30 06:16:59 +01:00
|
|
|
}
|
2020-03-04 15:48:43 +01:00
|
|
|
ast.TypeDecl {
|
|
|
|
g.writeln('// type')
|
|
|
|
}
|
2020-03-02 18:43:41 +01:00
|
|
|
ast.UnsafeStmt {
|
|
|
|
g.stmts(it.stmts)
|
|
|
|
}
|
|
|
|
ast.VarDecl {
|
2020-03-06 22:36:51 +01:00
|
|
|
styp := g.typ(it.typ)
|
2020-03-05 01:20:36 +01:00
|
|
|
g.write('$styp $it.name = ')
|
2019-12-28 14:11:05 +01:00
|
|
|
g.expr(it.expr)
|
2020-03-02 18:43:41 +01:00
|
|
|
g.writeln(';')
|
2019-12-28 14:11:05 +01:00
|
|
|
}
|
|
|
|
else {
|
2020-02-25 11:52:41 +01:00
|
|
|
verror('cgen.stmt(): unhandled node ' + typeof(node))
|
2019-12-28 14:11:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-06 17:05:58 +01:00
|
|
|
fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
|
|
|
|
if it.is_c || it.name == 'malloc' || it.no_body {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
g.reset_tmp_count()
|
|
|
|
is_main := it.name == 'main'
|
|
|
|
if is_main {
|
|
|
|
g.write('int ${it.name}(')
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mut name := it.name
|
|
|
|
if it.is_method {
|
|
|
|
name = g.table.get_type_symbol(it.receiver.typ).name + '_' + name
|
|
|
|
}
|
|
|
|
name = name.replace('.', '__')
|
|
|
|
// type_name := g.table.type_to_str(it.typ)
|
2020-03-06 22:36:51 +01:00
|
|
|
type_name := g.typ(it.typ)
|
2020-03-06 17:05:58 +01:00
|
|
|
g.write('$type_name ${name}(')
|
|
|
|
g.definitions.write('$type_name ${name}(')
|
|
|
|
}
|
|
|
|
// Receiver is the first argument
|
|
|
|
if it.is_method {
|
|
|
|
// styp := g.table.type_to_str(it.receiver.typ)
|
|
|
|
sym := g.table.get_type_symbol(it.receiver.typ)
|
|
|
|
styp := sym.name.replace('.', '__')
|
|
|
|
g.write('$styp $it.receiver.name')
|
|
|
|
g.definitions.write('$styp $it.receiver.name')
|
|
|
|
if it.args.len > 0 {
|
|
|
|
g.write(', ')
|
|
|
|
g.definitions.write(', ')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
no_names := it.args.len > 0 && it.args[0].name == 'arg_1'
|
|
|
|
for i, arg in it.args {
|
|
|
|
arg_type_sym := g.table.get_type_symbol(arg.typ)
|
|
|
|
mut arg_type_name := arg_type_sym.name.replace('.', '__')
|
|
|
|
if i == it.args.len - 1 && it.is_variadic {
|
|
|
|
arg_type_name = 'variadic_$arg_type_name'
|
|
|
|
}
|
|
|
|
if no_names {
|
|
|
|
g.write(arg_type_name)
|
|
|
|
g.definitions.write(arg_type_name)
|
|
|
|
}
|
|
|
|
else {
|
2020-03-06 20:22:58 +01:00
|
|
|
nr_muls := table.type_nr_muls(arg.typ)
|
|
|
|
mut s := arg_type_name + ' ' + arg.name
|
|
|
|
if nr_muls > 0 {
|
|
|
|
s = arg_type_name + strings.repeat(`*`, nr_muls) + ' ' + arg.name
|
|
|
|
}
|
|
|
|
g.write(s)
|
|
|
|
g.definitions.write(s)
|
2020-03-06 17:05:58 +01:00
|
|
|
}
|
|
|
|
if i < it.args.len - 1 {
|
|
|
|
g.write(', ')
|
|
|
|
g.definitions.write(', ')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g.writeln(') { ')
|
|
|
|
if !is_main {
|
|
|
|
g.definitions.writeln(');')
|
|
|
|
}
|
|
|
|
for stmt in it.stmts {
|
|
|
|
g.stmt(stmt)
|
|
|
|
}
|
|
|
|
if is_main {
|
|
|
|
g.writeln('return 0;')
|
|
|
|
}
|
|
|
|
g.writeln('}')
|
|
|
|
g.fn_decl = 0
|
|
|
|
}
|
|
|
|
|
2019-12-26 11:27:35 +01:00
|
|
|
fn (g mut Gen) expr(node ast.Expr) {
|
2020-03-04 15:48:43 +01:00
|
|
|
// println('cgen expr() line_nr=$node.pos.line_nr')
|
2019-12-24 18:54:43 +01:00
|
|
|
match node {
|
2020-02-17 22:50:04 +01:00
|
|
|
ast.ArrayInit {
|
|
|
|
type_sym := g.table.get_type_symbol(it.typ)
|
2020-03-05 00:43:02 +01:00
|
|
|
elem_sym := g.table.get_type_symbol(it.elem_type)
|
|
|
|
g.write('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($type_sym.name), ')
|
|
|
|
g.writeln('(${elem_sym.name}[]){\t')
|
2020-02-17 22:50:04 +01:00
|
|
|
for expr in it.exprs {
|
|
|
|
g.expr(expr)
|
|
|
|
g.write(', ')
|
|
|
|
}
|
|
|
|
g.write('\n})')
|
|
|
|
}
|
2020-03-04 15:48:43 +01:00
|
|
|
ast.AsCast {
|
|
|
|
g.write('/* as */')
|
|
|
|
}
|
2020-01-06 16:13:12 +01:00
|
|
|
ast.AssignExpr {
|
|
|
|
g.expr(it.left)
|
|
|
|
g.write(' $it.op.str() ')
|
|
|
|
g.expr(it.val)
|
|
|
|
}
|
2020-03-04 15:48:43 +01:00
|
|
|
ast.Assoc {
|
|
|
|
g.write('/* assoc */')
|
|
|
|
}
|
2020-02-17 22:50:04 +01:00
|
|
|
ast.BoolLiteral {
|
|
|
|
g.write(it.val.str())
|
|
|
|
}
|
2019-12-29 07:24:17 +01:00
|
|
|
ast.CallExpr {
|
2020-03-05 00:43:02 +01:00
|
|
|
mut name := it.name.replace('.', '__')
|
|
|
|
if it.is_c {
|
|
|
|
// Skip "C__"
|
|
|
|
name = name[3..]
|
|
|
|
}
|
2020-03-01 21:56:07 +01:00
|
|
|
g.write('${name}(')
|
2020-03-01 13:07:51 +01:00
|
|
|
g.call_args(it.args)
|
|
|
|
g.write(')')
|
|
|
|
/*
|
2019-12-29 08:51:55 +01:00
|
|
|
for i, expr in it.args {
|
|
|
|
g.expr(expr)
|
|
|
|
if i != it.args.len - 1 {
|
|
|
|
g.write(', ')
|
|
|
|
}
|
|
|
|
}
|
2020-03-01 13:07:51 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
}
|
2020-03-03 18:37:38 +01:00
|
|
|
ast.CastExpr {
|
|
|
|
styp := g.table.type_to_str(it.typ)
|
|
|
|
g.write('($styp)(')
|
2020-03-01 13:07:51 +01:00
|
|
|
g.expr(it.expr)
|
2019-12-29 08:51:55 +01:00
|
|
|
g.write(')')
|
2019-12-29 07:24:17 +01:00
|
|
|
}
|
2020-03-03 18:37:38 +01:00
|
|
|
ast.CharLiteral {
|
|
|
|
g.write("'$it.val'")
|
|
|
|
}
|
|
|
|
ast.EnumVal {
|
|
|
|
g.write('${it.enum_name}_$it.val')
|
|
|
|
}
|
|
|
|
ast.FloatLiteral {
|
|
|
|
g.write(it.val)
|
|
|
|
}
|
2019-12-28 14:11:05 +01:00
|
|
|
ast.Ident {
|
2020-03-01 22:06:36 +01:00
|
|
|
name := it.name.replace('.', '__')
|
|
|
|
g.write(name)
|
2019-12-24 18:54:43 +01:00
|
|
|
}
|
2019-12-29 08:51:55 +01:00
|
|
|
ast.IfExpr {
|
2020-01-02 20:09:15 +01:00
|
|
|
// If expression? Assign the value to a temp var.
|
|
|
|
// Previously ?: was used, but it's too unreliable.
|
2020-02-10 08:32:08 +01:00
|
|
|
type_sym := g.table.get_type_symbol(it.typ)
|
2020-01-02 20:09:15 +01:00
|
|
|
mut tmp := ''
|
2020-02-10 08:32:08 +01:00
|
|
|
if type_sym.kind != .void {
|
2020-02-18 03:17:21 +01:00
|
|
|
tmp = g.new_tmp_var()
|
2020-01-18 23:26:14 +01:00
|
|
|
// g.writeln('$ti.name $tmp;')
|
2020-01-02 20:09:15 +01:00
|
|
|
}
|
2020-03-05 00:43:02 +01:00
|
|
|
// one line ?:
|
|
|
|
// TODO clean this up once `is` is supported
|
|
|
|
if it.stmts.len == 1 && it.else_stmts.len == 1 && type_sym.kind != .void {
|
|
|
|
cond := it.cond
|
|
|
|
stmt1 := it.stmts[0]
|
|
|
|
else_stmt1 := it.else_stmts[0]
|
|
|
|
match stmt1 {
|
|
|
|
ast.ExprStmt {
|
|
|
|
g.expr(cond)
|
|
|
|
g.write(' ? ')
|
|
|
|
expr_stmt := stmt1 as ast.ExprStmt
|
|
|
|
g.expr(expr_stmt.expr)
|
|
|
|
g.write(' : ')
|
|
|
|
g.stmt(else_stmt1)
|
|
|
|
}
|
|
|
|
else {}
|
|
|
|
}
|
2019-12-29 08:51:55 +01:00
|
|
|
}
|
2020-03-05 00:43:02 +01:00
|
|
|
else {
|
|
|
|
g.write('if (')
|
|
|
|
g.expr(it.cond)
|
|
|
|
g.writeln(') {')
|
|
|
|
for i, stmt in it.stmts {
|
|
|
|
// Assign ret value
|
|
|
|
if i == it.stmts.len - 1 && type_sym.kind != .void {}
|
|
|
|
// g.writeln('$tmp =')
|
2019-12-31 19:42:16 +01:00
|
|
|
g.stmt(stmt)
|
|
|
|
}
|
|
|
|
g.writeln('}')
|
2020-03-05 00:43:02 +01:00
|
|
|
if it.else_stmts.len > 0 {
|
|
|
|
g.writeln('else { ')
|
|
|
|
for stmt in it.else_stmts {
|
|
|
|
g.stmt(stmt)
|
|
|
|
}
|
|
|
|
g.writeln('}')
|
|
|
|
}
|
2019-12-31 19:42:16 +01:00
|
|
|
}
|
2019-12-29 08:51:55 +01:00
|
|
|
}
|
2020-03-04 15:48:43 +01:00
|
|
|
ast.IfGuardExpr {
|
|
|
|
g.write('/* guard */')
|
|
|
|
}
|
2020-03-03 18:37:38 +01:00
|
|
|
ast.IndexExpr {
|
|
|
|
g.index_expr(it)
|
|
|
|
}
|
|
|
|
ast.InfixExpr {
|
|
|
|
g.expr(it.left)
|
2020-03-05 23:27:21 +01:00
|
|
|
// if it.op == .dot {
|
|
|
|
// println('!! dot')
|
|
|
|
// }
|
2020-03-03 18:37:38 +01:00
|
|
|
g.write(' $it.op.str() ')
|
|
|
|
g.expr(it.right)
|
|
|
|
// if typ.name != typ2.name {
|
|
|
|
// verror('bad types $typ.name $typ2.name')
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
ast.IntegerLiteral {
|
|
|
|
g.write(it.val.str())
|
|
|
|
}
|
2020-02-07 14:49:14 +01:00
|
|
|
ast.MatchExpr {
|
2020-03-04 15:48:43 +01:00
|
|
|
// println('match expr typ=$it.expr_type')
|
|
|
|
// TODO
|
|
|
|
if it.expr_type == 0 {
|
|
|
|
g.writeln('// match 0')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
type_sym := g.table.get_type_symbol(it.expr_type)
|
2020-02-07 14:49:14 +01:00
|
|
|
mut tmp := ''
|
2020-02-10 08:32:08 +01:00
|
|
|
if type_sym.kind != .void {
|
2020-02-18 03:17:21 +01:00
|
|
|
tmp = g.new_tmp_var()
|
2020-02-07 14:49:14 +01:00
|
|
|
}
|
2020-02-10 08:32:08 +01:00
|
|
|
g.write('$type_sym.name $tmp = ')
|
2020-02-07 14:49:14 +01:00
|
|
|
g.expr(it.cond)
|
|
|
|
g.writeln(';') // $it.blocks.len')
|
2020-03-04 11:59:45 +01:00
|
|
|
for branch in it.branches {
|
|
|
|
g.write('if ')
|
|
|
|
for i, expr in branch.exprs {
|
|
|
|
g.write('$tmp == ')
|
|
|
|
g.expr(expr)
|
2020-03-04 15:48:43 +01:00
|
|
|
if i < branch.exprs.len - 1 {
|
2020-03-04 11:59:45 +01:00
|
|
|
g.write(' || ')
|
|
|
|
}
|
|
|
|
}
|
2020-02-07 14:49:14 +01:00
|
|
|
g.writeln('{')
|
2020-03-04 11:59:45 +01:00
|
|
|
g.stmts(branch.stmts)
|
2020-02-07 14:49:14 +01:00
|
|
|
g.writeln('}')
|
|
|
|
}
|
|
|
|
}
|
2020-03-03 18:37:38 +01:00
|
|
|
ast.MethodCallExpr {
|
2020-03-06 10:52:03 +01:00
|
|
|
mut receiver_name := 'TODO'
|
|
|
|
// TODO: there are still due to unchecked exprs (opt/some fn arg)
|
|
|
|
if it.typ != 0 {
|
|
|
|
typ_sym := g.table.get_type_symbol(it.typ)
|
|
|
|
receiver_name = typ_sym.name
|
|
|
|
}
|
|
|
|
name := '${receiver_name}_$it.name'.replace('.', '__')
|
|
|
|
g.write('${name}(')
|
2020-03-03 18:37:38 +01:00
|
|
|
g.expr(it.expr)
|
|
|
|
if it.args.len > 0 {
|
|
|
|
g.write(', ')
|
|
|
|
}
|
|
|
|
g.call_args(it.args)
|
|
|
|
g.write(')')
|
|
|
|
}
|
2020-03-04 15:48:43 +01:00
|
|
|
ast.None {
|
|
|
|
g.write('0')
|
|
|
|
}
|
2020-03-03 18:37:38 +01:00
|
|
|
ast.ParExpr {
|
|
|
|
g.write('(')
|
|
|
|
g.expr(it.expr)
|
|
|
|
g.write(')')
|
|
|
|
}
|
|
|
|
ast.PostfixExpr {
|
|
|
|
g.expr(it.expr)
|
|
|
|
g.write(it.op.str())
|
|
|
|
}
|
|
|
|
ast.PrefixExpr {
|
|
|
|
g.write(it.op.str())
|
2020-03-06 20:25:38 +01:00
|
|
|
// g.write('/*pref*/')
|
2020-03-03 18:37:38 +01:00
|
|
|
g.expr(it.right)
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
ast.UnaryExpr {
|
|
|
|
// probably not :D
|
|
|
|
if it.op in [.inc, .dec] {
|
|
|
|
g.expr(it.left)
|
|
|
|
g.write(it.op.str())
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
g.write(it.op.str())
|
|
|
|
g.expr(it.left)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
ast.SizeOf {
|
|
|
|
g.write('sizeof($it.type_name)')
|
|
|
|
}
|
|
|
|
ast.StringLiteral {
|
|
|
|
g.write('tos3("$it.val")')
|
|
|
|
}
|
|
|
|
// `user := User{name: 'Bob'}`
|
|
|
|
ast.StructInit {
|
2020-03-06 22:36:51 +01:00
|
|
|
styp := g.typ(it.typ)
|
2020-03-06 14:14:33 +01:00
|
|
|
g.writeln('($styp){')
|
2020-03-03 18:37:38 +01:00
|
|
|
for i, field in it.fields {
|
|
|
|
g.write('\t.$field = ')
|
|
|
|
g.expr(it.exprs[i])
|
|
|
|
g.writeln(', ')
|
|
|
|
}
|
|
|
|
g.write('}')
|
|
|
|
}
|
|
|
|
ast.SelectorExpr {
|
|
|
|
g.expr(it.expr)
|
|
|
|
g.write('.')
|
|
|
|
g.write(it.field)
|
|
|
|
}
|
2020-03-04 15:48:43 +01:00
|
|
|
ast.Type {
|
|
|
|
g.write('/* Type */')
|
|
|
|
}
|
2019-12-24 18:54:43 +01:00
|
|
|
else {
|
2020-03-03 18:37:38 +01:00
|
|
|
// #printf("node=%d\n", node.typ);
|
|
|
|
println(term.red('cgen.expr(): bad node ' + typeof(node)))
|
2019-12-24 18:54:43 +01:00
|
|
|
}
|
|
|
|
}
|
2019-12-26 11:27:35 +01:00
|
|
|
}
|
|
|
|
|
2020-02-02 14:31:54 +01:00
|
|
|
fn (g mut Gen) index_expr(node ast.IndexExpr) {
|
|
|
|
// TODO else doesn't work with sum types
|
|
|
|
mut is_range := false
|
|
|
|
match node.index {
|
|
|
|
ast.RangeExpr {
|
|
|
|
is_range = true
|
|
|
|
g.write('array_slice(')
|
|
|
|
g.expr(node.left)
|
|
|
|
g.write(', ')
|
2020-03-06 22:24:39 +01:00
|
|
|
if it.has_low {
|
|
|
|
g.expr(it.low)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
g.write('0')
|
|
|
|
}
|
2020-02-02 14:31:54 +01:00
|
|
|
g.write(', ')
|
2020-03-06 22:24:39 +01:00
|
|
|
if it.has_high {
|
|
|
|
g.expr(it.high)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
g.expr(node.left)
|
|
|
|
g.write('.len')
|
|
|
|
}
|
2020-02-02 14:31:54 +01:00
|
|
|
g.write(')')
|
2020-03-06 22:24:39 +01:00
|
|
|
return
|
2020-02-02 14:31:54 +01:00
|
|
|
}
|
|
|
|
else {}
|
|
|
|
}
|
2020-03-06 17:05:58 +01:00
|
|
|
// if !is_range && node.container_type == 0 {
|
|
|
|
// }
|
|
|
|
if !is_range && node.container_type != 0 {
|
|
|
|
sym := g.table.get_type_symbol(node.container_type)
|
|
|
|
if sym.kind == .array {
|
|
|
|
g.write('array_get(')
|
|
|
|
g.expr(node.left)
|
|
|
|
g.write(', ')
|
|
|
|
g.expr(node.index)
|
|
|
|
g.write(')')
|
|
|
|
}
|
2020-03-06 20:22:58 +01:00
|
|
|
else if sym.kind == .string {
|
2020-03-06 22:24:39 +01:00
|
|
|
g.write('string_at(')
|
2020-03-06 20:22:58 +01:00
|
|
|
g.expr(node.left)
|
|
|
|
g.write(', ')
|
|
|
|
g.expr(node.index)
|
|
|
|
g.write(')')
|
|
|
|
}
|
|
|
|
// g.write('[')
|
2020-03-06 17:05:58 +01:00
|
|
|
// g.write(']')
|
2020-02-02 14:31:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-06 14:03:35 +01:00
|
|
|
fn (g mut Gen) const_decl(node ast.ConstDecl) {
|
|
|
|
for i, field in node.fields {
|
|
|
|
name := field.name.replace('.', '__')
|
|
|
|
expr := node.exprs[i]
|
|
|
|
match expr {
|
|
|
|
// Simple expressions should use a #define
|
|
|
|
// so that we don't pollute the binary with unnecessary global vars
|
|
|
|
// Do not do this when building a module, otherwise the consts
|
|
|
|
// will not be accessible.
|
|
|
|
ast.CharLiteral, ast.IntegerLiteral {
|
|
|
|
g.write('#define $name ')
|
|
|
|
g.expr(expr)
|
|
|
|
g.writeln('')
|
|
|
|
}
|
|
|
|
else {
|
2020-03-06 22:36:51 +01:00
|
|
|
styp := g.typ(field.typ)
|
2020-03-06 16:31:40 +01:00
|
|
|
g.definitions.writeln('$styp $name; // inited later') // = ')
|
2020-03-06 14:03:35 +01:00
|
|
|
// TODO
|
|
|
|
// g.expr(node.exprs[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-01 13:07:51 +01:00
|
|
|
fn (g mut Gen) call_args(args []ast.Expr) {
|
|
|
|
for i, expr in args {
|
|
|
|
g.expr(expr)
|
|
|
|
if i != args.len - 1 {
|
|
|
|
g.write(', ')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-26 11:27:35 +01:00
|
|
|
fn verror(s string) {
|
2020-03-04 15:48:43 +01:00
|
|
|
println('cgen error: $s')
|
|
|
|
// exit(1)
|
2019-12-24 18:54:43 +01:00
|
|
|
}
|
2020-03-05 23:27:21 +01:00
|
|
|
// C struct definitions, ordered
|
|
|
|
// Sort the types, make sure types that are referenced by other types
|
|
|
|
// are added before them.
|
|
|
|
fn (g mut Gen) write_sorted_types() {
|
|
|
|
mut types := []table.TypeSymbol // structs that need to be sorted
|
|
|
|
// builtin_types := [
|
|
|
|
mut builtin_types := []table.TypeSymbol // builtin types
|
|
|
|
// builtin types need to be on top
|
|
|
|
builtins := ['string', 'array', 'KeyValue', 'map', 'Option']
|
|
|
|
// everything except builtin will get sorted
|
2020-03-06 16:57:27 +01:00
|
|
|
for builtin_name in builtins {
|
|
|
|
builtin_types << g.table.types[g.table.type_idxs[builtin_name]]
|
|
|
|
}
|
2020-03-06 12:01:56 +01:00
|
|
|
for typ in g.table.types {
|
2020-03-06 16:57:27 +01:00
|
|
|
if !(typ.name in builtins) {
|
|
|
|
types << typ
|
2020-03-05 23:27:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// sort structs
|
|
|
|
types_sorted := g.sort_structs(types)
|
|
|
|
// Generate C code
|
|
|
|
g.definitions.writeln('// builtin types:')
|
|
|
|
g.write_types(builtin_types)
|
2020-03-06 20:22:58 +01:00
|
|
|
g.definitions.writeln('//------------------ #endbuiltin')
|
2020-03-05 23:27:21 +01:00
|
|
|
g.write_types(types_sorted)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (g mut Gen) write_types(types []table.TypeSymbol) {
|
|
|
|
for typ in types {
|
|
|
|
// sym := g.table.get_type_symbol(typ)
|
|
|
|
match typ.info {
|
|
|
|
table.Struct {
|
|
|
|
info := typ.info as table.Struct
|
|
|
|
name := typ.name.replace('.', '__')
|
|
|
|
// g.definitions.writeln('typedef struct {')
|
|
|
|
g.definitions.writeln('struct $name {')
|
|
|
|
for field in info.fields {
|
|
|
|
field_type_sym := g.table.get_type_symbol(field.typ)
|
|
|
|
type_name := field_type_sym.name.replace('.', '__')
|
|
|
|
g.definitions.writeln('\t$type_name $field.name;')
|
|
|
|
}
|
|
|
|
// g.definitions.writeln('} $name;\n')
|
|
|
|
//
|
|
|
|
g.definitions.writeln('};\n')
|
|
|
|
}
|
|
|
|
else {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// sort structs by dependant fields
|
|
|
|
fn (g &Gen) sort_structs(types []table.TypeSymbol) []table.TypeSymbol {
|
|
|
|
mut dep_graph := depgraph.new_dep_graph()
|
|
|
|
// types name list
|
|
|
|
mut type_names := []string
|
|
|
|
for typ in types {
|
|
|
|
type_names << typ.name
|
|
|
|
}
|
|
|
|
// loop over types
|
|
|
|
for t in types {
|
2020-03-06 12:01:56 +01:00
|
|
|
// create list of deps
|
|
|
|
mut field_deps := []string
|
2020-03-05 23:27:21 +01:00
|
|
|
match t.info {
|
|
|
|
table.Struct {
|
|
|
|
info := t.info as table.Struct
|
|
|
|
for field in info.fields {
|
|
|
|
// Need to handle fixed size arrays as well (`[10]Point`)
|
|
|
|
// ft := if field.typ.starts_with('[') { field.typ.all_after(']') } else { field.typ }
|
2020-03-06 12:01:56 +01:00
|
|
|
dep := g.table.get_type_symbol(field.typ).name
|
2020-03-05 23:27:21 +01:00
|
|
|
// skip if not in types list or already in deps
|
2020-03-06 20:22:58 +01:00
|
|
|
if !(dep in type_names) || dep in field_deps || table.type_is_ptr(field.typ) {
|
2020-03-06 12:01:56 +01:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
field_deps << dep
|
2020-03-05 23:27:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {}
|
2020-03-06 14:03:35 +01:00
|
|
|
}
|
2020-03-06 12:01:56 +01:00
|
|
|
// add type and dependant types to graph
|
|
|
|
dep_graph.add(t.name, field_deps)
|
2020-03-05 23:27:21 +01:00
|
|
|
}
|
|
|
|
// sort graph
|
|
|
|
dep_graph_sorted := dep_graph.resolve()
|
|
|
|
if !dep_graph_sorted.acyclic {
|
|
|
|
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')
|
|
|
|
}
|
|
|
|
// sort types
|
|
|
|
mut types_sorted := []table.TypeSymbol
|
|
|
|
for node in dep_graph_sorted.nodes {
|
2020-03-06 16:57:27 +01:00
|
|
|
types_sorted << g.table.types[g.table.type_idxs[node.name]]
|
2020-03-05 23:27:21 +01:00
|
|
|
}
|
|
|
|
return types_sorted
|
|
|
|
}
|