All Downloads are FREE. Search and download functionalities are using the official Maven repository.

parsley.internal.machine.instructions.IterativeInstrs.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2020 Parsley Contributors 
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
package parsley.internal.machine.instructions

import scala.collection.mutable

import parsley.XAssert._

import parsley.internal.machine.Context
import parsley.internal.machine.XAssert._

private [internal] final class Many(var label: Int) extends InstrWithLabel {
    override def apply(ctx: Context): Unit = {
        if (ctx.good) {
            val x = ctx.stack.upop()
            ctx.stack.peek[mutable.Builder[Any, Any]] += x
            ctx.updateCheckOffset()
            ctx.pc = label
        }
        // If the head of input stack is not the same size as the head of check stack, we fail to next handler
        else ctx.catchNoConsumed(ctx.handlers.check) {
            ctx.handlers = ctx.handlers.tail
            ctx.addErrorToHintsAndPop()
            ctx.exchangeAndContinue(ctx.stack.peek[mutable.Builder[Any, Any]].result())
        }
    }
    // $COVERAGE-OFF$
    override def toString: String = s"Many($label)"
    // $COVERAGE-ON$
}

// TODO: Factor these handlers out!
private [internal] final class SkipMany(var label: Int) extends InstrWithLabel {
    override def apply(ctx: Context): Unit = {
        if (ctx.good) {
            ctx.updateCheckOffset()
            ctx.pc = label
        }
        // If the head of input stack is not the same size as the head of check stack, we fail to next handler
        else ctx.catchNoConsumed(ctx.handlers.check) {
            ctx.handlers = ctx.handlers.tail
            ctx.addErrorToHintsAndPop()
            ctx.inc()
        }
    }
    // $COVERAGE-OFF$
    override def toString: String = s"SkipMany($label)"
    // $COVERAGE-ON$
}

private [internal] final class ChainPost(var label: Int) extends InstrWithLabel {
    override def apply(ctx: Context): Unit = {
        if (ctx.good) {
            val op = ctx.stack.pop[Any => Any]()
            ctx.stack.exchange(op(ctx.stack.upeek))
            ctx.updateCheckOffset()
            ctx.pc = label
        }
        // If the head of input stack is not the same size as the head of check stack, we fail to next handler
        else ctx.catchNoConsumed(ctx.handlers.check) {
            ctx.handlers = ctx.handlers.tail
            ctx.addErrorToHintsAndPop()
            ctx.inc()
        }
    }
    // $COVERAGE-OFF$
    override def toString: String = s"ChainPost($label)"
    // $COVERAGE-ON$
}

private [internal] final class ChainPre(var label: Int) extends InstrWithLabel {
    override def apply(ctx: Context): Unit = {
        if (ctx.good) {
            val f = ctx.stack.pop[Any => Any]()
            ctx.stack.exchange(f.andThen(ctx.stack.peek[Any => Any]))
            ctx.updateCheckOffset()
            ctx.pc = label
        }
        // If the head of input stack is not the same size as the head of check stack, we fail to next handler
        else ctx.catchNoConsumed(ctx.handlers.check) {
            ctx.handlers = ctx.handlers.tail
            ctx.addErrorToHintsAndPop()
            ctx.inc()
        }
    }
    // $COVERAGE-OFF$
    override def toString: String = s"ChainPre($label)"
    // $COVERAGE-ON$
}
private [internal] final class Chainl(var label: Int) extends InstrWithLabel {
    override def apply(ctx: Context): Unit = {
        if (ctx.good) {
            val y = ctx.stack.upop()
            val op = ctx.stack.pop[(Any, Any) => Any]()
            ctx.stack.exchange(op(ctx.stack.peek[Any], y))
            ctx.updateCheckOffset()
            ctx.pc = label
        }
        // If the head of input stack is not the same size as the head of check stack, we fail to next handler
        else ctx.catchNoConsumed(ctx.handlers.check) {
            ctx.handlers = ctx.handlers.tail
            ctx.addErrorToHintsAndPop()
            ctx.inc()
        }
    }
    // $COVERAGE-OFF$
    override def toString: String = s"Chainl($label)"
    // $COVERAGE-ON$
}

private [instructions] object DualHandler {
    def popSecondHandlerAndJump(ctx: Context, label: Int): Unit = {
        ctx.handlers = ctx.handlers.tail
        ctx.updateCheckOffset()
        ctx.pc = label
    }
}

private [internal] final class ChainrJump(var label: Int) extends InstrWithLabel {
    override def apply(ctx: Context): Unit = {
        ensureRegularInstruction(ctx)
        val f = ctx.stack.pop[(Any, Any) => Any]()
        val x = ctx.stack.upop()
        val acc = ctx.stack.peek[Any => Any]
        // We perform the acc after the tos function; the tos function is "closer" to the final p
        ctx.stack.exchange((y: Any) => acc(f(x, y)))
        DualHandler.popSecondHandlerAndJump(ctx, label)
    }

    // $COVERAGE-OFF$
    override def toString: String = s"ChainrJump($label)"
    // $COVERAGE-ON$
}

private [internal] final class ChainrOpHandler(wrap: Any => Any) extends Instr {
    override def apply(ctx: Context): Unit = {
        ensureHandlerInstruction(ctx)
        val check = ctx.handlers.check
        ctx.handlers = ctx.handlers.tail
        ctx.catchNoConsumed(check) {
            ctx.handlers = ctx.handlers.tail
            ctx.addErrorToHintsAndPop()
            val y = ctx.stack.upop()
            ctx.exchangeAndContinue(ctx.stack.peek[Any => Any](wrap(y)))
        }
    }

    // $COVERAGE-OFF$
    override def toString: String = "ChainrOpHandler"
    // $COVERAGE-ON$
}
private [internal] object ChainrOpHandler  {
    def apply[A, B](wrap: A => B): ChainrOpHandler = new ChainrOpHandler(wrap.asInstanceOf[Any => Any])
}

private [internal] final class SepEndBy1Jump(var label: Int) extends InstrWithLabel {
    override def apply(ctx: Context): Unit = {
        ensureRegularInstruction(ctx)
        val x = ctx.stack.upop()
        ctx.stack.pop_() // the bool
        ctx.stack.peek[mutable.Builder[Any, Any]] += x
        ctx.stack.upush(true)
        DualHandler.popSecondHandlerAndJump(ctx, label)
    }

    // $COVERAGE-OFF$
    override def toString: String = s"SepEndBy1Jump($label)"
    // $COVERAGE-ON$
}

private [instructions] object SepEndBy1Handlers {
    def pushAccWhenCheckValidAndContinue(ctx: Context, check: Int, acc: mutable.Builder[Any, Any], readP: Boolean): Unit = {
        if (ctx.offset != check || !readP) ctx.fail()
        else {
            ctx.addErrorToHintsAndPop()
            ctx.good = true
            ctx.exchangeAndContinue(acc.result())
        }
    }
}

private [internal] object SepEndBy1SepHandler extends Instr {
    override def apply(ctx: Context): Unit = {
        ensureHandlerInstruction(ctx)
        val check = ctx.handlers.check
        ctx.handlers = ctx.handlers.tail
        // p succeeded and sep didn't, so push p and fall-through to the whole handler
        val x = ctx.stack.upop()
        ctx.stack.pop_() // the bool is no longer needed
        val acc = ctx.stack.peek[mutable.Builder[Any, Any]]
        acc += x
        // discard the other handler and increment so that we are sat on the other handler
        assert(ctx.instrs(ctx.pc + 1) eq SepEndBy1WholeHandler, "the next instruction from the sep handler must be the whole handler")
        assert(ctx.handlers.pc == ctx.pc + 1, "the top-most handler must be the whole handler in the sep handler")
        ctx.handlers = ctx.handlers.tail
        ctx.inc()
        SepEndBy1Handlers.pushAccWhenCheckValidAndContinue(ctx, check, acc, readP = true)
    }

    // $COVERAGE-OFF$
    override def toString: String = "SepEndBy1SepHandler"
    // $COVERAGE-ON$
}

private [internal] object SepEndBy1WholeHandler extends Instr {
    override def apply(ctx: Context): Unit = {
        ensureHandlerInstruction(ctx)
        val check = ctx.handlers.check
        ctx.handlers = ctx.handlers.tail
        val readP = ctx.stack.pop[Boolean]()
        SepEndBy1Handlers.pushAccWhenCheckValidAndContinue(ctx, check, ctx.stack.peek[mutable.Builder[Any, Any]], readP)
    }

    // $COVERAGE-OFF$
    override def toString: String = "SepEndBy1WholeHandler"
    // $COVERAGE-ON$
}

private [internal] final class ManyUntil(var label: Int) extends InstrWithLabel {
    override def apply(ctx: Context): Unit = {
        ensureRegularInstruction(ctx)
        ctx.stack.upop() match {
            case parsley.combinator.ManyUntil.Stop => ctx.exchangeAndContinue(ctx.stack.peek[mutable.Builder[Any, Any]].result())
            case x =>
                ctx.stack.peek[mutable.Builder[Any, Any]] += x
                ctx.pc = label
        }
    }
    // $COVERAGE-OFF$
    override def toString: String = s"ManyUntil($label)"
    // $COVERAGE-ON$
}

private [internal] final class SkipManyUntil(var label: Int) extends InstrWithLabel {
    override def apply(ctx: Context): Unit = {
        ensureRegularInstruction(ctx)
        ctx.stack.upop() match {
            case parsley.combinator.ManyUntil.Stop => ctx.inc()
            case _ => ctx.pc = label
        }
    }
    // $COVERAGE-OFF$
    override def toString: String = s"SkipManyUntil($label)"
    // $COVERAGE-ON$
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy