mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 04:30:03 +00:00
it's now possible in more places to assign arrays and put array literals without the need to define explicit variable.
This commit is contained in:
parent
d31cf766eb
commit
bd237b2b95
@ -19,8 +19,8 @@ internal fun Program.processAstBeforeAsmGeneration(errors: ErrorReporter) {
|
||||
fixer.applyModifications()
|
||||
}
|
||||
|
||||
internal fun Program.reorderStatements() {
|
||||
val reorder = StatementReorderer(this)
|
||||
internal fun Program.reorderStatements(errors: ErrorReporter) {
|
||||
val reorder = StatementReorderer(this, errors)
|
||||
reorder.visit(this)
|
||||
reorder.applyModifications()
|
||||
}
|
||||
|
@ -756,8 +756,13 @@ internal class AstChecker(private val program: Program,
|
||||
return e is StringLiteralValue
|
||||
}
|
||||
|
||||
if(!array.value.all { it is NumericLiteralValue || it is AddressOf || isPassByReferenceElement(it) })
|
||||
errors.err("array literal contains invalid types", array.position)
|
||||
if(array.parent is VarDecl) {
|
||||
if (!array.value.all { it is NumericLiteralValue || it is AddressOf || isPassByReferenceElement(it) })
|
||||
errors.err("array literal for variable initialization contains invalid types", array.position)
|
||||
} else if(array.parent is ForLoop) {
|
||||
if (!array.value.all { it.constValue(program) != null })
|
||||
errors.err("array literal for iteration must contain constants. Try using a separate array variable instead?", array.position)
|
||||
}
|
||||
|
||||
super.visit(array)
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker()
|
||||
val arrayDt = array.type
|
||||
if(!arrayDt.istype(vardecl.datatype)) {
|
||||
val cast = array.cast(vardecl.datatype)
|
||||
if (cast != null && cast!=array)
|
||||
if (cast != null && cast !== array)
|
||||
return listOf(IAstModification.ReplaceNode(vardecl.value!!, cast, vardecl))
|
||||
}
|
||||
} else {
|
||||
@ -94,7 +94,7 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker()
|
||||
if(arrayDt.isKnown) {
|
||||
// this array literal is part of an expression, turn it into an identifier reference
|
||||
val litval2 = array.cast(arrayDt.typeOrElse(DataType.STRUCT))
|
||||
if(litval2!=null && litval2!=array) {
|
||||
if(litval2!=null) {
|
||||
val vardecl2 = VarDecl.createAuto(litval2)
|
||||
val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position)
|
||||
return listOf(
|
||||
|
@ -6,7 +6,7 @@ import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
|
||||
|
||||
internal class StatementReorderer(val program: Program) : AstWalker() {
|
||||
internal class StatementReorderer(val program: Program, val errors: ErrorReporter) : AstWalker() {
|
||||
// Reorders the statements in a way the compiler needs.
|
||||
// - 'main' block must be the very first statement UNLESS it has an address set.
|
||||
// - library blocks are put last.
|
||||
@ -84,20 +84,31 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
|
||||
override fun before(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
||||
val valueType = assignment.value.inferType(program)
|
||||
val targetType = assignment.target.inferType(program, assignment)
|
||||
var assignments = emptyList<Assignment>()
|
||||
|
||||
if(targetType.istype(DataType.STRUCT) && (valueType.istype(DataType.STRUCT) || valueType.typeOrElse(DataType.STRUCT) in ArrayDatatypes )) {
|
||||
val assignments = if (assignment.value is ArrayLiteralValue) {
|
||||
flattenStructAssignmentFromStructLiteral(assignment, program) // 'structvar = [ ..... ] '
|
||||
assignments = if (assignment.value is ArrayLiteralValue) {
|
||||
flattenStructAssignmentFromStructLiteral(assignment) // 'structvar = [ ..... ] '
|
||||
} else {
|
||||
flattenStructAssignmentFromIdentifier(assignment, program) // 'structvar1 = structvar2'
|
||||
flattenStructAssignmentFromIdentifier(assignment) // 'structvar1 = structvar2'
|
||||
}
|
||||
if(assignments.isNotEmpty()) {
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
assignments.reversed().mapTo(modifications) { IAstModification.InsertAfter(assignment, it, parent) }
|
||||
modifications.add(IAstModification.Remove(assignment, parent))
|
||||
return modifications
|
||||
}
|
||||
|
||||
if(targetType.typeOrElse(DataType.STRUCT) in ArrayDatatypes && valueType.typeOrElse(DataType.STRUCT) in ArrayDatatypes ) {
|
||||
assignments = if (assignment.value is ArrayLiteralValue) {
|
||||
flattenArrayAssignmentFromArrayLiteral(assignment) // 'arrayvar = [ ..... ] '
|
||||
} else {
|
||||
flattenArrayAssignmentFromIdentifier(assignment) // 'arrayvar1 = arrayvar2'
|
||||
}
|
||||
}
|
||||
|
||||
if(assignments.isNotEmpty()) {
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
assignments.reversed().mapTo(modifications) { IAstModification.InsertAfter(assignment, it, parent) }
|
||||
modifications.add(IAstModification.Remove(assignment, parent))
|
||||
return modifications
|
||||
}
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
@ -150,15 +161,69 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
|
||||
return noModifications
|
||||
}
|
||||
|
||||
private fun flattenStructAssignmentFromStructLiteral(structAssignment: Assignment, program: Program): List<Assignment> {
|
||||
private fun flattenArrayAssignmentFromArrayLiteral(assign: Assignment): List<Assignment> {
|
||||
// TODO use a pointer loop instead of individual assignments
|
||||
|
||||
val identifier = assign.target.identifier!!
|
||||
val targetVar = identifier.targetVarDecl(program.namespace)!!
|
||||
|
||||
val alv = assign.value as? ArrayLiteralValue
|
||||
if(targetVar.arraysize==null) {
|
||||
errors.err("array has no defined size", identifier.position)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
if(alv==null || alv.value.size != targetVar.arraysize!!.constIndex()) {
|
||||
errors.err("element count mismatch", assign.position)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return alv.value.withIndex().map { (index, value)->
|
||||
val idx = ArrayIndexedExpression(identifier, ArrayIndex(NumericLiteralValue(DataType.UBYTE, index, assign.position), assign.position), assign.position)
|
||||
Assignment(AssignTarget(null, idx, null, assign.position), value, value.position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun flattenArrayAssignmentFromIdentifier(assign: Assignment): List<Assignment> {
|
||||
// TODO use a pointer loop instead of individual assignments
|
||||
|
||||
val identifier = assign.target.identifier!!
|
||||
val targetVar = identifier.targetVarDecl(program.namespace)!!
|
||||
|
||||
val sourceIdent = assign.value as IdentifierReference
|
||||
val sourceVar = sourceIdent.targetVarDecl(program.namespace)!!
|
||||
if(!sourceVar.isArray) {
|
||||
errors.err("value must be an array", sourceIdent.position)
|
||||
return emptyList()
|
||||
}
|
||||
if(targetVar.arraysize==null) {
|
||||
errors.err("array has no defined size", identifier.position)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val alv = sourceVar.value as? ArrayLiteralValue
|
||||
if(alv==null || alv.value.size != targetVar.arraysize!!.constIndex()) {
|
||||
errors.err("element count mismatch", assign.position)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return alv.value.withIndex().map { (index, value)->
|
||||
val idx = ArrayIndexedExpression(identifier, ArrayIndex(NumericLiteralValue(DataType.UBYTE, index, assign.position), assign.position), assign.position)
|
||||
Assignment(AssignTarget(null, idx, null, assign.position), value, value.position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun flattenStructAssignmentFromStructLiteral(structAssignment: Assignment): List<Assignment> {
|
||||
val identifier = structAssignment.target.identifier!!
|
||||
val identifierName = identifier.nameInSource.single()
|
||||
val targetVar = identifier.targetVarDecl(program.namespace)!!
|
||||
val struct = targetVar.struct!!
|
||||
|
||||
val slv = structAssignment.value as? ArrayLiteralValue
|
||||
if(slv==null || slv.value.size != struct.numberOfElements)
|
||||
throw FatalAstException("element count mismatch")
|
||||
if(slv==null || slv.value.size != struct.numberOfElements) {
|
||||
errors.err("element count mismatch", structAssignment.position)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return struct.statements.zip(slv.value).map { (targetDecl, sourceValue) ->
|
||||
targetDecl as VarDecl
|
||||
@ -171,7 +236,8 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun flattenStructAssignmentFromIdentifier(structAssignment: Assignment, program: Program): List<Assignment> {
|
||||
private fun flattenStructAssignmentFromIdentifier(structAssignment: Assignment): List<Assignment> {
|
||||
// TODO use memcopy beyond a certain number of elements
|
||||
val identifier = structAssignment.target.identifier!!
|
||||
val identifierName = identifier.nameInSource.single()
|
||||
val targetVar = identifier.targetVarDecl(program.namespace)!!
|
||||
|
@ -171,7 +171,8 @@ private fun processAst(programAst: Program, errors: ErrorReporter, compilerOptio
|
||||
errors.handle()
|
||||
programAst.constantFold(errors)
|
||||
errors.handle()
|
||||
programAst.reorderStatements()
|
||||
programAst.reorderStatements(errors)
|
||||
errors.handle()
|
||||
programAst.addTypecasts(errors)
|
||||
errors.handle()
|
||||
programAst.variousCleanups()
|
||||
|
@ -260,6 +260,11 @@ Note that the various keywords for the data type and variable type (``byte``, ``
|
||||
can't be used as *identifiers* elsewhere. You can't make a variable, block or subroutine with the name ``byte``
|
||||
for instance.
|
||||
|
||||
It's possible to assign a new array to another array, this will overwrite all elements in the original
|
||||
array with those in the value array. The number and types of elements have to match.
|
||||
For large arrays this is a slow operation because every element is copied over. It should probably be avoided.
|
||||
|
||||
|
||||
**Arrays at a specific memory location:**
|
||||
Using the memory-mapped syntax it is possible to define an array to be located at a specific memory location.
|
||||
For instance to reference the first 5 rows of the Commodore 64's screen matrix as an array, you can define::
|
||||
|
@ -7,31 +7,40 @@ main {
|
||||
|
||||
sub start() {
|
||||
|
||||
repeat 0 {
|
||||
txt.print("repeat0\n")
|
||||
const ubyte c1 = 111
|
||||
const ubyte c2 = 122
|
||||
const ubyte c3 = 133
|
||||
ubyte ii
|
||||
|
||||
|
||||
for ii in [c1, c2, c3] {
|
||||
txt.print_ub(ii)
|
||||
}
|
||||
|
||||
repeat 2 {
|
||||
txt.print("repeat2\n")
|
||||
}
|
||||
; ubyte[3] numbers
|
||||
;
|
||||
; for ii in [55,44,33] {
|
||||
; txt.print_ub(ii)
|
||||
; }
|
||||
|
||||
ubyte u=3
|
||||
|
||||
repeat u-1 {
|
||||
txt.print("repeat u=2\n")
|
||||
}
|
||||
|
||||
u=2
|
||||
repeat u-1 {
|
||||
txt.print("repeat u=1\n")
|
||||
}
|
||||
|
||||
u=1
|
||||
repeat u-1 {
|
||||
txt.print("repeat u=0\n")
|
||||
}
|
||||
|
||||
txt.chrout('\n')
|
||||
; ubyte a = 99
|
||||
; ubyte b = 88
|
||||
; ubyte c = 77
|
||||
;
|
||||
; ;numbers = numbers ; TODO optimize away
|
||||
;
|
||||
; numbers = [c1,c2,c3]
|
||||
; numbers = [1,2,3]
|
||||
; numbers = [a,b,c]
|
||||
;
|
||||
; ubyte[] a1 = [c1,c2,c3]
|
||||
; ubyte[3] a2
|
||||
;
|
||||
; a2 = [a,b,c]
|
||||
;
|
||||
; txt.print_ub(a)
|
||||
; txt.print_ub(b)
|
||||
; txt.print_ub(c)
|
||||
}
|
||||
|
||||
asmsub testX() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user