summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--syntax-highlight/javascript.scm74
2 files changed, 75 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index 191f12b..e059e0f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -44,6 +44,7 @@ SOURCES = \
syntax-highlight/c.scm \
syntax-highlight/css.scm \
syntax-highlight/gitignore.scm \
+ syntax-highlight/javascript.scm \
syntax-highlight/lisp.scm \
syntax-highlight/scheme.scm \
syntax-highlight/xml.scm \
diff --git a/syntax-highlight/javascript.scm b/syntax-highlight/javascript.scm
new file mode 100644
index 0000000..544c213
--- /dev/null
+++ b/syntax-highlight/javascript.scm
@@ -0,0 +1,74 @@
+;;; guile-syntax-highlight --- General-purpose syntax highlighter
+;;; Copyright © 2023 David Thompson <davet@gnu.org>
+;;;
+;;; Guile-syntax-highlight is free software; you can redistribute it
+;;; and/or modify it under the terms of the GNU Lesser General Public
+;;; License as published by the Free Software Foundation; either
+;;; version 3 of the License, or (at your option) any later version.
+;;;
+;;; Guile-syntax-highlight is distributed in the hope that it will be
+;;; useful, but WITHOUT ANY WARRANTY; without even the implied
+;;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+;;; See the GNU Lesser General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU Lesser General Public
+;;; License along with guile-syntax-highlight. If not, see
+;;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Syntax highlighting for JavaScript.
+;;
+;;; Code:
+
+(define-module (syntax-highlight javascript)
+ #:use-module (ice-9 match)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-11)
+ #:use-module (srfi srfi-26)
+ #:use-module (syntax-highlight lexers)
+ #:export (lex-javascript))
+
+(define %js-reserved-words
+ '("async" "await" "break" "case" "catch" "class" "const" "continue"
+ "debugger" "default" "delete" "do" "else" "export" "extends" "false"
+ "finally" "for" "function" "if" "import" "in" "instanceof" "let" "new"
+ "null" "return" "static" "super" "switch" "this" "throw" "true" "try"
+ "typeof" "var" "void" "while" "with" "yield"))
+
+(define (js-reserved-word? str)
+ (any (cut string=? <> str) %js-reserved-words))
+
+(define %js-operators
+ '(";" "," "." "?." "..." "#" "=" "+=" "-=" "*=" "/=" "%=" "<<=" ">>="
+ ">>>=" "&=" "^=" "|=" "**=" "&&=" "||=" "??=" "?" ":" "||" "&&" "??"
+ "|" "^" "&" "~" "==" "===" "!=" "!==" "<=" ">=" "<" ">" "<<" ">>" ">>>"
+ "*" "/" "%" "!" "++" "--" "+" "-" ))
+
+(define lex-js-operator
+ (lex-any* (map lex-string %js-operators)))
+
+;; A rough approximation of characters that are allowed in Javascript
+;; variables, numbers, etc.
+(define char-set:js-identifier
+ (char-set-adjoin char-set:letter+digit #\$ #\_))
+
+(define lex-js-identifier
+ (lex-char-set char-set:js-identifier))
+
+;; TODO: Highlight regexp literals.
+(define lex-javascript
+ (lex-consume
+ (lex-any (lex-char-set char-set:whitespace)
+ (lex-tag 'open (lex-any* (map lex-string '("(" "[" "{"))))
+ (lex-tag 'close (lex-any* (map lex-string '(")" "]" "}"))))
+ (lex-tag 'comment (lex-any (lex-delimited "//" #:until "\n")
+ (lex-delimited "/*" #:until "*/")
+ (lex-delimited "#!" #:until "\n")))
+ (lex-tag 'special (lex-filter js-reserved-word? lex-js-identifier))
+ (lex-tag 'operator lex-js-operator)
+ (lex-tag 'string (lex-any (lex-delimited "\"")
+ (lex-delimited "'")))
+ ;; TODO: Highlight expressions within template literals.
+ (lex-tag 'template (lex-delimited "`"))
+ (lex-tag 'symbol lex-js-identifier))))