Conversation
| Var { name: String }, | ||
|
|
||
| /// Helper like random_path | ||
| Dynamic { name: String, args: Vec<Arg> }, |
There was a problem hiding this comment.
Oh lord, self referential structs/enums, this is going to be fun.
Mandatory "if you get into trouble you should read https://rust-unofficial.github.io/too-many-lists/" PSA.
There was a problem hiding this comment.
Hm? The page you've posted doesn't mention self referential structures at all, am I missing something?
And even if it's somehow bad in Rust, what is your suggestion? Parsing AST without self references is like trying to hammer a nail without an actual hammer -- you probably can do this, but it will likely be very awkward.
Molter73
left a comment
There was a problem hiding this comment.
The new script module is not actually included in the repo, so CI is not attempting to build or lint it. We should probably add mod script; somewhere in lib.rs
src/script/parser.rs
Outdated
| } | ||
|
|
||
| for i in pair.into_inner() { | ||
| if expr_rules.contains(&i.as_rule()) { |
There was a problem hiding this comment.
Have you considered using matches!() here? Think it would be a bit easier to read like this:
| if expr_rules.contains(&i.as_rule()) { | |
| if matches!(i.as_rule(), Rule::expr | Rule::machine) { |
src/script/parser.rs
Outdated
| ) -> Vec<MachineInstruction> { | ||
| let mut instr = vec![] as Vec<MachineInstruction>; | ||
|
|
||
| for i in pair { |
There was a problem hiding this comment.
[ultra-nit] Maybe we change pair to pairs and i to pair? That might help readability a bit
src/script/parser.rs
Outdated
| for i in pair { | ||
| let mut inner = i.into_inner(); | ||
| let name = inner.next().expect("No instruction name"); |
There was a problem hiding this comment.
[nit] Since you don't seem to use i beyond turning it into its inner representation:
| for i in pair { | |
| let mut inner = i.into_inner(); | |
| let name = inner.next().expect("No instruction name"); | |
| for mut inner in pair.into_inner() { | |
| let name = inner.next().expect("No instruction name"); |
src/script/parser.rs
Outdated
| pairs: pest::iterators::Pairs<Rule>, | ||
| ) -> (String, HashMap<String, String>) { | ||
| let mut work_parts = pairs.clone(); |
There was a problem hiding this comment.
Are we cloning here just to make the pairs mutable? If so, consider:
| pairs: pest::iterators::Pairs<Rule>, | |
| ) -> (String, HashMap<String, String>) { | |
| let mut work_parts = pairs.clone(); | |
| mut work_parts: pest::iterators::Pairs<Rule>, | |
| ) -> (String, HashMap<String, String>) { |
src/script/parser.rs
Outdated
| let mut params_map: HashMap<String, String> = HashMap::new(); | ||
|
|
||
| for param in params.into_inner() { | ||
| let mut kv = param.into_inner(); | ||
| let key = kv.next().expect("No parameter name"); | ||
| let value = kv.next().expect("No parameter value"); | ||
|
|
||
| assert_eq!(key.as_rule(), Rule::ident); | ||
| assert_eq!(value.as_rule(), Rule::value); | ||
|
|
||
| params_map.insert(pair_to_string(key), pair_to_string(value)); | ||
| } |
There was a problem hiding this comment.
Consider rewriting this part using iterators, this will save you the additional mutable map
| let mut params_map: HashMap<String, String> = HashMap::new(); | |
| for param in params.into_inner() { | |
| let mut kv = param.into_inner(); | |
| let key = kv.next().expect("No parameter name"); | |
| let value = kv.next().expect("No parameter value"); | |
| assert_eq!(key.as_rule(), Rule::ident); | |
| assert_eq!(value.as_rule(), Rule::value); | |
| params_map.insert(pair_to_string(key), pair_to_string(value)); | |
| } | |
| let params_map = params | |
| .into_inner() | |
| .map(|param| { | |
| let mut kv = param.into_inner(); | |
| let key = kv.next().expect("No parameter name"); | |
| let value = kv.next().expect("No parameter value"); | |
| assert_eq!(key.as_rule(), Rule::ident); | |
| assert_eq!(value.as_rule(), Rule::value); | |
| (pair_to_string(key), pair_to_string(value)) | |
| }) | |
| .collect::<HashMap<String, String>>(); |
src/script/parser.rs
Outdated
| fn build_ast_from_function(pairs: pest::iterators::Pairs<Rule>) -> Node { | ||
| let mut func_parts = pairs.clone(); |
There was a problem hiding this comment.
Similar to my previous comment on cloning for mutability:
| fn build_ast_from_function(pairs: pest::iterators::Pairs<Rule>) -> Node { | |
| let mut func_parts = pairs.clone(); | |
| fn build_ast_from_function(mut func_parts: pest::iterators::Pairs<Rule>) -> Node { |
src/script/parser.rs
Outdated
| let mut opts: HashMap<String, String> = HashMap::new(); | ||
|
|
||
| for p in pair.into_inner() { | ||
| if let Rule::opt = p.as_rule() { | ||
| let mut inner = p.into_inner(); | ||
| let key = inner.next().expect("No dist argument key"); | ||
| let value = inner.next().expect("No dist argument value"); | ||
|
|
||
| opts.insert(pair_to_string(key), pair_to_string(value)); | ||
| } | ||
| } |
There was a problem hiding this comment.
Consider the functional approach with filter_map:
| let mut opts: HashMap<String, String> = HashMap::new(); | |
| for p in pair.into_inner() { | |
| if let Rule::opt = p.as_rule() { | |
| let mut inner = p.into_inner(); | |
| let key = inner.next().expect("No dist argument key"); | |
| let value = inner.next().expect("No dist argument value"); | |
| opts.insert(pair_to_string(key), pair_to_string(value)); | |
| } | |
| } | |
| let opts = pair | |
| .into_inner() | |
| .filter_map(|p| { | |
| if let Rule::opt = p.as_rule() { | |
| let mut inner = p.into_inner(); | |
| let key = inner.next().expect("No dist argument key"); | |
| let value = | |
| inner.next().expect("No dist argument value"); | |
| Some((pair_to_string(key), pair_to_string(value))) | |
| } else { | |
| None | |
| } | |
| }) | |
| .collect::<HashMap<String, String>>(); |
src/script/parser.rs
Outdated
| let mut opts: HashMap<String, String> = HashMap::new(); | ||
|
|
||
| for p in pair.into_inner() { | ||
| if let Rule::opt = p.as_rule() { | ||
| let mut inner = p.into_inner(); | ||
| let key = inner.next().expect("No dist argument key"); | ||
| let value = inner.next().expect("No dist argument value"); | ||
|
|
||
| opts.insert(pair_to_string(key), pair_to_string(value)); | ||
| } | ||
| } | ||
|
|
||
| Dist::Exp { | ||
| rate: opts | ||
| .get("rate") | ||
| .cloned() | ||
| .unwrap_or(String::from("0")) | ||
| .parse() | ||
| .unwrap(), | ||
| } |
There was a problem hiding this comment.
You can probably take my previous comment one step further and not event build the full hashmap, since it looks like you only care about the rate option, something like this should work:
let rate = pair
.into_inner()
.filter_map(|p| {
if let Rule::opt = p.as_rule() {
let mut inner = p.into_inner();
let key = inner.next().expect("No dist argument key");
let key = pair_to_string(key);
if key == "rate" {
let value =
inner.next().expect("No dist argument value");
Some(pair_to_string(value).parse().unwrap())
} else {
None
}
} else {
None
}
})
.next()
.unwrap_or(0.0);
Dist::Exp { rate }There was a problem hiding this comment.
I would prefer to keep the map though, because there could be more distribution options than just rate in the future.
src/script/parser.rs
Outdated
| fn string_from_constant(pair: pest::iterators::Pair<Rule>) -> String { | ||
| assert_eq!(pair.as_rule(), Rule::constant); | ||
|
|
||
| // Extract "value" rule and convert it to String | ||
| pair_to_string(first_nested_pair(pair)) | ||
| } | ||
|
|
||
| fn string_from_ident(pair: pest::iterators::Pair<Rule>) -> String { | ||
| assert_eq!(pair.as_rule(), Rule::ident); | ||
|
|
||
| // Extract "name" rule and convert it to String | ||
| pair_to_string(first_nested_pair(pair)) | ||
| } |
There was a problem hiding this comment.
These two can probably be unified if you use the matches!() macro withing assert_eq!(), it'll look something like:
fn string_from_ident_or_const(pair: pest::iterators::Pair<Rule>) -> String {
assert!(matches!(pair.as_rule(), Rule::ident | Rule::constant));
pair_to_string(first_nested_pair(pair))
}Not really sure about the function name though.
Yep, it's actually coming in the subsequent PR, but I agree -- it belongs here. |
Introduce a new configurable workload parser. The workload definition
looks like this:
// Named work block
main (workers = 2, duration = 10) {
// Anon work block with only one unit.
// task(name) -- spawn a process with specified name
// debug(text) -- log with DEBUG level
// open(path) -- open file by path, create if needed and write something to it
debug("run task stub");
task(stub);
debug("open file /tmp/test");
open("/tmp/test");
} : exp {
// If no distribution provided, do the unit only once.
rate = 10.0;
}
Note that this commit only produces AST without JIT compiling it into anything
that looks like an actual code.
37739f9 to
5a01fb1
Compare
Otherwise improve the code readability.
5a01fb1 to
f0edb88
Compare
Introduce a new configurable workload parser. The workload definition looks like this:
Note that this commit only produces AST without JIT compiling it into anything that looks like an actual code.