Skip to content

Commit

Permalink
Move NodeId Generation to a separate crate (#484)
Browse files Browse the repository at this point in the history
Moves the `NodeId` and its Id generation to a new crate, `partiql-common` so that it can get consumed by multiple crates.

---------

Co-authored-by: Josh Pschorr <[email protected]>
  • Loading branch information
am357 and jpschorr authored Aug 9, 2024
1 parent 6dc088c commit e5b8ce7
Show file tree
Hide file tree
Showing 29 changed files with 164 additions and 151 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ members = [
"partiql-catalog",
"partiql-conformance-tests",
"partiql-conformance-test-generator",
"partiql-source-map",
"partiql-common",
"partiql-logical-planner",
"partiql-logical",
"partiql-eval",
Expand Down
1 change: 1 addition & 0 deletions partiql-ast-passes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ bench = false
[dependencies]
partiql-ast = { path = "../partiql-ast", version = "0.10.*" }
partiql-catalog = { path = "../partiql-catalog", version = "0.10.*" }
partiql-common = { path = "../partiql-common", version = "0.10.*" }
partiql-types = { path = "../partiql-types", version = "0.10.*" }

assert_matches = "1.5.*"
Expand Down
31 changes: 16 additions & 15 deletions partiql-ast-passes/src/name_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use partiql_ast::ast;
use partiql_ast::ast::{GroupByExpr, GroupKey};
use partiql_ast::visit::{Traverse, Visit, Visitor};
use partiql_catalog::Catalog;
use partiql_common::node::NodeId;
use std::sync::atomic::{AtomicU32, Ordering};

type FnvIndexSet<T> = IndexSet<T, FnvBuildHasher>;
Expand Down Expand Up @@ -40,9 +41,9 @@ pub struct KeySchema {

#[derive(Default, Debug, Clone)]
pub struct KeyRegistry {
pub in_scope: FnvIndexMap<ast::NodeId, Vec<ast::NodeId>>,
pub schema: FnvIndexMap<ast::NodeId, KeySchema>,
pub aliases: FnvIndexMap<ast::NodeId, Symbol>,
pub in_scope: FnvIndexMap<NodeId, Vec<NodeId>>,
pub schema: FnvIndexMap<NodeId, KeySchema>,
pub aliases: FnvIndexMap<NodeId, Symbol>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -87,17 +88,17 @@ enum EnclosingClause {
#[allow(dead_code)]
pub struct NameResolver<'c> {
// environment stack tracking
id_path_to_root: Vec<ast::NodeId>,
id_child_stack: Vec<Vec<ast::NodeId>>,
id_path_to_root: Vec<NodeId>,
id_child_stack: Vec<Vec<NodeId>>,
keyref_stack: Vec<KeyRefs>,
lateral_stack: Vec<Vec<ast::NodeId>>,
lateral_stack: Vec<Vec<NodeId>>,
id_gen: IdGenerator,

// data flow tracking
enclosing_clause: FnvIndexMap<EnclosingClause, Vec<ast::NodeId>>,
in_scope: FnvIndexMap<ast::NodeId, Vec<ast::NodeId>>,
schema: FnvIndexMap<ast::NodeId, KeySchema>,
aliases: FnvIndexMap<ast::NodeId, Symbol>,
enclosing_clause: FnvIndexMap<EnclosingClause, Vec<NodeId>>,
in_scope: FnvIndexMap<NodeId, Vec<NodeId>>,
schema: FnvIndexMap<NodeId, KeySchema>,
aliases: FnvIndexMap<NodeId, Symbol>,

// errors that occur during name resolution
errors: Vec<AstTransformError>,
Expand Down Expand Up @@ -148,7 +149,7 @@ impl<'c> NameResolver<'c> {
}

#[inline]
fn current_node(&self) -> &ast::NodeId {
fn current_node(&self) -> &NodeId {
self.id_path_to_root.last().unwrap()
}

Expand All @@ -175,7 +176,7 @@ impl<'c> NameResolver<'c> {
}

#[inline]
fn exit_lateral(&mut self) -> Result<Vec<ast::NodeId>, AstTransformError> {
fn exit_lateral(&mut self) -> Result<Vec<NodeId>, AstTransformError> {
self.lateral_stack.pop().ok_or_else(|| {
AstTransformError::IllegalState("Expected non-empty lateral stack".to_string())
})
Expand All @@ -187,7 +188,7 @@ impl<'c> NameResolver<'c> {
}

#[inline]
fn exit_child_stack(&mut self) -> Result<Vec<ast::NodeId>, AstTransformError> {
fn exit_child_stack(&mut self) -> Result<Vec<NodeId>, AstTransformError> {
self.id_child_stack.pop().ok_or_else(|| {
AstTransformError::IllegalState("Expected non-empty child stack".to_string())
})
Expand All @@ -212,14 +213,14 @@ impl<'c> NameResolver<'c> {
}

impl<'ast, 'c> Visitor<'ast> for NameResolver<'c> {
fn enter_ast_node(&mut self, id: ast::NodeId) -> Traverse {
fn enter_ast_node(&mut self, id: NodeId) -> Traverse {
self.id_path_to_root.push(id);
if let Some(children) = self.id_child_stack.last_mut() {
children.push(id);
}
Traverse::Continue
}
fn exit_ast_node(&mut self, id: ast::NodeId) -> Traverse {
fn exit_ast_node(&mut self, id: NodeId) -> Traverse {
assert_eq!(self.id_path_to_root.pop(), Some(id));
Traverse::Continue
}
Expand Down
2 changes: 2 additions & 0 deletions partiql-ast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ path = "src/lib.rs"
bench = false

[dependencies]
partiql-common = { path = "../partiql-common", version = "0.10.*" }
indexmap = "2.2"
rust_decimal = { version = "1.25.0", default-features = false, features = ["std"] }
serde = { version = "1.*", features = ["derive"], optional = true }
Expand All @@ -33,6 +34,7 @@ serde = [
"rust_decimal/serde-with-str",
"rust_decimal/serde",
"indexmap/serde",
"partiql-common/serde"
]

[dependencies.partiql-ast-macros]
Expand Down
8 changes: 1 addition & 7 deletions partiql-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
// As more changes to this AST are expected, unless explicitly advised, using the structures exposed
// in this crate directly is not recommended.

use indexmap::IndexMap;
use rust_decimal::Decimal as RustDecimal;

use std::fmt;
Expand All @@ -17,12 +16,7 @@ use std::fmt;
use serde::{Deserialize, Serialize};

use partiql_ast_macros::Visit;

pub type AstTypeMap<T> = IndexMap<NodeId, T>;

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct NodeId(pub u32);
use partiql_common::node::NodeId;

/// Represents an AST node.
#[derive(Clone, Debug, Eq, PartialEq)]
Expand Down
64 changes: 14 additions & 50 deletions partiql-ast/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,53 +1,17 @@
use crate::ast;
use crate::ast::{AstNode, NodeId};
use crate::ast::AstNode;
use partiql_common::node::{AutoNodeIdGenerator, NodeIdGenerator, NullIdGenerator};

/// A provider of 'fresh' [`NodeId`]s.
pub trait IdGenerator {
/// Provides a 'fresh' [`NodeId`].
fn id(&mut self) -> NodeId;
}

/// Auto-incrementing [`IdGenerator`]
pub struct AutoNodeIdGenerator {
next_id: ast::NodeId,
}

impl Default for AutoNodeIdGenerator {
fn default() -> Self {
AutoNodeIdGenerator { next_id: NodeId(1) }
}
}

impl IdGenerator for AutoNodeIdGenerator {
#[inline]
fn id(&mut self) -> NodeId {
let mut next = NodeId(&self.next_id.0 + 1);
std::mem::swap(&mut self.next_id, &mut next);
next
}
}

/// A provider of [`NodeId`]s that are always `0`; Useful for testing
#[derive(Default)]
pub struct NullIdGenerator {}

impl IdGenerator for NullIdGenerator {
fn id(&mut self) -> NodeId {
NodeId(0)
}
}

/// A Builder for [`AstNode`]s that uses a [`IdGenerator`] to assign [`NodeId`]s
pub struct NodeBuilder<Id: IdGenerator> {
/// A Builder for [`AstNode`]s that uses a [`NodeIdGenerator`] to assign [`NodeId`]s
pub struct AstNodeBuilder<IdGen: NodeIdGenerator> {
/// Generator for 'fresh' [`NodeId`]s
pub id_gen: Id,
pub id_gen: IdGen,
}

impl<Id> NodeBuilder<Id>
impl<IdGen> AstNodeBuilder<IdGen>
where
Id: IdGenerator,
IdGen: NodeIdGenerator,
{
pub fn new(id_gen: Id) -> Self {
pub fn new(id_gen: IdGen) -> Self {
Self { id_gen }
}

Expand All @@ -57,17 +21,17 @@ where
}
}

impl<T> Default for NodeBuilder<T>
impl<T> Default for AstNodeBuilder<T>
where
T: IdGenerator + Default,
T: NodeIdGenerator + Default,
{
fn default() -> Self {
Self::new(T::default())
}
}

/// A [`NodeBuilder`] whose 'fresh' [`NodeId`]s are Auto-incrementing.
pub type NodeBuilderWithAutoId = NodeBuilder<AutoNodeIdGenerator>;
/// A [`AstNodeBuilder`] whose 'fresh' [`NodeId`]s are Auto-incrementing.
pub type AstNodeBuilderWithAutoId = AstNodeBuilder<AutoNodeIdGenerator>;

/// A [`NodeBuilder`] whose 'fresh' [`NodeId`]s are always `0`; Useful for testing
pub type NodeBuilderWithNullId = NodeBuilder<NullIdGenerator>;
/// A [`AstNodeBuilder`] whose 'fresh' [`NodeId`]s are always `0`; Useful for testing
pub type AstNodeBuilderWithNullId = AstNodeBuilder<NullIdGenerator>;
5 changes: 3 additions & 2 deletions partiql-ast/src/visit.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::ast;
use crate::ast::NodeId;
use partiql_common::node::NodeId;

/// Indicates if tree traversal of the entire tree should continue or not.
#[derive(PartialEq, Debug)]
Expand Down Expand Up @@ -561,7 +561,8 @@ pub trait Visitor<'ast> {
mod tests {
use crate::ast;
use crate::visit::{Traverse, Visitor};
use ast::{AstNode, BinOp, BinOpKind, Expr, Lit, NodeId};
use ast::{AstNode, BinOp, BinOpKind, Expr, Lit};
use partiql_common::node::NodeId;
use std::ops::AddAssign;

#[test]
Expand Down
24 changes: 13 additions & 11 deletions partiql-source-map/Cargo.toml → partiql-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]
name = "partiql-source-map"
description = "PartiQL Source Map"
name = "partiql-common"
description = "PartiQL Core"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
license = "Apache-2.0"
readme = "../README.md"
keywords = ["sql", "sourcemap", "query", "compilers", "interpreters"]
keywords = ["sql", "ast", "query", "compilers", "interpreters"]
categories = ["database", "compilers"]
exclude = [
"**/.git/**",
Expand All @@ -16,18 +16,20 @@ version.workspace = true
edition.workspace = true

[lib]
path = "src/lib.rs"
bench = false

[dependencies]
partiql-ast = { path = "../partiql-ast", version = "0.10.*" }

smallvec = { version = "1.*" }
indexmap = "2.2"
pretty = "0.12"
serde = { version = "1.*", features = ["derive"], optional = true }


[dev-dependencies]

smallvec = { version = "1.*" }
thiserror = "1.0"

[features]
default = []
serde = ["dep:serde", "smallvec/serde"]
serde = [
"dep:serde",
"indexmap/serde",
"smallvec/serde"
]
File renamed without changes.
4 changes: 4 additions & 0 deletions partiql-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#![deny(rust_2018_idioms)]
#![deny(clippy::all)]
pub mod node;
pub mod syntax;
47 changes: 47 additions & 0 deletions partiql-common/src/node.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use indexmap::IndexMap;
use std::hash::Hash;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

pub type NodeMap<T> = IndexMap<NodeId, T>;

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct NodeId(pub u32);

/// Auto-incrementing [`NodeIdGenerator`]
pub struct AutoNodeIdGenerator {
next_id: NodeId,
}

impl Default for AutoNodeIdGenerator {
fn default() -> Self {
AutoNodeIdGenerator { next_id: NodeId(1) }
}
}

/// A provider of 'fresh' [`NodeId`]s.
pub trait NodeIdGenerator {
/// Provides a 'fresh' [`NodeId`].
fn id(&mut self) -> NodeId;
}

impl NodeIdGenerator for AutoNodeIdGenerator {
#[inline]
fn id(&mut self) -> NodeId {
let mut next = NodeId(&self.next_id.0 + 1);
std::mem::swap(&mut self.next_id, &mut next);
next
}
}

/// A provider of [`NodeId`]s that are always `0`; Useful for testing
#[derive(Default)]
pub struct NullIdGenerator {}

impl NodeIdGenerator for NullIdGenerator {
fn id(&mut self) -> NodeId {
NodeId(0)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! [`LineOffsetTracker`] and related types for mapping locations in source `str`s.
use crate::location::{ByteOffset, BytePosition, LineAndCharPosition, LineOffset};
use crate::syntax::location::{ByteOffset, BytePosition, LineAndCharPosition, LineOffset};
use smallvec::{smallvec, SmallVec};
use std::ops::Range;

Expand All @@ -14,8 +14,8 @@ use serde::{Deserialize, Serialize};
/// ## Example
///
/// ```rust
/// use partiql_source_map::location::{ByteOffset, LineAndCharPosition};
/// use partiql_source_map::line_offset_tracker::{LineOffsetError, LineOffsetTracker};
/// use partiql_common::syntax::location::{ByteOffset, LineAndCharPosition};
/// use partiql_common::syntax::line_offset_tracker::{LineOffsetError, LineOffsetTracker};
///
/// let source = "12345\n789012345\n789012345\n789012345";
/// let mut tracker = LineOffsetTracker::default();
Expand Down
Loading

1 comment on commit e5b8ce7

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PartiQL (rust) Benchmark

Benchmark suite Current: e5b8ce7 Previous: 6dc088c Ratio
arith_agg-avg 775198 ns/iter (± 34461) 769347 ns/iter (± 8086) 1.01
arith_agg-avg_distinct 856544 ns/iter (± 5154) 864631 ns/iter (± 3111) 0.99
arith_agg-count 820861 ns/iter (± 18988) 817735 ns/iter (± 44170) 1.00
arith_agg-count_distinct 852867 ns/iter (± 4970) 859871 ns/iter (± 16448) 0.99
arith_agg-min 827041 ns/iter (± 2639) 823541 ns/iter (± 16473) 1.00
arith_agg-min_distinct 860210 ns/iter (± 10560) 860789 ns/iter (± 3429) 1.00
arith_agg-max 835593 ns/iter (± 3961) 828686 ns/iter (± 1915) 1.01
arith_agg-max_distinct 864949 ns/iter (± 4270) 867876 ns/iter (± 32406) 1.00
arith_agg-sum 824926 ns/iter (± 1621) 824516 ns/iter (± 3833) 1.00
arith_agg-sum_distinct 857067 ns/iter (± 1983) 868788 ns/iter (± 2851) 0.99
arith_agg-avg-count-min-max-sum 968375 ns/iter (± 8380) 965437 ns/iter (± 13827) 1.00
arith_agg-avg-count-min-max-sum-group_by 1204293 ns/iter (± 13453) 1203160 ns/iter (± 24930) 1.00
arith_agg-avg-count-min-max-sum-group_by-group_as 1801364 ns/iter (± 31255) 1805354 ns/iter (± 41273) 1.00
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct 1229000 ns/iter (± 13263) 1264656 ns/iter (± 12802) 0.97
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct-group_by 1508448 ns/iter (± 9427) 1550278 ns/iter (± 24933) 0.97
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct-group_by-group_as 2098733 ns/iter (± 10245) 2145855 ns/iter (± 41224) 0.98
parse-1 5619 ns/iter (± 23) 5378 ns/iter (± 84) 1.04
parse-15 48240 ns/iter (± 118) 46773 ns/iter (± 120) 1.03
parse-30 93707 ns/iter (± 250) 91519 ns/iter (± 268) 1.02
compile-1 4326 ns/iter (± 10) 4321 ns/iter (± 23) 1.00
compile-15 33011 ns/iter (± 270) 33227 ns/iter (± 112) 0.99
compile-30 68472 ns/iter (± 296) 69079 ns/iter (± 1950) 0.99
plan-1 66983 ns/iter (± 261) 67288 ns/iter (± 1696) 1.00
plan-15 1047620 ns/iter (± 5242) 1050445 ns/iter (± 41700) 1.00
plan-30 2101187 ns/iter (± 26131) 2102844 ns/iter (± 19876) 1.00
eval-1 13463456 ns/iter (± 113930) 13304642 ns/iter (± 223004) 1.01
eval-15 91368497 ns/iter (± 276047) 86429143 ns/iter (± 2425132) 1.06
eval-30 174268173 ns/iter (± 529438) 166575250 ns/iter (± 2418779) 1.05
join 9998 ns/iter (± 152) 9850 ns/iter (± 102) 1.02
simple 2479 ns/iter (± 11) 2502 ns/iter (± 9) 0.99
simple-no 428 ns/iter (± 5) 423 ns/iter (± 2) 1.01
numbers 57 ns/iter (± 0) 57 ns/iter (± 0) 1
parse-simple 717 ns/iter (± 5) 775 ns/iter (± 9) 0.93
parse-ion 2263 ns/iter (± 5) 2398 ns/iter (± 5) 0.94
parse-group 7145 ns/iter (± 31) 6958 ns/iter (± 23) 1.03
parse-complex 18704 ns/iter (± 58) 18549 ns/iter (± 418) 1.01
parse-complex-fexpr 25839 ns/iter (± 81) 25695 ns/iter (± 131) 1.01

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.