feat(lint): eleven new rules over directives, data and addressing
Assisted-by: GLM 5.3
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package lint
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"sourcedock.dev/petrbalvin/gasm-sdk/ast"
|
||||
)
|
||||
|
||||
// scanAddressing flags the two pseudo-register spellings the language
|
||||
// reference (docs/asm/OPERANDS.md) calls its sharpest edge: a numeric offset
|
||||
// against FP names no symbol, and a negative numeric offset against SP
|
||||
// addresses the hardware stack pointer rather than the virtual frame.
|
||||
func scanAddressing(t *ast.Text, cfg Config) []Diagnostic {
|
||||
var out []Diagnostic
|
||||
for _, s := range t.Body {
|
||||
in, ok := s.(*ast.Instr)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, op := range in.Operands {
|
||||
if op.Kind != ast.OpAddr {
|
||||
continue
|
||||
}
|
||||
// FP is a pseudo-register, never a base register of a memory
|
||||
// operand; a Base of FP only arises from the numeric form
|
||||
// 0(FP), which the parser routes through memory parsing. The
|
||||
// toolchain rejects it with "cannot reference FP without a
|
||||
// symbol" and gasm with "unknown base register FP".
|
||||
if strings.EqualFold(op.Addr.Base, "FP") && !cfg.Disable[CodeUnnamedFPRef] {
|
||||
out = append(out, Diagnostic{
|
||||
Pos: op.Pos,
|
||||
Severity: Error,
|
||||
Code: CodeUnnamedFPRef,
|
||||
Message: "FP is referenced without a symbol; the assembler requires name+offset(FP)",
|
||||
})
|
||||
continue
|
||||
}
|
||||
// A numeric offset against (SP) addresses the hardware stack
|
||||
// pointer. Positive offsets are the deliberate runtime idiom
|
||||
// for reading caller frames, but a negative offset is exactly
|
||||
// the local-frame spelling with the name missing: x-8(SP) and
|
||||
// -8(SP) are one character apart and mean different registers.
|
||||
// Only the negative form is flagged, which keeps the rule
|
||||
// silent across GOROOT's 140-odd deliberate hardware-SP
|
||||
// references (all positive) while catching the mistyped local.
|
||||
if strings.EqualFold(op.Addr.Base, "SP") && op.Addr.Sym == nil &&
|
||||
op.Addr.HasOff && op.Addr.Offset < 0 && !cfg.Disable[CodeHardwareSP] {
|
||||
out = append(out, Diagnostic{
|
||||
Pos: op.Pos,
|
||||
Severity: Warning,
|
||||
Code: CodeHardwareSP,
|
||||
Message: fmt.Sprintf("%d(SP) addresses the hardware stack pointer, not the virtual frame; "+
|
||||
"a frame local is spelled x%d(SP)", op.Addr.Offset, op.Addr.Offset),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user