tamer: sym::prefill: Initial typed static symbol concept

We'll see how the syntax evolves over time.  It's not ideal to have to
specify the type, rather than having the compiler infer it, but I don't much
feel like getting into my first procedural macro right now, so we'll stick
with this approach for the time being.

This will set the stage to be able to safely e.g. create QNames statically
at compile-time and would allow us to make any attempts to bypass it
unsafe.
main
Mike Gerwitz 2021-09-23 00:37:39 -04:00
parent b972b0b202
commit ed245bb099
1 changed files with 92 additions and 13 deletions

View File

@ -29,20 +29,22 @@
use super::{Interner, SymbolId, SymbolIndexSize};
use crate::global;
use std::array;
use std::ops::Deref;
/// A size that is as small as possible to hold the necessary number of
/// values.
type StaticSymbolSize = u8;
/// Statically-allocated symbol.
///
/// This symbol is generated at compile-time and expected to be available in
/// any global interner once it has been initialized.
///
/// The size of this symbol is as small as possible to hold the necessary
/// number of values.
///
/// This symbol contains a number of `const` methods,
/// allowing for this symbol to be easily used to construct static
/// newtypes.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StaticSymbolId(u8);
pub struct StaticSymbolId(StaticSymbolSize);
impl StaticSymbolId {
/// Cast static symbol into a [`SymbolId`] suitable for the global
@ -88,6 +90,55 @@ impl From<StaticSymbolId> for SymbolId<global::PkgSymSize> {
}
}
/// Generate a newtype containing a [`StaticSymbolId`] that derefs to its
/// inner value.
macro_rules! static_symbol_newtype {
($(#[$attr:meta])* $name:ident) => {
$(#[$attr])*
#[doc=""]
#[doc="This will [`Deref`] into a [`StaticSymbolId`]."]
pub struct $name(StaticSymbolId);
impl $name {
const fn new(id: StaticSymbolSize) -> Self {
Self(StaticSymbolId(id))
}
}
impl Deref for $name {
type Target = StaticSymbolId;
fn deref(&self) -> &Self::Target {
&self.0
}
}
};
}
/// Generate a series of newtypes and the macro `static_symbol_ty!` which
/// can be used to take a short identifier and convert it into its full
/// type identifier.
macro_rules! static_symbol_newtypes {
($($(#[$attr:meta])* $short:ident: $ty:ident),*) => {
$(
static_symbol_newtype!($(#[$attr])* $ty);
)*
macro_rules! static_symbol_ty {
$(
($short) => {
$ty
};
)*
// Just some string value; a misc case.
(str) => {
StaticSymbolId
};
}
}
}
/// Generate symbols of size [`global::ProgSymSize`] for preinterned strings.
///
/// These symbols,
@ -98,10 +149,17 @@ impl From<StaticSymbolId> for SymbolId<global::PkgSymSize> {
/// which is on first access,
/// these symbols will reference valid values.
macro_rules! static_symbol_consts {
(@i $i:expr; $name:ident: $str:expr, $($ti:ident: $ts:expr,)*) => {
#[doc=concat!("Interned string `\"", $str, "\"`.")]
(@i $i:expr; $name:ident: $ty:ident $str:expr, $($tail:tt)*) => {
#[doc=concat!(
"Interned `",
stringify!($ty),
"` string `\"",
$str,
"\"`."
)]
#[allow(non_upper_case_globals)]
pub const $name: StaticSymbolId = StaticSymbolId($i);
pub const $name: static_symbol_ty!($ty) =
<static_symbol_ty!($ty)>::new($i);
// Recurse until no tail is left (terminating condition below).
static_symbol_consts!{
@ -110,7 +168,7 @@ macro_rules! static_symbol_consts {
// which time we may have to switch methodology.
@i $i + 1;
$($ti: $ts,)*
$($tail)*
}
};
@ -128,7 +186,7 @@ macro_rules! static_symbol_consts {
/// immediately after initialization,
/// /before/ any internment requests.
macro_rules! static_symbols {
($($name:ident : $str:expr),*) => {
($($name:ident : $ty:ident $str:expr),*) => {
/// Static symbols (pre-allocated).
///
/// Each of the constants in this module represent a [`SymbolId`]
@ -136,6 +194,14 @@ macro_rules! static_symbols {
/// The strings that they represent are automatically populated into
/// the global interners when the interner is first accessed.
///
/// _You should always use the generated constant to reference these
/// symbols!_
/// Do not rely upon their integer value,
/// as it _will_ change over time.
/// The sole exception is to use marker symbols to identify ranges
/// of symbols;
/// see [`MarkStaticSymbolId`].
///
/// See [`crate::sym`] for more information on static symbols.
///
/// `static` is a keyword in Rust,
@ -148,7 +214,7 @@ macro_rules! static_symbols {
@i 1;
$(
$name: $str,
$name: $ty $str,
)*
}
}
@ -184,6 +250,19 @@ macro_rules! static_symbols {
}
}
static_symbol_newtypes! {
/// A symbol suitable as a C-style identifier.
///
/// This is the traditional `[a-zA-Z_][a-zA-Z0-9_]*`,
/// common in many programming languages.
cid: CIdentStaticSymbolId,
/// This symbol serves only as a marker in the internment pool to
/// delimit symbol ranges;
/// its string value is incidental and should not be relied upon.
mark: MarkStaticSymbolId
}
// Static symbols that will have their strings interned upon global
// interner initialization.
//
@ -213,13 +292,13 @@ macro_rules! static_symbols {
// which is re-exported by the parent module.
static_symbols! {
// Index begins at 1, since 0 is reserved during interner initialization
True: "true",
False: "false",
True: cid "true",
False: cid "false",
// [Symbols will be added here as they are needed.]
// Marker indicating the end of the static symbols
END_STATIC: "{{end static}}"
END_STATIC: mark "{{end static}}"
}
#[cfg(test)]