Skip to content

Commit

Permalink
Merge branch 'master' into tf/bump-lsp-version
Browse files Browse the repository at this point in the history
* 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)
  • Loading branch information
TomAFrench committed Nov 17, 2023
2 parents 07cee17 + 3383740 commit 7e1e704
Show file tree
Hide file tree
Showing 29 changed files with 451 additions and 133 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

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

7 changes: 4 additions & 3 deletions compiler/noirc_errors/src/debug_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub struct DebugInfo {

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

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

for (opcode_location, locations) in self.locations.iter() {
for location in locations.iter() {
let opcodes = accumulator.entry(location).or_insert(Vec::new());
let opcodes = accumulator.entry(*location).or_insert(Vec::new());
opcodes.push(opcode_location);
}
}
Expand Down
30 changes: 24 additions & 6 deletions compiler/noirc_frontend/src/lexer/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct Lexer<'a> {
position: Position,
done: bool,
skip_comments: bool,
skip_whitespaces: bool,

Check warning on line 19 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (whitespaces)
}

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

pub fn new(source: &'a str) -> Self {
Lexer { chars: source.char_indices(), position: 0, done: false, skip_comments: true }
Lexer {
chars: source.char_indices(),
position: 0,
done: false,
skip_comments: true,
skip_whitespaces: true,

Check warning on line 46 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (whitespaces)
}
}

pub fn skip_comments(mut self, flag: bool) -> Self {
self.skip_comments = flag;
self
}

pub fn skip_whitespaces(mut self, flag: bool) -> Self {

Check warning on line 55 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (whitespaces)
self.skip_whitespaces = flag;

Check warning on line 56 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (whitespaces)
self
}

/// Iterates the cursor and returns the char at the new cursor position
fn next_char(&mut self) -> Option<char> {
let (position, ch) = self.chars.next()?;
Expand Down Expand Up @@ -82,9 +94,13 @@ impl<'a> Lexer<'a> {

fn next_token(&mut self) -> SpannedTokenResult {
match self.next_char() {
Some(x) if { x.is_whitespace() } => {
self.eat_whitespace();
self.next_token()
Some(x) if x.is_whitespace() => {
let spanned = self.eat_whitespace(x);
if self.skip_whitespaces {

Check warning on line 99 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (whitespaces)
self.next_token()
} else {
Ok(spanned)
}
}
Some('<') => self.glue(Token::Less),
Some('>') => self.glue(Token::Greater),
Expand Down Expand Up @@ -454,8 +470,10 @@ impl<'a> Lexer<'a> {
}

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

Expand Down
3 changes: 3 additions & 0 deletions compiler/noirc_frontend/src/lexer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ pub enum Token {
#[allow(clippy::upper_case_acronyms)]
EOF,

Whitespace(String),

/// An invalid character is one that is not in noir's language or grammar.
///
/// We don't report invalid tokens in the source as errors until parsing to
Expand Down Expand Up @@ -194,6 +196,7 @@ impl fmt::Display for Token {
Token::Bang => write!(f, "!"),
Token::EOF => write!(f, "end of input"),
Token::Invalid(c) => write!(f, "{c}"),
Token::Whitespace(ref s) => write!(f, "{s}"),
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions tooling/lsp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ serde_json.workspace = true
tower.workspace = true
cfg-if.workspace = true
async-lsp = { workspace = true, features = ["omni-trait"] }
serde_with = "3.2.0"
fm.workspace = true

[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dependencies]
wasm-bindgen.workspace = true
Expand Down
4 changes: 3 additions & 1 deletion tooling/lsp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ use notifications::{
on_did_open_text_document, on_did_save_text_document, on_exit, on_initialized,
};
use requests::{
on_code_lens_request, on_initialize, on_shutdown, on_test_run_request, on_tests_request,
on_code_lens_request, on_initialize, on_profile_run_request, on_shutdown, on_test_run_request,
on_tests_request,
};
use serde_json::Value as JsonValue;
use tower::Service;
Expand Down Expand Up @@ -66,6 +67,7 @@ impl NargoLspService {
.request::<request::CodeLens, _>(on_code_lens_request)
.request::<request::NargoTests, _>(on_tests_request)
.request::<request::NargoTestRun, _>(on_test_run_request)
.request::<request::NargoProfileRun, _>(on_profile_run_request)
.notification::<notification::Initialized>(on_initialized)
.notification::<notification::DidChangeConfiguration>(on_did_change_configuration)
.notification::<notification::DidOpenTextDocument>(on_did_open_text_document)
Expand Down
23 changes: 23 additions & 0 deletions tooling/lsp/src/requests/code_lens_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const INFO_CODELENS_TITLE: &str = "Info";
const EXECUTE_COMMAND: &str = "nargo.execute";
const EXECUTE_CODELENS_TITLE: &str = "Execute";

const PROFILE_COMMAND: &str = "nargo.profile";
const PROFILE_CODELENS_TITLE: &str = "Profile";

fn with_arrow(title: &str) -> String {
format!("{ARROW} {title}")
}
Expand Down Expand Up @@ -163,6 +166,16 @@ fn on_code_lens_request_inner(
let execute_lens = CodeLens { range, command: Some(execute_command), data: None };

lenses.push(execute_lens);

let profile_command = Command {
title: PROFILE_CODELENS_TITLE.to_string(),
command: PROFILE_COMMAND.into(),
arguments: Some(package_selection_args(&workspace, package)),
};

let profile_lens = CodeLens { range, command: Some(profile_command), data: None };

lenses.push(profile_lens);
}
}

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

lenses.push(info_lens);

let profile_command = Command {
title: PROFILE_CODELENS_TITLE.to_string(),
command: PROFILE_COMMAND.into(),
arguments: Some(package_selection_args(&workspace, package)),
};

let profile_lens = CodeLens { range, command: Some(profile_command), data: None };

lenses.push(profile_lens);
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion tooling/lsp/src/requests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ use crate::{
// and params passed in.

mod code_lens_request;
mod profile_run;
mod test_run;
mod tests;

pub(crate) use {
code_lens_request::on_code_lens_request, test_run::on_test_run_request, tests::on_tests_request,
code_lens_request::on_code_lens_request, profile_run::on_profile_run_request,
test_run::on_test_run_request, tests::on_tests_request,
};

pub(crate) fn on_initialize(
Expand Down
102 changes: 102 additions & 0 deletions tooling/lsp/src/requests/profile_run.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use std::{
collections::{BTreeMap, HashMap},
future::{self, Future},
};

use acvm::{acir::circuit::Opcode, Language};
use async_lsp::{ErrorCode, ResponseError};
use nargo::artifacts::debug::DebugArtifact;
use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection};
use noirc_driver::{CompileOptions, DebugFile, NOIR_ARTIFACT_VERSION_STRING};
use noirc_errors::{debug_info::OpCodesCount, Location};

use crate::{
types::{NargoProfileRunParams, NargoProfileRunResult},
LspState,
};
use fm::FileId;

pub(crate) fn on_profile_run_request(
state: &mut LspState,
params: NargoProfileRunParams,
) -> impl Future<Output = Result<NargoProfileRunResult, ResponseError>> {
future::ready(on_profile_run_request_inner(state, params))
}

fn on_profile_run_request_inner(
state: &LspState,
params: NargoProfileRunParams,
) -> Result<NargoProfileRunResult, ResponseError> {
let root_path = state.root_path.as_deref().ok_or_else(|| {
ResponseError::new(ErrorCode::REQUEST_FAILED, "Could not find project root")
})?;

let toml_path = find_package_manifest(root_path, root_path).map_err(|err| {
// If we cannot find a manifest, we can't run the test
ResponseError::new(ErrorCode::REQUEST_FAILED, err)
})?;

let crate_name = params.package;

let workspace = resolve_workspace_from_toml(
&toml_path,
PackageSelection::DefaultOrAll,
Some(NOIR_ARTIFACT_VERSION_STRING.to_string()),
)
.map_err(|err| {
// If we found a manifest, but the workspace is invalid, we raise an error about it
ResponseError::new(ErrorCode::REQUEST_FAILED, err)
})?;

// Since we filtered on crate name, this should be the only item in the iterator
match workspace.into_iter().next() {
Some(_package) => {
let (binary_packages, contract_packages): (Vec<_>, Vec<_>) = workspace
.into_iter()
.filter(|package| !package.is_library())
.cloned()
.partition(|package| package.is_binary());

// # TODO(#3504): Consider how to incorporate Backend relevant information in wider context.
let is_opcode_supported = |_opcode: &Opcode| true;
let np_language = Language::PLONKCSat { width: 3 };

let (compiled_programs, compiled_contracts) = nargo::ops::compile_workspace(
&workspace,
&binary_packages,
&contract_packages,
np_language,
is_opcode_supported,
&CompileOptions::default(),
)
.map_err(|err| ResponseError::new(ErrorCode::REQUEST_FAILED, err))?;

let mut opcodes_counts: HashMap<Location, OpCodesCount> = HashMap::new();
let mut file_map: BTreeMap<FileId, DebugFile> = BTreeMap::new();
for compiled_program in &compiled_programs {
let span_opcodes = compiled_program.debug.count_span_opcodes();
let debug_artifact: DebugArtifact = compiled_program.clone().into();
opcodes_counts.extend(span_opcodes);
file_map.extend(debug_artifact.file_map);
}

for compiled_contract in &compiled_contracts {
let functions = &compiled_contract.functions;
let debug_artifact: DebugArtifact = compiled_contract.clone().into();
file_map.extend(debug_artifact.file_map);
for contract_function in functions {
let span_opcodes = contract_function.debug.count_span_opcodes();
opcodes_counts.extend(span_opcodes);
}
}

let result = NargoProfileRunResult { file_map, opcodes_counts };

Ok(result)
}
None => Err(ResponseError::new(
ErrorCode::REQUEST_FAILED,
format!("Could not locate package named: {crate_name}"),
)),
}
}
28 changes: 26 additions & 2 deletions tooling/lsp/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use fm::FileId;
use noirc_driver::DebugFile;
use noirc_errors::{debug_info::OpCodesCount, Location};
use noirc_frontend::graph::CrateName;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use std::collections::{BTreeMap, HashMap};

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

use super::{
InitializeResult, NargoTestRunParams, NargoTestRunResult, NargoTestsParams,
NargoTestsResult,
InitializeResult, NargoProfileRunParams, NargoProfileRunResult, NargoTestRunParams,
NargoTestRunResult, NargoTestsParams, NargoTestsResult,
};

// Re-providing lsp_types that we don't need to override
Expand Down Expand Up @@ -44,6 +49,14 @@ pub(crate) mod request {
type Result = NargoTestsResult;
const METHOD: &'static str = "nargo/tests";
}

#[derive(Debug)]
pub(crate) struct NargoProfileRun;
impl Request for NargoProfileRun {
type Params = NargoProfileRunParams;
type Result = NargoProfileRunResult;
const METHOD: &'static str = "nargo/profile/run";
}
}

pub(crate) mod notification {
Expand Down Expand Up @@ -186,5 +199,16 @@ pub(crate) struct NargoTestRunResult {
pub(crate) result: String,
pub(crate) message: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct NargoProfileRunParams {
pub(crate) package: CrateName,
}
#[serde_as]
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct NargoProfileRunResult {
pub(crate) file_map: BTreeMap<FileId, DebugFile>,
#[serde_as(as = "Vec<(_, _)>")]
pub(crate) opcodes_counts: HashMap<Location, OpCodesCount>,
}

pub(crate) type CodeLensResult = Option<Vec<CodeLens>>;
1 change: 1 addition & 0 deletions tooling/nargo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ iter-extended.workspace = true
serde.workspace = true
thiserror.workspace = true
codespan-reporting.workspace = true
rayon = "1.8.0"
Loading

0 comments on commit 7e1e704

Please sign in to comment.