Big restructure pt.1
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "leaf_compiler"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
leaf_parser = { path = "../parser" }
|
||||
leaf_assembly = { path = "../assembly" }
|
||||
leaf_allocators = { path = "../allocators" }
|
||||
arcstr = "1.2.0"
|
||||
@@ -0,0 +1,52 @@
|
||||
use leaf_parser::{LineCol, ParseError};
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::SourceFile;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Kind {
|
||||
Unknown = 0x0000,
|
||||
|
||||
Parsing = 0x0100,
|
||||
|
||||
SymbolNotFound = 0x0200,
|
||||
UninitializedSymbol = 0x0201,
|
||||
NotAType = 0x0202,
|
||||
|
||||
FunctionCompilationFailed = 0x0301,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Location {
|
||||
None,
|
||||
Range {
|
||||
file: SourceFile,
|
||||
range: Range<usize>,
|
||||
},
|
||||
Position {
|
||||
file: SourceFile,
|
||||
position: LineCol,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompilationError {
|
||||
pub kind: Kind,
|
||||
pub message: String,
|
||||
pub location: Location,
|
||||
pub cause: Option<Box<CompilationError>>,
|
||||
}
|
||||
|
||||
impl CompilationError {
|
||||
pub fn parsing(file: SourceFile, err: ParseError<LineCol>) -> Self {
|
||||
Self {
|
||||
kind: Kind::Parsing,
|
||||
message: err.to_string(),
|
||||
location: Location::Position {
|
||||
file,
|
||||
position: err.location,
|
||||
},
|
||||
cause: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
use crate::{error::CompilationError, scope::Scope};
|
||||
use arcstr::literal_substr;
|
||||
use leaf_allocators::SyncAllocator;
|
||||
use leaf_assembly::{
|
||||
assembly::{Assembly, AssemblyIdentifier, Context},
|
||||
values::Value,
|
||||
};
|
||||
use leaf_parser::SourceCode;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
mod error;
|
||||
mod scope;
|
||||
|
||||
pub type SourceFile = Arc<SourceCode>;
|
||||
|
||||
pub struct CompilationContext<'l> {
|
||||
ctx: &'l Context<'l>,
|
||||
alloc: &'l dyn SyncAllocator,
|
||||
}
|
||||
|
||||
impl<'l> CompilationContext<'l> {
|
||||
pub fn new(alloc: &'l dyn SyncAllocator) -> Self {
|
||||
Self {
|
||||
alloc,
|
||||
ctx: Context::new(alloc),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_assembly(&self, ident: &AssemblyIdentifier) -> Option<&'l Assembly<'l>> {
|
||||
self.ctx.get_assembly(ident)
|
||||
}
|
||||
|
||||
pub fn extend(
|
||||
&'l self,
|
||||
ident: AssemblyIdentifier,
|
||||
sources: &[Arc<SourceCode>],
|
||||
) -> Result<(), CompilationError> {
|
||||
let assembly = self.ctx.get_or_create_assembly(ident.clone());
|
||||
|
||||
let mut units = Vec::with_capacity(sources.len());
|
||||
for src in sources {
|
||||
match leaf_parser::parse(src) {
|
||||
Ok(unit) => units.push(unit),
|
||||
Err(err) => return Err(CompilationError::parsing(src.clone(), err)),
|
||||
}
|
||||
}
|
||||
|
||||
let mut scopes: Vec<_> = sources
|
||||
.iter()
|
||||
.map(|src| {
|
||||
let mut scope = Scope::new(assembly, src.clone());
|
||||
scope.insert(literal_substr!("void"), Value::Type(self.ctx.void_t()));
|
||||
scope.insert(literal_substr!("i8"), Value::Type(self.ctx.i8_t()));
|
||||
scope.insert(literal_substr!("i16"), Value::Type(self.ctx.i16_t()));
|
||||
scope.insert(literal_substr!("i32"), Value::Type(self.ctx.i32_t()));
|
||||
scope.insert(literal_substr!("i64"), Value::Type(self.ctx.i64_t()));
|
||||
scope.insert(literal_substr!("i128"), Value::Type(self.ctx.i128_t()));
|
||||
scope.insert(literal_substr!("isize"), Value::Type(self.ctx.isize_t()));
|
||||
scope.insert(literal_substr!("u8"), Value::Type(self.ctx.u8_t()));
|
||||
scope.insert(literal_substr!("u16"), Value::Type(self.ctx.u16_t()));
|
||||
scope.insert(literal_substr!("u32"), Value::Type(self.ctx.u32_t()));
|
||||
scope.insert(literal_substr!("u64"), Value::Type(self.ctx.u64_t()));
|
||||
scope.insert(literal_substr!("u128"), Value::Type(self.ctx.u128_t()));
|
||||
scope.insert(literal_substr!("usize"), Value::Type(self.ctx.usize_t()));
|
||||
scope.insert(literal_substr!("f16"), Value::Type(self.ctx.f16_t()));
|
||||
scope.insert(literal_substr!("f32"), Value::Type(self.ctx.f32_t()));
|
||||
scope.insert(literal_substr!("f64"), Value::Type(self.ctx.f64_t()));
|
||||
scope.insert(literal_substr!("type"), Value::Type(self.ctx.type_t()));
|
||||
scope
|
||||
})
|
||||
.collect();
|
||||
|
||||
for i in 0..sources.len() {
|
||||
let unit = &units[i];
|
||||
let scope = &mut scopes[i];
|
||||
scope.declare_constants(&unit.decls);
|
||||
}
|
||||
|
||||
for i in 0..sources.len() {
|
||||
let unit = &units[i];
|
||||
let scope = &mut scopes[i];
|
||||
scope.define_constants(&unit.decls)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
use arcstr::ArcStr;
|
||||
use leaf_allocators::SyncArenaAllocator;
|
||||
use leaf_assembly::assembly::{AssemblyIdentifier, Version};
|
||||
use leaf_compiler::CompilationContext;
|
||||
use leaf_parser::SourceCode;
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
fn main() {
|
||||
let alloc = SyncArenaAllocator::default();
|
||||
let context = CompilationContext::new(&alloc);
|
||||
let ident = AssemblyIdentifier {
|
||||
version: Version::default(),
|
||||
name: std::borrow::Cow::Borrowed("leaf_test"),
|
||||
};
|
||||
if let Err(err) = context.extend(
|
||||
ident.clone(),
|
||||
&[Arc::new(SourceCode {
|
||||
text: ArcStr::from(std::fs::read_to_string("../test.leaf").unwrap()),
|
||||
file: PathBuf::from("../test.leaf"),
|
||||
})],
|
||||
) {
|
||||
println!("{}", err.message);
|
||||
} else {
|
||||
println!("{:#?}", context.get_assembly(&ident));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
use arcstr::Substr;
|
||||
use leaf_assembly::{
|
||||
assembly::Assembly,
|
||||
types::{Type, derivations::MakeTypeDerivations},
|
||||
values::Value,
|
||||
};
|
||||
use leaf_parser::{
|
||||
SourceCode,
|
||||
ast::{self, ConstDecl, Expr, Ident},
|
||||
};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Scope<'l> {
|
||||
assembly: &'l Assembly<'l>,
|
||||
source: Arc<SourceCode>,
|
||||
values: HashMap<Substr, Option<Value<'l>>>,
|
||||
}
|
||||
|
||||
impl<'l> Scope<'l> {
|
||||
pub fn new(assembly: &'l Assembly<'l>, source: Arc<SourceCode>) -> Self {
|
||||
Self {
|
||||
assembly,
|
||||
source,
|
||||
values: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, name: Substr, value: Value<'l>) {
|
||||
self.values.insert(name, Some(value));
|
||||
}
|
||||
|
||||
pub fn declare_constants(&mut self, decl: &[ConstDecl]) {
|
||||
for val in decl {
|
||||
for Ident(name) in val.names.as_slice() {
|
||||
self.values.insert(name.clone(), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn define_constants(&mut self, decl: &[ConstDecl]) -> Result<(), CompilationError> {
|
||||
for val in decl {
|
||||
let expr = self.compile_expression(&val.value)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile_expression(&self, expr: &Expr) -> Result<Value<'l>, CompilationError> {
|
||||
match expr {
|
||||
Expr::Ident(Ident(name)) => match self.values.get(name) {
|
||||
None => Err(CompilationError {
|
||||
kind: Kind::SymbolNotFound,
|
||||
message: format!("Symbol `{name}` does not exist in the current scope."),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: name.range(),
|
||||
},
|
||||
cause: None,
|
||||
}),
|
||||
Some(None) => Err(CompilationError {
|
||||
kind: Kind::UninitializedSymbol,
|
||||
message: format!("Symbol `{name}` is not initialized at this time."),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: name.range(),
|
||||
},
|
||||
cause: None,
|
||||
}),
|
||||
Some(Some(value)) => Ok(*value),
|
||||
},
|
||||
Expr::Func(func) => self.compile_function(func).map_err(|err| CompilationError {
|
||||
kind: Kind::FunctionCompilationFailed,
|
||||
message: format!("Could not compile function."),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: func.text.range(),
|
||||
},
|
||||
cause: Some(Box::new(err)),
|
||||
}),
|
||||
_ => todo!("{expr:#?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_function(&self, func: &ast::Function) -> Result<Value<'l>, CompilationError> {
|
||||
let ret_ty = self.assert_type(self.compile_expression(&func.ret)?)?;
|
||||
let mut par_ty = Vec::with_capacity(func.args.len());
|
||||
for arg in &func.args {
|
||||
let ty = self.assert_type(self.compile_expression(&arg.r#type)?)?;
|
||||
par_ty.push(ty);
|
||||
}
|
||||
let fn_ty = ret_ty.make_fn(par_ty);
|
||||
Ok(Value::Func(self.assembly.create_function(fn_ty)))
|
||||
}
|
||||
|
||||
fn assert_type(&self, val: Value<'l>) -> Result<Type<'l>, CompilationError> {
|
||||
match val {
|
||||
Value::Type(ty) => Ok(ty),
|
||||
_ => Err(CompilationError {
|
||||
kind: Kind::NotAType,
|
||||
message: format!("Value is not a type."),
|
||||
location: Location::None,
|
||||
cause: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user