Compress the Constant enum from 136 to 32 bytes

This commit is contained in:
Tad Hardesty 2021-11-21 00:33:13 -08:00
parent c5b5fb0ca8
commit f641186e01
6 changed files with 51 additions and 47 deletions

View file

@ -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,
};

View file

@ -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);
}

View file

@ -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 {

View file

@ -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() {

View file

@ -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);
}

View file

@ -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")"#);
}