mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
first steps to support multiple args in pipe expressions
This commit is contained in:
parent
942c5cc04b
commit
7c121bfc01
@ -442,11 +442,11 @@ class AsmGen(internal val program: Program,
|
||||
internal fun translateBuiltinFunctionCallExpression(bfc: BuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) =
|
||||
builtinFunctionsAsmGen.translateFunctioncallExpression(bfc, resultToStack, resultRegister)
|
||||
|
||||
private fun translateBuiltinFunctionCallExpression(name: String, singleArg:AsmAssignSource, scope: Subroutine): DataType =
|
||||
builtinFunctionsAsmGen.translateUnaryFunctioncall(name, singleArg, false, scope)
|
||||
private fun translateBuiltinFunctionCallExpression(bfc: IFunctionCall, firstArg: AsmAssignSource, scope: Subroutine): DataType =
|
||||
builtinFunctionsAsmGen.translateFunctionCallWithFirstArg(bfc, firstArg, false, scope)
|
||||
|
||||
private fun translateBuiltinFunctionCallStatement(name: String, singleArg: AsmAssignSource, scope: Subroutine) =
|
||||
builtinFunctionsAsmGen.translateUnaryFunctioncall(name, singleArg, true, scope)
|
||||
private fun translateBuiltinFunctionCallStatement(bfc: IFunctionCall, firstArg: AsmAssignSource, scope: Subroutine) =
|
||||
builtinFunctionsAsmGen.translateFunctionCallWithFirstArg(bfc, firstArg, true, scope)
|
||||
|
||||
internal fun translateFunctionCall(functionCallExpr: FunctionCallExpression, isExpression: Boolean) =
|
||||
functioncallAsmGen.translateFunctionCall(functionCallExpr, isExpression)
|
||||
@ -2829,20 +2829,20 @@ $repeatLabel lda $counterVar
|
||||
AsmAssignSource.fromAstSource(source, program, this)
|
||||
}
|
||||
|
||||
// the segments (except the last one): unary function calls taking a single param and producing a value.
|
||||
// directly assign their argument from the previous call's returnvalue.
|
||||
// the segments (except the last one): function calls taking one or more parameters and producing a value.
|
||||
// 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 {
|
||||
it as IFunctionCall
|
||||
valueDt = translateUnaryFunctionCallWithArgSource(it.target, valueSource, false, subroutine)
|
||||
valueDt = translateFunctionCallWithFirstArg(it, valueSource, false, subroutine)
|
||||
val resultReg = returnRegisterOfFunction(it.target)
|
||||
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
|
||||
if(isStatement) {
|
||||
translateUnaryFunctionCallWithArgSource(lastCall.target, valueSource, true, subroutine)
|
||||
translateFunctionCallWithFirstArg(lastCall, valueSource, true, subroutine)
|
||||
} else {
|
||||
valueDt = translateUnaryFunctionCallWithArgSource(lastCall.target, valueSource, false, subroutine)
|
||||
valueDt = translateFunctionCallWithFirstArg(lastCall, valueSource, false, subroutine)
|
||||
if(pushResultOnEstack) {
|
||||
when (valueDt) {
|
||||
in ByteDatatypes -> {
|
||||
@ -2860,14 +2860,23 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateUnaryFunctionCallWithArgSource(target: IdentifierReference, singleArg: AsmAssignSource, isStatement: Boolean, scope: Subroutine): DataType {
|
||||
when(val targetStmt = target.targetStatement(program)!!) {
|
||||
private fun translateFunctionCallWithFirstArg(
|
||||
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 -> {
|
||||
return if(isStatement) {
|
||||
translateBuiltinFunctionCallStatement(targetStmt.name, singleArg, scope)
|
||||
translateBuiltinFunctionCallStatement(fcall, firstArg, scope)
|
||||
DataType.UNDEFINED
|
||||
} else {
|
||||
translateBuiltinFunctionCallExpression(targetStmt.name, singleArg, scope)
|
||||
translateBuiltinFunctionCallExpression(fcall, firstArg, scope)
|
||||
}
|
||||
}
|
||||
is Subroutine -> {
|
||||
@ -2876,9 +2885,9 @@ $repeatLabel lda $counterVar
|
||||
// argument via registers
|
||||
val argRegister = targetStmt.asmParameterRegisters.single().registerOrPair!!
|
||||
val assignArgument = AsmAssignment(
|
||||
singleArg,
|
||||
firstArg,
|
||||
AsmAssignTarget.fromRegisters(argRegister, argDt in SignedDatatypes, scope, program, this),
|
||||
false, program.memsizer, target.position
|
||||
false, program.memsizer, fcall.position
|
||||
)
|
||||
translateNormalAssignment(assignArgument)
|
||||
} else {
|
||||
@ -2892,24 +2901,24 @@ $repeatLabel lda $counterVar
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
AsmAssignment(
|
||||
singleArg,
|
||||
firstArg,
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, program, this, argDt, scope, register = paramReg),
|
||||
false, program.memsizer, target.position
|
||||
false, program.memsizer, fcall.position
|
||||
)
|
||||
} else {
|
||||
// arg goes via parameter variable
|
||||
val argVarName = asmVariableName(targetStmt.scopedName + targetStmt.parameters.single().name)
|
||||
AsmAssignment(
|
||||
singleArg,
|
||||
firstArg,
|
||||
AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, argDt, scope, argVarName),
|
||||
false, program.memsizer, target.position
|
||||
false, program.memsizer, fcall.position
|
||||
)
|
||||
}
|
||||
translateNormalAssignment(assignArgument)
|
||||
}
|
||||
if(targetStmt.shouldSaveX())
|
||||
saveRegisterLocal(CpuRegister.X, scope)
|
||||
out(" jsr ${asmSymbolName(target)}")
|
||||
out(" jsr ${asmSymbolName(fcall.target)}")
|
||||
if(targetStmt.shouldSaveX())
|
||||
restoreRegisterLocal(CpuRegister.X)
|
||||
return if(isStatement) DataType.UNDEFINED else targetStmt.returntypes.single()
|
||||
|
@ -30,7 +30,8 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
||||
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 argExpression =
|
||||
when(singleArg.kind) {
|
||||
|
@ -158,8 +158,8 @@ internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorRe
|
||||
when (target) {
|
||||
is BuiltinFunctionPlaceholder -> {
|
||||
val func = BuiltinFunctions.getValue(target.name)
|
||||
if(func.parameters.size!=1)
|
||||
errors.err("can only use unary function", funccall.position)
|
||||
if(func.parameters.isEmpty())
|
||||
errors.err("function must have at least one parameter", funccall.position)
|
||||
else if(func.returnType==null && funccall !== segments.last())
|
||||
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)
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
is Subroutine -> {
|
||||
if(target.parameters.size!=1)
|
||||
errors.err("can only use unary function", funccall.position)
|
||||
if(target.parameters.isEmpty())
|
||||
errors.err("function must have at least one parameter", funccall.position)
|
||||
else if(target.returntypes.size!=1 && funccall !== segments.last())
|
||||
errors.err("function must return a single value", funccall.position)
|
||||
|
||||
|
@ -7,9 +7,17 @@
|
||||
|
||||
main {
|
||||
|
||||
sub add(ubyte first, ubyte second) -> ubyte {
|
||||
return first+second
|
||||
}
|
||||
|
||||
sub mul(ubyte first, ubyte second) -> ubyte {
|
||||
return first*second
|
||||
}
|
||||
|
||||
sub start() {
|
||||
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)
|
||||
|
||||
; expected output: aaabbb aaa bbb
|
||||
|
Loading…
Reference in New Issue
Block a user