Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 54 additions & 3 deletions cfgrammar/src/lib/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
},
};
use regex::{Regex, RegexBuilder};
use std::{error::Error, fmt, sync::LazyLock};
use std::{collections::HashMap, error::Error, fmt, sync::LazyLock};

/// An error regarding the `%grmtools` header section.
///
Expand Down Expand Up @@ -239,13 +239,53 @@ impl<T> Namespaced<T> {
static RE_LEADING_WS: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"^[\p{Pattern_White_Space}]*").unwrap());
static RE_NAME: LazyLock<Regex> = LazyLock::new(|| {
RegexBuilder::new(r"^[A-Z][A-Z_]*")
RegexBuilder::new(r"^[A-Z][A-Z_\.]*")
.case_insensitive(true)
.build()
.unwrap()
});
#[doc(hidden)]
pub static RE_CRATE_DOT: LazyLock<Regex> = LazyLock::new(|| {
RegexBuilder::new(r"^[A-Z][A-Z_]*\.")
.case_insensitive(true)
.build()
.unwrap()
});
static RE_DIGITS: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"^[0-9]+").unwrap());
static RE_STRING: LazyLock<Regex> = LazyLock::new(|| Regex::new(r#"^\"(\\.|[^"\\])*\""#).unwrap());
#[doc(hidden)]
pub static CRATE_KEY_MAP: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(|| {
let mut map = HashMap::new();
let cfgrammar = ["yacckind"];
let lrpar = ["recoverer", "test_files", "serialisation_format"];

let lrlex = ["lexerkind", "allow_wholeline_comments", "posix_escapes"];
let regex = [
"case_insensitive",
"dot_matches_new_line",
"multi_line",
"octal",
"swap_greed",
"ignore_whitespace",
"unicode",
"size_limit",
"dfa_size_limit",
"nest_limit",
];
for s in cfgrammar {
map.insert(s, "cfgrammar");
}
for s in lrpar {
map.insert(s, "lrpar");
}
for s in lrlex {
map.insert(s, "lrlex");
}
for s in regex {
map.insert(s, "regex");
}
map
});

const MAGIC: &str = "%grmtools";

Expand Down Expand Up @@ -429,7 +469,18 @@ impl<'input> GrmtoolsSectionParser<'input> {
i = self.parse_ws(j);
while self.lookahead_is("}", i).is_none() && i < self.src.len() {
let (key, key_loc, val, j) = match self.parse_key_value(i) {
Ok((key, key_loc, val, pos)) => (key, key_loc, val, pos),
Ok((key, key_loc, val, pos)) => {
let key = if !RE_CRATE_DOT.is_match(&key) {
if let Some(crate_name) = CRATE_KEY_MAP.get(key.as_str()) {
format!("{crate_name}.{key}")
} else {
key
}
} else {
key
};
(key, key_loc, val, pos)
}
Err(e) => {
errs.push(e);
return Err(errs);
Expand Down
4 changes: 2 additions & 2 deletions cfgrammar/src/lib/yacc/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl FromStr for ASTWithValidityInfo {
let (header, _) = GrmtoolsSectionParser::new(src, true)
.parse()
.map_err(|mut errs| errs.drain(..).map(|e| e.into()).collect::<Vec<_>>())?;
if let Some(HeaderValue(_, yk_val)) = header.get("yacckind") {
if let Some(HeaderValue(_, yk_val)) = header.get("cfgrammar.yacckind") {
let yacc_kind = YaccKind::try_from(yk_val).map_err(|e| vec![e.into()])?;
let ast = {
// We don't want to strip off the header so that span's will be correct.
Expand All @@ -138,7 +138,7 @@ impl FromStr for ASTWithValidityInfo {
} else {
Err(vec![
HeaderError {
kind: HeaderErrorKind::InvalidEntry("yacckind"),
kind: HeaderErrorKind::InvalidEntry("cfgrammar.yacckind"),
locations: vec![Span::new(0, 0)],
}
.into(),
Expand Down
32 changes: 16 additions & 16 deletions doc/src/lexextensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,26 @@ other flags should specify their value immediately after the flag name.

## List of flags:

| Flag | Value | Required | Regex[^regex] |
|-------------------------------|-----------|----------|---------------|
| `lexerkind` | [LexerKind](lexcompatibility.md#lexerkinds) | &cross; | &cross; |
| `posix_escapes`[^†] | bool | &cross; | &cross; |
| `allow_wholeline_comment`[^‡] | bool | &cross; | &cross; |
| `case_insensitive` | bool | &cross; | &checkmark; |
| `dot_matches_new_line` | bool | &cross; | &checkmark; |
| `multi_line` | bool | &cross; | &checkmark; |
| `octal` | bool | &cross; | &checkmark; |
| `swap_greed` | bool | &cross; | &checkmark; |
| `ignore_whitespace` | bool | &cross; | &checkmark; |
| `unicode` | bool | &cross; | &checkmark; |
| `size_limit` | usize | &cross; | &checkmark; |
| `dfa_size_limit` | usize | &cross; | &checkmark; |
| `nest_limit` | u32 | &cross; | &checkmark; |
| Flag | Value | Required |
|-------------------------------|-----------|----------|
| `lrlex.lexerkind` | [LexerKind](lexcompatibility.md#lexerkinds) | &cross; |
| `lrlex.posix_escapes`[^†] | bool | &cross; |
| `lrlex.allow_wholeline_comments`[^‡] | bool | &cross; |
| `regex.case_insensitive` | bool | &cross; |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex prefix hadn't occurred to me. I think I like it!

| `regex.dot_matches_new_line` | bool | &cross; |
| `regex.multi_line` | bool | &cross; |
| `regex.octal` | bool | &cross; |
| `regex.swap_greed` | bool | &cross; |
| `regex.ignore_whitespace` | bool | &cross; |
| `regex.unicode` | bool | &cross; |
| `regex.size_limit` | usize | &cross; |
| `regex.dfa_size_limit` | usize | &cross; |
| `regex.nest_limit` | u32 | &cross; |

[^†]: Enable compatibility with posix escape sequences.
[^‡]: Enables rust style `// comments` at the start of lines.
Which requires escaping of `/` when used in a regex.
[^regex]: &checkmark; Flag gets passed directly to `regex::RegexBuilder`.
[^regex]: Flag gets passed directly to `regex::RegexBuilder`.


## Flags affecting Posix compatibility
Expand Down
8 changes: 4 additions & 4 deletions doc/src/yaccextensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ But a default can be set or forced by using a `YaccKindResolver`.

| Flag | Value | Required |
|------------------|-------------------------------------------------|--------------|
| `yacckind` | [YaccKind](yacccompatibility.md#yacckinds) | &checkmark; |
| `recoverykind` | [RecoveryKind](errorrecovery.md#recoverykinds) | &cross; |
| `test_files`[^†] | Array of string values | &cross; |
| `serialisation_format`[^⹋] | `lrpar::SerialisationFormat` | &cross; |
| `cfgrammar.yacckind` | [YaccKind](yacccompatibility.md#yacckinds) | &checkmark; |
| `lrpar.recoverykind` | [RecoveryKind](errorrecovery.md#recoverykinds) | &cross; |
| `lrpar.test_files`[^†] | Array of string values | &cross; |
| `lrpar.serialisation_format`[^⹋] | `lrpar::SerialisationFormat` | &cross; |

[^†]: Strings containing globs are resolved relative to the yacc `.y` source file.
`test_files` is currently experimental.
Expand Down
4 changes: 2 additions & 2 deletions lrlex/src/lib/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,11 @@ where
{
self.merge_headers()?;
let mod_name = self.resolve_mod_name(&args)?;
self.header.mark_used(&"lexerkind".to_string());
self.header.mark_used(&"lrlex.lexerkind".to_string());
let lexerkind = match args.lexerkind {
Some(lexerkind) => lexerkind,
None => {
if let Some(HeaderValue(_, lk_val)) = self.header.get("lexerkind") {
if let Some(HeaderValue(_, lk_val)) = self.header.get("lrlex.lexerkind") {
LexerKind::try_from(lk_val)?
} else {
LexerKind::LRNonStreamingLexer
Expand Down
28 changes: 14 additions & 14 deletions lrlex/src/lib/ctbuilder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,9 +504,9 @@ where
.map(|(x, y)| (&**x, *y))
.collect::<HashMap<_, _>>();
closure_lexerdef.set_rule_ids(&owned_map);
yacc_header.mark_used(&"test_files".to_string());
yacc_header.mark_used(&"lrpar.test_files".to_string());
let grammar = rtpb.grammar();
let test_glob = yacc_header.get("test_files");
let test_glob = yacc_header.get("lrpar.test_files");
let mut err_str = None;
let add_error_line = |err_str: &mut Option<String>, line| {
if let Some(err_str) = err_str {
Expand Down Expand Up @@ -841,7 +841,7 @@ where
///
/// Setting this flag will override the same flag within a `%grmtools` section.
pub fn allow_wholeline_comments(mut self, flag: bool) -> Self {
let key = "allow_wholeline_comments".to_string();
let key = "lrlex.allow_wholeline_comments".to_string();
self.header.insert(
key,
HeaderValue(
Expand All @@ -857,7 +857,7 @@ where
///
/// Setting this flag will override the same flag within a `%grmtools` section.
pub fn dot_matches_new_line(mut self, flag: bool) -> Self {
let key = "dot_matches_new_line".to_string();
let key = "regex.dot_matches_new_line".to_string();
self.header.insert(
key,
HeaderValue(
Expand All @@ -873,7 +873,7 @@ where
///
/// Setting this flag will override the same flag within a `%grmtools` section.
pub fn multi_line(mut self, flag: bool) -> Self {
let key = "multi_line".to_string();
let key = "regex.multi_line".to_string();
self.header.insert(
key,
HeaderValue(
Expand All @@ -889,7 +889,7 @@ where
///
/// Setting this flag will override the same flag within a `%grmtools` section.
pub fn posix_escapes(mut self, flag: bool) -> Self {
let key = "posix_escapes".to_string();
let key = "lrlex.posix_escapes".to_string();
self.header.insert(
key,
HeaderValue(
Expand All @@ -905,7 +905,7 @@ where
///
/// Setting this flag will override the same flag within a `%grmtools` section.
pub fn octal(mut self, flag: bool) -> Self {
let key = "octal".to_string();
let key = "regex.octal".to_string();
self.header.insert(
key,
HeaderValue(
Expand All @@ -921,7 +921,7 @@ where
///
/// Setting this flag will override the same flag within a `%grmtools` section.
pub fn swap_greed(mut self, flag: bool) -> Self {
let key = "swap_greed".to_string();
let key = "regex.swap_greed".to_string();
self.header.insert(
key,
HeaderValue(
Expand All @@ -937,7 +937,7 @@ where
///
/// Setting this flag will override the same flag within a `%grmtools` section.
pub fn ignore_whitespace(mut self, flag: bool) -> Self {
let key = "ignore_whitespace".to_string();
let key = "regex.ignore_whitespace".to_string();
self.header.insert(
key,
HeaderValue(
Expand All @@ -953,7 +953,7 @@ where
///
/// Setting this flag will override the same flag within a `%grmtools` section.
pub fn unicode(mut self, flag: bool) -> Self {
let key = "unicode".to_string();
let key = "regex.unicode".to_string();
self.header.insert(
key,
HeaderValue(
Expand All @@ -969,7 +969,7 @@ where
///
/// Setting this flag will override the same flag within a `%grmtools` section.
pub fn case_insensitive(mut self, flag: bool) -> Self {
let key = "case_insensitive".to_string();
let key = "regex.case_insensitive".to_string();
self.header.insert(
key,
HeaderValue(
Expand All @@ -985,7 +985,7 @@ where
///
/// Setting this flag will override the same flag within a `%grmtools` section.
pub fn size_limit(mut self, sz: usize) -> Self {
let key = "size_limit".to_string();
let key = "regex.size_limit".to_string();
self.header.insert(
key,
HeaderValue(
Expand All @@ -1004,7 +1004,7 @@ where
///
/// Setting this flag will override the same flag within a `%grmtools` section.
pub fn dfa_size_limit(mut self, sz: usize) -> Self {
let key = "dfa_size_limit".to_string();
let key = "regex.dfa_size_limit".to_string();
self.header.insert(
key,
HeaderValue(
Expand All @@ -1023,7 +1023,7 @@ where
///
/// Setting this flag will override the same flag within a `%grmtools` section.
pub fn nest_limit(mut self, lim: u32) -> Self {
let key = "nest_limit".to_string();
let key = "regex.nest_limit".to_string();
self.header.insert(
key,
HeaderValue(
Expand Down
36 changes: 18 additions & 18 deletions lrlex/src/lib/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ impl<T: Clone> TryFrom<&mut Header<T>> for LexFlags {
nest_limit,
} = &mut lex_flags;
macro_rules! cvt_flag {
($it:ident) => {
header.mark_used(&stringify!($it).to_string());
*$it = match header.get(stringify!($it)) {
($prefix:ident, $it:ident) => {
header.mark_used(&stringify!($prefix.$it).to_string());
*$it = match header.get(stringify!($prefix.$it)) {
Some(HeaderValue(_, Value::Flag(flag, _))) => Some(*flag),
Some(HeaderValue(loc, _)) => Err(HeaderError {
kind: HeaderErrorKind::ConversionError("LexFlags", "Expected boolean"),
Expand All @@ -76,19 +76,19 @@ impl<T: Clone> TryFrom<&mut Header<T>> for LexFlags {
}
};
}
cvt_flag!(dot_matches_new_line);
cvt_flag!(multi_line);
cvt_flag!(octal);
cvt_flag!(posix_escapes);
cvt_flag!(allow_wholeline_comments);
cvt_flag!(case_insensitive);
cvt_flag!(swap_greed);
cvt_flag!(ignore_whitespace);
cvt_flag!(unicode);
cvt_flag!(regex, dot_matches_new_line);
cvt_flag!(regex, multi_line);
cvt_flag!(regex, octal);
cvt_flag!(lrlex, posix_escapes);
cvt_flag!(lrlex, allow_wholeline_comments);
cvt_flag!(regex, case_insensitive);
cvt_flag!(regex, swap_greed);
cvt_flag!(regex, ignore_whitespace);
cvt_flag!(regex, unicode);
macro_rules! cvt_num {
($it:ident, $num_ty: ty) => {
header.mark_used(&stringify!($it).to_string());
*$it = match header.get(stringify!($it)) {
($prefix:ident, $it:ident, $num_ty: ty) => {
header.mark_used(&stringify!($prefix.$it).to_string());
*$it = match header.get(stringify!($prefix.$it)) {
Some(HeaderValue(_, Value::Setting(Setting::Num(n, _)))) => Some(*n as $num_ty),
Some(HeaderValue(loc, _)) => Err(HeaderError {
kind: HeaderErrorKind::ConversionError("LexFlags", "Expected numeric"),
Expand All @@ -98,9 +98,9 @@ impl<T: Clone> TryFrom<&mut Header<T>> for LexFlags {
}
};
}
cvt_num!(size_limit, usize);
cvt_num!(dfa_size_limit, usize);
cvt_num!(nest_limit, u32);
cvt_num!(regex, size_limit, usize);
cvt_num!(regex, dfa_size_limit, usize);
cvt_num!(regex, nest_limit, u32);
Ok(lex_flags)
}
}
Expand Down
4 changes: 2 additions & 2 deletions lrlex/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ fn main() -> Result<(), Box<dyn Error>> {
process::exit(1);
}
};
header.mark_used(&"lexerkind".to_string());
let lexerkind = if let Some(HeaderValue(_, lk_val)) = header.get("lexerkind") {
header.mark_used(&"lrlex.lexerkind".to_string());
let lexerkind = if let Some(HeaderValue(_, lk_val)) = header.get("lrlex.lexerkind") {
LexerKind::try_from(lk_val)?
} else {
LexerKind::LRNonStreamingLexer
Expand Down
Loading