2019-10-20 18:59:53 +02:00
|
|
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
|
|
|
// Use of this source code is governed by an MIT license
|
|
|
|
// that can be found in the LICENSE file.
|
|
|
|
module compiler
|
|
|
|
|
2019-11-06 02:43:13 +01:00
|
|
|
fn (p mut Parser) enum_decl(no_name bool) {
|
2019-10-24 12:19:27 +02:00
|
|
|
is_pub := p.tok == .key_pub
|
|
|
|
if is_pub {
|
|
|
|
p.next()
|
2019-12-19 20:52:27 +01:00
|
|
|
p.fspace()
|
2019-12-05 12:09:33 +01:00
|
|
|
}
|
2019-11-06 02:43:13 +01:00
|
|
|
p.check(.key_enum)
|
2019-11-10 01:08:53 +01:00
|
|
|
p.fspace()
|
2019-12-19 22:29:37 +01:00
|
|
|
mut enum_name := p.check_name()
|
2019-11-06 02:43:13 +01:00
|
|
|
is_c := enum_name == 'C' && p.tok == .dot
|
|
|
|
if is_c {
|
|
|
|
p.check(.dot)
|
|
|
|
enum_name = p.check_name()
|
|
|
|
}
|
2019-10-20 18:59:53 +02:00
|
|
|
// Specify full type name
|
|
|
|
if !p.builtin_mod && p.mod != 'main' {
|
|
|
|
enum_name = p.prepend_mod(enum_name)
|
|
|
|
}
|
2019-11-10 01:08:53 +01:00
|
|
|
p.fspace()
|
2019-10-20 18:59:53 +02:00
|
|
|
p.check(.lcbr)
|
|
|
|
mut val := 0
|
|
|
|
mut fields := []string
|
2019-12-22 22:31:28 +01:00
|
|
|
mut tuple_variants := []string
|
2019-10-20 18:59:53 +02:00
|
|
|
for p.tok == .name {
|
|
|
|
field := p.check_name()
|
2019-12-22 22:31:28 +01:00
|
|
|
if p.pass == .decl && p.tok != .lpar && contains_capital(field) {
|
|
|
|
p.warn('enum values cannot contain uppercase letters, use snake_case instead (`$field`)')
|
2019-10-24 13:25:03 +02:00
|
|
|
}
|
2019-10-20 18:59:53 +02:00
|
|
|
fields << field
|
|
|
|
name := '${mod_gen_name(p.mod)}__${enum_name}_$field'
|
2019-10-21 13:00:41 +02:00
|
|
|
if p.tok == .assign {
|
2019-12-20 00:35:07 +01:00
|
|
|
p.fspace()
|
2019-10-21 13:00:41 +02:00
|
|
|
mut enum_assign_tidx := p.cur_tok_index()
|
2019-12-21 08:35:29 +01:00
|
|
|
next := p.peek()
|
|
|
|
if next in [.number, .minus] {
|
2019-10-21 13:00:41 +02:00
|
|
|
p.next()
|
2019-12-20 00:35:07 +01:00
|
|
|
p.fspace()
|
2019-12-21 08:35:29 +01:00
|
|
|
is_neg := p.tok == .minus
|
|
|
|
if is_neg {
|
|
|
|
p.next()
|
|
|
|
}
|
2019-10-21 13:00:41 +02:00
|
|
|
val = p.lit.int()
|
2019-12-21 08:35:29 +01:00
|
|
|
if is_neg {
|
|
|
|
val = -val
|
|
|
|
}
|
2019-10-21 13:00:41 +02:00
|
|
|
p.next()
|
2019-12-19 22:29:37 +01:00
|
|
|
}
|
|
|
|
else {
|
2019-10-21 13:00:41 +02:00
|
|
|
p.next()
|
|
|
|
enum_assign_tidx = p.cur_tok_index()
|
|
|
|
p.error_with_token_index('only numbers are allowed in enum initializations', enum_assign_tidx)
|
2019-12-05 12:09:33 +01:00
|
|
|
}
|
2019-10-21 13:00:41 +02:00
|
|
|
}
|
2019-12-22 22:31:28 +01:00
|
|
|
// `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'
|
|
|
|
}
|
|
|
|
}
|
2019-10-20 18:59:53 +02:00
|
|
|
if p.pass == .main {
|
|
|
|
p.cgen.consts << '#define $name $val'
|
|
|
|
}
|
|
|
|
if p.tok == .comma {
|
|
|
|
p.next()
|
2020-01-09 01:39:47 +01:00
|
|
|
p.fremove_last()
|
2019-10-20 18:59:53 +02:00
|
|
|
}
|
2019-12-20 00:35:07 +01:00
|
|
|
p.fgen_nl()
|
2019-10-20 18:59:53 +02:00
|
|
|
val++
|
|
|
|
}
|
2019-12-10 04:16:47 +01:00
|
|
|
is_flag := p.attr == 'flag'
|
|
|
|
if is_flag && fields.len > 32 {
|
|
|
|
p.error('when an enum is used as bit field, it must have a max of 32 fields')
|
|
|
|
}
|
2019-12-19 22:29:37 +01:00
|
|
|
mut T := Type{
|
2019-10-20 18:59:53 +02:00
|
|
|
name: enum_name
|
|
|
|
mod: p.mod
|
|
|
|
parent: 'int'
|
2019-11-06 04:26:04 +01:00
|
|
|
cat: .enum_
|
2019-10-20 18:59:53 +02:00
|
|
|
enum_vals: fields.clone()
|
2019-10-24 12:19:27 +02:00
|
|
|
is_public: is_pub
|
2019-12-10 04:16:47 +01:00
|
|
|
is_flag: is_flag
|
|
|
|
}
|
2019-12-22 22:31:28 +01:00
|
|
|
p.table.tuple_variants[enum_name] = tuple_variants
|
2019-12-10 04:16:47 +01:00
|
|
|
if is_flag && !p.first_pass() {
|
|
|
|
p.gen_enum_flag_methods(mut T)
|
|
|
|
}
|
2019-12-23 05:05:52 +01:00
|
|
|
if p.pass == .decl || is_flag {
|
2019-12-22 22:31:28 +01:00
|
|
|
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;
|
|
|
|
'
|
|
|
|
}
|
2020-01-21 18:47:52 +01:00
|
|
|
// Skip nameless enums
|
2019-12-22 22:31:28 +01:00
|
|
|
else if !no_name && !p.first_pass() {
|
|
|
|
p.cgen.typedefs << 'typedef int $enum_name;'
|
2020-01-21 18:47:52 +01:00
|
|
|
}
|
2019-10-20 18:59:53 +02:00
|
|
|
p.check(.rcbr)
|
2019-12-20 00:35:07 +01:00
|
|
|
p.fgen_nl()
|
|
|
|
p.fgen_nl()
|
2020-01-21 18:47:52 +01:00
|
|
|
if !no_name && fields.len == 0 {
|
|
|
|
p.error('Empty enums are not allowed.')
|
|
|
|
}
|
2019-10-20 18:59:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn (p mut Parser) check_enum_member_access() {
|
|
|
|
T := p.find_type(p.expected_type)
|
|
|
|
if T.cat == .enum_ {
|
|
|
|
p.check(.dot)
|
|
|
|
val := p.check_name()
|
|
|
|
// Make sure this enum value exists
|
|
|
|
if !T.has_enum_val(val) {
|
|
|
|
p.error('enum `$T.name` does not have value `$val`')
|
|
|
|
}
|
|
|
|
p.gen(mod_gen_name(T.mod) + '__' + p.expected_type + '_' + val)
|
2019-12-19 22:29:37 +01:00
|
|
|
}
|
|
|
|
else {
|
2019-10-20 18:59:53 +02:00
|
|
|
p.error('`$T.name` is not an enum')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-22 22:31:28 +01:00
|
|
|
/*
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|