Fix entry point reimports to give an error

This commit is contained in:
LunaAmora 2024-06-24 15:17:07 -03:00
parent 4814742247
commit 53ca86848d
13 changed files with 126 additions and 81 deletions

View File

@ -6,7 +6,7 @@ use crate::{
diagnostics::{Diagnostics, DiagnosticsConfig},
imports::PackageLoader,
};
use std::{fmt::Display, path::Path};
use std::path::Path;
// TODO: Refactor so that we don't mix the two syntaxes here.
@ -17,11 +17,11 @@ pub fn load_file_to_book(
diag: DiagnosticsConfig,
) -> Result<Book, Diagnostics> {
let code = std::fs::read_to_string(path).map_err(|e| e.to_string())?;
load_to_book(path.display(), &code, package_loader, diag)
load_to_book(path, &code, package_loader, diag)
}
pub fn load_to_book<T: Display>(
origin: T,
pub fn load_to_book(
origin: &Path,
code: &str,
package_loader: impl PackageLoader,
diag: DiagnosticsConfig,
@ -31,11 +31,11 @@ pub fn load_to_book<T: Display>(
book.load_imports(package_loader, diag)
}
pub fn do_parse_book<T: Display>(code: &str, origin: T, mut book: ParseBook) -> Result<ParseBook, String> {
book.source = Name::new(format!("{origin}"));
TermParser::new(code).parse_book(book, false).map_err(|e| format!("In {} :\n{}", origin, e))
pub fn do_parse_book(code: &str, origin: &Path, mut book: ParseBook) -> Result<ParseBook, String> {
book.source = Name::new(origin.to_string_lossy());
TermParser::new(code).parse_book(book, false).map_err(|e| format!("In {} :\n{}", origin.display(), e))
}
pub fn do_parse_book_default<T: Display>(code: &str, origin: T) -> Result<Book, String> {
pub fn do_parse_book_default(code: &str, origin: &Path) -> Result<Book, String> {
do_parse_book(code, origin, ParseBook::builtins())?.to_fun()
}

View File

@ -3,7 +3,7 @@ use crate::fun::Name;
use indexmap::IndexMap;
use std::{
collections::HashSet,
path::{Path, PathBuf},
path::{Component, Path, PathBuf},
};
pub type Sources = IndexMap<Name, String>;
@ -40,23 +40,33 @@ pub trait PackageLoader {
pub struct DefaultLoader {
local_path: PathBuf,
loaded: HashSet<Name>,
entrypoint: Name,
}
impl DefaultLoader {
pub fn new(local_path: &Path) -> Self {
let entrypoint = Name::new(local_path.file_stem().unwrap().to_string_lossy());
let local_path = local_path.parent().unwrap().to_path_buf();
Self { local_path, loaded: HashSet::new() }
Self { local_path, loaded: HashSet::new(), entrypoint }
}
fn read_file(&mut self, path: &Path, file: Name, src: &mut Sources) -> Option<Name> {
if !self.is_loaded(&file) {
self.loaded.insert(file.clone());
fn read_file(&mut self, path: &Path, file_path: &str, src: &mut Sources) -> Result<Option<Name>, String> {
let normalized = normalize_path(&PathBuf::from(file_path));
let file_path = Name::new(normalized.to_string_lossy());
if self.entrypoint == file_path {
return Err("Can not import the entry point of the program.".to_string());
};
if !self.is_loaded(&file_path) {
self.loaded.insert(file_path.clone());
let path = path.with_extension("bend");
let code = std::fs::read_to_string(path).ok()?;
src.insert(file.clone(), code);
let Some(code) = std::fs::read_to_string(path).ok() else { return Ok(None) };
src.insert(file_path.clone(), code);
}
Some(file)
Ok(Some(file_path))
}
fn read_file_in_folder(
@ -65,11 +75,15 @@ impl DefaultLoader {
folder: &str,
file_name: &str,
src: &mut Sources,
) -> Option<Name> {
let file_path = Name::new(format!("{}/{}", folder, file_name));
) -> Result<Option<Name>, String> {
let full_path = full_path.join(file_name);
self.read_file(&full_path, file_path, src)
if folder.is_empty() {
self.read_file(&full_path, file_name, src)
} else {
let file_name = &format!("{}/{}", folder, file_name);
self.read_file(&full_path, file_name, src)
}
}
fn read_path(
@ -77,12 +91,12 @@ impl DefaultLoader {
base_path: &Path,
path: &Name,
imp_type: &ImportType,
) -> Option<(BoundSource, Sources)> {
) -> Result<Option<(BoundSource, Sources)>, String> {
let full_path = base_path.join(path.as_ref());
let mut src = IndexMap::new();
let file = if full_path.with_extension("bend").is_file() {
self.read_file(&full_path, path.clone(), &mut src)
self.read_file(&full_path, path.as_ref(), &mut src)?
} else {
None
};
@ -92,13 +106,13 @@ impl DefaultLoader {
match imp_type {
ImportType::Single(file, _) => {
if let Some(name) = self.read_file_in_folder(&full_path, path, file, &mut src) {
if let Some(name) = self.read_file_in_folder(&full_path, path, file, &mut src)? {
names.insert(file.clone(), name);
}
}
ImportType::List(list) => {
for (file, _) in list {
if let Some(name) = self.read_file_in_folder(&full_path, path, file, &mut src) {
if let Some(name) = self.read_file_in_folder(&full_path, path, file, &mut src)? {
names.insert(file.clone(), name);
}
}
@ -109,7 +123,7 @@ impl DefaultLoader {
if let Some("bend") = file.extension().and_then(|f| f.to_str()) {
let file = file.file_stem().unwrap().to_string_lossy();
if let Some(name) = self.read_file_in_folder(&full_path, path, &file, &mut src) {
if let Some(name) = self.read_file_in_folder(&full_path, path, &file, &mut src)? {
names.insert(Name::new(file), name);
}
}
@ -126,12 +140,14 @@ impl DefaultLoader {
None
};
match (file, dir) {
let src = match (file, dir) {
(Some(f), None) => Some((BoundSource::File(f), src)),
(None, Some(d)) => Some((BoundSource::Dir(d), src)),
(Some(f), Some(d)) => Some((BoundSource::Either(f, d), src)),
(None, None) => None,
}
};
Ok(src)
}
fn is_loaded(&self, name: &Name) -> bool {
@ -154,7 +170,7 @@ impl PackageLoader for DefaultLoader {
};
for base in folders {
let Some((names, new_pkgs)) = self.read_path(&base, path, imp_type) else { continue };
let Some((names, new_pkgs)) = self.read_path(&base, path, imp_type)? else { continue };
*src = names;
sources.extend(new_pkgs);
@ -168,3 +184,31 @@ impl PackageLoader for DefaultLoader {
Ok(sources)
}
}
// Taken from 'cargo/util/paths.rs'
pub fn normalize_path(path: &Path) -> PathBuf {
let mut components = path.components().peekable();
let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
components.next();
PathBuf::from(c.as_os_str())
} else {
PathBuf::new()
};
for component in components {
match component {
Component::Prefix(..) => unreachable!(),
Component::RootDir => {
ret.push(component.as_os_str());
}
Component::CurDir => {}
Component::ParentDir => {
ret.pop();
}
Component::Normal(c) => {
ret.push(c);
}
}
}
ret
}

View File

@ -1,14 +1,10 @@
use super::{loader::PackageLoader, BoundSource, ImportCtx, ImportType, ImportsMap};
use super::{loader::PackageLoader, normalize_path, BoundSource, ImportCtx, ImportType, ImportsMap};
use crate::{
diagnostics::Diagnostics,
fun::{load_book::do_parse_book, parser::ParseBook, Name},
};
use indexmap::{IndexMap, IndexSet};
use std::{
cell::RefCell,
collections::VecDeque,
path::{Component, Path, PathBuf},
};
use std::{cell::RefCell, collections::VecDeque, path::PathBuf};
#[derive(Default)]
pub struct Packages {
@ -23,7 +19,7 @@ pub struct Packages {
impl Packages {
pub fn new(book: ParseBook) -> Self {
Self {
books: IndexMap::from([(Name::default(), book.into())]),
books: IndexMap::from([(book.source.clone(), book.into())]),
load_queue: VecDeque::new(),
loaded_adts: IndexMap::new(),
}
@ -84,7 +80,7 @@ impl Packages {
}
for (psrc, code) in sources {
let module = do_parse_book(&code, &psrc, ParseBook::default())?;
let module = do_parse_book(&code, &PathBuf::from(psrc.as_ref()), ParseBook::default())?;
self.load_queue.push_back(self.books.len());
self.books.insert(psrc, module.into());
}
@ -239,31 +235,3 @@ impl Packages {
bound_book.top_level_names().cloned().collect()
}
}
// Taken from 'cargo/util/paths.rs'
fn normalize_path(path: &Path) -> PathBuf {
let mut components = path.components().peekable();
let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
components.next();
PathBuf::from(c.as_os_str())
} else {
PathBuf::new()
};
for component in components {
match component {
Component::Prefix(..) => unreachable!(),
Component::RootDir => {
ret.push(component.as_os_str());
}
Component::CurDir => {}
Component::ParentDir => {
ret.pop();
}
Component::Normal(c) => {
ret.push(c);
}
}
}
ret
}

View File

@ -107,7 +107,7 @@ pub fn run_book_simple(
#[test]
fn compile_file() {
run_golden_test_dir(function_name!(), &|code, path| {
let mut book = do_parse_book_default(code, path.display())?;
let mut book = do_parse_book_default(code, path)?;
let compile_opts = CompileOpts::default();
let diagnostics_cfg = DiagnosticsConfig { unused_definition: Severity::Allow, ..Default::default() };
@ -119,7 +119,7 @@ fn compile_file() {
#[test]
fn compile_file_o_all() {
run_golden_test_dir(function_name!(), &|code, path| {
let mut book = do_parse_book_default(code, path.display())?;
let mut book = do_parse_book_default(code, path)?;
let opts = CompileOpts::default().set_all();
let diagnostics_cfg = DiagnosticsConfig {
recursion_cycle: Severity::Warning,
@ -135,7 +135,7 @@ fn compile_file_o_all() {
#[test]
fn compile_file_o_no_all() {
run_golden_test_dir(function_name!(), &|code, path| {
let mut book = do_parse_book_default(code, path.display())?;
let mut book = do_parse_book_default(code, path)?;
let compile_opts = CompileOpts::default().set_no_all();
let diagnostics_cfg = DiagnosticsConfig::default();
let res = compile_book(&mut book, compile_opts, diagnostics_cfg, None)?;
@ -147,7 +147,7 @@ fn compile_file_o_no_all() {
fn linear_readback() {
run_golden_test_dir(function_name!(), &|code, path| {
let _guard = RUN_MUTEX.lock().unwrap();
let book = do_parse_book_default(code, path.display())?;
let book = do_parse_book_default(code, path)?;
let compile_opts = CompileOpts::default().set_all();
let diagnostics_cfg = DiagnosticsConfig::default();
let (term, _, diags) = run_book_simple(
@ -168,7 +168,7 @@ fn run_file() {
function_name!(),
&[(&|code, path| {
let _guard = RUN_MUTEX.lock().unwrap();
let book = do_parse_book_default(code, path.display())?;
let book = do_parse_book_default(code, path)?;
let diagnostics_cfg = DiagnosticsConfig {
unused_definition: Severity::Allow,
..DiagnosticsConfig::new(Severity::Error, true)
@ -199,7 +199,7 @@ fn import_system() {
..DiagnosticsConfig::new(Severity::Error, true)
};
let book = load_to_book(path.display(), code, DefaultLoader::new(path), diagnostics_cfg)?;
let book = load_to_book(path, code, DefaultLoader::new(path), diagnostics_cfg)?;
let run_opts = RunOpts::default();
let mut res = String::new();
@ -253,7 +253,7 @@ fn simplify_matches() {
irrefutable_match: Severity::Allow,
..DiagnosticsConfig::new(Severity::Error, true)
};
let mut book = do_parse_book_default(code, path.display())?;
let mut book = do_parse_book_default(code, path)?;
let mut ctx = Ctx::new(&mut book, diagnostics_cfg);
ctx.check_shared_names();
@ -286,7 +286,7 @@ fn simplify_matches() {
#[test]
fn parse_file() {
run_golden_test_dir(function_name!(), &|code, path| {
let mut book = do_parse_book_default(code, path.display())?;
let mut book = do_parse_book_default(code, path)?;
let mut ctx = Ctx::new(&mut book, Default::default());
ctx.set_entrypoint();
ctx.book.encode_adts(AdtEncoding::NumScott);
@ -304,7 +304,7 @@ fn encode_pattern_match() {
let mut result = String::new();
for adt_encoding in [AdtEncoding::Scott, AdtEncoding::NumScott] {
let diagnostics_cfg = DiagnosticsConfig::default();
let mut book = do_parse_book_default(code, path.display())?;
let mut book = do_parse_book_default(code, path)?;
let mut ctx = Ctx::new(&mut book, diagnostics_cfg);
ctx.check_shared_names();
ctx.set_entrypoint();
@ -345,7 +345,7 @@ fn desugar_file() {
unused_definition: Severity::Allow,
..DiagnosticsConfig::new(Severity::Error, true)
};
let mut book = do_parse_book_default(code, path.display())?;
let mut book = do_parse_book_default(code, path)?;
desugar_book(&mut book, compile_opts, diagnostics_cfg, None)?;
Ok(book.to_string())
})
@ -358,7 +358,7 @@ fn hangs() {
run_golden_test_dir(function_name!(), &move |code, path| {
let _guard = RUN_MUTEX.lock().unwrap();
let book = do_parse_book_default(code, path.display())?;
let book = do_parse_book_default(code, path)?;
let compile_opts = CompileOpts::default().set_all();
let diagnostics_cfg = DiagnosticsConfig::new(Severity::Allow, false);
@ -380,7 +380,7 @@ fn hangs() {
#[test]
fn compile_entrypoint() {
run_golden_test_dir(function_name!(), &|code, path| {
let mut book = do_parse_book_default(code, path.display())?;
let mut book = do_parse_book_default(code, path)?;
book.entrypoint = Some(Name::new("foo"));
let diagnostics_cfg = DiagnosticsConfig { ..DiagnosticsConfig::new(Severity::Error, true) };
let res = compile_book(&mut book, CompileOpts::default(), diagnostics_cfg, None)?;
@ -393,7 +393,7 @@ fn compile_entrypoint() {
fn run_entrypoint() {
run_golden_test_dir(function_name!(), &|code, path| {
let _guard = RUN_MUTEX.lock().unwrap();
let mut book = do_parse_book_default(code, path.display())?;
let mut book = do_parse_book_default(code, path)?;
book.entrypoint = Some(Name::new("foo"));
let compile_opts = CompileOpts::default().set_all();
let diagnostics_cfg = DiagnosticsConfig { ..DiagnosticsConfig::new(Severity::Error, true) };
@ -428,7 +428,7 @@ fn mutual_recursion() {
run_golden_test_dir(function_name!(), &|code, path| {
let diagnostics_cfg =
DiagnosticsConfig { recursion_cycle: Severity::Error, ..DiagnosticsConfig::new(Severity::Allow, true) };
let mut book = do_parse_book_default(code, path.display())?;
let mut book = do_parse_book_default(code, path)?;
let opts = CompileOpts { merge: true, ..CompileOpts::default() };
let res = compile_book(&mut book, opts, diagnostics_cfg, None)?;
Ok(format!("{}{}", res.diagnostics, hvm_book_show_pretty(&res.hvm_book)))
@ -455,7 +455,7 @@ fn io() {
}), */
(&|code, path| {
let _guard = RUN_MUTEX.lock().unwrap();
let book = do_parse_book_default(code, path.display())?;
let book = do_parse_book_default(code, path)?;
let compile_opts = CompileOpts::default();
let diagnostics_cfg = DiagnosticsConfig::default();
let (term, _, diags) =
@ -482,7 +482,7 @@ fn examples() -> Result<(), Diagnostics> {
eprintln!("Testing {}", path.display());
let code = std::fs::read_to_string(path).map_err(|e| e.to_string())?;
let book = do_parse_book_default(&code, path.display()).unwrap();
let book = do_parse_book_default(&code, path).unwrap();
let compile_opts = CompileOpts::default();
let diagnostics_cfg = DiagnosticsConfig::default();
let (term, _, diags) = run_book_simple(book, RunOpts::default(), compile_opts, diagnostics_cfg, None)?;
@ -504,7 +504,7 @@ fn examples() -> Result<(), Diagnostics> {
#[test]
fn scott_triggers_unused() {
run_golden_test_dir(function_name!(), &|code, path| {
let mut book = do_parse_book_default(code, path.display())?;
let mut book = do_parse_book_default(code, path)?;
let opts = CompileOpts::default();
let diagnostics_cfg =
DiagnosticsConfig { unused_definition: Severity::Error, ..DiagnosticsConfig::default() };
@ -517,7 +517,7 @@ fn scott_triggers_unused() {
#[test]
fn compile_long() {
run_golden_test_dir(function_name!(), &|code, path| {
let mut book = do_parse_book_default(code, path.display())?;
let mut book = do_parse_book_default(code, path)?;
let opts = CompileOpts::default().set_all();
let diagnostics_cfg = DiagnosticsConfig {
recursion_cycle: Severity::Warning,

View File

@ -0,0 +1,4 @@
import lib/import_entry
def main():
return *

View File

@ -0,0 +1,4 @@
import lib/import_entry2
def main():
return *

View File

@ -0,0 +1,4 @@
import lib/folder/import_entry3
def main():
return *

View File

@ -0,0 +1 @@
import ../../../../import_main3 # multiples ../ have no effect past the main file folder

View File

@ -0,0 +1 @@
import import_main

View File

@ -0,0 +1 @@
import ../import_main2

View File

@ -0,0 +1,6 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/import_system/import_main.bend
---
Errors:
Can not import the entry point of the program.

View File

@ -0,0 +1,6 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/import_system/import_main2.bend
---
Errors:
Can not import the entry point of the program.

View File

@ -0,0 +1,6 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/import_system/import_main3.bend
---
Errors:
Can not import the entry point of the program.