diff --git a/compiler/parser.v b/compiler/parser.v index 85a264f122..edc3ba2d73 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -429,14 +429,19 @@ fn (p mut Parser) type_decl() { if p.tok == .key_struct { p.error('use `struct $name {` instead of `type $name struct {`') } - parent := p.get_type() - nt_pair := p.table.cgen_name_type_pair(name, parent) + parent := p.get_type2() + 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.contains('[') && !parent.starts_with('fn ') && !p.table.known_type(parent){'struct'} else { ''} - p.gen_typedef('typedef $_struct $nt_pair; // type alias name="$name" parent="$parent"') - p.register_type_with_parent(name, parent) + _struct := if parent.cat != .array && parent.cat != .func && + !p.table.known_type(parent.name) { + 'struct' + } else { + '' + } + p.gen_typedef('typedef $_struct $nt_pair; //type alias name="$name" parent=`$parent.name`') + p.register_type_with_parent(name, parent.name) } fn (p mut Parser) interface_method(field_name, receiver string) &Fn { @@ -743,7 +748,7 @@ if p.scanner.line_comment != '' { } fn (p mut Parser) warn(s string) { - println('$p.scanner.file_path:${p.scanner.line_nr+1}: $s') + println('warning: $p.scanner.file_path:${p.scanner.line_nr+1}: $s') } fn (p mut Parser) error(s string) { @@ -782,24 +787,17 @@ fn (p &Parser) first_pass() bool { // TODO return Type instead of string? fn (p mut Parser) get_type() string { - debug := p.fileis('fn_test') && false mut mul := false mut nr_muls := 0 mut typ := '' // fn type if p.tok == .func { - if debug { - println('\nget_type() .key_goT FN TYP line=$p.scanner.line_nr') - } mut f := Fn{name: '_', mod: p.mod} p.next() line_nr := p.scanner.line_nr p.fn_args(mut f) // Same line, it's a return type if p.scanner.line_nr == line_nr { - if debug { - println('same line getting type') - } if p.tok == .name { f.typ = p.get_type() } diff --git a/compiler/parser2.v b/compiler/parser2.v new file mode 100644 index 0000000000..daafe20b8f --- /dev/null +++ b/compiler/parser2.v @@ -0,0 +1,173 @@ +module main + +import strings + +fn (p mut Parser) get_type2() Type { + mut mul := false + mut nr_muls := 0 + mut typ := '' + mut cat := TypeCategory.struct_ + // fn type + if p.tok == .func { + mut f := Fn{name: '_', mod: p.mod} + p.next() + line_nr := p.scanner.line_nr + p.fn_args(mut f) + // Same line, it's a return type + if p.scanner.line_nr == line_nr { + if p.tok == .name { + f.typ = p.get_type() + } + else { + f.typ = 'void' + } + // println('fn return typ=$f.typ') + } + else { + f.typ = 'void' + } + // Register anon fn type + fn_typ := Type { + name: f.typ_str()// 'fn (int, int) string' + mod: p.mod + func: f + cat: TypeCategory.func + } + p.table.register_type2(fn_typ) + return fn_typ + } + // arrays ([]int) + mut is_arr := false + mut is_arr2 := false// [][]int TODO remove this and allow unlimited levels of arrays + is_question := p.tok == .question + if is_question { + p.check(.question) + } + if p.tok == .lsbr { + p.check(.lsbr) + // [10]int + if p.tok == .number { + typ = '[$p.lit]' + p.next() + } + else { + is_arr = true + } + p.check(.rsbr) + // [10][3]int + if p.tok == .lsbr { + p.next() + if p.tok == .number { + typ += '[$p.lit]' + p.check(.number) + } + else { + is_arr2 = true + } + p.check(.rsbr) + } + cat = .array + } + // map[string]int + if !p.builtin_mod && p.tok == .name && p.lit == 'map' { + p.next() + p.check(.lsbr) + key_type := p.check_name() + if key_type != 'string' { + p.error('maps only support string keys for now') + } + p.check(.rsbr) + val_type := p.get_type()// p.check_name() + typ = 'map_$val_type' + p.register_map(typ) + return Type{name: typ} + } + // + for p.tok == .mul { + if p.first_pass() { + p.warn('use `&Foo` instead of `*Foo`') + } + mul = true + nr_muls++ + p.check(.mul) + } + if p.tok == .amp { + mul = true + nr_muls++ + p.check(.amp) + } + typ += p.lit + if !p.is_struct_init { + // Otherwise we get `foo := FooFoo{` because `Foo` was already + // generated in name_expr() + p.fgen(p.lit) + } + // C.Struct import + if p.lit == 'C' && p.peek() == .dot { + p.next() + p.check(.dot) + typ = p.lit + } + else { + // Module specified? (e.g. gx.Image) + if p.peek() == .dot { + // try resolve full submodule + if !p.builtin_mod && p.import_table.known_alias(typ) { + mod := p.import_table.resolve_alias(typ) + if mod.contains('.') { + typ = mod.replace('.', '_dot_') + } + } + p.next() + p.check(.dot) + typ += '__$p.lit' + } + mut t := p.table.find_type(typ) + // "typ" not found? try "mod__typ" + if t.name == '' && !p.builtin_mod { + // && !p.first_pass() { + if !typ.contains('array_') && p.mod != 'main' && !typ.contains('__') && + !typ.starts_with('[') { + typ = p.prepend_mod(typ) + } + t = p.table.find_type(typ) + if t.name == '' && !p.pref.translated && !p.first_pass() && !typ.starts_with('[') { + println('get_type() bad type') + // println('all registered types:') + // for q in p.table.types { + // println(q.name) + // } + p.error('unknown type `$typ`') + } + } + } + if typ == 'void' { + p.error('unknown type `$typ`') + } + if mul { + typ += strings.repeat(`*`, nr_muls) + } + // Register an []array type + if is_arr2 { + typ = 'array_array_$typ' + p.register_array(typ) + } + else if is_arr { + typ = 'array_$typ' + // p.log('ARR TYPE="$typ" run=$p.pass') + // We come across "[]User" etc ? + p.register_array(typ) + } + p.next() + if p.tok == .question || is_question { + typ = 'Option_$typ' + p.table.register_type_with_parent(typ, 'Option') + if p.tok == .question { + p.next() + } + } + if typ.last_index('__') > typ.index('__') { + p.error('2 __ in gettype(): typ="$typ"') + } + return Type{name: typ, cat: cat} +} diff --git a/compiler/table.v b/compiler/table.v index cb760f6d28..639f306f58 100644 --- a/compiler/table.v +++ b/compiler/table.v @@ -53,6 +53,7 @@ enum TypeCategory { union_ // 5 c_struct c_typedef + array } struct Var { @@ -96,6 +97,7 @@ mut: // This information is needed in the first pass. is_placeholder bool gen_str bool // needs `.str()` method generation + } struct TypeNode {