summaryrefslogtreecommitdiff
path: root/oryxc/src/compiler.rs
diff options
context:
space:
mode:
Diffstat (limited to 'oryxc/src/compiler.rs')
-rw-r--r--oryxc/src/compiler.rs190
1 files changed, 124 insertions, 66 deletions
diff --git a/oryxc/src/compiler.rs b/oryxc/src/compiler.rs
index 98947f6..3bfe6c1 100644
--- a/oryxc/src/compiler.rs
+++ b/oryxc/src/compiler.rs
@@ -34,10 +34,11 @@ use crate::arena::{
LocalArena,
};
use crate::errors::OryxError;
+use crate::hashtrie::HTrie;
use crate::intern::Interner;
use crate::lexer::Token;
use crate::parser::{
- AstNode,
+ Ast,
AstType,
};
use crate::prelude::*;
@@ -51,12 +52,11 @@ use crate::{
#[allow(dead_code)]
pub struct FileData {
- pub name: OsString,
- pub buffer: String,
- pub tokens: OnceLock<Soa<Token>>,
- pub ast: OnceLock<Soa<AstNode>>,
- pub extra_data: OnceLock<Vec<u32>>,
- pub symtab: DashMap<(ScopeId, SymbolId), Symbol>,
+ pub name: OsString,
+ pub buffer: String,
+ pub tokens: OnceLock<Soa<Token>>,
+ pub ast: OnceLock<Ast>,
+ pub scopes: OnceLock<HTrie<ScopeId, Scope>>,
}
impl FileData {
@@ -72,14 +72,13 @@ impl FileData {
fs::File::open(&name)?.read_to_string(&mut buffer)?;
buffer.push_str(unsafe { std::str::from_utf8_unchecked(&PAD) });
- Ok(Self {
+ return Ok(Self {
name,
buffer,
tokens: OnceLock::new(),
ast: OnceLock::new(),
- extra_data: OnceLock::new(),
- symtab: DashMap::new(),
- })
+ scopes: OnceLock::new(),
+ });
}
}
@@ -93,15 +92,15 @@ pub enum JobType {
file: FileId,
fdata: Arc<FileData>,
},
- FindSymbolsInScope {
- fdata: Arc<FileData>,
- scope: ScopeId,
- block: u32,
+ IndexScopeConstants {
+ fdata: Arc<FileData>,
+ block: u32,
+ parent: ScopeId,
},
ResolveDefBind {
fdata: Arc<FileData>,
- scope: ScopeId,
node: u32,
+ scope: ScopeId,
},
}
@@ -138,17 +137,34 @@ impl<'a> CompilerState<'a> {
}
}
+ /// Generate a new ID for a job, scope, etc.
+ #[inline(always)]
+ fn genid(&self) -> usize {
+ return self.next_id.fetch_add(1, Ordering::Relaxed);
+ }
+
+ /// Build a new job of type KIND.
+ #[inline(always)]
fn job_new(&self, kind: JobType) -> Job {
- let id = self.next_id.fetch_add(1, Ordering::Relaxed);
+ let id = self.genid();
return Job { id, kind };
}
- /// Push a job onto a worker's local queue and wake all threads.
+ /// Push a job onto a worker’s local queue and wake all threads.
+ #[inline(always)]
fn job_push(&self, queue: &Worker<Job>, job: Job) {
self.njobs.fetch_add(1, Ordering::Relaxed);
queue.push(job);
self.wake_all();
}
+
+ /// Signal a job completion by decrementing the job count.
+ ///
+ /// Returns the number of remaining jobs
+ #[inline(always)]
+ fn job_complete(&self) -> usize {
+ return self.njobs.fetch_sub(1, Ordering::Release) - 1;
+ }
}
/// Initialize compiler state and drive all source files through the
@@ -218,20 +234,38 @@ where
let workers = unsafe { workers.assume_init() };
let stealers = Arc::from(unsafe { stealers.assume_init() });
- let mut worker_threads = Box::new_uninit_slice(workers.len());
+ let mut ok = true;
thread::scope(|s| {
+ let mut handles = Box::new_uninit_slice(workers.len());
+ let mut worker_threads = Box::new_uninit_slice(handles.len());
+
for (i, w) in workers.into_iter().enumerate() {
let stealers = Arc::clone(&stealers);
let state = Arc::clone(&state);
let arena = LocalArena::new(&state.global_arena);
let handle = s.spawn(move || worker_loop(i, state, w, stealers));
worker_threads[i].write(handle.thread().clone());
+ handles[i].write(handle);
}
let _ = state
.worker_threads
.set(unsafe { worker_threads.assume_init() });
state.wake_all();
+
+ for h in handles {
+ match unsafe { h.assume_init() }.join() {
+ Ok(thrd_ok) => {
+ if !thrd_ok {
+ ok = false;
+ }
+ },
+ Err(_) => ok = false,
+ }
+ }
});
+ if !ok {
+ process::exit(1);
+ }
}
/// Steal and execute jobs until all work is complete.
@@ -240,7 +274,8 @@ fn worker_loop(
c_state: Arc<CompilerState>,
queue: Worker<Job>,
stealers: Arc<[Stealer<Job>]>,
-) {
+) -> bool {
+ let mut ok = true;
let arena = LocalArena::new(&c_state.global_arena);
loop {
@@ -250,19 +285,21 @@ fn worker_loop(
let n = c_state.njobs.load(Ordering::Acquire);
if n == 0 {
c_state.wake_all();
- return;
+ return ok;
}
thread::park();
continue;
};
- match job.kind {
- JobType::Lex { file, fdata } => {
- let tokens =
- lexer::tokenize(&fdata.buffer).unwrap_or_else(|e| {
+ let result = match job.kind {
+ JobType::Lex { file, fdata } => 'blk: {
+ let tokens = match lexer::tokenize(&fdata.buffer) {
+ Ok(xs) => xs,
+ Err(e) => {
emit_errors(&fdata, iter::once(e));
- process::exit(1)
- });
+ break 'blk false;
+ },
+ };
if c_state.flags.debug_lexer {
let mut handle = io::stderr().lock();
@@ -276,65 +313,66 @@ fn worker_loop(
&queue,
c_state.job_new(JobType::Parse { file, fdata }),
);
+ true
},
- JobType::Parse { file, fdata } => {
- let (ast, extra_data) = parser::parse(
- fdata.tokens.get().unwrap(),
- )
- .unwrap_or_else(|errs| {
- emit_errors(&fdata, errs);
- process::exit(1)
- });
+ JobType::Parse { file, fdata } => 'blk: {
+ let ast = match parser::parse(fdata.tokens.get().unwrap()) {
+ Ok(ast) => ast,
+ Err(errs) => {
+ emit_errors(&fdata, errs);
+ break 'blk false;
+ },
+ };
if c_state.flags.debug_parser {
let mut handle = io::stderr().lock();
- for n in ast.iter() {
+ for n in ast.nodes.iter() {
let _ = write!(handle, "{n:?}\n");
}
}
- let root = (ast.len() - 1) as u32;
+ let root = (ast.nodes.len() - 1) as u32;
fdata.ast.set(ast).unwrap();
- fdata.extra_data.set(extra_data).unwrap();
+ fdata.scopes.set(HTrie::new()).unwrap();
c_state.job_push(
&queue,
- c_state.job_new(JobType::FindSymbolsInScope {
+ c_state.job_new(JobType::IndexScopeConstants {
fdata,
- scope: ScopeId::GLOBAL,
block: root,
+ parent: ScopeId::INVALID,
}),
);
+ true
},
- JobType::FindSymbolsInScope {
+ JobType::IndexScopeConstants {
fdata,
- scope,
block,
+ parent,
} => {
let tokens = fdata.tokens.get().unwrap();
let ast = fdata.ast.get().unwrap();
- let extra_data = fdata.extra_data.get().unwrap();
- let SubNodes(beg, nstmts) = ast.sub()[block as usize];
+ let SubNodes(beg, nstmts) = ast.nodes.sub()[block as usize];
let mut errors = Vec::new();
+ let scope = Scope::new(parent);
+ /* First pass inserts all the symbols in this scope into the
+ * symbol table */
for i in beg..beg + nstmts {
- let multi_def_bind = extra_data[i as usize];
-
- if ast.kind()[multi_def_bind as usize]
- != AstType::MultiDefBind
+ let node = ast.extra[i as usize];
+ if ast.nodes.kind()[node as usize] != AstType::MultiDefBind
{
continue;
}
- let def_idents = ast.sub()[multi_def_bind as usize].0;
- let nidents = extra_data[def_idents as usize];
+ let identsbeg = ast.nodes.sub()[node as usize].0;
+ let nidents = ast.extra[identsbeg as usize];
for j in 0..nidents {
- let ident =
- extra_data[(def_idents + 1 + j * 2) as usize];
+ let ident = ast.extra[(identsbeg + 1 + j * 2) as usize];
let span = tokens.view()[ident as usize];
/* Make string slice lifetime 'static */
@@ -343,14 +381,16 @@ fn worker_loop(
};
let symid = c_state.interner.intern(view);
- let sym = Symbol::default();
+ let sym = Symbol {
+ state: ResolutionState::Unresolved,
+ kind: SymbolType::Constant,
+ };
if let Some(mut sym) =
- fdata.symtab.insert((scope, symid), sym)
+ scope.symtab.insert(symid, sym, &arena)
{
sym.state = ResolutionState::Poisoned;
- fdata.symtab.insert((scope, symid), sym);
-
+ scope.symtab.insert(symid, sym, &arena);
errors.push(OryxError::new(
span,
format!(
@@ -359,21 +399,44 @@ fn worker_loop(
));
}
}
+ }
+
+ let scopeid = if parent == ScopeId::INVALID {
+ ScopeId::GLOBAL
+ } else {
+ ScopeId(c_state.genid())
+ };
+ fdata.scopes.get().unwrap().insert(scopeid, scope, &arena);
+ /* Second pass emits jobs to resolve types */
+ for i in beg..beg + nstmts {
+ let node = ast.extra[i as usize];
+ if ast.nodes.kind()[node as usize] != AstType::MultiDefBind
+ {
+ continue;
+ }
c_state.job_push(
&queue,
c_state.job_new(JobType::ResolveDefBind {
fdata: fdata.clone(),
- scope,
- node: multi_def_bind,
+ node,
+ scope: scopeid,
}),
);
}
+ let ok = errors.is_empty();
emit_errors(&fdata, errors);
+ ok
},
- JobType::ResolveDefBind { fdata, scope, node } => {},
+ JobType::ResolveDefBind { fdata, node, scope } => {
+ todo!("resolving is yet to be implemented");
+ true
+ },
+ };
+ if !result {
+ ok = false;
}
if let Some((_, deps)) = c_state.deps.remove(&job.id) {
@@ -382,14 +445,9 @@ fn worker_loop(
}
}
- if c_state.njobs.fetch_sub(1, Ordering::Release) == 1 {
- // njobs is 0; wake all threads so they can observe the termination
- // condition and exit.
+ if c_state.job_complete() == 0 {
c_state.wake_all();
-
- // break here to avoid unnecessary steal attempts after work is
- // done.
- break;
+ return ok;
}
}
}