sum types

pull/3195/head
Alexander Medvednikov 2019-12-23 00:31:28 +03:00
parent d2c3c66ba4
commit 7ab993c218
4 changed files with 126 additions and 11 deletions

View File

@ -21,18 +21,15 @@ fn (p mut Parser) enum_decl(no_name bool) {
if !p.builtin_mod && p.mod != 'main' { if !p.builtin_mod && p.mod != 'main' {
enum_name = p.prepend_mod(enum_name) enum_name = p.prepend_mod(enum_name)
} }
// Skip empty enums
if !no_name && !p.first_pass() {
p.cgen.typedefs << 'typedef int $enum_name;'
}
p.fspace() p.fspace()
p.check(.lcbr) p.check(.lcbr)
mut val := 0 mut val := 0
mut fields := []string mut fields := []string
mut tuple_variants := []string
for p.tok == .name { for p.tok == .name {
field := p.check_name() field := p.check_name()
if contains_capital(field) { if p.pass == .decl && p.tok != .lpar && contains_capital(field) {
p.warn('enum values cannot contain uppercase letters, use snake_case instead') p.warn('enum values cannot contain uppercase letters, use snake_case instead (`$field`)')
} }
fields << field fields << field
name := '${mod_gen_name(p.mod)}__${enum_name}_$field' name := '${mod_gen_name(p.mod)}__${enum_name}_$field'
@ -59,6 +56,18 @@ fn (p mut Parser) enum_decl(no_name bool) {
p.error_with_token_index('only numbers are allowed in enum initializations', enum_assign_tidx) p.error_with_token_index('only numbers are allowed in enum initializations', enum_assign_tidx)
} }
} }
// `BoolExpr(bool)`
else if p.tok == .lpar {
if !field[0].is_capital() {
p.error('sum types must be capitalized')
}
p.check(.lpar)
tuple_variants << p.get_type()
p.check(.rpar)
if p.pass == .main {
p.cgen.consts << '#define ${field}_type $val // LOL'
}
}
if p.pass == .main { if p.pass == .main {
p.cgen.consts << '#define $name $val' p.cgen.consts << '#define $name $val'
} }
@ -81,10 +90,25 @@ fn (p mut Parser) enum_decl(no_name bool) {
is_public: is_pub is_public: is_pub
is_flag: is_flag is_flag: is_flag
} }
p.table.tuple_variants[enum_name] = tuple_variants
if is_flag && !p.first_pass() { if is_flag && !p.first_pass() {
p.gen_enum_flag_methods(mut T) p.gen_enum_flag_methods(mut T)
} }
p.table.register_type(T) if p.pass == .decl {
p.table.register_type(T)
}
// Register `Expression` enum
if tuple_variants.len > 0 && p.pass == .main {
p.cgen.typedefs << 'typedef struct {
void* obj;
int typ;
} $enum_name;
'
}
// Skip empty enums
else if !no_name && !p.first_pass() {
p.cgen.typedefs << 'typedef int $enum_name;'
}
p.check(.rcbr) p.check(.rcbr)
p.fgen_nl() p.fgen_nl()
p.fgen_nl() p.fgen_nl()
@ -106,3 +130,23 @@ fn (p mut Parser) check_enum_member_access() {
} }
} }
/*
enum Expression {
Boolean(bool),
Integer(i32),
}
fn main() {
let expr = Expression::Integer(10);
let mut val = Expression::Boolean(true);
val = expr;
match val {
Expression::Integer(n) => println!("INT {}", n),
Expression::Boolean(b) => println!("BOOL {}", b),
}
//println!("HELLO {}", val);
}
*/

View File

@ -343,6 +343,31 @@ fn (p mut Parser) name_expr() string {
// no need in `if color == Color.red` // no need in `if color == Color.red`
p.warn('`${enum_type.name}.$val` is unnecessary, use `.$val`') p.warn('`${enum_type.name}.$val` is unnecessary, use `.$val`')
} }
// `expr := Expr.BoolExpr(true)` =>
// `Expr expr = { .obj = true, .typ = BoolExpr_type };`
if val[0].is_capital() {
p.next()
p.check(.lpar)
//println('sum type $val name=$val')
// Find a corresponding tuple variant
// TODO slow, but this will be re-written anyway
mut idx := 0
for i, val_ in enum_type.enum_vals {
//println('f $field.name')
if val_ == val {
idx = i
}
}
q := p.table.tuple_variants[enum_type.name]
//println(q)
//println(q[idx])
arg_type := q[idx]
p.gen('($enum_type.name) { .obj = ($arg_type[]) { ')
p.bool_expression()
p.check(.rpar)
p.gen('}, .typ = ${val}_type }')
return enum_type.name
}
// println('enum val $val') // println('enum val $val')
p.gen(mod_gen_name(enum_type.mod) + '__' + enum_type.name + '_' + val) // `color = main__Color_green` p.gen(mod_gen_name(enum_type.mod) + '__' + enum_type.name + '_' + val) // `color = main__Color_green`
p.next() p.next()
@ -377,7 +402,7 @@ fn (p mut Parser) name_expr() string {
// Register anon fn type // Register anon fn type
fn_typ := Type{ fn_typ := Type{
name: f.typ_str() // 'fn (int, int) string' name: f.typ_str() // 'fn (int, int) string'
mod: p.mod mod: p.mod
func: f func: f
} }

View File

@ -21,6 +21,7 @@ pub mut:
// names []Name // names []Name
max_field_len map[string]int // for vfmt: max_field_len['Parser'] == 12 max_field_len map[string]int // for vfmt: max_field_len['Parser'] == 12
generic_struct_params map[string][]string generic_struct_params map[string][]string
tuple_variants map[string][]string
} }
struct VargAccess { struct VargAccess {
@ -218,7 +219,7 @@ fn new_table(obfuscate bool) &Table {
mut t := &Table{ mut t := &Table{
obfuscate: obfuscate obfuscate: obfuscate
// enum_vals: map[string][]string // enum_vals: map[string][]string
} }
t.register_builtin('int') t.register_builtin('int')
t.register_builtin('size_t') t.register_builtin('size_t')
@ -411,7 +412,7 @@ fn (t mut Table) register_type_with_parent(typ, parent string) {
parent: parent parent: parent
is_public: true is_public: true
// mod: mod // mod: mod
} }
} }
@ -441,7 +442,7 @@ fn (table mut Table) add_field(type_name, field_name, field_type string, is_mut
is_mut: is_mut is_mut: is_mut
attr: attr attr: attr
parent_fn: type_name // Name of the parent type parent_fn: type_name // Name of the parent type
access_mod: access_mod access_mod: access_mod
} }
table.typesmap[type_name] = t table.typesmap[type_name] = t

View File

@ -54,3 +54,48 @@ fn test_nums() {
d := Foo.d d := Foo.d
assert d == -10 assert d == -10
} }
enum Expr {
BoolExpr(bool)
IntExpr(int)
//FloatExpr(int)
}
fn get_expr() Expr {
return Expr.IntExpr(10)
}
fn test_typed_enum() {
i := Expr.IntExpr(10)
expr := Expr.BoolExpr(true)
//println(i)
//if i == expr {
//}
println('done')
// expr = i
/*
match expr {
IntExpr(n) { println('INT $n') }
BoolExpr(b) { println('BOOL $b') }
}
*/
}
/*
fn test_typed_enum() {
Expr i = { .obj = 10, .typ = IntExpr_type };
Expr expr = { .obj = true, .typ = BoolExpr_type };
// val = expr;
if (expr.typ == IntExpr_type) {
int n = (int)expr.obj;
println('INT $n');
}
else if (expr.typ == BoolExpr_type) {
int b = (bool)expr.obj;
println('BOOL $b');
}
}
*/