Compare commits

..

8 Commits

Author SHA1 Message Date
ychenfo aebfd0a37d nac3core/artiq: raise ValueError for unwrap none 2022-03-26 01:54:42 +08:00
ychenfo 91d697c327 nac3standalone: add tests for option 2022-03-26 01:54:42 +08:00
ychenfo d18292dd28 nac3core/artiq: use none instead of None 2022-03-26 01:54:42 +08:00
ychenfo 29da2d1a9a nac3artiq/core: host option object support 2022-03-26 01:54:42 +08:00
ychenfo 34b460757b nac3core: option type codegen support 2022-03-26 01:54:42 +08:00
ychenfo 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
ychenfo 65110a2cf2 nac3core: fix broken tests 2022-03-25 03:49:57 +08:00
ychenfo 3d39a80df6 nac3core: option type front end 2022-03-25 02:37:08 +08:00
42 changed files with 278 additions and 798 deletions

117
Cargo.lock generated
View File

@ -249,9 +249,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.6"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
"cfg-if",
"libc",
@ -278,9 +278,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "1.8.1"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
@ -329,7 +329,7 @@ dependencies = [
"libc",
"llvm-sys",
"once_cell",
"parking_lot 0.11.2",
"parking_lot",
"regex",
]
@ -457,11 +457,10 @@ dependencies = [
[[package]]
name = "lock_api"
version = "0.4.7"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
dependencies = [
"autocfg",
"scopeguard",
]
@ -496,7 +495,7 @@ dependencies = [
"inkwell",
"nac3core",
"nac3parser",
"parking_lot 0.11.2",
"parking_lot",
"pyo3",
"tempfile",
]
@ -507,7 +506,7 @@ version = "0.1.0"
dependencies = [
"fxhash",
"lazy_static",
"parking_lot 0.11.2",
"parking_lot",
"string-interner",
]
@ -521,7 +520,7 @@ dependencies = [
"insta",
"itertools",
"nac3parser",
"parking_lot 0.11.2",
"parking_lot",
"rayon",
"regex",
"test-case",
@ -550,7 +549,7 @@ dependencies = [
"inkwell",
"nac3core",
"nac3parser",
"parking_lot 0.11.2",
"parking_lot",
]
[[package]]
@ -583,17 +582,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core 0.8.5",
]
[[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",
"parking_lot_core",
]
[[package]]
@ -610,19 +599,6 @@ dependencies = [
"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]]
name = "paste"
version = "0.1.18"
@ -756,7 +732,7 @@ dependencies = [
"cfg-if",
"indoc 0.3.6",
"libc",
"parking_lot 0.11.2",
"parking_lot",
"paste",
"pyo3-build-config",
"pyo3-macros",
@ -797,9 +773,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.17"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57"
dependencies = [
"proc-macro2",
]
@ -861,18 +837,18 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.2.13"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.4.3"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
checksum = "7776223e2696f1aa4c6b0170e83212f47296a00424305117d013dfe86fb0fe55"
dependencies = [
"getrandom",
"redox_syscall",
@ -1022,22 +998,22 @@ dependencies = [
[[package]]
name = "string_cache"
version = "0.8.4"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08"
checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26"
dependencies = [
"lazy_static",
"new_debug_unreachable",
"once_cell",
"parking_lot 0.12.0",
"parking_lot",
"phf_shared 0.10.0",
"precomputed-hash",
]
[[package]]
name = "syn"
version = "1.0.90"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f"
checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54"
dependencies = [
"proc-macro2",
"quote",
@ -1231,49 +1207,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "yaml-rust"
version = "0.4.5"

View File

@ -40,20 +40,17 @@ python setup.py install
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 -S unzip
wget https://nixbld.m-labs.hk/build/115529/download/1/nac3artiq.zip # edit the build number
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
```
Do the same for ``lld-msys2``:
Install additional NAC3 dependencies:
```
wget https://nixbld.m-labs.hk/build/115527/download/1/ld.lld.exe
mv ld.lld.exe C:/msys64/mingw64/bin
pacman -S mingw-w64-x86_64-lld
```
And you should be good to go.
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.
## For developers
This repository contains:

View File

@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1648553562,
"narHash": "sha256-xQhRKu6h0phd56oCzGjkhHkY4eDI1XKedGqkFtlXapk=",
"lastModified": 1647992509,
"narHash": "sha256-AG40Nt5OWz0LBs5p457emOuwLKOvTtcv/2fUdnEN3Ws=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9b168e5e62406fa2e55e132f390379a6ba22b402",
"rev": "d2caa9377539e3b5ff1272ac3aa2d15f3081069f",
"type": "github"
},
"original": {

View File

@ -8,7 +8,7 @@
pkgs = import nixpkgs { system = "x86_64-linux"; };
in rec {
packages.x86_64-linux = rec {
llvm-nac3 = pkgs.callPackage ./nix/llvm {};
llvm-nac3 = pkgs.callPackage "${self}/llvm" {};
nac3artiq = pkgs.python3Packages.toPythonModule (
pkgs.rustPlatform.buildRustPackage {
name = "nac3artiq";
@ -48,7 +48,7 @@
};
# LLVM PGO support
llvm-nac3-instrumented = pkgs.callPackage ./nix/llvm {
llvm-nac3-instrumented = pkgs.callPackage "${self}/llvm" {
stdenv = pkgs.llvmPackages_13.stdenv;
extraCmakeFlags = [ "-DLLVM_BUILD_INSTRUMENTED=IR" ];
};
@ -86,7 +86,7 @@
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;
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 {
name = "nac3-dev-shell";
@ -129,7 +129,7 @@
];
};
devShells.x86_64-linux.msys2 = pkgs.mkShell {
name = "nac3-dev-shell-msys2";
name = "nac3-dev-shell";
buildInputs = with pkgs; [
curl
pacman
@ -142,7 +142,6 @@
inherit (packages.x86_64-linux) llvm-nac3 nac3artiq;
llvm-nac3-msys2 = packages.x86_64-w64-mingw32.llvm-nac3;
nac3artiq-msys2 = packages.x86_64-w64-mingw32.nac3artiq;
lld-msys2 = packages.x86_64-w64-mingw32.lld;
};
};

View File

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

View File

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

View File

@ -6,7 +6,7 @@ use nac3core::{
},
symbol_resolver::ValueEnum,
toplevel::{DefinitionId, GenCall},
typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum}
typecheck::typedef::{FunSignature, Type},
};
use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
@ -15,9 +15,7 @@ use inkwell::{
context::Context, module::Linkage, types::IntType, values::BasicValueEnum, AddressSpace,
};
use pyo3::{PyObject, PyResult, Python, types::{PyDict, PyList}};
use crate::{symbol_resolver::InnerResolver, timeline::TimeFns};
use crate::timeline::TimeFns;
use std::{
collections::hash_map::DefaultHasher,
@ -272,6 +270,8 @@ fn gen_rpc_tag<'ctx, 'a>(
buffer.push(b'l');
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))),
}
}
@ -291,7 +291,7 @@ fn rpc_codegen_callback_fn<'ctx, 'a>(
let int32 = ctx.ctx.i32_type();
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
let mut tag = Vec::new();
if obj.is_some() {
@ -361,10 +361,7 @@ fn rpc_codegen_callback_fn<'ctx, 'a>(
}
// default value handling
for k in keys.into_iter() {
mapping.insert(
k.name,
ctx.gen_symbol_val(generator, &k.default_value.unwrap(), k.ty).into()
);
mapping.insert(k.name, ctx.gen_symbol_val(generator, &k.default_value.unwrap()).into());
}
// reorder the parameters
let mut real_params = fun
@ -489,81 +486,6 @@ fn rpc_codegen_callback_fn<'ctx, 'a>(
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, .. } => {
// 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)?.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)?.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> {
Arc::new(GenCall::new(Box::new(|ctx, obj, fun, args, generator| {
rpc_codegen_callback_fn(ctx, obj, fun, args, generator)

View File

@ -10,7 +10,6 @@ use inkwell::{
targets::*,
OptimizationLevel,
};
use nac3core::codegen::gen_func_impl;
use nac3core::toplevel::builtins::get_exn_constructor;
use nac3core::typecheck::typedef::{TypeEnum, Unifier};
use nac3parser::{
@ -37,7 +36,6 @@ use nac3core::{
use tempfile::{self, TempDir};
use crate::codegen::attributes_writeback;
use crate::{
codegen::{rpc_codegen_callback, ArtiqCodeGenerator},
symbol_resolver::{InnerResolver, PythonHelper, Resolver, DeferredEvaluationStore},
@ -478,8 +476,6 @@ impl Nac3 {
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_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 {
id_fn: builtins.getattr("id").unwrap().to_object(py),
len_fn: builtins.getattr("len").unwrap().to_object(py),
@ -500,13 +496,13 @@ impl Nac3 {
"KeyError",
"NotImplementedError",
"OverflowError",
"IOError",
"UnwrapNoneError",
"IOError"
];
add_exceptions(&mut composer, &mut builtins_def, &mut builtins_ty, &exception_names);
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![];
for (stmt, path, module) in self.top_levels.iter() {
let py_module: &PyAny = module.extract(py)?;
@ -620,7 +616,7 @@ impl Nac3 {
};
let mut synthesized =
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_def: builtins_def.clone().into(),
pyid_to_def: self.pyid_to_def.clone(),
@ -637,18 +633,17 @@ impl Nac3 {
string_store: self.string_store.clone(),
exception_ids: self.exception_ids.clone(),
deferred_eval_store: self.deferred_eval_store.clone(),
});
let resolver = Arc::new(Resolver(inner_resolver.clone())) as Arc<dyn SymbolResolver + Send + Sync>;
}))) as Arc<dyn SymbolResolver + Send + Sync>;
let (_, def_id, _) = composer
.register_top_level(synthesized.pop().unwrap(), Some(resolver.clone()), "".into())
.unwrap();
let fun_signature =
let signature =
FunSignature { args: vec![], ret: self.primitive.none, vars: HashMap::new() };
let mut store = ConcreteTypeStore::new();
let mut cache = HashMap::new();
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);
if let Err(e) = composer.start_analysis(true) {
@ -725,27 +720,10 @@ impl Nac3 {
symbol_name: "__modinit__".to_string(),
body: instance.body,
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,
store,
unifier_index: instance.unifier_id,
calls: Arc::new(Default::default()),
calls: instance.calls,
id: 0,
};
let isa = self.isa;
@ -767,27 +745,14 @@ impl Nac3 {
.map(|s| Box::new(ArtiqCodeGenerator::new(s.to_string(), size_t, self.time_fns)))
.collect();
let membuffer = membuffers.clone();
py.allow_threads(|| {
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level.clone(), f);
registry.add_task(task);
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 context = inkwell::context::Context::create();
let main = context
.create_module_from_ir(MemoryBuffer::create_from_memory_range(&buffers[0], "main"))
.unwrap();
@ -799,11 +764,6 @@ impl Nac3 {
main.link_in_module(other)
.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))
.map_err(|err| CompileError::new_err(err.to_string()))?;
@ -867,11 +827,7 @@ impl Nac3 {
);
}
#[cfg(not(windows))]
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 let Ok(linker_status) = Command::new("ld.lld").args(linker_args).status() {
if !linker_status.success() {
return Err(CompileError::new_err("failed to start linker"));
}

View File

@ -15,7 +15,7 @@ use pyo3::{
PyAny, PyObject, PyResult, Python,
};
use std::{
collections::HashMap,
collections::{HashMap, HashSet},
sync::{
Arc,
atomic::{AtomicBool, Ordering::Relaxed}
@ -54,7 +54,7 @@ pub struct InnerResolver {
pub id_to_pyval: RwLock<HashMap<StrRef, (u64, PyObject)>>,
pub id_to_primitive: RwLock<HashMap<u64, PrimitiveValue>>,
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 pyid_to_def: Arc<RwLock<HashMap<u64, DefinitionId>>>,
pub pyid_to_type: Arc<RwLock<HashMap<u64, Type>>>,
@ -503,7 +503,7 @@ impl InnerResolver {
}
}
pub fn get_obj_type(
fn get_obj_type(
&self,
py: Python,
obj: &PyAny,
@ -512,8 +512,8 @@ impl InnerResolver {
primitives: &PrimitiveStore,
) -> PyResult<Result<Type, String>> {
let ty = self.helper.type_fn.call1(py, (obj,)).unwrap();
let py_obj_id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
if let Some(ty) = self.pyid_to_type.read().get(&py_obj_id) {
let ty_id: u64 = self.helper.id_fn.call1(py, (ty.clone(),))?.extract(py)?;
if let Some(ty) = self.pyid_to_type.read().get(&ty_id) {
return Ok(Ok(*ty))
}
let (extracted_ty, inst_check) = match self.get_pyty_obj_type(
@ -605,7 +605,7 @@ impl InnerResolver {
unreachable!("must be tobj")
}
}
let ty = match self.get_obj_type(py, field_data, unifier, defs, primitives)? {
Ok(t) => t,
Err(e) => {
@ -620,7 +620,6 @@ impl InnerResolver {
Ok(Ok(res))
}
(TypeEnum::TObj { params, fields, .. }, false) => {
self.pyid_to_type.write().insert(py_obj_id, extracted_ty);
let var_map = params
.iter()
.map(|(id_var, ty)| {
@ -674,19 +673,13 @@ impl InnerResolver {
let extracted_ty = unifier.subst(extracted_ty, &var_map).unwrap_or(extracted_ty);
Ok(Ok(extracted_ty))
};
let result = 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
instantiate_obj()
}
_ => Ok(Ok(extracted_ty)),
}
}
pub fn get_obj_value<'ctx, 'a>(
fn get_obj_value<'ctx, 'a>(
&self,
py: Python,
obj: &PyAny,
@ -754,13 +747,13 @@ impl InnerResolver {
.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(|| {
ctx.module.add_global(arr_ty, Some(AddressSpace::Generic), &id_str)
});
return Ok(Some(global.as_pointer_value().into()));
} else {
self.global_value_ids.write().insert(id, obj.into());
self.global_value_ids.write().insert(id);
}
}
@ -808,13 +801,50 @@ impl InnerResolver {
Ok(Some(global.as_pointer_value().into()))
} else if ty_id == self.primitive_ids.tuple {
let id_str = id.to_string();
if let Some(global) = ctx.module.get_global(&id_str) {
return Ok(Some(global.as_pointer_value().into()));
}
let elements: &PyTuple = obj.cast_as()?;
let types: Result<Result<Vec<_>, _>, _> = elements
.iter()
.enumerate()
.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);
}
}
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);
Ok(Some(val.into()))
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 {
// for option type, just a null ptr, whose type needs to be casted in codegen
@ -832,13 +862,13 @@ impl InnerResolver {
Some(v) => {
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(|| {
ctx.module.add_global(v.get_type(), Some(AddressSpace::Generic), &global_str)
});
return Ok(Some(global.as_pointer_value().into()));
} 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);
@ -865,13 +895,13 @@ impl InnerResolver {
.get_element_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(|| {
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, obj.into());
self.global_value_ids.write().insert(id);
}
}
// should be classes
@ -880,32 +910,15 @@ impl InnerResolver {
if let TopLevelDef::Class { fields, .. } = &*definition {
let values: Result<Option<Vec<_>>, _> = fields
.iter()
.map(|(name, ty, _)| {
let v = self.get_obj_value(py, obj.getattr(&name.to_string())?, ctx, generator)
.map_err(|e| super::CompileError::new_err(format!("Error getting field {}: {}", name, e)));
match (v, ctx.unifier.get_ty_immutable(*ty).as_ref()) {
(Ok(Some(v)), TypeEnum::TObj { obj_id, params, .. })
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);
Ok(Some(ctx.builder.build_bitcast(
v,
actual_ptr_ty,
"option_none_ptr_cast",
)))
}
(v, _) => v,
}
.map(|(name, _, _)| {
self.get_obj_value(py, obj.getattr(&name.to_string())?, ctx, generator).map_err(|e|
super::CompileError::new_err(format!("Error getting field {}: {}", name, e)))
})
.collect();
let values = values?;
if let Some(values) = values {
let val = ty.const_named_struct(&values);
let global = ctx.module.get_global(&id_str).unwrap_or_else(|| {
ctx.module.add_global(ty, Some(AddressSpace::Generic), &id_str)
});
let global = ctx.module.add_global(ty, Some(AddressSpace::Generic), &id_str);
global.set_initializer(&val);
Ok(Some(global.as_pointer_value().into()))
} else {
@ -922,7 +935,6 @@ impl InnerResolver {
py: Python,
obj: &PyAny,
) -> PyResult<Result<SymbolValue, String>> {
let id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
let ty_id: u64 =
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 {
@ -931,12 +943,6 @@ impl InnerResolver {
} else if ty_id == self.primitive_ids.int64 {
let val: i64 = obj.extract()?;
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 {
let val: bool = obj.extract()?;
Ok(SymbolValue::Bool(val))
@ -947,17 +953,13 @@ impl InnerResolver {
let elements: &PyTuple = obj.cast_as()?;
let elements: Result<Result<Vec<_>, String>, _> =
elements.iter().map(|elem| self.get_default_param_obj_value(py, elem)).collect();
elements?.map(SymbolValue::Tuple)
} else if ty_id == self.primitive_ids.option {
if id == self.primitive_ids.none {
Ok(SymbolValue::OptionNone)
} else {
self
.get_default_param_obj_value(py, obj.getattr("_nac3_option").unwrap())?
.map(|v| SymbolValue::OptionSome(Box::new(v)))
}
let elements = match elements? {
Ok(el) => el,
Err(err) => return Ok(Err(err)),
};
Ok(SymbolValue::Tuple(elements))
} 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())
})
}
}
@ -973,9 +975,8 @@ impl SymbolResolver for Resolver {
for (key, val) in members.iter() {
let key: &str = key.extract()?;
if key == id.to_string() {
if let Ok(Ok(v)) = self.0.get_default_param_obj_value(py, val) {
sym_value = Some(v)
}
sym_value =
Some(self.0.get_default_param_obj_value(py, val).unwrap().unwrap());
break;
}
}
@ -983,7 +984,7 @@ impl SymbolResolver for Resolver {
})
.unwrap()
}
_ => unreachable!("only for resolving names"),
_ => unimplemented!("other type of expr not supported at {}", expr.location),
}
}

View File

@ -91,7 +91,6 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
&mut self,
generator: &mut dyn CodeGenerator,
val: &SymbolValue,
ty: Type,
) -> BasicValueEnum<'ctx> {
match val {
SymbolValue::I32(v) => self.ctx.i32_type().const_int(*v as u64, true).into(),
@ -108,7 +107,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
ty.const_named_struct(&[str_ptr, size.into()]).into()
}
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 ty = self.ctx.struct_type(&fields, false);
let ptr = self.builder.build_alloca(ty, "tuple");
@ -125,37 +124,6 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
}
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);
self.builder.build_bitcast(
self.ctx.i8_type().ptr_type(AddressSpace::Generic).const_null(),
actual_ptr_type,
"default_opt_none",
)
}
}
}
@ -387,9 +355,9 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
}
}
pub fn gen_string<S: Into<String>>(
pub fn gen_string<G: CodeGenerator, S: Into<String>>(
&mut self,
generator: &mut dyn CodeGenerator,
generator: &mut G,
s: S,
) -> BasicValueEnum<'ctx> {
self.gen_const(generator, &nac3parser::ast::Constant::Str(s.into()), self.primitives.str)
@ -442,19 +410,6 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
err_msg: &str,
params: [Option<IntValue<'ctx>>; 3],
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<G: CodeGenerator>(
&mut self,
generator: &mut G,
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_true = i1.const_all_ones();
@ -481,6 +436,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
let exn_block = self.ctx.append_basic_block(current_fun, "fail");
self.builder.build_conditional_branch(cond, then_block, 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.builder.position_at_end(then_block);
}
@ -637,7 +593,7 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
}
mapping.insert(
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
@ -948,12 +904,15 @@ pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
} else if ty1 == ctx.primitives.float && ty2 == ctx.primitives.int32 {
// Pow is the only operator that would pass typecheck between float and int
assert!(*op == Operator::Pow);
let i32_t = ctx.ctx.i32_type();
let pow_intr = ctx.module.get_function("llvm.powi.f64.i32").unwrap_or_else(|| {
// TODO: throw exception when rhs is out of i16 bound
// 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 ty = f64_t.fn_type(&[f64_t.into(), i32_t.into()], false);
ctx.module.add_function("llvm.powi.f64.i32", ty, None)
let ty = f64_t.fn_type(&[f64_t.into(), i16_t.into()], false);
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
.build_call(pow_intr, &[left.into(), right.into()], "f_pow_i")
.try_as_basic_value()
@ -998,22 +957,27 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
None => {
let resolver = ctx.resolver.clone();
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()) {
TypeEnum::TObj { obj_id, params, .. }
if *obj_id == ctx.primitives.option.get_obj_id(&ctx.unifier) =>
{
if let BasicValueEnum::PointerValue(ptr) = val.to_basic_value_enum(ctx, generator)? {
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()
} else {
unreachable!("option obj must be ptr")
}
}
_ => val,
}
}
@ -1026,7 +990,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
.map(|x| {
generator
.gen_expr(ctx, x)
.map_or_else(Err, |v| v.unwrap().to_basic_value_enum(ctx, generator))
.map_or_else(|e| Err(e), |v| v.unwrap().to_basic_value_enum(ctx, generator))
})
.collect::<Result<Vec<_>, _>>()?;
let ty = if elements.is_empty() {
@ -1059,7 +1023,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
.map(|x| {
generator
.gen_expr(ctx, x)
.map_or_else(Err, |v| v.unwrap().to_basic_value_enum(ctx, generator))
.map_or_else(|e| Err(e), |v| v.unwrap().to_basic_value_enum(ctx, generator))
})
.collect::<Result<Vec<_>, _>>()?;
let element_ty = element_val.iter().map(BasicValueEnum::get_type).collect_vec();
@ -1087,7 +1051,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
v.into_pointer_value(),
&[zero, int32.const_int(index as u64, false)],
))) as Result<_, String>
}, Ok)?,
}, |v| Ok(v))?,
ValueEnum::Dynamic(v) => {
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
ValueEnum::Dynamic(ctx.build_gep_and_load(
@ -1268,44 +1232,21 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
.unwrap()
.to_basic_value_enum(ctx, generator)?
.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 then_bb = ctx.ctx.append_basic_block(current, "then");
let else_bb = ctx.ctx.append_basic_block(current, "else");
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
ctx.builder.build_conditional_branch(test, then_bb, else_bb);
ctx.builder.position_at_end(then_bb);
let a = generator.gen_expr(ctx, body)?;
match result {
None => None,
Some(v) => {
let a = a.unwrap().to_basic_value_enum(ctx, generator)?;
Some(ctx.builder.build_store(v, a))
}
};
let a = generator.gen_expr(ctx, body)?.unwrap().to_basic_value_enum(ctx, generator)?;
ctx.builder.build_unconditional_branch(cont_bb);
ctx.builder.position_at_end(else_bb);
let b = generator.gen_expr(ctx, orelse)?;
match result {
None => None,
Some(v) => {
let b = b.unwrap().to_basic_value_enum(ctx, generator)?;
Some(ctx.builder.build_store(v, b))
}
};
let b = generator.gen_expr(ctx, orelse)?.unwrap().to_basic_value_enum(ctx, generator)?;
ctx.builder.build_unconditional_branch(cont_bb);
ctx.builder.position_at_end(cont_bb);
match result {
None => return Ok(None),
Some(v) => return Ok(Some(ctx.builder.build_load(v, "if_exp_val_load").into()))
}
let phi = ctx.builder.build_phi(a.get_type(), "ifexpr");
phi.add_incoming(&[(&a, then_bb), (&b, else_bb)]);
phi.as_basic_value().into()
}
ExprKind::Call { func, args, keywords } => {
let mut params = args
@ -1378,8 +1319,8 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
ctx.make_assert(
generator,
not_null,
"0:UnwrapNoneError",
"",
"0:ValueError",
"unwrap on none",
[None, None, None],
expr.location,
);

View File

@ -360,14 +360,13 @@ fn need_sret<'ctx>(ctx: &'ctx Context, ty: BasicTypeEnum<'ctx>) -> bool {
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,
generator: &mut G,
registry: &WorkerRegistry,
builder: Builder<'ctx>,
module: Module<'ctx>,
task: CodeGenTask,
codegen_function: F
) -> Result<(Builder<'ctx>, Module<'ctx>, FunctionValue<'ctx>), (Builder<'ctx>, String)> {
let top_level_ctx = registry.top_level_ctx.clone();
let static_value_store = registry.static_value_store.clone();
@ -573,34 +572,25 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
need_sret: has_sret
};
let result = codegen_function(generator, &mut code_gen_context);
let mut err = None;
for stmt in task.body.iter() {
if let Err(e) = generator.gen_stmt(&mut code_gen_context, stmt) {
err = Some(e);
break;
}
if code_gen_context.is_terminated() {
break;
}
}
// after static analysis, only void functions can have no return at the end.
if !code_gen_context.is_terminated() {
code_gen_context.builder.build_return(None);
}
let CodeGenContext { builder, module, .. } = code_gen_context;
if let Err(e) = result {
if let Some(e) = err {
return Err((builder, e));
}
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

@ -189,8 +189,7 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
if ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range) {
// setup
let iter_val = iter_val.into_pointer_value();
let i = generator.gen_var_alloc(ctx, int32.into())?;
let user_i = generator.gen_store_target(ctx, target)?;
let i = generator.gen_store_target(ctx, target)?;
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_unconditional_branch(test_bb);
@ -208,7 +207,6 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
"start_loop",
);
ctx.builder.build_store(i, tmp);
ctx.builder.build_store(user_i, tmp);
// // if step > 0, continue when i < end
let cmp1 = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, end, "cmp1");
// if step < 0, continue when i > end
@ -975,25 +973,7 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
gen_raise(generator, ctx, None, stmt.location);
}
}
StmtKind::Assert { test, msg, .. } => {
let test =
generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(ctx, generator)?;
let err_msg = match msg {
Some(msg) => {
generator.gen_expr(ctx, msg)?.unwrap().to_basic_value_enum(ctx, generator)?
}
None => ctx.gen_string(generator, ""),
};
ctx.make_assert_impl(
generator,
test.into_int_value(),
"0:AssertionError",
err_msg,
[None, None, None],
stmt.location,
)
}
_ => unimplemented!()
_ => unimplemented!(),
};
Ok(())
}

View File

@ -71,7 +71,7 @@ impl SymbolResolver for Resolver {
unimplemented!()
}
fn get_exception_id(&self, _tyid: usize) -> usize {
fn get_exception_id(&self, tyid: usize) -> usize {
unimplemented!()
}
}
@ -180,22 +180,13 @@ fn test_primitives() {
let expected = indoc! {"
; ModuleID = 'test'
source_filename = \"test\"
define i32 @testing(i32 %0, i32 %1) {
init:
%add = add i32 %0, %1
%cmp = icmp eq i32 %add, 1
br i1 %cmp, label %then, label %else
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
%ifexpr = select i1 %cmp, i32 %0, i32 0
ret i32 %ifexpr
}
"}
.trim();

View File

@ -14,7 +14,7 @@ use crate::{
typedef::{Type, Unifier},
},
};
use inkwell::values::{BasicValueEnum, FloatValue, IntValue, PointerValue, StructValue};
use inkwell::values::{BasicValueEnum, FloatValue, IntValue, PointerValue};
use itertools::{chain, izip};
use nac3parser::ast::{Expr, Location, StrRef};
use parking_lot::RwLock;
@ -29,8 +29,6 @@ pub enum SymbolValue {
Double(f64),
Bool(bool),
Tuple(Vec<SymbolValue>),
OptionSome(Box<SymbolValue>),
OptionNone,
}
impl Display for SymbolValue {
@ -52,8 +50,6 @@ impl Display for SymbolValue {
SymbolValue::Tuple(t) => {
write!(f, "({})", t.iter().map(|v| format!("{}", v)).collect::<Vec<_>>().join(", "))
}
SymbolValue::OptionSome(v) => write!(f, "Some({})", v),
SymbolValue::OptionNone => write!(f, "none"),
}
}
}
@ -110,12 +106,6 @@ 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> {
pub fn to_basic_value_enum<'a>(
self,

View File

@ -105,8 +105,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
("__param2__".into(), int64, true),
];
// for Option, is_some and is_none share the same type: () -> bool,
// and they are methods under the same class `Option`
// for Option, is_some and is_none share the same type
let (is_some_ty, unwrap_ty, (option_ty_var, option_ty_var_id)) =
if let TypeEnum::TObj { fields, params, .. } =
primitives.1.get_ty(primitives.0.option).as_ref()
@ -263,7 +262,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|_, _, _, _, _| {
|ctx, obj, _, _, generator| {
unreachable!("handled in gen_expr")
},
)))),

View File

@ -91,7 +91,7 @@ impl TopLevelComposer {
assert!(name == *simple_name);
builtin_ty.insert(name, *signature);
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);
if let Some(constructor) = constructor {

View File

@ -416,77 +416,76 @@ impl TopLevelComposer {
primitive: &PrimitiveStore,
unifier: &mut Unifier,
) -> Result<(), String> {
fn type_default_param(
val: &SymbolValue,
primitive: &PrimitiveStore,
unifier: &mut Unifier,
) -> TypeAnnotation {
match val {
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)
let res = match val {
SymbolValue::Bool(..) => {
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.bool) {
None
} else {
Some("bool".to_string())
}
SymbolValue::OptionNone => TypeAnnotation::CustomClass {
id: primitive.option.get_obj_id(unifier),
params: Default::default(),
},
SymbolValue::OptionSome(v) => {
let ty = type_default_param(v, primitive, unifier);
TypeAnnotation::CustomClass {
id: primitive.option.get_obj_id(unifier),
params: vec![ty],
}
SymbolValue::Double(..) => {
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.float) {
None
} else {
Some("float".to_string())
}
}
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())
}
}
}
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) {
};
if let Some(found) = res {
Err(format!(
"incompatible default parameter type, expect {}, found {}",
ty.stringify(unifier),
found.stringify(unifier),
found
))
} else {
Ok(())
@ -512,10 +511,6 @@ pub fn parse_parameter_default_value(
Constant::Tuple(tuple) => Ok(SymbolValue::Tuple(
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),
}
}
@ -553,11 +548,6 @@ pub fn parse_parameter_default_value(
}
_ => 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)),
}
}
@ -566,20 +556,15 @@ pub fn parse_parameter_default_value(
.map(|x| parse_parameter_default_value(x, resolver))
.collect::<Result<Vec<_>, _>>()?
)),
ast::ExprKind::Name { id, .. } if id == &"none".into() => Ok(SymbolValue::OptionNone),
ast::ExprKind::Name { id, .. } => {
resolver.get_default_param_value(default).ok_or_else(
|| format!(
"`{}` cannot be used as a default parameter at {} \
(not primitive type, option or tuple / not defined?)",
"`{}` cannot be used as a default parameter at {} (not primitive type or tuple / not defined?)",
id,
default.location
)
)
}
_ => Err(format!(
"unsupported default parameter (not primitive type, option or tuple) at {}",
default.location
))
_ => Err(format!("unsupported default parameter 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.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.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.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",
"Class {\nname: \"B\",\nancestors: [\"B[var7]\", \"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: [\"var7\"]\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.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",
]

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",
"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.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",
"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",
]

View File

@ -5,10 +5,10 @@ expression: res_vec
---
[
"Class {\nname: \"A\",\nancestors: [\"A[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",
"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.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.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",

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.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",
"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",
"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.fun\",\nsig: \"fn[[b:B], 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
assertion_line: 549
assertion_line: 541
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> {
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 {
unimplemented!()
}
fn get_exception_id(&self, _tyid: usize) -> usize {
fn get_exception_id(&self, tyid: usize) -> usize {
unimplemented!()
}
}

View File

@ -29,28 +29,20 @@ impl TypeAnnotation {
{
(*name).into()
} else {
unreachable!()
format!("def_{}", id.0)
}
}
None => format!("class_def_{}", id.0),
None => format!("def_{}", id.0),
};
format!(
"{}{}",
"{{class: {}, params: {:?}}}",
class_name,
{
let param_list = params.iter().map(|p| p.stringify(unifier)).collect_vec().join(", ");
if param_list.is_empty() {
"".into()
} else {
format!("[{}]", param_list)
}
}
params.iter().map(|p| p.stringify(unifier)).collect_vec()
)
}
Virtual(ty) => format!("virtual[{}]", ty.stringify(unifier)),
List(ty) => format!("list[{}]", ty.stringify(unifier)),
Virtual(ty) | List(ty) => ty.stringify(unifier),
Tuple(types) => {
format!("tuple[{}]", types.iter().map(|p| p.stringify(unifier)).collect_vec().join(", "))
format!("({:?})", types.iter().map(|p| p.stringify(unifier)).collect_vec())
}
}
}

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)?;
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),
};
Ok(stmt)

View File

@ -44,14 +44,14 @@ impl SymbolResolver for Resolver {
}
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 {
unimplemented!()
}
fn get_exception_id(&self, _tyid: usize) -> usize {
fn get_exception_id(&self, tyid: usize) -> usize {
unimplemented!()
}
}

View File

@ -121,7 +121,7 @@ mod tests {
#[test]
fn test_parse_lambda() {
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);
}
@ -129,7 +129,7 @@ mod tests {
fn test_parse_tuples() {
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]
@ -140,7 +140,7 @@ class Foo(A, B):
pass
def method_with_default(self, arg='default'):
pass";
insta::assert_debug_snapshot!(parse_program(source, Default::default()).unwrap());
insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
}
#[test]
@ -183,7 +183,7 @@ while i < 2: # nac3: 4
# nac3: if1
if 1: # nac3: if2
3";
insta::assert_debug_snapshot!(parse_program(source, Default::default()).unwrap());
insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
}
#[test]
@ -196,7 +196,7 @@ while test: # nac3: while3
# nac3: simple assign0
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]
@ -215,7 +215,7 @@ if a: # nac3: small2
for i in a: # nac3: for1
pass
";
insta::assert_debug_snapshot!(parse_program(source, Default::default()).unwrap());
insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
}
#[test]
@ -224,6 +224,6 @@ for i in a: # nac3: for1
if a: # nac3: something
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!();
}
#[no_mangle]
pub extern "C" fn __nac3_raise(_state: u32, _exception_object: u32, _context: u32) -> u32 {
unimplemented!();
}
extern "C" {
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

@ -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,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

@ -33,14 +33,13 @@ let
};
in rec {
llvm-nac3 = pkgs.stdenvNoCC.mkDerivation rec {
pname = "llvm-nac3-msys2";
version = "13.0.1";
name = "llvm-nac3-msys2";
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=";
};
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=";
};
buildInputs = [ pkgs.wineWowPackages.stable ];
@ -74,12 +73,11 @@ in rec {
''
wine64 ninja install
'';
dontFixup = true;
};
nac3artiq = pkgs.rustPlatform.buildRustPackage {
name = "nac3artiq-msys2";
src = ../../.;
cargoLock = { lockFile = ../../Cargo.lock; };
name = "nac3artiq";
src = ../.;
cargoLock = { lockFile = ../Cargo.lock; };
nativeBuildInputs = [ pkgs.wineWowPackages.stable pkgs.zip ];
buildPhase =
''
@ -103,38 +101,6 @@ in rec {
'';
dontFixup = true;
};
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"
''
export WINEDEBUG=-all