feat: usable edb

This commit is contained in:
Edgar 2024-03-11 12:02:14 +01:00
parent 22498719e1
commit bd3c4da7ea
No known key found for this signature in database
GPG key ID: 70ADAE8F35904387
16 changed files with 528 additions and 230 deletions

8
Cargo.lock generated
View file

@ -241,6 +241,7 @@ dependencies = [
"clap", "clap",
"edlang_driver", "edlang_driver",
"git2", "git2",
"owo-colors",
"serde", "serde",
"toml", "toml",
] ]
@ -294,6 +295,7 @@ dependencies = [
"test-case", "test-case",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"walkdir",
] ]
[[package]] [[package]]
@ -785,6 +787,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "owo-colors"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.1" version = "0.12.1"

View file

@ -20,3 +20,4 @@ clap = { version = "4.4.16", features = ["derive"] }
toml = "0.8.10" toml = "0.8.10"
serde = { version = "1.0.197", features = ["derive"] } serde = { version = "1.0.197", features = ["derive"] }
git2 = "0.18.2" git2 = "0.18.2"
owo-colors = "4.0.0"

View file

@ -1,9 +1,15 @@
use std::{collections::HashMap, path::PathBuf}; use std::{collections::HashMap, fs::File, io::Read, path::PathBuf, time::Instant};
use anyhow::{Context, Result}; use anyhow::{bail, Context, Result};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use config::{Config, Package, Profile}; use config::{Config, Package, Profile};
use git2::{IndexAddOption, Repository, RepositoryInitOptions}; use edlang_driver::{
compile,
linker::{link_binary, link_shared_lib},
CompilerArgs,
};
use git2::{IndexAddOption, Repository};
use owo_colors::OwoColorize;
mod config; mod config;
@ -36,6 +42,10 @@ enum Commands {
/// Build for release with all optimizations. /// Build for release with all optimizations.
#[arg(short, long, default_value_t = false)] #[arg(short, long, default_value_t = false)]
release: bool, release: bool,
/// Override the profile to use.
#[arg(short, long)]
profile: Option<String>,
}, },
} }
@ -131,13 +141,13 @@ mod {} {{
} }
{ {
let mut repo = Repository::init(&path).context("failed to create repository")?; let repo = Repository::init(&path).context("failed to create repository")?;
let sig = repo.signature()?; let sig = repo.signature()?;
let tree_id = { let tree_id = {
let mut index = repo.index()?; let mut index = repo.index()?;
index.add_all(["*"], IndexAddOption::DEFAULT, None)?; index.add_all(["."].iter(), IndexAddOption::DEFAULT, None)?;
index.write()?;
index.write_tree()? index.write_tree()?
}; };
@ -145,8 +155,138 @@ mod {} {{
repo.commit(Some("HEAD"), &sig, &sig, "Initial commit", &tree, &[]) repo.commit(Some("HEAD"), &sig, &sig, "Initial commit", &tree, &[])
.context("failed to create initial commit")?; .context("failed to create initial commit")?;
} }
if bin {
println!(
" {} binary (application) `{}` package",
"Created".green().bold(),
name
);
} else {
println!(" {} library `{}` package", "Created".green(), name);
}
}
Commands::Build { release, profile } => {
let mut current_dir = std::env::current_dir()?;
let mut config_path = None;
for _ in 0..3 {
if !current_dir.join("Ed.toml").exists() {
current_dir = if let Some(parent) = current_dir.parent() {
parent.to_path_buf()
} else {
bail!("Couldn't find Ed.toml");
};
} else {
config_path = Some(current_dir.join("Ed.toml"));
break;
}
}
let config_path = match config_path {
Some(x) => x,
None => bail!("Couldn't find Ed.toml"),
};
let base_dir = config_path
.parent()
.context("couldn't get config parent dir")?;
let mut config = File::open(&config_path).context("Failed to open Ed.toml")?;
let mut buf = String::new();
config.read_to_string(&mut buf)?;
let config: Config = toml::from_str(&buf).context("failed to parse Ed.toml")?;
println!(
" {} {} v{} ({})",
"Compiling".green().bold(),
config.package.name,
config.package.version,
base_dir.display()
);
let src_dir = base_dir.join("src");
let target_dir = base_dir.join("target-ed");
if !target_dir.exists() {
std::fs::create_dir_all(&target_dir)?;
}
let has_main = src_dir.join("main.ed").exists();
let output = target_dir.join(config.package.name);
let (profile, profile_name) = if let Some(profile) = profile {
(
config
.profile
.get(&profile)
.context("Couldn't get requested profile")?,
profile,
)
} else if release {
(
config
.profile
.get("release")
.context("Couldn't get profile: release")?,
"release".to_string(),
)
} else {
(
config
.profile
.get("dev")
.context("Couldn't get profile: dev")?,
"dev".to_string(),
)
};
let compile_args = CompilerArgs {
input: src_dir,
output: output.clone(),
release,
optlevel: Some(profile.opt_level),
debug_info: Some(profile.debug_info),
library: !has_main,
ast: false,
ir: false,
llvm: true,
asm: false,
object: true,
};
let start = Instant::now();
let object = compile(&compile_args)?;
if has_main {
link_shared_lib(&[object], &output)?;
} else {
link_binary(&[object], &output)?;
}
let elapsed = start.elapsed();
println!(
" {} {} [{}{}] in {elapsed:?}",
"Finished".green().bold(),
profile_name,
if profile.opt_level > 0 {
"optimized"
} else {
"unoptimized"
},
if profile.debug_info {
" + debuginfo"
} else {
""
}
);
/*
Finished dev [unoptimized + debuginfo] target(s) in 0.06s
Running `/data2/edgar/edlang/target/debug/edb build`
*/
} }
Commands::Build { release } => todo!(),
} }
Ok(()) Ok(())

View file

@ -9,11 +9,15 @@ pub fn lowering_error_to_report(
error: LoweringError, error: LoweringError,
session: &Session, session: &Session,
) -> Report<(String, Range<usize>)> { ) -> Report<(String, Range<usize>)> {
let path = session.file_path.display().to_string();
let mut colors = ColorGenerator::new(); let mut colors = ColorGenerator::new();
colors.next(); colors.next();
match error { match error {
LoweringError::ModuleNotFound { span, module } => { LoweringError::ModuleNotFound {
span,
module,
file_id,
} => {
let path = session.file_paths[file_id].display().to_string();
let offset = span.lo; let offset = span.lo;
Report::build(ReportKind::Error, path.clone(), offset) Report::build(ReportKind::Error, path.clone(), offset)
.with_code("E1") .with_code("E1")
@ -25,7 +29,12 @@ pub fn lowering_error_to_report(
.with_message("Unresolved import.") .with_message("Unresolved import.")
.finish() .finish()
} }
LoweringError::FunctionNotFound { span, function } => { LoweringError::FunctionNotFound {
span,
function,
file_id,
} => {
let path = session.file_paths[file_id].display().to_string();
Report::build(ReportKind::Error, path.clone(), span.lo) Report::build(ReportKind::Error, path.clone(), span.lo)
.with_code("EFNNOTFOUND") .with_code("EFNNOTFOUND")
.with_label( .with_label(
@ -34,8 +43,14 @@ pub fn lowering_error_to_report(
.with_color(colors.next()), .with_color(colors.next()),
) )
.finish() .finish()
}, }
LoweringError::ImportNotFound { import_span, module_span, symbol } => { LoweringError::ImportNotFound {
import_span,
module_span,
symbol,
file_id,
} => {
let path = session.file_paths[file_id].display().to_string();
let offset = symbol.span.lo; let offset = symbol.span.lo;
Report::build(ReportKind::Error, path.clone(), offset) Report::build(ReportKind::Error, path.clone(), offset)
.with_code("E2") .with_code("E2")
@ -54,26 +69,39 @@ pub fn lowering_error_to_report(
) )
.with_message("Unresolved import.") .with_message("Unresolved import.")
.finish() .finish()
}, }
LoweringError::BorrowNotMutable { span, name, type_span } => { LoweringError::BorrowNotMutable {
let mut labels = vec![ span,
Label::new((path.clone(), span.into())) name,
.with_message(format!("Can't mutate {name:?} because it's behind a immutable borrow")) type_span,
.with_color(colors.next()) file_id,
]; } => {
let path = session.file_paths[file_id].display().to_string();
let mut labels = vec![Label::new((path.clone(), span.into()))
.with_message(format!(
"Can't mutate {name:?} because it's behind a immutable borrow"
))
.with_color(colors.next())];
if let Some(type_span) = type_span { if let Some(type_span) = type_span {
labels.push(Label::new((path.clone(), type_span.into())) labels.push(
Label::new((path.clone(), type_span.into()))
.with_message(format!("Variable {name:?} has this type")) .with_message(format!("Variable {name:?} has this type"))
.with_color(colors.next())); .with_color(colors.next()),
);
} }
Report::build(ReportKind::Error, path.clone(), span.lo) Report::build(ReportKind::Error, path.clone(), span.lo)
.with_code("EREFMUT") .with_code("EREFMUT")
.with_labels(labels) .with_labels(labels)
.finish() .finish()
}, }
LoweringError::UnrecognizedType { span, name } => { LoweringError::UnrecognizedType {
span,
name,
file_id,
} => {
let path = session.file_paths[file_id].display().to_string();
Report::build(ReportKind::Error, path.clone(), span.lo) Report::build(ReportKind::Error, path.clone(), span.lo)
.with_code("E3") .with_code("E3")
.with_label( .with_label(
@ -83,19 +111,26 @@ pub fn lowering_error_to_report(
) )
.with_message(format!("Unresolved type {:?}.", name)) .with_message(format!("Unresolved type {:?}.", name))
.finish() .finish()
}, }
LoweringError::UnexpectedType { span, found, expected } => { LoweringError::UnexpectedType {
let mut labels = vec![ span,
Label::new((path.clone(), span.into())) found,
.with_message(format!("Unexpected type '{}', expected '{}'", found, expected.kind)) expected,
.with_color(colors.next()) file_id,
]; } => {
let path = session.file_paths[file_id].display().to_string();
let mut labels = vec![Label::new((path.clone(), span.into()))
.with_message(format!(
"Unexpected type '{}', expected '{}'",
found, expected.kind
))
.with_color(colors.next())];
if let Some(span) = expected.span { if let Some(span) = expected.span {
labels.push( labels.push(
Label::new((path.clone(), span.into())) Label::new((path.clone(), span.into()))
.with_message(format!("expected '{}' due to this type", expected.kind)) .with_message(format!("expected '{}' due to this type", expected.kind))
.with_color(colors.next()) .with_color(colors.next()),
); );
} }
@ -104,8 +139,9 @@ pub fn lowering_error_to_report(
.with_labels(labels) .with_labels(labels)
.with_message(format!("expected type {}.", expected.kind)) .with_message(format!("expected type {}.", expected.kind))
.finish() .finish()
}, }
LoweringError::IdNotFound { span, id } => { LoweringError::IdNotFound { span, id, file_id } => {
let path = session.file_paths[file_id].display().to_string();
Report::build(ReportKind::Error, path.clone(), span.lo) Report::build(ReportKind::Error, path.clone(), span.lo)
.with_code("E_ID") .with_code("E_ID")
.with_label( .with_label(
@ -115,8 +151,13 @@ pub fn lowering_error_to_report(
) )
.with_message(format!("Failed to find definition id {id:?}, this is most likely a compiler bug or a unimplemented lowering")) .with_message(format!("Failed to find definition id {id:?}, this is most likely a compiler bug or a unimplemented lowering"))
.finish() .finish()
}, }
LoweringError::NotYetImplemented { span, message } => { LoweringError::NotYetImplemented {
span,
message,
file_id,
} => {
let path = session.file_paths[file_id].display().to_string();
Report::build(ReportKind::Error, path.clone(), span.lo) Report::build(ReportKind::Error, path.clone(), span.lo)
.with_code("TODO") .with_code("TODO")
.with_label( .with_label(
@ -125,8 +166,13 @@ pub fn lowering_error_to_report(
.with_color(colors.next()), .with_color(colors.next()),
) )
.finish() .finish()
}, }
LoweringError::UseOfUndeclaredVariable { span, name } => { LoweringError::UseOfUndeclaredVariable {
span,
name,
file_id,
} => {
let path = session.file_paths[file_id].display().to_string();
Report::build(ReportKind::Error, path.clone(), span.lo) Report::build(ReportKind::Error, path.clone(), span.lo)
.with_code("UseOfUndeclaredVariable") .with_code("UseOfUndeclaredVariable")
.with_label( .with_label(
@ -135,6 +181,6 @@ pub fn lowering_error_to_report(
.with_color(colors.next()), .with_color(colors.next()),
) )
.finish() .finish()
}, }
} }
} }

View file

@ -35,17 +35,19 @@ struct ModuleCompileCtx<'ctx, 'm> {
di_builder: DebugInfoBuilder<'ctx>, di_builder: DebugInfoBuilder<'ctx>,
di_unit: DICompileUnit<'ctx>, di_unit: DICompileUnit<'ctx>,
target_data: TargetData, target_data: TargetData,
_module_id: DefId, module_id: DefId,
di_namespace: DIScope<'ctx>, di_namespace: DIScope<'ctx>,
} }
impl<'ctx, 'm> ModuleCompileCtx<'ctx, 'm> { impl<'ctx, 'm> ModuleCompileCtx<'ctx, 'm> {
pub fn _get_module_body(&self) -> &ModuleBody { pub fn get_module_body(&self) -> &ModuleBody {
self.ctx.program.modules.get(&self._module_id).unwrap() self.ctx.program.modules.get(&self.module_id).unwrap()
} }
pub fn set_debug_loc(&self, scope: DIScope<'ctx>, span: Span) -> DILocation<'ctx> { pub fn set_debug_loc(&self, scope: DIScope<'ctx>, span: Span) -> DILocation<'ctx> {
let (_, line, column) = self.ctx.session.source.get_offset_line(span.lo).unwrap(); let (_, line, column) = self.ctx.session.sources[self.get_module_body().file_id]
.get_offset_line(span.lo)
.unwrap();
let debug_loc = self.di_builder.create_debug_location( let debug_loc = self.di_builder.create_debug_location(
self.ctx.context, self.ctx.context,
line as u32 + 1, line as u32 + 1,
@ -98,25 +100,39 @@ pub fn compile(session: &Session, program: &ProgramBody) -> Result<PathBuf, Box<
info!("compiling for: {:?}", target.get_description()); info!("compiling for: {:?}", target.get_description());
let filename = session.file_path.file_name().unwrap().to_string_lossy();
let dir = session.file_path.parent().unwrap().to_string_lossy();
for module_id in program.top_level_modules.iter() { for module_id in program.top_level_modules.iter() {
let module = ctx.program.modules.get(module_id).unwrap(); let module = ctx.program.modules.get(module_id).unwrap();
let file_path = session.file_paths[module.file_id].clone();
let abs_file_path = file_path
.canonicalize()
.expect("failed to canonicalize file path");
let filename = file_path.file_name().unwrap().to_str().unwrap();
let dirname = abs_file_path
.parent()
.unwrap()
.file_name()
.unwrap()
.to_str()
.unwrap();
let llvm_module = context.create_module(&module.name); let llvm_module = context.create_module(&module.name);
llvm_module.set_source_file_name(&filename); llvm_module.set_source_file_name(filename);
llvm_module.set_triple(&triple); llvm_module.set_triple(&triple);
llvm_module.set_data_layout(&machine.get_target_data().get_data_layout()); llvm_module.set_data_layout(&machine.get_target_data().get_data_layout());
let (di_builder, di_unit) = llvm_module.create_debug_info_builder( let (di_builder, di_unit) = llvm_module.create_debug_info_builder(
true, true,
inkwell::debug_info::DWARFSourceLanguage::Rust, inkwell::debug_info::DWARFSourceLanguage::Rust,
&filename, filename,
&dir, dirname,
"edlang", "edlang",
true, true,
"", // compiler flags "", // compiler flags
1, 1,
"", // split name "", // split name
inkwell::debug_info::DWARFEmissionKind::Full, match session.debug_info {
edlang_session::DebugInfo::None => inkwell::debug_info::DWARFEmissionKind::None,
edlang_session::DebugInfo::Full => inkwell::debug_info::DWARFEmissionKind::Full,
},
module.module_id.program_id.try_into().unwrap(), // compile unit id? module.module_id.program_id.try_into().unwrap(), // compile unit id?
false, false,
false, false,
@ -135,7 +151,7 @@ pub fn compile(session: &Session, program: &ProgramBody) -> Result<PathBuf, Box<
di_unit, di_unit,
builder: &builder, builder: &builder,
target_data: machine.get_target_data(), target_data: machine.get_target_data(),
_module_id: *module_id, module_id: *module_id,
di_namespace, di_namespace,
}; };
@ -234,10 +250,7 @@ fn compile_fn_signature(ctx: &ModuleCompileCtx<'_, '_>, fn_id: DefId) {
fn_value.set_call_conventions(0); // cconv fn_value.set_call_conventions(0); // cconv
let (_, line, _col) = ctx let (_, line, _col) = ctx.ctx.session.sources[ctx.get_module_body().file_id]
.ctx
.session
.source
.get_offset_line(body.fn_span.lo) .get_offset_line(body.fn_span.lo)
.unwrap(); .unwrap();
@ -1480,10 +1493,7 @@ fn compile_debug_type<'ctx>(ctx: &ModuleCompileCtx<'ctx, '_>, ty: &ir::TypeInfo)
fields.push(ty); fields.push(ty);
} }
let (_, line, _column) = ctx let (_, line, _column) = ctx.ctx.session.sources[ctx.get_module_body().file_id]
.ctx
.session
.source
.get_offset_line(body.span.lo) .get_offset_line(body.span.lo)
.unwrap(); .unwrap();
let real_ty = compile_basic_type(ctx, ty); let real_ty = compile_basic_type(ctx, ty);

View file

@ -7,7 +7,6 @@ use edlang_session::Session;
use ir::ProgramBody; use ir::ProgramBody;
pub mod codegen; pub mod codegen;
pub mod linker;
pub fn compile( pub fn compile(
session: &Session, session: &Session,

View file

@ -25,6 +25,7 @@ edlang_parser = { version = "0.0.1-alpha.12", path = "../edlang_parser" }
edlang_session = { version = "0.0.1-alpha.12", path = "../edlang_session" } edlang_session = { version = "0.0.1-alpha.12", path = "../edlang_session" }
tracing = { workspace = true } tracing = { workspace = true }
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
walkdir = "2.5.0"
[dev-dependencies] [dev-dependencies]
tempfile = "3.10.1" tempfile = "3.10.1"

View file

@ -1,49 +1,60 @@
use std::{path::PathBuf, time::Instant}; use std::{path::PathBuf, time::Instant};
use anyhow::{bail, Result}; use anyhow::Result;
use ariadne::Source; use ariadne::{sources, Source};
use clap::Parser; use clap::Parser;
use edlang_codegen_llvm::linker::{link_binary, link_shared_lib};
use edlang_lowering::lower_modules; use edlang_lowering::lower_modules;
use edlang_session::{DebugInfo, OptLevel, Session}; use edlang_session::{DebugInfo, OptLevel, Session};
use walkdir::WalkDir;
use crate::linker::{link_binary, link_shared_lib};
pub mod linker;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(author, version, about = "edlang compiler driver", long_about = None, bin_name = "edlangc")] #[command(author, version, about = "edlang compiler driver", long_about = None, bin_name = "edlangc")]
pub struct CompilerArgs { pub struct CompilerArgs {
/// The input file. /// The input file.
input: PathBuf, pub input: PathBuf,
/// The output file.
pub output: PathBuf,
/// Build for release with all optimizations. /// Build for release with all optimizations.
#[arg(short, long, default_value_t = false)] #[arg(short, long, default_value_t = false)]
release: bool, pub release: bool,
/// Set the optimization level, 0,1,2,3 /// Set the optimization level, 0,1,2,3
#[arg(short = 'O', long)] #[arg(short = 'O', long)]
optlevel: Option<u8>, pub optlevel: Option<u8>,
/// Always add debug info /// Always add debug info
#[arg(long)] #[arg(long)]
debug_info: Option<bool>, pub debug_info: Option<bool>,
/// Build as a library. /// Build as a library.
#[arg(short, long, default_value_t = false)] #[arg(short, long, default_value_t = false)]
library: bool, pub library: bool,
/// Print the edlang AST /// Print the edlang AST
#[arg(long, default_value_t = false)] #[arg(long, default_value_t = false)]
ast: bool, pub ast: bool,
/// Print the edlang IR /// Print the edlang IR
#[arg(long, default_value_t = false)] #[arg(long, default_value_t = false)]
ir: bool, pub ir: bool,
/// Output llvm ir /// Output llvm ir
#[arg(long, default_value_t = false)] #[arg(long, default_value_t = false)]
llvm: bool, pub llvm: bool,
/// Output asm /// Output asm
#[arg(long, default_value_t = false)] #[arg(long, default_value_t = false)]
asm: bool, pub asm: bool,
/// Output a object file
#[arg(long, default_value_t = false)]
pub object: bool,
} }
pub fn main() -> Result<()> { pub fn main() -> Result<()> {
@ -51,51 +62,59 @@ pub fn main() -> Result<()> {
let args = CompilerArgs::parse(); let args = CompilerArgs::parse();
compile_single_file(args)?; let object = compile(&args)?;
if args.library {
link_shared_lib(&[object.clone()], &args.output)?;
} else {
link_binary(&[object.clone()], &args.output)?;
}
if !args.object {
std::fs::remove_file(object)?;
}
Ok(()) Ok(())
} }
pub fn compile_single_file(args: CompilerArgs) -> Result<()> { pub fn compile(args: &CompilerArgs) -> Result<PathBuf> {
if !args.input.is_file() { let mut files = Vec::new();
bail!("Input is not a file"); for entry in WalkDir::new(&args.input) {
let entry = entry?;
if let Some(ext) = entry.path().extension() {
if ext.eq_ignore_ascii_case("ed") {
files.push(entry.path().to_path_buf());
}
}
}
if files.is_empty() {
panic!("files is empty");
} }
let start_time = Instant::now(); let start_time = Instant::now();
tracing_subscriber::fmt::init(); let mut modules = Vec::new();
let path = args.input.display().to_string(); for path in files {
let source = std::fs::read_to_string(&args.input)?; let source = std::fs::read_to_string(&path)?;
let modules = edlang_parser::parse_ast(&source); let modules_ast = edlang_parser::parse_ast(&source);
let modules = match modules { let modules_temp = match modules_ast {
Ok(modules) => modules, Ok(modules) => modules,
Err(error) => { Err(error) => {
let path = path.display().to_string();
let report = edlang_parser::error_to_report(&path, &error)?; let report = edlang_parser::error_to_report(&path, &error)?;
edlang_parser::print_report(&path, &source, report)?; edlang_parser::print_report(&path, &source, report)?;
std::process::exit(1) std::process::exit(1)
} }
}; };
modules.push((path, source, modules_temp));
let cwd = std::env::current_dir()?;
// todo: find a better name, "target" would clash with rust if running in the source tree.
let target_dir = cwd.join("target_ed/");
if !target_dir.exists() {
std::fs::create_dir_all(&target_dir)?;
} }
let output_file = target_dir.join(PathBuf::from(args.input.file_name().unwrap()));
let output_file = if args.library {
output_file.with_extension(Session::get_platform_library_ext())
} else if cfg!(target_os = "windows") {
output_file.with_extension("exe")
} else {
output_file.with_extension("")
};
let session = Session { let session = Session {
file_path: args.input, file_paths: modules.iter().map(|x| x.0.clone()).collect(),
debug_info: if let Some(debug_info) = args.debug_info { debug_info: if let Some(debug_info) = args.debug_info {
if debug_info { if debug_info {
DebugInfo::Full DebugInfo::Full
@ -119,50 +138,50 @@ pub fn compile_single_file(args: CompilerArgs) -> Result<()> {
} else { } else {
OptLevel::None OptLevel::None
}, },
source: Source::from(source), sources: modules.iter().map(|x| Source::from(x.1.clone())).collect(),
library: args.library, library: args.library,
target_dir, output_file: args.output.with_extension("o"),
output_file,
output_asm: args.asm, output_asm: args.asm,
output_llvm: args.llvm, output_llvm: args.llvm,
}; };
tracing::debug!("Input file: {:#?}", session.file_path);
tracing::debug!("Target dir: {:#?}", session.target_dir);
tracing::debug!("Output file: {:#?}", session.output_file); tracing::debug!("Output file: {:#?}", session.output_file);
tracing::debug!("Is library: {:#?}", session.library); tracing::debug!("Is library: {:#?}", session.library);
tracing::debug!("Optlevel: {:#?}", session.optlevel); tracing::debug!("Optlevel: {:#?}", session.optlevel);
tracing::debug!("Debug Info: {:#?}", session.debug_info); tracing::debug!("Debug Info: {:#?}", session.debug_info);
let path_cache: Vec<_> = modules
.iter()
.map(|x| (x.0.display().to_string(), x.1.clone()))
.collect();
let modules: Vec<_> = modules.iter().map(|x| x.2.clone()).collect();
if args.ast { if args.ast {
println!("{:#?}", modules); std::fs::write(
return Ok(()); session.output_file.with_extension("ast"),
format!("{:#?}", modules),
)?;
} }
let program_ir = match lower_modules(&modules) { let program_ir = match lower_modules(&modules) {
Ok(ir) => ir, Ok(ir) => ir,
Err(error) => { Err(error) => {
let report = edlang_check::lowering_error_to_report(error, &session); let report = edlang_check::lowering_error_to_report(error, &session);
let path = session.file_path.display().to_string(); report.eprint(sources(path_cache))?;
report.eprint((path, session.source.clone()))?;
std::process::exit(1); std::process::exit(1);
} }
}; };
if args.ir { if args.ir {
println!("{:#?}", program_ir); std::fs::write(
return Ok(()); session.output_file.with_extension("ir"),
format!("{:#?}", program_ir),
)?;
} }
let object_path = edlang_codegen_llvm::compile(&session, &program_ir).unwrap(); let object_path = edlang_codegen_llvm::compile(&session, &program_ir).unwrap();
if session.library {
link_shared_lib(&object_path, &session.output_file)?;
} else {
link_binary(&object_path, &session.output_file)?;
}
let elapsed = start_time.elapsed(); let elapsed = start_time.elapsed();
tracing::debug!("Done in {:?}", elapsed); tracing::debug!("Done in {:?}", elapsed);
Ok(()) Ok(object_path)
} }

View file

@ -1,39 +1,41 @@
use std::path::Path; use std::path::{Path, PathBuf};
use tracing::instrument; use tracing::instrument;
#[instrument(level = "debug")] #[instrument(level = "debug")]
pub fn link_shared_lib(input_path: &Path, output_filename: &Path) -> std::io::Result<()> { pub fn link_shared_lib(objects: &[PathBuf], output_filename: &Path) -> std::io::Result<()> {
let args: &[&str] = { let objects: Vec<_> = objects.iter().map(|x| x.display().to_string()).collect();
let output_filename = output_filename.to_string_lossy().to_string();
let args: Vec<_> = {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
&[ let mut args = vec![
"-demangle", "-demangle",
"-no_deduplicate", "-no_deduplicate",
"-dynamic", "-dynamic",
"-dylib", "-dylib",
"-L/usr/local/lib", "-L/usr/local/lib",
"-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib", "-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib",
&input_path.display().to_string(), ];
"-o",
&output_filename.display().to_string(), args.extend(objects.iter().map(|x| x.as_str()));
"-lSystem",
] args.extend(&["-o", &output_filename, "-lSystem"]);
args
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
&[ let mut args = vec!["--hash-style=gnu", "--eh-frame-hdr", "-shared"];
"--hash-style=gnu",
"--eh-frame-hdr", args.extend(&["-o", &output_filename]);
"-shared",
"-o", args.extend(&["-L/lib/../lib64", "-L/usr/lib/../lib64", "-lc", "-O1"]);
&output_filename.display().to_string(),
"-L/lib/../lib64", args.extend(objects.iter().map(|x| x.as_str()));
"-L/usr/lib/../lib64",
"-lc", args
"-O1",
&input_path.display().to_string(),
]
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
{ {
@ -48,18 +50,24 @@ pub fn link_shared_lib(input_path: &Path, output_filename: &Path) -> std::io::Re
} }
#[instrument(level = "debug")] #[instrument(level = "debug")]
pub fn link_binary(input_path: &Path, output_filename: &Path) -> std::io::Result<()> { pub fn link_binary(objects: &[PathBuf], output_filename: &Path) -> std::io::Result<()> {
let args: &[&str] = { let objects: Vec<_> = objects.iter().map(|x| x.display().to_string()).collect();
let output_filename = output_filename.to_string_lossy().to_string();
let args: Vec<_> = {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
&[ let mut args = vec![
"-L/usr/local/lib", "-L/usr/local/lib",
"-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib", "-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib",
&input_path.display().to_string(), &input_path.display().to_string(),
"-o", ];
&output_filename.display().to_string(),
"-lSystem", args.extend(objects.iter().map(|x| x.as_str()));
]
args.extend(&["-o", &output_filename, "-lSystem"]);
args
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
@ -79,7 +87,7 @@ pub fn link_binary(input_path: &Path, output_filename: &Path) -> std::io::Result
} }
}; };
&[ let mut args = vec![
"-pie", "-pie",
"--hash-style=gnu", "--hash-style=gnu",
"--eh-frame-hdr", "--eh-frame-hdr",
@ -89,8 +97,11 @@ pub fn link_binary(input_path: &Path, output_filename: &Path) -> std::io::Result
"elf_x86_64", "elf_x86_64",
scrt1, scrt1,
crti, crti,
"-o", ];
&output_filename.display().to_string(),
args.extend(&["-o", &output_filename]);
args.extend(&[
"-L/lib64", "-L/lib64",
"-L/usr/lib64", "-L/usr/lib64",
"-L/lib/x86_64-linux-gnu", "-L/lib/x86_64-linux-gnu",
@ -99,8 +110,11 @@ pub fn link_binary(input_path: &Path, output_filename: &Path) -> std::io::Result
"-lc", "-lc",
"-O1", "-O1",
crtn, crtn,
&input_path.display().to_string(), ]);
]
args.extend(objects.iter().map(|x| x.as_str()));
args
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
{ {

View file

@ -6,7 +6,7 @@ use std::{
}; };
use ariadne::Source; use ariadne::Source;
use edlang_codegen_llvm::linker::{link_binary, link_shared_lib}; use edlang_driver::linker::{link_binary, link_shared_lib};
use edlang_lowering::lower_modules; use edlang_lowering::lower_modules;
use edlang_session::{DebugInfo, OptLevel, Session}; use edlang_session::{DebugInfo, OptLevel, Session};
use tempfile::TempDir; use tempfile::TempDir;
@ -36,13 +36,9 @@ pub fn compile_program(
) -> Result<CompileResult, Box<dyn std::error::Error>> { ) -> Result<CompileResult, Box<dyn std::error::Error>> {
let modules = edlang_parser::parse_ast(source).unwrap(); let modules = edlang_parser::parse_ast(source).unwrap();
let test_dir = tempfile::tempdir()?; let test_dir = tempfile::tempdir().unwrap();
let test_dir_path = test_dir.path(); let test_dir_path = test_dir.path().canonicalize()?;
let target_dir = test_dir_path.join("build_artifacts/"); let output_file = test_dir_path.join(PathBuf::from(name));
if !target_dir.exists() {
std::fs::create_dir_all(&target_dir)?;
}
let output_file = target_dir.join(PathBuf::from(name));
let output_file = if library { let output_file = if library {
output_file.with_extension(Session::get_platform_library_ext()) output_file.with_extension(Session::get_platform_library_ext())
} else if cfg!(target_os = "windows") { } else if cfg!(target_os = "windows") {
@ -51,26 +47,28 @@ pub fn compile_program(
output_file.with_extension("") output_file.with_extension("")
}; };
let input_file = output_file.with_extension("ed");
std::fs::write(&input_file, source)?;
let session = Session { let session = Session {
file_path: PathBuf::from(name), file_paths: vec![input_file],
debug_info: DebugInfo::Full, debug_info: DebugInfo::Full,
optlevel: OptLevel::Default, optlevel: OptLevel::Default,
source: Source::from(source.to_string()), sources: vec![Source::from(source.to_string())],
library, library,
target_dir,
output_file, output_file,
output_llvm: false, output_llvm: false,
output_asm: false, output_asm: false,
}; };
let program_ir = lower_modules(&modules)?; let program_ir = lower_modules(&[modules]).unwrap();
let object_path = edlang_codegen_llvm::compile(&session, &program_ir)?; let object_path = edlang_codegen_llvm::compile(&session, &program_ir).unwrap();
if library { if library {
link_shared_lib(&object_path, &session.output_file)?; link_shared_lib(&[object_path.clone()], &session.output_file).unwrap();
} else { } else {
link_binary(&object_path, &session.output_file)?; link_binary(&[object_path.clone()], &session.output_file).unwrap();
} }
Ok(CompileResult { Ok(CompileResult {
@ -81,5 +79,5 @@ pub fn compile_program(
} }
pub fn run_program(program: &Path, args: &[&str]) -> Result<Child, std::io::Error> { pub fn run_program(program: &Path, args: &[&str]) -> Result<Child, std::io::Error> {
std::process::Command::new(dbg!(program)).args(args).spawn() std::process::Command::new(program).args(args).spawn()
} }

View file

@ -39,6 +39,7 @@ pub struct ProgramBody {
pub struct ModuleBody { pub struct ModuleBody {
pub module_id: DefId, pub module_id: DefId,
pub parent_ids: Vec<DefId>, pub parent_ids: Vec<DefId>,
pub file_id: usize,
pub name: String, pub name: String,
pub symbols: SymbolTable, pub symbols: SymbolTable,
/// Functions defined in this module. /// Functions defined in this module.

View file

@ -60,6 +60,7 @@ pub struct BodyBuilder {
pub statements: Vec<Statement>, pub statements: Vec<Statement>,
pub name_to_local: HashMap<String, usize>, pub name_to_local: HashMap<String, usize>,
pub ret_local: usize, pub ret_local: usize,
pub file_id: usize,
pub ctx: BuildCtx, pub ctx: BuildCtx,
} }

View file

@ -7,33 +7,60 @@ use crate::DefId;
#[derive(Debug, Error, Clone)] #[derive(Debug, Error, Clone)]
pub enum LoweringError { pub enum LoweringError {
#[error("module {module:?} not found")] #[error("module {module:?} not found")]
ModuleNotFound { span: Span, module: String }, ModuleNotFound {
span: Span,
module: String,
file_id: usize,
},
#[error("function {function:?} not found")] #[error("function {function:?} not found")]
FunctionNotFound { span: Span, function: String }, FunctionNotFound {
span: Span,
function: String,
file_id: usize,
},
#[error("symbol {:?} not found", symbol.name)] #[error("symbol {:?} not found", symbol.name)]
ImportNotFound { ImportNotFound {
module_span: Span, module_span: Span,
import_span: Span, import_span: Span,
symbol: Ident, symbol: Ident,
file_id: usize,
}, },
#[error("trying to mutate a non-mutable reference")] #[error("trying to mutate a non-mutable reference")]
BorrowNotMutable { BorrowNotMutable {
span: Span, span: Span,
type_span: Option<Span>, type_span: Option<Span>,
name: String, name: String,
file_id: usize,
}, },
#[error("unrecognized type {name}")] #[error("unrecognized type {name}")]
UnrecognizedType { span: Span, name: String }, UnrecognizedType {
span: Span,
name: String,
file_id: usize,
},
#[error("id not found")] #[error("id not found")]
IdNotFound { span: Span, id: DefId }, IdNotFound {
span: Span,
id: DefId,
file_id: usize,
},
#[error("feature not yet implemented: {message}")] #[error("feature not yet implemented: {message}")]
NotYetImplemented { span: Span, message: &'static str }, NotYetImplemented {
span: Span,
message: &'static str,
file_id: usize,
},
#[error("unexpected type")] #[error("unexpected type")]
UnexpectedType { UnexpectedType {
span: Span, span: Span,
found: TypeKind, found: TypeKind,
expected: TypeInfo, expected: TypeInfo,
file_id: usize,
}, },
#[error("use of underclared variable {name:?}")] #[error("use of underclared variable {name:?}")]
UseOfUndeclaredVariable { span: Span, name: String }, UseOfUndeclaredVariable {
span: Span,
name: String,
file_id: usize,
},
} }

View file

@ -15,19 +15,24 @@ mod common;
pub mod errors; pub mod errors;
mod prepass; mod prepass;
pub fn lower_modules(modules: &[ast::Module]) -> Result<ProgramBody, LoweringError> { pub fn lower_modules(modules: &[Vec<ast::Module>]) -> Result<ProgramBody, LoweringError> {
let mut ctx = BuildCtx::default(); let mut ctx = BuildCtx::default();
// resolve symbols // resolve symbols
for (file_id, modules) in modules.iter().enumerate() {
for module in modules { for module in modules {
ctx = prepass::prepass_module(ctx, module)?; ctx = prepass::prepass_module(ctx, module, file_id)?;
}
} }
// resolve imports // resolve imports
for (file_id, modules) in modules.iter().enumerate() {
for module in modules { for module in modules {
ctx = prepass::prepass_imports(ctx, module)?; ctx = prepass::prepass_imports(ctx, module, file_id)?;
}
} }
for modules in modules {
for mod_def in modules { for mod_def in modules {
let id = *ctx let id = *ctx
.body .body
@ -37,6 +42,7 @@ pub fn lower_modules(modules: &[ast::Module]) -> Result<ProgramBody, LoweringErr
ctx = lower_module(ctx, mod_def, id)?; ctx = lower_module(ctx, mod_def, id)?;
} }
}
Ok(ctx.body) Ok(ctx.body)
} }
@ -157,6 +163,10 @@ fn lower_function(
ret_local: 0, ret_local: 0,
name_to_local: HashMap::new(), name_to_local: HashMap::new(),
statements: Vec::new(), statements: Vec::new(),
file_id: {
let body = ctx.body.modules.get(&module_id).unwrap();
body.file_id
},
ctx, ctx,
}; };
@ -450,6 +460,7 @@ fn lower_let(builder: &mut BodyBuilder, info: &ast::LetStmt) -> Result<(), Lower
span: info.span, span: info.span,
found: found_ty, found: found_ty,
expected: ty.clone(), expected: ty.clone(),
file_id: builder.file_id,
}); });
} }
@ -781,6 +792,7 @@ fn lower_binary_expr(
span: Some(lhs_span), span: Some(lhs_span),
kind: lhs_ty, kind: lhs_ty,
}, },
file_id: builder.file_id,
}); });
} }
@ -1112,6 +1124,7 @@ fn lower_return(
span, span,
found: ty, found: ty,
expected: return_type.clone(), expected: return_type.clone(),
file_id: builder.file_id,
}); });
} }
@ -1145,6 +1158,7 @@ fn lower_path(
LoweringError::UseOfUndeclaredVariable { LoweringError::UseOfUndeclaredVariable {
span: info.span, span: info.span,
name: info.first.name.clone(), name: info.first.name.clone(),
file_id: builder.file_id,
}, },
)?; )?;
@ -1256,6 +1270,7 @@ pub fn lower_type(
Err(LoweringError::UnrecognizedType { Err(LoweringError::UnrecognizedType {
span: t.name.span, span: t.name.span,
name: t.name.name.clone(), name: t.name.name.clone(),
file_id: module.file_id,
})? })?
} }
} }

View file

@ -6,7 +6,11 @@ use super::common::BuildCtx;
use edlang_ast as ast; use edlang_ast as ast;
use edlang_ir::ModuleBody; use edlang_ir::ModuleBody;
pub fn prepass_module(mut ctx: BuildCtx, mod_def: &ast::Module) -> Result<BuildCtx, LoweringError> { pub fn prepass_module(
mut ctx: BuildCtx,
mod_def: &ast::Module,
file_id: usize,
) -> Result<BuildCtx, LoweringError> {
let module_id = ctx.gen.next_defid(); let module_id = ctx.gen.next_defid();
tracing::debug!("running ir prepass on module {:?}", module_id); tracing::debug!("running ir prepass on module {:?}", module_id);
@ -29,6 +33,7 @@ pub fn prepass_module(mut ctx: BuildCtx, mod_def: &ast::Module) -> Result<BuildC
constants: Default::default(), constants: Default::default(),
imports: Default::default(), imports: Default::default(),
span: mod_def.span, span: mod_def.span,
file_id,
}, },
); );
@ -106,7 +111,7 @@ pub fn prepass_module(mut ctx: BuildCtx, mod_def: &ast::Module) -> Result<BuildC
.expect("module should exist"); .expect("module should exist");
let next_id = *current_module.symbols.modules.get(&info.name.name).unwrap(); let next_id = *current_module.symbols.modules.get(&info.name.name).unwrap();
ctx = prepass_sub_module(ctx, &[module_id], next_id, info)?; ctx = prepass_sub_module(ctx, &[module_id], next_id, info, file_id)?;
} }
} }
@ -118,6 +123,7 @@ pub fn prepass_sub_module(
parent_ids: &[DefId], parent_ids: &[DefId],
module_id: DefId, module_id: DefId,
mod_def: &ast::Module, mod_def: &ast::Module,
file_id: usize,
) -> Result<BuildCtx, LoweringError> { ) -> Result<BuildCtx, LoweringError> {
tracing::debug!("running ir prepass on submodule {:?}", module_id); tracing::debug!("running ir prepass on submodule {:?}", module_id);
let mut submodule_parents_ids = parent_ids.to_vec(); let mut submodule_parents_ids = parent_ids.to_vec();
@ -137,6 +143,7 @@ pub fn prepass_sub_module(
types: Default::default(), types: Default::default(),
constants: Default::default(), constants: Default::default(),
span: mod_def.span, span: mod_def.span,
file_id,
}; };
for ct in &mod_def.contents { for ct in &mod_def.contents {
@ -201,7 +208,7 @@ pub fn prepass_sub_module(
for ct in &mod_def.contents { for ct in &mod_def.contents {
if let ast::ModuleStatement::Module(info) = ct { if let ast::ModuleStatement::Module(info) = ct {
let next_id = ctx.gen.next_defid(); let next_id = ctx.gen.next_defid();
ctx = prepass_sub_module(ctx, &submodule_parents_ids, next_id, info)?; ctx = prepass_sub_module(ctx, &submodule_parents_ids, next_id, info, file_id)?;
} }
} }
@ -211,6 +218,7 @@ pub fn prepass_sub_module(
pub fn prepass_imports( pub fn prepass_imports(
mut ctx: BuildCtx, mut ctx: BuildCtx,
mod_def: &ast::Module, mod_def: &ast::Module,
file_id: usize,
) -> Result<BuildCtx, LoweringError> { ) -> Result<BuildCtx, LoweringError> {
let mod_id = *ctx let mod_id = *ctx
.body .body
@ -226,6 +234,7 @@ pub fn prepass_imports(
.ok_or_else(|| LoweringError::ModuleNotFound { .ok_or_else(|| LoweringError::ModuleNotFound {
span: import.module[0].span, span: import.module[0].span,
module: import.module[0].name.clone(), module: import.module[0].name.clone(),
file_id,
})?; })?;
let mut imported_module = let mut imported_module =
ctx.body ctx.body
@ -234,6 +243,7 @@ pub fn prepass_imports(
.ok_or(LoweringError::IdNotFound { .ok_or(LoweringError::IdNotFound {
span: mod_def.span, span: mod_def.span,
id: *imported_module_id, id: *imported_module_id,
file_id,
})?; })?;
for module_path in import.module.iter().skip(1) { for module_path in import.module.iter().skip(1) {
@ -244,11 +254,13 @@ pub fn prepass_imports(
.ok_or_else(|| LoweringError::ModuleNotFound { .ok_or_else(|| LoweringError::ModuleNotFound {
span: module_path.span, span: module_path.span,
module: module_path.name.clone(), module: module_path.name.clone(),
file_id,
})?; })?;
imported_module = ctx.body.modules.get(imported_module_id).ok_or({ imported_module = ctx.body.modules.get(imported_module_id).ok_or({
LoweringError::IdNotFound { LoweringError::IdNotFound {
span: module_path.span, span: module_path.span,
id: *imported_module_id, id: *imported_module_id,
file_id,
} }
})?; })?;
} }
@ -269,6 +281,7 @@ pub fn prepass_imports(
module_span: mod_def.span, module_span: mod_def.span,
import_span: import.span, import_span: import.span,
symbol: sym.clone(), symbol: sym.clone(),
file_id,
})?; })?;
} }
} }
@ -283,7 +296,7 @@ pub fn prepass_imports(
for c in &mod_def.contents { for c in &mod_def.contents {
if let ast::ModuleStatement::Module(info) = c { if let ast::ModuleStatement::Module(info) = c {
ctx = prepass_imports_submodule(ctx, info, mod_id)?; ctx = prepass_imports_submodule(ctx, info, mod_id, file_id)?;
} }
} }
@ -294,6 +307,7 @@ pub fn prepass_imports_submodule(
mut ctx: BuildCtx, mut ctx: BuildCtx,
mod_def: &ast::Module, mod_def: &ast::Module,
parent_id: DefId, parent_id: DefId,
file_id: usize,
) -> Result<BuildCtx, LoweringError> { ) -> Result<BuildCtx, LoweringError> {
let mod_id = *ctx let mod_id = *ctx
.body .body
@ -306,6 +320,7 @@ pub fn prepass_imports_submodule(
.ok_or_else(|| LoweringError::ModuleNotFound { .ok_or_else(|| LoweringError::ModuleNotFound {
span: mod_def.span, span: mod_def.span,
module: mod_def.name.name.clone(), module: mod_def.name.name.clone(),
file_id,
})?; })?;
for import in &mod_def.imports { for import in &mod_def.imports {
@ -316,11 +331,13 @@ pub fn prepass_imports_submodule(
.ok_or_else(|| LoweringError::ModuleNotFound { .ok_or_else(|| LoweringError::ModuleNotFound {
span: import.module[0].span, span: import.module[0].span,
module: import.module[0].name.clone(), module: import.module[0].name.clone(),
file_id,
})?; })?;
let mut imported_module = ctx.body.modules.get(imported_module_id).ok_or_else(|| { let mut imported_module = ctx.body.modules.get(imported_module_id).ok_or_else(|| {
LoweringError::ModuleNotFound { LoweringError::ModuleNotFound {
span: import.module[0].span, span: import.module[0].span,
module: import.module[0].name.clone(), module: import.module[0].name.clone(),
file_id,
} }
})?; })?;
@ -332,11 +349,13 @@ pub fn prepass_imports_submodule(
.ok_or_else(|| LoweringError::ModuleNotFound { .ok_or_else(|| LoweringError::ModuleNotFound {
span: module_path.span, span: module_path.span,
module: module_path.name.clone(), module: module_path.name.clone(),
file_id,
})?; })?;
imported_module = ctx.body.modules.get(imported_module_id).ok_or({ imported_module = ctx.body.modules.get(imported_module_id).ok_or({
LoweringError::IdNotFound { LoweringError::IdNotFound {
span: import.span, span: import.span,
id: *imported_module_id, id: *imported_module_id,
file_id,
} }
})?; })?;
} }
@ -357,6 +376,7 @@ pub fn prepass_imports_submodule(
module_span: mod_def.span, module_span: mod_def.span,
import_span: import.span, import_span: import.span,
symbol: sym.clone(), symbol: sym.clone(),
file_id,
})?; })?;
} }
} }

View file

@ -4,13 +4,11 @@ use ariadne::Source;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Session { pub struct Session {
pub file_path: PathBuf, pub file_paths: Vec<PathBuf>,
pub debug_info: DebugInfo, pub debug_info: DebugInfo,
pub optlevel: OptLevel, pub optlevel: OptLevel,
pub source: Source<String>, pub sources: Vec<Source<String>>,
pub library: bool, pub library: bool,
/// The directory where to store artifacts and intermediate files such as object files.
pub target_dir: PathBuf,
pub output_file: PathBuf, pub output_file: PathBuf,
pub output_llvm: bool, pub output_llvm: bool,
pub output_asm: bool, pub output_asm: bool,