Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ✨ various improvements on move and copy statements #822

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
41 changes: 41 additions & 0 deletions src/lua/zencode_data.lua
Original file line number Diff line number Diff line change
Expand Up @@ -583,3 +583,44 @@ end
local pruned_tables = prune_in(pruned_values)
return pruned_tables
end

-- encode the octet in ACK[src_name] following the src_enc
-- and then it transform it back to octet following the dest_enc
-- @param src_name name of the variable in ACK
-- @param src_enc the encoding to use when transforming ACK[src_name] into string
-- @param dest_enc the encoding to use when transfroming back the string into octet
-- @return the octet/table of octets of the above transformation
function apply_encoding(src_name, src_enc, dest_enc)
local src_value, src_codec = have(src_name)
f_src_enc = get_encoding_function(src_enc)
if not f_src_enc then error("Encoding format not found: "..src_enc, 2) end
local encoded_src
-- accpet also schemas as encoding
if ZEN.schemas[uscore(src_enc)] then
if uscore(src_enc) ~= src_codec.schema then
error("Source schema: "..src_codec.schema.." does not match encoding "..src_enc)
end
if f_src_enc == default_export_f then
f_src_enc = function (obj)
if luatype(obj) == "table" then
return deepmap(CONF.output.encoding.fun, obj)
else
return CONF.output.encoding.fun(obj)
end
end
end
if src_codec.zentype == "e" then
encoded_src = f_src_enc(src_value)
else
encoded_src = {}
for k,v in src_value do
encoded_src[k] = f_src_enc(src_value)
end
end
else
encoded_src = deepmap(f_src_enc, src_value)
end
f_dest_enc = input_encoding(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
51 changes: 39 additions & 12 deletions src/lua/zencode_table.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,30 @@
--on Monday, 28th August 2023
--]]

local function move_or_copy_in(src_value, src_name, dest)
local d = have(dest)
local function move_or_copy_in(src_value, src_name, dest, new, enc)
local d, cdest = have(dest)
if luatype(d) ~= 'table' then error("Object is not a table: "..dest, 2) end
local cdest = CODEC[dest]
local new_name = new or src_name
if enc then
src_value = apply_encoding(src_name, enc, cdest.encoding)
end
if cdest.zentype == 'e' and cdest.schema then
local sdest = ZEN.schemas[cdest.schema]
if luatype(sdest) ~= 'table' then -- old schema types are not open
error("Schema is not open to accept extra objects: "..dest)
error("Schema is not open to accept extra objects: "..dest, 2)
elseif not sdest.schematype or sdest.schematype ~= 'open' then
error("Schema is not open to accept extra objects: "..dest)
error("Schema is not open to accept extra objects: "..dest, 2)
end
if d[src_name] then
error("Cannot overwrite: "..src_name.." in "..dest,2)
if d[new_name] then
error("Cannot overwrite: "..new_name.." in "..dest,2)
end
d[src_name] = src_value
d[new_name] = src_value
ACK[dest] = d
elseif cdest.zentype == 'd' then
if d[src_name] then
error("Cannot overwrite: "..src_name.." in "..dest,2)
if d[new_name] then
error("Cannot overwrite: "..new_name.." in "..dest,2)
end
d[src_name] = src_value
d[new_name] = src_value
ACK[dest] = d
elseif cdest.zentype == 'a' then
table.insert(ACK[dest], src_value)
Expand All @@ -62,7 +65,19 @@ When("move '' in ''", function(src, dest)
CODEC[src] = nil
end)

When("move '' from '' to ''", function(name, src, dest)
When("move '' to '' in ''", function(src, new, dest)
move_or_copy_in(have(src), src, dest, new)
ACK[src] = nil
CODEC[src] = nil
end)

When("move '' as '' in ''", function(src, enc, dest)
move_or_copy_in(have(src), src, dest, nil, enc)
ACK[src] = nil
CODEC[src] = nil
end)

When("move '' from '' in ''", function(name, src, dest)
move_or_copy_in(have({src, name}), name, dest)
ACK[src][name] = nil
end)
Expand All @@ -76,6 +91,18 @@ When("copy '' in ''", function(src, dest)
move_or_copy_in(deepcopy(have(src)), src, dest)
end)

When("copy '' to '' in ''", function(src, new, dest)
move_or_copy_in(have(src), src, dest, new)
end)

When("copy '' as '' in ''", function(src, enc, dest)
move_or_copy_in(have(src), src, dest, nil, enc)
end)

When("copy '' from '' in ''", function(name, src, dest)
move_or_copy_in(have({src, name}), name, dest)
end)

local function _when_remove_dictionary(ele, from)
-- ele is just the name (key) of object to remove
local dict = have(from)
Expand Down
142 changes: 94 additions & 48 deletions src/lua/zencode_when.lua
Original file line number Diff line number Diff line change
Expand Up @@ -234,65 +234,111 @@ When("create '' string of ''", function(encoding, src)
encoding = 'string' })
end)

When("copy '' to ''", function(old,new)
have(old)
empty(new)
ACK[new] = deepcopy(ACK[old])
new_codec(new, { }, old)
end)

local function _copy_move_in(old, new, inside, delete)
local src = have(old)
local dst = have(inside)
zencode_assert(luatype(dst) == 'table', "Destination is not a table: "..inside)
zencode_assert(not dst[new],
"Cannot overwrite destination: "..new.." inside "..inside)
dst[new] = deepcopy(src)
ACK[inside] = dst
if delete then
ACK[old] = nil
CODEC[old] = nil
end
local function move_or_copy_to(src, dest, enc)
empty(dest)
if not enc then
ACK[dest] = deepcopy(ACK[src])
new_codec(dest, { }, src)
else
ACK[dest] = apply_encoding(src, enc, "string")
new_codec(dest, { encoding = 'string' })
end
end
When("copy '' to '' in ''", function(old,new,inside)
_copy_move_in(old, new, inside, false)

When("copy '' to ''", move_or_copy_to)

When("copy '' as '' to ''", function(src, enc, dest)
move_or_copy_to(src, dest, enc)
end)
When("move '' to '' in ''", function(old,new,inside)
_copy_move_in(old, new, inside, true)

When("move '' to ''", function(src, dest)
move_or_copy_to(src, dest)
ACK[src] = nil
CODEC[src] = nil
end)

When("move '' as '' to ''", function(src, enc, dest)
move_or_copy_to(src, dest, enc)
ACK[src] = nil
CODEC[src] = nil
end)

When("copy contents of '' in ''", function(src,dst)
local obj = have(src)
have(dst)
for k, v in pairs(obj) do
ACK[dst][k] = v -- no deepcopy
-- no new codec (using dst)
end
local obj, obj_codec = have(src)
zencode_assert(luatype(obj) == 'table', "Object is not a table: "..src)
local dest, dest_codec = have(dst)
zencode_assert(luatype(dest) == 'table', "Object is not a table: "..src)
if dest_codec.zentype == 'a' then
for _, v in pairs(obj) do
table.insert(ACK[dst], v)
end
elseif dest_codec.zentype == 'd' then
zencode_assert(obj_codec.zentype == 'd', "Can not copy contents of an array into a dictionary")
for k, v in pairs(obj) do
if ACK[dst][k] then error("Cannot overwrite: "..k.." in "..dst) end
ACK[dst][k] = v
end
elseif dest_codec.zentype == 'e' and dest_codec.schema then
local dest_schema = ZEN.schemas[dest_codec.schema]
if luatype(dest_schema) ~= 'table' then -- old schema types are not open
error("Schema is not open to accept extra objects: "..dst)
elseif not dest_schema.schematype or dest_schema.schematype ~= 'open' then
error("Schema is not open to accept extra objects: "..dst)
end
for k, v in pairs(obj) do
if ACK[dst][k] then error("Cannot overwrite: "..k.." in "..dst) end
ACK[dst][k] = v
end
end
end)

When("copy contents of '' named '' in ''", function(src,name,dst)
local obj = have(src)
have(dst)
for k, v in pairs(obj) do
if k == name then
ACK[dst][k] = v -- no deepcopy
end
-- no new codec (using dst)
end
local obj, obj_codec = have(src)
zencode_assert(luatype(obj) == 'table', "Object is not a table: "..src)
zencode_assert(obj_codec.zentype == 'd', "Object is not a dictionary: "..src)
zencode_assert(obj[name], "Object not found: "..name.." inside ".. src)
local dest, dest_codec = have(dst)
zencode_assert(luatype(dest) == 'table', "Object is not a table: "..src)
if dest_codec.zentype == 'a' then
table.insert(ACK[dst], obj[name])
elseif dest_codec.zentype == 'd' then
zencode_assert(dest[name], "Cannot overwrite: "..name.." in "..dst)
ACK[dst][name] = obj[name]
elseif dest_codec.zentype == 'e' and dest_codec.schema then
local dest_schema = ZEN.schemas[dest_codec.schema]
if luatype(dest_schema) ~= 'table' then -- old schema types are not open
error("Schema is not open to accept extra objects: "..dst)
elseif not dest_schema.schematype or dest_schema.schematype ~= 'open' then
error("Schema is not open to accept extra objects: "..dst)
end
zencode_assert(dest[name], "Cannot overwrite: "..name.." in "..dst)
ACK[dst][name] = obj[name]
end
end)

When("copy '' from '' to ''", function(old,inside,new)
zencode_assert(ACK[inside][old], "Object not found: "..old.." inside "..inside)
empty(new)
ACK[new] = deepcopy(ACK[inside][old])
local o_codec = CODEC[inside]
local n_codec = { encoding = o_codec.encoding }
-- table of schemas can only contain elements
if o_codec.schema then
n_codec.schema = o_codec.schema
n_codec.zentype = "e"
end
local function move_or_copy_from_to(ele, source, new)
local src, src_codec = have(source)
zencode_assert(src[ele], "Object not found: "..ele.." inside "..source)
if ACK[new] then
error("Cannot overwrite existing object: "..new.."\n"..
"To copy/move element in existing element use:\n"..
"When I move/copy '' from '' in ''", 2)
end
ACK[new] = deepcopy(src[ele])
local n_codec = { encoding = src_codec.encoding }
-- table of schemas can only contain elements
if src_codec.schema then
n_codec.schema = src_codec.schema
n_codec.zentype = "e"
end
new_codec(new, n_codec)
end

When("copy '' from '' to ''", move_or_copy_from_to)

When("move '' from '' to ''", function(ele, source, new)
move_or_copy_from_to(ele, source, new)
ACK[source][ele] = nil
end)

When("split rightmost '' bytes of ''", function(len, src)
Expand Down
55 changes: 52 additions & 3 deletions test/zencode/dictionary.bats
Original file line number Diff line number Diff line change
Expand Up @@ -678,10 +678,10 @@ Given I have a 'string' named 'name'

When I move 'myString' in 'myDict'
When I move named by 'name' in 'myArray'
When I move 'surname' from 'myDict' to 'myArray'
When I move 'surname' from 'myDict' in 'myArray'

When I create the 'string array' named 'myNewArray'
When I move 'name' from 'myDict' to 'myNewArray'
When I move 'name' from 'myDict' in 'myNewArray'

Then print the 'myDict'
and print the 'myArray'
Expand Down Expand Up @@ -720,12 +720,13 @@ Given I have a 'string' named 'name'
When I copy 'myArray' in 'myDict'
When I copy 'myDict' in 'myArray'
When I copy named by 'name' in 'myArray'
When I copy 'surname' from 'myDict' in 'myArray'

Then print the 'myDict'
and print the 'myArray'
EOF
save_output 'copy.json'
assert_output '{"myArray":["John","Doe","42",{"age":"44","myArray":["John","Doe","42"],"name":"Bruce","surname":"Wayne"},"where?"],"myDict":{"age":"44","myArray":["John","Doe","42"],"name":"Bruce","surname":"Wayne"}}'
assert_output '{"myArray":["John","Doe","42",{"age":"44","myArray":["John","Doe","42"],"name":"Bruce","surname":"Wayne"},"where?","Wayne"],"myDict":{"age":"44","myArray":["John","Doe","42"],"name":"Bruce","surname":"Wayne"}}'
}

@test "fail to move element in a close schema" {
Expand Down Expand Up @@ -800,3 +801,51 @@ EOF
save_output 'copy_from_schema_dictionary.json'
assert_output '{"copy":{"address":"0x2B8070975AF995Ef7eb949AE28ee7706B9039504","signature":"0xed8f36c71989f8660e8f5d4adbfd8f1c0288cca90d3a5330b7bf735d71ab52fe7ba0a7827dc4ba707431f1c10babd389f658f8e208b89390a9be3c097579a2ff1b"}}'
}

# TODO: move to table.bats (not doing in this moment since will create a lot of conflicts with another PR)
@test "move and copy statements" {
cat <<EOF | save_asset move_and_copy_statements.data.json
{
"my_dict": {
"str": "hello"
},
"keyring": {
"eddsa": "Cwj9CcqHNoBnXBo8iDfnhFkQeDun4Y4LStd2m3TEAYAg",
"ecdh": "yxL8P0pLHxsl3m8Nt6m9Zm0wSMzrWlD0JTAWlaheQg4="
},
"to_be_signed": "some data to be signed",
"base64_string": "aGVsbG8gbXkgZnJpZW5k"
}
EOF
cat <<EOF | zexe move_and_copy_statements.zen move_and_copy_statements.data.json
Scenario 'eddsa': sign
Scenario 'ecdh': sign
Given I have a 'keyring'
and I have a 'base64' named 'base64_string'
and I have a 'string' named 'to_be_signed'
and I have a 'string dictionary' named 'my_dict'

# sign
When I create the eddsa signature of 'to_be_signed'
and I create the ecdh signature of 'to_be_signed'

# copy
When I copy 'my_dict' to 'result_copy'
and I copy 'to_be_signed' to 'signed' in 'result_copy'
and I copy 'eddsa signature' as 'base58' in 'result_copy'
and I copy 'ecdh signature' as 'ecdh_signature' in 'result_copy'
and I copy 'base64_string' as 'string' in 'result_copy'

# move statement
When I rename 'my_dict' to 'result_move'
and I move 'to_be_signed' to 'signed' in 'result_move'
and I move 'eddsa signature' as 'base58' in 'result_move'
and I move 'ecdh signature' as 'ecdh_signature' in 'result_move'
and I move 'base64_string' as 'string' in 'result_move'

Then print the 'result_copy'
Then print the 'result_move'
EOF
save_output move_and_copy_statements.out.json
assert_output '{"result_copy":{"base64_string":"hello my friend","ecdh_signature":{"r":"d2tYw0FFyVU7UjX+IRpiN8SLkLR4S8bYZmCwI2rzurI=","s":"vUljXtnKkBqle/Ik7y3GfMa1o3wEIi4lRC+b/KmVbaI="},"eddsa_signature":"2iSCa9YxtYTQtmcUHHKsYZXVsqnSWSa7E2skWZqN4EdY8wBX9UuBgCYx7Np3hJmDVQ2NiHSebLHmz5BGH3cuZ4um","signed":"some data to be signed","str":"hello"},"result_move":{"base64_string":"hello my friend","ecdh_signature":{"r":"d2tYw0FFyVU7UjX+IRpiN8SLkLR4S8bYZmCwI2rzurI=","s":"vUljXtnKkBqle/Ik7y3GfMa1o3wEIi4lRC+b/KmVbaI="},"eddsa_signature":"2iSCa9YxtYTQtmcUHHKsYZXVsqnSWSa7E2skWZqN4EdY8wBX9UuBgCYx7Np3hJmDVQ2NiHSebLHmz5BGH3cuZ4um","signed":"some data to be signed","str":"hello"}}'
}
8 changes: 4 additions & 4 deletions test/zencode/pack.bats
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ EOF
cat << EOF | zexe newblock.zen L1_newheads_ethereum.json
Given I have a 'hex dictionary' named 'result' in 'params'
When I create the 'hex dictionary' named 'newblock'
When I move 'hash' from 'result' to 'newblock'
When I move 'number' from 'result' to 'newblock'
When I move 'parentHash' from 'result' to 'newblock'
When I move 'timestamp' from 'result' to 'newblock'
When I move 'hash' from 'result' in 'newblock'
When I move 'number' from 'result' in 'newblock'
When I move 'parentHash' from 'result' in 'newblock'
When I move 'timestamp' from 'result' in 'newblock'
Then print the 'newblock'
EOF
save_output "newblock.json"
Expand Down
Loading
Loading