Parsing properties, imbricated classes WIP.
parent
78afcf554e
commit
69122b1e7b
161
src/parse.zig
161
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 {
|
||||
|
|
Loading…
Reference in New Issue