Skip to content

Commit

Permalink
check
Browse files Browse the repository at this point in the history
  • Loading branch information
edg-l committed Jan 18, 2024
1 parent a7bc019 commit 843cdec
Show file tree
Hide file tree
Showing 14 changed files with 292 additions and 19 deletions.
16 changes: 12 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[workspace]
resolver = "2"

members = [ "crates/concrete","crates/concrete_ast", "crates/concrete_codegen_mlir", "crates/concrete_driver", "crates/concrete_parser", "crates/concrete_session", "crates/concrete_type_checker"]
members = [ "crates/concrete","crates/concrete_ast", "crates/concrete_codegen_mlir", "crates/concrete_driver", "crates/concrete_parser", "crates/concrete_session", "crates/concrete_check"]

[profile.release]
lto = true
Expand Down
8 changes: 8 additions & 0 deletions crates/concrete_ast/src/common.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::ops::Range;

#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Span {
pub from: usize,
Expand All @@ -10,6 +12,12 @@ impl Span {
}
}

impl From<Span> for Range<usize> {
fn from(val: Span) -> Self {
val.from..val.to
}
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct DocString {
contents: String,
Expand Down
3 changes: 2 additions & 1 deletion crates/concrete_ast/src/imports.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::common::Ident;
use crate::common::{Ident, Span};

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct ImportStmt {
pub module: Vec<Ident>,
pub symbols: Vec<Ident>,
pub span: Span,
}
3 changes: 2 additions & 1 deletion crates/concrete_ast/src/modules.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
common::{DocString, Ident},
common::{DocString, Ident, Span},
constants::ConstantDef,
functions::FunctionDef,
imports::ImportStmt,
Expand All @@ -13,6 +13,7 @@ pub struct Module {
pub imports: Vec<ImportStmt>,
pub name: Ident,
pub contents: Vec<ModuleDefItem>,
pub span: Span,
}

#[derive(Clone, Debug, Eq, PartialEq)]
Expand Down
13 changes: 13 additions & 0 deletions crates/concrete_check/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "concrete_check"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
ariadne = { version = "0.4.0", features = ["auto-color"] }
concrete_ast = { version = "0.1.0", path = "../concrete_ast" }
concrete_session = { version = "0.1.0", path = "../concrete_session" }
itertools = "0.12.0"
thiserror = "1.0.56"
127 changes: 127 additions & 0 deletions crates/concrete_check/src/ast_helper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use std::collections::HashMap;

use concrete_ast::{
common::Ident,
constants::ConstantDef,
functions::FunctionDef,
modules::{Module, ModuleDefItem},
structs::StructDecl,
types::TypeDecl,
Program,
};

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ModuleInfo<'p> {
pub name: String,
pub functions: HashMap<String, &'p FunctionDef>,
pub constants: HashMap<String, &'p ConstantDef>,
pub structs: HashMap<String, &'p StructDecl>,
pub types: HashMap<String, &'p TypeDecl>,
pub modules: HashMap<String, ModuleInfo<'p>>,
}

impl<'p> ModuleInfo<'p> {
pub fn get_module_from_import(&self, import: &[Ident]) -> Option<&ModuleInfo<'p>> {
let next = import.first()?;
let module = self.modules.get(&next.name)?;

if import.len() > 1 {
module.get_module_from_import(&import[1..])
} else {
Some(module)
}
}

/// Returns the symbol name from a local name.
pub fn get_symbol_name(&self, local_name: &str) -> String {
if local_name == "main" {
return local_name.to_string();
}

let mut result = self.name.clone();

result.push_str("::");
result.push_str(local_name);

result
}
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AstHelper<'p> {
pub root: &'p Program,
pub modules: HashMap<String, ModuleInfo<'p>>,
}

impl<'p> AstHelper<'p> {
pub fn new(root: &'p Program) -> Self {
let mut modules = HashMap::default();

for module in &root.modules {
modules.insert(
module.name.name.clone(),
Self::create_module_info(module, None),
);
}

Self { root, modules }
}

pub fn get_module_from_import(&self, import: &[Ident]) -> Option<&ModuleInfo<'p>> {
let next = import.first()?;
let module = self.modules.get(&next.name)?;

if import.len() > 1 {
module.get_module_from_import(&import[1..])
} else {
Some(module)
}
}

fn create_module_info(module: &Module, parent_name: Option<String>) -> ModuleInfo<'_> {
let mut functions = HashMap::default();
let mut constants = HashMap::default();
let mut structs = HashMap::default();
let mut types = HashMap::default();
let mut child_modules = HashMap::default();
let mut name = parent_name.clone().unwrap_or_default();

if name.is_empty() {
name = module.name.name.clone();
} else {
name.push_str(&format!("::{}", module.name.name));
}

for stmt in &module.contents {
match stmt {
ModuleDefItem::Constant(info) => {
constants.insert(info.decl.name.name.clone(), info);
}
ModuleDefItem::Function(info) => {
functions.insert(info.decl.name.name.clone(), info);
}
ModuleDefItem::Struct(info) => {
structs.insert(info.name.name.clone(), info);
}
ModuleDefItem::Type(info) => {
types.insert(info.name.name.clone(), info);
}
ModuleDefItem::Module(info) => {
child_modules.insert(
info.name.name.clone(),
Self::create_module_info(info, Some(name.clone())),
);
}
}
}

ModuleInfo {
name,
functions,
structs,
constants,
types,
modules: child_modules,
}
}
}
101 changes: 101 additions & 0 deletions crates/concrete_check/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use std::{collections::HashMap, ops::Range};

use ariadne::{ColorGenerator, Label, Report, ReportKind};
use ast_helper::AstHelper;
use concrete_ast::{imports::ImportStmt, modules::Module, Program};
use concrete_session::Session;
use itertools::Itertools;
use thiserror::Error;

mod ast_helper;

#[derive(Error, Debug, Clone)]
pub enum CheckError<'p> {
#[error("import not found {:?} in module {}", import, module.name.name)]
ImportModuleMissing {
module: &'p Module,
import: &'p ImportStmt,
},
}

impl<'p> CheckError<'p> {
pub fn to_report<'s>(&self, session: &'s Session) -> Report<'s, (String, Range<usize>)> {
let path = session.file_path.display().to_string();
let mut colors = ColorGenerator::new();
colors.next();

match self {
CheckError::ImportModuleMissing { module, import } => {
let contex_module_span = module.span;
let span = {
let mut span = import
.module
.first()
.expect("module path can't be empty")
.span;
span.to = import
.module
.last()
.expect("module path can't be empty")
.span
.to;
span
};
let offset = import.module[0].span.from;
Report::build(ReportKind::Error, path.clone(), offset)
.with_code("E1")
.with_label(
Label::new((path.clone(), contex_module_span.into()))
.with_message(format!("In module {:?}.", module.name.name)),
)
.with_label(
Label::new((path, span.into()))
.with_message(format!(
"Module {:?} not found.",
import.module.iter().map(|x| &x.name).join(".")
))
.with_color(colors.next()),
)
.with_message("Failed to find import.")
.finish()
}
}
}
}

pub fn check_program<'p>(
program: &'p Program,
_session: &Session,
) -> Result<(), Vec<CheckError<'p>>> {
let helper = AstHelper::new(program);

let mut errors = Vec::new();

for module in &program.modules {
// let info = helper.modules.get(&module.name.name).unwrap();

let mut imports = HashMap::new();

for import in &module.imports {
let target_module = helper.get_module_from_import(&import.module);

if target_module.is_none() {
errors.push(CheckError::ImportModuleMissing { module, import });
continue;
}

let target_module = target_module.unwrap();

for symbol in &import.symbols {
// todo: check if symbol exists.
imports.insert(symbol.name.clone(), target_module);
}
}
}

if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
1 change: 1 addition & 0 deletions crates/concrete_driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ concrete_session = { path = "../concrete_session"}
concrete_codegen_mlir = { path = "../concrete_codegen_mlir"}
salsa = { git = "https://github.com/salsa-rs/salsa.git", package = "salsa-2022" }
ariadne = { version = "0.4.0", features = ["auto-color"] }
concrete_check = { version = "0.1.0", path = "../concrete_check" }

[dev-dependencies]
tempfile = "3.9.0"
12 changes: 12 additions & 0 deletions crates/concrete_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,20 @@ pub fn main() -> Result<(), Box<dyn Error>> {
target_dir,
output_file,
};

tracing::debug!("Compiling with session: {:#?}", session);

if let Err(errors) = concrete_check::check_program(&program, &session) {
for error in &errors {
let path = session.file_path.display().to_string();
error
.to_report(&session)
.eprint((path, session.source.clone()))?;
}

std::process::exit(1);
}

let object_path = concrete_codegen_mlir::compile(&session, &program)?;

if session.library {
Expand Down
8 changes: 5 additions & 3 deletions crates/concrete_parser/src/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,13 @@ pub Program: ast::Program = {
// Modules

pub(crate) Module: ast::modules::Module = {
"mod" <name:Ident> "{" <imports:ImportList?> <contents:ModuleItems> "}" => {
<lo:@L> "mod" <name:Ident> "{" <imports:ImportList?> <contents:ModuleItems> "}" <hi:@R> => {
ast::modules::Module {
doc_string: None,
imports: imports.unwrap_or_else(Vec::new),
name,
contents
contents,
span: Span::new(lo, hi),
}
}
}
Expand All @@ -208,10 +209,11 @@ pub(crate) ImportList: Vec<ast::imports::ImportStmt> = {


pub(crate) ImportStmt: ast::imports::ImportStmt = {
"import" <module:Dot<Ident>> "{" <symbols:Comma<Ident>> "}" ";" => {
<lo:@L> "import" <module:Dot<Ident>> "{" <symbols:Comma<Ident>> "}" ";" <hi:@R> => {
ast::imports::ImportStmt {
module,
symbols,
span: Span::new(lo, hi),
}
}
}
Expand Down
Loading

0 comments on commit 843cdec

Please sign in to comment.