mirror of
https://github.com/SpaceManiac/SpacemanDMM.git
synced 2025-12-23 05:36:47 +00:00
Compress the Constant enum from 136 to 32 bytes
This commit is contained in:
parent
c5b5fb0ca8
commit
f641186e01
6 changed files with 51 additions and 47 deletions
|
|
@ -13,14 +13,14 @@ impl RenderPass for Spawners {
|
|||
}
|
||||
match atom.get_var("spawn_list", objtree) {
|
||||
&Constant::List(ref elements) => {
|
||||
for &(ref key, _) in elements {
|
||||
for &(ref key, _) in elements.iter() {
|
||||
// TODO: use a more civilized lookup method
|
||||
let type_key;
|
||||
let reference = match key {
|
||||
&Constant::String(ref s) => s,
|
||||
&Constant::Prefab(ref fab) => {
|
||||
type_key = dm::ast::FormatTreePath(&fab.path).to_string();
|
||||
&type_key
|
||||
type_key.as_str()
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1677,8 +1677,8 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
|
|||
Term::Null => Analysis::null(),
|
||||
Term::Int(number) => Analysis::from_value(self.objtree, Constant::from(*number), type_hint),
|
||||
Term::Float(number) => Analysis::from_value(self.objtree, Constant::from(*number), type_hint),
|
||||
Term::String(text) => Analysis::from_value(self.objtree, Constant::String(text.to_owned()), type_hint),
|
||||
Term::Resource(text) => Analysis::from_value(self.objtree, Constant::Resource(text.to_owned()), type_hint),
|
||||
Term::String(text) => Analysis::from_value(self.objtree, Constant::String(text.as_str().into()), type_hint),
|
||||
Term::Resource(text) => Analysis::from_value(self.objtree, Constant::Resource(text.as_str().into()), type_hint),
|
||||
Term::As(_) => assumption_set![Assumption::IsNum(true)].into(),
|
||||
|
||||
Term::Ident(unscoped_name) => {
|
||||
|
|
@ -1707,7 +1707,7 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
|
|||
Analysis {
|
||||
static_ty: StaticType::None,
|
||||
aset: assumption_set![Assumption::IsPath(true, nav.ty())].into(),
|
||||
value: Some(Constant::Prefab(pop)),
|
||||
value: Some(Constant::Prefab(Box::new(pop))),
|
||||
fix_hint: None,
|
||||
is_impure: None,
|
||||
}
|
||||
|
|
@ -2247,7 +2247,7 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
|
|||
.register(self.context);
|
||||
return Analysis::empty()
|
||||
});
|
||||
guard!(let Some(arglist) = VALID_FILTER_TYPES.get(typevalue.as_str()) else {
|
||||
guard!(let Some(arglist) = VALID_FILTER_TYPES.get(&typevalue) else {
|
||||
error(location, format!("filter() called with invalid type keyword parameter value '{}'", typevalue))
|
||||
.register(self.context);
|
||||
return Analysis::empty()
|
||||
|
|
@ -2259,7 +2259,7 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
|
|||
.register(self.context);
|
||||
}
|
||||
}
|
||||
if let Some((flagfieldname, exclusive, can_be_zero, valid_flags)) = VALID_FILTER_FLAGS.get(typevalue.as_str()) {
|
||||
if let Some((flagfieldname, exclusive, can_be_zero, valid_flags)) = VALID_FILTER_FLAGS.get(&typevalue) {
|
||||
if let Some(flagsvalue) = param_expr_map.get(flagfieldname) {
|
||||
self.check_filter_flag(flagsvalue, *can_be_zero, location, typevalue, valid_flags, flagfieldname, *exclusive);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,12 +200,16 @@ pub fn default_defines(defines: &mut DefineMap) {
|
|||
|
||||
/// Register BYOND builtins into the specified object tree.
|
||||
pub fn register_builtins(tree: &mut ObjectTreeBuilder) {
|
||||
fn path(path: &'static [&'static str]) -> Constant {
|
||||
Constant::Prefab(Box::new(super::constants::Pop {
|
||||
path: path.iter().copied().map(String::from).collect::<Box<[_]>>(),
|
||||
vars: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
macro_rules! path {
|
||||
($(/$elem:ident)*) => {
|
||||
Constant::Prefab(super::constants::Pop {
|
||||
path: vec![$(stringify!($elem).into()),*].into_boxed_slice(),
|
||||
vars: Default::default(),
|
||||
})
|
||||
path(&[$(stringify!($elem),)*])
|
||||
}
|
||||
}
|
||||
macro_rules! int {
|
||||
|
|
|
|||
|
|
@ -56,20 +56,20 @@ pub enum Constant {
|
|||
/// A `new` call.
|
||||
New {
|
||||
/// The type to be instantiated.
|
||||
type_: Option<Pop>,
|
||||
type_: Option<Box<Pop>>,
|
||||
/// The list of arugments to pass to the `New()` proc.
|
||||
args: Option<Vec<(Constant, Option<Constant>)>>,
|
||||
args: Option<Box<[(Constant, Option<Constant>)]>>,
|
||||
},
|
||||
/// A `list` literal. Elements have optional associations.
|
||||
List(Vec<(Constant, Option<Constant>)>),
|
||||
List(Box<[(Constant, Option<Constant>)]>),
|
||||
/// A call to a constant type constructor.
|
||||
Call(ConstFn, Vec<(Constant, Option<Constant>)>),
|
||||
Call(ConstFn, Box<[(Constant, Option<Constant>)]>),
|
||||
/// A prefab literal.
|
||||
Prefab(Pop),
|
||||
Prefab(Box<Pop>),
|
||||
/// A string literal.
|
||||
String(String),
|
||||
String(Box<str>),
|
||||
/// A resource literal.
|
||||
Resource(String),
|
||||
Resource(Box<str>),
|
||||
/// A floating-point (or integer) literal, following BYOND's rules.
|
||||
Float(f32),
|
||||
}
|
||||
|
|
@ -144,15 +144,13 @@ impl Constant {
|
|||
// ------------------------------------------------------------------------
|
||||
// Constructors
|
||||
|
||||
pub const EMPTY_STRING: &'static Constant = &Constant::String(String::new());
|
||||
|
||||
pub fn null() -> &'static Constant {
|
||||
static NULL: Constant = Constant::Null(None);
|
||||
&NULL
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn string<S: Into<String>>(s: S) -> Constant {
|
||||
pub fn string<S: Into<Box<str>>>(s: S) -> Constant {
|
||||
Constant::String(s.into())
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +210,7 @@ impl Constant {
|
|||
|
||||
pub fn eq_string(&self, string: &str) -> bool {
|
||||
match *self {
|
||||
Constant::String(ref s) => s == string,
|
||||
Constant::String(ref s) => &**s == string,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -220,7 +218,7 @@ impl Constant {
|
|||
pub fn eq_resource(&self, resource: &str) -> bool {
|
||||
match self {
|
||||
Constant::String(ref s) |
|
||||
Constant::Resource(ref s) => s == resource,
|
||||
Constant::Resource(ref s) => &**s == resource,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -230,7 +228,7 @@ impl Constant {
|
|||
|
||||
pub fn contains_key(&self, key: &Constant) -> bool {
|
||||
if let Constant::List(ref elements) = *self {
|
||||
for &(ref k, _) in elements {
|
||||
for &(ref k, _) in elements.iter() {
|
||||
if key == k {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -243,7 +241,7 @@ impl Constant {
|
|||
match (self, key) {
|
||||
// Narrowing conversion is intentional.
|
||||
(&Constant::List(ref elements), &Constant::Float(i)) => return elements.get(i as usize).map(|&(ref k, _)| k),
|
||||
(&Constant::List(ref elements), key) => for &(ref k, ref v) in elements {
|
||||
(&Constant::List(ref elements), key) => for &(ref k, ref v) in elements.iter() {
|
||||
if key == k {
|
||||
return v.as_ref();
|
||||
}
|
||||
|
|
@ -292,7 +290,7 @@ impl PartialEq<str> for Constant {
|
|||
fn eq(&self, other: &str) -> bool {
|
||||
match self {
|
||||
Constant::String(ref s) |
|
||||
Constant::Resource(ref s) => s == other,
|
||||
Constant::Resource(ref s) => &**s == other,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -585,7 +583,7 @@ impl<'a> ConstantFolder<'a> {
|
|||
/// list of expressions, keyword arguments disallowed
|
||||
#[allow(dead_code)]
|
||||
fn expr_vec(&mut self, v: Vec<Expression>) -> Result<Vec<Constant>, DMError> {
|
||||
let mut out = Vec::new();
|
||||
let mut out = Vec::with_capacity(v.len());
|
||||
for each in v {
|
||||
out.push(self.expr(each, None)?);
|
||||
}
|
||||
|
|
@ -593,8 +591,8 @@ impl<'a> ConstantFolder<'a> {
|
|||
}
|
||||
|
||||
/// arguments or keyword arguments
|
||||
fn arguments(&mut self, v: Box<[Expression]>) -> Result<Vec<(Constant, Option<Constant>)>, DMError> {
|
||||
let mut out = Vec::new();
|
||||
fn arguments(&mut self, v: Box<[Expression]>) -> Result<Box<[(Constant, Option<Constant>)]>, DMError> {
|
||||
let mut out = Vec::with_capacity(v.len());
|
||||
for each in Vec::from(v).into_iter() {
|
||||
out.push(match each {
|
||||
// handle associations
|
||||
|
|
@ -604,7 +602,7 @@ impl<'a> ConstantFolder<'a> {
|
|||
rhs,
|
||||
} => {
|
||||
let key = match Term::from(*lhs) {
|
||||
Term::Ident(ident) => Constant::String(ident),
|
||||
Term::Ident(ident) => Constant::String(ident.into()),
|
||||
other => self.term(other, None)?,
|
||||
};
|
||||
(key, Some(self.expr(*rhs, None)?))
|
||||
|
|
@ -612,7 +610,7 @@ impl<'a> ConstantFolder<'a> {
|
|||
key => (self.expr(key, None)?, None),
|
||||
});
|
||||
}
|
||||
Ok(out)
|
||||
Ok(out.into())
|
||||
}
|
||||
|
||||
fn follow(&mut self, term: Constant, follow: Follow) -> Result<Constant, DMError> {
|
||||
|
|
@ -696,7 +694,7 @@ impl<'a> ConstantFolder<'a> {
|
|||
integer!(RShift >>);
|
||||
|
||||
match (op, lhs, rhs) {
|
||||
(BinaryOp::Add, String(lhs), String(rhs)) => Ok(String(lhs + &rhs)),
|
||||
(BinaryOp::Add, String(lhs), String(rhs)) => Ok(String((std::string::String::from(lhs) + &rhs).into())),
|
||||
(BinaryOp::Eq, lhs, rhs) => Ok(Constant::from(lhs == rhs)),
|
||||
(BinaryOp::NotEq, lhs, rhs) => Ok(Constant::from(lhs != rhs)),
|
||||
(BinaryOp::And, lhs, rhs) => Ok(if lhs.to_bool() { rhs } else { lhs }),
|
||||
|
|
@ -709,7 +707,7 @@ impl<'a> ConstantFolder<'a> {
|
|||
Ok(match term {
|
||||
Term::Null => Constant::Null(type_hint.cloned()),
|
||||
Term::NewPrefab { prefab, args } => Constant::New {
|
||||
type_: Some(self.prefab(*prefab)?),
|
||||
type_: Some(Box::new(self.prefab(*prefab)?)),
|
||||
args: match args {
|
||||
Some(args) => Some(self.arguments(args)?),
|
||||
None => None,
|
||||
|
|
@ -737,7 +735,7 @@ impl<'a> ConstantFolder<'a> {
|
|||
"cos" => self.trig_op(args, f32::cos)?,
|
||||
"arcsin" => self.trig_op(args, f32::asin)?,
|
||||
"arccos" => self.trig_op(args, f32::acos)?,
|
||||
"rgb" => Constant::String(self.rgb(args)?),
|
||||
"rgb" => Constant::String(self.rgb(args)?.into()),
|
||||
"defined" if self.defines.is_some() => {
|
||||
let defines = self.defines.unwrap(); // annoying, but keeps the match clean
|
||||
if args.len() != 1 {
|
||||
|
|
@ -751,10 +749,10 @@ impl<'a> ConstantFolder<'a> {
|
|||
// other functions are no-goes
|
||||
_ => return Err(self.error(format!("non-constant function call: {}", ident))),
|
||||
},
|
||||
Term::Prefab(prefab) => Constant::Prefab(self.prefab(*prefab)?),
|
||||
Term::Prefab(prefab) => Constant::Prefab(Box::new(self.prefab(*prefab)?)),
|
||||
Term::Ident(ident) => self.ident(ident, false)?,
|
||||
Term::String(v) => Constant::String(v),
|
||||
Term::Resource(v) => Constant::Resource(v),
|
||||
Term::String(v) => Constant::String(v.into()),
|
||||
Term::Resource(v) => Constant::Resource(v.into()),
|
||||
Term::Int(v) => Constant::Float(v as f32),
|
||||
Term::Float(v) => Constant::from(v),
|
||||
Term::Expr(expr) => self.expr(*expr, type_hint)?,
|
||||
|
|
@ -865,7 +863,7 @@ impl<'a> ConstantFolder<'a> {
|
|||
let mut color_args = ColorArgs::default();
|
||||
|
||||
// Get the value of the `space` kwarg if present, or collect which kwargs are set to automatically determine the color space.
|
||||
for (value, potential_kwarg_value) in &arguments {
|
||||
for (value, potential_kwarg_value) in arguments.iter() {
|
||||
// Check for kwargs if we're in the right form
|
||||
if let Some(kwarg_value) = potential_kwarg_value {
|
||||
if let Some(kwarg) = value.as_str() {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use indexmap::IndexMap;
|
|||
use ahash::RandomState;
|
||||
|
||||
use super::ast::{Expression, VarType, VarTypeBuilder, VarSuffix, PathOp, Parameter, Block, ProcDeclKind, Ident};
|
||||
use super::constants::{Constant, Pop};
|
||||
use super::constants::Constant;
|
||||
use super::docs::DocCollection;
|
||||
use super::{DMError, Location, Context, Severity};
|
||||
|
||||
|
|
@ -730,9 +730,9 @@ impl ObjectTree {
|
|||
}
|
||||
|
||||
pub fn type_by_constant(&self, constant: &Constant) -> Option<TypeRef> {
|
||||
match *constant {
|
||||
Constant::String(ref string_path) => self.find(string_path),
|
||||
Constant::Prefab(Pop { ref path, .. }) => self.type_by_path(path.iter()),
|
||||
match constant {
|
||||
Constant::String(string_path) => self.find(string_path),
|
||||
Constant::Prefab(pop) => self.type_by_path(pop.path.iter()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -827,6 +827,7 @@ impl ObjectTreeBuilder {
|
|||
} else {
|
||||
let constant_buf;
|
||||
let mut parent_type_buf;
|
||||
let empty_string;
|
||||
let parent_type = if path == "/atom" {
|
||||
"/datum"
|
||||
} else if path == "/turf" || path == "/area" {
|
||||
|
|
@ -855,7 +856,8 @@ impl ObjectTreeBuilder {
|
|||
Err(e) => Err(e),
|
||||
}
|
||||
} else if path == "/client" {
|
||||
Ok(Constant::EMPTY_STRING)
|
||||
empty_string = Constant::String("".into());
|
||||
Ok(&empty_string)
|
||||
} else {
|
||||
// A weird situation which should not happen.
|
||||
Err(DMError::new(location, format!("missing {}/parent_type", path)))
|
||||
|
|
@ -865,9 +867,9 @@ impl ObjectTreeBuilder {
|
|||
Ok(Constant::String(s)) => {
|
||||
parent_type = s;
|
||||
}
|
||||
Ok(Constant::Prefab(Pop { ref path, ref vars })) if vars.is_empty() => {
|
||||
Ok(Constant::Prefab(ref pop)) if pop.vars.is_empty() => {
|
||||
parent_type_buf = String::new();
|
||||
for piece in path.iter() {
|
||||
for piece in pop.path.iter() {
|
||||
parent_type_buf.push('/');
|
||||
parent_type_buf.push_str(&piece);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,9 +43,9 @@ fn lists() {
|
|||
assert_eq!(List(vec![
|
||||
(Constant::string("KNOCKDOWN"), Some(Float(0.))),
|
||||
(Constant::string("THROW"), Some(Float(0.))),
|
||||
]).to_string(), r#"list("KNOCKDOWN" = 0, "THROW" = 0)"#);
|
||||
].into()).to_string(), r#"list("KNOCKDOWN" = 0, "THROW" = 0)"#);
|
||||
assert_eq!(List(vec![
|
||||
(Constant::string("neutral"), None),
|
||||
(Constant::string("Syndicate"), None),
|
||||
]).to_string(), r#"list("neutral","Syndicate")"#);
|
||||
].into()).to_string(), r#"list("neutral","Syndicate")"#);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue