Make continuations immutable and functional

This commit is contained in:
Alwinfy 2022-05-23 18:54:33 -04:00
parent cf89dfe38b
commit cd5657d7b8
No known key found for this signature in database
GPG key ID: 2CCB99445F0C949E
18 changed files with 127 additions and 90 deletions

View file

@ -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<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>>
override fun operate(continuation: MutableList<ContinuationFrame>, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
override fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, 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>(OperatorSideEffect.ConsumeMana(this.manaCost))
return OperationResult(stack, local, sideEffects)
return OperationResult(continuation, stack, local, sideEffects)
}
}

View file

@ -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<SpellDatum<*>>, val newLocalIota: SpellDatum<*>, val sideEffects: List<OperatorSideEffect>)
data class OperationResult(val newContinuation: SpellContinuation, val newStack: List<SpellDatum<*>>, val newLocalIota: SpellDatum<*>, val sideEffects: List<OperatorSideEffect>)

View file

@ -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<ContinuationFrame>, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult
fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult
/**
* Do you need to be enlightened to use this operator?

View file

@ -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<RenderedSpell, Int, List<ParticleSpray>>?
override fun operate(continuation: MutableList<ContinuationFrame>, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
override fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, 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)
}
}

View file

@ -63,19 +63,20 @@ class CastingHarness private constructor(
*/
fun executeIotas(iotas: List<SpellDatum<*>>, world: ServerLevel): ControllerInfo {
// Initialize the continuation stack to a single top-level eval for all iotas.
val continuation: MutableList<ContinuationFrame> = 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<ContinuationFrame>): 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<ContinuationFrame>): 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<OperatorSideEffect>,

View file

@ -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<ContinuationFrame>, 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<SpellDatum<*>>) = Pair(false, stack)
// Step the list of patterns, evaluating a single one.
override fun evaluate(continuation: MutableList<ContinuationFrame>, 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<SpellDatum<*>>) = Pair(true, stack)
// Evaluating it does nothing; it's only a boundary condition.
override fun evaluate(continuation: MutableList<ContinuationFrame>, 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<SpellDatum<*>>, var acc: MutableList<SpellDatum<*>>): ContinuationFrame {
/** Helper to append something to the original stack. */
fun appendBase(iota: SpellDatum<*>): List<SpellDatum<*>> {
val mutStack = baseStack.toMutableList()
mutStack.add(iota)
return mutStack
}
data class ForEach(val data: SpellList, val code: SpellList, val baseStack: List<SpellDatum<*>>?, val acc: MutableList<SpellDatum<*>>): 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<SpellDatum<*>>): Pair<Boolean, List<SpellDatum<*>>> {
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<ContinuationFrame>, 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())
}
}
}

View file

@ -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)
}

View file

@ -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<ContinuationFrame>, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
override fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, 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())
}
}

View file

@ -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<ContinuationFrame>, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
return OperationResult(stack, local, listOf())
override fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
return OperationResult(continuation, stack, local, listOf())
}
}

View file

@ -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<ContinuationFrame>, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
override fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, 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()
)
}
}

View file

@ -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<ContinuationFrame>, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
override fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, 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())
}
}

View file

@ -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<ContinuationFrame>, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
override fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
if (stack.isEmpty())
throw MishapNotEnoughArgs(1, 0)
val arg = stack.takeLast(1).getChecked<Double>(0)
@ -31,6 +31,6 @@ object OpLastNToList : Operator {
}
stack.addAll(output.asSpellResult)
return OperationResult(stack, local, listOf())
return OperationResult(continuation, stack, local, listOf())
}
}

View file

@ -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<ContinuationFrame>,
continuation: SpellContinuation,
stack: MutableList<SpellDatum<*>>,
local: SpellDatum<*>,
ctx: CastingContext
): OperationResult {
stack.add(local)
return OperationResult(stack, local, listOf())
return OperationResult(continuation, stack, local, listOf())
}
}

View file

@ -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<ContinuationFrame>,
continuation: SpellContinuation,
stack: MutableList<SpellDatum<*>>,
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())
}
}

View file

@ -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<ContinuationFrame>, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
override fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, 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)
)
)

View file

@ -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<ContinuationFrame>, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
override fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, 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))

View file

@ -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<ContinuationFrame>, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
override fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
if (stack.isEmpty())
throw MishapNotEnoughArgs(1, 0)
val arg = stack.getChecked<Double>(stack.lastIndex)
@ -32,6 +32,6 @@ object OpFisherman : Operator {
)
}
return OperationResult(stack, local, listOf())
return OperationResult(continuation, stack, local, listOf())
}
}

View file

@ -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<ContinuationFrame>, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
override fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
stack.add(SpellDatum.make(stack.size.toDouble()))
return OperationResult(stack, local, listOf())
return OperationResult(continuation, stack, local, listOf())
}
}