├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Elitefile ├── Elitefile_Example ├── LICENSE ├── README.md ├── examples └── cpp │ └── hello_world │ ├── Elitefile │ └── example.cpp ├── resources └── Elitebuild_Banner.png └── src ├── ast.rs ├── lexer.rs ├── lib.rs ├── logger.rs ├── main.rs ├── parser.rs ├── read.rs └── tokenizer.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "elite" 7 | version = "0.1.4" 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "elite" 3 | version = "0.1.4" 4 | authors = ["\"ferhatgec\""] 5 | edition = "2018" 6 | description = "New generation, simple & clean build system." 7 | keywords = ["rust", "term", "build", "system", "ast"] 8 | readme = "README.md" 9 | repository = "https://github.com/ferhatgec/elite" 10 | documentation = "https://docs.rs/elite" 11 | license = "MIT" 12 | 13 | include = [ 14 | ".gitignore", 15 | "Cargo.toml", 16 | "src/*.rs", 17 | "examples", 18 | "resource" 19 | ] -------------------------------------------------------------------------------- /Elitefile: -------------------------------------------------------------------------------- 1 | required_version is 0.1 2 | 3 | set name as "elite" 4 | set check as output "cargo" 5 | set home as env "HOME" 6 | 7 | for signal "start" [ 8 | if eq $check "" [ 9 | println "Cargo not found." 10 | use signal "exit" 11 | ] 12 | 13 | use exec "cargo install --path ." 14 | 15 | for exists "{home}/.cargo/bin/elite" [ 16 | println "Installed to {home}/.cargo/bin/elite" 17 | ] 18 | 19 | use signal "exit" 20 | ] -------------------------------------------------------------------------------- /Elitefile_Example: -------------------------------------------------------------------------------- 1 | required_version is 0.1 2 | 3 | set ProjectName as "Elite" 4 | 5 | set COMPILER as "gcc" 6 | set fn as "for" 7 | set commandline as "argument" 8 | set echo as "println" 9 | set make_arg as "make" 10 | 11 | set Linux as "linux" 12 | set FreeBSD as "freebsd" 13 | 14 | set HOME as env "HOME" 15 | 16 | set COMPILER_PATH as "/usr/bin/{COMPILER}" 17 | 18 | set LINKS as link "stdc++fs" 19 | set STANDARD as std "c++17" 20 | set OUTPUT as outfile "example" 21 | 22 | set sources as "example.cpp" 23 | use add_source sources "test.cpp" 24 | 25 | # Start signal 26 | $fn signal "start" [ 27 | print "CPU Architecture: " 28 | for specific "x86" [ println "x86" ] 29 | for specific "x86_64" [ println "x86_64" ] 30 | for specific "mips" [ println "mips" ] 31 | for specific "powerpc" [ println "powerpc" ] 32 | for specific "powerpc64"[ println "powerpc64" ] 33 | for specific "arm" [ println "arm" ] 34 | for specific "aarch64" [ println "aarch64" ] 35 | 36 | use append ProjectName "build" 37 | 38 | $echo "test.cpp file added: {sources}" 39 | 40 | $echo "Hello, {ProjectName}!" 41 | 42 | println "Default compiler is: {COMPILER}" 43 | 44 | println suppress "Suppressed stdout." 45 | 46 | use exec suppress "echo Suppressed syscall" 47 | 48 | set echo as "print" 49 | 50 | $echo "Huh!" 51 | 52 | set echo as "println" 53 | 54 | # Prints newline 55 | $echo 56 | 57 | $echo $HOME 58 | 59 | if eq "{ProjectName}" "Elitebuild" [ 60 | println "ProjectName checked." 61 | ] 62 | 63 | if uneq "{COMPILER}" "gcc" [ 64 | println "Your compiler seemsly not GCC, unoptimized." 65 | ] 66 | 67 | if uneq "{HOME}" env "PWD" [ 68 | println "Current directory isn't {HOME}!" 69 | print "Current dir is: " println env "PWD" 70 | ] 71 | 72 | # You can also use $ProjectName instead of formatter 73 | 74 | # Platform-specific functions. 75 | $fn specific "{Linux}" [ 76 | for exists "{COMPILER_PATH}" [ 77 | println "Compiler path found: {COMPILER_PATH} {LINKS} {STANDARD} {OUTPUT}" 78 | ] 79 | 80 | println "Linux-based" 81 | ] 82 | 83 | for $commandline "{make_arg}" [ 84 | println "There's nothing to do." 85 | ] 86 | 87 | for argument "hi" [ 88 | println "Hi!" 89 | ] 90 | 91 | for specific "{FreeBSD}" [ 92 | println "{FreeBSD}" 93 | ] 94 | 95 | # for argument("make") [ 96 | # for specific("linux") [ 97 | # use commandline( 98 | # $COMPILER, 99 | # $arguments, 100 | # $flags 101 | # ) 102 | 103 | # print "hello, world" 104 | # 105 | # use commandline( 106 | # "echo", 107 | # "hello, world" 108 | # ) 109 | # ] 110 | # ] 111 | 112 | set gech as "gech" 113 | println $gech 114 | unset gech 115 | print $gech 116 | 117 | 118 | # {...} default formatter 119 | for specific "{Linux}" [ use exec "echo Hello, Elitebuild from syscall! (for Linux-based)" ] 120 | 121 | for specific "{FreeBSD}" [ use exec "echo Hello, Elitebuild from syscall! (for FreeBSD)" ] 122 | 123 | for specific "{Linux}" [ use exec "uname --a" ] 124 | 125 | for specific "linux" [ use signal "exit" ] 126 | ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Ferhat Geçdoğan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Elitebuild :)](resources/Elitebuild_Banner.png) 2 | 3 | # Fegeya Elitebuild 4 | 5 | ## Small, powerful, work-in-progress build system. Written in Rust. 6 | 7 | ### Features: 8 | * No functions (all are built-ins) 9 | * All variables are global 10 | * Cross-platform (say 'thank you' to rust's standard lib) 11 | * Different syntax. 12 | * Preprocessor. 13 | * Aliases. 14 | * Built-in analyzer. 15 | * Language back-ends. 16 | 17 | ### A taste of Elite's syntax: 18 | ```cpp 19 | required_version is 0.1 20 | 21 | set BIN_PATH as "/usr/bin/" 22 | set COMPILER as "g++" 23 | set COMPILER_PATH as "{BIN_PATH}{COMPILER}" 24 | 25 | set SOURCE_FILE as "example.cpp" 26 | set OUTPUT as "example" 27 | 28 | for signal "start" [ 29 | for exists "{BIN_PATH}clang++" [ 30 | set COMPILER as "clang++" 31 | ] 32 | 33 | for specific "linux" [ 34 | println "OS: GNU/Linux" 35 | ] 36 | 37 | for specific "freebsd" [ 38 | println "OS: FreeBSD" 39 | ] 40 | 41 | for specific "windows" [ 42 | println "OS: Windows" 43 | ] 44 | 45 | for specific "openbsd" [ 46 | println "OS: OpenBSD" 47 | ] 48 | 49 | for argument "build" [ 50 | use exec "{COMPILER} {SOURCE_FILE} -o {OUTPUT}" 51 | 52 | for exists $OUTPUT [ 53 | println "Build succeeded" 54 | ] 55 | 56 | unset COMPILER_PATH 57 | use signal "exit" 58 | ] 59 | 60 | use signal "exit" 61 | ] 62 | ``` 63 | 64 | ### Other implementations? 65 | * [For C++ as ElitedotC++](https://github.com/ferhatgec/elite.cpp) 66 | * [Gretea's Runtime uses Elite](https://github.com/ferhatgec/gretea) 67 | 68 | ## Transpiler back-ends? (oldest-) 69 | * [Python](https://github.com/ferhatgec/elitetopy) 70 | * [C++](https://github.com/ferhatgec/elitetopp) 71 | * [C](https://github.com/ferhatgec/elitetoc) 72 | * [Rust](https://github.com/ferhatgec/elitetors) 73 | * [Bash](https://github.com/ferhatgec/elitetobash) 74 | * [Perl](https://github.com/ferhatgec/elitetoperl) 75 | * [Go](https://github.com/ferhatgec/elitetogo) 76 | * [D](https://github.com/ferhatgec/elitetod) 77 | * [Scala](https://github.com/ferhatgec/elitetoscala) 78 | 79 | ### Elitebuild licensed under the terms of MIT License. 80 | -------------------------------------------------------------------------------- /examples/cpp/hello_world/Elitefile: -------------------------------------------------------------------------------- 1 | set BIN_PATH as "/usr/bin/" 2 | set COMPILER as "g++" 3 | set COMPILER_PATH as "{BIN_PATH}{COMPILER}" 4 | 5 | set SOURCE_FILE as "example.cpp" 6 | set OUTPUT as outfile "example" 7 | 8 | for signal "start" [ 9 | for exists "{BIN_PATH}clang++" [ 10 | set COMPILER as "clang++" 11 | ] 12 | 13 | for specific "linux" [ 14 | println "OS: GNU/Linux" 15 | ] 16 | 17 | for specific "freebsd" [ 18 | println "OS: FreeBSD" 19 | ] 20 | 21 | for specific "windows" [ 22 | println "OS: Windows" 23 | ] 24 | 25 | for specific "openbsd" [ 26 | println "OS: OpenBSD" 27 | ] 28 | 29 | for argument "build" [ 30 | use exec "{COMPILER} {SOURCE_FILE} {OUTPUT}" 31 | 32 | for exists $OUTPUT [ 33 | println "Build succeeded" 34 | ] 35 | 36 | use signal "exit" 37 | ] 38 | 39 | use signal "exit" 40 | ] -------------------------------------------------------------------------------- /examples/cpp/hello_world/example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() noexcept { 4 | std::cout << "Hello, world!\n"; 5 | } -------------------------------------------------------------------------------- /resources/Elitebuild_Banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferhatgec/elite/d6c1572466991b65252b6f3c632677fa2cefdc73/resources/Elitebuild_Banner.png -------------------------------------------------------------------------------- /src/ast.rs: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2021 Ferhat Geçdoğan All Rights Reserved. 4 | // Distributed under the terms of the MIT License. 5 | // 6 | // 7 | 8 | use { 9 | std::collections::HashMap, 10 | crate::ast::EliteKeywords::{*} 11 | }; 12 | 13 | #[derive(Copy, Clone, PartialEq, Debug)] 14 | #[allow(non_camel_case_types)] 15 | pub enum EliteKeywords { 16 | Set, 17 | Unset, 18 | As, 19 | For, 20 | Print, 21 | Println, 22 | Use, 23 | If, 24 | RequiredVersion, 25 | Suppress, 26 | Change, 27 | 28 | IfArg, 29 | 30 | LeftParenthese, 31 | RightParenthese, 32 | 33 | LeftSqBracket, 34 | RightSqBracket, 35 | 36 | Windows, 37 | macOS, 38 | iOS, 39 | Linux, 40 | Android, 41 | FreeBSD, 42 | DragonFly, 43 | Bitrig, 44 | OpenBSD, 45 | NetBSD, 46 | 47 | x86, 48 | x86_64, 49 | Mips, 50 | PowerPc, 51 | PowerPc64, 52 | Arm, 53 | AArch64, 54 | 55 | Eq, 56 | UnEq, 57 | 58 | Signal, 59 | Exec, 60 | AddSource, 61 | Append, 62 | 63 | Exit, 64 | 65 | Specific, 66 | Argument, 67 | Exists, 68 | 69 | Undefined 70 | } 71 | 72 | #[derive(Copy, Clone)] 73 | pub enum Branch { 74 | Left, 75 | Right, 76 | Data 77 | } 78 | 79 | pub struct EliteAST { 80 | pub ast_set : String, 81 | pub ast_unset : String, 82 | pub ast_as : String, 83 | pub ast_is : String, 84 | pub ast_for : String, 85 | pub ast_print : String, 86 | pub ast_println : String, 87 | pub ast_use : String, 88 | pub ast_if : String, 89 | pub ast_required_version : String, 90 | pub ast_suppress : String, 91 | 92 | pub ast_left_parenthese : String, 93 | pub ast_right_parenthese : String, 94 | 95 | pub ast_square_left_bracket : String, 96 | pub ast_square_right_bracket : String, 97 | 98 | pub ast_for_use : Vec, 99 | 100 | pub ast_for_functions_arguments: Vec, 101 | pub ast_for_use_arguments : Vec, 102 | 103 | pub syntax_list : HashMap, 104 | 105 | pub ast_for_functions : HashMap, 106 | pub ast_for_specific_targets : HashMap, 107 | 108 | pub ast_if_functions : HashMap, 109 | 110 | pub ast_use_functions : HashMap, 111 | pub ast_use_list : HashMap 112 | } 113 | 114 | pub struct EliteDataInfos { 115 | pub __type: EliteKeywords, 116 | pub __name: String, 117 | pub __data: String 118 | } 119 | 120 | pub struct EliteDataTree { 121 | pub variable_list: Vec 122 | } 123 | 124 | 125 | pub struct ASTNode { 126 | pub data : Vec, 127 | pub right : Option>, 128 | pub left : Option> 129 | } 130 | 131 | impl Default for EliteDataInfos { 132 | fn default() -> Self { 133 | EliteDataInfos { 134 | __type: EliteKeywords::Undefined, 135 | __name: "".to_string(), 136 | __data: "".to_string() 137 | } 138 | } 139 | } 140 | 141 | impl Default for ASTNode { 142 | fn default() -> Self { 143 | ASTNode { 144 | data: Default::default(), 145 | right: None, 146 | left: None 147 | } 148 | } 149 | } 150 | 151 | impl ASTNode { 152 | pub 153 | fn search(&mut self, branch: Branch) { 154 | let mut node = self; 155 | let mut x: u32 = 0; 156 | 157 | loop { 158 | x += 1; 159 | 160 | match branch { 161 | Branch::Left => { 162 | if node.left.is_none() { 163 | break; 164 | } else { 165 | for val in &node.data { 166 | println!("(left){}name: {}, type: {:?}, data: {}", 167 | " ".repeat((x - 1) as usize), val.__name, val.__type, val.__data); 168 | } 169 | 170 | node = node.left.as_mut().unwrap(); 171 | } 172 | }, 173 | Branch::Right => { 174 | if node.right.is_none() { 175 | break; 176 | } else { 177 | for val in &node.data { 178 | println!("(right){}name: {}, type: {:?}, data: {}", 179 | " ".repeat((x - 1) as usize), val.__name, val.__type, val.__data); 180 | } 181 | 182 | node = node.right.as_mut().unwrap(); 183 | } 184 | }, 185 | Branch::Data => { 186 | for line in &node.data { 187 | println!("(data)name: {}, type: \x1b[0;35m{:?}\x1b[0m, data: {}", 188 | if line.__name == "" { 189 | "not_defined".to_string() 190 | } else { line.__name.clone() }, line.__type, if line.__data == "" { 191 | "not_defined".to_string() 192 | } else { line.__data.clone() }); 193 | } 194 | 195 | break; 196 | } 197 | } 198 | } 199 | } 200 | 201 | pub 202 | fn get_last_node(&mut self, branch: Branch) -> &ASTNode { 203 | let mut node = self; 204 | 205 | loop { 206 | match branch { 207 | Branch::Left => { 208 | if node.left.is_none() { 209 | break; 210 | } else { 211 | node = node.left.as_mut().unwrap(); 212 | } 213 | } 214 | Branch::Right => { 215 | if node.right.is_none() { 216 | break; 217 | } else { 218 | node = node.right.as_mut().unwrap(); 219 | } 220 | } 221 | Branch::Data => { 222 | break; 223 | } 224 | } 225 | } 226 | 227 | node 228 | } 229 | 230 | pub(crate) 231 | fn ret(&mut self) -> &mut ASTNode { 232 | self 233 | } 234 | 235 | //pub(crate) 236 | //fn get_last_node_with(&mut self, branch: Branch) -> EliteKeywords { 237 | // self.get_last_node(branch).data.last().unwrap().__type 238 | //} 239 | 240 | // some assignments were not used inside of function but 241 | // that are will be used later. 242 | #[allow(unused_must_use)] 243 | pub fn insert_key(&mut self, info: EliteDataInfos, branch: Branch) { 244 | let mut node = self.ret(); 245 | let mut x: u32 = 0; 246 | 247 | loop { 248 | match branch { 249 | Branch::Left => { 250 | if node.left.is_none() { 251 | match info.__type { 252 | Println | 253 | Print | 254 | Set | 255 | Use => { 256 | if x == 0 { 257 | if node.left.is_none() { node.left.insert(Default::default()); } 258 | 259 | node.data.push(EliteDataInfos { 260 | __type: info.__type, 261 | __name: info.__name.clone(), 262 | __data: info.__data.clone() 263 | }); 264 | break; 265 | } 266 | 267 | let mut var = self.ret(); 268 | 269 | for _ in 0..x - 1 { 270 | var = var.left.as_mut().unwrap(); 271 | } 272 | 273 | var.data.push(EliteDataInfos { 274 | __type: info.__type, 275 | __name: info.__name.clone(), 276 | __data: info.__data.clone() 277 | }); 278 | }, 279 | _ => { 280 | if node.left.is_none() { node.left.insert(Default::default()); } 281 | 282 | node.left.as_mut().unwrap().data.push(EliteDataInfos { 283 | __type: info.__type, 284 | __name: info.__name.clone(), 285 | __data: info.__data.clone() 286 | }); 287 | } 288 | } 289 | 290 | break; 291 | } else { 292 | node = node.left.as_mut().unwrap(); 293 | x += 1; 294 | } 295 | }, 296 | Branch::Right => { 297 | if node.right.is_none() { 298 | match info.__type { 299 | IfArg | 300 | Eq | 301 | UnEq | 302 | RightSqBracket | 303 | LeftSqBracket | 304 | Signal | 305 | Specific | 306 | Argument | 307 | Exists => { 308 | if self.right.is_none() || x == 0 { 309 | if self.right.is_none() { self.right.insert(Default::default()); } 310 | 311 | self.right.as_mut().unwrap().data.push(EliteDataInfos { 312 | __type: info.__type, 313 | __name: info.__name.clone(), 314 | __data: info.__data.clone() 315 | }); 316 | break; 317 | } 318 | 319 | let mut var = self.ret(); 320 | 321 | for _ in 0..x - 1 { 322 | var = var.right.as_mut().unwrap(); 323 | } 324 | 325 | var.data.push(EliteDataInfos { 326 | __type: info.__type, 327 | __name: info.__name.clone(), 328 | __data: info.__data.clone() 329 | }); 330 | }, 331 | _ => { 332 | if node.right.is_none() { node.right.insert(Default::default()); } 333 | 334 | node.right.as_mut().unwrap().data.push(EliteDataInfos { 335 | __type: info.__type, 336 | __name: info.__name.clone(), 337 | __data: info.__data.clone() 338 | }); 339 | } 340 | } 341 | break; 342 | } else { 343 | node = node.right.as_mut().unwrap(); 344 | x += 1; 345 | } 346 | }, 347 | Branch::Data => { 348 | self.data.push(EliteDataInfos { 349 | __type: info.__type, 350 | __name: info.__name.clone(), 351 | __data: info.__data.clone() 352 | }); 353 | 354 | break; 355 | } 356 | } 357 | } 358 | } 359 | } 360 | 361 | pub mod ast_helpers { 362 | pub fn extract_argument(argument: &String) -> String { 363 | if !argument.starts_with('"') && !argument.ends_with('"') { 364 | let mut __argument = String::new(); 365 | 366 | for character in argument.chars() { 367 | if character != '"' { 368 | __argument.push(character); 369 | 370 | continue; 371 | } 372 | 373 | break; 374 | } 375 | 376 | return __argument 377 | .replace("\\n", "\n") 378 | .replace("\\t", "\t") 379 | .replace("\\r", "\r") 380 | .replace("\\w", " ") 381 | .replace("\\x1b", "\x1b") 382 | .replace("\\033", "\x1b"); 383 | } 384 | else { 385 | let mut argument = String::from(argument); 386 | 387 | if argument.len() < 2 { return argument; } 388 | 389 | if argument.starts_with('"') || argument.starts_with('\'') { 390 | argument.remove(0); 391 | } 392 | 393 | if argument.ends_with('"') || argument.ends_with('\'') { 394 | argument.pop(); 395 | } 396 | 397 | argument 398 | .replace("\\n", "\n") 399 | .replace("\\t", "\t") 400 | .replace("\\r", "\r") 401 | .replace("\\w", " ") 402 | .replace("\\x1b", "\x1b") 403 | .replace("\\033", "\x1b") 404 | } 405 | } 406 | } 407 | 408 | impl Default for EliteAST { 409 | fn default() -> Self { 410 | EliteAST { 411 | ast_set : "".to_string(), 412 | ast_unset : "".to_string(), 413 | ast_as : "".to_string(), 414 | ast_is : "".to_string(), 415 | ast_for : "".to_string(), 416 | ast_print : "".to_string(), 417 | ast_println : "".to_string(), 418 | 419 | ast_use : "".to_string(), 420 | ast_if : "".to_string(), 421 | ast_required_version : "".to_string(), 422 | ast_suppress : "".to_string(), 423 | 424 | ast_left_parenthese : "".to_string(), 425 | ast_right_parenthese : "".to_string(), 426 | 427 | ast_square_left_bracket : "".to_string(), 428 | ast_square_right_bracket : "".to_string(), 429 | 430 | ast_for_use : vec![], 431 | 432 | ast_for_functions_arguments: vec![], 433 | ast_for_use_arguments : vec![], 434 | 435 | syntax_list : Default::default(), 436 | ast_for_functions : Default::default(), 437 | ast_for_specific_targets : Default::default(), 438 | ast_if_functions : Default::default(), 439 | ast_use_functions : Default::default(), 440 | ast_use_list : Default::default() 441 | } 442 | } 443 | } 444 | 445 | impl EliteAST { 446 | pub fn init_keywords(&mut self) { 447 | self.ast_set = self.to("set" ); 448 | self.ast_unset = self.to("unset" ); 449 | self.ast_as = self.to("as" ); 450 | self.ast_is = self.to("is" ); 451 | self.ast_for = self.to("for" ); 452 | self.ast_print = self.to("print" ); 453 | self.ast_println = format!("{}ln", self.ast_print ); 454 | self.ast_use = self.to("use" ); 455 | self.ast_if = self.to("if" ); 456 | self.ast_required_version = self.to("required_version"); 457 | self.ast_suppress = self.to("suppress" ); 458 | 459 | self.ast_left_parenthese = self.to("(" ); 460 | self.ast_right_parenthese = self.to(")" ); 461 | 462 | self.ast_square_left_bracket = self.to("[" ); 463 | self.ast_square_right_bracket= self.to("]" ); 464 | 465 | self.ast_for_functions_arguments = vec![ 466 | self.to("start") 467 | ]; 468 | 469 | self.ast_for_use = vec![ 470 | self.to("signal"), 471 | self.to("exec") 472 | ]; 473 | 474 | self.ast_for_use_arguments = vec![ 475 | self.to("exit") 476 | ]; 477 | 478 | self.add_token(self.ast_set.clone (), EliteKeywords::Set ); 479 | self.add_token(self.ast_unset.clone (), EliteKeywords::Unset ); 480 | 481 | // 'as' & 'is' keywords are same however, 482 | // 'is' mostly using by 'required_version' to declare required version, 483 | // 'as' mostly using by 'set' to variable data declaration. 484 | self.add_token(self.ast_as.clone (), EliteKeywords::As ); 485 | self.add_token(self.ast_is.clone (), EliteKeywords::As ); 486 | self.add_token(self.ast_for.clone (), EliteKeywords::For ); 487 | self.add_token(self.ast_print.clone (), EliteKeywords::Print ); 488 | self.add_token(self.ast_println.clone(), EliteKeywords::Println); 489 | self.add_token(self.ast_use.clone (), EliteKeywords::Use ); 490 | self.add_token(self.ast_if.clone (), EliteKeywords::If ); 491 | self.add_token(self.ast_required_version 492 | .clone(),EliteKeywords:: 493 | RequiredVersion); 494 | self.add_token(self.ast_suppress 495 | .clone(), EliteKeywords:: 496 | Suppress ); 497 | 498 | self.add_token(self.ast_left_parenthese.clone(), EliteKeywords::LeftParenthese ); 499 | self.add_token(self.ast_right_parenthese.clone(), EliteKeywords::RightParenthese); 500 | 501 | self.add_token(self.ast_square_left_bracket.clone(), EliteKeywords::LeftSqBracket ); 502 | self.add_token(self.ast_square_right_bracket.clone(), EliteKeywords::RightSqBracket); 503 | 504 | self.add_for_function(self.to("signal" ), EliteKeywords::Signal ); 505 | self.add_for_function(self.to("specific"), EliteKeywords::Specific); 506 | self.add_for_function(self.to("argument"), EliteKeywords::Argument); 507 | self.add_for_function(self.to("exists" ), EliteKeywords::Exists ); 508 | 509 | self.add_for_specific_target(self.to("windows" ), EliteKeywords::Windows ); 510 | self.add_for_specific_target(self.to("macos" ), EliteKeywords::macOS ); 511 | self.add_for_specific_target(self.to("ios" ), EliteKeywords::iOS ); 512 | self.add_for_specific_target(self.to("linux" ), EliteKeywords::Linux ); 513 | self.add_for_specific_target(self.to("android" ), EliteKeywords::Android ); 514 | self.add_for_specific_target(self.to("freebsd" ), EliteKeywords::FreeBSD ); 515 | self.add_for_specific_target(self.to("dragonfly"), EliteKeywords::DragonFly); 516 | self.add_for_specific_target(self.to("bitrig" ), EliteKeywords::Bitrig ); 517 | self.add_for_specific_target(self.to("openbsd" ), EliteKeywords::OpenBSD ); 518 | self.add_for_specific_target(self.to("netbsd" ), EliteKeywords::NetBSD ); 519 | 520 | self.add_for_specific_target(self.to("x86" ), EliteKeywords::x86 ); 521 | self.add_for_specific_target(self.to("x86_64" ), EliteKeywords::x86_64 ); 522 | self.add_for_specific_target(self.to("mips" ), EliteKeywords::Mips ); 523 | self.add_for_specific_target(self.to("powerpc" ), EliteKeywords::PowerPc ); 524 | self.add_for_specific_target(self.to("powerpc64"), EliteKeywords::PowerPc64); 525 | self.add_for_specific_target(self.to("arm" ), EliteKeywords::Arm ); 526 | self.add_for_specific_target(self.to("aarch64" ), EliteKeywords::AArch64 ); 527 | 528 | self.add_if_function (self.to("eq" ), EliteKeywords::Eq ); 529 | self.add_if_function (self.to("uneq" ), EliteKeywords::UnEq); 530 | 531 | self.add_use_function(self.to("signal" ), EliteKeywords::Signal ); 532 | self.add_use_function(self.to("exec" ), EliteKeywords::Exec ); 533 | self.add_use_function(self.to("add_source"), EliteKeywords::AddSource); 534 | self.add_use_function(self.to("append" ), EliteKeywords::Append ); 535 | 536 | self.add_use_argument(self.to("exit" ), EliteKeywords::Exit ); 537 | } 538 | 539 | fn add_token(&mut self, token: String, token_type: EliteKeywords) { 540 | self.syntax_list.insert(token, token_type); 541 | } 542 | 543 | fn add_for_function(&mut self, function: String, token_type: EliteKeywords) { 544 | self.ast_for_functions.insert(function, token_type); 545 | } 546 | 547 | fn add_for_specific_target(&mut self, function: String, token_type: EliteKeywords) { 548 | self.ast_for_specific_targets.insert(function, token_type); 549 | } 550 | 551 | fn add_if_function(&mut self, statement: String, token_type: EliteKeywords) { 552 | self.ast_if_functions.insert(statement, token_type); 553 | } 554 | 555 | fn add_use_function(&mut self, function: String, token_type: EliteKeywords) { 556 | self.ast_use_functions.insert(function, token_type); 557 | } 558 | 559 | fn add_use_argument(&mut self, argument: String, token_type: EliteKeywords) { 560 | self.ast_use_list.insert(argument, token_type); 561 | } 562 | 563 | pub fn to(&self, data: &str) -> String { 564 | data.to_string() 565 | } 566 | 567 | pub fn match_for_functions(&mut self, function: &String) -> &EliteKeywords { 568 | let function = self.ast_for_functions.get(function); 569 | 570 | if function.is_none() { return &EliteKeywords::Undefined; } 571 | 572 | function.unwrap() 573 | } 574 | 575 | pub fn match_for_specific_targets(&mut self, target: &String) -> &EliteKeywords { 576 | let target = self.ast_for_specific_targets.get(target); 577 | 578 | if target.is_none() { return &EliteKeywords::Undefined; } 579 | 580 | target.unwrap() 581 | } 582 | 583 | pub fn match_if_functions(&mut self, statement: &String) -> &EliteKeywords { 584 | let statement = self.ast_if_functions.get(statement); 585 | 586 | if statement.is_none() { return &EliteKeywords::Undefined; } 587 | 588 | statement.unwrap() 589 | } 590 | 591 | pub fn match_use_functions(&mut self, function: &String) -> &EliteKeywords { 592 | let function = self.ast_use_functions.get(function); 593 | 594 | if function.is_none() { return &EliteKeywords::Undefined; } 595 | 596 | function.unwrap() 597 | } 598 | 599 | pub fn match_use_arguments(&mut self, argument: &String) -> &EliteKeywords { 600 | let argument = self.ast_use_list.get(argument); 601 | 602 | if argument.is_none() { return &EliteKeywords::Undefined; } 603 | 604 | argument.unwrap() 605 | } 606 | 607 | pub fn match_types(&mut self, token: &String) -> &EliteKeywords { 608 | let token_type = self.syntax_list.get(token); 609 | 610 | if token_type.is_none() { return &EliteKeywords::Undefined; } 611 | 612 | token_type.unwrap() 613 | } 614 | } -------------------------------------------------------------------------------- /src/lexer.rs: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2021-2022 Ferhat Geçdoğan All Rights Reserved. 4 | // Distributed under the terms of the MIT License. 5 | // 6 | // 7 | 8 | pub mod elite_lexer { 9 | use crate::ast::EliteDataTree; 10 | 11 | pub fn init_lexer(init: &crate::read::EliteFileData, just_create_tree: bool) -> crate::parser::EliteParser { 12 | let tokens = crate::tokenizer::elite_tokenizer::tokenize_first(init); 13 | 14 | let mut init_ast = crate::ast::EliteAST::default(); 15 | 16 | init_ast.init_keywords(); 17 | 18 | let mut init_parser = crate::parser::EliteParser { 19 | init_ast : init_ast, 20 | ast_nodes: Default::default(), 21 | data_tree: EliteDataTree { variable_list: Default::default() }, 22 | arguments: vec![], 23 | platforms: vec![], 24 | just_ct : just_create_tree 25 | }; 26 | 27 | init_parser.parse_tokens(&tokens); 28 | 29 | //for token in tokens { 30 | // if token.is_empty() || token == init_ast.to("\n") { continue; } 31 | // 32 | // println!("<{}>", token); 33 | //} 34 | 35 | init_parser 36 | } 37 | } -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2021 Ferhat Geçdoğan All Rights Reserved. 4 | // Distributed under the terms of the MIT License. 5 | // 6 | // 7 | 8 | pub mod parser; 9 | pub mod read; 10 | pub mod lexer; 11 | pub mod tokenizer; 12 | pub mod ast; 13 | pub mod logger; 14 | 15 | pub static VERSION: f32 = 0.1; 16 | 17 | pub static VALID_VERSIONS: &'static [f32] = &[ 18 | 0.1 19 | ]; 20 | -------------------------------------------------------------------------------- /src/logger.rs: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2021 Ferhat Geçdoğan All Rights Reserved. 4 | // Distributed under the terms of the MIT License. 5 | // 6 | // 7 | 8 | #[derive(PartialEq)] 9 | pub enum EliteLogType { 10 | Success, 11 | Warning, 12 | Info , 13 | Error 14 | } 15 | 16 | pub mod elite_logger { 17 | use crate::logger::EliteLogType; 18 | 19 | pub fn log(_type: EliteLogType, token: &str, comment: &str) { 20 | println!("[{}] (\x1b[0;96m{}\x1b[0m) : {}", match _type { 21 | EliteLogType::Success => { 22 | format!("{}Success{}", "\x1b[1;93m", "\x1b[0m") 23 | }, 24 | EliteLogType::Warning => { 25 | format!("{}Warning{}", "\x1b[0;91m", "\x1b[0m") 26 | }, 27 | EliteLogType::Info => { 28 | format!("{}Info {}" , "\x1b[0;94m", "\x1b[0m") 29 | }, 30 | EliteLogType::Error => { 31 | format!("{}Error {}" , "\x1b[1;31m", "\x1b[0m") 32 | } 33 | }, token, comment); 34 | 35 | if _type == EliteLogType::Error { 36 | std::process::exit(1); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2021-2022 Ferhat Geçdoğan All Rights Reserved. 4 | // Distributed under the terms of the MIT License. 5 | // 6 | // 7 | extern crate elite; 8 | 9 | use elite::*; 10 | use elite::ast::Branch; 11 | 12 | const __VERSION__: Option<&str> = option_env!("CARGO_PKG_VERSION"); 13 | 14 | fn main() { 15 | let cli_arguments: Vec<_> = std::env::args().collect(); 16 | 17 | if cli_arguments.len() < 2 { 18 | println!("Fegeya Elite - small, powerful build system (version: {})\n\ 19 | -------\n\ 20 | Usage:\n \ 21 | {arg} file argument\n \ 22 | {arg} Elitefile install\n \ 23 | {arg} analyze Elitefile\n \ 24 | {arg} ast Elitefile", __VERSION__.unwrap_or("undefined"), 25 | arg = cli_arguments[0]); 26 | 27 | std::process::exit(1); 28 | } 29 | 30 | let arg = cli_arguments.get(1).unwrap(); 31 | if (arg == "ast" || arg == "analyze") && cli_arguments.len() < 3 { 32 | println!("{} {} Elitefile\n{}^^^^^^^^^\n{}", cli_arguments[0], 33 | &arg, 34 | " ".repeat(cli_arguments[0].len() + arg.len() + 2), 35 | " file required"); 36 | 37 | std::process::exit(1); 38 | } 39 | 40 | let mut elite_read = crate::read::EliteFileData { 41 | raw_data: crate::read::elite_file_contents::create_empty_string(), 42 | unparsed: vec![] 43 | }; 44 | 45 | let val = match cli_arguments.get(1).unwrap().as_str() { 46 | "ast" | 47 | "analyze" => { 48 | elite_read.read_raw_file(cli_arguments.get(2).unwrap()); 49 | true 50 | }, 51 | _ => { 52 | elite_read.read_raw_file(cli_arguments.get(1).unwrap()); 53 | false 54 | } 55 | }; 56 | 57 | let mut x = crate::lexer::elite_lexer::init_lexer(&elite_read, val); 58 | 59 | match cli_arguments.get(1).unwrap().as_str() { 60 | "ast" => x.ast_nodes.search(Branch::Data), 61 | "analyze" => { 62 | println!("Possible arguments:"); 63 | 64 | if x.arguments.is_empty() { 65 | println!("[not defined]"); 66 | } else { 67 | for arg in &x.arguments { 68 | println!(" * {}", arg); 69 | } 70 | } 71 | 72 | println!("\nPossible platforms:"); 73 | 74 | if x.platforms.is_empty() { 75 | println!("[not defined]"); 76 | } else { 77 | for platform in &x.platforms { 78 | println!(" * {}", platform); 79 | } 80 | } 81 | }, 82 | _ => {} 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/parser.rs: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2021-2022 Ferhat Geçdoğan All Rights Reserved. 4 | // Distributed under the terms of the MIT License. 5 | // 6 | // 7 | use { 8 | crate::{ 9 | ast::{ 10 | Branch, 11 | 12 | EliteKeywords, 13 | 14 | EliteAST, 15 | ASTNode, 16 | EliteDataTree, 17 | EliteDataInfos, 18 | 19 | ast_helpers 20 | }, 21 | 22 | logger::{*}, 23 | 24 | VALID_VERSIONS, 25 | VERSION 26 | } 27 | }; 28 | 29 | 30 | pub struct EliteParser { 31 | pub init_ast : EliteAST, 32 | pub ast_nodes: ASTNode, 33 | pub data_tree: EliteDataTree, 34 | pub arguments: Vec, 35 | pub platforms: Vec, 36 | pub just_ct : bool 37 | } 38 | 39 | impl EliteParser { 40 | pub fn parse_tokens(&mut self, tokens: &Vec) { 41 | let mut __matched_type = EliteKeywords::Undefined; 42 | let mut last_matched_function = EliteKeywords::Undefined; 43 | let mut last_matched_if_function = EliteKeywords::Undefined; 44 | 45 | let mut is_variable = false; 46 | let mut is_unset_variable = false; 47 | let mut is_defined = false; 48 | 49 | let mut is_for = false; 50 | let mut is_for_argument = false; 51 | 52 | let mut is_if = false; 53 | let mut is_if_function = false; 54 | 55 | let mut is_print = false; 56 | let mut is_newline = false; 57 | 58 | let mut is_use = false; 59 | let mut is_use_argument = false; 60 | 61 | let mut is_required_version = false; 62 | let mut is_required_version_initializer = false; 63 | 64 | let mut is_suppress = false; 65 | 66 | let mut is_data_initializer = false; 67 | 68 | // Used by argument() and specific() 69 | let mut is_main_os = true ; 70 | 71 | let mut is_use_add_source = false; 72 | let mut is_use_add_argument = false; 73 | 74 | let mut count_end_of_function: u32 = 0 ; 75 | 76 | let mut variable_name = String::new(); 77 | let mut variable_data = String::new(); 78 | 79 | let mut first_if_argument = String::new(); 80 | let mut second_if_argument = String::new(); 81 | 82 | let mut use_add_source_argument = String::new(); 83 | 84 | let mut use_current_function = String::new(); 85 | 86 | for token in tokens { 87 | if token.is_empty() { continue; } 88 | 89 | let mut token = self.init_ast.to(token.trim()); 90 | 91 | if is_defined { 92 | token = self.token_get(token.to_owned()); 93 | 94 | is_defined = false; 95 | } 96 | else if crate::tokenizer::elite_tokenizer::is_variable(&token.as_str()) { 97 | is_defined = true; 98 | 99 | continue; 100 | } 101 | 102 | __matched_type = *self.init_ast.match_types(&token); 103 | 104 | match __matched_type { 105 | EliteKeywords::Set => { 106 | is_variable = true; 107 | }, 108 | EliteKeywords::Unset => { 109 | is_unset_variable = true; 110 | }, 111 | EliteKeywords::As => { 112 | if is_variable { 113 | is_data_initializer = true; 114 | 115 | continue; 116 | } 117 | 118 | if is_required_version { 119 | is_required_version_initializer = true; 120 | } 121 | }, 122 | EliteKeywords::For => { 123 | is_for = true; 124 | }, 125 | EliteKeywords::Print => { 126 | is_print = true; 127 | }, 128 | EliteKeywords::Println => { 129 | is_print = true; 130 | is_newline = true; 131 | }, 132 | EliteKeywords::Use => { 133 | is_use = true; 134 | }, 135 | EliteKeywords::If => { 136 | is_if = true; 137 | }, 138 | EliteKeywords::RequiredVersion => { 139 | is_required_version = true; 140 | }, 141 | EliteKeywords::Suppress => { 142 | is_suppress = true; 143 | }, 144 | 145 | // Ignoring them. 146 | EliteKeywords::LeftParenthese | 147 | EliteKeywords::RightParenthese => {}, 148 | 149 | EliteKeywords::LeftSqBracket => { 150 | self.ast_nodes.insert_key(EliteDataInfos { 151 | __type: EliteKeywords::LeftSqBracket, 152 | __name: Default::default(), 153 | __data: Default::default() 154 | }, Branch::Data); 155 | 156 | if !is_main_os { 157 | count_end_of_function += 1; 158 | } 159 | 160 | continue; 161 | }, 162 | EliteKeywords::RightSqBracket => { 163 | self.ast_nodes.insert_key(EliteDataInfos { 164 | __type: EliteKeywords::RightSqBracket, 165 | __name: Default::default(), 166 | __data: Default::default() 167 | }, Branch::Data); 168 | 169 | if !is_main_os && count_end_of_function == 0 { 170 | elite_logger::log(EliteLogType::Error, 171 | "right-sq-bracket", 172 | "unmatched bracket"); 173 | } 174 | 175 | if !is_main_os { 176 | count_end_of_function -= 1; 177 | } 178 | 179 | if count_end_of_function == 0 { 180 | is_main_os = true; 181 | } 182 | }, 183 | _ => { 184 | if !is_main_os && !self.just_ct { 185 | is_newline = false; 186 | is_print = false; 187 | is_unset_variable = false; 188 | is_use = false; 189 | is_use_argument = false; 190 | is_if = false; 191 | is_if_function = false; 192 | continue; 193 | } 194 | 195 | if crate::tokenizer::elite_tokenizer::is_data(&token.as_str()) { 196 | let mut __data = String::new(); 197 | let mut __format = String::new(); 198 | 199 | let mut is_formatter = false; 200 | 201 | // token = token.replace(" ", "\\w"); 202 | 203 | for character in token.chars() { 204 | if is_formatter { 205 | if character == '}' { 206 | is_formatter = false; 207 | 208 | __data.push_str(self.token_get(__format.clone()).as_str()); 209 | 210 | __format.clear(); 211 | 212 | continue; 213 | } 214 | 215 | __format.push(character); 216 | 217 | continue; 218 | } 219 | 220 | if character == '{' { 221 | is_formatter = true; 222 | 223 | continue; 224 | } 225 | 226 | __data.push(character); 227 | 228 | continue; 229 | } 230 | 231 | token = __data; 232 | } 233 | 234 | if is_if { 235 | if token.is_empty() { continue; } 236 | 237 | if is_if_function { 238 | if first_if_argument.is_empty() { 239 | first_if_argument = crate::ast::ast_helpers::extract_argument(&token); 240 | 241 | continue; 242 | } 243 | 244 | if second_if_argument.is_empty() { 245 | second_if_argument = crate::ast::ast_helpers::extract_argument(&token); 246 | } 247 | 248 | match last_matched_if_function { 249 | EliteKeywords::Eq | 250 | EliteKeywords::UnEq => { 251 | self.ast_nodes.insert_key(EliteDataInfos { 252 | __type: EliteKeywords::IfArg, 253 | __name: variable_name.clone(), 254 | __data: crate::ast::ast_helpers::extract_argument(&first_if_argument.clone()) 255 | }, Branch::Data); 256 | 257 | self.ast_nodes.insert_key(EliteDataInfos { 258 | __type: last_matched_if_function.clone(), 259 | __name: variable_name.clone(), 260 | __data: crate::ast::ast_helpers::extract_argument(&second_if_argument.clone()) 261 | }, Branch::Data); 262 | 263 | is_main_os = self.ast_parse_if_function(variable_name.clone(), 264 | crate::ast::ast_helpers::extract_argument(&first_if_argument.clone()), 265 | crate::ast::ast_helpers::extract_argument(&second_if_argument.clone())); 266 | }, 267 | _ => { 268 | elite_logger::log(EliteLogType::Error, 269 | &token, 270 | "syntax error, \ 271 | undefined if function"); 272 | } 273 | } 274 | 275 | is_if = false; 276 | is_if_function = false; 277 | 278 | first_if_argument .clear(); 279 | second_if_argument.clear(); 280 | 281 | continue; 282 | } 283 | 284 | if self.init_ast.match_if_functions(&token) != &EliteKeywords::Undefined { 285 | is_if_function = true; 286 | 287 | last_matched_if_function = *self.init_ast.match_if_functions(&token); 288 | 289 | variable_name = token.clone(); 290 | } 291 | else { 292 | elite_logger::log(EliteLogType::Error, 293 | &token, "syntax error, undefined if function"); 294 | } 295 | 296 | continue; 297 | } 298 | 299 | if is_use { 300 | // All 'use' functions are takes 1 argument 301 | // add_source is excepted, it's requires 2 argument. 302 | if is_use_add_source { 303 | if is_use_add_argument { 304 | let token = ast_helpers::extract_argument(&token); 305 | 306 | match self.init_ast.match_use_functions(&use_current_function) { 307 | EliteKeywords::AddSource => { 308 | if !std::path::Path::new(&token).exists() { 309 | elite_logger::log(EliteLogType::Warning, 310 | &token, "source file is not exist"); 311 | } 312 | 313 | self.token_append(use_add_source_argument.clone(), 314 | ast_helpers::extract_argument(&token), 315 | ' '); 316 | }, 317 | EliteKeywords::Append => { 318 | self.token_append(use_add_source_argument.clone(), 319 | ast_helpers::extract_argument(&token), 320 | Default::default()); 321 | } 322 | _ => {} 323 | } 324 | 325 | 326 | is_use_add_source = false; 327 | is_use_add_argument = false; 328 | 329 | use_add_source_argument.clear(); 330 | 331 | continue; 332 | } 333 | 334 | use_add_source_argument = token.clone(); 335 | 336 | is_use_add_argument = true; 337 | 338 | continue; 339 | } 340 | 341 | match self.init_ast.match_use_functions(&token).clone() { 342 | EliteKeywords::AddSource | 343 | EliteKeywords::Append => { 344 | is_use_add_source = true; 345 | 346 | use_current_function = token.clone(); 347 | 348 | continue; 349 | }, 350 | _ => { 351 | is_use_add_source = false; 352 | 353 | use_current_function = token.clone(); 354 | } 355 | } 356 | 357 | if is_use_argument { 358 | let token: &String = &ast_helpers::extract_argument(&token); 359 | 360 | for argument in &self.init_ast.ast_for_use_arguments.clone() { 361 | if argument == token { 362 | self.ast_parse_use(token.to_string()); 363 | } 364 | } 365 | 366 | if token.is_empty() { continue; } 367 | 368 | self.ast_parse_use_function(variable_data.clone(), 369 | ast_helpers::extract_argument(token), 370 | is_suppress); 371 | 372 | if is_suppress { is_suppress = false; } 373 | 374 | is_use = false; 375 | is_use_argument = false; 376 | 377 | continue; 378 | } 379 | 380 | for function in &self.init_ast.ast_for_use { 381 | if function == &token { 382 | is_use_argument = true; 383 | variable_data = function.clone(); 384 | 385 | continue; 386 | } 387 | } 388 | } 389 | 390 | // Built-in regular print function. 391 | if is_print { 392 | if !is_suppress { 393 | if !self.just_ct { 394 | print!("{}", 395 | &ast_helpers::extract_argument(&token)); 396 | } 397 | } 398 | 399 | is_print = false; 400 | 401 | if is_newline { 402 | self.ast_nodes.insert_key(EliteDataInfos { 403 | __type: EliteKeywords::Println, 404 | __name: "not_defined".to_string(), 405 | __data: ast_helpers::extract_argument(&ast_helpers::extract_argument(&token)) 406 | }, Branch::Data); 407 | 408 | if !is_suppress { 409 | if !self.just_ct { 410 | println!(); 411 | } 412 | } 413 | 414 | is_newline = false; 415 | } else { 416 | self.ast_nodes.insert_key(EliteDataInfos { 417 | __type: EliteKeywords::Print, 418 | __name: "not_defined".to_string(), 419 | __data: ast_helpers::extract_argument(&ast_helpers::extract_argument(&token)) 420 | }, Branch::Data); 421 | } 422 | 423 | is_suppress = false; 424 | continue; 425 | } 426 | 427 | if is_unset_variable { 428 | self.ast_nodes.insert_key(EliteDataInfos { 429 | __type: EliteKeywords::Unset, 430 | __name: token.clone(), 431 | __data: "not_defined".to_string() 432 | }, Branch::Data); 433 | 434 | let token = ast_helpers::extract_argument(&token); 435 | 436 | self.data_tree.variable_list.retain(|val| *val.__name != token); 437 | is_unset_variable = false; 438 | continue; 439 | } 440 | 441 | // for signal("...") 442 | if is_for { 443 | if is_for_argument { 444 | let token = &(ast_helpers::extract_argument(&token)); 445 | 446 | match last_matched_function { 447 | EliteKeywords::Specific | 448 | EliteKeywords::Argument | 449 | EliteKeywords::Exists => { 450 | is_main_os = self.ast_parse_for_functions(variable_name.clone(), 451 | ast_helpers::extract_argument(token)); 452 | }, 453 | _ => { 454 | self.ast_parse_for_functions(variable_name.clone(), 455 | ast_helpers::extract_argument(token)); 456 | } 457 | } 458 | 459 | is_for = false; 460 | is_for_argument = false; 461 | 462 | variable_name.clear(); 463 | 464 | continue; 465 | } 466 | 467 | if self.init_ast.match_for_functions(&token) != &EliteKeywords::Undefined { 468 | is_for_argument = true; 469 | last_matched_function = *self.init_ast.match_for_functions(&token); 470 | 471 | variable_name = token.clone(); 472 | } 473 | 474 | continue; 475 | } 476 | 477 | if is_required_version { 478 | if is_required_version_initializer { 479 | self.ast_nodes.insert_key(EliteDataInfos { 480 | __type: EliteKeywords::RequiredVersion, 481 | __name: token.clone(), 482 | __data: token.clone() 483 | }, Branch::Data); 484 | 485 | if crate::tokenizer::elite_tokenizer::is_data(&token.as_str()) { 486 | elite_logger::log(EliteLogType::Error, 487 | "string_notation", &*format!( 488 | "required_version must be used with \ 489 | float literal, \ 490 | not string. \ 491 | use {data} instead of \"{data}\"", 492 | data = ast_helpers::extract_argument(&token))); 493 | } 494 | 495 | is_required_version = false; 496 | is_required_version_initializer = false; 497 | 498 | let version = token.parse::().unwrap(); 499 | let mut is_valid = false; 500 | 501 | for __version in VALID_VERSIONS { 502 | // Valid version 503 | if __version == &version { 504 | if version > VERSION { 505 | elite_logger::log(EliteLogType::Info, 506 | "required_version", 507 | &*format!("required {} or latest version", 508 | token)); 509 | 510 | if !self.just_ct { 511 | std::process::exit(1); 512 | } 513 | } 514 | 515 | is_valid = true; 516 | 517 | break; 518 | } 519 | } 520 | 521 | if !is_valid { 522 | elite_logger::log(EliteLogType::Error, 523 | "invalid_version", 524 | &*format!("invalid version: {}, \ 525 | for latest valid version: {}", 526 | version, 527 | VALID_VERSIONS.last().unwrap())); 528 | } 529 | } 530 | } 531 | 532 | if is_variable { 533 | if is_data_initializer { 534 | is_variable = false; 535 | is_data_initializer = false; 536 | 537 | self.token_set(variable_name.clone(), 538 | ast_helpers::extract_argument(&token)); 539 | 540 | variable_name.clear(); 541 | 542 | continue; 543 | } 544 | 545 | variable_name = token.clone(); 546 | continue; 547 | } 548 | } 549 | } 550 | } 551 | } 552 | 553 | pub fn ast_parse_for_functions(&mut self, function: String, argument: String) -> bool { 554 | self.ast_nodes.insert_key(EliteDataInfos { 555 | __type: self.init_ast.match_for_functions(&function).clone(), 556 | __name: "not_defined".to_string(), 557 | __data: argument.clone() 558 | }, Branch::Data); 559 | 560 | match *self.init_ast.match_for_functions(&function) { 561 | EliteKeywords::Argument => { 562 | if !self.arguments.contains(&argument.clone()) { 563 | self.arguments.push(argument.clone()); 564 | } 565 | }, 566 | EliteKeywords::Specific => { 567 | if !self.platforms.contains(&argument.clone()) { 568 | self.platforms.push(argument.clone()); 569 | } 570 | }, _ => {} 571 | } if self.just_ct { return true; } 572 | 573 | match self.init_ast.match_for_functions(&function) { 574 | EliteKeywords::Signal => { 575 | // TODO: Signal parser. 576 | false 577 | }, 578 | EliteKeywords::Specific => { 579 | self.ast_parse_for_specific_target(argument) 580 | }, 581 | EliteKeywords::Argument => { 582 | self.is_same_arg(&argument) 583 | }, 584 | EliteKeywords::Exists => { 585 | self.is_exists(&argument) 586 | }, 587 | _ => { 588 | elite_logger::log(EliteLogType::Error, 589 | &function, 590 | "syntax error, undefined for function"); 591 | false 592 | } 593 | } 594 | } 595 | 596 | pub fn ast_parse_for_specific_target(&mut self, target: String) -> bool { 597 | if self.just_ct { return true; } 598 | match self.init_ast.match_for_specific_targets(&target) { 599 | // EliteKeywords::Windows => { 600 | // 601 | // }, 602 | // EliteKeywords::macOS => { 603 | // 604 | // }, 605 | // EliteKeywords::iOS => { 606 | // 607 | // }, 608 | // EliteKeywords::Linux => { 609 | // 610 | // }, 611 | // EliteKeywords::Android => { 612 | // 613 | // }, 614 | // EliteKeywords::FreeBSD => { 615 | // 616 | // }, 617 | // EliteKeywords::DragonFly => { 618 | // 619 | // }, 620 | // EliteKeywords::Bitrig => { 621 | // 622 | // }, 623 | // EliteKeywords ::OpenBSD => { 624 | // 625 | // }, 626 | // EliteKeywords::NetBSD => { 627 | // 628 | // }, 629 | EliteKeywords::Undefined => { 630 | elite_logger::log(EliteLogType::Error, 631 | &target, 632 | "undefined os target"); 633 | 634 | false 635 | }, 636 | _ => { 637 | return self.is_same(&target); 638 | } 639 | } 640 | } 641 | 642 | pub fn ast_parse_if_function(&mut self, function: String, argument_1: String, argument_2: String) -> bool { 643 | if self.just_ct { return true; } 644 | 645 | match self.init_ast.match_if_functions(&function) { 646 | EliteKeywords::Eq => { 647 | self.is_same_argument(&argument_1, &argument_2) 648 | }, 649 | EliteKeywords::UnEq => { 650 | self.is_not_same_argument(&argument_1, &argument_2) 651 | }, 652 | _ => { 653 | false 654 | } 655 | } 656 | } 657 | 658 | pub fn ast_parse_use_function(&mut self, function: String, argument: String, suppress: bool) { 659 | self.ast_nodes.insert_key(EliteDataInfos { 660 | __type: self.init_ast.match_use_functions(&function).clone(), 661 | __name: argument.clone(), 662 | __data: function.clone() 663 | }, Branch::Data); 664 | 665 | match self.init_ast.match_use_functions(&function) { 666 | EliteKeywords::Signal => { 667 | self.ast_parse_use(argument); 668 | }, 669 | EliteKeywords::Exec => { 670 | let mut command = String::new(); 671 | 672 | for character in argument.split(' ').collect::>().get(0).unwrap().chars() { 673 | if character != '"' || character != ' ' { 674 | command.push(character); 675 | 676 | continue; 677 | } 678 | 679 | break; 680 | } 681 | 682 | if argument.contains(' ') { 683 | let mut arguments: Vec<&str> = argument.split(' ').collect(); 684 | let mut clean_args: Vec<&str> = vec![]; 685 | 686 | arguments.remove(0); 687 | 688 | for &mut arg in arguments.iter_mut() { 689 | let arg = arg.trim(); 690 | 691 | if !arg.is_empty() { 692 | clean_args.push(arg); 693 | } 694 | } 695 | 696 | let mut syscall = std::process::Command::new(command.clone()); 697 | 698 | syscall.args(clean_args); 699 | 700 | if !suppress { 701 | if !self.just_ct { 702 | syscall.status() 703 | .expect(format!("{} command failed to execute!", command.to_owned()).as_str()); 704 | } 705 | } else { 706 | match syscall.output() { _ => {} } 707 | } 708 | } 709 | else { 710 | let mut syscall = std::process::Command::new(command.clone()); 711 | 712 | if !suppress { 713 | if !self.just_ct { 714 | syscall.status() 715 | .expect(format!("{} command failed to execute!", command.to_owned()).as_str()); 716 | } 717 | } else { 718 | match syscall.output() { _ => {} } 719 | } 720 | } 721 | } 722 | _ => { 723 | elite_logger::log(EliteLogType::Error, 724 | &function, 725 | "syntax error, undefined use function"); 726 | } 727 | } 728 | } 729 | 730 | pub fn ast_parse_use(&mut self, argument: String) { 731 | match self.init_ast.match_use_arguments(&argument) { 732 | EliteKeywords::Exit => { 733 | if !self.just_ct { 734 | std::process::exit(0); 735 | } 736 | }, 737 | _ => { 738 | if argument != "start" { 739 | elite_logger::log(EliteLogType::Error, 740 | &format!("{}", argument), 741 | "syntax error, undefined use function"); 742 | } 743 | } 744 | } 745 | } 746 | 747 | // Syntax rule: 748 | // use {VARIABLE_NAME} as {data} 749 | pub fn token_set(&mut self, variable: String, data: String) { 750 | // Check is variable exists. 751 | for (_index, variable_list) in self.data_tree.variable_list.iter().enumerate() { 752 | if variable_list.__name == variable { 753 | self.data_tree.variable_list[_index].__data = data.clone(); 754 | 755 | self.ast_nodes.insert_key(EliteDataInfos { 756 | __type: EliteKeywords::Change, 757 | __name: self.data_tree.variable_list[_index].__name.clone(), 758 | __data: self.data_tree.variable_list[_index].__data.clone() 759 | }, Branch::Data); 760 | 761 | return; 762 | } 763 | } 764 | 765 | self.data_tree.variable_list.push( 766 | EliteDataInfos { 767 | __type: EliteKeywords::Set, 768 | __name: variable.clone(), 769 | __data: data.clone() 770 | } 771 | ); 772 | 773 | self.ast_nodes.insert_key(EliteDataInfos { 774 | __type: EliteKeywords::Set, 775 | __name: variable.clone(), 776 | __data: data.clone() 777 | }, Branch::Data); 778 | } 779 | 780 | pub fn token_get(&self, variable: String) -> String { 781 | for variable_list in self.data_tree.variable_list.iter() { 782 | if variable == variable_list.__name { 783 | if variable_list.__type != EliteKeywords::Undefined { return String::from(variable_list.__data.clone()); } 784 | } 785 | } 786 | 787 | self.init_ast.to("") 788 | } 789 | 790 | pub fn token_append(&mut self, variable: String, argument: String, delimiter: char) { 791 | for (_index, variable_list) in self.data_tree.variable_list.iter().enumerate() { 792 | if variable_list.__name == variable { 793 | self.data_tree.variable_list[_index].__data.push_str( 794 | format!("{}{}", delimiter, argument).as_str()); 795 | 796 | self.ast_nodes.insert_key(EliteDataInfos { 797 | __type: EliteKeywords::Append, 798 | __name: self.data_tree.variable_list[_index].__name.clone(), 799 | __data: argument.clone() 800 | }, Branch::Data); 801 | 802 | return; 803 | } 804 | } 805 | } 806 | 807 | pub fn is_exists(&self, path: &String) -> bool { 808 | return if std::path::Path::new(path).exists() { 809 | true 810 | } else { false }; 811 | } 812 | 813 | pub fn is_same_arg(&self, argument: &String) -> bool { 814 | let __argument: Vec<_> = std::env::args().collect(); 815 | 816 | return if __argument.last().unwrap() == argument { 817 | true 818 | } else { false }; 819 | } 820 | 821 | pub fn is_same(&self, target: &String) -> bool { 822 | return if std::env::consts::OS == target || std::env::consts::ARCH == target { 823 | true 824 | } else { false }; 825 | } 826 | 827 | pub fn is_same_argument(&self, argument_1: &String, argument_2: &String) -> bool { 828 | return if argument_1 == argument_2 { 829 | true 830 | } else { false }; 831 | } 832 | 833 | pub fn is_not_same_argument(&self, argument_1: &String, argument_2: &String) -> bool { 834 | return if argument_1 != argument_2 { 835 | true 836 | } else { false }; 837 | } 838 | } -------------------------------------------------------------------------------- /src/read.rs: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2021 Ferhat Geçdoğan All Rights Reserved. 4 | // Distributed under the terms of the MIT License. 5 | // 6 | // 7 | 8 | use std::io::BufRead; 9 | 10 | pub struct EliteFileData { 11 | pub raw_data: String, 12 | pub unparsed: Vec 13 | } 14 | 15 | pub mod elite_file_contents { 16 | // to_lowercase(filename) supported. 17 | // filename: EliTeFilE, eliteFILE, EliteFile etc. 18 | pub const GENERIC_FILENAME: &str = "elitefile"; 19 | 20 | pub fn create_empty_string() -> String { 21 | return "".to_string(); 22 | } 23 | } 24 | 25 | impl EliteFileData { 26 | pub fn check_is_elite(&self, file: &String) -> bool { 27 | return if file.to_ascii_lowercase() == elite_file_contents::GENERIC_FILENAME { 28 | true 29 | } else { 30 | false 31 | }; 32 | } 33 | 34 | pub fn read_raw_file(&mut self, file: &String) { 35 | // if !self.check_is_elite(file) { 36 | // elite_logger::log(EliteLogType::Info, 37 | // "filename", 38 | // &format!("to_lowercase({}) ignored", file)); 39 | // } 40 | 41 | let mut raw_data = String::new(); 42 | 43 | if let Ok(lines) = self.read_lines(file) { 44 | for line in lines { 45 | if let Ok(ip) = line { 46 | if crate::tokenizer::elite_tokenizer::is_comment(&ip.as_str()) { 47 | continue; 48 | } 49 | 50 | raw_data.push(' '); raw_data.push_str(&ip); raw_data.push('\n'); 51 | } 52 | } 53 | } 54 | 55 | self.raw_data = raw_data; 56 | } 57 | 58 | fn read_lines

(&self, file: &P) -> std::io::Result< 59 | std::io::Lines> 60 | > where P: AsRef, { 61 | Ok(std::io::BufReader::new( 62 | std::fs::File::open(file)?).lines()) 63 | } 64 | } -------------------------------------------------------------------------------- /src/tokenizer.rs: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2021 Ferhat Geçdoğan All Rights Reserved. 4 | // Distributed under the terms of the MIT License. 5 | // 6 | // 7 | 8 | pub mod elite_tokenizer { 9 | use crate::logger::{ EliteLogType, elite_logger }; 10 | 11 | static TOKEN_LIST: &'static [char] = &[ 12 | '(', 13 | ')', 14 | '[', 15 | ']', 16 | '$', 17 | ',' 18 | ]; 19 | 20 | pub fn tokenize_first(raw_data: &crate::read::EliteFileData) -> Vec { 21 | let mut tokenized_data: Vec = vec![]; 22 | let mut current_token = String::new(); 23 | let mut escape_sequence = false; 24 | let mut data = false; 25 | let mut skip_until_newline = false; 26 | let mut is_env = false; 27 | let mut is_link = false; 28 | let mut is_std = false; 29 | let mut is_outfile = false; 30 | 31 | for ch in raw_data.raw_data.chars() { 32 | if ch != '\n' && skip_until_newline { 33 | continue; 34 | } 35 | 36 | match ch { 37 | '\n' => { 38 | if skip_until_newline { 39 | skip_until_newline = false; 40 | } else if data { 41 | current_token.push_str("\\n"); 42 | } 43 | }, 44 | '(' | 45 | ')' | 46 | '[' | 47 | ']' | 48 | '$' | 49 | ',' | 50 | ' ' => { 51 | if data { 52 | current_token.push(ch); 53 | } else { 54 | if is_preprocessor_token(¤t_token, "env") { 55 | is_env = true; 56 | } else if is_preprocessor_token(¤t_token, "link") { 57 | is_link = true; 58 | } else if is_preprocessor_token(¤t_token, "std") { 59 | is_std = true; 60 | } else if is_preprocessor_token(¤t_token, "outfile") { 61 | is_outfile = true; 62 | } else { 63 | tokenized_data.push(current_token.clone()); 64 | } 65 | 66 | if ch != ' ' { 67 | tokenized_data.push(format!("{}", ch)); 68 | } 69 | 70 | current_token.clear(); 71 | } 72 | }, 73 | '\'' | 74 | '"' => { 75 | if escape_sequence { 76 | data = true; 77 | current_token.push(ch); 78 | } else { 79 | if !current_token.starts_with(ch) { 80 | data = true; 81 | current_token.push(ch); 82 | continue; 83 | } 84 | 85 | if is_link { 86 | let mut linker_flags = String::new(); 87 | 88 | for val in &crate::ast::ast_helpers::extract_argument(¤t_token.clone()).split(' ').collect::>() { 89 | linker_flags.push_str(format!("-l{} ", val).as_str()); 90 | } 91 | 92 | linker_flags.pop(); 93 | tokenized_data.push(linker_flags.to_owned()); 94 | 95 | is_link = false; 96 | } else if is_std { 97 | tokenized_data.push(format!("-std={}", 98 | &crate::ast::ast_helpers::extract_argument(¤t_token.clone()))); 99 | 100 | is_std = false; 101 | } else if is_outfile { 102 | tokenized_data.push(format!("-o {}", 103 | &crate::ast::ast_helpers::extract_argument(¤t_token.clone()))); 104 | 105 | is_outfile = false; 106 | } else if is_env { 107 | let environment = get_environment(&crate::ast::ast_helpers::extract_argument( 108 | ¤t_token.clone()).as_str()); 109 | 110 | // Replace whitespace with '_' 111 | //if !is_data(&token) { 112 | // Error (Environments must be string that has not any whitespace (use _ instead)) 113 | //} 114 | 115 | if !environment.is_empty() { 116 | tokenized_data.push(format!("{}", environment.to_owned())); 117 | } 118 | // else { 119 | // Error (environment not found in this scope) 120 | //} 121 | 122 | is_env = false; 123 | } else { 124 | current_token.push(ch); 125 | 126 | tokenized_data.push(current_token.clone()); 127 | } 128 | 129 | data = false; 130 | // escafe::run() 131 | current_token.clear(); 132 | escape_sequence = false; 133 | } 134 | }, 135 | '\\' => { 136 | if escape_sequence { 137 | current_token.push('\\'); 138 | } else if data { 139 | escape_sequence = true; 140 | } 141 | }, 142 | 'n' | 143 | 't' | 144 | 'r' | 145 | 'x' | 146 | '0' | 147 | '1' | 148 | 'm' | 149 | 'w' => { 150 | if escape_sequence { 151 | current_token.push('\\'); 152 | escape_sequence = false; 153 | } current_token.push(ch); 154 | }, 155 | '#' => { 156 | if !escape_sequence && !data { 157 | skip_until_newline = true; 158 | } else { 159 | current_token.push('#'); 160 | } 161 | }, 162 | _ => { 163 | current_token.push(ch); 164 | } 165 | } 166 | } 167 | 168 | if !current_token.is_empty() { 169 | tokenized_data.push(current_token.clone()); 170 | } 171 | 172 | tokenized_data 173 | } 174 | 175 | /*fn get_data(tokens: &Vec<&str>, n: usize) -> String { 176 | let mut temporary = String::new(); 177 | 178 | temporary.push_str(tokens.get(n).unwrap()); 179 | 180 | for (_index, token) in tokens.iter().enumerate().skip(&n + 1) { 181 | if token.is_empty() { continue; } 182 | 183 | if !is_data(token) { 184 | temporary.push(' '); 185 | temporary.push_str(token); 186 | 187 | continue; 188 | } 189 | 190 | temporary.push_str(" "); 191 | temporary.push_str(token); 192 | 193 | break; 194 | } 195 | 196 | temporary 197 | }*/ 198 | 199 | pub fn replace_for_tokenize(token: &String) -> String { 200 | let mut token= String::from(token); 201 | 202 | for character in TOKEN_LIST { 203 | token = replace_with(&token, *character); 204 | } 205 | 206 | token 207 | } 208 | 209 | pub fn is_data(token: &&str) -> bool { 210 | return if token.trim_start().starts_with('"') 211 | || token.trim_end().ends_with('"') { 212 | true 213 | } else { false }; 214 | } 215 | 216 | pub fn is_variable(token: &&str) -> bool { 217 | return if token.trim_start().starts_with('$') { 218 | true 219 | } else { false }; 220 | } 221 | 222 | pub fn is_preprocessor_token(token: &String, what: &str) -> bool { 223 | return if &token == &what { 224 | true 225 | } else { false }; 226 | } 227 | 228 | pub fn is_comment(token: &&str) -> bool { 229 | if token.len() < 2 { return false; } 230 | 231 | let token = token.trim(); 232 | 233 | return if token.starts_with('\\') && token.chars().nth(1).unwrap() == '\\' { 234 | true 235 | } 236 | else if token.starts_with('/') && token.chars().nth(1).unwrap() == '/' { 237 | elite_logger::log(EliteLogType::Warning, 238 | "comment", 239 | "do not use '\x1b[1;97m//\x1b[0m' as comment, ignored."); 240 | 241 | true 242 | } 243 | else { 244 | false 245 | }; 246 | } 247 | 248 | pub fn get_environment(data: &&str) -> String { 249 | return match std::env::var(data) { 250 | Ok(__data) => __data, 251 | Err(__error) => "".to_string() 252 | } 253 | } 254 | 255 | pub fn replace_with(token: &String, character: char) -> String { 256 | token.replace(character, format!(" {} ", character).as_str()).to_string() 257 | } 258 | } --------------------------------------------------------------------------------