Parsing properties, imbricated classes WIP.

mess
Karchnu 2020-12-17 03:00:56 +01:00
parent 78afcf554e
commit 69122b1e7b
1 changed files with 126 additions and 35 deletions

View File

@ -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 {