Use LCOV_EXCL comments to exclude some lines from test coverage (#1662)

This commit is contained in:
Rangi
2025-02-16 19:56:55 +01:00
committed by GitHub
parent c9060c7f2d
commit 632342b254
30 changed files with 133 additions and 100 deletions

1
.gitignore vendored
View File

@@ -14,4 +14,5 @@ CMakeCache.txt
CMakeFiles/ CMakeFiles/
cmake_install.cmake cmake_install.cmake
build/ build/
*.dSYM/
callgrind.out.* callgrind.out.*

View File

@@ -82,7 +82,6 @@ Symbol *sym_RedefEqu(std::string const &symName, int32_t value);
Symbol *sym_AddVar(std::string const &symName, int32_t value); Symbol *sym_AddVar(std::string const &symName, int32_t value);
int32_t sym_GetRSValue(); int32_t sym_GetRSValue();
void sym_SetRSValue(int32_t value); void sym_SetRSValue(int32_t value);
uint32_t sym_GetConstantValue(std::string const &symName);
// Find a symbol by exact name, bypassing expansion checks // Find a symbol by exact name, bypassing expansion checks
Symbol *sym_FindExactSymbol(std::string const &symName); Symbol *sym_FindExactSymbol(std::string const &symName);
// Find a symbol, possibly scoped, by name // Find a symbol, possibly scoped, by name

View File

@@ -103,7 +103,7 @@ public:
} else if (other._tag == other._t2.tag_value) { } else if (other._tag == other._t2.tag_value) {
*this = other._t2.value; *this = other._t2.value;
} else { } else {
_tag = nulltag; _tag = nulltag; // LCOV_EXCL_LINE
} }
return *this; return *this;
} }

View File

@@ -119,9 +119,11 @@ void fstk_SetPreIncludeFile(std::string const &path) {
warnx("Overriding pre-included filename %s", preIncludeName.c_str()); warnx("Overriding pre-included filename %s", preIncludeName.c_str());
} }
preIncludeName = path; preIncludeName = path;
// LCOV_EXCL_START
if (verbose) { if (verbose) {
printf("Pre-included filename %s\n", preIncludeName.c_str()); printf("Pre-included filename %s\n", preIncludeName.c_str());
} }
// LCOV_EXCL_STOP
} }
static void printDep(std::string const &path) { static void printDep(std::string const &path) {
@@ -308,9 +310,11 @@ void fstk_RunInclude(std::string const &path, bool preInclude) {
if (!fullPath) { if (!fullPath) {
if (generatedMissingIncludes && !preInclude) { if (generatedMissingIncludes && !preInclude) {
// LCOV_EXCL_START
if (verbose) { if (verbose) {
printf("Aborting (-MG) on INCLUDE file '%s' (%s)\n", path.c_str(), strerror(errno)); printf("Aborting (-MG) on INCLUDE file '%s' (%s)\n", path.c_str(), strerror(errno));
} }
// LCOV_EXCL_STOP
failedOnMissingInclude = true; failedOnMissingInclude = true;
} else { } else {
error("Unable to open included file '%s': %s\n", path.c_str(), strerror(errno)); error("Unable to open included file '%s': %s\n", path.c_str(), strerror(errno));
@@ -319,7 +323,7 @@ void fstk_RunInclude(std::string const &path, bool preInclude) {
} }
if (!newFileContext(*fullPath, false)) { if (!newFileContext(*fullPath, false)) {
fatalerror("Failed to set up lexer for file include\n"); fatalerror("Failed to set up lexer for file include\n"); // LCOV_EXCL_LINE
} }
} }

View File

@@ -77,6 +77,7 @@ struct FileUnmapDeleter {
static char *mapFile(int fd, std::string const &path, size_t size) { static char *mapFile(int fd, std::string const &path, size_t size) {
void *mappingAddr = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); void *mappingAddr = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
// LCOV_EXCL_START
if (mappingAddr == MAP_FAILED && errno == ENOTSUP) { if (mappingAddr == MAP_FAILED && errno == ENOTSUP) {
// The implementation may not support MAP_PRIVATE; try again with MAP_SHARED // The implementation may not support MAP_PRIVATE; try again with MAP_SHARED
// instead, offering, I believe, weaker guarantees about external modifications to // instead, offering, I believe, weaker guarantees about external modifications to
@@ -86,6 +87,7 @@ static char *mapFile(int fd, std::string const &path, size_t size) {
} }
mappingAddr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); mappingAddr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0);
} }
// LCOV_EXCL_STOP
return mappingAddr != MAP_FAILED ? static_cast<char *>(mappingAddr) : nullptr; return mappingAddr != MAP_FAILED ? static_cast<char *>(mappingAddr) : nullptr;
} }
@@ -412,21 +414,27 @@ bool LexerState::setFileAsNextState(std::string const &filePath, bool updateStat
if (filePath == "-") { if (filePath == "-") {
path = "<stdin>"; path = "<stdin>";
content.emplace<BufferedContent>(STDIN_FILENO); content.emplace<BufferedContent>(STDIN_FILENO);
// LCOV_EXCL_START
if (verbose) { if (verbose) {
printf("Opening stdin\n"); printf("Opening stdin\n");
} }
// LCOV_EXCL_STOP
} else { } else {
struct stat statBuf; struct stat statBuf;
if (stat(filePath.c_str(), &statBuf) != 0) { if (stat(filePath.c_str(), &statBuf) != 0) {
// LCOV_EXCL_START
error("Failed to stat file \"%s\": %s\n", filePath.c_str(), strerror(errno)); error("Failed to stat file \"%s\": %s\n", filePath.c_str(), strerror(errno));
return false; return false;
// LCOV_EXCL_STOP
} }
path = filePath; path = filePath;
int fd = open(path.c_str(), O_RDONLY); int fd = open(path.c_str(), O_RDONLY);
if (fd < 0) { if (fd < 0) {
// LCOV_EXCL_START
error("Failed to open file \"%s\": %s\n", path.c_str(), strerror(errno)); error("Failed to open file \"%s\": %s\n", path.c_str(), strerror(errno));
return false; return false;
// LCOV_EXCL_STOP
} }
bool isMmapped = false; bool isMmapped = false;
@@ -438,9 +446,11 @@ bool LexerState::setFileAsNextState(std::string const &filePath, bool updateStat
content.emplace<ViewedContent>( content.emplace<ViewedContent>(
std::shared_ptr<char[]>(mappingAddr, FileUnmapDeleter(size)), size std::shared_ptr<char[]>(mappingAddr, FileUnmapDeleter(size)), size
); );
// LCOV_EXCL_START
if (verbose) { if (verbose) {
printf("File \"%s\" is mmap()ped\n", path.c_str()); printf("File \"%s\" is mmap()ped\n", path.c_str());
} }
// LCOV_EXCL_STOP
isMmapped = true; isMmapped = true;
} }
} }
@@ -448,6 +458,7 @@ bool LexerState::setFileAsNextState(std::string const &filePath, bool updateStat
if (!isMmapped) { if (!isMmapped) {
// Sometimes mmap() fails or isn't available, so have a fallback // Sometimes mmap() fails or isn't available, so have a fallback
content.emplace<BufferedContent>(fd); content.emplace<BufferedContent>(fd);
// LCOV_EXCL_START
if (verbose) { if (verbose) {
if (statBuf.st_size == 0) { if (statBuf.st_size == 0) {
printf("File \"%s\" is empty\n", path.c_str()); printf("File \"%s\" is empty\n", path.c_str());
@@ -457,6 +468,7 @@ bool LexerState::setFileAsNextState(std::string const &filePath, bool updateStat
); );
} }
} }
// LCOV_EXCL_STOP
} }
} }
@@ -552,7 +564,9 @@ size_t BufferedContent::readMore(size_t startIndex, size_t nbChars) {
ssize_t nbReadChars = read(fd, &buf[startIndex], nbChars); ssize_t nbReadChars = read(fd, &buf[startIndex], nbChars);
if (nbReadChars == -1) { if (nbReadChars == -1) {
// LCOV_EXCL_START
fatalerror("Error while reading \"%s\": %s\n", lexerState->path.c_str(), strerror(errno)); fatalerror("Error while reading \"%s\": %s\n", lexerState->path.c_str(), strerror(errno));
// LCOV_EXCL_STOP
} }
size += nbReadChars; size += nbReadChars;
@@ -761,7 +775,9 @@ int LexerState::peekCharAhead() {
// and `.peekCharAhead()` will continue with its parent // and `.peekCharAhead()` will continue with its parent
assume(exp.offset <= exp.size()); assume(exp.offset <= exp.size());
if (exp.offset + distance < exp.size()) { if (exp.offset + distance < exp.size()) {
return static_cast<uint8_t>((*exp.contents)[exp.offset + distance]); // Macro args can't be recursive, since `peek()` marks them as scanned, so
// this is a failsafe that (as far as I can tell) won't ever actually run.
return static_cast<uint8_t>((*exp.contents)[exp.offset + distance]); // LCOV_EXCL_LINE
} }
distance -= exp.size() - exp.offset; distance -= exp.size() - exp.offset;
} }
@@ -1323,8 +1339,11 @@ static void appendEscapedString(std::string &str, std::string const &escape) {
str += "\\n"; str += "\\n";
break; break;
case '\r': case '\r':
// A literal CR in a string may get treated as a LF, so '\r' is not tested.
// LCOV_EXCL_START
str += "\\r"; str += "\\r";
break; break;
// LCOV_EXCL_STOP
case '\t': case '\t':
str += "\\t"; str += "\\t";
break; break;
@@ -2163,7 +2182,8 @@ static Token skipIfBlock(bool toEndc) {
case T_(POP_ELIF): case T_(POP_ELIF):
if (lexer_ReachedELSEBlock()) { if (lexer_ReachedELSEBlock()) {
fatalerror("Found ELIF after an ELSE block\n"); // This should be redundant, as the parser handles this error first.
fatalerror("Found ELIF after an ELSE block\n"); // LCOV_EXCL_LINE
} }
if (!toEndc && lexer_GetIFDepth() == startingDepth) { if (!toEndc && lexer_GetIFDepth() == startingDepth) {
return token; return token;
@@ -2255,9 +2275,8 @@ static Token yylex_SKIP_TO_ENDR() {
case T_(POP_ENDR): case T_(POP_ENDR):
depth--; depth--;
if (!depth) { // `lexer_CaptureRept` has already guaranteed that the `ENDR`s are balanced
return Token(T_(YYEOF)); // yywrap() will finish the REPT/FOR loop assume(depth > 0);
}
break; break;
case T_(POP_IF): case T_(POP_IF):

View File

@@ -87,6 +87,7 @@ static option const longopts[] = {
{nullptr, no_argument, nullptr, 0 } {nullptr, no_argument, nullptr, 0 }
}; };
// LCOV_EXCL_START
static void printUsage() { static void printUsage() {
fputs( fputs(
"Usage: rgbasm [-EhVvw] [-b chars] [-D name[=value]] [-g chars] [-I path]\n" "Usage: rgbasm [-EhVvw] [-b chars] [-D name[=value]] [-g chars] [-I path]\n"
@@ -107,6 +108,7 @@ static void printUsage() {
stderr stderr
); );
} }
// LCOV_EXCL_STOP
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
time_t now = time(nullptr); time_t now = time(nullptr);
@@ -176,8 +178,10 @@ int main(int argc, char *argv[]) {
break; break;
case 'h': case 'h':
// LCOV_EXCL_START
printUsage(); printUsage();
exit(0); exit(0);
// LCOV_EXCL_STOP
case 'I': case 'I':
fstk_AddIncludePath(musl_optarg); fstk_AddIncludePath(musl_optarg);
@@ -195,7 +199,7 @@ int main(int argc, char *argv[]) {
dependFileName = "<stdout>"; dependFileName = "<stdout>";
} }
if (dependFile == nullptr) { if (dependFile == nullptr) {
err("Failed to open dependfile \"%s\"", dependFileName); err("Failed to open dependfile \"%s\"", dependFileName); // LCOV_EXCL_LINE
} }
break; break;
@@ -302,9 +306,11 @@ int main(int argc, char *argv[]) {
if (stateFileSpecs.find(name) != stateFileSpecs.end()) { if (stateFileSpecs.find(name) != stateFileSpecs.end()) {
warnx("Overriding state filename %s", name); warnx("Overriding state filename %s", name);
} }
// LCOV_EXCL_START
if (verbose) { if (verbose) {
printf("State filename %s\n", name); printf("State filename %s\n", name);
} }
// LCOV_EXCL_STOP
stateFileSpecs.emplace(name, std::move(features)); stateFileSpecs.emplace(name, std::move(features));
break; break;
} }
@@ -314,8 +320,10 @@ int main(int argc, char *argv[]) {
exit(0); exit(0);
case 'v': case 'v':
// LCOV_EXCL_START
verbose = true; verbose = true;
break; break;
// LCOV_EXCL_STOP
case 'W': case 'W':
opt_W(musl_optarg); opt_W(musl_optarg);
@@ -367,8 +375,10 @@ int main(int argc, char *argv[]) {
// Unrecognized options // Unrecognized options
default: default:
// LCOV_EXCL_START
printUsage(); printUsage();
exit(1); exit(1);
// LCOV_EXCL_STOP
} }
} }
@@ -391,7 +401,7 @@ int main(int argc, char *argv[]) {
std::string mainFileName = argv[musl_optind]; std::string mainFileName = argv[musl_optind];
if (verbose) { if (verbose) {
printf("Assembling %s\n", mainFileName.c_str()); printf("Assembling %s\n", mainFileName.c_str()); // LCOV_EXCL_LINE
} }
if (dependFile) { if (dependFile) {

View File

@@ -61,7 +61,7 @@ void out_RegisterNode(std::shared_ptr<FileStackNode> node) {
} }
} }
// Return a section's ID, or UINT32_MAX if the section is not in the list // Return a section's ID, or UINT32_MAX if the section does not exist
static uint32_t getSectIDIfAny(Section *sect) { static uint32_t getSectIDIfAny(Section *sect) {
if (!sect) { if (!sect) {
return UINT32_MAX; return UINT32_MAX;
@@ -71,7 +71,8 @@ static uint32_t getSectIDIfAny(Section *sect) {
return static_cast<uint32_t>(search->second); return static_cast<uint32_t>(search->second);
} }
fatalerror("Unknown section '%s'\n", sect->name.c_str()); // Every section that exists should be in `sectionMap`
fatalerror("Unknown section '%s'\n", sect->name.c_str()); // LCOV_EXCL_LINE
} }
static void writePatch(Patch const &patch, FILE *file) { static void writePatch(Patch const &patch, FILE *file) {
@@ -175,7 +176,7 @@ static void writeRpn(std::vector<uint8_t> &rpnexpr, std::vector<uint8_t> const &
sym = sym_FindExactSymbol(symName); sym = sym_FindExactSymbol(symName);
if (sym->isConstant()) { if (sym->isConstant()) {
rpnexpr[rpnptr++] = RPN_CONST; rpnexpr[rpnptr++] = RPN_CONST;
value = sym_GetConstantValue(symName); value = sym->getConstantValue();
} else { } else {
rpnexpr[rpnptr++] = RPN_SYM; rpnexpr[rpnptr++] = RPN_SYM;
registerUnregisteredSymbol(*sym); // Ensure that `sym->ID` is set registerUnregisteredSymbol(*sym); // Ensure that `sym->ID` is set
@@ -323,7 +324,7 @@ void out_WriteObject() {
file = stdout; file = stdout;
} }
if (!file) { if (!file) {
err("Failed to open object file '%s'", objectFileName.c_str()); err("Failed to open object file '%s'", objectFileName.c_str()); // LCOV_EXCL_LINE
} }
Defer closeFile{[&] { fclose(file); }}; Defer closeFile{[&] { fclose(file); }};
@@ -343,14 +344,7 @@ void out_WriteObject() {
writeFileStackNode(node, file); writeFileStackNode(node, file);
// The list is supposed to have decrementing IDs // The list is supposed to have decrementing IDs
if (it + 1 != fileStackNodes.end() && it[1]->ID != node.ID - 1) { assume(it + 1 == fileStackNodes.end() || it[1]->ID == node.ID - 1);
fatalerror(
"Internal error: fstack node #%" PRIu32 " follows #%" PRIu32
". Please report this to the developers!\n",
it[1]->ID,
node.ID
);
}
} }
for (Symbol const *sym : objectSymbols) { for (Symbol const *sym : objectSymbols) {
@@ -373,9 +367,11 @@ void out_SetFileName(std::string const &name) {
warnx("Overriding output filename %s", objectFileName.c_str()); warnx("Overriding output filename %s", objectFileName.c_str());
} }
objectFileName = name; objectFileName = name;
// LCOV_EXCL_START
if (verbose) { if (verbose) {
printf("Output filename %s\n", objectFileName.c_str()); printf("Output filename %s\n", objectFileName.c_str());
} }
// LCOV_EXCL_STOP
} }
static void dumpString(std::string const &escape, FILE *file) { static void dumpString(std::string const &escape, FILE *file) {
@@ -528,7 +524,7 @@ void out_WriteState(std::string name, std::vector<StateFeature> const &features)
file = stdout; file = stdout;
} }
if (!file) { if (!file) {
err("Failed to open state file '%s'", name.c_str()); err("Failed to open state file '%s'", name.c_str()); // LCOV_EXCL_LINE
} }
Defer closeFile{[&] { fclose(file); }}; Defer closeFile{[&] { fclose(file); }};

View File

@@ -94,7 +94,7 @@ void Expression::makeSymbol(std::string const &symName) {
*ptr++ = RPN_SYM; *ptr++ = RPN_SYM;
memcpy(ptr, sym->name.c_str(), nameLen); memcpy(ptr, sym->name.c_str(), nameLen);
} else { } else {
data = static_cast<int32_t>(sym_GetConstantValue(symName)); data = static_cast<int32_t>(sym->getConstantValue());
} }
} }
@@ -325,42 +325,12 @@ void Expression::makeUnaryOp(RPNCommand op, Expression &&src) {
case RPN_TZCOUNT: case RPN_TZCOUNT:
data = val != 0 ? ctz(uval) : 32; data = val != 0 ? ctz(uval) : 32;
break; break;
default:
case RPN_LOGOR:
case RPN_LOGAND:
case RPN_LOGEQ:
case RPN_LOGGT:
case RPN_LOGLT:
case RPN_LOGGE:
case RPN_LOGLE:
case RPN_LOGNE:
case RPN_ADD:
case RPN_SUB:
case RPN_XOR:
case RPN_OR:
case RPN_AND:
case RPN_SHL:
case RPN_SHR:
case RPN_USHR:
case RPN_MUL:
case RPN_DIV:
case RPN_MOD:
case RPN_EXP:
case RPN_BANK_SYM:
case RPN_BANK_SECT:
case RPN_BANK_SELF:
case RPN_SIZEOF_SECT:
case RPN_STARTOF_SECT:
case RPN_SIZEOF_SECTTYPE:
case RPN_STARTOF_SECTTYPE:
case RPN_HRAM:
case RPN_RST:
case RPN_BIT_INDEX:
case RPN_CONST:
case RPN_SYM:
// `makeUnaryOp` should never be called with a non-unary operator! // `makeUnaryOp` should never be called with a non-unary operator!
// LCOV_EXCL_START
unreachable_(); unreachable_();
} }
// LCOV_EXCL_STOP
} else if (op == RPN_LOGNOT && tryConstLogNot(src)) { } else if (op == RPN_LOGNOT && tryConstLogNot(src)) {
data = 0; data = 0;
} else if (int32_t constVal; op == RPN_LOW && (constVal = tryConstLow(src)) != -1) { } else if (int32_t constVal; op == RPN_LOW && (constVal = tryConstLow(src)) != -1) {
@@ -503,29 +473,12 @@ void Expression::makeBinaryOp(RPNCommand op, Expression &&src1, Expression const
data = op_exponent(lval, rval); data = op_exponent(lval, rval);
break; break;
default:
case RPN_NEG:
case RPN_NOT:
case RPN_LOGNOT:
case RPN_BANK_SYM:
case RPN_BANK_SECT:
case RPN_BANK_SELF:
case RPN_SIZEOF_SECT:
case RPN_STARTOF_SECT:
case RPN_SIZEOF_SECTTYPE:
case RPN_STARTOF_SECTTYPE:
case RPN_HRAM:
case RPN_RST:
case RPN_BIT_INDEX:
case RPN_HIGH:
case RPN_LOW:
case RPN_BITWIDTH:
case RPN_TZCOUNT:
case RPN_CONST:
case RPN_SYM:
// `makeBinaryOp` should never be called with a non-binary operator! // `makeBinaryOp` should never be called with a non-binary operator!
// LCOV_EXCL_START
unreachable_(); unreachable_();
} }
// LCOV_EXCL_STOP
} else if (op == RPN_SUB && src1.isDiffConstant(src2.symbolOf())) { } else if (op == RPN_SUB && src1.isDiffConstant(src2.symbolOf())) {
data = src1.symbolOf()->getValue() - src2.symbolOf()->getValue(); data = src1.symbolOf()->getValue() - src2.symbolOf()->getValue();
} else if ((op == RPN_LOGAND || op == RPN_AND) && tryConstZero(src1, src2)) { } else if ((op == RPN_LOGAND || op == RPN_AND) && tryConstZero(src1, src2)) {

View File

@@ -875,9 +875,11 @@ void sect_BinaryFile(std::string const &name, int32_t startPos) {
} }
if (!file) { if (!file) {
if (generatedMissingIncludes) { if (generatedMissingIncludes) {
// LCOV_EXCL_START
if (verbose) { if (verbose) {
printf("Aborting (-MG) on INCBIN file '%s' (%s)\n", name.c_str(), strerror(errno)); printf("Aborting (-MG) on INCBIN file '%s' (%s)\n", name.c_str(), strerror(errno));
} }
// LCOV_EXCL_STOP
failedOnMissingInclude = true; failedOnMissingInclude = true;
} else { } else {
error("Error opening INCBIN file '%s': %s\n", name.c_str(), strerror(errno)); error("Error opening INCBIN file '%s': %s\n", name.c_str(), strerror(errno));
@@ -942,9 +944,11 @@ void sect_BinaryFileSlice(std::string const &name, int32_t startPos, int32_t len
} }
if (!file) { if (!file) {
if (generatedMissingIncludes) { if (generatedMissingIncludes) {
// LCOV_EXCL_START
if (verbose) { if (verbose) {
printf("Aborting (-MG) on INCBIN file '%s' (%s)\n", name.c_str(), strerror(errno)); printf("Aborting (-MG) on INCBIN file '%s' (%s)\n", name.c_str(), strerror(errno));
} }
// LCOV_EXCL_STOP
failedOnMissingInclude = true; failedOnMissingInclude = true;
} else { } else {
error("Error opening INCBIN file '%s': %s\n", name.c_str(), strerror(errno)); error("Error opening INCBIN file '%s': %s\n", name.c_str(), strerror(errno));

View File

@@ -325,19 +325,6 @@ uint32_t Symbol::getConstantValue() const {
return 0; return 0;
} }
uint32_t sym_GetConstantValue(std::string const &symName) {
if (Symbol const *sym = sym_FindScopedSymbol(symName); sym) {
return sym->getConstantValue();
}
if (sym_IsPurgedScoped(symName)) {
error("'%s' not defined; it was purged\n", symName.c_str());
} else {
error("'%s' not defined\n", symName.c_str());
}
return 0;
}
std::pair<Symbol const *, Symbol const *> sym_GetCurrentLabelScopes() { std::pair<Symbol const *, Symbol const *> sym_GetCurrentLabelScopes() {
return {globalScope, localScope}; return {globalScope, localScope};
} }
@@ -528,8 +515,10 @@ static uint32_t anonLabelID = 0;
Symbol *sym_AddAnonLabel() { Symbol *sym_AddAnonLabel() {
if (anonLabelID == UINT32_MAX) { if (anonLabelID == UINT32_MAX) {
// LCOV_EXCL_START
error("Only %" PRIu32 " anonymous labels can be created!", anonLabelID); error("Only %" PRIu32 " anonymous labels can be created!", anonLabelID);
return nullptr; return nullptr;
// LCOV_EXCL_STOP
} }
std::string anon = sym_MakeAnonLabelName(0, true); // The direction is important! std::string anon = sym_MakeAnonLabelName(0, true); // The direction is important!
@@ -555,6 +544,7 @@ std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg) {
} else { } else {
ofs--; // We're referencing symbols that haven't been created yet... ofs--; // We're referencing symbols that haven't been created yet...
if (ofs > UINT32_MAX - anonLabelID) { if (ofs > UINT32_MAX - anonLabelID) {
// LCOV_EXCL_START
error( error(
"Reference to anonymous label %" PRIu32 " after, when only %" PRIu32 "Reference to anonymous label %" PRIu32 " after, when only %" PRIu32
" may still be created\n", " may still be created\n",
@@ -562,6 +552,7 @@ std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg) {
UINT32_MAX - anonLabelID UINT32_MAX - anonLabelID
); );
} else { } else {
// LCOV_EXCL_STOP
id = anonLabelID + ofs; id = anonLabelID + ofs;
} }
} }
@@ -571,8 +562,11 @@ std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg) {
void sym_Export(std::string const &symName) { void sym_Export(std::string const &symName) {
if (symName.starts_with('!')) { if (symName.starts_with('!')) {
// LCOV_EXCL_START
// The parser does not accept anonymous labels for an `EXPORT` directive
error("Anonymous labels cannot be exported\n"); error("Anonymous labels cannot be exported\n");
return; return;
// LCOV_EXCL_STOP
} }
Symbol *sym = sym_FindScopedSymbol(symName); Symbol *sym = sym_FindScopedSymbol(symName);
@@ -654,11 +648,13 @@ void sym_Init(time_t now) {
sym_AddEqu("__RGBDS_RC__"s, PACKAGE_VERSION_RC)->isBuiltin = true; sym_AddEqu("__RGBDS_RC__"s, PACKAGE_VERSION_RC)->isBuiltin = true;
#endif #endif
// LCOV_EXCL_START
if (now == static_cast<time_t>(-1)) { if (now == static_cast<time_t>(-1)) {
warn("Failed to determine current time"); warn("Failed to determine current time");
// Fall back by pretending we are at the Epoch // Fall back by pretending we are at the Epoch
now = 0; now = 0;
} }
// LCOV_EXCL_STOP
tm const *time_local = localtime(&now); tm const *time_local = localtime(&now);

View File

@@ -54,6 +54,7 @@ static option const longopts[] = {
{nullptr, no_argument, nullptr, 0 } {nullptr, no_argument, nullptr, 0 }
}; };
// LCOV_EXCL_START
static void printUsage() { static void printUsage() {
fputs( fputs(
"Usage: rgbfix [-hjOsVv] [-C | -c] [-f <fix_spec>] [-i <game_id>] [-k <licensee>]\n" "Usage: rgbfix [-hjOsVv] [-C | -c] [-f <fix_spec>] [-i <game_id>] [-k <licensee>]\n"
@@ -72,6 +73,7 @@ static void printUsage() {
stderr stderr
); );
} }
// LCOV_EXCL_STOP
static uint8_t nbErrors; static uint8_t nbErrors;
@@ -1322,8 +1324,10 @@ int main(int argc, char *argv[]) {
break; break;
case 'h': case 'h':
// LCOV_EXCL_START
printUsage(); printUsage();
exit(0); exit(0);
// LCOV_EXCL_STOP
case 'i': case 'i':
gameID = musl_optarg; gameID = musl_optarg;

View File

@@ -156,6 +156,7 @@ static option const longopts[] = {
{nullptr, no_argument, nullptr, 0 } {nullptr, no_argument, nullptr, 0 }
}; };
// LCOV_EXCL_START
static void printUsage() { static void printUsage() {
fputs( fputs(
"Usage: rgbgfx [-r stride] [-ChmOuVXYZ] [-v [-v ...]] [-a <attr_map> | -A]\n" "Usage: rgbgfx [-r stride] [-ChmOuVXYZ] [-v [-v ...]] [-a <attr_map> | -A]\n"
@@ -174,6 +175,7 @@ static void printUsage() {
stderr stderr
); );
} }
// LCOV_EXCL_STOP
// Parses a number at the beginning of a string, moving the pointer to skip the parsed characters. // Parses a number at the beginning of a string, moving the pointer to skip the parsed characters.
// Returns the provided errVal on error. // Returns the provided errVal on error.
@@ -425,8 +427,10 @@ static char *parseArgv(int argc, char *argv[]) {
} }
break; break;
case 'h': case 'h':
// LCOV_EXCL_START
printUsage(); printUsage();
exit(0); exit(0);
// LCOV_EXCL_STOP
case 'i': case 'i':
if (!options.inputTileset.empty()) { if (!options.inputTileset.empty()) {
warning("Overriding input tileset file %s", options.inputTileset.c_str()); warning("Overriding input tileset file %s", options.inputTileset.c_str());
@@ -615,8 +619,10 @@ static char *parseArgv(int argc, char *argv[]) {
} }
break; break;
default: default:
// LCOV_EXCL_START
printUsage(); printUsage();
exit(1); exit(1);
// LCOV_EXCL_STOP
} }
} }

View File

@@ -163,6 +163,7 @@ static option const longopts[] = {
{nullptr, no_argument, nullptr, 0 } {nullptr, no_argument, nullptr, 0 }
}; };
// LCOV_EXCL_START
static void printUsage() { static void printUsage() {
fputs( fputs(
"Usage: rgblink [-dhMtVvwx] [-l script] [-m map_file] [-n sym_file]\n" "Usage: rgblink [-dhMtVvwx] [-l script] [-m map_file] [-n sym_file]\n"
@@ -181,6 +182,7 @@ static void printUsage() {
stderr stderr
); );
} }
// LCOV_EXCL_STOP
enum ScrambledRegion { enum ScrambledRegion {
SCRAMBLE_ROMX, SCRAMBLE_ROMX,
@@ -335,8 +337,10 @@ int main(int argc, char *argv[]) {
isWRAM0Mode = true; isWRAM0Mode = true;
break; break;
case 'h': case 'h':
// LCOV_EXCL_START
printUsage(); printUsage();
exit(0); exit(0);
// LCOV_EXCL_STOP
case 'l': case 'l':
if (linkerScriptName) { if (linkerScriptName) {
warnx("Overriding linker script %s", linkerScriptName); warnx("Overriding linker script %s", linkerScriptName);
@@ -407,8 +411,10 @@ int main(int argc, char *argv[]) {
is32kMode = true; is32kMode = true;
break; break;
default: default:
// LCOV_EXCL_START
printUsage(); printUsage();
exit(1); exit(1);
// LCOV_EXCL_STOP
} }
} }

View File

@@ -7,6 +7,17 @@ FOR V, 1, 100
PRINTLN "cont" PRINTLN "cont"
ENDR ENDR
WARN "done {d:V}" WARN "done {d:V}"
rept 2
break
; skips nested code
rept 3
println "\tinner"
endr
if 1
println "\tconditional"
endc
println "outer"
endr
rept 1 rept 1
break break
; skips invalid code ; skips invalid code

View File

@@ -1,8 +1,8 @@
warning: break.asm(9): [-Wuser] warning: break.asm(9): [-Wuser]
done 5 done 5
warning: break.asm(17): [-Wuser] warning: break.asm(28): [-Wuser]
OK OK
error: break.asm(18): error: break.asm(29):
BREAK can only be used inside a REPT/FOR block BREAK can only be used inside a REPT/FOR block
FATAL: break.asm(19) -> break.asm::REPT~1(23): FATAL: break.asm(30) -> break.asm::REPT~1(34):
Ended block with 1 unterminated IF construct Ended block with 1 unterminated IF construct

View File

@@ -19,7 +19,7 @@ DEF copy EQUS STRSUB("{invalid}", 1)
println "\"{#s:invalid}\" == \"{#s:copy}\" ({d:n})" println "\"{#s:invalid}\" == \"{#s:copy}\" ({d:n})"
DEF mid1 EQUS STRSUB("{invalid}", 5, 2) DEF mid1 EQUS STRSUB("{invalid}", 5, 2)
DEF mid2 EQUS STRSUB("{invalid}", 9, 1) DEF mid2 EQUS STRSLICE("{invalid}", 8, 9)
println "\"{#s:mid2}{#s:mid1}\"" println "\"{#s:mid2}{#s:mid1}\""
; characters: ; characters:
@@ -53,3 +53,6 @@ println "\"{#s:invalid}\": {d:n} == {d:r}"
DEF final EQUS STRSUB("{invalid}", 4, 1) DEF final EQUS STRSUB("{invalid}", 4, 1)
println "\"{#s:invalid}\" ends \"{#s:final}\"" println "\"{#s:invalid}\" ends \"{#s:final}\""
REDEF final EQUS STRSLICE("{invalid}", 3, 4)
println "\"{#s:invalid}\" ends \"{#s:final}\""

View File

@@ -15,9 +15,9 @@ error: invalid-utf-8-strings.asm(17):
error: invalid-utf-8-strings.asm(17): error: invalid-utf-8-strings.asm(17):
STRSUB: Invalid UTF-8 byte 0xA2 STRSUB: Invalid UTF-8 byte 0xA2
error: invalid-utf-8-strings.asm(22): error: invalid-utf-8-strings.asm(22):
STRSUB: Invalid UTF-8 byte 0xA3 STRSLICE: Invalid UTF-8 byte 0xA3
error: invalid-utf-8-strings.asm(22): error: invalid-utf-8-strings.asm(22):
STRSUB: Invalid UTF-8 byte 0xA4 STRSLICE: Invalid UTF-8 byte 0xA4
error: invalid-utf-8-strings.asm(35): error: invalid-utf-8-strings.asm(35):
STRLEN: Invalid UTF-8 byte 0xFE STRLEN: Invalid UTF-8 byte 0xFE
error: invalid-utf-8-strings.asm(35): error: invalid-utf-8-strings.asm(35):
@@ -56,4 +56,6 @@ error: invalid-utf-8-strings.asm(50):
STRLEN: Incomplete UTF-8 character STRLEN: Incomplete UTF-8 character
error: invalid-utf-8-strings.asm(54): error: invalid-utf-8-strings.asm(54):
STRSUB: Incomplete UTF-8 character STRSUB: Incomplete UTF-8 character
error: Assembly aborted (29 errors)! error: invalid-utf-8-strings.asm(57):
STRSLICE: Incomplete UTF-8 character
error: Assembly aborted (30 errors)!

View File

@@ -4,3 +4,4 @@
"漢<>" "漢<>"
"abc<62><63>": 4 == 4 "abc<62><63>": 4 == 4
"abc<62><63>" ends "<22><>" "abc<62><63>" ends "<22><>"
"abc<62><63>" ends "<22><>"

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,5 @@
MACRO mac
DEF s EQUS "\#"
println "{#s:s}"
ENDM
mac \\\"\t\r\0\n\{\}\,\(\)\w\

View File

@@ -1,5 +1,5 @@
error: macro-arg-escape-chars.asm(5): error: macro-arg-illegal-escape.asm(5):
Illegal character escape 'w' Illegal character escape 'w'
error: macro-arg-escape-chars.asm(5): error: macro-arg-illegal-escape.asm(5):
Illegal character escape at end of input Illegal character escape at end of input
error: Assembly aborted (2 errors)! error: Assembly aborted (2 errors)!

View File

@@ -0,0 +1 @@
\\\"\t\r\0\n\{},()w\\

View File

@@ -28,7 +28,10 @@ purge #name
assert !def(name) && !def(#name) && def(hello) assert !def(name) && !def(#name) && def(hello)
section "test", rom0 section "test", rom0
#label:
db #hello db #hello
dw #hello dw #hello
dl #hello
#label:
dw BANK(#label), #label dw BANK(#label), #label

Binary file not shown.

View File

@@ -0,0 +1,2 @@
if 0
; no newline at end of file

View File

@@ -0,0 +1,2 @@
FATAL: unterminated-if-eof.asm(2):
Ended block with 1 unterminated IF construct

View File

@@ -109,6 +109,10 @@ for f in *.[12]bpp; do
runTest && tryCmp "$f" result.2bpp || failTest $? runTest && tryCmp "$f" result.2bpp || failTest $?
done done
# Test writing to stdout
newTest "$RGBGFX -m -o - write_stdout.bin > result.2bpp"
runTest && tryCmp write_stdout.out.2bpp result.2bpp || failTest $?
if [[ "$failed" -eq 0 ]]; then if [[ "$failed" -eq 0 ]]; then
echo "${bold}${green}All ${tests} tests passed!${rescolors}${resbold}" echo "${bold}${green}All ${tests} tests passed!${rescolors}${resbold}"
else else

BIN
test/gfx/write_stdout.bin Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

View File

@@ -0,0 +1 @@
? @@˙Ś˙˙€˙€đđŹxG~A? ˙ńâ~‚üřŕŕ