v2: short struct init syntax; .xxx enum checks; unions; assert
parent
c26016b132
commit
857cbfb0d2
|
@ -2522,8 +2522,8 @@ fn (p mut Parser) indot_expr() string {
|
|||
if is_map && typ != 'string' {
|
||||
p.error('bad element type: expecting `string`')
|
||||
}
|
||||
T := p.table.find_type(arr_typ)
|
||||
if !is_map && !T.has_method('contains') {
|
||||
arr_typ2 := p.table.find_type(arr_typ)
|
||||
if !is_map && !arr_typ2.has_method('contains') {
|
||||
p.error('$arr_typ has no method `contains`')
|
||||
}
|
||||
// `typ` is element's type
|
||||
|
|
|
@ -122,18 +122,18 @@ fn (p mut Parser) check_enum_member_access() {
|
|||
if p.expected_type.starts_with('Option_') {
|
||||
p.expected_type = p.expected_type[7..]
|
||||
}
|
||||
T := p.find_type(p.expected_type)
|
||||
if T.cat == .enum_ {
|
||||
tt := p.find_type(p.expected_type)
|
||||
if tt.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`')
|
||||
if !tt.has_enum_val(val) {
|
||||
p.error('enum `$tt.name` does not have value `$val`')
|
||||
}
|
||||
p.gen(mod_gen_name(T.mod) + '__' + p.expected_type + '_' + val)
|
||||
p.gen(mod_gen_name(tt.mod) + '__' + p.expected_type + '_' + val)
|
||||
}
|
||||
else {
|
||||
p.error('`$T.name` is not an enum')
|
||||
p.error('`$tt.name` is not an enum')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -675,8 +675,8 @@ fn (p mut Parser) expression() string {
|
|||
return typ
|
||||
}
|
||||
|
||||
fn (p mut Parser) handle_operator(op string, typ string, cpostfix string, ph int, T &Type) {
|
||||
if T.has_method(op) {
|
||||
fn (p mut Parser) handle_operator(op string, typ string,cpostfix string, ph int, tt &Type) {
|
||||
if tt.has_method(op) {
|
||||
p.cgen.set_placeholder(ph, '${typ}_${cpostfix}(')
|
||||
p.gen(')')
|
||||
}
|
||||
|
|
|
@ -1138,7 +1138,7 @@ fn (p mut Parser) fn_call_args(f mut Fn, generic_param_types []string) {
|
|||
}
|
||||
if i == 0 && (f.name == 'println' || f.name == 'print') && !(typ in ['string', 'ustring', 'void']) {
|
||||
//
|
||||
T := p.table.find_type(typ)
|
||||
tt := p.table.find_type(typ)
|
||||
$if !windows {
|
||||
$if !js {
|
||||
fmt := p.typ_to_fmt(typ, 0)
|
||||
|
@ -1156,31 +1156,31 @@ fn (p mut Parser) fn_call_args(f mut Fn, generic_param_types []string) {
|
|||
}
|
||||
// Make sure this type has a `str()` method
|
||||
$if !js {
|
||||
if !T.has_method('str') {
|
||||
if !tt.has_method('str') {
|
||||
// varg
|
||||
if T.name.starts_with('varg_') {
|
||||
p.gen_varg_str(T)
|
||||
if tt.name.starts_with('varg_') {
|
||||
p.gen_varg_str(tt)
|
||||
p.cgen.set_placeholder(ph, '${typ}_str(')
|
||||
p.gen(')')
|
||||
continue
|
||||
}
|
||||
// Arrays have automatic `str()` methods
|
||||
else if T.name.starts_with('array_') {
|
||||
p.gen_array_str(T)
|
||||
else if tt.name.starts_with('array_') {
|
||||
p.gen_array_str(tt)
|
||||
p.cgen.set_placeholder(ph, '${typ}_str(')
|
||||
p.gen(')')
|
||||
continue
|
||||
}
|
||||
// struct
|
||||
else if T.cat == .struct_ {
|
||||
p.gen_struct_str(T)
|
||||
else if tt.cat == .struct_ {
|
||||
p.gen_struct_str(tt)
|
||||
p.cgen.set_placeholder(ph, '${typ}_str(')
|
||||
p.gen(')')
|
||||
continue
|
||||
}
|
||||
else {
|
||||
base := p.base_type(T.name)
|
||||
if base != T.name {
|
||||
base := p.base_type(tt.name)
|
||||
if base != tt.name {
|
||||
base_type := p.find_type(base)
|
||||
if base_type.has_method('str') {
|
||||
p.cgen.set_placeholder(ph, '${base_type.name}_str(')
|
||||
|
|
|
@ -291,7 +291,7 @@ pub fn f32_to_decimal(mant u32, exp u32) Dec32 {
|
|||
out = vr + bool_to_u32(vr == vm || last_removed_digit >= 5)
|
||||
}
|
||||
|
||||
return Dec32{m: out, e: e10 + removed}
|
||||
return Dec32{m: out e: e10 + removed}
|
||||
}
|
||||
|
||||
// f32_to_str return a string in scientific notation with max n_digit after the dot
|
||||
|
|
|
@ -55,8 +55,8 @@ pow5_inv_split_32 = [
|
|||
]
|
||||
|
||||
pow5_split_64 =[
|
||||
Uint128{u64(0), 72057594037927936},
|
||||
Uint128{u64(0), 90071992547409920},
|
||||
Uint128{0, 72057594037927936},
|
||||
Uint128{0, 90071992547409920},
|
||||
Uint128{u64(0), 112589990684262400},
|
||||
Uint128{u64(0), 140737488355328000},
|
||||
Uint128{u64(0), 87960930222080000},
|
||||
|
|
|
@ -16,7 +16,7 @@ CastExpr | EnumVal | Assoc | SizeOf | None | MapInit
|
|||
pub type Stmt = VarDecl | GlobalDecl | FnDecl | Return | Module | Import | ExprStmt |
|
||||
ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt |
|
||||
HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt |
|
||||
LineComment | MultiLineComment
|
||||
LineComment | MultiLineComment | AssertStmt
|
||||
|
||||
pub type Type = StructType | ArrayType
|
||||
|
||||
|
@ -469,6 +469,11 @@ pub:
|
|||
expr Expr
|
||||
}
|
||||
|
||||
pub struct AssertStmt {
|
||||
pub:
|
||||
expr Expr
|
||||
}
|
||||
|
||||
pub struct Assoc {
|
||||
pub:
|
||||
name string
|
||||
|
|
|
@ -21,6 +21,7 @@ mut:
|
|||
file ast.File
|
||||
nr_errors int
|
||||
errors []string
|
||||
expected_type table.Type
|
||||
}
|
||||
|
||||
pub fn new_checker(table &table.Table) Checker {
|
||||
|
@ -78,6 +79,10 @@ pub fn (c mut Checker) check_struct_init(struct_init ast.StructInit) table.Type
|
|||
}
|
||||
.struct_ {
|
||||
info := typ_sym.info as table.Struct
|
||||
if struct_init.fields.len == 0 {
|
||||
// Short syntax TODO check
|
||||
return struct_init.typ
|
||||
}
|
||||
if struct_init.exprs.len > info.fields.len {
|
||||
c.error('too many fields', struct_init.pos)
|
||||
}
|
||||
|
@ -279,6 +284,7 @@ pub fn (c mut Checker) array_init(array_init mut ast.ArrayInit) table.Type {
|
|||
// The first element's type
|
||||
if i == 0 {
|
||||
elem_type = typ
|
||||
c.expected_type = typ
|
||||
continue
|
||||
}
|
||||
if !c.table.check(elem_type, typ) {
|
||||
|
@ -366,15 +372,7 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
|
|||
c.check_assign_expr(it)
|
||||
}
|
||||
ast.EnumVal {
|
||||
typ_idx := c.table.find_type_idx(it.enum_name) // or {
|
||||
typ := c.table.find_type(it.enum_name) or {
|
||||
panic(err)
|
||||
}
|
||||
info := typ.info as table.Enum
|
||||
if !(it.val in info.vals) {
|
||||
c.error('enum `$it.enum_name` does not have a value `$it.val`', it.pos)
|
||||
}
|
||||
return typ_idx
|
||||
return c.enum_val(it)
|
||||
}
|
||||
ast.FloatLiteral {
|
||||
return table.f64_type
|
||||
|
@ -651,6 +649,20 @@ pub fn (c mut Checker) index_expr(node ast.IndexExpr) table.Type {
|
|||
return typ
|
||||
}
|
||||
|
||||
// `.green` or `Color.green`
|
||||
// If a short form is used, `expected_type` needs to be an enum
|
||||
// with this value.
|
||||
pub fn (c mut Checker) enum_val(node ast.EnumVal) table.Type {
|
||||
typ_idx := if node.enum_name == '' { c.expected_type } else { c.table.find_type_idx(node.enum_name) }
|
||||
typ := c.table.get_type_symbol(table.Type(typ_idx))
|
||||
// println('checker: enum val $c.expected_type $typ.name')
|
||||
info := typ.info as table.Enum
|
||||
if !(node.val in info.vals) {
|
||||
c.error('enum `$typ.name` does not have a value `$node.val`', node.pos)
|
||||
}
|
||||
return typ_idx
|
||||
}
|
||||
|
||||
pub fn (c mut Checker) error(s string, pos token.Position) {
|
||||
c.nr_errors++
|
||||
print_backtrace()
|
||||
|
|
|
@ -238,6 +238,9 @@ pub fn (p mut Parser) top_stmt() ast.Stmt {
|
|||
.key_enum {
|
||||
return p.enum_decl()
|
||||
}
|
||||
.key_union {
|
||||
return p.struct_decl()
|
||||
}
|
||||
.line_comment {
|
||||
// p.next()
|
||||
return ast.LineComment{
|
||||
|
@ -252,7 +255,7 @@ pub fn (p mut Parser) top_stmt() ast.Stmt {
|
|||
}
|
||||
else {
|
||||
// #printf("");
|
||||
p.error('parser: bad top level statement')
|
||||
p.error('parser: bad top level statement ' + p.tok.str())
|
||||
return ast.Stmt{}
|
||||
}
|
||||
}
|
||||
|
@ -260,6 +263,13 @@ pub fn (p mut Parser) top_stmt() ast.Stmt {
|
|||
|
||||
pub fn (p mut Parser) stmt() ast.Stmt {
|
||||
match p.tok.kind {
|
||||
.key_assert {
|
||||
p.next()
|
||||
expr,_ := p.expr(0)
|
||||
return ast.AssertStmt{
|
||||
expr: expr
|
||||
}
|
||||
}
|
||||
.key_mut {
|
||||
return p.var_decl()
|
||||
}
|
||||
|
@ -481,7 +491,7 @@ fn (p mut Parser) struct_init() ast.StructInit {
|
|||
mut field_names := []string
|
||||
mut exprs := []ast.Expr
|
||||
mut i := 0
|
||||
// TODO if sym.info is table.Struct
|
||||
// TODO `if sym.info is table.Struct`
|
||||
mut is_struct := false
|
||||
match sym.info {
|
||||
table.Struct {
|
||||
|
@ -489,25 +499,41 @@ fn (p mut Parser) struct_init() ast.StructInit {
|
|||
}
|
||||
else {}
|
||||
}
|
||||
is_short_syntax := !(p.peek_tok.kind == .colon || p.tok.kind == .rcbr) // `Vec{a,b,c}`
|
||||
// p.warn(is_short_syntax.str())
|
||||
for p.tok.kind != .rcbr {
|
||||
field_name := p.check_name()
|
||||
mut field_name := ''
|
||||
if is_short_syntax {
|
||||
expr,_ := p.expr(0)
|
||||
exprs << expr
|
||||
}
|
||||
else {
|
||||
field_name = p.check_name()
|
||||
field_names << field_name
|
||||
}
|
||||
// Set expected type for this field's expression
|
||||
// p.warn('$sym.name field $field_name')
|
||||
if is_struct {
|
||||
info := sym.info as table.Struct
|
||||
if is_short_syntax {}
|
||||
else {
|
||||
field := sym.find_field(field_name) or {
|
||||
p.error('field `${sym.name}.$field_name` not found')
|
||||
continue
|
||||
}
|
||||
p.expected_type = field.typ
|
||||
}
|
||||
// p.warn('setting exp $field.typ')
|
||||
}
|
||||
//
|
||||
if !is_short_syntax {
|
||||
p.check(.colon)
|
||||
expr,_ := p.expr(0)
|
||||
exprs << expr
|
||||
}
|
||||
i++
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
}
|
||||
}
|
||||
node := ast.StructInit{
|
||||
typ: typ
|
||||
|
@ -609,7 +635,8 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) {
|
|||
}
|
||||
.dot {
|
||||
// .enum_val
|
||||
node,typ = p.enum_val()
|
||||
// node,typ = p.enum_val()
|
||||
node = p.enum_val()
|
||||
}
|
||||
.chartoken {
|
||||
typ = table.byte_type
|
||||
|
@ -909,14 +936,25 @@ fn (p &Parser) is_addative() bool {
|
|||
*/
|
||||
// `.green`
|
||||
// `pref.BuildMode.default_mode`
|
||||
fn (p mut Parser) enum_val() (ast.Expr,table.Type) {
|
||||
fn (p mut Parser) enum_val() ast.EnumVal {
|
||||
p.check(.dot)
|
||||
val := p.check_name()
|
||||
mut node := ast.Expr{}
|
||||
node = ast.EnumVal{
|
||||
/*
|
||||
if p.expected_type == 0 {
|
||||
p.error('wtf')
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
sym := p.table.get_type_symbol(p.expected_type) //or {
|
||||
//return ast.EnumVal{val:val}
|
||||
//}
|
||||
p.warn(sym.name)
|
||||
*/
|
||||
|
||||
return ast.EnumVal{
|
||||
val: val
|
||||
}
|
||||
return node,table.int_type
|
||||
}
|
||||
|
||||
fn (p mut Parser) for_statement() ast.Stmt {
|
||||
|
@ -1332,12 +1370,18 @@ fn (p mut Parser) const_decl() ast.ConstDecl {
|
|||
}
|
||||
}
|
||||
|
||||
// structs and unions
|
||||
fn (p mut Parser) struct_decl() ast.StructDecl {
|
||||
is_pub := p.tok.kind == .key_pub
|
||||
if is_pub {
|
||||
p.next()
|
||||
}
|
||||
if p.tok.kind == .key_struct {
|
||||
p.check(.key_struct)
|
||||
}
|
||||
else {
|
||||
p.check(.key_union)
|
||||
}
|
||||
is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot
|
||||
if is_c {
|
||||
p.next() // C
|
||||
|
|
|
@ -186,7 +186,7 @@ pub fn (t &Table) get_type_symbol(typ Type) &TypeSymbol {
|
|||
return &t.types[idx]
|
||||
}
|
||||
// this should never happen
|
||||
panic('get_type_symbol: invalid type $typ - $idx')
|
||||
panic('get_type_symbol: invalid type $typ - ${idx}. This should neer happen')
|
||||
}
|
||||
|
||||
// this will override or register builtin type
|
||||
|
|
Loading…
Reference in New Issue