microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.2.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

compiler/qsc_frontend/src/compile/preprocess.rs

145lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use core::str::FromStr;
5use qsc_ast::{
6 ast::{Attr, ExprKind, ItemKind, Namespace, Stmt, StmtKind},
7 mut_visit::MutVisitor,
8};
9use qsc_hir::hir;
10use std::rc::Rc;
11
12use super::{ConfigAttr, RuntimeCapabilityFlags};
13
14#[derive(PartialEq, Hash, Clone, Debug)]
15pub struct TrackedName {
16 pub name: Rc<str>,
17 pub namespace: Rc<str>,
18}
19
20pub(crate) struct Conditional {
21 capabilities: RuntimeCapabilityFlags,
22 dropped_names: Vec<TrackedName>,
23 included_names: Vec<TrackedName>,
24}
25
26impl Conditional {
27 pub(crate) fn new(capabilities: RuntimeCapabilityFlags) -> Self {
28 Self {
29 capabilities,
30 dropped_names: Vec::new(),
31 included_names: Vec::new(),
32 }
33 }
34
35 pub(crate) fn into_names(self) -> Vec<TrackedName> {
36 self.dropped_names
37 .into_iter()
38 .filter(|n| !self.included_names.contains(n))
39 .collect()
40 }
41}
42
43impl MutVisitor for Conditional {
44 fn visit_namespace(&mut self, namespace: &mut Namespace) {
45 namespace.items = namespace
46 .items
47 .iter()
48 .filter_map(|item| {
49 if matches_config(&item.attrs, self.capabilities) {
50 match item.kind.as_ref() {
51 ItemKind::Callable(callable) => {
52 self.included_names.push(TrackedName {
53 name: callable.name.name.clone(),
54 namespace: namespace.name.name.clone(),
55 });
56 }
57 ItemKind::Ty(ident, _) => self.included_names.push(TrackedName {
58 name: ident.name.clone(),
59 namespace: namespace.name.name.clone(),
60 }),
61 _ => {}
62 }
63 Some(item.clone())
64 } else {
65 match item.kind.as_ref() {
66 ItemKind::Callable(callable) => {
67 self.dropped_names.push(TrackedName {
68 name: callable.name.name.clone(),
69 namespace: namespace.name.name.clone(),
70 });
71 }
72 ItemKind::Ty(ident, _) => self.dropped_names.push(TrackedName {
73 name: ident.name.clone(),
74 namespace: namespace.name.name.clone(),
75 }),
76 _ => {}
77 }
78 None
79 }
80 })
81 .collect::<Vec<_>>()
82 .into_boxed_slice();
83 }
84
85 fn visit_stmt(&mut self, stmt: &mut Stmt) {
86 if let StmtKind::Item(item) = stmt.kind.as_mut() {
87 if matches_config(&item.attrs, self.capabilities) {
88 match item.kind.as_ref() {
89 ItemKind::Callable(callable) => {
90 self.included_names.push(TrackedName {
91 name: callable.name.name.clone(),
92 namespace: Rc::from(""),
93 });
94 }
95 ItemKind::Ty(ident, _) => self.included_names.push(TrackedName {
96 name: ident.name.clone(),
97 namespace: Rc::from(""),
98 }),
99 _ => {}
100 }
101 } else {
102 match item.kind.as_ref() {
103 ItemKind::Callable(callable) => {
104 self.dropped_names.push(TrackedName {
105 name: callable.name.name.clone(),
106 namespace: Rc::from(""),
107 });
108 }
109 ItemKind::Ty(ident, _) => self.dropped_names.push(TrackedName {
110 name: ident.name.clone(),
111 namespace: Rc::from(""),
112 }),
113 _ => {}
114 }
115 stmt.kind = Box::new(StmtKind::Empty);
116 }
117 }
118 }
119}
120
121fn matches_config(attrs: &[Box<Attr>], capabilities: RuntimeCapabilityFlags) -> bool {
122 attrs.iter().all(|attr| {
123 if hir::Attr::from_str(attr.name.name.as_ref()) == Ok(hir::Attr::Config) {
124 if let ExprKind::Paren(inner) = attr.arg.kind.as_ref() {
125 match inner.kind.as_ref() {
126 // If there is no config attribute, then we assume that the item matches
127 // the target. We can't do membership tests on the capabilities because
128 // Base is not a subset of any capabilities, it is a lack of capabilities.
129 ExprKind::Path(path) => match ConfigAttr::from_str(path.name.name.as_ref()) {
130 Ok(ConfigAttr::Unrestricted) => capabilities.is_all(),
131 Ok(ConfigAttr::Base) => capabilities.is_empty(),
132 _ => true,
133 },
134 _ => true, // Unknown config attribute, so we assume it matches
135 }
136 } else {
137 // Something other than a parenthesized expression, so we assume it matches
138 true
139 }
140 } else {
141 // Unknown attribute, so we assume it matches
142 true
143 }
144 })
145}
146