mirror of
https://github.com/irmen/prog8.git
synced 2024-12-26 14:29:35 +00:00
fix returntype handling of builtinfunctions, fix errors in pipe expressions
This commit is contained in:
parent
c4fe3ecc0a
commit
60b2c44a44
@ -968,14 +968,27 @@ $repeatLabel lda $counterVar
|
||||
assemblyLines.add(assembly)
|
||||
}
|
||||
|
||||
internal fun returnRegisterOfFunction(it: IdentifierReference): RegisterOrPair {
|
||||
internal fun returnRegisterOfFunction(it: IdentifierReference, argumentTypesForBuiltinFunc: List<DataType>?): RegisterOrPair {
|
||||
return when (val targetRoutine = it.targetStatement(program)!!) {
|
||||
is BuiltinFunctionPlaceholder -> {
|
||||
when (BuiltinFunctions.getValue(targetRoutine.name).known_returntype) {
|
||||
val func = BuiltinFunctions.getValue(targetRoutine.name)
|
||||
when (func.returnType) {
|
||||
in ByteDatatypes -> RegisterOrPair.A
|
||||
in WordDatatypes -> RegisterOrPair.AY
|
||||
DataType.FLOAT -> RegisterOrPair.FAC1
|
||||
else -> throw AssemblyError("weird returntype")
|
||||
else -> {
|
||||
if(!func.hasReturn)
|
||||
throw AssemblyError("func has no returntype")
|
||||
else {
|
||||
val args = argumentTypesForBuiltinFunc!!.map { defaultZero(it, Position.DUMMY) }
|
||||
when(builtinFunctionReturnType(func.name, args, program).getOrElse { DataType.UNDEFINED }) {
|
||||
in ByteDatatypes -> RegisterOrPair.A
|
||||
in WordDatatypes -> RegisterOrPair.AY
|
||||
DataType.FLOAT -> RegisterOrPair.FAC1
|
||||
else -> throw AssemblyError("weird returntype")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is Subroutine -> targetRoutine.asmReturnvaluesRegisters.single().registerOrPair!!
|
||||
@ -2833,7 +2846,7 @@ $repeatLabel lda $counterVar
|
||||
var valueDt = firstTerm.inferType(program).getOrElse { throw FatalAstException("invalid dt") }
|
||||
var valueSource: AsmAssignSource =
|
||||
if(firstTerm is IFunctionCall) {
|
||||
val resultReg = returnRegisterOfFunction(firstTerm.target)
|
||||
val resultReg = returnRegisterOfFunction(firstTerm.target, listOf(valueDt))
|
||||
assignExpressionToRegister(firstTerm, resultReg, valueDt in listOf(DataType.BYTE, DataType.WORD, DataType.FLOAT))
|
||||
AsmAssignSource(SourceStorageKind.REGISTER, program, this, valueDt, register = resultReg)
|
||||
} else {
|
||||
@ -2844,7 +2857,7 @@ $repeatLabel lda $counterVar
|
||||
// directly assign their argument from the previous call's returnvalue.
|
||||
expressions.drop(1).dropLast(1).forEach {
|
||||
valueDt = functioncallAsmGen.translateUnaryFunctionCallWithArgSource(it as IdentifierReference, valueSource, false, subroutine)
|
||||
val resultReg = returnRegisterOfFunction(it)
|
||||
val resultReg = returnRegisterOfFunction(it, listOf(valueDt))
|
||||
valueSource = AsmAssignSource(SourceStorageKind.REGISTER, program, this, valueDt, register = resultReg)
|
||||
}
|
||||
|
||||
|
@ -11,10 +11,7 @@ import prog8.ast.statements.DirectMemoryWrite
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.toHex
|
||||
import prog8.codegen.cpu6502.assignment.*
|
||||
import prog8.compilerinterface.AssemblyError
|
||||
import prog8.compilerinterface.BuiltinFunctions
|
||||
import prog8.compilerinterface.CpuType
|
||||
import prog8.compilerinterface.FSignature
|
||||
import prog8.compilerinterface.*
|
||||
|
||||
|
||||
internal class BuiltinFunctionsAsmGen(private val program: Program,
|
||||
@ -60,7 +57,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
||||
val fcall = BuiltinFunctionCall(IdentifierReference(listOf(name), Position.DUMMY), argExpressions, Position.DUMMY)
|
||||
fcall.linkParents(scope)
|
||||
translateFunctioncall(fcall, func, discardResult = false, resultToStack = false, null)
|
||||
return if(isStatement) DataType.UNDEFINED else func.known_returntype!!
|
||||
if(isStatement) {
|
||||
return DataType.UNDEFINED
|
||||
} else {
|
||||
return builtinFunctionReturnType(func.name, argExpressions, program).getOrElse { throw AssemblyError("unknown dt") }
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateFunctioncall(fcall: IFunctionCall, func: FSignature, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
||||
|
@ -335,6 +335,14 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr
|
||||
|
||||
override fun after(pipeExpr: PipeExpression, parent: Node): Iterable<IAstModification> {
|
||||
val expressions = pipeExpr.expressions
|
||||
if(expressions.size==2 && expressions[0].isSimple) {
|
||||
// just replace with a normal function call
|
||||
val funcname = expressions[1] as IdentifierReference
|
||||
val arg = expressions[0]
|
||||
val call = FunctionCallExpression(funcname.copy(), mutableListOf(arg), arg.position)
|
||||
return listOf(IAstModification.ReplaceNode(pipeExpr, call, parent))
|
||||
}
|
||||
require(expressions.size>=2) { "pipe expression should have 2 or more parts" }
|
||||
val firstValue = expressions.first()
|
||||
if(firstValue.isSimple) {
|
||||
val funcname = expressions[1] as IdentifierReference
|
||||
|
@ -238,7 +238,8 @@ class UnusedCodeRemover(private val program: Program,
|
||||
is PrefixExpression,
|
||||
is BinaryExpression,
|
||||
is TypecastExpression,
|
||||
is FunctionCallExpression -> { /* don't remove */ }
|
||||
is PipeExpression,
|
||||
is IFunctionCall -> { /* don't remove */ }
|
||||
else -> {
|
||||
if(assign1.value !is IFunctionCall)
|
||||
linesToRemove.add(assign1)
|
||||
|
@ -171,8 +171,6 @@ private class BuiltinFunctionsFacade(functions: Map<String, FSignature>): IBuilt
|
||||
null
|
||||
}
|
||||
}
|
||||
else if(func.known_returntype==null)
|
||||
return null // builtin function $name can't be used here because it doesn't return a value
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
@ -1245,27 +1245,30 @@ internal class AstChecker(private val program: Program,
|
||||
|
||||
override fun visit(pipe: PipeExpression) {
|
||||
processPipe(pipe.expressions, pipe)
|
||||
val last = pipe.expressions.last() as IdentifierReference
|
||||
val target = last.targetStatement(program)!!
|
||||
when(target) {
|
||||
is BuiltinFunctionPlaceholder -> {
|
||||
if(BuiltinFunctions.getValue(target.name).known_returntype==null)
|
||||
errors.err("invalid pipe expression; last term doesn't return a value", last.position)
|
||||
if(errors.noErrors()) {
|
||||
val last = pipe.expressions.last() as IdentifierReference
|
||||
when (val target = last.targetStatement(program)!!) {
|
||||
is BuiltinFunctionPlaceholder -> {
|
||||
if (!BuiltinFunctions.getValue(target.name).hasReturn)
|
||||
errors.err("invalid pipe expression; last term doesn't return a value", last.position)
|
||||
}
|
||||
is Subroutine -> {
|
||||
if (target.returntypes.isEmpty())
|
||||
errors.err("invalid pipe expression; last term doesn't return a value", last.position)
|
||||
else if (target.returntypes.size != 1)
|
||||
errors.err("invalid pipe expression; last term doesn't return a single value", last.position)
|
||||
}
|
||||
else -> errors.err("invalid pipe expression; last term doesn't return a value", last.position)
|
||||
}
|
||||
is Subroutine -> {
|
||||
if(target.returntypes.isEmpty())
|
||||
errors.err("invalid pipe expression; last term doesn't return a value", last.position)
|
||||
else if(target.returntypes.size!=1)
|
||||
errors.err("invalid pipe expression; last term doesn't return a single value", last.position)
|
||||
}
|
||||
else -> errors.err("invalid pipe expression; last term doesn't return a value", last.position)
|
||||
super.visit(pipe)
|
||||
}
|
||||
super.visit(pipe)
|
||||
}
|
||||
|
||||
override fun visit(pipe: Pipe) {
|
||||
processPipe(pipe.expressions, pipe)
|
||||
super.visit(pipe)
|
||||
if(errors.noErrors()) {
|
||||
super.visit(pipe)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processPipe(expressions: List<Expression>, scope: Node) {
|
||||
@ -1289,14 +1292,19 @@ internal class AstChecker(private val program: Program,
|
||||
val func = BuiltinFunctions.getValue(function.name)
|
||||
if(func.parameters.size!=1)
|
||||
errors.err("can only use unary function", expr.position)
|
||||
else if(func.known_returntype==null && expr !== expressions.last())
|
||||
else if(!func.hasReturn && expr !== expressions.last())
|
||||
errors.err("function must return a single value", expr.position)
|
||||
|
||||
val paramDts = func.parameters.firstOrNull()?.possibleDatatypes
|
||||
if(paramDts!=null && !paramDts.any { valueDt isAssignableTo it })
|
||||
errors.err("pipe value datatype $valueDt incompatible withfunction argument ${paramDts.toList()}", functionName.position)
|
||||
|
||||
valueDt = func.known_returntype!!
|
||||
if(errors.noErrors()) {
|
||||
// type can depend on the argument(s) of the function. For now, we only deal with unary functions,
|
||||
// so we know there must be a single argument. Take its type from the previous expression in the pipe chain.
|
||||
val zero = defaultZero(valueDt, expr.position)
|
||||
valueDt = builtinFunctionReturnType(func.name, listOf(zero), program).getOrElse { DataType.UNDEFINED }
|
||||
}
|
||||
}
|
||||
is Subroutine -> {
|
||||
if(function.parameters.size!=1)
|
||||
|
93
compiler/test/TestBuiltinFunctions.kt
Normal file
93
compiler/test/TestBuiltinFunctions.kt
Normal file
@ -0,0 +1,93 @@
|
||||
package prog8tests
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.base.NumericDatatypes
|
||||
import prog8.ast.base.RegisterOrPair
|
||||
import prog8.compilerinterface.BuiltinFunctions
|
||||
|
||||
|
||||
class TestBuiltinFunctions: FunSpec({
|
||||
|
||||
test("pure func with fixed type") {
|
||||
val func = BuiltinFunctions.getValue("sin8u")
|
||||
func.name shouldBe "sin8u"
|
||||
func.parameters.size shouldBe 1
|
||||
func.parameters[0].name shouldBe "angle8"
|
||||
func.parameters[0].possibleDatatypes shouldBe arrayOf(DataType.UBYTE)
|
||||
func.pure shouldBe true
|
||||
func.hasReturn shouldBe true
|
||||
func.returnType shouldBe DataType.UBYTE
|
||||
|
||||
val conv = func.callConvention(listOf(DataType.UBYTE))
|
||||
conv.params.size shouldBe 1
|
||||
conv.params[0].dt shouldBe DataType.UBYTE
|
||||
conv.params[0].reg shouldBe RegisterOrPair.A
|
||||
conv.params[0].variable shouldBe false
|
||||
conv.returns.dt shouldBe DataType.UBYTE
|
||||
conv.returns.floatFac1 shouldBe false
|
||||
conv.returns.reg shouldBe RegisterOrPair.A
|
||||
}
|
||||
|
||||
test("not-pure func with fixed type") {
|
||||
val func = BuiltinFunctions.getValue("rnd")
|
||||
func.name shouldBe "rnd"
|
||||
func.parameters.size shouldBe 0
|
||||
func.pure shouldBe false
|
||||
func.hasReturn shouldBe true
|
||||
func.returnType shouldBe DataType.UBYTE
|
||||
|
||||
val conv = func.callConvention(emptyList())
|
||||
conv.params.size shouldBe 0
|
||||
conv.returns.dt shouldBe DataType.UBYTE
|
||||
conv.returns.floatFac1 shouldBe false
|
||||
conv.returns.reg shouldBe RegisterOrPair.A
|
||||
}
|
||||
|
||||
test("func without return type") {
|
||||
val func = BuiltinFunctions.getValue("poke")
|
||||
func.name shouldBe "poke"
|
||||
func.parameters.size shouldBe 2
|
||||
func.parameters[0].name shouldBe "address"
|
||||
func.parameters[0].possibleDatatypes shouldBe arrayOf(DataType.UWORD)
|
||||
func.parameters[1].name shouldBe "value"
|
||||
func.parameters[1].possibleDatatypes shouldBe arrayOf(DataType.UBYTE)
|
||||
func.pure shouldBe false
|
||||
func.hasReturn shouldBe false
|
||||
func.returnType shouldBe null
|
||||
|
||||
val conv = func.callConvention(listOf(DataType.UWORD, DataType.UBYTE))
|
||||
conv.params.size shouldBe 2
|
||||
conv.params[0].dt shouldBe DataType.UWORD
|
||||
conv.params[0].reg shouldBe null
|
||||
conv.params[0].variable shouldBe true
|
||||
conv.params[1].dt shouldBe DataType.UBYTE
|
||||
conv.params[1].reg shouldBe null
|
||||
conv.params[1].variable shouldBe true
|
||||
conv.returns.dt shouldBe null
|
||||
conv.returns.floatFac1 shouldBe false
|
||||
conv.returns.reg shouldBe null
|
||||
}
|
||||
|
||||
test("func with variable return type") {
|
||||
val func = BuiltinFunctions.getValue("abs")
|
||||
func.name shouldBe "abs"
|
||||
func.parameters.size shouldBe 1
|
||||
func.parameters[0].name shouldBe "value"
|
||||
func.parameters[0].possibleDatatypes.toSet() shouldBe NumericDatatypes.toSet()
|
||||
func.pure shouldBe true
|
||||
func.hasReturn shouldBe true
|
||||
func.returnType shouldBe null
|
||||
|
||||
val conv = func.callConvention(listOf(DataType.UWORD))
|
||||
conv.params.size shouldBe 1
|
||||
conv.params[0].dt shouldBe DataType.UWORD
|
||||
conv.params[0].reg shouldBe RegisterOrPair.AY
|
||||
conv.params[0].variable shouldBe false
|
||||
conv.returns.dt shouldBe DataType.UWORD
|
||||
conv.returns.floatFac1 shouldBe false
|
||||
conv.returns.reg shouldBe RegisterOrPair.AY
|
||||
}
|
||||
})
|
||||
|
@ -4,10 +4,9 @@ import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import io.kotest.matchers.types.instanceOf
|
||||
import prog8.ast.expressions.FunctionCallExpression
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.expressions.PipeExpression
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.Assignment
|
||||
import prog8.ast.statements.FunctionCallStatement
|
||||
import prog8.ast.statements.Pipe
|
||||
import prog8.codegen.target.C64Target
|
||||
import prog8tests.helpers.ErrorReporterForTests
|
||||
@ -32,6 +31,11 @@ class TestPipes: FunSpec({
|
||||
9999 |> addword
|
||||
|> txt.print_uw
|
||||
|
||||
; these are optimized into just the function calls:
|
||||
9999 |> abs |> txt.print_uw
|
||||
9999 |> txt.print_uw
|
||||
99 |> abs |> txt.print_ub
|
||||
99 |> txt.print_ub
|
||||
}
|
||||
|
||||
sub addfloat(float fl) -> float {
|
||||
@ -44,7 +48,7 @@ class TestPipes: FunSpec({
|
||||
"""
|
||||
val result = compileText(C64Target(), true, text, writeAssembly = true).assertSuccess()
|
||||
val stmts = result.program.entrypoint.statements
|
||||
stmts.size shouldBe 3
|
||||
stmts.size shouldBe 7
|
||||
val pipef = stmts[0] as Pipe
|
||||
pipef.expressions.size shouldBe 2
|
||||
pipef.expressions[0] shouldBe instanceOf<FunctionCallExpression>()
|
||||
@ -54,6 +58,15 @@ class TestPipes: FunSpec({
|
||||
pipew.expressions.size shouldBe 2
|
||||
pipew.expressions[0] shouldBe instanceOf<FunctionCallExpression>()
|
||||
pipew.expressions[1] shouldBe instanceOf<IdentifierReference>()
|
||||
|
||||
var stmt = stmts[2] as FunctionCallStatement
|
||||
stmt.target.nameInSource shouldBe listOf("txt", "print_uw")
|
||||
stmt = stmts[3] as FunctionCallStatement
|
||||
stmt.target.nameInSource shouldBe listOf("txt", "print_uw")
|
||||
stmt = stmts[4] as FunctionCallStatement
|
||||
stmt.target.nameInSource shouldBe listOf("txt", "print_ub")
|
||||
stmt = stmts[5] as FunctionCallStatement
|
||||
stmt.target.nameInSource shouldBe listOf("txt", "print_ub")
|
||||
}
|
||||
|
||||
test("incorrect type in pipe statement") {
|
||||
@ -94,6 +107,8 @@ class TestPipes: FunSpec({
|
||||
uword @shared ww = 9999 |> addword
|
||||
|> addword
|
||||
|
||||
ubyte @shared cc = 30 |> sin8u |> cos8u ; will be optimized away into a const number
|
||||
cc = cc |> sin8u |> cos8u
|
||||
}
|
||||
|
||||
sub addfloat(float fl) -> float {
|
||||
@ -102,11 +117,14 @@ class TestPipes: FunSpec({
|
||||
sub addword(uword ww) -> uword {
|
||||
return ww+2222
|
||||
}
|
||||
}
|
||||
sub addbyte(ubyte bb) -> ubyte {
|
||||
return bb+1
|
||||
}
|
||||
}
|
||||
"""
|
||||
val result = compileText(C64Target(), true, text, writeAssembly = true).assertSuccess()
|
||||
val stmts = result.program.entrypoint.statements
|
||||
stmts.size shouldBe 5
|
||||
stmts.size shouldBe 8
|
||||
val assignf = stmts[1] as Assignment
|
||||
val pipef = assignf.value as PipeExpression
|
||||
pipef.expressions.size shouldBe 2
|
||||
@ -118,6 +136,16 @@ class TestPipes: FunSpec({
|
||||
pipew.expressions.size shouldBe 2
|
||||
pipew.expressions[0] shouldBe instanceOf<FunctionCallExpression>()
|
||||
pipew.expressions[1] shouldBe instanceOf<IdentifierReference>()
|
||||
|
||||
var assigncc = stmts[5] as Assignment
|
||||
val value = assigncc.value as NumericLiteral
|
||||
value.number shouldBe 194.0
|
||||
|
||||
assigncc = stmts[6] as Assignment
|
||||
val pipecc = assignw.value as PipeExpression
|
||||
pipecc.expressions.size shouldBe 2
|
||||
pipecc.expressions[0] shouldBe instanceOf<FunctionCallExpression>()
|
||||
pipecc.expressions[1] shouldBe instanceOf<IdentifierReference>()
|
||||
}
|
||||
|
||||
test("incorrect type in pipe expression") {
|
||||
@ -143,4 +171,50 @@ class TestPipes: FunSpec({
|
||||
errors.errors.size shouldBe 1
|
||||
errors.errors[0] shouldContain "incompatible"
|
||||
}
|
||||
|
||||
test("correct pipe statement with builtin expression") {
|
||||
val text = """
|
||||
%import textio
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
uword ww = 9999
|
||||
ubyte bb = 99
|
||||
ww |> abs |> txt.print_uw
|
||||
bb |> abs |> txt.print_ub
|
||||
}
|
||||
}
|
||||
"""
|
||||
val result = compileText(C64Target(), true, text, writeAssembly = true).assertSuccess()
|
||||
val stmts = result.program.entrypoint.statements
|
||||
stmts.size shouldBe 7
|
||||
val pipef = stmts[4] as Pipe
|
||||
pipef.expressions.size shouldBe 2
|
||||
pipef.expressions[0] shouldBe instanceOf<BuiltinFunctionCall>()
|
||||
pipef.expressions[1] shouldBe instanceOf<IdentifierReference>()
|
||||
|
||||
val pipew = stmts[5] as Pipe
|
||||
pipew.expressions.size shouldBe 2
|
||||
pipew.expressions[0] shouldBe instanceOf<BuiltinFunctionCall>()
|
||||
pipew.expressions[1] shouldBe instanceOf<IdentifierReference>()
|
||||
}
|
||||
|
||||
test("pipe statement with type errors") {
|
||||
val text = """
|
||||
%import textio
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
uword ww = 9999
|
||||
9999 |> abs |> txt.print_ub
|
||||
ww |> abs |> txt.print_ub
|
||||
}
|
||||
}
|
||||
"""
|
||||
val errors = ErrorReporterForTests()
|
||||
compileText(C64Target(), true, text, writeAssembly = true, errors=errors).assertFailure()
|
||||
errors.errors.size shouldBe 2
|
||||
errors.errors[0] shouldContain "UWORD incompatible"
|
||||
errors.errors[1] shouldContain "UWORD incompatible"
|
||||
}
|
||||
})
|
||||
|
@ -1098,17 +1098,34 @@ class PipeExpression(val expressions: MutableList<Expression>, override val posi
|
||||
override fun referencesIdentifier(nameInSource: List<String>) =
|
||||
expressions.any { it.referencesIdentifier(nameInSource) }
|
||||
|
||||
override fun inferType(program: Program): InferredTypes.InferredType {
|
||||
val last = expressions.last()
|
||||
val type = last.inferType(program)
|
||||
if(type.isKnown)
|
||||
return type
|
||||
val identifier = last as? IdentifierReference
|
||||
override fun inferType(program: Program): InferredTypes.InferredType = inferType(program, expressions)
|
||||
|
||||
private fun inferType(program: Program, functionNames: List<Expression>): InferredTypes.InferredType {
|
||||
val identifier = functionNames.last() as? IdentifierReference
|
||||
if(identifier!=null) {
|
||||
val call = FunctionCallExpression(identifier, mutableListOf(), identifier.position)
|
||||
return call.inferType(program)
|
||||
val target = identifier.targetStatement(program)
|
||||
when(target) {
|
||||
is BuiltinFunctionPlaceholder -> {
|
||||
val typeOfPrev = inferType(program, functionNames.dropLast(1))
|
||||
return if(typeOfPrev.isKnown) {
|
||||
val zero = defaultZero(typeOfPrev.getOr(DataType.UNDEFINED), identifier.position)
|
||||
val args = mutableListOf<Expression>(zero)
|
||||
program.builtinFunctions.returnType(identifier.nameInSource[0], args)
|
||||
} else {
|
||||
InferredTypes.InferredType.unknown()
|
||||
}
|
||||
}
|
||||
is Subroutine -> {
|
||||
val call = FunctionCallExpression(identifier, mutableListOf(), identifier.position)
|
||||
return call.inferType(program)
|
||||
}
|
||||
is VarDecl -> {
|
||||
return InferredTypes.InferredType.known(target.datatype)
|
||||
}
|
||||
else -> return InferredTypes.InferredType.unknown()
|
||||
}
|
||||
}
|
||||
return InferredTypes.InferredType.unknown()
|
||||
return functionNames.last().inferType(program)
|
||||
}
|
||||
|
||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||
|
@ -9,7 +9,7 @@ import kotlin.math.*
|
||||
|
||||
private typealias ConstExpressionCaller = (args: List<Expression>, position: Position, program: Program) -> NumericLiteral
|
||||
|
||||
class ReturnConvention(val dt: DataType, val reg: RegisterOrPair?, val floatFac1: Boolean)
|
||||
class ReturnConvention(val dt: DataType?, val reg: RegisterOrPair?, val floatFac1: Boolean)
|
||||
class ParamConvention(val dt: DataType, val reg: RegisterOrPair?, val variable: Boolean)
|
||||
class CallConvention(val params: List<ParamConvention>, val returns: ReturnConvention) {
|
||||
override fun toString(): String {
|
||||
@ -35,35 +35,42 @@ class FParam(val name: String, val possibleDatatypes: Array<DataType>)
|
||||
class FSignature(val name: String,
|
||||
val pure: Boolean, // does it have side effects?
|
||||
val parameters: List<FParam>,
|
||||
val known_returntype: DataType?, // specify return type if fixed, otherwise null if it depends on the arguments
|
||||
val hasReturn: Boolean, // is there a return value at all?
|
||||
val returnType: DataType?, // specify return type if fixed, otherwise null if it depends on the arguments
|
||||
val constExpressionFunc: ConstExpressionCaller? = null) {
|
||||
|
||||
init {
|
||||
require(hasReturn || returnType==null) { "$name has invalid return spec" }
|
||||
}
|
||||
|
||||
fun callConvention(actualParamTypes: List<DataType>): CallConvention {
|
||||
val returns = when(known_returntype) {
|
||||
DataType.UBYTE, DataType.BYTE -> ReturnConvention(known_returntype, RegisterOrPair.A, false)
|
||||
DataType.UWORD, DataType.WORD -> ReturnConvention(known_returntype, RegisterOrPair.AY, false)
|
||||
DataType.FLOAT -> ReturnConvention(known_returntype, null, true)
|
||||
in PassByReferenceDatatypes -> ReturnConvention(known_returntype!!, RegisterOrPair.AY, false)
|
||||
else -> {
|
||||
val paramType = actualParamTypes.first()
|
||||
if(pure)
|
||||
// return type depends on arg type
|
||||
when(paramType) {
|
||||
val returns: ReturnConvention
|
||||
if(hasReturn) {
|
||||
returns = when (returnType) {
|
||||
DataType.UBYTE, DataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A, false)
|
||||
DataType.UWORD, DataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY, false)
|
||||
DataType.FLOAT -> ReturnConvention(returnType, null, true)
|
||||
in PassByReferenceDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY, false)
|
||||
else -> {
|
||||
// return type depends on arg type
|
||||
when (val paramType = actualParamTypes.first()) {
|
||||
DataType.UBYTE, DataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A, false)
|
||||
DataType.UWORD, DataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY, false)
|
||||
DataType.FLOAT -> ReturnConvention(paramType, null, true)
|
||||
in PassByReferenceDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY, false)
|
||||
else -> ReturnConvention(paramType, null, false)
|
||||
}
|
||||
else {
|
||||
ReturnConvention(paramType, null, false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
require(returnType==null)
|
||||
returns = ReturnConvention(null, null, false)
|
||||
}
|
||||
|
||||
return when {
|
||||
actualParamTypes.isEmpty() -> CallConvention(emptyList(), returns)
|
||||
actualParamTypes.size==1 -> {
|
||||
// one parameter? via register/registerpair
|
||||
// one parameter goes via register/registerpair
|
||||
val paramConv = when(val paramType = actualParamTypes[0]) {
|
||||
DataType.UBYTE, DataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false)
|
||||
DataType.UWORD, DataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false)
|
||||
@ -74,7 +81,7 @@ class FSignature(val name: String,
|
||||
CallConvention(listOf(paramConv), returns)
|
||||
}
|
||||
else -> {
|
||||
// multiple parameters? via variables
|
||||
// multiple parameters go via variables
|
||||
val paramConvs = actualParamTypes.map { ParamConvention(it, null, true) }
|
||||
CallConvention(paramConvs, returns)
|
||||
}
|
||||
@ -88,78 +95,78 @@ class FSignature(val name: String,
|
||||
@Suppress("UNUSED_ANONYMOUS_PARAMETER")
|
||||
private val functionSignatures: List<FSignature> = listOf(
|
||||
// this set of function have no return value and operate in-place:
|
||||
FSignature("rol" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
|
||||
FSignature("ror" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
|
||||
FSignature("rol2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
|
||||
FSignature("ror2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
|
||||
FSignature("sort" , false, listOf(FParam("array", ArrayDatatypes)), null),
|
||||
FSignature("reverse" , false, listOf(FParam("array", ArrayDatatypes)), null),
|
||||
FSignature("cmp" , false, listOf(FParam("value1", IntegerDatatypes), FParam("value2", NumericDatatypes)), null),
|
||||
FSignature("rol" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), false,null),
|
||||
FSignature("ror" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), false, null),
|
||||
FSignature("rol2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), false, null),
|
||||
FSignature("ror2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), false, null),
|
||||
FSignature("sort" , false, listOf(FParam("array", ArrayDatatypes)), false, null),
|
||||
FSignature("reverse" , false, listOf(FParam("array", ArrayDatatypes)), false, null),
|
||||
// cmp returns a status in the carry flag, but not a proper return value
|
||||
FSignature("cmp" , false, listOf(FParam("value1", IntegerDatatypes), FParam("value2", NumericDatatypes)), false, null),
|
||||
// these few have a return value depending on the argument(s):
|
||||
FSignature("max" , true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMax) }, // type depends on args
|
||||
FSignature("min" , true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMin) }, // type depends on args
|
||||
FSignature("sum" , true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinSum) }, // type depends on args
|
||||
FSignature("abs" , true, listOf(FParam("value", NumericDatatypes)), null, ::builtinAbs), // type depends on argument
|
||||
FSignature("len" , true, listOf(FParam("values", IterableDatatypes)), null, ::builtinLen), // type is UBYTE or UWORD depending on actual length
|
||||
FSignature("sizeof" , true, listOf(FParam("object", DataType.values())), DataType.UBYTE, ::builtinSizeof),
|
||||
FSignature("max" , true, listOf(FParam("values", ArrayDatatypes)), true, null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMax) }, // type depends on args
|
||||
FSignature("min" , true, listOf(FParam("values", ArrayDatatypes)), true, null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMin) }, // type depends on args
|
||||
FSignature("sum" , true, listOf(FParam("values", ArrayDatatypes)), true, null) { a, p, prg -> collectionArg(a, p, prg, ::builtinSum) }, // type depends on args
|
||||
FSignature("abs" , true, listOf(FParam("value", NumericDatatypes)), true, null, ::builtinAbs), // type depends on argument
|
||||
FSignature("len" , true, listOf(FParam("values", IterableDatatypes)), true, null, ::builtinLen), // type is UBYTE or UWORD depending on actual length
|
||||
FSignature("sizeof" , true, listOf(FParam("object", DataType.values())), true, DataType.UBYTE, ::builtinSizeof),
|
||||
// normal functions follow:
|
||||
FSignature("sgn" , true, listOf(FParam("value", NumericDatatypes)), DataType.BYTE, ::builtinSgn ),
|
||||
FSignature("sin" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sin) },
|
||||
FSignature("sin8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.BYTE, ::builtinSin8 ),
|
||||
FSignature("sin8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UBYTE, ::builtinSin8u ),
|
||||
FSignature("sin16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.WORD, ::builtinSin16 ),
|
||||
FSignature("sin16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinSin16u ),
|
||||
FSignature("sinr8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.BYTE, ::builtinSinR8 ),
|
||||
FSignature("sinr8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UBYTE, ::builtinSinR8u ),
|
||||
FSignature("sinr16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.WORD, ::builtinSinR16 ),
|
||||
FSignature("sinr16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinSinR16u ),
|
||||
FSignature("cos" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::cos) },
|
||||
FSignature("cos8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.BYTE, ::builtinCos8 ),
|
||||
FSignature("cos8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UBYTE, ::builtinCos8u ),
|
||||
FSignature("cos16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.WORD, ::builtinCos16 ),
|
||||
FSignature("cos16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinCos16u ),
|
||||
FSignature("cosr8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.BYTE, ::builtinCosR8 ),
|
||||
FSignature("cosr8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UBYTE, ::builtinCosR8u ),
|
||||
FSignature("cosr16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.WORD, ::builtinCosR16 ),
|
||||
FSignature("cosr16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinCosR16u ),
|
||||
FSignature("tan" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::tan) },
|
||||
FSignature("atan" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::atan) },
|
||||
FSignature("ln" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::log) },
|
||||
FSignature("log2" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, ::log2) },
|
||||
FSignature("sqrt16" , true, listOf(FParam("value", arrayOf(DataType.UWORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { sqrt(it.toDouble()) } },
|
||||
FSignature("sqrt" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sqrt) },
|
||||
FSignature("rad" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::toRadians) },
|
||||
FSignature("deg" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::toDegrees) },
|
||||
FSignature("round" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, ::round) },
|
||||
FSignature("floor" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::floor) },
|
||||
FSignature("ceil" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::ceil) },
|
||||
FSignature("any" , true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, prg -> collectionArg(a, p, prg, ::builtinAny) },
|
||||
FSignature("all" , true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, prg -> collectionArg(a, p, prg, ::builtinAll) },
|
||||
FSignature("lsb" , true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> (x and 255).toDouble() } },
|
||||
FSignature("msb" , true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> (x ushr 8 and 255).toDouble()} },
|
||||
FSignature("mkword" , true, listOf(FParam("msb", arrayOf(DataType.UBYTE)), FParam("lsb", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinMkword),
|
||||
FSignature("peek" , true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UBYTE),
|
||||
FSignature("peekw" , true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UWORD),
|
||||
FSignature("poke" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), null),
|
||||
FSignature("pokemon" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), null),
|
||||
FSignature("pokew" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UWORD))), null),
|
||||
FSignature("pop" , false, listOf(FParam("target", ByteDatatypes)), null),
|
||||
FSignature("popw" , false, listOf(FParam("target", WordDatatypes)), null),
|
||||
FSignature("push" , false, listOf(FParam("value", ByteDatatypes)), null),
|
||||
FSignature("pushw" , false, listOf(FParam("value", WordDatatypes)), null),
|
||||
FSignature("rsave" , false, emptyList(), null),
|
||||
FSignature("rsavex" , false, emptyList(), null),
|
||||
FSignature("rrestore" , false, emptyList(), null),
|
||||
FSignature("rrestorex" , false, emptyList(), null),
|
||||
FSignature("rnd" , false, emptyList(), DataType.UBYTE),
|
||||
FSignature("rndw" , false, emptyList(), DataType.UWORD),
|
||||
FSignature("rndf" , false, emptyList(), DataType.FLOAT),
|
||||
FSignature("memory" , true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD),
|
||||
FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), null),
|
||||
FSignature("callfar" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null),
|
||||
FSignature("callrom" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null),
|
||||
|
||||
)
|
||||
FSignature("sgn" , true, listOf(FParam("value", NumericDatatypes)), true, DataType.BYTE, ::builtinSgn ),
|
||||
FSignature("sin" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sin) },
|
||||
FSignature("sin8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.BYTE, ::builtinSin8 ),
|
||||
FSignature("sin8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.UBYTE, ::builtinSin8u ),
|
||||
FSignature("sin16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.WORD, ::builtinSin16 ),
|
||||
FSignature("sin16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.UWORD, ::builtinSin16u ),
|
||||
FSignature("sinr8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.BYTE, ::builtinSinR8 ),
|
||||
FSignature("sinr8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.UBYTE, ::builtinSinR8u ),
|
||||
FSignature("sinr16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.WORD, ::builtinSinR16 ),
|
||||
FSignature("sinr16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.UWORD, ::builtinSinR16u ),
|
||||
FSignature("cos" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::cos) },
|
||||
FSignature("cos8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.BYTE, ::builtinCos8 ),
|
||||
FSignature("cos8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.UBYTE, ::builtinCos8u ),
|
||||
FSignature("cos16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.WORD, ::builtinCos16 ),
|
||||
FSignature("cos16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.UWORD, ::builtinCos16u ),
|
||||
FSignature("cosr8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.BYTE, ::builtinCosR8 ),
|
||||
FSignature("cosr8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.UBYTE, ::builtinCosR8u ),
|
||||
FSignature("cosr16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.WORD, ::builtinCosR16 ),
|
||||
FSignature("cosr16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), true, DataType.UWORD, ::builtinCosR16u ),
|
||||
FSignature("tan" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::tan) },
|
||||
FSignature("atan" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::atan) },
|
||||
FSignature("ln" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::log) },
|
||||
FSignature("log2" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, ::log2) },
|
||||
FSignature("sqrt16" , true, listOf(FParam("value", arrayOf(DataType.UWORD))), true, DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { sqrt(it.toDouble()) } },
|
||||
FSignature("sqrt" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sqrt) },
|
||||
FSignature("rad" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::toRadians) },
|
||||
FSignature("deg" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::toDegrees) },
|
||||
FSignature("round" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, ::round) },
|
||||
FSignature("floor" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::floor) },
|
||||
FSignature("ceil" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::ceil) },
|
||||
FSignature("any" , true, listOf(FParam("values", ArrayDatatypes)), true, DataType.UBYTE) { a, p, prg -> collectionArg(a, p, prg, ::builtinAny) },
|
||||
FSignature("all" , true, listOf(FParam("values", ArrayDatatypes)), true, DataType.UBYTE) { a, p, prg -> collectionArg(a, p, prg, ::builtinAll) },
|
||||
FSignature("lsb" , true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), true, DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> (x and 255).toDouble() } },
|
||||
FSignature("msb" , true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), true, DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> (x ushr 8 and 255).toDouble()} },
|
||||
FSignature("mkword" , true, listOf(FParam("msb", arrayOf(DataType.UBYTE)), FParam("lsb", arrayOf(DataType.UBYTE))), true, DataType.UWORD, ::builtinMkword),
|
||||
FSignature("peek" , true, listOf(FParam("address", arrayOf(DataType.UWORD))), true, DataType.UBYTE),
|
||||
FSignature("peekw" , true, listOf(FParam("address", arrayOf(DataType.UWORD))), true, DataType.UWORD),
|
||||
FSignature("poke" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), false,null),
|
||||
FSignature("pokemon" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), false,null),
|
||||
FSignature("pokew" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UWORD))), false,null),
|
||||
FSignature("pop" , false, listOf(FParam("target", ByteDatatypes)), false, null),
|
||||
FSignature("popw" , false, listOf(FParam("target", WordDatatypes)), false, null),
|
||||
FSignature("push" , false, listOf(FParam("value", ByteDatatypes)), false, null),
|
||||
FSignature("pushw" , false, listOf(FParam("value", WordDatatypes)), false, null),
|
||||
FSignature("rsave" , false, emptyList(), false,null),
|
||||
FSignature("rsavex" , false, emptyList(), false,null),
|
||||
FSignature("rrestore" , false, emptyList(), false,null),
|
||||
FSignature("rrestorex" , false, emptyList(), false,null),
|
||||
FSignature("rnd" , false, emptyList(), true, DataType.UBYTE),
|
||||
FSignature("rndw" , false, emptyList(), true, DataType.UWORD),
|
||||
FSignature("rndf" , false, emptyList(), true, DataType.FLOAT),
|
||||
FSignature("memory" , true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), true, DataType.UWORD),
|
||||
FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), false, null),
|
||||
FSignature("callfar" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), false, null),
|
||||
FSignature("callrom" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), false, null),
|
||||
)
|
||||
|
||||
val BuiltinFunctions = functionSignatures.associateBy { it.name }
|
||||
|
||||
@ -203,8 +210,10 @@ fun builtinFunctionReturnType(function: String, args: List<Expression>, program:
|
||||
}
|
||||
|
||||
val func = BuiltinFunctions.getValue(function)
|
||||
if(func.known_returntype!=null)
|
||||
return InferredTypes.knownFor(func.known_returntype)
|
||||
if(func.returnType!=null)
|
||||
return InferredTypes.knownFor(func.returnType)
|
||||
if(!func.hasReturn)
|
||||
return InferredTypes.InferredType.void()
|
||||
|
||||
// function has return values, but the return type depends on the arguments
|
||||
return when (function) {
|
||||
|
@ -3,7 +3,8 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
...
|
||||
- allow the last term in a pipe *statement* to be a variable, rewrite this as var = <rest of pipe>
|
||||
|
||||
|
||||
Need help with
|
||||
^^^^^^^^^^^^^^
|
||||
|
@ -2,73 +2,17 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
ubyte xx = 200
|
||||
ubyte yy = 100
|
||||
uword @shared cc
|
||||
ubyte xx = 30
|
||||
ubyte cc
|
||||
|
||||
ubyte[200] array
|
||||
; cc = 30 |> sin8u |> cos8u
|
||||
; txt.print_ub(cc)
|
||||
; txt.nl()
|
||||
cc = xx |> sin8u |> cos8u
|
||||
txt.print_ub(cc)
|
||||
txt.nl()
|
||||
|
||||
cc=array[xx+yy+10]
|
||||
|
||||
cc = xx-yy>10
|
||||
|
||||
uword qq = 100
|
||||
cmp(qq,xx)
|
||||
|
||||
simple(xx+yy)
|
||||
void routine(xx+yy, yy+99, 99, true)
|
||||
uword @shared zz = mkword(xx+yy,yy+99)
|
||||
zz = routine(1000+xx+yy, yy+99, 55, true)
|
||||
|
||||
|
||||
txt.print("1300 199 55 1 ?:\n")
|
||||
txt.print_uw(r_arg)
|
||||
txt.spc()
|
||||
txt.print_ub(r_arg2)
|
||||
txt.spc()
|
||||
txt.print_ub(r_arg3)
|
||||
txt.spc()
|
||||
txt.print_ub(r_arg4)
|
||||
txt.spc()
|
||||
|
||||
memory.mem()
|
||||
repeat {
|
||||
}
|
||||
}
|
||||
|
||||
uword @shared r_arg
|
||||
ubyte @shared r_arg2
|
||||
ubyte @shared r_arg3
|
||||
ubyte @shared r_arg4
|
||||
|
||||
asmsub simple(ubyte arg @A) {
|
||||
%asm {{
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub routine(uword arg @AY, ubyte arg2 @X, ubyte arg3 @R0, ubyte arg4 @Pc) -> ubyte @A {
|
||||
%asm {{
|
||||
pha
|
||||
lda #0
|
||||
adc #0
|
||||
sta r_arg4
|
||||
pla
|
||||
sta r_arg
|
||||
sty r_arg+1
|
||||
stx r_arg2
|
||||
lda cx16.r0
|
||||
sta r_arg3
|
||||
lda #99
|
||||
rts
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
memory {
|
||||
sub mem() {
|
||||
%asm {{
|
||||
nop
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user