From e5b71f6f25e1cf7483750430fe9065bffa4466eb Mon Sep 17 00:00:00 2001 From: Sarrus1 Date: Wed, 19 Jul 2023 01:08:06 +0200 Subject: [PATCH] feat: add support for stringizing in preprocessor --- CHANGELOG.md | 4 + Cargo.lock | 4 +- Cargo.toml | 2 +- src/sourcepawn_preprocessor/Cargo.toml | 2 +- src/sourcepawn_preprocessor/src/lib.rs | 92 +++++++++++++++++++++++ src/sourcepawn_preprocessor/src/macros.rs | 53 +++++++++++-- src/store.rs | 12 ++- 7 files changed, 155 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da64893..311a3d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [0.10.12] +### Added + +- Added support for stringizing in preprocessor. + ### Fixed - Fixed "receiving on an empty or disconnected channel" bug when stopping the server. diff --git a/Cargo.lock b/Cargo.lock index 51cb119..7552de5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1859,9 +1859,7 @@ dependencies = [ [[package]] name = "sourcepawn_lexer" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4551b3db94918208b29ad12993233d3c076467026784885503eb32bbf89560a" +version = "0.1.1" dependencies = [ "lazy_static", "logos", diff --git a/Cargo.toml b/Cargo.toml index 20bb539..ff3ed30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ tempfile = "3.4.0" clap = { version = "4.1.13", features = ["derive"] } fern = "0.6.2" humantime = "2.1.0" -sourcepawn_lexer = "0.1.0" +sourcepawn_lexer = "0.1.1" sourcepawn_preprocessor = { path = "src/sourcepawn_preprocessor" } sentry = "0.31.3" strip_bom = "1.0.0" diff --git a/src/sourcepawn_preprocessor/Cargo.toml b/src/sourcepawn_preprocessor/Cargo.toml index e18eda5..b75d335 100644 --- a/src/sourcepawn_preprocessor/Cargo.toml +++ b/src/sourcepawn_preprocessor/Cargo.toml @@ -15,4 +15,4 @@ anyhow = "1.0.66" lazy_static = "1.4.0" regex = "1.7.0" fxhash = "0.2.1" -sourcepawn_lexer = "0.1.0" +sourcepawn_lexer = "0.1.1" diff --git a/src/sourcepawn_preprocessor/src/lib.rs b/src/sourcepawn_preprocessor/src/lib.rs index bd54205..37d893f 100644 --- a/src/sourcepawn_preprocessor/src/lib.rs +++ b/src/sourcepawn_preprocessor/src/lib.rs @@ -1135,6 +1135,34 @@ int foo = 1 + 2; ); } + #[test] + fn macro_expansion_5() { + let input = r#"#define GET_VALUE(%1,%2) \ + public %1 Get%2(){ \ + %1 i; \ + this.GetValue("m_" ... #%2, i); \ + return i;} + + GET_VALUE(void, Foo)"#; + let output = r#"#define GET_VALUE(%1,%2) \ + public %1 Get%2(){ \ + %1 i; \ + this.GetValue("m_" ... #%2, i); \ + return i;} + + public void GetFoo(){ void i; this.GetValue("m_" ... "Foo", i); return i;}"#; + + assert_eq!( + SourcepawnPreprocessor::new( + Arc::new(Url::parse("https://example.net").unwrap()), + input + ) + .preprocess_input(&mut extend_macros) + .unwrap(), + output + ); + } + #[test] fn include_directive_1() { let input = r#"#include "#; @@ -1184,4 +1212,68 @@ int foo = 1 + 2; output ); } + + #[test] + fn stringizing_1() { + let input = r#"#define FOO(%0) #%0 +char foo[8] = FOO(foo);"#; + let output = r#"#define FOO(%0) #%0 +char foo[8] = "foo";"#; + assert_eq!( + SourcepawnPreprocessor::new( + Arc::new(Url::parse("https://example.net").unwrap()), + input + ) + .preprocess_input(&mut extend_macros) + .unwrap(), + output + ); + } + + #[test] + fn stringizing_2() { + let input = r#"#define FOO(%0,%1) #%0 ... #%1 +char foo[8] = FOO(foo, bar);"#; + let output = r#"#define FOO(%0,%1) #%0 ... #%1 +char foo[8] = "foo" ... "bar";"#; + assert_eq!( + SourcepawnPreprocessor::new( + Arc::new(Url::parse("https://example.net").unwrap()), + input + ) + .preprocess_input(&mut extend_macros) + .unwrap(), + output + ); + } + + #[test] + fn stringizing_3() { + let input = r#"#define DISPOSE_MEMBER(%1) \ + Handle m_h%1; \ + if(this.GetValue("m_" ... #%1, m_h%1)){ \ + delete m_h%1;} +void foo(){ + DISPOSE_MEMBER(Foo) +}"#; + let output = r#"#define DISPOSE_MEMBER(%1) \ + Handle m_h%1; \ + if(this.GetValue("m_" ... #%1, m_h%1)){ \ + delete m_h%1;} +void foo(){ + Handle m_hFoo; if(this.GetValue("m_" ... "Foo", m_hFoo)){ delete m_hFoo;} +}"#; + assert_eq!( + SourcepawnPreprocessor::new( + Arc::new(Url::parse("https://example.net").unwrap()), + input + ) + .preprocess_input(&mut extend_macros) + .unwrap_or_else(|err| { + eprintln!("{:?}", err); + "".to_string() + }), + output + ); + } } diff --git a/src/sourcepawn_preprocessor/src/macros.rs b/src/sourcepawn_preprocessor/src/macros.rs index 36c7357..6d76075 100644 --- a/src/sourcepawn_preprocessor/src/macros.rs +++ b/src/sourcepawn_preprocessor/src/macros.rs @@ -101,6 +101,7 @@ fn expand_macro( d: i32, ) -> Result<(), ParseIntError> { let mut consecutive_percent = 0; + let mut stringize_delta = None; for (i, child) in macro_.body.iter().enumerate() { match &child.token_kind { TokenKind::Operator(Operator::Percent) => { @@ -114,9 +115,13 @@ fn expand_macro( stack.push((child.clone(), child.delta, d + 1)) } } + TokenKind::Operator(Operator::Stringize) => { + stringize_delta = Some(child.delta); + stack.push((child.clone(), child.delta, d + 1)) + } TokenKind::Literal(Literal::IntegerLiteral) => { if consecutive_percent == 1 { - stack.pop(); + let percent_symbol = stack.pop().unwrap(); // Safe unwrap. let arg_idx = child .to_int() .ok_or_else(|| ParseIntError::new(child.text(), child.range))? @@ -129,12 +134,45 @@ fn expand_macro( if arg_idx >= 10 { return Err(ParseIntError::new(child.text(), child.range)); } - for (j, sub_child) in args[arg_idx as usize].iter().enumerate() { - stack.push(( - sub_child.clone(), - if j == 0 { child.delta } else { sub_child.delta }, - d + 1, - )); + if let Some(stringize_delta) = stringize_delta.take() { + stack.pop(); + let mut stringized = '"'.to_string(); + for sub_child in args[arg_idx as usize].iter() { + stringized.push_str(&sub_child.inline_text()); + } + stringized.push('"'); + let delta = if i == 2 { + symbol.delta + } else { + stringize_delta + }; + let symbol = Symbol::new( + TokenKind::Literal(Literal::StringLiteral), + Some(&stringized), + Range::new( + symbol.range.start, + Position::new( + symbol.range.start.line, + symbol.range.start.character + stringized.len() as u32, + ), + ), + delta, + ); + stack.push((symbol, delta, d + 1)); + } else { + for (j, sub_child) in args[arg_idx as usize].iter().enumerate() { + stack.push(( + sub_child.clone(), + if i == 1 { + symbol.delta + } else if j == 0 { + percent_symbol.1 + } else { + sub_child.delta + }, + d + 1, + )); + } } } else { stack.push((child.clone(), child.delta, d + 1)); @@ -148,6 +186,7 @@ fn expand_macro( d + 1, )); consecutive_percent = 0; + stringize_delta = None; } } } diff --git a/src/store.rs b/src/store.rs index baf2b71..bc08709 100644 --- a/src/store.rs +++ b/src/store.rs @@ -289,7 +289,11 @@ impl Store { self.extend_macros(macros, path, document_uri, quoted) }), ) - .unwrap_or_else(|_| document.text.clone()); + .unwrap_or_else(|err| { + log::error!("{:?}", err); + document.text.clone() + }); + document.preprocessed_text = preprocessed_text; document.macros = preprocessor.macros.clone(); document.offsets = preprocessor.offsets.clone(); @@ -334,7 +338,11 @@ impl Store { self.extend_macros(macros, path, document_uri, quoted) }), ) - .unwrap_or_else(|_| text.clone()); + .unwrap_or_else(|err| { + log::error!("{:?}", err); + text.clone() + }); + if let Some(document) = self.documents.get_mut(&uri) { document.preprocessed_text = preprocessed_text; document.macros = preprocessor.macros.clone();