Fixed ownership issues in name resolver

This commit is contained in:
2022-06-02 04:27:01 +02:00
parent ec1734e113
commit 6ddbda8cd5
7 changed files with 133 additions and 34 deletions

View File

@@ -0,0 +1,5 @@
[[target]]
name = 'Dummy Project'
type = 'executable'
[target.dependencies]

View File

@@ -0,0 +1,18 @@
import std::io::(println, out) -- imports
-- single word substitution (alias)
greet = \name. printf out "Hello {}!\n" [name]
-- multi-word exported substitution
export (...$pre ;) $a ...$post) =200=> (...$pre (greet $a) ...$post)
-- single-word exported substitution
export main = (
print "What is your name? >>
readln >>= \name.
greet name
)
-- The broadest trait definition in existence
Foo = Bar Baz
default anyFoo = @T. @impl:(T (Bar Baz)). impl:(T Foo)

19
notes.md Normal file
View File

@@ -0,0 +1,19 @@
# Anatomy of a code file
```orchid
import std::io::(println, out) -- imports
-- single word substitution (alias)
greet = \name. printf out "Hello {}!\n" [name]
-- multi-word exported substitution
export (...$pre ;) $a ...$post) =200=> (...$pre (greet $a) ...$post)
-- single-word exported substitution
export main = (
print "What is your name? >>
readln >>= \name.
greet name
)
```

View File

@@ -12,5 +12,6 @@ pub use expression::expression_parser;
pub use sourcefile::FileEntry; pub use sourcefile::FileEntry;
pub use sourcefile::file_parser; pub use sourcefile::file_parser;
pub use sourcefile::imports; pub use sourcefile::imports;
pub use sourcefile::is_op;
pub use sourcefile::exported_names; pub use sourcefile::exported_names;
pub use import::Import; pub use import::Import;

View File

@@ -61,7 +61,7 @@ pub fn file_parser<'a>(
/// Decide if a string can be an operator. Operators can include digits and text, just not at the /// Decide if a string can be an operator. Operators can include digits and text, just not at the
/// start. /// start.
fn is_op(s: &str) -> bool { pub fn is_op(s: &str) -> bool {
return match s.chars().next() { return match s.chars().next() {
Some(x) => !x.is_alphanumeric(), Some(x) => !x.is_alphanumeric(),
None => false None => false
@@ -99,9 +99,12 @@ pub fn all_ops(src: &Vec<FileEntry>) -> Vec<&String> { defined_ops(src, false) }
pub fn exported_ops(src: &Vec<FileEntry>) -> Vec<&String> { defined_ops(src, true) } pub fn exported_ops(src: &Vec<FileEntry>) -> Vec<&String> { defined_ops(src, true) }
/// Summarize all imports from a file in a single list of qualified names /// Summarize all imports from a file in a single list of qualified names
pub fn imports(src: &Vec<FileEntry>) -> Vec<&import::Import> { pub fn imports<'a, 'b, I>(
src.into_iter().filter_map(|ent| match ent { src: I
) -> impl Iterator<Item = &'b import::Import> + 'a
where I: Iterator<Item = &'b FileEntry> + 'a {
src.filter_map(|ent| match ent {
FileEntry::Import(impv) => Some(impv.iter()), FileEntry::Import(impv) => Some(impv.iter()),
_ => None _ => None
}).flatten().collect() }).flatten()
} }

View File

@@ -1,4 +1,8 @@
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc;
use std::{iter, clone};
use chumsky::{Parser, prelude::Simple}; use chumsky::{Parser, prelude::Simple};
use thiserror::Error; use thiserror::Error;
@@ -36,8 +40,6 @@ impl ParseError {
} }
} }
// Loading a module: // Loading a module:
// 1. [X] Parse the imports // 1. [X] Parse the imports
// 2. [ ] Build a mapping of all imported symbols to full paths // 2. [ ] Build a mapping of all imported symbols to full paths
@@ -45,31 +47,74 @@ impl ParseError {
// 3. [ ] Parse everything using the full list of operators // 3. [ ] Parse everything using the full list of operators
// 4. [ ] Traverse and remap elements // 4. [ ] Traverse and remap elements
pub fn load_project<F>( type GetLoaded<'a> = dyn FnMut(&'a [&str]) -> &'a Option<Loaded>;
mut load_mod: F, prelude: &[&str], entry: &str type GetPreparsed<'a> = dyn FnMut(&'a [&str]) -> &'a Option<Vec<FileEntry>>;
pub fn load_project<'a, F>(
mut load_mod: F, prelude: &[&'a str], entry: &str
) -> Result<super::Project, ParseError> ) -> Result<super::Project, ParseError>
where F: FnMut(&[&str]) -> Option<Loaded> { where F: FnMut(&[&str]) -> Option<Loaded> {
// TODO: Welcome to Kamino!
let prelude_vec: Vec<String> = prelude.iter().map(|s| s.to_string()).collect();
let preparser = file_parser(prelude, &[]); let preparser = file_parser(prelude, &[]);
let mut loaded = Cache::new(|path: &[&str]| load_mod(path)); let loaded_cell = RefCell::new(Cache::new(|path: Vec<String>| {
let mut preparsed = Cache::new(|path: &[&str]| { load_mod(&path.iter().map(|s| s.as_str()).collect::<Vec<_>>())
loaded.get(path).as_ref().map(|loaded| match loaded { }));
let preparsed_cell = RefCell::new(Cache::new(|path: Vec<String>| {
let mut loaded = loaded_cell.borrow_mut();
loaded.by_clone(path).as_ref().map(|loaded| match loaded {
Loaded::Module(source) => Some(preparser.parse(source.as_str()).ok()?), Loaded::Module(source) => Some(preparser.parse(source.as_str()).ok()?),
_ => return None _ => return None
}).flatten() }).flatten()
}); }));
let exports = Cache::new(|path: &[&str]| loaded.get(path).map(|data| { let exports_cell = RefCell::new(Cache::new(|path: Vec<String>| {
match data { let mut loaded = loaded_cell.borrow_mut();
Loaded::Namespace(names) => Some(names), loaded.by_clone(path.clone()).as_ref().map(|data| {
Loaded::Module(source) => preparsed.get(path).map(|data| { let mut preparsed = preparsed_cell.borrow_mut();
exported_names(&data).into_iter().map(|n| n[0]).collect() match data {
}) Loaded::Namespace(names) => Some(names.clone()),
Loaded::Module(source) => preparsed.by_clone(path).as_ref().map(|data| {
parse::exported_names(&data).into_iter()
.map(|n| n[0].clone())
.collect()
}),
_ => None
}
}).flatten()
}));
let imports_cell = RefCell::new(Cache::new(|path: Vec<String>| {
let mut preparsed = preparsed_cell.borrow_mut();
let entv = preparsed.by_clone(path).clone()?;
let import_entries = parse::imports(entv.iter());
let mut imported_symbols: HashMap<String, Vec<String>> = HashMap::new();
for imp in import_entries {
let mut exports = exports_cell.borrow_mut();
let export = exports.by_clone(imp.path.clone()).as_ref()?;
if let Some(ref name) = imp.name {
if export.contains(&name) {
imported_symbols.insert(name.clone(), imp.path.clone());
}
} else {
for exp in export.clone() {
imported_symbols.insert(exp.clone(), imp.path.clone());
}
}
} }
}).flatten()); Some(imported_symbols)
let imports = Cache::new(|path: &[&str]| preparsed.get(path).map(|data| { }));
data.iter().filter_map(|ent| match ent { let parsed = RefCell::new(Cache::new(|path: Vec<String>| {
FileEntry::Import(imp) => Some(imp), let mut imports = imports_cell.borrow_mut();
_ => None let mut loaded = loaded_cell.borrow_mut();
}).flatten().collect::<Vec<_>>() let data = loaded.by_clone(path.clone()).as_ref()?;
let text = match data { Loaded::Module(s) => Some(s), _ => None }?;
let imported_symbols = imports.by_clone(path).as_ref()?;
let imported_ops: Vec<&str> = imported_symbols.keys()
.chain(prelude_vec.iter())
.map(|s| s.as_str())
.filter(|s| parse::is_op(s))
.collect();
let file_parser = file_parser(prelude, &imported_ops);
file_parser.parse(text.as_str()).ok()
})); }));
// let main = preparsed.get(&[entry]); // let main = preparsed.get(&[entry]);
// for imp in parse::imports(main) { // for imp in parse::imports(main) {
@@ -81,7 +126,6 @@ where F: FnMut(&[&str]) -> Option<Loaded> {
// modules: HashMap::new() // modules: HashMap::new()
// }; // };
// Some(project) // Some(project)
todo!("Finish this function") todo!("Finish this function")
} }

View File

@@ -1,23 +1,32 @@
use std::{collections::HashMap, hash::Hash}; use std::collections::HashMap;
use std::hash::Hash;
/// Cache the return values of an effectless closure in a hashmap /// Cache the return values of an effectless closure in a hashmap
/// Inspired by the closure_cacher crate. /// Inspired by the closure_cacher crate.
pub struct Cache<I, O, F> where F: FnMut(I) -> O { pub struct Cache<I, O, F> {
store: HashMap<I, O>, store: HashMap<I, O>,
closure: F closure: F
} }
impl<I, O, F> Cache<I, O, F> impl<I, O, F> Cache<I, O, F> where
where I: Eq + Hash,
F: FnMut(I) -> O, F: FnMut(I) -> O
I: Eq + Hash + Copy
{ {
pub fn new(closure: F) -> Self { Self { store: HashMap::new(), closure } } pub fn new(closure: F) -> Self {
pub fn get(&mut self, i: I) -> &O { Self { store: HashMap::new(), closure }
// I copied it because I might need `drop` and I prefer `I` to be unconstrained. }
pub fn by_copy(&mut self, i: I) -> &O where I: Copy {
let closure = &mut self.closure; let closure = &mut self.closure;
self.store.entry(i).or_insert_with(|| closure(i)) self.store.entry(i).or_insert_with(|| closure(i))
} }
pub fn by_clone(&mut self, i: I) -> &O where I: Clone {
let closure = &mut self.closure;
// Make sure we only clone if necessary
self.store.entry(i).or_insert_with_key(|k| closure(k.clone()))
}
pub fn known(&self, i: &I) -> Option<&O> {
self.store.get(i)
}
/// Forget the output for the given input /// Forget the output for the given input
pub fn drop(&mut self, i: &I) -> bool { pub fn drop(&mut self, i: &I) -> bool {
self.store.remove(i).is_some() self.store.remove(i).is_some()