cgen: lots of fixes

pull/3949/head
Alexander Medvednikov 2020-03-10 23:21:26 +01:00
parent 1143320b8b
commit de55a26cfe
12 changed files with 214 additions and 94 deletions

View File

@ -255,7 +255,7 @@ fn (a array) slice2(start, _end int, end_max bool) array {
} }
// array.clone returns an independent copy of a given array // array.clone returns an independent copy of a given array
pub fn (a array) clone() array { pub fn (a &array) clone() array {
mut size := a.cap * a.element_size mut size := a.cap * a.element_size
if size == 0 { if size == 0 {
size++ size++
@ -270,7 +270,7 @@ pub fn (a array) clone() array {
return arr return arr
} }
fn (a array) slice_clone(start, _end int) array { fn (a &array) slice_clone(start, _end int) array {
mut end := _end mut end := _end
$if !no_bounds_checking? { $if !no_bounds_checking? {
if start > end { if start > end {
@ -316,8 +316,6 @@ pub fn (a3 mut array) push_many(val voidptr, size int) {
// handle `arr << arr` // handle `arr << arr`
copy := a3.clone() copy := a3.clone()
a3.ensure_cap(a3.len + size) a3.ensure_cap(a3.len + size)
C.printf("%d", a3.len*2)
println(a3.len*2)
//C.memcpy(a.data, copy.data, copy.element_size * copy.len) //C.memcpy(a.data, copy.data, copy.element_size * copy.len)
C.memcpy(a3.data + a3.element_size * a3.len, copy.data, a3.element_size * size) C.memcpy(a3.data + a3.element_size * a3.len, copy.data, a3.element_size * size)
} else { } else {

View File

@ -190,7 +190,7 @@ pub fn (c rune) str() string {
for i in 0..len { for i in 0..len {
str.str[i] = int(c)>>8 * (3 - i) & 0xff str.str[i] = int(c)>>8 * (3 - i) & 0xff
} }
str[len] = `\0` str.str[len] = `\0`
return str return str
} }

View File

@ -40,6 +40,11 @@ pub fn (b mut Builder) write(s string) {
b.len += s.len b.len += s.len
} }
pub fn (b mut Builder) go_back(n int) {
b.buf.trim(b.buf.len-n)
//b.len -= n
}
pub fn (b mut Builder) writeln(s string) { pub fn (b mut Builder) writeln(s string) {
// for c in s { // for c in s {
// b.buf << c // b.buf << c

View File

@ -161,6 +161,7 @@ mut:
// func Expr // func Expr
name string name string
args []Expr args []Expr
arg_types []table.Type
is_c bool is_c bool
muts []bool muts []bool
or_block OrExpr or_block OrExpr
@ -171,12 +172,14 @@ pub struct MethodCallExpr {
pub: pub:
// tok token.Token // tok token.Token
pos token.Position pos token.Position
expr Expr expr Expr // `user` in `user.register()`
name string name string
args []Expr args []Expr
muts []bool muts []bool
or_block OrExpr or_block OrExpr
mut: mut:
expr_type table.Type // type of `user`
receiver_type table.Type // User
typ table.Type typ table.Type
} }

View File

@ -22,6 +22,7 @@ mut:
errors []string errors []string
expected_type table.Type expected_type table.Type
fn_return_type table.Type // current function's return type fn_return_type table.Type // current function's return type
// is_amp bool
} }
pub fn new_checker(table &table.Table) Checker { pub fn new_checker(table &table.Table) Checker {
@ -250,7 +251,7 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
// TODO: clean this up, remove dupe code & consider merging method/fn call everywhere // TODO: clean this up, remove dupe code & consider merging method/fn call everywhere
pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr) table.Type { pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr) table.Type {
typ := c.expr(method_call_expr.expr) typ := c.expr(method_call_expr.expr)
method_call_expr.typ = typ method_call_expr.expr_type = typ
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
name := method_call_expr.name name := method_call_expr.name
if typ_sym.kind == .array && name in ['filter', 'clone'] { if typ_sym.kind == .array && name in ['filter', 'clone'] {
@ -281,6 +282,10 @@ pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr)
return typ return typ
} }
if method := typ_sym.find_method(name) { if method := typ_sym.find_method(name) {
if name == 'clone' {
println('CLONE nr args=$method.args.len')
}
method_call_expr.receiver_type = method.args[0].typ
for i, arg_expr in method_call_expr.args { for i, arg_expr in method_call_expr.args {
c.expected_type = method.args[i].typ c.expected_type = method.args[i].typ
c.expr(arg_expr) c.expr(arg_expr)

View File

@ -19,6 +19,7 @@ mut:
is_c_call bool // e.g. `C.printf("v")` is_c_call bool // e.g. `C.printf("v")`
is_assign_expr bool is_assign_expr bool
is_array_set bool is_array_set bool
is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
} }
pub fn cgen(files []ast.File, table &table.Table) string { pub fn cgen(files []ast.File, table &table.Table) string {
@ -42,6 +43,7 @@ pub fn (g mut Gen) init() {
g.definitions.writeln('#include <inttypes.h>') // int64_t etc g.definitions.writeln('#include <inttypes.h>') // int64_t etc
g.definitions.writeln(c_builtin_types) g.definitions.writeln(c_builtin_types)
g.definitions.writeln(c_headers) g.definitions.writeln(c_headers)
g.write_builtin_types()
g.write_array_types() g.write_array_types()
g.write_sorted_types() g.write_sorted_types()
g.write_multi_return_types() g.write_multi_return_types()
@ -211,7 +213,12 @@ fn (g mut Gen) stmt(node ast.Stmt) {
} }
ast.ForStmt { ast.ForStmt {
g.write('while (') g.write('while (')
if it.is_inf {
g.write('1')
}
else {
g.expr(it.cond) g.expr(it.cond)
}
g.writeln(') {') g.writeln(') {')
for stmt in it.stmts { for stmt in it.stmts {
g.stmt(stmt) g.stmt(stmt)
@ -289,19 +296,19 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
panic('expected call') panic('expected call')
} }
} }
mr_typ_sym := g.table.get_type_symbol(return_type)
mr_var_name := 'mr_$assign_stmt.pos.pos' mr_var_name := 'mr_$assign_stmt.pos.pos'
g.write('$mr_typ_sym.name $mr_var_name = ') mr_typ_str := g.typ(return_type)
g.write('$mr_typ_str $mr_var_name = ')
g.expr(assign_stmt.right[0]) g.expr(assign_stmt.right[0])
g.writeln(';') g.writeln(';')
for i, ident in assign_stmt.left { for i, ident in assign_stmt.left {
ident_var_info := ident.var_info() ident_var_info := ident.var_info()
var_type_sym := g.table.get_type_symbol(ident_var_info.typ) styp := g.typ(ident_var_info.typ)
if ident.kind == .blank_ident { if ident.kind == .blank_ident {
g.writeln('{$var_type_sym.name _ = $mr_var_name->arg[$i]};') g.writeln('{ $styp _ = ${mr_var_name}.arg$i};')
} }
else { else {
g.writeln('$var_type_sym.name $ident.name = $mr_var_name->arg[$i];') g.writeln('$styp $ident.name = ${mr_var_name}.arg$i;')
} }
} }
} }
@ -310,24 +317,29 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
for i, ident in assign_stmt.left { for i, ident in assign_stmt.left {
val := assign_stmt.right[i] val := assign_stmt.right[i]
ident_var_info := ident.var_info() ident_var_info := ident.var_info()
var_type_sym := g.table.get_type_symbol(ident_var_info.typ) styp := g.typ(ident_var_info.typ)
if ident.kind == .blank_ident { if ident.kind == .blank_ident {
is_call := match val { is_call := match val {
ast.CallExpr { true } ast.CallExpr{
ast.MethodCallExpr { true } true
else { false } }
ast.MethodCallExpr{
true
}
else {
false}
} }
if is_call { if is_call {
g.expr(val) g.expr(val)
} }
else { else {
g.write('{$var_type_sym.name _ = ') g.write('{$styp _ = ')
g.expr(val) g.expr(val)
g.write('}') g.write('}')
} }
} }
else { else {
g.write('$var_type_sym.name $ident.name = ') g.write('$styp $ident.name = ')
g.expr(val) g.expr(val)
} }
g.writeln(';') g.writeln(';')
@ -359,6 +371,7 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
g.definitions.write('$type_name ${name}(') g.definitions.write('$type_name ${name}(')
} }
// Receiver is the first argument // Receiver is the first argument
/*
if it.is_method { if it.is_method {
mut styp := g.typ(it.receiver.typ) mut styp := g.typ(it.receiver.typ)
// if table.type_nr_muls(it.receiver.typ) > 0 { // if table.type_nr_muls(it.receiver.typ) > 0 {
@ -373,6 +386,7 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
g.definitions.write(', ') g.definitions.write(', ')
} }
} }
*/
// //
no_names := it.args.len > 0 && it.args[0].name == 'arg_1' no_names := it.args.len > 0 && it.args[0].name == 'arg_1'
for i, arg in it.args { for i, arg in it.args {
@ -459,13 +473,24 @@ fn (g mut Gen) expr(node ast.Expr) {
name = name[3..] name = name[3..]
} }
g.write('${name}(') g.write('${name}(')
g.call_args(it.args) g.call_args(it.args, it.muts)
g.write(')') g.write(')')
g.is_c_call = false g.is_c_call = false
} }
ast.CastExpr { ast.CastExpr {
// g.write('/*cast*/')
if g.is_amp {
// &Foo(0) => ((Foo*)0)
g.out.go_back(1)
}
if it.typ == table.string_type_idx { if it.typ == table.string_type_idx {
// tos(str, len), tos2(str)
if it.has_arg {
g.write('tos(') g.write('tos(')
}
else {
g.write('tos2(')
}
g.expr(it.expr) g.expr(it.expr)
if it.has_arg { if it.has_arg {
g.write(',') g.write(',')
@ -474,10 +499,16 @@ fn (g mut Gen) expr(node ast.Expr) {
g.write(')') g.write(')')
} }
else { else {
styp := g.table.type_to_str(it.typ) // styp := g.table.type_to_str(it.typ)
g.write('($styp)(') styp := g.typ(it.typ)
// g.write('($styp)(')
g.write('(($styp)(')
// if g.is_amp {
// g.write('*')
// }
// g.write(')(')
g.expr(it.expr) g.expr(it.expr)
g.write(')') g.write('))')
} }
} }
ast.CharLiteral { ast.CharLiteral {
@ -491,8 +522,13 @@ fn (g mut Gen) expr(node ast.Expr) {
} }
ast.Ident { ast.Ident {
name := it.name.replace('.', '__') name := it.name.replace('.', '__')
if name.starts_with('C__') {
g.write(name[3..])
}
else {
g.write(name) g.write(name)
} }
}
ast.IfExpr { ast.IfExpr {
// If expression? Assign the value to a temp var. // If expression? Assign the value to a temp var.
// Previously ?: was used, but it's too unreliable. // Previously ?: was used, but it's too unreliable.
@ -544,9 +580,11 @@ fn (g mut Gen) expr(node ast.Expr) {
g.write('/* guard */') g.write('/* guard */')
} }
ast.IndexExpr { ast.IndexExpr {
//
g.index_expr(it) g.index_expr(it)
} }
ast.InfixExpr { ast.InfixExpr {
// sdf
g.infix_expr(it) g.infix_expr(it)
} }
ast.IntegerLiteral { ast.IntegerLiteral {
@ -614,20 +652,30 @@ fn (g mut Gen) expr(node ast.Expr) {
ast.MethodCallExpr { ast.MethodCallExpr {
mut receiver_name := 'TODO' mut receiver_name := 'TODO'
// TODO: there are still due to unchecked exprs (opt/some fn arg) // TODO: there are still due to unchecked exprs (opt/some fn arg)
if it.typ != 0 { if it.expr_type != 0 {
typ_sym := g.table.get_type_symbol(it.typ) typ_sym := g.table.get_type_symbol(it.expr_type)
receiver_name = typ_sym.name receiver_name = typ_sym.name
// if typ_sym.kind == .array { if typ_sym.kind == .array && receiver_name.starts_with('array_') {
// receiver_name = 'array' // array_byte_clone => array_clone
// } receiver_name = 'array'
}
} }
name := '${receiver_name}_$it.name'.replace('.', '__') name := '${receiver_name}_$it.name'.replace('.', '__')
// if it.receiver_type != 0 {
// g.write('/*${g.typ(it.receiver_type)}*/')
// g.write('/*expr_type=${g.typ(it.expr_type)} rec type=${g.typ(it.receiver_type)}*/')
// }
g.write('${name}(') g.write('${name}(')
if table.type_is_ptr(it.receiver_type) && !table.type_is_ptr(it.expr_type) {
// The receiver is a reference, but the caller provided a value
// Add `&` automatically.
g.write('&')
}
g.expr(it.expr) g.expr(it.expr)
if it.args.len > 0 { if it.args.len > 0 {
g.write(', ') g.write(', ')
} }
g.call_args(it.args) g.call_args(it.args, it.muts)
g.write(')') g.write(')')
} }
ast.None { ast.None {
@ -643,9 +691,13 @@ fn (g mut Gen) expr(node ast.Expr) {
g.write(it.op.str()) g.write(it.op.str())
} }
ast.PrefixExpr { ast.PrefixExpr {
g.write(it.op.str()) if it.op == .amp {
g.is_amp = true
}
// g.write('/*pref*/') // g.write('/*pref*/')
g.write(it.op.str())
g.expr(it.right) g.expr(it.right)
g.is_amp = false
} }
/* /*
ast.UnaryExpr { ast.UnaryExpr {
@ -677,13 +729,22 @@ fn (g mut Gen) expr(node ast.Expr) {
// `user := User{name: 'Bob'}` // `user := User{name: 'Bob'}`
ast.StructInit { ast.StructInit {
styp := g.typ(it.typ) styp := g.typ(it.typ)
if g.is_amp {
g.out.go_back(1) // delete the & already generated in `prefix_expr()
g.write('($styp*)memdup(&($styp){')
}
else {
g.writeln('($styp){') g.writeln('($styp){')
}
for i, field in it.fields { for i, field in it.fields {
g.write('\t.$field = ') g.write('\t.$field = ')
g.expr(it.exprs[i]) g.expr(it.exprs[i])
g.writeln(', ') g.writeln(', ')
} }
g.write('}') g.write('}')
if g.is_amp {
g.write(', sizeof($styp))')
}
} }
ast.SelectorExpr { ast.SelectorExpr {
g.expr(it.expr) g.expr(it.expr)
@ -731,14 +792,27 @@ fn (g mut Gen) infix_expr(it ast.InfixExpr) {
g.expr(it.right) g.expr(it.right)
g.write(')') g.write(')')
} }
// arr << val else if it.op == .key_in {
else if it.op == .left_shift && g.table.get_type_symbol(it.left_type).kind == .array { styp := g.typ(it.left_type)
g.write('array_push(') g.write('_IN($styp, ')
g.expr(it.left) g.expr(it.left)
g.write(', ') g.write(', ')
g.expr(it.right) g.expr(it.right)
g.write(')') g.write(')')
} }
// arr << val
else if it.op == .left_shift && g.table.get_type_symbol(it.left_type).kind == .array {
sym := g.table.get_type_symbol(it.left_type)
info := sym.info as table.Array
elem_type_str := g.typ(info.elem_type)
// g.write('array_push(&')
tmp := g.new_tmp_var()
g.write('_PUSH(&')
g.expr(it.left)
g.write(', ')
g.expr(it.right)
g.write(', $tmp, $elem_type_str)')
}
else { else {
// if it.op == .dot { // if it.op == .dot {
// println('!! dot') // println('!! dot')
@ -847,8 +921,11 @@ fn (g mut Gen) const_decl(node ast.ConstDecl) {
} }
} }
fn (g mut Gen) call_args(args []ast.Expr) { fn (g mut Gen) call_args(args []ast.Expr, muts []bool) {
for i, expr in args { for i, expr in args {
if muts[i] {
g.write('&/*mut*/')
}
g.expr(expr) g.expr(expr)
if i != args.len - 1 { if i != args.len - 1 {
g.write(', ') g.write(', ')
@ -860,19 +937,26 @@ fn verror(s string) {
println('cgen error: $s') println('cgen error: $s')
// exit(1) // exit(1)
} }
const (
builtins = ['string', 'array', 'KeyValue', 'map', 'Option']
)
fn (g mut Gen) write_builtin_types() {
mut builtin_types := []table.TypeSymbol // builtin types
// builtin types need to be on top
// everything except builtin will get sorted
for builtin_name in builtins {
builtin_types << g.table.types[g.table.type_idxs[builtin_name]]
}
g.write_types(builtin_types)
}
// C struct definitions, ordered // C struct definitions, ordered
// Sort the types, make sure types that are referenced by other types // Sort the types, make sure types that are referenced by other types
// are added before them. // are added before them.
fn (g mut Gen) write_sorted_types() { fn (g mut Gen) write_sorted_types() {
mut types := []table.TypeSymbol // structs that need to be sorted 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
for builtin_name in builtins {
builtin_types << g.table.types[g.table.type_idxs[builtin_name]]
}
for typ in g.table.types { for typ in g.table.types {
if !(typ.name in builtins) { if !(typ.name in builtins) {
types << typ types << typ
@ -882,7 +966,7 @@ fn (g mut Gen) write_sorted_types() {
types_sorted := g.sort_structs(types) types_sorted := g.sort_structs(types)
// Generate C code // Generate C code
g.definitions.writeln('// builtin types:') g.definitions.writeln('// builtin types:')
g.write_types(builtin_types) // g.write_types(builtin_types)
g.definitions.writeln('//------------------ #endbuiltin') g.definitions.writeln('//------------------ #endbuiltin')
g.write_types(types_sorted) g.write_types(types_sorted)
} }

View File

@ -7,14 +7,14 @@ import (
const ( const (
nr_tests = 4 nr_tests = 4
term_ok = term.ok_message('OK')
term_fail = term.fail_message('FAIL')
) )
fn test_c_files() { fn test_c_files() {
println('Running V => C tests') println('Running V => C tests')
vexe := os.getenv('VEXE') vexe := os.getenv('VEXE')
vroot := os.dir(vexe) vroot := os.dir(vexe)
term_ok := term.ok_message('OK')
term_fail := term.fail_message('FAIL')
for i in 1 .. (nr_tests + 1) { for i in 1 .. (nr_tests + 1) {
path := '$vroot/vlib/v/gen/tests/${i}.vv' path := '$vroot/vlib/v/gen/tests/${i}.vv'
mut ctext := os.read_file('$vroot/vlib/v/gen/tests/${i}.c') or { mut ctext := os.read_file('$vroot/vlib/v/gen/tests/${i}.c') or {
@ -24,30 +24,31 @@ fn test_c_files() {
mut b := builder.new_builder(pref.Preferences{}) mut b := builder.new_builder(pref.Preferences{})
b.module_search_paths = ['$vroot/vlib/v/gen/tests/'] b.module_search_paths = ['$vroot/vlib/v/gen/tests/']
res := b.gen_c([path]).after('#endbuiltin') res := b.gen_c([path]).after('#endbuiltin')
if compare_texts(res, ctext) { if compare_texts(res, ctext, path) {
eprintln('${term_ok} ${i}') println('${term_ok} ${i}')
} }
else { else {
eprintln('${term_fail} ${i}')
eprintln('${path}: got\n$res')
assert false assert false
} }
} }
} }
fn compare_texts(a, b string) bool { fn compare_texts(a, b, path string) bool {
lines_a_ := a.trim_space().split_into_lines() lines_a_ := a.trim_space().split_into_lines()
lines_b_ := b.trim_space().split_into_lines() lines_b_ := b.trim_space().split_into_lines()
lines_a := lines_a_.filter(it != '') lines_a := lines_a_.filter(it != '')
lines_b := lines_b_.filter(it != '') lines_b := lines_b_.filter(it != '')
if lines_a.len != lines_b.len { if lines_a.len != lines_b.len {
println(term.red('different len')) println(term.red('different len'))
// return false println('${path}: got\n$a')
return false
} }
for i, line_a in lines_a { for i, line_a in lines_a {
line_b := lines_b[i] line_b := lines_b[i]
if line_a.trim_space() != line_b.trim_space() { if line_a.trim_space() != line_b.trim_space() {
println(term.red('i=$i V="$line_a" C="$line_b"')) println('${path}: got\n$a')
println('${term_fail} ${i}')
println(term.red('i=$i "$line_a" expected="$line_b"'))
// exit(1) // exit(1)
return false return false
} }

View File

@ -294,6 +294,7 @@ typedef array array_u32;
typedef array array_u64; typedef array array_u64;
typedef map map_int; typedef map map_int;
typedef map map_string; typedef map map_string;
typedef byte array_fixed_byte_300 [300];
#ifndef bool #ifndef bool
typedef int bool; typedef int bool;
#define true 1 #define true 1

View File

@ -52,7 +52,9 @@ int main() {
localmod__pub_foo(); localmod__pub_foo();
int ten = localmod__get_int_10(); int ten = localmod__get_int_10();
println(localmod__pub_int_const); println(localmod__pub_int_const);
int g = (int)(3.0); int g = ((int)(3.0));
byte* bytes = ((byte*)(0));
User user_ptr = (User*)memdup(&(User){}, sizeof(User));
return 0; return 0;
} }

View File

@ -34,6 +34,8 @@ fn main() {
ten := localmod.get_int_10() ten := localmod.get_int_10()
println(localmod.pub_int_const) println(localmod.pub_int_const)
g := int(3.0) g := int(3.0)
bytes := &byte(0)
user_ptr := &User{}
} }
/* /*
user := User{} user := User{}

View File

@ -75,6 +75,8 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
mut is_method := false mut is_method := false
mut rec_type := table.void_type mut rec_type := table.void_type
mut rec_mut := false mut rec_mut := false
mut args := []table.Var
mut ast_args := []ast.Arg
if p.tok.kind == .lpar { if p.tok.kind == .lpar {
is_method = true is_method = true
p.next() p.next()
@ -84,6 +86,15 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
rec_mut = true rec_mut = true
} }
rec_type = p.parse_type() rec_type = p.parse_type()
args << table.Var{
// Receiver is the first arg
typ: rec_type
name: rec_name
}
ast_args << ast.Arg{
name: rec_name
typ: rec_type
}
// p.table.register_var(table.Var{ // p.table.register_var(table.Var{
// name: rec_name // name: rec_name
// typ: rec_type // typ: rec_type
@ -111,8 +122,8 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
} }
// println('fn decl $name') // println('fn decl $name')
// Args // Args
mut args := []table.Var ast_args2,is_variadic := p.fn_args()
ast_args,is_variadic := p.fn_args() ast_args << ast_args2
for ast_arg in ast_args { for ast_arg in ast_args {
var := table.Var{ var := table.Var{
name: ast_arg.name name: ast_arg.name

View File

@ -44,6 +44,7 @@ mut:
scope &ast.Scope scope &ast.Scope
imports map[string]string imports map[string]string
ast_imports []ast.Import ast_imports []ast.Import
is_amp bool
} }
// for tests // for tests
@ -558,7 +559,11 @@ pub fn (p mut Parser) name_expr() ast.Expr {
// if name in table.builtin_type_names { // if name in table.builtin_type_names {
if (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) && !(name in ['C.stat', 'C.sigaction']) { if (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) && !(name in ['C.stat', 'C.sigaction']) {
// TODO handle C.stat() // TODO handle C.stat()
to_typ := p.parse_type() mut to_typ := p.parse_type()
if p.is_amp {
// Handle `&Foo(0)`
to_typ = table.type_to_ptr(to_typ)
}
p.check(.lpar) p.check(.lpar)
mut expr := ast.Expr{} mut expr := ast.Expr{}
mut arg := ast.Expr{} mut arg := ast.Expr{}
@ -810,8 +815,12 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
fn (p mut Parser) prefix_expr() ast.PrefixExpr { fn (p mut Parser) prefix_expr() ast.PrefixExpr {
op := p.tok.kind op := p.tok.kind
if op == .amp {
p.is_amp = true
}
p.next() p.next()
right := p.expr(1) right := p.expr(1)
p.is_amp = false
return ast.PrefixExpr{ return ast.PrefixExpr{
op: op op: op
right: right right: right
@ -1715,7 +1724,6 @@ fn (p mut Parser) type_decl() ast.TypeDecl {
sub_types: sum_variants sub_types: sum_variants
} }
} }
// type MyType int // type MyType int
parent_type := p.parse_type() parent_type := p.parse_type()
pid := table.type_idx(parent_type) pid := table.type_idx(parent_type)