Replace any with union for subtyping in core:odin/ast

This commit is contained in:
gingerBill
2022-02-06 13:31:16 +00:00
parent cda9fd5271
commit ad6ea3d6aa
5 changed files with 581 additions and 343 deletions
+90 -90
View File
@@ -195,10 +195,10 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool {
for p.curr_tok.kind != .EOF {
stmt := parse_stmt(p)
if stmt != nil {
if _, ok := stmt.derived.(ast.Empty_Stmt); !ok {
if _, ok := stmt.derived.(^ast.Empty_Stmt); !ok {
append(&p.file.decls, stmt)
if es, es_ok := stmt.derived.(ast.Expr_Stmt); es_ok && es.expr != nil {
if _, pl_ok := es.expr.derived.(ast.Proc_Lit); pl_ok {
if es, es_ok := stmt.derived.(^ast.Expr_Stmt); es_ok && es.expr != nil {
if _, pl_ok := es.expr.derived.(^ast.Proc_Lit); pl_ok {
error(p, stmt.pos, "procedure literal evaluated but not used")
}
}
@@ -447,7 +447,7 @@ is_blank_ident_token :: proc(tok: tokenizer.Token) -> bool {
return false
}
is_blank_ident_node :: proc(node: ^ast.Node) -> bool {
if ident, ok := node.derived.(ast.Ident); ok {
if ident, ok := node.derived.(^ast.Ident); ok {
return is_blank_ident(ident.name)
}
return true
@@ -490,34 +490,34 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool {
return true
}
switch n in node.derived {
case ast.Empty_Stmt, ast.Block_Stmt:
#partial switch n in node.derived {
case ^ast.Empty_Stmt, ^ast.Block_Stmt:
return true
case ast.If_Stmt, ast.When_Stmt,
ast.For_Stmt, ast.Range_Stmt, ast.Inline_Range_Stmt,
ast.Switch_Stmt, ast.Type_Switch_Stmt:
case ^ast.If_Stmt, ^ast.When_Stmt,
^ast.For_Stmt, ^ast.Range_Stmt, ^ast.Inline_Range_Stmt,
^ast.Switch_Stmt, ^ast.Type_Switch_Stmt:
return true
case ast.Helper_Type:
case ^ast.Helper_Type:
return is_semicolon_optional_for_node(p, n.type)
case ast.Distinct_Type:
case ^ast.Distinct_Type:
return is_semicolon_optional_for_node(p, n.type)
case ast.Pointer_Type:
case ^ast.Pointer_Type:
return is_semicolon_optional_for_node(p, n.elem)
case ast.Struct_Type, ast.Union_Type, ast.Enum_Type:
case ^ast.Struct_Type, ^ast.Union_Type, ^ast.Enum_Type:
// Require semicolon within a procedure body
return p.curr_proc == nil
case ast.Proc_Lit:
case ^ast.Proc_Lit:
return true
case ast.Package_Decl, ast.Import_Decl, ast.Foreign_Import_Decl:
case ^ast.Package_Decl, ^ast.Import_Decl, ^ast.Foreign_Import_Decl:
return true
case ast.Foreign_Block_Decl:
case ^ast.Foreign_Block_Decl:
return is_semicolon_optional_for_node(p, n.body)
case ast.Value_Decl:
case ^ast.Value_Decl:
if n.is_mutable {
return false
}
@@ -629,10 +629,10 @@ parse_stmt_list :: proc(p: ^Parser) -> []^ast.Stmt {
p.curr_tok.kind != .EOF {
stmt := parse_stmt(p)
if stmt != nil {
if _, ok := stmt.derived.(ast.Empty_Stmt); !ok {
if _, ok := stmt.derived.(^ast.Empty_Stmt); !ok {
append(&list, stmt)
if es, es_ok := stmt.derived.(ast.Expr_Stmt); es_ok && es.expr != nil {
if _, pl_ok := es.expr.derived.(ast.Proc_Lit); pl_ok {
if es, es_ok := stmt.derived.(^ast.Expr_Stmt); es_ok && es.expr != nil {
if _, pl_ok := es.expr.derived.(^ast.Proc_Lit); pl_ok {
error(p, stmt.pos, "procedure literal evaluated but not used")
}
}
@@ -710,7 +710,7 @@ convert_stmt_to_expr :: proc(p: ^Parser, stmt: ^ast.Stmt, kind: string) -> ^ast.
if stmt == nil {
return nil
}
if es, ok := stmt.derived.(ast.Expr_Stmt); ok {
if es, ok := stmt.derived.(^ast.Expr_Stmt); ok {
return es.expr
}
error(p, stmt.pos, "expected %s, found a simple statement", kind)
@@ -852,7 +852,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
if p.curr_tok.kind != .Semicolon {
cond = parse_simple_stmt(p, {Stmt_Allow_Flag.In})
if as, ok := cond.derived.(ast.Assign_Stmt); ok && as.op.kind == .In {
if as, ok := cond.derived.(^ast.Assign_Stmt); ok && as.op.kind == .In {
is_range = true
}
}
@@ -894,7 +894,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
if is_range {
assign_stmt := cond.derived.(ast.Assign_Stmt)
assign_stmt := cond.derived.(^ast.Assign_Stmt)
vals := assign_stmt.lhs[:]
rhs: ^ast.Expr
@@ -975,7 +975,7 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
tag = as
} else {
tag = parse_simple_stmt(p, {Stmt_Allow_Flag.In})
if as, ok := tag.derived.(ast.Assign_Stmt); ok && as.op.kind == .In {
if as, ok := tag.derived.(^ast.Assign_Stmt); ok && as.op.kind == .In {
is_type_switch = true
} else if parse_control_statement_semicolon_separator(p) {
init = tag
@@ -1062,14 +1062,14 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
skip_possible_newline(p)
decl := parse_stmt(p)
switch d in &decl.derived {
case ast.Value_Decl:
#partial switch d in decl.derived_stmt {
case ^ast.Value_Decl:
if d.docs == nil { d.docs = docs }
append(&d.attributes, attribute)
case ast.Foreign_Block_Decl:
case ^ast.Foreign_Block_Decl:
if d.docs == nil { d.docs = docs }
append(&d.attributes, attribute)
case ast.Foreign_Import_Decl:
case ^ast.Foreign_Import_Decl:
if d.docs == nil { d.docs = docs }
append(&d.attributes, attribute)
case:
@@ -1083,11 +1083,11 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
parse_foreign_block_decl :: proc(p: ^Parser) -> ^ast.Stmt {
decl := parse_stmt(p)
switch in decl.derived {
case ast.Empty_Stmt, ast.Bad_Stmt, ast.Bad_Decl:
#partial switch in decl.derived_stmt {
case ^ast.Empty_Stmt, ^ast.Bad_Stmt, ^ast.Bad_Decl:
// Ignore
return nil
case ast.When_Stmt, ast.Value_Decl:
case ^ast.When_Stmt, ^ast.Value_Decl:
return decl
}
@@ -1291,13 +1291,13 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
case .Defer:
tok := advance_token(p)
stmt := parse_stmt(p)
switch s in stmt.derived {
case ast.Empty_Stmt:
#partial switch s in stmt.derived_stmt {
case ^ast.Empty_Stmt:
error(p, s.pos, "empty statement after defer (e.g. ';')")
case ast.Defer_Stmt:
case ^ast.Defer_Stmt:
error(p, s.pos, "you cannot defer a defer statement")
stmt = s.stmt
case ast.Return_Stmt:
case ^ast.Return_Stmt:
error(p, s.pos, "you cannot defer a return statement")
}
ds := ast.new(ast.Defer_Stmt, tok.pos, stmt.end)
@@ -1369,8 +1369,8 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
expect_token_after(p, .Colon, "identifier list")
decl := parse_value_decl(p, list, docs)
if decl != nil {
switch d in &decl.derived {
case ast.Value_Decl:
#partial switch d in decl.derived_stmt {
case ^ast.Value_Decl:
d.is_using = true
return decl
}
@@ -1401,9 +1401,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
return stmt
case "partial":
stmt := parse_stmt(p)
switch s in &stmt.derived {
case ast.Switch_Stmt: s.partial = true
case ast.Type_Switch_Stmt: s.partial = true
#partial switch s in stmt.derived_stmt {
case ^ast.Switch_Stmt: s.partial = true
case ^ast.Type_Switch_Stmt: s.partial = true
case: error(p, stmt.pos, "#partial can only be applied to a switch statement")
}
return stmt
@@ -1548,11 +1548,11 @@ parse_body :: proc(p: ^Parser) -> ^ast.Block_Stmt {
}
convert_stmt_to_body :: proc(p: ^Parser, stmt: ^ast.Stmt) -> ^ast.Stmt {
switch s in stmt.derived {
case ast.Block_Stmt:
#partial switch s in stmt.derived_stmt {
case ^ast.Block_Stmt:
error(p, stmt.pos, "expected a normal statement rather than a block statement")
return stmt
case ast.Empty_Stmt:
case ^ast.Empty_Stmt:
error(p, stmt.pos, "expected a non-empty statement")
}
@@ -1629,10 +1629,10 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags,
id: ^ast.Expr = ident.expr
switch n in ident.expr.derived {
case ast.Ident:
case ast.Bad_Expr:
case ast.Poly_Type:
#partial switch n in ident.expr.derived_expr {
case ^ast.Ident:
case ^ast.Bad_Expr:
case ^ast.Poly_Type:
if allow_poly_names {
if n.specialization == nil {
break
@@ -1794,21 +1794,21 @@ check_procedure_name_list :: proc(p: ^Parser, names: []^ast.Expr) -> bool {
return false
}
_, first_is_polymorphic := names[0].derived.(ast.Poly_Type)
_, first_is_polymorphic := names[0].derived.(^ast.Poly_Type)
any_polymorphic_names := first_is_polymorphic
for i := 1; i < len(names); i += 1 {
name := names[i]
if first_is_polymorphic {
if _, ok := name.derived.(ast.Poly_Type); ok {
if _, ok := name.derived.(^ast.Poly_Type); ok {
any_polymorphic_names = true
} else {
error(p, name.pos, "mixture of polymorphic and non-polymorphic identifiers")
return any_polymorphic_names
}
} else {
if _, ok := name.derived.(ast.Poly_Type); ok {
if _, ok := name.derived.(^ast.Poly_Type); ok {
any_polymorphic_names = true
error(p, name.pos, "mixture of polymorphic and non-polymorphic identifiers")
return any_polymorphic_names
@@ -1873,7 +1873,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
if type == nil {
return false
}
_, ok := type.derived.(ast.Ellipsis)
_, ok := type.derived.(^ast.Ellipsis)
return ok
}
@@ -1891,7 +1891,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
type = parse_var_type(p, allowed_flags)
tt := ast.unparen_expr(type)
if is_signature && !any_polymorphic_names {
if ti, ok := tt.derived.(ast.Typeid_Type); ok && ti.specialization != nil {
if ti, ok := tt.derived.(^ast.Typeid_Type); ok && ti.specialization != nil {
error(p, tt.pos, "specialization of typeid is not allowed without polymorphic names")
}
}
@@ -1967,7 +1967,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
p.curr_tok.kind != .EOF {
prefix_flags := parse_field_prefixes(p)
param := parse_var_type(p, allowed_flags & {.Typeid_Token, .Ellipsis})
if _, ok := param.derived.(ast.Ellipsis); ok {
if _, ok := param.derived.(^ast.Ellipsis); ok {
if seen_ellipsis {
error(p, param.pos, "extra variadic parameter after ellipsis")
}
@@ -1994,8 +1994,8 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
names := make([]^ast.Expr, 1)
names[0] = ast.new(ast.Ident, tok.pos, end_pos(tok))
switch ident in &names[0].derived {
case ast.Ident:
#partial switch ident in names[0].derived_expr {
case ^ast.Ident:
ident.name = tok.text
case:
unreachable()
@@ -2125,12 +2125,12 @@ parse_proc_type :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Proc_Type {
loop: for param in params.list {
if param.type != nil {
if _, ok := param.type.derived.(ast.Poly_Type); ok {
if _, ok := param.type.derived.(^ast.Poly_Type); ok {
is_generic = true
break loop
}
for name in param.names {
if _, ok := name.derived.(ast.Poly_Type); ok {
if _, ok := name.derived.(^ast.Poly_Type); ok {
is_generic = true
break loop
}
@@ -2167,13 +2167,13 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^
}
}
switch e in &ast.unparen_expr(expr).derived {
case ast.Proc_Lit:
#partial switch e in ast.unparen_expr(expr).derived_expr {
case ^ast.Proc_Lit:
if e.inlining != .None && e.inlining != pi {
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal")
}
e.inlining = pi
case ast.Call_Expr:
case ^ast.Call_Expr:
if e.inlining != .None && e.inlining != pi {
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure call")
}
@@ -2264,9 +2264,9 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
bd.name = name.text
original_type := parse_type(p)
type := ast.unparen_expr(original_type)
switch t in &type.derived {
case ast.Array_Type: t.tag = bd
case ast.Dynamic_Array_Type: t.tag = bd
#partial switch t in type.derived_expr {
case ^ast.Array_Type: t.tag = bd
case ^ast.Dynamic_Array_Type: t.tag = bd
case:
error(p, original_type.pos, "expected an array type after #%s", name.text)
}
@@ -2278,10 +2278,10 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tag.name = name.text
original_expr := parse_expr(p, lhs)
expr := ast.unparen_expr(original_expr)
switch t in &expr.derived {
case ast.Comp_Lit:
#partial switch t in expr.derived_expr {
case ^ast.Comp_Lit:
t.tag = tag
case ast.Array_Type:
case ^ast.Array_Type:
t.tag = tag
error(p, tok.pos, "#%s has been replaced with #sparse for non-contiguous enumerated array types", name.text)
case:
@@ -2296,8 +2296,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tag.name = name.text
original_type := parse_type(p)
type := ast.unparen_expr(original_type)
switch t in &type.derived {
case ast.Array_Type:
#partial switch t in type.derived_expr {
case ^ast.Array_Type:
t.tag = tag
case:
error(p, tok.pos, "expected an enumerated array type after #%s", name.text)
@@ -2677,7 +2677,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
variants: [dynamic]^ast.Expr
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
type := parse_type(p)
if _, ok := type.derived.(ast.Bad_Expr); !ok {
if _, ok := type.derived.(^ast.Bad_Expr); !ok {
append(&variants, type)
}
if !allow_token(p, .Comma) {
@@ -2852,19 +2852,19 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool {
if val == nil {
return false
}
switch _ in val.derived {
case ast.Bad_Expr,
ast.Ident,
ast.Selector_Expr,
ast.Array_Type,
ast.Struct_Type,
ast.Union_Type,
ast.Enum_Type,
ast.Dynamic_Array_Type,
ast.Map_Type,
ast.Bit_Set_Type,
ast.Matrix_Type,
ast.Call_Expr:
#partial switch _ in val.derived_expr {
case ^ast.Bad_Expr,
^ast.Ident,
^ast.Selector_Expr,
^ast.Array_Type,
^ast.Struct_Type,
^ast.Union_Type,
^ast.Enum_Type,
^ast.Dynamic_Array_Type,
^ast.Map_Type,
^ast.Bit_Set_Type,
^ast.Matrix_Type,
^ast.Call_Expr:
return true
}
return false
@@ -2986,7 +2986,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
ce.close = close.pos
o := ast.unparen_expr(operand)
if se, ok := o.derived.(ast.Selector_Expr); ok && se.op.kind == .Arrow_Right {
if se, ok := o.derived.(^ast.Selector_Expr); ok && se.op.kind == .Arrow_Right {
sce := ast.new(ast.Selector_Call_Expr, ce.pos, ce.end)
sce.expr = o
sce.call = ce
@@ -3416,13 +3416,13 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
stmt := parse_stmt(p)
if stmt != nil {
switch n in &stmt.derived {
case ast.Block_Stmt: n.label = label
case ast.If_Stmt: n.label = label
case ast.For_Stmt: n.label = label
case ast.Switch_Stmt: n.label = label
case ast.Type_Switch_Stmt: n.label = label
case ast.Range_Stmt: n.label = label
#partial switch n in stmt.derived_stmt {
case ^ast.Block_Stmt: n.label = label
case ^ast.If_Stmt: n.label = label
case ^ast.For_Stmt: n.label = label
case ^ast.Switch_Stmt: n.label = label
case ^ast.Type_Switch_Stmt: n.label = label
case ^ast.Range_Stmt: n.label = label
}
}