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) {
in NumericDatatypes -> null
in StringDatatypes -> DataType.UBYTE
DataType.ARRAY_UB -> DataType.UBYTE
DataType.ARRAY_B -> DataType.BYTE
DataType.ARRAY_UW -> DataType.UWORD
DataType.ARRAY_W -> DataType.WORD
DataType.ARRAY_F -> DataType.FLOAT
in ArrayDatatypes -> ArrayElementTypes[target.datatype]
else -> throw FatalAstException("invalid dt")
}
}

View File

@ -406,11 +406,13 @@ internal class AstChecker(private val program: Program,
if(targetDatatype!=null) {
val constVal = assignment.value.constValue(program)
if(constVal!=null) {
val arrayspec = if(target.identifier!=null) {
val targetVar = program.namespace.lookup(target.identifier.nameInSource, assignment) as? VarDecl
targetVar?.arraysize
} else null
checkValueTypeAndRange(targetDatatype,
val targetVar =
if(target.identifier!=null)
program.namespace.lookup(target.identifier.nameInSource, assignment) as? VarDecl
else
null
val arrayspec = if(target.identifier!=null) targetVar?.arraysize else null
checkValueTypeAndRange(targetDatatype, targetVar?.struct,
arrayspec ?: ArrayIndex(LiteralValue.optimalInteger(-1, assignment.position), assignment.position),
constVal, program.heap)
} else {
@ -424,8 +426,9 @@ internal class AstChecker(private val program: Program,
else
checkResult.add(ExpressionError("assignment value is invalid or has no proper datatype", assignment.value.position))
}
else
checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, target, assignment.position)
else {
checkAssignmentCompatible(targetDatatype, target, sourceDatatype, assignment.value, assignment.position)
}
}
}
return assignment
@ -521,7 +524,7 @@ internal class AstChecker(private val program: Program,
else
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 -> {
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)
else
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)
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 {
checkResult.add(ExpressionError(msg, value.position))
return false
@ -1138,9 +1142,20 @@ internal class AstChecker(private val program: Program,
return err("invalid float array initialization value ${value.type}, expected $targetDt")
}
DataType.STRUCT -> {
if(value.type!=DataType.STRUCT)
return err("cannot assign a normal value to a struct")
TODO("check struct, $value ")
if(value.type in ArrayDatatypes) {
if(value.arrayvalue!!.size != struct!!.numberOfElements)
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
@ -1196,9 +1211,9 @@ internal class AstChecker(private val program: Program,
}
private fun checkAssignmentCompatible(targetDatatype: DataType,
target: AssignTarget,
sourceDatatype: DataType,
sourceValue: IExpression,
target: AssignTarget,
position: Position) : Boolean {
if(sourceValue is RangeExpr)
@ -1214,6 +1229,13 @@ internal class AstChecker(private val program: Program,
DataType.STR_S -> sourceDatatype== DataType.STR_S
DataType.STRUCT -> {
// 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) {
// val sourcename = (sourceValue as IdentifierReference).nameInSource
// 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.
// 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)
val variable = VarDecl(VarDeclType.VAR, literalValue.type, false, null, "$autoHeapValuePrefix${literalValue.heapId}", null, literalValue,
isArray = false, hiddenButDoNotRemove = false, position = literalValue.position)
val declaredType = if(literalValue.isArray) ArrayElementTypes.getValue(literalValue.type) else literalValue.type
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)
}
return super.visit(literalValue)

View File

@ -6,6 +6,7 @@ import prog8.ast.expressions.*
import prog8.ast.processing.IAstModifyingVisitor
import prog8.ast.processing.IAstVisitor
import prog8.compiler.HeapValues
import prog8.compiler.target.c64.Mflpt5
class BuiltinFunctionStatementPlaceholder(val name: String, override val position: Position) : IStatement {
@ -162,7 +163,7 @@ class VarDecl(val type: VarDeclType,
DataType.FLOAT -> DataType.ARRAY_F
else -> {
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) }
}
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: IAstModifyingVisitor) = visitor.visit(this)
}

View File

@ -103,10 +103,10 @@ class AstToSourceCode(val output: (text: String) -> Unit): IAstVisitor {
}
override fun visit(decl: VarDecl) {
if(decl.hiddenButDoNotRemove) {
// skip autogenerated vardecl
return
}
// if(decl.hiddenButDoNotRemove) {
// // skip autogenerated vardecl
// return
// }
when(decl.type) {
VarDeclType.VAR -> {}
@ -114,6 +114,7 @@ class AstToSourceCode(val output: (text: String) -> Unit): IAstVisitor {
VarDeclType.MEMORY -> output("&")
VarDeclType.STRUCT -> output("${decl.struct!!.name} ")
}
output(decl.struct?.name ?: "")
output(datatypeString(decl.datatype))
if(decl.arraysize!=null) {
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")
}
}
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 ArrayDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
else -> throw CompilerException("weird/unknown targetdt")
@ -1499,7 +1520,9 @@ internal class Compiler(private val program: Program) {
prog.instr(opcode, RuntimeValue(DataType.UWORD, address))
}
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}")
}

View File

@ -175,6 +175,9 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
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}")
}
}

View File

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

View File

@ -5,38 +5,49 @@
sub start() {
uword derp
ubyte[] v = [22,33,44]
Color foreground ; = [0,1,2] @todo init values
Color background
Color cursor
Color foreground
Color foreground2 = [11,22,33]
foreground.red=99
background.blue=foreground.red
;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
foreground.red = 111
; foreground2.red = 111
}
; 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 {
ubyte red
ubyte green