Structs can be compiled and executed in the vm! structs are just syntactic sugar for a set of variables for now.

This commit is contained in:
Irmen de Jong 2019-07-12 12:41:08 +02:00
parent 44f9d5e69e
commit 1e9586f635
6 changed files with 57 additions and 22 deletions

View File

@ -1,6 +1,5 @@
package prog8.ast.processing package prog8.ast.processing
import com.sun.org.apache.bcel.internal.generic.ISTORE
import prog8.ast.* import prog8.ast.*
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.base.printWarning import prog8.ast.base.printWarning
@ -426,7 +425,7 @@ internal class AstChecker(private val program: Program,
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, assignment.position) checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, target, assignment.position)
} }
} }
return assignment return assignment
@ -1138,7 +1137,11 @@ 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 -> TODO("struct dt") DataType.STRUCT -> {
if(value.type!=DataType.STRUCT)
return err("cannot assign a normal value to a struct")
TODO("check struct, $value ")
}
} }
return true return true
} }
@ -1195,10 +1198,11 @@ internal class AstChecker(private val program: Program,
private fun checkAssignmentCompatible(targetDatatype: DataType, private fun checkAssignmentCompatible(targetDatatype: DataType,
sourceDatatype: DataType, sourceDatatype: DataType,
sourceValue: IExpression, sourceValue: IExpression,
target: AssignTarget,
position: Position) : Boolean { position: Position) : Boolean {
if(sourceValue is RangeExpr) if(sourceValue is RangeExpr)
checkResult.add(SyntaxError("can't assign a range value", position)) checkResult.add(SyntaxError("can't assign a range value to something else", position))
val result = when(targetDatatype) { val result = when(targetDatatype) {
DataType.BYTE -> sourceDatatype== DataType.BYTE DataType.BYTE -> sourceDatatype== DataType.BYTE
@ -1208,6 +1212,17 @@ internal class AstChecker(private val program: Program,
DataType.FLOAT -> sourceDatatype in NumericDatatypes DataType.FLOAT -> sourceDatatype in NumericDatatypes
DataType.STR -> sourceDatatype== DataType.STR DataType.STR -> sourceDatatype== DataType.STR
DataType.STR_S -> sourceDatatype== DataType.STR_S DataType.STR_S -> sourceDatatype== DataType.STR_S
DataType.STRUCT -> {
// for now we've decided you cannot assign struct by-value.
// 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)) else -> checkResult.add(SyntaxError("cannot assign new value to variable of type $targetDatatype", position))
} }

View File

@ -12,10 +12,14 @@ import kotlin.math.*
class BuiltinFunctionParam(val name: String, val possibleDatatypes: Set<DataType>) class BuiltinFunctionParam(val name: String, val possibleDatatypes: Set<DataType>)
typealias ConstExpressionCaller = (args: List<IExpression>, position: Position, program: Program) -> LiteralValue
class FunctionSignature(val pure: Boolean, // does it have side effects? class FunctionSignature(val pure: Boolean, // does it have side effects?
val parameters: List<BuiltinFunctionParam>, val parameters: List<BuiltinFunctionParam>,
val returntype: DataType?, val returntype: DataType?,
val constExpressionFunc: ((args: List<IExpression>, position: Position, program: Program) -> LiteralValue)? = null) val constExpressionFunc: ConstExpressionCaller? = null)
val BuiltinFunctions = mapOf( val BuiltinFunctions = mapOf(

View File

@ -265,7 +265,7 @@ class AstVm(val program: Program) {
class LoopControlJump(val identifier: IdentifierReference?, val address: Int?, val generatedLabel: String?) : Exception() class LoopControlJump(val identifier: IdentifierReference?, val address: Int?, val generatedLabel: String?) : Exception()
internal fun executeSubroutine(sub: Subroutine, arguments: List<RuntimeValue>, startlabel: Label?=null): RuntimeValue? { internal fun executeSubroutine(sub: Subroutine, arguments: List<RuntimeValue>, startAtLabel: Label?=null): RuntimeValue? {
if(sub.isAsmSubroutine) { if(sub.isAsmSubroutine) {
return performSyscall(sub, arguments) return performSyscall(sub, arguments)
} }
@ -282,10 +282,10 @@ class AstVm(val program: Program) {
} }
val statements = sub.statements.iterator() val statements = sub.statements.iterator()
if(startlabel!=null) { if(startAtLabel!=null) {
do { do {
val stmt = statements.next() val stmt = statements.next()
} while(stmt!==startlabel) } while(stmt!==startAtLabel)
} }
try { try {

View File

@ -13,10 +13,15 @@ import prog8.vm.RuntimeValue
import prog8.vm.RuntimeValueRange import prog8.vm.RuntimeValueRange
import kotlin.math.abs import kotlin.math.abs
typealias BuiltinfunctionCaller = (name: String, args: List<RuntimeValue>, flags: StatusFlags) -> RuntimeValue?
typealias SubroutineCaller = (sub: Subroutine, args: List<RuntimeValue>, startAtLabel: Label?) -> RuntimeValue?
class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags, class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags,
val runtimeVars: RuntimeVariables, val runtimeVars: RuntimeVariables,
val performBuiltinFunction: (String, List<RuntimeValue>, StatusFlags) -> RuntimeValue?, val performBuiltinFunction: BuiltinfunctionCaller,
val executeSubroutine: (sub: Subroutine, args: List<RuntimeValue>, startlabel: Label?) -> RuntimeValue?) val executeSubroutine: SubroutineCaller)
fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue { fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
val constval = expr.constValue(ctx.program) val constval = expr.constValue(ctx.program)
@ -96,6 +101,9 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
if(variable is VarDecl) { if(variable is VarDecl) {
if(variable.type==VarDeclType.VAR) if(variable.type==VarDeclType.VAR)
return ctx.runtimeVars.get(variable.definingScope(), variable.name) return ctx.runtimeVars.get(variable.definingScope(), variable.name)
else if(variable.type==VarDeclType.STRUCT) {
throw VmExecutionException("cannot process structs by-value. at ${expr.position}")
}
else { else {
val address = ctx.runtimeVars.getMemoryAddress(variable.definingScope(), variable.name) val address = ctx.runtimeVars.getMemoryAddress(variable.definingScope(), variable.name)
return when(variable.datatype) { return when(variable.datatype) {

View File

@ -4,6 +4,7 @@ import prog8.ast.*
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.expressions.LiteralValue import prog8.ast.expressions.LiteralValue
import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.processing.IAstModifyingVisitor
import prog8.ast.statements.StructDecl
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
import prog8.compiler.HeapValues import prog8.compiler.HeapValues
import prog8.vm.RuntimeValue import prog8.vm.RuntimeValue
@ -34,19 +35,25 @@ class VariablesCreator(private val runtimeVariables: RuntimeVariables, private v
} }
override fun visit(decl: VarDecl): IStatement { override fun visit(decl: VarDecl): IStatement {
when(decl.type) { // if the decl is part of a struct, just skip it
// we can assume the value in the vardecl already has been converted into a constant LiteralValue here. if(decl.parent !is StructDecl) {
VarDeclType.VAR -> { when (decl.type) {
val value = RuntimeValue.from(decl.value as LiteralValue, heap) // we can assume the value in the vardecl already has been converted into a constant LiteralValue here.
runtimeVariables.define(decl.definingScope(), decl.name, value) VarDeclType.VAR -> {
println("$decl")
val value = RuntimeValue.from(decl.value as LiteralValue, heap)
runtimeVariables.define(decl.definingScope(), decl.name, value)
}
VarDeclType.MEMORY -> {
runtimeVariables.defineMemory(decl.definingScope(), decl.name, (decl.value as LiteralValue).asIntegerValue!!)
}
VarDeclType.CONST -> {
// consts should have been const-folded away
}
VarDeclType.STRUCT -> {
// struct vardecl can be skipped because its members have been flattened out
}
} }
VarDeclType.MEMORY -> {
runtimeVariables.defineMemory(decl.definingScope(), decl.name, (decl.value as LiteralValue).asIntegerValue!!)
}
VarDeclType.CONST -> {
// consts should have been const-folded away
}
VarDeclType.STRUCT -> TODO("struct decltype")
} }
return super.visit(decl) return super.visit(decl)
} }

View File

@ -4,6 +4,7 @@
~ main { ~ main {
sub start() { sub start() {
uword derp
Color foreground ; = [0,1,2] @todo init values Color foreground ; = [0,1,2] @todo init values
Color background Color background