From 69122b1e7b84f206ec75a8990402ba1b1ab55dbf Mon Sep 17 00:00:00 2001 From: Karchnu Date: Thu, 17 Dec 2020 03:00:56 +0100 Subject: [PATCH] Parsing properties, imbricated classes WIP. --- src/parse.zig | 161 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 126 insertions(+), 35 deletions(-) diff --git a/src/parse.zig b/src/parse.zig index cb078e2..f4d6d12 100644 --- a/src/parse.zig +++ b/src/parse.zig @@ -51,6 +51,7 @@ pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!*Tree { .token_locs = token_locs.items, // Location of the tokens. .errors = .{}, // List of errors in our parsing. .tok_i = 0, // Index of current token being analyzed. + .indent = 0, // Indentation for debug. }; defer parser.errors.deinit(gpa); errdefer parser.arena.deinit(); @@ -91,6 +92,7 @@ const Parser = struct { token_locs: []const Token.Loc, tok_i: TokenIndex, errors: std.ArrayListUnmanaged(AstError), + indent: u16, // Indentation for debug. /// Root <- skip ContainerMembers eof fn parseRoot(p: *Parser) Allocator.Error!*Node.Root { @@ -165,7 +167,7 @@ const Parser = struct { // without it, default property values can be changed. // statement => Keyword_property Identifier Identifier Colon value - // value => StringLiteral | NullLiteral | IntegerLiteral | FloatLiteral + // value => StringLiteral | Keyword_null | IntegerLiteral | FloatLiteral // True start of parsing. while (true) { @@ -190,12 +192,14 @@ const Parser = struct { }, .Identifier => { - // Identifier => on top level this means either a + // Identifier => on top level this means a class. p.putBackToken(token); p.parseClass() catch |err| switch(err) { // Propagate memory errors. error.OutOfMemory => { return (error.OutOfMemory); }, error.ParseError => { + p.say("we catched a ParseError on token: {}\n" + , .{p.giveTokenContent(p.tok_i)}); continue; } }; // |normal_value| { stuff; to; do; } @@ -216,6 +220,15 @@ const Parser = struct { return list.toOwnedSlice(); } + fn say(p: *Parser, comptime fmt: []const u8, args: anytype) void { + var i = p.indent; + while (i > 0) { + std.debug.print("\t", .{}); + i-=1; + } + std.debug.print(fmt, args); + } + // TODO: require "file" // file should be read, parsed and a loop detection should take place. fn parseRequire(p: *Parser) void { @@ -240,6 +253,9 @@ const Parser = struct { // TODO: class definition (inheritance). fn parseClass(p: *Parser) !void { + p.indent += 1; + defer { p.indent -= 1; } + const class_name = p.eatToken(.Identifier); if (class_name == null) { return; @@ -247,8 +263,7 @@ const Parser = struct { // Either simple or full header. const identifier: ?[] const u8 = try p.parseFullClassHeader(); - std.debug.print("TODO: read class: {}", - .{p.giveTokenContent(class_name.?)}); + p.say("TODO: read class: {}", .{p.giveTokenContent(class_name.?)}); if (identifier) |id| { std.debug.print(", id: {}\n", .{id}); @@ -257,43 +272,119 @@ const Parser = struct { std.debug.print("\n", .{}); } - // TODO: parsing class content. - const token = p.nextToken(); - switch (p.token_ids[token]) { - .Identifier => { - p.putBackToken(token); - const assignment = try p.parseAssignment(); - std.debug.print("redefining an attribute {} => {}\n" - , .{ p.giveTokenContent(assignment.id_attribute) - , p.giveTokenContent(assignment.id_value)}); - }, - else => { - p.putBackToken(token); - std.debug.print("reading {} in a class, backing up\n" - , .{p.giveTokenContent(token)}); - return; + // Starting the class. + // const lbrace = p.nextToken(); + const ignored = try p.expectToken(.LBrace); + + while (true) { + // TODO: parsing class content. + // TODO: loop over this. + const token = p.nextToken(); + switch (p.token_ids[token]) { + + .Identifier => { + const following = p.nextToken(); + switch (p.token_ids[following]) { + .LBrace => { + p.putBackToken(following); + p.putBackToken(token); + p.say("reading a new class\n", .{}); + // WARNING: RECURSION: this may cause errors. + const res = p.parseClass(); + continue; + }, + + .Colon => { + p.putBackToken(following); + p.putBackToken(token); + const assignment = try p.parseAssignment(); + p.say("redefining an attribute {} => {}\n" + , .{ p.giveTokenContent(assignment.id_attribute) + , p.giveTokenContent(assignment.id_value)}); + }, + + else => { + // Wasn't expected. + // Couln't understand what was in this class. + p.putBackToken(following); + p.putBackToken(token); + break; + } + } + }, + + .Keyword_property => { + p.say("Reading a property\n", .{}); + p.putBackToken(token); + try p.parseProperty(); + }, + + .LBrace => { + p.say("Reading a LBrace\n", .{}); + }, + + .RBrace => { + p.say("Reading a RBrace\n", .{}); + // p.putBackToken(token); + break; + }, + + else => { + p.putBackToken(token); + p.say("reading {} in a class, backing up\n" + , .{p.giveTokenContent(token)}); + break; + } } } + // Class definition or instance ends with a RBrace. + const end_of_class = try p.expectToken(.RBrace); } + fn parseProperty(p: *Parser) !void { + const property = try p.expectToken(.Keyword_property); + const class_name = try p.expectToken(.Identifier); + const attribute_name = try p.expectToken(.Identifier); + const colon = try p.expectToken(.Colon); + const id_value = p.nextToken(); + switch (p.token_ids[id_value]) { + .Keyword_null, + .StringLiteral, + .IntegerLiteral, + .FloatLiteral => { + p.say("property: {} {} = {}\n" + , .{p.giveTokenContent(class_name), p.giveTokenContent(attribute_name), p.giveTokenContent(id_value)}); + return ; + // return Assignment{.id_attribute = ia, .id_value = id_value}; + }, + else => { + return error.ParseError; + } + } + } + + + // statement => Keyword_property Identifier Identifier Colon value + // value => StringLiteral | Keyword_null | IntegerLiteral | FloatLiteral fn parseAssignment(p: *Parser) !Assignment { - const id_attribute = p.eatToken(.Identifier); - const ignored = try p.expectToken(.Colon); - const id_value = p.nextToken(); - switch (p.token_ids[id_value]) { - .StringLiteral, - .IntegerLiteral, - .FloatLiteral => { - if (id_attribute) |ia| { - return Assignment{.id_attribute = ia, .id_value = id_value}; - } - }, - else => { - return error.ParseError; - } - } - return error.ParseError; + const id_attribute = p.eatToken(.Identifier); + const ignored = try p.expectToken(.Colon); + const id_value = p.nextToken(); + switch (p.token_ids[id_value]) { + .Keyword_null, + .StringLiteral, + .IntegerLiteral, + .FloatLiteral => { + if (id_attribute) |ia| { + return Assignment{.id_attribute = ia, .id_value = id_value}; + } + }, + else => { + return error.ParseError; + } + } + return error.ParseError; } fn parseFullClassHeader(p: *Parser) !?[]const u8 {