use std::sync::Arc; | |
use crate::{interner::Interner, values::*}; | |
#[salsa::query_group(CompilerDatabase)] | |
pub trait Compiler: Interner { | |
#[salsa::input] | |
fn input_string(&self) -> Arc<String>; | |
/// Get the fields. | |
fn fields(&self, class: Class) -> Arc<Vec<Field>>; | |
/// Get the list of all classes | |
fn all_classes(&self) -> Arc<Vec<Class>>; | |
/// Get the list of all fields | |
fn all_fields(&self) -> Arc<Vec<Field>>; | |
} | |
/// This function parses a dummy language with the following structure: | |
/// | |
/// Classes are defined one per line, consisting of a comma-separated list of fields. | |
/// | |
/// Example: | |
/// | |
/// ``` | |
/// lorem,ipsum | |
/// dolor,sit,amet, | |
/// consectetur,adipiscing,elit | |
/// ``` | |
fn all_classes(db: &dyn Compiler) -> Arc<Vec<Class>> { | |
let string = db.input_string(); | |
let rows = string.split('\n'); | |
let classes: Vec<_> = rows | |
.filter(|string| !string.is_empty()) | |
.map(|string| { | |
let fields = string | |
.trim() | |
.split(',') | |
.filter(|string| !string.is_empty()) | |
.map(|name_str| { | |
let name = name_str.to_owned(); | |
let field_data = FieldData { name }; | |
db.intern_field(field_data) | |
}) | |
.collect(); | |
let class_data = ClassData { fields }; | |
db.intern_class(class_data) | |
}) | |
.collect(); | |
Arc::new(classes) | |
} | |
fn fields(db: &dyn Compiler, class: Class) -> Arc<Vec<Field>> { | |
let class = db.lookup_intern_class(class); | |
Arc::new(class.fields) | |
} | |
fn all_fields(db: &dyn Compiler) -> Arc<Vec<Field>> { | |
Arc::new( | |
db.all_classes() | |
.iter() | |
.cloned() | |
.flat_map(|class| { | |
let fields = db.fields(class); | |
(0..fields.len()).map(move |i| fields[i]) | |
}) | |
.collect(), | |
) | |
} |