Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
jvanstraten committed Oct 5, 2022
1 parent 7e80632 commit 542bfc2
Show file tree
Hide file tree
Showing 26 changed files with 814 additions and 324 deletions.
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.

38 changes: 34 additions & 4 deletions proto/substrait/validator/simple_extensions.proto
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,25 @@ message ExtensionDefinition {
WindowProperties window_function = 9;
}

// For table functions, when defined; to be added to above oneof.
reserved 10;

// Nullability behavior that the function was declared with. Note that the
// patterns have already been desugared to represent this, so this can be
// ignored; it exists only for completeness.
oneof consistency {
// Nullability of toplevel binding and data type patterns of all argument
// and return types was overridden to `??nullable`.
google.protobuf.Empty mirror = 11;

// Nullability of toplevel binding and data type patterns of all argument
// types was overridden to `??nullable`.
google.protobuf.Empty declared_output = 12;

// No desugaring overrides were applied.
google.protobuf.Empty discrete = 13;
}

// Properties common to aggregate and window functions.
message AggregateProperties {
// When specified, the function is decomposable.
Expand Down Expand Up @@ -250,9 +269,8 @@ message ExtensionDefinition {
}
}

// Represents a parameter pack for a user-defined compound type class or a
// function argument slot list. In the latter case, the patterns will only
// ever be passed typenames.
// Represents a positional parameter pack for a user-defined compound type
// class or a function argument slot list.
//
// The order of operations for the various patterns is:
//
Expand Down Expand Up @@ -303,7 +321,7 @@ message ExtensionDefinition {
// for aggregate and window functions.
google.protobuf.Empty literal = 6;

// An data value must be bound to the slot. This is done by means of
// A data value must be bound to the slot. This is done by means of
// binding an expression, but the expression can always be evaluated or
// reduced before the function is invoked. This is used for value
// function arguments that are not marked as constant. The data type of
Expand Down Expand Up @@ -350,6 +368,18 @@ message ExtensionDefinition {
// The maximum number of arguments that can be bound to the slot. Zero
// is treated as unspecified/no upper limit.
uint64 maximum = 2;

// Consistency that the variadic slot was declared with. Note that the
// patterns have already been desugared to represent this, so this can be
// ignored; it exists only for completeness.
oneof consistency {
// No desugaring overrides were applied.
google.protobuf.Empty consistent = 3;

// All consistent bindings in the last argument slot were overridden to
// inconsistent bindings.
google.protobuf.Empty inconsistent = 4;
}
}

// Optional additional constraints to apply when determining whether a
Expand Down
2 changes: 1 addition & 1 deletion rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ serde_yaml = "0.9"
# both the schema and the input, so we need to depend on that as well, even
# though we don't actually do any JSON serialization and deserialization.
jsonschema = { version = "=0.15.0", default-features = false }
serde_json = "1"
serde_json = { version = "1", features = ["preserve_order"] }

# Used for checking identifier syntax (could be removed if regexes don't end up
# being useful elsewhere too).
Expand Down
19 changes: 0 additions & 19 deletions rs/src/export/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,25 +353,6 @@ impl From<&extension::simple::type_class::Reference> for validator::data_type::U
}
}

impl From<&extension::simple::type_class::Definition>
for validator::data_type::user_defined_type::Definition
{
fn from(node: &extension::simple::type_class::Definition) -> Self {
Self {
structure: node
.structure
.iter()
.map(
|(name, simple)| validator::data_type::user_defined_type::Element {
name: name.to_string(),
kind: simple.into(),
},
)
.collect(),
}
}
}

impl From<&data::Variation> for validator::data_type::Variation {
fn from(node: &data::Variation) -> Self {
match node {
Expand Down
3 changes: 3 additions & 0 deletions rs/src/output/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ pub enum Classification {
#[strum(props(HiddenDescription = "invalid compound vs. simple function name usage"))]
LinkCompoundVsSimpleFunctionName = 3010,

#[strum(props(Description = "discouraged name"))]
LinkDiscouragedName = 3011,

// Type-related diagnostics (group 4).
#[strum(props(HiddenDescription = "type-related diagnostics"))]
Type = 4000,
Expand Down
30 changes: 16 additions & 14 deletions rs/src/output/extension/namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,22 @@ impl<T> ResolutionResult<T> {
self.expect(parse_context, if_not_applicable, |_, _| true, true, false)
}

/// Emits an error if one or more definitions were found for this name
/// resolution, to be used just before defining a new item.
pub fn expect_not_yet_defined(&self, parse_context: &mut context::Context) {
if !self.visible.is_empty() {
traversal::push_diagnostic(
parse_context,
diagnostic::Level::Error,
cause!(
LinkDuplicateDefinition,
"{} is already defined",
self.unresolved_reference
),
);
}
}

/// Silently returns the first matching item, if any. If there are none,
/// this just returns an unresolved reference. Use
/// filter_items().expect_one() to formulate error messages if there are
Expand Down Expand Up @@ -567,18 +583,4 @@ impl<T> ResolutionResult<T> {
.next()
.flatten()
}

/// Return an error if one or more definitions were found for this name
/// resolution, to be used just before defining a new item.
pub fn expect_not_yet_defined(&self) -> diagnostic::Result<()> {
if self.visible.is_empty() {
Ok(())
} else {
Err(cause!(
LinkDuplicateDefinition,
"{} is already defined",
self.unresolved_reference
))
}
}
}
9 changes: 5 additions & 4 deletions rs/src/output/extension/reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ use crate::output::path;
use crate::util;
use std::sync::Arc;

/// Represents an identifier that was used to reference something. It is
/// stored along with a resolution result to retain information about the
/// reference even if the resolution failed, and is generally only used for
/// identity/equality checks and diagnostic information.
/// Represents an identifier that was used to reference an extension at the
/// protobuf level. It is stored along with a resolution result to retain
/// information about the reference even if the resolution failed, and is
/// generally only used for identity/equality checks and diagnostic
/// information.
#[derive(Clone, Debug, Default)]
pub struct Identifier {
/// The name of the object being referred to, if known. Always stored using
Expand Down
28 changes: 28 additions & 0 deletions rs/src/output/extension/simple/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: Apache-2.0

//! Module for the common types involved with representing extension
//! definitions.

/// Identifying information associated with an extension, that can be used to
/// refer to the extension from elsewhere.
#[derive(Clone, Debug)]
pub struct Identifier {
/// The URI that the extension was declared with. Matched case-sensitively.
pub uri: String,

/// One or more aliases for this extension within the scope of the URI.
/// Matched case-insensitively.
pub names: Vec<String>,

/// Unique number for the extension, generated during traversal. The
/// number is only unique within the scope of a single run of the
/// validator, and may change between runs.
pub extension_id: u64,
}

/// Non-functional metadata common to all extension types.
#[derive(Clone, Debug, Default)]
pub struct Metadata {
// Optional description of the extension. Only serves as documentation.
pub description: String,
}
1 change: 1 addition & 0 deletions rs/src/output/extension/simple/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

//! Module for representing simple extensions.

pub mod common;
pub mod function;
pub mod module;
pub mod type_class;
Expand Down
11 changes: 5 additions & 6 deletions rs/src/output/extension/simple/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,13 @@ impl<T: Scope> DynScope for T {
}

/// A parsed simple extension module/file.
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug)]
pub struct Definition {
/// Unique number within the tree that can be used to refer to this
/// extension when exporting in protobuf form.
pub extension_id: u64,
/// Identifier for the extension.
pub identifier: extension::simple::common::Identifier,

/// Description of the module.
pub description: String,
/// Common metadata for the extension.
pub metadata: extension::simple::common::Metadata,

/// The URI that was actually used to resolve the module.
pub actual_uri: String,
Expand Down
30 changes: 24 additions & 6 deletions rs/src/output/extension/simple/type_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,26 @@ pub struct Definition {
/// Description of the type class.
pub description: String,

/// The underlying structure of the type.
pub structure: Vec<(String, data::class::Simple)>,

/// The parameters expected by the data type.
pub parameter_slots: Vec<ParameterSlot>,

/// Whether or not the last parameter slot is variadic.
pub parameters_variadic: bool,

/// Constraint program for checking the parameters.
pub contraints: Vec<meta::Statement>,

/// The underlying structure of the type. Empty for opaque types.
pub structure: Option<meta::pattern::Value>,
}

/// A parameter slot for a user-defined data type.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParameterSlot {
/// YAML-provided name of the parameter.
/// Name of the parameter.
pub name: String,

/// YAML-provided human-readable description of the parameter.
/// Human-readable description of the parameter.
pub description: String,

/// Pattern for type- and bounds-checking parameters bound to this slot.
Expand Down Expand Up @@ -89,6 +92,7 @@ impl ParameterInfo for Definition {
}

// Match parameters to slots positionally.
let mut context = meta::Context::default();
for (index, param) in params.iter().enumerate() {
// Determine the slot that corresponds to this parameter.
let slot = self
Expand Down Expand Up @@ -119,7 +123,10 @@ impl ParameterInfo for Definition {
));
}
if let Some(value) = &param.value {
if !slot.pattern.match_pattern(value)? {
if !slot
.pattern
.match_pattern_with_context(&mut context, value)?
{
return Err(cause!(
TypeMismatchedParameters,
"parameter {} does not match pattern {}",
Expand All @@ -135,6 +142,17 @@ impl ParameterInfo for Definition {
));
}
}

// Check constraints.
for constraint in self.contraints.iter() {
constraint.execute(&mut context)?;
}

// If there is a structure pattern, check that it can be evaluated.
if let Some(structure) = &self.structure {
structure.evaluate_with_context(&mut context)?;
}

Ok(())
}

Expand Down
Loading

0 comments on commit 542bfc2

Please sign in to comment.