Skip to content

Commit d20dd52

Browse files
author
BirdeeHub
committed
fix(spec): inline properly prevents further setting in all cases now
1 parent 0b29130 commit d20dd52

4 files changed

Lines changed: 84 additions & 120 deletions

File tree

src/decode.c

Lines changed: 23 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212
#include "decode_inline_value.h"
1313

1414
#define DECODE_RESULT_IDX 2
15-
#define DECODE_ERR_IDX 3
1615
// @type { [table]: len if array or -1 for defined table }
17-
#define DECODE_DEFINED_IDX 4
16+
// or error userdata type on error
17+
#define DECODE_DEFINED_IDX 3
1818

1919
// pops keys, leaves new root on top
2020
static inline bool heading_nav(lua_State *L, int keys_len, bool array_type) {
21-
if (keys_len <= 0) return set_tmlerr(new_tmlerr(L, DECODE_ERR_IDX), false, 28, "no keys provided to navigate");
21+
if (keys_len <= 0) return set_tmlerr(new_tmlerr(L, DECODE_DEFINED_IDX), false, 28, "no keys provided to navigate");
2222
int keys_start = absindex(lua_gettop(L), -keys_len);
2323
lua_pushvalue(L, DECODE_RESULT_IDX);
2424
for (int key_idx = keys_start; key_idx < keys_start + keys_len; key_idx++) {
@@ -33,7 +33,7 @@ static inline bool heading_nav(lua_State *L, int keys_len, bool array_type) {
3333
lua_pushvalue(L, -2);
3434
lua_rawset(L, parent_idx); // t[key] = new table
3535
} else if (vtype != LUA_TTABLE) {
36-
return set_tmlerr(new_tmlerr(L, DECODE_ERR_IDX), false, 33, "cannot navigate through non-table");
36+
return set_tmlerr(new_tmlerr(L, DECODE_DEFINED_IDX), false, 33, "cannot navigate through non-table");
3737
}
3838
lua_remove(L, parent_idx); // remove parent table, keep child on top
3939
lua_pushvalue(L, -1);
@@ -54,7 +54,7 @@ static inline bool heading_nav(lua_State *L, int keys_len, bool array_type) {
5454
lua_rawseti(L, parent_idx, len);
5555
lua_remove(L, parent_idx); // remove parent table, keep child on top
5656
} else if (len != 0) {
57-
return set_tmlerr(new_tmlerr(L, DECODE_ERR_IDX), false, 22, "table already defined!");
57+
return set_tmlerr(new_tmlerr(L, DECODE_DEFINED_IDX), false, 22, "table already defined!");
5858
} else {
5959
lua_pushvalue(L, -1);
6060
lua_pushinteger(L, -1);
@@ -64,58 +64,14 @@ static inline bool heading_nav(lua_State *L, int keys_len, bool array_type) {
6464
lua_rawgeti(L, -1, len);
6565
lua_remove(L, -2);
6666
if (!lua_istable(L, -1))
67-
return set_tmlerr(new_tmlerr(L, DECODE_ERR_IDX), false, 33, "cannot navigate through non-table");
67+
return set_tmlerr(new_tmlerr(L, DECODE_DEFINED_IDX), false, 33, "cannot navigate through non-table");
6868
}
6969
}
7070
lua_insert(L, keys_start);
7171
lua_settop(L, keys_start);
7272
return true;
7373
}
7474

75-
// pops value and keys, leaves root on top
76-
static inline bool set_kv(lua_State *L, int keys_len, int value_idx, int erridx) {
77-
if (keys_len <= 0) return set_tmlerr(new_tmlerr(L, erridx), false, 22, "no key provided to set");
78-
int keys_start = value_idx + 1;
79-
int root_idx = value_idx - 1;
80-
lua_pushvalue(L, root_idx); // copy root table to top
81-
82-
// Navigate through all keys except the last
83-
for (int key_idx = keys_start; key_idx < keys_start + keys_len - 1; key_idx++) {
84-
int parent_idx = lua_gettop(L);
85-
lua_pushvalue(L, key_idx);
86-
lua_rawget(L, parent_idx);
87-
int vtype = lua_type(L, -1);
88-
if (vtype == LUA_TNIL) {
89-
lua_pop(L, 1); // remove nil
90-
lua_newtable(L); // create new table
91-
lua_pushvalue(L, key_idx);
92-
lua_pushvalue(L, -2); // copy so we can continue with it after rawset
93-
lua_rawset(L, parent_idx); // t[key] = new table
94-
} else if (vtype != LUA_TTABLE) {
95-
return set_tmlerr(new_tmlerr(L, erridx), false, 18, "key is not a table");
96-
}
97-
lua_remove(L, parent_idx);
98-
// NOTE: set_kv in decode_inline_value does not do the next 3 lines
99-
lua_pushvalue(L, -1);
100-
lua_pushinteger(L, -1);
101-
lua_rawset(L, DECODE_DEFINED_IDX);
102-
}
103-
104-
lua_pushvalue(L, -2);
105-
lua_rawget(L, -2);
106-
if (!lua_isnil(L, -1)) {
107-
return set_tmlerr(new_tmlerr(L, erridx), false, 18, "key already defined!");
108-
}
109-
lua_pop(L, 1);
110-
111-
lua_pushvalue(L, -2); // push last key
112-
lua_pushvalue(L, value_idx); // push value
113-
lua_rawset(L, -3); // parent[last_key] = value
114-
115-
lua_settop(L, root_idx);
116-
return true;
117-
}
118-
11975
int tomlua_decode(lua_State *L) {
12076
// process arguments and options
12177
str_iter src = lua_str_to_iter(L, 1);
@@ -131,10 +87,9 @@ int tomlua_decode(lua_State *L) {
13187
lua_settop(L, 1);
13288
// DECODE_RESULT_IDX == 2 == here
13389
lua_newtable(L);
134-
// DECODE_ERR_IDX == 3 == here
135-
lua_pushnil(L);
136-
// DECODE_DEFINED_IDX == 4 == here
90+
// DECODE_DEFINED_IDX == 3 == here
13791
// @type { [table]: len if array or -1 for defined table }
92+
// or error if error
13893
lua_newtable(L);
13994

14095
// set top as the starting location
@@ -157,56 +112,56 @@ int tomlua_decode(lua_State *L) {
157112
if (iter_starts_with(&src, "[[", 2)) {
158113
iter_skip_n(&src, 2);
159114
lua_pop(L, 1); // pop current location, we are moving
160-
int keys_len = parse_keys(L, &src, &scratch, int_keys, DECODE_ERR_IDX);
115+
int keys_len = parse_keys(L, &src, &scratch, int_keys, DECODE_DEFINED_IDX);
161116
if (!keys_len) goto fail;
162117
if (!iter_starts_with(&src, "]]", 2)) {
163-
set_tmlerr(new_tmlerr(L, DECODE_ERR_IDX), false, 30, "table heading must end with ]]");
118+
set_tmlerr(new_tmlerr(L, DECODE_DEFINED_IDX), false, 30, "table heading must end with ]]");
164119
goto fail;
165120
}
166121
iter_skip_n(&src, 2); // consume ]]
167122
if (!consume_whitespace_to_line(&src)) {
168-
set_tmlerr(new_tmlerr(L, DECODE_ERR_IDX), false, 56, "array [[headers]] must have a new line before new values");
123+
set_tmlerr(new_tmlerr(L, DECODE_DEFINED_IDX), false, 56, "array [[headers]] must have a new line before new values");
169124
goto fail;
170125
}
171126
if (!heading_nav(L, keys_len, true)) goto fail;
172127
} else if (iter_peek(&src).v == '[') {
173128
iter_skip(&src);
174129
lua_pop(L, 1); // pop current location, we are moving
175-
int keys_len = parse_keys(L, &src, &scratch, int_keys, DECODE_ERR_IDX);
130+
int keys_len = parse_keys(L, &src, &scratch, int_keys, DECODE_DEFINED_IDX);
176131
if (!keys_len) goto fail;
177132
if (iter_peek(&src).v != ']') {
178-
set_tmlerr(new_tmlerr(L, DECODE_ERR_IDX), false, 29, "table heading must end with ]");
133+
set_tmlerr(new_tmlerr(L, DECODE_DEFINED_IDX), false, 29, "table heading must end with ]");
179134
goto fail;
180135
}
181136
iter_skip(&src); // consume ]
182137
if (!consume_whitespace_to_line(&src)) {
183-
set_tmlerr(new_tmlerr(L, DECODE_ERR_IDX), false, 54, "table [headers] must have a new line before new values");
138+
set_tmlerr(new_tmlerr(L, DECODE_DEFINED_IDX), false, 54, "table [headers] must have a new line before new values");
184139
goto fail;
185140
}
186141
if (!heading_nav(L, keys_len, false)) goto fail;
187142
} else {
188143
lua_pushnil(L);
189144
int val_spacer = lua_gettop(L);
190-
int keys_len = parse_keys(L, &src, &scratch, int_keys, DECODE_ERR_IDX);
145+
int keys_len = parse_keys(L, &src, &scratch, int_keys, DECODE_DEFINED_IDX);
191146
if (!keys_len) goto fail;
192147
if (iter_peek(&src).v != '=') {
193-
set_tmlerr(new_tmlerr(L, DECODE_ERR_IDX), false, 35, "keys for assignment must end with =");
148+
set_tmlerr(new_tmlerr(L, DECODE_DEFINED_IDX), false, 35, "keys for assignment must end with =");
194149
goto fail;
195150
}
196151
iter_skip(&src); // consume =
197152
if (consume_whitespace_to_line(&src)) {
198-
set_tmlerr(new_tmlerr(L, DECODE_ERR_IDX), false, 76, "the value in key = value expressions must begin on the same line as the key!");
153+
set_tmlerr(new_tmlerr(L, DECODE_DEFINED_IDX), false, 76, "the value in key = value expressions must begin on the same line as the key!");
199154
goto fail;
200155
}
201-
if (!decode_inline_value(L, &src, &scratch, uopts, DECODE_ERR_IDX)) goto fail;
156+
if (!decode_inline_value(L, &src, &scratch, uopts, DECODE_DEFINED_IDX)) goto fail;
202157
lua_replace(L, val_spacer);
203158
// [-1?] keys
204159
// [-?] value
205160
// [-?-1] current root table
206-
if (!set_kv(L, keys_len, val_spacer, DECODE_ERR_IDX)) goto fail;
161+
if (!set_kv(L, keys_len, val_spacer, DECODE_DEFINED_IDX)) goto fail;
207162
// [-1] current root table
208163
if (!consume_whitespace_to_line(&src)) {
209-
set_tmlerr(new_tmlerr(L, DECODE_ERR_IDX), false, 66, "key value pairs must be followed by a new line (or end of content)");
164+
set_tmlerr(new_tmlerr(L, DECODE_DEFINED_IDX), false, 66, "key value pairs must be followed by a new line (or end of content)");
210165
goto fail;
211166
}
212167
}
@@ -217,10 +172,10 @@ int tomlua_decode(lua_State *L) {
217172
return 1;
218173

219174
fail:
220-
lua_settop(L, DECODE_ERR_IDX);
221-
tmlerr_push_ctx_from_iter(get_err_val(L, DECODE_ERR_IDX), 7, &src);
175+
lua_settop(L, DECODE_DEFINED_IDX);
176+
tmlerr_push_ctx_from_iter(get_err_val(L, DECODE_DEFINED_IDX), 7, &src);
222177
free_str_buf(&scratch);
223178
lua_pushnil(L);
224-
push_tmlerr_string(L, get_err_val(L, DECODE_ERR_IDX));
179+
push_tmlerr_string(L, get_err_val(L, DECODE_DEFINED_IDX));
225180
return 2;
226181
}

src/decode_inline_value.c

Lines changed: 8 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,46 +14,6 @@
1414
#include "decode_str.h"
1515
#include "decode_inline_value.h"
1616

17-
// pops value and keys, leaves root on top
18-
static inline bool set_kv(lua_State *L, int keys_len, int value_idx, int erridx) {
19-
if (keys_len <= 0) return set_tmlerr(new_tmlerr(L, erridx), false, 22, "no key provided to set");
20-
int keys_start = value_idx + 1;
21-
int root_idx = value_idx - 1;
22-
lua_pushvalue(L, root_idx); // copy root table to top
23-
24-
// Navigate through all keys except the last
25-
for (int key_idx = keys_start; key_idx < keys_start + keys_len - 1; key_idx++) {
26-
int parent_idx = lua_gettop(L);
27-
lua_pushvalue(L, key_idx);
28-
lua_rawget(L, parent_idx);
29-
int vtype = lua_type(L, -1);
30-
if (vtype == LUA_TNIL) {
31-
lua_pop(L, 1); // remove nil
32-
lua_newtable(L); // create new table
33-
lua_pushvalue(L, key_idx);
34-
lua_pushvalue(L, -2); // copy so we can continue with it after rawset
35-
lua_rawset(L, parent_idx); // t[key] = new table
36-
} else if (vtype != LUA_TTABLE) {
37-
return set_tmlerr(new_tmlerr(L, erridx), false, 18, "key is not a table");
38-
}
39-
lua_remove(L, parent_idx);
40-
}
41-
42-
lua_pushvalue(L, -2);
43-
lua_rawget(L, -2);
44-
if (!lua_isnil(L, -1)) {
45-
return set_tmlerr(new_tmlerr(L, erridx), false, 18, "key already defined!");
46-
}
47-
lua_pop(L, 1);
48-
49-
lua_pushvalue(L, -2); // push last key
50-
lua_pushvalue(L, value_idx); // push value
51-
lua_rawset(L, -3); // parent[last_key] = value
52-
53-
lua_settop(L, root_idx);
54-
return true;
55-
}
56-
5717
// adds a table to the lua stack and return NULL or error
5818
static inline bool parse_inline_table(lua_State *L, str_iter *src, str_buf *buf, const TomluaUserOpts opts, int erridx) {
5919
lua_newtable(L);
@@ -63,6 +23,10 @@ static inline bool parse_inline_table(lua_State *L, str_iter *src, str_buf *buf,
6323
lua_setfield(L, -2, "toml_type");
6424
lua_setmetatable(L, -2);
6525
}
26+
// NOTE: erridx is secretly also our defined table when no error
27+
lua_pushvalue(L, -1);
28+
lua_pushinteger(L, -1);
29+
lua_rawset(L, erridx);
6630
bool last_was_comma = false;
6731
const bool int_keys = opts[TOMLOPTS_INT_KEYS];
6832
const bool fancy_tables = opts[TOMLOPTS_FANCY_TABLES];
@@ -451,6 +415,10 @@ bool decode_inline_value(lua_State *L, str_iter *src, str_buf *buf, const Tomlua
451415
lua_setfield(L, -2, "toml_type");
452416
lua_setmetatable(L, -2);
453417
}
418+
// NOTE: erridx is secretly also our defined table when no error
419+
lua_pushvalue(L, -1);
420+
lua_pushinteger(L, -1);
421+
lua_rawset(L, erridx);
454422
int idx = 1;
455423
while (iter_peek(src).ok) {
456424
char d = iter_peek(src).v;

src/decode_inline_value.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,54 @@
55
#include <lua.h>
66
#include "./types.h"
77
#include "./opts.h"
8+
#include "./error_context.h"
89

910
// function is to recieve src iterator starting after the first `=`,
1011
// and place 1 new item on the stack but otherwise leave the stack unchanged
1112
bool decode_inline_value(lua_State *L, str_iter *src, str_buf *buf, const TomluaUserOpts opts, int erridx);
1213

14+
// pops value and keys, leaves root on top
15+
static inline bool set_kv(lua_State *L, int keys_len, int value_idx, int erridx) {
16+
if (keys_len <= 0) return set_tmlerr(new_tmlerr(L, erridx), false, 22, "no key provided to set");
17+
int keys_start = value_idx + 1;
18+
int root_idx = value_idx - 1;
19+
lua_pushvalue(L, root_idx); // copy root table to top
20+
21+
// Navigate through all keys except the last
22+
for (int key_idx = keys_start; key_idx < keys_start + keys_len - 1; key_idx++) {
23+
int parent_idx = lua_gettop(L);
24+
lua_pushvalue(L, key_idx);
25+
lua_rawget(L, parent_idx);
26+
int vtype = lua_type(L, -1);
27+
if (vtype == LUA_TNIL) {
28+
lua_pop(L, 1); // remove nil
29+
lua_newtable(L); // create new table
30+
lua_pushvalue(L, key_idx);
31+
lua_pushvalue(L, -2); // copy so we can continue with it after rawset
32+
lua_rawset(L, parent_idx); // t[key] = new table
33+
} else if (vtype != LUA_TTABLE) {
34+
return set_tmlerr(new_tmlerr(L, erridx), false, 18, "key is not a table");
35+
}
36+
lua_remove(L, parent_idx);
37+
// NOTE: erridx is secretly also our defined table when no error
38+
lua_pushvalue(L, -1);
39+
lua_pushinteger(L, -1);
40+
lua_rawset(L, erridx);
41+
}
42+
43+
lua_pushvalue(L, -2);
44+
lua_rawget(L, -2);
45+
if (!lua_isnil(L, -1)) {
46+
return set_tmlerr(new_tmlerr(L, erridx), false, 18, "key already defined!");
47+
}
48+
lua_pop(L, 1);
49+
50+
lua_pushvalue(L, -2); // push last key
51+
lua_pushvalue(L, value_idx); // push value
52+
lua_rawset(L, -3); // parent[last_key] = value
53+
54+
lua_settop(L, root_idx);
55+
return true;
56+
}
57+
1358
#endif // SRC_DECODE_INLINE_VALUE_H_

tests/scratch.lua

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,16 @@ do
117117
multi_strings = true,
118118
}
119119
local errtoml = [=[
120+
121+
# INVALID TOML DOC
122+
fruits = []
123+
database = { duplicate = { hehe = "haha" }}
124+
120125
release_date = 2022-08-24T12:00:00.666969696969696969Z
121126
next_release = 2028-08-24T12:00:00.666Z
122127
last_backup = 2025-08-23T23:45:12-07:00
123128
last_modified = 2025-08-24 12:00:00Z
129+
124130
[[fruits]]
125131
name = "apple"
126132
@@ -149,17 +155,6 @@ do
149155
names."boo2" = "hi2"
150156
"tk2-dsadas.com" = "value"
151157
"tk2-dsadas.com" = "vaaalue"
152-
I AM AN ERROR
153-
[test2]
154-
key = "value"
155-
"tk1-assass.com" = "value"
156-
[[test2.key2]]
157-
das1 = "dasda"
158-
das2 = 'dasda'
159-
'das3' = '''da
160-
sda'''
161-
das4 = """da
162-
sda"""
163158
164159
[database]
165160
type = "postgres"
@@ -173,7 +168,8 @@ do
173168
host = "replica1.local"
174169
port = 5433
175170
]=]
176-
print(toml.decode(errtoml))
171+
local d, e = toml.decode(errtoml)
172+
print(require('inspect')(d), e)
177173
end
178174

179175
local val = { c = 123456, b = { "hi", a = "b" } }

0 commit comments

Comments
 (0)