From 7733ccdeb641513512f33d7215014cb78485caf8 Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Sat, 4 Oct 2025 16:41:21 -0400 Subject: [PATCH] Implement `__SCOPE__` (#1845) --- man/rgbasm.5 | 1 + src/asm/symbol.cpp | 23 +++++++++++++++++++++++ test/asm/scope-level.asm | 27 +++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 test/asm/scope-level.asm diff --git a/man/rgbasm.5 b/man/rgbasm.5 index f7841b8b..13d7de74 100644 --- a/man/rgbasm.5 +++ b/man/rgbasm.5 @@ -1729,6 +1729,7 @@ The following symbols are defined by the assembler: .It Dv @ Ta Ic EQU Ta PC value (essentially, the current memory address) .It Dv . Ta Ic EQUS Ta The current global label scope .It Dv .. Ta Ic EQUS Ta The current local label scope +.It Dv __SCOPE__ Ta Ic EQUS Ta The innermost current label scope level (empty, ".", or "..") .It Dv _RS Ta Ic = Ta _RS Counter .It Dv _NARG Ta Ic EQU Ta Number of arguments passed to macro, updated by Ic SHIFT .It Dv __ISO_8601_LOCAL__ Ta Ic EQUS Ta ISO 8601 timestamp (local) diff --git a/src/asm/symbol.cpp b/src/asm/symbol.cpp index f95af7ca..571dd2f3 100644 --- a/src/asm/symbol.cpp +++ b/src/asm/symbol.cpp @@ -39,6 +39,7 @@ static Symbol const *localScope = nullptr; // Current section's local label sco static Symbol *PCSymbol; static Symbol *NARGSymbol; +static Symbol *SCOPESymbol; static Symbol *globalScopeSymbol; static Symbol *localScopeSymbol; static Symbol *RSSymbol; @@ -67,6 +68,19 @@ static int32_t NARGCallback() { } } +static std::shared_ptr SCOPECallback() { + if (localScope) { + return std::make_shared(".."); + } else if (globalScope) { + return std::make_shared("."); + } else { + if (!sect_GetSymbolSection()) { + error("`__SCOPE__` has no value outside of a section"); + } + return std::make_shared(""); + } +} + static std::shared_ptr globalScopeCallback() { if (!globalScope) { error("`.` has no value outside of a label scope"); @@ -296,6 +310,10 @@ Symbol *sym_FindScopedValidSymbol(std::string const &symName) { if (sym == localScopeSymbol && !localScope) { return nullptr; } + // `__SCOPE__` has no value outside of a section + if (sym == SCOPESymbol && !sect_GetSymbolSection()) { + return nullptr; + } return sym; } @@ -683,6 +701,11 @@ void sym_Init(time_t now) { localScopeSymbol->data = localScopeCallback; localScopeSymbol->isBuiltin = true; + SCOPESymbol = &createSymbol("__SCOPE__"s); + SCOPESymbol->type = SYM_EQUS; + SCOPESymbol->data = SCOPECallback; + SCOPESymbol->isBuiltin = true; + RSSymbol = sym_AddVar("_RS"s, 0); RSSymbol->isBuiltin = true; diff --git a/test/asm/scope-level.asm b/test/asm/scope-level.asm new file mode 100644 index 00000000..ee4d6529 --- /dev/null +++ b/test/asm/scope-level.asm @@ -0,0 +1,27 @@ +assert !def(__SCOPE__) + +section "test", rom0 + +assert !def(.) +assert !def(..) +assert #__SCOPE__ === "" + +Alpha.local1: +assert !def(.) +assert #.. === "Alpha.local1" +assert #__SCOPE__ === ".." + +Beta: +assert #. === "Beta" +assert !def(..) +assert #__SCOPE__ === "." + +Alpha.local2: +assert #. === "Beta" +assert #.. === "Alpha.local2" +assert #__SCOPE__ === ".." + +.newLocal: +assert #. === "Beta" +assert #.. === "Beta.newLocal" +assert #__SCOPE__ === ".."