Compare commits

..

8 Commits

Author SHA1 Message Date
aebfd0a37d nac3core/artiq: raise ValueError for unwrap none 2022-03-26 01:54:42 +08:00
91d697c327 nac3standalone: add tests for option 2022-03-26 01:54:42 +08:00
d18292dd28 nac3core/artiq: use none instead of None 2022-03-26 01:54:42 +08:00
29da2d1a9a nac3artiq/core: host option object support 2022-03-26 01:54:42 +08:00
34b460757b nac3core: option type codegen support 2022-03-26 01:54:42 +08:00
925f1c2cc4 nac3core: remove previous handling of None
not to confuse with option none, and the None token is parsed as a special ast::constant instead of an ast::name so the handling is invalid
2022-03-26 01:51:54 +08:00
65110a2cf2 nac3core: fix broken tests 2022-03-25 03:49:57 +08:00
3d39a80df6 nac3core: option type front end 2022-03-25 02:37:08 +08:00
50 changed files with 541 additions and 1514 deletions

125
Cargo.lock generated
View File

@ -249,9 +249,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.6" version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@ -278,9 +278,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.8.1" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@ -329,7 +329,7 @@ dependencies = [
"libc", "libc",
"llvm-sys", "llvm-sys",
"once_cell", "once_cell",
"parking_lot 0.11.2", "parking_lot",
"regex", "regex",
] ]
@ -422,9 +422,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.122" version = "0.2.121"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259" checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -457,11 +457,10 @@ dependencies = [
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.7" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
dependencies = [ dependencies = [
"autocfg",
"scopeguard", "scopeguard",
] ]
@ -496,7 +495,7 @@ dependencies = [
"inkwell", "inkwell",
"nac3core", "nac3core",
"nac3parser", "nac3parser",
"parking_lot 0.11.2", "parking_lot",
"pyo3", "pyo3",
"tempfile", "tempfile",
] ]
@ -507,7 +506,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"fxhash", "fxhash",
"lazy_static", "lazy_static",
"parking_lot 0.11.2", "parking_lot",
"string-interner", "string-interner",
] ]
@ -521,7 +520,7 @@ dependencies = [
"insta", "insta",
"itertools", "itertools",
"nac3parser", "nac3parser",
"parking_lot 0.11.2", "parking_lot",
"rayon", "rayon",
"regex", "regex",
"test-case", "test-case",
@ -550,7 +549,7 @@ dependencies = [
"inkwell", "inkwell",
"nac3core", "nac3core",
"nac3parser", "nac3parser",
"parking_lot 0.11.2", "parking_lot",
] ]
[[package]] [[package]]
@ -583,17 +582,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [ dependencies = [
"instant", "instant",
"lock_api", "lock_api",
"parking_lot_core 0.8.5", "parking_lot_core",
]
[[package]]
name = "parking_lot"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58"
dependencies = [
"lock_api",
"parking_lot_core 0.9.2",
] ]
[[package]] [[package]]
@ -610,19 +599,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "parking_lot_core"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
]
[[package]] [[package]]
name = "paste" name = "paste"
version = "0.1.18" version = "0.1.18"
@ -740,9 +716,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.37" version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [ dependencies = [
"unicode-xid", "unicode-xid",
] ]
@ -756,7 +732,7 @@ dependencies = [
"cfg-if", "cfg-if",
"indoc 0.3.6", "indoc 0.3.6",
"libc", "libc",
"parking_lot 0.11.2", "parking_lot",
"paste", "paste",
"pyo3-build-config", "pyo3-build-config",
"pyo3-macros", "pyo3-macros",
@ -797,9 +773,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.18" version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -861,18 +837,18 @@ dependencies = [
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.2.13" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
dependencies = [ dependencies = [
"bitflags", "bitflags",
] ]
[[package]] [[package]]
name = "redox_users" name = "redox_users"
version = "0.4.3" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" checksum = "7776223e2696f1aa4c6b0170e83212f47296a00424305117d013dfe86fb0fe55"
dependencies = [ dependencies = [
"getrandom", "getrandom",
"redox_syscall", "redox_syscall",
@ -1022,22 +998,22 @@ dependencies = [
[[package]] [[package]]
name = "string_cache" name = "string_cache"
version = "0.8.4" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26"
dependencies = [ dependencies = [
"lazy_static",
"new_debug_unreachable", "new_debug_unreachable",
"once_cell", "parking_lot",
"parking_lot 0.12.0",
"phf_shared 0.10.0", "phf_shared 0.10.0",
"precomputed-hash", "precomputed-hash",
] ]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.91" version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1231,49 +1207,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825"
dependencies = [
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d"
[[package]]
name = "windows_i686_gnu"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed"
[[package]]
name = "windows_i686_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956"
[[package]]
name = "windows_x86_64_gnu"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4"
[[package]]
name = "windows_x86_64_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9"
[[package]] [[package]]
name = "yaml-rust" name = "yaml-rust"
version = "0.4.5" version = "0.4.5"

View File

@ -16,28 +16,40 @@ NAC3 is packaged using the [Nix](https://nixos.org) Flakes system. Install Nix 2
After setting up Nix as above, use ``nix shell git+https://github.com/m-labs/artiq.git?ref=nac3`` to get a shell with the NAC3 version of ARTIQ. See the ``examples`` directory in ARTIQ (``nac3`` Git branch) for some samples of NAC3 kernel code. After setting up Nix as above, use ``nix shell git+https://github.com/m-labs/artiq.git?ref=nac3`` to get a shell with the NAC3 version of ARTIQ. See the ``examples`` directory in ARTIQ (``nac3`` Git branch) for some samples of NAC3 kernel code.
### Windows ### Windows (work in progress)
Install [MSYS2](https://www.msys2.org/), and open "MSYS2 MinGW x64". Edit ``/etc/pacman.conf`` to add: NAC3 ARTIQ packaging for MSYS2/Windows is not yet complete so installation involves many manual steps. It is also less tested and you may encounter problems.
Install [MSYS2](https://www.msys2.org/) and run the following commands:
``` ```
[artiq] pacman -S mingw-w64-x86_64-python-h5py mingw-w64-x86_64-python-pyqt5 mingw-w64-x86_64-python-scipy mingw-w64-x86_64-python-prettytable mingw-w64-x86_64-python-pygit2
SigLevel = Optional TrustAll pacman -S mingw-w64-x86_64-python-pip
Server = https://lab.m-labs.hk/msys2 pip install qasync
pip install pyqtgraph
pacman -S patch git
git clone https://github.com/m-labs/sipyco
cd sipyco
git show 20c946aad78872fe60b78d9b57a624d69f3eea47 | patch -p1 -R
python setup.py install
cd ..
git clone -b nac3 https://github.com/m-labs/artiq
cd artiq
python setup.py install
``` ```
Then run the following commands: Locate a recent build of ``nac3artiq-msys2`` from [Hydra](https://nixbld.m-labs.hk) and download ``nac3artiq.zip``. Then extract the contents in the appropriate location:
``` ```
pacman -Syu pacman -S unzip
pacman -S mingw-w64-x86_64-artiq wget https://nixbld.m-labs.hk/build/97899/download/1/nac3artiq.zip # edit the build number
unzip nac3artiq.zip -d C:/msys64/mingw64/lib/python3.9/site-packages
``` ```
Install ``lld-msys2`` manually: Install additional NAC3 dependencies:
``` ```
wget https://nixbld.m-labs.hk/build/115527/download/1/ld.lld.exe pacman -S mingw-w64-x86_64-lld
mv ld.lld.exe C:/msys64/mingw64/bin
``` ```
Note: This build of NAC3 cannot be used with Anaconda Python nor the python.org binaries for Windows. Those Python versions are compiled with Visual Studio (MSVC) and their ABI is incompatible with the GNU ABI used in this build. We have no plans to support Visual Studio nor the MSVC ABI. If you need a MSVC build, please install the requisite bloated spyware from Microsoft and compile NAC3 yourself. And you should be good to go.
## For developers ## For developers

6
flake.lock generated
View File

@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1649619156, "lastModified": 1647992509,
"narHash": "sha256-p0q4zpuKMwrzGF+5ZU7Thnpac5TinhDI9jr2mBxhV4w=", "narHash": "sha256-AG40Nt5OWz0LBs5p457emOuwLKOvTtcv/2fUdnEN3Ws=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e7d63bd0d50df412f5a1d8acfa3caae75522e347", "rev": "d2caa9377539e3b5ff1272ac3aa2d15f3081069f",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -8,7 +8,7 @@
pkgs = import nixpkgs { system = "x86_64-linux"; }; pkgs = import nixpkgs { system = "x86_64-linux"; };
in rec { in rec {
packages.x86_64-linux = rec { packages.x86_64-linux = rec {
llvm-nac3 = pkgs.callPackage ./nix/llvm {}; llvm-nac3 = pkgs.callPackage "${self}/llvm" {};
nac3artiq = pkgs.python3Packages.toPythonModule ( nac3artiq = pkgs.python3Packages.toPythonModule (
pkgs.rustPlatform.buildRustPackage { pkgs.rustPlatform.buildRustPackage {
name = "nac3artiq"; name = "nac3artiq";
@ -48,7 +48,7 @@
}; };
# LLVM PGO support # LLVM PGO support
llvm-nac3-instrumented = pkgs.callPackage ./nix/llvm { llvm-nac3-instrumented = pkgs.callPackage "${self}/llvm" {
stdenv = pkgs.llvmPackages_13.stdenv; stdenv = pkgs.llvmPackages_13.stdenv;
extraCmakeFlags = [ "-DLLVM_BUILD_INSTRUMENTED=IR" ]; extraCmakeFlags = [ "-DLLVM_BUILD_INSTRUMENTED=IR" ];
}; };
@ -86,7 +86,7 @@
llvm-profdata merge -o $out/llvm.profdata /build/llvm/build/profiles/* llvm-profdata merge -o $out/llvm.profdata /build/llvm/build/profiles/*
''; '';
}; };
llvm-nac3-pgo = pkgs.callPackage ./nix/llvm { llvm-nac3-pgo = pkgs.callPackage "${self}/llvm" {
stdenv = pkgs.llvmPackages_13.stdenv; stdenv = pkgs.llvmPackages_13.stdenv;
extraCmakeFlags = [ "-DLLVM_PROFDATA_FILE=${nac3artiq-profile}/llvm.profdata" ]; extraCmakeFlags = [ "-DLLVM_PROFDATA_FILE=${nac3artiq-profile}/llvm.profdata" ];
}; };
@ -109,7 +109,7 @@
); );
}; };
packages.x86_64-w64-mingw32 = import ./nix/windows { inherit pkgs; }; packages.x86_64-w64-mingw32 = import ./windows { inherit pkgs; };
devShell.x86_64-linux = pkgs.mkShell { devShell.x86_64-linux = pkgs.mkShell {
name = "nac3-dev-shell"; name = "nac3-dev-shell";
@ -129,7 +129,7 @@
]; ];
}; };
devShells.x86_64-linux.msys2 = pkgs.mkShell { devShells.x86_64-linux.msys2 = pkgs.mkShell {
name = "nac3-dev-shell-msys2"; name = "nac3-dev-shell";
buildInputs = with pkgs; [ buildInputs = with pkgs; [
curl curl
pacman pacman
@ -142,13 +142,11 @@
inherit (packages.x86_64-linux) llvm-nac3 nac3artiq; 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;
lld-msys2 = packages.x86_64-w64-mingw32.lld;
}; };
}; };
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,4 +1,10 @@
from min_artiq import * from min_artiq import *
from numpy import int32, int64
@extern
def output_int(x: int32):
...
@nac3 @nac3

View File

@ -5,7 +5,6 @@ class EmbeddingMap:
self.string_map = {} self.string_map = {}
self.string_reverse_map = {} self.string_reverse_map = {}
self.function_map = {} self.function_map = {}
self.attributes_writeback = []
# preallocate exception names # preallocate exception names
self.preallocate_runtime_exception_names(["RuntimeError", self.preallocate_runtime_exception_names(["RuntimeError",
@ -17,8 +16,7 @@ class EmbeddingMap:
"CacheError", "CacheError",
"SPIError", "SPIError",
"0:ZeroDivisionError", "0:ZeroDivisionError",
"0:IndexError", "0:IndexError"])
"0:UnwrapNoneError"])
def preallocate_runtime_exception_names(self, names): def preallocate_runtime_exception_names(self, names):
for i, name in enumerate(names): for i, name in enumerate(names):

View File

@ -11,7 +11,7 @@ from embedding_map import EmbeddingMap
__all__ = [ __all__ = [
"Kernel", "KernelInvariant", "virtual", "Kernel", "KernelInvariant", "virtual",
"Option", "Some", "none", "UnwrapNoneError", "Option", "Some", "none",
"round64", "floor64", "ceil64", "round64", "floor64", "ceil64",
"extern", "kernel", "portable", "nac3", "extern", "kernel", "portable", "nac3",
"rpc", "ms", "us", "ns", "rpc", "ms", "us", "ns",
@ -47,7 +47,7 @@ class Option(Generic[T]):
def unwrap(self): def unwrap(self):
if self.is_none(): if self.is_none():
raise UnwrapNoneError() raise ValueError("unwrap on none")
return self._nac3_option return self._nac3_option
def __repr__(self) -> str: def __repr__(self) -> str:
@ -274,10 +274,5 @@ class KernelContextManager:
def __exit__(self): def __exit__(self):
pass pass
@nac3
class UnwrapNoneError(Exception):
"""raised when unwrapping a none value"""
artiq_builtin = True
parallel = KernelContextManager() parallel = KernelContextManager()
sequential = KernelContextManager() sequential = KernelContextManager()

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, Type},
}; };
use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef}; use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
@ -15,9 +15,7 @@ use inkwell::{
context::Context, module::Linkage, types::IntType, values::BasicValueEnum, AddressSpace, context::Context, module::Linkage, types::IntType, values::BasicValueEnum, AddressSpace,
}; };
use pyo3::{PyObject, PyResult, Python, types::{PyDict, PyList}}; use crate::timeline::TimeFns;
use crate::{symbol_resolver::InnerResolver, timeline::TimeFns};
use std::{ use std::{
collections::hash_map::DefaultHasher, collections::hash_map::DefaultHasher,
@ -68,7 +66,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(ctx, self, end.custom.unwrap())?; let old_end = self.gen_expr(ctx, &end)?.unwrap().to_basic_value_enum(ctx, self)?;
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();
@ -88,7 +86,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(ctx, self, start.custom.unwrap())?; let start_val = self.gen_expr(ctx, &start)?.unwrap().to_basic_value_enum(ctx, self)?;
self.timeline.emit_at_mu(ctx, start_val); self.timeline.emit_at_mu(ctx, start_val);
} }
Ok(result) Ok(result)
@ -120,7 +118,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(ctx, self, old_start.custom.unwrap())? self.gen_expr(ctx, old_start)?.unwrap().to_basic_value_enum(ctx, self)?
} else { } else {
self.timeline.emit_now_mu(ctx) self.timeline.emit_now_mu(ctx)
}; };
@ -174,10 +172,8 @@ 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 let end_val =
.gen_expr(ctx, &end_expr)? self.gen_expr(ctx, &end_expr)?.unwrap().to_basic_value_enum(ctx, self)?;
.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() {
@ -188,7 +184,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
let outer_end_val = self let outer_end_val = self
.gen_expr(ctx, old_end)? .gen_expr(ctx, old_end)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, self, old_end.custom.unwrap())?; .to_basic_value_enum(ctx, self)?;
let smax = let smax =
ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| { ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
let i64 = ctx.ctx.i64_type(); let i64 = ctx.ctx.i64_type();
@ -274,6 +270,8 @@ fn gen_rpc_tag<'ctx, 'a>(
buffer.push(b'l'); buffer.push(b'l');
gen_rpc_tag(ctx, *ty, buffer)?; gen_rpc_tag(ctx, *ty, buffer)?;
} }
// we should return an error, this will be fixed after improving error message
// as this requires returning an error during codegen
_ => return Err(format!("Unsupported type: {:?}", ctx.unifier.stringify(ty))), _ => return Err(format!("Unsupported type: {:?}", ctx.unifier.stringify(ty))),
} }
} }
@ -293,7 +291,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() {
@ -363,17 +361,14 @@ 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.insert( mapping.insert(k.name, ctx.gen_symbol_val(generator, &k.default_value.unwrap()).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
.0 .0
.args .args
.iter() .iter()
.map(|arg| mapping.remove(&arg.name).unwrap().to_basic_value_enum(ctx, generator, arg.ty)) .map(|arg| mapping.remove(&arg.name).unwrap().to_basic_value_enum(ctx, generator))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
if let Some(obj) = obj { if let Some(obj) = obj {
if let ValueEnum::Static(obj) = obj.1 { if let ValueEnum::Static(obj) = obj.1 {
@ -491,83 +486,6 @@ fn rpc_codegen_callback_fn<'ctx, 'a>(
Ok(Some(result)) Ok(Some(result))
} }
pub fn attributes_writeback<'ctx, 'a>(
ctx: &mut CodeGenContext<'ctx, 'a>,
generator: &mut dyn CodeGenerator,
inner_resolver: &InnerResolver,
host_attributes: PyObject,
) -> Result<(), String> {
Python::with_gil(|py| -> PyResult<Result<(), String>> {
let host_attributes = host_attributes.cast_as::<PyList>(py)?;
let top_levels = ctx.top_level.definitions.read();
let globals = inner_resolver.global_value_ids.read();
let int32 = ctx.ctx.i32_type();
let zero = int32.const_zero();
let mut values = Vec::new();
let mut scratch_buffer = Vec::new();
for (_, val) in globals.iter() {
let val = val.as_ref(py);
let ty = inner_resolver.get_obj_type(py, val, &mut ctx.unifier, &top_levels, &ctx.primitives)?;
if let Err(ty) = ty {
return Ok(Err(ty))
}
let ty = ty.unwrap();
match &*ctx.unifier.get_ty(ty) {
TypeEnum::TObj { fields, obj_id, .. }
if *obj_id != ctx.primitives.option.get_obj_id(&ctx.unifier) =>
{
// we only care about primitive attributes
// for non-primitive attributes, they should be in another global
let mut attributes = Vec::new();
let obj = inner_resolver.get_obj_value(py, val, ctx, generator, ty)?.unwrap();
for (name, (field_ty, is_mutable)) in fields.iter() {
if !is_mutable {
continue
}
if gen_rpc_tag(ctx, *field_ty, &mut scratch_buffer).is_ok() {
attributes.push(name.to_string());
let index = ctx.get_attr_index(ty, *name);
values.push((*field_ty, ctx.build_gep_and_load(
obj.into_pointer_value(),
&[zero, int32.const_int(index as u64, false)])));
}
}
if !attributes.is_empty() {
let pydict = PyDict::new(py);
pydict.set_item("obj", val)?;
pydict.set_item("fields", attributes)?;
host_attributes.append(pydict)?;
}
},
TypeEnum::TList { ty: elem_ty } => {
if gen_rpc_tag(ctx, *elem_ty, &mut scratch_buffer).is_ok() {
let pydict = PyDict::new(py);
pydict.set_item("obj", val)?;
host_attributes.append(pydict)?;
values.push((ty, inner_resolver.get_obj_value(py, val, ctx, generator, ty)?.unwrap()));
}
},
_ => {}
}
}
let fun = FunSignature {
args: values.iter().enumerate().map(|(i, (ty, _))| FuncArg {
name: i.to_string().into(),
ty: *ty,
default_value: None
}).collect(),
ret: ctx.primitives.none,
vars: Default::default()
};
let args: Vec<_> = 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) {
return Ok(Err(e));
}
Ok(Ok(()))
}).unwrap()?;
Ok(())
}
pub fn rpc_codegen_callback() -> Arc<GenCall> { pub fn rpc_codegen_callback() -> Arc<GenCall> {
Arc::new(GenCall::new(Box::new(|ctx, obj, fun, args, generator| { Arc::new(GenCall::new(Box::new(|ctx, obj, fun, args, generator| {
rpc_codegen_callback_fn(ctx, obj, fun, args, generator) rpc_codegen_callback_fn(ctx, obj, fun, args, generator)

View File

@ -10,7 +10,6 @@ use inkwell::{
targets::*, targets::*,
OptimizationLevel, OptimizationLevel,
}; };
use nac3core::codegen::gen_func_impl;
use nac3core::toplevel::builtins::get_exn_constructor; use nac3core::toplevel::builtins::get_exn_constructor;
use nac3core::typecheck::typedef::{TypeEnum, Unifier}; use nac3core::typecheck::typedef::{TypeEnum, Unifier};
use nac3parser::{ use nac3parser::{
@ -37,7 +36,6 @@ use nac3core::{
use tempfile::{self, TempDir}; use tempfile::{self, TempDir};
use crate::codegen::attributes_writeback;
use crate::{ use crate::{
codegen::{rpc_codegen_callback, ArtiqCodeGenerator}, codegen::{rpc_codegen_callback, ArtiqCodeGenerator},
symbol_resolver::{InnerResolver, PythonHelper, Resolver, DeferredEvaluationStore}, symbol_resolver::{InnerResolver, PythonHelper, Resolver, DeferredEvaluationStore},
@ -65,7 +63,6 @@ pub struct PrimitivePythonId {
uint32: u64, uint32: u64,
uint64: u64, uint64: u64,
float: u64, float: u64,
float64: u64,
bool: u64, bool: u64,
list: u64, list: u64,
tuple: u64, tuple: u64,
@ -329,9 +326,8 @@ impl Nac3 {
ret: primitive.none, ret: primitive.none,
vars: HashMap::new(), vars: HashMap::new(),
}, },
Arc::new(GenCall::new(Box::new(move |ctx, _, fun, args, generator| { Arc::new(GenCall::new(Box::new(move |ctx, _, _, args, generator| {
let arg_ty = fun.0.args[0].ty; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator).unwrap();
let arg = 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)
}))), }))),
@ -347,9 +343,8 @@ impl Nac3 {
ret: primitive.none, ret: primitive.none,
vars: HashMap::new(), vars: HashMap::new(),
}, },
Arc::new(GenCall::new(Box::new(move |ctx, _, fun, args, generator| { Arc::new(GenCall::new(Box::new(move |ctx, _, _, args, generator| {
let arg_ty = fun.0.args[0].ty; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator).unwrap();
let arg = 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)
}))), }))),
@ -398,7 +393,6 @@ impl Nac3 {
uint64: get_attr_id(numpy_mod, "uint64"), uint64: get_attr_id(numpy_mod, "uint64"),
bool: get_attr_id(builtins_mod, "bool"), bool: get_attr_id(builtins_mod, "bool"),
float: get_attr_id(builtins_mod, "float"), float: get_attr_id(builtins_mod, "float"),
float64: get_attr_id(numpy_mod, "float64"),
list: get_attr_id(builtins_mod, "list"), list: get_attr_id(builtins_mod, "list"),
tuple: get_attr_id(builtins_mod, "tuple"), tuple: get_attr_id(builtins_mod, "tuple"),
exception: get_attr_id(builtins_mod, "Exception"), exception: get_attr_id(builtins_mod, "Exception"),
@ -482,8 +476,6 @@ impl Nac3 {
let store_obj = embedding_map.getattr("store_object").unwrap().to_object(py); let store_obj = embedding_map.getattr("store_object").unwrap().to_object(py);
let store_str = embedding_map.getattr("store_str").unwrap().to_object(py); let store_str = embedding_map.getattr("store_str").unwrap().to_object(py);
let store_fun = embedding_map.getattr("store_function").unwrap().to_object(py); let store_fun = embedding_map.getattr("store_function").unwrap().to_object(py);
let host_attributes = embedding_map.getattr("attributes_writeback").unwrap().to_object(py);
let global_value_ids: Arc<RwLock<HashMap<_, _>>> = Arc::new(RwLock::new(HashMap::new()));
let helper = PythonHelper { let helper = PythonHelper {
id_fn: builtins.getattr("id").unwrap().to_object(py), id_fn: builtins.getattr("id").unwrap().to_object(py),
len_fn: builtins.getattr("len").unwrap().to_object(py), len_fn: builtins.getattr("len").unwrap().to_object(py),
@ -504,13 +496,13 @@ impl Nac3 {
"KeyError", "KeyError",
"NotImplementedError", "NotImplementedError",
"OverflowError", "OverflowError",
"IOError", "IOError"
"UnwrapNoneError",
]; ];
add_exceptions(&mut composer, &mut builtins_def, &mut builtins_ty, &exception_names); add_exceptions(&mut composer, &mut builtins_def, &mut builtins_ty, &exception_names);
let mut module_to_resolver_cache: HashMap<u64, _> = HashMap::new(); let mut module_to_resolver_cache: HashMap<u64, _> = HashMap::new();
let global_value_ids = Arc::new(RwLock::new(HashSet::<u64>::new()));
let mut rpc_ids = vec![]; let mut rpc_ids = vec![];
for (stmt, path, module) in self.top_levels.iter() { for (stmt, path, module) in self.top_levels.iter() {
let py_module: &PyAny = module.extract(py)?; let py_module: &PyAny = module.extract(py)?;
@ -624,7 +616,7 @@ impl Nac3 {
}; };
let mut synthesized = let mut synthesized =
parse_program(&synthesized, "__nac3_synthesized_modinit__".to_string().into()).unwrap(); parse_program(&synthesized, "__nac3_synthesized_modinit__".to_string().into()).unwrap();
let inner_resolver = Arc::new(InnerResolver { let resolver = Arc::new(Resolver(Arc::new(InnerResolver {
id_to_type: builtins_ty.clone().into(), id_to_type: builtins_ty.clone().into(),
id_to_def: builtins_def.clone().into(), id_to_def: builtins_def.clone().into(),
pyid_to_def: self.pyid_to_def.clone(), pyid_to_def: self.pyid_to_def.clone(),
@ -641,18 +633,17 @@ impl Nac3 {
string_store: self.string_store.clone(), string_store: self.string_store.clone(),
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(),
}); }))) as Arc<dyn SymbolResolver + Send + Sync>;
let resolver = 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();
let fun_signature = let signature =
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 = let signature =
store.from_signature(&mut composer.unifier, &self.primitive, &fun_signature, &mut cache); store.from_signature(&mut composer.unifier, &self.primitive, &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) {
@ -729,27 +720,10 @@ impl Nac3 {
symbol_name: "__modinit__".to_string(), symbol_name: "__modinit__".to_string(),
body: instance.body, body: instance.body,
signature, signature,
resolver: resolver.clone(),
store,
unifier_index: instance.unifier_id,
calls: instance.calls,
id: 0,
};
let mut store = ConcreteTypeStore::new();
let mut cache = HashMap::new();
let signature =
store.from_signature(&mut composer.unifier, &self.primitive, &fun_signature, &mut cache);
let signature = store.add_cty(signature);
let attributes_writeback_task = CodeGenTask {
subst: Default::default(),
symbol_name: "attributes_writeback".to_string(),
body: Arc::new(Default::default()),
signature,
resolver, resolver,
store, store,
unifier_index: instance.unifier_id, unifier_index: instance.unifier_id,
calls: Arc::new(Default::default()), calls: instance.calls,
id: 0, id: 0,
}; };
let isa = self.isa; let isa = self.isa;
@ -771,27 +745,14 @@ impl Nac3 {
.map(|s| Box::new(ArtiqCodeGenerator::new(s.to_string(), size_t, self.time_fns))) .map(|s| Box::new(ArtiqCodeGenerator::new(s.to_string(), size_t, self.time_fns)))
.collect(); .collect();
let membuffer = membuffers.clone();
py.allow_threads(|| { py.allow_threads(|| {
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level.clone(), f); let (registry, handles) = WorkerRegistry::create_workers(threads, top_level.clone(), f);
registry.add_task(task); registry.add_task(task);
registry.wait_tasks_complete(handles); registry.wait_tasks_complete(handles);
let mut generator = ArtiqCodeGenerator::new("attributes_writeback".to_string(), size_t, self.time_fns);
let context = inkwell::context::Context::create();
let module = context.create_module("attributes_writeback");
let builder = context.create_builder();
let (_, module, _) = gen_func_impl(&context, &mut generator, &registry, builder, module,
attributes_writeback_task, |generator, ctx| {
attributes_writeback(ctx, generator, inner_resolver.as_ref(), host_attributes)
}).unwrap();
let buffer = module.write_bitcode_to_memory();
let buffer = buffer.as_slice().into();
membuffer.lock().push(buffer);
}); });
let context = inkwell::context::Context::create();
let buffers = membuffers.lock(); let buffers = membuffers.lock();
let context = inkwell::context::Context::create();
let main = context let main = context
.create_module_from_ir(MemoryBuffer::create_from_memory_range(&buffers[0], "main")) .create_module_from_ir(MemoryBuffer::create_from_memory_range(&buffers[0], "main"))
.unwrap(); .unwrap();
@ -803,11 +764,6 @@ impl Nac3 {
main.link_in_module(other) main.link_in_module(other)
.map_err(|err| CompileError::new_err(err.to_string()))?; .map_err(|err| CompileError::new_err(err.to_string()))?;
} }
let builder = context.create_builder();
let modinit_return = main.get_function("__modinit__").unwrap().get_last_basic_block().unwrap().get_terminator().unwrap();
builder.position_before(&modinit_return);
builder.build_call(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()))?;
@ -871,11 +827,7 @@ impl Nac3 {
); );
} }
#[cfg(not(windows))] if let Ok(linker_status) = Command::new("ld.lld").args(linker_args).status() {
let lld_command = "ld.lld";
#[cfg(windows)]
let lld_command = "ld.lld.exe";
if let Ok(linker_status) = Command::new(lld_command).args(linker_args).status() {
if !linker_status.success() { if !linker_status.success() {
return Err(CompileError::new_err("failed to start linker")); return Err(CompileError::new_err("failed to start linker"));
} }

View File

@ -15,7 +15,7 @@ use pyo3::{
PyAny, PyObject, PyResult, Python, PyAny, PyObject, PyResult, Python,
}; };
use std::{ use std::{
collections::HashMap, collections::{HashMap, HashSet},
sync::{ sync::{
Arc, Arc,
atomic::{AtomicBool, Ordering::Relaxed} atomic::{AtomicBool, Ordering::Relaxed}
@ -54,7 +54,7 @@ pub struct InnerResolver {
pub id_to_pyval: RwLock<HashMap<StrRef, (u64, PyObject)>>, pub id_to_pyval: RwLock<HashMap<StrRef, (u64, PyObject)>>,
pub id_to_primitive: RwLock<HashMap<u64, PrimitiveValue>>, pub id_to_primitive: RwLock<HashMap<u64, PrimitiveValue>>,
pub field_to_val: RwLock<HashMap<(u64, StrRef), Option<(u64, PyObject)>>>, pub field_to_val: RwLock<HashMap<(u64, StrRef), Option<(u64, PyObject)>>>,
pub global_value_ids: Arc<RwLock<HashMap<u64, PyObject>>>, pub global_value_ids: Arc<RwLock<HashSet<u64>>>,
pub class_names: Mutex<HashMap<StrRef, Type>>, pub class_names: Mutex<HashMap<StrRef, Type>>,
pub pyid_to_def: Arc<RwLock<HashMap<u64, DefinitionId>>>, pub pyid_to_def: Arc<RwLock<HashMap<u64, DefinitionId>>>,
pub pyid_to_type: Arc<RwLock<HashMap<u64, Type>>>, pub pyid_to_type: Arc<RwLock<HashMap<u64, Type>>>,
@ -131,7 +131,6 @@ impl StaticValue for PythonValue {
&self, &self,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
expected_ty: Type,
) -> Result<BasicValueEnum<'ctx>, String> { ) -> Result<BasicValueEnum<'ctx>, String> {
if let Some(val) = self.resolver.id_to_primitive.read().get(&self.id) { if let Some(val) = self.resolver.id_to_primitive.read().get(&self.id) {
return Ok(match val { return Ok(match val {
@ -151,7 +150,7 @@ impl StaticValue for PythonValue {
Python::with_gil(|py| -> PyResult<BasicValueEnum<'ctx>> { Python::with_gil(|py| -> PyResult<BasicValueEnum<'ctx>> {
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)
.map(Option::unwrap) .map(Option::unwrap)
}).map_err(|e| e.to_string()) }).map_err(|e| e.to_string())
} }
@ -170,16 +169,6 @@ impl StaticValue for PythonValue {
let helper = &self.resolver.helper; let helper = &self.resolver.helper;
let ty = helper.type_fn.call1(py, (&self.value,))?; let ty = helper.type_fn.call1(py, (&self.value,))?;
let ty_id: u64 = helper.id_fn.call1(py, (ty,))?.extract(py)?; let ty_id: u64 = helper.id_fn.call1(py, (ty,))?.extract(py)?;
// for optimizing unwrap KernelInvariant
if ty_id == self.resolver.primitive_ids.option && name == "_nac3_option".into() {
let obj = self.value.getattr(py, &name.to_string())?;
let id = self.resolver.helper.id_fn.call1(py, (&obj,))?.extract(py)?;
if self.id == self.resolver.primitive_ids.none {
return Ok(None)
} else {
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() };
let mut mutable = true; let mut mutable = true;
let defs = ctx.top_level.definitions.read(); let defs = ctx.top_level.definitions.read();
@ -212,28 +201,6 @@ impl StaticValue for PythonValue {
})) }))
}) })
} }
fn get_tuple_element<'ctx>(&self, index: u32) -> Option<ValueEnum<'ctx>> {
Python::with_gil(|py| -> PyResult<Option<(u64, PyObject)>> {
let helper = &self.resolver.helper;
let ty = helper.type_fn.call1(py, (&self.value,))?;
let ty_id: u64 = helper.id_fn.call1(py, (ty,))?.extract(py)?;
assert_eq!(ty_id, self.resolver.primitive_ids.tuple);
let tup: &PyTuple = self.value.extract(py)?;
let elem = tup.get_item(index as usize);
let id = self.resolver.helper.id_fn.call1(py, (elem,))?.extract(py)?;
Ok(Some((id, elem.into())))
})
.unwrap()
.map(|(id, obj)| {
ValueEnum::Static(Arc::new(PythonValue {
id,
value: obj,
store_obj: self.store_obj.clone(),
resolver: self.resolver.clone(),
}))
})
}
} }
impl InnerResolver { impl InnerResolver {
@ -302,8 +269,6 @@ impl InnerResolver {
Ok(Ok((primitives.bool, true))) Ok(Ok((primitives.bool, true)))
} else if ty_id == self.primitive_ids.float { } else if ty_id == self.primitive_ids.float {
Ok(Ok((primitives.float, true))) Ok(Ok((primitives.float, true)))
} else if ty_id == self.primitive_ids.float64 {
Ok(Ok((primitives.float, true)))
} else if ty_id == self.primitive_ids.exception { } else if ty_id == self.primitive_ids.exception {
Ok(Ok((primitives.exception, true))) Ok(Ok((primitives.exception, true)))
} else if ty_id == self.primitive_ids.list { } else if ty_id == self.primitive_ids.list {
@ -538,7 +503,7 @@ impl InnerResolver {
} }
} }
pub fn get_obj_type( fn get_obj_type(
&self, &self,
py: Python, py: Python,
obj: &PyAny, obj: &PyAny,
@ -547,8 +512,8 @@ impl InnerResolver {
primitives: &PrimitiveStore, primitives: &PrimitiveStore,
) -> PyResult<Result<Type, String>> { ) -> PyResult<Result<Type, String>> {
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 ty_id: u64 = self.helper.id_fn.call1(py, (ty.clone(),))?.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(&ty_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(
@ -579,7 +544,7 @@ 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)?;
if len == 0 { if len == 0 {
assert!(matches!( assert!(matches!(
&*unifier.get_ty(*ty), &*unifier.get_ty(extracted_ty),
TypeEnum::TVar { fields: None, range, .. } TypeEnum::TVar { fields: None, range, .. }
if range.is_empty() if range.is_empty()
)); ));
@ -655,7 +620,6 @@ impl InnerResolver {
Ok(Ok(res)) Ok(Ok(res))
} }
(TypeEnum::TObj { params, fields, .. }, false) => { (TypeEnum::TObj { params, fields, .. }, false) => {
self.pyid_to_type.write().insert(py_obj_id, extracted_ty);
let var_map = params let var_map = params
.iter() .iter()
.map(|(id_var, ty)| { .map(|(id_var, ty)| {
@ -709,25 +673,18 @@ impl InnerResolver {
let extracted_ty = unifier.subst(extracted_ty, &var_map).unwrap_or(extracted_ty); let extracted_ty = unifier.subst(extracted_ty, &var_map).unwrap_or(extracted_ty);
Ok(Ok(extracted_ty)) Ok(Ok(extracted_ty))
}; };
let result = instantiate_obj(); instantiate_obj()
// update/remove the cache according to the result
match result {
Ok(Ok(ty)) => self.pyid_to_type.write().insert(py_obj_id, ty),
_ => self.pyid_to_type.write().remove(&py_obj_id)
};
result
} }
_ => Ok(Ok(extracted_ty)), _ => Ok(Ok(extracted_ty)),
} }
} }
pub fn get_obj_value<'ctx, 'a>( fn get_obj_value<'ctx, 'a>(
&self, &self,
py: Python, py: Python,
obj: &PyAny, obj: &PyAny,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
expected_ty: Type,
) -> PyResult<Option<BasicValueEnum<'ctx>>> { ) -> PyResult<Option<BasicValueEnum<'ctx>>> {
let ty_id: u64 = let ty_id: u64 =
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)?;
@ -757,7 +714,7 @@ impl InnerResolver {
format!("{} is not in the range of bool", obj)))?; 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 {
let val: f64 = obj.extract().map_err(|_| super::CompileError::new_err( let val: f64 = obj.extract().map_err(|_| super::CompileError::new_err(
format!("{} is not in the range of float64", obj)))?; 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));
@ -770,39 +727,40 @@ 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 = let ty = if len == 0 {
if let TypeEnum::TList { ty } = ctx.unifier.get_ty_immutable(expected_ty).as_ref() ctx.primitives.int32
{
*ty
} else { } else {
unreachable!("must be list") self.get_list_elem_type(
py,
obj,
len,
&mut ctx.unifier,
&ctx.top_level.definitions.read(),
&ctx.primitives,
)?
.unwrap()
}; };
let ty = ctx.get_llvm_type(generator, elem_ty); let ty = ctx.get_llvm_type(generator, ty);
let size_t = generator.get_size_type(ctx.ctx); let size_t = generator.get_size_type(ctx.ctx);
let arr_ty = ctx let arr_ty = ctx
.ctx .ctx
.struct_type(&[ty.ptr_type(AddressSpace::Generic).into(), size_t.into()], false); .struct_type(&[ty.ptr_type(AddressSpace::Generic).into(), size_t.into()], false);
{ {
if self.global_value_ids.read().contains_key(&id) { if self.global_value_ids.read().contains(&id) {
let global = ctx.module.get_global(&id_str).unwrap_or_else(|| { let global = ctx.module.get_global(&id_str).unwrap_or_else(|| {
ctx.module.add_global(arr_ty, Some(AddressSpace::Generic), &id_str) ctx.module.add_global(arr_ty, Some(AddressSpace::Generic), &id_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);
} }
} }
let arr: Result<Option<Vec<_>>, _> = (0..len) let arr: Result<Option<Vec<_>>, _> = (0..len)
.map(|i| { .map(|i| {
obj obj.get_item(i).and_then(|elem| self.get_obj_value(py, elem, ctx, generator).map_err(
.get_item(i) |e| super::CompileError::new_err(format!("Error getting element {}: {}", i, e))))
.and_then(|elem| self.get_obj_value(py, elem, ctx, generator, elem_ty)
.map_err(
|e| super::CompileError::new_err(
format!("Error getting element {}: {}", i, e))
))
}) })
.collect(); .collect();
let arr = arr?.unwrap(); let arr = arr?.unwrap();
@ -843,48 +801,58 @@ impl InnerResolver {
Ok(Some(global.as_pointer_value().into())) Ok(Some(global.as_pointer_value().into()))
} else if ty_id == self.primitive_ids.tuple { } else if ty_id == self.primitive_ids.tuple {
if let TypeEnum::TTuple { ty } = ctx.unifier.get_ty_immutable(expected_ty).as_ref() { let id_str = id.to_string();
let tup_tys = ty.iter();
let elements: &PyTuple = obj.cast_as()?; if let Some(global) = ctx.module.get_global(&id_str) {
assert_eq!(elements.len(), tup_tys.len()); return Ok(Some(global.as_pointer_value().into()));
let val: Result<Option<Vec<_>>, _> =
elements
.iter()
.enumerate()
.zip(tup_tys)
.map(|((i, elem), ty)| self
.get_obj_value(py, elem, ctx, generator, *ty).map_err(|e|
super::CompileError::new_err(
format!("Error getting element {}: {}", i, e)
)
)
).collect();
let val = val?.unwrap();
let val = ctx.ctx.const_struct(&val, false);
Ok(Some(val.into()))
} else {
unreachable!("must expect tuple type")
} }
} else if ty_id == self.primitive_ids.option {
let option_val_ty = match ctx.unifier.get_ty_immutable(expected_ty).as_ref() { let elements: &PyTuple = obj.cast_as()?;
TypeEnum::TObj { obj_id, params, .. } let types: Result<Result<Vec<_>, _>, _> = elements
if *obj_id == ctx.primitives.option.get_obj_id(&ctx.unifier) => .iter()
{ .enumerate()
*params.iter().next().unwrap().1 .map(|(i, elem)| {
self.get_obj_type(
py,
elem,
&mut ctx.unifier,
&ctx.top_level.definitions.read(),
&ctx.primitives,
)
.map_err(|e| super::CompileError::new_err(format!("Error getting element {}: {}", i, e)))
.map(|ty| ty.map(|ty| ctx.get_llvm_type(generator, ty)))
})
.collect();
let types = types?.unwrap();
let ty = ctx.ctx.struct_type(&types, false);
{
if self.global_value_ids.read().contains(&id) {
let global = ctx.module.get_global(&id_str).unwrap_or_else(|| {
ctx.module.add_global(ty, Some(AddressSpace::Generic), &id_str)
});
return Ok(Some(global.as_pointer_value().into()));
} else {
self.global_value_ids.write().insert(id);
} }
_ => unreachable!("must be option type") }
};
let val: Result<Option<Vec<_>>, _> =
elements.iter().enumerate().map(|(i, elem)| self.get_obj_value(py, elem, ctx, generator).map_err(|e|
super::CompileError::new_err(format!("Error getting element {}: {}", i, e)))).collect();
let val = val?.unwrap();
let val = ctx.ctx.const_struct(&val, false);
let global = ctx.module.add_global(ty, Some(AddressSpace::Generic), &id_str);
global.set_initializer(&val);
Ok(Some(global.as_pointer_value().into()))
} else if ty_id == self.primitive_ids.option {
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, whose type needs to be casted in codegen
Ok(Some( // according to the type info attached in the ast
ctx.get_llvm_type(generator, option_val_ty) Ok(Some(ctx.ctx.i8_type().ptr_type(AddressSpace::Generic).const_null().into()))
.ptr_type(AddressSpace::Generic)
.const_null()
.into(),
))
} else { } else {
match self match self
.get_obj_value(py, obj.getattr("_nac3_option").unwrap(), ctx, generator, option_val_ty) .get_obj_value(py, obj.getattr("_nac3_option").unwrap(), ctx, generator)
.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: {}",
@ -894,13 +862,13 @@ impl InnerResolver {
Some(v) => { Some(v) => {
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(&id) {
let global = ctx.module.get_global(&global_str).unwrap_or_else(|| { let global = 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);
} }
} }
let global = ctx.module.add_global(v.get_type(), Some(AddressSpace::Generic), &global_str); let global = ctx.module.add_global(v.get_type(), Some(AddressSpace::Generic), &global_str);
@ -927,13 +895,13 @@ impl InnerResolver {
.get_element_type() .get_element_type()
.into_struct_type(); .into_struct_type();
{ {
if self.global_value_ids.read().contains_key(&id) { if self.global_value_ids.read().contains(&id) {
let global = ctx.module.get_global(&id_str).unwrap_or_else(|| { let global = ctx.module.get_global(&id_str).unwrap_or_else(|| {
ctx.module.add_global(ty, Some(AddressSpace::Generic), &id_str) ctx.module.add_global(ty, Some(AddressSpace::Generic), &id_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);
} }
} }
// should be classes // should be classes
@ -942,17 +910,15 @@ impl InnerResolver {
if let TopLevelDef::Class { fields, .. } = &*definition { if let TopLevelDef::Class { fields, .. } = &*definition {
let values: Result<Option<Vec<_>>, _> = fields let values: Result<Option<Vec<_>>, _> = fields
.iter() .iter()
.map(|(name, ty, _)| { .map(|(name, _, _)| {
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).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?;
if let Some(values) = values { if let Some(values) = values {
let val = ty.const_named_struct(&values); let val = ty.const_named_struct(&values);
let global = ctx.module.get_global(&id_str).unwrap_or_else(|| { let global = ctx.module.add_global(ty, Some(AddressSpace::Generic), &id_str);
ctx.module.add_global(ty, Some(AddressSpace::Generic), &id_str)
});
global.set_initializer(&val); global.set_initializer(&val);
Ok(Some(global.as_pointer_value().into())) Ok(Some(global.as_pointer_value().into()))
} else { } else {
@ -969,7 +935,6 @@ impl InnerResolver {
py: Python, py: Python,
obj: &PyAny, obj: &PyAny,
) -> PyResult<Result<SymbolValue, String>> { ) -> PyResult<Result<SymbolValue, String>> {
let id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
let ty_id: u64 = let ty_id: u64 =
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)?;
Ok(if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 { Ok(if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 {
@ -978,33 +943,23 @@ impl InnerResolver {
} else if ty_id == self.primitive_ids.int64 { } else if ty_id == self.primitive_ids.int64 {
let val: i64 = obj.extract()?; let val: i64 = obj.extract()?;
Ok(SymbolValue::I64(val)) Ok(SymbolValue::I64(val))
} else if ty_id == self.primitive_ids.uint32 {
let val: u32 = obj.extract()?;
Ok(SymbolValue::U32(val))
} else if ty_id == self.primitive_ids.uint64 {
let val: u64 = obj.extract()?;
Ok(SymbolValue::U64(val))
} else if ty_id == self.primitive_ids.bool { } else if ty_id == self.primitive_ids.bool {
let val: bool = obj.extract()?; let val: bool = obj.extract()?;
Ok(SymbolValue::Bool(val)) Ok(SymbolValue::Bool(val))
} else if ty_id == self.primitive_ids.float || ty_id == self.primitive_ids.float64 { } else if ty_id == self.primitive_ids.float {
let val: f64 = obj.extract()?; let val: f64 = obj.extract()?;
Ok(SymbolValue::Double(val)) Ok(SymbolValue::Double(val))
} else if ty_id == self.primitive_ids.tuple { } else if ty_id == self.primitive_ids.tuple {
let elements: &PyTuple = obj.cast_as()?; let elements: &PyTuple = obj.cast_as()?;
let elements: Result<Result<Vec<_>, String>, _> = let elements: Result<Result<Vec<_>, String>, _> =
elements.iter().map(|elem| self.get_default_param_obj_value(py, elem)).collect(); elements.iter().map(|elem| self.get_default_param_obj_value(py, elem)).collect();
elements?.map(SymbolValue::Tuple) let elements = match elements? {
} else if ty_id == self.primitive_ids.option { Ok(el) => el,
if id == self.primitive_ids.none { Err(err) => return Ok(Err(err)),
Ok(SymbolValue::OptionNone) };
} else { Ok(SymbolValue::Tuple(elements))
self
.get_default_param_obj_value(py, obj.getattr("_nac3_option").unwrap())?
.map(|v| SymbolValue::OptionSome(Box::new(v)))
}
} else { } else {
Err("only primitives values, option and tuple can be default parameter value".into()) Err("only primitives values and tuple can be default parameter value".into())
}) })
} }
} }
@ -1020,9 +975,8 @@ impl SymbolResolver for Resolver {
for (key, val) in members.iter() { for (key, val) in members.iter() {
let key: &str = key.extract()?; let key: &str = key.extract()?;
if key == id.to_string() { if key == id.to_string() {
if let Ok(Ok(v)) = self.0.get_default_param_obj_value(py, val) { sym_value =
sym_value = Some(v) Some(self.0.get_default_param_obj_value(py, val).unwrap().unwrap());
}
break; break;
} }
} }
@ -1030,7 +984,7 @@ impl SymbolResolver for Resolver {
}) })
.unwrap() .unwrap()
} }
_ => unreachable!("only for resolving names"), _ => unimplemented!("other type of expr not supported at {}", expr.location),
} }
} }

View File

@ -14,7 +14,6 @@ use crate::{
}; };
use inkwell::{ use inkwell::{
AddressSpace, AddressSpace,
debug_info::AsDIScope,
attributes::{Attribute, AttributeLoc}, attributes::{Attribute, AttributeLoc},
types::{AnyType, BasicType, BasicTypeEnum}, types::{AnyType, BasicType, BasicTypeEnum},
values::{BasicValueEnum, FunctionValue, IntValue, PointerValue} values::{BasicValueEnum, FunctionValue, IntValue, PointerValue}
@ -92,7 +91,6 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
&mut self, &mut self,
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
val: &SymbolValue, val: &SymbolValue,
ty: Type,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
match val { match val {
SymbolValue::I32(v) => self.ctx.i32_type().const_int(*v as u64, true).into(), SymbolValue::I32(v) => self.ctx.i32_type().const_int(*v as u64, true).into(),
@ -109,7 +107,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
ty.const_named_struct(&[str_ptr, size.into()]).into() ty.const_named_struct(&[str_ptr, size.into()]).into()
} }
SymbolValue::Tuple(ls) => { SymbolValue::Tuple(ls) => {
let vals = ls.iter().map(|v| self.gen_symbol_val(generator, v, ty)).collect_vec(); let vals = ls.iter().map(|v| self.gen_symbol_val(generator, v)).collect_vec();
let fields = vals.iter().map(|v| v.get_type()).collect_vec(); let fields = vals.iter().map(|v| v.get_type()).collect_vec();
let ty = self.ctx.struct_type(&fields, false); let ty = self.ctx.struct_type(&fields, false);
let ptr = self.builder.build_alloca(ty, "tuple"); let ptr = self.builder.build_alloca(ty, "tuple");
@ -126,33 +124,6 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
} }
self.builder.build_load(ptr, "tup_val") self.builder.build_load(ptr, "tup_val")
} }
SymbolValue::OptionSome(v) => {
let ty = match self.unifier.get_ty_immutable(ty).as_ref() {
TypeEnum::TObj { obj_id, params, .. }
if *obj_id == self.primitives.option.get_obj_id(&self.unifier) =>
{
*params.iter().next().unwrap().1
}
_ => unreachable!("must be option type"),
};
let val = self.gen_symbol_val(generator, v, ty);
let ptr = self.builder.build_alloca(val.get_type(), "default_opt_some");
self.builder.build_store(ptr, val);
ptr.into()
}
SymbolValue::OptionNone => {
let ty = match self.unifier.get_ty_immutable(ty).as_ref() {
TypeEnum::TObj { obj_id, params, .. }
if *obj_id == self.primitives.option.get_obj_id(&self.unifier) =>
{
*params.iter().next().unwrap().1
}
_ => unreachable!("must be option type"),
};
let actual_ptr_type =
self.get_llvm_type(generator, ty).ptr_type(AddressSpace::Generic);
actual_ptr_type.const_null().into()
}
} }
} }
@ -235,7 +206,6 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
pub fn gen_int_ops( pub fn gen_int_ops(
&mut self, &mut self,
generator: &mut dyn CodeGenerator,
op: &Operator, op: &Operator,
lhs: BasicValueEnum<'ctx>, lhs: BasicValueEnum<'ctx>,
rhs: BasicValueEnum<'ctx>, rhs: BasicValueEnum<'ctx>,
@ -271,7 +241,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
(Operator::RShift, _) => self.builder.build_right_shift(lhs, rhs, true, "rshift").into(), (Operator::RShift, _) => 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, 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, 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(self, lhs, rhs, s).into(),
// special implementation? // special implementation?
(Operator::MatMult, _) => unreachable!(), (Operator::MatMult, _) => unreachable!(),
} }
@ -385,17 +355,17 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
} }
} }
pub fn gen_string<S: Into<String>>( pub fn gen_string<G: CodeGenerator, S: Into<String>>(
&mut self, &mut self,
generator: &mut dyn CodeGenerator, generator: &mut G,
s: S, s: S,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
self.gen_const(generator, &nac3parser::ast::Constant::Str(s.into()), self.primitives.str) self.gen_const(generator, &nac3parser::ast::Constant::Str(s.into()), self.primitives.str)
} }
pub fn raise_exn( pub fn raise_exn<G: CodeGenerator>(
&mut self, &mut self,
generator: &mut dyn CodeGenerator, generator: &mut G,
name: &str, name: &str,
msg: BasicValueEnum<'ctx>, msg: BasicValueEnum<'ctx>,
params: [Option<IntValue<'ctx>>; 3], params: [Option<IntValue<'ctx>>; 3],
@ -432,27 +402,14 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
gen_raise(generator, self, Some(&zelf.into()), loc); gen_raise(generator, self, Some(&zelf.into()), loc);
} }
pub fn make_assert( pub fn make_assert<G: CodeGenerator>(
&mut self, &mut self,
generator: &mut dyn CodeGenerator, generator: &mut G,
cond: IntValue<'ctx>, cond: IntValue<'ctx>,
err_name: &str, err_name: &str,
err_msg: &str, err_msg: &str,
params: [Option<IntValue<'ctx>>; 3], params: [Option<IntValue<'ctx>>; 3],
loc: Location, loc: Location,
) {
let err_msg = self.gen_string(generator, err_msg);
self.make_assert_impl(generator, cond, err_name, err_msg, params, loc)
}
pub fn make_assert_impl(
&mut self,
generator: &mut dyn CodeGenerator,
cond: IntValue<'ctx>,
err_name: &str,
err_msg: BasicValueEnum<'ctx>,
params: [Option<IntValue<'ctx>>; 3],
loc: Location,
) { ) {
let i1 = self.ctx.bool_type(); let i1 = self.ctx.bool_type();
let i1_true = i1.const_all_ones(); let i1_true = i1.const_all_ones();
@ -479,6 +436,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
let exn_block = self.ctx.append_basic_block(current_fun, "fail"); let exn_block = self.ctx.append_basic_block(current_fun, "fail");
self.builder.build_conditional_branch(cond, then_block, exn_block); self.builder.build_conditional_branch(cond, then_block, exn_block);
self.builder.position_at_end(exn_block); self.builder.position_at_end(exn_block);
let err_msg = self.gen_string(generator, err_msg);
self.raise_exn(generator, err_name, err_msg, params, loc); self.raise_exn(generator, err_name, err_msg, params, loc);
self.builder.position_at_end(then_block); self.builder.position_at_end(then_block);
} }
@ -635,19 +593,19 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
} }
mapping.insert( mapping.insert(
k.name, k.name,
ctx.gen_symbol_val(generator, &k.default_value.unwrap(), k.ty).into(), ctx.gen_symbol_val(generator, &k.default_value.unwrap()).into(),
); );
} }
// reorder the parameters // reorder the parameters
let mut real_params = let mut real_params =
fun.0.args.iter().map(|arg| (mapping.remove(&arg.name).unwrap(), arg.ty)).collect_vec(); fun.0.args.iter().map(|arg| mapping.remove(&arg.name).unwrap()).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());
} }
let static_params = real_params let static_params = real_params
.iter() .iter()
.enumerate() .enumerate()
.filter_map(|(i, (v, _))| { .filter_map(|(i, v)| {
if let ValueEnum::Static(s) = v { if let ValueEnum::Static(s) = v {
Some((i, s.clone())) Some((i, s.clone()))
} else { } else {
@ -679,7 +637,7 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
}; };
param_vals = real_params param_vals = real_params
.into_iter() .into_iter()
.map(|(p, t)| p.to_basic_value_enum(ctx, generator, t)) .map(|p| p.to_basic_value_enum(ctx, generator))
.collect::<Result<Vec<_>, String>>()?; .collect::<Result<Vec<_>, String>>()?;
instance_to_symbol.get(&key).cloned().ok_or_else(|| "".into()) instance_to_symbol.get(&key).cloned().ok_or_else(|| "".into())
} }
@ -792,7 +750,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(ctx, generator, iter.custom.unwrap())?; let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(ctx, generator)?;
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();
@ -897,7 +855,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
let result = generator let result = generator
.gen_expr(ctx, cond)? .gen_expr(ctx, cond)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, cond.custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.into_int_value(); .into_int_value();
let succ = ctx.ctx.append_basic_block(current, "then"); let succ = ctx.ctx.append_basic_block(current, "then");
ctx.builder.build_conditional_branch(result, succ, test_bb); ctx.builder.build_conditional_branch(result, succ, test_bb);
@ -906,7 +864,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
let elem = generator.gen_expr(ctx, elt)?.unwrap(); let elem = generator.gen_expr(ctx, elt)?.unwrap();
let i = ctx.builder.build_load(index, "i").into_int_value(); let i = ctx.builder.build_load(index, "i").into_int_value();
let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") }; let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") };
let val = elem.to_basic_value_enum(ctx, generator, elt.custom.unwrap())?; let val = elem.to_basic_value_enum(ctx, generator)?;
ctx.builder.build_store(elem_ptr, val); ctx.builder.build_store(elem_ptr, val);
ctx.builder ctx.builder
.build_store(index, ctx.builder.build_int_add(i, size_t.const_int(1, false), "inc")); .build_store(index, ctx.builder.build_int_add(i, size_t.const_int(1, false), "inc"));
@ -931,27 +889,30 @@ pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
) -> Result<ValueEnum<'ctx>, String> { ) -> Result<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 = generator.gen_expr(ctx, left)?.unwrap().to_basic_value_enum(ctx, generator, left.custom.unwrap())?; let left = generator.gen_expr(ctx, left)?.unwrap().to_basic_value_enum(ctx, generator)?;
let right = generator.gen_expr(ctx, right)?.unwrap().to_basic_value_enum(ctx, generator, right.custom.unwrap())?; let right = generator.gen_expr(ctx, right)?.unwrap().to_basic_value_enum(ctx, generator)?;
// 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
Ok(if ty1 == ty2 && [ctx.primitives.int32, ctx.primitives.int64].contains(&ty1) { Ok(if ty1 == ty2 && [ctx.primitives.int32, ctx.primitives.int64].contains(&ty1) {
ctx.gen_int_ops(generator, op, left, right, true) ctx.gen_int_ops(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) {
ctx.gen_int_ops(generator, op, left, right, false) ctx.gen_int_ops(op, left, right, false)
} else if ty1 == ty2 && ctx.primitives.float == ty1 { } else if ty1 == ty2 && ctx.primitives.float == ty1 {
ctx.gen_float_ops(op, left, right) 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);
let i32_t = ctx.ctx.i32_type(); // TODO: throw exception when rhs is out of i16 bound
let pow_intr = ctx.module.get_function("llvm.powi.f64.i32").unwrap_or_else(|| { // since llvm intrinsic only support to i16 for f64
let i16_t = ctx.ctx.i16_type();
let pow_intr = ctx.module.get_function("llvm.powi.f64.i16").unwrap_or_else(|| {
let f64_t = ctx.ctx.f64_type(); let f64_t = ctx.ctx.f64_type();
let ty = f64_t.fn_type(&[f64_t.into(), i32_t.into()], false); let ty = f64_t.fn_type(&[f64_t.into(), i16_t.into()], false);
ctx.module.add_function("llvm.powi.f64.i32", ty, None) ctx.module.add_function("llvm.powi.f64.i16", ty, None)
}); });
let right = ctx.builder.build_int_truncate(right.into_int_value(), i16_t, "r_pow");
ctx.builder ctx.builder
.build_call(pow_intr, &[left.into(), right.into()], "f_pow_i") .build_call(pow_intr, &[left.into(), right.into()], "f_pow_i")
.try_as_basic_value() .try_as_basic_value()
@ -967,19 +928,8 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
expr: &Expr<Option<Type>>, expr: &Expr<Option<Type>>,
) -> Result<Option<ValueEnum<'ctx>>, String> { ) -> Result<Option<ValueEnum<'ctx>>, String> {
ctx.current_loc = expr.location;
let int32 = ctx.ctx.i32_type(); let int32 = ctx.ctx.i32_type();
let zero = int32.const_int(0, false); let zero = int32.const_int(0, false);
let loc = ctx.debug_info.0.create_debug_location(
ctx.ctx,
ctx.current_loc.row as u32,
ctx.current_loc.column as u32,
ctx.debug_info.2.as_debug_info_scope(),
None,
);
ctx.builder.set_current_debug_location(ctx.ctx, loc);
Ok(Some(match &expr.node { Ok(Some(match &expr.node {
ExprKind::Constant { value, .. } => { ExprKind::Constant { value, .. } => {
let ty = expr.custom.unwrap(); let ty = expr.custom.unwrap();
@ -1006,7 +956,30 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
Some((_, Some(static_value), _)) => ValueEnum::Static(static_value.clone()), Some((_, Some(static_value), _)) => ValueEnum::Static(static_value.clone()),
None => { None => {
let resolver = ctx.resolver.clone(); let resolver = ctx.resolver.clone();
resolver.get_symbol_value(*id, ctx).unwrap() let val = resolver.get_symbol_value(*id, ctx).unwrap();
// if is tuple, need to deref it to handle tuple as value
// if is option, need to cast pointer to handle None
match (
&*ctx.unifier.get_ty(expr.custom.unwrap()),
resolver
.get_symbol_value(*id, ctx)
.unwrap()
.to_basic_value_enum(ctx, generator)?,
) {
(TypeEnum::TTuple { .. }, BasicValueEnum::PointerValue(ptr)) => {
ctx.builder.build_load(ptr, "tup_val").into()
}
(TypeEnum::TObj { obj_id, params, .. }, BasicValueEnum::PointerValue(ptr))
if *obj_id == ctx.primitives.option.get_obj_id(&ctx.unifier) => {
let actual_ptr_ty = ctx.get_llvm_type(
generator,
*params.iter().next().unwrap().1,
)
.ptr_type(AddressSpace::Generic);
ctx.builder.build_bitcast(ptr, actual_ptr_ty, "option_ptr_cast").into()
}
_ => val,
}
} }
}, },
ExprKind::List { elts, .. } => { ExprKind::List { elts, .. } => {
@ -1017,10 +990,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
.map(|x| { .map(|x| {
generator generator
.gen_expr(ctx, x) .gen_expr(ctx, x)
.map_or_else( .map_or_else(|e| Err(e), |v| v.unwrap().to_basic_value_enum(ctx, generator))
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() {
@ -1053,7 +1023,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
.map(|x| { .map(|x| {
generator generator
.gen_expr(ctx, x) .gen_expr(ctx, x)
.map_or_else(Err, |v| v.unwrap().to_basic_value_enum(ctx, generator, x.custom.unwrap())) .map_or_else(|e| Err(e), |v| v.unwrap().to_basic_value_enum(ctx, generator))
}) })
.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();
@ -1075,13 +1045,13 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
// 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)?;
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)?, }, |v| Ok(v))?,
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(
@ -1096,7 +1066,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
let left = generator let left = generator
.gen_expr(ctx, &values[0])? .gen_expr(ctx, &values[0])?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, values[0].custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.into_int_value(); .into_int_value();
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap(); let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
let a_bb = ctx.ctx.append_basic_block(current, "a"); let a_bb = ctx.ctx.append_basic_block(current, "a");
@ -1112,7 +1082,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
let b = generator let b = generator
.gen_expr(ctx, &values[1])? .gen_expr(ctx, &values[1])?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.into_int_value(); .into_int_value();
ctx.builder.build_unconditional_branch(cont_bb); ctx.builder.build_unconditional_branch(cont_bb);
(a, b) (a, b)
@ -1122,7 +1092,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
let a = generator let a = generator
.gen_expr(ctx, &values[1])? .gen_expr(ctx, &values[1])?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.into_int_value(); .into_int_value();
ctx.builder.build_unconditional_branch(cont_bb); ctx.builder.build_unconditional_branch(cont_bb);
ctx.builder.position_at_end(b_bb); ctx.builder.position_at_end(b_bb);
@ -1140,9 +1110,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
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 = let val =
generator.gen_expr(ctx, operand)? generator.gen_expr(ctx, operand)?.unwrap().to_basic_value_enum(ctx, generator)?;
.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 {
@ -1202,11 +1170,11 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
generator generator
.gen_expr(ctx, lhs)? .gen_expr(ctx, lhs)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, lhs.custom.unwrap())?, .to_basic_value_enum(ctx, generator)?,
generator generator
.gen_expr(ctx, rhs)? .gen_expr(ctx, rhs)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, rhs.custom.unwrap())?, .to_basic_value_enum(ctx, generator)?,
) { ) {
(lhs, rhs) (lhs, rhs)
} else { } else {
@ -1230,11 +1198,11 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
generator generator
.gen_expr(ctx, lhs)? .gen_expr(ctx, lhs)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, lhs.custom.unwrap())?, .to_basic_value_enum(ctx, generator)?,
generator generator
.gen_expr(ctx, rhs)? .gen_expr(ctx, rhs)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, rhs.custom.unwrap())?, .to_basic_value_enum(ctx, generator)?,
) { ) {
(lhs, rhs) (lhs, rhs)
} else { } else {
@ -1262,46 +1230,23 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
let test = generator let test = generator
.gen_expr(ctx, test)? .gen_expr(ctx, test)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, test.custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.into_int_value(); .into_int_value();
let body_ty = body.custom.unwrap();
let is_none = ctx.unifier.get_representative(body_ty) == ctx.primitives.none;
let result = if !is_none {
let llvm_ty = ctx.get_llvm_type(generator, body_ty);
Some(ctx.builder.build_alloca(llvm_ty, "if_exp_result"))
} else {
None
};
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap(); let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
let then_bb = ctx.ctx.append_basic_block(current, "then"); let then_bb = ctx.ctx.append_basic_block(current, "then");
let else_bb = ctx.ctx.append_basic_block(current, "else"); let else_bb = ctx.ctx.append_basic_block(current, "else");
let cont_bb = ctx.ctx.append_basic_block(current, "cont"); let cont_bb = ctx.ctx.append_basic_block(current, "cont");
ctx.builder.build_conditional_branch(test, then_bb, else_bb); ctx.builder.build_conditional_branch(test, then_bb, else_bb);
ctx.builder.position_at_end(then_bb); ctx.builder.position_at_end(then_bb);
let a = generator.gen_expr(ctx, body)?; let a = generator.gen_expr(ctx, body)?.unwrap().to_basic_value_enum(ctx, generator)?;
match result {
None => None,
Some(v) => {
let a = a.unwrap().to_basic_value_enum(ctx, generator, body.custom.unwrap())?;
Some(ctx.builder.build_store(v, a))
}
};
ctx.builder.build_unconditional_branch(cont_bb); ctx.builder.build_unconditional_branch(cont_bb);
ctx.builder.position_at_end(else_bb); ctx.builder.position_at_end(else_bb);
let b = generator.gen_expr(ctx, orelse)?; let b = generator.gen_expr(ctx, orelse)?.unwrap().to_basic_value_enum(ctx, generator)?;
match result {
None => None,
Some(v) => {
let b = b.unwrap().to_basic_value_enum(ctx, generator, orelse.custom.unwrap())?;
Some(ctx.builder.build_store(v, b))
}
};
ctx.builder.build_unconditional_branch(cont_bb); ctx.builder.build_unconditional_branch(cont_bb);
ctx.builder.position_at_end(cont_bb); ctx.builder.position_at_end(cont_bb);
match result { let phi = ctx.builder.build_phi(a.get_type(), "ifexpr");
None => return Ok(None), phi.add_incoming(&[(&a, then_bb), (&b, else_bb)]);
Some(v) => return Ok(Some(ctx.builder.build_load(v, "if_exp_val_load").into())) phi.as_basic_value().into()
}
} }
ExprKind::Call { func, args, keywords } => { ExprKind::Call { func, args, keywords } => {
let mut params = args let mut params = args
@ -1365,66 +1310,23 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
} }
}; };
// directly generate code for option.unwrap // directly generate code for option.unwrap
// since it needs to return static value to optimize for kernel invariant // since it needs location information from ast
if attr == &"unwrap".into() if attr == &"unwrap".into()
&& id == ctx.primitives.option.get_obj_id(&ctx.unifier) && id == ctx.primitives.option.get_obj_id(&ctx.unifier)
{ {
match val { if let BasicValueEnum::PointerValue(ptr) = val.to_basic_value_enum(ctx, generator)? {
ValueEnum::Static(v) => match v.get_field("_nac3_option".into(), ctx) { let not_null = ctx.builder.build_is_not_null(ptr, "unwrap_not_null");
// if is none, raise exception directly ctx.make_assert(
None => { generator,
let err_msg = ctx.gen_string(generator, ""); not_null,
let current_fun = ctx "0:ValueError",
.builder "unwrap on none",
.get_insert_block() [None, None, None],
.unwrap() expr.location,
.get_parent() );
.unwrap(); return Ok(Some(ctx.builder.build_load(ptr, "unwrap_some").into()))
let unreachable_block = ctx.ctx.append_basic_block( } else {
current_fun, unreachable!("option must be ptr")
"unwrap_none_unreachable"
);
let exn_block = ctx.ctx.append_basic_block(
current_fun,
"unwrap_none_exception"
);
ctx.builder.build_unconditional_branch(exn_block);
ctx.builder.position_at_end(exn_block);
ctx.raise_exn(
generator,
"0:UnwrapNoneError",
err_msg,
[None, None, None],
ctx.current_loc
);
ctx.builder.position_at_end(unreachable_block);
let ptr = ctx
.get_llvm_type(generator, value.custom.unwrap())
.into_pointer_type()
.const_null();
return Ok(Some(ctx.builder.build_load(
ptr,
"unwrap_none_unreachable_load"
).into()));
}
Some(v) => return Ok(Some(v)),
}
ValueEnum::Dynamic(BasicValueEnum::PointerValue(ptr)) => {
let not_null = ctx.builder.build_is_not_null(ptr, "unwrap_not_null");
ctx.make_assert(
generator,
not_null,
"0:UnwrapNoneError",
"",
[None, None, None],
expr.location,
);
return Ok(Some(ctx.builder.build_load(
ptr,
"unwrap_some_load"
).into()))
}
_ => unreachable!("option must be static or ptr")
} }
} }
return Ok(generator return Ok(generator
@ -1444,7 +1346,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
let v = generator let v = generator
.gen_expr(ctx, value)? .gen_expr(ctx, value)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, value.custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.into_pointer_value(); .into_pointer_value();
let ty = ctx.get_llvm_type(generator, *ty); let ty = ctx.get_llvm_type(generator, *ty);
let arr_ptr = ctx.build_gep_and_load(v, &[zero, zero]).into_pointer_value(); let arr_ptr = ctx.build_gep_and_load(v, &[zero, zero]).into_pointer_value();
@ -1453,7 +1355,6 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
let (start, end, step) = let (start, end, step) =
handle_slice_indices(lower, upper, step, ctx, generator, v)?; handle_slice_indices(lower, upper, step, ctx, generator, v)?;
let length = calculate_len_for_slice_range( let length = calculate_len_for_slice_range(
generator,
ctx, ctx,
start, start,
ctx.builder ctx.builder
@ -1475,8 +1376,8 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
let res_ind = let res_ind =
handle_slice_indices(&None, &None, &None, ctx, generator, res_array_ret)?; handle_slice_indices(&None, &None, &None, ctx, generator, res_array_ret)?;
list_slice_assignment( list_slice_assignment(
generator,
ctx, ctx,
generator.get_size_type(ctx.ctx),
ty, ty,
res_array_ret, res_array_ret,
res_ind, res_ind,
@ -1491,7 +1392,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
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)?
.into_int_value(); .into_int_value();
let raw_index = ctx.builder.build_int_s_extend( let raw_index = ctx.builder.build_int_s_extend(
raw_index, raw_index,
@ -1526,39 +1427,26 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
[Some(raw_index), Some(len), None], [Some(raw_index), Some(len), None],
expr.location, expr.location,
); );
ctx.build_gep_and_load(arr_ptr, &[index]).into() ctx.build_gep_and_load(arr_ptr, &[index])
} }
} else if let TypeEnum::TTuple { .. } = &*ctx.unifier.get_ty(value.custom.unwrap()) { } else if let TypeEnum::TTuple { .. } = &*ctx.unifier.get_ty(value.custom.unwrap()) {
let v = generator
.gen_expr(ctx, value)?
.unwrap()
.to_basic_value_enum(ctx, generator)?
.into_struct_value();
let index: u32 = let index: u32 =
if let ExprKind::Constant { value: ast::Constant::Int(v), .. } = &slice.node { if let ExprKind::Constant { value: ast::Constant::Int(v), .. } = &slice.node {
(*v).try_into().unwrap() (*v).try_into().unwrap()
} 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 ctx.builder.build_extract_value(v, index, "tup_elem").unwrap()
.gen_expr(ctx, value)?
.unwrap();
match v {
ValueEnum::Dynamic(v) => {
let v = v.into_struct_value();
ctx.builder.build_extract_value(v, index, "tup_elem").unwrap().into()
}
ValueEnum::Static(v) => {
match v.get_tuple_element(index) {
Some(v) => v,
None => {
let tup = v
.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
.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");
} }
}, }
.into(),
ExprKind::ListComp { .. } => gen_comprehension(generator, ctx, expr)?.into(), ExprKind::ListComp { .. } => gen_comprehension(generator, ctx, expr)?.into(),
_ => unimplemented!(), _ => unimplemented!(),
})) }))

View File

@ -36,7 +36,7 @@ pub trait CodeGenerator {
} }
/// Generate object constructor and returns the constructed object. /// Generate object constructor and returns the constructed object.
/// - signature: Function signature of the constructor. /// - signature: Function signature of the contructor.
/// - def: Class definition for the constructor class. /// - def: Class definition for the constructor class.
/// - params: Function parameters. /// - params: Function parameters.
fn gen_constructor<'ctx, 'a>( fn gen_constructor<'ctx, 'a>(

View File

@ -6,7 +6,7 @@ use inkwell::{
context::Context, context::Context,
memory_buffer::MemoryBuffer, memory_buffer::MemoryBuffer,
module::Module, module::Module,
types::BasicTypeEnum, types::{BasicTypeEnum, IntType},
values::{IntValue, PointerValue}, values::{IntValue, PointerValue},
AddressSpace, IntPredicate, AddressSpace, IntPredicate,
}; };
@ -34,7 +34,6 @@ pub fn load_irrt(ctx: &Context) -> Module {
// repeated squaring method adapted from GNU Scientific Library: // repeated squaring method adapted from GNU Scientific Library:
// https://git.savannah.gnu.org/cgit/gsl.git/tree/sys/pow_int.c // https://git.savannah.gnu.org/cgit/gsl.git/tree/sys/pow_int.c
pub fn integer_power<'ctx, 'a>( pub fn integer_power<'ctx, 'a>(
generator: &mut dyn CodeGenerator,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
base: IntValue<'ctx>, base: IntValue<'ctx>,
exp: IntValue<'ctx>, exp: IntValue<'ctx>,
@ -52,21 +51,7 @@ pub fn integer_power<'ctx, 'a>(
let fn_type = base_type.fn_type(&[base_type.into(), base_type.into()], false); let fn_type = base_type.fn_type(&[base_type.into(), base_type.into()], false);
ctx.module.add_function(symbol, fn_type, None) ctx.module.add_function(symbol, fn_type, None)
}); });
// throw exception when exp < 0 // TODO: throw exception when exp < 0
let ge_zero = ctx.builder.build_int_compare(
IntPredicate::SGE,
exp,
exp.get_type().const_zero(),
"assert_int_pow_ge_0",
);
ctx.make_assert(
generator,
ge_zero,
"0:ValueError",
"integer power must be positive or zero",
[None, None, None],
ctx.current_loc,
);
ctx.builder ctx.builder
.build_call(pow_fun, &[base.into(), exp.into()], "call_int_pow") .build_call(pow_fun, &[base.into(), exp.into()], "call_int_pow")
.try_as_basic_value() .try_as_basic_value()
@ -75,7 +60,6 @@ pub fn integer_power<'ctx, 'a>(
} }
pub fn calculate_len_for_slice_range<'ctx, 'a>( pub fn calculate_len_for_slice_range<'ctx, 'a>(
generator: &mut dyn CodeGenerator,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
start: IntValue<'ctx>, start: IntValue<'ctx>,
end: IntValue<'ctx>, end: IntValue<'ctx>,
@ -88,21 +72,7 @@ pub fn calculate_len_for_slice_range<'ctx, 'a>(
ctx.module.add_function(SYMBOL, fn_t, None) ctx.module.add_function(SYMBOL, fn_t, None)
}); });
// assert step != 0, throw exception if not // TODO: assert step != 0, throw exception if not
let not_zero = ctx.builder.build_int_compare(
IntPredicate::NE,
step,
step.get_type().const_zero(),
"range_step_ne",
);
ctx.make_assert(
generator,
not_zero,
"0:ValueError",
"step must not be zero",
[None, None, None],
ctx.current_loc,
);
ctx.builder ctx.builder
.build_call(len_func, &[start.into(), end.into(), step.into()], "calc_len") .build_call(len_func, &[start.into(), end.into(), step.into()], "calc_len")
.try_as_basic_value() .try_as_basic_value()
@ -159,6 +129,7 @@ pub fn handle_slice_indices<'a, 'ctx, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
list: PointerValue<'ctx>, list: PointerValue<'ctx>,
) -> Result<(IntValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>), String> { ) -> Result<(IntValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>), String> {
// TODO: throw exception when step is 0
let int32 = ctx.ctx.i32_type(); let int32 = ctx.ctx.i32_type();
let zero = int32.const_zero(); let zero = int32.const_zero();
let one = int32.const_int(1, false); let one = int32.const_int(1, false);
@ -183,23 +154,8 @@ pub fn handle_slice_indices<'a, 'ctx, G: CodeGenerator>(
let step = generator let step = generator
.gen_expr(ctx, step)? .gen_expr(ctx, step)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, ctx.primitives.int32)? .to_basic_value_enum(ctx, generator)?
.into_int_value(); .into_int_value();
// assert step != 0, throw exception if not
let not_zero = ctx.builder.build_int_compare(
IntPredicate::NE,
step,
step.get_type().const_zero(),
"range_step_ne",
);
ctx.make_assert(
generator,
not_zero,
"0:ValueError",
"slice step cannot be zero",
[None, None, None],
ctx.current_loc,
);
let len_id = ctx.builder.build_int_sub(length, one, "lenmin1"); let len_id = ctx.builder.build_int_sub(length, one, "lenmin1");
let neg = ctx.builder.build_int_compare(IntPredicate::SLT, step, zero, "step_is_neg"); let neg = ctx.builder.build_int_compare(IntPredicate::SLT, step, zero, "step_is_neg");
( (
@ -261,7 +217,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(ctx, generator, i.custom.unwrap())?; let i = generator.gen_expr(ctx, i)?.unwrap().to_basic_value_enum(ctx, generator)?;
Ok(ctx Ok(ctx
.builder .builder
.build_call(func, &[i.into(), length.into()], "bounded_ind") .build_call(func, &[i.into(), length.into()], "bounded_ind")
@ -275,15 +231,14 @@ pub fn handle_slice_index_bound<'a, 'ctx, G: CodeGenerator>(
/// Order of tuples assign_idx and value_idx is ('start', 'end', 'step'). /// Order of tuples assign_idx and value_idx is ('start', 'end', 'step').
/// Negative index should be handled before entering this function /// Negative index should be handled before entering this function
pub fn list_slice_assignment<'ctx, 'a>( pub fn list_slice_assignment<'ctx, 'a>(
generator: &mut dyn CodeGenerator,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
size_ty: IntType<'ctx>,
ty: BasicTypeEnum<'ctx>, ty: BasicTypeEnum<'ctx>,
dest_arr: PointerValue<'ctx>, dest_arr: PointerValue<'ctx>,
dest_idx: (IntValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>), dest_idx: (IntValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>),
src_arr: PointerValue<'ctx>, src_arr: PointerValue<'ctx>,
src_idx: (IntValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>), src_idx: (IntValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>),
) { ) {
let size_ty = generator.get_size_type(ctx.ctx);
let int8_ptr = ctx.ctx.i8_type().ptr_type(AddressSpace::Generic); let int8_ptr = ctx.ctx.i8_type().ptr_type(AddressSpace::Generic);
let int32 = ctx.ctx.i32_type(); let int32 = ctx.ctx.i32_type();
let (fun_symbol, elem_ptr_type) = ("__nac3_list_slice_assign_var_size", int8_ptr); let (fun_symbol, elem_ptr_type) = ("__nac3_list_slice_assign_var_size", int8_ptr);
@ -327,67 +282,8 @@ pub fn list_slice_assignment<'ctx, 'a>(
let src_len = ctx.builder.build_int_truncate_or_bit_cast(src_len, int32, "srclen32"); let src_len = ctx.builder.build_int_truncate_or_bit_cast(src_len, int32, "srclen32");
// 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 // TODO: 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.builder
.build_select(
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_add(src_idx.1, one, "e_add_one"),
"final_e",
)
.into_int_value();
let dest_end = ctx.builder
.build_select(
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_add(dest_idx.1, one, "e_add_one"),
"final_e",
)
.into_int_value();
let src_slice_len =
calculate_len_for_slice_range(generator, ctx, src_idx.0, src_end, src_idx.2);
let dest_slice_len =
calculate_len_for_slice_range(generator, ctx, dest_idx.0, dest_end, dest_idx.2);
let src_eq_dest = ctx.builder.build_int_compare(
IntPredicate::EQ,
src_slice_len,
dest_slice_len,
"slice_src_eq_dest",
);
let src_slt_dest = ctx.builder.build_int_compare(
IntPredicate::SLT,
src_slice_len,
dest_slice_len,
"slice_src_slt_dest",
);
let dest_step_eq_one = ctx.builder.build_int_compare(
IntPredicate::EQ,
dest_idx.2,
dest_idx.2.get_type().const_int(1, false),
"slice_dest_step_eq_one",
);
let cond_1 = ctx.builder.build_and(dest_step_eq_one, src_slt_dest, "slice_cond_1");
let cond = ctx.builder.build_or(src_eq_dest, cond_1, "slice_cond");
ctx.make_assert(
generator,
cond,
"0:ValueError",
"attempt to assign sequence of size {0} to slice of size {1} with step size {2}",
[Some(src_slice_len), Some(dest_slice_len), Some(dest_idx.2)],
ctx.current_loc,
);
let new_len = { let new_len = {
let args = vec![ let args = vec![
dest_idx.0.into(), // dest start idx dest_idx.0.into(), // dest start idx

View File

@ -17,13 +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}
debug_info::{
DebugInfoBuilder, DICompileUnit, DISubprogram, AsDIScope, DIFlagsConstants, DILexicalBlock
},
}; };
use itertools::Itertools; use itertools::Itertools;
use nac3parser::ast::{Stmt, StrRef, Location}; use nac3parser::ast::{Stmt, StrRef};
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::{
@ -55,7 +52,6 @@ pub type VarValue<'ctx> = (PointerValue<'ctx>, Option<Arc<dyn StaticValue + Send
pub struct CodeGenContext<'ctx, 'a> { pub struct CodeGenContext<'ctx, 'a> {
pub ctx: &'ctx Context, pub ctx: &'ctx Context,
pub builder: Builder<'ctx>, pub builder: Builder<'ctx>,
pub debug_info: (DebugInfoBuilder<'ctx>, DICompileUnit<'ctx>, DILexicalBlock<'ctx>),
pub module: Module<'ctx>, pub module: Module<'ctx>,
pub top_level: &'a TopLevelContext, pub top_level: &'a TopLevelContext,
pub unifier: Unifier, pub unifier: Unifier,
@ -81,7 +77,6 @@ pub struct CodeGenContext<'ctx, 'a> {
pub outer_catch_clauses: pub outer_catch_clauses:
Option<(Vec<Option<BasicValueEnum<'ctx>>>, BasicBlock<'ctx>, PhiValue<'ctx>)>, Option<(Vec<Option<BasicValueEnum<'ctx>>>, BasicBlock<'ctx>, PhiValue<'ctx>)>,
pub need_sret: bool, pub need_sret: bool,
pub current_loc: Location,
} }
impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
@ -207,17 +202,6 @@ impl WorkerRegistry {
let mut builder = context.create_builder(); let mut builder = context.create_builder();
let module = context.create_module(generator.get_name()); let module = context.create_module(generator.get_name());
module.add_basic_value_flag(
"Debug Info Version",
inkwell::module::FlagBehavior::Warning,
context.i32_type().const_int(3, false),
);
module.add_basic_value_flag(
"Dwarf Version",
inkwell::module::FlagBehavior::Warning,
context.i32_type().const_int(4, false),
);
let pass_builder = PassManagerBuilder::create(); let pass_builder = PassManagerBuilder::create();
pass_builder.set_optimization_level(OptimizationLevel::Default); pass_builder.set_optimization_level(OptimizationLevel::Default);
let passes = PassManager::create(&module); let passes = PassManager::create(&module);
@ -376,14 +360,13 @@ fn need_sret<'ctx>(ctx: &'ctx Context, ty: BasicTypeEnum<'ctx>) -> bool {
need_sret_impl(ctx, ty, true) need_sret_impl(ctx, ty, true)
} }
pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenContext) -> Result<(), String>> ( pub fn gen_func<'ctx, G: CodeGenerator>(
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
) -> 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();
@ -566,61 +549,6 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
builder.build_unconditional_branch(body_bb); builder.build_unconditional_branch(body_bb);
builder.position_at_end(body_bb); builder.position_at_end(body_bb);
let (dibuilder, compile_unit) = module.create_debug_info_builder(
/* allow_unresolved */ true,
/* language */ inkwell::debug_info::DWARFSourceLanguage::Python,
/* filename */
&task
.body
.get(0)
.map_or_else(|| "_nac3_internal".to_string(), |f| f.location.file.0.to_string()),
/* directory */ ".",
/* producer */ "NAC3",
/* is_optimized */ false,
/* compiler command line flags */ "",
/* runtime_ver */ 0,
/* split_name */ "",
/* kind */ inkwell::debug_info::DWARFEmissionKind::LineTablesOnly,
/* dwo_id */ 0,
/* split_debug_inling */ false,
/* debug_info_for_profiling */ false,
/* sysroot */ "",
/* sdk */ "",
);
let subroutine_type = dibuilder.create_subroutine_type(
compile_unit.get_file(),
Some(
dibuilder
.create_basic_type("_", 0_u64, 0x00, inkwell::debug_info::DIFlags::PUBLIC)
.unwrap()
.as_type(),
),
&[],
inkwell::debug_info::DIFlags::PUBLIC,
);
let func_scope: DISubprogram<'_> = dibuilder.create_function(
/* scope */ compile_unit.as_debug_info_scope(),
/* func name */ symbol,
/* linkage_name */ None,
/* file */ compile_unit.get_file(),
/* line_no */ 0,
/* DIType */ subroutine_type,
/* is_local_to_unit */ true,
/* is_definition */ true,
/* scope_line */ 0,
/* flags */ inkwell::debug_info::DIFlags::PUBLIC,
/* is_optimized */ false,
);
fn_val.set_subprogram(func_scope);
let (row, col) =
task.body.get(0).map_or_else(|| (0, 0), |b| (b.location.row, b.location.column));
let lexical_block = dibuilder.create_lexical_block(
/* scope */ func_scope.as_debug_info_scope(),
/* file */ compile_unit.get_file(),
/* line_no */ row as u32,
/* column_no */ col as u32,
);
let mut code_gen_context = CodeGenContext { let mut code_gen_context = CodeGenContext {
ctx: context, ctx: context,
resolver: task.resolver, resolver: task.resolver,
@ -641,51 +569,28 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
module, module,
unifier, unifier,
static_value_store, static_value_store,
need_sret: has_sret, need_sret: has_sret
current_loc: Default::default(),
debug_info: (dibuilder, compile_unit, lexical_block),
}; };
let loc = code_gen_context.debug_info.0.create_debug_location( let mut err = None;
context, for stmt in task.body.iter() {
row as u32, if let Err(e) = generator.gen_stmt(&mut code_gen_context, stmt) {
col as u32, err = Some(e);
lexical_block.as_debug_info_scope(), break;
None }
); if code_gen_context.is_terminated() {
code_gen_context.builder.set_current_debug_location(context, loc); break;
}
let result = codegen_function(generator, &mut code_gen_context); }
// after static analysis, only void functions can have no return at the end. // after static analysis, only void functions can have no return at the end.
if !code_gen_context.is_terminated() { if !code_gen_context.is_terminated() {
code_gen_context.builder.build_return(None); code_gen_context.builder.build_return(None);
} }
code_gen_context.builder.unset_current_debug_location();
code_gen_context.debug_info.0.finalize();
let CodeGenContext { builder, module, .. } = code_gen_context; let CodeGenContext { builder, module, .. } = code_gen_context;
if let Err(e) = result { if let Some(e) = err {
return Err((builder, e)); return Err((builder, e));
} }
Ok((builder, module, fn_val)) Ok((builder, module, fn_val))
} }
pub fn gen_func<'ctx, G: CodeGenerator>(
context: &'ctx Context,
generator: &mut G,
registry: &WorkerRegistry,
builder: Builder<'ctx>,
module: Module<'ctx>,
task: CodeGenTask,
) -> Result<(Builder<'ctx>, Module<'ctx>, FunctionValue<'ctx>), (Builder<'ctx>, String)> {
let body = task.body.clone();
gen_func_impl(context, generator, registry, builder, module, task, |generator, ctx| {
for stmt in body.iter() {
generator.gen_stmt(ctx, stmt)?;
}
Ok(())
})
}

View File

@ -11,7 +11,6 @@ use crate::{
}; };
use inkwell::{ use inkwell::{
attributes::{Attribute, AttributeLoc}, attributes::{Attribute, AttributeLoc},
debug_info::AsDIScope,
basic_block::BasicBlock, basic_block::BasicBlock,
types::BasicTypeEnum, types::BasicTypeEnum,
values::{BasicValue, BasicValueEnum, FunctionValue, PointerValue}, values::{BasicValue, BasicValueEnum, FunctionValue, PointerValue},
@ -26,16 +25,12 @@ pub fn gen_var<'ctx, 'a>(
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
ty: BasicTypeEnum<'ctx>, ty: BasicTypeEnum<'ctx>,
) -> Result<PointerValue<'ctx>, String> { ) -> Result<PointerValue<'ctx>, String> {
let loc = ctx.builder.get_current_debug_location();
// put the alloca in init block // put the alloca in init block
let current = ctx.builder.get_insert_block().unwrap(); let current = ctx.builder.get_insert_block().unwrap();
// position before the last branching instruction... // position before the last branching instruction...
ctx.builder.position_before(&ctx.init_bb.get_last_instruction().unwrap()); ctx.builder.position_before(&ctx.init_bb.get_last_instruction().unwrap());
let ptr = ctx.builder.build_alloca(ty, "tmp"); let ptr = ctx.builder.build_alloca(ty, "tmp");
ctx.builder.position_at_end(current); ctx.builder.position_at_end(current);
if let Some(l) = loc {
ctx.builder.set_current_debug_location(ctx.ctx, l);
}
Ok(ptr) Ok(ptr)
} }
@ -59,11 +54,7 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
} }
ExprKind::Attribute { value, attr, .. } => { ExprKind::Attribute { value, attr, .. } => {
let index = ctx.get_attr_index(value.custom.unwrap(), *attr); let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
let val = generator.gen_expr(ctx, value)?.unwrap().to_basic_value_enum( let val = generator.gen_expr(ctx, value)?.unwrap().to_basic_value_enum(ctx, generator)?;
ctx,
generator,
value.custom.unwrap(),
)?;
let ptr = if let BasicValueEnum::PointerValue(v) = val { let ptr = if let BasicValueEnum::PointerValue(v) = val {
v v
} else { } else {
@ -81,58 +72,17 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
} }
} }
ExprKind::Subscript { value, slice, .. } => { ExprKind::Subscript { value, slice, .. } => {
assert!(matches!(
ctx.unifier.get_ty_immutable(value.custom.unwrap()).as_ref(),
TypeEnum::TList { .. },
));
let i32_type = ctx.ctx.i32_type(); let i32_type = ctx.ctx.i32_type();
let zero = i32_type.const_zero();
let v = generator let v = generator
.gen_expr(ctx, value)? .gen_expr(ctx, value)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, value.custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.into_pointer_value(); .into_pointer_value();
let len = ctx let index = generator
.build_gep_and_load(v, &[zero, i32_type.const_int(1, false)])
.into_int_value();
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)?
.into_int_value(); .into_int_value();
let raw_index = ctx.builder.build_int_s_extend(
raw_index,
generator.get_size_type(ctx.ctx),
"sext",
);
// handle negative index
let is_negative = ctx.builder.build_int_compare(
inkwell::IntPredicate::SLT,
raw_index,
generator.get_size_type(ctx.ctx).const_zero(),
"is_neg",
);
let adjusted = ctx.builder.build_int_add(raw_index, len, "adjusted");
let index = ctx
.builder
.build_select(is_negative, adjusted, raw_index, "index")
.into_int_value();
// unsigned less than is enough, because negative index after adjustment is
// bigger than the length (for unsigned cmp)
let bound_check = ctx.builder.build_int_compare(
inkwell::IntPredicate::ULT,
index,
len,
"inbound",
);
ctx.make_assert(
generator,
bound_check,
"0:IndexError",
"index {0} out of bounds 0:{1}",
[Some(raw_index), Some(len), None],
slice.location,
);
unsafe { unsafe {
let arr_ptr = ctx let arr_ptr = ctx
.build_gep_and_load(v, &[i32_type.const_zero(), i32_type.const_zero()]) .build_gep_and_load(v, &[i32_type.const_zero(), i32_type.const_zero()])
@ -152,9 +102,7 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
) -> Result<(), String> { ) -> Result<(), String> {
match &target.node { match &target.node {
ExprKind::Tuple { elts, .. } => { ExprKind::Tuple { elts, .. } => {
if let BasicValueEnum::StructValue(v) = if let BasicValueEnum::StructValue(v) = value.to_basic_value_enum(ctx, generator)? {
value.to_basic_value_enum(ctx, generator, target.custom.unwrap())?
{
for (i, elt) in elts.iter().enumerate() { for (i, elt) in elts.iter().enumerate() {
let v = ctx let v = ctx
.builder .builder
@ -173,13 +121,11 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
let ls = generator let ls = generator
.gen_expr(ctx, ls)? .gen_expr(ctx, ls)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, ls.custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.into_pointer_value(); .into_pointer_value();
let (start, end, step) = let (start, end, step) =
handle_slice_indices(lower, upper, step, ctx, generator, ls)?; handle_slice_indices(lower, upper, step, ctx, generator, ls)?;
let value = value let value = value.to_basic_value_enum(ctx, generator)?.into_pointer_value();
.to_basic_value_enum(ctx, generator, target.custom.unwrap())?
.into_pointer_value();
let ty = let ty =
if let TypeEnum::TList { ty } = &*ctx.unifier.get_ty(target.custom.unwrap()) { if let TypeEnum::TList { ty } = &*ctx.unifier.get_ty(target.custom.unwrap()) {
ctx.get_llvm_type(generator, *ty) ctx.get_llvm_type(generator, *ty)
@ -187,7 +133,15 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
unreachable!() unreachable!()
}; };
let src_ind = handle_slice_indices(&None, &None, &None, ctx, generator, value)?; let src_ind = handle_slice_indices(&None, &None, &None, ctx, generator, value)?;
list_slice_assignment(generator, ctx, ty, ls, (start, end, step), value, src_ind) list_slice_assignment(
ctx,
generator.get_size_type(ctx.ctx),
ty,
ls,
(start, end, step),
value,
src_ind,
)
} else { } else {
unreachable!() unreachable!()
} }
@ -201,7 +155,7 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
*static_value = Some(s.clone()); *static_value = Some(s.clone());
} }
} }
let val = value.to_basic_value_enum(ctx, generator, target.custom.unwrap())?; let val = value.to_basic_value_enum(ctx, generator)?;
ctx.builder.build_store(ptr, val); ctx.builder.build_store(ptr, val);
} }
}; };
@ -231,16 +185,11 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
// store loop bb information and restore it later // store loop bb information and restore it later
let loop_bb = ctx.loop_target.replace((test_bb, cont_bb)); let loop_bb = ctx.loop_target.replace((test_bb, cont_bb));
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)?;
ctx,
generator,
iter.custom.unwrap(),
)?;
if ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range) { if ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range) {
// setup // setup
let iter_val = iter_val.into_pointer_value(); let iter_val = iter_val.into_pointer_value();
let i = generator.gen_var_alloc(ctx, int32.into())?; let i = generator.gen_store_target(ctx, target)?;
let user_i = generator.gen_store_target(ctx, target)?;
let (start, end, step) = destructure_range(ctx, iter_val); let (start, end, step) = destructure_range(ctx, iter_val);
ctx.builder.build_store(i, ctx.builder.build_int_sub(start, step, "start_init")); ctx.builder.build_store(i, ctx.builder.build_int_sub(start, step, "start_init"));
ctx.builder.build_unconditional_branch(test_bb); ctx.builder.build_unconditional_branch(test_bb);
@ -258,7 +207,6 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
"start_loop", "start_loop",
); );
ctx.builder.build_store(i, tmp); ctx.builder.build_store(i, tmp);
ctx.builder.build_store(user_i, tmp);
// // if step > 0, continue when i < end // // if step > 0, continue when i < end
let cmp1 = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, end, "cmp1"); let cmp1 = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, end, "cmp1");
// if step < 0, continue when i > end // if step < 0, continue when i > end
@ -348,11 +296,7 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
let loop_bb = ctx.loop_target.replace((test_bb, cont_bb)); let loop_bb = ctx.loop_target.replace((test_bb, cont_bb));
ctx.builder.build_unconditional_branch(test_bb); ctx.builder.build_unconditional_branch(test_bb);
ctx.builder.position_at_end(test_bb); ctx.builder.position_at_end(test_bb);
let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum( let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(ctx, generator)?;
ctx,
generator,
test.custom.unwrap(),
)?;
if let BasicValueEnum::IntValue(test) = test { if let BasicValueEnum::IntValue(test) = test {
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb); ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
} else { } else {
@ -413,11 +357,7 @@ pub fn gen_if<'ctx, 'a, G: CodeGenerator>(
}; };
ctx.builder.build_unconditional_branch(test_bb); ctx.builder.build_unconditional_branch(test_bb);
ctx.builder.position_at_end(test_bb); ctx.builder.position_at_end(test_bb);
let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum( let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(ctx, generator)?;
ctx,
generator,
test.custom.unwrap(),
)?;
if let BasicValueEnum::IntValue(test) = test { if let BasicValueEnum::IntValue(test) = test {
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb); ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
} else { } else {
@ -480,8 +420,8 @@ pub fn final_proxy<'ctx, 'a>(
final_paths.push(block); final_paths.push(block);
} }
pub fn get_builtins<'ctx, 'a>( pub fn get_builtins<'ctx, 'a, G: CodeGenerator>(
generator: &mut dyn CodeGenerator, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
symbol: &str, symbol: &str,
) -> FunctionValue<'ctx> { ) -> FunctionValue<'ctx> {
@ -514,7 +454,7 @@ pub fn exn_constructor<'ctx, 'a>(
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
) -> Result<Option<BasicValueEnum<'ctx>>, String> { ) -> Result<Option<BasicValueEnum<'ctx>>, String> {
let (zelf_ty, zelf) = obj.unwrap(); let (zelf_ty, zelf) = obj.unwrap();
let zelf = zelf.to_basic_value_enum(ctx, generator, zelf_ty)?.into_pointer_value(); let zelf = zelf.to_basic_value_enum(ctx, generator)?.into_pointer_value();
let int32 = ctx.ctx.i32_type(); let int32 = ctx.ctx.i32_type();
let zero = int32.const_zero(); let zero = int32.const_zero();
let zelf_id = { let zelf_id = {
@ -537,14 +477,14 @@ pub fn exn_constructor<'ctx, 'a>(
let ptr = let ptr =
ctx.builder.build_in_bounds_gep(zelf, &[zero, int32.const_int(5, false)], "exn.msg"); ctx.builder.build_in_bounds_gep(zelf, &[zero, int32.const_int(5, false)], "exn.msg");
let msg = if !args.is_empty() { let msg = if !args.is_empty() {
args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.str)? args.remove(0).1.to_basic_value_enum(ctx, generator)?
} else { } else {
empty_string empty_string
}; };
ctx.builder.build_store(ptr, msg); ctx.builder.build_store(ptr, msg);
for i in [6, 7, 8].iter() { for i in [6, 7, 8].iter() {
let value = if !args.is_empty() { let value = if !args.is_empty() {
args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.int64)? args.remove(0).1.to_basic_value_enum(ctx, generator)?
} else { } else {
ctx.ctx.i64_type().const_zero().into() ctx.ctx.i64_type().const_zero().into()
}; };
@ -577,8 +517,8 @@ pub fn exn_constructor<'ctx, 'a>(
Ok(Some(zelf.into())) Ok(Some(zelf.into()))
} }
pub fn gen_raise<'ctx, 'a>( pub fn gen_raise<'ctx, 'a, G: CodeGenerator>(
generator: &mut dyn CodeGenerator, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
exception: Option<&BasicValueEnum<'ctx>>, exception: Option<&BasicValueEnum<'ctx>>,
loc: Location, loc: Location,
@ -966,11 +906,7 @@ pub fn gen_return<'ctx, 'a, G: CodeGenerator>(
) -> Result<(), String> { ) -> Result<(), String> {
let value = value let value = value
.as_ref() .as_ref()
.map(|v_expr| { .map(|v| generator.gen_expr(ctx, v).and_then(|v| v.unwrap().to_basic_value_enum(ctx, generator)))
generator.gen_expr(ctx, v_expr).and_then(|v| {
v.unwrap().to_basic_value_enum(ctx, generator, v_expr.custom.unwrap())
})
})
.transpose()?; .transpose()?;
if let Some(return_target) = ctx.return_target { if let Some(return_target) = ctx.return_target {
if let Some(value) = value { if let Some(value) = value {
@ -993,17 +929,6 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
stmt: &Stmt<Option<Type>>, stmt: &Stmt<Option<Type>>,
) -> Result<(), String> { ) -> Result<(), String> {
ctx.current_loc = stmt.location;
let loc = ctx.debug_info.0.create_debug_location(
ctx.ctx,
ctx.current_loc.row as u32,
ctx.current_loc.column as u32,
ctx.debug_info.2.as_debug_info_scope(),
None,
);
ctx.builder.set_current_debug_location(ctx.ctx, loc);
match &stmt.node { match &stmt.node {
StmtKind::Pass { .. } => {} StmtKind::Pass { .. } => {}
StmtKind::Expr { value, .. } => { StmtKind::Expr { value, .. } => {
@ -1041,40 +966,14 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
StmtKind::Try { .. } => gen_try(generator, ctx, stmt)?, StmtKind::Try { .. } => gen_try(generator, ctx, stmt)?,
StmtKind::Raise { exc, .. } => { StmtKind::Raise { exc, .. } => {
if let Some(exc) = exc { if let Some(exc) = exc {
let exc = generator.gen_expr(ctx, exc)?.unwrap().to_basic_value_enum( let exc =
ctx, generator.gen_expr(ctx, exc)?.unwrap().to_basic_value_enum(ctx, generator)?;
generator,
exc.custom.unwrap(),
)?;
gen_raise(generator, ctx, Some(&exc), stmt.location); gen_raise(generator, ctx, Some(&exc), stmt.location);
} else { } else {
gen_raise(generator, ctx, None, stmt.location); gen_raise(generator, ctx, None, stmt.location);
} }
} }
StmtKind::Assert { test, msg, .. } => { _ => unimplemented!(),
let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(
ctx,
generator,
test.custom.unwrap(),
)?;
let err_msg = match msg {
Some(msg) => generator.gen_expr(ctx, msg)?.unwrap().to_basic_value_enum(
ctx,
generator,
msg.custom.unwrap(),
)?,
None => ctx.gen_string(generator, ""),
};
ctx.make_assert_impl(
generator,
test.into_int_value(),
"0:AssertionError",
err_msg,
[None, None, None],
stmt.location,
)
}
_ => unimplemented!()
}; };
Ok(()) Ok(())
} }

View File

@ -71,7 +71,7 @@ impl SymbolResolver for Resolver {
unimplemented!() unimplemented!()
} }
fn get_exception_id(&self, _tyid: usize) -> usize { fn get_exception_id(&self, tyid: usize) -> usize {
unimplemented!() unimplemented!()
} }
} }
@ -185,17 +185,8 @@ fn test_primitives() {
init: init:
%add = add i32 %0, %1 %add = add i32 %0, %1
%cmp = icmp eq i32 %add, 1 %cmp = icmp eq i32 %add, 1
br i1 %cmp, label %then, label %else %ifexpr = select i1 %cmp, i32 %0, i32 0
ret i32 %ifexpr
then: ; preds = %init
br label %cont
else: ; preds = %init
br label %cont
cont: ; preds = %else, %then
%if_exp_result.0 = phi i32 [ %0, %then ], [ 0, %else ]
ret i32 %if_exp_result.0
} }
"} "}
.trim(); .trim();

View File

@ -14,7 +14,7 @@ use crate::{
typedef::{Type, Unifier}, typedef::{Type, Unifier},
}, },
}; };
use inkwell::values::{BasicValueEnum, FloatValue, IntValue, PointerValue, StructValue}; use inkwell::values::{BasicValueEnum, FloatValue, IntValue, PointerValue};
use itertools::{chain, izip}; use itertools::{chain, izip};
use nac3parser::ast::{Expr, Location, StrRef}; use nac3parser::ast::{Expr, Location, StrRef};
use parking_lot::RwLock; use parking_lot::RwLock;
@ -29,8 +29,6 @@ pub enum SymbolValue {
Double(f64), Double(f64),
Bool(bool), Bool(bool),
Tuple(Vec<SymbolValue>), Tuple(Vec<SymbolValue>),
OptionSome(Box<SymbolValue>),
OptionNone,
} }
impl Display for SymbolValue { impl Display for SymbolValue {
@ -52,8 +50,6 @@ impl Display for SymbolValue {
SymbolValue::Tuple(t) => { SymbolValue::Tuple(t) => {
write!(f, "({})", t.iter().map(|v| format!("{}", v)).collect::<Vec<_>>().join(", ")) write!(f, "({})", t.iter().map(|v| format!("{}", v)).collect::<Vec<_>>().join(", "))
} }
SymbolValue::OptionSome(v) => write!(f, "Some({})", v),
SymbolValue::OptionNone => write!(f, "none"),
} }
} }
} }
@ -71,7 +67,6 @@ pub trait StaticValue {
&self, &self,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
expected_ty: Type,
) -> Result<BasicValueEnum<'ctx>, String>; ) -> Result<BasicValueEnum<'ctx>, String>;
fn get_field<'ctx, 'a>( fn get_field<'ctx, 'a>(
@ -79,8 +74,6 @@ pub trait StaticValue {
name: StrRef, name: StrRef,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
) -> Option<ValueEnum<'ctx>>; ) -> Option<ValueEnum<'ctx>>;
fn get_tuple_element<'ctx>(&self, index: u32) -> Option<ValueEnum<'ctx>>;
} }
#[derive(Clone)] #[derive(Clone)]
@ -113,21 +106,14 @@ impl<'ctx> From<FloatValue<'ctx>> for ValueEnum<'ctx> {
} }
} }
impl<'ctx> From<StructValue<'ctx>> for ValueEnum<'ctx> {
fn from(v: StructValue<'ctx>) -> Self {
ValueEnum::Dynamic(v.into())
}
}
impl<'ctx> ValueEnum<'ctx> { impl<'ctx> ValueEnum<'ctx> {
pub fn to_basic_value_enum<'a>( pub fn to_basic_value_enum<'a>(
self, self,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
expected_ty: Type,
) -> Result<BasicValueEnum<'ctx>, String> { ) -> Result<BasicValueEnum<'ctx>, String> {
match self { match self {
ValueEnum::Static(v) => v.to_basic_value_enum(ctx, generator, expected_ty), ValueEnum::Static(v) => v.to_basic_value_enum(ctx, generator),
ValueEnum::Dynamic(v) => Ok(v), ValueEnum::Dynamic(v) => Ok(v),
} }
} }
@ -367,7 +353,7 @@ impl dyn SymbolResolver + Send + Sync {
unreachable!("expected class definition") unreachable!("expected class definition")
} }
}, },
&mut |id| format!("typevar{}", id), &mut |id| format!("var{}", id),
&mut None, &mut None,
) )
} }

View File

@ -105,8 +105,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
("__param2__".into(), int64, true), ("__param2__".into(), int64, true),
]; ];
// for Option, is_some and is_none share the same type: () -> bool, // for Option, is_some and is_none share the same type
// and they are methods under the same class `Option`
let (is_some_ty, unwrap_ty, (option_ty_var, option_ty_var_id)) = let (is_some_ty, unwrap_ty, (option_ty_var, option_ty_var_id)) =
if let TypeEnum::TObj { fields, params, .. } = if let TypeEnum::TObj { fields, params, .. } =
primitives.1.get_ty(primitives.0.option).as_ref() primitives.1.get_ty(primitives.0.option).as_ref()
@ -224,12 +223,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, obj, _, _, generator| { |ctx, obj, _, _, generator| {
let expect_ty = obj.clone().unwrap().0; let obj_val = obj.unwrap().1.clone().to_basic_value_enum(ctx, generator)?;
let obj_val = obj.unwrap().1.clone().to_basic_value_enum(
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 {
@ -249,12 +243,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, obj, _, _, generator| { |ctx, obj, _, _, generator| {
let expect_ty = obj.clone().unwrap().0; let obj_val = obj.unwrap().1.clone().to_basic_value_enum(ctx, generator)?;
let obj_val = obj.unwrap().1.clone().to_basic_value_enum(
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 {
@ -273,7 +262,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
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(
|_, _, _, _, _| { |ctx, obj, _, _, generator| {
unreachable!("handled in gen_expr") unreachable!("handled in gen_expr")
}, },
)))), )))),
@ -300,7 +289,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
let float = ctx.primitives.float; let float = ctx.primitives.float;
let boolean = ctx.primitives.bool; let boolean = ctx.primitives.bool;
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
Ok(if ctx.unifier.unioned(arg_ty, boolean) { Ok(if ctx.unifier.unioned(arg_ty, boolean) {
Some( Some(
ctx.builder ctx.builder
@ -365,7 +354,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
let float = ctx.primitives.float; let float = ctx.primitives.float;
let boolean = ctx.primitives.bool; let boolean = ctx.primitives.bool;
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
Ok( Ok(
if ctx.unifier.unioned(arg_ty, boolean) if ctx.unifier.unioned(arg_ty, boolean)
|| ctx.unifier.unioned(arg_ty, uint32) || ctx.unifier.unioned(arg_ty, uint32)
@ -432,7 +421,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
let float = ctx.primitives.float; let float = ctx.primitives.float;
let boolean = ctx.primitives.bool; let boolean = ctx.primitives.bool;
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
let res = if ctx.unifier.unioned(arg_ty, boolean) { let res = if ctx.unifier.unioned(arg_ty, boolean) {
ctx.builder ctx.builder
.build_int_z_extend(arg.into_int_value(), ctx.ctx.i64_type(), "zext") .build_int_z_extend(arg.into_int_value(), ctx.ctx.i64_type(), "zext")
@ -484,7 +473,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
let float = ctx.primitives.float; let float = ctx.primitives.float;
let boolean = ctx.primitives.bool; let boolean = ctx.primitives.bool;
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
let res = if ctx.unifier.unioned(arg_ty, int32) let res = if ctx.unifier.unioned(arg_ty, int32)
|| ctx.unifier.unioned(arg_ty, uint32) || ctx.unifier.unioned(arg_ty, uint32)
|| ctx.unifier.unioned(arg_ty, boolean) || ctx.unifier.unioned(arg_ty, boolean)
@ -531,7 +520,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
let boolean = ctx.primitives.bool; let boolean = ctx.primitives.bool;
let float = ctx.primitives.float; let float = ctx.primitives.float;
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
Ok( Ok(
if ctx.unifier.unioned(arg_ty, boolean) if ctx.unifier.unioned(arg_ty, boolean)
|| ctx.unifier.unioned(arg_ty, int32) || ctx.unifier.unioned(arg_ty, int32)
@ -567,7 +556,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(ctx, generator, ctx.primitives.float)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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();
@ -607,7 +596,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(ctx, generator, ctx.primitives.float)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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();
@ -665,44 +654,23 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
let mut step = None; let mut step = None;
let int32 = ctx.ctx.i32_type(); let int32 = ctx.ctx.i32_type();
let zero = int32.const_zero(); let zero = int32.const_zero();
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 = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?); start = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
} 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)?);
} 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)?);
} else if i == 0 { } else if i == 0 {
start = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?); start = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
} 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)?);
} else if i == 2 { } else if i == 2 {
step = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?); step = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
} }
} }
let step = match step { // TODO: error when step == 0
Some(step) => { let step = step.unwrap_or_else(|| int32.const_int(1, false).into());
let step = step.into_int_value();
// assert step != 0, throw exception if not
let not_zero = ctx.builder.build_int_compare(
IntPredicate::NE,
step,
step.get_type().const_zero(),
"range_step_ne",
);
ctx.make_assert(
generator,
not_zero,
"0:ValueError",
"range() step must not be zero",
[None, None, None],
ctx.current_loc,
);
step
}
None => int32.const_int(1, false),
};
let stop = stop.unwrap_or_else(|| { let stop = stop.unwrap_or_else(|| {
let v = start.unwrap(); let v = start.unwrap();
start = None; start = None;
@ -745,9 +713,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
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(
|ctx, _, fun, args, generator| { |ctx, _, _, args, generator| {
let arg_ty = fun.0.args[0].ty; Ok(Some(args[0].1.clone().to_basic_value_enum(ctx, generator)?))
Ok(Some(args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?))
}, },
)))), )))),
loc: None, loc: None,
@ -771,7 +738,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
let float = ctx.primitives.float; let float = ctx.primitives.float;
let boolean = ctx.primitives.bool; let boolean = ctx.primitives.bool;
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
Ok(if ctx.unifier.unioned(arg_ty, boolean) { Ok(if ctx.unifier.unioned(arg_ty, boolean) {
Some(arg) Some(arg)
} else if ctx.unifier.unioned(arg_ty, int32) { } else if ctx.unifier.unioned(arg_ty, int32) {
@ -829,7 +796,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(ctx, generator, ctx.primitives.float)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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();
@ -869,7 +836,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(ctx, generator, ctx.primitives.float)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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();
@ -909,7 +876,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(ctx, generator, ctx.primitives.float)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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();
@ -949,7 +916,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(ctx, generator, ctx.primitives.float)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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();
@ -1001,11 +968,11 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|ctx, _, fun, args, generator| { |ctx, _, fun, args, generator| {
let range_ty = ctx.primitives.range; let range_ty = ctx.primitives.range;
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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(calculate_len_for_slice_range(generator, ctx, start, end, step).into()) Some(calculate_len_for_slice_range(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();
@ -1055,8 +1022,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum(); let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
let m_ty = fun.0.args[0].ty; let m_ty = fun.0.args[0].ty;
let n_ty = fun.0.args[1].ty; let n_ty = fun.0.args[1].ty;
let m_val = args[0].1.clone().to_basic_value_enum(ctx, generator, m_ty)?; let m_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator, n_ty)?; let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator)?;
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b); let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
let (fun_name, arg_ty) = if is_type(m_ty, n_ty) && is_type(n_ty, boolean) { let (fun_name, arg_ty) = if is_type(m_ty, n_ty) && is_type(n_ty, boolean) {
("llvm.umin.i1", llvm_i1) ("llvm.umin.i1", llvm_i1)
@ -1117,8 +1084,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum(); let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
let m_ty = fun.0.args[0].ty; let m_ty = fun.0.args[0].ty;
let n_ty = fun.0.args[1].ty; let n_ty = fun.0.args[1].ty;
let m_val = args[0].1.clone().to_basic_value_enum(ctx, generator, m_ty)?; let m_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator, n_ty)?; let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator)?;
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b); let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
let (fun_name, arg_ty) = if is_type(m_ty, n_ty) && is_type(n_ty, boolean) { let (fun_name, arg_ty) = if is_type(m_ty, n_ty) && is_type(n_ty, boolean) {
("llvm.umax.i1", llvm_i1) ("llvm.umax.i1", llvm_i1)
@ -1175,7 +1142,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
let llvm_i64 = ctx.ctx.i64_type().as_basic_type_enum(); let llvm_i64 = ctx.ctx.i64_type().as_basic_type_enum();
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum(); let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
let n_ty = fun.0.args[0].ty; let n_ty = fun.0.args[0].ty;
let n_val = args[0].1.clone().to_basic_value_enum(ctx, generator, n_ty)?; let n_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b); let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
let mut is_float = false; let mut is_float = false;
let (fun_name, arg_ty) = let (fun_name, arg_ty) =
@ -1232,9 +1199,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
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(
|ctx, _, fun, args, generator| { |ctx, _, _fun, args, generator| {
let arg_ty = fun.0.args[0].ty; let arg_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
let arg_val = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
let alloca = ctx.builder.build_alloca(arg_val.get_type(), "alloca_some"); let alloca = ctx.builder.build_alloca(arg_val.get_type(), "alloca_some");
ctx.builder.build_store(alloca, arg_val); ctx.builder.build_store(alloca, arg_val);
Ok(Some(alloca.into())) Ok(Some(alloca.into()))

View File

@ -91,7 +91,7 @@ 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, type_vars, .. } = &*def
{ {
assert!(id == object_id.0); assert!(id == object_id.0);
if let Some(constructor) = constructor { if let Some(constructor) = constructor {
@ -434,11 +434,11 @@ impl TopLevelComposer {
// check if all are unique type vars // check if all are unique type vars
let all_unique_type_var = { let all_unique_type_var = {
let mut occurred_type_var_id: HashSet<u32> = HashSet::new(); let mut occured_type_var_id: HashSet<u32> = HashSet::new();
type_vars.iter().all(|x| { type_vars.iter().all(|x| {
let ty = unifier.get_ty(*x); let ty = unifier.get_ty(*x);
if let TypeEnum::TVar { id, .. } = ty.as_ref() { if let TypeEnum::TVar { id, .. } = ty.as_ref() {
occurred_type_var_id.insert(*id) occured_type_var_id.insert(*id)
} else { } else {
false false
} }
@ -536,7 +536,7 @@ impl TopLevelComposer {
} }
has_base = true; has_base = true;
// the function parse_ast_to make sure that no type var occurred in // the function parse_ast_to make sure that no type var occured in
// bast_ty if it is a CustomClassKind // bast_ty if it is a CustomClassKind
let base_ty = parse_ast_to_type_annotation_kinds( let base_ty = parse_ast_to_type_annotation_kinds(
class_resolver, class_resolver,
@ -696,7 +696,7 @@ impl TopLevelComposer {
return Err(errors.into_iter().sorted().join("\n----------\n")); return Err(errors.into_iter().sorted().join("\n----------\n"));
} }
// handle the inherited methods and fields // handle the inheritanced methods and fields
// Note: we cannot defer error handling til the end of the loop, because there is loop // Note: we cannot defer error handling til the end of the loop, because there is loop
// carried dependency, ignoring the error (temporarily) will cause all assumptions to break // carried dependency, ignoring the error (temporarily) will cause all assumptions to break
// and produce weird error messages // and produce weird error messages
@ -825,9 +825,9 @@ impl TopLevelComposer {
let mut function_var_map: HashMap<u32, Type> = HashMap::new(); let mut function_var_map: HashMap<u32, Type> = HashMap::new();
let arg_types = { let arg_types = {
// make sure no duplicate parameter // make sure no duplicate parameter
let mut defined_parameter_name: HashSet<_> = HashSet::new(); let mut defined_paramter_name: HashSet<_> = HashSet::new();
for x in args.args.iter() { for x in args.args.iter() {
if !defined_parameter_name.insert(x.node.arg) if !defined_paramter_name.insert(x.node.arg)
|| keyword_list.contains(&x.node.arg) || keyword_list.contains(&x.node.arg)
{ {
return Err(format!( return Err(format!(
@ -1074,10 +1074,10 @@ impl TopLevelComposer {
let arg_types: Vec<FuncArg> = { let arg_types: Vec<FuncArg> = {
// check method parameters cannot have same name // check method parameters cannot have same name
let mut defined_parameter_name: HashSet<_> = HashSet::new(); let mut defined_paramter_name: HashSet<_> = HashSet::new();
let zelf: StrRef = "self".into(); let zelf: StrRef = "self".into();
for x in args.args.iter() { for x in args.args.iter() {
if !defined_parameter_name.insert(x.node.arg) if !defined_paramter_name.insert(x.node.arg)
|| (keyword_list.contains(&x.node.arg) && x.node.arg != zelf) || (keyword_list.contains(&x.node.arg) && x.node.arg != zelf)
{ {
return Err(format!( return Err(format!(
@ -1088,13 +1088,13 @@ impl TopLevelComposer {
} }
} }
if name == &"__init__".into() && !defined_parameter_name.contains(&zelf) { if name == &"__init__".into() && !defined_paramter_name.contains(&zelf) {
return Err(format!( return Err(format!(
"__init__ method must have a `self` parameter (at {})", "__init__ method must have a `self` parameter (at {})",
b.location b.location
)); ));
} }
if !defined_parameter_name.contains(&zelf) { if !defined_paramter_name.contains(&zelf) {
return Err(format!( return Err(format!(
"class method must have a `self` parameter (at {})", "class method must have a `self` parameter (at {})",
b.location b.location
@ -1227,7 +1227,7 @@ impl TopLevelComposer {
dummy_return_type dummy_return_type
} else { } else {
// if do not have return annotation, return none // if do not have return annotation, return none
// for uniform handling, still use type annotation // for uniform handling, still use type annoatation
let dummy_return_type = unifier.get_dummy_var().0; let dummy_return_type = unifier.get_dummy_var().0;
type_var_to_concrete_def.insert( type_var_to_concrete_def.insert(
dummy_return_type, dummy_return_type,
@ -1468,7 +1468,7 @@ impl TopLevelComposer {
Ok(()) Ok(())
} }
/// step 5, analyze and call type inferencer to fill the `instance_to_stmt` of topleveldef::function /// step 5, analyze and call type inferecer to fill the `instance_to_stmt` of topleveldef::function
fn analyze_function_instance(&mut self) -> Result<(), String> { fn analyze_function_instance(&mut self) -> Result<(), String> {
// first get the class contructor type correct for the following type check in function body // first get the class contructor type correct for the following type check in function body
// also do class field instantiation check // also do class field instantiation check
@ -1906,7 +1906,7 @@ impl TopLevelComposer {
unreachable!("must be class id here") unreachable!("must be class id here")
} }
}, },
&mut |id| format!("typevar{}", id), &mut |id| format!("tvar{}", id),
&mut None, &mut None,
); );
return Err(format!( return Err(format!(

View File

@ -149,7 +149,7 @@ impl TopLevelComposer {
} }
/// already include the definition_id of itself inside the ancestors vector /// already include the definition_id of itself inside the ancestors vector
/// when first registering, the type_vars, fields, methods, ancestors are invalid /// when first regitering, the type_vars, fields, methods, ancestors are invalid
pub fn make_top_level_class_def( pub fn make_top_level_class_def(
index: usize, index: usize,
resolver: Option<Arc<dyn SymbolResolver + Send + Sync>>, resolver: Option<Arc<dyn SymbolResolver + Send + Sync>>,
@ -416,77 +416,76 @@ impl TopLevelComposer {
primitive: &PrimitiveStore, primitive: &PrimitiveStore,
unifier: &mut Unifier, unifier: &mut Unifier,
) -> Result<(), String> { ) -> Result<(), String> {
fn type_default_param( let res = match val {
val: &SymbolValue, SymbolValue::Bool(..) => {
primitive: &PrimitiveStore, if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.bool) {
unifier: &mut Unifier, None
) -> TypeAnnotation { } else {
match val { Some("bool".to_string())
SymbolValue::Bool(..) => TypeAnnotation::Primitive(primitive.bool),
SymbolValue::Double(..) => TypeAnnotation::Primitive(primitive.float),
SymbolValue::I32(..) => TypeAnnotation::Primitive(primitive.int32),
SymbolValue::I64(..) => TypeAnnotation::Primitive(primitive.int64),
SymbolValue::U32(..) => TypeAnnotation::Primitive(primitive.uint32),
SymbolValue::U64(..) => TypeAnnotation::Primitive(primitive.uint64),
SymbolValue::Str(..) => TypeAnnotation::Primitive(primitive.str),
SymbolValue::Tuple(vs) => {
let vs_tys = vs
.iter()
.map(|v| type_default_param(v, primitive, unifier))
.collect::<Vec<_>>();
TypeAnnotation::Tuple(vs_tys)
} }
SymbolValue::OptionNone => TypeAnnotation::CustomClass { }
id: primitive.option.get_obj_id(unifier), SymbolValue::Double(..) => {
params: Default::default(), if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.float) {
}, None
SymbolValue::OptionSome(v) => { } else {
let ty = type_default_param(v, primitive, unifier); Some("float".to_string())
TypeAnnotation::CustomClass { }
id: primitive.option.get_obj_id(unifier), }
params: vec![ty], SymbolValue::I32(..) => {
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.int32) {
None
} else {
Some("int32".to_string())
}
}
SymbolValue::I64(..) => {
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.int64) {
None
} else {
Some("int64".to_string())
}
}
SymbolValue::U32(..) => {
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.uint32) {
None
} else {
Some("uint32".to_string())
}
}
SymbolValue::U64(..) => {
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.uint64) {
None
} else {
Some("uint64".to_string())
}
}
SymbolValue::Str(..) => {
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.str) {
None
} else {
Some("str".to_string())
}
}
SymbolValue::Tuple(elts) => {
if let TypeAnnotation::Tuple(elts_ty) = ty {
for (e, t) in elts.iter().zip(elts_ty.iter()) {
Self::check_default_param_type(e, t, primitive, unifier)?
} }
if elts.len() != elts_ty.len() {
Some(format!("tuple of length {}", elts.len()))
} else {
None
}
} else {
Some("tuple".to_string())
} }
} }
} };
if let Some(found) = res {
fn is_compatible(
found: &TypeAnnotation,
expect: &TypeAnnotation,
unifier: &mut Unifier,
primitive: &PrimitiveStore,
) -> bool {
match (found, expect) {
(TypeAnnotation::Primitive(f), TypeAnnotation::Primitive(e)) => {
unifier.unioned(*f, *e)
}
(
TypeAnnotation::CustomClass { id: f_id, params: f_param },
TypeAnnotation::CustomClass { id: e_id, params: e_param },
) => {
*f_id == *e_id
&& *f_id == primitive.option.get_obj_id(unifier)
&& (f_param.is_empty()
|| (f_param.len() == 1
&& e_param.len() == 1
&& is_compatible(&f_param[0], &e_param[0], unifier, primitive)))
}
(TypeAnnotation::Tuple(f), TypeAnnotation::Tuple(e)) => {
f.len() == e.len()
&& f.iter()
.zip(e.iter())
.all(|(f, e)| is_compatible(f, e, unifier, primitive))
}
_ => false,
}
}
let found = type_default_param(val, primitive, unifier);
if !is_compatible(&found, ty, unifier, primitive) {
Err(format!( Err(format!(
"incompatible default parameter type, expect {}, found {}", "incompatible default parameter type, expect {}, found {}",
ty.stringify(unifier), ty.stringify(unifier),
found.stringify(unifier), found
)) ))
} else { } else {
Ok(()) Ok(())
@ -512,10 +511,6 @@ pub fn parse_parameter_default_value(
Constant::Tuple(tuple) => Ok(SymbolValue::Tuple( Constant::Tuple(tuple) => Ok(SymbolValue::Tuple(
tuple.iter().map(|x| handle_constant(x, loc)).collect::<Result<Vec<_>, _>>()?, tuple.iter().map(|x| handle_constant(x, loc)).collect::<Result<Vec<_>, _>>()?,
)), )),
Constant::None => Err(format!(
"`None` is not supported, use `none` for option type instead ({})",
loc
)),
_ => unimplemented!("this constant is not supported at {}", loc), _ => unimplemented!("this constant is not supported at {}", loc),
} }
} }
@ -553,11 +548,6 @@ pub fn parse_parameter_default_value(
} }
_ => 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(
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)),
} }
} }
@ -566,20 +556,15 @@ pub fn parse_parameter_default_value(
.map(|x| parse_parameter_default_value(x, resolver)) .map(|x| parse_parameter_default_value(x, resolver))
.collect::<Result<Vec<_>, _>>()? .collect::<Result<Vec<_>, _>>()?
)), )),
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 or tuple / not defined?)",
(not primitive type, option or tuple / not defined?)",
id, id,
default.location default.location
) )
) )
} }
_ => Err(format!( _ => Err(format!("unsupported default parameter at {}", default.location))
"unsupported default parameter (not primitive type, option or tuple) at {}",
default.location
))
} }
} }

View File

@ -5,10 +5,10 @@ expression: res_vec
--- ---
[ [
"Class {\nname: \"Generic_A\",\nancestors: [\"Generic_A[V]\", \"B\"],\nfields: [\"aa\", \"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\"), (\"fun\", \"fn[[a:int32], V]\")],\ntype_vars: [\"V\"]\n}\n", "Class {\nname: \"Generic_A\",\nancestors: [\"{class: Generic_A, params: [\\\"V\\\"]}\", \"{class: B, params: []}\"],\nfields: [\"aa\", \"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\"), (\"fun\", \"fn[[a:int32], V]\")],\ntype_vars: [\"V\"]\n}\n",
"Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n", "Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [18]\n}\n", "Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [18]\n}\n",
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [\"aa\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\")],\ntype_vars: []\n}\n", "Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\"],\nfields: [\"aa\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\")],\ntype_vars: []\n}\n",
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n", "Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:T], none]\",\nvar_id: []\n}\n", "Function {\nname: \"B.foo\",\nsig: \"fn[[b:T], none]\",\nvar_id: []\n}\n",
] ]

View File

@ -5,13 +5,13 @@ expression: res_vec
--- ---
[ [
"Class {\nname: \"A\",\nancestors: [\"A[T]\"],\nfields: [\"a\", \"b\", \"c\"],\nmethods: [(\"__init__\", \"fn[[t:T], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"T\"]\n}\n", "Class {\nname: \"A\",\nancestors: [\"{class: A, params: [\\\"T\\\"]}\"],\nfields: [\"a\", \"b\", \"c\"],\nmethods: [(\"__init__\", \"fn[[t:T], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"T\"]\n}\n",
"Function {\nname: \"A.__init__\",\nsig: \"fn[[t:T], none]\",\nvar_id: []\n}\n", "Function {\nname: \"A.__init__\",\nsig: \"fn[[t:T], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n", "Function {\nname: \"A.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
"Function {\nname: \"A.foo\",\nsig: \"fn[[c:C], none]\",\nvar_id: []\n}\n", "Function {\nname: \"A.foo\",\nsig: \"fn[[c:C], none]\",\nvar_id: []\n}\n",
"Class {\nname: \"B\",\nancestors: [\"B[typevar7]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"typevar7\"]\n}\n", "Class {\nname: \"B\",\nancestors: [\"{class: B, params: [\\\"var7\\\"]}\", \"{class: A, params: [\\\"float\\\"]}\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"var7\"]\n}\n",
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n", "Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n", "Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
"Class {\nname: \"C\",\nancestors: [\"C\", \"B[bool]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: []\n}\n", "Class {\nname: \"C\",\nancestors: [\"{class: C, params: []}\", \"{class: B, params: [\\\"bool\\\"]}\", \"{class: A, params: [\\\"float\\\"]}\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: []\n}\n",
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n", "Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
] ]

View File

@ -6,10 +6,10 @@ expression: res_vec
--- ---
[ [
"Function {\nname: \"foo\",\nsig: \"fn[[a:list[int32], b:tuple[T, float]], A[B, bool]]\",\nvar_id: []\n}\n", "Function {\nname: \"foo\",\nsig: \"fn[[a:list[int32], b:tuple[T, float]], A[B, bool]]\",\nvar_id: []\n}\n",
"Class {\nname: \"A\",\nancestors: [\"A[T, V]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[v:V], none]\"), (\"fun\", \"fn[[a:T], V]\")],\ntype_vars: [\"T\", \"V\"]\n}\n", "Class {\nname: \"A\",\nancestors: [\"{class: A, params: [\\\"T\\\", \\\"V\\\"]}\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[v:V], none]\"), (\"fun\", \"fn[[a:T], V]\")],\ntype_vars: [\"T\", \"V\"]\n}\n",
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [20]\n}\n", "Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [20]\n}\n",
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [25]\n}\n", "Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [25]\n}\n",
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[int32, list[float]]], none]\",\nvar_id: []\n}\n", "Function {\nname: \"gfun\",\nsig: \"fn[[a:A[int32, list[float]]], none]\",\nvar_id: []\n}\n",
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n", "Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n", "Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
] ]

View File

@ -5,10 +5,10 @@ expression: res_vec
--- ---
[ [
"Class {\nname: \"A\",\nancestors: [\"A[typevar6, typevar7]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[bool, float], b:B], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\")],\ntype_vars: [\"typevar6\", \"typevar7\"]\n}\n", "Class {\nname: \"A\",\nancestors: [\"{class: A, params: [\\\"var6\\\", \\\"var7\\\"]}\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[bool, float], b:B], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\")],\ntype_vars: [\"var6\", \"var7\"]\n}\n",
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[bool, float], b:B], none]\",\nvar_id: []\n}\n", "Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[bool, float], b:B], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[bool, float]], A[bool, int32]]\",\nvar_id: []\n}\n", "Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[bool, float]], A[bool, int32]]\",\nvar_id: []\n}\n",
"Class {\nname: \"B\",\nancestors: [\"B\", \"A[int64, bool]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[int32, list[B]]], tuple[A[bool, virtual[A[B, int32]]], B]]\")],\ntype_vars: []\n}\n", "Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\", \"{class: A, params: [\\\"int64\\\", \\\"bool\\\"]}\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[int32, list[B]]], tuple[A[bool, virtual[A[B, int32]]], B]]\")],\ntype_vars: []\n}\n",
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n", "Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:B], B]\",\nvar_id: []\n}\n", "Function {\nname: \"B.foo\",\nsig: \"fn[[b:B], B]\",\nvar_id: []\n}\n",
"Function {\nname: \"B.bar\",\nsig: \"fn[[a:A[int32, list[B]]], tuple[A[bool, virtual[A[B, int32]]], B]]\",\nvar_id: []\n}\n", "Function {\nname: \"B.bar\",\nsig: \"fn[[a:A[int32, list[B]]], tuple[A[bool, virtual[A[B, int32]]], B]]\",\nvar_id: []\n}\n",

View File

@ -5,13 +5,13 @@ expression: res_vec
--- ---
[ [
"Class {\nname: \"A\",\nancestors: [\"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n", "Class {\nname: \"A\",\nancestors: [\"{class: A, params: []}\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
"Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n", "Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"A.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n", "Function {\nname: \"A.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [26]\n}\n", "Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [26]\n}\n",
"Class {\nname: \"B\",\nancestors: [\"B\", \"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n", "Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\", \"{class: C, params: []}\", \"{class: A, params: []}\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n", "Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Class {\nname: \"C\",\nancestors: [\"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n", "Class {\nname: \"C\",\nancestors: [\"{class: C, params: []}\", \"{class: A, params: []}\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n", "Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"C.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n", "Function {\nname: \"C.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"foo\",\nsig: \"fn[[a:A], none]\",\nvar_id: []\n}\n", "Function {\nname: \"foo\",\nsig: \"fn[[a:A], none]\",\nvar_id: []\n}\n",

View File

@ -1,9 +1,9 @@
--- ---
source: nac3core/src/toplevel/test.rs source: nac3core/src/toplevel/test.rs
assertion_line: 549 assertion_line: 541
expression: res_vec expression: res_vec
--- ---
[ [
"Class {\nname: \"A\",\nancestors: [\"A\"],\nfields: [],\nmethods: [],\ntype_vars: []\n}\n", "Class {\nname: \"A\",\nancestors: [\"{class: A, params: []}\"],\nfields: [],\nmethods: [],\ntype_vars: []\n}\n",
] ]

View File

@ -65,14 +65,14 @@ impl SymbolResolver for Resolver {
} }
fn get_identifier_def(&self, id: StrRef) -> Result<DefinitionId, String> { fn get_identifier_def(&self, id: StrRef) -> Result<DefinitionId, String> {
self.0.id_to_def.lock().get(&id).cloned().ok_or_else(|| "Unknown identifier".to_string()) self.0.id_to_def.lock().get(&id).cloned().ok_or("Unknown identifier".to_string())
} }
fn get_string_id(&self, _: &str) -> i32 { fn get_string_id(&self, _: &str) -> i32 {
unimplemented!() unimplemented!()
} }
fn get_exception_id(&self, _tyid: usize) -> usize { fn get_exception_id(&self, tyid: usize) -> usize {
unimplemented!() unimplemented!()
} }
} }
@ -763,7 +763,7 @@ fn make_internal_resolver_with_tvar(
(name, { (name, {
let (ty, id) = unifier.get_fresh_var_with_range(range.as_slice(), None, None); let (ty, id) = unifier.get_fresh_var_with_range(range.as_slice(), None, None);
if print { if print {
println!("{}: {:?}, typevar{}", name, ty, id); println!("{}: {:?}, tvar{}", name, ty, id);
} }
ty ty
}) })
@ -791,7 +791,7 @@ impl<'a> Fold<Option<Type>> for TypeToStringFolder<'a> {
self.unifier.internal_stringify( self.unifier.internal_stringify(
ty, ty,
&mut |id| format!("class{}", id.to_string()), &mut |id| format!("class{}", id.to_string()),
&mut |id| format!("typevar{}", id.to_string()), &mut |id| format!("tvar{}", id.to_string()),
&mut None, &mut None,
) )
} else { } else {

View File

@ -29,28 +29,20 @@ impl TypeAnnotation {
{ {
(*name).into() (*name).into()
} else { } else {
unreachable!() format!("def_{}", id.0)
} }
} }
None => format!("class_def_{}", id.0), None => format!("def_{}", id.0),
}; };
format!( format!(
"{}{}", "{{class: {}, params: {:?}}}",
class_name, class_name,
{ params.iter().map(|p| p.stringify(unifier)).collect_vec()
let param_list = params.iter().map(|p| p.stringify(unifier)).collect_vec().join(", ");
if param_list.is_empty() {
"".into()
} else {
format!("[{}]", param_list)
}
}
) )
} }
Virtual(ty) => format!("virtual[{}]", ty.stringify(unifier)), Virtual(ty) | List(ty) => ty.stringify(unifier),
List(ty) => format!("list[{}]", ty.stringify(unifier)),
Tuple(types) => { Tuple(types) => {
format!("tuple[{}]", types.iter().map(|p| p.stringify(unifier)).collect_vec().join(", ")) format!("({:?})", types.iter().map(|p| p.stringify(unifier)).collect_vec())
} }
} }
} }
@ -356,7 +348,7 @@ pub fn get_type_from_type_annotation_kinds(
unifier.internal_stringify( unifier.internal_stringify(
p, p,
&mut |id| format!("class{}", id), &mut |id| format!("class{}", id),
&mut |id| format!("typevar{}", id), &mut |id| format!("tvar{}", id),
&mut None &mut None
), ),
*id *id
@ -436,7 +428,7 @@ pub fn get_type_from_type_annotation_kinds(
/// the type of `self` should be similar to `A[T, V]`, where `T`, `V` /// the type of `self` should be similar to `A[T, V]`, where `T`, `V`
/// considered to be type variables associated with the class \ /// considered to be type variables associated with the class \
/// \ /// \
/// But note that here we do not make a duplication of `T`, `V`, we directly /// But note that here we do not make a duplication of `T`, `V`, we direclty
/// use them as they are in the TopLevelDef::Class since those in the /// use them as they are in the TopLevelDef::Class since those in the
/// TopLevelDef::Class.type_vars will be substitute later when seeing applications/instantiations /// TopLevelDef::Class.type_vars will be substitute later when seeing applications/instantiations
/// the Type of their fields and methods will also be subst when application/instantiation /// the Type of their fields and methods will also be subst when application/instantiation

View File

@ -426,13 +426,6 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
let res_ty = self.infer_bin_ops(stmt.location, target, op, value)?; 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, .. } => {
self.unify(test.custom.unwrap(), self.primitives.bool, &test.location)?;
match msg {
Some(m) => self.unify(m.custom.unwrap(), self.primitives.str, &m.location)?,
None => ()
}
}
_ => return report_error("Unsupported statement type", stmt.location), _ => return report_error("Unsupported statement type", stmt.location),
}; };
Ok(stmt) Ok(stmt)

View File

@ -44,14 +44,14 @@ impl SymbolResolver for Resolver {
} }
fn get_identifier_def(&self, id: StrRef) -> Result<DefinitionId, String> { fn get_identifier_def(&self, id: StrRef) -> Result<DefinitionId, String> {
self.id_to_def.get(&id).cloned().ok_or_else(|| "Unknown identifier".to_string()) self.id_to_def.get(&id).cloned().ok_or("Unknown identifier".to_string())
} }
fn get_string_id(&self, _: &str) -> i32 { fn get_string_id(&self, _: &str) -> i32 {
unimplemented!() unimplemented!()
} }
fn get_exception_id(&self, _tyid: usize) -> usize { fn get_exception_id(&self, tyid: usize) -> usize {
unimplemented!() unimplemented!()
} }
} }

View File

@ -16,7 +16,7 @@ use crate::toplevel::{DefinitionId, TopLevelContext, TopLevelDef};
#[cfg(test)] #[cfg(test)]
mod test; mod test;
/// Handle for a type, implemented as a key in the unification table. /// Handle for a type, implementated as a key in the unification table.
pub type Type = UnificationKey; pub type Type = UnificationKey;
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
@ -830,7 +830,7 @@ impl Unifier {
}, },
) )
}, },
&mut |id| format!("typevar{}", id), &mut |id| format!("var{}", id),
notes, notes,
) )
} }

View File

@ -302,14 +302,14 @@ fn test_unify(
("v1", "Record[a=float,b=int]"), ("v1", "Record[a=float,b=int]"),
("v2", "Foo[v3]"), ("v2", "Foo[v3]"),
], ],
(("v1", "v2"), "`3[typevar4]::b` field/method does not exist") (("v1", "v2"), "`3[var4]::b` field/method does not exist")
; "record obj merge" ; "record obj merge"
)] )]
/// Test cases for invalid unifications. /// Test cases for invalid unifications.
fn test_invalid_unification( fn test_invalid_unification(
variable_count: u32, variable_count: u32,
unify_pairs: &[(&'static str, &'static str)], unify_pairs: &[(&'static str, &'static str)],
erroneous_pair: ((&'static str, &'static str), &'static str), errornous_pair: ((&'static str, &'static str), &'static str),
) { ) {
let mut env = TestEnvironment::new(); let mut env = TestEnvironment::new();
let mut mapping = HashMap::new(); let mut mapping = HashMap::new();
@ -326,11 +326,11 @@ fn test_invalid_unification(
pairs.push((t1, t2)); pairs.push((t1, t2));
} }
let (t1, t2) = let (t1, t2) =
(env.parse(erroneous_pair.0 .0, &mapping), env.parse(erroneous_pair.0 .1, &mapping)); (env.parse(errornous_pair.0 .0, &mapping), env.parse(errornous_pair.0 .1, &mapping));
for (a, b) in pairs { for (a, b) in pairs {
env.unifier.unify(a, b).unwrap(); env.unifier.unify(a, b).unwrap();
} }
assert_eq!(env.unify(t1, t2), Err(erroneous_pair.1.to_string())); assert_eq!(env.unify(t1, t2), Err(errornous_pair.1.to_string()));
} }
#[test] #[test]
@ -445,7 +445,7 @@ fn test_typevar_range() {
// where v in (int, list[v1]), v1 in (int, bool) // where v in (int, list[v1]), v1 in (int, bool)
assert_eq!( assert_eq!(
env.unify(float_list, v), env.unify(float_list, v),
Err("Expected any one of these types: 0, list[typevar5], but got list[1]\n\nNotes:\n typevar5 ∈ {0, 2}".to_string()) Err("Expected any one of these types: 0, list[var5], but got list[1]\n\nNotes:\n var5 ∈ {0, 2}".to_string())
); );
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;
@ -504,9 +504,9 @@ fn test_rigid_var() {
let int = env.parse("int", &HashMap::new()); let int = env.parse("int", &HashMap::new());
let list_int = env.parse("list[int]", &HashMap::new()); let list_int = env.parse("list[int]", &HashMap::new());
assert_eq!(env.unify(a, b), Err("Incompatible types: typevar3 and typevar2".to_string())); assert_eq!(env.unify(a, b), Err("Incompatible types: var3 and var2".to_string()));
env.unifier.unify(list_a, list_x).unwrap(); env.unifier.unify(list_a, list_x).unwrap();
assert_eq!(env.unify(list_x, list_int), Err("Incompatible types: 0 and typevar2".to_string())); assert_eq!(env.unify(list_x, list_int), Err("Incompatible types: 0 and var2".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

@ -121,7 +121,7 @@ mod tests {
#[test] #[test]
fn test_parse_lambda() { fn test_parse_lambda() {
let source = "lambda x, y: x * y"; // lambda(x, y): x * y"; let source = "lambda x, y: x * y"; // lambda(x, y): x * y";
let parse_ast = parse_program(source, Default::default()).unwrap(); let parse_ast = parse_program(&source, Default::default()).unwrap();
insta::assert_debug_snapshot!(parse_ast); insta::assert_debug_snapshot!(parse_ast);
} }
@ -129,7 +129,7 @@ mod tests {
fn test_parse_tuples() { fn test_parse_tuples() {
let source = "a, b = 4, 5"; let source = "a, b = 4, 5";
insta::assert_debug_snapshot!(parse_program(source, Default::default()).unwrap()); insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
} }
#[test] #[test]
@ -140,7 +140,7 @@ class Foo(A, B):
pass pass
def method_with_default(self, arg='default'): def method_with_default(self, arg='default'):
pass"; pass";
insta::assert_debug_snapshot!(parse_program(source, Default::default()).unwrap()); insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
} }
#[test] #[test]
@ -183,7 +183,7 @@ while i < 2: # nac3: 4
# nac3: if1 # nac3: if1
if 1: # nac3: if2 if 1: # nac3: if2
3"; 3";
insta::assert_debug_snapshot!(parse_program(source, Default::default()).unwrap()); insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
} }
#[test] #[test]
@ -196,7 +196,7 @@ while test: # nac3: while3
# nac3: simple assign0 # nac3: simple assign0
a = 3 # nac3: simple assign1 a = 3 # nac3: simple assign1
"; ";
insta::assert_debug_snapshot!(parse_program(source, Default::default()).unwrap()); insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
} }
#[test] #[test]
@ -215,7 +215,7 @@ if a: # nac3: small2
for i in a: # nac3: for1 for i in a: # nac3: for1
pass pass
"; ";
insta::assert_debug_snapshot!(parse_program(source, Default::default()).unwrap()); insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
} }
#[test] #[test]
@ -224,6 +224,6 @@ for i in a: # nac3: for1
if a: # nac3: something if a: # nac3: something
a = 3 a = 3
"; ";
assert!(parse_program(source, Default::default()).is_err()); assert!(parse_program(&source, Default::default()).is_err());
} }
} }

View File

@ -74,11 +74,6 @@ pub extern "C" fn __nac3_personality(_state: u32, _exception_object: u32, _conte
unimplemented!(); unimplemented!();
} }
#[no_mangle]
pub extern "C" fn __nac3_raise(_state: u32, _exception_object: u32, _context: u32) -> u32 {
unimplemented!();
}
extern "C" { extern "C" {
fn run() -> i32; fn run() -> i32;
} }

View File

@ -1,43 +0,0 @@
@extern
def output_int32(x: int32):
...
def f1(a: int32 = 4):
output_int32(a)
def f2(a: int64 = int64(123)):
output_int32(int32(a))
def f3(a: uint32 = uint32(234)):
output_int32(int32(a))
def f4(a: tuple[int32, tuple[int32, int32], int64] = (4, (5, 6), int64(7))):
output_int32(a[0])
output_int32(a[1][0])
output_int32(a[1][1])
output_int32(int32(a[2]))
def f5(a: float = 3.45):
output_int32(int32(a))
def f6(a: Option[list[int32]] = none):
if a.is_none():
a = Some([11,22,33])
output_int32(a.unwrap()[2])
def f7(a: Option[tuple[int32, int64]] = Some((3, int64(123)))):
if a.is_some():
a_unwrap = a.unwrap()
output_int32(a_unwrap[0])
output_int32(int32(a_unwrap[1]))
def run() -> int32:
f1()
f2()
f3()
f4()
f5()
f6()
f7()
return 0

View File

@ -229,7 +229,7 @@ def list_slice_assignment():
bl5[3:-5] = [] bl5[3:-5] = []
output_int32_list([int32(b) for b in bl5]) output_int32_list([int32(b) for b in bl5])
bl6 = bl[:] bl6 = bl[:]
bl6[3:-5] = [True, False] bl6[3:-5] = [True, False, False]
output_int32_list([int32(b) for b in bl6]) output_int32_list([int32(b) for b in bl6])
bl7 = bl[:] bl7 = bl[:]
bl7[:-2] = [False] bl7[:-2] = [False]

View File

@ -1,9 +0,0 @@
@extern
def output_int32(x: int32):
...
def run() -> int32:
for _ in range(10):
output_int32(_)
_ = 0
return 0

View File

@ -1,26 +0,0 @@
@extern
def output_float64(f: float):
...
def run() -> int32:
output_float64(float(3 ** 1))
output_float64(float(3 ** 0))
output_float64(float(3 ** 19))
output_float64(1.0 ** -100)
output_float64(1.0 ** -2)
output_float64(1.0 ** 0)
output_float64(1.0 ** 1)
output_float64(1.0 ** 100)
output_float64(3.0 ** 0)
output_float64(3.0 ** 1)
output_float64(3.0 ** 2)
output_float64(3.0 ** -1)
output_float64(3.0 ** -2)
output_float64(3.0 ** -32767)
output_float64(3.0 ** -3.0)
output_float64(3.0 ** -0.0)
output_float64(3.0 ** 0.0)
output_float64(4.0 ** 0.5)
output_float64(4.0 ** -0.5)
return 0

View File

@ -1,29 +0,0 @@
@extern
def output_int32_list(x: list[int32]):
...
@extern
def output_int32(x: int32):
...
class A:
a: int32
b: bool
def __init__(self, a: int32, b: bool):
self.a = a
self.b = b
def run() -> int32:
data = [0, 1, 2, 3]
t = [(d, d + d) for d in data]
for i in t:
tt = (Some(i[1]), i[0])
tl = ([i[0], i[1] + i[0]], i[1])
output_int32(tt[0].unwrap())
output_int32(tt[1])
output_int32(tl[0][0])
output_int32(tl[0][1])
output_int32(tl[1])
return 0

View File

@ -1,26 +0,0 @@
pkgbase="mingw-w64-nac3artiq"
pkgname="mingw-w64-x86_64-nac3artiq"
pkgver=1.0
pkgrel=1
pkgdesc="New ARTIQ compiler 3"
arch=("any")
mingw_arch=("mingw64")
url="https://m-labs.hk"
license=("LGPL")
source=("nac3artiq.pyd")
noextract=("nac3artiq.pyd")
sha256sums=("SKIP")
depends=("mingw-w64-x86_64-python")
prepare() {
true
}
build() {
true
}
package() {
mkdir -p $pkgdir/mingw64/lib/python3.9/site-packages
cp ${srcdir}/nac3artiq.pyd $pkgdir/mingw64/lib/python3.9/site-packages
}

View File

@ -1,36 +0,0 @@
diff '--color=auto' -Naur lld-13.0.1.src/CMakeLists.txt lld-13.0.1.src-new/CMakeLists.txt
--- lld-13.0.1.src/CMakeLists.txt 2022-01-21 05:31:59.000000000 +0800
+++ lld-13.0.1.src-new/CMakeLists.txt 2022-03-27 18:26:30.284921982 +0800
@@ -206,7 +206,6 @@
add_subdirectory(docs)
add_subdirectory(COFF)
add_subdirectory(ELF)
-add_subdirectory(MachO)
add_subdirectory(MinGW)
add_subdirectory(wasm)
diff '--color=auto' -Naur lld-13.0.1.src/tools/lld/CMakeLists.txt lld-13.0.1.src-new/tools/lld/CMakeLists.txt
--- lld-13.0.1.src/tools/lld/CMakeLists.txt 2022-01-21 05:31:59.000000000 +0800
+++ lld-13.0.1.src-new/tools/lld/CMakeLists.txt 2022-03-27 18:26:40.805046295 +0800
@@ -15,7 +15,6 @@
lldCOFF
lldDriver
lldELF
- lldMachO2
lldMinGW
lldWasm
)
diff '--color=auto' -Naur lld-13.0.1.src/tools/lld/lld.cpp lld-13.0.1.src-new/tools/lld/lld.cpp
--- lld-13.0.1.src/tools/lld/lld.cpp 2022-01-21 05:31:59.000000000 +0800
+++ lld-13.0.1.src-new/tools/lld/lld.cpp 2022-03-27 08:43:54.205524156 +0800
@@ -148,10 +148,6 @@
return !elf::link(args, exitEarly, stdoutOS, stderrOS);
case WinLink:
return !coff::link(args, exitEarly, stdoutOS, stderrOS);
- case Darwin:
- return !macho::link(args, exitEarly, stdoutOS, stderrOS);
- case DarwinOld:
- return !mach_o::link(args, exitEarly, stdoutOS, stderrOS);
case Wasm:
return !lld::wasm::link(args, exitEarly, stdoutOS, stderrOS);
default:

View File

@ -1,2 +0,0 @@
PKGEXT='.pkg.tar.zst'
SRCEXT='.src.tar.gz'

View File

@ -33,14 +33,13 @@ let
}; };
in rec { in rec {
llvm-nac3 = pkgs.stdenvNoCC.mkDerivation rec { llvm-nac3 = pkgs.stdenvNoCC.mkDerivation rec {
pname = "llvm-nac3-msys2"; name = "llvm-nac3-msys2";
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-13.0.1/llvm-13.0.1.src.tar.xz";
sha256 = "sha256-7GuA2Cw4SsrS3BkpA6bPLNuv+4ibhL+5janXHmMPyDQ="; 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-13.0.1/clang-13.0.1.src.tar.xz";
sha256 = "sha256-eHqeLZn1yHIKoXc+S+AJRhzTDTvUD90kWR5HNGfJF8k="; sha256 = "sha256-eHqeLZn1yHIKoXc+S+AJRhzTDTvUD90kWR5HNGfJF8k=";
}; };
buildInputs = [ pkgs.wineWowPackages.stable ]; buildInputs = [ pkgs.wineWowPackages.stable ];
@ -74,13 +73,12 @@ in rec {
'' ''
wine64 ninja install wine64 ninja install
''; '';
dontFixup = true;
}; };
nac3artiq = pkgs.rustPlatform.buildRustPackage { nac3artiq = pkgs.rustPlatform.buildRustPackage {
name = "nac3artiq-msys2"; name = "nac3artiq";
src = ../../.; src = ../.;
cargoLock = { lockFile = ../../Cargo.lock; }; cargoLock = { lockFile = ../Cargo.lock; };
nativeBuildInputs = [ pkgs.wineWowPackages.stable ]; nativeBuildInputs = [ pkgs.wineWowPackages.stable pkgs.zip ];
buildPhase = buildPhase =
'' ''
export HOME=`mktemp -d` export HOME=`mktemp -d`
@ -92,9 +90,10 @@ in rec {
''; '';
installPhase = installPhase =
'' ''
mkdir $out $out/nix-support mkdir -p $out $out/nix-support
cp target/release/nac3artiq.dll $out/nac3artiq.pyd ln -s target/release/nac3artiq.dll nac3artiq.pyd
echo file binary-dist $out/nac3artiq.pyd >> $out/nix-support/hydra-build-products zip $out/nac3artiq.zip nac3artiq.pyd
echo file binary-dist $out/nac3artiq.zip >> $out/nix-support/hydra-build-products
''; '';
checkPhase = checkPhase =
'' ''
@ -102,56 +101,6 @@ in rec {
''; '';
dontFixup = true; dontFixup = true;
}; };
nac3artiq-pkg = pkgs.stdenvNoCC.mkDerivation {
name = "nac3artiq-msys2-pkg";
nativeBuildInputs = [ pkgs.pacman pkgs.fakeroot pkgs.libarchive pkgs.zstd ];
src = nac3artiq;
phases = [ "buildPhase" "installPhase" ];
buildPhase =
''
ln -s ${./PKGBUILD} PKGBUILD
ln -s $src/nac3artiq.pyd nac3artiq.pyd
makepkg --config ${./makepkg.conf} --nodeps
'';
installPhase =
''
mkdir $out $out/nix-support
cp *.pkg.tar.zst $out
echo file msys2 $out/*.pkg.tar.zst >> $out/nix-support/hydra-build-products
'';
};
lld = pkgs.stdenvNoCC.mkDerivation rec {
pname = "lld-msys2";
version = "13.0.1";
src = pkgs.fetchurl {
url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/lld-${version}.src.tar.xz";
sha256 = "sha256-Zmr3Rei/e2gFM7TRi3ox3HyrV1sebk0mGSK7r9lkTPs=";
};
buildInputs = [ pkgs.wineWowPackages.stable ];
phases = [ "unpackPhase" "patchPhase" "configurePhase" "buildPhase" "installPhase" ];
patches = [ ./lld-disable-macho.diff ];
configurePhase =
''
export HOME=`mktemp -d`
export WINEDEBUG=-all
export WINEPATH=Z:${msys2-env}/mingw64/bin\;Z:${llvm-nac3}/bin
${silenceFontconfig}
mkdir build
cd build
wine64 cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=Z:$out
'';
buildPhase =
''
wine64 ninja
'';
installPhase =
''
mkdir -p $out $out/nix-support
cp bin/ld.lld.exe $out
echo file binary-dist $out/ld.lld.exe >> $out/nix-support/hydra-build-products
'';
dontFixup = true;
};
wine-msys2 = pkgs.writeShellScriptBin "wine-msys2" wine-msys2 = pkgs.writeShellScriptBin "wine-msys2"
'' ''
export WINEDEBUG=-all export WINEDEBUG=-all
@ -159,12 +108,4 @@ in rec {
export PYO3_CONFIG_FILE=Z:${pyo3-mingw-config} export PYO3_CONFIG_FILE=Z:${pyo3-mingw-config}
exec ${pkgs.wineWowPackages.stable}/bin/wine64 cmd exec ${pkgs.wineWowPackages.stable}/bin/wine64 cmd
''; '';
wine-msys2-build = pkgs.writeShellScriptBin "wine-msys2-build"
''
export HOME=`mktemp -d`
export WINEDEBUG=-all
export WINEPATH=Z:${msys2-env}/mingw64/bin
${silenceFontconfig}
exec ${pkgs.wineWowPackages.stable}/bin/wine64 $@
'';
} }

View File

@ -10,7 +10,7 @@ curl -L https://mirror.msys2.org/msys/x86_64/pacman-mirrors-20220205-1-any.pkg.t
curl -L https://raw.githubusercontent.com/msys2/MSYS2-packages/master/pacman/pacman.conf | grep -v SigLevel | sed s\|/etc/pacman.d\|$MSYS2DIR/etc/pacman.d\|g > $MSYS2DIR/etc/pacman.conf curl -L https://raw.githubusercontent.com/msys2/MSYS2-packages/master/pacman/pacman.conf | grep -v SigLevel | sed s\|/etc/pacman.d\|$MSYS2DIR/etc/pacman.d\|g > $MSYS2DIR/etc/pacman.conf
fakeroot pacman --root $MSYS2DIR --config $MSYS2DIR/etc/pacman.conf -Syy fakeroot pacman --root $MSYS2DIR --config $MSYS2DIR/etc/pacman.conf -Syy
pacman --root $MSYS2DIR --config $MSYS2DIR/etc/pacman.conf --cachedir $MSYS2DIR/msys/cache -Sp mingw-w64-x86_64-rust mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-python3.9 mingw-w64-x86_64-python-numpy mingw-w64-x86_64-python-setuptools > $MSYS2DIR/packages.txt pacman --root $MSYS2DIR --config $MSYS2DIR/etc/pacman.conf --cachedir $MSYS2DIR/msys/cache -Sp mingw-w64-x86_64-rust mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-python3.9 mingw-w64-x86_64-python-numpy > $MSYS2DIR/packages.txt
echo "{ pkgs } : [" > msys2_packages.nix echo "{ pkgs } : [" > msys2_packages.nix
while read package; do while read package; do

View File

@ -6,8 +6,8 @@
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-zlib-1.2.12-1-any.pkg.tar.zst"; url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-zlib-1.2.11-9-any.pkg.tar.zst";
sha256 = "1b461ic5s3hjk3y70ldik82ny08rdywn1zfqa8d2jyyvnh4dya77"; sha256 = "0fb3xbw9a0ah4viwp3a7hr5phnc7mvcl9ba2yjidncpqmspypacx";
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
@ -16,13 +16,13 @@
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-headers-git-9.0.0.6454.b4445ee52-1-any.pkg.tar.zst"; url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-headers-git-9.0.0.6451.a3f6d363d-1-any.pkg.tar.zst";
sha256 = "0wyg5ad3fh2lwd7avxvpncipj5wxmp647l43wzr1l3rrkd820yy3"; sha256 = "1ngnjb9vgk295wlwqandm0nhqqdfrp584kx3nfshxkhwmj5gpzxk";
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-crt-git-9.0.0.6454.b4445ee52-1-any.pkg.tar.zst"; url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-crt-git-9.0.0.6451.a3f6d363d-1-any.pkg.tar.zst";
sha256 = "0bnzwgf395fbwbsq8900prj409b081hi0dd76kak6d971xqyy2r4"; sha256 = "1ccipidbsjncdhr48k50ia53dwn7v3ghdl8f1svgwvnh3mrx0bww";
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
@ -46,8 +46,8 @@
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-libwinpthread-git-9.0.0.6454.b4445ee52-1-any.pkg.tar.zst"; url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-libwinpthread-git-9.0.0.6451.a3f6d363d-1-any.pkg.tar.zst";
sha256 = "181fm72bi6cs348hixkqjzivizzcsyn2lxvnbqprx4366prjf7nn"; sha256 = "0qdy79l5y02lw2xa8i3j6yayhz8a7awfgyyd82pcmbzwx57q2xqb";
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
@ -61,8 +61,8 @@
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-winpthreads-git-9.0.0.6454.b4445ee52-1-any.pkg.tar.zst"; url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-winpthreads-git-9.0.0.6451.a3f6d363d-1-any.pkg.tar.zst";
sha256 = "0n3pim85wlsc93y9sh06rnfraqgzbz300sp9hd8n7wgvcsmpj9rx"; sha256 = "08zwgkrp45y5ry8avz61krasjkk4k4a5rrdz4nd78bbbah84mpgz";
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
@ -86,8 +86,8 @@
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-expat-2.4.8-1-any.pkg.tar.zst"; url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-expat-2.4.7-1-any.pkg.tar.zst";
sha256 = "1qkw4k61ddaflns5ms0xh0czbx99wxhs0dfbk8sv8by2rkshl51k"; sha256 = "19qh3kk2kmkkzxirpx1swgfsfb29gy9q8qgdmrzzbwrqrn8vs77j";
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
@ -101,8 +101,8 @@
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-libidn2-2.3.2-1-any.pkg.tar.zst"; url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-libidn2-2.3.1-1-any.pkg.tar.zst";
sha256 = "0p694g8g716zyvcxc48xmdanjyrkp3ir4naqlradrw2szy9bj800"; sha256 = "00vm6d56ldr1f4h0dn15j0ja17dif45qxlxaqv4x5nw555frklf5";
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
@ -231,8 +231,8 @@
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-cmake-3.23.0-1-any.pkg.tar.zst"; url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-cmake-3.22.3-2-any.pkg.tar.zst";
sha256 = "1gcmm3bd29zfd88ack6xdqwmbskyvhb4ymrfspayk4jfcj4svky5"; sha256 = "1xp8n5s98va7a9cq36d9p49lk32yv9vkvlayc4d4j465xzm21hgp";
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
@ -266,8 +266,8 @@
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-sqlite3-3.38.2-1-any.pkg.tar.zst"; url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-sqlite3-3.38.1-1-any.pkg.tar.zst";
sha256 = "14agi4611h5400j7bqh1w5i5qbhp4hp6apzaddilxq97y37vj90q"; sha256 = "04h4m72mwmad82nzrl5qj9wlsinjs7z7bsbbq17dxkx92aj75p26";
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
@ -291,17 +291,12 @@
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-openblas-0.3.20-2-any.pkg.tar.zst"; url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-openblas-0.3.20-1-any.pkg.tar.zst";
sha256 = "1cj0j06b2xhcvq9v6jx5cn130r8pkv2xa885f3z3z98kmrifjw0l"; sha256 = "1adbbycbvs2nkjhgap92fk3x0vqfjb3ghhvyd1xlnn56c5n0iphf";
}) })
(pkgs.fetchurl { (pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-python-numpy-1.21.5-1-any.pkg.tar.zst"; url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-python-numpy-1.21.5-1-any.pkg.tar.zst";
sha256 = "10bhfq65nrzxipgy75bqaad74daif4ay06phwvbx70b9j0wm33c3"; sha256 = "10bhfq65nrzxipgy75bqaad74daif4ay06phwvbx70b9j0wm33c3";
}) })
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-python-setuptools-59.8.0-2-any.pkg.tar.zst";
sha256 = "1jbvsmh1r00yb6fm8by6z7xp9069f9lkj73jrsnxmflmvpdkjl5c";
})
] ]