Skip to content

Commit 67f368c

Browse files
authored
feat: support arbitrary pointer literals and expand CLI build options (#275)
This commit enhances the handling of pointer literals in the LLVM backend and introduces new CLI capabilities for building object files and executables. Changes: - **Pointer Literal Enhancements**: - Relaxed the restriction on pointer literals. Previously, only `0` was allowed as a null pointer. - Now supports arbitrary numeric literals by parsing them as integers and using `build_int_to_ptr` to cast them to the target pointer type. - Added a panic check to prevent negative numeric literals from being used as pointers. - **CLI & Command Expansion**: - **`run` command**: Added a `--img` flag to trigger an image-based build-and-run flow. - **`build` command**: - Added a `-o` flag to compile source files into machine object files (`.o`). - The default build command now compiles and links files into a final binary inside the `target/` directory. - **Runner & Pipeline Refactoring**: - Implemented `object_build_wave_file` to handle the full compilation pipeline (lexing, parsing, IR generation, and object code emission) with detailed debug support for tokens, AST, and hex dumps. - Implemented `build_wave_file` to orchestrate the linking of generated object files into executable binaries. - **Library API**: - Exported `compile_and_build` and `compile_and_build_obj` in `lib.rs` to provide programmatic access to the new build workflows. These changes provide more flexibility for system-level programming and improve the developer experience when managing build artifacts.
1 parent 5ab8b6b commit 67f368c

File tree

4 files changed

+156
-11
lines changed

4 files changed

+156
-11
lines changed

llvm_temporary/src/llvm_temporary/expression/rvalue/literals.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,24 @@ pub(crate) fn gen<'ctx, 'a>(
5555
}
5656

5757
Some(BasicTypeEnum::PointerType(ptr_ty)) => {
58-
if is_zero_decimal(v.as_str()) {
59-
ptr_ty.const_null().as_basic_value_enum()
60-
} else {
61-
panic!("Only 0 can be used as null pointer literal");
58+
let s = v.as_str();
59+
let (neg, raw) = parse_signed_decimal(s);
60+
let (radix, digits) = parse_int_radix(raw);
61+
62+
if neg {
63+
panic!("negative pointer literal not allowed: {}", s);
6264
}
65+
66+
let int_val = env
67+
.context
68+
.i64_type()
69+
.const_int_from_string(digits, radix)
70+
.unwrap_or_else(|| panic!("invalid pointer literal: {}", s));
71+
72+
env.builder
73+
.build_int_to_ptr(int_val, ptr_ty, "int_to_ptr")
74+
.unwrap()
75+
.as_basic_value_enum()
6376
}
6477

6578
Some(BasicTypeEnum::FloatType(ft)) => {

src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ pub unsafe fn compile_and_run(path: &Path, opt_flag: &str, debug: &DebugFlags) {
1414
runner::run_wave_file(path, opt_flag, debug);
1515
}
1616

17+
pub unsafe fn compile_and_build(path: &Path, opt_flag: &str, debug: &DebugFlags) {
18+
runner::build_wave_file(path, opt_flag, debug);
19+
}
20+
21+
pub unsafe fn compile_and_build_obj(path: &Path, opt_flag: &str, debug: &DebugFlags) {
22+
runner::object_build_wave_file(path, opt_flag, debug);
23+
}
24+
1725
pub unsafe fn compile_and_img(path: &Path) {
1826
runner::img_wave_file(path);
1927
}

src/main.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{env, process};
44
use utils::colorex::*;
55
use wavec::commands::{handle_build, handle_install_std, handle_run, handle_update_std, DebugFlags};
66
use wavec::errors::CliError;
7-
use wavec::version_wave;
7+
use wavec::{compile_and_build, compile_and_build_obj, version_wave};
88

99
fn main() {
1010
if let Err(e) = run() {
@@ -51,23 +51,44 @@ fn run() -> Result<(), CliError> {
5151
}
5252

5353
"run" => {
54-
let file = iter.next().ok_or(CliError::MissingArgument {
54+
let next = iter.next().ok_or(CliError::MissingArgument {
5555
command: "run",
56-
expected: "<file>",
56+
expected: "<file | --img>",
5757
})?;
5858

59-
handle_run(Path::new(&file), &opt_flag, &debug_flags)?;
59+
if next == "--img" {
60+
let file = iter.next().ok_or(CliError::MissingArgument {
61+
command: "run --img",
62+
expected: "<file>",
63+
})?;
64+
65+
handle_build(Path::new(&file), &opt_flag, &debug_flags)?;
66+
} else {
67+
handle_run(Path::new(&next), &opt_flag, &debug_flags)?;
68+
}
6069
}
6170

6271
"build" => {
63-
let file = iter.next().ok_or(CliError::MissingArgument {
72+
let next = iter.next().ok_or(CliError::MissingArgument {
6473
command: "build",
65-
expected: "<file>",
74+
expected: "<file | -o>",
6675
})?;
6776

68-
handle_build(Path::new(&file), &opt_flag, &debug_flags)?;
77+
unsafe {
78+
if next == "-o" {
79+
let file = iter.next().ok_or(CliError::MissingArgument {
80+
command: "build -o",
81+
expected: "<file>",
82+
})?;
83+
84+
compile_and_build_obj(Path::new(&file), &opt_flag, &debug_flags);
85+
} else {
86+
compile_and_build(Path::new(&next), &opt_flag, &debug_flags);
87+
}
88+
}
6989
}
7090

91+
7192
"install" => {
7293
let target = iter.next().ok_or(CliError::MissingArgument {
7394
command: "install",

src/runner.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,109 @@ pub(crate) unsafe fn run_wave_file(file_path: &Path, opt_flag: &str, debug: &Deb
163163
}
164164
}
165165

166+
pub(crate) unsafe fn object_build_wave_file(
167+
file_path: &Path,
168+
opt_flag: &str,
169+
debug: &DebugFlags,
170+
) -> String {
171+
let code = fs::read_to_string(file_path).unwrap_or_else(|_| {
172+
WaveError::new(
173+
WaveErrorKind::FileReadError(file_path.display().to_string()),
174+
format!("failed to read file `{}`", file_path.display()),
175+
file_path.display().to_string(),
176+
0,
177+
0,
178+
)
179+
.display();
180+
process::exit(1);
181+
});
182+
183+
let mut lexer = Lexer::new(&code);
184+
let tokens = lexer.tokenize();
185+
186+
let ast = parse(&tokens).unwrap_or_else(|| {
187+
WaveError::new(
188+
WaveErrorKind::SyntaxError("failed to parse Wave code".to_string()),
189+
"failed to parse Wave code",
190+
file_path.display().to_string(),
191+
0,
192+
0,
193+
)
194+
.display();
195+
process::exit(1);
196+
});
197+
198+
if debug.tokens {
199+
println!("\n===== Tokens =====");
200+
for token in &tokens {
201+
println!("{:?}", token);
202+
}
203+
}
204+
205+
if debug.ast {
206+
println!("\n===== AST =====\n{:#?}", ast);
207+
}
208+
209+
let ast = expand_imports_for_codegen(file_path, ast).unwrap_or_else(|e| {
210+
e.display();
211+
process::exit(1);
212+
});
213+
214+
let ir = generate_ir(&ast);
215+
216+
if debug.ir {
217+
println!("\n===== LLVM IR =====\n{}", ir);
218+
}
219+
220+
let file_stem = file_path.file_stem().unwrap().to_str().unwrap();
221+
let object_path = compile_ir_to_object(&ir, file_stem, opt_flag);
222+
223+
if debug.mc {
224+
println!("\n===== MACHINE CODE PATH =====");
225+
println!("{}", object_path);
226+
}
227+
228+
if debug.hex {
229+
println!("\n===== HEX DUMP =====");
230+
let data = fs::read(&object_path).unwrap();
231+
for (i, b) in data.iter().enumerate() {
232+
if i % 16 == 0 {
233+
print!("\n{:04x}: ", i);
234+
}
235+
print!("{:02x} ", b);
236+
}
237+
println!();
238+
}
239+
240+
object_path
241+
}
242+
243+
pub(crate) unsafe fn build_wave_file(
244+
file_path: &Path,
245+
opt_flag: &str,
246+
debug: &DebugFlags,
247+
) {
248+
let object_path = object_build_wave_file(file_path, opt_flag, debug);
249+
250+
let file_stem = file_path.file_stem().unwrap().to_str().unwrap();
251+
let exe_path = format!("target/{}", file_stem);
252+
253+
let link_libs: Vec<String> = Vec::new();
254+
let link_lib_paths: Vec<String> = Vec::new();
255+
256+
link_objects(
257+
&[object_path],
258+
&exe_path,
259+
&link_libs,
260+
&link_lib_paths,
261+
);
262+
263+
if debug.mc {
264+
println!("\n===== OUTPUT BINARY =====");
265+
println!("{}", exe_path);
266+
}
267+
}
268+
166269
pub(crate) unsafe fn img_wave_file(file_path: &Path) {
167270
let code = fs::read_to_string(file_path).expect("Failed to read file");
168271

0 commit comments

Comments
 (0)