Skip to content

Commit

Permalink
Merge pull request #20 from j-mie6/refactor
Browse files Browse the repository at this point in the history
Factored out similar operations within the instructions
  • Loading branch information
j-mie6 authored Dec 30, 2020
2 parents 4f65d95 + 7d91fb7 commit 30eded5
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 683 deletions.
105 changes: 71 additions & 34 deletions src/main/scala/parsley/internal/instructions/Context.scala
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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) {
Expand All @@ -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
}
Expand All @@ -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 = {
Expand All @@ -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 = {
Expand Down Expand Up @@ -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)
}
}
Loading

0 comments on commit 30eded5

Please sign in to comment.