Implement import-pass

This commit is contained in:
Sofia 2025-07-14 20:13:30 +03:00
parent 464156b2dc
commit a71843dfe9
11 changed files with 208 additions and 31 deletions

View File

@ -1,12 +1,14 @@
use std::{env, fs}; use std::{env, fs, path::PathBuf};
use reid::compile; use reid::compile;
fn main() -> Result<(), std::io::Error> { fn main() -> Result<(), std::io::Error> {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if let Some(filename) = args.get(1) { if let Some(filename) = args.get(1) {
let text = fs::read_to_string(filename)?; let path = PathBuf::from(filename);
let output = match compile(&text) {
let text = fs::read_to_string(&path)?;
let output = match compile(&text, PathBuf::from(path)) {
Ok(t) => t, Ok(t) => t,
Err(e) => panic!("{}", e), Err(e) => panic!("{}", e),
}; };

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use reid::mir::{self, *}; use reid::mir::{self, *};
use reid_lib::Context; use reid_lib::Context;
@ -159,7 +161,9 @@ fn main() {
name: "test module".to_owned(), name: "test module".to_owned(),
imports: vec![], imports: vec![],
functions: vec![fibonacci, main], functions: vec![fibonacci, main],
path: None,
}], }],
base: PathBuf::new(),
}; };
println!("test1"); println!("test1");

View File

@ -1,6 +1,8 @@
//! This is the module that contains relevant code to parsing Reid, that is to //! This is the module that contains relevant code to parsing Reid, that is to
//! say transforming a Vec of FullTokens into a loose parsed AST that can be //! say transforming a Vec of FullTokens into a loose parsed AST that can be
//! used for unwrapping syntax sugar, and then be transformed into Reid MIR. //! used for unwrapping syntax sugar, and then be transformed into Reid MIR.
use std::path::PathBuf;
use crate::token_stream::TokenRange; use crate::token_stream::TokenRange;
pub mod parse; pub mod parse;
@ -166,4 +168,5 @@ pub enum TopLevelStatement {
pub struct Module { pub struct Module {
pub name: String, pub name: String,
pub top_level_statements: Vec<TopLevelStatement>, pub top_level_statements: Vec<TopLevelStatement>,
pub path: Option<PathBuf>,
} }

View File

@ -1,18 +1,18 @@
use std::path::PathBuf;
use crate::{ use crate::{
ast::{self}, ast::{self},
mir::{self, NamedVariableRef, StmtKind}, mir::{self, NamedVariableRef, StmtKind},
}; };
impl mir::Context { impl mir::Context {
pub fn from(modules: Vec<ast::Module>) -> mir::Context { pub fn from(modules: Vec<mir::Module>, base: PathBuf) -> mir::Context {
mir::Context { mir::Context { modules, base }
modules: modules.iter().map(|m| m.process()).collect(),
}
} }
} }
impl ast::Module { impl ast::Module {
fn process(&self) -> mir::Module { pub fn process(&self) -> mir::Module {
let mut imports = Vec::new(); let mut imports = Vec::new();
let mut functions = Vec::new(); let mut functions = Vec::new();
@ -67,6 +67,7 @@ impl ast::Module {
name: self.name.clone(), name: self.name.clone(),
imports, imports,
functions, functions,
path: self.path.clone(),
} }
} }
} }

View File

@ -267,7 +267,7 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
Ok(tokens) Ok(tokens)
} }
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug, Clone)]
pub enum Error { pub enum Error {
#[error("Invalid token '{}' at Ln {}, Col {}", .0, (.1).1, (.1).0)] #[error("Invalid token '{}' at Ln {}, Col {}", .0, (.1).1, (.1).0)]
InvalidToken(char, Position), InvalidToken(char, Position),

View File

@ -40,6 +40,8 @@
//! - Loops //! - Loops
//! ``` //! ```
use std::path::PathBuf;
use mir::{typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs}; use mir::{typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs};
use reid_lib::Context; use reid_lib::Context;
@ -53,7 +55,7 @@ mod pad_adapter;
mod token_stream; mod token_stream;
mod util; mod util;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug, Clone)]
pub enum ReidError { pub enum ReidError {
#[error(transparent)] #[error(transparent)]
LexerError(#[from] lexer::Error), LexerError(#[from] lexer::Error),
@ -63,10 +65,7 @@ pub enum ReidError {
TypeCheckErrors(Vec<mir::pass::Error<mir::typecheck::ErrorKind>>), TypeCheckErrors(Vec<mir::pass::Error<mir::typecheck::ErrorKind>>),
} }
/// Takes in a bit of source code, parses and compiles it and produces `hello.o` pub fn compile_module(source: &str, path: Option<PathBuf>) -> Result<mir::Module, ReidError> {
/// and `hello.asm` from it, which can be linked using `ld` to produce an
/// executable file.
pub fn compile(source: &str) -> Result<String, ReidError> {
let tokens = lexer::tokenize(source)?; let tokens = lexer::tokenize(source)?;
dbg!(&tokens); dbg!(&tokens);
@ -83,10 +82,20 @@ pub fn compile(source: &str) -> Result<String, ReidError> {
let ast_module = ast::Module { let ast_module = ast::Module {
name: "test".to_owned(), name: "test".to_owned(),
top_level_statements: statements, top_level_statements: statements,
path,
}; };
dbg!(&ast_module); Ok(ast_module.process())
let mut mir_context = mir::Context::from(vec![ast_module]); }
/// Takes in a bit of source code, parses and compiles it and produces `hello.o`
/// and `hello.asm` from it, which can be linked using `ld` to produce an
/// executable file.
pub fn compile(source: &str, path: PathBuf) -> Result<String, ReidError> {
let mut mir_context = mir::Context::from(
vec![compile_module(source, Some(path.clone()))?],
path.parent().unwrap().to_owned(),
);
println!("{}", &mir_context); println!("{}", &mir_context);

120
reid/src/mir/imports.rs Normal file
View File

@ -0,0 +1,120 @@
use std::{collections::HashMap, convert::Infallible, fs, path::PathBuf};
use crate::{compile_module, ReidError};
use super::{
pass::{Pass, PassState},
types::EqualsIssue,
Context, FunctionDefinition, Import, Module,
};
#[derive(thiserror::Error, Debug, Clone)]
pub enum ErrorKind {
#[error("Unable to import inner modules, not yet supported: {0}")]
InnerModulesNotYetSupported(Import),
#[error("No such module: {0}")]
ModuleNotFound(String),
#[error("Error while compiling module {0}: {1}")]
ModuleCompilationError(String, ReidError),
#[error("No such function {0} found in module {1}")]
NoSuchFunctionInModule(String, String),
#[error("Importing function {0}::{1} not possible: {2}")]
FunctionImportIssue(String, String, EqualsIssue),
}
/// Struct used to implement a type-checking pass that can be performed on the
/// MIR.
pub struct ImportsPass {}
impl Pass for ImportsPass {
type TError = ErrorKind;
fn context(&mut self, context: &mut Context, mut state: PassState<Self::TError>) {
let mut modules = HashMap::<String, Module>::new();
for module in context.modules.clone() {
modules.insert(module.name.clone(), module);
}
let mut modules_to_process: Vec<_> = modules.values().cloned().collect();
let iter = modules_to_process.iter_mut();
for module in iter {
let mut new_modules = Vec::new();
for import in &module.imports {
let Import(path, _) = import;
if path.len() != 2 {
state.ok::<_, Infallible>(
Err(ErrorKind::InnerModulesNotYetSupported(import.clone())),
import.1,
);
}
let module_name = unsafe { path.get_unchecked(0) };
let imported = if let Some(module) = modules.get(module_name) {
module
} else {
let file_path = PathBuf::from(&context.base.clone()).join(module_name);
let Ok(source) = fs::read_to_string(&file_path) else {
state.ok::<_, Infallible>(
Err(ErrorKind::ModuleNotFound(module_name.clone())),
import.1,
);
continue;
};
match compile_module(&source, Some(file_path)) {
Ok(m) => {
new_modules.push(m);
new_modules.last().unwrap()
}
Err(err) => {
state.ok::<_, Infallible>(
Err(ErrorKind::ModuleCompilationError(module_name.clone(), err)),
import.1,
);
continue;
}
}
};
let func_name = unsafe { path.get_unchecked(1) };
let Some(func) = imported.functions.iter().find(|f| f.name == *func_name) else {
state.ok::<_, Infallible>(
Err(ErrorKind::NoSuchFunctionInModule(
module_name.clone(),
func_name.clone(),
)),
import.1,
);
continue;
};
if let Some(existing) = module.functions.iter().find(|f| f.name == *func_name) {
if let Err(e) = existing.equals_as_imported(func) {
state.ok::<_, Infallible>(
Err(ErrorKind::FunctionImportIssue(
module_name.clone(),
func_name.clone(),
e,
)),
import.1,
);
}
}
module.functions.push(FunctionDefinition {
name: func.name.clone(),
is_pub: false,
return_type: func.return_type.clone(),
parameters: func.parameters.clone(),
kind: super::FunctionDefinitionKind::Extern,
});
}
}
}
}

View File

@ -2,9 +2,12 @@
//! Reid. It contains a simplified version of Reid which can be e.g. //! Reid. It contains a simplified version of Reid which can be e.g.
//! typechecked. //! typechecked.
use std::path::PathBuf;
use crate::token_stream::TokenRange; use crate::token_stream::TokenRange;
mod display; mod display;
pub mod imports;
pub mod pass; pub mod pass;
pub mod typecheck; pub mod typecheck;
pub mod typeinference; pub mod typeinference;
@ -205,13 +208,13 @@ pub enum ReturnKind {
Soft, Soft,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata); pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata);
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Import(pub Vec<String>, pub Metadata); pub struct Import(pub Vec<String>, pub Metadata);
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum ExprKind { pub enum ExprKind {
Variable(NamedVariableRef), Variable(NamedVariableRef),
Index(Box<Expression>, TypeKind, u64), Index(Box<Expression>, TypeKind, u64),
@ -223,21 +226,21 @@ pub enum ExprKind {
Block(Block), Block(Block),
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Expression(pub ExprKind, pub Metadata); pub struct Expression(pub ExprKind, pub Metadata);
/// Condition, Then, Else /// Condition, Then, Else
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct IfExpression(pub Box<Expression>, pub Block, pub Option<Block>); pub struct IfExpression(pub Box<Expression>, pub Block, pub Option<Block>);
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct FunctionCall { pub struct FunctionCall {
pub name: String, pub name: String,
pub return_type: TypeKind, pub return_type: TypeKind,
pub parameters: Vec<Expression>, pub parameters: Vec<Expression>,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct FunctionDefinition { pub struct FunctionDefinition {
pub name: String, pub name: String,
pub is_pub: bool, pub is_pub: bool,
@ -246,7 +249,7 @@ pub struct FunctionDefinition {
pub kind: FunctionDefinitionKind, pub kind: FunctionDefinitionKind,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum FunctionDefinitionKind { pub enum FunctionDefinitionKind {
/// Actual definition block and surrounding signature range /// Actual definition block and surrounding signature range
Local(Block, Metadata), Local(Block, Metadata),
@ -269,7 +272,7 @@ impl FunctionDefinition {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Block { pub struct Block {
/// List of non-returning statements /// List of non-returning statements
pub statements: Vec<Statement>, pub statements: Vec<Statement>,
@ -277,22 +280,22 @@ pub struct Block {
pub meta: Metadata, pub meta: Metadata,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Statement(pub StmtKind, pub Metadata); pub struct Statement(pub StmtKind, pub Metadata);
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct IndexedVariableReference { pub struct IndexedVariableReference {
pub kind: IndexedVariableReferenceKind, pub kind: IndexedVariableReferenceKind,
pub meta: Metadata, pub meta: Metadata,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum IndexedVariableReferenceKind { pub enum IndexedVariableReferenceKind {
Named(NamedVariableRef), Named(NamedVariableRef),
Index(Box<IndexedVariableReference>, u64), Index(Box<IndexedVariableReference>, u64),
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum StmtKind { pub enum StmtKind {
/// Variable name++mutability+type, evaluation /// Variable name++mutability+type, evaluation
Let(NamedVariableRef, bool, Expression), Let(NamedVariableRef, bool, Expression),
@ -301,14 +304,16 @@ pub enum StmtKind {
Expression(Expression), Expression(Expression),
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Module { pub struct Module {
pub name: String, pub name: String,
pub imports: Vec<Import>, pub imports: Vec<Import>,
pub functions: Vec<FunctionDefinition>, pub functions: Vec<FunctionDefinition>,
pub path: Option<PathBuf>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Context { pub struct Context {
pub modules: Vec<Module>, pub modules: Vec<Module>,
pub base: PathBuf,
} }

View File

@ -191,6 +191,7 @@ impl<'st, 'sc, TError: STDError + Clone> PassState<'st, 'sc, TError> {
pub trait Pass { pub trait Pass {
type TError: STDError + Clone; type TError: STDError + Clone;
fn context(&mut self, _context: &mut Context, mut _state: PassState<Self::TError>) {}
fn module(&mut self, _module: &mut Module, mut _state: PassState<Self::TError>) {} fn module(&mut self, _module: &mut Module, mut _state: PassState<Self::TError>) {}
fn function( fn function(
&mut self, &mut self,
@ -207,6 +208,7 @@ impl Context {
pub fn pass<T: Pass>(&mut self, pass: &mut T) -> State<T::TError> { pub fn pass<T: Pass>(&mut self, pass: &mut T) -> State<T::TError> {
let mut state = State::new(); let mut state = State::new();
let mut scope = Scope::default(); let mut scope = Scope::default();
pass.context(self, PassState::from(&mut state, &mut scope));
for module in &mut self.modules { for module in &mut self.modules {
module.pass(pass, &mut state, &mut scope); module.pass(pass, &mut state, &mut scope);
} }

View File

@ -180,3 +180,34 @@ impl IndexedVariableReference {
} }
} }
} }
#[derive(Debug, Clone, Copy, thiserror::Error)]
pub enum EqualsIssue {
#[error("Function is already defined locally at {:?}", (.0).range)]
ExistsLocally(Metadata),
#[error("asd")]
Equals,
#[error("asd")]
ConflictingImports,
}
impl FunctionDefinition {
pub fn equals_as_imported(&self, other: &FunctionDefinition) -> Result<(), EqualsIssue> {
match &self.kind {
FunctionDefinitionKind::Local(_, metadata) => {
Err(EqualsIssue::ExistsLocally(*metadata))
}
FunctionDefinitionKind::Extern => {
if self.is_pub == other.is_pub
&& self.name == other.name
&& self.parameters == other.parameters
&& self.return_type == other.return_type
{
Ok(())
} else {
Err(EqualsIssue::ConflictingImports)
}
}
}
}
}

View File

@ -205,7 +205,7 @@ impl std::iter::Sum for TokenRange {
} }
} }
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug, Clone)]
pub enum Error { pub enum Error {
#[error("Expected {} at Ln {}, Col {}, got {:?}", .0, (.2).1, (.2).0, .1)] #[error("Expected {} at Ln {}, Col {}, got {:?}", .0, (.2).1, (.2).0, .1)]
Expected(String, Token, Position), Expected(String, Token, Position),