mirror of
https://github.com/johnkerl/miller.git
synced 2026-01-23 02:14:13 +00:00
* Update package version * Update makefile targets * Update readme packages * Remaining old packages via rg/sd
78 lines
2.8 KiB
Go
78 lines
2.8 KiB
Go
// ================================================================
|
|
// CST build/execute for subroutine nodes.
|
|
//
|
|
// Subroutines can't be used as rvalues; their invocation must be the entire
|
|
// statement. Nonetheless, their name-resolution, argument/parameter binding,
|
|
// etc. are very similar to functions.
|
|
// ================================================================
|
|
|
|
package cst
|
|
|
|
import (
|
|
"github.com/johnkerl/miller/v6/pkg/dsl"
|
|
"github.com/johnkerl/miller/v6/pkg/lib"
|
|
)
|
|
|
|
// ----------------------------------------------------------------
|
|
// Subroutine lookup:
|
|
//
|
|
// * Unlike for functions, There are no built-in subroutines -- the only ones
|
|
// that exist are user-defined.
|
|
// * Try UDS lookup (i.e. the UDS has been defined before being called)
|
|
// * Absent a match there:
|
|
// o Make a UDS-placeholder node with present signature but nil function-pointer
|
|
// o Append that node to CST to-be-resolved list
|
|
// o On a next pass, we will walk that list resolving against all encountered
|
|
// UDS definitions. (It will be an error then if it's still unresolvable.)
|
|
|
|
func (root *RootNode) BuildSubroutineCallsiteNode(astNode *dsl.ASTNode) (IExecutable, error) {
|
|
lib.InternalCodingErrorIf(
|
|
astNode.Type != dsl.NodeTypeSubroutineCallsite &&
|
|
astNode.Type != dsl.NodeTypeOperator,
|
|
)
|
|
lib.InternalCodingErrorIf(astNode.Token == nil)
|
|
lib.InternalCodingErrorIf(astNode.Children == nil)
|
|
|
|
subroutineName := string(astNode.Token.Lit)
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Look for a user-defined subroutine with the given name.
|
|
|
|
callsiteArity := len(astNode.Children)
|
|
uds, err := root.udsManager.LookUp(subroutineName, callsiteArity)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// AST snippet for 'call s($x, $y)':
|
|
//
|
|
// * statement block
|
|
// * subroutine callsite "call"
|
|
// * direct field value "x"
|
|
// * direct field value "y"
|
|
//
|
|
// Here we need to make an array of our arguments at the callsite, to be
|
|
// paired up with the parameters within he subroutine definition at runtime.
|
|
argumentNodes := make([]IEvaluable, callsiteArity)
|
|
for i, argumentASTNode := range astNode.Children {
|
|
argumentNode, err := root.BuildEvaluableNode(argumentASTNode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
argumentNodes[i] = argumentNode
|
|
}
|
|
|
|
if uds == nil {
|
|
// Mark this as unresolved for an after-pass to see if a UDS with this
|
|
// name/arity has been defined farther down in the DSL expression after
|
|
// this callsite. This happens example when a subroutine is called before
|
|
// it's defined.
|
|
uds = NewUnresolvedUDS(subroutineName, callsiteArity)
|
|
udsCallsiteNode := NewUDSCallsite(argumentNodes, uds)
|
|
root.rememberUnresolvedSubroutineCallsite(udsCallsiteNode)
|
|
return udsCallsiteNode, nil
|
|
} else {
|
|
udsCallsiteNode := NewUDSCallsite(argumentNodes, uds)
|
|
return udsCallsiteNode, nil
|
|
}
|
|
}
|