clarity-pattern-parser 11.5.4 → 11.6.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.
- package/architecture.md +300 -0
- package/dist/grammar/Grammar.d.ts +24 -25
- package/dist/grammar/patterns/grammar.d.ts +99 -0
- package/dist/grammar/patterns/grammar.test.d.ts +1 -0
- package/dist/index.browser.js +2314 -2592
- package/dist/index.browser.js.map +1 -1
- package/dist/index.esm.js +2314 -2592
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +2314 -2592
- package/dist/index.js.map +1 -1
- package/grammar-guide.md +836 -0
- package/package.json +1 -1
- package/src/grammar/Grammar.test.ts +418 -0
- package/src/grammar/Grammar.ts +483 -515
- package/src/grammar/patterns/grammar.test.ts +276 -0
- package/src/grammar/patterns/grammar.ts +113 -37
- package/src/grammar/patterns.ts +6 -6
- package/src/grammar/patterns/anonymousPattern.ts +0 -23
- package/src/grammar/patterns/body.ts +0 -22
- package/src/grammar/patterns/comment.ts +0 -4
- package/src/grammar/patterns/decoratorStatement.ts +0 -85
- package/src/grammar/patterns/import.ts +0 -88
- package/src/grammar/patterns/literal.ts +0 -4
- package/src/grammar/patterns/literals.ts +0 -21
- package/src/grammar/patterns/name.ts +0 -3
- package/src/grammar/patterns/optionsLiteral.ts +0 -25
- package/src/grammar/patterns/pattern.ts +0 -29
- package/src/grammar/patterns/regexLiteral.ts +0 -5
- package/src/grammar/patterns/repeatLiteral.ts +0 -71
- package/src/grammar/patterns/sequenceLiteral.ts +0 -24
- package/src/grammar/patterns/spaces.ts +0 -16
- package/src/grammar/patterns/statement.ts +0 -22
- package/src/grammar/patterns/takeUtilLiteral.ts +0 -20
- package/src/grammar/spec.md +0 -331
- package/src/grammar_v2/patterns/Grammar.ts +0 -170
- package/src/grammar_v2/patterns/patterns/cpat.cpat +0 -91
- package/src/grammar_v2/patterns/patterns/grammar.test.ts +0 -218
- package/src/grammar_v2/patterns/patterns/grammar.ts +0 -103
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { Sequence } from "../../patterns/Sequence";
|
|
2
|
-
import { Repeat } from "../../patterns/Repeat";
|
|
3
|
-
import { Literal } from "../../patterns/Literal";
|
|
4
|
-
import { Regex } from "../../patterns/Regex";
|
|
5
|
-
import { literal } from "./literal";
|
|
6
|
-
import { Options } from "../../patterns/Options";
|
|
7
|
-
import { body } from "./body";
|
|
8
|
-
import { allSpaces, lineSpaces } from "./spaces";
|
|
9
|
-
import { Optional } from "../../patterns/Optional";
|
|
10
|
-
|
|
11
|
-
const optionalSpaces = new Optional("optional-spaces", allSpaces);
|
|
12
|
-
const optionalLineSpaces = new Optional("optional-line-spaces", lineSpaces);
|
|
13
|
-
|
|
14
|
-
const importNameDivider = new Regex("import-name-divider", "(\\s+)?,(\\s+)?");
|
|
15
|
-
importNameDivider.setTokens([", "]);
|
|
16
|
-
|
|
17
|
-
const name = new Regex("import-name", "[^}\\s,]+");
|
|
18
|
-
name.setTokens(["[IMPORT_NAME]"]);
|
|
19
|
-
|
|
20
|
-
const importKeyword = new Literal("import", "import");
|
|
21
|
-
const useParamsKeyword = new Literal("use-params", "use params");
|
|
22
|
-
const asKeyword = new Literal("as", "as");
|
|
23
|
-
const fromKeyword = new Literal("from", "from");
|
|
24
|
-
const openBracket = new Literal("open-bracket", "{");
|
|
25
|
-
const closeBracket = new Literal("close-bracket", "}");
|
|
26
|
-
const equal = new Literal("equal", "=");
|
|
27
|
-
|
|
28
|
-
const importNameAlias = name.clone("import-name-alias");
|
|
29
|
-
const importAlias = new Sequence("import-alias", [name, lineSpaces, asKeyword, lineSpaces, importNameAlias]);
|
|
30
|
-
const importedNames = new Repeat("imported-names", new Options("import-names", [importAlias, name]), { divider: importNameDivider });
|
|
31
|
-
const paramName = name.clone("param-name");
|
|
32
|
-
const defaultParamName = name.clone("default-param-name");
|
|
33
|
-
|
|
34
|
-
const paramNameWithDefault = new Sequence("param-name-with-default-value", [
|
|
35
|
-
paramName,
|
|
36
|
-
new Optional("optional-param-default", new Sequence("param-default", [
|
|
37
|
-
optionalLineSpaces,
|
|
38
|
-
equal,
|
|
39
|
-
optionalLineSpaces,
|
|
40
|
-
defaultParamName,
|
|
41
|
-
])),
|
|
42
|
-
]);
|
|
43
|
-
const paramNames = new Repeat("param-names", paramNameWithDefault, { divider: importNameDivider });
|
|
44
|
-
const resource = literal.clone("resource");
|
|
45
|
-
|
|
46
|
-
const useParams = new Sequence("import-params", [
|
|
47
|
-
useParamsKeyword,
|
|
48
|
-
optionalLineSpaces,
|
|
49
|
-
openBracket,
|
|
50
|
-
optionalSpaces,
|
|
51
|
-
paramNames,
|
|
52
|
-
optionalSpaces,
|
|
53
|
-
closeBracket
|
|
54
|
-
]);
|
|
55
|
-
|
|
56
|
-
const withParamsKeyword = new Literal("with-params", "with params");
|
|
57
|
-
const withParamsStatement = new Optional("optional-with-params-statement", new Sequence("with-params-statement", [
|
|
58
|
-
withParamsKeyword,
|
|
59
|
-
optionalLineSpaces,
|
|
60
|
-
openBracket,
|
|
61
|
-
optionalSpaces,
|
|
62
|
-
body,
|
|
63
|
-
optionalSpaces,
|
|
64
|
-
closeBracket
|
|
65
|
-
]));
|
|
66
|
-
|
|
67
|
-
const importFromStatement = new Sequence("import-from", [
|
|
68
|
-
importKeyword,
|
|
69
|
-
optionalLineSpaces,
|
|
70
|
-
openBracket,
|
|
71
|
-
optionalSpaces,
|
|
72
|
-
importedNames,
|
|
73
|
-
optionalSpaces,
|
|
74
|
-
closeBracket,
|
|
75
|
-
optionalLineSpaces,
|
|
76
|
-
fromKeyword,
|
|
77
|
-
optionalLineSpaces,
|
|
78
|
-
resource,
|
|
79
|
-
optionalLineSpaces,
|
|
80
|
-
withParamsStatement
|
|
81
|
-
]);
|
|
82
|
-
|
|
83
|
-
export const importStatement = new Options("import-statement", [
|
|
84
|
-
useParams,
|
|
85
|
-
importFromStatement
|
|
86
|
-
]);
|
|
87
|
-
|
|
88
|
-
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Options } from "../../patterns/Options";
|
|
2
|
-
import { Reference } from "../../patterns/Reference";
|
|
3
|
-
import { literal } from "./literal";
|
|
4
|
-
import { name } from "./name";
|
|
5
|
-
import { regexLiteral } from "./regexLiteral";
|
|
6
|
-
|
|
7
|
-
const patternName = name.clone("pattern-name");
|
|
8
|
-
|
|
9
|
-
export const anonymousLiterals = new Options("anonymous-literals", [
|
|
10
|
-
literal,
|
|
11
|
-
regexLiteral,
|
|
12
|
-
patternName,
|
|
13
|
-
new Reference("repeat-literal"),
|
|
14
|
-
]);
|
|
15
|
-
|
|
16
|
-
export const anonymousWrappedLiterals = new Options("anonymous-wrapped-literals", [
|
|
17
|
-
new Reference("take-until-literal"),
|
|
18
|
-
new Reference("options-literal"),
|
|
19
|
-
new Reference("sequence-literal"),
|
|
20
|
-
new Reference("complex-anonymous-pattern")
|
|
21
|
-
]);
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Repeat } from "../../patterns/Repeat";
|
|
2
|
-
import { Regex } from "../../patterns/Regex";
|
|
3
|
-
import { name } from "./name";
|
|
4
|
-
import { anonymousPattern } from "./anonymousPattern";
|
|
5
|
-
import { Options } from "../../patterns/Options";
|
|
6
|
-
import { Sequence } from "../../patterns/Sequence";
|
|
7
|
-
import { Optional } from "../../patterns/Optional";
|
|
8
|
-
import { Literal } from "../../patterns/Literal";
|
|
9
|
-
|
|
10
|
-
const patternName = name.clone("pattern-name");
|
|
11
|
-
patternName.setTokens(["[PATTERN_NAME]"]);
|
|
12
|
-
|
|
13
|
-
const patterns = new Sequence("patterns", [
|
|
14
|
-
new Options("options-patterns", [patternName, anonymousPattern]),
|
|
15
|
-
new Optional("optional-right-associated", new Literal("right-associated", " right"))
|
|
16
|
-
]);
|
|
17
|
-
const defaultDivider = new Regex("default-divider", "\\s*[|]\\s*");
|
|
18
|
-
defaultDivider.setTokens(["|"]);
|
|
19
|
-
|
|
20
|
-
const greedyDivider = new Regex("greedy-divider", "\\s*[<][|][>]\\s*");
|
|
21
|
-
greedyDivider.setTokens(["<|>"]);
|
|
22
|
-
|
|
23
|
-
const divider = new Options("options-divider", [defaultDivider, greedyDivider]);
|
|
24
|
-
|
|
25
|
-
export const optionsLiteral = new Repeat("options-literal", patterns, { divider, min: 2, trimDivider: true });
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { Options } from "../../patterns/Options";
|
|
2
|
-
import { literal } from "./literal";
|
|
3
|
-
import { regexLiteral } from "./regexLiteral";
|
|
4
|
-
import { repeatLiteral } from "./repeatLiteral";
|
|
5
|
-
import { sequenceLiteral } from "./sequenceLiteral";
|
|
6
|
-
import { optionsLiteral } from "./optionsLiteral";
|
|
7
|
-
import { anonymousPattern } from "./anonymousPattern";
|
|
8
|
-
import { takeUntilLiteral } from "./takeUtilLiteral";
|
|
9
|
-
import { Sequence } from "../../patterns/Sequence";
|
|
10
|
-
import { Literal } from "../../patterns/Literal";
|
|
11
|
-
import { name } from "./name";
|
|
12
|
-
import { Optional } from "../../patterns/Optional";
|
|
13
|
-
|
|
14
|
-
const aliasLiteral = name.clone("alias-literal");
|
|
15
|
-
aliasLiteral.setTokens(["[ALIAS_LITERAL]"]);
|
|
16
|
-
|
|
17
|
-
const optionalIsOptional = new Optional("optional-flag", new Literal("is-optional", "?"));
|
|
18
|
-
const configurableAnonymousPattern = new Sequence("configurable-anonymous-pattern", [anonymousPattern, optionalIsOptional]);
|
|
19
|
-
|
|
20
|
-
export const pattern = new Options("pattern", [
|
|
21
|
-
literal,
|
|
22
|
-
regexLiteral,
|
|
23
|
-
repeatLiteral,
|
|
24
|
-
takeUntilLiteral,
|
|
25
|
-
aliasLiteral,
|
|
26
|
-
optionsLiteral,
|
|
27
|
-
sequenceLiteral,
|
|
28
|
-
configurableAnonymousPattern,
|
|
29
|
-
], true);
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { Sequence } from "../../patterns/Sequence";
|
|
2
|
-
import { Literal } from "../../patterns/Literal";
|
|
3
|
-
import { Options } from "../../patterns/Options";
|
|
4
|
-
import { Regex } from "../../patterns/Regex";
|
|
5
|
-
import { anonymousPattern } from "./anonymousPattern";
|
|
6
|
-
import { name } from "./name";
|
|
7
|
-
import { lineSpaces, spaces } from "./spaces";
|
|
8
|
-
import { Optional } from "../../patterns/Optional";
|
|
9
|
-
|
|
10
|
-
const optionalSpaces = new Optional("optional-spaces", spaces);
|
|
11
|
-
const openBracket = new Literal("repeat-open-bracket", "{");
|
|
12
|
-
const closeBracket = new Literal("repeat-close-bracket", "}");
|
|
13
|
-
const comma = new Literal("comma", ",");
|
|
14
|
-
|
|
15
|
-
const integer = new Regex("integer", "([1-9][0-9]*)|0");
|
|
16
|
-
integer.setTokens(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
|
|
17
|
-
|
|
18
|
-
const min = new Optional("optional-min", integer.clone("min"));
|
|
19
|
-
const max = new Optional("optional-max", integer.clone("max"));
|
|
20
|
-
const trimKeyword = new Literal("trim-keyword", "trim");
|
|
21
|
-
const trimFlag = new Optional("optional-trim-flag", new Sequence("trim-flag", [lineSpaces, trimKeyword]));
|
|
22
|
-
|
|
23
|
-
const bounds = new Sequence("bounds", [
|
|
24
|
-
openBracket,
|
|
25
|
-
optionalSpaces,
|
|
26
|
-
min,
|
|
27
|
-
optionalSpaces,
|
|
28
|
-
comma,
|
|
29
|
-
optionalSpaces,
|
|
30
|
-
max,
|
|
31
|
-
closeBracket
|
|
32
|
-
]);
|
|
33
|
-
|
|
34
|
-
const exactCount = new Sequence("exact-count", [
|
|
35
|
-
openBracket,
|
|
36
|
-
optionalSpaces,
|
|
37
|
-
integer,
|
|
38
|
-
optionalSpaces,
|
|
39
|
-
closeBracket,
|
|
40
|
-
]);
|
|
41
|
-
|
|
42
|
-
const quantifierShorthand = new Regex("quantifier-shorthand", "\\*|\\+");
|
|
43
|
-
quantifierShorthand.setTokens(["*", "+"]);
|
|
44
|
-
|
|
45
|
-
const quantifier = new Options("quantifier", [
|
|
46
|
-
quantifierShorthand,
|
|
47
|
-
exactCount,
|
|
48
|
-
bounds
|
|
49
|
-
]);
|
|
50
|
-
|
|
51
|
-
const openParen = new Literal("repeat-open-paren", "(");
|
|
52
|
-
const closeParen = new Literal("repeat-close-paren", ")");
|
|
53
|
-
const dividerComma = new Regex("divider-comma", "\\s*,\\s*");
|
|
54
|
-
dividerComma.setTokens([", "]);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const patternName = name.clone("pattern-name");
|
|
58
|
-
const repeatPattern = new Options("repeat-pattern", [patternName, anonymousPattern]);
|
|
59
|
-
const repeatDividerPattern = repeatPattern.clone("repeat-divider-pattern");
|
|
60
|
-
const repeatDividerSection = new Sequence("repeat-divider-section", [dividerComma, repeatDividerPattern, trimFlag]);
|
|
61
|
-
const repeatOptionalDividerSection = new Optional("repeat-optional-divider-section", repeatDividerSection);
|
|
62
|
-
|
|
63
|
-
export const repeatLiteral = new Sequence("repeat-literal", [
|
|
64
|
-
openParen,
|
|
65
|
-
optionalSpaces,
|
|
66
|
-
repeatPattern,
|
|
67
|
-
repeatOptionalDividerSection,
|
|
68
|
-
optionalSpaces,
|
|
69
|
-
closeParen,
|
|
70
|
-
new Sequence("quantifier-section", [quantifier]),
|
|
71
|
-
]);
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Repeat } from "../../patterns/Repeat";
|
|
2
|
-
import { Regex } from "../../patterns/Regex";
|
|
3
|
-
import { name } from "./name";
|
|
4
|
-
import { anonymousPattern } from "./anonymousPattern";
|
|
5
|
-
import { Options } from "../../patterns/Options";
|
|
6
|
-
import { Sequence } from "../../patterns/Sequence";
|
|
7
|
-
import { Literal } from "../../patterns/Literal";
|
|
8
|
-
import { Optional } from "../../patterns/Optional";
|
|
9
|
-
|
|
10
|
-
const optionalNot = new Optional("optional-not", new Literal("not", "!"));
|
|
11
|
-
const optionalIsOptional = new Optional("optional-is-optional", new Literal("is-optional", "?"));
|
|
12
|
-
const patternName = name.clone("pattern-name");
|
|
13
|
-
const patterns = new Options("sequence-patterns", [patternName, anonymousPattern]);
|
|
14
|
-
|
|
15
|
-
export const pattern = new Sequence("sequence-child-pattern", [
|
|
16
|
-
optionalNot,
|
|
17
|
-
patterns,
|
|
18
|
-
optionalIsOptional,
|
|
19
|
-
]);
|
|
20
|
-
|
|
21
|
-
const divider = new Regex("sequence-divider", "\\s*[+]\\s*");
|
|
22
|
-
divider.setTokens([" + "]);
|
|
23
|
-
|
|
24
|
-
export const sequenceLiteral = new Repeat("sequence-literal", pattern, { divider, min: 2, trimDivider: true });
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { Options } from "../../patterns/Options";
|
|
2
|
-
import { Regex } from "../../patterns/Regex";
|
|
3
|
-
import { Repeat } from "../../patterns/Repeat";
|
|
4
|
-
|
|
5
|
-
export const tabs = new Regex("tabs", "\\t+");
|
|
6
|
-
tabs.setTokens(["\t"]);
|
|
7
|
-
|
|
8
|
-
export const spaces = new Regex("spaces", "[ ]+");
|
|
9
|
-
spaces.setTokens([" "]);
|
|
10
|
-
|
|
11
|
-
export const newLine = new Regex("new-line", "(\\r?\\n)+");
|
|
12
|
-
newLine.setTokens(["\n"]);
|
|
13
|
-
|
|
14
|
-
export const lineSpaces = new Repeat("line-spaces", new Options("line-space", [tabs, spaces]));
|
|
15
|
-
export const allSpaces = new Regex("all-spaces", "\\s+");
|
|
16
|
-
allSpaces.setTokens([" "]);
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { Sequence } from "../../patterns/Sequence";
|
|
2
|
-
import { Literal } from "../../patterns/Literal";
|
|
3
|
-
import { Options } from "../../patterns/Options";
|
|
4
|
-
import { name } from "./name";
|
|
5
|
-
import { spaces } from "./spaces";
|
|
6
|
-
import { pattern } from "./pattern";
|
|
7
|
-
import { Optional } from "../../patterns/Optional";
|
|
8
|
-
import {decoratorStatement} from './decoratorStatement';
|
|
9
|
-
|
|
10
|
-
const optionalSpaces = new Optional("optional-spaces", spaces);
|
|
11
|
-
const assignOperator = new Literal("assign-operator", "=");
|
|
12
|
-
|
|
13
|
-
const assignStatement = new Sequence("assign-statement", [
|
|
14
|
-
optionalSpaces,
|
|
15
|
-
name,
|
|
16
|
-
optionalSpaces,
|
|
17
|
-
assignOperator,
|
|
18
|
-
optionalSpaces,
|
|
19
|
-
pattern,
|
|
20
|
-
]);
|
|
21
|
-
|
|
22
|
-
export const statement = new Options("statement", [decoratorStatement, assignStatement, name.clone("export-name")]);
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Literal } from "../../patterns/Literal"
|
|
2
|
-
import { Optional } from "../../patterns/Optional";
|
|
3
|
-
import { Sequence } from "../../patterns/Sequence";
|
|
4
|
-
import { lineSpaces } from "./spaces";
|
|
5
|
-
import { Reference } from "../../patterns/Reference";
|
|
6
|
-
|
|
7
|
-
const anyChar = new Literal("any-char", "?");
|
|
8
|
-
const upTo = new Literal("up-to", "->");
|
|
9
|
-
const wall = new Literal("wall", "|");
|
|
10
|
-
const optionalLineSpaces = new Optional("optional-line-spaces", lineSpaces);
|
|
11
|
-
|
|
12
|
-
export const takeUntilLiteral = new Sequence("take-until-literal", [
|
|
13
|
-
anyChar,
|
|
14
|
-
optionalLineSpaces,
|
|
15
|
-
upTo,
|
|
16
|
-
optionalLineSpaces,
|
|
17
|
-
wall,
|
|
18
|
-
optionalLineSpaces,
|
|
19
|
-
new Reference("pattern")
|
|
20
|
-
]);
|
package/src/grammar/spec.md
DELETED
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
# Grammar Documentation
|
|
2
|
-
|
|
3
|
-
This guide describes the syntax rules and composition patterns supported by cpat. Each section shows how to define reusable parsing rules.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Literals
|
|
8
|
-
|
|
9
|
-
A **literal** matches an exact string.
|
|
10
|
-
|
|
11
|
-
```grammar
|
|
12
|
-
name = "Literal"
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Regex
|
|
18
|
-
|
|
19
|
-
A **regex** pattern matches text using a regular expression.
|
|
20
|
-
|
|
21
|
-
```grammar
|
|
22
|
-
digits = /\d+/
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### Regex Caveats
|
|
26
|
-
Do **not** use `^` at the start or `$` at the end of your regex. If you want to constrain the beginning or end of the input, use a dedicated pattern instead.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Sequence
|
|
31
|
-
|
|
32
|
-
A **sequence** succeeds only if all patterns match in the given order.
|
|
33
|
-
|
|
34
|
-
```grammar
|
|
35
|
-
space = " "
|
|
36
|
-
first-name = "John"
|
|
37
|
-
last-name = "Doe"
|
|
38
|
-
full-name = first-name + space + last-name
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## Optional Pattern
|
|
44
|
-
|
|
45
|
-
Patterns in a sequence may be marked **optional**.
|
|
46
|
-
|
|
47
|
-
```grammar
|
|
48
|
-
space = " "
|
|
49
|
-
first-name = /\w+/
|
|
50
|
-
last-name = /\w+/
|
|
51
|
-
middle-name = /\w+/
|
|
52
|
-
middle-name-with-space = middle-name + space
|
|
53
|
-
|
|
54
|
-
full-name = first-name + space + middle-name-with-space? + last-name
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## Negative Lookahead
|
|
60
|
-
|
|
61
|
-
Use `!` to prevent a specific pattern from matching.
|
|
62
|
-
|
|
63
|
-
```grammar
|
|
64
|
-
space = " "
|
|
65
|
-
first-name = /\w+/
|
|
66
|
-
last-name = /\w+/
|
|
67
|
-
jack = "Jack"
|
|
68
|
-
|
|
69
|
-
full-name = !jack + first-name + space + last-name
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
This ensures the first name is not `"Jack"`.
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
## Options
|
|
77
|
-
|
|
78
|
-
An **options** pattern succeeds if *any one* of the choices matches.
|
|
79
|
-
|
|
80
|
-
```grammar
|
|
81
|
-
multiply = "*"
|
|
82
|
-
divide = "/"
|
|
83
|
-
operators = multiply | divide
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## Repeat
|
|
89
|
-
|
|
90
|
-
### Zero or More
|
|
91
|
-
|
|
92
|
-
```grammar
|
|
93
|
-
digit = /\d/
|
|
94
|
-
digits = (digit)*
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### Zero or More with Delimiters
|
|
98
|
-
|
|
99
|
-
```grammar
|
|
100
|
-
digit = /\d/
|
|
101
|
-
comma = ","
|
|
102
|
-
digits = (digit, comma)*
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### One or More with Trimmed Trailing Delimiter
|
|
106
|
-
|
|
107
|
-
```grammar
|
|
108
|
-
digit = /\d/
|
|
109
|
-
comma = ","
|
|
110
|
-
digits = (digit, comma trim)+
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
This prevents trailing commas from being accepted.
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
### One or More
|
|
118
|
-
|
|
119
|
-
```grammar
|
|
120
|
-
digit = /\d/
|
|
121
|
-
digits = (digit)+
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### Exact Count
|
|
125
|
-
|
|
126
|
-
```grammar
|
|
127
|
-
digit = /\d/
|
|
128
|
-
digits = (digit){2}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### Bounded Repeats
|
|
132
|
-
|
|
133
|
-
```grammar
|
|
134
|
-
digit = /\d/
|
|
135
|
-
digits = (digit){1,3} # between 1 and 3
|
|
136
|
-
digits = (digit){,3} # up to 3
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## Expressions
|
|
142
|
-
|
|
143
|
-
Expressions support **prefix**, **infix**, **postfix**, and **right-associative** notation, with operator precedence and recursion.
|
|
144
|
-
|
|
145
|
-
- **Prefix**: Operator(s) come before the expression. The sequence must end with the name of the expression being made.
|
|
146
|
-
- **Infix**: Operator(s) come between expressions.
|
|
147
|
-
- **Postfix**: Operator(s) come after the expression.
|
|
148
|
-
- **Right-associative**: Operator(s) group toward the right.
|
|
149
|
-
|
|
150
|
-
### Prefix Expression
|
|
151
|
-
|
|
152
|
-
```grammar
|
|
153
|
-
increment = "++"
|
|
154
|
-
integer = /[1-9][0-9]*/
|
|
155
|
-
space = /\s+/
|
|
156
|
-
|
|
157
|
-
prefix-expr = increment + space? + expr
|
|
158
|
-
expr = prefix-expr | integer
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
Examples:
|
|
162
|
-
- `++5`
|
|
163
|
-
- `++ 10`
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
### Infix Expression
|
|
168
|
-
|
|
169
|
-
```grammar
|
|
170
|
-
add-sub = "+" | "-"
|
|
171
|
-
mul-div = "*" | "/"
|
|
172
|
-
integer = /[1-9][0-9]*/
|
|
173
|
-
space = /\s+/
|
|
174
|
-
|
|
175
|
-
add-sub-expr = expr + space? + add-sub + space? + expr
|
|
176
|
-
mul-div-expr = expr + space? + mul-div + space? + expr
|
|
177
|
-
|
|
178
|
-
expr = mul-div-expr | add-sub-expr | integer
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
Examples:
|
|
182
|
-
- `4 * 2`
|
|
183
|
-
- `7 + 3`
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
### Postfix Expression
|
|
188
|
-
|
|
189
|
-
```grammar
|
|
190
|
-
factorial = "!"
|
|
191
|
-
integer = /[1-9][0-9]?/
|
|
192
|
-
space = /\s+/
|
|
193
|
-
|
|
194
|
-
postfix-expr = expr + space? + factorial
|
|
195
|
-
expr = postfix-expr | integer
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
Examples:
|
|
199
|
-
- `5!`
|
|
200
|
-
- `10 !`
|
|
201
|
-
|
|
202
|
-
---
|
|
203
|
-
|
|
204
|
-
### Combined Expressions
|
|
205
|
-
|
|
206
|
-
By layering them into a single `expr` rule, you can combine prefix, infix, and postfix with precedence:
|
|
207
|
-
|
|
208
|
-
```grammar
|
|
209
|
-
increment = "++"
|
|
210
|
-
factorial = "!"
|
|
211
|
-
add-sub = "+" | "-"
|
|
212
|
-
mul-div = "*" | "/"
|
|
213
|
-
|
|
214
|
-
integer = /[1-9][0-9]*/
|
|
215
|
-
space = /\s+/
|
|
216
|
-
|
|
217
|
-
prefix-expr = increment + space? + expr
|
|
218
|
-
postfix-expr = expr + space? + factorial
|
|
219
|
-
mul-div-expr = expr + space? + mul-div + space? + expr
|
|
220
|
-
add-sub-expr = expr + space? + add-sub + space? + expr
|
|
221
|
-
|
|
222
|
-
expr = postfix-expr
|
|
223
|
-
| prefix-expr
|
|
224
|
-
| mul-div-expr
|
|
225
|
-
| add-sub-expr
|
|
226
|
-
| integer
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
Examples:
|
|
230
|
-
- `++5`
|
|
231
|
-
- `5!`
|
|
232
|
-
- `++5!`
|
|
233
|
-
- `2 + 3 * 4`
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
### Recursive Expressions
|
|
238
|
-
|
|
239
|
-
Since each rule references `expr`, the grammar is recursive and can handle deeply nested inputs.
|
|
240
|
-
|
|
241
|
-
Examples:
|
|
242
|
-
- `7++` → `postfix-expr`
|
|
243
|
-
- `7++ * 9` → `mul-div-expr`
|
|
244
|
-
- `7++ * 9 + 10` → `(7++) * 9 + 10` with correct precedence
|
|
245
|
-
|
|
246
|
-
---
|
|
247
|
-
|
|
248
|
-
### Right-Associative Expressions
|
|
249
|
-
|
|
250
|
-
Some operators must associate to the **right**. Mark the operator with `right` to enforce this.
|
|
251
|
-
|
|
252
|
-
```grammar
|
|
253
|
-
power = "^"
|
|
254
|
-
integer = /[1-9][0-9]*/
|
|
255
|
-
space = /\s+/
|
|
256
|
-
|
|
257
|
-
power-expr = expr + space? + power + space? + expr
|
|
258
|
-
expr = power-expr right | integer
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
Examples:
|
|
262
|
-
- `2 ^ 3 ^ 2`
|
|
263
|
-
- Right-associative → `2 ^ (3 ^ 2)` = `512`
|
|
264
|
-
- Left-associative → `(2 ^ 3) ^ 2` = `64`
|
|
265
|
-
|
|
266
|
-
---
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
## Imports
|
|
270
|
-
|
|
271
|
-
### Basic Import
|
|
272
|
-
|
|
273
|
-
```grammar
|
|
274
|
-
import { spaces } from "https://some.cdn.com/some/spaces.cpat"
|
|
275
|
-
|
|
276
|
-
first-name = "John"
|
|
277
|
-
last-name = "Doe"
|
|
278
|
-
full-name = first-name + spaces + last-name
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
### Multiple Named Imports
|
|
282
|
-
|
|
283
|
-
```grammar
|
|
284
|
-
import { spaces, first-name } from "https://some.cdn.com/some/spaces.cpat"
|
|
285
|
-
|
|
286
|
-
last-name = "Doe"
|
|
287
|
-
full-name = first-name + spaces + last-name
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### Multiple Imports
|
|
291
|
-
|
|
292
|
-
```grammar
|
|
293
|
-
import { spaces, first-name } from "https://some.cdn.com/some/patterns.cpat"
|
|
294
|
-
import { last-name } from "https://some.cdn.com/some/last-name.cpat"
|
|
295
|
-
|
|
296
|
-
full-name = first-name + spaces + last-name
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
---
|
|
300
|
-
|
|
301
|
-
## Import Parameters
|
|
302
|
-
|
|
303
|
-
You can inject parameters into imported patterns.
|
|
304
|
-
|
|
305
|
-
**File:** `main.ts`
|
|
306
|
-
```ts
|
|
307
|
-
const firstName = new Literal("first-name", "John");
|
|
308
|
-
const lastName = new Literal("last-name", "Doe");
|
|
309
|
-
const grammar = Grammar.import('file.cpat', { params: [firstName, LastName] });
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
**File:** `file.cpat`
|
|
313
|
-
```grammar
|
|
314
|
-
use params { first-name, last-name }
|
|
315
|
-
|
|
316
|
-
full-name = first-name + spaces + last-name
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
### Imports with Params
|
|
320
|
-
|
|
321
|
-
```grammar
|
|
322
|
-
use params { other-pattern }
|
|
323
|
-
import { first-names, last-names } from "some-file.cpat" with params {
|
|
324
|
-
some-pattern = "Some Pattern"
|
|
325
|
-
some-pattern2 = other-pattern
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
full-name = first-names + spaces + last-names
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
---
|