Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fud2] Additional Syntax to Rhai DSL #2203

Merged
merged 33 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9f7782c
create function to begin listening for op body
jku20 Jul 9, 2024
1c9afbd
implement adding shells to builds
jku20 Jul 10, 2024
e9fe9e9
add function to emit built op
jku20 Jul 10, 2024
11d7efe
add custom syntax for defining op using shell
jku20 Jul 11, 2024
e0844a1
implement config and config_or
jku20 Jul 11, 2024
155412e
read configs from cli
jku20 Jul 11, 2024
b35bb30
change syntax for shell to #ident
jku20 Jul 11, 2024
4e791c6
Merge branch 'main' into fud2-rhai-rework
jku20 Jul 11, 2024
ed1e7e3
tiny bug fixes
jku20 Jul 12, 2024
71c122b
remove config_data field from driver
jku20 Jul 16, 2024
5ce36a3
use ninja varaibles for input/output files
jku20 Jul 16, 2024
ad8f279
rewrite axi and calyx scripts
jku20 Jul 16, 2024
58f0772
Merge branch 'fud2-rhai-rework' into rud2-rhai-scripts-rewrite
jku20 Jul 16, 2024
d155cd7
use variables instead of hardcoding names
jku20 Jul 18, 2024
34e38fc
factor out genation of ninja varaibles name
jku20 Jul 18, 2024
5611817
replace closure with struct
jku20 Jul 18, 2024
54ce0dc
name tuple fields
jku20 Jul 18, 2024
2e91948
rename OpSig
jku20 Jul 18, 2024
41c98af
improve docs
jku20 Jul 18, 2024
0475ce8
use Ninja variables for configs
jku20 Jul 19, 2024
18f2bba
revert rhai scripts
jku20 Jul 19, 2024
9206e32
revert calyx.rhai
jku20 Jul 25, 2024
2fc8e22
add function for testing rhai scripts
jku20 Jul 26, 2024
890d918
add enumerate planner
jku20 Jul 29, 2024
346bc26
bug fix and tests
jku20 Jul 29, 2024
838bcb6
add basic tests for config and config_or
jku20 Jul 29, 2024
6b03030
improve name and doc of struct for emiting ops
jku20 Aug 2, 2024
2e4e92d
being wishy-washy on names
jku20 Aug 2, 2024
be95dcf
name clarification and improved docs
jku20 Aug 2, 2024
b59bc02
improve docs for build_cmd_with_vars
jku20 Aug 2, 2024
4a24316
more name bikesheadding
jku20 Aug 2, 2024
5111ad6
more improvements to build_cmd_with_args
jku20 Aug 2, 2024
2e4357b
Merge branch 'main' into fud2-rhai-rework
jku20 Aug 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions fud2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ path = "src/main.rs"
[dev-dependencies]
insta = "1.36.0"
itertools.workspace = true
figment = { version = "0.10.12", features = ["toml"] }
jku20 marked this conversation as resolved.
Show resolved Hide resolved
36 changes: 21 additions & 15 deletions fud2/fud-core/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,26 @@ fn get_resource(driver: &Driver, cmd: GetResource) -> anyhow::Result<()> {
bail!("unknown resource file {}", cmd.filename);
}

pub fn cli(driver: &Driver) -> anyhow::Result<()> {
/// Given the name of a Driver, returns a config based on that name and CLI arguments.
pub fn config_from_cli(name: &str) -> anyhow::Result<figment::Figment> {
let args: FakeArgs = argh::from_env();
let mut config = config::load_config(name);

// Use `--set` arguments to override configuration values.
for set in args.set {
let mut parts = set.splitn(2, '=');
let key = parts.next().unwrap();
let value = parts
.next()
.ok_or(anyhow!("--set arguments must be in key=value form"))?;
let dict = figment::util::nest(key, value.into());
config = config.merge(figment::providers::Serialized::defaults(dict));
}

Ok(config)
}

pub fn cli(driver: &Driver, config: &figment::Figment) -> anyhow::Result<()> {
let args: FakeArgs = argh::from_env();

// Configure logging.
Expand Down Expand Up @@ -345,7 +364,7 @@ pub fn cli(driver: &Driver) -> anyhow::Result<()> {
let plan = driver.plan(req).ok_or(anyhow!("could not find path"))?;

// Configure.
let mut run = Run::new(driver, plan);
let mut run = Run::new(driver, plan, config.clone());

// Override some global config options.
if let Some(keep) = args.keep {
Expand All @@ -355,19 +374,6 @@ pub fn cli(driver: &Driver) -> anyhow::Result<()> {
run.global_config.verbose = verbose;
}

// Use `--set` arguments to override configuration values.
for set in args.set {
let mut parts = set.splitn(2, '=');
let key = parts.next().unwrap();
let value = parts
.next()
.ok_or(anyhow!("--set arguments must be in key=value form"))?;
let dict = figment::util::nest(key, value.into());
run.config_data = run
.config_data
.merge(figment::providers::Serialized::defaults(dict));
}

// Execute.
match args.mode {
Mode::ShowPlan => run.show(),
Expand Down
10 changes: 3 additions & 7 deletions fud2/fud-core/src/exec/driver.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{OpRef, Operation, Request, Setup, SetupRef, State, StateRef};
use crate::{config, run, script, utils};
use crate::{run, script, utils};
use camino::{Utf8Path, Utf8PathBuf};
use cranelift_entity::PrimaryMap;
use rand::distributions::{Alphanumeric, DistString};
Expand Down Expand Up @@ -439,15 +439,11 @@ impl DriverBuilder {
}

/// Load any plugin scripts specified in the configuration file.
pub fn load_plugins(mut self) -> Self {
pub fn load_plugins(mut self, config_data: &figment::Figment) -> Self {
// pull out things from self that we need
let plugin_dir = self.scripts_dir.take();
let plugin_files = self.script_files.take();

// TODO: Let's try to avoid loading/parsing the configuration file here and
// somehow reusing it from wherever we do that elsewhere.
let config = config::load_config(&self.name);

let mut runner = script::ScriptRunner::new(self);

// add system plugins
Expand All @@ -469,7 +465,7 @@ impl DriverBuilder {

// add user plugins defined in config
if let Ok(plugins) =
config.extract_inner::<Vec<std::path::PathBuf>>("plugins")
config_data.extract_inner::<Vec<std::path::PathBuf>>("plugins")
{
runner.add_files(plugins.into_iter());
}
Expand Down
102 changes: 99 additions & 3 deletions fud2/fud-core/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,79 @@ impl EmitBuild for EmitBuildFn {
}
}

/// A config variable.
#[derive(Debug, Clone)]
pub enum ConfigVar {
/// The key for the config variable.
Required(String),
/// The key for the config variable followed by the value it should be if the key is not found.
Optional(String, String),
}

/// The data required to emit a single, simple op whose body is composed of an ordered set of
/// commands.
pub struct RulesOp {
/// The name of the rule generated.
pub rule_name: String,

/// The shell commands emitted by to the generated rule.
/// Each of these must be run in order in a context where the variables in each cmd are
/// supplied. In particular, this means that variables of the form "$[i|o]<digit>" are in
/// scope.
pub cmds: Vec<String>,
jku20 marked this conversation as resolved.
Show resolved Hide resolved

/// Variables to be emitted
pub config_vars: Vec<ConfigVar>,
}

/// Given the `index` of a file in the list of input/output files and if the file is an
/// `input`, returns a valid Ninja variable name.
pub fn io_file_var_name(index: usize, input: bool) -> String {
if input {
format!("i{}", index)
} else {
format!("o{}", index)
}
}

impl EmitBuild for RulesOp {
fn build(
&self,
emitter: &mut StreamEmitter,
inputs: &[&str],
outputs: &[&str],
) -> EmitResult {
// Write the Ninja file.
let cmd = self.cmds.join(" && ");
emitter.rule(&self.rule_name, &cmd)?;
let in_vars = inputs
.iter()
.enumerate()
.map(|(k, &v)| (io_file_var_name(k, true), v));
let out_vars = outputs
.iter()
.enumerate()
.map(|(k, &v)| (io_file_var_name(k, false), v));
let vars: Vec<_> = in_vars.chain(out_vars).collect();
jku20 marked this conversation as resolved.
Show resolved Hide resolved

for var in &self.config_vars {
match var {
ConfigVar::Required(k) => emitter.config_var(k, k)?,
ConfigVar::Optional(k, d) => emitter.config_var_or(k, k, d)?,
}
}

emitter.build_cmd_with_args(
outputs,
&self.rule_name,
inputs,
&[],
&vars,
)?;
Ok(())
}
jku20 marked this conversation as resolved.
Show resolved Hide resolved
}

// TODO make this unnecessary...
/// A simple `build` emitter that just runs a Ninja rule.
pub struct EmitRuleBuild {
Expand Down Expand Up @@ -126,9 +199,12 @@ pub struct Run<'a> {
}

impl<'a> Run<'a> {
pub fn new(driver: &'a Driver, plan: Plan) -> Self {
let config_data = config::load_config(&driver.name);
Self::with_config(driver, plan, config_data)
pub fn new(
driver: &'a Driver,
plan: Plan,
config: figment::Figment,
) -> Self {
Self::with_config(driver, plan, config)
}

pub fn with_config(
Expand Down Expand Up @@ -507,6 +583,26 @@ impl<W: Write> Emitter<W> {
Ok(())
}

/// Emit a Ninja build command with variable list.
jku20 marked this conversation as resolved.
Show resolved Hide resolved
///
/// Here `variables` is an association list, the first element of each tuple a key and the
/// second a value.
pub fn build_cmd_with_args(
&mut self,
targets: &[&str],
rule: &str,
deps: &[&str],
implicit_deps: &[&str],
variables: &[(String, &str)],
) -> std::io::Result<()> {
self.build_cmd(targets, rule, deps, implicit_deps)?;
for (key, value) in variables {
self.arg(key, value)?;
}
writeln!(self.out)?;
Ok(())
}

/// Emit a Ninja comment.
pub fn comment(&mut self, text: &str) -> std::io::Result<()> {
writeln!(self.out, "# {}", text)?;
Expand Down
42 changes: 39 additions & 3 deletions fud2/fud-core/src/script/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,40 @@ pub(super) struct RhaiSystemError {

#[derive(Debug)]
pub(super) enum RhaiSystemErrorKind {
ErrorSetupRef(String),
SetupRef(String),
StateRef(String),
BeganOp(String, String),
NoOp,
}

impl RhaiSystemError {
pub(super) fn setup_ref(v: rhai::Dynamic) -> Self {
Self {
kind: RhaiSystemErrorKind::ErrorSetupRef(v.to_string()),
kind: RhaiSystemErrorKind::SetupRef(v.to_string()),
position: rhai::Position::NONE,
}
}

pub(super) fn state_ref(v: rhai::Dynamic) -> Self {
Self {
kind: RhaiSystemErrorKind::StateRef(v.to_string()),
position: rhai::Position::NONE,
}
}

pub(super) fn began_op(old_name: &str, new_name: &str) -> Self {
Self {
kind: RhaiSystemErrorKind::BeganOp(
old_name.to_string(),
new_name.to_string(),
),
position: rhai::Position::NONE,
}
}

pub(super) fn no_op() -> Self {
Self {
kind: RhaiSystemErrorKind::NoOp,
position: rhai::Position::NONE,
}
}
Expand All @@ -30,9 +57,18 @@ impl RhaiSystemError {
impl Display for RhaiSystemError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.kind {
RhaiSystemErrorKind::ErrorSetupRef(v) => {
RhaiSystemErrorKind::SetupRef(v) => {
write!(f, "Unable to construct SetupRef: `{v:?}`")
}
RhaiSystemErrorKind::StateRef(v) => {
write!(f, "Unable to construct StateRef: `{v:?}`")
}
RhaiSystemErrorKind::BeganOp(old_name, new_name) => {
write!(f, "Unable to build two ops at once: trying to build `{new_name:?}` but already building `{old_name:?}`")
}
RhaiSystemErrorKind::NoOp => {
write!(f, "Unable to find current op being built. Consider calling start_op_stmts earlier in the program.")
}
}
}
}
Expand Down
Loading
Loading