@codincod/codemirror-lang-wren
v0.1.0
Published
Wren language support for the CodeMirror code editor
Maintainers
Readme
@codincod/codemirror-lang-wren
This package implements Wren language support for the CodeMirror code editor: a Lezer grammar, highlighting, indentation, folding and completion for the core library.
It is a fork of Josh Goebel's @exercism/codemirror-lang-wren, which is the only Lezer grammar Wren has ever had. Its precedence table and the shape of its expression rules are kept; the rest is below.
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 {wren} from "@codincod/codemirror-lang-wren"
const view = new EditorView({
parent: document.body,
doc: `class Point {
construct new(x, y) {
_x = x
_y = y
}
x { _x }
y { _y }
+(other) { Point.new(_x + other.x, _y + other.y) }
toString { "(%(_x), %(_y))" }
}
var points = [Point.new(1, 2), Point.new(3, 4)]
System.print(points.reduce { |a, b| a + b })
`,
extensions: [basicSetup, wren()]
})What this fixes
The first reason for the fork is that upstream cannot be used: it is built for
CodeMirror 0.19 and lezer 0.13, so its LanguageSupport is not the one a
CodeMirror 6 editor recognises, and its parser is not one @lezer/lr can run.
Nothing in the editor throws; the language simply never arrives.
The second is the parse. Measured over 1020 files (3.06 MiB) of Wren's own test suite, the Wren CLI, wren-console and DOME, upstream's grammar reads 83.82% of them with no error node, leaving 883 error nodes. This package reads 100.00%, leaving none. The 159 files in that suite meant not to compile are skipped by both.
Four of the fixes are ordinary bugs.
- A range was two numbers. The number token ended at
1., so1..10lexed as1.and.10with an error node between them, andRangeOpnever appeared in a tree. A digit is now required after the point, which is what Wren requires too. - A class name had to be capitalised.
class foois legal Wren and did not parse. The case of a name says nothing where only a class can stand. staticandconstructcould be members of their own. A member was allowed to be a bare name, sostatic origin { }read as two members, the first of them calledstatic. Only a foreign method has no body, and it says so now.- A class could only inherit from a name. Wren reads an expression there and
rejects a non-class when it runs, which is why its own test suite holds
class Foo is null.
Three are syntax Wren has and upstream never had.
- Attributes:
#key,#key = value,#group(a, b = c)and the runtime#!form, on a class and on a method. - The subscript operators:
[index] { }and[index]=(value) { }, andisas a method name beside the other operators. - A shebang, which Wren skips and every script written for the CLI opens with.
And two are the language read more closely.
- A line break ends a statement. Wren spends no semicolons and upstream had
no statement separator at all, so
stepand a block under it read as one call taking a block rather than as two statements, and a getter followed by anything at all ran the two together. A zero-width token now ends a statement wherever a line break did, in the way@lezer/javascriptinserts a semicolon. The two places the answer runs the other way are handled too:returntakes a value only from the rest of its line, and so doesimport "io" for Stdin. A leading dot carries a call chain on, which Wren allows and its ownchained_newline.wrenspends twenty lines on. - Fields, classes and names are told apart.
_count,__count,Pointandcountall reach different nodes, so a theme can colour them differently. Strings are cut into their pieces rather than read a character at a time, and"""raw"""takes neither escapes nor holes, which is what makes it raw.
SequenceExpression and the object patterns are gone. Both were left over from
the JavaScript grammar this one started as, and Wren has no comma operator and
no destructuring.
Measuring it yourself
npm run corpus -- path/to/wren/filesNo corpus ships with the package, because none of that code is ours to redistribute. Point it at your own; it counts files with no error node and groups them by directory, so a project that drags the total down names itself.
