wip
This commit is contained in:
160
src/attempt_2.zig
Normal file
160
src/attempt_2.zig
Normal file
@@ -0,0 +1,160 @@
|
||||
const Token = @import("Token.zig");
|
||||
const std = @import("std");
|
||||
|
||||
pub fn stripWhiteSpace(line_with_white_space: []const u8) []const u8 {
|
||||
return std.mem.trimStart(u8, line_with_white_space, " \t");
|
||||
}
|
||||
|
||||
pub fn countWhiteSpace(line_with_white_space: []const u8, tab_width: usize) usize {
|
||||
var sum: usize = 0;
|
||||
for (line_with_white_space) |char| {
|
||||
if (char == ' ') {
|
||||
sum += 1;
|
||||
continue;
|
||||
}
|
||||
if (char == '\t') {
|
||||
sum += tab_width;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
const DocumentStyle = struct {
|
||||
const Self = @This();
|
||||
|
||||
heading_char: u8 = '#',
|
||||
heading_levels: usize = 6,
|
||||
|
||||
pub const default = Self{
|
||||
.heading_char = '#',
|
||||
.heading_levels = 6,
|
||||
};
|
||||
};
|
||||
|
||||
pub const Document = struct {
|
||||
const Self = @This();
|
||||
|
||||
const Newline = struct {
|
||||
chars: []const u8,
|
||||
|
||||
pub const newline = Newline{
|
||||
.chars = "\n",
|
||||
};
|
||||
|
||||
pub const newline_carriage_return = Newline{
|
||||
.chars = "\n\r",
|
||||
};
|
||||
};
|
||||
|
||||
const FoundToken = bool;
|
||||
|
||||
const StartLineParserFn = *const fn (self: *Self, alloc: std.mem.Allocator, line: *[]const u8) anyerror!FoundToken;
|
||||
const InlineParserFn = *const fn (self: *Self, alloc: std.mem.Allocator, line: *[]const u8) anyerror!FoundToken;
|
||||
const EndLineParserFn = *const fn (self: *Self, alloc: std.mem.Allocator, line: *[]const u8) anyerror!FoundToken;
|
||||
const MultiLineParserFn = *const fn (self: *Self, alloc: std.mem.Allocator, line_itter: *std.mem.SplitIterator(u8)) anyerror!void;
|
||||
|
||||
tokens: std.ArrayList(Token) = .empty,
|
||||
tab_width: usize = 4,
|
||||
newline_char: Newline = .newline,
|
||||
|
||||
document_style: DocumentStyle = .default,
|
||||
|
||||
// each function will
|
||||
start_line_parsers: std.ArrayList(StartLineParserFn) = .empty,
|
||||
inline_parsers: std.ArrayList(InlineParserFn) = .empty,
|
||||
end_line_parsers: std.ArrayList(EndLineParserFn) = .empty,
|
||||
|
||||
pub fn initDefault(alloc: std.mem.Allocator) !Self {
|
||||
var doc = Self{
|
||||
.tab_width = 4,
|
||||
.newline_char = .newline,
|
||||
.document_style = .default,
|
||||
};
|
||||
|
||||
try doc.appendStartLineParsers(alloc, &[_]StartLineParserFn{
|
||||
&headingParser,
|
||||
});
|
||||
|
||||
try doc.appendInlineParsers(alloc, &[_]InlineParserFn{
|
||||
&baseLineParser,
|
||||
});
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
pub fn appendStartLineParsers(self: *Self, alloc: std.mem.Allocator, parser_fns: []const StartLineParserFn) !void {
|
||||
try self.start_line_parsers.appendSlice(alloc, parser_fns);
|
||||
}
|
||||
pub fn appendInlineParsers(self: *Self, alloc: std.mem.Allocator, parser_fns: []const InlineParserFn) !void {
|
||||
try self.inline_parsers.appendSlice(alloc, parser_fns);
|
||||
}
|
||||
pub fn appendEndLineParsers(self: *Self, alloc: std.mem.Allocator, parser_fns: []const EndLineParserFn) !void {
|
||||
try self.end_line_parsers.appendSlice(alloc, parser_fns);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, alloc: std.mem.Allocator) void {
|
||||
self.tokens.deinit(alloc);
|
||||
self.start_line_parsers.deinit(alloc);
|
||||
self.end_line_parsers.deinit(alloc);
|
||||
self.inline_parsers.deinit(alloc);
|
||||
}
|
||||
|
||||
fn baseLineParser(self: *Self, alloc: std.mem.Allocator, line: *[]const u8) !FoundToken {
|
||||
try self.tokens.append(alloc, Token{
|
||||
.data = stripWhiteSpace(line.*),
|
||||
.padding = countWhiteSpace(line.*, self.tab_width),
|
||||
.type = .text,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
// im going to need to hide a stack in here somewhere
|
||||
fn inlineParser(self: *Self, alloc: std.mem.Allocator, line: *[]const u8) !void {
|
||||
for (self.inline_parsers.items) |parser| {
|
||||
_ = try parser(self, alloc, line);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(self: *Self, alloc: std.mem.Allocator, document: []const u8) !void {
|
||||
var line_iter = std.mem.splitSequence(u8, document, self.newline_char.chars);
|
||||
|
||||
while (line_iter.next()) |line| {
|
||||
var current_line = line;
|
||||
|
||||
for (self.start_line_parsers.items) |parser| {
|
||||
const token_found = try parser(self, alloc, ¤t_line);
|
||||
|
||||
if (token_found) break;
|
||||
}
|
||||
|
||||
try self.inlineParser(alloc, ¤t_line);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn headingParser(self: *Self, alloc: std.mem.Allocator, line: *[]const u8) !FoundToken {
|
||||
const heading_end_index: usize = blk: {
|
||||
var i: usize = 0;
|
||||
while (i < self.document_style.heading_levels) : (i += 1) {
|
||||
if (line.*[i] == self.document_style.heading_char) continue;
|
||||
}
|
||||
break :blk i;
|
||||
};
|
||||
|
||||
// if no heading was detected
|
||||
if (heading_end_index == 0) return false;
|
||||
|
||||
// allows for blank headings
|
||||
const space_remove: usize = if (line.len == heading_end_index) 0 else 1;
|
||||
|
||||
try self.tokens.append(alloc, Token{
|
||||
.data = line.*[0..heading_end_index],
|
||||
.padding = 0,
|
||||
.type = .heading,
|
||||
});
|
||||
|
||||
line.* = line.*[heading_end_index + space_remove ..];
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user