diff --git a/go/reg-test/cases/case-subr.sh b/go/reg-test/cases/case-subr.sh index 270bd458b..be5531bca 100644 --- a/go/reg-test/cases/case-subr.sh +++ b/go/reg-test/cases/case-subr.sh @@ -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; diff --git a/go/reg-test/expected/case-subr.sh.out b/go/reg-test/expected/case-subr.sh.out index 884ba359e..77bdda75f 100644 --- a/go/reg-test/expected/case-subr.sh.out +++ b/go/reg-test/expected/case-subr.sh.out @@ -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; diff --git a/go/src/miller/dsl/cst/udf.go b/go/src/miller/dsl/cst/udf.go index 991b217b4..e238845b6 100644 --- a/go/src/miller/dsl/cst/udf.go +++ b/go/src/miller/dsl/cst/udf.go @@ -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] diff --git a/go/src/miller/dsl/cst/uds.go b/go/src/miller/dsl/cst/uds.go index 6f6f19e5b..d8003c8ea 100644 --- a/go/src/miller/dsl/cst/uds.go +++ b/go/src/miller/dsl/cst/uds.go @@ -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 {