Compare commits

..

No commits in common. "ndarray" and "master" have entirely different histories.

50 changed files with 1919 additions and 2278 deletions

59
Cargo.lock generated
View File

@ -320,21 +320,24 @@ dependencies = [
[[package]] [[package]]
name = "inkwell" name = "inkwell"
version = "0.1.0" version = "0.1.0-beta.4"
source = "git+https://github.com/nbaksalyar/inkwell.git?branch=llvm14#54f9e286279666d40d5f6e2c3fde8a91334a7b63" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2223d0eba0ae6d40a3e4680c6a3209143471e1f38b41746ea309aa36dde9f90b"
dependencies = [ dependencies = [
"either", "either",
"inkwell_internals", "inkwell_internals",
"libc", "libc",
"llvm-sys", "llvm-sys",
"once_cell", "once_cell",
"parking_lot 0.12.0", "parking_lot 0.11.2",
"regex",
] ]
[[package]] [[package]]
name = "inkwell_internals" name = "inkwell_internals"
version = "0.5.0" version = "0.5.0"
source = "git+https://github.com/nbaksalyar/inkwell.git?branch=llvm14#54f9e286279666d40d5f6e2c3fde8a91334a7b63" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c7090af3d300424caa81976b8c97bca41cd70e861272c072e188ae082fb49f9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -419,9 +422,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.123" version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd" checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -441,9 +444,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]] [[package]]
name = "llvm-sys" name = "llvm-sys"
version = "140.0.0" version = "130.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edbec78fa56ea7a1ff451683a51b8ecf79a65ca9e88a4be6c4b0a6fc300d2a6" checksum = "95eb03b4f7ae21f48ef7c565a3e3aa22c50616aea64645fb1fd7f6f56b51c274"
dependencies = [ dependencies = [
"cc", "cc",
"lazy_static", "lazy_static",
@ -639,6 +642,15 @@ dependencies = [
"proc-macro-hack", "proc-macro-hack",
] ]
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[package]] [[package]]
name = "petgraph" name = "petgraph"
version = "0.5.1" version = "0.5.1"
@ -824,9 +836,9 @@ dependencies = [
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.5.2" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221" checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"crossbeam-deque", "crossbeam-deque",
@ -836,13 +848,14 @@ dependencies = [
[[package]] [[package]]
name = "rayon-core" name = "rayon-core"
version = "1.9.2" version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4" checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
dependencies = [ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"crossbeam-deque", "crossbeam-deque",
"crossbeam-utils", "crossbeam-utils",
"lazy_static",
"num_cpus", "num_cpus",
] ]
@ -919,9 +932,21 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.7" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
dependencies = [
"pest",
]
[[package]] [[package]]
name = "serde" name = "serde"
@ -1096,6 +1121,12 @@ dependencies = [
"crunchy", "crunchy",
] ]
[[package]]
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]] [[package]]
name = "unic-char-property" name = "unic-char-property"
version = "0.9.0" version = "0.9.0"

View File

@ -1,10 +1,5 @@
<div align="center">
![icon](https://git.m-labs.hk/M-Labs/nac3/raw/branch/master/nac3.svg)
</div>
# NAC3 # NAC3
NAC3 is a major, backward-incompatible rewrite of the compiler for the [ARTIQ](https://m-labs.hk/artiq) physics experiment control and data acquisition system. It features greatly improved compilation speeds, a much better type system, and more predictable and transparent operation. NAC3 is a major, backward-incompatible rewrite of the compiler for the [ARTIQ](https://m-labs.hk/artiq) physics experiment control and data acquisition system. It features greatly improved compilation speeds, a much better type system, and more predictable and transparent operation.
NAC3 has a modular design and its applicability reaches beyond ARTIQ. The ``nac3core`` module does not contain anything specific to ARTIQ, and can be used in any project that requires compiling Python to machine code. NAC3 has a modular design and its applicability reaches beyond ARTIQ. The ``nac3core`` module does not contain anything specific to ARTIQ, and can be used in any project that requires compiling Python to machine code.

View File

@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1650244918, "lastModified": 1649619156,
"narHash": "sha256-DsS5nxjTpnoUC4pNXJI1rit7TnDTij8vQDa5PtcDCD0=", "narHash": "sha256-p0q4zpuKMwrzGF+5ZU7Thnpac5TinhDI9jr2mBxhV4w=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "7b38b03d76ab71bdc8dc325e3f6338d984cc35ca", "rev": "e7d63bd0d50df412f5a1d8acfa3caae75522e347",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -5,23 +5,17 @@
outputs = { self, nixpkgs }: outputs = { self, nixpkgs }:
let let
pkgs = import nixpkgs { system = "aarch64-darwin"; }; pkgs = import nixpkgs { system = "x86_64-linux"; };
in rec { in rec {
packages.aarch64-darwin = rec { packages.x86_64-linux = rec {
llvm-nac3 = pkgs.callPackage ./nix/llvm {}; llvm-nac3 = pkgs.callPackage ./nix/llvm {};
nac3artiq = pkgs.python3Packages.toPythonModule ( nac3artiq = pkgs.python3Packages.toPythonModule (
pkgs.rustPlatform.buildRustPackage rec { pkgs.rustPlatform.buildRustPackage {
name = "nac3artiq"; name = "nac3artiq";
outputs = [ "out" "runkernel" "standalone" ]; outputs = [ "out" "runkernel" "standalone" ];
src = self; src = self;
cargoLock = { cargoLock = { lockFile = ./Cargo.lock; };
lockFile = ./Cargo.lock; nativeBuildInputs = [ pkgs.python3 pkgs.llvmPackages_13.clang-unwrapped llvm-nac3 ];
outputHashes = {
"inkwell-0.1.0" = "sha256-THGKoTqQCSusxMukOiksQ9pCnxdIBUO6MH3fiwQjYVA=";
};
};
passthru.cargoLock = cargoLock;
nativeBuildInputs = [ pkgs.python3 pkgs.llvmPackages_13.clang-unwrapped pkgs.llvmPackages_13.llvm.out llvm-nac3 ];
buildInputs = [ pkgs.python3 llvm-nac3 ]; buildInputs = [ pkgs.python3 llvm-nac3 ];
checkInputs = [ (pkgs.python3.withPackages(ps: [ ps.numpy ])) ]; checkInputs = [ (pkgs.python3.withPackages(ps: [ ps.numpy ])) ];
checkPhase = checkPhase =
@ -62,8 +56,8 @@
pkgs.rustPlatform.buildRustPackage { pkgs.rustPlatform.buildRustPackage {
name = "nac3artiq-instrumented"; name = "nac3artiq-instrumented";
src = self; src = self;
inherit (nac3artiq) cargoLock; cargoLock = { lockFile = ./Cargo.lock; };
nativeBuildInputs = [ pkgs.python3 pkgs.llvmPackages_13.clang-unwrapped pkgs.llvmPackages_13.llvm.out llvm-nac3-instrumented ]; nativeBuildInputs = [ pkgs.python3 pkgs.llvmPackages_13.clang-unwrapped llvm-nac3-instrumented ];
buildInputs = [ pkgs.python3 llvm-nac3-instrumented ]; buildInputs = [ pkgs.python3 llvm-nac3-instrumented ];
cargoBuildFlags = [ "--package" "nac3artiq" "--features" "init-llvm-profile" ]; cargoBuildFlags = [ "--package" "nac3artiq" "--features" "init-llvm-profile" ];
doCheck = false; doCheck = false;
@ -81,36 +75,11 @@
); );
nac3artiq-profile = pkgs.stdenvNoCC.mkDerivation { nac3artiq-profile = pkgs.stdenvNoCC.mkDerivation {
name = "nac3artiq-profile"; name = "nac3artiq-profile";
srcs = [ src = self;
(pkgs.fetchFromGitHub { buildInputs = [ (python3-mimalloc.withPackages(ps: [ ps.numpy nac3artiq-instrumented ])) pkgs.lld_13 pkgs.llvmPackages_13.libllvm ];
owner = "m-labs";
repo = "sipyco";
rev = "939f84f9b5eef7efbf7423c735d1834783b6140e";
sha256 = "sha256-15Nun4EY35j+6SPZkjzZtyH/ncxLS60KuGJjFh5kSTc=";
})
(pkgs.fetchFromGitHub {
owner = "m-labs";
repo = "artiq";
rev = "dd57fdc530baf926a5f354dc1c2bd90564affd96";
sha256 = "sha256-hcqVcToYWkc3oDFkKr9wZUF65ydiSYVHdmiGiu2Mc1c=";
})
];
buildInputs = [
(python3-mimalloc.withPackages(ps: [ ps.numpy ps.jsonschema nac3artiq-instrumented ]))
pkgs.lld_13
pkgs.llvmPackages_13.llvm.out
];
phases = [ "buildPhase" "installPhase" ]; phases = [ "buildPhase" "installPhase" ];
buildPhase = # TODO: get more representative code.
'' buildPhase = "python $src/nac3artiq/demo/demo.py";
srcs=($srcs)
sipyco=''${srcs[0]}
artiq=''${srcs[1]}
export PYTHONPATH=$sipyco:$artiq
python -m artiq.frontend.artiq_ddb_template $artiq/artiq/examples/nac3devices/nac3devices.json > device_db.py
cp $artiq/artiq/examples/nac3devices/nac3devices.py .
python -m artiq.frontend.artiq_compile nac3devices.py
'';
installPhase = installPhase =
'' ''
mkdir $out mkdir $out
@ -125,8 +94,8 @@
pkgs.rustPlatform.buildRustPackage { pkgs.rustPlatform.buildRustPackage {
name = "nac3artiq-pgo"; name = "nac3artiq-pgo";
src = self; src = self;
inherit (nac3artiq) cargoLock; cargoLock = { lockFile = ./Cargo.lock; };
nativeBuildInputs = [ pkgs.python3 pkgs.llvmPackages_13.clang-unwrapped pkgs.llvmPackages_13.llvm.out llvm-nac3-pgo ]; nativeBuildInputs = [ pkgs.python3 pkgs.llvmPackages_13.clang-unwrapped llvm-nac3-pgo ];
buildInputs = [ pkgs.python3 llvm-nac3-pgo ]; buildInputs = [ pkgs.python3 llvm-nac3-pgo ];
cargoBuildFlags = [ "--package" "nac3artiq" ]; cargoBuildFlags = [ "--package" "nac3artiq" ];
cargoTestFlags = [ "--package" "nac3ast" "--package" "nac3parser" "--package" "nac3core" "--package" "nac3artiq" ]; cargoTestFlags = [ "--package" "nac3ast" "--package" "nac3parser" "--package" "nac3core" "--package" "nac3artiq" ];
@ -142,26 +111,24 @@
packages.x86_64-w64-mingw32 = import ./nix/windows { inherit pkgs; }; packages.x86_64-w64-mingw32 = import ./nix/windows { inherit pkgs; };
devShell.aarch64-darwin = pkgs.mkShell { devShell.x86_64-linux = pkgs.mkShell {
name = "nac3-dev-shell"; name = "nac3-dev-shell";
buildInputs = with pkgs; [ buildInputs = with pkgs; [
# build dependencies # build dependencies
packages.aarch64-darwin.llvm-nac3 packages.x86_64-linux.llvm-nac3
llvmPackages_13.clang-unwrapped # IRRT llvmPackages_13.clang-unwrapped # IRRT
pkgs.llvmPackages_13.llvm.out # IRRT
libiconv
cargo cargo
rustc rustc
# runtime dependencies # runtime dependencies
lld_13 lld_13
(packages.aarch64-darwin.python3-mimalloc.withPackages(ps: [ ps.numpy ])) (packages.x86_64-linux.python3-mimalloc.withPackages(ps: [ ps.numpy ]))
# development tools # development tools
cargo-insta cargo-insta
clippy clippy
rustfmt rustfmt
]; ];
}; };
devShells.aarch64-darwin.msys2 = pkgs.mkShell { devShells.x86_64-linux.msys2 = pkgs.mkShell {
name = "nac3-dev-shell-msys2"; name = "nac3-dev-shell-msys2";
buildInputs = with pkgs; [ buildInputs = with pkgs; [
curl curl
@ -172,7 +139,7 @@
}; };
hydraJobs = { hydraJobs = {
inherit (packages.aarch64-darwin) llvm-nac3 nac3artiq nac3artiq-pgo; inherit (packages.x86_64-linux) llvm-nac3 nac3artiq;
llvm-nac3-msys2 = packages.x86_64-w64-mingw32.llvm-nac3; llvm-nac3-msys2 = packages.x86_64-w64-mingw32.llvm-nac3;
nac3artiq-msys2 = packages.x86_64-w64-mingw32.nac3artiq; nac3artiq-msys2 = packages.x86_64-w64-mingw32.nac3artiq;
nac3artiq-msys2-pkg = packages.x86_64-w64-mingw32.nac3artiq-pkg; nac3artiq-msys2-pkg = packages.x86_64-w64-mingw32.nac3artiq-pkg;
@ -181,7 +148,7 @@
}; };
nixConfig = { nixConfig = {
extra-trusted-public-keys = "nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc="; binaryCachePublicKeys = ["nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc="];
extra-substituters = "https://nixbld.m-labs.hk"; binaryCaches = ["https://nixbld.m-labs.hk" "https://cache.nixos.org"];
}; };
} }

View File

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="a"
width="128"
height="128"
viewBox="0 0 95.99999 95.99999"
version="1.1"
sodipodi:docname="nac3.svg"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs11" />
<sodipodi:namedview
id="namedview9"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
units="px"
width="128px"
inkscape:zoom="5.9448568"
inkscape:cx="60.472441"
inkscape:cy="60.556547"
inkscape:window-width="2560"
inkscape:window-height="1371"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="a" />
<rect
x="40.072601"
y="-26.776209"
width="55.668747"
height="55.668747"
transform="matrix(0.71803815,0.69600374,-0.71803815,0.69600374,0,0)"
style="fill:#be211e;stroke:#000000;stroke-width:4.37375px;stroke-linecap:round;stroke-linejoin:round"
id="rect2" />
<line
x1="38.00692"
y1="63.457153"
x2="57.993061"
y2="63.457153"
style="fill:none;stroke:#000000;stroke-width:4.37269px;stroke-linecap:round;stroke-linejoin:round"
id="line4" />
<path
d="m 48.007301,57.843329 c -1.943097,0 -3.877522,-0.41727 -5.686157,-1.246007 -3.218257,-1.474616 -5.650382,-4.075418 -6.849639,-7.323671 -2.065624,-5.588921 -1.192751,-10.226647 2.575258,-13.827 0.611554,-0.584909 1.518048,-0.773041 2.323689,-0.488206 0.80673,0.286405 1.369495,0.998486 1.447563,1.827234 0.237469,2.549302 2.439719,5.917376 4.28414,6.55273 0.396859,0.13506 0.820953,-0.05859 1.097084,-0.35222 0.339254,-0.360754 0.451065,-0.961893 -1.013597,-3.191372 -2.089851,-3.181137 -4.638728,-8.754903 -0.262407,-15.069853 0.494457,-0.713491 1.384673,-1.068907 2.256469,-0.909156 0.871795,0.161332 1.583757,0.806404 1.752251,1.651189 0.716448,3.591862 2.962357,6.151755 5.199306,8.023138 1.935503,1.61861 4.344688,3.867387 5.435687,7.096643 2.283183,6.758017 -1.202511,14.114988 -8.060822,16.494025 -1.467083,0.509226 -2.98513,0.762536 -4.498836,0.762536 z M 39.358865,40.002192 c -0.304711,0.696206 -0.541636,2.080524 -0.56865,2.237454 -0.330316,1.918771 0.168305,3.803963 0.846157,5.539951 0.856828,2.19436 2.437543,3.942467 4.583411,4.925713 2.143691,0.981675 4.554131,1.097816 6.789992,0.322666 4.571485,-1.586549 6.977584,-6.532238 5.363036,-11.02597 v -5.27e-4 C 55.455481,39.447968 54.023463,38.162043 52.221335,36.65432 50.876945,35.529534 49.409662,33.987726 48.417983,32.135555 48.01343,31.37996 47.79547,30.34303 47.76669,29.413263 c -0.187481,0.669514 -0.212441,2.325923 -0.150396,2.93691 0.179209,1.764456 1.333476,3.644546 2.340611,5.171243 1.311568,1.988179 2.72058,6.037272 0.459681,8.367985 -1.54192,1.58953 -4.038511,2.052034 -5.839973,1.38492 -2.398314,-0.888147 -3.942744,-2.690627 -4.941118,-4.768029 -0.121194,-0.25217 -0.532464,-1.174187 -0.276619,-2.5041 z"
id="path6"
style="stroke-width:1.09317" />
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -16,10 +16,9 @@ nac3parser = { path = "../nac3parser" }
nac3core = { path = "../nac3core" } nac3core = { path = "../nac3core" }
[dependencies.inkwell] [dependencies.inkwell]
git = "https://github.com/nbaksalyar/inkwell.git" version = "0.1.0-beta.4"
branch = "llvm14"
default-features = false default-features = false
features = ["llvm14-0", "target-aarch64", "target-arm", "target-riscv", "no-libffi-linking"] features = ["llvm13-0", "target-x86", "target-arm", "target-riscv", "no-libffi-linking"]
[features] [features]
init-llvm-profile = [] init-llvm-profile = []

View File

@ -6,7 +6,7 @@ use nac3core::{
}, },
symbol_resolver::ValueEnum, symbol_resolver::ValueEnum,
toplevel::{DefinitionId, GenCall}, toplevel::{DefinitionId, GenCall},
typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum}, typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum}
}; };
use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef}; use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
@ -15,10 +15,7 @@ use inkwell::{
context::Context, module::Linkage, types::IntType, values::BasicValueEnum, AddressSpace, context::Context, module::Linkage, types::IntType, values::BasicValueEnum, AddressSpace,
}; };
use pyo3::{ use pyo3::{PyObject, PyResult, Python, types::{PyDict, PyList}};
types::{PyDict, PyList},
PyObject, PyResult, Python,
};
use crate::{symbol_resolver::InnerResolver, timeline::TimeFns}; use crate::{symbol_resolver::InnerResolver, timeline::TimeFns};
@ -71,11 +68,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
) -> Result<Option<BasicValueEnum<'ctx>>, String> { ) -> Result<Option<BasicValueEnum<'ctx>>, String> {
let result = gen_call(self, ctx, obj, fun, params)?; let result = gen_call(self, ctx, obj, fun, params)?;
if let Some(end) = self.end.clone() { if let Some(end) = self.end.clone() {
let old_end = self.gen_expr(ctx, &end)?.unwrap().to_basic_value_enum( let old_end = self.gen_expr(ctx, &end)?.unwrap().to_basic_value_enum(ctx, self, end.custom.unwrap())?;
ctx,
self,
end.custom.unwrap(),
)?;
let now = self.timeline.emit_now_mu(ctx); let now = self.timeline.emit_now_mu(ctx);
let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| { let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
let i64 = ctx.ctx.i64_type(); let i64 = ctx.ctx.i64_type();
@ -95,11 +88,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
ctx.builder.build_store(end_store, max); ctx.builder.build_store(end_store, max);
} }
if let Some(start) = self.start.clone() { if let Some(start) = self.start.clone() {
let start_val = self.gen_expr(ctx, &start)?.unwrap().to_basic_value_enum( let start_val = self.gen_expr(ctx, &start)?.unwrap().to_basic_value_enum(ctx, self, start.custom.unwrap())?;
ctx,
self,
start.custom.unwrap(),
)?;
self.timeline.emit_at_mu(ctx, start_val); self.timeline.emit_at_mu(ctx, start_val);
} }
Ok(result) Ok(result)
@ -131,11 +120,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
let old_start = self.start.take(); let old_start = self.start.take();
let old_end = self.end.take(); let old_end = self.end.take();
let now = if let Some(old_start) = &old_start { let now = if let Some(old_start) = &old_start {
self.gen_expr(ctx, old_start)?.unwrap().to_basic_value_enum( self.gen_expr(ctx, old_start)?.unwrap().to_basic_value_enum(ctx, self, old_start.custom.unwrap())?
ctx,
self,
old_start.custom.unwrap(),
)?
} else { } else {
self.timeline.emit_now_mu(ctx) self.timeline.emit_now_mu(ctx)
}; };
@ -189,11 +174,10 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
}; };
// set duration // set duration
let end_expr = self.end.take().unwrap(); let end_expr = self.end.take().unwrap();
let end_val = self.gen_expr(ctx, &end_expr)?.unwrap().to_basic_value_enum( let end_val = self
ctx, .gen_expr(ctx, &end_expr)?
self, .unwrap()
end_expr.custom.unwrap(), .to_basic_value_enum(ctx, self, end_expr.custom.unwrap())?;
)?;
// inside a sequential block // inside a sequential block
if old_start.is_none() { if old_start.is_none() {
@ -309,7 +293,7 @@ fn rpc_codegen_callback_fn<'ctx, 'a>(
let int32 = ctx.ctx.i32_type(); let int32 = ctx.ctx.i32_type();
let tag_ptr_type = ctx.ctx.struct_type(&[ptr_type.into(), size_type.into()], false); let tag_ptr_type = ctx.ctx.struct_type(&[ptr_type.into(), size_type.into()], false);
let service_id = int32.const_int(fun.1 .0 as u64, false); let service_id = int32.const_int(fun.1.0 as u64, false);
// -- setup rpc tags // -- setup rpc tags
let mut tag = Vec::new(); let mut tag = Vec::new();
if obj.is_some() { if obj.is_some() {
@ -379,8 +363,10 @@ fn rpc_codegen_callback_fn<'ctx, 'a>(
} }
// default value handling // default value handling
for k in keys.into_iter() { for k in keys.into_iter() {
mapping mapping.insert(
.insert(k.name, ctx.gen_symbol_val(generator, &k.default_value.unwrap(), k.ty).into()); k.name,
ctx.gen_symbol_val(generator, &k.default_value.unwrap(), k.ty).into()
);
} }
// reorder the parameters // reorder the parameters
let mut real_params = fun let mut real_params = fun
@ -521,15 +507,9 @@ pub fn attributes_writeback<'ctx, 'a>(
let mut scratch_buffer = Vec::new(); let mut scratch_buffer = Vec::new();
for (_, val) in globals.iter() { for (_, val) in globals.iter() {
let val = val.as_ref(py); let val = val.as_ref(py);
let ty = inner_resolver.get_obj_type( let ty = inner_resolver.get_obj_type(py, val, &mut ctx.unifier, &top_levels, &ctx.primitives)?;
py,
val,
&mut ctx.unifier,
&top_levels,
&ctx.primitives,
)?;
if let Err(ty) = ty { if let Err(ty) = ty {
return Ok(Err(ty)); return Ok(Err(ty))
} }
let ty = ty.unwrap(); let ty = ty.unwrap();
match &*ctx.unifier.get_ty(ty) { match &*ctx.unifier.get_ty(ty) {
@ -542,18 +522,14 @@ pub fn attributes_writeback<'ctx, 'a>(
let obj = inner_resolver.get_obj_value(py, val, ctx, generator, ty)?.unwrap(); let obj = inner_resolver.get_obj_value(py, val, ctx, generator, ty)?.unwrap();
for (name, (field_ty, is_mutable)) in fields.iter() { for (name, (field_ty, is_mutable)) in fields.iter() {
if !is_mutable { if !is_mutable {
continue; continue
} }
if gen_rpc_tag(ctx, *field_ty, &mut scratch_buffer).is_ok() { if gen_rpc_tag(ctx, *field_ty, &mut scratch_buffer).is_ok() {
attributes.push(name.to_string()); attributes.push(name.to_string());
let index = ctx.get_attr_index(ty, *name); let index = ctx.get_attr_index(ty, *name);
values.push(( values.push((*field_ty, ctx.build_gep_and_load(
*field_ty, obj.into_pointer_value(),
ctx.build_gep_and_load( &[zero, int32.const_int(index as u64, false)])));
obj.into_pointer_value(),
&[zero, int32.const_int(index as u64, false)],
),
));
} }
} }
if !attributes.is_empty() { if !attributes.is_empty() {
@ -562,43 +538,33 @@ pub fn attributes_writeback<'ctx, 'a>(
pydict.set_item("fields", attributes)?; pydict.set_item("fields", attributes)?;
host_attributes.append(pydict)?; host_attributes.append(pydict)?;
} }
} },
TypeEnum::TList { ty: elem_ty } => { TypeEnum::TList { ty: elem_ty } => {
if gen_rpc_tag(ctx, *elem_ty, &mut scratch_buffer).is_ok() { if gen_rpc_tag(ctx, *elem_ty, &mut scratch_buffer).is_ok() {
let pydict = PyDict::new(py); let pydict = PyDict::new(py);
pydict.set_item("obj", val)?; pydict.set_item("obj", val)?;
host_attributes.append(pydict)?; host_attributes.append(pydict)?;
values.push(( values.push((ty, inner_resolver.get_obj_value(py, val, ctx, generator, ty)?.unwrap()));
ty,
inner_resolver.get_obj_value(py, val, ctx, generator, ty)?.unwrap(),
));
} }
} },
_ => {} _ => {}
} }
} }
let fun = FunSignature { let fun = FunSignature {
args: values args: values.iter().enumerate().map(|(i, (ty, _))| FuncArg {
.iter() name: i.to_string().into(),
.enumerate() ty: *ty,
.map(|(i, (ty, _))| FuncArg { default_value: None
name: i.to_string().into(), }).collect(),
ty: *ty,
default_value: None,
})
.collect(),
ret: ctx.primitives.none, ret: ctx.primitives.none,
vars: Default::default(), vars: Default::default()
}; };
let args: Vec<_> = let args: Vec<_> = values.into_iter().map(|(_, val)| (None, ValueEnum::Dynamic(val))).collect();
values.into_iter().map(|(_, val)| (None, ValueEnum::Dynamic(val))).collect(); if let Err(e) = rpc_codegen_callback_fn(ctx, None, (&fun, DefinitionId(0)), args, generator) {
if let Err(e) = rpc_codegen_callback_fn(ctx, None, (&fun, DefinitionId(0)), args, generator)
{
return Ok(Err(e)); return Ok(Err(e));
} }
Ok(Ok(())) Ok(Ok(()))
}) }).unwrap()?;
.unwrap()?;
Ok(()) Ok(())
} }

View File

@ -17,9 +17,9 @@ use nac3parser::{
ast::{self, ExprKind, Stmt, StmtKind, StrRef}, ast::{self, ExprKind, Stmt, StmtKind, StrRef},
parser::{self, parse_program}, parser::{self, parse_program},
}; };
use pyo3::create_exception;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::{exceptions, types::PyBytes, types::PyDict, types::PySet}; use pyo3::{exceptions, types::PyBytes, types::PyDict, types::PySet};
use pyo3::create_exception;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
@ -40,7 +40,7 @@ use tempfile::{self, TempDir};
use crate::codegen::attributes_writeback; use crate::codegen::attributes_writeback;
use crate::{ use crate::{
codegen::{rpc_codegen_callback, ArtiqCodeGenerator}, codegen::{rpc_codegen_callback, ArtiqCodeGenerator},
symbol_resolver::{DeferredEvaluationStore, InnerResolver, PythonHelper, Resolver}, symbol_resolver::{InnerResolver, PythonHelper, Resolver, DeferredEvaluationStore},
}; };
mod codegen; mod codegen;
@ -93,7 +93,7 @@ struct Nac3 {
top_levels: Vec<TopLevelComponent>, top_levels: Vec<TopLevelComponent>,
string_store: Arc<RwLock<HashMap<String, i32>>>, string_store: Arc<RwLock<HashMap<String, i32>>>,
exception_ids: Arc<RwLock<HashMap<usize, usize>>>, exception_ids: Arc<RwLock<HashMap<usize, usize>>>,
deferred_eval_store: DeferredEvaluationStore, deferred_eval_store: DeferredEvaluationStore
} }
create_exception!(nac3artiq, CompileError, exceptions::PyException); create_exception!(nac3artiq, CompileError, exceptions::PyException);
@ -268,7 +268,7 @@ fn add_exceptions(
composer: &mut TopLevelComposer, composer: &mut TopLevelComposer,
builtin_def: &mut HashMap<StrRef, DefinitionId>, builtin_def: &mut HashMap<StrRef, DefinitionId>,
builtin_ty: &mut HashMap<StrRef, Type>, builtin_ty: &mut HashMap<StrRef, Type>,
error_names: &[&str], error_names: &[&str]
) -> Vec<Type> { ) -> Vec<Type> {
let mut types = Vec::new(); let mut types = Vec::new();
// note: this is only for builtin exceptions, i.e. the exception name is "0:{exn}" // note: this is only for builtin exceptions, i.e. the exception name is "0:{exn}"
@ -281,7 +281,7 @@ fn add_exceptions(
// constructor id // constructor id
def_id + 1, def_id + 1,
&mut composer.unifier, &mut composer.unifier,
&composer.primitives_ty, &composer.primitives_ty
); );
composer.definition_ast_list.push((Arc::new(RwLock::new(exception_class)), None)); composer.definition_ast_list.push((Arc::new(RwLock::new(exception_class)), None));
composer.definition_ast_list.push((Arc::new(RwLock::new(exception_fn)), None)); composer.definition_ast_list.push((Arc::new(RwLock::new(exception_fn)), None));
@ -331,8 +331,7 @@ impl Nac3 {
}, },
Arc::new(GenCall::new(Box::new(move |ctx, _, fun, args, generator| { Arc::new(GenCall::new(Box::new(move |ctx, _, fun, args, generator| {
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty).unwrap();
args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty).unwrap();
time_fns.emit_at_mu(ctx, arg); time_fns.emit_at_mu(ctx, arg);
Ok(None) Ok(None)
}))), }))),
@ -350,8 +349,7 @@ impl Nac3 {
}, },
Arc::new(GenCall::new(Box::new(move |ctx, _, fun, args, generator| { Arc::new(GenCall::new(Box::new(move |ctx, _, fun, args, generator| {
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty).unwrap();
args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty).unwrap();
time_fns.emit_delay_mu(ctx, arg); time_fns.emit_delay_mu(ctx, arg);
Ok(None) Ok(None)
}))), }))),
@ -365,19 +363,18 @@ impl Nac3 {
let types_mod = PyModule::import(py, "types").unwrap(); let types_mod = PyModule::import(py, "types").unwrap();
let get_id = |x| id_fn.call1((x,)).unwrap().extract().unwrap(); let get_id = |x| id_fn.call1((x,)).unwrap().extract().unwrap();
let get_attr_id = |obj: &PyModule, attr| { let get_attr_id = |obj: &PyModule, attr| id_fn.call1((obj.getattr(attr).unwrap(),))
id_fn.call1((obj.getattr(attr).unwrap(),)).unwrap().extract().unwrap() .unwrap().extract().unwrap();
};
let primitive_ids = PrimitivePythonId { let primitive_ids = PrimitivePythonId {
virtual_id: get_id( virtual_id: get_id(
builtins_mod builtins_mod
.getattr("globals") .getattr("globals")
.unwrap() .unwrap()
.call0() .call0()
.unwrap() .unwrap()
.get_item("virtual") .get_item("virtual")
.unwrap(), .unwrap(
), )),
generic_alias: ( generic_alias: (
get_attr_id(typing_mod, "_GenericAlias"), get_attr_id(typing_mod, "_GenericAlias"),
get_attr_id(types_mod, "GenericAlias"), get_attr_id(types_mod, "GenericAlias"),
@ -522,9 +519,8 @@ impl Nac3 {
let class_obj; let class_obj;
if let StmtKind::ClassDef { name, .. } = &stmt.node { if let StmtKind::ClassDef { name, .. } = &stmt.node {
let class = py_module.getattr(name.to_string()).unwrap(); let class = py_module.getattr(name.to_string()).unwrap();
if issubclass.call1((class, exn_class)).unwrap().extract().unwrap() if issubclass.call1((class, exn_class)).unwrap().extract().unwrap() &&
&& class.getattr("artiq_builtin").is_err() class.getattr("artiq_builtin").is_err() {
{
class_obj = Some(class); class_obj = Some(class);
} else { } else {
class_obj = None; class_obj = None;
@ -570,12 +566,13 @@ impl Nac3 {
let (name, def_id, ty) = composer let (name, def_id, ty) = composer
.register_top_level(stmt.clone(), Some(resolver.clone()), path.clone()) .register_top_level(stmt.clone(), Some(resolver.clone()), path.clone())
.map_err(|e| { .map_err(|e| {
CompileError::new_err(format!("compilation failed\n----------\n{}", e)) CompileError::new_err(format!(
"compilation failed\n----------\n{}",
e
))
})?; })?;
if let Some(class_obj) = class_obj { if let Some(class_obj) = class_obj {
self.exception_ids self.exception_ids.write().insert(def_id.0, store_obj.call1(py, (class_obj, ))?.extract(py)?);
.write()
.insert(def_id.0, store_obj.call1(py, (class_obj,))?.extract(py)?);
} }
match &stmt.node { match &stmt.node {
@ -645,8 +642,7 @@ impl Nac3 {
exception_ids: self.exception_ids.clone(), exception_ids: self.exception_ids.clone(),
deferred_eval_store: self.deferred_eval_store.clone(), deferred_eval_store: self.deferred_eval_store.clone(),
}); });
let resolver = let resolver = Arc::new(Resolver(inner_resolver.clone())) as Arc<dyn SymbolResolver + Send + Sync>;
Arc::new(Resolver(inner_resolver.clone())) as Arc<dyn SymbolResolver + Send + Sync>;
let (_, def_id, _) = composer let (_, def_id, _) = composer
.register_top_level(synthesized.pop().unwrap(), Some(resolver.clone()), "".into()) .register_top_level(synthesized.pop().unwrap(), Some(resolver.clone()), "".into())
.unwrap(); .unwrap();
@ -655,12 +651,8 @@ impl Nac3 {
FunSignature { args: vec![], ret: self.primitive.none, vars: HashMap::new() }; FunSignature { args: vec![], ret: self.primitive.none, vars: HashMap::new() };
let mut store = ConcreteTypeStore::new(); let mut store = ConcreteTypeStore::new();
let mut cache = HashMap::new(); let mut cache = HashMap::new();
let signature = store.from_signature( let signature =
&mut composer.unifier, store.from_signature(&mut composer.unifier, &self.primitive, &fun_signature, &mut cache);
&self.primitive,
&fun_signature,
&mut cache,
);
let signature = store.add_cty(signature); let signature = store.add_cty(signature);
if let Err(e) = composer.start_analysis(true) { if let Err(e) = composer.start_analysis(true) {
@ -746,12 +738,8 @@ impl Nac3 {
let mut store = ConcreteTypeStore::new(); let mut store = ConcreteTypeStore::new();
let mut cache = HashMap::new(); let mut cache = HashMap::new();
let signature = store.from_signature( let signature =
&mut composer.unifier, store.from_signature(&mut composer.unifier, &self.primitive, &fun_signature, &mut cache);
&self.primitive,
&fun_signature,
&mut cache,
);
let signature = store.add_cty(signature); let signature = store.add_cty(signature);
let attributes_writeback_task = CodeGenTask { let attributes_writeback_task = CodeGenTask {
subst: Default::default(), subst: Default::default(),
@ -789,23 +777,14 @@ impl Nac3 {
registry.add_task(task); registry.add_task(task);
registry.wait_tasks_complete(handles); registry.wait_tasks_complete(handles);
let mut generator = let mut generator = ArtiqCodeGenerator::new("attributes_writeback".to_string(), size_t, self.time_fns);
ArtiqCodeGenerator::new("attributes_writeback".to_string(), size_t, self.time_fns);
let context = inkwell::context::Context::create(); let context = inkwell::context::Context::create();
let module = context.create_module("attributes_writeback"); let module = context.create_module("attributes_writeback");
let builder = context.create_builder(); let builder = context.create_builder();
let (_, module, _) = gen_func_impl( let (_, module, _) = gen_func_impl(&context, &mut generator, &registry, builder, module,
&context, attributes_writeback_task, |generator, ctx| {
&mut generator,
&registry,
builder,
module,
attributes_writeback_task,
|generator, ctx| {
attributes_writeback(ctx, generator, inner_resolver.as_ref(), host_attributes) attributes_writeback(ctx, generator, inner_resolver.as_ref(), host_attributes)
}, }).unwrap();
)
.unwrap();
let buffer = module.write_bitcode_to_memory(); let buffer = module.write_bitcode_to_memory();
let buffer = buffer.as_slice().into(); let buffer = buffer.as_slice().into();
membuffer.lock().push(buffer); membuffer.lock().push(buffer);
@ -821,22 +800,13 @@ impl Nac3 {
.create_module_from_ir(MemoryBuffer::create_from_memory_range(buffer, "main")) .create_module_from_ir(MemoryBuffer::create_from_memory_range(buffer, "main"))
.unwrap(); .unwrap();
main.link_in_module(other).map_err(|err| CompileError::new_err(err.to_string()))?; main.link_in_module(other)
.map_err(|err| CompileError::new_err(err.to_string()))?;
} }
let builder = context.create_builder(); let builder = context.create_builder();
let modinit_return = main let modinit_return = main.get_function("__modinit__").unwrap().get_last_basic_block().unwrap().get_terminator().unwrap();
.get_function("__modinit__")
.unwrap()
.get_last_basic_block()
.unwrap()
.get_terminator()
.unwrap();
builder.position_before(&modinit_return); builder.position_before(&modinit_return);
builder.build_call( builder.build_call(main.get_function("attributes_writeback").unwrap(), &[], "attributes_writeback");
main.get_function("attributes_writeback").unwrap(),
&[],
"attributes_writeback",
);
main.link_in_module(load_irrt(&context)) main.link_in_module(load_irrt(&context))
.map_err(|err| CompileError::new_err(err.to_string()))?; .map_err(|err| CompileError::new_err(err.to_string()))?;
@ -910,7 +880,9 @@ impl Nac3 {
return Err(CompileError::new_err("failed to start linker")); return Err(CompileError::new_err("failed to start linker"));
} }
} else { } else {
return Err(CompileError::new_err("linker returned non-zero status code")); return Err(CompileError::new_err(
"linker returned non-zero status code",
));
} }
Ok(()) Ok(())

View File

@ -17,9 +17,9 @@ use pyo3::{
use std::{ use std::{
collections::HashMap, collections::HashMap,
sync::{ sync::{
atomic::{AtomicBool, Ordering::Relaxed},
Arc, Arc,
}, atomic::{AtomicBool, Ordering::Relaxed}
}
}; };
use crate::PrimitivePythonId; use crate::PrimitivePythonId;
@ -153,8 +153,7 @@ impl StaticValue for PythonValue {
self.resolver self.resolver
.get_obj_value(py, self.value.as_ref(py), ctx, generator, expected_ty) .get_obj_value(py, self.value.as_ref(py), ctx, generator, expected_ty)
.map(Option::unwrap) .map(Option::unwrap)
}) }).map_err(|e| e.to_string())
.map_err(|e| e.to_string())
} }
fn get_field<'ctx, 'a>( fn get_field<'ctx, 'a>(
@ -176,9 +175,9 @@ impl StaticValue for PythonValue {
let obj = self.value.getattr(py, &name.to_string())?; let obj = self.value.getattr(py, &name.to_string())?;
let id = self.resolver.helper.id_fn.call1(py, (&obj,))?.extract(py)?; let id = self.resolver.helper.id_fn.call1(py, (&obj,))?.extract(py)?;
if self.id == self.resolver.primitive_ids.none { if self.id == self.resolver.primitive_ids.none {
return Ok(None); return Ok(None)
} else { } else {
return Ok(Some((id, obj))); return Ok(Some((id, obj)))
} }
} }
let def_id = { *self.resolver.pyid_to_def.read().get(&ty_id).unwrap() }; let def_id = { *self.resolver.pyid_to_def.read().get(&ty_id).unwrap() };
@ -385,11 +384,11 @@ impl InnerResolver {
} }
} }
if needs_defer { if needs_defer {
self.deferred_eval_store.store.write().push(( self.deferred_eval_store.store.write()
result.clone(), .push((result.clone(),
constraints.extract()?, constraints.extract()?,
pyty.getattr("__name__")?.extract::<String>()?, pyty.getattr("__name__")?.extract::<String>()?
)) ))
} }
result result
}; };
@ -532,7 +531,10 @@ impl InnerResolver {
let str_fn = let str_fn =
pyo3::types::PyModule::import(py, "builtins").unwrap().getattr("repr").unwrap(); pyo3::types::PyModule::import(py, "builtins").unwrap().getattr("repr").unwrap();
let str_repr: String = str_fn.call1((pyty,)).unwrap().extract().unwrap(); let str_repr: String = str_fn.call1((pyty,)).unwrap().extract().unwrap();
Ok(Err(format!("{} is not registered with NAC3 (@nac3 decorator missing?)", str_repr))) Ok(Err(format!(
"{} is not registered with NAC3 (@nac3 decorator missing?)",
str_repr
)))
} }
} }
@ -547,7 +549,7 @@ impl InnerResolver {
let ty = self.helper.type_fn.call1(py, (obj,)).unwrap(); let ty = self.helper.type_fn.call1(py, (obj,)).unwrap();
let py_obj_id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?; let py_obj_id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
if let Some(ty) = self.pyid_to_type.read().get(&py_obj_id) { if let Some(ty) = self.pyid_to_type.read().get(&py_obj_id) {
return Ok(Ok(*ty)); return Ok(Ok(*ty))
} }
let (extracted_ty, inst_check) = match self.get_pyty_obj_type( let (extracted_ty, inst_check) = match self.get_pyty_obj_type(
py, py,
@ -614,7 +616,7 @@ impl InnerResolver {
let field_data = match obj.getattr("_nac3_option") { let field_data = match obj.getattr("_nac3_option") {
Ok(d) => d, Ok(d) => d,
// we use `none = Option(None)`, so the obj always have attr `_nac3_option` // we use `none = Option(None)`, so the obj always have attr `_nac3_option`
Err(_) => unreachable!("cannot be None"), Err(_) => unreachable!("cannot be None")
}; };
// if is `none` // if is `none`
let zelf_id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?; let zelf_id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
@ -625,9 +627,7 @@ impl InnerResolver {
let var_map = params let var_map = params
.iter() .iter()
.map(|(id_var, ty)| { .map(|(id_var, ty)| {
if let TypeEnum::TVar { id, range, name, loc, .. } = if let TypeEnum::TVar { id, range, name, loc, .. } = &*unifier.get_ty(*ty) {
&*unifier.get_ty(*ty)
{
assert_eq!(*id, *id_var); assert_eq!(*id, *id_var);
(*id, unifier.get_fresh_var_with_range(range, *name, *loc).0) (*id, unifier.get_fresh_var_with_range(range, *name, *loc).0)
} else { } else {
@ -635,7 +635,7 @@ impl InnerResolver {
} }
}) })
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();
return Ok(Ok(unifier.subst(primitives.option, &var_map).unwrap())); return Ok(Ok(unifier.subst(primitives.option, &var_map).unwrap()))
} else { } else {
unreachable!("must be tobj") unreachable!("must be tobj")
} }
@ -659,7 +659,9 @@ impl InnerResolver {
let var_map = params let var_map = params
.iter() .iter()
.map(|(id_var, ty)| { .map(|(id_var, ty)| {
if let TypeEnum::TVar { id, range, name, loc, .. } = &*unifier.get_ty(*ty) { if let TypeEnum::TVar { id, range, name, loc, .. } =
&*unifier.get_ty(*ty)
{
assert_eq!(*id, *id_var); assert_eq!(*id, *id_var);
(*id, unifier.get_fresh_var_with_range(range, *name, *loc).0) (*id, unifier.get_fresh_var_with_range(range, *name, *loc).0)
} else { } else {
@ -671,7 +673,7 @@ impl InnerResolver {
// loop through non-function fields of the class to get the instantiated value // loop through non-function fields of the class to get the instantiated value
for field in fields.iter() { for field in fields.iter() {
let name: String = (*field.0).into(); let name: String = (*field.0).into();
if let TypeEnum::TFunc(..) = &*unifier.get_ty(field.1 .0) { if let TypeEnum::TFunc(..) = &*unifier.get_ty(field.1.0) {
continue; continue;
} else { } else {
let field_data = obj.getattr(&name)?; let field_data = obj.getattr(&name)?;
@ -687,7 +689,7 @@ impl InnerResolver {
} }
}; };
let field_ty = let field_ty =
unifier.subst(field.1 .0, &var_map).unwrap_or(field.1 .0); unifier.subst(field.1.0, &var_map).unwrap_or(field.1.0);
if let Err(e) = unifier.unify(ty, field_ty) { if let Err(e) = unifier.unify(ty, field_ty) {
// field type mismatch // field type mismatch
return Ok(Err(format!( return Ok(Err(format!(
@ -704,54 +706,18 @@ impl InnerResolver {
return Ok(Err("object is not of concrete type".into())); return Ok(Err("object is not of concrete type".into()));
} }
} }
let extracted_ty = let extracted_ty = unifier.subst(extracted_ty, &var_map).unwrap_or(extracted_ty);
unifier.subst(extracted_ty, &var_map).unwrap_or(extracted_ty);
Ok(Ok(extracted_ty)) Ok(Ok(extracted_ty))
}; };
let result = instantiate_obj(); let result = instantiate_obj();
// update/remove the cache according to the result // update/remove the cache according to the result
match result { match result {
Ok(Ok(ty)) => self.pyid_to_type.write().insert(py_obj_id, ty), Ok(Ok(ty)) => self.pyid_to_type.write().insert(py_obj_id, ty),
_ => self.pyid_to_type.write().remove(&py_obj_id), _ => self.pyid_to_type.write().remove(&py_obj_id)
}; };
result result
} }
_ => { _ => Ok(Ok(extracted_ty)),
// check integer bounds
if unifier.unioned(extracted_ty, primitives.int32) {
obj.extract::<i32>().map_or_else(
|_| Ok(Err(format!("{} is not in the range of int32", obj))),
|_| Ok(Ok(extracted_ty)),
)
} else if unifier.unioned(extracted_ty, primitives.int64) {
obj.extract::<i64>().map_or_else(
|_| Ok(Err(format!("{} is not in the range of int64", obj))),
|_| Ok(Ok(extracted_ty)),
)
} else if unifier.unioned(extracted_ty, primitives.uint32) {
obj.extract::<u32>().map_or_else(
|_| Ok(Err(format!("{} is not in the range of uint32", obj))),
|_| Ok(Ok(extracted_ty)),
)
} else if unifier.unioned(extracted_ty, primitives.uint64) {
obj.extract::<u64>().map_or_else(
|_| Ok(Err(format!("{} is not in the range of uint64", obj))),
|_| Ok(Ok(extracted_ty)),
)
} else if unifier.unioned(extracted_ty, primitives.bool) {
obj.extract::<bool>().map_or_else(
|_| Ok(Err(format!("{} is not in the range of bool", obj))),
|_| Ok(Ok(extracted_ty)),
)
} else if unifier.unioned(extracted_ty, primitives.float) {
obj.extract::<f64>().map_or_else(
|_| Ok(Err(format!("{} is not in the range of float64", obj))),
|_| Ok(Ok(extracted_ty)),
)
} else {
Ok(Ok(extracted_ty))
}
}
} }
} }
@ -767,27 +733,33 @@ impl InnerResolver {
self.helper.id_fn.call1(py, (self.helper.type_fn.call1(py, (obj,))?,))?.extract(py)?; self.helper.id_fn.call1(py, (self.helper.type_fn.call1(py, (obj,))?,))?.extract(py)?;
let id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?; let id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 { if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 {
let val: i32 = obj.extract().unwrap(); let val: i32 = obj.extract().map_err(|_| super::CompileError::new_err(
format!("{} is not in the range of int32", obj)))?;
self.id_to_primitive.write().insert(id, PrimitiveValue::I32(val)); self.id_to_primitive.write().insert(id, PrimitiveValue::I32(val));
Ok(Some(ctx.ctx.i32_type().const_int(val as u64, false).into())) Ok(Some(ctx.ctx.i32_type().const_int(val as u64, false).into()))
} else if ty_id == self.primitive_ids.int64 { } else if ty_id == self.primitive_ids.int64 {
let val: i64 = obj.extract().unwrap(); let val: i64 = obj.extract().map_err(|_| super::CompileError::new_err(
format!("{} is not in the range of int64", obj)))?;
self.id_to_primitive.write().insert(id, PrimitiveValue::I64(val)); self.id_to_primitive.write().insert(id, PrimitiveValue::I64(val));
Ok(Some(ctx.ctx.i64_type().const_int(val as u64, false).into())) Ok(Some(ctx.ctx.i64_type().const_int(val as u64, false).into()))
} else if ty_id == self.primitive_ids.uint32 { } else if ty_id == self.primitive_ids.uint32 {
let val: u32 = obj.extract().unwrap(); let val: u32 = obj.extract().map_err(|_| super::CompileError::new_err(
format!("{} is not in the range of uint32", obj)))?;
self.id_to_primitive.write().insert(id, PrimitiveValue::U32(val)); self.id_to_primitive.write().insert(id, PrimitiveValue::U32(val));
Ok(Some(ctx.ctx.i32_type().const_int(val as u64, false).into())) Ok(Some(ctx.ctx.i32_type().const_int(val as u64, false).into()))
} else if ty_id == self.primitive_ids.uint64 { } else if ty_id == self.primitive_ids.uint64 {
let val: u64 = obj.extract().unwrap(); let val: u64 = obj.extract().map_err(|_| super::CompileError::new_err(
format!("{} is not in the range of uint64", obj)))?;
self.id_to_primitive.write().insert(id, PrimitiveValue::U64(val)); self.id_to_primitive.write().insert(id, PrimitiveValue::U64(val));
Ok(Some(ctx.ctx.i64_type().const_int(val, false).into())) Ok(Some(ctx.ctx.i64_type().const_int(val, false).into()))
} else if ty_id == self.primitive_ids.bool { } else if ty_id == self.primitive_ids.bool {
let val: bool = obj.extract().unwrap(); let val: bool = obj.extract().map_err(|_| super::CompileError::new_err(
format!("{} is not in the range of bool", obj)))?;
self.id_to_primitive.write().insert(id, PrimitiveValue::Bool(val)); self.id_to_primitive.write().insert(id, PrimitiveValue::Bool(val));
Ok(Some(ctx.ctx.bool_type().const_int(val as u64, false).into())) Ok(Some(ctx.ctx.bool_type().const_int(val as u64, false).into()))
} else if ty_id == self.primitive_ids.float || ty_id == self.primitive_ids.float64 { } else if ty_id == self.primitive_ids.float || ty_id == self.primitive_ids.float64 {
let val: f64 = obj.extract().unwrap(); let val: f64 = obj.extract().map_err(|_| super::CompileError::new_err(
format!("{} is not in the range of float64", obj)))?;
self.id_to_primitive.write().insert(id, PrimitiveValue::F64(val)); self.id_to_primitive.write().insert(id, PrimitiveValue::F64(val));
Ok(Some(ctx.ctx.f64_type().const_float(val).into())) Ok(Some(ctx.ctx.f64_type().const_float(val).into()))
} else if ty_id == self.primitive_ids.list { } else if ty_id == self.primitive_ids.list {
@ -798,8 +770,8 @@ impl InnerResolver {
} }
let len: usize = self.helper.len_fn.call1(py, (obj,))?.extract(py)?; let len: usize = self.helper.len_fn.call1(py, (obj,))?.extract(py)?;
let elem_ty = if let TypeEnum::TList { ty } = let elem_ty =
ctx.unifier.get_ty_immutable(expected_ty).as_ref() if let TypeEnum::TList { ty } = ctx.unifier.get_ty_immutable(expected_ty).as_ref()
{ {
*ty *ty
} else { } else {
@ -824,14 +796,13 @@ impl InnerResolver {
let arr: Result<Option<Vec<_>>, _> = (0..len) let arr: Result<Option<Vec<_>>, _> = (0..len)
.map(|i| { .map(|i| {
obj.get_item(i).and_then(|elem| { obj
self.get_obj_value(py, elem, ctx, generator, elem_ty).map_err(|e| { .get_item(i)
super::CompileError::new_err(format!( .and_then(|elem| self.get_obj_value(py, elem, ctx, generator, elem_ty)
"Error getting element {}: {}", .map_err(
i, e |e| super::CompileError::new_err(
)) format!("Error getting element {}: {}", i, e))
}) ))
})
}) })
.collect(); .collect();
let arr = arr?.unwrap(); let arr = arr?.unwrap();
@ -876,19 +847,18 @@ impl InnerResolver {
let tup_tys = ty.iter(); let tup_tys = ty.iter();
let elements: &PyTuple = obj.cast_as()?; let elements: &PyTuple = obj.cast_as()?;
assert_eq!(elements.len(), tup_tys.len()); assert_eq!(elements.len(), tup_tys.len());
let val: Result<Option<Vec<_>>, _> = elements let val: Result<Option<Vec<_>>, _> =
.iter() elements
.enumerate() .iter()
.zip(tup_tys) .enumerate()
.map(|((i, elem), ty)| { .zip(tup_tys)
self.get_obj_value(py, elem, ctx, generator, *ty).map_err(|e| { .map(|((i, elem), ty)| self
super::CompileError::new_err(format!( .get_obj_value(py, elem, ctx, generator, *ty).map_err(|e|
"Error getting element {}: {}", super::CompileError::new_err(
i, e format!("Error getting element {}: {}", i, e)
)) )
}) )
}) ).collect();
.collect();
let val = val?.unwrap(); let val = val?.unwrap();
let val = ctx.ctx.const_struct(&val, false); let val = ctx.ctx.const_struct(&val, false);
Ok(Some(val.into())) Ok(Some(val.into()))
@ -902,7 +872,7 @@ impl InnerResolver {
{ {
*params.iter().next().unwrap().1 *params.iter().next().unwrap().1
} }
_ => unreachable!("must be option type"), _ => unreachable!("must be option type")
}; };
if id == self.primitive_ids.none { if id == self.primitive_ids.none {
// for option type, just a null ptr // for option type, just a null ptr
@ -914,13 +884,7 @@ impl InnerResolver {
)) ))
} else { } else {
match self match self
.get_obj_value( .get_obj_value(py, obj.getattr("_nac3_option").unwrap(), ctx, generator, option_val_ty)
py,
obj.getattr("_nac3_option").unwrap(),
ctx,
generator,
option_val_ty,
)
.map_err(|e| { .map_err(|e| {
super::CompileError::new_err(format!( super::CompileError::new_err(format!(
"Error getting value of Option object: {}", "Error getting value of Option object: {}",
@ -931,27 +895,18 @@ impl InnerResolver {
let global_str = format!("{}_option", id); let global_str = format!("{}_option", id);
{ {
if self.global_value_ids.read().contains_key(&id) { if self.global_value_ids.read().contains_key(&id) {
let global = let global = ctx.module.get_global(&global_str).unwrap_or_else(|| {
ctx.module.get_global(&global_str).unwrap_or_else(|| { ctx.module.add_global(v.get_type(), Some(AddressSpace::Generic), &global_str)
ctx.module.add_global( });
v.get_type(),
Some(AddressSpace::Generic),
&global_str,
)
});
return Ok(Some(global.as_pointer_value().into())); return Ok(Some(global.as_pointer_value().into()));
} else { } else {
self.global_value_ids.write().insert(id, obj.into()); self.global_value_ids.write().insert(id, obj.into());
} }
} }
let global = ctx.module.add_global( let global = ctx.module.add_global(v.get_type(), Some(AddressSpace::Generic), &global_str);
v.get_type(),
Some(AddressSpace::Generic),
&global_str,
);
global.set_initializer(&v); global.set_initializer(&v);
Ok(Some(global.as_pointer_value().into())) Ok(Some(global.as_pointer_value().into()))
} },
None => Ok(None), None => Ok(None),
} }
} }
@ -989,12 +944,7 @@ impl InnerResolver {
.iter() .iter()
.map(|(name, ty, _)| { .map(|(name, ty, _)| {
self.get_obj_value(py, obj.getattr(&name.to_string())?, ctx, generator, *ty) self.get_obj_value(py, obj.getattr(&name.to_string())?, ctx, generator, *ty)
.map_err(|e| { .map_err(|e| super::CompileError::new_err(format!("Error getting field {}: {}", name, e)))
super::CompileError::new_err(format!(
"Error getting field {}: {}",
name, e
))
})
}) })
.collect(); .collect();
let values = values?; let values = values?;
@ -1049,7 +999,8 @@ impl InnerResolver {
if id == self.primitive_ids.none { if id == self.primitive_ids.none {
Ok(SymbolValue::OptionNone) Ok(SymbolValue::OptionNone)
} else { } else {
self.get_default_param_obj_value(py, obj.getattr("_nac3_option").unwrap())? self
.get_default_param_obj_value(py, obj.getattr("_nac3_option").unwrap())?
.map(|v| SymbolValue::OptionSome(Box::new(v))) .map(|v| SymbolValue::OptionSome(Box::new(v)))
} }
} else { } else {
@ -1204,7 +1155,7 @@ impl SymbolResolver for Resolver {
&self, &self,
unifier: &mut Unifier, unifier: &mut Unifier,
defs: &[Arc<RwLock<TopLevelDef>>], defs: &[Arc<RwLock<TopLevelDef>>],
primitives: &PrimitiveStore, primitives: &PrimitiveStore
) -> Result<(), String> { ) -> Result<(), String> {
// we don't need a lock because this will only be run in a single thread // we don't need a lock because this will only be run in a single thread
if self.0.deferred_eval_store.needs_defer.load(Relaxed) { if self.0.deferred_eval_store.needs_defer.load(Relaxed) {
@ -1234,8 +1185,7 @@ impl SymbolResolver for Resolver {
} }
} }
Ok(Ok(())) Ok(Ok(()))
}) }).unwrap()?
.unwrap()?
} }
Ok(()) Ok(())
} }

File diff suppressed because it is too large Load Diff

View File

@ -85,22 +85,33 @@ impl<U> crate::fold::Fold<U> for ConstantOptimizer {
fn fold_expr(&mut self, node: crate::Expr<U>) -> Result<crate::Expr<U>, Self::Error> { fn fold_expr(&mut self, node: crate::Expr<U>) -> Result<crate::Expr<U>, Self::Error> {
match node.node { match node.node {
crate::ExprKind::Tuple { elts, ctx } => { crate::ExprKind::Tuple { elts, ctx } => {
let elts = let elts = elts
elts.into_iter().map(|x| self.fold_expr(x)).collect::<Result<Vec<_>, _>>()?; .into_iter()
let expr = .map(|x| self.fold_expr(x))
if elts.iter().all(|e| matches!(e.node, crate::ExprKind::Constant { .. })) { .collect::<Result<Vec<_>, _>>()?;
let tuple = elts let expr = if elts
.into_iter() .iter()
.map(|e| match e.node { .all(|e| matches!(e.node, crate::ExprKind::Constant { .. }))
crate::ExprKind::Constant { value, .. } => value, {
_ => unreachable!(), let tuple = elts
}) .into_iter()
.collect(); .map(|e| match e.node {
crate::ExprKind::Constant { value: Constant::Tuple(tuple), kind: None } crate::ExprKind::Constant { value, .. } => value,
} else { _ => unreachable!(),
crate::ExprKind::Tuple { elts, ctx } })
}; .collect();
Ok(crate::Expr { node: expr, custom: node.custom, location: node.location }) crate::ExprKind::Constant {
value: Constant::Tuple(tuple),
kind: None,
}
} else {
crate::ExprKind::Tuple { elts, ctx }
};
Ok(crate::Expr {
node: expr,
custom: node.custom,
location: node.location,
})
} }
_ => crate::fold::fold_expr(self, node), _ => crate::fold::fold_expr(self, node),
} }
@ -127,12 +138,18 @@ mod tests {
Located { Located {
location, location,
custom, custom,
node: ExprKind::Constant { value: 1.into(), kind: None }, node: ExprKind::Constant {
value: 1.into(),
kind: None,
},
}, },
Located { Located {
location, location,
custom, custom,
node: ExprKind::Constant { value: 2.into(), kind: None }, node: ExprKind::Constant {
value: 2.into(),
kind: None,
},
}, },
Located { Located {
location, location,
@ -143,17 +160,26 @@ mod tests {
Located { Located {
location, location,
custom, custom,
node: ExprKind::Constant { value: 3.into(), kind: None }, node: ExprKind::Constant {
value: 3.into(),
kind: None,
},
}, },
Located { Located {
location, location,
custom, custom,
node: ExprKind::Constant { value: 4.into(), kind: None }, node: ExprKind::Constant {
value: 4.into(),
kind: None,
},
}, },
Located { Located {
location, location,
custom, custom,
node: ExprKind::Constant { value: 5.into(), kind: None }, node: ExprKind::Constant {
value: 5.into(),
kind: None,
},
}, },
], ],
}, },
@ -161,7 +187,9 @@ mod tests {
], ],
}, },
}; };
let new_ast = ConstantOptimizer::new().fold_expr(ast).unwrap_or_else(|e| match e {}); let new_ast = ConstantOptimizer::new()
.fold_expr(ast)
.unwrap_or_else(|e| match e {});
assert_eq!( assert_eq!(
new_ast, new_ast,
Located { Located {
@ -171,7 +199,11 @@ mod tests {
value: Constant::Tuple(vec![ value: Constant::Tuple(vec![
1.into(), 1.into(),
2.into(), 2.into(),
Constant::Tuple(vec![3.into(), 4.into(), 5.into(),]) Constant::Tuple(vec![
3.into(),
4.into(),
5.into(),
])
]), ]),
kind: None kind: None
}, },

View File

@ -64,4 +64,11 @@ macro_rules! simple_fold {
}; };
} }
simple_fold!(usize, String, bool, StrRef, constant::Constant, constant::ConversionFlag); simple_fold!(
usize,
String,
bool,
StrRef,
constant::Constant,
constant::ConversionFlag
);

View File

@ -34,7 +34,10 @@ impl<U> ExprKind<U> {
ExprKind::Starred { .. } => "starred", ExprKind::Starred { .. } => "starred",
ExprKind::Slice { .. } => "slice", ExprKind::Slice { .. } => "slice",
ExprKind::JoinedStr { values } => { ExprKind::JoinedStr { values } => {
if values.iter().any(|e| matches!(e.node, ExprKind::JoinedStr { .. })) { if values
.iter()
.any(|e| matches!(e.node, ExprKind::JoinedStr { .. }))
{
"f-string expression" "f-string expression"
} else { } else {
"literal" "literal"

View File

@ -9,6 +9,6 @@ mod impls;
mod location; mod location;
pub use ast_gen::*; pub use ast_gen::*;
pub use location::{FileName, Location}; pub use location::{Location, FileName};
pub type Suite<U = ()> = Vec<Stmt<U>>; pub type Suite<U = ()> = Vec<Stmt<U>>;

View File

@ -21,7 +21,7 @@ impl From<String> for FileName {
pub struct Location { pub struct Location {
pub row: usize, pub row: usize,
pub column: usize, pub column: usize,
pub file: FileName, pub file: FileName
} }
impl fmt::Display for Location { impl fmt::Display for Location {
@ -53,7 +53,11 @@ impl Location {
) )
} }
} }
Visualize { loc: *self, line, desc } Visualize {
loc: *self,
line,
desc,
}
} }
} }

View File

@ -12,10 +12,9 @@ rayon = "1.5.1"
nac3parser = { path = "../nac3parser" } nac3parser = { path = "../nac3parser" }
[dependencies.inkwell] [dependencies.inkwell]
git = "https://github.com/nbaksalyar/inkwell.git" version = "0.1.0-beta.4"
branch = "llvm14"
default-features = false default-features = false
features = ["llvm14-0", "target-aarch64", "target-arm", "target-riscv", "no-libffi-linking"] features = ["llvm13-0", "target-x86", "target-arm", "target-riscv", "no-libffi-linking"]
[dev-dependencies] [dev-dependencies]
test-case = "1.2.0" test-case = "1.2.0"

View File

@ -18,8 +18,17 @@ fn main() {
* Compiling for WASM32 and filtering the output with regex is the closest we can get. * Compiling for WASM32 and filtering the output with regex is the closest we can get.
*/ */
const FLAG: &[&str] = const FLAG: &[&str] = &[
&["--target=wasm32", FILE, "-O3", "-emit-llvm", "-S", "-Wall", "-Wextra", "-o", "-"]; "--target=wasm32",
FILE,
"-O3",
"-emit-llvm",
"-S",
"-Wall",
"-Wextra",
"-o",
"-",
];
let output = Command::new("clang") let output = Command::new("clang")
.args(FLAG) .args(FLAG)
.output() .output()

View File

@ -10,23 +10,20 @@ use crate::{
}, },
symbol_resolver::{SymbolValue, ValueEnum}, symbol_resolver::{SymbolValue, ValueEnum},
toplevel::{DefinitionId, TopLevelDef}, toplevel::{DefinitionId, TopLevelDef},
typecheck::{ typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier},
magic_methods::{binop_assign_name, binop_name},
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier},
},
}; };
use inkwell::{ use inkwell::{
AddressSpace,
attributes::{Attribute, AttributeLoc}, attributes::{Attribute, AttributeLoc},
types::{AnyType, BasicType, BasicTypeEnum}, types::{AnyType, BasicType, BasicTypeEnum},
values::{BasicValueEnum, FunctionValue, IntValue, PointerValue}, values::{BasicValueEnum, FunctionValue, IntValue, PointerValue}
AddressSpace,
}; };
use itertools::{chain, izip, zip, Itertools}; use itertools::{chain, izip, zip, Itertools};
use nac3parser::ast::{ use nac3parser::ast::{
self, Boolop, Comprehension, Constant, Expr, ExprKind, Location, Operator, StrRef, self, Boolop, Comprehension, Constant, Expr, ExprKind, Location, Operator, StrRef,
}; };
use super::{need_sret, CodeGenerator}; use super::{CodeGenerator, need_sret};
pub fn get_subst_key( pub fn get_subst_key(
unifier: &mut Unifier, unifier: &mut Unifier,
@ -241,7 +238,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
op: &Operator, op: &Operator,
lhs: BasicValueEnum<'ctx>, lhs: BasicValueEnum<'ctx>,
rhs: BasicValueEnum<'ctx>, rhs: BasicValueEnum<'ctx>,
signed: bool, signed: bool
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
let (lhs, rhs) = let (lhs, rhs) =
if let (BasicValueEnum::IntValue(lhs), BasicValueEnum::IntValue(rhs)) = (lhs, rhs) { if let (BasicValueEnum::IntValue(lhs), BasicValueEnum::IntValue(rhs)) = (lhs, rhs) {
@ -270,15 +267,9 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
(Operator::BitXor, _) => self.builder.build_xor(lhs, rhs, "xor").into(), (Operator::BitXor, _) => self.builder.build_xor(lhs, rhs, "xor").into(),
(Operator::BitAnd, _) => self.builder.build_and(lhs, rhs, "and").into(), (Operator::BitAnd, _) => self.builder.build_and(lhs, rhs, "and").into(),
(Operator::LShift, _) => self.builder.build_left_shift(lhs, rhs, "lshift").into(), (Operator::LShift, _) => self.builder.build_left_shift(lhs, rhs, "lshift").into(),
(Operator::RShift, _) => { (Operator::RShift, _) => self.builder.build_right_shift(lhs, rhs, true, "rshift").into(),
self.builder.build_right_shift(lhs, rhs, true, "rshift").into() (Operator::FloorDiv, true) => self.builder.build_int_signed_div(lhs, rhs, "floordiv").into(),
} (Operator::FloorDiv, false) => self.builder.build_int_unsigned_div(lhs, rhs, "floordiv").into(),
(Operator::FloorDiv, true) => {
self.builder.build_int_signed_div(lhs, rhs, "floordiv").into()
}
(Operator::FloorDiv, false) => {
self.builder.build_int_unsigned_div(lhs, rhs, "floordiv").into()
}
(Operator::Pow, s) => integer_power(generator, self, lhs, rhs, s).into(), (Operator::Pow, s) => integer_power(generator, self, lhs, rhs, s).into(),
// special implementation? // special implementation?
(Operator::MatMult, _) => unreachable!(), (Operator::MatMult, _) => unreachable!(),
@ -346,28 +337,18 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
let byval_id = Attribute::get_named_enum_kind_id("byval"); let byval_id = Attribute::get_named_enum_kind_id("byval");
let offset = if fun.get_enum_attribute(AttributeLoc::Param(0), sret_id).is_some() { let offset = if fun.get_enum_attribute(AttributeLoc::Param(0), sret_id).is_some() {
return_slot = Some( return_slot = Some(self.builder.build_alloca(fun.get_type().get_param_types()[0]
self.builder.build_alloca( .into_pointer_type().get_element_type().into_struct_type(), call_name));
fun.get_type().get_param_types()[0]
.into_pointer_type()
.get_element_type()
.into_struct_type(),
call_name,
),
);
loc_params.push((*return_slot.as_ref().unwrap()).into()); loc_params.push((*return_slot.as_ref().unwrap()).into());
1 1
} else { } else {
0 0
}; };
for (i, param) in params.iter().enumerate() { for (i, param) in params.iter().enumerate() {
if fun if fun.get_enum_attribute(AttributeLoc::Param((i + offset) as u32), byval_id).is_some() {
.get_enum_attribute(AttributeLoc::Param((i + offset) as u32), byval_id)
.is_some()
{
// lazy update // lazy update
if loc_params.is_empty() { if loc_params.is_empty() {
loc_params.extend(params[0..i + offset].iter().copied()); loc_params.extend(params[0..i+offset].iter().copied());
} }
let slot = self.builder.build_alloca(param.get_type(), call_name); let slot = self.builder.build_alloca(param.get_type(), call_name);
loc_params.push(slot.into()); loc_params.push(slot.into());
@ -377,7 +358,11 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
} }
} }
} }
let params = if loc_params.is_empty() { params } else { &loc_params }; let params = if loc_params.is_empty() {
params
} else {
&loc_params
};
let result = if let Some(target) = self.unwind_target { let result = if let Some(target) = self.unwind_target {
let current = self.builder.get_insert_block().unwrap().get_parent().unwrap(); let current = self.builder.get_insert_block().unwrap().get_parent().unwrap();
let then_block = self.ctx.append_basic_block(current, &format!("after.{}", call_name)); let then_block = self.ctx.append_basic_block(current, &format!("after.{}", call_name));
@ -508,10 +493,12 @@ pub fn gen_constructor<'ctx, 'a, G: CodeGenerator>(
match def { match def {
TopLevelDef::Class { methods, .. } => { TopLevelDef::Class { methods, .. } => {
// TODO: what about other fields that require alloca? // TODO: what about other fields that require alloca?
let fun_id = methods let mut fun_id = None;
.iter() for (name, _, id) in methods.iter() {
.find(|method| method.0 == "__init__".into()) if name == &"__init__".into() {
.and_then(|method| Some(method.2)); fun_id = Some(*id);
}
}
let ty = ctx.get_llvm_type(generator, signature.ret).into_pointer_type(); let ty = ctx.get_llvm_type(generator, signature.ret).into_pointer_type();
let zelf_ty: BasicTypeEnum = ty.get_element_type().try_into().unwrap(); let zelf_ty: BasicTypeEnum = ty.get_element_type().try_into().unwrap();
let zelf: BasicValueEnum<'ctx> = ctx.builder.build_alloca(zelf_ty, "alloca").into(); let zelf: BasicValueEnum<'ctx> = ctx.builder.build_alloca(zelf_ty, "alloca").into();
@ -651,12 +638,8 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
); );
} }
// reorder the parameters // reorder the parameters
let mut real_params = fun let mut real_params =
.0 fun.0.args.iter().map(|arg| (mapping.remove(&arg.name).unwrap(), arg.ty)).collect_vec();
.args
.iter()
.map(|arg| (mapping.remove(&arg.name).unwrap(), arg.ty))
.collect_vec();
if let Some(obj) = &obj { if let Some(obj) = &obj {
real_params.insert(0, (obj.1.clone(), obj.0)); real_params.insert(0, (obj.1.clone(), obj.0));
} }
@ -719,48 +702,32 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
}; };
let has_sret = ret_type.map_or(false, |ret_type| need_sret(ctx.ctx, ret_type)); let has_sret = ret_type.map_or(false, |ret_type| need_sret(ctx.ctx, ret_type));
let mut byvals = Vec::new(); let mut byvals = Vec::new();
let mut params = args let mut params =
.iter() args.iter().enumerate().map(|(i, arg)| match ctx.get_llvm_type(generator, arg.ty) {
.enumerate() BasicTypeEnum::StructType(ty) if is_extern => {
.map(|(i, arg)| { byvals.push((i, ty));
match ctx.get_llvm_type(generator, arg.ty) { ty.ptr_type(AddressSpace::Generic).into()
BasicTypeEnum::StructType(ty) if is_extern => { },
byvals.push((i, ty)); x => x
ty.ptr_type(AddressSpace::Generic).into() }.into()).collect_vec();
}
x => x,
}
.into()
})
.collect_vec();
if has_sret { if has_sret {
params.insert(0, ret_type.unwrap().ptr_type(AddressSpace::Generic).into()); params.insert(0, ret_type.unwrap().ptr_type(AddressSpace::Generic).into());
} }
let fun_ty = match ret_type { let fun_ty = match ret_type {
Some(ret_type) if !has_sret => ret_type.fn_type(&params, false), Some(ret_type) if !has_sret => ret_type.fn_type(&params, false),
_ => ctx.ctx.void_type().fn_type(&params, false), _ => ctx.ctx.void_type().fn_type(&params, false)
}; };
let fun_val = ctx.module.add_function(&symbol, fun_ty, None); let fun_val = ctx.module.add_function(&symbol, fun_ty, None);
let offset = if has_sret { let offset = if has_sret {
fun_val.add_attribute( fun_val.add_attribute(AttributeLoc::Param(0),
AttributeLoc::Param(0), ctx.ctx.create_type_attribute(Attribute::get_named_enum_kind_id("sret"), ret_type.unwrap().as_any_type_enum()));
ctx.ctx.create_type_attribute(
Attribute::get_named_enum_kind_id("sret"),
ret_type.unwrap().as_any_type_enum(),
),
);
1 1
} else { } else {
0 0
}; };
for (i, ty) in byvals { for (i, ty) in byvals {
fun_val.add_attribute( fun_val.add_attribute(AttributeLoc::Param((i as u32) + offset),
AttributeLoc::Param((i as u32) + offset), ctx.ctx.create_type_attribute(Attribute::get_named_enum_kind_id("byval"), ty.as_any_type_enum()));
ctx.ctx.create_type_attribute(
Attribute::get_named_enum_kind_id("byval"),
ty.as_any_type_enum(),
),
);
} }
fun_val fun_val
}); });
@ -824,11 +791,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
let cont_bb = ctx.ctx.append_basic_block(current, "cont"); let cont_bb = ctx.ctx.append_basic_block(current, "cont");
let Comprehension { target, iter, ifs, .. } = &generators[0]; let Comprehension { target, iter, ifs, .. } = &generators[0];
let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum( let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(ctx, generator, iter.custom.unwrap())?;
ctx,
generator,
iter.custom.unwrap(),
)?;
let int32 = ctx.ctx.i32_type(); let int32 = ctx.ctx.i32_type();
let size_t = generator.get_size_type(ctx.ctx); let size_t = generator.get_size_type(ctx.ctx);
let zero_size_t = size_t.const_zero(); let zero_size_t = size_t.const_zero();
@ -964,31 +927,21 @@ pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
left: &Expr<Option<Type>>, left: &Expr<Option<Type>>,
op: &Operator, op: &Operator,
right: &Expr<Option<Type>>, right: &Expr<Option<Type>>,
loc: Location, ) -> Result<ValueEnum<'ctx>, String> {
is_aug_assign: bool,
) -> Result<Option<ValueEnum<'ctx>>, String> {
let ty1 = ctx.unifier.get_representative(left.custom.unwrap()); let ty1 = ctx.unifier.get_representative(left.custom.unwrap());
let ty2 = ctx.unifier.get_representative(right.custom.unwrap()); let ty2 = ctx.unifier.get_representative(right.custom.unwrap());
let left_val = generator.gen_expr(ctx, left)?.unwrap().to_basic_value_enum( let left = generator.gen_expr(ctx, left)?.unwrap().to_basic_value_enum(ctx, generator, left.custom.unwrap())?;
ctx, let right = generator.gen_expr(ctx, right)?.unwrap().to_basic_value_enum(ctx, generator, right.custom.unwrap())?;
generator,
left.custom.unwrap(),
)?;
let right_val = generator.gen_expr(ctx, right)?.unwrap().to_basic_value_enum(
ctx,
generator,
right.custom.unwrap(),
)?;
// we can directly compare the types, because we've got their representatives // we can directly compare the types, because we've got their representatives
// which would be unchanged until further unification, which we would never do // which would be unchanged until further unification, which we would never do
// when doing code generation for function instances // when doing code generation for function instances
if ty1 == ty2 && [ctx.primitives.int32, ctx.primitives.int64].contains(&ty1) { Ok(if ty1 == ty2 && [ctx.primitives.int32, ctx.primitives.int64].contains(&ty1) {
Ok(Some(ctx.gen_int_ops(generator, op, left_val, right_val, true).into())) ctx.gen_int_ops(generator, op, left, right, true)
} else if ty1 == ty2 && [ctx.primitives.uint32, ctx.primitives.uint64].contains(&ty1) { } else if ty1 == ty2 && [ctx.primitives.uint32, ctx.primitives.uint64].contains(&ty1) {
Ok(Some(ctx.gen_int_ops(generator, op, left_val, right_val, false).into())) ctx.gen_int_ops(generator, op, left, right, false)
} else if ty1 == ty2 && ctx.primitives.float == ty1 { } else if ty1 == ty2 && ctx.primitives.float == ty1 {
Ok(Some(ctx.gen_float_ops(op, left_val, right_val).into())) ctx.gen_float_ops(op, left, right)
} else if ty1 == ctx.primitives.float && ty2 == ctx.primitives.int32 { } else if ty1 == ctx.primitives.float && ty2 == ctx.primitives.int32 {
// Pow is the only operator that would pass typecheck between float and int // Pow is the only operator that would pass typecheck between float and int
assert!(*op == Operator::Pow); assert!(*op == Operator::Pow);
@ -998,62 +951,14 @@ pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
let ty = f64_t.fn_type(&[f64_t.into(), i32_t.into()], false); let ty = f64_t.fn_type(&[f64_t.into(), i32_t.into()], false);
ctx.module.add_function("llvm.powi.f64.i32", ty, None) ctx.module.add_function("llvm.powi.f64.i32", ty, None)
}); });
let res = ctx ctx.builder
.builder .build_call(pow_intr, &[left.into(), right.into()], "f_pow_i")
.build_call(pow_intr, &[left_val.into(), right_val.into()], "f_pow_i")
.try_as_basic_value() .try_as_basic_value()
.unwrap_left(); .unwrap_left()
Ok(Some(res.into()))
} else { } else {
let (op_name, id) = if let TypeEnum::TObj { fields, obj_id, .. } = unimplemented!()
ctx.unifier.get_ty_immutable(left.custom.unwrap()).as_ref()
{
let (binop_name, binop_assign_name) =
(binop_name(op).into(), binop_assign_name(op).into());
// if is aug_assign, try aug_assign operator first
if is_aug_assign && fields.contains_key(&binop_assign_name) {
(binop_assign_name, *obj_id)
} else {
(binop_name, *obj_id)
}
} else {
unreachable!("must be tobj")
};
let signature = match ctx.calls.get(&loc.into()) {
Some(call) => ctx.unifier.get_call_signature(*call).unwrap(),
None => {
if let TypeEnum::TObj { fields, .. } =
ctx.unifier.get_ty_immutable(left.custom.unwrap()).as_ref()
{
let fn_ty = fields.get(&op_name).unwrap().0;
if let TypeEnum::TFunc(sig) = ctx.unifier.get_ty_immutable(fn_ty).as_ref() {
sig.clone()
} else {
unreachable!("must be func sig")
}
} else {
unreachable!("must be tobj")
}
}
};
let fun_id = {
let defs = ctx.top_level.definitions.read();
let obj_def = defs.get(id.0).unwrap().read();
if let TopLevelDef::Class { methods, .. } = &*obj_def {
methods.iter().find(|method| method.0 == op_name).unwrap().2
} else {
unreachable!()
}
};
generator
.gen_call(
ctx,
Some((left.custom.unwrap(), left_val.into())),
(&signature, fun_id),
vec![(None, right_val.into())],
)
.map(|f| f.map(|f| f.into()))
} }
.into())
} }
pub fn gen_expr<'ctx, 'a, G: CodeGenerator>( pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
@ -1074,14 +979,14 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
ctx.unifier.get_ty(expr.custom.unwrap()).as_ref(), ctx.unifier.get_ty(expr.custom.unwrap()).as_ref(),
ctx.unifier.get_ty(ctx.primitives.option).as_ref(), ctx.unifier.get_ty(ctx.primitives.option).as_ref(),
) { ) {
(TypeEnum::TObj { obj_id, params, .. }, TypeEnum::TObj { obj_id: opt_id, .. }) (
if *obj_id == *opt_id => TypeEnum::TObj { obj_id, params, .. },
{ TypeEnum::TObj { obj_id: opt_id, .. },
ctx.get_llvm_type(generator, *params.iter().next().unwrap().1) ) if *obj_id == *opt_id => ctx
.ptr_type(AddressSpace::Generic) .get_llvm_type(generator, *params.iter().next().unwrap().1)
.const_null() .ptr_type(AddressSpace::Generic)
.into() .const_null()
} .into(),
_ => unreachable!("must be option type"), _ => unreachable!("must be option type"),
} }
} }
@ -1099,9 +1004,12 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
let elements = elts let elements = elts
.iter() .iter()
.map(|x| { .map(|x| {
generator.gen_expr(ctx, x).map_or_else(Err, |v| { generator
v.unwrap().to_basic_value_enum(ctx, generator, x.custom.unwrap()) .gen_expr(ctx, x)
}) .map_or_else(
Err,
|v| v.unwrap().to_basic_value_enum(ctx, generator, x.custom.unwrap())
)
}) })
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let ty = if elements.is_empty() { let ty = if elements.is_empty() {
@ -1132,9 +1040,9 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
let element_val = elts let element_val = elts
.iter() .iter()
.map(|x| { .map(|x| {
generator.gen_expr(ctx, x).map_or_else(Err, |v| { generator
v.unwrap().to_basic_value_enum(ctx, generator, x.custom.unwrap()) .gen_expr(ctx, x)
}) .map_or_else(Err, |v| v.unwrap().to_basic_value_enum(ctx, generator, x.custom.unwrap()))
}) })
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let element_ty = element_val.iter().map(BasicValueEnum::get_type).collect_vec(); let element_ty = element_val.iter().map(BasicValueEnum::get_type).collect_vec();
@ -1155,17 +1063,14 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
ExprKind::Attribute { value, attr, .. } => { ExprKind::Attribute { value, attr, .. } => {
// note that we would handle class methods directly in calls // note that we would handle class methods directly in calls
match generator.gen_expr(ctx, value)?.unwrap() { match generator.gen_expr(ctx, value)?.unwrap() {
ValueEnum::Static(v) => v.get_field(*attr, ctx).map_or_else( ValueEnum::Static(v) => v.get_field(*attr, ctx).map_or_else(|| {
|| { let v = v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?;
let v = v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?; let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
let index = ctx.get_attr_index(value.custom.unwrap(), *attr); Ok(ValueEnum::Dynamic(ctx.build_gep_and_load(
Ok(ValueEnum::Dynamic(ctx.build_gep_and_load( v.into_pointer_value(),
v.into_pointer_value(), &[zero, int32.const_int(index as u64, false)],
&[zero, int32.const_int(index as u64, false)], ))) as Result<_, String>
))) as Result<_, String> }, Ok)?,
},
Ok,
)?,
ValueEnum::Dynamic(v) => { ValueEnum::Dynamic(v) => {
let index = ctx.get_attr_index(value.custom.unwrap(), *attr); let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
ValueEnum::Dynamic(ctx.build_gep_and_load( ValueEnum::Dynamic(ctx.build_gep_and_load(
@ -1220,16 +1125,13 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
phi.add_incoming(&[(&a, a_bb), (&b, b_bb)]); phi.add_incoming(&[(&a, a_bb), (&b, b_bb)]);
phi.as_basic_value().into() phi.as_basic_value().into()
} }
ExprKind::BinOp { op, left, right } => { ExprKind::BinOp { op, left, right } => gen_binop_expr(generator, ctx, left, op, right)?,
return gen_binop_expr(generator, ctx, left, op, right, expr.location, false);
}
ExprKind::UnaryOp { op, operand } => { ExprKind::UnaryOp { op, operand } => {
let ty = ctx.unifier.get_representative(operand.custom.unwrap()); let ty = ctx.unifier.get_representative(operand.custom.unwrap());
let val = generator.gen_expr(ctx, operand)?.unwrap().to_basic_value_enum( let val =
ctx, generator.gen_expr(ctx, operand)?
generator, .unwrap()
operand.custom.unwrap(), .to_basic_value_enum(ctx, generator, operand.custom.unwrap())?;
)?;
if ty == ctx.primitives.bool { if ty == ctx.primitives.bool {
let val = val.into_int_value(); let val = val.into_int_value();
match op { match op {
@ -1286,16 +1188,14 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
BasicValueEnum::IntValue(lhs), BasicValueEnum::IntValue(lhs),
BasicValueEnum::IntValue(rhs), BasicValueEnum::IntValue(rhs),
) = ( ) = (
generator.gen_expr(ctx, lhs)?.unwrap().to_basic_value_enum( generator
ctx, .gen_expr(ctx, lhs)?
generator, .unwrap()
lhs.custom.unwrap(), .to_basic_value_enum(ctx, generator, lhs.custom.unwrap())?,
)?, generator
generator.gen_expr(ctx, rhs)?.unwrap().to_basic_value_enum( .gen_expr(ctx, rhs)?
ctx, .unwrap()
generator, .to_basic_value_enum(ctx, generator, rhs.custom.unwrap())?,
rhs.custom.unwrap(),
)?,
) { ) {
(lhs, rhs) (lhs, rhs)
} else { } else {
@ -1316,16 +1216,14 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
BasicValueEnum::FloatValue(lhs), BasicValueEnum::FloatValue(lhs),
BasicValueEnum::FloatValue(rhs), BasicValueEnum::FloatValue(rhs),
) = ( ) = (
generator.gen_expr(ctx, lhs)?.unwrap().to_basic_value_enum( generator
ctx, .gen_expr(ctx, lhs)?
generator, .unwrap()
lhs.custom.unwrap(), .to_basic_value_enum(ctx, generator, lhs.custom.unwrap())?,
)?, generator
generator.gen_expr(ctx, rhs)?.unwrap().to_basic_value_enum( .gen_expr(ctx, rhs)?
ctx, .unwrap()
generator, .to_basic_value_enum(ctx, generator, rhs.custom.unwrap())?,
rhs.custom.unwrap(),
)?,
) { ) {
(lhs, rhs) (lhs, rhs)
} else { } else {
@ -1383,8 +1281,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
match result { match result {
None => None, None => None,
Some(v) => { Some(v) => {
let b = let b = b.unwrap().to_basic_value_enum(ctx, generator, orelse.custom.unwrap())?;
b.unwrap().to_basic_value_enum(ctx, generator, orelse.custom.unwrap())?;
Some(ctx.builder.build_store(v, b)) Some(ctx.builder.build_store(v, b))
} }
}; };
@ -1392,7 +1289,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
ctx.builder.position_at_end(cont_bb); ctx.builder.position_at_end(cont_bb);
match result { match result {
None => return Ok(None), None => return Ok(None),
Some(v) => return Ok(Some(ctx.builder.build_load(v, "if_exp_val_load").into())), Some(v) => return Ok(Some(ctx.builder.build_load(v, "if_exp_val_load").into()))
} }
} }
ExprKind::Call { func, args, keywords } => { ExprKind::Call { func, args, keywords } => {
@ -1445,7 +1342,13 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
let defs = ctx.top_level.definitions.read(); let defs = ctx.top_level.definitions.read();
let obj_def = defs.get(id.0).unwrap().read(); let obj_def = defs.get(id.0).unwrap().read();
if let TopLevelDef::Class { methods, .. } = &*obj_def { if let TopLevelDef::Class { methods, .. } = &*obj_def {
methods.iter().find(|method| method.0 == *attr).unwrap().2 let mut fun_id = None;
for (name, _, id) in methods.iter() {
if name == attr {
fun_id = Some(*id);
}
}
fun_id.unwrap()
} else { } else {
unreachable!() unreachable!()
} }
@ -1466,12 +1369,14 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
.unwrap() .unwrap()
.get_parent() .get_parent()
.unwrap(); .unwrap();
let unreachable_block = ctx let unreachable_block = ctx.ctx.append_basic_block(
.ctx current_fun,
.append_basic_block(current_fun, "unwrap_none_unreachable"); "unwrap_none_unreachable"
let exn_block = ctx );
.ctx let exn_block = ctx.ctx.append_basic_block(
.append_basic_block(current_fun, "unwrap_none_exception"); current_fun,
"unwrap_none_exception"
);
ctx.builder.build_unconditional_branch(exn_block); ctx.builder.build_unconditional_branch(exn_block);
ctx.builder.position_at_end(exn_block); ctx.builder.position_at_end(exn_block);
ctx.raise_exn( ctx.raise_exn(
@ -1479,24 +1384,22 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
"0:UnwrapNoneError", "0:UnwrapNoneError",
err_msg, err_msg,
[None, None, None], [None, None, None],
ctx.current_loc, ctx.current_loc
); );
ctx.builder.position_at_end(unreachable_block); ctx.builder.position_at_end(unreachable_block);
let ptr = ctx let ptr = ctx
.get_llvm_type(generator, value.custom.unwrap()) .get_llvm_type(generator, value.custom.unwrap())
.into_pointer_type() .into_pointer_type()
.const_null(); .const_null();
return Ok(Some( return Ok(Some(ctx.builder.build_load(
ctx.builder ptr,
.build_load(ptr, "unwrap_none_unreachable_load") "unwrap_none_unreachable_load"
.into(), ).into()));
));
} }
Some(v) => return Ok(Some(v)), Some(v) => return Ok(Some(v)),
}, }
ValueEnum::Dynamic(BasicValueEnum::PointerValue(ptr)) => { ValueEnum::Dynamic(BasicValueEnum::PointerValue(ptr)) => {
let not_null = let not_null = ctx.builder.build_is_not_null(ptr, "unwrap_not_null");
ctx.builder.build_is_not_null(ptr, "unwrap_not_null");
ctx.make_assert( ctx.make_assert(
generator, generator,
not_null, not_null,
@ -1505,11 +1408,12 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
[None, None, None], [None, None, None],
expr.location, expr.location,
); );
return Ok(Some( return Ok(Some(ctx.builder.build_load(
ctx.builder.build_load(ptr, "unwrap_some_load").into(), ptr,
)); "unwrap_some_load"
).into()))
} }
_ => unreachable!("option must be static or ptr"), _ => unreachable!("option must be static or ptr")
} }
} }
return Ok(generator return Ok(generator
@ -1620,26 +1524,30 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
} else { } else {
unreachable!("tuple subscript must be const int after type check"); unreachable!("tuple subscript must be const int after type check");
}; };
let v = generator.gen_expr(ctx, value)?.unwrap(); let v = generator
.gen_expr(ctx, value)?
.unwrap();
match v { match v {
ValueEnum::Dynamic(v) => { ValueEnum::Dynamic(v) => {
let v = v.into_struct_value(); let v = v.into_struct_value();
ctx.builder.build_extract_value(v, index, "tup_elem").unwrap().into() ctx.builder.build_extract_value(v, index, "tup_elem").unwrap().into()
} }
ValueEnum::Static(v) => match v.get_tuple_element(index) { ValueEnum::Static(v) => {
Some(v) => v, match v.get_tuple_element(index) {
None => { Some(v) => v,
let tup = v None => {
.to_basic_value_enum(ctx, generator, value.custom.unwrap())? let tup = v
.into_struct_value(); .to_basic_value_enum(ctx, generator, value.custom.unwrap())?
ctx.builder.build_extract_value(tup, index, "tup_elem").unwrap().into() .into_struct_value();
ctx.builder.build_extract_value(tup, index, "tup_elem").unwrap().into()
}
} }
}, }
} }
} else { } else {
unreachable!("should not be other subscriptable types after type check"); unreachable!("should not be other subscriptable types after type check");
} }
} },
ExprKind::ListComp { .. } => gen_comprehension(generator, ctx, expr)?.into(), ExprKind::ListComp { .. } => gen_comprehension(generator, ctx, expr)?.into(),
_ => unimplemented!(), _ => unimplemented!(),
})) }))

View File

@ -1,4 +1,9 @@
#include "stdint.h" typedef _ExtInt(8) int8_t;
typedef unsigned _ExtInt(8) uint8_t;
typedef _ExtInt(32) int32_t;
typedef unsigned _ExtInt(32) uint32_t;
typedef _ExtInt(64) int64_t;
typedef unsigned _ExtInt(64) uint64_t;
# define MAX(a, b) (a > b ? a : b) # define MAX(a, b) (a > b ? a : b)
# define MIN(a, b) (a > b ? b : a) # define MIN(a, b) (a > b ? b : a)

View File

@ -261,11 +261,7 @@ pub fn handle_slice_index_bound<'a, 'ctx, G: CodeGenerator>(
ctx.module.add_function(SYMBOL, fn_t, None) ctx.module.add_function(SYMBOL, fn_t, None)
}); });
let i = generator.gen_expr(ctx, i)?.unwrap().to_basic_value_enum( let i = generator.gen_expr(ctx, i)?.unwrap().to_basic_value_enum(ctx, generator, i.custom.unwrap())?;
ctx,
generator,
i.custom.unwrap(),
)?;
Ok(ctx Ok(ctx
.builder .builder
.build_call(func, &[i.into(), length.into()], "bounded_ind") .build_call(func, &[i.into(), length.into()], "bounded_ind")
@ -333,19 +329,27 @@ pub fn list_slice_assignment<'ctx, 'a>(
// index in bound and positive should be done // index in bound and positive should be done
// assert if dest.step == 1 then len(src) <= len(dest) else len(src) == len(dest), and // assert if dest.step == 1 then len(src) <= len(dest) else len(src) == len(dest), and
// throw exception if not satisfied // throw exception if not satisfied
let src_end = ctx let src_end = ctx.builder
.builder
.build_select( .build_select(
ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, src_idx.2, zero, "is_neg"), ctx.builder.build_int_compare(
inkwell::IntPredicate::SLT,
src_idx.2,
zero,
"is_neg",
),
ctx.builder.build_int_sub(src_idx.1, one, "e_min_one"), ctx.builder.build_int_sub(src_idx.1, one, "e_min_one"),
ctx.builder.build_int_add(src_idx.1, one, "e_add_one"), ctx.builder.build_int_add(src_idx.1, one, "e_add_one"),
"final_e", "final_e",
) )
.into_int_value(); .into_int_value();
let dest_end = ctx let dest_end = ctx.builder
.builder
.build_select( .build_select(
ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, dest_idx.2, zero, "is_neg"), ctx.builder.build_int_compare(
inkwell::IntPredicate::SLT,
dest_idx.2,
zero,
"is_neg",
),
ctx.builder.build_int_sub(dest_idx.1, one, "e_min_one"), ctx.builder.build_int_sub(dest_idx.1, one, "e_min_one"),
ctx.builder.build_int_add(dest_idx.1, one, "e_add_one"), ctx.builder.build_int_add(dest_idx.1, one, "e_add_one"),
"final_e", "final_e",

View File

@ -8,6 +8,8 @@ use crate::{
}; };
use crossbeam::channel::{unbounded, Receiver, Sender}; use crossbeam::channel::{unbounded, Receiver, Sender};
use inkwell::{ use inkwell::{
AddressSpace,
OptimizationLevel,
attributes::{Attribute, AttributeLoc}, attributes::{Attribute, AttributeLoc},
basic_block::BasicBlock, basic_block::BasicBlock,
builder::Builder, builder::Builder,
@ -15,11 +17,10 @@ use inkwell::{
module::Module, module::Module,
passes::{PassManager, PassManagerBuilder}, passes::{PassManager, PassManagerBuilder},
types::{AnyType, BasicType, BasicTypeEnum}, types::{AnyType, BasicType, BasicTypeEnum},
values::{BasicValueEnum, FunctionValue, PhiValue, PointerValue}, values::{BasicValueEnum, FunctionValue, PhiValue, PointerValue}
AddressSpace, OptimizationLevel,
}; };
use itertools::Itertools; use itertools::Itertools;
use nac3parser::ast::{Location, Stmt, StrRef}; use nac3parser::ast::{Stmt, StrRef, Location};
use parking_lot::{Condvar, Mutex}; use parking_lot::{Condvar, Mutex};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::sync::{ use std::sync::{
@ -299,10 +300,7 @@ fn get_llvm_type<'ctx>(
&*definition.read() &*definition.read()
{ {
let struct_type = ctx.opaque_struct_type(&name.to_string()); let struct_type = ctx.opaque_struct_type(&name.to_string());
type_cache.insert( type_cache.insert(unifier.get_representative(ty), struct_type.ptr_type(AddressSpace::Generic).into());
unifier.get_representative(ty),
struct_type.ptr_type(AddressSpace::Generic).into(),
);
let fields = fields_list let fields = fields_list
.iter() .iter()
.map(|f| { .map(|f| {
@ -328,11 +326,7 @@ fn get_llvm_type<'ctx>(
// a struct with fields in the order present in the tuple // a struct with fields in the order present in the tuple
let fields = ty let fields = ty
.iter() .iter()
.map(|ty| { .map(|ty| get_llvm_type(ctx, generator, unifier, top_level, type_cache, primitives, *ty))
get_llvm_type(
ctx, generator, unifier, top_level, type_cache, primitives, *ty,
)
})
.collect_vec(); .collect_vec();
ctx.struct_type(&fields, false).into() ctx.struct_type(&fields, false).into()
} }
@ -355,35 +349,26 @@ fn get_llvm_type<'ctx>(
} }
fn need_sret<'ctx>(ctx: &'ctx Context, ty: BasicTypeEnum<'ctx>) -> bool { fn need_sret<'ctx>(ctx: &'ctx Context, ty: BasicTypeEnum<'ctx>) -> bool {
fn need_sret_impl<'ctx>( fn need_sret_impl<'ctx>(ctx: &'ctx Context, ty: BasicTypeEnum<'ctx>, maybe_large: bool) -> bool {
ctx: &'ctx Context,
ty: BasicTypeEnum<'ctx>,
maybe_large: bool,
) -> bool {
match ty { match ty {
BasicTypeEnum::IntType(_) | BasicTypeEnum::PointerType(_) => false, BasicTypeEnum::IntType(_) | BasicTypeEnum::PointerType(_) => false,
BasicTypeEnum::FloatType(_) if maybe_large => false, BasicTypeEnum::FloatType(_) if maybe_large => false,
BasicTypeEnum::StructType(ty) if maybe_large && ty.count_fields() <= 2 => { BasicTypeEnum::StructType(ty) if maybe_large && ty.count_fields() <= 2 =>
ty.get_field_types().iter().any(|ty| need_sret_impl(ctx, *ty, false)) ty.get_field_types().iter().any(|ty| need_sret_impl(ctx, *ty, false)),
}
_ => true, _ => true,
} }
} }
need_sret_impl(ctx, ty, true) need_sret_impl(ctx, ty, true)
} }
pub fn gen_func_impl< pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenContext) -> Result<(), String>> (
'ctx,
G: CodeGenerator,
F: FnOnce(&mut G, &mut CodeGenContext) -> Result<(), String>,
>(
context: &'ctx Context, context: &'ctx Context,
generator: &mut G, generator: &mut G,
registry: &WorkerRegistry, registry: &WorkerRegistry,
builder: Builder<'ctx>, builder: Builder<'ctx>,
module: Module<'ctx>, module: Module<'ctx>,
task: CodeGenTask, task: CodeGenTask,
codegen_function: F, codegen_function: F
) -> Result<(Builder<'ctx>, Module<'ctx>, FunctionValue<'ctx>), (Builder<'ctx>, String)> { ) -> Result<(Builder<'ctx>, Module<'ctx>, FunctionValue<'ctx>), (Builder<'ctx>, String)> {
let top_level_ctx = registry.top_level_ctx.clone(); let top_level_ctx = registry.top_level_ctx.clone();
let static_value_store = registry.static_value_store.clone(); let static_value_store = registry.static_value_store.clone();
@ -478,15 +463,7 @@ pub fn gen_func_impl<
let ret_type = if unifier.unioned(ret, primitives.none) { let ret_type = if unifier.unioned(ret, primitives.none) {
None None
} else { } else {
Some(get_llvm_type( Some(get_llvm_type(context, generator, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, &primitives, ret))
context,
generator,
&mut unifier,
top_level_ctx.as_ref(),
&mut type_cache,
&primitives,
ret,
))
}; };
let has_sret = ret_type.map_or(false, |ty| need_sret(context, ty)); let has_sret = ret_type.map_or(false, |ty| need_sret(context, ty));
@ -512,7 +489,7 @@ pub fn gen_func_impl<
let fn_type = match ret_type { let fn_type = match ret_type {
Some(ret_type) if !has_sret => ret_type.fn_type(&params, false), Some(ret_type) if !has_sret => ret_type.fn_type(&params, false),
_ => context.void_type().fn_type(&params, false), _ => context.void_type().fn_type(&params, false)
}; };
let symbol = &task.symbol_name; let symbol = &task.symbol_name;
@ -527,13 +504,9 @@ pub fn gen_func_impl<
fn_val.set_personality_function(personality); fn_val.set_personality_function(personality);
} }
if has_sret { if has_sret {
fn_val.add_attribute( fn_val.add_attribute(AttributeLoc::Param(0),
AttributeLoc::Param(0), context.create_type_attribute(Attribute::get_named_enum_kind_id("sret"),
context.create_type_attribute( ret_type.unwrap().as_any_type_enum()));
Attribute::get_named_enum_kind_id("sret"),
ret_type.unwrap().as_any_type_enum(),
),
);
} }
let init_bb = context.append_basic_block(fn_val, "init"); let init_bb = context.append_basic_block(fn_val, "init");

View File

@ -87,15 +87,19 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, value.custom.unwrap())? .to_basic_value_enum(ctx, generator, value.custom.unwrap())?
.into_pointer_value(); .into_pointer_value();
let len = let len = ctx
ctx.build_gep_and_load(v, &[zero, i32_type.const_int(1, false)]).into_int_value(); .build_gep_and_load(v, &[zero, i32_type.const_int(1, false)])
.into_int_value();
let raw_index = generator let raw_index = generator
.gen_expr(ctx, slice)? .gen_expr(ctx, slice)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, slice.custom.unwrap())? .to_basic_value_enum(ctx, generator, slice.custom.unwrap())?
.into_int_value(); .into_int_value();
let raw_index = let raw_index = ctx.builder.build_int_s_extend(
ctx.builder.build_int_s_extend(raw_index, generator.get_size_type(ctx.ctx), "sext"); raw_index,
generator.get_size_type(ctx.ctx),
"sext",
);
// handle negative index // handle negative index
let is_negative = ctx.builder.build_int_compare( let is_negative = ctx.builder.build_int_compare(
inkwell::IntPredicate::SLT, inkwell::IntPredicate::SLT,
@ -110,8 +114,12 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
.into_int_value(); .into_int_value();
// unsigned less than is enough, because negative index after adjustment is // unsigned less than is enough, because negative index after adjustment is
// bigger than the length (for unsigned cmp) // bigger than the length (for unsigned cmp)
let bound_check = let bound_check = ctx.builder.build_int_compare(
ctx.builder.build_int_compare(inkwell::IntPredicate::ULT, index, len, "inbound"); inkwell::IntPredicate::ULT,
index,
len,
"inbound",
);
ctx.make_assert( ctx.make_assert(
generator, generator,
bound_check, bound_check,
@ -486,7 +494,7 @@ pub fn get_builtins<'ctx, 'a>(
if symbol == "__nac3_raise" || symbol == "__nac3_resume" { if symbol == "__nac3_raise" || symbol == "__nac3_resume" {
fun.add_attribute( fun.add_attribute(
AttributeLoc::Function, AttributeLoc::Function,
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("noreturn"), 0), ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("noreturn"), 1),
); );
} }
fun fun
@ -688,15 +696,12 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
&mut ctx.unifier, &mut ctx.unifier,
type_.custom.unwrap(), type_.custom.unwrap(),
); );
let obj_id = if let TypeEnum::TObj { obj_id, .. } = let obj_id = if let TypeEnum::TObj { obj_id, .. } = &*ctx.unifier.get_ty(type_.custom.unwrap()) {
&*ctx.unifier.get_ty(type_.custom.unwrap())
{
*obj_id *obj_id
} else { } else {
unreachable!() unreachable!()
}; };
let exception_name = let exception_name = format!("{}:{}", ctx.resolver.get_exception_id(obj_id.0), exn_name);
format!("{}:{}", ctx.resolver.get_exception_id(obj_id.0), exn_name);
let exn_id = ctx.resolver.get_string_id(&exception_name); let exn_id = ctx.resolver.get_string_id(&exception_name);
let exn_id_global = let exn_id_global =
ctx.module.add_global(ctx.ctx.i32_type(), None, &format!("exn.{}", exn_id)); ctx.module.add_global(ctx.ctx.i32_type(), None, &format!("exn.{}", exn_id));
@ -746,9 +751,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
let mut final_proxy_lambda = let mut final_proxy_lambda =
|ctx: &mut CodeGenContext<'ctx, 'a>, |ctx: &mut CodeGenContext<'ctx, 'a>,
target: BasicBlock<'ctx>, target: BasicBlock<'ctx>,
block: BasicBlock<'ctx>| { block: BasicBlock<'ctx>| final_proxy(ctx, target, block, final_data.as_mut().unwrap());
final_proxy(ctx, target, block, final_data.as_mut().unwrap())
};
let mut redirect_lambda = |ctx: &mut CodeGenContext<'ctx, 'a>, let mut redirect_lambda = |ctx: &mut CodeGenContext<'ctx, 'a>,
target: BasicBlock<'ctx>, target: BasicBlock<'ctx>,
block: BasicBlock<'ctx>| { block: BasicBlock<'ctx>| {
@ -1017,8 +1020,8 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
StmtKind::For { .. } => generator.gen_for(ctx, stmt)?, StmtKind::For { .. } => generator.gen_for(ctx, stmt)?,
StmtKind::With { .. } => generator.gen_with(ctx, stmt)?, StmtKind::With { .. } => generator.gen_with(ctx, stmt)?,
StmtKind::AugAssign { target, op, value, .. } => { StmtKind::AugAssign { target, op, value, .. } => {
let value = gen_binop_expr(generator, ctx, target, op, value, stmt.location, true)?; let value = gen_binop_expr(generator, ctx, target, op, value)?;
generator.gen_assign(ctx, target, value.unwrap())?; generator.gen_assign(ctx, target, value)?;
} }
StmtKind::Try { .. } => gen_try(generator, ctx, stmt)?, StmtKind::Try { .. } => gen_try(generator, ctx, stmt)?,
StmtKind::Raise { exc, .. } => { StmtKind::Raise { exc, .. } => {
@ -1056,7 +1059,7 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
stmt.location, stmt.location,
) )
} }
_ => unimplemented!(), _ => unimplemented!()
}; };
Ok(()) Ok(())
} }

View File

@ -160,7 +160,7 @@ pub trait SymbolResolver {
&self, &self,
_unifier: &mut Unifier, _unifier: &mut Unifier,
_top_level_defs: &[Arc<RwLock<TopLevelDef>>], _top_level_defs: &[Arc<RwLock<TopLevelDef>>],
_primitives: &PrimitiveStore, _primitives: &PrimitiveStore
) -> Result<(), String> { ) -> Result<(), String> {
Ok(()) Ok(())
} }

View File

@ -14,8 +14,8 @@ pub fn get_exn_constructor(
class_id: usize, class_id: usize,
cons_id: usize, cons_id: usize,
unifier: &mut Unifier, unifier: &mut Unifier,
primitives: &PrimitiveStore, primitives: &PrimitiveStore
) -> (TopLevelDef, TopLevelDef, Type, Type) { )-> (TopLevelDef, TopLevelDef, Type, Type) {
let int32 = primitives.int32; let int32 = primitives.int32;
let int64 = primitives.int64; let int64 = primitives.int64;
let string = primitives.str; let string = primitives.str;
@ -225,8 +225,11 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
codegen_callback: Some(Arc::new(GenCall::new(Box::new( codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, obj, _, _, generator| { |ctx, obj, _, _, generator| {
let expect_ty = obj.clone().unwrap().0; let expect_ty = obj.clone().unwrap().0;
let obj_val = let obj_val = obj.unwrap().1.clone().to_basic_value_enum(
obj.unwrap().1.clone().to_basic_value_enum(ctx, generator, expect_ty)?; ctx,
generator,
expect_ty,
)?;
if let BasicValueEnum::PointerValue(ptr) = obj_val { if let BasicValueEnum::PointerValue(ptr) = obj_val {
Ok(Some(ctx.builder.build_is_not_null(ptr, "is_some").into())) Ok(Some(ctx.builder.build_is_not_null(ptr, "is_some").into()))
} else { } else {
@ -247,8 +250,11 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
codegen_callback: Some(Arc::new(GenCall::new(Box::new( codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, obj, _, _, generator| { |ctx, obj, _, _, generator| {
let expect_ty = obj.clone().unwrap().0; let expect_ty = obj.clone().unwrap().0;
let obj_val = let obj_val = obj.unwrap().1.clone().to_basic_value_enum(
obj.unwrap().1.clone().to_basic_value_enum(ctx, generator, expect_ty)?; ctx,
generator,
expect_ty,
)?;
if let BasicValueEnum::PointerValue(ptr) = obj_val { if let BasicValueEnum::PointerValue(ptr) = obj_val {
Ok(Some(ctx.builder.build_is_null(ptr, "is_none").into())) Ok(Some(ctx.builder.build_is_null(ptr, "is_none").into()))
} else { } else {
@ -266,9 +272,11 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
instance_to_symbol: Default::default(), instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(), instance_to_stmt: Default::default(),
resolver: None, resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|_, _, _, _, _| { codegen_callback: Some(Arc::new(GenCall::new(Box::new(
unreachable!("handled in gen_expr") |_, _, _, _, _| {
})))), unreachable!("handled in gen_expr")
},
)))),
loc: None, loc: None,
})), })),
Arc::new(RwLock::new(TopLevelDef::Function { Arc::new(RwLock::new(TopLevelDef::Function {
@ -559,11 +567,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
resolver: None, resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new( codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, _, args, generator| { |ctx, _, _, args, generator| {
let arg = args[0].1.clone().to_basic_value_enum( let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, ctx.primitives.float)?;
ctx,
generator,
ctx.primitives.float,
)?;
let round_intrinsic = let round_intrinsic =
ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| { ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type(); let float = ctx.ctx.f64_type();
@ -603,11 +607,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
resolver: None, resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new( codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, _, args, generator| { |ctx, _, _, args, generator| {
let arg = args[0].1.clone().to_basic_value_enum( let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, ctx.primitives.float)?;
ctx,
generator,
ctx.primitives.float,
)?;
let round_intrinsic = let round_intrinsic =
ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| { ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type(); let float = ctx.ctx.f64_type();
@ -668,15 +668,13 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
let ty_i32 = ctx.primitives.int32; let ty_i32 = ctx.primitives.int32;
for (i, arg) in args.iter().enumerate() { for (i, arg) in args.iter().enumerate() {
if arg.0 == Some("start".into()) { if arg.0 == Some("start".into()) {
start = start = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
} else if arg.0 == Some("stop".into()) { } else if arg.0 == Some("stop".into()) {
stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?); stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
} else if arg.0 == Some("step".into()) { } else if arg.0 == Some("step".into()) {
step = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?); step = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
} else if i == 0 { } else if i == 0 {
start = start = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
} else if i == 1 { } else if i == 1 {
stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?); stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
} else if i == 2 { } else if i == 2 {
@ -831,11 +829,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
resolver: None, resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new( codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, _, args, generator| { |ctx, _, _, args, generator| {
let arg = args[0].1.clone().to_basic_value_enum( let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, ctx.primitives.float)?;
ctx,
generator,
ctx.primitives.float,
)?;
let floor_intrinsic = let floor_intrinsic =
ctx.module.get_function("llvm.floor.f64").unwrap_or_else(|| { ctx.module.get_function("llvm.floor.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type(); let float = ctx.ctx.f64_type();
@ -875,11 +869,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
resolver: None, resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new( codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, _, args, generator| { |ctx, _, _, args, generator| {
let arg = args[0].1.clone().to_basic_value_enum( let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, ctx.primitives.float)?;
ctx,
generator,
ctx.primitives.float,
)?;
let floor_intrinsic = let floor_intrinsic =
ctx.module.get_function("llvm.floor.f64").unwrap_or_else(|| { ctx.module.get_function("llvm.floor.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type(); let float = ctx.ctx.f64_type();
@ -919,11 +909,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
resolver: None, resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new( codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, _, args, generator| { |ctx, _, _, args, generator| {
let arg = args[0].1.clone().to_basic_value_enum( let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, ctx.primitives.float)?;
ctx,
generator,
ctx.primitives.float,
)?;
let ceil_intrinsic = let ceil_intrinsic =
ctx.module.get_function("llvm.ceil.f64").unwrap_or_else(|| { ctx.module.get_function("llvm.ceil.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type(); let float = ctx.ctx.f64_type();
@ -963,11 +949,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
resolver: None, resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new( codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, _, args, generator| { |ctx, _, _, args, generator| {
let arg = args[0].1.clone().to_basic_value_enum( let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, ctx.primitives.float)?;
ctx,
generator,
ctx.primitives.float,
)?;
let ceil_intrinsic = let ceil_intrinsic =
ctx.module.get_function("llvm.ceil.f64").unwrap_or_else(|| { ctx.module.get_function("llvm.ceil.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type(); let float = ctx.ctx.f64_type();
@ -1023,10 +1005,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
Ok(if ctx.unifier.unioned(arg_ty, range_ty) { Ok(if ctx.unifier.unioned(arg_ty, range_ty) {
let arg = arg.into_pointer_value(); let arg = arg.into_pointer_value();
let (start, end, step) = destructure_range(ctx, arg); let (start, end, step) = destructure_range(ctx, arg);
Some( Some(calculate_len_for_slice_range(generator, ctx, start, end, step).into())
calculate_len_for_slice_range(generator, ctx, start, end, step)
.into(),
)
} else { } else {
let int32 = ctx.ctx.i32_type(); let int32 = ctx.ctx.i32_type();
let zero = int32.const_zero(); let zero = int32.const_zero();
@ -1265,12 +1244,30 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
})), })),
]; ];
let ast_list: Vec<Option<ast::Stmt<()>>> = vec![None; top_level_def_list.len()]; let ast_list: Vec<Option<ast::Stmt<()>>> =
(0..top_level_def_list.len()).map(|_| None).collect();
( (
izip!(top_level_def_list, ast_list).collect_vec(), izip!(top_level_def_list, ast_list).collect_vec(),
&[ &[
"int32", "int64", "uint32", "uint64", "float", "round", "round64", "range", "str", "int32",
"bool", "floor", "floor64", "ceil", "ceil64", "len", "min", "max", "abs", "Some", "int64",
"uint32",
"uint64",
"float",
"round",
"round64",
"range",
"str",
"bool",
"floor",
"floor64",
"ceil",
"ceil64",
"len",
"min",
"max",
"abs",
"Some",
], ],
) )
} }

View File

@ -91,7 +91,8 @@ impl TopLevelComposer {
assert!(name == *simple_name); assert!(name == *simple_name);
builtin_ty.insert(name, *signature); builtin_ty.insert(name, *signature);
builtin_id.insert(name, DefinitionId(id)); builtin_id.insert(name, DefinitionId(id));
} else if let TopLevelDef::Class { name, constructor, object_id, .. } = &*def { } else if let TopLevelDef::Class { name, constructor, object_id, .. } = &*def
{
assert!(id == object_id.0); assert!(id == object_id.0);
if let Some(constructor) = constructor { if let Some(constructor) = constructor {
builtin_ty.insert(*name, *constructor); builtin_ty.insert(*name, *constructor);
@ -738,13 +739,8 @@ impl TopLevelComposer {
let mut subst_list = Some(Vec::new()); let mut subst_list = Some(Vec::new());
// unification of previously assigned typevar // unification of previously assigned typevar
let mut unification_helper = |ty, def| { let mut unification_helper = |ty, def| {
let target_ty = get_type_from_type_annotation_kinds( let target_ty =
&temp_def_list, get_type_from_type_annotation_kinds(&temp_def_list, unifier, primitives, &def, &mut subst_list)?;
unifier,
primitives,
&def,
&mut subst_list,
)?;
unifier.unify(ty, target_ty).map_err(|e| e.to_display(unifier).to_string())?; unifier.unify(ty, target_ty).map_err(|e| e.to_display(unifier).to_string())?;
Ok(()) as Result<(), String> Ok(()) as Result<(), String>
}; };
@ -784,9 +780,7 @@ impl TopLevelComposer {
match &*def.read() { match &*def.read() {
TopLevelDef::Class { resolver: Some(resolver), .. } TopLevelDef::Class { resolver: Some(resolver), .. }
| TopLevelDef::Function { resolver: Some(resolver), .. } => { | TopLevelDef::Function { resolver: Some(resolver), .. } => {
if let Err(e) = if let Err(e) = resolver.handle_deferred_eval(unifier, &temp_def_list, primitives) {
resolver.handle_deferred_eval(unifier, &temp_def_list, primitives)
{
errors.insert(e); errors.insert(e);
} }
} }
@ -910,7 +904,7 @@ impl TopLevelComposer {
unifier, unifier,
primitives_store, primitives_store,
&type_annotation, &type_annotation,
&mut None, &mut None
)?; )?;
Ok(FuncArg { Ok(FuncArg {
@ -978,7 +972,7 @@ impl TopLevelComposer {
unifier, unifier,
primitives_store, primitives_store,
&return_ty_annotation, &return_ty_annotation,
&mut None, &mut None
)? )?
} else { } else {
primitives_store.none primitives_store.none
@ -1340,7 +1334,7 @@ impl TopLevelComposer {
)); ));
} }
} }
ast::StmtKind::Assign { .. } => {} // we don't class attributes ast::StmtKind::Assign { .. } => {}, // we don't class attributes
ast::StmtKind::Pass { .. } => {} ast::StmtKind::Pass { .. } => {}
ast::StmtKind::Expr { value: _, .. } => {} // typically a docstring; ignoring all expressions matches CPython behavior ast::StmtKind::Expr { value: _, .. } => {} // typically a docstring; ignoring all expressions matches CPython behavior
_ => { _ => {
@ -1489,30 +1483,24 @@ impl TopLevelComposer {
// first, fix function typevar ids // first, fix function typevar ids
// they may be changed with our use of placeholders // they may be changed with our use of placeholders
for (def, _) in definition_ast_list.iter().skip(self.builtin_num) { for (def, _) in definition_ast_list.iter().skip(self.builtin_num) {
if let TopLevelDef::Function { signature, var_id, .. } = &mut *def.write() { if let TopLevelDef::Function {
signature,
var_id,
..
} = &mut *def.write() {
if let TypeEnum::TFunc(FunSignature { args, ret, vars }) = if let TypeEnum::TFunc(FunSignature { args, ret, vars }) =
unifier.get_ty(*signature).as_ref() unifier.get_ty(*signature).as_ref() {
{ let new_var_ids = vars.values().map(|v| match &*unifier.get_ty(*v) {
let new_var_ids = vars TypeEnum::TVar{id, ..} => *id,
.values() _ => unreachable!(),
.map(|v| match &*unifier.get_ty(*v) { }).collect_vec();
TypeEnum::TVar { id, .. } => *id,
_ => unreachable!(),
})
.collect_vec();
if new_var_ids != *var_id { if new_var_ids != *var_id {
let new_signature = FunSignature { let new_signature = FunSignature {
args: args.clone(), args: args.clone(),
ret: *ret, ret: *ret,
vars: new_var_ids vars: new_var_ids.iter().zip(vars.values()).map(|(id, v)| (*id, *v)).collect(),
.iter()
.zip(vars.values())
.map(|(id, v)| (*id, *v))
.collect(),
}; };
unifier unifier.unification_table.set_value(*signature, Rc::new(TypeEnum::TFunc(new_signature)));
.unification_table
.set_value(*signature, Rc::new(TypeEnum::TFunc(new_signature)));
*var_id = new_var_ids; *var_id = new_var_ids;
} }
} }
@ -1539,7 +1527,7 @@ impl TopLevelComposer {
unifier, unifier,
primitives_ty, primitives_ty,
&make_self_type_annotation(type_vars, *object_id), &make_self_type_annotation(type_vars, *object_id),
&mut None, &mut None
)?; )?;
if ancestors if ancestors
.iter() .iter()
@ -1708,15 +1696,14 @@ impl TopLevelComposer {
unifier, unifier,
primitives_ty, primitives_ty,
&ty_ann, &ty_ann,
&mut None, &mut None
)?; )?;
vars.extend(type_vars.iter().map(|ty| { vars.extend(type_vars.iter().map(|ty|
if let TypeEnum::TVar { id, .. } = &*unifier.get_ty(*ty) { if let TypeEnum::TVar { id, .. } = &*unifier.get_ty(*ty) {
(*id, *ty) (*id, *ty)
} else { } else {
unreachable!() unreachable!()
} }));
}));
Some((self_ty, type_vars.clone())) Some((self_ty, type_vars.clone()))
} else { } else {
unreachable!("must be class def") unreachable!("must be class def")
@ -1931,12 +1918,7 @@ impl TopLevelComposer {
} }
instance_to_stmt.insert( instance_to_stmt.insert(
get_subst_key( get_subst_key(unifier, self_type, &subst, Some(&vars.keys().cloned().collect())),
unifier,
self_type,
&subst,
Some(&vars.keys().cloned().collect()),
),
FunInstance { FunInstance {
body: Arc::new(fun_body), body: Arc::new(fun_body),
unifier_id: 0, unifier_id: 0,

View File

@ -521,66 +521,65 @@ pub fn parse_parameter_default_value(
} }
match &default.node { match &default.node {
ast::ExprKind::Constant { value, .. } => handle_constant(value, &default.location), ast::ExprKind::Constant { value, .. } => handle_constant(value, &default.location),
ast::ExprKind::Call { func, args, .. } if args.len() == 1 => match &func.node { ast::ExprKind::Call { func, args, .. } if args.len() == 1 => {
ast::ExprKind::Name { id, .. } if *id == "int64".into() => match &args[0].node { match &func.node {
ast::ExprKind::Constant { value: Constant::Int(v), .. } => { ast::ExprKind::Name { id, .. } if *id == "int64".into() => match &args[0].node {
let v: Result<i64, _> = (*v).try_into(); ast::ExprKind::Constant { value: Constant::Int(v), .. } => {
match v { let v: Result<i64, _> = (*v).try_into();
Ok(v) => Ok(SymbolValue::I64(v)), match v {
_ => { Ok(v) => Ok(SymbolValue::I64(v)),
Err(format!("default param value out of range at {}", default.location)) _ => Err(format!("default param value out of range at {}", default.location)),
} }
} }
_ => Err(format!("only allow constant integer here at {}", default.location))
} }
_ => Err(format!("only allow constant integer here at {}", default.location)), ast::ExprKind::Name { id, .. } if *id == "uint32".into() => match &args[0].node {
}, ast::ExprKind::Constant { value: Constant::Int(v), .. } => {
ast::ExprKind::Name { id, .. } if *id == "uint32".into() => match &args[0].node { let v: Result<u32, _> = (*v).try_into();
ast::ExprKind::Constant { value: Constant::Int(v), .. } => { match v {
let v: Result<u32, _> = (*v).try_into(); Ok(v) => Ok(SymbolValue::U32(v)),
match v { _ => Err(format!("default param value out of range at {}", default.location)),
Ok(v) => Ok(SymbolValue::U32(v)),
_ => {
Err(format!("default param value out of range at {}", default.location))
} }
} }
_ => Err(format!("only allow constant integer here at {}", default.location))
} }
_ => Err(format!("only allow constant integer here at {}", default.location)), ast::ExprKind::Name { id, .. } if *id == "uint64".into() => match &args[0].node {
}, ast::ExprKind::Constant { value: Constant::Int(v), .. } => {
ast::ExprKind::Name { id, .. } if *id == "uint64".into() => match &args[0].node { let v: Result<u64, _> = (*v).try_into();
ast::ExprKind::Constant { value: Constant::Int(v), .. } => { match v {
let v: Result<u64, _> = (*v).try_into(); Ok(v) => Ok(SymbolValue::U64(v)),
match v { _ => Err(format!("default param value out of range at {}", default.location)),
Ok(v) => Ok(SymbolValue::U64(v)),
_ => {
Err(format!("default param value out of range at {}", default.location))
} }
} }
_ => Err(format!("only allow constant integer here at {}", default.location))
} }
_ => Err(format!("only allow constant integer here at {}", default.location)), ast::ExprKind::Name { id, .. } if *id == "Some".into() => Ok(
}, SymbolValue::OptionSome(
ast::ExprKind::Name { id, .. } if *id == "Some".into() => Ok(SymbolValue::OptionSome( Box::new(parse_parameter_default_value(&args[0], resolver)?)
Box::new(parse_parameter_default_value(&args[0], resolver)?), )
)), ),
_ => Err(format!("unsupported default parameter at {}", default.location)), _ => Err(format!("unsupported default parameter at {}", default.location)),
}, }
ast::ExprKind::Tuple { elts, .. } => Ok(SymbolValue::Tuple( }
elts.iter() ast::ExprKind::Tuple { elts, .. } => Ok(SymbolValue::Tuple(elts
.map(|x| parse_parameter_default_value(x, resolver)) .iter()
.collect::<Result<Vec<_>, _>>()?, .map(|x| parse_parameter_default_value(x, resolver))
.collect::<Result<Vec<_>, _>>()?
)), )),
ast::ExprKind::Name { id, .. } if id == &"none".into() => Ok(SymbolValue::OptionNone), ast::ExprKind::Name { id, .. } if id == &"none".into() => Ok(SymbolValue::OptionNone),
ast::ExprKind::Name { id, .. } => { ast::ExprKind::Name { id, .. } => {
resolver.get_default_param_value(default).ok_or_else(|| { resolver.get_default_param_value(default).ok_or_else(
format!( || format!(
"`{}` cannot be used as a default parameter at {} \ "`{}` cannot be used as a default parameter at {} \
(not primitive type, option or tuple / not defined?)", (not primitive type, option or tuple / not defined?)",
id, default.location id,
default.location
) )
}) )
} }
_ => Err(format!( _ => Err(format!(
"unsupported default parameter (not primitive type, option or tuple) at {}", "unsupported default parameter (not primitive type, option or tuple) at {}",
default.location default.location
)), ))
} }
} }

View File

@ -34,23 +34,23 @@ impl TypeAnnotation {
} }
None => format!("class_def_{}", id.0), None => format!("class_def_{}", id.0),
}; };
format!("{}{}", class_name, { format!(
let param_list = "{}{}",
params.iter().map(|p| p.stringify(unifier)).collect_vec().join(", "); class_name,
if param_list.is_empty() { {
"".into() let param_list = params.iter().map(|p| p.stringify(unifier)).collect_vec().join(", ");
} else { if param_list.is_empty() {
format!("[{}]", param_list) "".into()
} else {
format!("[{}]", param_list)
}
} }
}) )
} }
Virtual(ty) => format!("virtual[{}]", ty.stringify(unifier)), Virtual(ty) => format!("virtual[{}]", ty.stringify(unifier)),
List(ty) => format!("list[{}]", ty.stringify(unifier)), List(ty) => format!("list[{}]", ty.stringify(unifier)),
Tuple(types) => { Tuple(types) => {
format!( format!("tuple[{}]", types.iter().map(|p| p.stringify(unifier)).collect_vec().join(", "))
"tuple[{}]",
types.iter().map(|p| p.stringify(unifier)).collect_vec().join(", ")
)
} }
} }
} }
@ -302,7 +302,7 @@ pub fn get_type_from_type_annotation_kinds(
unifier: &mut Unifier, unifier: &mut Unifier,
primitives: &PrimitiveStore, primitives: &PrimitiveStore,
ann: &TypeAnnotation, ann: &TypeAnnotation,
subst_list: &mut Option<Vec<Type>>, subst_list: &mut Option<Vec<Type>>
) -> Result<Type, String> { ) -> Result<Type, String> {
match ann { match ann {
TypeAnnotation::CustomClass { id: obj_id, params } => { TypeAnnotation::CustomClass { id: obj_id, params } => {
@ -324,7 +324,7 @@ pub fn get_type_from_type_annotation_kinds(
unifier, unifier,
primitives, primitives,
x, x,
subst_list, subst_list
) )
}) })
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
@ -402,7 +402,7 @@ pub fn get_type_from_type_annotation_kinds(
unifier, unifier,
primitives, primitives,
ty.as_ref(), ty.as_ref(),
subst_list, subst_list
)?; )?;
Ok(unifier.add_ty(TypeEnum::TVirtual { ty })) Ok(unifier.add_ty(TypeEnum::TVirtual { ty }))
} }
@ -412,7 +412,7 @@ pub fn get_type_from_type_annotation_kinds(
unifier, unifier,
primitives, primitives,
ty.as_ref(), ty.as_ref(),
subst_list, subst_list
)?; )?;
Ok(unifier.add_ty(TypeEnum::TList { ty })) Ok(unifier.add_ty(TypeEnum::TList { ty }))
} }
@ -420,13 +420,7 @@ pub fn get_type_from_type_annotation_kinds(
let tys = tys let tys = tys
.iter() .iter()
.map(|x| { .map(|x| {
get_type_from_type_annotation_kinds( get_type_from_type_annotation_kinds(top_level_defs, unifier, primitives, x, subst_list)
top_level_defs,
unifier,
primitives,
x,
subst_list,
)
}) })
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
Ok(unifier.add_ty(TypeEnum::TTuple { ty: tys })) Ok(unifier.add_ty(TypeEnum::TTuple { ty: tys }))

View File

@ -20,9 +20,8 @@ impl<'a> Inferencer<'a> {
defined_identifiers: &mut HashSet<StrRef>, defined_identifiers: &mut HashSet<StrRef>,
) -> Result<(), String> { ) -> Result<(), String> {
match &pattern.node { match &pattern.node {
ast::ExprKind::Name { id, .. } if id == &"none".into() => { ast::ExprKind::Name { id, .. } if id == &"none".into() =>
Err(format!("cannot assign to a `none` (at {})", pattern.location)) Err(format!("cannot assign to a `none` (at {})", pattern.location)),
}
ExprKind::Name { id, .. } => { ExprKind::Name { id, .. } => {
if !defined_identifiers.contains(id) { if !defined_identifiers.contains(id) {
defined_identifiers.insert(*id); defined_identifiers.insert(*id);

View File

@ -83,7 +83,7 @@ where
pub fn impl_binop( pub fn impl_binop(
unifier: &mut Unifier, unifier: &mut Unifier,
_store: &PrimitiveStore, store: &PrimitiveStore,
ty: Type, ty: Type,
other_ty: &[Type], other_ty: &[Type],
ret_ty: Type, ret_ty: Type,
@ -120,7 +120,7 @@ pub fn impl_binop(
fields.insert(binop_assign_name(op).into(), { fields.insert(binop_assign_name(op).into(), {
( (
unifier.add_ty(TypeEnum::TFunc(FunSignature { unifier.add_ty(TypeEnum::TFunc(FunSignature {
ret: ret_ty, ret: store.none,
vars: function_vars.clone(), vars: function_vars.clone(),
args: vec![FuncArg { args: vec![FuncArg {
ty: other_ty, ty: other_ty,

View File

@ -423,14 +423,14 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
(None, None) => {} (None, None) => {}
}, },
ast::StmtKind::AugAssign { target, op, value, .. } => { ast::StmtKind::AugAssign { target, op, value, .. } => {
let res_ty = self.infer_bin_ops(stmt.location, target, op, value, true)?; let res_ty = self.infer_bin_ops(stmt.location, target, op, value)?;
self.unify(res_ty, target.custom.unwrap(), &stmt.location)?; self.unify(res_ty, target.custom.unwrap(), &stmt.location)?;
} }
ast::StmtKind::Assert { test, msg, .. } => { ast::StmtKind::Assert { test, msg, .. } => {
self.unify(test.custom.unwrap(), self.primitives.bool, &test.location)?; self.unify(test.custom.unwrap(), self.primitives.bool, &test.location)?;
match msg { match msg {
Some(m) => self.unify(m.custom.unwrap(), self.primitives.str, &m.location)?, Some(m) => self.unify(m.custom.unwrap(), self.primitives.str, &m.location)?,
None => (), None => ()
} }
} }
_ => return report_error("Unsupported statement type", stmt.location), _ => return report_error("Unsupported statement type", stmt.location),
@ -464,14 +464,9 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
let var_map = params let var_map = params
.iter() .iter()
.map(|(id_var, ty)| { .map(|(id_var, ty)| {
if let TypeEnum::TVar { id, range, name, loc, .. } = if let TypeEnum::TVar { id, range, name, loc, .. } = &*self.unifier.get_ty(*ty) {
&*self.unifier.get_ty(*ty)
{
assert_eq!(*id, *id_var); assert_eq!(*id, *id_var);
( (*id, self.unifier.get_fresh_var_with_range(range, *name, *loc).0)
*id,
self.unifier.get_fresh_var_with_range(range, *name, *loc).0,
)
} else { } else {
unreachable!() unreachable!()
} }
@ -510,7 +505,7 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
} }
ast::ExprKind::BoolOp { values, .. } => Some(self.infer_bool_ops(values)?), ast::ExprKind::BoolOp { values, .. } => Some(self.infer_bool_ops(values)?),
ast::ExprKind::BinOp { left, op, right } => { ast::ExprKind::BinOp { left, op, right } => {
Some(self.infer_bin_ops(expr.location, left, op, right, false)?) Some(self.infer_bin_ops(expr.location, left, op, right)?)
} }
ast::ExprKind::UnaryOp { op, operand } => Some(self.infer_unary_ops(op, operand)?), ast::ExprKind::UnaryOp { op, operand } => Some(self.infer_unary_ops(op, operand)?),
ast::ExprKind::Compare { left, ops, comparators } => { ast::ExprKind::Compare { left, ops, comparators } => {
@ -827,7 +822,7 @@ impl<'a> Inferencer<'a> {
}, },
}); });
} else { } else {
return report_error("Integer out of bound", args[0].location); return report_error("Integer out of bound", args[0].location)
} }
} }
} }
@ -847,13 +842,13 @@ impl<'a> Inferencer<'a> {
}, },
}); });
} else { } else {
return report_error("Integer out of bound", args[0].location); return report_error("Integer out of bound", args[0].location)
} }
} }
} }
if id == "uint64".into() && args.len() == 1 { if id == "uint64".into() && args.len() == 1 {
if let ExprKind::Constant { value: ast::Constant::Int(val), kind } = if let ExprKind::Constant { value: ast::Constant::Int(val), kind } =
&args[0].node &args[0].node
{ {
let custom = Some(self.primitives.uint64); let custom = Some(self.primitives.uint64);
let v: Result<u64, _> = (*val).try_into(); let v: Result<u64, _> = (*val).try_into();
@ -867,62 +862,10 @@ impl<'a> Inferencer<'a> {
}, },
}); });
} else { } else {
return report_error("Integer out of bound", args[0].location); return report_error("Integer out of bound", args[0].location)
} }
} }
} }
// array() is a "magic" function call that determines the number of
// dimensions in the result from the nesting of the array argument type,
// to match the host Python NumPy API.
if id == "array".into() {
if args.is_empty() {
return report_error(
"`array()` expects at least one argument (contents in list form)",
func_location,
);
}
if args.len() > 2 || !keywords.is_empty() {
return report_error(
"Additional `array()` arguments not yet implemented",
func_location,
);
// TODO: Implement `dtype=` kwarg.
}
let list_arg = self.fold_expr(args.remove(0))?;
// TODO: Implement special case for emtpy arrays (e.g. `array([[]]))`)
// to match NumPy.
let mut num_dims = 0;
let mut elem_type = list_arg.custom.unwrap();
while let TypeEnum::TList { ty } = &*self.unifier.get_ty(elem_type) {
elem_type = *ty;
num_dims += 1;
}
if num_dims == 0 {
return report_error(
"expected list argument to array(), not xxx",
func_location,
);
}
let custom =
Some(self.unifier.add_ty(TypeEnum::TNDArray { ty: elem_type, num_dims }));
return Ok(Located {
location,
custom,
node: ExprKind::Call {
func: Box::new(Located {
custom: None,
location: func.location,
node: ExprKind::Name { id, ctx },
}),
args: vec![list_arg],
keywords: vec![],
},
});
}
Located { location: func_location, custom, node: ExprKind::Name { id, ctx } } Located { location: func_location, custom, node: ExprKind::Name { id, ctx } }
} else { } else {
func func
@ -1019,9 +962,8 @@ impl<'a> Inferencer<'a> {
Ok(self.unifier.add_ty(TypeEnum::TTuple { ty: ty? })) Ok(self.unifier.add_ty(TypeEnum::TTuple { ty: ty? }))
} }
ast::Constant::Str(_) => Ok(self.primitives.str), ast::Constant::Str(_) => Ok(self.primitives.str),
ast::Constant::None => { ast::Constant::None
report_error("CPython `None` not supported (nac3 uses `none` instead)", *loc) => report_error("CPython `None` not supported (nac3 uses `none` instead)", *loc),
}
_ => report_error("not supported", *loc), _ => report_error("not supported", *loc),
} }
} }
@ -1056,11 +998,8 @@ impl<'a> Inferencer<'a> {
} }
(None, _) => { (None, _) => {
let t = self.unifier.stringify(ty); let t = self.unifier.stringify(ty);
report_error( report_error(&format!("`{}::{}` field/method does not exist", t, attr), value.location)
&format!("`{}::{}` field/method does not exist", t, attr), },
value.location,
)
}
} }
} else { } else {
let attr_ty = self.unifier.get_dummy_var().0; let attr_ty = self.unifier.get_dummy_var().0;
@ -1089,22 +1028,8 @@ impl<'a> Inferencer<'a> {
left: &ast::Expr<Option<Type>>, left: &ast::Expr<Option<Type>>,
op: &ast::Operator, op: &ast::Operator,
right: &ast::Expr<Option<Type>>, right: &ast::Expr<Option<Type>>,
is_aug_assign: bool,
) -> InferenceResult { ) -> InferenceResult {
let method = if let TypeEnum::TObj { fields, .. } = let method = binop_name(op).into();
self.unifier.get_ty_immutable(left.custom.unwrap()).as_ref()
{
let (binop_name, binop_assign_name) =
(binop_name(op).into(), binop_assign_name(op).into());
// if is aug_assign, try aug_assign operator first
if is_aug_assign && fields.contains_key(&binop_assign_name) {
binop_assign_name
} else {
binop_name
}
} else {
binop_name(op).into()
};
self.build_method_call( self.build_method_call(
location, location,
method, method,
@ -1156,7 +1081,6 @@ impl<'a> Inferencer<'a> {
for v in [lower.as_ref(), upper.as_ref(), step.as_ref()].iter().flatten() { for v in [lower.as_ref(), upper.as_ref(), step.as_ref()].iter().flatten() {
self.constrain(v.custom.unwrap(), self.primitives.int32, &v.location)?; self.constrain(v.custom.unwrap(), self.primitives.int32, &v.location)?;
} }
// xxx: Support TNDArray.
let list = self.unifier.add_ty(TypeEnum::TList { ty }); let list = self.unifier.add_ty(TypeEnum::TList { ty });
self.constrain(value.custom.unwrap(), list, &value.location)?; self.constrain(value.custom.unwrap(), list, &value.location)?;
Ok(list) Ok(list)
@ -1175,76 +1099,15 @@ impl<'a> Inferencer<'a> {
Ok(ty) Ok(ty)
} }
_ => { _ => {
match &*self.unifier.get_ty(value.custom.unwrap()) { if let TypeEnum::TTuple { .. } = &*self.unifier.get_ty(value.custom.unwrap())
TypeEnum::TTuple { .. } => return report_error( {
"Tuple index must be a constant (KernelInvariant is also not supported)", return report_error("Tuple index must be a constant (KernelInvariant is also not supported)", slice.location)
slice.location,
),
TypeEnum::TNDArray { ty: elem_ty, num_dims } => {
let num_idxs = match &*self.unifier.get_ty(slice.custom.unwrap()) {
TypeEnum::TTuple { ty: idx_tys } => {
for idx_ty in idx_tys.iter() {
// xxx: NumPy supports a tuple of tuples for "advanced indexing"
// of multidimensional arrays (sequence index -> subset). We
// don't support this, but could give a better error message.
self.constrain(
*idx_ty,
self.primitives.int32,
&slice.location,
)?;
}
idx_tys.len()
}
TypeEnum::TList { .. } | TypeEnum::TNDArray { .. } => {
return report_error(
concat!(
"ndarray index is list/array, but NumPy advanced (subset)",
"indexing is not supported yet"
),
slice.location,
);
}
_ => {
// xxx: Could lead to suboptimal error message, as higher-dimensional indexing is not mentioned?!
self.constrain(
slice.custom.unwrap(),
self.primitives.int32,
&slice.location,
)?;
1
}
};
if *num_dims < num_idxs {
report_error(
&format!(
"ndarray has dimension {}, but {} indices supplied",
num_dims, num_idxs
),
slice.location,
)
} else if *num_dims == num_idxs {
Ok(*elem_ty)
} else {
Ok(self.unifier.add_ty(TypeEnum::TNDArray {
ty: *elem_ty,
num_dims: *num_dims - num_idxs,
}))
}
}
_ => {
// the index is not a constant, so value can only be a list
// xxx: Or an ndarray now, so remove the constraint?
self.constrain(
slice.custom.unwrap(),
self.primitives.int32,
&slice.location,
)?;
let list = self.unifier.add_ty(TypeEnum::TList { ty });
self.constrain(value.custom.unwrap(), list, &value.location)?;
Ok(ty)
}
} }
// the index is not a constant, so value can only be a list
self.constrain(slice.custom.unwrap(), self.primitives.int32, &slice.location)?;
let list = self.unifier.add_ty(TypeEnum::TList { ty });
self.constrain(value.custom.unwrap(), list, &value.location)?;
Ok(ty)
} }
} }
} }

View File

@ -513,20 +513,6 @@ impl TestEnvironment {
[("a", "list[int32]"), ("b", "list[int32]")].iter().cloned().collect(), [("a", "list[int32]"), ("b", "list[int32]")].iter().cloned().collect(),
&[] &[]
; "listcomp test")] ; "listcomp test")]
#[test_case(
indoc! {"
a = array([1, 2])
a0 = a[0]
b = array([[1, 2], [3, 4]])
b0 = b[0]
b00 = b[0, 0]
c = 1
ac = a[c]
"},
[("a", "ndarray[int32, 1]"), ("a0", "int32"), ("b", "ndarray[int32, 2]"),
("b0", "ndarray[int32, 1]"), ("b00", "int32"), ("ac", "int32")].iter().cloned().collect(),
&[]
; "array test")]
#[test_case(indoc! {" #[test_case(indoc! {"
a = virtual(Bar(), Bar) a = virtual(Bar(), Bar)
b = a.b() b = a.b()
@ -547,7 +533,6 @@ fn test_basic(source: &str, mapping: HashMap<&str, &str>, virtuals: &[(&str, &st
let mut env = TestEnvironment::new(); let mut env = TestEnvironment::new();
let id_to_name = std::mem::take(&mut env.id_to_name); let id_to_name = std::mem::take(&mut env.id_to_name);
let mut defined_identifiers: HashSet<_> = env.identifier_mapping.keys().cloned().collect(); let mut defined_identifiers: HashSet<_> = env.identifier_mapping.keys().cloned().collect();
defined_identifiers.insert("array".into());
defined_identifiers.insert("virtual".into()); defined_identifiers.insert("virtual".into());
let mut inferencer = env.get_inferencer(); let mut inferencer = env.get_inferencer();
inferencer.defined_identifiers = defined_identifiers.clone(); inferencer.defined_identifiers = defined_identifiers.clone();

View File

@ -137,13 +137,6 @@ pub enum TypeEnum {
TList { TList {
ty: Type, ty: Type,
}, },
TNDArray {
ty: Type,
// We could introduce a more sensible limit for the number of dimensions
// and make this e.g. u8; usize for now to avoid some casts.
num_dims: usize,
},
TObj { TObj {
obj_id: DefinitionId, obj_id: DefinitionId,
fields: Mapping<StrRef, (Type, bool)>, fields: Mapping<StrRef, (Type, bool)>,
@ -163,7 +156,6 @@ impl TypeEnum {
TypeEnum::TVar { .. } => "TVar", TypeEnum::TVar { .. } => "TVar",
TypeEnum::TTuple { .. } => "TTuple", TypeEnum::TTuple { .. } => "TTuple",
TypeEnum::TList { .. } => "TList", TypeEnum::TList { .. } => "TList",
TypeEnum::TNDArray { .. } => "TNDArray",
TypeEnum::TObj { .. } => "TObj", TypeEnum::TObj { .. } => "TObj",
TypeEnum::TVirtual { .. } => "TVirtual", TypeEnum::TVirtual { .. } => "TVirtual",
TypeEnum::TCall { .. } => "TCall", TypeEnum::TCall { .. } => "TCall",
@ -181,7 +173,7 @@ pub struct Unifier {
pub(crate) calls: Vec<Rc<Call>>, pub(crate) calls: Vec<Rc<Call>>,
var_id: u32, var_id: u32,
unify_cache: HashSet<(Type, Type)>, unify_cache: HashSet<(Type, Type)>,
snapshot: Option<(usize, u32)>, snapshot: Option<(usize, u32)>
} }
impl Default for Unifier { impl Default for Unifier {
@ -395,7 +387,6 @@ impl Unifier {
TVar { .. } => allowed_typevars.iter().any(|b| self.unification_table.unioned(a, *b)), TVar { .. } => allowed_typevars.iter().any(|b| self.unification_table.unioned(a, *b)),
TCall { .. } => false, TCall { .. } => false,
TList { ty } => self.is_concrete(*ty, allowed_typevars), TList { ty } => self.is_concrete(*ty, allowed_typevars),
TNDArray { ty, .. } => self.is_concrete(*ty, allowed_typevars),
TTuple { ty } => ty.iter().all(|ty| self.is_concrete(*ty, allowed_typevars)), TTuple { ty } => ty.iter().all(|ty| self.is_concrete(*ty, allowed_typevars)),
TObj { params: vars, .. } => { TObj { params: vars, .. } => {
vars.values().all(|ty| self.is_concrete(*ty, allowed_typevars)) vars.values().all(|ty| self.is_concrete(*ty, allowed_typevars))
@ -468,10 +459,13 @@ impl Unifier {
if let Some(i) = required.iter().position(|v| v == k) { if let Some(i) = required.iter().position(|v| v == k) {
required.remove(i); required.remove(i);
} }
let i = all_names.iter().position(|v| &v.0 == k).ok_or_else(|| { let i = all_names
self.restore_snapshot(); .iter()
TypeError::new(TypeErrorKind::UnknownArgName(*k), *loc) .position(|v| &v.0 == k)
})?; .ok_or_else(|| {
self.restore_snapshot();
TypeError::new(TypeErrorKind::UnknownArgName(*k), *loc)
})?;
let (name, expected) = all_names.remove(i); let (name, expected) = all_names.remove(i);
self.unify_impl(expected, *t, false).map_err(|_| { self.unify_impl(expected, *t, false).map_err(|_| {
self.restore_snapshot(); self.restore_snapshot();
@ -658,43 +652,17 @@ impl Unifier {
self.unify_impl(x, b, false)?; self.unify_impl(x, b, false)?;
self.set_a_to_b(a, x); self.set_a_to_b(a, x);
} }
(TVar { fields: Some(fields), range, .. }, TNDArray { ty, num_dims }) => {
for (k, v) in fields.iter() {
match *k {
RecordKey::Int(_) => {
// .<n> is generated during generic scalar indexing lowering.
let indexed_ty = if *num_dims == 1 {
*ty
} else {
self.add_ty(TNDArray { ty: *ty, num_dims: *num_dims - 1 })
};
self.unify_impl(v.ty, indexed_ty, false).map_err(|e| e.at(v.loc))?
}
RecordKey::Str(_) => {
// xxx: Implement .shape here?
return Err(TypeError::new(TypeErrorKind::NoSuchField(*k, b), v.loc));
}
}
}
let x = self.check_var_compatibility(b, range)?.unwrap_or(b);
self.unify_impl(x, b, false)?;
self.set_a_to_b(a, x);
}
(TTuple { ty: ty1 }, TTuple { ty: ty2 }) => { (TTuple { ty: ty1 }, TTuple { ty: ty2 }) => {
if ty1.len() != ty2.len() { if ty1.len() != ty2.len() {
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None)); return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
} }
for (x, y) in ty1.iter().zip(ty2.iter()) { for (x, y) in ty1.iter().zip(ty2.iter()) {
if self.unify_impl(*x, *y, false).is_err() { self.unify_impl(*x, *y, false)?;
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
}
} }
self.set_a_to_b(a, b); self.set_a_to_b(a, b);
} }
(TList { ty: ty1 }, TList { ty: ty2 }) => { (TList { ty: ty1 }, TList { ty: ty2 }) => {
if self.unify_impl(*ty1, *ty2, false).is_err() { self.unify_impl(*ty1, *ty2, false)?;
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
}
self.set_a_to_b(a, b); self.set_a_to_b(a, b);
} }
(TVar { fields: Some(map), range, .. }, TObj { fields, .. }) => { (TVar { fields: Some(map), range, .. }, TObj { fields, .. }) => {
@ -775,16 +743,12 @@ impl Unifier {
self.incompatible_types(a, b)?; self.incompatible_types(a, b)?;
} }
for (x, y) in zip(params1.values(), params2.values()) { for (x, y) in zip(params1.values(), params2.values()) {
if self.unify_impl(*x, *y, false).is_err() { self.unify_impl(*x, *y, false)?;
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
};
} }
self.set_a_to_b(a, b); self.set_a_to_b(a, b);
} }
(TVirtual { ty: ty1 }, TVirtual { ty: ty2 }) => { (TVirtual { ty: ty1 }, TVirtual { ty: ty2 }) => {
if self.unify_impl(*ty1, *ty2, false).is_err() { self.unify_impl(*ty1, *ty2, false)?;
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
};
self.set_a_to_b(a, b); self.set_a_to_b(a, b);
} }
(TCall(calls1), TCall(calls2)) => { (TCall(calls1), TCall(calls2)) => {
@ -820,13 +784,9 @@ impl Unifier {
if x.name != y.name || x.default_value != y.default_value { if x.name != y.name || x.default_value != y.default_value {
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None)); return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
} }
if self.unify_impl(x.ty, y.ty, false).is_err() { self.unify_impl(x.ty, y.ty, false)?;
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
};
} }
if self.unify_impl(sign1.ret, sign2.ret, false).is_err() { self.unify_impl(sign1.ret, sign2.ret, false)?;
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
};
self.set_a_to_b(a, b); self.set_a_to_b(a, b);
} }
(TVar { fields: Some(fields), .. }, _) => { (TVar { fields: Some(fields), .. }, _) => {
@ -935,13 +895,6 @@ impl Unifier {
TypeEnum::TList { ty } => { TypeEnum::TList { ty } => {
format!("list[{}]", self.internal_stringify(*ty, obj_to_name, var_to_name, notes)) format!("list[{}]", self.internal_stringify(*ty, obj_to_name, var_to_name, notes))
} }
TypeEnum::TNDArray { ty, num_dims } => {
format!(
"ndarray[{}, {}]",
self.internal_stringify(*ty, obj_to_name, var_to_name, notes),
num_dims
)
}
TypeEnum::TVirtual { ty } => { TypeEnum::TVirtual { ty } => {
format!( format!(
"virtual[{}]", "virtual[{}]",

View File

@ -286,7 +286,7 @@ fn test_unify(
("v1", "tuple[int]"), ("v1", "tuple[int]"),
("v2", "tuple[float]"), ("v2", "tuple[float]"),
], ],
(("v1", "v2"), "Incompatible types: tuple[0] and tuple[1]") (("v1", "v2"), "Incompatible types: 0 and 1")
; "tuple parameter mismatch" ; "tuple parameter mismatch"
)] )]
#[test_case(2, #[test_case(2,
@ -478,9 +478,7 @@ fn test_typevar_range() {
let int_list = env.unifier.add_ty(TypeEnum::TList { ty: int }); let int_list = env.unifier.add_ty(TypeEnum::TList { ty: int });
assert_eq!( assert_eq!(
env.unify(a_list, int_list), env.unify(a_list, int_list),
Err("Incompatible types: list[typevar22] and list[0]\ Err("Expected any one of these types: 1, but got 0".into())
\n\nNotes:\n typevar22 {1}"
.into())
); );
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).0; let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).0;
@ -508,10 +506,7 @@ fn test_rigid_var() {
assert_eq!(env.unify(a, b), Err("Incompatible types: typevar3 and typevar2".to_string())); assert_eq!(env.unify(a, b), Err("Incompatible types: typevar3 and typevar2".to_string()));
env.unifier.unify(list_a, list_x).unwrap(); env.unifier.unify(list_a, list_x).unwrap();
assert_eq!( assert_eq!(env.unify(list_x, list_int), Err("Incompatible types: 0 and typevar2".to_string()));
env.unify(list_x, list_int),
Err("Incompatible types: list[typevar2] and list[0]".to_string())
);
env.unifier.replace_rigid_var(a, int); env.unifier.replace_rigid_var(a, int);
env.unifier.unify(list_x, list_int).unwrap(); env.unifier.unify(list_x, list_int).unwrap();

View File

@ -16,10 +16,21 @@ pub struct UnificationTable<V> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum Action<V> { enum Action<V> {
Parent { key: usize, original_parent: usize }, Parent {
Value { key: usize, original_value: Option<V> }, key: usize,
Rank { key: usize, original_rank: u32 }, original_parent: usize,
Marker { generation: u32 }, },
Value {
key: usize,
original_value: Option<V>,
},
Rank {
key: usize,
original_rank: u32,
},
Marker {
generation: u32,
}
} }
impl<V> Default for UnificationTable<V> { impl<V> Default for UnificationTable<V> {
@ -30,13 +41,7 @@ impl<V> Default for UnificationTable<V> {
impl<V> UnificationTable<V> { impl<V> UnificationTable<V> {
pub fn new() -> UnificationTable<V> { pub fn new() -> UnificationTable<V> {
UnificationTable { UnificationTable { parents: Vec::new(), ranks: Vec::new(), values: Vec::new(), log: Vec::new(), generation: 0 }
parents: Vec::new(),
ranks: Vec::new(),
values: Vec::new(),
log: Vec::new(),
generation: 0,
}
} }
pub fn new_key(&mut self, v: V) -> UnificationKey { pub fn new_key(&mut self, v: V) -> UnificationKey {
@ -120,10 +125,7 @@ impl<V> UnificationTable<V> {
pub fn restore_snapshot(&mut self, snapshot: (usize, u32)) { pub fn restore_snapshot(&mut self, snapshot: (usize, u32)) {
let (log_len, generation) = snapshot; let (log_len, generation) = snapshot;
assert!(self.log.len() >= log_len, "snapshot restoration error"); assert!(self.log.len() >= log_len, "snapshot restoration error");
assert!( assert!(matches!(self.log[log_len - 1], Action::Marker { generation: gen } if gen == generation), "snapshot restoration error");
matches!(self.log[log_len - 1], Action::Marker { generation: gen } if gen == generation),
"snapshot restoration error"
);
for action in self.log.drain(log_len - 1..).rev() { for action in self.log.drain(log_len - 1..).rev() {
match action { match action {
Action::Parent { key, original_parent } => { Action::Parent { key, original_parent } => {
@ -143,10 +145,7 @@ impl<V> UnificationTable<V> {
pub fn discard_snapshot(&mut self, snapshot: (usize, u32)) { pub fn discard_snapshot(&mut self, snapshot: (usize, u32)) {
let (log_len, generation) = snapshot; let (log_len, generation) = snapshot;
assert!(self.log.len() >= log_len, "snapshot discard error"); assert!(self.log.len() >= log_len, "snapshot discard error");
assert!( assert!(matches!(self.log[log_len - 1], Action::Marker { generation: gen } if gen == generation), "snapshot discard error");
matches!(self.log[log_len - 1], Action::Marker { generation: gen } if gen == generation),
"snapshot discard error"
);
self.log.clear(); self.log.clear();
} }
} }
@ -160,23 +159,11 @@ where
.enumerate() .enumerate()
.map(|(i, (v, p))| if *p == i { v.as_ref().map(|v| v.as_ref().clone()) } else { None }) .map(|(i, (v, p))| if *p == i { v.as_ref().map(|v| v.as_ref().clone()) } else { None })
.collect(); .collect();
UnificationTable { UnificationTable { parents: self.parents.clone(), ranks: self.ranks.clone(), values, log: Vec::new(), generation: 0 }
parents: self.parents.clone(),
ranks: self.ranks.clone(),
values,
log: Vec::new(),
generation: 0,
}
} }
pub fn from_send(table: &UnificationTable<V>) -> UnificationTable<Rc<V>> { pub fn from_send(table: &UnificationTable<V>) -> UnificationTable<Rc<V>> {
let values = table.values.iter().cloned().map(|v| v.map(Rc::new)).collect(); let values = table.values.iter().cloned().map(|v| v.map(Rc::new)).collect();
UnificationTable { UnificationTable { parents: table.parents.clone(), ranks: table.ranks.clone(), values, log: Vec::new(), generation: 0 }
parents: table.parents.clone(),
ranks: table.ranks.clone(),
values,
log: Vec::new(),
generation: 0,
}
} }
} }

View File

@ -1,15 +1,15 @@
use crate::ast::Ident;
use crate::ast::Location;
use crate::error::*;
use crate::token::Tok;
use lalrpop_util::ParseError; use lalrpop_util::ParseError;
use nac3ast::*; use nac3ast::*;
use crate::ast::Ident;
use crate::ast::Location;
use crate::token::Tok;
use crate::error::*;
pub fn make_config_comment( pub fn make_config_comment(
com_loc: Location, com_loc: Location,
stmt_loc: Location, stmt_loc: Location,
nac3com_above: Vec<(Ident, Tok)>, nac3com_above: Vec<(Ident, Tok)>,
nac3com_end: Option<Ident>, nac3com_end: Option<Ident>
) -> Result<Vec<Ident>, ParseError<Location, Tok, LexicalError>> { ) -> Result<Vec<Ident>, ParseError<Location, Tok, LexicalError>> {
if com_loc.column() != stmt_loc.column() && !nac3com_above.is_empty() { if com_loc.column() != stmt_loc.column() && !nac3com_above.is_empty() {
return Err(ParseError::User { return Err(ParseError::User {
@ -23,21 +23,18 @@ pub fn make_config_comment(
) )
) )
} }
}); })
}; };
Ok(nac3com_above Ok(
.into_iter() nac3com_above
.map(|(com, _)| com) .into_iter()
.chain(nac3com_end.map_or_else(|| vec![].into_iter(), |com| vec![com].into_iter())) .map(|(com, _)| com)
.collect()) .chain(nac3com_end.map_or_else(|| vec![].into_iter(), |com| vec![com].into_iter()))
.collect()
)
} }
pub fn handle_small_stmt<U>( pub fn handle_small_stmt<U>(stmts: &mut [Stmt<U>], nac3com_above: Vec<(Ident, Tok)>, nac3com_end: Option<Ident>, com_above_loc: Location) -> Result<(), ParseError<Location, Tok, LexicalError>> {
stmts: &mut [Stmt<U>],
nac3com_above: Vec<(Ident, Tok)>,
nac3com_end: Option<Ident>,
com_above_loc: Location,
) -> Result<(), ParseError<Location, Tok, LexicalError>> {
if com_above_loc.column() != stmts[0].location.column() && !nac3com_above.is_empty() { if com_above_loc.column() != stmts[0].location.column() && !nac3com_above.is_empty() {
return Err(ParseError::User { return Err(ParseError::User {
error: LexicalError { error: LexicalError {
@ -50,12 +47,17 @@ pub fn handle_small_stmt<U>(
) )
) )
} }
}); })
} }
apply_config_comments(&mut stmts[0], nac3com_above.into_iter().map(|(com, _)| com).collect()); apply_config_comments(
&mut stmts[0],
nac3com_above
.into_iter()
.map(|(com, _)| com).collect()
);
apply_config_comments( apply_config_comments(
stmts.last_mut().unwrap(), stmts.last_mut().unwrap(),
nac3com_end.map_or_else(Vec::new, |com| vec![com]), nac3com_end.map_or_else(Vec::new, |com| vec![com])
); );
Ok(()) Ok(())
} }
@ -70,7 +72,7 @@ fn apply_config_comments<U>(stmt: &mut Stmt<U>, comments: Vec<Ident>) {
| StmtKind::AnnAssign { config_comment, .. } | StmtKind::AnnAssign { config_comment, .. }
| StmtKind::Break { config_comment, .. } | StmtKind::Break { config_comment, .. }
| StmtKind::Continue { config_comment, .. } | StmtKind::Continue { config_comment, .. }
| StmtKind::Return { config_comment, .. } | StmtKind::Return { config_comment, .. }
| StmtKind::Raise { config_comment, .. } | StmtKind::Raise { config_comment, .. }
| StmtKind::Import { config_comment, .. } | StmtKind::Import { config_comment, .. }
| StmtKind::ImportFrom { config_comment, .. } | StmtKind::ImportFrom { config_comment, .. }
@ -78,8 +80,6 @@ fn apply_config_comments<U>(stmt: &mut Stmt<U>, comments: Vec<Ident>) {
| StmtKind::Nonlocal { config_comment, .. } | StmtKind::Nonlocal { config_comment, .. }
| StmtKind::Assert { config_comment, .. } => config_comment.extend(comments), | StmtKind::Assert { config_comment, .. } => config_comment.extend(comments),
_ => { _ => { unreachable!("only small statements should call this function") }
unreachable!("only small statements should call this function")
}
} }
} }

View File

@ -145,27 +145,35 @@ impl From<LalrpopError<Location, Tok, LexicalError>> for ParseError {
fn from(err: LalrpopError<Location, Tok, LexicalError>) -> Self { fn from(err: LalrpopError<Location, Tok, LexicalError>) -> Self {
match err { match err {
// TODO: Are there cases where this isn't an EOF? // TODO: Are there cases where this isn't an EOF?
LalrpopError::InvalidToken { location } => { LalrpopError::InvalidToken { location } => ParseError {
ParseError { error: ParseErrorType::Eof, location } error: ParseErrorType::Eof,
} location,
LalrpopError::ExtraToken { token } => { },
ParseError { error: ParseErrorType::ExtraToken(token.1), location: token.0 } LalrpopError::ExtraToken { token } => ParseError {
} error: ParseErrorType::ExtraToken(token.1),
LalrpopError::User { error } => { location: token.0,
ParseError { error: ParseErrorType::Lexical(error.error), location: error.location } },
} LalrpopError::User { error } => ParseError {
error: ParseErrorType::Lexical(error.error),
location: error.location,
},
LalrpopError::UnrecognizedToken { token, expected } => { LalrpopError::UnrecognizedToken { token, expected } => {
// Hacky, but it's how CPython does it. See PyParser_AddToken, // Hacky, but it's how CPython does it. See PyParser_AddToken,
// in particular "Only one possible expected token" comment. // in particular "Only one possible expected token" comment.
let expected = if expected.len() == 1 { Some(expected[0].clone()) } else { None }; let expected = if expected.len() == 1 {
Some(expected[0].clone())
} else {
None
};
ParseError { ParseError {
error: ParseErrorType::UnrecognizedToken(token.1, expected), error: ParseErrorType::UnrecognizedToken(token.1, expected),
location: token.0, location: token.0,
} }
} }
LalrpopError::UnrecognizedEOF { location, .. } => { LalrpopError::UnrecognizedEOF { location, .. } => ParseError {
ParseError { error: ParseErrorType::Eof, location } error: ParseErrorType::Eof,
} location,
},
} }
} }
} }

View File

@ -15,7 +15,10 @@ struct FStringParser<'a> {
impl<'a> FStringParser<'a> { impl<'a> FStringParser<'a> {
fn new(source: &'a str, str_location: Location) -> Self { fn new(source: &'a str, str_location: Location) -> Self {
Self { chars: source.chars().peekable(), str_location } Self {
chars: source.chars().peekable(),
str_location,
}
} }
#[inline] #[inline]
@ -248,11 +251,17 @@ impl<'a> FStringParser<'a> {
} }
if !content.is_empty() { if !content.is_empty() {
values.push(self.expr(ExprKind::Constant { value: content.into(), kind: None })) values.push(self.expr(ExprKind::Constant {
value: content.into(),
kind: None,
}))
} }
let s = match values.len() { let s = match values.len() {
0 => self.expr(ExprKind::Constant { value: String::new().into(), kind: None }), 0 => self.expr(ExprKind::Constant {
value: String::new().into(),
kind: None,
}),
1 => values.into_iter().next().unwrap(), 1 => values.into_iter().next().unwrap(),
_ => self.expr(ExprKind::JoinedStr { values }), _ => self.expr(ExprKind::JoinedStr { values }),
}; };
@ -268,7 +277,9 @@ fn parse_fstring_expr(source: &str) -> Result<Expr, ParseError> {
/// Parse an fstring from a string, located at a certain position in the sourcecode. /// Parse an fstring from a string, located at a certain position in the sourcecode.
/// In case of errors, we will get the location and the error returned. /// In case of errors, we will get the location and the error returned.
pub fn parse_located_fstring(source: &str, location: Location) -> Result<Expr, FStringError> { pub fn parse_located_fstring(source: &str, location: Location) -> Result<Expr, FStringError> {
FStringParser::new(source, location).parse().map_err(|error| FStringError { error, location }) FStringParser::new(source, location)
.parse()
.map_err(|error| FStringError { error, location })
} }
#[cfg(test)] #[cfg(test)]

View File

@ -69,7 +69,10 @@ pub fn parse_args(func_args: Vec<FunctionArgument>) -> Result<ArgumentList, Lexi
keywords.push(ast::Keyword::new( keywords.push(ast::Keyword::new(
location, location,
ast::KeywordData { arg: name.map(|name| name.into()), value: Box::new(value) }, ast::KeywordData {
arg: name.map(|name| name.into()),
value: Box::new(value),
},
)); ));
} }
None => { None => {

View File

@ -3,12 +3,12 @@
//! This means source code is translated into separate tokens. //! This means source code is translated into separate tokens.
pub use super::token::Tok; pub use super::token::Tok;
use crate::ast::{FileName, Location}; use crate::ast::{Location, FileName};
use crate::error::{LexicalError, LexicalErrorType}; use crate::error::{LexicalError, LexicalErrorType};
use std::char; use std::char;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::num::IntErrorKind;
use std::str::FromStr; use std::str::FromStr;
use std::num::IntErrorKind;
use unic_emoji_char::is_emoji_presentation; use unic_emoji_char::is_emoji_presentation;
use unic_ucd_ident::{is_xid_continue, is_xid_start}; use unic_ucd_ident::{is_xid_continue, is_xid_start};
@ -32,14 +32,20 @@ impl IndentationLevel {
if self.spaces <= other.spaces { if self.spaces <= other.spaces {
Ok(Ordering::Less) Ok(Ordering::Less)
} else { } else {
Err(LexicalError { location, error: LexicalErrorType::TabError }) Err(LexicalError {
location,
error: LexicalErrorType::TabError,
})
} }
} }
Ordering::Greater => { Ordering::Greater => {
if self.spaces >= other.spaces { if self.spaces >= other.spaces {
Ok(Ordering::Greater) Ok(Ordering::Greater)
} else { } else {
Err(LexicalError { location, error: LexicalErrorType::TabError }) Err(LexicalError {
location,
error: LexicalErrorType::TabError,
})
} }
} }
Ordering::Equal => Ok(self.spaces.cmp(&other.spaces)), Ordering::Equal => Ok(self.spaces.cmp(&other.spaces)),
@ -57,7 +63,7 @@ pub struct Lexer<T: Iterator<Item = char>> {
chr1: Option<char>, chr1: Option<char>,
chr2: Option<char>, chr2: Option<char>,
location: Location, location: Location,
config_comment_prefix: Option<&'static str>, config_comment_prefix: Option<&'static str>
} }
pub static KEYWORDS: phf::Map<&'static str, Tok> = phf::phf_map! { pub static KEYWORDS: phf::Map<&'static str, Tok> = phf::phf_map! {
@ -130,7 +136,11 @@ where
T: Iterator<Item = char>, T: Iterator<Item = char>,
{ {
pub fn new(source: T) -> Self { pub fn new(source: T) -> Self {
let mut nlh = NewlineHandler { source, chr0: None, chr1: None }; let mut nlh = NewlineHandler {
source,
chr0: None,
chr1: None,
};
nlh.shift(); nlh.shift();
nlh.shift(); nlh.shift();
nlh nlh
@ -185,7 +195,7 @@ where
location: start, location: start,
chr1: None, chr1: None,
chr2: None, chr2: None,
config_comment_prefix: Some(" nac3:"), config_comment_prefix: Some(" nac3:")
}; };
lxr.next_char(); lxr.next_char();
lxr.next_char(); lxr.next_char();
@ -277,15 +287,15 @@ where
let end_pos = self.get_pos(); let end_pos = self.get_pos();
let value = match i128::from_str_radix(&value_text, radix) { let value = match i128::from_str_radix(&value_text, radix) {
Ok(value) => value, Ok(value) => value,
Err(e) => match e.kind() { Err(e) => {
IntErrorKind::PosOverflow | IntErrorKind::NegOverflow => i128::MAX, match e.kind() {
_ => { IntErrorKind::PosOverflow | IntErrorKind::NegOverflow => i128::MAX,
return Err(LexicalError { _ => return Err(LexicalError {
error: LexicalErrorType::OtherError(format!("{:?}", e)), error: LexicalErrorType::OtherError(format!("{:?}", e)),
location: start_pos, location: start_pos,
}) }),
} }
}, }
}; };
Ok((start_pos, Tok::Int { value }, end_pos)) Ok((start_pos, Tok::Int { value }, end_pos))
} }
@ -328,7 +338,14 @@ where
if self.chr0 == Some('j') || self.chr0 == Some('J') { if self.chr0 == Some('j') || self.chr0 == Some('J') {
self.next_char(); self.next_char();
let end_pos = self.get_pos(); let end_pos = self.get_pos();
Ok((start_pos, Tok::Complex { real: 0.0, imag: value }, end_pos)) Ok((
start_pos,
Tok::Complex {
real: 0.0,
imag: value,
},
end_pos,
))
} else { } else {
let end_pos = self.get_pos(); let end_pos = self.get_pos();
Ok((start_pos, Tok::Float { value }, end_pos)) Ok((start_pos, Tok::Float { value }, end_pos))
@ -347,7 +364,7 @@ where
let value = value_text.parse::<i128>().ok(); let value = value_text.parse::<i128>().ok();
let nonzero = match value { let nonzero = match value {
Some(value) => value != 0i128, Some(value) => value != 0i128,
None => true, None => true
}; };
if start_is_zero && nonzero { if start_is_zero && nonzero {
return Err(LexicalError { return Err(LexicalError {
@ -416,8 +433,9 @@ where
fn lex_comment(&mut self) -> Option<Spanned> { fn lex_comment(&mut self) -> Option<Spanned> {
self.next_char(); self.next_char();
// if possibly nac3 pseudocomment, special handling for `# nac3:` // if possibly nac3 pseudocomment, special handling for `# nac3:`
let (mut prefix, mut is_comment) = let (mut prefix, mut is_comment) = self
self.config_comment_prefix.map_or_else(|| ("".chars(), false), |v| (v.chars(), true)); .config_comment_prefix
.map_or_else(|| ("".chars(), false), |v| (v.chars(), true));
// for the correct location of config comment // for the correct location of config comment
let mut start_loc = self.location; let mut start_loc = self.location;
start_loc.go_left(); start_loc.go_left();
@ -442,20 +460,22 @@ where
return Some(( return Some((
start_loc, start_loc,
Tok::ConfigComment { content: content.trim().into() }, Tok::ConfigComment { content: content.trim().into() },
self.location, self.location
)); ));
} }
} }
} }
} }
self.next_char(); self.next_char();
} };
} }
fn unicode_literal(&mut self, literal_number: usize) -> Result<char, LexicalError> { fn unicode_literal(&mut self, literal_number: usize) -> Result<char, LexicalError> {
let mut p: u32 = 0u32; let mut p: u32 = 0u32;
let unicode_error = let unicode_error = LexicalError {
LexicalError { error: LexicalErrorType::UnicodeError, location: self.get_pos() }; error: LexicalErrorType::UnicodeError,
location: self.get_pos(),
};
for i in 1..=literal_number { for i in 1..=literal_number {
match self.next_char() { match self.next_char() {
Some(c) => match c.to_digit(16) { Some(c) => match c.to_digit(16) {
@ -510,8 +530,10 @@ where
} }
} }
} }
unicode_names2::character(&name) unicode_names2::character(&name).ok_or(LexicalError {
.ok_or(LexicalError { error: LexicalErrorType::UnicodeError, location: start_pos }) error: LexicalErrorType::UnicodeError,
location: start_pos,
})
} }
fn lex_string( fn lex_string(
@ -628,9 +650,14 @@ where
let end_pos = self.get_pos(); let end_pos = self.get_pos();
let tok = if is_bytes { let tok = if is_bytes {
Tok::Bytes { value: string_content.chars().map(|c| c as u8).collect() } Tok::Bytes {
value: string_content.chars().map(|c| c as u8).collect(),
}
} else { } else {
Tok::String { value: string_content, is_fstring } Tok::String {
value: string_content,
is_fstring,
}
}; };
Ok((start_pos, tok, end_pos)) Ok((start_pos, tok, end_pos))
@ -815,7 +842,11 @@ where
let tok_start = self.get_pos(); let tok_start = self.get_pos();
self.next_char(); self.next_char();
let tok_end = self.get_pos(); let tok_end = self.get_pos();
self.emit((tok_start, Tok::Name { name: c.to_string().into() }, tok_end)); self.emit((
tok_start,
Tok::Name { name: c.to_string().into() },
tok_end,
));
} else { } else {
self.consume_character(c)?; self.consume_character(c)?;
} }
@ -1408,8 +1439,14 @@ class Foo(A, B):
assert_eq!( assert_eq!(
tokens, tokens,
vec![ vec![
Tok::String { value: "\\\\".to_owned(), is_fstring: false }, Tok::String {
Tok::String { value: "\\".to_owned(), is_fstring: false }, value: "\\\\".to_owned(),
is_fstring: false,
},
Tok::String {
value: "\\".to_owned(),
is_fstring: false,
},
Tok::Newline, Tok::Newline,
] ]
); );
@ -1422,13 +1459,27 @@ class Foo(A, B):
assert_eq!( assert_eq!(
tokens, tokens,
vec![ vec![
Tok::Int { value: 47i128 }, Tok::Int {
Tok::Int { value: 13i128 }, value: 47i128,
Tok::Int { value: 0i128 }, },
Tok::Int { value: 123i128 }, Tok::Int {
value: 13i128,
},
Tok::Int {
value: 0i128,
},
Tok::Int {
value: 123i128,
},
Tok::Float { value: 0.2 }, Tok::Float { value: 0.2 },
Tok::Complex { real: 0.0, imag: 2.0 }, Tok::Complex {
Tok::Complex { real: 0.0, imag: 2.2 }, real: 0.0,
imag: 2.0,
},
Tok::Complex {
real: 0.0,
imag: 2.2,
},
Tok::Newline, Tok::Newline,
] ]
); );
@ -1488,13 +1539,21 @@ class Foo(A, B):
assert_eq!( assert_eq!(
tokens, tokens,
vec![ vec![
Tok::Name { name: String::from("avariable").into() }, Tok::Name {
name: String::from("avariable").into(),
},
Tok::Equal, Tok::Equal,
Tok::Int { value: 99i128 }, Tok::Int {
value: 99i128
},
Tok::Plus, Tok::Plus,
Tok::Int { value: 2i128 }, Tok::Int {
value: 2i128
},
Tok::Minus, Tok::Minus,
Tok::Int { value: 0i128 }, Tok::Int {
value: 0i128
},
Tok::Newline, Tok::Newline,
] ]
); );
@ -1681,15 +1740,42 @@ class Foo(A, B):
assert_eq!( assert_eq!(
tokens, tokens,
vec![ vec![
Tok::String { value: String::from("double"), is_fstring: false }, Tok::String {
Tok::String { value: String::from("single"), is_fstring: false }, value: String::from("double"),
Tok::String { value: String::from("can't"), is_fstring: false }, is_fstring: false,
Tok::String { value: String::from("\\\""), is_fstring: false }, },
Tok::String { value: String::from("\t\r\n"), is_fstring: false }, Tok::String {
Tok::String { value: String::from("\\g"), is_fstring: false }, value: String::from("single"),
Tok::String { value: String::from("raw\\'"), is_fstring: false }, is_fstring: false,
Tok::String { value: String::from("Đ"), is_fstring: false }, },
Tok::String { value: String::from("\u{80}\u{0}a"), is_fstring: false }, Tok::String {
value: String::from("can't"),
is_fstring: false,
},
Tok::String {
value: String::from("\\\""),
is_fstring: false,
},
Tok::String {
value: String::from("\t\r\n"),
is_fstring: false,
},
Tok::String {
value: String::from("\\g"),
is_fstring: false,
},
Tok::String {
value: String::from("raw\\'"),
is_fstring: false,
},
Tok::String {
value: String::from("Đ"),
is_fstring: false,
},
Tok::String {
value: String::from("\u{80}\u{0}a"),
is_fstring: false,
},
Tok::Newline, Tok::Newline,
] ]
); );
@ -1754,17 +1840,41 @@ class Foo(A, B):
fn test_raw_byte_literal() { fn test_raw_byte_literal() {
let source = r"rb'\x1z'"; let source = r"rb'\x1z'";
let tokens = lex_source(source); let tokens = lex_source(source);
assert_eq!(tokens, vec![Tok::Bytes { value: b"\\x1z".to_vec() }, Tok::Newline]); assert_eq!(
tokens,
vec![
Tok::Bytes {
value: b"\\x1z".to_vec()
},
Tok::Newline
]
);
let source = r"rb'\\'"; let source = r"rb'\\'";
let tokens = lex_source(source); let tokens = lex_source(source);
assert_eq!(tokens, vec![Tok::Bytes { value: b"\\\\".to_vec() }, Tok::Newline]) assert_eq!(
tokens,
vec![
Tok::Bytes {
value: b"\\\\".to_vec()
},
Tok::Newline
]
)
} }
#[test] #[test]
fn test_escape_octet() { fn test_escape_octet() {
let source = r##"b'\43a\4\1234'"##; let source = r##"b'\43a\4\1234'"##;
let tokens = lex_source(source); let tokens = lex_source(source);
assert_eq!(tokens, vec![Tok::Bytes { value: b"#a\x04S4".to_vec() }, Tok::Newline]) assert_eq!(
tokens,
vec![
Tok::Bytes {
value: b"#a\x04S4".to_vec()
},
Tok::Newline
]
)
} }
#[test] #[test]
@ -1773,7 +1883,13 @@ class Foo(A, B):
let tokens = lex_source(source); let tokens = lex_source(source);
assert_eq!( assert_eq!(
tokens, tokens,
vec![Tok::String { value: "\u{2002}".to_owned(), is_fstring: false }, Tok::Newline] vec![
Tok::String {
value: "\u{2002}".to_owned(),
is_fstring: false,
},
Tok::Newline
]
) )
} }
} }

View File

@ -31,5 +31,5 @@ lalrpop_mod!(
#[allow(unused)] #[allow(unused)]
python python
); );
pub mod config_comment_helper;
pub mod token; pub mod token;
pub mod config_comment_helper;

View File

@ -75,7 +75,9 @@ pub fn parse(source: &str, mode: Mode, file: FileName) -> Result<ast::Mod, Parse
let marker_token = (Default::default(), mode.to_marker(), Default::default()); let marker_token = (Default::default(), mode.to_marker(), Default::default());
let tokenizer = iter::once(Ok(marker_token)).chain(lxr); let tokenizer = iter::once(Ok(marker_token)).chain(lxr);
python::TopParser::new().parse(tokenizer).map_err(ParseError::from) python::TopParser::new()
.parse(tokenizer)
.map_err(ParseError::from)
} }
#[cfg(test)] #[cfg(test)]
@ -161,7 +163,7 @@ class Foo(A, B):
let parse_ast = parse_expression(&source).unwrap(); let parse_ast = parse_expression(&source).unwrap();
insta::assert_debug_snapshot!(parse_ast); insta::assert_debug_snapshot!(parse_ast);
} }
#[test] #[test]
fn test_more_comment() { fn test_more_comment() {
let source = "\ let source = "\
@ -183,7 +185,7 @@ while i < 2: # nac3: 4
3"; 3";
insta::assert_debug_snapshot!(parse_program(source, Default::default()).unwrap()); insta::assert_debug_snapshot!(parse_program(source, Default::default()).unwrap());
} }
#[test] #[test]
fn test_sample_comment() { fn test_sample_comment() {
let source = "\ let source = "\

View File

@ -1,7 +1,7 @@
//! Different token definitions. //! Different token definitions.
//! Loosely based on token.h from CPython source: //! Loosely based on token.h from CPython source:
use crate::ast;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use crate::ast;
/// Python source code can be tokenized in a sequence of these tokens. /// Python source code can be tokenized in a sequence of these tokens.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -111,16 +111,8 @@ impl fmt::Display for Tok {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Tok::*; use Tok::*;
match self { match self {
Name { name } => { Name { name } => write!(f, "'{}'", ast::get_str_from_ref(&ast::get_str_ref_lock(), *name)),
write!(f, "'{}'", ast::get_str_from_ref(&ast::get_str_ref_lock(), *name)) Int { value } => if *value != i128::MAX { write!(f, "'{}'", value) } else { write!(f, "'#OFL#'") },
}
Int { value } => {
if *value != i128::MAX {
write!(f, "'{}'", value)
} else {
write!(f, "'#OFL#'")
}
}
Float { value } => write!(f, "'{}'", value), Float { value } => write!(f, "'{}'", value),
Complex { real, imag } => write!(f, "{}j{}", real, imag), Complex { real, imag } => write!(f, "{}j{}", real, imag),
String { value, is_fstring } => { String { value, is_fstring } => {
@ -142,11 +134,7 @@ impl fmt::Display for Tok {
} }
f.write_str("\"") f.write_str("\"")
} }
ConfigComment { content } => write!( ConfigComment { content } => write!(f, "ConfigComment: '{}'", ast::get_str_from_ref(&ast::get_str_ref_lock(), *content)),
f,
"ConfigComment: '{}'",
ast::get_str_from_ref(&ast::get_str_ref_lock(), *content)
),
Newline => f.write_str("Newline"), Newline => f.write_str("Newline"),
Indent => f.write_str("Indent"), Indent => f.write_str("Indent"),
Dedent => f.write_str("Dedent"), Dedent => f.write_str("Dedent"),

View File

@ -10,7 +10,6 @@ nac3parser = { path = "../nac3parser" }
nac3core = { path = "../nac3core" } nac3core = { path = "../nac3core" }
[dependencies.inkwell] [dependencies.inkwell]
git = "https://github.com/nbaksalyar/inkwell.git" version = "0.1.0-beta.4"
branch = "llvm14"
default-features = false default-features = false
features = ["llvm14-0", "target-aarch64", "target-arm", "target-riscv", "no-libffi-linking"] features = ["llvm13-0", "target-x86", "target-arm", "target-riscv", "no-libffi-linking"]

View File

@ -1,257 +0,0 @@
from __future__ import annotations
@extern
def output_int32(x: int32):
...
@extern
def output_uint32(x: uint32):
...
@extern
def output_int64(x: int64):
...
@extern
def output_uint64(x: uint64):
...
@extern
def output_float64(x: float):
...
def run() -> int32:
test_int32()
test_uint32()
test_int64()
test_uint64()
test_A()
test_B()
return 0
def test_int32():
a = 17
b = 3
output_int32(a + b)
output_int32(a - b)
output_int32(a * b)
output_int32(a // b)
output_int32(a % b)
output_int32(a | b)
output_int32(a ^ b)
output_int32(a & b)
output_int32(a << b)
output_int32(a >> b)
output_float64(a / b)
a += b
output_int32(a)
a -= b
output_int32(a)
a *= b
output_int32(a)
a //= b
output_int32(a)
a %= b
output_int32(a)
a |= b
output_int32(a)
a ^= b
output_int32(a)
a &= b
output_int32(a)
a <<= b
output_int32(a)
a >>= b
output_int32(a)
# fail because (a / b) is float
# a /= b
def test_uint32():
a = uint32(17)
b = uint32(3)
output_uint32(a + b)
output_uint32(a - b)
output_uint32(a * b)
output_uint32(a // b)
output_uint32(a % b)
output_uint32(a | b)
output_uint32(a ^ b)
output_uint32(a & b)
output_uint32(a << b)
output_uint32(a >> b)
output_float64(a / b)
a += b
output_uint32(a)
a -= b
output_uint32(a)
a *= b
output_uint32(a)
a //= b
output_uint32(a)
a %= b
output_uint32(a)
a |= b
output_uint32(a)
a ^= b
output_uint32(a)
a &= b
output_uint32(a)
a <<= b
output_uint32(a)
a >>= b
output_uint32(a)
def test_int64():
a = int64(17)
b = int64(3)
output_int64(a + b)
output_int64(a - b)
output_int64(a * b)
output_int64(a // b)
output_int64(a % b)
output_int64(a | b)
output_int64(a ^ b)
output_int64(a & b)
output_int64(a << b)
output_int64(a >> b)
output_float64(a / b)
a += b
output_int64(a)
a -= b
output_int64(a)
a *= b
output_int64(a)
a //= b
output_int64(a)
a %= b
output_int64(a)
a |= b
output_int64(a)
a ^= b
output_int64(a)
a &= b
output_int64(a)
a <<= b
output_int64(a)
a >>= b
output_int64(a)
def test_uint64():
a = uint64(17)
b = uint64(3)
output_uint64(a + b)
output_uint64(a - b)
output_uint64(a * b)
output_uint64(a // b)
output_uint64(a % b)
output_uint64(a | b)
output_uint64(a ^ b)
output_uint64(a & b)
output_uint64(a << b)
output_uint64(a >> b)
output_float64(a / b)
a += b
output_uint64(a)
a -= b
output_uint64(a)
a *= b
output_uint64(a)
a //= b
output_uint64(a)
a %= b
output_uint64(a)
a |= b
output_uint64(a)
a ^= b
output_uint64(a)
a &= b
output_uint64(a)
a <<= b
output_uint64(a)
a >>= b
output_uint64(a)
class A:
a: int32
def __init__(self, a: int32):
self.a = a
def __add__(self, other: A) -> A:
output_int32(self.a + other.a)
return A(self.a + other.a)
def __sub__(self, other: A) -> A:
output_int32(self.a - other.a)
return A(self.a - other.a)
def test_A():
a = A(17)
b = A(3)
c = a + b
# fail due to alloca in __add__ function
# output_int32(c.a)
a += b
# fail due to alloca in __add__ function
# output_int32(a.a)
a = A(17)
b = A(3)
d = a - b
# fail due to alloca in __add__ function
# output_int32(c.a)
a -= b
# fail due to alloca in __add__ function
# output_int32(a.a)
a = A(17)
b = A(3)
a.__add__(b)
a.__sub__(b)
class B:
a: int32
def __init__(self, a: int32):
self.a = a
def __add__(self, other: B) -> B:
output_int32(self.a + other.a)
return B(self.a + other.a)
def __sub__(self, other: B) -> B:
output_int32(self.a - other.a)
return B(self.a - other.a)
def __iadd__(self, other: B) -> B:
output_int32(self.a + other.a + 24)
return B(self.a + other.a + 24)
def __isub__(self, other: B) -> B:
output_int32(self.a - other.a - 24)
return B(self.a - other.a - 24)
def test_B():
a = B(17)
b = B(3)
c = a + b
# fail due to alloca in __add__ function
# output_int32(c.a)
a += b
# fail due to alloca in __add__ function
# output_int32(a.a)
a = B(17)
b = B(3)
d = a - b
# fail due to alloca in __add__ function
# output_int32(c.a)
a -= b
# fail due to alloca in __add__ function
# output_int32(a.a)
a = B(17)
b = B(3)
a.__add__(b)
a.__sub__(b)

View File

@ -30,119 +30,6 @@ use nac3parser::{
mod basic_symbol_resolver; mod basic_symbol_resolver;
use basic_symbol_resolver::*; use basic_symbol_resolver::*;
fn handle_typevar_definition(
var: &Expr,
resolver: &(dyn SymbolResolver + Send + Sync),
def_list: &[Arc<RwLock<TopLevelDef>>],
unifier: &mut Unifier,
primitives: &PrimitiveStore,
) -> Result<Type, String> {
if let ExprKind::Call { func, args, .. } = &var.node {
if matches!(&func.node, ExprKind::Name { id, .. } if id == &"TypeVar".into()) {
let constraints = args
.iter()
.skip(1)
.map(|x| -> Result<Type, String> {
let ty = parse_ast_to_type_annotation_kinds(
resolver,
def_list,
unifier,
primitives,
x,
Default::default(),
)?;
get_type_from_type_annotation_kinds(
def_list, unifier, primitives, &ty, &mut None,
)
})
.collect::<Result<Vec<_>, _>>()?;
Ok(unifier.get_fresh_var_with_range(&constraints, None, None).0)
} else {
Err(format!("expression {:?} cannot be handled as a TypeVar in global scope", var))
}
} else {
Err(format!("expression {:?} cannot be handled as a TypeVar in global scope", var))
}
}
fn handle_assignment_pattern(
targets: &[Expr],
value: &Expr,
resolver: &(dyn SymbolResolver + Send + Sync),
internal_resolver: &ResolverInternal,
def_list: &[Arc<RwLock<TopLevelDef>>],
unifier: &mut Unifier,
primitives: &PrimitiveStore,
) -> Result<(), String> {
if targets.len() == 1 {
match &targets[0].node {
ExprKind::Name { id, .. } => {
if let Ok(var) = handle_typevar_definition(
value.borrow(),
resolver,
def_list,
unifier,
primitives,
) {
internal_resolver.add_id_type(*id, var);
Ok(())
} else if let Ok(val) = parse_parameter_default_value(value.borrow(), resolver) {
internal_resolver.add_module_global(*id, val);
Ok(())
} else {
Err(format!(
"fails to evaluate this expression `{:?}` as a constant or TypeVar at {}",
targets[0].node, targets[0].location,
))
}
}
ExprKind::List { elts, .. } | ExprKind::Tuple { elts, .. } => {
handle_assignment_pattern(
elts,
value,
resolver,
internal_resolver,
def_list,
unifier,
primitives,
)?;
Ok(())
}
_ => Err(format!(
"assignment to {:?} is not supported at {}",
targets[0], targets[0].location
)),
}
} else {
match &value.node {
ExprKind::List { elts, .. } | ExprKind::Tuple { elts, .. } => {
if elts.len() != targets.len() {
Err(format!(
"number of elements to unpack does not match (expect {}, found {}) at {}",
targets.len(),
elts.len(),
value.location
))
} else {
for (tar, val) in targets.iter().zip(elts) {
handle_assignment_pattern(
std::slice::from_ref(tar),
val,
resolver,
internal_resolver,
def_list,
unifier,
primitives,
)?;
}
Ok(())
}
}
_ => Err(format!("unpack of this expression is not supported at {}", value.location)),
}
}
}
fn main() { fn main() {
let file_name = env::args().nth(1).unwrap(); let file_name = env::args().nth(1).unwrap();
let threads: u32 = env::args().nth(2).map(|s| str::parse(&s).unwrap()).unwrap_or(1); let threads: u32 = env::args().nth(2).map(|s| str::parse(&s).unwrap()).unwrap_or(1);
@ -175,41 +62,155 @@ fn main() {
let parser_result = parser::parse_program(&program, file_name.into()).unwrap(); let parser_result = parser::parse_program(&program, file_name.into()).unwrap();
for stmt in parser_result.into_iter() { for stmt in parser_result.into_iter() {
match &stmt.node { if let StmtKind::Assign { targets, value, .. } = &stmt.node {
StmtKind::Assign { targets, value, .. } => { fn handle_typevar_definition(
let def_list = composer.extract_def_list(); var: &Expr,
let unifier = &mut composer.unifier; resolver: &(dyn SymbolResolver + Send + Sync),
let primitives = &composer.primitives_ty; def_list: &[Arc<RwLock<TopLevelDef>>],
if let Err(err) = handle_assignment_pattern( unifier: &mut Unifier,
targets, primitives: &PrimitiveStore,
value, ) -> Result<Type, String> {
resolver.as_ref(), if let ExprKind::Call { func, args, .. } = &var.node {
internal_resolver.as_ref(), if matches!(&func.node, ExprKind::Name { id, .. } if id == &"TypeVar".into()) {
&def_list, let constraints = args
unifier, .iter()
primitives, .skip(1)
) { .map(|x| -> Result<Type, String> {
eprintln!("{}", err); let ty = parse_ast_to_type_annotation_kinds(
return; resolver,
def_list,
unifier,
primitives,
x,
Default::default(),
)?;
get_type_from_type_annotation_kinds(
def_list, unifier, primitives, &ty, &mut None
)
})
.collect::<Result<Vec<_>, _>>()?;
Ok(unifier.get_fresh_var_with_range(&constraints, None, None).0)
} else {
Err(format!(
"expression {:?} cannot be handled as a TypeVar in global scope",
var
))
}
} else {
Err(format!(
"expression {:?} cannot be handled as a TypeVar in global scope",
var
))
} }
} }
// allow (and ignore) "from __future__ import annotations"
StmtKind::ImportFrom { module, names, .. } fn handle_assignment_pattern(
if module == &Some("__future__".into()) targets: &[Expr],
&& names.len() == 1 value: &Expr,
&& names[0].name == "annotations".into() => resolver: &(dyn SymbolResolver + Send + Sync),
{ internal_resolver: &ResolverInternal,
() def_list: &[Arc<RwLock<TopLevelDef>>],
} unifier: &mut Unifier,
_ => { primitives: &PrimitiveStore,
let (name, def_id, ty) = composer ) -> Result<(), String> {
.register_top_level(stmt, Some(resolver.clone()), "__main__".into()) if targets.len() == 1 {
.unwrap(); match &targets[0].node {
internal_resolver.add_id_def(name, def_id); ExprKind::Name { id, .. } => {
if let Some(ty) = ty { if let Ok(var) = handle_typevar_definition(
internal_resolver.add_id_type(name, ty); value.borrow(),
resolver,
def_list,
unifier,
primitives,
) {
internal_resolver.add_id_type(*id, var);
Ok(())
} else if let Ok(val) =
parse_parameter_default_value(value.borrow(), resolver)
{
internal_resolver.add_module_global(*id, val);
Ok(())
} else {
Err(format!("fails to evaluate this expression `{:?}` as a constant or TypeVar at {}",
targets[0].node,
targets[0].location,
))
}
}
ExprKind::List { elts, .. } | ExprKind::Tuple { elts, .. } => {
handle_assignment_pattern(
elts,
value,
resolver,
internal_resolver,
def_list,
unifier,
primitives,
)?;
Ok(())
}
_ => Err(format!(
"assignment to {:?} is not supported at {}",
targets[0], targets[0].location
)),
}
} else {
match &value.node {
ExprKind::List { elts, .. } | ExprKind::Tuple { elts, .. } => {
if elts.len() != targets.len() {
Err(format!(
"number of elements to unpack does not match (expect {}, found {}) at {}",
targets.len(),
elts.len(),
value.location
))
} else {
for (tar, val) in targets.iter().zip(elts) {
handle_assignment_pattern(
std::slice::from_ref(tar),
val,
resolver,
internal_resolver,
def_list,
unifier,
primitives,
)?;
}
Ok(())
}
}
_ => Err(format!(
"unpack of this expression is not supported at {}",
value.location
)),
}
} }
} }
let def_list = composer.extract_def_list();
let unifier = &mut composer.unifier;
let primitives = &composer.primitives_ty;
if let Err(err) = handle_assignment_pattern(
targets,
value,
resolver.as_ref(),
internal_resolver.as_ref(),
&def_list,
unifier,
primitives,
) {
eprintln!("{}", err);
return;
}
continue;
}
let (name, def_id, ty) =
composer.register_top_level(stmt, Some(resolver.clone()), "__main__".into()).unwrap();
internal_resolver.add_id_def(name, def_id);
if let Some(ty) = ty {
internal_resolver.add_id_type(name, ty);
} }
} }

View File

@ -8,6 +8,7 @@
, ncurses , ncurses
, zlib , zlib
, which , which
, llvmPackages_13
, debugVersion ? false , debugVersion ? false
, enableManpages ? false , enableManpages ? false
, enableSharedLibraries ? false , enableSharedLibraries ? false
@ -17,7 +18,7 @@
let let
inherit (lib) optional optionals optionalString; inherit (lib) optional optionals optionalString;
release_version = "14.0.1"; release_version = "13.0.1";
candidate = ""; # empty or "rcN" candidate = ""; # empty or "rcN"
dash-candidate = lib.optionalString (candidate != "") "-${candidate}"; dash-candidate = lib.optionalString (candidate != "") "-${candidate}";
version = "${release_version}${dash-candidate}"; # differentiating these (variables) is important for RCs version = "${release_version}${dash-candidate}"; # differentiating these (variables) is important for RCs
@ -34,7 +35,7 @@ in stdenv.mkDerivation (rec {
pname = "llvm"; pname = "llvm";
inherit version; inherit version;
src = fetch pname "sha256-W4kBfewnKTEasUNALwPaHeptDHndXHAbyTnPizTwHsI="; src = fetch pname "sha256-7GuA2Cw4SsrS3BkpA6bPLNuv+4ibhL+5janXHmMPyDQ=";
unpackPhase = '' unpackPhase = ''
unpackFile $src unpackFile $src
@ -49,12 +50,19 @@ in stdenv.mkDerivation (rec {
buildInputs = [ ]; buildInputs = [ ];
propagatedBuildInputs = [ ncurses zlib ]; propagatedBuildInputs = optionals (stdenv.buildPlatform == stdenv.hostPlatform) [ ncurses ]
++ [ zlib ];
checkInputs = [ which ]; checkInputs = [ which ];
patches = [ patches = [
./gnu-install-dirs.patch ./gnu-install-dirs.patch
# Fix random compiler crashes: https://bugs.llvm.org/show_bug.cgi?id=50611
(fetchpatch {
url = "https://raw.githubusercontent.com/archlinux/svntogit-packages/4764a4f8c920912a2bfd8b0eea57273acfe0d8a8/trunk/no-strict-aliasing-DwarfCompileUnit.patch";
sha256 = "18l6mrvm2vmwm77ckcnbjvh6ybvn72rhrb799d4qzwac4x2ifl7g";
stripLen = 1;
})
./llvm-future-riscv-abi.diff ./llvm-future-riscv-abi.diff
]; ];
@ -113,9 +121,7 @@ in stdenv.mkDerivation (rec {
"-DLLVM_DEFAULT_TARGET_TRIPLE=${stdenv.hostPlatform.config}" "-DLLVM_DEFAULT_TARGET_TRIPLE=${stdenv.hostPlatform.config}"
"-DLLVM_ENABLE_UNWIND_TABLES=OFF" "-DLLVM_ENABLE_UNWIND_TABLES=OFF"
"-DLLVM_ENABLE_THREADS=OFF" "-DLLVM_ENABLE_THREADS=OFF"
"-DLLVM_INCLUDE_BENCHMARKS=OFF" "-DLLVM_TARGETS_TO_BUILD=X86;ARM;RISCV"
"-DLLVM_BUILD_TOOLS=OFF"
"-DLLVM_TARGETS_TO_BUILD=host;ARM;RISCV"
] ++ optionals enableSharedLibraries [ ] ++ optionals enableSharedLibraries [
"-DLLVM_LINK_LLVM_DYLIB=ON" "-DLLVM_LINK_LLVM_DYLIB=ON"
] ++ optionals enableManpages [ ] ++ optionals enableManpages [
@ -131,6 +137,7 @@ in stdenv.mkDerivation (rec {
"-DCAN_TARGET_i386=false" "-DCAN_TARGET_i386=false"
] ++ optionals (stdenv.hostPlatform != stdenv.buildPlatform) [ ] ++ optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
"-DCMAKE_CROSSCOMPILING=True" "-DCMAKE_CROSSCOMPILING=True"
"-DLLVM_TABLEGEN=${llvmPackages_13.tools.llvm}/bin/llvm-tblgen"
( (
let let
nativeCC = pkgsBuildBuild.targetPackages.stdenv.cc; nativeCC = pkgsBuildBuild.targetPackages.stdenv.cc;
@ -147,7 +154,6 @@ in stdenv.mkDerivation (rec {
] ++ extraCmakeFlags; ] ++ extraCmakeFlags;
postBuild = '' postBuild = ''
make llvm-config
rm -fR $out rm -fR $out
''; '';
@ -156,7 +162,6 @@ in stdenv.mkDerivation (rec {
''; '';
postInstall = '' postInstall = ''
cp bin/llvm-config $out/bin
mkdir -p $python/share mkdir -p $python/share
mv $out/share/opt-viewer $python/share/opt-viewer mv $out/share/opt-viewer $python/share/opt-viewer
moveToOutput "bin/llvm-config*" "$dev" moveToOutput "bin/llvm-config*" "$dev"

View File

@ -1,10 +1,23 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt
index fec956091cd5..5a766f5c5d7c 100644 index 135036f509d2..265c36f8211b 100644
--- a/CMakeLists.txt --- a/CMakeLists.txt
+++ b/CMakeLists.txt +++ b/CMakeLists.txt
@@ -303,6 +303,9 @@ set(LLVM_EXAMPLES_INSTALL_DIR "examples" CACHE STRING @@ -270,15 +270,21 @@ if (CMAKE_BUILD_TYPE AND
"Path for examples subdirectory (enabled by LLVM_BUILD_EXAMPLES=ON) (defaults to 'examples')") message(FATAL_ERROR "Invalid value for CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
mark_as_advanced(LLVM_EXAMPLES_INSTALL_DIR) endif()
+include(GNUInstallDirs)
+
set(LLVM_LIBDIR_SUFFIX "" CACHE STRING "Define suffix of library directory name (32/64)" )
-set(LLVM_TOOLS_INSTALL_DIR "bin" CACHE STRING "Path for binary subdirectory (defaults to 'bin')")
+set(LLVM_TOOLS_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}" CACHE STRING
+ "Path for binary subdirectory (defaults to 'bin')")
mark_as_advanced(LLVM_TOOLS_INSTALL_DIR)
set(LLVM_UTILS_INSTALL_DIR "${LLVM_TOOLS_INSTALL_DIR}" CACHE STRING
"Path to install LLVM utilities (enabled by LLVM_INSTALL_UTILS=ON) (defaults to LLVM_TOOLS_INSTALL_DIR)")
mark_as_advanced(LLVM_UTILS_INSTALL_DIR)
+set(LLVM_INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}/cmake/llvm" CACHE STRING +set(LLVM_INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}/cmake/llvm" CACHE STRING
+ "Path for CMake subdirectory (defaults to lib/cmake/llvm)" ) + "Path for CMake subdirectory (defaults to lib/cmake/llvm)" )
@ -12,22 +25,70 @@ index fec956091cd5..5a766f5c5d7c 100644
# They are used as destination of target generators. # They are used as destination of target generators.
set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin) set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin)
set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
@@ -581,9 +587,9 @@ option (LLVM_ENABLE_SPHINX "Use Sphinx to generate llvm documentation." OFF)
option (LLVM_ENABLE_OCAMLDOC "Build OCaml bindings documentation." ON)
option (LLVM_ENABLE_BINDINGS "Build bindings." ON)
-set(LLVM_INSTALL_DOXYGEN_HTML_DIR "share/doc/llvm/doxygen-html"
+set(LLVM_INSTALL_DOXYGEN_HTML_DIR "${CMAKE_INSTALL_DOCDIR}/${project}/doxygen-html"
CACHE STRING "Doxygen-generated HTML documentation install directory")
-set(LLVM_INSTALL_OCAMLDOC_HTML_DIR "share/doc/llvm/ocaml-html"
+set(LLVM_INSTALL_OCAMLDOC_HTML_DIR "${CMAKE_INSTALL_DOCDIR}/${project}/ocaml-html"
CACHE STRING "OCamldoc-generated HTML documentation install directory")
option (LLVM_BUILD_EXTERNAL_COMPILER_RT
@@ -1048,7 +1054,7 @@ endif()
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
install(DIRECTORY include/llvm include/llvm-c
- DESTINATION include
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
COMPONENT llvm-headers
FILES_MATCHING
PATTERN "*.def"
@@ -1059,7 +1065,7 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
)
install(DIRECTORY ${LLVM_INCLUDE_DIR}/llvm ${LLVM_INCLUDE_DIR}/llvm-c
- DESTINATION include
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
COMPONENT llvm-headers
FILES_MATCHING
PATTERN "*.def"
@@ -1073,13 +1079,13 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
if (LLVM_INSTALL_MODULEMAPS)
install(DIRECTORY include/llvm include/llvm-c
- DESTINATION include
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
COMPONENT llvm-headers
FILES_MATCHING
PATTERN "module.modulemap"
)
install(FILES include/llvm/module.install.modulemap
- DESTINATION include/llvm
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/llvm
COMPONENT llvm-headers
RENAME "module.extern.modulemap"
)
diff --git a/cmake/modules/AddLLVM.cmake b/cmake/modules/AddLLVM.cmake diff --git a/cmake/modules/AddLLVM.cmake b/cmake/modules/AddLLVM.cmake
index fed1fec7d72e..4baed19b9e98 100644 index 9c2b85374307..5531ceeb2eeb 100644
--- a/cmake/modules/AddLLVM.cmake --- a/cmake/modules/AddLLVM.cmake
+++ b/cmake/modules/AddLLVM.cmake +++ b/cmake/modules/AddLLVM.cmake
@@ -838,8 +838,8 @@ macro(add_llvm_library name) @@ -818,9 +818,9 @@ macro(add_llvm_library name)
get_target_export_arg(${name} LLVM export_to_llvmexports ${umbrella}) get_target_export_arg(${name} LLVM export_to_llvmexports ${umbrella})
install(TARGETS ${name} install(TARGETS ${name}
${export_to_llvmexports} ${export_to_llvmexports}
- LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT ${name} - LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT ${name}
- ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT ${name} - ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT ${name}
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}" COMPONENT ${name} - RUNTIME DESTINATION bin COMPONENT ${name})
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}" COMPONENT ${name} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX} COMPONENT ${name}
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT ${name}) + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX} COMPONENT ${name}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${name})
if (NOT LLVM_ENABLE_IDE) if (NOT LLVM_ENABLE_IDE)
@@ -1056,7 +1056,7 @@ function(process_llvm_pass_plugins) add_llvm_install_targets(install-${name}
@@ -1036,7 +1036,7 @@ function(process_llvm_pass_plugins)
"set(LLVM_STATIC_EXTENSIONS ${LLVM_STATIC_EXTENSIONS})") "set(LLVM_STATIC_EXTENSIONS ${LLVM_STATIC_EXTENSIONS})")
install(FILES install(FILES
${llvm_cmake_builddir}/LLVMConfigExtensions.cmake ${llvm_cmake_builddir}/LLVMConfigExtensions.cmake
@ -36,7 +97,16 @@ index fed1fec7d72e..4baed19b9e98 100644
COMPONENT cmake-exports) COMPONENT cmake-exports)
set(ExtensionDef "${LLVM_BINARY_DIR}/include/llvm/Support/Extension.def") set(ExtensionDef "${LLVM_BINARY_DIR}/include/llvm/Support/Extension.def")
@@ -1902,7 +1902,7 @@ function(llvm_install_library_symlink name dest type) @@ -1250,7 +1250,7 @@ macro(add_llvm_example name)
endif()
add_llvm_executable(${name} ${ARGN})
if( LLVM_BUILD_EXAMPLES )
- install(TARGETS ${name} RUNTIME DESTINATION examples)
+ install(TARGETS ${name} RUNTIME DESTINATION ${CMAKE_INSTALL_DOCDIR}/examples)
endif()
set_target_properties(${name} PROPERTIES FOLDER "Examples")
endmacro(add_llvm_example name)
@@ -1868,7 +1868,7 @@ function(llvm_install_library_symlink name dest type)
set(full_name ${CMAKE_${type}_LIBRARY_PREFIX}${name}${CMAKE_${type}_LIBRARY_SUFFIX}) set(full_name ${CMAKE_${type}_LIBRARY_PREFIX}${name}${CMAKE_${type}_LIBRARY_SUFFIX})
set(full_dest ${CMAKE_${type}_LIBRARY_PREFIX}${dest}${CMAKE_${type}_LIBRARY_SUFFIX}) set(full_dest ${CMAKE_${type}_LIBRARY_PREFIX}${dest}${CMAKE_${type}_LIBRARY_SUFFIX})
@ -45,7 +115,7 @@ index fed1fec7d72e..4baed19b9e98 100644
if(WIN32 AND "${type}" STREQUAL "SHARED") if(WIN32 AND "${type}" STREQUAL "SHARED")
set(output_dir bin) set(output_dir bin)
endif() endif()
@@ -1913,7 +1913,7 @@ function(llvm_install_library_symlink name dest type) @@ -1879,7 +1879,7 @@ function(llvm_install_library_symlink name dest type)
endfunction() endfunction()
@ -54,7 +124,7 @@ index fed1fec7d72e..4baed19b9e98 100644
cmake_parse_arguments(ARG "ALWAYS_GENERATE" "COMPONENT" "" ${ARGN}) cmake_parse_arguments(ARG "ALWAYS_GENERATE" "COMPONENT" "" ${ARGN})
foreach(path ${CMAKE_MODULE_PATH}) foreach(path ${CMAKE_MODULE_PATH})
if(EXISTS ${path}/LLVMInstallSymlink.cmake) if(EXISTS ${path}/LLVMInstallSymlink.cmake)
@@ -1936,7 +1936,7 @@ function(llvm_install_symlink name dest) @@ -1902,7 +1902,7 @@ function(llvm_install_symlink name dest)
set(full_dest ${dest}${CMAKE_EXECUTABLE_SUFFIX}) set(full_dest ${dest}${CMAKE_EXECUTABLE_SUFFIX})
install(SCRIPT ${INSTALL_SYMLINK} install(SCRIPT ${INSTALL_SYMLINK}
@ -63,7 +133,7 @@ index fed1fec7d72e..4baed19b9e98 100644
COMPONENT ${component}) COMPONENT ${component})
if (NOT LLVM_ENABLE_IDE AND NOT ARG_ALWAYS_GENERATE) if (NOT LLVM_ENABLE_IDE AND NOT ARG_ALWAYS_GENERATE)
@@ -2019,7 +2019,8 @@ function(add_llvm_tool_symlink link_name target) @@ -1985,7 +1985,8 @@ function(add_llvm_tool_symlink link_name target)
endif() endif()
if ((TOOL_IS_TOOLCHAIN OR NOT LLVM_INSTALL_TOOLCHAIN_ONLY) AND LLVM_BUILD_TOOLS) if ((TOOL_IS_TOOLCHAIN OR NOT LLVM_INSTALL_TOOLCHAIN_ONLY) AND LLVM_BUILD_TOOLS)
@ -73,7 +143,7 @@ index fed1fec7d72e..4baed19b9e98 100644
endif() endif()
endif() endif()
endfunction() endfunction()
@@ -2148,9 +2149,9 @@ function(llvm_setup_rpath name) @@ -2114,9 +2115,9 @@ function(llvm_setup_rpath name)
# Since BUILD_SHARED_LIBS is only recommended for use by developers, # Since BUILD_SHARED_LIBS is only recommended for use by developers,
# hardcode the rpath to build/install lib dir first in this mode. # hardcode the rpath to build/install lib dir first in this mode.
# FIXME: update this when there is better solution. # FIXME: update this when there is better solution.
@ -86,10 +156,10 @@ index fed1fec7d72e..4baed19b9e98 100644
set_property(TARGET ${name} APPEND_STRING PROPERTY set_property(TARGET ${name} APPEND_STRING PROPERTY
LINK_FLAGS " -Wl,-z,origin ") LINK_FLAGS " -Wl,-z,origin ")
diff --git a/cmake/modules/AddOCaml.cmake b/cmake/modules/AddOCaml.cmake diff --git a/cmake/modules/AddOCaml.cmake b/cmake/modules/AddOCaml.cmake
index 891c9e6d618c..8d963f3b0069 100644 index 554046b20edf..4d1ad980641e 100644
--- a/cmake/modules/AddOCaml.cmake --- a/cmake/modules/AddOCaml.cmake
+++ b/cmake/modules/AddOCaml.cmake +++ b/cmake/modules/AddOCaml.cmake
@@ -147,9 +147,9 @@ function(add_ocaml_library name) @@ -144,9 +144,9 @@ function(add_ocaml_library name)
endforeach() endforeach()
if( APPLE ) if( APPLE )
@ -101,55 +171,86 @@ index 891c9e6d618c..8d963f3b0069 100644
endif() endif()
list(APPEND ocaml_flags "-ldopt" "-Wl,-rpath,${ocaml_rpath}") list(APPEND ocaml_flags "-ldopt" "-Wl,-rpath,${ocaml_rpath}")
diff --git a/cmake/modules/AddSphinxTarget.cmake b/cmake/modules/AddSphinxTarget.cmake
index e80c3b5c1cac..482f6d715ef5 100644
--- a/cmake/modules/AddSphinxTarget.cmake
+++ b/cmake/modules/AddSphinxTarget.cmake
@@ -90,7 +90,7 @@ function (add_sphinx_target builder project)
endif()
elseif (builder STREQUAL html)
string(TOUPPER "${project}" project_upper)
- set(${project_upper}_INSTALL_SPHINX_HTML_DIR "share/doc/${project}/html"
+ set(${project_upper}_INSTALL_SPHINX_HTML_DIR "${CMAKE_INSTALL_DOCDIR}/${project}/html"
CACHE STRING "HTML documentation install directory for ${project}")
# '/.' indicates: copy the contents of the directory directly into
diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt
index cea0c1df0a14..eedcd9450312 100644 index 51b6a4fdc284..4adc2acfc074 100644
--- a/cmake/modules/CMakeLists.txt --- a/cmake/modules/CMakeLists.txt
+++ b/cmake/modules/CMakeLists.txt +++ b/cmake/modules/CMakeLists.txt
@@ -2,7 +2,7 @@ include(ExtendPath) @@ -1,6 +1,6 @@
include(LLVMDistributionSupport) include(LLVMDistributionSupport)
include(FindPrefixFromConfig)
-set(LLVM_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm) -set(LLVM_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm)
+set(LLVM_INSTALL_PACKAGE_DIR ${LLVM_INSTALL_CMAKE_DIR} CACHE STRING "Path for CMake subdirectory (defaults to 'cmake/llvm')") +set(LLVM_INSTALL_PACKAGE_DIR ${LLVM_INSTALL_CMAKE_DIR} CACHE STRING "Path for CMake subdirectory (defaults to 'cmake/llvm')")
set(llvm_cmake_builddir "${LLVM_BINARY_DIR}/${LLVM_INSTALL_PACKAGE_DIR}") set(llvm_cmake_builddir "${LLVM_BINARY_DIR}/${LLVM_INSTALL_PACKAGE_DIR}")
# First for users who use an installed LLVM, create the LLVMExports.cmake file. # First for users who use an installed LLVM, create the LLVMExports.cmake file.
@@ -122,7 +122,7 @@ set(LLVM_CONFIG_INCLUDE_DIRS @@ -109,13 +109,13 @@ foreach(p ${_count})
) set(LLVM_CONFIG_CODE "${LLVM_CONFIG_CODE}
list(REMOVE_DUPLICATES LLVM_CONFIG_INCLUDE_DIRS) get_filename_component(LLVM_INSTALL_PREFIX \"\${LLVM_INSTALL_PREFIX}\" PATH)")
endforeach(p)
-set(LLVM_CONFIG_INCLUDE_DIRS "\${LLVM_INSTALL_PREFIX}/include")
+set(LLVM_CONFIG_INCLUDE_DIRS "\${LLVM_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}")
set(LLVM_CONFIG_INCLUDE_DIR "${LLVM_CONFIG_INCLUDE_DIRS}")
set(LLVM_CONFIG_MAIN_INCLUDE_DIR "${LLVM_CONFIG_INCLUDE_DIRS}")
-set(LLVM_CONFIG_LIBRARY_DIRS "\${LLVM_INSTALL_PREFIX}/lib\${LLVM_LIBDIR_SUFFIX}")
+set(LLVM_CONFIG_LIBRARY_DIRS "\${LLVM_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}\${LLVM_LIBDIR_SUFFIX}")
set(LLVM_CONFIG_CMAKE_DIR "\${LLVM_INSTALL_PREFIX}/${LLVM_INSTALL_PACKAGE_DIR}")
set(LLVM_CONFIG_BINARY_DIR "\${LLVM_INSTALL_PREFIX}")
-set(LLVM_CONFIG_TOOLS_BINARY_DIR "\${LLVM_INSTALL_PREFIX}/bin")
+set(LLVM_CONFIG_TOOLS_BINARY_DIR "\${LLVM_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
-extend_path(LLVM_CONFIG_LIBRARY_DIR "\${LLVM_INSTALL_PREFIX}" "lib\${LLVM_LIBDIR_SUFFIX}") # Generate a default location for lit
+extend_path(LLVM_CONFIG_LIBRARY_DIR "\${LLVM_INSTALL_PREFIX}" "${CMAKE_INSTALL_LIBDIR}\${LLVM_LIBDIR_SUFFIX}") if (LLVM_INSTALL_UTILS AND LLVM_BUILD_UTILS)
set(LLVM_CONFIG_LIBRARY_DIRS
"${LLVM_CONFIG_LIBRARY_DIR}"
# FIXME: Should there be other entries here?
diff --git a/cmake/modules/LLVMInstallSymlink.cmake b/cmake/modules/LLVMInstallSymlink.cmake diff --git a/cmake/modules/LLVMInstallSymlink.cmake b/cmake/modules/LLVMInstallSymlink.cmake
index b5c35f706cb7..9261ab797de6 100644 index 3e6a2c9a2648..52e14d955c60 100644
--- a/cmake/modules/LLVMInstallSymlink.cmake --- a/cmake/modules/LLVMInstallSymlink.cmake
+++ b/cmake/modules/LLVMInstallSymlink.cmake +++ b/cmake/modules/LLVMInstallSymlink.cmake
@@ -6,7 +6,7 @@ include(GNUInstallDirs) @@ -4,7 +4,7 @@
function(install_symlink name target outdir) function(install_symlink name target outdir)
set(DESTDIR $ENV{DESTDIR}) set(DESTDIR $ENV{DESTDIR})
- set(bindir "${DESTDIR}${CMAKE_INSTALL_PREFIX}/${outdir}") - set(bindir "${DESTDIR}${CMAKE_INSTALL_PREFIX}/${outdir}/")
+ set(bindir "${DESTDIR}${outdir}/") + set(bindir "${DESTDIR}${outdir}/")
message(STATUS "Creating ${name}") message(STATUS "Creating ${name}")
diff --git a/docs/CMake.rst b/docs/CMake.rst diff --git a/docs/CMake.rst b/docs/CMake.rst
index 044ec8a4d39d..504d0eac3ade 100644 index f1ac2c7d4934..c6e1469b5e13 100644
--- a/docs/CMake.rst --- a/docs/CMake.rst
+++ b/docs/CMake.rst +++ b/docs/CMake.rst
@@ -224,7 +224,7 @@ description is in `LLVM-related variables`_ below. @@ -202,7 +202,7 @@ CMake manual, or execute ``cmake --help-variable VARIABLE_NAME``.
**LLVM_LIBDIR_SUFFIX**:STRING **LLVM_LIBDIR_SUFFIX**:STRING
Extra suffix to append to the directory where libraries are to be Extra suffix to append to the directory where libraries are to be
installed. On a 64-bit architecture, one could use ``-DLLVM_LIBDIR_SUFFIX=64`` installed. On a 64-bit architecture, one could use ``-DLLVM_LIBDIR_SUFFIX=64``
- to install libraries to ``/usr/lib64``. - to install libraries to ``/usr/lib64``.
+ to install libraries to ``/usr/lib64``. See also ``CMAKE_INSTALL_LIBDIR``. + to install libraries to ``/usr/lib64``. See also ``CMAKE_INSTALL_LIBDIR``.
**LLVM_PARALLEL_{COMPILE,LINK}_JOBS**:STRING Rarely-used CMake variables
Building the llvm toolchain can use a lot of resources, particularly ---------------------------
@@ -910,9 +910,11 @@ the ``cmake`` command or by setting it directly in ``ccmake`` or ``cmake-gui``). @@ -551,8 +551,8 @@ LLVM-specific variables
**LLVM_INSTALL_DOXYGEN_HTML_DIR**:STRING
The path to install Doxygen-generated HTML documentation to. This path can
- either be absolute or relative to the CMAKE_INSTALL_PREFIX. Defaults to
- `share/doc/llvm/doxygen-html`.
+ either be absolute or relative to the ``CMAKE_INSTALL_PREFIX``. Defaults to
+ `${CMAKE_INSTALL_DOCDIR}/${project}/doxygen-html`.
**LLVM_LINK_LLVM_DYLIB**:BOOL
If enabled, tools will be linked with the libLLVM shared library. Defaults
@@ -792,9 +792,11 @@ the ``cmake`` command or by setting it directly in ``ccmake`` or ``cmake-gui``).
This file is available in two different locations. This file is available in two different locations.
@ -164,6 +265,18 @@ index 044ec8a4d39d..504d0eac3ade 100644
* ``<LLVM_BUILD_ROOT>/lib/cmake/llvm/LLVMConfig.cmake`` where * ``<LLVM_BUILD_ROOT>/lib/cmake/llvm/LLVMConfig.cmake`` where
``<LLVM_BUILD_ROOT>`` is the root of the LLVM build tree. **Note: this is only ``<LLVM_BUILD_ROOT>`` is the root of the LLVM build tree. **Note: this is only
diff --git a/examples/Bye/CMakeLists.txt b/examples/Bye/CMakeLists.txt
index bb96edb4b4bf..678c22fb43c8 100644
--- a/examples/Bye/CMakeLists.txt
+++ b/examples/Bye/CMakeLists.txt
@@ -14,6 +14,6 @@ if (NOT WIN32)
BUILDTREE_ONLY
)
- install(TARGETS ${name} RUNTIME DESTINATION examples)
+ install(TARGETS ${name} RUNTIME DESTINATION ${CMAKE_INSTALL_DOCDIR}/examples)
set_target_properties(${name} PROPERTIES FOLDER "Examples")
endif()
diff --git a/include/llvm/CMakeLists.txt b/include/llvm/CMakeLists.txt diff --git a/include/llvm/CMakeLists.txt b/include/llvm/CMakeLists.txt
index b46319f24fc8..2feabd1954e4 100644 index b46319f24fc8..2feabd1954e4 100644
--- a/include/llvm/CMakeLists.txt --- a/include/llvm/CMakeLists.txt
@ -176,45 +289,93 @@ index b46319f24fc8..2feabd1954e4 100644
+ configure_file(module.modulemap.build ${LLVM_INCLUDE_DIR}/module.modulemap COPYONLY) + configure_file(module.modulemap.build ${LLVM_INCLUDE_DIR}/module.modulemap COPYONLY)
endif (NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") endif (NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
diff --git a/tools/llvm-config/BuildVariables.inc.in b/tools/llvm-config/BuildVariables.inc.in diff --git a/tools/llvm-config/BuildVariables.inc.in b/tools/llvm-config/BuildVariables.inc.in
index abbb8a450da6..70c497be12f5 100644 index ebe5b73a5c65..70c497be12f5 100644
--- a/tools/llvm-config/BuildVariables.inc.in --- a/tools/llvm-config/BuildVariables.inc.in
+++ b/tools/llvm-config/BuildVariables.inc.in +++ b/tools/llvm-config/BuildVariables.inc.in
@@ -23,7 +23,10 @@ @@ -23,6 +23,10 @@
#define LLVM_CXXFLAGS "@LLVM_CXXFLAGS@" #define LLVM_CXXFLAGS "@LLVM_CXXFLAGS@"
#define LLVM_BUILDMODE "@LLVM_BUILDMODE@" #define LLVM_BUILDMODE "@LLVM_BUILDMODE@"
#define LLVM_LIBDIR_SUFFIX "@LLVM_LIBDIR_SUFFIX@" #define LLVM_LIBDIR_SUFFIX "@LLVM_LIBDIR_SUFFIX@"
+#define LLVM_INSTALL_BINDIR "@CMAKE_INSTALL_BINDIR@" +#define LLVM_INSTALL_BINDIR "@CMAKE_INSTALL_BINDIR@"
+#define LLVM_INSTALL_LIBDIR "@CMAKE_INSTALL_LIBDIR@" +#define LLVM_INSTALL_LIBDIR "@CMAKE_INSTALL_LIBDIR@"
#define LLVM_INSTALL_INCLUDEDIR "@CMAKE_INSTALL_INCLUDEDIR@" +#define LLVM_INSTALL_INCLUDEDIR "@CMAKE_INSTALL_INCLUDEDIR@"
+#define LLVM_INSTALL_CMAKEDIR "@LLVM_INSTALL_CMAKE_DIR@" +#define LLVM_INSTALL_CMAKEDIR "@LLVM_INSTALL_CMAKE_DIR@"
#define LLVM_TARGETS_BUILT "@LLVM_TARGETS_BUILT@" #define LLVM_TARGETS_BUILT "@LLVM_TARGETS_BUILT@"
#define LLVM_SYSTEM_LIBS "@LLVM_SYSTEM_LIBS@" #define LLVM_SYSTEM_LIBS "@LLVM_SYSTEM_LIBS@"
#define LLVM_BUILD_SYSTEM "@LLVM_BUILD_SYSTEM@" #define LLVM_BUILD_SYSTEM "@LLVM_BUILD_SYSTEM@"
diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp
index 8ed88f33ead4..5e7184bab90d 100644 index 1a2f04552d13..44fa7d3eec6b 100644
--- a/tools/llvm-config/llvm-config.cpp --- a/tools/llvm-config/llvm-config.cpp
+++ b/tools/llvm-config/llvm-config.cpp +++ b/tools/llvm-config/llvm-config.cpp
@@ -363,12 +363,20 @@ int main(int argc, char **argv) { @@ -357,12 +357,26 @@ int main(int argc, char **argv) {
ActiveIncludeDir = std::string(Path.str()); ("-I" + ActiveIncludeDir + " " + "-I" + ActiveObjRoot + "/include");
} } else {
{ ActivePrefix = CurrentExecPrefix;
- SmallString<256> Path(LLVM_TOOLS_INSTALL_DIR); - ActiveIncludeDir = ActivePrefix + "/include";
+ SmallString<256> Path(LLVM_INSTALL_BINDIR); - SmallString<256> path(StringRef(LLVM_TOOLS_INSTALL_DIR));
sys::fs::make_absolute(ActivePrefix, Path); - sys::fs::make_absolute(ActivePrefix, path);
ActiveBinDir = std::string(Path.str()); - ActiveBinDir = std::string(path.str());
}
- ActiveLibDir = ActivePrefix + "/lib" + LLVM_LIBDIR_SUFFIX; - ActiveLibDir = ActivePrefix + "/lib" + LLVM_LIBDIR_SUFFIX;
- ActiveCMakeDir = ActiveLibDir + "/cmake/llvm"; - ActiveCMakeDir = ActiveLibDir + "/cmake/llvm";
+ { + {
+ SmallString<256> Path(LLVM_INSTALL_LIBDIR LLVM_LIBDIR_SUFFIX); + SmallString<256> path(StringRef(LLVM_INSTALL_INCLUDEDIR));
+ sys::fs::make_absolute(ActivePrefix, Path); + sys::fs::make_absolute(ActivePrefix, path);
+ ActiveLibDir = std::string(Path.str()); + ActiveIncludeDir = std::string(path.str());
+ } + }
+ { + {
+ SmallString<256> Path(LLVM_INSTALL_CMAKEDIR); + SmallString<256> path(StringRef(LLVM_INSTALL_BINDIR));
+ sys::fs::make_absolute(ActivePrefix, Path); + sys::fs::make_absolute(ActivePrefix, path);
+ ActiveCMakeDir = std::string(Path.str()); + ActiveBinDir = std::string(path.str());
+ }
+ {
+ SmallString<256> path(StringRef(LLVM_INSTALL_LIBDIR LLVM_LIBDIR_SUFFIX));
+ sys::fs::make_absolute(ActivePrefix, path);
+ ActiveLibDir = std::string(path.str());
+ }
+ {
+ SmallString<256> path(StringRef(LLVM_INSTALL_CMAKEDIR));
+ sys::fs::make_absolute(ActivePrefix, path);
+ ActiveCMakeDir = std::string(path.str());
+ } + }
ActiveIncludeOption = "-I" + ActiveIncludeDir; ActiveIncludeOption = "-I" + ActiveIncludeDir;
} }
diff --git a/tools/lto/CMakeLists.txt b/tools/lto/CMakeLists.txt
index 0af29ad762c5..37b99b83e35c 100644
--- a/tools/lto/CMakeLists.txt
+++ b/tools/lto/CMakeLists.txt
@@ -33,7 +33,7 @@ add_llvm_library(${LTO_LIBRARY_NAME} ${LTO_LIBRARY_TYPE} INSTALL_WITH_TOOLCHAIN
${SOURCES} DEPENDS intrinsics_gen)
install(FILES ${LLVM_MAIN_INCLUDE_DIR}/llvm-c/lto.h
- DESTINATION include/llvm-c
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/llvm-c
COMPONENT LTO)
if (APPLE)
diff --git a/tools/opt-viewer/CMakeLists.txt b/tools/opt-viewer/CMakeLists.txt
index ead73ec13a8f..250362021f17 100644
--- a/tools/opt-viewer/CMakeLists.txt
+++ b/tools/opt-viewer/CMakeLists.txt
@@ -8,7 +8,7 @@ set (files
foreach (file ${files})
install(PROGRAMS ${file}
- DESTINATION share/opt-viewer
+ DESTINATION ${CMAKE_INSTALL_DATADIR}/opt-viewer
COMPONENT opt-viewer)
endforeach (file)
diff --git a/tools/remarks-shlib/CMakeLists.txt b/tools/remarks-shlib/CMakeLists.txt
index 865436247270..ce1daa62f6ab 100644
--- a/tools/remarks-shlib/CMakeLists.txt
+++ b/tools/remarks-shlib/CMakeLists.txt
@@ -19,7 +19,7 @@ if(LLVM_ENABLE_PIC)
endif()
install(FILES ${LLVM_MAIN_INCLUDE_DIR}/llvm-c/Remarks.h
- DESTINATION include/llvm-c
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/llvm-c
COMPONENT Remarks)
if (APPLE)

View File

@ -34,14 +34,14 @@ let
in rec { in rec {
llvm-nac3 = pkgs.stdenvNoCC.mkDerivation rec { llvm-nac3 = pkgs.stdenvNoCC.mkDerivation rec {
pname = "llvm-nac3-msys2"; pname = "llvm-nac3-msys2";
version = "14.0.1"; version = "13.0.1";
src-llvm = pkgs.fetchurl { src-llvm = pkgs.fetchurl {
url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/llvm-${version}.src.tar.xz"; url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/llvm-${version}.src.tar.xz";
sha256 = "sha256-W4kBfewnKTEasUNALwPaHeptDHndXHAbyTnPizTwHsI="; sha256 = "sha256-7GuA2Cw4SsrS3BkpA6bPLNuv+4ibhL+5janXHmMPyDQ=";
}; };
src-clang = pkgs.fetchurl { src-clang = pkgs.fetchurl {
url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/clang-${version}.src.tar.xz"; url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/clang-${version}.src.tar.xz";
sha256 = "sha256-hE+O1cVEOPxTPQoW4KrPdfhLmKWaU9CEhT0tvsL9kqE="; sha256 = "sha256-eHqeLZn1yHIKoXc+S+AJRhzTDTvUD90kWR5HNGfJF8k=";
}; };
buildInputs = [ pkgs.wineWowPackages.stable ]; buildInputs = [ pkgs.wineWowPackages.stable ];
phases = [ "unpackPhase" "patchPhase" "configurePhase" "buildPhase" "installPhase" ]; phases = [ "unpackPhase" "patchPhase" "configurePhase" "buildPhase" "installPhase" ];
@ -49,7 +49,6 @@ in rec {
'' ''
mkdir llvm mkdir llvm
tar xf ${src-llvm} -C llvm --strip-components=1 tar xf ${src-llvm} -C llvm --strip-components=1
mv llvm/Modules/* llvm/cmake/modules # work around https://github.com/llvm/llvm-project/issues/53281
mkdir clang mkdir clang
tar xf ${src-clang} -C clang --strip-components=1 tar xf ${src-clang} -C clang --strip-components=1
cd llvm cd llvm
@ -65,7 +64,7 @@ in rec {
${silenceFontconfig} ${silenceFontconfig}
mkdir build mkdir build
cd build cd build
wine64 cmake .. -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_UNWIND_TABLES=OFF -DLLVM_ENABLE_THREADS=OFF -DLLVM_TARGETS_TO_BUILD=X86\;ARM\;RISCV -DLLVM_LINK_LLVM_DYLIB=OFF -DLLVM_ENABLE_FFI=OFF -DFFI_INCLUDE_DIR=fck-cmake -DFFI_LIBRARY_DIR=fck-cmake -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_INSTALL_PREFIX=Z:$out wine64 cmake .. -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_UNWIND_TABLES=OFF -DLLVM_ENABLE_THREADS=OFF -DLLVM_TARGETS_TO_BUILD=X86\;ARM\;RISCV -DLLVM_LINK_LLVM_DYLIB=OFF -DLLVM_ENABLE_FFI=OFF -DFFI_INCLUDE_DIR=fck-cmake -DFFI_LIBRARY_DIR=fck-cmake -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_INSTALL_PREFIX=Z:$out
''; '';
buildPhase = buildPhase =
'' ''
@ -80,12 +79,7 @@ in rec {
nac3artiq = pkgs.rustPlatform.buildRustPackage { nac3artiq = pkgs.rustPlatform.buildRustPackage {
name = "nac3artiq-msys2"; name = "nac3artiq-msys2";
src = ../../.; src = ../../.;
cargoLock = { cargoLock = { lockFile = ../../Cargo.lock; };
lockFile = ../../Cargo.lock;
outputHashes = {
"inkwell-0.1.0" = "sha256-THGKoTqQCSusxMukOiksQ9pCnxdIBUO6MH3fiwQjYVA=";
};
};
nativeBuildInputs = [ pkgs.wineWowPackages.stable ]; nativeBuildInputs = [ pkgs.wineWowPackages.stable ];
buildPhase = buildPhase =
'' ''
@ -128,19 +122,14 @@ in rec {
}; };
lld = pkgs.stdenvNoCC.mkDerivation rec { lld = pkgs.stdenvNoCC.mkDerivation rec {
pname = "lld-msys2"; pname = "lld-msys2";
version = "14.0.1"; version = "13.0.1";
src = pkgs.fetchurl { src = pkgs.fetchurl {
url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/lld-${version}.src.tar.xz"; url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/lld-${version}.src.tar.xz";
sha256 = "sha256-MbrFSILSfJ4hfqRFA0BGrAUkLlyOSyxQ8/mAL8ijeBo="; sha256 = "sha256-Zmr3Rei/e2gFM7TRi3ox3HyrV1sebk0mGSK7r9lkTPs=";
}; };
buildInputs = [ pkgs.wineWowPackages.stable ]; buildInputs = [ pkgs.wineWowPackages.stable ];
phases = [ "unpackPhase" "patchPhase" "configurePhase" "buildPhase" "installPhase" ]; phases = [ "unpackPhase" "patchPhase" "configurePhase" "buildPhase" "installPhase" ];
patches = [ ./lld-disable-macho.diff ]; patches = [ ./lld-disable-macho.diff ];
setSourceRoot = # work around https://github.com/llvm/llvm-project/issues/53281
''
mv cmake/Modules/* lld-14.0.1.src/cmake/modules
sourceRoot=lld-14.0.1.src
'';
configurePhase = configurePhase =
'' ''
export HOME=`mktemp -d` export HOME=`mktemp -d`

View File

@ -1,7 +1,7 @@
diff '--color=auto' -Naur lld-14.0.1.src.orig/CMakeLists.txt lld-14.0.1.src/CMakeLists.txt diff '--color=auto' -Naur lld-13.0.1.src/CMakeLists.txt lld-13.0.1.src-new/CMakeLists.txt
--- lld-14.0.1.src.orig/CMakeLists.txt 2022-04-12 07:44:22.000000000 +0800 --- lld-13.0.1.src/CMakeLists.txt 2022-01-21 05:31:59.000000000 +0800
+++ lld-14.0.1.src/CMakeLists.txt 2022-04-18 18:03:22.530746411 +0800 +++ lld-13.0.1.src-new/CMakeLists.txt 2022-03-27 18:26:30.284921982 +0800
@@ -248,7 +248,6 @@ @@ -206,7 +206,6 @@
add_subdirectory(docs) add_subdirectory(docs)
add_subdirectory(COFF) add_subdirectory(COFF)
add_subdirectory(ELF) add_subdirectory(ELF)
@ -9,26 +9,28 @@ diff '--color=auto' -Naur lld-14.0.1.src.orig/CMakeLists.txt lld-14.0.1.src/CMak
add_subdirectory(MinGW) add_subdirectory(MinGW)
add_subdirectory(wasm) add_subdirectory(wasm)
diff '--color=auto' -Naur lld-14.0.1.src.orig/tools/lld/CMakeLists.txt lld-14.0.1.src/tools/lld/CMakeLists.txt diff '--color=auto' -Naur lld-13.0.1.src/tools/lld/CMakeLists.txt lld-13.0.1.src-new/tools/lld/CMakeLists.txt
--- lld-14.0.1.src.orig/tools/lld/CMakeLists.txt 2022-04-12 07:44:22.000000000 +0800 --- lld-13.0.1.src/tools/lld/CMakeLists.txt 2022-01-21 05:31:59.000000000 +0800
+++ lld-14.0.1.src/tools/lld/CMakeLists.txt 2022-04-18 18:03:34.434692221 +0800 +++ lld-13.0.1.src-new/tools/lld/CMakeLists.txt 2022-03-27 18:26:40.805046295 +0800
@@ -14,7 +14,6 @@ @@ -15,7 +15,6 @@
lldCommon
lldCOFF lldCOFF
lldDriver
lldELF lldELF
- lldMachO - lldMachO2
lldMinGW lldMinGW
lldWasm lldWasm
) )
diff '--color=auto' -Naur lld-14.0.1.src.orig/tools/lld/lld.cpp lld-14.0.1.src/tools/lld/lld.cpp diff '--color=auto' -Naur lld-13.0.1.src/tools/lld/lld.cpp lld-13.0.1.src-new/tools/lld/lld.cpp
--- lld-14.0.1.src.orig/tools/lld/lld.cpp 2022-04-12 07:44:22.000000000 +0800 --- lld-13.0.1.src/tools/lld/lld.cpp 2022-01-21 05:31:59.000000000 +0800
+++ lld-14.0.1.src/tools/lld/lld.cpp 2022-04-18 18:04:08.517537288 +0800 +++ lld-13.0.1.src-new/tools/lld/lld.cpp 2022-03-27 08:43:54.205524156 +0800
@@ -151,8 +151,6 @@ @@ -148,10 +148,6 @@
return elf::link; return !elf::link(args, exitEarly, stdoutOS, stderrOS);
else if (f == WinLink) case WinLink:
return coff::link; return !coff::link(args, exitEarly, stdoutOS, stderrOS);
- else if (f == Darwin) - case Darwin:
- return macho::link; - return !macho::link(args, exitEarly, stdoutOS, stderrOS);
else if (f == Wasm) - case DarwinOld:
return lld::wasm::link; - return !mach_o::link(args, exitEarly, stdoutOS, stderrOS);
else case Wasm:
return !lld::wasm::link(args, exitEarly, stdoutOS, stderrOS);
default:

View File

@ -47,11 +47,12 @@ pub extern "C" fn __nac3_personality(_state: u32, _exception_object: u32, _conte
unimplemented!(); unimplemented!();
} }
fn main() { fn main() {
let filename = env::args().nth(1).unwrap(); let filename = env::args().nth(1).unwrap();
unsafe { unsafe {
let lib = libloading::Library::new(filename).unwrap(); let lib = libloading::Library::new(filename).unwrap();
let func: libloading::Symbol<unsafe extern "C" fn()> = lib.get(b"__modinit__").unwrap(); let func: libloading::Symbol<unsafe extern fn()> = lib.get(b"__modinit__").unwrap();
func() func()
} }
} }