summaryrefslogtreecommitdiffstats
path: root/public/prism/prism-icu-message-format.js
blob: b12ee2c7486724120545bb8e23f3b4d8a26ce303 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// https://unicode-org.github.io/icu/userguide/format_parse/messages/
// https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/text/MessageFormat.html

(function (Prism) {
  /**
   * @param {string} source
   * @param {number} level
   * @returns {string}
   */
  function nested(source, level) {
    if (level <= 0) {
      return /[]/.source;
    } else {
      return source.replace(/<SELF>/g, function () {
        return nested(source, level - 1);
      });
    }
  }

  var stringPattern = /'[{}:=,](?:[^']|'')*'(?!')/;

  var escape = {
    pattern: /''/,
    greedy: true,
    alias: 'operator',
  };
  var string = {
    pattern: stringPattern,
    greedy: true,
    inside: {
      escape: escape,
    },
  };

  var argumentSource = nested(
    /\{(?:[^{}']|'(?![{},'])|''|<STR>|<SELF>)*\}/.source.replace(
      /<STR>/g,
      function () {
        return stringPattern.source;
      }
    ),
    8
  );

  var nestedMessage = {
    pattern: RegExp(argumentSource),
    inside: {
      message: {
        pattern: /^(\{)[\s\S]+(?=\}$)/,
        lookbehind: true,
        inside: null, // see below
      },
      'message-delimiter': {
        pattern: /./,
        alias: 'punctuation',
      },
    },
  };

  Prism.languages['icu-message-format'] = {
    argument: {
      pattern: RegExp(argumentSource),
      greedy: true,
      inside: {
        content: {
          pattern: /^(\{)[\s\S]+(?=\}$)/,
          lookbehind: true,
          inside: {
            'argument-name': {
              pattern: /^(\s*)[^{}:=,\s]+/,
              lookbehind: true,
            },
            'choice-style': {
              // https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1ChoiceFormat.html#details
              pattern: /^(\s*,\s*choice\s*,\s*)\S(?:[\s\S]*\S)?/,
              lookbehind: true,
              inside: {
                punctuation: /\|/,
                range: {
                  pattern: /^(\s*)[+-]?(?:\d+(?:\.\d*)?|\u221e)\s*[<#\u2264]/,
                  lookbehind: true,
                  inside: {
                    operator: /[<#\u2264]/,
                    number: /\S+/,
                  },
                },
                rest: null, // see below
              },
            },
            'plural-style': {
              // https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/text/PluralFormat.html#:~:text=Patterns%20and%20Their%20Interpretation
              pattern:
                /^(\s*,\s*(?:plural|selectordinal)\s*,\s*)\S(?:[\s\S]*\S)?/,
              lookbehind: true,
              inside: {
                offset: /^offset:\s*\d+/,
                'nested-message': nestedMessage,
                selector: {
                  pattern: /=\d+|[^{}:=,\s]+/,
                  inside: {
                    keyword: /^(?:few|many|one|other|two|zero)$/,
                  },
                },
              },
            },
            'select-style': {
              // https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/text/SelectFormat.html#:~:text=Patterns%20and%20Their%20Interpretation
              pattern: /^(\s*,\s*select\s*,\s*)\S(?:[\s\S]*\S)?/,
              lookbehind: true,
              inside: {
                'nested-message': nestedMessage,
                selector: {
                  pattern: /[^{}:=,\s]+/,
                  inside: {
                    keyword: /^other$/,
                  },
                },
              },
            },
            keyword: /\b(?:choice|plural|select|selectordinal)\b/,
            'arg-type': {
              pattern: /\b(?:date|duration|number|ordinal|spellout|time)\b/,
              alias: 'keyword',
            },
            'arg-skeleton': {
              pattern: /(,\s*)::[^{}:=,\s]+/,
              lookbehind: true,
            },
            'arg-style': {
              pattern:
                /(,\s*)(?:currency|full|integer|long|medium|percent|short)(?=\s*$)/,
              lookbehind: true,
            },
            'arg-style-text': {
              pattern: RegExp(
                /(^\s*,\s*(?=\S))/.source +
                  nested(/(?:[^{}']|'[^']*'|\{(?:<SELF>)?\})+/.source, 8) +
                  '$'
              ),
              lookbehind: true,
              alias: 'string',
            },
            punctuation: /,/,
          },
        },
        'argument-delimiter': {
          pattern: /./,
          alias: 'operator',
        },
      },
    },
    escape: escape,
    string: string,
  };

  nestedMessage.inside.message.inside = Prism.languages['icu-message-format'];
  Prism.languages['icu-message-format'].argument.inside.content.inside[
    'choice-style'
  ].inside.rest = Prism.languages['icu-message-format'];
})(Prism);
lic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
(function (Prism) {
  var comment_inside = {
    function:
      /\b(?:BUGS?|FIX(?:MES?)?|NOTES?|TODOS?|XX+|HACKS?|WARN(?:ING)?|\?{2,}|!{2,})\b/,
  };
  var string_inside = {
    number: /\\[^\s']|%\w/,
  };

  var factor = {
    comment: [
      {
        // ! single-line exclamation point comments with whitespace after/around the !
        pattern: /(^|\s)(?:! .*|!$)/,
        lookbehind: true,
        inside: comment_inside,
      },

      /* from basis/multiline: */
      {
        // /* comment */, /* comment*/
        pattern: /(^|\s)\/\*\s[\s\S]*?\*\/(?=\s|$)/,
        lookbehind: true,
        greedy: true,
        inside: comment_inside,
      },
      {
        // ![[ comment ]] , ![===[ comment]===]
        pattern: /(^|\s)!\[(={0,6})\[\s[\s\S]*?\]\2\](?=\s|$)/,
        lookbehind: true,
        greedy: true,
        inside: comment_inside,
      },
    ],

    number: [
      {
        // basic base 10 integers 9, -9
        pattern: /(^|\s)[+-]?\d+(?=\s|$)/,
        lookbehind: true,
      },
      {
        // base prefix integers 0b010 0o70 0xad 0d10 0XAD -0xa9
        pattern: /(^|\s)[+-]?0(?:b[01]+|o[0-7]+|d\d+|x[\dA-F]+)(?=\s|$)/i,
        lookbehind: true,
      },
      {
        // fractional ratios 1/5 -1/5 and the literal float approximations 1/5. -1/5.
        pattern: /(^|\s)[+-]?\d+\/\d+\.?(?=\s|$)/,
        lookbehind: true,
      },
      {
        // positive mixed numbers 23+1/5 +23+1/5
        pattern: /(^|\s)\+?\d+\+\d+\/\d+(?=\s|$)/,
        lookbehind: true,
      },
      {
        // negative mixed numbers -23-1/5
        pattern: /(^|\s)-\d+-\d+\/\d+(?=\s|$)/,
        lookbehind: true,
      },
      {
        // basic decimal floats -0.01 0. .0 .1 -.1 -1. -12.13 +12.13
        // and scientific notation with base 10 exponents 3e4 3e-4 .3e-4
        pattern: /(^|\s)[+-]?(?:\d*\.\d+|\d+\.\d*|\d+)(?:e[+-]?\d+)?(?=\s|$)/i,
        lookbehind: true,
      },
      {
        // NAN literal syntax NAN: 80000deadbeef, NAN: a
        pattern: /(^|\s)NAN:\s+[\da-fA-F]+(?=\s|$)/,
        lookbehind: true,
      },
      {
        /*
					base prefix floats 0x1.0p3 (8.0) 0b1.010p2 (5.0) 0x1.p1 0b1.11111111p11111...
					"The normalized hex form ±0x1.MMMMMMMMMMMMM[pP]±EEEE allows any floating-point number to be specified precisely.
					The values of MMMMMMMMMMMMM and EEEE map directly to the mantissa and exponent fields of the binary IEEE 754 representation."
					<https://docs.factorcode.org/content/article-syntax-floats.html>
				*/
        pattern:
          /(^|\s)[+-]?0(?:b1\.[01]*|o1\.[0-7]*|d1\.\d*|x1\.[\dA-F]*)p\d+(?=\s|$)/i,
        lookbehind: true,
      },
    ],

    // R/ regexp?\/\\/
    regexp: {
      pattern:
        /(^|\s)R\/\s(?:\\\S|[^\\/])*\/(?:[idmsr]*|[idmsr]+-[idmsr]+)(?=\s|$)/,
      lookbehind: true,
      alias: 'number',
      inside: {
        variable: /\\\S/,
        keyword: /[+?*\[\]^$(){}.|]/,
        operator: {
          pattern: /(\/)[idmsr]+(?:-[idmsr]+)?/,
          lookbehind: true,
        },
      },
    },

    boolean: {
      pattern: /(^|\s)[tf](?=\s|$)/,
      lookbehind: true,
    },

    // SBUF" asd", URL" ://...", P" /etc/"
    'custom-string': {
      pattern: /(^|\s)[A-Z0-9\-]+"\s(?:\\\S|[^"\\])*"/,
      lookbehind: true,
      greedy: true,
      alias: 'string',
      inside: {
        number: /\\\S|%\w|\//,
      },
    },

    'multiline-string': [
      {
        // STRING: name \n content \n ; -> CONSTANT: name "content" (symbol)
        pattern: /(^|\s)STRING:\s+\S+(?:\n|\r\n).*(?:\n|\r\n)\s*;(?=\s|$)/,
        lookbehind: true,
        greedy: true,
        alias: 'string',
        inside: {
          number: string_inside.number,
          // trailing semicolon on its own line
          'semicolon-or-setlocal': {
            pattern: /([\r\n][ \t]*);(?=\s|$)/,
            lookbehind: true,
            alias: 'function',
          },
        },
      },
      {
        // HEREDOC: marker \n content \n marker ; -> "content" (immediate)
        pattern: /(^|\s)HEREDOC:\s+\S+(?:\n|\r\n).*(?:\n|\r\n)\s*\S+(?=\s|$)/,
        lookbehind: true,
        greedy: true,
        alias: 'string',
        inside: string_inside,
      },
      {
        // [[ string ]], [==[ string]==]
        pattern: /(^|\s)\[(={0,6})\[\s[\s\S]*?\]\2\](?=\s|$)/,
        lookbehind: true,
        greedy: true,
        alias: 'string',
        inside: string_inside,
      },
    ],

    'special-using': {
      pattern: /(^|\s)USING:(?:\s\S+)*(?=\s+;(?:\s|$))/,
      lookbehind: true,
      alias: 'function',
      inside: {
        // this is essentially a regex for vocab names, which i don't want to specify
        // but the USING: gets picked up as a vocab name
        string: {
          pattern: /(\s)[^:\s]+/,
          lookbehind: true,
        },
      },
    },

    /* this description of stack effect literal syntax is not complete and not as specific as theoretically possible
			trying to do better is more work and regex-computation-time than it's worth though.
			- we'd like to have the "delimiter" parts of the stack effect [ (, --, and ) ] be a different (less-important or comment-like) colour to the stack effect contents
			- we'd like if nested stack effects were treated as such rather than just appearing flat (with `inside`)
			- we'd like if the following variable name conventions were recognised specifically:
				special row variables = ..a b..
				type and stack effect annotations end with a colon = ( quot: ( a: ( -- ) -- b ) -- x ), ( x: number -- )
				word throws unconditional error = *
				any other word-like variable name = a ? q' etc

			https://docs.factorcode.org/content/article-effects.html

			these are pretty complicated to highlight properly without a real parser, and therefore out of scope
			the old pattern, which may be later useful, was: (^|\s)(?:call|execute|eval)?\((?:\s+[^"\r\n\t ]\S*)*?\s+--(?:\s+[^"\n\t ]\S*)*?\s+\)(?=\s|$)
		*/

    // current solution is not great
    'stack-effect-delimiter': [
      {
        // opening parenthesis
        pattern: /(^|\s)(?:call|eval|execute)?\((?=\s)/,
        lookbehind: true,
        alias: 'operator',
      },
      {
        // middle --
        pattern: /(\s)--(?=\s)/,
        lookbehind: true,
        alias: 'operator',
      },
      {
        // closing parenthesis
        pattern: /(\s)\)(?=\s|$)/,
        lookbehind: true,
        alias: 'operator',
      },
    ],

    combinators: {
      pattern: null,
      lookbehind: true,
      alias: 'keyword',
    },

    'kernel-builtin': {
      pattern: null,
      lookbehind: true,
      alias: 'variable',
    },

    'sequences-builtin': {
      pattern: null,
      lookbehind: true,
      alias: 'variable',
    },

    'math-builtin': {
      pattern: null,
      lookbehind: true,
      alias: 'variable',
    },

    'constructor-word': {
      // <array> but not <=>
      pattern: /(^|\s)<(?!=+>|-+>)\S+>(?=\s|$)/,
      lookbehind: true,
      alias: 'keyword',
    },

    'other-builtin-syntax': {
      pattern: null,
      lookbehind: true,
      alias: 'operator',
    },

    /*
			full list of supported word naming conventions: (the convention appears outside of the [brackets])
				set-[x]
				change-[x]
				with-[x]
				new-[x]
				>[string]
				[base]>
				[string]>[number]
				+[symbol]+
				[boolean-word]?
				?[of]
				[slot-reader]>>
				>>[slot-setter]
				[slot-writer]<<
				([implementation-detail])
				[mutater]!
				[variant]*
				[prettyprint].
				$[help-markup]

			<constructors>, SYNTAX:, etc are supported by their own patterns.

			`with` and `new` from `kernel` are their own builtins.

			see <https://docs.factorcode.org/content/article-conventions.html>
		*/
    'conventionally-named-word': {
      pattern:
        /(^|\s)(?!")(?:(?:change|new|set|with)-\S+|\$\S+|>[^>\s]+|[^:>\s]+>|[^>\s]+>[^>\s]+|\+[^+\s]+\+|[^?\s]+\?|\?[^?\s]+|[^>\s]+>>|>>[^>\s]+|[^<\s]+<<|\([^()\s]+\)|[^!\s]+!|[^*\s]\S*\*|[^.\s]\S*\.)(?=\s|$)/,
      lookbehind: true,
      alias: 'keyword',
    },

    'colon-syntax': {
      pattern: /(^|\s)(?:[A-Z0-9\-]+#?)?:{1,2}\s+(?:;\S+|(?!;)\S+)(?=\s|$)/,
      lookbehind: true,
      greedy: true,
      alias: 'function',
    },

    'semicolon-or-setlocal': {
      pattern: /(\s)(?:;|:>)(?=\s|$)/,
      lookbehind: true,
      alias: 'function',
    },

    // do not highlight leading } or trailing X{ at the begin/end of the file as it's invalid syntax
    'curly-brace-literal-delimiter': [
      {
        // opening
        pattern: /(^|\s)[a-z]*\{(?=\s)/i,
        lookbehind: true,
        alias: 'operator',
      },
      {
        // closing
        pattern: /(\s)\}(?=\s|$)/,
        lookbehind: true,
        alias: 'operator',
      },
    ],

    // do not highlight leading ] or trailing [ at the begin/end of the file as it's invalid syntax
    'quotation-delimiter': [
      {
        // opening
        pattern: /(^|\s)\[(?=\s)/,
        lookbehind: true,
        alias: 'operator',
      },
      {
        // closing
        pattern: /(\s)\](?=\s|$)/,
        lookbehind: true,
        alias: 'operator',
      },
    ],

    'normal-word': {
      pattern: /(^|\s)[^"\s]\S*(?=\s|$)/,
      lookbehind: true,
    },

    /*
			basic first-class string "a"
				with escaped double-quote "a\""
				escaped backslash "\\"
				and general escapes since Factor has so many "\N"

			syntax that works in the reference implementation that isn't fully
			supported because it's an implementation detail:
				"string 1""string 2" -> 2 strings (works anyway)
				"string"5 -> string, 5
				"string"[ ] -> string, quotation
				{ "a"} -> array<string>

			the rest of those examples all properly recognise the string, but not
				the other object (number, quotation, etc)
			this is fine for a regex-only implementation.
		*/
    string: {
      pattern: /"(?:\\\S|[^"\\])*"/,
      greedy: true,
      inside: string_inside,
    },
  };

  var escape = function (str) {
    return (str + '').replace(/([.?*+\^$\[\]\\(){}|\-])/g, '\\$1');
  };

  var arrToWordsRegExp = function (arr) {
    return new RegExp('(^|\\s)(?:' + arr.map(escape).join('|') + ')(?=\\s|$)');
  };

  var builtins = {
    'kernel-builtin': [
      'or',
      '2nipd',
      '4drop',
      'tuck',
      'wrapper',
      'nip',
      'wrapper?',
      'callstack>array',
      'die',
      'dupd',
      'callstack',
      'callstack?',
      '3dup',
      'hashcode',
      'pick',
      '4nip',
      'build',
      '>boolean',
      'nipd',
      'clone',
      '5nip',
      'eq?',
      '?',
      '=',
      'swapd',
      '2over',
      'clear',
      '2dup',
      'get-retainstack',
      'not',
      'tuple?',
      'dup',
      '3nipd',
      'call',
      '-rotd',
      'object',
      'drop',
      'assert=',
      'assert?',
      '-rot',
      'execute',
      'boa',
      'get-callstack',
      'curried?',
      '3drop',
      'pickd',
      'overd',
      'over',
      'roll',
      '3nip',
      'swap',
      'and',
      '2nip',
      'rotd',
      'throw',
      '(clone)',
      'hashcode*',
      'spin',
      'reach',
      '4dup',
      'equal?',
      'get-datastack',
      'assert',
      '2drop',
      '<wrapper>',
      'boolean?',
      'identity-hashcode',
      'identity-tuple?',
      'null',
      'composed?',
      'new',
      '5drop',
      'rot',
      '-roll',
      'xor',
      'identity-tuple',
      'boolean',
    ],
    'other-builtin-syntax': [
      // syntax
      '=======',
      'recursive',
      'flushable',
      '>>',
      '<<<<<<',
      'M\\',
      'B',
      'PRIVATE>',
      '\\',
      '======',
      'final',
      'inline',
      'delimiter',
      'deprecated',
      '<PRIVATE',
      '>>>>>>',
      '<<<<<<<',
      'parse-complex',
      'malformed-complex',
      'read-only',
      '>>>>>>>',
      'call-next-method',
      '<<',
      'foldable',
      // literals
      '$',
      '$[',
      '${',
    ],
    'sequences-builtin': [
      'member-eq?',
      'mismatch',
      'append',
      'assert-sequence=',
      'longer',
      'repetition',
      'clone-like',
      '3sequence',
      'assert-sequence?',
      'last-index-from',
      'reversed',
      'index-from',
      'cut*',
      'pad-tail',
      'join-as',
      'remove-eq!',
      'concat-as',
      'but-last',
      'snip',
      'nths',
      'nth',
      'sequence',
      'longest',
      'slice?',
      '<slice>',
      'remove-nth',
      'tail-slice',
      'empty?',
      'tail*',
      'member?',
      'virtual-sequence?',
      'set-length',
      'drop-prefix',
      'iota',
      'unclip',
      'bounds-error?',
      'unclip-last-slice',
      'non-negative-integer-expected',
      'non-negative-integer-expected?',
      'midpoint@',
      'longer?',
      '?set-nth',
      '?first',
      'rest-slice',
      'prepend-as',
      'prepend',
      'fourth',
      'sift',
      'subseq-start',
      'new-sequence',
      '?last',
      'like',
      'first4',
      '1sequence',
      'reverse',
      'slice',
      'virtual@',
      'repetition?',
      'set-last',
      'index',
      '4sequence',
      'max-length',
      'set-second',
      'immutable-sequence',
      'first2',
      'first3',
      'supremum',
      'unclip-slice',
      'suffix!',
      'insert-nth',
      'tail',
      '3append',
      'short',
      'suffix',
      'concat',
      'flip',
      'immutable?',
      'reverse!',
      '2sequence',
      'sum',
      'delete-all',
      'indices',
      'snip-slice',
      '<iota>',
      'check-slice',
      'sequence?',
      'head',
      'append-as',
      'halves',
      'sequence=',
      'collapse-slice',
      '?second',
      'slice-error?',
      'product',
      'bounds-check?',
      'bounds-check',
      'immutable',
      'virtual-exemplar',
      'harvest',
      'remove',
      'pad-head',
      'last',
      'set-fourth',
      'cartesian-product',
      'remove-eq',
      'shorten',
      'shorter',
      'reversed?',
      'shorter?',
      'shortest',
      'head-slice',
      'pop*',
      'tail-slice*',
      'but-last-slice',
      'iota?',
      'append!',
      'cut-slice',
      'new-resizable',
      'head-slice*',
      'sequence-hashcode',
      'pop',
      'set-nth',
      '?nth',
      'second',
      'join',
      'immutable-sequence?',
      '<reversed>',
      '3append-as',
      'virtual-sequence',
      'subseq?',
      'remove-nth!',
      'length',
      'last-index',
      'lengthen',
      'assert-sequence',
      'copy',
      'move',
      'third',
      'first',
      'tail?',
      'set-first',
      'prefix',
      'bounds-error',
      '<repetition>',
      'exchange',
      'surround',
      'cut',
      'min-length',
      'set-third',
      'push-all',
      'head?',
      'subseq-start-from',
      'delete-slice',
      'rest',
      'sum-lengths',
      'head*',
      'infimum',
      'remove!',
      'glue',
      'slice-error',
      'subseq',
      'push',
      'replace-slice',
      'subseq-as',
      'unclip-last',
    ],
    'math-builtin': [
      'number=',
      'next-power-of-2',
      '?1+',
      'fp-special?',
      'imaginary-part',
      'float>bits',
      'number?',
      'fp-infinity?',
      'bignum?',
      'fp-snan?',
      'denominator',
      'gcd',
      '*',
      '+',
      'fp-bitwise=',
      '-',
      'u>=',
      '/',
      '>=',
      'bitand',
      'power-of-2?',
      'log2-expects-positive',
      'neg?',
      '<',
      'log2',
      '>',
      'integer?',
      'number',
      'bits>double',
      '2/',
      'zero?',
      'bits>float',
      'float?',
      'shift',
      'ratio?',
      'rect>',
      'even?',
      'ratio',
      'fp-sign',
      'bitnot',
      '>fixnum',
      'complex?',
      '/i',
      'integer>fixnum',
      '/f',
      'sgn',
      '>bignum',
      'next-float',
      'u<',
      'u>',
      'mod',
      'recip',
      'rational',
      '>float',
      '2^',
      'integer',
      'fixnum?',
      'neg',
      'fixnum',
      'sq',
      'bignum',
      '>rect',
      'bit?',
      'fp-qnan?',
      'simple-gcd',
      'complex',
      '<fp-nan>',
      'real',
      '>fraction',
      'double>bits',
      'bitor',
      'rem',
      'fp-nan-payload',
      'real-part',
      'log2-expects-positive?',
      'prev-float',
      'align',
      'unordered?',
      'float',
      'fp-nan?',
      'abs',
      'bitxor',
      'integer>fixnum-strict',
      'u<=',
      'odd?',
      '<=',
      '/mod',
      '>integer',
      'real?',
      'rational?',
      'numerator',
    ],
    // that's all for now
  };

  Object.keys(builtins).forEach(function (k) {
    factor[k].pattern = arrToWordsRegExp(builtins[k]);
  });

  var combinators = [
    // kernel
    '2bi',
    'while',
    '2tri',
    'bi*',
    '4dip',
    'both?',
    'same?',
    'tri@',
    'curry',
    'prepose',
    '3bi',
    '?if',
    'tri*',
    '2keep',
    '3keep',
    'curried',
    '2keepd',
    'when',
    '2bi*',
    '2tri*',
    '4keep',
    'bi@',
    'keepdd',
    'do',
    'unless*',
    'tri-curry',
    'if*',
    'loop',
    'bi-curry*',
    'when*',
    '2bi@',
    '2tri@',
    'with',
    '2with',
    'either?',
    'bi',
    'until',
    '3dip',
    '3curry',
    'tri-curry*',
    'tri-curry@',
    'bi-curry',
    'keepd',
    'compose',
    '2dip',
    'if',
    '3tri',
    'unless',
    'tuple',
    'keep',
    '2curry',
    'tri',
    'most',
    'while*',
    'dip',
    'composed',
    'bi-curry@',
    // sequences
    'find-last-from',
    'trim-head-slice',
    'map-as',
    'each-from',
    'none?',
    'trim-tail',
    'partition',
    'if-empty',
    'accumulate*',
    'reject!',
    'find-from',
    'accumulate-as',
    'collector-for-as',
    'reject',
    'map',
    'map-sum',
    'accumulate!',
    '2each-from',
    'follow',
    'supremum-by',
    'map!',
    'unless-empty',
    'collector',
    'padding',
    'reduce-index',
    'replicate-as',
    'infimum-by',
    'trim-tail-slice',
    'count',
    'find-index',
    'filter',
    'accumulate*!',
    'reject-as',
    'map-integers',
    'map-find',
    'reduce',
    'selector',
    'interleave',
    '2map',
    'filter-as',
    'binary-reduce',
    'map-index-as',
    'find',
    'produce',
    'filter!',
    'replicate',
    'cartesian-map',
    'cartesian-each',
    'find-index-from',
    'map-find-last',
    '3map-as',
    '3map',
    'find-last',
    'selector-as',
    '2map-as',
    '2map-reduce',
    'accumulate',
    'each',
    'each-index',
    'accumulate*-as',
    'when-empty',
    'all?',
    'collector-as',
    'push-either',
    'new-like',
    'collector-for',
    '2selector',
    'push-if',
    '2all?',
    'map-reduce',
    '3each',
    'any?',
    'trim-slice',
    '2reduce',
    'change-nth',
    'produce-as',
    '2each',
    'trim',
    'trim-head',
    'cartesian-find',
    'map-index',
    // math
    'if-zero',
    'each-integer',
    'unless-zero',
    '(find-integer)',
    'when-zero',
    'find-last-integer',
    '(all-integers?)',
    'times',
    '(each-integer)',
    'find-integer',
    'all-integers?',
    // math.combinators
    'unless-negative',
    'if-positive',
    'when-positive',
    'when-negative',
    'unless-positive',
    'if-negative',
    // combinators
    'case',
    '2cleave',
    'cond>quot',
    'case>quot',
    '3cleave',
    'wrong-values',
    'to-fixed-point',
    'alist>quot',
    'cond',
    'cleave',
    'call-effect',
    'recursive-hashcode',
    'spread',
    'deep-spread>quot',
    // combinators.short-circuit
    '2||',
    '0||',
    'n||',
    '0&&',
    '2&&',
    '3||',
    '1||',
    '1&&',
    'n&&',
    '3&&',
    // combinators.smart
    'smart-unless*',
    'keep-inputs',
    'reduce-outputs',
    'smart-when*',
    'cleave>array',
    'smart-with',
    'smart-apply',
    'smart-if',
    'inputs/outputs',
    'output>sequence-n',
    'map-outputs',
    'map-reduce-outputs',
    'dropping',
    'output>array',
    'smart-map-reduce',
    'smart-2map-reduce',
    'output>array-n',
    'nullary',
    'input<sequence',
    'append-outputs',
    'drop-inputs',
    'inputs',
    'smart-2reduce',
    'drop-outputs',
    'smart-reduce',
    'preserving',
    'smart-when',
    'outputs',
    'append-outputs-as',
    'smart-unless',
    'smart-if*',
    'sum-outputs',
    'input<sequence-unsafe',
    'output>sequence',
    // tafn
  ];

  factor.combinators.pattern = arrToWordsRegExp(combinators);

  Prism.languages.factor = factor;
})(Prism);