From 6543884366b4842d6847c435e85f7c49d189974c Mon Sep 17 00:00:00 2001 From: Luna Date: Thu, 26 Sep 2019 22:22:11 -0300 Subject: [PATCH] analysis: add check of composite types (structs and enums) - analysis: add bool check for loop condition exprs --- examples/hello.ry | 7 +++- src/types.zig | 85 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 81 insertions(+), 11 deletions(-) diff --git a/examples/hello.ry b/examples/hello.ry index 886e348..f338ce4 100644 --- a/examples/hello.ry +++ b/examples/hello.ry @@ -17,8 +17,13 @@ enum B { c } +enum C { + blah + bluh +} + fn test_function() B { - return B.a; + return B.bluh; } fn multwo(num: i32, double_flag: bool) i32 { diff --git a/src/types.zig b/src/types.zig index d1d7a3b..50ab2bb 100644 --- a/src/types.zig +++ b/src/types.zig @@ -88,14 +88,75 @@ pub const TypeSolver = struct { } } - pub fn expectSymUnType(self: *@This(), symbol_type: comp.SymbolUnderlyingType, wanted_type: comp.SymbolUnderlyingTypeEnum) !void { - var actual_type = comp.SymbolUnderlyingTypeEnum(symbol_type); - if (actual_type != wanted_type) { - std.debug.warn("Expected {}, got {}\n", wanted_type, actual_type); + /// Check if the given symbol type matches a given category. + /// Does not validate equality of Structs and Enums. + pub fn expectSymUnTypeEnum( + self: *@This(), + symbol_type: comp.SymbolUnderlyingType, + wanted_type_enum: comp.SymbolUnderlyingTypeEnum, + ) !void { + var actual_enum = comp.SymbolUnderlyingTypeEnum(symbol_type); + if (actual_enum != wanted_type_enum) { + std.debug.warn("Expected {}, got {}\n", wanted_type_enum, actual_enum); return CompileError.TypeError; } } + fn compositeIdentifierEqual( + self: *@This(), + typ_enum: comp.SymbolUnderlyingTypeEnum, + sym_ident: []const u8, + expected_ident: []const u8, + ) !void { + if (!std.mem.eql(u8, sym_ident, expected_ident)) { + self.doError( + "Expected {} {}, got {}", + @tagName(typ_enum), + expected_ident, + sym_ident, + ); + + return CompileError.TypeError; + } + } + + /// Check if the given type matches the given expected type. + /// This does proper validation of the types if they're structs or enums. + pub fn expectSymUnTypeEqual( + self: *@This(), + symbol_type: comp.SymbolUnderlyingType, + expected_type: comp.SymbolUnderlyingType, + ) !void { + const symbol_enum = comp.SymbolUnderlyingTypeEnum(symbol_type); + const expected_enum = comp.SymbolUnderlyingTypeEnum(expected_type); + + if (symbol_enum != expected_enum) { + std.debug.warn("Expected {}, got {}\n", expected_enum, symbol_enum); + return CompileError.TypeError; + } + + // for most cases, this is already enough, however, for + // composite/abstraction types (structs & enums) we must check + // if they're actually equal types inside + + switch (expected_type) { + .Struct => |expected_identifier| try self.compositeIdentifierEqual( + .Struct, + symbol_type.Struct, + expected_identifier, + ), + + .Enum => |expected_identifier| try self.compositeIdentifierEqual( + .Enum, + symbol_type.Enum, + expected_identifier, + ), + + // for everything else, an enum equality test is enough + else => {}, + } + } + // TODO make return type optional and so, skip exprs that // fail to be fully resolved, instead of returning CompileError pub fn resolveExprType( @@ -193,7 +254,10 @@ pub const TypeSolver = struct { // TODO we need to fetch the given // struct field (on get.name) type and return it .Struct => @panic("TODO analysis of struct"), + + // TODO check if get.name exists in enum .Enum => return global_typ, + else => { std.debug.warn( "Expected Struct/Enum as get target, got {}\n", @@ -238,13 +302,13 @@ pub const TypeSolver = struct { // pull a hack with err contexts, lol) .Return => |ret| { var ret_stmt_type = try self.resolveExprType(ctx, ret.value); - try self.expectSymUnType(ret_stmt_type, ctx.cur_function.?.return_type); + try self.expectSymUnTypeEqual(ret_stmt_type, ctx.cur_function.?.return_type); }, // If create two scopes for each branch of the if .If => |ifstmt| { var cond_type = try self.resolveExprType(ctx, ifstmt.condition); - try self.expectSymUnType(cond_type, .Bool); + try self.expectSymUnTypeEnum(cond_type, .Bool); try ctx.bumpScope("if_then"); @@ -267,9 +331,10 @@ pub const TypeSolver = struct { // Loop (creates 1 scope) asserts that the expression // type is a bool .Loop => |loop| { - if (loop.condition) |cond| - // TODO assert condition's type is bool - _ = try self.resolveExprType(ctx, cond); + if (loop.condition) |cond| { + var expr = try self.resolveExprType(ctx, cond); + try self.expectSymUnTypeEnum(expr, .Bool); + } // TODO bump-dump scope for (loop.then_branch.toSlice()) |then_stmt| { @@ -303,7 +368,7 @@ pub const TypeSolver = struct { self.setErrContext("function {}", name); var ret_type = self.resolveGlobalType(ctx, decl.return_type.lexeme); - std.debug.warn("start analysis of fn {} ret_type: {}\n", decl.func_name.lexeme, ret_type); + std.debug.warn("start analysis of fn {}, ret type: {}\n", decl.func_name.lexeme, ret_type); var parameters = comp.TypeList.init(self.allocator); for (decl.params.toSlice()) |param| {