diff --git a/examples/hello.ry b/examples/hello.ry index 4c0dad8..34bcb18 100644 --- a/examples/hello.ry +++ b/examples/hello.ry @@ -7,8 +7,8 @@ fn f() i32 { return 2; } -fn f2() i64 { - return 1301; +fn f2() i32 { + return f() + 2; } enum B { diff --git a/src/ast.zig b/src/ast.zig index e1e3205..7a5c4cd 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -83,10 +83,7 @@ pub const UnaryExpr = struct { pub const LiteralExpr = union(enum) { Bool: bool, - - Integer32: i32, - Integer64: i64, - + Integer: []const u8, Float: []const u8, String: []const u8, Array: ExprList, diff --git a/src/ast_printer.zig b/src/ast_printer.zig index 1eb5407..322ccb7 100644 --- a/src/ast_printer.zig +++ b/src/ast_printer.zig @@ -227,8 +227,7 @@ pub fn printExpr(expr: *const Expr) void { .Literal => |literal| { switch (literal) { .Bool => |val| std.debug.warn("{}", val), - .Integer32 => |val| std.debug.warn("{}", val), - .Integer64 => |val| std.debug.warn("{}", val), + .Integer => |val| std.debug.warn("{}", val), .Float => |val| std.debug.warn("{}", val), .String => |val| std.debug.warn("'{}'", val), .Array => |exprs| { @@ -363,7 +362,6 @@ fn prettyType(typ: SymbolUnderlyingType) []const u8 { .Integer32 => "i32", .Integer64 => "i64", .Bool => "bool", - .Double => "double", .OpaqueType => |ident| retWithName("opaque", ident), .Struct => |ident| retWithName("struct", ident), diff --git a/src/codegen.zig b/src/codegen.zig index 63af360..d481a7f 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -2,7 +2,7 @@ const std = @import("std"); const ast = @import("ast.zig"); const llvm = @import("llvm.zig"); const comp = @import("comp_ctx.zig"); -// const analysis = @import("analysis.zig"); +const types = @import("types.zig"); fn sliceify(non_slice: ?[*]const u8) []const u8 { if (non_slice == null) return ""; @@ -85,17 +85,10 @@ pub const Codegen = struct { .Literal => |literal| blk: { break :blk switch (literal) { // TODO other literals - .Integer32 => |val| llvm.LLVMConstInt( - llvm.LLVMInt32Type(), - @intCast(c_ulonglong, val), - 10, - ), - .Integer64 => |val| llvm.LLVMConstInt( - llvm.LLVMInt64Type(), - @intCast(c_ulonglong, val), - 10, - ), - + .Integer => |val| blk2: { + var val_cstr = try std.cstr.addNullByte(self.allocator, val); + break :blk2 llvm.LLVMConstIntOfString(llvm.LLVMInt32Type(), val_cstr.ptr, 10); + }, .Float => |val| blk2: { var val_cstr = try std.cstr.addNullByte(self.allocator, val); break :blk2 llvm.LLVMConstRealOfString(llvm.LLVMDoubleType(), val_cstr.ptr); diff --git a/src/comp_ctx.zig b/src/comp_ctx.zig index ac1cfa8..e04b18a 100644 --- a/src/comp_ctx.zig +++ b/src/comp_ctx.zig @@ -9,7 +9,6 @@ pub const TypeList = std.ArrayList(SymbolUnderlyingType); pub const SymbolUnderlyingTypeEnum = enum { Integer32, Integer64, - Double, Bool, // opaque unsolved identifier @@ -23,7 +22,6 @@ pub const SymbolUnderlyingTypeEnum = enum { pub const SymbolUnderlyingType = union(SymbolUnderlyingTypeEnum) { Integer32: void, Integer64: void, - Double: void, Bool: void, OpaqueType: []const u8, diff --git a/src/main.zig b/src/main.zig index 2becea9..517738b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4,7 +4,7 @@ const scanners = @import("scanners.zig"); const parsers = @import("parsers.zig"); const printer = @import("ast_printer.zig"); const codegen = @import("codegen.zig"); -const analysis = @import("analysis.zig"); +const types = @import("types.zig"); pub const Result = enum { Ok, @@ -50,7 +50,7 @@ pub fn run(allocator: *std.mem.Allocator, slice: []const u8) !Result { std.debug.warn("parse tree\n"); printer.printNode(root, 0); - var solver = try analysis.TypeSolver.init(allocator); + var solver = types.TypeSolver.init(allocator); var ctx = try solver.pass(root); std.debug.warn("symbol table\n"); diff --git a/src/parsers.zig b/src/parsers.zig index 3bb8572..2e278cc 100644 --- a/src/parsers.zig +++ b/src/parsers.zig @@ -14,7 +14,6 @@ const TokenType = tokens.TokenType; pub const ParseError = error{ CompileError, UnknownOperator, - InvalidInteger, }; const Node = ast.Node; @@ -357,22 +356,11 @@ pub const Parser = struct { return expr; } - fn mkInt32(self: *Parser, val: i32) !*ast.Expr { + fn mkInteger(self: *Parser, val: []const u8) !*ast.Expr { var expr = try self.allocator.create(Expr); expr.* = Expr{ .Literal = ast.LiteralExpr{ - .Integer32 = val, - }, - }; - - return expr; - } - - fn mkInt64(self: *Parser, val: i64) !*ast.Expr { - var expr = try self.allocator.create(Expr); - expr.* = Expr{ - .Literal = ast.LiteralExpr{ - .Integer64 = val, + .Integer = val, }, }; @@ -1136,40 +1124,8 @@ pub const Parser = struct { .False => try self.mkBool(false), .True => try self.mkBool(true), - .Integer => blk: { - // hacky, but it works. the old approach was doing - // parseInt(i64) on the catch block of parseInt(i32) - var i32_num_opt: ?i32 = std.fmt.parseInt(i32, lexeme, 10) catch null; - var i64_num: i64 = std.fmt.parseInt(i64, lexeme, 10) catch |err| { - return self.doError( - "Invalid integer (not 32bit or 64bit) '{}': {}", - lexeme, - err, - ); - }; - - if (i32_num_opt) |i32_num| { - break :blk try self.mkInt32(i32_num); - } else { - break :blk try self.mkInt64(i64_num); - } - - // old one - - //break :blk try self.mkInt32(std.fmt.parseInt(i32, lexeme, 10) catch |err32| { - // break :blk try self.mkInt64(std.fmt.parseInt(i64, lexeme, 10) catch |err64| { - // return self.doError( - // "Invalid integer (not 32bit or 64bit) '{}': {}", - // lexeme, - // err64, - // ); - // }); - //}); - }, - - // TODO std.fmt.parseFloat + .Integer => try self.mkInteger(lexeme), .Float => try self.mkFloat(lexeme), - .String => try self.mkString(lexeme), .Identifier => try self.mkVariable(self.peek()), diff --git a/src/analysis.zig b/src/types.zig similarity index 90% rename from src/analysis.zig rename to src/types.zig index c6ef1f8..c9ac686 100644 --- a/src/analysis.zig +++ b/src/types.zig @@ -16,13 +16,8 @@ pub const TypeSolver = struct { err_tok: ?Token = null, hadError: bool = false, - err_ctx_buffer: []u8, - - pub fn init(allocator: *std.mem.Allocator) !TypeSolver { - return TypeSolver{ - .allocator = allocator, - .err_ctx_buffer = try allocator.alloc(u8, 512), - }; + pub fn init(allocator: *std.mem.Allocator) TypeSolver { + return TypeSolver{ .allocator = allocator }; } fn setErrContext(self: *@This(), comptime fmt: ?[]const u8, args: ...) void { @@ -31,11 +26,9 @@ pub const TypeSolver = struct { return; } - self.err_ctx = std.fmt.bufPrint( - self.err_ctx_buffer, - fmt.?, - args, - ) catch unreachable; + // TODO allocate buffer on init() and use it + var buf = self.allocator.alloc(u8, 256) catch unreachable; + self.err_ctx = std.fmt.bufPrint(buf, fmt.?, args) catch unreachable; } fn setErrToken(self: *@This(), tok: ?Token) void { @@ -45,7 +38,7 @@ pub const TypeSolver = struct { fn doError(self: *@This(), comptime fmt: []const u8, args: ...) void { self.hadError = true; - std.debug.warn("analysis error"); + std.debug.warn("type error"); if (self.err_tok) |tok| { std.debug.warn(" at line {}", tok.line); } @@ -60,41 +53,35 @@ pub const TypeSolver = struct { } /// Resolve a type in global scope - /// Properly resolves composite (currently opaque) types to structs/enums. fn resolveGlobalType( self: *@This(), ctx: *comp.CompilationContext, identifier: []const u8, ) ?SymbolUnderlyingType { - // first, we assume the identifier is for a simple type - // if we fail (and this always returns OpaqueType as a fallback), - // we take it and find something in global scope + // assume the identifier references a builtin var typ = ctx.solveType(identifier); switch (typ) { .OpaqueType => |val| { + // solve for opaque so it isnt opaque var sym = ctx.symbol_table.get(val); + if (sym != null) + return switch (sym.?.value) { + .Struct => SymbolUnderlyingType{ .Struct = val }, + .Enum => SymbolUnderlyingType{ .Enum = val }, - if (sym == null) { - self.doError("Unknown type: '{}'", val); - return null; - } + else => blk: { + self.doError( + "expected struct or enum for type '{}', got {}", + val, + sym, + ); + break :blk null; + }, + }; - return switch (sym.?.value) { - .Struct => SymbolUnderlyingType{ .Struct = val }, - .Enum => SymbolUnderlyingType{ .Enum = val }, - - // TODO name resolution - - else => blk: { - self.doError( - "expected struct or enum for '{}', got {}", - val, - @tagName(comp.SymbolType(sym.?.value)), - ); - break :blk null; - }, - }; + self.doError("Unknown type: '{}'", val); + return null; }, else => return typ, @@ -115,7 +102,6 @@ pub const TypeSolver = struct { } } - /// Compare if the given type names are equal. fn compositeIdentifierEqual( self: *@This(), typ_enum: comp.SymbolUnderlyingTypeEnum, @@ -209,9 +195,7 @@ pub const TypeSolver = struct { .Bool => SymbolUnderlyingType{ .Bool = {} }, // TODO determine its i64 depending of parseInt results - .Integer32 => SymbolUnderlyingType{ .Integer32 = {} }, - .Integer64 => SymbolUnderlyingType{ .Integer64 = {} }, - .Float => SymbolUnderlyingType{ .Double = {} }, + .Integer => SymbolUnderlyingType{ .Integer32 = {} }, else => unreachable, };