├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches └── basic │ └── ascii.cpp ├── cli_ast ├── Cargo.toml └── src │ └── main.rs ├── cli_macro_stats ├── Cargo.lock ├── Cargo.toml └── src │ └── main.rs └── src ├── args.rs ├── defaults.rs ├── errors.rs ├── lexer ├── buffer.rs ├── cchar.rs ├── comment.rs ├── errors.rs ├── extra.rs ├── lexer.rs ├── mod.rs ├── number.rs ├── preprocessor │ ├── cache.rs │ ├── condition.rs │ ├── context.rs │ ├── include.rs │ ├── macro_args.rs │ ├── macros.rs │ ├── mod.rs │ └── preprocessor.rs ├── source.rs ├── string.rs └── tools.rs ├── lib.rs ├── macros.rs └── parser ├── attributes.rs ├── context.rs ├── declarations ├── array.rs ├── asm.rs ├── bitfield.rs ├── class.rs ├── decl.rs ├── enum.rs ├── extern.rs ├── function.rs ├── member.rs ├── mod.rs ├── namespace.rs ├── pointer.rs ├── specifier.rs ├── static_assert.rs ├── types.rs └── using.rs ├── dump.rs ├── errors.rs ├── expressions ├── casts.rs ├── expr.rs ├── left_paren.rs ├── list.rs ├── mod.rs ├── operator.rs └── params.rs ├── initializer ├── init.rs └── mod.rs ├── literals.rs ├── mod.rs ├── names ├── dtor.rs ├── mod.rs ├── name.rs └── operator.rs ├── statements ├── compound.rs ├── do.rs ├── for.rs ├── goto.rs ├── if.rs ├── mod.rs ├── return.rs ├── stmt.rs ├── switch.rs ├── try.rs └── while.rs ├── types ├── cv.rs ├── mod.rs ├── primitive.rs └── type.rs └── unit.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | *~ 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cpp-parser" 3 | version = "0.0.1" 4 | authors = ["calixteman "] 5 | edition = "2018" 6 | license = "MIT OR Apache-2.0" 7 | repository = "https://github.com/calixteman/rust-cpp-parser" 8 | 9 | [dependencies] 10 | bitflags = "1.2" 11 | termcolor = "1.0" 12 | hashbrown = "0.7" 13 | lazy_static = "1.4" 14 | same-file = "1.0" 15 | serde = { version = "1.0", features = ["derive"] } 16 | serde_json = "1.0" 17 | 18 | [dev-dependencies] 19 | tempdir = "0.3" 20 | pretty_assertions = "0.6" 21 | 22 | [lib] 23 | name = "cpp_parser" 24 | path = "src/lib.rs" 25 | 26 | [workspace] 27 | members = ["cli_macro_stats", "cli_ast"] 28 | 29 | [profile.release] 30 | lto = true -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-cpp-parser 2 | 3 | A C/C++ parser in Rust. 4 | 5 | It's a WIP so don't use it except if you want to contribute or fix bugs. 6 | 7 | There are several goals here: 8 | - be able to identify unused macros 9 | - remove useless includes 10 | - help with the analysis of code change 11 | 12 | It's a spare time project so I'm not super active (it mainly depends on what I've to do during the week-end). 13 | 14 | Disclaimer 15 | ---------- 16 | 17 | This is not an official Mozilla product. -------------------------------------------------------------------------------- /benches/basic/ascii.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | std::cout << "Printable ASCII:\n"; 6 | for (char i = 32; i < 127; ++i) { 7 | std::cout << i << ' '; 8 | if (i % 16 == 15) 9 | std::cout << '\n'; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /cli_ast/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ast" 3 | version = "0.0.1" 4 | authors = ["calixteman "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | clap = "2.33" 9 | cpp-parser = { path = ".." } 10 | -------------------------------------------------------------------------------- /cli_ast/src/main.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | #[macro_use] 7 | extern crate clap; 8 | 9 | use clap::{App, Arg}; 10 | use cpp_parser::args::{Language, PreprocOptions}; 11 | use cpp_parser::defaults; 12 | use cpp_parser::lexer::preprocessor::cache::IfCache; 13 | use cpp_parser::lexer::preprocessor::context::{DefaultContext, PreprocContext}; 14 | use cpp_parser::lexer::source; 15 | use cpp_parser::lexer::Lexer; 16 | use cpp_parser::parser::{Context, Dump, UnitParser}; 17 | use std::path::PathBuf; 18 | use std::sync::Arc; 19 | 20 | fn main() { 21 | let matches = App::new("AST dump") 22 | .version(crate_version!()) 23 | .author(&*env!("CARGO_PKG_AUTHORS").replace(':', "\n")) 24 | .about("Report macro use") 25 | .arg( 26 | Arg::with_name("file") 27 | .help("File to dump") 28 | .takes_value(true), 29 | ) 30 | .get_matches(); 31 | 32 | let file = matches.value_of("file").unwrap().to_string(); 33 | 34 | let source = source::get_source_mutex(); 35 | let if_cache = Arc::new(IfCache::default()); 36 | let opt = PreprocOptions { 37 | def: defaults::get_defined(), 38 | sys_paths: defaults::get_sys_paths(), 39 | includes: vec![], 40 | current_dir: PathBuf::from("."), 41 | file: PathBuf::from(""), 42 | lang: Language::CPP, 43 | }; 44 | 45 | let lexer = Lexer::::new_from_file(&file, source, if_cache, opt); 46 | 47 | let context = Context::default(); 48 | let mut parser = UnitParser { lexer, context }; 49 | 50 | match parser.parse() { 51 | Ok(unit) => { 52 | unit.dump_me(); 53 | } 54 | Err(e) => { 55 | eprintln!("{:?}", e); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /cli_macro_stats/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "ahash" 5 | version = "0.3.5" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "2f3e0bf23f51883cce372d5d5892211236856e4bb37fb942e1eb135ee0f146e3" 8 | 9 | [[package]] 10 | name = "analyze" 11 | version = "0.1.0" 12 | dependencies = [ 13 | "cpp-parser", 14 | "crossbeam", 15 | "hashbrown", 16 | ] 17 | 18 | [[package]] 19 | name = "autocfg" 20 | version = "1.0.0" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 23 | 24 | [[package]] 25 | name = "bitflags" 26 | version = "1.2.1" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 29 | 30 | [[package]] 31 | name = "cfg-if" 32 | version = "0.1.10" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 35 | 36 | [[package]] 37 | name = "cpp-parser" 38 | version = "0.0.1" 39 | dependencies = [ 40 | "bitflags", 41 | "hashbrown", 42 | "lazy_static", 43 | "same-file", 44 | "serde", 45 | "serde_json", 46 | "termcolor", 47 | ] 48 | 49 | [[package]] 50 | name = "crossbeam" 51 | version = "0.7.3" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" 54 | dependencies = [ 55 | "cfg-if", 56 | "crossbeam-channel", 57 | "crossbeam-deque", 58 | "crossbeam-epoch", 59 | "crossbeam-queue", 60 | "crossbeam-utils", 61 | ] 62 | 63 | [[package]] 64 | name = "crossbeam-channel" 65 | version = "0.4.2" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" 68 | dependencies = [ 69 | "crossbeam-utils", 70 | "maybe-uninit", 71 | ] 72 | 73 | [[package]] 74 | name = "crossbeam-deque" 75 | version = "0.7.3" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" 78 | dependencies = [ 79 | "crossbeam-epoch", 80 | "crossbeam-utils", 81 | "maybe-uninit", 82 | ] 83 | 84 | [[package]] 85 | name = "crossbeam-epoch" 86 | version = "0.8.2" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" 89 | dependencies = [ 90 | "autocfg", 91 | "cfg-if", 92 | "crossbeam-utils", 93 | "lazy_static", 94 | "maybe-uninit", 95 | "memoffset", 96 | "scopeguard", 97 | ] 98 | 99 | [[package]] 100 | name = "crossbeam-queue" 101 | version = "0.2.2" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "ab6bffe714b6bb07e42f201352c34f51fefd355ace793f9e638ebd52d23f98d2" 104 | dependencies = [ 105 | "cfg-if", 106 | "crossbeam-utils", 107 | ] 108 | 109 | [[package]] 110 | name = "crossbeam-utils" 111 | version = "0.7.2" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" 114 | dependencies = [ 115 | "autocfg", 116 | "cfg-if", 117 | "lazy_static", 118 | ] 119 | 120 | [[package]] 121 | name = "hashbrown" 122 | version = "0.7.2" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf" 125 | dependencies = [ 126 | "ahash", 127 | "autocfg", 128 | ] 129 | 130 | [[package]] 131 | name = "itoa" 132 | version = "0.4.5" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" 135 | 136 | [[package]] 137 | name = "lazy_static" 138 | version = "1.4.0" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 141 | 142 | [[package]] 143 | name = "maybe-uninit" 144 | version = "2.0.0" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 147 | 148 | [[package]] 149 | name = "memoffset" 150 | version = "0.5.4" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" 153 | dependencies = [ 154 | "autocfg", 155 | ] 156 | 157 | [[package]] 158 | name = "proc-macro2" 159 | version = "1.0.17" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101" 162 | dependencies = [ 163 | "unicode-xid", 164 | ] 165 | 166 | [[package]] 167 | name = "quote" 168 | version = "1.0.6" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" 171 | dependencies = [ 172 | "proc-macro2", 173 | ] 174 | 175 | [[package]] 176 | name = "ryu" 177 | version = "1.0.4" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" 180 | 181 | [[package]] 182 | name = "same-file" 183 | version = "1.0.6" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 186 | dependencies = [ 187 | "winapi-util", 188 | ] 189 | 190 | [[package]] 191 | name = "scopeguard" 192 | version = "1.1.0" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 195 | 196 | [[package]] 197 | name = "serde" 198 | version = "1.0.111" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d" 201 | dependencies = [ 202 | "serde_derive", 203 | ] 204 | 205 | [[package]] 206 | name = "serde_derive" 207 | version = "1.0.111" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250" 210 | dependencies = [ 211 | "proc-macro2", 212 | "quote", 213 | "syn", 214 | ] 215 | 216 | [[package]] 217 | name = "serde_json" 218 | version = "1.0.53" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" 221 | dependencies = [ 222 | "itoa", 223 | "ryu", 224 | "serde", 225 | ] 226 | 227 | [[package]] 228 | name = "syn" 229 | version = "1.0.29" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "bb37da98a55b1d08529362d9cbb863be17556873df2585904ab9d2bc951291d0" 232 | dependencies = [ 233 | "proc-macro2", 234 | "quote", 235 | "unicode-xid", 236 | ] 237 | 238 | [[package]] 239 | name = "termcolor" 240 | version = "1.1.0" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" 243 | dependencies = [ 244 | "winapi-util", 245 | ] 246 | 247 | [[package]] 248 | name = "unicode-xid" 249 | version = "0.2.0" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 252 | 253 | [[package]] 254 | name = "winapi" 255 | version = "0.3.8" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 258 | dependencies = [ 259 | "winapi-i686-pc-windows-gnu", 260 | "winapi-x86_64-pc-windows-gnu", 261 | ] 262 | 263 | [[package]] 264 | name = "winapi-i686-pc-windows-gnu" 265 | version = "0.4.0" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 268 | 269 | [[package]] 270 | name = "winapi-util" 271 | version = "0.1.5" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 274 | dependencies = [ 275 | "winapi", 276 | ] 277 | 278 | [[package]] 279 | name = "winapi-x86_64-pc-windows-gnu" 280 | version = "0.4.0" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 283 | -------------------------------------------------------------------------------- /cli_macro_stats/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stats" 3 | version = "0.0.1" 4 | authors = ["calixteman "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | clap = "2.33" 9 | cpp-parser = { path = ".." } 10 | crossbeam = "0.7" 11 | globset = "0.4" 12 | hashbrown = "0.7" 13 | num_cpus = "1.13" 14 | serde = "1.0" 15 | serde_json = "1.0" -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use crate::lexer::errors::LexerError; 7 | use crate::lexer::lexer::Location; 8 | use crate::lexer::source::FileId; 9 | 10 | #[derive(Debug, Clone, Copy, Default)] 11 | pub struct Span { 12 | pub file: Option, 13 | pub start: Location, 14 | pub end: Location, 15 | } 16 | 17 | #[derive(Debug, Clone)] 18 | pub enum Error { 19 | LexerError(LexerError), 20 | } 21 | 22 | impl Error { 23 | pub fn stringly(&self) -> StringlyError { 24 | let stringly = match self { 25 | Error::LexerError(le) => le.stringly(), 26 | }; 27 | stringly 28 | } 29 | } 30 | 31 | pub struct StringlyError { 32 | pub message: String, 33 | pub sp: Span, 34 | } 35 | -------------------------------------------------------------------------------- /src/lexer/buffer.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use super::preprocessor::include::PathIndex; 7 | use super::source::FileId; 8 | 9 | #[derive(Debug)] 10 | pub(crate) struct OutBuf { 11 | pub(crate) buf: Vec, 12 | pub(crate) last: Option, 13 | } 14 | 15 | impl Default for OutBuf { 16 | fn default() -> Self { 17 | Self { 18 | buf: Vec::with_capacity(512), 19 | last: None, 20 | } 21 | } 22 | } 23 | 24 | impl OutBuf { 25 | #[inline(always)] 26 | pub(crate) fn invalidate(&mut self) { 27 | if let Some(last) = self.last.take() { 28 | self.buf.extend_from_slice(last.as_bytes()); 29 | } 30 | } 31 | } 32 | 33 | #[derive(Debug, Clone)] 34 | pub struct Position { 35 | pub(crate) pos: usize, 36 | pub(crate) line: u32, 37 | pub(crate) lpos: usize, 38 | } 39 | 40 | impl Default for Position { 41 | fn default() -> Self { 42 | Self { 43 | pos: 0, 44 | line: 1, 45 | lpos: 0, 46 | } 47 | } 48 | } 49 | 50 | #[derive(Debug)] 51 | pub struct BufferData { 52 | buf: Vec, 53 | position: Position, 54 | source_id: FileId, 55 | path_index: PathIndex, 56 | fake_source_id: Option, 57 | } 58 | 59 | impl BufferData { 60 | pub fn new(buf: Vec, source_id: FileId, path_index: PathIndex) -> Self { 61 | Self { 62 | buf, 63 | position: Position::default(), 64 | source_id, 65 | path_index, 66 | fake_source_id: None, 67 | } 68 | } 69 | } 70 | 71 | #[derive(Clone, Debug, Default, Hash, PartialEq)] 72 | pub struct FileInfo { 73 | pub line: u32, 74 | pub source_id: Option, 75 | } 76 | 77 | #[derive(Debug)] 78 | pub(crate) struct Buffer<'a> { 79 | stack: Vec, 80 | preproc: OutBuf, 81 | current: &'a [u8], 82 | len: usize, 83 | position: Position, 84 | saved_position: Position, 85 | saved_buf: &'a [u8], 86 | } 87 | 88 | impl<'a> Buffer<'a> { 89 | pub(crate) fn new(buf: Vec, source_id: FileId, path_index: PathIndex) -> Self { 90 | let mut ret = Self { 91 | stack: Vec::new(), 92 | preproc: OutBuf::default(), 93 | current: &[], 94 | len: buf.len(), 95 | position: Position::default(), 96 | saved_position: Position::default(), 97 | saved_buf: &[], 98 | }; 99 | ret.stack.push(BufferData { 100 | buf, 101 | position: Position::default(), 102 | source_id, 103 | fake_source_id: None, 104 | path_index, 105 | }); 106 | ret.current = 107 | unsafe { &*std::mem::transmute::<&[u8], *const [u8]>(&ret.stack.last().unwrap().buf) }; 108 | ret 109 | } 110 | 111 | pub(crate) fn switch_to_preproc(&mut self) { 112 | if self.preproc.buf.is_empty() { 113 | return; 114 | } 115 | 116 | self.saved_position = self.position.clone(); 117 | self.saved_buf = self.current; 118 | self.current = unsafe { &*std::mem::transmute::<&[u8], *const [u8]>(&self.preproc.buf) }; 119 | self.position = Position::default(); 120 | self.len = self.preproc.buf.len(); 121 | } 122 | 123 | #[inline(always)] 124 | pub(crate) fn preproc_use(&self) -> bool { 125 | !self.preproc.buf.is_empty() 126 | } 127 | 128 | #[inline(always)] 129 | pub(crate) fn get_line_file(&self) -> FileInfo { 130 | FileInfo { 131 | line: self.get_line(), 132 | source_id: self.get_source_id(), 133 | } 134 | } 135 | 136 | pub(crate) fn add_buffer(&mut self, buf: BufferData) { 137 | let last = self.stack.last_mut().unwrap(); 138 | last.position = self.position.clone(); 139 | 140 | self.stack.push(buf); 141 | let last = self.stack.last().unwrap(); 142 | self.current = unsafe { &*std::mem::transmute::<&[u8], *const [u8]>(&last.buf) }; 143 | self.position = Position::default(); 144 | self.len = self.current.len() 145 | } 146 | 147 | pub(crate) fn rm_buffer(&mut self) -> bool { 148 | if self.preproc_use() { 149 | self.current = self.saved_buf; 150 | self.len = self.current.len(); 151 | self.position = self.saved_position.clone(); 152 | self.preproc.buf.clear(); 153 | return true; 154 | } 155 | 156 | if self.stack.pop().is_none() { 157 | // the stack is empty 158 | return false; 159 | } 160 | 161 | while let Some(data) = self.stack.last() { 162 | if data.position.pos < data.buf.len() { 163 | self.current = unsafe { &*std::mem::transmute::<&[u8], *const [u8]>(&data.buf) }; 164 | self.len = self.current.len(); 165 | self.position = data.position.clone(); 166 | return true; 167 | } 168 | self.stack.pop(); 169 | } 170 | 171 | !self.stack.is_empty() 172 | } 173 | 174 | pub(crate) fn add_new_line(&mut self) { 175 | self.position.line += 1; 176 | self.position.lpos = self.position.pos + 1; 177 | } 178 | 179 | pub(crate) fn get_line(&self) -> u32 { 180 | self.position.line 181 | } 182 | 183 | pub(crate) fn set_line(&mut self, line: u32) { 184 | self.position.line = line; 185 | } 186 | 187 | pub(crate) fn get_source_id(&self) -> Option { 188 | self.stack 189 | .last() 190 | .map(|last| last.fake_source_id.unwrap_or(last.source_id)) 191 | } 192 | 193 | pub(crate) fn get_path_index(&self) -> Option { 194 | self.stack.last().map(|last| last.path_index) 195 | } 196 | 197 | pub(crate) fn set_source_id(&mut self, id: FileId) { 198 | let last = self.stack.last_mut().unwrap(); 199 | last.fake_source_id = Some(id); 200 | } 201 | 202 | pub(crate) fn get_column(&self) -> u32 { 203 | ((self.position.pos + 1) - self.position.lpos) as u32 204 | } 205 | 206 | pub(crate) fn reset(&mut self) { 207 | self.position.pos = 0; 208 | } 209 | 210 | #[inline(always)] 211 | pub(crate) fn pos(&self) -> usize { 212 | self.position.pos 213 | } 214 | 215 | #[inline(always)] 216 | pub(crate) fn raw_pos(&self) -> Position { 217 | self.position.clone() 218 | } 219 | 220 | #[inline(always)] 221 | pub(crate) fn set_pos(&mut self, pos: usize) { 222 | self.position.pos = pos; 223 | } 224 | 225 | #[inline(always)] 226 | pub(crate) fn reset_pos(&mut self, pos: Position) { 227 | self.position = pos; 228 | } 229 | 230 | #[inline(always)] 231 | pub(crate) fn rem(&self) -> usize { 232 | self.len - self.position.pos 233 | } 234 | 235 | #[inline(always)] 236 | pub(crate) fn get_preproc_buf(&mut self) -> &mut OutBuf { 237 | &mut self.preproc 238 | } 239 | 240 | #[inline(always)] 241 | pub(crate) fn slice(&self, start: usize) -> &'a [u8] { 242 | unsafe { self.current.get_unchecked(start..self.position.pos) } 243 | } 244 | 245 | #[inline(always)] 246 | pub(crate) fn slice_p(&self, start: usize, end: usize) -> &'a [u8] { 247 | unsafe { self.current.get_unchecked(start..end) } 248 | } 249 | 250 | #[inline(always)] 251 | pub(crate) fn slice_m_n(&self, start: usize, n: usize) -> &'a [u8] { 252 | unsafe { self.current.get_unchecked(start..self.position.pos - n) } 253 | } 254 | 255 | #[inline(always)] 256 | pub(crate) fn slice_n(&self, start: usize, n: usize) -> &'a [u8] { 257 | unsafe { self.current.get_unchecked(start..self.position.pos + n) } 258 | } 259 | 260 | #[inline(always)] 261 | pub(crate) fn next_char(&self) -> u8 { 262 | unsafe { *self.current.get_unchecked(self.position.pos) } 263 | } 264 | 265 | #[inline(always)] 266 | pub(crate) fn next_char_n(&self, n: usize) -> u8 { 267 | unsafe { *self.current.get_unchecked(self.position.pos + n) } 268 | } 269 | 270 | #[inline(always)] 271 | pub(crate) fn prev_char(&self) -> u8 { 272 | unsafe { *self.current.get_unchecked(self.position.pos - 1) } 273 | } 274 | 275 | #[inline(always)] 276 | pub(crate) fn prev_char_n(&self, n: usize) -> u8 { 277 | unsafe { *self.current.get_unchecked(self.position.pos - n) } 278 | } 279 | 280 | pub(crate) fn as_str(&self) -> &'a str { 281 | unsafe { std::str::from_utf8_unchecked(self.current) } 282 | } 283 | 284 | pub(crate) fn remainder_as_str(&self) -> &'a str { 285 | unsafe { std::str::from_utf8_unchecked(&self.current[self.position.pos..]) } 286 | } 287 | 288 | #[inline(always)] 289 | pub(crate) fn inc(&mut self) { 290 | self.position.pos += 1; 291 | } 292 | 293 | #[inline(always)] 294 | pub(crate) fn dec(&mut self) { 295 | self.position.pos -= 1; 296 | } 297 | 298 | #[inline(always)] 299 | pub(crate) fn inc_n(&mut self, n: usize) { 300 | self.position.pos += n; 301 | } 302 | 303 | #[inline(always)] 304 | pub(crate) fn dec_n(&mut self, n: usize) { 305 | self.position.pos -= n; 306 | } 307 | 308 | #[inline(always)] 309 | pub(crate) fn check_char(&mut self) -> bool { 310 | if self.position.pos < self.len { 311 | true 312 | } else { 313 | self.rm_buffer() 314 | } 315 | } 316 | 317 | #[inline(always)] 318 | pub(crate) fn has_char(&self) -> bool { 319 | self.position.pos < self.len 320 | } 321 | 322 | #[inline(always)] 323 | pub(crate) fn has_char_n(&self, n: usize) -> bool { 324 | self.position.pos + n < self.len 325 | } 326 | } 327 | 328 | #[cfg(test)] 329 | mod tests { 330 | 331 | use super::*; 332 | 333 | #[test] 334 | fn test_buffer() { 335 | let mut buf = Buffer::new(b"abc".to_vec(), FileId(0), PathIndex(0)); 336 | assert_eq!(buf.next_char(), b'a'); 337 | buf.inc(); 338 | 339 | buf.preproc.buf.extend_from_slice(b"def"); 340 | buf.switch_to_preproc(); 341 | 342 | assert_eq!(buf.next_char(), b'd'); 343 | buf.rm_buffer(); 344 | assert_eq!(buf.next_char(), b'b'); 345 | buf.inc(); 346 | 347 | buf.add_buffer(BufferData::new(b"ghi".to_vec(), FileId(0), PathIndex(0))); 348 | assert_eq!(buf.next_char(), b'g'); 349 | buf.rm_buffer(); 350 | 351 | assert_eq!(buf.next_char(), b'c'); 352 | } 353 | } 354 | -------------------------------------------------------------------------------- /src/lexer/comment.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use super::lexer::{Lexer, Token}; 7 | use super::preprocessor::context::PreprocContext; 8 | 9 | impl<'a, PC: PreprocContext> Lexer<'a, PC> { 10 | pub(crate) fn get_multiline_comment(&mut self) -> Token { 11 | self.buf.inc(); 12 | let spos = self.buf.pos(); 13 | loop { 14 | if self.buf.has_char() { 15 | let c = self.buf.next_char(); 16 | if c == b'/' { 17 | // TODO: we can have a continuation line between '*' and '/' 18 | let c = self.buf.prev_char(); 19 | if c == b'*' && self.buf.pos() != spos { 20 | let comment = self.buf.slice_m_n(spos, 1); 21 | self.buf.inc(); 22 | self.comment = Some(comment); 23 | return Token::Comment; 24 | } 25 | } else if c == b'\n' { 26 | self.buf.add_new_line(); 27 | } 28 | self.buf.inc(); 29 | } else { 30 | break; 31 | } 32 | } 33 | 34 | let comment = self.buf.slice(spos); 35 | self.comment = Some(comment); 36 | Token::Comment 37 | } 38 | 39 | pub(crate) fn get_single_comment(&mut self) -> Token { 40 | let spos = self.buf.pos() + 1; 41 | self.buf.inc(); 42 | loop { 43 | if self.buf.has_char() { 44 | let c = self.buf.next_char(); 45 | self.buf.inc(); 46 | if c == b'\\' { 47 | self.buf.inc(); 48 | if self.buf.has_char() { 49 | let c = self.buf.next_char(); 50 | if c == b'\n' { 51 | self.buf.add_new_line(); 52 | } 53 | } 54 | } else if c == b'\n' { 55 | //self.buf.add_new_line(); 56 | let comment = self.buf.slice_m_n(spos, 1); 57 | self.buf.dec(); 58 | self.comment = Some(comment); 59 | return Token::Comment; 60 | } 61 | } else { 62 | break; 63 | } 64 | } 65 | 66 | let comment = self.buf.slice(spos); 67 | self.comment = Some(comment); 68 | Token::Comment 69 | } 70 | 71 | #[inline(always)] 72 | pub(crate) fn skip_multiline_comment(&mut self) { 73 | let spos = self.buf.pos(); 74 | loop { 75 | if self.buf.has_char() { 76 | let c = self.buf.next_char(); 77 | if c == b'/' { 78 | let c = self.buf.prev_char(); 79 | if c == b'*' && self.buf.pos() != spos { 80 | self.buf.inc(); 81 | break; 82 | } 83 | } else if c == b'\n' { 84 | self.buf.add_new_line(); 85 | } 86 | self.buf.inc(); 87 | } else { 88 | break; 89 | } 90 | } 91 | } 92 | 93 | #[inline(always)] 94 | pub(crate) fn skip_single_comment(&mut self) { 95 | loop { 96 | if self.buf.has_char() { 97 | let c = self.buf.next_char(); 98 | if c == b'\n' { 99 | // no buf.add_new_line here (will be done later) 100 | break; 101 | } else if c == b'\\' { 102 | self.buf.inc(); 103 | if self.buf.has_char() { 104 | let c = self.buf.next_char(); 105 | if c == b'\n' { 106 | self.buf.add_new_line(); 107 | } 108 | } 109 | } 110 | self.buf.inc(); 111 | } else { 112 | break; 113 | } 114 | } 115 | } 116 | } 117 | 118 | #[cfg(test)] 119 | mod tests { 120 | 121 | use super::*; 122 | use crate::lexer::preprocessor::context::DefaultContext; 123 | use pretty_assertions::assert_eq; 124 | 125 | #[test] 126 | fn test_comment_1() { 127 | let mut p = Lexer::::new(b"/* test */"); 128 | assert_eq!(p.next_token(), Token::Comment); 129 | assert_eq!(p.get_comment().unwrap(), b" test "); 130 | } 131 | 132 | #[test] 133 | fn test_comment_2() { 134 | let mut p = Lexer::::new(b"// one line comment \n"); 135 | assert_eq!(p.next_token(), Token::Comment); 136 | assert_eq!(p.get_comment().unwrap(), b" one line comment "); 137 | } 138 | 139 | #[test] 140 | fn test_comment_3() { 141 | let mut p = Lexer::::new(b"/*/ */"); 142 | assert_eq!(p.next_token(), Token::Comment); 143 | assert_eq!(p.get_comment().unwrap(), b"/ "); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/lexer/errors.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use crate::errors::{Span, StringlyError}; 7 | 8 | #[derive(Clone, Debug)] 9 | pub enum LexerError { 10 | ErrorDirective { sp: Span, msg: String }, 11 | EndifWithoutPreceedingIf { sp: Span }, 12 | FileIncludeError { sp: Span, file: String }, 13 | } 14 | 15 | impl LexerError { 16 | pub fn stringly(&self) -> StringlyError { 17 | use self::LexerError::*; 18 | let (sp, message) = match self { 19 | ErrorDirective { sp, msg } => (*sp, format!("reached #error directive: {}", msg)), 20 | EndifWithoutPreceedingIf { sp } => { 21 | (*sp, "reached #endif without preceeding #if".to_owned()) 22 | } 23 | FileIncludeError { sp, file } => { 24 | (*sp, format!("can't open file {} for inclusion", file)) 25 | } 26 | }; 27 | StringlyError { message, sp } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/lexer/extra.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use crate::errors::Span; 7 | use crate::lexer::{TLexer, Token}; 8 | 9 | #[derive(Clone, Debug)] 10 | pub struct SavedLexer { 11 | toks: Vec, 12 | pos: usize, 13 | } 14 | 15 | impl TLexer for SavedLexer { 16 | fn next_useful(&mut self) -> Token { 17 | if let Some(tok) = self.toks.get(self.pos) { 18 | self.pos += 1; 19 | tok.clone() 20 | } else { 21 | Token::Eof 22 | } 23 | } 24 | 25 | fn span(&self) -> Span { 26 | Span::default() 27 | } 28 | } 29 | 30 | impl SavedLexer { 31 | pub fn new(toks: Vec) -> Self { 32 | Self { toks, pos: 0 } 33 | } 34 | 35 | pub fn push(&mut self, tok: Token) { 36 | self.toks.push(tok); 37 | } 38 | 39 | pub fn is_consumed(&self) -> bool { 40 | self.pos >= self.toks.len() 41 | } 42 | 43 | pub fn reset(&mut self) { 44 | self.pos = 0; 45 | } 46 | } 47 | 48 | pub struct CombinedLexers<'l1, 'l2> { 49 | first: &'l1 mut dyn TLexer, 50 | second: &'l2 mut dyn TLexer, 51 | state: bool, 52 | } 53 | 54 | impl<'l1, 'l2> TLexer for CombinedLexers<'l1, 'l2> { 55 | fn next_useful(&mut self) -> Token { 56 | let tok = if self.state { 57 | let tok = self.first.next_useful(); 58 | if tok == Token::Eof { 59 | self.state = false; 60 | self.second.next_useful() 61 | } else { 62 | tok 63 | } 64 | } else { 65 | self.second.next_useful() 66 | }; 67 | tok 68 | } 69 | 70 | fn span(&self) -> Span { 71 | if self.state { 72 | Span::default() 73 | } else { 74 | self.second.span() 75 | } 76 | } 77 | } 78 | 79 | impl<'l1, 'l2> CombinedLexers<'l1, 'l2> { 80 | pub fn new(first: &'l1 mut dyn TLexer, second: &'l2 mut dyn TLexer) -> Self { 81 | Self { 82 | first, 83 | second, 84 | state: true, 85 | } 86 | } 87 | } 88 | 89 | #[cfg(test)] 90 | mod tests { 91 | 92 | use super::*; 93 | use crate::lexer::{preprocessor::context::DefaultContext, Lexer, Token}; 94 | use pretty_assertions::assert_eq; 95 | 96 | #[test] 97 | fn test_saved_lexer() { 98 | let mut l = Lexer::::new(b"(1 + 2 * 3) + (4 - 5))"); 99 | let (_, saved) = l.save_until(Token::RightParen, 1); 100 | 101 | assert_eq!( 102 | saved.toks, 103 | vec![ 104 | Token::LeftParen, 105 | Token::LiteralInt(1), 106 | Token::Plus, 107 | Token::LiteralInt(2), 108 | Token::Star, 109 | Token::LiteralInt(3), 110 | Token::RightParen, 111 | Token::Plus, 112 | Token::LeftParen, 113 | Token::LiteralInt(4), 114 | Token::Minus, 115 | Token::LiteralInt(5), 116 | Token::RightParen, 117 | Token::RightParen 118 | ] 119 | ); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/lexer/mod.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | pub mod lexer; 7 | pub use self::lexer::*; 8 | 9 | pub mod buffer; 10 | pub mod errors; 11 | pub mod extra; 12 | pub mod preprocessor; 13 | pub mod source; 14 | 15 | mod cchar; 16 | mod comment; 17 | mod number; 18 | mod string; 19 | mod tools; 20 | -------------------------------------------------------------------------------- /src/lexer/preprocessor/cache.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use hashbrown::HashMap; 7 | use std::sync::Mutex; 8 | 9 | use crate::lexer::buffer::Position; 10 | use crate::lexer::source::FileId; 11 | 12 | #[derive(Debug, PartialEq, Hash)] 13 | struct Key { 14 | file_id: FileId, 15 | pos: usize, 16 | } 17 | 18 | impl Eq for Key {} 19 | 20 | #[derive(Debug, Default)] 21 | pub struct IfCache { 22 | cache: Mutex>, 23 | } 24 | 25 | impl IfCache { 26 | pub fn get_next(&self, file_id: FileId, pos: usize) -> Option { 27 | let cache = self.cache.lock().unwrap(); 28 | cache.get(&Key { file_id, pos }).map(|v| v.clone()) 29 | } 30 | 31 | pub fn save_next(&self, file_id: FileId, pos: usize, next: Position) { 32 | let mut cache = self.cache.lock().unwrap(); 33 | cache.insert(Key { file_id, pos }, next); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/lexer/preprocessor/context.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use hashbrown::HashMap; 7 | use std::path::{Path, PathBuf}; 8 | use std::sync::Arc; 9 | 10 | use super::cache::IfCache; 11 | use super::include::{DefaultIncludeLocator, IncludeLocator, PathIndex}; 12 | use super::macros::{ 13 | Macro, MacroCounter, MacroFile, MacroFunction, MacroLine, MacroObject, MacroType, 14 | }; 15 | use crate::lexer::buffer::{BufferData, Position}; 16 | use crate::lexer::source::{FileId, SourceMutex}; 17 | 18 | /// Indicate the state of the if statement 19 | /// Eval: indicates that we're evaluating the tokens 20 | /// Skip: indicates that we're skipping everything until the corresponding endif 21 | /// SkipAndSwitch: indicates that we're skipping until the else (if one) 22 | #[derive(Clone, Debug, PartialEq)] 23 | pub enum IfState { 24 | Eval(usize), 25 | Skip(usize), 26 | SkipAndSwitch(usize), 27 | } 28 | 29 | pub trait PreprocContext: Default + IncludeLocator { 30 | /// Set the if state 31 | fn add_if(&mut self, state: IfState); 32 | 33 | /// Call on endif 34 | fn rm_if(&mut self); 35 | 36 | /// Get the current if state 37 | fn if_state(&self) -> Option<&IfState>; 38 | 39 | /// Change the state 40 | /// For example if we're in SkipAndSwitch state then switch to Eval on else 41 | fn if_change(&mut self, state: IfState); 42 | 43 | /// Add a macro function: #define foo(a, b)... 44 | fn add_function(&mut self, name: String, mac: MacroFunction); 45 | 46 | /// Add a macro object: #define foo ... 47 | fn add_object(&mut self, name: String, mac: MacroObject); 48 | 49 | /// Remove a macro 50 | /// Called on undef 51 | fn undef(&mut self, name: &str); 52 | 53 | /// Check if a macro is defined (used in condition with function defined()) 54 | fn defined(&mut self, name: &str) -> bool; 55 | 56 | /// Get a macro (if one) with the given name 57 | fn get(&self, name: &str) -> Option<&Macro>; 58 | 59 | /// Get MacroType 60 | fn get_type(&self, name: &str) -> MacroType; 61 | 62 | /// The first time the file is preprocessed, we can save the positions of 63 | /// #if, #else, #elif and #endif. 64 | /// And when the file is read a second time then it's possible to directly 65 | /// jump to the matching preproc element according to the condition 66 | fn skip_until_next(&self, file: FileId, pos: usize) -> Option; 67 | 68 | /// Save the position of matching #if/#else|#endif 69 | fn save_switch(&self, file: FileId, pos: usize, next: Position); 70 | 71 | fn new_with_if_cache(if_cache: Arc) -> Self; 72 | } 73 | 74 | #[derive(Default)] 75 | pub struct EmptyContext {} 76 | 77 | impl PreprocContext for EmptyContext { 78 | fn add_if(&mut self, _state: IfState) {} 79 | fn rm_if(&mut self) {} 80 | 81 | fn if_state(&self) -> Option<&IfState> { 82 | None 83 | } 84 | 85 | fn if_change(&mut self, _state: IfState) {} 86 | 87 | fn add_function(&mut self, _name: String, _mac: MacroFunction) {} 88 | 89 | fn add_object(&mut self, _name: String, _mac: MacroObject) {} 90 | 91 | fn undef(&mut self, _name: &str) {} 92 | 93 | fn defined(&mut self, _name: &str) -> bool { 94 | false 95 | } 96 | 97 | fn get(&self, _name: &str) -> Option<&Macro> { 98 | None 99 | } 100 | 101 | fn get_type(&self, _name: &str) -> MacroType { 102 | MacroType::None 103 | } 104 | 105 | fn skip_until_next(&self, _file: FileId, _pos: usize) -> Option { 106 | None 107 | } 108 | 109 | fn save_switch(&self, _file: FileId, _pos: usize, _next: Position) {} 110 | 111 | fn new_with_if_cache(_if_cache: Arc) -> Self { 112 | Self {} 113 | } 114 | } 115 | 116 | impl IncludeLocator for EmptyContext { 117 | fn find( 118 | &mut self, 119 | _angle: bool, 120 | _path: &str, 121 | _next: bool, 122 | _current: FileId, 123 | _path_index: PathIndex, 124 | ) -> Option { 125 | None 126 | } 127 | 128 | fn get_id(&mut self, _path: &PathBuf) -> FileId { 129 | FileId(0) 130 | } 131 | 132 | fn get_path(&self, _id: FileId) -> PathBuf { 133 | PathBuf::from("") 134 | } 135 | 136 | fn set_source(&mut self, _source: SourceMutex) {} 137 | 138 | fn set_sys_paths>(&mut self, _paths: &[P]) {} 139 | } 140 | 141 | #[derive(Clone, Debug, PartialEq)] 142 | pub enum IfKind { 143 | If, 144 | Ifdef, 145 | Ifndef, 146 | } 147 | 148 | #[derive(Clone, Debug)] 149 | pub struct Context { 150 | macros: HashMap, 151 | if_stack: Vec, 152 | if_cache: Arc, 153 | include: IL, 154 | buffer: Option<()>, 155 | } 156 | 157 | pub type DefaultContext = Context; 158 | 159 | impl Default for Context { 160 | fn default() -> Self { 161 | Self { 162 | macros: { 163 | let mut map = HashMap::default(); 164 | map.insert("__LINE__".to_string(), Macro::Line(MacroLine::new())); 165 | map.insert("__FILE__".to_string(), Macro::File(MacroFile::new())); 166 | map.insert( 167 | "__COUNTER__".to_string(), 168 | Macro::Counter(MacroCounter::new()), 169 | ); 170 | map 171 | }, 172 | if_stack: Vec::new(), 173 | if_cache: Arc::new(IfCache::default()), 174 | include: IL::default(), 175 | buffer: None, 176 | } 177 | } 178 | } 179 | 180 | impl Context { 181 | pub fn new(include: IL) -> Self { 182 | Self { 183 | macros: HashMap::default(), 184 | if_stack: Vec::new(), 185 | if_cache: Arc::new(IfCache::default()), 186 | include, 187 | buffer: None, 188 | } 189 | } 190 | } 191 | 192 | impl PreprocContext for Context { 193 | fn add_if(&mut self, state: IfState) { 194 | self.if_stack.push(state); 195 | } 196 | 197 | fn rm_if(&mut self) { 198 | self.if_stack.pop(); 199 | } 200 | 201 | fn if_state(&self) -> Option<&IfState> { 202 | self.if_stack.last() 203 | } 204 | 205 | fn if_change(&mut self, state: IfState) { 206 | *self.if_stack.last_mut().unwrap() = state; 207 | } 208 | 209 | fn add_function(&mut self, name: String, mac: MacroFunction) { 210 | self.macros.insert(name, Macro::Function(mac)); 211 | } 212 | 213 | fn add_object(&mut self, name: String, mac: MacroObject) { 214 | self.macros.insert(name, Macro::Object(mac)); 215 | } 216 | 217 | fn undef(&mut self, name: &str) { 218 | self.macros.remove(name); 219 | } 220 | 221 | fn defined(&mut self, name: &str) -> bool { 222 | self.macros.contains_key(name) 223 | } 224 | 225 | fn get(&self, name: &str) -> Option<&Macro> { 226 | if let Some(mac) = self.macros.get(name) { 227 | match mac { 228 | Macro::Object(m) => { 229 | if m.in_use.get() { 230 | None 231 | } else { 232 | Some(mac) 233 | } 234 | } 235 | Macro::Function(m) => { 236 | if m.in_use.get() { 237 | None 238 | } else { 239 | Some(mac) 240 | } 241 | } 242 | Macro::Line(_) | Macro::File(_) | Macro::Counter(_) => Some(mac), 243 | } 244 | } else { 245 | None 246 | } 247 | } 248 | 249 | fn get_type(&self, name: &str) -> MacroType { 250 | if let Some(mac) = self.get(name) { 251 | match mac { 252 | Macro::Object(mac) => MacroType::Object(&mac), 253 | Macro::Function(mac) => MacroType::Function((mac.len(), mac.va_args)), 254 | Macro::Line(mac) => MacroType::Line(*mac), 255 | Macro::File(mac) => MacroType::File(*mac), 256 | Macro::Counter(mac) => MacroType::Counter(mac), 257 | } 258 | } else { 259 | MacroType::None 260 | } 261 | } 262 | 263 | fn skip_until_next(&self, file: FileId, pos: usize) -> Option { 264 | self.if_cache.get_next(file, pos) 265 | } 266 | 267 | fn save_switch(&self, file: FileId, pos: usize, next: Position) { 268 | self.if_cache.save_next(file, pos, next); 269 | } 270 | 271 | fn new_with_if_cache(if_cache: Arc) -> Self { 272 | Self { 273 | macros: HashMap::default(), 274 | if_stack: Vec::new(), 275 | if_cache, 276 | include: IL::default(), 277 | buffer: None, 278 | } 279 | } 280 | } 281 | 282 | impl IncludeLocator for Context { 283 | fn find( 284 | &mut self, 285 | angle: bool, 286 | path: &str, 287 | next: bool, 288 | current: FileId, 289 | path_index: PathIndex, 290 | ) -> Option { 291 | self.include.find(angle, path, next, current, path_index) 292 | } 293 | 294 | fn get_id(&mut self, path: &PathBuf) -> FileId { 295 | self.include.get_id(path) 296 | } 297 | 298 | fn get_path(&self, id: FileId) -> PathBuf { 299 | self.include.get_path(id) 300 | } 301 | 302 | fn set_source(&mut self, source: SourceMutex) { 303 | self.include.set_source(source); 304 | } 305 | 306 | fn set_sys_paths>(&mut self, paths: &[P]) { 307 | self.include.set_sys_paths(paths); 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /src/lexer/preprocessor/mod.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | pub mod context; 7 | pub use self::context::*; 8 | 9 | pub mod cache; 10 | pub mod include; 11 | pub mod macros; 12 | 13 | mod condition; 14 | mod macro_args; 15 | mod preprocessor; 16 | -------------------------------------------------------------------------------- /src/lexer/source.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use hashbrown::{hash_map, HashMap}; 7 | use std::path::PathBuf; 8 | use std::sync::{Arc, Mutex}; 9 | 10 | #[derive(Debug, Clone, Copy, Default, Hash, PartialEq)] 11 | pub struct FileId(pub u32); 12 | 13 | #[derive(Debug)] 14 | pub struct SourceLocator { 15 | file2id: HashMap, 16 | id2file: Vec, 17 | } 18 | 19 | impl Default for SourceLocator { 20 | fn default() -> Self { 21 | Self { 22 | file2id: { 23 | let mut map = HashMap::default(); 24 | map.insert(PathBuf::from(""), FileId(0)); 25 | map 26 | }, 27 | id2file: vec![PathBuf::from("")], 28 | } 29 | } 30 | } 31 | 32 | pub type SourceMutex = Arc>; 33 | 34 | pub fn get_source_mutex() -> SourceMutex { 35 | Arc::new(Mutex::new(SourceLocator::default())) 36 | } 37 | 38 | impl SourceLocator { 39 | pub fn get_id(&mut self, path: &PathBuf) -> FileId { 40 | match self.file2id.entry(path.clone()) { 41 | hash_map::Entry::Occupied(e) => *e.get(), 42 | hash_map::Entry::Vacant(p) => { 43 | let id = FileId(self.id2file.len() as u32); 44 | p.insert(id); 45 | self.id2file.push(path.clone()); 46 | id 47 | } 48 | } 49 | } 50 | 51 | pub fn get_path(&self, id: FileId) -> PathBuf { 52 | unsafe { self.id2file.get_unchecked(id.0 as usize).clone() } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/lexer/tools.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | pub fn extend_with_u64(buf: &mut Vec, n: u64) { 7 | // TODO: can be optimized using "Three Optimization Tips for C++" talk 8 | let mut n = n; 9 | let mut s = vec![0; 20]; 10 | let mut i = 19; 11 | loop { 12 | *s.get_mut(i).unwrap() = (n % 10) as u8 + b'0'; 13 | if n < 10 { 14 | break; 15 | } 16 | n /= 10; 17 | i -= 1; 18 | } 19 | 20 | buf.extend_from_slice(&s.get(i..).unwrap()); 21 | } 22 | 23 | pub fn extend_with_u32(buf: &mut Vec, n: u32) { 24 | // TODO: can be optimized using "Three Optimization Tips for C++" talk 25 | let mut n = n; 26 | let mut s = vec![0; 11]; 27 | let mut i = 10; 28 | loop { 29 | *s.get_mut(i).unwrap() = (n % 10) as u8 + b'0'; 30 | if n < 10 { 31 | break; 32 | } 33 | n /= 10; 34 | i -= 1; 35 | } 36 | 37 | buf.extend_from_slice(&s.get(i..).unwrap()); 38 | } 39 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | #![allow( 7 | // Currently WIP and some code might not end up used 8 | dead_code, 9 | clippy::cognitive_complexity, 10 | clippy::module_inception, 11 | )] 12 | 13 | #[macro_use] 14 | pub mod macros; 15 | pub use self::macros::*; 16 | 17 | pub mod args; 18 | pub mod defaults; 19 | pub mod errors; 20 | pub mod lexer; 21 | pub mod parser; 22 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | #[macro_export] 7 | macro_rules! node { 8 | ( $kind: ident $($toks:tt)*) => { 9 | ExprNode::$kind(Box::new($kind $( $toks )*)) 10 | }; 11 | } 12 | 13 | #[macro_export] 14 | macro_rules! skip_whites { 15 | ( $lexer: expr) => {{ 16 | loop { 17 | if $lexer.buf.has_char() { 18 | let c = $lexer.buf.next_char(); 19 | if c == b'\\' { 20 | if $lexer.buf.has_char_n(1) { 21 | let c = $lexer.buf.next_char_n(1); 22 | if c == b'\n' { 23 | $lexer.buf.add_new_line(); 24 | $lexer.buf.inc_n(2); 25 | continue; 26 | } 27 | } 28 | break; 29 | } 30 | if c != b' ' && c != b'\t' { 31 | break; 32 | } 33 | $lexer.buf.inc(); 34 | } else { 35 | break; 36 | } 37 | } 38 | }}; 39 | } 40 | 41 | #[macro_export] 42 | macro_rules! skip_whites_back { 43 | ( $lexer: expr) => {{ 44 | loop { 45 | let c = $lexer.buf.next_char(); 46 | if c != b' ' && c != b'\t' { 47 | break; 48 | } 49 | $lexer.buf.dec_n(1); 50 | } 51 | }}; 52 | } 53 | 54 | #[macro_export] 55 | macro_rules! skip_until { 56 | ( $lexer: expr, $char: expr ) => {{ 57 | loop { 58 | if $lexer.buf.has_char() { 59 | let c = $lexer.buf.next_char(); 60 | if c == $char { 61 | break; 62 | } 63 | $lexer.buf.inc(); 64 | } else { 65 | break; 66 | } 67 | } 68 | }}; 69 | } 70 | 71 | #[macro_export] 72 | macro_rules! color { 73 | ( $stdout: ident, $color: ident) => {{ 74 | use termcolor::WriteColor; 75 | 76 | $stdout 77 | .set_color(termcolor::ColorSpec::new().set_fg(Some(termcolor::Color::$color))) 78 | .unwrap(); 79 | }}; 80 | ( $stdout: ident, $color: ident, $intense: ident) => {{ 81 | use termcolor::WriteColor; 82 | 83 | $stdout 84 | .set_color( 85 | termcolor::ColorSpec::new() 86 | .set_fg(Some(termcolor::Color::$color)) 87 | .set_intense($intense), 88 | ) 89 | .unwrap(); 90 | }}; 91 | } 92 | 93 | #[macro_export] 94 | macro_rules! dump_start { 95 | ( $name: expr, $val: expr, $prefix: ident, $is_last: expr, $out: ident) => {{ 96 | use std::io::Write; 97 | 98 | let prefix = format!("{}{}", $prefix, Self::get_pref($is_last)); 99 | 100 | $crate::color!($out, Blue); 101 | write!($out, "{}", prefix).unwrap(); 102 | 103 | if !$name.is_empty() { 104 | $crate::color!($out, Yellow); 105 | write!($out, "{}: ", $name).unwrap(); 106 | } 107 | 108 | $crate::color!($out, Green); 109 | writeln!($out, "{}", $val).unwrap(); 110 | 111 | format!("{}{}", $prefix, Self::get_pref_child($is_last)) 112 | }}; 113 | } 114 | 115 | #[macro_export] 116 | macro_rules! dump_fields { 117 | ( $self: ident, $prefix: ident, $out: ident, $last: ident) => {{ 118 | $self.$last.dump(stringify!($last), &$prefix, true, $out); 119 | }}; 120 | 121 | ( $self: ident, $prefix: ident, $out: ident, $field: ident, $( $fields: ident ), *) => {{ 122 | $self.$field.dump(stringify!($field), &$prefix, false, $out); 123 | dump_fields!($self, $prefix, $out, $( $fields ),*); 124 | }}; 125 | } 126 | 127 | #[macro_export] 128 | macro_rules! dump_obj { 129 | ( $self: ident, $name: expr, $obj_name: expr, $prefix: ident, $is_last: expr, $out: ident, $( $fields: ident ), *) => {{ 130 | let prefix = $crate::dump_start!($name, $obj_name, $prefix, $is_last, $out); 131 | $crate::dump_fields!($self, prefix, $out, $( $fields ),*); 132 | }}; 133 | } 134 | 135 | #[macro_export] 136 | macro_rules! dump_vec { 137 | ( $name: expr, $vec: expr, $elem_name: expr, $prefix: ident, $is_last: expr, $out: ident ) => {{ 138 | let prefix = $crate::dump_start!($name, "", $prefix, $is_last, $out); 139 | let mut count = 1; 140 | 141 | if let Some((last, elems)) = $vec.split_last() { 142 | for e in elems.iter() { 143 | e.dump(&format!("{}{}", $elem_name, count), &prefix, false, $out); 144 | count += 1; 145 | } 146 | last.dump(&format!("{}{}", $elem_name, count), &prefix, true, $out); 147 | } 148 | }}; 149 | } 150 | 151 | #[macro_export] 152 | macro_rules! dump_str { 153 | ( $name: expr, $val: expr, $prefix: ident, $last: ident, $out: ident) => {{ 154 | dump_str!($name, $val, White, $prefix, $last, $out); 155 | }}; 156 | 157 | ( $name: expr, $val: expr, $color: ident, $prefix: ident, $last: ident, $out: ident) => {{ 158 | use std::io::Write; 159 | let prefix = format!("{}{}", $prefix, Self::get_pref($last)); 160 | 161 | $crate::color!($out, Blue); 162 | write!($out, "{}", prefix).unwrap(); 163 | 164 | $crate::color!($out, Yellow); 165 | 166 | if !$val.is_empty() { 167 | write!($out, "{}: ", $name).unwrap(); 168 | $crate::color!($out, $color); 169 | writeln!($out, "{}", $val).unwrap(); 170 | } else { 171 | writeln!($out, "{}", $name).unwrap(); 172 | } 173 | }}; 174 | } 175 | 176 | #[macro_export] 177 | macro_rules! bitflags_to_str { 178 | ( $self: ident, $name: ident, $( $field: ident, $value: expr ), *) => {{ 179 | let mut v = Vec::new(); 180 | $( 181 | if $self.contains($name::$field) { 182 | v.push($value); 183 | } 184 | )* 185 | v.join(" | ") 186 | }}; 187 | } 188 | -------------------------------------------------------------------------------- /src/parser/declarations/array.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use crate::lexer::{TLexer, Token}; 9 | use crate::parser::attributes::{Attributes, AttributesParser}; 10 | use crate::parser::dump::Dump; 11 | use crate::parser::errors::ParserError; 12 | use crate::parser::expressions::{ExprNode, ExpressionParser}; 13 | use crate::parser::types::Type; 14 | use crate::parser::Context; 15 | 16 | #[derive(Clone, Debug, PartialEq)] 17 | pub struct Dimension { 18 | pub size: Option, 19 | pub attributes: Option, 20 | } 21 | 22 | impl Dump for Dimension { 23 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 24 | dump_obj!(self, name, "", prefix, last, stdout, size, attributes); 25 | } 26 | } 27 | 28 | pub type Dimensions = Vec; 29 | 30 | impl Dump for Dimensions { 31 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 32 | dump_vec!(name, self, "dim", prefix, last, stdout); 33 | } 34 | } 35 | 36 | #[derive(Clone, Debug, PartialEq)] 37 | pub struct Array { 38 | pub base: Option, 39 | pub dimensions: Dimensions, 40 | } 41 | 42 | impl Dump for Array { 43 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 44 | dump_obj!(self, name, "array", prefix, last, stdout, base, dimensions); 45 | } 46 | } 47 | 48 | pub struct ArrayParser<'a, L: TLexer> { 49 | lexer: &'a mut L, 50 | } 51 | 52 | impl<'a, L: TLexer> ArrayParser<'a, L> { 53 | pub(super) fn new(lexer: &'a mut L) -> Self { 54 | Self { lexer } 55 | } 56 | 57 | pub(super) fn parse( 58 | self, 59 | tok: Option, 60 | context: &mut Context, 61 | ) -> Result<(Option, Option), ParserError> { 62 | let mut tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 63 | let mut dimensions = Vec::new(); 64 | 65 | loop { 66 | if tok != Token::LeftBrack { 67 | break; 68 | } 69 | 70 | let mut ep = ExpressionParser::new(self.lexer, Token::RightBrack); 71 | let (tk, size) = ep.parse(None, context)?; 72 | 73 | let tk = tk.unwrap_or_else(|| self.lexer.next_useful()); 74 | if tk != Token::RightBrack { 75 | return Err(ParserError::InvalidTokenInArraySize { 76 | sp: self.lexer.span(), 77 | tok, 78 | }); 79 | } 80 | 81 | let ap = AttributesParser::new(self.lexer); 82 | let (tk, attributes) = ap.parse(None, context)?; 83 | 84 | tok = tk.unwrap_or_else(|| self.lexer.next_useful()); 85 | 86 | dimensions.push(Dimension { size, attributes }); 87 | } 88 | 89 | Ok(if dimensions.is_empty() { 90 | (Some(tok), None) 91 | } else { 92 | ( 93 | Some(tok), 94 | Some(Array { 95 | base: None, 96 | dimensions, 97 | }), 98 | ) 99 | }) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/parser/declarations/asm.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use crate::lexer::{TLexer, Token}; 9 | use crate::parser::attributes::Attributes; 10 | use crate::parser::dump::Dump; 11 | use crate::parser::errors::ParserError; 12 | use crate::parser::literals::StringLiteralParser; 13 | use crate::parser::Context; 14 | 15 | #[derive(Clone, Debug, PartialEq)] 16 | pub struct Asm { 17 | pub attributes: Option, 18 | pub code: String, 19 | } 20 | 21 | impl Dump for Asm { 22 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 23 | dump_obj!(self, name, "asm", prefix, last, stdout, attributes); 24 | } 25 | } 26 | 27 | pub(crate) struct AsmParser<'a, L: TLexer> { 28 | lexer: &'a mut L, 29 | } 30 | 31 | impl<'a, L: TLexer> AsmParser<'a, L> { 32 | pub(crate) fn new(lexer: &'a mut L) -> Self { 33 | Self { lexer } 34 | } 35 | 36 | pub(crate) fn parse( 37 | self, 38 | tok: Option, 39 | context: &mut Context, 40 | ) -> Result<(Option, Option), ParserError> { 41 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 42 | if tok != Token::Asm { 43 | return Ok((Some(tok), None)); 44 | } 45 | 46 | let tok = self.lexer.next_useful(); 47 | if tok != Token::LeftParen { 48 | return Err(ParserError::InvalidTokenInAsm { 49 | sp: self.lexer.span(), 50 | tok, 51 | }); 52 | } 53 | 54 | let tok = self.lexer.next_useful(); 55 | 56 | if let Some(code) = tok.get_string() { 57 | // TODO: add an asm lexer & parser 58 | let slp = StringLiteralParser::new(self.lexer); 59 | let (tok, code) = slp.parse(&code, context)?; 60 | 61 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 62 | if tok != Token::RightParen { 63 | return Err(ParserError::InvalidTokenInAsm { 64 | sp: self.lexer.span(), 65 | tok, 66 | }); 67 | } 68 | 69 | Ok(( 70 | None, 71 | Some(Asm { 72 | attributes: None, 73 | code, 74 | }), 75 | )) 76 | } else { 77 | Err(ParserError::InvalidTokenInAsm { 78 | sp: self.lexer.span(), 79 | tok: Token::None, 80 | }) 81 | } 82 | } 83 | } 84 | 85 | #[cfg(test)] 86 | mod tests { 87 | 88 | use super::*; 89 | use crate::lexer::{preprocessor::context::DefaultContext, Lexer}; 90 | use pretty_assertions::assert_eq; 91 | 92 | #[test] 93 | fn test_asm() { 94 | let mut l = Lexer::::new( 95 | r#" 96 | asm(R"( 97 | .globl func 98 | .type func, @function 99 | func: 100 | .cfi_startproc 101 | movl $7, %eax 102 | ret 103 | .cfi_endproc 104 | )") 105 | "# 106 | .as_bytes(), 107 | ); 108 | let p = AsmParser::new(&mut l); 109 | let mut context = Context::default(); 110 | let (_, u) = p.parse(None, &mut context).unwrap(); 111 | 112 | let code = r#" 113 | .globl func 114 | .type func, @function 115 | func: 116 | .cfi_startproc 117 | movl $7, %eax 118 | ret 119 | .cfi_endproc 120 | "#; 121 | 122 | assert_eq!( 123 | u.unwrap(), 124 | Asm { 125 | attributes: None, 126 | code: code.to_string(), 127 | } 128 | ); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/parser/declarations/bitfield.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use super::TypeDeclarator; 7 | use crate::lexer::{TLexer, Token}; 8 | use crate::parser::errors::ParserError; 9 | use crate::parser::expressions::Operator; 10 | use crate::parser::expressions::{ExprNode, ExpressionParser}; 11 | use crate::parser::initializer::Initializer; 12 | use crate::parser::Context; 13 | 14 | pub struct BitFieldDeclaratorParser<'a, L: TLexer> { 15 | lexer: &'a mut L, 16 | } 17 | 18 | impl<'a, L: TLexer> BitFieldDeclaratorParser<'a, L> { 19 | pub(super) fn new(lexer: &'a mut L) -> Self { 20 | Self { lexer } 21 | } 22 | 23 | pub(super) fn parse( 24 | self, 25 | tok: Option, 26 | typ: &mut TypeDeclarator, 27 | context: &mut Context, 28 | ) -> Result, ParserError> { 29 | let mut ep = ExpressionParser::new(self.lexer, Token::Comma); 30 | let (tok, size) = ep.parse(tok, context)?; 31 | 32 | let size = if let Some(size) = size { 33 | size 34 | } else { 35 | return Err(ParserError::InvalidBitfieldSize { 36 | sp: self.lexer.span(), 37 | }); 38 | }; 39 | 40 | let (size, init) = match size { 41 | ExprNode::BinaryOp(operation) => { 42 | if operation.op == Operator::Assign { 43 | (operation.arg1, Some(Initializer::Equal(operation.arg2))) 44 | } else { 45 | (ExprNode::BinaryOp(operation), None) 46 | } 47 | } 48 | ExprNode::InitExpr(init) => (init.base, Some(Initializer::Brace(init.list))), 49 | _ => (size, None), 50 | }; 51 | 52 | typ.init = init; 53 | typ.bitfield_size = Some(size); 54 | 55 | Ok(tok) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/parser/declarations/decl.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use std::rc::Rc; 7 | use termcolor::StandardStreamLock; 8 | 9 | use super::types::{DeclHint, TypeDeclarator, TypeDeclaratorParser}; 10 | use super::{ 11 | Asm, AsmParser, Extern, ExternParser, Namespace, NamespaceAlias, NamespaceParser, StaticAssert, 12 | StaticAssertParser, UsingAlias, UsingDecl, UsingEnum, UsingNS, UsingParser, 13 | }; 14 | use crate::check_semicolon; 15 | 16 | use crate::lexer::{TLexer, Token}; 17 | use crate::parser::attributes::{Attributes, AttributesParser}; 18 | use crate::parser::dump::Dump; 19 | use crate::parser::errors::ParserError; 20 | use crate::parser::Context; 21 | 22 | #[derive(Clone, Debug, PartialEq)] 23 | pub enum Declaration { 24 | Type(Rc), 25 | Extern(Extern), 26 | Namespace(Namespace), 27 | NamespaceAlias(NamespaceAlias), 28 | StaticAssert(StaticAssert), 29 | Asm(Asm), 30 | Attributes(Attributes), 31 | UsingDecl(UsingDecl), 32 | UsingEnum(UsingEnum), 33 | UsingNS(UsingNS), 34 | UsingAlias(UsingAlias), 35 | Empty, 36 | } 37 | 38 | impl Dump for Declaration { 39 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 40 | macro_rules! dump { 41 | ( $x: ident) => { 42 | $x.dump(name, prefix, last, stdout) 43 | }; 44 | } 45 | 46 | match self { 47 | Self::Type(x) => dump!(x), 48 | Self::Extern(x) => dump!(x), 49 | Self::Namespace(x) => dump!(x), 50 | Self::NamespaceAlias(x) => dump!(x), 51 | Self::StaticAssert(x) => dump!(x), 52 | Self::Asm(x) => dump!(x), 53 | Self::Attributes(x) => dump!(x), 54 | Self::UsingDecl(x) => dump!(x), 55 | Self::UsingEnum(x) => dump!(x), 56 | Self::UsingNS(x) => dump!(x), 57 | Self::UsingAlias(x) => dump!(x), 58 | Self::Empty => dump_str!(name, "empty", Cyan, prefix, last, stdout), 59 | } 60 | } 61 | } 62 | 63 | pub type Declarations = Vec; 64 | 65 | impl Dump for Declarations { 66 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 67 | dump_vec!(name, self, "dec", prefix, last, stdout); 68 | } 69 | } 70 | 71 | impl Declaration { 72 | pub(crate) fn has_semicolon(&self) -> bool { 73 | match self { 74 | Self::Type(d) => d.has_semicolon(), 75 | Self::Extern(e) => !e.multiple, 76 | Self::Namespace(_) => false, 77 | _ => true, 78 | } 79 | } 80 | } 81 | 82 | pub(crate) struct DeclarationParser<'a, L: TLexer> { 83 | lexer: &'a mut L, 84 | } 85 | 86 | impl<'a, L: TLexer> DeclarationParser<'a, L> { 87 | pub(crate) fn new(lexer: &'a mut L) -> Self { 88 | Self { lexer } 89 | } 90 | 91 | pub(crate) fn parse( 92 | self, 93 | tok: Option, 94 | hint: Option, // TODO: remove hint 95 | context: &mut Context, 96 | ) -> Result<(Option, Option), ParserError> { 97 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 98 | if tok == Token::SemiColon { 99 | return Ok((None, Some(Declaration::Empty))); 100 | } 101 | let tok = Some(tok); 102 | 103 | let ep = ExternParser::new(self.lexer); 104 | let (tok, decl) = ep.parse(tok, context)?; 105 | 106 | if decl.is_some() { 107 | return Ok((tok, decl)); 108 | } 109 | 110 | let np = NamespaceParser::new(self.lexer); 111 | let (tok, decl) = np.parse(tok, context)?; 112 | 113 | if decl.is_some() { 114 | return Ok((tok, decl)); 115 | } 116 | 117 | let sap = StaticAssertParser::new(self.lexer); 118 | let (tok, sa) = sap.parse(tok, context)?; 119 | 120 | if let Some(sa) = sa { 121 | return Ok((tok, Some(Declaration::StaticAssert(sa)))); 122 | } 123 | 124 | let ap = AttributesParser::new(self.lexer); 125 | let (tok, mut attrs) = ap.parse(tok, context)?; 126 | 127 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 128 | if tok == Token::SemiColon { 129 | return Ok((None, Some(Declaration::Attributes(attrs.unwrap())))); 130 | } 131 | let tok = Some(tok); 132 | 133 | let ap = AsmParser::new(self.lexer); 134 | let (tok, asm) = ap.parse(tok, context)?; 135 | 136 | if let Some(mut asm) = asm { 137 | asm.attributes = attrs; 138 | return Ok((tok, Some(Declaration::Asm(asm)))); 139 | } 140 | 141 | let up = UsingParser::new(self.lexer); 142 | let (tok, using) = up.parse(tok, context)?; 143 | 144 | if let Some(mut using) = using { 145 | if let Declaration::UsingNS(ref mut u) = using { 146 | std::mem::swap(&mut u.attributes, &mut attrs); 147 | } 148 | return Ok((tok, Some(using))); 149 | } 150 | 151 | let tdp = TypeDeclaratorParser::new(self.lexer); 152 | let (tok, decl) = tdp.parse(tok, hint, true, context)?; 153 | 154 | let decl = if let Some(decl) = decl { 155 | context.add_type_decl(Rc::clone(&decl)); 156 | Some(Declaration::Type(decl)) 157 | } else { 158 | None 159 | }; 160 | 161 | Ok((tok, decl)) 162 | } 163 | } 164 | 165 | pub struct DeclarationListParser<'a, L: TLexer> { 166 | lexer: &'a mut L, 167 | } 168 | 169 | impl<'a, L: TLexer> DeclarationListParser<'a, L> { 170 | pub(crate) fn new(lexer: &'a mut L) -> Self { 171 | Self { lexer } 172 | } 173 | 174 | pub(crate) fn parse( 175 | self, 176 | tok: Option, 177 | context: &mut Context, 178 | ) -> Result<(Option, Option), ParserError> { 179 | let mut tok = tok; 180 | let mut list = Vec::new(); 181 | 182 | loop { 183 | let dp = DeclarationParser::new(self.lexer); 184 | let (tk, decl) = dp.parse(tok, None, context)?; 185 | 186 | tok = if let Some(decl) = decl { 187 | let tk = if decl.has_semicolon() { 188 | check_semicolon!(self, tk); 189 | None 190 | } else { 191 | tk 192 | }; 193 | list.push(decl); 194 | tk 195 | } else { 196 | return Ok((tk, Some(list))); 197 | }; 198 | } 199 | } 200 | } 201 | 202 | #[cfg(test)] 203 | mod tests { 204 | 205 | /*use super::super::function::*; 206 | use super::*; 207 | use crate::lexer::preprocessor::context::DefaultContext; 208 | use crate::parser::array::*; 209 | use crate::parser::attributes::Attribute; 210 | use crate::parser::declarations::pointer::*; 211 | use crate::parser::declarations::r#enum::*; 212 | use crate::parser::expressions::{self, *}; 213 | use crate::parser::literals::{self, *}; 214 | use crate::parser::names::{self, operator, Name}; 215 | use crate::parser::types::Primitive; 216 | use pretty_assertions::assert_eq; 217 | 218 | #[test] 219 | fn test_decl() {}*/ 220 | } 221 | -------------------------------------------------------------------------------- /src/parser/declarations/extern.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use std::rc::Rc; 7 | use termcolor::StandardStreamLock; 8 | 9 | use super::{ 10 | DeclHint, Declaration, DeclarationListParser, Declarations, Specifier, TypeDeclaratorParser, 11 | }; 12 | use crate::lexer::lexer::{TLexer, Token}; 13 | use crate::parser::dump::Dump; 14 | use crate::parser::errors::ParserError; 15 | use crate::parser::Context; 16 | 17 | #[derive(Clone, Debug, PartialEq)] 18 | pub struct Extern { 19 | pub language: String, 20 | pub decls: Declarations, 21 | pub multiple: bool, 22 | } 23 | 24 | impl Dump for Extern { 25 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 26 | dump_obj!(self, name, "extern", prefix, last, stdout, language, decls, multiple); 27 | } 28 | } 29 | 30 | pub(crate) struct ExternParser<'a, L: TLexer> { 31 | lexer: &'a mut L, 32 | } 33 | 34 | impl<'a, L: TLexer> ExternParser<'a, L> { 35 | pub(super) fn new(lexer: &'a mut L) -> Self { 36 | Self { lexer } 37 | } 38 | 39 | pub(super) fn parse( 40 | self, 41 | tok: Option, 42 | context: &mut Context, 43 | ) -> Result<(Option, Option), ParserError> { 44 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 45 | if tok != Token::Extern { 46 | return Ok((Some(tok), None)); 47 | } 48 | 49 | let tok = self.lexer.next_useful(); 50 | 51 | if let Token::LiteralString(language) = tok { 52 | let tok = self.lexer.next_useful(); 53 | let has_brace = tok == Token::LeftBrace; 54 | let dlp = DeclarationListParser::new(self.lexer); 55 | 56 | let (tok, list) = dlp.parse(None, context)?; 57 | 58 | if has_brace { 59 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 60 | if tok == Token::RightBrace { 61 | Ok(( 62 | None, 63 | Some(Declaration::Extern(Extern { 64 | language, 65 | decls: list.unwrap(), 66 | multiple: true, 67 | })), 68 | )) 69 | } else { 70 | Err(ParserError::InvalidTokenInExtern { 71 | sp: self.lexer.span(), 72 | tok, 73 | }) 74 | } 75 | } else { 76 | Ok(( 77 | tok, 78 | Some(Declaration::Extern(Extern { 79 | language, 80 | decls: list.unwrap(), 81 | multiple: false, 82 | })), 83 | )) 84 | } 85 | } else { 86 | let tdp = TypeDeclaratorParser::new(self.lexer); 87 | let hint = DeclHint::Specifier(Specifier::EXTERN); 88 | let (tok, typ) = tdp.parse(Some(tok), Some(hint), true, context)?; 89 | let typ = typ.unwrap(); 90 | context.add_type_decl(Rc::clone(&typ)); 91 | 92 | Ok((tok, Some(Declaration::Type(typ)))) 93 | } 94 | } 95 | } 96 | 97 | #[cfg(test)] 98 | mod tests { 99 | 100 | use std::cell::RefCell; 101 | use std::rc::Rc; 102 | 103 | use super::*; 104 | use crate::lexer::{preprocessor::context::DefaultContext, Lexer}; 105 | use crate::parser::declarations::{types, *}; 106 | use crate::parser::names::*; 107 | use crate::parser::types::*; 108 | use pretty_assertions::assert_eq; 109 | 110 | #[test] 111 | fn test_extern_c() { 112 | let mut l = Lexer::::new( 113 | br#" 114 | extern "C" { 115 | double sqrt(double); 116 | } 117 | "#, 118 | ); 119 | let p = ExternParser::new(&mut l); 120 | let mut context = Context::default(); 121 | let (_, ext) = p.parse(None, &mut context).unwrap(); 122 | 123 | let ext = ext.unwrap(); 124 | 125 | assert_eq!( 126 | ext, 127 | Declaration::Extern(Extern { 128 | language: "C".to_string(), 129 | decls: vec![Declaration::Type(Rc::new(TypeDeclarator { 130 | typ: Type { 131 | base: BaseType::Function(Box::new(Function { 132 | return_type: Some(Type { 133 | base: BaseType::Primitive(Primitive::Double), 134 | cv: CVQualifier::empty(), 135 | pointers: None, 136 | }), 137 | params: vec![Parameter { 138 | attributes: None, 139 | decl: Rc::new(TypeDeclarator { 140 | typ: Type { 141 | base: BaseType::Primitive(Primitive::Double), 142 | cv: CVQualifier::empty(), 143 | pointers: None, 144 | }, 145 | specifier: Specifier::empty(), 146 | identifier: types::Identifier { 147 | identifier: None, 148 | attributes: None 149 | }, 150 | init: None, 151 | bitfield_size: None, 152 | }), 153 | }], 154 | cv: CVQualifier::empty(), 155 | refq: RefQualifier::None, 156 | except: None, 157 | attributes: None, 158 | trailing: None, 159 | virt_specifier: VirtSpecifier::empty(), 160 | status: FunStatus::None, 161 | requires: None, 162 | ctor_init: None, 163 | body: RefCell::new(None) 164 | })), 165 | cv: CVQualifier::empty(), 166 | pointers: None, 167 | }, 168 | specifier: Specifier::empty(), 169 | identifier: types::Identifier { 170 | identifier: Some(mk_id!("sqrt")), 171 | attributes: None 172 | }, 173 | init: None, 174 | bitfield_size: None, 175 | }))], 176 | multiple: true, 177 | }) 178 | ); 179 | } 180 | 181 | #[test] 182 | fn test_extern_decl() { 183 | let mut l = Lexer::::new( 184 | br#" 185 | extern double sqrt(double); 186 | "#, 187 | ); 188 | let p = ExternParser::new(&mut l); 189 | let mut context = Context::default(); 190 | let (_, ext) = p.parse(None, &mut context).unwrap(); 191 | 192 | let ext = ext.unwrap(); 193 | 194 | assert_eq!( 195 | ext, 196 | Declaration::Type(Rc::new(TypeDeclarator { 197 | typ: Type { 198 | base: BaseType::Function(Box::new(Function { 199 | return_type: Some(Type { 200 | base: BaseType::Primitive(Primitive::Double), 201 | cv: CVQualifier::empty(), 202 | pointers: None, 203 | }), 204 | params: vec![Parameter { 205 | attributes: None, 206 | decl: Rc::new(TypeDeclarator { 207 | typ: Type { 208 | base: BaseType::Primitive(Primitive::Double), 209 | cv: CVQualifier::empty(), 210 | pointers: None, 211 | }, 212 | specifier: Specifier::empty(), 213 | identifier: types::Identifier { 214 | identifier: None, 215 | attributes: None 216 | }, 217 | init: None, 218 | bitfield_size: None, 219 | }), 220 | }], 221 | cv: CVQualifier::empty(), 222 | refq: RefQualifier::None, 223 | except: None, 224 | attributes: None, 225 | trailing: None, 226 | virt_specifier: VirtSpecifier::empty(), 227 | status: FunStatus::None, 228 | requires: None, 229 | ctor_init: None, 230 | body: RefCell::new(None) 231 | })), 232 | cv: CVQualifier::empty(), 233 | pointers: None, 234 | }, 235 | specifier: Specifier::EXTERN, 236 | identifier: types::Identifier { 237 | identifier: Some(mk_id!("sqrt")), 238 | attributes: None 239 | }, 240 | init: None, 241 | bitfield_size: None, 242 | })) 243 | ); 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /src/parser/declarations/member.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use std::rc::Rc; 7 | use termcolor::StandardStreamLock; 8 | 9 | use super::bitfield::BitFieldDeclaratorParser; 10 | use super::{StaticAssert, StaticAssertParser, UsingAlias, UsingDecl, UsingEnum, UsingParser}; 11 | use crate::lexer::{TLexer, Token}; 12 | use crate::parser::declarations::{Declaration, TypeDeclarator, TypeDeclaratorParser}; 13 | use crate::parser::dump::Dump; 14 | use crate::parser::errors::ParserError; 15 | use crate::parser::Context; 16 | 17 | #[derive(Clone, Debug, PartialEq)] 18 | pub enum Member { 19 | Type(Rc), 20 | StaticAssert(StaticAssert), 21 | UsingDecl(UsingDecl), 22 | UsingEnum(UsingEnum), 23 | UsingAlias(UsingAlias), 24 | Empty, 25 | } 26 | 27 | impl Member { 28 | pub(crate) fn has_semicolon(&self) -> bool { 29 | match self { 30 | Self::Type(d) => d.has_semicolon(), 31 | _ => true, 32 | } 33 | } 34 | } 35 | 36 | impl Dump for Member { 37 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 38 | macro_rules! dump { 39 | ( $x: ident ) => { 40 | $x.dump(name, prefix, last, stdout) 41 | }; 42 | } 43 | 44 | match self { 45 | Self::Type(x) => dump!(x), 46 | Self::StaticAssert(x) => dump!(x), 47 | Self::UsingDecl(x) => dump!(x), 48 | Self::UsingEnum(x) => dump!(x), 49 | Self::UsingAlias(x) => dump!(x), 50 | Self::Empty => dump_str!(name, "empty", Cyan, prefix, last, stdout), 51 | } 52 | } 53 | } 54 | 55 | pub type Members = Vec; 56 | 57 | impl Dump for Members { 58 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 59 | dump_vec!(name, self, "mem", prefix, last, stdout); 60 | } 61 | } 62 | 63 | #[derive(Clone, Debug, PartialEq)] 64 | pub(super) enum Visibility { 65 | Public, 66 | Protected, 67 | Private, 68 | } 69 | 70 | #[derive(Clone, Debug, PartialEq)] 71 | #[allow(clippy::large_enum_variant)] 72 | pub(super) enum MemberRes { 73 | Vis(Visibility), 74 | Decl(Member), 75 | } 76 | 77 | pub struct MemberParser<'a, L: TLexer> { 78 | lexer: &'a mut L, 79 | } 80 | 81 | impl<'a, L: TLexer> MemberParser<'a, L> { 82 | pub(super) fn new(lexer: &'a mut L) -> Self { 83 | Self { lexer } 84 | } 85 | 86 | pub(super) fn parse( 87 | self, 88 | tok: Option, 89 | context: &mut Context, 90 | ) -> Result<(Option, Option), ParserError> { 91 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 92 | if tok == Token::SemiColon { 93 | return Ok((None, Some(MemberRes::Decl(Member::Empty)))); 94 | } 95 | let tok = Some(tok); 96 | 97 | let pppp = PPPParser::new(self.lexer); 98 | let (tok, vis) = pppp.parse(tok, context)?; 99 | 100 | if let Some(vis) = vis { 101 | return Ok((tok, Some(MemberRes::Vis(vis)))); 102 | } 103 | 104 | let sap = StaticAssertParser::new(self.lexer); 105 | let (tok, sa) = sap.parse(tok, context)?; 106 | 107 | if let Some(sa) = sa { 108 | return Ok((tok, Some(MemberRes::Decl(Member::StaticAssert(sa))))); 109 | } 110 | 111 | let up = UsingParser::new(self.lexer); 112 | let (tok, using) = up.parse(tok, context)?; 113 | 114 | if let Some(using) = using { 115 | let using = match using { 116 | Declaration::UsingDecl(d) => Member::UsingDecl(d), 117 | Declaration::UsingEnum(d) => Member::UsingEnum(d), 118 | Declaration::UsingAlias(d) => Member::UsingAlias(d), 119 | _ => { 120 | return Err(ParserError::InvalidTokenInClass { 121 | sp: self.lexer.span(), 122 | tok: tok.unwrap(), 123 | }); 124 | } 125 | }; 126 | 127 | return Ok((tok, Some(MemberRes::Decl(using)))); 128 | } 129 | 130 | let tdp = TypeDeclaratorParser::new(self.lexer); 131 | let (tok, typ) = tdp.parse(tok, None, true, context)?; 132 | 133 | let mut typ = if let Some(typ) = typ { 134 | typ 135 | } else { 136 | return Ok((tok, None)); 137 | }; 138 | 139 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 140 | let tok = if tok == Token::Colon { 141 | // we've a bitfield 142 | let bfdp = BitFieldDeclaratorParser::new(self.lexer); 143 | let tok = bfdp.parse(None, Rc::get_mut(&mut typ).unwrap(), context)?; 144 | tok 145 | } else { 146 | Some(tok) 147 | }; 148 | 149 | context.add_type_decl(Rc::clone(&typ)); 150 | 151 | Ok((tok, Some(MemberRes::Decl(Member::Type(typ))))) 152 | } 153 | } 154 | 155 | struct PPPParser<'a, L: TLexer> { 156 | lexer: &'a mut L, 157 | } 158 | 159 | impl<'a, L: TLexer> PPPParser<'a, L> { 160 | fn new(lexer: &'a mut L) -> Self { 161 | Self { lexer } 162 | } 163 | 164 | fn parse( 165 | self, 166 | tok: Option, 167 | _context: &mut Context, 168 | ) -> Result<(Option, Option), ParserError> { 169 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 170 | let visibility = match tok { 171 | Token::Public => Visibility::Public, 172 | Token::Protected => Visibility::Protected, 173 | Token::Private => Visibility::Private, 174 | _ => { 175 | return Ok((Some(tok), None)); 176 | } 177 | }; 178 | 179 | let tok = self.lexer.next_useful(); 180 | if tok != Token::Colon { 181 | return Err(ParserError::InvalidTokenInClass { 182 | sp: self.lexer.span(), 183 | tok, 184 | }); 185 | } 186 | 187 | Ok((None, Some(visibility))) 188 | } 189 | } 190 | 191 | #[cfg(test)] 192 | mod tests { 193 | 194 | use super::*; 195 | use crate::lexer::{preprocessor::context::DefaultContext, Lexer}; 196 | use crate::parser::declarations::{Identifier, Specifier}; 197 | use crate::parser::expressions::*; 198 | use crate::parser::initializer::Initializer; 199 | use crate::parser::literals::*; 200 | use crate::parser::names::*; 201 | use crate::parser::types::*; 202 | use pretty_assertions::assert_eq; 203 | 204 | #[test] 205 | fn test_member_public() { 206 | let mut l = Lexer::::new(b"public:"); 207 | let p = MemberParser::new(&mut l); 208 | let mut context = Context::default(); 209 | let (_, m) = p.parse(None, &mut context).unwrap(); 210 | let v = if let MemberRes::Vis(v) = m.unwrap() { 211 | v 212 | } else { 213 | assert!(false); 214 | return; 215 | }; 216 | 217 | assert_eq!(v, Visibility::Public); 218 | } 219 | 220 | #[test] 221 | fn test_member_bitfield() { 222 | let mut l = Lexer::::new(b"int x : 4"); 223 | let p = MemberParser::new(&mut l); 224 | let mut context = Context::default(); 225 | let (_, m) = p.parse(None, &mut context).unwrap(); 226 | let d = if let MemberRes::Decl(d) = m.unwrap() { 227 | d 228 | } else { 229 | assert!(false); 230 | return; 231 | }; 232 | 233 | assert_eq!( 234 | d, 235 | Member::Type(Rc::new(TypeDeclarator { 236 | typ: Type { 237 | base: BaseType::Primitive(Primitive::Int), 238 | cv: CVQualifier::empty(), 239 | pointers: None, 240 | }, 241 | specifier: Specifier::empty(), 242 | identifier: Identifier { 243 | identifier: Some(mk_id!("x")), 244 | attributes: None 245 | }, 246 | init: None, 247 | bitfield_size: Some(ExprNode::Integer(Box::new(Integer { 248 | value: IntLiteral::Int(4) 249 | }))), 250 | })) 251 | ); 252 | } 253 | 254 | #[test] 255 | fn test_member_bitfield_equal() { 256 | let mut l = Lexer::::new(b"int x : 4 = 1"); 257 | let p = MemberParser::new(&mut l); 258 | let mut context = Context::default(); 259 | let (_, m) = p.parse(None, &mut context).unwrap(); 260 | let d = if let MemberRes::Decl(d) = m.unwrap() { 261 | d 262 | } else { 263 | assert!(false); 264 | return; 265 | }; 266 | 267 | assert_eq!( 268 | d, 269 | Member::Type(Rc::new(TypeDeclarator { 270 | typ: Type { 271 | base: BaseType::Primitive(Primitive::Int), 272 | cv: CVQualifier::empty(), 273 | pointers: None, 274 | }, 275 | specifier: Specifier::empty(), 276 | identifier: Identifier { 277 | identifier: Some(mk_id!("x")), 278 | attributes: None 279 | }, 280 | init: Some(Initializer::Equal(ExprNode::Integer(Box::new(Integer { 281 | value: IntLiteral::Int(1) 282 | })))), 283 | bitfield_size: Some(ExprNode::Integer(Box::new(Integer { 284 | value: IntLiteral::Int(4) 285 | }))), 286 | })) 287 | ); 288 | } 289 | 290 | #[test] 291 | fn test_member_bitfield_brace() { 292 | let mut l = Lexer::::new(b"int x : 4 {1}"); 293 | let p = MemberParser::new(&mut l); 294 | let mut context = Context::default(); 295 | let (_, m) = p.parse(None, &mut context).unwrap(); 296 | let d = if let MemberRes::Decl(d) = m.unwrap() { 297 | d 298 | } else { 299 | assert!(false); 300 | return; 301 | }; 302 | 303 | assert_eq!( 304 | d, 305 | Member::Type(Rc::new(TypeDeclarator { 306 | typ: Type { 307 | base: BaseType::Primitive(Primitive::Int), 308 | cv: CVQualifier::empty(), 309 | pointers: None, 310 | }, 311 | specifier: Specifier::empty(), 312 | identifier: Identifier { 313 | identifier: Some(mk_id!("x")), 314 | attributes: None 315 | }, 316 | init: Some(Initializer::Brace(vec![ExprNode::Integer(Box::new( 317 | Integer { 318 | value: IntLiteral::Int(1) 319 | } 320 | )),])), 321 | bitfield_size: Some(ExprNode::Integer(Box::new(Integer { 322 | value: IntLiteral::Int(4) 323 | }))), 324 | })) 325 | ); 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /src/parser/declarations/mod.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | pub mod decl; 7 | pub use self::decl::*; 8 | 9 | pub mod types; 10 | pub use self::types::*; 11 | 12 | pub mod specifier; 13 | pub use self::specifier::*; 14 | 15 | pub mod pointer; 16 | pub use self::pointer::*; 17 | 18 | pub mod function; 19 | pub use self::function::*; 20 | 21 | pub mod array; 22 | pub use self::array::*; 23 | 24 | pub mod r#enum; 25 | pub use self::r#enum::*; 26 | 27 | pub mod member; 28 | pub use self::member::*; 29 | 30 | pub mod bitfield; 31 | pub use self::bitfield::*; 32 | 33 | mod using; 34 | pub use self::using::*; 35 | 36 | mod static_assert; 37 | pub use self::static_assert::*; 38 | 39 | mod asm; 40 | pub use self::asm::*; 41 | 42 | pub mod namespace; 43 | pub use self::namespace::*; 44 | 45 | pub mod r#extern; 46 | pub use self::r#extern::*; 47 | 48 | mod class; 49 | pub use self::class::*; 50 | -------------------------------------------------------------------------------- /src/parser/declarations/pointer.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use bitflags::bitflags; 7 | use termcolor::StandardStreamLock; 8 | 9 | use super::super::types::CVQualifier; 10 | use super::specifier::Specifier; 11 | use super::types::{NoPtrDeclaratorParser, TypeDeclarator}; 12 | use crate::lexer::{TLexer, Token}; 13 | use crate::parser::attributes::{Attributes, AttributesParser}; 14 | use crate::parser::dump::Dump; 15 | use crate::parser::errors::ParserError; 16 | use crate::parser::types::{BaseType, Type}; 17 | use crate::parser::Context; 18 | 19 | bitflags! { 20 | pub struct MSModifier: u8 { 21 | const RESTRICT = 0b1; 22 | const UPTR = 0b10; 23 | const SPTR = 0b100; 24 | const UNALIGNED = 0b1000; 25 | } 26 | } 27 | 28 | impl ToString for MSModifier { 29 | fn to_string(&self) -> String { 30 | let mut vec = Vec::with_capacity(1); 31 | if self.contains(Self::RESTRICT) { 32 | vec.push("__restrict"); 33 | } 34 | if self.contains(Self::UPTR) { 35 | vec.push("__uptr"); 36 | } 37 | if self.contains(Self::SPTR) { 38 | vec.push("__sptr"); 39 | } 40 | if self.contains(Self::UNALIGNED) { 41 | vec.push("__unaligned"); 42 | } 43 | vec.join(" | ") 44 | } 45 | } 46 | 47 | impl Dump for MSModifier { 48 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 49 | dump_str!(name, self.to_string(), Cyan, prefix, last, stdout); 50 | } 51 | } 52 | 53 | impl MSModifier { 54 | pub(crate) fn from_tok(&mut self, tok: &Token) -> bool { 55 | match tok { 56 | Token::MSRestrict => { 57 | *self |= Self::RESTRICT; 58 | true 59 | } 60 | Token::MSUptr => { 61 | *self |= Self::UPTR; 62 | true 63 | } 64 | Token::MSSptr => { 65 | *self |= Self::SPTR; 66 | true 67 | } 68 | Token::MSUnaligned | Token::MS1Unaligned => { 69 | *self |= Self::UNALIGNED; 70 | true 71 | } 72 | _ => false, 73 | } 74 | } 75 | } 76 | 77 | #[derive(Clone, Debug, PartialEq, Hash)] 78 | pub enum PtrKind { 79 | Pointer, 80 | Reference, 81 | RValue, 82 | } 83 | 84 | impl ToString for PtrKind { 85 | fn to_string(&self) -> String { 86 | match self { 87 | Self::Pointer => "*".to_string(), 88 | Self::Reference => "&".to_string(), 89 | Self::RValue => "&&".to_string(), 90 | } 91 | } 92 | } 93 | 94 | impl Dump for PtrKind { 95 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 96 | dump_str!(name, self.to_string(), Cyan, prefix, last, stdout); 97 | } 98 | } 99 | 100 | impl PtrKind { 101 | pub(crate) fn from_tok(tok: &Token) -> Option { 102 | match tok { 103 | Token::Star => Some(PtrKind::Pointer), 104 | Token::And => Some(PtrKind::Reference), 105 | Token::AndAnd => Some(PtrKind::RValue), 106 | _ => None, 107 | } 108 | } 109 | 110 | pub(crate) fn is_ptr(tok: &Token) -> bool { 111 | match tok { 112 | Token::Star | Token::And | Token::AndAnd => true, 113 | _ => false, 114 | } 115 | } 116 | } 117 | 118 | #[derive(Clone, Debug, PartialEq, Hash)] 119 | pub struct Pointer { 120 | pub kind: PtrKind, 121 | pub attributes: Option, 122 | pub cv: CVQualifier, 123 | pub ms: MSModifier, 124 | } 125 | 126 | impl Dump for Pointer { 127 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 128 | dump_obj!(self, name, "", prefix, last, stdout, kind, attributes, cv, ms); 129 | } 130 | } 131 | 132 | pub type Pointers = Vec; 133 | 134 | impl Dump for Pointers { 135 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 136 | dump_vec!(name, self, "ptr", prefix, last, stdout); 137 | } 138 | } 139 | 140 | pub struct PointerDeclaratorParser<'a, L: TLexer> { 141 | lexer: &'a mut L, 142 | } 143 | 144 | impl<'a, L: TLexer> PointerDeclaratorParser<'a, L> { 145 | pub(crate) fn new(lexer: &'a mut L) -> Self { 146 | Self { lexer } 147 | } 148 | 149 | pub(crate) fn parse( 150 | self, 151 | tok: Option, 152 | hint: Option, 153 | context: &mut Context, 154 | ) -> Result<(Option, Option), ParserError> { 155 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 156 | let mut ptrs = Vec::new(); 157 | let mut kind = if let Some(hint) = hint { 158 | hint 159 | } else { 160 | let kind = PtrKind::from_tok(&tok); 161 | if let Some(kind) = kind { 162 | kind 163 | } else { 164 | return Ok((Some(tok), None)); 165 | } 166 | }; 167 | 168 | let tok = loop { 169 | let ap = AttributesParser::new(self.lexer); 170 | let (tok, attributes) = ap.parse(None, context)?; 171 | let mut tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 172 | 173 | let mut cv = CVQualifier::empty(); 174 | let mut ms = MSModifier::empty(); 175 | 176 | while cv.from_tok(&tok) || ms.from_tok(&tok) { 177 | tok = self.lexer.next_useful(); 178 | } 179 | 180 | ptrs.push(Pointer { 181 | kind, 182 | attributes, 183 | cv, 184 | ms, 185 | }); 186 | 187 | kind = if let Some(kind) = PtrKind::from_tok(&tok) { 188 | kind 189 | } else { 190 | break tok; 191 | }; 192 | }; 193 | 194 | Ok((Some(tok), Some(ptrs))) 195 | } 196 | } 197 | 198 | pub struct ParenPointerDeclaratorParser<'a, L: TLexer> { 199 | lexer: &'a mut L, 200 | } 201 | 202 | impl<'a, L: TLexer> ParenPointerDeclaratorParser<'a, L> { 203 | pub(super) fn new(lexer: &'a mut L) -> Self { 204 | Self { lexer } 205 | } 206 | 207 | pub(super) fn parse( 208 | self, 209 | tok: Option, 210 | context: &mut Context, 211 | ) -> Result<(Option, (Option, bool)), ParserError> { 212 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 213 | if tok != Token::LeftParen { 214 | return Ok((Some(tok), (None, false))); 215 | } 216 | 217 | // The previous token was a parenthesis 218 | // so we can have some params (function type, e.g. int * (int, int))) 219 | // or a function/array pointer 220 | let pdp = PointerDeclaratorParser::new(self.lexer); 221 | let (tok, pointers) = pdp.parse(None, None, context)?; 222 | 223 | if pointers.is_some() { 224 | let npdp = NoPtrDeclaratorParser::new(self.lexer); 225 | let typ = Type { 226 | base: BaseType::None, 227 | cv: CVQualifier::empty(), 228 | pointers, 229 | }; 230 | let (tok, decl, _, _) = 231 | npdp.parse(tok, typ, Specifier::empty(), false, false, context)?; 232 | 233 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 234 | if tok != Token::RightParen { 235 | return Err(ParserError::InvalidTokenInPointer { 236 | sp: self.lexer.span(), 237 | tok, 238 | }); 239 | } 240 | 241 | Ok((None, (decl, false))) 242 | } else { 243 | // we've function params 244 | Ok((tok, (None, true))) 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /src/parser/declarations/specifier.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use bitflags::bitflags; 7 | use termcolor::StandardStreamLock; 8 | 9 | use crate::lexer::Token; 10 | use crate::parser::dump::Dump; 11 | 12 | bitflags! { 13 | pub struct Specifier: u32 { 14 | const TYPEDEF = 0b1; 15 | const INLINE = 0b10; 16 | const VIRTUAL = 0b100; 17 | const EXPLICIT = 0b1000; 18 | const FRIEND = 0b1_0000; 19 | const CONSTEVAL = 0b10_0000; 20 | const CONSTEXPR = 0b100_0000; 21 | const CONSTINIT = 0b1000_0000; 22 | const REGISTER = 0b1_0000_0000; 23 | const STATIC = 0b10_0000_0000; 24 | const THREAD_LOCAL = 0b100_0000_0000; 25 | const EXTERN = 0b1000_0000_0000; 26 | const MUTABLE = 0b1_0000_0000_0000; 27 | const CDECL = 0b10_0000_0000_0000; 28 | const CLRCALL = 0b100_0000_0000_0000; 29 | const FASTCALL = 0b1000_0000_0000_0000; 30 | const STDCALL = 0b1_0000_0000_0000_0000; 31 | const THISCALL = 0b10_0000_0000_0000_0000; 32 | const VECTORCALL = 0b100_0000_0000_0000_0000; 33 | } 34 | } 35 | 36 | impl ToString for Specifier { 37 | fn to_string(&self) -> String { 38 | bitflags_to_str!( 39 | self, 40 | Self, 41 | TYPEDEF, 42 | "typedef", 43 | INLINE, 44 | "inline", 45 | VIRTUAL, 46 | "virtual", 47 | EXPLICIT, 48 | "explicit", 49 | FRIEND, 50 | "friend", 51 | CONSTEVAL, 52 | "consteval", 53 | CONSTEXPR, 54 | "constexpr", 55 | CONSTINIT, 56 | "constinit", 57 | REGISTER, 58 | "register", 59 | STATIC, 60 | "static", 61 | THREAD_LOCAL, 62 | "thread_local", 63 | EXTERN, 64 | "extern", 65 | MUTABLE, 66 | "mutable", 67 | CDECL, 68 | "__cdecl", 69 | CLRCALL, 70 | "__clrcall", 71 | FASTCALL, 72 | "__fastcall", 73 | STDCALL, 74 | "__stdcall", 75 | THISCALL, 76 | "__thiscall", 77 | VECTORCALL, 78 | "__vectorcall" 79 | ) 80 | } 81 | } 82 | 83 | impl Dump for Specifier { 84 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 85 | dump_str!(name, self.to_string(), Cyan, prefix, last, stdout); 86 | } 87 | } 88 | 89 | impl Specifier { 90 | pub(crate) fn from_tok(&mut self, tok: &Token) -> bool { 91 | match tok { 92 | Token::Typedef => { 93 | *self |= Specifier::TYPEDEF; 94 | true 95 | } 96 | Token::Inline | Token::UInline | Token::UInlineU => { 97 | *self |= Specifier::INLINE; 98 | true 99 | } 100 | Token::Virtual => { 101 | *self |= Specifier::VIRTUAL; 102 | true 103 | } 104 | Token::Explicit => { 105 | *self |= Specifier::EXPLICIT; 106 | true 107 | } 108 | Token::Friend => { 109 | *self |= Specifier::FRIEND; 110 | true 111 | } 112 | Token::Consteval => { 113 | *self |= Specifier::CONSTEVAL; 114 | true 115 | } 116 | Token::Constexpr => { 117 | *self |= Specifier::CONSTEXPR; 118 | true 119 | } 120 | Token::Constinit => { 121 | *self |= Specifier::CONSTINIT; 122 | true 123 | } 124 | Token::Register => { 125 | *self |= Specifier::REGISTER; 126 | true 127 | } 128 | Token::Static => { 129 | *self |= Specifier::STATIC; 130 | true 131 | } 132 | Token::ThreadLocal => { 133 | *self |= Specifier::THREAD_LOCAL; 134 | true 135 | } 136 | Token::Extern => { 137 | *self |= Specifier::EXTERN; 138 | true 139 | } 140 | Token::Mutable => { 141 | *self |= Specifier::MUTABLE; 142 | true 143 | } 144 | Token::Cdecl => { 145 | *self |= Specifier::CDECL; 146 | true 147 | } 148 | Token::Clrcall => { 149 | *self |= Specifier::CLRCALL; 150 | true 151 | } 152 | Token::Fastcall => { 153 | *self |= Specifier::FASTCALL; 154 | true 155 | } 156 | Token::Stdcall => { 157 | *self |= Specifier::STDCALL; 158 | true 159 | } 160 | Token::Thiscall => { 161 | *self |= Specifier::THISCALL; 162 | true 163 | } 164 | Token::Vectorcall => { 165 | *self |= Specifier::VECTORCALL; 166 | true 167 | } 168 | _ => false, 169 | } 170 | } 171 | 172 | pub(crate) fn is_specifier(tok: &Token) -> bool { 173 | match tok { 174 | Token::Typedef 175 | | Token::Inline 176 | | Token::UInline 177 | | Token::UInlineU 178 | | Token::Virtual 179 | | Token::Explicit 180 | | Token::Friend 181 | | Token::Consteval 182 | | Token::Constexpr 183 | | Token::Constinit 184 | | Token::Register 185 | | Token::Static 186 | | Token::ThreadLocal 187 | | Token::Extern 188 | | Token::Mutable 189 | | Token::Cdecl 190 | | Token::Clrcall 191 | | Token::Fastcall 192 | | Token::Stdcall 193 | | Token::Thiscall 194 | | Token::Vectorcall => true, 195 | _ => false, 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/parser/declarations/static_assert.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use crate::lexer::{TLexer, Token}; 9 | use crate::parser::dump::Dump; 10 | use crate::parser::errors::ParserError; 11 | use crate::parser::expressions::{ExprNode, ExpressionParser}; 12 | use crate::parser::literals::StringLiteralParser; 13 | use crate::parser::Context; 14 | 15 | #[derive(Clone, Debug, PartialEq)] 16 | pub struct StaticAssert { 17 | pub condition: ExprNode, 18 | pub string: Option, 19 | pub cpp: bool, 20 | } 21 | 22 | impl Dump for StaticAssert { 23 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 24 | dump_obj!( 25 | self, 26 | name, 27 | "static_assert", 28 | prefix, 29 | last, 30 | stdout, 31 | condition, 32 | string, 33 | cpp 34 | ); 35 | } 36 | } 37 | 38 | pub(crate) struct StaticAssertParser<'a, L: TLexer> { 39 | lexer: &'a mut L, 40 | } 41 | 42 | impl<'a, L: TLexer> StaticAssertParser<'a, L> { 43 | pub(crate) fn new(lexer: &'a mut L) -> Self { 44 | Self { lexer } 45 | } 46 | 47 | pub(crate) fn parse( 48 | self, 49 | tok: Option, 50 | context: &mut Context, 51 | ) -> Result<(Option, Option), ParserError> { 52 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 53 | if tok != Token::StaticAssert && tok != Token::CStaticAssert { 54 | return Ok((Some(tok), None)); 55 | } 56 | 57 | let cpp = tok == Token::StaticAssert; 58 | 59 | let tok = self.lexer.next_useful(); 60 | if tok != Token::LeftParen { 61 | return Err(ParserError::InvalidTokenInStaticAssert { 62 | sp: self.lexer.span(), 63 | tok, 64 | }); 65 | } 66 | 67 | let mut ep = ExpressionParser::new(self.lexer, Token::Comma); 68 | let (tok, expr) = ep.parse(None, context)?; 69 | 70 | let condition = if let Some(cond) = expr { 71 | cond 72 | } else { 73 | return Err(ParserError::InvalidTokenInStaticAssert { 74 | sp: self.lexer.span(), 75 | tok: tok.unwrap(), 76 | }); 77 | }; 78 | 79 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 80 | match tok { 81 | Token::RightParen => { 82 | return Ok(( 83 | None, 84 | Some(StaticAssert { 85 | condition, 86 | string: None, 87 | cpp, 88 | }), 89 | )) 90 | } 91 | Token::Comma => {} 92 | _ => { 93 | return Err(ParserError::InvalidTokenInStaticAssert { 94 | sp: self.lexer.span(), 95 | tok, 96 | }); 97 | } 98 | } 99 | 100 | let tok = self.lexer.next_useful(); 101 | let string = tok.get_string(); 102 | 103 | let string = if let Some(string) = string { 104 | string 105 | } else { 106 | return Err(ParserError::InvalidArgInStaticAssert { 107 | sp: self.lexer.span(), 108 | }); 109 | }; 110 | 111 | let slp = StringLiteralParser::new(self.lexer); 112 | let (tok, string) = slp.parse(&string, context)?; 113 | 114 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 115 | if tok != Token::RightParen { 116 | return Err(ParserError::InvalidTokenInStaticAssert { 117 | sp: self.lexer.span(), 118 | tok, 119 | }); 120 | } 121 | 122 | Ok(( 123 | None, 124 | Some(StaticAssert { 125 | condition, 126 | string: Some(string), 127 | cpp, 128 | }), 129 | )) 130 | } 131 | } 132 | 133 | #[cfg(test)] 134 | mod tests { 135 | 136 | use super::*; 137 | use crate::lexer::{preprocessor::context::DefaultContext, Lexer}; 138 | use crate::mk_var; 139 | use crate::parser::expressions::*; 140 | use crate::parser::names::Qualified; 141 | use pretty_assertions::assert_eq; 142 | 143 | #[test] 144 | fn test_static_assert_1() { 145 | let mut l = Lexer::::new(b"static_assert(a != b)"); 146 | let p = StaticAssertParser::new(&mut l); 147 | let mut context = Context::default(); 148 | let (_, u) = p.parse(None, &mut context).unwrap(); 149 | 150 | assert_eq!( 151 | u.unwrap(), 152 | StaticAssert { 153 | condition: node!(BinaryOp { 154 | op: Operator::Neq, 155 | arg1: ExprNode::Variable(Box::new(mk_var!("a"))), 156 | arg2: ExprNode::Variable(Box::new(mk_var!("b"))), 157 | }), 158 | string: None, 159 | cpp: true, 160 | } 161 | ); 162 | } 163 | 164 | #[test] 165 | fn test_static_assert_2() { 166 | let mut l = Lexer::::new(b"_Static_assert(a != b, \"an assertion\")"); 167 | let p = StaticAssertParser::new(&mut l); 168 | let mut context = Context::default(); 169 | let (_, u) = p.parse(None, &mut context).unwrap(); 170 | 171 | assert_eq!( 172 | u.unwrap(), 173 | StaticAssert { 174 | condition: node!(BinaryOp { 175 | op: Operator::Neq, 176 | arg1: ExprNode::Variable(Box::new(mk_var!("a"))), 177 | arg2: ExprNode::Variable(Box::new(mk_var!("b"))), 178 | }), 179 | string: Some("an assertion".to_string()), 180 | cpp: false, 181 | } 182 | ); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/parser/dump.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use std::cell::RefCell; 7 | use std::rc::Rc; 8 | use termcolor::{ColorChoice, StandardStream, StandardStreamLock}; 9 | 10 | use crate::dump_str; 11 | 12 | pub trait Dump { 13 | fn dump_me(&self) { 14 | let stdout = StandardStream::stdout(ColorChoice::Always); 15 | let mut stdout = stdout.lock(); 16 | self.dump("", "", true, &mut stdout); 17 | color!(stdout, White); 18 | } 19 | 20 | fn get_pref(last: bool) -> &'static str { 21 | // https://en.wikipedia.org/wiki/Box-drawing_character 22 | if last { 23 | // "`- " 24 | "\u{2570}\u{2500} " 25 | } else { 26 | // "|- " 27 | "\u{251C}\u{2500} " 28 | } 29 | } 30 | 31 | fn get_pref_child(last: bool) -> &'static str { 32 | if last { 33 | " " 34 | } else { 35 | // "| " 36 | "\u{2502} " 37 | } 38 | } 39 | 40 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock); 41 | } 42 | 43 | impl Dump for Option { 44 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 45 | if let Some(x) = self { 46 | x.dump(name, prefix, last, stdout); 47 | } else { 48 | dump_str!(name, "\u{2717}", Red, prefix, last, stdout); 49 | } 50 | } 51 | } 52 | 53 | impl Dump for Rc { 54 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 55 | self.as_ref().dump(name, prefix, last, stdout); 56 | } 57 | } 58 | 59 | impl Dump for RefCell { 60 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 61 | self.borrow().dump(name, prefix, last, stdout); 62 | } 63 | } 64 | 65 | impl<'a, T: Dump> Dump for &'a T { 66 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 67 | (*self).dump(name, prefix, last, stdout); 68 | } 69 | } 70 | 71 | impl Dump for String { 72 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 73 | dump_str!(name, self, prefix, last, stdout); 74 | } 75 | } 76 | 77 | impl Dump for bool { 78 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 79 | let v = if *self { "true" } else { "false" }; 80 | dump_str!(name, v, Cyan, prefix, last, stdout); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/parser/errors.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use crate::errors::{Span, StringlyError}; 7 | use crate::lexer::Token; 8 | 9 | #[derive(Clone, Debug)] 10 | pub enum ParserError { 11 | // TODO: rewrite that stuff 12 | InvalidVarInDecl { sp: Span, name: String }, 13 | InvalidTokenInOp { sp: Span, tok: Token }, 14 | InvalidTokenInDtor { sp: Span, tok: Token }, 15 | InvalidTokenInArraySize { sp: Span, tok: Token }, 16 | InvalidTokenInAttrs { sp: Span, tok: Token }, 17 | InvalidTokenInAsm { sp: Span, tok: Token }, 18 | InvalidTokenInExtern { sp: Span, tok: Token }, 19 | InvalidTokenInParamList { sp: Span, tok: Token }, 20 | InvalidTokenInFuncDecl { sp: Span, tok: Token }, 21 | InvalidTokenInThrow { sp: Span, tok: Token }, 22 | InvalidTokenInClass { sp: Span, tok: Token }, 23 | InvalidTokenInNs { sp: Span, tok: Token }, 24 | InvalidTokenInGoto { sp: Span, tok: Token }, 25 | InvalidTokenInIf { sp: Span, tok: Token }, 26 | InvalidTokenInSwitch { sp: Span, tok: Token }, 27 | InvalidTokenInTry { sp: Span, tok: Token }, 28 | InvalidTokenInPointer { sp: Span, tok: Token }, 29 | InvalidTokenInStaticAssert { sp: Span, tok: Token }, 30 | InvalidTokenInUsingEnum { sp: Span, tok: Token }, 31 | InvalidTokenInEnum { sp: Span, tok: Token }, 32 | InvalidTokenInUsing { sp: Span, tok: Token }, 33 | InvalidTokenInAlias { sp: Span, tok: Token }, 34 | InvalidTokenInConditional { sp: Span, tok: Token }, 35 | InvalidTokenInDo { sp: Span, tok: Token }, 36 | InvalidTokenInStmt { sp: Span, tok: Token }, 37 | InvalidTokenInFor { sp: Span, tok: Token }, 38 | InvalidTokenInWhile { sp: Span, tok: Token }, 39 | InvalidTokenInUnit { sp: Span, tok: Token }, 40 | InvalidTokenInExpr { sp: Span, tok: Token }, 41 | InvalidExprInFor { sp: Span }, 42 | InvalidTypeInOp { sp: Span, name: String }, 43 | InvalidTypeInExpr { sp: Span, name: String }, 44 | UnknownId { sp: Span, name: String }, 45 | InvalidArgInStaticAssert { sp: Span }, 46 | UnbalancedAttr { sp: Span, tok: Token }, 47 | UnexpectedEof { sp: Span }, 48 | InvalidBitfieldSize { sp: Span }, 49 | InvalidCtorInit { sp: Span }, 50 | InvalidCast { sp: Span }, 51 | InvalidDeclOrExpr { sp: Span }, 52 | } 53 | 54 | impl ParserError { 55 | pub fn stringly(&self) -> StringlyError { 56 | use self::ParserError::*; 57 | let (sp, message) = match self { 58 | InvalidVarInDecl { sp, name } => { 59 | (*sp, format!("Invalid variable {} in declaration", name)) 60 | } 61 | InvalidTokenInOp { sp, tok } => { 62 | (*sp, format!("Invalid token {:?} in operator name", tok)) 63 | } 64 | InvalidTokenInDtor { sp, tok } => { 65 | (*sp, format!("Invalid token {:?} in dtor name", tok)) 66 | } 67 | InvalidTokenInArraySize { sp, tok } => { 68 | (*sp, format!("Invalid token {:?} in array size", tok)) 69 | } 70 | InvalidTokenInAttrs { sp, tok } => { 71 | (*sp, format!("Invalid token {:?} in attributes", tok)) 72 | } 73 | InvalidTokenInAsm { sp, tok } => { 74 | (*sp, format!("Invalid token {:?} in asm declaration", tok)) 75 | } 76 | InvalidTokenInParamList { sp, tok } => { 77 | (*sp, format!("Invalid token {:?} in parameter list", tok)) 78 | } 79 | InvalidTokenInExtern { sp, tok } => ( 80 | *sp, 81 | format!("Invalid token {:?} in extern declaration", tok), 82 | ), 83 | InvalidTokenInFuncDecl { sp, tok } => ( 84 | *sp, 85 | format!("Invalid token {:?} in function declaration", tok), 86 | ), 87 | InvalidTokenInThrow { sp, tok } => (*sp, format!("Invalid token {:?} in throw", tok)), 88 | InvalidTokenInClass { sp, tok } => { 89 | (*sp, format!("Invalid token {:?} in class declaration", tok)) 90 | } 91 | InvalidTokenInNs { sp, tok } => ( 92 | *sp, 93 | format!("Invalid token {:?} in namespace declaration", tok), 94 | ), 95 | InvalidTokenInGoto { sp, tok } => { 96 | (*sp, format!("Invalid token {:?} in goto statement", tok)) 97 | } 98 | InvalidTokenInIf { sp, tok } => { 99 | (*sp, format!("Invalid token {:?} in if statement", tok)) 100 | } 101 | InvalidTokenInSwitch { sp, tok } => { 102 | (*sp, format!("Invalid token {:?} in switch statement", tok)) 103 | } 104 | InvalidTokenInTry { sp, tok } => { 105 | (*sp, format!("Invalid token {:?} in try statement", tok)) 106 | } 107 | InvalidTokenInPointer { sp, tok } => ( 108 | *sp, 109 | format!("Invalid token {:?} in pointer declarator", tok), 110 | ), 111 | InvalidTokenInStaticAssert { sp, tok } => ( 112 | *sp, 113 | format!("Invalid token {:?} in static_assert declarator", tok), 114 | ), 115 | InvalidTokenInUsingEnum { sp, tok } => ( 116 | *sp, 117 | format!("Invalid token {:?} in using enum declaration", tok), 118 | ), 119 | InvalidTokenInEnum { sp, tok } => { 120 | (*sp, format!("Invalid token {:?} in enum declaration", tok)) 121 | } 122 | InvalidTokenInUsing { sp, tok } => { 123 | (*sp, format!("Invalid token {:?} in using declaration", tok)) 124 | } 125 | InvalidTokenInAlias { sp, tok } => { 126 | (*sp, format!("Invalid token {:?} in alias declaration", tok)) 127 | } 128 | InvalidTokenInConditional { sp, tok } => ( 129 | *sp, 130 | format!("Invalid token {:?} in conditional expression", tok), 131 | ), 132 | InvalidTokenInDo { sp, tok } => { 133 | (*sp, format!("Invalid token {:?} in do statement", tok)) 134 | } 135 | InvalidTokenInStmt { sp, tok } => { 136 | (*sp, format!("Invalid token {:?} in statement", tok)) 137 | } 138 | InvalidTokenInFor { sp, tok } => { 139 | (*sp, format!("Invalid token {:?} in for statement", tok)) 140 | } 141 | InvalidTokenInWhile { sp, tok } => { 142 | (*sp, format!("Invalid token {:?} in while statement", tok)) 143 | } 144 | InvalidTokenInUnit { sp, tok } => (*sp, format!("Invalid token {:?} in CU", tok)), 145 | InvalidTokenInExpr { sp, tok } => { 146 | (*sp, format!("Invalid token {:?} in expression", tok)) 147 | } 148 | InvalidExprInFor { sp } => (*sp, format!("Invalid expression in for statement")), 149 | InvalidTypeInOp { sp, name } => { 150 | (*sp, format!("Invalid type {} in conversion operator", name)) 151 | } 152 | InvalidTypeInExpr { sp, name } => (*sp, format!("Invalid type {} in expression", name)), 153 | UnknownId { sp, name } => (*sp, format!("Unknown identifier {}", name)), 154 | UnbalancedAttr { sp, tok } => (*sp, format!("Unbalanced {:?} in attriute", tok)), 155 | UnexpectedEof { sp } => (*sp, format!("Unexpected eof")), 156 | InvalidBitfieldSize { sp } => (*sp, format!("Invalid bitfield size")), 157 | InvalidCtorInit { sp } => (*sp, format!("Invalid ctor initializer")), 158 | InvalidArgInStaticAssert { sp } => (*sp, format!("Invalid argument in static_assert")), 159 | InvalidCast { sp } => (*sp, format!("Invalid cast")), 160 | InvalidDeclOrExpr { sp } => (*sp, format!("Invalid declaration or expression")), 161 | }; 162 | StringlyError { message, sp } 163 | } 164 | } 165 | 166 | // use crate::parser::errors::ParserError; 167 | // return Err(ParserError:: { sp: self.lexer.span(), tok }); 168 | -------------------------------------------------------------------------------- /src/parser/expressions/casts.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use std::rc::Rc; 7 | use termcolor::StandardStreamLock; 8 | 9 | use crate::lexer::{TLexer, Token}; 10 | use crate::parser::declarations::TypeDeclaratorParser; 11 | use crate::parser::dump::Dump; 12 | use crate::parser::errors::ParserError; 13 | use crate::parser::expressions::{ExprNode, ExpressionParser}; 14 | use crate::parser::types::Type; 15 | use crate::parser::Context; 16 | 17 | #[derive(Clone, Debug, PartialEq)] 18 | pub struct StaticCast { 19 | pub typ: Type, 20 | pub arg: ExprNode, 21 | } 22 | 23 | #[derive(Clone, Debug, PartialEq)] 24 | pub struct DynamicCast { 25 | pub typ: Type, 26 | pub arg: ExprNode, 27 | } 28 | 29 | #[derive(Clone, Debug, PartialEq)] 30 | pub struct ConstCast { 31 | pub typ: Type, 32 | pub arg: ExprNode, 33 | } 34 | 35 | #[derive(Clone, Debug, PartialEq)] 36 | pub struct ReinterpretCast { 37 | pub typ: Type, 38 | pub arg: ExprNode, 39 | } 40 | 41 | impl Dump for StaticCast { 42 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 43 | dump_obj!(self, name, "static_cast", prefix, last, stdout, typ, arg); 44 | } 45 | } 46 | 47 | impl Dump for DynamicCast { 48 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 49 | dump_obj!(self, name, "dynamic_cast", prefix, last, stdout, typ, arg); 50 | } 51 | } 52 | 53 | impl Dump for ConstCast { 54 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 55 | dump_obj!(self, name, "const_cast", prefix, last, stdout, typ, arg); 56 | } 57 | } 58 | 59 | impl Dump for ReinterpretCast { 60 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 61 | dump_obj!( 62 | self, 63 | name, 64 | "reinterpret_cast", 65 | prefix, 66 | last, 67 | stdout, 68 | typ, 69 | arg 70 | ); 71 | } 72 | } 73 | 74 | pub(crate) struct FooCastParser<'a, L: TLexer> { 75 | lexer: &'a mut L, 76 | } 77 | 78 | impl<'a, L: TLexer> FooCastParser<'a, L> { 79 | pub(crate) fn new(lexer: &'a mut L) -> Self { 80 | Self { lexer } 81 | } 82 | 83 | pub(crate) fn parse( 84 | self, 85 | base_tok: Token, 86 | context: &mut Context, 87 | ) -> Result<(Option, Option), ParserError> { 88 | let tok = self.lexer.next_useful(); 89 | if tok != Token::Lower { 90 | return Err(ParserError::InvalidTokenInExpr { 91 | sp: self.lexer.span(), 92 | tok, 93 | }); 94 | } 95 | 96 | let tdp = TypeDeclaratorParser::new(self.lexer); 97 | let (tok, typ) = tdp.parse(None, None, false, context)?; 98 | 99 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 100 | if tok != Token::Greater { 101 | return Err(ParserError::InvalidTokenInExpr { 102 | sp: self.lexer.span(), 103 | tok, 104 | }); 105 | } 106 | 107 | let typ = Rc::try_unwrap(typ.unwrap()).unwrap().typ; 108 | 109 | let tok = self.lexer.next_useful(); 110 | if tok != Token::LeftParen { 111 | return Err(ParserError::InvalidTokenInExpr { 112 | sp: self.lexer.span(), 113 | tok, 114 | }); 115 | } 116 | 117 | let mut ep = ExpressionParser::new(self.lexer, Token::RightParen); 118 | let (_, expr) = ep.parse(None, context)?; 119 | 120 | let arg = expr.unwrap(); 121 | 122 | let node = match base_tok { 123 | Token::StaticCast => Some(ExprNode::StaticCast(Box::new(StaticCast { typ, arg }))), 124 | Token::DynamicCast => Some(ExprNode::DynamicCast(Box::new(DynamicCast { typ, arg }))), 125 | Token::ConstCast => Some(ExprNode::ConstCast(Box::new(ConstCast { typ, arg }))), 126 | Token::ReinterpretCast => Some(ExprNode::ReinterpretCast(Box::new(ReinterpretCast { 127 | typ, 128 | arg, 129 | }))), 130 | _ => None, 131 | }; 132 | 133 | Ok((None, node)) 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/parser/expressions/list.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use crate::lexer::{TLexer, Token}; 7 | use crate::parser::errors::ParserError; 8 | use crate::parser::expressions::{Parameters, ParametersParser}; 9 | use crate::parser::Context; 10 | 11 | pub type ListInitialization = Parameters; 12 | 13 | pub struct ListInitializationParser<'a, L: TLexer> { 14 | lexer: &'a mut L, 15 | } 16 | 17 | impl<'a, L: TLexer> ListInitializationParser<'a, L> { 18 | pub(crate) fn new(lexer: &'a mut L) -> Self { 19 | Self { lexer } 20 | } 21 | 22 | pub(crate) fn parse( 23 | self, 24 | tok: Option, 25 | context: &mut Context, 26 | ) -> Result<(Option, Option), ParserError> { 27 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 28 | 29 | if tok != Token::LeftBrace { 30 | return Ok((Some(tok), None)); 31 | } 32 | 33 | let pp = ParametersParser::new(self.lexer, Token::RightBrace); 34 | pp.parse(None, None, context) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/parser/expressions/mod.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | #[macro_use] 7 | pub mod expr; 8 | pub use self::expr::*; 9 | 10 | pub mod operator; 11 | pub use self::operator::*; 12 | 13 | pub mod params; 14 | pub use self::params::*; 15 | 16 | pub mod list; 17 | pub use self::list::*; 18 | 19 | pub mod left_paren; 20 | pub use self::left_paren::*; 21 | 22 | pub mod casts; 23 | pub use self::casts::*; 24 | -------------------------------------------------------------------------------- /src/parser/expressions/operator.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use super::ExprNode; 9 | use crate::parser::dump::Dump; 10 | 11 | #[derive(Clone, Copy, Debug, PartialEq, Hash)] 12 | pub enum Operator { 13 | ScopeResolution, 14 | PostInc, 15 | PostDec, 16 | Call, 17 | Parenthesis, 18 | Dot, 19 | Arrow, 20 | Subscript, 21 | PreInc, 22 | PreDec, 23 | Plus, 24 | Minus, 25 | Indirection, 26 | AddressOf, 27 | AddressOfLabel, 28 | Sizeof, 29 | New, 30 | NewArray, 31 | Delete, 32 | DeleteArray, 33 | CoAwait, 34 | Not, 35 | BitNeg, 36 | DotIndirection, 37 | ArrowIndirection, 38 | Mul, 39 | Div, 40 | Mod, 41 | Add, 42 | Sub, 43 | LShift, 44 | RShift, 45 | ThreeWayComp, 46 | Lt, 47 | Gt, 48 | Leq, 49 | Geq, 50 | Eq, 51 | Neq, 52 | BitAnd, 53 | BitXor, 54 | BitOr, 55 | And, 56 | Or, 57 | Conditional, 58 | Throw, 59 | CoYield, 60 | Assign, 61 | AddAssign, 62 | SubAssign, 63 | MulAssign, 64 | DivAssign, 65 | ModAssign, 66 | LShiftAssign, 67 | RShiftAssign, 68 | AndAssign, 69 | XorAssign, 70 | OrAssign, 71 | Comma, 72 | Cast, 73 | } 74 | 75 | impl Operator { 76 | pub fn operate(self, stack: &mut Vec) { 77 | use Operator::*; 78 | 79 | match self { 80 | Plus | Minus | Not | BitNeg | Sizeof | PreInc | PreDec | Indirection | AddressOf 81 | | Throw | CoAwait | CoYield => { 82 | let arg = stack.pop().unwrap(); 83 | stack.push(ExprNode::UnaryOp(Box::new(UnaryOp { op: self, arg }))); 84 | } 85 | Conditional => { 86 | let right = stack.pop().unwrap(); 87 | let left = stack.pop().unwrap(); 88 | let condition = stack.pop().unwrap(); 89 | stack.push(ExprNode::Conditional(Box::new(super::Conditional { 90 | condition, 91 | left, 92 | right, 93 | }))); 94 | } 95 | _ => { 96 | let arg2 = stack.pop().unwrap(); 97 | let arg1 = stack.pop().unwrap(); 98 | stack.push(ExprNode::BinaryOp(Box::new(BinaryOp { 99 | op: self, 100 | arg1, 101 | arg2, 102 | }))); 103 | } 104 | } 105 | } 106 | 107 | pub fn to_str(self) -> &'static str { 108 | use Operator::*; 109 | 110 | match self { 111 | ScopeResolution => "::", 112 | PostInc => "()++", 113 | PostDec => "()--", 114 | Call => "()", 115 | Parenthesis => "(", 116 | Dot => ".", 117 | Arrow => "->", 118 | Subscript => "[]", 119 | PreInc => "++()", 120 | PreDec => "--()", 121 | Plus => "+", 122 | Minus => "-", 123 | Indirection => "indirection", 124 | AddressOf => "address-of", 125 | AddressOfLabel => "&&", 126 | Sizeof => "sizeof", 127 | New => "new", 128 | NewArray => "new []", 129 | Delete => "delete", 130 | DeleteArray => "delete []", 131 | CoAwait => "co_await", 132 | Not => "!", 133 | BitNeg => "~", 134 | DotIndirection => ".*", 135 | ArrowIndirection => "->*", 136 | Mul => "*", 137 | Div => "/", 138 | Mod => "%", 139 | Add => "+", 140 | Sub => "-", 141 | LShift => "<<", 142 | RShift => ">>", 143 | ThreeWayComp => "<=>", 144 | Lt => "<", 145 | Gt => ">", 146 | Leq => "<=", 147 | Geq => ">=", 148 | Eq => "==", 149 | Neq => "!=", 150 | BitAnd => "&", 151 | BitXor => "^", 152 | BitOr => "|", 153 | And => "&&", 154 | Or => "||", 155 | Conditional => "?:", 156 | Throw => "throw", 157 | CoYield => "coyield", 158 | Assign => "=", 159 | AddAssign => "+=", 160 | SubAssign => "-=", 161 | MulAssign => "*=", 162 | DivAssign => "/=", 163 | ModAssign => "%=", 164 | LShiftAssign => "<<=", 165 | RShiftAssign => ">>=", 166 | AndAssign => "&=", 167 | XorAssign => "^=", 168 | OrAssign => "|=", 169 | Comma => ",", 170 | Cast => "()", 171 | } 172 | } 173 | } 174 | 175 | #[derive(Clone, Debug, PartialEq)] 176 | pub struct BinaryOp { 177 | pub op: Operator, 178 | pub arg1: ExprNode, 179 | pub arg2: ExprNode, 180 | } 181 | 182 | #[derive(Clone, Debug, PartialEq)] 183 | pub struct UnaryOp { 184 | pub op: Operator, 185 | pub arg: ExprNode, 186 | } 187 | 188 | #[derive(Clone, Debug, PartialEq)] 189 | pub struct Conditional { 190 | pub condition: ExprNode, 191 | pub left: ExprNode, 192 | pub right: ExprNode, 193 | } 194 | 195 | impl Dump for BinaryOp { 196 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 197 | let prefix = dump_start!(name, self.op.to_str(), prefix, last, stdout); 198 | dump_fields!(self, prefix, stdout, arg1, arg2); 199 | } 200 | } 201 | 202 | impl Dump for UnaryOp { 203 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 204 | let prefix = dump_start!(name, self.op.to_str(), prefix, last, stdout); 205 | dump_fields!(self, prefix, stdout, arg); 206 | } 207 | } 208 | 209 | impl Dump for Conditional { 210 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 211 | let prefix = dump_start!( 212 | name, 213 | "conditional(\u{b7}?\u{b7}:\u{b7})", 214 | prefix, 215 | last, 216 | stdout 217 | ); 218 | dump_fields!(self, prefix, stdout, condition, left, right); 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/parser/expressions/params.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use crate::lexer::{TLexer, Token}; 9 | use crate::parser::dump::Dump; 10 | use crate::parser::errors::ParserError; 11 | use crate::parser::expressions::{ExprNode, ExpressionParser}; 12 | use crate::parser::Context; 13 | 14 | pub type Parameters = Vec; 15 | 16 | impl Dump for Parameters { 17 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 18 | dump_vec!(name, self, "par", prefix, last, stdout); 19 | } 20 | } 21 | 22 | pub(crate) struct ParametersParser<'a, L: TLexer> { 23 | lexer: &'a mut L, 24 | term: Token, 25 | } 26 | 27 | impl<'a, L: TLexer> ParametersParser<'a, L> { 28 | pub(crate) fn new(lexer: &'a mut L, term: Token) -> Self { 29 | Self { lexer, term } 30 | } 31 | 32 | pub(crate) fn parse( 33 | self, 34 | tok: Option, 35 | first: Option, 36 | context: &mut Context, 37 | ) -> Result<(Option, Option), ParserError> { 38 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 39 | let (mut tok, mut params) = if let Some(first) = first { 40 | let tok = if tok == Token::Comma { 41 | self.lexer.next_useful() 42 | } else { 43 | tok 44 | }; 45 | (tok, vec![first]) 46 | } else { 47 | (tok, Vec::new()) 48 | }; 49 | 50 | if tok == self.term { 51 | return Ok((None, Some(params))); 52 | } 53 | 54 | loop { 55 | let mut ep = ExpressionParser::new(self.lexer, Token::Comma); 56 | let (tk, expr) = ep.parse(Some(tok), context)?; 57 | 58 | params.push(expr.unwrap()); 59 | 60 | let tk = tk.unwrap_or_else(|| self.lexer.next_useful()); 61 | 62 | match tk { 63 | Token::Comma => {} 64 | _ => { 65 | if tk == self.term { 66 | return Ok((None, Some(params))); 67 | } else { 68 | return Err(ParserError::InvalidTokenInParamList { 69 | sp: self.lexer.span(), 70 | tok: tk, 71 | }); 72 | } 73 | } 74 | } 75 | tok = self.lexer.next_useful(); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/parser/initializer/init.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use crate::lexer::{TLexer, Token}; 9 | use crate::parser::dump::Dump; 10 | use crate::parser::errors::ParserError; 11 | use crate::parser::expressions::{ 12 | ExprNode, ExpressionParser, ListInitialization, ListInitializationParser, Parameters, 13 | ParametersParser, 14 | }; 15 | use crate::parser::Context; 16 | 17 | #[derive(Clone, Debug, PartialEq)] 18 | pub enum Initializer { 19 | Equal(ExprNode), 20 | Paren(Parameters), 21 | Brace(ListInitialization), 22 | } 23 | 24 | impl Dump for Initializer { 25 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 26 | macro_rules! dump { 27 | ( $x: ident) => { 28 | $x.dump(name, prefix, last, stdout) 29 | }; 30 | } 31 | 32 | match self { 33 | Self::Equal(x) => dump!(x), 34 | Self::Paren(x) => dump!(x), 35 | Self::Brace(x) => dump!(x), 36 | } 37 | } 38 | } 39 | 40 | pub struct InitializerParser<'a, L: TLexer> { 41 | lexer: &'a mut L, 42 | } 43 | 44 | impl<'a, L: TLexer> InitializerParser<'a, L> { 45 | pub(crate) fn new(lexer: &'a mut L) -> Self { 46 | Self { lexer } 47 | } 48 | 49 | pub(crate) fn parse( 50 | self, 51 | tok: Option, 52 | context: &mut Context, 53 | ) -> Result<(Option, Option), ParserError> { 54 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 55 | 56 | match tok { 57 | Token::Equal => { 58 | let mut ep = ExpressionParser::new(self.lexer, Token::Comma); 59 | let (tok, expr) = ep.parse(None, context)?; 60 | Ok((tok, Some(Initializer::Equal(expr.unwrap())))) 61 | } 62 | Token::LeftParen => { 63 | let pp = ParametersParser::new(self.lexer, Token::RightParen); 64 | let (tok, params) = pp.parse(None, None, context)?; 65 | Ok((tok, Some(Initializer::Paren(params.unwrap())))) 66 | } 67 | Token::LeftBrace => { 68 | let lip = ListInitializationParser::new(self.lexer); 69 | let (tok, params) = lip.parse(Some(tok), context)?; 70 | Ok((tok, Some(Initializer::Brace(params.unwrap())))) 71 | } 72 | _ => Ok((Some(tok), None)), 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/parser/initializer/mod.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | pub mod init; 7 | pub use self::init::*; 8 | -------------------------------------------------------------------------------- /src/parser/literals.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use crate::lexer::{TLexer, Token}; 9 | use crate::parser::dump::Dump; 10 | use crate::parser::errors::ParserError; 11 | use crate::parser::Context; 12 | 13 | #[derive(Clone, Debug, PartialEq)] 14 | pub enum IntLiteral { 15 | Int(u64), 16 | UInt(u64), 17 | Long(u64), 18 | ULong(u64), 19 | LongLong(u64), 20 | ULongLong(u64), 21 | } 22 | 23 | #[derive(Clone, Debug, PartialEq)] 24 | pub struct Integer { 25 | pub value: IntLiteral, 26 | } 27 | 28 | impl Into for &IntLiteral { 29 | fn into(self) -> u64 { 30 | use IntLiteral::*; 31 | match *self { 32 | Int(n) | UInt(n) | Long(n) | ULong(n) | LongLong(n) | ULongLong(n) => n, 33 | } 34 | } 35 | } 36 | 37 | impl ToString for Integer { 38 | fn to_string(&self) -> String { 39 | format!("{}", Into::::into(&self.value)) 40 | } 41 | } 42 | 43 | impl Dump for Integer { 44 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 45 | dump_str!(name, self.to_string(), prefix, last, stdout); 46 | } 47 | } 48 | 49 | #[derive(Clone, Debug, PartialEq)] 50 | pub enum FloatLiteral { 51 | Float(f64), 52 | Double(f64), 53 | LongDouble(f64), 54 | FloatUD(Box<(f64, String)>), 55 | } 56 | 57 | #[derive(Clone, Debug, PartialEq)] 58 | pub struct Float { 59 | pub value: FloatLiteral, 60 | } 61 | 62 | impl Into for &FloatLiteral { 63 | fn into(self) -> f64 { 64 | use FloatLiteral::*; 65 | match &*self { 66 | Float(x) | Double(x) | LongDouble(x) => *x, 67 | FloatUD(ref x) => x.0, 68 | } 69 | } 70 | } 71 | 72 | impl ToString for Float { 73 | fn to_string(&self) -> String { 74 | match &self.value { 75 | FloatLiteral::FloatUD(x) => format!("{}{}", x.0, x.1), 76 | x => format!("{}", Into::::into(x)), 77 | } 78 | } 79 | } 80 | 81 | impl Dump for Float { 82 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 83 | dump_str!(name, self.to_string(), prefix, last, stdout); 84 | } 85 | } 86 | 87 | #[derive(Clone, Debug, PartialEq)] 88 | pub enum CharLiteral { 89 | Char(u32), 90 | LChar(u32), 91 | UChar(u32), 92 | UUChar(u32), 93 | U8Char(u32), 94 | CharUD(Box<(u32, String)>), 95 | LCharUD(Box<(u32, String)>), 96 | UCharUD(Box<(u32, String)>), 97 | UUCharUD(Box<(u32, String)>), 98 | U8CharUD(Box<(u32, String)>), 99 | } 100 | 101 | #[derive(Clone, Debug, PartialEq)] 102 | pub struct Char { 103 | pub value: CharLiteral, 104 | } 105 | 106 | impl Into for &CharLiteral { 107 | fn into(self) -> u32 { 108 | use CharLiteral::*; 109 | match &*self { 110 | Char(x) | LChar(x) | UChar(x) | UUChar(x) | U8Char(x) => *x, 111 | CharUD(ref x) | LCharUD(ref x) | UCharUD(ref x) | UUCharUD(ref x) | U8CharUD(ref x) => { 112 | x.0 113 | } 114 | } 115 | } 116 | } 117 | 118 | impl ToString for Char { 119 | fn to_string(&self) -> String { 120 | use CharLiteral::*; 121 | match &self.value { 122 | CharUD(x) | LCharUD(x) | UCharUD(x) | UUCharUD(x) | U8CharUD(x) => { 123 | if let Some(c) = std::char::from_u32(x.0) { 124 | format!("'{}'{}", c, x.1) 125 | } else { 126 | format!("'\\x{:x}'{}", x.0, x.1) 127 | } 128 | } 129 | x => { 130 | let x = Into::::into(x); 131 | if let Some(c) = std::char::from_u32(x) { 132 | format!("'{}'", c) 133 | } else { 134 | format!("'\\x{:x}'", x) 135 | } 136 | } 137 | } 138 | } 139 | } 140 | 141 | impl Dump for Char { 142 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 143 | dump_str!(name, self.to_string(), prefix, last, stdout); 144 | } 145 | } 146 | 147 | #[derive(Clone, Debug, PartialEq)] 148 | pub enum StrLiteral { 149 | Str(String), 150 | LStr(String), 151 | UStr(String), 152 | UUStr(String), 153 | U8Str(String), 154 | RStr(String), 155 | LRStr(String), 156 | URStr(String), 157 | UURStr(String), 158 | U8RStr(String), 159 | StrUD(Box<(String, String)>), 160 | LStrUD(Box<(String, String)>), 161 | UStrUD(Box<(String, String)>), 162 | UUStrUD(Box<(String, String)>), 163 | U8StrUD(Box<(String, String)>), 164 | RStrUD(Box<(String, String)>), 165 | LRStrUD(Box<(String, String)>), 166 | URStrUD(Box<(String, String)>), 167 | UURStrUD(Box<(String, String)>), 168 | U8RStrUD(Box<(String, String)>), 169 | } 170 | 171 | #[derive(Clone, Debug, PartialEq)] 172 | pub struct Str { 173 | pub value: StrLiteral, 174 | } 175 | 176 | impl ToString for Str { 177 | fn to_string(&self) -> String { 178 | use StrLiteral::*; 179 | match &self.value { 180 | Str(s) | LStr(s) | UStr(s) | UUStr(s) | U8Str(s) | RStr(s) | LRStr(s) | URStr(s) 181 | | UURStr(s) | U8RStr(s) => format!("\"{}\"", s), 182 | 183 | StrUD(x) | LStrUD(x) | UStrUD(x) | UUStrUD(x) | U8StrUD(x) | RStrUD(x) | LRStrUD(x) 184 | | URStrUD(x) | UURStrUD(x) | U8RStrUD(x) => format!("\"{}\"{}", x.0, x.1), 185 | } 186 | } 187 | } 188 | 189 | impl Dump for Str { 190 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 191 | dump_str!(name, self.to_string(), prefix, last, stdout); 192 | } 193 | } 194 | 195 | #[derive(Clone, Debug, PartialEq)] 196 | pub struct Bool { 197 | pub value: bool, 198 | } 199 | 200 | impl ToString for Bool { 201 | fn to_string(&self) -> String { 202 | if self.value { 203 | "true".to_string() 204 | } else { 205 | "false".to_string() 206 | } 207 | } 208 | } 209 | 210 | impl Dump for Bool { 211 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 212 | dump_str!(name, self.to_string(), prefix, last, stdout); 213 | } 214 | } 215 | 216 | pub(crate) struct StringLiteralParser<'a, L: TLexer> { 217 | lexer: &'a mut L, 218 | } 219 | 220 | impl<'a, L: TLexer> StringLiteralParser<'a, L> { 221 | pub(crate) fn new(lexer: &'a mut L) -> Self { 222 | Self { lexer } 223 | } 224 | 225 | #[inline(always)] 226 | fn concat(first: &str, lens: usize, strings: Vec) -> String { 227 | let mut res = String::with_capacity(lens + first.len() + 1); 228 | res.push_str(first); 229 | for s in strings { 230 | res.push_str(&s); 231 | } 232 | res 233 | } 234 | 235 | pub(crate) fn parse( 236 | self, 237 | first: &str, 238 | _context: &mut Context, 239 | ) -> Result<(Option, String), ParserError> { 240 | let mut strings = Vec::with_capacity(32); // TODO: put a good value here if it's useful 241 | let mut lens = 0; 242 | 243 | let tok = loop { 244 | let tok = self.lexer.next_useful(); 245 | match tok { 246 | Token::LiteralString(s) 247 | | Token::LiteralLString(s) 248 | | Token::LiteralUString(s) 249 | | Token::LiteralUUString(s) 250 | | Token::LiteralU8String(s) 251 | | Token::LiteralRString(s) 252 | | Token::LiteralLRString(s) 253 | | Token::LiteralURString(s) 254 | | Token::LiteralUURString(s) 255 | | Token::LiteralU8RString(s) => { 256 | lens += s.len(); 257 | strings.push(s); 258 | } 259 | Token::LiteralStringUD(s_suf) 260 | | Token::LiteralLStringUD(s_suf) 261 | | Token::LiteralUStringUD(s_suf) 262 | | Token::LiteralUUStringUD(s_suf) 263 | | Token::LiteralU8StringUD(s_suf) 264 | | Token::LiteralRStringUD(s_suf) 265 | | Token::LiteralLRStringUD(s_suf) 266 | | Token::LiteralURStringUD(s_suf) 267 | | Token::LiteralUURStringUD(s_suf) 268 | | Token::LiteralU8RStringUD(s_suf) => { 269 | lens += s_suf.0.len(); 270 | strings.push(s_suf.0); 271 | } 272 | _ => { 273 | break tok; 274 | } 275 | } 276 | }; 277 | 278 | Ok((Some(tok), Self::concat(first, lens, strings))) 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /src/parser/mod.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | pub mod dump; 7 | pub use self::dump::*; 8 | 9 | #[macro_use] 10 | pub mod names; 11 | pub use self::names::*; 12 | 13 | pub mod types; 14 | pub use self::types::*; 15 | 16 | pub mod declarations; 17 | pub use self::declarations::*; 18 | 19 | #[macro_use] 20 | pub mod expressions; 21 | pub use self::expressions::*; 22 | 23 | pub mod attributes; 24 | pub use self::attributes::*; 25 | 26 | pub mod statements; 27 | pub use self::statements::*; 28 | 29 | pub mod initializer; 30 | pub use self::initializer::*; 31 | 32 | pub mod literals; 33 | pub use self::literals::*; 34 | 35 | pub mod context; 36 | pub use self::context::*; 37 | 38 | pub mod unit; 39 | pub use self::unit::*; 40 | 41 | pub mod errors; 42 | 43 | /* 44 | pub mod parser; 45 | pub use self::parser::*; 46 | */ 47 | -------------------------------------------------------------------------------- /src/parser/names/dtor.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use crate::lexer::{TLexer, Token}; 7 | use crate::parser::errors::ParserError; 8 | use crate::parser::Context; 9 | 10 | #[derive(Clone, Debug, PartialEq, Hash)] 11 | pub struct Destructor { 12 | pub name: String, 13 | } 14 | 15 | pub(crate) struct DtorParser<'a, L: TLexer> { 16 | lexer: &'a mut L, 17 | } 18 | 19 | impl<'a, L: TLexer> DtorParser<'a, L> { 20 | pub(crate) fn new(lexer: &'a mut L) -> Self { 21 | Self { lexer } 22 | } 23 | 24 | pub(crate) fn parse( 25 | self, 26 | tok: Option, 27 | _context: &mut Context, 28 | ) -> Result<(Option, Option), ParserError> { 29 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 30 | if tok != Token::Tilde { 31 | return Ok((Some(tok), None)); 32 | } 33 | 34 | let tok = self.lexer.next_useful(); 35 | if let Token::Identifier(name) = tok { 36 | Ok((None, Some(Destructor { name }))) 37 | } else { 38 | Err(ParserError::InvalidTokenInDtor { 39 | sp: self.lexer.span(), 40 | tok, 41 | }) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/parser/names/mod.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | #[macro_use] 7 | pub mod name; 8 | pub use self::name::*; 9 | 10 | pub mod operator; 11 | pub use self::operator::*; 12 | 13 | pub mod dtor; 14 | pub use self::dtor::*; 15 | -------------------------------------------------------------------------------- /src/parser/names/name.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use super::dtor::{Destructor, DtorParser}; 9 | use super::operator::{Operator, OperatorParser}; 10 | use crate::lexer::{TLexer, Token}; 11 | use crate::parser::dump::Dump; 12 | use crate::parser::errors::ParserError; 13 | use crate::parser::expressions::{Parameters, ParametersParser}; 14 | use crate::parser::Context; 15 | 16 | #[derive(Clone, Debug, PartialEq, Hash)] 17 | pub struct Identifier { 18 | pub val: String, 19 | } 20 | 21 | #[derive(Clone, Debug, PartialEq)] 22 | pub struct Template { 23 | id: Identifier, 24 | params: Parameters, 25 | //keyword: bool, TODO: set to true when we've A::template B<...>::... 26 | } 27 | 28 | #[derive(Clone, Debug, PartialEq, Hash)] 29 | pub enum Name { 30 | Identifier(Identifier), 31 | Destructor(Destructor), 32 | //Template(Template), 33 | Operator(Box), 34 | Empty, 35 | //Decltype(ExprNode), TODO: add that 36 | } 37 | 38 | impl AsRef for Name { 39 | fn as_ref(&self) -> &str { 40 | match self { 41 | Name::Identifier(id) => &id.val, 42 | _ => "", 43 | } 44 | } 45 | } 46 | 47 | impl Eq for Name {} 48 | 49 | impl ToString for Name { 50 | fn to_string(&self) -> String { 51 | match self { 52 | Name::Identifier(id) => id.val.clone(), 53 | //Name::Template(t) => t.id.val.clone(), 54 | Name::Destructor(d) => format!("~{}", d.name), 55 | Name::Operator(op) => op.to_string(), 56 | Name::Empty => "".to_string(), 57 | } 58 | } 59 | } 60 | 61 | #[macro_export] 62 | macro_rules! mk_id { 63 | ( $( $name:expr ),* ) => { 64 | Qualified { 65 | names: vec![ 66 | $( 67 | crate::parser::names::Name::Identifier(crate::parser::names::Identifier { val: $name.to_string()}), 68 | )* 69 | ], 70 | } 71 | } 72 | } 73 | 74 | #[derive(Clone, Debug, PartialEq, Hash)] 75 | pub struct Qualified { 76 | pub names: Vec, 77 | } 78 | 79 | impl ToString for Qualified { 80 | fn to_string(&self) -> String { 81 | let mut buf = String::new(); 82 | if let Some((last, names)) = self.names.split_last() { 83 | for name in names.iter() { 84 | buf.push_str(&name.to_string()); 85 | buf.push_str("::"); 86 | } 87 | buf.push_str(&last.to_string()); 88 | } 89 | buf 90 | } 91 | } 92 | 93 | impl Dump for Qualified { 94 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 95 | dump_str!(name, self.to_string(), prefix, last, stdout); 96 | } 97 | } 98 | 99 | impl Qualified { 100 | pub fn is_conv_op(&self) -> bool { 101 | if let Name::Operator(op) = self.names.last().unwrap() { 102 | op.is_conv() 103 | } else { 104 | false 105 | } 106 | } 107 | 108 | pub fn get_first_name(mut self) -> String { 109 | if let Name::Identifier(id) = self.names.pop().unwrap() { 110 | id.val 111 | } else { 112 | unreachable!("Not a valid identifier"); 113 | } 114 | } 115 | 116 | pub fn len(&self) -> usize { 117 | self.names.len() 118 | } 119 | } 120 | 121 | pub struct QualifiedParser<'a, L: TLexer> { 122 | lexer: &'a mut L, 123 | } 124 | 125 | impl<'a, L: TLexer> QualifiedParser<'a, L> { 126 | pub(crate) fn new(lexer: &'a mut L) -> Self { 127 | Self { lexer } 128 | } 129 | 130 | pub(crate) fn parse( 131 | self, 132 | tok: Option, 133 | first: Option, 134 | context: &mut Context, 135 | ) -> Result<(Option, Option), ParserError> { 136 | let mut tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 137 | let mut names = Vec::new(); 138 | let mut wait_id = if let Some(val) = first { 139 | names.push(Name::Identifier(Identifier { val })); 140 | false 141 | } else { 142 | true 143 | }; 144 | 145 | loop { 146 | match tok { 147 | Token::ColonColon => { 148 | if names.is_empty() { 149 | // ::foo::bar 150 | names.push(Name::Empty); 151 | } 152 | wait_id = true; 153 | } 154 | /*Token::Lower => { 155 | let id = if let Some(Name::Identifier(id)) = names.pop() { 156 | id 157 | } else { 158 | unreachable!("Cannot have two templates args"); 159 | }; 160 | 161 | let pp = ParametersParser::new(self.lexer, Token::Greater); 162 | let (_, params) = pp.parse(None, None); 163 | 164 | names.push(Name::Template(Template { 165 | id, 166 | params: params.unwrap(), 167 | })); 168 | 169 | wait_id = false; 170 | }*/ 171 | Token::Identifier(val) if wait_id => { 172 | names.push(Name::Identifier(Identifier { val })); 173 | wait_id = false; 174 | } 175 | Token::Identifier(_) if !wait_id => { 176 | return Ok((Some(tok), Some(Qualified { names }))); 177 | } 178 | Token::Operator => { 179 | let op = OperatorParser::new(self.lexer); 180 | let (tok, operator) = op.parse(Some(tok), context)?; 181 | 182 | names.push(Name::Operator(Box::new(operator.unwrap()))); 183 | 184 | return Ok((tok, Some(Qualified { names }))); 185 | } 186 | Token::Tilde => { 187 | if wait_id { 188 | let dp = DtorParser::new(self.lexer); 189 | let (tok, dtor) = dp.parse(Some(tok), context)?; 190 | 191 | names.push(Name::Destructor(dtor.unwrap())); 192 | return Ok((tok, Some(Qualified { names }))); 193 | } else { 194 | return Ok((Some(tok), Some(Qualified { names }))); 195 | } 196 | } 197 | _ => { 198 | if names.is_empty() { 199 | return Ok((Some(tok), None)); 200 | } else { 201 | return Ok((Some(tok), Some(Qualified { names }))); 202 | } 203 | } 204 | } 205 | tok = self.lexer.next_useful(); 206 | } 207 | } 208 | } 209 | 210 | #[cfg(test)] 211 | mod tests { 212 | 213 | use super::*; 214 | use crate::lexer::{preprocessor::context::DefaultContext, Lexer}; 215 | use pretty_assertions::assert_eq; 216 | 217 | #[test] 218 | fn test_name_one() { 219 | let mut l = Lexer::::new(b"abc"); 220 | let p = QualifiedParser::new(&mut l); 221 | let mut context = Context::default(); 222 | let (_, q) = p.parse(None, None, &mut context).unwrap(); 223 | 224 | assert_eq!(q.unwrap(), mk_id!("abc")); 225 | } 226 | 227 | #[test] 228 | fn test_name_two() { 229 | let mut l = Lexer::::new(b"abc::defg"); 230 | let p = QualifiedParser::new(&mut l); 231 | let mut context = Context::default(); 232 | let (_, q) = p.parse(None, None, &mut context).unwrap(); 233 | 234 | assert_eq!(q.unwrap(), mk_id!("abc", "defg")); 235 | } 236 | 237 | #[test] 238 | fn test_name_three() { 239 | let mut l = Lexer::::new(b"abc::defg::hijkl"); 240 | let p = QualifiedParser::new(&mut l); 241 | let mut context = Context::default(); 242 | let (_, q) = p.parse(None, None, &mut context).unwrap(); 243 | 244 | assert_eq!(q.unwrap(), mk_id!("abc", "defg", "hijkl")); 245 | } 246 | 247 | /*#[test] 248 | fn test_name_template_zero() { 249 | let mut l = Lexer::::new(b"A<>"); 250 | let p = QualifiedParser::new(&mut l); 251 | let (_, q) = p.parse(None, None); 252 | 253 | assert_eq!( 254 | q.unwrap(), 255 | Qualified { 256 | names: vec![Name::Template(Template { 257 | id: Identifier { 258 | val: "A".to_string() 259 | }, 260 | params: vec![], 261 | }),], 262 | } 263 | ); 264 | } 265 | 266 | #[test] 267 | fn test_name_template_one() { 268 | let mut l = Lexer::::new(b"A"); 269 | let p = QualifiedParser::new(&mut l); 270 | let (_, q) = p.parse(None, None); 271 | 272 | assert_eq!( 273 | q.unwrap(), 274 | Qualified { 275 | names: vec![Name::Template(Template { 276 | id: Identifier { 277 | val: "A".to_string() 278 | }, 279 | params: vec![Some(ExprNode::Qualified(Box::new(mk_id!("B")))),], 280 | }),], 281 | } 282 | ); 283 | } 284 | 285 | #[test] 286 | fn test_name_complex() { 287 | let mut l = Lexer::::new(b"A::B::H"); 288 | let p = QualifiedParser::new(&mut l); 289 | let (_, q) = p.parse(None, None); 290 | 291 | assert_eq!( 292 | q.unwrap(), 293 | Qualified { 294 | names: vec![ 295 | Name::Identifier(Identifier { 296 | val: "A".to_string(), 297 | }), 298 | Name::Template(Template { 299 | id: Identifier { 300 | val: "B".to_string() 301 | }, 302 | params: vec![ 303 | Some(ExprNode::Qualified(Box::new(mk_id!("C", "D")))), 304 | Some(ExprNode::Qualified(Box::new(mk_id!("E", "F")))), 305 | Some(ExprNode::Qualified(Box::new(mk_id!("G")))), 306 | ] 307 | }), 308 | Name::Template(Template { 309 | id: Identifier { 310 | val: "H".to_string() 311 | }, 312 | params: vec![Some(ExprNode::Qualified(Box::new(mk_id!("I")))),] 313 | }) 314 | ] 315 | } 316 | ); 317 | }*/ 318 | } 319 | -------------------------------------------------------------------------------- /src/parser/statements/compound.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use super::{Statement, StatementParser}; 9 | use crate::lexer::lexer::{TLexer, Token}; 10 | use crate::parser::attributes::Attributes; 11 | use crate::parser::dump::Dump; 12 | use crate::parser::errors::ParserError; 13 | use crate::parser::{Context, ScopeKind}; 14 | 15 | #[derive(Clone, Debug, Default, PartialEq)] 16 | pub struct Compound { 17 | pub(crate) attributes: Option, 18 | pub(crate) stmts: Vec, 19 | } 20 | 21 | impl Dump for Compound { 22 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 23 | let prefix = dump_start!(name, "compound", prefix, last, stdout); 24 | self.attributes 25 | .dump("attributes", &prefix, self.stmts.is_empty(), stdout); 26 | 27 | let mut count = 1; 28 | if let Some((last, stmts)) = self.stmts.split_last() { 29 | for stmt in stmts.iter() { 30 | stmt.dump(&format!("stmt{}", count), &prefix, false, stdout); 31 | count += 1; 32 | } 33 | last.dump(&format!("stmt{}", count), &prefix, true, stdout); 34 | } 35 | } 36 | } 37 | 38 | pub struct CompoundStmtParser<'a, L: TLexer> { 39 | lexer: &'a mut L, 40 | } 41 | 42 | impl<'a, L: TLexer> CompoundStmtParser<'a, L> { 43 | pub(crate) fn new(lexer: &'a mut L) -> Self { 44 | Self { lexer } 45 | } 46 | 47 | pub(crate) fn parse( 48 | self, 49 | attributes: Option, 50 | context: &mut Context, 51 | ) -> Result<(Option, Option), ParserError> { 52 | let mut stmts = Vec::new(); 53 | let mut tok = self.lexer.next_useful(); 54 | context.set_current(None, ScopeKind::Block); 55 | 56 | loop { 57 | if tok == Token::RightBrace || tok == Token::Eof { 58 | context.pop(); 59 | return Ok((None, Some(Compound { attributes, stmts }))); 60 | } 61 | 62 | let sp = StatementParser::new(self.lexer); 63 | let (tk, stmt) = sp.parse(Some(tok), context)?; 64 | 65 | if let Some(stmt) = stmt { 66 | stmts.push(stmt); 67 | } 68 | 69 | tok = tk.unwrap_or_else(|| self.lexer.next_useful()); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/parser/statements/do.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use super::{Statement, StatementParser}; 9 | use crate::lexer::lexer::{TLexer, Token}; 10 | use crate::parser::attributes::Attributes; 11 | use crate::parser::dump::Dump; 12 | use crate::parser::errors::ParserError; 13 | use crate::parser::expressions::{ExprNode, ExpressionParser}; 14 | use crate::parser::{Context, ScopeKind}; 15 | 16 | #[derive(Clone, Debug, PartialEq)] 17 | pub struct Do { 18 | pub attributes: Option, 19 | pub body: Statement, 20 | pub condition: ExprNode, 21 | } 22 | 23 | impl Dump for Do { 24 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 25 | dump_obj!(self, name, "do", prefix, last, stdout, attributes, body, condition); 26 | } 27 | } 28 | 29 | pub struct DoStmtParser<'a, L: TLexer> { 30 | lexer: &'a mut L, 31 | } 32 | 33 | impl<'a, L: TLexer> DoStmtParser<'a, L> { 34 | pub(super) fn new(lexer: &'a mut L) -> Self { 35 | Self { lexer } 36 | } 37 | 38 | pub(super) fn parse( 39 | self, 40 | attributes: Option, 41 | context: &mut Context, 42 | ) -> Result<(Option, Option), ParserError> { 43 | context.set_current(None, ScopeKind::DoBlock); 44 | let sp = StatementParser::new(self.lexer); 45 | let (tok, body) = sp.parse(None, context)?; 46 | context.pop(); 47 | 48 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 49 | if tok != Token::While { 50 | return Err(ParserError::InvalidTokenInDo { 51 | sp: self.lexer.span(), 52 | tok, 53 | }); 54 | } 55 | 56 | let tok = self.lexer.next_useful(); 57 | if tok != Token::LeftParen { 58 | return Err(ParserError::InvalidTokenInDo { 59 | sp: self.lexer.span(), 60 | tok, 61 | }); 62 | } 63 | 64 | let mut ep = ExpressionParser::new(self.lexer, Token::RightParen); 65 | let (tok, condition) = ep.parse(None, context)?; 66 | 67 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 68 | if tok != Token::RightParen { 69 | return Err(ParserError::InvalidTokenInDo { 70 | sp: self.lexer.span(), 71 | tok, 72 | }); 73 | } 74 | 75 | let tok = self.lexer.next_useful(); 76 | match tok { 77 | Token::SemiColon => Ok(( 78 | None, 79 | Some(Do { 80 | attributes, 81 | body: body.unwrap(), 82 | condition: condition.unwrap(), 83 | }), 84 | )), 85 | _ => Err(ParserError::InvalidTokenInDo { 86 | sp: self.lexer.span(), 87 | tok, 88 | }), 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/parser/statements/for.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use std::rc::Rc; 7 | use termcolor::StandardStreamLock; 8 | 9 | use super::{Statement, StatementParser}; 10 | use crate::lexer::lexer::{TLexer, Token}; 11 | use crate::parser::attributes::Attributes; 12 | use crate::parser::declarations::{DeclOrExpr, DeclOrExprParser, TypeDeclarator}; 13 | use crate::parser::dump::Dump; 14 | use crate::parser::errors::ParserError; 15 | use crate::parser::expressions::{ExprNode, ExpressionParser}; 16 | use crate::parser::{Context, ScopeKind}; 17 | 18 | #[derive(Clone, Debug, PartialEq)] 19 | pub struct For { 20 | pub attributes: Option, 21 | pub init: Option, 22 | pub condition: Option, 23 | pub iteration: Option, 24 | pub body: Statement, 25 | } 26 | 27 | impl Dump for For { 28 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 29 | dump_obj!( 30 | self, name, "for", prefix, last, stdout, attributes, init, condition, iteration, body 31 | ); 32 | } 33 | } 34 | 35 | #[derive(Clone, Debug, PartialEq)] 36 | pub struct ForRange { 37 | pub attributes: Option, 38 | pub init: Option, 39 | pub decl: Rc, 40 | pub expr: ExprNode, 41 | pub body: Statement, 42 | } 43 | 44 | impl Dump for ForRange { 45 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 46 | dump_obj!( 47 | self, 48 | name, 49 | "for-range", 50 | prefix, 51 | last, 52 | stdout, 53 | attributes, 54 | init, 55 | decl, 56 | expr, 57 | body 58 | ); 59 | } 60 | } 61 | 62 | pub(super) enum ForRes { 63 | Normal(For), 64 | Range(ForRange), 65 | } 66 | 67 | pub struct ForStmtParser<'a, L: TLexer> { 68 | lexer: &'a mut L, 69 | } 70 | 71 | impl<'a, L: TLexer> ForStmtParser<'a, L> { 72 | pub(super) fn new(lexer: &'a mut L) -> Self { 73 | Self { lexer } 74 | } 75 | 76 | pub(super) fn parse( 77 | self, 78 | attributes: Option, 79 | context: &mut Context, 80 | ) -> Result<(Option, Option), ParserError> { 81 | let tok = self.lexer.next_useful(); 82 | 83 | if tok != Token::LeftParen { 84 | return Err(ParserError::InvalidTokenInFor { 85 | sp: self.lexer.span(), 86 | tok, 87 | }); 88 | } 89 | 90 | context.set_current(None, ScopeKind::ForBlock); 91 | 92 | let dep = DeclOrExprParser::new(self.lexer); 93 | let (tok, init) = dep.parse(None, context)?; 94 | 95 | if let Some(DeclOrExpr::Decl(typ)) = init.as_ref() { 96 | context.add_type_decl(Rc::clone(typ)); 97 | } 98 | 99 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 100 | if tok == Token::Colon { 101 | // for (decl : ...) 102 | let decl = if let DeclOrExpr::Decl(typ) = init.unwrap() { 103 | context.add_type_decl(Rc::clone(&typ)); 104 | typ 105 | } else { 106 | context.pop(); 107 | return Err(ParserError::InvalidExprInFor { 108 | sp: self.lexer.span(), 109 | }); 110 | }; 111 | 112 | let mut ep = ExpressionParser::new(self.lexer, Token::RightParen); 113 | let (tok, expr) = ep.parse(None, context)?; 114 | 115 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 116 | if tok != Token::RightParen { 117 | context.pop(); 118 | return Err(ParserError::InvalidTokenInFor { 119 | sp: self.lexer.span(), 120 | tok, 121 | }); 122 | } 123 | 124 | let sp = StatementParser::new(self.lexer); 125 | let (tok, body) = sp.parse(None, context)?; 126 | context.pop(); 127 | 128 | return Ok(( 129 | tok, 130 | Some(ForRes::Range(ForRange { 131 | attributes, 132 | init: None, 133 | decl, 134 | expr: expr.unwrap(), 135 | body: body.unwrap(), 136 | })), 137 | )); 138 | } 139 | 140 | if tok != Token::SemiColon { 141 | context.pop(); 142 | return Err(ParserError::InvalidTokenInFor { 143 | sp: self.lexer.span(), 144 | tok, 145 | }); 146 | } 147 | 148 | let dep = DeclOrExprParser::new(self.lexer); 149 | let (tok, condition) = dep.parse(None, context)?; 150 | 151 | if let Some(DeclOrExpr::Decl(typ)) = condition.as_ref() { 152 | context.add_type_decl(Rc::clone(typ)); 153 | } 154 | 155 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 156 | if tok == Token::Colon { 157 | // for (init; decl : ...) 158 | let decl = if let DeclOrExpr::Decl(typ) = condition.unwrap() { 159 | typ 160 | } else { 161 | context.pop(); 162 | return Err(ParserError::InvalidExprInFor { 163 | sp: self.lexer.span(), 164 | }); 165 | }; 166 | 167 | let mut ep = ExpressionParser::new(self.lexer, Token::RightParen); 168 | let (tok, expr) = ep.parse(None, context)?; 169 | 170 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 171 | if tok != Token::RightParen { 172 | context.pop(); 173 | return Err(ParserError::InvalidTokenInFor { 174 | sp: self.lexer.span(), 175 | tok, 176 | }); 177 | } 178 | 179 | let sp = StatementParser::new(self.lexer); 180 | let (tok, body) = sp.parse(None, context)?; 181 | context.pop(); 182 | 183 | return Ok(( 184 | tok, 185 | Some(ForRes::Range(ForRange { 186 | attributes, 187 | init, 188 | decl, 189 | expr: expr.unwrap(), 190 | body: body.unwrap(), 191 | })), 192 | )); 193 | } 194 | 195 | // we're in a classic for loop so the condition is an expression 196 | let condition = if let Some(cond) = condition { 197 | if let DeclOrExpr::Expr(cond) = cond { 198 | Some(cond) 199 | } else { 200 | context.pop(); 201 | return Err(ParserError::InvalidExprInFor { 202 | sp: self.lexer.span(), 203 | }); 204 | } 205 | } else { 206 | None 207 | }; 208 | 209 | if tok != Token::SemiColon { 210 | context.pop(); 211 | return Err(ParserError::InvalidTokenInFor { 212 | sp: self.lexer.span(), 213 | tok, 214 | }); 215 | } 216 | 217 | let mut ep = ExpressionParser::new(self.lexer, Token::RightParen); 218 | let (tok, iteration) = ep.parse(None, context)?; 219 | 220 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 221 | if tok != Token::RightParen { 222 | context.pop(); 223 | return Err(ParserError::InvalidTokenInFor { 224 | sp: self.lexer.span(), 225 | tok, 226 | }); 227 | } 228 | 229 | let sp = StatementParser::new(self.lexer); 230 | let (tok, body) = sp.parse(None, context)?; 231 | context.pop(); 232 | 233 | Ok(( 234 | tok, 235 | Some(ForRes::Normal(For { 236 | attributes, 237 | init, 238 | condition, 239 | iteration, 240 | body: body.unwrap(), 241 | })), 242 | )) 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/parser/statements/goto.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use crate::lexer::lexer::{TLexer, Token}; 9 | use crate::parser::attributes::Attributes; 10 | use crate::parser::dump::Dump; 11 | use crate::parser::errors::ParserError; 12 | use crate::parser::expressions::{ExprNode, ExpressionParser}; 13 | use crate::parser::Context; 14 | 15 | #[derive(Clone, Debug, PartialEq)] 16 | pub enum Label { 17 | Id(String), 18 | Expr(ExprNode), 19 | } 20 | 21 | impl Dump for Label { 22 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 23 | match self { 24 | Self::Id(l) => l.dump(name, prefix, last, stdout), 25 | Self::Expr(l) => l.dump(name, prefix, last, stdout), 26 | } 27 | } 28 | } 29 | 30 | #[derive(Clone, Debug, PartialEq)] 31 | pub struct Goto { 32 | pub(crate) attributes: Option, 33 | pub(crate) label: Label, 34 | } 35 | 36 | impl Dump for Goto { 37 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 38 | dump_obj!(self, name, "goto", prefix, last, stdout, attributes, label); 39 | } 40 | } 41 | 42 | pub struct GotoStmtParser<'a, L: TLexer> { 43 | lexer: &'a mut L, 44 | } 45 | 46 | impl<'a, L: TLexer> GotoStmtParser<'a, L> { 47 | pub(super) fn new(lexer: &'a mut L) -> Self { 48 | Self { lexer } 49 | } 50 | 51 | pub(super) fn parse( 52 | self, 53 | attributes: Option, 54 | context: &mut Context, 55 | ) -> Result<(Option, Option), ParserError> { 56 | let tok = self.lexer.next_useful(); 57 | 58 | match tok { 59 | Token::Identifier(id) => Ok(( 60 | None, 61 | Some(Goto { 62 | attributes, 63 | label: Label::Id(id), 64 | }), 65 | )), 66 | Token::Star => { 67 | let mut ep = ExpressionParser::new(self.lexer, Token::SemiColon); 68 | let (tok, expr) = ep.parse(Some(tok), context)?; 69 | 70 | Ok(( 71 | tok, 72 | Some(Goto { 73 | attributes, 74 | label: Label::Expr(expr.unwrap()), 75 | }), 76 | )) 77 | } 78 | _ => Err(ParserError::InvalidTokenInGoto { 79 | sp: self.lexer.span(), 80 | tok, 81 | }), 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/parser/statements/if.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use super::{Statement, StatementParser}; 9 | use crate::lexer::lexer::{TLexer, Token}; 10 | use crate::parser::attributes::Attributes; 11 | use crate::parser::dump::Dump; 12 | use crate::parser::errors::ParserError; 13 | use crate::parser::expressions::{ExprNode, ExpressionParser}; 14 | use crate::parser::Context; 15 | 16 | #[derive(Clone, Debug, PartialEq)] 17 | pub struct If { 18 | pub attributes: Option, 19 | pub constexpr: bool, 20 | pub condition: ExprNode, 21 | pub then: Statement, 22 | pub r#else: Option, 23 | } 24 | 25 | impl Dump for If { 26 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 27 | dump_obj!( 28 | self, name, "if", prefix, last, stdout, attributes, constexpr, condition, then, r#else 29 | ); 30 | } 31 | } 32 | 33 | pub struct IfStmtParser<'a, L: TLexer> { 34 | lexer: &'a mut L, 35 | } 36 | 37 | impl<'a, L: TLexer> IfStmtParser<'a, L> { 38 | pub(super) fn new(lexer: &'a mut L) -> Self { 39 | Self { lexer } 40 | } 41 | 42 | pub(super) fn parse( 43 | self, 44 | attributes: Option, 45 | context: &mut Context, 46 | ) -> Result<(Option, Option), ParserError> { 47 | let mut tok = self.lexer.next_useful(); 48 | let constexpr = if tok == Token::Constexpr { 49 | tok = self.lexer.next_useful(); 50 | true 51 | } else { 52 | false 53 | }; 54 | 55 | if tok != Token::LeftParen { 56 | return Err(ParserError::InvalidTokenInIf { 57 | sp: self.lexer.span(), 58 | tok, 59 | }); 60 | } 61 | 62 | let mut ep = ExpressionParser::new(self.lexer, Token::RightParen); 63 | let (tok, condition) = ep.parse(None, context)?; 64 | 65 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 66 | if tok != Token::RightParen { 67 | return Err(ParserError::InvalidTokenInIf { 68 | sp: self.lexer.span(), 69 | tok, 70 | }); 71 | } 72 | 73 | let sp = StatementParser::new(self.lexer); 74 | let (tok, then) = sp.parse(None, context)?; 75 | 76 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 77 | 78 | let (tok, r#else) = if tok == Token::Else { 79 | let sp = StatementParser::new(self.lexer); 80 | sp.parse(None, context)? 81 | } else { 82 | (Some(tok), None) 83 | }; 84 | 85 | Ok(( 86 | tok, 87 | Some(If { 88 | attributes, 89 | constexpr, 90 | condition: condition.unwrap(), 91 | then: then.unwrap(), 92 | r#else, 93 | }), 94 | )) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/parser/statements/mod.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | pub mod r#return; 7 | pub use self::r#return::*; 8 | 9 | pub mod compound; 10 | pub use self::compound::*; 11 | 12 | #[macro_use] 13 | pub mod stmt; 14 | pub use self::stmt::*; 15 | 16 | pub mod r#if; 17 | pub use self::r#if::*; 18 | 19 | pub mod switch; 20 | pub use self::switch::*; 21 | 22 | pub mod r#do; 23 | pub use self::r#do::*; 24 | 25 | pub mod r#while; 26 | pub use self::r#while::*; 27 | 28 | pub mod goto; 29 | pub use self::goto::*; 30 | 31 | pub mod r#try; 32 | pub use self::r#try::*; 33 | 34 | pub mod r#for; 35 | pub use self::r#for::*; 36 | -------------------------------------------------------------------------------- /src/parser/statements/return.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use crate::lexer::lexer::{TLexer, Token}; 9 | use crate::parser::attributes::Attributes; 10 | use crate::parser::dump::Dump; 11 | use crate::parser::errors::ParserError; 12 | use crate::parser::expressions::{ExprNode, ExpressionParser}; 13 | use crate::parser::Context; 14 | 15 | #[derive(Clone, Debug, PartialEq)] 16 | pub struct Return { 17 | pub(crate) attributes: Option, 18 | pub(crate) val: Option, 19 | } 20 | 21 | impl Dump for Return { 22 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 23 | dump_obj!(self, name, "return", prefix, last, stdout, attributes, val); 24 | } 25 | } 26 | 27 | pub struct ReturnStmtParser<'a, L: TLexer> { 28 | lexer: &'a mut L, 29 | } 30 | 31 | impl<'a, L: TLexer> ReturnStmtParser<'a, L> { 32 | pub(super) fn new(lexer: &'a mut L) -> Self { 33 | Self { lexer } 34 | } 35 | 36 | pub(super) fn parse( 37 | self, 38 | attributes: Option, 39 | context: &mut Context, 40 | ) -> Result<(Option, Option), ParserError> { 41 | let mut ep = ExpressionParser::new(self.lexer, Token::Eof); 42 | let (tok, expr) = ep.parse(None, context)?; 43 | 44 | Ok(( 45 | tok, 46 | Some(Return { 47 | attributes, 48 | val: expr, 49 | }), 50 | )) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/parser/statements/switch.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use std::rc::Rc; 7 | use termcolor::StandardStreamLock; 8 | 9 | use super::{Statement, StatementParser}; 10 | use crate::lexer::lexer::{TLexer, Token}; 11 | use crate::parser::attributes::Attributes; 12 | use crate::parser::declarations::{DeclOrExpr, DeclOrExprParser}; 13 | use crate::parser::dump::Dump; 14 | use crate::parser::errors::ParserError; 15 | use crate::parser::expressions::{ExprNode, ExpressionParser}; 16 | use crate::parser::{Context, ScopeKind}; 17 | 18 | #[derive(Clone, Debug, PartialEq)] 19 | pub struct Switch { 20 | pub attributes: Option, 21 | pub condition: DeclOrExpr, 22 | pub cases: Statement, 23 | } 24 | 25 | impl Dump for Switch { 26 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 27 | dump_obj!(self, name, "switch", prefix, last, stdout, attributes, condition, cases); 28 | } 29 | } 30 | 31 | pub struct SwitchStmtParser<'a, L: TLexer> { 32 | lexer: &'a mut L, 33 | } 34 | 35 | impl<'a, L: TLexer> SwitchStmtParser<'a, L> { 36 | pub(super) fn new(lexer: &'a mut L) -> Self { 37 | Self { lexer } 38 | } 39 | 40 | pub(super) fn parse( 41 | self, 42 | attributes: Option, 43 | context: &mut Context, 44 | ) -> Result<(Option, Option), ParserError> { 45 | let tok = self.lexer.next_useful(); 46 | if tok != Token::LeftParen { 47 | return Err(ParserError::InvalidTokenInSwitch { 48 | sp: self.lexer.span(), 49 | tok, 50 | }); 51 | } 52 | 53 | context.set_current(None, ScopeKind::SwitchBlock); 54 | 55 | let dep = DeclOrExprParser::new(self.lexer); 56 | let (tok, condition) = dep.parse(None, context)?; 57 | 58 | if let Some(DeclOrExpr::Decl(typ)) = condition.as_ref() { 59 | context.add_type_decl(Rc::clone(typ)); 60 | } 61 | 62 | if let Some(tok) = tok { 63 | if tok != Token::RightParen { 64 | context.pop(); 65 | return Err(ParserError::InvalidTokenInSwitch { 66 | sp: self.lexer.span(), 67 | tok, 68 | }); 69 | } 70 | } 71 | 72 | let sp = StatementParser::new(self.lexer); 73 | let (tok, cases) = sp.parse(None, context)?; 74 | context.pop(); 75 | 76 | Ok(( 77 | tok, 78 | Some(Switch { 79 | attributes, 80 | condition: condition.unwrap(), 81 | cases: cases.unwrap(), 82 | }), 83 | )) 84 | } 85 | } 86 | 87 | #[derive(Clone, Debug, PartialEq)] 88 | pub struct Case { 89 | pub attributes: Option, 90 | pub value: ExprNode, 91 | } 92 | 93 | impl Dump for Case { 94 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 95 | dump_obj!(self, name, "case", prefix, last, stdout, attributes, value); 96 | } 97 | } 98 | 99 | pub struct CaseStmtParser<'a, L: TLexer> { 100 | lexer: &'a mut L, 101 | } 102 | 103 | impl<'a, L: TLexer> CaseStmtParser<'a, L> { 104 | pub(super) fn new(lexer: &'a mut L) -> Self { 105 | Self { lexer } 106 | } 107 | 108 | pub(super) fn parse( 109 | self, 110 | attributes: Option, 111 | context: &mut Context, 112 | ) -> Result<(Option, Option), ParserError> { 113 | let mut ep = ExpressionParser::new(self.lexer, Token::Eof); 114 | let (tok, value) = ep.parse(None, context)?; 115 | 116 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 117 | if tok != Token::Colon { 118 | return Err(ParserError::InvalidTokenInSwitch { 119 | sp: self.lexer.span(), 120 | tok, 121 | }); 122 | } 123 | 124 | Ok(( 125 | None, 126 | Some(Case { 127 | attributes, 128 | value: value.unwrap(), 129 | }), 130 | )) 131 | } 132 | } 133 | 134 | #[derive(Clone, Debug, PartialEq)] 135 | pub struct Default { 136 | pub attributes: Option, 137 | } 138 | 139 | impl Dump for Default { 140 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 141 | dump_obj!(self, name, "default", prefix, last, stdout, attributes); 142 | } 143 | } 144 | 145 | pub struct DefaultStmtParser<'a, L: TLexer> { 146 | lexer: &'a mut L, 147 | } 148 | 149 | impl<'a, L: TLexer> DefaultStmtParser<'a, L> { 150 | pub(super) fn new(lexer: &'a mut L) -> Self { 151 | Self { lexer } 152 | } 153 | 154 | pub(super) fn parse( 155 | self, 156 | attributes: Option, 157 | _context: &mut Context, 158 | ) -> Result<(Option, Option), ParserError> { 159 | let tok = self.lexer.next_useful(); 160 | if tok != Token::Colon { 161 | return Err(ParserError::InvalidTokenInSwitch { 162 | sp: self.lexer.span(), 163 | tok, 164 | }); 165 | } 166 | 167 | Ok((None, Some(Default { attributes }))) 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/parser/statements/try.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use std::rc::Rc; 7 | use termcolor::StandardStreamLock; 8 | 9 | use super::{Statement, StatementParser}; 10 | use crate::lexer::lexer::{TLexer, Token}; 11 | use crate::parser::attributes::Attributes; 12 | use crate::parser::declarations::{TypeDeclarator, TypeDeclaratorParser}; 13 | use crate::parser::dump::Dump; 14 | use crate::parser::errors::ParserError; 15 | use crate::parser::{Context, ScopeKind}; 16 | 17 | #[derive(Clone, Debug, PartialEq)] 18 | pub struct Try { 19 | pub attributes: Option, 20 | pub body: Box, 21 | pub clause: Option>, 22 | pub handler: Box, 23 | } 24 | 25 | impl Dump for Try { 26 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 27 | dump_obj!(self, name, "try", prefix, last, stdout, attributes, body, clause, handler); 28 | } 29 | } 30 | 31 | pub struct TryStmtParser<'a, L: TLexer> { 32 | lexer: &'a mut L, 33 | } 34 | 35 | impl<'a, L: TLexer> TryStmtParser<'a, L> { 36 | pub(super) fn new(lexer: &'a mut L) -> Self { 37 | Self { lexer } 38 | } 39 | 40 | pub(super) fn parse( 41 | self, 42 | attributes: Option, 43 | context: &mut Context, 44 | ) -> Result<(Option, Option), ParserError> { 45 | let sp = StatementParser::new(self.lexer); 46 | let (tok, body) = sp.parse(None, context)?; 47 | 48 | let body = if let Some(body) = body { 49 | body 50 | } else { 51 | return Err(ParserError::InvalidTokenInTry { 52 | sp: self.lexer.span(), 53 | tok: tok.unwrap(), 54 | }); 55 | }; 56 | 57 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 58 | if tok != Token::Catch { 59 | return Err(ParserError::InvalidTokenInTry { 60 | sp: self.lexer.span(), 61 | tok, 62 | }); 63 | } 64 | 65 | let tok = self.lexer.next_useful(); 66 | if tok != Token::LeftParen { 67 | return Err(ParserError::InvalidTokenInTry { 68 | sp: self.lexer.span(), 69 | tok, 70 | }); 71 | } 72 | 73 | let tok = self.lexer.next_useful(); 74 | let (tok, clause) = if tok == Token::Ellipsis { 75 | (None, None) 76 | } else { 77 | let tp = TypeDeclaratorParser::new(self.lexer); 78 | let (tok, typ) = tp.parse(Some(tok), None, false, context)?; 79 | 80 | if typ.is_some() { 81 | (tok, typ) 82 | } else { 83 | return Err(ParserError::InvalidTokenInTry { 84 | sp: self.lexer.span(), 85 | tok: tok.unwrap(), 86 | }); 87 | } 88 | }; 89 | 90 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 91 | if tok != Token::RightParen { 92 | return Err(ParserError::InvalidTokenInTry { 93 | sp: self.lexer.span(), 94 | tok, 95 | }); 96 | } 97 | 98 | // Exception handler 99 | let clause = if let Some(clause) = clause { 100 | context.set_current(None, ScopeKind::CatchBlock); 101 | context.add_type_decl(Rc::clone(&clause)); 102 | Some(clause) 103 | } else { 104 | None 105 | }; 106 | 107 | let sp = StatementParser::new(self.lexer); 108 | let (tok, handler) = sp.parse(None, context)?; 109 | 110 | if clause.is_some() { 111 | context.pop(); 112 | } 113 | 114 | let handler = if let Some(handler) = handler { 115 | handler 116 | } else { 117 | return Err(ParserError::InvalidTokenInTry { 118 | sp: self.lexer.span(), 119 | tok: tok.unwrap(), 120 | }); 121 | }; 122 | 123 | Ok(( 124 | tok, 125 | Some(Try { 126 | attributes, 127 | body: Box::new(body), 128 | clause, 129 | handler: Box::new(handler), 130 | }), 131 | )) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/parser/statements/while.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use std::rc::Rc; 7 | use termcolor::StandardStreamLock; 8 | 9 | use super::{Statement, StatementParser}; 10 | use crate::lexer::lexer::{TLexer, Token}; 11 | use crate::parser::attributes::Attributes; 12 | use crate::parser::declarations::{DeclOrExpr, DeclOrExprParser}; 13 | use crate::parser::dump::Dump; 14 | use crate::parser::errors::ParserError; 15 | use crate::parser::{Context, ScopeKind}; 16 | 17 | #[derive(Clone, Debug, PartialEq)] 18 | pub struct While { 19 | pub attributes: Option, 20 | pub condition: DeclOrExpr, 21 | pub body: Statement, 22 | } 23 | 24 | impl Dump for While { 25 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 26 | dump_obj!(self, name, "while", prefix, last, stdout, attributes, condition, body); 27 | } 28 | } 29 | 30 | pub struct WhileStmtParser<'a, L: TLexer> { 31 | lexer: &'a mut L, 32 | } 33 | 34 | impl<'a, L: TLexer> WhileStmtParser<'a, L> { 35 | pub(super) fn new(lexer: &'a mut L) -> Self { 36 | Self { lexer } 37 | } 38 | 39 | pub(super) fn parse( 40 | self, 41 | attributes: Option, 42 | context: &mut Context, 43 | ) -> Result<(Option, Option), ParserError> { 44 | let tok = self.lexer.next_useful(); 45 | 46 | if tok != Token::LeftParen { 47 | return Err(ParserError::InvalidTokenInWhile { 48 | sp: self.lexer.span(), 49 | tok, 50 | }); 51 | } 52 | 53 | context.set_current(None, ScopeKind::WhileBlock); 54 | 55 | let dep = DeclOrExprParser::new(self.lexer); 56 | let (tok, condition) = dep.parse(None, context)?; 57 | 58 | if let Some(DeclOrExpr::Decl(typ)) = condition.as_ref() { 59 | context.add_type_decl(Rc::clone(typ)); 60 | } 61 | 62 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 63 | if tok != Token::RightParen { 64 | context.pop(); 65 | return Err(ParserError::InvalidTokenInWhile { 66 | sp: self.lexer.span(), 67 | tok, 68 | }); 69 | } 70 | 71 | let sp = StatementParser::new(self.lexer); 72 | let (tok, body) = sp.parse(None, context)?; 73 | context.pop(); 74 | 75 | Ok(( 76 | tok, 77 | Some(While { 78 | attributes, 79 | condition: condition.unwrap(), 80 | body: body.unwrap(), 81 | }), 82 | )) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/parser/types/cv.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use bitflags::bitflags; 7 | use termcolor::StandardStreamLock; 8 | 9 | use crate::lexer::Token; 10 | use crate::parser::dump::Dump; 11 | 12 | bitflags! { 13 | pub struct CVQualifier: u8 { 14 | const CONST = 0b1; 15 | const VOLATILE = 0b10; 16 | const RESTRICT = 0b100; 17 | } 18 | } 19 | 20 | impl ToString for CVQualifier { 21 | fn to_string(&self) -> String { 22 | bitflags_to_str!(self, Self, CONST, "const", VOLATILE, "volatile", RESTRICT, "restrict") 23 | } 24 | } 25 | 26 | impl Dump for CVQualifier { 27 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 28 | dump_str!(name, self.to_string(), Cyan, prefix, last, stdout); 29 | } 30 | } 31 | 32 | impl CVQualifier { 33 | pub(crate) fn from_tok(&mut self, tok: &Token) -> bool { 34 | match tok { 35 | Token::Const => { 36 | *self |= Self::CONST; 37 | true 38 | } 39 | Token::Volatile => { 40 | *self |= Self::VOLATILE; 41 | true 42 | } 43 | Token::Restrict => { 44 | *self |= Self::RESTRICT; 45 | true 46 | } 47 | _ => false, 48 | } 49 | } 50 | 51 | pub(crate) fn is_cv(tok: &Token) -> bool { 52 | match tok { 53 | Token::Const | Token::Volatile | Token::Restrict => true, 54 | _ => false, 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/parser/types/mod.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | pub mod primitive; 7 | pub use self::primitive::*; 8 | 9 | pub mod cv; 10 | pub use self::cv::*; 11 | 12 | pub mod r#type; 13 | pub use self::r#type::*; 14 | -------------------------------------------------------------------------------- /src/parser/types/primitive.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use bitflags::bitflags; 7 | use termcolor::StandardStreamLock; 8 | 9 | use crate::lexer::Token; 10 | use crate::parser::dump::Dump; 11 | 12 | bitflags! { 13 | pub(crate) struct Modifier: u64 { 14 | const SIGNED = 0b1; 15 | const UNSIGNED = 0b10; 16 | const CHAR = 0b100; 17 | const SHORT = 0b1000; 18 | const INT = 0b1_0000; 19 | const LONG = 0b10_0000; 20 | const LONGLONG = 0b100_0000; 21 | const FLOAT = 0b1000_0000; 22 | const DOUBLE = 0b1_0000_0000; 23 | const BOOL = 0b10_0000_0000; 24 | const WCHART = 0b100_0000_0000; 25 | const CHAR8T = 0b1000_0000_0000; 26 | const CHAR16T = 0b1_0000_0000_0000; 27 | const CHAR32T = 0b10_0000_0000_0000; 28 | const COMPLEX = 0b100_0000_0000_0000; 29 | const IMAGINARY = 0b1000_0000_0000_0000; 30 | const VOID = 0b1_0000_0000_0000_0000; 31 | } 32 | } 33 | 34 | #[derive(Clone, Copy, Debug, PartialEq, Hash)] 35 | pub enum Primitive { 36 | None, 37 | Void, 38 | Char, 39 | SignedChar, 40 | Short, 41 | Int, 42 | Long, 43 | LongLong, 44 | UnsignedChar, 45 | UnsignedShort, 46 | UnsignedInt, 47 | UnsignedLong, 48 | UnsignedLongLong, 49 | CharComplex, 50 | SignedCharComplex, 51 | ShortComplex, 52 | IntComplex, 53 | LongComplex, 54 | LongLongComplex, 55 | UnsignedCharComplex, 56 | UnsignedShortComplex, 57 | UnsignedIntComplex, 58 | UnsignedLongComplex, 59 | UnsignedLongLongComplex, 60 | Float, 61 | Double, 62 | LongDouble, 63 | FloatComplex, 64 | DoubleComplex, 65 | LongDoubleComplex, 66 | FloatImaginary, 67 | DoubleImaginary, 68 | LongDoubleImaginary, 69 | Bool, 70 | WcharT, 71 | Char8T, 72 | Char16T, 73 | Char32T, 74 | } 75 | 76 | impl Primitive { 77 | pub fn to_str(&self) -> &'static str { 78 | use Primitive::*; 79 | match self { 80 | None => "", 81 | Void => "void", 82 | Char => "char", 83 | SignedChar => "signed char", 84 | Short => "short", 85 | Int => "int", 86 | Long => "long", 87 | LongLong => "long long", 88 | UnsignedChar => "unsigned char", 89 | UnsignedShort => "unsigned short", 90 | UnsignedInt => "unsigned int", 91 | UnsignedLong => "unsigned long", 92 | UnsignedLongLong => "unsigned long long", 93 | CharComplex => "_Complex char", 94 | SignedCharComplex => "_Complex signed char", 95 | ShortComplex => "_Cmplex short", 96 | IntComplex => "_Complex int", 97 | LongComplex => "_Complex long", 98 | LongLongComplex => "_Complex long long", 99 | UnsignedCharComplex => "_Complex unsigned char", 100 | UnsignedShortComplex => "_Complex unsigned short", 101 | UnsignedIntComplex => "_Complex unsigned int", 102 | UnsignedLongComplex => "_Complex unsigned long", 103 | UnsignedLongLongComplex => "_Complex unsigned long long", 104 | Float => "float", 105 | Double => "double", 106 | LongDouble => "long double", 107 | FloatComplex => "_Complex float", 108 | DoubleComplex => "_Complex double", 109 | LongDoubleComplex => "_Complex long double", 110 | FloatImaginary => "float _Imaginary", 111 | DoubleImaginary => "double _Imaginary", 112 | LongDoubleImaginary => "long double _Imaginary", 113 | Bool => "bool", 114 | WcharT => "wchar_t", 115 | Char8T => "char8_t", 116 | Char16T => "char16_t", 117 | Char32T => "char32_t", 118 | } 119 | } 120 | } 121 | 122 | impl Dump for Primitive { 123 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 124 | dump_str!(name, self.to_str(), Magenta, prefix, last, stdout) 125 | } 126 | } 127 | 128 | impl Modifier { 129 | pub(crate) fn to_primitive(self) -> Primitive { 130 | // TODO: check if it could be interesting to replace that stuff with a hashmap 131 | match self.bits() { 132 | 0b100 => Primitive::Char, 133 | 0b101 => Primitive::SignedChar, 134 | 0b110 => Primitive::UnsignedChar, 135 | 0b1001 | 0b1_1001 | 0b1_1000 | 0b1000 => Primitive::Short, 136 | 0b1010 | 0b1_1010 => Primitive::UnsignedShort, 137 | 0b1_0000 | 0b1_0001 | 0b1 => Primitive::Int, 138 | 0b1_0010 | 0b10 => Primitive::UnsignedInt, 139 | 0b10_0000 | 0b11_0000 | 0b10_0001 | 0b11_0001 => Primitive::Long, 140 | 0b10_0010 | 0b11_0010 => Primitive::UnsignedLong, 141 | 0b100_0000 | 0b101_0000 | 0b100_0001 | 0b101_0001 => Primitive::LongLong, 142 | 0b100_0010 | 0b101_0010 => Primitive::UnsignedLongLong, 143 | 0b100_0000_0000_0100 => Primitive::CharComplex, 144 | 0b100_0000_0000_0101 => Primitive::SignedCharComplex, 145 | 0b100_0000_0000_0110 => Primitive::UnsignedCharComplex, 146 | 0b100_0000_0000_1001 | 0b100_0000_0001_1001 | 0b100_0000_0001_1000 147 | | 0b100_0000_0000_1000 => Primitive::ShortComplex, 148 | 0b100_0000_0000_1010 | 0b100_0000_0001_1010 => Primitive::UnsignedShortComplex, 149 | 0b100_0000_0001_0000 | 0b100_0000_0001_0001 | 0b100_0000_0000_0001 => { 150 | Primitive::IntComplex 151 | } 152 | 0b100_0000_0001_0010 | 0b100_0000_0000_0010 => Primitive::UnsignedIntComplex, 153 | 0b100_0000_0010_0000 | 0b100_0000_0011_0000 | 0b100_0000_0010_0001 154 | | 0b100_0000_0011_0001 => Primitive::LongComplex, 155 | 0b100_0000_0010_0010 | 0b100_0000_0011_0010 => Primitive::UnsignedLongComplex, 156 | 0b100_0000_0100_0000 | 0b100_0000_0101_0000 | 0b100_0000_0100_0001 157 | | 0b100_0000_0101_0001 => Primitive::LongLongComplex, 158 | 0b100_0000_0100_0010 | 0b100_0000_0101_0010 => Primitive::UnsignedLongLongComplex, 159 | 0b1000_0000 => Primitive::Float, 160 | 0b1_0000_0000 => Primitive::Double, 161 | 0b1_0010_0000 => Primitive::LongDouble, 162 | 0b10_0000_0000 => Primitive::Bool, 163 | 0b100_0000_0000 => Primitive::WcharT, 164 | 0b1000_0000_0000 => Primitive::Char8T, 165 | 0b1_0000_0000_0000 => Primitive::Char16T, 166 | 0b10_0000_0000_0000 => Primitive::Char32T, 167 | 0b100_0000_1000_0000 => Primitive::FloatComplex, 168 | 0b100_0001_0000_0000 => Primitive::DoubleComplex, 169 | 0b100_0001_0010_0000 => Primitive::LongDoubleComplex, 170 | 0b1000_0000_1000_0000 => Primitive::FloatImaginary, 171 | 0b1000_0001_0000_0000 => Primitive::DoubleImaginary, 172 | 0b1000_0001_0010_0000 => Primitive::LongDoubleImaginary, 173 | 0b1_0000_0000_0000_0000 => Primitive::Void, 174 | _ => unreachable!("Invalid modifier {:?}", self), 175 | } 176 | } 177 | 178 | pub(crate) fn from_tok(&mut self, tok: &Token) -> bool { 179 | match tok { 180 | Token::Signed => { 181 | *self |= Modifier::SIGNED; 182 | true 183 | } 184 | Token::Unsigned => { 185 | *self |= Modifier::UNSIGNED; 186 | true 187 | } 188 | Token::Char => { 189 | *self |= Modifier::CHAR; 190 | true 191 | } 192 | Token::Short => { 193 | *self |= Modifier::SHORT; 194 | true 195 | } 196 | Token::Int => { 197 | *self |= Modifier::INT; 198 | true 199 | } 200 | Token::Long => { 201 | if self.intersects(Modifier::LONG) { 202 | self.remove(Modifier::LONG); 203 | *self |= Modifier::LONGLONG; 204 | } else { 205 | *self |= Modifier::LONG; 206 | } 207 | true 208 | } 209 | Token::Float => { 210 | *self |= Modifier::FLOAT; 211 | true 212 | } 213 | Token::Double => { 214 | *self |= Modifier::DOUBLE; 215 | true 216 | } 217 | Token::Complex => { 218 | *self |= Modifier::COMPLEX; 219 | true 220 | } 221 | Token::Imaginary => { 222 | *self |= Modifier::IMAGINARY; 223 | true 224 | } 225 | Token::Bool => { 226 | *self |= Modifier::BOOL; 227 | true 228 | } 229 | Token::WcharT => { 230 | *self |= Modifier::WCHART; 231 | true 232 | } 233 | Token::Char8T => { 234 | *self |= Modifier::CHAR8T; 235 | true 236 | } 237 | Token::Char16T => { 238 | *self |= Modifier::CHAR16T; 239 | true 240 | } 241 | Token::Char32T => { 242 | *self |= Modifier::CHAR32T; 243 | true 244 | } 245 | Token::Void => { 246 | *self |= Modifier::VOID; 247 | true 248 | } 249 | _ => false, 250 | } 251 | } 252 | 253 | pub(crate) fn is_primitive_part(tok: &Token) -> bool { 254 | match tok { 255 | Token::Signed 256 | | Token::Unsigned 257 | | Token::Char 258 | | Token::Short 259 | | Token::Int 260 | | Token::Long 261 | | Token::Float 262 | | Token::Double 263 | | Token::Complex 264 | | Token::Imaginary 265 | | Token::Bool 266 | | Token::WcharT 267 | | Token::Char8T 268 | | Token::Char16T 269 | | Token::Char32T 270 | | Token::Void => true, 271 | _ => false, 272 | } 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /src/parser/types/type.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use std::hash::{Hash, Hasher}; 7 | use std::rc::Rc; 8 | use termcolor::StandardStreamLock; 9 | 10 | use super::cv::CVQualifier; 11 | use super::primitive::Primitive; 12 | use crate::parser::context::TypeToFix; 13 | use crate::parser::declarations::types::TypeDeclarator; 14 | use crate::parser::declarations::{Array, Class, Enum, Function, Pointers}; 15 | use crate::parser::dump::Dump; 16 | use crate::parser::names::Qualified; 17 | 18 | #[derive(Clone, Debug, PartialEq)] 19 | pub enum UDType { 20 | Direct(Rc), 21 | // Used when a type is used insided itself: 22 | // struct A { ... A* ... } 23 | // Once the struct is parsed then the Indirect value is set 24 | Indirect(TypeToFix), 25 | } 26 | 27 | impl Dump for UDType { 28 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 29 | match self { 30 | Self::Direct(_) => dump_str!(name, "", Cyan, prefix, last, stdout), 31 | Self::Indirect(i) => i.dump(name, prefix, last, stdout), 32 | }; 33 | } 34 | } 35 | 36 | #[derive(Clone, Debug, PartialEq)] 37 | pub struct UserDefined { 38 | pub name: Qualified, 39 | pub typ: UDType, 40 | } 41 | 42 | impl Hash for UserDefined { 43 | fn hash(&self, state: &mut H) { 44 | self.name.hash(state); 45 | } 46 | } 47 | 48 | impl Dump for UserDefined { 49 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 50 | dump_obj!(self, name, "UD", prefix, last, stdout, name, typ); 51 | } 52 | } 53 | 54 | #[derive(Clone, Debug, PartialEq)] 55 | pub enum BaseType { 56 | None, 57 | Auto, 58 | Primitive(Primitive), 59 | UD(Box), 60 | Enum(Box), 61 | Class(Box), 62 | Function(Box), 63 | Array(Box), 64 | } 65 | 66 | impl ToString for BaseType { 67 | fn to_string(&self) -> String { 68 | use BaseType::*; 69 | 70 | match self { 71 | None => "".to_string(), 72 | Auto => "auto".to_string(), 73 | Primitive(p) => p.to_str().to_string(), 74 | UD(ud) => ud.name.to_string(), 75 | Enum(_) => "enum".to_string(), 76 | Class(_) => "class".to_string(), 77 | Function(_) => "function".to_string(), 78 | Array(_) => "array".to_string(), 79 | } 80 | } 81 | } 82 | 83 | impl Dump for BaseType { 84 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 85 | macro_rules! dump { 86 | ( $x: ident ) => { 87 | $x.dump(name, prefix, last, stdout) 88 | }; 89 | } 90 | 91 | match self { 92 | Self::None => dump_str!(name, "None", Cyan, prefix, last, stdout), 93 | Self::Auto => dump_str!(name, "auto", Cyan, prefix, last, stdout), 94 | Self::Primitive(x) => dump!(x), 95 | Self::UD(x) => dump!(x), 96 | Self::Enum(x) => dump!(x), 97 | Self::Class(x) => dump!(x), 98 | Self::Function(x) => dump!(x), 99 | Self::Array(x) => dump!(x), 100 | } 101 | } 102 | } 103 | 104 | #[derive(Clone, Debug, PartialEq)] 105 | pub struct Type { 106 | pub base: BaseType, 107 | pub cv: CVQualifier, 108 | pub pointers: Option, 109 | } 110 | 111 | impl Dump for Type { 112 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 113 | dump_obj!(self, name, "type", prefix, last, stdout, base, cv, pointers); 114 | } 115 | } 116 | 117 | impl Default for Type { 118 | fn default() -> Self { 119 | Self { 120 | base: BaseType::None, 121 | cv: CVQualifier::empty(), 122 | pointers: None, 123 | } 124 | } 125 | } 126 | 127 | impl Type { 128 | pub fn base(&self) -> &BaseType { 129 | &self.base 130 | } 131 | 132 | pub fn is_const(&self) -> bool { 133 | self.cv.intersects(CVQualifier::CONST) 134 | } 135 | 136 | pub fn is_volatile(&self) -> bool { 137 | self.cv.intersects(CVQualifier::VOLATILE) 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/parser/unit.rs: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 4 | // copied, modified, or distributed except according to those terms. 5 | 6 | use termcolor::StandardStreamLock; 7 | 8 | use super::context::Context; 9 | use super::declarations::{DeclarationListParser, Declarations}; 10 | use crate::lexer::preprocessor::context::PreprocContext; 11 | use crate::lexer::{Lexer, TLexer, Token}; 12 | use crate::parser::dump::Dump; 13 | use crate::parser::errors::ParserError; 14 | 15 | #[derive(Clone, Debug, PartialEq)] 16 | pub struct Unit { 17 | decls: Declarations, 18 | } 19 | 20 | impl Dump for Unit { 21 | fn dump(&self, name: &str, prefix: &str, last: bool, stdout: &mut StandardStreamLock) { 22 | dump_obj!(self, name, "unit", prefix, last, stdout, decls); 23 | } 24 | } 25 | 26 | pub struct UnitParser<'a, PC: PreprocContext> { 27 | pub lexer: Lexer<'a, PC>, 28 | pub context: Context, 29 | } 30 | 31 | impl<'a, PC: PreprocContext> UnitParser<'a, PC> { 32 | pub fn new(buf: &'a [u8]) -> Self { 33 | Self { 34 | lexer: Lexer::new(buf), 35 | context: Context::default(), 36 | } 37 | } 38 | 39 | pub fn parse(&mut self) -> Result { 40 | let dlp = DeclarationListParser::new(&mut self.lexer); 41 | let (tok, decls) = dlp.parse(None, &mut self.context)?; 42 | 43 | let tok = tok.unwrap_or_else(|| self.lexer.next_useful()); 44 | if tok != Token::Eof { 45 | return Err(ParserError::InvalidTokenInUnit { 46 | sp: self.lexer.span(), 47 | tok, 48 | }); 49 | } 50 | 51 | Ok(Unit { 52 | decls: decls.unwrap(), 53 | }) 54 | } 55 | } 56 | --------------------------------------------------------------------------------