funcion call parameters are now checked against function signature

This commit is contained in:
Irmen de Jong 2018-09-30 20:58:47 +02:00
parent d1589bef26
commit 734948c813
3 changed files with 53 additions and 99 deletions

View File

@ -14,76 +14,12 @@ sub start() {
word[5] warrayvar
set_carry()
clear_carry()
set_irqd()
clear_irqd()
fvar=test(34455)
return
rol(bvar)
rol(wvar)
rol(fvar)
rol(svar)
rol(spvar)
rol(ssvar)
rol(spsvar)
rol(matrixvar)
rol(barrayvar)
rol(warrayvar)
rol2(bvar)
rol2(wvar)
rol2(fvar)
rol2(svar)
rol2(spvar)
rol2(ssvar)
rol2(spsvar)
rol2(matrixvar)
rol2(barrayvar)
rol2(warrayvar)
ror(bvar)
ror(wvar)
ror(fvar)
ror(svar)
ror(spvar)
ror(ssvar)
ror(spsvar)
ror(matrixvar)
ror(barrayvar)
ror(warrayvar)
ror2(bvar)
ror2(wvar)
ror2(fvar)
ror2(svar)
ror2(spvar)
ror2(ssvar)
ror2(spsvar)
ror2(matrixvar)
ror2(barrayvar)
ror2(warrayvar)
lsl(bvar)
lsl(wvar)
lsl(fvar)
lsl(svar)
lsl(spvar)
lsl(ssvar)
lsl(spsvar)
lsl(matrixvar)
lsl(barrayvar)
lsl(warrayvar)
lsr(bvar)
lsr(wvar)
lsr(fvar)
lsr(svar)
lsr(spvar)
lsr(ssvar)
lsr(spsvar)
lsr(matrixvar)
lsr(barrayvar)
lsr(warrayvar)
sub test(arg: byte) -> float {
return 44.54
}
}
}

View File

@ -83,7 +83,10 @@ class AstChecker(private val namespace: INameScope,
if(expectedReturnValues.size != returnStmt.values.size)
checkResult.add(SyntaxError("number of return values doesn't match subroutine return spec", returnStmt.position))
// @todo: check return value types versus sub return spec
for (rv in expectedReturnValues.withIndex().zip(returnStmt.values)) {
if(rv.first.value!=rv.second.resultingDatatype(namespace, heap))
checkResult.add(ExpressionError("type of return value ${rv.first.index+1} doesn't match subroutine return type ${rv.first.value}", rv.second.position))
}
return super.process(returnStmt)
}
@ -193,14 +196,13 @@ class AstChecker(private val namespace: INameScope,
// (or if it has an asm block, that must contain a 'rts' or 'jmp')
if(subroutine.statements.count { it is Return || it is Jump } == 0) {
if(subroutine.address==null) {
val amount = subroutine.statements
.asSequence()
.filter { it is InlineAssembly }
.map {(it as InlineAssembly).assembly}
.count { "rts" in it || "\trts" in it || "jmp" in it || "\tjmp" in it }
if(amount==0 && subroutine.returnvalues.isNotEmpty())
err("subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)")
// @todo validate return values versus subroutine signature
val amount = subroutine.statements
.asSequence()
.filter { it is InlineAssembly }
.map { (it as InlineAssembly).assembly }
.count { "rts" in it || "\trts" in it || "jmp" in it || "\tjmp" in it }
if (amount == 0 && subroutine.returnvalues.isNotEmpty())
err("subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)")
}
}
@ -519,15 +521,25 @@ class AstChecker(private val namespace: INameScope,
checkResult.add(SyntaxError("cannot use arguments when calling a label", position))
if(target is BuiltinFunctionStatementPlaceholder) {
// it's a cal to a builtin function.
// todo make the signature checking similar to when calling a user-defined function
if(target.name=="set_carry" || target.name=="set_irqd" || target.name=="clear_carry" || target.name=="clear_irqd") {
// these functions have zero arguments
if(args.isNotEmpty())
checkResult.add(SyntaxError("${target.name} has zero arguments", position))
// it's a call to a builtin function.
val func = BuiltinFunctions[target.name]!!
if(args.size!=func.parameters.size)
checkResult.add(SyntaxError("invalid number of parameters", position))
else {
for (arg in args.withIndex().zip(func.parameters)) {
if(arg.first.value.resultingDatatype(namespace, heap) !in arg.second.possibleDatatypes)
checkResult.add(SyntaxError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.possibleDatatypes}", position))
}
}
} else if(target is Subroutine) {
if(args.size!=target.parameters.size)
checkResult.add(SyntaxError("invalid number of parameters", position))
else {
for (arg in args.withIndex().zip(target.parameters)) {
if(arg.first.value.resultingDatatype(namespace, heap) != arg.second.type)
checkResult.add(SyntaxError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.type}", position))
}
}
} else {
// @todo check call (params against signature) to user function
}
}

View File

@ -6,7 +6,7 @@ import kotlin.math.log2
class BuiltinFunctionParam(val name: String, possibleDatatypes: List<DataType>)
class BuiltinFunctionParam(val name: String, val possibleDatatypes: List<DataType>)
class FunctionSignature(val pure: Boolean, // does it have side effects?
val parameters: List<BuiltinFunctionParam>,
@ -67,15 +67,6 @@ val BuiltinFunctions = mapOf(
fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespace: INameScope, heap: HeapValues): DataType? {
fun integerDatatypeFromArg(arg: IExpression): DataType {
val dt = arg.resultingDatatype(namespace, heap)
return when(dt) {
DataType.BYTE -> DataType.BYTE
DataType.WORD -> DataType.WORD
DataType.FLOAT -> DataType.WORD
else -> throw FatalAstException("fuction $function can only return a numeric value")
}
}
fun datatypeFromListArg(arglist: IExpression): DataType {
if(arglist is LiteralValue) {
@ -119,7 +110,15 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
DataType.MATRIX -> DataType.BYTE
}
}
"round", "floor", "ceil" -> integerDatatypeFromArg(args.single())
"round", "floor", "ceil" -> {
val dt=args.single().resultingDatatype(namespace, heap)
when(dt) {
DataType.BYTE -> DataType.BYTE
DataType.WORD -> DataType.WORD
DataType.FLOAT -> DataType.WORD
else -> null
}
}
"sum" -> {
val dt=datatypeFromListArg(args.single())
when(dt) {
@ -205,8 +204,15 @@ private fun collectionArgOutputNumber(args: List<IExpression>, position: Positio
throw NotConstArgumentException()
function(constants.map { it!!.toDouble() }).toDouble()
} else {
val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("function requires array/matrix argument", position)
function(array.map { it.toDouble() })
when(iterable.type) {
DataType.BYTE, DataType.WORD, DataType.FLOAT -> throw SyntaxError("function expects an iterable type", position)
else -> {
if(iterable.heapId==null)
throw FatalAstException("iterable value should be on the heap")
val array = heap.get(iterable.heapId).array ?: throw SyntaxError("function expects an iterable type", position)
function(array.map { it.toDouble() })
}
}
}
return numericLiteral(result, args[0].position)
}