mirror of
				https://github.com/irmen/prog8.git
				synced 2025-10-31 00:16:08 +00:00 
			
		
		
		
	type check tuning
This commit is contained in:
		| @@ -67,6 +67,7 @@ val BaseDataType.isPassByValue get() = !this.isIterable || this.isPointer | ||||
|  | ||||
| interface ISubType { | ||||
|     val scopedNameString: String | ||||
|     fun memsize(sizer: IMemSizer): Int | ||||
| } | ||||
|  | ||||
| class DataType private constructor(val base: BaseDataType, val sub: BaseDataType?, var subType: ISubType?, var subTypeFromAntlr: List<String>?=null) { | ||||
| @@ -296,6 +297,14 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType | ||||
|     fun largerSizeThan(other: DataType): Boolean = base.largerSizeThan(other.base) | ||||
|     fun equalsSize(other: DataType): Boolean = base.equalsSize(other.base) | ||||
|  | ||||
|     fun size(memsizer: IMemSizer): Int = if(sub!=null) { | ||||
|             memsizer.memorySize(sub) | ||||
|         } else if(subType!=null) { | ||||
|             subType!!.memsize(memsizer) | ||||
|         } else { | ||||
|             memsizer.memorySize(base) | ||||
|         } | ||||
|  | ||||
|     val isBasic = sub==null && subType==null && subTypeFromAntlr==null | ||||
|     val isUndefined = base == BaseDataType.UNDEFINED | ||||
|     val isByte = base.isByte | ||||
| @@ -382,7 +391,7 @@ enum class RegisterOrPair { | ||||
|             BaseDataType.BYTE -> "sL" | ||||
|             BaseDataType.WORD -> "s" | ||||
|             BaseDataType.UWORD, null -> "" | ||||
|             else -> throw kotlin.IllegalArgumentException("invalid register param type") | ||||
|             else -> throw IllegalArgumentException("invalid register param type") | ||||
|         } | ||||
|         return listOf("cx16", name.lowercase()+suffix) | ||||
|     } | ||||
|   | ||||
| @@ -1304,7 +1304,7 @@ internal class AstChecker(private val program: Program, | ||||
|             errors.err("defer cannot contain jumps or returns", defer.position) | ||||
|     } | ||||
|  | ||||
|     private val supportedPointerOperatorsVirtual: Set<String> = emptySet() | ||||
|     private val supportedPointerOperatorsVirtual: Set<String> = setOf("+") | ||||
|     private val supportedPointerOperators6502: Set<String> = emptySet() | ||||
|  | ||||
|     override fun visit(expr: BinaryExpression) { | ||||
| @@ -1437,12 +1437,22 @@ internal class AstChecker(private val program: Program, | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(!leftDt.isNumeric && !leftDt.isString && !leftDt.isBool) | ||||
|             errors.err("left operand is not numeric or str", expr.left.position) | ||||
|         if(!rightDt.isNumeric && !rightDt.isString && !rightDt.isBool) | ||||
|             errors.err("right operand is not numeric or str", expr.right.position) | ||||
|         if(!leftDt.isNumeric && !leftDt.isString && !leftDt.isBool && !leftDt.isPointer) | ||||
|             errors.err("invalid left operand type", expr.left.position) | ||||
|         if(!rightDt.isNumeric && !rightDt.isString && !rightDt.isBool && !rightDt.isPointer) | ||||
|             errors.err("invalid right operand type", expr.right.position) | ||||
|         if(leftDt!=rightDt) { | ||||
|             if(leftDt.isString && rightDt.isInteger && expr.operator=="*") { | ||||
|             if(leftDt.isPointer) { | ||||
|                 if(!rightDt.isUnsignedWord) { | ||||
|                     errors.err("pointer arithmetic requires unsigned word operand", expr.right.position) | ||||
|                 } | ||||
|             } | ||||
|             else if(rightDt.isPointer) { | ||||
|                 if(!leftDt.isUnsignedWord) { | ||||
|                     errors.err("pointer arithmetic requires unsigned word operand", expr.left.position) | ||||
|                 } | ||||
|             } | ||||
|             else if(leftDt.isString && rightDt.isInteger && expr.operator=="*") { | ||||
|                 // exception allowed: str * constvalue | ||||
|                 if(expr.right.constValue(program)==null) | ||||
|                     errors.err("can only use string repeat with a constant number value", expr.left.position) | ||||
|   | ||||
| @@ -180,6 +180,38 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro | ||||
|                 else -> Pair("", null) | ||||
|             } | ||||
|             if(augmentedValue!=null) { | ||||
|  | ||||
|                 if(srcAssign.target.inferType(program).isPointer) { | ||||
|                     val expr = srcExpr as BinaryExpression | ||||
|                     if(expr.operator=="+") { | ||||
|                         // pointer arithmetic: add the size of the struct times the argument | ||||
|                         val leftDt = expr.left.inferType(program).getOrUndef() | ||||
|                         require(leftDt.isPointer && !expr.right.inferType(program).isPointer) | ||||
|                         val structSize = leftDt.size(program.memsizer) | ||||
|                         val constValue = augmentedValue.constValue(program) | ||||
|                         if(constValue!=null) { | ||||
|                             val total = constValue.number*structSize | ||||
|                             if (total == 0.0) | ||||
|                                 return PtNop(srcAssign.position) | ||||
|                             else { | ||||
|                                 val assign = PtAugmentedAssign(operator, srcAssign.position) | ||||
|                                 assign.add(transform(srcAssign.target)) | ||||
|                                 assign.add(PtNumber(BaseDataType.UWORD, total, srcAssign.position)) | ||||
|                                 return assign | ||||
|                             } | ||||
|                         } else { | ||||
|                             val multiplication = PtBinaryExpression("*", DataType.UWORD, srcAssign.position) | ||||
|                             multiplication.add(transformExpression(augmentedValue)) | ||||
|                             multiplication.add(PtNumber(BaseDataType.UWORD, structSize.toDouble(), srcAssign.position)) | ||||
|                             val assign = PtAugmentedAssign(operator, srcAssign.position) | ||||
|                             assign.add(transform(srcAssign.target)) | ||||
|                             assign.add(multiplication) | ||||
|                             return assign | ||||
|                         } | ||||
|                     } else | ||||
|                         throw FatalAstException("unexpected augmented assignment operator on pointer ${expr.operator}") | ||||
|                 } | ||||
|  | ||||
|                 val assign = PtAugmentedAssign(operator, srcAssign.position) | ||||
|                 assign.add(transform(srcAssign.target)) | ||||
|                 assign.add(transformExpression(augmentedValue)) | ||||
| @@ -705,6 +737,48 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro | ||||
|  | ||||
|                 else -> throw FatalAstException("unknown deref at ${srcExpr.position}") | ||||
|             } | ||||
|         } else { | ||||
|             if(srcExpr.left.inferType(program).isPointer || srcExpr.right.inferType(program).isPointer) { | ||||
|                 if(srcExpr.operator=="+") { | ||||
|                     // pointer arithmetic:  ptr + value | ||||
|                     val leftDt = srcExpr.left.inferType(program).getOrUndef() | ||||
|                     val rightDt = srcExpr.right.inferType(program).getOrUndef() | ||||
|                     if(leftDt.isPointer && !rightDt.isPointer) { | ||||
|                         val structSize = leftDt.size(program.memsizer) | ||||
|                         val constValue = srcExpr.right.constValue(program) | ||||
|                         if(constValue!=null) { | ||||
|                             TODO("ptr +  $constValue * $structSize") | ||||
|                         } else { | ||||
|                             TODO("ptr +  ${srcExpr.right} * $structSize") | ||||
|                         } | ||||
|                     } else if(!leftDt.isPointer && rightDt.isPointer) { | ||||
|                         val structSize = rightDt.size(program.memsizer) | ||||
|                         val constValue = srcExpr.left.constValue(program) | ||||
|                         if(constValue!=null) { | ||||
|                             val total = constValue.number*structSize | ||||
|                             if (total == 0.0) | ||||
|                                 return transformExpression(srcExpr.left) | ||||
|                             else { | ||||
|                                 TODO("ptr +  $constValue * $structSize") | ||||
| //                                val assign = PtAugmentedAssign(operator, srcAssign.position) | ||||
| //                                assign.add(transform(srcAssign.target)) | ||||
| //                                assign.add(PtNumber(BaseDataType.UWORD, total, srcAssign.position)) | ||||
| //                                return assign | ||||
|                             } | ||||
|                         } else { | ||||
|                             val total = PtBinaryExpression("*", DataType.UWORD, srcExpr.position) | ||||
|                             total.add(transformExpression(srcExpr.left)) | ||||
|                             total.add(PtNumber(BaseDataType.UWORD, structSize.toDouble(), srcExpr.position)) | ||||
|                             val addition = PtBinaryExpression("+", DataType.UWORD, srcExpr.position) | ||||
|                             addition.add(transformExpression(srcExpr.right)) | ||||
|                             addition.add(total) | ||||
|                             return addition | ||||
|                         } | ||||
|                     } else { | ||||
|                         throw FatalAstException("weird pointer arithmetic ${srcExpr.position}") | ||||
|                     } | ||||
|                 } else | ||||
|                     throw FatalAstException("unsupported operator on pointer: ${srcExpr.operator} at ${srcExpr.position}") | ||||
|             } else { | ||||
|                 val expr = PtBinaryExpression(srcExpr.operator, type, srcExpr.position) | ||||
|                 expr.add(transformExpression(srcExpr.left)) | ||||
| @@ -712,6 +786,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro | ||||
|                 return expr | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun transform(srcCheck: ContainmentCheck): PtExpression { | ||||
|  | ||||
|   | ||||
| @@ -211,6 +211,16 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val | ||||
|                     } | ||||
|                     return modifications | ||||
|                 } | ||||
|  | ||||
|  | ||||
|                 // pointer arithmetic | ||||
|                 if(leftDt.isPointer) { | ||||
|                     val cast = TypecastExpression(expr.right, DataType.UWORD, true, expr.right.position) | ||||
|                     return listOf(IAstModification.ReplaceNode(expr.right, cast, expr)) | ||||
|                 } else if(rightDt.isPointer) { | ||||
|                     val cast = TypecastExpression(expr.left, DataType.UWORD, true, expr.left.position) | ||||
|                     return listOf(IAstModification.ReplaceNode(expr.left, cast, expr)) | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // check if shifts have a positive integer shift type | ||||
|   | ||||
| @@ -353,12 +353,13 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: | ||||
|  | ||||
|     override fun visit(assignment: Assignment) { | ||||
|         val binExpr = assignment.value as? BinaryExpression | ||||
|         if(binExpr!=null && assignment.isAugmentable) { | ||||
|         if(binExpr!=null && binExpr.left isSameAs assignment.target && binExpr.operator !in ComparisonOperators) { | ||||
|             // we only support the inplace assignments of the form A = A <operator> <value> | ||||
|             // don't use assignment.isAugmentable here! That one is a more general check, and not suitable for printing the AST like here | ||||
|             assignment.target.accept(this) | ||||
|             output(" ${binExpr.operator}= ") | ||||
|             binExpr.right.accept(this) | ||||
|         } else { | ||||
|             val whyNot = assignment.isAugmentable | ||||
|             assignment.target.accept(this) | ||||
|             output(" = ") | ||||
|             assignment.value.accept(this) | ||||
|   | ||||
| @@ -386,7 +386,7 @@ class StructDecl(override val name: String, val fields: List<Pair<DataType, Stri | ||||
|     override fun copy() = StructDecl(name, fields.toList(), position) | ||||
|     override fun accept(visitor: IAstVisitor) = visitor.visit(this) | ||||
|     override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) | ||||
|     fun memsize(sizer: IMemSizer): Int = fields.sumOf { sizer.memorySize(it.first, 1) } | ||||
|     override fun memsize(sizer: IMemSizer): Int = fields.sumOf { sizer.memorySize(it.first, 1) } | ||||
|     fun getFieldType(name: String): DataType? = fields.firstOrNull { it.second==name }?.first | ||||
|     override val scopedNameString by lazy { scopedName.joinToString(".") } | ||||
| } | ||||
| @@ -503,6 +503,7 @@ class Assignment(var target: AssignTarget, var value: Expression, var origin: As | ||||
|  | ||||
|     /** | ||||
|      * Is the assigment value an expression that references the assignment target itself? | ||||
|      * Note it doesn't have to be the first term in the expression! | ||||
|      * The expression can be a BinaryExpression, PrefixExpression or TypecastExpression (possibly with one sub-cast). | ||||
|      */ | ||||
|     val isAugmentable: Boolean | ||||
|   | ||||
| @@ -34,6 +34,7 @@ STRUCTS and TYPED POINTERS | ||||
| - DONE: pointer arrays are split-words only, enforce this (variable dt + initializer array dt) | ||||
| - DONE: make an error message for all pointer expressions (prefixed, binary) so we can start implementing the ones we need one by one. | ||||
| - start by making ptr.value++ work  , and  ptr.value = ptr.value+20,   and ptr.value = cx16.r0L+20+ptr.value   Likewise for --  DON'T FORGET C POINTER SEMANTICS | ||||
| - don't do pointer arith in the codegen, do it in Pt translation! | ||||
| - fix actual _msb/_lsb storage of the split-words pointer-arrays | ||||
| - support @dirty on pointer vars -> uninitialized pointer placed in BSS_noclear segment | ||||
| - pointer types in subroutine signatures (both normal and asm-subs) | ||||
| @@ -49,6 +50,7 @@ STRUCTS and TYPED POINTERS | ||||
| - pointer-to-array syntax = TBD | ||||
| - what about pointers to subroutines? should these be typed as well now? | ||||
| - What about static initialization of an array of struct pointers? -> impossible right now because the pointer values are not contants | ||||
| - 6502 codegen should warn about writing to initialized struct instances when using romable code, like with arrays "can only be used as read-only in ROMable code" | ||||
| - 6502 asm symbol name prefixing should work for dereferences too. | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -20,10 +20,50 @@ main { | ||||
|  | ||||
| ; TODO (Borked:) | ||||
|         ^^Node @shared ptr = 2000 | ||||
|         ptr++ | ||||
|         ptr += 2 | ||||
|         ptr = cx16.r0 + ptr | ||||
| ;        ^^bool bptr = 3000 | ||||
| ;        ^^float fptr = 3000 | ||||
| ; | ||||
| ;        bptr++ | ||||
| ;        fptr++ | ||||
| ; | ||||
| ;        txt.print_uw(ptr) | ||||
| ;        txt.nl() | ||||
| ; | ||||
| ;        ptr++ | ||||
| ;        txt.print_uw(ptr) | ||||
| ;        txt.nl() | ||||
| ; | ||||
| ;        ptr += 2 | ||||
| ;        txt.print_uw(ptr) | ||||
| ;        txt.nl() | ||||
| ; | ||||
| ;        cx16.r0 = 5 | ||||
| ;        ptr = cx16.r0 + ptr | ||||
| ;        txt.print_uw(ptr) | ||||
| ;        txt.nl() | ||||
|  | ||||
|         cx16.r0 = 4 | ||||
|  | ||||
|         ptr = cx16.r0 + ptr + 1 | ||||
|         txt.print_uw(ptr) | ||||
|         txt.nl() | ||||
|         ptr = cx16.r0 + 1 + ptr | ||||
|         txt.print_uw(ptr) | ||||
|         txt.nl() | ||||
|         ptr = ptr + 1 + cx16.r0 | ||||
|         txt.print_uw(ptr) | ||||
|         txt.nl() | ||||
|  | ||||
|         ptr = cx16.r0 + ptr + 10 | ||||
|         txt.print_uw(ptr) | ||||
|         txt.nl() | ||||
|         ptr = cx16.r0 + 10 + ptr | ||||
|         txt.print_uw(ptr) | ||||
|         txt.nl() | ||||
|         ptr = ptr + 10 + cx16.r0 | ||||
|         txt.print_uw(ptr) | ||||
|         txt.nl() | ||||
|  | ||||
| ;        ptr.value++ | ||||
| ;        ptr.value += 30 | ||||
| ;        ptr.value = ptr.value + 20 | ||||
|   | ||||
| @@ -540,8 +540,8 @@ class IRInlineBinaryChunk(label: String?, | ||||
| typealias IRCodeChunks = List<IRCodeChunkBase> | ||||
|  | ||||
|  | ||||
| internal class IRSubtypePlaceholder(val name: String): ISubType { | ||||
|     override val scopedNameString = name | ||||
| internal class IRSubtypePlaceholder(override val scopedNameString: String, val size: Int = 999999999): ISubType { | ||||
|     override fun memsize(sizer: IMemSizer) = size | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -295,6 +295,8 @@ class StStruct( | ||||
|         } | ||||
|         throw NoSuchElementException("field $name not found in struct ${this.name}") | ||||
|     } | ||||
|  | ||||
|     override fun memsize(sizer: IMemSizer): Int = size.toInt() | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user