goldstein 1.4.0 → 2.0.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 +18 -0
- package/README.md +18 -6
- package/package.json +1 -1
- package/packages/goldstein/index.js +2 -2
- package/packages/keyword-guard/index.js +6 -2
- package/packages/keyword-if/index.js +27 -0
- package/packages/{keyword-safe → keyword-try}/index.js +44 -25
- package/packages/operator/index.js +1 -0
- package/packages/operator/scopeflags.js +21 -0
package/ChangeLog
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
2022.06.22, v2.0.0
|
|
2
|
+
|
|
3
|
+
feature:
|
|
4
|
+
- goldstein: keyword: safe -> try
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
2022.06.22, v1.6.0
|
|
8
|
+
|
|
9
|
+
feature:
|
|
10
|
+
- goldstein: guard keyword: add ability to omit parens
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
2022.06.22, v1.5.0
|
|
14
|
+
|
|
15
|
+
feature:
|
|
16
|
+
- goldstein: keyword if: add ability to omit parens
|
|
17
|
+
|
|
18
|
+
|
|
1
19
|
2022.06.22, v1.4.0
|
|
2
20
|
|
|
3
21
|
feature:
|
package/README.md
CHANGED
|
@@ -77,7 +77,7 @@ Here is the list.
|
|
|
77
77
|
|
|
78
78
|
You can use `fn` to declare a `function`:
|
|
79
79
|
|
|
80
|
-
```
|
|
80
|
+
```rust
|
|
81
81
|
fn hello() {
|
|
82
82
|
return 'world';
|
|
83
83
|
}
|
|
@@ -95,9 +95,9 @@ function hello() {
|
|
|
95
95
|
|
|
96
96
|
Applies not to `IfCondition`:
|
|
97
97
|
|
|
98
|
-
```
|
|
98
|
+
```swift
|
|
99
99
|
fn hello() {
|
|
100
|
-
guard
|
|
100
|
+
guard text !== "world" else {
|
|
101
101
|
return ""
|
|
102
102
|
}
|
|
103
103
|
|
|
@@ -117,12 +117,14 @@ function hello() {
|
|
|
117
117
|
}
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
### `
|
|
120
|
+
### `try`
|
|
121
|
+
|
|
122
|
+
`try` can be used as an expression.
|
|
121
123
|
|
|
122
124
|
Applies [`tryCatch`](https://github.com/coderaiser/try-catch):
|
|
123
125
|
|
|
124
126
|
```gs
|
|
125
|
-
const [error, result] =
|
|
127
|
+
const [error, result] = try hello(1, 2, 3);
|
|
126
128
|
```
|
|
127
129
|
|
|
128
130
|
Is the same as:
|
|
@@ -135,7 +137,7 @@ const [error, result] = tryCatch(1, 2, 3);
|
|
|
135
137
|
and
|
|
136
138
|
|
|
137
139
|
```gs
|
|
138
|
-
const [error, result] =
|
|
140
|
+
const [error, result] = try await hello(1, 2, 3);
|
|
139
141
|
```
|
|
140
142
|
|
|
141
143
|
Is the same as:
|
|
@@ -145,6 +147,16 @@ import tryToCatch from 'try-catch';
|
|
|
145
147
|
const [error, result] = await tryToCatch(1, 2, 3);
|
|
146
148
|
```
|
|
147
149
|
|
|
150
|
+
### `if`
|
|
151
|
+
|
|
152
|
+
You can omit parens. But you must use braces in this case.
|
|
153
|
+
|
|
154
|
+
```rust
|
|
155
|
+
if a > 3 {
|
|
156
|
+
hello();
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
148
160
|
## How to contribute?
|
|
149
161
|
|
|
150
162
|
Clone the registry, create a new keyword with a prefix `keyword-`, then create directory `fixture` and put there two files with extensions `.js` and `.gs`. Half way done 🥳!
|
package/package.json
CHANGED
|
@@ -4,13 +4,13 @@ import putout, {
|
|
|
4
4
|
import {extendParser} from '../parser/index.js';
|
|
5
5
|
import keywordFn from '../keyword-fn/index.js';
|
|
6
6
|
import keywordGuard from '../keyword-guard/index.js';
|
|
7
|
-
import
|
|
7
|
+
import keywordTry from '../keyword-try/index.js';
|
|
8
8
|
|
|
9
9
|
export const compile = (source) => {
|
|
10
10
|
const {parse} = extendParser([
|
|
11
11
|
keywordFn,
|
|
12
12
|
keywordGuard,
|
|
13
|
-
|
|
13
|
+
keywordTry,
|
|
14
14
|
]);
|
|
15
15
|
|
|
16
16
|
const ast = parse(source);
|
|
@@ -33,7 +33,7 @@ export default function newSpeak(Parser) {
|
|
|
33
33
|
} = tokTypes;
|
|
34
34
|
|
|
35
35
|
const node = super.startNode();
|
|
36
|
-
super.
|
|
36
|
+
const isParenL = super.eat(parenL);
|
|
37
37
|
|
|
38
38
|
node.test = {
|
|
39
39
|
type: 'UnaryExpression',
|
|
@@ -42,7 +42,11 @@ export default function newSpeak(Parser) {
|
|
|
42
42
|
argument: super.parseExpression(),
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
super.
|
|
45
|
+
const isParenR = super.eat(parenR);
|
|
46
|
+
|
|
47
|
+
if (isParenL !== isParenR)
|
|
48
|
+
this.raise(this.start, `Use both parens ('(', ')') or none`);
|
|
49
|
+
|
|
46
50
|
super.expect(_else);
|
|
47
51
|
|
|
48
52
|
node.consequent = this.parseStatement();
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
tokTypes as tt,
|
|
3
|
+
} from '../operator/index.js';
|
|
4
|
+
|
|
5
|
+
export default function fn(Parser) {
|
|
6
|
+
return class extends Parser {
|
|
7
|
+
parseIfStatement(node) {
|
|
8
|
+
this.next();
|
|
9
|
+
|
|
10
|
+
const isParenL = this.eat(tt.parenL);
|
|
11
|
+
node.test = this.parseExpression();
|
|
12
|
+
const isParenR = this.eat(tt.parenR);
|
|
13
|
+
|
|
14
|
+
if (!isParenL && !isParenR && this.type !== tt.braceL)
|
|
15
|
+
this.raise(this.start, `Use braces ('{', '}') when omit parens ('(', ')')`);
|
|
16
|
+
|
|
17
|
+
if (isParenL !== isParenR)
|
|
18
|
+
this.raise(this.start, `Use both parens ('(', ')') or none`);
|
|
19
|
+
|
|
20
|
+
node.consequent = this.parseStatement('if');
|
|
21
|
+
node.alternate = this.eat(tt._else) ? this.parseStatement('if') : null;
|
|
22
|
+
|
|
23
|
+
return this.finishNode(node, 'IfStatement');
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {types} from 'putout';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
BIND_LEXICAL,
|
|
4
|
+
BIND_SIMPLE_CATCH,
|
|
5
|
+
SCOPE_SIMPLE_CATCH,
|
|
6
|
+
tokTypes as tt,
|
|
5
7
|
} from '../operator/index.js';
|
|
6
8
|
|
|
7
9
|
const {
|
|
@@ -9,39 +11,24 @@ const {
|
|
|
9
11
|
isAwaitExpression,
|
|
10
12
|
} = types;
|
|
11
13
|
|
|
12
|
-
// why not 'try'?
|
|
13
|
-
// because acorn internals should be copied, and added tests.
|
|
14
|
-
// there is no such thing as this.previous(), only this.next() 🤷
|
|
15
|
-
|
|
16
14
|
export default function newSpeak(Parser) {
|
|
17
15
|
const {keywordTypes} = Parser.acorn;
|
|
18
|
-
keywordTypes.safe = new TokenType('safe', {
|
|
19
|
-
keyword: 'safe',
|
|
20
|
-
});
|
|
21
16
|
|
|
22
17
|
return class extends Parser {
|
|
23
|
-
parse() {
|
|
24
|
-
this.keywords = addKeyword('safe', this.keywords);
|
|
25
|
-
|
|
26
|
-
return super.parse();
|
|
27
|
-
}
|
|
28
|
-
parseStatement(context, topLevel, exports) {
|
|
29
|
-
if (this.type === keywordTypes.safe)
|
|
30
|
-
return this.parseSafe();
|
|
31
|
-
|
|
32
|
-
return super.parseStatement(context, topLevel, exports);
|
|
33
|
-
}
|
|
34
18
|
parseExprAtom(refDestructuringErrors, forInit) {
|
|
35
|
-
if (this.type === keywordTypes.
|
|
36
|
-
return this.
|
|
19
|
+
if (this.type === keywordTypes.try)
|
|
20
|
+
return this.parseTryStatement();
|
|
37
21
|
|
|
38
22
|
return super.parseExprAtom(refDestructuringErrors, forInit);
|
|
39
23
|
}
|
|
40
24
|
|
|
41
|
-
|
|
25
|
+
parseTryStatement() {
|
|
42
26
|
this.next();
|
|
43
|
-
|
|
44
27
|
const node = super.startNode();
|
|
28
|
+
|
|
29
|
+
if (this.type === tt.braceL)
|
|
30
|
+
return this.parseUglyTry(node);
|
|
31
|
+
|
|
45
32
|
const expression = this.parseExpression();
|
|
46
33
|
|
|
47
34
|
if (isCallExpression(expression))
|
|
@@ -74,10 +61,42 @@ export default function newSpeak(Parser) {
|
|
|
74
61
|
};
|
|
75
62
|
|
|
76
63
|
else
|
|
77
|
-
this.raise(this.start, `After '
|
|
64
|
+
this.raise(this.start, `After 'try' only '{', 'await' and 'function call' can come`);
|
|
78
65
|
|
|
79
66
|
return super.finishNode(node, 'ExpressionStatement');
|
|
80
67
|
}
|
|
68
|
+
parseUglyTry(node) {
|
|
69
|
+
node.block = this.parseBlock();
|
|
70
|
+
node.handler = null;
|
|
71
|
+
|
|
72
|
+
if (this.type === tt._catch) {
|
|
73
|
+
const clause = this.startNode();
|
|
74
|
+
this.next();
|
|
75
|
+
|
|
76
|
+
if (this.eat(tt.parenL)) {
|
|
77
|
+
clause.param = this.parseBindingAtom();
|
|
78
|
+
const simple = clause.param.type === 'Identifier';
|
|
79
|
+
|
|
80
|
+
this.enterScope(simple ? SCOPE_SIMPLE_CATCH : 0);
|
|
81
|
+
this.checkLValPattern(clause.param, simple ? BIND_SIMPLE_CATCH : BIND_LEXICAL);
|
|
82
|
+
this.expect(tt.parenR);
|
|
83
|
+
} else {
|
|
84
|
+
clause.param = null;
|
|
85
|
+
this.enterScope(0);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
clause.body = this.parseBlock(false);
|
|
89
|
+
this.exitScope();
|
|
90
|
+
node.handler = this.finishNode(clause, 'CatchClause');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null;
|
|
94
|
+
|
|
95
|
+
if (!node.handler && !node.finalizer)
|
|
96
|
+
this.raise(node.start, 'Missing catch or finally clause');
|
|
97
|
+
|
|
98
|
+
return this.finishNode(node, 'TryStatement');
|
|
99
|
+
}
|
|
81
100
|
};
|
|
82
101
|
}
|
|
83
102
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Each scope gets a bitset that may contain these flags
|
|
2
|
+
export const
|
|
3
|
+
SCOPE_TOP = 1,
|
|
4
|
+
SCOPE_FUNCTION = 2,
|
|
5
|
+
SCOPE_ASYNC = 4,
|
|
6
|
+
SCOPE_GENERATOR = 8,
|
|
7
|
+
SCOPE_ARROW = 16,
|
|
8
|
+
SCOPE_SIMPLE_CATCH = 32,
|
|
9
|
+
SCOPE_SUPER = 64,
|
|
10
|
+
SCOPE_DIRECT_SUPER = 128,
|
|
11
|
+
SCOPE_CLASS_STATIC_BLOCK = 256,
|
|
12
|
+
SCOPE_VAR = SCOPE_TOP | SCOPE_FUNCTION | SCOPE_CLASS_STATIC_BLOCK;
|
|
13
|
+
|
|
14
|
+
// Used in checkLVal* and declareName to determine the type of a binding
|
|
15
|
+
export const
|
|
16
|
+
BIND_NONE = 0, // Not a binding
|
|
17
|
+
BIND_VAR = 1, // Var-style binding
|
|
18
|
+
BIND_LEXICAL = 2, // Let- or const-style binding
|
|
19
|
+
BIND_FUNCTION = 3, // Function declaration
|
|
20
|
+
BIND_SIMPLE_CATCH = 4, // Simple (identifier pattern) catch binding
|
|
21
|
+
BIND_OUTSIDE = 5; // Special case for function names as bound inside the function
|