From b2a2ba5a5033453f0766ddbf80bdafd619e4762c Mon Sep 17 00:00:00 2001
From: cjprieb <cjprieb@gmail.com>
Date: Tue, 18 Oct 2022 17:57:56 -0500
Subject: [PATCH] added lexer for PSL (#688)

---
 README.md                    |   2 +-
 lexers/embedded/psl.xml      | 126 +++++++++
 lexers/testdata/psl.actual   |  13 +
 lexers/testdata/psl.expected | 478 +++++++++++++++++++++++++++++++++++
 4 files changed, 618 insertions(+), 1 deletion(-)
 create mode 100644 lexers/embedded/psl.xml
 create mode 100644 lexers/testdata/psl.actual
 create mode 100644 lexers/testdata/psl.expected

diff --git a/README.md b/README.md
index df7e0f1..9ddbcfe 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ L | Lighttpd configuration file, LLVM, Lua
 M | Mako, markdown, Mason, Mathematica, Matlab, MiniZinc, MLIR, Modula-2, MonkeyC, MorrowindScript, Myghty, MySQL
 N | NASM, Newspeak, Nginx configuration file, Nim, Nix
 O | Objective-C, OCaml, Octave, OnesEnterprise, OpenEdge ABL, OpenSCAD, Org Mode
-P | PacmanConf, Perl, PHP, PHTML, Pig, PkgConfig, PL/pgSQL, plaintext, Pony, PostgreSQL SQL dialect, PostScript, POVRay, PowerShell, Prolog, PromQL, Properties, Protocol Buffer, Puppet, Python 2, Python
+P | PacmanConf, Perl, PHP, PHTML, Pig, PkgConfig, PL/pgSQL, plaintext, Pony, PostgreSQL SQL dialect, PostScript, POVRay, PowerShell, Prolog, PromQL, Properties, Protocol Buffer, PSL, Puppet, Python 2, Python
 Q | QBasic
 R | R, Racket, Ragel, Raku, react, ReasonML, reg, reStructuredText, Rexx, Ruby, Rust
 S | SAS, Sass, Scala, Scheme, Scilab, SCSS, Sed, Smalltalk, Smarty, Snobol, Solidity, SPARQL, SQL, SquidConf, Standard ML, Stylus, Svelte, Swift, SYSTEMD, systemverilog
diff --git a/lexers/embedded/psl.xml b/lexers/embedded/psl.xml
new file mode 100644
index 0000000..93b24d2
--- /dev/null
+++ b/lexers/embedded/psl.xml
@@ -0,0 +1,126 @@
+<lexer>
+  <config>
+    <name>PSL</name>
+    <alias>psl</alias>
+    <filename>*.psl</filename>
+    <filename>*.BATCH</filename>
+    <filename>*.TRIG</filename>
+    <filename>*.PROC</filename>
+    <mime_type>text/x-psl</mime_type>
+  </config>
+  <rules>
+  <!-- NameFunction|TypeName -->
+    <state name="root">
+      <rule pattern="//.*$">
+        <token type="CommentSingle"/>
+      </rule>
+      <rule pattern="/(\\\n)?[*](.|\n)*?[*](\\\n)?/">
+        <token type="CommentMultiline"/>
+      </rule>
+      <rule pattern="\+|-|\*|/|%|'?&lt;|'?&gt;|'?=|\band\b|\bor\b|_|:">
+        <token type="Operator"/>
+      </rule>
+      <rule pattern="[{}(),\[\]]">
+        <token type="Punctuation"/>
+      </rule>
+      <rule pattern="[+-]?\d*\.\d+">
+        <token type="LiteralNumber"/>
+      </rule>
+      <rule pattern="&quot;">
+        <token type="LiteralString"/>
+        <push state="string"/>
+      </rule>
+      <rule pattern="\.">
+        <token type="Operator"/>
+        <push state="method"/>
+      </rule>
+      <rule pattern="\$\$">
+        <token type="NameFunction"/>
+        <push state="method"/>
+      </rule>
+      <rule pattern="\bdo\b">
+        <token type="KeywordReserved"/>
+        <push state="callmethod"/>
+      </rule>
+      <rule pattern="\b(do|set|if|for|while|quit|catch|return|while)\b">
+        <token type="Keyword"/>
+      </rule>
+      <rule pattern="\b(true|false)\b">
+        <token type="KeywordConstant"/>
+      </rule>
+      <rule pattern="\btype\b">
+        <token type="KeywordDeclaration"/>
+        <push state="typename"/>
+      </rule>
+      <rule pattern="\b(public|req|private|void)\b">
+        <token type="KeywordDeclaration"/>
+      </rule>
+      <rule pattern="\b(Boolean|String|Number|Date)\b">
+        <token type="KeywordType"/>
+      </rule>
+      <rule pattern="\^?[a-zA-Z][a-zA-Z0-9]*">
+        <token type="Name"/>
+      </rule>
+      <rule pattern="\s+">
+        <token type="Text"/>
+      </rule>
+    </state>
+    <state name="string">
+      <rule pattern="&quot;">
+        <token type="LiteralString"/>
+        <pop depth="1"/>
+      </rule>
+      <rule pattern="\\([\\abfnrtv&quot;\&#x27;]|x[a-fA-F0-9]{2,4}|u[a-fA-F0-9]{4}|U[a-fA-F0-9]{8}|[0-7]{1,3})">
+        <token type="LiteralStringEscape"/>
+      </rule>
+      <rule pattern="[^\\&quot;\n]+">
+        <token type="LiteralString"/>
+      </rule>
+      <rule pattern="\\\n">
+        <token type="LiteralString"/>
+      </rule>
+      <rule pattern="\\">
+        <token type="LiteralString"/>
+      </rule>
+    </state>
+    <state name="method">
+      <rule pattern="\(">
+        <token type="Punctuation"/>
+        <pop depth="1"/>
+      </rule>
+      <rule pattern="\^[a-zA-Z][a-zA-Z0-9]*">
+        <token type="NameClass"/>
+      </rule>
+      <rule pattern="[a-zA-Z][a-zA-Z0-9]*">
+        <token type="NameFunction"/>
+      </rule>
+    </state>
+    <state name="callmethod">
+      <rule pattern="\(|{">
+        <token type="Punctuation"/>
+        <pop depth="1"/>
+      </rule>
+      <rule pattern="\^[a-zA-Z][a-zA-Z0-9]*">
+        <token type="NameClass"/>
+      </rule>
+      <rule pattern="[a-zA-Z][a-zA-Z0-9]*">
+        <token type="NameFunction"/>
+      </rule>
+      <rule pattern="\s+">
+        <token type="Text"/>
+      </rule>
+    </state>
+    <state name="typename">
+      <rule pattern="\s+">
+        <token type="Text"/>
+      </rule>
+      <rule pattern="\b(public|req|private|void)\b">
+        <token type="KeywordDeclaration"/>
+      </rule>
+      <rule pattern="[a-zA-Z][a-zA-Z0-9]*">
+        <token type="NameClass"/>
+        <pop depth="1"/>
+      </rule>
+    </state>
+  </rules>
+</lexer>
\ No newline at end of file
diff --git a/lexers/testdata/psl.actual b/lexers/testdata/psl.actual
new file mode 100644
index 0000000..9d948f7
--- /dev/null
+++ b/lexers/testdata/psl.actual
@@ -0,0 +1,13 @@
+public Number SumMethod() {
+    // this is a comment
+    type public Number x
+    set x = 10.0
+    type String thisIsAString = "this"_x_"conjoined"
+    type String i = ""
+    for  set i = ^UTBL("test",i).order() quit:i.isNull()  {
+        set x = x + i
+    }
+    set x = x + $$getMore^ProcedureName("AAA")
+    do finishTask(x, "AAA")
+
+    quit
\ No newline at end of file
diff --git a/lexers/testdata/psl.expected b/lexers/testdata/psl.expected
new file mode 100644
index 0000000..7e84b5c
--- /dev/null
+++ b/lexers/testdata/psl.expected
@@ -0,0 +1,478 @@
+[
+  {
+    "type": "KeywordDeclaration",
+    "value": "public"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "KeywordType",
+    "value": "Number"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Name",
+    "value": "SumMethod"
+   },
+   {
+    "type": "Punctuation",
+    "value": "()"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Punctuation",
+    "value": "{"
+   },
+   {
+    "type": "Text",
+    "value": "\n    "
+   },
+   {
+    "type": "CommentSingle",
+    "value": "// this is a comment"
+   },
+   {
+    "type": "Text",
+    "value": "\n    "
+   },
+   {
+    "type": "KeywordDeclaration",
+    "value": "type"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "KeywordDeclaration",
+    "value": "public"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "NameClass",
+    "value": "Number"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Name",
+    "value": "x"
+   },
+   {
+    "type": "Text",
+    "value": "\n    "
+   },
+   {
+    "type": "Keyword",
+    "value": "set"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Name",
+    "value": "x"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Operator",
+    "value": "="
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "LiteralNumber",
+    "value": "10.0"
+   },
+   {
+    "type": "Text",
+    "value": "\n    "
+   },
+   {
+    "type": "KeywordDeclaration",
+    "value": "type"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "NameClass",
+    "value": "String"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Name",
+    "value": "thisIsAString"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Operator",
+    "value": "="
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "LiteralString",
+    "value": "\"this\""
+   },
+   {
+    "type": "Operator",
+    "value": "_"
+   },
+   {
+    "type": "Name",
+    "value": "x"
+   },
+   {
+    "type": "Operator",
+    "value": "_"
+   },
+   {
+    "type": "LiteralString",
+    "value": "\"conjoined\""
+   },
+   {
+    "type": "Text",
+    "value": "\n    "
+   },
+   {
+    "type": "KeywordDeclaration",
+    "value": "type"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "NameClass",
+    "value": "String"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Name",
+    "value": "i"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Operator",
+    "value": "="
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "LiteralString",
+    "value": "\"\""
+   },
+   {
+    "type": "Text",
+    "value": "\n    "
+   },
+   {
+    "type": "Keyword",
+    "value": "for"
+   },
+   {
+    "type": "Text",
+    "value": "  "
+   },
+   {
+    "type": "Keyword",
+    "value": "set"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Name",
+    "value": "i"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Operator",
+    "value": "="
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Name",
+    "value": "^UTBL"
+   },
+   {
+    "type": "Punctuation",
+    "value": "("
+   },
+   {
+    "type": "LiteralString",
+    "value": "\"test\""
+   },
+   {
+    "type": "Punctuation",
+    "value": ","
+   },
+   {
+    "type": "Name",
+    "value": "i"
+   },
+   {
+    "type": "Punctuation",
+    "value": ")"
+   },
+   {
+    "type": "Operator",
+    "value": "."
+   },
+   {
+    "type": "NameFunction",
+    "value": "order"
+   },
+   {
+    "type": "Punctuation",
+    "value": "()"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Keyword",
+    "value": "quit"
+   },
+   {
+    "type": "Operator",
+    "value": ":"
+   },
+   {
+    "type": "Name",
+    "value": "i"
+   },
+   {
+    "type": "Operator",
+    "value": "."
+   },
+   {
+    "type": "NameFunction",
+    "value": "isNull"
+   },
+   {
+    "type": "Punctuation",
+    "value": "()"
+   },
+   {
+    "type": "Text",
+    "value": "  "
+   },
+   {
+    "type": "Punctuation",
+    "value": "{"
+   },
+   {
+    "type": "Text",
+    "value": "\n        "
+   },
+   {
+    "type": "Keyword",
+    "value": "set"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Name",
+    "value": "x"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Operator",
+    "value": "="
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Name",
+    "value": "x"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Operator",
+    "value": "+"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Name",
+    "value": "i"
+   },
+   {
+    "type": "Text",
+    "value": "\n    "
+   },
+   {
+    "type": "Punctuation",
+    "value": "}"
+   },
+   {
+    "type": "Text",
+    "value": "\n    "
+   },
+   {
+    "type": "Keyword",
+    "value": "set"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Name",
+    "value": "x"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Operator",
+    "value": "="
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Name",
+    "value": "x"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "Operator",
+    "value": "+"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "NameFunction",
+    "value": "$$getMore"
+   },
+   {
+    "type": "NameClass",
+    "value": "^ProcedureName"
+   },
+   {
+    "type": "Punctuation",
+    "value": "("
+   },
+   {
+    "type": "LiteralString",
+    "value": "\"AAA\""
+   },
+   {
+    "type": "Punctuation",
+    "value": ")"
+   },
+   {
+    "type": "Text",
+    "value": "\n    "
+   },
+   {
+    "type": "KeywordReserved",
+    "value": "do"
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "NameFunction",
+    "value": "finishTask"
+   },
+   {
+    "type": "Punctuation",
+    "value": "("
+   },
+   {
+    "type": "Name",
+    "value": "x"
+   },
+   {
+    "type": "Punctuation",
+    "value": ","
+   },
+   {
+    "type": "Text",
+    "value": " "
+   },
+   {
+    "type": "LiteralString",
+    "value": "\"AAA\""
+   },
+   {
+    "type": "Punctuation",
+    "value": ")"
+   },
+   {
+    "type": "Text",
+    "value": "\n\n    "
+   },
+   {
+    "type": "Keyword",
+    "value": "quit"
+   }
+]
\ No newline at end of file