001package gudusoft.gsqlparser.ir.bound;
002
003import gudusoft.gsqlparser.ir.common.SourceAnchor;
004
005import java.util.Collections;
006import java.util.List;
007
008/**
009 * A procedure/function symbol declaration.
010 */
011public class BoundRoutineSymbol extends BoundSymbol {
012
013    /** Owning package name (optional, null for standalone routines). */
014    private final String packageName;
015
016    /** Procedure/function name. */
017    private final String routineName;
018
019    /** Parameter signatures. */
020    private final List<BoundParameterSymbol> parameters;
021
022    /** Return type (for functions). */
023    private final BoundTypeRef returnType;
024
025    /** Routine type. */
026    private final ERoutineKind routineKind;
027
028    public BoundRoutineSymbol(String routineName, String packageName,
029                              BoundScope declaringScope, SourceAnchor declarationAnchor,
030                              List<BoundParameterSymbol> parameters,
031                              BoundTypeRef returnType, ERoutineKind routineKind) {
032        super(routineName, declaringScope, declarationAnchor);
033        this.routineName = routineName;
034        this.packageName = packageName;
035        this.parameters = parameters != null
036                ? Collections.unmodifiableList(parameters)
037                : Collections.<BoundParameterSymbol>emptyList();
038        this.returnType = returnType;
039        this.routineKind = routineKind;
040    }
041
042    public String getPackageName() { return packageName; }
043    public String getRoutineName() { return routineName; }
044    public List<BoundParameterSymbol> getParameters() { return parameters; }
045    public BoundTypeRef getReturnType() { return returnType; }
046    public ERoutineKind getRoutineKind() { return routineKind; }
047
048    /**
049     * Returns a unique identifier for this routine.
050     * Format: {@code [pkg.]name/KIND(paramCount)} where KIND is one of:
051     * P (procedure), F (function), T (trigger), A (anonymous block),
052     * NP (nested procedure), NF (nested function), TM (type method).
053     * <p>
054     * Examples:
055     * <pre>
056     *   MY_PKG.CALC/F(2)    — function CALC in MY_PKG, 2 params
057     *   MY_PKG.CALC/P(2)    — procedure CALC in MY_PKG, 2 params
058     *   STANDALONE/P(0)      — standalone procedure, no params
059     *   &lt;anonymous&gt;/A(0)     — anonymous block
060     * </pre>
061     */
062    public String getRoutineId() {
063        StringBuilder sb = new StringBuilder();
064        if (packageName != null && !packageName.isEmpty()) {
065            sb.append(packageName).append('.');
066        }
067        sb.append(routineName);
068        sb.append('/').append(kindCode());
069        sb.append('(').append(parameters.size()).append(')');
070        return sb.toString();
071    }
072
073    private String kindCode() {
074        switch (routineKind) {
075            case PROCEDURE:        return "P";
076            case FUNCTION:         return "F";
077            case TRIGGER:          return "T";
078            case ANONYMOUS_BLOCK:  return "A";
079            case NESTED_PROCEDURE: return "NP";
080            case NESTED_FUNCTION:  return "NF";
081            case TYPE_METHOD:      return "TM";
082            default:               return "P";
083        }
084    }
085
086    @Override
087    public ESymbolKind getSymbolKind() {
088        return ESymbolKind.ROUTINE;
089    }
090
091    @Override
092    public String toString() {
093        return "BoundRoutineSymbol{" + getRoutineId() + ", " + routineKind + "}";
094    }
095}