Repository: alecthomas/chroma
Pull request #466 (2021-04-07 05:18:52)

Add a Dylan lexer
Add a [Dylan](https://opendylan.org) lexer.  An example result can be seen [here](https://play.opendylan.org/static/highlight-native.html).  (Or replace "native" in the URL with one of the other theme names.)

All tests pass, running with `go test ./...` in the top-level chroma directory. (I am not an expert at the Go command line; normally using Go with Bazel.)




Patch:
diff --git a/README.md b/README.md
index 21b21c7..c617130 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@ Prefix | Language
 A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Angular2, ANTLR, ApacheConf, APL, AppleScript, Arduino, Awk
 B | Ballerina, Base Makefile, Bash, Batchfile, BibTeX, BlitzBasic, BNF, Brainfuck
 C | C, C#, C++, Caddyfile, Caddyfile Directives, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Crystal, CSS, Cython
-D | D, Dart, Diff, Django/Jinja, Docker, DTD
+D | D, Dart, Diff, Django/Jinja, Docker, DTD, Dylan
 E | EBNF, Elixir, Elm, EmacsLisp, Erlang
 F | Factor, Fish, Forth, Fortran, FSharp
 G | GAS, GDScript, Genshi, Genshi HTML, Genshi Text, Gherkin, GLSL, Gnuplot, Go, Go HTML Template, Go Text Template, GraphQL, Groovy
diff --git a/lexers/d/dylan.go b/lexers/d/dylan.go
new file mode 100644
index 0000000..0e51f45
--- /dev/null
+++ b/lexers/d/dylan.go
@@ -0,0 +1,74 @@
+package d
+
+import (
+	. "github.com/alecthomas/chroma" // nolint
+	"github.com/alecthomas/chroma/lexers/internal"
+)
+
+// Dylan lexer.
+var Dylan = internal.Register(MustNewLexer(
+	&Config{
+		Name:            "Dylan",
+		Aliases:         []string{"dylan"},
+		Filenames:       []string{"*.dylan", "*.dyl", "*.intr"},
+		MimeTypes:       []string{"text/x-dylan"},
+		CaseInsensitive: true,
+	},
+	Rules{
+		"root": {
+			{`\s+`, Whitespace, nil},
+			{`//.*?\n`, CommentSingle, nil},
+			{`([a-z0-9-]+:)([ \t]*)(.*(?:\n[ \t].+)*)`, ByGroups(NameAttribute, Whitespace, LiteralString), nil},
+			Default(Push("code")),
+		},
+		"code": {
+			{`\s+`, Whitespace, nil},
+			{`//.*?\n`, CommentSingle, nil},
+			{`/\*`, CommentMultiline, Push("comment")},
+			{`"`, LiteralString, Push("string")},
+			{`'(\\.|\\[0-7]{1,3}|\\x[a-f0-9]{1,2}|[^\\\'\n])'`, LiteralStringChar, nil},
+			{`#b[01]+`, LiteralNumberBin, nil},
+			{`#o[0-7]+`, LiteralNumberOct, nil},
+			{`[-+]?(\d*\.\d+([ed][-+]?\d+)?|\d+(\.\d*)?e[-+]?\d+)`, LiteralNumberFloat, nil},
+			{`[-+]?\d+`, LiteralNumberInteger, nil},
+			{`#x[0-9a-f]+`, LiteralNumberHex, nil},
+
+			{`(\?\\?)([\w!&*<>|^$%@+~?/=-]+)(:)(token|name|variable|expression|body|case-body|\*)`,
+				ByGroups(Operator, NameVariable, Operator, NameBuiltin), nil},
+			{`(\?)(:)(token|name|variable|expression|body|case-body|\*)`,
+				ByGroups(Operator, Operator, NameVariable), nil},
+			{`(\?\\?)([\w!&*<>|^$%@+~?/=-]+)`, ByGroups(Operator, NameVariable), nil},
+
+			{`(=>|::|#\(|#\[|##|\?\?|\?=|\?|[(){}\[\],.;])`, Punctuation, nil},
+			{`:=`, Operator, nil},
+			{`#[tf]`, Literal, nil},
+			{`#"`, LiteralStringSymbol, Push("symbol")},
+			{`#[a-z0-9-]+`, Keyword, nil},
+			{`#(all-keys|include|key|next|rest)`, Keyword, nil},
+			{`[\w!&*<>|^$%@+~?/=-]+:`, KeywordConstant, nil},
+			{`<[\w!&*<>|^$%@+~?/=-]+>`, NameClass, nil},
+			{`\*[\w!&*<>|^$%@+~?/=-]+\*`, NameVariableGlobal, nil},
+			{`\$[\w!&*<>|^$%@+~?/=-]+`, NameConstant, nil},
+			{`(let|method|function)([ \t]+)([\w!&*<>|^$%@+~?/=-]+)`, ByGroups(NameBuiltin, Whitespace, NameVariable), nil},
+			{`(error|signal|return|break)`, NameException, nil},
+			{`(\\?)([\w!&*<>|^$%@+~?/=-]+)`, ByGroups(Operator, Name), nil},
+		},
+		"comment": {
+			{`[^*/]`, CommentMultiline, nil},
+			{`/\*`, CommentMultiline, Push()},
+			{`\*/`, CommentMultiline, Pop(1)},
+			{`[*/]`, CommentMultiline, nil},
+		},
+		"symbol": {
+			{`"`, LiteralStringSymbol, Pop(1)},
+			{`[^\\"]+`, LiteralStringSymbol, nil},
+		},
+		"string": {
+			{`"`, LiteralString, Pop(1)},
+			{`\\([\\abfnrtv"\']|x[a-f0-9]{2,4}|[0-7]{1,3})`, LiteralStringEscape, nil},
+			{`[^\\"\n]+`, LiteralString, nil},
+			{`\\\n`, LiteralString, nil},
+			{`\\`, LiteralString, nil},
+		},
+	},
+))


Test patch:
diff --git a/lexers/testdata/dylan.actual b/lexers/testdata/dylan.actual
new file mode 100644
index 0000000..7c075f1
--- /dev/null
+++ b/lexers/testdata/dylan.actual
@@ -0,0 +1,20 @@
+Module: mod
+
+define constant $pi = 3.1415927d0;
+
+define macro moo
+  { moo(?:name, ?e:expression) } => { let ?name = ?e; }
+end;
+
+// abc
+define method foo-bar (n :: <integer>, #rest a, #key k, #all-keys) => (m :: <float>, b :: <boolean>)
+  let x = n + 2.0 + #b10 + #o2 + #x02;
+  format-out("dog // cat\n");
+  local method pi () $pi end;
+  pi()
+end method foo-bar;
+
+/*
+ cow
+ */
+foo-bar(2, k: k, a-b: c);
diff --git a/lexers/testdata/dylan.expected b/lexers/testdata/dylan.expected
new file mode 100644
index 0000000..e5e27da
--- /dev/null
+++ b/lexers/testdata/dylan.expected
@@ -0,0 +1,175 @@
+[
+  {"type":"NameAttribute","value":"Module:"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralString","value":"mod"},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"Name","value":"define"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"constant"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameConstant","value":"$pi"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"="},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumberFloat","value":"3.1415927d0"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"Name","value":"define"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"macro"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"moo"},
+  {"type":"TextWhitespace","value":"\n  "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"moo"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Operator","value":"?:"},
+  {"type":"NameVariable","value":"name"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Operator","value":"?"},
+  {"type":"NameVariable","value":"e"},
+  {"type":"Operator","value":":"},
+  {"type":"NameBuiltin","value":"expression"},
+  {"type":"Punctuation","value":")"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"=\u003e"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameBuiltin","value":"let"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameVariable","value":"?name"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"="},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Operator","value":"?"},
+  {"type":"NameVariable","value":"e"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Name","value":"end"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"CommentSingle","value":"// abc\n"},
+  {"type":"Name","value":"define"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameBuiltin","value":"method"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameVariable","value":"foo-bar"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"n"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"::"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"\u003cinteger\u003e"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Keyword","value":"#rest"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"a"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Keyword","value":"#key"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"k"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Keyword","value":"#all-keys"},
+  {"type":"Punctuation","value":")"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"=\u003e"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"m"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"::"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"\u003cfloat\u003e"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"b"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"::"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"\u003cboolean\u003e"},
+  {"type":"Punctuation","value":")"},
+  {"type":"TextWhitespace","value":"\n  "},
+  {"type":"NameBuiltin","value":"let"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameVariable","value":"x"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"="},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"n"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"+"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumberFloat","value":"2.0"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"+"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumberBin","value":"#b10"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"+"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumberOct","value":"#o2"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"+"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumberHex","value":"#x02"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n  "},
+  {"type":"Name","value":"format-out"},
+  {"type":"Punctuation","value":"("},
+  {"type":"LiteralString","value":"\"dog // cat"},
+  {"type":"LiteralStringEscape","value":"\\n"},
+  {"type":"LiteralString","value":"\""},
+  {"type":"Punctuation","value":");"},
+  {"type":"TextWhitespace","value":"\n  "},
+  {"type":"Name","value":"local"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameBuiltin","value":"method"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameVariable","value":"pi"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"()"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameConstant","value":"$pi"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"end"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n  "},
+  {"type":"Name","value":"pi"},
+  {"type":"Punctuation","value":"()"},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Name","value":"end"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameBuiltin","value":"method"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameVariable","value":"foo-bar"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"CommentMultiline","value":"/*\n cow\n */"},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Name","value":"foo-bar"},
+  {"type":"Punctuation","value":"("},
+  {"type":"LiteralNumberInteger","value":"2"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"KeywordConstant","value":"k:"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"k"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"KeywordConstant","value":"a-b:"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"c"},
+  {"type":"Punctuation","value":");"},
+  {"type":"TextWhitespace","value":"\n"}
+]