Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions src/lua/zencode_data.lua
Original file line number Diff line number Diff line change
Expand Up @@ -672,3 +672,102 @@ function apply_encoding(src_name, src_enc, dest_enc)
if not f_dest_enc then error("Destination encoding format not found: "..dest_enc, 2) end
return deepmap(f_dest_enc.fun, encoded_src)
end

-- READ and WRITE to ACK memory

-- extract an element from deep down
-- works both in IN and ACK memory
-- @param path path to variable separated by points
-- @return element found following the path
-- @return name of the destination
function read_from_path(path, no_dest)
local path_array = strtok(uscore(path), CONF.path.separator)
local root = path_array[1]
table.remove(path_array, 1)
local dest = path_array[#path_array]
if not no_dest then empty(dest) end
-- should works both in given and when phase
-- IN is checked firstly since in the When phase IN will be empty
local res = IN[root] or ACK[root]
for _,v in pairs(path_array) do
zencode_assert(luatype(res) == 'table', "Object is not a table: "..root)
if res[v] == nil then
local v_number = tonumber(v)
zencode_assert(v_number and res[v_number] ~= nil, "Key "..v.." not found in "..root)
res = res[v_number]
else
res = res[v]
end
root = v
end
return res, dest
end

-- set an element deep down
-- @param path to dest separated by points
-- @param value to set in path
function write_to_path(path, value)
local path_array <const> = strtok(uscore(path), CONF.path.separator)
if #path_array == 0 then
error("write_to_path path input is empty", 2)
end
local current_path = ""
local current = ACK

for i = 1, #path_array - 1 do
local raw_key = path_array[i]
local key = tonumber(raw_key) or raw_key
current_path = fif(i == 1, "", current_path .. ".") .. raw_key

-- Current must always be a table
if luatype(current) ~= "table" then
error("Path error at segment '" .. current_path .. "': not a table")
end
-- Handle array case
if luatype(key) == "number" then
local arr_length = isarray(current)
if not arr_length then
error("Path error at '" .. current_path .. "': expected array, found " .. luatype(current[key]))
end
if current[key] == nil then
if key ~= arr_length + 1 then
error("Invalid array index at '" .. current_path .. "': expected position between 1 and " .. (arr_length + 1))
end
current[key] = {}
end
else
if current[key] ~= nil then
local ltc <const> = luatype(current[key])
if ltc ~= "table" then
error("Path conflict at '" .. current_path .. "': expected table, found " .. ltc)
end
else
current[key] = {}
end
end
current = current[key]
end

local final_raw = path_array[#path_array]
local final_key = tonumber(final_raw) or final_raw
current_path = current_path.."."..final_raw

if luatype(current) ~= "table" then
error("Cannot assign at path '" .. current_path .. "': parent is not a table")
end
-- Make sure to not overwrite existing value
if current[final_key] ~= nil then
error("Cannot overwrite existing value at path '" .. current_path .. "'")
end
-- Final value: if it's an array index, make sure it's next free position
if luatype(final_key) == "number" then
local arr_length = isarray(current)
if not arr_length then
error("Path error at '" .. current_path .. "': expected array, found " .. luatype(current))
end
if final_key ~= arr_length + 1 then
error("Invalid array index at '" .. current_path .. "': expected position " .. (arr_length + 1))
end
end
current[final_key] = value
end
6 changes: 3 additions & 3 deletions src/lua/zencode_given.lua
Original file line number Diff line number Diff line change
Expand Up @@ -445,15 +445,15 @@ Given("'' part of '' before string suffix ''", function(enc, src, sfx_name)
end)

Given("'' in path ''", function(enc, path)
local ele_from_path, dest = pick_from_path(path)
local ele_from_path, dest = read_from_path(path)
ZEN.TMP = guess_conversion(ele_from_path, enc)
ZEN.TMP.name = dest
ack(dest)
gc()
end)

Given("'' part of path '' after string prefix ''", function(enc, path, pfx_name)
local ele_from_path, dest = pick_from_path(path)
local ele_from_path, dest = read_from_path(path)
local pfx = IN[pfx_name] or pfx_name
local plen = #pfx
elelen = #ele_from_path
Expand All @@ -470,7 +470,7 @@ end)


Given("'' part of path '' before string suffix ''", function(enc, path, sfx_name)
local ele_from_path, dest = pick_from_path(path)
local ele_from_path, dest = read_from_path(path)
local sfx = IN[sfx_name] or sfx_name
local slen = #sfx
elelen = #ele_from_path
Expand Down
2 changes: 1 addition & 1 deletion src/lua/zencode_math.lua
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ local function _rpn_eval(rpn)
res = v
else
-- handle path divided by conf separator in value name
res = pick_from_path(v, true)
res = read_from_path(v, true)
end
end
insert(values, res)
Expand Down
4 changes: 2 additions & 2 deletions src/lua/zencode_merkle.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
local MT = require'crypto_merkle'

local function _zencode_merkle_root(name, hashtype)
local data = pick_from_path(name, true)
local data = read_from_path(name, true)
if not data or type(data) ~= 'table' then
error("Table not found in path: "..name, 2)
end
Expand All @@ -39,7 +39,7 @@ When("create merkle root of dictionary path '' using hash ''", _zencode_merkle_r
-- Function to verify the integrity of a Merkle root
local function _verify_merkle_root(root, name)
local merkle_root = have(root)
local data_table = pick_from_path(name, true)
local data_table = read_from_path(name, true)
if not data_table or type(data_table) ~= 'table' then
error("Table not found in path: "..name, 2)
end
Expand Down
2 changes: 1 addition & 1 deletion src/lua/zencode_table.lua
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ end)

local function take_out_f(path, dest, format)
if dest then path = path..CONF.path.separator..dest end
local ele <const>, dest <const> = pick_from_path(path)
local ele <const>, dest <const> = read_from_path(path)
ACK[dest] = ele
if format then
new_codec(dest, guess_conversion(ACK[dest], format))
Expand Down
7 changes: 7 additions & 0 deletions src/lua/zencode_when.lua
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,13 @@ When("write string '' in ''", function(content, dest)
zentype = 'e' })
end)

When("write string '' in path ''", function(content, dest_path)
local maybe = mayhave(dest_path)
local path = maybe and maybe:octet():string() or dest_path
have(string.match(path, "^[^%.]+"))
write_to_path(path, O.from_string(content))
end)

-- ... and from a number
When("write number '' in ''", function(content, dest)
empty(dest)
Expand Down
28 changes: 0 additions & 28 deletions src/lua/zenroom_common.lua
Original file line number Diff line number Diff line change
Expand Up @@ -420,34 +420,6 @@ function zip(...)
end
end

-- extract an element from deep down
-- works both in IN and ACK memory
-- @param path path to variable separated by points
-- @return element found following the path
-- @return name of the destination
function pick_from_path(path, no_dest)
local path_array = strtok(uscore(path), CONF.path.separator)
local root = path_array[1]
table.remove(path_array, 1)
local dest = path_array[#path_array]
if not no_dest then empty(dest) end
-- should works both in given and when phase
-- IN is checked firstly since in the When phase IN will be empty
local res = IN[root] or ACK[root]
for _,v in pairs(path_array) do
zencode_assert(luatype(res) == 'table', "Object is not a table: "..root)
if res[v] == nil then
local v_number = tonumber(v)
zencode_assert(v_number and res[v_number] ~= nil, "Key "..v.." not found in "..root)
res = res[v_number]
else
res = res[v]
end
root = v
end
return res, dest
end

-- -- MULTIBASE

-- Unicode, character, encoding, description, status
Expand Down
30 changes: 28 additions & 2 deletions test/zencode/cookbook_when.bats
Original file line number Diff line number Diff line change
Expand Up @@ -1847,7 +1847,7 @@ Then print 'random dictionary'
EOF
save_output when_random_from_table.out.json
assert_output '{"random_array":[1,3],"random_dictionary":{"str3":"world","str4":"!"},"random_pick":"world"}'
}
}

@test "hash to point on a curve" {
cat <<EOF | save_asset when_hash_to_point.data.json
Expand All @@ -1869,4 +1869,30 @@ Then print 'hash to point ecp'
EOF
save_output when_hash_to_point.out.json
assert_output '{"hash_to_point_ecp":"AxAXy/Tldf0HPLWpeby/p9r5N5KWsRtyOOhupzDyD+zgpiyIM9ET0sBhcfXQyxD2Iw==","hash_to_point_ecp2":"EKDkY8NZoPBUrXbCKuGTfACzGhYjDN1ukN4WFeC1KruGArzmM2GjcNl540ccj1NwBmJripsCB8dKAZdHsPExCa2bd1HXbCvOIlaT0+yvl8Zb+MjzPAuvOs2y9rpKK/+GBGkYvsUr8aoHyijjv34XjG+6APolthn9+RA3p+Eluos5RjoIiPsYcgixpF+8rj4OEWDf3to6w2qomLHGf0lwhEzMZbPZ67zGYXUkJHSR2cGT/jdPufs7M9Havmq0iCiY"}'
}
}

@test "write string in path" {
cat <<EOF | save_asset write_string_in_path.data.json
{
"path": "a.b.c.1.1.d",
"a": {
"b": {
}
}
}
EOF
cat <<EOF | zexe write_string_in_path.zen write_string_in_path.data.json
Given I have a 'string' named 'path'
Given I have a 'string dictionary' named 'a'

When I write string 'hello' in path 'path'
When I write string 'hello' in path 'a.b.e'
When I write string 'hello' in path 'a.b.c.2'
When I write string 'hello' in path 'a.b.c.1.2'

Then print 'a'

EOF
save_output write_string_in_path.out.json
assert_output '{"a":{"b":{"c":[[{"d":"hello"},"hello"],"hello"],"e":"hello"}}}'
}