-
Notifications
You must be signed in to change notification settings - Fork 207
/
subroutines.go
78 lines (69 loc) · 2.79 KB
/
subroutines.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// ================================================================
// 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/pkg/dsl"
"github.com/johnkerl/miller/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
}
}