@codincod/codemirror-lang-chef
v0.3.0
Published
Chef language support for the CodeMirror code editor
Maintainers
Readme
@codincod/codemirror-lang-chef
This package implements Chef language support for the CodeMirror code editor: a Lezer grammar, highlighting and folding.
Written in part for CodinCod, a competitive coding platform, where it colours the editor people solve puzzles in.
This code is released under an MIT license.
Usage
import {EditorView, basicSetup} from "codemirror"
import {chef} from "@codincod/codemirror-lang-chef"
const view = new EditorView({
parent: document.body,
doc: `Hello World Souffle.
This recipe prints hello world.
Ingredients.
72 g haricot beans
101 eggs
108 g lard
Method.
Put lard into mixing bowl.
Put haricot beans into mixing bowl.
Liquefy contents of the mixing bowl.
Pour contents of the mixing bowl into the baking dish.
Serves 1.
`,
extensions: [basicSetup, chef()]
})What it reads
Chef is a joke with a compiler behind it: a program is a recipe, and it has to read as one. A title, a paragraph about the dish, a list of ingredients, and a method in ordinary imperative English. The ingredients are the variables and the mixing bowls are the stack.
The shape is what makes it parseable. Ingredients. and Method. are lines
that say exactly that, so everything above the first of them is the title and
the prose under it.
On CodinCod's language-guessing pool, 11 snippets of Chef from Rosetta Code:
| | Tagged | Colours | Busiest colour | | --- | --: | --: | --: | | this | 100.00% | 9 | 24.01% | | plain text, which is what it had | 0.00% | 0 | – |
Every character gets a colour. A bare word inside a sentence of the method is
how an ingredient is referred to again, so it is a name in both places and
takes a name's ink in both; a directive like Cooking time: 45 minutes. is
addressed to the cook and to nobody else, so all of it but the opening word is
grey.
Unlike the grid languages, this grammar can say no: a file that is not a
recipe has no Ingredients. in it and comes out as an error, which is what
the clean figure below is measuring.
Eleven files is too few to conclude anything from, so the recipes people have actually written were parsed too, ten of them from joostrijneveld's interpreter. Doing that was worth it. Six of the ten failed on the first run, on two things neither the spec nor the pool shows:
- Half of them write
Methods.where the spec writesMethod., and every interpreter takes both. - A sentence that talks about two of them says
mixing bowls.
With those fixed, 20 of the 21 files across both sources parse clean, which
puts the true rate above 79% with 95% confidence and no higher claim than
that. The one failure is the pool snippet that opens This is pseudocode. and
then writes Methods. three times inside a method body to demonstrate what a
Chef comment looks like. It is not a program and no interpreter would run it.
What took the work
Three things the parser cannot work out for itself, all of them in
src/tokens.ts.
- A comment is a comment because of where it sits. Chef has no comment
marker at all. What is between the title and the word
Ingredientsis a paragraph about the dish, and that is the whole of it. Colouring it grey is most of what this grammar is for, and there is no character anywhere that says so. - A title looks exactly like the next sentence of the method above it. An
auxiliary recipe is a whole recipe, title and all, written under the first
one, so a line that opens a recipe and a line that continues a method are the
same shape. What tells them apart is what comes after: a title is followed,
further down, by
Ingredients., and a sentence in the middle of a method reaches the end of its recipe first. The tokenizer reads ahead to whichever ofIngredients.,Method.andServesturns up first and calls the line a title only when the answer is the first of them. - An ingredient's name is whatever is left of its line.
0 g Vitamin Aopens with a quantity and a measure,2 cups flourwith a different measure, andinputwith the name itself. No rule can say where a name starts, because a name is any words at all. So the tokenizer declines three times and consumes once: on a digit, so the quantity is read as a number; on a measure, so the measure is read as one; and on a section header, so a list ends whereMethod.begins.
What it does not claim
The loop. Chef opens one with any verb the author likes and closes it with any
other, and the only fixed word in either is until:
Loop the input.
…
Endloop input until looped.Sift the flour. and Shake until sifted. are the same pair with different
words in it. A grammar that guessed which sentences match would be wrong on a
recipe that writes two loops in a row, so a sentence keeps its verb and the
verb keeps a colour of its own, and the pairing is left to the reader, who can
see the words. It is the one thing here that looks like structure and is not.
Development
npm install
npm test # the parse specs and the colours