Repository: alecthomas/chroma
Pull request #995 (2024-08-27 14:49:19)

add beef syntax and tests
This adds #994 Beeflang.
The  syntax itself is just a modifed version of c# with a few keywords added or removed.
Also Ive added a test and run the test until it worked.

I am unsure if the mime_type is relevant to keep in there since I dont know where that actually used.
Another thing im unsure of is how the selection of what language/syntax to use for a file actually works aka:
Does this actually choose Beef syntax highlighting over Brainfuck if its used on a beef (.bf) file ?
for that I would probably need help.


Patch:
diff --git a/lexers/embedded/beef.xml b/lexers/embedded/beef.xml
new file mode 100644
index 0000000..031a220
--- /dev/null
+++ b/lexers/embedded/beef.xml
@@ -0,0 +1,120 @@
+<lexer>
+  <config>
+    <name>Beef</name>
+    <alias>beef</alias>
+    <filename>*.bf</filename>
+    <mime_type>text/x-beef</mime_type>
+    <dot_all>true</dot_all>
+    <ensure_nl>true</ensure_nl>
+  </config>
+  <rules>
+    <state name="root">
+      <rule pattern="^\s*\[.*?\]">
+        <token type="NameAttribute"/>
+      </rule>
+      <rule pattern="[^\S\n]+">
+        <token type="Text"/>
+      </rule>
+      <rule pattern="\\\n">
+        <token type="Text"/>
+      </rule>
+      <rule pattern="///[^\n\r]*">
+        <token type="CommentSpecial"/>
+      </rule>
+      <rule pattern="//[^\n\r]*">
+        <token type="CommentSingle"/>
+      </rule>
+      <rule pattern="/[*].*?[*]/">
+        <token type="CommentMultiline"/>
+      </rule>
+      <rule pattern="\n">
+        <token type="Text"/>
+      </rule>
+      <rule pattern="[~!%^&amp;*()+=|\[\]:;,.&lt;&gt;/?-]">
+        <token type="Punctuation"/>
+      </rule>
+      <rule pattern="[{}]">
+        <token type="Punctuation"/>
+      </rule>
+      <rule pattern="@&#34;(&#34;&#34;|[^&#34;])*&#34;">
+        <token type="LiteralString"/>
+      </rule>
+      <rule pattern="\$@?&#34;(&#34;&#34;|[^&#34;])*&#34;">
+        <token type="LiteralString"/>
+      </rule>
+      <rule pattern="&#34;(\\\\|\\&#34;|[^&#34;\n])*[&#34;\n]">
+        <token type="LiteralString"/>
+      </rule>
+      <rule pattern="&#39;\\.&#39;|&#39;[^\\]&#39;">
+        <token type="LiteralStringChar"/>
+      </rule>
+      <rule pattern="0[xX][0-9a-fA-F]+[Ll]?|\d[_\d]*(\.\d*)?([eE][+-]?\d+)?[flFLdD]?">
+        <token type="LiteralNumber"/>
+      </rule>
+      <rule pattern="#[ \t]*(if|endif|else|elif|define|undef|line|error|warning|region|endregion|pragma|nullable)\b">
+        <token type="CommentPreproc"/>
+      </rule>
+      <rule pattern="\b(extern)(\s+)(alias)\b">
+        <bygroups>
+          <token type="Keyword"/>
+          <token type="Text"/>
+          <token type="Keyword"/>
+        </bygroups>
+      </rule>
+      <rule pattern="(as|await|base|break|by|case|catch|checked|continue|default|delegate|else|event|finally|fixed|for|repeat|goto|if|in|init|is|let|lock|new|scope|on|out|params|readonly|ref|return|sizeof|stackalloc|switch|this|throw|try|typeof|unchecked|virtual|void|while|get|set|new|yield|add|remove|value|alias|ascending|descending|from|group|into|orderby|select|thenby|where|join|equals)\b">
+        <token type="Keyword"/>
+      </rule>
+      <rule pattern="(global)(::)">
+        <bygroups>
+          <token type="Keyword"/>
+          <token type="Punctuation"/>
+        </bygroups>
+      </rule>
+      <rule pattern="(abstract|async|const|enum|explicit|extern|implicit|internal|operator|override|partial|extension|private|protected|public|static|sealed|unsafe|volatile)\b">
+        <token type="KeywordDeclaration"/>
+      </rule>
+      <rule pattern="(bool|byte|char8|char16|char32|decimal|double|float|int|int8|int16|int32|int64|long|object|sbyte|short|string|uint|uint8|uint16|uint32|uint64|uint|let|var)\b\??">
+        <token type="KeywordType"/>
+      </rule>
+      <rule pattern="(true|false|null)\b">
+        <token type="KeywordConstant"/>
+      </rule>
+      <rule pattern="(class|struct|record|interface)(\s+)">
+        <bygroups>
+          <token type="Keyword"/>
+          <token type="Text"/>
+        </bygroups>
+        <push state="class"/>
+      </rule>
+      <rule pattern="(namespace|using)(\s+)">
+        <bygroups>
+          <token type="Keyword"/>
+          <token type="Text"/>
+        </bygroups>
+        <push state="namespace"/>
+      </rule>
+      <rule pattern="@?[_a-zA-Z]\w*">
+        <token type="Name"/>
+      </rule>
+    </state>
+    <state name="class">
+      <rule pattern="@?[_a-zA-Z]\w*">
+        <token type="NameClass"/>
+        <pop depth="1"/>
+      </rule>
+      <rule>
+        <pop depth="1"/>
+      </rule>
+    </state>
+    <state name="namespace">
+      <rule pattern="(?=\()">
+        <token type="Text"/>
+        <pop depth="1"/>
+      </rule>
+      <rule pattern="(@?[_a-zA-Z]\w*|\.)+">
+        <token type="NameNamespace"/>
+        <pop depth="1"/>
+      </rule>
+    </state>
+  </rules>
+</lexer>
\ No newline at end of file


Test patch:
diff --git a/lexers/testdata/beef.actual b/lexers/testdata/beef.actual
new file mode 100644
index 0000000..1b02c9d
--- /dev/null
+++ b/lexers/testdata/beef.actual
@@ -0,0 +1,22 @@
+using System;
+
+class Program
+{
+    public static void Main()
+    {
+        Console.WriteLine("Hello, World!");
+    }
+
+    // Try! propagates file and parsing errors down the call stack
+    static Result<void> Parse(StringView filePath, List<float> outValues)
+    {
+        var fs = scope FileStream();
+        Try!(fs.Open(filePath));
+        for (var lineResult in scope StreamReader(fs).Lines)
+        {
+            for (let elem in Try!(lineResult).Split(','))
+                outValues.Add(Try!(float.Parse(elem)));
+        }
+        return .Ok;
+    }
+}
\ No newline at end of file
diff --git a/lexers/testdata/beef.expected b/lexers/testdata/beef.expected
new file mode 100644
index 0000000..2171f8d
--- /dev/null
+++ b/lexers/testdata/beef.expected
@@ -0,0 +1,141 @@
+[
+  {"type":"Keyword","value":"using"},
+  {"type":"Text","value":" "},
+  {"type":"NameNamespace","value":"System"},
+  {"type":"Punctuation","value":";"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"class"},
+  {"type":"Text","value":" "},
+  {"type":"NameClass","value":"Program"},
+  {"type":"Text","value":"\n"},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Text","value":"\n    "},
+  {"type":"KeywordDeclaration","value":"public"},
+  {"type":"Text","value":" "},
+  {"type":"KeywordDeclaration","value":"static"},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"void"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Main"},
+  {"type":"Punctuation","value":"()"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Text","value":"\n        "},
+  {"type":"Name","value":"Console"},
+  {"type":"Punctuation","value":"."},
+  {"type":"Name","value":"WriteLine"},
+  {"type":"Punctuation","value":"("},
+  {"type":"LiteralString","value":"\"Hello, World!\""},
+  {"type":"Punctuation","value":");"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n\n    "},
+  {"type":"CommentSingle","value":"// Try! propagates file and parsing errors down the call stack"},
+  {"type":"Text","value":"\n    "},
+  {"type":"KeywordDeclaration","value":"static"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Result"},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"Keyword","value":"void"},
+  {"type":"Punctuation","value":"\u003e"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Parse"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"StringView"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"filePath"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"List"},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"KeywordType","value":"float"},
+  {"type":"Punctuation","value":"\u003e"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"outValues"},
+  {"type":"Punctuation","value":")"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Text","value":"\n        "},
+  {"type":"KeywordType","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"fs"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"scope"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"FileStream"},
+  {"type":"Punctuation","value":"();"},
+  {"type":"Text","value":"\n        "},
+  {"type":"Name","value":"Try"},
+  {"type":"Punctuation","value":"!("},
+  {"type":"Name","value":"fs"},
+  {"type":"Punctuation","value":"."},
+  {"type":"Name","value":"Open"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"filePath"},
+  {"type":"Punctuation","value":"));"},
+  {"type":"Text","value":"\n        "},
+  {"type":"Keyword","value":"for"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"("},
+  {"type":"KeywordType","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"lineResult"},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"in"},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"scope"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"StreamReader"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"fs"},
+  {"type":"Punctuation","value":")."},
+  {"type":"Name","value":"Lines"},
+  {"type":"Punctuation","value":")"},
+  {"type":"Text","value":"\n        "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Text","value":"\n            "},
+  {"type":"Keyword","value":"for"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"("},
+  {"type":"Keyword","value":"let"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"elem"},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"in"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Try"},
+  {"type":"Punctuation","value":"!("},
+  {"type":"Name","value":"lineResult"},
+  {"type":"Punctuation","value":")."},
+  {"type":"Name","value":"Split"},
+  {"type":"Punctuation","value":"("},
+  {"type":"LiteralStringChar","value":"','"},
+  {"type":"Punctuation","value":"))"},
+  {"type":"Text","value":"\n                "},
+  {"type":"Name","value":"outValues"},
+  {"type":"Punctuation","value":"."},
+  {"type":"Name","value":"Add"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"Try"},
+  {"type":"Punctuation","value":"!("},
+  {"type":"KeywordType","value":"float"},
+  {"type":"Punctuation","value":"."},
+  {"type":"Name","value":"Parse"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"elem"},
+  {"type":"Punctuation","value":")));"},
+  {"type":"Text","value":"\n        "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n        "},
+  {"type":"Keyword","value":"return"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"."},
+  {"type":"Name","value":"Ok"},
+  {"type":"Punctuation","value":";"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n"},
+  {"type":"Punctuation","value":"}"}
+]