@@ -149,6 +149,8 @@ interface FlattenerContext {
149149 streamConnections ?: { side1 : string ; side2 : string } [ ] ;
150150 /** Deferred flow variable connection pairs for connection-set-based flow balance generation. */
151151 flowConnectPairs ?: { name1 : string ; name2 : string } [ ] ;
152+ /** Monomorphization bindings for higher order functions */
153+ functionBindings ?: Map < string , ModelicaPartialFunctionExpression | string > ;
152154}
153155
154156/** Extract an integer shape array from a list of expressions (all must be ModelicaIntegerLiteral). */
@@ -2926,6 +2928,22 @@ class ModelicaSyntaxFlattener extends ModelicaSyntaxVisitor<ModelicaExpression,
29262928 let functionName =
29272929 node . functionReference ?. parts ?. map ( ( p ) => p . identifier ?. text ?? "" ) . join ( "." ) ||
29282930 ( node . functionReferenceName ?? "" ) ;
2931+
2932+ // Monomorphization: Resolve bound function parameters dynamically
2933+ let boundArgsMap : Map < string , ModelicaExpression > | null = null ;
2934+ if ( ctx . functionBindings ?. has ( functionName ) ) {
2935+ const boundItem = ctx . functionBindings . get ( functionName ) ;
2936+ if ( typeof boundItem === "string" ) {
2937+ functionName = boundItem ;
2938+ } else if ( boundItem instanceof ModelicaPartialFunctionExpression ) {
2939+ functionName = boundItem . functionName ;
2940+ boundArgsMap = new Map ( ) ;
2941+ for ( const namedArg of boundItem . namedArgs ) {
2942+ boundArgsMap . set ( namedArg . name , namedArg . value ) ;
2943+ }
2944+ }
2945+ }
2946+
29292947 let flatArgs : ModelicaExpression [ ] = [ ] ;
29302948 for ( const arg of node . functionCallArguments ?. arguments ?? [ ] ) {
29312949 let flatArg : ModelicaExpression | null ;
@@ -2937,6 +2955,39 @@ class ModelicaSyntaxFlattener extends ModelicaSyntaxVisitor<ModelicaExpression,
29372955 if ( flatArg ) flatArgs . push ( flatArg ) ;
29382956 }
29392957
2958+ // Merge bound arguments into the flattened arguments array
2959+ if ( boundArgsMap && boundArgsMap . size > 0 ) {
2960+ // Resolve the target function to correctly align named bound arguments with positions
2961+ const resolved = ctx . classInstance . resolveName ( functionName . split ( "." ) ) ;
2962+ if (
2963+ resolved instanceof ModelicaClassInstance &&
2964+ ( resolved . classKind === ModelicaClassKind . FUNCTION ||
2965+ resolved . classKind === ModelicaClassKind . OPERATOR_FUNCTION )
2966+ ) {
2967+ if ( ! resolved . instantiated ) resolved . instantiate ( ) ;
2968+ const inputs = Array . from ( resolved . components ) . filter ( ( c ) => c . causality ?. toString ( ) === "input" ) ;
2969+
2970+ const mergedArgs : ModelicaExpression [ ] = [ ] ;
2971+ let positionalIndex = 0 ;
2972+ for ( const input of inputs ) {
2973+ const inputName = input . name ?? "" ;
2974+ const boundValue = boundArgsMap . get ( inputName ) ;
2975+ if ( boundValue ) {
2976+ mergedArgs . push ( boundValue ) ;
2977+ } else if ( positionalIndex < flatArgs . length ) {
2978+ mergedArgs . push ( flatArgs [ positionalIndex ] as ModelicaExpression ) ;
2979+ positionalIndex ++ ;
2980+ }
2981+ }
2982+ // Append any remaining arguments
2983+ while ( positionalIndex < flatArgs . length ) {
2984+ mergedArgs . push ( flatArgs [ positionalIndex ] as ModelicaExpression ) ;
2985+ positionalIndex ++ ;
2986+ }
2987+ flatArgs = mergedArgs ;
2988+ }
2989+ }
2990+
29402991 // Handle record constructor calls: Complex(re=2.0, im=3.0) or Rec(r = 1.0)
29412992 // Record constructors use the record type name as the function name and may have named arguments.
29422993 {
@@ -3862,8 +3913,73 @@ class ModelicaSyntaxFlattener extends ModelicaSyntaxVisitor<ModelicaExpression,
38623913 }
38633914 }
38643915 }
3916+ // Specialized Higher-Order Function Execution (Monomorphization)
3917+ let finalFunctionName = isExternalBuiltinAlias ? functionName : originalName ;
3918+ let finalArgs = flatArgs ;
38653919
3866- const result = new ModelicaFunctionCallExpression ( isExternalBuiltinAlias ? functionName : originalName , flatArgs ) ;
3920+ if ( ! builtinDef ) {
3921+ const fDef =
3922+ ctx . dae . functions . find ( ( f ) => f . name === functionName ) ||
3923+ ctx . rootDae ?. functions . find ( ( f ) => f . name === functionName ) ;
3924+ if ( fDef ) {
3925+ const inputVars = fDef . variables . filter ( ( v ) => v . causality === "input" ) ;
3926+ let hasHigherOrderArg = false ;
3927+ const newBindings = new Map < string , ModelicaPartialFunctionExpression | string > ( ) ;
3928+ const filteredArgs : ModelicaExpression [ ] = [ ] ;
3929+
3930+ for ( let i = 0 ; i < flatArgs . length && i < inputVars . length ; i ++ ) {
3931+ const inVar = inputVars [ i ] ;
3932+ const argVal = flatArgs [ i ] ;
3933+ if ( inVar ?. functionType ) {
3934+ hasHigherOrderArg = true ;
3935+ if ( argVal instanceof ModelicaPartialFunctionExpression ) {
3936+ newBindings . set ( inVar . name , argVal ) ;
3937+ } else if ( argVal instanceof ModelicaNameExpression ) {
3938+ newBindings . set ( inVar . name , argVal . name ) ;
3939+ }
3940+ } else if ( argVal ) {
3941+ filteredArgs . push ( argVal ) ;
3942+ }
3943+ }
3944+
3945+ // Push any remaining defaults that were expanded
3946+ for ( let i = inputVars . length ; i < flatArgs . length ; i ++ ) {
3947+ const argVal = flatArgs [ i ] ;
3948+ if ( argVal ) filteredArgs . push ( argVal ) ;
3949+ }
3950+
3951+ if ( hasHigherOrderArg ) {
3952+ // Generate deterministic specialized name based on bound function names
3953+ const hashPairs = Array . from ( newBindings . entries ( ) ) . map ( ( [ k , v ] ) => {
3954+ const vName = v instanceof ModelicaPartialFunctionExpression ? v . functionName : v ;
3955+ return `${ k } _${ vName . replace ( / \\ ./ g, "_" ) } ` ;
3956+ } ) ;
3957+ const specializedName = `${ functionName } $${ hashPairs . join ( "$" ) } ` ;
3958+
3959+ // Resolve the base function class instance to use as an override
3960+ let baseResolved : ModelicaClassInstance | undefined = resolvedOverride ;
3961+ if ( ! baseResolved && ctx . classInstance ) {
3962+ const parts = originalName . split ( "." ) ;
3963+ const r = ctx . classInstance . resolveName ( parts ) ;
3964+ if ( r instanceof ModelicaClassInstance ) baseResolved = r ;
3965+ }
3966+
3967+ if ( baseResolved ) {
3968+ const baseBindings = ctx . functionBindings ? Array . from ( ctx . functionBindings . entries ( ) ) : [ ] ;
3969+ const specializedCtx : FlattenerContext = {
3970+ ...ctx ,
3971+ functionBindings : new Map ( [ ...baseBindings , ...Array . from ( newBindings . entries ( ) ) ] ) ,
3972+ } ;
3973+ this . #collectFunctionDefinition( specializedName , specializedCtx , baseResolved , componentPrefix ) ;
3974+
3975+ finalFunctionName = specializedName ;
3976+ finalArgs = filteredArgs ;
3977+ }
3978+ }
3979+ }
3980+ }
3981+
3982+ const result = new ModelicaFunctionCallExpression ( finalFunctionName , finalArgs ) ;
38673983
38683984 // Only inline user-defined function calls when ALL arguments are compile-time constants.
38693985 // Parameters are NOT constants — they can change between simulations.
@@ -4468,6 +4584,11 @@ class ModelicaSyntaxFlattener extends ModelicaSyntaxVisitor<ModelicaExpression,
44684584 variable . customTypeName = typeInstance . name ?? null ;
44694585 }
44704586 }
4587+
4588+ if ( ctx . functionBindings ?. has ( compName ) ) {
4589+ // Skip emitting this variable as an argument! It is statically bound.
4590+ continue ;
4591+ }
44714592 fnDae . variables . push ( variable ) ;
44724593 }
44734594
@@ -4526,6 +4647,7 @@ class ModelicaSyntaxFlattener extends ModelicaSyntaxVisitor<ModelicaExpression,
45264647 stmtCollector : [ ] ,
45274648 rootDae : targetDae ,
45284649 ...( componentPrefix ? { componentFunctionPrefix : componentPrefix } : { } ) ,
4650+ ...( ctx . functionBindings ? { functionBindings : ctx . functionBindings } : { } ) ,
45294651 } ) ;
45304652 }
45314653 }
@@ -4539,6 +4661,7 @@ class ModelicaSyntaxFlattener extends ModelicaSyntaxVisitor<ModelicaExpression,
45394661 stmtCollector : collector ,
45404662 rootDae : targetDae ,
45414663 ...( componentPrefix ? { componentFunctionPrefix : componentPrefix } : { } ) ,
4664+ ...( ctx . functionBindings ? { functionBindings : ctx . functionBindings } : { } ) ,
45424665 } ) ;
45434666 }
45444667 if ( collector . length > 0 ) {
0 commit comments