2014-12-16 15 views
5

Tôi cần thực hiện kiểm tra cú pháp phức tạp hơn đối với kết hợp trình phân tích cú pháp so với giấy phép ký hiệu chuẩn và hiện đang làm trong ứng dụng chức năng ^^. Một ví dụ, kịch bản đơn giản là kiểm tra cho các từ khóa trùng lặp:Lỗi báo hiệu qua bộ phối hợp trình phân tích cú pháp ứng dụng chức năng

def keywords: Parser[List[String]] = "[" ~ repsep(keyword, ",") ~ "]" ^^ { 
    case _ ~ ks ~ _ => 
    ks.groupBy(x => x).filter(_._2.length > 1).keys.toList match { 
     case Nil => ks 
     case x => throw new DuplicateKeywordsException(x) 
    } 
} 

này hoạt động, như trong phân tích cú pháp của tôi sẽ ném một ngoại lệ, nhưng tôi muốn sự thất bại để được chụp như một ParseResult.Failure chụp Input về nơi nó đã xảy ra . Tôi không thể tìm ra cách để báo hiệu điều này từ bên trong một khối ^^ hoặc sử dụng một số cấu trúc khác để đạt được cùng một kết thúc.

Trả lời

3

Ok, tôi đã làm theo lời khuyên của Erik Meijer về số sau các Loại xuống đường dẫn hạnh phúc. Nhìn vào cách ^^ được định nghĩa trong Lập trình trong Scala (mà khác với mã thực tế), tôi nhận ra đó là về cơ bản chỉ là một chức năng Map:

def ˆˆ [U](f: T => U): Parser[U] = new Parser[U] { 
    def apply(in: Input) = p(in) match { 
    case Success(x, in1) => Success(f(x), in1) 
    case failure => failure 
    } 
} 

Về cơ bản nó là Parser[T] => Parser[U].

Parser[T] chính nó là một chức năng của Input => ParseResult[T]^^ chỉ định nghĩa một phân tích cú pháp mới bằng cách cung cấp các phương pháp apply, mà trên gọi một trong hai biến Success[T]-Success[U] hoặc chỉ đi cùng Failure.

Để đạt được mục tiêu tiêm mới Failure trong khi ánh xạ, tôi cần một hàm ánh xạ mới có chức năng như f: T => Either[String,U] để tôi có thể báo hiệu thông báo lỗi hoặc ánh xạ thành công. Tôi đã chọn Hoặc bằng chuỗi, vì Thất bại chỉ nhận một tin nhắn chuỗi. chức năng lập bản đồ mới này sau đó được bổ sung vào Parser[U] qua một lớp ẩn:

implicit class RichParser[+T](p: Parser[T]) { 
    def ^^? [U](f: T => Either[String,U]): Parser[U] = new Parser[U] { 
    def apply(in: Input) = p(in) match { 
     case Success(x, in1) => f(x) match { 
     case Left(error) => Failure(error,in1) 
     case Right(x1) => Success(x1,in1) 
     } 
     case failure:Failure => failure 
     case error:Error => error 
    } 
    } 
} 

Và bây giờ keywords có thể được định nghĩa là:

def keywords: Parser[List[String]] = "[" ~ repsep(keyword, ",") ~ "]" ^^? { 
    case _ ~ ks ~ _ => 
    ks.groupBy(x => x).filter(_._2.length > 1).keys.toList match { 
     case Nil => Right(ks) 
     case x => Left("found duplicate keywords: "+x.reduce[String] { case (a, b) => s"$a, $b"}) 
    } 
} 
+0

Brilliant. Nếu đây không phải là một phần của thư viện chính (tôi không thể tìm thấy nó) nó nên được. – Jxek

Các vấn đề liên quan