diff options
Diffstat (limited to 'oryxc')
| -rw-r--r-- | oryxc/src/arena.rs | 73 | ||||
| -rw-r--r-- | oryxc/src/compiler.rs | 190 | ||||
| -rw-r--r-- | oryxc/src/hashtrie.rs | 219 | ||||
| -rw-r--r-- | oryxc/src/lexer.rs | 9 | ||||
| -rw-r--r-- | oryxc/src/main.rs | 7 | ||||
| -rw-r--r-- | oryxc/src/parser.rs | 28 | ||||
| -rw-r--r-- | oryxc/src/prelude.rs | 36 |
7 files changed, 449 insertions, 113 deletions
diff --git a/oryxc/src/arena.rs b/oryxc/src/arena.rs index 2268c9b..34a48cb 100644 --- a/oryxc/src/arena.rs +++ b/oryxc/src/arena.rs @@ -31,10 +31,10 @@ pub struct GlobalArena { impl GlobalArena { pub fn new(blksz: usize) -> Self { - Self { + return Self { blksz, blocks: Mutex::new(Vec::new()), - } + }; } fn allocate_block(&self, layout: Layout) -> RawBlock { @@ -179,7 +179,7 @@ impl<'a> LocalArena<'a> { return unsafe { slice::from_raw_parts_mut(ptr, len) }; } - fn mark(&self) -> Mark { + pub fn mark(&self) -> Mark { return Mark { blk: self.curblk.get(), beg: self.beg.get(), @@ -187,7 +187,7 @@ impl<'a> LocalArena<'a> { }; } - fn restore(&self, mark: Mark) { + pub fn restore(&self, mark: Mark) { self.curblk.set(mark.blk); self.beg.set(mark.beg); self.end.set(mark.end); @@ -214,44 +214,47 @@ impl<'s, 'a> ScopedArena<'s, 'a> { return self.inner.alloc(value); } - pub fn alloc_slice<T>(&self, len: usize) -> &'a mut [T] { + pub fn alloc_slice<T>(&self, len: usize) -> &'s mut [T] { return self.inner.alloc_slice(len); } } -#[test] -fn test_alloc_slice() { - let arena_global = GlobalArena::new(8); - let arena_local_1 = LocalArena::new(&arena_global); - let arena_local_2 = LocalArena::new(&arena_global); - - let s1 = arena_local_1.alloc_slice(8); - let s2 = arena_local_2.alloc_slice(4); - assert_eq!(s1.len(), 8); - assert_eq!(s2.len(), 4); - - for i in 0..s1.len() { - s1[i] = i; - } - for i in 0..s2.len() { - s2[i] = i; +#[cfg(test)] +mod tests { + #[test] + fn test_alloc_slice() { + let arena_global = GlobalArena::new(8); + let arena_local_1 = LocalArena::new(&arena_global); + let arena_local_2 = LocalArena::new(&arena_global); + + let s1 = arena_local_1.alloc_slice(8); + let s2 = arena_local_2.alloc_slice(4); + assert_eq!(s1.len(), 8); + assert_eq!(s2.len(), 4); + + for i in 0..s1.len() { + s1[i] = i; + } + for i in 0..s2.len() { + s2[i] = i; + } } -} -#[test] -fn test_arena_grows() { - let arena_global = GlobalArena::new(8); - let arena_local = LocalArena::new(&arena_global); + #[test] + fn test_arena_grows() { + let arena_global = GlobalArena::new(8); + let arena_local = LocalArena::new(&arena_global); - let s1 = arena_local.alloc_slice(8); - let s2 = arena_local.alloc_slice(69); - assert_eq!(s1.len(), 8); - assert_eq!(s2.len(), 69); + let s1 = arena_local.alloc_slice(8); + let s2 = arena_local.alloc_slice(69); + assert_eq!(s1.len(), 8); + assert_eq!(s2.len(), 69); - for i in 0..s1.len() { - s1[i] = i; - } - for i in 0..s2.len() { - s2[i] = i; + for i in 0..s1.len() { + s1[i] = i; + } + for i in 0..s2.len() { + s2[i] = i; + } } } 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; } } } diff --git a/oryxc/src/hashtrie.rs b/oryxc/src/hashtrie.rs new file mode 100644 index 0000000..87c561e --- /dev/null +++ b/oryxc/src/hashtrie.rs @@ -0,0 +1,219 @@ +use std::hash::{ + Hash, + Hasher, +}; +use std::ptr; +use std::sync::atomic::{ + AtomicPtr, + Ordering, +}; + +use crate::arena::LocalArena; + +struct FNV1a { + state: u64, +} + +impl FNV1a { + const OFFSET_BASIS: u64 = 0xCBF29CE484222325; + const PRIME: u64 = 0x00000100000001B3; + + fn new() -> Self { + return Self { + state: Self::OFFSET_BASIS, + }; + } +} + +impl Hasher for FNV1a { + fn write(&mut self, bytes: &[u8]) { + for &b in bytes { + self.state ^= b as u64; + self.state = self.state.wrapping_mul(Self::PRIME); + } + } + + fn finish(&self) -> u64 { + return self.state; + } +} + +pub struct HTrieNode<K, V> +where + K: Copy + Eq + Hash, +{ + sub: [AtomicPtr<HTrieNode<K, V>>; 4], + key: K, + val: AtomicPtr<V>, +} + +impl<K, V> HTrieNode<K, V> +where + K: Copy + Eq + Hash, +{ + fn new(key: K, valptr: *mut V) -> Self { + return Self { + sub: [ + AtomicPtr::new(ptr::null_mut()), + AtomicPtr::new(ptr::null_mut()), + AtomicPtr::new(ptr::null_mut()), + AtomicPtr::new(ptr::null_mut()), + ], + key, + val: AtomicPtr::new(valptr), + }; + } +} + +#[derive(Debug)] +pub struct HTrie<K, V> +where + K: Copy + Eq + Hash, +{ + root: AtomicPtr<HTrieNode<K, V>>, +} + +impl<K, V> HTrie<K, V> +where + K: Copy + Eq + Hash, +{ + pub fn new() -> Self { + return Self { + root: AtomicPtr::new(ptr::null_mut()), + }; + } + + /// Lock-free insert into the hash-trie. + /// + /// Returns `None` if the key was newly inserted. + /// Returns `Some(val)` with the previous value if the key already + /// existed. + pub fn insert(&self, key: K, val: V, arena: &LocalArena) -> Option<V> { + let mut h = { + let mut h = FNV1a::new(); + key.hash(&mut h); + h.finish() + }; + + let mut m = &self.root; + let valptr = arena.alloc(val); + + loop { + let mut n = m.load(Ordering::Acquire); + + if n.is_null() { + let mark = arena.mark(); + let node = arena.alloc(HTrieNode::new(key, valptr)); + + match m.compare_exchange( + ptr::null_mut(), + node as *mut HTrieNode<K, V>, + Ordering::Release, + Ordering::Acquire, + ) { + Ok(_) => { + return None; + }, + Err(ptr) => { + arena.restore(mark); + n = ptr; + }, + } + } + + let n = unsafe { &*n }; + + if n.key == key { + let old_valptr = n.val.swap(valptr, Ordering::AcqRel); + + if old_valptr.is_null() { + return None; + } else { + let old_val = unsafe { ptr::read(old_valptr) }; + return Some(old_val); + } + } + + m = &n.sub[(h >> 62) as usize]; + h <<= 2; + } + } + + /// Check if the given key exists in the hash-trie. + pub fn contains(&self, key: K) -> bool { + let mut h = { + let mut h = FNV1a::new(); + key.hash(&mut h); + h.finish() + }; + + let mut m = &self.root; + + loop { + let n = m.load(Ordering::Acquire); + if n.is_null() { + return false; + } + let n = unsafe { &*n }; + if n.key == key { + return !n.val.load(Ordering::Acquire).is_null(); + } + m = &n.sub[(h >> 62) as usize]; + h <<= 2; + } + } +} + +#[cfg(test)] +mod tests { + use crate::arena::{ + GlobalArena, + LocalArena, + }; + use crate::hashtrie::HTrie; + + #[test] + fn test_htrie_insert() { + let ga = GlobalArena::new(128); + let la = LocalArena::new(&ga); + let ht = HTrie::new(); + + assert_eq!(ht.insert("foo", "bar", &la), None); + assert_eq!(ht.insert("hello", "sailor", &la), None); + assert_eq!(ht.insert("thomas", "voss", &la), None); + } + + #[test] + fn test_htrie_overwrite() { + let ga = GlobalArena::new(128); + let la = LocalArena::new(&ga); + let ht = HTrie::new(); + + ht.insert("foo", "bar", &la); + ht.insert("hello", "sailor", &la); + ht.insert("thomas", "voss", &la); + assert_eq!(ht.insert("foo", "bar-0", &la), Some("bar")); + assert_eq!(ht.insert("hello", "sailor-0", &la), Some("sailor")); + assert_eq!(ht.insert("thomas", "voss-0", &la), Some("voss")); + assert_eq!(ht.insert("foo", "bar-1", &la), Some("bar-0")); + assert_eq!(ht.insert("hello", "sailor-1", &la), Some("sailor-0")); + assert_eq!(ht.insert("thomas", "voss-1", &la), Some("voss-0")); + } + + #[test] + fn test_htrie_contains() { + let ga = GlobalArena::new(128); + let la = LocalArena::new(&ga); + let ht = HTrie::new(); + + assert!(!ht.contains("foo")); + assert!(!ht.contains("hello")); + assert!(!ht.contains("thomas")); + ht.insert("foo", "bar", &la); + ht.insert("hello", "sailor", &la); + ht.insert("thomas", "voss", &la); + assert!(ht.contains("foo")); + assert!(ht.contains("hello")); + assert!(ht.contains("thomas")); + } +} diff --git a/oryxc/src/lexer.rs b/oryxc/src/lexer.rs index 09e2881..2dace02 100644 --- a/oryxc/src/lexer.rs +++ b/oryxc/src/lexer.rs @@ -56,9 +56,11 @@ pub enum TokenType { Identifier, KeywordDef, KeywordFunc, + KeywordModule, KeywordReturn, Number, Percent2, + SlashPercent, String, } @@ -219,6 +221,13 @@ pub fn tokenize(s: &str) -> Result<Soa<Token>, OryxError> { view: (i, j + 1), }) }, + '/' if ctx.peek().is_some_and(|c| c == '%') => { + ctx.next(); /* Consume ‘/’ */ + Some(Token { + kind: TokenType::SlashPercent, + view: (i, j + 1), + }) + }, '!' | '&' | '(' | ')' | '*' | '+' | ',' | '-' | '/' | ';' | '<' | '=' | '>' | '[' | ']' | '^' | '{' | '|' | '}' | '~' | '…' | '%' => Some(Token { diff --git a/oryxc/src/main.rs b/oryxc/src/main.rs index 636b8ed..e3523bd 100644 --- a/oryxc/src/main.rs +++ b/oryxc/src/main.rs @@ -3,6 +3,7 @@ mod arena; mod compiler; mod errors; +mod hashtrie; mod intern; mod lexer; mod parser; @@ -29,10 +30,10 @@ pub struct Flags { #[derive(Parser)] struct Args { - #[arg(short = 'l', long)] + #[arg(long)] debug_lexer: bool, - #[arg(short = 'p', long)] + #[arg(long)] debug_parser: bool, #[arg(short = 's', long, default_value = "standard")] @@ -78,7 +79,7 @@ fn main() { fn usage() -> String { format!( concat!( - "Usage: {0} [-lp] [-s oneline|standard] [-t threads]\n", + "Usage: {0} [-s oneline|standard] [-t threads]\n", " {0} -h", ), errors::progname().display() diff --git a/oryxc/src/parser.rs b/oryxc/src/parser.rs index 89e2769..629b290 100644 --- a/oryxc/src/parser.rs +++ b/oryxc/src/parser.rs @@ -44,6 +44,12 @@ pub struct AstNode { pub sub: SubNodes, } +#[derive(Debug)] +pub struct Ast { + pub nodes: Soa<AstNode>, + pub extra: Vec<u32>, +} + struct Parser<'a> { ast: Soa<AstNode>, extra_data: Vec<u32>, @@ -536,6 +542,15 @@ impl<'a> Parser<'a> { self.next(); /* Consume ‘(’ */ return self.scratch_guard(|p| { let lhs = p.parse_decl_list()?; + if let Some(&ty) = p.scratch[lhs..].last() { + if ty == u32::MAX { + let i = p.scratch.len() as u32 - 2; + return Err(OryxError::new( + p.get_view_at(i), + "function parameter has no declared type", + )); + } + } if p.get_n_move() != TokenType::ParenR { /* TODO: Highlight the entire argument list */ @@ -568,7 +583,7 @@ impl<'a> Parser<'a> { _ => p.scratch.len(), }; - let nargs = rhs - lhs; + let nargs = (rhs - lhs) / 2; let nrets = p.scratch.len() - rhs; let argbeg = p.extra_data.len(); let retbeg = argbeg + nargs * 2 + 1; @@ -686,6 +701,7 @@ impl<'a> Parser<'a> { | TokenType::Asterisk | TokenType::Percent | TokenType::Percent2 + | TokenType::SlashPercent | TokenType::Slash => 5, TokenType::Bar | TokenType::Minus @@ -817,6 +833,7 @@ impl<'a> Parser<'a> { | TokenType::Percent2 | TokenType::Plus | TokenType::Slash + | TokenType::SlashPercent | TokenType::Tilde => { let i = self.cursor; self.next(); @@ -883,9 +900,7 @@ impl<'a> Parser<'a> { } } -pub fn parse( - tokens: &Soa<Token>, -) -> Result<(Soa<AstNode>, Vec<u32>), Vec<OryxError>> { +pub fn parse(tokens: &Soa<Token>) -> Result<Ast, Vec<OryxError>> { let mut p = Parser::new(tokens); while p.get() != TokenType::Eof { p.parse_toplevel(); @@ -902,5 +917,8 @@ pub fn parse( tok: 0, sub: SubNodes(stmtsbeg as u32, nstmts as u32), }); - return Ok((p.ast, p.extra_data)); + return Ok(Ast { + nodes: p.ast, + extra: p.extra_data, + }); } diff --git a/oryxc/src/prelude.rs b/oryxc/src/prelude.rs index 32a123f..4e36f33 100644 --- a/oryxc/src/prelude.rs +++ b/oryxc/src/prelude.rs @@ -4,6 +4,8 @@ use std::fmt::{ Formatter, }; +use crate::hashtrie::HTrie; + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct FileId(pub usize); @@ -11,14 +13,32 @@ pub struct FileId(pub usize); #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct SymbolId(pub u32); +#[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct ScopeId(pub usize); impl ScopeId { pub const GLOBAL: Self = Self(0); + pub const INVALID: Self = Self(usize::MAX); } -#[derive(Default)] +#[derive(Debug)] +pub struct Scope { + pub parent: ScopeId, + pub symtab: HTrie<SymbolId, Symbol>, +} + +impl Scope { + pub fn new(parent: ScopeId) -> Self { + return Self { + parent, + symtab: HTrie::new(), + }; + } +} + +#[repr(u8)] +#[derive(Debug, Default)] pub enum ResolutionState { #[default] Unresolved, @@ -27,14 +47,22 @@ pub enum ResolutionState { Poisoned, } -#[derive(Default)] +#[derive(Debug)] pub struct Symbol { - pub state: ResolutionState, - pub r#type: u32, + pub state: ResolutionState, + pub kind: SymbolType, +} + +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum SymbolType { + Constant, + FuncParam, } pub enum OryxType { Integer { bits: usize, signed: bool }, + Boolean, Pointer { base: u32 }, Function { args: Vec<u32>, rets: Vec<u32> }, } |