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
import com.sun.org.apache.bcel.internal.generic.ISTORE
import prog8.ast.*
import prog8.ast.base.*
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))
}
else
checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, assignment.position)
checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, target, assignment.position)
}
}
return assignment
@ -1138,7 +1137,11 @@ internal class AstChecker(private val program: Program,
}
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
}
@ -1195,10 +1198,11 @@ internal class AstChecker(private val program: Program,
private fun checkAssignmentCompatible(targetDatatype: DataType,
sourceDatatype: DataType,
sourceValue: IExpression,
target: AssignTarget,
position: Position) : Boolean {
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) {
DataType.BYTE -> sourceDatatype== DataType.BYTE
@ -1208,6 +1212,17 @@ internal class AstChecker(private val program: Program,
DataType.FLOAT -> sourceDatatype in NumericDatatypes
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.
// 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))
}

View File

@ -12,10 +12,14 @@ import kotlin.math.*
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?
val parameters: List<BuiltinFunctionParam>,
val returntype: DataType?,
val constExpressionFunc: ((args: List<IExpression>, position: Position, program: Program) -> LiteralValue)? = null)
val constExpressionFunc: ConstExpressionCaller? = null)
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()
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) {
return performSyscall(sub, arguments)
}
@ -282,10 +282,10 @@ class AstVm(val program: Program) {
}
val statements = sub.statements.iterator()
if(startlabel!=null) {
if(startAtLabel!=null) {
do {
val stmt = statements.next()
} while(stmt!==startlabel)
} while(stmt!==startAtLabel)
}
try {

View File

@ -13,10 +13,15 @@ import prog8.vm.RuntimeValue
import prog8.vm.RuntimeValueRange
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,
val runtimeVars: RuntimeVariables,
val performBuiltinFunction: (String, List<RuntimeValue>, StatusFlags) -> RuntimeValue?,
val executeSubroutine: (sub: Subroutine, args: List<RuntimeValue>, startlabel: Label?) -> RuntimeValue?)
val performBuiltinFunction: BuiltinfunctionCaller,
val executeSubroutine: SubroutineCaller)
fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
val constval = expr.constValue(ctx.program)
@ -96,6 +101,9 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
if(variable is VarDecl) {
if(variable.type==VarDeclType.VAR)
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 {
val address = ctx.runtimeVars.getMemoryAddress(variable.definingScope(), variable.name)
return when(variable.datatype) {

View File

@ -4,6 +4,7 @@ import prog8.ast.*
import prog8.ast.base.*
import prog8.ast.expressions.LiteralValue
import prog8.ast.processing.IAstModifyingVisitor
import prog8.ast.statements.StructDecl
import prog8.ast.statements.VarDecl
import prog8.compiler.HeapValues
import prog8.vm.RuntimeValue
@ -34,19 +35,25 @@ class VariablesCreator(private val runtimeVariables: RuntimeVariables, private v
}
override fun visit(decl: VarDecl): IStatement {
when(decl.type) {
// we can assume the value in the vardecl already has been converted into a constant LiteralValue here.
VarDeclType.VAR -> {
val value = RuntimeValue.from(decl.value as LiteralValue, heap)
runtimeVariables.define(decl.definingScope(), decl.name, value)
// if the decl is part of a struct, just skip it
if(decl.parent !is StructDecl) {
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)
}
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)
}

View File

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