Skip to content
Open
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
# Change Log

## 0.9.20

- The DLS will now properly not report conflicts between statements in a `#if` and its corresponding `#else` branch
- The DLS will now consider all `#if` branches on conditions directly based on `dml\_1\_2` and `dml\_1\_4` dead or alive appropriately

## 0.9.19
- Added configuration option to control the max cache size while resolving references in semantic analysis, defaulting to 500MB
Expand Down
165 changes: 111 additions & 54 deletions src/analysis/structure/toplevel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
// SPDX-License-Identifier: Apache-2.0 and MIT
use std::fmt::{Display, Formatter, self as fmt};
use std::path::PathBuf;
use std::sync::Arc;

use crate::analysis::templating::evaluation::{Evaluatable, EvaluationContext};
use crate::logging::trace;

use crate::analysis::structure::objects::{Bitorder, CBlock, CompObjectKind, CompositeObject, Constant, DMLObject, DMLStatement, Device, Error, Export, Hook, Import, InEach, Instantiation, Loggroup, Method, MethodModifier, Parameter, Statements, Template, ToStructure, Typedef, Variable, Version, make_statements};
use crate::analysis::structure::expressions::{Expression};
use crate::analysis::FileSpec;
use crate::analysis::{DMLError, FileSpec};
use crate::analysis::parsing::tree::{ZeroRange, ZeroSpan, TreeElement};
use crate::analysis::parsing::structure;
use crate::analysis::{DeclarationSpan, LocationSpan, Named,
Expand All @@ -30,7 +32,51 @@ pub enum ExistCondition {
// Note: Right now we are implicitly assuming this has some ordering, such
// that two objectdecls within the same hashif block will have the same
// existcondition
Conditional(Vec<(bool, Expression)>),
// These conditions are _hugely_ duplicated between objects, and are stored
// in an Arc to save memory. TODO: We could optimize this even further by
// storing references into a slice of conditional expression from outer
// to inner contexts
Conditional(Arc<Vec<(bool, Expression)>>),
}

impl ExistCondition {
pub fn exists(&self, context: &EvaluationContext, report: &mut Vec<DMLError>) -> bool {
match self {
ExistCondition::Always => true,
ExistCondition::Conditional(conds) => {
for (tbranch, cond) in conds.as_ref() {
let evaluated = cond.evaluate(context, report);
// TODO: check type and value validness
// NOTE: this concludes that non-evaluatable conditions are treated
// as always existing
if evaluated.as_bool()
.is_some_and(|b|b != *tbranch) {
return false;
}
}
true
}
}
}
pub fn guaranteed_exists(&self, context: &EvaluationContext, report: &mut Vec<DMLError>) -> bool {
match self {
ExistCondition::Always => true,
ExistCondition::Conditional(conds) => {
for (tbranch, cond) in conds.as_ref() {
let evaluated = cond.evaluate(context, report);
// TODO: check type and value validness
if let Some(value) = evaluated.as_bool() {
if value != *tbranch {
return false;
}
} else {
return false;
}
}
true
}
}
}
}

impl ExistCondition {
Expand All @@ -39,10 +85,8 @@ impl ExistCondition {
(ExistCondition::Always, ExistCondition::Always) => true,
(ExistCondition::Conditional(selfvec),
ExistCondition::Conditional(othervec)) => {
// This becomes equivalent to checking if they are in the
// same nested hashifs
// As it turns out, collision is guaranted regardless of
// which branch they are in
// Currently we cannt check if a condition is equivalent with another,
// so we will only check if they are literally the same condition expression
for ((_, cond1),
(_, cond2)) in selfvec.iter().zip(othervec.iter()) {
if cond1 != cond2 {
Expand All @@ -54,6 +98,27 @@ impl ExistCondition {
_ => false,
}
}

pub fn guaranteed_excluded_from(&self, other: &ExistCondition) -> bool {
match (self, other) {
(ExistCondition::Conditional(selfvec),
ExistCondition::Conditional(othervec)) => {
// Currently we cannt check if a condition is equivalent with another,
// so we will only check if they are literally the same condition expression
for ((inverted1, cond1),
(inverted2, cond2)) in selfvec.iter().zip(othervec.iter()) {
if cond1 != cond2 {
return false;
}
if inverted1 != inverted2 {
return true;
}
}
false
},
_ => false,
}
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -154,16 +219,10 @@ where T: DeclarationSpan {

impl <T: Clone> ObjectDecl<T>
where T: DeclarationSpan {
pub fn depending_on_context(obj: &T,
context: StatementContext,
conds: &[(bool, Expression)])
pub fn with_conds(obj: &T,
conds: &Arc<Vec<(bool, Expression)>>)
-> ObjectDecl<T> {
match context {
StatementContext::HashIfTrue |
StatementContext::HashIfElse =>
ObjectDecl::conditional(obj, conds),
_ => ObjectDecl::always(obj),
}
ObjectDecl::conditional(obj, conds)
}

pub fn always(obj: &T) -> ObjectDecl<T> {
Expand All @@ -174,10 +233,10 @@ where T: DeclarationSpan {
}
}
pub fn conditional(obj: &T,
conds: &[(bool, Expression)])
conds: &Arc<Vec<(bool, Expression)>>)
-> ObjectDecl<T> {
ObjectDecl {
cond: ExistCondition::Conditional(conds.to_vec()),
cond: ExistCondition::Conditional(Arc::clone(conds)),
obj: obj.clone(),
spec: StatementSpec::empty(),
}
Expand Down Expand Up @@ -330,7 +389,7 @@ impl StatementSpec {
// Flattens hashifs
fn flatten_hashif_branch(context: StatementContext,
stmnts: &Statements,
conds: Vec<(bool, Expression)>,
conds: Arc<Vec<(bool, Expression)>>,
report: &mut Vec<LocalDMLError>)
-> StatementSpec {
let mut objects = vec![];
Expand All @@ -347,24 +406,23 @@ fn flatten_hashif_branch(context: StatementContext,
let mut errors = vec![];
let mut templates = vec![];
for inst in &stmnts.instantiations {
instantiations.push(ObjectDecl::depending_on_context(
inst, context, &conds));
instantiations.push(ObjectDecl::with_conds(
inst, &conds));
}
for err in &stmnts.errors {
errors.push(ObjectDecl::depending_on_context(
err, context, &conds));
errors.push(ObjectDecl::with_conds(
err, &conds));
}
for ineach in stmnts.ineachs.iter() {
let spec = flatten_hashif_branch(StatementContext::InEach,
&ineach.statements,
vec![], report);
Arc::default(), report);
ineachs.push(
ObjectDecl {
cond: match context {
StatementContext::HashIfTrue |
StatementContext::HashIfElse =>
ExistCondition::Conditional(
conds.clone()),
ExistCondition::Conditional(Arc::clone(&conds)),
_ => ExistCondition::Always,
},
obj: ineach.clone(),
Expand Down Expand Up @@ -412,7 +470,7 @@ fn flatten_hashif_branch(context: StatementContext,
let subspec = flatten_hashif_branch(
StatementContext::Template,
&tmpl.statements,
vec![],
Arc::default(),
report);
templates.push(
ObjectDecl {
Expand Down Expand Up @@ -444,8 +502,8 @@ fn flatten_hashif_branch(context: StatementContext,
// TODO: Verify that conditions are constants
// or builtin parameters
DMLObject::Import(import) =>
imports.push(ObjectDecl::depending_on_context(
import, context, &conds)),
imports.push(ObjectDecl::with_conds(
import, &conds)),
DMLObject::Loggroup(loggroup) =>
report.push(LocalDMLError {
range: loggroup.span.range,
Expand All @@ -464,26 +522,25 @@ fn flatten_hashif_branch(context: StatementContext,
let subspec = flatten_hashif_branch(
StatementContext::Object,
&compobj.statements,
vec![], report);
Arc::clone(&conds), report);
objects.push(
ObjectDecl {
cond: match context {
StatementContext::HashIfTrue |
StatementContext::HashIfElse =>
ExistCondition::Conditional(
conds.clone()),
ExistCondition::Conditional(Arc::clone(&conds)),
_ => ExistCondition::Always,
},
obj: compobj.clone(),
spec: subspec,
});
},
DMLObject::Export(exp) =>
exports.push(ObjectDecl::depending_on_context(
exp, context, &conds)),
exports.push(ObjectDecl::with_conds(
exp, &conds)),
DMLObject::Hook(hook)=>
hooks.push(ObjectDecl::depending_on_context(
hook, context, &conds)),
hooks.push(ObjectDecl::with_conds(
hook, &conds)),
DMLObject::Method(meth) =>
// This error has already been reported, but
// we also need to clear our and pretend
Expand All @@ -496,40 +553,40 @@ fn flatten_hashif_branch(context: StatementContext,
modified_method.modifier
= MethodModifier::None;
methods.push(
ObjectDecl::depending_on_context(
&modified_method, context, &conds))
ObjectDecl::with_conds(
&modified_method, &conds))
} else {
methods.push(
ObjectDecl::depending_on_context(
meth, context, &conds))
ObjectDecl::with_conds(
meth, &conds))
},
DMLObject::Saved(saved) =>
saveds.push(ObjectDecl::depending_on_context(
saved, context, &conds)),
saveds.push(ObjectDecl::with_conds(
saved, &conds)),
DMLObject::Session(sess) =>
sessions.push(ObjectDecl::depending_on_context(
sess, context, &conds)),
sessions.push(ObjectDecl::with_conds(
sess, &conds)),
DMLObject::Parameter(param) =>
params.push(ObjectDecl::depending_on_context(
param, context, &conds)),
params.push(ObjectDecl::with_conds(
param, &conds)),
}
},
DMLStatement::HashIf(hi) => {
let mut true_conds = conds.clone();
let mut true_conds = (*conds).clone();
true_conds.push(
(true, hi.condition.clone()));
let mut false_conds = conds.clone();
let mut false_conds = (*conds).clone();
false_conds.push(
(false, hi.condition.clone()));
let truebranchspec = flatten_hashif_branch(
StatementContext::HashIfTrue,
&hi.truebranch,
true_conds,
Arc::new(true_conds),
report);
let falsebranchspec = flatten_hashif_branch(
StatementContext::HashIfElse,
&hi.falsebranch,
false_conds,
Arc::new(false_conds),
report);
truebranchspec.consume(&mut objects,
&mut sessions,
Expand Down Expand Up @@ -695,7 +752,7 @@ impl TopLevel {
for ineach in &statements.ineachs {
let spec = flatten_hashif_branch(StatementContext::Object,
&ineach.statements,
vec![], report);
Arc::default(), report);
ineachs.push(
ObjectDecl {
cond: ExistCondition::Always,
Expand Down Expand Up @@ -748,7 +805,7 @@ impl TopLevel {
let subspec = flatten_hashif_branch(
StatementContext::Template,
&tmpl.statements,
vec![],
Arc::default(),
report);
templates.push(
ObjectDecl {
Expand All @@ -768,7 +825,7 @@ impl TopLevel {
let subspec = flatten_hashif_branch(
StatementContext::Object,
&compobj.statements,
vec![], report);
Arc::default(), report);
objects.push(
ObjectDecl {
cond: ExistCondition::Always,
Expand Down Expand Up @@ -803,8 +860,8 @@ impl TopLevel {
DMLStatement::HashIf(hi) => {
// First element of the cond tuple is whether the
// condition is NOT in an elsebranch
let true_conds = vec![(true, hi.condition.clone())];
let false_conds = vec![(false, hi.condition.clone())];
let true_conds = Arc::new(vec![(true, hi.condition.clone())]);
let false_conds = Arc::new(vec![(false, hi.condition.clone())]);
let truebranchspec = flatten_hashif_branch(
StatementContext::HashIfTrue,
&hi.truebranch,
Expand Down
Loading
Loading