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
8.12

Linea: line oriented reader🔗ℹ

William Hatch <william@hatch.uno>

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🔗ℹ

Everything documented here is stable unless it says otherwise.

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

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 MIT license and the Apache version 2.0 license, at your option.