occam-parsers 23.0.53 → 23.0.54

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 (85) hide show
  1. package/README.md +7 -7
  2. package/example.js +494 -167
  3. package/lib/bnf/bnf.js +2 -2
  4. package/lib/bnf/parser.js +4 -4
  5. package/lib/definition/{lookAheadModifierRule.js → callAheadModifierRule.js} +11 -11
  6. package/lib/definition/partRule/nonTerminal/ruleName.js +3 -3
  7. package/lib/example/basic/bnf.js +14 -0
  8. package/lib/example/basic/entries.js +18 -0
  9. package/lib/example/basic/lexer.js +136 -0
  10. package/lib/example/basic/parser.js +134 -0
  11. package/lib/example/view/basic.js +8 -8
  12. package/lib/example/view/div/sizeable.js +2 -2
  13. package/lib/node/bnf/{lookAheadModifier.js → callAheadModifier.js} +12 -12
  14. package/lib/node/bnf/choiceOfParts.js +4 -4
  15. package/lib/node/bnf/definition.js +3 -3
  16. package/lib/node/bnf/endOfLine.js +2 -2
  17. package/lib/node/bnf/epsilon.js +2 -2
  18. package/lib/node/bnf/noWhitespacePart.js +2 -2
  19. package/lib/node/bnf/part/nonTerminal.js +6 -6
  20. package/lib/node/bnf/part/terminal.js +3 -3
  21. package/lib/node/bnf/part.js +5 -5
  22. package/lib/node/bnf/partChoice.js +4 -4
  23. package/lib/node/bnf/regularExpression.js +2 -2
  24. package/lib/node/bnf/ruleName.js +3 -3
  25. package/lib/node/bnf/sequenceOfParts.js +4 -4
  26. package/lib/node/bnf/significantTokenType.js +2 -2
  27. package/lib/node/bnf/startOfContentPart.js +2 -2
  28. package/lib/node/bnf/terminalSymbol.js +2 -2
  29. package/lib/node/bnf/wildcard.js +2 -2
  30. package/lib/part/nonTerminal/choiceOfParts.js +4 -4
  31. package/lib/part/nonTerminal/oneOrMoreParts.js +4 -4
  32. package/lib/part/nonTerminal/optionalPart.js +4 -4
  33. package/lib/part/nonTerminal/ruleName.js +8 -8
  34. package/lib/part/nonTerminal/sequenceOfParts.js +4 -4
  35. package/lib/part/nonTerminal/zeroOrMoreParts.js +4 -4
  36. package/lib/part/nonTerminal.js +6 -6
  37. package/lib/part/terminal.js +5 -5
  38. package/lib/rule/{lookAheadModifier.js → callAheadModifier.js} +15 -15
  39. package/lib/rule.js +15 -9
  40. package/lib/ruleNames.js +5 -5
  41. package/lib/utilities/bnf.js +9 -9
  42. package/lib/utilities/parse.js +28 -28
  43. package/package.json +1 -1
  44. package/src/bnf/bnf.js +2 -2
  45. package/src/bnf/parser.js +3 -3
  46. package/src/definition/{lookAheadModifierRule.js → callAheadModifierRule.js} +3 -3
  47. package/src/definition/partRule/nonTerminal/ruleName.js +4 -4
  48. package/src/example/basic/bnf.js +27 -0
  49. package/src/example/basic/entries.js +9 -0
  50. package/src/example/basic/lexer.js +17 -0
  51. package/src/example/basic/parser.js +15 -0
  52. package/src/example/view/basic.js +13 -10
  53. package/src/example/view/div/sizeable.js +1 -1
  54. package/src/node/bnf/callAheadModifier.js +7 -0
  55. package/src/node/bnf/choiceOfParts.js +3 -3
  56. package/src/node/bnf/definition.js +2 -2
  57. package/src/node/bnf/endOfLine.js +1 -1
  58. package/src/node/bnf/epsilon.js +1 -1
  59. package/src/node/bnf/noWhitespacePart.js +1 -1
  60. package/src/node/bnf/part/nonTerminal.js +6 -6
  61. package/src/node/bnf/part/terminal.js +2 -2
  62. package/src/node/bnf/part.js +4 -4
  63. package/src/node/bnf/partChoice.js +3 -3
  64. package/src/node/bnf/regularExpression.js +1 -1
  65. package/src/node/bnf/ruleName.js +2 -2
  66. package/src/node/bnf/sequenceOfParts.js +3 -3
  67. package/src/node/bnf/significantTokenType.js +1 -1
  68. package/src/node/bnf/startOfContentPart.js +1 -1
  69. package/src/node/bnf/terminalSymbol.js +1 -1
  70. package/src/node/bnf/wildcard.js +1 -1
  71. package/src/part/nonTerminal/choiceOfParts.js +4 -4
  72. package/src/part/nonTerminal/oneOrMoreParts.js +4 -4
  73. package/src/part/nonTerminal/optionalPart.js +4 -4
  74. package/src/part/nonTerminal/ruleName.js +9 -9
  75. package/src/part/nonTerminal/sequenceOfParts.js +4 -4
  76. package/src/part/nonTerminal/zeroOrMoreParts.js +4 -4
  77. package/src/part/nonTerminal.js +4 -4
  78. package/src/part/terminal.js +3 -3
  79. package/src/rule/callAheadModifier.js +22 -0
  80. package/src/rule.js +21 -15
  81. package/src/ruleNames.js +1 -1
  82. package/src/utilities/bnf.js +6 -6
  83. package/src/utilities/parse.js +38 -28
  84. package/src/node/bnf/lookAheadModifier.js +0 -7
  85. package/src/rule/lookAheadModifier.js +0 -22
@@ -4,7 +4,7 @@ import WildcardPart from "../../part/terminal/wildcard";
4
4
  import NonTerminalNode from "../../node/nonTerminal";
5
5
 
6
6
  export default class WildcardBNFNode extends NonTerminalNode {
7
- generatePart(lookAhead) {
7
+ generatePart(callAhead) {
8
8
  const wildcardPart = WildcardPart.fromNothing();
9
9
 
10
10
  return wildcardPart;
@@ -6,8 +6,8 @@ import { parsePart } from "../../utilities/parse";
6
6
  import { ChoiceOfPartsPartType } from "../../partTypes";
7
7
 
8
8
  export default class ChoiceOfPartsPart extends NonTerminalPart {
9
- constructor(type, lookAhead, partChoices) {
10
- super(type, lookAhead);
9
+ constructor(type, callAhead, partChoices) {
10
+ super(type, callAhead);
11
11
 
12
12
  this.partChoices = partChoices;
13
13
  }
@@ -92,8 +92,8 @@ export default class ChoiceOfPartsPart extends NonTerminalPart {
92
92
 
93
93
  static fromPartChoices(partChoices) {
94
94
  const type = ChoiceOfPartsPartType,
95
- lookAhead = false,
96
- choiceOfPartsPart = new ChoiceOfPartsPart(type, lookAhead, partChoices);
95
+ callAhead = false,
96
+ choiceOfPartsPart = new ChoiceOfPartsPart(type, callAhead, partChoices);
97
97
 
98
98
  return choiceOfPartsPart;
99
99
  }
@@ -10,8 +10,8 @@ import { parseZeroOrMorePartsPart } from "./zeroOrMoreParts";
10
10
  const { plus } = specialSymbols;
11
11
 
12
12
  export default class OneOrMorePartsPart extends NonTerminalPart {
13
- constructor(type, lookAhead, part) {
14
- super(type, lookAhead);
13
+ constructor(type, callAhead, part) {
14
+ super(type, callAhead);
15
15
 
16
16
  this.part = part;
17
17
  }
@@ -48,8 +48,8 @@ export default class OneOrMorePartsPart extends NonTerminalPart {
48
48
 
49
49
  static fromPart(part) {
50
50
  const type = OneOrMorePartsPartType,
51
- lookAhead = false,
52
- oneOrMorePartsPart = new OneOrMorePartsPart(type, lookAhead, part);
51
+ callAhead = false,
52
+ oneOrMorePartsPart = new OneOrMorePartsPart(type, callAhead, part);
53
53
 
54
54
  return oneOrMorePartsPart;
55
55
  }
@@ -10,8 +10,8 @@ import { OptionalPartPartType } from "../../partTypes";
10
10
  const { questionMark } = specialSymbols;
11
11
 
12
12
  export default class OptionalPartPart extends NonTerminalPart {
13
- constructor(type, lookAhead, part) {
14
- super(type, lookAhead);
13
+ constructor(type, callAhead, part) {
14
+ super(type, callAhead);
15
15
 
16
16
  this.part = part;
17
17
  }
@@ -48,8 +48,8 @@ export default class OptionalPartPart extends NonTerminalPart {
48
48
 
49
49
  static fromPart(part) {
50
50
  const type = OptionalPartPartType,
51
- lookAhead = false,
52
- optionalPartPart = new OptionalPartPart(type, lookAhead, part);
51
+ callAhead = false,
52
+ optionalPartPart = new OptionalPartPart(type, callAhead, part);
53
53
 
54
54
  return optionalPartPart;
55
55
  }
@@ -10,8 +10,8 @@ import { RuleNamePartType } from "../../partTypes";
10
10
  const { ellipsis } = specialSymbols;
11
11
 
12
12
  export default class RuleNamePart extends NonTerminalPart {
13
- constructor(type, lookAhead, ruleName) {
14
- super(type, lookAhead);
13
+ constructor(type, callAAhead, ruleName) {
14
+ super(type, callAAhead);
15
15
 
16
16
  this.ruleName = ruleName;
17
17
  }
@@ -46,26 +46,26 @@ export default class RuleNamePart extends NonTerminalPart {
46
46
  }
47
47
 
48
48
  asString() {
49
- const lookAhead = this.isLookAhead(),
50
- lookAheadString = lookAhead ?
49
+ const callAAhead = this.isCallAhead(),
50
+ callAAheadString = callAAhead ?
51
51
  ellipsis :
52
52
  EMPTY_STRING,
53
- string = `${this.ruleName}${lookAheadString}`;
53
+ string = `${this.ruleName}${callAAheadString}`;
54
54
 
55
55
  return string;
56
56
  }
57
57
 
58
58
  static fromRuleName(ruleName) {
59
59
  const type = RuleNamePartType,
60
- lookAhead = false,
61
- ruleNamePart = new RuleNamePart(type, lookAhead, ruleName);
60
+ callAAhead = false,
61
+ ruleNamePart = new RuleNamePart(type, callAAhead, ruleName);
62
62
 
63
63
  return ruleNamePart;
64
64
  }
65
65
 
66
- static fromLookAheadAndRuleName(lookAhead, ruleName) {
66
+ static fromCallAheadAndRuleName(callAAhead, ruleName) {
67
67
  const type = RuleNamePartType,
68
- ruleNamePart = new RuleNamePart(type, lookAhead, ruleName);
68
+ ruleNamePart = new RuleNamePart(type, callAAhead, ruleName);
69
69
 
70
70
  return ruleNamePart;
71
71
  }
@@ -6,8 +6,8 @@ import { parseParts } from "../../utilities/parse";
6
6
  import { SequenceOfPartsPartType } from "../../partTypes";
7
7
 
8
8
  export default class SequenceOfPartsPart extends NonTerminalPart {
9
- constructor(type, lookAhead, parts) {
10
- super(type, lookAhead);
9
+ constructor(type, callAhead, parts) {
10
+ super(type, callAhead);
11
11
 
12
12
  this.parts = parts;
13
13
  }
@@ -64,8 +64,8 @@ export default class SequenceOfPartsPart extends NonTerminalPart {
64
64
 
65
65
  static fromParts(parts) {
66
66
  const type = SequenceOfPartsPartType,
67
- lookAhead = false,
68
- sequenceOfPartsPart = new SequenceOfPartsPart(type, lookAhead, parts);
67
+ callAhead = false,
68
+ sequenceOfPartsPart = new SequenceOfPartsPart(type, callAhead, parts);
69
69
 
70
70
  return sequenceOfPartsPart;
71
71
  }
@@ -10,8 +10,8 @@ import { ZeroOrMorePartsPartType } from "../../partTypes";
10
10
  const { asterisk } = specialSymbols;
11
11
 
12
12
  export default class ZeroOrMorePartsPart extends NonTerminalPart {
13
- constructor(type, lookAhead, part) {
14
- super(type, lookAhead);
13
+ constructor(type, callAhead, part) {
14
+ super(type, callAhead);
15
15
 
16
16
  this.part = part;
17
17
  }
@@ -48,8 +48,8 @@ export default class ZeroOrMorePartsPart extends NonTerminalPart {
48
48
 
49
49
  static fromPart(part) {
50
50
  const type = ZeroOrMorePartsPartType,
51
- lookAhead = false,
52
- zeroOrMorePartsPart = new ZeroOrMorePartsPart(type, lookAhead, part);
51
+ callAhead = false,
52
+ zeroOrMorePartsPart = new ZeroOrMorePartsPart(type, callAhead, part);
53
53
 
54
54
  return zeroOrMorePartsPart;
55
55
  }
@@ -1,17 +1,17 @@
1
1
  "use strict";
2
2
 
3
3
  export default class NonTerminalPart {
4
- constructor(type, lookAhead) {
4
+ constructor(type, callAhead) {
5
5
  this.type = type;
6
- this.lookAhead = lookAhead;
6
+ this.callAhead = callAhead;
7
7
  }
8
8
 
9
9
  getType() {
10
10
  return this.type;
11
11
  }
12
12
 
13
- isLookAhead() {
14
- return this.lookAhead;
13
+ isCallAhead() {
14
+ return this.callAhead;
15
15
  }
16
16
 
17
17
  isNonTerminalPart() {
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
 
3
3
  export default class TerminalPart {
4
- isLookAhead() {
5
- const lookAhead = false;
4
+ isCallAhead() {
5
+ const callAhead = false;
6
6
 
7
- return lookAhead;
7
+ return callAhead;
8
8
  }
9
9
 
10
10
  isNonTerminalPart() {
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+
3
+ import Rule from "../rule";
4
+ import CallAheadModifierBNFNode from "../node/bnf/callAheadModifier";
5
+ import CallAheadModifierRuleDefinition from "../definition/callAheadModifierRule";
6
+
7
+ import { callAheadModifierRuleName } from "../ruleNames";
8
+
9
+ export default class CallAheadModifierRule extends Rule {
10
+ static fromNothing() {
11
+ const name = callAheadModifierRuleName, ///
12
+ callAheadModifierRuleDefinition = CallAheadModifierRuleDefinition.fromNothing(),
13
+ opacity = null,
14
+ definitions = [
15
+ callAheadModifierRuleDefinition
16
+ ],
17
+ NonTerminalNode = CallAheadModifierBNFNode, ///
18
+ callAheadModifierRule = new CallAheadModifierRule(name, opacity, definitions, NonTerminalNode);
19
+
20
+ return callAheadModifierRule;
21
+ }
22
+ }
package/src/rule.js CHANGED
@@ -4,7 +4,7 @@ import { EMPTY_STRING } from "./constants";
4
4
  import { specialSymbols } from "occam-lexers";
5
5
  import { paddingFromPaddingLength } from "./utilities/string";
6
6
 
7
- const { opaque : opaqueSpecialSymbol , semiOpaque: semiOpaqueSpecialSymbol } = specialSymbols;
7
+ const { opaque: opaqueSpecialSymbol, semiOpaque: semiOpaqueSpecialSymbol } = specialSymbols;
8
8
 
9
9
  export default class Rule {
10
10
  constructor(name, opacity, definitions, NonTerminalNode) {
@@ -46,6 +46,15 @@ export default class Rule {
46
46
  this.NonTerminalNode = NonTerminalNode;
47
47
  }
48
48
 
49
+ createNonTerminalNode() {
50
+ const opacity = this.opacity,
51
+ ruleName = this.name, ///
52
+ childNodes = [],
53
+ nonTerminalNode = this.NonTerminalNode.fromRuleNameChildNodesAndOpacity(ruleName, childNodes, opacity);
54
+
55
+ return nonTerminalNode;
56
+ }
57
+
49
58
  isOpaque() {
50
59
  const opaque = (this.opacity === opaqueSpecialSymbol);
51
60
 
@@ -64,24 +73,19 @@ export default class Rule {
64
73
  const savedPrecedence = state.getSavedPrecedence();
65
74
 
66
75
  parsed = this.definitions.some((definition) => {
67
- let node,
68
- nonTerminalNode;
69
-
70
- const ruleName = this.name,
71
- opacity = this.opacity,
72
- childNodes = [];
73
-
74
- nonTerminalNode = this.NonTerminalNode.fromRuleNameChildNodesAndOpacity(ruleName, childNodes, opacity);
76
+ let parsed;
75
77
 
76
- const precedence = definition.getPrecedence();
78
+ let nonTerminalNode = this.createNonTerminalNode(),
79
+ node = nonTerminalNode; ///
77
80
 
78
- node = nonTerminalNode; ///
81
+ const precedence = definition.getPrecedence(),
82
+ childNodes = nonTerminalNode.getChildNodes();
79
83
 
80
84
  nodes.push(node);
81
85
 
82
86
  state.setPrecedence(precedence);
83
87
 
84
- const parsed = definition.parse(childNodes, state, () => {
88
+ callback = () => { ///
85
89
  let parsed;
86
90
 
87
91
  parsed = true;
@@ -137,12 +141,14 @@ export default class Rule {
137
141
  }
138
142
 
139
143
  return parsed;
140
- }, callAhead);
144
+ };
141
145
 
142
- if (!parsed) {
143
- nodes.pop();
146
+ parsed = definition.parse(childNodes, state, callback, callAhead);
144
147
 
148
+ if (!parsed) {
145
149
  state.resetPrecedence(savedPrecedence);
150
+
151
+ nodes.pop();
146
152
  }
147
153
 
148
154
  return parsed;
package/src/ruleNames.js CHANGED
@@ -21,7 +21,7 @@ export const nonTerminalPartRuleName = "nonTerminalPart";
21
21
  export const sequenceOfPartsRuleName = "sequenceOfParts";
22
22
  export const opacityModifierRuleName = "opacityModifier";
23
23
  export const noWhitespacePartRuleName = "noWhitespace";
24
- export const lookAheadModifierRuleName = "lookAheadModifier";
24
+ export const CallAheadModifierRuleName = "callAheadModifier";
25
25
  export const regularExpressionRuleName = "regularExpression";
26
26
  export const optionalQuantifierRuleName = "optionalQuantifier";
27
27
  export const startOfContentPartRuleName = "startOfContent";
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { arrayUtilities } from "necessary";
4
4
 
5
- import { ruleNameRuleName, quantifierRuleName, lookAheadModifierRuleName } from "../ruleNames";
5
+ import { ruleNameRuleName, quantifierRuleName, callAheadModifierRuleName } from "../ruleNames";
6
6
 
7
7
  const { first } = arrayUtilities;
8
8
 
@@ -53,20 +53,20 @@ export function isNodeQuantifierNode(node) {
53
53
  return nodeQuantifierNode;
54
54
  }
55
55
 
56
- export function isNodeLookAheadModifierNode(node) {
57
- let nodeLookAheadModifierNode = false;
56
+ export function isNodeCallAheadModifierNode(node) {
57
+ let nodeCallAheadModifierNode = false;
58
58
 
59
59
  const nodeNonTerminalNode = node.isNonTerminalNode();
60
60
 
61
61
  if (nodeNonTerminalNode) {
62
62
  const nonTerminalNode = node, ///
63
63
  ruleName = nonTerminalNode.getRuleName(),
64
- ruleNameLookAheadModifierRuleName = (ruleName === lookAheadModifierRuleName);
64
+ ruleNameCallAheadModifierRuleName = (ruleName === callAheadModifierRuleName);
65
65
 
66
- nodeLookAheadModifierNode = ruleNameLookAheadModifierRuleName; ///
66
+ nodeCallAheadModifierNode = ruleNameCallAheadModifierRuleName; ///
67
67
  }
68
68
 
69
- return nodeLookAheadModifierNode;
69
+ return nodeCallAheadModifierNode;
70
70
 
71
71
  }
72
72
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { arrayUtilities } from "necessary";
4
4
 
5
- const { push } = arrayUtilities;
5
+ const { push, clear } = arrayUtilities;
6
6
 
7
7
  export function parsePart(part, nodes, state, callback, callAhead) {
8
8
  let parsed;
@@ -37,44 +37,54 @@ function parsePartOfParts(index, parts, nodes, state, callback, callAhead) {
37
37
  callback() :
38
38
  true;
39
39
  } else {
40
- const part = parts[index];
40
+ const part = parts[index],
41
+ partCallAhead = (callAhead === null) ?
42
+ part.isCallAhead() :
43
+ true;
41
44
 
42
45
  index++;
43
46
 
44
- if (callAhead === null) {
45
- const partLookAhead = part.isLookAhead();
47
+ parsed = partCallAhead ?
48
+ parsePartWithCallAhead(part, index, parts, nodes, state, callback, callAhead) :
49
+ parsePartWithoutCallAhead(part, index, parts, nodes, state, callback, callAhead);
50
+ }
51
+
52
+ return parsed;
53
+ }
54
+
55
+ function parsePartWithCallAhead(part, index, parts, nodes, state, callback, callAhead) {
56
+ let parsed;
57
+
58
+ const partNodes = [];
46
59
 
47
- if (partLookAhead) {
48
- let partNodes;
60
+ callAhead = () => { ///
61
+ let parsed;
49
62
 
50
- parsed = part.parse(nodes, state, callback, () => {
51
- partNodes = [];
63
+ clear(partNodes);
52
64
 
53
- const nodes = partNodes, ///
54
- parsed = parsePartOfParts(index, parts, nodes, state, callback, callAhead);
65
+ const nodes = partNodes; ///
55
66
 
56
- return parsed;
57
- });
67
+ parsed = parsePartOfParts(index, parts, nodes, state, callback, callAhead);
58
68
 
59
- if (parsed) {
60
- push(nodes, partNodes);
61
- }
62
- } else {
63
- parsed = part.parse(nodes, state, callback, callAhead);
69
+ return parsed;
70
+ };
64
71
 
65
- if (parsed) {
66
- parsed = parsePartOfParts(index, parts, nodes, state, callback, callAhead);
67
- }
68
- }
69
- } else {
70
- parsed = part.parse(nodes, state, callback, () => {
71
- let parsed;
72
+ parsed = part.parse(nodes, state, callback, callAhead);
73
+
74
+ if (parsed) {
75
+ push(nodes, partNodes);
76
+ }
77
+
78
+ return parsed;
79
+ }
80
+
81
+ function parsePartWithoutCallAhead(part, index, parts, nodes, state, callback, callAhead) {
82
+ let parsed;
72
83
 
73
- parsed = parsePartOfParts(index, parts, nodes, state, callback, callAhead);
84
+ parsed = part.parse(nodes, state, callback, callAhead);
74
85
 
75
- return parsed;
76
- });
77
- }
86
+ if (parsed) {
87
+ parsed = parsePartOfParts(index, parts, nodes, state, callback, callAhead);
78
88
  }
79
89
 
80
90
  return parsed;
@@ -1,7 +0,0 @@
1
- "use strict";
2
-
3
- import NonTerminalNode from "../../node/nonTerminal";
4
-
5
- export default class LookAheadModifierBNFNode extends NonTerminalNode {
6
- static fromRuleNameChildNodesAndLookAhead(ruleName, childNode, opacity) { return NonTerminalNode.fromRuleNameChildNodesAndLookAhead(LookAheadModifierBNFNode, ruleName, childNode, opacity); }
7
- }
@@ -1,22 +0,0 @@
1
- "use strict";
2
-
3
- import Rule from "../rule";
4
- import LookAheadModifierBNFNode from "../node/bnf/lookAheadModifier";
5
- import LookAheadModifierRuleDefinition from "../definition/lookAheadModifierRule";
6
-
7
- import { lookAheadModifierRuleName } from "../ruleNames";
8
-
9
- export default class LookAheadModifierRule extends Rule {
10
- static fromNothing() {
11
- const name = lookAheadModifierRuleName, ///
12
- lookAheadModifierRuleDefinition = LookAheadModifierRuleDefinition.fromNothing(),
13
- opacity = null,
14
- definitions = [
15
- lookAheadModifierRuleDefinition
16
- ],
17
- NonTerminalNode = LookAheadModifierBNFNode, ///
18
- lookAheadModifierRule = new LookAheadModifierRule(name, opacity, definitions, NonTerminalNode);
19
-
20
- return lookAheadModifierRule;
21
- }
22
- }