diff options
| -rw-r--r-- | grammar.ebnf | 4 | ||||
| -rw-r--r-- | src/bootstrap/main.src | 5 | ||||
| -rw-r--r-- | src/bootstrap/tokenizer.src | 6 | ||||
| -rw-r--r-- | src/codegen.zig | 13 | ||||
| -rw-r--r-- | src/main.zig | 15 | ||||
| -rw-r--r-- | src/parser.zig | 58 | ||||
| -rw-r--r-- | src/tokenizer.zig | 16 |
7 files changed, 101 insertions, 16 deletions
diff --git a/grammar.ebnf b/grammar.ebnf index 18d71da..70a1bfd 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -1,9 +1,11 @@ Program ::= Statement+ -Statement ::= (AssignmentStatement | ExternDeclaration | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement) SEMICOLON +Statement ::= (AssignmentStatement | ImportDeclaration | ExternDeclaration | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement) SEMICOLON AssignmentStatement ::= ("let")? ("*")? Expression EQUALS Expression +ImportDeclaration ::= "import" STRING + ExternDeclaration ::= "extern" IDENTIFIER EQUALS Type FunctionCallStatement ::= (IDENTIFIER | FunctionDefinition) LPAREN FunctionArguments? RPAREN diff --git a/src/bootstrap/main.src b/src/bootstrap/main.src index b953e3d..22af2d1 100644 --- a/src/bootstrap/main.src +++ b/src/bootstrap/main.src @@ -1,4 +1,3 @@ -extern printf = (*i8, varargs) => void; extern fopen = (*i8, *i8) => *i8; extern fgets = (*i8, i64, *i8) => void; extern feof = (*i8) => bool; @@ -9,6 +8,8 @@ extern fclose = (*i8) => *i8; extern malloc = (i64) => *i8; extern free = (*i8) => void; +import "tokenizer.src"; + let file_size = 0; let file = 0; let buf = 0; @@ -55,5 +56,7 @@ let main = (argc: i64, argv: **i8) => i64 { free(buf); fclose(file); + printf("TEST: %d\n", test()); + return 0; }; diff --git a/src/bootstrap/tokenizer.src b/src/bootstrap/tokenizer.src new file mode 100644 index 0000000..751a0ac --- /dev/null +++ b/src/bootstrap/tokenizer.src @@ -0,0 +1,6 @@ +extern printf = (*i8, varargs) => void; + +let test = () => i64 { + printf("HELLO\n"); + return 2; +}; diff --git a/src/codegen.zig b/src/codegen.zig index a6d8ed0..38febe6 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -116,6 +116,7 @@ pub const CodeGen = struct { .RETURN_STATEMENT => |*return_statement| return try self.generate_return_statement(@ptrCast(return_statement)), .IF_STATEMENT => |*if_statement| return try self.generate_if_statement(@ptrCast(if_statement)), .WHILE_STATEMENT => |*while_statement| return try self.generate_while_statement(@ptrCast(while_statement)), + .IMPORT_DECLARATION => |*import_declaration| return try self.generate_import_declaration(@ptrCast(import_declaration)), else => unreachable, } } @@ -170,6 +171,7 @@ pub const CodeGen = struct { if (assignment_statement.is_declaration) { try self.environment.add_variable(identifier.name, new_variable); } else { + // TODO: Dont allow changing types of variables if its not declaration try self.environment.set_variable(identifier.name, new_variable); } } else { @@ -288,6 +290,15 @@ pub const CodeGen = struct { llvm.LLVMPositionBuilderAtEnd(self.builder, outer_block); } + fn generate_import_declaration(self: *CodeGen, declaration: *parser.Node) !void { + errdefer std.debug.print("Error generating import declaration\n", .{}); + std.debug.assert(declaration.* == parser.Node.IMPORT_DECLARATION); + + const import_declaration = declaration.IMPORT_DECLARATION; + + try self.generate(import_declaration.program); + } + fn generate_expression_value(self: *CodeGen, expression: *parser.Node, name: ?[]const u8) !*Variable { errdefer std.debug.print("Error generating statement value\n", .{}); return switch (expression.*) { @@ -328,7 +339,7 @@ pub const CodeGen = struct { }, }); - // // Needed for recursive functions + // Needed for recursive functions if (name != null) { try self.environment.add_variable(name.?, try self.create_variable(.{ .value = function, diff --git a/src/main.zig b/src/main.zig index 5ddd750..79def61 100644 --- a/src/main.zig +++ b/src/main.zig @@ -25,26 +25,19 @@ pub fn main() !void { defer source_codegen.deinit(); try process_buf( buf, - allocator, arena.allocator(), source_codegen, + path, ); source_codegen.compile(); } -fn process_buf(buf: []u8, allocator: std.mem.Allocator, arena: std.mem.Allocator, source_codegen: ?*codegen.CodeGen) !void { +fn process_buf(buf: []u8, arena: std.mem.Allocator, source_codegen: ?*codegen.CodeGen, filename: []const u8) !void { std.debug.print("Buf:\n{s}\n", .{buf}); - var token_list = std.ArrayList(tokenizer.Token).init(allocator); - defer token_list.deinit(); - var source_tokenizer = try tokenizer.Tokenizer.init(buf, arena); - while (try source_tokenizer.next()) |token| { - std.debug.print("{any}\n", .{token}); - try token_list.append(token); - } - - const source_parser = try parser.Parser.init(token_list.items, arena); + const token_list = try source_tokenizer.tokenize(); + const source_parser = try parser.Parser.init(token_list, arena, filename); const ast = try source_parser.parse(); std.debug.print("AST: {any}\n", .{ast}); diff --git a/src/parser.zig b/src/parser.zig index 7ed1cb3..748d08b 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -19,6 +19,10 @@ pub const Node = union(enum) { lhs: *Node, rhs: *Node, }, + IMPORT_DECLARATION: struct { + filename: []const u8, + program: *Node, + }, FUNCTION_CALL_STATEMENT: struct { expression: *Node, arguments: []*Node, @@ -103,6 +107,8 @@ pub const MultiplicativeExpressionType = enum { }; pub const Parser = struct { + filename: []const u8, + tokens: []tokenizer.Token, offset: u32, @@ -110,9 +116,10 @@ pub const Parser = struct { try_context: bool, //TODO: I dont like this - pub fn init(tokens: []tokenizer.Token, arena_allocator: std.mem.Allocator) ParserError!*Parser { + pub fn init(tokens: []tokenizer.Token, arena_allocator: std.mem.Allocator, filename: []const u8) ParserError!*Parser { const parser = try arena_allocator.create(Parser); parser.* = .{ + .filename = filename, .tokens = tokens, .offset = 0, .arena = arena_allocator, @@ -146,6 +153,7 @@ pub const Parser = struct { self.accept_parse(parse_while_statement) orelse self.accept_parse(parse_return_statement) orelse self.accept_parse(parse_assignment_statement) orelse + self.accept_parse(parse_import_declaration) orelse try self.parse_extern_declaration(); _ = try self.parse_token(tokenizer.TokenType.SEMICOLON); @@ -187,6 +195,54 @@ pub const Parser = struct { }); } + // ImportDeclaration ::= "import" STRING + fn parse_import_declaration(self: *Parser) ParserError!*Node { + errdefer if (!self.try_context) std.debug.print("Error parsing import declaration {any}\n", .{self.peek_token()}); + + _ = try self.parse_token(.IMPORT); + + const expr = try self.parse_primary_expression(); + + std.debug.assert(expr.PRIMARY_EXPRESSION == .STRING); + + const filename = expr.PRIMARY_EXPRESSION.STRING.value; + + // Open the directory containing self.filename + const dir_path = std.fs.path.dirname(self.filename) orelse "."; + var x = std.fs.cwd().openDir(dir_path, .{}) catch { + std.debug.print("COULDNT OPEN DIR {s}\n", .{self.filename}); + return ParserError.OutOfMemory; + }; + defer x.close(); + + // Open the target file + const file = x.openFile(filename, .{}) catch { + std.debug.print("COULDNT OPEN FILENAME {s}\n", .{filename}); + return ParserError.OutOfMemory; + }; + defer file.close(); + + // Read file contents + const buf = file.readToEndAlloc(self.arena, 1 * 1024 * 1024) catch return ParserError.OutOfMemory; + + // Initialize tokenizer and parse + var inner_tokenizer = try tokenizer.Tokenizer.init(buf, self.arena); + const tokens = inner_tokenizer.tokenize() catch return ParserError.OutOfMemory; + + // Resolve the full path of the imported file + const full_path = try std.fs.path.resolve(self.arena, &.{ dir_path, filename }); + + const inner_parser = try Parser.init(tokens, self.arena, full_path); + const ast = try inner_parser.parse(); + + return self.create_node(.{ + .IMPORT_DECLARATION = .{ + .filename = filename, + .program = ast, + }, + }); + } + // ExternDeclaration ::= "extern" IDENTIFIER EQUALS Type fn parse_extern_declaration(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing extern declaration {any}\n", .{self.peek_token()}); diff --git a/src/tokenizer.zig b/src/tokenizer.zig index 2b57b8d..53e5c63 100644 --- a/src/tokenizer.zig +++ b/src/tokenizer.zig @@ -6,6 +6,7 @@ const TokenizerError = error{ pub const TokenType = union(enum) { // Keywords + IMPORT: void, LET: void, EXTERN: void, IF: void, @@ -64,13 +65,26 @@ pub const Tokenizer = struct { return Tokenizer{ .buf = buf, .offset = 0, .arena = arena }; } - pub fn next(self: *Tokenizer) TokenizerError!?Token { + pub fn tokenize(self: *Tokenizer) ![]Token { + var token_list = std.ArrayList(Token).init(self.arena); + + while (try self.next()) |token| { + std.debug.print("{any}\n", .{token}); + try token_list.append(token); + } + + return token_list.items; + } + + fn next(self: *Tokenizer) TokenizerError!?Token { self.skip_whitespace(); self.skip_comments(); self.skip_whitespace(); if (self.offset >= self.buf.len) return null; + if (self.accept_string("import")) return self.create_token(.{ .IMPORT = void{} }); + if (self.accept_string("let")) return self.create_token(.{ .LET = void{} }); if (self.accept_string("extern")) return self.create_token(.{ .EXTERN = void{} }); if (self.accept_string("if")) return self.create_token(.{ .IF = void{} }); |