conlang: Use interned strings (Sym) for all symbols

This commit is contained in:
John 2024-04-24 19:34:29 -05:00
parent ede00c3c86
commit 40ec9b30e4
19 changed files with 198 additions and 195 deletions

View File

@ -11,6 +11,8 @@
//! - [Path]: Path expressions //! - [Path]: Path expressions
use cl_structures::span::*; use cl_structures::span::*;
pub use cl_structures::arena::global_intern::Sym;
/// Whether a binding ([Static] or [Let]) or reference is mutable or not /// Whether a binding ([Static] or [Let]) or reference is mutable or not
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum Mutability { pub enum Mutability {
@ -30,7 +32,7 @@ pub enum Visibility {
// TODO: Capture token? // TODO: Capture token?
/// A name /// A name
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Identifier(pub String); pub struct Identifier(pub Sym);
/// A [Literal]: 0x42, 1e123, 2.4, "Hello" /// A [Literal]: 0x42, 1e123, 2.4, "Hello"
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]

View File

@ -6,6 +6,7 @@ use super::{
temp_type_impl::ConValue, temp_type_impl::ConValue,
BuiltIn, Callable, BuiltIn, Callable,
}; };
use cl_ast::Sym;
use std::{ use std::{
io::{stdout, Write}, io::{stdout, Write},
rc::Rc, rc::Rc,
@ -68,7 +69,7 @@ builtins! {
Ok(match (lhs, rhs) { Ok(match (lhs, rhs) {
(ConValue::Empty, ConValue::Empty) => ConValue::Empty, (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b), (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b),
(ConValue::String(a), ConValue::String(b)) => (a.to_string() + b).into(), (ConValue::String(a), ConValue::String(b)) => (a.to_string() + &b.to_string()).into(),
_ => Err(Error::TypeError)? _ => Err(Error::TypeError)?
}) })
} }
@ -230,7 +231,7 @@ macro builtins (
$(let [$($arg),*] = to_args(args)?;)? $(let [$($arg),*] = to_args(args)?;)?
$body $body
} }
fn name(&self) -> &str { stringify!($name) } fn name(&self) -> Sym { stringify!($name).into() }
} }
)* )*
} }
@ -242,7 +243,7 @@ macro cmp ($a:expr, $b:expr, $empty:literal, $op:tt) {
(ConValue::Int(a), ConValue::Int(b)) => Ok(ConValue::Bool(a $op b)), (ConValue::Int(a), ConValue::Int(b)) => Ok(ConValue::Bool(a $op b)),
(ConValue::Bool(a), ConValue::Bool(b)) => Ok(ConValue::Bool(a $op b)), (ConValue::Bool(a), ConValue::Bool(b)) => Ok(ConValue::Bool(a $op b)),
(ConValue::Char(a), ConValue::Char(b)) => Ok(ConValue::Bool(a $op b)), (ConValue::Char(a), ConValue::Char(b)) => Ok(ConValue::Bool(a $op b)),
(ConValue::String(a), ConValue::String(b)) => Ok(ConValue::Bool(a $op b)), (ConValue::String(a), ConValue::String(b)) => Ok(ConValue::Bool(a.get() $op b.get())),
_ => Err(Error::TypeError) _ => Err(Error::TypeError)
} }
} }

View File

@ -112,7 +112,7 @@ impl Interpret for Let {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Let { mutable: _, name: Identifier(name), ty: _, init } = self; let Let { mutable: _, name: Identifier(name), ty: _, init } = self;
let init = init.as_ref().map(|i| i.interpret(env)).transpose()?; let init = init.as_ref().map(|i| i.interpret(env)).transpose()?;
env.insert(name, init); env.insert(*name, init);
Ok(ConValue::Empty) Ok(ConValue::Empty)
} }
} }
@ -172,7 +172,7 @@ impl Interpret for Assign {
}; };
// Get the initializer and the tail // Get the initializer and the tail
let init = tail.interpret(env)?; let init = tail.interpret(env)?;
let target = env.get_mut(head)?; let target = env.get_mut(*head)?;
if let AssignKind::Plain = op { if let AssignKind::Plain = op {
use std::mem::discriminant as variant; use std::mem::discriminant as variant;
@ -187,7 +187,7 @@ impl Interpret for Assign {
return Ok(ConValue::Empty); return Ok(ConValue::Empty);
} }
let Some(target) = target else { let Some(target) = target else {
return Err(Error::NotInitialized(head.into())); return Err(Error::NotInitialized(*head));
}; };
match op { match op {
@ -302,9 +302,9 @@ impl Interpret for Unary {
let Unary { kind, tail } = self; let Unary { kind, tail } = self;
let operand = tail.interpret(env)?; let operand = tail.interpret(env)?;
match kind { match kind {
UnaryKind::Deref => env.call("deref", &[operand]), UnaryKind::Deref => env.call("deref".into(), &[operand]),
UnaryKind::Neg => env.call("neg", &[operand]), UnaryKind::Neg => env.call("neg".into(), &[operand]),
UnaryKind::Not => env.call("not", &[operand]), UnaryKind::Not => env.call("not".into(), &[operand]),
UnaryKind::At => { UnaryKind::At => {
println!("{operand}"); println!("{operand}");
Ok(operand) Ok(operand)
@ -335,7 +335,7 @@ impl Interpret for Path {
if parts.len() == 1 { if parts.len() == 1 {
match parts.last().expect("parts should not be empty") { match parts.last().expect("parts should not be empty") {
PathPart::SuperKw | PathPart::SelfKw => todo!("Path navigation"), PathPart::SuperKw | PathPart::SelfKw => todo!("Path navigation"),
PathPart::Ident(Identifier(s)) => env.get(s), PathPart::Ident(Identifier(name)) => env.get(*name),
} }
} else { } else {
todo!("Path navigation!") todo!("Path navigation!")
@ -469,7 +469,7 @@ impl Interpret for For {
loop { loop {
let mut env = env.frame("loop variable"); let mut env = env.frame("loop variable");
if let Some(loop_var) = bounds.next() { if let Some(loop_var) = bounds.next() {
env.insert(name, Some(loop_var.into())); env.insert(*name, Some(loop_var.into()));
match pass.interpret(&mut env) { match pass.interpret(&mut env) {
Err(Error::Break(value)) => return Ok(value), Err(Error::Break(value)) => return Ok(value),
Err(Error::Continue) => continue, Err(Error::Continue) => continue,

View File

@ -2,6 +2,7 @@
#![warn(clippy::all)] #![warn(clippy::all)]
#![feature(decl_macro)] #![feature(decl_macro)]
use cl_ast::Sym;
use env::Environment; use env::Environment;
use error::{Error, IResult}; use error::{Error, IResult};
use interpret::Interpret; use interpret::Interpret;
@ -13,7 +14,7 @@ pub trait Callable: std::fmt::Debug {
/// The Callable is responsible for checking the argument count and validating types /// The Callable is responsible for checking the argument count and validating types
fn call(&self, interpreter: &mut Environment, args: &[ConValue]) -> IResult<ConValue>; fn call(&self, interpreter: &mut Environment, args: &[ConValue]) -> IResult<ConValue>;
/// Returns the common name of this identifier. /// Returns the common name of this identifier.
fn name(&self) -> &str; fn name(&self) -> Sym;
} }
/// [BuiltIn]s are [Callable]s with bespoke definitions /// [BuiltIn]s are [Callable]s with bespoke definitions
@ -25,6 +26,8 @@ pub mod temp_type_impl {
//! Temporary implementations of Conlang values //! Temporary implementations of Conlang values
//! //!
//! The most permanent fix is a temporary one. //! The most permanent fix is a temporary one.
use cl_ast::Sym;
use super::{ use super::{
error::{Error, IResult}, error::{Error, IResult},
function::Function, function::Function,
@ -50,7 +53,7 @@ pub mod temp_type_impl {
/// A unicode character /// A unicode character
Char(char), Char(char),
/// A string /// A string
String(Rc<str>), String(Sym),
/// A reference /// A reference
Ref(Rc<ConValue>), Ref(Rc<ConValue>),
/// An Array /// An Array
@ -120,11 +123,11 @@ pub mod temp_type_impl {
} }
impl Callable for ConValue { impl Callable for ConValue {
fn name(&self) -> &str { fn name(&self) -> Sym {
match self { match self {
ConValue::Function(func) => func.name(), ConValue::Function(func) => func.name(),
ConValue::BuiltIn(func) => func.name(), ConValue::BuiltIn(func) => func.name(),
_ => "", _ => "".into(),
} }
} }
fn call(&self, interpreter: &mut Environment, args: &[ConValue]) -> IResult<ConValue> { fn call(&self, interpreter: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
@ -145,7 +148,7 @@ pub mod temp_type_impl {
(Self::Int(a), Self::Int(b)) => Ok(Self::Bool(a $op b)), (Self::Int(a), Self::Int(b)) => Ok(Self::Bool(a $op b)),
(Self::Bool(a), Self::Bool(b)) => Ok(Self::Bool(a $op b)), (Self::Bool(a), Self::Bool(b)) => Ok(Self::Bool(a $op b)),
(Self::Char(a), Self::Char(b)) => Ok(Self::Bool(a $op b)), (Self::Char(a), Self::Char(b)) => Ok(Self::Bool(a $op b)),
(Self::String(a), Self::String(b)) => Ok(Self::Bool(a $op b)), (Self::String(a), Self::String(b)) => Ok(Self::Bool(a.get() $op b.get())),
_ => Err(Error::TypeError) _ => Err(Error::TypeError)
} }
} }
@ -162,10 +165,16 @@ pub mod temp_type_impl {
fn from(value: $T) -> Self { $v(value.into()) } fn from(value: $T) -> Self { $v(value.into()) }
})* })*
} }
impl From<&Sym> for ConValue {
fn from(value: &Sym) -> Self {
ConValue::String(*value)
}
}
from! { from! {
Integer => ConValue::Int, Integer => ConValue::Int,
bool => ConValue::Bool, bool => ConValue::Bool,
char => ConValue::Char, char => ConValue::Char,
Sym => ConValue::String,
&str => ConValue::String, &str => ConValue::String,
String => ConValue::String, String => ConValue::String,
Rc<str> => ConValue::String, Rc<str> => ConValue::String,
@ -202,7 +211,7 @@ pub mod temp_type_impl {
Add: add = [ Add: add = [
(ConValue::Empty, ConValue::Empty) => ConValue::Empty, (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b), (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b),
(ConValue::String(a), ConValue::String(b)) => (a.to_string() + &b).into(), (ConValue::String(a), ConValue::String(b)) => (a.to_string() + &b.to_string()).into(),
_ => Err(Error::TypeError)? _ => Err(Error::TypeError)?
] ]
BitAnd: bitand = [ BitAnd: bitand = [
@ -302,7 +311,7 @@ pub mod function {
//! Represents a block of code which lives inside the Interpreter //! Represents a block of code which lives inside the Interpreter
use super::{Callable, ConValue, Environment, Error, IResult, Interpret}; use super::{Callable, ConValue, Environment, Error, IResult, Interpret};
use cl_ast::{Function as FnDecl, Identifier, Param}; use cl_ast::{Function as FnDecl, Identifier, Param, Sym};
use std::rc::Rc; use std::rc::Rc;
/// Represents a block of code which persists inside the Interpreter /// Represents a block of code which persists inside the Interpreter
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -323,8 +332,8 @@ pub mod function {
} }
impl Callable for Function { impl Callable for Function {
fn name(&self) -> &str { fn name(&self) -> Sym {
let FnDecl { name: Identifier(ref name), .. } = *self.decl; let FnDecl { name: Identifier(name), .. } = *self.decl;
name name
} }
fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> { fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
@ -334,12 +343,12 @@ pub mod function {
return Err(Error::ArgNumber { want: bind.len(), got: args.len() }); return Err(Error::ArgNumber { want: bind.len(), got: args.len() });
} }
let Some(body) = body else { let Some(body) = body else {
return Err(Error::NotDefined(name.into())); return Err(Error::NotDefined(*name));
}; };
// TODO: completely refactor data storage // TODO: completely refactor data storage
let mut frame = env.frame("fn args"); let mut frame = env.frame("fn args");
for (Param { mutability: _, name: Identifier(name) }, value) in bind.iter().zip(args) { for (Param { mutability: _, name: Identifier(name) }, value) in bind.iter().zip(args) {
frame.insert(name, Some(value.clone())); frame.insert(*name, Some(value.clone()));
} }
match body.interpret(&mut frame) { match body.interpret(&mut frame) {
Err(Error::Return(value)) => Ok(value), Err(Error::Return(value)) => Ok(value),
@ -361,14 +370,14 @@ pub mod env {
temp_type_impl::ConValue, temp_type_impl::ConValue,
BuiltIn, Callable, Interpret, BuiltIn, Callable, Interpret,
}; };
use cl_ast::{Function as FnDecl, Identifier}; use cl_ast::{Function as FnDecl, Identifier, Sym};
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::Display, fmt::Display,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
}; };
type StackFrame = HashMap<String, Option<ConValue>>; type StackFrame = HashMap<Sym, Option<ConValue>>;
/// Implements a nested lexical scope /// Implements a nested lexical scope
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -404,10 +413,8 @@ pub mod env {
} }
} }
} }
fn to_hashmap(from: &[&'static dyn BuiltIn]) -> HashMap<String, Option<ConValue>> { fn to_hashmap(from: &[&'static dyn BuiltIn]) -> HashMap<Sym, Option<ConValue>> {
from.iter() from.iter().map(|&v| (v.name(), Some(v.into()))).collect()
.map(|&v| (v.name().into(), Some(v.into())))
.collect()
} }
impl Environment { impl Environment {
@ -425,7 +432,7 @@ pub mod env {
/// Calls a function inside the interpreter's scope, /// Calls a function inside the interpreter's scope,
/// and returns the result /// and returns the result
pub fn call(&mut self, name: &str, args: &[ConValue]) -> IResult<ConValue> { pub fn call(&mut self, name: Sym, args: &[ConValue]) -> IResult<ConValue> {
// FIXME: Clone to satisfy the borrow checker // FIXME: Clone to satisfy the borrow checker
let function = self.get(name)?.clone(); let function = self.get(name)?.clone();
function.call(self, args) function.call(self, args)
@ -439,39 +446,39 @@ pub mod env {
/// Resolves a variable mutably. /// Resolves a variable mutably.
/// ///
/// Returns a mutable reference to the variable's record, if it exists. /// Returns a mutable reference to the variable's record, if it exists.
pub fn get_mut(&mut self, id: &str) -> IResult<&mut Option<ConValue>> { pub fn get_mut(&mut self, id: Sym) -> IResult<&mut Option<ConValue>> {
for (frame, _) in self.frames.iter_mut().rev() { for (frame, _) in self.frames.iter_mut().rev() {
if let Some(var) = frame.get_mut(id) { if let Some(var) = frame.get_mut(&id) {
return Ok(var); return Ok(var);
} }
} }
Err(Error::NotDefined(id.into())) Err(Error::NotDefined(id))
} }
/// Resolves a variable immutably. /// Resolves a variable immutably.
/// ///
/// Returns a reference to the variable's contents, if it is defined and initialized. /// Returns a reference to the variable's contents, if it is defined and initialized.
pub fn get(&self, id: &str) -> IResult<ConValue> { pub fn get(&self, id: Sym) -> IResult<ConValue> {
for (frame, _) in self.frames.iter().rev() { for (frame, _) in self.frames.iter().rev() {
match frame.get(id) { match frame.get(&id) {
Some(Some(var)) => return Ok(var.clone()), Some(Some(var)) => return Ok(var.clone()),
Some(None) => return Err(Error::NotInitialized(id.into())), Some(None) => return Err(Error::NotInitialized(id)),
_ => (), _ => (),
} }
} }
Err(Error::NotDefined(id.into())) Err(Error::NotDefined(id))
} }
/// Inserts a new [ConValue] into this [Environment] /// Inserts a new [ConValue] into this [Environment]
pub fn insert(&mut self, id: &str, value: Option<ConValue>) { pub fn insert(&mut self, id: Sym, value: Option<ConValue>) {
if let Some((frame, _)) = self.frames.last_mut() { if let Some((frame, _)) = self.frames.last_mut() {
frame.insert(id.into(), value); frame.insert(id, value);
} }
} }
/// A convenience function for registering a [FnDecl] as a [Function] /// A convenience function for registering a [FnDecl] as a [Function]
pub fn insert_fn(&mut self, decl: &FnDecl) { pub fn insert_fn(&mut self, decl: &FnDecl) {
let FnDecl { name: Identifier(name), .. } = decl; let FnDecl { name: Identifier(name), .. } = decl;
let (name, function) = (name.clone(), Some(Function::new(decl).into())); let (name, function) = (name, Some(Function::new(decl).into()));
if let Some((frame, _)) = self.frames.last_mut() { if let Some((frame, _)) = self.frames.last_mut() {
frame.insert(name, function); frame.insert(*name, function);
} }
} }
} }
@ -525,6 +532,8 @@ pub mod env {
pub mod error { pub mod error {
//! The [Error] type represents any error thrown by the [Environment](super::Environment) //! The [Error] type represents any error thrown by the [Environment](super::Environment)
use cl_ast::Sym;
use super::temp_type_impl::ConValue; use super::temp_type_impl::ConValue;
pub type IResult<T> = Result<T, Error>; pub type IResult<T> = Result<T, Error>;
@ -556,9 +565,9 @@ pub mod error {
/// An expression is not assignable /// An expression is not assignable
NotAssignable, NotAssignable,
/// A name was not defined in scope before being used /// A name was not defined in scope before being used
NotDefined(String), NotDefined(Sym),
/// A name was defined but not initialized /// A name was defined but not initialized
NotInitialized(String), NotInitialized(Sym),
/// A value was called, but is not callable /// A value was called, but is not callable
NotCallable(ConValue), NotCallable(ConValue),
/// A function was called with the wrong number of arguments /// A function was called with the wrong number of arguments

View File

@ -127,7 +127,7 @@ mod macros {
} }
pub macro env_ne($env:ident.$var:ident, $expr:expr) {{ pub macro env_ne($env:ident.$var:ident, $expr:expr) {{
let evaluated = $env.get(stringify!($var)) let evaluated = $env.get(stringify!($var).into())
.expect(stringify!($var should be defined and initialized)); .expect(stringify!($var should be defined and initialized));
if !conv_cmp!(neq, evaluated, $expr) { if !conv_cmp!(neq, evaluated, $expr) {
panic!("assertion {} ({evaluated}) != {} failed.", stringify!($var), stringify!($expr)) panic!("assertion {} ({evaluated}) != {} failed.", stringify!($var), stringify!($expr))
@ -135,7 +135,7 @@ mod macros {
}} }}
pub macro env_eq($env:ident.$var:ident, $expr:expr) {{ pub macro env_eq($env:ident.$var:ident, $expr:expr) {{
let evaluated = $env.get(stringify!($var)) let evaluated = $env.get(stringify!($var).into())
.expect(stringify!($var should be defined and initialized)); .expect(stringify!($var should be defined and initialized));
if !conv_cmp!(eq, evaluated, $expr) { if !conv_cmp!(eq, evaluated, $expr) {
panic!("assertion {} ({evaluated}) == {} failed.", stringify!($var), stringify!($expr)) panic!("assertion {} ({evaluated}) == {} failed.", stringify!($var), stringify!($expr))
@ -190,7 +190,7 @@ mod fn_declarations {
"fn empty_fn () {\n \n}", "fn empty_fn () {\n \n}",
format!( format!(
"{}", "{}",
env.get("empty_fn") env.get("empty_fn".into())
.expect(stringify!(empty_fn should be defined and initialized)) .expect(stringify!(empty_fn should be defined and initialized))
) )
) )

View File

@ -64,7 +64,8 @@ impl Fold for ModuleInliner {
/// Traverses down the module tree, entering ever nested directories /// Traverses down the module tree, entering ever nested directories
fn fold_module(&mut self, m: Module) -> Module { fn fold_module(&mut self, m: Module) -> Module {
let Module { name, kind } = m; let Module { name, kind } = m;
self.path.push(&name.0); // cd ./name let sym = name.0.get().expect("Could not get name!");
self.path.push(sym); // cd ./name
let kind = self.fold_module_kind(kind); let kind = self.fold_module_kind(kind);

View File

@ -471,7 +471,7 @@ pub mod yamlify {
} }
impl Yamlify for Fielder { impl Yamlify for Fielder {
fn yaml(&self, y: &mut Yamler) { fn yaml(&self, y: &mut Yamler) {
let Self { name: Identifier(name), init } = self; let Self { name, init } = self;
y.key("Fielder").pair("name", name).pair("init", init); y.key("Fielder").pair("name", name).pair("init", init);
} }
} }

View File

@ -45,10 +45,7 @@ pub fn run(args: Args) -> Result<(), Box<dyn Error>> {
Ok(()) Ok(())
} }
fn load_file( fn load_file(env: &mut Environment, path: impl AsRef<Path>) -> Result<ConValue, Box<dyn Error>> {
env: &mut Environment,
path: impl AsRef<Path>,
) -> Result<ConValue, Box<dyn Error>> {
let file = std::fs::read_to_string(path)?; let file = std::fs::read_to_string(path)?;
let code = Parser::new(Lexer::new(&file)).file()?; let code = Parser::new(Lexer::new(&file)).file()?;
Ok(env.eval(&code)?) Ok(env.eval(&code)?)
@ -79,8 +76,8 @@ fn run_code(code: &str, env: &mut Environment) -> Result<(), Box<dyn Error>> {
ConValue::Empty => {} ConValue::Empty => {}
ret => println!("{ret}"), ret => println!("{ret}"),
} }
if env.get("main").is_ok() { if env.get("main".into()).is_ok() {
match env.call("main", &[])? { match env.call("main".into(), &[])? {
ConValue::Empty => {} ConValue::Empty => {}
ret => println!("{ret}"), ret => println!("{ret}"),
} }

View File

@ -1,4 +1,4 @@
//! A global intern pool for strings, represented by the [GlobalSym] symbol //! A global intern pool for strings, represented by the [Sym] symbol
use super::{intern::Interner, symbol::Symbol}; use super::{intern::Interner, symbol::Symbol};
use std::{ use std::{
@ -7,19 +7,19 @@ use std::{
sync::{OnceLock, RwLock}, sync::{OnceLock, RwLock},
}; };
/// Holds a globally accessible [Interner] which uses [GlobalSym] as its [Symbol] /// Holds a globally accessible [Interner] which uses [Sym] as its [Symbol]
static GLOBAL_INTERNER: OnceLock<RwLock<Interner<GlobalSym>>> = OnceLock::new(); static GLOBAL_INTERNER: OnceLock<RwLock<Interner<Sym>>> = OnceLock::new();
/// A unique identifier corresponding to a particular interned [String]. /// A unique identifier corresponding to a particular globally-interned [String].
/// ///
/// Copies of that string can be obtained with [GlobalSym::get] or [String::try_from]. /// Copies of that string can be obtained with [Sym::get] or [String::try_from].
/// ///
/// New strings can be interned with [GlobalSym::new] or [GlobalSym::from] /// New strings can be interned with [Sym::new] or [Sym::from]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct GlobalSym(NonZeroU32); pub struct Sym(NonZeroU32);
impl GlobalSym { impl Sym {
/// Gets the interned [GlobalSym] for the given value, or interns a new one. /// Gets the interned [Sym] for the given value, or interns a new one.
/// ///
/// # Blocks /// # Blocks
/// This conversion blocks if the Global Interner lock is held. /// This conversion blocks if the Global Interner lock is held.
@ -33,25 +33,25 @@ impl GlobalSym {
.expect("global interner should not be poisoned in another thread") .expect("global interner should not be poisoned in another thread")
.get_or_insert(value) .get_or_insert(value)
} }
/// Gets a [GlobalSym] associated with the given string, if one already exists /// Gets a [Sym] associated with the given string, if one already exists
pub fn try_from_str(value: &str) -> Option<Self> { pub fn try_from_str(value: &str) -> Option<Self> {
GLOBAL_INTERNER.get()?.read().ok()?.get(value) GLOBAL_INTERNER.get()?.read().ok()?.get(value)
} }
/// Gets a copy of the value of the [GlobalSym] /// Gets a copy of the value of the [Sym]
// TODO: Make this copy-less // TODO: Make this copy-less
pub fn get(self) -> Option<String> { pub fn get(self) -> Option<String> {
String::try_from(self).ok() String::try_from(self).ok()
} }
/// Looks up the string associated with this [GlobalSym], /// Looks up the string associated with this [Sym],
/// and performs a transformation on it if it exists. /// and performs a transformation on it if it exists.
pub fn map<T>(&self, f: impl Fn(&str) -> T) -> Option<T> { pub fn map<T>(&self, f: impl Fn(&str) -> T) -> Option<T> {
Some(f(GLOBAL_INTERNER.get()?.read().ok()?.get_str(*self)?)) Some(f(GLOBAL_INTERNER.get()?.read().ok()?.get_str(*self)?))
} }
} }
impl Display for GlobalSym { impl Display for Sym {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Some(interner) = GLOBAL_INTERNER.get() else { let Some(interner) = GLOBAL_INTERNER.get() else {
return write!(f, "[sym@{} (uninitialized)]", self.0); return write!(f, "[sym@{} (uninitialized)]", self.0);
@ -66,7 +66,7 @@ impl Display for GlobalSym {
} }
} }
impl Symbol for GlobalSym { impl Symbol for Sym {
const MAX: usize = u32::MAX as usize - 1; const MAX: usize = u32::MAX as usize - 1;
fn try_from_usize(value: usize) -> Option<Self> { fn try_from_usize(value: usize) -> Option<Self> {
Some(Self(NonZeroU32::try_from_usize(value)?)) Some(Self(NonZeroU32::try_from_usize(value)?))
@ -76,7 +76,7 @@ impl Symbol for GlobalSym {
} }
} }
impl<T: AsRef<str>> From<T> for GlobalSym { impl<T: AsRef<str>> From<T> for Sym {
/// Converts to this type from the input type. /// Converts to this type from the input type.
/// ///
/// # Blocks /// # Blocks
@ -89,36 +89,37 @@ impl<T: AsRef<str>> From<T> for GlobalSym {
} }
} }
impl TryFrom<GlobalSym> for String { impl TryFrom<Sym> for String {
type Error = GlobalSymError; type Error = SymError;
fn try_from(value: GlobalSym) -> Result<Self, Self::Error> { fn try_from(value: Sym) -> Result<Self, Self::Error> {
let Some(interner) = GLOBAL_INTERNER.get() else { let Some(interner) = GLOBAL_INTERNER.get() else {
Err(GlobalSymError::Uninitialized)? Err(SymError::Uninitialized)?
}; };
let Ok(interner) = interner.write() else { let Ok(interner) = interner.write() else {
Err(GlobalSymError::Poisoned)? Err(SymError::Poisoned)?
}; };
match interner.get_str(value) { match interner.get_str(value) {
None => Err(GlobalSymError::Unseen(value)), None => Err(SymError::Unseen(value)),
Some(string) => Ok(string.into()), Some(string) => Ok(string.into()),
} }
} }
} }
/// Describes an error in [Sym] to [String] lookup
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GlobalSymError { pub enum SymError {
Uninitialized, Uninitialized,
Poisoned, Poisoned,
Unseen(GlobalSym), Unseen(Sym),
} }
impl std::error::Error for GlobalSymError {} impl std::error::Error for SymError {}
impl Display for GlobalSymError { impl Display for SymError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
GlobalSymError::Uninitialized => "String pool was not initialized".fmt(f), SymError::Uninitialized => "String pool was not initialized".fmt(f),
GlobalSymError::Poisoned => "String pool was held by panicking thread".fmt(f), SymError::Poisoned => "String pool was held by panicking thread".fmt(f),
GlobalSymError::Unseen(sym) => { SymError::Unseen(sym) => {
write!(f, "Symbol {sym:?} not present in String pool") write!(f, "Symbol {sym:?} not present in String pool")
} }
} }

View File

@ -3,32 +3,32 @@ use super::*;
#[test] #[test]
fn globalsym_from_returns_unique_value_for_unique_keys() { fn globalsym_from_returns_unique_value_for_unique_keys() {
let foo_bar = GlobalSym::from("foo_bar"); let foo_bar = Sym::from("foo_bar");
let foo_baz = GlobalSym::from("foo_baz"); let foo_baz = Sym::from("foo_baz");
assert_ne!(foo_bar, foo_baz); assert_ne!(foo_bar, foo_baz);
assert_eq!(foo_bar, GlobalSym::from("foo_bar")); assert_eq!(foo_bar, Sym::from("foo_bar"));
assert_eq!(foo_baz, GlobalSym::from("foo_baz")); assert_eq!(foo_baz, Sym::from("foo_baz"));
} }
#[test] #[test]
fn try_from_str_returns_none_before_init() { fn try_from_str_returns_none_before_init() {
if let Some(value) = GlobalSym::try_from_str("") { if let Some(value) = Sym::try_from_str("") {
panic!("{value}") panic!("{value}")
} }
} }
#[test] #[test]
fn try_from_str_returns_some_when_key_exists() { fn try_from_str_returns_some_when_key_exists() {
let _ = GlobalSym::from("foo_bar"); let _ = Sym::from("foo_bar");
assert!(dbg!(GlobalSym::try_from_str("foo_bar")).is_some()); assert!(dbg!(Sym::try_from_str("foo_bar")).is_some());
} }
#[test] #[test]
fn try_from_str_returns_the_same_thing_as_globalsym_from() { fn try_from_str_returns_the_same_thing_as_globalsym_from() {
let foo_bar = GlobalSym::from("foo_bar"); let foo_bar = Sym::from("foo_bar");
assert_eq!(Some(foo_bar), GlobalSym::try_from_str("foo_bar")); assert_eq!(Some(foo_bar), Sym::try_from_str("foo_bar"));
} }
#[test] #[test]
fn map_works() { fn map_works() {
let foo_bar = GlobalSym::from("foo_bar"); let foo_bar = Sym::from("foo_bar");
assert!(foo_bar.map(|sym| "foo_bar" == sym).unwrap()); assert!(foo_bar.map(|sym| "foo_bar" == sym).unwrap());
} }

View File

@ -131,9 +131,6 @@ fn list_types(prj: &mut Project) {
println!(" name\x1b[30G type"); println!(" name\x1b[30G type");
for (idx, Def { name, vis, kind, .. }) in prj.pool.iter().enumerate() { for (idx, Def { name, vis, kind, .. }) in prj.pool.iter().enumerate() {
print!("{idx:3}: {vis}"); print!("{idx:3}: {vis}");
if name.is_empty() {
print!("\x1b[30m_\x1b[0m")
}
println!("{name}\x1b[30G| {kind}"); println!("{name}\x1b[30G| {kind}");
} }
} }

View File

@ -35,16 +35,16 @@ pub enum DefSource<'a> {
} }
impl<'a> DefSource<'a> { impl<'a> DefSource<'a> {
pub fn name(&self) -> Option<&'a str> { pub fn name(&self) -> Option<Sym> {
match self { match self {
DefSource::Module(v) => Some(v.name.0.as_str()), DefSource::Module(v) => Some(v.name.0),
DefSource::Alias(v) => Some(v.to.0.as_str()), DefSource::Alias(v) => Some(v.to.0),
DefSource::Enum(v) => Some(v.name.0.as_str()), DefSource::Enum(v) => Some(v.name.0),
DefSource::Struct(v) => Some(v.name.0.as_str()), DefSource::Struct(v) => Some(v.name.0),
DefSource::Const(v) => Some(v.name.0.as_str()), DefSource::Const(v) => Some(v.name.0),
DefSource::Static(v) => Some(v.name.0.as_str()), DefSource::Static(v) => Some(v.name.0),
DefSource::Function(v) => Some(v.name.0.as_str()), DefSource::Function(v) => Some(v.name.0),
DefSource::Local(l) => Some(l.name.0.as_str()), DefSource::Local(l) => Some(l.name.0),
DefSource::Impl(_) | DefSource::Use(_) | DefSource::Ty(_) => None, DefSource::Impl(_) | DefSource::Use(_) | DefSource::Ty(_) => None,
} }
} }

View File

@ -1,24 +1,24 @@
use crate::{key::DefID, module::Module}; use crate::{key::DefID, module::Module};
use cl_ast::{Item, Meta, Visibility}; use cl_ast::{Item, Meta, Sym, Visibility};
use std::{fmt::Debug, str::FromStr}; use std::{fmt::Debug, str::FromStr};
mod display; mod display;
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct Def<'a> { pub struct Def<'a> {
pub name: &'a str, pub name: Sym,
pub vis: Visibility, pub vis: Visibility,
pub meta: &'a [Meta], pub meta: &'a [Meta],
pub kind: DefKind<'a>, pub kind: DefKind,
pub source: Option<&'a Item>, pub source: Option<&'a Item>,
pub module: Module<'a>, pub module: Module,
} }
mod builder_functions { mod builder_functions {
use super::*; use super::*;
impl<'a> Def<'a> { impl<'a> Def<'a> {
pub fn set_name(&mut self, name: &'a str) -> &mut Self { pub fn set_name(&mut self, name: Sym) -> &mut Self {
self.name = name; self.name = name;
self self
} }
@ -30,7 +30,7 @@ mod builder_functions {
self.meta = meta; self.meta = meta;
self self
} }
pub fn set_kind(&mut self, kind: DefKind<'a>) -> &mut Self { pub fn set_kind(&mut self, kind: DefKind) -> &mut Self {
self.kind = kind; self.kind = kind;
self self
} }
@ -38,7 +38,7 @@ mod builder_functions {
self.source = Some(source); self.source = Some(source);
self self
} }
pub fn set_module(&mut self, module: Module<'a>) -> &mut Self { pub fn set_module(&mut self, module: Module) -> &mut Self {
self.module = module; self.module = module;
self self
} }
@ -48,7 +48,7 @@ mod builder_functions {
impl Default for Def<'_> { impl Default for Def<'_> {
fn default() -> Self { fn default() -> Self {
Self { Self {
name: Default::default(), name: "".into(),
vis: Visibility::Public, vis: Visibility::Public,
meta: Default::default(), meta: Default::default(),
kind: Default::default(), kind: Default::default(),
@ -59,7 +59,7 @@ impl Default for Def<'_> {
} }
#[derive(Clone, Default, Debug, PartialEq, Eq)] #[derive(Clone, Default, Debug, PartialEq, Eq)]
pub enum DefKind<'a> { pub enum DefKind {
/// An unevaluated definition /// An unevaluated definition
#[default] #[default]
Undecided, Undecided,
@ -68,7 +68,7 @@ pub enum DefKind<'a> {
/// A use tree, and its parent /// A use tree, and its parent
Use(DefID), Use(DefID),
/// A type, such as a `type`, `struct`, or `enum` /// A type, such as a `type`, `struct`, or `enum`
Type(TypeKind<'a>), Type(TypeKind),
/// A value, such as a `const`, `static`, or `fn` /// A value, such as a `const`, `static`, or `fn`
Value(ValueKind), Value(ValueKind),
} }
@ -84,13 +84,13 @@ pub enum ValueKind {
/// A [TypeKind] represents an item in the Type Namespace /// A [TypeKind] represents an item in the Type Namespace
/// (a component of a [Project](crate::project::Project)). /// (a component of a [Project](crate::project::Project)).
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum TypeKind<'a> { pub enum TypeKind {
/// An alias for an already-defined type /// An alias for an already-defined type
Alias(Option<DefID>), Alias(Option<DefID>),
/// A primitive type, built-in to the compiler /// A primitive type, built-in to the compiler
Intrinsic(Intrinsic), Intrinsic(Intrinsic),
/// A user-defined aromatic data type /// A user-defined aromatic data type
Adt(Adt<'a>), Adt(Adt),
/// A reference to an already-defined type: &T /// A reference to an already-defined type: &T
Ref(u16, DefID), Ref(u16, DefID),
/// A contiguous view of dynamically sized memory /// A contiguous view of dynamically sized memory
@ -113,16 +113,16 @@ pub enum TypeKind<'a> {
/// A user-defined Aromatic Data Type /// A user-defined Aromatic Data Type
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Adt<'a> { pub enum Adt {
/// A union-like enum type /// A union-like enum type
Enum(Vec<(&'a str, Option<DefID>)>), Enum(Vec<(Sym, Option<DefID>)>),
/// A C-like enum /// A C-like enum
CLikeEnum(Vec<(&'a str, u128)>), CLikeEnum(Vec<(Sym, u128)>),
/// An enum with no fields, which can never be constructed /// An enum with no fields, which can never be constructed
FieldlessEnum, FieldlessEnum,
/// A structural product type with named members /// A structural product type with named members
Struct(Vec<(&'a str, Visibility, DefID)>), Struct(Vec<(Sym, Visibility, DefID)>),
/// A structural product type with unnamed members /// A structural product type with unnamed members
TupleStruct(Vec<(Visibility, DefID)>), TupleStruct(Vec<(Visibility, DefID)>),
/// A structural product type of neither named nor unnamed members /// A structural product type of neither named nor unnamed members
@ -130,7 +130,7 @@ pub enum Adt<'a> {
/// A choose your own undefined behavior type /// A choose your own undefined behavior type
/// TODO: should unions be a language feature? /// TODO: should unions be a language feature?
Union(Vec<(&'a str, DefID)>), Union(Vec<(Sym, DefID)>),
} }
/// The set of compiler-intrinsic types. /// The set of compiler-intrinsic types.

View File

@ -44,7 +44,7 @@ impl Display for Def<'_> {
} }
} }
impl Display for DefKind<'_> { impl Display for DefKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
DefKind::Undecided => write!(f, "undecided"), DefKind::Undecided => write!(f, "undecided"),
@ -66,7 +66,7 @@ impl std::fmt::Display for ValueKind {
} }
} }
impl Display for TypeKind<'_> { impl Display for TypeKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
TypeKind::Alias(def) => match def { TypeKind::Alias(def) => match def {
@ -99,7 +99,7 @@ impl Display for TypeKind<'_> {
} }
} }
impl Display for Adt<'_> { impl Display for Adt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Adt::Enum(variants) => { Adt::Enum(variants) => {

View File

@ -1,5 +1,6 @@
//! A [Module] is a node in the Module Tree (a component of a //! A [Module] is a node in the Module Tree (a component of a
//! [Project](crate::project::Project)) //! [Project](crate::project::Project))
use cl_ast::Sym;
use cl_structures::intern_pool::InternKey; use cl_structures::intern_pool::InternKey;
use crate::key::DefID; use crate::key::DefID;
@ -8,14 +9,14 @@ use std::collections::HashMap;
/// A [Module] is a node in the Module Tree (a component of a /// A [Module] is a node in the Module Tree (a component of a
/// [Project](crate::project::Project)). /// [Project](crate::project::Project)).
#[derive(Clone, Debug, Default, PartialEq, Eq)] #[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Module<'a> { pub struct Module {
pub parent: Option<DefID>, pub parent: Option<DefID>,
pub types: HashMap<&'a str, DefID>, pub types: HashMap<Sym, DefID>,
pub values: HashMap<&'a str, DefID>, pub values: HashMap<Sym, DefID>,
pub imports: Vec<DefID>, pub imports: Vec<DefID>,
} }
impl<'a> Module<'a> { impl Module {
pub fn new(parent: DefID) -> Self { pub fn new(parent: DefID) -> Self {
Self { parent: Some(parent), ..Default::default() } Self { parent: Some(parent), ..Default::default() }
} }
@ -23,29 +24,29 @@ impl<'a> Module<'a> {
Self { parent, ..Default::default() } Self { parent, ..Default::default() }
} }
pub fn get(&self, name: &'a str) -> (Option<DefID>, Option<DefID>) { pub fn get(&self, name: Sym) -> (Option<DefID>, Option<DefID>) {
(self.get_type(name), self.get_value(name)) (self.get_type(name), self.get_value(name))
} }
pub fn get_type(&self, name: &'a str) -> Option<DefID> { pub fn get_type(&self, name: Sym) -> Option<DefID> {
self.types.get(name).copied() self.types.get(&name).copied()
} }
pub fn get_value(&self, name: &'a str) -> Option<DefID> { pub fn get_value(&self, name: Sym) -> Option<DefID> {
self.values.get(name).copied() self.values.get(&name).copied()
} }
/// Inserts a type with the provided [name](str) and [id](DefID) /// Inserts a type with the provided [name](str) and [id](DefID)
pub fn insert_type(&mut self, name: &'a str, id: DefID) -> Option<DefID> { pub fn insert_type(&mut self, name: Sym, id: DefID) -> Option<DefID> {
self.types.insert(name, id) self.types.insert(name, id)
} }
/// Inserts a value with the provided [name](str) and [id](DefID) /// Inserts a value with the provided [name](str) and [id](DefID)
pub fn insert_value(&mut self, name: &'a str, id: DefID) -> Option<DefID> { pub fn insert_value(&mut self, name: Sym, id: DefID) -> Option<DefID> {
self.values.insert(name, id) self.values.insert(name, id)
} }
} }
impl std::fmt::Display for Module<'_> { impl std::fmt::Display for Module {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let Self { parent, types, values, imports } = self; let Self { parent, types, values, imports } = self;
if let Some(parent) = parent { if let Some(parent) = parent {
writeln!(f, "Parent: {}", parent.get())?; writeln!(f, "Parent: {}", parent.get())?;

View File

@ -50,8 +50,8 @@ impl<'a> NameCollectable<'a> for Module {
let Self { name: Identifier(name), kind } = self; let Self { name: Identifier(name), kind } = self;
let module = let module =
c.pool c.pool
.insert(Def { name, module: Mod::new(parent), ..Default::default() }); .insert(Def { name: *name, module: Mod::new(parent), ..Default::default() });
c[parent].module.types.insert(name, module); c[parent].module.types.insert(*name, module);
match kind { match kind {
ModuleKind::Inline(file) => file.collect(c, module)?, ModuleKind::Inline(file) => file.collect(c, module)?,
@ -87,10 +87,10 @@ impl<'a> NameCollectable<'a> for Alias {
fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> { fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> {
let Alias { to: Identifier(name), .. } = self; let Alias { to: Identifier(name), .. } = self;
let def = Def { name, module: Mod::new(parent), ..Default::default() }; let def = Def { name: *name, module: Mod::new(parent), ..Default::default() };
let id = c.pool.insert(def); let id = c.pool.insert(def);
c[parent].module.types.insert(name, id); c[parent].module.types.insert(*name, id);
Ok(id) Ok(id)
} }
} }
@ -98,10 +98,10 @@ impl<'a> NameCollectable<'a> for Enum {
fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> { fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> {
let Enum { name: Identifier(name), .. } = self; let Enum { name: Identifier(name), .. } = self;
let def = Def { name, module: Mod::new(parent), ..Default::default() }; let def = Def { name: *name, module: Mod::new(parent), ..Default::default() };
let id = c.pool.insert(def); let id = c.pool.insert(def);
c[parent].module.types.insert(name, id); c[parent].module.types.insert(*name, id);
Ok(id) Ok(id)
} }
} }
@ -109,10 +109,10 @@ impl<'a> NameCollectable<'a> for Struct {
fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> { fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> {
let Struct { name: Identifier(name), .. } = self; let Struct { name: Identifier(name), .. } = self;
let def = Def { name, module: Mod::new(parent), ..Default::default() }; let def = Def { name: *name, module: Mod::new(parent), ..Default::default() };
let id = c.pool.insert(def); let id = c.pool.insert(def);
c[parent].module.types.insert(name, id); c[parent].module.types.insert(*name, id);
Ok(id) Ok(id)
} }
} }
@ -122,10 +122,10 @@ impl<'a> NameCollectable<'a> for Const {
let kind = DefKind::Undecided; let kind = DefKind::Undecided;
let def = Def { name, kind, module: Mod::new(parent), ..Default::default() }; let def = Def { name: *name, kind, module: Mod::new(parent), ..Default::default() };
let id = c.pool.insert(def); let id = c.pool.insert(def);
c[parent].module.values.insert(name, id); c[parent].module.values.insert(*name, id);
init.collect(c, id)?; init.collect(c, id)?;
Ok(id) Ok(id)
@ -137,10 +137,10 @@ impl<'a> NameCollectable<'a> for Static {
let kind = DefKind::Undecided; let kind = DefKind::Undecided;
let def = Def { name, kind, module: Mod::new(parent), ..Default::default() }; let def = Def { name: *name, kind, module: Mod::new(parent), ..Default::default() };
let id = c.pool.insert(def); let id = c.pool.insert(def);
c[parent].module.values.insert(name, id); c[parent].module.values.insert(*name, id);
init.collect(c, id)?; init.collect(c, id)?;
Ok(id) Ok(id)
@ -152,10 +152,10 @@ impl<'a> NameCollectable<'a> for Function {
let kind = DefKind::Undecided; let kind = DefKind::Undecided;
let def = Def { name, kind, module: Mod::new(parent), ..Default::default() }; let def = Def { name: *name, kind, module: Mod::new(parent), ..Default::default() };
let id = c.pool.insert(def); let id = c.pool.insert(def);
c[parent].module.values.insert(name, id); c[parent].module.values.insert(*name, id);
body.collect(c, id)?; body.collect(c, id)?;
Ok(id) Ok(id)

View File

@ -18,7 +18,7 @@ use self::evaluate::EvaluableTypeExpression;
pub struct Project<'a> { pub struct Project<'a> {
pub pool: Pool<Def<'a>, DefID>, pub pool: Pool<Def<'a>, DefID>,
/// Stores anonymous tuples, function pointer types, etc. /// Stores anonymous tuples, function pointer types, etc.
pub anon_types: HashMap<TypeKind<'a>, DefID>, pub anon_types: HashMap<TypeKind, DefID>,
pub root: DefID, pub root: DefID,
} }
@ -32,21 +32,21 @@ impl Default for Project<'_> {
fn default() -> Self { fn default() -> Self {
let mut pool = Pool::default(); let mut pool = Pool::default();
let root = pool.insert(Def { let root = pool.insert(Def {
name: "🌳 root 🌳", name: "🌳 root 🌳".into(),
kind: DefKind::Type(TypeKind::Module), kind: DefKind::Type(TypeKind::Module),
..Default::default() ..Default::default()
}); });
// Insert the Never(!) type // Insert the Never(!) type
let never = pool.insert(Def { let never = pool.insert(Def {
name: "!", name: "!".into(),
vis: Visibility::Public, vis: Visibility::Public,
kind: DefKind::Type(TypeKind::Never), kind: DefKind::Type(TypeKind::Never),
module: module::Module::new(root), module: module::Module::new(root),
..Default::default() ..Default::default()
}); });
let empty = pool.insert(Def { let empty = pool.insert(Def {
name: "()", name: "()".into(),
vis: Visibility::Public, vis: Visibility::Public,
kind: DefKind::Type(TypeKind::Empty), kind: DefKind::Type(TypeKind::Empty),
module: module::Module::new(root), module: module::Module::new(root),
@ -54,7 +54,7 @@ impl Default for Project<'_> {
}); });
// TODO: Self is not a real type! // TODO: Self is not a real type!
let selfty = pool.insert(Def { let selfty = pool.insert(Def {
name: "Self", name: "Self".into(),
vis: Visibility::Public, vis: Visibility::Public,
kind: DefKind::Type(TypeKind::SelfTy), kind: DefKind::Type(TypeKind::SelfTy),
module: module::Module::new(root), module: module::Module::new(root),
@ -92,11 +92,11 @@ impl<'a> Project<'a> {
match path.as_ref() { match path.as_ref() {
[] => Some((Some(within), None, path)), [] => Some((Some(within), None, path)),
[PathPart::Ident(Identifier(name))] => { [PathPart::Ident(Identifier(name))] => {
let (ty, val) = self[within].module.get(name); let (ty, val) = self[within].module.get(*name);
Some((ty, val, path.pop_front()?)) Some((ty, val, path.pop_front()?))
} }
[PathPart::Ident(Identifier(name)), ..] => { [PathPart::Ident(Identifier(name)), ..] => {
let ty = self[within].module.get_type(name)?; let ty = self[within].module.get_type(*name)?;
self.get(path.pop_front()?, ty) self.get(path.pop_front()?, ty)
} }
[PathPart::SelfKw, ..] => self.get(path.pop_front()?, within), [PathPart::SelfKw, ..] => self.get(path.pop_front()?, within),
@ -114,7 +114,7 @@ impl<'a> Project<'a> {
match front { match front {
PathPart::SelfKw => self.get_type(path.pop_front()?, within), PathPart::SelfKw => self.get_type(path.pop_front()?, within),
PathPart::SuperKw => self.get_type(path.pop_front()?, module.parent?), PathPart::SuperKw => self.get_type(path.pop_front()?, module.parent?),
PathPart::Ident(Identifier(name)) => match module.types.get(name.as_str()) { PathPart::Ident(Identifier(name)) => match module.types.get(name) {
Some(&submodule) => self.get_type(path.pop_front()?, submodule), Some(&submodule) => self.get_type(path.pop_front()?, submodule),
None => Some((within, path)), None => Some((within, path)),
}, },
@ -127,7 +127,7 @@ impl<'a> Project<'a> {
pub fn get_value<'p>(&self, path: Path<'p>, within: DefID) -> Option<(DefID, Path<'p>)> { pub fn get_value<'p>(&self, path: Path<'p>, within: DefID) -> Option<(DefID, Path<'p>)> {
match path.front()? { match path.front()? {
PathPart::Ident(Identifier(name)) => Some(( PathPart::Ident(Identifier(name)) => Some((
self[within].module.values.get(name.as_str()).copied()?, self[within].module.values.get(name).copied()?,
path.pop_front()?, path.pop_front()?,
)), )),
_ => None, _ => None,
@ -139,7 +139,7 @@ impl<'a> Project<'a> {
/// Assumes `kind` uniquely identifies the type! /// Assumes `kind` uniquely identifies the type!
pub fn insert_anonymous_type( pub fn insert_anonymous_type(
&mut self, &mut self,
kind: TypeKind<'a>, kind: TypeKind,
def: impl FnOnce() -> Def<'a>, def: impl FnOnce() -> Def<'a>,
) -> DefID { ) -> DefID {
*(self *(self
@ -171,7 +171,7 @@ pub mod evaluate {
//! or an intermediate result of expression evaluation. //! or an intermediate result of expression evaluation.
use super::*; use super::*;
use cl_ast::Ty; use cl_ast::{Sym, Ty};
/// Things that can be evaluated as a type expression /// Things that can be evaluated as a type expression
pub trait EvaluableTypeExpression { pub trait EvaluableTypeExpression {
@ -203,8 +203,7 @@ pub mod evaluate {
if path.is_empty() { if path.is_empty() {
id id
} else { } else {
let (id, path) = let (id, path) = prj.get_value(path, id).ok_or("Failed to get value")?;
prj.get_value(path, id).ok_or("Failed to get value")?;
path.is_empty() path.is_empty()
.then_some(id) .then_some(id)
.ok_or("Path not fully resolved")? .ok_or("Path not fully resolved")?
@ -220,7 +219,7 @@ pub mod evaluate {
} }
} }
impl EvaluableTypeExpression for str { impl EvaluableTypeExpression for Sym {
type Out = DefID; type Out = DefID;
fn evaluate(&self, prj: &mut Project, parent: DefID) -> Result<Self::Out, String> { fn evaluate(&self, prj: &mut Project, parent: DefID) -> Result<Self::Out, String> {
@ -298,7 +297,7 @@ pub mod evaluate {
.parent_of(parent) .parent_of(parent)
.ok_or_else(|| "Attempt to get super of root".into()), .ok_or_else(|| "Attempt to get super of root".into()),
PathPart::SelfKw => Ok(parent), PathPart::SelfKw => Ok(parent),
PathPart::Ident(Identifier(name)) => name.as_str().evaluate(prj, parent), PathPart::Ident(Identifier(name)) => name.evaluate(prj, parent),
} }
} }
} }

View File

@ -45,7 +45,7 @@ pub trait TypeResolvable<'a> {
} }
impl<'a> TypeResolvable<'a> for Item { impl<'a> TypeResolvable<'a> for Item {
type Out = DefKind<'a>; type Out = DefKind;
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
let Self { attrs: Attrs { meta }, kind, .. } = self; let Self { attrs: Attrs { meta }, kind, .. } = self;
for meta in meta { for meta in meta {
@ -58,11 +58,12 @@ impl<'a> TypeResolvable<'a> for Item {
} }
impl<'a> TypeResolvable<'a> for Meta { impl<'a> TypeResolvable<'a> for Meta {
type Out = DefKind<'a>; type Out = DefKind;
#[allow(unused_variables)] #[allow(unused_variables)]
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
let Self { name: Identifier(name), kind } = self; let Self { name: Identifier(name), kind } = self;
let name = name.get().unwrap_or_default();
match (name.as_str(), kind) { match (name.as_str(), kind) {
("intrinsic", MetaKind::Equals(Literal::String(intrinsic))) => Ok(DefKind::Type( ("intrinsic", MetaKind::Equals(Literal::String(intrinsic))) => Ok(DefKind::Type(
TypeKind::Intrinsic(intrinsic.parse().map_err(|_| "unknown intrinsic type")?), TypeKind::Intrinsic(intrinsic.parse().map_err(|_| "unknown intrinsic type")?),
@ -76,7 +77,7 @@ impl<'a> TypeResolvable<'a> for Meta {
} }
impl<'a> TypeResolvable<'a> for ItemKind { impl<'a> TypeResolvable<'a> for ItemKind {
type Out = DefKind<'a>; type Out = DefKind;
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
if prj[id].source.map(|s| &s.kind as *const _) != Some(self as *const _) { if prj[id].source.map(|s| &s.kind as *const _) != Some(self as *const _) {
return Err("id is not self!"); return Err("id is not self!");
@ -96,7 +97,7 @@ impl<'a> TypeResolvable<'a> for ItemKind {
} }
impl<'a> TypeResolvable<'a> for Module { impl<'a> TypeResolvable<'a> for Module {
type Out = DefKind<'a>; type Out = DefKind;
#[allow(unused_variables)] #[allow(unused_variables)]
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
Ok(DefKind::Type(TypeKind::Module)) Ok(DefKind::Type(TypeKind::Module))
@ -104,7 +105,7 @@ impl<'a> TypeResolvable<'a> for Module {
} }
impl<'a> TypeResolvable<'a> for Impl { impl<'a> TypeResolvable<'a> for Impl {
type Out = DefKind<'a>; type Out = DefKind;
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
let parent = prj.parent_of(id).unwrap_or(id); let parent = prj.parent_of(id).unwrap_or(id);
@ -122,7 +123,7 @@ impl<'a> TypeResolvable<'a> for Impl {
} }
impl<'a> TypeResolvable<'a> for Use { impl<'a> TypeResolvable<'a> for Use {
type Out = DefKind<'a>; type Out = DefKind;
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
todo!("Resolve types for {self} with ID {id} in {prj:?}") todo!("Resolve types for {self} with ID {id} in {prj:?}")
@ -130,7 +131,7 @@ impl<'a> TypeResolvable<'a> for Use {
} }
impl<'a> TypeResolvable<'a> for Alias { impl<'a> TypeResolvable<'a> for Alias {
type Out = DefKind<'a>; type Out = DefKind;
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
let parent = prj.parent_of(id).unwrap_or(id); let parent = prj.parent_of(id).unwrap_or(id);
@ -149,7 +150,7 @@ impl<'a> TypeResolvable<'a> for Alias {
} }
impl<'a> TypeResolvable<'a> for Enum { impl<'a> TypeResolvable<'a> for Enum {
type Out = DefKind<'a>; type Out = DefKind;
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
let Self { name: _, kind } = self; let Self { name: _, kind } = self;
@ -159,7 +160,7 @@ impl<'a> TypeResolvable<'a> for Enum {
let mut fields = vec![]; let mut fields = vec![];
for v @ Variant { name: Identifier(name), kind: _ } in v { for v @ Variant { name: Identifier(name), kind: _ } in v {
let id = v.resolve_type(prj, id)?; let id = v.resolve_type(prj, id)?;
fields.push((name.as_str(), id)) fields.push((*name, id))
} }
Ok(DefKind::Type(TypeKind::Adt(Adt::Enum(fields)))) Ok(DefKind::Type(TypeKind::Adt(Adt::Enum(fields))))
} }
@ -185,7 +186,7 @@ impl<'a> TypeResolvable<'a> for Variant {
}; };
let def = Def { let def = Def {
name, name: *name,
kind: DefKind::Type(TypeKind::Adt(adt)), kind: DefKind::Type(TypeKind::Adt(adt)),
module: module::Module::new(id), module: module::Module::new(id),
..Default::default() ..Default::default()
@ -193,14 +194,14 @@ impl<'a> TypeResolvable<'a> for Variant {
let new_id = prj.pool.insert(def); let new_id = prj.pool.insert(def);
// Insert the struct variant type into the enum's namespace // Insert the struct variant type into the enum's namespace
prj[id].module.types.insert(name, new_id); prj[id].module.types.insert(*name, new_id);
Ok(Some(new_id)) Ok(Some(new_id))
} }
} }
impl<'a> TypeResolvable<'a> for Struct { impl<'a> TypeResolvable<'a> for Struct {
type Out = DefKind<'a>; type Out = DefKind;
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
let parent = prj.parent_of(id).unwrap_or(id); let parent = prj.parent_of(id).unwrap_or(id);
let Self { name: _, kind } = self; let Self { name: _, kind } = self;
@ -225,7 +226,7 @@ impl<'a> TypeResolvable<'a> for Struct {
} }
impl<'a> TypeResolvable<'a> for StructMember { impl<'a> TypeResolvable<'a> for StructMember {
type Out = (&'a str, Visibility, DefID); type Out = (Sym, Visibility, DefID);
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
let parent = prj.parent_of(id).unwrap_or(id); let parent = prj.parent_of(id).unwrap_or(id);
@ -235,12 +236,12 @@ impl<'a> TypeResolvable<'a> for StructMember {
.evaluate(prj, parent) .evaluate(prj, parent)
.map_err(|_| "Invalid type while resolving StructMember")?; .map_err(|_| "Invalid type while resolving StructMember")?;
Ok((name, *vis, ty)) Ok((*name, *vis, ty))
} }
} }
impl<'a> TypeResolvable<'a> for Const { impl<'a> TypeResolvable<'a> for Const {
type Out = DefKind<'a>; type Out = DefKind;
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
let Self { ty, .. } = self; let Self { ty, .. } = self;
@ -251,7 +252,7 @@ impl<'a> TypeResolvable<'a> for Const {
} }
} }
impl<'a> TypeResolvable<'a> for Static { impl<'a> TypeResolvable<'a> for Static {
type Out = DefKind<'a>; type Out = DefKind;
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
let parent = prj.parent_of(id).unwrap_or(id); let parent = prj.parent_of(id).unwrap_or(id);
@ -264,7 +265,7 @@ impl<'a> TypeResolvable<'a> for Static {
} }
impl<'a> TypeResolvable<'a> for Function { impl<'a> TypeResolvable<'a> for Function {
type Out = DefKind<'a>; type Out = DefKind;
fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> { fn resolve_type(&'a self, prj: &mut Prj<'a>, id: DefID) -> Result<Self::Out, &'static str> {
let parent = prj.parent_of(id).unwrap_or(id); let parent = prj.parent_of(id).unwrap_or(id);

View File

@ -1,5 +1,5 @@
//! WIP use-item importer. This performs eager import resolution on the AST //! WIP use-item importer. This performs eager import resolution on the AST
//! //!
//! # TODOs: //! # TODOs:
//! - [ ] Resolve imports using a graph traversal rather than linear iteration //! - [ ] Resolve imports using a graph traversal rather than linear iteration
//! - [ ] Separate imported items from natively declared items //! - [ ] Separate imported items from natively declared items
@ -7,7 +7,6 @@
//! - [ ] Report errors in a meaningful way //! - [ ] Report errors in a meaningful way
//! - [ ] Lazy import resolution using graph-edge traversal during name lookup? //! - [ ] Lazy import resolution using graph-edge traversal during name lookup?
//! - It doesn't seem to me like the imports in a given scope *can change*. //! - It doesn't seem to me like the imports in a given scope *can change*.
//!
#![allow(unused)] #![allow(unused)]
use std::fmt::format; use std::fmt::format;
@ -74,20 +73,15 @@ impl<'a> Project<'a> {
Ok(()) Ok(())
} }
pub fn visit_use_leaf( pub fn visit_use_leaf(&mut self, part: &'a Identifier, parent: DefID, c: DefID) -> UseResult {
&mut self,
part: &'a Identifier,
parent: DefID,
c: DefID,
) -> UseResult {
let Identifier(name) = part; let Identifier(name) = part;
self.visit_use_alias(name, name, parent, c) self.visit_use_alias(name, name, parent, c)
} }
pub fn visit_use_alias( pub fn visit_use_alias(
&mut self, &mut self,
from: &'a str, from: &Sym,
name: &'a str, name: &Sym,
parent: DefID, parent: DefID,
c: DefID, c: DefID,
) -> UseResult { ) -> UseResult {
@ -100,12 +94,12 @@ impl<'a> Project<'a> {
let parent = &mut self[parent].module; let parent = &mut self[parent].module;
if let Some(tid) = tid { if let Some(tid) = tid {
parent.types.insert(name, tid); parent.types.insert(*name, tid);
imported = true; imported = true;
} }
if let Some(vid) = vid { if let Some(vid) = vid {
parent.values.insert(name, vid); parent.values.insert(*name, vid);
imported = true; imported = true;
} }