// 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 import ( strings ) fn (p mut Parser) get_type2() Type { mut mul := false mut nr_muls := 0 mut typ := '' cat := TypeCategory.struct_ // multiple returns if p.tok == .lpar { // p.warn('`()` are no longer necessary in multiple returns' + // '\nuse `fn foo() int, int {` instead of `fn foo() (int, int) {`') // if p.inside_tuple {p.error('unexpected (')} // p.inside_tuple = true p.check(.lpar) mut types := []string for { types << p.get_type() if p.tok != .comma { break } p.check(.comma) p.fspace() } p.check(.rpar) // p.inside_tuple = false typ = p.register_multi_return_stuct(types) return Type{ name: typ mod: p.mod cat: cat } } // fn type if p.tok == .key_fn { 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 in [.name, .mul, .amp, .lsbr, .question, .lpar] { 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: .func } p.table.register_type(fn_typ) return fn_typ } // arrays ([]int) mut arr_level := 0 is_question := p.tok == .question if is_question { p.check(.question) } for p.tok == .lsbr { p.check(.lsbr) // [10]int if p.tok == .number || (p.tok == .name && !p.inside_const) { if p.tok == .name { typ += '[${p.mod}__$p.lit]' } else { typ += '[$p.lit]' } p.next() } else { arr_level++ } p.check(.rsbr) } // 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 := stringify_pointer(p.get_type()) // p.check_name() typ = 'map_$val_type' p.register_map(typ) return Type{ name: typ } } // ptr/ref mut warn := false for p.tok == .mul { if p.first_pass() { warn = true } mul = true nr_muls++ p.check(.mul) } if p.tok == .amp { mul = true nr_muls++ p.check(.amp) } // generic type check ti := p.generic_dispatch.inst if p.lit in ti.keys() { typ += ti[p.lit] } else { typ += p.lit } // C.Struct import if p.lit == 'C' && p.peek() == .dot { p.next() p.check(.dot) typ = p.lit } else { if warn && p.mod != 'ui' { p.warn('use `&Foo` instead of `*Foo`') } // 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_gen_name(mod) } } 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) // } mut t_suggest,tc_suggest := p.table.find_misspelled_type(typ, p, 0.50) if t_suggest.len > 0 { t_suggest = '. did you mean: ($tc_suggest) `$t_suggest`' } econtext := if p.pref.is_debug { '('+@FILE+':'+@LINE+')' } else {''} p.error('unknown type `$typ`$t_suggest $econtext') } } else if !t.is_public && t.mod != p.mod && !p.is_vgen && t.name != '' && !p.first_pass() { p.error('type `$t.name` is private') } } if typ == 'void' { p.error('unknown type `$typ`') } if mul { typ += strings.repeat(`*`, nr_muls) } // Register an []array type if arr_level > 0 { // p.log('ARR TYPE="$typ" run=$p.pass') // We come across "[]User" etc ? typ = stringify_pointer(typ) for i := 0; i < arr_level; i++ { typ = 'array_$typ' } p.register_array(typ) } p.next() if is_question { typ = stringify_pointer(typ) typ = 'Option_$typ' p.table.register_type_with_parent(typ, 'Option') } // Because the code uses * to see if it's a pointer if typ == 'byteptr' { typ = 'byte*' } if typ == 'voidptr' { // if !p.builtin_mod && p.mod != 'os' && p.mod != 'gx' && p.mod != 'gg' && !p.pref.translated { // p.error('voidptr can only be used in unsafe code') // } typ = 'void*' } /* TODO this is not needed? if typ.last_index('__') > typ.index('__') { p.error('2 __ in gettype(): typ="$typ"') } */ return Type{ name: typ cat: cat } } fn parse_pointer(_typ string) string { if !_typ.starts_with('ptr_') { return _typ } mut typ := _typ.clone() for typ.starts_with('ptr_') { typ = typ[4..] + '*' } return typ } fn stringify_pointer(typ string) string { if !typ.ends_with('*') { return typ } count := typ.count('*') return 'ptr_'.repeat(count) + typ.trim_right('*') }