11import { describe , it , test } from "node:test"
22import assert from "node:assert"
3- import { parseRegExp , parseRegExpString } from "../src/regex-parser"
3+ import { parseRegExp , parseRegExpString , UnsupportedSyntaxError } from "../src/regex-parser"
44import { RB } from "../src/index"
55import { ParseError } from "../src/parser"
66import * as AST from "../src/ast"
@@ -12,7 +12,7 @@ import * as Arbitrary from './arbitrary-ast'
1212function char ( c : string ) {
1313 return AST . literal ( CharSet . singleton ( c ) )
1414}
15- function str ( s : string ) {
15+ function str ( s : string ) {
1616 const chars = [ ...s ] . map ( char )
1717 // Use right-associative concatenation: a(bc) not (ab)c
1818 return chars . reduceRight ( ( acc , curr ) => AST . concat ( curr , acc ) )
@@ -44,7 +44,7 @@ describe('parseRegExp', () => {
4444 [ / a { 3 , 5 } / , AST . repeat ( char ( 'a' ) , { min : 3 , max : 5 } ) ] ,
4545 // if curly bracket is not terminated the whole thing is interpreted literally:
4646 [ / a { 3 , 5 / , str ( 'a{3,5' ) ] ,
47- // same if max value is given but min value is missing:
47+ // same if max value is given but min value is missing:
4848 [ / a { , 5 } / , str ( 'a{,5}' ) ] ,
4949 // char classes / escaping:
5050 [ / \w / , AST . literal ( CharSet . wordChars ) ] ,
@@ -72,21 +72,21 @@ describe('parseRegExp', () => {
7272 [ / ^ a b c $ / , AST . startAnchor ( undefined , AST . endAnchor ( str ( 'abc' ) , undefined ) ) ] ,
7373 [ / $ a ^ / , AST . startAnchor ( AST . endAnchor ( undefined , char ( 'a' ) ) , undefined ) ] ,
7474 // positive lookahead - now parsed as lookahead AST nodes, not intersections
75- [ / (? = a ) b / , AST . lookahead ( true , char ( 'a' ) , char ( 'b' ) ) ] ,
76- [ / (? = a ) (?: b ) / , AST . lookahead ( true , char ( 'a' ) , char ( 'b' ) ) ] ,
77- [ / (? = a ) (? = b ) c / , AST . lookahead ( true , char ( 'a' ) , AST . lookahead ( true , char ( 'b' ) , char ( 'c' ) ) ) ] ,
78- [ / a (? = b ) c / , AST . concat ( char ( 'a' ) , AST . lookahead ( true , char ( 'b' ) , char ( 'c' ) ) ) ] ,
79- [ / a (? = b ) / , AST . concat ( char ( 'a' ) , AST . lookahead ( true , char ( 'b' ) , AST . epsilon ) ) ] ,
80- [ / a (? = b ) c (? = d ) e / , AST . concat ( char ( 'a' ) , AST . lookahead ( true , char ( 'b' ) , AST . concat ( char ( 'c' ) , AST . lookahead ( true , char ( 'd' ) , char ( 'e' ) ) ) ) ) ] ,
81- [ / (? = ) / , AST . lookahead ( true , AST . epsilon , AST . epsilon ) ] ,
75+ [ / (? = a ) b / , AST . lookahead ( true , char ( 'a' ) , char ( 'b' ) ) ] ,
76+ [ / (? = a ) (?: b ) / , AST . lookahead ( true , char ( 'a' ) , char ( 'b' ) ) ] ,
77+ [ / (? = a ) (? = b ) c / , AST . lookahead ( true , char ( 'a' ) , AST . lookahead ( true , char ( 'b' ) , char ( 'c' ) ) ) ] ,
78+ [ / a (? = b ) c / , AST . concat ( char ( 'a' ) , AST . lookahead ( true , char ( 'b' ) , char ( 'c' ) ) ) ] ,
79+ [ / a (? = b ) / , AST . concat ( char ( 'a' ) , AST . lookahead ( true , char ( 'b' ) , AST . epsilon ) ) ] ,
80+ [ / a (? = b ) c (? = d ) e / , AST . concat ( char ( 'a' ) , AST . lookahead ( true , char ( 'b' ) , AST . concat ( char ( 'c' ) , AST . lookahead ( true , char ( 'd' ) , char ( 'e' ) ) ) ) ) ] ,
81+ [ / (? = ) / , AST . lookahead ( true , AST . epsilon , AST . epsilon ) ] ,
8282 // negative lookahead
83- [ / (? ! a ) b / , AST . lookahead ( false , char ( 'a' ) , char ( 'b' ) ) ] ,
83+ [ / (? ! a ) b / , AST . lookahead ( false , char ( 'a' ) , char ( 'b' ) ) ] ,
8484 [ / (? ! a ) b | c / , AST . union ( AST . lookahead ( false , char ( 'a' ) , char ( 'b' ) ) , char ( 'c' ) ) ] ,
8585 [ / (? ! ) / , AST . lookahead ( false , AST . epsilon , AST . epsilon ) ] ,
8686 // TODO: positive lookbehind
87- // [/(?<=a)/, AST.positiveLookbehind(char('a'))],
87+ // [/(?<=a)/, AST.positiveLookbehind(char('a'))],
8888 // TODO: negative lookbehind
89- // [/(?<!a)/, AST.negativeLookbehind(char('a'))],
89+ // [/(?<!a)/, AST.negativeLookbehind(char('a'))],
9090 // some special chars don't need escape when inside brackets:
9191 [ / [ . ^ $ * + ? ( ) [ { - | ] / , AST . literal ( CharSet . fromArray ( [ ...'.^$*+?()[{-|' ] ) ) ] ,
9292 // other special chars need escape even inside brackets:
@@ -134,12 +134,24 @@ describe('parseRegExp', () => {
134134
135135} )
136136
137+ function parse_skipKnownIssues ( re : RegExp ) {
138+ try {
139+ return RB ( re )
140+ } catch ( error ) {
141+ if ( error instanceof UnsupportedSyntaxError ) {
142+ fc . pre ( false )
143+ } else {
144+ throw error
145+ }
146+ }
147+ }
148+
137149test ( 'parse/stringify roundtrip preserves equivalence' , { todo :true } , ( ) => {
138150 fc . assert (
139151 fc . property (
140152 Arbitrary . regexp ( ) ,
141153 ( inputRegExp : RegExp ) => {
142- const builder = RB ( inputRegExp )
154+ const builder = parse_skipKnownIssues ( inputRegExp )
143155 const outputRegExp = builder . toRegExp ( )
144156
145157 for ( const str of builder . enumerate ( ) . take ( 10 ) ) {
@@ -148,19 +160,6 @@ test('parse/stringify roundtrip preserves equivalence', {todo:true}, () => {
148160 }
149161 } ,
150162 ) ,
151- // { numRuns: 1000 },
163+ { numRuns : 100 } ,
152164 )
153165} )
154-
155- test ( 'fixme 1' , { todo : true } , ( ) => {
156- const inputRegExp = / ( ^ ) + a /
157- const builder = RB ( inputRegExp )
158- const outputRegExp = builder . toRegExp ( )
159-
160- // console.debug(outputRegExp)
161-
162- for ( const str of builder . enumerate ( ) . take ( 10 ) ) {
163- assert . match ( str , outputRegExp )
164- assert . match ( str , inputRegExp )
165- }
166- } )
0 commit comments