mirror of https://github.com/mtshiba/pylyzer
feat: add `pylyzer_wasm` crate
This commit is contained in:
parent
6828ddcf56
commit
b6a368257f
|
|
@ -85,6 +85,12 @@ version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
@ -583,6 +589,16 @@ dependencies = [
|
||||||
"rustpython-parser",
|
"rustpython-parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pylyzer_wasm"
|
||||||
|
version = "0.0.60"
|
||||||
|
dependencies = [
|
||||||
|
"erg_common",
|
||||||
|
"erg_compiler",
|
||||||
|
"pylyzer_core",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.36"
|
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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
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]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ repository.workspace = true
|
||||||
members = [
|
members = [
|
||||||
"crates/py2erg",
|
"crates/py2erg",
|
||||||
"crates/pylyzer_core",
|
"crates/pylyzer_core",
|
||||||
|
"crates/pylyzer_wasm",
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ use erg_common::traits::{ExitStatus, New, Runnable, Stream};
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
use erg_compiler::artifact::{BuildRunnable, Buildable, CompleteArtifact, IncompleteArtifact};
|
use erg_compiler::artifact::{BuildRunnable, Buildable, CompleteArtifact, IncompleteArtifact};
|
||||||
use erg_compiler::build_package::GenericPackageBuilder;
|
use erg_compiler::build_package::GenericPackageBuilder;
|
||||||
use erg_compiler::context::ModuleContext;
|
use erg_compiler::context::{Context, ContextProvider, ModuleContext};
|
||||||
use erg_compiler::erg_parser::ast::{Module, AST};
|
use erg_compiler::erg_parser::ast::{Module, VarName, AST};
|
||||||
use erg_compiler::erg_parser::build_ast::ASTBuildable;
|
use erg_compiler::erg_parser::build_ast::ASTBuildable;
|
||||||
use erg_compiler::erg_parser::error::{
|
use erg_compiler::erg_parser::error::{
|
||||||
CompleteArtifact as ParseArtifact, IncompleteArtifact as IncompleteParseArtifact, ParseErrors,
|
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::erg_parser::parse::Parsable;
|
||||||
use erg_compiler::error::{CompileError, CompileErrors};
|
use erg_compiler::error::{CompileError, CompileErrors};
|
||||||
use erg_compiler::module::SharedCompilerResource;
|
use erg_compiler::module::SharedCompilerResource;
|
||||||
|
use erg_compiler::varinfo::VarInfo;
|
||||||
use erg_compiler::GenericHIRBuilder;
|
use erg_compiler::GenericHIRBuilder;
|
||||||
use py2erg::{dump_decl_package, ShadowingMode};
|
use py2erg::{dump_decl_package, ShadowingMode};
|
||||||
use rustpython_ast::source_code::{RandomLocator, SourceRange};
|
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 {
|
impl Runnable for PythonAnalyzer {
|
||||||
type Err = CompileError;
|
type Err = CompileError;
|
||||||
type Errs = CompileErrors;
|
type Errs = CompileErrors;
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
@ -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();
|
||||||
|
```
|
||||||
|
|
@ -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…
Reference in New Issue