Skip to content

Commit

Permalink
chore: add Grit node compilers (#2689)
Browse files Browse the repository at this point in the history
  • Loading branch information
arendjr authored May 3, 2024
1 parent 6d264aa commit 26a94cc
Show file tree
Hide file tree
Showing 64 changed files with 2,713 additions and 57 deletions.
12 changes: 8 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,7 @@ opt-level = "s"
[profile.release.package.biome_wasm]
debug = false
opt-level = 3

#[patch.crates-io]
#grit-pattern-matcher = { path = "../gritql/crates/grit-pattern-matcher" }
#grit-util = { path = "../gritql/crates/grit-util" }
8 changes: 6 additions & 2 deletions crates/biome_grit_patterns/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ version = "0.0.1"
anyhow = { workspace = true }
biome_console = { workspace = true }
biome_diagnostics = { workspace = true }
grit-pattern-matcher = { version = "0.1" }
grit-util = { version = "0.1" }
biome_grit_parser = { workspace = true }
biome_grit_syntax = { workspace = true }
biome_rowan = { workspace = true }
grit-pattern-matcher = { version = "0.2" }
grit-util = { version = "0.2" }
im = { version = "15.1.0" }
itertools = "0.10.5"
serde = { workspace = true, features = ["derive"] }

[lints]
Expand Down
22 changes: 22 additions & 0 deletions crates/biome_grit_patterns/src/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use biome_diagnostics::Diagnostic;
use biome_rowan::TextRange;

#[derive(Debug, Diagnostic)]
#[diagnostic(severity = Warning)]
pub(crate) struct CompilerDiagnostic {
#[message]
#[description]
message: String,

#[location(span)]
range: TextRange,
}

impl CompilerDiagnostic {
pub(crate) fn new_warning(message: impl Into<String>, range: TextRange) -> Self {
Self {
message: message.into(),
range,
}
}
}
36 changes: 34 additions & 2 deletions crates/biome_grit_patterns/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use biome_diagnostics::serde::Diagnostic as SerializableDiagnostic;
use biome_diagnostics::Diagnostic;
use biome_rowan::SyntaxError;
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Diagnostic, Serialize)]
Expand All @@ -22,11 +23,42 @@ pub struct ParseSnippetError {
diagnostics: Vec<SerializableDiagnostic>,
}

#[derive(Debug, Deserialize, Diagnostic, Serialize)]
pub enum ParseError {
#[derive(Debug, Deserialize, Serialize)]
pub enum CompileError {
/// Indicates the (top-level) pattern could not be parsed.
ParsePatternError(ParsePatternError),

/// Indicates one of the pattern's snippets could not be parsed.
ParseSnippetError(ParseSnippetError),

/// Used for missing syntax nodes.
MissingSyntaxNode,

/// If a function or bubble pattern has multiple parameters with the same name.
DuplicateParameters,

/// Tried to declare or assign a Grit reserved metavariable.
ReservedMetavariable(String),

/// When an unsupported node kind was discovered during compilation.
UnsupportedKind(u16),

/// When an unexpected node kind was discovered during compilation.
UnexpectedKind(u16),

/// A literal value was too large or too small.
LiteralOutOfRange(String),

/// A pattern is required to compile a Grit query.
MissingPattern,
}

impl Diagnostic for CompileError {}

impl From<SyntaxError> for CompileError {
fn from(error: SyntaxError) -> Self {
match error {
SyntaxError::MissingRequiredChild => Self::MissingSyntaxNode,
}
}
}
28 changes: 17 additions & 11 deletions crates/biome_grit_patterns/src/grit_binding.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::{grit_context::GritQueryContext, grit_language::GritLanguage, grit_node::GritNode};
use crate::{
grit_context::GritQueryContext, grit_node::GritNode, grit_target_language::GritTargetLanguage,
};
use grit_pattern_matcher::{binding::Binding, constant::Constant};
use grit_util::{CodeRange, Range};
use grit_util::{ByteRange, CodeRange, Range};
use std::path::Path;

#[derive(Clone, Debug, PartialEq)]
Expand All @@ -19,7 +21,7 @@ impl<'a> Binding<'a, GritQueryContext> for GritBinding {
todo!()
}

fn from_range(_range: Range, _source: &'a str) -> Self {
fn from_range(_range: ByteRange, _source: &'a str) -> Self {
todo!()
}

Expand All @@ -31,34 +33,38 @@ impl<'a> Binding<'a, GritQueryContext> for GritBinding {
todo!()
}

fn position(&self, _language: &GritLanguage) -> Option<Range> {
fn position(&self, _language: &GritTargetLanguage) -> Option<Range> {
todo!()
}

fn code_range(&self, _language: &GritLanguage) -> Option<CodeRange> {
fn range(&self, _language: &GritTargetLanguage) -> Option<ByteRange> {
todo!()
}

fn is_equivalent_to(&self, _other: &Self, _language: &GritLanguage) -> bool {
fn code_range(&self, _language: &GritTargetLanguage) -> Option<CodeRange> {
todo!()
}

fn is_suppressed(&self, _language: &GritLanguage, _current_name: Option<&str>) -> bool {
fn is_equivalent_to(&self, _other: &Self, _language: &GritTargetLanguage) -> bool {
todo!()
}

fn is_suppressed(&self, _language: &GritTargetLanguage, _current_name: Option<&str>) -> bool {
todo!()
}

fn get_insertion_padding(
&self,
_text: &str,
_is_first: bool,
_language: &GritLanguage,
_language: &GritTargetLanguage,
) -> Option<String> {
todo!()
}

fn linearized_text(
&self,
_language: &GritLanguage,
_language: &GritTargetLanguage,
_effects: &[grit_pattern_matcher::effects::Effect<'a, GritQueryContext>],
_files: &grit_pattern_matcher::pattern::FileRegistry<'a, GritQueryContext>,
_memo: &mut std::collections::HashMap<grit_util::CodeRange, Option<String>>,
Expand All @@ -68,7 +74,7 @@ impl<'a> Binding<'a, GritQueryContext> for GritBinding {
todo!()
}

fn text(&self, _language: &GritLanguage) -> anyhow::Result<std::borrow::Cow<str>> {
fn text(&self, _language: &GritTargetLanguage) -> anyhow::Result<std::borrow::Cow<str>> {
todo!()
}

Expand Down Expand Up @@ -106,7 +112,7 @@ impl<'a> Binding<'a, GritQueryContext> for GritBinding {

fn log_empty_field_rewrite_error(
&self,
_language: &GritLanguage,
_language: &GritTargetLanguage,
_logs: &mut grit_util::AnalysisLogs,
) -> anyhow::Result<()> {
todo!()
Expand Down
5 changes: 4 additions & 1 deletion crates/biome_grit_patterns/src/grit_code_snippet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use grit_pattern_matcher::pattern::{
use grit_util::AnalysisLogs;

#[derive(Clone, Debug)]
pub(crate) struct GritCodeSnippet;
pub(crate) struct GritCodeSnippet {
pub(crate) source: String,
pub(crate) dynamic_snippet: Option<DynamicPattern<GritQueryContext>>,
}

impl CodeSnippet<GritQueryContext> for GritCodeSnippet {
fn patterns(&self) -> impl Iterator<Item = &Pattern<GritQueryContext>> {
Expand Down
6 changes: 3 additions & 3 deletions crates/biome_grit_patterns/src/grit_context.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::grit_binding::GritBinding;
use crate::grit_code_snippet::GritCodeSnippet;
use crate::grit_file::GritFile;
use crate::grit_language::GritLanguage;
use crate::grit_node::GritNode;
use crate::grit_node_patterns::{GritLeafNodePattern, GritNodePattern};
use crate::grit_target_language::GritTargetLanguage;
use crate::grit_tree::GritTree;
use crate::resolved_pattern::GritResolvedPattern;
use anyhow::Result;
Expand All @@ -25,7 +25,7 @@ impl QueryContext for GritQueryContext {
type Binding<'a> = GritBinding;
type CodeSnippet = GritCodeSnippet;
type ResolvedPattern<'a> = GritResolvedPattern;
type Language<'a> = GritLanguage;
type Language<'a> = GritTargetLanguage;
type File<'a> = GritFile;
type Tree = GritTree;
}
Expand Down Expand Up @@ -64,7 +64,7 @@ impl<'a> ExecContext<'a, GritQueryContext> for GritExecContext {
todo!()
}

fn language(&self) -> &GritLanguage {
fn language(&self) -> &GritTargetLanguage {
todo!()
}

Expand Down
4 changes: 2 additions & 2 deletions crates/biome_grit_patterns/src/grit_file.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::grit_context::GritQueryContext;
use crate::grit_language::GritLanguage;
use crate::grit_target_language::GritTargetLanguage;
use crate::resolved_pattern::GritResolvedPattern;
use grit_pattern_matcher::pattern::{File, FileRegistry};

Expand All @@ -13,7 +13,7 @@ impl<'a> File<'a, GritQueryContext> for GritFile {
fn absolute_path(
&self,
_files: &FileRegistry<'a, GritQueryContext>,
_language: &GritLanguage,
_language: &GritTargetLanguage,
) -> anyhow::Result<GritResolvedPattern> {
todo!()
}
Expand Down
29 changes: 25 additions & 4 deletions crates/biome_grit_patterns/src/grit_node.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
use grit_util::{AstCursor, AstNode as GritAstNode, CodeRange, Range};
use std::{borrow::Cow, str::Utf8Error};
use biome_grit_syntax::GritSyntaxNode;
use grit_util::{AstCursor, AstNode as GritAstNode, ByteRange, CodeRange};
use std::{borrow::Cow, ops::Deref, str::Utf8Error};

#[derive(Clone, Debug)]
pub(crate) struct GritNode;
pub struct GritNode(GritSyntaxNode);

impl Deref for GritNode {
type Target = GritSyntaxNode;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl From<GritSyntaxNode> for GritNode {
fn from(value: GritSyntaxNode) -> Self {
Self(value)
}
}

impl From<&GritSyntaxNode> for GritNode {
fn from(value: &GritSyntaxNode) -> Self {
Self(value.clone())
}
}

impl GritAstNode for GritNode {
fn ancestors(&self) -> impl Iterator<Item = Self> {
Expand Down Expand Up @@ -37,7 +58,7 @@ impl GritAstNode for GritNode {
todo!()
}

fn range(&self) -> Range {
fn byte_range(&self) -> ByteRange {
todo!()
}

Expand Down
74 changes: 74 additions & 0 deletions crates/biome_grit_patterns/src/grit_query.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use crate::diagnostics::CompilerDiagnostic;
use crate::grit_context::{GritExecContext, GritQueryContext};
use crate::grit_target_language::GritTargetLanguage;
use crate::pattern_compiler::PatternCompiler;
use crate::pattern_compiler::{
compilation_context::CompilationContext, compilation_context::NodeCompilationContext,
};
use crate::resolved_pattern::GritResolvedPattern;
use crate::variables::{VarRegistry, VariableLocations};
use crate::CompileError;
use anyhow::Result;
use biome_grit_syntax::{GritRoot, GritRootExt};
use grit_pattern_matcher::pattern::{Matcher, Pattern, State};
use std::collections::BTreeMap;

/// Represents a top-level Grit query.
///
/// Grit queries provide the
pub struct GritQuery {
pub(crate) pattern: Pattern<GritQueryContext>,

/// Diagnostics discovered during compilation of the query.
diagnostics: Vec<CompilerDiagnostic>,

/// All variables discovered during query compilation.
locations: VariableLocations,
}

impl GritQuery {
pub fn execute(&self) -> Result<bool> {
let var_registry = VarRegistry::from_locations(&self.locations);

let binding = GritResolvedPattern;
let context = GritExecContext;
let mut state = State::new(var_registry.into(), Vec::new());
let mut logs = Vec::new().into();

self.pattern
.execute(&binding, &mut state, &context, &mut logs)
}

pub fn from_node(root: GritRoot, lang: GritTargetLanguage) -> Result<Self, CompileError> {
let context = CompilationContext::new_anonymous(lang);

let mut vars_array = Vec::new();
let mut global_vars = BTreeMap::new();
let mut diagnostics = Vec::new();

// We're not in a local scope yet, so this map is kinda useless.
// It's just there because all node compilers expect one.
let mut vars = BTreeMap::new();

let mut node_context = NodeCompilationContext::new(
&context,
&mut vars,
&mut vars_array,
&mut global_vars,
&mut diagnostics,
);

let pattern = PatternCompiler::from_node(
&root.pattern().ok_or(CompileError::MissingPattern)?,
&mut node_context,
)?;

let locations = VariableLocations::new(vars_array);

Ok(Self {
pattern,
diagnostics,
locations,
})
}
}
Loading

0 comments on commit 26a94cc

Please sign in to comment.