add duplicate-check for user-defined subroutines, as in the C impl

This commit is contained in:
John Kerl 2020-11-24 14:09:38 -05:00
parent b0685a759a
commit 8065237641
4 changed files with 41 additions and 7 deletions

View file

@ -18,6 +18,8 @@ run_mlr --from $indir/2.dkvp put 'subr s() {return}'
mlr_expect_fail --from $indir/2.dkvp put 'call s()'
mlr_expect_fail -n put 'subr s(){} subr s(){}'
run_mlr --from $indir/2.dkvp put -v -q '
func s(x) {
return x*2;

View file

@ -120,6 +120,8 @@ a=eks,b=pan,i=2,x=0.7586799647899636,y=0.5221511083334797
mlr --from ./reg-test/input/2.dkvp put call s()
mlr -n put subr s(){} subr s(){}
mlr --from ./reg-test/input/2.dkvp put -v -q
func s(x) {
return x*2;

View file

@ -206,6 +206,11 @@ func (this *UDFManager) Install(udf *UDF) {
this.functions[udf.signature.funcOrSubrName] = udf
}
func (this *UDFManager) ExistsByName(name string) bool {
_, ok := this.functions[name]
return ok
}
// ----------------------------------------------------------------
// Example AST for UDF definition and callsite:
@ -251,6 +256,16 @@ func (this *RootNode) BuildAndInstallUDF(astNode *dsl.ASTNode) error {
lib.InternalCodingErrorIf(len(astNode.Children) != 2 && len(astNode.Children) != 3)
functionName := string(astNode.Token.Lit)
if this.udsManager.ExistsByName(functionName) {
return errors.New(
fmt.Sprintf(
"Miller: function named \"%s\" has already been defined.",
functionName,
),
)
}
parameterListASTNode := astNode.Children[0]
functionBodyASTNode := astNode.Children[1]

View file

@ -32,10 +32,10 @@ func NewUDS(
// For when a subroutine is called before being defined. This gives us something
// to go back and fill in later once we've encountered the subroutine definition.
func NewUnresolvedUDS(
functionName string,
subroutineName string,
callsiteArity int,
) *UDS {
signature := NewSignature(functionName, callsiteArity, nil, nil)
signature := NewSignature(subroutineName, callsiteArity, nil, nil)
uds := NewUDS(signature, nil)
return uds
}
@ -162,8 +162,8 @@ func NewUDSManager() *UDSManager {
}
}
func (this *UDSManager) LookUp(functionName string, callsiteArity int) (*UDS, error) {
uds := this.subroutines[functionName]
func (this *UDSManager) LookUp(subroutineName string, callsiteArity int) (*UDS, error) {
uds := this.subroutines[subroutineName]
if uds == nil {
return nil, nil
}
@ -171,7 +171,7 @@ func (this *UDSManager) LookUp(functionName string, callsiteArity int) (*UDS, er
return nil, errors.New(
fmt.Sprintf(
"Miller: subroutine %s invoked with %d argument%s; expected %d",
functionName,
subroutineName,
callsiteArity,
lib.Plural(callsiteArity),
uds.signature.arity,
@ -185,6 +185,11 @@ func (this *UDSManager) Install(uds *UDS) {
this.subroutines[uds.signature.funcOrSubrName] = uds
}
func (this *UDSManager) ExistsByName(name string) bool {
_, ok := this.subroutines[name]
return ok
}
// ----------------------------------------------------------------
// Example AST for UDS definition and callsite:
@ -229,7 +234,17 @@ func (this *RootNode) BuildAndInstallUDS(astNode *dsl.ASTNode) error {
lib.InternalCodingErrorIf(astNode.Children == nil)
lib.InternalCodingErrorIf(len(astNode.Children) != 2 && len(astNode.Children) != 3)
functionName := string(astNode.Token.Lit)
subroutineName := string(astNode.Token.Lit)
if this.udsManager.ExistsByName(subroutineName) {
return errors.New(
fmt.Sprintf(
"Miller: subroutine named \"%s\" has already been defined.",
subroutineName,
),
)
}
parameterListASTNode := astNode.Children[0]
subroutineBodyASTNode := astNode.Children[1]
@ -263,7 +278,7 @@ func (this *RootNode) BuildAndInstallUDS(astNode *dsl.ASTNode) error {
typeGatedParameterNames[i] = typeGatedParameterName
}
signature := NewSignature(functionName, arity, typeGatedParameterNames, nil)
signature := NewSignature(subroutineName, arity, typeGatedParameterNames, nil)
subroutineBody, err := this.BuildStatementBlockNode(subroutineBodyASTNode)
if err != nil {