Skip to content

Commit 7e1e704

Browse files
committed
Merge branch 'master' into tf/bump-lsp-version
* master: fix: adding proving key initialization (#3322) chore(fmt): don't lose line breaks between comments (#3505) feat: Add LSP command to profile opcodes in vscode (#3496)
2 parents 07cee17 + 3383740 commit 7e1e704

File tree

29 files changed

+451
-133
lines changed

29 files changed

+451
-133
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/noirc_errors/src/debug_info.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub struct DebugInfo {
2222

2323
/// Holds OpCodes Counts for Acir and Brillig Opcodes
2424
/// To be printed with `nargo info --profile-info`
25+
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
2526
pub struct OpCodesCount {
2627
pub acir_size: usize,
2728
pub brillig_size: usize,
@@ -51,12 +52,12 @@ impl DebugInfo {
5152
self.locations.get(loc).cloned()
5253
}
5354

54-
pub fn count_span_opcodes(&self) -> HashMap<&Location, OpCodesCount> {
55-
let mut accumulator: HashMap<&Location, Vec<&OpcodeLocation>> = HashMap::new();
55+
pub fn count_span_opcodes(&self) -> HashMap<Location, OpCodesCount> {
56+
let mut accumulator: HashMap<Location, Vec<&OpcodeLocation>> = HashMap::new();
5657

5758
for (opcode_location, locations) in self.locations.iter() {
5859
for location in locations.iter() {
59-
let opcodes = accumulator.entry(location).or_insert(Vec::new());
60+
let opcodes = accumulator.entry(*location).or_insert(Vec::new());
6061
opcodes.push(opcode_location);
6162
}
6263
}

compiler/noirc_frontend/src/lexer/lexer.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub struct Lexer<'a> {
1616
position: Position,
1717
done: bool,
1818
skip_comments: bool,
19+
skip_whitespaces: bool,
1920
}
2021

2122
pub type SpannedTokenResult = Result<SpannedToken, LexerErrorKind>;
@@ -37,14 +38,25 @@ impl<'a> Lexer<'a> {
3738
}
3839

3940
pub fn new(source: &'a str) -> Self {
40-
Lexer { chars: source.char_indices(), position: 0, done: false, skip_comments: true }
41+
Lexer {
42+
chars: source.char_indices(),
43+
position: 0,
44+
done: false,
45+
skip_comments: true,
46+
skip_whitespaces: true,
47+
}
4148
}
4249

4350
pub fn skip_comments(mut self, flag: bool) -> Self {
4451
self.skip_comments = flag;
4552
self
4653
}
4754

55+
pub fn skip_whitespaces(mut self, flag: bool) -> Self {
56+
self.skip_whitespaces = flag;
57+
self
58+
}
59+
4860
/// Iterates the cursor and returns the char at the new cursor position
4961
fn next_char(&mut self) -> Option<char> {
5062
let (position, ch) = self.chars.next()?;
@@ -82,9 +94,13 @@ impl<'a> Lexer<'a> {
8294

8395
fn next_token(&mut self) -> SpannedTokenResult {
8496
match self.next_char() {
85-
Some(x) if { x.is_whitespace() } => {
86-
self.eat_whitespace();
87-
self.next_token()
97+
Some(x) if x.is_whitespace() => {
98+
let spanned = self.eat_whitespace(x);
99+
if self.skip_whitespaces {
100+
self.next_token()
101+
} else {
102+
Ok(spanned)
103+
}
88104
}
89105
Some('<') => self.glue(Token::Less),
90106
Some('>') => self.glue(Token::Greater),
@@ -454,8 +470,10 @@ impl<'a> Lexer<'a> {
454470
}
455471

456472
/// Skips white space. They are not significant in the source language
457-
fn eat_whitespace(&mut self) {
458-
self.eat_while(None, |ch| ch.is_whitespace());
473+
fn eat_whitespace(&mut self, initial_char: char) -> SpannedToken {
474+
let start = self.position;
475+
let whitespace = self.eat_while(initial_char.into(), |ch| ch.is_whitespace());
476+
SpannedToken::new(Token::Whitespace(whitespace), Span::inclusive(start, self.position))
459477
}
460478
}
461479

compiler/noirc_frontend/src/lexer/token.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ pub enum Token {
8888
#[allow(clippy::upper_case_acronyms)]
8989
EOF,
9090

91+
Whitespace(String),
92+
9193
/// An invalid character is one that is not in noir's language or grammar.
9294
///
9395
/// We don't report invalid tokens in the source as errors until parsing to
@@ -194,6 +196,7 @@ impl fmt::Display for Token {
194196
Token::Bang => write!(f, "!"),
195197
Token::EOF => write!(f, "end of input"),
196198
Token::Invalid(c) => write!(f, "{c}"),
199+
Token::Whitespace(ref s) => write!(f, "{s}"),
197200
}
198201
}
199202
}

tooling/lsp/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ serde_json.workspace = true
2323
tower.workspace = true
2424
cfg-if.workspace = true
2525
async-lsp = { workspace = true, features = ["omni-trait"] }
26+
serde_with = "3.2.0"
27+
fm.workspace = true
2628

2729
[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dependencies]
2830
wasm-bindgen.workspace = true

tooling/lsp/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ use notifications::{
2626
on_did_open_text_document, on_did_save_text_document, on_exit, on_initialized,
2727
};
2828
use requests::{
29-
on_code_lens_request, on_initialize, on_shutdown, on_test_run_request, on_tests_request,
29+
on_code_lens_request, on_initialize, on_profile_run_request, on_shutdown, on_test_run_request,
30+
on_tests_request,
3031
};
3132
use serde_json::Value as JsonValue;
3233
use tower::Service;
@@ -66,6 +67,7 @@ impl NargoLspService {
6667
.request::<request::CodeLens, _>(on_code_lens_request)
6768
.request::<request::NargoTests, _>(on_tests_request)
6869
.request::<request::NargoTestRun, _>(on_test_run_request)
70+
.request::<request::NargoProfileRun, _>(on_profile_run_request)
6971
.notification::<notification::Initialized>(on_initialized)
7072
.notification::<notification::DidChangeConfiguration>(on_did_change_configuration)
7173
.notification::<notification::DidOpenTextDocument>(on_did_open_text_document)

tooling/lsp/src/requests/code_lens_request.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ const INFO_CODELENS_TITLE: &str = "Info";
2323
const EXECUTE_COMMAND: &str = "nargo.execute";
2424
const EXECUTE_CODELENS_TITLE: &str = "Execute";
2525

26+
const PROFILE_COMMAND: &str = "nargo.profile";
27+
const PROFILE_CODELENS_TITLE: &str = "Profile";
28+
2629
fn with_arrow(title: &str) -> String {
2730
format!("{ARROW} {title}")
2831
}
@@ -163,6 +166,16 @@ fn on_code_lens_request_inner(
163166
let execute_lens = CodeLens { range, command: Some(execute_command), data: None };
164167

165168
lenses.push(execute_lens);
169+
170+
let profile_command = Command {
171+
title: PROFILE_CODELENS_TITLE.to_string(),
172+
command: PROFILE_COMMAND.into(),
173+
arguments: Some(package_selection_args(&workspace, package)),
174+
};
175+
176+
let profile_lens = CodeLens { range, command: Some(profile_command), data: None };
177+
178+
lenses.push(profile_lens);
166179
}
167180
}
168181

@@ -200,6 +213,16 @@ fn on_code_lens_request_inner(
200213
let info_lens = CodeLens { range, command: Some(info_command), data: None };
201214

202215
lenses.push(info_lens);
216+
217+
let profile_command = Command {
218+
title: PROFILE_CODELENS_TITLE.to_string(),
219+
command: PROFILE_COMMAND.into(),
220+
arguments: Some(package_selection_args(&workspace, package)),
221+
};
222+
223+
let profile_lens = CodeLens { range, command: Some(profile_command), data: None };
224+
225+
lenses.push(profile_lens);
203226
}
204227
}
205228
}

tooling/lsp/src/requests/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ use crate::{
1919
// and params passed in.
2020

2121
mod code_lens_request;
22+
mod profile_run;
2223
mod test_run;
2324
mod tests;
2425

2526
pub(crate) use {
26-
code_lens_request::on_code_lens_request, test_run::on_test_run_request, tests::on_tests_request,
27+
code_lens_request::on_code_lens_request, profile_run::on_profile_run_request,
28+
test_run::on_test_run_request, tests::on_tests_request,
2729
};
2830

2931
pub(crate) fn on_initialize(
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use std::{
2+
collections::{BTreeMap, HashMap},
3+
future::{self, Future},
4+
};
5+
6+
use acvm::{acir::circuit::Opcode, Language};
7+
use async_lsp::{ErrorCode, ResponseError};
8+
use nargo::artifacts::debug::DebugArtifact;
9+
use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection};
10+
use noirc_driver::{CompileOptions, DebugFile, NOIR_ARTIFACT_VERSION_STRING};
11+
use noirc_errors::{debug_info::OpCodesCount, Location};
12+
13+
use crate::{
14+
types::{NargoProfileRunParams, NargoProfileRunResult},
15+
LspState,
16+
};
17+
use fm::FileId;
18+
19+
pub(crate) fn on_profile_run_request(
20+
state: &mut LspState,
21+
params: NargoProfileRunParams,
22+
) -> impl Future<Output = Result<NargoProfileRunResult, ResponseError>> {
23+
future::ready(on_profile_run_request_inner(state, params))
24+
}
25+
26+
fn on_profile_run_request_inner(
27+
state: &LspState,
28+
params: NargoProfileRunParams,
29+
) -> Result<NargoProfileRunResult, ResponseError> {
30+
let root_path = state.root_path.as_deref().ok_or_else(|| {
31+
ResponseError::new(ErrorCode::REQUEST_FAILED, "Could not find project root")
32+
})?;
33+
34+
let toml_path = find_package_manifest(root_path, root_path).map_err(|err| {
35+
// If we cannot find a manifest, we can't run the test
36+
ResponseError::new(ErrorCode::REQUEST_FAILED, err)
37+
})?;
38+
39+
let crate_name = params.package;
40+
41+
let workspace = resolve_workspace_from_toml(
42+
&toml_path,
43+
PackageSelection::DefaultOrAll,
44+
Some(NOIR_ARTIFACT_VERSION_STRING.to_string()),
45+
)
46+
.map_err(|err| {
47+
// If we found a manifest, but the workspace is invalid, we raise an error about it
48+
ResponseError::new(ErrorCode::REQUEST_FAILED, err)
49+
})?;
50+
51+
// Since we filtered on crate name, this should be the only item in the iterator
52+
match workspace.into_iter().next() {
53+
Some(_package) => {
54+
let (binary_packages, contract_packages): (Vec<_>, Vec<_>) = workspace
55+
.into_iter()
56+
.filter(|package| !package.is_library())
57+
.cloned()
58+
.partition(|package| package.is_binary());
59+
60+
// # TODO(#3504): Consider how to incorporate Backend relevant information in wider context.
61+
let is_opcode_supported = |_opcode: &Opcode| true;
62+
let np_language = Language::PLONKCSat { width: 3 };
63+
64+
let (compiled_programs, compiled_contracts) = nargo::ops::compile_workspace(
65+
&workspace,
66+
&binary_packages,
67+
&contract_packages,
68+
np_language,
69+
is_opcode_supported,
70+
&CompileOptions::default(),
71+
)
72+
.map_err(|err| ResponseError::new(ErrorCode::REQUEST_FAILED, err))?;
73+
74+
let mut opcodes_counts: HashMap<Location, OpCodesCount> = HashMap::new();
75+
let mut file_map: BTreeMap<FileId, DebugFile> = BTreeMap::new();
76+
for compiled_program in &compiled_programs {
77+
let span_opcodes = compiled_program.debug.count_span_opcodes();
78+
let debug_artifact: DebugArtifact = compiled_program.clone().into();
79+
opcodes_counts.extend(span_opcodes);
80+
file_map.extend(debug_artifact.file_map);
81+
}
82+
83+
for compiled_contract in &compiled_contracts {
84+
let functions = &compiled_contract.functions;
85+
let debug_artifact: DebugArtifact = compiled_contract.clone().into();
86+
file_map.extend(debug_artifact.file_map);
87+
for contract_function in functions {
88+
let span_opcodes = contract_function.debug.count_span_opcodes();
89+
opcodes_counts.extend(span_opcodes);
90+
}
91+
}
92+
93+
let result = NargoProfileRunResult { file_map, opcodes_counts };
94+
95+
Ok(result)
96+
}
97+
None => Err(ResponseError::new(
98+
ErrorCode::REQUEST_FAILED,
99+
format!("Could not locate package named: {crate_name}"),
100+
)),
101+
}
102+
}

tooling/lsp/src/types.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1+
use fm::FileId;
2+
use noirc_driver::DebugFile;
3+
use noirc_errors::{debug_info::OpCodesCount, Location};
14
use noirc_frontend::graph::CrateName;
25
use serde::{Deserialize, Serialize};
6+
use serde_with::serde_as;
7+
use std::collections::{BTreeMap, HashMap};
38

49
// Re-providing lsp_types that we don't need to override
510
pub(crate) use lsp_types::{
@@ -14,8 +19,8 @@ pub(crate) mod request {
1419
use lsp_types::{request::Request, InitializeParams};
1520

1621
use super::{
17-
InitializeResult, NargoTestRunParams, NargoTestRunResult, NargoTestsParams,
18-
NargoTestsResult,
22+
InitializeResult, NargoProfileRunParams, NargoProfileRunResult, NargoTestRunParams,
23+
NargoTestRunResult, NargoTestsParams, NargoTestsResult,
1924
};
2025

2126
// Re-providing lsp_types that we don't need to override
@@ -44,6 +49,14 @@ pub(crate) mod request {
4449
type Result = NargoTestsResult;
4550
const METHOD: &'static str = "nargo/tests";
4651
}
52+
53+
#[derive(Debug)]
54+
pub(crate) struct NargoProfileRun;
55+
impl Request for NargoProfileRun {
56+
type Params = NargoProfileRunParams;
57+
type Result = NargoProfileRunResult;
58+
const METHOD: &'static str = "nargo/profile/run";
59+
}
4760
}
4861

4962
pub(crate) mod notification {
@@ -186,5 +199,16 @@ pub(crate) struct NargoTestRunResult {
186199
pub(crate) result: String,
187200
pub(crate) message: Option<String>,
188201
}
202+
#[derive(Debug, Serialize, Deserialize)]
203+
pub(crate) struct NargoProfileRunParams {
204+
pub(crate) package: CrateName,
205+
}
206+
#[serde_as]
207+
#[derive(Debug, Serialize, Deserialize)]
208+
pub(crate) struct NargoProfileRunResult {
209+
pub(crate) file_map: BTreeMap<FileId, DebugFile>,
210+
#[serde_as(as = "Vec<(_, _)>")]
211+
pub(crate) opcodes_counts: HashMap<Location, OpCodesCount>,
212+
}
189213

190214
pub(crate) type CodeLensResult = Option<Vec<CodeLens>>;

0 commit comments

Comments
 (0)