Skip to content

Commit

Permalink
Move core to workspace crate rune-core
Browse files Browse the repository at this point in the history
It's key to note that in the process, we include different changes that
guide the build process of the crates, in order to arrive at a place
that is both ergonomic and easy to maintain:

We removed the `defvar`, `defvar_bool` and `defsym` macros. They were
not adding that much regarding work saved (just create a constant and
initialize it) and they were convoluting the dependency graph between
the crates. It's key that the core crate can use the symbols that were
previously generated on the build.rs file, but it does not need to know
the defuns.

For that, we moved the variables and symbols (not the defun symbols) to
a static file `env/sym.rs`. That file contains all the required
constants for the variables and symbols.

On the other hand, the defun symbols and constants are still generated
with the build script, to avoid loosing the convenience of defining the
functions with the `defun` proc macro.

Additionally, the macros were moved into their own module:
`rune_core::macros`, by re-exporting the now privately named macros. The
motivation behind it is that we need to access macros by name that may
conflict with other modules with the same name. An example of that is
the `error` module, which we import with self. The `error!` macro needs
to be imported as well, but a conflict arises. Now, we can import the
macro with `use rune_core::macros::error` and the module with `use rune_core::error`.
  • Loading branch information
Qkessler committed Dec 9, 2023
1 parent 9dc25ab commit 17ac7d0
Show file tree
Hide file tree
Showing 58 changed files with 1,415 additions and 1,306 deletions.
56 changes: 36 additions & 20 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,65 @@ edition = "2021"
[workspace]
members = [
"crates/text-buffer",
"crates/rune-macros"
"crates/rune-macros",
"crates/rune-core"
]

[workspace.dependencies]
quote = "1.0.26"
syn = { version = "2.0.15", features = ["full"]}

[workspace.package]
edition = "2021"

[dependencies]
[workspace.dependencies]
syn = { version = "2.0.15", features = ["full"] }
quote = "1.0.26"
proc-macro2 = "1.0.60"
anyhow = "1.0.69"
sptr = "0.3.2"
fallible-iterator = "0.3.0"
fallible-streaming-iterator = "0.1.9"
fxhash = "0.2.1"
indexmap = "2.1.0"
memoffset = "0.9.0"
bstr = "1.3.0"
float-cmp = "0.9.0"

text-buffer = { version = "0.1.0", path = "crates/text-buffer" }
rune-core = { version = "0.1.0", path = "crates/rune-core" }
rune-macros = { version = "0.1.0", path = "crates/rune-macros" }

[dependencies]
anyhow = { workspace = true }
bstr = { workspace = true }
bytecount = "0.6.3"
druid = "0.8.3"
fancy-regex = "0.12.0"
float-cmp = "0.9.0"
float-cmp = { workspace = true }
hostname = "0.3.1"
memoffset = "0.9.0"
memoffset = { workspace = true }
num_enum = "0.7.1"
paste = "1.0.12"
rand = "0.8.5"
rune-macros = { version = "0.1.0", path = "crates/rune-macros" }
sptr = "0.3.2"
sptr = { workspace = true }
streaming-iterator = "0.1.9"
text-buffer = { version = "0.1.0", path = "crates/text-buffer" }
titlecase = "2.2.1"
fallible-iterator = "0.3.0"
fallible-streaming-iterator = "0.1.9"
indexmap = "2.1.0"
fxhash = "0.2.1"
fallible-iterator = { workspace = true }
fallible-streaming-iterator = { workspace = true }
indexmap = { workspace = true }
fxhash = { workspace = true }

text-buffer = { workspace = true }
rune-macros = { workspace = true }
rune-core = { workspace = true }

[target.'cfg(not(target_env = "msvc"))'.dependencies]
tikv-jemallocator = "0.5"

# [dev-dependencies]
# backtrace-on-stack-overflow = "0.3.0"

[build-dependencies]
syn = { workspace = true }
quote = { workspace = true }

[profile.dev.build-override]
opt-level = 3

Expand All @@ -58,11 +79,6 @@ debug = true
default = []
debug_bytecode = []

[build-dependencies]
quote = { workspace = true}
syn = { workspace = true }
proc-macro2 = "1.0.60"

[workspace.lints.rust]
macro_use_extern_crate = "deny"
keyword_idents = "deny"
Expand Down
192 changes: 17 additions & 175 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,44 +32,20 @@ where
&contents[start_idx..end_idx]
}

fn map_varname(ident: &str) -> String {
if let Some(stripped) = ident.strip_prefix("KW_") {
convert(':', stripped)
} else {
convert("", ident)
}
}

fn convert(lisp_name: impl Into<String>, rust_name: &str) -> String {
let mut lisp_name = lisp_name.into();
lisp_name.extend(rust_name.chars().map(|c| match c {
'_' => '-',
c => c.to_ascii_lowercase(),
}));
lisp_name
}

#[derive(PartialEq)]
enum DefvarType {
Bool,
Other,
}

#[allow(clippy::too_many_lines)]
fn main() {
let mut all_defun = Vec::new();
let mut all_defvar = Vec::new();
let mut all_defsym = Vec::new();
let src_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("src");

// rerun for all top level files
for entry in fs::read_dir("src").unwrap() {
for entry in fs::read_dir(&src_dir).unwrap() {
let path = entry.unwrap().path();
if path.extension().and_then(OsStr::to_str) == Some("rs") {
println!("cargo:rerun-if-changed={}", path.display());
}
}

for entry in fs::read_dir("src").unwrap() {
for entry in fs::read_dir(&src_dir).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
if path.is_file() {
Expand All @@ -87,94 +63,36 @@ fn main() {
};
// convert the path name to a hierarchy name with slashes replaced with colons
let struct_name = {
let basename = path.strip_prefix("src/").unwrap().file_stem().unwrap();
let import_path = basename.to_str().unwrap().replace(MAIN_SEPARATOR, ":");
let file_without_extension = path.file_stem().expect("file name to work");
let import_path =
file_without_extension.to_str().unwrap().replace(MAIN_SEPARATOR, ":");
format!("crate::{import_path}::__subr_{name}")
};
all_defun.push((struct_name, name.to_string(), lisp_name));
}
// process all strings starting with defvar
for (start, _) in contents.match_indices("\ndefvar") {
let defvar_type = if contents[start..].starts_with("\ndefvar_bool!") {
DefvarType::Bool
} else if contents[start..].starts_with("\ndefvar!") {
DefvarType::Other
} else {
continue;
};
let body = get_substring_between(&contents[start..], "!", ";");
let args = parse_args(body);
let len = args.len();
let mut fields = args.into_iter();
let ident = fields.next().unwrap();
let (ident, name, value) = match len {
1 => {
let name = map_varname(&ident);
(ident, name, None)
}
2 => {
let name = map_varname(&ident);
let value = fields.next().unwrap();
(ident, name, Some(value))
}
3 => {
let name = fields.next().unwrap();
let value = fields.next().unwrap();
(ident, name, Some(value))
}
_ => panic!("defvar form was too long {path:?}"),
};
all_defvar.push((ident, name, value, defvar_type));
}

// process all strings starting with defsym
for (start, _) in contents.match_indices("\ndefsym!") {
let body = get_substring_between(&contents[start..], "defsym!", ";");
let args = parse_args(body);
let mut fields = args.into_iter();
let name = fields.next().unwrap();
let value = fields.next();
all_defsym.push((name, value));
}
}
}

let out_dir = std::env::var("OUT_DIR").unwrap();
// println!("cargo:warning={out_dir}/sym.rs");
let dest_path = Path::new(&out_dir).join("sym.rs");
let dest_path = Path::new(&out_dir).join("defun.rs");
let mut f = File::create(dest_path).unwrap();

let symbol_len = all_defsym.len() + all_defun.len() + all_defvar.len() + 2;
writeln!(
f,
"
#[allow(non_upper_case_globals)]
#[allow(non_snake_case)]
#[allow(dead_code)]
pub(crate) mod sym {{
use crate::core::env::SymbolCell;
use crate::core::env::Symbol;
pub(crate) mod defun {{
use rune_core::env::SymbolCell;
use rune_core::env::Symbol;
pub(super) static BUILTIN_SYMBOLS: [SymbolCell; {symbol_len}] = [
SymbolCell::new_const(\"nil\"),
SymbolCell::new_const(\"t\"),",
/// Contains all the dynamically generated symbols for `#[defun]` marked functions.
pub(super) static DEFUN_SYMBOLS: [SymbolCell; {}] = [",
all_defun.len()
)
.unwrap();

// write the list of all defsym to the file
for (sym, name) in &all_defsym {
let sym_name = match name {
Some(name) => name.trim_matches('"').to_string(),
None => map_varname(sym),
};
writeln!(f, " SymbolCell::new(\"{sym_name}\"),").unwrap();
}

for (_, name, _, _) in &all_defvar {
#[rustfmt::skip]
writeln!(f, " SymbolCell::new_special(\"{name}\"),").unwrap();
}

// write the list of all defun to a file in out_dir
for (_, _, lisp_name) in &all_defun {
#[rustfmt::skip]
Expand All @@ -184,34 +102,26 @@ pub(super) static BUILTIN_SYMBOLS: [SymbolCell; {symbol_len}] = [
// End BUILTIN_SYMBOLS
writeln!(f, "];\n").unwrap();

let special = ["nil".to_owned(), "true".to_owned()];
let all_elements = special
.iter()
.chain(all_defsym.iter().map(|x| &x.0))
.chain(all_defvar.iter().map(|x| &x.0))
.chain(all_defun.iter().map(|x| &x.1))
.enumerate();
for (idx, element) in all_elements {
for (idx, element) in all_defun.iter().map(|x| &x.1).enumerate() {
let sym_name = element.to_ascii_uppercase();
#[rustfmt::skip]
writeln!(f, "pub(crate) const {sym_name}: Symbol = Symbol::new_builtin({idx});").unwrap();
}

// all SubrFn
let subr_len = all_defun.len();
writeln!(f, "static SUBR_DEFS: [&crate::core::object::SubrFn; {subr_len}] = [",).unwrap();
writeln!(f, "static SUBR_DEFS: [&rune_core::object::SubrFn; {subr_len}] = [",).unwrap();
for (subr_name, _, _) in &all_defun {
writeln!(f, " &{subr_name},",).unwrap();
}
// End SUBR_DEFS
writeln!(f, "];\n").unwrap();

let defun_start = symbol_len - subr_len;
writeln!(
f,
"
pub(crate) fn init_symbols() {{
for (sym, func) in BUILTIN_SYMBOLS[{defun_start}..].iter().zip(SUBR_DEFS.iter()) {{
pub(crate) fn init_defun() {{
for (sym, func) in DEFUN_SYMBOLS.iter().zip(SUBR_DEFS.iter()) {{
unsafe {{ sym.set_func((*func).into()).unwrap(); }}
}}
}}
Expand All @@ -220,72 +130,4 @@ pub(crate) fn init_symbols() {{
.unwrap();
// End mod sym
writeln!(f, "}}").unwrap();

writeln!(
f,
"
/// TODO: Use `LazyLock`: https://github.com/CeleritasCelery/rune/issues/34
use std::sync::OnceLock;
static INTERNED_SYMBOLS: OnceLock<Mutex<ObjectMap>> = OnceLock::new();
pub(crate) fn interned_symbols() -> &'static Mutex<ObjectMap> {{
INTERNED_SYMBOLS.get_or_init(|| Mutex::new({{
let size: usize = {symbol_len};
let mut map = SymbolMap::with_capacity(size);
for sym in &sym::BUILTIN_SYMBOLS {{
map.pre_init(Symbol::new(sym));
}}
ObjectMap {{
map,
block: Block::new_global(),
}}
}}))
}}
"
)
.unwrap();

writeln!(
f,
"
#[allow(unused_qualifications)]
pub(crate) fn init_variables(
cx: &crate::core::gc::Context,
env: &mut crate::core::gc::Rt<crate::core::env::Env>,
) {{
use crate::core::object::Object;
"
)
.unwrap();

let mut bool_vars = Vec::new();

// write out the value of each defvar
for (ident, _, value, ty) in all_defvar {
// handled below
if ident == "BYTE_BOOLEAN_VARS" {
continue;
}
let mut value = value.unwrap_or_else(|| "Object::NIL".to_string());

// if value starts with list! then insert cx before that last character
if value.starts_with("list") {
let len = value.len();
value.insert_str(len - 1, "; cx");
}
writeln!(f, "env.vars.insert(sym::{ident}, cx.add({value}));").unwrap();
if DefvarType::Bool == ty {
bool_vars.push(ident);
}
}

// write out the boolean vars
writeln!(f, "let bool_vars = list![").unwrap();
for ident in bool_vars {
writeln!(f, " sym::{ident},").unwrap();
}
writeln!(f, "; cx];").unwrap();
writeln!(f, "env.vars.insert(sym::BYTE_BOOLEAN_VARS, bool_vars);").unwrap();

writeln!(f, "}}").unwrap();
}
24 changes: 24 additions & 0 deletions crates/rune-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "rune-core"
version = "0.1.0"
description = "Core functionality of the Rune Emacs Runtime."
edition.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = { workspace = true }
bstr = { workspace = true }
sptr = { workspace = true }
fallible-iterator = { workspace = true }
fallible-streaming-iterator = { workspace = true }
float-cmp = { workspace = true }
fxhash = { workspace = true }
indexmap = { workspace = true }
memoffset = { workspace = true }

rune-macros = { workspace = true }
text-buffer = { workspace = true }

[lints]
workspace = true
Loading

0 comments on commit 17ac7d0

Please sign in to comment.