mirror of
https://github.com/irmen/prog8.git
synced 2025-11-03 04:17:16 +00:00
6502 statementreorderer: str -> ^^ubyte
This commit is contained in:
13
.idea/inspectionProfiles/Project_Default.xml
generated
13
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -542,9 +542,6 @@
|
||||
<inspection_tool class="HardcodedLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="HardwiredNamespacePrefix" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HashCodeUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="HelmChartMissingKeys" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="HelmChartUnknownKeys" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HelmChartUnknownValues" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="HibernateConfigDomFacetInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HibernateConfigDomInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="HibernateFindAnnotationInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
@@ -802,15 +799,6 @@
|
||||
<inspection_tool class="KeySetIterationMayUseEntrySet" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="KotlinBigDecimalEquals" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="KtorYamlConfig" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KubernetesDeprecatedKeys" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KubernetesDeprecatedResources" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KubernetesDuplicatedEnvVars" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="KubernetesMissingKeys" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="KubernetesNonEditableKeys" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KubernetesNonEditableResources" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KubernetesUnknownKeys" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="KubernetesUnknownResourcesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KubernetesUnknownValues" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="LabeledStatement" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="LambdaParameterHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
@@ -1161,7 +1149,6 @@
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ReturnOfInnerClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ReturnThis" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="RunBlockingInSuspendFunction" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="RuntimeExec" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="RuntimeExecWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SafeLock" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
|
||||
@@ -747,6 +747,7 @@ class AsmGen6502Internal (
|
||||
assignExpressionToRegister(value, RegisterOrPair.A)
|
||||
assignmentAsmGen.assignRegisterByte(target, CpuRegister.A, target.datatype.isSigned, false)
|
||||
}
|
||||
target.datatype.isPointer -> TODO("assign expression to pointer ${target.position}")
|
||||
target.datatype.isWord || target.datatype.isPassByRef -> {
|
||||
assignExpressionToRegister(value, RegisterOrPair.AY)
|
||||
translateNormalAssignment(
|
||||
@@ -1087,7 +1088,8 @@ $repeatLabel""")
|
||||
val returnRegs = sub.returnsWhatWhere()
|
||||
|
||||
if(returnvalue!=null) {
|
||||
if (sub.signature.returns.single().isNumericOrBool) {
|
||||
val returnDt = sub.signature.returns.single()
|
||||
if (returnDt.isNumericOrBool || returnDt.isPointer) {
|
||||
assignExpressionToRegister(returnvalue, returnRegs.single().first.registerOrPair!!)
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -45,7 +45,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
val rightDt = compareCond.right.type
|
||||
return when {
|
||||
rightDt.isByteOrBool -> translateIfByte(stmt, jumpAfterIf)
|
||||
rightDt.isWord -> translateIfWord(stmt, compareCond, jumpAfterIf)
|
||||
rightDt.isWord || rightDt.isPointer -> translateIfWord(stmt, compareCond, jumpAfterIf)
|
||||
rightDt.isFloat -> translateIfFloat(stmt, compareCond, jumpAfterIf)
|
||||
else -> throw AssemblyError("weird dt")
|
||||
}
|
||||
|
||||
@@ -446,32 +446,22 @@ internal class AssignmentAsmGen(
|
||||
private fun assignExpression(assign: AsmAssignment, scope: IPtSubroutine?) {
|
||||
when(val value = assign.source.expression!!) {
|
||||
is PtAddressOf -> {
|
||||
val identifier = value.identifier
|
||||
if (identifier != null) {
|
||||
if (value.identifier != null || value.isFromArrayElement) {
|
||||
val identifier = value.identifier!!
|
||||
val source = asmgen.symbolTable.lookup(identifier.name)
|
||||
require(source !is StConstant) { "addressOf of a constant should have been rewritten to a simple addition expression" }
|
||||
val arrayDt = identifier.type
|
||||
val sourceName =
|
||||
if (value.isMsbForSplitArray)
|
||||
asmgen.asmSymbolName(identifier) + "_msb"
|
||||
else if (arrayDt.isSplitWordArray)
|
||||
else if (identifier.type.isSplitWordArray)
|
||||
asmgen.asmSymbolName(identifier) + "_lsb" // the _lsb split array comes first in memory
|
||||
else
|
||||
asmgen.asmSymbolName(identifier)
|
||||
assignAddressOf(assign.target, sourceName, value.isMsbForSplitArray, arrayDt, value.arrayIndexExpr)
|
||||
assignAddressOf(assign.target, sourceName, value.isMsbForSplitArray, identifier.type, value.arrayIndexExpr)
|
||||
} else {
|
||||
val ptrderef = value.dereference
|
||||
if(ptrderef!=null) {
|
||||
val zpPtrVar = pointergen.deref(ptrderef)
|
||||
assignVariableWord(assign.target, zpPtrVar, DataType.UWORD)
|
||||
} else {
|
||||
val array = value.arrayIndexExpr
|
||||
if(array!=null) {
|
||||
TODO("assign &array indexed ${assign.position}")
|
||||
} else {
|
||||
throw AssemblyError("weird addressOf value ${value.position}")
|
||||
}
|
||||
}
|
||||
val ptrderef = value.dereference!!
|
||||
val zpPtrVar = pointergen.deref(ptrderef)
|
||||
assignVariableWord(assign.target, zpPtrVar, DataType.UWORD)
|
||||
}
|
||||
}
|
||||
is PtBool -> throw AssemblyError("source kind should have been literalboolean")
|
||||
@@ -2161,7 +2151,16 @@ $endLabel""")
|
||||
return
|
||||
}
|
||||
}
|
||||
is PtNumber, is PtBool -> throw AssemblyError("a cast of a literal value should have been const-folded away")
|
||||
is PtNumber -> {
|
||||
if(targetDt.isPointer) {
|
||||
// assign a number to a pointer type
|
||||
require(valueDt.isInteger)
|
||||
assignConstantWord(target, value.number.toInt())
|
||||
}
|
||||
else
|
||||
throw AssemblyError("literal value cast should have been const-folded away (target type=$targetDt)")
|
||||
}
|
||||
is PtBool -> throw AssemblyError("literal value cast should have been const-folded away (target type=$targetDt)")
|
||||
is PtArrayIndexer -> {
|
||||
if(targetDt.isByte && valueDt.isWord) {
|
||||
// just assign the lsb from the array value
|
||||
|
||||
@@ -123,6 +123,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
}
|
||||
target.datatype.isPointer ->
|
||||
ptrgen.inplaceModification(PtrTarget(target), operator, value)
|
||||
else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}")
|
||||
}
|
||||
}
|
||||
@@ -307,7 +309,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
target.datatype.isPointer -> ptrgen.inplaceModification(PtrTarget(target), operator, value)
|
||||
else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}")
|
||||
}
|
||||
}
|
||||
@@ -510,7 +512,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
pla ; restore array ptr lsb
|
||||
jsr floats.copy_float""")
|
||||
}
|
||||
|
||||
target.datatype.isPointer -> ptrgen.inplaceModification(PtrTarget(target), operator, value)
|
||||
else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,7 +615,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
it += IRInstruction(Opcode.AND, IRDataType.BYTE, reg1=actualResultReg2, immediate = 1)
|
||||
}
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
else -> throw AssemblyError("weird cast value type ${cast.position}")
|
||||
}
|
||||
}
|
||||
BaseDataType.UBYTE -> {
|
||||
@@ -631,7 +631,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
actualResultReg2 = codeGen.registers.next(IRDataType.BYTE)
|
||||
addInstr(result, IRInstruction(Opcode.FTOUB, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
else -> throw AssemblyError("weird cast value type ${cast.position}")
|
||||
}
|
||||
}
|
||||
BaseDataType.BYTE -> {
|
||||
@@ -647,7 +647,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
actualResultReg2 = codeGen.registers.next(IRDataType.BYTE)
|
||||
addInstr(result, IRInstruction(Opcode.FTOSB, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
else -> throw AssemblyError("weird cast value type ${cast.position}")
|
||||
}
|
||||
}
|
||||
BaseDataType.UWORD -> {
|
||||
@@ -672,7 +672,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
BaseDataType.POINTER -> {
|
||||
actualResultReg2 = tr.resultReg
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
else -> throw AssemblyError("weird cast value type ${cast.position}")
|
||||
}
|
||||
}
|
||||
BaseDataType.WORD -> {
|
||||
@@ -694,7 +694,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
actualResultReg2 = codeGen.registers.next(IRDataType.WORD)
|
||||
addInstr(result, IRInstruction(Opcode.FTOSW, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
else -> throw AssemblyError("weird cast value type ${cast.position}")
|
||||
}
|
||||
}
|
||||
BaseDataType.FLOAT -> {
|
||||
@@ -712,7 +712,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
BaseDataType.WORD -> {
|
||||
addInstr(result, IRInstruction(Opcode.FFROMSW, IRDataType.FLOAT, reg1=tr.resultReg, fpReg1 = actualResultFpReg2), null)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
else -> throw AssemblyError("weird cast value type ${cast.position}")
|
||||
}
|
||||
}
|
||||
BaseDataType.POINTER -> {
|
||||
@@ -723,7 +723,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
BaseDataType.ARRAY_POINTER -> {
|
||||
TODO("typecast to array of pointers $valueDt -> ${cast.type}")
|
||||
}
|
||||
else -> throw AssemblyError("weird cast type")
|
||||
else -> throw AssemblyError("weird cast value type ${cast.position}")
|
||||
}
|
||||
|
||||
return ExpressionCodeResult(result, irType(cast.type), actualResultReg2, actualResultFpReg2)
|
||||
|
||||
@@ -242,14 +242,16 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr
|
||||
}
|
||||
}
|
||||
if (rightVal?.number == 1.0) {
|
||||
if (rightDt != leftDt) {
|
||||
val right = NumericLiteral(leftDt.base, rightVal.number, rightVal.position)
|
||||
if (rightDt != leftDt && !(leftDt.isPointer && rightDt.isUnsignedWord)) {
|
||||
val dt = if(leftDt.isPointer) BaseDataType.UWORD else leftDt.base
|
||||
val right = NumericLiteral(dt, rightVal.number, rightVal.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr.right, right, expr))
|
||||
}
|
||||
}
|
||||
else if (rightVal?.number == 0.0) {
|
||||
if (rightDt != leftDt) {
|
||||
val right = NumericLiteral(leftDt.base, rightVal.number, rightVal.position)
|
||||
if (rightDt != leftDt && !(leftDt.isPointer && rightDt.isUnsignedWord)) {
|
||||
val dt = if(leftDt.isPointer) BaseDataType.UWORD else leftDt.base
|
||||
val right = NumericLiteral(dt, rightVal.number, rightVal.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr.right, right, expr))
|
||||
}
|
||||
}
|
||||
@@ -262,14 +264,16 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr
|
||||
}
|
||||
}
|
||||
if (rightVal?.number == 1.0) {
|
||||
if(rightDt!=leftDt) {
|
||||
val right = NumericLiteral(leftDt.base, rightVal.number, rightVal.position)
|
||||
if(rightDt!=leftDt && !(leftDt.isPointer && rightDt.isUnsignedWord)) {
|
||||
val dt = if(leftDt.isPointer) BaseDataType.UWORD else leftDt.base
|
||||
val right = NumericLiteral(dt, rightVal.number, rightVal.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr.right, right, expr))
|
||||
}
|
||||
}
|
||||
else if (rightVal?.number == 0.0) {
|
||||
if(rightDt!=leftDt) {
|
||||
val right = NumericLiteral(leftDt.base, rightVal.number, rightVal.position)
|
||||
if(rightDt!=leftDt && !(leftDt.isPointer && rightDt.isUnsignedWord)) {
|
||||
val dt = if(leftDt.isPointer) BaseDataType.UWORD else leftDt.base
|
||||
val right = NumericLiteral(dt, rightVal.number, rightVal.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr.right, right, expr))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ strings {
|
||||
repeat cx16.r2L {
|
||||
if startswith(cx16.r3, needle) {
|
||||
sys.set_carry()
|
||||
return cx16.r3-haystack as ubyte
|
||||
return cx16.r3-(haystack as uword) as ubyte
|
||||
}
|
||||
cx16.r3++
|
||||
}
|
||||
|
||||
@@ -181,8 +181,8 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||
val stMaker = SymbolTableMaker(intermediateAst, compilationOptions)
|
||||
val symbolTable = stMaker.make()
|
||||
|
||||
postprocessSimplifiedAst(intermediateAst, symbolTable, compilationOptions, args.errors)
|
||||
args.errors.report()
|
||||
postprocessSimplifiedAst(intermediateAst, symbolTable, compilationOptions, args.errors)
|
||||
args.errors.report()
|
||||
|
||||
if (compilationOptions.optimize) {
|
||||
optimizeSimplifiedAst(intermediateAst, compilationOptions, symbolTable, args.errors)
|
||||
|
||||
@@ -696,8 +696,10 @@ internal class AstChecker(private val program: Program,
|
||||
// unfortunately the AST regarding pointer dereferencing is a bit of a mess, and we cannot do precise type checking on elements inside such expressions yet.
|
||||
if(assignment.value.inferType(program).isUnknown) {
|
||||
val binexpr = assignment.value as? BinaryExpression
|
||||
if (binexpr?.operator != ".") {
|
||||
if(assignment.value !is PtrDereference && assignment.target.multi==null)
|
||||
if(assignment.target.multi==null) {
|
||||
if (binexpr != null && binexpr.operator != ".")
|
||||
errors.err("invalid assignment value", assignment.value.position)
|
||||
else
|
||||
errors.err("invalid assignment value", assignment.value.position)
|
||||
}
|
||||
}
|
||||
@@ -833,7 +835,8 @@ internal class AstChecker(private val program: Program,
|
||||
if(trueDt.isUnknown || falseDt.isUnknown) {
|
||||
errors.err("invalid value type(s)", ifExpr.position)
|
||||
} else if(trueDt!=falseDt) {
|
||||
errors.err("both values should be the same type", ifExpr.truevalue.position)
|
||||
// if (!(trueDt.isUnsignedWord && falseDt.isPointer || trueDt.isPointer && falseDt.isUnsignedWord))
|
||||
errors.err("both values in the if expression should be the same type", ifExpr.truevalue.position)
|
||||
}
|
||||
super.visit(ifExpr)
|
||||
}
|
||||
@@ -1510,6 +1513,10 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
}
|
||||
}
|
||||
"-" -> {
|
||||
if(leftDt.isNumeric && rightDt.isPointer)
|
||||
errors.err("unclear pointer arithmetic in expression, perhaps you meant to just subtract addresses? Cast pointer to uword in that case.", expr.right.position)
|
||||
}
|
||||
}
|
||||
|
||||
if(!leftDt.isNumeric && !leftDt.isString && !leftDt.isBool && !leftDt.isPointer)
|
||||
@@ -2472,6 +2479,9 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
else if(targetDatatype.isString && sourceDatatype.isUnsignedWord)
|
||||
errors.err("can't assign uword to str. If the source is a string pointer and you actually want to overwrite the target string, use an explicit strings.copy(src,tgt) instead.", position)
|
||||
else if(targetDatatype.isString && sourceDatatype == DataType.pointer(BaseDataType.UBYTE)) {
|
||||
// this is allowed: assigning ^^ubyte to a str (will use stringcopy)
|
||||
}
|
||||
else if(targetDatatype.isStructInstance) {
|
||||
if(sourceDatatype.isStructInstance && sourceDatatype != targetDatatype)
|
||||
errors.err("value type $sourceDatatype doesn't match target type $targetDatatype", position)
|
||||
|
||||
@@ -220,9 +220,9 @@ internal class StatementReorderer(
|
||||
subs.map { IAstModification.InsertLast(it, subroutine) }
|
||||
}
|
||||
|
||||
// change 'str' and 'ubyte[]' parameters or return types into ^^ubyte (TODO also for 6502 target, that is still uword for now)
|
||||
// change 'str' and 'ubyte[]' parameters or return types into ^^ubyte
|
||||
val stringParams = subroutine.parameters.filter { it.type.isString || it.type.isUnsignedByteArray }
|
||||
val replacementForStrDt = if(options.compTarget.cpu!=CpuType.VIRTUAL) DataType.UWORD else DataType.pointer(BaseDataType.UBYTE) // TODO fix this once 6502 has pointers too
|
||||
val replacementForStrDt = DataType.pointer(BaseDataType.UBYTE)
|
||||
val parameterChanges = stringParams.map {
|
||||
val uwordParam = SubroutineParameter(it.name, replacementForStrDt, it.zp, it.registerOrPair, it.position)
|
||||
IAstModification.ReplaceNode(it, uwordParam, subroutine)
|
||||
@@ -240,9 +240,9 @@ internal class StatementReorderer(
|
||||
subroutine.statements
|
||||
.asSequence()
|
||||
.filterIsInstance<VarDecl>()
|
||||
.filter { it.origin==VarDeclOrigin.SUBROUTINEPARAM && it.name in stringParamsByNames }
|
||||
.filter { it.origin==VarDeclOrigin.SUBROUTINEPARAM && it.name in stringParamsByNames && it.datatype!=DataType.pointer(BaseDataType.UBYTE) }
|
||||
.map {
|
||||
val newvar = VarDecl(it.type, it.origin, DataType.UWORD,
|
||||
val newvar = VarDecl(it.type, it.origin, DataType.pointer(BaseDataType.UBYTE),
|
||||
it.zeropage,
|
||||
it.splitwordarray,
|
||||
null,
|
||||
@@ -299,9 +299,11 @@ internal class StatementReorderer(
|
||||
}
|
||||
|
||||
if(!assignment.isAugmentable) {
|
||||
if (valueType issimpletype BaseDataType.STR && targetType issimpletype BaseDataType.STR) {
|
||||
// replace string assignment by a call to stringcopy
|
||||
return copyStringValue(assignment)
|
||||
if (targetType issimpletype BaseDataType.STR) {
|
||||
if (valueType issimpletype BaseDataType.STR || valueType.getOrUndef() == DataType.pointer(BaseDataType.UBYTE)) {
|
||||
// replace string assignment by a call to stringcopy
|
||||
return copyStringValue(assignment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -180,6 +180,12 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
}
|
||||
}
|
||||
|
||||
if(typecast.type.isWord && typecast.expression.inferType(program).isPointer) {
|
||||
// pointers can be assigned to untyped pointer (uword) without a cast, but not if it's part of an expression!
|
||||
if(parent !is Expression)
|
||||
return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent))
|
||||
}
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
|
||||
@@ -776,6 +776,32 @@ main {
|
||||
(a4v.right as TypecastExpression).expression shouldBe instanceOf<IdentifierReference>()
|
||||
}
|
||||
|
||||
test("odd pointer arithmetic") {
|
||||
val src="""
|
||||
main{
|
||||
|
||||
sub start() {
|
||||
^^ubyte @shared ptr = 2000
|
||||
cx16.r0L = (cx16.r1 - ptr) as ubyte
|
||||
cx16.r1L = (cx16.r1 - (ptr as uword)) as ubyte
|
||||
void findstr1("asdf")
|
||||
void findstr2("asdf")
|
||||
}
|
||||
|
||||
sub findstr1(str haystack) -> ubyte {
|
||||
return (cx16.r3-haystack) as ubyte
|
||||
}
|
||||
sub findstr2(str haystack) -> ubyte {
|
||||
return (cx16.r3-(haystack as uword)) as ubyte
|
||||
}
|
||||
}"""
|
||||
val errors = ErrorReporterForTests()
|
||||
compileText(VMTarget(), false, src, outputDir, errors=errors, writeAssembly = false) shouldBe null
|
||||
errors.errors.size shouldBe 2
|
||||
errors.errors[0] shouldContain("6:31: unclear pointer arithmetic in expression")
|
||||
errors.errors[1] shouldContain("13:25: unclear pointer arithmetic in expression")
|
||||
}
|
||||
|
||||
test("uword struct field array indexing") {
|
||||
val src="""
|
||||
main {
|
||||
@@ -1355,6 +1381,29 @@ main {
|
||||
compileText(Cx16Target(), false, src, outputDir) shouldNotBe null
|
||||
}
|
||||
|
||||
test("str replaced by ^^ubyte in subroutine args and return type") {
|
||||
val src="""
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
void test("hello")
|
||||
}
|
||||
|
||||
sub test(str argument) -> str {
|
||||
return "bye"
|
||||
}
|
||||
}"""
|
||||
val vmprg = compileText(VMTarget(), false, src, outputDir)!!
|
||||
val vmtest = vmprg.codegenAst!!.allBlocks().first { it.name == "main" }.children[1] as PtSub
|
||||
vmtest.signature.returns.single() shouldBe DataType.pointer(BaseDataType.UBYTE)
|
||||
(vmtest.signature.children.single() as PtSubroutineParameter).type shouldBe DataType.pointer(BaseDataType.UBYTE)
|
||||
|
||||
val c64prg = compileText(C64Target(), false, src, outputDir)!!
|
||||
val c64test = c64prg.codegenAst!!.allBlocks().first { it.name == "p8b_main" }.children[1] as PtSub
|
||||
c64test.signature.returns.single() shouldBe DataType.pointer(BaseDataType.UBYTE)
|
||||
(c64test.signature.children.single() as PtSubroutineParameter).type shouldBe DataType.pointer(BaseDataType.UBYTE)
|
||||
}
|
||||
|
||||
test("hoist variable decl and initializer correctly in case of pointer type variable as well") {
|
||||
val src="""
|
||||
%import textio
|
||||
|
||||
@@ -10,6 +10,7 @@ import io.kotest.matchers.types.instanceOf
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.statements.*
|
||||
import prog8.code.core.BaseDataType
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.VMTarget
|
||||
@@ -41,30 +42,29 @@ class TestSubroutines: FunSpec({
|
||||
|
||||
test("stringParameter") {
|
||||
val text = """
|
||||
main {
|
||||
sub start() {
|
||||
str text = "test"
|
||||
|
||||
asmfunc("text")
|
||||
asmfunc(text)
|
||||
asmfunc($2000)
|
||||
func("text")
|
||||
func(text)
|
||||
func($2000)
|
||||
}
|
||||
|
||||
asmsub asmfunc(str thing @AY) {
|
||||
%asm {{
|
||||
rts
|
||||
}}
|
||||
}
|
||||
main {
|
||||
sub start() {
|
||||
str text = "test"
|
||||
|
||||
asmfunc("text")
|
||||
asmfunc(text)
|
||||
asmfunc($2000)
|
||||
func("text")
|
||||
func(text)
|
||||
func($2000)
|
||||
}
|
||||
|
||||
asmsub asmfunc(str thing @AY) {
|
||||
%asm {{
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
sub func(str thing) {
|
||||
uword t2 = thing as uword
|
||||
asmfunc(thing)
|
||||
}
|
||||
}
|
||||
"""
|
||||
sub func(str thing) {
|
||||
uword t2 = thing as uword
|
||||
asmfunc(thing)
|
||||
}
|
||||
}"""
|
||||
val result = compileText(C64Target(), false, text, outputDir, writeAssembly = false)!!
|
||||
val mainBlock = result.compilerAst.entrypoint.definingBlock
|
||||
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
|
||||
@@ -72,13 +72,14 @@ class TestSubroutines: FunSpec({
|
||||
asmfunc.isAsmSubroutine shouldBe true
|
||||
asmfunc.statements.size shouldBe 1
|
||||
func.isAsmSubroutine shouldBe false
|
||||
withClue("str param for subroutines should be changed into UWORD") {
|
||||
asmfunc.parameters.single().type shouldBe DataType.UWORD
|
||||
func.parameters.single().type shouldBe DataType.UWORD
|
||||
withClue("str param for subroutines should be changed into ^^ubyte") {
|
||||
asmfunc.parameters.single().type shouldBe DataType.pointer(BaseDataType.UBYTE)
|
||||
func.parameters.single().type shouldBe DataType.pointer(BaseDataType.UBYTE)
|
||||
func.statements.size shouldBe 5
|
||||
val paramvar = func.statements[0] as VarDecl
|
||||
paramvar.name shouldBe "thing"
|
||||
paramvar.datatype shouldBe DataType.UWORD
|
||||
paramvar.origin shouldBe VarDeclOrigin.SUBROUTINEPARAM
|
||||
paramvar.datatype shouldBe DataType.pointer(BaseDataType.UBYTE)
|
||||
}
|
||||
val assign = func.statements[2] as Assignment
|
||||
assign.target.identifier!!.nameInSource shouldBe listOf("t2")
|
||||
@@ -133,17 +134,17 @@ class TestSubroutines: FunSpec({
|
||||
(asmfunc.statements.single() as InlineAssembly).assembly.trim() shouldBe "rts"
|
||||
asmfunc.hasRtsInAsm(false) shouldBe true
|
||||
func.isAsmSubroutine shouldBe false
|
||||
withClue("str param should have been changed to uword") {
|
||||
asmfunc.parameters.single().type shouldBe DataType.UWORD
|
||||
func.parameters.single().type shouldBe DataType.UWORD
|
||||
withClue("str param should have been changed to ^^ubyte") {
|
||||
asmfunc.parameters.single().type shouldBe DataType.pointer(BaseDataType.UBYTE)
|
||||
func.parameters.single().type shouldBe DataType.pointer(BaseDataType.UBYTE)
|
||||
}
|
||||
|
||||
func.statements.size shouldBe 5
|
||||
func.statements[4] shouldBe instanceOf<Return>()
|
||||
val paramvar = func.statements[0] as VarDecl
|
||||
paramvar.name shouldBe "thing"
|
||||
withClue("pre-asmgen should have changed str to uword type") {
|
||||
paramvar.datatype shouldBe DataType.UWORD
|
||||
withClue("pre-asmgen should have changed str to ^^ubyte type") {
|
||||
paramvar.datatype shouldBe DataType.pointer(BaseDataType.UBYTE)
|
||||
}
|
||||
val assign = func.statements[2] as Assignment
|
||||
assign.target.identifier!!.nameInSource shouldBe listOf("t2")
|
||||
@@ -191,9 +192,9 @@ class TestSubroutines: FunSpec({
|
||||
val mainBlock = result.compilerAst.entrypoint.definingBlock
|
||||
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
|
||||
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
|
||||
withClue("ubyte array param should have been replaced by UWORD pointer") {
|
||||
asmfunc.parameters.single().type shouldBe DataType.UWORD
|
||||
func.parameters.single().type shouldBe DataType.UWORD
|
||||
withClue("ubyte array param should have been replaced by ^^ubyte pointer") {
|
||||
asmfunc.parameters.single().type shouldBe DataType.pointer(BaseDataType.UBYTE)
|
||||
func.parameters.single().type shouldBe DataType.pointer(BaseDataType.UBYTE)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,6 @@ import prog8.ast.expressions.*
|
||||
import prog8.ast.printProgram
|
||||
import prog8.ast.statements.Assignment
|
||||
import prog8.ast.statements.IfElse
|
||||
import prog8.code.ast.PtAsmSub
|
||||
import prog8.code.ast.PtSub
|
||||
import prog8.code.ast.PtSubroutineParameter
|
||||
import prog8.code.core.BaseDataType
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Position
|
||||
@@ -759,37 +756,6 @@ main {
|
||||
errors.errors[3] shouldContain (":9:28: value type uword doesn't match target")
|
||||
}
|
||||
|
||||
test("str replaced with uword in subroutine params and return types (6502 only until that has pointers too)") { // TODO remove this test once 6502 has pointers too
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
derp("hello")
|
||||
mult3("hello")
|
||||
}
|
||||
|
||||
sub derp(str arg) -> str {
|
||||
cx16.r0++
|
||||
return arg
|
||||
}
|
||||
|
||||
asmsub mult3(str input @XY) -> str @XY {
|
||||
%asm {{
|
||||
ldx #100
|
||||
ldy #101
|
||||
rts
|
||||
}}
|
||||
}
|
||||
}"""
|
||||
val result = compileText(C64Target(), true, src, outputDir, writeAssembly = true)!!
|
||||
val main = result.codegenAst!!.allBlocks().first()
|
||||
val derp = main.children.single { it is PtSub && it.name == "p8s_derp" } as PtSub
|
||||
derp.signature.returns shouldBe listOf(DataType.UWORD)
|
||||
(derp.signature.children.single() as PtSubroutineParameter).type shouldBe DataType.UWORD
|
||||
val mult3 = main.children.single { it is PtAsmSub && it.name == "p8s_mult3" } as PtAsmSub
|
||||
mult3.parameters.single().second.type shouldBe DataType.UWORD
|
||||
mult3.returns.single().second shouldBe DataType.UWORD
|
||||
}
|
||||
|
||||
test("return 0 for str converted to uword") {
|
||||
val src = """
|
||||
main {
|
||||
@@ -805,6 +771,7 @@ main {
|
||||
return 42
|
||||
}
|
||||
}"""
|
||||
compileText(VMTarget(), true, src, outputDir, writeAssembly = true) shouldNotBe null
|
||||
compileText(C64Target(), true, src, outputDir, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
|
||||
|
||||
@@ -189,6 +189,10 @@ class BinaryExpression(
|
||||
"+", "-", "*", "%", "/" -> {
|
||||
if (!leftDt.isKnown || !rightDt.isKnown)
|
||||
InferredTypes.unknown()
|
||||
else if(operator=="-" && leftDt.isNumeric && rightDt.isPointer) {
|
||||
// x - pointer is not pointer arithmetic like pointer-x or pointer+x, it's invalid, but return untyped pointer uword here
|
||||
return InferredTypes.knownFor(BaseDataType.UWORD)
|
||||
}
|
||||
else {
|
||||
try {
|
||||
val dt = InferredTypes.knownFor(
|
||||
@@ -478,7 +482,7 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp
|
||||
override fun referencesIdentifier(nameInSource: List<String>) = expression.referencesIdentifier(nameInSource)
|
||||
override fun inferType(program: Program) = InferredTypes.knownFor(type)
|
||||
override fun constValue(program: Program): NumericLiteral? {
|
||||
if(!type.isBasic)
|
||||
if(!type.isBasic && !type.isPointer)
|
||||
return null
|
||||
val cv = expression.constValue(program) ?: return null
|
||||
cv.linkParents(parent)
|
||||
@@ -628,7 +632,9 @@ class NumericLiteral(val type: BaseDataType, // only numerical types allowed
|
||||
BaseDataType.WORD -> require(number in -32768.0..32767.0)
|
||||
BaseDataType.LONG -> require(number in -2147483647.0..2147483647.0)
|
||||
BaseDataType.BOOL -> require(number==0.0 || number==1.0)
|
||||
else -> require(type.isNumericOrBool) { "numeric literal type should be numeric or bool: $type" }
|
||||
BaseDataType.POINTER -> throw FatalAstException("pointer literals should not be created, should have been UWORD $position")
|
||||
else -> require(type.isNumericOrBool) {
|
||||
"numeric literal type should be numeric or bool: $type" }
|
||||
}
|
||||
if(type!=BaseDataType.FLOAT) {
|
||||
if(truncate(number) != number)
|
||||
@@ -829,6 +835,7 @@ class NumericLiteral(val type: BaseDataType, // only numerical types allowed
|
||||
return ValueAfterCast(true, null, NumericLiteral(targettype, number, position))
|
||||
if(targettype==BaseDataType.LONG)
|
||||
return ValueAfterCast(true, null, NumericLiteral(targettype, number, position))
|
||||
// note: do not reduce a number casted to a pointer, back to a number...
|
||||
}
|
||||
BaseDataType.WORD -> {
|
||||
if(targettype==BaseDataType.BYTE && number >= -128 && number <=127)
|
||||
|
||||
@@ -272,7 +272,11 @@ class VarDecl(
|
||||
decltype = VarDeclType.MEMORY
|
||||
value = AddressOf(IdentifierReference(regname, param.position), null, null, false, false,param.position)
|
||||
}
|
||||
val dt = if(param.type.isArray) DataType.UWORD else param.type
|
||||
val dt = when {
|
||||
param.type.isArray -> DataType.UWORD
|
||||
param.type.isString -> DataType.pointer(BaseDataType.UBYTE)
|
||||
else -> param.type
|
||||
}
|
||||
return VarDecl(decltype, VarDeclOrigin.SUBROUTINEPARAM, dt, param.zp, SplitWish.DONTCARE, null, param.name, emptyList(), value,
|
||||
sharedWithAsm = false,
|
||||
alignment = 0u,
|
||||
|
||||
@@ -5,7 +5,6 @@ TODO
|
||||
STRUCTS and TYPED POINTERS (6502 codegen specific)
|
||||
--------------------------------------------------
|
||||
|
||||
- 6502 statementreorderer: fix todo for str -> ^^ubyte instead of uword
|
||||
- fix struct allocations/inits.
|
||||
|
||||
- prefixSymbols(): what to do with prefixing struct fields? Should they be prefixed with something or no?
|
||||
|
||||
@@ -1,52 +1,14 @@
|
||||
%import floats
|
||||
%import textio
|
||||
%option no_sysinit
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
struct List {
|
||||
uword s
|
||||
ubyte n
|
||||
float f
|
||||
bool b
|
||||
^^List next
|
||||
}
|
||||
sub start() {
|
||||
^^List @shared l0 = 30000
|
||||
^^List @shared l1 = 20000
|
||||
l1.next = l0
|
||||
|
||||
cx16.r0 = &l1.s
|
||||
cx16.r1 = &l1.n
|
||||
cx16.r2 = &l1.f
|
||||
cx16.r3 = &l1.b
|
||||
cx16.r4 = &l1.next
|
||||
cx16.r5 = &l1.next.s
|
||||
cx16.r6 = &l1.next.n
|
||||
cx16.r7 = &l1.next.f
|
||||
cx16.r8 = &l1.next.b
|
||||
cx16.r9 = &l1.next.next
|
||||
label:
|
||||
uword @shared addr
|
||||
addr = label
|
||||
addr = thing
|
||||
addr = &label
|
||||
addr = &thing
|
||||
}
|
||||
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r1)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r2)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r3)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r4)
|
||||
txt.nl()
|
||||
|
||||
txt.print_uw(cx16.r5)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r6)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r7)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r8)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r9)
|
||||
txt.nl()
|
||||
sub thing() {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user