initial commit

This commit is contained in:
Shunsuke Shibayama 2022-12-12 22:40:50 +09:00
commit 20472bfb3c
21 changed files with 1930 additions and 0 deletions

13
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,13 @@
# These are supported funding model platforms
github: mtshiba # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

989
Cargo.lock generated Normal file
View file

@ -0,0 +1,989 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "ascii-canvas"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff8eb72df928aafb99fe5d37b383f2fe25bd2a765e3e5f7c365916b6f2463a29"
dependencies = [
"term",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78"
dependencies = [
"autocfg 1.1.0",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "bit-set"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "blake2b_simd"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
dependencies = [
"arrayref",
"arrayvec",
"constant_time_eq",
]
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
"block-padding",
"byte-tools",
"byteorder",
"generic-array",
]
[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
"byte-tools",
]
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
]
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "crossbeam-utils"
version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
dependencies = [
"cfg-if",
]
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
"generic-array",
]
[[package]]
name = "dirs"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "docopt"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f3f119846c823f9eafcf953a8f6ffb6ed69bf6240883261a7f13b634579a51f"
dependencies = [
"lazy_static",
"regex",
"serde",
"strsim",
]
[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "els"
version = "0.1.11"
source = "git+https://github.com/erg-lang/erg-language-server?branch=main#be627c99faf539e8ad58f77eb41f8e76b759e6ab"
dependencies = [
"erg_common",
"erg_compiler",
"lsp-types",
"serde",
"serde_json",
]
[[package]]
name = "ena"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36"
dependencies = [
"log",
]
[[package]]
name = "erg_common"
version = "0.6.0-beta.2"
source = "git+https://github.com/erg-lang/erg?branch=main#2e289f7cd1503778293fa8c927df03825f6ef69b"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "erg_compiler"
version = "0.6.0-beta.2"
source = "git+https://github.com/erg-lang/erg?branch=main#2e289f7cd1503778293fa8c927df03825f6ef69b"
dependencies = [
"erg_common",
"erg_parser",
]
[[package]]
name = "erg_parser"
version = "0.6.0-beta.2"
source = "git+https://github.com/erg-lang/erg?branch=main#2e289f7cd1503778293fa8c927df03825f6ef69b"
dependencies = [
"erg_common",
"unicode-xid 0.2.4",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "fixedbitset"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
[[package]]
name = "form_urlencoded"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
dependencies = [
"percent-encoding",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "generic-array"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
"typenum",
]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "idna"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
dependencies = [
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "itertools"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
[[package]]
name = "lalrpop"
version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64dc3698e75d452867d9bd86f4a723f452ce9d01fe1d55990b79f0c790aa67db"
dependencies = [
"ascii-canvas",
"atty",
"bit-set",
"diff",
"docopt",
"ena",
"itertools",
"lalrpop-util",
"petgraph",
"regex",
"regex-syntax",
"serde",
"serde_derive",
"sha2",
"string_cache",
"term",
"unicode-xid 0.1.0",
]
[[package]]
name = "lalrpop-util"
version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c277d18683b36349ab5cd030158b54856fca6bb2d5dc5263b06288f486958b7c"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "lsp-types"
version = "0.93.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be6e9c7e2d18f651974370d7aff703f9513e0df6e464fd795660edc77e6ca51"
dependencies = [
"bitflags",
"serde",
"serde_json",
"serde_repr",
"url",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "num-bigint"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
dependencies = [
"autocfg 1.1.0",
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg 1.1.0",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg 1.1.0",
]
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "ordermap"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
[[package]]
name = "percent-encoding"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "petgraph"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f"
dependencies = [
"fixedbitset",
"ordermap",
]
[[package]]
name = "phf_generator"
version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_shared"
version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
dependencies = [
"siphasher",
]
[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "proc-macro2"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
dependencies = [
"unicode-ident",
]
[[package]]
name = "py2erg"
version = "0.1.0"
dependencies = [
"erg_common",
"erg_compiler",
"rustpython-parser",
]
[[package]]
name = "pype"
version = "0.1.0"
dependencies = [
"els",
"erg_common",
"erg_compiler",
"py2erg",
"rustpython-parser",
]
[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
dependencies = [
"autocfg 0.1.8",
"libc",
"rand_chacha",
"rand_core 0.4.2",
"rand_hc",
"rand_isaac",
"rand_jitter",
"rand_os",
"rand_pcg",
"rand_xorshift",
"winapi",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
dependencies = [
"autocfg 0.1.8",
"rand_core 0.3.1",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
dependencies = [
"libc",
"rand_core 0.4.2",
"winapi",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
dependencies = [
"cloudabi",
"fuchsia-cprng",
"libc",
"rand_core 0.4.2",
"rdrand",
"winapi",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
dependencies = [
"autocfg 0.1.8",
"rand_core 0.4.2",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "redox_syscall"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "redox_users"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
dependencies = [
"getrandom",
"redox_syscall",
"rust-argon2",
]
[[package]]
name = "regex"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "rust-argon2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
dependencies = [
"base64",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils",
]
[[package]]
name = "rustpython-parser"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d85b1038ecd8791bdae455ae784b48f522ebeca1b3323d0af2b251c5c8ff1c68"
dependencies = [
"lalrpop",
"lalrpop-util",
"log",
"num-bigint",
"num-traits",
"unic-emoji-char",
"unic-ucd-ident",
"unicode_names2",
]
[[package]]
name = "ryu"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "serde"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_repr"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "sha2"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
dependencies = [
"block-buffer",
"digest",
"fake-simd",
"opaque-debug",
]
[[package]]
name = "siphasher"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
[[package]]
name = "string_cache"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89c058a82f9fd69b1becf8c274f412281038877c553182f1d02eb027045a2d67"
dependencies = [
"lazy_static",
"new_debug_unreachable",
"phf_shared",
"precomputed-hash",
"serde",
"string_cache_codegen",
"string_cache_shared",
]
[[package]]
name = "string_cache_codegen"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f45ed1b65bf9a4bf2f7b7dc59212d1926e9eaf00fa998988e420fd124467c6"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro2",
"quote",
"string_cache_shared",
]
[[package]]
name = "string_cache_shared"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "term"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
dependencies = [
"byteorder",
"dirs",
"winapi",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "unic-char-property"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
dependencies = [
"unic-char-range",
]
[[package]]
name = "unic-char-range"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
[[package]]
name = "unic-common"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
[[package]]
name = "unic-emoji-char"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d"
dependencies = [
"unic-char-property",
"unic-char-range",
"unic-ucd-version",
]
[[package]]
name = "unic-ucd-ident"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987"
dependencies = [
"unic-char-property",
"unic-char-range",
"unic-ucd-version",
]
[[package]]
name = "unic-ucd-version"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
dependencies = [
"unic-common",
]
[[package]]
name = "unicode-bidi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
[[package]]
name = "unicode-ident"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]]
name = "unicode-normalization"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]]
name = "unicode-xid"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "unicode_names2"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87d6678d7916394abad0d4b19df4d3802e1fd84abd7d701f39b75ee71b9e8cf1"
[[package]]
name = "url"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

19
Cargo.toml Normal file
View file

@ -0,0 +1,19 @@
[package]
name = "pype"
version = "0.1.0"
edition = "2021"
description = "A Python static code analyzer & language server"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace]
members = [
"crates/py2erg",
]
[dependencies]
rustpython-parser = "0.1.2"
erg_compiler = { git = "https://github.com/erg-lang/erg", branch = "main" }
erg_common = { git = "https://github.com/erg-lang/erg", branch = "main" }
els = { git = "https://github.com/erg-lang/erg-language-server", branch = "main" }
py2erg = { path = "./crates/py2erg" }

19
LICENSE Normal file
View file

@ -0,0 +1,19 @@
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

38
README.md Normal file
View file

@ -0,0 +1,38 @@
# pype
`pype` is a Python static code analyzer & language server written in Rust.
## Installation
### cargo (rust package manager)
```bash
cargo install pype
```
or download the binary from [the releases page].
## How it works
pype uses the type checker of [the erg programming language](https://erg-lang.org) internally.
This language is a transpiled language that targets Python, and has a static type system.
pype converts Python ASTs to Erg ASTs and passes them to Erg's type checker. It then displays the results with appropriate modifications.
## What is the advantage over pylint, pyright, pytype, etc.?
pype performs type inference of Python source code. Therefore, there is no need to annotate or type your Python scripts in order to use pype. You can, however, explicitly request type checks by specifying types.
Other softwares that takes the same approach as pype are pytype, pyright, etc.
However, pype is superior to them in the following points:
* Checking speed: pype can inspect Python scripts on average 100 times faster than pytype. This is largely due to the fact that pype is implemented in Rust, whereas pytype is implemented in Python.
* Type checking accuracy: pytype is just a static code analysis tool in python, whereas pype appropriates the type checker of Erg, a real statically typed programming language.
* Reporting quality: While pytype's error reports are frankly very crude, showing only that an error has occurred, pype shows where the error occurred and provides clear error messages. Also, pytype only displays the first error when there are multiple errors. pype enumerates as many errors as possible.

15
crates/py2erg/Cargo.toml Normal file
View file

@ -0,0 +1,15 @@
[package]
name = "py2erg"
version = "0.1.0"
edition = "2021"
description = "A Python -> Erg converter"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rustpython-parser = "0.1.2"
erg_compiler = { git = "https://github.com/erg-lang/erg", branch = "main" }
erg_common = { git = "https://github.com/erg-lang/erg", branch = "main" }
[lib]
path = "lib.rs"

343
crates/py2erg/convert.rs Normal file
View file

@ -0,0 +1,343 @@
use erg_common::traits::Stream;
use rustpython_parser::ast::{StatementType, ExpressionType, Located, Program, Number, StringGroup, Operator, BooleanOperator, UnaryOperator, Suite, Parameters, Parameter};
use rustpython_parser::ast::Location as PyLocation;
use erg_common::set::Set as HashSet;
use erg_compiler::erg_parser::token::{Token, TokenKind, EQUAL, COLON};
use erg_compiler::erg_parser::ast::{
Expr, Module, Signature, VarSignature, VarPattern, Params, Identifier, VarName, DefBody, DefId, Block, Def, Literal, Args, PosArg, Accessor,
BinOp, Lambda, LambdaSignature, TypeBoundSpecs, TypeSpec, SubrSignature, Decorator, NonDefaultParamSignature, DefaultParamSignature, ParamPattern, TypeSpecWithOp,
Tuple, NormalTuple, Array, NormalArray, Set, NormalSet, Dict, NormalDict, PreDeclTypeSpec, SimpleTypeSpec, ConstArgs, AttrDef, UnaryOp, KeyValue, Dummy
};
fn add_procedural_mark(name: String) -> String {
match &name[..] {
"print" => "print!".to_string(),
"input" => "input!".to_string(),
"open" => "open!".to_string(),
"int" => "Int".to_string(),
"float" => "Float".to_string(),
"str" => "Str".to_string(),
"bool" => "Bool".to_string(),
"list" => "GenericArray".to_string(),
"tuple" => "GenericTuple".to_string(),
"range" => "Range".to_string(),
_ => name,
}
}
fn convert_attr(name: String, loc: PyLocation) -> Identifier {
let token = Token::new(TokenKind::Symbol, add_procedural_mark(name), loc.row(), loc.column() - 1);
let name = VarName::new(token);
let dot = Token::new(TokenKind::Dot, ".", loc.row(), loc.column());
Identifier::new(Some(dot), name)
}
fn convert_ident(name: String, loc: PyLocation) -> Identifier {
let token = Token::new(TokenKind::Symbol, add_procedural_mark(name), loc.row(), loc.column() - 1);
let name = VarName::new(token);
Identifier::new(None, name)
}
fn convert_param_pattern(arg: String, loc: PyLocation) -> ParamPattern {
let token = Token::new(TokenKind::Symbol, arg, loc.row(), loc.column() - 1);
let name = VarName::new(token);
ParamPattern::VarName(name)
}
fn convert_nd_param(param: Parameter) -> NonDefaultParamSignature {
let pat = convert_param_pattern(param.arg, param.location);
let t_spec = param.annotation
.map(|anot| convert_type_spec(*anot))
.map(|t_spec| TypeSpecWithOp::new(COLON, t_spec));
NonDefaultParamSignature::new(pat, t_spec)
}
fn _convert_default_param(_param: Parameter) -> DefaultParamSignature {
todo!()
}
// TODO: defaults
fn convert_params(args: Box<Parameters>) -> Params {
let non_defaults = args.args.into_iter().map(convert_nd_param).collect();
// let defaults = args. args.defaults.into_iter().map(convert_default_param).collect();
Params::new(non_defaults, None, vec![], None)
}
fn convert_for_param(name: String, loc: PyLocation) -> NonDefaultParamSignature {
let pat = convert_param_pattern(name, loc);
let t_spec = None;
NonDefaultParamSignature::new(pat, t_spec)
}
fn convert_for_body(lhs: Located<ExpressionType>, body: Suite) -> Lambda {
let ExpressionType::Identifier { name } = lhs.node else { todo!() };
let param = convert_for_param(name, lhs.location);
let params = Params::new(vec![param], None, vec![], None);
let body = body.into_iter().map(convert_statement).collect::<Vec<_>>();
let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
let op = Token::from_str(TokenKind::ProcArrow, "=>");
Lambda::new(sig, op, Block::new(body), DefId(0))
}
fn convert_type_spec(expr: Located<ExpressionType>) -> TypeSpec {
match expr.node {
ExpressionType::Identifier { name } =>
TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(SimpleTypeSpec::new(convert_ident(name, expr.location), ConstArgs::empty()))),
_other => TypeSpec::Infer(Token::new(TokenKind::UBar, "_", expr.location.row(), expr.location.column() - 1)),
}
}
fn gen_enclosure_tokens<'i, Elems>(l_kind: TokenKind, elems: Elems, expr_loc: PyLocation) -> (Token, Token)
where Elems: Iterator<Item=&'i Located<ExpressionType>> + ExactSizeIterator {
let (l_cont, r_cont, r_kind) = match l_kind {
TokenKind::LBrace => ("{", "}", TokenKind::RBrace),
TokenKind::LParen => ("(", ")", TokenKind::RParen),
TokenKind::LSqBr => ("[", "]", TokenKind::RSqBr),
_ => unreachable!(),
};
let (l_end, c_end) = if elems.len() == 0 {
(expr_loc.row(), expr_loc.column() - 1)
} else {
let last = elems.last().unwrap();
(last.location.row(), last.location.column())
};
let l_brace = Token::new(l_kind, l_cont, expr_loc.row(), expr_loc.column() - 1);
let r_brace = Token::new(r_kind, r_cont, l_end, c_end);
(l_brace, r_brace)
}
fn convert_expr(expr: Located<ExpressionType>) -> Expr {
match expr.node {
ExpressionType::Number { value } => {
let (kind, cont) = match value {
Number::Integer { value } => (TokenKind::IntLit, value.to_string()),
Number::Float { value } => (TokenKind::RatioLit, value.to_string()),
Number::Complex { .. } => { return Expr::Dummy(Dummy::new(vec![])); },
};
let token = Token::new(kind, cont, expr.location.row(), expr.location.column() - 1);
Expr::Lit(Literal::new(token))
}
ExpressionType::String { value } => {
let StringGroup::Constant{ value } = value else {
return Expr::Dummy(Dummy::new(vec![]));
};
let value = format!("\"{value}\"");
// column - 2 because of the quotes
let token = Token::new(TokenKind::StrLit, value, expr.location.row(), expr.location.column() - 2);
Expr::Lit(Literal::new(token))
}
ExpressionType::Call { function, args, keywords: _ } => {
let function = convert_expr(*function);
let pos_args = args.into_iter().map(|ex| PosArg::new(convert_expr(ex))).collect::<Vec<_>>();
let args = Args::new(pos_args, vec![], None);
function.call_expr(args)
}
ExpressionType::Binop { a, op, b } => {
let lhs = convert_expr(*a);
let rhs = convert_expr(*b);
let (kind, cont) = match op {
Operator::Add => (TokenKind::Plus, "+"),
Operator::Sub => (TokenKind::Minus, "-"),
Operator::Mult => (TokenKind::Star, "*"),
Operator::Div => (TokenKind::Slash, "/"),
Operator::Mod => (TokenKind::Mod, "%"),
Operator::Pow => (TokenKind::Pow, "**"),
Operator::LShift => (TokenKind::Shl, "<<"),
Operator::RShift => (TokenKind::Shr, ">>"),
Operator::BitOr => (TokenKind::BitOr, "|"),
Operator::BitXor => (TokenKind::BitXor, "^"),
Operator::BitAnd => (TokenKind::BitAnd, "&"),
Operator::FloorDiv => (TokenKind::FloorDiv, "//"),
Operator::MatMult => (TokenKind::AtSign, "@"),
};
let op = Token::from_str(kind, cont);
Expr::BinOp(BinOp::new(op, lhs, rhs))
}
ExpressionType::Unop { op, a } => {
let rhs = convert_expr(*a);
let (kind, cont) = match op {
UnaryOperator::Pos => (TokenKind::PrePlus, "+"),
// UnaryOperator::Not => (TokenKind::PreBitNot, "not"),
UnaryOperator::Neg => (TokenKind::PreMinus, "-"),
UnaryOperator::Inv => (TokenKind::Minus, "~"),
_ => { return Expr::Dummy(Dummy::new(vec![rhs])) }
};
let op = Token::from_str(kind, cont);
Expr::UnaryOp(UnaryOp::new(op, rhs))
}
// TODO
ExpressionType::BoolOp { op, mut values } => {
let lhs = convert_expr(values.remove(0));
let rhs = convert_expr(values.remove(0));
let (kind, cont) = match op {
BooleanOperator::And => (TokenKind::AndOp, "and"),
BooleanOperator::Or => (TokenKind::OrOp, "or"),
};
let op = Token::from_str(kind, cont);
Expr::BinOp(BinOp::new(op, lhs, rhs))
}
ExpressionType::Identifier { name } => {
let ident = convert_ident(name, expr.location);
Expr::Accessor(Accessor::Ident(ident))
}
ExpressionType::Lambda { args, body } => {
let params = convert_params(args);
let body = vec![convert_expr(*body)];
let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
let op = Token::from_str(TokenKind::ProcArrow, "=>");
Expr::Lambda(Lambda::new(sig, op, Block::new(body), DefId(0)))
}
ExpressionType::List { elements } => {
let (l_sqbr, r_sqbr) = gen_enclosure_tokens(TokenKind::LSqBr, elements.iter(), expr.location);
let elements = elements.into_iter()
.map(|ex| PosArg::new(convert_expr(ex)))
.collect::<Vec<_>>();
let elems = Args::new(elements, vec![], None);
Expr::Array(Array::Normal(NormalArray::new(l_sqbr, r_sqbr, elems)))
}
ExpressionType::Set { elements } => {
let (l_brace, r_brace) = gen_enclosure_tokens(TokenKind::LBrace, elements.iter(), expr.location);
let elements = elements.into_iter()
.map(|ex| PosArg::new(convert_expr(ex)))
.collect::<Vec<_>>();
let elems = Args::new(elements, vec![], None);
Expr::Set(Set::Normal(NormalSet::new(l_brace, r_brace, elems)))
}
ExpressionType::Dict { elements } => {
let (l_brace, r_brace) = gen_enclosure_tokens(TokenKind::LBrace, elements.iter().map(|(_, v)| v), expr.location);
let kvs = elements.into_iter()
.map(|(k, v)|
KeyValue::new(k.map(convert_expr).unwrap_or(Expr::Dummy(Dummy::empty())), convert_expr(v))
).collect::<Vec<_>>();
Expr::Dict(Dict::Normal(NormalDict::new(l_brace, r_brace, kvs)))
}
ExpressionType::Tuple { elements } => {
let elements = elements.into_iter()
.map(|ex| PosArg::new(convert_expr(ex)))
.collect::<Vec<_>>();
let elems = Args::new(elements, vec![], None);
Expr::Tuple(Tuple::Normal(NormalTuple::new(elems)))
}
ExpressionType::Subscript { a, b } => {
let obj = convert_expr(*a);
let method = obj.attr_expr(convert_attr("__getitem__".to_string(), expr.location));
let args = Args::new(vec![PosArg::new(convert_expr(*b))], vec![], None);
method.call_expr(args)
}
_other => {
erg_common::log!(err "unimplemented: {:?}", _other);
Expr::Dummy(Dummy::empty())
},
}
}
fn convert_block(block: Vec<Located<StatementType>>) -> Block {
Block::new(block.into_iter().map(convert_statement).collect::<Vec<_>>())
}
fn convert_statement(stmt: Located<StatementType>) -> Expr {
match stmt.node {
StatementType::Expression { expression } => convert_expr(expression),
StatementType::Assign { mut targets, value } => {
let lhs = targets.remove(0);
match lhs.node {
ExpressionType::Identifier { name } => {
let ident = convert_ident(name, stmt.location);
let sig = Signature::Var(VarSignature::new(VarPattern::Ident(ident), None));
let block = Block::new(vec![convert_expr(value)]);
let body = DefBody::new(EQUAL, block, DefId(0));
let def = Def::new(sig, body);
Expr::Def(def)
}
ExpressionType::Attribute { value: attr, name } => {
let attr = convert_expr(*attr).attr(convert_ident(name, lhs.location));
let expr = convert_expr(value);
let adef = AttrDef::new(attr, expr);
Expr::AttrDef(adef)
}
_other => Expr::Dummy(Dummy::empty()),
}
}
StatementType::FunctionDef {
is_async: _,
name,
args,
body,
decorator_list,
returns
} => {
let decos = decorator_list.into_iter().map(|ex| Decorator(convert_expr(ex))).collect::<HashSet<_>>();
let ident = convert_ident(name, stmt.location);
let params = convert_params(args);
let return_t = returns.map(convert_type_spec);
let sig = Signature::Subr(SubrSignature::new(decos, ident, TypeBoundSpecs::empty(), params, return_t));
let block = convert_block(body);
let body = DefBody::new(EQUAL, block, DefId(0));
let def = Def::new(sig, body);
Expr::Def(def)
}
// TODO
StatementType::ClassDef { name: _, body, bases, keywords: _, decorator_list } => {
let exprs = decorator_list.into_iter().map(convert_expr).collect::<Vec<_>>();
let bases = bases.into_iter().map(convert_expr).collect::<Vec<_>>();
// let decos = decorator_list.into_iter().map(|ex| Decorator(convert_expr(ex))).collect::<Set<_>>();
// let ident = convert_ident(name, stmt.location);
// let params = Params::new(vec![], None, vec![], None);
let mut block = convert_block(body);
block.extend(exprs);
block.extend(bases);
// let body = DefBody::new(EQUAL, block, DefId(0));
// let def = Def::new(sig, body);
Expr::Dummy(Dummy::new(block.into_iter().collect()))
}
StatementType::For { is_async: _, target, iter, body, orelse: _ } => {
let block = convert_for_body(*target, body);
let iter = convert_expr(*iter);
let for_ident = convert_ident("for!".to_string(), stmt.location);
let for_acc = Expr::Accessor(Accessor::Ident(for_ident));
for_acc.call_expr(Args::new(vec![PosArg::new(iter), PosArg::new(Expr::Lambda(block))], vec![], None))
}
StatementType::While { test, body, orelse: _ } => {
let block = convert_block(body);
let params = Params::new(vec![], None, vec![], None);
let body = Lambda::new(LambdaSignature::new(params, None, TypeBoundSpecs::empty()), Token::DUMMY, block, DefId(0));
let test = convert_expr(test);
let while_ident = convert_ident("while!".to_string(), stmt.location);
let while_acc = Expr::Accessor(Accessor::Ident(while_ident));
while_acc.call_expr(Args::new(vec![PosArg::new(test), PosArg::new(Expr::Lambda(body))], vec![], None))
}
StatementType::If { test, body, orelse } => {
let block = convert_block(body);
let params = Params::new(vec![], None, vec![], None);
let sig = LambdaSignature::new(params.clone(), None, TypeBoundSpecs::empty());
let body = Lambda::new(sig, Token::DUMMY, block, DefId(0));
let test = convert_expr(test);
let if_ident = convert_ident("if!".to_string(), stmt.location);
let if_acc = Expr::Accessor(Accessor::Ident(if_ident));
if let Some(orelse) = orelse {
let else_block = convert_block(orelse);
let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
let else_body = Lambda::new(sig, Token::DUMMY, else_block, DefId(0));
let args = Args::new(vec![PosArg::new(test), PosArg::new(Expr::Lambda(body)), PosArg::new(Expr::Lambda(else_body))], vec![], None);
if_acc.call_expr(args)
} else {
let args = Args::new(vec![PosArg::new(test), PosArg::new(Expr::Lambda(body))], vec![], None);
if_acc.call_expr(args)
}
}
// This is fine for static analysis only.
StatementType::Return { value } => {
value.map(convert_expr)
.unwrap_or_else(||Expr::Tuple(Tuple::Normal(NormalTuple::new(Args::empty()))))
}
_other => {
erg_common::log!(err "unimplemented: {:?}", _other);
Expr::Dummy(Dummy::empty())
},
}
}
pub fn convert_program(program: Program) -> Module {
Module::new(program.statements.into_iter().map(convert_statement).collect())
}

2
crates/py2erg/lib.rs Normal file
View file

@ -0,0 +1,2 @@
mod convert;
pub use convert::*;

3
extension/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*.vsix
node_modules
example.py

17
extension/.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,17 @@
// A launch configuration that launches the extension inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
]
}
]
}

3
extension/.vscodeignore Normal file
View file

@ -0,0 +1,3 @@
.vscode/**
.vscode-test/**
.gitignore

19
extension/LICENSE Normal file
View file

@ -0,0 +1,19 @@
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

11
extension/README.md Normal file
View file

@ -0,0 +1,11 @@
# vscode-pype
## Requirements
You need to have the [pype](https://github.com/mtshiba/pype) installed on your system.
To install it, run the following command:
```console
cargo install pype
```

32
extension/extension.js Normal file
View file

@ -0,0 +1,32 @@
"use strict";
const vscode = require("vscode");
const languageclient = require("vscode-languageclient");
let client;
function activate(context) {
try {
const serverOptions = {
command: "pype",
args: ["--server"]
};
const clientOptions = {
documentSelector: [
{
scheme: "file",
language: "python",
}
],
};
client = new languageclient.LanguageClient("pype", serverOptions, clientOptions);
context.subscriptions.push(client.start());
} catch (e) {
vscode.window.showErrorMessage("failed to start pype.");
}
}
function deactivate() {
if (client) return client.stop();
}
module.exports = { activate, deactivate }

113
extension/package-lock.json generated Normal file
View file

@ -0,0 +1,113 @@
{
"name": "vscode-pype",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "vscode-pype",
"version": "0.1.0",
"dependencies": {
"vscode-languageclient": "^7.0.0"
},
"engines": {
"vscode": "^1.70.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/semver": {
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/vscode-jsonrpc": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz",
"integrity": "sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==",
"engines": {
"node": ">=8.0.0 || >=10.0.0"
}
},
"node_modules/vscode-languageclient": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.0.0.tgz",
"integrity": "sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg==",
"dependencies": {
"minimatch": "^3.0.4",
"semver": "^7.3.4",
"vscode-languageserver-protocol": "3.16.0"
},
"engines": {
"vscode": "^1.52.0"
}
},
"node_modules/vscode-languageserver-protocol": {
"version": "3.16.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz",
"integrity": "sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==",
"dependencies": {
"vscode-jsonrpc": "6.0.0",
"vscode-languageserver-types": "3.16.0"
}
},
"node_modules/vscode-languageserver-types": {
"version": "3.16.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz",
"integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA=="
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
}

38
extension/package.json Normal file
View file

@ -0,0 +1,38 @@
{
"name": "vscode-pype",
"displayName": "pype",
"description": "A Python static code analyzer & language server for VSCode",
"publisher": "gmshiba",
"version": "0.1.0",
"engines": {
"vscode": "^1.70.0"
},
"categories": [
"Programming Languages"
],
"repository": {
"type": "git",
"url": "https://github.com/mtshiba/pype.git"
},
"main": "./extension.js",
"activationEvents": [
"onLanguage:python"
],
"contributes": {
"languages": [
{
"id": "python",
"aliases": [
"Python",
"python"
],
"extensions": [
".py"
]
}
]
},
"dependencies": {
"vscode-languageclient": "^7.0.0"
}
}

105
src/analyze.rs Normal file
View file

@ -0,0 +1,105 @@
use erg_common::traits::{Runnable, Stream};
use erg_common::config::{ErgConfig};
use erg_common::error::MultiErrorDisplay;
use erg_compiler::artifact::{BuildRunnable, CompleteArtifact, IncompleteArtifact, Buildable};
use erg_compiler::context::Context;
use erg_compiler::erg_parser::ast::AST;
use erg_compiler::error::{CompileErrors, CompileError};
use erg_compiler::lower::ASTLowerer;
use rustpython_parser::parser;
use crate::handle_err;
#[derive(Debug, Default)]
pub struct PythonAnalyzer {
pub cfg: ErgConfig,
checker: ASTLowerer,
}
impl Runnable for PythonAnalyzer {
type Err = CompileError;
type Errs = CompileErrors;
const NAME: &'static str = "Python Analyzer";
fn new(cfg: ErgConfig) -> Self {
let checker = ASTLowerer::new(cfg.clone());
Self {
checker,
cfg,
}
}
fn cfg(&self) -> &ErgConfig {
&self.cfg
}
fn finish(&mut self) {
self.checker.finish();
}
fn initialize(&mut self) {
self.checker.initialize();
}
fn clear(&mut self) {
self.checker.clear();
}
fn eval(&mut self, src: String) -> Result<String, Self::Errs> {
self.checker.eval(src)
}
fn exec(&mut self) -> Result<i32, Self::Errs> {
self.checker.exec()
}
}
impl Buildable for PythonAnalyzer {
fn build(&mut self, code: String, mode: &str) -> Result<CompleteArtifact, IncompleteArtifact> {
self.analyze(code, mode)
}
fn pop_context(&mut self) -> Option<Context> {
Some(self.checker.pop_mod_ctx())
}
fn get_context(&self) -> Option<&Context> {
Some(self.checker.get_mod_ctx())
}
}
impl BuildRunnable for PythonAnalyzer {}
impl PythonAnalyzer {
pub fn analyze(&mut self, py_code: String, mode: &str) -> Result<CompleteArtifact, IncompleteArtifact> {
let filename = self.cfg.input.filename();
let py_program = parser::parse_program(&py_code).unwrap();
let erg_module = py2erg::convert_program(py_program);
let erg_ast = AST::new(erg_common::Str::rc(filename), erg_module);
self.checker.lower(erg_ast, mode).map_err(|iart| {
let filtered = handle_err::filter_errors(self.checker.get_mod_ctx(), iart.errors);
IncompleteArtifact::new(iart.object, filtered, iart.warns)
})
}
pub fn run(&mut self) {
let filename = self.cfg.input.filename();
let py_code = self.cfg.input.read();
println!("Start checking: {filename}");
match self.analyze(py_code, "exec") {
Ok(artifact) => {
if !artifact.warns.is_empty() {
println!("Found warnings: {}", artifact.warns.len());
artifact.warns.fmt_all_stderr();
}
println!("All checks OK.");
std::process::exit(0);
}
Err(artifact) => {
if !artifact.warns.is_empty() {
println!("Found warnings: {}", artifact.warns.len());
artifact.warns.fmt_all_stderr();
}
if artifact.errors.is_empty() {
println!("All checks OK.");
std::process::exit(0);
} else {
println!("Found errors: {}", artifact.errors.len());
artifact.errors.fmt_all_stderr();
std::process::exit(1);
}
}
}
}
}

40
src/handle_err.rs Normal file
View file

@ -0,0 +1,40 @@
use erg_common::error::ErrorKind;
use erg_common::style::{remove_style, StyledString, Color};
use erg_compiler::error::{CompileErrors, CompileError};
use erg_compiler::context::Context;
pub(crate) fn filter_errors(ctx: &Context, errors: CompileErrors) -> CompileErrors {
errors.into_iter().filter_map(|error| filter_error(ctx, error)).collect()
}
fn filter_error(ctx: &Context, error: CompileError) -> Option<CompileError> {
match error.core.kind {
ErrorKind::VisibilityError => None,
ErrorKind::NameError => Some(map_name_error(ctx, error)),
ErrorKind::AssignError => handle_assign_error(error),
_ => Some(error),
}
}
fn map_name_error(ctx: &Context, mut error: CompileError) -> CompileError {
let hint = error.core.sub_messages.iter_mut().find_map(|sub| sub.hint.as_mut());
if let Some(hint) = hint {
if let Some(name) = hint.split("exists a similar name variable: ").last() {
let name = remove_style(name);
if let Some((_, vi)) = ctx.get_var_info(&name) {
if let Some(py_name) = &vi.py_name {
*hint = format!("exists a similar name variable: {}", StyledString::new(&py_name[..], Some(Color::Green), None));
}
}
}
}
error
}
fn handle_assign_error(error: CompileError) -> Option<CompileError> {
if error.core.main_message.ends_with("cannot be assigned more than once") {
None
} else {
Some(error)
}
}

82
src/main.rs Normal file
View file

@ -0,0 +1,82 @@
mod handle_err;
mod analyze;
use std::env;
use std::path::PathBuf;
use std::str::FromStr;
use analyze::PythonAnalyzer;
use els::Server;
use erg_common::config::{Input, ErgConfig};
use erg_common::traits::Runnable;
pub fn parse_args() -> ErgConfig {
let mut args = env::args();
args.next(); // "pype"
let mut cfg = ErgConfig::default();
while let Some(arg) = args.next() {
match &arg[..] {
"--" => {
for arg in args {
cfg.runtime_args.push(Box::leak(arg.into_boxed_str()));
}
break;
}
"-c" | "--code" => {
cfg.input = Input::Str(args.next().expect("the value of `-c` is not passed"));
}
"--server" => {
cfg.mode = "server";
}
"--verbose" => {
cfg.verbose = args
.next()
.expect("the value of `--verbose` is not passed")
.parse::<u8>()
.expect("the value of `--verbose` is not a number");
}
"-V" | "--version" => {
println!("Erg {}", env!("CARGO_PKG_VERSION"));
std::process::exit(0);
}
other if other.starts_with('-') => {
println!(
"\
invalid option: {other}
USAGE:
pype [OPTIONS] [SUBCOMMAND] [ARGS]...
For more information try `pype --help`"
);
std::process::exit(2);
}
_ => {
cfg.input = Input::File(
PathBuf::from_str(&arg[..])
.unwrap_or_else(|_| panic!("invalid file path: {}", arg)),
);
if let Some("--") = args.next().as_ref().map(|s| &s[..]) {
for arg in args {
cfg.runtime_args.push(Box::leak(arg.into_boxed_str()));
}
}
break;
}
}
}
cfg
}
fn main() {
let cfg = parse_args();
if cfg.mode == "server" {
let mut lang_server = Server::<PythonAnalyzer>::new();
lang_server.run().unwrap_or_else(|_| {
std::process::exit(1);
});
} else {
let mut analyzer = PythonAnalyzer::new(cfg);
analyzer.run();
}
}

28
tests/test.py Normal file
View file

@ -0,0 +1,28 @@
def add(x, y):
return x + y
print(add(1, 2))
print(add(1, "a"))
add.x = 1
def add2(x: int, y: int) -> str:
return x + y
print(add2(1, 2))
for i in [1, 2, 3]:
j = i + "aa"
print(j)
while "aaa":
print("invalid")
break
class C:
x = 1 + "a"
dic = {"a": 1, "b": 2}
print(dic["c"])
a = [1, 2, 3]
print(a[4])