This commit is contained in:
Irmen de Jong 2019-07-15 02:26:51 +02:00
parent d5b12fb01d
commit 78d7849197
11 changed files with 121 additions and 141 deletions

View File

@ -15,11 +15,6 @@ import java.io.File
internal class AstChecker(private val program: Program, internal class AstChecker(private val program: Program,
private val compilerOptions: CompilationOptions) : IAstVisitor { private val compilerOptions: CompilationOptions) : IAstVisitor {
private val checkResult: MutableList<AstException> = mutableListOf() private val checkResult: MutableList<AstException> = mutableListOf()
private val heapIdSentinel: Int
init {
val stringSentinel = program.heap.allEntries().firstOrNull {it.value.str==""}
heapIdSentinel = stringSentinel?.key ?: program.heap.addString(DataType.STR, "")
}
fun result(): List<AstException> { fun result(): List<AstException> {
return checkResult return checkResult
@ -358,13 +353,13 @@ internal class AstChecker(private val program: Program,
override fun visit(assignTarget: AssignTarget) { override fun visit(assignTarget: AssignTarget) {
val memAddr = assignTarget.memoryAddress?.addressExpression?.constValue(program)?.number?.toInt() val memAddr = assignTarget.memoryAddress?.addressExpression?.constValue(program)?.number?.toInt()
if(memAddr!=null) { if (memAddr != null) {
if(memAddr<0 || memAddr>=65536) if (memAddr < 0 || memAddr >= 65536)
checkResult.add(ExpressionError("address out of range", assignTarget.position)) checkResult.add(ExpressionError("address out of range", assignTarget.position))
} }
val assignment = assignTarget.parent as Assignment val assignment = assignTarget.parent as IStatement
if(assignTarget.identifier!=null) { if (assignTarget.identifier != null) {
val targetName = assignTarget.identifier.nameInSource val targetName = assignTarget.identifier.nameInSource
val targetSymbol = program.namespace.lookup(targetName, assignment) val targetSymbol = program.namespace.lookup(targetName, assignment)
when (targetSymbol) { when (targetSymbol) {
@ -377,7 +372,7 @@ internal class AstChecker(private val program: Program,
return return
} }
else -> { else -> {
if(targetSymbol.type == VarDeclType.CONST) { if (targetSymbol.type == VarDeclType.CONST) {
checkResult.add(ExpressionError("cannot assign new value to a constant", assignment.position)) checkResult.add(ExpressionError("cannot assign new value to a constant", assignment.position))
return return
} }
@ -385,15 +380,17 @@ internal class AstChecker(private val program: Program,
} }
} }
if(assignment.aug_op!=null) if (assignment is Assignment) {
throw FatalAstException("augmented assignment should have been converted into normal assignment")
val targetDatatype = assignTarget.inferType(program, assignment) if (assignment.aug_op != null)
if(targetDatatype!=null) { throw FatalAstException("augmented assignment should have been converted into normal assignment")
val constVal = assignment.value.constValue(program)
if(constVal!=null) { val targetDatatype = assignTarget.inferType(program, assignment)
checkValueTypeAndRange(targetDatatype, constVal) if (targetDatatype != null) {
// TODO what about arrays etc: val constVal = assignment.value.constValue(program)
if (constVal != null) {
checkValueTypeAndRange(targetDatatype, constVal)
// TODO what about arrays etc:
// val targetVar = // val targetVar =
// if(target.identifier!=null) // if(target.identifier!=null)
// program.namespace.lookup(target.identifier.nameInSource, assignment) as? VarDecl // program.namespace.lookup(target.identifier.nameInSource, assignment) as? VarDecl
@ -403,19 +400,18 @@ internal class AstChecker(private val program: Program,
// checkValueTypeAndRange(targetDatatype, targetVar?.struct, // checkValueTypeAndRange(targetDatatype, targetVar?.struct,
// arrayspec ?: ArrayIndex(NumericLiteralValue.optimalInteger(-1, assignment.position), assignment.position), // arrayspec ?: ArrayIndex(NumericLiteralValue.optimalInteger(-1, assignment.position), assignment.position),
// constVal, program.heap) // constVal, program.heap)
} else { } else {
val sourceDatatype: DataType? = assignment.value.inferType(program) val sourceDatatype: DataType? = assignment.value.inferType(program)
if(sourceDatatype==null) { if (sourceDatatype == null) {
if (assignment.value is FunctionCall) { if (assignment.value is FunctionCall) {
val targetStmt = (assignment.value as FunctionCall).target.targetStatement(program.namespace) val targetStmt = (assignment.value as FunctionCall).target.targetStatement(program.namespace)
if(targetStmt!=null) if (targetStmt != null)
checkResult.add(ExpressionError("function call doesn't return a suitable value to use in assignment", assignment.value.position)) checkResult.add(ExpressionError("function call doesn't return a suitable value to use in assignment", assignment.value.position))
} else
checkResult.add(ExpressionError("assignment value is invalid or has no proper datatype", assignment.value.position))
} else {
checkAssignmentCompatible(targetDatatype, assignTarget, sourceDatatype, assignment.value, assignment.position)
} }
else
checkResult.add(ExpressionError("assignment value is invalid or has no proper datatype", assignment.value.position))
}
else {
checkAssignmentCompatible(targetDatatype, assignTarget, sourceDatatype, assignment.value, assignment.position)
} }
} }
} }

View File

@ -2,7 +2,6 @@ package prog8.ast.processing
import prog8.ast.* import prog8.ast.*
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.base.autoHeapValuePrefix
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.functions.BuiltinFunctions import prog8.functions.BuiltinFunctions
@ -12,7 +11,8 @@ internal class AstIdentifiersChecker(private val namespace: INameScope) : IAstMo
private val checkResult: MutableList<AstException> = mutableListOf() private val checkResult: MutableList<AstException> = mutableListOf()
private var blocks = mutableMapOf<String, Block>() private var blocks = mutableMapOf<String, Block>()
internal val anonymousVariablesFromHeap = mutableMapOf<String, Pair<ReferenceLiteralValue, VarDecl>>() internal val anonymousVariablesFromHeap = mutableMapOf<String, Pair<ReferenceLiteralValue, VarDecl>>() // TODO
private val vardeclsToAdd = mutableMapOf<INameScope, MutableList<VarDecl>>()
internal fun result(): List<AstException> { internal fun result(): List<AstException> {
return checkResult return checkResult
@ -23,8 +23,14 @@ internal class AstIdentifiersChecker(private val namespace: INameScope) : IAstMo
} }
override fun visit(module: Module) { override fun visit(module: Module) {
vardeclsToAdd.clear()
blocks.clear() // blocks may be redefined within a different module blocks.clear() // blocks may be redefined within a different module
super.visit(module) super.visit(module)
// add any new vardecls to the various scopes
for((where, decls) in vardeclsToAdd) {
where.statements.addAll(0, decls)
decls.forEach { it.linkParents(where as Node) }
}
} }
override fun visit(block: Block): IStatement { override fun visit(block: Block): IStatement {
@ -208,20 +214,13 @@ internal class AstIdentifiersChecker(private val namespace: INameScope) : IAstMo
} }
override fun visit(refLiteral: ReferenceLiteralValue): ReferenceLiteralValue { override fun visit(refLiteral: ReferenceLiteralValue): ReferenceLiteralValue {
if(refLiteral.heapId!=null && refLiteral.parent !is VarDecl) { if(refLiteral.parent !is VarDecl) {
// a literal value that's not declared as a variable, which refers to something on the heap. // a referencetype literal value that's not declared as a variable
// 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)
val declaredType = if(refLiteral.isArray) ArrayElementTypes.getValue(refLiteral.type) else refLiteral.type val declaredType = if(refLiteral.isArray) ArrayElementTypes.getValue(refLiteral.type) else refLiteral.type
val variable = VarDecl(VarDeclType.VAR, val variable = VarDecl.createAuto(refLiteral)
declaredType, addVarDecl(refLiteral.definingScope(), variable)
ZeropageWish.NOT_IN_ZEROPAGE, // TODO anonymousVariablesFromHeap[variable.name] = Pair(refLiteral, variable)
null,
"$autoHeapValuePrefix${refLiteral.heapId}",
null,
refLiteral,
isArray = refLiteral.isArray, autogeneratedDontRemove = true, position = refLiteral.position)
anonymousVariablesFromHeap[variable.name] = Pair(refLiteral, variable)
} }
return super.visit(refLiteral) return super.visit(refLiteral)
} }
@ -243,4 +242,12 @@ internal class AstIdentifiersChecker(private val namespace: INameScope) : IAstMo
return super.visit(structDecl) return super.visit(structDecl)
} }
private fun addVarDecl(scope: INameScope, variable: VarDecl) {
if(scope !in vardeclsToAdd)
vardeclsToAdd[scope] = mutableListOf()
val declList = vardeclsToAdd.getValue(scope)
if(declList.all{it.name!=variable.name})
declList.add(variable)
}
} }

View File

@ -2,7 +2,6 @@ package prog8.ast.processing
import prog8.ast.* import prog8.ast.*
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.base.autoHeapValuePrefix
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
@ -24,7 +23,6 @@ internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope
override fun visit(module: Module) { override fun visit(module: Module) {
vardeclsToAdd.clear() vardeclsToAdd.clear()
super.visit(module) super.visit(module)
// add any new vardecls to the various scopes // add any new vardecls to the various scopes
for((where, decls) in vardeclsToAdd) { for((where, decls) in vardeclsToAdd) {
where.statements.addAll(0, decls) where.statements.addAll(0, decls)
@ -96,17 +94,15 @@ internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope
} }
else if(strvalue!=null) { else if(strvalue!=null) {
if(strvalue.isString) { if(strvalue.isString) {
// add a vardecl so that the autovar can be resolved in later lookups
val variable = VarDecl.createAuto(strvalue)
addVarDecl(strvalue.definingScope(), variable)
// replace the argument with &autovar // replace the argument with &autovar
val autoVarName = "$autoHeapValuePrefix${strvalue.heapId}" val autoHeapvarRef = IdentifierReference(listOf(variable.name), strvalue.position)
val autoHeapvarRef = IdentifierReference(listOf(autoVarName), strvalue.position)
val pointerExpr = AddressOf(autoHeapvarRef, strvalue.position) val pointerExpr = AddressOf(autoHeapvarRef, strvalue.position)
pointerExpr.scopedname = parent.makeScopedName(autoVarName) pointerExpr.scopedname = parent.makeScopedName(variable.name)
pointerExpr.linkParents(arglist[argparam.first.index].parent) pointerExpr.linkParents(arglist[argparam.first.index].parent)
arglist[argparam.first.index] = pointerExpr arglist[argparam.first.index] = pointerExpr
// add a vardecl so that the autovar can be resolved in later lookups
val variable = VarDecl(VarDeclType.VAR, strvalue.type, ZeropageWish.NOT_IN_ZEROPAGE, null, autoVarName, null, strvalue,
isArray = false, autogeneratedDontRemove = false, position = strvalue.position)
addVarDecl(strvalue.definingScope(), variable)
} }
} }
} }

View File

@ -162,6 +162,14 @@ class VarDecl(val type: VarDeclType,
override val expensiveToInline override val expensiveToInline
get() = value!=null && value !is NumericLiteralValue get() = value!=null && value !is NumericLiteralValue
companion object {
fun createAuto(refLv: ReferenceLiteralValue): VarDecl {
val autoVarName = "$autoHeapValuePrefix${refLv.heapId}"
return VarDecl(VarDeclType.VAR, refLv.type, ZeropageWish.NOT_IN_ZEROPAGE, null, autoVarName, null, refLv,
isArray = false, autogeneratedDontRemove = true, position = refLv.position)
}
}
val datatypeErrors = mutableListOf<SyntaxError>() // don't crash at init time, report them in the AstChecker val datatypeErrors = mutableListOf<SyntaxError>() // don't crash at init time, report them in the AstChecker
val datatype = val datatype =
if (!isArray) declaredDatatype if (!isArray) declaredDatatype

View File

@ -116,7 +116,7 @@ class HeapValues {
fun get(heapId: Int): HeapValue { fun get(heapId: Int): HeapValue {
return heap[heapId] ?: return heap[heapId] ?:
throw IllegalArgumentException("heapId not found in heap") throw IllegalArgumentException("heapId $heapId not found in heap")
} }
fun allEntries() = heap.entries fun allEntries() = heap.entries
@ -746,7 +746,8 @@ internal class Compiler(private val program: Program) {
val arg=args.single() val arg=args.single()
when (arg.inferType(program)) { when (arg.inferType(program)) {
DataType.STR, DataType.STR_S -> createSyscall("${funcname}_str") DataType.STR, DataType.STR_S -> createSyscall("${funcname}_str")
else -> throw CompilerException("wrong datatype for len()") in ArrayDatatypes -> throw CompilerException("len() of an array type should have been const-folded")
else -> throw CompilerException("wrong datatype for len() $arg")
} }
} }
"any", "all" -> { "any", "all" -> {

View File

@ -417,10 +417,10 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
RuntimeValue(decl.datatype, heapId = litval.heapId) RuntimeValue(decl.datatype, heapId = litval.heapId)
} }
in ArrayDatatypes -> { in ArrayDatatypes -> {
val litval = (decl.value as ReferenceLiteralValue) val litval = (decl.value as? ReferenceLiteralValue)
if(litval.heapId==null) if(litval!=null && litval.heapId==null)
throw CompilerException("array should already be in the heap") throw CompilerException("array should already be in the heap")
RuntimeValue(decl.datatype, heapId = litval.heapId) RuntimeValue(decl.datatype, heapId = litval?.heapId ?: -999)
} }
DataType.STRUCT -> { DataType.STRUCT -> {
// struct variables have been flattened already // struct variables have been flattened already

View File

@ -7,6 +7,7 @@ import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.expressions.ReferenceLiteralValue import prog8.ast.expressions.ReferenceLiteralValue
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
import prog8.compiler.CompilerException
import kotlin.math.* import kotlin.math.*
@ -336,44 +337,40 @@ private fun builtinLen(args: List<IExpression>, position: Position, program: Pro
// note: in some cases the length is > 255 and then we have to return a UWORD type instead of a UBYTE. // note: in some cases the length is > 255 and then we have to return a UWORD type instead of a UBYTE.
if(args.size!=1) if(args.size!=1)
throw SyntaxError("len requires one argument", position) throw SyntaxError("len requires one argument", position)
var argument = args[0].constValue(program) val constArg = args[0].constValue(program)
if(argument==null) { if(constArg!=null)
val directMemVar = ((args[0] as? DirectMemoryRead)?.addressExpression as? IdentifierReference)?.targetVarDecl(program.namespace) throw SyntaxError("len of weird argument ${args[0]}", position)
val arraySize = directMemVar?.arraysize?.size()
if(arraySize != null) val directMemVar = ((args[0] as? DirectMemoryRead)?.addressExpression as? IdentifierReference)?.targetVarDecl(program.namespace)
return NumericLiteralValue.optimalInteger(arraySize, position) var arraySize = directMemVar?.arraysize?.size()
if(args[0] !is IdentifierReference) if(arraySize != null)
throw SyntaxError("len argument should be an identifier, but is ${args[0]}", position) return NumericLiteralValue.optimalInteger(arraySize, position)
val target = (args[0] as IdentifierReference).targetStatement(program.namespace) if(args[0] !is IdentifierReference)
val argValue = (target as? VarDecl)?.value throw SyntaxError("len argument should be an identifier, but is ${args[0]}", position)
argument = argValue?.constValue(program) val target = (args[0] as IdentifierReference).targetStatement(program.namespace) as VarDecl
?: throw NotConstArgumentException()
return when(target.datatype) {
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> {
arraySize = target.arraysize!!.size()!!
if(arraySize>256)
throw CompilerException("array length exceeds byte limit ${target.position}")
NumericLiteralValue.optimalInteger(arraySize, args[0].position)
}
DataType.ARRAY_F -> {
arraySize = target.arraysize!!.size()!!
if(arraySize>256)
throw CompilerException("array length exceeds byte limit ${target.position}")
NumericLiteralValue.optimalInteger(arraySize, args[0].position)
}
in StringDatatypes -> {
val refLv = target.value as ReferenceLiteralValue
if(refLv.str!!.length>255)
throw CompilerException("string length exceeds byte limit ${refLv.position}")
NumericLiteralValue.optimalInteger(refLv.str.length, args[0].position)
}
in NumericDatatypes -> throw SyntaxError("len of weird argument ${args[0]}", position)
else -> throw CompilerException("weird datatype")
} }
TODO("collection functions over iterables (array, string) $argument")
// return when(argument.type) {
// DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> {
// val arraySize = argument.arrayvalue?.size ?: program.heap.get(argument.heapId!!).arraysize
// if(arraySize>256)
// throw CompilerException("array length exceeds byte limit ${argument.position}")
// LiteralValue.optimalInteger(arraySize, args[0].position)
// }
// DataType.ARRAY_F -> {
// val arraySize = argument.arrayvalue?.size ?: program.heap.get(argument.heapId!!).arraysize
// if(arraySize>256)
// throw CompilerException("array length exceeds byte limit ${argument.position}")
// LiteralValue.optimalInteger(arraySize, args[0].position)
// }
// in StringDatatypes -> {
// val str = argument.strvalue!!
// if(str.length>255)
// throw CompilerException("string length exceeds byte limit ${argument.position}")
// LiteralValue.optimalInteger(str.length, args[0].position)
// }
// in NumericDatatypes -> throw SyntaxError("len of weird argument ${args[0]}", position)
// else -> throw CompilerException("weird datatype")
// }
} }

View File

@ -618,20 +618,19 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
throw FatalAstException("missing array value") throw FatalAstException("missing array value")
} }
val array = litval.array!! val typesInArray = litval.array.mapNotNull { it.inferType(program) }.toSet()
val typesInArray = array.mapNotNull { it.inferType(program) }.toSet()
val arrayDt = val arrayDt =
when { when {
array.any { it is AddressOf } -> DataType.ARRAY_UW litval.array.any { it is AddressOf } -> DataType.ARRAY_UW
DataType.FLOAT in typesInArray -> DataType.ARRAY_F DataType.FLOAT in typesInArray -> DataType.ARRAY_F
DataType.WORD in typesInArray -> DataType.ARRAY_W DataType.WORD in typesInArray -> DataType.ARRAY_W
else -> { else -> {
val allElementsAreConstantOrAddressOf = array.fold(true) { c, expr-> c and (expr is NumericLiteralValue|| expr is AddressOf)} val allElementsAreConstantOrAddressOf = litval.array.fold(true) { c, expr-> c and (expr is NumericLiteralValue|| expr is AddressOf)}
if(!allElementsAreConstantOrAddressOf) { if(!allElementsAreConstantOrAddressOf) {
addError(ExpressionError("array literal can only consist of constant primitive numerical values or memory pointers", litval.position)) addError(ExpressionError("array literal can only consist of constant primitive numerical values or memory pointers", litval.position))
return litval return litval
} else { } else {
val integerArray = array.map { it.constValue(program)!!.number.toInt() } val integerArray = litval.array.map { it.constValue(program)!!.number.toInt() }
val maxValue = integerArray.max()!! val maxValue = integerArray.max()!!
val minValue = integerArray.min()!! val minValue = integerArray.min()!!
if (minValue >= 0) { if (minValue >= 0) {

View File

@ -226,18 +226,18 @@ class Program (val name: String,
if(valueStr[0] !='"' && ':' !in valueStr) if(valueStr[0] !='"' && ':' !in valueStr)
throw VmExecutionException("missing value type character") throw VmExecutionException("missing value type character")
val value = when(val type = DataType.valueOf(typeStr.toUpperCase())) { val value = when(val type = DataType.valueOf(typeStr.toUpperCase())) {
DataType.UBYTE -> RuntimeValue(DataType.UBYTE, valueStr.substring(3).toShort(16)) DataType.UBYTE -> RuntimeValue(DataType.UBYTE, valueStr.substring(3).substringBefore(' ').toShort(16))// TODO process ZP and struct info?
DataType.BYTE -> RuntimeValue(DataType.BYTE, valueStr.substring(2).toShort(16)) DataType.BYTE -> RuntimeValue(DataType.BYTE, valueStr.substring(2).substringBefore(' ').toShort(16))// TODO process ZP and struct info?
DataType.UWORD -> RuntimeValue(DataType.UWORD, valueStr.substring(3).toInt(16)) DataType.UWORD -> RuntimeValue(DataType.UWORD, valueStr.substring(3).substringBefore(' ').toInt(16))// TODO process ZP and struct info?
DataType.WORD -> RuntimeValue(DataType.WORD, valueStr.substring(2).toInt(16)) DataType.WORD -> RuntimeValue(DataType.WORD, valueStr.substring(2).substringBefore(' ').toInt(16))// TODO process ZP and struct info?
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, valueStr.substring(2).toDouble()) DataType.FLOAT -> RuntimeValue(DataType.FLOAT, valueStr.substring(2).substringBefore(' ').toDouble())// TODO process ZP and struct info?
in StringDatatypes -> { in StringDatatypes -> {
if(valueStr.startsWith('"') && valueStr.endsWith('"')) if(valueStr.startsWith('"') && valueStr.endsWith('"'))
throw VmExecutionException("encountered a var with a string value, but all string values should already have been moved into the heap") throw VmExecutionException("encountered a var with a string value, but all string values should already have been moved into the heap")
else if(!valueStr.startsWith("heap:")) else if(!valueStr.startsWith("heap:"))
throw VmExecutionException("invalid string value, should be a heap reference") throw VmExecutionException("invalid string value, should be a heap reference")
else { else {
val heapId = valueStr.substring(5).toInt() val heapId = valueStr.substring(5).substringBefore(' ').toInt() // TODO process ZP and struct info?
RuntimeValue(type, heapId = heapId) RuntimeValue(type, heapId = heapId)
} }
} }
@ -245,7 +245,7 @@ class Program (val name: String,
if(!valueStr.startsWith("heap:")) if(!valueStr.startsWith("heap:"))
throw VmExecutionException("invalid array value, should be a heap reference") throw VmExecutionException("invalid array value, should be a heap reference")
else { else {
val heapId = valueStr.substring(5).toInt() val heapId = valueStr.substring(5).substringBefore(' ').toInt() // TODO process ZP and struct info?
RuntimeValue(type, heapId = heapId) RuntimeValue(type, heapId = heapId)
} }
} }

View File

@ -215,7 +215,7 @@ Variable declarations
^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
Variables should be declared with their exact type and size so the compiler can allocate storage Variables should be declared with their exact type and size so the compiler can allocate storage
for them. You must give them an initial value as well. That value can be a simple literal value, for them. You can give them an initial value as well. That value can be a simple literal value,
or an expression. You can add a ``@zp`` zeropage-tag, to tell the compiler to prioritize it or an expression. You can add a ``@zp`` zeropage-tag, to tell the compiler to prioritize it
when selecting variables to be put into zeropage. when selecting variables to be put into zeropage.
The syntax is:: The syntax is::

View File

@ -3,41 +3,17 @@
~ main { ~ main {
struct Color {
uword red
ubyte green
ubyte blue
}
str naam = "irmen"
word[] array = [1,2,3,4]
uword uw = $ab12
Color rgb = [255,128,0]
Color rgb2 = [111,222,33]
ubyte @zp zpvar=99
sub start() { sub start() {
uword fake_address str naam = "irmen"
fake_address = &naam
c64scr.print_uwhex(1, fake_address)
c64scr.print(", ")
fake_address = &array
c64scr.print_uwhex(1, fake_address)
c64scr.print(", ")
fake_address = &rgb
c64scr.print_uwhex(1, fake_address)
c64scr.print("\n")
; @todo only works once reference types are actually references:
;str name2 = naam ; @todo name2 points to same str as naam
;str name2 = fake_address ; @todo fake_address hopefully points to a str
;Color colz = fake_address ; @todo fake_address hopefully points to a Color
ubyte length = len(naam)
c64scr.print(naam)
c64scr.print("irmen")
c64scr.print("irmen2")
c64scr.print("irmen2")
ubyte length2 = len("irmen") ; @todo same string as 'naam'
ubyte length3 = len("zxfdsfsf") ; @todo new string
return return
} }