Skip to content
(Lispex)2.0Specification · not released

Search documentation

Searches the English specification

Enter a question, symbol, diagnostic code, or command.

Contents

Search the specification
Lispex 2.0 · Language · I.2

I.2

Source and normalization

Source text, tokens, literals, and the normalized form of a Lispex rule.

Scope

Write a rule as UTF-8 source and supply its input separately. Preparation reads the source and resolves its names before evaluation begins.

UTF-8 source

Source text is the UTF-8 spelling supplied for a module. Decoded characters use Unicode scalar values. Source identity retains the original bytes. The resolved program has its separate program identity. Values and text defines the text values that a rule can return.

2.1 Preserve source spelling

Source reading applies the raw Unicode rule to names and string literals. The resulting spellings determine source identifiers and literal text.

Why

Distinct decoded scalar sequences remain distinct across products. A host locale or compiler table must not silently rename a binding or alter data.

Keep two Unicode spellings distinct

lispex.example.v2.source.distinct-name-spellings · rev. 1

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
(define rule
  (lambda (input)
    (let ((|é| 1) (|é| 2))
      (list |é| |é|))))
)
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient to prepare this source",
    "evaluate": "finite values sufficient for the stated finite calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result(1 2)
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "list",
    "items": [
      {
        "kind": "integer",
        "value": "1"
      },
      {
        "kind": "integer",
        "value": "2"
      }
    ]
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Product invocation

Expected result

The two names denote different bindings and the result is the list of exact integers 1 and 2. Product invocation awaits its 2.0 adapter.

The first name contains one scalar. The second contains an e followed by a combining accent. Normalizing the names would merge distinct bindings.

Preserve text inside a string

lispex.example.v2.source.literal-text · rev. 1

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
(define rule
  (lambda (input)
    "A (; B)"))
)
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient to prepare this source",
    "evaluate": "finite values sufficient for the stated finite calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result"A (; B)"
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "string",
    "value": "A (; B)"
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Product invocation

Expected result

The rule returns the exact string A followed by a space, an opening parenthesis, a semicolon, a space, B, and a closing parenthesis. Product invocation awaits its 2.0 adapter.

Delimiters and a comment marker inside the quoted text belong to the string value.

2.2 Decode exact UTF-8 source bytes

Each module must satisfy the byte grammar before reading starts. Reject every malformed UTF-8 sequence. Decoding never inserts a replacement scalar. A byte order mark has no special treatment. A leading mark therefore fails the reader grammar. The same scalar is permitted inside a string, a quoted identifier, or a comment.

Why

Exact decoding keeps the submitted bytes and their meaning reproducible. Repair and automatic marker removal would silently change an input.

Reject malformed source octets

lispex.example.v2.source.invalid-utf8 · rev. 2

invalid-utf8.json
{
  "notation": "documentation-reader-cases",
  "cases": [
    {
      "case": "overlong",
      "sourceOctetsHex": "c080",
      "moduleName": "main",
      "diagnostic": {
        "phase": "decode",
        "code": "source.encoding",
        "data": {
          "reason": "invalid-utf8"
        }
      }
    },
    {
      "case": "surrogate",
      "sourceOctetsHex": "eda080",
      "moduleName": "main",
      "diagnostic": {
        "phase": "decode",
        "code": "source.encoding",
        "data": {
          "reason": "invalid-utf8"
        }
      }
    },
    {
      "case": "out-of-range",
      "sourceOctetsHex": "f4908080",
      "moduleName": "main",
      "diagnostic": {
        "phase": "decode",
        "code": "source.encoding",
        "data": {
          "reason": "invalid-utf8"
        }
      }
    },
    {
      "case": "stray-continuation",
      "sourceOctetsHex": "80",
      "moduleName": "main",
      "diagnostic": {
        "phase": "decode",
        "code": "source.encoding",
        "data": {
          "reason": "invalid-utf8"
        }
      }
    },
    {
      "case": "truncated",
      "sourceOctetsHex": "e282",
      "moduleName": "main",
      "diagnostic": {
        "phase": "decode",
        "code": "source.encoding",
        "data": {
          "reason": "invalid-utf8"
        }
      }
    },
    {
      "case": "invalid-leading-byte",
      "sourceOctetsHex": "ff",
      "moduleName": "main",
      "diagnostic": {
        "phase": "decode",
        "code": "source.encoding",
        "data": {
          "reason": "invalid-utf8"
        }
      }
    },
    {
      "case": "decode-before-reader",
      "sourceOctetsHex": "29ff",
      "moduleName": "main",
      "diagnostic": {
        "phase": "decode",
        "code": "source.encoding",
        "data": {
          "reason": "invalid-utf8"
        }
      }
    }
  ]
}
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "invalid-utf8.json",
  "rootModule": "main",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "caseInput": "submit-each-listed-source-independently"
}
Specification outcome
Diagnosticsource.encoding
Outcome details
{
  "case": "overlong",
  "kind": "prepare-failure",
  "stage": "decode",
  "valueCount": 0,
  "diagnostic": {
    "phase": "decode",
    "code": "source.encoding",
    "data": {
      "reason": "invalid-utf8"
    }
  }
}
Diagnosticsource.encoding
Outcome details
{
  "case": "surrogate",
  "kind": "prepare-failure",
  "stage": "decode",
  "valueCount": 0,
  "diagnostic": {
    "phase": "decode",
    "code": "source.encoding",
    "data": {
      "reason": "invalid-utf8"
    }
  }
}
Diagnosticsource.encoding
Outcome details
{
  "case": "out-of-range",
  "kind": "prepare-failure",
  "stage": "decode",
  "valueCount": 0,
  "diagnostic": {
    "phase": "decode",
    "code": "source.encoding",
    "data": {
      "reason": "invalid-utf8"
    }
  }
}
Diagnosticsource.encoding
Outcome details
{
  "case": "stray-continuation",
  "kind": "prepare-failure",
  "stage": "decode",
  "valueCount": 0,
  "diagnostic": {
    "phase": "decode",
    "code": "source.encoding",
    "data": {
      "reason": "invalid-utf8"
    }
  }
}
Diagnosticsource.encoding
Outcome details
{
  "case": "truncated",
  "kind": "prepare-failure",
  "stage": "decode",
  "valueCount": 0,
  "diagnostic": {
    "phase": "decode",
    "code": "source.encoding",
    "data": {
      "reason": "invalid-utf8"
    }
  }
}
Diagnosticsource.encoding
Outcome details
{
  "case": "invalid-leading-byte",
  "kind": "prepare-failure",
  "stage": "decode",
  "valueCount": 0,
  "diagnostic": {
    "phase": "decode",
    "code": "source.encoding",
    "data": {
      "reason": "invalid-utf8"
    }
  }
}
Diagnosticsource.encoding
Outcome details
{
  "case": "decode-before-reader",
  "kind": "prepare-failure",
  "stage": "decode",
  "valueCount": 0,
  "diagnostic": {
    "phase": "decode",
    "code": "source.encoding",
    "data": {
      "reason": "invalid-utf8"
    }
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "entryEvaluated": false,
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false,
  "replacementScalarsInserted": false
}
Product invocation

Expected result

Every byte sequence is rejected during decoding. The final case does not reach its earlier unmatched parenthesis. Product invocation awaits its 2.0 adapter.

The text fixture lists independent source inputs. Hex octets describe exact submitted bytes. This notation is not a public input codec.

Preserve a mark inside literal text

lispex.example.v2.source.literal-byte-order-mark · rev. 1

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
  (define rule (lambda (input)
    "")))
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "rootModule": "main",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result""
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "string",
    "value": ""
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Product invocation

Expected result

The result contains the literal U+FEFF scalar. Product invocation awaits its 2.0 adapter.

The UTF-8 decoder preserves the mark as a scalar. The string grammar admits it as data.

Tokens

Tokens distinguish identifiers, literal data, and the delimiters of a form. Reading produces syntax for preparation. Evaluation uses the lexical binding selected during preparation. Quotation uses the decoded name as data. The complete grammar below fixes token boundaries and escapes.

2.3 Read one fixed syntax

The complete reader grammar below determines every source token and datum. Bare identifiers use ASCII characters. Vertical bars admit every Unicode scalar sequence through literal characters or escapes. Identifiers compare by their decoded scalar sequence. Spelling escapes do not create a different name. Only the listed separators end tokens. Block comments nest. A datum comment reads and discards the next datum. Discarded data must satisfy the reader grammar but undergo no normalization. Reader directives and unlisted token prefixes are rejected.

Why

Explicit character sets avoid host locale and Unicode classification differences. Quoted names retain arbitrary text without adding invisible token boundaries. Nested comments remain readable while discarded syntax receives the same finite reading checks.

Read exact names with bars and escapes

lispex.example.v2.source.identifier-spellings · rev. 1

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
  (define rule (lambda (input)
    (let ((|caf\u{e9}| 1) (|café| 2)) (list |café| |café| '|a b| '|| '|1|)))))
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "rootModule": "main",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result(1 2 a b 1)
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "list",
    "items": [
      {
        "kind": "integer",
        "value": "1"
      },
      {
        "kind": "integer",
        "value": "2"
      },
      {
        "kind": "symbol",
        "value": "a b"
      },
      {
        "kind": "symbol",
        "value": ""
      },
      {
        "kind": "symbol",
        "value": "1"
      }
    ]
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Product invocation

Expected result

The escaped and literal spellings of café select the same binding. The decomposed name remains distinct. Product invocation awaits its 2.0 adapter.

A numeric spelling inside bars denotes a symbol. The empty barred spelling also denotes a symbol.

Read nested comments and discard complete data

lispex.example.v2.source.nested-and-datum-comments · rev. 1

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
  (define rule (lambda (input)
    (list 1#| outer #| nested |# end |#2 #;#;(ignored) (set! input 9) 3))))
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "rootModule": "main",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result(1 2 3)
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "list",
    "items": [
      {
        "kind": "integer",
        "value": "1"
      },
      {
        "kind": "integer",
        "value": "2"
      },
      {
        "kind": "integer",
        "value": "3"
      }
    ]
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Product invocation

Expected result

The rule returns the exact integers 1, 2, and 3 in order. Product invocation awaits its 2.0 adapter.

The inner datum comment discards its datum. The outer datum comment then discards the mutation form before normalization.

Reject unlisted source syntax

lispex.example.v2.source.reader-rejections · rev. 2

reader-rejections.json
{
  "notation": "documentation-reader-cases",
  "cases": [
    {
      "case": "bare-nonascii",
      "source": "café",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "invalid-token"
        }
      }
    },
    {
      "case": "nbsp-separator",
      "source": "a b",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "invalid-token"
        }
      }
    },
    {
      "case": "lone-carriage-return",
      "source": "a\rb",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "invalid-token"
        }
      }
    },
    {
      "case": "leading-mark",
      "source": "(define x 1)",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unexpected-source-scalar"
        }
      }
    },
    {
      "case": "double-mark",
      "source": "",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unexpected-source-scalar"
        }
      }
    },
    {
      "case": "case-directive",
      "source": "#!fold-case",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unsupported-reader-prefix"
        }
      }
    },
    {
      "case": "language-directive",
      "source": "#lang lispex",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unsupported-reader-prefix"
        }
      }
    },
    {
      "case": "shebang",
      "source": "#!/usr/bin/lispex",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unsupported-reader-prefix"
        }
      }
    },
    {
      "case": "unterminated-block",
      "source": "#| outer #| inner |#",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.delimiter",
        "data": {
          "reason": "unexpected-end"
        }
      }
    },
    {
      "case": "missing-discard",
      "source": "#;",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.delimiter",
        "data": {
          "reason": "unexpected-end"
        }
      }
    },
    {
      "case": "invalid-discard",
      "source": "#; (",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.delimiter",
        "data": {
          "reason": "unexpected-end"
        }
      }
    },
    {
      "case": "datum-label",
      "source": "#0=(a . #0#)",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unsupported-reader-prefix"
        }
      }
    },
    {
      "case": "alternate-brackets",
      "source": "[1 2]",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "invalid-token"
        }
      }
    },
    {
      "case": "quasiquote",
      "source": "`x",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "invalid-token"
        }
      }
    },
    {
      "case": "empty-dotted-list",
      "source": "(. a)",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.delimiter",
        "data": {
          "reason": "improper-form"
        }
      }
    },
    {
      "case": "extra-dotted-tail",
      "source": "(a . b c)",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.delimiter",
        "data": {
          "reason": "improper-form"
        }
      }
    },
    {
      "case": "vector-dot",
      "source": "#(a . b)",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.delimiter",
        "data": {
          "reason": "improper-form"
        }
      }
    },
    {
      "case": "wrong-boolean",
      "source": "#true",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "invalid-token"
        }
      }
    }
  ]
}
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "reader-rejections.json",
  "rootModule": "main",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "caseInput": "submit-each-listed-source-independently"
}
Specification outcome
Diagnosticsource.token
Outcome details
{
  "case": "bare-nonascii",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "invalid-token"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "nbsp-separator",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "invalid-token"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "lone-carriage-return",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "invalid-token"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "leading-mark",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unexpected-source-scalar"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "double-mark",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unexpected-source-scalar"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "case-directive",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-reader-prefix"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "language-directive",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-reader-prefix"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "shebang",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-reader-prefix"
    }
  }
}
Diagnosticsource.delimiter
Outcome details
{
  "case": "unterminated-block",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.delimiter",
    "data": {
      "reason": "unexpected-end"
    }
  }
}
Diagnosticsource.delimiter
Outcome details
{
  "case": "missing-discard",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.delimiter",
    "data": {
      "reason": "unexpected-end"
    }
  }
}
Diagnosticsource.delimiter
Outcome details
{
  "case": "invalid-discard",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.delimiter",
    "data": {
      "reason": "unexpected-end"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "datum-label",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-reader-prefix"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "alternate-brackets",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "invalid-token"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "quasiquote",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "invalid-token"
    }
  }
}
Diagnosticsource.delimiter
Outcome details
{
  "case": "empty-dotted-list",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.delimiter",
    "data": {
      "reason": "improper-form"
    }
  }
}
Diagnosticsource.delimiter
Outcome details
{
  "case": "extra-dotted-tail",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.delimiter",
    "data": {
      "reason": "improper-form"
    }
  }
}
Diagnosticsource.delimiter
Outcome details
{
  "case": "vector-dot",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.delimiter",
    "data": {
      "reason": "improper-form"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "wrong-boolean",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "invalid-token"
    }
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "entryEvaluated": false,
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false
}
Product invocation

Expected result

Each source fails reading before normalization begins. Product invocation awaits its 2.0 adapter.

The text fixture lists independent source inputs. Hex octets describe exact submitted bytes. This notation is not a public input codec.

2.4 Separate tokens outside literals

Use the token and literal boundaries in the reader grammar. A comment marker is recognized outside String, BarredIdentifier, and Character tokens. A semicolon inside an admitted literal remains part of that literal.

Why

Explicit separators make a source file independent of a host tokenizer. Keeping comments outside literals preserves the data written inside a string.

Token boundaries specify separators and line comments.

Ignore a comment between forms

lispex.example.v2.source.separators-and-comment · rev. 2

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
(define rule
  (lambda (input)
    (+	input ; the supplied value
       1)))
)
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient to prepare this source",
    "evaluate": "finite values sufficient for the stated finite calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "41"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result42
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "integer",
    "value": "42"
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Product invocation

Expected result

The comment and separators leave an addition that returns the exact integer 42. Product invocation awaits its 2.0 adapter.

The tab separates two tokens. The line comment ends before the second operand.

Complete reader grammar

EBNF
SourceBytes = { Utf8Scalar } ;
Utf8Scalar = "00" .. "7F" | "C2" .. "DF" Continuation | "E0" "A0" .. "BF" Continuation | "E1" .. "EC" Continuation Continuation | "ED" "80" .. "9F" Continuation | "EE" .. "EF" Continuation Continuation | "F0" "90" .. "BF" Continuation Continuation | "F1" .. "F3" Continuation Continuation Continuation | "F4" "80" .. "8F" Continuation Continuation ;
Continuation = "80" .. "BF" ;
Document = Gap { Datum Gap } End ;
Datum = List | Vector | Bytevector | Abbreviation | String TokenEnd | Character TokenEnd | Boolean TokenEnd | Number TokenEnd | Identifier TokenEnd ;
List = "(" Gap [ Datum Gap { Datum Gap } [ "." TokenEnd Gap Datum Gap ] ] ")" ;
Vector = "#(" Gap { Datum Gap } ")" ;
Bytevector = "#u8(" Gap { Number TokenEnd Gap } ")" ;
Abbreviation = "'" Gap Datum ;
Gap = { White | LineComment | BlockComment | DatumComment } ;
White = "U+0020" | "U+0009" | LineEnd ;
LineEnd = "U+000A" | "U+000D" "U+000A" ;
LineComment = ";" { !LineEnd Scalar } [ LineEnd ] ;
BlockComment = "#|" { BlockComment | BlockScalar } "|#" ;
BlockScalar = !( "#|" | "|#" ) Scalar ;
DatumComment = "#;" Gap Datum ;
Delimiter = White | "(" | ")" | "'" | "U+0022" | ";" | "#|" | "#;" ;
TokenEnd = &( Delimiter | End ) ;
End = "end-of-input" ;
Identifier = BareIdentifier | BarredIdentifier ;
BareIdentifier = ( Initial { Subsequent } ) - NumericCandidate - ReservedNumber - "." ;
Initial = "A" .. "Z" | "a" .. "z" | "!" | "$" | "%" | "&" | "*" | "/" | ":" | "<" | "=" | ">" | "?" | "^" | "_" | "~" | "+" | "-" | "." | "@" ;
Subsequent = Initial | DecimalDigit ;
NumericCandidate = [ Sign ] ( DecimalDigit { Subsequent } | "." DecimalDigit { Subsequent } ) ;
ReservedNumber = InexactWord | "+i" | "-i" ;
InexactWord = "+inf.0" | "-inf.0" | "+nan.0" | "-nan.0" ;
BarredIdentifier = "|" { BarredScalar | IdentifierEscape } "|" ;
BarredScalar = Scalar - Control - "|" - "U+005C" ;
IdentifierEscape = "U+005C" ( "|" | "U+005C" | ScalarEscape ) ;
String = "U+0022" { StringScalar | StringEscape } "U+0022" ;
StringScalar = Scalar - Control - "U+0022" - "U+005C" ;
StringEscape = "U+005C" ( "U+0022" | "U+005C" | "n" | "r" | "t" | ScalarEscape ) ;
ScalarEscape = "u{" HexDigits "}" ;
HexDigits = HexDigit [ HexDigit [ HexDigit [ HexDigit [ HexDigit [ HexDigit ] ] ] ] ] ;
Character = "#" "U+005C" ( CharacterName | ScalarEscape | CharacterScalar ) ;
CharacterName = "space" | "newline" | "tab" | "return" | "null" ;
CharacterScalar = Scalar - Control - "U+0020" ;
Boolean = "#t" | "#f" ;
Number = [ Sign ] DecimalMagnitude | "#d" [ Sign ] DecimalMagnitude | "#b" [ Sign ] BinaryMagnitude | "#o" [ Sign ] OctalMagnitude | "#x" [ Sign ] HexMagnitude ;
Sign = "+" | "-" ;
DecimalMagnitude = DecimalInteger [ "/" DecimalInteger ] | DecimalInteger "." [ DecimalInteger ] [ Exponent ] | "." DecimalInteger [ Exponent ] | DecimalInteger Exponent ;
Exponent = ( "e" | "E" ) [ Sign ] DecimalInteger ;
DecimalInteger = DecimalDigit { DecimalDigit } ;
BinaryMagnitude = BinaryInteger [ "/" BinaryInteger ] ;
BinaryInteger = BinaryDigit { BinaryDigit } ;
OctalMagnitude = OctalInteger [ "/" OctalInteger ] ;
OctalInteger = OctalDigit { OctalDigit } ;
HexMagnitude = HexInteger [ "/" HexInteger ] ;
HexInteger = HexDigit { HexDigit } ;
BinaryDigit = "0" | "1" ;
OctalDigit = "0" .. "7" ;
DecimalDigit = "0" .. "9" ;
HexDigit = DecimalDigit | "a" .. "f" | "A" .. "F" ;
Control = "U+0000" .. "U+001F" | "U+007F" .. "U+009F" ;
Scalar = "U+0000" .. "U+D7FF" | "U+E000" .. "U+10FFFF" ;
NotationMeaning
SourceBytesMatch all submitted octets before scalar decoding
Hex pairs in Utf8Scalar and ContinuationOne octet or an inclusive octet range
U+ terminalsThe indicated scalar value or inclusive scalar range
Other quoted terminalsLiteral scalar sequences
end-of-inputA zero width test for the end of the decoded module
& and !Positive and negative lookahead without consumption
-Exclude the right operand from the language on the left

Use the longest complete atomic token. A token beginning with a decimal digit is numeric. A sign or dot followed by decimal digits also starts a numeric candidate. Radix prefixes commit to their numeric grammar. A malformed candidate cannot fall back to an identifier. The standalone dot is permitted only in a nonempty list before its single tail datum. Parentheses pair exactly. Brackets and braces have no alternate list meaning.

Input formDecoded meaning or restriction
\n, \r, \t in a stringLine feed, carriage return, tab
\u{...}The hexadecimal scalar value
A scalar escape in the surrogate range or above U+10FFFFReader failure
Literal control scalars in strings or barred identifiersUse an escape instead
||The empty identifier name
#\space, #\newline, #\tab, #\return, #\nullU+0020, U+000A, U+0009, U+000D, U+0000
A direct character scalar after #\Exactly one scalar followed by a token boundary
#b, #o, #d, #xLowercase radix prefixes with a following optional sign
A numeric rationalAn unsigned nonzero denominator in the selected radix
Decimal leading zeroes and hexadecimal letter casePreserve the same exact numeric value
#e, #i, +inf.0, -inf.0, +nan.0, -nan.0, +i, -iReader failure
Complex tokens that begin as numeric candidatesReader failure
#!, #lang, a shebang, datum labels, backquote, commaReader failure outside literal text or comments
A leading or repeated byte order markReader failure
Other whitespace and a lone carriage returnReader failure outside literal text or comments

An escaped identifier and a literal identifier with the same decoded scalar sequence name the same binding. A barred numeric spelling is an identifier. It is not a number. Comment and radix prefixes are ordinary text where the literal grammar admits their characters. Block comment delimiters nest even when their surrounding comment text contains quote characters. A datum comment skips trivia before reading its one discarded datum. This includes nested datum comments. An unfinished comment, escape, string, list, or quoted datum fails reading. Syntax inside a discarded datum must still be complete.

The quote prefix becomes the ordinary quote form during normalization. Lists, pairs, vectors, and bytevectors retain their element order. Decimal fractions and exponents reduce to the exact values defined by Exact numbers. The reader creates no cyclic datum.

The reader checks an escape when its final scalar is read. It checks literal control scalars when they are read. Atomic token grammar and numeric value checks occur at the completed token. A bytevector element receives its integer and octet range checks before the next element is read. A malformed numeric token fails before its value checks. A zero denominator fails before a bytevector range check. If reading reaches source end, its end test reserves one read-step.

Literals and surface forms

A literal denotes an immutable value. Quoted names are symbols. Quoted lists are data. Decimal spelling denotes an exact number. Exact numbers defines its arithmetic and rounding contracts. Datum defines the data allowed at the rule boundary.

2.5 Read numeric literals exactly

Numeric literals follow the exact arithmetic rule and the exact-only rule. Reading a decimal spelling uses the decimal value contract.

Why

The same source must denote the same value on every architecture. Decimal notation must retain the value that the author wrote.

Add exact decimal literals

lispex.example.v2.source.exact-decimal · rev. 1

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
(define rule
  (lambda (input)
    (= (+ 0.1 0.2) 3/10)))
)
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient to prepare this source",
    "evaluate": "finite values sufficient for the stated finite calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result#t
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "boolean",
    "value": true
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Product invocation

Expected result

The exact decimal sum equals three tenths and the rule returns true. Product invocation awaits its 2.0 adapter.

The comparison checks exact arithmetic. Decimal representation and codec bytes remain separate contracts.

Reject an inexact literal

lispex.example.v2.source.inexact-literal · rev. 3

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
(define rule
  (lambda (input)
    #i0.1))
)
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient to prepare this source",
    "evaluate": "finite values sufficient for the stated finite calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Diagnosticsource.token
Outcome details
{
  "kind": "prepare-failure",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-reader-prefix"
    }
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "entryEvaluated": false,
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false
}
Product invocation

Expected result

Preparation rejects the explicitly inexact literal and the entry is not evaluated. Product invocation awaits its 2.0 adapter.

The reader mapping uses read and source.token with reason unsupported-reader-prefix. Rejection does not convert this spelling to a supported float.

2.6 Give literals exact values

Strings and quoted identifiers use only the listed escapes. A scalar escape must name a Unicode scalar value. Every numeric token denotes an exact integer or a reduced rational. A decimal exponent scales by an exact power of ten. A rational denominator must be nonzero. Radix prefixes select the digit alphabet in the grammar. Numeric candidates that fail that grammar are errors. They cannot become identifiers. Bytevector elements must denote exact integers from 0 through 255.

Why

One lexical interpretation prevents malformed numbers from becoming accidental names. Exact literals give every product the same data before arithmetic or admission begins.

Read escaped scalars and delimiters

lispex.example.v2.source.scalar-escapes · rev. 1

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
  (define rule (lambda (input)
    (list "line\n\u{1F642}\\\"" #\u{1F642} '|a\|b|))))
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "rootModule": "main",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result("line\n🙂\\\"" #\🙂 a|b)
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "list",
    "items": [
      {
        "kind": "string",
        "value": "line\n🙂\\\""
      },
      {
        "kind": "character",
        "value": "🙂"
      },
      {
        "kind": "symbol",
        "value": "a|b"
      }
    ]
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Product invocation

Expected result

The result preserves the decoded newline, supplementary scalar, quote, backslash, and barred name. Product invocation awaits its 2.0 adapter.

Escapes name Unicode scalar values. They do not normalize or case fold the result.

Read exact values in every radix

lispex.example.v2.source.radix-and-decimal-values · rev. 1

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
  (define rule (lambda (input)
    (list #b101 #o17 #x-ff #d+12 0.125 12e-1 #xA/F .5 1.))))
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "rootModule": "main",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result(5 15 -255 12 1/8 6/5 2/3 1/2 1)
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "list",
    "items": [
      {
        "kind": "integer",
        "value": "5"
      },
      {
        "kind": "integer",
        "value": "15"
      },
      {
        "kind": "integer",
        "value": "-255"
      },
      {
        "kind": "integer",
        "value": "12"
      },
      {
        "kind": "rational",
        "numerator": "1",
        "denominator": "8"
      },
      {
        "kind": "rational",
        "numerator": "6",
        "denominator": "5"
      },
      {
        "kind": "rational",
        "numerator": "2",
        "denominator": "3"
      },
      {
        "kind": "rational",
        "numerator": "1",
        "denominator": "2"
      },
      {
        "kind": "integer",
        "value": "1"
      }
    ]
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Product invocation

Expected result

Every spelling becomes its stated exact integer or reduced rational. Product invocation awaits its 2.0 adapter.

The source scale and radix do not become observable numeric state.

Read pair tails, vectors, and bytevectors

lispex.example.v2.source.compound-datum · rev. 1

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
  (define rule (lambda (input)
    '((a . b) #(1 #t) #u8(0 255)))))
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "rootModule": "main",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result((a . b) #(1 #t) #u8(0 255))
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "list",
    "items": [
      {
        "kind": "pair",
        "car": {
          "kind": "symbol",
          "value": "a"
        },
        "cdr": {
          "kind": "symbol",
          "value": "b"
        }
      },
      {
        "kind": "vector",
        "items": [
          {
            "kind": "integer",
            "value": "1"
          },
          {
            "kind": "boolean",
            "value": true
          }
        ]
      },
      {
        "kind": "bytevector",
        "bytes": [
          0,
          255
        ]
      }
    ]
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Product invocation

Expected result

The quote returns its ordered pair, vector, and bytevector data. Product invocation awaits its 2.0 adapter.

A dot denotes one list tail. Vectors and bytevectors have no dotted tail syntax.

Reject malformed literal values

lispex.example.v2.source.literal-rejections · rev. 2

literal-rejections.json
{
  "notation": "documentation-reader-cases",
  "cases": [
    {
      "case": "unknown-string-escape",
      "source": "\"\\q\"",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "invalid-escape"
        }
      }
    },
    {
      "case": "unknown-identifier-escape",
      "source": "|a\\n|",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "invalid-escape"
        }
      }
    },
    {
      "case": "surrogate-escape",
      "source": "\"\\u{d800}\"",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "invalid-scalar"
        }
      }
    },
    {
      "case": "out-of-range-escape",
      "source": "#\\u{110000}",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "invalid-scalar"
        }
      }
    },
    {
      "case": "too-long-escape",
      "source": "\"\\u{0000000}\"",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "invalid-scalar"
        }
      }
    },
    {
      "case": "raw-newline",
      "source": "\"a\nb\"",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "invalid-scalar"
        }
      }
    },
    {
      "case": "binary-digit",
      "source": "#b102",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.number",
        "data": {
          "reason": "invalid-number"
        }
      }
    },
    {
      "case": "uppercase-prefix",
      "source": "#Xff",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unsupported-reader-prefix"
        }
      }
    },
    {
      "case": "radix-decimal",
      "source": "#x1.2",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.number",
        "data": {
          "reason": "invalid-number"
        }
      }
    },
    {
      "case": "zero-denominator",
      "source": "1/0",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.number",
        "data": {
          "reason": "zero-denominator"
        }
      }
    },
    {
      "case": "signed-denominator",
      "source": "1/-2",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.number",
        "data": {
          "reason": "invalid-number"
        }
      }
    },
    {
      "case": "unfinished-exponent",
      "source": "1e+",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.number",
        "data": {
          "reason": "invalid-number"
        }
      }
    },
    {
      "case": "numeric-name",
      "source": "+12abc",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.number",
        "data": {
          "reason": "invalid-number"
        }
      }
    },
    {
      "case": "inexact-prefix",
      "source": "#i1.0",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unsupported-reader-prefix"
        }
      }
    },
    {
      "case": "exactness-prefix",
      "source": "#e1",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unsupported-reader-prefix"
        }
      }
    },
    {
      "case": "infinity",
      "source": "+inf.0",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.number",
        "data": {
          "reason": "inexact-number"
        }
      }
    },
    {
      "case": "nan",
      "source": "-nan.0",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.number",
        "data": {
          "reason": "inexact-number"
        }
      }
    },
    {
      "case": "complex",
      "source": "1+2i",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.number",
        "data": {
          "reason": "invalid-number"
        }
      }
    },
    {
      "case": "octet-range",
      "source": "#u8(256)",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unsupported-literal"
        }
      }
    },
    {
      "case": "octet-fraction",
      "source": "#u8(1/2)",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unsupported-literal"
        }
      }
    },
    {
      "case": "invalid-discard-number",
      "source": "#; #i1.0",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unsupported-reader-prefix"
        }
      }
    },
    {
      "case": "unit-imaginary",
      "source": "+i",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unsupported-literal"
        }
      }
    },
    {
      "case": "octet-before-later-token",
      "source": "#u8(256 #b2)",
      "moduleName": "main",
      "diagnostic": {
        "phase": "read",
        "code": "source.token",
        "data": {
          "reason": "unsupported-literal"
        }
      }
    }
  ]
}
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "literal-rejections.json",
  "rootModule": "main",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "caseInput": "submit-each-listed-source-independently"
}
Specification outcome
Diagnosticsource.token
Outcome details
{
  "case": "unknown-string-escape",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "invalid-escape"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "unknown-identifier-escape",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "invalid-escape"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "surrogate-escape",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "invalid-scalar"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "out-of-range-escape",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "invalid-scalar"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "too-long-escape",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "invalid-scalar"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "raw-newline",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "invalid-scalar"
    }
  }
}
Diagnosticsource.number
Outcome details
{
  "case": "binary-digit",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.number",
    "data": {
      "reason": "invalid-number"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "uppercase-prefix",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-reader-prefix"
    }
  }
}
Diagnosticsource.number
Outcome details
{
  "case": "radix-decimal",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.number",
    "data": {
      "reason": "invalid-number"
    }
  }
}
Diagnosticsource.number
Outcome details
{
  "case": "zero-denominator",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.number",
    "data": {
      "reason": "zero-denominator"
    }
  }
}
Diagnosticsource.number
Outcome details
{
  "case": "signed-denominator",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.number",
    "data": {
      "reason": "invalid-number"
    }
  }
}
Diagnosticsource.number
Outcome details
{
  "case": "unfinished-exponent",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.number",
    "data": {
      "reason": "invalid-number"
    }
  }
}
Diagnosticsource.number
Outcome details
{
  "case": "numeric-name",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.number",
    "data": {
      "reason": "invalid-number"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "inexact-prefix",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-reader-prefix"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "exactness-prefix",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-reader-prefix"
    }
  }
}
Diagnosticsource.number
Outcome details
{
  "case": "infinity",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.number",
    "data": {
      "reason": "inexact-number"
    }
  }
}
Diagnosticsource.number
Outcome details
{
  "case": "nan",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.number",
    "data": {
      "reason": "inexact-number"
    }
  }
}
Diagnosticsource.number
Outcome details
{
  "case": "complex",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.number",
    "data": {
      "reason": "invalid-number"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "octet-range",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-literal"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "octet-fraction",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-literal"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "invalid-discard-number",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-reader-prefix"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "unit-imaginary",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-literal"
    }
  }
}
Diagnosticsource.token
Outcome details
{
  "case": "octet-before-later-token",
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.token",
    "data": {
      "reason": "unsupported-literal"
    }
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "entryEvaluated": false,
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false
}
Product invocation

Expected result

Each malformed literal is rejected. No token is reinterpreted as an identifier. Product invocation awaits its 2.0 adapter.

The text fixture lists independent source inputs. Hex octets describe exact submitted bytes. This notation is not a public input codec.

Normalization

Normalization follows the canonical source construction. That table defines the admitted rewrites and preserved semantic nodes. Preparation resolves their references to lexical bindings. A normalizer preserves quoted data and follows the evaluation rules. Source maps retain source positions for display.

2.7 Preserve meaning through normalization

Normalization preserves lexical bindings, literal values, evaluation order, and the first observable failure. A generated binding cannot capture a source reference.

Why

Surface syntax is a way to write the rule. Changing its spelling must not give the normalizer permission to change the rule being evaluated.

Read both quotation forms as data

lispex.example.v2.source.quote-forms · rev. 1

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
(define rule
  (lambda (input)
    (equal? '(a b) (quote (a b)))))
)
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient to prepare this source",
    "evaluate": "finite values sufficient for the stated finite calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result#t
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "boolean",
    "value": true
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Product invocation

Expected result

The two quoted lists have equal data and the rule returns true. Product invocation awaits its 2.0 adapter.

Quotation preserves the symbols a and b as data. These spellings do not look up procedure bindings.

Preserve a binding through conditional sugar

lispex.example.v2.source.conditional-sugar · rev. 1

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
(define rule
  (lambda (input)
    (let ((saved input))
      (cond (#f 0)
            (else saved)))))
)
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient to prepare this source",
    "evaluate": "finite values sufficient for the stated finite calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "42"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result42
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "integer",
    "value": "42"
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Product invocation

Expected result

The conditional reads the surrounding saved binding and returns the exact integer 42. Product invocation awaits its 2.0 adapter.

Lowering the conditional must preserve the surrounding lexical scope.

2.8 Resolve only submitted source

Source submission follows the closed-bundle rule. Reading or normalization cannot add a dependency outside that submitted bundle.

Why

A rule must use the source and library identities fixed by its request. Runtime discovery would introduce an unstated input and an external authority.

Reject runtime source loading

lispex.example.v2.source.runtime-load · rev. 3

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
(define rule
  (lambda (input)
    (load "other.scm")))
)
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient to prepare this source",
    "evaluate": "finite values sufficient for the stated finite calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Diagnosticlibrary.reference
Outcome details
{
  "kind": "failure",
  "valueCount": 0,
  "diagnostic": {
    "phase": "resolve",
    "code": "library.reference",
    "data": {
      "name": "load",
      "reason": "removed-operation"
    }
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "externalAccess": {
    "filesystem": false,
    "network": false
  },
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false
}
Product invocation

Expected result

The runtime load request fails without reading a file or accessing a network. Product invocation awaits its 2.0 adapter.

The string names no granted capability. The source bundle determines which dependencies preparation can resolve.

Preparation failures

Reader and normalization failures use source-bound preparation reports. Preparation and modules defines the closed bundle. The entry runs only after preparation succeeds. The preparation diagnostic mapping gives each failure its catalog identity and typed fields.

2.9 Reject invalid source before evaluation

A reader or normalization failure stops preparation before entry. Record it under the source-bound preparation report rule.

Why

An invalid source cannot provide a valid program identity. Keeping the failure with its source preserves a useful diagnostic without inventing an evaluation.

Reject an unfinished source form

lispex.example.v2.source.unclosed-form · rev. 3

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
(define rule
  (lambda (input)
    input)
)
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient to prepare this source",
    "evaluate": "finite values sufficient for the stated finite calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Diagnosticsource.delimiter
Outcome details
{
  "kind": "prepare-failure",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.delimiter",
    "data": {
      "reason": "unexpected-end"
    }
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "entryEvaluated": false,
  "failureIdentity": {
    "basis": "submitted-source",
    "validProgramIdentity": false
  },
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false
}
Product invocation

Expected result

The unfinished form fails preparation and produces no rule result. Product invocation awaits its 2.0 adapter.

The definition is complete. The enclosing module is unfinished, so reading fails before preparation can continue.

2.10 Account for preparation separately

Source decoding, reading, and normalization use the preparation account defined by Resources. The finite-limit rule applies before any entry evaluation.

Why

Deep or large source can require work before any rule runs. A finite evaluation budget alone cannot bound that work.

Stop when preparation has insufficient budget

lispex.example.v2.source.prepare-exhaustion · rev. 3

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
(define rule
  (lambda (input)
    input))
)
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite limits below a required preparation reservation",
    "evaluate": "finite values sufficient for the identity rule"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Resultresource-stop
Outcome details
{
  "kind": "resource-stop",
  "phase": "prepare",
  "valueCount": 0,
  "terminal": true,
  "diagnosticIdentity": {
    "phase": "prepare",
    "code": "resource.exhausted"
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "entryEvaluated": false,
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false
}
Product invocation

Expected result

An insufficient preparation budget causes a terminal resource stop before entry evaluation. Product invocation awaits its 2.0 adapter.

The request describes a relation to a required reservation. It does not freeze a numeric tariff or a default limit.

2.11 Check a binding group before its children

Preparation follows the complete reading order. Normalization visits forms in source order. It checks a binding group when that traversal reaches the group. The shallow checks finish before any initializer or body in that group is normalized. Each required check reserves its event before inspecting syntax. A refused reservation stops before that inspection. An observed error stops before any later reservation. The event and check tables below fix this order. The reservation axis rule applies within each event.

Why

A complete group check gives each binding one static meaning. Local prechecks preserve the order of unrelated forms. Reservations bound the work needed to discover an error without moving a later event before that error.

EventNext operationOrder
prepare.decode-stepDecode the next UTF-8 scalar or confirm source endComplete the module before reading
prepare.read-stepInspect the next decoded scalar or confirm source endLeft to right with each scalar inspected once
prepare.read-enterEnter a list, vector, bytevector, quote, block comment, or datum commentAfter its opening marker and before its contents
prepare.read-nodeValidate and construct a completed datumChildren before their containing datum
prepare.normalize-nodeInspect the next source formSource order with children after their parent checks
prepare.binding-checkInspect the group envelope or the next member checkBefore that inspection
prepare.binding-publishRecord a checked lexical bindingMember order after all group checks

Reading completes before normalization starts. Reader lookahead reuses scalars already inspected and adds no second read event. A nested marker selects its enter event before any child event. A closing marker is read before its completed datum event. A block comment has enter events and scalar events but no datum node. A completed atomic token reserves its node event before token and numeric value checks. Its bytevector element checks finish before reading the next element. Datum comments retain every event of their discarded datum. Each event reserves all required axes before its effect. Reader enter events include required frame capacity. These events follow the grammar rather than implementation scanner loops. A comment or discarded datum still requires its reading events. The resource model names the requirements for each event. Its coefficients and finite defaults follow the cost model freeze.

CheckFailure selection
Group envelopeReject a malformed group before visiting a member
Member shapeReject the first malformed binding or parameter
IdentifierReject a binding position that is not an identifier
DuplicateReject a repeated name in the same binding scope
Recursive lambda headRequire the lambda head where recursive bindings require it

Run these member checks from left to right. Skip the lambda check for a nonrecursive binding. Stop at the first failed check. Parameter lists include their rest parameter in the same duplicate check. A parallel let, named let, letrec, or recursive definition group checks all members before descending. Each let* binding forms its own nested group. Its initializer is normalized before the next binding group.

Publishing a binding records its identity. The lexical scope rules determine where that binding is visible. A parallel let initializer and a named let initializer retain their enclosing scope. All checks finish during preparation. They execute no guest initializer.

Find a duplicate before an initializer error

lispex.example.v2.source.group-before-initializer · rev. 2

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
  (define rule (lambda (input)
    (let ((x (set! input 1)) (x 2)) x))))
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Diagnosticbinding.duplicate
Outcome details
{
  "kind": "prepare-failure",
  "stage": "normalization",
  "valueCount": 0,
  "binding": "x",
  "check": "duplicate",
  "initializerVisited": false,
  "diagnostic": {
    "phase": "normalize",
    "code": "binding.duplicate",
    "data": {
      "name": "x",
      "scope": "let"
    }
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "entryEvaluated": false,
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false
}
Product invocation

Expected result

The duplicate x is rejected before normalization enters the first initializer. Product invocation awaits its 2.0 adapter.

The expected meaning is authored for Lispex 2.0. Product execution remains not-run.

Check every recursive initializer head first

lispex.example.v2.source.recursive-group-before-body · rev. 2

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
  (define rule (lambda (input)
    (letrec ((f (lambda (x) (set! x 0))) (g 1)) f))))
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Diagnosticbinding.initializer
Outcome details
{
  "kind": "prepare-failure",
  "stage": "normalization",
  "valueCount": 0,
  "binding": "g",
  "earlierLambdaBodyVisited": false,
  "diagnostic": {
    "phase": "normalize",
    "code": "binding.initializer",
    "data": {
      "form": "letrec",
      "name": "g",
      "expected": "lambda"
    }
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "entryEvaluated": false,
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false
}
Product invocation

Expected result

The initializer of g is rejected before normalization enters the body of f. Product invocation awaits its 2.0 adapter.

The expected meaning is authored for Lispex 2.0. Product execution remains not-run.

Keep an earlier form ahead of a later group

lispex.example.v2.source.earlier-form-before-group · rev. 2

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
  (define rule (lambda (input)
    (begin (set! input 1) (let ((x 1) (x 2)) x)))))
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Diagnosticbinding.immutable
Outcome details
{
  "kind": "prepare-failure",
  "stage": "normalization",
  "valueCount": 0,
  "form": "set!",
  "laterGroupInspected": false,
  "diagnostic": {
    "phase": "normalize",
    "code": "binding.immutable",
    "data": {
      "name": "input"
    }
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "entryEvaluated": false,
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false
}
Product invocation

Expected result

The earlier mutation form is rejected before the later binding group is inspected. Product invocation awaits its 2.0 adapter.

The expected meaning is authored for Lispex 2.0. Product execution remains not-run.

Reserve only the next required check

lispex.example.v2.source.precheck-reservation-order · rev. 3

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
  (define rule (lambda (input)
    (let ((x (set! input 1)) (x 2)) x))))
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "reservationCases": [
    {
      "case": "refuse-required-duplicate-check",
      "limits": "the work reservation for the second x duplicate check is refused"
    },
    {
      "case": "permit-error-check-refuse-later-work",
      "limits": "all group checks fit but the first initializer normalization would be refused"
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Diagnosticresource.exhausted
Outcome details
{
  "case": "refuse-required-duplicate-check",
  "kind": "resource-stop",
  "stage": "normalization",
  "axis": "work",
  "event": "prepare.binding-check",
  "check": "duplicate",
  "binding": "x",
  "duplicateObserved": false,
  "eventCommitted": false,
  "earlierChargesRetained": true,
  "valueCount": 0,
  "phase": "prepare",
  "terminal": true,
  "diagnostic": {
    "phase": "prepare",
    "code": "resource.exhausted",
    "data": {
      "stage": "normalize",
      "axis": "work",
      "event": "prepare.binding-check"
    }
  }
}
Diagnosticbinding.duplicate
Outcome details
{
  "case": "permit-error-check-refuse-later-work",
  "kind": "prepare-failure",
  "stage": "normalization",
  "binding": "x",
  "laterReservationAttempted": false,
  "valueCount": 0,
  "diagnostic": {
    "phase": "normalize",
    "code": "binding.duplicate",
    "data": {
      "name": "x",
      "scope": "let"
    }
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "entryEvaluated": false,
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false
}
Product invocation

Expected result

A refused check stops before discovering the duplicate. A discovered duplicate prevents every later reservation. Product invocation awaits its 2.0 adapter.

The fixture selects symbolic reservation boundaries. It assigns no tariff coefficient or finite default.

Keep sequential bindings in separate scopes

lispex.example.v2.source.sequential-group-scopes · rev. 1

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
  (define rule (lambda (input)
    (let* ((x 1) (x (+ x 1))) x))))
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient for the stated checks",
    "evaluate": "finite values sufficient for the stated calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Result2
Outcome details
{
  "kind": "value",
  "valueCount": 1,
  "datum": {
    "kind": "integer",
    "value": "2"
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "bindingGroups": "distinct-nested-scopes"
}
Product invocation

Expected result

Each x belongs to a separate nested scope and the rule returns the exact integer 2. Product invocation awaits its 2.0 adapter.

The expected meaning is authored for Lispex 2.0. Product execution remains not-run.

See Resource model numbers.

2.12 Read the complete module before normalization

For one module, preparation decodes UTF-8 before reading syntax. Reading completes before normalization starts. A reader failure takes precedence over a normalization failure in that module. Normalization checks source forms in their written order.

Why

A fixed phase order makes the first failure reproducible. An earlier form with invalid meaning cannot hide a later reader failure in an unread part of the module.

Each module follows a fixed preparation order.

Finish reading before checking recursive bindings

lispex.example.v2.source.read-before-normalization-error · rev. 4

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
(define rule
  (lambda (input)
    (letrec ((x 1)) x)))
)
)
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient to prepare this source",
    "evaluate": "finite values sufficient for the stated finite calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Diagnosticsource.delimiter
Outcome details
{
  "kind": "prepare-failure",
  "stage": "reader",
  "valueCount": 0,
  "diagnostic": {
    "phase": "read",
    "code": "source.delimiter",
    "data": {
      "reason": "unexpected-close"
    }
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "entryEvaluated": false,
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false
}
Product invocation

Expected result

The trailing closing parenthesis causes the reader failure before normalization can reject the recursive binding. Product invocation awaits its 2.0 adapter.

The first form is readable but its letrec initializer is not a lambda. The later reader failure takes precedence. The diagnostic catalog gives this failure its phase, code, and typed reason.

Check recursive forms in source order

lispex.example.v2.source.normalization-source-order · rev. 4

source.scm
(module main
  (import)
  (export rule)
  (entry rule)
(define rule
  (lambda (input)
    (begin
      (letrec ((x 1)) x)
      (letrec ((y 2)) y))))
)
Request and files
request.json
{
  "notation": "documentation-request",
  "source": "source.scm",
  "semantics": {
    "language": "Lispex 2.0",
    "standardLibrary": "one fixed library identity",
    "unicode": "one fixed Unicode semantics version",
    "resourceModel": "one fixed finite resource model"
  },
  "limits": {
    "prepare": "finite values sufficient to prepare this source",
    "evaluate": "finite values sufficient for the stated finite calculation"
  },
  "requests": [
    {
      "input": {
        "kind": "integer",
        "value": "0"
      }
    }
  ],
  "rootModule": "main",
  "moduleSources": [
    {
      "name": "main",
      "source": "source.scm"
    }
  ]
}
Specification outcome
Diagnosticbinding.initializer
Outcome details
{
  "kind": "prepare-failure",
  "stage": "normalization",
  "valueCount": 0,
  "binding": "x",
  "diagnostic": {
    "phase": "normalize",
    "code": "binding.initializer",
    "data": {
      "form": "letrec",
      "name": "x",
      "expected": "lambda"
    }
  }
}

Specification outcome. Product runs are pending the 2.0 adapter.

Semantic details
{
  "entryEvaluated": false,
  "canonicalOutcomeProduced": false,
  "evaluationReceiptEligible": false
}
Product invocation

Expected result

Normalization rejects the initializer of x before it reaches the initializer of y. Product invocation awaits its 2.0 adapter.

Both forms violate the lambda requirement. The first form determines this failure. Finite preparation limits are sufficient to reach the stated checks.

Related chapters

Values and text

Evaluation and bindings

Preparation and modules

Identity, receipt, replay