mirror of
https://github.com/mtshiba/pylyzer.git
synced 2025-08-04 22:38:02 +00:00
feat: add pylyzer_wasm
crate
This commit is contained in:
parent
6828ddcf56
commit
b6a368257f
6 changed files with 381 additions and 2 deletions
71
Cargo.lock
generated
71
Cargo.lock
generated
|
@ -85,6 +85,12 @@ version = "2.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
|
@ -583,6 +589,16 @@ dependencies = [
|
|||
"rustpython-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pylyzer_wasm"
|
||||
version = "0.0.60"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_compiler",
|
||||
"pylyzer_core",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
|
@ -977,6 +993,61 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.74",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.74",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
|
|
|
@ -13,6 +13,7 @@ repository.workspace = true
|
|||
members = [
|
||||
"crates/py2erg",
|
||||
"crates/pylyzer_core",
|
||||
"crates/pylyzer_wasm",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
|
|
|
@ -6,8 +6,8 @@ use erg_common::traits::{ExitStatus, New, Runnable, Stream};
|
|||
use erg_common::Str;
|
||||
use erg_compiler::artifact::{BuildRunnable, Buildable, CompleteArtifact, IncompleteArtifact};
|
||||
use erg_compiler::build_package::GenericPackageBuilder;
|
||||
use erg_compiler::context::ModuleContext;
|
||||
use erg_compiler::erg_parser::ast::{Module, AST};
|
||||
use erg_compiler::context::{Context, ContextProvider, ModuleContext};
|
||||
use erg_compiler::erg_parser::ast::{Module, VarName, AST};
|
||||
use erg_compiler::erg_parser::build_ast::ASTBuildable;
|
||||
use erg_compiler::erg_parser::error::{
|
||||
CompleteArtifact as ParseArtifact, IncompleteArtifact as IncompleteParseArtifact, ParseErrors,
|
||||
|
@ -16,6 +16,7 @@ use erg_compiler::erg_parser::error::{
|
|||
use erg_compiler::erg_parser::parse::Parsable;
|
||||
use erg_compiler::error::{CompileError, CompileErrors};
|
||||
use erg_compiler::module::SharedCompilerResource;
|
||||
use erg_compiler::varinfo::VarInfo;
|
||||
use erg_compiler::GenericHIRBuilder;
|
||||
use py2erg::{dump_decl_package, ShadowingMode};
|
||||
use rustpython_ast::source_code::{RandomLocator, SourceRange};
|
||||
|
@ -140,6 +141,18 @@ impl New for PythonAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
impl ContextProvider for PythonAnalyzer {
|
||||
fn dir(&self) -> erg_common::dict::Dict<&VarName, &VarInfo> {
|
||||
self.checker.dir()
|
||||
}
|
||||
fn get_receiver_ctx(&self, receiver_name: &str) -> Option<&Context> {
|
||||
self.checker.get_receiver_ctx(receiver_name)
|
||||
}
|
||||
fn get_var_info(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
|
||||
self.checker.get_var_info(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl Runnable for PythonAnalyzer {
|
||||
type Err = CompileError;
|
||||
type Errs = CompileErrors;
|
||||
|
|
19
crates/pylyzer_wasm/Cargo.toml
Normal file
19
crates/pylyzer_wasm/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "pylyzer_wasm"
|
||||
description = "Wasm wrapper for pylyzer"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
repository.workspace = true
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
erg_common = { workspace = true }
|
||||
erg_compiler = { workspace = true }
|
||||
pylyzer_core = { version = "*", path = "../pylyzer_core" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
path = "lib.rs"
|
13
crates/pylyzer_wasm/README.md
Normal file
13
crates/pylyzer_wasm/README.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
# pylyzer_wasm
|
||||
|
||||
Wasm wrapper for pylyzer.
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { Analyzer } from 'pylyzer_wasm';
|
||||
|
||||
const analyzer = new Analyzer();
|
||||
const errors = analyzer.check('print("Hello, World!")');
|
||||
const locals = analyzer.dir();
|
||||
```
|
262
crates/pylyzer_wasm/lib.rs
Normal file
262
crates/pylyzer_wasm/lib.rs
Normal file
|
@ -0,0 +1,262 @@
|
|||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use erg_common::error::ErrorCore;
|
||||
use erg_common::error::Location as Loc;
|
||||
use erg_common::traits::{Runnable, Stream};
|
||||
use erg_compiler::context::ContextProvider;
|
||||
use erg_compiler::erg_parser::ast::VarName;
|
||||
use erg_compiler::error::CompileError;
|
||||
use erg_compiler::ty::Type as Ty;
|
||||
use erg_compiler::varinfo::VarInfo;
|
||||
use pylyzer_core::PythonAnalyzer;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[wasm_bindgen]
|
||||
pub enum CompItemKind {
|
||||
Method = 0,
|
||||
Function = 1,
|
||||
Constructor = 2,
|
||||
Field = 3,
|
||||
Variable = 4,
|
||||
Class = 5,
|
||||
Struct = 6,
|
||||
Interface = 7,
|
||||
Module = 8,
|
||||
Property = 9,
|
||||
Event = 10,
|
||||
Operator = 11,
|
||||
Unit = 12,
|
||||
Value = 13,
|
||||
Constant = 14,
|
||||
Enum = 15,
|
||||
EnumMember = 16,
|
||||
Keyword = 17,
|
||||
Text = 18,
|
||||
Color = 19,
|
||||
File = 20,
|
||||
Reference = 21,
|
||||
Customcolor = 22,
|
||||
Folder = 23,
|
||||
TypeParameter = 24,
|
||||
User = 25,
|
||||
Issue = 26,
|
||||
Snippet = 27,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[wasm_bindgen]
|
||||
pub struct Location(Loc);
|
||||
|
||||
impl From<Loc> for Location {
|
||||
fn from(loc: Loc) -> Self {
|
||||
Self(loc)
|
||||
}
|
||||
}
|
||||
|
||||
impl Location {
|
||||
pub const UNKNOWN: Location = Location(Loc::Unknown);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[wasm_bindgen]
|
||||
#[allow(dead_code)]
|
||||
pub struct Type(Ty);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[wasm_bindgen]
|
||||
pub struct VarEntry {
|
||||
name: VarName,
|
||||
vi: VarInfo,
|
||||
}
|
||||
|
||||
impl VarEntry {
|
||||
pub fn new(name: VarName, vi: VarInfo) -> Self {
|
||||
Self { name, vi }
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl VarEntry {
|
||||
pub fn name(&self) -> String {
|
||||
self.name.to_string()
|
||||
}
|
||||
pub fn item_kind(&self) -> CompItemKind {
|
||||
match &self.vi.t {
|
||||
Ty::Callable { .. } => CompItemKind::Function,
|
||||
Ty::Subr(subr) => {
|
||||
if subr.self_t().is_some() {
|
||||
CompItemKind::Method
|
||||
} else {
|
||||
CompItemKind::Function
|
||||
}
|
||||
}
|
||||
Ty::Quantified(quant) => match quant.as_ref() {
|
||||
Ty::Callable { .. } => CompItemKind::Function,
|
||||
Ty::Subr(subr) => {
|
||||
if subr.self_t().is_some() {
|
||||
CompItemKind::Method
|
||||
} else {
|
||||
CompItemKind::Function
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Ty::ClassType => CompItemKind::Class,
|
||||
Ty::TraitType => CompItemKind::Interface,
|
||||
Ty::Poly { name, .. } if &name[..] == "Module" => CompItemKind::Module,
|
||||
_ if self.vi.muty.is_const() => CompItemKind::Constant,
|
||||
_ => CompItemKind::Variable,
|
||||
}
|
||||
}
|
||||
pub fn typ(&self) -> String {
|
||||
self.vi.t.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Location {
|
||||
pub fn ln_begin(&self) -> Option<u32> {
|
||||
self.0.ln_begin()
|
||||
}
|
||||
|
||||
pub fn ln_end(&self) -> Option<u32> {
|
||||
self.0.ln_end()
|
||||
}
|
||||
|
||||
pub fn col_begin(&self) -> Option<u32> {
|
||||
self.0.col_begin()
|
||||
}
|
||||
|
||||
pub fn col_end(&self) -> Option<u32> {
|
||||
self.0.col_end()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[wasm_bindgen(getter_with_clone)]
|
||||
pub struct Error {
|
||||
pub errno: usize,
|
||||
pub is_warning: bool,
|
||||
// pub kind: ErrorKind,
|
||||
pub loc: Location,
|
||||
pub desc: String,
|
||||
pub hint: Option<String>,
|
||||
}
|
||||
|
||||
fn find_fallback_loc(err: &ErrorCore) -> Loc {
|
||||
if err.loc == Loc::Unknown {
|
||||
for sub in &err.sub_messages {
|
||||
if sub.loc != Loc::Unknown {
|
||||
return sub.loc;
|
||||
}
|
||||
}
|
||||
Loc::Unknown
|
||||
} else {
|
||||
err.loc
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CompileError> for Error {
|
||||
fn from(err: CompileError) -> Self {
|
||||
let loc = Location(find_fallback_loc(&err.core));
|
||||
let sub_msg = err
|
||||
.core
|
||||
.sub_messages
|
||||
.first()
|
||||
.map(|sub| {
|
||||
sub.msg
|
||||
.iter()
|
||||
.fold("\n".to_string(), |acc, s| acc + s + "\n")
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let desc = err.core.main_message + &sub_msg;
|
||||
Self {
|
||||
errno: err.core.errno,
|
||||
is_warning: err.core.kind.is_warning(),
|
||||
// kind: err.kind(),
|
||||
loc,
|
||||
desc,
|
||||
hint: err
|
||||
.core
|
||||
.sub_messages
|
||||
.first()
|
||||
.and_then(|sub| sub.hint.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub const fn new(
|
||||
errno: usize,
|
||||
is_warning: bool,
|
||||
loc: Location,
|
||||
desc: String,
|
||||
hint: Option<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
errno,
|
||||
is_warning,
|
||||
loc,
|
||||
desc,
|
||||
hint,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
// #[derive()]
|
||||
pub struct Analyzer {
|
||||
analyzer: PythonAnalyzer,
|
||||
}
|
||||
|
||||
impl Default for Analyzer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Analyzer {
|
||||
pub fn new() -> Self {
|
||||
Analyzer {
|
||||
analyzer: PythonAnalyzer::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.analyzer.clear();
|
||||
}
|
||||
|
||||
pub fn start_message(&self) -> String {
|
||||
self.analyzer.start_message()
|
||||
}
|
||||
|
||||
pub fn dir(&mut self) -> Box<[VarEntry]> {
|
||||
self.analyzer
|
||||
.dir()
|
||||
.into_iter()
|
||||
.map(|(n, vi)| VarEntry::new(n.clone(), vi.clone()))
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice()
|
||||
}
|
||||
|
||||
pub fn check(&mut self, input: &str) -> Box<[Error]> {
|
||||
match self.analyzer.analyze(input.to_string(), "exec") {
|
||||
Ok(artifact) => artifact
|
||||
.warns
|
||||
.into_iter()
|
||||
.map(Error::from)
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice(),
|
||||
Err(mut err_artifact) => {
|
||||
err_artifact.errors.extend(err_artifact.warns);
|
||||
let errs = err_artifact
|
||||
.errors
|
||||
.into_iter()
|
||||
.map(Error::from)
|
||||
.collect::<Vec<_>>();
|
||||
errs.into_boxed_slice()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue