Skip to content

Commit 6167b28

Browse files
authored
Update main.rs
1 parent dd73e60 commit 6167b28

File tree

1 file changed

+172
-44
lines changed

1 file changed

+172
-44
lines changed

hacker-compiler/src/main.rs

Lines changed: 172 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
1616
use base64::Engine;
1717

1818
const HACKER_DIR: &str = "~/.hackeros/hacker-lang";
19+
1920
fn expand_home(path: &str) -> String {
2021
if path.starts_with("~/") {
2122
if let Some(home) = env::var_os("HOME") {
@@ -24,35 +25,55 @@ fn expand_home(path: &str) -> String {
2425
}
2526
path.to_string()
2627
}
28+
2729
#[derive(Debug)]
2830
struct Plugin {
2931
name: String,
30-
// Dodatkowe pola dla pluginów, np. path: String,
32+
is_super: bool,
3133
}
32-
fn parse_hacker_file(path: &Path, verbose: bool, bytes_mode: bool) -> io::Result<(Vec<String>, Vec<String>, Vec<(String, String)>, Vec<String>, Vec<String>, Vec<String>, Vec<String>, std::collections::HashMap<String, String>, Vec<Plugin>)> {
34+
35+
fn parse_hacker_file(path: &Path, verbose: bool, bytes_mode: bool) -> io::Result<(Vec<String>, Vec<String>, Vec<(String, String)>, Vec<String>, Vec<String>, Vec<String>, Vec<(String, String)>, Vec<String>, std::collections::HashMap<String, String>, Vec<Plugin>, std::collections::HashMap<String, Vec<String>>)> {
3336
let file = File::open(path)?;
34-
let mut deps = Vec::new();
35-
let mut libs = Vec::new();
36-
let mut vars = Vec::new();
37-
let mut cmds = Vec::new();
38-
let mut includes = Vec::new();
39-
let mut binaries = Vec::new(); // Binary lib paths
40-
let mut errors = Vec::new();
41-
let mut config = std::collections::HashMap::new();
42-
let mut plugins = Vec::new(); // Nowe: lista pluginów
37+
let mut deps: Vec<String> = Vec::new();
38+
let mut libs: Vec<String> = Vec::new();
39+
let mut vars: Vec<(String, String)> = Vec::new();
40+
let mut local_vars: Vec<(String, String)> = Vec::new();
41+
let mut cmds: Vec<String> = Vec::new();
42+
let mut includes: Vec<String> = Vec::new();
43+
let mut binaries: Vec<String> = Vec::new(); // Binary lib paths
44+
let mut errors: Vec<String> = Vec::new();
45+
let mut config: std::collections::HashMap<String, String> = std::collections::HashMap::new();
46+
let mut plugins: Vec<Plugin> = Vec::new();
47+
let mut functions: std::collections::HashMap<String, Vec<String>> = std::collections::HashMap::new();
4348
let mut in_config = false;
49+
let mut in_comment = false;
50+
let mut in_function: Option<String> = None;
4451
let mut line_num = 0;
4552
for line in io::BufReader::new(file).lines() {
4653
line_num += 1;
47-
let line = line?;
48-
let line = line.trim().to_string();
54+
let mut line = line?;
55+
line = line.trim().to_string();
4956
if line.is_empty() {
5057
continue;
5158
}
59+
if line == "!!" {
60+
in_comment = !in_comment;
61+
continue;
62+
}
63+
if in_comment {
64+
continue;
65+
}
66+
let is_super = line.starts_with('^');
67+
if is_super {
68+
line = line[1..].trim().to_string();
69+
}
5270
if line == "[" {
5371
if in_config {
5472
errors.push(format!("Line {}: Nested config section", line_num));
5573
}
74+
if in_function.is_some() {
75+
errors.push(format!("Line {}: Config in function", line_num));
76+
}
5677
in_config = true;
5778
continue;
5879
} else if line == "]" {
@@ -70,14 +91,67 @@ fn parse_hacker_file(path: &Path, verbose: bool, bytes_mode: bool) -> io::Result
7091
}
7192
continue;
7293
}
94+
if line == ":" {
95+
if in_function.is_some() {
96+
in_function = None;
97+
} else {
98+
errors.push(format!("Line {}: Ending function without start", line_num));
99+
}
100+
continue;
101+
} else if line.starts_with(":") {
102+
let func_name = line[1..].trim().to_string();
103+
if func_name.is_empty() {
104+
errors.push(format!("Line {}: Empty function name", line_num));
105+
continue;
106+
}
107+
if in_function.is_some() {
108+
errors.push(format!("Line {}: Nested function", line_num));
109+
}
110+
functions.insert(func_name.clone(), Vec::new());
111+
in_function = Some(func_name);
112+
continue;
113+
} else if line.starts_with(".") {
114+
let func_name = line[1..].trim().to_string();
115+
if func_name.is_empty() {
116+
errors.push(format!("Line {}: Empty function call", line_num));
117+
continue;
118+
}
119+
if let Some(f_cmds) = functions.get(&func_name).cloned() {
120+
let target = if let Some(ref f) = in_function {
121+
functions.get_mut(f).unwrap()
122+
} else {
123+
&mut cmds
124+
};
125+
for c in &f_cmds {
126+
target.push(c.clone());
127+
}
128+
} else {
129+
errors.push(format!("Line {}: Unknown function {}", line_num, func_name));
130+
}
131+
continue;
132+
}
133+
if in_function.is_some() {
134+
if !line.starts_with(">") && !line.starts_with("=") && !line.starts_with("?") && !line.starts_with("&") && !line.starts_with("!") && !line.starts_with("@") && !line.starts_with("$") && !line.starts_with("\\") {
135+
errors.push(format!("Line {}: Invalid in function", line_num));
136+
continue;
137+
}
138+
}
73139
if line.starts_with("//") {
140+
if in_function.is_some() {
141+
errors.push(format!("Line {}: Deps not allowed in function", line_num));
142+
continue;
143+
}
74144
let dep = line[2..].trim().to_string();
75145
if dep.is_empty() {
76146
errors.push(format!("Line {}: Empty system dependency", line_num));
77147
} else {
78148
deps.push(dep);
79149
}
80150
} else if line.starts_with("#") {
151+
if in_function.is_some() {
152+
errors.push(format!("Line {}: Libs not allowed in function", line_num));
153+
continue;
154+
}
81155
let lib = line[1..].trim().to_string();
82156
if lib.is_empty() {
83157
errors.push(format!("Line {}: Empty library/include", line_num));
@@ -87,10 +161,11 @@ fn parse_hacker_file(path: &Path, verbose: bool, bytes_mode: bool) -> io::Result
87161
let lib_bin_path = expand_home(&format!("{}/libs/{}", HACKER_DIR, lib)); // Binary file
88162
if Path::new(&lib_hacker_path).exists() {
89163
includes.push(lib.clone());
90-
let (sub_deps, sub_libs, sub_vars, sub_cmds, sub_includes, sub_binaries, sub_errors, sub_config, sub_plugins) = parse_hacker_file(Path::new(&lib_hacker_path), verbose, bytes_mode)?;
164+
let (sub_deps, sub_libs, sub_vars, sub_cmds, sub_includes, sub_binaries, sub_local_vars, sub_errors, sub_config, sub_plugins, sub_functions) = parse_hacker_file(Path::new(&lib_hacker_path), verbose, bytes_mode)?;
91165
deps.extend(sub_deps);
92166
libs.extend(sub_libs);
93167
vars.extend(sub_vars);
168+
local_vars.extend(sub_local_vars);
94169
cmds.extend(sub_cmds);
95170
includes.extend(sub_includes);
96171
binaries.extend(sub_binaries);
@@ -99,6 +174,7 @@ fn parse_hacker_file(path: &Path, verbose: bool, bytes_mode: bool) -> io::Result
99174
}
100175
config.extend(sub_config);
101176
plugins.extend(sub_plugins);
177+
functions.extend(sub_functions);
102178
} else if Path::new(&lib_bin_path).exists() && Path::new(&lib_bin_path).metadata()?.permissions().mode() & 0o111 != 0 {
103179
binaries.push(lib_bin_path.clone());
104180
if bytes_mode {
@@ -111,11 +187,15 @@ fn parse_hacker_file(path: &Path, verbose: bool, bytes_mode: bool) -> io::Result
111187
}
112188
} else if line.starts_with(">") {
113189
let parts: Vec<String> = line[1..].split('!').map(|s| s.trim().to_string()).collect();
114-
let cmd = parts[0].clone();
190+
let mut cmd = parts[0].clone();
191+
if is_super {
192+
cmd = format!("sudo {}", cmd);
193+
}
115194
if cmd.is_empty() {
116195
errors.push(format!("Line {}: Empty command", line_num));
117196
} else {
118-
cmds.push(cmd);
197+
let target = if let Some(ref f) = in_function { functions.get_mut(f).unwrap() } else { &mut cmds };
198+
target.push(cmd);
119199
}
120200
} else if line.starts_with("@") {
121201
if let Some(eq_idx) = line.find('=') {
@@ -127,35 +207,50 @@ fn parse_hacker_file(path: &Path, verbose: bool, bytes_mode: bool) -> io::Result
127207
vars.push((var, value));
128208
}
129209
} else {
130-
// Nowe: obsługa pluginów @ nazwa_pluginu (bez =)
131-
let plugin_name = line[1..].trim().to_string();
132-
if plugin_name.is_empty() {
133-
errors.push(format!("Line {}: Empty plugin name", line_num));
210+
errors.push(format!("Line {}: Invalid @ syntax", line_num));
211+
}
212+
} else if line.starts_with("$") {
213+
if let Some(eq_idx) = line.find('=') {
214+
let var = line[1..eq_idx].trim().to_string();
215+
let value = line[eq_idx + 1..].trim().to_string();
216+
if var.is_empty() || value.is_empty() {
217+
errors.push(format!("Line {}: Invalid local variable", line_num));
134218
} else {
135-
// Szukaj pluginu w ~/.hackeros/hacker-lang/plugins/ jako binarka lub źródło
136-
let plugin_path = expand_home(&format!("{}/plugins/{}", HACKER_DIR, plugin_name));
137-
if Path::new(&plugin_path).exists() && Path::new(&plugin_path).metadata()?.permissions().mode() & 0o111 != 0 {
138-
plugins.push(Plugin { name: plugin_name.clone() });
139-
if verbose {
140-
println!("Loaded plugin: {}", plugin_name);
141-
}
142-
// Dodaj komendę do wykonania pluginu, np. cmds.push(format!("{} &", plugin_path));
143-
} else {
144-
errors.push(format!("Line {}: Plugin {} not found or not executable", line_num, plugin_name));
219+
local_vars.push((var, value));
220+
}
221+
} else {
222+
errors.push(format!("Line {}: Invalid $ syntax", line_num));
223+
}
224+
} else if line.starts_with("\\") {
225+
let plugin_name = line[1..].trim().to_string();
226+
if plugin_name.is_empty() {
227+
errors.push(format!("Line {}: Empty plugin name", line_num));
228+
} else {
229+
let plugin_path = expand_home(&format!("{}/plugins/{}", HACKER_DIR, plugin_name));
230+
if Path::new(&plugin_path).exists() && Path::new(&plugin_path).metadata()?.permissions().mode() & 0o111 != 0 {
231+
plugins.push(Plugin { name: plugin_name.clone(), is_super });
232+
if verbose {
233+
println!("Loaded plugin: {}", plugin_name);
145234
}
235+
} else {
236+
errors.push(format!("Line {}: Plugin {} not found or not executable", line_num, plugin_name));
146237
}
147238
}
148239
} else if line.starts_with("=") {
149240
let parts: Vec<String> = line[1..].split('>').map(|s| s.trim().to_string()).collect();
150241
if parts.len() == 2 {
151242
if let Ok(num) = parts[0].parse::<usize>() {
152243
let cmd_parts: Vec<String> = parts[1].split('!').map(|s| s.trim().to_string()).collect();
153-
let cmd = cmd_parts[0].clone();
244+
let mut cmd = cmd_parts[0].clone();
245+
if is_super {
246+
cmd = format!("sudo {}", cmd);
247+
}
154248
if cmd.is_empty() {
155249
errors.push(format!("Line {}: Empty loop command", line_num));
156250
} else {
251+
let target = if let Some(ref f) = in_function { functions.get_mut(f).unwrap() } else { &mut cmds };
157252
for _ in 0..num {
158-
cmds.push(cmd.clone());
253+
target.push(cmd.clone());
159254
}
160255
}
161256
} else {
@@ -169,22 +264,31 @@ fn parse_hacker_file(path: &Path, verbose: bool, bytes_mode: bool) -> io::Result
169264
if parts.len() == 2 {
170265
let condition = parts[0].clone();
171266
let cmd_parts: Vec<String> = parts[1].split('!').map(|s| s.trim().to_string()).collect();
172-
let cmd = cmd_parts[0].clone();
267+
let mut cmd = cmd_parts[0].clone();
268+
if is_super {
269+
cmd = format!("sudo {}", cmd);
270+
}
173271
if condition.is_empty() || cmd.is_empty() {
174272
errors.push(format!("Line {}: Invalid conditional", line_num));
175273
} else {
176-
cmds.push(format!("if {}; then {}; fi", condition, cmd));
274+
let if_cmd = format!("if {}; then {}; fi", condition, cmd);
275+
let target = if let Some(ref f) = in_function { functions.get_mut(f).unwrap() } else { &mut cmds };
276+
target.push(if_cmd);
177277
}
178278
} else {
179279
errors.push(format!("Line {}: Invalid conditional syntax", line_num));
180280
}
181281
} else if line.starts_with("&") {
182282
let parts: Vec<String> = line[1..].split('!').map(|s| s.trim().to_string()).collect();
183-
let cmd = parts[0].clone();
184-
if cmd.is_empty() {
283+
let mut cmd = format!("{} &", parts[0]);
284+
if is_super {
285+
cmd = format!("sudo {}", cmd);
286+
}
287+
if parts[0].is_empty() {
185288
errors.push(format!("Line {}: Empty background command", line_num));
186289
} else {
187-
cmds.push(format!("{} &", cmd));
290+
let target = if let Some(ref f) = in_function { functions.get_mut(f).unwrap() } else { &mut cmds };
291+
target.push(cmd);
188292
}
189293
} else if line.starts_with("!") {
190294
// Comment
@@ -195,27 +299,37 @@ fn parse_hacker_file(path: &Path, verbose: bool, bytes_mode: bool) -> io::Result
195299
if in_config {
196300
errors.push("Unclosed config section".to_string());
197301
}
302+
if in_comment {
303+
errors.push("Unclosed comment block".to_string());
304+
}
305+
if in_function.is_some() {
306+
errors.push("Unclosed function block".to_string());
307+
}
198308
if verbose {
199309
println!("System Deps: {:?}", deps);
200310
println!("Custom Libs: {:?}", libs);
201311
println!("Vars: {:?}", vars);
312+
println!("Local Vars: {:?}", local_vars);
202313
println!("Cmds: {:?}", cmds);
203314
println!("Includes: {:?}", includes);
204315
println!("Binaries: {:?}", binaries);
205316
println!("Plugins: {:?}", plugins);
317+
println!("Functions: {:?}", functions);
206318
println!("Config: {:?}", config);
207319
if !errors.is_empty() {
208320
println!("Errors: {:?}", errors);
209321
}
210322
}
211-
Ok((deps, libs, vars, cmds, includes, binaries, errors, config, plugins))
323+
Ok((deps, libs, vars, cmds, includes, binaries, local_vars, errors, config, plugins, functions))
212324
}
325+
213326
fn generate_check_cmd(dep: &str) -> String {
214327
if dep == "sudo" {
215328
return String::new();
216329
}
217330
format!("command -v {} &> /dev/null || (sudo apt update && sudo apt install -y {})", dep, dep)
218331
}
332+
219333
fn main() -> io::Result<()> {
220334
let args: Vec<String> = env::args().collect();
221335
let mut bytes_mode = false;
@@ -243,28 +357,42 @@ fn main() -> io::Result<()> {
243357
}
244358
let input_path = Path::new(&input_path_str);
245359
let output_path = Path::new(&output_path_str);
246-
let (deps, _libs, vars, cmds, _includes, binaries, errors, _config, plugins) = parse_hacker_file(input_path, verbose, bytes_mode)?;
360+
let (deps, _libs, vars, cmds, _includes, binaries, local_vars, errors, _config, plugins, _functions) = parse_hacker_file(input_path, verbose, bytes_mode)?;
247361
if !errors.is_empty() {
248362
for err in errors {
249363
eprintln!("{}", err);
250364
}
251365
process::exit(1);
252366
}
253-
let mut final_cmds = Vec::new();
367+
let mut substituted_cmds: Vec<String> = Vec::new();
368+
for cmd in cmds {
369+
let mut sub_cmd = cmd.clone();
370+
for (k, v) in &local_vars {
371+
let pattern = format!("${}", k);
372+
sub_cmd = sub_cmd.replace(&pattern, v);
373+
}
374+
substituted_cmds.push(sub_cmd);
375+
}
376+
let mut final_cmds: Vec<String> = Vec::new();
254377
for dep in deps {
255378
let check = generate_check_cmd(&dep);
256379
if !check.is_empty() {
257380
final_cmds.push(check);
258381
}
259382
}
260-
final_cmds.extend(cmds);
383+
final_cmds.extend(substituted_cmds);
261384
// Dla pluginów, dodaj komendy wykonania
262385
for plugin in plugins {
263386
let plugin_path = expand_home(&format!("{}/plugins/{}", HACKER_DIR, plugin.name));
264-
final_cmds.push(format!("{} &", plugin_path));
387+
let cmd = if plugin.is_super {
388+
format!("sudo {} &", plugin_path)
389+
} else {
390+
format!("{} &", plugin_path)
391+
};
392+
final_cmds.push(cmd);
265393
}
266394
// Dla binarek, extract cmds
267-
let mut bin_extract_cmds = Vec::new();
395+
let mut bin_extract_cmds: Vec<String> = Vec::new();
268396
for (i, bin_path) in binaries.iter().enumerate() {
269397
let bin_data = fs::read(bin_path)?;
270398
let data_name = format!("bin_lib_{i}");
@@ -280,7 +408,7 @@ fn main() -> io::Result<()> {
280408
let builder = ObjectBuilder::new(
281409
isa,
282410
output_path.file_stem().unwrap().to_str().unwrap().as_bytes().to_vec(),
283-
cranelift_module::default_libcall_names(),
411+
cranelift_module::default_libcall_names(),
284412
).expect("ObjectBuilder failed");
285413
let mut module = ObjectModule::new(builder);
286414
let pointer_type = module.target_config().pointer_type();

0 commit comments

Comments
 (0)