Skip to content

Commit 753ec3d

Browse files
committed
implement !
1 parent 0e7482a commit 753ec3d

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

parboiled-core/src/main/scala-3/org/parboiled2/ParserMacros.scala

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,47 @@ class OpTreeContext(parser: Expr[Parser])(using Quotes) {
358358
}
359359
}
360360

361+
case class NotPredicate(op: OpTree) extends OpTree {
362+
363+
def render(wrapped: Boolean): Expr[Boolean] = {
364+
def unwrappedExpr(setMatchEnd: Option[Expr[Int] => Expr[Unit]]): Expr[Boolean] = '{
365+
val mark = $parser.__saveState
366+
val saved = $parser.__enterNotPredicate()
367+
val matched = ${ op.render(wrapped) }
368+
$parser.__exitNotPredicate(saved)
369+
${
370+
setMatchEnd match {
371+
case Some(matchEndSetter) => matchEndSetter('{ $parser.cursor })
372+
case None => '{}
373+
}
374+
}
375+
$parser.__restoreState(mark)
376+
!matched
377+
}
378+
379+
if (wrapped) {
380+
val base = op match {
381+
case x: TerminalOpTree => '{ RuleTrace.NotPredicate.Terminal(${ x.ruleTraceTerminal }) }
382+
case x: RuleCall => '{ RuleTrace.NotPredicate.RuleCall(${ x.calleeNameTree }) }
383+
case x: StringMatch => '{ RuleTrace.NotPredicate.Named(s"\"${${ x.stringTree }}\"") }
384+
case x: IgnoreCaseString => '{ RuleTrace.NotPredicate.Named(s"\"${${ x.stringTree }}\"") }
385+
//case x: Named => '{RuleTrace.NotPredicate.Named(s"\"${${x.stringTree}}\"")}
386+
case _ => '{ RuleTrace.NotPredicate.Anonymous }
387+
}
388+
'{
389+
var matchEnd = 0
390+
try ${ unwrappedExpr(Some(v => '{ matchEnd = $v })) } || $parser.__registerMismatch()
391+
catch {
392+
case Parser.StartTracingException =>
393+
$parser.__bubbleUp {
394+
RuleTrace.NotPredicate($base, matchEnd - $parser.cursor)
395+
}
396+
}
397+
}
398+
} else unwrappedExpr(None)
399+
}
400+
}
401+
361402
private case class Action(body: Term, ts: List[TypeTree]) extends DefaultNonTerminalOpTree {
362403
def ruleTraceNonTerminalKey = '{ RuleTrace.Action }
363404

@@ -762,6 +803,7 @@ class OpTreeContext(parser: Expr[Parser])(using Quotes) {
762803
Sequence(rec(base), Action(body, ts))
763804

764805
case Apply(Select(_, "&"), List(arg)) => AndPredicate(rec(arg))
806+
case Select(arg, "unary_!") => NotPredicate(rec(arg))
765807

766808
case Apply(
767809
Select(Apply(TypeApply(Select(_, "rule2WithSeparatedBy"), _), List(base)), "separatedBy"),

parboiled-core/src/test/scala/org/parboiled2/CombinatorSpec.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,12 @@ object CombinatorSpec extends TestParserSpec {
162162
"axx" must beMismatched
163163
}
164164

165-
/*"`!(Rule0)` modifier" - new TestParser0 {
165+
"`!(Rule0)` modifier" - new TestParser0 {
166166
def targetRule = rule(!"a")
167167
"a" must beMismatched
168168
"b" must beMatched
169169
"" must beMatched
170-
}*/
170+
}
171171

172172
"`&` modifier" - new TestParser0 {
173173
def targetRule = rule(&("a"))

0 commit comments

Comments
 (0)