This commit is contained in:
Irmen de Jong 2019-07-12 14:38:37 +02:00
parent 1e9586f635
commit 9f6fa60bf1
9 changed files with 135 additions and 56 deletions

View File

@ -231,11 +231,7 @@ class ArrayIndexedExpression(val identifier: IdentifierReference,
return when (target.datatype) { return when (target.datatype) {
in NumericDatatypes -> null in NumericDatatypes -> null
in StringDatatypes -> DataType.UBYTE in StringDatatypes -> DataType.UBYTE
DataType.ARRAY_UB -> DataType.UBYTE in ArrayDatatypes -> ArrayElementTypes[target.datatype]
DataType.ARRAY_B -> DataType.BYTE
DataType.ARRAY_UW -> DataType.UWORD
DataType.ARRAY_W -> DataType.WORD
DataType.ARRAY_F -> DataType.FLOAT
else -> throw FatalAstException("invalid dt") else -> throw FatalAstException("invalid dt")
} }
} }

View File

@ -406,11 +406,13 @@ internal class AstChecker(private val program: Program,
if(targetDatatype!=null) { if(targetDatatype!=null) {
val constVal = assignment.value.constValue(program) val constVal = assignment.value.constValue(program)
if(constVal!=null) { if(constVal!=null) {
val arrayspec = if(target.identifier!=null) { val targetVar =
val targetVar = program.namespace.lookup(target.identifier.nameInSource, assignment) as? VarDecl if(target.identifier!=null)
targetVar?.arraysize program.namespace.lookup(target.identifier.nameInSource, assignment) as? VarDecl
} else null else
checkValueTypeAndRange(targetDatatype, null
val arrayspec = if(target.identifier!=null) targetVar?.arraysize else null
checkValueTypeAndRange(targetDatatype, targetVar?.struct,
arrayspec ?: ArrayIndex(LiteralValue.optimalInteger(-1, assignment.position), assignment.position), arrayspec ?: ArrayIndex(LiteralValue.optimalInteger(-1, assignment.position), assignment.position),
constVal, program.heap) constVal, program.heap)
} else { } else {
@ -424,8 +426,9 @@ internal class AstChecker(private val program: Program,
else else
checkResult.add(ExpressionError("assignment value is invalid or has no proper datatype", assignment.value.position)) checkResult.add(ExpressionError("assignment value is invalid or has no proper datatype", assignment.value.position))
} }
else else {
checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, target, assignment.position) checkAssignmentCompatible(targetDatatype, target, sourceDatatype, assignment.value, assignment.position)
}
} }
} }
return assignment return assignment
@ -521,7 +524,7 @@ internal class AstChecker(private val program: Program,
else else
ArrayIndex(LiteralValue.optimalInteger(-2, decl.position), decl.position) ArrayIndex(LiteralValue.optimalInteger(-2, decl.position), decl.position)
) )
checkValueTypeAndRange(decl.datatype, arraySpec, decl.value as LiteralValue, program.heap) checkValueTypeAndRange(decl.datatype, decl.struct, arraySpec, decl.value as LiteralValue, program.heap)
} }
else -> { else -> {
err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!.javaClass.simpleName}") err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!.javaClass.simpleName}")
@ -664,7 +667,7 @@ internal class AstChecker(private val program: Program,
ArrayIndex.forArray(literalValue, program.heap) ArrayIndex.forArray(literalValue, program.heap)
else else
ArrayIndex(LiteralValue.optimalInteger(-3, literalValue.position), literalValue.position) ArrayIndex(LiteralValue.optimalInteger(-3, literalValue.position), literalValue.position)
checkValueTypeAndRange(literalValue.type, arrayspec, literalValue, program.heap) checkValueTypeAndRange(literalValue.type, null, arrayspec, literalValue, program.heap)
val lv = super.visit(literalValue) val lv = super.visit(literalValue)
when(lv.type) { when(lv.type) {
@ -1009,7 +1012,8 @@ internal class AstChecker(private val program: Program,
} }
} }
private fun checkValueTypeAndRange(targetDt: DataType, arrayspec: ArrayIndex, value: LiteralValue, heap: HeapValues) : Boolean { private fun checkValueTypeAndRange(targetDt: DataType, struct: StructDecl?,
arrayspec: ArrayIndex, value: LiteralValue, heap: HeapValues) : Boolean {
fun err(msg: String) : Boolean { fun err(msg: String) : Boolean {
checkResult.add(ExpressionError(msg, value.position)) checkResult.add(ExpressionError(msg, value.position))
return false return false
@ -1138,9 +1142,20 @@ internal class AstChecker(private val program: Program,
return err("invalid float array initialization value ${value.type}, expected $targetDt") return err("invalid float array initialization value ${value.type}, expected $targetDt")
} }
DataType.STRUCT -> { DataType.STRUCT -> {
if(value.type!=DataType.STRUCT) if(value.type in ArrayDatatypes) {
return err("cannot assign a normal value to a struct") if(value.arrayvalue!!.size != struct!!.numberOfElements)
TODO("check struct, $value ") return err("number of values is not the same as the number of members in the struct")
for(elt in value.arrayvalue.zip(struct.statements)) {
val vardecl = elt.second as VarDecl
val valuetype = elt.first.inferType(program)!!
if (!(valuetype isAssignableTo vardecl.datatype)) {
checkResult.add(ExpressionError("invalid struct member init value type $valuetype, expected ${vardecl.datatype}", elt.first.position))
return false
}
}
return true
}
return false
} }
} }
return true return true
@ -1196,9 +1211,9 @@ internal class AstChecker(private val program: Program,
} }
private fun checkAssignmentCompatible(targetDatatype: DataType, private fun checkAssignmentCompatible(targetDatatype: DataType,
target: AssignTarget,
sourceDatatype: DataType, sourceDatatype: DataType,
sourceValue: IExpression, sourceValue: IExpression,
target: AssignTarget,
position: Position) : Boolean { position: Position) : Boolean {
if(sourceValue is RangeExpr) if(sourceValue is RangeExpr)
@ -1214,6 +1229,13 @@ internal class AstChecker(private val program: Program,
DataType.STR_S -> sourceDatatype== DataType.STR_S DataType.STR_S -> sourceDatatype== DataType.STR_S
DataType.STRUCT -> { DataType.STRUCT -> {
// for now we've decided you cannot assign struct by-value. // for now we've decided you cannot assign struct by-value.
// but you can however assign an array to it of the correct size
if(sourceDatatype in ArrayDatatypes) {
val identifier = sourceValue as IdentifierReference
val sourceArraySize = identifier.targetVarDecl(program.namespace)!!.arraysize?.size()
val targetstruct = target.identifier!!.targetVarDecl(program.namespace)!!.struct!!
return targetstruct.numberOfElements == sourceArraySize
}
// if(sourceDatatype==DataType.STRUCT) { // if(sourceDatatype==DataType.STRUCT) {
// val sourcename = (sourceValue as IdentifierReference).nameInSource // val sourcename = (sourceValue as IdentifierReference).nameInSource
// val vd1 = program.namespace.lookup(sourcename, target) as? VarDecl // val vd1 = program.namespace.lookup(sourcename, target) as? VarDecl

View File

@ -223,8 +223,15 @@ internal class AstIdentifiersChecker(private val namespace: INameScope) : IAstMo
// a literal value that's not declared as a variable, which refers to something on the heap. // a literal value that's not declared as a variable, which refers to something on the heap.
// we need to introduce an auto-generated variable for this to be able to refer to the value! // we need to introduce an auto-generated variable for this to be able to refer to the value!
// (note: ususally, this has been taken care of already when the var was created) // (note: ususally, this has been taken care of already when the var was created)
val variable = VarDecl(VarDeclType.VAR, literalValue.type, false, null, "$autoHeapValuePrefix${literalValue.heapId}", null, literalValue, val declaredType = if(literalValue.isArray) ArrayElementTypes.getValue(literalValue.type) else literalValue.type
isArray = false, hiddenButDoNotRemove = false, position = literalValue.position) val variable = VarDecl(VarDeclType.VAR,
declaredType,
false,
null,
"$autoHeapValuePrefix${literalValue.heapId}",
null,
literalValue,
isArray = literalValue.isArray, hiddenButDoNotRemove = true, position = literalValue.position)
anonymousVariablesFromHeap[variable.name] = Pair(literalValue, variable) anonymousVariablesFromHeap[variable.name] = Pair(literalValue, variable)
} }
return super.visit(literalValue) return super.visit(literalValue)

View File

@ -6,6 +6,7 @@ import prog8.ast.expressions.*
import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.processing.IAstModifyingVisitor
import prog8.ast.processing.IAstVisitor import prog8.ast.processing.IAstVisitor
import prog8.compiler.HeapValues import prog8.compiler.HeapValues
import prog8.compiler.target.c64.Mflpt5
class BuiltinFunctionStatementPlaceholder(val name: String, override val position: Position) : IStatement { class BuiltinFunctionStatementPlaceholder(val name: String, override val position: Position) : IStatement {
@ -162,7 +163,7 @@ class VarDecl(val type: VarDeclType,
DataType.FLOAT -> DataType.ARRAY_F DataType.FLOAT -> DataType.ARRAY_F
else -> { else -> {
datatypeErrors.add(SyntaxError("array can only contain bytes/words/floats", position)) datatypeErrors.add(SyntaxError("array can only contain bytes/words/floats", position))
DataType.UBYTE DataType.ARRAY_UB
} }
} }
@ -740,6 +741,22 @@ class StructDecl(override val name: String,
this.statements.forEach { it.linkParents(this) } this.statements.forEach { it.linkParents(this) }
} }
val numberOfElements: Int
get() = this.statements.size
val memorySize: Int
get() = this.statements.map {
val decl = it as VarDecl
when {
decl.datatype in ByteDatatypes -> 8
decl.datatype in WordDatatypes -> 16
decl.datatype==DataType.FLOAT -> Mflpt5.MemorySize
decl.datatype in StringDatatypes -> TODO("stringvalue size")
decl.datatype in ArrayDatatypes -> decl.arraysize!!.size()!!
decl.datatype==DataType.STRUCT -> decl.struct!!.memorySize
else -> throw FatalAstException("can't get size for $decl")
}
}.sum()
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
} }

View File

@ -103,10 +103,10 @@ class AstToSourceCode(val output: (text: String) -> Unit): IAstVisitor {
} }
override fun visit(decl: VarDecl) { override fun visit(decl: VarDecl) {
if(decl.hiddenButDoNotRemove) { // if(decl.hiddenButDoNotRemove) {
// skip autogenerated vardecl // // skip autogenerated vardecl
return // return
} // }
when(decl.type) { when(decl.type) {
VarDeclType.VAR -> {} VarDeclType.VAR -> {}
@ -114,6 +114,7 @@ class AstToSourceCode(val output: (text: String) -> Unit): IAstVisitor {
VarDeclType.MEMORY -> output("&") VarDeclType.MEMORY -> output("&")
VarDeclType.STRUCT -> output("${decl.struct!!.name} ") VarDeclType.STRUCT -> output("${decl.struct!!.name} ")
} }
output(decl.struct?.name ?: "")
output(datatypeString(decl.datatype)) output(datatypeString(decl.datatype))
if(decl.arraysize!=null) { if(decl.arraysize!=null) {
decl.arraysize!!.index.accept(this) decl.arraysize!!.index.accept(this)

View File

@ -1446,6 +1446,27 @@ internal class Compiler(private val program: Program) {
else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
} }
} }
DataType.STRUCT -> {
// Assume the value is an array. Flatten the struct assignment into memberwise assignments.
val identifier = stmt.target.identifier!!
val identifierName = identifier.nameInSource.single()
val targetVar = identifier.targetVarDecl(program.namespace)!!
val struct = targetVar.struct!!
val sourceVar = (stmt.value as IdentifierReference).targetVarDecl(program.namespace)!!
if(!sourceVar.isArray)
throw CompilerException("can only assign arrays to structs")
val sourceArray = (sourceVar.value as LiteralValue).arrayvalue!!
for(member in struct.statements.zip(sourceArray)) {
val decl = member.first as VarDecl
val value = member.second.constValue(program)!!
val mangled = mangledStructMemberName(identifierName, decl.name)
val idref = IdentifierReference(listOf(mangled), stmt.position)
val assign = Assignment(AssignTarget(null, idref, null, null, stmt.position), null, value, value.position)
assign.linkParents(stmt)
translate(assign)
}
return
}
in StringDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") in StringDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
in ArrayDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") in ArrayDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
else -> throw CompilerException("weird/unknown targetdt") else -> throw CompilerException("weird/unknown targetdt")
@ -1499,7 +1520,9 @@ internal class Compiler(private val program: Program) {
prog.instr(opcode, RuntimeValue(DataType.UWORD, address)) prog.instr(opcode, RuntimeValue(DataType.UWORD, address))
} }
VarDeclType.CONST -> throw CompilerException("cannot assign to const") VarDeclType.CONST -> throw CompilerException("cannot assign to const")
VarDeclType.STRUCT -> TODO("decltype struct") VarDeclType.STRUCT -> {
TODO("decltype struct $assignTarget")
}
} }
} else throw CompilerException("invalid assignment target type ${target::class}") } else throw CompilerException("invalid assignment target type ${target::class}")
} }

View File

@ -175,6 +175,9 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
decl.value = LiteralValue(decl.datatype, initHeapId = heapId, position = litval.position) decl.value = LiteralValue(decl.datatype, initHeapId = heapId, position = litval.position)
} }
} }
DataType.STRUCT -> {
// leave it alone for structs.
}
else -> throw FatalAstException("invalid array vardecl type ${decl.datatype}") else -> throw FatalAstException("invalid array vardecl type ${decl.datatype}")
} }
} }

View File

@ -40,7 +40,6 @@ class VariablesCreator(private val runtimeVariables: RuntimeVariables, private v
when (decl.type) { when (decl.type) {
// we can assume the value in the vardecl already has been converted into a constant LiteralValue here. // we can assume the value in the vardecl already has been converted into a constant LiteralValue here.
VarDeclType.VAR -> { VarDeclType.VAR -> {
println("$decl")
val value = RuntimeValue.from(decl.value as LiteralValue, heap) val value = RuntimeValue.from(decl.value as LiteralValue, heap)
runtimeVariables.define(decl.definingScope(), decl.name, value) runtimeVariables.define(decl.definingScope(), decl.name, value)
} }

View File

@ -5,38 +5,49 @@
sub start() { sub start() {
uword derp uword derp
ubyte[] v = [22,33,44]
Color foreground ; = [0,1,2] @todo init values Color foreground
Color background Color foreground2 = [11,22,33]
Color cursor
foreground.red=99 foreground.red = 111
background.blue=foreground.red ; foreground2.red = 111
;cursor=foreground ; @todo full by-value copy
c64scr.print_ub(foreground.red)
c64.CHROUT(':')
c64scr.print_ub(foreground.green)
c64.CHROUT(':')
c64scr.print_ub(foreground.blue)
c64.CHROUT('\n')
c64scr.print_ub(background.red)
c64.CHROUT(':')
c64scr.print_ub(background.green)
c64.CHROUT(':')
c64scr.print_ub(background.blue)
c64.CHROUT('\n')
c64scr.print_ub(cursor.red)
c64.CHROUT(':')
c64scr.print_ub(cursor.green)
c64.CHROUT(':')
c64scr.print_ub(cursor.blue)
c64.CHROUT('\n')
return
} }
; sub test() {
; Color foreground ; = [0,1,2] ;@todo init values
; Color background
; Color cursor
;
; foreground.red=99
; background.blue=foreground.red
;
; cursor = [1,2,3] ; assign all members at once
; cursor = v
; cursor=foreground ; @todo memberwise assignment
;
; c64scr.print_ub(foreground.red)
; c64.CHROUT(':')
; c64scr.print_ub(foreground.green)
; c64.CHROUT(':')
; c64scr.print_ub(foreground.blue)
; c64.CHROUT('\n')
; c64scr.print_ub(background.red)
; c64.CHROUT(':')
; c64scr.print_ub(background.green)
; c64.CHROUT(':')
; c64scr.print_ub(background.blue)
; c64.CHROUT('\n')
; c64scr.print_ub(cursor.red)
; c64.CHROUT(':')
; c64scr.print_ub(cursor.green)
; c64.CHROUT(':')
; c64scr.print_ub(cursor.blue)
; c64.CHROUT('\n')
;
; return
; }
struct Color { struct Color {
ubyte red ubyte red
ubyte green ubyte green