ohm-js 17.2.1 → 17.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/ohm-extras.cjs +517 -471
  2. package/dist/ohm-extras.js +517 -471
  3. package/dist/ohm.cjs +510 -464
  4. package/dist/ohm.cjs.map +1 -1
  5. package/dist/ohm.js +511 -465
  6. package/dist/ohm.min.js +1 -1
  7. package/extras/VisitorFamily.js +9 -9
  8. package/extras/index.d.ts +1 -1
  9. package/extras/semantics-toAST.js +1 -1
  10. package/index.d.ts +24 -4
  11. package/package.json +4 -4
  12. package/src/Builder.js +8 -8
  13. package/src/CaseInsensitiveTerminal.js +3 -3
  14. package/src/Grammar.js +69 -70
  15. package/src/GrammarDecl.js +5 -5
  16. package/src/IndentationSensitive.js +6 -6
  17. package/src/InputStream.js +3 -0
  18. package/src/Interval.js +19 -7
  19. package/src/MatchResult.js +14 -16
  20. package/src/MatchState.js +17 -17
  21. package/src/PosInfo.js +7 -7
  22. package/src/Semantics.js +43 -43
  23. package/src/Trace.js +19 -19
  24. package/src/buildGrammar.js +4 -4
  25. package/src/common.js +9 -9
  26. package/src/errors.js +36 -36
  27. package/src/main.js +3 -3
  28. package/src/nodes.js +4 -4
  29. package/src/ohm-cmd.js +5 -5
  30. package/src/pexprs-allowsSkippingPrecedingSpace.js +2 -2
  31. package/src/pexprs-assertAllApplicationsAreValid.js +11 -11
  32. package/src/pexprs-assertChoicesHaveUniformArity.js +9 -9
  33. package/src/pexprs-assertIteratedExprsAreNotNullable.js +7 -7
  34. package/src/pexprs-eval.js +39 -36
  35. package/src/pexprs-getArity.js +6 -6
  36. package/src/pexprs-introduceParams.js +5 -5
  37. package/src/pexprs-isNullable.js +9 -9
  38. package/src/pexprs-main.js +12 -4
  39. package/src/pexprs-outputRecipe.js +15 -15
  40. package/src/pexprs-substituteParams.js +6 -6
  41. package/src/pexprs-toArgumentNameList.js +20 -20
  42. package/src/pexprs-toDisplayString.js +5 -5
  43. package/src/pexprs-toFailure.js +12 -12
  44. package/src/pexprs-toString.js +20 -20
  45. package/src/semanticsDeferredInit.js +8 -8
  46. package/src/unicode.js +54 -0
  47. package/src/util.js +3 -3
  48. package/src/version.js +1 -1
  49. package/dist/ohm-grammar.js.new +0 -0
  50. package/src/UnicodeCategories.js +0 -30
@@ -19,19 +19,19 @@ pexprs.any.substituteParams =
19
19
  pexprs.Terminal.prototype.substituteParams =
20
20
  pexprs.Range.prototype.substituteParams =
21
21
  pexprs.UnicodeChar.prototype.substituteParams =
22
- function(actuals) {
22
+ function (actuals) {
23
23
  return this;
24
24
  };
25
25
 
26
- pexprs.Param.prototype.substituteParams = function(actuals) {
26
+ pexprs.Param.prototype.substituteParams = function (actuals) {
27
27
  return checkNotNull(actuals[this.index]);
28
28
  };
29
29
 
30
- pexprs.Alt.prototype.substituteParams = function(actuals) {
30
+ pexprs.Alt.prototype.substituteParams = function (actuals) {
31
31
  return new pexprs.Alt(this.terms.map(term => term.substituteParams(actuals)));
32
32
  };
33
33
 
34
- pexprs.Seq.prototype.substituteParams = function(actuals) {
34
+ pexprs.Seq.prototype.substituteParams = function (actuals) {
35
35
  return new pexprs.Seq(this.factors.map(factor => factor.substituteParams(actuals)));
36
36
  };
37
37
 
@@ -39,11 +39,11 @@ pexprs.Iter.prototype.substituteParams =
39
39
  pexprs.Not.prototype.substituteParams =
40
40
  pexprs.Lookahead.prototype.substituteParams =
41
41
  pexprs.Lex.prototype.substituteParams =
42
- function(actuals) {
42
+ function (actuals) {
43
43
  return new this.constructor(this.expr.substituteParams(actuals));
44
44
  };
45
45
 
46
- pexprs.Apply.prototype.substituteParams = function(actuals) {
46
+ pexprs.Apply.prototype.substituteParams = function (actuals) {
47
47
  if (this.args.length === 0) {
48
48
  // Avoid making a copy of this application, as an optimization
49
49
  return this;
@@ -65,15 +65,15 @@ function resolveDuplicatedNames(argumentNameList) {
65
65
  // function(firstArgIndex, noDupCheck) { ... }
66
66
  pexprs.PExpr.prototype.toArgumentNameList = abstract('toArgumentNameList');
67
67
 
68
- pexprs.any.toArgumentNameList = function(firstArgIndex, noDupCheck) {
68
+ pexprs.any.toArgumentNameList = function (firstArgIndex, noDupCheck) {
69
69
  return ['any'];
70
70
  };
71
71
 
72
- pexprs.end.toArgumentNameList = function(firstArgIndex, noDupCheck) {
72
+ pexprs.end.toArgumentNameList = function (firstArgIndex, noDupCheck) {
73
73
  return ['end'];
74
74
  };
75
75
 
76
- pexprs.Terminal.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck) {
76
+ pexprs.Terminal.prototype.toArgumentNameList = function (firstArgIndex, noDupCheck) {
77
77
  if (typeof this.obj === 'string' && /^[_a-zA-Z0-9]+$/.test(this.obj)) {
78
78
  // If this terminal is a valid suffix for a JS identifier, just prepend it with '_'
79
79
  return ['_' + this.obj];
@@ -83,7 +83,7 @@ pexprs.Terminal.prototype.toArgumentNameList = function(firstArgIndex, noDupChec
83
83
  }
84
84
  };
85
85
 
86
- pexprs.Range.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck) {
86
+ pexprs.Range.prototype.toArgumentNameList = function (firstArgIndex, noDupCheck) {
87
87
  let argName = this.from + '_to_' + this.to;
88
88
  // If the `argName` is not valid then try to prepend a `_`.
89
89
  if (!isRestrictedJSIdentifier(argName)) {
@@ -96,11 +96,11 @@ pexprs.Range.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck)
96
96
  return [argName];
97
97
  };
98
98
 
99
- pexprs.Alt.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck) {
99
+ pexprs.Alt.prototype.toArgumentNameList = function (firstArgIndex, noDupCheck) {
100
100
  // `termArgNameLists` is an array of arrays where each row is the
101
101
  // argument name list that corresponds to a term in this alternation.
102
102
  const termArgNameLists = this.terms.map(term =>
103
- term.toArgumentNameList(firstArgIndex, true),
103
+ term.toArgumentNameList(firstArgIndex, true)
104
104
  );
105
105
 
106
106
  const argumentNameList = [];
@@ -120,7 +120,7 @@ pexprs.Alt.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck) {
120
120
  return argumentNameList;
121
121
  };
122
122
 
123
- pexprs.Seq.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck) {
123
+ pexprs.Seq.prototype.toArgumentNameList = function (firstArgIndex, noDupCheck) {
124
124
  // Generate the argument name list, without worrying about duplicates.
125
125
  let argumentNameList = [];
126
126
  this.factors.forEach(factor => {
@@ -136,44 +136,44 @@ pexprs.Seq.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck) {
136
136
  return argumentNameList;
137
137
  };
138
138
 
139
- pexprs.Iter.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck) {
139
+ pexprs.Iter.prototype.toArgumentNameList = function (firstArgIndex, noDupCheck) {
140
140
  const argumentNameList = this.expr
141
- .toArgumentNameList(firstArgIndex, noDupCheck)
142
- .map(exprArgumentString =>
143
- exprArgumentString[exprArgumentString.length - 1] === 's' ?
144
- exprArgumentString + 'es' :
145
- exprArgumentString + 's',
146
- );
141
+ .toArgumentNameList(firstArgIndex, noDupCheck)
142
+ .map(exprArgumentString =>
143
+ exprArgumentString[exprArgumentString.length - 1] === 's'
144
+ ? exprArgumentString + 'es'
145
+ : exprArgumentString + 's'
146
+ );
147
147
  if (!noDupCheck) {
148
148
  resolveDuplicatedNames(argumentNameList);
149
149
  }
150
150
  return argumentNameList;
151
151
  };
152
152
 
153
- pexprs.Opt.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck) {
153
+ pexprs.Opt.prototype.toArgumentNameList = function (firstArgIndex, noDupCheck) {
154
154
  return this.expr.toArgumentNameList(firstArgIndex, noDupCheck).map(argName => {
155
155
  return 'opt' + argName[0].toUpperCase() + argName.slice(1);
156
156
  });
157
157
  };
158
158
 
159
- pexprs.Not.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck) {
159
+ pexprs.Not.prototype.toArgumentNameList = function (firstArgIndex, noDupCheck) {
160
160
  return [];
161
161
  };
162
162
 
163
163
  pexprs.Lookahead.prototype.toArgumentNameList = pexprs.Lex.prototype.toArgumentNameList =
164
- function(firstArgIndex, noDupCheck) {
164
+ function (firstArgIndex, noDupCheck) {
165
165
  return this.expr.toArgumentNameList(firstArgIndex, noDupCheck);
166
166
  };
167
167
 
168
- pexprs.Apply.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck) {
168
+ pexprs.Apply.prototype.toArgumentNameList = function (firstArgIndex, noDupCheck) {
169
169
  return [this.ruleName];
170
170
  };
171
171
 
172
- pexprs.UnicodeChar.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck) {
172
+ pexprs.UnicodeChar.prototype.toArgumentNameList = function (firstArgIndex, noDupCheck) {
173
173
  return ['$' + firstArgIndex];
174
174
  };
175
175
 
176
- pexprs.Param.prototype.toArgumentNameList = function(firstArgIndex, noDupCheck) {
176
+ pexprs.Param.prototype.toArgumentNameList = function (firstArgIndex, noDupCheck) {
177
177
  return ['param' + this.index];
178
178
  };
179
179
 
@@ -8,7 +8,7 @@ import * as pexprs from './pexprs-main.js';
8
8
  // Returns a string representing the PExpr, for use as a UI label, etc.
9
9
  pexprs.PExpr.prototype.toDisplayString = abstract('toDisplayString');
10
10
 
11
- pexprs.Alt.prototype.toDisplayString = pexprs.Seq.prototype.toDisplayString = function() {
11
+ pexprs.Alt.prototype.toDisplayString = pexprs.Seq.prototype.toDisplayString = function () {
12
12
  if (this.source) {
13
13
  return this.source.trimmed().contents;
14
14
  }
@@ -24,11 +24,11 @@ pexprs.any.toDisplayString =
24
24
  pexprs.Terminal.prototype.toDisplayString =
25
25
  pexprs.Range.prototype.toDisplayString =
26
26
  pexprs.Param.prototype.toDisplayString =
27
- function() {
27
+ function () {
28
28
  return this.toString();
29
29
  };
30
30
 
31
- pexprs.Apply.prototype.toDisplayString = function() {
31
+ pexprs.Apply.prototype.toDisplayString = function () {
32
32
  if (this.args.length > 0) {
33
33
  const ps = this.args.map(arg => arg.toDisplayString());
34
34
  return this.ruleName + '<' + ps.join(',') + '>';
@@ -37,6 +37,6 @@ pexprs.Apply.prototype.toDisplayString = function() {
37
37
  }
38
38
  };
39
39
 
40
- pexprs.UnicodeChar.prototype.toDisplayString = function() {
41
- return 'Unicode [' + this.category + '] character';
40
+ pexprs.UnicodeChar.prototype.toDisplayString = function () {
41
+ return 'Unicode [' + this.categoryOrProp + '] character';
42
42
  };
@@ -8,34 +8,34 @@ import {Failure} from './Failure.js';
8
8
 
9
9
  pexprs.PExpr.prototype.toFailure = abstract('toFailure');
10
10
 
11
- pexprs.any.toFailure = function(grammar) {
11
+ pexprs.any.toFailure = function (grammar) {
12
12
  return new Failure(this, 'any object', 'description');
13
13
  };
14
14
 
15
- pexprs.end.toFailure = function(grammar) {
15
+ pexprs.end.toFailure = function (grammar) {
16
16
  return new Failure(this, 'end of input', 'description');
17
17
  };
18
18
 
19
- pexprs.Terminal.prototype.toFailure = function(grammar) {
19
+ pexprs.Terminal.prototype.toFailure = function (grammar) {
20
20
  return new Failure(this, this.obj, 'string');
21
21
  };
22
22
 
23
- pexprs.Range.prototype.toFailure = function(grammar) {
23
+ pexprs.Range.prototype.toFailure = function (grammar) {
24
24
  // TODO: come up with something better
25
25
  return new Failure(this, JSON.stringify(this.from) + '..' + JSON.stringify(this.to), 'code');
26
26
  };
27
27
 
28
- pexprs.Not.prototype.toFailure = function(grammar) {
28
+ pexprs.Not.prototype.toFailure = function (grammar) {
29
29
  const description =
30
30
  this.expr === pexprs.any ? 'nothing' : 'not ' + this.expr.toFailure(grammar);
31
31
  return new Failure(this, description, 'description');
32
32
  };
33
33
 
34
- pexprs.Lookahead.prototype.toFailure = function(grammar) {
34
+ pexprs.Lookahead.prototype.toFailure = function (grammar) {
35
35
  return this.expr.toFailure(grammar);
36
36
  };
37
37
 
38
- pexprs.Apply.prototype.toFailure = function(grammar) {
38
+ pexprs.Apply.prototype.toFailure = function (grammar) {
39
39
  let {description} = grammar.rules[this.ruleName];
40
40
  if (!description) {
41
41
  const article = /^[aeiouAEIOU]/.test(this.ruleName) ? 'an' : 'a';
@@ -44,23 +44,23 @@ pexprs.Apply.prototype.toFailure = function(grammar) {
44
44
  return new Failure(this, description, 'description');
45
45
  };
46
46
 
47
- pexprs.UnicodeChar.prototype.toFailure = function(grammar) {
48
- return new Failure(this, 'a Unicode [' + this.category + '] character', 'description');
47
+ pexprs.UnicodeChar.prototype.toFailure = function (grammar) {
48
+ return new Failure(this, 'a Unicode [' + this.categoryOrProp + '] character', 'description');
49
49
  };
50
50
 
51
- pexprs.Alt.prototype.toFailure = function(grammar) {
51
+ pexprs.Alt.prototype.toFailure = function (grammar) {
52
52
  const fs = this.terms.map(t => t.toFailure(grammar));
53
53
  const description = '(' + fs.join(' or ') + ')';
54
54
  return new Failure(this, description, 'description');
55
55
  };
56
56
 
57
- pexprs.Seq.prototype.toFailure = function(grammar) {
57
+ pexprs.Seq.prototype.toFailure = function (grammar) {
58
58
  const fs = this.factors.map(f => f.toFailure(grammar));
59
59
  const description = '(' + fs.join(' ') + ')';
60
60
  return new Failure(this, description, 'description');
61
61
  };
62
62
 
63
- pexprs.Iter.prototype.toFailure = function(grammar) {
63
+ pexprs.Iter.prototype.toFailure = function (grammar) {
64
64
  const description = '(' + this.expr.toFailure(grammar) + this.operator + ')';
65
65
  return new Failure(this, description, 'description');
66
66
  };
@@ -14,55 +14,55 @@ import * as pexprs from './pexprs-main.js';
14
14
  */
15
15
  pexprs.PExpr.prototype.toString = abstract('toString');
16
16
 
17
- pexprs.any.toString = function() {
17
+ pexprs.any.toString = function () {
18
18
  return 'any';
19
19
  };
20
20
 
21
- pexprs.end.toString = function() {
21
+ pexprs.end.toString = function () {
22
22
  return 'end';
23
23
  };
24
24
 
25
- pexprs.Terminal.prototype.toString = function() {
25
+ pexprs.Terminal.prototype.toString = function () {
26
26
  return JSON.stringify(this.obj);
27
27
  };
28
28
 
29
- pexprs.Range.prototype.toString = function() {
29
+ pexprs.Range.prototype.toString = function () {
30
30
  return JSON.stringify(this.from) + '..' + JSON.stringify(this.to);
31
31
  };
32
32
 
33
- pexprs.Param.prototype.toString = function() {
33
+ pexprs.Param.prototype.toString = function () {
34
34
  return '$' + this.index;
35
35
  };
36
36
 
37
- pexprs.Lex.prototype.toString = function() {
37
+ pexprs.Lex.prototype.toString = function () {
38
38
  return '#(' + this.expr.toString() + ')';
39
39
  };
40
40
 
41
- pexprs.Alt.prototype.toString = function() {
42
- return this.terms.length === 1 ?
43
- this.terms[0].toString() :
44
- '(' + this.terms.map(term => term.toString()).join(' | ') + ')';
41
+ pexprs.Alt.prototype.toString = function () {
42
+ return this.terms.length === 1
43
+ ? this.terms[0].toString()
44
+ : '(' + this.terms.map(term => term.toString()).join(' | ') + ')';
45
45
  };
46
46
 
47
- pexprs.Seq.prototype.toString = function() {
48
- return this.factors.length === 1 ?
49
- this.factors[0].toString() :
50
- '(' + this.factors.map(factor => factor.toString()).join(' ') + ')';
47
+ pexprs.Seq.prototype.toString = function () {
48
+ return this.factors.length === 1
49
+ ? this.factors[0].toString()
50
+ : '(' + this.factors.map(factor => factor.toString()).join(' ') + ')';
51
51
  };
52
52
 
53
- pexprs.Iter.prototype.toString = function() {
53
+ pexprs.Iter.prototype.toString = function () {
54
54
  return this.expr + this.operator;
55
55
  };
56
56
 
57
- pexprs.Not.prototype.toString = function() {
57
+ pexprs.Not.prototype.toString = function () {
58
58
  return '~' + this.expr;
59
59
  };
60
60
 
61
- pexprs.Lookahead.prototype.toString = function() {
61
+ pexprs.Lookahead.prototype.toString = function () {
62
62
  return '&' + this.expr;
63
63
  };
64
64
 
65
- pexprs.Apply.prototype.toString = function() {
65
+ pexprs.Apply.prototype.toString = function () {
66
66
  if (this.args.length > 0) {
67
67
  const ps = this.args.map(arg => arg.toString());
68
68
  return this.ruleName + '<' + ps.join(',') + '>';
@@ -71,6 +71,6 @@ pexprs.Apply.prototype.toString = function() {
71
71
  }
72
72
  };
73
73
 
74
- pexprs.UnicodeChar.prototype.toString = function() {
75
- return '\\p{' + this.category + '}';
74
+ pexprs.UnicodeChar.prototype.toString = function () {
75
+ return '\\p{' + this.categoryOrProp + '}';
76
76
  };
@@ -19,14 +19,14 @@ function initBuiltInSemantics(builtInRules) {
19
19
  };
20
20
 
21
21
  Semantics.BuiltInSemantics = Semantics.createSemantics(builtInRules, null).addOperation(
22
- 'asIteration',
23
- {
24
- emptyListOf: actions.empty,
25
- nonemptyListOf: actions.nonEmpty,
26
- EmptyListOf: actions.empty,
27
- NonemptyListOf: actions.nonEmpty,
28
- _iter: actions.self,
29
- },
22
+ 'asIteration',
23
+ {
24
+ emptyListOf: actions.empty,
25
+ nonemptyListOf: actions.nonEmpty,
26
+ EmptyListOf: actions.empty,
27
+ NonemptyListOf: actions.nonEmpty,
28
+ _iter: actions.self,
29
+ }
30
30
  );
31
31
  }
32
32
 
package/src/unicode.js ADDED
@@ -0,0 +1,54 @@
1
+ // The full list of categories from:
2
+ // https://www.unicode.org/Public/UCD/latest/ucd/extracted/DerivedGeneralCategory.txt.
3
+
4
+ const toRegExp = val => new RegExp(String.raw`\p{${val}}`, 'u');
5
+
6
+ /*
7
+ grep -v '^#' DerivedGeneralCategory.txt \
8
+ | cut -d';' -f2 \
9
+ | awk 'NF{print $1}' \
10
+ | sort -u \
11
+ | awk '{printf "\x27%s\x27,\n",$1}'
12
+ */
13
+
14
+ export const UnicodeCategories = Object.fromEntries(
15
+ [
16
+ 'Cc',
17
+ 'Cf',
18
+ 'Cn',
19
+ 'Co',
20
+ 'Cs',
21
+ 'Ll',
22
+ 'Lm',
23
+ 'Lo',
24
+ 'Lt',
25
+ 'Lu',
26
+ 'Mc',
27
+ 'Me',
28
+ 'Mn',
29
+ 'Nd',
30
+ 'Nl',
31
+ 'No',
32
+ 'Pc',
33
+ 'Pd',
34
+ 'Pe',
35
+ 'Pf',
36
+ 'Pi',
37
+ 'Po',
38
+ 'Ps',
39
+ 'Sc',
40
+ 'Sk',
41
+ 'Sm',
42
+ 'So',
43
+ 'Zl',
44
+ 'Zp',
45
+ 'Zs',
46
+ ].map(cat => [cat, toRegExp(cat)])
47
+ );
48
+ UnicodeCategories['Ltmo'] = /\p{Lt}|\p{Lm}|\p{Lo}/u;
49
+
50
+ // We only support a few of these for now, but could add more later.
51
+ // See https://www.unicode.org/Public/UCD/latest/ucd/PropertyAliases.txt
52
+ export const UnicodeBinaryProperties = Object.fromEntries(
53
+ ['XID_Start', 'XID_Continue', 'White_Space'].map(prop => [prop, toRegExp(prop)])
54
+ );
package/src/util.js CHANGED
@@ -134,9 +134,9 @@ export function getLineAndColumn(str, offset) {
134
134
  // Get the next line.
135
135
  const nextLineEndOffset = str.indexOf('\n', lineEndOffset + 1);
136
136
  nextLine =
137
- nextLineEndOffset === -1 ?
138
- str.slice(lineEndOffset) :
139
- str.slice(lineEndOffset, nextLineEndOffset);
137
+ nextLineEndOffset === -1
138
+ ? str.slice(lineEndOffset)
139
+ : str.slice(lineEndOffset, nextLineEndOffset);
140
140
  // Strip leading and trailing EOL char(s).
141
141
  nextLine = nextLine.replace(/^\r?\n/, '').replace(/\r$/, '');
142
142
  }
package/src/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by scripts/prebuild.js
2
- export const version = '17.2.1';
2
+ export const version = '17.3.0';
File without changes
@@ -1,30 +0,0 @@
1
- // These are just categories that are used in ES5/ES2015.
2
- // The full list of Unicode categories is here: http://www.fileformat.info/info/unicode/category/index.htm.
3
- export const UnicodeCategories = {
4
- // Letters
5
- Lu: /\p{Lu}/u,
6
- Ll: /\p{Ll}/u,
7
- Lt: /\p{Lt}/u,
8
- Lm: /\p{Lm}/u,
9
- Lo: /\p{Lo}/u,
10
-
11
- // Numbers
12
- Nl: /\p{Nl}/u,
13
- Nd: /\p{Nd}/u,
14
-
15
- // Marks
16
- Mn: /\p{Mn}/u,
17
- Mc: /\p{Mc}/u,
18
-
19
- // Punctuation, Connector
20
- Pc: /\p{Pc}/u,
21
-
22
- // Separator, Space
23
- Zs: /\p{Zs}/u,
24
-
25
- // These two are not real Unicode categories, but our useful for Ohm.
26
- // L is a combination of all the letter categories.
27
- // Ltmo is a combination of Lt, Lm, and Lo.
28
- L: /\p{Letter}/u,
29
- Ltmo: /\p{Lt}|\p{Lm}|\p{Lo}/u,
30
- };