From 685de311e5263acee803c07f41652d8febf87abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Tue, 22 Oct 2024 06:09:52 -0400 Subject: [PATCH] Add support to resolve bindings to built-in functions, types and variables (#1101) This PR adds the infrastructure to the Bindings implementation to be able to: - define built-in functions, types and global variables, optionally specifying version ranges for those - generate an internal built-ins file that can be consumed by the implementation when creating a `Bindings` object for a specific language version - resolve references to built-ins in Solidity by adding some rules to the graph builder file to connect the built-ins parsed file and make all definitions there available to all other ingested source units So far, this contains just a few built-ins to test the infrastructure and verify that all functions, types and variables can be resolved. --- .../src/compiler/analysis/references.rs | 73 +++++- .../definition/src/model/built_ins.rs | 40 ++++ .../language/definition/src/model/manifest.rs | 45 +++- .../language/definition/src/model/mod.rs | 2 + .../internal_macros/src/derive/spanned.rs | 7 +- .../duplicate_expression_name/test.rs | 3 +- .../definitions/duplicate_item_name/test.rs | 3 +- .../duplicate_variant_name/test.rs | 3 +- .../definitions/operator_mismatch/test.rs | 3 +- .../fail/parsing/duplicate_map_key/test.rs | 3 +- .../fail/parsing/duplicate_set_entry/test.rs | 3 +- .../src/fail/parsing/empty_string/test.rs | 3 +- .../src/fail/parsing/missing_field/test.rs | 3 +- .../fail/parsing/unrecognized_field/test.rs | 3 +- .../fail/parsing/unrecognized_variant/test.rs | 3 +- .../src/fail/reachability/unreachable/test.rs | 3 +- .../fail/reachability/unused_version/test.rs | 3 +- .../fail/references/disabled_too_late/test.rs | 3 +- .../fail/references/enabled_too_early/test.rs | 3 +- .../fail/references/invalid_filter/test.rs | 3 +- .../fail/references/invalid_version/test.rs | 3 +- .../fail/references/unknown_reference/test.rs | 3 +- .../references/unordered_version_pair/test.rs | 3 +- .../fail/references/version_not_found/test.rs | 3 +- .../language/tests/src/pass/tiny_language.rs | 8 +- .../src/runtime/bindings/built_ins.rs.jinja2 | 24 ++ .../runtime/bindings/generated/built_ins.rs | 8 + .../cargo/crate/src/runtime/bindings/mod.rs | 7 + .../runtime/generator/src/bindings/mod.rs | 9 + .../runtime/generator/src/built_ins/mod.rs | 96 ++++++++ crates/codegen/runtime/generator/src/lib.rs | 8 +- crates/infra/utils/src/codegen/formatting.rs | 4 +- crates/infra/utils/src/codegen/runtime.rs | 6 +- .../bindings/generated/public_api.txt | 17 +- .../bindings/src/builder/functions.rs | 52 ++++- crates/metaslang/bindings/src/builder/mod.rs | 2 +- crates/metaslang/bindings/src/lib.rs | 85 +++++-- .../inputs/language/bindings/rules.msgb | 64 ++++-- .../solidity/inputs/language/src/bindings.rs | 55 +++++ .../inputs/language/src/definition.rs | 42 ++++ crates/solidity/inputs/language/src/lib.rs | 2 + crates/solidity/outputs/cargo/crate/build.rs | 11 +- .../cargo/crate/generated/public_api.txt | 1 + .../bindings/generated/binding_rules.rs | 64 ++++-- .../generated/bindings/generated/built_ins.rs | 14 ++ .../bindings/generated/built_ins/0.4.11.sol | 17 ++ .../bindings/generated/built_ins/0.5.0.sol | 19 ++ .../bindings/generated/built_ins/0.8.0.sol | 20 ++ .../cargo/crate/src/generated/bindings/mod.rs | 7 + .../outputs/cargo/tests/src/bindings.rs | 22 ++ .../src/bindings_assertions/assertions.rs | 17 +- .../tests/src/bindings_assertions/runner.rs | 11 +- .../bindings_output/generated/built_ins.rs | 15 ++ .../src/bindings_output/generated/mod.rs | 1 + .../tests/src/bindings_output/renderer.rs | 215 ++++++++++-------- .../cargo/tests/src/bindings_output/runner.rs | 31 +-- .../outputs/cargo/tests/src/built_ins.rs | 27 +++ .../solidity/outputs/cargo/tests/src/lib.rs | 2 + crates/solidity/outputs/cargo/wasm/build.rs | 2 +- crates/solidity/outputs/npm/package/build.rs | 2 +- .../solidity/testing/perf/benches/iai/main.rs | 11 +- .../perf/benches/iai/tests/definitions.rs | 37 ++- .../perf/benches/iai/tests/init_bindings.rs | 28 +++ .../testing/perf/benches/iai/tests/mod.rs | 1 + .../perf/benches/iai/tests/references.rs | 4 +- .../functions/generated/0.4.11-failure.txt | 29 +++ .../functions/generated/0.5.0-success.txt | 29 +++ .../functions/generated/0.8.4-success.txt | 26 +++ .../built_ins/functions/input.sol | 13 ++ .../generated/0.4.11-success.txt | 34 +++ .../built_ins/global_properties/input.sol | 8 + .../generated/0.4.11-failure.txt | 10 +- ...{0.4.22-success.txt => 0.4.22-failure.txt} | 10 +- .../contracts/constructor_modifier/input.sol | 2 +- ...{0.4.11-success.txt => 0.4.11-failure.txt} | 0 ...{0.4.11-success.txt => 0.4.11-failure.txt} | 0 ...{0.4.16-success.txt => 0.4.16-failure.txt} | 0 .../{0.6.0-success.txt => 0.6.0-failure.txt} | 0 ...{0.4.11-success.txt => 0.4.11-failure.txt} | 0 ...{0.4.16-success.txt => 0.4.16-failure.txt} | 0 .../{0.6.0-success.txt => 0.6.0-failure.txt} | 0 .../if_else/generated/0.4.11-success.txt | 16 +- .../if_else/generated/0.5.0-success.txt | 51 ----- .../bindings_output/control/if_else/input.sol | 2 +- .../{0.5.3-success.txt => 0.5.3-failure.txt} | 0 .../custom_types/generated/0.4.11-failure.txt | 2 +- .../generated/0.4.11-failure.txt | 2 +- .../{0.5.3-success.txt => 0.5.3-failure.txt} | 0 .../{0.6.0-success.txt => 0.6.0-failure.txt} | 0 ...{0.4.11-success.txt => 0.4.11-failure.txt} | 0 ...{0.4.11-success.txt => 0.4.11-failure.txt} | 10 +- .../modifiers/simple/input.sol | 2 +- .../{0.6.0-success.txt => 0.6.0-failure.txt} | 0 ...{0.4.11-success.txt => 0.4.11-failure.txt} | 10 +- .../modifiers/with_args/input.sol | 2 +- .../{0.6.0-success.txt => 0.6.0-failure.txt} | 0 .../inputs/language/src/definition.rs | 3 +- crates/testlang/outputs/cargo/crate/build.rs | 2 +- .../generated/bindings/generated/built_ins.rs | 8 + .../cargo/crate/src/generated/bindings/mod.rs | 7 + crates/testlang/outputs/cargo/wasm/build.rs | 2 +- crates/testlang/outputs/npm/package/build.rs | 2 +- 102 files changed, 1245 insertions(+), 329 deletions(-) create mode 100644 crates/codegen/language/definition/src/model/built_ins.rs create mode 100644 crates/codegen/runtime/cargo/crate/src/runtime/bindings/built_ins.rs.jinja2 create mode 100644 crates/codegen/runtime/cargo/crate/src/runtime/bindings/generated/built_ins.rs create mode 100644 crates/codegen/runtime/generator/src/built_ins/mod.rs create mode 100644 crates/solidity/inputs/language/src/bindings.rs create mode 100644 crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs create mode 100644 crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.11.sol create mode 100644 crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.5.0.sol create mode 100644 crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.0.sol create mode 100644 crates/solidity/outputs/cargo/tests/src/bindings.rs create mode 100644 crates/solidity/outputs/cargo/tests/src/bindings_output/generated/built_ins.rs create mode 100644 crates/solidity/outputs/cargo/tests/src/built_ins.rs create mode 100644 crates/solidity/testing/perf/benches/iai/tests/init_bindings.rs create mode 100644 crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.11-failure.txt create mode 100644 crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.5.0-success.txt create mode 100644 crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.4-success.txt create mode 100644 crates/solidity/testing/snapshots/bindings_output/built_ins/functions/input.sol create mode 100644 crates/solidity/testing/snapshots/bindings_output/built_ins/global_properties/generated/0.4.11-success.txt create mode 100644 crates/solidity/testing/snapshots/bindings_output/built_ins/global_properties/input.sol rename crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/generated/{0.4.22-success.txt => 0.4.22-failure.txt} (82%) rename crates/solidity/testing/snapshots/bindings_output/contracts/public_getters/generated/{0.4.11-success.txt => 0.4.11-failure.txt} (100%) rename crates/solidity/testing/snapshots/bindings_output/contracts/super_linearisation/generated/{0.4.11-success.txt => 0.4.11-failure.txt} (100%) rename crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/{0.4.16-success.txt => 0.4.16-failure.txt} (100%) rename crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/{0.6.0-success.txt => 0.6.0-failure.txt} (100%) rename crates/solidity/testing/snapshots/bindings_output/contracts/this_scope/generated/{0.4.11-success.txt => 0.4.11-failure.txt} (100%) rename crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/{0.4.16-success.txt => 0.4.16-failure.txt} (100%) rename crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/{0.6.0-success.txt => 0.6.0-failure.txt} (100%) delete mode 100644 crates/solidity/testing/snapshots/bindings_output/control/if_else/generated/0.5.0-success.txt rename crates/solidity/testing/snapshots/bindings_output/enums/sample/generated/{0.5.3-success.txt => 0.5.3-failure.txt} (100%) rename crates/solidity/testing/snapshots/bindings_output/expressions/type_expr/generated/{0.5.3-success.txt => 0.5.3-failure.txt} (100%) rename crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/generated/{0.6.0-success.txt => 0.6.0-failure.txt} (100%) rename crates/solidity/testing/snapshots/bindings_output/modifiers/inherited/generated/{0.4.11-success.txt => 0.4.11-failure.txt} (100%) rename crates/solidity/testing/snapshots/bindings_output/modifiers/simple/generated/{0.4.11-success.txt => 0.4.11-failure.txt} (83%) rename crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/generated/{0.6.0-success.txt => 0.6.0-failure.txt} (100%) rename crates/solidity/testing/snapshots/bindings_output/modifiers/with_args/generated/{0.4.11-success.txt => 0.4.11-failure.txt} (87%) rename crates/solidity/testing/snapshots/bindings_output/structs/sample/generated/{0.6.0-success.txt => 0.6.0-failure.txt} (100%) create mode 100644 crates/testlang/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs diff --git a/crates/codegen/language/definition/src/compiler/analysis/references.rs b/crates/codegen/language/definition/src/compiler/analysis/references.rs index 45fa364fb9..8e3f266458 100644 --- a/crates/codegen/language/definition/src/compiler/analysis/references.rs +++ b/crates/codegen/language/definition/src/compiler/analysis/references.rs @@ -11,8 +11,9 @@ use crate::model::SpannedItemDiscriminants::{ self, Enum, Fragment, Keyword, Precedence, Repeated, Separated, Struct, Token, Trivia, }; use crate::model::{ - Identifier, SpannedEnumItem, SpannedEnumVariant, SpannedField, SpannedFragmentItem, - SpannedItem, SpannedKeywordDefinition, SpannedKeywordItem, SpannedPrecedenceExpression, + Identifier, SpannedBuiltIn, SpannedBuiltInField, SpannedBuiltInFunction, SpannedBuiltInType, + SpannedEnumItem, SpannedEnumVariant, SpannedField, SpannedFragmentItem, SpannedItem, + SpannedKeywordDefinition, SpannedKeywordItem, SpannedPrecedenceExpression, SpannedPrecedenceItem, SpannedPrecedenceOperator, SpannedPrimaryExpression, SpannedRepeatedItem, SpannedScanner, SpannedSeparatedItem, SpannedStructItem, SpannedTokenDefinition, SpannedTokenItem, SpannedTriviaItem, SpannedTriviaParser, @@ -39,6 +40,10 @@ pub(crate) fn analyze_references(analysis: &mut Analysis) { for item in language.items() { check_item(analysis, item, &enablement); } + + for built_in in &language.built_ins { + check_built_in(analysis, built_in, &enablement); + } } fn check_item(analysis: &mut Analysis, item: &SpannedItem, enablement: &VersionSet) { @@ -396,6 +401,70 @@ fn check_reference( } } +fn check_built_in(analysis: &mut Analysis, built_in: &SpannedBuiltIn, enablement: &VersionSet) { + match built_in { + SpannedBuiltIn::BuiltInFunction { item } => { + check_built_in_function(analysis, item, enablement); + } + SpannedBuiltIn::BuiltInType { item } => { + check_built_in_type(analysis, item, enablement); + } + SpannedBuiltIn::BuiltInVariable { item } => { + check_built_in_field(analysis, item, enablement); + } + } +} + +fn check_built_in_function( + analysis: &mut Analysis, + built_in: &SpannedBuiltInFunction, + enablement: &VersionSet, +) { + let SpannedBuiltInFunction { + name: _, + return_type: _, + parameters: _, + enabled, + } = built_in; + + let _ = update_enablement(analysis, enablement, enabled); +} + +fn check_built_in_type( + analysis: &mut Analysis, + built_in: &SpannedBuiltInType, + enablement: &VersionSet, +) { + let SpannedBuiltInType { + name: _, + fields, + functions, + enabled, + } = built_in; + + let enablement = update_enablement(analysis, enablement, enabled); + + for field in fields { + check_built_in_field(analysis, field, &enablement); + } + for function in functions { + check_built_in_function(analysis, function, &enablement); + } +} + +fn check_built_in_field( + analysis: &mut Analysis, + built_in: &SpannedBuiltInField, + enablement: &VersionSet, +) { + let SpannedBuiltInField { + definition: _, + enabled, + } = built_in; + + let _ = update_enablement(analysis, enablement, enabled); +} + fn update_enablement( analysis: &mut Analysis, existing_enablement: &VersionSet, diff --git a/crates/codegen/language/definition/src/model/built_ins.rs b/crates/codegen/language/definition/src/model/built_ins.rs new file mode 100644 index 0000000000..741b88b390 --- /dev/null +++ b/crates/codegen/language/definition/src/model/built_ins.rs @@ -0,0 +1,40 @@ +use std::rc::Rc; + +use codegen_language_internal_macros::{derive_spanned_type, ParseInputTokens, WriteOutputTokens}; +use serde::{Deserialize, Serialize}; +use strum_macros::EnumDiscriminants; + +use crate::model::VersionSpecifier; + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive_spanned_type(Clone, Debug, EnumDiscriminants, ParseInputTokens, WriteOutputTokens)] +pub enum BuiltIn { + BuiltInFunction { item: Rc }, + BuiltInType { item: Rc }, + BuiltInVariable { item: Rc }, +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive_spanned_type(Clone, Debug, ParseInputTokens, WriteOutputTokens)] +pub struct BuiltInFunction { + pub name: String, + pub parameters: Vec, + pub return_type: Option, + pub enabled: Option, +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive_spanned_type(Clone, Debug, ParseInputTokens, WriteOutputTokens)] +pub struct BuiltInType { + pub name: String, + pub fields: Vec, + pub functions: Vec, + pub enabled: Option, +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive_spanned_type(Clone, Debug, ParseInputTokens, WriteOutputTokens)] +pub struct BuiltInField { + pub definition: String, + pub enabled: Option, +} diff --git a/crates/codegen/language/definition/src/model/manifest.rs b/crates/codegen/language/definition/src/model/manifest.rs index 21b95b4c48..116b73c568 100644 --- a/crates/codegen/language/definition/src/model/manifest.rs +++ b/crates/codegen/language/definition/src/model/manifest.rs @@ -6,7 +6,7 @@ use indexmap::IndexSet; use semver::Version; use serde::{Deserialize, Serialize}; -use crate::model::{Field, Identifier, Item, TriviaParser, VersionSpecifier}; +use crate::model::{BuiltIn, Field, Identifier, Item, TriviaParser, VersionSpecifier}; #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[derive_spanned_type(Clone, Debug, ParseInputTokens, WriteOutputTokens)] @@ -15,6 +15,7 @@ pub struct Language { pub documentation_dir: PathBuf, pub binding_rules_file: PathBuf, + pub file_extension: Option, pub root_item: Identifier, @@ -24,6 +25,7 @@ pub struct Language { pub versions: IndexSet, pub sections: Vec
, + pub built_ins: Vec, } impl Language { @@ -104,6 +106,47 @@ impl Language { res } + + /// Collects all versions that change the language built-ins. + /// + /// Includes the first supported version. Returns an empty set if there are + /// no built-ins defined. + pub fn collect_built_ins_versions(&self) -> BTreeSet { + if self.built_ins.is_empty() { + return BTreeSet::new(); + } + + let first = self.versions.first().unwrap().clone(); + let mut res = BTreeSet::from_iter([first]); + + let mut add_spec = |spec: &Option| { + if let Some(spec) = spec { + res.extend(spec.versions().cloned()); + } + }; + + for item in &self.built_ins { + match item { + BuiltIn::BuiltInFunction { item } => { + add_spec(&item.enabled); + } + BuiltIn::BuiltInType { item } => { + add_spec(&item.enabled); + for field in &item.fields { + add_spec(&field.enabled); + } + for function in &item.functions { + add_spec(&function.enabled); + } + } + BuiltIn::BuiltInVariable { item } => { + add_spec(&item.enabled); + } + } + } + + res + } } #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] diff --git a/crates/codegen/language/definition/src/model/mod.rs b/crates/codegen/language/definition/src/model/mod.rs index 9b6c9b8558..df8699c0c2 100644 --- a/crates/codegen/language/definition/src/model/mod.rs +++ b/crates/codegen/language/definition/src/model/mod.rs @@ -1,9 +1,11 @@ +mod built_ins; mod item; mod manifest; mod nonterminals; mod terminals; mod utils; +pub use built_ins::*; pub use item::*; pub use manifest::*; pub use nonterminals::*; diff --git a/crates/codegen/language/internal_macros/src/derive/spanned.rs b/crates/codegen/language/internal_macros/src/derive/spanned.rs index 79e1a4b7eb..81a3cc43aa 100644 --- a/crates/codegen/language/internal_macros/src/derive/spanned.rs +++ b/crates/codegen/language/internal_macros/src/derive/spanned.rs @@ -110,7 +110,12 @@ fn get_spanned_type(input: Type) -> Type { match type_name.as_str() { // These are model Types that have a derived 'SpannedXXX' type. // Let's use that instead: - "EnumItem" + "BuiltIn" + | "BuiltInField" + | "BuiltInFunction" + | "BuiltInParameter" + | "BuiltInType" + | "EnumItem" | "EnumVariant" | "Field" | "FieldDelimiters" diff --git a/crates/codegen/language/tests/src/fail/definitions/duplicate_expression_name/test.rs b/crates/codegen/language/tests/src/fail/definitions/duplicate_expression_name/test.rs index a0b46fa8de..5b6ec3c74d 100644 --- a/crates/codegen/language/tests/src/fail/definitions/duplicate_expression_name/test.rs +++ b/crates/codegen/language/tests/src/fail/definitions/duplicate_expression_name/test.rs @@ -46,7 +46,8 @@ codegen_language_macros::compile!(Language( ) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/definitions/duplicate_item_name/test.rs b/crates/codegen/language/tests/src/fail/definitions/duplicate_item_name/test.rs index 3436db958e..47e3448b32 100644 --- a/crates/codegen/language/tests/src/fail/definitions/duplicate_item_name/test.rs +++ b/crates/codegen/language/tests/src/fail/definitions/duplicate_item_name/test.rs @@ -18,7 +18,8 @@ codegen_language_macros::compile!(Language( Struct(name = Bar2, fields = (field = Required(Bar1))) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/definitions/duplicate_variant_name/test.rs b/crates/codegen/language/tests/src/fail/definitions/duplicate_variant_name/test.rs index 0080ea364e..a3b7287263 100644 --- a/crates/codegen/language/tests/src/fail/definitions/duplicate_variant_name/test.rs +++ b/crates/codegen/language/tests/src/fail/definitions/duplicate_variant_name/test.rs @@ -31,7 +31,8 @@ codegen_language_macros::compile!(Language( ) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/definitions/operator_mismatch/test.rs b/crates/codegen/language/tests/src/fail/definitions/operator_mismatch/test.rs index 23aaaa8a2c..143be44999 100644 --- a/crates/codegen/language/tests/src/fail/definitions/operator_mismatch/test.rs +++ b/crates/codegen/language/tests/src/fail/definitions/operator_mismatch/test.rs @@ -36,7 +36,8 @@ codegen_language_macros::compile!(Language( ) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/parsing/duplicate_map_key/test.rs b/crates/codegen/language/tests/src/fail/parsing/duplicate_map_key/test.rs index e915c53645..aa53d5905d 100644 --- a/crates/codegen/language/tests/src/fail/parsing/duplicate_map_key/test.rs +++ b/crates/codegen/language/tests/src/fail/parsing/duplicate_map_key/test.rs @@ -27,7 +27,8 @@ codegen_language_macros::compile!(Language( ) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/parsing/duplicate_set_entry/test.rs b/crates/codegen/language/tests/src/fail/parsing/duplicate_set_entry/test.rs index dee843ef70..87236ac4b1 100644 --- a/crates/codegen/language/tests/src/fail/parsing/duplicate_set_entry/test.rs +++ b/crates/codegen/language/tests/src/fail/parsing/duplicate_set_entry/test.rs @@ -17,7 +17,8 @@ codegen_language_macros::compile!(Language( definitions = [TokenDefinition(scanner = Atom("bar"))] )] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/parsing/empty_string/test.rs b/crates/codegen/language/tests/src/fail/parsing/empty_string/test.rs index f9308e65e6..a14eec2aeb 100644 --- a/crates/codegen/language/tests/src/fail/parsing/empty_string/test.rs +++ b/crates/codegen/language/tests/src/fail/parsing/empty_string/test.rs @@ -17,7 +17,8 @@ codegen_language_macros::compile!(Language( definitions = [TokenDefinition(scanner = Atom(""))] )] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/parsing/missing_field/test.rs b/crates/codegen/language/tests/src/fail/parsing/missing_field/test.rs index 0e6a5d7a1a..3676713290 100644 --- a/crates/codegen/language/tests/src/fail/parsing/missing_field/test.rs +++ b/crates/codegen/language/tests/src/fail/parsing/missing_field/test.rs @@ -11,7 +11,8 @@ codegen_language_macros::compile!(Language( sections = [Section( // title = "Section One" topics = [] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/parsing/unrecognized_field/test.rs b/crates/codegen/language/tests/src/fail/parsing/unrecognized_field/test.rs index 90fe028477..82318d9f02 100644 --- a/crates/codegen/language/tests/src/fail/parsing/unrecognized_field/test.rs +++ b/crates/codegen/language/tests/src/fail/parsing/unrecognized_field/test.rs @@ -18,7 +18,8 @@ codegen_language_macros::compile!(Language( )], unrecognized_field = true )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/parsing/unrecognized_variant/test.rs b/crates/codegen/language/tests/src/fail/parsing/unrecognized_variant/test.rs index 41bc2e5da7..ec42e71b8c 100644 --- a/crates/codegen/language/tests/src/fail/parsing/unrecognized_variant/test.rs +++ b/crates/codegen/language/tests/src/fail/parsing/unrecognized_variant/test.rs @@ -20,7 +20,8 @@ codegen_language_macros::compile!(Language( ), Topic(title = "Topic Two", items = [Unrecognized(true)]) ] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/reachability/unreachable/test.rs b/crates/codegen/language/tests/src/fail/reachability/unreachable/test.rs index 2954211178..a6af2b7398 100644 --- a/crates/codegen/language/tests/src/fail/reachability/unreachable/test.rs +++ b/crates/codegen/language/tests/src/fail/reachability/unreachable/test.rs @@ -21,7 +21,8 @@ codegen_language_macros::compile!(Language( Struct(name = Baz2, fields = (field = Required(Baz1))) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/reachability/unused_version/test.rs b/crates/codegen/language/tests/src/fail/reachability/unused_version/test.rs index ff979fee25..d7363c8998 100644 --- a/crates/codegen/language/tests/src/fail/reachability/unused_version/test.rs +++ b/crates/codegen/language/tests/src/fail/reachability/unused_version/test.rs @@ -23,7 +23,8 @@ codegen_language_macros::compile!(Language( ) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/references/disabled_too_late/test.rs b/crates/codegen/language/tests/src/fail/references/disabled_too_late/test.rs index 569777136a..d6c9e86c59 100644 --- a/crates/codegen/language/tests/src/fail/references/disabled_too_late/test.rs +++ b/crates/codegen/language/tests/src/fail/references/disabled_too_late/test.rs @@ -34,7 +34,8 @@ codegen_language_macros::compile!(Language( ) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/references/enabled_too_early/test.rs b/crates/codegen/language/tests/src/fail/references/enabled_too_early/test.rs index 7df2730226..15acba2144 100644 --- a/crates/codegen/language/tests/src/fail/references/enabled_too_early/test.rs +++ b/crates/codegen/language/tests/src/fail/references/enabled_too_early/test.rs @@ -34,7 +34,8 @@ codegen_language_macros::compile!(Language( ) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/references/invalid_filter/test.rs b/crates/codegen/language/tests/src/fail/references/invalid_filter/test.rs index a02de5b05c..31a2df3036 100644 --- a/crates/codegen/language/tests/src/fail/references/invalid_filter/test.rs +++ b/crates/codegen/language/tests/src/fail/references/invalid_filter/test.rs @@ -17,7 +17,8 @@ codegen_language_macros::compile!(Language( Fragment(name = Baz, scanner = Atom("baz")) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/references/invalid_version/test.rs b/crates/codegen/language/tests/src/fail/references/invalid_version/test.rs index bf3bd74789..f01871269f 100644 --- a/crates/codegen/language/tests/src/fail/references/invalid_version/test.rs +++ b/crates/codegen/language/tests/src/fail/references/invalid_version/test.rs @@ -46,7 +46,8 @@ codegen_language_macros::compile!(Language( ) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/references/unknown_reference/test.rs b/crates/codegen/language/tests/src/fail/references/unknown_reference/test.rs index fa686f3f71..96cd096237 100644 --- a/crates/codegen/language/tests/src/fail/references/unknown_reference/test.rs +++ b/crates/codegen/language/tests/src/fail/references/unknown_reference/test.rs @@ -23,7 +23,8 @@ codegen_language_macros::compile!(Language( ) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/references/unordered_version_pair/test.rs b/crates/codegen/language/tests/src/fail/references/unordered_version_pair/test.rs index 8f8df24a7d..c6e5120d50 100644 --- a/crates/codegen/language/tests/src/fail/references/unordered_version_pair/test.rs +++ b/crates/codegen/language/tests/src/fail/references/unordered_version_pair/test.rs @@ -29,7 +29,8 @@ codegen_language_macros::compile!(Language( ) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/fail/references/version_not_found/test.rs b/crates/codegen/language/tests/src/fail/references/version_not_found/test.rs index 9eb4324341..f7ac4684b3 100644 --- a/crates/codegen/language/tests/src/fail/references/version_not_found/test.rs +++ b/crates/codegen/language/tests/src/fail/references/version_not_found/test.rs @@ -26,7 +26,8 @@ codegen_language_macros::compile!(Language( ) ] )] - )] + )], + built_ins = [] )); fn main() {} diff --git a/crates/codegen/language/tests/src/pass/tiny_language.rs b/crates/codegen/language/tests/src/pass/tiny_language.rs index 441031b7b3..6b5652634a 100644 --- a/crates/codegen/language/tests/src/pass/tiny_language.rs +++ b/crates/codegen/language/tests/src/pass/tiny_language.rs @@ -11,6 +11,7 @@ codegen_language_macros::compile!(Language( name = Tiny, documentation_dir = "tiny/docs", binding_rules_file = "tiny/bindings/rules.msgb", + file_extension = ".tiny", root_item = Foo, leading_trivia = Sequence([]), trailing_trivia = Sequence([]), @@ -38,7 +39,8 @@ codegen_language_macros::compile!(Language( ) ] )] - )] + )], + built_ins = [] )); #[test] @@ -49,6 +51,7 @@ fn definition() { name: "Tiny".into(), documentation_dir: Path::repo_path("tiny/docs"), binding_rules_file: Path::repo_path("tiny/bindings/rules.msgb"), + file_extension: Some(".tiny".into()), root_item: "Foo".into(), leading_trivia: TriviaParser::Sequence { parsers: [].into() }, trailing_trivia: TriviaParser::Sequence { parsers: [].into() }, @@ -119,7 +122,8 @@ fn definition() { ] .into() }], - }] + }], + built_ins: [].into(), } .into(), ); diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/bindings/built_ins.rs.jinja2 b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/built_ins.rs.jinja2 new file mode 100644 index 0000000000..856f983808 --- /dev/null +++ b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/built_ins.rs.jinja2 @@ -0,0 +1,24 @@ +use semver::Version; + +#[allow(unused_variables)] +pub fn get_contents(version: &Version) -> &'static str { + {%- if not rendering_in_stubs -%} + {%- for version in model.bindings.built_ins_versions %} + {%- if not loop.first -%} + if *version < Version::new({{ version | split(pat=".") | join(sep=", ") }}) { + include_str!("./built_ins/{{ prev_version }}{{ model.bindings.file_extension }}") + } else + {% endif %} + {% if loop.last %} + { + include_str!("./built_ins/{{ version }}{{ model.bindings.file_extension }}") + } + {% endif %} + {% set_global prev_version = version %} + {%- else -%} + "" + {%- endfor -%} + {%- else -%} + unreachable!("Built-ins not defined in stubs") + {%- endif -%} +} diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/bindings/generated/built_ins.rs b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/generated/built_ins.rs new file mode 100644 index 0000000000..f7337ecff2 --- /dev/null +++ b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/generated/built_ins.rs @@ -0,0 +1,8 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use semver::Version; + +#[allow(unused_variables)] +pub fn get_contents(version: &Version) -> &'static str { + unreachable!("Built-ins not defined in stubs") +} diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/bindings/mod.rs b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/mod.rs index eba0e25eb0..3769f5d1b1 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/bindings/mod.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/mod.rs @@ -1,6 +1,9 @@ #[path = "generated/binding_rules.rs"] mod binding_rules; +#[path = "generated/built_ins.rs"] +mod built_ins; + use std::sync::Arc; use metaslang_bindings::{self, PathResolver}; @@ -23,3 +26,7 @@ pub fn create_with_resolver( pub fn get_binding_rules() -> &'static str { binding_rules::BINDING_RULES_SOURCE } + +pub fn get_built_ins(version: &semver::Version) -> &'static str { + built_ins::get_contents(version) +} diff --git a/crates/codegen/runtime/generator/src/bindings/mod.rs b/crates/codegen/runtime/generator/src/bindings/mod.rs index ae29b4ef48..61e9f5687e 100644 --- a/crates/codegen/runtime/generator/src/bindings/mod.rs +++ b/crates/codegen/runtime/generator/src/bindings/mod.rs @@ -1,12 +1,17 @@ +use std::collections::BTreeSet; + use anyhow::Result; use codegen_language_definition::model; use infra_utils::codegen::CodegenFileSystem; use infra_utils::paths::PathExtensions; +use semver::Version; use serde::Serialize; #[derive(Default, Serialize)] pub struct BindingsModel { binding_rules_source: String, + built_ins_versions: BTreeSet, + file_extension: String, } impl BindingsModel { @@ -15,9 +20,13 @@ impl BindingsModel { let binding_rules_dir = language.binding_rules_file.unwrap_parent(); let mut fs = CodegenFileSystem::new(binding_rules_dir)?; let binding_rules_source = fs.read_file(&language.binding_rules_file)?; + let built_ins_versions = language.collect_built_ins_versions(); + let file_extension = language.file_extension.clone().unwrap_or_default(); Ok(Self { binding_rules_source, + built_ins_versions, + file_extension, }) } } diff --git a/crates/codegen/runtime/generator/src/built_ins/mod.rs b/crates/codegen/runtime/generator/src/built_ins/mod.rs new file mode 100644 index 0000000000..638a89fe8b --- /dev/null +++ b/crates/codegen/runtime/generator/src/built_ins/mod.rs @@ -0,0 +1,96 @@ +use std::path::Path; +use std::rc::Rc; + +use anyhow::Result; +use codegen_language_definition::model::{ + BuiltIn, BuiltInField, BuiltInFunction, BuiltInType, Language, +}; +use infra_utils::codegen::CodegenFileSystem; +use semver::Version; + +pub fn render_built_ins( + file_system: &mut CodegenFileSystem, + language: &Rc, + output_dir: &Path, + render_fn: impl Fn(&[BuiltIn]) -> String, +) -> Result<()> { + let versions = language.collect_built_ins_versions(); + let file_extension = language.file_extension.clone().unwrap_or_default(); + for version in &versions { + let built_ins = filter_built_ins_for_version(&language.built_ins, version); + let contents = render_fn(&built_ins); + + let output_path = output_dir.join(format!("{version}{file_extension}")); + file_system.write_file(output_path, contents)?; + } + Ok(()) +} + +fn filter_built_ins_for_version(built_ins: &[BuiltIn], version: &Version) -> Vec { + built_ins + .iter() + .filter_map(|built_in| match built_in { + BuiltIn::BuiltInFunction { item } => filter_built_in_function(item, version) + .map(|item| BuiltIn::BuiltInFunction { item: item.into() }), + BuiltIn::BuiltInType { item } => filter_built_in_type(item, version) + .map(|item| BuiltIn::BuiltInType { item: item.into() }), + BuiltIn::BuiltInVariable { item } => filter_built_in_field(item, version) + .map(|item| BuiltIn::BuiltInVariable { item: item.into() }), + }) + .collect() +} + +fn filter_built_in_function( + function: &BuiltInFunction, + version: &Version, +) -> Option { + if function + .enabled + .as_ref() + .map_or(true, |enabled| enabled.contains(version)) + { + Some(function.clone()) + } else { + None + } +} + +fn filter_built_in_field(field: &BuiltInField, version: &Version) -> Option { + if field + .enabled + .as_ref() + .map_or(true, |enabled| enabled.contains(version)) + { + Some(field.clone()) + } else { + None + } +} + +fn filter_built_in_type(typ: &BuiltInType, version: &Version) -> Option { + if typ + .enabled + .as_ref() + .map_or(true, |enabled| enabled.contains(version)) + { + let fields = typ + .fields + .iter() + .filter_map(|field| filter_built_in_field(field, version)) + .collect(); + let functions = typ + .functions + .iter() + .filter_map(|function| filter_built_in_function(function, version)) + .collect(); + + Some(BuiltInType { + name: typ.name.clone(), + fields, + functions, + enabled: typ.enabled.clone(), + }) + } else { + None + } +} diff --git a/crates/codegen/runtime/generator/src/lib.rs b/crates/codegen/runtime/generator/src/lib.rs index 9ff2ba898d..786747c84c 100644 --- a/crates/codegen/runtime/generator/src/lib.rs +++ b/crates/codegen/runtime/generator/src/lib.rs @@ -1,5 +1,6 @@ mod ast; mod bindings; +mod built_ins; mod kinds; mod parser; @@ -8,9 +9,10 @@ use std::path::Path; use std::rc::Rc; use anyhow::Result; +pub use built_ins::render_built_ins; use codegen_language_definition::model::Language; use infra_utils::cargo::CargoWorkspace; -use infra_utils::codegen::CodegenRuntime; +use infra_utils::codegen::{CodegenFileSystem, CodegenRuntime}; use semver::Version; use serde::Serialize; @@ -26,13 +28,13 @@ impl RuntimeGenerator { language: &Rc, input_dir: &Path, output_dir: &Path, - ) -> Result<()> { + ) -> Result { let model = ModelWrapper { rendering_in_stubs: false, model: RuntimeModel::from_language(language)?, }; - let mut runtime = CodegenRuntime::new(input_dir)?; + let runtime = CodegenRuntime::new(input_dir)?; runtime.render_product(model, output_dir) } diff --git a/crates/infra/utils/src/codegen/formatting.rs b/crates/infra/utils/src/codegen/formatting.rs index 8c9546ae37..dd4d020ceb 100644 --- a/crates/infra/utils/src/codegen/formatting.rs +++ b/crates/infra/utils/src/codegen/formatting.rs @@ -32,7 +32,7 @@ fn generate_header(file_path: &Path) -> String { (_, "ebnf") => format!("(* {warning_line} *)"), (_, "json") => String::new(), (_, "html" | "md") => format!(""), - (_, "dot" | "js" | "mts" | "rs" | "ts" | "wit") => format!("// {warning_line}"), + (_, "dot" | "js" | "mts" | "rs" | "sol" | "ts" | "wit") => format!("// {warning_line}"), (_, "yml" | "txt") => format!("# {warning_line}"), (_, "mmd") => format!("%% {warning_line}"), @@ -48,7 +48,7 @@ fn run_formatter(file_path: &Path, contents: &str) -> Result { // No formatters available for these yet: (".gitignore", _) => Ok(contents.to_owned()), - (_, "dot" | "ebnf" | "mmd" | "txt" | "wit") => Ok(contents.to_owned()), + (_, "dot" | "ebnf" | "mmd" | "sol" | "txt" | "wit") => Ok(contents.to_owned()), // We already generate formatted content for these, so no need to run expensive formatting: (_, "html" | "md" | "yml") => Ok(contents.to_owned()), diff --git a/crates/infra/utils/src/codegen/runtime.rs b/crates/infra/utils/src/codegen/runtime.rs index 533593cef7..9a98f24644 100644 --- a/crates/infra/utils/src/codegen/runtime.rs +++ b/crates/infra/utils/src/codegen/runtime.rs @@ -41,10 +41,10 @@ impl CodegenRuntime { } pub fn render_product( - &mut self, + mut self, model: impl Serialize, output_dir: impl AsRef, - ) -> Result<()> { + ) -> Result { let context = tera::Context::from_serialize(model)?; let output_dir = output_dir.as_ref(); @@ -75,7 +75,7 @@ impl CodegenRuntime { } } - Ok(()) + Ok(self.fs) } fn get_stub_path(template_path: &Path) -> PathBuf { diff --git a/crates/metaslang/bindings/generated/public_api.txt b/crates/metaslang/bindings/generated/public_api.txt index ba30f909dc..f98a7e4582 100644 --- a/crates/metaslang/bindings/generated/public_api.txt +++ b/crates/metaslang/bindings/generated/public_api.txt @@ -1,13 +1,22 @@ # This file is generated automatically by infrastructure scripts. Please don't edit by hand. pub mod metaslang_bindings +pub enum metaslang_bindings::FileDescriptor +pub metaslang_bindings::FileDescriptor::System(alloc::string::String) +pub metaslang_bindings::FileDescriptor::User(alloc::string::String) +impl metaslang_bindings::FileDescriptor +pub fn metaslang_bindings::FileDescriptor::get_path(&self) -> &str +pub fn metaslang_bindings::FileDescriptor::is_system(&self) -> bool +pub fn metaslang_bindings::FileDescriptor::is_user(&self) -> bool +pub fn metaslang_bindings::FileDescriptor::is_user_path(&self, path: &str) -> bool pub enum metaslang_bindings::ResolutionError<'a, KT: metaslang_cst::kinds::KindTypes + 'static> pub metaslang_bindings::ResolutionError::AmbiguousDefinitions(alloc::vec::Vec>) pub metaslang_bindings::ResolutionError::Unresolved pub struct metaslang_bindings::Bindings impl metaslang_bindings::Bindings -pub fn metaslang_bindings::Bindings::add_file(&mut self, file_path: &str, tree_cursor: metaslang_cst::cursor::Cursor) -pub fn metaslang_bindings::Bindings::add_file_returning_graph(&mut self, file_path: &str, tree_cursor: metaslang_cst::cursor::Cursor) -> metaslang_graph_builder::graph::Graph +pub fn metaslang_bindings::Bindings::add_system_file(&mut self, file_path: &str, tree_cursor: metaslang_cst::cursor::Cursor) +pub fn metaslang_bindings::Bindings::add_user_file(&mut self, file_path: &str, tree_cursor: metaslang_cst::cursor::Cursor) +pub fn metaslang_bindings::Bindings::add_user_file_returning_graph(&mut self, file_path: &str, tree_cursor: metaslang_cst::cursor::Cursor) -> metaslang_graph_builder::graph::Graph pub fn metaslang_bindings::Bindings::all_definitions(&self) -> impl core::iter::traits::iterator::Iterator> + '_ pub fn metaslang_bindings::Bindings::all_references(&self) -> impl core::iter::traits::iterator::Iterator> + '_ pub fn metaslang_bindings::Bindings::create(version: semver::Version, binding_rules: &str, path_resolver: alloc::sync::Arc<(dyn metaslang_bindings::PathResolver + core::marker::Sync + core::marker::Send)>) -> Self @@ -20,7 +29,7 @@ pub struct metaslang_bindings::Definition<'a, KT: metaslang_cst::kinds::KindType impl<'a, KT: metaslang_cst::kinds::KindTypes + 'static> metaslang_bindings::Definition<'a, KT> pub fn metaslang_bindings::Definition<'a, KT>::get_cursor(&self) -> core::option::Option> pub fn metaslang_bindings::Definition<'a, KT>::get_definiens_cursor(&self) -> core::option::Option> -pub fn metaslang_bindings::Definition<'a, KT>::get_file(&self) -> core::option::Option<&'a str> +pub fn metaslang_bindings::Definition<'a, KT>::get_file(&self) -> metaslang_bindings::FileDescriptor pub fn metaslang_bindings::Definition<'a, KT>::to_handle(self) -> metaslang_bindings::DefinitionHandle impl<'a, KT: core::clone::Clone + metaslang_cst::kinds::KindTypes + 'static> core::clone::Clone for metaslang_bindings::Definition<'a, KT> pub fn metaslang_bindings::Definition<'a, KT>::clone(&self) -> metaslang_bindings::Definition<'a, KT> @@ -38,7 +47,7 @@ pub struct metaslang_bindings::Reference<'a, KT: metaslang_cst::kinds::KindTypes impl<'a, KT: metaslang_cst::kinds::KindTypes + 'static> metaslang_bindings::Reference<'a, KT> pub fn metaslang_bindings::Reference<'a, KT>::definitions(&self) -> alloc::vec::Vec> pub fn metaslang_bindings::Reference<'a, KT>::get_cursor(&self) -> core::option::Option> -pub fn metaslang_bindings::Reference<'a, KT>::get_file(&self) -> core::option::Option<&'a str> +pub fn metaslang_bindings::Reference<'a, KT>::get_file(&self) -> metaslang_bindings::FileDescriptor pub fn metaslang_bindings::Reference<'a, KT>::jump_to_definition(&self) -> core::result::Result, metaslang_bindings::ResolutionError<'a, KT>> impl<'a, KT: core::clone::Clone + metaslang_cst::kinds::KindTypes + 'static> core::clone::Clone for metaslang_bindings::Reference<'a, KT> pub fn metaslang_bindings::Reference<'a, KT>::clone(&self) -> metaslang_bindings::Reference<'a, KT> diff --git a/crates/metaslang/bindings/src/builder/functions.rs b/crates/metaslang/bindings/src/builder/functions.rs index fc0ee95085..67a1f9eeff 100644 --- a/crates/metaslang/bindings/src/builder/functions.rs +++ b/crates/metaslang/bindings/src/builder/functions.rs @@ -63,13 +63,14 @@ mod resolver { use metaslang_graph_builder::graph::{Graph, Value}; use metaslang_graph_builder::ExecutionError; - use crate::PathResolver; + use crate::{FileDescriptor, PathResolver}; pub fn add_functions( functions: &mut Functions, path_resolver: Arc, ) { functions.add("resolve-path".into(), ResolvePath { path_resolver }); + functions.add("is-system-file".into(), IsSystemFile {}); } struct ResolvePath { @@ -86,18 +87,53 @@ mod resolver { let path_to_resolve = parameters.param()?.into_string()?; parameters.finish()?; + let context_file_descriptor = FileDescriptor::from_string(&context_path); + let Ok(FileDescriptor::User(context_user_path)) = context_file_descriptor else { + // Since the path resolver should only map to user paths from + // user paths, it is an error to attempt to resolve a path in + // the context of a system file + return Err(ExecutionError::FunctionFailed( + "resolve-path".into(), + "Cannot execute with a non-user context file path".into(), + )); + }; + let resolved_path = self .path_resolver .as_ref() - .resolve_path(&context_path, &path_to_resolve) - .unwrap_or_else(|| { - // In case we cannot resolve the path, we return a special value that is unique - // per context/path pait. This way, we can still run incrementally and resolve - // other symbols in the file: - format!("__SLANG_UNRESOLVED_PATH__{context_path}__{path_to_resolve}__") - }); + .resolve_path(&context_user_path, &path_to_resolve) + .map_or_else( + || { + // In case we cannot resolve the path, we return a special value that is unique + // per context/path pait. This way, we can still run incrementally and resolve + // other symbols in the file: + format!("__SLANG_UNRESOLVED_PATH__{context_path}__{path_to_resolve}__") + }, + |resolved_path| FileDescriptor::User(resolved_path).as_string(), + ); Ok(resolved_path.into()) } } + + struct IsSystemFile {} + + impl Function for IsSystemFile { + fn call( + &self, + _graph: &mut Graph, + parameters: &mut dyn Parameters, + ) -> Result { + let file_path = parameters.param()?.into_string()?; + parameters.finish()?; + + let Ok(file_descriptor) = FileDescriptor::from_string(&file_path) else { + return Err(ExecutionError::FunctionFailed( + "is-system-file".into(), + "Parameter is not a valid file path".into(), + )); + }; + Ok(file_descriptor.is_system().into()) + } + } } diff --git a/crates/metaslang/bindings/src/builder/mod.rs b/crates/metaslang/bindings/src/builder/mod.rs index bf9141e5fc..03eb7d16c9 100644 --- a/crates/metaslang/bindings/src/builder/mod.rs +++ b/crates/metaslang/bindings/src/builder/mod.rs @@ -398,7 +398,7 @@ impl<'a, KT: KindTypes + 'static> Builder<'a, KT> { let file_path = self.stack_graph[self.file].name(); variables .add(FILE_PATH_VAR.into(), file_path.into()) - .expect("failed to add FILE_PATH variable"); + .expect("Failed to add FILE_PATH variable"); let root_node = self.inject_node(NodeID::root()); variables diff --git a/crates/metaslang/bindings/src/lib.rs b/crates/metaslang/bindings/src/lib.rs index 25b4fc9ce1..57ef3048ff 100644 --- a/crates/metaslang/bindings/src/lib.rs +++ b/crates/metaslang/bindings/src/lib.rs @@ -17,6 +17,7 @@ use stack_graphs::graph::StackGraph; type Builder<'a, KT> = builder::Builder<'a, KT>; type GraphHandle = stack_graphs::arena::Handle; +type FileHandle = stack_graphs::arena::Handle; type CursorID = usize; pub struct DefinitionHandle(GraphHandle); @@ -54,6 +55,54 @@ pub struct Bindings { context: Option, } +pub enum FileDescriptor { + User(String), + System(String), +} + +pub(crate) struct FileDescriptorError; + +impl FileDescriptor { + // Internal functions to convert a FileDescriptor to and from a string for + // representation inside the stack graph + + pub(crate) fn as_string(&self) -> String { + match self { + Self::User(path) => format!("user:{path}"), + Self::System(path) => format!("system:{path}"), + } + } + + pub(crate) fn from_string(value: &str) -> Result { + if let Some(path) = value.strip_prefix("user:") { + Ok(FileDescriptor::User(path.into())) + } else if let Some(path) = value.strip_prefix("system:") { + Ok(FileDescriptor::System(path.into())) + } else { + Err(FileDescriptorError) + } + } + + pub fn get_path(&self) -> &str { + match self { + Self::User(path) => path, + Self::System(path) => path, + } + } + + pub fn is_system(&self) -> bool { + matches!(self, Self::System(_)) + } + + pub fn is_user(&self) -> bool { + matches!(self, Self::User(_)) + } + + pub fn is_user_path(&self, path: &str) -> bool { + matches!(self, Self::User(user_path) if user_path == path) + } +} + pub trait PathResolver { fn resolve_path(&self, context_path: &str, path_to_resolve: &str) -> Option; } @@ -82,23 +131,31 @@ impl Bindings { } } - pub fn add_file(&mut self, file_path: &str, tree_cursor: Cursor) { - _ = self.add_file_internal(file_path, tree_cursor); + pub fn add_system_file(&mut self, file_path: &str, tree_cursor: Cursor) { + let file_kind = FileDescriptor::System(file_path.into()); + let file = self.stack_graph.get_or_create_file(&file_kind.as_string()); + _ = self.add_file_internal(file, tree_cursor); + } + + pub fn add_user_file(&mut self, file_path: &str, tree_cursor: Cursor) { + let file_kind = FileDescriptor::User(file_path.into()); + let file = self.stack_graph.get_or_create_file(&file_kind.as_string()); + _ = self.add_file_internal(file, tree_cursor); } #[cfg(feature = "__private_testing_utils")] - pub fn add_file_returning_graph( + pub fn add_user_file_returning_graph( &mut self, file_path: &str, tree_cursor: Cursor, ) -> metaslang_graph_builder::graph::Graph { - let result = self.add_file_internal(file_path, tree_cursor); + let file_kind = FileDescriptor::User(file_path.into()); + let file = self.stack_graph.get_or_create_file(&file_kind.as_string()); + let result = self.add_file_internal(file, tree_cursor); result.graph } - fn add_file_internal(&mut self, file_path: &str, tree_cursor: Cursor) -> BuildResult { - let file = self.stack_graph.get_or_create_file(file_path); - + fn add_file_internal(&mut self, file: FileHandle, tree_cursor: Cursor) -> BuildResult { let builder = Builder::new( &self.graph_builder_file, &self.functions, @@ -277,7 +334,7 @@ impl Bindings { struct DisplayCursor<'a, KT: KindTypes + 'static> { cursor: &'a Cursor, - file: Option<&'a str>, + file: FileDescriptor, } impl<'a, KT: KindTypes + 'static> fmt::Display for DisplayCursor<'a, KT> { @@ -287,7 +344,7 @@ impl<'a, KT: KindTypes + 'static> fmt::Display for DisplayCursor<'a, KT> { f, "`{}` at {}:{}:{}", self.cursor.node().unparse(), - self.file.unwrap_or(""), + self.file.get_path(), offset.line + 1, offset.column + 1, ) @@ -312,10 +369,11 @@ impl<'a, KT: KindTypes + 'static> Definition<'a, KT> { .and_then(|info| info.definiens.clone()) } - pub fn get_file(&self) -> Option<&'a str> { + pub fn get_file(&self) -> FileDescriptor { self.owner.stack_graph[self.handle] .file() - .map(|file| self.owner.stack_graph[file].name()) + .and_then(|file| FileDescriptor::from_string(self.owner.stack_graph[file].name()).ok()) + .unwrap_or_else(|| unreachable!("Definition does not have a valid file descriptor")) } pub(crate) fn has_tag(&self, tag: Tag) -> bool { @@ -398,10 +456,11 @@ impl<'a, KT: KindTypes + 'static> Reference<'a, KT> { self.owner.cursors.get(&self.handle).cloned() } - pub fn get_file(&self) -> Option<&'a str> { + pub fn get_file(&self) -> FileDescriptor { self.owner.stack_graph[self.handle] .file() - .map(|file| self.owner.stack_graph[file].name()) + .and_then(|file| FileDescriptor::from_string(self.owner.stack_graph[file].name()).ok()) + .unwrap_or_else(|| unreachable!("Reference does not have a valid file descriptor")) } pub fn jump_to_definition(&self) -> Result, ResolutionError<'a, KT>> { diff --git a/crates/solidity/inputs/language/bindings/rules.msgb b/crates/solidity/inputs/language/bindings/rules.msgb index ade66f99a5..15ec5050ad 100644 --- a/crates/solidity/inputs/language/bindings/rules.msgb +++ b/crates/solidity/inputs/language/bindings/rules.msgb @@ -25,11 +25,28 @@ inherit .parent_scope ;; This provides all the exported symbols from the file node @source_unit.defs + ;; Connect to ROOT_NODE to export our symbols node export - attr (export) pop_symbol = FILE_PATH edge ROOT_NODE -> export edge export -> @source_unit.defs + if (is-system-file FILE_PATH) { + ; If this is a system file (aka. built-ins), export everything through this + ; special symbol (which is automatically imported below) + attr (export) pop_symbol = "@@built-ins@@" + + } else { + ; This is a user file, so we want to export under the file's path symbol + attr (export) pop_symbol = FILE_PATH + + ; ... and also import the global built-ins + node built_ins + attr (built_ins) push_symbol = "@@built-ins@@" + + edge @source_unit.lexical_scope -> built_ins + edge built_ins -> ROOT_NODE + } + let @source_unit.enclosing_def = #null ;; This defines a parent_scope at the source unit level (this attribute is @@ -58,6 +75,21 @@ inherit .parent_scope edge @source_unit.defs -> @unit_member.def } +;; Special case for built-ins: we want to export all symbols in the contract: +;; functions, types and state variables. All built-in symbols are defined in an +;; internal contract named '$BuiltIns$' so we need to export all its members and +;; type members directly as a source unit definition. +;; __SLANG_SOLIDITY_BUILT_INS_CONTRACT_NAME__ keep in sync with built-ins generation. +@source_unit [SourceUnit [SourceUnitMembers + [SourceUnitMember @contract [ContractDefinition name: ["$BuiltIns$"]]] +]] { + if (is-system-file FILE_PATH) { + edge @source_unit.defs -> @contract.members + edge @source_unit.defs -> @contract.type_members + edge @source_unit.defs -> @contract.state_vars + } +} + @source_unit [SourceUnit [SourceUnitMembers [SourceUnitMember @using [UsingDirective]]]] { let @using.lexical_scope = @source_unit.lexical_scope edge @source_unit.lexical_scope -> @using.def @@ -80,9 +112,9 @@ inherit .parent_scope )] ]] ]] { - node @import.defs - edge @source_unit.defs -> @import.defs - edge @source_unit.lexical_scope -> @import.defs + node @import.defs + edge @source_unit.defs -> @import.defs + edge @source_unit.lexical_scope -> @import.defs } @@ -257,9 +289,11 @@ inherit .parent_scope node @contract.members node @contract.type_members node @contract.modifiers + node @contract.state_vars edge @contract.lexical_scope -> @contract.members edge @contract.lexical_scope -> @contract.type_members + edge @contract.lexical_scope -> @contract.state_vars ;; Modifiers are available as a contract type members through a special '@modifier' symbol node modifier @@ -386,25 +420,22 @@ inherit .parent_scope } @contract [ContractDefinition [ContractMembers - [ContractMember @member ( - [FunctionDefinition] - | [StateVariableDefinition] - )] + [ContractMember @state_var [StateVariableDefinition]] ]] { - edge @contract.lexical_scope -> @member.def + edge @contract.state_vars -> @state_var.def } ;; Public state variables are also exposed as external member functions -@contract [ContractDefinition [ContractMembers [ContractMember - @state_var [StateVariableDefinition +@contract [ContractDefinition [ContractMembers + [ContractMember @state_var [StateVariableDefinition [StateVariableAttributes [StateVariableAttribute [PublicKeyword]]] - ] -]]] { + ]] +]] { edge @contract.members -> @state_var.def } -@contract [ContractDefinition members: [ContractMembers - item: [ContractMember @function variant: [FunctionDefinition]] +@contract [ContractDefinition [ContractMembers + [ContractMember @function [FunctionDefinition]] ]] { ;; Contract functions are also accessible for an instance of the contract edge @contract.members -> @function.def @@ -416,7 +447,7 @@ inherit .parent_scope } @contract [ContractDefinition members: [ContractMembers - item: [ContractMember @modifier variant: [ModifierDefinition]] + [ContractMember @modifier [ModifierDefinition]] ]] { edge @contract.modifiers -> @modifier.def @@ -1514,7 +1545,6 @@ inherit .parent_scope attr (@state_var.def) node_definition = @name attr (@state_var.def) definiens_node = @state_var - edge @state_var.def -> @state_var.def edge @type_name.type_ref -> @state_var.lexical_scope node typeof diff --git a/crates/solidity/inputs/language/src/bindings.rs b/crates/solidity/inputs/language/src/bindings.rs new file mode 100644 index 0000000000..51984435bd --- /dev/null +++ b/crates/solidity/inputs/language/src/bindings.rs @@ -0,0 +1,55 @@ +use std::fmt::{Error, Write}; + +use codegen_language_definition::model::BuiltIn; + +pub fn render_built_ins(built_ins: &[BuiltIn]) -> String { + try_render_built_ins(built_ins).expect("Failed to render built-ins") +} + +fn try_render_built_ins(built_ins: &[BuiltIn]) -> Result { + let mut buffer = String::new(); + // __SLANG_SOLIDITY_BUILT_INS_CONTRACT_NAME__ keep in sync with binding rules + writeln!(buffer, "contract $BuiltIns$ {{")?; + for item in built_ins { + match item { + BuiltIn::BuiltInFunction { item } => { + writeln!( + buffer, + " function {name}({parameters}) public{return_type};", + name = item.name, + parameters = item.parameters.join(", "), + return_type = item + .return_type + .as_ref() + .map(|return_type| format!(" returns ({return_type})")) + .unwrap_or_default(), + )?; + } + BuiltIn::BuiltInType { item } => { + writeln!(buffer, " struct {name} {{", name = item.name)?; + for field in &item.fields { + writeln!(buffer, " {field_def};", field_def = field.definition)?; + } + for function in &item.functions { + writeln!( + buffer, + " function({parameters}){return_type} {name};", + name = function.name, + return_type = function + .return_type + .as_deref() + .map(|return_type| format!(" returns ({return_type})")) + .unwrap_or_default(), + parameters = function.parameters.join(", "), + )?; + } + writeln!(buffer, " }}")?; + } + BuiltIn::BuiltInVariable { item } => { + writeln!(buffer, " {var_def};", var_def = item.definition)?; + } + } + } + writeln!(buffer, "}}")?; + Ok(buffer) +} diff --git a/crates/solidity/inputs/language/src/definition.rs b/crates/solidity/inputs/language/src/definition.rs index 3c6e281f8e..1a01c3ae95 100644 --- a/crates/solidity/inputs/language/src/definition.rs +++ b/crates/solidity/inputs/language/src/definition.rs @@ -4,6 +4,7 @@ codegen_language_macros::compile!(Language( name = Solidity, documentation_dir = "crates/solidity/inputs/language/docs", binding_rules_file = "crates/solidity/inputs/language/bindings/rules.msgb", + file_extension = ".sol", root_item = SourceUnit, // TODO(#1020): Define the end-of-file trivia explicitly rather than // implicitly reusing the leading trivia in the generater parser code. @@ -6617,5 +6618,46 @@ codegen_language_macros::compile!(Language( ) ] ) + ], + built_ins = [ + BuiltInFunction( + name = "addmod", + parameters = ["uint x", "uint y", "uint k"], + return_type = "uint" + ), + BuiltInFunction(name = "assert", parameters = ["bool condition"]), + BuiltInFunction( + name = "require", + parameters = ["bool condition"], + enabled = From("0.5.0") + ), + BuiltInFunction( + name = "require", + parameters = ["bool condition", "string memory message"], + enabled = From("0.5.0") + ), + BuiltInFunction(name = "revert", parameters = ["string memory reason"]), + BuiltInType( + name = "$BuiltIn$Address", + fields = [ + BuiltInField(definition = "uint256 balance"), + BuiltInField(definition = "bytes code", enabled = From("0.8.0")) + ], + functions = [BuiltInFunction( + name = "send", + parameters = ["uint256 amount"], + return_type = "bool" + )] + ), + BuiltInType( + name = "$BuiltIn$TxType", + fields = [ + BuiltInField(definition = "uint gasprice"), + BuiltInField(definition = "address payable origin") + ], + functions = [] + ), + BuiltInVariable(definition = "uint now"), + BuiltInVariable(definition = "$BuiltIn$TxType tx") ] )); diff --git a/crates/solidity/inputs/language/src/lib.rs b/crates/solidity/inputs/language/src/lib.rs index 364dece810..59f8d775a5 100644 --- a/crates/solidity/inputs/language/src/lib.rs +++ b/crates/solidity/inputs/language/src/lib.rs @@ -1,5 +1,7 @@ //! This crate is responsible for creating the Solidity language definition and exposing it to downstream crates. +mod bindings; mod definition; +pub use bindings::render_built_ins; pub use definition::SolidityDefinition; diff --git a/crates/solidity/outputs/cargo/crate/build.rs b/crates/solidity/outputs/cargo/crate/build.rs index 4423ee5667..7c3bae76a3 100644 --- a/crates/solidity/outputs/cargo/crate/build.rs +++ b/crates/solidity/outputs/cargo/crate/build.rs @@ -4,7 +4,7 @@ use anyhow::Result; use codegen_runtime_generator::RuntimeGenerator; use infra_utils::cargo::CargoWorkspace; -use solidity_language::SolidityDefinition; +use solidity_language::{render_built_ins, SolidityDefinition}; fn main() -> Result<()> { let language = SolidityDefinition::create(); @@ -14,5 +14,12 @@ fn main() -> Result<()> { let output_dir = CargoWorkspace::locate_source_crate("slang_solidity")?.join("src/generated"); - RuntimeGenerator::generate_product(&language, &input_dir, &output_dir) + let mut fs = RuntimeGenerator::generate_product(&language, &input_dir, &output_dir)?; + let built_ins_output_dir = output_dir.join("bindings/generated/built_ins"); + codegen_runtime_generator::render_built_ins( + &mut fs, + &language, + &built_ins_output_dir, + render_built_ins, + ) } diff --git a/crates/solidity/outputs/cargo/crate/generated/public_api.txt b/crates/solidity/outputs/cargo/crate/generated/public_api.txt index 2a7e87b49a..ed8e613a2c 100644 --- a/crates/solidity/outputs/cargo/crate/generated/public_api.txt +++ b/crates/solidity/outputs/cargo/crate/generated/public_api.txt @@ -4,6 +4,7 @@ pub mod slang_solidity pub mod slang_solidity::bindings pub fn slang_solidity::bindings::create_with_resolver(version: semver::Version, resolver: alloc::sync::Arc<(dyn metaslang_bindings::PathResolver + core::marker::Sync + core::marker::Send)>) -> slang_solidity::bindings::Bindings pub fn slang_solidity::bindings::get_binding_rules() -> &'static str +pub fn slang_solidity::bindings::get_built_ins(version: &semver::Version) -> &'static str pub type slang_solidity::bindings::Bindings = metaslang_bindings::Bindings pub type slang_solidity::bindings::Definition<'a> = metaslang_bindings::Definition<'a, slang_solidity::cst::KindTypes> pub type slang_solidity::bindings::Reference<'a> = metaslang_bindings::Reference<'a, slang_solidity::cst::KindTypes> diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/binding_rules.rs b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/binding_rules.rs index 86d7f5ebd2..eb9ad8c9b0 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/binding_rules.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/binding_rules.rs @@ -30,11 +30,28 @@ inherit .parent_scope ;; This provides all the exported symbols from the file node @source_unit.defs + ;; Connect to ROOT_NODE to export our symbols node export - attr (export) pop_symbol = FILE_PATH edge ROOT_NODE -> export edge export -> @source_unit.defs + if (is-system-file FILE_PATH) { + ; If this is a system file (aka. built-ins), export everything through this + ; special symbol (which is automatically imported below) + attr (export) pop_symbol = "@@built-ins@@" + + } else { + ; This is a user file, so we want to export under the file's path symbol + attr (export) pop_symbol = FILE_PATH + + ; ... and also import the global built-ins + node built_ins + attr (built_ins) push_symbol = "@@built-ins@@" + + edge @source_unit.lexical_scope -> built_ins + edge built_ins -> ROOT_NODE + } + let @source_unit.enclosing_def = #null ;; This defines a parent_scope at the source unit level (this attribute is @@ -63,6 +80,21 @@ inherit .parent_scope edge @source_unit.defs -> @unit_member.def } +;; Special case for built-ins: we want to export all symbols in the contract: +;; functions, types and state variables. All built-in symbols are defined in an +;; internal contract named '$BuiltIns$' so we need to export all its members and +;; type members directly as a source unit definition. +;; __SLANG_SOLIDITY_BUILT_INS_CONTRACT_NAME__ keep in sync with built-ins generation. +@source_unit [SourceUnit [SourceUnitMembers + [SourceUnitMember @contract [ContractDefinition name: ["$BuiltIns$"]]] +]] { + if (is-system-file FILE_PATH) { + edge @source_unit.defs -> @contract.members + edge @source_unit.defs -> @contract.type_members + edge @source_unit.defs -> @contract.state_vars + } +} + @source_unit [SourceUnit [SourceUnitMembers [SourceUnitMember @using [UsingDirective]]]] { let @using.lexical_scope = @source_unit.lexical_scope edge @source_unit.lexical_scope -> @using.def @@ -85,9 +117,9 @@ inherit .parent_scope )] ]] ]] { - node @import.defs - edge @source_unit.defs -> @import.defs - edge @source_unit.lexical_scope -> @import.defs + node @import.defs + edge @source_unit.defs -> @import.defs + edge @source_unit.lexical_scope -> @import.defs } @@ -262,9 +294,11 @@ inherit .parent_scope node @contract.members node @contract.type_members node @contract.modifiers + node @contract.state_vars edge @contract.lexical_scope -> @contract.members edge @contract.lexical_scope -> @contract.type_members + edge @contract.lexical_scope -> @contract.state_vars ;; Modifiers are available as a contract type members through a special '@modifier' symbol node modifier @@ -391,25 +425,22 @@ inherit .parent_scope } @contract [ContractDefinition [ContractMembers - [ContractMember @member ( - [FunctionDefinition] - | [StateVariableDefinition] - )] + [ContractMember @state_var [StateVariableDefinition]] ]] { - edge @contract.lexical_scope -> @member.def + edge @contract.state_vars -> @state_var.def } ;; Public state variables are also exposed as external member functions -@contract [ContractDefinition [ContractMembers [ContractMember - @state_var [StateVariableDefinition +@contract [ContractDefinition [ContractMembers + [ContractMember @state_var [StateVariableDefinition [StateVariableAttributes [StateVariableAttribute [PublicKeyword]]] - ] -]]] { + ]] +]] { edge @contract.members -> @state_var.def } -@contract [ContractDefinition members: [ContractMembers - item: [ContractMember @function variant: [FunctionDefinition]] +@contract [ContractDefinition [ContractMembers + [ContractMember @function [FunctionDefinition]] ]] { ;; Contract functions are also accessible for an instance of the contract edge @contract.members -> @function.def @@ -421,7 +452,7 @@ inherit .parent_scope } @contract [ContractDefinition members: [ContractMembers - item: [ContractMember @modifier variant: [ModifierDefinition]] + [ContractMember @modifier [ModifierDefinition]] ]] { edge @contract.modifiers -> @modifier.def @@ -1519,7 +1550,6 @@ inherit .parent_scope attr (@state_var.def) node_definition = @name attr (@state_var.def) definiens_node = @state_var - edge @state_var.def -> @state_var.def edge @type_name.type_ref -> @state_var.lexical_scope node typeof diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs new file mode 100644 index 0000000000..84fa153e90 --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs @@ -0,0 +1,14 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use semver::Version; + +#[allow(unused_variables)] +pub fn get_contents(version: &Version) -> &'static str { + if *version < Version::new(0, 5, 0) { + include_str!("./built_ins/0.4.11.sol") + } else if *version < Version::new(0, 8, 0) { + include_str!("./built_ins/0.5.0.sol") + } else { + include_str!("./built_ins/0.8.0.sol") + } +} diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.11.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.11.sol new file mode 100644 index 0000000000..01facdfd34 --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.11.sol @@ -0,0 +1,17 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +contract $BuiltIns$ { + function addmod(uint x, uint y, uint k) public returns (uint); + function assert(bool condition) public; + function revert(string memory reason) public; + struct $BuiltIn$Address { + uint256 balance; + function(uint256 amount) returns (bool) send; + } + struct $BuiltIn$TxType { + uint gasprice; + address payable origin; + } + uint now; + $BuiltIn$TxType tx; +} diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.5.0.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.5.0.sol new file mode 100644 index 0000000000..2308b12c25 --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.5.0.sol @@ -0,0 +1,19 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +contract $BuiltIns$ { + function addmod(uint x, uint y, uint k) public returns (uint); + function assert(bool condition) public; + function require(bool condition) public; + function require(bool condition, string memory message) public; + function revert(string memory reason) public; + struct $BuiltIn$Address { + uint256 balance; + function(uint256 amount) returns (bool) send; + } + struct $BuiltIn$TxType { + uint gasprice; + address payable origin; + } + uint now; + $BuiltIn$TxType tx; +} diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.0.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.0.sol new file mode 100644 index 0000000000..494cd74c52 --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.0.sol @@ -0,0 +1,20 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +contract $BuiltIns$ { + function addmod(uint x, uint y, uint k) public returns (uint); + function assert(bool condition) public; + function require(bool condition) public; + function require(bool condition, string memory message) public; + function revert(string memory reason) public; + struct $BuiltIn$Address { + uint256 balance; + bytes code; + function(uint256 amount) returns (bool) send; + } + struct $BuiltIn$TxType { + uint gasprice; + address payable origin; + } + uint now; + $BuiltIn$TxType tx; +} diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/mod.rs b/crates/solidity/outputs/cargo/crate/src/generated/bindings/mod.rs index c04d7cd11a..66c8a8c4da 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/mod.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/mod.rs @@ -3,6 +3,9 @@ #[path = "generated/binding_rules.rs"] mod binding_rules; +#[path = "generated/built_ins.rs"] +mod built_ins; + use std::sync::Arc; use metaslang_bindings::{self, PathResolver}; @@ -25,3 +28,7 @@ pub fn create_with_resolver( pub fn get_binding_rules() -> &'static str { binding_rules::BINDING_RULES_SOURCE } + +pub fn get_built_ins(version: &semver::Version) -> &'static str { + built_ins::get_contents(version) +} diff --git a/crates/solidity/outputs/cargo/tests/src/bindings.rs b/crates/solidity/outputs/cargo/tests/src/bindings.rs new file mode 100644 index 0000000000..64b16595de --- /dev/null +++ b/crates/solidity/outputs/cargo/tests/src/bindings.rs @@ -0,0 +1,22 @@ +use std::sync::Arc; + +use anyhow::Result; +use semver::Version; +use slang_solidity::bindings::{self, Bindings}; +use slang_solidity::parser::Parser; + +use crate::resolver::TestsPathResolver; + +pub fn create_bindings(version: &Version) -> Result { + let parser = Parser::create(version.clone())?; + let mut bindings = + bindings::create_with_resolver(version.clone(), Arc::new(TestsPathResolver {})); + + let built_ins_parse_output = parser.parse(Parser::ROOT_KIND, bindings::get_built_ins(version)); + assert!( + built_ins_parse_output.is_valid(), + "built-ins parse without errors" + ); + bindings.add_system_file("built_ins.sol", built_ins_parse_output.create_tree_cursor()); + Ok(bindings) +} diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/assertions.rs b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/assertions.rs index 5421ff4b92..f52a0085c3 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/assertions.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/assertions.rs @@ -87,7 +87,7 @@ impl<'a> fmt::Display for DefinitionAssertion<'a> { f, "Assert Definition {id} {cursor}", id = self.id, - cursor = DisplayCursor(&self.cursor, Some(self.file)), + cursor = DisplayCursor(&self.cursor, self.file), ) } } @@ -103,11 +103,11 @@ impl<'a> fmt::Display for ReferenceAssertion<'a> { if let Some(version_req) = &self.version_req { write!(f, " in versions {version_req}")?; } - write!(f, " {}", DisplayCursor(&self.cursor, Some(self.file))) + write!(f, " {}", DisplayCursor(&self.cursor, self.file)) } } -struct DisplayCursor<'a>(&'a Cursor, Option<&'a str>); +struct DisplayCursor<'a>(&'a Cursor, &'a str); impl<'a> fmt::Display for DisplayCursor<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -116,7 +116,7 @@ impl<'a> fmt::Display for DisplayCursor<'a> { f, "`{}` at {}:{}:{}", self.0.node().unparse(), - self.1.unwrap_or(""), + self.1, offset.line + 1, offset.column + 1, ) @@ -415,7 +415,7 @@ fn check_reference_assertion( let resolved_file = resolved_handle.get_file(); return Err(format!( "{assertion} failed: expected not to resolve, but instead resolved to {resolved}", - resolved = DisplayCursor(&resolved_cursor, resolved_file) + resolved = DisplayCursor(&resolved_cursor, resolved_file.get_path()) )); } } @@ -431,8 +431,8 @@ fn check_reference_assertion( if expected_cursor != resolved_cursor { return Err(format!( "{assertion} failed: expected resolve to {expected}, but instead resolved to {resolved}", - resolved = DisplayCursor(&resolved_cursor, resolved_handle.get_file()), - expected = DisplayCursor(&expected_cursor, expected_handle.get_file()), + resolved = DisplayCursor(&resolved_cursor, resolved_handle.get_file().get_path()), + expected = DisplayCursor(&expected_cursor, expected_handle.get_file().get_path()), )); } } @@ -452,7 +452,8 @@ fn check_reference_assertion( if referenced_cursor == resolved_cursor { return Err(format!( "{assertion} failed: expected to not resolve to {resolved} in this version", - resolved = DisplayCursor(&resolved_cursor, resolved_handle.get_file()), + resolved = + DisplayCursor(&resolved_cursor, resolved_handle.get_file().get_path()), )); } } diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/runner.rs b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/runner.rs index 93f982be82..fc009f9a68 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/runner.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/runner.rs @@ -1,18 +1,17 @@ use std::fs; -use std::sync::Arc; use anyhow::Result; use infra_utils::cargo::CargoWorkspace; use semver::Version; +use slang_solidity::diagnostic; use slang_solidity::parser::Parser; -use slang_solidity::{bindings, diagnostic}; +use crate::bindings::create_bindings; use crate::bindings_assertions::assertions::{ check_assertions, collect_assertions_into, Assertions, }; use crate::generated::VERSION_BREAKS; use crate::multi_part_file::{split_multi_file, Part}; -use crate::resolver::TestsPathResolver; pub fn run(group_name: &str, test_name: &str) -> Result<()> { let file_name = format!("{test_name}.sol"); @@ -30,8 +29,8 @@ pub fn run(group_name: &str, test_name: &str) -> Result<()> { fn check_assertions_with_version(version: &Version, contents: &str) -> Result<()> { let parser = Parser::create(version.clone())?; - let mut bindings = - bindings::create_with_resolver(version.clone(), Arc::new(TestsPathResolver {})); + let mut bindings = create_bindings(version)?; + let mut assertions = Assertions::new(); let mut skipped = 0; @@ -54,7 +53,7 @@ fn check_assertions_with_version(version: &Version, contents: &str) -> Result<() eprintln!("\nParse errors for version {version}\nFile: {file_path}\n{report}"); } - bindings.add_file(file_path, parse_output.create_tree_cursor()); + bindings.add_user_file(file_path, parse_output.create_tree_cursor()); skipped += collect_assertions_into( &mut assertions, parse_output.create_tree_cursor(), diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/built_ins.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/built_ins.rs new file mode 100644 index 0000000000..24ed6f0f12 --- /dev/null +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/built_ins.rs @@ -0,0 +1,15 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use anyhow::Result; + +use crate::bindings_output::runner::run; + +#[test] +fn functions() -> Result<()> { + run("built_ins", "functions") +} + +#[test] +fn global_properties() -> Result<()> { + run("built_ins", "global_properties") +} diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/mod.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/mod.rs index 4cf2c8df17..21535aaec2 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/mod.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/mod.rs @@ -1,5 +1,6 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +mod built_ins; mod contracts; mod control; mod enums; diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs index f553099805..7298d965d5 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs @@ -1,123 +1,160 @@ +use std::iter::once; use std::ops::Range; use anyhow::Result; use ariadne::{Color, Config, FnCache, Label, Report, ReportBuilder, ReportKind, Source}; use metaslang_bindings::ResolutionError; -use slang_solidity::bindings::{Bindings, Definition}; +use slang_solidity::bindings::{Bindings, Definition, Reference}; use slang_solidity::diagnostic; use super::runner::ParsedPart; +type ReportSpan<'a> = (&'a str, Range); + pub(crate) fn render_bindings( bindings: &Bindings, parsed_parts: &[ParsedPart<'_>], -) -> Result { +) -> Result<(String, bool)> { let mut buffer: Vec = Vec::new(); + let mut all_resolved = true; - let mut definitions: Vec> = Vec::new(); - for definition in bindings.all_definitions() { - if definition.get_cursor().is_some() { - definitions.push(definition); - }; - } + let all_definitions = collect_all_definitions(bindings); for part in parsed_parts { - let mut builder: ReportBuilder<'_, (&str, Range)> = Report::build( - ReportKind::Custom("References and definitions", Color::Unset), - part.path, - 0, - ) - .with_config(Config::default().with_color(false)); - if !part.parse_output.is_valid() { - let mut report = part - .parse_output - .errors() - .iter() - .map(|error| diagnostic::render(error, part.path, part.contents, false)) - .collect::>() - .join("\n") - .into_bytes(); + let mut parse_errors_report = part.parse_errors_report().into_bytes(); buffer.extend_from_slice("Parse errors:\n".as_bytes()); - buffer.append(&mut report); + buffer.append(&mut parse_errors_report); buffer.push(b'\n'); } - for (index, definition) in definitions.iter().enumerate() { - let Some(cursor) = definition.get_cursor() else { - continue; - }; - let def_file = definition - .get_file() - .expect("definition should be in a file"); - if def_file != part.path { - continue; - } + let part_references = bindings + .all_references() + .filter(|reference| reference.get_file().is_user_path(part.path)); + let (bindings_report, part_all_resolved) = + build_report_for_part(part, &all_definitions, part_references); + all_resolved = all_resolved && part_all_resolved; - let range = { - let range = cursor.text_range(); - let start = part.contents[..range.start.utf8].chars().count(); - let end = part.contents[..range.end.utf8].chars().count(); - start..end - }; + let file_cache = FnCache::new( + (move |id| Err(Box::new(format!("Failed to fetch source '{id}'")) as _)) as fn(&_) -> _, + ) + .with_sources( + once(part) + .map(|part| (part.path, Source::from(part.contents))) + .collect(), + ); + bindings_report.write(file_cache, &mut buffer)?; + } - let message = format!("def: {}", index + 1); - builder = builder.with_label(Label::new((part.path, range)).with_message(message)); + let result = String::from_utf8(buffer)?; + Ok((result, all_resolved)) +} + +// We collect all non built-in definitions in a vector to be able to identify +// them by a numeric index +fn collect_all_definitions(bindings: &Bindings) -> Vec> { + let mut definitions: Vec> = Vec::new(); + for definition in bindings.all_definitions() { + if definition.get_file().is_user() && definition.get_cursor().is_some() { + definitions.push(definition); } + } + definitions +} - for reference in bindings.all_references() { - let Some(cursor) = reference.get_cursor() else { - continue; - }; - let ref_file = reference.get_file().expect("reference should be in a file"); - if ref_file != part.path { - continue; - } +impl ParsedPart<'_> { + fn parse_errors_report(&self) -> String { + self.parse_output + .errors() + .iter() + .map(|error| diagnostic::render(error, self.path, self.contents, false)) + .collect::>() + .join("\n") + } +} + +fn build_report_for_part<'a>( + part: &'a ParsedPart<'a>, + all_definitions: &'a [Definition<'a>], + part_references: impl Iterator> + 'a, +) -> (Report<'a, ReportSpan<'a>>, bool) { + let mut builder: ReportBuilder<'_, ReportSpan<'_>> = Report::build( + ReportKind::Custom("References and definitions", Color::Unset), + part.path, + 0, + ) + .with_config(Config::default().with_color(false)); - let range = { - let range = cursor.text_range(); - let start = part.contents[..range.start.utf8].chars().count(); - let end = part.contents[..range.end.utf8].chars().count(); - start..end - }; - - let definition = reference.jump_to_definition(); - let message = match definition { - Ok(definition) => { - let def_id = definitions.iter().position(|d| *d == definition).unwrap(); + for (index, definition) in all_definitions.iter().enumerate() { + let Some(cursor) = definition.get_cursor() else { + continue; + }; + if !definition.get_file().is_user_path(part.path) { + continue; + } + + let range = { + let range = cursor.text_range(); + let start = part.contents[..range.start.utf8].chars().count(); + let end = part.contents[..range.end.utf8].chars().count(); + start..end + }; + + let message = format!("def: {}", index + 1); + builder = builder.with_label(Label::new((part.path, range)).with_message(message)); + } + + let mut all_resolved = true; + + for reference in part_references { + let Some(cursor) = reference.get_cursor() else { + continue; + }; + + let range = { + let range = cursor.text_range(); + let start = part.contents[..range.start.utf8].chars().count(); + let end = part.contents[..range.end.utf8].chars().count(); + start..end + }; + + let definition = reference.jump_to_definition(); + let message = match definition { + Ok(definition) => { + if definition.get_file().is_system() { + "ref: built-in".to_string() + } else { + let def_id = all_definitions + .iter() + .position(|d| *d == definition) + .unwrap(); format!("ref: {}", def_id + 1) } - Err(ResolutionError::Unresolved) => "unresolved".to_string(), - Err(ResolutionError::AmbiguousDefinitions(ambiguous_definitions)) => { - let ref_labels = ambiguous_definitions - .iter() - .filter_map(|ambiguous_definition| { - definitions + } + Err(ResolutionError::Unresolved) => { + all_resolved = false; + "unresolved".to_string() + } + Err(ResolutionError::AmbiguousDefinitions(ambiguous_definitions)) => { + let ref_labels = ambiguous_definitions + .iter() + .filter_map(|ambiguous_definition| { + if ambiguous_definition.get_file().is_system() { + Some("built-in".to_string()) + } else { + all_definitions .iter() .position(|d| d == ambiguous_definition) - .map(|index| format!("ref: {}", index + 1)) - }) - .collect::>(); - format!("ambiguous: {}", ref_labels.join(", ")) - } - }; - - builder = builder.with_label(Label::new((part.path, range)).with_message(message)); - } + .map(|index| format!("{}", index + 1)) + } + }) + .collect::>(); + format!("refs: {ref_labels}", ref_labels = ref_labels.join(", ")) + } + }; - let report = builder.finish(); - let file_cache = FnCache::new( - (move |id| Err(Box::new(format!("Failed to fetch source '{id}'")) as _)) as fn(&_) -> _, - ) - .with_sources( - parsed_parts - .iter() - .map(|part| (part.path, Source::from(part.contents))) - .collect(), - ); - report.write(file_cache, &mut buffer)?; + builder = builder.with_label(Label::new((part.path, range)).with_message(message)); } - let result = String::from_utf8(buffer)?; - Ok(result) + (builder.finish(), all_resolved) } diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/runner.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/runner.rs index 58027ab1f9..80f0b05d0e 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/runner.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/runner.rs @@ -1,21 +1,18 @@ -use std::sync::Arc; - use anyhow::Result; use infra_utils::cargo::CargoWorkspace; use infra_utils::codegen::CodegenFileSystem; use infra_utils::github::GitHub; use infra_utils::paths::PathExtensions; use metaslang_graph_builder::graph::Graph; -use slang_solidity::bindings; use slang_solidity::cst::KindTypes; use slang_solidity::parser::{ParseOutput, Parser}; use super::graph::graphviz::render as render_graphviz_graph; use super::graph::mermaid::render as render_mermaid_graph; use super::renderer::render_bindings; +use crate::bindings::create_bindings; use crate::generated::VERSION_BREAKS; use crate::multi_part_file::{split_multi_file, Part}; -use crate::resolver::TestsPathResolver; pub(crate) struct ParsedPart<'a> { pub path: &'a str, @@ -40,10 +37,9 @@ pub fn run(group_name: &str, test_name: &str) -> Result<()> { for version in &VERSION_BREAKS { let parser = Parser::create(version.clone())?; - let mut bindings = - bindings::create_with_resolver(version.clone(), Arc::new(TestsPathResolver {})); - let mut parsed_parts: Vec> = Vec::new(); + let mut bindings = create_bindings(version)?; + let mut parsed_parts: Vec> = Vec::new(); let multi_part = split_multi_file(&contents); for Part { name: path, @@ -51,7 +47,8 @@ pub fn run(group_name: &str, test_name: &str) -> Result<()> { } in &multi_part.parts { let parse_output = parser.parse(Parser::ROOT_KIND, contents); - let graph = bindings.add_file_returning_graph(path, parse_output.create_tree_cursor()); + let graph = + bindings.add_user_file_returning_graph(path, parse_output.create_tree_cursor()); parsed_parts.push(ParsedPart { path, contents, @@ -59,8 +56,6 @@ pub fn run(group_name: &str, test_name: &str) -> Result<()> { graph, }); } - let parse_success = parsed_parts.iter().all(|part| part.parse_output.is_valid()); - let parse_status = if parse_success { "success" } else { "failure" }; if let Some(context) = multi_part.context { let context_definition = bindings @@ -70,6 +65,15 @@ pub fn run(group_name: &str, test_name: &str) -> Result<()> { bindings.set_context(&context_definition); } + let (bindings_output, all_resolved) = render_bindings(&bindings, &parsed_parts)?; + + let parse_success = parsed_parts.iter().all(|part| part.parse_output.is_valid()); + let status = if parse_success && all_resolved { + "success" + } else { + "failure" + }; + if !GitHub::is_running_in_ci() { // Don't run this in CI, since the graph outputs are not committed // to the repository and hence we cannot verify their contents, @@ -80,7 +84,7 @@ pub fn run(group_name: &str, test_name: &str) -> Result<()> { _ => { let snapshot_path = test_dir .join("generated") - .join(format!("{version}-{parse_status}.mmd")); + .join(format!("{version}-{status}.mmd")); fs.write_file(snapshot_path, &graph_output)?; last_graph_output = Some(graph_output); @@ -88,19 +92,18 @@ pub fn run(group_name: &str, test_name: &str) -> Result<()> { let dot_output = render_graphviz_graph(&parsed_parts); let dot_output_path = test_dir .join("generated") - .join(format!("{version}-{parse_status}.dot")); + .join(format!("{version}-{status}.dot")); fs.write_file(dot_output_path, &dot_output)?; } }; } - let bindings_output = render_bindings(&bindings, &parsed_parts)?; match last_bindings_output { Some(ref last) if last == &bindings_output => (), _ => { let snapshot_path = test_dir .join("generated") - .join(format!("{version}-{parse_status}.txt")); + .join(format!("{version}-{status}.txt")); fs.write_file(snapshot_path, &bindings_output)?; last_bindings_output = Some(bindings_output); diff --git a/crates/solidity/outputs/cargo/tests/src/built_ins.rs b/crates/solidity/outputs/cargo/tests/src/built_ins.rs new file mode 100644 index 0000000000..995602d5cb --- /dev/null +++ b/crates/solidity/outputs/cargo/tests/src/built_ins.rs @@ -0,0 +1,27 @@ +use anyhow::Result; +use slang_solidity::parser::Parser; +use slang_solidity::{bindings, diagnostic}; + +use crate::generated::VERSION_BREAKS; + +#[test] +fn test_built_ins_parse_successfully() -> Result<()> { + for version in &VERSION_BREAKS { + let built_ins = bindings::get_built_ins(version); + let parser = Parser::create(version.clone())?; + let parse_output = parser.parse(Parser::ROOT_KIND, built_ins); + + let report = parse_output + .errors() + .iter() + .map(|error| diagnostic::render(error, "built-ins", built_ins, false)) + .collect::>() + .join("\n"); + assert!( + parse_output.is_valid(), + "Failed to parse built-ins with version {version}: {report}" + ); + } + + Ok(()) +} diff --git a/crates/solidity/outputs/cargo/tests/src/lib.rs b/crates/solidity/outputs/cargo/tests/src/lib.rs index 16187eb2fa..b62d53c1a2 100644 --- a/crates/solidity/outputs/cargo/tests/src/lib.rs +++ b/crates/solidity/outputs/cargo/tests/src/lib.rs @@ -3,8 +3,10 @@ use metaslang_bindings as _; mod binding_rules; +mod bindings; mod bindings_assertions; mod bindings_output; +mod built_ins; mod cst_output; mod doc_examples; mod generated; diff --git a/crates/solidity/outputs/cargo/wasm/build.rs b/crates/solidity/outputs/cargo/wasm/build.rs index afd4c936e8..4d86bb1bef 100644 --- a/crates/solidity/outputs/cargo/wasm/build.rs +++ b/crates/solidity/outputs/cargo/wasm/build.rs @@ -12,5 +12,5 @@ fn main() -> Result<()> { let output_dir = CargoWorkspace::locate_source_crate("solidity_cargo_wasm")?.join("src/generated"); - RuntimeGenerator::generate_product(&language, &input_dir, &output_dir) + RuntimeGenerator::generate_product(&language, &input_dir, &output_dir).map(|_| ()) } diff --git a/crates/solidity/outputs/npm/package/build.rs b/crates/solidity/outputs/npm/package/build.rs index 59e685334f..85f35f66d1 100644 --- a/crates/solidity/outputs/npm/package/build.rs +++ b/crates/solidity/outputs/npm/package/build.rs @@ -12,5 +12,5 @@ fn main() -> Result<()> { let output_dir = CargoWorkspace::locate_source_crate("solidity_npm_package")?.join("src/generated"); - RuntimeGenerator::generate_product(&language, &input_dir, &output_dir) + RuntimeGenerator::generate_product(&language, &input_dir, &output_dir).map(|_| ()) } diff --git a/crates/solidity/testing/perf/benches/iai/main.rs b/crates/solidity/testing/perf/benches/iai/main.rs index 7c45652994..d5408e08b5 100644 --- a/crates/solidity/testing/perf/benches/iai/main.rs +++ b/crates/solidity/testing/perf/benches/iai/main.rs @@ -36,9 +36,14 @@ fn query(files: Vec) { black_box(tests::query::run(&files)); } +#[library_benchmark] +fn init_bindings() { + black_box(tests::init_bindings::run()); +} + #[library_benchmark(setup = tests::definitions::setup)] -fn definitions(files: Vec) { - black_box(tests::definitions::run(&files)); +fn definitions(dependencies: tests::definitions::Dependencies) { + black_box(tests::definitions::run(dependencies)); } #[library_benchmark(setup = tests::references::setup)] @@ -49,7 +54,7 @@ fn references(bindings: Bindings) { library_benchmark_group!( name = benchmarks; - benchmarks = parser, cursor, query, definitions, references + benchmarks = parser, cursor, query, init_bindings, definitions, references ); main!( diff --git a/crates/solidity/testing/perf/benches/iai/tests/definitions.rs b/crates/solidity/testing/perf/benches/iai/tests/definitions.rs index 12e8d02471..dc7bf063bd 100644 --- a/crates/solidity/testing/perf/benches/iai/tests/definitions.rs +++ b/crates/solidity/testing/perf/benches/iai/tests/definitions.rs @@ -1,29 +1,34 @@ -use std::sync::Arc; - -use metaslang_bindings::PathResolver; -use slang_solidity::bindings::{create_with_resolver, Bindings}; +use slang_solidity::bindings::Bindings; use slang_solidity::cst::TextIndex; -use crate::dataset::SOLC_VERSION; use crate::tests::parser::ParsedFile; -pub fn setup() -> Vec { - let files = super::parser::setup(); +pub struct Dependencies { + pub bindings: Bindings, + pub files: Vec, +} + +pub fn setup() -> Dependencies { + let bindings = super::init_bindings::run(); + let files = super::parser::run(super::parser::setup()); - super::parser::run(files) + Dependencies { bindings, files } } -pub fn run(files: &[ParsedFile]) -> Bindings { +pub fn run(dependencies: Dependencies) -> Bindings { let mut definition_count = 0_usize; - let mut bindings = create_with_resolver(SOLC_VERSION, Arc::new(NoOpResolver {})); + let Dependencies { + mut bindings, + files, + } = dependencies; for ParsedFile { path, contents: _, tree, - } in files + } in &files { - bindings.add_file( + bindings.add_user_file( path.to_str().unwrap(), tree.cursor_with_offset(TextIndex::ZERO), ); @@ -38,11 +43,3 @@ pub fn run(files: &[ParsedFile]) -> Bindings { bindings } - -struct NoOpResolver; - -impl PathResolver for NoOpResolver { - fn resolve_path(&self, _context_path: &str, path_to_resolve: &str) -> Option { - Some(path_to_resolve.to_string()) - } -} diff --git a/crates/solidity/testing/perf/benches/iai/tests/init_bindings.rs b/crates/solidity/testing/perf/benches/iai/tests/init_bindings.rs new file mode 100644 index 0000000000..e3837b8816 --- /dev/null +++ b/crates/solidity/testing/perf/benches/iai/tests/init_bindings.rs @@ -0,0 +1,28 @@ +use std::sync::Arc; + +use metaslang_bindings::PathResolver; +use slang_solidity::bindings::{create_with_resolver, get_built_ins, Bindings}; +use slang_solidity::parser::Parser; + +use crate::dataset::SOLC_VERSION; + +pub fn run() -> Bindings { + let parser = Parser::create(SOLC_VERSION).unwrap(); + let mut bindings = create_with_resolver(SOLC_VERSION, Arc::new(NoOpResolver {})); + + let built_ins_parse_output = parser.parse(Parser::ROOT_KIND, get_built_ins(&SOLC_VERSION)); + assert!( + built_ins_parse_output.is_valid(), + "built-ins parse without errors" + ); + bindings.add_system_file("built_ins.sol", built_ins_parse_output.create_tree_cursor()); + bindings +} + +struct NoOpResolver; + +impl PathResolver for NoOpResolver { + fn resolve_path(&self, _context_path: &str, path_to_resolve: &str) -> Option { + Some(path_to_resolve.to_string()) + } +} diff --git a/crates/solidity/testing/perf/benches/iai/tests/mod.rs b/crates/solidity/testing/perf/benches/iai/tests/mod.rs index 57805e7041..d593675b64 100644 --- a/crates/solidity/testing/perf/benches/iai/tests/mod.rs +++ b/crates/solidity/testing/perf/benches/iai/tests/mod.rs @@ -1,5 +1,6 @@ pub mod cursor; pub mod definitions; +pub mod init_bindings; pub mod parser; pub mod query; pub mod references; diff --git a/crates/solidity/testing/perf/benches/iai/tests/references.rs b/crates/solidity/testing/perf/benches/iai/tests/references.rs index 4e2df5b1d8..c3f41ee8d7 100644 --- a/crates/solidity/testing/perf/benches/iai/tests/references.rs +++ b/crates/solidity/testing/perf/benches/iai/tests/references.rs @@ -1,9 +1,9 @@ use slang_solidity::bindings::Bindings; pub fn setup() -> Bindings { - let trees = super::definitions::setup(); + let dependencies = super::definitions::setup(); - super::definitions::run(&trees) + super::definitions::run(dependencies) } pub fn run(bindings: &Bindings) { diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.11-failure.txt new file mode 100644 index 0000000000..2663a5e58d --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.11-failure.txt @@ -0,0 +1,29 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract BuiltInsTest { + │ ──────┬───── + │ ╰─────── def: 1 + 2 │ function testRequire() public { + │ ─────┬───── + │ ╰─────── def: 2 + 3 │ require(true, "should always succeed"); + │ ───┬─── + │ ╰───── unresolved + │ + 6 │ function testRevert() public { + │ ─────┬──── + │ ╰────── def: 3 + 7 │ revert("testing revert"); + │ ───┬── + │ ╰──── ref: built-in + │ + 10 │ function testAssert() public { + │ ─────┬──── + │ ╰────── def: 4 + 11 │ assert(2 + 2 == 4); + │ ───┬── + │ ╰──── ref: built-in +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.5.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.5.0-success.txt new file mode 100644 index 0000000000..49045c3e07 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.5.0-success.txt @@ -0,0 +1,29 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract BuiltInsTest { + │ ──────┬───── + │ ╰─────── def: 1 + 2 │ function testRequire() public { + │ ─────┬───── + │ ╰─────── def: 2 + 3 │ require(true, "should always succeed"); + │ ───┬─── + │ ╰───── refs: built-in, built-in + │ + 6 │ function testRevert() public { + │ ─────┬──── + │ ╰────── def: 3 + 7 │ revert("testing revert"); + │ ───┬── + │ ╰──── ref: built-in + │ + 10 │ function testAssert() public { + │ ─────┬──── + │ ╰────── def: 4 + 11 │ assert(2 + 2 == 4); + │ ───┬── + │ ╰──── ref: built-in +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.4-success.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.4-success.txt new file mode 100644 index 0000000000..22ccf3a118 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.4-success.txt @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract BuiltInsTest { + │ ──────┬───── + │ ╰─────── def: 1 + 2 │ function testRequire() public { + │ ─────┬───── + │ ╰─────── def: 2 + 3 │ require(true, "should always succeed"); + │ ───┬─── + │ ╰───── refs: built-in, built-in + │ + 6 │ function testRevert() public { + │ ─────┬──── + │ ╰────── def: 3 + │ + 10 │ function testAssert() public { + │ ─────┬──── + │ ╰────── def: 4 + 11 │ assert(2 + 2 == 4); + │ ───┬── + │ ╰──── ref: built-in +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/input.sol b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/input.sol new file mode 100644 index 0000000000..85cc7b46b5 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/input.sol @@ -0,0 +1,13 @@ +contract BuiltInsTest { + function testRequire() public { + require(true, "should always succeed"); + } + + function testRevert() public { + revert("testing revert"); + } + + function testAssert() public { + assert(2 + 2 == 4); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/global_properties/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/global_properties/generated/0.4.11-success.txt new file mode 100644 index 0000000000..5e8ff0bca0 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/global_properties/generated/0.4.11-success.txt @@ -0,0 +1,34 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ uint last_time; + │ ────┬──── + │ ╰────── def: 2 + 3 │ function foo() public { + │ ─┬─ + │ ╰─── def: 3 + 4 │ address origin = tx.origin; + │ ───┬── ─┬ ───┬── + │ ╰──────────────── def: 4 + │ │ │ + │ ╰───────── ref: built-in + │ │ + │ ╰──── ref: built-in + 5 │ last_time = now; + │ ────┬──── ─┬─ + │ ╰──────────── ref: 2 + │ │ + │ ╰─── ref: built-in + 6 │ uint price = tx.gasprice; + │ ──┬── ─┬ ────┬─── + │ ╰────────────────── def: 5 + │ │ │ + │ ╰─────────── ref: built-in + │ │ + │ ╰───── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/global_properties/input.sol b/crates/solidity/testing/snapshots/bindings_output/built_ins/global_properties/input.sol new file mode 100644 index 0000000000..78c528e193 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/global_properties/input.sol @@ -0,0 +1,8 @@ +contract Test { + uint last_time; + function foo() public { + address origin = tx.origin; + last_time = now; + uint price = tx.gasprice; + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/generated/0.4.11-failure.txt index c5b652de3f..a736696118 100644 --- a/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/generated/0.4.11-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/generated/0.4.11-failure.txt @@ -19,11 +19,11 @@ References and definitions: │ ╰───────────────────── def: 2 │ │ │ ╰──── def: 3 - 3 │ require(_addr != address(0), "Not valid address"); - │ ───┬─── ──┬── - │ ╰─────────── unresolved - │ │ - │ ╰──── ref: 3 + 3 │ assert(_addr != address(0)); + │ ───┬── ──┬── + │ ╰────────── ref: built-in + │ │ + │ ╰──── ref: 3 4 │ _; │ ┬ │ ╰── unresolved diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/generated/0.4.22-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/generated/0.4.22-failure.txt similarity index 82% rename from crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/generated/0.4.22-success.txt rename to crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/generated/0.4.22-failure.txt index 0025d23e4c..9e05c1d54b 100644 --- a/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/generated/0.4.22-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/generated/0.4.22-failure.txt @@ -11,11 +11,11 @@ References and definitions: │ ╰───────────────────── def: 2 │ │ │ ╰──── def: 3 - 3 │ require(_addr != address(0), "Not valid address"); - │ ───┬─── ──┬── - │ ╰─────────── unresolved - │ │ - │ ╰──── ref: 3 + 3 │ assert(_addr != address(0)); + │ ───┬── ──┬── + │ ╰────────── ref: built-in + │ │ + │ ╰──── ref: 3 4 │ _; │ ┬ │ ╰── unresolved diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/input.sol index 0adbd8767d..0398426588 100644 --- a/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/input.sol +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_modifier/input.sol @@ -1,6 +1,6 @@ contract Test { modifier validAddress(address _addr) { - require(_addr != address(0), "Not valid address"); + assert(_addr != address(0)); _; } diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/public_getters/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/public_getters/generated/0.4.11-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/contracts/public_getters/generated/0.4.11-success.txt rename to crates/solidity/testing/snapshots/bindings_output/contracts/public_getters/generated/0.4.11-failure.txt diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/super_linearisation/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/super_linearisation/generated/0.4.11-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/contracts/super_linearisation/generated/0.4.11-success.txt rename to crates/solidity/testing/snapshots/bindings_output/contracts/super_linearisation/generated/0.4.11-failure.txt diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.4.16-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.4.16-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.4.16-success.txt rename to crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.4.16-failure.txt diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.6.0-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.6.0-success.txt rename to crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.6.0-failure.txt diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/this_scope/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/this_scope/generated/0.4.11-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/contracts/this_scope/generated/0.4.11-success.txt rename to crates/solidity/testing/snapshots/bindings_output/contracts/this_scope/generated/0.4.11-failure.txt diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.4.16-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.4.16-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.4.16-success.txt rename to crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.4.16-failure.txt diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.6.0-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.6.0-success.txt rename to crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.6.0-failure.txt diff --git a/crates/solidity/testing/snapshots/bindings_output/control/if_else/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/control/if_else/generated/0.4.11-success.txt index d247bc29d3..b096844b53 100644 --- a/crates/solidity/testing/snapshots/bindings_output/control/if_else/generated/0.4.11-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/control/if_else/generated/0.4.11-success.txt @@ -36,15 +36,13 @@ References and definitions: │ │ │ ╰── ref: 3 │ - 12 │ int r = y + z + w; - │ ┬ ┬ ┬ ┬ - │ ╰────────────── def: 7 - │ │ │ │ - │ ╰────────── ref: 4 - │ │ │ - │ ╰────── ref: 5 - │ │ - │ ╰── ref: 6 + 12 │ int r = x + y; + │ ┬ ┬ ┬ + │ ╰────────── def: 7 + │ │ │ + │ ╰────── ref: 3 + │ │ + │ ╰── ref: 4 13 │ return r; │ ┬ │ ╰── ref: 7 diff --git a/crates/solidity/testing/snapshots/bindings_output/control/if_else/generated/0.5.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/control/if_else/generated/0.5.0-success.txt deleted file mode 100644 index 118379317f..0000000000 --- a/crates/solidity/testing/snapshots/bindings_output/control/if_else/generated/0.5.0-success.txt +++ /dev/null @@ -1,51 +0,0 @@ -# This file is generated automatically by infrastructure scripts. Please don't edit by hand. - -References and definitions: - ╭─[input.sol:1:1] - │ - 1 │ contract Test { - │ ──┬─ - │ ╰─── def: 1 - 2 │ function test() public returns (int) { - │ ──┬─ - │ ╰─── def: 2 - 3 │ int x = 1; - │ ┬ - │ ╰── def: 3 - 4 │ int y = 2; - │ ┬ - │ ╰── def: 4 - 5 │ if (x > 1) { - │ ┬ - │ ╰── ref: 3 - 6 │ int z = 3; - │ ┬ - │ ╰── def: 5 - 7 │ y = x + 10; - │ ┬ ┬ - │ ╰────── ref: 4 - │ │ - │ ╰── ref: 3 - │ - 9 │ int w = 4; - │ ┬ - │ ╰── def: 6 - 10 │ y = x + 20; - │ ┬ ┬ - │ ╰────── ref: 4 - │ │ - │ ╰── ref: 3 - │ - 12 │ int r = y + z + w; - │ ┬ ┬ ┬ ┬ - │ ╰────────────── def: 7 - │ │ │ │ - │ ╰────────── ref: 4 - │ │ │ - │ ╰────── unresolved - │ │ - │ ╰── unresolved - 13 │ return r; - │ ┬ - │ ╰── ref: 7 -────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/control/if_else/input.sol b/crates/solidity/testing/snapshots/bindings_output/control/if_else/input.sol index 298e124f76..121624fa92 100644 --- a/crates/solidity/testing/snapshots/bindings_output/control/if_else/input.sol +++ b/crates/solidity/testing/snapshots/bindings_output/control/if_else/input.sol @@ -9,7 +9,7 @@ contract Test { int w = 4; y = x + 20; } - int r = y + z + w; + int r = x + y; return r; } } diff --git a/crates/solidity/testing/snapshots/bindings_output/enums/sample/generated/0.5.3-success.txt b/crates/solidity/testing/snapshots/bindings_output/enums/sample/generated/0.5.3-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/enums/sample/generated/0.5.3-success.txt rename to crates/solidity/testing/snapshots/bindings_output/enums/sample/generated/0.5.3-failure.txt diff --git a/crates/solidity/testing/snapshots/bindings_output/errors/custom_types/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/errors/custom_types/generated/0.4.11-failure.txt index 9cf0d8c365..d81fb618e4 100644 --- a/crates/solidity/testing/snapshots/bindings_output/errors/custom_types/generated/0.4.11-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/errors/custom_types/generated/0.4.11-failure.txt @@ -44,7 +44,7 @@ References and definitions: │ ╰─── def: 6 13 │ revert Failure(Severity.ERROR, "Testing"); │ ───┬── ───┬─── - │ ╰──────────── unresolved + │ ╰──────────── ref: built-in │ │ │ ╰───── def: 7 ────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/revert_named_args/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/expressions/revert_named_args/generated/0.4.11-failure.txt index 4fbb44b584..5bc1e6badb 100644 --- a/crates/solidity/testing/snapshots/bindings_output/expressions/revert_named_args/generated/0.4.11-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/revert_named_args/generated/0.4.11-failure.txt @@ -34,7 +34,7 @@ References and definitions: │ ╰─── def: 3 8 │ revert Failure({severity: 100, cause: "Testing"}); │ ───┬── ───┬─── - │ ╰──────────── unresolved + │ ╰──────────── ref: built-in │ │ │ ╰───── def: 4 ───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/type_expr/generated/0.5.3-success.txt b/crates/solidity/testing/snapshots/bindings_output/expressions/type_expr/generated/0.5.3-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/expressions/type_expr/generated/0.5.3-success.txt rename to crates/solidity/testing/snapshots/bindings_output/expressions/type_expr/generated/0.5.3-failure.txt diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/generated/0.6.0-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/generated/0.6.0-success.txt rename to crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/generated/0.6.0-failure.txt diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/inherited/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/modifiers/inherited/generated/0.4.11-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/modifiers/inherited/generated/0.4.11-success.txt rename to crates/solidity/testing/snapshots/bindings_output/modifiers/inherited/generated/0.4.11-failure.txt diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/simple/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/modifiers/simple/generated/0.4.11-failure.txt similarity index 83% rename from crates/solidity/testing/snapshots/bindings_output/modifiers/simple/generated/0.4.11-success.txt rename to crates/solidity/testing/snapshots/bindings_output/modifiers/simple/generated/0.4.11-failure.txt index c82d36bf65..930ca8906f 100644 --- a/crates/solidity/testing/snapshots/bindings_output/modifiers/simple/generated/0.4.11-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/modifiers/simple/generated/0.4.11-failure.txt @@ -13,11 +13,11 @@ References and definitions: 4 │ modifier noReentrancy() { │ ──────┬───── │ ╰─────── def: 3 - 5 │ require(!locked, "No reentrancy"); - │ ───┬─── ───┬── - │ ╰───────────── unresolved - │ │ - │ ╰──── ref: 2 + 5 │ assert(!locked); + │ ───┬── ───┬── + │ ╰──────────── ref: built-in + │ │ + │ ╰──── ref: 2 │ 7 │ locked = true; │ ───┬── diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/simple/input.sol b/crates/solidity/testing/snapshots/bindings_output/modifiers/simple/input.sol index cebc39b0d6..34511fb8a2 100644 --- a/crates/solidity/testing/snapshots/bindings_output/modifiers/simple/input.sol +++ b/crates/solidity/testing/snapshots/bindings_output/modifiers/simple/input.sol @@ -2,7 +2,7 @@ contract FunctionModifier { bool public locked; modifier noReentrancy() { - require(!locked, "No reentrancy"); + assert(!locked); locked = true; _; diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/generated/0.6.0-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/generated/0.6.0-success.txt rename to crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/generated/0.6.0-failure.txt diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/with_args/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/modifiers/with_args/generated/0.4.11-failure.txt similarity index 87% rename from crates/solidity/testing/snapshots/bindings_output/modifiers/with_args/generated/0.4.11-success.txt rename to crates/solidity/testing/snapshots/bindings_output/modifiers/with_args/generated/0.4.11-failure.txt index 7f485928de..6d21688a73 100644 --- a/crates/solidity/testing/snapshots/bindings_output/modifiers/with_args/generated/0.4.11-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/modifiers/with_args/generated/0.4.11-failure.txt @@ -15,11 +15,11 @@ References and definitions: │ ╰───────────────────── def: 3 │ │ │ ╰──── def: 4 - 5 │ require(_addr != address(0), "Not valid address"); - │ ───┬─── ──┬── - │ ╰─────────── unresolved - │ │ - │ ╰──── ref: 4 + 5 │ assert(_addr != address(0)); + │ ───┬── ──┬── + │ ╰────────── ref: built-in + │ │ + │ ╰──── ref: 4 6 │ _; │ ┬ │ ╰── unresolved diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/with_args/input.sol b/crates/solidity/testing/snapshots/bindings_output/modifiers/with_args/input.sol index 76bd428b7b..f5308fd65a 100644 --- a/crates/solidity/testing/snapshots/bindings_output/modifiers/with_args/input.sol +++ b/crates/solidity/testing/snapshots/bindings_output/modifiers/with_args/input.sol @@ -2,7 +2,7 @@ contract FunctionModifier { address public owner; modifier validAddress(address _addr) { - require(_addr != address(0), "Not valid address"); + assert(_addr != address(0)); _; } diff --git a/crates/solidity/testing/snapshots/bindings_output/structs/sample/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/structs/sample/generated/0.6.0-failure.txt similarity index 100% rename from crates/solidity/testing/snapshots/bindings_output/structs/sample/generated/0.6.0-success.txt rename to crates/solidity/testing/snapshots/bindings_output/structs/sample/generated/0.6.0-failure.txt diff --git a/crates/testlang/inputs/language/src/definition.rs b/crates/testlang/inputs/language/src/definition.rs index a4d344e5a7..569348b328 100644 --- a/crates/testlang/inputs/language/src/definition.rs +++ b/crates/testlang/inputs/language/src/definition.rs @@ -305,5 +305,6 @@ codegen_language_macros::compile!(Language( ] ) ] - )] + )], + built_ins = [] )); diff --git a/crates/testlang/outputs/cargo/crate/build.rs b/crates/testlang/outputs/cargo/crate/build.rs index 00212d7515..babb70f034 100644 --- a/crates/testlang/outputs/cargo/crate/build.rs +++ b/crates/testlang/outputs/cargo/crate/build.rs @@ -11,5 +11,5 @@ fn main() -> Result<()> { let output_dir = CargoWorkspace::locate_source_crate("slang_testlang")?.join("src/generated"); - RuntimeGenerator::generate_product(&language, &input_dir, &output_dir) + RuntimeGenerator::generate_product(&language, &input_dir, &output_dir).map(|_| ()) } diff --git a/crates/testlang/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs b/crates/testlang/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs new file mode 100644 index 0000000000..0c4a214fc9 --- /dev/null +++ b/crates/testlang/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs @@ -0,0 +1,8 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use semver::Version; + +#[allow(unused_variables)] +pub fn get_contents(version: &Version) -> &'static str { + "" +} diff --git a/crates/testlang/outputs/cargo/crate/src/generated/bindings/mod.rs b/crates/testlang/outputs/cargo/crate/src/generated/bindings/mod.rs index c04d7cd11a..66c8a8c4da 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/bindings/mod.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/bindings/mod.rs @@ -3,6 +3,9 @@ #[path = "generated/binding_rules.rs"] mod binding_rules; +#[path = "generated/built_ins.rs"] +mod built_ins; + use std::sync::Arc; use metaslang_bindings::{self, PathResolver}; @@ -25,3 +28,7 @@ pub fn create_with_resolver( pub fn get_binding_rules() -> &'static str { binding_rules::BINDING_RULES_SOURCE } + +pub fn get_built_ins(version: &semver::Version) -> &'static str { + built_ins::get_contents(version) +} diff --git a/crates/testlang/outputs/cargo/wasm/build.rs b/crates/testlang/outputs/cargo/wasm/build.rs index 9071da026f..359bf08b53 100644 --- a/crates/testlang/outputs/cargo/wasm/build.rs +++ b/crates/testlang/outputs/cargo/wasm/build.rs @@ -12,5 +12,5 @@ fn main() -> Result<()> { let output_dir = CargoWorkspace::locate_source_crate("testlang_cargo_wasm")?.join("src/generated"); - RuntimeGenerator::generate_product(&language, &input_dir, &output_dir) + RuntimeGenerator::generate_product(&language, &input_dir, &output_dir).map(|_| ()) } diff --git a/crates/testlang/outputs/npm/package/build.rs b/crates/testlang/outputs/npm/package/build.rs index 95e6de6e63..83e16d7979 100644 --- a/crates/testlang/outputs/npm/package/build.rs +++ b/crates/testlang/outputs/npm/package/build.rs @@ -12,5 +12,5 @@ fn main() -> Result<()> { let output_dir = CargoWorkspace::locate_source_crate("testlang_npm_package")?.join("src/generated"); - RuntimeGenerator::generate_product(&language, &input_dir, &output_dir) + RuntimeGenerator::generate_product(&language, &input_dir, &output_dir).map(|_| ()) }