summaryrefslogtreecommitdiff
path: root/sources/examples/parsers.scala
blob: 43a386e8dbbd218da409e921c9ceb0074b9abe94 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package examples;

module Parse {

  type Result = Option[List[Char]];

  trait Parser extends Function1[List[Char],Result] with {
    def &&& (def p: Parser) = new Parser {
      def apply(in: List[Char]) = Parser.this.apply(in) match {
        case Some(in1) => p(in1)
        case n => n
      }
    }

    def ||| (def p: Parser) = new Parser {
      def apply(in: List[Char]) = Parser.this.apply(in) match {
        case None() => p(in)
        case s => s
      }
    }
  }

  val empty = new Parser { def apply(in: List[Char]): Result = Some(in) }

  def fail = new Parser { def apply(in: List[Char]): Result = None() }

  def chrWith(p: Char => Boolean) = new Parser {
    def apply(in: List[Char]): Result = in match {
      case List() => None()
      case (c :: in1) => if (p(c)) Some(in1) else None()
    }
  }

  def chr(c: Char): Parser = chrWith(d => d == c);

  def opt(p: Parser): Parser = p ||| empty;
  def rep(p: Parser): Parser = opt(rep1(p));
  def rep1(p: Parser): Parser = p &&& rep(p);
}

module ExprParser {
  import Parse._;

  def letter    =   chrWith(c => c.isLetter);
  def digit     =   chrWith(c => c.isDigit);

  def ident     =   letter &&& rep(letter ||| digit);
  def number    =   digit &&& rep(digit);

  def expr:Parser =  expr1 &&& rep((chr('+') &&& expr1) ||| (chr('-') &&& expr1));
  def expr1     =  expr2 &&& rep((chr('*') &&& expr2) ||| (chr('/') &&& expr2));
  def expr2     =  ident ||| number ||| (chr('(') &&& expr &&& chr(')'));
}