From 7ab993c2184b5df4e584877e5e27207a00e7ae21 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Mon, 23 Dec 2019 00:31:28 +0300 Subject: [PATCH] sum types --- vlib/compiler/enum.v | 58 +++++++++++++++++++++++++++++---- vlib/compiler/expression.v | 27 ++++++++++++++- vlib/compiler/table.v | 7 ++-- vlib/compiler/tests/enum_test.v | 45 +++++++++++++++++++++++++ 4 files changed, 126 insertions(+), 11 deletions(-) diff --git a/vlib/compiler/enum.v b/vlib/compiler/enum.v index cdae97f573..7e665ae7c2 100644 --- a/vlib/compiler/enum.v +++ b/vlib/compiler/enum.v @@ -21,18 +21,15 @@ fn (p mut Parser) enum_decl(no_name bool) { if !p.builtin_mod && p.mod != 'main' { 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.check(.lcbr) mut val := 0 mut fields := []string + mut tuple_variants := []string for p.tok == .name { field := p.check_name() - if contains_capital(field) { - p.warn('enum values cannot contain uppercase letters, use snake_case instead') + if p.pass == .decl && p.tok != .lpar && contains_capital(field) { + p.warn('enum values cannot contain uppercase letters, use snake_case instead (`$field`)') } fields << 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) } } + // `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 { p.cgen.consts << '#define $name $val' } @@ -81,10 +90,25 @@ fn (p mut Parser) enum_decl(no_name bool) { is_public: is_pub is_flag: is_flag } + p.table.tuple_variants[enum_name] = tuple_variants if is_flag && !p.first_pass() { 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.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); +} +*/ + diff --git a/vlib/compiler/expression.v b/vlib/compiler/expression.v index 56b9dbc46f..490031b8c1 100644 --- a/vlib/compiler/expression.v +++ b/vlib/compiler/expression.v @@ -343,6 +343,31 @@ fn (p mut Parser) name_expr() string { // no need in `if color == Color.red` 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') p.gen(mod_gen_name(enum_type.mod) + '__' + enum_type.name + '_' + val) // `color = main__Color_green` p.next() @@ -377,7 +402,7 @@ fn (p mut Parser) name_expr() string { // Register anon fn type fn_typ := Type{ name: f.typ_str() // 'fn (int, int) string' - + mod: p.mod func: f } diff --git a/vlib/compiler/table.v b/vlib/compiler/table.v index d36adfba69..f4dfed78d6 100644 --- a/vlib/compiler/table.v +++ b/vlib/compiler/table.v @@ -21,6 +21,7 @@ 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 } struct VargAccess { @@ -218,7 +219,7 @@ fn new_table(obfuscate bool) &Table { mut t := &Table{ obfuscate: obfuscate // enum_vals: map[string][]string - + } t.register_builtin('int') t.register_builtin('size_t') @@ -411,7 +412,7 @@ fn (t mut Table) register_type_with_parent(typ, parent string) { parent: parent is_public: true // 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 attr: attr parent_fn: type_name // Name of the parent type - + access_mod: access_mod } table.typesmap[type_name] = t diff --git a/vlib/compiler/tests/enum_test.v b/vlib/compiler/tests/enum_test.v index 7c491028dd..f36064eaab 100644 --- a/vlib/compiler/tests/enum_test.v +++ b/vlib/compiler/tests/enum_test.v @@ -54,3 +54,48 @@ fn test_nums() { d := Foo.d 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'); + } +} +*/