Factor flags of VarType into VarTypeFlags bitfield

This commit is contained in:
Tad Hardesty 2020-05-07 19:55:51 -07:00
parent 4cbccb4819
commit 3f7c793162
9 changed files with 134 additions and 89 deletions

View file

@ -359,12 +359,12 @@ fn main2() -> Result<(), Box<dyn std::error::Error>> {
let block = DocBlock::parse(&var.value.docs.text(), Some(broken_link_callback));
// `type` is pulled from the parent if necessary
let type_ = ty.get_var_declaration(name).map(|decl| VarType {
is_static: decl.var_type.is_static,
is_const: decl.var_type.is_const,
is_tmp: decl.var_type.is_tmp,
is_final: decl.var_type.is_final,
is_private: decl.var_type.is_private,
is_protected: decl.var_type.is_protected,
is_static: decl.var_type.flags.is_static(),
is_const: decl.var_type.flags.is_const(),
is_tmp: decl.var_type.flags.is_tmp(),
is_final: decl.var_type.flags.is_final(),
is_private: decl.var_type.flags.is_private(),
is_protected: decl.var_type.flags.is_protected(),
path: &decl.var_type.type_path,
});
parsed_type.vars.insert(name, Var {

View file

@ -940,14 +940,14 @@ pub fn check_var_defs(objtree: &ObjectTree, context: &Context) {
.register(context);
}
if decl.var_type.is_final {
if decl.var_type.flags.is_final() {
DMError::new(typevar.value.location, format!("{} overrides final var {:?}", path, varname))
.with_errortype("final_var")
.with_note(decl.location, format!("declared final on {} here", parent.path))
.register(context);
}
if decl.var_type.is_private {
if decl.var_type.flags.is_private() {
DMError::new(typevar.value.location, format!("{} overrides private var {:?}", path, varname))
.with_errortype("private_var")
.with_note(decl.location, format!("declared private on {} here", parent.path))
@ -1812,13 +1812,13 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
Follow::Field(kind, name) => {
if let Some(ty) = lhs.static_ty.basic_type() {
if let Some(decl) = ty.get_var_declaration(name) {
if ty != self.ty && decl.var_type.is_private {
if ty != self.ty && decl.var_type.flags.is_private() {
error(location, format!("field {:?} on {} is declared as private", name, ty))
.with_errortype("private_var")
.set_severity(Severity::Warning)
.with_note(decl.location, "definition is here")
.register(self.context);
} else if !self.ty.is_subtype_of(ty.get()) && decl.var_type.is_protected {
} else if !self.ty.is_subtype_of(ty.get()) && decl.var_type.flags.is_protected() {
error(location, format!("field {:?} on {} is declared as protected", name, ty))
.with_errortype("protected_var")
.set_severity(Severity::Warning)

View file

@ -815,27 +815,117 @@ type_table! {
"color", COLOR, 1 << 17;
}
bitflags! {
#[derive(Default)]
pub struct VarTypeFlags: u8 {
// DM flags
const STATIC = 1 << 0;
const CONST = 1 << 2;
const TMP = 1 << 3;
// SpacemanDMM flags
const FINAL = 1 << 4;
const PRIVATE = 1 << 5;
const PROTECTED = 1 << 6;
}
}
impl VarTypeFlags {
pub fn from_name(name: &str) -> Option<VarTypeFlags> {
match name {
// DM flags
"global" | "static" => Some(VarTypeFlags::STATIC),
"const" => Some(VarTypeFlags::CONST),
"tmp" => Some(VarTypeFlags::TMP),
// SpacemanDMM flags
"SpacemanDMM_final" => Some(VarTypeFlags::FINAL),
"SpacemanDMM_private" => Some(VarTypeFlags::PRIVATE),
"SpacemanDMM_protected" => Some(VarTypeFlags::PROTECTED),
// Fallback
_ => None,
}
}
#[inline]
pub fn is_static(&self) -> bool {
self.contains(VarTypeFlags::STATIC)
}
#[inline]
pub fn is_const(&self) -> bool {
self.contains(VarTypeFlags::CONST)
}
#[inline]
pub fn is_tmp(&self) -> bool {
self.contains(VarTypeFlags::TMP)
}
#[inline]
pub fn is_final(&self) -> bool {
self.contains(VarTypeFlags::FINAL)
}
#[inline]
pub fn is_private(&self) -> bool {
self.contains(VarTypeFlags::PRIVATE)
}
#[inline]
pub fn is_protected(&self) -> bool {
self.contains(VarTypeFlags::PROTECTED)
}
#[inline]
pub fn is_const_evaluable(&self) -> bool {
self.contains(VarTypeFlags::CONST) || !self.intersects(VarTypeFlags::STATIC | VarTypeFlags::PROTECTED)
}
#[inline]
pub fn is_normal(&self) -> bool {
!self.intersects(VarTypeFlags::CONST | VarTypeFlags::STATIC | VarTypeFlags::PROTECTED)
}
}
impl fmt::Display for VarTypeFlags {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
if self.is_static() {
fmt.write_str("static/")?;
}
if self.is_const() {
fmt.write_str("const/")?;
}
if self.is_tmp() {
fmt.write_str("tmp/")?;
}
if self.is_final() {
fmt.write_str("SpacemanDMM_final/")?;
}
if self.is_private() {
fmt.write_str("SpacemanDMM_private/")?;
}
if self.is_protected() {
fmt.write_str("SpacemanDMM_protected/")?;
}
Ok(())
}
}
/// A type which may be ascribed to a `var`.
#[derive(Debug, Clone, PartialEq, Default)]
pub struct VarType {
pub is_static: bool,
pub is_const: bool,
pub is_tmp: bool,
pub is_final: bool,
pub is_private: bool,
pub is_protected: bool,
pub flags: VarTypeFlags,
pub type_path: TreePath,
}
impl VarType {
#[inline]
pub fn is_const_evaluable(&self) -> bool {
self.is_const || (!self.is_static && !self.is_tmp)
self.flags.is_const_evaluable()
}
#[inline]
pub fn is_normal(&self) -> bool {
!(self.is_static || self.is_const || self.is_tmp)
self.flags.is_normal()
}
pub fn suffix(&mut self, suffix: &VarSuffix) {
@ -847,39 +937,19 @@ impl VarType {
impl FromIterator<String> for VarType {
fn from_iter<T: IntoIterator<Item=String>>(iter: T) -> Self {
let (mut is_static, mut is_const, mut is_tmp, mut is_final, mut is_private, mut is_protected) = (false, false, false, false, false, false);
let mut flags = VarTypeFlags::default();
let type_path = iter
.into_iter()
.skip_while(|p| {
if p == "global" || p == "static" {
is_static = true;
true
} else if p == "SpacemanDMM_final" {
is_final = true;
true
} else if p == "SpacemanDMM_private" {
is_private = true;
true
} else if p == "SpacemanDMM_protected" {
is_protected = true;
true
} else if p == "const" {
is_const = true;
true
} else if p == "tmp" {
is_tmp = true;
if let Some(flag) = VarTypeFlags::from_name(p) {
flags |= flag;
true
} else {
false
}
}).collect();
VarType {
is_static,
is_const,
is_tmp,
is_final,
is_private,
is_protected,
flags,
type_path,
}
}
@ -887,24 +957,7 @@ impl FromIterator<String> for VarType {
impl fmt::Display for VarType {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
if self.is_static {
fmt.write_str("static/")?;
}
if self.is_const {
fmt.write_str("const/")?;
}
if self.is_tmp {
fmt.write_str("tmp/")?;
}
if self.is_final {
fmt.write_str("SpacemanDMM_final/")?;
}
if self.is_private {
fmt.write_str("SpacemanDMM_private/")?;
}
if self.is_protected {
fmt.write_str("SpacemanDMM_protected/")?;
}
self.flags.fmt(fmt)?;
for bit in self.type_path.iter() {
fmt.write_str(bit)?;
fmt.write_str("/")?;

View file

@ -434,7 +434,7 @@ pub(crate) fn evaluate_all(context: &Context, tree: &mut ObjectTree) {
if !tree[ty]
.get_var_declaration(&key, tree)
.map_or(true, |x| {
x.var_type.is_const_evaluable() && (x.var_type.is_const || ty != NodeIndex::new(0))
x.var_type.is_const_evaluable() && (x.var_type.flags.is_const() || ty != NodeIndex::new(0))
})
{
continue; // skip non-constant-evaluable vars
@ -497,7 +497,7 @@ fn constant_ident_lookup(
var.value.location,
format!("non-const-evaluable variable: {}", ident),
));
} else if !decl.var_type.is_const && must_be_const {
} else if !decl.var_type.flags.is_const() && must_be_const {
return Err(DMError::new(
var.value.location,
format!("non-const variable: {}", ident),

View file

@ -919,7 +919,9 @@ impl ObjectTree {
where
I: Iterator<Item=&'a str>,
{
let (mut is_declaration, mut is_static, mut is_const, mut is_tmp, mut is_final, mut is_private, mut is_protected) = (false, false, false, false, false, false, false);
use super::ast::VarTypeFlags;
let mut is_declaration = false;
let mut flags = VarTypeFlags::default();
if is_var_decl(prev) {
is_declaration = true;
@ -927,14 +929,9 @@ impl ObjectTree {
Some(name) => name,
None => return Ok(None), // var{} block, children will be real vars
};
while prev == "global" || prev == "static" || prev == "tmp" || prev == "const" || prev == "SpacemanDMM_final" || prev == "SpacemanDMM_private" || prev == "SpacemanDMM_protected" {
while let Some(flag) = VarTypeFlags::from_name(prev) {
if let Some(name) = rest.next() {
is_static |= prev == "global" || prev == "static";
is_const |= prev == "const";
is_tmp |= prev == "tmp";
is_final |= prev == "SpacemanDMM_final";
is_private |= prev == "SpacemanDMM_private";
is_protected |= prev == "SpacemanDMM_protected";
flags |= flag;
prev = name;
} else {
return Ok(None); // var/const{} block, children will be real vars
@ -950,12 +947,7 @@ impl ObjectTree {
prev = each;
}
let mut var_type = VarType {
is_static,
is_const,
is_tmp,
is_final,
is_private,
is_protected,
flags,
type_path,
};
var_type.suffix(&suffix);

View file

@ -986,7 +986,7 @@ impl<'ctx, 'an, 'inp> Parser<'ctx, 'an, 'inp> {
.register(self.context);
}
let mut var_type: VarType = path.into_iter().collect();
if var_type.is_static {
if var_type.flags.is_static() {
DMError::new(leading_loc, "'static/' has no effect here")
.set_severity(Severity::Warning)
.with_errortype("static_in_proc_parameter")
@ -1460,25 +1460,25 @@ impl<'ctx, 'an, 'inp> Parser<'ctx, 'an, 'inp> {
};
let mut var_type = tree_path.into_iter().collect::<VarType>();
if var_type.is_tmp {
if var_type.flags.is_tmp() {
DMError::new(type_path_start, "var/tmp has no effect here")
.set_severity(Severity::Warning)
.with_errortype("tmp_no_effect")
.register(self.context);
}
if var_type.is_final {
if var_type.flags.is_final() {
DMError::new(type_path_start, "var/final has no effect here")
.set_severity(Severity::Warning)
.with_errortype("final_no_effect")
.register(self.context);
}
if var_type.is_private {
if var_type.flags.is_private() {
DMError::new(type_path_start, "var/SpacemanDMM_private has no effect here")
.with_errortype("private_var")
.set_severity(Severity::Warning)
.register(self.context);
}
if var_type.is_protected {
if var_type.flags.is_protected() {
DMError::new(type_path_start, "var/SpacemanDMM_protected has no effect here")
.with_errortype("protected_var")
.set_severity(Severity::Warning)

View file

@ -14,7 +14,7 @@ use crate::symbol_search::contains;
pub fn item_var(ty: TypeRef, name: &str, var: &TypeVar) -> CompletionItem {
let mut detail = ty.pretty_path().to_owned();
if let Some(ref decl) = var.declaration {
if decl.var_type.is_const {
if decl.var_type.flags.is_const() {
if let Some(ref constant) = var.value.constant {
if ty.is_root() {
detail = constant.to_string();

View file

@ -105,7 +105,7 @@ impl<'o> WalkProc<'o> {
fn visit_var(&mut self, _location: Location, var_type: &VarType, name: &str, _value: Option<&'o Expression>) {
// static and const vars do not exist in the stack frame
if !var_type.is_static && !var_type.is_const {
if !var_type.flags.is_static() && !var_type.flags.is_const() {
self.local_vars.push(name.to_owned());
}
}

View file

@ -1102,22 +1102,22 @@ handle_method_call! {
if let Some(ref decl) = var.declaration {
let mut declaration = String::new();
declaration.push_str("var");
if decl.var_type.is_static {
if decl.var_type.flags.is_static() {
declaration.push_str("/static");
}
if decl.var_type.is_const {
if decl.var_type.flags.is_const() {
declaration.push_str("/const");
}
if decl.var_type.is_tmp {
if decl.var_type.flags.is_tmp() {
declaration.push_str("/tmp");
}
if decl.var_type.is_final {
if decl.var_type.flags.is_final() {
declaration.push_str("/SpacemanDMM_final");
}
if decl.var_type.is_private {
if decl.var_type.flags.is_private() {
declaration.push_str("/SpacemanDMM_private");
}
if decl.var_type.is_protected {
if decl.var_type.flags.is_protected() {
declaration.push_str("/SpacemanDMM_protected");
}
for bit in decl.var_type.type_path.iter() {