Programming Language for Old Timers


by David A. Moon
February 2006 .. September 2008

Comments and criticisms to dave underscore moon atsign alum dot mit dot edu.


Previous page   Table of Contents   Next page


Data Syntax

The # macro introduces data syntax, which can be used to describe data. The expansion of the macro is an expression that constructs the data described. In the simplest case, it is simply a quotation of constant data. However, data syntax allows variables' values to be dropped into a template.

Data syntax is extensible. When the name (including punctuation) xxx appears, if a function parse-#xxx is defined, it is called to parse its own form of data syntax. The statement def#parser can be used to define these functions; it is identical to defparser except for the name of the parse function to which it adds a method. By convention xxx should only be punctuation or a funny-looking name, to avoid conflicts with #xxx as a quoted simple-name xxx. By convention, the syntax for a form of data object called xyz begins with #/xyz; this is implemented by defining a function named parse-#/xyz.

When a name-in-context is quoted in data syntax, and the context is not a module, it is translated to the simple-name with the same spelling.

Data syntax is defined as follows:

defmacro # ?:data => data

defparser data
  ;; Any name or string can be quoted with backslash
  \\ ?n is name => quotation(if context(n) is false or module then n
                             else simple-name(spelling(n)))
  \\ ?s is string => quotation(name(s))

  ;; Literal numbers and characters represent themselves,
  ;; while strings are string templates
  ?:literal => if literal is string
                 expand-string-template(literal)
               else literal

  ;; If parse-#x is defined as a function, call it
  ?x is data-macro-call => x

  ;; For convenience, ignore extra # inside data
  \# ?:data => data

  ;; Any name not defined that way is quoted
  ?n is name => quotation(if context(n) is false or module then n
                          else simple-name(spelling(n)))

;; This predefined data syntax parser allows ? variable to
;; substitute the value of a variable into the data being constructed
def#parser \? ?:variable => variable

;; This predefined data syntax parser allows a list or dictionary to
;; be expressed within parentheses
;; #(x y z ?true ?false) is a list
;; #(x => 1 y => 2 z => 3) is a dictionary
;; commas between the items are optional
def#parser ( { ?item is data [ \=> ?item2 is data ] [,] }* ) =>
  ;; Utility function to unwrap quotations
  def unwrap(x is quotation) x.data
  def unwrap(x is anything) x

  ;; If no arrows are present, it is a list
  if every?(\not, item2)
    ;; If all items are literals or quotations, quote the whole list
    if every?(_ is quotation or literal, item)
      quotation(list(map(unwrap, item)...))
    else
      ;; This is a list template, expand into invocation of list constructor
      invocation(#list@PLOT, item...)

  ;; If arrows are present, it is a dictionary
  else
    if member?(false, item2)
      error("Inconsistent use of arrows in (...) data syntax")
    ;; If all items are literals or quotations, quote the whole dictionary
    if every?(_ is quotation or literal, item) and
       every?(_ is quotation or literal, item2)
      quotation(dictionary((for key in item, value in item2
                                collect unwrap(key)
                                collect unwrap(value))...))
    else
      ;; This is a dictionary template, expand into invocation of dictionary constructor
      invocation(#dictionary@PLOT, (for key in item, value in item2
                                        collect key
                                        collect value)...)


Previous page   Table of Contents   Next page