roll-parser 3.0.0-alpha.0 → 3.0.0-beta.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/CHANGELOG.md +91 -0
- package/README.md +166 -30
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/format.d.ts +1 -1
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli.js +1110 -277
- package/dist/cli.js.map +28 -0
- package/dist/errors.d.ts +7 -4
- package/dist/errors.d.ts.map +1 -1
- package/dist/evaluator/evaluator.d.ts +63 -7
- package/dist/evaluator/evaluator.d.ts.map +1 -1
- package/dist/evaluator/index.d.ts +2 -2
- package/dist/evaluator/index.d.ts.map +1 -1
- package/dist/evaluator/modifiers/compare.d.ts +1 -1
- package/dist/evaluator/modifiers/compare.d.ts.map +1 -1
- package/dist/evaluator/modifiers/crit-threshold.d.ts +28 -0
- package/dist/evaluator/modifiers/crit-threshold.d.ts.map +1 -0
- package/dist/evaluator/modifiers/explode.d.ts +8 -4
- package/dist/evaluator/modifiers/explode.d.ts.map +1 -1
- package/dist/evaluator/modifiers/keep-drop.d.ts +1 -1
- package/dist/evaluator/modifiers/keep-drop.d.ts.map +1 -1
- package/dist/evaluator/modifiers/reroll.d.ts +4 -4
- package/dist/evaluator/modifiers/reroll.d.ts.map +1 -1
- package/dist/evaluator/modifiers/sort.d.ts +23 -0
- package/dist/evaluator/modifiers/sort.d.ts.map +1 -0
- package/dist/evaluator/modifiers/success-count.d.ts +1 -1
- package/dist/evaluator/modifiers/success-count.d.ts.map +1 -1
- package/dist/index.d.ts +13 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1112 -275
- package/dist/index.js.map +26 -0
- package/dist/lexer/lexer.d.ts +18 -3
- package/dist/lexer/lexer.d.ts.map +1 -1
- package/dist/lexer/tokens.d.ts +22 -2
- package/dist/lexer/tokens.d.ts.map +1 -1
- package/dist/parser/ast.d.ts +209 -24
- package/dist/parser/ast.d.ts.map +1 -1
- package/dist/parser/parser.d.ts +48 -5
- package/dist/parser/parser.d.ts.map +1 -1
- package/dist/rng/index.d.ts +2 -2
- package/dist/rng/index.d.ts.map +1 -1
- package/dist/rng/mock.d.ts +1 -1
- package/dist/rng/mock.d.ts.map +1 -1
- package/dist/rng/seeded.d.ts +8 -1
- package/dist/rng/seeded.d.ts.map +1 -1
- package/dist/roll.d.ts +6 -2
- package/dist/roll.d.ts.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +3 -0
- package/dist/testing.js.map +11 -0
- package/dist/types.d.ts +143 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +22 -18
- package/src/cli/args.ts +2 -1
- package/src/cli/format.ts +8 -4
- package/src/cli/index.ts +22 -5
- package/src/errors.ts +15 -3
- package/src/evaluator/evaluator.ts +826 -111
- package/src/evaluator/index.ts +2 -2
- package/src/evaluator/modifiers/compare.ts +1 -1
- package/src/evaluator/modifiers/crit-threshold.ts +59 -0
- package/src/evaluator/modifiers/explode.ts +29 -25
- package/src/evaluator/modifiers/keep-drop.ts +1 -1
- package/src/evaluator/modifiers/reroll.ts +18 -25
- package/src/evaluator/modifiers/sort.ts +30 -0
- package/src/evaluator/modifiers/success-count.ts +2 -2
- package/src/index.ts +33 -15
- package/src/lexer/lexer.ts +101 -8
- package/src/lexer/tokens.ts +42 -2
- package/src/parser/ast.ts +397 -30
- package/src/parser/parser.ts +590 -67
- package/src/rng/index.ts +2 -2
- package/src/rng/mock.ts +1 -1
- package/src/rng/seeded.ts +31 -1
- package/src/roll.ts +14 -6
- package/src/testing.ts +1 -1
- package/src/types.ts +127 -2
- package/dist/index.mjs +0 -1724
- package/dist/testing.mjs +0 -39
package/dist/lexer/lexer.d.ts
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module lexer/lexer
|
|
5
5
|
*/
|
|
6
|
-
import type { RollParserErrorCode } from '../errors';
|
|
7
|
-
import { RollParserError } from '../errors';
|
|
8
|
-
import { type Token } from './tokens';
|
|
6
|
+
import type { RollParserErrorCode } from '../errors.js';
|
|
7
|
+
import { RollParserError } from '../errors.js';
|
|
8
|
+
import { type Token } from './tokens.js';
|
|
9
9
|
/**
|
|
10
10
|
* Error thrown when the lexer encounters an invalid character.
|
|
11
11
|
*/
|
|
@@ -47,6 +47,19 @@ export declare class Lexer {
|
|
|
47
47
|
* accumulation loop stops naturally and the post-loop check handles it.
|
|
48
48
|
*/
|
|
49
49
|
private scanIdentifier;
|
|
50
|
+
/**
|
|
51
|
+
* Scans a variable reference introduced by `@`.
|
|
52
|
+
*
|
|
53
|
+
* Two forms:
|
|
54
|
+
* - Bare: `@name` where `name` matches `[A-Za-z_][A-Za-z0-9_]*` (case preserved).
|
|
55
|
+
* - Braced: `@{name}` where `name` is any run of printable characters except
|
|
56
|
+
* `}` and newline (permits spaces, hyphens, digits).
|
|
57
|
+
*
|
|
58
|
+
* Case is preserved — distinct from `scanIdentifier`, which lowercases the
|
|
59
|
+
* captured value. The emitted token's `value` is the variable name without
|
|
60
|
+
* the leading `@` or the surrounding braces.
|
|
61
|
+
*/
|
|
62
|
+
private scanAt;
|
|
50
63
|
private peek;
|
|
51
64
|
private peekNext;
|
|
52
65
|
private advance;
|
|
@@ -54,6 +67,8 @@ export declare class Lexer {
|
|
|
54
67
|
private isAtEnd;
|
|
55
68
|
private isDigit;
|
|
56
69
|
private isAlpha;
|
|
70
|
+
private isIdentifierStart;
|
|
71
|
+
private isIdentifierPart;
|
|
57
72
|
private isWhitespace;
|
|
58
73
|
private createToken;
|
|
59
74
|
private createTokenAt;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../src/lexer/lexer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../src/lexer/lexer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,KAAK,KAAK,EAAa,MAAM,aAAa,CAAC;AAEpD;;GAEG;AACH,qBAAa,UAAW,SAAQ,eAAe;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAM5F;AA2CD;;;;;GAKG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,KAAK,EAAE,MAAM;IAIzB;;OAEG;IACH,QAAQ,IAAI,KAAK,EAAE;IAYnB;;OAEG;IACH,SAAS,IAAI,KAAK;IAuFlB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,UAAU;IAoBlB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,cAAc;IAqCtB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,MAAM;IA+Bd,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,aAAa;CAGtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,CAE1C"}
|
package/dist/lexer/tokens.d.ts
CHANGED
|
@@ -70,8 +70,22 @@ export declare enum TokenType {
|
|
|
70
70
|
FUNCTION = 28,
|
|
71
71
|
/** Versus operator: 'vs' */
|
|
72
72
|
VS = 29,
|
|
73
|
+
/** Left brace: '{' */
|
|
74
|
+
LBRACE = 30,
|
|
75
|
+
/** Right brace: '}' */
|
|
76
|
+
RBRACE = 31,
|
|
77
|
+
/** Variable reference prefix: '@' */
|
|
78
|
+
AT = 32,
|
|
79
|
+
/** Ascending sort: 's' or 'sa' */
|
|
80
|
+
SORT_ASC = 33,
|
|
81
|
+
/** Descending sort: 'sd' */
|
|
82
|
+
SORT_DESC = 34,
|
|
83
|
+
/** Critical success threshold: 'cs' */
|
|
84
|
+
CRIT_SUCCESS = 35,
|
|
85
|
+
/** Critical failure threshold: 'cf' */
|
|
86
|
+
CRIT_FAIL = 36,
|
|
73
87
|
/** End of input marker */
|
|
74
|
-
EOF =
|
|
88
|
+
EOF = 37
|
|
75
89
|
}
|
|
76
90
|
/**
|
|
77
91
|
* A token produced by the lexer.
|
|
@@ -81,7 +95,13 @@ export type Token = {
|
|
|
81
95
|
type: TokenType;
|
|
82
96
|
/** The raw string value from input (lowercased for identifiers) */
|
|
83
97
|
value: string;
|
|
84
|
-
/** Zero-based
|
|
98
|
+
/** Zero-based start offset in the input string (UTF-16 code units) */
|
|
85
99
|
position: number;
|
|
100
|
+
/**
|
|
101
|
+
* Zero-based end offset (exclusive). Not always `position + value.length` —
|
|
102
|
+
* braced variables (`@{name}` stores only `name`) and case-normalized
|
|
103
|
+
* identifiers consume more input than their `value` retains.
|
|
104
|
+
*/
|
|
105
|
+
end: number;
|
|
86
106
|
};
|
|
87
107
|
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/lexer/tokens.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;GAKG;AACH,oBAAY,SAAS;IAKnB,0CAA0C;IAC1C,MAAM,IAAI;IAMV,gCAAgC;IAChC,IAAI,IAAI;IACR,sDAAsD;IACtD,YAAY,IAAI;IAChB,qCAAqC;IACrC,SAAS,IAAI;IAMb,6BAA6B;IAC7B,IAAI,IAAI;IACR,gCAAgC;IAChC,KAAK,IAAI;IACT,mCAAmC;IACnC,QAAQ,IAAI;IACZ,6BAA6B;IAC7B,MAAM,IAAI;IACV,2BAA2B;IAC3B,MAAM,IAAI;IACV,kCAAkC;IAClC,KAAK,IAAI;IAMT,wBAAwB;IACxB,OAAO,KAAK;IACZ,kCAAkC;IAClC,aAAa,KAAK;IAClB,qBAAqB;IACrB,IAAI,KAAK;IACT,+BAA+B;IAC/B,UAAU,KAAK;IACf,iBAAiB;IACjB,KAAK,KAAK;IAMV,4BAA4B;IAC5B,MAAM,KAAK;IACX,6BAA6B;IAC7B,MAAM,KAAK;IACX,8BAA8B;IAC9B,KAAK,KAAK;IAMV,yCAAyC;IACzC,SAAS,KAAK;IACd,iCAAiC;IACjC,QAAQ,KAAK;IACb,kCAAkC;IAClC,SAAS,KAAK;IACd,iCAAiC;IACjC,QAAQ,KAAK;IAMb,4BAA4B;IAC5B,OAAO,KAAK;IACZ,gCAAgC;IAChC,gBAAgB,KAAK;IACrB,gCAAgC;IAChC,mBAAmB,KAAK;IAMxB,4BAA4B;IAC5B,MAAM,KAAK;IACX,wBAAwB;IACxB,WAAW,KAAK;IAMhB,uBAAuB;IACvB,IAAI,KAAK;IAMT,mEAAmE;IACnE,QAAQ,KAAK;IAMb,4BAA4B;IAC5B,EAAE,KAAK;IAMP,0BAA0B;IAC1B,GAAG,KAAK;CACT;AAED;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG;IAClB,6BAA6B;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/lexer/tokens.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;GAKG;AACH,oBAAY,SAAS;IAKnB,0CAA0C;IAC1C,MAAM,IAAI;IAMV,gCAAgC;IAChC,IAAI,IAAI;IACR,sDAAsD;IACtD,YAAY,IAAI;IAChB,qCAAqC;IACrC,SAAS,IAAI;IAMb,6BAA6B;IAC7B,IAAI,IAAI;IACR,gCAAgC;IAChC,KAAK,IAAI;IACT,mCAAmC;IACnC,QAAQ,IAAI;IACZ,6BAA6B;IAC7B,MAAM,IAAI;IACV,2BAA2B;IAC3B,MAAM,IAAI;IACV,kCAAkC;IAClC,KAAK,IAAI;IAMT,wBAAwB;IACxB,OAAO,KAAK;IACZ,kCAAkC;IAClC,aAAa,KAAK;IAClB,qBAAqB;IACrB,IAAI,KAAK;IACT,+BAA+B;IAC/B,UAAU,KAAK;IACf,iBAAiB;IACjB,KAAK,KAAK;IAMV,4BAA4B;IAC5B,MAAM,KAAK;IACX,6BAA6B;IAC7B,MAAM,KAAK;IACX,8BAA8B;IAC9B,KAAK,KAAK;IAMV,yCAAyC;IACzC,SAAS,KAAK;IACd,iCAAiC;IACjC,QAAQ,KAAK;IACb,kCAAkC;IAClC,SAAS,KAAK;IACd,iCAAiC;IACjC,QAAQ,KAAK;IAMb,4BAA4B;IAC5B,OAAO,KAAK;IACZ,gCAAgC;IAChC,gBAAgB,KAAK;IACrB,gCAAgC;IAChC,mBAAmB,KAAK;IAMxB,4BAA4B;IAC5B,MAAM,KAAK;IACX,wBAAwB;IACxB,WAAW,KAAK;IAMhB,uBAAuB;IACvB,IAAI,KAAK;IAMT,mEAAmE;IACnE,QAAQ,KAAK;IAMb,4BAA4B;IAC5B,EAAE,KAAK;IAMP,sBAAsB;IACtB,MAAM,KAAK;IACX,uBAAuB;IACvB,MAAM,KAAK;IAMX,qCAAqC;IACrC,EAAE,KAAK;IAMP,kCAAkC;IAClC,QAAQ,KAAK;IACb,4BAA4B;IAC5B,SAAS,KAAK;IAMd,uCAAuC;IACvC,YAAY,KAAK;IACjB,uCAAuC;IACvC,SAAS,KAAK;IAMd,0BAA0B;IAC1B,GAAG,KAAK;CACT;AAED;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG;IAClB,6BAA6B;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;CACb,CAAC"}
|
package/dist/parser/ast.d.ts
CHANGED
|
@@ -3,11 +3,23 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module parser/ast
|
|
5
5
|
*/
|
|
6
|
-
import type { ComparePoint } from '../types';
|
|
6
|
+
import type { ComparePoint } from '../types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Source span carried by every AST node.
|
|
9
|
+
*
|
|
10
|
+
* `start` is inclusive, `end` exclusive, both in UTF-16 code units into the
|
|
11
|
+
* original notation string. The parser sets both on every node it produces;
|
|
12
|
+
* they are typed optional so hand-constructed ASTs (tests, programmatic
|
|
13
|
+
* consumers) remain valid without positions.
|
|
14
|
+
*/
|
|
15
|
+
export type NodeSpan = {
|
|
16
|
+
start?: number;
|
|
17
|
+
end?: number;
|
|
18
|
+
};
|
|
7
19
|
/**
|
|
8
20
|
* Numeric literal node.
|
|
9
21
|
*/
|
|
10
|
-
export type LiteralNode = {
|
|
22
|
+
export type LiteralNode = NodeSpan & {
|
|
11
23
|
type: 'Literal';
|
|
12
24
|
value: number;
|
|
13
25
|
};
|
|
@@ -15,7 +27,7 @@ export type LiteralNode = {
|
|
|
15
27
|
* Dice roll node.
|
|
16
28
|
* Count and sides can be expressions to support computed dice like (1+1)d(3*2).
|
|
17
29
|
*/
|
|
18
|
-
export type DiceNode = {
|
|
30
|
+
export type DiceNode = NodeSpan & {
|
|
19
31
|
type: 'Dice';
|
|
20
32
|
count: ASTNode;
|
|
21
33
|
sides: ASTNode;
|
|
@@ -24,14 +36,14 @@ export type DiceNode = {
|
|
|
24
36
|
* Fate/Fudge dice node (`dF`).
|
|
25
37
|
* Each die produces a result in {-1, 0, +1}. No configurable sides.
|
|
26
38
|
*/
|
|
27
|
-
export type FateDiceNode = {
|
|
39
|
+
export type FateDiceNode = NodeSpan & {
|
|
28
40
|
type: 'FateDice';
|
|
29
41
|
count: ASTNode;
|
|
30
42
|
};
|
|
31
43
|
/**
|
|
32
44
|
* Binary operation node.
|
|
33
45
|
*/
|
|
34
|
-
export type BinaryOpNode = {
|
|
46
|
+
export type BinaryOpNode = NodeSpan & {
|
|
35
47
|
type: 'BinaryOp';
|
|
36
48
|
operator: '+' | '-' | '*' | '/' | '%' | '**';
|
|
37
49
|
left: ASTNode;
|
|
@@ -40,7 +52,7 @@ export type BinaryOpNode = {
|
|
|
40
52
|
/**
|
|
41
53
|
* Unary operation node.
|
|
42
54
|
*/
|
|
43
|
-
export type UnaryOpNode = {
|
|
55
|
+
export type UnaryOpNode = NodeSpan & {
|
|
44
56
|
type: 'UnaryOp';
|
|
45
57
|
operator: '-';
|
|
46
58
|
operand: ASTNode;
|
|
@@ -49,7 +61,7 @@ export type UnaryOpNode = {
|
|
|
49
61
|
* Keep/drop modifier node.
|
|
50
62
|
* Wraps a dice expression with keep highest/lowest or drop highest/lowest.
|
|
51
63
|
*/
|
|
52
|
-
export type ModifierNode = {
|
|
64
|
+
export type ModifierNode = NodeSpan & {
|
|
53
65
|
type: 'Modifier';
|
|
54
66
|
modifier: 'keep' | 'drop';
|
|
55
67
|
selector: 'highest' | 'lowest';
|
|
@@ -61,7 +73,7 @@ export type ModifierNode = {
|
|
|
61
73
|
* Wraps a dice expression with a standard, compounding, or penetrating
|
|
62
74
|
* explosion. An absent `threshold` means "explode on the die's maximum face".
|
|
63
75
|
*/
|
|
64
|
-
export type ExplodeNode = {
|
|
76
|
+
export type ExplodeNode = NodeSpan & {
|
|
65
77
|
type: 'Explode';
|
|
66
78
|
variant: 'standard' | 'compound' | 'penetrating';
|
|
67
79
|
threshold?: ComparePoint;
|
|
@@ -73,7 +85,7 @@ export type ExplodeNode = {
|
|
|
73
85
|
* keeps the second result regardless of match; `once: false` for `r`
|
|
74
86
|
* re-rolls recursively until the condition no longer matches.
|
|
75
87
|
*/
|
|
76
|
-
export type RerollNode = {
|
|
88
|
+
export type RerollNode = NodeSpan & {
|
|
77
89
|
type: 'Reroll';
|
|
78
90
|
once: boolean;
|
|
79
91
|
condition: ComparePoint;
|
|
@@ -83,11 +95,12 @@ export type RerollNode = {
|
|
|
83
95
|
* Success counting node (`>=T`, `>T`, `<T`, `<=T`, `=T`, with optional `f=F`).
|
|
84
96
|
*
|
|
85
97
|
* Transforms a dice pool into a success count: each die meeting `threshold`
|
|
86
|
-
* adds +1, each die meeting `failThreshold` subtracts 1. Terminal —
|
|
87
|
-
*
|
|
88
|
-
* operator
|
|
98
|
+
* adds +1, each die meeting `failThreshold` subtracts 1. Terminal — a
|
|
99
|
+
* `SuccessCountNode` may not be wrapped by any postfix modifier, binary
|
|
100
|
+
* operator, unary operator, versus operand, or function argument. The
|
|
101
|
+
* `failThreshold` accepts any `CompareOp`; bare `fN` defaults to `operator: '='`.
|
|
89
102
|
*/
|
|
90
|
-
export type SuccessCountNode = {
|
|
103
|
+
export type SuccessCountNode = NodeSpan & {
|
|
91
104
|
type: 'SuccessCount';
|
|
92
105
|
target: ASTNode;
|
|
93
106
|
threshold: ComparePoint;
|
|
@@ -103,7 +116,7 @@ export type SuccessCountNode = {
|
|
|
103
116
|
* rejected at parse time; nesting via parens (`a vs (b vs c)`) is rejected
|
|
104
117
|
* at evaluation time.
|
|
105
118
|
*/
|
|
106
|
-
export type VersusNode = {
|
|
119
|
+
export type VersusNode = NodeSpan & {
|
|
107
120
|
type: 'Versus';
|
|
108
121
|
roll: ASTNode;
|
|
109
122
|
dc: ASTNode;
|
|
@@ -116,15 +129,91 @@ export type VersusNode = {
|
|
|
116
129
|
* parse time against a static table; by the time the evaluator sees a
|
|
117
130
|
* `FunctionCallNode`, `args.length` is guaranteed to match the function.
|
|
118
131
|
*/
|
|
119
|
-
export type FunctionCallNode = {
|
|
132
|
+
export type FunctionCallNode = NodeSpan & {
|
|
120
133
|
type: 'FunctionCall';
|
|
121
134
|
name: string;
|
|
122
135
|
args: ASTNode[];
|
|
123
136
|
};
|
|
137
|
+
/**
|
|
138
|
+
* Parenthesized group node (`(<expr>)`).
|
|
139
|
+
*
|
|
140
|
+
* Preserves explicit grouping typed by the user so that
|
|
141
|
+
* `RollResult.expression` and `RollResult.rendered` round-trip through
|
|
142
|
+
* `parse` without losing precedence information. Semantically transparent:
|
|
143
|
+
* evaluation returns the inner expression's value unchanged.
|
|
144
|
+
*/
|
|
145
|
+
export type GroupedNode = NodeSpan & {
|
|
146
|
+
type: 'Grouped';
|
|
147
|
+
expression: ASTNode;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Variable reference node (`@name` or `@{name with spaces}`).
|
|
151
|
+
*
|
|
152
|
+
* Resolves to a numeric value from the evaluator's `context` map at
|
|
153
|
+
* evaluation time. Names are case-sensitive (`@StrMod` ≠ `@strmod`) — the
|
|
154
|
+
* lexer preserves case in the `AT` token's `value`, distinct from other
|
|
155
|
+
* identifier tokens which lowercase. Leaf node — no LED, never wraps a
|
|
156
|
+
* sub-expression.
|
|
157
|
+
*/
|
|
158
|
+
export type VariableNode = NodeSpan & {
|
|
159
|
+
type: 'Variable';
|
|
160
|
+
name: string;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Grouped-roll node (`{expr}`, `{expr1, expr2, ...}`).
|
|
164
|
+
*
|
|
165
|
+
* Distinct from `GroupedNode` (parenthesized wrapper) — a `GroupNode`
|
|
166
|
+
* collects one or more sub-expressions whose evaluation semantics change
|
|
167
|
+
* with the sub-roll count. `expressions.length === 1` is a passthrough
|
|
168
|
+
* (flat-pool when wrapped by keep/drop); `expressions.length >= 2` treats
|
|
169
|
+
* each sub-roll's subtotal as a compound die for keep/drop selection.
|
|
170
|
+
*/
|
|
171
|
+
export type GroupNode = NodeSpan & {
|
|
172
|
+
type: 'Group';
|
|
173
|
+
expressions: ASTNode[];
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Sort modifier node (`s`, `sa`, `sd`).
|
|
177
|
+
*
|
|
178
|
+
* Cosmetically reorders the dice produced by `target` in ascending or
|
|
179
|
+
* descending order. Purely visual — does not affect `total`,
|
|
180
|
+
* `successes`/`failures`, or any die-level flag (`kept`/`dropped`/
|
|
181
|
+
* `critical`/`fumble`). Dropped dice retain their `dropped` flag and
|
|
182
|
+
* appear in sorted position alongside kept dice.
|
|
183
|
+
*/
|
|
184
|
+
export type SortNode = NodeSpan & {
|
|
185
|
+
type: 'Sort';
|
|
186
|
+
order: 'ascending' | 'descending';
|
|
187
|
+
target: ASTNode;
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* Sentinel for bare `cs` / `cf` without a ComparePoint. Resolved to
|
|
191
|
+
* `result === sides` (for critical) or `result === 1` (for fumble) at
|
|
192
|
+
* evaluation time, using each die's own `sides`.
|
|
193
|
+
*/
|
|
194
|
+
export type CritThreshold = ComparePoint | 'default';
|
|
195
|
+
/**
|
|
196
|
+
* Critical threshold modifier node (`cs`, `cf`).
|
|
197
|
+
*
|
|
198
|
+
* Overrides the default `critical`/`fumble` flag logic for the dice
|
|
199
|
+
* produced by `target`. Bare `cs`/`cf` uses the `'default'` sentinel
|
|
200
|
+
* (max face / 1). Custom thresholds accept any ComparePoint. Chaining
|
|
201
|
+
* collapses into a single node — `1d20cs=20cs=1cf>18` has two success
|
|
202
|
+
* and one fail threshold. Display-only: does not change `total`,
|
|
203
|
+
* explosion triggers, or success counting. `cs` and `cf` are independent
|
|
204
|
+
* overrides — a side with no explicit thresholds keeps the default rule
|
|
205
|
+
* (the evaluator substitutes the `'default'` sentinel at apply time).
|
|
206
|
+
*/
|
|
207
|
+
export type CritThresholdNode = NodeSpan & {
|
|
208
|
+
type: 'CritThreshold';
|
|
209
|
+
successThresholds: CritThreshold[];
|
|
210
|
+
failThresholds: CritThreshold[];
|
|
211
|
+
target: ASTNode;
|
|
212
|
+
};
|
|
124
213
|
/**
|
|
125
214
|
* Union type of all AST nodes.
|
|
126
215
|
*/
|
|
127
|
-
export type ASTNode = LiteralNode | DiceNode | FateDiceNode | BinaryOpNode | UnaryOpNode | ModifierNode | ExplodeNode | RerollNode | SuccessCountNode | VersusNode | FunctionCallNode;
|
|
216
|
+
export type ASTNode = LiteralNode | DiceNode | FateDiceNode | BinaryOpNode | UnaryOpNode | ModifierNode | ExplodeNode | RerollNode | SuccessCountNode | VersusNode | FunctionCallNode | GroupedNode | VariableNode | GroupNode | SortNode | CritThresholdNode;
|
|
128
217
|
/**
|
|
129
218
|
* Type guard for LiteralNode.
|
|
130
219
|
*/
|
|
@@ -170,14 +259,110 @@ export declare function isVersus(node: ASTNode): node is VersusNode;
|
|
|
170
259
|
*/
|
|
171
260
|
export declare function isFunctionCall(node: ASTNode): node is FunctionCallNode;
|
|
172
261
|
/**
|
|
173
|
-
*
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
*
|
|
262
|
+
* Type guard for GroupedNode.
|
|
263
|
+
*/
|
|
264
|
+
export declare function isGrouped(node: ASTNode): node is GroupedNode;
|
|
265
|
+
/**
|
|
266
|
+
* Type guard for VariableNode.
|
|
267
|
+
*/
|
|
268
|
+
export declare function isVariable(node: ASTNode): node is VariableNode;
|
|
269
|
+
/**
|
|
270
|
+
* Type guard for GroupNode.
|
|
271
|
+
*/
|
|
272
|
+
export declare function isGroup(node: ASTNode): node is GroupNode;
|
|
273
|
+
/**
|
|
274
|
+
* Type guard for SortNode.
|
|
275
|
+
*/
|
|
276
|
+
export declare function isSort(node: ASTNode): node is SortNode;
|
|
277
|
+
/**
|
|
278
|
+
* Type guard for CritThresholdNode.
|
|
279
|
+
*/
|
|
280
|
+
export declare function isCritThreshold(node: ASTNode): node is CritThresholdNode;
|
|
281
|
+
/**
|
|
282
|
+
* Wrapper kinds that `unwrapTransparent` can peel.
|
|
283
|
+
*
|
|
284
|
+
* "Transparent" is relative to the question being asked. `Modifier`/`Sort`/
|
|
285
|
+
* `CritThreshold` are transparent for "what is the underlying operand?" when
|
|
286
|
+
* deciding whether to reject a `Group` target — they preserve `containsDicePool`'s
|
|
287
|
+
* answer for whatever they wrap. They are NOT transparent for "is this a
|
|
288
|
+
* `SuccessCount`?" or "is this a `Versus`?", because the parsers that build
|
|
289
|
+
* those wrappers already reject `SuccessCount`/`Versus` operands upstream.
|
|
290
|
+
*/
|
|
291
|
+
export type TransparentWrapperKind = 'Grouped' | 'Modifier' | 'Sort' | 'CritThreshold';
|
|
292
|
+
/**
|
|
293
|
+
* Walks `node` while its `.type` is in `kinds`, returning the first descendant
|
|
294
|
+
* that is not one of the listed wrappers. Each caller picks the subset that
|
|
295
|
+
* matches its rejection semantics — see `TransparentWrapperKind` for guidance.
|
|
296
|
+
*
|
|
297
|
+
* Used by parser reject helpers to look past wrappers when deciding whether
|
|
298
|
+
* an operand violates a rule (e.g., `Group` cannot be the target of `cs`/`cf`,
|
|
299
|
+
* even when wrapped in `Modifier` like `{1d6}kh1cs>5`).
|
|
300
|
+
*/
|
|
301
|
+
export declare function unwrapTransparent(node: ASTNode, kinds: readonly TransparentWrapperKind[]): ASTNode;
|
|
302
|
+
/**
|
|
303
|
+
* Returns `true` only when `node`'s direct result is a dice pool —
|
|
304
|
+
* `Dice`, `FateDice`, or a chained pool modifier (`Modifier` / `Explode` /
|
|
305
|
+
* `Reroll`). Does NOT recurse through arithmetic wrappers (`BinaryOp`,
|
|
306
|
+
* `UnaryOp`, `FunctionCall`), so `(1d6+5)` and `floor(1d6/2)` are rejected.
|
|
178
307
|
*
|
|
179
|
-
* Used by the parser to reject
|
|
180
|
-
*
|
|
308
|
+
* Used by the parser to reject postfix pool-modifier targets (kh/kl/dh/dl,
|
|
309
|
+
* !/!!/!p, r/ro) that wrap a non-pool expression. Operating on the inner
|
|
310
|
+
* dice pool would silently drop the surrounding arithmetic.
|
|
311
|
+
*/
|
|
312
|
+
export declare function containsDicePool(node: ASTNode): boolean;
|
|
313
|
+
/**
|
|
314
|
+
* Deeper variant of `containsDicePool` that recurses through arithmetic and
|
|
315
|
+
* function wrappers. Used from the `Group` case above (ordinary parenthesized
|
|
316
|
+
* arithmetic `(1d6+5)kh1` must still reject, so the shallow `containsDicePool`
|
|
317
|
+
* handles those directly) and from the Sort parser guard (sort accepts
|
|
318
|
+
* `(1d6+2d8)s` per Stage 3 spec).
|
|
319
|
+
*/
|
|
320
|
+
export declare function deepContainsDicePool(node: ASTNode): boolean;
|
|
321
|
+
/**
|
|
322
|
+
* Returns `true` if the pool this node resolves to is (or wraps) a `FateDice`
|
|
323
|
+
* pool. Walks through chained pool modifiers (`Modifier` / `Explode` /
|
|
324
|
+
* `Reroll`) but not arithmetic wrappers — callers should run
|
|
325
|
+
* `containsDicePool` first to reject those.
|
|
326
|
+
*
|
|
327
|
+
* Used by the parser to reject `!`, `!!`, `!p` applied to Fate pools
|
|
328
|
+
* (`4dF!`, `(4dF)kh2!`, etc.). Fate explosion semantics are undefined, so
|
|
329
|
+
* parse-time rejection is preferred over a silent evaluator no-op.
|
|
330
|
+
*
|
|
331
|
+
* Inside a `Group`, recursion uses `deepContainsFatePool` to mirror
|
|
332
|
+
* `containsDicePool`'s deep walk through the same case — otherwise
|
|
333
|
+
* `{4dF+1d6}cf` slips past the bare-Fate guard and the default fumble
|
|
334
|
+
* check (`result === 1`) flips `+1` faces into fumbles.
|
|
335
|
+
*/
|
|
336
|
+
export declare function containsFatePool(node: ASTNode): boolean;
|
|
337
|
+
/**
|
|
338
|
+
* Deeper variant of `containsFatePool` that recurses through arithmetic and
|
|
339
|
+
* function wrappers. Mirrors `deepContainsDicePool`. Used from
|
|
340
|
+
* `containsFatePool`'s `Group` case so single-sub-roll groups containing
|
|
341
|
+
* arithmetic-wrapped Fate (`{4dF+1d6}cf`) still trip the bare-Fate guard.
|
|
342
|
+
*
|
|
343
|
+
* Outside a `Group`, ordinary parenthesized arithmetic (`(4dF+1d6)cf`) is
|
|
344
|
+
* already rejected upstream by shallow `containsDicePool`, so this helper
|
|
345
|
+
* intentionally stays Group-internal.
|
|
346
|
+
*/
|
|
347
|
+
export declare function deepContainsFatePool(node: ASTNode): boolean;
|
|
348
|
+
/**
|
|
349
|
+
* Deep-walks a node to find any descendant `Group` with two or more
|
|
350
|
+
* sub-expressions. Used by `rejectGroupTarget`'s single-sub-roll
|
|
351
|
+
* passthrough so a multi-sub Group buried under arithmetic
|
|
352
|
+
* (`{{1d6,2d8}+0}cs>5`), function calls (`{abs({1d6,2d8})}cs>5`), or any
|
|
353
|
+
* other non-transparent wrapper still rejects with the same error code.
|
|
354
|
+
*
|
|
355
|
+
* Without this walk, the unwrap inside `rejectGroupTarget` only peels
|
|
356
|
+
* `Grouped`/`Modifier`/`Sort`/`CritThreshold` — a multi-sub Group cloaked
|
|
357
|
+
* in a `BinaryOp`/`UnaryOp`/`FunctionCall` revives issue #97.
|
|
358
|
+
*/
|
|
359
|
+
export declare function containsMultiSubGroup(node: ASTNode): boolean;
|
|
360
|
+
/**
|
|
361
|
+
* Deep-walks a node to find any descendant `Versus`. Used by
|
|
362
|
+
* `rejectVersusTarget`'s single-sub-roll Group passthrough so a buried
|
|
363
|
+
* Versus (`{1+(1d20 vs 15)}cs>18`, `{abs(1d20 vs 15)}cs>18`,
|
|
364
|
+
* `{-(1d20 vs 15)}kh1`) still rejects with `NESTED_VERSUS` instead of
|
|
365
|
+
* silently dropping `versusMetadata` at the modifier consumer site.
|
|
181
366
|
*/
|
|
182
|
-
export declare function
|
|
367
|
+
export declare function containsVersus(node: ASTNode): boolean;
|
|
183
368
|
//# sourceMappingURL=ast.d.ts.map
|
package/dist/parser/ast.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/parser/ast.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/parser/ast.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG;IACnC,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC;IAC7C,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG;IACnC,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,GAAG,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,QAAQ,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG;IACnC,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,UAAU,GAAG,UAAU,GAAG,aAAa,CAAC;IACjD,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG;IAClC,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,YAAY,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG;IACxC,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,YAAY,CAAC;IACxB,aAAa,CAAC,EAAE,YAAY,CAAC;CAC9B,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG;IAClC,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,OAAO,CAAC;CACb,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG;IACxC,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG;IACnC,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,OAAO,EAAE,CAAC;CACxB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,GAAG,YAAY,CAAC;IAClC,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,SAAS,CAAC;AAErD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG;IACzC,IAAI,EAAE,eAAe,CAAC;IACtB,iBAAiB,EAAE,aAAa,EAAE,CAAC;IACnC,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,OAAO,GACf,WAAW,GACX,QAAQ,GACR,YAAY,GACZ,YAAY,GACZ,WAAW,GACX,YAAY,GACZ,WAAW,GACX,UAAU,GACV,gBAAgB,GAChB,UAAU,GACV,gBAAgB,GAChB,WAAW,GACX,YAAY,GACZ,SAAS,GACT,QAAQ,GACR,iBAAiB,CAAC;AAEtB;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,WAAW,CAE5D;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,QAAQ,CAEtD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,YAAY,CAE9D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,YAAY,CAE9D;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,WAAW,CAE5D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,YAAY,CAE9D;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,WAAW,CAE5D;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,UAAU,CAE1D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,gBAAgB,CAEtE;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,UAAU,CAE1D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,gBAAgB,CAEtE;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,WAAW,CAE5D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,YAAY,CAE9D;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,SAAS,CAExD;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,QAAQ,CAEtD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,iBAAiB,CAExE;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,eAAe,CAAC;AAEvF;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,SAAS,sBAAsB,EAAE,GACvC,OAAO,CAwBT;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAwBvD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CA2B3D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAiBvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CA0B3D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAwB5D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAwBrD"}
|
package/dist/parser/parser.d.ts
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module parser/parser
|
|
5
5
|
*/
|
|
6
|
-
import type { RollParserErrorCode } from '../errors';
|
|
7
|
-
import { RollParserError } from '../errors';
|
|
8
|
-
import { type Token } from '../lexer/tokens';
|
|
9
|
-
import type { ComparePoint } from '../types';
|
|
10
|
-
import type { ASTNode } from './ast';
|
|
6
|
+
import type { RollParserErrorCode } from '../errors.js';
|
|
7
|
+
import { RollParserError } from '../errors.js';
|
|
8
|
+
import { type Token } from '../lexer/tokens.js';
|
|
9
|
+
import type { ComparePoint } from '../types.js';
|
|
10
|
+
import type { ASTNode } from './ast.js';
|
|
11
11
|
/**
|
|
12
12
|
* Error thrown when the parser encounters invalid syntax.
|
|
13
13
|
*/
|
|
@@ -25,6 +25,7 @@ export declare class ParseError extends RollParserError {
|
|
|
25
25
|
export declare class Parser {
|
|
26
26
|
private readonly tokens;
|
|
27
27
|
private pos;
|
|
28
|
+
private depth;
|
|
28
29
|
constructor(tokens: Token[]);
|
|
29
30
|
/**
|
|
30
31
|
* Parse the token stream into an AST.
|
|
@@ -44,6 +45,11 @@ export declare class Parser {
|
|
|
44
45
|
* Handles tokens that appear between expressions (infix/postfix position).
|
|
45
46
|
*/
|
|
46
47
|
private parseLed;
|
|
48
|
+
/**
|
|
49
|
+
* Zero-width span for synthetic nodes (implicit counts, `d%` sides) that
|
|
50
|
+
* have no source text of their own — anchored at the governing token.
|
|
51
|
+
*/
|
|
52
|
+
private static syntheticLiteral;
|
|
47
53
|
private parseLiteral;
|
|
48
54
|
private parseUnaryMinus;
|
|
49
55
|
private parsePrefixDice;
|
|
@@ -53,12 +59,42 @@ export declare class Parser {
|
|
|
53
59
|
private parsePrefixFateDice;
|
|
54
60
|
private parseInfixFateDice;
|
|
55
61
|
private parseGrouped;
|
|
62
|
+
private parseGroup;
|
|
63
|
+
private parseVariable;
|
|
56
64
|
private parseFunctionCall;
|
|
57
65
|
private parseBinaryOp;
|
|
66
|
+
/**
|
|
67
|
+
* Rejects a dice token whose count operand is itself a bare (unparenthesized)
|
|
68
|
+
* dice expression. `4d6d1` would otherwise silently parse as `(4d6)d1` —
|
|
69
|
+
* roll 4d6, then use the result as a count of d1 dice — which is almost
|
|
70
|
+
* never intended: every major dice dialect reads `4d6d1` as "drop lowest 1".
|
|
71
|
+
* Both meanings stay reachable through explicit forms: `4d6dl1` to drop,
|
|
72
|
+
* `(4d6)d1` for nested dice.
|
|
73
|
+
*/
|
|
74
|
+
private rejectBareDiceChain;
|
|
58
75
|
private rejectSuccessCountTarget;
|
|
76
|
+
/**
|
|
77
|
+
* Rejects `GroupNode` (or a wrapper-cloaked group) as the target of `token`.
|
|
78
|
+
* Explode, reroll, and crit-threshold wrap bare dice pools only — a group
|
|
79
|
+
* is a container of sub-expressions, so these modifiers have no defined
|
|
80
|
+
* semantics. Walks `Grouped`/`Modifier`/`Sort`/`CritThreshold` so wrappers
|
|
81
|
+
* cannot smuggle a group past the check (`{1d6}kh1cs>5`, `({1d6})!`,
|
|
82
|
+
* `{1d6}scs>5` all reject the same as `{1d6}!`/`{1d6}cs>5`).
|
|
83
|
+
*
|
|
84
|
+
* `singleSubRollPasses` opts the caller into the Stage 3 single-sub-roll
|
|
85
|
+
* passthrough rule (STAGE3.md "Group Semantics: Single vs Multi Sub-Roll"):
|
|
86
|
+
* a `Group` with one expression is the user's explicit flat-pool escape
|
|
87
|
+
* hatch and is equivalent to its unwrapped form. Currently only
|
|
88
|
+
* `parseCritThreshold` opts in — explode/reroll keep the strict reject so
|
|
89
|
+
* existing notation contracts don't shift.
|
|
90
|
+
*/
|
|
91
|
+
private rejectGroupTarget;
|
|
92
|
+
private rejectVersusTarget;
|
|
59
93
|
private parseModifier;
|
|
60
94
|
private parseExplode;
|
|
61
95
|
private parseReroll;
|
|
96
|
+
private parseSort;
|
|
97
|
+
private parseCritThreshold;
|
|
62
98
|
private parseSuccessCount;
|
|
63
99
|
private parseVersus;
|
|
64
100
|
/**
|
|
@@ -69,6 +105,13 @@ export declare class Parser {
|
|
|
69
105
|
* Parses a comparison operator followed by a value expression.
|
|
70
106
|
* Called by modifier parsers (explode, reroll, success counting).
|
|
71
107
|
*
|
|
108
|
+
* The threshold value is parsed at `BP.DICE_LEFT`, which binds tighter than
|
|
109
|
+
* arithmetic. This keeps the comparison bound to the dice pool on the left
|
|
110
|
+
* rather than letting arithmetic to the right be consumed into the
|
|
111
|
+
* threshold. As a consequence, `1d6>=5+2` parses as `(1d6>=5)+2` with
|
|
112
|
+
* threshold `5` — not `7`. Computed thresholds require parens:
|
|
113
|
+
* `1d6>=(5+2)`. Same binding applies to `parseSuccessCount` below.
|
|
114
|
+
*
|
|
72
115
|
* @returns A ComparePoint with the operator and value AST node
|
|
73
116
|
* @throws {ParseError} If the next token is not a comparison operator
|
|
74
117
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser/parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser/parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,KAAK,KAAK,EAAa,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAa,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EACV,OAAO,EAkBR,MAAM,UAAU,CAAC;AAYlB;;GAEG;AACH,qBAAa,UAAW,SAAQ,eAAe;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;gBAEtB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAMxF;AAwED;;;;;GAKG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IACjC,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,KAAK,CAAK;gBAEN,MAAM,EAAE,KAAK,EAAE;IAI3B;;OAEG;IACH,KAAK,IAAI,OAAO;IAqBhB;;OAEG;IACH,OAAO,CAAC,eAAe;IA8BvB;;;OAGG;IACH,OAAO,CAAC,QAAQ;IA4ChB;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAgEhB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAI/B,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,qBAAqB;IAc7B,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,kBAAkB;IAe1B,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,UAAU;IA4BlB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,iBAAiB;IA0DzB,OAAO,CAAC,aAAa;IAmBrB;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,wBAAwB;IAgBhC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,kBAAkB;IAoC1B,OAAO,CAAC,aAAa;IAqDrB,OAAO,CAAC,YAAY;IA+DpB,OAAO,CAAC,WAAW;IAyCnB,OAAO,CAAC,SAAS;IAgDjB,OAAO,CAAC,kBAAkB;IA+E1B,OAAO,CAAC,iBAAiB;IA8CzB,OAAO,CAAC,WAAW;IA6BnB;;OAEG;IACH,mBAAmB,IAAI,OAAO;IAW9B;;;;;;;;;;;;;OAaG;IACH,iBAAiB,IAAI,YAAY;IAajC,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,SAAS;IA2DjB,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,IAAI;IAMZ,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,MAAM;IAed,OAAO,CAAC,SAAS;CAGlB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAI/C"}
|
package/dist/rng/index.d.ts
CHANGED
package/dist/rng/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rng/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EAAE,GAAG,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rng/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/rng/mock.d.ts
CHANGED
package/dist/rng/mock.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/rng/mock.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/rng/mock.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEtC;;;;;GAKG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,QAAQ,EAAE,MAAM;CAK7B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAsBnD"}
|
package/dist/rng/seeded.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module rng/seeded
|
|
5
5
|
*/
|
|
6
|
-
import type { RNG } from './types';
|
|
6
|
+
import type { RNG } from './types.js';
|
|
7
7
|
/**
|
|
8
8
|
* Seedable pseudo-random number generator using xorshift128.
|
|
9
9
|
*
|
|
@@ -29,5 +29,12 @@ export declare class SeededRNG implements RNG {
|
|
|
29
29
|
private nextUint32;
|
|
30
30
|
next(): number;
|
|
31
31
|
nextInt(min: number, max: number): number;
|
|
32
|
+
/**
|
|
33
|
+
* Unbiased sampling in `[0, range)` for ranges above 2^32, built from two
|
|
34
|
+
* uint32 draws combined into a 53-bit integer (the largest width JS numbers
|
|
35
|
+
* represent exactly). Ranges beyond 2^53 cannot be sampled without bias —
|
|
36
|
+
* throw instead of silently degrading.
|
|
37
|
+
*/
|
|
38
|
+
private nextBoundedWide;
|
|
32
39
|
}
|
|
33
40
|
//# sourceMappingURL=seeded.d.ts.map
|
package/dist/rng/seeded.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seeded.d.ts","sourceRoot":"","sources":["../../src/rng/seeded.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"seeded.d.ts","sourceRoot":"","sources":["../../src/rng/seeded.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEtC;;;;;;;;;;;;;GAaG;AACH,qBAAa,SAAU,YAAW,GAAG;IACnC,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,EAAE,CAAS;gBAEP,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;IAelC,OAAO,CAAC,SAAS;IA+BjB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,UAAU;IAgBlB,IAAI,IAAI,MAAM;IAKd,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IA6BzC;;;;;OAKG;IACH,OAAO,CAAC,eAAe;CAiBxB"}
|
package/dist/roll.d.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module roll
|
|
5
5
|
*/
|
|
6
|
-
import type { RNG } from './rng/types';
|
|
7
|
-
import type { RollResult } from './types';
|
|
6
|
+
import type { RNG } from './rng/types.js';
|
|
7
|
+
import type { RollResult } from './types.js';
|
|
8
8
|
/**
|
|
9
9
|
* Options for the roll function.
|
|
10
10
|
*/
|
|
@@ -19,6 +19,10 @@ export type RollOptions = {
|
|
|
19
19
|
maxExplodeIterations?: number;
|
|
20
20
|
/** Maximum reroll iterations allowed per die (default: 1,000) */
|
|
21
21
|
maxRerollIterations?: number;
|
|
22
|
+
/** Variable context for `@name` / `@{name}` references (default: empty) */
|
|
23
|
+
context?: Record<string, number>;
|
|
24
|
+
/** Behavior when a referenced variable is missing from context (default: 'throw') */
|
|
25
|
+
onMissingVariable?: 'throw' | 'zero';
|
|
22
26
|
};
|
|
23
27
|
/**
|
|
24
28
|
* Parses and evaluates a dice notation string.
|
package/dist/roll.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roll.d.ts","sourceRoot":"","sources":["../src/roll.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"roll.d.ts","sourceRoot":"","sources":["../src/roll.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,EAAmB,UAAU,EAAE,MAAM,YAAY,CAAC;AAM9D;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,uDAAuD;IACvD,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,qFAAqF;IACrF,iBAAiB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACtC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,UAAU,CAiB5E"}
|
package/dist/testing.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module testing
|
|
7
7
|
*/
|
|
8
|
-
import { MockRNGExhaustedError as _MockRNGExhaustedError, createMockRng as _createMockRng } from './rng/mock';
|
|
8
|
+
import { MockRNGExhaustedError as _MockRNGExhaustedError, createMockRng as _createMockRng } from './rng/mock.js';
|
|
9
9
|
export declare const createMockRng: typeof _createMockRng;
|
|
10
10
|
export declare const MockRNGExhaustedError: typeof _MockRNGExhaustedError;
|
|
11
11
|
//# sourceMappingURL=testing.d.ts.map
|
package/dist/testing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EACL,qBAAqB,IAAI,sBAAsB,EAC/C,aAAa,IAAI,cAAc,EAChC,MAAM,
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EACL,qBAAqB,IAAI,sBAAsB,EAC/C,aAAa,IAAI,cAAc,EAChC,MAAM,eAAe,CAAC;AAEvB,eAAO,MAAM,aAAa,uBAAiB,CAAC;AAC5C,eAAO,MAAM,qBAAqB,+BAAyB,CAAC"}
|