v: cleanup & fixes. update variadic & multiple return

pull/3358/head
joe-conigliaro 2020-01-07 22:10:07 +11:00 committed by Alexander Medvednikov
parent 8c5923297e
commit b7509577b5
10 changed files with 121 additions and 57 deletions

View File

@ -121,7 +121,7 @@ pub:
pub struct Return { pub struct Return {
pub: pub:
expr Expr exprs []Expr
} }
/* /*

View File

@ -4,6 +4,7 @@ import (
strings strings
v.ast v.ast
v.table v.table
v.types
term term
) )
@ -11,6 +12,8 @@ struct Gen {
out strings.Builder out strings.Builder
definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file) definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
table &table.Table table &table.Table
mut:
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
} }
pub fn cgen(files []ast.File, table &table.Table) string { pub fn cgen(files []ast.File, table &table.Table) string {
@ -19,6 +22,7 @@ pub fn cgen(files []ast.File, table &table.Table) string {
out: strings.new_builder(100) out: strings.new_builder(100)
definitions: strings.new_builder(100) definitions: strings.new_builder(100)
table: table table: table
fn_decl: 0
} }
for file in files { for file in files {
for stmt in file.stmts { for stmt in file.stmts {
@ -45,6 +49,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
match node { match node {
ast.Import {} ast.Import {}
ast.FnDecl { ast.FnDecl {
g.fn_decl = &it
is_main := it.name == 'main' is_main := it.name == 'main'
if is_main { if is_main {
g.write('int ${it.name}(') g.write('int ${it.name}(')
@ -53,8 +58,11 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.write('$it.ti.name ${it.name}(') g.write('$it.ti.name ${it.name}(')
g.definitions.write('$it.ti.name ${it.name}(') g.definitions.write('$it.ti.name ${it.name}(')
} }
for arg in it.args { for i, arg in it.args {
g.write(arg.ti.name + ' ' + arg.name) g.write(arg.ti.name + ' ' + arg.name)
if i < it.args.len - 1 {
g.write(', ')
}
g.definitions.write(arg.ti.name + ' ' + arg.name) g.definitions.write(arg.ti.name + ' ' + arg.name)
} }
g.writeln(') { ') g.writeln(') { ')
@ -68,10 +76,26 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.writeln('return 0;') g.writeln('return 0;')
} }
g.writeln('}') g.writeln('}')
g.fn_decl = 0
} }
ast.Return { ast.Return {
g.write('return ') g.write('return ')
g.expr(it.expr) // multiple returns
if it.exprs.len > 1 {
g.write('($g.fn_decl.ti.name){')
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
else {
g.expr(it.exprs[0])
}
g.writeln(';') g.writeln(';')
} }
ast.VarDecl { ast.VarDecl {

View File

@ -46,7 +46,12 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
} }
ast.Return { ast.Return {
g.write('return ') g.write('return ')
g.expr(it.expr) if it.exprs.len > 0 {
}
else {
g.expr(it.exprs[0])
}
g.writeln(';') g.writeln(';')
} }
ast.VarDecl { ast.VarDecl {

View File

@ -2,6 +2,7 @@ void foo(int a);
int get_int(string a); int get_int(string a);
int get_int2(); int get_int2();
void myuser(); void myuser();
multi_return_int_string multi_return();
void variadic(variadic_int a); void variadic(variadic_int a);
typedef struct { typedef struct {
@ -49,5 +50,9 @@ void myuser() {
bool b2 = user.age > 0; bool b2 = user.age > 0;
} }
multi_return_int_string multi_return() {
return (multi_return_int_string){.arg0=4,.arg1=tos3("four")};
}
void variadic(variadic_int a) { void variadic(variadic_int a) {
} }

View File

@ -51,5 +51,10 @@ fn myuser() {
b2 := user.age > 0 b2 := user.age > 0
} }
fn multi_return() (int,string) {
return 4, 'four'
}
fn variadic(a ...int) { fn variadic(a ...int) {
} }

View File

@ -1,5 +1,4 @@
module parser module parser
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
@ -40,10 +39,10 @@ pub fn (p mut Parser) parse_map_ti(nr_muls int) types.TypeIdent {
pub fn (p mut Parser) parse_multi_return_ti() types.TypeIdent { pub fn (p mut Parser) parse_multi_return_ti() types.TypeIdent {
p.check(.lpar) p.check(.lpar)
mut mr_tis := []&types.TypeIdent mut mr_tis := []types.TypeIdent
for { for {
mr_ti := p.parse_ti() mr_ti := p.parse_ti()
mr_tis << &mr_ti mr_tis << mr_ti
if p.tok.kind == .comma { if p.tok.kind == .comma {
p.check(.comma) p.check(.comma)
} }
@ -99,52 +98,52 @@ pub fn (p mut Parser) parse_ti() types.TypeIdent {
return p.parse_map_ti(nr_muls) return p.parse_map_ti(nr_muls)
} }
'voidptr' { 'voidptr' {
return types.new_base_ti(._voidptr, nr_muls) return types.new_builtin_ti(._voidptr, nr_muls)
} }
'byteptr' { 'byteptr' {
return types.new_base_ti(._byteptr, nr_muls) return types.new_builtin_ti(._byteptr, nr_muls)
} }
'charptr' { 'charptr' {
return types.new_base_ti(._charptr, nr_muls) return types.new_builtin_ti(._charptr, nr_muls)
} }
'i8' { 'i8' {
return types.new_base_ti(._i8, nr_muls) return types.new_builtin_ti(._i8, nr_muls)
} }
'i16' { 'i16' {
return types.new_base_ti(._i16, nr_muls) return types.new_builtin_ti(._i16, nr_muls)
} }
'int' { 'int' {
return types.new_base_ti(._int, nr_muls) return types.new_builtin_ti(._int, nr_muls)
} }
'i64' { 'i64' {
return types.new_base_ti(._i64, nr_muls) return types.new_builtin_ti(._i64, nr_muls)
} }
'byte' { 'byte' {
return types.new_base_ti(._byte, nr_muls) return types.new_builtin_ti(._byte, nr_muls)
} }
'u16' { 'u16' {
return types.new_base_ti(._u16, nr_muls) return types.new_builtin_ti(._u16, nr_muls)
} }
'u32' { 'u32' {
return types.new_base_ti(._u32, nr_muls) return types.new_builtin_ti(._u32, nr_muls)
} }
'u64' { 'u64' {
return types.new_base_ti(._u64, nr_muls) return types.new_builtin_ti(._u64, nr_muls)
} }
'f32' { 'f32' {
return types.new_base_ti(._f32, nr_muls) return types.new_builtin_ti(._f32, nr_muls)
} }
'f64' { 'f64' {
return types.new_base_ti(._f64, nr_muls) return types.new_builtin_ti(._f64, nr_muls)
} }
'string' { 'string' {
return types.new_base_ti(._string, nr_muls) return types.new_builtin_ti(._string, nr_muls)
} }
'char' { 'char' {
return types.new_base_ti(._char, nr_muls) return types.new_builtin_ti(._char, nr_muls)
} }
'bool' { 'bool' {
return types.new_base_ti(._bool, nr_muls) return types.new_builtin_ti(._bool, nr_muls)
} }
// struct / enum / placeholder // struct / enum / placeholder
else { else {

View File

@ -120,6 +120,9 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
ti: ti ti: ti
name: arg_name name: arg_name
} }
if ti.kind == ._variadic && p.tok.kind == .comma {
p.error('cannot use ...(variadic) with non-final parameter $arg_name')
}
} }
if p.tok.kind != .rpar { if p.tok.kind != .rpar {
p.check(.comma) p.check(.comma)
@ -128,7 +131,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
p.check(.rpar) p.check(.rpar)
// Return type // Return type
mut ti := types.void_ti mut ti := types.void_ti
if p.tok.kind == .name { if p.tok.kind in [.name, .lpar] {
ti = p.parse_ti() ti = p.parse_ti()
p.return_ti = ti p.return_ti = ti
} }

View File

@ -630,19 +630,19 @@ fn (p mut Parser) array_init() (ast.Expr,types.TypeIdent) {
fn (p mut Parser) parse_number_literal() (ast.Expr,types.TypeIdent) { fn (p mut Parser) parse_number_literal() (ast.Expr,types.TypeIdent) {
lit := p.tok.lit lit := p.tok.lit
mut node := ast.Expr{} mut node := ast.Expr{}
mut ti := types.new_base_ti(._int, 0) mut ti := types.int_ti
if lit.contains('.') { if lit.contains('.') {
node = ast.FloatLiteral{ node = ast.FloatLiteral{
// val: lit.f64() // val: lit.f64()
val: lit val: lit
} }
ti = types.new_base_ti(._f64, 0) ti = types.new_builtin_ti(._f64, 0)
} }
else { else {
node = ast.IntegerLiteral{ node = ast.IntegerLiteral{
val: lit.int() val: lit.int()
} }
// ti = types.new_base_ti(._int, 0) // ti = types.int_ti
} }
p.next() p.next()
return node,ti return node,ti
@ -709,12 +709,37 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
fn (p mut Parser) return_stmt() ast.Return { fn (p mut Parser) return_stmt() ast.Return {
p.next() p.next()
expr,t := p.expr(0) // return expressions
if !types.check(p.return_ti, t) { mut exprs := []ast.Expr
p.warn('cannot use `$t.name` as type `$p.return_ti.name` in return argument') // return type idents
mut got_tis := []types.TypeIdent
for {
expr,ti := p.expr(0)
exprs << expr
got_tis << ti
if p.tok.kind == .comma {
p.check(.comma)
}
else {
break
}
}
mut expected_tis := [p.return_ti]
if p.return_ti.kind == ._multi_return {
mr_type := p.table.types[p.return_ti.idx] as types.MultiReturn
expected_tis = mr_type.tis
}
if expected_tis.len != got_tis.len {
p.error('wrong number of return arguments:\n\texpected: $expected_tis.str()\n\tgot: $got_tis.str()')
}
for i, exp_ti in expected_tis {
got_ti := got_tis[i]
if !types.check(exp_ti, got_ti) {
p.error('cannot use `$got_ti.name` as type `$exp_ti.name` in return argument')
}
} }
return ast.Return{ return ast.Return{
expr: expr exprs: exprs
} }
} }

View File

@ -20,7 +20,6 @@ pub fn (t &Table) find_type(name string) ?types.Type {
} }
pub fn (t mut Table) register_struct(typ types.Struct) int { pub fn (t mut Table) register_struct(typ types.Struct) int {
mut struct_type := types.Type{}
// existing // existing
existing_idx := t.type_idxs[typ.name] existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 { if existing_idx > 0 {
@ -29,6 +28,7 @@ pub fn (t mut Table) register_struct(typ types.Struct) int {
types.Placeholder { types.Placeholder {
// override placeholder // override placeholder
println('overriding type placeholder `$it.name` with struct') println('overriding type placeholder `$it.name` with struct')
mut struct_type := types.Type{}
struct_type = { struct_type = {
typ | typ |
idx:existing_idx idx:existing_idx
@ -48,6 +48,7 @@ pub fn (t mut Table) register_struct(typ types.Struct) int {
println('registering: $typ.name') println('registering: $typ.name')
idx := t.types.len idx := t.types.len
t.type_idxs[typ.name] = idx t.type_idxs[typ.name] = idx
mut struct_type := types.Type{}
struct_type = { struct_type = {
typ | typ |
idx:idx idx:idx
@ -121,14 +122,10 @@ pub fn (t mut Table) find_or_register_array_fixed(elem_ti &types.TypeIdent, size
return idx,name return idx,name
} }
pub fn (t mut Table) find_or_register_multi_return(mr_tis []&types.TypeIdent) (int,string) { pub fn (t mut Table) find_or_register_multi_return(mr_tis []types.TypeIdent) (int,string) {
mut name := 'multi_return' mut name := 'multi_return'
mut mr_type_kinds := []types.Kind
mut mr_type_idxs := []int
for mr_ti in mr_tis { for mr_ti in mr_tis {
name += '_$mr_ti.name' name += '_$mr_ti.name'
mr_type_kinds << mr_ti.kind
mr_type_idxs << mr_ti.idx
} }
// existing // existing
existing_idx := t.type_idxs[name] existing_idx := t.type_idxs[name]
@ -141,8 +138,7 @@ pub fn (t mut Table) find_or_register_multi_return(mr_tis []&types.TypeIdent) (i
mr_type = types.MultiReturn{ mr_type = types.MultiReturn{
idx: idx idx: idx
name: name name: name
type_kinds: mr_type_kinds tis: mr_tis
type_idxs: mr_type_idxs
} }
t.type_idxs[name] = idx t.type_idxs[name] = idx
t.types << mr_type t.types << mr_type
@ -161,8 +157,7 @@ pub fn (t mut Table) find_or_register_variadic(variadic_ti &types.TypeIdent) (in
mut variadic_type := types.Type{} mut variadic_type := types.Type{}
variadic_type = types.Variadic{ variadic_type = types.Variadic{
idx: idx idx: idx
type_kind: variadic_ti.kind ti: variadic_ti
type_idx: variadic_ti.idx
} }
t.type_idxs[name] = idx t.type_idxs[name] = idx
t.types << variadic_type t.types << variadic_type

View File

@ -54,8 +54,9 @@ pub fn new_ti(kind Kind, name string, idx int, nr_muls int) TypeIdent {
} }
[inline] [inline]
pub fn new_base_ti(kind Kind, nr_muls int) TypeIdent { pub fn new_builtin_ti(kind Kind, nr_muls int) TypeIdent {
return TypeIdent{ return TypeIdent{
idx: -int(kind)
kind: kind kind: kind
name: kind.str() name: kind.str()
nr_muls: nr_muls nr_muls: nr_muls
@ -83,7 +84,11 @@ pub fn (ti &TypeIdent) is_number() bool {
} }
pub fn (ti &TypeIdent) str() string { pub fn (ti &TypeIdent) str() string {
return '$ti.kind.str() $ti.idx: $ti.name ($ti.nr_muls)' mut muls := ''
for _ in 0 .. ti.nr_muls {
muls += '&'
}
return '$muls$ti.name'
} }
pub fn check(got, expected &TypeIdent) bool { pub fn check(got, expected &TypeIdent) bool {
@ -277,15 +282,13 @@ pub struct MultiReturn {
pub: pub:
idx int idx int
name string name string
type_kinds []Kind tis []TypeIdent
type_idxs []int
} }
pub struct Variadic { pub struct Variadic {
pub: pub:
idx int idx int
type_kind Kind ti TypeIdent
type_idx int
} }
pub fn (t Void) str() string { pub fn (t Void) str() string {
@ -353,7 +356,7 @@ pub fn (t MultiReturn) str() string {
} }
pub fn (t Variadic) str() string { pub fn (t Variadic) str() string {
return 'variadic_$t.type_kind.str()' return 'variadic_$t.ti.kind.str()'
} }
pub const ( pub const (
@ -387,8 +390,8 @@ pub const (
) )
pub const ( pub const (
void_ti = new_base_ti(._void, 0) void_ti = new_builtin_ti(._void, 0)
int_ti = new_base_ti(._int, 0) int_ti = new_builtin_ti(._int, 0)
string_ti = new_base_ti(._string, 0) string_ti = new_builtin_ti(._string, 0)
bool_ti = new_base_ti(._bool, 0) bool_ti = new_builtin_ti(._bool, 0)
) )