From 3dfd69dcb46f7c1a2e8be31a241fafaddc0b4670 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Fri, 10 Nov 2023 06:28:05 +0100 Subject: [PATCH] optimize scope=given execution by omitting other zencode optimize scope=given by disabling When/Then/etc. function handles no need to process Then when scope=given on introspection only the Given block is executed and the CODEC is printed, please note the structure is named uppercase: "CODEC" includes a small optimization to zencoed parser for comments add scope test to meson tests --- bindings/javascript/src/index.ts | 2 +- build/meson.build | 2 +- src/lua/zencode.lua | 123 +++++++++++++++++++------------ test/zencode/scope.bats | 10 +-- 4 files changed, 83 insertions(+), 54 deletions(-) diff --git a/bindings/javascript/src/index.ts b/bindings/javascript/src/index.ts index 7645b5d3a..a05aa8a84 100644 --- a/bindings/javascript/src/index.ts +++ b/bindings/javascript/src/index.ts @@ -205,7 +205,7 @@ export const zencode_valid_input = async ( export const introspect = async (zencode, props?: ZenroomProps) => { try { const { result } = await zencode_valid_input(zencode, props); - return JSON.parse(result).codec; + return JSON.parse(result).CODEC; } catch ({ logs }) { console.error(logs); const heap = JSON.parse(logs) diff --git a/build/meson.build b/build/meson.build index da846080d..9d6a2ad01 100644 --- a/build/meson.build +++ b/build/meson.build @@ -201,7 +201,7 @@ tests = [ 'generic_dilithium', 'generic_ecdh', 'generic_eddsa', 'generic_schnorr', 'given', 'hash', 'http', 'keys', 'kyber', 'ntrup', 'numbers', 'output', 'pack', 'parser', 'planetmint', 'pvss', 'random', 'reflow', 'rules', 'secshare', 'then', 'w3c', 'w3c_did', 'when', -'zencode_exec', 'zenswarm', 'zkp', 'zkp_multi_petitions', 'logfmt' +'zencode_exec', 'zenswarm', 'zkp', 'zkp_multi_petitions', 'logfmt', 'scope' ] foreach test_suite : tests test('zencode_'+test_suite.underscorify(), diff --git a/src/lua/zencode.lua b/src/lua/zencode.lua index 980aa0b99..4b7bbb7dc 100644 --- a/src/lua/zencode.lua +++ b/src/lua/zencode.lua @@ -353,8 +353,6 @@ function ZEN:begin(new_heap) {name = 'enter_given', from = {'init', 'rule', 'scenario'}, to = 'given'}, {name = 'enter_given', from = {'given'}, to = 'given'}, {name = 'enter_and', from = 'given', to = 'given'}, - {name = 'enter_then', from = {'given', 'when', 'then', 'endif', 'endforeach'}, to = 'then'}, - {name = 'enter_and', from = 'then', to = 'then'}, } if CONF.exec.scope == 'full' then -- rule output given-only @@ -395,7 +393,9 @@ function ZEN:begin(new_heap) {name = 'enter_and', from = 'ifforeach', to = 'ifforeach'}, {name = 'enter_and', from = 'foreachif', to = 'foreachif'}, {name = 'enter_and', from = 'whenforeach', to = 'whenforeach'}, - {name = 'enter_and', from = 'whenifforeach', to = 'whenifforeach'} + {name = 'enter_and', from = 'whenifforeach', to = 'whenifforeach'}, + {name = 'enter_then', from = {'given', 'when', 'then', 'endif', 'endforeach'}, to = 'then'}, + {name = 'enter_and', from = 'then', to = 'then'}, } for _,v in pairs(extra_events) do table.insert(events, v) end end @@ -422,7 +422,7 @@ local function zencode_isempty(b) end end local function zencode_iscomment(b) - local x = string.char(b:byte(1)) + local x = string.sub(b,1,1) -- string.char(b:byte(1)) if x == '#' then return true else @@ -641,26 +641,27 @@ function ZEN:run() end -- PRINT output self:ftrace('--- Zencode execution completed') - if type(OUT) == 'table' then - self:ftrace('<<< Encoding { OUT } to JSON ') - -- this is all already encoded - -- needs to be formatted - -- was used CONF.output.format.fun - -- suspended until more formats are implemented - print( JSON.encode(OUT) ) - self:ftrace('>>> Encoding successful') - else -- this should never occur in zencode, OUT is always a table - self:ftrace('<<< Printing OUT (plain format, not a table)') - print(OUT) + if CONF.exec.scope == 'full' then + if type(OUT) == 'table' then + self:ftrace('<<< Encoding { OUT } to JSON ') + -- this is all already encoded + -- needs to be formatted + -- was used CONF.output.format.fun + -- suspended until more formats are implemented + print( JSON.encode(OUT) ) + self:ftrace('>>> Encoding successful') + else -- this should never occur in zencode, OUT is always a table + self:ftrace('<<< Printing OUT (plain format, not a table)') + print(OUT) + end + elseif CONF.exec.scope == 'given' then + print(JSON.encode({CODEC = CODEC})) + ZEN:debug() -- J64 HEAP and TRACE end end - - - - ---------------------------------------------------------------- --- ZENCODE PARSER +------------------- +-- ZENCODE WATCHDOG -- assert all values in table are converted to zenroom types -- used in zencode when transitioning out of given memory function zenguard(val, key) -- AKA watchdog @@ -671,8 +672,6 @@ function zenguard(val, key) -- AKA watchdog return nil end end - - -- compare heap.ACK and heap.CODEC function ZEN:codecguard() local left = ACK @@ -697,40 +696,70 @@ function ZEN:codecguard() return true end --- the global ZEN context +------------------------------------------ +-- ZENCODE STATEMENT DECLARATION FUNCTIONS function Given(text, fn) - text = text:lower() - assert(not ZEN.given_steps[text], 'Conflicting GIVEN statement loaded by scenario: ' .. text, 2) - ZEN.given_steps[text] = fn + text = text:lower() + if ZEN.given_steps[text] then + error('Conflicting GIVEN statement loaded by scenario: ' .. text, 2) + end + ZEN.given_steps[text] = fn end function When(text, fn) - text = text:lower() - if ZEN.when_steps[text] then - error('Conflicting WHEN statement loaded by scenario: ' .. text, 2) - end - ZEN.when_steps[text] = fn + if ZENCODE_SCOPE == 'GIVEN' then + text = nil + fn = nil + else + text = text:lower() + if ZEN.when_steps[text] then + error('Conflicting WHEN statement loaded by scenario: ' .. text, 2) + end + ZEN.when_steps[text] = fn + end end function IfWhen(text, fn) - text = text:lower() - if ZEN.if_steps[text] then - error('Conflicting IF-WHEN statement loaded by scenario: ' .. text, 2) - end - if ZEN.when_steps[text] then - error('Conflicting IF-WHEN statement loaded by scenario: ' .. text, 2) - end - ZEN.if_steps[text] = fn - ZEN.when_steps[text] = fn + if ZENCODE_SCOPE == 'GIVEN' then + text = nil + fn = nil + else + text = text:lower() + if ZEN.if_steps[text] then + error('Conflicting IF-WHEN statement loaded by scenario: '..text, 2) + end + if ZEN.when_steps[text] then + error('Conflicting IF-WHEN statement loaded by scenario: '..text, 2) + end + ZEN.if_steps[text] = fn + ZEN.when_steps[text] = fn + end end function Foreach(text, fn) - text = text:lower() - assert(not ZEN.foreach_steps[text],'Conflicting FOREACH statement loaded by scenario: ' .. text, 2) - ZEN.foreach_steps[text] = fn + if ZENCODE_SCOPE == 'GIVEN' then + text = nil + fn = nil + else + text = text:lower() + if ZEN.foreach_steps[text] then + error('Conflicting FOREACH statement loaded by scenario: ' .. text, 2) + end + ZEN.foreach_steps[text] = fn + end end function Then(text, fn) - text = text:lower() - assert(not ZEN.then_steps[text],'Conflicting THEN statement loaded by scenario : ' .. text, 2) - ZEN.then_steps[text] = fn + if ZENCODE_SCOPE == 'GIVEN' then + text = nil + fn = nil + else + text = text:lower() + if ZEN.then_steps[text] then + error('Conflicting THEN statement loaded by scenario : ' .. text, 2) + end + ZEN.then_steps[text] = fn + end end + +--------------------------- +-- ZENCODE GLOBAL UTILITIES function Iam(name) if name then zencode_assert(not WHO, 'Identity already defined in WHO') diff --git a/test/zencode/scope.bats b/test/zencode/scope.bats index 317f2ce27..7fb937f60 100644 --- a/test/zencode/scope.bats +++ b/test/zencode/scope.bats @@ -43,7 +43,7 @@ When I create the random 'random' Then print codec EOF save_output given_only_schema_output.json - assert_output '{"codec":{"keyring":{"encoding":"complex","name":"keyring","root":"Alice","schema":"keyring","zentype":"e"},"myFirstObject":{"encoding":"string","name":"myFirstObject","zentype":"d"},"mySecondObject":{"encoding":"string","name":"mySecondObject","zentype":"d"}}}' + assert_output '{"CODEC":{"keyring":{"encoding":"complex","name":"keyring","root":"Alice","schema":"keyring","zentype":"e"},"myFirstObject":{"encoding":"string","name":"myFirstObject","zentype":"d"},"mySecondObject":{"encoding":"string","name":"mySecondObject","zentype":"d"}}}' } @test "Zencode scope=given with missing element" { @@ -71,7 +71,7 @@ When I create the random 'random' Then print codec EOF save_output given_schema_missing.json - assert_output '{"codec":{"does_not_exists":{"encoding":"string","missing":true,"name":"does_not_exists","zentype":"e"},"myFirstObject":{"encoding":"string","name":"myFirstObject","zentype":"d"}}}' + assert_output '{"CODEC":{"does_not_exists":{"encoding":"string","missing":true,"name":"does_not_exists","zentype":"e"},"myFirstObject":{"encoding":"string","name":"myFirstObject","zentype":"d"}}}' } @test "Zencode scope=given with missing dictionary or array" { @@ -100,7 +100,7 @@ and I have a 'base64 dictionary' named 'missingArray' Then print codec EOF save_output given_schema_missing.json - assert_output '{"codec":{"missingArray":{"encoding":"base64","missing":true,"name":"missingArray","zentype":"d"},"missingDictionary":{"encoding":"string","missing":true,"name":"missingDictionary","zentype":"d"},"myArray":{"encoding":"string","name":"myArray","zentype":"a"},"myDictionary":{"encoding":"string","name":"myDictionary","zentype":"d"}}}' + assert_output '{"CODEC":{"missingArray":{"encoding":"base64","missing":true,"name":"missingArray","zentype":"d"},"missingDictionary":{"encoding":"string","missing":true,"name":"missingDictionary","zentype":"d"},"myArray":{"encoding":"string","name":"myArray","zentype":"a"},"myDictionary":{"encoding":"string","name":"myDictionary","zentype":"d"}}}' } @test "Zencode scope=given with missing schema type" { @@ -125,7 +125,7 @@ and I have a 'keyring' Then print codec EOF save_output given_schema_missing.json - assert_output '{"codec":{"ethereum_address":{"bintype":"zenroom.octet","encoding":"complex","name":"ethereum_address","schema":"ethereum_address","zentype":"e"},"keyring":{"encoding":"complex","name":"keyring","schema":"keyring","zentype":"e"},"missing_address":{"encoding":"complex","missing":true,"name":"missing_address","schema":"ethereum_address","zentype":"e"}}}' + assert_output '{"CODEC":{"ethereum_address":{"bintype":"zenroom.octet","encoding":"complex","name":"ethereum_address","schema":"ethereum_address","zentype":"e"},"keyring":{"encoding":"complex","name":"keyring","schema":"keyring","zentype":"e"},"missing_address":{"encoding":"complex","missing":true,"name":"missing_address","schema":"ethereum_address","zentype":"e"}}}' # TODO: missing keyring @@ -162,6 +162,6 @@ When I create the random 'random' Then print codec EOF save_output given_schema_missing.json - assert_output '{"codec":{"does_not_exists":{"encoding":"string","missing":true,"name":"does_not_exists","root":"myFirstObject","zentype":"d"},"missing_public_key":{"encoding":"hex","missing":true,"name":"missing_public_key","root":"Alice","zentype":"e"},"myStringArray":{"encoding":"string","name":"myStringArray","root":"myFirstObject","zentype":"a"}}}' + assert_output '{"CODEC":{"does_not_exists":{"encoding":"string","missing":true,"name":"does_not_exists","root":"myFirstObject","zentype":"d"},"missing_public_key":{"encoding":"hex","missing":true,"name":"missing_public_key","root":"Alice","zentype":"e"},"myStringArray":{"encoding":"string","name":"myStringArray","root":"myFirstObject","zentype":"a"}}}' }