sum type `type Foo = Bar | Baz`

pull/3212/head
Alexander Medvednikov 2019-12-24 11:07:26 +03:00
parent 9dd05474b0
commit 803ded3dec
4 changed files with 137 additions and 12 deletions

View File

@ -4,6 +4,8 @@
module compiler
fn (p mut Parser) bool_expression() string {
start_ph := p.cgen.add_placeholder()
expected := p.expected_type
tok := p.tok
typ := p.bterm()
mut got_and := false // to catch `a && b || c` in one expression without ()
@ -44,6 +46,11 @@ fn (p mut Parser) bool_expression() string {
println(tok.str())
p.error('expr() returns empty type')
}
if expected != typ && expected in p.table.sum_types { // TODO perf
p.cgen.set_placeholder(start_ph, '/*KUK*/($expected) { .obj = ($typ[]) { ')
p.gen('}, .typ = 1}')//${val}_type }')
}
return typ
}

View File

@ -793,12 +793,70 @@ fn (p mut Parser) type_decl() {
if p.tok == .key_struct {
p.error('use `struct $name {` instead of `type $name struct {`')
}
if p.tok == .assign {
p.next()
}
parent := p.get_type2()
// Sum type
is_sum := p.tok == .pipe
if is_sum {
// Register the first child (name we already parsed)
/*
p.table.register_type(Type{
parent: name
name: parent.name // yeah it's not a parent here
mod: p.mod
is_public: is_pub
})
*/
// Register the rest of them
for p.tok == .pipe {
p.next()
child := p.check_name()
if p.pass == .main {
// Update the type's parent
println('child=$child parent=$name')
mut t := p.table.find_type(child)
if t.name == '' {
p.error('unknown type `$child`')
}
t.parent = name
p.table.rewrite_type(t)
/*
p.table.register_type(Type{
parent: name
name: child
mod: p.mod
is_public: is_pub
})
*/
}
}
if p.pass == .decl {
p.table.sum_types << name
println(p.table.sum_types)
}
// Register the actual sum type
println('reging sum $name')
p.table.register_type(Type{
name: name
mod: p.mod
cat: .alias
is_public: is_pub
})
p.gen_typedef('typedef struct {
void* obj;
int typ;
} $name;
')
}
nt_pair := p.table.cgen_name_type_pair(name, parent.name)
// TODO dirty C typedef hacks for DOOM
// Unknown type probably means it's a struct, and it's used before the struct is defined,
// so specify "struct"
_struct := if parent.cat != .array && parent.cat != .func && !p.table.known_type(parent.name) { 'struct' } else { '' }
if !is_sum {
p.gen_typedef('typedef $_struct $nt_pair; //type alias name="$name" parent=`$parent.name`')
p.table.register_type(Type{
name: name
@ -807,6 +865,7 @@ fn (p mut Parser) type_decl() {
cat: .alias
is_public: is_pub
})
}
if p.tok != .key_type {
p.fspace()
}

View File

@ -21,7 +21,8 @@ pub mut:
// names []Name
max_field_len map[string]int // for vfmt: max_field_len['Parser'] == 12
generic_struct_params map[string][]string
tuple_variants map[string][]string
tuple_variants map[string][]string // enum( Bool(BoolExpr) )
sum_types []string
}
struct VargAccess {
@ -593,6 +594,9 @@ fn (t &Table) find_type(name_ string) Type {
}
fn (p mut Parser) check_types2(got_, expected_ string, throw bool) bool {
if p.fileis('type_test') {
println('got=$got_ exp=$expected_')
}
mut got := got_
mut expected := expected_
// p.log('check types got="$got" exp="$expected" ')
@ -725,6 +729,16 @@ fn (p mut Parser) check_types2(got_, expected_ string, throw bool) bool {
return true
}
}
// Sum type
println(expected)
if expected in p.table.sum_types {
println('checking sum')
child := p.table.find_type(got)
if child.parent == expected {
println('yep $expected')
return true
}
}
if !throw {
return false
}

View File

@ -17,3 +17,48 @@ fn test_person_str() {
println(p)
assert p.str() == 'Person: Bilbo'
}
struct Foo {}
struct WTF {
wtf int
}
struct BoolExpr {
foo int
}
struct BinExpr {
}
struct UnaryExpr {
}
type Expr = Foo | BoolExpr | BinExpr | UnaryExpr
fn handle_expr(e Expr) {
}
fn parse_bool() BoolExpr {
return BoolExpr{}
}
fn test_sum() {
b := parse_bool()
handle_expr(b)
}
/*
#define ExprType_BoolExpr 0
#define ExprType_BinExpr 1
#define ExprType_UnaryExpr 2
struct Expr {
int typ;
void* obj;
}
*/