Fixed ownership issues in name resolver
This commit is contained in:
5
examples/dummy_project/Orchid.toml
Normal file
5
examples/dummy_project/Orchid.toml
Normal file
@@ -0,0 +1,5 @@
|
||||
[[target]]
|
||||
name = 'Dummy Project'
|
||||
type = 'executable'
|
||||
|
||||
[target.dependencies]
|
||||
18
examples/dummy_project/main.orc
Normal file
18
examples/dummy_project/main.orc
Normal 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
19
notes.md
Normal 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
|
||||
)
|
||||
```
|
||||
|
||||
@@ -12,5 +12,6 @@ pub use expression::expression_parser;
|
||||
pub use sourcefile::FileEntry;
|
||||
pub use sourcefile::file_parser;
|
||||
pub use sourcefile::imports;
|
||||
pub use sourcefile::is_op;
|
||||
pub use sourcefile::exported_names;
|
||||
pub use import::Import;
|
||||
@@ -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
|
||||
/// start.
|
||||
fn is_op(s: &str) -> bool {
|
||||
pub fn is_op(s: &str) -> bool {
|
||||
return match s.chars().next() {
|
||||
Some(x) => !x.is_alphanumeric(),
|
||||
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) }
|
||||
|
||||
/// Summarize all imports from a file in a single list of qualified names
|
||||
pub fn imports(src: &Vec<FileEntry>) -> Vec<&import::Import> {
|
||||
src.into_iter().filter_map(|ent| match ent {
|
||||
pub fn imports<'a, 'b, I>(
|
||||
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()),
|
||||
_ => None
|
||||
}).flatten().collect()
|
||||
}).flatten()
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
use std::borrow::Borrow;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::{iter, clone};
|
||||
|
||||
use chumsky::{Parser, prelude::Simple};
|
||||
use thiserror::Error;
|
||||
@@ -36,8 +40,6 @@ impl ParseError {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Loading a module:
|
||||
// 1. [X] Parse the imports
|
||||
// 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
|
||||
// 4. [ ] Traverse and remap elements
|
||||
|
||||
pub fn load_project<F>(
|
||||
mut load_mod: F, prelude: &[&str], entry: &str
|
||||
type GetLoaded<'a> = dyn FnMut(&'a [&str]) -> &'a Option<Loaded>;
|
||||
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>
|
||||
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 mut loaded = Cache::new(|path: &[&str]| load_mod(path));
|
||||
let mut preparsed = Cache::new(|path: &[&str]| {
|
||||
loaded.get(path).as_ref().map(|loaded| match loaded {
|
||||
let loaded_cell = RefCell::new(Cache::new(|path: Vec<String>| {
|
||||
load_mod(&path.iter().map(|s| s.as_str()).collect::<Vec<_>>())
|
||||
}));
|
||||
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()?),
|
||||
_ => return None
|
||||
}).flatten()
|
||||
});
|
||||
let exports = Cache::new(|path: &[&str]| loaded.get(path).map(|data| {
|
||||
}));
|
||||
let exports_cell = RefCell::new(Cache::new(|path: Vec<String>| {
|
||||
let mut loaded = loaded_cell.borrow_mut();
|
||||
loaded.by_clone(path.clone()).as_ref().map(|data| {
|
||||
let mut preparsed = preparsed_cell.borrow_mut();
|
||||
match data {
|
||||
Loaded::Namespace(names) => Some(names),
|
||||
Loaded::Module(source) => preparsed.get(path).map(|data| {
|
||||
exported_names(&data).into_iter().map(|n| n[0]).collect()
|
||||
})
|
||||
}
|
||||
}).flatten());
|
||||
let imports = Cache::new(|path: &[&str]| preparsed.get(path).map(|data| {
|
||||
data.iter().filter_map(|ent| match ent {
|
||||
FileEntry::Import(imp) => Some(imp),
|
||||
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().collect::<Vec<_>>()
|
||||
}
|
||||
}).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());
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(imported_symbols)
|
||||
}));
|
||||
let parsed = RefCell::new(Cache::new(|path: Vec<String>| {
|
||||
let mut imports = imports_cell.borrow_mut();
|
||||
let mut loaded = loaded_cell.borrow_mut();
|
||||
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]);
|
||||
// for imp in parse::imports(main) {
|
||||
@@ -81,7 +126,6 @@ where F: FnMut(&[&str]) -> Option<Loaded> {
|
||||
// modules: HashMap::new()
|
||||
// };
|
||||
|
||||
|
||||
// Some(project)
|
||||
todo!("Finish this function")
|
||||
}
|
||||
@@ -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
|
||||
/// 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>,
|
||||
closure: F
|
||||
}
|
||||
|
||||
impl<I, O, F> Cache<I, O, F>
|
||||
where
|
||||
F: FnMut(I) -> O,
|
||||
I: Eq + Hash + Copy
|
||||
impl<I, O, F> Cache<I, O, F> where
|
||||
I: Eq + Hash,
|
||||
F: FnMut(I) -> O
|
||||
{
|
||||
pub fn new(closure: F) -> Self { Self { store: HashMap::new(), closure } }
|
||||
pub fn get(&mut self, i: I) -> &O {
|
||||
// I copied it because I might need `drop` and I prefer `I` to be unconstrained.
|
||||
pub fn new(closure: F) -> Self {
|
||||
Self { store: HashMap::new(), closure }
|
||||
}
|
||||
pub fn by_copy(&mut self, i: I) -> &O where I: Copy {
|
||||
let closure = &mut self.closure;
|
||||
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
|
||||
pub fn drop(&mut self, i: &I) -> bool {
|
||||
self.store.remove(i).is_some()
|
||||
|
||||
Reference in New Issue
Block a user