LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
/*
* Copyright ( c ) 2020 , Emanuel Sprung < emanuel . sprung @ gmail . com >
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
*/
2021-06-16 11:28:06 +00:00
# include "LibRegex/RegexMatcher.h"
2021-04-25 05:53:23 +00:00
# include <LibTest/TestCase.h> // import first, to prevent warning of VERIFY* redefinition
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
2020-06-09 15:16:04 +00:00
# include <AK/StringBuilder.h>
2021-09-12 13:00:27 +00:00
# include <AK/Tuple.h>
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
# include <LibRegex/Regex.h>
# include <LibRegex/RegexDebug.h>
# include <stdio.h>
static ECMAScriptOptions match_test_api_options ( const ECMAScriptOptions options )
{
return options ;
}
static PosixOptions match_test_api_options ( const PosixOptions options )
{
return options ;
}
2021-08-11 20:41:57 +00:00
template < typename . . . Flags >
static constexpr ECMAScriptFlags combine_flags ( Flags & & . . . flags ) requires ( ( IsSame < Flags , ECMAScriptFlags > & & . . . ) )
{
return static_cast < ECMAScriptFlags > ( ( static_cast < regex : : FlagsUnderlyingType > ( flags ) | . . . ) ) ;
}
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
TEST_CASE ( regex_options_ecmascript )
{
ECMAScriptOptions eo ;
eo | = ECMAScriptFlags : : Global ;
EXPECT ( eo & ECMAScriptFlags : : Global ) ;
EXPECT ( ! ( eo & ECMAScriptFlags : : Insensitive ) ) ;
eo = match_test_api_options ( ECMAScriptFlags : : Global | ECMAScriptFlags : : Insensitive | ECMAScriptFlags : : Sticky ) ;
EXPECT ( eo & ECMAScriptFlags : : Global ) ;
EXPECT ( eo & ECMAScriptFlags : : Insensitive ) ;
EXPECT ( eo & ECMAScriptFlags : : Sticky ) ;
EXPECT ( ! ( eo & ECMAScriptFlags : : Unicode ) ) ;
EXPECT ( ! ( eo & ECMAScriptFlags : : Multiline ) ) ;
EXPECT ( ! ( eo & ECMAScriptFlags : : SingleLine ) ) ;
eo & = ECMAScriptFlags : : Insensitive ;
EXPECT ( ! ( eo & ECMAScriptFlags : : Global ) ) ;
EXPECT ( eo & ECMAScriptFlags : : Insensitive ) ;
EXPECT ( ! ( eo & ECMAScriptFlags : : Multiline ) ) ;
eo & = ECMAScriptFlags : : Sticky ;
EXPECT ( ! ( eo & ECMAScriptFlags : : Global ) ) ;
EXPECT ( ! ( eo & ECMAScriptFlags : : Insensitive ) ) ;
EXPECT ( ! ( eo & ECMAScriptFlags : : Multiline ) ) ;
EXPECT ( ! ( eo & ECMAScriptFlags : : Sticky ) ) ;
eo = ~ ECMAScriptFlags : : Insensitive ;
EXPECT ( eo & ECMAScriptFlags : : Global ) ;
EXPECT ( ! ( eo & ECMAScriptFlags : : Insensitive ) ) ;
EXPECT ( eo & ECMAScriptFlags : : Multiline ) ;
EXPECT ( eo & ECMAScriptFlags : : Sticky ) ;
}
TEST_CASE ( regex_options_posix )
{
PosixOptions eo ;
eo | = PosixFlags : : Global ;
EXPECT ( eo & PosixFlags : : Global ) ;
EXPECT ( ! ( eo & PosixFlags : : Insensitive ) ) ;
eo = match_test_api_options ( PosixFlags : : Global | PosixFlags : : Insensitive | PosixFlags : : MatchNotBeginOfLine ) ;
EXPECT ( eo & PosixFlags : : Global ) ;
EXPECT ( eo & PosixFlags : : Insensitive ) ;
EXPECT ( eo & PosixFlags : : MatchNotBeginOfLine ) ;
EXPECT ( ! ( eo & PosixFlags : : Unicode ) ) ;
EXPECT ( ! ( eo & PosixFlags : : Multiline ) ) ;
eo & = PosixFlags : : Insensitive ;
EXPECT ( ! ( eo & PosixFlags : : Global ) ) ;
EXPECT ( eo & PosixFlags : : Insensitive ) ;
EXPECT ( ! ( eo & PosixFlags : : Multiline ) ) ;
eo & = PosixFlags : : MatchNotBeginOfLine ;
EXPECT ( ! ( eo & PosixFlags : : Global ) ) ;
EXPECT ( ! ( eo & PosixFlags : : Insensitive ) ) ;
EXPECT ( ! ( eo & PosixFlags : : Multiline ) ) ;
eo = ~ PosixFlags : : Insensitive ;
EXPECT ( eo & PosixFlags : : Global ) ;
EXPECT ( ! ( eo & PosixFlags : : Insensitive ) ) ;
EXPECT ( eo & PosixFlags : : Multiline ) ;
}
TEST_CASE ( regex_lexer )
{
Lexer l ( " /[.*+?^${}() | [ \ \ ] \ \ \ \ ] / g " ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : Slash ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : LeftBracket ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : Period ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : Asterisk ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : Plus ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : Questionmark ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : Circumflex ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : Dollar ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : LeftCurly ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : RightCurly ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : LeftParen ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : RightParen ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : Pipe ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : LeftBracket ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : EscapeSequence ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : EscapeSequence ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : RightBracket ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : Slash ) ;
EXPECT ( l . next ( ) . type ( ) = = regex : : TokenType : : Char ) ;
}
TEST_CASE ( parser_error_parens )
{
String pattern = " test()test " ;
Lexer l ( pattern ) ;
PosixExtendedParser p ( l ) ;
p . parse ( ) ;
EXPECT ( p . has_error ( ) ) ;
2021-11-06 09:33:46 +00:00
EXPECT ( p . error ( ) = = regex : : Error : : EmptySubExpression ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
}
TEST_CASE ( parser_error_special_characters_used_at_wrong_place )
{
String pattern ;
Vector < char , 5 > chars = { ' * ' , ' + ' , ' ? ' , ' { ' } ;
StringBuilder b ;
Lexer l ;
PosixExtended p ( l ) ;
for ( auto & ch : chars ) {
// First in ere
b . clear ( ) ;
b . append ( ch ) ;
pattern = b . build ( ) ;
l . set_source ( pattern ) ;
p . parse ( ) ;
EXPECT ( p . has_error ( ) ) ;
2021-11-06 09:33:46 +00:00
EXPECT ( p . error ( ) = = regex : : Error : : InvalidRepetitionMarker ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
// After vertical line
b . clear ( ) ;
b . append ( " a| " ) ;
b . append ( ch ) ;
pattern = b . build ( ) ;
l . set_source ( pattern ) ;
p . parse ( ) ;
EXPECT ( p . has_error ( ) ) ;
2021-11-06 09:33:46 +00:00
EXPECT ( p . error ( ) = = regex : : Error : : InvalidRepetitionMarker ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
// After circumflex
b . clear ( ) ;
b . append ( " ^ " ) ;
b . append ( ch ) ;
pattern = b . build ( ) ;
l . set_source ( pattern ) ;
p . parse ( ) ;
EXPECT ( p . has_error ( ) ) ;
2021-11-06 09:33:46 +00:00
EXPECT ( p . error ( ) = = regex : : Error : : InvalidRepetitionMarker ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
// After dollar
b . clear ( ) ;
b . append ( " $ " ) ;
b . append ( ch ) ;
pattern = b . build ( ) ;
l . set_source ( pattern ) ;
p . parse ( ) ;
EXPECT ( p . has_error ( ) ) ;
2021-11-06 09:33:46 +00:00
EXPECT ( p . error ( ) = = regex : : Error : : InvalidRepetitionMarker ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
// After left parens
b . clear ( ) ;
b . append ( " ( " ) ;
b . append ( ch ) ;
b . append ( " ) " ) ;
pattern = b . build ( ) ;
l . set_source ( pattern ) ;
p . parse ( ) ;
EXPECT ( p . has_error ( ) ) ;
2021-11-06 09:33:46 +00:00
EXPECT ( p . error ( ) = = regex : : Error : : InvalidRepetitionMarker ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
}
}
TEST_CASE ( parser_error_vertical_line_used_at_wrong_place )
{
Lexer l ;
PosixExtended p ( l ) ;
// First in ere
l . set_source ( " |asdf " ) ;
p . parse ( ) ;
EXPECT ( p . has_error ( ) ) ;
2021-11-06 09:33:46 +00:00
EXPECT ( p . error ( ) = = regex : : Error : : EmptySubExpression ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
// Last in ere
l . set_source ( " asdf| " ) ;
p . parse ( ) ;
EXPECT ( p . has_error ( ) ) ;
2021-11-06 09:33:46 +00:00
EXPECT ( p . error ( ) = = regex : : Error : : EmptySubExpression ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
// After left parens
l . set_source ( " (|asdf) " ) ;
p . parse ( ) ;
EXPECT ( p . has_error ( ) ) ;
2021-11-06 09:33:46 +00:00
EXPECT ( p . error ( ) = = regex : : Error : : EmptySubExpression ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
// Proceed right parens
l . set_source ( " (asdf)| " ) ;
p . parse ( ) ;
EXPECT ( p . has_error ( ) ) ;
2021-11-06 09:33:46 +00:00
EXPECT ( p . error ( ) = = regex : : Error : : EmptySubExpression ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
}
TEST_CASE ( catch_all_first )
{
Regex < PosixExtended > re ( " ^.*$ " ) ;
RegexResult m ;
re . match ( " Hello World " , m ) ;
EXPECT ( m . count = = 1 ) ;
EXPECT ( re . match ( " Hello World " , m ) ) ;
}
TEST_CASE ( catch_all )
{
Regex < PosixExtended > re ( " ^.*$ " , PosixFlags : : Global ) ;
EXPECT ( re . has_match ( " Hello World " ) ) ;
EXPECT ( re . match ( " Hello World " ) . success ) ;
EXPECT ( re . match ( " Hello World " ) . count = = 1 ) ;
EXPECT ( has_match ( " Hello World " , re ) ) ;
auto res = match ( " Hello World " , re ) ;
EXPECT ( res . success ) ;
EXPECT ( res . count = = 1 ) ;
EXPECT ( res . matches . size ( ) = = 1 ) ;
EXPECT ( res . matches . first ( ) . view = = " Hello World " ) ;
}
TEST_CASE ( catch_all_again )
{
Regex < PosixExtended > re ( " ^.*$ " , PosixFlags : : Extra ) ;
EXPECT_EQ ( has_match ( " Hello World " , re ) , true ) ;
}
TEST_CASE ( char_utf8 )
{
Regex < PosixExtended > re ( " 😀 " ) ;
RegexResult result ;
2021-09-18 16:02:41 +00:00
EXPECT_EQ ( ( result = match ( Utf8View { " Привет, мир! 😀 γειά σ ο υ κόσμος 😀 こんにちは世界 " sv } , re , PosixFlags : : Global ) ) . success , true ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
EXPECT_EQ ( result . count , 2u ) ;
}
TEST_CASE ( catch_all_newline )
{
Regex < PosixExtended > re ( " ^.*$ " , PosixFlags : : Multiline | PosixFlags : : StringCopyMatches ) ;
RegexResult result ;
auto lambda = [ & result , & re ] ( ) {
String aaa = " Hello World \n Test \n 1234 \n " ;
result = match ( aaa , re ) ;
EXPECT_EQ ( result . success , true ) ;
} ;
lambda ( ) ;
EXPECT_EQ ( result . count , 3u ) ;
EXPECT_EQ ( result . matches . at ( 0 ) . view , " Hello World " ) ;
EXPECT_EQ ( result . matches . at ( 1 ) . view , " Test " ) ;
EXPECT_EQ ( result . matches . at ( 2 ) . view , " 1234 " ) ;
}
TEST_CASE ( catch_all_newline_view )
{
Regex < PosixExtended > re ( " ^.*$ " , PosixFlags : : Multiline ) ;
RegexResult result ;
String aaa = " Hello World \n Test \n 1234 \n " ;
result = match ( aaa , re ) ;
EXPECT_EQ ( result . success , true ) ;
EXPECT_EQ ( result . count , 3u ) ;
String str = " Hello World " ;
EXPECT_EQ ( result . matches . at ( 0 ) . view , str . view ( ) ) ;
EXPECT_EQ ( result . matches . at ( 1 ) . view , " Test " ) ;
EXPECT_EQ ( result . matches . at ( 2 ) . view , " 1234 " ) ;
}
TEST_CASE ( catch_all_newline_2 )
{
Regex < PosixExtended > re ( " ^.*$ " ) ;
RegexResult result ;
result = match ( " Hello World \n Test \n 1234 \n " , re , PosixFlags : : Multiline | PosixFlags : : StringCopyMatches ) ;
EXPECT_EQ ( result . success , true ) ;
EXPECT_EQ ( result . count , 3u ) ;
EXPECT_EQ ( result . matches . at ( 0 ) . view , " Hello World " ) ;
EXPECT_EQ ( result . matches . at ( 1 ) . view , " Test " ) ;
EXPECT_EQ ( result . matches . at ( 2 ) . view , " 1234 " ) ;
result = match ( " Hello World \n Test \n 1234 \n " , re ) ;
EXPECT_EQ ( result . success , true ) ;
EXPECT_EQ ( result . count , 1u ) ;
EXPECT_EQ ( result . matches . at ( 0 ) . view , " Hello World \n Test \n 1234 \n " ) ;
}
TEST_CASE ( match_all_character_class )
{
Regex < PosixExtended > re ( " [[:alpha:]] " ) ;
String str = " [Window] \n Opacity=255 \n AudibleBeep=0 \n " ;
RegexResult result = match ( str , re , PosixFlags : : Global | PosixFlags : : StringCopyMatches ) ;
EXPECT_EQ ( result . success , true ) ;
EXPECT_EQ ( result . count , 24u ) ;
EXPECT_EQ ( result . matches . at ( 0 ) . view , " W " ) ;
EXPECT_EQ ( result . matches . at ( 1 ) . view , " i " ) ;
EXPECT_EQ ( result . matches . at ( 2 ) . view , " n " ) ;
}
2020-11-19 15:27:39 +00:00
TEST_CASE ( match_character_class_with_assertion )
{
Regex < PosixExtended > re ( " [[:alpha:]]+$ " ) ;
String str = " abcdef " ;
RegexResult result = match ( str , re ) ;
EXPECT_EQ ( result . success , true ) ;
EXPECT_EQ ( result . count , 1u ) ;
}
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
TEST_CASE ( example_for_git_commit )
{
Regex < PosixExtended > re ( " ^.*$ " ) ;
auto result = re . match ( " Well, hello friends! \n Hello World! " ) ;
EXPECT ( result . success ) ;
EXPECT ( result . count = = 1 ) ;
EXPECT ( result . matches . at ( 0 ) . view . starts_with ( " Well " ) ) ;
EXPECT ( result . matches . at ( 0 ) . view . length ( ) = = 33 ) ;
EXPECT ( re . has_match ( " Well,.... " ) ) ;
result = re . match ( " Well, hello friends! \n Hello World! " , PosixFlags : : Multiline ) ;
EXPECT ( result . success ) ;
EXPECT ( result . count = = 2 ) ;
EXPECT ( result . matches . at ( 0 ) . view = = " Well, hello friends! " ) ;
EXPECT ( result . matches . at ( 1 ) . view = = " Hello World! " ) ;
}
TEST_CASE ( email_address )
{
Regex < PosixExtended > re ( " ^[A-Z0-9a-z._%+-]{1,64}@([A-Za-z0-9-]{1,63} \\ .){1,125}[A-Za-z]{2,63}$ " ) ;
EXPECT ( re . has_match ( " hello.world@domain.tld " ) ) ;
EXPECT ( re . has_match ( " this.is.a.very_long_email_address@world.wide.web " ) ) ;
}
TEST_CASE ( ini_file_entries )
{
Regex < PosixExtended > re ( " [[:alpha:]]*=([[:digit:]]*)| \\ [(.*) \\ ] " ) ;
RegexResult result ;
2021-05-01 19:10:08 +00:00
if constexpr ( REGEX_DEBUG ) {
RegexDebug regex_dbg ( stderr ) ;
regex_dbg . print_raw_bytecode ( re ) ;
regex_dbg . print_header ( ) ;
regex_dbg . print_bytecode ( re ) ;
}
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
String haystack = " [Window] \n Opacity=255 \n AudibleBeep=0 \n " ;
EXPECT_EQ ( re . search ( haystack . view ( ) , result , PosixFlags : : Multiline ) , true ) ;
EXPECT_EQ ( result . count , 3u ) ;
2021-05-01 19:10:08 +00:00
if constexpr ( REGEX_DEBUG ) {
for ( auto & v : result . matches )
fprintf ( stderr , " %s \n " , v . view . to_string ( ) . characters ( ) ) ;
}
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
EXPECT_EQ ( result . matches . at ( 0 ) . view , " [Window] " ) ;
2020-06-08 22:15:09 +00:00
EXPECT_EQ ( result . capture_group_matches . at ( 0 ) . at ( 0 ) . view , " Window " ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
EXPECT_EQ ( result . matches . at ( 1 ) . view , " Opacity=255 " ) ;
EXPECT_EQ ( result . matches . at ( 1 ) . line , 1u ) ;
EXPECT_EQ ( result . matches . at ( 1 ) . column , 0u ) ;
EXPECT_EQ ( result . capture_group_matches . at ( 1 ) . at ( 0 ) . view , " 255 " ) ;
EXPECT_EQ ( result . capture_group_matches . at ( 1 ) . at ( 0 ) . line , 1u ) ;
EXPECT_EQ ( result . capture_group_matches . at ( 1 ) . at ( 0 ) . column , 8u ) ;
EXPECT_EQ ( result . matches . at ( 2 ) . view , " AudibleBeep=0 " ) ;
EXPECT_EQ ( result . capture_group_matches . at ( 2 ) . at ( 0 ) . view , " 0 " ) ;
EXPECT_EQ ( result . capture_group_matches . at ( 2 ) . at ( 0 ) . line , 2u ) ;
EXPECT_EQ ( result . capture_group_matches . at ( 2 ) . at ( 0 ) . column , 12u ) ;
}
2020-06-08 22:15:09 +00:00
TEST_CASE ( ini_file_entries2 )
{
Regex < PosixExtended > re ( " [[:alpha:]]*=([[:digit:]]*) " ) ;
RegexResult result ;
String haystack = " ViewMode=Icon " ;
EXPECT_EQ ( re . match ( haystack . view ( ) , result ) , false ) ;
EXPECT_EQ ( result . count , 0u ) ;
EXPECT_EQ ( re . search ( haystack . view ( ) , result ) , true ) ;
EXPECT_EQ ( result . count , 1u ) ;
}
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
TEST_CASE ( named_capture_group )
{
Regex < PosixExtended > re ( " [[:alpha:]]*=(?<Test>[[:digit:]]*) " ) ;
RegexResult result ;
2021-05-01 19:10:08 +00:00
if constexpr ( REGEX_DEBUG ) {
RegexDebug regex_dbg ( stderr ) ;
regex_dbg . print_raw_bytecode ( re ) ;
regex_dbg . print_header ( ) ;
regex_dbg . print_bytecode ( re ) ;
}
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
String haystack = " [Window] \n Opacity=255 \n AudibleBeep=0 \n " ;
EXPECT_EQ ( re . search ( haystack , result , PosixFlags : : Multiline ) , true ) ;
EXPECT_EQ ( result . count , 2u ) ;
EXPECT_EQ ( result . matches . at ( 0 ) . view , " Opacity=255 " ) ;
2021-08-14 20:28:54 +00:00
EXPECT_EQ ( result . capture_group_matches . at ( 0 ) . at ( 0 ) . view , " 255 " ) ;
EXPECT_EQ ( result . capture_group_matches . at ( 0 ) . at ( 0 ) . capture_group_name , " Test " ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
EXPECT_EQ ( result . matches . at ( 1 ) . view , " AudibleBeep=0 " ) ;
2021-08-14 20:28:54 +00:00
EXPECT_EQ ( result . capture_group_matches . at ( 1 ) . at ( 0 ) . view , " 0 " ) ;
EXPECT_EQ ( result . capture_group_matches . at ( 1 ) . at ( 0 ) . capture_group_name , " Test " ) ;
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
}
2021-07-06 15:09:46 +00:00
TEST_CASE ( ecma262_named_capture_group_with_dollar_sign )
{
Regex < ECMA262 > re ( " [a-zA-Z]*=(?<$Test$>[0-9]*) " ) ;
RegexResult result ;
if constexpr ( REGEX_DEBUG ) {
RegexDebug regex_dbg ( stderr ) ;
regex_dbg . print_raw_bytecode ( re ) ;
regex_dbg . print_header ( ) ;
regex_dbg . print_bytecode ( re ) ;
}
String haystack = " [Window] \n Opacity=255 \n AudibleBeep=0 \n " ;
EXPECT_EQ ( re . search ( haystack , result , ECMAScriptFlags : : Multiline ) , true ) ;
EXPECT_EQ ( result . count , 2u ) ;
EXPECT_EQ ( result . matches . at ( 0 ) . view , " Opacity=255 " ) ;
2021-08-14 20:28:54 +00:00
EXPECT_EQ ( result . capture_group_matches . at ( 0 ) . at ( 0 ) . view , " 255 " ) ;
EXPECT_EQ ( result . capture_group_matches . at ( 0 ) . at ( 0 ) . capture_group_name , " $Test$ " ) ;
2021-07-06 15:09:46 +00:00
EXPECT_EQ ( result . matches . at ( 1 ) . view , " AudibleBeep=0 " ) ;
2021-08-14 20:28:54 +00:00
EXPECT_EQ ( result . capture_group_matches . at ( 1 ) . at ( 0 ) . view , " 0 " ) ;
EXPECT_EQ ( result . capture_group_matches . at ( 1 ) . at ( 0 ) . capture_group_name , " $Test$ " ) ;
2021-07-06 15:09:46 +00:00
}
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
TEST_CASE ( a_star )
{
Regex < PosixExtended > re ( " a* " ) ;
RegexResult result ;
2021-05-01 19:10:08 +00:00
if constexpr ( REGEX_DEBUG ) {
RegexDebug regex_dbg ( stderr ) ;
regex_dbg . print_raw_bytecode ( re ) ;
regex_dbg . print_header ( ) ;
regex_dbg . print_bytecode ( re ) ;
}
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
String haystack = " [Window] \n Opacity=255 \n AudibleBeep=0 \n " ;
EXPECT_EQ ( re . search ( haystack . view ( ) , result , PosixFlags : : Multiline ) , true ) ;
EXPECT_EQ ( result . count , 32u ) ;
2021-07-18 00:36:01 +00:00
if ( result . count = = 32u ) {
EXPECT_EQ ( result . matches . at ( 0 ) . view . length ( ) , 0u ) ;
EXPECT_EQ ( result . matches . at ( 10 ) . view . length ( ) , 1u ) ;
EXPECT_EQ ( result . matches . at ( 10 ) . view , " a " ) ;
EXPECT_EQ ( result . matches . at ( 31 ) . view . length ( ) , 0u ) ;
}
LibRegex: Add a regular expression library
This commit is a mix of several commits, squashed into one because the
commits before 'Move regex to own Library and fix all the broken stuff'
were not fixable in any elegant way.
The commits are listed below for "historical" purposes:
- AK: Add options/flags and Errors for regular expressions
Flags can be provided for any possible flavour by adding a new scoped enum.
Handling of flags is done by templated Options class and the overloaded
'|' and '&' operators.
- AK: Add Lexer for regular expressions
The lexer parses the input and extracts tokens needed to parse a regular
expression.
- AK: Add regex Parser and PosixExtendedParser
This patchset adds a abstract parser class that can be derived to implement
different parsers. A parser produces bytecode to be executed within the
regex matcher.
- AK: Add regex matcher
This patchset adds an regex matcher based on the principles of the T-REX VM.
The bytecode pruduced by the respective Parser is put into the matcher and
the VM will recursively execute the bytecode according to the available OpCodes.
Possible improvement: the recursion could be replaced by multi threading capabilities.
To match a Regular expression, e.g. for the Posix standard regular expression matcher
use the following API:
```
Pattern<PosixExtendedParser> pattern("^.*$");
auto result = pattern.match("Well, hello friends!\nHello World!"); // Match whole needle
EXPECT(result.count == 1);
EXPECT(result.matches.at(0).view.starts_with("Well"));
EXPECT(result.matches.at(0).view.end() == "!");
result = pattern.match("Well, hello friends!\nHello World!", PosixFlags::Multiline); // Match line by line
EXPECT(result.count == 2);
EXPECT(result.matches.at(0).view == "Well, hello friends!");
EXPECT(result.matches.at(1).view == "Hello World!");
EXPECT(pattern.has_match("Well,....")); // Just check if match without a result, which saves some resources.
```
- AK: Rework regex to work with opcodes objects
This patchsets reworks the matcher to work on a more structured base.
For that an abstract OpCode class and derived classes for the specific
OpCodes have been added. The respective opcode logic is contained in
each respective execute() method.
- AK: Add benchmark for regex
- AK: Some optimization in regex for runtime and memory
- LibRegex: Move regex to own Library and fix all the broken stuff
Now regex works again and grep utility is also in place for testing.
This commit also fixes the use of regex.h in C by making `regex_t`
an opaque (-ish) type, which makes its behaviour consistent between
C and C++ compilers.
Previously, <regex.h> would've blown C compilers up, and even if it
didn't, would've caused a leak in C code, and not in C++ code (due to
the existence of `OwnPtr` inside the struct).
To make this whole ordeal easier to deal with (for now), this pulls the
definitions of `reg*()` into LibRegex.
pros:
- The circular dependency between LibC and LibRegex is broken
- Eaiser to test (without accidentally pulling in the host's libc!)
cons:
- Using any of the regex.h functions will require the user to link -lregex
- The symbols will be missing from libc, which will be a big surprise
down the line (especially with shared libs).
Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2020-04-26 12:45:10 +00:00
}
TEST_CASE ( simple_period_end_benchmark )
{
Regex < PosixExtended > re ( " hello.$ " ) ;
RegexResult m ;
EXPECT_EQ ( re . search ( " Hello1 " , m ) , false ) ;
EXPECT_EQ ( re . search ( " hello1hello1 " , m ) , true ) ;
EXPECT_EQ ( re . search ( " hello2hell " , m ) , false ) ;
EXPECT_EQ ( re . search ( " hello? " , m ) , true ) ;
}
2021-09-07 10:03:06 +00:00
TEST_CASE ( posix_extended_nested_capture_group )
{
Regex < PosixExtended > re ( " (h(e(?<llo>llo))) " ) ; // group 0 -> "hello", group 1 -> "ello", group 2/"llo" -> "llo"
auto result = re . match ( " hello " ) ;
EXPECT ( result . success ) ;
EXPECT_EQ ( result . capture_group_matches . size ( ) , 1u ) ;
EXPECT_EQ ( result . capture_group_matches [ 0 ] . size ( ) , 3u ) ;
EXPECT_EQ ( result . capture_group_matches [ 0 ] [ 0 ] . view , " hello " sv ) ;
EXPECT_EQ ( result . capture_group_matches [ 0 ] [ 1 ] . view , " ello " sv ) ;
EXPECT_EQ ( result . capture_group_matches [ 0 ] [ 2 ] . view , " llo " sv ) ;
}
2020-11-27 16:03:53 +00:00
TEST_CASE ( ECMA262_parse )
{
2020-11-30 14:16:53 +00:00
struct _test {
2021-08-15 03:28:06 +00:00
StringView pattern ;
2020-11-30 14:16:53 +00:00
regex : : Error expected_error { regex : : Error : : NoError } ;
2020-12-06 13:34:28 +00:00
regex : : ECMAScriptFlags flags { } ;
2020-11-30 14:16:53 +00:00
} ;
constexpr _test tests [ ] {
2021-08-15 03:28:06 +00:00
{ " ^hello.$ " sv } ,
{ " ^(hello.)$ " sv } ,
{ " ^h{0,1}ello.$ " sv } ,
{ " ^hello \\ W$ " sv } ,
{ " ^hell \\ w.$ " sv } ,
{ " ^hell \\ x6f1$ " sv } , // ^hello1$
{ " ^hel(?:l \\ w).$ " sv } ,
{ " ^hel(?<LO>l \\ w).$ " sv } ,
{ " ^[-a-zA-Z \\ w \\ s]+$ " sv } ,
{ " \\ bhello \\ B " sv } ,
{ " ^[ \\ w+/_-]+[=]{0,2}$ " sv } , // #4189
{ " ^(?:[^<]*(<[ \\ w \\ W]+>)[^>]*$|#([ \\ w \\ -]*)$) " sv } , // #4189
{ " \\ / " sv } , // #4189
{ " ,/=-: " sv } , // #4243
{ " \\ x " sv } , // Even invalid escapes are allowed if ~unicode.
{ " \\ x1 " sv } , // Even invalid escapes are allowed if ~unicode.
{ " \\ x1 " sv , regex : : Error : : InvalidPattern , regex : : ECMAScriptFlags : : Unicode } ,
{ " \\ x11 " sv } ,
{ " \\ x11 " sv , regex : : Error : : NoError , regex : : ECMAScriptFlags : : Unicode } ,
{ " \\ " sv , regex : : Error : : InvalidTrailingEscape } ,
{ " (? " sv , regex : : Error : : InvalidCaptureGroup } ,
{ " \\ u1234 " sv , regex : : Error : : NoError , regex : : ECMAScriptFlags : : Unicode } ,
{ " [ \\ u1234] " sv , regex : : Error : : NoError , regex : : ECMAScriptFlags : : Unicode } ,
{ " \\ u1 " sv , regex : : Error : : InvalidPattern , regex : : ECMAScriptFlags : : Unicode } ,
{ " [ \\ u1] " sv , regex : : Error : : InvalidPattern , regex : : ECMAScriptFlags : : Unicode } ,
{ " ,(? " sv , regex : : Error : : InvalidCaptureGroup } , // #4583
{ " {1} " sv , regex : : Error : : InvalidPattern } ,
{ " {1,2} " sv , regex : : Error : : InvalidPattern } ,
{ " \\ uxxxx " sv , regex : : Error : : NoError } ,
{ " \\ uxxxx " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " \\ ud83d " sv , regex : : Error : : NoError , ECMAScriptFlags : : Unicode } ,
{ " \\ ud83d \\ uxxxx " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
2021-08-15 14:29:03 +00:00
{ " \\ u{0} " sv } ,
2021-08-15 03:28:06 +00:00
{ " \\ u{0} " sv , regex : : Error : : NoError , ECMAScriptFlags : : Unicode } ,
{ " \\ u{10ffff} " sv , regex : : Error : : NoError , ECMAScriptFlags : : Unicode } ,
{ " \\ u{10ffff " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " \\ u{10ffffx " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " \\ u{110000} " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " \\ p " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " \\ p{ " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " \\ p{} " sv , regex : : Error : : InvalidNameForProperty , ECMAScriptFlags : : Unicode } ,
{ " \\ p{AsCiI} " sv , regex : : Error : : InvalidNameForProperty , ECMAScriptFlags : : Unicode } ,
{ " \\ p{hello friends} " sv , regex : : Error : : InvalidNameForProperty , ECMAScriptFlags : : Unicode } ,
{ " \\ p{Prepended_Concatenation_Mark} " sv , regex : : Error : : InvalidNameForProperty , ECMAScriptFlags : : Unicode } ,
{ " \\ p{ASCII} " sv , regex : : Error : : NoError , ECMAScriptFlags : : Unicode } ,
{ " \\ \\ p{1} " sv , regex : : Error : : NoError , ECMAScriptFlags : : Unicode } ,
{ " \\ \\ p{AsCiI} " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " \\ \\ p{ASCII} " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " \\ c " sv , regex : : Error : : NoError , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ c " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " [ \\ c] " sv , regex : : Error : : NoError , ECMAScriptFlags : : BrowserExtended } ,
{ " [ \\ c] " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " \\ c` " sv , regex : : Error : : NoError , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ c` " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " [ \\ c`] " sv , regex : : Error : : NoError , ECMAScriptFlags : : BrowserExtended } ,
{ " [ \\ c`] " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " \\ A " sv , regex : : Error : : NoError , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ A " sv , regex : : Error : : InvalidCharacterClass , ECMAScriptFlags : : Unicode } ,
{ " [ \\ A] " sv , regex : : Error : : NoError , ECMAScriptFlags : : BrowserExtended } ,
{ " [ \\ A] " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
2021-08-11 20:41:57 +00:00
{ " \\ 0 " sv , regex : : Error : : NoError , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ 0 " sv , regex : : Error : : NoError , combine_flags ( ECMAScriptFlags : : Unicode , ECMAScriptFlags : : BrowserExtended ) } ,
{ " \\ 00 " sv , regex : : Error : : NoError , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ 00 " sv , regex : : Error : : InvalidCharacterClass , combine_flags ( ECMAScriptFlags : : Unicode , ECMAScriptFlags : : BrowserExtended ) } ,
{ " [ \\ 0] " sv , regex : : Error : : NoError , ECMAScriptFlags : : BrowserExtended } ,
{ " [ \\ 0] " sv , regex : : Error : : NoError , combine_flags ( ECMAScriptFlags : : Unicode , ECMAScriptFlags : : BrowserExtended ) } ,
{ " [ \\ 00] " sv , regex : : Error : : NoError , ECMAScriptFlags : : BrowserExtended } ,
{ " [ \\ 00] " sv , regex : : Error : : InvalidPattern , combine_flags ( ECMAScriptFlags : : Unicode , ECMAScriptFlags : : BrowserExtended ) } ,
2021-08-11 21:52:57 +00:00
{ " \\ ^ \\ $ \\ \\ \\ . \\ * \\ + \\ ? \\ ( \\ ) \\ [ \\ ] \\ { \\ } \\ | \\ / " sv , regex : : Error : : NoError , ECMAScriptFlags : : Unicode } ,
{ " [ \\ ^ \\ $ \\ \\ \\ . \\ * \\ + \\ ? \\ ( \\ ) \\ [ \\ ] \\ { \\ } \\ | \\ /] " sv , regex : : Error : : NoError , ECMAScriptFlags : : Unicode } ,
2021-08-11 22:06:33 +00:00
{ " ] " sv , regex : : Error : : NoError , ECMAScriptFlags : : BrowserExtended } ,
{ " ] " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " \\ ] " sv , regex : : Error : : NoError , ECMAScriptFlags : : Unicode } ,
{ " } " sv , regex : : Error : : NoError , ECMAScriptFlags : : BrowserExtended } ,
{ " } " sv , regex : : Error : : InvalidPattern , ECMAScriptFlags : : Unicode } ,
{ " \\ } " sv , regex : : Error : : NoError , ECMAScriptFlags : : Unicode } ,
2021-08-12 15:02:46 +00:00
{ " a{9007199254740991} " sv } , // 2^53 - 1
{ " a{9007199254740991,} " sv } ,
{ " a{9007199254740991,9007199254740991} " sv } ,
{ " a{9007199254740992} " sv , regex : : Error : : InvalidBraceContent } ,
{ " a{9007199254740992,} " sv , regex : : Error : : InvalidBraceContent } ,
{ " a{9007199254740991,9007199254740992} " sv , regex : : Error : : InvalidBraceContent } ,
{ " a{9007199254740992,9007199254740991} " sv , regex : : Error : : InvalidBraceContent } ,
{ " a{9007199254740992,9007199254740992} " sv , regex : : Error : : InvalidBraceContent } ,
2021-12-19 01:31:21 +00:00
{ " (?<a>a)(?<a>b) " sv , regex : : Error : : DuplicateNamedCapture } ,
{ " (?<a>a)(?<b>b)(?<a>c) " sv , regex : : Error : : DuplicateNamedCapture } ,
2021-12-19 16:03:08 +00:00
{ " (?<1a>a) " sv , regex : : Error : : InvalidNameForCaptureGroup } ,
{ " (?< \\ a>a) " sv , regex : : Error : : InvalidNameForCaptureGroup } ,
{ " (?< \t a>a) " sv , regex : : Error : : InvalidNameForCaptureGroup } ,
{ " (?<$$_$$>a) " sv } ,
{ " (?<ÿ>a) " sv } ,
{ " (?<𝓑 𝓻 𝓸 𝔀 𝓷 >a) " sv } ,
2020-11-27 16:03:53 +00:00
} ;
2020-11-30 14:16:53 +00:00
for ( auto & test : tests ) {
2021-07-21 02:33:00 +00:00
Regex < ECMA262 > re ( test . pattern , test . flags ) ;
2020-11-30 14:16:53 +00:00
EXPECT_EQ ( re . parser_result . error , test . expected_error ) ;
2021-05-01 19:10:08 +00:00
if constexpr ( REGEX_DEBUG ) {
dbgln ( " \n " ) ;
RegexDebug regex_dbg ( stderr ) ;
regex_dbg . print_raw_bytecode ( re ) ;
regex_dbg . print_header ( ) ;
regex_dbg . print_bytecode ( re ) ;
dbgln ( " \n " ) ;
}
2020-11-27 16:03:53 +00:00
}
}
TEST_CASE ( ECMA262_match )
{
struct _test {
2021-08-15 03:28:06 +00:00
StringView pattern ;
StringView subject ;
2020-11-27 16:03:53 +00:00
bool matches { true } ;
ECMAScriptFlags options { } ;
} ;
2021-02-26 19:19:34 +00:00
// clang-format off
2020-11-27 16:03:53 +00:00
constexpr _test tests [ ] {
2021-08-15 03:28:06 +00:00
{ " ^hello.$ " sv , " hello1 " sv } ,
{ " ^(hello.)$ " sv , " hello1 " sv } ,
{ " ^h{0,1}ello.$ " sv , " ello1 " sv } ,
{ " ^hello \\ W$ " sv , " hello! " sv } ,
{ " ^hell \\ w.$ " sv , " hellx! " sv } ,
{ " ^hell \\ x6f1$ " sv , " hello1 " sv } ,
{ " ^hel(?<LO>l.)1$ " sv , " hello1 " sv } ,
{ " ^hel(?<LO>l.)1* \\ k<LO>.$ " sv , " hello1lo1 " sv } ,
{ " ^[-a-z1-3 \\ s]+$ " sv , " hell2 o1 " sv } ,
{ " ^[ \\ 0- \\ x1f]$ " sv , " \n " sv } ,
{ . pattern = " \\ bhello \\ B " sv , . subject = " hello1 " sv , . options = ECMAScriptFlags : : Global } ,
{ " \\ b.* \\ b " sv , " hello1 " sv } ,
{ " [^ \\ D \\ S]{2} " sv , " 1 " sv } ,
{ " bar(?=f.)foo " sv , " barfoo " sv } ,
{ " bar(?=foo)bar " sv , " barbar " sv , false } ,
{ " bar(?!foo)bar " sv , " barbar " sv , true } ,
{ " bar(?!bar)bar " sv , " barbar " sv , false } ,
{ " bar.*(?<=foo) " sv , " barbar " sv , false } ,
{ " bar.*(?<!foo) " sv , " barbar " sv , true } ,
{ " ((...)X)+ " sv , " fooXbarXbazX " sv , true } ,
{ " (?:) " sv , " " sv , true } ,
{ " \\ ^ " sv , " ^ " sv } ,
2021-08-11 21:52:57 +00:00
{ " \\ ^ \\ $ \\ \\ \\ . \\ * \\ + \\ ? \\ ( \\ ) \\ [ \\ ] \\ { \\ } \\ | \\ / " sv , " ^$ \\ .*+?()[]{}|/ " sv , true , ECMAScriptFlags : : Unicode } ,
{ " [ \\ ^ \\ $ \\ \\ \\ . \\ * \\ + \\ ? \\ ( \\ ) \\ [ \\ ] \\ { \\ } \\ | \\ /]{15} " sv , " ^$ \\ .*+?()[]{}|/ " sv , true , ECMAScriptFlags : : Unicode } ,
2021-08-12 15:02:46 +00:00
{ " (a{2}){3} " sv , " aaaaaa " sv } ,
{ " (a{2}){3} " sv , " aaaabaa " sv , false } ,
{ " (a{2}){4} " sv , " aaaaaaaa " sv } ,
{ " (a{2}){4} " sv , " aaaaaabaa " sv , false } ,
{ " (a{3}){2} " sv , " aaaaaa " sv } ,
{ " (a{3}){2} " sv , " aaaabaa " sv , false } ,
{ " (a{4}){2} " sv , " aaaaaaaa " sv } ,
{ " (a{4}){2} " sv , " aaaaaabaa " sv , false } ,
2021-08-15 14:29:03 +00:00
{ " \\ u{4} " sv , " uuuu " } ,
2021-08-16 14:28:26 +00:00
{ " (?<=.{3})f " sv , " abcdef " sv , true , ( ECMAScriptFlags ) regex : : AllFlags : : Global } ,
{ " (?<=.{3})f " sv , " abc😀ef " sv , true , ( ECMAScriptFlags ) regex : : AllFlags : : Global } ,
2021-02-26 19:19:34 +00:00
// ECMA262, B.1.4. Regular Expression Pattern extensions for browsers
2021-08-15 03:28:06 +00:00
{ " { " sv , " { " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ 5 " sv , " \5 " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ 05 " sv , " \5 " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ 455 " sv , " \45 " " 5 " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ 314 " sv , " \314 " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ c " sv , " \\ c " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ cf " sv , " \06 " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ c1 " sv , " \\ c1 " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " [ \\ c1] " sv , " \x11 " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " [ \\ w- \\ d] " sv , " - " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " ^(?:^^ \\ .?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=| \\ (| \\ *| \\ *=| \\ +=|,|-=|->| \\ /| \\ /=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]| \\ ^=| \\ ^ \\ ^| \\ ^ \\ ^=|{| \\ || \\ |=| \\ | \\ || \\ | \\ |=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof) \\ s*( \\ /(?=[^*/])(?:[^/[ \\ \\ ]| \\ \\ [ \\ S \\ s]| \\ [(?:[^ \\ \\ \\ ]]| \\ \\ [ \\ S \\ s])*(?:]|$))+ \\ /) " sv ,
" return /xx/ " sv , true , ECMAScriptFlags : : BrowserExtended
2021-02-26 19:19:34 +00:00
} , // #5517, appears to be matching JS expressions that involve regular expressions...
2021-08-15 03:28:06 +00:00
{ " a{2,} " sv , " aaaa " sv } , // #5518
2021-08-11 20:41:57 +00:00
{ " \\ 0 " sv , " \0 " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " \\ 0 " sv , " \0 " sv , true , combine_flags ( ECMAScriptFlags : : Unicode , ECMAScriptFlags : : BrowserExtended ) } ,
{ " \\ 01 " sv , " \1 " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " [ \\ 0] " sv , " \0 " sv , true , ECMAScriptFlags : : BrowserExtended } ,
{ " [ \\ 0] " sv , " \0 " sv , true , combine_flags ( ECMAScriptFlags : : Unicode , ECMAScriptFlags : : BrowserExtended ) } ,
{ " [ \\ 01] " sv , " \1 " sv , true , ECMAScriptFlags : : BrowserExtended } ,
2021-08-30 15:50:58 +00:00
{ " ( \0 |a) " sv , " a " sv , true } , // #9686, Should allow null bytes in pattern
2022-01-21 16:38:47 +00:00
{ " (.*?)a(?!(a+)b \\ 2c) \\ 2(.*) " sv , " baaabaac " sv , true } , // #6042, Groups inside lookarounds may be referenced outside, but their contents appear empty if the pattern in the lookaround fails.
2022-01-21 11:20:30 +00:00
{ " a|$ " sv , " x " sv , true , ( ECMAScriptFlags ) regex : : AllFlags : : Global } , // #11940, Global (not the 'g' flag) regexps should attempt to match the zero-length end of the string too.
2022-01-25 10:00:27 +00:00
{ " foo \n bar " sv , " foo \n bar " sv , true } , // #12126, ECMA262 regexp should match literal newlines without the 's' flag.
{ " foo[^]bar " sv , " foo \n bar " sv , true } , // #12126, ECMA262 regexp should match newline with [^].
2020-11-27 16:03:53 +00:00
} ;
2021-02-26 19:19:34 +00:00
// clang-format on
2020-11-27 16:03:53 +00:00
for ( auto & test : tests ) {
Regex < ECMA262 > re ( test . pattern , test . options ) ;
2021-05-01 19:10:08 +00:00
if constexpr ( REGEX_DEBUG ) {
dbgln ( " \n " ) ;
RegexDebug regex_dbg ( stderr ) ;
regex_dbg . print_raw_bytecode ( re ) ;
regex_dbg . print_header ( ) ;
regex_dbg . print_bytecode ( re ) ;
dbgln ( " \n " ) ;
}
2021-11-06 09:33:46 +00:00
EXPECT_EQ ( re . parser_result . error , regex : : Error : : NoError ) ;
2020-11-27 16:03:53 +00:00
EXPECT_EQ ( re . match ( test . subject ) . success , test . matches ) ;
}
}
2021-07-21 02:33:00 +00:00
TEST_CASE ( ECMA262_unicode_match )
{
2022-02-05 15:43:13 +00:00
constexpr auto space_and_line_terminator_code_points = Array { 0x0009 , 0x000A , 0x000B , 0x000C , 0x000D , 0x0020 , 0x00A0 , 0x1680 , 0x2000 , 0x2001 , 0x2002 , 0x2003 , 0x2004 , 0x2005 , 0x2006 , 0x2007 , 0x2008 , 0x2009 , 0x200A , 0x2028 , 0x2029 , 0x202F , 0x205F , 0x3000 , 0xFEFF } ;
StringBuilder builder ;
for ( u32 code_point : space_and_line_terminator_code_points )
builder . append_code_point ( code_point ) ;
auto space_and_line_terminators = builder . build ( ) ;
2021-07-21 02:33:00 +00:00
struct _test {
2021-08-15 03:28:06 +00:00
StringView pattern ;
StringView subject ;
2021-07-21 02:33:00 +00:00
bool matches { true } ;
ECMAScriptFlags options { } ;
} ;
_test tests [ ] {
LibRegex: Treat pattern string characters as unsigned
For example, consider the following pattern:
new RegExp('\ud834\udf06', 'u')
With this pattern, the regex parser should insert the UTF-8 encoded
bytes 0xf0, 0x9d, 0x8c, and 0x86. However, because these characters are
currently treated as normal char types, they have a negative value since
they are all > 0x7f. Then, due to sign extension, when these characters
are cast to u64, the sign bit is preserved. The result is that these
bytes are inserted as 0xfffffffffffffff0, 0xffffffffffffff9d, etc.
Fortunately, there are only a few places where we insert bytecode with
the raw characters. In these places, be sure to treat the bytes as u8
before they are cast to u64.
2021-08-20 14:22:23 +00:00
{ " \xf0 \x9d \x8c \x86 " sv , " abcdef " sv , false , ECMAScriptFlags : : Unicode } ,
{ " [ \xf0 \x9d \x8c \x86 ] " sv , " abcdef " sv , false , ECMAScriptFlags : : Unicode } ,
2021-08-15 03:28:06 +00:00
{ " \\ ud83d " sv , " 😀 " sv , true } ,
{ " \\ ud83d " sv , " 😀 " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ ude00 " sv , " 😀 " sv , true } ,
{ " \\ ude00 " sv , " 😀 " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ ud83d \\ ude00 " sv , " 😀 " sv , true } ,
{ " \\ ud83d \\ ude00 " sv , " 😀 " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ u{1f600} " sv , " 😀 " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ ud83d \\ ud83d " sv , " \xed \xa0 \xbd \xed \xa0 \xbd " sv , true } ,
{ " \\ ud83d \\ ud83d " sv , " \xed \xa0 \xbd \xed \xa0 \xbd " sv , true , ECMAScriptFlags : : Unicode } ,
2021-08-16 14:28:26 +00:00
{ " (?<=.{3})f " sv , " abcdef " sv , true , ECMAScriptFlags : : Unicode } ,
{ " (?<=.{3})f " sv , " abc😀ef " sv , true , ECMAScriptFlags : : Unicode } ,
2021-08-18 21:17:18 +00:00
{ " (?<𝓑 𝓻 𝓸 𝔀 𝓷 >brown) " sv , " brown " sv , true , ECMAScriptFlags : : Unicode } ,
{ " (?< \\ u{1d4d1} \\ u{1d4fb} \\ u{1d4f8} \\ u{1d500} \\ u{1d4f7}>brown) " sv , " brown " sv , true , ECMAScriptFlags : : Unicode } ,
{ " (?< \\ ud835 \\ udcd1 \\ ud835 \\ udcfb \\ ud835 \\ udcf8 \\ ud835 \\ udd00 \\ ud835 \\ udcf7>brown) " sv , " brown " sv , true , ECMAScriptFlags : : Unicode } ,
2022-02-05 15:43:13 +00:00
{ " ^ \\ s+$ " sv , space_and_line_terminators } ,
{ " ^ \\ s+$ " sv , space_and_line_terminators , true , ECMAScriptFlags : : Unicode } ,
2021-07-21 02:33:00 +00:00
} ;
for ( auto & test : tests ) {
Regex < ECMA262 > re ( test . pattern , ( ECMAScriptFlags ) regex : : AllFlags : : Global | test . options ) ;
auto subject = AK : : utf8_to_utf16 ( test . subject ) ;
Utf16View view { subject } ;
if constexpr ( REGEX_DEBUG ) {
dbgln ( " \n " ) ;
RegexDebug regex_dbg ( stderr ) ;
regex_dbg . print_raw_bytecode ( re ) ;
regex_dbg . print_header ( ) ;
regex_dbg . print_bytecode ( re ) ;
dbgln ( " \n " ) ;
}
2021-11-06 09:33:46 +00:00
EXPECT_EQ ( re . parser_result . error , regex : : Error : : NoError ) ;
2021-07-21 02:33:00 +00:00
EXPECT_EQ ( re . match ( view ) . success , test . matches ) ;
}
}
2021-07-29 18:18:51 +00:00
TEST_CASE ( ECMA262_property_match )
{
struct _test {
2021-08-15 03:28:06 +00:00
StringView pattern ;
StringView subject ;
2021-07-29 18:18:51 +00:00
bool matches { true } ;
ECMAScriptFlags options { } ;
} ;
constexpr _test tests [ ] {
2021-08-15 03:28:06 +00:00
{ " \\ p{ASCII} " sv , " a " sv , false } ,
{ " \\ p{ASCII} " sv , " p{ASCII} " sv , true } ,
{ " \\ p{ASCII} " sv , " a " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{ASCII} " sv , " 😀 " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ P{ASCII} " sv , " a " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ P{ASCII} " sv , " 😀 " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{ASCII_Hex_Digit} " sv , " 1 " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{ASCII_Hex_Digit} " sv , " a " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{ASCII_Hex_Digit} " sv , " x " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ P{ASCII_Hex_Digit} " sv , " 1 " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ P{ASCII_Hex_Digit} " sv , " a " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ P{ASCII_Hex_Digit} " sv , " x " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{Any} " sv , " \xcd \xb8 " sv , true , ECMAScriptFlags : : Unicode } , // U+0378, which is an unassigned code point.
{ " \\ P{Any} " sv , " \xcd \xb8 " sv , false , ECMAScriptFlags : : Unicode } , // U+0378, which is an unassigned code point.
{ " \\ p{Assigned} " sv , " \xcd \xb8 " sv , false , ECMAScriptFlags : : Unicode } , // U+0378, which is an unassigned code point.
{ " \\ P{Assigned} " sv , " \xcd \xb8 " sv , true , ECMAScriptFlags : : Unicode } , // U+0378, which is an unassigned code point.
{ " \\ p{Lu} " sv , " a " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ p{Lu} " sv , " A " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{Lu} " sv , " 9 " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ p{Cased_Letter} " sv , " a " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{Cased_Letter} " sv , " A " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{Cased_Letter} " sv , " 9 " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ P{Cased_Letter} " sv , " a " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ P{Cased_Letter} " sv , " A " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ P{Cased_Letter} " sv , " 9 " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{General_Category=Cased_Letter} " sv , " a " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{General_Category=Cased_Letter} " sv , " A " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{General_Category=Cased_Letter} " sv , " 9 " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ p{gc=Cased_Letter} " sv , " a " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{gc=Cased_Letter} " sv , " A " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{gc=Cased_Letter} " sv , " 9 " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ p{Script=Latin} " sv , " a " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{Script=Latin} " sv , " A " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{Script=Latin} " sv , " 9 " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ p{sc=Latin} " sv , " a " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{sc=Latin} " sv , " A " sv , true , ECMAScriptFlags : : Unicode } ,
{ " \\ p{sc=Latin} " sv , " 9 " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ p{Script_Extensions=Deva} " sv , " a " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ p{Script_Extensions=Beng} " sv , " \xe1 \xb3 \x95 " sv , true , ECMAScriptFlags : : Unicode } , // U+01CD5
{ " \\ p{Script_Extensions=Deva} " sv , " \xe1 \xb3 \x95 " sv , true , ECMAScriptFlags : : Unicode } , // U+01CD5
{ " \\ p{scx=Deva} " sv , " a " sv , false , ECMAScriptFlags : : Unicode } ,
{ " \\ p{scx=Beng} " sv , " \xe1 \xb3 \x95 " sv , true , ECMAScriptFlags : : Unicode } , // U+01CD5
{ " \\ p{scx=Deva} " sv , " \xe1 \xb3 \x95 " sv , true , ECMAScriptFlags : : Unicode } , // U+01CD5
2021-07-29 18:18:51 +00:00
} ;
for ( auto & test : tests ) {
Regex < ECMA262 > re ( test . pattern , ( ECMAScriptFlags ) regex : : AllFlags : : Global | regex : : ECMAScriptFlags : : BrowserExtended | test . options ) ;
auto subject = AK : : utf8_to_utf16 ( test . subject ) ;
Utf16View view { subject } ;
if constexpr ( REGEX_DEBUG ) {
dbgln ( " \n " ) ;
RegexDebug regex_dbg ( stderr ) ;
regex_dbg . print_raw_bytecode ( re ) ;
regex_dbg . print_header ( ) ;
regex_dbg . print_bytecode ( re ) ;
dbgln ( " \n " ) ;
}
2021-11-06 09:33:46 +00:00
EXPECT_EQ ( re . parser_result . error , regex : : Error : : NoError ) ;
2021-07-29 18:18:51 +00:00
EXPECT_EQ ( re . match ( view ) . success , test . matches ) ;
}
}
2020-12-03 15:25:36 +00:00
TEST_CASE ( replace )
{
struct _test {
2021-08-15 03:28:06 +00:00
StringView pattern ;
StringView replacement ;
StringView subject ;
StringView expected ;
2020-12-03 15:25:36 +00:00
ECMAScriptFlags options { } ;
} ;
constexpr _test tests [ ] {
2021-08-15 03:28:06 +00:00
{ " foo(.+) " sv , " aaa " sv , " test " sv , " test " sv } ,
{ " foo(.+) " sv , " test \\ 1 " sv , " foobar " sv , " testbar " sv } ,
{ " foo(.+) " sv , " \\ 2 \\ 1 " sv , " foobar " sv , " \\ 2bar " sv } ,
{ " foo(.+) " sv , " \\ \\ \\ 1 " sv , " foobar " sv , " \\ bar " sv } ,
{ " foo(.) " sv , " a \\ 1 " sv , " fooxfooy " sv , " axay " sv , ECMAScriptFlags : : Multiline } ,
2020-12-03 15:25:36 +00:00
} ;
for ( auto & test : tests ) {
Regex < ECMA262 > re ( test . pattern , test . options ) ;
2021-05-01 19:10:08 +00:00
if constexpr ( REGEX_DEBUG ) {
dbgln ( " \n " ) ;
RegexDebug regex_dbg ( stderr ) ;
regex_dbg . print_raw_bytecode ( re ) ;
regex_dbg . print_header ( ) ;
regex_dbg . print_bytecode ( re ) ;
dbgln ( " \n " ) ;
}
2021-11-06 09:33:46 +00:00
EXPECT_EQ ( re . parser_result . error , regex : : Error : : NoError ) ;
2020-12-03 15:25:36 +00:00
EXPECT_EQ ( re . replace ( test . subject , test . replacement ) , test . expected ) ;
}
}
2021-06-16 11:28:06 +00:00
TEST_CASE ( case_insensitive_match )
{
Regex < PosixExtended > re ( " cd " , PosixFlags : : Insensitive | PosixFlags : : Global ) ;
auto result = re . match ( " AEKFCD " ) ;
EXPECT_EQ ( result . success , true ) ;
2021-07-18 00:36:01 +00:00
if ( result . success ) {
EXPECT_EQ ( result . matches . at ( 0 ) . column , 4ul ) ;
}
2021-06-16 11:28:06 +00:00
}
2021-07-31 14:17:44 +00:00
TEST_CASE ( extremely_long_fork_chain )
{
Regex < ECMA262 > re ( " (?:aa)* " ) ;
2021-09-05 23:28:35 +00:00
auto result = re . match ( String : : repeated ( ' a ' , 1000 ) ) ;
2021-07-31 14:17:44 +00:00
EXPECT_EQ ( result . success , true ) ;
}
2021-09-05 22:08:47 +00:00
TEST_CASE ( theoretically_infinite_loop )
{
Array patterns {
" (a*)* " sv , // Infinitely matching empty substrings, the outer loop should short-circuit.
" (a*?)* " sv , // Infinitely matching empty substrings, the outer loop should short-circuit.
" (a*)*? " sv , // Should match exactly nothing.
" (?:)*? " sv , // Should not generate an infinite fork loop.
} ;
for ( auto & pattern : patterns ) {
Regex < ECMA262 > re ( pattern ) ;
auto result = re . match ( " " ) ;
EXPECT_EQ ( result . success , true ) ;
}
}
2021-07-31 14:17:44 +00:00
static auto g_lots_of_a_s = String : : repeated ( ' a ' , 10'000'000 ) ;
BENCHMARK_CASE ( fork_performance )
{
Regex < ECMA262 > re ( " (?:aa)* " ) ;
auto result = re . match ( g_lots_of_a_s ) ;
EXPECT_EQ ( result . success , true ) ;
}
2021-09-12 13:00:27 +00:00
TEST_CASE ( optimizer_atomic_groups )
{
Array tests {
// Fork -> ForkReplace
Tuple { " a*b " sv , " aaaaa " sv , false } ,
Tuple { " a+b " sv , " aaaaa " sv , false } ,
2021-11-18 04:30:29 +00:00
Tuple { " \\ \\ ( \\ d+) " sv , " \\ \\ " sv , false } , // Rewrite bug turning a+ to a*, see #10952.
2021-09-12 13:00:27 +00:00
// Alternative fuse
Tuple { " (abcfoo|abcbar|abcbaz).*x " sv , " abcbarx " sv , true } ,
Tuple { " (a|a) " sv , " a " sv , true } ,
2021-12-15 05:22:07 +00:00
Tuple { " (a|) " sv , " " sv , true } , // Ensure that empty alternatives are not outright removed
2022-01-06 14:07:15 +00:00
Tuple { " a{2,3}|a{5,8} " sv , " abc " sv , false } , // Optimizer should not mess up the instruction stream by ignoring inter-insn dependencies, see #11247.
Tuple { " ^(a{2,3}|a{5,8})$ " sv , " aaaa " sv , false } , // Optimizer should not mess up the instruction stream by ignoring inter-insn dependencies, see #11247.
2021-09-15 10:01:55 +00:00
// ForkReplace shouldn't be applied where it would change the semantics
Tuple { " (1+) \\ 1 " sv , " 11 " sv , true } ,
Tuple { " (1+)1 " sv , " 11 " sv , true } ,
Tuple { " (1+)0 " sv , " 10 " sv , true } ,
2022-01-21 09:03:49 +00:00
// Rewrite should not skip over first required iteration of <x>+.
Tuple { " a+ " sv , " " sv , false } ,
2021-09-12 13:00:27 +00:00
} ;
for ( auto & test : tests ) {
Regex < ECMA262 > re ( test . get < 0 > ( ) ) ;
auto result = re . match ( test . get < 1 > ( ) ) ;
EXPECT_EQ ( result . success , test . get < 2 > ( ) ) ;
}
}
2021-10-03 15:31:25 +00:00
TEST_CASE ( optimizer_char_class_lut )
{
Regex < ECMA262 > re ( R " ([ \f \n \r \t \v \u00a0 \u1680 \u2000 \u2001 \u2002 \u2003 \u2004 \u2005 \u2006 \u2007 \u2008 \u2009 \u200a \u2028 \u2029 \u202f \u205f \u3000 \ufeff ]+$) " ) ;
if constexpr ( REGEX_DEBUG ) {
dbgln ( " \n " ) ;
RegexDebug regex_dbg ( stderr ) ;
regex_dbg . print_raw_bytecode ( re ) ;
regex_dbg . print_header ( ) ;
regex_dbg . print_bytecode ( re ) ;
dbgln ( " \n " ) ;
}
// This will go through _all_ alternatives in the character class, and then fail.
for ( size_t i = 0 ; i < 1'000'000 ; + + i )
EXPECT_EQ ( re . match ( " 1635488940000 " sv ) . success , false ) ;
}
2021-11-13 10:50:35 +00:00
TEST_CASE ( posix_basic_dollar_is_end_anchor )
{
// Ensure that a dollar sign at the end only matches the end of the line.
{
Regex < PosixBasic > re ( " abc$ " ) ;
EXPECT_EQ ( re . match ( " 123abcdef " , PosixFlags : : Global ) . success , false ) ;
EXPECT_EQ ( re . match ( " 123abc " , PosixFlags : : Global ) . success , true ) ;
EXPECT_EQ ( re . match ( " 123abc$def " , PosixFlags : : Global ) . success , false ) ;
EXPECT_EQ ( re . match ( " 123abc$ " , PosixFlags : : Global ) . success , false ) ;
}
}
TEST_CASE ( posix_basic_dollar_is_literal )
{
// Ensure that a dollar sign in the middle is treated as a literal.
{
Regex < PosixBasic > re ( " abc$d " ) ;
EXPECT_EQ ( re . match ( " 123abcdef " , PosixFlags : : Global ) . success , false ) ;
EXPECT_EQ ( re . match ( " 123abc " , PosixFlags : : Global ) . success , false ) ;
EXPECT_EQ ( re . match ( " 123abc$def " , PosixFlags : : Global ) . success , true ) ;
EXPECT_EQ ( re . match ( " 123abc$ " , PosixFlags : : Global ) . success , false ) ;
}
// Ensure that a dollar sign is always treated as a literal if escaped, even if at the end of the pattern.
{
Regex < PosixBasic > re ( " abc \\ $ " ) ;
EXPECT_EQ ( re . match ( " 123abcdef " , PosixFlags : : Global ) . success , false ) ;
EXPECT_EQ ( re . match ( " 123abc " , PosixFlags : : Global ) . success , false ) ;
EXPECT_EQ ( re . match ( " 123abc$def " , PosixFlags : : Global ) . success , true ) ;
EXPECT_EQ ( re . match ( " 123abc$ " , PosixFlags : : Global ) . success , true ) ;
}
}
2021-12-25 02:05:09 +00:00
TEST_CASE ( negative_lookahead )
{
{
// Negative lookahead with more than 2 forks difference between lookahead init and finish.
2022-02-04 20:26:44 +00:00
auto options = ECMAScriptOptions { ECMAScriptFlags : : Global } ;
options . reset_flag ( ( ECMAScriptFlags ) regex : : AllFlags : : Internal_Stateful ) ;
Regex < ECMA262 > re ( " :(?! \\ ^ \\ )|1) " , options ) ;
2021-12-25 02:05:09 +00:00
EXPECT_EQ ( re . match ( " :^) " ) . success , false ) ;
EXPECT_EQ ( re . match ( " :1 " ) . success , false ) ;
EXPECT_EQ ( re . match ( " :foobar " ) . success , true ) ;
}
}
2022-02-04 15:59:26 +00:00
TEST_CASE ( single_match_flag )
{
{
// Ensure that only a single match is produced and nothing past that.
Regex < ECMA262 > re ( " [ \\ u0008- \\ uffff] " sv , ECMAScriptFlags : : Global | ( ECMAScriptFlags ) regex : : AllFlags : : SingleMatch ) ;
auto result = re . match ( " ABC " ) ;
EXPECT_EQ ( result . success , true ) ;
EXPECT_EQ ( result . matches . size ( ) , 1u ) ;
EXPECT_EQ ( result . matches . first ( ) . view . to_string ( ) , " A " sv ) ;
}
}