1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Copyright 2020-2021, The Tremor Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{
arena::{self, Arena},
ast::{self, docs::Docs, helper::Warning, DeployStmt},
errors::Result,
highlighter::Highlighter,
lexer::{self, Lexer},
prelude::*,
};
use std::collections::BTreeSet;
/// A tremor deployment ( troy)
#[derive(Debug, Clone)]
pub struct Deploy {
/// The deployment
pub deploy: ast::Deploy<'static>,
/// Source of the query
pub aid: arena::Index,
/// Warnings emitted by the script
pub warnings: BTreeSet<Warning>,
/// Number of local variables (should be 0)
pub locals: usize,
}
impl<'run, 'event, 'script> Deploy
where
'script: 'event,
'event: 'run,
{
/// Removes a deploy from the arena, freeing the memory and marking it valid for reause
/// this function generally should not ever be used. It is a special case for the language
/// server where we know that we really only parse the script to check for errors and
/// warnings.
/// That's also why it's behind a feature falg
#[cfg(feature = "arena-delete")]
pub unsafe fn consume_and_free(self) -> Result<()> {
let Deploy { aid, deploy, .. } = self;
drop(deploy);
Arena::delte_index_this_is_really_unsafe_dont_use_it(aid)
}
/// Retrieve deployment unit
/// # Errors
/// If the underlying structures do not resolve to a correctly deployable unit
pub fn iter_flows(&self) -> impl Iterator<Item = &ast::DeployFlow<'static>> {
self.deploy.stmts.iter().filter_map(|stmt| {
if let DeployStmt::DeployFlowStmt(stmt) = stmt {
Some(stmt.as_ref())
} else {
None
}
})
}
/// Provides a `GraphViz` dot representation of the deployment graph
#[must_use]
pub fn dot(&self) -> String {
self.deploy.dot()
}
/// Returns the documentation for the Deployment
#[must_use]
pub fn docs(&self) -> &Docs {
&self.deploy.docs
}
/// Parses a string into a deployment
///
/// # Errors
/// if the deployment can not be parsed
fn parse_(
aid: arena::Index,
src: &'static str,
reg: &Registry,
aggr_reg: &AggrRegistry,
) -> Result<Self> {
let mut helper = ast::Helper::new(reg, aggr_reg);
//let cu = include_stack.push(&file_name)?;
let tokens = Lexer::new(src, aid).collect::<Result<Vec<_>>>()?;
let filtered_tokens = tokens.into_iter().filter(|t| !t.value.is_ignorable());
let script_stage_1 = crate::parser::g::DeployParser::new().parse(filtered_tokens)?;
let deploy = script_stage_1.up_script(&mut helper)?;
// let mut warnings = BTreeSet::new();
// std::mem::swap(&mut warnings, &mut helper.warnings);
let locals = helper.locals.len();
Ok(Self {
deploy,
aid,
warnings: helper.warnings,
locals,
})
}
/// Parses a string into a deployment
///
/// this is used in the language server to delete lements on a
/// parsing error
///
/// # Errors
/// if the deployment can not be parsed
#[cfg(feature = "arena-delete")]
pub fn parse_with_aid<S>(
src: &S,
reg: &Registry,
aggr_reg: &AggrRegistry,
) -> std::result::Result<Self, crate::errors::ErrorWithIndex>
where
S: ToString + ?Sized,
{
let (aid, src) = Arena::insert(src)?;
Self::parse_(aid, src, reg, aggr_reg).map_err(|e| crate::errors::ErrorWithIndex(aid, e))
}
/// Parses a string into a deployment
///
/// # Errors
/// if the deployment can not be parsed
pub fn parse<S>(src: &S, reg: &Registry, aggr_reg: &AggrRegistry) -> Result<Self>
where
S: ToString + ?Sized,
{
let (aid, src) = Arena::insert(src)?;
Self::parse_(aid, src, reg, aggr_reg)
}
/// Format an error given a script source.
/// # Errors
/// on io errors
pub fn format_warnings_with<H: Highlighter>(&self, h: &mut H) -> std::io::Result<()> {
for w in &self.warnings {
let tokens: Vec<_> = lexer::Lexer::new(Arena::io_get(self.aid)?, self.aid)
.tokenize_until_err()
.collect();
h.highlight_error(None, &tokens, "", true, Some(w.outer), Some(w.into()))?;
}
h.finalize()
}
}
#[cfg(test)]
mod test {
use super::*;
fn parse(query: &str) {
let reg = crate::registry();
let aggr_reg = crate::aggr_registry();
if let Err(e) = Deploy::parse(query, ®, &aggr_reg) {
eprintln!("{}", e);
assert!(false, "error during parsing")
} else {
assert!(true)
}
}
#[test]
fn basic_pipeline() {
parse(
r#"define flow test flow define pipeline passthrough pipeline select args from in into out end; end;"#,
);
}
}