Permalink
Browse files

Completely Revamp Function & Assignment Parsing

- Function assignments now work the same as assignments in general
- Assignments now instead take the expanded value into consideration when comparing types
- The pre-expanded value determines arrayness
  • Loading branch information...
mmstick committed Aug 27, 2017
1 parent 6594755 commit 6308880f6af776164e4e16daa5ffb00f555ad366
@@ -11,7 +11,7 @@ use std::os::unix::fs::PermissionsExt;
use builtins::Builtin;
use shell::Shell;
#[cfg(test)]
use shell::flow_control::{Function, FunctionArgument, Statement};
use shell::flow_control::{Function, Statement};
const MAN_PAGE: &'static str = r#"NAME
exists - check whether items exist
@@ -217,6 +217,7 @@ fn function_is_defined(function: &str, shell: &Shell) -> bool {
#[test]
fn test_evaluate_arguments() {
use parser::types::parse::{Primitive, TypeArgBuf};
let builtins = Builtin::map();
let mut shell = Shell::new(&builtins);
let mut sink = BufWriter::new(io::sink());
@@ -304,7 +305,10 @@ fn test_evaluate_arguments() {
let name_str = "test_function";
let name = SmallString::from_str(name_str);
let mut args = Vec::new();
args.push(FunctionArgument::Untyped("testy".to_owned()));
args.push(TypeArgBuf {
name: "testy".into(),
kind: Primitive::Any,
});
let mut statements = Vec::new();
statements.push(Statement::End);
let description = "description".to_owned();
@@ -315,7 +319,7 @@ fn test_evaluate_arguments() {
name: name,
args: args,
statements: statements,
description: description,
description: Some(description),
},
);
@@ -461,14 +465,18 @@ fn test_string_var_is_not_empty() {
#[test]
fn test_function_is_defined() {
use parser::types::parse::{Primitive, TypeArgBuf};
let builtins = Builtin::map();
let mut shell = Shell::new(&builtins);
// create a simple dummy function
let name_str = "test_function";
let name = SmallString::from_str(name_str);
let mut args = Vec::new();
args.push(FunctionArgument::Untyped("testy".to_owned()));
args.push(TypeArgBuf {
name: "testy".into(),
kind: Primitive::Any,
});
let mut statements = Vec::new();
statements.push(Statement::End);
let description = "description".to_owned();
@@ -479,7 +487,7 @@ fn test_function_is_defined() {
name: name,
args: args,
statements: statements,
description: description,
description: Some(description),
},
);
@@ -10,7 +10,7 @@ fn print_functions(functions: &FnvHashMap<Identifier, Function>) {
let _ = writeln!(stdout, "# Functions");
for fn_name in functions.keys() {
let description = &functions.get(fn_name).unwrap().description;
if description.len() >= 1 {
if let Some(ref description) = *description {
let _ = writeln!(stdout, " {} -- {}", fn_name, description);
} else {
let _ = writeln!(stdout, " {}", fn_name);
@@ -0,0 +1,38 @@
use super::super::types::parse::{TypeArgBuf, TypeError, TypeParser};
fn split_comments<'a>(arg: &'a str) -> (&'a str, Option<&'a str>) {
match arg.find("--") {
Some(pos) => {
let args = &arg[..pos].trim();
let comment = &arg[pos + 2..].trim();
if comment.is_empty() { (args, None) } else { (args, Some(comment)) }
}
None => (arg, None),
}
}
pub fn parse_function<'a>(arg: &'a str) -> (TypeParser<'a>, Option<&'a str>) {
let (args, description) = split_comments(arg);
(TypeParser::new(args), description)
}
pub fn collect_arguments<'a>(args: TypeParser<'a>) -> Result<Vec<TypeArgBuf>, TypeError<'a>> {
let mut output: Vec<TypeArgBuf> = Vec::new();
for arg in args {
output.push(arg?.into());
}
Ok(output)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn function_parsing() {
let (args, description) = split_comments("a:int b:bool -- a comment");
assert_eq!(args, "a:int b:bool");
assert_eq!(description, Some("a comment"));
}
}
@@ -1,7 +1,8 @@
mod functions;
mod parse;
mod splitter;
pub use self::parse::{get_function_args, parse};
pub use self::parse::parse;
pub use self::splitter::{StatementError, StatementSplitter};
use shell::flow_control::Statement;
@@ -1,8 +1,8 @@
use std::char;
use super::functions::{collect_arguments, parse_function};
use super::super::{ArgumentSplitter, pipelines};
use super::super::pipelines::Pipeline;
use shell::flow_control::{Case, ElseIf, FunctionArgument, Statement, Type};
use shell::flow_control::{Case, ElseIf, Statement};
use std::char;
fn collect<F>(arguments: &str, statement: F) -> Statement
where F: Fn(Pipeline) -> Statement
@@ -110,65 +110,25 @@ pub fn parse(code: &str) -> Statement {
let name = &cmd[..pos];
if !is_valid_name(name) {
eprintln!(
"ion: syntax error: {} is not a valid function name\n \
"ion: syntax error: '{}' is not a valid function name\n \
Function names may only contain alphanumeric characters",
name
);
return Statement::Default;
}
let mut args_iter = cmd[pos..].split_whitespace();
let mut args = Vec::new();
let mut description = String::new();
let mut description_flag = 0u8;
while let Some(arg) = args_iter.next() {
if arg.starts_with("--") {
if arg.len() > 2 {
description.push_str(&arg[2..]);
description_flag |= 1;
}
description_flag |= 2;
break;
} else {
args.push(arg.to_owned());
}
}
if description_flag & 2 != 0 {
if description_flag & 1 != 0 {
if let Some(arg) = args_iter.next() {
description.push(' ');
description.push_str(&arg);
}
for argument in args_iter {
description.push(' ');
description.push_str(&argument);
}
} else {
if let Some(arg) = args_iter.next() {
description.push_str(&arg);
}
for argument in args_iter {
description.push(' ');
description.push_str(&argument);
}
}
}
match get_function_args(args) {
Some(args) => {
let (args, description) = parse_function(&cmd[pos..]);
match collect_arguments(args) {
Ok(args) => {
return Statement::Function {
description: description,
description: description.map(String::from),
name: name.into(),
args: args,
args,
statements: Vec::new(),
};
}
}
None => {
eprintln!("ion: syntax error: invalid arguments");
Err(why) => {
eprintln!("ion: function argument error: {}", why);
return Statement::Default;
}
}
@@ -185,49 +145,10 @@ pub fn parse(code: &str) -> Statement {
}
pub fn get_function_args(args: Vec<String>) -> Option<Vec<FunctionArgument>> {
let mut fn_args = Vec::with_capacity(args.len());
for argument in args.into_iter() {
let length = argument.len();
let argument = if argument.ends_with(":int") {
if length <= 4 {
return None;
}
let arg = &argument[..length - 4];
if arg.contains(':') {
return None;
}
FunctionArgument::Typed(arg.to_owned(), Type::Int)
} else if argument.ends_with(":float") {
if length <= 6 {
return None;
}
let arg = &argument[..length - 6];
if arg.contains(':') {
return None;
}
FunctionArgument::Typed(arg.to_owned(), Type::Float)
} else if argument.ends_with(":bool") {
if length <= 5 {
return None;
}
let arg = &argument[..length - 5];
if arg.contains(':') {
return None;
}
FunctionArgument::Typed(arg.to_owned(), Type::Bool)
} else {
FunctionArgument::Untyped(argument)
};
fn_args.push(argument);
}
Some(fn_args)
}
#[cfg(test)]
mod tests {
use super::*;
use parser::types::parse::{Primitive, TypeArgBuf};
use shell::{Job, JobKind};
use shell::flow_control::Statement;
@@ -302,7 +223,7 @@ mod tests {
// Default case where spaced normally
let parsed_if = parse("fn bob");
let correct_parse = Statement::Function {
description: "".into(),
description: None,
name: "bob".into(),
args: Default::default(),
statements: Default::default(),
@@ -319,11 +240,17 @@ mod tests {
// Default case where spaced normally
let parsed_if = parse("fn bob a b");
let correct_parse = Statement::Function {
description: "".into(),
description: None,
name: "bob".into(),
args: vec![
FunctionArgument::Untyped("a".to_owned()),
FunctionArgument::Untyped("b".to_owned()),
TypeArgBuf {
name: "a".into(),
kind: Primitive::Any,
},
TypeArgBuf {
name: "b".into(),
kind: Primitive::Any,
},
],
statements: Default::default(),
};
@@ -335,11 +262,17 @@ mod tests {
let parsed_if = parse("fn bob a b --bob is a nice function");
let correct_parse = Statement::Function {
description: "bob is a nice function".to_string(),
description: Some("bob is a nice function".to_string()),
name: "bob".into(),
args: vec![
FunctionArgument::Untyped("a".to_owned()),
FunctionArgument::Untyped("b".to_owned()),
TypeArgBuf {
name: "a".into(),
kind: Primitive::Any,
},
TypeArgBuf {
name: "b".into(),
kind: Primitive::Any,
},
],
statements: vec![],
};
Oops, something went wrong.

0 comments on commit 6308880

Please sign in to comment.