Skip to content

Commit 65ada71

Browse files
committed
lexer: fixes & match gawk 5.4.0
1 parent 97968d7 commit 65ada71

1 file changed

Lines changed: 59 additions & 40 deletions

File tree

lexer/src/lib.rs

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod tests;
88

99
use core::str;
1010
use std::{
11+
cmp::Ordering,
1112
fmt::{Debug, Display},
1213
slice::SliceIndex,
1314
};
@@ -33,7 +34,7 @@ pub type Result<T, E = LexingError> = std::result::Result<T, E>;
3334
#[logos(subpattern ignore_with_nl = r"(?:(?&ignore)|\n)*")]
3435
#[logos(error(LexingError, callback = |lex| LexingError::unexpected(lex)))]
3536
pub enum Token<'a> {
36-
#[regex(r"[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?", parse_float)]
37+
#[regex(r"(-)?[0-9]+(\.[0-9]*)?([eE][+-]?[0-9]+)?", parse_float)]
3738
#[regex(r"\.[0-9]+([eE][+-]?[0-9]+)?", parse_float)]
3839
Number(f64),
3940
#[token("\"", parse_string)]
@@ -308,14 +309,15 @@ fn skip_line(lex: &mut Lexer<'_>) -> Skip {
308309
}
309310

310311
fn parse_string<'a>(lex: &mut logos::Lexer<'a, Token<'a>>) -> Result<Slice<'a>> {
311-
parse_content::<false, false, '"'>(lex)
312+
accept_operator(lex);
313+
parse_content::<false, '"'>(lex)
312314
}
313315

314316
fn parse_regex_or_slash<'a>(lex: &mut logos::Lexer<'a, Token<'a>>) -> Result<Token<'a>> {
315317
match lex.extras.ctx {
316318
Context::AcceptExpression => {
317319
accept_operator(lex);
318-
parse_content::<false, true, '/'>(lex).map(Token::Regex)
320+
parse_content::<true, '/'>(lex).map(Token::Regex)
319321
}
320322
Context::AcceptOperator => {
321323
accept_expression(lex);
@@ -326,7 +328,7 @@ fn parse_regex_or_slash<'a>(lex: &mut logos::Lexer<'a, Token<'a>>) -> Result<Tok
326328

327329
fn parse_directive<'a>(lex: &mut Lexer<'a>) -> Result<Slice<'a>> {
328330
accept_expression(lex);
329-
parse_content::<true, false, '"'>(lex)
331+
parse_content::<false, '"'>(lex)
330332
}
331333

332334
fn parse_non_posix_directive<'a>(lex: &mut Lexer<'a>) -> Result<Slice<'a>> {
@@ -347,7 +349,7 @@ fn parse_namespace_directive<'a>(lex: &mut Lexer<'a>) -> Result<&'a str> {
347349
}
348350
}
349351

350-
fn parse_content<'a, const MINIMAL: bool, const REGEX: bool, const DELIMITER: char>(
352+
fn parse_content<'a, const REGEX: bool, const DELIMITER: char>(
351353
lex: &mut Lexer<'a>,
352354
) -> Result<Slice<'a>> {
353355
let rest = lex.remainder();
@@ -372,7 +374,7 @@ fn parse_content<'a, const MINIMAL: bool, const REGEX: bool, const DELIMITER: ch
372374
b'\\' => {
373375
out.to_mut(lex.extras.arena())
374376
.extend_from_slice(&rest[start..i]);
375-
let consumed = parse_escape::<MINIMAL, REGEX>(
377+
let consumed = parse_escape::<REGEX>(
376378
&rest[i..],
377379
out.to_mut(lex.extras.arena()),
378380
lex.extras.posix_strict,
@@ -389,7 +391,7 @@ fn parse_content<'a, const MINIMAL: bool, const REGEX: bool, const DELIMITER: ch
389391
}
390392
}
391393

392-
fn parse_escape<const MINIMAL: bool, const REGEX: bool>(
394+
fn parse_escape<const REGEX: bool>(
393395
slice: &[u8],
394396
out: &mut Vec<u8>,
395397
posix_strict: bool,
@@ -406,39 +408,30 @@ fn parse_escape<const MINIMAL: bool, const REGEX: bool>(
406408
}
407409

408410
// On minimal, only drop backslash for '"' and '\n'
409-
let escaped = if MINIMAL && !matches!(to_escape, '"' | '\n') {
410-
out.push(b'\\');
411-
to_escape
412-
} else if MINIMAL {
413-
to_escape
414-
} else {
415-
match to_escape {
416-
c @ ('\\' | '"') if !REGEX => c,
417-
c @ ('[' | ']' | '{' | '}' | '(' | ')' | '*' | '+' | '^' | '$' | '.' | '?')
418-
if REGEX =>
419-
{
420-
out.push(b'\\');
421-
c
422-
}
423-
'a' => 7 as char,
424-
'b' => 8 as char,
425-
'f' => 12 as char,
426-
'n' => '\n',
427-
'r' => '\r',
428-
't' => '\t',
429-
'v' => 11 as char,
430-
n if is_oct(n) => {
431-
count += is_slice_oct(2) as usize + (is_slice_oct(2) && is_slice_oct(3)) as usize;
432-
slice[1..]
433-
.iter()
434-
.take(count - 1)
435-
.fold(0, |acc, digit| acc * 8 + digit - b'0') as char
436-
}
437-
'x' if !posix_strict => todo!(),
438-
'u' => todo!(),
439-
// Unspecified by POSIX; we ditto GNU.
440-
c => c, // TODO: Output warning
411+
let escaped = match to_escape {
412+
c @ ('\\' | '"') if !REGEX => c,
413+
c @ ('[' | ']' | '{' | '}' | '(' | ')' | '*' | '+' | '^' | '$' | '.' | '?') if REGEX => {
414+
out.push(b'\\');
415+
c
416+
}
417+
'a' => 7 as char,
418+
'b' => 8 as char,
419+
'f' => 12 as char,
420+
'n' => '\n',
421+
'r' => '\r',
422+
't' => '\t',
423+
'v' => 11 as char,
424+
n if is_oct(n) => {
425+
count += is_slice_oct(2) as usize + (is_slice_oct(2) && is_slice_oct(3)) as usize;
426+
slice[1..]
427+
.iter()
428+
.take(count - 1)
429+
.fold(0, |acc, digit| acc * 8 + digit - b'0') as char
441430
}
431+
'x' if !posix_strict => todo!(),
432+
'u' => todo!(),
433+
// Unspecified by POSIX; we ditto GNU.
434+
c => c, // TODO: Output warning
442435
};
443436
out.push(escaped as u8);
444437
Ok(count)
@@ -511,7 +504,7 @@ fn accept_operator(lex: &mut Lexer<'_>) {
511504
lex.extras.ctx = Context::AcceptOperator;
512505
}
513506

514-
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
507+
#[derive(Clone)]
515508
pub enum Slice<'a> {
516509
Borrowed(&'a [u8]),
517510
Owned(Vec<'a, u8>),
@@ -556,12 +549,38 @@ impl<'a> From<&'a [u8]> for Slice<'a> {
556549
}
557550
}
558551

552+
impl<'a, const N: usize> From<&'a [u8; N]> for Slice<'a> {
553+
fn from(value: &'a [u8; N]) -> Self {
554+
Self::Borrowed(value)
555+
}
556+
}
557+
559558
impl<'a> From<Vec<'a, u8>> for Slice<'a> {
560559
fn from(value: Vec<'a, u8>) -> Self {
561560
Self::Owned(value)
562561
}
563562
}
564563

564+
impl PartialEq for Slice<'_> {
565+
fn eq(&self, other: &Self) -> bool {
566+
self.as_ref() == other.as_ref()
567+
}
568+
}
569+
570+
impl Eq for Slice<'_> {}
571+
572+
impl PartialOrd for Slice<'_> {
573+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
574+
Some(self.cmp(other))
575+
}
576+
}
577+
578+
impl Ord for Slice<'_> {
579+
fn cmp(&self, other: &Self) -> Ordering {
580+
self.as_ref().cmp(other.as_ref())
581+
}
582+
}
583+
565584
impl Extra {
566585
fn arena<'a>(&self) -> &'a Bump {
567586
// SAFETY: lives for as long as self because it's the same lifetime as

0 commit comments

Comments
 (0)