first steps to support multiple args in pipe expressions

This commit is contained in:
Irmen de Jong 2022-05-07 18:44:23 +02:00
parent 942c5cc04b
commit 7c121bfc01
4 changed files with 45 additions and 29 deletions

View File

@ -442,11 +442,11 @@ class AsmGen(internal val program: Program,
internal fun translateBuiltinFunctionCallExpression(bfc: BuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) = internal fun translateBuiltinFunctionCallExpression(bfc: BuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) =
builtinFunctionsAsmGen.translateFunctioncallExpression(bfc, resultToStack, resultRegister) builtinFunctionsAsmGen.translateFunctioncallExpression(bfc, resultToStack, resultRegister)
private fun translateBuiltinFunctionCallExpression(name: String, singleArg:AsmAssignSource, scope: Subroutine): DataType = private fun translateBuiltinFunctionCallExpression(bfc: IFunctionCall, firstArg: AsmAssignSource, scope: Subroutine): DataType =
builtinFunctionsAsmGen.translateUnaryFunctioncall(name, singleArg, false, scope) builtinFunctionsAsmGen.translateFunctionCallWithFirstArg(bfc, firstArg, false, scope)
private fun translateBuiltinFunctionCallStatement(name: String, singleArg: AsmAssignSource, scope: Subroutine) = private fun translateBuiltinFunctionCallStatement(bfc: IFunctionCall, firstArg: AsmAssignSource, scope: Subroutine) =
builtinFunctionsAsmGen.translateUnaryFunctioncall(name, singleArg, true, scope) builtinFunctionsAsmGen.translateFunctionCallWithFirstArg(bfc, firstArg, true, scope)
internal fun translateFunctionCall(functionCallExpr: FunctionCallExpression, isExpression: Boolean) = internal fun translateFunctionCall(functionCallExpr: FunctionCallExpression, isExpression: Boolean) =
functioncallAsmGen.translateFunctionCall(functionCallExpr, isExpression) functioncallAsmGen.translateFunctionCall(functionCallExpr, isExpression)
@ -2829,20 +2829,20 @@ $repeatLabel lda $counterVar
AsmAssignSource.fromAstSource(source, program, this) AsmAssignSource.fromAstSource(source, program, this)
} }
// the segments (except the last one): unary function calls taking a single param and producing a value. // the segments (except the last one): function calls taking one or more parameters and producing a value.
// directly assign their argument from the previous call's returnvalue. // directly assign their first argument from the previous call's returnvalue (and take the rest, if any, from the call itself)
segments.dropLast(1).forEach { segments.dropLast(1).forEach {
it as IFunctionCall it as IFunctionCall
valueDt = translateUnaryFunctionCallWithArgSource(it.target, valueSource, false, subroutine) valueDt = translateFunctionCallWithFirstArg(it, valueSource, false, subroutine)
val resultReg = returnRegisterOfFunction(it.target) val resultReg = returnRegisterOfFunction(it.target)
valueSource = AsmAssignSource(SourceStorageKind.REGISTER, program, this, valueDt, register = resultReg) valueSource = AsmAssignSource(SourceStorageKind.REGISTER, program, this, valueDt, register = resultReg)
} }
// the last segment: unary function call taking a single param and optionally producing a result value. // the last segment: function call taking one or more parameters and optionally producing a result value.
val lastCall = segments.last() as IFunctionCall val lastCall = segments.last() as IFunctionCall
if(isStatement) { if(isStatement) {
translateUnaryFunctionCallWithArgSource(lastCall.target, valueSource, true, subroutine) translateFunctionCallWithFirstArg(lastCall, valueSource, true, subroutine)
} else { } else {
valueDt = translateUnaryFunctionCallWithArgSource(lastCall.target, valueSource, false, subroutine) valueDt = translateFunctionCallWithFirstArg(lastCall, valueSource, false, subroutine)
if(pushResultOnEstack) { if(pushResultOnEstack) {
when (valueDt) { when (valueDt) {
in ByteDatatypes -> { in ByteDatatypes -> {
@ -2860,14 +2860,23 @@ $repeatLabel lda $counterVar
} }
} }
private fun translateUnaryFunctionCallWithArgSource(target: IdentifierReference, singleArg: AsmAssignSource, isStatement: Boolean, scope: Subroutine): DataType { private fun translateFunctionCallWithFirstArg(
when(val targetStmt = target.targetStatement(program)!!) { fcall: IFunctionCall,
firstArg: AsmAssignSource,
isStatement: Boolean,
scope: Subroutine
): DataType {
if(fcall.args.isNotEmpty())
TODO("deal with additional args (non-unary function): ${fcall.target.nameInSource} (... , ${fcall.args.joinToString(", ")})")
when(val targetStmt = fcall.target.targetStatement(program)!!) {
is BuiltinFunctionPlaceholder -> { is BuiltinFunctionPlaceholder -> {
return if(isStatement) { return if(isStatement) {
translateBuiltinFunctionCallStatement(targetStmt.name, singleArg, scope) translateBuiltinFunctionCallStatement(fcall, firstArg, scope)
DataType.UNDEFINED DataType.UNDEFINED
} else { } else {
translateBuiltinFunctionCallExpression(targetStmt.name, singleArg, scope) translateBuiltinFunctionCallExpression(fcall, firstArg, scope)
} }
} }
is Subroutine -> { is Subroutine -> {
@ -2876,9 +2885,9 @@ $repeatLabel lda $counterVar
// argument via registers // argument via registers
val argRegister = targetStmt.asmParameterRegisters.single().registerOrPair!! val argRegister = targetStmt.asmParameterRegisters.single().registerOrPair!!
val assignArgument = AsmAssignment( val assignArgument = AsmAssignment(
singleArg, firstArg,
AsmAssignTarget.fromRegisters(argRegister, argDt in SignedDatatypes, scope, program, this), AsmAssignTarget.fromRegisters(argRegister, argDt in SignedDatatypes, scope, program, this),
false, program.memsizer, target.position false, program.memsizer, fcall.position
) )
translateNormalAssignment(assignArgument) translateNormalAssignment(assignArgument)
} else { } else {
@ -2892,24 +2901,24 @@ $repeatLabel lda $counterVar
else -> throw AssemblyError("invalid dt") else -> throw AssemblyError("invalid dt")
} }
AsmAssignment( AsmAssignment(
singleArg, firstArg,
AsmAssignTarget(TargetStorageKind.REGISTER, program, this, argDt, scope, register = paramReg), AsmAssignTarget(TargetStorageKind.REGISTER, program, this, argDt, scope, register = paramReg),
false, program.memsizer, target.position false, program.memsizer, fcall.position
) )
} else { } else {
// arg goes via parameter variable // arg goes via parameter variable
val argVarName = asmVariableName(targetStmt.scopedName + targetStmt.parameters.single().name) val argVarName = asmVariableName(targetStmt.scopedName + targetStmt.parameters.single().name)
AsmAssignment( AsmAssignment(
singleArg, firstArg,
AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, argDt, scope, argVarName), AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, argDt, scope, argVarName),
false, program.memsizer, target.position false, program.memsizer, fcall.position
) )
} }
translateNormalAssignment(assignArgument) translateNormalAssignment(assignArgument)
} }
if(targetStmt.shouldSaveX()) if(targetStmt.shouldSaveX())
saveRegisterLocal(CpuRegister.X, scope) saveRegisterLocal(CpuRegister.X, scope)
out(" jsr ${asmSymbolName(target)}") out(" jsr ${asmSymbolName(fcall.target)}")
if(targetStmt.shouldSaveX()) if(targetStmt.shouldSaveX())
restoreRegisterLocal(CpuRegister.X) restoreRegisterLocal(CpuRegister.X)
return if(isStatement) DataType.UNDEFINED else targetStmt.returntypes.single() return if(isStatement) DataType.UNDEFINED else targetStmt.returntypes.single()

View File

@ -30,7 +30,8 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
translateFunctioncall(fcall, func, discardResult = true, resultToStack = false, resultRegister = null) translateFunctioncall(fcall, func, discardResult = true, resultToStack = false, resultRegister = null)
} }
internal fun translateUnaryFunctioncall(name: String, singleArg: AsmAssignSource, isStatement: Boolean, scope: Subroutine): DataType { internal fun translateFunctionCallWithFirstArg(bfc: IFunctionCall, singleArg: AsmAssignSource, isStatement: Boolean, scope: Subroutine): DataType {
val name = bfc.target.nameInSource.single()
val func = BuiltinFunctions.getValue(name) val func = BuiltinFunctions.getValue(name)
val argExpression = val argExpression =
when(singleArg.kind) { when(singleArg.kind) {

View File

@ -158,8 +158,8 @@ internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorRe
when (target) { when (target) {
is BuiltinFunctionPlaceholder -> { is BuiltinFunctionPlaceholder -> {
val func = BuiltinFunctions.getValue(target.name) val func = BuiltinFunctions.getValue(target.name)
if(func.parameters.size!=1) if(func.parameters.isEmpty())
errors.err("can only use unary function", funccall.position) errors.err("function must have at least one parameter", funccall.position)
else if(func.returnType==null && funccall !== segments.last()) else if(func.returnType==null && funccall !== segments.last())
errors.err("function must return a single value", funccall.position) errors.err("function must return a single value", funccall.position)
@ -168,14 +168,12 @@ internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorRe
errors.err("pipe value datatype $valueDt incompatible with function argument ${paramDts.toList()}", funccall.position) errors.err("pipe value datatype $valueDt incompatible with function argument ${paramDts.toList()}", funccall.position)
if(errors.noErrors()) { 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.
valueDt = builtinFunctionReturnType(func.name).getOrElse { DataType.UNDEFINED } valueDt = builtinFunctionReturnType(func.name).getOrElse { DataType.UNDEFINED }
} }
} }
is Subroutine -> { is Subroutine -> {
if(target.parameters.size!=1) if(target.parameters.isEmpty())
errors.err("can only use unary function", funccall.position) errors.err("function must have at least one parameter", funccall.position)
else if(target.returntypes.size!=1 && funccall !== segments.last()) else if(target.returntypes.size!=1 && funccall !== segments.last())
errors.err("function must return a single value", funccall.position) errors.err("function must return a single value", funccall.position)

View File

@ -7,9 +7,17 @@
main { main {
sub add(ubyte first, ubyte second) -> ubyte {
return first+second
}
sub mul(ubyte first, ubyte second) -> ubyte {
return first*second
}
sub start() { sub start() {
ubyte source=99 ubyte source=99
ubyte value= source |> math.sin8u() |> math.cos8u() ubyte value = add(3,4) |> add(10) |> mul(2) |> math.sin8u() ; TODO should not work yet on vm codegen, but it compiles.... :/
txt.print_ub(value) txt.print_ub(value)
; expected output: aaabbb aaa bbb ; expected output: aaabbb aaa bbb