Skip to content

Commit 6426ae6

Browse files
authored
Give AST nodes identity & decouple source location from AST node. (#194)
- Move the source offset location that gave rise to each AST node into a `LocationMap` - Add a unique `NodeId` to each AST node
1 parent 19e92da commit 6426ae6

File tree

14 files changed

+470
-365
lines changed

14 files changed

+470
-365
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
9+
### Changed
10+
- *BREAKING:* Refactors the AST
11+
- Removed Location from the AST, replacing with a 'node id' that gives the AST node identity; the id can be used to retrieve Location
12+
913
### Added
1014
- Adds the following functionalities to PartiQL Playground:
1115
- Moves the project to a Node.js project

partiql-ast/Cargo.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ version = "0.1.0"
2121
path = "src/lib.rs"
2222

2323
[dependencies]
24-
partiql-source-map = { path = "../partiql-source-map", version = "0.1.0" }
25-
26-
derive_builder = "~0.11.1"
2724
rust_decimal = { version = "1.25.0", default-features = false, features = ["std"] }
2825

2926
serde = { version = "1.*", features = ["derive"], optional = true }
@@ -36,7 +33,6 @@ serde = { version = "1.*", features = ["derive"], optional = true }
3633
default = []
3734
serde = [
3835
"dep:serde",
39-
"partiql-source-map/serde",
4036
"rust_decimal/serde-with-str",
4137
"rust_decimal/serde"
4238
]

partiql-ast/src/ast.rs

Lines changed: 63 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -7,86 +7,25 @@
77
// As more changes to this AST are expected, unless explicitly advised, using the structures exposed
88
// in this crate directly is not recommended.
99

10-
use partiql_source_map::location::{ByteOffset, BytePosition, Location};
1110
use rust_decimal::Decimal as RustDecimal;
1211

1312
use std::fmt;
14-
use std::fmt::Display;
15-
use std::ops::Range;
1613

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

20-
/// Provides the required methods for AstNode conversations.
21-
pub trait ToAstNode: Sized {
22-
/// Wraps the `self` to an [AstNode] and returns an `AstNodeBuilder` for
23-
/// further [AstNode] construction.
24-
/// ## Example:
25-
/// ```
26-
/// use partiql_ast::ast;
27-
/// use partiql_ast::ast::{SymbolPrimitive, ToAstNode};
28-
/// use partiql_ast::ast::CaseSensitivity::CaseInsensitive;
29-
/// use partiql_source_map::location::{ByteOffset, BytePosition, Location, ToLocated};
30-
///
31-
/// let p = SymbolPrimitive {
32-
/// value: "symbol2".to_string(),
33-
/// case: Some(ast::CaseSensitivity::CaseInsensitive)
34-
/// };
35-
///
36-
/// let node = p
37-
/// .to_node()
38-
/// .location((BytePosition::from(12)..BytePosition::from(1)).into())
39-
/// .build()
40-
/// .expect("Could not retrieve ast node");
41-
/// ```
42-
fn to_node(self) -> AstNodeBuilder<Self, BytePosition>
43-
where
44-
Self: Clone,
45-
{
46-
AstNodeBuilder::default().node(self).clone()
47-
}
48-
49-
fn to_ast<Loc, IntoLoc>(self, location: IntoLoc) -> AstNode<Self, Loc>
50-
where
51-
Loc: Display,
52-
IntoLoc: Into<Location<Loc>>,
53-
{
54-
AstNode {
55-
node: self,
56-
location: Some(location.into()),
57-
}
58-
}
59-
60-
fn ast(self, Range { start, end }: Range<ByteOffset>) -> AstNode<Self, BytePosition> {
61-
self.to_ast(start.into()..end.into())
62-
}
63-
}
64-
65-
/// Implements [ToAstNode] for all types within this crate, read further [here][1].
66-
///
67-
/// [1]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
68-
impl<T> ToAstNode for T {}
17+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
18+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19+
pub struct NodeId(pub u32);
6920

70-
/// Represents an AST node. [AstNode] uses [derive_builder][1] to expose a Builder
71-
/// for creating the node. See [ToAstNode] for more details on the usage.
72-
///
73-
/// [1]: https://crates.io/crates/derive_builder
74-
#[derive(Builder, Clone, Debug)]
21+
/// Represents an AST node.
22+
#[derive(Clone, Debug, Eq, PartialEq)]
7523
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
76-
pub struct AstNode<T, Loc: Display> {
24+
pub struct AstNode<T> {
25+
pub id: NodeId,
7726
pub node: T,
78-
#[builder(setter(strip_option), default)]
79-
pub location: Option<Location<Loc>>,
8027
}
8128

82-
impl<T: PartialEq, Loc: Display> PartialEq for AstNode<T, Loc> {
83-
fn eq(&self, other: &Self) -> bool {
84-
self.node == other.node
85-
}
86-
}
87-
88-
impl<T: Eq, Loc: Display> Eq for AstNode<T, Loc> {}
89-
9029
#[derive(Clone, Debug, PartialEq)]
9130
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9231
pub struct Item {
@@ -140,13 +79,13 @@ pub enum DdlOpKind {
14079
DropIndex(DropIndex),
14180
}
14281

143-
#[derive(Clone, Debug, PartialEq)]
82+
#[derive(Clone, Debug, PartialEq, Eq)]
14483
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14584
pub struct CreateTable {
14685
pub table_name: SymbolPrimitive,
14786
}
14887

149-
#[derive(Clone, Debug, PartialEq)]
88+
#[derive(Clone, Debug, PartialEq, Eq)]
15089
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
15190
pub struct DropTable {
15291
pub table_name: SymbolPrimitive,
@@ -159,7 +98,7 @@ pub struct CreateIndex {
15998
pub fields: Vec<Box<Expr>>,
16099
}
161100

162-
#[derive(Clone, Debug, PartialEq)]
101+
#[derive(Clone, Debug, PartialEq, Eq)]
163102
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
164103
pub struct DropIndex {
165104
pub table: Ident,
@@ -234,7 +173,7 @@ pub struct OnConflict {
234173
}
235174

236175
/// `CONFLICT_ACTION <action>`
237-
#[derive(Clone, Debug, PartialEq)]
176+
#[derive(Clone, Debug, PartialEq, Eq)]
238177
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
239178
pub enum ConflictAction {
240179
DoNothing,
@@ -246,43 +185,40 @@ pub struct Expr {
246185
pub kind: ExprKind,
247186
}
248187

249-
/// Represents an AST Node of type T with BytePosition Location
250-
pub type AstBytePos<T> = AstNode<T, BytePosition>;
251-
252-
pub type BagAst = AstBytePos<Bag>;
253-
pub type BetweenAst = AstBytePos<Between>;
254-
pub type BinOpAst = AstBytePos<BinOp>;
255-
pub type CallAggAst = AstBytePos<CallAgg>;
256-
pub type CallArgAst = AstBytePos<CallArg>;
257-
pub type CallAst = AstBytePos<Call>;
258-
pub type CaseAst = AstBytePos<Case>;
259-
pub type FromClauseAst = AstBytePos<FromClause>;
260-
pub type FromLetAst = AstBytePos<FromLet>;
261-
pub type GroupByExprAst = AstBytePos<GroupByExpr>;
262-
pub type GroupKeyAst = AstBytePos<GroupKey>;
263-
pub type InAst = AstBytePos<In>;
264-
pub type JoinAst = AstBytePos<Join>;
265-
pub type JoinSpecAst = AstBytePos<JoinSpec>;
266-
pub type LetAst = AstBytePos<Let>;
267-
pub type LikeAst = AstBytePos<Like>;
268-
pub type ListAst = AstBytePos<List>;
269-
pub type LitAst = AstBytePos<Lit>;
270-
pub type OrderByExprAst = AstBytePos<OrderByExpr>;
271-
pub type ParamAst = AstBytePos<Param>;
272-
pub type PathAst = AstBytePos<Path>;
273-
pub type ProjectItemAst = AstBytePos<ProjectItem>;
274-
pub type ProjectionAst = AstBytePos<Projection>;
275-
pub type QueryAst = AstBytePos<Query>;
276-
pub type QuerySetAst = AstBytePos<QuerySet>;
277-
pub type SearchedCaseAst = AstBytePos<SearchedCase>;
278-
pub type SelectAst = AstBytePos<Select>;
279-
pub type SetExprAst = AstBytePos<SetExpr>;
280-
pub type SexpAst = AstBytePos<Sexp>;
281-
pub type SimpleCaseAst = AstBytePos<SimpleCase>;
282-
pub type SortSpecAst = AstBytePos<SortSpec>;
283-
pub type StructAst = AstBytePos<Struct>;
284-
pub type UniOpAst = AstBytePos<UniOp>;
285-
pub type VarRefAst = AstBytePos<VarRef>;
188+
pub type BagAst = AstNode<Bag>;
189+
pub type BetweenAst = AstNode<Between>;
190+
pub type BinOpAst = AstNode<BinOp>;
191+
pub type CallAggAst = AstNode<CallAgg>;
192+
pub type CallArgAst = AstNode<CallArg>;
193+
pub type CallAst = AstNode<Call>;
194+
pub type CaseAst = AstNode<Case>;
195+
pub type FromClauseAst = AstNode<FromClause>;
196+
pub type FromLetAst = AstNode<FromLet>;
197+
pub type GroupByExprAst = AstNode<GroupByExpr>;
198+
pub type GroupKeyAst = AstNode<GroupKey>;
199+
pub type InAst = AstNode<In>;
200+
pub type JoinAst = AstNode<Join>;
201+
pub type JoinSpecAst = AstNode<JoinSpec>;
202+
pub type LetAst = AstNode<Let>;
203+
pub type LikeAst = AstNode<Like>;
204+
pub type ListAst = AstNode<List>;
205+
pub type LitAst = AstNode<Lit>;
206+
pub type OrderByExprAst = AstNode<OrderByExpr>;
207+
pub type ParamAst = AstNode<Param>;
208+
pub type PathAst = AstNode<Path>;
209+
pub type ProjectItemAst = AstNode<ProjectItem>;
210+
pub type ProjectionAst = AstNode<Projection>;
211+
pub type QueryAst = AstNode<Query>;
212+
pub type QuerySetAst = AstNode<QuerySet>;
213+
pub type SearchedCaseAst = AstNode<SearchedCase>;
214+
pub type SelectAst = AstNode<Select>;
215+
pub type SetExprAst = AstNode<SetExpr>;
216+
pub type SexpAst = AstNode<Sexp>;
217+
pub type SimpleCaseAst = AstNode<SimpleCase>;
218+
pub type SortSpecAst = AstNode<SortSpec>;
219+
pub type StructAst = AstNode<Struct>;
220+
pub type UniOpAst = AstNode<UniOp>;
221+
pub type VarRefAst = AstNode<VarRef>;
286222

287223
#[derive(Clone, Debug, PartialEq)]
288224
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -311,7 +247,7 @@ pub struct SetExpr {
311247
pub rhs: Box<QuerySetAst>,
312248
}
313249

314-
#[derive(Clone, Debug, PartialEq)]
250+
#[derive(Clone, Debug, PartialEq, Eq)]
315251
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
316252
pub enum SetOperator {
317253
Union,
@@ -385,29 +321,29 @@ pub enum Lit {
385321
TypedLit(String, Type),
386322
}
387323

388-
#[derive(Clone, Debug, PartialEq)]
324+
#[derive(Clone, Debug, PartialEq, Eq)]
389325
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
390326
pub enum CollectionLit {
391327
ArrayLit(String),
392328
BagLit(String),
393329
}
394330

395-
#[derive(Clone, Debug, PartialEq)]
331+
#[derive(Clone, Debug, PartialEq, Eq)]
396332
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
397333
pub enum DateTimeLit {
398334
DateLit(String),
399335
TimeLit(String),
400336
TimestampLit(String),
401337
}
402338

403-
#[derive(Clone, Debug, PartialEq)]
339+
#[derive(Clone, Debug, PartialEq, Eq)]
404340
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
405341
pub struct VarRef {
406342
pub name: SymbolPrimitive,
407343
pub qualifier: ScopeQualifier,
408344
}
409345

410-
#[derive(Clone, Debug, PartialEq)]
346+
#[derive(Clone, Debug, PartialEq, Eq)]
411347
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
412348
pub struct Param {
413349
pub index: i32,
@@ -421,7 +357,7 @@ pub struct BinOp {
421357
pub rhs: Box<Expr>,
422358
}
423359

424-
#[derive(Clone, Debug, PartialEq)]
360+
#[derive(Clone, Debug, PartialEq, Eq)]
425361
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
426362
pub enum BinOpKind {
427363
// Arithmetic
@@ -453,7 +389,7 @@ pub struct UniOp {
453389
pub expr: Box<Expr>,
454390
}
455391

456-
#[derive(Clone, Debug, PartialEq)]
392+
#[derive(Clone, Debug, PartialEq, Eq)]
457393
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
458394
pub enum UniOpKind {
459395
Pos,
@@ -607,7 +543,7 @@ pub struct PathExpr {
607543
}
608544

609545
/// Is used to determine if variable lookup should be case-sensitive or not.
610-
#[derive(Clone, Debug, PartialEq)]
546+
#[derive(Clone, Debug, PartialEq, Eq)]
611547
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
612548
pub enum CaseSensitivity {
613549
CaseSensitive,
@@ -706,15 +642,15 @@ pub enum JoinSpec {
706642

707643
/// Indicates the type of FromLet, see the following for more details:
708644
/// https:///github.com/partiql/partiql-lang-kotlin/issues/242
709-
#[derive(Clone, Debug, PartialEq)]
645+
#[derive(Clone, Debug, PartialEq, Eq)]
710646
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
711647
pub enum FromLetKind {
712648
Scan,
713649
Unpivot,
714650
}
715651

716652
/// Indicates the logical type of join.
717-
#[derive(Clone, Debug, PartialEq)]
653+
#[derive(Clone, Debug, PartialEq, Eq)]
718654
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
719655
pub enum JoinKind {
720656
Inner,
@@ -744,7 +680,7 @@ pub struct GroupByExpr {
744680

745681
/// Desired grouping qualifier: ALL or PARTIAL. Note: the `group_` prefix is
746682
/// needed to avoid naming clashes.
747-
#[derive(Clone, Debug, PartialEq)]
683+
#[derive(Clone, Debug, PartialEq, Eq)]
748684
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
749685
pub enum GroupingStrategy {
750686
GroupFull,
@@ -782,14 +718,14 @@ pub struct SortSpec {
782718
pub null_ordering_spec: Option<NullOrderingSpec>,
783719
}
784720

785-
#[derive(Clone, Debug, PartialEq)]
721+
#[derive(Clone, Debug, PartialEq, Eq)]
786722
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
787723
pub enum OrderingSpec {
788724
Asc,
789725
Desc,
790726
}
791727

792-
#[derive(Clone, Debug, PartialEq)]
728+
#[derive(Clone, Debug, PartialEq, Eq)]
793729
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
794730
pub enum NullOrderingSpec {
795731
First,
@@ -798,7 +734,7 @@ pub enum NullOrderingSpec {
798734

799735
/// Indicates scope search order when resolving variables.
800736
/// Has no effect except within `FROM` sources.
801-
#[derive(Clone, Debug, PartialEq)]
737+
#[derive(Clone, Debug, PartialEq, Eq)]
802738
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
803739
pub enum ScopeQualifier {
804740
/// Use the default search order.
@@ -808,7 +744,7 @@ pub enum ScopeQualifier {
808744
}
809745

810746
/// Indicates if a set should be reduced to its distinct elements or not.
811-
#[derive(Clone, Debug, PartialEq)]
747+
#[derive(Clone, Debug, PartialEq, Eq)]
812748
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
813749
pub enum SetQuantifier {
814750
All,
@@ -844,7 +780,7 @@ pub struct ReturningColumn {
844780
}
845781

846782
/// ( MODIFIED | ALL ) ( NEW | OLD )
847-
#[derive(Clone, Debug, PartialEq)]
783+
#[derive(Clone, Debug, PartialEq, Eq)]
848784
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
849785
pub enum ReturningMapping {
850786
ModifiedNew,
@@ -863,7 +799,7 @@ pub enum ReturningMapping {
863799
/// an element of a type. (Even though in the Kotlin code each varaint is its own type.) Hence, we
864800
/// define an `Ident` type above which can be used without opening up an element's domain to
865801
/// all of `expr`.
866-
#[derive(Clone, Debug, PartialEq)]
802+
#[derive(Clone, Debug, PartialEq, Eq)]
867803
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
868804
pub struct Ident {
869805
pub name: SymbolPrimitive,
@@ -937,7 +873,7 @@ pub struct CustomType {
937873
pub parts: Vec<CustomTypePart>,
938874
}
939875

940-
#[derive(Clone, Debug, PartialEq)]
876+
#[derive(Clone, Debug, PartialEq, Eq)]
941877
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
942878
pub struct SymbolPrimitive {
943879
pub value: String,

0 commit comments

Comments
 (0)