From cb8908dc809b0919d40d1956de5f948514fae70d Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 25 Sep 2019 14:34:32 -0300 Subject: [PATCH] add type analysis for consts - add the basics of recursive type resolving for expressions - set err context for enum --- examples/hello.ry | 4 +++ src/ast.zig | 3 +- src/ast_printer.zig | 34 ++++++++++++++++--- src/comp_ctx.zig | 6 ++++ src/parsers.zig | 24 ++++++++++--- src/types.zig | 83 +++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 142 insertions(+), 12 deletions(-) diff --git a/examples/hello.ry b/examples/hello.ry index 35c51bc..fb0d673 100644 --- a/examples/hello.ry +++ b/examples/hello.ry @@ -1,5 +1,9 @@ // import std; +const ( + AWOO = 1 + 2 +) + enum B { a b diff --git a/src/ast.zig b/src/ast.zig index ed5c56b..c68eefe 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -73,10 +73,11 @@ pub const BinaryExpr = struct { pub const UnaryOperator = enum { Not, + Negate, }; pub const UnaryExpr = struct { - op: Token, + op: UnaryOperator, right: *Expr, }; diff --git a/src/ast_printer.zig b/src/ast_printer.zig index 423d448..0e9b549 100644 --- a/src/ast_printer.zig +++ b/src/ast_printer.zig @@ -191,8 +191,28 @@ fn printBinOp(inner: var) void { std.debug.warn(")"); } -fn printSingleOp(tok: []const u8, applied: *const Expr) void { - std.debug.warn("({}", tok); +const unary_operator_tokens = [_][]const u8{ + "!", "-", +}; + +const unary_operators = [_]UnaryOperator{ + .Not, .Negate, +}; + +fn unOpToStr(op: UnaryOperator) ?[]const u8 { + inline for (unary_operators) |val, idx| { + if (val == op) return unary_operator_tokens[idx]; + } + + return null; +} + +fn printSingleOp(op: UnaryOperator, applied: *const Expr) void { + printSimpleOp(unOpToStr(op), applied); +} + +fn printSimpleOp(op: ?[]const u8, applied: *const Expr) void { + std.debug.warn("({}", op); printExpr(applied); std.debug.warn(")"); } @@ -201,8 +221,8 @@ pub fn printExpr(expr: *const Expr) void { switch (expr.*) { .Binary => |binary| printBinOp(binary), - .Unary => |unary| printSingleOp(unary.op.lexeme, unary.right), - .Grouping => |expr_ptr| printSingleOp("group", expr_ptr), + .Unary => |unary| printSingleOp(unary.op, unary.right), + .Grouping => |expr_ptr| printSimpleOp("group", expr_ptr), .Literal => |literal| { switch (literal) { @@ -282,7 +302,7 @@ pub fn printExpr(expr: *const Expr) void { pub fn printStmt(ident: usize, stmt: *const Stmt) void { switch (stmt.*) { - .Println => |expr| printSingleOp("println", expr), + .Println => |expr| printSimpleOp("println", expr), .Expr => |expr| printExpr(expr), .If => |ifstmt| { @@ -405,6 +425,10 @@ pub fn printContext(ctx: CompilationContext) void { } }, + .Const => |typ| { + std.debug.warn("const '{}', typ={}\n", kv.key, prettyType(typ)); + }, + else => { std.debug.warn("TODO handle print of {}\n", kv.value); unreachable; diff --git a/src/comp_ctx.zig b/src/comp_ctx.zig index 12fc5d4..2cacc07 100644 --- a/src/comp_ctx.zig +++ b/src/comp_ctx.zig @@ -68,6 +68,7 @@ pub const SymbolType = enum { Struct, Enum, Variable, + Const, }; pub const SymbolData = union(SymbolType) { @@ -78,6 +79,7 @@ pub const SymbolData = union(SymbolType) { // variables (parameters and variables), for the type system // only have types Variable: SymbolUnderlyingType, + Const: SymbolUnderlyingType, }; const builtin_type_identifiers = [_][]const u8{ "i32", "i64", "bool" }; @@ -175,4 +177,8 @@ pub const CompilationContext = struct { .Enum = ident_map, }); } + + pub fn insertConst(self: *@This(), constdecl: ast.SingleConst, typ: SymbolUnderlyingType) !void { + _ = try self.symbol_table.put(constdecl.name.lexeme, SymbolData{ .Const = typ }); + } }; diff --git a/src/parsers.zig b/src/parsers.zig index 3e0dc91..361fc66 100644 --- a/src/parsers.zig +++ b/src/parsers.zig @@ -61,6 +61,24 @@ fn toBinaryOperator(op: Token) !ast.BinaryOperator { return ParseError.UnknownOperator; } +const unary_operator_tokens = [_][]const u8{ + "!", "-", +}; + +const unary_operators = [_]ast.UnaryOperator{ + .Not, .Negate, +}; + +fn toUnaryOperator(op: Token) !ast.UnaryOperator { + const lex = op.lexeme; + + inline for (unary_operator_tokens) |op_str, idx| { + if (std.mem.eql(u8, lex, op_str)) return unary_operators[idx]; + } + + return ParseError.UnknownOperator; +} + pub const Parser = struct { allocator: *Allocator, scanner: *Scanner, @@ -241,9 +259,7 @@ pub const Parser = struct { return grouping; } - fn mkUnary(self: *Parser, op: Token, right: *Expr) !*Expr { - std.debug.warn("Unary\n"); - + fn mkUnary(self: *Parser, op: ast.UnaryOperator, right: *Expr) !*Expr { var expr = try self.allocator.create(Expr); expr.* = Expr{ .Unary = ast.UnaryExpr{ @@ -1015,7 +1031,7 @@ pub const Parser = struct { var op = self.previous(); var right = try self.parseUnary(); - return try self.mkUnary(op, right); + return try self.mkUnary(try toUnaryOperator(op), right); } var expr = try self.parseCall(); diff --git a/src/types.zig b/src/types.zig index 951bdaf..f89d728 100644 --- a/src/types.zig +++ b/src/types.zig @@ -88,11 +88,80 @@ pub const TypeSolver = struct { } } + pub fn resolveExprType( + self: *@This(), + ctx: *comp.CompilationContext, + expr: *const ast.Expr, + ) anyerror!SymbolUnderlyingType { + switch (expr.*) { + .Binary => |binary| { + var left_type = self.resolveExprType(ctx, binary.left); + var right_type = self.resolveExprType(ctx, binary.right); + + return switch (binary.op) { + // all numeric operations return numeric types + .Add, .Sub, .Mul, .Div, .Mod => left_type, + + // TODO check left and right as numeric + .Greater, .GreaterEqual, .Less, .LessEqual => SymbolUnderlyingType{ .Bool = {} }, + + // all boolean ops return bools + .Equal, .And, .Or => SymbolUnderlyingType{ .Bool = {} }, + }; + }, + + // for now, unary operators only have .Not + .Unary => |unary| { + var right_type = self.resolveExprType(ctx, unary.right); + return switch (unary.op) { + .Negate => right_type, + .Not => right_type, + }; + }, + + .Literal => |literal| { + return switch (literal) { + .Bool => SymbolUnderlyingType{ .Bool = {} }, + + // TODO determine its i64 depending of parseInt results + .Integer => SymbolUnderlyingType{ .Integer32 = {} }, + + else => unreachable, + }; + }, + + .Grouping => |group_expr| return try self.resolveExprType(ctx, group_expr), + + .Struct => |struc| blk: { + const name = struc.name.lexeme; + var typ = self.resolveGlobalType(ctx, name); + if (typ == null) { + self.doError("Unknown struct name '{}'\n", name); + return CompileError.TypeError; + } + + return typ.?; + }, + + // TODO variable resolution + + // TODO Get (for structs and enums) + + else => { + std.debug.warn("TODO resolve expr {}\n", ast.ExprType(expr.*)); + unreachable; + }, + } + } + pub fn nodePass( self: *@This(), ctx: *comp.CompilationContext, node: *ast.Node, ) !void { + self.setErrToken(null); + self.setErrContext(null); + switch (node.*) { .Root => unreachable, .FnDecl => |decl| { @@ -145,11 +214,21 @@ pub const TypeSolver = struct { // TODO change enums to u32 .Enum => |enu| { + self.setErrToken(enu.name); + self.setErrContext("enum {}", enu.name.lexeme); + try ctx.insertEnum(enu); }, - // TODO infer type of expr in const - //.ConstDecl => {}, + .ConstDecl => |constlist| { + for (constlist.toSlice()) |constdecl| { + self.setErrToken(constdecl.name); + self.setErrContext("const {}", constdecl.name.lexeme); + + var expr_type = try self.resolveExprType(ctx, constdecl.expr); + try ctx.insertConst(constdecl, expr_type); + } + }, else => { std.debug.warn("TODO type analysis of {}\n", node.*);