Improved funchandler.go HandleFuncCall to handle consts and expressions better
This commit is contained in:
parent
2dc591f40d
commit
d57a40a7cf
1 changed files with 66 additions and 6 deletions
|
|
@ -272,25 +272,57 @@ func (fh *FunctionHandler) HandleFuncCall(line preproc.Line) ([]string, error) {
|
||||||
for i, arg := range callArgs {
|
for i, arg := range callArgs {
|
||||||
param := funcDecl.Params[i]
|
param := funcDecl.Params[i]
|
||||||
|
|
||||||
// Handle different argument types
|
// Handle special cases first
|
||||||
if strings.HasPrefix(arg, "@") {
|
if strings.HasPrefix(arg, "@") {
|
||||||
// Label reference: @labelname
|
// Label reference: @labelname
|
||||||
if err := fh.processLabelArg(arg, param, funcName, line, &inAssigns); err != nil {
|
if err := fh.processLabelArg(arg, param, funcName, line, &inAssigns); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else if strings.HasPrefix(arg, "\"") && strings.HasSuffix(arg, "\"") {
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(arg, "\"") && strings.HasSuffix(arg, "\"") {
|
||||||
// String constant
|
// String constant
|
||||||
if err := fh.processStringArg(arg, param, funcName, line, pragmaSet, &inAssigns); err != nil {
|
if err := fh.processStringArg(arg, param, funcName, line, pragmaSet, &inAssigns); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else if sym := fh.symTable.Lookup(arg, fh.currentFuncs); sym != nil {
|
continue
|
||||||
// Variable reference
|
}
|
||||||
|
|
||||||
|
// Use ParseOperandParam for variables, constants, and expressions
|
||||||
|
constLookup := func(name string) (int64, bool) {
|
||||||
|
if sym := fh.symTable.Lookup(name, fh.currentFuncs); sym != nil && sym.IsConst() {
|
||||||
|
return int64(sym.Value), true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, value, isVar, err := ParseOperandParam(
|
||||||
|
arg, fh.symTable, fh.currentFuncs, constLookup)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s:%d: CALL %s arg %d (%q): %w",
|
||||||
|
line.Filename, line.LineNo, funcName, i+1, arg, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Out/IO parameters must be writable variables
|
||||||
|
if param.Direction.Has(DirOut) && !isVar {
|
||||||
|
return nil, fmt.Errorf("%s:%d: CALL %s: cannot pass constant/expression to out/io parameter %q",
|
||||||
|
line.Filename, line.LineNo, funcName, param.Symbol.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isVar {
|
||||||
|
// Variable - get full symbol for type checking
|
||||||
|
sym := fh.symTable.Lookup(arg, fh.currentFuncs)
|
||||||
|
if sym == nil {
|
||||||
|
return nil, fmt.Errorf("%s:%d: CALL %s: internal error - variable %q not found",
|
||||||
|
line.Filename, line.LineNo, funcName, arg)
|
||||||
|
}
|
||||||
if err := fh.processVarArg(sym, param, funcName, line, &inAssigns, &outAssigns); err != nil {
|
if err := fh.processVarArg(sym, param, funcName, line, &inAssigns, &outAssigns); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Numeric constant
|
// Constant or expression result
|
||||||
if err := fh.processConstArg(arg, param, funcName, line, &inAssigns); err != nil {
|
if err := fh.processConstValue(value, param, funcName, line, &inAssigns); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -439,6 +471,34 @@ func (fh *FunctionHandler) processConstArg(arg string, param *FuncParam, funcNam
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// processConstValue handles pre-computed constant/expression values
|
||||||
|
// Used after ParseOperandParam has already validated and computed the value
|
||||||
|
func (fh *FunctionHandler) processConstValue(value uint16, param *FuncParam, funcName string, line preproc.Line, inAssigns *[]string) error {
|
||||||
|
// Verify value fits in parameter type
|
||||||
|
if param.Symbol.IsByte() && value > 255 {
|
||||||
|
return fmt.Errorf("%s:%d: CALL %s: value %d out of byte range for parameter %q",
|
||||||
|
line.Filename, line.LineNo, funcName, value, param.Symbol.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
lowByte := uint8(value & 0xFF)
|
||||||
|
highByte := uint8((value >> 8) & 0xFF)
|
||||||
|
|
||||||
|
*inAssigns = append(*inAssigns,
|
||||||
|
fmt.Sprintf(" lda #%d", lowByte),
|
||||||
|
fmt.Sprintf(" sta %s", param.Symbol.FullName()),
|
||||||
|
)
|
||||||
|
|
||||||
|
if param.Symbol.IsWord() {
|
||||||
|
// Optimize: only reload A if high byte differs
|
||||||
|
if highByte != lowByte {
|
||||||
|
*inAssigns = append(*inAssigns, fmt.Sprintf(" lda #%d", highByte))
|
||||||
|
}
|
||||||
|
*inAssigns = append(*inAssigns, fmt.Sprintf(" sta %s+1", param.Symbol.FullName()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// parseImplicitDecl parses {BYTE varname} or {WORD varname} and adds to symbol table
|
// parseImplicitDecl parses {BYTE varname} or {WORD varname} and adds to symbol table
|
||||||
func (fh *FunctionHandler) parseImplicitDecl(decl string, funcName string) error {
|
func (fh *FunctionHandler) parseImplicitDecl(decl string, funcName string) error {
|
||||||
parts := strings.Fields(decl)
|
parts := strings.Fields(decl)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue