Lexical syntax

spork-lang 0.6.0

Understand whitespace, comments, delimiters, atomic literals, symbols, and identifier normalization.

Spork source is a sequence of forms. The tokenizer separates atoms and delimiters, and the reader turns them into lists, collection literals, symbols, keywords, and scalar values. Prefix forms that change how the reader interprets the next form are documented together in reader macros.

Whitespace and comments#

Spaces, tabs, carriage returns, and newlines separate forms. Newlines do not terminate statements; balanced delimiters determine where a form ends. Unlike in some Lisps, a comma is not whitespace and should not separate forms.

A semicolon begins a line comment outside a string. The reader ignores everything from that semicolon through the end of the line. One and two semicolons behave identically; ;; is only a source-style convention for longer comments.

; One complete form may span lines
(def total
  (+ 10
     20))

;; A comment may follow a form
total ; => 30

Delimiters and collection forms#

SyntaxReader resultTypical use
(form ...)list formCalls, special forms, and macro forms
[value ...]vector literalPersistent vectors, bindings, and parameter patterns
{key value ...}map literalPersistent maps; requires an even number of forms
#{value ...}set literalPersistent sets
"text"string atomPython string value

The meaning of a list depends on its first form and compilation context. Collection runtime behavior is covered under data structures; binding and call contexts are covered under forms and control flow and functions.

Mismatched or missing closing delimiters are syntax errors. Delimiters inside strings do not end the surrounding form.

Scalar literals#

; Decimal and hexadecimal integers
42
-17
0x2a
-0x2a

; Floating-point values contain a decimal point
3.14
-0.5
1.0e3

; Strings may contain escapes or span source lines
"hello"
"line 1\nline 2"
"tab:\tvalue"

; These map directly to Python values
true        ; Python True
false       ; Python False
nil         ; Python None

Ordinary strings recognize \n and \t; a backslash before another character includes that character without the backslash. A backslash immediately followed by a newline continues the string without including that newline. Regex literals have separate raw-pattern behavior documented under #r"...".

Keywords#

A nonempty atom beginning with : is a Keyword. Keywords evaluate to themselves, retain hyphens in their names, and can be called as map lookup functions.

:name
:my-key

(:name {:name "Alice"})                ; => "Alice"
(:missing {:a 1})                       ; => nil
(:missing {:a 1} "default")             ; => "default"

The lone token : is a symbol, not a keyword.

Symbols and identifier normalization#

Any atom that is not a scalar literal or keyword is read as a symbol. A quoted symbol retains its source spelling. When a symbol is compiled as a Python name, Spork normalizes Lisp punctuation for Python compatibility:

Spork symbolPython nameRule
my-variablemy_variableHyphens become underscores
valid?valid_qA trailing question mark becomes _q
swap!swap_bangA trailing exclamation mark becomes _bang
math.sinmath.sinDots remain attribute or namespace access
foo.bar.bazfoo.bar.bazDotted access may have several segments
+_plus_Operator symbols have dedicated normalized names

Punctuation inside a name is normalized as well. Because normalization is not one-to-one, source spellings such as my-variable and my_variable collide when used as names in the same scope.

Dotted-symbol call and import behavior is defined under namespaces and modules.

Reader prefixes#

Quote, quasiquote, unquote, decoration, anonymous-function, slice, discard, tagged-literal, and read-time-evaluation prefixes are all defined on the reader macro reference. Keeping those transformations on one page separates token and literal rules from syntax that constructs or rewrites forms.

#{...} is a persistent set literal rather than a reader-macro transformation. Likewise, *{...} is keyword-argument call syntax and is documented under keyword arguments.