From cd5657d7b8cd51cfd126c03e0a6951a7e781a67a Mon Sep 17 00:00:00 2001 From: Alwinfy <20421383+Alwinfy@users.noreply.github.com> Date: Mon, 23 May 2022 18:54:33 -0400 Subject: [PATCH] Make continuations immutable and functional --- .../hexcasting/api/spell/ConstManaOperator.kt | 6 +- .../hexcasting/api/spell/OperationResult.kt | 3 +- .../petrak/hexcasting/api/spell/Operator.kt | 4 +- .../hexcasting/api/spell/SpellOperator.kt | 8 +-- .../api/spell/casting/CastingHarness.kt | 24 ++++--- .../api/spell/casting/ContinuationFrame.kt | 71 +++++++++---------- .../api/spell/casting/SpellContinuation.kt | 17 +++++ .../common/casting/operators/eval/OpEval.kt | 13 ++-- .../casting/operators/eval/OpEvalDelay.kt | 6 +- .../casting/operators/eval/OpForEach.kt | 12 +++- .../common/casting/operators/eval/OpHalt.kt | 12 ++-- .../casting/operators/lists/OpLastNToList.kt | 6 +- .../casting/operators/local/OpPeekLocal.kt | 6 +- .../casting/operators/local/OpPushLocal.kt | 6 +- .../casting/operators/spells/OpPrint.kt | 6 +- .../OpAlwinfyHasAscendedToABeingOfPureMath.kt | 5 +- .../casting/operators/stack/OpFisherman.kt | 6 +- .../casting/operators/stack/OpStackSize.kt | 6 +- 18 files changed, 127 insertions(+), 90 deletions(-) create mode 100644 Common/src/main/java/at/petrak/hexcasting/api/spell/casting/SpellContinuation.kt diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt index dc024b6b..6790f846 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt @@ -1,7 +1,7 @@ package at.petrak.hexcasting.api.spell import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.ContinuationFrame +import at.petrak.hexcasting.api.spell.casting.SpellContinuation import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs @@ -15,7 +15,7 @@ interface ConstManaOperator : Operator { fun execute(args: List>, ctx: CastingContext): List> - override fun operate(continuation: MutableList, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { + override fun operate(continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (this.argc > stack.size) throw MishapNotEnoughArgs(this.argc, stack.size) val args = stack.takeLast(this.argc) @@ -25,6 +25,6 @@ interface ConstManaOperator : Operator { val sideEffects = mutableListOf(OperatorSideEffect.ConsumeMana(this.manaCost)) - return OperationResult(stack, local, sideEffects) + return OperationResult(continuation, stack, local, sideEffects) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/OperationResult.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/OperationResult.kt index 09845dbb..5bf47985 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/OperationResult.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/OperationResult.kt @@ -1,8 +1,9 @@ package at.petrak.hexcasting.api.spell import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect +import at.petrak.hexcasting.api.spell.casting.SpellContinuation /** * What happens when an operator is through? */ -data class OperationResult(val newStack: List>, val newLocalIota: SpellDatum<*>, val sideEffects: List) +data class OperationResult(val newContinuation: SpellContinuation, val newStack: List>, val newLocalIota: SpellDatum<*>, val sideEffects: List) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt index a7245228..c34e6707 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt @@ -1,7 +1,7 @@ package at.petrak.hexcasting.api.spell import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.ContinuationFrame +import at.petrak.hexcasting.api.spell.casting.SpellContinuation import net.minecraft.world.phys.Vec3 /** @@ -22,7 +22,7 @@ interface Operator { * * A particle effect at the cast site and various messages and advancements are done automagically. */ - fun operate(continuation: MutableList, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult + fun operate(continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult /** * Do you need to be enlightened to use this operator? diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/SpellOperator.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/SpellOperator.kt index b5865f64..ba68120e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/SpellOperator.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/SpellOperator.kt @@ -1,7 +1,7 @@ package at.petrak.hexcasting.api.spell import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.ContinuationFrame +import at.petrak.hexcasting.api.spell.casting.SpellContinuation import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs @@ -17,12 +17,12 @@ interface SpellOperator : Operator { ctx: CastingContext ): Triple>? - override fun operate(continuation: MutableList, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { + override fun operate(continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (this.argc > stack.size) throw MishapNotEnoughArgs(this.argc, stack.size) val args = stack.takeLast(this.argc) for (_i in 0 until this.argc) stack.removeLast() - val executeResult = this.execute(args, ctx) ?: return OperationResult(stack, local, listOf()) + val executeResult = this.execute(args, ctx) ?: return OperationResult(continuation, stack, local, listOf()) val (spell, mana, particles) = executeResult val sideEffects = mutableListOf( @@ -33,7 +33,7 @@ interface SpellOperator : Operator { sideEffects.add(OperatorSideEffect.Particles(spray)) } - return OperationResult(stack, local, sideEffects) + return OperationResult(continuation, stack, local, sideEffects) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt index 8666c799..197cddcc 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt @@ -63,19 +63,20 @@ class CastingHarness private constructor( */ fun executeIotas(iotas: List>, world: ServerLevel): ControllerInfo { // Initialize the continuation stack to a single top-level eval for all iotas. - val continuation: MutableList = mutableListOf(ContinuationFrame.Evaluate(SpellList.LList(0, iotas))) + var continuation = SpellContinuation.Done.pushFrame(ContinuationFrame.Evaluate(SpellList.LList(0, iotas))) // Begin aggregating info val info = TempControllerInfo(false, false) var lastResolutionType = ResolvedPatternType.UNKNOWN - while (continuation.isNotEmpty() && !info.earlyExit) { + while (continuation is SpellContinuation.NotDone && !info.earlyExit) { // Take the top of the continuation stack... - val next = continuation.removeLast() + val next = continuation.frame // ...and execute it. - val result = next.evaluate(continuation, world, this) + val result = next.evaluate(continuation.next, world, this) // Then write all pertinent data back to the harness for the next iteration. if (result.newData != null) { this.applyFunctionalData(result.newData) } + continuation = result.continuation lastResolutionType = result.resolutionType performSideEffects(info, result.sideEffects) info.earlyExit = info.earlyExit || !lastResolutionType.success @@ -89,16 +90,17 @@ class CastingHarness private constructor( ) } - fun getUpdate(iota: SpellDatum<*>, world: ServerLevel, continuation: MutableList): CastResult { + fun getUpdate(iota: SpellDatum<*>, world: ServerLevel, continuation: SpellContinuation): CastResult { try { this.handleParentheses(iota)?.let { (data, resolutionType) -> - return@getUpdate CastResult(data, resolutionType, listOf()) + return@getUpdate CastResult(continuation, data, resolutionType, listOf()) } return if (iota.getType() == DatumType.PATTERN) { updateWithPattern(iota.payload as HexPattern, world, continuation) } else { CastResult( + continuation, null, ResolvedPatternType.INVALID, // Should never matter listOf( @@ -111,6 +113,7 @@ class CastingHarness private constructor( } } catch (mishap: Mishap) { return CastResult( + continuation, null, mishap.resolutionType(ctx), listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null))), @@ -118,6 +121,7 @@ class CastingHarness private constructor( } catch (exception: Exception) { exception.printStackTrace() return CastResult( + continuation, null, ResolvedPatternType.ERROR, listOf(OperatorSideEffect.DoMishap(MishapError(exception), Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null))) @@ -129,7 +133,7 @@ class CastingHarness private constructor( * When the server gets a packet from the client with a new pattern, * handle it functionally. */ - fun updateWithPattern(newPat: HexPattern, world: ServerLevel, continuation: MutableList): CastResult { + fun updateWithPattern(newPat: HexPattern, world: ServerLevel, continuation: SpellContinuation): CastResult { if (this.ctx.spellCircle == null) this.ctx.caster.awardStat(HexStatistics.PATTERNS_DRAWN) @@ -141,7 +145,7 @@ class CastingHarness private constructor( if (!HexConfig.server().isActionAllowed(operatorIdPair.second)) { throw MishapDisallowedSpell() } - val (stack2, local2, sideEffectsUnmut) = operatorIdPair.first.operate(continuation, this.stack.toMutableList(), this.localIota, this.ctx) + val (cont2, stack2, local2, sideEffectsUnmut) = operatorIdPair.first.operate(continuation, this.stack.toMutableList(), this.localIota, this.ctx) this.localIota = local2 // Stick a poofy particle effect at the caster position val sideEffects = sideEffectsUnmut.toMutableList() @@ -161,12 +165,14 @@ class CastingHarness private constructor( ) return CastResult( + cont2, fd, ResolvedPatternType.OK, sideEffects, ) } catch (mishap: Mishap) { return CastResult( + continuation, null, mishap.resolutionType(ctx), listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(newPat, operatorIdPair?.second))), @@ -174,6 +180,7 @@ class CastingHarness private constructor( } catch (exception: Exception) { exception.printStackTrace() return CastResult( + continuation, null, ResolvedPatternType.ERROR, listOf(OperatorSideEffect.DoMishap(MishapError(exception), Mishap.Context(newPat, operatorIdPair?.second))) @@ -469,6 +476,7 @@ class CastingHarness private constructor( ) data class CastResult( + val continuation: SpellContinuation, val newData: FunctionalData?, val resolutionType: ResolvedPatternType, val sideEffects: List, diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/ContinuationFrame.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/ContinuationFrame.kt index 7b8d3d01..f1ada530 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/ContinuationFrame.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/ContinuationFrame.kt @@ -23,7 +23,7 @@ sealed interface ContinuationFrame { * For Evaluate, this consumes one pattern; for ForEach this queues the next iteration of the outer loop. * @return the result of this pattern step */ - fun evaluate(continuation: MutableList, level: ServerLevel, harness: CastingHarness): CastResult + fun evaluate(continuation: SpellContinuation, level: ServerLevel, harness: CastingHarness): CastResult /** * The OpHalt instruction wants us to "jump to" the END of the nearest meta-eval. * In other words, we should consume Evaluate frames until we hit a FinishEval or Thoth frame. @@ -35,25 +35,23 @@ sealed interface ContinuationFrame { * A list of patterns to be evaluated in sequence. * @property list the *remaining* list of patterns to be evaluated */ - data class Evaluate(var list: SpellList): ContinuationFrame { + data class Evaluate(val list: SpellList): ContinuationFrame { // Discard this frame and keep discarding frames. override fun breakDownwards(stack: List>) = Pair(false, stack) // Step the list of patterns, evaluating a single one. - override fun evaluate(continuation: MutableList, level: ServerLevel, harness: CastingHarness): CastResult { + override fun evaluate(continuation: SpellContinuation, level: ServerLevel, harness: CastingHarness): CastResult { // If there are patterns left... if (list.nonEmpty) { - val toEval = list.car - list = list.cdr - if (list.nonEmpty) { // yay TCO + val newCont = if (list.cdr.nonEmpty) { // yay TCO // ...enqueue the evaluation of the rest of the patterns... - continuation.add(this) - } + continuation.pushFrame(Evaluate(list.cdr)) + } else continuation // ...before evaluating the first one in the list. - return harness.getUpdate(toEval, level, continuation) + return harness.getUpdate(list.car, level, newCont) } else { // If there are no patterns (e.g. empty Hermes), just return OK. - return CastResult(null, ResolvedPatternType.OK, listOf()) + return CastResult(continuation, null, ResolvedPatternType.OK, listOf()) } } @@ -68,8 +66,8 @@ sealed interface ContinuationFrame { override fun breakDownwards(stack: List>) = Pair(true, stack) // Evaluating it does nothing; it's only a boundary condition. - override fun evaluate(continuation: MutableList, level: ServerLevel, harness: CastingHarness): CastResult { - return CastResult(FunctionalData(harness.stack.toList(), 0, listOf(), false), ResolvedPatternType.OK, listOf()) + override fun evaluate(continuation: SpellContinuation, level: ServerLevel, harness: CastingHarness): CastResult { + return CastResult(continuation, FunctionalData(harness.stack.toList(), 0, listOf(), false), ResolvedPatternType.OK, listOf()) } } @@ -82,44 +80,45 @@ sealed interface ContinuationFrame { * @property baseStack the stack state at Thoth entry * @property acc concatenated list of final stack states after Thoth exit */ - data class ForEach(var first: Boolean, var data: SpellList, val code: SpellList, val baseStack: List>, var acc: MutableList>): ContinuationFrame { - /** Helper to append something to the original stack. */ - fun appendBase(iota: SpellDatum<*>): List> { - val mutStack = baseStack.toMutableList() - mutStack.add(iota) - return mutStack - } + data class ForEach(val data: SpellList, val code: SpellList, val baseStack: List>?, val acc: MutableList>): ContinuationFrame { /** When halting, we add the stack state at halt to the stack accumulator, then return the original pre-Thoth stack, plus the accumulator. */ override fun breakDownwards(stack: List>): Pair>> { + val newStack = baseStack!!.toMutableList() acc.addAll(stack) - return Pair(true, appendBase(SpellDatum.make(acc))) + newStack.add(SpellDatum.make(acc)) + return Pair(true, newStack) } /** Step the Thoth computation, enqueueing one code evaluation. */ - override fun evaluate(continuation: MutableList, level: ServerLevel, harness: CastingHarness): CastResult { + override fun evaluate(continuation: SpellContinuation, level: ServerLevel, harness: CastingHarness): CastResult { // If this isn't the very first Thoth step (i.e. no Thoth computations run yet)... - if (!first) { - // add everything we've added + val stack = if (baseStack == null) { + // init stack to the harness stack... + harness.stack.toList() + } else { + // else save the stack to the accumulator and reuse the saved base stack. acc.addAll(harness.stack) + baseStack } - first = false + // If we still have data to process... - val stackTop = if (data.nonEmpty) { - // queue next datum for Thoth eval. - val toEval = data.car - data = data.cdr - // Put this Thoth object: back on the stack for the next Thoth cycle, - continuation.add(this) - // and prep the Thoth'd code block for evaluation. - continuation.add(Evaluate(code)) - // Push the next datum to the top of the stack. - toEval + val (stackTop, newCont) = if (data.nonEmpty) { + Pair( + data.car, // Push the next datum to the top of the stack, + continuation + // put the next Thoth object back on the stack for the next Thoth cycle, + .pushFrame(ForEach(data.cdr, code, stack, acc)) + // and prep the Thoth'd code block for evaluation. + .pushFrame(Evaluate(code)) + ) } else { // Else, dump our final list onto the stack. - SpellDatum.make(acc) + Pair(SpellDatum.make(acc), continuation) } - return CastResult(FunctionalData(appendBase(stackTop), 0, listOf(), false), ResolvedPatternType.OK, listOf()) + val tStack = stack.toMutableList() + tStack.add(stackTop) + return CastResult(newCont, FunctionalData(tStack, 0, listOf(), false), ResolvedPatternType.OK, listOf()) } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/SpellContinuation.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/SpellContinuation.kt new file mode 100644 index 00000000..aa7cbb68 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/SpellContinuation.kt @@ -0,0 +1,17 @@ +package at.petrak.hexcasting.api.spell.casting + +import at.petrak.hexcasting.api.spell.SpellDatum +import at.petrak.hexcasting.api.spell.SpellList +import at.petrak.hexcasting.api.spell.casting.CastingHarness.CastResult +import net.minecraft.server.level.ServerLevel + +/** + * A continuation during the execution of a spell. + */ +sealed interface SpellContinuation { + object Done: SpellContinuation {} + + data class NotDone(val frame: ContinuationFrame, val next: SpellContinuation): SpellContinuation {} + + fun pushFrame(frame: ContinuationFrame): SpellContinuation = NotDone(frame, this) +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEval.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEval.kt index 1e9213e6..95d44944 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEval.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEval.kt @@ -9,20 +9,23 @@ import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingHarness import at.petrak.hexcasting.api.spell.casting.ContinuationFrame import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect +import at.petrak.hexcasting.api.spell.casting.SpellContinuation object OpEval : Operator { - override fun operate(continuation: MutableList, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { + override fun operate(continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { val instrs: SpellList = stack.getChecked(stack.lastIndex) stack.removeLastOrNull() ctx.incDepth() // if not installed already... - if (!(continuation.isNotEmpty() && continuation.last() is ContinuationFrame.FinishEval)) { - continuation.add(ContinuationFrame.FinishEval()) // install a break-boundary after eval + val newCont = if (continuation is SpellContinuation.NotDone && continuation.frame is ContinuationFrame.FinishEval) { + continuation + } else { + continuation.pushFrame(ContinuationFrame.FinishEval()) // install a break-boundary after eval } - continuation.add(ContinuationFrame.Evaluate(instrs)) - return OperationResult(stack, local, listOf()) + val frame = ContinuationFrame.Evaluate(instrs) + return OperationResult(newCont.pushFrame(frame), stack, local, listOf()) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEvalDelay.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEvalDelay.kt index 82457dac..ec0082b5 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEvalDelay.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEvalDelay.kt @@ -4,10 +4,10 @@ import at.petrak.hexcasting.api.spell.OperationResult import at.petrak.hexcasting.api.spell.Operator import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.ContinuationFrame +import at.petrak.hexcasting.api.spell.casting.SpellContinuation object OpEvalDelay : Operator { - override fun operate(continuation: MutableList, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { - return OperationResult(stack, local, listOf()) + override fun operate(continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { + return OperationResult(continuation, stack, local, listOf()) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpForEach.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpForEach.kt index 1cd7f37b..a528dff9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpForEach.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpForEach.kt @@ -10,9 +10,10 @@ import at.petrak.hexcasting.api.spell.casting.CastingHarness import at.petrak.hexcasting.api.spell.casting.ContinuationFrame import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs +import at.petrak.hexcasting.api.spell.casting.SpellContinuation object OpForEach : Operator { - override fun operate(continuation: MutableList, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { + override fun operate(continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (stack.size < 2) throw MishapNotEnoughArgs(2, stack.size) @@ -21,8 +22,13 @@ object OpForEach : Operator { stack.removeLastOrNull() stack.removeLastOrNull() - continuation.add(ContinuationFrame.ForEach(true, datums, instrs, stack, mutableListOf())) + val frame = ContinuationFrame.ForEach(datums, instrs, null, mutableListOf()) - return OperationResult(stack, local, listOf()) + return OperationResult( + continuation.pushFrame(frame), + stack, + local, + listOf() + ) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpHalt.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpHalt.kt index 4695fc89..eb0ca826 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpHalt.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpHalt.kt @@ -7,18 +7,20 @@ import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.SpellList import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingHarness -import at.petrak.hexcasting.api.spell.casting.ContinuationFrame +import at.petrak.hexcasting.api.spell.casting.SpellContinuation import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect object OpHalt : Operator { - override fun operate(continuation: MutableList, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { + override fun operate(continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { var newStack = stack.toList() var done = false - while (!done && continuation.isNotEmpty()) { + var newCont = continuation + while (!done && newCont is SpellContinuation.NotDone) { // Kotlin Y U NO destructuring assignment - val newInfo = continuation.removeLast().breakDownwards(newStack) + val newInfo = newCont.frame.breakDownwards(newStack) done = newInfo.first newStack = newInfo.second + newCont = newCont.next } // if we hit no continuation boundaries (i.e. thoth/hermes exits), we've TOTALLY cleared the itinerary... if (!done) { @@ -26,6 +28,6 @@ object OpHalt : Operator { newStack = listOf() } - return OperationResult(newStack, local, listOf()) + return OperationResult(newCont, newStack, local, listOf()) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/lists/OpLastNToList.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/lists/OpLastNToList.kt index 9ecccbc8..f2dc9db5 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/lists/OpLastNToList.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/lists/OpLastNToList.kt @@ -2,7 +2,7 @@ package at.petrak.hexcasting.common.casting.operators.lists import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.ContinuationFrame +import at.petrak.hexcasting.api.spell.casting.SpellContinuation import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs import net.minecraft.network.chat.TranslatableComponent @@ -10,7 +10,7 @@ import kotlin.math.abs import kotlin.math.roundToInt object OpLastNToList : Operator { - override fun operate(continuation: MutableList, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { + override fun operate(continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (stack.isEmpty()) throw MishapNotEnoughArgs(1, 0) val arg = stack.takeLast(1).getChecked(0) @@ -31,6 +31,6 @@ object OpLastNToList : Operator { } stack.addAll(output.asSpellResult) - return OperationResult(stack, local, listOf()) + return OperationResult(continuation, stack, local, listOf()) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPeekLocal.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPeekLocal.kt index 27cc2124..1271b513 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPeekLocal.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPeekLocal.kt @@ -4,16 +4,16 @@ import at.petrak.hexcasting.api.spell.OperationResult import at.petrak.hexcasting.api.spell.Operator import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.ContinuationFrame +import at.petrak.hexcasting.api.spell.casting.SpellContinuation object OpPeekLocal : Operator { override fun operate( - continuation: MutableList, + continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext ): OperationResult { stack.add(local) - return OperationResult(stack, local, listOf()) + return OperationResult(continuation, stack, local, listOf()) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPushLocal.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPushLocal.kt index 0e02a559..7fb1facd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPushLocal.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPushLocal.kt @@ -5,11 +5,11 @@ import at.petrak.hexcasting.api.spell.Operator import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs -import at.petrak.hexcasting.api.spell.casting.ContinuationFrame +import at.petrak.hexcasting.api.spell.casting.SpellContinuation object OpPushLocal : Operator { override fun operate( - continuation: MutableList, + continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext @@ -17,6 +17,6 @@ object OpPushLocal : Operator { if (stack.isEmpty()) throw MishapNotEnoughArgs(1, 0) val newLocal = stack.removeLast() - return OperationResult(stack, newLocal, listOf()) + return OperationResult(continuation, stack, newLocal, listOf()) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpPrint.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpPrint.kt index 82383747..9ff1eb1c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpPrint.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpPrint.kt @@ -5,19 +5,19 @@ import at.petrak.hexcasting.api.spell.Operator import at.petrak.hexcasting.api.spell.RenderedSpell import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.ContinuationFrame +import at.petrak.hexcasting.api.spell.casting.SpellContinuation import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs import net.minecraft.Util object OpPrint : Operator { - override fun operate(continuation: MutableList, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { + override fun operate(continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (stack.isEmpty()) { throw MishapNotEnoughArgs(1, 0) } val datum = stack[stack.lastIndex] return OperationResult( - stack, local, listOf( + continuation, stack, local, listOf( OperatorSideEffect.AttemptSpell(Spell(datum), false) ) ) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpAlwinfyHasAscendedToABeingOfPureMath.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpAlwinfyHasAscendedToABeingOfPureMath.kt index c82ca8f3..314f90e2 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpAlwinfyHasAscendedToABeingOfPureMath.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpAlwinfyHasAscendedToABeingOfPureMath.kt @@ -6,10 +6,10 @@ import at.petrak.hexcasting.api.spell.Operator import at.petrak.hexcasting.api.spell.getChecked import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.ContinuationFrame import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs +import at.petrak.hexcasting.api.spell.casting.SpellContinuation import it.unimi.dsi.fastutil.ints.IntArrayList import net.minecraft.network.chat.TranslatableComponent import kotlin.math.abs @@ -18,7 +18,7 @@ import kotlin.math.roundToInt // "lehmer code" object OpAlwinfyHasAscendedToABeingOfPureMath : Operator { - override fun operate(continuation: MutableList, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { + override fun operate(continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (stack.isEmpty()) throw MishapNotEnoughArgs(1, 0) // todo: better message? @@ -56,6 +56,7 @@ object OpAlwinfyHasAscendedToABeingOfPureMath : Operator { val cost = (ln((strides.lastOrNull() ?: 0).toFloat()) * ManaConstants.DUST_UNIT).toInt() return OperationResult( + continuation, stack, local, listOf(OperatorSideEffect.ConsumeMana(cost)) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpFisherman.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpFisherman.kt index 12909684..93218736 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpFisherman.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpFisherman.kt @@ -5,7 +5,7 @@ import at.petrak.hexcasting.api.spell.Operator import at.petrak.hexcasting.api.spell.getChecked import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.ContinuationFrame +import at.petrak.hexcasting.api.spell.casting.SpellContinuation import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs import net.minecraft.network.chat.TranslatableComponent @@ -13,7 +13,7 @@ import kotlin.math.abs import kotlin.math.roundToInt object OpFisherman : Operator { - override fun operate(continuation: MutableList, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { + override fun operate(continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (stack.isEmpty()) throw MishapNotEnoughArgs(1, 0) val arg = stack.getChecked(stack.lastIndex) @@ -32,6 +32,6 @@ object OpFisherman : Operator { ) } - return OperationResult(stack, local, listOf()) + return OperationResult(continuation, stack, local, listOf()) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpStackSize.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpStackSize.kt index fe739447..011adfea 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpStackSize.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpStackSize.kt @@ -4,11 +4,11 @@ import at.petrak.hexcasting.api.spell.OperationResult import at.petrak.hexcasting.api.spell.Operator import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.ContinuationFrame +import at.petrak.hexcasting.api.spell.casting.SpellContinuation object OpStackSize : Operator { - override fun operate(continuation: MutableList, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { + override fun operate(continuation: SpellContinuation, stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { stack.add(SpellDatum.make(stack.size.toDouble())) - return OperationResult(stack, local, listOf()) + return OperationResult(continuation, stack, local, listOf()) } }