config: remove some duplication in the parser
There's still a fair amount lurking in here, but I believe this logic is sound. Rather than duplicating the map/list logic under the opposing key, we set the logic up to use the second loop around (this is was how dedents worked, and now it also works for indents). I'm not convinced this is as easy to follow, and it did lead me to add some additional unreachables to the code, which should maybe be turned into error returns instead. It does reduce the odds of a code change missing a copied instance, which I think is a good thing.
This commit is contained in:
parent
47f4a1c479
commit
9c866970f8
116
src/config.zig
116
src/config.zig
@ -757,7 +757,7 @@ pub const Parser = struct {
|
|||||||
.value => switch (stack.getLast().*) {
|
.value => switch (stack.getLast().*) {
|
||||||
// these three states are never reachable here. flow_list and
|
// these three states are never reachable here. flow_list and
|
||||||
// flow_map are parsed with a separate state machine. These
|
// flow_map are parsed with a separate state machine. These
|
||||||
// value tyeps can only be present by themselves as the first
|
// value types can only be present by themselves as the first
|
||||||
// line of the document, in which case the document consists
|
// line of the document, in which case the document consists
|
||||||
// only of that single line: this parser jumps immediately into
|
// only of that single line: this parser jumps immediately into
|
||||||
// the .done state, bypassing the .value state in which this
|
// the .done state, bypassing the .value state in which this
|
||||||
@ -799,7 +799,7 @@ pub const Parser = struct {
|
|||||||
//
|
//
|
||||||
// the first line here creates the expect_shift, but the second line
|
// the first line here creates the expect_shift, but the second line
|
||||||
// is a valid continuation of the list despite not being indented
|
// is a valid continuation of the list despite not being indented
|
||||||
if (expect_shift == .indent and line.indent != .indent)
|
if (!flop and (expect_shift == .indent and line.indent != .indent))
|
||||||
try list.append(Value.newScalar(arena_alloc));
|
try list.append(Value.newScalar(arena_alloc));
|
||||||
|
|
||||||
// Consider:
|
// Consider:
|
||||||
@ -838,47 +838,33 @@ pub const Parser = struct {
|
|||||||
.line_string, .space_string => |str| {
|
.line_string, .space_string => |str| {
|
||||||
// string pushes the stack
|
// string pushes the stack
|
||||||
const new_string = try appendListGetValue(list, try Value.fromString(arena_alloc, str));
|
const new_string = try appendListGetValue(list, try Value.fromString(arena_alloc, str));
|
||||||
|
try stack.append(new_string);
|
||||||
|
|
||||||
try new_string.string.append(in_line.lineEnding());
|
try new_string.string.append(in_line.lineEnding());
|
||||||
|
|
||||||
try stack.append(new_string);
|
|
||||||
expect_shift = .none;
|
expect_shift = .none;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.list_item => |value| {
|
.list_item => |value| {
|
||||||
switch (line.indent) {
|
if (flop or (line.indent == .none or line.indent == .dedent)) {
|
||||||
// for dedent, the stack has already been popped, so this should be fine
|
expect_shift = .none;
|
||||||
.none, .dedent => {
|
switch (value) {
|
||||||
expect_shift = .none;
|
.empty => expect_shift = .indent,
|
||||||
switch (value) {
|
.scalar => |str| try list.append(try Value.fromScalar(arena_alloc, str)),
|
||||||
.empty => expect_shift = .indent,
|
.line_string, .space_string => |str| try list.append(try Value.fromString(arena_alloc, str)),
|
||||||
.scalar => |str| try list.append(try Value.fromScalar(arena_alloc, str)),
|
.flow_list => |str| try list.append(try parseFlowList(arena_alloc, str, self.dupe_behavior)),
|
||||||
.line_string, .space_string => |str| try list.append(try Value.fromString(arena_alloc, str)),
|
.flow_map => |str| try list.append(try parseFlowMap(arena_alloc, str, self.dupe_behavior)),
|
||||||
.flow_list => |str| try list.append(try parseFlowList(arena_alloc, str, self.dupe_behavior)),
|
}
|
||||||
.flow_map => |str| try list.append(try parseFlowMap(arena_alloc, str, self.dupe_behavior)),
|
} else if (line.indent == .indent) {
|
||||||
}
|
if (expect_shift != .indent) return error.UnexpectedIndent;
|
||||||
},
|
|
||||||
// a new list is being created
|
|
||||||
.indent => {
|
|
||||||
if (expect_shift != .indent)
|
|
||||||
return error.UnexpectedIndent;
|
|
||||||
|
|
||||||
const new_list = try appendListGetValue(list, Value.newList(arena_alloc));
|
const new_list = try appendListGetValue(list, Value.newList(arena_alloc));
|
||||||
try stack.append(new_list);
|
try stack.append(new_list);
|
||||||
|
expect_shift = .none;
|
||||||
expect_shift = .none;
|
continue :flipflop;
|
||||||
switch (value) {
|
} else unreachable;
|
||||||
.empty => expect_shift = .indent,
|
|
||||||
.scalar => |str| try new_list.list.append(try Value.fromScalar(arena_alloc, str)),
|
|
||||||
.line_string, .space_string => |str| try new_list.list.append(try Value.fromString(arena_alloc, str)),
|
|
||||||
.flow_list => |str| try new_list.list.append(try parseFlowList(arena_alloc, str, self.dupe_behavior)),
|
|
||||||
.flow_map => |str| try new_list.list.append(try parseFlowMap(arena_alloc, str, self.dupe_behavior)),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.map_item => |pair| {
|
.map_item => {
|
||||||
// this prong cannot be hit on dedent in a valid way.
|
// this prong cannot be hit on dedent in a valid way.
|
||||||
//
|
//
|
||||||
// -
|
// -
|
||||||
@ -894,17 +880,7 @@ pub const Parser = struct {
|
|||||||
const new_map = try appendListGetValue(list, Value.newMap(arena_alloc));
|
const new_map = try appendListGetValue(list, Value.newMap(arena_alloc));
|
||||||
try stack.append(new_map);
|
try stack.append(new_map);
|
||||||
expect_shift = .none;
|
expect_shift = .none;
|
||||||
|
continue :flipflop;
|
||||||
switch (pair.val) {
|
|
||||||
.empty => {
|
|
||||||
dangling_key = try arena_alloc.dupe(u8, pair.key);
|
|
||||||
expect_shift = .indent;
|
|
||||||
},
|
|
||||||
.scalar => |str| try new_map.map.put(pair.key, try Value.fromScalar(arena_alloc, str)),
|
|
||||||
.line_string, .space_string => |str| try new_map.map.put(pair.key, try Value.fromString(arena_alloc, str)),
|
|
||||||
.flow_list => |str| try new_map.map.put(pair.key, try parseFlowList(arena_alloc, str, self.dupe_behavior)),
|
|
||||||
.flow_map => |str| try new_map.map.put(pair.key, try parseFlowMap(arena_alloc, str, self.dupe_behavior)),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -916,7 +892,7 @@ pub const Parser = struct {
|
|||||||
//
|
//
|
||||||
// the first line here creates the expect_shift, but the second line
|
// the first line here creates the expect_shift, but the second line
|
||||||
// is a valid continuation of the map despite not being indented
|
// is a valid continuation of the map despite not being indented
|
||||||
if (expect_shift == .indent and line.indent != .indent) {
|
if (!flop and (expect_shift == .indent and line.indent != .indent)) {
|
||||||
try putMap(
|
try putMap(
|
||||||
map,
|
map,
|
||||||
dangling_key orelse return error.Fail,
|
dangling_key orelse return error.Fail,
|
||||||
@ -963,7 +939,7 @@ pub const Parser = struct {
|
|||||||
|
|
||||||
dangling_key = null;
|
dangling_key = null;
|
||||||
},
|
},
|
||||||
.list_item => |value| {
|
.list_item => {
|
||||||
// this prong cannot be hit on dedent in a valid way.
|
// this prong cannot be hit on dedent in a valid way.
|
||||||
//
|
//
|
||||||
// map:
|
// map:
|
||||||
@ -978,21 +954,13 @@ pub const Parser = struct {
|
|||||||
const new_list = try putMapGetValue(map, dangling_key.?, Value.newList(arena_alloc), self.dupe_behavior);
|
const new_list = try putMapGetValue(map, dangling_key.?, Value.newList(arena_alloc), self.dupe_behavior);
|
||||||
try stack.append(new_list);
|
try stack.append(new_list);
|
||||||
dangling_key = null;
|
dangling_key = null;
|
||||||
|
|
||||||
expect_shift = .none;
|
expect_shift = .none;
|
||||||
switch (value) {
|
continue :flipflop;
|
||||||
.empty => expect_shift = .indent,
|
|
||||||
.scalar => |str| try new_list.list.append(try Value.fromScalar(arena_alloc, str)),
|
|
||||||
.line_string, .space_string => |str| try new_list.list.append(try Value.fromString(arena_alloc, str)),
|
|
||||||
.flow_list => |str| try new_list.list.append(try parseFlowList(arena_alloc, str, self.dupe_behavior)),
|
|
||||||
.flow_map => |str| try new_list.list.append(try parseFlowMap(arena_alloc, str, self.dupe_behavior)),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.map_item => |pair| {
|
.map_item => |pair| {
|
||||||
expect_shift = .none;
|
if (flop or (line.indent == .none or line.indent == .dedent)) {
|
||||||
switch (line.indent) {
|
expect_shift = .none;
|
||||||
// for dedent, the stack has already been popped, so this should be fine
|
switch (pair.val) {
|
||||||
.none, .dedent => switch (pair.val) {
|
|
||||||
.empty => {
|
.empty => {
|
||||||
expect_shift = .indent;
|
expect_shift = .indent;
|
||||||
dangling_key = try arena_alloc.dupe(u8, pair.key);
|
dangling_key = try arena_alloc.dupe(u8, pair.key);
|
||||||
@ -1001,27 +969,15 @@ pub const Parser = struct {
|
|||||||
.line_string, .space_string => |str| try putMap(map, pair.key, try Value.fromString(arena_alloc, str), self.dupe_behavior),
|
.line_string, .space_string => |str| try putMap(map, pair.key, try Value.fromString(arena_alloc, str), self.dupe_behavior),
|
||||||
.flow_list => |str| try putMap(map, pair.key, try parseFlowList(arena_alloc, str, self.dupe_behavior), self.dupe_behavior),
|
.flow_list => |str| try putMap(map, pair.key, try parseFlowList(arena_alloc, str, self.dupe_behavior), self.dupe_behavior),
|
||||||
.flow_map => |str| try putMap(map, pair.key, try parseFlowMap(arena_alloc, str, self.dupe_behavior), self.dupe_behavior),
|
.flow_map => |str| try putMap(map, pair.key, try parseFlowMap(arena_alloc, str, self.dupe_behavior), self.dupe_behavior),
|
||||||
},
|
}
|
||||||
// a new map is being created
|
} else if (line.indent == .indent) {
|
||||||
.indent => {
|
if (expect_shift != .indent or dangling_key == null) return error.UnexpectedValue;
|
||||||
if (expect_shift != .indent or dangling_key == null) return error.UnexpectedValue;
|
|
||||||
|
|
||||||
const new_map = try putMapGetValue(map, dangling_key.?, Value.newMap(arena_alloc), self.dupe_behavior);
|
const new_map = try putMapGetValue(map, dangling_key.?, Value.newMap(arena_alloc), self.dupe_behavior);
|
||||||
try stack.append(new_map);
|
try stack.append(new_map);
|
||||||
dangling_key = null;
|
dangling_key = null;
|
||||||
|
continue :flipflop;
|
||||||
switch (pair.val) {
|
} else unreachable;
|
||||||
.empty => {
|
|
||||||
expect_shift = .indent;
|
|
||||||
dangling_key = try arena_alloc.dupe(u8, pair.key);
|
|
||||||
},
|
|
||||||
.scalar => |str| try new_map.map.put(pair.key, try Value.fromScalar(arena_alloc, str)),
|
|
||||||
.line_string, .space_string => |str| try new_map.map.put(pair.key, try Value.fromString(arena_alloc, str)),
|
|
||||||
.flow_list => |str| try new_map.map.put(pair.key, try parseFlowList(arena_alloc, str, self.dupe_behavior)),
|
|
||||||
.flow_map => |str| try new_map.map.put(pair.key, try parseFlowMap(arena_alloc, str, self.dupe_behavior)),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1319,7 +1275,7 @@ pub const FlowParser = struct {
|
|||||||
// forbid these characters so that flow dictionary keys cannot start
|
// forbid these characters so that flow dictionary keys cannot start
|
||||||
// with characters that regular dictionary keys cannot start with
|
// with characters that regular dictionary keys cannot start with
|
||||||
// (even though they're unambiguous in this specific context).
|
// (even though they're unambiguous in this specific context).
|
||||||
'{', '[', '#', '>', '|', ',' => return error.BadToken,
|
'{', '[', '#', '-', '>', '|', ',' => return error.BadToken,
|
||||||
':' => {
|
':' => {
|
||||||
// we have an empty map key
|
// we have an empty map key
|
||||||
dangling_key = "";
|
dangling_key = "";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user