roc/crates/compiler/module/src/ident.rs
2023-03-26 10:01:05 -04:00

347 lines
8 KiB
Rust

pub use roc_ident::IdentStr;
use std::fmt::{self, Debug};
use crate::symbol::PQModuleName;
/// This could be uppercase or lowercase, qualified or unqualified.
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
pub struct Ident(pub IdentStr);
impl Ident {
pub fn as_inline_str(&self) -> &IdentStr {
&self.0
}
#[inline(always)]
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
pub struct QualifiedModuleName<'a> {
pub opt_package: Option<&'a str>,
pub module: ModuleName,
}
impl<'a> QualifiedModuleName<'a> {
pub fn into_pq_module_name(self, opt_shorthand: Option<&'a str>) -> PQModuleName<'a> {
if self.is_builtin() {
// If this is a builtin, it must be unqualified, and we should *never* prefix it
// with the package shorthand! The user intended to import the module as-is here.
debug_assert!(self.opt_package.is_none());
PQModuleName::Unqualified(self.module)
} else {
match self.opt_package {
None => match opt_shorthand {
Some(shorthand) => PQModuleName::Qualified(shorthand, self.module),
None => PQModuleName::Unqualified(self.module),
},
Some(package) => PQModuleName::Qualified(package, self.module),
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ModuleName(IdentStr);
impl std::ops::Deref for ModuleName {
type Target = str;
fn deref(&self) -> &Self::Target {
self.0.as_str()
}
}
/// An uncapitalized identifier, such as a field name or local variable
#[derive(Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Lowercase(IdentStr);
/// A capitalized identifier, such as a tag name or module name
#[derive(Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Uppercase(IdentStr);
/// A string representing a foreign (linked-in) symbol
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct ForeignSymbol(IdentStr);
pub type TagIdIntType = u16;
/// Tags have no module, but tend to be short strings (since they're
/// never qualified), so we store them as ident strings.
///
/// This is allows canonicalization to happen in parallel without locks.
/// If tags had a Symbol representation, then each module would have to
/// deal with contention on a global mutex around translating tag strings
/// into integers. (Record field labels work the same way, for the same reason.)
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct TagName(pub Uppercase);
roc_error_macros::assert_sizeof_non_wasm!(TagName, 16);
roc_error_macros::assert_sizeof_wasm!(TagName, 8);
impl TagName {
pub fn as_ident_str(&self) -> IdentStr {
self.0.as_ident_str().clone()
}
}
impl Debug for TagName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.0, f)
}
}
impl From<&str> for TagName {
fn from(string: &str) -> Self {
Self(string.into())
}
}
impl ModuleName {
// NOTE: After adding one of these, go to `impl ModuleId` and
// add a corresponding ModuleId to there!
pub const APP: &'static str = "#UserApp"; // app modules have this hardcoded name
pub const BOOL: &'static str = "Bool";
pub const STR: &'static str = "Str";
pub const NUM: &'static str = "Num";
pub const LIST: &'static str = "List";
pub const DICT: &'static str = "Dict";
pub const SET: &'static str = "Set";
pub const RESULT: &'static str = "Result";
pub const BOX: &'static str = "Box";
pub const ENCODE: &'static str = "Encode";
pub const DECODE: &'static str = "Decode";
pub const HASH: &'static str = "Hash";
pub const JSON: &'static str = "Json";
pub fn as_str(&self) -> &str {
self.0.as_str()
}
pub fn as_ident_str(&self) -> &IdentStr {
&self.0
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl AsRef<str> for ModuleName {
#[inline(always)]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<'a> From<&'a str> for ModuleName {
fn from(string: &'a str) -> Self {
Self(string.into())
}
}
impl From<IdentStr> for ModuleName {
fn from(string: IdentStr) -> Self {
Self(string.as_str().into())
}
}
impl From<Box<str>> for ModuleName {
fn from(string: Box<str>) -> Self {
Self((string.as_ref()).into())
}
}
impl From<String> for ModuleName {
fn from(string: String) -> Self {
Self(string.into())
}
}
impl From<ModuleName> for Box<str> {
fn from(name: ModuleName) -> Self {
name.0.to_string().into()
}
}
impl fmt::Display for ModuleName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl ForeignSymbol {
pub fn as_str(&self) -> &str {
self.0.as_str()
}
pub fn as_inline_str(&self) -> &IdentStr {
&self.0
}
}
impl<'a> From<&'a str> for ForeignSymbol {
fn from(string: &'a str) -> Self {
Self(string.into())
}
}
impl From<String> for ForeignSymbol {
fn from(string: String) -> Self {
Self(string.into())
}
}
impl Uppercase {
pub fn as_str(&self) -> &str {
self.0.as_str()
}
pub fn as_ident_str(&self) -> &IdentStr {
&self.0
}
}
impl<'a> From<&'a str> for Uppercase {
fn from(string: &'a str) -> Self {
Self(string.into())
}
}
impl From<String> for Uppercase {
fn from(string: String) -> Self {
Self(string.into())
}
}
impl Lowercase {
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl From<Lowercase> for String {
fn from(lowercase: Lowercase) -> Self {
lowercase.0.into()
}
}
impl From<Lowercase> for Box<str> {
fn from(lowercase: Lowercase) -> Self {
let string: String = lowercase.0.into();
string.into()
}
}
impl<'a> From<&'a str> for Lowercase {
fn from(string: &'a str) -> Self {
Self(string.into())
}
}
impl<'a> From<&'a Lowercase> for &'a str {
fn from(lowercase: &'a Lowercase) -> Self {
lowercase.as_str()
}
}
impl From<String> for Lowercase {
fn from(string: String) -> Self {
Self(string.into())
}
}
impl AsRef<str> for Ident {
#[inline(always)]
fn as_ref(&self) -> &str {
self.0.as_str()
}
}
impl<'a> From<&'a str> for Ident {
fn from(string: &'a str) -> Self {
Self(string.into())
}
}
impl From<Box<str>> for Ident {
fn from(string: Box<str>) -> Self {
Self((string.as_ref()).into())
}
}
impl From<String> for Ident {
fn from(string: String) -> Self {
Self(string.into())
}
}
impl From<IdentStr> for Ident {
fn from(string: IdentStr) -> Self {
Self(string)
}
}
impl From<Ident> for IdentStr {
fn from(ident: Ident) -> Self {
ident.0
}
}
impl<'a> From<&'a Ident> for &'a IdentStr {
fn from(ident: &'a Ident) -> Self {
&ident.0
}
}
impl From<Ident> for Box<str> {
fn from(ident: Ident) -> Self {
ident.0.to_string().into()
}
}
impl fmt::Display for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
/// Rather than displaying as this:
///
/// Lowercase("foo")
///
/// ...instead display as this:
///
/// 'foo'
impl fmt::Debug for Lowercase {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "'{}'", self.0)
}
}
impl fmt::Display for Lowercase {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
/// Rather than displaying as this:
///
/// Uppercase("Foo")
///
/// ...instead display as this:
///
/// 'Foo'
impl fmt::Debug for Uppercase {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "'{}'", self.0)
}
}
impl fmt::Display for Uppercase {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}