Skip to content

Commit

Permalink
feat: implement expression evaluation in wdl-engine. (#249)
Browse files Browse the repository at this point in the history
  • Loading branch information
peterhuene authored Nov 12, 2024
1 parent 1897ba3 commit e57e3ae
Show file tree
Hide file tree
Showing 26 changed files with 7,014 additions and 3,618 deletions.
1,185 changes: 595 additions & 590 deletions Arena.toml

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ rowan = "0.15.15"
serde = { version = "1", features = ["derive"] }
serde_json = "1.0.120"
serde_with = "3.8.1"
string-interner = "0.17.0"
tempfile = "3.10.1"
tokio = { version = "1.38.0", features = ["full"] }
toml = "0.8.14"
Expand Down
2,481 changes: 1,238 additions & 1,243 deletions Gauntlet.toml

Large diffs are not rendered by default.

20 changes: 11 additions & 9 deletions gauntlet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,15 +249,17 @@ pub async fn gauntlet(args: Args) -> Result<()> {
.unwrap_or_default();
// The `+1` here is because line_index() is 0-based.
let line_no = file.line_index((), byte_start).unwrap_or_default() + 1;
assert!(
actual.insert((
std::str::from_utf8(buffer.as_slice())
.context("diagnostic should be UTF-8")?
.trim()
.to_string(),
line_no,
))
);
let message = std::str::from_utf8(buffer.as_slice())
.context("diagnostic should be UTF-8")?
.trim()
.to_string();

if !actual.insert((message.clone(), line_no)) {
panic!(
"duplicate diagnostic: `{message}` at {path}:{line_no}",
path = document_identifier.path()
);
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions wdl-analysis/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Exposed information about workflow calls from an analyzed document ([#239](https://github.com/stjude-rust-labs/wdl/pull/239)).
* Added formatting to the analyzer ([#247](https://github.com/stjude-rust-labs/wdl/pull/247)).

### Changed

* Made diagnostic creation functions public ([#249](https://github.com/stjude-rust-labs/wdl/pull/249)).
* Refactored expression type evaluator to provide context via a trait ([#249](https://github.com/stjude-rust-labs/wdl/pull/249)).
* Removed `PartialEq`, `Eq`, and `Hash` from WDL-type-related types ([#249](https://github.com/stjude-rust-labs/wdl/pull/249)).

## 0.5.0 - 10-22-2024

### Changed
Expand Down
15 changes: 6 additions & 9 deletions wdl-analysis/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use crate::types::CallType;
use crate::types::Type;
use crate::types::Types;
use crate::types::display_types;
use crate::types::v1::ComparisonOperator;
use crate::types::v1::NumericOperator;

/// Utility type to represent an input or an output.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -506,17 +508,12 @@ pub fn missing_struct_members(name: &Ident, count: usize, members: &str) -> Diag
}

/// Creates a "map key not primitive" diagnostic.
pub fn map_key_not_primitive(
types: &Types,
span: Span,
actual: Type,
actual_span: Span,
) -> Diagnostic {
pub fn map_key_not_primitive(types: &Types, span: Span, actual: Type) -> Diagnostic {
Diagnostic::error("expected map literal to use primitive type keys")
.with_highlight(span)
.with_label(
format!("this is type `{actual}`", actual = actual.display(types)),
actual_span,
span,
)
}

Expand Down Expand Up @@ -588,7 +585,7 @@ pub fn logical_and_mismatch(types: &Types, actual: Type, actual_span: Span) -> D
/// Creates a "comparison mismatch" diagnostic.
pub fn comparison_mismatch(
types: &Types,
op: &impl fmt::Display,
op: ComparisonOperator,
span: Span,
lhs: Type,
lhs_span: Span,
Expand All @@ -614,7 +611,7 @@ pub fn comparison_mismatch(
/// Creates a "numeric mismatch" diagnostic.
pub fn numeric_mismatch(
types: &Types,
op: &impl fmt::Display,
op: NumericOperator,
span: Span,
lhs: Type,
lhs_span: Span,
Expand Down
104 changes: 25 additions & 79 deletions wdl-analysis/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::sync::Arc;

use indexmap::IndexMap;
use petgraph::graph::NodeIndex;
use rowan::GreenNode;
use url::Url;
use wdl_ast::Ast;
use wdl_ast::AstNode;
Expand All @@ -14,6 +15,7 @@ use wdl_ast::Diagnostic;
use wdl_ast::Span;
use wdl_ast::SupportedVersion;
use wdl_ast::SyntaxKind;
use wdl_ast::SyntaxNode;
use wdl_ast::ToSpan;
use wdl_ast::WorkflowDescriptionLanguage;
use wdl_ast::support::token;
Expand Down Expand Up @@ -209,30 +211,12 @@ pub struct ScopeRef<'a> {
scopes: &'a [Scope],
/// The index of the scope in the collection.
index: ScopeIndex,
/// The name of the task associated with the scope.
///
/// This is `Some` only when evaluating a task `hints` section.
task_name: Option<&'a str>,
/// The input type map.
///
/// This is `Some` only when evaluating a task `hints` section.
inputs: Option<&'a HashMap<String, Input>>,
/// The output type map.
///
/// This is `Some` only when evaluating a task `hints` section.
outputs: Option<&'a HashMap<String, Output>>,
}

impl<'a> ScopeRef<'a> {
/// Creates a new scope reference given the scope index.
fn new(scopes: &'a [Scope], index: ScopeIndex) -> Self {
Self {
scopes,
index,
task_name: None,
inputs: None,
outputs: None,
}
Self { scopes, index }
}

/// Gets the span of the scope.
Expand All @@ -247,9 +231,6 @@ impl<'a> ScopeRef<'a> {
self.scopes[self.index.0].parent.map(|p| Self {
scopes: self.scopes,
index: p,
task_name: self.task_name,
inputs: self.inputs,
outputs: self.outputs,
})
}

Expand Down Expand Up @@ -284,59 +265,6 @@ impl<'a> ScopeRef<'a> {

None
}

/// Gets an input for the given name.
///
/// Returns `Err(())` if input hidden types are not supported by this scope.
///
/// Returns `Ok(None)` if input hidden types are supported, but the
/// specified name is not a known input.
///
/// Returns `Ok(Some)` if input hidden types are supported and the specified
/// name is a known input.
pub(crate) fn input(&self, name: &str) -> Result<Option<Input>, ()> {
match self.inputs {
Some(map) => Ok(map.get(name).copied()),
None => Err(()),
}
}

/// Gets an output for the given name.
///
/// Returns `Err(())` if output hidden types are not supported by this
/// scope.
///
/// Returns `Ok(None)` if input hidden types are supported, but the
/// specified name is not a known output.
///
/// Returns `Ok(Some)` if input hidden types are supported and the specified
/// name is a known output.
pub(crate) fn output(&self, name: &str) -> Result<Option<Output>, ()> {
match self.outputs {
Some(map) => Ok(map.get(name).copied()),
None => Err(()),
}
}

/// The task name associated with the scope.
pub(crate) fn task_name(&self) -> Option<&str> {
self.task_name
}

/// Whether or not `hints` hidden types are supported by this scope.
pub(crate) fn supports_hints(&self) -> bool {
self.task_name.is_some()
}

/// Whether or not `input` hidden types are supported by this scope.
pub(crate) fn supports_inputs(&self) -> bool {
self.inputs.is_some()
}

/// Whether or not `output` hidden types are supported by this scope.
pub(crate) fn supports_outputs(&self) -> bool {
self.outputs.is_some()
}
}

/// Represents a mutable reference to a scope.
Expand Down Expand Up @@ -383,9 +311,6 @@ impl<'a> ScopeRefMut<'a> {
ScopeRef {
scopes: self.scopes,
index: self.index,
task_name: None,
inputs: None,
outputs: None,
}
}
}
Expand Down Expand Up @@ -529,6 +454,10 @@ impl Workflow {
/// Represents an analyzed WDL document.
#[derive(Debug, Default)]
pub struct Document {
/// The root CST node of the document.
///
/// This is `None` when the document could not be parsed.
root: Option<GreenNode>,
/// The version of the document.
version: Option<SupportedVersion>,
/// The namespaces in the document.
Expand Down Expand Up @@ -601,9 +530,26 @@ impl Document {
(document, diagnostics)
}

/// Gets the AST of the document.
///
/// Returns [`Ast::Unsupported`] when the document could not be parsed or
/// has an unsupported version.
pub fn ast(&self) -> Ast {
match &self.version {
Some(SupportedVersion::V1(_)) => Ast::V1(
wdl_ast::v1::Ast::cast(SyntaxNode::new_root(
self.root.clone().expect("should have a root"),
))
.expect("should cast"),
),
_ => Ast::Unsupported,
}
}

/// Gets the supported version of the document.
///
/// Returns `None` if the document version is not supported.
/// Returns `None` if the document could not be parsed or contains an
/// unsupported version.
pub fn version(&self) -> Option<SupportedVersion> {
self.version
}
Expand Down
Loading

0 comments on commit e57e3ae

Please sign in to comment.