Skip to content
Raphaël Pinson edited this page Jan 21, 2014 · 4 revisions

Square lenses let you manage symmetric patterns in files, such as XML/SGML syntax, or quoting string (double vs simple).

Square lenses are built using the square operator with three parameters:

square LEFT BODY RIGHT

where LEFT and RIGHT must assume the same language and match the same string.

Tag-based square lenses

As a simple example, let's pretend we need to match an XML-like string such as the following:

<a>text</a>

where the opening and closing tags must match.

This is done using a key RE for the LEFT lens. We could write a square lens such as:

let xml = [ Util.del_str "<"                (* start of opening tag                          *)
          . square (key Rx.word)            (* LEFT side of square lens matches tag name     *)
                   (Util.del_str ">"        (* BODY:  end of opening tag                     *)
                    . store Rx.word         (*        get text value                         *)
                    . Util.del_str "</")    (*        start of closing tag                   *)
                   (del Rx.word "DEFAULT")  (* RIGHT side of square lens matches closing tag *)
          . Util.del_str ">" . Util.eol ]   (* end closing tag and add newline               *)

(* Sample tree produced by this lens *)
test xml get "<ab>text</ab>\n" = { "ab" = "text" }

Note that the "DEFAULT" string provided for the RIGHT lens does not matter, as it will never be used.

The XML and Httpd modules contain more complete examples of such lenses.

Symmetric deletion square lenses

Another type of usage for square lenses is symmetric deletion, such as quotes. Let's say we want to parse a quoted string and use the quoted value as a key. Both single and double quotes are accepted for our string, so we need to make sure that the quotes match (and possibly allow for single quotes inside a double quoted string, and vice versa). A square lens can be used for that, with the LEFT lens using a del RE STR pattern:

let quote =
     let quote_lns = del /["']/ "\""  (* Delete single or double quote  *)
  in [ square quote_lns               (* LEFT: a single or double quote *)
              (key Rx.word)           (* BODY: a word used as a key     *)
              quote_lns ]             (* RIGHT: a matching quote        *)
    
(* Sample trees produced by this lens *)
test quote get "'abc'" = { "abc" }
test quote get "\"abc\"" = { "abc" }

The Quote module provides useful wrapping definitions for quoting values in lenses.