~subsetpark/the-brzozowski-variations

d7abf92189acb8da90c2f53f4065c491227ca400 — Zach Smith 7 months ago
Initial commit
4 files changed, 100 insertions(+), 0 deletions(-)

A README.md
A impls/fugue/brzo.janet
A impls/fugue/project.janet
A impls/fugue/test/brzo.janet
A  => README.md +12 -0
@@ 1,12 @@
# The Brzozowski Variations

A series of implementations of the regex model described in the paper
[Parsing with Derivatives][parsing] in various languages or frameworks.

[parsing]: http://matt.might.net/papers/might2011derivatives.pdf

## Index

### fugue

An implementation using the *fugue* object system for Janet. 

A  => impls/fugue/brzo.janet +58 -0
@@ 1,58 @@
(setdyn :doc "Regexing with Derivatives.")
(use fugue)

(defproto Language ())

(defproto Empty Language)
(defproto Epsilon Language)
(defproto Char Language value {:init? true})
(defproto Union Language left {:init? true} right {:init? true})
(defproto Cat Language left {:init? true} right {:init? true})
(defproto Star Language value {:init? true})

(defgeneric nullable? [_] false)
(defmethod nullable? Epsilon [_] true)

(defmethod nullable? Union
  [{:left left :right right}]
  (or (nullable? left) (nullable? right)))

(defmethod nullable? Cat
  [{:left left :right right}]
  (and (nullable? left) (nullable? right)))

(defmethod nullable? Star [_] true)

(defgeneric derive [symbol letter] (:new Empty))

(defmethod derive Char
  [{:value val} letter]
  (case val
    letter (:new Epsilon)
    (:new Empty)))

(defmethod derive Union
  [{:left left :right right} letter]
  (:new Union (derive left letter) (derive right letter)))

(defmethod derive Star
  [star letter]
  (:new Cat (derive (star :value) letter) star))

(defmethod derive Cat
  [{:left left :right right} letter]
  (let [base (:new Cat (derive left letter) right)]
    (if (nullable? left)
      (:new Union (derive right letter) base)
      base)))

(defmethod matches? Language
  [self string]
  ((fn inner
     [sym bytes]
     (cond
       (empty? bytes) (nullable? sym)
       true (let [hd (first bytes)
                  rest (array/slice bytes 1)
                  d (derive sym hd)]
              (inner d rest)))) self (string/bytes string)))

A  => impls/fugue/project.janet +9 -0
@@ 1,9 @@
(declare-project
  :name "brzozowski-fugue"
  :author "Z. D. Smith <zd@zdsmith.com>"
  :license "BSD3"
  :dependencies ["https://github.com/pyrmont/testament"
                 "fugue"])

(declare-source
  :source ["fugue.janet"])

A  => impls/fugue/test/brzo.janet +21 -0
@@ 1,21 @@
(use testament)
(import /brzo :as b)

(deftest regexes
  (let [regex (:new b/Star (:new b/Cat
                                 (:new b/Union
                                       (:new b/Char (chr "k"))
                                       (:new b/Char (chr "j")))
                                 (:new b/Union
                                       (:new b/Char (chr "h"))
                                       (:new b/Char (chr "l")))))]
    (is (b/matches? regex ""))
    (is (b/matches? regex "kh"))
    (is (b/matches? regex "jl"))
    (is (b/matches? regex "kljhkhkhjh"))

    (is (not (b/matches? regex "k")))
    (is (not (b/matches? regex "j")))
    (is (not (b/matches? regex "khk")))))

(run-tests!)