Skip to content

Commit

Permalink
Jump to definition of signal and variable (#30)
Browse files Browse the repository at this point in the history
* jump to signal

* only allow jump to same template for signal

* jump to var decl
  • Loading branch information
vuvoth authored Feb 19, 2024
1 parent 971b332 commit 0765ffd
Show file tree
Hide file tree
Showing 14 changed files with 243 additions and 145 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ members = ["crates/*", "xtask/"]
parser = {path = "./crates/parser", version = "0.1.0"}
vfs = {path = "./crates/vfs", version = "0.1.0"}
syntax = {path = './crates/syntax', version = "0.1.0"}

circom-lsp = {path = './crates/lsp', version = "*"}
[workspace.package]
rust-version = "1.71"
2 changes: 2 additions & 0 deletions crates/lsp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ log = "0.4.18"

lsp-server = "0.7.6"

rowan = "0.15.15"

lsp-types = {version = "0.94.1", features = ["proposed"]}
parser.workspace = true
vfs.workspace = true
Expand Down
22 changes: 14 additions & 8 deletions crates/lsp/src/global_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ use parser::{
ast::{AstCircomProgram, AstNode},
parser::Parser,
syntax_node::SyntaxNode,
utils::FileUtils,
};

use crate::handler::goto_definition::{lookup_definition, lookup_token_at_postion};
use crate::handler::{
goto_definition::{lookup_definition, lookup_token_at_postion},
lsp_utils::FileUtils,
};

#[derive(Debug)]
pub struct TextDocument {
Expand Down Expand Up @@ -57,16 +59,20 @@ impl GlobalState {
let ast = self.ast_map.get(&uri.to_string()).unwrap();
let file = self.file_map.get(&uri.to_string()).unwrap();

let mut result = Some(GotoDefinitionResponse::Array(Vec::new()));
let mut ranges = Vec::new();

eprintln!("{:?}", params.text_document_position_params.position);
if let Some(token) =
lookup_token_at_postion(&file, &ast, params.text_document_position_params.position)
{
if let Some(range) = lookup_definition(&file, &ast, token) {
result = Some(GotoDefinitionResponse::Scalar(Location::new(uri, range)));
};
}
ranges = lookup_definition(&file, &ast, token);
};

let locations = ranges
.into_iter()
.map(|range| Location::new(uri.clone(), range))
.collect();

let result = Some(GotoDefinitionResponse::Array(locations));

let result = serde_json::to_value(result).unwrap();

Expand Down
133 changes: 125 additions & 8 deletions crates/lsp/src/handler/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use parser::{
ast::{AstCircomProgram, AstNode},
syntax_node::SyntaxToken,
token_kind::TokenKind,
utils::FileUtils,
};

use super::lsp_utils::FileUtils;

pub fn lookup_token_at_postion(
file: &FileUtils,
ast: &AstCircomProgram,
Expand All @@ -27,18 +28,134 @@ pub fn lookup_definition(
file: &FileUtils,
ast: &AstCircomProgram,
token: SyntaxToken,
) -> Option<Range> {
) -> Vec<Range> {
let template_list = ast.template_list();

let mut result = Vec::new();

for template in template_list {
let template_name = template.template_name().unwrap();
if template_name.name().unwrap().syntax().text() == token.text() {
let range = Some(Range {
start: file.position(template.syntax().text_range().start()),
end: file.position(template.syntax().text_range().end()),
});
return range;
let range = file.range(template.syntax());
result.push(range);
}

if !template
.syntax()
.text_range()
.contains_range(token.text_range())
{
continue;
}

if let Some(fn_body) = template.func_body() {
if let Some(statements) = fn_body.statement_list() {
for signal in statements.input_signals() {
if let Some(name) = signal.signal_name() {
if name.syntax().text() == token.text() {
result.push(file.range(signal.syntax()));
}
}
}

for signal in statements.output_signals() {
if let Some(name) = signal.signal_name() {
if name.syntax().text() == token.text() {
result.push(file.range(signal.syntax()));
}
}
}

for signal in statements.internal_signals() {
if let Some(name) = signal.signal_name() {
if name.syntax().text() == token.text() {
result.push(file.range(signal.syntax()));
}
}
}

for var in statements.variables() {
if let Some(name) = var.variable_name() {
if name.syntax().text() == token.text() {
result.push(file.range(var.syntax()));
}
}
}
}
}
}
result
}

#[cfg(test)]
mod tests {
use parser::{ast::AstCircomProgram, parser::Parser, syntax_node::SyntaxNode};
use rowan::ast::AstNode;

use crate::handler::lsp_utils::FileUtils;

#[test]
fn goto_decl_test() {
let source: String = r#"
pragma circom 2.0.0;
template X() {
signal x = 10;
signal input x = 10;
component x = Multiplier2();
component y = X();
component y = Multiplier2();
component z = Multiplier2();
}
template M() {
component h = X();
component k = Multiplier2();
test
}
template Multiplier2 () {
template m = M();
// hello world
signal input a;
signal input b;
signal output c;
component y = X();
mintlkrekerjke;
component e = Y();
component z = Y();
component h = Y();
signal output d;
c <== a * b;
}
template Y() {
component y = X();
component a = X();
}
"#
.to_string();

let _file = FileUtils::create(&source);

let green_node = Parser::parse_circom(&source);
let syntax_node = SyntaxNode::new_root(green_node.clone());
if let Some(program_ast) = AstCircomProgram::cast(syntax_node) {
for template in program_ast.template_list() {
println!("{template:?}");
}

let inputs = program_ast.template_list()[0]
.func_body()
.unwrap()
.statement_list()
.unwrap()
.input_signals();
let signal_name = inputs[0].signal_name().unwrap();

let tmp = signal_name.syntax().text_range().start();

println!("{:?}", program_ast.syntax().token_at_offset(tmp));
}
}
None
}
15 changes: 12 additions & 3 deletions crates/parser/src/utils.rs → crates/lsp/src/handler/lsp_utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use lsp_types::Position;
use lsp_types::{Position, Range};
use parser::syntax_node::SyntaxNode;
use rowan::TextSize;

pub struct FileId(u32);
Expand All @@ -13,7 +14,7 @@ impl FileUtils {
Self::new(FileId(0), content)
}

pub fn new(file_id: FileId, content: &str) -> Self {
pub(super) fn new(file_id: FileId, content: &str) -> Self {
let mut file_utils = Self {
file_id,
end_line_vec: Vec::new(),
Expand Down Expand Up @@ -50,13 +51,21 @@ impl FileUtils {
},
)
}

pub fn range(&self, syntax: &SyntaxNode) -> Range {
let syntax_range = syntax.text_range();
Range {
start: self.position(syntax_range.start()),
end: self.position(syntax_range.end()),
}
}
}

#[cfg(test)]
mod tests {
use lsp_types::Position;

use crate::utils::{FileId, FileUtils};
use crate::handler::lsp_utils::{FileId, FileUtils};

#[test]
fn off_set_test() {
Expand Down
2 changes: 2 additions & 0 deletions crates/lsp/src/handler/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pub mod goto_definition;

pub mod lsp_utils;
58 changes: 57 additions & 1 deletion crates/parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,74 @@ macro_rules! ast_node {
};
}

ast_node!(AstSignalHeader, SignalHeader);
ast_node!(AstInputSignalDecl, InputSignalDecl);
ast_node!(AstOutputSignalDecl, OutputSignalDecl);
ast_node!(AstSignalDecl, SignalDecl);

impl AstInputSignalDecl {
pub fn signal_name(&self) -> Option<AstIdentifier> {
support::child(self.syntax())
}
}

impl AstOutputSignalDecl {
pub fn signal_name(&self) -> Option<AstIdentifier> {
support::child(self.syntax())
}
}
impl AstSignalDecl {
pub fn signal_name(&self) -> Option<AstIdentifier> {
support::child(self.syntax())
}
}
ast_node!(AstVarDecl, VarDecl);

impl AstVarDecl {
pub fn variable_name(&self) -> Option<AstIdentifier> {
support::child(self.syntax())
}
}
ast_node!(AstStatement, Statement);

ast_node!(AstStatementList, StatementList);

impl AstStatementList {
pub fn statement_list(&self) -> AstChildren<AstStatement> {
support::children(self.syntax())
}

pub fn input_signals(&self) -> Vec<AstInputSignalDecl> {
self.syntax()
.children()
.filter_map(AstInputSignalDecl::cast)
.collect()
}

pub fn output_signals(&self) -> Vec<AstOutputSignalDecl> {
self.syntax()
.children()
.filter_map(AstOutputSignalDecl::cast)
.collect()
}

pub fn internal_signals(&self) -> Vec<AstSignalDecl> {
self.syntax()
.children()
.filter_map(AstSignalDecl::cast)
.collect()
}
pub fn variables(&self) -> Vec<AstVarDecl> {
self.syntax()
.children()
.filter_map(AstVarDecl::cast)
.collect()
}
}

ast_node!(AstBlock, Block);
impl AstBlock {
pub fn statement(&self) -> Option<AstStatementList> {
pub fn statement_list(&self) -> Option<AstStatementList> {
support::child::<AstStatementList>(self.syntax())
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/parser/src/grammar/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ mod tests {
let syntax_node = SyntaxNode::new_root(green_node);

if let Some(ast_block) = AstBlock::cast(syntax_node) {
println!("{:?}", ast_block.statement().unwrap().syntax().kind());
println!("{:?}", ast_block.statement_list().unwrap().syntax().kind());
}
}
}
Loading

0 comments on commit 0765ffd

Please sign in to comment.