diff --git a/CONFIGURING.md b/CONFIGURING.md index a4a7c8e5..ca8dbc3a 100644 --- a/CONFIGURING.md +++ b/CONFIGURING.md @@ -101,6 +101,26 @@ The `[dmdoc]` section has the following options: * `use_typepath_names` - Set to `true` to have dmdoc use the true typepath name instead of the value of the `name` var for types +### Directives + +The `[procdirective]` section can be used to change the limitations of proc directives, the following names can be used which each corrospond to a `set SpacemanDMM_` proc directive: + +* `must_call_parent` +* `must_not_override` +* `private` +* `protected` +* `must_not_sleep` +* `must_be_pure` +* `can_be_redefined` + +In each section you can set the following as `true` or `false`: + +* `can_be_disabled` - Allows the directive to be set false in a child proc +* `set_at_definition` - Enforces the requirement the directive be set in the proc definition +* `can_be_global` - Allows the directive to be set in global procs + +See the example below on how to use these. + ## Example ```toml @@ -113,4 +133,8 @@ dreamchecker = true [diagnostics] duplicate_include = "error" macro_redefined = "off" + +[procdirective] + [procdirective.must_call_parent] + can_be_disabled = false ``` diff --git a/src/dreamchecker/lib.rs b/src/dreamchecker/lib.rs index 4e1a5958..3789289d 100644 --- a/src/dreamchecker/lib.rs +++ b/src/dreamchecker/lib.rs @@ -8,6 +8,7 @@ use dm::{Context, DMError, Location, Severity}; use dm::objtree::{ObjectTree, TypeRef, ProcRef, Code}; use dm::constants::{Constant, ConstFn}; use dm::ast::*; +use dm::config::*; use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; @@ -518,6 +519,35 @@ impl DMErrorExt for DMError { } } +trait DirectiveFromConfig { + fn to_proc_directive(self, directive_string: &'static str) -> ProcDirective; +} + +macro_rules! to_proc_directive { + ($name: ident) => { + impl DirectiveFromConfig for $name { + fn to_proc_directive(self, directive_string: &'static str) -> ProcDirective { + ProcDirective { + directive: Default::default(), + directive_string, + can_be_disabled: self.can_be_disabled, + set_at_definition: self.set_at_definition, + can_be_global: self.can_be_global, + } + } + } + } +} + +to_proc_directive! { MustCallParent } +to_proc_directive! { MustNotOverride } +to_proc_directive! { PrivateDirective } +to_proc_directive! { ProtectedDirective } +to_proc_directive! { MustNotSleep } +to_proc_directive! { SleepExempt } +to_proc_directive! { MustBePure } +to_proc_directive! { CanBeRedefined } + #[derive(Default)] pub struct ViolatingProcs<'o> { violators: HashMap, Vec<(String, Location)>>, @@ -584,14 +614,14 @@ impl<'o> AnalyzeObjectTree<'o> { context, objtree, return_type, - must_call_parent: ProcDirective::new("SpacemanDMM_should_call_parent", true, false, false), - must_not_override: ProcDirective::new("SpacemanDMM_should_not_override", false, false, false), - private: ProcDirective::new("SpacemanDMM_private_proc", false, true, false), - protected: ProcDirective::new("SpacemanDMM_protected_proc", false, true, false), - must_not_sleep: ProcDirective::new("SpacemanDMM_should_not_sleep", false, true, true), - sleep_exempt: ProcDirective::new("SpacemanDMM_allowed_to_sleep", false, true, true), - must_be_pure: ProcDirective::new("SpacemanDMM_should_be_pure", false, true, true), - can_be_redefined: ProcDirective::new("SpacemanDMM_can_be_redefined", false, false, false), + must_call_parent: context.config().procdirective.must_call_parent.to_proc_directive("SpacemanDMM_should_call_parent"), + must_not_override: context.config().procdirective.must_not_override.to_proc_directive("SpacemanDMM_should_not_override"), + private: context.config().procdirective.private.to_proc_directive("SpacemanDMM_private_proc"), + protected: context.config().procdirective.protected.to_proc_directive("SpacemanDMM_protected_proc"), + must_not_sleep: context.config().procdirective.must_not_sleep.to_proc_directive("SpacemanDMM_should_not_sleep"), + sleep_exempt: context.config().procdirective.sleep_exempt.to_proc_directive("SpacemanDMM_allowed_to_sleep"), + must_be_pure: context.config().procdirective.must_be_pure.to_proc_directive("SpacemanDMM_should_be_pure"), + can_be_redefined: context.config().procdirective.can_be_redefined.to_proc_directive("SpacemanDMM_can_be_redefined"), used_kwargs: Default::default(), call_tree: Default::default(), sleeping_procs: Default::default(), @@ -613,8 +643,8 @@ impl<'o> AnalyzeObjectTree<'o> { #[inline] fn add_directive_or_error(&mut self, proc: ProcRef<'o>, directive: &str, expr: &Expression, location: Location) { let procdirective = match directive { - "SpacemanDMM_should_not_override" => &mut self.must_not_override, "SpacemanDMM_should_call_parent" => &mut self.must_call_parent, + "SpacemanDMM_should_not_override" => &mut self.must_not_override, "SpacemanDMM_private_proc" => &mut self.private, "SpacemanDMM_protected_proc" => &mut self.protected, "SpacemanDMM_should_not_sleep" => &mut self.must_not_sleep, diff --git a/src/dreamchecker/test_helpers.rs b/src/dreamchecker/test_helpers.rs index dd7d14b9..070ad10f 100644 --- a/src/dreamchecker/test_helpers.rs +++ b/src/dreamchecker/test_helpers.rs @@ -42,7 +42,7 @@ pub fn check_errors_match>>(buffer: S, errorlist: &[(u )); } } - if iter.next().is_some() { - panic!("found more errors than was expected"); + if let Some(nexterror) = iter.next() { + panic!(format!("found more errors than was expected, next was: {}:{}:{}", nexterror.location().line, nexterror.location().column, nexterror.description())); } } diff --git a/src/dreammaker/config.rs b/src/dreammaker/config.rs index bb8785c8..17f885ca 100644 --- a/src/dreammaker/config.rs +++ b/src/dreammaker/config.rs @@ -24,6 +24,7 @@ pub struct Config { // tool-specific configuration pub langserver: Langserver, pub dmdoc: DMDoc, + pub procdirective: ProcDirectiveSection, } /// General error display options @@ -186,3 +187,47 @@ impl From for Error { Error::Toml(err) } } + +#[derive(Debug, Deserialize, Default, Clone)] +#[serde(default)] +pub struct ProcDirectiveSection { + pub must_call_parent: MustCallParent, + pub must_not_override: MustNotOverride, + pub private: PrivateDirective, + pub protected: ProtectedDirective, + pub must_not_sleep: MustNotSleep, + pub sleep_exempt: SleepExempt, + pub must_be_pure: MustBePure, + pub can_be_redefined: CanBeRedefined, +} + +macro_rules! procdirective { + ($name: ident $cbd: tt $sad: tt $cbg: tt) => { + #[derive(Debug, Deserialize, Clone, Copy)] + #[serde(default)] + pub struct $name { + pub can_be_disabled: bool, + pub set_at_definition: bool, + pub can_be_global: bool, + } + + impl Default for $name { + fn default() -> Self { + $name { + can_be_disabled: $cbd, + set_at_definition: $sad, + can_be_global: $cbg, + } + } + } + }; +} + +procdirective! {MustCallParent true false false} +procdirective! {MustNotOverride false false false} +procdirective! {PrivateDirective false true false} +procdirective! {ProtectedDirective false true false} +procdirective! {MustNotSleep false true true} +procdirective! {SleepExempt false true true} +procdirective! {MustBePure false true true} +procdirective! {CanBeRedefined false false false}