Skip to content

Commit ac5e57d

Browse files
Merge pull request #53 from ShaderFrog/error-format
6.0.0 Breaking change: parser.parse() -> parse() with better error message
2 parents 93eba7b + f0cf83a commit ac5e57d

16 files changed

+176
-225
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ dist
55
tmp
66
src/parser/parser.js
77
src/preprocessor/preprocessor-parser.js
8-
tsconfig.tsbuildinfo
8+
tsconfig.tsbuildinfo

README.md

Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,18 @@ npm install --save @shaderfrog/glsl-parser
3939
## Parsing
4040

4141
```typescript
42-
import { parser, generate } from '@shaderfrog/glsl-parser';
42+
import { parse, generate } from '@shaderfrog/glsl-parser';
4343

4444
// To parse a GLSL program's source code into an AST:
45-
const program = parser.parse('float a = 1.0;');
45+
const program = parse('float a = 1.0;');
4646

4747
// To turn a parsed AST back into a source program
4848
const transpiled = generate(program);
4949
```
5050

5151
The parser accepts an optional second `options` argument:
5252
```js
53-
parser.parse('float a = 1.0;', options);
53+
parse('float a = 1.0;', options);
5454
```
5555

5656
Where `options` is:
@@ -72,28 +72,26 @@ type ParserOptions = {
7272
// Hide warnings. If set to false or not set, then the parser logs warnings
7373
// like undefined functions and variables. If `failOnWarn` is set to true,
7474
// warnings will still cause the parser to raise an error. Defaults to false.
75-
quiet: boolean;
76-
77-
// An optional string representing the origin of the GLSL, for debugging and
78-
// error messages. For example, "main.js". If the parser raises an error, the
79-
// grammarSource shows up in the error.source field. If you format the error
80-
// (see the errors section), the grammarSource shows up in the formatted error
81-
// string. Defaults to undefined.
82-
grammarSource: string;
75+
quiet?: boolean;
8376

8477
// If true, sets location information on each AST node, in the form of
8578
// { column: number, line: number, offset: number }. Defaults to false.
86-
includeLocation: boolean;
79+
includeLocation?: boolean;
8780

8881
// If true, causes the parser to raise an error instead of log a warning.
8982
// The parser does limited type checking, and things like undeclared variables
9083
// are treated as warnings. Defaults to false.
91-
failOnWarn: boolean;
84+
failOnWarn?: boolean;
85+
86+
// An optional string representing the file name of your GLSL For example,
87+
// you can pass "main.glsl" here. If an error is raised, the error message
88+
// will show "main.glsl:row:column". This is only used in the error message.
89+
grammarSource?: string;
9290
}
9391
```
9492
9593
## The program type
96-
`parser.parse()` returns a `Program`, which is a special AST Node:
94+
`parse()` returns a `Program`, which is a special AST Node:
9795
9896
```typescript
9997
interface Program {
@@ -194,27 +192,23 @@ See also [Utility-Functions](#Utility-Functions) for renaming scope references.
194192

195193
## Errors
196194

197-
If you have invalid GLSL, the parser throws a `GlslSyntaxError`. The parser uses
198-
Peggy under the hood, so `GlslSyntaxError` is a convenience type alias for a
199-
`peggy.SyntaxError`.
195+
If you have invalid GLSL, the parser throws a `GlslSyntaxError`.
200196

201197
```ts
202-
import { parser, GlslSyntaxError } from '@shaderfrog/glsl-parser';
198+
import { parse, GlslSyntaxError } from '@shaderfrog/glsl-parser';
203199

204200
let error: GlslSyntaxError | undefined;
205201
try {
206202
// Line without a semicolon
207-
c.parse(`float a`);
203+
parse(`float a`);
208204
} catch (e) {
209205
error = e as GlslSyntaxError;
210206
}
211207
```
212208

213-
If you want to check if a caught error is an `instanceof` a `GlslSyntaxError`,
214-
then you need to use the Peggy `SyntaxError` error object, which lives on the
215-
parser:
209+
If you want to check if a caught error is an `instanceof` a `GlslSyntaxError`:
216210
```ts
217-
console.log(error instanceof parser.SyntaxError)
211+
console.log(error instanceof GlslSyntaxError)
218212
// true
219213
```
220214

@@ -224,7 +218,13 @@ should be safe to cast it to a `GlslSyntaxError` with `as` in Typescript.
224218
The error message string is automatically generated by Peggy:
225219
```ts
226220
console.log(error.message)
227-
// 'Expected ",", ";", "=", or array specifier but end of input found'
221+
/*
222+
Error: Expected ",", ";", "=", or array specifier but "f" found.
223+
--> undefined:2:1
224+
|
225+
2 | float b
226+
| ^
227+
*/
228228
```
229229

230230
The error object includes the location of the error. It is not printed in the
@@ -241,26 +241,10 @@ console.log(error.location)
241241
```
242242
Note the `source` field on the error object is the `grammarSource` string
243243
provided to the parser options, which is `undefined` by default. If you pass in
244-
a `grammarSource` to `parser.parse()`, it shows up in the error object. This is
244+
a `grammarSource` to `parse()`, it shows up in the error object. This is
245245
meant to help you track which source file you're parsing, for example you could
246-
enter `"myfile.glsl"` as an argument to `parser.parse()` so that the error
246+
enter `"myfile.glsl"` as an argument to `parse()` so that the error
247247
includes that your source GLSL came from your application's `myfile.glsl` file.
248-
249-
The error object also has a fairly confusing `format()` method, which comes
250-
from the underlying Peggy error object. It produces an ASCII formatted string
251-
with arrows and underlines. The `source` option passed to `.format()` **must**
252-
match your `grammarSource` in parser options (which is `undefined` by default).
253-
This API is awkward and I might override it in future versions of the parser.
254-
255-
```ts
256-
console.log(error.format([{ text, source: undefined }])
257-
/*
258-
Error: Expected ",", ";", "=", or array specifier but "f" found.
259-
--> undefined:2:1
260-
|
261-
2 | float b
262-
| ^
263-
*/
264248
```
265249
266250
## Preprocessing
@@ -311,14 +295,14 @@ import {
311295
preprocessAst,
312296
preprocessComments,
313297
generate,
314-
parser,
298+
parse,
315299
} from '@shaderfrog/glsl-parser/preprocessor';
316300

317301
// Remove comments before preprocessing
318302
const commentsRemoved = preprocessComments(`float a = 1.0;`);
319303

320304
// Parse the source text into an AST
321-
const ast = parser.parse(commentsRemoved);
305+
const ast = parse(commentsRemoved);
322306

323307
// Then preprocess it, expanding #defines, evaluating #ifs, etc
324308
preprocessAst(ast);
@@ -328,6 +312,23 @@ preprocessAst(ast);
328312
const preprocessed = generate(ast);
329313
```
330314

315+
## Accessing the raw Peggy parser
316+
If you need to access the Peggy compiled parser directly, import the `parser`.
317+
You can manually call `parser.parse()` if you prefer. Note if there are errors,
318+
rather than returning a `GlslSyntaxError`, it will return the underlying
319+
`peg$syntaxError`.
320+
321+
```typescript
322+
import { parser } from '@shaderfrog/glsl-parser';
323+
import { parser as preprocessorParser } from '@shaderfrog/glsl-parser/preprocessor';
324+
325+
try {
326+
const ast = parser.parse('float f = 1.0;');
327+
} catch (e) {
328+
console.log(e instanceof parser.SyntaxError); // true
329+
}
330+
```
331+
331332
## Manipulating and Searching ASTs
332333

333334
### Visitors
@@ -409,12 +410,12 @@ follow the same convention outlined above.
409410

410411
```typescript
411412
import {
412-
parser,
413+
parse,
413414
visitPreprocessedAst,
414415
} from '@shaderfrog/glsl-parser/preprocessor';
415416

416417
// Parse the source text into an AST
417-
const ast = parser.parse(`float a = 1.0;`);
418+
const ast = parse(`float a = 1.0;`);
418419
visitPreprocessedAst(ast, visitors);
419420
```
420421

build.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ npx tsc
1111
npx peggy --cache --format es -o dist/parser/parser.js src/parser/glsl-grammar.pegjs
1212
# Manualy copy in the type definitions
1313
cp src/parser/parser.d.ts dist/parser/
14-
cp src/error.d.ts dist/
1514

1615
npx peggy --cache --format es -o dist/preprocessor/preprocessor-parser.js src/preprocessor/preprocessor-grammar.pegjs
1716
cp src/preprocessor/preprocessor-parser.d.ts dist/preprocessor/preprocessor-parser.d.ts

jest.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ export default {
88
transform: {
99
'^.+\\.(t|j)sx?$': '@swc/jest',
1010
},
11+
// In CI, it builds the test files into JS files, which we don't want to run
12+
testMatch: ['**/*.test.ts'],
1113
};

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"engines": {
44
"node": ">=16"
55
},
6-
"version": "5.5.1",
6+
"version": "6.0.1",
77
"type": "module",
88
"description": "A GLSL ES 1.0 and 3.0 parser and preprocessor that can preserve whitespace and comments",
99
"scripts": {
@@ -16,8 +16,8 @@
1616
"files": [
1717
"ast",
1818
"index.d.ts",
19-
"error.d.ts",
2019
"index.js",
20+
"error.js",
2121
"parser",
2222
"preprocessor"
2323
],

postbuild.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/bin/bash
22
set -e
33

4-
rm -rf ast index.d.ts index.js parser preprocessor
4+
rm -rf ast index.d.ts error.js index.js parser preprocessor

src/error.d.ts

Lines changed: 0 additions & 143 deletions
This file was deleted.

0 commit comments

Comments
 (0)