1use crate::{
2 lex, parse_block,
3 parse_helpers::garbage_pipeline,
4 parser::{
5 ArgumentParsingLevel, ParsedInternalCall, parse_internal_call, parse_var_with_opt_type,
6 },
7 type_check::{check_pipeline_type, type_compatible},
8};
9
10use log::trace;
11use nu_protocol::{
12 ParseError, Span, Type,
13 ast::{Argument, Call, Expr, Expression, Pipeline},
14 engine::StateWorkingSet,
15 eval_const::eval_constant,
16};
17use std::{collections::HashMap, sync::Arc};
18
19pub fn parse_let(
21 working_set: &mut StateWorkingSet,
22 spans: &[Span],
23 input_type: Option<&Type>,
24) -> Pipeline {
25 trace!("parsing: let");
26
27 if let Some(decl_id) = working_set.find_decl(b"let") {
28 if spans.len() >= 4 {
29 for span in spans.iter().enumerate() {
30 let item = working_set.get_span_contents(*span.1);
31 if item == b"=" && spans.len() > (span.0 + 1) && span.0 > 1 {
32 let (tokens, parse_error) = lex(
33 working_set.get_span_contents(Span::concat(&spans[(span.0 + 1)..])),
34 spans[span.0 + 1].start,
35 &[],
36 &[],
37 false,
38 );
39
40 if let Some(parse_error) = parse_error {
41 working_set.error(parse_error)
42 }
43
44 let rvalue_span = Span::concat(&spans[(span.0 + 1)..]);
45 let rvalue_block =
46 parse_block(working_set, &tokens, rvalue_span, false, true, input_type);
47
48 let output_type = match rvalue_block.pipelines.as_slice() {
49 [pipeline] if let Some(input) = input_type => {
50 match check_pipeline_type(working_set, pipeline, input) {
51 Ok(output_ty) => output_ty,
52 Err((output_ty, errors)) => {
53 working_set.parse_errors.extend(errors);
54 output_ty
55 }
56 }
57 }
58 _ => rvalue_block.output_type(),
59 };
60
61 let block_id = working_set.add_block(Arc::new(rvalue_block));
62
63 let rvalue = Expression::new(
64 working_set,
65 Expr::Block(block_id),
66 rvalue_span,
67 output_type,
68 );
69
70 let mut idx = 0;
71 let (lvalue, explicit_type) = parse_var_with_opt_type(
72 working_set,
73 &spans[1..(span.0)],
74 &mut idx,
75 false,
76 input_type,
77 );
78 if idx + 1 < span.0 - 1 {
79 working_set.error(ParseError::ExtraTokens(spans[idx + 2]));
80 }
81
82 let var_id = lvalue.as_var();
83 let rhs_type = rvalue.ty.clone();
84
85 if let Some(explicit_type) = &explicit_type
86 && !type_compatible(explicit_type, &rhs_type)
87 {
88 working_set.error(ParseError::TypeMismatch(
89 explicit_type.clone(),
90 rhs_type.clone(),
91 Span::concat(&spans[(span.0 + 1)..]),
92 ));
93 }
94
95 if let Some(var_id) = var_id
96 && explicit_type.is_none()
97 {
98 working_set.set_variable_type(var_id, rhs_type);
99 }
100
101 let call = Box::new(Call {
102 decl_id,
103 head: spans[0],
104 arguments: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
105 parser_info: HashMap::new(),
106 });
107
108 return Pipeline::from_vec(vec![Expression::new(
109 working_set,
110 Expr::Call(call),
111 Span::concat(spans),
112 Type::Any,
113 )]);
114 }
115 }
116 }
117 let ParsedInternalCall { call, output, .. } = parse_internal_call(
118 working_set,
119 spans[0],
120 &spans[1..],
121 decl_id,
122 ArgumentParsingLevel::Full,
123 input_type,
124 );
125
126 return Pipeline::from_vec(vec![Expression::new(
127 working_set,
128 Expr::Call(call),
129 Span::concat(spans),
130 output,
131 )]);
132 } else {
133 working_set.error(ParseError::UnknownState(
134 "internal error: let or const statements not found in core language".into(),
135 Span::concat(spans),
136 ))
137 }
138
139 working_set.error(ParseError::UnknownState(
140 "internal error: let or const statement unparsable".into(),
141 Span::concat(spans),
142 ));
143
144 garbage_pipeline(working_set, spans)
145}
146
147pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> (Pipeline, Option<Span>) {
149 trace!("parsing: const");
150
151 if let Some(decl_id) = working_set.find_decl(b"const") {
152 if spans.len() >= 4 {
153 for span in spans.iter().enumerate() {
154 let item = working_set.get_span_contents(*span.1);
155 if item == b"=" && spans.len() > (span.0 + 1) && span.0 > 1 {
156 let rvalue_span = Span::concat(&spans[(span.0 + 1)..]);
157
158 let (rvalue_tokens, rvalue_error) = lex(
159 working_set.get_span_contents(rvalue_span),
160 rvalue_span.start,
161 &[],
162 &[],
163 false,
164 );
165 working_set.parse_errors.extend(rvalue_error);
166
167 trace!("parsing: const right-hand side subexpression");
168 let rvalue_block =
169 parse_block(working_set, &rvalue_tokens, rvalue_span, false, true, None);
170 let rvalue_ty = rvalue_block.output_type();
171 let rvalue_block_id = working_set.add_block(Arc::new(rvalue_block));
172 let rvalue = Expression::new(
173 working_set,
174 Expr::Subexpression(rvalue_block_id),
175 rvalue_span,
176 rvalue_ty,
177 );
178
179 let mut idx = 0;
180
181 let (lvalue, explicit_type) = parse_var_with_opt_type(
182 working_set,
183 &spans[1..(span.0)],
184 &mut idx,
185 false,
186 None,
187 );
188 if idx + 1 < span.0 - 1 {
189 working_set.error(ParseError::ExtraTokens(spans[idx + 2]));
190 }
191
192 let var_id = lvalue.as_var();
193 let rhs_type = rvalue.ty.clone();
194
195 if let Some(explicit_type) = &explicit_type
196 && !type_compatible(explicit_type, &rhs_type)
197 {
198 working_set.error(ParseError::TypeMismatch(
199 explicit_type.clone(),
200 rhs_type.clone(),
201 Span::concat(&spans[(span.0 + 1)..]),
202 ));
203 }
204
205 if let Some(var_id) = var_id {
206 if explicit_type.is_none() {
207 working_set.set_variable_type(var_id, rhs_type);
208 }
209
210 match eval_constant(working_set, &rvalue) {
211 Ok(mut value) => {
212 let mut const_type = value.get_type();
213
214 if let Some(explicit_type) = &explicit_type {
215 if !type_compatible(explicit_type, &const_type) {
216 working_set.error(ParseError::TypeMismatch(
217 explicit_type.clone(),
218 const_type.clone(),
219 Span::concat(&spans[(span.0 + 1)..]),
220 ));
221 }
222 let val_span = value.span();
223
224 match value {
225 nu_protocol::Value::String { val, .. }
226 if explicit_type == &nu_protocol::Type::Glob =>
227 {
228 value = nu_protocol::Value::glob(val, false, val_span);
229 const_type = value.get_type();
230 }
231 _ => {}
232 }
233 }
234
235 working_set.set_variable_type(var_id, const_type);
236
237 working_set.set_variable_const_val(var_id, value);
238 }
239 Err(err) => working_set.error(err.wrap(working_set, rvalue.span)),
240 }
241 }
242
243 let call = Box::new(Call {
244 decl_id,
245 head: spans[0],
246 arguments: vec![
247 Argument::Positional(lvalue.clone()),
248 Argument::Positional(rvalue),
249 ],
250 parser_info: HashMap::new(),
251 });
252
253 return (
254 Pipeline::from_vec(vec![Expression::new(
255 working_set,
256 Expr::Call(call),
257 Span::concat(spans),
258 Type::Any,
259 )]),
260 Some(lvalue.span),
261 );
262 }
263 }
264 }
265 let ParsedInternalCall { call, output, .. } = parse_internal_call(
266 working_set,
267 spans[0],
268 &spans[1..],
269 decl_id,
270 ArgumentParsingLevel::Full,
271 None,
272 );
273
274 return (
275 Pipeline::from_vec(vec![Expression::new(
276 working_set,
277 Expr::Call(call),
278 Span::concat(spans),
279 output,
280 )]),
281 None,
282 );
283 } else {
284 working_set.error(ParseError::UnknownState(
285 "internal error: let or const statements not found in core language".into(),
286 Span::concat(spans),
287 ))
288 }
289
290 working_set.error(ParseError::UnknownState(
291 "internal error: let or const statement unparsable".into(),
292 Span::concat(spans),
293 ));
294
295 (garbage_pipeline(working_set, spans), None)
296}
297
298pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline {
299 trace!("parsing: mut");
300
301 if let Some(decl_id) = working_set.find_decl(b"mut") {
302 if spans.len() >= 4 {
303 for span in spans.iter().enumerate() {
304 let item = working_set.get_span_contents(*span.1);
305 if item == b"=" && spans.len() > (span.0 + 1) && span.0 > 1 {
306 let (tokens, parse_error) = lex(
307 working_set.get_span_contents(Span::concat(&spans[(span.0 + 1)..])),
308 spans[span.0 + 1].start,
309 &[],
310 &[],
311 false,
312 );
313
314 if let Some(parse_error) = parse_error {
315 working_set.error(parse_error);
316 }
317
318 let rvalue_span = Span::concat(&spans[(span.0 + 1)..]);
319 let rvalue_block =
320 parse_block(working_set, &tokens, rvalue_span, false, true, None);
321
322 let output_type = rvalue_block.output_type();
323
324 let block_id = working_set.add_block(Arc::new(rvalue_block));
325
326 let rvalue = Expression::new(
327 working_set,
328 Expr::Block(block_id),
329 rvalue_span,
330 output_type,
331 );
332
333 let mut idx = 0;
334
335 let (lvalue, explicit_type) = parse_var_with_opt_type(
336 working_set,
337 &spans[1..(span.0)],
338 &mut idx,
339 true,
340 None,
341 );
342 if idx + 1 < span.0 - 1 {
343 working_set.error(ParseError::ExtraTokens(spans[idx + 2]));
344 }
345
346 let var_id = lvalue.as_var();
347 let rhs_type = rvalue.ty.clone();
348
349 if let Some(explicit_type) = &explicit_type
350 && !type_compatible(explicit_type, &rhs_type)
351 {
352 working_set.error(ParseError::TypeMismatch(
353 explicit_type.clone(),
354 rhs_type.clone(),
355 Span::concat(&spans[(span.0 + 1)..]),
356 ));
357 }
358
359 if let Some(var_id) = var_id
360 && explicit_type.is_none()
361 {
362 working_set.set_variable_type(var_id, rhs_type);
363 }
364
365 let call = Box::new(Call {
366 decl_id,
367 head: spans[0],
368 arguments: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
369 parser_info: HashMap::new(),
370 });
371
372 return Pipeline::from_vec(vec![Expression::new(
373 working_set,
374 Expr::Call(call),
375 Span::concat(spans),
376 Type::Any,
377 )]);
378 }
379 }
380 }
381 let ParsedInternalCall { call, output, .. } = parse_internal_call(
382 working_set,
383 spans[0],
384 &spans[1..],
385 decl_id,
386 ArgumentParsingLevel::Full,
387 None,
388 );
389
390 return Pipeline::from_vec(vec![Expression::new(
391 working_set,
392 Expr::Call(call),
393 Span::concat(spans),
394 output,
395 )]);
396 } else {
397 working_set.error(ParseError::UnknownState(
398 "internal error: let or const statements not found in core language".into(),
399 Span::concat(spans),
400 ))
401 }
402
403 working_set.error(ParseError::UnknownState(
404 "internal error: let or const statement unparsable".into(),
405 Span::concat(spans),
406 ));
407
408 garbage_pipeline(working_set, spans)
409}