import { isArray } from "@thi.ng/checks/is-array" ; import { isFunction } from "@thi.ng/checks/is-function" ; import { compL } from "@thi.ng/compose/comp" ; import type { StackContext , StackEnv , StackFn , StackProc , StackProgram , } from "./api.js" ; import { $ } from "./safe.js" ; import { tos } from "./stack.js" ; export const $stackFn = ( f ) => ( isArray ( f ) ? defWord ( f ) : f ) ; const compile = ( prog ) => prog . length > 0 ? compL . apply ( null , < any > ( prog . map ( ( w ) => ! isFunction ( w ) ? ( ctx ) => ( ctx [ 0 ] . push ( w ) , ctx ) : w ) ) ) : ( ctx ) => ctx ; /**
 * Takes a result tuple returned by  run and unwraps one or more
 * items from result stack. If no `n` is given, defaults to single value
 * (TOS) and returns it as is. Returns an array for all other `n`.
 *
 *  param result param n export const unwrap = ( [ stack ] , n = 1 ) => n === 1 ? tos ( stack ) : stack . slice ( Math . max ( 0 , stack . length - n ) ) ; /**
 * Higher order word. Takes a StackProgram and returns it as StackFn to
 * be used like any word. Unknown stack effect.
 *
 * If the optional `env` is given, uses a shallow copy of that
 * environment (one per invocation) instead of the current one passed by
 *  run at runtime. If `mergeEnv` is true (default), the user
 * provided env will be merged with the current env (also shallow
 * copies). This is useful in conjunction with  pushenv and  store * or `storekey()` to save results of sub procedures in the main env.
 *
 * Note: The provided (or merged) env is only active within the
 * execution scope of the word.
 *
 * ( ? -- ? )
 *
 *  param prog param env param mergeEnv export const defWord = ( prog , env ? , mergeEnv = true ) => { const w = compile ( prog ) ; return env ? mergeEnv ? ( ctx ) => ( w ( [ ctx [ 0 ] , ctx [ 1 ] , { ... ctx [ 2 ] , ... env } ] ) , ctx ) : ( ctx ) => ( w ( [ ctx [ 0 ] , ctx [ 1 ] , { ... env } ] ) , ctx ) : w ; } ; /**
 * Like  word , but automatically calls  unwrap on result context
 * to produced unwrapped value/tuple.
 *
 * **Importatant:** Words defined with this function CANNOT be used as
 * part of a larger stack program, only for standalone use.
 *
 *  param prog param n param env param mergeEnv export const defWordU = ( prog , n = 1 , env ? , mergeEnv = true ) => { const w = compile ( prog ) ; return env ? mergeEnv ? ( ctx ) => unwrap ( w ( [ ctx [ 0 ] , ctx [ 1 ] , { ... ctx [ 2 ] , ... env } ] ) , n ) : ( ctx ) => unwrap ( w ( [ ctx [ 0 ] , ctx [ 1 ] , { ... env } ] ) , n ) : ( ctx ) => unwrap ( w ( ctx ) , n ) ; } ; param ctx export const exec = ( ctx ) => ( $ ( ctx [ 0 ] , 1 ) , $stackFn ( ctx [ 0 ] . pop ( ) ) ( ctx ) ) ; param ctx export const $try = ( ctx ) => { const stack = ctx [ 0 ] ; $ ( stack , 2 ) ; const err = stack . pop ( ) ; try { return exec ( ctx ) ; } catch ( e ) { stack . push ( e , err ) ; return exec ( ctx ) ; } } ; param ctx export const execjs = ( ctx ) => { const stack = ctx [ 0 ] ; $ ( stack , 1 ) ; const [ fn , ... args ] = stack . pop ( ) ; stack . push ( fn ( ... args ) ) ; return ctx ; } ;