1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-04-11 08:37:00 +00:00

Put almost all warnings behind internal flags

This commit is contained in:
Karol Stasiak 2020-03-17 21:08:43 +01:00
parent 7939b0f2c1
commit 2eb8ef53ca
18 changed files with 94 additions and 47 deletions

View File

@ -409,7 +409,7 @@ object Cpu extends Enumeration {
private val alwaysDefaultFlags = Set(
VariableOverlap, CompactReturnDispatchParams, FunctionFallthrough, RegisterVariables, FunctionDeduplication, EnableBreakpoints,
NonZeroTerminatedLiteralWarning, CallToOverlappingBankWarning,
GenericWarnings, UselessCodeWarning, BuggyCodeWarning, FallbackValueUseWarning, DeprecationWarning, NonZeroTerminatedLiteralWarning, CallToOverlappingBankWarning,
)
private val mosAlwaysDefaultFlags = alwaysDefaultFlags
@ -562,6 +562,11 @@ object CompilationFlag extends Enumeration {
// special options
SingleThreaded,
// warning options
GenericWarnings,
UselessCodeWarning,
BuggyCodeWarning,
DeprecationWarning,
FallbackValueUseWarning,
ExtraComparisonWarnings,
RorWarning,
NonZeroTerminatedLiteralWarning,
@ -571,7 +576,7 @@ object CompilationFlag extends Enumeration {
EnableInternalTestSyntax,
InternalCurrentlyOptimizingForMeasurement = Value
val allWarnings: Set[CompilationFlag.Value] = Set(ExtraComparisonWarnings)
val allWarnings: Set[CompilationFlag.Value] = Set(GenericWarnings, UselessCodeWarning, BuggyCodeWarning, DeprecationWarning, FallbackValueUseWarning, ExtraComparisonWarnings, NonZeroTerminatedLiteralWarning, CallToOverlappingBankWarning)
val fromString: Map[String, CompilationFlag.Value] = Map(
"lunix" -> LUnixRelocatableCode,

View File

@ -67,7 +67,7 @@ object CoarseFlowAnalyzer {
var staSpIsNow = false
codeArray(i) match {
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(l))) =>
if (tFlag) {
if (tFlag && optimizationContext.options.flag(CompilationFlag.BuggyCodeWarning)) {
// T flag should not be set at a label!
optimizationContext.log.warn("The SET instruction shouldn't occur before a label")
}
@ -177,7 +177,7 @@ object CoarseFlowAnalyzer {
if (OpcodeClasses.ChangesStack(opcode) || OpcodeClasses.ChangesS(opcode)) currentStatus = currentStatus.copy(eqSX = false)
}
staSpWasLast = staSpIsNow
if (tFlag) {
if (tFlag && optimizationContext.options.flag(CompilationFlag.BuggyCodeWarning)) {
if (OpcodeClasses.ShortBranching(codeArray(i).opcode) || codeArray(i).opcode == JMP || codeArray(i).opcode == JSR) {
// T flag should not be set at a jump!
optimizationContext.log.warn("The SET instruction shouldn't occur before a jump")

View File

@ -49,7 +49,7 @@ abstract class AbstractReturnDispatch[T <: AbstractCode] {
if (indexerType.size != 1) {
ctx.log.error("Return dispatch index expression type has to be a byte", stmt.indexer.position)
}
if (indexerType.isSigned) {
if (indexerType.isSigned && ctx.options.flag(CompilationFlag.BuggyCodeWarning)) {
ctx.log.warn("Return dispatch index expression type will be automatically casted to unsigned", stmt.indexer.position)
}
stmt.params.foreach {
@ -81,7 +81,7 @@ abstract class AbstractReturnDispatch[T <: AbstractCode] {
}
val function: String = ctx.env.evalForAsm(branch.function) match {
case Some(MemoryAddressConstant(f: FunctionInMemory)) =>
if (f.returnType.name != returnType.name) {
if (f.returnType.name != returnType.name && ctx.options.flag(CompilationFlag.BuggyCodeWarning)) {
ctx.log.warn(s"Dispatching to a function of different return type: dispatcher return type: ${returnType.name}, dispatchee return type: ${f.returnType.name}", branch.function.position)
}
f.name

View File

@ -369,7 +369,7 @@ abstract class AbstractStatementCompiler[T <: AbstractCode] {
)
)._1 ++ callChunk(Label(callLabel)))
return calls -> (labelChunk(callLabel) ++ extractedBody ++ extra ++ extra2)
} else {
} else if (ctx.options.flag(CompilationFlag.FallbackValueUseWarning)) {
ctx.log.warn("For loop too complex to extract, inlining", f.position)
}
}

View File

@ -100,12 +100,30 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
// generic warnings:
stmt match {
case ExpressionStatement(expr@FunctionCallExpression("strzlen" | "putstrz" | "strzcmp" | "strzcopy", params)) =>
for (param <- params) checkIfNullTerminated(stmt, param)
for (param <- params) checkIfNullTerminated(ctx, stmt, param)
case ExpressionStatement(expr@FunctionCallExpression(f, List(VariableExpression(v)))) if hiddenEffectFreeFunctions(f)=>
val volatile = ctx.env.maybeGet[ThingInMemory](v).fold(false)(_.isVolatile)
if (!volatile && ctx.options.flag(CompilationFlag.UselessCodeWarning)) {
ctx.log.warn("Pointless expression.", stmt.position)
}
case ExpressionStatement(expr@FunctionCallExpression(f, List(_: LiteralExpression))) if hiddenEffectFreeFunctions(f) =>
if (ctx.options.flag(CompilationFlag.UselessCodeWarning)) {
ctx.log.warn("Pointless expression.", stmt.position)
}
case ExpressionStatement(VariableExpression(v)) =>
val volatile = ctx.env.maybeGet[ThingInMemory](v).fold(false)(_.isVolatile)
if (!volatile) ctx.log.warn("Pointless expression.", stmt.position)
case ExpressionStatement(LiteralExpression(_, _)) =>
ctx.log.warn("Pointless expression.", stmt.position)
if (!volatile && ctx.options.flag(CompilationFlag.UselessCodeWarning)) {
ctx.log.warn("Pointless expression.", stmt.position)
}
case ExpressionStatement(_: LiteralExpression) =>
if (ctx.options.flag(CompilationFlag.UselessCodeWarning)) {
ctx.log.warn("Pointless expression.", stmt.position)
}
case _ =>
}
stmt match {
@ -253,11 +271,13 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
}
}
private def checkIfNullTerminated(stmt: ExecutableStatement, param: Expression): Unit = {
private def checkIfNullTerminated(ctx: CompilationContext, stmt: ExecutableStatement, param: Expression): Unit = {
if (!ctx.options.flag(CompilationFlag.BuggyCodeWarning)) return
val TERMINATOR = ctx.options.platform.defaultCodec.stringTerminator.head
param match {
case TextLiteralExpression(ch) =>
ch.last match {
case LiteralExpression(0, _) => //ok
case LiteralExpression(TERMINATOR, _) => //ok
case _ => ctx.log.warn("Passing a non-null-terminated string to a function that expects a null-terminated string.", stmt.position)
}
case _ =>
@ -327,17 +347,17 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
// generic warnings:
expr match {
case FunctionCallExpression("*" | "*=", params) =>
if (params.exists {
if (ctx.options.flag(CompilationFlag.UselessCodeWarning) && params.exists {
case LiteralExpression(0, _) => true
case _ => false
}) ctx.log.warn("Multiplication by zero.", params.head.position)
case FunctionCallExpression("/" | "/=" | "%%" | "%%=", params) =>
if (params.tail.exists {
if (ctx.options.flag(CompilationFlag.BuggyCodeWarning) && params.tail.exists {
case LiteralExpression(0, _) => true
case _ => false
}) ctx.log.warn("Division by zero.", params.head.position)
case FunctionCallExpression("<<" | ">>" | "<<'" | "<<=" | ">>=" | "<<'=" | ">>>>", List(lhs@_, LiteralExpression(0, _))) =>
ctx.log.warn("Shift by zero.", lhs.position)
if (ctx.options.flag(CompilationFlag.UselessCodeWarning)) ctx.log.warn("Shift by zero.", lhs.position)
case _ =>
}
expr match {

View File

@ -1,5 +1,6 @@
package millfork.compiler.m6809
import millfork.CompilationFlag
import millfork.assembly.m6809.{DAccumulatorIndexed, Immediate, Indexed, InherentB, MLine, MLine0, MOpcode, RegisterSet, TwoRegisters}
import millfork.compiler.{AbstractExpressionCompiler, BranchIfFalse, BranchIfTrue, BranchSpec, ComparisonType, CompilationContext, NoBranching}
import millfork.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SumExpression, VariableExpression}
@ -706,7 +707,9 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case IndexedExpression(_, GeneratedConstantExpression(_, _)) =>
case IndexedExpression(_, SumExpression(sumParams, false)) if isUpToOneVar(sumParams) =>
case _ =>
ctx.log.warn("A complex expression may be evaluated multiple times", e.position)
if (ctx.options.flag(CompilationFlag.BuggyCodeWarning)) {
ctx.log.warn("A complex expression may be evaluated multiple times", e.position)
}
}
}
val conjunction = params.init.zip(params.tail).map {

View File

@ -484,7 +484,7 @@ object BuiltIns {
}
val firstParamCompiled = MosExpressionCompiler.compile(ctx, lhs, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching)
val maybeConstant = env.eval(rhs)
maybeConstant match {
if (ctx.options.flag(CompilationFlag.UselessCodeWarning)) maybeConstant match {
case Some(NumericConstant(0, _)) =>
compType match {
case ComparisonType.LessUnsigned =>

View File

@ -1308,7 +1308,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
}
case None =>
assertAllArithmeticBytes("Nonet argument has to be a byte", ctx, params)
params.head match {
if (ctx.options.flag(CompilationFlag.BuggyCodeWarning)) params.head match {
case SumExpression(addends, _) =>
if (addends.exists(a => a._1)) {
ctx.log.warn("Nonet subtraction may not work as expected", expr.position)
@ -1734,7 +1734,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
if (nf.name == "main" && ctx.options.flag(CompilationFlag.SoftwareStack)) {
if (nf.stackVariablesSize != 0 || env.things.values.exists(_.isInstanceOf[StackVariable])) {
ctx.log.error("Calling the main function when using software stack is not allowed", expr.position)
} else {
} else if (ctx.options.flag(CompilationFlag.BuggyCodeWarning)) {
ctx.log.warn("Calling the main function when using software stack is not allowed", expr.position)
}
}
@ -1758,7 +1758,9 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
case Seq((MosRegister.A, pa), (_, pxy)) => pa ++ preserveRegisterIfNeeded(ctx, MosRegister.A, pxy)
case Seq((_, pxy), (MosRegister.A, pa)) => pa ++ preserveRegisterIfNeeded(ctx, MosRegister.A, pxy)
case other =>
ctx.log.warn("Unsupported register parameter combination: " + other.map(_._1.toString).mkString("(", ",", ")"), expr.position)
if (ctx.options.flag(CompilationFlag.BuggyCodeWarning)) {
ctx.log.warn("Unsupported register parameter combination: " + other.map(_._1.toString).mkString("(", ",", ")"), expr.position)
}
other.flatMap(_._2) // TODO : make sure all registers are passed in correctly
}
secondViaMemory ++ thirdViaRegisters :+ AssemblyLine.absoluteOrLongAbsolute(JSR, function, ctx.options)
@ -1811,7 +1813,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
case IndexedExpression(_, GeneratedConstantExpression(_, _)) =>
case IndexedExpression(_, SumExpression(ps, false)) if isUpToOneVar(ps) =>
case _ =>
ctx.log.warn("A complex expression may be evaluated multiple times", e.position)
if (ctx.options.flag(CompilationFlag.BuggyCodeWarning)) ctx.log.warn("A complex expression may be evaluated multiple times", e.position)
}
}
val conjunction = params.init.zip(params.tail).map {

View File

@ -202,7 +202,9 @@ object MosStatementCompiler extends AbstractStatementCompiler[AssemblyLine] {
case ExpressionStatement(e) =>
e match {
case VariableExpression(_) | LiteralExpression(_, _) | _:GeneratedConstantExpression =>
ctx.log.warn("Pointless expression statement", statement.position)
if (ctx.options.flag(CompilationFlag.UselessCodeWarning)) {
ctx.log.warn("Pointless expression statement", statement.position)
}
case _ =>
}
MosExpressionCompiler.compile(ctx, e, None, NoBranching) -> Nil
@ -217,19 +219,19 @@ object MosStatementCompiler extends AbstractStatementCompiler[AssemblyLine] {
stackPointerFixBeforeReturn(ctx) ++
List(AssemblyLine.discardAF(), AssemblyLine.discardXF(), AssemblyLine.discardYF()) ++ returnInstructions
case 1 =>
if (statement.position.isDefined){
if (statement.position.isDefined && ctx.options.flag(CompilationFlag.BuggyCodeWarning)){
ctx.log.warn("Returning without a value", statement.position)
}
stackPointerFixBeforeReturn(ctx) ++
List(AssemblyLine.discardXF(), AssemblyLine.discardYF()) ++ returnInstructions
case 2 =>
if (statement.position.isDefined){
if (statement.position.isDefined && ctx.options.flag(CompilationFlag.BuggyCodeWarning)){
ctx.log.warn("Returning without a value", statement.position)
}
stackPointerFixBeforeReturn(ctx) ++
List(AssemblyLine.discardYF()) ++ returnInstructions
case _ =>
if (statement.position.isDefined){
if (statement.position.isDefined && ctx.options.flag(CompilationFlag.BuggyCodeWarning)){
ctx.log.warn("Returning without a value", statement.position)
}
stackPointerFixBeforeReturn(ctx) ++

View File

@ -223,7 +223,9 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
xs => ldhl.copy(parameter = param + 2) :: addhlsp :: fixTsx(ctx, xs)
case (x@ZLine0(EX_SP, _, _)) :: xs =>
// EX_SP should be only generated by the optimizer
ctx.log.warn("Stray EX (SP) encountered, generated code might be invalid")
if (ctx.options.flag(CompilationFlag.BuggyCodeWarning)) {
ctx.log.warn("Stray EX (SP) encountered, generated code might be invalid")
}
x :: fixTsx(ctx, xs)
case x :: xs => x :: fixTsx(ctx, xs)
case Nil => Nil
@ -1288,7 +1290,9 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
case Seq((ZRegister.BC, pbc), (_, pxx)) => pbc ++ stashBCIfChanged(ctx, pxx)
case Seq((_, pxx), (ZRegister.BC, pbc)) => pbc ++ stashBCIfChanged(ctx, pxx)
case other =>
ctx.log.warn("Unsupported register parameter combination: " + other.map(_._1.toString).mkString("(", ",", ")"), expression.position)
if (ctx.options.flag(CompilationFlag.BuggyCodeWarning)) {
ctx.log.warn("Unsupported register parameter combination: " + other.map(_._1.toString).mkString("(", ",", ")"), expression.position)
}
other.flatMap(_._2) // TODO : make sure all registers are passed in correctly
}
viaMemory ++ viaRegisters :+ ZLine(CALL, NoRegisters, function.toAddress)
@ -2098,7 +2102,9 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
case IndexedExpression(_, GeneratedConstantExpression(_, _)) =>
case IndexedExpression(_, SumExpression(sumParams, false)) if isUpToOneVar(sumParams) =>
case _ =>
ctx.log.warn("A complex expression may be evaluated multiple times", e.position)
if (ctx.options.flag(CompilationFlag.BuggyCodeWarning)) {
ctx.log.warn("A complex expression may be evaluated multiple times", e.position)
}
}
}
val conjunction = params.init.zip(params.tail).map {

View File

@ -182,7 +182,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
)
} else Nil
case VariableAllocationMethod.Auto | VariableAllocationMethod.Register | VariableAllocationMethod.Static =>
if (m.alloc == VariableAllocationMethod.Register) {
if (m.alloc == VariableAllocationMethod.Register && options.flag(CompilationFlag.FallbackValueUseWarning)) {
log.warn(s"Failed to inline variable `${m.name}` into a register", None)
}
if (m.sizeInBytes == 0) Nil else {
@ -316,7 +316,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
} else {
t match {
case Alias(_, target, deprectated) =>
if (deprectated) {
if (deprectated && options.flag(CompilationFlag.DeprecationWarning)) {
log.warn(s"Alias `$name` is deprecated, use `$target` instead", position)
}
root.get[T](target)
@ -344,7 +344,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
val clazz = implicitly[Manifest[T]].runtimeClass
t match {
case Alias(_, target, deprectated) =>
if (deprectated) {
if (deprectated && options.flag(CompilationFlag.DeprecationWarning)) {
log.warn(s"Alias `$name` is deprecated, use `$target` instead")
}
root.maybeGet[T](target)
@ -1068,10 +1068,10 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
val name = stmt.name
val resultType = get[Type](stmt.resultType)
if (stmt.name == "main") {
if (stmt.resultType != "void") {
if (stmt.resultType != "void" && options.flag(CompilationFlag.UselessCodeWarning)) {
log.warn("`main` should return `void`.", stmt.position)
}
if (stmt.params.nonEmpty) {
if (stmt.params.nonEmpty && options.flag(CompilationFlag.BuggyCodeWarning)) {
log.warn("`main` shouldn't have parameters.", stmt.position)
}
}
@ -1186,7 +1186,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
val g = getAllSafeGotos(statements).toSet
val bad = g.&(env.knownLocalLabels.map(_._1)).--(l)
if (bad.nonEmpty) {
log.warn("Detected cross-loop gotos to labels " + bad.mkString(", "), position)
if (options.flag(CompilationFlag.BuggyCodeWarning)) log.warn("Detected cross-loop gotos to labels " + bad.mkString(", "), position)
}
}
def recurse(statements: Seq[Statement]):Unit = statements.foreach {
@ -1769,7 +1769,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
if (stmt.initialValue.isDefined && stmt.address.isDefined) {
if (options.platform.ramInitialValuesBank.isDefined) {
log.error(s"`$name` has both address and initial value, which is unsupported on this target", position)
} else {
} else if (options.flag(CompilationFlag.BuggyCodeWarning)) {
log.warn(s"`$name` has both address and initial value - this may not work as expected!", position)
}
}
@ -1792,7 +1792,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
else if (stmt.global) VariableAllocationMethod.Static
else if (stmt.register) VariableAllocationMethod.Register
else VariableAllocationMethod.Auto
if (stmt.volatile && !stmt.global) {
if (stmt.volatile && !stmt.global && options.flag(CompilationFlag.FallbackValueUseWarning)) {
log.warn(s"Volatile variable `$name` assumed to be static", position)
}
if (stmt.volatile && stmt.stack) {

View File

@ -98,7 +98,7 @@ abstract class AbstractSourceLoadingQueue[T](val initialFilenames: List[String],
val shortFileName = path.getFileName.toString
val PreprocessingResult(src, featureConstants, pragmas) = Preprocessor(options, shortFileName, Files.readAllLines(path, StandardCharsets.UTF_8).toIndexedSeq)
for (pragma <- pragmas) {
if (!supportedPragmas(pragma._1)) {
if (!supportedPragmas(pragma._1) && options.flag(CompilationFlag.BuggyCodeWarning)) {
options.log.warn(s"Unsupported pragma: #pragma ${pragma._1}", Some(Position(moduleName, pragma._2, 1, 0)))
}
}

View File

@ -3,7 +3,7 @@ package millfork.parser
import java.util.Locale
import fastparse.all._
import millfork.CompilationOptions
import millfork.{CompilationFlag, CompilationOptions}
import millfork.assembly.Elidability
import millfork.assembly.m6809.{AAccumulatorIndexed, Absolute, BAccumulatorIndexed, DAccumulatorIndexed, DirectPage, Immediate, Indexed, Inherent, InherentA, InherentB, LongRelative, MAddrMode, MLine, MOpcode, NonExistent, PostIncremented, PreDecremented, RegisterSet, Relative, TwoRegisters}
import millfork.env.{ByM6809Register, ParamPassingConvention}
@ -145,6 +145,7 @@ case class M6809Parser(filename: String,
override def validateAsmFunctionBody(p: Position, flags: Set[String], name: String, statements: Option[List[Statement]]): Unit = {
if (!options.flag(CompilationFlag.BuggyCodeWarning)) return
statements match {
case Some(Nil) => log.warn("Assembly function `$name` is empty, did you mean RTS, RTI, JMP, BRA or LBRA?", Some(p))
case Some(xs) =>

View File

@ -274,10 +274,10 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
} yield {
val fixedDirection = direction match {
case ForDirection.ParallelUntil =>
log.warn("`paralleluntil` is not allowed in array definitions, assuming `until`", Some(pos))
if (options.flag(CompilationFlag.FallbackValueUseWarning)) log.warn("`paralleluntil` is not allowed in array definitions, assuming `until`", Some(pos))
ForDirection.Until
case ForDirection.ParallelTo =>
log.warn("`parallelto` is not allowed in array definitions, assuming `to`", Some(pos))
if (options.flag(CompilationFlag.FallbackValueUseWarning)) log.warn("`parallelto` is not allowed in array definitions, assuming `to`", Some(pos))
ForDirection.To
case x => x
}

View File

@ -4,7 +4,7 @@ import fastparse.all._
import millfork.assembly.mos.{AddrMode, AssemblyLine, Opcode, OpcodeClasses}
import millfork.env._
import millfork.node._
import millfork.CompilationOptions
import millfork.{CompilationFlag, CompilationOptions}
import millfork.assembly.Elidability
import millfork.output.{MemoryAlignment, WithinPageAlignment}
@ -137,6 +137,7 @@ case class MosParser(filename: String, input: String, currentDirectory: String,
} yield ParameterDeclaration(typ, appc).pos(p)
def validateAsmFunctionBody(p: Position, flags: Set[String], name: String, statements: Option[List[Statement]]): Unit = {
if (!options.flag(CompilationFlag.BuggyCodeWarning)) return
statements match {
case Some(Nil) => log.warn("Assembly function `$name` is empty, did you mean RTS, RTI or JMP", Some(p))
case Some(xs) =>

View File

@ -1,7 +1,7 @@
package millfork.parser
import fastparse.core.Parsed.{Failure, Success}
import millfork.{CompilationOptions, Platform, SeparatedList}
import millfork.{CompilationFlag, CompilationOptions, Platform, SeparatedList}
import millfork.error.{ConsoleLogger, Logger}
import millfork.node.Position
@ -79,7 +79,7 @@ object Preprocessor {
param.split("=", 2) match {
case Array(p) =>
featureConstants += param -> options.features.getOrElse(param, {
log.warn(s"Undefined parameter $param, assuming 0", pos)
if (options.flag(CompilationFlag.FallbackValueUseWarning)) log.warn(s"Undefined parameter $param, assuming 0", pos)
0L
})
case Array(p0,p1) => featureConstants += assertIdentifier(p0.trim(), pos) -> evalParam(p1, pos)

View File

@ -77,7 +77,9 @@ class UnicodeTextCodec(override val name: String, val charset: Charset, override
encode(log, position, List(c), options, lenient)
case None =>
if (lenient) {
log.warn(s"Cannot encode escape sequence {$escSeq} in encoding `$name`, skipped it", position)
if (options.flag(CompilationFlag.FallbackValueUseWarning)) {
log.warn(s"Cannot encode escape sequence {$escSeq} in encoding `$name`, skipped it", position)
}
} else {
log.error(s"Invalid escape sequence {$escSeq} for encoding `$name`", position)
}
@ -170,7 +172,9 @@ class TableTextCodec(override val name: String,
Some(List(index))
} else if (lenient) {
val alternative = TextCodec.lossyAlternatives.getOrElse(c, Nil).:+("?").find(alts => alts.forall(alt => encodeChar(log, position, alt, options, lenient = false).isDefined)).getOrElse("")
log.warn(s"Cannot encode ${format(c)} in encoding `$name`, replaced it with ${format(alternative)}", position)
if (options.flag(CompilationFlag.FallbackValueUseWarning)) {
log.warn(s"Cannot encode ${format(c)} in encoding `$name`, replaced it with ${format(alternative)}", position)
}
Some(alternative.toList.flatMap(encodeChar(log, position, _, options, lenient = false).get))
} else {
None
@ -228,7 +232,9 @@ class TableTextCodec(override val name: String,
}
escapeSequences.getOrElse(escSeq, {
if (lenient) {
log.warn(s"Cannot encode escape sequence {$escSeq} in encoding `$name`, skipped it", position)
if (options.flag(CompilationFlag.FallbackValueUseWarning)) {
log.warn(s"Cannot encode escape sequence {$escSeq} in encoding `$name`, skipped it", position)
}
} else {
log.error(s"Invalid escape sequence {$escSeq} for encoding `$name`", position)
}

View File

@ -663,6 +663,7 @@ case class Z80Parser(filename: String,
override val asmStatement: P[ExecutableStatement] = (position("assembly statement") ~ P(asmLabel | asmMacro | arrayContentsForAsm | asmInstruction)).map { case (p, s) => s.pos(p) } // TODO: macros
override def validateAsmFunctionBody(p: Position, flags: Set[String], name: String, statements: Option[List[Statement]]): Unit = {
if (!options.flag(CompilationFlag.BuggyCodeWarning)) return
statements match {
case Some(Nil) => log.warn("Assembly function `$name` is empty, did you mean RET, RETI, RETN or JP", Some(p))
case Some(xs) =>