Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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.

7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ glob = "0.3.1"
insta = "1.39.0"
jsonwebtoken = { version = "10.3.0", features = ["rust_crypto"] }
log = "0.4.25"
reqwest = { version = "0.11.27", features = ["native-tls-vendored", "blocking", "json"] }
reqwest = { version = "0.11.27", features = [
"native-tls-vendored",
"blocking",
"json",
] }
la-arena = "0.3.1"
serde = { version = "1.0.215", features = ["derive"] }
serde_json = "1.0"
Expand Down Expand Up @@ -52,6 +56,7 @@ console_error_panic_hook = "0.1.7"
console_log = "1.0.0"
annotate-snippets = "0.12.4"
anyhow = "1.0.94"
either = "1.15.0"
convert_case = "0.7.1"
clap = { version = "4.5.8", features = ["derive", "env"] }
ungrammar = "1.1.4"
Expand Down
41 changes: 41 additions & 0 deletions crates/squawk_ide/src/file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// via https://github.com/rust-lang/rust-analyzer/blob/2efc80078029894eec0699f62ec8d5c1a56af763/crates/hir-expand/src/files.rs#L21C21-L21C21
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use crate::db::File;

/// `InFile<T>` stores a value of `T` inside a particular file/syntax tree.
///
/// Typical usages are:
///
/// * `InFile<SyntaxNode>` -- syntax node in a file
/// * `InFile<ast::FnDef>` -- ast node in a file
/// * `InFile<TextSize>` -- offset in a file
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct InFileWrapper<FileKind, T> {
pub file_id: FileKind,
pub value: T,
}
pub type InFile<T> = InFileWrapper<File, T>;
1 change: 1 addition & 0 deletions crates/squawk_syntax/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ doctest = false
squawk-parser.workspace = true
rowan.workspace = true
smol_str.workspace = true
either.workspace = true

[dev-dependencies]
annotate-snippets.workspace = true
Expand Down
4 changes: 3 additions & 1 deletion crates/squawk_syntax/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
pub mod ast;
pub mod identifier;
mod parsing;
mod ptr;
pub mod syntax_error;
mod syntax_node;
mod token_text;
Expand All @@ -40,9 +41,10 @@ use std::{marker::PhantomData, sync::Arc};
pub use squawk_parser::SyntaxKind;

use ast::AstNode;
pub use ptr::{AstPtr, SyntaxNodePtr};
use rowan::GreenNode;
use syntax_error::SyntaxError;
pub use syntax_node::{SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken};
pub use syntax_node::{SyntaxElement, SyntaxNode, SyntaxToken};
pub use token_text::TokenText;

/// `Parse` is the result of the parsing: a syntax tree and a collection of
Expand Down
178 changes: 178 additions & 0 deletions crates/squawk_syntax/src/ptr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// via https://github.com/rust-lang/rust-analyzer/blob/2efc80078029894eec0699f62ec8d5c1a56af763/crates/syntax/src/ptr.rs#L22C19-L22C19
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! In squawk, syntax trees are transient objects.
//!
//! That means that we create trees when we need them, and tear them down to
//! save memory. In this architecture, hanging on to a particular syntax node
//! for a long time is ill-advisable, as that keeps the whole tree resident.
//!
//! Instead, we provide a [`SyntaxNodePtr`] type, which stores information about
//! *location* of a particular syntax node in a tree. Its a small type which can
//! be cheaply stored, and which can be resolved to a real [`SyntaxNode`] when
//! necessary.

use std::{
hash::{Hash, Hasher},
marker::PhantomData,
};

use rowan::TextRange;

use crate::{AstNode, SyntaxNode, syntax_node::Sql};

/// A "pointer" to a [`SyntaxNode`], via location in the source code.
pub type SyntaxNodePtr = rowan::ast::SyntaxNodePtr<Sql>;

/// Like [`SyntaxNodePtr`], but remembers the type of node.
pub struct AstPtr<N: AstNode> {
raw: SyntaxNodePtr,
_ty: PhantomData<fn() -> N>,
}

impl<N: AstNode> std::fmt::Debug for AstPtr<N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("AstPtr").field(&self.raw).finish()
}
}

impl<N: AstNode> Copy for AstPtr<N> {}
impl<N: AstNode> Clone for AstPtr<N> {
fn clone(&self) -> AstPtr<N> {
*self
}
}

impl<N: AstNode> Eq for AstPtr<N> {}

impl<N: AstNode> PartialEq for AstPtr<N> {
fn eq(&self, other: &AstPtr<N>) -> bool {
self.raw == other.raw
}
}

impl<N: AstNode> Hash for AstPtr<N> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.raw.hash(state);
}
}

impl<N: AstNode> AstPtr<N> {
pub fn new(node: &N) -> AstPtr<N> {
AstPtr {
raw: SyntaxNodePtr::new(node.syntax()),
_ty: PhantomData,
}
}

pub fn to_node(&self, root: &SyntaxNode) -> N {
let syntax_node = self.raw.to_node(root);
N::cast(syntax_node).unwrap()
}

pub fn syntax_node_ptr(&self) -> SyntaxNodePtr {
self.raw
}

pub fn text_range(&self) -> TextRange {
self.raw.text_range()
}

pub fn cast<U: AstNode>(self) -> Option<AstPtr<U>> {
if !U::can_cast(self.raw.kind()) {
return None;
}
Some(AstPtr {
raw: self.raw,
_ty: PhantomData,
})
}

pub fn kind(&self) -> squawk_parser::SyntaxKind {
self.raw.kind()
}

pub fn upcast<M: AstNode>(self) -> AstPtr<M>
where
N: Into<M>,
{
AstPtr {
raw: self.raw,
_ty: PhantomData,
}
}

/// Like `SyntaxNodePtr::cast` but the trait bounds work out.
pub fn try_from_raw(raw: SyntaxNodePtr) -> Option<AstPtr<N>> {
N::can_cast(raw.kind()).then_some(AstPtr {
raw,
_ty: PhantomData,
})
}

pub fn wrap_left<R>(self) -> AstPtr<either::Either<N, R>>
where
either::Either<N, R>: AstNode,
{
AstPtr {
raw: self.raw,
_ty: PhantomData,
}
}

pub fn wrap_right<L>(self) -> AstPtr<either::Either<L, N>>
where
either::Either<L, N>: AstNode,
{
AstPtr {
raw: self.raw,
_ty: PhantomData,
}
}
}

impl<N: AstNode> From<AstPtr<N>> for SyntaxNodePtr {
fn from(ptr: AstPtr<N>) -> SyntaxNodePtr {
ptr.raw
}
}

#[test]
fn test_local_syntax_ptr() {
use crate::{AstNode, ast};

let file = ast::SourceFile::parse("create table t(c int8);")
.ok()
.unwrap();
let field = file
.syntax()
.descendants()
.find_map(ast::Column::cast)
.unwrap();
let ptr = SyntaxNodePtr::new(field.syntax());
let field_syntax = ptr.to_node(file.syntax());
assert_eq!(field.syntax(), &field_syntax);
}
1 change: 0 additions & 1 deletion crates/squawk_syntax/src/syntax_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ impl Language for Sql {

pub type SyntaxNode = rowan::SyntaxNode<Sql>;
pub type SyntaxToken = rowan::SyntaxToken<Sql>;
pub type SyntaxNodePtr = rowan::ast::SyntaxNodePtr<Sql>;
pub type SyntaxElement = rowan::SyntaxElement<Sql>;
pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren<Sql>;
// pub type SyntaxElementChildren = rowan::SyntaxElementChildren<Sql>;
Expand Down
Loading