mirror of
https://github.com/irmen/prog8.git
synced 2025-06-13 20:23:46 +00:00
Compare commits
1 Commits
structs
...
long-const
Author | SHA1 | Date | |
---|---|---|---|
7b2da74233 |
@ -69,6 +69,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
"prog8_lib_stringcompare" -> funcStringCompare(fcall, resultRegister)
|
||||
"prog8_lib_square_byte" -> funcSquare(fcall, BaseDataType.UBYTE, resultRegister)
|
||||
"prog8_lib_square_word" -> funcSquare(fcall, BaseDataType.UWORD, resultRegister)
|
||||
"len" -> throw AssemblyError("len() should have been replaced by the actual constant number")
|
||||
else -> throw AssemblyError("missing asmgen for builtin func ${fcall.name}")
|
||||
}
|
||||
|
||||
|
@ -35,14 +35,6 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
|
||||
|
||||
override fun after(numLiteral: NumericLiteral, parent: Node): Iterable<IAstModification> {
|
||||
|
||||
if(numLiteral.type==BaseDataType.LONG) {
|
||||
// see if LONG values may be reduced to something smaller
|
||||
val smaller = NumericLiteral.optimalInteger(numLiteral.number.toInt(), numLiteral.position)
|
||||
if(smaller.type!=BaseDataType.LONG) {
|
||||
return listOf(IAstModification.ReplaceNode(numLiteral, smaller, parent))
|
||||
}
|
||||
}
|
||||
|
||||
if(parent is Assignment) {
|
||||
val iDt = parent.target.inferType(program)
|
||||
if(iDt.isKnown && !iDt.isBool && !(iDt issimpletype numLiteral.type)) {
|
||||
|
@ -314,13 +314,14 @@ internal class ConstantIdentifierReplacer(
|
||||
return noModifications
|
||||
|
||||
try {
|
||||
val cval = identifier.constValue(program) ?: return noModifications
|
||||
val cvalue = identifier.constValue(program) ?: return noModifications
|
||||
val arrayIdx = identifier.parent as? ArrayIndexedExpression
|
||||
if(arrayIdx!=null && cval.type.isNumeric) {
|
||||
if(arrayIdx!=null && cvalue.type.isNumeric) {
|
||||
// special case when the identifier is used as a pointer var
|
||||
// var = constpointer[x] --> var = @(constvalue+x) [directmemoryread]
|
||||
// constpointer[x] = var -> @(constvalue+x) [directmemorywrite] = var
|
||||
val add = BinaryExpression(NumericLiteral(cval.type, cval.number, identifier.position), "+", arrayIdx.indexer.indexExpr, identifier.position)
|
||||
val dt = if(cvalue.type == BaseDataType.LONG) NumericLiteral.optimalInteger(cvalue.number.toInt(), cvalue.position).type else cvalue.type
|
||||
val add = BinaryExpression(NumericLiteral(dt, cvalue.number, identifier.position), "+", arrayIdx.indexer.indexExpr, identifier.position)
|
||||
return if(arrayIdx.parent is AssignTarget) {
|
||||
val memwrite = DirectMemoryWrite(add, identifier.position)
|
||||
val assignTarget = AssignTarget(null, null, memwrite, null, false, identifier.position)
|
||||
@ -331,18 +332,19 @@ internal class ConstantIdentifierReplacer(
|
||||
}
|
||||
}
|
||||
when {
|
||||
cval.type.isNumericOrBool -> {
|
||||
cvalue.type.isNumericOrBool -> {
|
||||
if(parent is AddressOf)
|
||||
return noModifications // cannot replace the identifier INSIDE the addr-of here, let's do it later.
|
||||
val dt = if(cvalue.type == BaseDataType.LONG) NumericLiteral.optimalInteger(cvalue.number.toInt(), cvalue.position).type else cvalue.type
|
||||
return listOf(
|
||||
IAstModification.ReplaceNode(
|
||||
identifier,
|
||||
NumericLiteral(cval.type, cval.number, identifier.position),
|
||||
NumericLiteral(dt, cvalue.number, identifier.position),
|
||||
identifier.parent
|
||||
)
|
||||
)
|
||||
}
|
||||
cval.type.isPassByRef -> throw InternalCompilerException("pass-by-reference type should not be considered a constant")
|
||||
cvalue.type.isPassByRef -> throw InternalCompilerException("pass-by-reference type should not be considered a constant")
|
||||
else -> return noModifications
|
||||
}
|
||||
} catch (x: UndefinedSymbolError) {
|
||||
@ -452,15 +454,20 @@ internal class ConstantIdentifierReplacer(
|
||||
if(declArraySize!=null && declArraySize!=rangeExpr.size())
|
||||
errors.err("range expression size (${rangeExpr.size()}) doesn't match declared array size ($declArraySize)", decl.value?.position!!)
|
||||
if(constRange!=null) {
|
||||
val rangeType = rangeExpr.inferType(program).getOr(DataType.UBYTE)
|
||||
return if(rangeType.isByte) {
|
||||
val rangeType2 = rangeExpr.inferType(program).getOr(DataType.UBYTE)
|
||||
return if(rangeType2.isByte) {
|
||||
ArrayLiteral(InferredTypes.InferredType.known(decl.datatype),
|
||||
constRange.map { NumericLiteral(rangeType.base, it.toDouble(), decl.value!!.position) }.toTypedArray(),
|
||||
constRange.map { NumericLiteral(rangeType2.base, it.toDouble(), decl.value!!.position) }.toTypedArray(),
|
||||
position = decl.value!!.position)
|
||||
} else {
|
||||
require(rangeType.sub!=null)
|
||||
require(rangeType2.sub!=null)
|
||||
val subDt = if(rangeType2.sub == BaseDataType.LONG) {
|
||||
val first = NumericLiteral.optimalInteger(constRange.first, Position.DUMMY).type
|
||||
val last = NumericLiteral.optimalInteger(constRange.last, Position.DUMMY).type
|
||||
if(last.largerSizeThan(first)) last else first
|
||||
} else rangeType2.sub!!
|
||||
ArrayLiteral(InferredTypes.InferredType.known(decl.datatype),
|
||||
constRange.map { NumericLiteral(rangeType.sub!!, it.toDouble(), decl.value!!.position) }.toTypedArray(),
|
||||
constRange.map { NumericLiteral(subDt, it.toDouble(), decl.value!!.position) }.toTypedArray(),
|
||||
position = decl.value!!.position)
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
checkLongType(identifier)
|
||||
checkResidualLongType(identifier)
|
||||
val stmt = identifier.targetStatement(program)
|
||||
if(stmt==null)
|
||||
errors.undefined(identifier.nameInSource, identifier.position)
|
||||
@ -328,7 +328,7 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(numLiteral: NumericLiteral) {
|
||||
checkLongType(numLiteral)
|
||||
checkResidualLongType(numLiteral)
|
||||
}
|
||||
|
||||
private fun hasReturnOrExternalJumpOrRts(scope: IStatementContainer): Boolean {
|
||||
@ -709,7 +709,7 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(addressOf: AddressOf) {
|
||||
checkLongType(addressOf)
|
||||
checkResidualLongType(addressOf)
|
||||
val variable=addressOf.identifier.targetVarDecl()
|
||||
if (variable!=null) {
|
||||
if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null)
|
||||
@ -1164,7 +1164,7 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
checkLongType(expr)
|
||||
checkResidualLongType(expr)
|
||||
val dt = expr.expression.inferType(program).getOrUndef()
|
||||
if(!dt.isUndefined) {
|
||||
when (expr.operator) {
|
||||
@ -1221,7 +1221,7 @@ internal class AstChecker(private val program: Program,
|
||||
|
||||
override fun visit(expr: BinaryExpression) {
|
||||
super.visit(expr)
|
||||
checkLongType(expr)
|
||||
checkResidualLongType(expr)
|
||||
|
||||
val leftIDt = expr.left.inferType(program)
|
||||
val rightIDt = expr.right.inferType(program)
|
||||
@ -1333,7 +1333,7 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(typecast: TypecastExpression) {
|
||||
checkLongType(typecast)
|
||||
checkResidualLongType(typecast)
|
||||
if(typecast.type.isIterable)
|
||||
errors.err("cannot type cast to string or array type", typecast.position)
|
||||
|
||||
@ -1384,7 +1384,7 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(functionCallExpr: FunctionCallExpression) {
|
||||
checkLongType(functionCallExpr)
|
||||
checkResidualLongType(functionCallExpr)
|
||||
// this function call is (part of) an expression, which should be in a statement somewhere.
|
||||
val stmtOfExpression = findParentNode<Statement>(functionCallExpr)
|
||||
?: throw FatalAstException("cannot determine statement scope of function call expression at ${functionCallExpr.position}")
|
||||
@ -1601,7 +1601,7 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
args.forEach{
|
||||
checkLongType(it)
|
||||
checkResidualLongType(it)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1612,7 +1612,7 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
|
||||
checkLongType(arrayIndexedExpression)
|
||||
checkResidualLongType(arrayIndexedExpression)
|
||||
val target = arrayIndexedExpression.arrayvar.targetStatement(program)
|
||||
if(target is VarDecl) {
|
||||
if(!target.datatype.isIterable && !target.datatype.isUnsignedWord)
|
||||
@ -1779,12 +1779,15 @@ internal class AstChecker(private val program: Program,
|
||||
errors.err("%asm containing IR code cannot be translated to 6502 assembly", inlineAssembly.position)
|
||||
}
|
||||
|
||||
private fun checkLongType(expression: Expression) {
|
||||
private fun checkResidualLongType(expression: Expression) {
|
||||
if(expression.inferType(program) issimpletype BaseDataType.LONG) {
|
||||
if((expression.parent as? VarDecl)?.type!=VarDeclType.CONST) {
|
||||
if (expression.parent !is RepeatLoop) {
|
||||
if (errors.noErrorForLine(expression.position))
|
||||
errors.err("integer overflow", expression.position)
|
||||
val constvalue = expression.constValue(program)
|
||||
if(constvalue==null || constvalue.number>65535 || constvalue.number <= -32768) {
|
||||
if (expression.parent !is RepeatLoop) {
|
||||
if (errors.noErrorForLine(expression.position))
|
||||
errors.err("integer overflow", expression.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -186,6 +186,23 @@ class AstPreprocessor(val program: Program,
|
||||
return makeUnSplitArray(decl)
|
||||
}
|
||||
|
||||
if(decl.type == VarDeclType.CONST && decl.datatype.isInteger && !decl.datatype.isLong) {
|
||||
// All const vardecls are changed to LONG type, but ONLY if their scope is not an anonymous scope.
|
||||
// This is because elsewhere in this processor, variables from anonymous scopes are first moved
|
||||
// up to the subroutine scope, and this would otherwise interfere in the same modification iteration.
|
||||
if(parent !is AnonymousScope) {
|
||||
errors.info("byte or word const (deprecated) converted to long const", decl.position)
|
||||
val longdecl = decl.copy(DataType.forDt(BaseDataType.LONG))
|
||||
val declvalue = decl.value!!.constValue(program)
|
||||
if(declvalue!=null) {
|
||||
val longvalue = NumericLiteral(BaseDataType.LONG, declvalue.number, declvalue.position)
|
||||
longdecl.value = longvalue
|
||||
longvalue.linkParents(longdecl)
|
||||
}
|
||||
return listOf(IAstModification.ReplaceNode(decl, longdecl, parent))
|
||||
}
|
||||
}
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
|
@ -165,24 +165,32 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
}
|
||||
}
|
||||
|
||||
// if one of the operands is a long const, convert to a smaller type const if possible
|
||||
val constLeft = expr.left.constValue(program)
|
||||
val constRight = expr.right.constValue(program)
|
||||
if(constLeft?.type == BaseDataType.LONG) {
|
||||
val small1 = NumericLiteral.optimalInteger(constLeft.number.toInt(), constLeft.position)
|
||||
var small = NumericLiteral.optimalInteger(small1.type, rightDt.getOrUndef().base, small1.number.toInt(), small1.position)
|
||||
val (commonDt, toFix) = BinaryExpression.commonDatatype(DataType.forDt(small.type), rightDt.getOrUndef(), small, expr.right)
|
||||
if(toFix != null && toFix===small) {
|
||||
small = NumericLiteral(commonDt.base, small.number, small.position)
|
||||
}
|
||||
return listOf(IAstModification.ReplaceNode(expr.left, small, expr))
|
||||
}
|
||||
if(constRight?.type == BaseDataType.LONG) {
|
||||
val small1 = NumericLiteral.optimalInteger(constRight.number.toInt(), constRight.position)
|
||||
var small = NumericLiteral.optimalInteger(small1.type, leftDt.getOrUndef().base, small1.number.toInt(), small1.position)
|
||||
val (commonDt, toFix) = BinaryExpression.commonDatatype(DataType.forDt(small.type), leftDt.getOrUndef(), small, expr.left)
|
||||
if(toFix != null && toFix===small) {
|
||||
small = NumericLiteral(commonDt.base, small.number, small.position)
|
||||
}
|
||||
return listOf(IAstModification.ReplaceNode(expr.right, small, expr))
|
||||
}
|
||||
|
||||
if((expr.operator!="<<" && expr.operator!=">>") || !leftDt.isWords || !rightDt.isBytes) {
|
||||
// determine common datatype and add typecast as required to make left and right equal types
|
||||
val (commonDt, toFix) = BinaryExpression.commonDatatype(leftDt.getOrUndef(), rightDt.getOrUndef(), expr.left, expr.right)
|
||||
if(toFix!=null) {
|
||||
if(commonDt.isBool) {
|
||||
// don't automatically cast to bool
|
||||
errors.err("left and right operands aren't the same type: $leftDt vs $rightDt", expr.position)
|
||||
} else {
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
when {
|
||||
toFix===expr.left -> addTypecastOrCastedValueModification(modifications, expr.left, commonDt.base, expr)
|
||||
toFix===expr.right -> addTypecastOrCastedValueModification(modifications, expr.right, commonDt.base, expr)
|
||||
else -> throw FatalAstException("confused binary expression side")
|
||||
}
|
||||
return modifications
|
||||
}
|
||||
}
|
||||
val modifications = makeCommonDt(leftDt.getOrUndef(), rightDt.getOrUndef(), expr)
|
||||
if(modifications.isNotEmpty())
|
||||
return modifications
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,6 +208,26 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
return noModifications
|
||||
}
|
||||
|
||||
private fun makeCommonDt(leftDt: DataType, rightDt: DataType, expr: BinaryExpression): List<IAstModification> {
|
||||
// determine common datatype and add typecast as required to make left and right equal types
|
||||
val (commonDt, toFix) = BinaryExpression.commonDatatype(leftDt, rightDt, expr.left, expr.right)
|
||||
if(toFix!=null) {
|
||||
if(commonDt.isBool) {
|
||||
// don't automatically cast to bool
|
||||
errors.err("left and right operands aren't the same type: $leftDt vs $rightDt", expr.position)
|
||||
} else {
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
when {
|
||||
toFix===expr.left -> addTypecastOrCastedValueModification(modifications, expr.left, commonDt.base, expr)
|
||||
toFix===expr.right -> addTypecastOrCastedValueModification(modifications, expr.right, commonDt.base, expr)
|
||||
else -> throw FatalAstException("confused binary expression side")
|
||||
}
|
||||
return modifications
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
||||
// see if a typecast is needed to convert the value's type into the proper target type
|
||||
val valueItype = assignment.value.inferType(program)
|
||||
|
@ -53,8 +53,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
errors.err("value '${constValue.number}' out of range for ${decl.datatype}", constValue.position)
|
||||
} else {
|
||||
// don't make it signed if it was unsigned and vice versa
|
||||
if(valueDt.isSigned && decl.datatype.isUnsigned ||
|
||||
valueDt.isUnsigned && decl.datatype.isSigned) {
|
||||
if(!decl.datatype.isLong && (valueDt.isSigned && decl.datatype.isUnsigned || valueDt.isUnsigned && decl.datatype.isSigned)) {
|
||||
val constValue = decl.value!!.constValue(program)!!
|
||||
errors.err("value '${constValue.number}' out of range for ${decl.datatype}", constValue.position)
|
||||
} else {
|
||||
@ -63,8 +62,14 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
}
|
||||
}
|
||||
}
|
||||
VarDeclType.MEMORY -> if(!valueType.isWords && !valueType.isBytes)
|
||||
throw FatalAstException("value type for a memory var should be word or byte (address)")
|
||||
VarDeclType.MEMORY -> {
|
||||
if(!valueType.isWords && !valueType.isBytes) {
|
||||
val constVal = decl.value?.constValue(program)
|
||||
if(constVal == null || constVal.number>65535) {
|
||||
throw FatalAstException("value type for a memory var should be word or byte (address) ${decl.position}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -131,9 +131,10 @@ class TestNumbers: FunSpec({
|
||||
val errors = ErrorReporterForTests(keepMessagesAfterReporting = true)
|
||||
compileText(C64Target(), true, src, outputDir, writeAssembly = false, errors=errors) shouldNotBe null
|
||||
errors.errors.size shouldBe 0
|
||||
errors.infos.size shouldBe 2
|
||||
errors.infos[0] shouldContain "converted to float"
|
||||
errors.infos[1] shouldContain "converted to float"
|
||||
val nondeprecations = errors.infos.filter { "deprecat" !in it }
|
||||
nondeprecations.size shouldBe 2
|
||||
nondeprecations[0] shouldContain "converted to float"
|
||||
nondeprecations[1] shouldContain "converted to float"
|
||||
}
|
||||
|
||||
test("implicit float conversion error if not enabled") {
|
||||
|
@ -31,9 +31,10 @@ class TestAstChecks: FunSpec({
|
||||
val errors = ErrorReporterForTests(keepMessagesAfterReporting = true)
|
||||
compileText(C64Target(), true, text, outputDir, writeAssembly = true, errors=errors) shouldNotBe null
|
||||
errors.errors.size shouldBe 0
|
||||
errors.infos.size shouldBe 2
|
||||
errors.infos[0] shouldContain "converted to float"
|
||||
errors.infos[1] shouldContain "converted to float"
|
||||
val nondeprecations = errors.infos.filter { "deprecat" !in it }
|
||||
nondeprecations.size shouldBe 2
|
||||
nondeprecations[0] shouldContain "converted to float"
|
||||
nondeprecations[1] shouldContain "converted to float"
|
||||
}
|
||||
|
||||
test("can't assign label or subroutine without using address-of") {
|
||||
|
@ -2,6 +2,7 @@ package prog8tests.ast
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.engine.spec.tempdir
|
||||
import io.kotest.matchers.comparables.shouldBeGreaterThanOrEqualTo
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
@ -17,13 +18,14 @@ import prog8.code.core.BaseDataType
|
||||
import prog8.code.core.Position
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.Cx16Target
|
||||
import prog8.code.target.VMTarget
|
||||
import prog8tests.helpers.ErrorReporterForTests
|
||||
import prog8tests.helpers.compileText
|
||||
|
||||
class TestConst: FunSpec({
|
||||
|
||||
val outputDir = tempdir().toPath()
|
||||
|
||||
|
||||
test("const folding multiple scenarios +/-") {
|
||||
val source = """
|
||||
main {
|
||||
@ -327,7 +329,7 @@ main {
|
||||
assignAddr2.operator shouldBe "+"
|
||||
}
|
||||
|
||||
test("out of range const byte and word give correct error") {
|
||||
test("deprecated typed consts get converted with message") {
|
||||
var src="""
|
||||
main {
|
||||
sub start() {
|
||||
@ -335,16 +337,25 @@ main {
|
||||
const word MIN_WORD = -32769
|
||||
const byte MAX_BYTE = 128
|
||||
const word MAX_WORD = 32768
|
||||
const long MAX_LONG = 999999999
|
||||
}
|
||||
}"""
|
||||
|
||||
val errors = ErrorReporterForTests()
|
||||
compileText(C64Target(), true, src, outputDir, writeAssembly = false, errors=errors) shouldBe null
|
||||
errors.errors.size shouldBe 4
|
||||
errors.errors[0] shouldContain "out of range"
|
||||
errors.errors[1] shouldContain "out of range"
|
||||
errors.errors[2] shouldContain "out of range"
|
||||
errors.errors[3] shouldContain "out of range"
|
||||
val errors = ErrorReporterForTests(keepMessagesAfterReporting = true)
|
||||
val result = compileText(VMTarget(), true, src, outputDir, writeAssembly = false, errors=errors)!!
|
||||
val st = result.compilerAst.entrypoint.statements
|
||||
st.size shouldBe 5
|
||||
(st[0] as VarDecl).datatype.isLong shouldBe true
|
||||
(st[1] as VarDecl).datatype.isLong shouldBe true
|
||||
(st[2] as VarDecl).datatype.isLong shouldBe true
|
||||
(st[3] as VarDecl).datatype.isLong shouldBe true
|
||||
(st[4] as VarDecl).datatype.isLong shouldBe true
|
||||
errors.errors.size shouldBe 0
|
||||
errors.infos.size shouldBeGreaterThanOrEqualTo 4
|
||||
errors.infos[0] shouldContain "converted to long"
|
||||
errors.infos[1] shouldContain "converted to long"
|
||||
errors.infos[2] shouldContain "converted to long"
|
||||
errors.infos[3] shouldContain "converted to long"
|
||||
}
|
||||
|
||||
test("out of range var byte and word give correct error") {
|
||||
@ -466,4 +477,19 @@ main {
|
||||
compileText(C64Target(), false, src, outputDir, writeAssembly = false) shouldNotBe null
|
||||
|
||||
}
|
||||
|
||||
test("const in scope ok") {
|
||||
val src="""
|
||||
main {
|
||||
sub start() {
|
||||
repeat {
|
||||
const ubyte MAX_WORDS = 8
|
||||
|
||||
cx16.r0L = MAX_WORDS
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
compileText(C64Target(), true, src, outputDir, writeAssembly = false) shouldNotBe null
|
||||
}
|
||||
})
|
||||
|
@ -403,7 +403,8 @@ main {
|
||||
val errors = ErrorReporterForTests(keepMessagesAfterReporting = true)
|
||||
val result = compileText(C64Target(), optimize=false, src, outputDir, writeAssembly=false, errors=errors)!!
|
||||
errors.warnings.size shouldBe 6
|
||||
errors.infos.size shouldBe 0
|
||||
val nondeprecations = errors.infos.filter { "deprecat" !in it }
|
||||
nondeprecations.size shouldBe 0
|
||||
errors.warnings.all { "dirty variable" in it } shouldBe true
|
||||
val start = result.compilerAst.entrypoint
|
||||
val st = start.statements
|
||||
|
@ -167,7 +167,7 @@ class BinaryExpression(
|
||||
when {
|
||||
node===left -> left = replacement
|
||||
node===right -> right = replacement
|
||||
else -> throw FatalAstException("invalid replace, no child $node")
|
||||
else -> throw FatalAstException("invalid replace in $this, no child $node")
|
||||
}
|
||||
replacement.parent = this
|
||||
}
|
||||
@ -434,7 +434,7 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI
|
||||
arrayIndex = replacement
|
||||
replacement.parent = this
|
||||
} else {
|
||||
throw FatalAstException("invalid replace, no child node $node")
|
||||
throw FatalAstException("invalid replace in $this, no child node $node")
|
||||
}
|
||||
}
|
||||
|
||||
@ -453,8 +453,9 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI
|
||||
if (index != null) {
|
||||
address += when {
|
||||
target.datatype.isUnsignedWord -> index
|
||||
target.datatype.isLong -> index
|
||||
target.datatype.isArray -> program.memsizer.memorySize(targetVar.datatype, index)
|
||||
else -> throw FatalAstException("need array or uword ptr")
|
||||
else -> throw FatalAstException("need array or uword ptr, got ${target.datatype}")
|
||||
}
|
||||
} else
|
||||
return null
|
||||
@ -588,6 +589,7 @@ class NumericLiteral(val type: BaseDataType, // only numerical types allowed
|
||||
BaseDataType.BOOL -> {}
|
||||
BaseDataType.UBYTE -> largestOrig = BaseDataType.BYTE
|
||||
BaseDataType.UWORD -> largestOrig = BaseDataType.WORD
|
||||
BaseDataType.LONG -> largestOrig = BaseDataType.LONG
|
||||
else -> throw FatalAstException("invalid dt")
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ object InferredTypes {
|
||||
val isBool = datatype?.isBool==true
|
||||
val isBytes = datatype?.isByte==true
|
||||
val isWords = datatype?.isWord==true
|
||||
val isLong = datatype?.isLong==true
|
||||
val isInteger = datatype?.isInteger==true
|
||||
val isNumeric = datatype?.isNumeric==true
|
||||
val isNumericOrBool = datatype?.isNumericOrBool==true
|
||||
|
@ -1,6 +1,13 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- swirl example (and rockrunner) is broken with long const now (code is missing?)
|
||||
|
||||
- const values should always either be of type long or float, this is how they were usually treated in const expression evaluation already anyway
|
||||
TODO: add new syntax where const declarations don't need the type anymore (and it's always set to long in the parser)
|
||||
BUT!!! how to deal with variables turned into constants? Can't be LONG constants, it will fuck up the type restriction system (types shouldn't grow)
|
||||
|
||||
|
||||
STRUCTS: are being developed in their own separate branch for now, called "structs".
|
||||
Idea is to make it feature complete in the IR/Virtual target, then merge it to master?, and then start building the 6502 code generation for it.
|
||||
|
||||
@ -17,7 +24,13 @@ Future Things and Ideas
|
||||
- Kotlin: can we use inline value classes in certain spots?
|
||||
- add float support to the configurable compiler targets
|
||||
- Improve the SublimeText syntax file for prog8, you can also install this for 'bat': https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions
|
||||
- Change scoping rules for qualified symbols so that they don't always start from the root but behave like other programming languages (look in local scope first), maybe only when qualified symbol starts with '.' such as: .local.value = 33
|
||||
- [problematic due to using 64tass:] better support for building library programs, where unused .proc are NOT deleted from the assembly.
|
||||
Perhaps replace all uses of .proc/.pend/.endproc by .block/.bend will fix that with a compiler flag?
|
||||
But all library code written in asm uses .proc already..... (textual search/replace when writing the actual asm?)
|
||||
Maybe propose a patch to 64tass itself that will treat .proc as .block ?
|
||||
Once new codegen is written that is based on the IR, this point is mostly moot anyway as that will have its own dead code removal on the IR level.
|
||||
|
||||
- Change scoping rules for qualified symbols so that they don't always start from the root but behave like other programming languages (look in local scope first)
|
||||
- something to reduce the need to use fully qualified names all the time. 'with' ? Or 'using <prefix>'?
|
||||
- Improve register load order in subroutine call args assignments:
|
||||
in certain situations (need examples!), the "wrong" order of evaluation of function call arguments is done which results
|
||||
@ -25,11 +38,10 @@ Future Things and Ideas
|
||||
Maybe this routine can be made more intelligent. See usesOtherRegistersWhileEvaluating() and argumentsViaRegisters().
|
||||
- Does it make codegen easier if everything is an expression? Start with the PtProgram ast classes, change statements to expressions that have (new) VOID data type
|
||||
- Can we support signed % (remainder) somehow?
|
||||
- Multidimensional arrays and chained indexing, purely as syntactic sugar over regular arrays. Probaby only useful if we have typed pointers. (addressed in 'struct' branch)
|
||||
- Multidimensional arrays and chained indexing, purely as syntactic sugar over regular arrays. Probaby only useful if we have typed pointers.
|
||||
- make a form of "manual generics" possible like: varsub routine(T arg)->T where T is expanded to a specific type
|
||||
(this is already done hardcoded for several of the builtin functions)
|
||||
- [much work:] more support for (64tass) SEGMENTS in the prog8 syntax itself?
|
||||
- ability to use a sub instead of only a var for @bank ? what for though? dynamic bank/overlay loading?
|
||||
- [much work:] more support for (64tass) SEGMENTS ?
|
||||
- Zig-like try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for that) But the V flag is also set on certain normal instructions
|
||||
|
||||
|
||||
@ -66,6 +78,7 @@ Libraries
|
||||
- pet32 target: make syslib more complete (missing kernal routines)?
|
||||
- need help with: PET disk routines (OPEN, SETLFS etc are not exposed as kernal calls)
|
||||
- c128 target: make syslib more complete (missing kernal routines)?
|
||||
- VM: implement the last diskio support (file listings)
|
||||
|
||||
|
||||
Optimizations
|
||||
@ -73,7 +86,22 @@ Optimizations
|
||||
|
||||
- Compilation speed: try to join multiple modifications in 1 result in the AST processors instead of returning it straight away every time
|
||||
- Compare output of some Oscar64 samples to what prog8 does for the equivalent code (see https://github.com/drmortalwombat/OscarTutorials/tree/main and https://github.com/drmortalwombat/oscar64/tree/main/samples)
|
||||
- Multi-value returns of normal subroutines: Can FAC then be used for floats as well again? Those are now not supported for multi-value returns.
|
||||
- Optimize the IfExpression code generation to be more like regular if-else code. (both 6502 and IR) search for "TODO don't store condition as expression"
|
||||
- VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served?
|
||||
for instance, vars used inside loops first, then loopvars, then uwords used as pointers (or these first??), then the rest
|
||||
- various optimizers skip stuff if compTarget.name==VMTarget.NAME. Once 6502-codegen is done from IR code, those checks should probably be removed, or be made permanent
|
||||
|
||||
|
||||
STRUCTS?
|
||||
--------
|
||||
|
||||
- declare struct *type*, or directly declare the variable itself? Problem with the latter is: you cannot easily define multiple variables of the same struct type.
|
||||
- can contain only numeric types (byte,word,float) - no nested structs, no reference types (strings, arrays) inside structs
|
||||
- only as a reference type (uword pointer). This removes a lot of the problems related to introducing a variable length value type.
|
||||
- arrays of struct is just an array of uword pointers. Can even be @split?
|
||||
- need to introduce typed pointer datatype in prog8
|
||||
- STR remains the type for a string literal (so we can keep doing register-indexed addressing directly on it)
|
||||
- ARRAY remains the type for an array literal (so we can keep doing register-indexed addressing directly on it)
|
||||
- we probably need to have a STRBYREF and ARRAYBYREF if we deal with a pointer to a string / array (such as when passing it to a function)
|
||||
the subtype of those should include the declared element type and the declared length of the string / array
|
||||
|
806
examples/test.p8
806
examples/test.p8
@ -1,800 +1,26 @@
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
%option no_sysinit
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
txt.plot(0, 49)
|
||||
bytesoverflow()
|
||||
bytesoverflow_jump()
|
||||
bytesoverflow_jump_indirect()
|
||||
bytessmall()
|
||||
bytessmall_jump()
|
||||
bytessmall_jump_indirect()
|
||||
bytes99()
|
||||
bytes100()
|
||||
bytes101()
|
||||
words()
|
||||
zerobytes()
|
||||
zerowords()
|
||||
}
|
||||
const uword screenwidth = 80
|
||||
const ubyte ten = 10
|
||||
ubyte @shared vten = 10
|
||||
|
||||
sub zerobytes() {
|
||||
byte @shared sb = -100
|
||||
byte @shared p = 0
|
||||
const byte cb = -100
|
||||
|
||||
txt.print("\nsigned bytes with 0\n")
|
||||
txt.print("expected: ")
|
||||
txt.print_b(cb)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>0)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>=0)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<0)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<=0)
|
||||
sub start() {
|
||||
; TODO should print 3 , 3
|
||||
cx16.r0L = msb(vten * screenwidth) ; TODO in main , vten is casted to uword
|
||||
txt.print_ub(cx16.r0L)
|
||||
txt.nl()
|
||||
txt.print_ub(msb(vten * screenwidth)) ; TODO in main, vten is casted to uword
|
||||
txt.nl()
|
||||
|
||||
txt.print(" calc'd: ")
|
||||
txt.print_b(sb)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>0)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>=0)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<0)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<=0)
|
||||
txt.nl()
|
||||
; ok; prints 0, 0
|
||||
; cx16.r0L = msb(vten * 80)
|
||||
; txt.print_ub(cx16.r0L)
|
||||
; txt.nl()
|
||||
; txt.print_ub(msb(vten * 80))
|
||||
; txt.nl()
|
||||
|
||||
txt.print("calc'd 2: ")
|
||||
txt.print_b(sb)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>=p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<=p)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" if stmt: ")
|
||||
txt.print_b(sb)
|
||||
txt.spc()
|
||||
if sb>0 txt.print("true ") else txt.print("false ")
|
||||
if sb>=0 txt.print("true ") else txt.print("false ")
|
||||
if sb<0 txt.print("true ") else txt.print("false ")
|
||||
if sb<=0 txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
|
||||
txt.print(" ifstmt2: ")
|
||||
txt.print_b(sb)
|
||||
txt.spc()
|
||||
if sb>p txt.print("true ") else txt.print("false ")
|
||||
if sb>=p txt.print("true ") else txt.print("false ")
|
||||
if sb<p txt.print("true ") else txt.print("false ")
|
||||
if sb<=p txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub zerowords() {
|
||||
word @shared sbw = -30000
|
||||
word @shared pw = 0
|
||||
const word cbw = -30000
|
||||
|
||||
txt.print("\nsigned words\n")
|
||||
txt.print("expected: ")
|
||||
txt.print_w(cbw)
|
||||
txt.spc()
|
||||
txt.print_bool(cbw>0)
|
||||
txt.spc()
|
||||
txt.print_bool(cbw>=0)
|
||||
txt.spc()
|
||||
txt.print_bool(cbw<0)
|
||||
txt.spc()
|
||||
txt.print_bool(cbw<=0)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" calc'd: ")
|
||||
txt.print_w(sbw)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw>0)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw>=0)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw<0)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw<=0)
|
||||
txt.nl()
|
||||
|
||||
txt.print("calc'd 2: ")
|
||||
txt.print_w(sbw)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw>pw)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw>=pw)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw<pw)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw<=pw)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" if stmt: ")
|
||||
txt.print_w(sbw)
|
||||
txt.spc()
|
||||
if sbw>0 txt.print("true ") else txt.print("false ")
|
||||
if sbw>=0 txt.print("true ") else txt.print("false ")
|
||||
if sbw<0 txt.print("true ") else txt.print("false ")
|
||||
if sbw<=0 txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
|
||||
txt.print(" ifstmt2: ")
|
||||
txt.print_w(sbw)
|
||||
txt.spc()
|
||||
if sbw>pw txt.print("true ") else txt.print("false ")
|
||||
if sbw>=pw txt.print("true ") else txt.print("false ")
|
||||
if sbw<pw txt.print("true ") else txt.print("false ")
|
||||
if sbw<=pw txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub bytes99() {
|
||||
const byte cb = 99
|
||||
byte @shared sb = 99
|
||||
byte @shared p = 100
|
||||
|
||||
txt.print("\nsigned bytes, 99\n")
|
||||
txt.print("expected: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>=100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<=100)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" calc'd: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>=100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<=100)
|
||||
txt.nl()
|
||||
|
||||
txt.print("calc'd 2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>=p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<=p)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" if stmt: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
if sb>100 txt.print("true ") else txt.print("false ")
|
||||
if sb>=100 txt.print("true ") else txt.print("false ")
|
||||
if sb<100 txt.print("true ") else txt.print("false ")
|
||||
if sb<=100 txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
|
||||
txt.print(" ifstmt2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
if sb>p txt.print("true ") else txt.print("false ")
|
||||
if sb>=p txt.print("true ") else txt.print("false ")
|
||||
if sb<p txt.print("true ") else txt.print("false ")
|
||||
if sb<=p txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub bytes100() {
|
||||
const byte cb = 100
|
||||
byte @shared sb = 100
|
||||
byte @shared p = 100
|
||||
|
||||
txt.print("\nsigned bytes, 100\n")
|
||||
txt.print("expected: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>=100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<=100)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" calc'd: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>=100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<=100)
|
||||
txt.nl()
|
||||
|
||||
txt.print("calc'd 2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>=p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<=p)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" if stmt: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
if sb>100 txt.print("true ") else txt.print("false ")
|
||||
if sb>=100 txt.print("true ") else txt.print("false ")
|
||||
if sb<100 txt.print("true ") else txt.print("false ")
|
||||
if sb<=100 txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
|
||||
txt.print(" ifstmt2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
if sb>p txt.print("true ") else txt.print("false ")
|
||||
if sb>=p txt.print("true ") else txt.print("false ")
|
||||
if sb<p txt.print("true ") else txt.print("false ")
|
||||
if sb<=p txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub bytes101() {
|
||||
const byte cb = 101
|
||||
byte @shared sb = 101
|
||||
byte @shared p = 100
|
||||
|
||||
txt.print("\nsigned bytes, 101\n")
|
||||
txt.print("expected: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>=100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<=100)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" calc'd: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>=100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<=100)
|
||||
txt.nl()
|
||||
|
||||
txt.print("calc'd 2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>=p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<=p)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" if stmt: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
if sb>100 txt.print("true ") else txt.print("false ")
|
||||
if sb>=100 txt.print("true ") else txt.print("false ")
|
||||
if sb<100 txt.print("true ") else txt.print("false ")
|
||||
if sb<=100 txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
|
||||
txt.print(" ifstmt2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
if sb>p txt.print("true ") else txt.print("false ")
|
||||
if sb>=p txt.print("true ") else txt.print("false ")
|
||||
if sb<p txt.print("true ") else txt.print("false ")
|
||||
if sb<=p txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub bytesoverflow() {
|
||||
byte @shared sb = -100
|
||||
byte @shared p = 100
|
||||
const byte cb = -100
|
||||
|
||||
txt.print("\nsigned bytes, overflow\n")
|
||||
txt.print("expected: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>=100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<=100)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" calc'd: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>=100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<100)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<=100)
|
||||
txt.nl()
|
||||
|
||||
txt.print("calc'd 2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>=p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<=p)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" if stmt: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
if sb>100 txt.print("true ") else txt.print("false ")
|
||||
if sb>=100 txt.print("true ") else txt.print("false ")
|
||||
if sb<100 txt.print("true ") else txt.print("false ")
|
||||
if sb<=100 txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
|
||||
txt.print(" ifstmt2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
if sb>p txt.print("true ") else txt.print("false ")
|
||||
if sb>=p txt.print("true ") else txt.print("false ")
|
||||
if sb<p txt.print("true ") else txt.print("false ")
|
||||
if sb<=p txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub bytessmall() {
|
||||
byte @shared sb = -10
|
||||
byte @shared p = 10
|
||||
const byte cb = -10
|
||||
|
||||
txt.print("\nsigned bytes, small value\n")
|
||||
txt.print("expected: ")
|
||||
txt.print_b(10)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>10)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>=10)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<10)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<=10)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" calc'd: ")
|
||||
txt.print_b(10)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>10)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>=10)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<10)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<=10)
|
||||
txt.nl()
|
||||
|
||||
txt.print("calc'd 2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb>=p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<p)
|
||||
txt.spc()
|
||||
txt.print_bool(sb<=p)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" if stmt: ")
|
||||
txt.print_b(10)
|
||||
txt.spc()
|
||||
if sb>10 txt.print("true ") else txt.print("false ")
|
||||
if sb>=10 txt.print("true ") else txt.print("false ")
|
||||
if sb<10 txt.print("true ") else txt.print("false ")
|
||||
if sb<=10 txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
|
||||
txt.print(" ifstmt2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
if sb>p txt.print("true ") else txt.print("false ")
|
||||
if sb>=p txt.print("true ") else txt.print("false ")
|
||||
if sb<p txt.print("true ") else txt.print("false ")
|
||||
if sb<=p txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub bytesoverflow_jump() {
|
||||
byte @shared sb = -100
|
||||
byte @shared p = 100
|
||||
const byte cb = -100
|
||||
|
||||
txt.print("\nsigned bytes, overflow, jmp after if\n")
|
||||
txt.print("expected: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>=100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<=100)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" calc'd: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
if sb>100 goto jump1
|
||||
else { txt.print("false ") goto next1 }
|
||||
jump1:
|
||||
txt.print("true ")
|
||||
next1:
|
||||
if sb>=100 goto jump2
|
||||
else { txt.print("false ") goto next2 }
|
||||
jump2:
|
||||
txt.print("true ")
|
||||
next2:
|
||||
if sb<100 goto jump3
|
||||
else { txt.print("false ") goto next3 }
|
||||
jump3:
|
||||
txt.print("true ")
|
||||
next3:
|
||||
if sb<=100 goto jump4
|
||||
else { txt.print("false ") goto next4 }
|
||||
jump4:
|
||||
txt.print("true ")
|
||||
next4:
|
||||
txt.nl()
|
||||
|
||||
txt.print("calc'd 2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
if sb>p goto jump1b
|
||||
else { txt.print("false ") goto next1b }
|
||||
jump1b:
|
||||
txt.print("true ")
|
||||
next1b:
|
||||
if sb>=p goto jump2b
|
||||
else { txt.print("false ") goto next2b }
|
||||
jump2b:
|
||||
txt.print("true ")
|
||||
next2b:
|
||||
if sb<p goto jump3b
|
||||
else { txt.print("false ") goto next3b }
|
||||
jump3b:
|
||||
txt.print("true ")
|
||||
next3b:
|
||||
if sb<=p goto jump4b
|
||||
else { txt.print("false ") goto next4b }
|
||||
jump4b:
|
||||
txt.print("true ")
|
||||
next4b:
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub bytesoverflow_jump_indirect() {
|
||||
byte @shared sb = -100
|
||||
byte @shared p = 100
|
||||
const byte cb = -100
|
||||
|
||||
txt.print("\nsigned bytes, overflow, jmp indirect after if\n")
|
||||
txt.print("expected: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>=100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<100)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<=100)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" calc'd: ")
|
||||
txt.print_b(100)
|
||||
txt.spc()
|
||||
uword tgt = &jump1
|
||||
if sb>100 goto tgt
|
||||
else { txt.print("false ") goto next1 }
|
||||
jump1:
|
||||
txt.print("true ")
|
||||
next1:
|
||||
tgt = &jump2
|
||||
if sb>=100 goto tgt
|
||||
else { txt.print("false ") goto next2 }
|
||||
jump2:
|
||||
txt.print("true ")
|
||||
next2:
|
||||
tgt = &jump3
|
||||
if sb<100 goto tgt
|
||||
else { txt.print("false ") goto next3 }
|
||||
jump3:
|
||||
txt.print("true ")
|
||||
next3:
|
||||
tgt = &jump4
|
||||
if sb<=100 goto tgt
|
||||
else { txt.print("false ") goto next4 }
|
||||
jump4:
|
||||
txt.print("true ")
|
||||
next4:
|
||||
txt.nl()
|
||||
|
||||
txt.print("calc'd 2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
tgt = &jump1b
|
||||
if sb>p goto tgt
|
||||
else { txt.print("false ") goto next1b }
|
||||
jump1b:
|
||||
txt.print("true ")
|
||||
next1b:
|
||||
tgt = &jump2b
|
||||
if sb>=p goto tgt
|
||||
else { txt.print("false ") goto next2b }
|
||||
jump2b:
|
||||
txt.print("true ")
|
||||
next2b:
|
||||
tgt = &jump3b
|
||||
if sb<p goto tgt
|
||||
else { txt.print("false ") goto next3b }
|
||||
jump3b:
|
||||
txt.print("true ")
|
||||
next3b:
|
||||
tgt = &jump4b
|
||||
if sb<=p goto tgt
|
||||
else { txt.print("false ") goto next4b }
|
||||
jump4b:
|
||||
txt.print("true ")
|
||||
next4b:
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub bytessmall_jump() {
|
||||
byte @shared sb = -10
|
||||
byte @shared p = 10
|
||||
const byte cb = -10
|
||||
|
||||
txt.print("\nsigned bytes, small value, jmp after if\n")
|
||||
txt.print("expected: ")
|
||||
txt.print_b(10)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>10)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>=10)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<10)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<=10)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" calc'd: ")
|
||||
txt.print_b(10)
|
||||
txt.spc()
|
||||
if sb>10 goto jump1
|
||||
else { txt.print("false ") goto next1 }
|
||||
jump1:
|
||||
txt.print("true ")
|
||||
next1:
|
||||
if sb>=10 goto jump2
|
||||
else { txt.print("false ") goto next2 }
|
||||
jump2:
|
||||
txt.print("true ")
|
||||
next2:
|
||||
if sb<10 goto jump3
|
||||
else { txt.print("false ") goto next3 }
|
||||
jump3:
|
||||
txt.print("true ")
|
||||
next3:
|
||||
if sb<=10 goto jump4
|
||||
else { txt.print("false ") goto next4 }
|
||||
jump4:
|
||||
txt.print("true ")
|
||||
next4:
|
||||
txt.nl()
|
||||
|
||||
txt.print("calc'd 2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
if sb>p goto jump1b
|
||||
else { txt.print("false ") goto next1b }
|
||||
jump1b:
|
||||
txt.print("true ")
|
||||
next1b:
|
||||
if sb>=p goto jump2b
|
||||
else { txt.print("false ") goto next2b }
|
||||
jump2b:
|
||||
txt.print("true ")
|
||||
next2b:
|
||||
if sb<p goto jump3b
|
||||
else { txt.print("false ") goto next3b }
|
||||
jump3b:
|
||||
txt.print("true ")
|
||||
next3b:
|
||||
if sb<=p goto jump4b
|
||||
else { txt.print("false ") goto next4b }
|
||||
jump4b:
|
||||
txt.print("true ")
|
||||
next4b:
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub bytessmall_jump_indirect() {
|
||||
byte @shared sb = -10
|
||||
byte @shared p = 10
|
||||
const byte cb = -10
|
||||
|
||||
txt.print("\nsigned bytes, small value, jmp indirect after if\n")
|
||||
txt.print("expected: ")
|
||||
txt.print_b(10)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>10)
|
||||
txt.spc()
|
||||
txt.print_bool(cb>=10)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<10)
|
||||
txt.spc()
|
||||
txt.print_bool(cb<=10)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" calc'd: ")
|
||||
txt.print_b(10)
|
||||
txt.spc()
|
||||
uword tgt = &jump1
|
||||
if sb>10 goto tgt
|
||||
else { txt.print("false ") goto next1 }
|
||||
jump1:
|
||||
txt.print("true ")
|
||||
next1:
|
||||
tgt = &jump2
|
||||
if sb>=10 goto tgt
|
||||
else { txt.print("false ") goto next2 }
|
||||
jump2:
|
||||
txt.print("true ")
|
||||
next2:
|
||||
tgt = &jump3
|
||||
if sb<10 goto tgt
|
||||
else { txt.print("false ") goto next3 }
|
||||
jump3:
|
||||
txt.print("true ")
|
||||
next3:
|
||||
tgt = &jump4
|
||||
if sb<=10 goto tgt
|
||||
else { txt.print("false ") goto next4 }
|
||||
jump4:
|
||||
txt.print("true ")
|
||||
next4:
|
||||
txt.nl()
|
||||
|
||||
txt.print("calc'd 2: ")
|
||||
txt.print_b(p)
|
||||
txt.spc()
|
||||
tgt = &jump1b
|
||||
if sb>p goto tgt
|
||||
else { txt.print("false ") goto next1b }
|
||||
jump1b:
|
||||
txt.print("true ")
|
||||
next1b:
|
||||
tgt = &jump2b
|
||||
if sb>=p goto tgt
|
||||
else { txt.print("false ") goto next2b }
|
||||
jump2b:
|
||||
txt.print("true ")
|
||||
next2b:
|
||||
tgt = &jump3b
|
||||
if sb<p goto tgt
|
||||
else { txt.print("false ") goto next3b }
|
||||
jump3b:
|
||||
txt.print("true ")
|
||||
next3b:
|
||||
tgt = &jump4b
|
||||
if sb<=p goto tgt
|
||||
else { txt.print("false ") goto next4b }
|
||||
jump4b:
|
||||
txt.print("true ")
|
||||
next4b:
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub words() {
|
||||
word @shared sbw = -30000
|
||||
word @shared pw = 30000
|
||||
const word cbw = -30000
|
||||
|
||||
txt.print("\nsigned words\n")
|
||||
txt.print("expected: ")
|
||||
txt.print_w(cbw)
|
||||
txt.spc()
|
||||
txt.print_bool(cbw>30000)
|
||||
txt.spc()
|
||||
txt.print_bool(cbw>=30000)
|
||||
txt.spc()
|
||||
txt.print_bool(cbw<30000)
|
||||
txt.spc()
|
||||
txt.print_bool(cbw<=30000)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" calc'd: ")
|
||||
txt.print_w(sbw)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw>30000)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw>=30000)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw<30000)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw<=30000)
|
||||
txt.nl()
|
||||
|
||||
txt.print("calc'd 2: ")
|
||||
txt.print_w(sbw)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw>pw)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw>=pw)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw<pw)
|
||||
txt.spc()
|
||||
txt.print_bool(sbw<=pw)
|
||||
txt.nl()
|
||||
|
||||
txt.print(" if stmt: ")
|
||||
txt.print_w(sbw)
|
||||
txt.spc()
|
||||
if sbw>30000 txt.print("true ") else txt.print("false ")
|
||||
if sbw>=30000 txt.print("true ") else txt.print("false ")
|
||||
if sbw<30000 txt.print("true ") else txt.print("false ")
|
||||
if sbw<=30000 txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
|
||||
txt.print(" ifstmt2: ")
|
||||
txt.print_w(sbw)
|
||||
txt.spc()
|
||||
if sbw>pw txt.print("true ") else txt.print("false ")
|
||||
if sbw>=pw txt.print("true ") else txt.print("false ")
|
||||
if sbw<pw txt.print("true ") else txt.print("false ")
|
||||
if sbw<=pw txt.print("true ") else txt.print("false ")
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user