Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replace panics with JS exceptions in npm package #489

Merged
merged 1 commit into from
Jun 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fifty-students-applaud.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"changelog": minor
---

replace panics with JS exceptions in npm package
1 change: 1 addition & 0 deletions Cargo.lock

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

19 changes: 8 additions & 11 deletions crates/codegen/syntax/src/rust_lib_code_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,18 @@ impl CodeGenerator {
"
{language_boilerplate_common}

#[derive(Debug)]
pub struct Language {{
pub(crate) version: Version,
{version_flag_declarations}
}}

#[derive(thiserror::Error, Debug)]
pub enum Error {{
#[error(\"Invalid {language_title} language version '{{0}}'.\")]
InvalidLanguageVersion(Version),
#[error(\"Unsupported {language_title} language version '{{0}}'.\")]
UnsupportedLanguageVersion(Version),
#[error(\"Production '{{0:?}}' is not valid in this version of {language_title}.\")]
InvalidProductionVersion(ProductionKind),
}}

impl Language {{
Expand All @@ -75,27 +78,21 @@ impl CodeGenerator {
version,
}})
}} else {{
Err(Error::InvalidLanguageVersion(version))
Err(Error::UnsupportedLanguageVersion(version))
}}
}}

pub fn version(&self) -> &Version {{
&self.version
}}

pub fn parse(&self, production_kind: ProductionKind, input: &str) -> ParseOutput {{
pub fn parse(&self, production_kind: ProductionKind, input: &str) -> Result<ParseOutput, Error> {{
let output = match production_kind {{
{scanner_invocations},
{parser_invocations},
}};

output.unwrap_or_else(|| {{
let message = format!(\"ProductionKind {{production_kind}} is not valid in this version of {language_title}\");
ParseOutput {{
parse_tree: None,
errors: vec![ParseError::new(Default::default(), message)]
}}
}})
output.ok_or_else(|| Error::InvalidProductionVersion(production_kind))
}}
}}
",
Expand Down
33 changes: 26 additions & 7 deletions crates/codegen/syntax/src/typescript_lib_code_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,38 @@ impl CodeGenerator {
{version_flag_declarations}
}}

#[derive(thiserror::Error, Debug)]
pub enum Error {{
// Shared with Rust
#[error(\"Unsupported {language_title} language version '{{0}}'.\")]
UnsupportedLanguageVersion(Version),
#[error(\"Production '{{0:?}}' is not valid in this version of {language_title}.\")]
InvalidProductionVersion(ProductionKind),

// TypeScript-specific
#[error(\"Invalid semantic version '{{0}}'.\")]
InvalidSemanticVersion(String),
}}

impl From<Error> for napi::Error {{
fn from(value: Error) -> Self {{
napi::Error::from_reason(value.to_string())
}}
}}

#[napi]
impl Language {{
#[napi(constructor)]
pub fn new(version: String) -> Self {{
pub fn new(version: String) -> Result<Self, napi::Error> {{
{versions_array}
let version = Version::parse(&version).unwrap();
let version = Version::parse(&version).map_err(|_| Error::InvalidSemanticVersion(version))?;
if VERSIONS.contains(&version.to_string().as_str()) {{
Self {{
Ok(Self {{
{version_flag_initializers},
version,
}}
}})
}} else {{
panic!(\"Invalid {language_title} language version: {{version}}\");
Err(Error::UnsupportedLanguageVersion(version).into())
}}
}}

Expand All @@ -83,12 +102,12 @@ impl CodeGenerator {
}}

#[napi]
pub fn parse(&self, production_kind: ProductionKind, input: String) -> ParseOutput {{
pub fn parse(&self, production_kind: ProductionKind, input: String) -> Result<ParseOutput, napi::Error> {{
let input = input.as_str();
match production_kind {{
{scanner_invocations},
{parser_invocations},
}}.expect(&format!(\"Production {{production_kind:?}} is not valid in this version of {language_title}\"))
}}.ok_or_else(|| Error::InvalidProductionVersion(production_kind).into())
}}
}}
",
Expand Down
4 changes: 2 additions & 2 deletions crates/codegen/syntax_templates/src/rust/parser_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use super::{
language::{render_error_report, TextPosition},
};

#[derive(PartialEq)]
#[derive(Debug, PartialEq)]
pub struct ParseOutput {
pub(crate) parse_tree: Option<Rc<cst::Node>>,
pub(crate) errors: Vec<ParseError>,
Expand All @@ -25,7 +25,7 @@ impl ParseOutput {
}
}

#[derive(PartialEq)]
#[derive(Debug, PartialEq)]
pub struct ParseError {
pub(crate) position: TextPosition,
pub(crate) expected: BTreeSet<String>,
Expand Down
25 changes: 12 additions & 13 deletions crates/solidity/outputs/cargo/crate/src/generated/language.rs

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

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

4 changes: 3 additions & 1 deletion crates/solidity/outputs/cargo/crate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ mod public_api {
* __SLANG_PUBLIC_API_SYNC__ (please keep in sync across all other instances)
*/

pub use crate::generated::language::Language;
pub mod language {
pub use crate::generated::language::{Error, Language};
}

pub mod syntax {
pub mod nodes {
Expand Down
24 changes: 10 additions & 14 deletions crates/solidity/outputs/cargo/crate/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::{fs, path::PathBuf};

use anyhow::Result;
use anyhow::{Context, Result};
use clap::{Parser as ClapParser, Subcommand};
use semver::Version;
use slang_solidity::{syntax::parser::ProductionKind, Language};
use slang_solidity::{language::Language, syntax::parser::ProductionKind};

mod _supress_library_dependencies_ {
// Below are dependencies used by the library `lib.rs`, but not here.
Expand Down Expand Up @@ -54,23 +54,19 @@ fn main() -> Result<()> {
};
}

fn execute_parse_command(file_path: String, version: Version, json: bool) -> Result<()> {
let input_file = &PathBuf::from(file_path).canonicalize()?;
let input = fs::read_to_string(input_file)?;
fn execute_parse_command(file_path_string: String, version: Version, json: bool) -> Result<()> {
let file_path = PathBuf::from(&file_path_string)
.canonicalize()
.with_context(|| format!("Failed to find file path: {file_path_string:?}"))?;

let input = fs::read_to_string(file_path)?;
let language = Language::new(version)?;
let output = language.parse(ProductionKind::SourceUnit, &input);
let output = language.parse(ProductionKind::SourceUnit, &input)?;

let errors = output.errors();
for error in errors {
eprintln!(
"{report}",
report = error.to_error_report(
input_file.to_str().unwrap(),
&input,
/* with_colour */ true,
)
);
let report = error.to_error_report(&file_path_string, &input, /* with_colour */ true);
eprintln!("{report}");
}

if json {
Expand Down
13 changes: 11 additions & 2 deletions crates/solidity/outputs/cargo/tests/src/cst_output/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use anyhow::Result;
use codegen_utils::context::CodegenContext;
use semver::Version;
use slang_solidity::{
language::{Error, Language},
syntax::parser::{ParseOutput, ProductionKind},
Language,
};
use solidity_testing_utils::cst_snapshots::ParseOutputTestSnapshotExtensions;

Expand Down Expand Up @@ -35,7 +35,16 @@ pub fn run(parser_name: &str, test_name: &str) -> Result<()> {

let production_kind = ProductionKind::from_str(parser_name)
.expect(format!("No such parser: {parser_name}").as_str());
let output = Language::new(version)?.parse(production_kind, &source);

let output = match Language::new(version)?.parse(production_kind, &source) {
Ok(output) => output,
Err(error) => match error {
Error::InvalidProductionVersion(_) => {
continue; // Skip versions that this production is not defined in.
}
_ => panic!("Unexpected error: {:?}", error),
},
};

if let Some(last_output) = &last_output {
if &output == last_output {
Expand Down
27 changes: 27 additions & 0 deletions crates/solidity/outputs/cargo/tests/src/errors/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use semver::Version;
use slang_solidity::{language::Language, syntax::parser::ProductionKind};

#[test]
fn unsupported_language_version() {
let version = Version::parse("0.0.0").unwrap();
let error = Language::new(version).unwrap_err();

assert_eq!(
error.to_string(),
"Unsupported Solidity language version '0.0.0'."
);
}

#[test]
fn invalid_production_version() {
let version = Version::parse("0.4.11").unwrap();
let language = Language::new(version).unwrap();
let error = language
.parse(ProductionKind::ConstructorDefinition, "")
.unwrap_err();

assert_eq!(
error.to_string(),
"Production 'ConstructorDefinition' is not valid in this version of Solidity."
);
}
2 changes: 2 additions & 0 deletions crates/solidity/outputs/cargo/tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
#[cfg(test)]
mod cst_output;
#[cfg(test)]
mod errors;
1 change: 1 addition & 0 deletions crates/solidity/outputs/npm/crate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ napi = { workspace = true }
napi-derive = { workspace = true }
semver = { workspace = true }
serde = { workspace = true }
thiserror = { workspace = true }
Loading