diff --git a/contracts/mal_like_tay.sol b/contracts/mal_like_tay.sol index 5856673..20c6823 100644 --- a/contracts/mal_like_tay.sol +++ b/contracts/mal_like_tay.sol @@ -863,10 +863,40 @@ object "Taylor" { let fptr := mload(add(ptrs, 32)) let list_ptr := mload(add(ptrs, 64)) let accum_ptr := mload(add(ptrs, 96)) - result_ptr := _reduceInner(add(fptr, 4), list_ptr, accum_ptr) + + let sigsig := mslice(fptr, 4) + switch sigsig + case 0x04000004 { + result_ptr := _reduceInnerNative(mslice(add(fptr, 4), 4), list_ptr, accum_ptr) + } + default { + result_ptr := _reduceInnerLambda(add(fptr, 4), list_ptr, accum_ptr) + } + } + + function _reduceInnerNative(sig, list_ptr, accum_ptr) -> result_ptr { + let list_arity := listTypeSize(mslice(list_ptr, 4)) + let arg_ptr := add(list_ptr, 4) + let accum_length := getTypedLength(accum_ptr) + + // iterate over list & apply function on each arg + for { let i := 0 } lt(i, list_arity) { i := add(i, 1) } { + let arg_length := getTypedLength(arg_ptr) + let dataptr := allocate(add(add(4, arg_length), accum_length)) + mslicestore(dataptr, sig, 4) + mmultistore(add(dataptr, 4), accum_ptr, accum_length) + mmultistore(add(add(dataptr, 4), accum_length), arg_ptr, arg_length) + + let end, res := eval(dataptr, 0) + + mmultistore(accum_ptr, res, getTypedLength(res)) + arg_ptr := add(arg_ptr, arg_length) + } + + result_ptr := accum_ptr } - function _reduceInner(lambda_body_ptr, list_ptr, accum_ptr) -> result_ptr { + function _reduceInnerLambda(lambda_body_ptr, list_ptr, accum_ptr) -> result_ptr { let list_arity := listTypeSize(mslice(list_ptr, 4)) let arg_ptr := add(list_ptr, 4) let accum_length := getTypedLength(accum_ptr) diff --git a/src/mal_backend.js b/src/mal_backend.js index 9508110..cbdecc9 100644 --- a/src/mal_backend.js +++ b/src/mal_backend.js @@ -38,6 +38,12 @@ modifyEnv('js-eval', (orig_func, str) => { return interop.js_to_mal(answ); }) +/* Taylor */ + +mal.reps(` +(def! reduce (fn* (f xs init) (if (empty? xs) init (reduce f (rest xs) (f init (first xs)) )))) +`) + /* EVM */ mal.reps(` diff --git a/tests/maltay.test.js b/tests/maltay.test.js index 5647566..9b3103a 100644 --- a/tests/maltay.test.js +++ b/tests/maltay.test.js @@ -130,21 +130,6 @@ it('test bytes contig', async function () { expect(resp).toBe('0x221111ccdd221111ccdd'); }); -it('test reduce', async function () { - let resp; - - await MalTay.sendAndWait('(def! myfunc2 (fn* (a b) (add a b)) )'); - - resp = await MalTay.call('(myfunc2 4 5)'); - expect(resp).toBe(9); - - resp = await MalTay.call('(myfunc2 0 5)'); - expect(resp).toBe(5); - - resp = await MalTay.call('(reduce myfunc2 (list 5 8 2) 0)'); - expect(resp).toBe(15); -}); - it('test recursive', async function () { let resp; @@ -170,7 +155,7 @@ it('test recursive fibonacci', async function () { expect(resp).toBe(21); }); -it('test reduce recursive', async function () { +it.skip('test reduce recursive', async function () { let expr, resp; await MalTay.sendAndWait('(def! myfunc3 (fn* (a b) (add a b)) )'); @@ -437,6 +422,30 @@ describe.each([ } }); + it('test reduce', async function () { + let resp; + + resp = await instance.call('(reduce add (list) 2)'); + expect(resp).toBe(2); + + resp = await instance.call('(reduce add (list 5 8 2) 0)'); + expect(resp).toBe(15); + + resp = await instance.call('(reduce sub (list 45 8 2) 100)'); + expect(resp).toBe(45); + + await instance.sendAndWait('(def! myfunc2 (fn* (a b) (add a b)) )'); + + resp = await instance.call('(myfunc2 4 5)'); + expect(resp).toBe(9); + + resp = await instance.call('(myfunc2 0 5)'); + expect(resp).toBe(5); + + resp = await instance.call('(reduce myfunc2 (list 5 8 2) 0)'); + expect(resp).toBe(15); + }); + test(`add`, async () => { resp = await instance.call('(add 9 3)'); expect(resp).toBe(12); @@ -741,7 +750,7 @@ describe.each([ it('test logs', async function() { if (backendname === 'chain') { const resp = await instance.getFns(); - expect(resp.length).toBe(3); + expect(resp.length).toBe(4); } }); });