Linea:   line oriented reader
1 Stability
2 Linea Guide
2.1 Line Macros
3 Linea Reference
3.1 linea/  defaults
#%linea-expressions-begin
#%linea-line
#%linea-s-exp
#%linea-default-line-macro
3.2 linea/  line-macro
define-line-macro
default-line-macro
with-default-line-macro
splicing-with-default-line-macro
3.3 linea/  line-macro-prop
line-macro
prop:  line-macro
line-macro?
3.4 #lang linea
3.5 linea/  read
4 Code and License
7.1

Linea: line oriented reader

William Hatch <[email protected]>

Linea is a line-oriented reader and one of the main components of the Rash language. While it was designed for Rash, it is flexible and suited to many potential line-oriented languages. Linea is simply another way to write s-expressions.

Note that you can’t represent any arbitrary s-expression with Linea, but you can represent a very useful subset of them.

1 Stability

Not yet stable. Things may still change a bit.

2 Linea Guide

TODO

Explanation of inner/outer reading, readtable modifications, #%symbol defaults.

TL;DR

This module:

#lang linea "my-lang-bindings.rkt"

 

finwe feanor fingolfin finarfin

 

beren (and) \

  luthien tinuviel

 

(huan (vs) werewolf-sauron)

 

manwe orome {

  varda yavanna

  aule (mandos

        nienna #{ulmo tulkas})

  melkor

}

reads as:

(module <some-file-name> "my-lang-bindings.rkt"

  (#%module-begin

    (#%linea-line finwe feanor fingolfin finarfin)

    (#%linea-line beren (and) luthien tinuviel)

    (#%linea-s-exp (huan (vs) werewold-sauron))

    (#%linea-line

     manwe

     orome

     (#%linea-expressions-begin

      (#%linea-line varda yavanna)

      (#%linea-line aule (mandos

                          nienna

                          (#%hash-braces

                           (#%linea-expressions-begin

                            (#%linea-line ulmo tulkas)))))

      (#%linea-line melkor)))))

2.1 Line Macros

Line macros are designed to give lines of code flexible meaning. They are similar to Racket’s treatment of S-expressions with macros and #%app.

Just like the macro expander will check whether the first element of a form is bound as a macro, #%linea-line checks if the first element of a line is a line macro. Just like the macro expander inserts #%app if there is not an explicit macro use, #%linea-line inserts #%linea-default-line-macro.

One major difference is that line macros are specially marked with prop:line-macro, because the macros that you want to override S-expression meaning and line meaning are not necessarily the same. The define-line-macro form defines line macros that also work as a normal macro (and execute the same syntax transformer), but that is not required.

3 Linea Reference

3.1 linea/defaults

TODO: #%hash-braces – currently #%hash-braces are not defined by default, but they are defined if you (require rash/demo/setup)...

Simply a rename-transformer for begin.

syntax

(#%linea-line starter e ...)

If starter is a line-macro, then it acts as #’(starter e ...). If starter is not a line-macro, then the current default (as set by with-default-line-macro) is inserted in place of #%linea-line.

syntax

(#%linea-s-exp e)

This is just a pass-through – (#%linea-s-exp foo) simply turns into foo.
NOT STABLE

The identifier #%linea-default-line-macro is the default that is inserted when no explicit line macro is used. But by default it just raises an error. This is configured with with-default-line-macro.

Don’t count on the name being the same at any future time. Don’t set it yourself. Use with-default-line-macro.

3.2 linea/line-macro

syntax

(define-line-macro name transformer)

Defines name to be a line-macro with transformer as its syntax transformer. Note that identifiers defined by define-line-macro can be used both as line-macros and normal macros and behave the same either way.

;; in a language like Rash that uses the Linea reader...
(require (for-syntax racket/base syntax/parse))
(define-line-macro basic-app
  (syntax-parser [(_ e ...) #'(#%app e ...)]))
 
basic-app println "hello world"
 
(define-line-macro my-for
  (syntax-parser
    [(_ i:id (~datum in) from:id ... (~datum do) body:expr)
     #'(for ([i (list 'from ...)])
          body)]))
 
my-for f in file1.txt file2.txt do {
  basic-app println f
}

syntax

default-line-macro

Syntax parameter used to determine which line macro to place when one is not explicitly given.

Use with-default-line-macro to set it for a region of code.

line-macro

(with-default-line-macro new-default-line-macro body ...)

Executes the bodies with new-default-line-macro as the default line-macro.

(with-default-line-macro basic-app {
  displayln "Oh hi"
  displayln "what's up?"
})
 
;; or
with-default-line-macro basic-app {
  displayln "Oh hi"
  displayln "what's up?"
}

line-macro

(splicing-with-default-line-macro new-default-line-macro body ...)

Like with-default-line-macro, only the bodies are spliced into the surrounding context as with splicing-let-syntax.

3.3 linea/line-macro-prop

syntax class

line-macro

Syntax class for matching line macros. These are matched by #%linea-line to determine whether to insert a default line interpretation.

You can define your own structs that are line macros and maybe other things too with prop:line-macro. If you make a struct with this property and it is the syntax-local-value of an identifier, then it will match the line-macro syntax class.

The property should hold a procedure that takes a struct instance as its first argument and a syntax object as its second argument.

(struct my-line-macro-struct
  (transformer)
  #:property prop:line-macro (λ (inst . args)
                               (apply
                                (my-line-macro-struct-transformer inst)
                                args)))

procedure

(line-macro? x)  any/c

  x : any/c
Detects if x is a struct with prop:line-macro. You probably don’t want to use this directly, use the line-macro syntax class.

3.4 #lang linea

 #lang linea package: linea

Similar to

You can use
to read a module with custom language bindings using the linea notation. Here is an example:

mylang.rkt:
#lang racket/base
(require linea/defaults linea/line-macro
         (for-syntax racket/base syntax/parse))
 
(define-line-macro print-quoted-list
  (syntax-parser
    [(_ e ...) #'(println '(e ...))]))
 
(provide (all-from-out linea/defaults
                       linea/line-macro
                       racket/base)
         print-quoted-list)

use-mylang.rkt
#lang linea "mylang.rkt"
 
;; prints '(a b c)
print-quoted-list a b c
with-default-line-macro print-quoted-list {
  ;; prints '(hello world)
  hello world
}

Be sure that the module you name at the top-level provides a binding for #%linea-line, #%linea-s-exp, and #%linea-expressions-begin, in addition to other #% identifiers that a module needs (eg. #%module-begin, #%app, ...).

3.5 linea/read

TODO:

linea-read-syntax

linea-read

make-linea-read-funcs

readtable-add-linea-escape

default-linea-s-exp-readtable

default-linea-line-readtable

default-linea-line-avoid-list

current-linea-s-exp-readtable

current-linea-line-readtable

current-linea-line-avoid-list

4 Code and License

The code is available on github.

This library is licensed under the terms of the LGPL version 3, or (at your option) any later version published by the Free Software Foundation (IE LGPL3+).