mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 08:29:25 +00:00
struct literals
This commit is contained in:
parent
17be722e2b
commit
61af72b906
@ -6,6 +6,10 @@ import prog8.ast.processing.IAstModifyingVisitor
|
||||
import prog8.ast.processing.IAstVisitor
|
||||
import prog8.ast.statements.*
|
||||
|
||||
|
||||
// TODO sealed classes instead??
|
||||
|
||||
|
||||
interface Node {
|
||||
val position: Position
|
||||
var parent: Node // will be linked correctly later (late init)
|
||||
|
@ -443,6 +443,10 @@ private fun prog8Parser.ExpressionContext.toAst() : IExpression {
|
||||
// the ConstantFolder takes care of that and converts the type if needed.
|
||||
ReferenceLiteralValue(DataType.ARRAY_UB, array = array, position = litval.toPosition())
|
||||
}
|
||||
litval.structliteral()!=null -> {
|
||||
val values = litval.structliteral().expression().map { it.toAst() }
|
||||
StructLiteralValue(values, litval.toPosition())
|
||||
}
|
||||
else -> throw FatalAstException("invalid parsed literal")
|
||||
}
|
||||
}
|
||||
@ -518,6 +522,9 @@ private fun prog8Parser.BooleanliteralContext.toAst() = when(text) {
|
||||
private fun prog8Parser.ArrayliteralContext.toAst() : Array<IExpression> =
|
||||
expression().map { it.toAst() }.toTypedArray()
|
||||
|
||||
private fun prog8Parser.StructliteralContext.toAst() : Array<IExpression> =
|
||||
expression().map { it.toAst() }.toTypedArray()
|
||||
|
||||
|
||||
private fun prog8Parser.If_stmtContext.toAst(): IfStatement {
|
||||
val condition = expression().toAst()
|
||||
|
@ -420,6 +420,26 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed
|
||||
}
|
||||
}
|
||||
|
||||
class StructLiteralValue(var values: List<IExpression>,
|
||||
override val position: Position): IExpression {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent=parent
|
||||
values.forEach { it.linkParents(this) }
|
||||
}
|
||||
|
||||
override fun constValue(program: Program): NumericLiteralValue? = null
|
||||
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun referencesIdentifiers(vararg name: String) = values.any { it.referencesIdentifiers(*name) }
|
||||
override fun inferType(program: Program) = DataType.STRUCT
|
||||
|
||||
override fun toString(): String {
|
||||
return "struct{ ${values.joinToString(", ")} }"
|
||||
}
|
||||
}
|
||||
|
||||
class ReferenceLiteralValue(val type: DataType, // only reference types allowed here
|
||||
val str: String? = null,
|
||||
val array: Array<IExpression>? = null,
|
||||
@ -428,9 +448,7 @@ class ReferenceLiteralValue(val type: DataType, // only reference types allo
|
||||
override val position: Position) : IExpression {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun referencesIdentifiers(vararg name: String): Boolean {
|
||||
return array?.any { it.referencesIdentifiers(*name) } ?: false
|
||||
}
|
||||
override fun referencesIdentifiers(vararg name: String) = array?.any { it.referencesIdentifiers(*name) } ?: false
|
||||
|
||||
val isString = type in StringDatatypes
|
||||
val isArray = type in ArrayDatatypes
|
||||
@ -443,8 +461,6 @@ class ReferenceLiteralValue(val type: DataType, // only reference types allo
|
||||
if(str==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId")
|
||||
in ArrayDatatypes ->
|
||||
if(array==null && heapId==null) throw FatalAstException("literal value missing arrayvalue/heapId")
|
||||
// DataType.STRUCT ->
|
||||
// if(struct==null && heapId==null) throw FatalAstException("literal value missing structvalue/heapId")
|
||||
else -> throw FatalAstException("invalid type $type")
|
||||
}
|
||||
if(array==null && str==null && heapId==null)
|
||||
|
@ -526,6 +526,29 @@ internal class AstChecker(private val program: Program,
|
||||
is NumericLiteralValue -> {
|
||||
checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue)
|
||||
}
|
||||
is StructLiteralValue -> {
|
||||
if(decl.datatype==DataType.STRUCT) {
|
||||
val struct = decl.struct!!
|
||||
val structLv = decl.value as StructLiteralValue
|
||||
if(struct.numberOfElements != structLv.values.size) {
|
||||
checkResult.add(ExpressionError("struct value has incorrect number of elements", structLv.position))
|
||||
return
|
||||
}
|
||||
for(value in structLv.values.zip(struct.statements)) {
|
||||
val memberdecl = value.second as VarDecl
|
||||
val constValue = value.first.constValue(program)
|
||||
if(constValue==null) {
|
||||
checkResult.add(ExpressionError("struct literal value for field '${memberdecl.name}' should consist of compile-time constants", value.first.position))
|
||||
return
|
||||
}
|
||||
val memberDt = memberdecl.datatype
|
||||
if(!checkValueTypeAndRange(memberDt, constValue)) {
|
||||
checkResult.add(ExpressionError("struct member value's type is not compatible with member field '${memberdecl.name}'", value.first.position))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!.javaClass.simpleName}")
|
||||
super.visit(decl)
|
||||
@ -1245,21 +1268,12 @@ internal class AstChecker(private val program: Program,
|
||||
DataType.STR -> sourceDatatype== DataType.STR
|
||||
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()
|
||||
if(sourceDatatype==DataType.STRUCT) {
|
||||
val structLv = sourceValue as StructLiteralValue
|
||||
val numValues = structLv.values.size
|
||||
val targetstruct = target.identifier!!.targetVarDecl(program.namespace)!!.struct!!
|
||||
return targetstruct.numberOfElements == sourceArraySize
|
||||
return targetstruct.numberOfElements == numValues
|
||||
}
|
||||
// if(sourceDatatype==DataType.STRUCT) {
|
||||
// val sourcename = (sourceValue as IdentifierReference).nameInSource
|
||||
// val vd1 = program.namespace.lookup(sourcename, target) as? VarDecl
|
||||
// val targetname = target.identifier!!.nameInSource
|
||||
// val vd2 = program.namespace.lookup(targetname, target) as? VarDecl
|
||||
// return vd1?.struct == vd2?.struct
|
||||
// }
|
||||
false
|
||||
}
|
||||
else -> checkResult.add(SyntaxError("cannot assign new value to variable of type $targetDatatype", position))
|
||||
|
@ -225,4 +225,9 @@ interface IAstModifyingVisitor {
|
||||
structDecl.statements = structDecl.statements.map{ it.accept(this) }.toMutableList()
|
||||
return structDecl
|
||||
}
|
||||
|
||||
fun visit(structLv: StructLiteralValue): IExpression {
|
||||
structLv.values = structLv.values.map { it.accept(this) }
|
||||
return structLv
|
||||
}
|
||||
}
|
||||
|
@ -173,4 +173,8 @@ interface IAstVisitor {
|
||||
fun visit(structDecl: StructDecl) {
|
||||
structDecl.statements.forEach { it.accept(this) }
|
||||
}
|
||||
|
||||
fun visit(structLv: StructLiteralValue) {
|
||||
structLv.values.forEach { it.accept(this) }
|
||||
}
|
||||
}
|
||||
|
@ -9,47 +9,41 @@ import prog8.ast.statements.*
|
||||
import prog8.functions.BuiltinFunctions
|
||||
|
||||
|
||||
fun flattenStructAssignment(structAssignment: Assignment, program: Program): List<Assignment> {
|
||||
fun flattenStructAssignmentFromIdentifier(structAssignment: Assignment, program: Program): List<Assignment> {
|
||||
val identifier = structAssignment.target.identifier!!
|
||||
val identifierName = identifier.nameInSource.single()
|
||||
val targetVar = identifier.targetVarDecl(program.namespace)!!
|
||||
val struct = targetVar.struct!!
|
||||
val sourceVar = (structAssignment.value as IdentifierReference).targetVarDecl(program.namespace)!!
|
||||
if(!sourceVar.isArray && sourceVar.struct==null)
|
||||
throw FatalAstException("can only assign arrays or structs to structs")
|
||||
if(sourceVar.isArray) {
|
||||
val sourceArray = (sourceVar.value as ReferenceLiteralValue).array!!
|
||||
return struct.statements.zip(sourceArray).map { member ->
|
||||
val decl = member.first as VarDecl
|
||||
val mangled = mangledStructMemberName(identifierName, decl.name)
|
||||
val idref = IdentifierReference(listOf(mangled), structAssignment.position)
|
||||
val assign = Assignment(AssignTarget(null, idref, null, null, structAssignment.position),
|
||||
null, member.second, member.second.position)
|
||||
assign.linkParents(structAssignment)
|
||||
assign
|
||||
when {
|
||||
structAssignment.value is IdentifierReference -> {
|
||||
val sourceVar = (structAssignment.value as IdentifierReference).targetVarDecl(program.namespace)!!
|
||||
if (sourceVar.struct == null)
|
||||
throw FatalAstException("can only assign arrays or structs to structs")
|
||||
// struct memberwise copy
|
||||
val sourceStruct = sourceVar.struct!!
|
||||
if(sourceStruct!==targetVar.struct) {
|
||||
// structs are not the same in assignment
|
||||
return listOf() // error will be printed elsewhere
|
||||
}
|
||||
return struct.statements.zip(sourceStruct.statements).map { member ->
|
||||
val targetDecl = member.first as VarDecl
|
||||
val sourceDecl = member.second as VarDecl
|
||||
if(targetDecl.name != sourceDecl.name)
|
||||
throw FatalAstException("struct member mismatch")
|
||||
val mangled = mangledStructMemberName(identifierName, targetDecl.name)
|
||||
val idref = IdentifierReference(listOf(mangled), structAssignment.position)
|
||||
val sourcemangled = mangledStructMemberName(sourceVar.name, sourceDecl.name)
|
||||
val sourceIdref = IdentifierReference(listOf(sourcemangled), structAssignment.position)
|
||||
val assign = Assignment(AssignTarget(null, idref, null, null, structAssignment.position),
|
||||
null, sourceIdref, member.second.position)
|
||||
assign.linkParents(structAssignment)
|
||||
assign
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// struct memberwise copy
|
||||
val sourceStruct = sourceVar.struct!!
|
||||
if(sourceStruct!==targetVar.struct) {
|
||||
// structs are not the same in assignment
|
||||
return listOf() // error will be printed elsewhere
|
||||
}
|
||||
return struct.statements.zip(sourceStruct.statements).map { member ->
|
||||
val targetDecl = member.first as VarDecl
|
||||
val sourceDecl = member.second as VarDecl
|
||||
if(targetDecl.name != sourceDecl.name)
|
||||
throw FatalAstException("struct member mismatch")
|
||||
val mangled = mangledStructMemberName(identifierName, targetDecl.name)
|
||||
val idref = IdentifierReference(listOf(mangled), structAssignment.position)
|
||||
val sourcemangled = mangledStructMemberName(sourceVar.name, sourceDecl.name)
|
||||
val sourceIdref = IdentifierReference(listOf(sourcemangled), structAssignment.position)
|
||||
val assign = Assignment(AssignTarget(null, idref, null, null, structAssignment.position),
|
||||
null, sourceIdref, member.second.position)
|
||||
assign.linkParents(structAssignment)
|
||||
assign
|
||||
structAssignment.value is StructLiteralValue -> {
|
||||
throw IllegalArgumentException("not going to flatten a structLv assignment here")
|
||||
}
|
||||
else -> throw FatalAstException("strange struct value")
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,52 +209,59 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
|
||||
}
|
||||
|
||||
override fun visit(assignment: Assignment): IStatement {
|
||||
val assg = super.visit(assignment)
|
||||
if(assg !is Assignment)
|
||||
return assg
|
||||
|
||||
// see if a typecast is needed to convert the value's type into the proper target type
|
||||
val valuetype = assignment.value.inferType(program)
|
||||
val targettype = assignment.target.inferType(program, assignment)
|
||||
val valuetype = assg.value.inferType(program)
|
||||
val targettype = assg.target.inferType(program, assg)
|
||||
if(targettype!=null && valuetype!=null) {
|
||||
if(valuetype!=targettype) {
|
||||
if (valuetype isAssignableTo targettype) {
|
||||
assignment.value = TypecastExpression(assignment.value, targettype, true, assignment.value.position)
|
||||
assignment.value.linkParents(assignment)
|
||||
assg.value = TypecastExpression(assg.value, targettype, true, assg.value.position)
|
||||
assg.value.linkParents(assg)
|
||||
}
|
||||
// if they're not assignable, we'll get a proper error later from the AstChecker
|
||||
}
|
||||
}
|
||||
|
||||
// struct assignments will be flattened
|
||||
// struct assignments will be flattened (if it's not a struct literal)
|
||||
if(valuetype==DataType.STRUCT && targettype==DataType.STRUCT) {
|
||||
val assignments = flattenStructAssignment(assignment, program)
|
||||
if(assg.value is StructLiteralValue)
|
||||
return assg // do NOT flatten it at this point!! (the compiler will take care if it, later, if needed)
|
||||
|
||||
val assignments = flattenStructAssignmentFromIdentifier(assg, program) // 'structvar1 = structvar2'
|
||||
if(assignments.isEmpty()) {
|
||||
// something went wrong (probably incompatible struct types)
|
||||
// we'll get an error later from the AstChecker
|
||||
return assignment
|
||||
return assg
|
||||
} else {
|
||||
val scope = AnonymousScope(assignments.toMutableList(), assignment.position)
|
||||
scope.linkParents(assignment.parent)
|
||||
val scope = AnonymousScope(assignments.toMutableList(), assg.position)
|
||||
scope.linkParents(assg.parent)
|
||||
return scope
|
||||
}
|
||||
}
|
||||
|
||||
if(assignment.aug_op!=null) {
|
||||
// transform augmented assignment into normal assignment so we have one case less to deal with later
|
||||
if(assg.aug_op!=null) {
|
||||
// transform augmented assg into normal assg so we have one case less to deal with later
|
||||
val newTarget: IExpression =
|
||||
when {
|
||||
assignment.target.register != null -> RegisterExpr(assignment.target.register!!, assignment.target.position)
|
||||
assignment.target.identifier != null -> assignment.target.identifier!!
|
||||
assignment.target.arrayindexed != null -> assignment.target.arrayindexed!!
|
||||
assignment.target.memoryAddress != null -> DirectMemoryRead(assignment.target.memoryAddress!!.addressExpression, assignment.value.position)
|
||||
else -> throw FatalAstException("strange assignment")
|
||||
assg.target.register != null -> RegisterExpr(assg.target.register!!, assg.target.position)
|
||||
assg.target.identifier != null -> assg.target.identifier!!
|
||||
assg.target.arrayindexed != null -> assg.target.arrayindexed!!
|
||||
assg.target.memoryAddress != null -> DirectMemoryRead(assg.target.memoryAddress!!.addressExpression, assg.value.position)
|
||||
else -> throw FatalAstException("strange assg")
|
||||
}
|
||||
|
||||
val expression = BinaryExpression(newTarget, assignment.aug_op.substringBeforeLast('='), assignment.value, assignment.position)
|
||||
expression.linkParents(assignment.parent)
|
||||
val convertedAssignment = Assignment(assignment.target, null, expression, assignment.position)
|
||||
convertedAssignment.linkParents(assignment.parent)
|
||||
val expression = BinaryExpression(newTarget, assg.aug_op.substringBeforeLast('='), assg.value, assg.position)
|
||||
expression.linkParents(assg.parent)
|
||||
val convertedAssignment = Assignment(assg.target, null, expression, assg.position)
|
||||
convertedAssignment.linkParents(assg.parent)
|
||||
return super.visit(convertedAssignment)
|
||||
}
|
||||
|
||||
return super.visit(assignment)
|
||||
return assg
|
||||
}
|
||||
|
||||
override fun visit(functionCallStatement: FunctionCallStatement): IStatement {
|
||||
@ -319,28 +320,6 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
|
||||
}
|
||||
}
|
||||
|
||||
private fun sortConstantAssignmentSequence(first: Assignment, stmtIter: MutableIterator<IStatement>): Pair<List<Assignment>, IStatement?> {
|
||||
val sequence= mutableListOf(first)
|
||||
var trailing: IStatement? = null
|
||||
while(stmtIter.hasNext()) {
|
||||
val next = stmtIter.next()
|
||||
if(next is Assignment) {
|
||||
val constValue = next.value.constValue(program)
|
||||
if(constValue==null) {
|
||||
trailing = next
|
||||
break
|
||||
}
|
||||
sequence.add(next)
|
||||
}
|
||||
else {
|
||||
trailing=next
|
||||
break
|
||||
}
|
||||
}
|
||||
val sorted = sequence.sortedWith(compareBy({it.value.inferType(program)}, {it.target.shortString(true)}))
|
||||
return Pair(sorted, trailing)
|
||||
}
|
||||
|
||||
override fun visit(typecast: TypecastExpression): IExpression {
|
||||
// warn about any implicit type casts to Float, because that may not be intended
|
||||
if(typecast.implicit && typecast.type in setOf(DataType.FLOAT, DataType.ARRAY_F)) {
|
||||
@ -397,4 +376,42 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
|
||||
}
|
||||
super.visit(memwrite)
|
||||
}
|
||||
|
||||
override fun visit(structLv: StructLiteralValue): IExpression {
|
||||
val litval = super.visit(structLv)
|
||||
if(litval !is StructLiteralValue)
|
||||
return litval
|
||||
|
||||
val decl = litval.parent as? VarDecl
|
||||
if(decl != null) {
|
||||
val struct = decl.struct
|
||||
if(struct != null) {
|
||||
addTypecastsIfNeeded(litval, struct)
|
||||
}
|
||||
} else {
|
||||
val assign = litval.parent as? Assignment
|
||||
if (assign != null) {
|
||||
val decl2 = assign.target.identifier?.targetVarDecl(program.namespace)
|
||||
if(decl2 != null) {
|
||||
val struct = decl2.struct
|
||||
if(struct != null) {
|
||||
addTypecastsIfNeeded(litval, struct)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return litval
|
||||
}
|
||||
|
||||
private fun addTypecastsIfNeeded(structLv: StructLiteralValue, struct: StructDecl) {
|
||||
structLv.values = struct.statements.zip(structLv.values).map {
|
||||
val memberDt = (it.first as VarDecl).datatype
|
||||
val valueDt = it.second.inferType(program)
|
||||
if (valueDt != memberDt)
|
||||
TypecastExpression(it.second, memberDt, true, it.second.position)
|
||||
else
|
||||
it.second
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +225,7 @@ class VarDecl(val type: VarDeclType,
|
||||
DataType.FLOAT -> NumericLiteralValue(DataType.FLOAT, 0.0, position)
|
||||
else -> throw FatalAstException("can only set a default value for a numeric type")
|
||||
}
|
||||
val decl = VarDecl(type, declaredDatatype, zeropage, arraysize, name, structName, constValue, isArray, true, position)
|
||||
val decl = VarDecl(type, declaredDatatype, zeropage, arraysize, name, structName, constValue, isArray, false, position)
|
||||
if(parent!=null)
|
||||
decl.linkParents(parent)
|
||||
return decl
|
||||
@ -234,7 +234,7 @@ class VarDecl(val type: VarDeclType,
|
||||
fun flattenStructMembers(): MutableList<IStatement> {
|
||||
val result = struct!!.statements.withIndex().map {
|
||||
val member = it.value as VarDecl
|
||||
val initvalue = if(value!=null) (value as ReferenceLiteralValue).array!![it.index] else null
|
||||
val initvalue = if(value!=null) (value as StructLiteralValue).values[it.index] else null
|
||||
VarDecl(
|
||||
VarDeclType.VAR,
|
||||
member.datatype,
|
||||
|
@ -1,16 +1,13 @@
|
||||
package prog8.compiler
|
||||
|
||||
import prog8.ast.*
|
||||
import prog8.ast.antlr.escape
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.IStatement
|
||||
import prog8.ast.Module
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.processing.IAstVisitor
|
||||
import prog8.ast.statements.*
|
||||
|
||||
class AstToSourceCode(val output: (text: String) -> Unit): IAstVisitor {
|
||||
class AstToSourceCode(val output: (text: String) -> Unit, val program: Program): IAstVisitor {
|
||||
var scopelevel = 0
|
||||
|
||||
fun indent(s: String) = " ".repeat(scopelevel) + s
|
||||
@ -261,30 +258,42 @@ class AstToSourceCode(val output: (text: String) -> Unit): IAstVisitor {
|
||||
refLiteral.isString -> output("\"${escape(refLiteral.str!!)}\"")
|
||||
refLiteral.isArray -> {
|
||||
if(refLiteral.array!=null) {
|
||||
var counter = 0
|
||||
output("[")
|
||||
scopelevel++
|
||||
for (v in refLiteral.array) {
|
||||
v.accept(this)
|
||||
if (v !== refLiteral.array.last())
|
||||
output(", ")
|
||||
counter++
|
||||
if(counter > 16) {
|
||||
outputln("")
|
||||
outputi("")
|
||||
counter=0
|
||||
}
|
||||
}
|
||||
scopelevel--
|
||||
output("]")
|
||||
outputListMembers(refLiteral.array.asSequence(), '[', ']')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun outputListMembers(array: Sequence<IExpression>, openchar: Char, closechar: Char) {
|
||||
var counter = 0
|
||||
output(openchar.toString())
|
||||
scopelevel++
|
||||
for (v in array) {
|
||||
v.accept(this)
|
||||
if (v !== array.last())
|
||||
output(", ")
|
||||
counter++
|
||||
if (counter > 16) {
|
||||
outputln("")
|
||||
outputi("")
|
||||
counter = 0
|
||||
}
|
||||
}
|
||||
scopelevel--
|
||||
output(closechar.toString())
|
||||
}
|
||||
|
||||
override fun visit(assignment: Assignment) {
|
||||
if(assignment is VariableInitializationAssignment) {
|
||||
val targetVar = assignment.target.identifier?.targetVarDecl(program.namespace)
|
||||
if(targetVar?.struct != null) {
|
||||
// skip STRUCT init assignments
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
assignment.target.accept(this)
|
||||
if(assignment.aug_op!=null)
|
||||
if (assignment.aug_op != null)
|
||||
output(" ${assignment.aug_op} ")
|
||||
else
|
||||
output(" = ")
|
||||
@ -432,6 +441,11 @@ class AstToSourceCode(val output: (text: String) -> Unit): IAstVisitor {
|
||||
whenChoice.statements.accept(this)
|
||||
outputln("")
|
||||
}
|
||||
|
||||
override fun visit(structLv: StructLiteralValue) {
|
||||
outputListMembers(structLv.values.asSequence(), '{', '}')
|
||||
}
|
||||
|
||||
override fun visit(nopStatement: NopStatement) {
|
||||
output("; NOP @ ${nopStatement.position} $nopStatement")
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import prog8.ast.*
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.base.RegisterOrPair.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.processing.flattenStructAssignment
|
||||
import prog8.ast.statements.*
|
||||
import prog8.compiler.intermediate.IntermediateProgram
|
||||
import prog8.compiler.intermediate.Opcode
|
||||
@ -593,6 +592,7 @@ internal class Compiler(private val program: Program) {
|
||||
is TypecastExpression -> translate(expr)
|
||||
is DirectMemoryRead -> translate(expr)
|
||||
is AddressOf -> translate(expr)
|
||||
is StructLiteralValue -> throw CompilerException("a struct Lv should have been flattened as assignments")
|
||||
else -> {
|
||||
val lv = expr.constValue(program) ?: throw CompilerException("constant expression required, not $expr")
|
||||
when(lv.type) {
|
||||
@ -1404,6 +1404,26 @@ internal class Compiler(private val program: Program) {
|
||||
|
||||
private fun translate(stmt: Assignment) {
|
||||
prog.line(stmt.position)
|
||||
if(stmt.value is StructLiteralValue) {
|
||||
// flatten into individual struct member assignments
|
||||
val identifier = stmt.target.identifier!!
|
||||
val identifierName = identifier.nameInSource.single()
|
||||
val targetVar = identifier.targetVarDecl(program.namespace)!!
|
||||
val struct = targetVar.struct!!
|
||||
val sourcevalues = (stmt.value as StructLiteralValue).values
|
||||
val assignments = struct.statements.zip(sourcevalues).map { member ->
|
||||
val decl = member.first as VarDecl
|
||||
val mangled = mangledStructMemberName(identifierName, decl.name)
|
||||
val idref = IdentifierReference(listOf(mangled), stmt.position)
|
||||
val assign = Assignment(AssignTarget(null, idref, null, null, stmt.position),
|
||||
null, member.second, member.second.position)
|
||||
assign.linkParents(stmt)
|
||||
assign
|
||||
}
|
||||
assignments.forEach { translate(it) }
|
||||
return
|
||||
}
|
||||
|
||||
translate(stmt.value)
|
||||
|
||||
val valueDt = stmt.value.inferType(program)
|
||||
@ -1448,11 +1468,6 @@ 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.
|
||||
flattenStructAssignment(stmt, program).forEach { translate(it) }
|
||||
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")
|
||||
|
@ -17,7 +17,6 @@ import prog8.parser.importModule
|
||||
import prog8.parser.moduleName
|
||||
import java.io.File
|
||||
import java.io.PrintStream
|
||||
import java.lang.Exception
|
||||
import java.nio.file.Path
|
||||
import kotlin.system.exitProcess
|
||||
import kotlin.system.measureTimeMillis
|
||||
@ -146,7 +145,7 @@ fun compileProgram(filepath: Path,
|
||||
|
||||
fun printAst(programAst: Program) {
|
||||
println()
|
||||
val printer = AstToSourceCode(::print)
|
||||
val printer = AstToSourceCode(::print, programAst)
|
||||
printer.visit(programAst)
|
||||
println()
|
||||
}
|
||||
|
@ -261,7 +261,7 @@ private fun builtinLen(args: List<IExpression>, position: Position, program: Pro
|
||||
return NumericLiteralValue.optimalInteger(arraySize, position)
|
||||
if(args[0] !is IdentifierReference)
|
||||
throw SyntaxError("len argument should be an identifier, but is ${args[0]}", position)
|
||||
val target = (args[0] as IdentifierReference).targetStatement(program.namespace) as VarDecl
|
||||
val target = (args[0] as IdentifierReference).targetVarDecl(program.namespace)!!
|
||||
|
||||
return when(target.datatype) {
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||
|
@ -12,11 +12,18 @@
|
||||
}
|
||||
|
||||
sub start() {
|
||||
Color rgb1
|
||||
Color rgb1 = {1,2,3.44}
|
||||
Color rgb2
|
||||
|
||||
rgb2 = {22233, 33, 1.1} ; @todo implicit type conversion
|
||||
c64scr.print_b(rgb1.green)
|
||||
c64.CHROUT('\n')
|
||||
c64scr.print_b(rgb2.green)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
rgb1=rgb2
|
||||
c64scr.print_b(rgb1.green)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -214,7 +214,9 @@ wordsuffix : '.w' ;
|
||||
|
||||
booleanliteral : 'true' | 'false' ;
|
||||
|
||||
arrayliteral : '[' EOL? expression (',' EOL? expression)* EOL? ']' ; // you can split the array list over several lines
|
||||
arrayliteral : '[' EOL? expression (',' EOL? expression)* EOL? ']' ; // you can split the values over several lines
|
||||
|
||||
structliteral : '{' EOL? expression (',' EOL? expression)* EOL? '}' ; // you can split the values over several lines
|
||||
|
||||
stringliteral : STRING ;
|
||||
|
||||
@ -222,6 +224,7 @@ charliteral : SINGLECHAR ;
|
||||
|
||||
floatliteral : FLOAT_NUMBER ;
|
||||
|
||||
|
||||
literalvalue :
|
||||
integerliteral
|
||||
| booleanliteral
|
||||
@ -229,6 +232,7 @@ literalvalue :
|
||||
| stringliteral
|
||||
| charliteral
|
||||
| floatliteral
|
||||
| structliteral
|
||||
;
|
||||
|
||||
inlineasm : '%asm' INLINEASMBLOCK;
|
||||
|
Loading…
Reference in New Issue
Block a user