mirror of
https://github.com/irmen/prog8.git
synced 2024-08-19 14:29:17 +00:00
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:
parent
44f9d5e69e
commit
1e9586f635
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(
|
||||||
|
@ -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 {
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user