Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
56f51ad
Test reload_paths
Imberflur Sep 11, 2025
83598ab
Fix reload_paths overwriting the wrong file in certain cases where ne…
Imberflur Sep 11, 2025
00c01fb
Rename filter to iter_all_children and remove filtering closure in favor
Imberflur Sep 24, 2025
6e5dce3
Move private parse function from crate root to method on BaubleContext
Imberflur Sep 24, 2025
28c7568
Rename walk to node_at and return reference to node instead of accepting
Imberflur Sep 24, 2025
3650d56
Fix walk_find not always returning None when the path doesnt fully ex…
Imberflur Sep 24, 2025
8bae07e
Simplify skipping logic in reload_files and add note about potential bug
Imberflur Sep 24, 2025
53c8316
Rename ref_kinds to refs_of_kind to better reflect functionality
Imberflur Sep 24, 2025
b72674a
Add notes and make minor improvements to bauble_test macro. Including…
Imberflur Sep 24, 2025
ce4ee17
Remove type aliases that only appear in a few places
Imberflur Sep 24, 2025
daf6e0e
fmt
Imberflur Sep 24, 2025
f1f1fd7
More documentation and notes in the code
Imberflur Sep 24, 2025
4099dd1
Minor code edits (no functionality change)
Imberflur Sep 24, 2025
ddd551d
Various TODOs
Imberflur Sep 24, 2025
f5e1041
Duplicate object paths test
Imberflur Sep 19, 2025
0c0520e
Add test for empty modules and default uses
Imberflur Sep 23, 2025
30702dc
More CtxNode documentation and improve readability
Imberflur Sep 23, 2025
ca422e4
Remove obsolete default_uses code and add note explaining how adding …
Imberflur Sep 23, 2025
c4965a1
Add rustfmt.toml so vim autofmt will use the right edition
Imberflur Sep 24, 2025
002c42f
Add test for case where some files fail to load while others succeed
Imberflur Sep 24, 2025
09ceea8
Fix mismatch in zip when some files fail to load
Imberflur Sep 24, 2025
80e6166
Fix typos
Imberflur Oct 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
354 changes: 194 additions & 160 deletions bauble/src/context.rs

Large diffs are not rendered by default.

68 changes: 28 additions & 40 deletions bauble/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,16 @@ pub mod types;
pub use bauble_macros::Bauble;

pub use context::{BaubleContext, BaubleContextBuilder, FileId, PathReference, Source};
pub use error::{print_errors, BaubleError, BaubleErrors, CustomError, Level};
pub use error::{BaubleError, BaubleErrors, CustomError, Level, print_errors};
pub use spanned::{Span, SpanExt, Spanned};
pub use traits::{
Bauble, BaubleAllocator, DefaultAllocator, ToRustError, ToRustErrorKind, VariantKind,
};
pub use types::path;
pub use value::{
compare_object_sets, display_formatted, AdditionalUnspannedObjects, Attributes,
CompareObjectsError, ConversionError, DisplayConfig, Fields, FieldsKind, IndentedDisplay, Map,
Object, PrimitiveValue, Sequence, SpannedValue, UnspannedVal, Val, Value, ValueContainer,
ValueTrait,
AdditionalUnspannedObjects, Attributes, CompareObjectsError, ConversionError, DisplayConfig,
Fields, FieldsKind, IndentedDisplay, Map, Object, PrimitiveValue, Sequence, SpannedValue,
UnspannedVal, Val, Value, ValueContainer, ValueTrait, compare_object_sets, display_formatted,
};

// re-exporting crates from other crates
Expand All @@ -69,32 +68,14 @@ pub mod private {
pub use indexmap::IndexMap;
}

use parse::ParseValues;

fn parse(file_id: FileId, ctx: &BaubleContext) -> Result<ParseValues, BaubleErrors> {
use chumsky::Parser;

let parser = parse::parser();
let result = parser.parse(parse::ParserSource { file_id, ctx });

result.into_result().map_err(|errors| {
BaubleErrors::from(
errors
.into_iter()
.map(|e| e.into_owned())
.collect::<Vec<_>>(),
)
})
}

// TODO(@docs)
#[allow(missing_docs)]
#[macro_export]
macro_rules! bauble_test {
( [$($ty:ty),* $(,)?] $source:literal [$($expr:expr),* $(,)?]) => {
$crate::bauble_test!(__TEST_CTX [$($ty),*] $source [$($expr),*])
( [$($ty:ty),* $(,)?] $source:literal [$($test_value:expr),* $(,)?]) => {
$crate::bauble_test!(__TEST_CTX [$($ty),*] $source [$($test_value),*])
};
($ctx_static:ident [$($ty:ty),* $(,)?] $source:literal [$($expr:expr),* $(,)?]) => {
($ctx_static:ident [$($ty:ty),* $(,)?] $source:literal [$($test_value:expr),* $(,)?]) => {
static $ctx_static: std::sync::OnceLock<std::sync::RwLock<$crate::BaubleContext>> = std::sync::OnceLock::new();
{
let file_path = $crate::path::TypePath::new("test").unwrap();
Expand All @@ -110,14 +91,15 @@ macro_rules! bauble_test {
std::sync::RwLock::new(ctx)
});

// Test initial parsing from source
let (objects, errors) = ctx.write().unwrap().load_all();

if !errors.is_empty() {
$crate::print_errors(Err::<(), _>(errors), &ctx.read().unwrap());

panic!("Error converting");
}

// Test round-trip of objects through source format
let re_source = $crate::display_formatted(objects.as_slice(), ctx.read().unwrap().type_registry(), &$crate::DisplayConfig {
..$crate::DisplayConfig::default()
});
Expand All @@ -126,29 +108,35 @@ macro_rules! bauble_test {

if !errors.is_empty() {
$crate::print_errors(Err::<(), _>(errors), &ctx.read().unwrap());

println!("{re_source}");

eprintln!("{re_source}");
panic!("Error re-converting");
}

assert_eq!(objects, re_objects);

// Test that original parsed objects and round-trip objects convert into typed values
// that match the provided test values.
let compare_objects = |mut objects: Vec<$crate::Object>| {
let mut objects = objects.into_iter();

$(
let value = objects.next().expect("Not as many objects as test expr in bauble test?");
let mut read_value = $expr;
let test_value = ::std::mem::replace(&mut read_value, $crate::print_errors(Bauble::from_bauble(value.value, &::bauble::DefaultAllocator), &ctx.read().unwrap()).unwrap());


assert_eq!(
read_value,
test_value,
);
// Infer type for `read_value` to be the same as `test_value`.
let [test_value, read_value] = [
$test_value,
$crate::print_errors(
$crate::Bauble::from_bauble(value.value, &$crate::DefaultAllocator),
&ctx.read().unwrap()
).unwrap(),
];

assert_eq!(read_value, test_value);
)*
};

assert_eq!(objects, re_objects);
if objects.next().is_some() {
panic!("More objects in bauble test than test expr?");
}
};

compare_objects(objects);
compare_objects(re_objects);
Expand Down
2 changes: 1 addition & 1 deletion bauble/src/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ pub fn parser<'a>() -> impl Parser<'a, ParserSource<'a>, ParseValues, Extra<'a>>
'{',
'}',
[('[', ']'), ('(', ')')],
|_| crate::parse::Fields::new(),
|_| IndexMap::<Ident, ParseVal>::new(),
)));

let reference = just('$').ignore_then(path).map(|path| {
Expand Down
16 changes: 5 additions & 11 deletions bauble/src/parse/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@ use crate::{
};
use indexmap::IndexMap;

pub type Fields = IndexMap<Ident, ParseVal>;

pub type Use = Spanned<PathTreeNode>;

#[derive(Clone, Debug, PartialEq)]
pub enum PathEnd {
// TODO: document how this syntax works?
/// path::*::ident
WithIdent(Ident),
/// path::ident
Expand Down Expand Up @@ -77,7 +74,7 @@ impl fmt::Debug for Path {

#[derive(Debug)]
pub enum PathTreeEnd {
Group(Vec<Use>),
Group(Vec<Spanned<PathTreeNode>>),
Everything,
PathEnd(PathEnd),
}
Expand All @@ -88,14 +85,11 @@ pub struct PathTreeNode {
pub end: Spanned<PathTreeEnd>,
}

pub type Attributes = crate::value::Attributes<ParseVal>;
pub type Value = crate::Value<ParseVal>;

#[derive(Debug, Clone)]
pub struct ParseVal {
pub ty: Option<Path>,
pub attributes: Spanned<Attributes>,
pub value: Spanned<Value>,
pub attributes: Spanned<crate::Attributes<ParseVal>>,
pub value: Spanned<crate::Value<ParseVal>>,
}

impl ValueTrait for ParseVal {
Expand Down Expand Up @@ -149,7 +143,7 @@ pub struct Binding {

#[derive(Debug)]
pub struct ParseValues {
pub uses: Vec<Use>,
pub uses: Vec<Spanned<PathTreeNode>>,
pub values: IndexMap<Ident, Binding>,
pub copies: IndexMap<Ident, Binding>,
}
5 changes: 3 additions & 2 deletions bauble/src/spanned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ use std::{
use crate::context::FileId;

/// Represents a span in the parsed source of the Bauble context.
/// This type correspond to the byte offset of the first character and the byte offset of the last character
/// in a file.
///
/// This type corresponds to the byte offset in a file of the first character and the byte offset
/// just past the last character.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Span {
/// The offset to the first character covered by the span.
Expand Down
10 changes: 5 additions & 5 deletions bauble/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub mod path;
use indexmap::IndexMap;
use path::{TypePath, TypePathElem};

use crate::{value::UnspannedVal, AdditionalUnspannedObjects, Bauble, BaubleAllocator};
use crate::{AdditionalUnspannedObjects, Bauble, BaubleAllocator, value::UnspannedVal};

#[allow(missing_docs)]
pub type Extra = IndexMap<String, String>;
Expand Down Expand Up @@ -276,7 +276,7 @@ impl TypeRegistry {

// The element at index 0 is always any trait
let any_trait = this.get_or_register_trait::<dyn std::any::Any>();
this.types[any_trait.0 .0].kind = TypeKind::Trait(TypeSet(SealedTypeSet::All));
Comment thread
Imberflur marked this conversation as resolved.
this.types[any_trait.0.0].kind = TypeKind::Trait(TypeSet(SealedTypeSet::All));

// The element at index 1 is any trait.
let any_id = this.get_or_register_type::<crate::Val, crate::DefaultAllocator>();
Expand Down Expand Up @@ -445,7 +445,7 @@ impl TypeRegistry {

fn on_register_type(&mut self, id: TypeId, ty: &mut Type) {
for tr in ty.meta.traits.iter() {
let TypeKind::Trait(types) = &mut self.types[tr.0 .0].kind else {
let TypeKind::Trait(types) = &mut self.types[tr.0.0].kind else {
panic!("Invariant")
};

Expand Down Expand Up @@ -517,7 +517,7 @@ impl TypeRegistry {
}

if let Some(ty) = ty.meta.generic_base_type {
let TypeKind::Generic(types) = &mut self.types[ty.0 .0].kind else {
let TypeKind::Generic(types) = &mut self.types[ty.0.0].kind else {
panic!("`generic_base_type` pointing to a type that isn't `TypeKind::Generic`")
};

Expand Down Expand Up @@ -756,7 +756,7 @@ impl TypeRegistry {
pub fn add_trait_dependency(&mut self, ty: TypeId, tr: TraitId) {
self.types[ty.0].meta.traits.push(tr);

let TypeKind::Trait(tr) = &mut self.types[tr.0 .0].kind else {
let TypeKind::Trait(tr) = &mut self.types[tr.0.0].kind else {
unreachable!("Invariant");
};

Expand Down
58 changes: 29 additions & 29 deletions bauble/src/value/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ pub(super) fn value_type(value: &ParseVal, symbols: &Symbols) -> Result<Option<S
return Ok(Some(symbols.resolve_type(ty)?.spanned(ty.span())));
};

let ty = match &value.value.value {
let ty = match &*value.value {
Value::Ref(path) => {
// Don't resolve types of copy types.
if let Some(ident) = path.as_ident()
Expand Down Expand Up @@ -1021,36 +1021,36 @@ where
if matches!(f, FieldsKind::Unit) {
if let Some(val_type) = raw_val_type {
match &types.key_type(val_type.value).kind {
types::TypeKind::EnumVariant {
variant,
enum_type,
fields,
} => {
debug_assert!(matches!(fields, types::Fields::Unit));
debug_assert_eq!(*enum_type, *ty_id);
debug_assert!(variants.variants.contains(variant));
types::TypeKind::EnumVariant {
variant,
enum_type,
fields,
} => {
debug_assert!(matches!(fields, types::Fields::Unit));
debug_assert_eq!(*enum_type, *ty_id);
debug_assert!(variants.variants.contains(variant));

Value::Or(vec![variant.clone().spanned(span)])
}

Value::Or(vec![variant.clone().spanned(span)])
types::TypeKind::Generic(generic) => types
.iter_type_set(generic)
.next()
.map(|t| {
if let types::TypeKind::EnumVariant { variant, .. } =
&types.key_type(t).kind
{
Value::Or(vec![variant.clone().spanned(span)])
} else {
unreachable!(
"Our type checking should make sure this can't happen"
)
}
})
.expect("Our type checking should make sure this can't happen"),

_ => Err(expected_err())?,
}

types::TypeKind::Generic(generic) => types
.iter_type_set(generic)
.next()
.map(|t| {
if let types::TypeKind::EnumVariant { variant, .. } =
&types.key_type(t).kind
{
Value::Or(vec![variant.clone().spanned(span)])
} else {
unreachable!(
"Our type checking should make sure this can't happen"
)
}
})
.expect("Our type checking should make sure this can't happen"),

_ => Err(expected_err())?,
}
} else {
Err(expected_err())?
}
Expand Down
4 changes: 2 additions & 2 deletions bauble/src/value/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
use std::{borrow::Borrow, collections::HashMap};

use crate::{
parse::{allowed_in_raw_literal, ParseVal, ParseValues, PathTreeEnd, PathTreeNode},
Spanned,
parse::{ParseVal, ParseValues, PathTreeEnd, PathTreeNode, allowed_in_raw_literal},
path::TypePath,
types::{TypeKind, TypeRegistry},
Spanned,
};

use super::{Attributes, FieldsKind, Object, UnspannedVal, Val, Value, ValueContainer, ValueTrait};
Expand Down
6 changes: 3 additions & 3 deletions bauble/src/value/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ impl BaubleError for Spanned<ConversionError> {
match &ref_err.path {
PathKind::Direct(path) => {
let options = ctx
.ref_kinds(TypePath::empty(), ref_err.kind, None)
.refs_of_kind(TypePath::empty(), ref_err.kind, None)
.map(|p| p.into_inner());
if path.len() == 1
&& let Some(uses) = &ref_err.uses
Expand Down Expand Up @@ -604,7 +604,7 @@ impl BaubleError for Spanned<ConversionError> {
}
PathKind::Indirect(module, ident) => {
if let Some(suggestions) = get_suggestions(
ctx.ref_kinds(module.borrow(), ref_err.kind, None)
ctx.refs_of_kind(module.borrow(), ref_err.kind, None)
.filter_map(|s| {
s.split_end()
.map(|(_, ident)| format!("{module}::*::{ident}"))
Expand Down Expand Up @@ -673,7 +673,7 @@ impl BaubleError for Spanned<ConversionError> {
&& ident.len() == 1
{
let suggestions = ctx
.ref_kinds(TypePath::empty(), ref_err.kind, None)
.refs_of_kind(TypePath::empty(), ref_err.kind, None)
.filter(|path| path.ends_with(ident.borrow()))
.map(|path| format!("`{path}`"))
.collect::<Vec<_>>();
Expand Down
Loading
Loading