11// This is the synchronous version of the optimizer; which the Async one should be based on.
22import { isDeterministic } from './compiler.js'
33import { map } from './async_iterators.js'
4+ import { isSync , Sync } from './constants.js'
5+ import declareSync from './utilities/declareSync.js'
46
57/**
68 * Turns an expression like { '+': [1, 2] } into a function that can be called with data.
@@ -14,6 +16,7 @@ function getMethod (logic, engine, methodName, above) {
1416 const method = engine . methods [ methodName ]
1517 const called = method . asyncMethod ? method . asyncMethod : method . method ? method . method : method
1618
19+ // Todo: Like "deterministic", we should add "sync" to the method object to determine if the structure can be run synchronously.
1720 if ( method . traverse === false ) {
1821 const args = logic [ methodName ]
1922 return ( data , abv ) => called ( args , data , abv || above , engine )
@@ -23,12 +26,27 @@ function getMethod (logic, engine, methodName, above) {
2326
2427 if ( Array . isArray ( args ) ) {
2528 const optimizedArgs = args . map ( l => optimize ( l , engine , above ) )
29+
30+ if ( isSync ( optimizedArgs ) && ( method . method || method [ Sync ] ) ) {
31+ const called = method . method ? method . method : method
32+ return declareSync ( ( data , abv ) => {
33+ const evaluatedArgs = optimizedArgs . map ( l => typeof l === 'function' ? l ( data , abv ) : l )
34+ return called ( evaluatedArgs , data , abv || above , engine )
35+ } , true )
36+ }
37+
2638 return async ( data , abv ) => {
2739 const evaluatedArgs = await map ( optimizedArgs , l => typeof l === 'function' ? l ( data , abv ) : l )
2840 return called ( evaluatedArgs , data , abv || above , engine )
2941 }
3042 } else {
3143 const optimizedArgs = optimize ( args , engine , above )
44+
45+ if ( isSync ( optimizedArgs ) && ( method . method || method [ Sync ] ) ) {
46+ const called = method . method ? method . method : method
47+ return declareSync ( ( data , abv ) => called ( typeof optimizedArgs === 'function' ? optimizedArgs ( data , abv ) : optimizedArgs , data , abv || above , engine ) , true )
48+ }
49+
3250 return async ( data , abv ) => {
3351 return called ( typeof optimizedArgs === 'function' ? await optimizedArgs ( data , abv ) : optimizedArgs , data , abv || above , engine )
3452 }
@@ -45,6 +63,7 @@ function getMethod (logic, engine, methodName, above) {
4563export function optimize ( logic , engine , above = [ ] ) {
4664 if ( Array . isArray ( logic ) ) {
4765 const arr = logic . map ( l => optimize ( l , engine , above ) )
66+ if ( isSync ( arr ) ) return declareSync ( ( data , abv ) => arr . map ( l => typeof l === 'function' ? l ( data , abv ) : l ) , true )
4867 return async ( data , abv ) => map ( arr , l => typeof l === 'function' ? l ( data , abv ) : l )
4968 } ;
5069
@@ -63,6 +82,14 @@ export function optimize (logic, engine, above = []) {
6382 const result = getMethod ( logic , engine , methodName , above )
6483 if ( deterministic ) {
6584 let computed
85+
86+ if ( isSync ( result ) ) {
87+ return declareSync ( ( ) => {
88+ if ( ! computed ) computed = result ( )
89+ return computed
90+ } , true )
91+ }
92+
6693 // For async, it's a little less straightforward since it could be a promise,
6794 // so we'll make it a closure.
6895 return async ( ) => {
0 commit comments