Linea:   line oriented reader
1 Stability
2 Linea Guide
2.1 Line Macros
3 Linea Reference
3.1 linea/  defaults
3.2 linea/  line-macro
3.3 linea/  line-macro-prop
prop:  line-macro
3.4 #lang linea
3.5 linea/  read
4 Code and License

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


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


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})



reads as:

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


    (#%linea-line finwe feanor fingolfin finarfin)

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

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





      (#%linea-line varda yavanna)

      (#%linea-line aule (mandos




                            (#%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.


(#%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.


(#%linea-s-exp e)

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

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


(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
    [(_ i:id (~datum in) from:id ... (~datum do) body:expr)
     #'(for ([i (list 'from ...)])
my-for f in file1.txt file2.txt do {
  basic-app println f



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.


(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?"


(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


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
  #:property prop:line-macro (λ (inst . args)
                                (my-line-macro-struct-transformer inst)


(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:

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

#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












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+).