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 {
|
||||
param := funcDecl.Params[i]
|
||||
|
||||
// Handle different argument types
|
||||
// Handle special cases first
|
||||
if strings.HasPrefix(arg, "@") {
|
||||
// Label reference: @labelname
|
||||
if err := fh.processLabelArg(arg, param, funcName, line, &inAssigns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if strings.HasPrefix(arg, "\"") && strings.HasSuffix(arg, "\"") {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(arg, "\"") && strings.HasSuffix(arg, "\"") {
|
||||
// String constant
|
||||
if err := fh.processStringArg(arg, param, funcName, line, pragmaSet, &inAssigns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if sym := fh.symTable.Lookup(arg, fh.currentFuncs); sym != nil {
|
||||
// Variable reference
|
||||
continue
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// Numeric constant
|
||||
if err := fh.processConstArg(arg, param, funcName, line, &inAssigns); err != nil {
|
||||
// Constant or expression result
|
||||
if err := fh.processConstValue(value, param, funcName, line, &inAssigns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
@ -439,6 +471,34 @@ func (fh *FunctionHandler) processConstArg(arg string, param *FuncParam, funcNam
|
|||
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
|
||||
func (fh *FunctionHandler) parseImplicitDecl(decl string, funcName string) error {
|
||||
parts := strings.Fields(decl)
|
||||
|
|
|
|||
Loading…
Reference in a new issue