pub mod ast;
pub mod error;
pub mod ir;
pub mod lexer;
pub mod location;
pub mod parser;
pub mod pipeline;
pub mod reporting;
pub mod semantic;
pub(crate) const PRELUDE_SOURCE: &str = include_str!("prelude.fv");
pub use ast::{Definition, Expr, File, Ident, Statement, Type};
pub use error::CompilerError;
pub use ir::{
simple_type_name, EnumId, FunctionId, GenericBase, ImportedKind, IrFunction, IrFunctionParam,
IrFunctionSig, IrImport, IrImportItem, IrModule, ResolvedType, StructId, TraitId,
};
pub use lexer::{Lexer, Token};
pub use location::{Location, Span};
pub use parser::{parse_file, parse_file_with_source};
pub use pipeline::{Backend, IrPass, Pipeline, PipelineError};
pub use reporting::{report_error, report_errors};
pub use semantic::module_resolver::FileSystemResolver;
pub use semantic::SemanticAnalyzer;
pub fn compile_with_analyzer(
source: &str,
) -> Result<(File, SemanticAnalyzer<FileSystemResolver>), Vec<CompilerError>> {
compile_with_analyzer_and_resolver(
source,
FileSystemResolver::new(std::env::current_dir().unwrap_or_else(|_| ".".into())),
)
}
pub fn compile_with_analyzer_and_resolver<R>(
source: &str,
resolver: R,
) -> Result<(File, SemanticAnalyzer<R>), Vec<CompilerError>>
where
R: semantic::module_resolver::ModuleResolver,
{
let (tokens, lex_errors) = Lexer::tokenize_all_with_errors(source);
let parse_result = parse_file_with_source(&tokens, source).map_err(|errors| {
errors
.into_iter()
.map(|(msg, span)| CompilerError::ParseError { message: msg, span })
.collect::<Vec<_>>()
});
let mut file = match parse_result {
Ok(f) if lex_errors.is_empty() => f,
Ok(_) => return Err(lex_errors),
Err(mut parse_errors) => {
let mut all = lex_errors;
all.append(&mut parse_errors);
return Err(all);
}
};
let prelude_file = parse_prelude_file()?;
let mut merged_statements = prelude_file.statements;
merged_statements.append(&mut file.statements);
file.statements = merged_statements;
let mut analyzer =
SemanticAnalyzer::new_with_file(resolver, std::path::PathBuf::from("<root>"));
analyzer.analyze_and_classify(&mut file)?;
Ok((file, analyzer))
}
fn parse_prelude_file() -> Result<File, Vec<CompilerError>> {
let (tokens, lex_errors) = Lexer::tokenize_all_with_errors(PRELUDE_SOURCE);
if !lex_errors.is_empty() {
return Err(lex_errors);
}
parse_file_with_source(&tokens, PRELUDE_SOURCE).map_err(|errors| {
errors
.into_iter()
.map(|(msg, span)| CompilerError::ParseError { message: msg, span })
.collect::<Vec<_>>()
})
}
pub fn compile_and_report(source: &str, filename: &str) -> Result<IrModule, String> {
compile_to_ir(source).map_err(|errors| report_errors(&errors, source, filename))
}
pub fn parse_only(source: &str) -> Result<File, Vec<CompilerError>> {
let (tokens, lex_errors) = Lexer::tokenize_all_with_errors(source);
let parse_result = parse_file_with_source(&tokens, source).map_err(|errors| {
errors
.into_iter()
.map(|(msg, span)| CompilerError::ParseError { message: msg, span })
.collect::<Vec<_>>()
});
match parse_result {
Ok(f) if lex_errors.is_empty() => Ok(f),
Ok(_) => Err(lex_errors),
Err(mut parse_errors) => {
let mut all = lex_errors;
all.append(&mut parse_errors);
Err(all)
}
}
}
pub fn compile_to_ir(source: &str) -> Result<IrModule, Vec<CompilerError>> {
let (ast, analyzer) = compile_with_analyzer(source)?;
ir::lower_to_ir(&ast, analyzer.symbols())
}
pub fn compile_to_ir_with_path(
source: &str,
path: std::path::PathBuf,
) -> Result<IrModule, Vec<CompilerError>> {
let (ast, analyzer) = compile_with_analyzer(source)?;
ir::lower_to_ir_with_path(&ast, analyzer.symbols(), path)
}
pub fn compile_to_ir_with_resolver<R>(
source: &str,
resolver: R,
) -> Result<IrModule, Vec<CompilerError>>
where
R: semantic::module_resolver::ModuleResolver,
{
let (ast, analyzer) = compile_with_analyzer_and_resolver(source, resolver)?;
let module = ir::lower_to_ir(&ast, analyzer.symbols())?;
let imported_ir = analyzer.imported_ir_modules();
let mut imports_map: std::collections::HashMap<Vec<String>, IrModule> =
std::collections::HashMap::with_capacity(module.imports.len());
for imp in &module.imports {
if let Some(ir_mod) = imported_ir.get(&imp.source_file) {
imports_map.insert(imp.module_path.clone(), ir_mod.clone());
}
}
Pipeline::new()
.pass(ir::MonomorphisePass::default().with_imports(imports_map))
.run(module)
}
pub fn compile_to_ir_with_path_and_resolver<R>(
source: &str,
path: std::path::PathBuf,
resolver: R,
) -> Result<IrModule, Vec<CompilerError>>
where
R: semantic::module_resolver::ModuleResolver,
{
let (ast, analyzer) = compile_with_analyzer_and_resolver(source, resolver)?;
ir::lower_to_ir_with_path(&ast, analyzer.symbols(), path)
}