Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ anathema-testutils = { path = "anathema-testutils" }

[features]
default = []
profile = ["anathema-runtime/profile", "anathema-widgets/profile", "anathema-backend/profile", "anathema-value-resolver/profile"]
profile = [
"anathema-runtime/profile",
"anathema-widgets/profile",
"anathema-backend/profile",
"anathema-value-resolver/profile",
]
serde = ["anathema-state/serde", "anathema-store/serde"]
# filelog = ["anathema-debug/filelog", "anathema-widgets/filelog", "anathema-runtime/filelog"]

Expand Down
2 changes: 1 addition & 1 deletion anathema-default-widgets/src/border.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ impl Widget for Border {
id: WidgetId,
ctx: &mut LayoutCtx<'_, 'bp>,
) -> Result<Size> {
let attributes = ctx.attribute_storage.get_mut(id);
let attributes = ctx.attribute_storage.get(id);

self.sides = attributes.get_as::<Sides>("sides").unwrap_or_default();

Expand Down
9 changes: 9 additions & 0 deletions anathema-default-widgets/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ pub struct TestRunner {
variables: Variables,
components: Components,
function_table: FunctionTable,
doc: Document,
}

impl TestRunner {
Expand Down Expand Up @@ -171,6 +172,7 @@ impl TestRunner {
variables,
components: Components::new(),
function_table: FunctionTable::new(),
doc,
}
}

Expand All @@ -184,6 +186,7 @@ impl TestRunner {
&mut self.component_registry,
&mut self.components,
&self.function_table,
&self.doc,
)
}
}
Expand All @@ -202,6 +205,7 @@ pub struct TestInstance<'bp> {
changes: Changes,
glyph_map: GlyphMap,
function_table: &'bp FunctionTable,
doc: &'bp Document,
}

impl<'bp> TestInstance<'bp> {
Expand All @@ -214,6 +218,7 @@ impl<'bp> TestInstance<'bp> {
component_registry: &'bp mut ComponentRegistry,
components: &'bp mut Components,
function_table: &'bp FunctionTable,
doc: &'bp Document,
) -> Self {
let mut tree = WidgetTree::empty();
let mut attribute_storage = AttributeStorage::empty();
Expand All @@ -233,6 +238,7 @@ impl<'bp> TestInstance<'bp> {
&mut glyph_map,
&mut viewport,
function_table,
&doc.expressions,
);

let mut ctx = ctx.eval_ctx(None, None);
Expand All @@ -254,6 +260,7 @@ impl<'bp> TestInstance<'bp> {
changes: Changes::empty(),
glyph_map,
function_table,
doc,
}
}

Expand Down Expand Up @@ -285,6 +292,7 @@ impl<'bp> TestInstance<'bp> {
&mut self.glyph_map,
&mut self.viewport,
self.function_table,
&self.doc.expressions,
);

self.changes.iter().for_each(|(sub, change)| {
Expand Down Expand Up @@ -331,6 +339,7 @@ impl<'bp> TestInstance<'bp> {
&mut self.glyph_map,
&mut self.viewport,
self.function_table,
&self.doc.expressions,
);

let mut cycle = WidgetCycle::new(self.backend, self.tree.view(), constraints);
Expand Down
3 changes: 2 additions & 1 deletion anathema-runtime/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ impl<G: GlobalEventHandler> Builder<G> {
}

pub fn register_global(&mut self, key: impl Into<String>, value: impl Into<Expression>) -> Result<()> {
self.variables.define_global(key, value).map_err(|e| e.to_error(None))?;
let id = self.document.expressions.insert_at_root(value.into());
self.variables.define_global(key, id).map_err(|e| e.to_error(None))?;
Ok(())
}

Expand Down
4 changes: 3 additions & 1 deletion anathema-runtime/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ impl Runtime<()> {
}

pub fn register_global(&mut self, key: impl Into<String>, value: impl Into<Expression>) -> Result<()> {
self.variables.define_global(key, value).map_err(|e| e.to_error(None))?;
let id = self.document.expressions.insert_at_root(value.into());
self.variables.define_global(key, id).map_err(|e| e.to_error(None))?;
Ok(())
}

Expand Down Expand Up @@ -239,6 +240,7 @@ impl<G: GlobalEventHandler> Runtime<G> {
&mut self.glyph_map,
&mut self.viewport,
&self.function_table,
&self.document.expressions,
);

let inst = Frame {
Expand Down
14 changes: 14 additions & 0 deletions anathema-store/src/slab/generational.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,20 @@ where
}
}

// -----------------------------------------------------------------------------
// - Index -
// -----------------------------------------------------------------------------
impl<T> std::ops::Index<Key> for GenSlab<T> {
type Output = T;

fn index(&self, index: Key) -> &Self::Output {
match self.get(index) {
Some(val) => val,
None => panic!("invalid index or generation"),
}
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
15 changes: 8 additions & 7 deletions anathema-templates/src/blueprints.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
use anathema_store::smallmap::SmallMap;
use anathema_store::storage::strings::StringId;

use crate::ComponentBlueprintId;
use crate::components::AssocEventMapping;
use crate::{ComponentBlueprintId, Expression};
use crate::expressions::ExpressionId;

#[derive(Debug, Clone, PartialEq)]
pub struct Single {
pub ident: String,
pub children: Vec<Blueprint>,
pub attributes: SmallMap<String, Expression>,
pub value: Option<Expression>,
pub attributes: SmallMap<String, ExpressionId>,
pub value: Option<ExpressionId>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct For {
pub binding: String,
pub data: Expression,
pub data: ExpressionId,
pub body: Vec<Blueprint>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct With {
pub binding: String,
pub data: Expression,
pub data: ExpressionId,
pub body: Vec<Blueprint>,
}

Expand All @@ -34,7 +35,7 @@ pub struct ControlFlow {

#[derive(Debug, Clone, PartialEq)]
pub struct Else {
pub cond: Option<Expression>,
pub cond: Option<ExpressionId>,
pub body: Vec<Blueprint>,
}

Expand All @@ -44,7 +45,7 @@ pub struct Component {
pub name_id: StringId,
pub id: ComponentBlueprintId,
pub body: Vec<Blueprint>,
pub attributes: SmallMap<String, Expression>,
pub attributes: SmallMap<String, ExpressionId>,
pub assoc_functions: Vec<AssocEventMapping>,
/// The parent component in the blueprint
pub parent: Option<ComponentBlueprintId>,
Expand Down
7 changes: 5 additions & 2 deletions anathema-templates/src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use anathema_store::storage::Storage;
use crate::Lexer;
use crate::blueprints::Blueprint;
use crate::error::{Error, ErrorKind, Result};
use crate::expressions::Expressions;
use crate::statements::eval::Scope;
use crate::statements::parser::Parser;
use crate::statements::{Context, Statements};
Expand Down Expand Up @@ -223,6 +224,7 @@ impl ComponentTemplates {
variables: &mut Variables,
slots: SmallMap<StringId, Vec<Blueprint>>,
strings: &mut Strings,
expressions: &mut Expressions,
) -> Result<Vec<Blueprint>> {
let ticket = self.components.checkout(component_id);
let (_, component_src) = &*ticket;
Expand All @@ -238,7 +240,7 @@ impl ComponentTemplates {
// NOTE
// The ticket has to be restored to the component store,
// this is why the error is returned rather than using `?` on `self.compile`.
let ret = self.compile(component_src, variables, slots, strings, component_id);
let ret = self.compile(component_src, variables, slots, strings, expressions, component_id);
self.components.restore(ticket);
self.dependencies.pop();
ret
Expand All @@ -250,6 +252,7 @@ impl ComponentTemplates {
variables: &mut Variables,
slots: SmallMap<StringId, Vec<Blueprint>>,
strings: &mut Strings,
expressions: &mut Expressions,
parent: ComponentBlueprintId,
) -> Result<Vec<Blueprint>> {
let tokens = Lexer::new(template, strings).collect::<Result<Vec<_>>>()?;
Expand All @@ -258,7 +261,7 @@ impl ComponentTemplates {

let statements = parser.collect::<Result<Statements>>()?;

let mut context = Context::new(template, variables, self, strings, slots, Some(parent));
let mut context = Context::new(template, variables, self, strings, expressions, slots, Some(parent));

Scope::new(statements).eval(&mut context)
}
Expand Down
6 changes: 6 additions & 0 deletions anathema-templates/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use anathema_store::smallmap::SmallMap;
use crate::blueprints::Blueprint;
use crate::components::{ComponentTemplates, SourceKind, TemplateSource};
use crate::error::{Error, ErrorKind, Result};
use crate::expressions::Expressions;
use crate::statements::eval::Scope;
use crate::statements::parser::Parser;
use crate::statements::{Context, Statements};
Expand All @@ -21,6 +22,7 @@ use crate::{ComponentBlueprintId, Lexer, Variables};
pub struct Document {
template: TemplateSource,
pub strings: Strings,
pub expressions: Expressions,
components: ComponentTemplates,
pub hot_reload: bool,
}
Expand All @@ -31,6 +33,7 @@ impl Document {
Self {
template,
strings: Strings::new(),
expressions: Expressions::empty(),
components: ComponentTemplates::new(),
hot_reload: true,
}
Expand Down Expand Up @@ -58,6 +61,8 @@ impl Document {

pub fn compile(&mut self, globals: &mut Variables) -> Result<Blueprint> {
globals.reset_globals();
self.expressions.clear();

let tokens = Lexer::new(&self.template, &mut self.strings).collect::<Result<Vec<_>>>()?;
let tokens = Tokens::new(tokens, self.template.len());
let parser = Parser::new(tokens, &mut self.strings, &self.template, &mut self.components);
Expand All @@ -68,6 +73,7 @@ impl Document {
template: &self.template,
variables: globals,
strings: &mut self.strings,
expressions: &mut self.expressions,
components: &mut self.components,
slots: SmallMap::empty(),
current_component_parent: None,
Expand Down
69 changes: 68 additions & 1 deletion anathema-templates/src/expressions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,80 @@ use std::collections::HashMap;
use std::fmt::Display;

use anathema_state::Hex;
use anathema_store::slab::Index;

use crate::primitives::Primitive;
use crate::variables::VarId;
use crate::variables::{ScopeId, VarId};

pub(crate) mod eval;
pub(crate) mod parser;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ExpressionId(u32);

impl From<ExpressionId> for Index {
fn from(value: ExpressionId) -> Self {
value.0.into()
}
}

#[derive(Debug)]
pub struct Expressions {
inner: Vec<(Expression, ScopeId)>,
}

impl Expressions {
pub fn empty() -> Self {
Self { inner: vec![] }
}

/// Get a reference to an expression
///
/// # Panics
///
/// Panics if the expression id is greater than the length of expressions.
/// This should never happen as the ids are assigned to blueprints using them.
///
/// Only time this could happen is if the expression id is created outside of the tempalte
/// generation.
pub fn get(&self, id: ExpressionId) -> &Expression {
&self.inner[id.0 as usize].0
}

/// Insert an expression in the root scope
pub fn insert_at_root(&mut self, expression: impl Into<Expression>) -> ExpressionId {
self.insert(expression.into(), ScopeId::root().clone())
}

/// Insert an expression and return the id to the newly inserted expression
pub fn insert(&mut self, expression: Expression, boundary: ScopeId) -> ExpressionId {
let id = ExpressionId(self.inner.len() as u32);
match self
.inner
.iter()
.position(|(e, scope)| expression.eq(e) && boundary.eq(scope))
{
Some(id) => ExpressionId(id as u32),
None => {
self.inner.push((expression, boundary));
id
}
}
}

pub(crate) fn clear(&mut self) {
self.inner.clear()
}
}

impl std::ops::Index<ExpressionId> for Expressions {
type Output = Expression;

fn index(&self, index: ExpressionId) -> &Self::Output {
&self.inner[index.0 as usize].0
}
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Op {
Add,
Expand Down
14 changes: 7 additions & 7 deletions anathema-templates/src/statements/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn eval_path(expr: Expression, ctx: &Context<'_>) -> Option<Expression> {
}

// Returning `None` here means we evaluated a const expression but the expression didn't exist,
// e.g indexing outside of a list of primitives.
// e.g indexing outside of a list of primitives or refering to state value / attributes.
pub(crate) fn const_eval(expr: impl Into<Expression>, ctx: &Context<'_>) -> Option<Expression> {
use {Expression as E, Primitive as P};

Expand All @@ -54,11 +54,11 @@ pub(crate) fn const_eval(expr: impl Into<Expression>, ctx: &Context<'_>) -> Opti
Some(expr) => E::Either(expr.into(), ce!(second)),
None => return None,
},
E::Not(expr) => E::Not(ce!(*expr)),
E::Negative(expr) => E::Negative(ce!(*expr)),
E::Equality(lhs, rhs, eq) => E::Equality(ce!(*lhs), ce!(*rhs), eq),
E::LogicalOp(lhs, rhs, op) => E::LogicalOp(ce!(*lhs), ce!(*rhs), op),
E::Range(from, to) => E::Range(ce!(*from), ce!(*to)),
E::Not(expr) => E::Not(ce!(expr)),
E::Negative(expr) => E::Negative(ce!(expr)),
E::Equality(lhs, rhs, eq) => E::Equality(ce!(lhs), ce!(rhs), eq),
E::LogicalOp(lhs, rhs, op) => E::LogicalOp(ce!(lhs), ce!(rhs), op),
E::Range(from, to) => E::Range(ce!(from), ce!(to)),

E::Ident(_) | E::Index(..) => eval_path(expr, ctx)?,
E::Variable(_) => unreachable!("const eval is not recursive so this can never happen"),
Expand All @@ -76,7 +76,7 @@ pub(crate) fn const_eval(expr: impl Into<Expression>, ctx: &Context<'_>) -> Opti
let hm = HashMap::from_iter(map.into_iter().flat_map(|(k, v)| Some((k, ce!(v)))));
E::Map(hm)
}
E::Op(lhs, rhs, op) => match (ce!(*lhs), ce!(*rhs)) {
E::Op(lhs, rhs, op) => match (ce!(lhs), ce!(rhs)) {
(E::Primitive(P::Int(lhs)), E::Primitive(P::Int(rhs))) => {
let val = match op {
Op::Add => lhs + rhs,
Expand Down
Loading
Loading