summaryrefslogtreecommitdiff
path: root/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/scalap/scala/tools/scalap/scalax/rules/Rules.scala')
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Rules.scala144
1 files changed, 144 insertions, 0 deletions
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala b/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala
new file mode 100644
index 0000000000..fa6f959384
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala
@@ -0,0 +1,144 @@
+// -----------------------------------------------------------------------------
+//
+// Scalax - The Scala Community Library
+// Copyright (c) 2005-8 The Scalax Project. All rights reserved.
+//
+// The primary distribution site is http://scalax.scalaforge.org/
+//
+// This software is released under the terms of the Revised BSD License.
+// There is NO WARRANTY. See the file LICENSE for the full text.
+//
+// -----------------------------------------------------------------------------
+
+package scala.tools.scalap.scalax.rules
+
+trait Name {
+ def name : String
+ override def toString = name
+}
+
+/** A factory for rules.
+ *
+ * @author Andrew Foggin
+ *
+ * Inspired by the Scala parser combinator.
+ */
+trait Rules {
+ implicit def rule[In, Out, A, X](f : In => Result[Out, A, X]) : Rule[In, Out, A, X] = new DefaultRule(f)
+
+ implicit def inRule[In, Out, A, X](rule : Rule[In, Out, A, X]) : InRule[In, Out, A, X] = new InRule(rule)
+ implicit def seqRule[In, A, X](rule : Rule[In, In, A, X]) : SeqRule[In, A, X] = new SeqRule(rule)
+
+ def from[In] = new {
+ def apply[Out, A, X](f : In => Result[Out, A, X]) = rule(f)
+ }
+
+ def state[s] = new StateRules {
+ type S = s
+ val factory = Rules.this
+ }
+
+ def success[Out, A](out : Out, a : A) = rule { in : Any => Success(out, a) }
+
+ def failure = rule { in : Any => Failure }
+
+ def error[In] = rule { in : In => Error(in) }
+ def error[X](err : X) = rule { in : Any => Error(err) }
+
+ def oneOf[In, Out, A, X](rules : Rule[In, Out, A, X] *) : Rule[In, Out, A, X] = new Choice[In, Out, A, X] {
+ val factory = Rules.this
+ val choices = rules.toList
+ }
+
+ def ruleWithName[In, Out, A, X](_name : String, f : In => Result[Out, A, X]) : Rule[In, Out, A, X] with Name =
+ new DefaultRule(f) with Name {
+ val name = _name
+ }
+
+ class DefaultRule[In, Out, A, X](f : In => Result[Out, A, X]) extends Rule[In, Out, A, X] {
+ val factory = Rules.this
+ def apply(in : In) = f(in)
+ }
+
+ /** Converts a rule into a function that throws an Exception on failure. */
+ def expect[In, Out, A, Any](rule : Rule[In, Out, A, Any]) : In => A = (in) => rule(in) match {
+ case Success(_, a) => a
+ case Failure => throw new ScalaSigParserError("Unexpected failure")
+ case Error(x) => throw new ScalaSigParserError("Unexpected error: " + x)
+ }
+}
+
+/** A factory for rules that apply to a particular context.
+ *
+ * @requires S the context to which rules apply.
+ *
+ * @author Andrew Foggin
+ *
+ * Inspired by the Scala parser combinator.
+ */
+trait StateRules {
+ type S
+ type Rule[+A, +X] = rules.Rule[S, S, A, X]
+
+ val factory : Rules
+ import factory._
+
+ def apply[A, X](f : S => Result[S, A, X]) = rule(f)
+
+ def unit[A](a : => A) = apply { s => Success(s, a) }
+ def read[A](f : S => A) = apply { s => Success(s, f(s)) }
+
+ def get = apply { s => Success(s, s) }
+ def set(s : => S) = apply { oldS => Success(s, oldS) }
+
+ def update(f : S => S) = apply { s => Success(s, f(s)) }
+
+ def nil = unit(Nil)
+ def none = unit(None)
+
+ /** Create a rule that suceeds if f(in) is true. */
+ def cond(f : S => Boolean) = get filter f
+
+ /** Create a rule that succeeds if all of the given rules succeed.
+ @param rules the rules to apply in sequence.
+ */
+ def allOf[A, X](rules : Seq[Rule[A, X]]) = {
+ def rep(in : S, rules : List[Rule[A, X]], results : List[A]) : Result[S, List[A], X] = {
+ rules match {
+ case Nil => Success(in, results.reverse)
+ case rule::tl => rule(in) match {
+ case Failure => Failure
+ case Error(x) => Error(x)
+ case Success(out, v) => rep(out, tl, v::results)
+ }
+ }
+ }
+ in : S => rep(in, rules.toList, Nil)
+ }
+
+
+ /** Create a rule that succeeds with a list of all the provided rules that succeed.
+ @param rules the rules to apply in sequence.
+ */
+ def anyOf[A, X](rules : Seq[Rule[A, X]]) = allOf(rules.map(_ ?)) ^^ { opts => opts.flatMap(x => x) }
+
+ /** Repeatedly apply a rule from initial value until finished condition is met. */
+ def repeatUntil[T, X](rule : Rule[T => T, X])(finished : T => Boolean)(initial : T) = apply {
+ // more compact using HoF but written this way so it's tail-recursive
+ def rep(in : S, t : T) : Result[S, T, X] = {
+ if (finished(t)) Success(in, t)
+ else rule(in) match {
+ case Success(out, f) => rep(out, f(t))
+ case Failure => Failure
+ case Error(x) => Error(x)
+ }
+ }
+ in => rep(in, initial)
+ }
+
+
+}
+
+trait RulesWithState extends Rules with StateRules {
+ val factory = this
+}