diff --git a/src/main/scala/parsley/internal/instructions/Context.scala b/src/main/scala/parsley/internal/instructions/Context.scala index ad58cbb60..78f34d1b8 100644 --- a/src/main/scala/parsley/internal/instructions/Context.scala +++ b/src/main/scala/parsley/internal/instructions/Context.scala @@ -1,6 +1,6 @@ package parsley.internal.instructions -import Stack.{drop, isEmpty, mkString, map} +import Stack.{drop, isEmpty, mkString, map, push} import parsley.{Failure, Result, Success} import parsley.internal.UnsafeOption @@ -88,19 +88,54 @@ final class Context private [parsley] (private [instructions] var instrs: Array[ } } + private def adjustErrorOverride(): Unit = { + if (depth < overrideDepth) { + overrideDepth = 0 + errorOverride = null + } + } + + private [instructions] def call(newInstrs: Array[Instr], at: Int, expected: UnsafeOption[String]) = { + calls = push(calls, new Frame(pc + 1, instrs)) + instrs = newInstrs + pc = at + depth += 1 + if (expected != null && errorOverride == null) + { + overrideDepth = depth + errorOverride = expected + } + } + private [instructions] def ret(): Unit = { val frame = calls.head instrs = frame.instrs calls = calls.tail pc = frame.ret depth -= 1 - if (depth < overrideDepth) { - overrideDepth = 0 - errorOverride = null + adjustErrorOverride() + } + + private def adjustErrors(e: UnsafeOption[String]): Unit = { + if (offset > erroffset) { + erroffset = offset + errcol = col + errline = line + unexpected = if (offset < inputsz) "\"" + nextChar + "\"" else "end of " + sourceName + expected = (if (errorOverride == null) e else errorOverride)::Nil + raw = Nil + unexpectAnyway = false } + else if (offset == erroffset) expected ::= (if (errorOverride == null) e else errorOverride) + adjustErrorOverride() } - private [instructions] def fail(e: UnsafeOption[String] = null): Unit = { + private [instructions] def fail(expected: UnsafeOption[String], unexpected: String): Unit = { + this.fail(expected) + this.unexpected = unexpected + this.unexpectAnyway = true + } + private [instructions] def fail(expected: UnsafeOption[String] = null): Unit = { if (isEmpty(handlers)) { status = Failed if (erroffset == -1) { @@ -114,7 +149,7 @@ final class Context private [parsley] (private [instructions] var instrs: Array[ handlers = handlers.tail val diffdepth = depth - handler.depth - 1 if (diffdepth >= 0) { - val calls_ = if (diffdepth != 0) drop(calls, diffdepth) else calls + val calls_ = drop(calls, diffdepth) instrs = calls_.head.instrs calls = calls_.tail } @@ -123,20 +158,7 @@ final class Context private [parsley] (private [instructions] var instrs: Array[ if (diffstack > 0) stack.drop(diffstack) depth = handler.depth } - if (offset > erroffset) { - erroffset = offset - errcol = col - errline = line - unexpected = if (offset < inputsz) "\"" + nextChar + "\"" else "end of " + sourceName - expected = (if (errorOverride == null) e else errorOverride)::Nil - raw = Nil - unexpectAnyway = false - } - else if (offset == erroffset) expected ::= (if (errorOverride == null) e else errorOverride) - if (depth < overrideDepth) { - overrideDepth = 0 - errorOverride = null - } + adjustErrors(expected) } private def errorMessage: String = { @@ -147,24 +169,39 @@ final class Context private [parsley] (private [instructions] var instrs: Array[ val rawFiltered = raw.filterNot(_.isEmpty) val expectedStr = if (expectedFiltered.isEmpty) None else Some(s"expected ${expectedFiltered.distinct.reverse.mkString(" or ")}") val rawStr = if (rawFiltered.isEmpty) None else Some(rawFiltered.distinct.reverse.mkString(" or ")) - unexpectAnyway = unexpectAnyway || expectedFlat.nonEmpty || raw.nonEmpty - if (rawStr.isEmpty && expectedStr.isEmpty && unexpectAnyway) { - s"$posStr\n ${unexpectedStr.getOrElse("unknown parse error")}" - } - else if (rawStr.isEmpty && expectedStr.isEmpty) { - s"$posStr\n unknown parse error" - } - else if (expectedStr.isEmpty) { - s"$posStr\n ${rawStr.get}" - } - else { - s"$posStr${unexpectedStr.fold("")("\n " + _)}\n ${expectedStr.get}${rawStr.fold("")("\n " + _)}" - } + unexpectAnyway ||= expectedFlat.nonEmpty || raw.nonEmpty + if (expectedStr.nonEmpty) s"$posStr${unexpectedStr.fold("")("\n " + _)}\n ${expectedStr.get}${rawStr.fold("")("\n " + _)}" + else if (rawStr.nonEmpty) s"$posStr\n ${rawStr.get}" + else if (unexpectAnyway) s"$posStr\n ${unexpectedStr.getOrElse("unknown parse error")}" + else s"$posStr\n unknown parse error" } + private [instructions] def pushAndContinue(x: Any) = { + stack.push(x) + inc() + } + private [instructions] def exchangeAndContinue(x: Any) = { + stack.exchange(x) + inc() + } private [instructions] def inc(): Unit = pc += 1 private [instructions] def nextChar: Char = input(offset) private [instructions] def moreInput: Boolean = offset < inputsz + private [instructions] def pushHandler(label: Int): Unit = handlers = push(handlers, new Handler(depth, label, stack.usize)) + private [instructions] def pushCheck(): Unit = checkStack = push(checkStack, offset) + private [instructions] def saveState(): Unit = states = push(states, new State(offset, line, col, regs)) + private [instructions] def restoreState(): Unit = { + val state = states.head + states = states.tail + offset = state.offset + line = state.line + col = state.col + regs = state.regs + } + private [instructions] def copyOnWrite(v: Int, x: Any): Unit = { + if (!isEmpty(states) && (states.head.regs eq regs)) regs = regs.clone + regs(v) = x + } // Allows us to reuse a context, helpful for benchmarking and potentially user applications private [parsley] def apply(_instrs: Array[Instr], _input: Array[Char]): Context = { @@ -199,4 +236,4 @@ final class Context private [parsley] (private [instructions] var instrs: Array[ private [parsley] object Context { private [Context] val NumRegs = 4 def empty: Context = new Context(null, Array.emptyCharArray) -} +} \ No newline at end of file diff --git a/src/main/scala/parsley/internal/instructions/CoreInstrs.scala b/src/main/scala/parsley/internal/instructions/CoreInstrs.scala index 040f2932e..c6f204447 100644 --- a/src/main/scala/parsley/internal/instructions/CoreInstrs.scala +++ b/src/main/scala/parsley/internal/instructions/CoreInstrs.scala @@ -9,75 +9,55 @@ import scala.annotation.tailrec import scala.language.existentials // Stack Manipulators -private [internal] final class Push[A](x: A) extends Instr -{ - override def apply(ctx: Context): Unit = - { - ctx.stack.push(x) - ctx.inc() - } +private [internal] final class Push[A](x: A) extends Instr { + override def apply(ctx: Context): Unit = ctx.pushAndContinue(x) override def toString: String = s"Push($x)" } -private [internal] object Pop extends Instr -{ - override def apply(ctx: Context): Unit = - { +private [internal] object Pop extends Instr { + override def apply(ctx: Context): Unit = { ctx.stack.pop_() ctx.inc() } override def toString: String = "Pop" } -private [internal] object Flip extends Instr -{ - override def apply(ctx: Context): Unit = - { - val y = ctx.stack.upeek - ctx.stack.exchange(ctx.stack(1)) - ctx.stack(1) = y - ctx.inc() +private [internal] object Flip extends Instr { + override def apply(ctx: Context): Unit = { + val x = ctx.stack(1) + ctx.stack(1) = ctx.stack.upeek + ctx.exchangeAndContinue(x) } override def toString: String = "Flip" } // Primitives -private [internal] class CharTok protected (protected final val c: Char, _expected: UnsafeOption[String]) extends Instr -{ +private [internal] class CharTok protected (protected final val c: Char, _expected: UnsafeOption[String]) extends Instr { protected val expected: String = if (_expected == null) "\"" + c + "\"" else _expected protected final val ac: Any = c - override def apply(ctx: Context): Unit = - { - if (ctx.moreInput && ctx.nextChar == c) - { - ctx.stack.push(ac) - ctx.offset += 1 - ctx.col += 1 - ctx.inc() + override def apply(ctx: Context): Unit = { + if (ctx.moreInput && ctx.nextChar == c) { + ctx.offset += 1 + ctx.col += 1 + ctx.pushAndContinue(ac) } else ctx.fail(expected) } override final def toString: String = s"Chr($c)" } -private [internal] final class Satisfies(f: Char => Boolean, expected: UnsafeOption[String]) extends Instr -{ - override def apply(ctx: Context): Unit = - { - if (ctx.moreInput) - { +private [internal] final class Satisfies(f: Char => Boolean, expected: UnsafeOption[String]) extends Instr { + override def apply(ctx: Context): Unit = { + if (ctx.moreInput) { val c = ctx.nextChar - if (f(ctx.nextChar)) - { - ctx.stack.push(c) + if (f(ctx.nextChar)) { ctx.offset += 1 - c match - { + c match { case '\n' => ctx.line += 1; ctx.col = 1 case '\t' => ctx.col += 4 - ((ctx.col - 1) & 3) case _ => ctx.col += 1 } - ctx.inc() + ctx.pushAndContinue(c) } else ctx.fail(expected) } @@ -86,27 +66,23 @@ private [internal] final class Satisfies(f: Char => Boolean, expected: UnsafeOpt override def toString: String = "Sat(?)" } -private [internal] final class StringTok(s: String, _expected: UnsafeOption[String]) extends Instr -{ +private [internal] final class StringTok(s: String, _expected: UnsafeOption[String]) extends Instr { private [this] val expected = if (_expected == null) "\"" + s + "\"" else _expected private [this] val cs = s.toCharArray private [this] val sz = cs.length private [this] val adjustAtIndex = new Array[(Int => Int, Int => Int)](s.length + 1) def makeAdjusters(col: Int, line: Int, tabprefix: Option[Int]): (Int => Int, Int => Int) = if (line > 0) ((_: Int) => col, (x: Int) => x + line) - else (tabprefix match - { + else (tabprefix match { case Some(prefix) => val outer = 4 + col + prefix val inner = prefix - 1 (x: Int) => outer + x - ((x + inner) & 3) case None => (x: Int) => x + col }, (x: Int) => x) - @tailrec def compute(cs: Array[Char], i: Int = 0, col: Int = 0, line: Int = 0)(implicit tabprefix: Option[Int] = None): Unit = - { + @tailrec def compute(cs: Array[Char], i: Int = 0, col: Int = 0, line: Int = 0)(implicit tabprefix: Option[Int] = None): Unit = { adjustAtIndex(i) = makeAdjusters(col, line, tabprefix) - if (i < cs.length) cs(i) match - { + if (i < cs.length) cs(i) match { case '\n' => compute(cs, i + 1, 1, line + 1)(Some(0)) case '\t' if tabprefix.isEmpty => compute(cs, i + 1, 0, line)(Some(col)) case '\t' => compute(cs, i + 1, col + 4 - ((col - 1) & 3), line) @@ -115,21 +91,17 @@ private [internal] final class StringTok(s: String, _expected: UnsafeOption[Stri } compute(cs) - override def apply(ctx: Context): Unit = - { + override def apply(ctx: Context): Unit = { val strsz = this.sz val inputsz = ctx.inputsz val input = ctx.input var i = ctx.offset var j = 0 val cs = this.cs - if (inputsz != i) - { - while (j < strsz) - { + if (inputsz != i) { + while (j < strsz) { val c = cs(j) - if (i == inputsz || input(i) != c) - { + if (i == inputsz || input(i) != c) { ctx.offset = i val (colAdjust, lineAdjust) = adjustAtIndex(j) ctx.col = colAdjust(ctx.col) @@ -144,8 +116,7 @@ private [internal] final class StringTok(s: String, _expected: UnsafeOption[Stri ctx.col = colAdjust(ctx.col) ctx.line = lineAdjust(ctx.line) ctx.offset = i - ctx.stack.push(s) - ctx.inc() + ctx.pushAndContinue(s) } else ctx.fail(expected) } @@ -153,107 +124,58 @@ private [internal] final class StringTok(s: String, _expected: UnsafeOption[Stri } // Applicative Functors -private [internal] object Apply extends Instr -{ - override def apply(ctx: Context): Unit = - { +private [internal] object Apply extends Instr { + override def apply(ctx: Context): Unit = { val x = ctx.stack.upop() val f = ctx.stack.peek[Any => Any] - ctx.stack.exchange(f(x)) - ctx.inc() + ctx.exchangeAndContinue(f(x)) } override def toString: String = "Apply" } // Monadic -private [internal] final class DynCall[-A](f: A => Array[Instr], expected: UnsafeOption[String]) extends Instr -{ +private [internal] final class DynCall[-A](f: A => Array[Instr], expected: UnsafeOption[String]) extends Instr { private [DynCall] val g = f.asInstanceOf[Any => Array[Instr]] - override def apply(ctx: Context): Unit = - { - ctx.calls = push(ctx.calls, new Frame(ctx.pc + 1, ctx.instrs)) - ctx.instrs = g(ctx.stack.upop()) - ctx.depth += 1 - ctx.pc = 0 - if (expected != null && ctx.errorOverride == null) - { - ctx.overrideDepth = ctx.depth - ctx.errorOverride = expected - } - } + override def apply(ctx: Context): Unit = ctx.call(g(ctx.stack.upop()), 0, expected) override def toString: String = "DynCall(?)" } // Control Flow -private [internal] final class Call(_instrs: =>Array[Instr], expected: UnsafeOption[String]) extends Instr -{ +private [internal] final class Call(_instrs: =>Array[Instr], expected: UnsafeOption[String]) extends Instr { private [Call] lazy val (instrs, pindices) = { val is = _instrs (is, statefulIndices(is)) } - override def apply(ctx: Context): Unit = - { - ctx.calls = push(ctx.calls, new Frame(ctx.pc + 1, ctx.instrs)) - ctx.instrs = stateSafeCopy(instrs, pindices) - ctx.depth += 1 - if (expected != null && ctx.errorOverride == null) - { - ctx.overrideDepth = ctx.depth - ctx.errorOverride = expected - } - ctx.pc = 0 - } + override def apply(ctx: Context): Unit = ctx.call(stateSafeCopy(instrs, pindices), 0, expected) override def toString: String = "Call" } -private [internal] final class GoSub(var label: Int, expected: UnsafeOption[String]) extends JumpInstr -{ - override def apply(ctx: Context): Unit = - { - ctx.calls = push(ctx.calls, new Frame(ctx.pc + 1, ctx.instrs)) - ctx.pc = label - ctx.depth += 1 - if (expected != null && ctx.errorOverride == null) - { - ctx.overrideDepth = ctx.depth - ctx.errorOverride = expected - } - } +private [internal] final class GoSub(var label: Int, expected: UnsafeOption[String]) extends JumpInstr { + override def apply(ctx: Context): Unit = ctx.call(ctx.instrs, label, expected) override def toString: String = s"GoSub($label)" } -private [internal] object Return extends Instr -{ +private [internal] object Return extends Instr { override def apply(ctx: Context): Unit = ctx.ret() override def toString: String = "Return" } -private [internal] final class Fail(msg: String, expected: UnsafeOption[String]) extends Instr -{ - override def apply(ctx: Context): Unit = - { +private [internal] final class Fail(msg: String, expected: UnsafeOption[String]) extends Instr { + override def apply(ctx: Context): Unit = { ctx.fail(expected) ctx.raw ::= msg } override def toString: String = s"Fail($msg)" } -private [internal] final class Unexpected(msg: String, expected: UnsafeOption[String]) extends Instr -{ - override def apply(ctx: Context): Unit = - { - ctx.fail(expected) - ctx.unexpected = msg - ctx.unexpectAnyway = true - } +private [internal] final class Unexpected(msg: String, expected: UnsafeOption[String]) extends Instr { + override def apply(ctx: Context): Unit = ctx.fail(expected = expected, unexpected = msg) override def toString: String = s"Unexpected($msg)" } -private [internal] final class Empty(expected: UnsafeOption[String]) extends Instr -{ - override def apply(ctx: Context): Unit = - { +private [internal] final class Empty(expected: UnsafeOption[String]) extends Instr { + override def apply(ctx: Context): Unit = { val strip = ctx.expected.isEmpty ctx.fail(expected) if (strip) ctx.unexpected = null @@ -261,70 +183,48 @@ private [internal] final class Empty(expected: UnsafeOption[String]) extends Ins override def toString: String = "Empty" } -private [internal] final class PushHandler(var label: Int) extends JumpInstr -{ - override def apply(ctx: Context): Unit = - { - ctx.handlers = push(ctx.handlers, new Handler(ctx.depth, label, ctx.stack.usize)) - ctx.states = push(ctx.states, new State(ctx.offset, ctx.line, ctx.col, ctx.regs)) +private [internal] final class PushHandler(var label: Int) extends JumpInstr { + override def apply(ctx: Context): Unit = { + ctx.pushHandler(label) + ctx.saveState() ctx.inc() } override def toString: String = s"PushHandler($label)" } -private [internal] final class PushFallthrough(var label: Int) extends JumpInstr -{ - override def apply(ctx: Context): Unit = - { - ctx.handlers = push(ctx.handlers, new Handler(ctx.depth, label, ctx.stack.usize)) +private [internal] final class PushFallthrough(var label: Int) extends JumpInstr { + override def apply(ctx: Context): Unit = { + ctx.pushHandler(label) ctx.inc() } override def toString: String = s"PushFallthrough($label)" } -private [internal] object Attempt extends Instr -{ - override def apply(ctx: Context): Unit = - { +private [internal] object Attempt extends Instr { + override def apply(ctx: Context): Unit = { // Remove the recovery input from the stack, it isn't needed anymore - if (ctx.status eq Good) - { + if (ctx.status eq Good) { ctx.states = ctx.states.tail ctx.handlers = ctx.handlers.tail ctx.inc() } // Pop input off head then fail to next handler - else - { - val state = ctx.states.head - ctx.states = ctx.states.tail - ctx.offset = state.offset - ctx.line = state.line - ctx.col = state.col - ctx.regs = state.regs + else { + ctx.restoreState() ctx.fail() } } override def toString: String = "Attempt" } -private [internal] object Look extends Instr -{ - override def apply(ctx: Context): Unit = - { - if (ctx.status eq Good) - { - val state = ctx.states.head - ctx.states = ctx.states.tail - ctx.offset = state.offset - ctx.line = state.line - ctx.col = state.col - ctx.regs = state.regs +private [internal] object Look extends Instr { + override def apply(ctx: Context): Unit = { + if (ctx.status eq Good) { + ctx.restoreState() ctx.handlers = ctx.handlers.tail ctx.inc() } - else - { + else { ctx.states = ctx.states.tail ctx.fail() } @@ -332,27 +232,22 @@ private [internal] object Look extends Instr override def toString: String = "Look" } -private [internal] final class InputCheck(var label: Int) extends JumpInstr -{ - override def apply(ctx: Context): Unit = - { - ctx.checkStack = push(ctx.checkStack, ctx.offset) - ctx.handlers = push(ctx.handlers, new Handler(ctx.depth, label, ctx.stack.usize)) +private [internal] final class InputCheck(var label: Int) extends JumpInstr { + override def apply(ctx: Context): Unit = { + ctx.pushCheck() + ctx.pushHandler(label) ctx.inc() } override def toString: String = s"InputCheck($label)" } -private [internal] final class Jump(var label: Int) extends JumpInstr -{ +private [internal] final class Jump(var label: Int) extends JumpInstr { override def apply(ctx: Context): Unit = ctx.pc = label override def toString: String = s"Jump($label)" } -private [internal] final class JumpGood(var label: Int) extends JumpInstr -{ - override def apply(ctx: Context): Unit = - { +private [internal] final class JumpGood(var label: Int) extends JumpInstr { + override def apply(ctx: Context): Unit = { ctx.handlers = ctx.handlers.tail ctx.checkStack = ctx.checkStack.tail ctx.pc = label @@ -360,13 +255,10 @@ private [internal] final class JumpGood(var label: Int) extends JumpInstr override def toString: String = s"JumpGood($label)" } -private [internal] object Catch extends Instr -{ - override def apply(ctx: Context): Unit = - { +private [internal] object Catch extends Instr { + override def apply(ctx: Context): Unit = { if (ctx.offset != ctx.checkStack.head) ctx.fail() - else - { + else { ctx.status = Good ctx.inc() } @@ -376,99 +268,65 @@ private [internal] object Catch extends Instr } // Position Extractors -private [internal] object Line extends Instr -{ - override def apply(ctx: Context): Unit = - { - ctx.stack.push(ctx.line) - ctx.inc() - } +private [internal] object Line extends Instr { + override def apply(ctx: Context): Unit = ctx.pushAndContinue(ctx.line) override def toString: String = "Line" } -private [internal] object Col extends Instr -{ - override def apply(ctx: Context): Unit = - { - ctx.stack.push(ctx.col) - ctx.inc() - } +private [internal] object Col extends Instr { + override def apply(ctx: Context): Unit = ctx.pushAndContinue(ctx.col) override def toString: String = "Col" } // Register-Manipulators -private [internal] final class Get(v: Int) extends Instr -{ - override def apply(ctx: Context): Unit = - { - ctx.stack.push(ctx.regs(v)) - ctx.inc() - } +private [internal] final class Get(v: Int) extends Instr { + override def apply(ctx: Context): Unit = ctx.pushAndContinue(ctx.regs(v)) override def toString: String = s"Get($v)" } -private [internal] final class Put(v: Int) extends Instr -{ - override def apply(ctx: Context): Unit = - { - if (!isEmpty(ctx.states) && (ctx.states.head.regs eq ctx.regs)) ctx.regs = ctx.regs.clone - ctx.regs(v) = ctx.stack.peekAndExchange(()) +private [internal] final class Put(v: Int) extends Instr { + override def apply(ctx: Context): Unit = { + ctx.copyOnWrite(v, ctx.stack.peekAndExchange(())) ctx.inc() } override def toString: String = s"Put($v)" } -private [internal] final class Modify[S](v: Int, f: S => S) extends Instr -{ +private [internal] final class Modify[S](v: Int, f: S => S) extends Instr { private [this] val g = f.asInstanceOf[Any => Any] - override def apply(ctx: Context): Unit = - { - if (!isEmpty(ctx.states) && (ctx.states.head.regs eq ctx.regs)) ctx.regs = ctx.regs.clone - ctx.regs(v) = g(ctx.regs(v)) - ctx.stack.push(()) - ctx.inc() + override def apply(ctx: Context): Unit = { + ctx.copyOnWrite(v, g(ctx.regs(v))) + ctx.pushAndContinue(()) } override def toString: String = s"Modify($v, f)" } -private [internal] final class LocalEntry(v: Int) extends Instr -{ - override def apply(ctx: Context): Unit = - { - ctx.states = push(ctx.states, new State(0, 0, 0, ctx.regs)) - ctx.regs = ctx.regs.clone - ctx.regs(v) = ctx.stack.upop() +private [internal] final class LocalEntry(v: Int) extends Instr { + override def apply(ctx: Context): Unit = { + ctx.saveState() + // This will always cause a copy + ctx.copyOnWrite(v, ctx.stack.upop()) ctx.inc() } override def toString: String = s"LocalEntry($v)" } -private [internal] final class LocalExit[S](v: Int) extends Instr -{ - override def apply(ctx: Context): Unit = - { - if (ctx.status eq Good) - { - val x = ctx.states.head.regs(v) - ctx.states = ctx.states.tail - ctx.regs(v) = x +private [internal] final class LocalExit[S](v: Int) extends Instr { + override def apply(ctx: Context): Unit = { + if (ctx.status eq Good) { + ctx.regs(v) = ctx.states.head.regs(v) ctx.inc() } - else - { - ctx.states = ctx.states.tail - ctx.fail() - } + else ctx.fail() + ctx.states = ctx.states.tail } override def toString: String = s"LocalExit($v)" } // Debugging Instructions -private [instructions] trait Logger -{ +private [instructions] trait Logger { val name: String - final protected def preludeString(dir: Char, ctx: Context, ends: String = "") = - { + final protected def preludeString(dir: Char, ctx: Context, ends: String = "") = { val indent = this.indent(ctx) val start = Math.max(ctx.offset - 5, 0) val end = Math.min(ctx.offset + 6, ctx.inputsz) @@ -482,32 +340,26 @@ private [instructions] trait Logger final protected def indent(ctx: Context) = " " * (ctx.debuglvl * 2) } -private [internal] final class LogBegin(var label: Int, val name: String, break: Boolean) extends JumpInstr with Logger -{ - override def apply(ctx: Context): Unit = - { +private [internal] final class LogBegin(var label: Int, val name: String, break: Boolean) extends JumpInstr with Logger { + override def apply(ctx: Context): Unit = { println(preludeString('>', ctx)) - if (break) - { + if (break) { print(s"${indent(ctx)}{stack: ${ctx.stack.mkString(", ")}})\n" + s"${indent(ctx)}{registers: ${ctx.regs.zipWithIndex.map{case (x, i) => s"r$i: $x"}.mkString("[", ", ", "])}")}}\n" + s"${indent(ctx)}...") Console.in.read() } ctx.debuglvl += 1 - ctx.handlers = push(ctx.handlers, new Handler(ctx.depth, label, ctx.stack.usize)) + ctx.pushHandler(label) ctx.inc() } override def toString: String = s"LogBegin($label, $name)" } -private [internal] final class LogEnd(val name: String, break: Boolean) extends Instr with Logger -{ - override def apply(ctx: Context): Unit = - { +private [internal] final class LogEnd(val name: String, break: Boolean) extends Instr with Logger { + override def apply(ctx: Context): Unit = { ctx.debuglvl -= 1 - val end = " " + (ctx.status match - { + val end = " " + (ctx.status match { case Good => ctx.handlers = ctx.handlers.tail ctx.inc() @@ -517,23 +369,19 @@ private [internal] final class LogEnd(val name: String, break: Boolean) extends Console.RED + "Fail" + Console.RESET }) println(preludeString('<', ctx, end)) - if (break) - { + if (break) { print(s"${indent(ctx)}{stack: ${ctx.stack.mkString(", ")}})\n" + s"${indent(ctx)}{registers: ${ctx.regs.zipWithIndex.map{case (x, i) => s"r$i: $x"}.mkString("[", ", ", "])}")}}\n" + s"${indent(ctx)}...") Console.in.read() } - } override def toString: String = s"LogEnd($name)" } // Extractor Objects -private [internal] object CharTok -{ - def apply(c: Char, expected: UnsafeOption[String]): CharTok = c match - { +private [internal] object CharTok { + def apply(c: Char, expected: UnsafeOption[String]): CharTok = c match { case '\n' => new Newline(expected) case '\t' => new Tab(expected) case _ => new CharTok(c, expected) diff --git a/src/main/scala/parsley/internal/instructions/IntrinsicInstrs.scala b/src/main/scala/parsley/internal/instructions/IntrinsicInstrs.scala index 546cb3c75..b3e7dcf31 100644 --- a/src/main/scala/parsley/internal/instructions/IntrinsicInstrs.scala +++ b/src/main/scala/parsley/internal/instructions/IntrinsicInstrs.scala @@ -6,90 +6,70 @@ import Stack.isEmpty import scala.collection.mutable.ListBuffer -private [internal] final class Lift2[A, B, C](f: (A, B) => C) extends Instr -{ +private [internal] final class Lift2[A, B, C](f: (A, B) => C) extends Instr { private [this] val g = f.asInstanceOf[(Any, Any) => C] - override def apply(ctx: Context): Unit = - { + override def apply(ctx: Context): Unit = { val y = ctx.stack.upop() - ctx.stack.exchange(g(ctx.stack.peek, y)) - ctx.inc() + ctx.exchangeAndContinue(g(ctx.stack.peek, y)) } override def toString: String = "Lift2(f)" } -private [internal] final class Lift3[A, B, C, D](f: (A, B, C) => D) extends Instr -{ +private [internal] final class Lift3[A, B, C, D](f: (A, B, C) => D) extends Instr { private [this] val g = f.asInstanceOf[(Any, Any, Any) => D] - override def apply(ctx: Context): Unit = - { + override def apply(ctx: Context): Unit = { val z = ctx.stack.upop() val y = ctx.stack.upop() - ctx.stack.exchange(g(ctx.stack.peek, y, z)) - ctx.inc() + ctx.exchangeAndContinue(g(ctx.stack.peek, y, z)) } override def toString: String = "Lift3(f)" } -private [internal] final class Many(var label: Int) extends JumpInstr with Stateful -{ +private [internal] final class Many(var label: Int) extends JumpInstr with Stateful { private [this] val acc: ListBuffer[Any] = ListBuffer.empty - override def apply(ctx: Context): Unit = - { - if (ctx.status eq Good) - { + override def apply(ctx: Context): Unit = { + if (ctx.status eq Good) { acc += ctx.stack.upop() ctx.checkStack.head = ctx.offset 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 if (ctx.offset != ctx.checkStack.head) { ctx.checkStack = ctx.checkStack.tail; acc.clear(); ctx.fail() } - else - { - ctx.stack.push(acc.toList) + else { + ctx.pushAndContinue(acc.toList) acc.clear() ctx.checkStack = ctx.checkStack.tail ctx.status = Good - ctx.inc() } } override def toString: String = s"Many($label)" override def copy: Many = new Many(label) } -private [internal] final class SkipMany(var label: Int) extends JumpInstr -{ - override def apply(ctx: Context): Unit = - { - if (ctx.status eq Good) - { +private [internal] final class SkipMany(var label: Int) extends JumpInstr { + override def apply(ctx: Context): Unit = { + if (ctx.status eq Good) { ctx.stack.pop_() ctx.checkStack.head = ctx.offset 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 if (ctx.offset != ctx.checkStack.head) { ctx.checkStack = ctx.checkStack.tail; ctx.fail() } - else - { + else { ctx.checkStack = ctx.checkStack.tail ctx.status = Good - ctx.stack.push(()) - ctx.inc() + ctx.pushAndContinue(()) } } override def toString: String = s"SkipMany($label)" } -private [internal] final class ChainPost(var label: Int) extends JumpInstr with Stateful -{ +private [internal] final class ChainPost(var label: Int) extends JumpInstr with Stateful { private [this] var acc: Any = _ - override def apply(ctx: Context): Unit = - { - if (ctx.status eq Good) - { + override def apply(ctx: Context): Unit = { + if (ctx.status eq Good) { // When acc is null, we are entering the instruction for the first time, a p will be on the stack - if (acc == null) - { + if (acc == null) { // after this point, the inputCheck will roll back one too many items on the stack, because this item // was consumed. It should be adjusted val op = ctx.stack.upop() @@ -103,11 +83,9 @@ private [internal] final class ChainPost(var label: Int) extends JumpInstr with } // If the head of input stack is not the same size as the head of check stack, we fail to next handler else if (ctx.offset != ctx.checkStack.head) { ctx.checkStack = ctx.checkStack.tail; acc = null; ctx.fail() } - else - { + else { // When acc is null, we have entered for first time but the op failed, so the result is already on the stack - if (acc != null) - { + if (acc != null) { ctx.stack.push(acc) acc = null } @@ -120,13 +98,10 @@ private [internal] final class ChainPost(var label: Int) extends JumpInstr with override def copy: ChainPost = new ChainPost(label) } -private [internal] final class ChainPre(var label: Int) extends JumpInstr with Stateful -{ +private [internal] final class ChainPre(var label: Int) extends JumpInstr with Stateful { private var acc: Any => Any = _ - override def apply(ctx: Context): Unit = - { - if (ctx.status eq Good) - { + override def apply(ctx: Context): Unit = { + if (ctx.status eq Good) { // If acc is null we are entering the instruction, so nothing to compose, this saves on an identity call if (acc == null) acc = ctx.stack.pop[Any => Any]() // We perform the acc after the tos function; the tos function is "closer" to the final p @@ -136,31 +111,25 @@ private [internal] final class ChainPre(var label: Int) extends JumpInstr with S } // If the head of input stack is not the same size as the head of check stack, we fail to next handler else if (ctx.offset != ctx.checkStack.head) { ctx.checkStack = ctx.checkStack.tail; acc = null; ctx.fail() } - else - { - ctx.stack.push(if (acc == null) identity[Any] _ else acc) + else { + ctx.pushAndContinue(if (acc == null) identity[Any] _ else acc) acc = null ctx.checkStack = ctx.checkStack.tail ctx.status = Good - ctx.inc() } } override def toString: String = s"ChainPre($label)" override def copy: ChainPre = new ChainPre(label) } -private [internal] final class Chainl[A, B](var label: Int, _wrap: A => B) extends JumpInstr with Stateful -{ +private [internal] final class Chainl[A, B](var label: Int, _wrap: A => B) extends JumpInstr with Stateful { private [this] val wrap: Any => B = _wrap.asInstanceOf[Any => B] private [this] var acc: Any = _ - override def apply(ctx: Context): Unit = - { - if (ctx.status eq Good) - { + override def apply(ctx: Context): Unit = { + if (ctx.status eq Good) { val y = ctx.stack.upop() val op = ctx.stack.pop[(Any, Any) => Any]() // When acc is null, we are entering the instruction for the first time, a p will be on the stack - if (acc == null) - { + if (acc == null) { // after this point, the inputCheck will roll back one too many items on the stack, because this item // was consumed. It should be adjusted acc = op(wrap(ctx.stack.upop()), y) @@ -171,14 +140,12 @@ private [internal] final class Chainl[A, B](var label: Int, _wrap: A => B) exten 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 if (ctx.offset != ctx.checkStack.head) - { + else if (ctx.offset != ctx.checkStack.head) { ctx.checkStack = ctx.checkStack.tail acc = null ctx.fail() } - else - { + else { ctx.checkStack = ctx.checkStack.tail // if acc is null this is first entry, p already on the stack! if (acc != null) ctx.stack.push(acc) @@ -190,21 +157,17 @@ private [internal] final class Chainl[A, B](var label: Int, _wrap: A => B) exten override def toString: String = s"Chainl($label)" override def copy: Chainl[A, B] = new Chainl(label, wrap) } -private [internal] final class Chainr[A, B](var label: Int, _wrap: A => B) extends JumpInstr with Stateful -{ +private [internal] final class Chainr[A, B](var label: Int, _wrap: A => B) extends JumpInstr with Stateful { private [this] val wrap: Any => B = _wrap.asInstanceOf[Any => B] private [this] var acc: Any => Any = _ - override def apply(ctx: Context): Unit = - { - if (ctx.status eq Good) - { + override def apply(ctx: Context): Unit = { + if (ctx.status eq Good) { val f = ctx.stack.pop[(Any, Any) => Any]() val x = ctx.stack.upop() // If acc is null we are entering the instruction, so nothing to compose, this saves on an identity call if (acc == null) acc = (y: Any) => f(x, y) // We perform the acc after the tos function; the tos function is "closer" to the final p - else - { + else { val acc_ = acc acc = (y: Any) => acc_(f(x, y)) } @@ -215,11 +178,9 @@ private [internal] final class Chainr[A, B](var label: Int, _wrap: A => B) exten 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 if (ctx.offset != ctx.checkStack.head) - { + else if (ctx.offset != ctx.checkStack.head) { // H1 might still be on the stack - if (!isEmpty(ctx.handlers) && ctx.handlers.head.pc == ctx.pc) - { + if (!isEmpty(ctx.handlers) && ctx.handlers.head.pc == ctx.pc) { ctx.handlers = ctx.handlers.tail ctx.checkStack = ctx.checkStack.tail.tail } @@ -227,21 +188,16 @@ private [internal] final class Chainr[A, B](var label: Int, _wrap: A => B) exten acc = null ctx.fail() } - else - { + else { // H1 is on the stack, so p succeeded, just not op - if (!isEmpty(ctx.handlers) && ctx.handlers.head.pc == ctx.pc) - { - if (acc != null) ctx.stack.exchange(acc(wrap(ctx.stack.upeek))) - else ctx.stack.exchange(wrap(ctx.stack.upeek)) - ctx.checkStack = ctx.checkStack.tail.tail + if (!isEmpty(ctx.handlers) && ctx.handlers.head.pc == ctx.pc) { + ctx.exchangeAndContinue(if (acc != null) acc(wrap(ctx.stack.upeek)) else wrap(ctx.stack.upeek)) ctx.handlers = ctx.handlers.tail - ctx.inc() + ctx.checkStack = ctx.checkStack.tail.tail ctx.status = Good } // p did not succeed and hence neither did op - else - { + else { ctx.checkStack = ctx.checkStack.tail ctx.fail() } @@ -252,13 +208,10 @@ private [internal] final class Chainr[A, B](var label: Int, _wrap: A => B) exten override def copy: Chainr[A, B] = new Chainr(label, wrap) } -private [internal] final class SepEndBy1(var label: Int) extends JumpInstr with Stateful -{ +private [internal] final class SepEndBy1(var label: Int) extends JumpInstr with Stateful { private [this] val acc: ListBuffer[Any] = ListBuffer.empty - override def apply(ctx: Context): Unit = - { - if (ctx.status eq Good) - { + override def apply(ctx: Context): Unit = { + if (ctx.status eq Good) { ctx.stack.pop_() acc += ctx.stack.upop() // Pop H2 off the stack @@ -269,11 +222,9 @@ private [internal] final class SepEndBy1(var label: Int) extends JumpInstr with 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 if (ctx.offset != ctx.checkStack.head) - { + else if (ctx.offset != ctx.checkStack.head) { // H1 might still be on the stack - if (!isEmpty(ctx.handlers) && ctx.handlers.head.pc == ctx.pc) - { + if (!isEmpty(ctx.handlers) && ctx.handlers.head.pc == ctx.pc) { ctx.handlers = ctx.handlers.tail ctx.checkStack = ctx.checkStack.tail.tail } @@ -281,23 +232,19 @@ private [internal] final class SepEndBy1(var label: Int) extends JumpInstr with acc.clear() ctx.fail() } - else - { + else { // H1 is on the stack, so p succeeded, just not sep - if (!isEmpty(ctx.handlers) && ctx.handlers.head.pc == ctx.pc) - { + if (!isEmpty(ctx.handlers) && ctx.handlers.head.pc == ctx.pc) { acc += ctx.stack.upop() ctx.checkStack = ctx.checkStack.tail.tail ctx.handlers = ctx.handlers.tail } else ctx.checkStack = ctx.checkStack.tail if (acc.isEmpty) ctx.fail() - else - { - ctx.stack.push(acc.toList) + else { + ctx.pushAndContinue(acc.toList) acc.clear() ctx.status = Good - ctx.inc() } } } @@ -305,23 +252,17 @@ private [internal] final class SepEndBy1(var label: Int) extends JumpInstr with override def copy: SepEndBy1 = new SepEndBy1(label) } -private [internal] final class ManyUntil(var label: Int) extends JumpInstr with Stateful -{ +private [internal] final class ManyUntil(var label: Int) extends JumpInstr with Stateful { private [this] val acc: ListBuffer[Any] = ListBuffer.empty - override def apply(ctx: Context): Unit = - { - if (ctx.status eq Good) - { + override def apply(ctx: Context): Unit = { + if (ctx.status eq Good) { val x = ctx.stack.upop() - if (x == deepembedding.ManyUntil.Stop) - { - ctx.stack.push(acc.toList) + if (x == deepembedding.ManyUntil.Stop) { + ctx.pushAndContinue(acc.toList) acc.clear() ctx.handlers = ctx.handlers.tail - ctx.inc() } - else - { + else { acc += x ctx.pc = label } @@ -333,24 +274,19 @@ private [internal] final class ManyUntil(var label: Int) extends JumpInstr with override def copy: ManyUntil = new ManyUntil(label) } -private [internal] final class If(var label: Int) extends JumpInstr -{ - override def apply(ctx: Context): Unit = - { +private [internal] final class If(var label: Int) extends JumpInstr { + override def apply(ctx: Context): Unit = { if (ctx.stack.pop()) ctx.pc = label else ctx.inc() } override def toString: String = s"If(true: $label)" } -private [internal] final class Filter[A](pred: A=>Boolean, expected: UnsafeOption[String]) extends Instr -{ +private [internal] final class Filter[A](pred: A=>Boolean, expected: UnsafeOption[String]) extends Instr { private [this] val pred_ = pred.asInstanceOf[Any=>Boolean] - override def apply(ctx: Context): Unit = - { + override def apply(ctx: Context): Unit = { if (pred_(ctx.stack.upeek)) ctx.inc() - else - { + else { val strip = ctx.expected.isEmpty ctx.fail(expected) if (strip) ctx.unexpected = null @@ -359,14 +295,11 @@ private [internal] final class Filter[A](pred: A=>Boolean, expected: UnsafeOptio override def toString: String = "Filter(?)" } -private [internal] final class Guard[A](pred: A=>Boolean, msg: String, expected: UnsafeOption[String]) extends Instr -{ +private [internal] final class Guard[A](pred: A=>Boolean, msg: String, expected: UnsafeOption[String]) extends Instr { private [this] val pred_ = pred.asInstanceOf[Any=>Boolean] - override def apply(ctx: Context): Unit = - { + override def apply(ctx: Context): Unit = { if (pred_(ctx.stack.upeek)) ctx.inc() - else - { + else { ctx.stack.pop_() //this might not be needed? drop handles in fail ctx.fail(expected) ctx.raw ::= msg @@ -375,15 +308,12 @@ private [internal] final class Guard[A](pred: A=>Boolean, msg: String, expected: override def toString: String = s"Guard(?, $msg)" } -private [internal] final class FastGuard[A](pred: A=>Boolean, msggen: A=>String, expected: UnsafeOption[String]) extends Instr -{ +private [internal] final class FastGuard[A](pred: A=>Boolean, msggen: A=>String, expected: UnsafeOption[String]) extends Instr { private [this] val pred_ = pred.asInstanceOf[Any=>Boolean] private [this] val msggen_ = msggen.asInstanceOf[Any=>String] - override def apply(ctx: Context): Unit = - { + override def apply(ctx: Context): Unit = { if (pred_(ctx.stack.upeek)) ctx.inc() - else - { + else { val msg = msggen_(ctx.stack.upop()) ctx.fail(expected) ctx.raw ::= msg @@ -392,11 +322,9 @@ private [internal] final class FastGuard[A](pred: A=>Boolean, msggen: A=>String, override def toString: String = "FastGuard(?, ?)" } -private [internal] final class FastFail[A](msggen: A=>String, expected: UnsafeOption[String]) extends Instr -{ +private [internal] final class FastFail[A](msggen: A=>String, expected: UnsafeOption[String]) extends Instr { private [this] val msggen_ = msggen.asInstanceOf[Any => String] - override def apply(ctx: Context): Unit = - { + override def apply(ctx: Context): Unit = { val msg = msggen_(ctx.stack.upop()) ctx.fail(expected) ctx.raw ::= msg @@ -404,60 +332,34 @@ private [internal] final class FastFail[A](msggen: A=>String, expected: UnsafeOp override def toString: String = "FastFail(?)" } -private [internal] final class FastUnexpected[A](msggen: A=>String, expected: UnsafeOption[String]) extends Instr -{ +private [internal] final class FastUnexpected[A](msggen: A=>String, expected: UnsafeOption[String]) extends Instr { private [this] val msggen_ = msggen.asInstanceOf[Any => String] - override def apply(ctx: Context): Unit = - { - val msg = msggen_(ctx.stack.upop()) - ctx.fail(expected) - ctx.unexpected = msg - ctx.unexpectAnyway = true - } + override def apply(ctx: Context): Unit = ctx.fail(expected = expected, unexpected = msggen_(ctx.stack.upop())) override def toString: String = "FastUnexpected(?)" } -private [internal] final class NotFollowedBy(expected: UnsafeOption[String]) extends Instr -{ - override def apply(ctx: Context): Unit = - { +private [internal] final class NotFollowedBy(expected: UnsafeOption[String]) extends Instr { + override def apply(ctx: Context): Unit = { // Recover the previous state; notFollowedBy NEVER consumes input - val state = ctx.states.head - ctx.states = ctx.states.tail - ctx.offset = state.offset - ctx.line = state.line - ctx.col = state.col - ctx.regs = state.regs + ctx.restoreState() // A previous success is a failure - if (ctx.status eq Good) - { + if (ctx.status eq Good) { ctx.handlers = ctx.handlers.tail - val x = ctx.stack.upop() - ctx.fail(expected) - ctx.unexpected = "\"" + x.toString + "\"" - ctx.unexpectAnyway = true + ctx.fail(expected = expected, unexpected = "\"" + ctx.stack.upop().toString + "\"") } // A failure is what we wanted - else - { + else { ctx.status = Good - ctx.stack.push(()) - ctx.inc() + ctx.pushAndContinue(()) } } override def toString: String = "NotFollowedBy" } -private [internal] class Eof(_expected: UnsafeOption[String]) extends Instr -{ +private [internal] class Eof(_expected: UnsafeOption[String]) extends Instr { val expected: String = if (_expected == null) "end of input" else _expected - override def apply(ctx: Context): Unit = - { - if (ctx.offset == ctx.inputsz) - { - ctx.stack.push(()) - ctx.inc() - } + override def apply(ctx: Context): Unit = { + if (ctx.offset == ctx.inputsz) ctx.pushAndContinue(()) else ctx.fail(expected) } override final def toString: String = "Eof" diff --git a/src/main/scala/parsley/internal/instructions/OptInstrs.scala b/src/main/scala/parsley/internal/instructions/OptInstrs.scala index 27ad1a745..6c2247f0f 100644 --- a/src/main/scala/parsley/internal/instructions/OptInstrs.scala +++ b/src/main/scala/parsley/internal/instructions/OptInstrs.scala @@ -8,110 +8,79 @@ import scala.annotation.tailrec import scala.language.implicitConversions import scala.collection.mutable -private [internal] final class Perform[-A, +B](f: A => B) extends Instr -{ +private [internal] final class Perform[-A, +B](f: A => B) extends Instr { private [Perform] val g = f.asInstanceOf[Any => B] - override def apply(ctx: Context): Unit = - { - ctx.stack.exchange(g(ctx.stack.upeek)) - ctx.inc() - } + override def apply(ctx: Context): Unit = ctx.exchangeAndContinue(g(ctx.stack.upeek)) override def toString: String = "Perform(?)" } -private [internal] final class Exchange[A](private [Exchange] val x: A) extends Instr -{ - override def apply(ctx: Context): Unit = - { - ctx.stack.exchange(x) - ctx.inc() - } +private [internal] final class Exchange[A](private [Exchange] val x: A) extends Instr { + override def apply(ctx: Context): Unit = ctx.exchangeAndContinue(x) override def toString: String = s"Ex($x)" } -private [internal] class Newline(_expected: UnsafeOption[String]) extends CharTok('\n', _expected) -{ - override def apply(ctx: Context): Unit = - { - if (ctx.moreInput && ctx.nextChar == '\n') - { - ctx.stack.push(ac) +private [internal] class Newline(_expected: UnsafeOption[String]) extends CharTok('\n', _expected) { + override def apply(ctx: Context): Unit = { + if (ctx.moreInput && ctx.nextChar == '\n') { ctx.offset += 1 ctx.col = 1 ctx.line += 1 - ctx.inc() + ctx.pushAndContinue(ac) } else ctx.fail(expected) } } -private [internal] class Tab(_expected: UnsafeOption[String]) extends CharTok('\t', _expected) -{ - override def apply(ctx: Context): Unit = - { - if (ctx.moreInput && ctx.nextChar == '\t') - { - ctx.stack.push(ac) +private [internal] class Tab(_expected: UnsafeOption[String]) extends CharTok('\t', _expected) { + override def apply(ctx: Context): Unit = { + if (ctx.moreInput && ctx.nextChar == '\t') { ctx.offset += 1 ctx.col += 4 - ((ctx.col - 1) & 3) - ctx.inc() + ctx.pushAndContinue(ac) } else ctx.fail(expected) } } private [internal] class CharTokFastPerform protected (protected final val c: Char, protected final val f: Char => Any, _expected: UnsafeOption[String]) - extends Instr -{ + extends Instr { protected val expected: String = if (_expected == null) "\"" + c.toString + "\"" else _expected protected final val fc: Any = f(c) - override def apply(ctx: Context): Unit = - { - if (ctx.moreInput && ctx.nextChar == c) - { - ctx.stack.push(fc) + override def apply(ctx: Context): Unit = { + if (ctx.moreInput && ctx.nextChar == c) { ctx.offset += 1 ctx.col += 1 - ctx.inc() + ctx.pushAndContinue(fc) } else ctx.fail(expected) } override final def toString: String = s"ChrPerform($c, ?)" } -private [internal] final class NewlineFastPerform(g: Char => Any, _expected: UnsafeOption[String]) extends CharTokFastPerform('\n', g, _expected) -{ - override def apply(ctx: Context): Unit = - { - if (ctx.moreInput && ctx.nextChar == '\n') - { - ctx.stack.push(fc) +private [internal] final class NewlineFastPerform(g: Char => Any, _expected: UnsafeOption[String]) extends CharTokFastPerform('\n', g, _expected) { + override def apply(ctx: Context): Unit = { + if (ctx.moreInput && ctx.nextChar == '\n') { ctx.offset += 1 ctx.col = 1 ctx.line += 1 - ctx.inc() + ctx.pushAndContinue(fc) } else ctx.fail(expected) } } -private [internal] final class TabFastPerform(g: Char => Any, _expected: UnsafeOption[String]) extends CharTokFastPerform('\t', g, _expected) -{ - override def apply(ctx: Context): Unit = - { - if (ctx.moreInput && ctx.nextChar == '\t') - { - ctx.stack.push(fc) +private [internal] final class TabFastPerform(g: Char => Any, _expected: UnsafeOption[String]) extends CharTokFastPerform('\t', g, _expected) { + override def apply(ctx: Context): Unit = { + if (ctx.moreInput && ctx.nextChar == '\t') { ctx.offset += 1 ctx.col += 4 - ((ctx.col - 1) & 3) - ctx.inc() + ctx.pushAndContinue(fc) } else ctx.fail(expected) } } -private [internal] final class StringTokFastPerform(s: String, f: String => Any, _expected: UnsafeOption[String]) extends Instr -{ +private [internal] final class StringTokFastPerform(s: String, f: String => Any, _expected: UnsafeOption[String]) extends Instr { protected val expected: String = if (_expected == null) "\"" + s + "\"" else _expected private [this] val cs = s.toCharArray private [this] val sz = cs.length @@ -119,19 +88,16 @@ private [internal] final class StringTokFastPerform(s: String, f: String => Any, private [this] val adjustAtIndex = new Array[(Int => Int, Int => Int)](s.length + 1) def makeAdjusters(col: Int, line: Int, tabprefix: Option[Int]): (Int => Int, Int => Int) = if (line > 0) ((_: Int) => col, (x: Int) => x + line) - else (tabprefix match - { + else (tabprefix match { case Some(prefix) => val outer = 4 + col + prefix val inner = prefix - 1 (x: Int) => outer + x - ((x + inner) & 3) case None => (x: Int) => x + col }, (x: Int) => x) - @tailrec def compute(cs: Array[Char], i: Int = 0, col: Int = 0, line: Int = 0)(implicit tabprefix: Option[Int] = None): Unit = - { + @tailrec def compute(cs: Array[Char], i: Int = 0, col: Int = 0, line: Int = 0)(implicit tabprefix: Option[Int] = None): Unit = { adjustAtIndex(i) = makeAdjusters(col, line, tabprefix) - if (i < cs.length) cs(i) match - { + if (i < cs.length) cs(i) match { case '\n' => compute(cs, i + 1, 1, line + 1)(Some(0)) case '\t' if tabprefix.isEmpty => compute(cs, i + 1, 0, line)(Some(col)) case '\t' => compute(cs, i + 1, col + 4 - ((col-1) & 3), line) @@ -139,21 +105,17 @@ private [internal] final class StringTokFastPerform(s: String, f: String => Any, } } compute(cs) - override def apply(ctx: Context): Unit = - { + override def apply(ctx: Context): Unit = { val strsz = this.sz val inputsz = ctx.inputsz val input = ctx.input var i = ctx.offset var j = 0 val cs = this.cs - if (inputsz != i) - { - while (j < strsz) - { + if (inputsz != i) { + while (j < strsz) { val c = cs(j) - if (i == inputsz || input(i) != c) - { + if (i == inputsz || input(i) != c) { ctx.offset = i val (colAdjust, lineAdjust) = adjustAtIndex(j) ctx.col = colAdjust(ctx.col) @@ -168,32 +130,25 @@ private [internal] final class StringTokFastPerform(s: String, f: String => Any, ctx.col = colAdjust(ctx.col) ctx.line = lineAdjust(ctx.line) ctx.offset = i - ctx.stack.push(fs) - ctx.inc() + ctx.pushAndContinue(fs) } else ctx.fail(expected) } override def toString: String = s"StrPerform($s, ?)" } -private [internal] final class SatisfyExchange[A](f: Char => Boolean, x: A, expected: UnsafeOption[String]) extends Instr -{ - override def apply(ctx: Context): Unit = - { - if (ctx.moreInput) - { +private [internal] final class SatisfyExchange[A](f: Char => Boolean, x: A, expected: UnsafeOption[String]) extends Instr { + override def apply(ctx: Context): Unit = { + if (ctx.moreInput) { val c = ctx.nextChar - if (f(ctx.nextChar)) - { - ctx.stack.push(x) + if (f(ctx.nextChar)) { ctx.offset += 1 - c match - { + c match { case '\n' => ctx.line += 1; ctx.col = 1 case '\t' => ctx.col += 4 - ((ctx.col - 1) & 3) case _ => ctx.col += 1 } - ctx.inc() + ctx.pushAndContinue(x) } else ctx.fail(expected) } @@ -202,24 +157,15 @@ private [internal] final class SatisfyExchange[A](f: Char => Boolean, x: A, expe override def toString: String = s"SatEx(?, $x)" } -private [internal] final class JumpGoodAttempt(var label: Int) extends JumpInstr -{ - override def apply(ctx: Context): Unit = - { - if (ctx.status eq Good) - { +private [internal] final class JumpGoodAttempt(var label: Int) extends JumpInstr { + override def apply(ctx: Context): Unit = { + if (ctx.status eq Good) { ctx.states = ctx.states.tail ctx.handlers = ctx.handlers.tail ctx.pc = label } - else - { - val state = ctx.states.head - ctx.states = ctx.states.tail - ctx.offset = state.offset - ctx.line = state.line - ctx.col = state.col - ctx.regs = state.regs + else { + ctx.restoreState() ctx.status = Good ctx.inc() } @@ -227,79 +173,58 @@ private [internal] final class JumpGoodAttempt(var label: Int) extends JumpInstr override def toString: String = s"JumpGood'($label)" } -private [internal] final class RecoverWith[A](x: A) extends Instr -{ - override def apply(ctx: Context): Unit = - { +private [internal] final class RecoverWith[A](x: A) extends Instr { + override def apply(ctx: Context): Unit = { if (ctx.offset != ctx.checkStack.head) ctx.fail() - else - { + else { ctx.status = Good - ctx.stack.push(x) - ctx.inc() + ctx.pushAndContinue(x) } ctx.checkStack = ctx.checkStack.tail } override def toString: String = s"Recover($x)" } -private [internal] final class AlwaysRecoverWith[A](x: A) extends Instr -{ - override def apply(ctx: Context): Unit = - { - if (ctx.status eq Good) - { +private [internal] final class AlwaysRecoverWith[A](x: A) extends Instr { + override def apply(ctx: Context): Unit = { + if (ctx.status eq Good) { ctx.states = ctx.states.tail ctx.handlers = ctx.handlers.tail ctx.inc() } - else - { - val state = ctx.states.head - ctx.states = ctx.states.tail - ctx.offset = state.offset - ctx.line = state.line - ctx.col = state.col - ctx.regs = state.regs + else { + ctx.restoreState() ctx.status = Good - ctx.stack.push(x) - ctx.inc() + ctx.pushAndContinue(x) } } override def toString: String = s"AlwaysRecover($x)" } private [internal] final class JumpTable(prefixes: List[Char], labels: List[Int], private [this] var default: Int, _expecteds: List[UnsafeOption[String]]) - extends Instr -{ + extends Instr { private [this] var defaultPreamble: Int = _ private [this] val jumpTable = mutable.LongMap(prefixes.map(_.toLong).zip(labels): _*) val expecteds = prefixes.zip(_expecteds).map{case (c, expected) => if (expected == null) "\"" + c + "\"" else expected} - override def apply(ctx: Context): Unit = - { - if (ctx.moreInput) - { + override def apply(ctx: Context): Unit = { + if (ctx.moreInput) { val dest = jumpTable.getOrElse(ctx.nextChar, default) ctx.pc = dest if (dest == default) addErrors(ctx) - else - { - ctx.checkStack = push(ctx.checkStack, ctx.offset) - ctx.handlers = push(ctx.handlers, new Handler(ctx.depth, defaultPreamble, ctx.stack.usize)) + else { + ctx.pushCheck() + ctx.pushHandler(defaultPreamble) } } - else - { + else { addErrors(ctx) ctx.pc = default } } - private def addErrors(ctx: Context): Unit = - { - if (ctx.offset > ctx.erroffset) - { + private def addErrors(ctx: Context): Unit = { + if (ctx.offset > ctx.erroffset) { ctx.erroffset = ctx.offset ctx.errcol = ctx.col ctx.errline = ctx.line @@ -308,15 +233,13 @@ private [internal] final class JumpTable(prefixes: List[Char], labels: List[Int] ctx.raw = Nil ctx.unexpectAnyway = false } - else if (ctx.offset == ctx.erroffset) - { + else if (ctx.offset == ctx.erroffset) { if (ctx.errorOverride == null) ctx.expected = ctx.expected reverse_::: expecteds else ctx.expected ::= ctx.errorOverride } } - private [internal] def relabel(labels: Array[Int]): Unit = - { + private [internal] def relabel(labels: Array[Int]): Unit = { jumpTable.mapValuesInPlace((_, v) => labels(v)) default = labels(default) defaultPreamble = default - 1 @@ -324,17 +247,14 @@ private [internal] final class JumpTable(prefixes: List[Char], labels: List[Int] override def toString: String = s"JumpTable(${jumpTable.map{case (k, v) => k.toChar -> v}.mkString(", ")}, _ -> $default)" } -private [internal] object CharTokFastPerform -{ - def apply[A >: Char, B](c: Char, f: A => B, expected: UnsafeOption[String]): CharTokFastPerform = c match - { +private [internal] object CharTokFastPerform { + def apply[A >: Char, B](c: Char, f: A => B, expected: UnsafeOption[String]): CharTokFastPerform = c match { case '\n' => new NewlineFastPerform(f, expected) case '\t' => new TabFastPerform(f, expected) case _ => new CharTokFastPerform(c, f, expected) } } -private [internal] object Exchange -{ +private [internal] object Exchange { def unapply[A](ex: Exchange[A]): Option[A] = Some(ex.x) } diff --git a/src/main/scala/parsley/internal/instructions/TokenInstrs.scala b/src/main/scala/parsley/internal/instructions/TokenInstrs.scala index 57385791d..0c6270d07 100644 --- a/src/main/scala/parsley/internal/instructions/TokenInstrs.scala +++ b/src/main/scala/parsley/internal/instructions/TokenInstrs.scala @@ -36,8 +36,7 @@ private [internal] class TokenSkipComments(start: String, end: String, line: Str startsMulti = ctx.input.startsWith(start, ctx.offset) } } - ctx.stack.push(()) - ctx.inc() + ctx.pushAndContinue(()) } protected final def singleLineComment(ctx: Context): Unit = @@ -110,8 +109,7 @@ private [internal] final class TokenComment(start: String, end: String, line: St else { if (!multiLineComment(ctx)) return - ctx.stack.push(()) - ctx.inc() + ctx.pushAndContinue(()) } } else if (noMulti) @@ -120,8 +118,7 @@ private [internal] final class TokenComment(start: String, end: String, line: St else { singleLineComment(ctx) - ctx.stack.push(()) - ctx.inc() + ctx.pushAndContinue(()) } } else @@ -136,8 +133,7 @@ private [internal] final class TokenComment(start: String, end: String, line: St if (!multiLineComment(ctx)) return } else singleLineComment(ctx) - ctx.stack.push(()) - ctx.inc() + ctx.pushAndContinue(()) } } } @@ -235,8 +231,7 @@ private [internal] final class TokenWhiteSpace(ws: TokenSet, start: String, end: startsMulti = ctx.input.startsWith(start, ctx.offset) } } - ctx.inc() - ctx.stack.push(()) + ctx.pushAndContinue(()) } private def spaces(ctx: Context): Unit = @@ -276,13 +271,13 @@ private [internal] final class TokenSign(ty: SignType, _expected: UnsafeOption[S ctx.col += 1 ctx.stack.push(neg) } - else if (ctx.nextChar == '+') - { - ctx.offset += 1 - ctx.col += 1 + else { + if (ctx.nextChar == '+') { + ctx.offset += 1 + ctx.col += 1 + } ctx.stack.push(pos) } - else ctx.stack.push(pos) } ctx.inc() } @@ -300,11 +295,7 @@ private [internal] final class TokenNatural(_expected: UnsafeOption[String]) ext case '0' => ctx.offset += 1 ctx.col += 1 - if (!ctx.moreInput) - { - ctx.stack.push(0) - ctx.inc() - } + if (!ctx.moreInput) ctx.pushAndContinue(0) else { (ctx.nextChar: @switch) match @@ -321,8 +312,7 @@ private [internal] final class TokenNatural(_expected: UnsafeOption[String]) ext | 'A' | 'B' | 'C' | 'D' | 'E' | 'F') => ctx.offset += 1 ctx.col += 1 - ctx.stack.push(hexadecimal(ctx, d.asDigit)) - ctx.inc() + ctx.pushAndContinue(hexadecimal(ctx, d.asDigit)) case _ => ctx.fail(expected) } } @@ -337,8 +327,7 @@ private [internal] final class TokenNatural(_expected: UnsafeOption[String]) ext { ctx.offset += 1 ctx.col += 1 - ctx.stack.push(octal(ctx, d.asDigit)) - ctx.inc() + ctx.pushAndContinue(octal(ctx, d.asDigit)) } else ctx.fail(expected) } @@ -346,18 +335,14 @@ private [internal] final class TokenNatural(_expected: UnsafeOption[String]) ext case d@('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9') => ctx.offset += 1 ctx.col += 1 - ctx.stack.push(decimal(ctx, d.asDigit)) - ctx.inc() - case _ => - ctx.stack.push(0) - ctx.inc() + ctx.pushAndContinue(decimal(ctx, d.asDigit)) + case _ => ctx.pushAndContinue(0) } } case d@('1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9') => ctx.offset += 1 ctx.col += 1 - ctx.stack.push(decimal(ctx, d.asDigit)) - ctx.inc() + ctx.pushAndContinue(decimal(ctx, d.asDigit)) case _ => ctx.fail(expected) } else ctx.fail(expected) @@ -509,11 +494,7 @@ private [internal] class TokenEscape(_expected: UnsafeOption[String]) extends In override def apply(ctx: Context): Unit = { badCode = false - if (escape(ctx)) - { - ctx.stack.push(escapeChar) - ctx.inc() - } + if (escape(ctx)) ctx.pushAndContinue(escapeChar) else { ctx.fail(expected) @@ -887,8 +868,7 @@ private [internal] final class TokenString(ws: TokenSet, _expected: UnsafeOption case '"' => ctx.offset += 1 ctx.col += 1 - ctx.stack.push(builder.toString) - ctx.inc() + ctx.pushAndContinue(builder.toString) case '\\' => ctx.offset += 1 ctx.col += 1 @@ -971,8 +951,7 @@ private [internal] final class TokenRawString(_expected: UnsafeOption[String]) e case '"' => ctx.offset += 1 ctx.col += 1 - ctx.stack.push(builder.toString) - ctx.inc() + ctx.pushAndContinue(builder.toString) case '\\' => ctx.offset += 1 ctx.col += 1 @@ -1037,8 +1016,7 @@ private [internal] final class TokenIdentifier(start: TokenSet, letter: TokenSet else { ctx.col += nameStr.length - ctx.stack.push(nameStr) - ctx.inc() + ctx.pushAndContinue(nameStr) } } } @@ -1083,8 +1061,7 @@ private [internal] final class TokenUserOperator(start: TokenSet, letter: TokenS else { ctx.col += nameStr.length - ctx.stack.push(nameStr) - ctx.inc() + ctx.pushAndContinue(nameStr) } } } @@ -1129,8 +1106,7 @@ private [internal] final class TokenOperator(start: TokenSet, letter: TokenSet, else { ctx.col += nameStr.length - ctx.stack.push(nameStr) - ctx.inc() + ctx.pushAndContinue(nameStr) } } } @@ -1168,11 +1144,7 @@ private [internal] class TokenKeyword(_keyword: String, letter: TokenSet, caseSe ctx.col += strsz ctx.offset = i if (i < inputsz && letter(input(i))) ctx.fail(expectedEnd) - else - { - ctx.stack.push(()) - ctx.inc() - } + else ctx.pushAndContinue(()) } else ctx.fail(expected) } @@ -1209,11 +1181,7 @@ private [internal] class TokenOperator_(_operator: String, letter: TokenSet, _ex ctx.col += strsz ctx.offset = i if (i < inputsz && letter(input(i))) ctx.fail(expectedEnd) - else - { - ctx.stack.push(()) - ctx.inc() - } + else ctx.pushAndContinue(()) } else ctx.fail(expected) } @@ -1270,8 +1238,7 @@ private [internal] class TokenMaxOp(_operator: String, _ops: Set[String], _expec } ctx.col = ctx.col + strsz ctx.offset = j - ctx.stack.push(()) - ctx.inc() + ctx.pushAndContinue(()) } else ctx.fail(expected) }