Skip to content

Commit

Permalink
Merge pull request #135 from tree-sitter/inherited-scoped-variables
Browse files Browse the repository at this point in the history
Inherited scoped variables
  • Loading branch information
hendrikvanantwerpen authored Jun 1, 2023
2 parents c363c83 + d2af0e1 commit a037d0c
Show file tree
Hide file tree
Showing 14 changed files with 278 additions and 34 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## v0.10.3 -- 2023-06-01

### DSL

#### Added

- Scoped variables can be inherited by child nodes by specifying `inherit .var_name` as part of the source. Using `@node.var_name` will either use the value set on the node itself, or otherwise the one set on the closest enclosing node.

## v0.10.2 -- 2023-05-25

### Library
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tree-sitter-graph"
version = "0.10.2"
version = "0.10.3"
description = "Construct graphs from parsed source code"
homepage = "https://github.com/tree-sitter/tree-sitter-graph/"
repository = "https://github.com/tree-sitter/tree-sitter-graph/"
Expand Down
4 changes: 4 additions & 0 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use regex::Regex;
use std::collections::HashMap;
use std::collections::HashSet;
use std::fmt;
use tree_sitter::CaptureQuantifier;
use tree_sitter::Language;
Expand All @@ -24,6 +25,8 @@ pub struct File {
pub language: Language,
/// The expected global variables used in this file
pub globals: Vec<Global>,
/// The scoped variables that are inherited by child nodes
pub inherited_variables: HashSet<Identifier>,
/// The combined query of all stanzas in the file
pub query: Option<Query>,
/// The list of stanzas in the file
Expand All @@ -37,6 +40,7 @@ impl File {
File {
language,
globals: Vec::new(),
inherited_variables: HashSet::new(),
query: None,
stanzas: Vec::new(),
shorthands: AttributeShorthands::new(),
Expand Down
14 changes: 14 additions & 0 deletions src/execution/lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod values;
use log::{debug, trace};

use std::collections::HashMap;
use std::collections::HashSet;

use tree_sitter::QueryCursor;
use tree_sitter::QueryMatch;
Expand Down Expand Up @@ -81,6 +82,7 @@ impl ast::File {
&mut lazy_graph,
&mut function_parameters,
&mut prev_element_debug_info,
&self.inherited_variables,
&self.shorthands,
cancellation_flag,
)
Expand All @@ -92,6 +94,7 @@ impl ast::File {
functions: config.functions,
store: &store,
scoped_store: &scoped_store,
inherited_variables: &self.inherited_variables,
function_parameters: &mut function_parameters,
prev_element_debug_info: &mut prev_element_debug_info,
cancellation_flag,
Expand Down Expand Up @@ -141,6 +144,7 @@ struct ExecutionContext<'a, 'c, 'g, 'tree> {
function_parameters: &'a mut Vec<graph::Value>, // re-usable buffer to reduce memory allocations
prev_element_debug_info: &'a mut HashMap<GraphElementKey, DebugInfo>,
error_context: StatementContext,
inherited_variables: &'a HashSet<Identifier>,
shorthands: &'a ast::AttributeShorthands,
cancellation_flag: &'a dyn CancellationFlag,
}
Expand All @@ -152,6 +156,7 @@ pub(self) struct EvaluationContext<'a, 'tree> {
pub functions: &'a Functions,
pub store: &'a LazyStore,
pub scoped_store: &'a LazyScopedVariables,
pub inherited_variables: &'a HashSet<Identifier>,
pub function_parameters: &'a mut Vec<graph::Value>, // re-usable buffer to reduce memory allocations
pub prev_element_debug_info: &'a mut HashMap<GraphElementKey, DebugInfo>,
pub cancellation_flag: &'a dyn CancellationFlag,
Expand All @@ -177,6 +182,7 @@ impl ast::Stanza {
lazy_graph: &mut Vec<LazyStatement>,
function_parameters: &mut Vec<graph::Value>,
prev_element_debug_info: &mut HashMap<GraphElementKey, DebugInfo>,
inherited_variables: &HashSet<Identifier>,
shorthands: &ast::AttributeShorthands,
cancellation_flag: &dyn CancellationFlag,
) -> Result<(), ExecutionError> {
Expand All @@ -203,6 +209,7 @@ impl ast::Stanza {
function_parameters,
prev_element_debug_info,
error_context,
inherited_variables,
shorthands,
cancellation_flag,
};
Expand Down Expand Up @@ -366,6 +373,7 @@ impl ast::Scan {
function_parameters: exec.function_parameters,
prev_element_debug_info: exec.prev_element_debug_info,
error_context: exec.error_context.clone(),
inherited_variables: exec.inherited_variables,
shorthands: exec.shorthands,
cancellation_flag: exec.cancellation_flag,
};
Expand Down Expand Up @@ -431,6 +439,7 @@ impl ast::If {
function_parameters: exec.function_parameters,
prev_element_debug_info: exec.prev_element_debug_info,
error_context: exec.error_context.clone(),
inherited_variables: exec.inherited_variables,
shorthands: exec.shorthands,
cancellation_flag: exec.cancellation_flag,
};
Expand Down Expand Up @@ -477,6 +486,7 @@ impl ast::ForIn {
function_parameters: exec.function_parameters,
prev_element_debug_info: exec.prev_element_debug_info,
error_context: exec.error_context.clone(),
inherited_variables: exec.inherited_variables,
shorthands: exec.shorthands,
cancellation_flag: exec.cancellation_flag,
};
Expand Down Expand Up @@ -520,6 +530,7 @@ impl ast::Expression {
functions: exec.config.functions,
store: exec.store,
scoped_store: exec.scoped_store,
inherited_variables: exec.inherited_variables,
function_parameters: exec.function_parameters,
prev_element_debug_info: exec.prev_element_debug_info,
cancellation_flag: exec.cancellation_flag,
Expand Down Expand Up @@ -569,6 +580,7 @@ impl ast::ListComprehension {
function_parameters: exec.function_parameters,
prev_element_debug_info: exec.prev_element_debug_info,
error_context: exec.error_context.clone(),
inherited_variables: exec.inherited_variables,
shorthands: exec.shorthands,
cancellation_flag: exec.cancellation_flag,
};
Expand Down Expand Up @@ -611,6 +623,7 @@ impl ast::SetComprehension {
function_parameters: exec.function_parameters,
prev_element_debug_info: exec.prev_element_debug_info,
error_context: exec.error_context.clone(),
inherited_variables: exec.inherited_variables,
shorthands: exec.shorthands,
cancellation_flag: exec.cancellation_flag,
};
Expand Down Expand Up @@ -825,6 +838,7 @@ impl ast::AttributeShorthand {
function_parameters: exec.function_parameters,
prev_element_debug_info: exec.prev_element_debug_info,
error_context: exec.error_context.clone(),
inherited_variables: exec.inherited_variables,
shorthands: exec.shorthands,
cancellation_flag: exec.cancellation_flag,
};
Expand Down
36 changes: 25 additions & 11 deletions src/execution/lazy/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::execution::error::ExecutionError;
use crate::execution::error::ResultWithExecutionError;
use crate::execution::error::StatementContext;
use crate::graph;
use crate::graph::SyntaxNodeID;
use crate::graph::SyntaxNodeRef;
use crate::Identifier;

Expand Down Expand Up @@ -151,15 +152,28 @@ impl LazyScopedVariables {
};
let values = cell.replace(ScopedValues::Forcing);
let map = self.force(name, values, exec)?;
let result = map
.get(&scope)
.ok_or(ExecutionError::UndefinedScopedVariable(format!(
"{}.{}",
scope, name,
)))?
.clone();

let mut result = None;

if let Some(value) = map.get(&scope.index) {
result = Some(value.clone());
} else if exec.inherited_variables.contains(name) {
let mut parent = exec
.graph
.syntax_nodes
.get(&scope.index)
.and_then(|n| n.parent());
while let Some(scope) = parent {
if let Some(value) = map.get(&(scope.id() as u32)) {
result = Some(value.clone());
break;
}
parent = scope.parent();
}
}

cell.replace(ScopedValues::Forced(map));
Ok(result)
result.ok_or_else(|| ExecutionError::UndefinedScopedVariable(format!("{}.{}", scope, name)))
}

pub(super) fn evaluate_all(&self, exec: &mut EvaluationContext) -> Result<(), ExecutionError> {
Expand All @@ -176,7 +190,7 @@ impl LazyScopedVariables {
name: &Identifier,
values: ScopedValues,
exec: &mut EvaluationContext,
) -> Result<HashMap<SyntaxNodeRef, LazyValue>, ExecutionError> {
) -> Result<HashMap<SyntaxNodeID, LazyValue>, ExecutionError> {
match values {
ScopedValues::Unforced(pairs) => {
let mut map = HashMap::new();
Expand All @@ -187,7 +201,7 @@ impl LazyScopedVariables {
.with_context(|| format!("Evaluating scope of variable _.{}", name,).into())
.with_context(|| debug_info.0.clone().into())?;
let prev_debug_info = debug_infos.insert(node, debug_info.clone());
match map.insert(node, value.clone()) {
match map.insert(node.index, value.clone()) {
Some(_) => {
return Err(ExecutionError::DuplicateVariable(format!(
"{}.{}",
Expand All @@ -211,7 +225,7 @@ impl LazyScopedVariables {
enum ScopedValues {
Unforced(Vec<(LazyValue, LazyValue, DebugInfo)>),
Forcing,
Forced(HashMap<SyntaxNodeRef, LazyValue>),
Forced(HashMap<SyntaxNodeID, LazyValue>),
}

impl ScopedValues {
Expand Down
Loading

0 comments on commit a037d0c

Please sign in to comment.