mirror of
https://github.com/nushell/nushell
synced 2025-01-16 07:04:09 +00:00
Add var usage
This commit is contained in:
parent
e3abadd686
commit
43fd0b6ae9
3 changed files with 49 additions and 14 deletions
|
@ -6,4 +6,5 @@ pub enum ParseError {
|
||||||
UnexpectedEof(String, Span),
|
UnexpectedEof(String, Span),
|
||||||
UnknownStatement(Span),
|
UnknownStatement(Span),
|
||||||
Mismatch(String, Span),
|
Mismatch(String, Span),
|
||||||
|
VariableNotFound(Span),
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,22 @@ fn garbage(span: Span) -> Expression {
|
||||||
Expression::garbage(span)
|
Expression::garbage(span)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_identifier_byte(b: u8) -> bool {
|
||||||
|
b != b'.' && b != b'[' && b != b'(' && b != b'{'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_identifier(bytes: &[u8]) -> bool {
|
||||||
|
bytes.iter().all(|x| is_identifier_byte(*x))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_variable(bytes: &[u8]) -> bool {
|
||||||
|
if bytes.len() > 1 && bytes[0] == b'$' {
|
||||||
|
is_identifier(&bytes[1..])
|
||||||
|
} else {
|
||||||
|
is_identifier(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn span(spans: &[Span]) -> Span {
|
fn span(spans: &[Span]) -> Span {
|
||||||
let length = spans.len();
|
let length = spans.len();
|
||||||
|
|
||||||
|
@ -254,9 +270,25 @@ impl ParserWorkingSet {
|
||||||
span: Span,
|
span: Span,
|
||||||
shape: SyntaxShape,
|
shape: SyntaxShape,
|
||||||
) -> (Expression, Option<ParseError>) {
|
) -> (Expression, Option<ParseError>) {
|
||||||
|
let bytes = self.get_span_contents(span);
|
||||||
|
if !bytes.is_empty() && bytes[0] == b'$' {
|
||||||
|
if let Some((var_id, _, ty)) = self.find_variable(bytes) {
|
||||||
|
return (
|
||||||
|
Expression {
|
||||||
|
expr: Expr::Var(var_id),
|
||||||
|
ty,
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (garbage(span), Some(ParseError::VariableNotFound(span)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match shape {
|
match shape {
|
||||||
SyntaxShape::Number => {
|
SyntaxShape::Number => {
|
||||||
if let Ok(token) = String::from_utf8(self.get_span_contents(span).into()) {
|
if let Ok(token) = String::from_utf8(bytes.into()) {
|
||||||
self.parse_number(&token, span)
|
self.parse_number(&token, span)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
|
@ -280,13 +312,17 @@ impl ParserWorkingSet {
|
||||||
self.parse_math_expression(spans)
|
self.parse_math_expression(spans)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_variable(&mut self, span: Span) -> Option<ParseError> {
|
pub fn parse_variable(&mut self, span: Span) -> (Option<VarId>, Option<ParseError>) {
|
||||||
let contents = self.get_span_contents(span);
|
let bytes = self.get_span_contents(span);
|
||||||
|
|
||||||
if !contents.is_empty() && contents[0] == b'$' {
|
if is_variable(bytes) {
|
||||||
None
|
if let Some((var_id, _, _)) = self.find_variable(bytes) {
|
||||||
|
(Some(var_id), None)
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Some(ParseError::Mismatch("variable".into(), span))
|
(None, Some(ParseError::Mismatch("variable".into(), span)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +340,7 @@ impl ParserWorkingSet {
|
||||||
pub fn parse_let(&mut self, spans: &[Span]) -> (Statement, Option<ParseError>) {
|
pub fn parse_let(&mut self, spans: &[Span]) -> (Statement, Option<ParseError>) {
|
||||||
let mut error = None;
|
let mut error = None;
|
||||||
if spans.len() >= 4 && self.parse_keyword(spans[0], b"let").is_none() {
|
if spans.len() >= 4 && self.parse_keyword(spans[0], b"let").is_none() {
|
||||||
let err = self.parse_variable(spans[1]);
|
let (_, err) = self.parse_variable(spans[1]);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let err = self.parse_keyword(spans[2], b"=");
|
let err = self.parse_keyword(spans[2], b"=");
|
||||||
|
@ -369,8 +405,6 @@ impl ParserWorkingSet {
|
||||||
let (output, err) = lite_parse(&output);
|
let (output, err) = lite_parse(&output);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
println!("{:?}", output);
|
|
||||||
|
|
||||||
let (output, err) = self.parse_block(&output);
|
let (output, err) = self.parse_block(&output);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
|
|
|
@ -122,15 +122,15 @@ impl ParserWorkingSet {
|
||||||
self.scope.push(ScopeFrame::new());
|
self.scope.push(ScopeFrame::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_variable(&self, name: &[u8]) -> Option<(VarLocation, Type)> {
|
pub fn find_variable(&self, name: &[u8]) -> Option<(VarId, VarLocation, Type)> {
|
||||||
for scope in self.scope.iter().rev().enumerate() {
|
for scope in self.scope.iter().rev().enumerate() {
|
||||||
if let Some(result) = scope.1.vars.get(name) {
|
if let Some(var_id) = scope.1.vars.get(name) {
|
||||||
if let Some(result) = self.vars.get(result) {
|
if let Some(result) = self.vars.get(var_id) {
|
||||||
if scope.0 == 0 {
|
if scope.0 == 0 {
|
||||||
// Top level
|
// Top level
|
||||||
return Some((VarLocation::CurrentScope, result.clone()));
|
return Some((*var_id, VarLocation::CurrentScope, *result));
|
||||||
} else {
|
} else {
|
||||||
return Some((VarLocation::OuterScope, result.clone()));
|
return Some((*var_id, VarLocation::OuterScope, *result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue