-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
And along, a few fixes to the parser and binding APIs (more details in the added changesets).
- Loading branch information
1 parent
5cec87c
commit 950d218
Showing
170 changed files
with
5,244 additions
and
601 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@nomicfoundation/slang": minor | ||
--- | ||
|
||
rename `parser/Parser.supportedVersions()` API to `utils/LanguageFacts.supportedVersions()`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@nomicfoundation/slang": minor | ||
--- | ||
|
||
expose the `BingingGraph` API to allow querying definitions/references between source files. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@nomicfoundation/slang": minor | ||
--- | ||
|
||
add a `CompilationBuilder` API to incrementally load and resolve source files and their imports. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
crates/codegen/runtime/cargo/crate/src/runtime/compilation/file.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// This file is generated automatically by infrastructure scripts. Please don't edit by hand. | ||
|
||
use std::collections::BTreeMap; | ||
|
||
use metaslang_cst::text_index::TextIndex; | ||
|
||
use crate::cst::{Cursor, Node}; | ||
|
||
#[derive(Clone)] | ||
pub struct File { | ||
id: String, | ||
tree: Node, | ||
|
||
resolved_imports: BTreeMap<usize, String>, | ||
} | ||
|
||
impl File { | ||
pub(super) fn new(id: String, tree: Node) -> Self { | ||
Self { | ||
id, | ||
tree, | ||
|
||
resolved_imports: BTreeMap::new(), | ||
} | ||
} | ||
|
||
pub fn id(&self) -> &str { | ||
&self.id | ||
} | ||
|
||
pub fn tree(&self) -> &Node { | ||
&self.tree | ||
} | ||
|
||
pub fn create_tree_cursor(&self) -> Cursor { | ||
self.tree.clone().cursor_with_offset(TextIndex::ZERO) | ||
} | ||
|
||
pub(super) fn resolve_import(&mut self, import_path: &Cursor, destination_file_id: String) { | ||
self.resolved_imports | ||
.insert(import_path.node().id(), destination_file_id); | ||
} | ||
|
||
pub(super) fn resolved_import(&self, import_path: &Cursor) -> Option<&String> { | ||
self.resolved_imports.get(&import_path.node().id()) | ||
} | ||
} |
213 changes: 213 additions & 0 deletions
213
crates/codegen/runtime/cargo/crate/src/runtime/compilation/internal_builder.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
// This file is generated automatically by infrastructure scripts. Please don't edit by hand. | ||
|
||
use std::collections::BTreeMap; | ||
use std::rc::Rc; | ||
|
||
use semver::Version; | ||
|
||
use crate::compilation::{CompilationUnit, File}; | ||
use crate::cst::{Cursor, Query}; | ||
use crate::parser::{Parser, ParserInitializationError}; | ||
|
||
pub struct InternalCompilationBuilder { | ||
parser: Parser, | ||
files: BTreeMap<String, File>, | ||
} | ||
|
||
#[derive(thiserror::Error, Debug)] | ||
pub enum CompilationInitializationError { | ||
#[error(transparent)] | ||
ParserInitialization(#[from] ParserInitializationError), | ||
} | ||
|
||
impl InternalCompilationBuilder { | ||
pub fn create(language_version: Version) -> Result<Self, CompilationInitializationError> { | ||
let parser = match Parser::create(language_version) { | ||
Ok(parser) => parser, | ||
Err(error) => { | ||
return Err(error.into()); | ||
} | ||
}; | ||
|
||
Ok(Self { | ||
parser, | ||
files: BTreeMap::new(), | ||
}) | ||
} | ||
|
||
pub fn add_file( | ||
&mut self, | ||
id: String, | ||
contents: &str, | ||
) -> Result<AddFileResponse, AddFileError> { | ||
let parse_output = self.parser.parse(Parser::ROOT_KIND, contents); | ||
|
||
let import_paths = extract_import_paths(parse_output.create_tree_cursor()) | ||
.map_err(AddFileError::Internal)?; | ||
|
||
let file = File::new(id.clone(), parse_output.tree().clone()); | ||
self.files.insert(id, file); | ||
|
||
Ok(AddFileResponse { import_paths }) | ||
} | ||
|
||
pub fn resolve_import( | ||
&mut self, | ||
source_file_id: &str, | ||
import_path: &Cursor, | ||
destination_file_id: String, | ||
) -> Result<(), ResolveImportError> { | ||
self.files | ||
.get_mut(source_file_id) | ||
.ok_or_else(|| ResolveImportError::SourceFileNotFound(source_file_id.to_owned()))? | ||
.resolve_import(import_path, destination_file_id); | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn build(&self) -> CompilationUnit { | ||
let language_version = self.parser.language_version().to_owned(); | ||
|
||
let files = self | ||
.files | ||
.iter() | ||
.map(|(id, file)| (id.to_owned(), Rc::new(file.to_owned()))) | ||
.collect(); | ||
|
||
CompilationUnit::new(language_version, files) | ||
} | ||
} | ||
|
||
pub struct AddFileResponse { | ||
pub import_paths: Vec<Cursor>, | ||
} | ||
|
||
#[derive(thiserror::Error, Debug)] | ||
pub enum AddFileError { | ||
#[error("Internal Error: {0}")] | ||
Internal(String), | ||
} | ||
|
||
#[derive(thiserror::Error, Debug)] | ||
pub enum ResolveImportError { | ||
#[error( | ||
"Source file not found: '{0}'. Make sure to add it first, before resolving its imports." | ||
)] | ||
SourceFileNotFound(String), | ||
} | ||
|
||
fn extract_import_paths(cursor: Cursor) -> Result<Vec<Cursor>, String> { | ||
let mut import_paths = Vec::new(); | ||
|
||
for query_match in cursor.query(vec![ | ||
Query::parse( | ||
"[PathImport | ||
path: [StringLiteral | ||
@variant ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) | ||
] | ||
]", | ||
) | ||
.map_err(|e| e.to_string())?, | ||
Query::parse( | ||
"[NamedImport | ||
path: [StringLiteral | ||
@variant ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) | ||
] | ||
]", | ||
) | ||
.map_err(|e| e.to_string())?, | ||
Query::parse( | ||
"[ImportDeconstruction | ||
path: [StringLiteral | ||
@variant ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) | ||
] | ||
]", | ||
) | ||
.map_err(|e| e.to_string())?, | ||
]) { | ||
for (match_name, _, cursors) in query_match.captures() { | ||
if match_name != "variant" { | ||
return Err(format!("Unexpected match name: {match_name}")); | ||
} | ||
|
||
import_paths.extend(cursors); | ||
} | ||
} | ||
|
||
Ok(import_paths) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::utils::LanguageFacts; | ||
|
||
#[test] | ||
pub fn path_import() { | ||
run( | ||
r#" | ||
import "foo-double"; | ||
import "bar-double" as bar; | ||
import 'foo-single'; | ||
import 'bar-single' as bar; | ||
"#, | ||
&[ | ||
"\"foo-double\"", | ||
"\"bar-double\"", | ||
"\'foo-single\'", | ||
"\'bar-single\'", | ||
], | ||
); | ||
} | ||
|
||
#[test] | ||
pub fn named_import() { | ||
run( | ||
r#" | ||
import * as foo from "foo-double"; | ||
import * as foo from 'foo-single'; | ||
"#, | ||
&["\"foo-double\"", "\'foo-single\'"], | ||
); | ||
} | ||
|
||
#[test] | ||
pub fn import_deconstruction() { | ||
run( | ||
r#" | ||
import {a, b} from "foo-double"; | ||
import {a, b} from 'foo-single'; | ||
"#, | ||
&["\"foo-double\"", "\'foo-single\'"], | ||
); | ||
} | ||
|
||
fn run(source: &str, expected: &[&str]) { | ||
match LanguageFacts::NAME { | ||
"Solidity" => { | ||
// Run the test only for Solidity: | ||
} | ||
"CodegenRuntime" | "Testlang" => { | ||
return; | ||
} | ||
other => { | ||
panic!("Unexpected language name: {other}"); | ||
} | ||
}; | ||
|
||
let parser = Parser::create(Version::new(0, 8, 0)).unwrap(); | ||
let parse_output = parser.parse(Parser::ROOT_KIND, source); | ||
|
||
let actual: Vec<_> = extract_import_paths(parse_output.create_tree_cursor()) | ||
.unwrap() | ||
.into_iter() | ||
.map(|cursor| cursor.node().unparse()) | ||
.collect(); | ||
|
||
assert_eq!(actual, expected.to_vec()); | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
crates/codegen/runtime/cargo/crate/src/runtime/compilation/mod.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// This file is generated automatically by infrastructure scripts. Please don't edit by hand. | ||
|
||
mod file; | ||
mod internal_builder; | ||
mod unit; | ||
|
||
pub use file::File; | ||
pub use internal_builder::{AddFileResponse, InternalCompilationBuilder}; | ||
pub use unit::CompilationUnit; |
69 changes: 69 additions & 0 deletions
69
crates/codegen/runtime/cargo/crate/src/runtime/compilation/unit.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// This file is generated automatically by infrastructure scripts. Please don't edit by hand. | ||
|
||
use std::cell::OnceCell; | ||
use std::collections::BTreeMap; | ||
use std::rc::Rc; | ||
|
||
use semver::Version; | ||
|
||
use crate::bindings::{create_with_resolver, BindingGraph, PathResolver}; | ||
use crate::compilation::File; | ||
use crate::cst::{Cursor, KindTypes}; | ||
|
||
pub struct CompilationUnit { | ||
language_version: Version, | ||
files: BTreeMap<String, Rc<File>>, | ||
binding_graph: OnceCell<Rc<BindingGraph>>, | ||
} | ||
|
||
impl CompilationUnit { | ||
pub(super) fn new(language_version: Version, files: BTreeMap<String, Rc<File>>) -> Self { | ||
Self { | ||
language_version, | ||
files, | ||
binding_graph: OnceCell::new(), | ||
} | ||
} | ||
|
||
pub fn language_version(&self) -> &Version { | ||
&self.language_version | ||
} | ||
|
||
pub fn files(&self) -> Vec<Rc<File>> { | ||
self.files.values().cloned().collect() | ||
} | ||
|
||
pub fn file(&self, id: &str) -> Option<Rc<File>> { | ||
self.files.get(id).cloned() | ||
} | ||
|
||
pub fn binding_graph(&self) -> &Rc<BindingGraph> { | ||
self.binding_graph.get_or_init(|| { | ||
let resolver = Resolver { | ||
files: self.files.clone(), | ||
}; | ||
|
||
let mut binding_graph = | ||
create_with_resolver(self.language_version.clone(), Rc::new(resolver)); | ||
|
||
for (id, file) in &self.files { | ||
binding_graph.add_user_file(id, file.create_tree_cursor()); | ||
} | ||
|
||
Rc::new(binding_graph) | ||
}) | ||
} | ||
} | ||
|
||
struct Resolver { | ||
files: BTreeMap<String, Rc<File>>, | ||
} | ||
|
||
impl PathResolver<KindTypes> for Resolver { | ||
fn resolve_path(&self, context_path: &str, path_to_resolve: &Cursor) -> Option<String> { | ||
self.files | ||
.get(context_path)? | ||
.resolved_import(path_to_resolve) | ||
.cloned() | ||
} | ||
} |
Oops, something went wrong.