config: item start does not need to be stored at every stack level

This is a simplification, but the main motivation is that the flow
parser stack can be integrated with the main parser stack because they
are not disparate types any more.
This commit is contained in:
torque 2023-09-23 17:27:21 -07:00
parent dcd33bdf27
commit 54e4a14e38
Signed by: torque
SSH Key Fingerprint: SHA256:nCrXefBNo6EbjNSQhv0nXmEg/VuNq3sMF5b8zETw3Tk

View File

@ -987,22 +987,11 @@ pub const Parser = struct {
return document; return document;
} }
const FlowStackItem = struct { const FlowStack: type = std.ArrayList(*Value);
value: *Value,
// lists need this. maps do also for keys and values.
item_start: usize = 0,
};
const FlowStack: type = std.ArrayList(FlowStackItem); inline fn getStackTip(stack: FlowStack) Error!*Value {
inline fn getStackTip(stack: FlowStack) Error!*FlowStackItem {
if (stack.items.len == 0) return error.BadState; if (stack.items.len == 0) return error.BadState;
return &stack.items[stack.items.len - 1]; return stack.items[stack.items.len - 1];
}
inline fn setStackItemStart(stack: FlowStack, start: usize) Error!void {
if (stack.items.len == 0) return error.BadState;
stack.items[stack.items.len - 1].item_start = start;
} }
inline fn popStack(stack: *FlowStack) Error!FlowParseState { inline fn popStack(stack: *FlowStack) Error!FlowParseState {
@ -1011,7 +1000,7 @@ pub const Parser = struct {
const parent = stack.getLastOrNull() orelse return .done; const parent = stack.getLastOrNull() orelse return .done;
return switch (parent.value.*) { return switch (parent.*) {
.flow_list => .want_list_separator, .flow_list => .want_list_separator,
.flow_map => .want_map_separator, .flow_map => .want_map_separator,
else => return error.BadState, else => return error.BadState,
@ -1047,7 +1036,10 @@ pub const Parser = struct {
else => unreachable, else => unreachable,
}; };
var stack = try FlowStack.initCapacity(alloc, 1); var stack = try FlowStack.initCapacity(alloc, 1);
stack.appendAssumeCapacity(.{ .value = &root }); stack.appendAssumeCapacity(&root);
// used to distinguish betwen [] and [ ], and it also tracks
// a continuous value between different states
var item_start: usize = 0;
var dangling_key: ?[]const u8 = null; var dangling_key: ?[]const u8 = null;
charloop: for (contents, 0..) |char, idx| { charloop: for (contents, 0..) |char, idx| {
@ -1057,41 +1049,41 @@ pub const Parser = struct {
',' => { ',' => {
// empty value // empty value
const tip = try getStackTip(stack); const tip = try getStackTip(stack);
try tip.value.flow_list.append(Value.newScalar(alloc)); try tip.flow_list.append(Value.newScalar(alloc));
tip.item_start = idx + 1; item_start = idx + 1;
}, },
'{' => { '{' => {
const tip = try getStackTip(stack); const tip = try getStackTip(stack);
const new_map = try Parser.appendListGetValue( const new_map = try Parser.appendListGetValue(
&tip.value.flow_list, &tip.flow_list,
Value.newFlowMap(alloc), Value.newFlowMap(alloc),
); );
tip.item_start = idx; item_start = idx;
try stack.append(.{ .value = new_map }); try stack.append(new_map);
state = .want_map_key; state = .want_map_key;
}, },
'[' => { '[' => {
const tip = try getStackTip(stack); const tip = try getStackTip(stack);
const new_list = try Parser.appendListGetValue( const new_list = try Parser.appendListGetValue(
&tip.value.flow_list, &tip.flow_list,
Value.newFlowList(alloc), Value.newFlowList(alloc),
); );
tip.item_start = idx; item_start = idx + 1;
try stack.append(.{ .value = new_list, .item_start = idx + 1 }); try stack.append(new_list);
state = .want_list_item; state = .want_list_item;
}, },
']' => { ']' => {
const finished = stack.getLastOrNull() orelse return error.BadState; const finished = stack.getLastOrNull() orelse return error.BadState;
if (finished.value.flow_list.items.len > 0 or idx > finished.item_start) if (finished.flow_list.items.len > 0 or idx > item_start)
try finished.value.flow_list.append(Value.newScalar(alloc)); try finished.flow_list.append(Value.newScalar(alloc));
state = try popStack(&stack); state = try popStack(&stack);
}, },
else => { else => {
try setStackItemStart(stack, idx); item_start = idx;
state = .consuming_list_item; state = .consuming_list_item;
}, },
}, },
@ -1099,17 +1091,17 @@ pub const Parser = struct {
',' => { ',' => {
const tip = try getStackTip(stack); const tip = try getStackTip(stack);
try tip.value.flow_list.append( try tip.flow_list.append(
try Value.fromScalar(alloc, contents[tip.item_start..idx]), try Value.fromScalar(alloc, contents[item_start..idx]),
); );
tip.item_start = idx + 1; item_start = idx + 1;
state = .want_list_item; state = .want_list_item;
}, },
']' => { ']' => {
const finished = stack.getLastOrNull() orelse return error.BadState; const finished = stack.getLastOrNull() orelse return error.BadState;
try finished.value.flow_list.append( try finished.flow_list.append(
try Value.fromScalar(alloc, contents[finished.item_start..idx]), try Value.fromScalar(alloc, contents[item_start..idx]),
); );
state = try popStack(&stack); state = try popStack(&stack);
}, },
@ -1118,7 +1110,7 @@ pub const Parser = struct {
.want_list_separator => switch (char) { .want_list_separator => switch (char) {
' ', '\t' => continue :charloop, ' ', '\t' => continue :charloop,
',' => { ',' => {
try setStackItemStart(stack, idx); item_start = idx;
state = .want_list_item; state = .want_list_item;
}, },
']' => state = try popStack(&stack), ']' => state = try popStack(&stack),
@ -1137,15 +1129,13 @@ pub const Parser = struct {
}, },
'}' => state = try popStack(&stack), '}' => state = try popStack(&stack),
else => { else => {
try setStackItemStart(stack, idx); item_start = idx;
state = .consuming_map_key; state = .consuming_map_key;
}, },
}, },
.consuming_map_key => switch (char) { .consuming_map_key => switch (char) {
':' => { ':' => {
const tip = try getStackTip(stack); dangling_key = try alloc.dupe(u8, contents[item_start..idx]);
dangling_key = try alloc.dupe(u8, contents[tip.item_start..idx]);
state = .want_map_value; state = .want_map_value;
}, },
else => continue :charloop, else => continue :charloop,
@ -1155,7 +1145,7 @@ pub const Parser = struct {
',' => { ',' => {
const tip = try getStackTip(stack); const tip = try getStackTip(stack);
try Parser.putMap( try Parser.putMap(
&tip.value.flow_map, &tip.flow_map,
dangling_key.?, dangling_key.?,
Value.newScalar(alloc), Value.newScalar(alloc),
dupe_behavior, dupe_behavior,
@ -1168,27 +1158,28 @@ pub const Parser = struct {
const tip = try getStackTip(stack); const tip = try getStackTip(stack);
const new_list = try Parser.putMapGetValue( const new_list = try Parser.putMapGetValue(
&tip.value.flow_map, &tip.flow_map,
dangling_key.?, dangling_key.?,
Value.newFlowList(alloc), Value.newFlowList(alloc),
dupe_behavior, dupe_behavior,
); );
try stack.append(.{ .value = new_list, .item_start = idx + 1 }); try stack.append(new_list);
dangling_key = null; dangling_key = null;
item_start = idx + 1;
state = .want_list_item; state = .want_list_item;
}, },
'{' => { '{' => {
const tip = try getStackTip(stack); const tip = try getStackTip(stack);
const new_map = try Parser.putMapGetValue( const new_map = try Parser.putMapGetValue(
&tip.value.flow_map, &tip.flow_map,
dangling_key.?, dangling_key.?,
Value.newFlowMap(alloc), Value.newFlowMap(alloc),
dupe_behavior, dupe_behavior,
); );
try stack.append(.{ .value = new_map }); try stack.append(new_map);
dangling_key = null; dangling_key = null;
state = .want_map_key; state = .want_map_key;
}, },
@ -1196,7 +1187,7 @@ pub const Parser = struct {
// the value is an empty string and this map is closed // the value is an empty string and this map is closed
const tip = try getStackTip(stack); const tip = try getStackTip(stack);
try Parser.putMap( try Parser.putMap(
&tip.value.flow_map, &tip.flow_map,
dangling_key.?, dangling_key.?,
Value.newScalar(alloc), Value.newScalar(alloc),
dupe_behavior, dupe_behavior,
@ -1206,7 +1197,7 @@ pub const Parser = struct {
state = try popStack(&stack); state = try popStack(&stack);
}, },
else => { else => {
try setStackItemStart(stack, idx); item_start = idx;
state = .consuming_map_value; state = .consuming_map_value;
}, },
}, },
@ -1214,9 +1205,9 @@ pub const Parser = struct {
',', '}' => |term| { ',', '}' => |term| {
const tip = try getStackTip(stack); const tip = try getStackTip(stack);
try Parser.putMap( try Parser.putMap(
&tip.value.flow_map, &tip.flow_map,
dangling_key.?, dangling_key.?,
try Value.fromScalar(alloc, contents[tip.item_start..idx]), try Value.fromScalar(alloc, contents[item_start..idx]),
dupe_behavior, dupe_behavior,
); );
dangling_key = null; dangling_key = null;