Skip to content
Extraits de code Groupes Projets
Non vérifiée Valider b85f4ab8 rédigé par Kubat's avatar Kubat
Parcourir les fichiers

[SPELL] Complement the API to have something usable to build spells

parent 307730a4
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
......@@ -7,10 +7,22 @@ pub mod parser;
pub mod spell;
pub mod prelude {
// Types prefixed by crate name.
pub use crate::{
ast::expr::{Const as GrimoireConstant, Expression as GrimoireExpression},
ast::{
Const as GrimoireConstant, Expression as GrimoireExpression,
VarOrConst as GrimoireVarOrConst,
},
error::Error as GrimoireError,
state::State as GrimoireState,
types::Type as GrimoireType,
};
// Spell structs/traits re-exports.
pub use crate::spell::{BuildableSpell, Spell, SpellArguments, SpellFactory};
// Standard spells re-rexports.
pub mod spell {
pub use crate::spell::std::*;
}
}
use crate::{
ast::expr::{Const, Expression},
error::Error,
state::State,
types::Type,
};
use crate::{ast::Const, error::Error, types::Type};
use std::collections::HashMap;
/// The arguments that may be passed to a spell for its instanciation.
#[derive(Debug, Default)]
pub struct SpellArguments(HashMap<String, Expression>);
pub struct SpellArguments {
named: HashMap<String, Const>,
trailing: Vec<Const>,
}
impl SpellArguments {
/// Set/Override the value in the [Argument] list.
pub fn set(&mut self, name: impl Into<String>, value: Expression) {
_ = self.0.insert(name.into(), value);
pub fn insert(&mut self, name: impl Into<String>, value: Const) {
_ = self.named.insert(name.into(), value);
}
/// Push an unamed argument to the argument list.
pub fn push(&mut self, value: Const) {
self.trailing.push(value);
}
/// Removes a named argument of a [SpellArguments], and try to cast it into the asked type. On
/// success returns [Option<Argument>::Some], otherwise [None].
pub fn remove_as<S>(&mut self, name: S, ty: Type) -> Result<Const, Error>
where
S: AsRef<str>,
{
self.remove(name.as_ref())
.ok_or_else(|| Error::Undefined(name.as_ref().to_string()))?
.cast_into(ty)
}
/// Pops the value of an [Argument], and try to cast it into the asked type. On success returns
/// Removes a named argument of a [SpellArguments]. On success returns
/// [Option<Argument>::Some], otherwise [None].
pub fn pop<S>(&mut self, state: &State, name: S, ty: Type) -> Result<Const, Error>
pub fn remove<S>(&mut self, name: S) -> Option<Const>
where
S: AsRef<str>,
{
self.0
.remove(name.as_ref())
.ok_or_else(|| Error::Undefined(name.as_ref().to_string()))
.map(|expr| state.evaluate_as(expr, ty))?
self.named.remove(name.as_ref())
}
/// Pops an unamed argument from the argument list.
pub fn pop_as(&mut self, ty: Type) -> Result<Const, Error> {
self.pop()
.ok_or(Error::Empty("unamed argument list"))?
.cast_into(ty)
}
/// Pops an unamed argument from the argument list.
pub fn pop(&mut self) -> Option<Const> {
self.trailing.pop()
}
/// Iterate over the name of the named arguments.
pub fn iter_named_keys(&self) -> impl Iterator<Item = &str> {
self.named.keys().map(String::as_str)
}
/// Iterate over named arguments.
pub fn iter_named(&self) -> impl Iterator<Item = (&str, &Const)> {
self.named
.iter()
.map(|(key, constant)| (key.as_str(), constant))
}
/// Iterate over unnamed arguments.
pub fn iter_unamed(&self) -> impl Iterator<Item = &Const> {
self.trailing.iter()
}
/// Tells wether we have named arguments or not.
pub fn has_named(&self) -> bool {
self.named.is_empty()
}
/// Tells wether we have unamed arguments or not.
pub fn has_unamed(&self) -> bool {
self.trailing.is_empty()
}
/// Tells wether the argument list is empty or not. Note that at the end of the
/// [crate::spell::Spell] creation, the argument list must be empty!
pub fn is_empty(&self) -> bool {
!self.has_named() && !self.has_unamed()
}
}
impl FromIterator<(String, Expression)> for SpellArguments {
fn from_iter<T: IntoIterator<Item = (String, Expression)>>(iter: T) -> Self {
Self(iter.into_iter().collect())
/// Iterate over all the arguments. You are guarentied to have first the named arguments - in an
/// unspecified order - then the unamed arguments in order.
pub struct IntoIter {
named: <HashMap<String, Const> as IntoIterator>::IntoIter,
trailing: <Vec<Const> as IntoIterator>::IntoIter,
}
impl IntoIterator for SpellArguments {
type Item = <Self::IntoIter as Iterator>::Item;
type IntoIter = IntoIter;
/// Iterate over all the arguments. You are guarentied to have first the named arguments - in
/// an unspecified order - then the unamed arguments in order.
fn into_iter(self) -> Self::IntoIter {
IntoIter {
named: self.named.into_iter(),
trailing: self.trailing.into_iter(),
}
}
}
impl Iterator for IntoIter {
type Item = (Option<String>, Const);
fn next(&mut self) -> Option<Self::Item> {
self.named
.next()
.map(|(key, constant)| (Some(key), constant))
.or_else(|| self.trailing.next().map(|constant| (None, constant)))
}
}
use crate::{error::Error, spell::SpellArguments, state::State};
/// A spell, can be casted or reverted if we need to.
/// A spell, can be casted on a state to modify it.
pub trait Spell {
/// Cast the spell on a [State]. Returns a new [State].
fn cast(&mut self, state: State) -> Result<State, Error>;
/// UnCast the spell from a [State]. Returns the previous [State].
fn uncast(&mut self, state: State) -> Result<State, Error>;
fn cast(&self, state: State) -> Result<State, Error>;
}
/// A [Spell] that we can create. Is used to be able to register it into a
......@@ -33,7 +30,7 @@ where
/// Create a spell from a set of arguments. May fail.
fn create(arguments: SpellArguments) -> Result<Box<dyn Spell>, Error> {
Self::try_from(arguments)
.map(Box::new)
.map(|boxed| boxed as Box<dyn Spell>)
.map(|this| Box::new(this) as Box<dyn Spell>)
.map_err(|err| Error::BuildSpell(Self::name(), Box::new(err)))
}
}
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter