Add bat syntax for WAFER / Forth 2012
Ship tools/editor-support/bat/WAFER.sublime-syntax so any bat user (including oked, which probes bat first) renders .fth files with proper keyword colouring, including the WAFER extras CONSOLIDATE, RANDOM, RND-SEED, and UTIME. Keyword list derives from register_primitive/register_host_primitive calls in crates/core/src/outer.rs plus the boot.fth definitions. Internal underscore-prefixed words are deliberately omitted. Install with `just install-syntax`.
This commit is contained in:
@@ -57,3 +57,9 @@ ci: fmt clippy deny test
|
||||
# Check compilation without running
|
||||
check:
|
||||
cargo check --workspace
|
||||
|
||||
# Install bat syntax highlighting for WAFER / Forth
|
||||
install-syntax:
|
||||
mkdir -p ~/.config/bat/syntaxes
|
||||
cp tools/editor-support/bat/WAFER.sublime-syntax ~/.config/bat/syntaxes/
|
||||
bat cache --build
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# Editor support for WAFER
|
||||
|
||||
Syntax highlighting assets for editors and pagers.
|
||||
|
||||
## bat (and other Sublime-Text-compatible tools)
|
||||
|
||||
`bat/WAFER.sublime-syntax` is a Sublime Text grammar covering Forth 2012 plus
|
||||
WAFER-specific words (`CONSOLIDATE`, `RANDOM`, `RND-SEED`, `UTIME`).
|
||||
|
||||
### Install
|
||||
|
||||
```
|
||||
just install-syntax
|
||||
```
|
||||
|
||||
or manually:
|
||||
|
||||
```
|
||||
mkdir -p ~/.config/bat/syntaxes
|
||||
cp tools/editor-support/bat/WAFER.sublime-syntax ~/.config/bat/syntaxes/
|
||||
bat cache --build
|
||||
```
|
||||
|
||||
### Verify
|
||||
|
||||
```
|
||||
bat --list-languages | grep -i forth # should list Forth
|
||||
bat --language forth crates/core/boot.fth # should render with colour
|
||||
```
|
||||
|
||||
### Use with `oked`
|
||||
|
||||
`oked` auto-detects `.fth` / `.4th` / `.forth` files and invokes `bat` with
|
||||
`--language forth`. After the install step above, opening any WAFER source in
|
||||
`oked` and toggling highlight (`H` command, or `oked -S forth`) will use this
|
||||
syntax.
|
||||
|
||||
### Updating the keyword list
|
||||
|
||||
Primitives live in `crates/core/src/outer.rs` (`register_primitive` and
|
||||
`register_host_primitive` calls). When a new **user-facing, non-standard** word
|
||||
is added, append it to the `wafer_extras` context in
|
||||
`bat/WAFER.sublime-syntax`. Standard Forth 2012 words are already covered by
|
||||
the main contexts.
|
||||
|
||||
Internal symbols (names that start with `_`) should not be added — they are
|
||||
implementation details that user code never types.
|
||||
@@ -0,0 +1,155 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# WAFER / Forth 2012 syntax for `bat` (and any Sublime Text compatible highlighter).
|
||||
#
|
||||
# Keyword list is derived from the primitives registered in
|
||||
# crates/core/src/outer.rs plus the Forth 2012 core-ext wordset and the boot.fth
|
||||
# definitions in crates/core/boot.fth. WAFER-specific additions are tagged below.
|
||||
#
|
||||
# Install: see tools/editor-support/README.md.
|
||||
name: Forth
|
||||
file_extensions:
|
||||
- fth
|
||||
- 4th
|
||||
- forth
|
||||
scope: source.forth
|
||||
|
||||
variables:
|
||||
ident_break: '(?=\s|$)'
|
||||
|
||||
contexts:
|
||||
main:
|
||||
- include: comments
|
||||
- include: strings
|
||||
- include: numbers
|
||||
- include: definitions
|
||||
- include: control
|
||||
- include: stack_ops
|
||||
- include: return_stack
|
||||
- include: arithmetic
|
||||
- include: logic
|
||||
- include: compare
|
||||
- include: memory
|
||||
- include: io
|
||||
- include: float
|
||||
- include: dictionary
|
||||
- include: exception
|
||||
- include: parsing
|
||||
- include: literals
|
||||
- include: wafer_extras
|
||||
|
||||
comments:
|
||||
# Line comment: backslash to end of line, must be followed by whitespace or EOL.
|
||||
- match: '(?i)(?:^|(?<=\s))\\(?=\s|$).*$'
|
||||
scope: comment.line.backslash.forth
|
||||
# Stack-effect / block comment: ( ... ) — the `(` must be followed by whitespace.
|
||||
- match: '(?i)(?:^|(?<=\s))\((?=\s|$)'
|
||||
scope: punctuation.definition.comment.forth
|
||||
push:
|
||||
- meta_scope: comment.block.paren.forth
|
||||
- match: '\)'
|
||||
scope: punctuation.definition.comment.forth
|
||||
pop: true
|
||||
# Immediate print comment: .( ... )
|
||||
- match: '(?i)(?:^|(?<=\s))\.\((?=\s|$)'
|
||||
scope: punctuation.definition.comment.forth
|
||||
push:
|
||||
- meta_scope: comment.block.dot-paren.forth
|
||||
- match: '\)'
|
||||
scope: punctuation.definition.comment.forth
|
||||
pop: true
|
||||
|
||||
strings:
|
||||
# Standard Forth strings: leading word followed by space then body, closed with ".
|
||||
- match: '(?i)(?:^|(?<=\s))(S\\"|S"|C"|\."|ABORT")(\s)'
|
||||
captures:
|
||||
1: keyword.other.string-prefix.forth
|
||||
push:
|
||||
- meta_scope: string.quoted.double.forth
|
||||
- match: '"'
|
||||
pop: true
|
||||
|
||||
numbers:
|
||||
# Hex / binary / decimal / char literals / negatives; all whitespace-delimited.
|
||||
- match: '(?i)(?:^|(?<=\s))\$[0-9A-F]+{{ident_break}}'
|
||||
scope: constant.numeric.hex.forth
|
||||
- match: '(?i)(?:^|(?<=\s))#-?[0-9]+{{ident_break}}'
|
||||
scope: constant.numeric.decimal.forth
|
||||
- match: '(?i)(?:^|(?<=\s))%[01]+{{ident_break}}'
|
||||
scope: constant.numeric.binary.forth
|
||||
- match: "(?i)(?:^|(?<=\\s))'.'{{ident_break}}"
|
||||
scope: constant.character.forth
|
||||
- match: '(?i)(?:^|(?<=\s))-?[0-9]+(?:\.[0-9]*)?(?:[eE]-?[0-9]+)?{{ident_break}}'
|
||||
scope: constant.numeric.forth
|
||||
|
||||
definitions:
|
||||
- match: '(?i)(?:^|(?<=\s))(:|:NONAME)(\s+)(\S+)?'
|
||||
captures:
|
||||
1: keyword.other.definition.forth
|
||||
3: entity.name.function.forth
|
||||
- match: '(?i)(?:^|(?<=\s));{{ident_break}}'
|
||||
scope: keyword.other.definition.forth
|
||||
- match: '(?i)(?:^|(?<=\s))(VARIABLE|2VARIABLE|CONSTANT|2CONSTANT|VALUE|CREATE|DEFER|MARKER|BUFFER:|FCONSTANT|FVARIABLE)(\s+)(\S+)?'
|
||||
captures:
|
||||
1: keyword.other.defining.forth
|
||||
3: entity.name.constant.forth
|
||||
- match: '(?i)(?:^|(?<=\s))(DOES>|IMMEDIATE|RECURSE|POSTPONE|COMPILE,|LITERAL|2LITERAL|FLITERAL|SLITERAL){{ident_break}}'
|
||||
scope: keyword.other.defining.forth
|
||||
|
||||
control:
|
||||
- match: '(?i)(?:^|(?<=\s))(IF|THEN|ELSE|BEGIN|UNTIL|WHILE|REPEAT|AGAIN|DO|\?DO|LOOP|\+LOOP|LEAVE|UNLOOP|EXIT|CASE|OF|ENDOF|ENDCASE|QUIT){{ident_break}}'
|
||||
scope: keyword.control.forth
|
||||
|
||||
stack_ops:
|
||||
- match: '(?i)(?:^|(?<=\s))(DUP|\?DUP|DROP|SWAP|OVER|ROT|-ROT|NIP|TUCK|PICK|ROLL|2DUP|2DROP|2SWAP|2OVER|2ROT|DEPTH|SP@){{ident_break}}'
|
||||
scope: support.function.stack.forth
|
||||
|
||||
return_stack:
|
||||
- match: '(?i)(?:^|(?<=\s))(>R|R>|R@|2>R|2R>|2R@|N>R|NR>|I|J|CS-PICK|CS-ROLL){{ident_break}}'
|
||||
scope: support.function.return-stack.forth
|
||||
|
||||
arithmetic:
|
||||
- match: '(?i)(?:^|(?<=\s))(\+|-|\*|/|MOD|/MOD|\*/|\*/MOD|NEGATE|ABS|MIN|MAX|1\+|1-|2\*|2/|M\*|M\+|M\*/|UM\*|UM/MOD|FM/MOD|SM/REM|S>D|D>S){{ident_break}}'
|
||||
scope: keyword.operator.arithmetic.forth
|
||||
|
||||
logic:
|
||||
- match: '(?i)(?:^|(?<=\s))(AND|OR|XOR|INVERT|LSHIFT|RSHIFT){{ident_break}}'
|
||||
scope: keyword.operator.logical.forth
|
||||
|
||||
compare:
|
||||
- match: '(?i)(?:^|(?<=\s))(=|<>|<|>|<=|>=|U<|U>|0=|0<>|0<|0>){{ident_break}}'
|
||||
scope: keyword.operator.comparison.forth
|
||||
|
||||
memory:
|
||||
- match: '(?i)(?:^|(?<=\s))(@|!|C@|C!|\+!|2@|2!|ALLOT|HERE|ALIGN|ALIGNED|CELL\+|CELLS|CHAR\+|CHARS|UNUSED|MOVE|CMOVE|CMOVE>|FILL|ERASE|BLANK|ALLOCATE|FREE|RESIZE|PAD){{ident_break}}'
|
||||
scope: support.function.memory.forth
|
||||
|
||||
io:
|
||||
- match: '(?i)(?:^|(?<=\s))(EMIT|CR|SPACE|SPACES|TYPE|\.|U\.|\.R|U\.R|D\.|D\.R|\?|KEY|KEY\?|PAGE|AT-XY|ACCEPT|EXPECT|\.S){{ident_break}}'
|
||||
scope: support.function.io.forth
|
||||
|
||||
float:
|
||||
- match: '(?i)(?:^|(?<=\s))(F\+|F-|F\*|F/|FNEGATE|FABS|FMAX|FMIN|FSQRT|FFLOOR|FROUND|FSINCOS|F=|F<|F0=|F0<|F~|FDUP|FDROP|FSWAP|FOVER|FROT|FNIP|FTUCK|FDEPTH|F@|F!|FE\.|FS\.|F\.|F>D|D>F|F>S|S>F|>FLOAT|REPRESENT|PRECISION|SET-PRECISION|FALIGNED|DFALIGNED|SFALIGNED|DF@|DF!|SF@|SF!){{ident_break}}'
|
||||
scope: support.function.float.forth
|
||||
|
||||
dictionary:
|
||||
- match: "(?i)(?:^|(?<=\\s))('|\\[']|,|>BODY|FIND|WORDS|ONLY|ALSO|PREVIOUS|DEFINITIONS|FORTH|GET-ORDER|SET-ORDER|GET-CURRENT|SET-CURRENT|WORDLIST|SEARCH-WORDLIST|FORTH-WORDLIST|ENVIRONMENT\\?|EXECUTE){{ident_break}}"
|
||||
scope: support.function.dictionary.forth
|
||||
|
||||
exception:
|
||||
- match: '(?i)(?:^|(?<=\s))(CATCH|THROW|ABORT){{ident_break}}'
|
||||
scope: keyword.control.exception.forth
|
||||
|
||||
parsing:
|
||||
- match: '(?i)(?:^|(?<=\s))(PARSE|PARSE-NAME|WORD|REFILL|EVALUATE|SOURCE|SOURCE-ID|>IN|BASE|STATE|>NUMBER|SEARCH|SUBSTITUTE|UNESCAPE|REPLACES){{ident_break}}'
|
||||
scope: support.function.parsing.forth
|
||||
|
||||
literals:
|
||||
- match: '(?i)(?:^|(?<=\s))(TRUE|FALSE|BL|CHAR|\[CHAR\]|\[COMPILE\]){{ident_break}}'
|
||||
scope: constant.language.forth
|
||||
|
||||
wafer_extras:
|
||||
# WAFER-specific extensions beyond the Forth 2012 standard.
|
||||
# When the language grows new user-facing non-standard words, add them here.
|
||||
- match: '(?i)(?:^|(?<=\s))(CONSOLIDATE|RANDOM|RND-SEED|UTIME){{ident_break}}'
|
||||
scope: support.function.wafer-extra.forth
|
||||
Reference in New Issue
Block a user