Skip to content
Snippets Groups Projects
Commit a6fd2514 authored by Michael Aaron Murphy's avatar Michael Aaron Murphy
Browse files

Implement Multiple Assignments

parent 5d3ca899
No related branches found
No related tags found
No related merge requests found
...@@ -21,6 +21,7 @@ Ion is a shell for UNIX platforms, and is the default shell in Redox. It is stil ...@@ -21,6 +21,7 @@ Ion is a shell for UNIX platforms, and is the default shell in Redox. It is stil
- [x] Executing Scripts with an @args Array - [x] Executing Scripts with an @args Array
- [x] Aliases - [x] Aliases
- [x] Variables (**$variable**) - [x] Variables (**$variable**)
- [x] Multiple Variable Assignments
- [x] Substring Slicing of Variables - [x] Substring Slicing of Variables
- [x] Arrays (**@array**) - [x] Arrays (**@array**)
- [x] Array Expressions (**[]**) - [x] Array Expressions (**[]**)
...@@ -70,6 +71,14 @@ a similar action, only setting the variable globally as an environment variable ...@@ -70,6 +71,14 @@ a similar action, only setting the variable globally as an environment variable
let git_branch = $(git rev-parse --abbrev-ref HEAD ^> /dev/null) let git_branch = $(git rev-parse --abbrev-ref HEAD ^> /dev/null)
``` ```
It is also possible to assign multiple variables at once, or swap variables.
```ion
let a b = 1 2
let a b = [1 2]
let a b = [$b $a]
```
If the command is executed without any arguments, it will simply list all available variables. If the command is executed without any arguments, it will simply list all available variables.
### Using Variables ### Using Variables
......
...@@ -2,8 +2,7 @@ fn fib n ...@@ -2,8 +2,7 @@ fn fib n
if test $n -le 1 if test $n -le 1
echo $n echo $n
else else
let output = 1 let output previous = 1 1
let previous = 1
for _ in 2..$n for _ in 2..$n
let temp = $output let temp = $output
let output += $previous let output += $previous
......
let a = 5
echo $a
let a b = [10 $a]
echo $a
echo $b
let b a = [$a $b]
echo $a
echo $b
let a b c = 1 2 3
echo $a
echo $b
echo $c
5
10
5
5
10
1
2
3
...@@ -15,6 +15,7 @@ pub enum Binding { ...@@ -15,6 +15,7 @@ pub enum Binding {
KeyOnly(Identifier), KeyOnly(Identifier),
KeyValue(Identifier, VString), KeyValue(Identifier, VString),
Math(Identifier, Operator, VString), Math(Identifier, Operator, VString),
MultipleKeys(Vec<Identifier>, VString)
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
...@@ -39,6 +40,7 @@ pub fn parse_assignment(arguments: &str) -> Binding { ...@@ -39,6 +40,7 @@ pub fn parse_assignment(arguments: &str) -> Binding {
// Find the key and advance the iterator until the equals operator is found. // Find the key and advance the iterator until the equals operator is found.
let mut key = "".to_owned(); let mut key = "".to_owned();
let mut keys: Vec<Identifier> = Vec::new();
let mut found_key = false; let mut found_key = false;
let mut operator = None; let mut operator = None;
...@@ -56,7 +58,10 @@ pub fn parse_assignment(arguments: &str) -> Binding { ...@@ -56,7 +58,10 @@ pub fn parse_assignment(arguments: &str) -> Binding {
while let Some(character) = char_iter.next() { while let Some(character) = char_iter.next() {
match character { match character {
' ' if key.is_empty() => (), ' ' if key.is_empty() => (),
' ' => found_key = true, ' ' => {
keys.push(key.clone().into());
key.clear();
},
'+' => { '+' => {
match_operator!(Operator::Add); match_operator!(Operator::Add);
break break
...@@ -78,6 +83,7 @@ pub fn parse_assignment(arguments: &str) -> Binding { ...@@ -78,6 +83,7 @@ pub fn parse_assignment(arguments: &str) -> Binding {
break break
}, },
'=' => { '=' => {
if !key.is_empty() { keys.push(key.into()); }
found_key = true; found_key = true;
break break
}, },
...@@ -86,9 +92,19 @@ pub fn parse_assignment(arguments: &str) -> Binding { ...@@ -86,9 +92,19 @@ pub fn parse_assignment(arguments: &str) -> Binding {
} }
} }
if !found_key && key.is_empty() { if !found_key {
Binding::ListEntries
} else if keys.len() > 1 {
for key in &keys {
if !Variables::is_valid_variable_name(&key) {
return Binding::InvalidKey(key.clone());
}
}
Binding::MultipleKeys(keys, char_iter.skip_while(|&x| x == ' ').collect::<VString>())
} else if keys.is_empty() {
Binding::ListEntries Binding::ListEntries
} else { } else {
let key = keys.drain(..).next().unwrap();
let value = char_iter.skip_while(|&x| x == ' ').collect::<VString>(); let value = char_iter.skip_while(|&x| x == ' ').collect::<VString>();
if value.is_empty() { if value.is_empty() {
Binding::KeyOnly(key.into()) Binding::KeyOnly(key.into())
......
...@@ -23,6 +23,7 @@ use super::status::*; ...@@ -23,6 +23,7 @@ use super::status::*;
enum Action { enum Action {
UpdateString(Identifier, VString), UpdateString(Identifier, VString),
UpdateStrings(Vec<Identifier>, VArray),
UpdateArray(Identifier, VArray), UpdateArray(Identifier, VArray),
List List
} }
...@@ -77,6 +78,14 @@ fn parse_assignment(binding: Binding, ...@@ -77,6 +78,14 @@ fn parse_assignment(binding: Binding,
Value::String(value) => Ok(Action::UpdateString(key, value)), Value::String(value) => Ok(Action::UpdateString(key, value)),
Value::Array(array) => Ok(Action::UpdateArray(key, array)) Value::Array(array) => Ok(Action::UpdateArray(key, array))
}, },
Binding::MultipleKeys(keys, value) => match parse_expression(&value, &expanders) {
Value::String(value) => {
let array = value.split_whitespace().map(String::from)
.collect::<VArray>();
Ok(Action::UpdateStrings(keys, array))
},
Value::Array(array) => Ok(Action::UpdateStrings(keys, array))
},
Binding::KeyOnly(key) => { Binding::KeyOnly(key) => {
let stderr = io::stderr(); let stderr = io::stderr();
let _ = writeln!(&mut stderr.lock(), "ion: please provide value for variable '{}'", key); let _ = writeln!(&mut stderr.lock(), "ion: please provide value for variable '{}'", key);
...@@ -120,6 +129,11 @@ pub fn let_assignment(binding: Binding, vars: &mut Variables, dir_stack: &Direct ...@@ -120,6 +129,11 @@ pub fn let_assignment(binding: Binding, vars: &mut Variables, dir_stack: &Direct
match parse_assignment(binding, vars, dir_stack) { match parse_assignment(binding, vars, dir_stack) {
Ok(Action::UpdateArray(key, array)) => vars.set_array(&key, array), Ok(Action::UpdateArray(key, array)) => vars.set_array(&key, array),
Ok(Action::UpdateString(key, string)) => vars.set_var(&key, &string), Ok(Action::UpdateString(key, string)) => vars.set_var(&key, &string),
Ok(Action::UpdateStrings(keys, array)) => {
for (key, value) in keys.iter().zip(array.iter()) {
vars.set_var(key, value);
}
},
Ok(Action::List) => { Ok(Action::List) => {
print_vars(&vars.variables); print_vars(&vars.variables);
print_arrays(&vars.arrays); print_arrays(&vars.arrays);
...@@ -136,6 +150,11 @@ pub fn export_variable(binding : Binding, vars: &mut Variables, dir_stack : &Dir ...@@ -136,6 +150,11 @@ pub fn export_variable(binding : Binding, vars: &mut Variables, dir_stack : &Dir
match parse_assignment(binding, vars, dir_stack) { match parse_assignment(binding, vars, dir_stack) {
Ok(Action::UpdateArray(key, array)) => env::set_var(&key, array.join(" ")), Ok(Action::UpdateArray(key, array)) => env::set_var(&key, array.join(" ")),
Ok(Action::UpdateString(key, string)) => env::set_var(&key, string), Ok(Action::UpdateString(key, string)) => env::set_var(&key, string),
Ok(Action::UpdateStrings(keys, array)) => {
for (key, value) in keys.iter().zip(array.iter()) {
env::set_var(key, value);
}
}
Ok(Action::List) => { Ok(Action::List) => {
let stdout = io::stdout(); let stdout = io::stdout();
let stdout = &mut stdout.lock(); let stdout = &mut stdout.lock();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment