Compare commits
No commits in common. "master" and "master" have entirely different histories.
72
Cargo.lock
generated
72
Cargo.lock
generated
@ -127,9 +127,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.18"
|
||||
version = "1.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||
checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@ -142,9 +142,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.35"
|
||||
version = "4.5.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
|
||||
checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@ -152,9 +152,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.35"
|
||||
version = "4.5.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
|
||||
checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@ -222,9 +222,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.15"
|
||||
version = "0.5.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
||||
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
@ -318,9 +318,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.11"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
@ -442,9 +442,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.9.0"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@ -584,9 +584,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.4"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
|
||||
|
||||
[[package]]
|
||||
name = "llvm-sys"
|
||||
@ -726,9 +726,9 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
version = "1.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
@ -897,9 +897,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3"
|
||||
version = "0.24.1"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17da310086b068fbdcefbba30aeb3721d5bb9af8db4987d6735b2183ca567229"
|
||||
checksum = "7f1c6c3591120564d64db2261bec5f910ae454f01def849b9c22835a84695e86"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"indoc",
|
||||
@ -915,9 +915,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-build-config"
|
||||
version = "0.24.1"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e27165889bd793000a098bb966adc4300c312497ea25cf7a690a9f0ac5aa5fc1"
|
||||
checksum = "e9b6c2b34cf71427ea37c7001aefbaeb85886a074795e35f161f5aecc7620a7a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"target-lexicon",
|
||||
@ -925,9 +925,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-ffi"
|
||||
version = "0.24.1"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05280526e1dbf6b420062f3ef228b78c0c54ba94e157f5cb724a609d0f2faabc"
|
||||
checksum = "5507651906a46432cdda02cd02dd0319f6064f1374c9147c45b978621d2c3a9c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pyo3-build-config",
|
||||
@ -935,9 +935,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-macros"
|
||||
version = "0.24.1"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c3ce5686aa4d3f63359a5100c62a127c9f15e8398e5fdeb5deef1fed5cd5f44"
|
||||
checksum = "b0d394b5b4fd8d97d48336bb0dd2aebabad39f1d294edd6bcd2cccf2eefe6f42"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"pyo3-macros-backend",
|
||||
@ -947,9 +947,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-macros-backend"
|
||||
version = "0.24.1"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4cf6faa0cbfb0ed08e89beb8103ae9724eb4750e3a78084ba4017cbe94f3855"
|
||||
checksum = "fd72da09cfa943b1080f621f024d2ef7e2773df7badd51aa30a2be1f8caa7c8e"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@ -1005,9 +1005,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.11"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
|
||||
checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@ -1050,9 +1050,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.5"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
|
||||
checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
@ -1165,9 +1165,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.0"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||
|
||||
[[package]]
|
||||
name = "string-interner"
|
||||
@ -1181,9 +1181,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.9"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
|
||||
checksum = "938d512196766101d333398efde81bc1f37b00cb42c2f8350e5df639f040bbbe"
|
||||
dependencies = [
|
||||
"new_debug_unreachable",
|
||||
"parking_lot",
|
||||
@ -1618,9 +1618,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.6"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
|
||||
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
6
flake.lock
generated
6
flake.lock
generated
@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1744098102,
|
||||
"narHash": "sha256-tzCdyIJj9AjysC3OuKA+tMD/kDEDAF9mICPDU7ix0JA=",
|
||||
"lastModified": 1741851582,
|
||||
"narHash": "sha256-cPfs8qMccim2RBgtKGF+x9IBCduRvd/N5F4nYpU0TVE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c8cd81426f45942bb2906d5ed2fe21d2f19d95b7",
|
||||
"rev": "6607cf789e541e7873d40d3a8f7815ea92204f32",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -1,27 +0,0 @@
|
||||
from min_artiq import kernel, KernelInvariant, nac3
|
||||
import min_artiq as artiq
|
||||
|
||||
|
||||
@nac3
|
||||
class Demo:
|
||||
core: KernelInvariant[artiq.Core]
|
||||
led0: KernelInvariant[artiq.TTLOut]
|
||||
led1: KernelInvariant[artiq.TTLOut]
|
||||
|
||||
def __init__(self):
|
||||
self.core = artiq.Core()
|
||||
self.led0 = artiq.TTLOut(self.core, 18)
|
||||
self.led1 = artiq.TTLOut(self.core, 19)
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
self.core.reset()
|
||||
while True:
|
||||
with artiq.parallel:
|
||||
self.led0.pulse(100.*artiq.ms)
|
||||
self.led1.pulse(100.*artiq.ms)
|
||||
self.core.delay(100.*artiq.ms)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
Demo().run()
|
@ -1,9 +1,9 @@
|
||||
from inspect import getfullargspec
|
||||
from functools import wraps
|
||||
from types import SimpleNamespace
|
||||
from numpy import int32, int64
|
||||
from typing import Generic, TypeVar
|
||||
from math import floor, ceil
|
||||
from numpy import int32, int64, uint32, uint64, float64, bool_, str_, ndarray
|
||||
from types import GenericAlias, ModuleType, SimpleNamespace
|
||||
from typing import _GenericAlias, Generic, TypeVar
|
||||
|
||||
import nac3artiq
|
||||
|
||||
@ -40,10 +40,10 @@ class Option(Generic[T]):
|
||||
|
||||
def is_none(self):
|
||||
return self._nac3_option is None
|
||||
|
||||
|
||||
def is_some(self):
|
||||
return not self.is_none()
|
||||
|
||||
|
||||
def unwrap(self):
|
||||
if self.is_none():
|
||||
raise UnwrapNoneError()
|
||||
@ -54,7 +54,7 @@ class Option(Generic[T]):
|
||||
return "none"
|
||||
else:
|
||||
return "Some({})".format(repr(self._nac3_option))
|
||||
|
||||
|
||||
def __str__(self) -> str:
|
||||
if self.is_none():
|
||||
return "none"
|
||||
@ -85,46 +85,13 @@ def ceil64(x):
|
||||
import device_db
|
||||
core_arguments = device_db.device_db["core"]["arguments"]
|
||||
|
||||
builtins = {
|
||||
"int": int,
|
||||
"float": float,
|
||||
"bool": bool,
|
||||
"str": str,
|
||||
"list": list,
|
||||
"tuple": tuple,
|
||||
"Exception": Exception,
|
||||
|
||||
"types": {
|
||||
"GenericAlias": GenericAlias,
|
||||
"ModuleType": ModuleType,
|
||||
},
|
||||
|
||||
"typing": {
|
||||
"_GenericAlias": _GenericAlias,
|
||||
"TypeVar": TypeVar,
|
||||
},
|
||||
|
||||
"numpy": {
|
||||
"int32": int32,
|
||||
"int64": int64,
|
||||
"uint32": uint32,
|
||||
"uint64": uint64,
|
||||
"float64": float64,
|
||||
"bool_": bool_,
|
||||
"str_": str_,
|
||||
"ndarray": ndarray,
|
||||
},
|
||||
|
||||
"artiq": {
|
||||
"Kernel": Kernel,
|
||||
"KernelInvariant": KernelInvariant,
|
||||
"_ConstGenericMarker": _ConstGenericMarker,
|
||||
"none": none,
|
||||
"virtual": virtual,
|
||||
"Option": Option,
|
||||
},
|
||||
artiq_builtins = {
|
||||
"none": none,
|
||||
"virtual": virtual,
|
||||
"_ConstGenericMarker": _ConstGenericMarker,
|
||||
"Option": Option,
|
||||
}
|
||||
compiler = nac3artiq.NAC3(core_arguments["target"], builtins)
|
||||
compiler = nac3artiq.NAC3(core_arguments["target"], artiq_builtins)
|
||||
allow_registration = True
|
||||
# Delay NAC3 analysis until all referenced variables are supposed to exist on the CPython side.
|
||||
registered_functions = set()
|
||||
@ -185,9 +152,9 @@ def nac3(cls):
|
||||
return cls
|
||||
|
||||
|
||||
ms: KernelInvariant[float] = 1e-3
|
||||
us: KernelInvariant[float] = 1e-6
|
||||
ns: KernelInvariant[float] = 1e-9
|
||||
ms = 1e-3
|
||||
us = 1e-6
|
||||
ns = 1e-9
|
||||
|
||||
@extern
|
||||
def rtio_init():
|
||||
@ -368,9 +335,9 @@ class UnwrapNoneError(Exception):
|
||||
"""raised when unwrapping a none value"""
|
||||
artiq_builtin = True
|
||||
|
||||
parallel: KernelInvariant[KernelContextManager] = KernelContextManager()
|
||||
legacy_parallel: KernelInvariant[KernelContextManager] = KernelContextManager()
|
||||
sequential: KernelInvariant[KernelContextManager] = KernelContextManager()
|
||||
parallel = KernelContextManager()
|
||||
legacy_parallel = KernelContextManager()
|
||||
sequential = KernelContextManager()
|
||||
|
||||
special_ids = {
|
||||
"parallel": id(parallel),
|
||||
|
@ -1015,7 +1015,7 @@ pub fn attributes_writeback<'ctx>(
|
||||
*field_ty,
|
||||
ctx.build_gep_and_load(
|
||||
obj.into_pointer_value(),
|
||||
&[zero, int32.const_int(index.unwrap() as u64, false)],
|
||||
&[zero, int32.const_int(index as u64, false)],
|
||||
None,
|
||||
),
|
||||
));
|
||||
@ -1056,7 +1056,7 @@ pub fn attributes_writeback<'ctx>(
|
||||
*field_ty,
|
||||
ctx.build_gep_and_load(
|
||||
obj.into_pointer_value(),
|
||||
&[zero, int32.const_int(index.unwrap() as u64, false)],
|
||||
&[zero, int32.const_int(index as u64, false)],
|
||||
None,
|
||||
),
|
||||
));
|
||||
|
@ -1,273 +0,0 @@
|
||||
use itertools::Itertools;
|
||||
|
||||
use nac3core::{toplevel::TopLevelDef, typecheck::typedef::Unifier};
|
||||
|
||||
use super::{InnerResolver, symbol_resolver::PyValueHandle};
|
||||
|
||||
impl InnerResolver {
|
||||
pub fn debug_str(&self, tld: Option<&[TopLevelDef]>, unifier: &Option<&mut Unifier>) -> String {
|
||||
fn fmt_elems(elems: &str) -> String {
|
||||
if elems.is_empty() { String::new() } else { format!("\n{elems}\n\t") }
|
||||
}
|
||||
fn stringify_pyvalue_handle(handle: &PyValueHandle) -> String {
|
||||
format!("(id: {}, value: {})", handle.0, handle.1)
|
||||
}
|
||||
fn stringify_tld(tld: &TopLevelDef) -> String {
|
||||
match tld {
|
||||
TopLevelDef::Module { name, .. } => {
|
||||
format!("TopLevelDef::Module {{ name: {name} }}")
|
||||
}
|
||||
TopLevelDef::Class { name, .. } => {
|
||||
format!("TopLevelDef::Class {{ name: {name} }}")
|
||||
}
|
||||
TopLevelDef::Function { name, .. } => {
|
||||
format!("TopLevelDef::Function {{ name: {name} }}")
|
||||
}
|
||||
TopLevelDef::Variable { name, .. } => {
|
||||
format!("TopLevelDef::Variable {{ name: {name} }}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut str = String::new();
|
||||
str.push_str("nac3artiq::InnerResolver {");
|
||||
|
||||
{
|
||||
let id_to_type = self.id_to_type.read();
|
||||
str.push_str(
|
||||
format!(
|
||||
"\n\tid_to_type: {{{}}},",
|
||||
fmt_elems(
|
||||
id_to_type
|
||||
.iter()
|
||||
.sorted_by_cached_key(|(k, _)| k.to_string())
|
||||
.map(|(k, v)| {
|
||||
let ty_str = unifier.as_ref().map_or_else(
|
||||
|| format!("{v:?}"),
|
||||
|unifier| unifier.stringify(*v),
|
||||
);
|
||||
format!("\t\t{k} -> {ty_str}")
|
||||
})
|
||||
.join(",\n")
|
||||
.as_str()
|
||||
),
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let id_to_def = self.id_to_def.read();
|
||||
str.push_str(
|
||||
format!(
|
||||
"\n\tid_to_def: {{{}}},",
|
||||
fmt_elems(
|
||||
id_to_def
|
||||
.iter()
|
||||
.sorted_by_cached_key(|(k, _)| k.to_string())
|
||||
.map(|(k, v)| {
|
||||
let tld_str = tld.map_or_else(
|
||||
|| format!("{v:?}"),
|
||||
|tlds| stringify_tld(&tlds[v.0]),
|
||||
);
|
||||
format!("\t\t{k} -> {tld_str}")
|
||||
})
|
||||
.join(",\n")
|
||||
.as_str()
|
||||
)
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let id_to_pyval = self.id_to_pyval.read();
|
||||
str.push_str(
|
||||
format!(
|
||||
"\n\tid_to_pyval: {{{}}},",
|
||||
fmt_elems(
|
||||
id_to_pyval
|
||||
.iter()
|
||||
.sorted_by_cached_key(|(k, _)| k.to_string())
|
||||
.map(|(k, v)| { format!("\t\t{k} -> {}", stringify_pyvalue_handle(v)) })
|
||||
.join(",\n")
|
||||
.as_str()
|
||||
)
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let id_to_primitive = self.id_to_primitive.read();
|
||||
str.push_str(
|
||||
format!(
|
||||
"\n\tid_to_primitive: {{{}}},",
|
||||
fmt_elems(
|
||||
id_to_primitive
|
||||
.iter()
|
||||
.sorted_by_key(|(k, _)| *k)
|
||||
.map(|(k, v)| { format!("\t\t{k} -> {v:?}") })
|
||||
.join(",\n")
|
||||
.as_str()
|
||||
)
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let field_to_val = self.field_to_val.read();
|
||||
str.push_str(
|
||||
format!(
|
||||
"\n\tfield_to_val: {{{}}},",
|
||||
fmt_elems(
|
||||
field_to_val
|
||||
.iter()
|
||||
.sorted_by_key(|((id, _), _)| *id)
|
||||
.map(|((id, name), pyval)| {
|
||||
format!(
|
||||
"\t\t({id}, {name}) -> {}",
|
||||
pyval.as_ref().map_or_else(
|
||||
|| String::from("None"),
|
||||
|pyval| format!(
|
||||
"Some({})",
|
||||
stringify_pyvalue_handle(pyval)
|
||||
)
|
||||
)
|
||||
)
|
||||
})
|
||||
.join(",\n")
|
||||
.as_str()
|
||||
)
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let global_value_ids = self.global_value_ids.read();
|
||||
str.push_str(
|
||||
format!(
|
||||
"\n\tglobal_value_ids: {{{}}},",
|
||||
fmt_elems(
|
||||
global_value_ids
|
||||
.iter()
|
||||
.sorted_by_key(|(k, _)| *k)
|
||||
.map(|(k, v)| format!("\t\t{k} -> {v}"))
|
||||
.join(",\n")
|
||||
.as_str()
|
||||
)
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let pyid_to_def = self.pyid_to_def.read();
|
||||
str.push_str(
|
||||
format!(
|
||||
"\n\tpyid_to_def: {{{}}},",
|
||||
fmt_elems(
|
||||
pyid_to_def
|
||||
.iter()
|
||||
.sorted_by_key(|(k, _)| *k)
|
||||
.map(|(k, v)| {
|
||||
let tld_str = tld.map_or_else(
|
||||
|| format!("{v:?}"),
|
||||
|tlds| stringify_tld(&tlds[v.0]),
|
||||
);
|
||||
format!("\t\t{k} -> {tld_str}")
|
||||
})
|
||||
.join(",\n")
|
||||
.as_str()
|
||||
)
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let pyid_to_type = self.pyid_to_type.read();
|
||||
str.push_str(
|
||||
format!(
|
||||
"\n\tpyid_to_type: {{{}}},",
|
||||
fmt_elems(
|
||||
pyid_to_type
|
||||
.iter()
|
||||
.sorted_by_key(|(k, _)| *k)
|
||||
.map(|(k, v)| {
|
||||
let ty_str = unifier.as_ref().map_or_else(
|
||||
|| format!("{v:?}"),
|
||||
|unifier| unifier.stringify(*v),
|
||||
);
|
||||
format!("\t\t{k} -> {ty_str}")
|
||||
})
|
||||
.join(",\n")
|
||||
.as_str()
|
||||
)
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let string_store = self.string_store.read();
|
||||
str.push_str(
|
||||
format!(
|
||||
"\n\tstring_store: {{{}}},",
|
||||
fmt_elems(
|
||||
string_store
|
||||
.iter()
|
||||
.sorted_by_key(|(k, _)| *k)
|
||||
.map(|(k, v)| format!("\t\t{k} -> {v}"))
|
||||
.join(",\n")
|
||||
.as_str()
|
||||
)
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let exception_ids = self.exception_ids.read();
|
||||
str.push_str(
|
||||
format!(
|
||||
"\n\texception_ids: {{{}}},",
|
||||
fmt_elems(
|
||||
exception_ids
|
||||
.iter()
|
||||
.sorted_by_key(|(k, _)| *k)
|
||||
.map(|(k, v)| format!("\t\t{k} -> {v}"))
|
||||
.join(",\n")
|
||||
.as_str()
|
||||
)
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
let name_to_pyid = &self.name_to_pyid;
|
||||
str.push_str(
|
||||
format!(
|
||||
"\n\tname_to_pyid: {{{}}},",
|
||||
fmt_elems(
|
||||
name_to_pyid
|
||||
.iter()
|
||||
.sorted_by_cached_key(|(k, _)| k.to_string())
|
||||
.map(|(k, v)| format!("\t\t{k} -> {v}"))
|
||||
.join(",\n")
|
||||
.as_str()
|
||||
)
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
let module = &self.module;
|
||||
str.push_str(format!("\n\tmodule: {module}").as_str());
|
||||
|
||||
str.push_str("\n}");
|
||||
|
||||
str
|
||||
}
|
||||
}
|
@ -10,11 +10,9 @@
|
||||
)]
|
||||
|
||||
use std::{
|
||||
cell::LazyCell,
|
||||
collections::{HashMap, HashSet},
|
||||
fs,
|
||||
io::Write,
|
||||
path::Path,
|
||||
process::Command,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
@ -68,13 +66,9 @@ use symbol_resolver::{DeferredEvaluationStore, InnerResolver, PythonHelper, Reso
|
||||
use timeline::TimeFns;
|
||||
|
||||
mod codegen;
|
||||
mod debug;
|
||||
mod symbol_resolver;
|
||||
mod timeline;
|
||||
|
||||
const ENV_NAC3_EMIT_LLVM_BC: &str = "NAC3_EMIT_LLVM_BC";
|
||||
const ENV_NAC3_EMIT_LLVM_LL: &str = "NAC3_EMIT_LLVM_LL";
|
||||
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
enum Isa {
|
||||
Host,
|
||||
@ -89,7 +83,7 @@ impl Isa {
|
||||
match self {
|
||||
Isa::Host => TargetMachine::get_default_triple(),
|
||||
Isa::RiscV32G | Isa::RiscV32IMA => TargetTriple::create("riscv32-unknown-linux"),
|
||||
Isa::CortexA9 => TargetTriple::create("armv7-unknown-linux-eabihf"),
|
||||
Isa::CortexA9 => TargetTriple::create("armv7-unknown-linux-gnueabihf"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,8 +160,6 @@ pub struct PrimitivePythonId {
|
||||
virtual_id: u64,
|
||||
option: u64,
|
||||
module: u64,
|
||||
kernel: u64,
|
||||
kernel_invariant: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
@ -236,17 +228,6 @@ impl Nac3 {
|
||||
let parser_result = parse_program(&source, source_file.into())
|
||||
.map_err(|e| exceptions::PySyntaxError::new_err(format!("parse error: {e}")))?;
|
||||
|
||||
let id_fn = LazyCell::new(|| {
|
||||
Python::with_gil(|py| {
|
||||
PyModule::import(py, "builtins").unwrap().getattr("id").unwrap().unbind()
|
||||
})
|
||||
});
|
||||
let get_type_hints_fn = LazyCell::new(|| {
|
||||
Python::with_gil(|py| {
|
||||
PyModule::import(py, "typing").unwrap().getattr("get_type_hints").unwrap().unbind()
|
||||
})
|
||||
});
|
||||
|
||||
for mut stmt in parser_result {
|
||||
let include = match stmt.node {
|
||||
StmtKind::ClassDef { ref decorator_list, ref mut body, ref mut bases, .. } => {
|
||||
@ -263,6 +244,7 @@ impl Nac3 {
|
||||
// Drop unregistered (i.e. host-only) base classes.
|
||||
bases.retain(|base| {
|
||||
Python::with_gil(|py| -> PyResult<bool> {
|
||||
let id_fn = PyModule::import(py, "builtins")?.getattr("id")?;
|
||||
match &base.node {
|
||||
ExprKind::Name { id, .. } => {
|
||||
if *id == "Exception".into() {
|
||||
@ -270,8 +252,7 @@ impl Nac3 {
|
||||
} else {
|
||||
let base_obj =
|
||||
module.bind(py).getattr(id.to_string().as_str())?;
|
||||
let base_id =
|
||||
id_fn.bind(py).call1((base_obj,))?.extract()?;
|
||||
let base_id = id_fn.call1((base_obj,))?.extract()?;
|
||||
Ok(registered_class_ids.contains(&base_id))
|
||||
}
|
||||
}
|
||||
@ -304,28 +285,10 @@ impl Nac3 {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Allow global variable declaration with `Kernel` or `KernelInvariant` type annotation
|
||||
StmtKind::AnnAssign { ref target, .. } => match &target.node {
|
||||
ExprKind::Name { id, .. } => Python::with_gil(|py| {
|
||||
let py_type_hints =
|
||||
get_type_hints_fn.bind(py).call1((module.bind(py),)).unwrap();
|
||||
let py_type_hints = py_type_hints.downcast::<PyDict>().unwrap();
|
||||
let var_type_hint =
|
||||
py_type_hints.get_item(id.to_string().as_str()).unwrap().unwrap();
|
||||
let var_type = var_type_hint.getattr_opt("__origin__").unwrap();
|
||||
if let Some(var_type) = var_type {
|
||||
let var_type_id = id_fn.bind(py).call1((var_type,)).unwrap();
|
||||
let var_type_id = var_type_id.extract::<u64>().unwrap();
|
||||
|
||||
[self.primitive_ids.kernel, self.primitive_ids.kernel_invariant]
|
||||
.contains(&var_type_id)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}),
|
||||
_ => false,
|
||||
},
|
||||
// Allow global variable declaration with `Kernel` type annotation
|
||||
StmtKind::AnnAssign { ref annotation, .. } => {
|
||||
matches!(&annotation.node, ExprKind::Subscript { value, .. } if matches!(&value.node, ExprKind::Name {id, ..} if id == &"Kernel".into()))
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
@ -605,10 +568,7 @@ impl Nac3 {
|
||||
py,
|
||||
(
|
||||
def_id.0.into_py_any(py)?,
|
||||
module
|
||||
.bind(py)
|
||||
.getattr(name.to_string().as_str())
|
||||
.unwrap(),
|
||||
module.getattr(py, name.to_string().as_str()).unwrap(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
@ -633,7 +593,7 @@ impl Nac3 {
|
||||
}
|
||||
StmtKind::ClassDef { name, body, .. } => {
|
||||
let class_name = name.to_string();
|
||||
let class_obj = module.bind(py).getattr(class_name.as_str()).unwrap();
|
||||
let class_obj = Arc::new(module.getattr(py, class_name.as_str()).unwrap());
|
||||
for stmt in body {
|
||||
if let StmtKind::FunctionDef { name, decorator_list, .. } = &stmt.node {
|
||||
for decorator in decorator_list {
|
||||
@ -805,7 +765,9 @@ impl Nac3 {
|
||||
py,
|
||||
(
|
||||
id.0.into_py_any(py)?,
|
||||
class_def.getattr(name.to_string().as_str()).unwrap(),
|
||||
class_def
|
||||
.getattr(py, name.to_string().as_str())
|
||||
.unwrap(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
@ -939,18 +901,6 @@ impl Nac3 {
|
||||
|
||||
embedding_map.setattr("expects_return", has_return).unwrap();
|
||||
|
||||
let emit_llvm_bc = std::env::var(ENV_NAC3_EMIT_LLVM_BC).is_ok();
|
||||
let emit_llvm_ll = std::env::var(ENV_NAC3_EMIT_LLVM_LL).is_ok();
|
||||
|
||||
let emit_llvm = |module: &Module<'_>, filename: &str| {
|
||||
if emit_llvm_bc {
|
||||
module.write_bitcode_to_path(Path::new(format!("{filename}.bc").as_str()));
|
||||
}
|
||||
if emit_llvm_ll {
|
||||
module.print_to_file(Path::new(format!("{filename}.ll").as_str())).unwrap();
|
||||
}
|
||||
};
|
||||
|
||||
// Link all modules into `main`.
|
||||
let buffers = membuffers.lock();
|
||||
let main = context
|
||||
@ -959,8 +909,6 @@ impl Nac3 {
|
||||
"main",
|
||||
))
|
||||
.unwrap();
|
||||
emit_llvm(&main, "main");
|
||||
|
||||
for buffer in buffers.iter().rev().skip(1) {
|
||||
let other = context
|
||||
.create_module_from_ir(MemoryBuffer::create_from_memory_range(buffer, "main"))
|
||||
@ -968,10 +916,7 @@ impl Nac3 {
|
||||
|
||||
main.link_in_module(other).map_err(|err| CompileError::new_err(err.to_string()))?;
|
||||
}
|
||||
emit_llvm(&main, "main.merged");
|
||||
|
||||
main.link_in_module(irrt).map_err(|err| CompileError::new_err(err.to_string()))?;
|
||||
emit_llvm(&main, "main.fat");
|
||||
|
||||
let mut function_iter = main.get_first_function();
|
||||
while let Some(func) = function_iter {
|
||||
@ -991,8 +936,6 @@ impl Nac3 {
|
||||
global_option = global.get_next_global();
|
||||
}
|
||||
|
||||
emit_llvm(&main, "main.pre-opt");
|
||||
|
||||
let target_machine = self
|
||||
.llvm_options
|
||||
.target
|
||||
@ -1007,8 +950,6 @@ impl Nac3 {
|
||||
panic!("Failed to run optimization for module `main`: {}", err.to_string());
|
||||
}
|
||||
|
||||
emit_llvm(&main, "main.post-opt");
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let string_store = self.string_store.read();
|
||||
let mut string_store_vec = string_store.iter().collect::<Vec<_>>();
|
||||
@ -1192,59 +1133,42 @@ impl Nac3 {
|
||||
|
||||
let builtins_mod = PyModule::import(py, "builtins").unwrap();
|
||||
let id_fn = builtins_mod.getattr("id").unwrap();
|
||||
let numpy_mod = PyModule::import(py, "numpy").unwrap();
|
||||
let typing_mod = PyModule::import(py, "typing").unwrap();
|
||||
let types_mod = PyModule::import(py, "types").unwrap();
|
||||
|
||||
let get_id = |x: &Bound<PyAny>| id_fn.call1((x,)).and_then(|id| id.extract()).unwrap();
|
||||
let get_artiq_builtin = |mod_name: Option<&str>, name: &str| -> Bound<PyAny> {
|
||||
if let Some(mod_name) = mod_name {
|
||||
artiq_builtins
|
||||
.get_item(mod_name)
|
||||
.unwrap()
|
||||
.unwrap_or_else(|| {
|
||||
panic!("no module key '{mod_name}' present in artiq_builtins")
|
||||
})
|
||||
.downcast::<PyDict>()
|
||||
.unwrap()
|
||||
.get_item(name)
|
||||
.unwrap()
|
||||
.unwrap_or_else(|| {
|
||||
panic!("no key '{name}' present in artiq_builtins.{mod_name}")
|
||||
})
|
||||
} else {
|
||||
artiq_builtins
|
||||
.get_item(name)
|
||||
.unwrap()
|
||||
.unwrap_or_else(|| panic!("no key '{name}' present in artiq_builtins"))
|
||||
}
|
||||
let get_attr_id = |obj: &Bound<PyModule>, attr| {
|
||||
id_fn.call1((obj.getattr(attr).unwrap(),)).unwrap().extract().unwrap()
|
||||
};
|
||||
|
||||
let primitive_ids = PrimitivePythonId {
|
||||
virtual_id: get_id(&get_artiq_builtin(Some("artiq"), "virtual")),
|
||||
virtual_id: get_id(&artiq_builtins.get_item("virtual").ok().flatten().unwrap()),
|
||||
generic_alias: (
|
||||
get_id(&get_artiq_builtin(Some("typing"), "_GenericAlias")),
|
||||
get_id(&get_artiq_builtin(Some("types"), "GenericAlias")),
|
||||
get_attr_id(&typing_mod, "_GenericAlias"),
|
||||
get_attr_id(&types_mod, "GenericAlias"),
|
||||
),
|
||||
none: get_id(&get_artiq_builtin(Some("artiq"), "none")),
|
||||
typevar: get_id(&get_artiq_builtin(Some("typing"), "TypeVar")),
|
||||
const_generic_marker: get_id(&get_artiq_builtin(Some("artiq"), "_ConstGenericMarker")),
|
||||
int: get_id(&get_artiq_builtin(None, "int")),
|
||||
int32: get_id(&get_artiq_builtin(Some("numpy"), "int32")),
|
||||
int64: get_id(&get_artiq_builtin(Some("numpy"), "int64")),
|
||||
uint32: get_id(&get_artiq_builtin(Some("numpy"), "uint32")),
|
||||
uint64: get_id(&get_artiq_builtin(Some("numpy"), "uint64")),
|
||||
bool: get_id(&get_artiq_builtin(None, "bool")),
|
||||
np_bool_: get_id(&get_artiq_builtin(Some("numpy"), "bool_")),
|
||||
string: get_id(&get_artiq_builtin(None, "str")),
|
||||
np_str_: get_id(&get_artiq_builtin(Some("numpy"), "str_")),
|
||||
float: get_id(&get_artiq_builtin(None, "float")),
|
||||
float64: get_id(&get_artiq_builtin(Some("numpy"), "float64")),
|
||||
list: get_id(&get_artiq_builtin(None, "list")),
|
||||
ndarray: get_id(&get_artiq_builtin(Some("numpy"), "ndarray")),
|
||||
tuple: get_id(&get_artiq_builtin(None, "tuple")),
|
||||
exception: get_id(&get_artiq_builtin(None, "Exception")),
|
||||
option: get_id(&get_artiq_builtin(Some("artiq"), "Option")),
|
||||
module: get_id(&get_artiq_builtin(Some("types"), "ModuleType")),
|
||||
kernel: get_id(&get_artiq_builtin(Some("artiq"), "Kernel")),
|
||||
kernel_invariant: get_id(&get_artiq_builtin(Some("artiq"), "KernelInvariant")),
|
||||
none: get_id(&artiq_builtins.get_item("none").ok().flatten().unwrap()),
|
||||
typevar: get_attr_id(&typing_mod, "TypeVar"),
|
||||
const_generic_marker: get_id(
|
||||
&artiq_builtins.get_item("_ConstGenericMarker").ok().flatten().unwrap(),
|
||||
),
|
||||
int: get_attr_id(&builtins_mod, "int"),
|
||||
int32: get_attr_id(&numpy_mod, "int32"),
|
||||
int64: get_attr_id(&numpy_mod, "int64"),
|
||||
uint32: get_attr_id(&numpy_mod, "uint32"),
|
||||
uint64: get_attr_id(&numpy_mod, "uint64"),
|
||||
bool: get_attr_id(&builtins_mod, "bool"),
|
||||
np_bool_: get_attr_id(&numpy_mod, "bool_"),
|
||||
string: get_attr_id(&builtins_mod, "str"),
|
||||
np_str_: get_attr_id(&numpy_mod, "str_"),
|
||||
float: get_attr_id(&builtins_mod, "float"),
|
||||
float64: get_attr_id(&numpy_mod, "float64"),
|
||||
list: get_attr_id(&builtins_mod, "list"),
|
||||
ndarray: get_attr_id(&numpy_mod, "ndarray"),
|
||||
tuple: get_attr_id(&builtins_mod, "tuple"),
|
||||
exception: get_attr_id(&builtins_mod, "Exception"),
|
||||
option: get_id(&artiq_builtins.get_item("Option").ok().flatten().unwrap()),
|
||||
module: get_attr_id(&types_mod, "ModuleType"),
|
||||
};
|
||||
|
||||
let working_directory = tempfile::Builder::new().prefix("nac3-").tempdir().unwrap();
|
||||
@ -1390,8 +1314,9 @@ impl Nac3 {
|
||||
py: Python<'py>,
|
||||
) -> PyResult<()> {
|
||||
let target_machine = self.get_llvm_target_machine();
|
||||
let link_fn = |module: &Module| {
|
||||
if self.isa == Isa::Host {
|
||||
|
||||
if self.isa == Isa::Host {
|
||||
let link_fn = |module: &Module| {
|
||||
let working_directory = self.working_directory.path().to_owned();
|
||||
target_machine
|
||||
.write_to_file(module, FileType::Object, &working_directory.join("module.o"))
|
||||
@ -1401,7 +1326,11 @@ impl Nac3 {
|
||||
working_directory.join("module.o").to_string_lossy().to_string(),
|
||||
)?;
|
||||
Ok(())
|
||||
} else {
|
||||
};
|
||||
|
||||
self.compile_method(obj, method_name, args, embedding_map, py, &link_fn)
|
||||
} else {
|
||||
let link_fn = |module: &Module| {
|
||||
let object_mem = target_machine
|
||||
.write_to_memory_buffer(module, FileType::Object)
|
||||
.expect("couldn't write module to object file buffer");
|
||||
@ -1415,10 +1344,10 @@ impl Nac3 {
|
||||
} else {
|
||||
Err(CompileError::new_err("linker failed to process object file"))
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
self.compile_method(obj, method_name, args, embedding_map, py, &link_fn)
|
||||
self.compile_method(obj, method_name, args, embedding_map, py, &link_fn)
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_method_to_mem<'py>(
|
||||
@ -1430,8 +1359,9 @@ impl Nac3 {
|
||||
py: Python<'py>,
|
||||
) -> PyResult<PyObject> {
|
||||
let target_machine = self.get_llvm_target_machine();
|
||||
let link_fn = |module: &Module| {
|
||||
if self.isa == Isa::Host {
|
||||
|
||||
if self.isa == Isa::Host {
|
||||
let link_fn = |module: &Module| {
|
||||
let working_directory = self.working_directory.path().to_owned();
|
||||
target_machine
|
||||
.write_to_file(module, FileType::Object, &working_directory.join("module.o"))
|
||||
@ -1445,7 +1375,11 @@ impl Nac3 {
|
||||
)?;
|
||||
|
||||
Ok(PyBytes::new(py, &fs::read(filename).unwrap()).into())
|
||||
} else {
|
||||
};
|
||||
|
||||
self.compile_method(obj, method_name, args, embedding_map, py, &link_fn)
|
||||
} else {
|
||||
let link_fn = |module: &Module| {
|
||||
let object_mem = target_machine
|
||||
.write_to_memory_buffer(module, FileType::Object)
|
||||
.expect("couldn't write module to object file buffer");
|
||||
@ -1454,10 +1388,10 @@ impl Nac3 {
|
||||
} else {
|
||||
Err(CompileError::new_err("linker failed to process object file"))
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
self.compile_method(obj, method_name, args, embedding_map, py, &link_fn)
|
||||
self.compile_method(obj, method_name, args, embedding_map, py, &link_fn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fmt::Debug,
|
||||
sync::{
|
||||
Arc,
|
||||
atomic::{AtomicBool, Ordering::Relaxed},
|
||||
@ -42,7 +41,6 @@ use nac3core::{
|
||||
|
||||
use super::PrimitivePythonId;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PrimitiveValue {
|
||||
I32(i32),
|
||||
I64(i64),
|
||||
@ -75,10 +73,10 @@ impl DeferredEvaluationStore {
|
||||
|
||||
/// A class field as stored in the [`InnerResolver`], represented by the ID and name of the
|
||||
/// associated [`PythonValue`].
|
||||
pub(crate) type ResolverField = (u64, StrRef);
|
||||
type ResolverField = (u64, StrRef);
|
||||
|
||||
/// A value as stored in Python, represented by the `id()` and [`PyObject`] of the value.
|
||||
pub(crate) type PyValueHandle = (u64, Arc<PyObject>);
|
||||
type PyValueHandle = (u64, Arc<PyObject>);
|
||||
|
||||
pub struct InnerResolver {
|
||||
pub id_to_type: RwLock<HashMap<StrRef, Type>>,
|
||||
@ -99,13 +97,6 @@ pub struct InnerResolver {
|
||||
pub module: Arc<PyObject>,
|
||||
}
|
||||
|
||||
impl Debug for InnerResolver {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.debug_str(None, &None))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Resolver(pub Arc<InnerResolver>);
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -206,65 +197,36 @@ impl StaticValue for PythonValue {
|
||||
.unwrap_or_else(|| {
|
||||
Python::with_gil(|py| -> PyResult<Option<PyValueHandle>> {
|
||||
let helper = &self.resolver.helper;
|
||||
let id = helper.id_fn.bind(py).call1((&*self.value,))?.extract::<u64>()?;
|
||||
let ty = helper.type_fn.bind(py).call1((&*self.value,))?;
|
||||
let ty_id: u64 = helper.id_fn.bind(py).call1((ty,))?.extract()?;
|
||||
|
||||
// for optimizing unwrap KernelInvariant
|
||||
if ty_id == self.resolver.primitive_ids.option && name == "_nac3_option".into() {
|
||||
let obj = self.value.bind(py).getattr(name.to_string().as_str())?;
|
||||
let id = self.resolver.helper.id_fn.bind(py).call1((&obj,))?.extract()?;
|
||||
let obj = Arc::new(obj.into_py_any(py)?);
|
||||
let obj = Arc::new(self.value.getattr(py, name.to_string().as_str())?);
|
||||
let id = self.resolver.helper.id_fn.bind(py).call1((&*obj,))?.extract()?;
|
||||
return if self.id == self.resolver.primitive_ids.none {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some((id, obj)))
|
||||
};
|
||||
}
|
||||
|
||||
let result = if let Some(def_id) =
|
||||
self.resolver.pyid_to_def.read().get(&ty_id).copied()
|
||||
{
|
||||
let mut mutable = true;
|
||||
let defs = ctx.top_level.definitions.read();
|
||||
if let TopLevelDef::Class { fields, .. } = &*defs[def_id.0].read() {
|
||||
for (field_name, _, is_mutable) in fields {
|
||||
if field_name == &name {
|
||||
mutable = *is_mutable;
|
||||
break;
|
||||
}
|
||||
let def_id = { *self.resolver.pyid_to_def.read().get(&ty_id).unwrap() };
|
||||
let mut mutable = true;
|
||||
let defs = ctx.top_level.definitions.read();
|
||||
if let TopLevelDef::Class { fields, .. } = &*defs[def_id.0].read() {
|
||||
for (field_name, _, is_mutable) in fields {
|
||||
if field_name == &name {
|
||||
mutable = *is_mutable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if mutable {
|
||||
None
|
||||
} else {
|
||||
let obj = self.value.bind(py).getattr(name.to_string().as_str())?;
|
||||
let id = self.resolver.helper.id_fn.bind(py).call1((&obj,))?.extract()?;
|
||||
let obj = Arc::new(obj.into_py_any(py)?);
|
||||
Some((id, obj))
|
||||
}
|
||||
} else if let Some(def_id) = self.resolver.pyid_to_def.read().get(&id).copied() {
|
||||
// Check if self.value is a module
|
||||
let in_mod_ctx = ctx
|
||||
.top_level
|
||||
.definitions
|
||||
.read()
|
||||
.get(def_id.0)
|
||||
.is_some_and(|def| matches!(&*def.read(), TopLevelDef::Module { .. }));
|
||||
|
||||
if in_mod_ctx {
|
||||
let obj = self.value.bind(py).getattr(name.to_string().as_str())?;
|
||||
let id = self.resolver.helper.id_fn.bind(py).call1((&obj,))?.extract()?;
|
||||
let obj = Arc::new(obj.into_py_any(py)?);
|
||||
Some((id, obj))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
}
|
||||
let result = if mutable {
|
||||
None
|
||||
} else {
|
||||
let obj = Arc::new(self.value.getattr(py, name.to_string().as_str())?);
|
||||
let id = self.resolver.helper.id_fn.bind(py).call1((&*obj,))?.extract()?;
|
||||
Some((id, obj))
|
||||
};
|
||||
|
||||
self.resolver.field_to_val.write().insert((self.id, name), result.clone());
|
||||
Ok(result)
|
||||
})
|
||||
@ -1728,60 +1690,42 @@ impl SymbolResolver for Resolver {
|
||||
) -> Option<ValueEnum<'ctx>> {
|
||||
if let Some(def_id) = self.0.id_to_def.read().get(&id) {
|
||||
let top_levels = ctx.top_level.definitions.read();
|
||||
if let TopLevelDef::Variable { resolver, .. } = &*top_levels[def_id.0].read() {
|
||||
if matches!(&*top_levels[def_id.0].read(), TopLevelDef::Variable { .. }) {
|
||||
let module_val = &self.0.module;
|
||||
let Ok((obj, idx)) = Python::with_gil(
|
||||
|py| -> PyResult<Result<(BasicValueEnum<'ctx>, Option<usize>), String>> {
|
||||
let module_val = (**module_val).bind(py);
|
||||
let ret = Python::with_gil(|py| -> PyResult<Result<BasicValueEnum, String>> {
|
||||
let module_val = (**module_val).bind(py);
|
||||
|
||||
let ty = self.0.get_obj_type(
|
||||
py,
|
||||
module_val,
|
||||
&mut ctx.unifier,
|
||||
&top_levels,
|
||||
&ctx.primitives,
|
||||
)?;
|
||||
if let Err(ty) = ty {
|
||||
return Ok(Err(ty));
|
||||
}
|
||||
let ty = ty.unwrap();
|
||||
let obj =
|
||||
self.0.get_obj_value(py, module_val, ctx, generator, ty)?.unwrap();
|
||||
let (idx, _) = ctx.get_attr_index(ty, id);
|
||||
|
||||
Ok(Ok((obj, idx)))
|
||||
},
|
||||
)
|
||||
.unwrap() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(idx) = idx else {
|
||||
// `idx` not found in the current resolver - try the resolver of the variable
|
||||
return resolver.as_ref().and_then(|resolver| {
|
||||
let resolver = &**resolver;
|
||||
|
||||
// TODO: Can we assume that if get_identifier_def returns a result,
|
||||
// get_symbol_value will also return a value?
|
||||
resolver
|
||||
.get_identifier_def(id)
|
||||
.ok()
|
||||
.and_then(|_| resolver.get_symbol_value(id, ctx, generator))
|
||||
});
|
||||
};
|
||||
|
||||
let ret = unsafe {
|
||||
ctx.builder.build_gep(
|
||||
obj.into_pointer_value(),
|
||||
&[
|
||||
ctx.ctx.i32_type().const_zero(),
|
||||
ctx.ctx.i32_type().const_int(idx as u64, false),
|
||||
],
|
||||
id.to_string().as_str(),
|
||||
)
|
||||
}
|
||||
let ty = self.0.get_obj_type(
|
||||
py,
|
||||
module_val,
|
||||
&mut ctx.unifier,
|
||||
&top_levels,
|
||||
&ctx.primitives,
|
||||
)?;
|
||||
if let Err(ty) = ty {
|
||||
return Ok(Err(ty));
|
||||
}
|
||||
let ty = ty.unwrap();
|
||||
let obj = self.0.get_obj_value(py, module_val, ctx, generator, ty)?.unwrap();
|
||||
let (idx, _) = ctx.get_attr_index(ty, id);
|
||||
let ret = unsafe {
|
||||
ctx.builder.build_gep(
|
||||
obj.into_pointer_value(),
|
||||
&[
|
||||
ctx.ctx.i32_type().const_zero(),
|
||||
ctx.ctx.i32_type().const_int(idx as u64, false),
|
||||
],
|
||||
id.to_string().as_str(),
|
||||
)
|
||||
}
|
||||
.unwrap();
|
||||
Ok(Ok(ret.as_basic_value_enum()))
|
||||
})
|
||||
.unwrap();
|
||||
return Some(ret.as_basic_value_enum().into());
|
||||
if ret.is_err() {
|
||||
return None;
|
||||
}
|
||||
return Some(ret.unwrap().into());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ impl<'ctx> CodeGenContext<'ctx, '_> {
|
||||
|
||||
/// Checks the field and attributes of classes
|
||||
/// Returns the index of attr in class fields otherwise returns the attribute value
|
||||
pub fn get_attr_index(&mut self, ty: Type, attr: StrRef) -> (Option<usize>, Option<Constant>) {
|
||||
pub fn get_attr_index(&mut self, ty: Type, attr: StrRef) -> (usize, Option<Constant>) {
|
||||
let obj_id = match &*self.unifier.get_ty(ty) {
|
||||
TypeEnum::TObj { obj_id, .. } => *obj_id,
|
||||
TypeEnum::TModule { module_id, .. } => *module_id,
|
||||
@ -134,16 +134,13 @@ impl<'ctx> CodeGenContext<'ctx, '_> {
|
||||
let def = &self.top_level.definitions.read()[obj_id.0];
|
||||
let (index, value) = if let TopLevelDef::Class { fields, attributes, .. } = &*def.read() {
|
||||
if let Some(field_index) = fields.iter().find_position(|x| x.0 == attr) {
|
||||
(Some(field_index.0), None)
|
||||
(field_index.0, None)
|
||||
} else {
|
||||
let attribute_index = attributes.iter().find_position(|x| x.0 == attr);
|
||||
(
|
||||
attribute_index.map(|(idx, _)| idx),
|
||||
attribute_index.map(|(_, (_, _, k))| k.clone()),
|
||||
)
|
||||
let attribute_index = attributes.iter().find_position(|x| x.0 == attr).unwrap();
|
||||
(attribute_index.0, Some(attribute_index.1.2.clone()))
|
||||
}
|
||||
} else if let TopLevelDef::Module { attributes, .. } = &*def.read() {
|
||||
(attributes.iter().find_position(|x| x.0 == attr).map(|(idx, _)| idx), None)
|
||||
(attributes.iter().find_position(|x| x.0 == attr).unwrap().0, None)
|
||||
} else {
|
||||
codegen_unreachable!(self)
|
||||
};
|
||||
@ -2464,7 +2461,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
||||
let (index, _) = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
||||
Ok(ValueEnum::Dynamic(ctx.build_gep_and_load(
|
||||
v.into_pointer_value(),
|
||||
&[zero, int32.const_int(index.unwrap() as u64, false)],
|
||||
&[zero, int32.const_int(index as u64, false)],
|
||||
None,
|
||||
))) as Result<_, String>
|
||||
},
|
||||
@ -2481,7 +2478,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
||||
}
|
||||
ValueEnum::Dynamic(ctx.build_gep_and_load(
|
||||
v.into_pointer_value(),
|
||||
&[zero, int32.const_int(index.unwrap() as u64, false)],
|
||||
&[zero, int32.const_int(index as u64, false)],
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ pub fn gen_store_target<'ctx, G: CodeGenerator>(
|
||||
ptr,
|
||||
&[
|
||||
ctx.ctx.i32_type().const_zero(),
|
||||
ctx.ctx.i32_type().const_int(index.unwrap() as u64, false),
|
||||
ctx.ctx.i32_type().const_int(index as u64, false),
|
||||
],
|
||||
name.unwrap_or(""),
|
||||
)
|
||||
@ -1471,7 +1471,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
|
||||
ctx.loop_target = old_loop_target.or(ctx.loop_target);
|
||||
|
||||
let old_unwind = if finalbody.is_empty() {
|
||||
old_unwind
|
||||
None
|
||||
} else {
|
||||
let final_landingpad = ctx.ctx.append_basic_block(current_fun, "try.catch.final");
|
||||
ctx.builder.position_at_end(final_landingpad);
|
||||
|
@ -463,9 +463,9 @@ impl TopLevelComposer {
|
||||
|
||||
/// Registers a top-level variable with the given `name` into the composer.
|
||||
///
|
||||
/// - `annotation` - The type annotation of the top-level variable, or [`None`] if no type
|
||||
/// annotation is provided.
|
||||
/// - `location` - The location of the top-level variable.
|
||||
/// `annotation` - The type annotation of the top-level variable, or [`None`] if no type
|
||||
/// annotation is provided.
|
||||
/// `location` - The location of the top-level variable.
|
||||
pub fn register_top_level_var(
|
||||
&mut self,
|
||||
name: Ident,
|
||||
@ -1999,15 +1999,13 @@ impl TopLevelComposer {
|
||||
ExprKind::Subscript { value, slice, .. }
|
||||
if matches!(
|
||||
&value.node,
|
||||
ast::ExprKind::Name { id, .. } if self.core_config.kernel_ann.is_some_and(|c| id == &c.into()) || id == &self.core_config.kernel_invariant_ann.into()
|
||||
ast::ExprKind::Name { id, .. } if self.core_config.kernel_ann.is_some_and(|c| id == &c.into())
|
||||
) =>
|
||||
{
|
||||
slice
|
||||
}
|
||||
_ if self.core_config.kernel_ann.is_none() => ty_decl,
|
||||
_ => unreachable!(
|
||||
"Global variables should be annotated with Kernel[] or KernelInvariant[]"
|
||||
), // ignore fields annotated otherwise
|
||||
_ => unreachable!("Global variables should be annotated with Kernel[]"), // ignore fields annotated otherwise
|
||||
};
|
||||
|
||||
let ty_annotation = parse_ast_to_type_annotation_kinds(
|
||||
|
@ -60,182 +60,6 @@ impl TypeAnnotation {
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a [`DefinitionId`] representing a [`TopLevelDef::Class`] and its type arguments into a
|
||||
/// [`TypeAnnotation`].
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn class_def_id_to_type_annotation<T, S: std::hash::BuildHasher + Clone>(
|
||||
resolver: &(dyn SymbolResolver + Send + Sync),
|
||||
top_level_defs: &[Arc<RwLock<TopLevelDef>>],
|
||||
unifier: &mut Unifier,
|
||||
primitives: &PrimitiveStore,
|
||||
mut locked: HashMap<DefinitionId, Vec<Type>, S>,
|
||||
id: StrRef,
|
||||
(obj_id, type_args): (DefinitionId, Option<&Expr<T>>),
|
||||
location: &Location,
|
||||
) -> Result<TypeAnnotation, HashSet<String>> {
|
||||
let Some(top_level_def) = top_level_defs.get(obj_id.0) else {
|
||||
return Err(HashSet::from([format!(
|
||||
"NameError: name '{id}' is not defined (at {location})",
|
||||
)]));
|
||||
};
|
||||
|
||||
// We need to use `try_read` here, since the composer may be processing our class right now,
|
||||
// which requires exclusive access to modify the class internals.
|
||||
//
|
||||
// `locked` is guaranteed to hold a k-v pair of the composer-processing class, so fallback
|
||||
// to it if the `top_level_def` is already locked for mutation.
|
||||
let type_vars = if let Some(def_read) = top_level_def.try_read() {
|
||||
if let TopLevelDef::Class { type_vars, .. } = &*def_read {
|
||||
type_vars.clone()
|
||||
} else {
|
||||
return Err(HashSet::from([format!(
|
||||
"function cannot be used as a type (at {location})",
|
||||
)]));
|
||||
}
|
||||
} else {
|
||||
locked.get(&obj_id).unwrap().clone()
|
||||
};
|
||||
|
||||
let param_type_infos = if let Some(slice) = type_args {
|
||||
// we do not check whether the application of type variables are compatible here
|
||||
let params_ast = if let ast::ExprKind::Tuple { elts, .. } = &slice.node {
|
||||
elts.iter().collect_vec()
|
||||
} else {
|
||||
vec![slice]
|
||||
};
|
||||
|
||||
if type_vars.len() != params_ast.len() {
|
||||
return Err(HashSet::from([format!(
|
||||
"expect {} type parameters but got {} (at {})",
|
||||
type_vars.len(),
|
||||
params_ast.len(),
|
||||
params_ast[0].location,
|
||||
)]));
|
||||
}
|
||||
|
||||
let result = params_ast
|
||||
.iter()
|
||||
.map(|x| {
|
||||
parse_ast_to_type_annotation_kinds(
|
||||
resolver,
|
||||
top_level_defs,
|
||||
unifier,
|
||||
primitives,
|
||||
x,
|
||||
{
|
||||
locked.insert(obj_id, type_vars.clone());
|
||||
locked.clone()
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
// make sure the result do not contain any type vars
|
||||
let no_type_var =
|
||||
result.iter().all(|x| get_type_var_contained_in_type_annotation(x).is_empty());
|
||||
if no_type_var {
|
||||
result
|
||||
} else {
|
||||
return Err(HashSet::from([format!(
|
||||
"application of type vars to generic class is not currently supported (at {})",
|
||||
params_ast[0].location
|
||||
)]));
|
||||
}
|
||||
} else {
|
||||
// check param number here
|
||||
if !type_vars.is_empty() {
|
||||
return Err(HashSet::from([format!(
|
||||
"expect {} type variable parameter but got 0 (at {location})",
|
||||
type_vars.len(),
|
||||
)]));
|
||||
}
|
||||
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
Ok(TypeAnnotation::CustomClass { id: obj_id, params: param_type_infos })
|
||||
}
|
||||
|
||||
/// Parses the `id` of a [`ast::ExprKind::Name`] expression as a [`TypeAnnotation`].
|
||||
fn parse_name_as_type_annotation<T, S: std::hash::BuildHasher + Clone>(
|
||||
resolver: &(dyn SymbolResolver + Send + Sync),
|
||||
top_level_defs: &[Arc<RwLock<TopLevelDef>>],
|
||||
unifier: &mut Unifier,
|
||||
primitives: &PrimitiveStore,
|
||||
locked: HashMap<DefinitionId, Vec<Type>, S>,
|
||||
id: StrRef,
|
||||
location: &Location,
|
||||
) -> Result<TypeAnnotation, HashSet<String>> {
|
||||
if id == "int32".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.int32))
|
||||
} else if id == "int64".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.int64))
|
||||
} else if id == "uint32".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.uint32))
|
||||
} else if id == "uint64".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.uint64))
|
||||
} else if id == "float".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.float))
|
||||
} else if id == "bool".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.bool))
|
||||
} else if id == "str".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.str))
|
||||
} else if id == "Exception".into() {
|
||||
Ok(TypeAnnotation::CustomClass { id: PrimDef::Exception.id(), params: Vec::default() })
|
||||
} else if let Ok(obj_id) = resolver.get_identifier_def(id) {
|
||||
class_def_id_to_type_annotation(
|
||||
resolver,
|
||||
top_level_defs,
|
||||
unifier,
|
||||
primitives,
|
||||
locked,
|
||||
id,
|
||||
(obj_id, None as Option<&Expr<T>>),
|
||||
location,
|
||||
)
|
||||
} else if let Ok(ty) = resolver.get_symbol_type(unifier, top_level_defs, primitives, id) {
|
||||
if let TypeEnum::TVar { .. } = unifier.get_ty(ty).as_ref() {
|
||||
let var = unifier.get_fresh_var(Some(id), Some(*location)).ty;
|
||||
unifier.unify(var, ty).unwrap();
|
||||
Ok(TypeAnnotation::TypeVar(ty))
|
||||
} else {
|
||||
Err(HashSet::from([format!("`{id}` is not a valid type annotation (at {location})",)]))
|
||||
}
|
||||
} else {
|
||||
Err(HashSet::from([format!("`{id}` is not a valid type annotation (at {location})",)]))
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses the `id` and generic arguments of a class as a [`TypeAnnotation`].
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn parse_class_id_as_type_annotation<T, S: std::hash::BuildHasher + Clone>(
|
||||
resolver: &(dyn SymbolResolver + Send + Sync),
|
||||
top_level_defs: &[Arc<RwLock<TopLevelDef>>],
|
||||
unifier: &mut Unifier,
|
||||
primitives: &PrimitiveStore,
|
||||
locked: HashMap<DefinitionId, Vec<Type>, S>,
|
||||
id: StrRef,
|
||||
slice: &Expr<T>,
|
||||
location: &Location,
|
||||
) -> Result<TypeAnnotation, HashSet<String>> {
|
||||
if ["virtual".into(), "Generic".into(), "tuple".into(), "Option".into()].contains(&id) {
|
||||
return Err(HashSet::from([format!("keywords cannot be class name (at {location})")]));
|
||||
}
|
||||
|
||||
let obj_id = resolver.get_identifier_def(id)?;
|
||||
|
||||
class_def_id_to_type_annotation(
|
||||
resolver,
|
||||
top_level_defs,
|
||||
unifier,
|
||||
primitives,
|
||||
locked,
|
||||
id,
|
||||
(obj_id, Some(slice)),
|
||||
location,
|
||||
)
|
||||
}
|
||||
|
||||
/// Parses an AST expression `expr` into a [`TypeAnnotation`].
|
||||
///
|
||||
/// * `locked` - A [`HashMap`] containing the IDs of known definitions, mapped to a [`Vec`] of all
|
||||
@ -251,17 +75,152 @@ pub fn parse_ast_to_type_annotation_kinds<T, S: std::hash::BuildHasher + Clone>(
|
||||
// the key stores the type_var of this topleveldef::class, we only need this field here
|
||||
locked: HashMap<DefinitionId, Vec<Type>, S>,
|
||||
) -> Result<TypeAnnotation, HashSet<String>> {
|
||||
match &expr.node {
|
||||
ast::ExprKind::Name { id, .. } => parse_name_as_type_annotation::<T, S>(
|
||||
resolver,
|
||||
top_level_defs,
|
||||
unifier,
|
||||
primitives,
|
||||
locked,
|
||||
*id,
|
||||
&expr.location,
|
||||
),
|
||||
let name_handle = |id: &StrRef,
|
||||
unifier: &mut Unifier,
|
||||
locked: HashMap<DefinitionId, Vec<Type>, S>| {
|
||||
if id == &"int32".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.int32))
|
||||
} else if id == &"int64".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.int64))
|
||||
} else if id == &"uint32".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.uint32))
|
||||
} else if id == &"uint64".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.uint64))
|
||||
} else if id == &"float".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.float))
|
||||
} else if id == &"bool".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.bool))
|
||||
} else if id == &"str".into() {
|
||||
Ok(TypeAnnotation::Primitive(primitives.str))
|
||||
} else if id == &"Exception".into() {
|
||||
Ok(TypeAnnotation::CustomClass { id: PrimDef::Exception.id(), params: Vec::default() })
|
||||
} else if let Ok(obj_id) = resolver.get_identifier_def(*id) {
|
||||
let type_vars = {
|
||||
let Some(top_level_def) = top_level_defs.get(obj_id.0) else {
|
||||
return Err(HashSet::from([format!(
|
||||
"NameError: name '{id}' is not defined (at {})",
|
||||
expr.location
|
||||
)]));
|
||||
};
|
||||
let def_read = top_level_def.try_read();
|
||||
if let Some(def_read) = def_read {
|
||||
if let TopLevelDef::Class { type_vars, .. } = &*def_read {
|
||||
type_vars.clone()
|
||||
} else {
|
||||
return Err(HashSet::from([format!(
|
||||
"function cannot be used as a type (at {})",
|
||||
expr.location
|
||||
)]));
|
||||
}
|
||||
} else {
|
||||
locked.get(&obj_id).unwrap().clone()
|
||||
}
|
||||
};
|
||||
// check param number here
|
||||
if !type_vars.is_empty() {
|
||||
return Err(HashSet::from([format!(
|
||||
"expect {} type variable parameter but got 0 (at {})",
|
||||
type_vars.len(),
|
||||
expr.location,
|
||||
)]));
|
||||
}
|
||||
Ok(TypeAnnotation::CustomClass { id: obj_id, params: vec![] })
|
||||
} else if let Ok(ty) = resolver.get_symbol_type(unifier, top_level_defs, primitives, *id) {
|
||||
if let TypeEnum::TVar { .. } = unifier.get_ty(ty).as_ref() {
|
||||
let var = unifier.get_fresh_var(Some(*id), Some(expr.location)).ty;
|
||||
unifier.unify(var, ty).unwrap();
|
||||
Ok(TypeAnnotation::TypeVar(ty))
|
||||
} else {
|
||||
Err(HashSet::from([format!(
|
||||
"`{}` is not a valid type annotation (at {})",
|
||||
id, expr.location
|
||||
)]))
|
||||
}
|
||||
} else {
|
||||
Err(HashSet::from([format!(
|
||||
"`{}` is not a valid type annotation (at {})",
|
||||
id, expr.location
|
||||
)]))
|
||||
}
|
||||
};
|
||||
|
||||
let class_name_handle =
|
||||
|id: &StrRef,
|
||||
slice: &ast::Expr<T>,
|
||||
unifier: &mut Unifier,
|
||||
mut locked: HashMap<DefinitionId, Vec<Type>, S>| {
|
||||
if ["virtual".into(), "Generic".into(), "tuple".into(), "Option".into()].contains(id) {
|
||||
return Err(HashSet::from([format!(
|
||||
"keywords cannot be class name (at {})",
|
||||
expr.location
|
||||
)]));
|
||||
}
|
||||
let obj_id = resolver.get_identifier_def(*id)?;
|
||||
let type_vars = {
|
||||
let Some(top_level_def) = top_level_defs.get(obj_id.0) else {
|
||||
return Err(HashSet::from([format!(
|
||||
"NameError: name '{id}' is not defined (at {})",
|
||||
expr.location
|
||||
)]));
|
||||
};
|
||||
let def_read = top_level_def.try_read();
|
||||
if let Some(def_read) = def_read {
|
||||
let TopLevelDef::Class { type_vars, .. } = &*def_read else {
|
||||
unreachable!("must be class here")
|
||||
};
|
||||
type_vars.clone()
|
||||
} else {
|
||||
locked.get(&obj_id).unwrap().clone()
|
||||
}
|
||||
};
|
||||
// we do not check whether the application of type variables are compatible here
|
||||
let param_type_infos = {
|
||||
let params_ast = if let ast::ExprKind::Tuple { elts, .. } = &slice.node {
|
||||
elts.iter().collect_vec()
|
||||
} else {
|
||||
vec![slice]
|
||||
};
|
||||
if type_vars.len() != params_ast.len() {
|
||||
return Err(HashSet::from([format!(
|
||||
"expect {} type parameters but got {} (at {})",
|
||||
type_vars.len(),
|
||||
params_ast.len(),
|
||||
params_ast[0].location,
|
||||
)]));
|
||||
}
|
||||
let result = params_ast
|
||||
.iter()
|
||||
.map(|x| {
|
||||
parse_ast_to_type_annotation_kinds(
|
||||
resolver,
|
||||
top_level_defs,
|
||||
unifier,
|
||||
primitives,
|
||||
x,
|
||||
{
|
||||
locked.insert(obj_id, type_vars.clone());
|
||||
locked.clone()
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
// make sure the result do not contain any type vars
|
||||
let no_type_var =
|
||||
result.iter().all(|x| get_type_var_contained_in_type_annotation(x).is_empty());
|
||||
if no_type_var {
|
||||
result
|
||||
} else {
|
||||
return Err(HashSet::from([format!(
|
||||
"application of type vars to generic class is not currently supported (at {})",
|
||||
params_ast[0].location
|
||||
)]));
|
||||
}
|
||||
};
|
||||
Ok(TypeAnnotation::CustomClass { id: obj_id, params: param_type_infos })
|
||||
};
|
||||
|
||||
match &expr.node {
|
||||
ast::ExprKind::Name { id, .. } => name_handle(id, unifier, locked),
|
||||
// virtual
|
||||
ast::ExprKind::Subscript { value, slice, .. }
|
||||
if {
|
||||
@ -382,105 +341,9 @@ pub fn parse_ast_to_type_annotation_kinds<T, S: std::hash::BuildHasher + Clone>(
|
||||
|
||||
// custom class
|
||||
ast::ExprKind::Subscript { value, slice, .. } => {
|
||||
match &value.node {
|
||||
ast::ExprKind::Name { id, .. } => parse_class_id_as_type_annotation(
|
||||
resolver,
|
||||
top_level_defs,
|
||||
unifier,
|
||||
primitives,
|
||||
locked,
|
||||
*id,
|
||||
slice,
|
||||
&expr.location,
|
||||
),
|
||||
|
||||
ast::ExprKind::Attribute { value, attr, .. } => {
|
||||
if let ast::ExprKind::Name { id, .. } = &value.node {
|
||||
let mod_id = resolver.get_identifier_def(*id)?;
|
||||
let Some(mod_tld) = top_level_defs.get(mod_id.0) else {
|
||||
return Err(HashSet::from([format!(
|
||||
"NameError: name '{id}' is not defined (at {})",
|
||||
expr.location
|
||||
)]));
|
||||
};
|
||||
|
||||
let matching_attr =
|
||||
if let TopLevelDef::Module { methods, .. } = &*mod_tld.read() {
|
||||
methods.get(attr).copied()
|
||||
} else {
|
||||
unreachable!("must be module here")
|
||||
};
|
||||
|
||||
let Some(def_id) = matching_attr else {
|
||||
return Err(HashSet::from([format!(
|
||||
"AttributeError: module '{id}' has no attribute '{attr}' (at {})",
|
||||
expr.location
|
||||
)]));
|
||||
};
|
||||
|
||||
class_def_id_to_type_annotation::<T, S>(
|
||||
resolver,
|
||||
top_level_defs,
|
||||
unifier,
|
||||
primitives,
|
||||
locked,
|
||||
*attr,
|
||||
(def_id, Some(slice)),
|
||||
&expr.location,
|
||||
)
|
||||
} else {
|
||||
// TODO: Handle multiple indirection
|
||||
Err(HashSet::from([format!(
|
||||
"unsupported expression type for class name (at {})",
|
||||
value.location
|
||||
)]))
|
||||
}
|
||||
}
|
||||
|
||||
_ => Err(HashSet::from([format!(
|
||||
"unsupported expression type for class name (at {})",
|
||||
value.location
|
||||
)])),
|
||||
}
|
||||
}
|
||||
|
||||
ast::ExprKind::Constant { value, .. } => Ok(TypeAnnotation::Literal(vec![value.clone()])),
|
||||
|
||||
ast::ExprKind::Attribute { value, attr, .. } => {
|
||||
if let ast::ExprKind::Name { id, .. } = &value.node {
|
||||
let mod_id = resolver.get_identifier_def(*id)?;
|
||||
let Some(mod_tld) = top_level_defs.get(mod_id.0) else {
|
||||
return Err(HashSet::from([format!(
|
||||
"NameError: name '{id}' is not defined (at {})",
|
||||
expr.location
|
||||
)]));
|
||||
};
|
||||
|
||||
let matching_attr = if let TopLevelDef::Module { methods, .. } = &*mod_tld.read() {
|
||||
methods.get(attr).copied()
|
||||
} else {
|
||||
unreachable!("must be module here")
|
||||
};
|
||||
|
||||
let Some(def_id) = matching_attr else {
|
||||
return Err(HashSet::from([format!(
|
||||
"AttributeError: module '{id}' has no attribute '{attr}' (at {})",
|
||||
expr.location
|
||||
)]));
|
||||
};
|
||||
|
||||
class_def_id_to_type_annotation::<T, S>(
|
||||
resolver,
|
||||
top_level_defs,
|
||||
unifier,
|
||||
primitives,
|
||||
locked,
|
||||
*attr,
|
||||
(def_id, None),
|
||||
&expr.location,
|
||||
)
|
||||
class_name_handle(id, slice, unifier, locked)
|
||||
} else {
|
||||
// TODO: Handle multiple indirection
|
||||
Err(HashSet::from([format!(
|
||||
"unsupported expression type for class name (at {})",
|
||||
value.location
|
||||
@ -488,6 +351,8 @@ pub fn parse_ast_to_type_annotation_kinds<T, S: std::hash::BuildHasher + Clone>(
|
||||
}
|
||||
}
|
||||
|
||||
ast::ExprKind::Constant { value, .. } => Ok(TypeAnnotation::Literal(vec![value.clone()])),
|
||||
|
||||
_ => Err(HashSet::from([format!(
|
||||
"unsupported expression for type annotation (at {})",
|
||||
expr.location
|
||||
|
@ -19,12 +19,8 @@ use nac3core::{
|
||||
WithCall, WorkerRegistry, concrete_type::ConcreteTypeStore, irrt::load_irrt,
|
||||
},
|
||||
inkwell::{
|
||||
OptimizationLevel,
|
||||
memory_buffer::MemoryBuffer,
|
||||
module::{Linkage, Module},
|
||||
passes::PassBuilderOptions,
|
||||
support::is_multithreaded,
|
||||
targets::*,
|
||||
OptimizationLevel, memory_buffer::MemoryBuffer, module::Linkage,
|
||||
passes::PassBuilderOptions, support::is_multithreaded, targets::*,
|
||||
},
|
||||
nac3parser::{
|
||||
ast::{Constant, Expr, ExprKind, StmtKind, StrRef},
|
||||
@ -63,13 +59,11 @@ struct CommandLineArgs {
|
||||
#[arg(short = 'O', default_value_t = 2, value_parser = clap::value_parser!(u32).range(0..=3))]
|
||||
opt_level: u32,
|
||||
|
||||
/// Whether to emit LLVM bitcode at the end of every module.
|
||||
/// Whether to emit LLVM IR at the end of every module.
|
||||
///
|
||||
/// If multithreaded compilation is also enabled, each thread will emit its own module.
|
||||
#[arg(long, default_value_t = false)]
|
||||
emit_llvm_bc: bool,
|
||||
|
||||
/// Whether to emit LLVM IR text at the end of every module.
|
||||
#[arg(long, default_value_t = false)]
|
||||
emit_llvm_ir: bool,
|
||||
emit_llvm: bool,
|
||||
|
||||
/// The target triple to compile for.
|
||||
#[arg(long)]
|
||||
@ -282,16 +276,8 @@ fn handle_global_var(
|
||||
|
||||
fn main() {
|
||||
let cli = CommandLineArgs::parse();
|
||||
let CommandLineArgs {
|
||||
file_name,
|
||||
threads,
|
||||
opt_level,
|
||||
emit_llvm_bc,
|
||||
emit_llvm_ir,
|
||||
triple,
|
||||
mcpu,
|
||||
target_features,
|
||||
} = cli;
|
||||
let CommandLineArgs { file_name, threads, opt_level, emit_llvm, triple, mcpu, target_features } =
|
||||
cli;
|
||||
|
||||
Target::initialize_all(&InitializationConfig::default());
|
||||
|
||||
@ -360,18 +346,11 @@ fn main() {
|
||||
let resolver =
|
||||
Arc::new(Resolver(internal_resolver.clone())) as Arc<dyn SymbolResolver + Send + Sync>;
|
||||
|
||||
let emit_llvm = |module: &Module<'_>, filename: &str| {
|
||||
if emit_llvm_bc {
|
||||
module.write_bitcode_to_path(Path::new(format!("{filename}.bc").as_str()));
|
||||
}
|
||||
if emit_llvm_ir {
|
||||
module.print_to_file(Path::new(format!("{filename}.ll").as_str())).unwrap();
|
||||
}
|
||||
};
|
||||
|
||||
// Process IRRT
|
||||
let irrt = load_irrt(&context, resolver.as_ref());
|
||||
emit_llvm(&irrt, "irrt");
|
||||
if emit_llvm {
|
||||
irrt.write_bitcode_to_path(Path::new("irrt.bc"));
|
||||
}
|
||||
|
||||
// Process the Python script
|
||||
let parser_result = parser::parse_program(&program, file_name.into()).unwrap();
|
||||
@ -496,19 +475,23 @@ fn main() {
|
||||
let main = context
|
||||
.create_module_from_ir(MemoryBuffer::create_from_memory_range(&buffers[0], "main"))
|
||||
.unwrap();
|
||||
emit_llvm(&main, "main");
|
||||
if emit_llvm {
|
||||
main.write_bitcode_to_path(Path::new("main.bc"));
|
||||
}
|
||||
|
||||
for buffer in buffers.iter().skip(1) {
|
||||
for (idx, buffer) in buffers.iter().skip(1).enumerate() {
|
||||
let other = context
|
||||
.create_module_from_ir(MemoryBuffer::create_from_memory_range(buffer, "main"))
|
||||
.unwrap();
|
||||
|
||||
if emit_llvm {
|
||||
other.write_bitcode_to_path(Path::new(&format!("module{idx}.bc")));
|
||||
}
|
||||
|
||||
main.link_in_module(other).unwrap();
|
||||
}
|
||||
emit_llvm(&main, "main.merged");
|
||||
|
||||
main.link_in_module(irrt).unwrap();
|
||||
emit_llvm(&main, "main.fat");
|
||||
|
||||
// Private all functions except "run"
|
||||
let mut function_iter = main.get_first_function();
|
||||
@ -519,8 +502,6 @@ fn main() {
|
||||
function_iter = func.get_next_function();
|
||||
}
|
||||
|
||||
emit_llvm(&main, "main.pre-opt");
|
||||
|
||||
// Optimize `main`
|
||||
let pass_options = PassBuilderOptions::create();
|
||||
pass_options.set_merge_functions(true);
|
||||
@ -530,8 +511,6 @@ fn main() {
|
||||
panic!("Failed to run optimization for module `main`: {}", err.to_string());
|
||||
}
|
||||
|
||||
emit_llvm(&main, "main.post-opt");
|
||||
|
||||
// Write output
|
||||
target_machine
|
||||
.write_to_file(&main, FileType::Object, Path::new("module.o"))
|
||||
|
Loading…
x
Reference in New Issue
Block a user