forked from M-Labs/nac3
Compare commits
17 Commits
4069852503
...
d5fa3fafa1
Author | SHA1 | Date | |
---|---|---|---|
d5fa3fafa1 | |||
69320a6cf1 | |||
9e0601837a | |||
432c81a500 | |||
6beff7a268 | |||
6ca7aecd4a | |||
8fd7216243 | |||
4f5e417012 | |||
a0614bad83 | |||
5539d144ed | |||
b3891b9a0d | |||
6fb8939179 | |||
973dc5041a | |||
d0da688aa7 | |||
12c4e1cf48 | |||
9b988647ed | |||
35a7cecc12 |
52
Cargo.lock
generated
52
Cargo.lock
generated
@ -117,9 +117,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.1.7"
|
version = "1.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc"
|
checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
@ -129,9 +129,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.13"
|
version = "4.5.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc"
|
checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@ -139,9 +139,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.13"
|
version = "4.5.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99"
|
checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@ -158,7 +158,7 @@ dependencies = [
|
|||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.74",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -421,7 +421,7 @@ checksum = "4fa4d8d74483041a882adaa9a29f633253a66dde85055f0495c121620ac484b2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.74",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -749,7 +749,7 @@ dependencies = [
|
|||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.2",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.74",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -853,7 +853,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-macros-backend",
|
"pyo3-macros-backend",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.74",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -866,7 +866,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-build-config",
|
"pyo3-build-config",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.74",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1032,29 +1032,29 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.204"
|
version = "1.0.206"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
checksum = "5b3e4cd94123dd520a128bcd11e34d9e9e423e7e3e50425cb1b4b1e3549d0284"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.204"
|
version = "1.0.206"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
checksum = "fabfb6138d2383ea8208cf98ccf69cdfb1aff4088460681d84189aa259762f97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.74",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.122"
|
version = "1.0.124"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
|
checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -1138,7 +1138,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"syn 2.0.72",
|
"syn 2.0.74",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1154,9 +1154,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.72"
|
version = "2.0.74"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
|
checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1171,15 +1171,15 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.11.0"
|
version = "3.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
|
checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1223,7 +1223,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.74",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1501,5 +1501,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.74",
|
||||||
]
|
]
|
||||||
|
@ -180,7 +180,9 @@
|
|||||||
clippy
|
clippy
|
||||||
pre-commit
|
pre-commit
|
||||||
rustfmt
|
rustfmt
|
||||||
|
rust-analyzer
|
||||||
];
|
];
|
||||||
|
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
|
||||||
shellHook =
|
shellHook =
|
||||||
''
|
''
|
||||||
export DEMO_LINALG_STUB=${packages.x86_64-linux.demo-linalg-stub}/lib/liblinalg.a
|
export DEMO_LINALG_STUB=${packages.x86_64-linux.demo-linalg-stub}/lib/liblinalg.a
|
||||||
|
@ -24,3 +24,4 @@ features = ["llvm14-0", "target-x86", "target-arm", "target-riscv", "no-libffi-l
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
init-llvm-profile = []
|
init-llvm-profile = []
|
||||||
|
no-escape-analysis = ["nac3core/no-escape-analysis"]
|
||||||
|
26
nac3artiq/demo/str_abi.py
Normal file
26
nac3artiq/demo/str_abi.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
from min_artiq import *
|
||||||
|
from numpy import ndarray, zeros as np_zeros
|
||||||
|
|
||||||
|
|
||||||
|
@nac3
|
||||||
|
class StrFail:
|
||||||
|
core: KernelInvariant[Core]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.core = Core()
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def hello(self, arg: str):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def consume_ndarray(self, arg: ndarray[str, 1]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.hello("world")
|
||||||
|
self.consume_ndarray(np_zeros([10], dtype=str))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
StrFail().run()
|
@ -1,8 +1,10 @@
|
|||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::{
|
codegen::{
|
||||||
expr::gen_call,
|
classes::{ListValue, NDArrayValue, RangeValue, UntypedArrayLikeAccessor},
|
||||||
|
expr::{destructure_range, gen_call},
|
||||||
|
irrt::call_ndarray_calc_size,
|
||||||
llvm_intrinsics::{call_int_smax, call_stackrestore, call_stacksave},
|
llvm_intrinsics::{call_int_smax, call_stackrestore, call_stacksave},
|
||||||
stmt::{gen_block, gen_with},
|
stmt::{gen_block, gen_for_callback_incrementing, gen_if_callback, gen_with},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
},
|
},
|
||||||
symbol_resolver::ValueEnum,
|
symbol_resolver::ValueEnum,
|
||||||
@ -13,7 +15,11 @@ use nac3core::{
|
|||||||
use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
|
use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
|
||||||
|
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::Context, module::Linkage, types::IntType, values::BasicValueEnum, AddressSpace,
|
context::Context,
|
||||||
|
module::Linkage,
|
||||||
|
types::IntType,
|
||||||
|
values::{BasicValueEnum, StructValue},
|
||||||
|
AddressSpace, IntPredicate,
|
||||||
};
|
};
|
||||||
|
|
||||||
use pyo3::{
|
use pyo3::{
|
||||||
@ -23,10 +29,12 @@ use pyo3::{
|
|||||||
|
|
||||||
use crate::{symbol_resolver::InnerResolver, timeline::TimeFns};
|
use crate::{symbol_resolver::InnerResolver, timeline::TimeFns};
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
use std::{
|
use std::{
|
||||||
collections::hash_map::DefaultHasher,
|
collections::{hash_map::DefaultHasher, HashMap},
|
||||||
collections::HashMap,
|
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
|
iter::once,
|
||||||
|
mem,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -724,3 +732,472 @@ pub fn rpc_codegen_callback() -> Arc<GenCall> {
|
|||||||
rpc_codegen_callback_fn(ctx, obj, fun, args, generator)
|
rpc_codegen_callback_fn(ctx, obj, fun, args, generator)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `fprintf` format constant for the given [`llvm_int_t`][`IntType`] on a platform with
|
||||||
|
/// [`llvm_usize`] as its native word size.
|
||||||
|
///
|
||||||
|
/// Note that, similar to format constants in `<inttypes.h>`, these constants need to be prepended
|
||||||
|
/// with `%`.
|
||||||
|
#[must_use]
|
||||||
|
fn get_fprintf_format_constant<'ctx>(
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
llvm_int_t: IntType<'ctx>,
|
||||||
|
is_unsigned: bool,
|
||||||
|
) -> String {
|
||||||
|
debug_assert!(matches!(llvm_usize.get_bit_width(), 8 | 16 | 32 | 64));
|
||||||
|
|
||||||
|
let conv_spec = if is_unsigned { 'u' } else { 'd' };
|
||||||
|
|
||||||
|
// https://en.cppreference.com/w/c/language/arithmetic_types
|
||||||
|
// Note that NAC3 does **not** support LP32 and LLP64 configurations
|
||||||
|
match llvm_int_t.get_bit_width() {
|
||||||
|
8 => format!("hh{conv_spec}"),
|
||||||
|
16 => format!("h{conv_spec}"),
|
||||||
|
32 => conv_spec.to_string(),
|
||||||
|
64 => format!("{}{conv_spec}", if llvm_usize.get_bit_width() == 64 { "l" } else { "ll" }),
|
||||||
|
_ => todo!(
|
||||||
|
"Not yet implemented for i{} on {}-bit platform",
|
||||||
|
llvm_int_t.get_bit_width(),
|
||||||
|
llvm_usize.get_bit_width()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prints one or more `values` to `core_log` or `rtio_log`.
|
||||||
|
///
|
||||||
|
/// * `separator` - The separator between multiple values.
|
||||||
|
/// * `suffix` - String to terminate the printed string, if any.
|
||||||
|
/// * `as_repr` - Whether the `repr()` output of values instead of `str()`.
|
||||||
|
/// * `as_rtio` - Whether to print to `rtio_log` instead of `core_log`.
|
||||||
|
fn polymorphic_print<'ctx>(
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
values: &[(Type, ValueEnum<'ctx>)],
|
||||||
|
separator: &str,
|
||||||
|
suffix: Option<&str>,
|
||||||
|
as_repr: bool,
|
||||||
|
as_rtio: bool,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let printf = |ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
fmt: String,
|
||||||
|
args: Vec<BasicValueEnum<'ctx>>| {
|
||||||
|
debug_assert!(!fmt.is_empty());
|
||||||
|
debug_assert_eq!(fmt.as_bytes().last().unwrap(), &0u8);
|
||||||
|
|
||||||
|
let fn_name = if as_rtio { "rtio_log" } else { "core_log" };
|
||||||
|
let print_fn = ctx.module.get_function(fn_name).unwrap_or_else(|| {
|
||||||
|
let llvm_pi8 = ctx.ctx.i8_type().ptr_type(AddressSpace::default());
|
||||||
|
let fn_t = if as_rtio {
|
||||||
|
let llvm_void = ctx.ctx.void_type();
|
||||||
|
llvm_void.fn_type(&[llvm_pi8.into()], true)
|
||||||
|
} else {
|
||||||
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
|
llvm_i32.fn_type(&[llvm_pi8.into()], true)
|
||||||
|
};
|
||||||
|
ctx.module.add_function(fn_name, fn_t, None)
|
||||||
|
});
|
||||||
|
|
||||||
|
let fmt = ctx.gen_string(generator, fmt);
|
||||||
|
let fmt = unsafe { fmt.get_field_at_index_unchecked(0) }.into_pointer_value();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(
|
||||||
|
print_fn,
|
||||||
|
&once(fmt.into()).chain(args).map(BasicValueEnum::into).collect_vec(),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
};
|
||||||
|
|
||||||
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
|
let llvm_i64 = ctx.ctx.i64_type();
|
||||||
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
|
|
||||||
|
let suffix = suffix.unwrap_or_default();
|
||||||
|
|
||||||
|
let mut fmt = String::new();
|
||||||
|
let mut args = Vec::new();
|
||||||
|
|
||||||
|
let flush = |ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
fmt: &mut String,
|
||||||
|
args: &mut Vec<BasicValueEnum<'ctx>>| {
|
||||||
|
if !fmt.is_empty() {
|
||||||
|
fmt.push('\0');
|
||||||
|
printf(ctx, generator, mem::take(fmt), mem::take(args));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (ty, value) in values {
|
||||||
|
let ty = *ty;
|
||||||
|
let value = value.clone().to_basic_value_enum(ctx, generator, ty).unwrap();
|
||||||
|
|
||||||
|
if !fmt.is_empty() {
|
||||||
|
fmt.push_str(separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
match &*ctx.unifier.get_ty_immutable(ty) {
|
||||||
|
TypeEnum::TTuple { ty: tys, is_vararg_ctx: false } => {
|
||||||
|
let pvalue = {
|
||||||
|
let pvalue = generator.gen_var_alloc(ctx, value.get_type(), None).unwrap();
|
||||||
|
ctx.builder.build_store(pvalue, value).unwrap();
|
||||||
|
pvalue
|
||||||
|
};
|
||||||
|
|
||||||
|
fmt.push('(');
|
||||||
|
flush(ctx, generator, &mut fmt, &mut args);
|
||||||
|
|
||||||
|
let tuple_vals = tys
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, ty)| {
|
||||||
|
(*ty, {
|
||||||
|
let pfield =
|
||||||
|
ctx.builder.build_struct_gep(pvalue, i as u32, "").unwrap();
|
||||||
|
|
||||||
|
ValueEnum::from(ctx.builder.build_load(pfield, "").unwrap())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
polymorphic_print(ctx, generator, &tuple_vals, ", ", None, true, as_rtio)?;
|
||||||
|
|
||||||
|
if tuple_vals.len() == 1 {
|
||||||
|
fmt.push_str(",)");
|
||||||
|
} else {
|
||||||
|
fmt.push(')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeEnum::TFunc { .. } => todo!(),
|
||||||
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::None.id() => {
|
||||||
|
fmt.push_str("None");
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::Bool.id() => {
|
||||||
|
fmt.push_str("%.*s");
|
||||||
|
|
||||||
|
let true_str = ctx.gen_string(generator, "True");
|
||||||
|
let true_data =
|
||||||
|
unsafe { true_str.get_field_at_index_unchecked(0) }.into_pointer_value();
|
||||||
|
let true_len = unsafe { true_str.get_field_at_index_unchecked(1) }.into_int_value();
|
||||||
|
let false_str = ctx.gen_string(generator, "False");
|
||||||
|
let false_data =
|
||||||
|
unsafe { false_str.get_field_at_index_unchecked(0) }.into_pointer_value();
|
||||||
|
let false_len =
|
||||||
|
unsafe { false_str.get_field_at_index_unchecked(1) }.into_int_value();
|
||||||
|
|
||||||
|
let bool_val = generator.bool_to_i1(ctx, value.into_int_value());
|
||||||
|
|
||||||
|
args.extend([
|
||||||
|
ctx.builder.build_select(bool_val, true_len, false_len, "").unwrap(),
|
||||||
|
ctx.builder.build_select(bool_val, true_data, false_data, "").unwrap(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeEnum::TObj { obj_id, .. }
|
||||||
|
if *obj_id == PrimDef::Int32.id()
|
||||||
|
|| *obj_id == PrimDef::Int64.id()
|
||||||
|
|| *obj_id == PrimDef::UInt32.id()
|
||||||
|
|| *obj_id == PrimDef::UInt64.id() =>
|
||||||
|
{
|
||||||
|
let is_unsigned =
|
||||||
|
*obj_id == PrimDef::UInt32.id() || *obj_id == PrimDef::UInt64.id();
|
||||||
|
|
||||||
|
let llvm_int_t = value.get_type().into_int_type();
|
||||||
|
debug_assert!(matches!(llvm_usize.get_bit_width(), 32 | 64));
|
||||||
|
debug_assert!(matches!(llvm_int_t.get_bit_width(), 32 | 64));
|
||||||
|
|
||||||
|
let fmt_spec = format!(
|
||||||
|
"%{}",
|
||||||
|
get_fprintf_format_constant(llvm_usize, llvm_int_t, is_unsigned)
|
||||||
|
);
|
||||||
|
|
||||||
|
fmt.push_str(fmt_spec.as_str());
|
||||||
|
args.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::Float.id() => {
|
||||||
|
fmt.push_str("%g");
|
||||||
|
args.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::Str.id() => {
|
||||||
|
if as_repr {
|
||||||
|
fmt.push_str("\"%.*s\"");
|
||||||
|
} else {
|
||||||
|
fmt.push_str("%.*s");
|
||||||
|
}
|
||||||
|
|
||||||
|
let str = value.into_struct_value();
|
||||||
|
let str_data = unsafe { str.get_field_at_index_unchecked(0) }.into_pointer_value();
|
||||||
|
let str_len = unsafe { str.get_field_at_index_unchecked(1) }.into_int_value();
|
||||||
|
|
||||||
|
args.extend(&[str_len.into(), str_data.into()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
|
let elem_ty = *params.iter().next().unwrap().1;
|
||||||
|
|
||||||
|
fmt.push('[');
|
||||||
|
flush(ctx, generator, &mut fmt, &mut args);
|
||||||
|
|
||||||
|
let val = ListValue::from_ptr_val(value.into_pointer_value(), llvm_usize, None);
|
||||||
|
let len = val.load_size(ctx, None);
|
||||||
|
let last =
|
||||||
|
ctx.builder.build_int_sub(len, llvm_usize.const_int(1, false), "").unwrap();
|
||||||
|
|
||||||
|
gen_for_callback_incrementing(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
None,
|
||||||
|
llvm_usize.const_zero(),
|
||||||
|
(len, false),
|
||||||
|
|generator, ctx, _, i| {
|
||||||
|
let elem = unsafe { val.data().get_unchecked(ctx, generator, &i, None) };
|
||||||
|
|
||||||
|
polymorphic_print(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
&[(elem_ty, elem.into())],
|
||||||
|
"",
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
as_rtio,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
gen_if_callback(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
|_, ctx| {
|
||||||
|
Ok(ctx
|
||||||
|
.builder
|
||||||
|
.build_int_compare(IntPredicate::ULT, i, last, "")
|
||||||
|
.unwrap())
|
||||||
|
},
|
||||||
|
|generator, ctx| {
|
||||||
|
printf(ctx, generator, ", \0".into(), Vec::default());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
|_, _| Ok(()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
llvm_usize.const_int(1, false),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
fmt.push(']');
|
||||||
|
flush(ctx, generator, &mut fmt, &mut args);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
||||||
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
||||||
|
|
||||||
|
fmt.push_str("array([");
|
||||||
|
flush(ctx, generator, &mut fmt, &mut args);
|
||||||
|
|
||||||
|
let val = NDArrayValue::from_ptr_val(value.into_pointer_value(), llvm_usize, None);
|
||||||
|
let len = call_ndarray_calc_size(generator, ctx, &val.dim_sizes(), (None, None));
|
||||||
|
let last =
|
||||||
|
ctx.builder.build_int_sub(len, llvm_usize.const_int(1, false), "").unwrap();
|
||||||
|
|
||||||
|
gen_for_callback_incrementing(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
None,
|
||||||
|
llvm_usize.const_zero(),
|
||||||
|
(len, false),
|
||||||
|
|generator, ctx, _, i| {
|
||||||
|
let elem = unsafe { val.data().get_unchecked(ctx, generator, &i, None) };
|
||||||
|
|
||||||
|
polymorphic_print(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
&[(elem_ty, elem.into())],
|
||||||
|
"",
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
as_rtio,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
gen_if_callback(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
|_, ctx| {
|
||||||
|
Ok(ctx
|
||||||
|
.builder
|
||||||
|
.build_int_compare(IntPredicate::ULT, i, last, "")
|
||||||
|
.unwrap())
|
||||||
|
},
|
||||||
|
|generator, ctx| {
|
||||||
|
printf(ctx, generator, ", \0".into(), Vec::default());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
|_, _| Ok(()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
llvm_usize.const_int(1, false),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
fmt.push_str(")]");
|
||||||
|
flush(ctx, generator, &mut fmt, &mut args);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::Range.id() => {
|
||||||
|
fmt.push_str("range(");
|
||||||
|
flush(ctx, generator, &mut fmt, &mut args);
|
||||||
|
|
||||||
|
let val = RangeValue::from_ptr_val(value.into_pointer_value(), None);
|
||||||
|
|
||||||
|
let (start, stop, step) = destructure_range(ctx, val);
|
||||||
|
|
||||||
|
polymorphic_print(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
&[
|
||||||
|
(ctx.primitives.int32, start.into()),
|
||||||
|
(ctx.primitives.int32, stop.into()),
|
||||||
|
(ctx.primitives.int32, step.into()),
|
||||||
|
],
|
||||||
|
", ",
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
as_rtio,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
fmt.push(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::Exception.id() => {
|
||||||
|
let fmt_str = format!(
|
||||||
|
"%{}(%{}, %{1:}, %{1:})",
|
||||||
|
get_fprintf_format_constant(llvm_usize, llvm_i32, false),
|
||||||
|
get_fprintf_format_constant(llvm_usize, llvm_i64, false),
|
||||||
|
);
|
||||||
|
|
||||||
|
let exn = value.into_pointer_value();
|
||||||
|
let name = ctx
|
||||||
|
.build_in_bounds_gep_and_load(
|
||||||
|
exn,
|
||||||
|
&[llvm_i32.const_zero(), llvm_i32.const_zero()],
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.into_int_value();
|
||||||
|
let param0 = ctx
|
||||||
|
.build_in_bounds_gep_and_load(
|
||||||
|
exn,
|
||||||
|
&[llvm_i32.const_zero(), llvm_i32.const_int(6, false)],
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.into_int_value();
|
||||||
|
let param1 = ctx
|
||||||
|
.build_in_bounds_gep_and_load(
|
||||||
|
exn,
|
||||||
|
&[llvm_i32.const_zero(), llvm_i32.const_int(7, false)],
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.into_int_value();
|
||||||
|
let param2 = ctx
|
||||||
|
.build_in_bounds_gep_and_load(
|
||||||
|
exn,
|
||||||
|
&[llvm_i32.const_zero(), llvm_i32.const_int(8, false)],
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.into_int_value();
|
||||||
|
|
||||||
|
fmt.push_str(fmt_str.as_str());
|
||||||
|
args.extend_from_slice(&[name.into(), param0.into(), param1.into(), param2.into()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => unreachable!(
|
||||||
|
"Unsupported object type for polymorphic_print: {}",
|
||||||
|
ctx.unifier.stringify(ty)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.push_str(suffix);
|
||||||
|
flush(ctx, generator, &mut fmt, &mut args);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the `core_log` intrinsic function.
|
||||||
|
pub fn call_core_log_impl<'ctx>(
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
arg: (Type, BasicValueEnum<'ctx>),
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let (arg_ty, arg_val) = arg;
|
||||||
|
|
||||||
|
polymorphic_print(ctx, generator, &[(arg_ty, arg_val.into())], " ", Some("\n"), false, false)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the `rtio_log` intrinsic function.
|
||||||
|
pub fn call_rtio_log_impl<'ctx>(
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
channel: StructValue<'ctx>,
|
||||||
|
arg: (Type, BasicValueEnum<'ctx>),
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let (arg_ty, arg_val) = arg;
|
||||||
|
|
||||||
|
polymorphic_print(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
&[(ctx.primitives.str, channel.into())],
|
||||||
|
" ",
|
||||||
|
Some("\x1E"),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
polymorphic_print(ctx, generator, &[(arg_ty, arg_val.into())], " ", Some("\x1D"), false, true)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a call to `core_log`.
|
||||||
|
pub fn gen_core_log<'ctx>(
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
obj: &Option<(Type, ValueEnum<'ctx>)>,
|
||||||
|
fun: (&FunSignature, DefinitionId),
|
||||||
|
args: &[(Option<StrRef>, ValueEnum<'ctx>)],
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
assert!(obj.is_none());
|
||||||
|
assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
let value_ty = fun.0.args[0].ty;
|
||||||
|
let value_arg = args[0].1.clone().to_basic_value_enum(ctx, generator, value_ty)?;
|
||||||
|
|
||||||
|
call_core_log_impl(ctx, generator, (value_ty, value_arg))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a call to `rtio_log`.
|
||||||
|
pub fn gen_rtio_log<'ctx>(
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
obj: &Option<(Type, ValueEnum<'ctx>)>,
|
||||||
|
fun: (&FunSignature, DefinitionId),
|
||||||
|
args: &[(Option<StrRef>, ValueEnum<'ctx>)],
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
assert!(obj.is_none());
|
||||||
|
assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
|
let channel_ty = fun.0.args[0].ty;
|
||||||
|
assert!(ctx.unifier.unioned(channel_ty, ctx.primitives.str));
|
||||||
|
let channel_arg =
|
||||||
|
args[0].1.clone().to_basic_value_enum(ctx, generator, channel_ty)?.into_struct_value();
|
||||||
|
let value_ty = fun.0.args[1].ty;
|
||||||
|
let value_arg = args[1].1.clone().to_basic_value_enum(ctx, generator, value_ty)?;
|
||||||
|
|
||||||
|
call_rtio_log_impl(ctx, generator, channel_arg, (value_ty, value_arg))
|
||||||
|
}
|
||||||
|
@ -35,7 +35,7 @@ use inkwell::{
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nac3core::codegen::{gen_func_impl, CodeGenLLVMOptions, CodeGenTargetMachineOptions};
|
use nac3core::codegen::{gen_func_impl, CodeGenLLVMOptions, CodeGenTargetMachineOptions};
|
||||||
use nac3core::toplevel::builtins::get_exn_constructor;
|
use nac3core::toplevel::builtins::get_exn_constructor;
|
||||||
use nac3core::typecheck::typedef::{TypeEnum, Unifier, VarMap};
|
use nac3core::typecheck::typedef::{into_var_map, TypeEnum, Unifier, VarMap};
|
||||||
use nac3parser::{
|
use nac3parser::{
|
||||||
ast::{ExprKind, Stmt, StmtKind, StrRef},
|
ast::{ExprKind, Stmt, StmtKind, StrRef},
|
||||||
parser::parse_program,
|
parser::parse_program,
|
||||||
@ -51,7 +51,7 @@ use nac3core::{
|
|||||||
codegen::{concrete_type::ConcreteTypeStore, CodeGenTask, WithCall, WorkerRegistry},
|
codegen::{concrete_type::ConcreteTypeStore, CodeGenTask, WithCall, WorkerRegistry},
|
||||||
symbol_resolver::SymbolResolver,
|
symbol_resolver::SymbolResolver,
|
||||||
toplevel::{
|
toplevel::{
|
||||||
composer::{ComposerConfig, TopLevelComposer},
|
composer::{BuiltinFuncCreator, BuiltinFuncSpec, ComposerConfig, TopLevelComposer},
|
||||||
DefinitionId, GenCall, TopLevelDef,
|
DefinitionId, GenCall, TopLevelDef,
|
||||||
},
|
},
|
||||||
typecheck::typedef::{FunSignature, FuncArg},
|
typecheck::typedef::{FunSignature, FuncArg},
|
||||||
@ -60,13 +60,13 @@ use nac3core::{
|
|||||||
|
|
||||||
use nac3ld::Linker;
|
use nac3ld::Linker;
|
||||||
|
|
||||||
use tempfile::{self, TempDir};
|
|
||||||
|
|
||||||
use crate::codegen::attributes_writeback;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::{rpc_codegen_callback, ArtiqCodeGenerator},
|
codegen::{
|
||||||
|
attributes_writeback, gen_core_log, gen_rtio_log, rpc_codegen_callback, ArtiqCodeGenerator,
|
||||||
|
},
|
||||||
symbol_resolver::{DeferredEvaluationStore, InnerResolver, PythonHelper, Resolver},
|
symbol_resolver::{DeferredEvaluationStore, InnerResolver, PythonHelper, Resolver},
|
||||||
};
|
};
|
||||||
|
use tempfile::{self, TempDir};
|
||||||
|
|
||||||
mod codegen;
|
mod codegen;
|
||||||
mod symbol_resolver;
|
mod symbol_resolver;
|
||||||
@ -127,7 +127,7 @@ struct Nac3 {
|
|||||||
isa: Isa,
|
isa: Isa,
|
||||||
time_fns: &'static (dyn TimeFns + Sync),
|
time_fns: &'static (dyn TimeFns + Sync),
|
||||||
primitive: PrimitiveStore,
|
primitive: PrimitiveStore,
|
||||||
builtins: Vec<(StrRef, FunSignature, Arc<GenCall>)>,
|
builtins: Vec<BuiltinFuncSpec>,
|
||||||
pyid_to_def: Arc<RwLock<HashMap<u64, DefinitionId>>>,
|
pyid_to_def: Arc<RwLock<HashMap<u64, DefinitionId>>>,
|
||||||
primitive_ids: PrimitivePythonId,
|
primitive_ids: PrimitivePythonId,
|
||||||
working_directory: TempDir,
|
working_directory: TempDir,
|
||||||
@ -301,6 +301,64 @@ impl Nac3 {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a [`Vec`] of builtins that needs to be initialized during method compilation time.
|
||||||
|
fn get_lateinit_builtins() -> Vec<Box<BuiltinFuncCreator>> {
|
||||||
|
vec![
|
||||||
|
Box::new(|primitives, unifier| {
|
||||||
|
let arg_ty = unifier.get_fresh_var(Some("T".into()), None);
|
||||||
|
|
||||||
|
(
|
||||||
|
"core_log".into(),
|
||||||
|
FunSignature {
|
||||||
|
args: vec![FuncArg {
|
||||||
|
name: "arg".into(),
|
||||||
|
ty: arg_ty.ty,
|
||||||
|
default_value: None,
|
||||||
|
is_vararg: false,
|
||||||
|
}],
|
||||||
|
ret: primitives.none,
|
||||||
|
vars: into_var_map([arg_ty]),
|
||||||
|
},
|
||||||
|
Arc::new(GenCall::new(Box::new(move |ctx, obj, fun, args, generator| {
|
||||||
|
gen_core_log(ctx, &obj, fun, &args, generator)?;
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}))),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
Box::new(|primitives, unifier| {
|
||||||
|
let arg_ty = unifier.get_fresh_var(Some("T".into()), None);
|
||||||
|
|
||||||
|
(
|
||||||
|
"rtio_log".into(),
|
||||||
|
FunSignature {
|
||||||
|
args: vec![
|
||||||
|
FuncArg {
|
||||||
|
name: "channel".into(),
|
||||||
|
ty: primitives.str,
|
||||||
|
default_value: None,
|
||||||
|
is_vararg: false,
|
||||||
|
},
|
||||||
|
FuncArg {
|
||||||
|
name: "arg".into(),
|
||||||
|
ty: arg_ty.ty,
|
||||||
|
default_value: None,
|
||||||
|
is_vararg: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ret: primitives.none,
|
||||||
|
vars: into_var_map([arg_ty]),
|
||||||
|
},
|
||||||
|
Arc::new(GenCall::new(Box::new(move |ctx, obj, fun, args, generator| {
|
||||||
|
gen_rtio_log(ctx, &obj, fun, &args, generator)?;
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}))),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
fn compile_method<T>(
|
fn compile_method<T>(
|
||||||
&self,
|
&self,
|
||||||
obj: &PyAny,
|
obj: &PyAny,
|
||||||
@ -313,6 +371,7 @@ impl Nac3 {
|
|||||||
let size_t = self.isa.get_size_type();
|
let size_t = self.isa.get_size_type();
|
||||||
let (mut composer, mut builtins_def, mut builtins_ty) = TopLevelComposer::new(
|
let (mut composer, mut builtins_def, mut builtins_ty) = TopLevelComposer::new(
|
||||||
self.builtins.clone(),
|
self.builtins.clone(),
|
||||||
|
Self::get_lateinit_builtins(),
|
||||||
ComposerConfig { kernel_ann: Some("Kernel"), kernel_invariant_ann: "KernelInvariant" },
|
ComposerConfig { kernel_ann: Some("Kernel"), kernel_invariant_ann: "KernelInvariant" },
|
||||||
size_t,
|
size_t,
|
||||||
);
|
);
|
||||||
@ -853,7 +912,7 @@ impl Nac3 {
|
|||||||
Isa::RiscV32IMA => &timeline::NOW_PINNING_TIME_FNS,
|
Isa::RiscV32IMA => &timeline::NOW_PINNING_TIME_FNS,
|
||||||
Isa::CortexA9 | Isa::Host => &timeline::EXTERN_TIME_FNS,
|
Isa::CortexA9 | Isa::Host => &timeline::EXTERN_TIME_FNS,
|
||||||
};
|
};
|
||||||
let primitive: PrimitiveStore = TopLevelComposer::make_primitives(isa.get_size_type()).0;
|
let (primitive, _) = TopLevelComposer::make_primitives(isa.get_size_type());
|
||||||
let builtins = vec![
|
let builtins = vec![
|
||||||
(
|
(
|
||||||
"now_mu".into(),
|
"now_mu".into(),
|
||||||
|
@ -163,7 +163,7 @@ impl StaticValue for PythonValue {
|
|||||||
PrimitiveValue::Bool(val) => {
|
PrimitiveValue::Bool(val) => {
|
||||||
ctx.ctx.i8_type().const_int(u64::from(*val), false).into()
|
ctx.ctx.i8_type().const_int(u64::from(*val), false).into()
|
||||||
}
|
}
|
||||||
PrimitiveValue::Str(val) => ctx.ctx.const_string(val.as_bytes(), true).into(),
|
PrimitiveValue::Str(val) => ctx.gen_string(generator, val).into(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if let Some(global) = ctx.module.get_global(&self.id.to_string()) {
|
if let Some(global) = ctx.module.get_global(&self.id.to_string()) {
|
||||||
@ -977,7 +977,7 @@ impl InnerResolver {
|
|||||||
} else if ty_id == self.primitive_ids.string || ty_id == self.primitive_ids.np_str_ {
|
} else if ty_id == self.primitive_ids.string || ty_id == self.primitive_ids.np_str_ {
|
||||||
let val: String = obj.extract().unwrap();
|
let val: String = obj.extract().unwrap();
|
||||||
self.id_to_primitive.write().insert(id, PrimitiveValue::Str(val.clone()));
|
self.id_to_primitive.write().insert(id, PrimitiveValue::Str(val.clone()));
|
||||||
Ok(Some(ctx.ctx.const_string(val.as_bytes(), true).into()))
|
Ok(Some(ctx.gen_string(generator, val).into()))
|
||||||
} else if ty_id == self.primitive_ids.float || ty_id == self.primitive_ids.float64 {
|
} else if ty_id == self.primitive_ids.float || ty_id == self.primitive_ids.float64 {
|
||||||
let val: f64 = obj.extract().unwrap();
|
let val: f64 = obj.extract().unwrap();
|
||||||
self.id_to_primitive.write().insert(id, PrimitiveValue::F64(val));
|
self.id_to_primitive.write().insert(id, PrimitiveValue::F64(val));
|
||||||
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
|||||||
authors = ["M-Labs"]
|
authors = ["M-Labs"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
no-escape-analysis = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
itertools = "0.13"
|
itertools = "0.13"
|
||||||
crossbeam = "0.8"
|
crossbeam = "0.8"
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
use inkwell::types::BasicTypeEnum;
|
use inkwell::types::BasicTypeEnum;
|
||||||
use inkwell::values::{BasicValue, BasicValueEnum, PointerValue};
|
use inkwell::values::{BasicValue, BasicValueEnum, IntValue, PointerValue};
|
||||||
use inkwell::{FloatPredicate, IntPredicate, OptimizationLevel};
|
use inkwell::{FloatPredicate, IntPredicate, OptimizationLevel};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::codegen::classes::{
|
use crate::codegen::classes::{
|
||||||
NDArrayValue, ProxyValue, UntypedArrayLikeAccessor, UntypedArrayLikeMutator,
|
ArrayLikeValue, NDArrayValue, ProxyValue, RangeValue, TypedArrayLikeAccessor,
|
||||||
|
UntypedArrayLikeAccessor, UntypedArrayLikeMutator,
|
||||||
};
|
};
|
||||||
|
use crate::codegen::expr::destructure_range;
|
||||||
|
use crate::codegen::irrt::calculate_len_for_slice_range;
|
||||||
use crate::codegen::numpy::ndarray_elementwise_unaryop_impl;
|
use crate::codegen::numpy::ndarray_elementwise_unaryop_impl;
|
||||||
use crate::codegen::stmt::gen_for_callback_incrementing;
|
use crate::codegen::stmt::gen_for_callback_incrementing;
|
||||||
use crate::codegen::{extern_fns, irrt, llvm_intrinsics, numpy, CodeGenContext, CodeGenerator};
|
use crate::codegen::{extern_fns, irrt, llvm_intrinsics, numpy, CodeGenContext, CodeGenerator};
|
||||||
use crate::toplevel::helper::PrimDef;
|
use crate::toplevel::helper::PrimDef;
|
||||||
use crate::toplevel::numpy::unpack_ndarray_var_tys;
|
use crate::toplevel::numpy::unpack_ndarray_var_tys;
|
||||||
use crate::typecheck::typedef::Type;
|
use crate::typecheck::typedef::{Type, TypeEnum};
|
||||||
|
|
||||||
/// Shorthand for [`unreachable!()`] when a type of argument is not supported.
|
/// Shorthand for [`unreachable!()`] when a type of argument is not supported.
|
||||||
///
|
///
|
||||||
@ -23,6 +26,67 @@ fn unsupported_type(ctx: &CodeGenContext<'_, '_>, fn_name: &str, tys: &[Type]) -
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invokes the `len` builtin function.
|
||||||
|
pub fn call_len<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
n: (Type, BasicValueEnum<'ctx>),
|
||||||
|
) -> Result<IntValue<'ctx>, String> {
|
||||||
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
|
let range_ty = ctx.primitives.range;
|
||||||
|
let (arg_ty, arg) = n;
|
||||||
|
|
||||||
|
Ok(if ctx.unifier.unioned(arg_ty, range_ty) {
|
||||||
|
let arg = RangeValue::from_ptr_val(arg.into_pointer_value(), Some("range"));
|
||||||
|
let (start, end, step) = destructure_range(ctx, arg);
|
||||||
|
calculate_len_for_slice_range(generator, ctx, start, end, step)
|
||||||
|
} else {
|
||||||
|
match &*ctx.unifier.get_ty_immutable(arg_ty) {
|
||||||
|
TypeEnum::TTuple { ty, .. } => llvm_i32.const_int(ty.len() as u64, false),
|
||||||
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
|
let zero = llvm_i32.const_zero();
|
||||||
|
let len = ctx
|
||||||
|
.build_gep_and_load(
|
||||||
|
arg.into_pointer_value(),
|
||||||
|
&[zero, llvm_i32.const_int(1, false)],
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.into_int_value();
|
||||||
|
ctx.builder.build_int_truncate_or_bit_cast(len, llvm_i32, "len").unwrap()
|
||||||
|
}
|
||||||
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
||||||
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
|
|
||||||
|
let arg = NDArrayValue::from_ptr_val(arg.into_pointer_value(), llvm_usize, None);
|
||||||
|
|
||||||
|
let ndims = arg.dim_sizes().size(ctx, generator);
|
||||||
|
ctx.make_assert(
|
||||||
|
generator,
|
||||||
|
ctx.builder
|
||||||
|
.build_int_compare(IntPredicate::NE, ndims, llvm_usize.const_zero(), "")
|
||||||
|
.unwrap(),
|
||||||
|
"0:TypeError",
|
||||||
|
"len() of unsized object",
|
||||||
|
[None, None, None],
|
||||||
|
ctx.current_loc,
|
||||||
|
);
|
||||||
|
|
||||||
|
let len = unsafe {
|
||||||
|
arg.dim_sizes().get_typed_unchecked(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
&llvm_usize.const_zero(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.builder.build_int_truncate_or_bit_cast(len, llvm_i32, "len").unwrap()
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Invokes the `int32` builtin function.
|
/// Invokes the `int32` builtin function.
|
||||||
pub fn call_int32<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_int32<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
|
@ -32,7 +32,7 @@ use crate::{
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
attributes::{Attribute, AttributeLoc},
|
attributes::{Attribute, AttributeLoc},
|
||||||
types::{AnyType, BasicType, BasicTypeEnum},
|
types::{AnyType, BasicType, BasicTypeEnum},
|
||||||
values::{BasicValueEnum, CallSiteValue, FunctionValue, IntValue, PointerValue},
|
values::{BasicValueEnum, CallSiteValue, FunctionValue, IntValue, PointerValue, StructValue},
|
||||||
AddressSpace, IntPredicate, OptimizationLevel,
|
AddressSpace, IntPredicate, OptimizationLevel,
|
||||||
};
|
};
|
||||||
use itertools::{chain, izip, Either, Itertools};
|
use itertools::{chain, izip, Either, Itertools};
|
||||||
@ -82,6 +82,20 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
self.builder.build_load(gep, name.unwrap_or_default()).unwrap()
|
self.builder.build_load(gep, name.unwrap_or_default()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a sequence of `getelementptr inbounds` and `load` instructions which stores the value
|
||||||
|
/// of a struct field into an LLVM value.
|
||||||
|
///
|
||||||
|
/// Any out-of-bounds accesses to `ptr` will return in a `poison` value.
|
||||||
|
pub fn build_in_bounds_gep_and_load(
|
||||||
|
&mut self,
|
||||||
|
ptr: PointerValue<'ctx>,
|
||||||
|
index: &[IntValue<'ctx>],
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> BasicValueEnum<'ctx> {
|
||||||
|
let gep = unsafe { self.builder.build_in_bounds_gep(ptr, index, "") }.unwrap();
|
||||||
|
self.builder.build_load(gep, name.unwrap_or_default()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_subst_key(
|
fn get_subst_key(
|
||||||
&mut self,
|
&mut self,
|
||||||
obj: Option<Type>,
|
obj: Option<Type>,
|
||||||
@ -308,7 +322,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
self.raise_exn(
|
self.raise_exn(
|
||||||
generator,
|
generator,
|
||||||
"0:NotImplementedError",
|
"0:NotImplementedError",
|
||||||
msg,
|
msg.into(),
|
||||||
[None, None, None],
|
[None, None, None],
|
||||||
self.current_loc,
|
self.current_loc,
|
||||||
);
|
);
|
||||||
@ -568,12 +582,14 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function for generating a LLVM variable storing a [String].
|
/// Helper function for generating a LLVM variable storing a [String].
|
||||||
pub fn gen_string<G, S>(&mut self, generator: &mut G, s: S) -> BasicValueEnum<'ctx>
|
pub fn gen_string<G, S>(&mut self, generator: &mut G, s: S) -> StructValue<'ctx>
|
||||||
where
|
where
|
||||||
G: CodeGenerator + ?Sized,
|
G: CodeGenerator + ?Sized,
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
{
|
{
|
||||||
self.gen_const(generator, &Constant::Str(s.into()), self.primitives.str).unwrap()
|
self.gen_const(generator, &Constant::Str(s.into()), self.primitives.str)
|
||||||
|
.map(BasicValueEnum::into_struct_value)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raise_exn<G: CodeGenerator + ?Sized>(
|
pub fn raise_exn<G: CodeGenerator + ?Sized>(
|
||||||
@ -632,7 +648,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
loc: Location,
|
loc: Location,
|
||||||
) {
|
) {
|
||||||
let err_msg = self.gen_string(generator, err_msg);
|
let err_msg = self.gen_string(generator, err_msg);
|
||||||
self.make_assert_impl(generator, cond, err_name, err_msg, params, loc);
|
self.make_assert_impl(generator, cond, err_name, err_msg.into(), params, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_assert_impl<G: CodeGenerator + ?Sized>(
|
pub fn make_assert_impl<G: CodeGenerator + ?Sized>(
|
||||||
@ -2966,8 +2982,23 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Call { func, args, keywords } => {
|
ExprKind::Call { func, args, keywords } => {
|
||||||
|
// Check if expr is override or not
|
||||||
|
let mut is_override = false;
|
||||||
|
if let Some(arg) = args.first() {
|
||||||
|
if let ExprKind::Name { id, .. } = arg.node {
|
||||||
|
if id == "self".into() {
|
||||||
|
is_override = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut args = args.clone();
|
||||||
|
if is_override {
|
||||||
|
args.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
let mut params = args
|
let mut params = args
|
||||||
.iter()
|
.iter()
|
||||||
|
.skip(if is_override { 1 } else { 0 })
|
||||||
.map(|arg| generator.gen_expr(ctx, arg))
|
.map(|arg| generator.gen_expr(ctx, arg))
|
||||||
.take_while(|expr| !matches!(expr, Ok(None)))
|
.take_while(|expr| !matches!(expr, Ok(None)))
|
||||||
.map(|expr| Ok((None, expr?.unwrap())) as Result<_, String>)
|
.map(|expr| Ok((None, expr?.unwrap())) as Result<_, String>)
|
||||||
@ -3019,9 +3050,14 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
let fun_id = {
|
let fun_id = {
|
||||||
let defs = ctx.top_level.definitions.read();
|
let defs = ctx.top_level.definitions.read();
|
||||||
let obj_def = defs.get(id.0).unwrap().read();
|
let obj_def = defs.get(id.0).unwrap().read();
|
||||||
let TopLevelDef::Class { methods, .. } = &*obj_def else { unreachable!() };
|
let TopLevelDef::Class { methods, virtual_table, .. } = &*obj_def else {
|
||||||
|
unreachable!()
|
||||||
methods.iter().find(|method| method.0 == *attr).unwrap().2
|
};
|
||||||
|
if is_override {
|
||||||
|
virtual_table.get(attr).unwrap().1
|
||||||
|
} else {
|
||||||
|
methods.iter().find(|method| method.0 == *attr).unwrap().2
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// directly generate code for option.unwrap
|
// directly generate code for option.unwrap
|
||||||
// since it needs to return static value to optimize for kernel invariant
|
// since it needs to return static value to optimize for kernel invariant
|
||||||
@ -3053,7 +3089,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
ctx.raise_exn(
|
ctx.raise_exn(
|
||||||
generator,
|
generator,
|
||||||
"0:UnwrapNoneError",
|
"0:UnwrapNoneError",
|
||||||
err_msg,
|
err_msg.into(),
|
||||||
[None, None, None],
|
[None, None, None],
|
||||||
ctx.current_loc,
|
ctx.current_loc,
|
||||||
);
|
);
|
||||||
|
@ -257,7 +257,7 @@ fn ndarray_zero_value<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
} else if ctx.unifier.unioned(elem_ty, ctx.primitives.bool) {
|
} else if ctx.unifier.unioned(elem_ty, ctx.primitives.bool) {
|
||||||
ctx.ctx.bool_type().const_zero().into()
|
ctx.ctx.bool_type().const_zero().into()
|
||||||
} else if ctx.unifier.unioned(elem_ty, ctx.primitives.str) {
|
} else if ctx.unifier.unioned(elem_ty, ctx.primitives.str) {
|
||||||
ctx.gen_string(generator, "")
|
ctx.gen_string(generator, "").into()
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@ -285,7 +285,7 @@ fn ndarray_one_value<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
} else if ctx.unifier.unioned(elem_ty, ctx.primitives.bool) {
|
} else if ctx.unifier.unioned(elem_ty, ctx.primitives.bool) {
|
||||||
ctx.ctx.bool_type().const_int(1, false).into()
|
ctx.ctx.bool_type().const_int(1, false).into()
|
||||||
} else if ctx.unifier.unioned(elem_ty, ctx.primitives.str) {
|
} else if ctx.unifier.unioned(elem_ty, ctx.primitives.str) {
|
||||||
ctx.gen_string(generator, "1")
|
ctx.gen_string(generator, "1").into()
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -1780,7 +1780,7 @@ pub fn gen_stmt<G: CodeGenerator>(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => ctx.gen_string(generator, ""),
|
None => ctx.gen_string(generator, "").into(),
|
||||||
};
|
};
|
||||||
ctx.make_assert_impl(
|
ctx.make_assert_impl(
|
||||||
generator,
|
generator,
|
||||||
|
@ -94,7 +94,7 @@ fn test_primitives() {
|
|||||||
"};
|
"};
|
||||||
let statements = parse_program(source, FileName::default()).unwrap();
|
let statements = parse_program(source, FileName::default()).unwrap();
|
||||||
|
|
||||||
let composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 32).0;
|
let composer = TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 32).0;
|
||||||
let mut unifier = composer.unifier.clone();
|
let mut unifier = composer.unifier.clone();
|
||||||
let primitives = composer.primitives_ty;
|
let primitives = composer.primitives_ty;
|
||||||
let top_level = Arc::new(composer.make_top_level_context());
|
let top_level = Arc::new(composer.make_top_level_context());
|
||||||
@ -258,7 +258,7 @@ fn test_simple_call() {
|
|||||||
"};
|
"};
|
||||||
let statements_2 = parse_program(source_2, FileName::default()).unwrap();
|
let statements_2 = parse_program(source_2, FileName::default()).unwrap();
|
||||||
|
|
||||||
let composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 32).0;
|
let composer = TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 32).0;
|
||||||
let mut unifier = composer.unifier.clone();
|
let mut unifier = composer.unifier.clone();
|
||||||
let primitives = composer.primitives_ty;
|
let primitives = composer.primitives_ty;
|
||||||
let top_level = Arc::new(composer.make_top_level_context());
|
let top_level = Arc::new(composer.make_top_level_context());
|
||||||
|
@ -14,9 +14,7 @@ use strum::IntoEnumIterator;
|
|||||||
use crate::{
|
use crate::{
|
||||||
codegen::{
|
codegen::{
|
||||||
builtin_fns,
|
builtin_fns,
|
||||||
classes::{ArrayLikeValue, NDArrayValue, ProxyValue, RangeValue, TypedArrayLikeAccessor},
|
classes::{ProxyValue, RangeValue},
|
||||||
expr::destructure_range,
|
|
||||||
irrt::*,
|
|
||||||
numpy::*,
|
numpy::*,
|
||||||
stmt::exn_constructor,
|
stmt::exn_constructor,
|
||||||
},
|
},
|
||||||
@ -98,6 +96,7 @@ pub fn get_exn_constructor(
|
|||||||
fields: exception_fields,
|
fields: exception_fields,
|
||||||
attributes: Vec::default(),
|
attributes: Vec::default(),
|
||||||
methods: vec![("__init__".into(), signature, DefinitionId(cons_id))],
|
methods: vec![("__init__".into(), signature, DefinitionId(cons_id))],
|
||||||
|
virtual_table: HashMap::default(),
|
||||||
ancestors: vec![
|
ancestors: vec![
|
||||||
TypeAnnotation::CustomClass { id: DefinitionId(class_id), params: Vec::default() },
|
TypeAnnotation::CustomClass { id: DefinitionId(class_id), params: Vec::default() },
|
||||||
TypeAnnotation::CustomClass { id: PrimDef::Exception.id(), params: Vec::default() },
|
TypeAnnotation::CustomClass { id: PrimDef::Exception.id(), params: Vec::default() },
|
||||||
@ -691,6 +690,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
fields,
|
fields,
|
||||||
attributes: Vec::default(),
|
attributes: Vec::default(),
|
||||||
methods: vec![("__init__".into(), ctor_signature, PrimDef::FunRangeInit.id())],
|
methods: vec![("__init__".into(), ctor_signature, PrimDef::FunRangeInit.id())],
|
||||||
|
virtual_table: HashMap::default(),
|
||||||
ancestors: Vec::default(),
|
ancestors: Vec::default(),
|
||||||
constructor: Some(ctor_signature),
|
constructor: Some(ctor_signature),
|
||||||
resolver: None,
|
resolver: None,
|
||||||
@ -823,6 +823,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
fields: make_exception_fields(int32, int64, str),
|
fields: make_exception_fields(int32, int64, str),
|
||||||
attributes: Vec::default(),
|
attributes: Vec::default(),
|
||||||
methods: Vec::default(),
|
methods: Vec::default(),
|
||||||
|
virtual_table: HashMap::default(),
|
||||||
ancestors: vec![],
|
ancestors: vec![],
|
||||||
constructor: None,
|
constructor: None,
|
||||||
resolver: None,
|
resolver: None,
|
||||||
@ -857,6 +858,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
Self::create_method(PrimDef::FunOptionIsNone, self.is_some_ty.0),
|
Self::create_method(PrimDef::FunOptionIsNone, self.is_some_ty.0),
|
||||||
Self::create_method(PrimDef::FunOptionUnwrap, self.unwrap_ty.0),
|
Self::create_method(PrimDef::FunOptionUnwrap, self.unwrap_ty.0),
|
||||||
],
|
],
|
||||||
|
virtual_table: HashMap::default(),
|
||||||
ancestors: vec![TypeAnnotation::CustomClass {
|
ancestors: vec![TypeAnnotation::CustomClass {
|
||||||
id: prim.id(),
|
id: prim.id(),
|
||||||
params: Vec::default(),
|
params: Vec::default(),
|
||||||
@ -964,6 +966,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
fields: Vec::default(),
|
fields: Vec::default(),
|
||||||
attributes: Vec::default(),
|
attributes: Vec::default(),
|
||||||
methods: Vec::default(),
|
methods: Vec::default(),
|
||||||
|
virtual_table: HashMap::default(),
|
||||||
ancestors: Vec::default(),
|
ancestors: Vec::default(),
|
||||||
constructor: None,
|
constructor: None,
|
||||||
resolver: None,
|
resolver: None,
|
||||||
@ -992,6 +995,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
Self::create_method(PrimDef::FunNDArrayCopy, self.ndarray_copy_ty.0),
|
Self::create_method(PrimDef::FunNDArrayCopy, self.ndarray_copy_ty.0),
|
||||||
Self::create_method(PrimDef::FunNDArrayFill, self.ndarray_fill_ty.0),
|
Self::create_method(PrimDef::FunNDArrayFill, self.ndarray_fill_ty.0),
|
||||||
],
|
],
|
||||||
|
virtual_table: HashMap::default(),
|
||||||
ancestors: Vec::default(),
|
ancestors: Vec::default(),
|
||||||
constructor: None,
|
constructor: None,
|
||||||
resolver: None,
|
resolver: None,
|
||||||
@ -1466,36 +1470,21 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
fn build_len_function(&mut self) -> TopLevelDef {
|
fn build_len_function(&mut self) -> TopLevelDef {
|
||||||
let prim = PrimDef::FunLen;
|
let prim = PrimDef::FunLen;
|
||||||
|
|
||||||
let PrimitiveStore { uint64, int32, .. } = *self.primitives;
|
// Type handled in [`Inferencer::try_fold_special_call`]
|
||||||
|
let arg_tvar = self.unifier.get_dummy_var();
|
||||||
|
|
||||||
let tvar = self.unifier.get_fresh_var(Some("L".into()), None);
|
|
||||||
let list = self
|
|
||||||
.unifier
|
|
||||||
.subst(
|
|
||||||
self.primitives.list,
|
|
||||||
&into_var_map([TypeVar { id: self.list_tvar.id, ty: tvar.ty }]),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let ndims = self.unifier.get_fresh_const_generic_var(uint64, Some("N".into()), None);
|
|
||||||
let ndarray = make_ndarray_ty(self.unifier, self.primitives, Some(tvar.ty), Some(ndims.ty));
|
|
||||||
|
|
||||||
let arg_ty = self.unifier.get_fresh_var_with_range(
|
|
||||||
&[list, ndarray, self.primitives.range],
|
|
||||||
Some("I".into()),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
TopLevelDef::Function {
|
TopLevelDef::Function {
|
||||||
name: prim.name().into(),
|
name: prim.name().into(),
|
||||||
simple_name: prim.simple_name().into(),
|
simple_name: prim.simple_name().into(),
|
||||||
signature: self.unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
signature: self.unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
||||||
args: vec![FuncArg {
|
args: vec![FuncArg {
|
||||||
name: "ls".into(),
|
name: "obj".into(),
|
||||||
ty: arg_ty.ty,
|
ty: arg_tvar.ty,
|
||||||
default_value: None,
|
default_value: None,
|
||||||
is_vararg: false,
|
is_vararg: false,
|
||||||
}],
|
}],
|
||||||
ret: int32,
|
ret: self.primitives.int32,
|
||||||
vars: into_var_map([tvar, arg_ty]),
|
vars: into_var_map([arg_tvar]),
|
||||||
})),
|
})),
|
||||||
var_id: Vec::default(),
|
var_id: Vec::default(),
|
||||||
instance_to_symbol: HashMap::default(),
|
instance_to_symbol: HashMap::default(),
|
||||||
@ -1503,86 +1492,10 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
move |ctx, _, fun, args, generator| {
|
move |ctx, _, fun, args, generator| {
|
||||||
let range_ty = ctx.primitives.range;
|
|
||||||
let arg_ty = fun.0.args[0].ty;
|
let arg_ty = fun.0.args[0].ty;
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
||||||
Ok(if ctx.unifier.unioned(arg_ty, range_ty) {
|
|
||||||
let arg = RangeValue::from_ptr_val(arg.into_pointer_value(), Some("range"));
|
|
||||||
let (start, end, step) = destructure_range(ctx, arg);
|
|
||||||
Some(calculate_len_for_slice_range(generator, ctx, start, end, step).into())
|
|
||||||
} else {
|
|
||||||
match &*ctx.unifier.get_ty_immutable(arg_ty) {
|
|
||||||
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::List.id() => {
|
|
||||||
let int32 = ctx.ctx.i32_type();
|
|
||||||
let zero = int32.const_zero();
|
|
||||||
let len = ctx
|
|
||||||
.build_gep_and_load(
|
|
||||||
arg.into_pointer_value(),
|
|
||||||
&[zero, int32.const_int(1, false)],
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.into_int_value();
|
|
||||||
if len.get_type().get_bit_width() == 32 {
|
|
||||||
Some(len.into())
|
|
||||||
} else {
|
|
||||||
Some(
|
|
||||||
ctx.builder
|
|
||||||
.build_int_truncate(len, int32, "len2i32")
|
|
||||||
.map(Into::into)
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
|
||||||
let llvm_i32 = ctx.ctx.i32_type();
|
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
|
||||||
|
|
||||||
let arg = NDArrayValue::from_ptr_val(
|
builtin_fns::call_len(generator, ctx, (arg_ty, arg)).map(|ret| Some(ret.into()))
|
||||||
arg.into_pointer_value(),
|
|
||||||
llvm_usize,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
let ndims = arg.dim_sizes().size(ctx, generator);
|
|
||||||
ctx.make_assert(
|
|
||||||
generator,
|
|
||||||
ctx.builder
|
|
||||||
.build_int_compare(
|
|
||||||
IntPredicate::NE,
|
|
||||||
ndims,
|
|
||||||
llvm_usize.const_zero(),
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
"0:TypeError",
|
|
||||||
&format!("{name}() of unsized object", name = prim.name()),
|
|
||||||
[None, None, None],
|
|
||||||
ctx.current_loc,
|
|
||||||
);
|
|
||||||
|
|
||||||
let len = unsafe {
|
|
||||||
arg.dim_sizes().get_typed_unchecked(
|
|
||||||
ctx,
|
|
||||||
generator,
|
|
||||||
&llvm_usize.const_zero(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if len.get_type().get_bit_width() == 32 {
|
|
||||||
Some(len.into())
|
|
||||||
} else {
|
|
||||||
Some(
|
|
||||||
ctx.builder
|
|
||||||
.build_int_truncate(len, llvm_i32, "len")
|
|
||||||
.map(Into::into)
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
)))),
|
)))),
|
||||||
loc: None,
|
loc: None,
|
||||||
|
@ -44,12 +44,27 @@ pub struct TopLevelComposer {
|
|||||||
pub size_t: u32,
|
pub size_t: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The specification for a builtin function, consisting of the function name, the function
|
||||||
|
/// signature, and a [code generation callback][`GenCall`].
|
||||||
|
pub type BuiltinFuncSpec = (StrRef, FunSignature, Arc<GenCall>);
|
||||||
|
|
||||||
|
/// A function that creates a [`BuiltinFuncSpec`] using the provided [`PrimitiveStore`] and
|
||||||
|
/// [`Unifier`].
|
||||||
|
pub type BuiltinFuncCreator = dyn Fn(&PrimitiveStore, &mut Unifier) -> BuiltinFuncSpec;
|
||||||
|
|
||||||
impl TopLevelComposer {
|
impl TopLevelComposer {
|
||||||
/// return a composer and things to make a "primitive" symbol resolver, so that the symbol
|
/// return a composer and things to make a "primitive" symbol resolver, so that the symbol
|
||||||
/// resolver can later figure out primitive type definitions when passed a primitive type name
|
/// resolver can later figure out primitive tye definitions when passed a primitive type name
|
||||||
|
///
|
||||||
|
/// `lateinit_builtins` are specifically for the ARTIQ module. Since the [`Unifier`] instance
|
||||||
|
/// used to create builtin functions do not persist until method compilation, any types
|
||||||
|
/// created (e.g. [`TypeEnum::TVar`]) also do not persist. Those functions should be instead put
|
||||||
|
/// in `lateinit_builtins`, where they will be instantiated with the [`Unifier`] instance used
|
||||||
|
/// for method compilation.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
builtins: Vec<(StrRef, FunSignature, Arc<GenCall>)>,
|
builtins: Vec<BuiltinFuncSpec>,
|
||||||
|
lateinit_builtins: Vec<Box<BuiltinFuncCreator>>,
|
||||||
core_config: ComposerConfig,
|
core_config: ComposerConfig,
|
||||||
size_t: u32,
|
size_t: u32,
|
||||||
) -> (Self, HashMap<StrRef, DefinitionId>, HashMap<StrRef, Type>) {
|
) -> (Self, HashMap<StrRef, DefinitionId>, HashMap<StrRef, Type>) {
|
||||||
@ -119,7 +134,13 @@ impl TopLevelComposer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, sig, codegen_callback) in builtins {
|
// Materialize lateinit_builtins, now that the unifier is ready
|
||||||
|
let lateinit_builtins = lateinit_builtins
|
||||||
|
.into_iter()
|
||||||
|
.map(|builtin| builtin(&primitives_ty, &mut unifier))
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
for (name, sig, codegen_callback) in builtins.into_iter().chain(lateinit_builtins) {
|
||||||
let fun_sig = unifier.add_ty(TypeEnum::TFunc(sig));
|
let fun_sig = unifier.add_ty(TypeEnum::TFunc(sig));
|
||||||
builtin_ty.insert(name, fun_sig);
|
builtin_ty.insert(name, fun_sig);
|
||||||
builtin_id.insert(name, DefinitionId(definition_ast_list.len()));
|
builtin_id.insert(name, DefinitionId(definition_ast_list.len()));
|
||||||
@ -1507,9 +1528,9 @@ impl TopLevelComposer {
|
|||||||
fn analyze_single_class_ancestors(
|
fn analyze_single_class_ancestors(
|
||||||
class_def: &mut TopLevelDef,
|
class_def: &mut TopLevelDef,
|
||||||
temp_def_list: &[Arc<RwLock<TopLevelDef>>],
|
temp_def_list: &[Arc<RwLock<TopLevelDef>>],
|
||||||
unifier: &mut Unifier,
|
_unifier: &mut Unifier,
|
||||||
_primitives: &PrimitiveStore,
|
_primitives: &PrimitiveStore,
|
||||||
type_var_to_concrete_def: &mut HashMap<Type, TypeAnnotation>,
|
_type_var_to_concrete_def: &mut HashMap<Type, TypeAnnotation>,
|
||||||
) -> Result<(), HashSet<String>> {
|
) -> Result<(), HashSet<String>> {
|
||||||
let TopLevelDef::Class {
|
let TopLevelDef::Class {
|
||||||
object_id,
|
object_id,
|
||||||
@ -1517,6 +1538,7 @@ impl TopLevelComposer {
|
|||||||
fields,
|
fields,
|
||||||
attributes,
|
attributes,
|
||||||
methods,
|
methods,
|
||||||
|
virtual_table,
|
||||||
resolver,
|
resolver,
|
||||||
type_vars,
|
type_vars,
|
||||||
..
|
..
|
||||||
@ -1530,9 +1552,19 @@ impl TopLevelComposer {
|
|||||||
class_fields_def,
|
class_fields_def,
|
||||||
class_attribute_def,
|
class_attribute_def,
|
||||||
class_methods_def,
|
class_methods_def,
|
||||||
|
class_virtual_table,
|
||||||
_class_type_vars_def,
|
_class_type_vars_def,
|
||||||
_class_resolver,
|
_class_resolver,
|
||||||
) = (*object_id, ancestors, fields, attributes, methods, type_vars, resolver);
|
) = (
|
||||||
|
*object_id,
|
||||||
|
ancestors,
|
||||||
|
fields,
|
||||||
|
attributes,
|
||||||
|
methods,
|
||||||
|
virtual_table,
|
||||||
|
type_vars,
|
||||||
|
resolver,
|
||||||
|
);
|
||||||
|
|
||||||
// since when this function is called, the ancestors of the direct parent
|
// since when this function is called, the ancestors of the direct parent
|
||||||
// are supposed to be already handled, so we only need to deal with the direct parent
|
// are supposed to be already handled, so we only need to deal with the direct parent
|
||||||
@ -1543,51 +1575,88 @@ impl TopLevelComposer {
|
|||||||
|
|
||||||
let base = temp_def_list.get(id.0).unwrap();
|
let base = temp_def_list.get(id.0).unwrap();
|
||||||
let base = base.read();
|
let base = base.read();
|
||||||
let TopLevelDef::Class { methods, fields, attributes, .. } = &*base else {
|
let TopLevelDef::Class { methods, virtual_table, fields, attributes, .. } = &*base else {
|
||||||
unreachable!("must be top level class def")
|
unreachable!("must be top level class def")
|
||||||
};
|
};
|
||||||
|
|
||||||
// handle methods override
|
// handle methods override
|
||||||
// since we need to maintain the order, create a new list
|
// since we need to maintain the order, create a new list
|
||||||
|
|
||||||
|
// handle methods override
|
||||||
|
// Since we are following python and its lax syntax, signature is ignored in overriding
|
||||||
|
// Mark the overrided methods and add them to the child overrides
|
||||||
|
|
||||||
let mut new_child_methods: Vec<(StrRef, Type, DefinitionId)> = Vec::new();
|
let mut new_child_methods: Vec<(StrRef, Type, DefinitionId)> = Vec::new();
|
||||||
|
let mut new_child_virtual_table: HashMap<StrRef, (Type, DefinitionId)> =
|
||||||
|
virtual_table.clone();
|
||||||
let mut is_override: HashSet<StrRef> = HashSet::new();
|
let mut is_override: HashSet<StrRef> = HashSet::new();
|
||||||
|
|
||||||
for (anc_method_name, anc_method_ty, anc_method_def_id) in methods {
|
for (anc_method_name, anc_method_ty, anc_method_def_id) in methods {
|
||||||
// find if there is a method with same name in the child class
|
|
||||||
let mut to_be_added = (*anc_method_name, *anc_method_ty, *anc_method_def_id);
|
let mut to_be_added = (*anc_method_name, *anc_method_ty, *anc_method_def_id);
|
||||||
for (class_method_name, class_method_ty, class_method_defid) in &*class_methods_def {
|
for class_method in &*class_methods_def {
|
||||||
if class_method_name == anc_method_name {
|
if class_method.0 == *anc_method_name {
|
||||||
// ignore and handle self
|
to_be_added = *class_method;
|
||||||
// if is __init__ method, no need to check return type
|
// Add to virtual table
|
||||||
let ok = class_method_name == &"__init__".into()
|
new_child_virtual_table
|
||||||
|| Self::check_overload_function_type(
|
.insert(class_method.0, (class_method.1, class_method.2));
|
||||||
*class_method_ty,
|
is_override.insert(class_method.0);
|
||||||
*anc_method_ty,
|
|
||||||
unifier,
|
|
||||||
type_var_to_concrete_def,
|
|
||||||
);
|
|
||||||
if !ok {
|
|
||||||
return Err(HashSet::from([format!(
|
|
||||||
"method {class_method_name} has same name as ancestors' method, but incompatible type"),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
// mark it as added
|
|
||||||
is_override.insert(*class_method_name);
|
|
||||||
to_be_added = (*class_method_name, *class_method_ty, *class_method_defid);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new_child_methods.push(to_be_added);
|
new_child_methods.push(to_be_added);
|
||||||
}
|
}
|
||||||
// add those that are not overriding method to the new_child_methods
|
for class_method in &*class_methods_def {
|
||||||
for (class_method_name, class_method_ty, class_method_defid) in &*class_methods_def {
|
if !is_override.contains(&class_method.0) {
|
||||||
if !is_override.contains(class_method_name) {
|
new_child_methods.push(*class_method);
|
||||||
new_child_methods.push((*class_method_name, *class_method_ty, *class_method_defid));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
|
||||||
|
Call => class method
|
||||||
|
super() or class_name A.f1() => method, virtual_tables
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// for (anc_method_name, anc_method_ty, anc_method_def_id) in methods {
|
||||||
|
// // find if there is a method with same name in the child class
|
||||||
|
// let mut to_be_added = (*anc_method_name, *anc_method_ty, *anc_method_def_id);
|
||||||
|
// for (class_method_name, class_method_ty, class_method_defid) in &*class_methods_def {
|
||||||
|
// if class_method_name == anc_method_name {
|
||||||
|
// // ignore and handle self
|
||||||
|
// // if is __init__ method, no need to check return type
|
||||||
|
// let ok = class_method_name == &"__init__".into()
|
||||||
|
// || Self::check_overload_function_type(
|
||||||
|
// *class_method_ty,
|
||||||
|
// *anc_method_ty,
|
||||||
|
// unifier,
|
||||||
|
// type_var_to_concrete_def,
|
||||||
|
// );
|
||||||
|
// if !ok {
|
||||||
|
// return Err(HashSet::from([format!(
|
||||||
|
// "method {class_method_name} has same name as ancestors' method, but incompatible type"),
|
||||||
|
// ]));
|
||||||
|
// }
|
||||||
|
// // mark it as added
|
||||||
|
// is_override.insert(*class_method_name);
|
||||||
|
// to_be_added = (*class_method_name, *class_method_ty, *class_method_defid);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// new_child_methods.push(to_be_added);
|
||||||
|
// }
|
||||||
|
// // add those that are not overriding method to the new_child_methods
|
||||||
|
// for (class_method_name, class_method_ty, class_method_defid) in &*class_methods_def {
|
||||||
|
// if !is_override.contains(class_method_name) {
|
||||||
|
// new_child_methods.push((*class_method_name, *class_method_ty, *class_method_defid));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
// use the new_child_methods to replace all the elements in `class_methods_def`
|
// use the new_child_methods to replace all the elements in `class_methods_def`
|
||||||
class_methods_def.clear();
|
class_methods_def.clear();
|
||||||
class_methods_def.extend(new_child_methods);
|
class_methods_def.extend(new_child_methods);
|
||||||
|
|
||||||
|
class_virtual_table.clear();
|
||||||
|
class_virtual_table.extend(new_child_virtual_table);
|
||||||
|
|
||||||
// handle class fields
|
// handle class fields
|
||||||
let mut new_child_fields: Vec<(StrRef, Type, bool)> = Vec::new();
|
let mut new_child_fields: Vec<(StrRef, Type, bool)> = Vec::new();
|
||||||
// let mut is_override: HashSet<_> = HashSet::new();
|
// let mut is_override: HashSet<_> = HashSet::new();
|
||||||
|
@ -559,6 +559,7 @@ impl TopLevelComposer {
|
|||||||
fields: Vec::default(),
|
fields: Vec::default(),
|
||||||
attributes: Vec::default(),
|
attributes: Vec::default(),
|
||||||
methods: Vec::default(),
|
methods: Vec::default(),
|
||||||
|
virtual_table: HashMap::default(),
|
||||||
ancestors: Vec::default(),
|
ancestors: Vec::default(),
|
||||||
constructor,
|
constructor,
|
||||||
resolver,
|
resolver,
|
||||||
|
@ -109,6 +109,8 @@ pub enum TopLevelDef {
|
|||||||
attributes: Vec<(StrRef, Type, ast::Constant)>,
|
attributes: Vec<(StrRef, Type, ast::Constant)>,
|
||||||
/// Class methods, pointing to the corresponding function definition.
|
/// Class methods, pointing to the corresponding function definition.
|
||||||
methods: Vec<(StrRef, Type, DefinitionId)>,
|
methods: Vec<(StrRef, Type, DefinitionId)>,
|
||||||
|
/// Overridden class methods
|
||||||
|
virtual_table: HashMap<StrRef, (Type, DefinitionId)>,
|
||||||
/// Ancestor classes, including itself.
|
/// Ancestor classes, including itself.
|
||||||
ancestors: Vec<TypeAnnotation>,
|
ancestors: Vec<TypeAnnotation>,
|
||||||
/// Symbol resolver of the module defined the class; [None] if it is built-in type.
|
/// Symbol resolver of the module defined the class; [None] if it is built-in type.
|
||||||
|
@ -5,7 +5,7 @@ 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: [\"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",
|
||||||
"Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [TypeVarId(246)]\n}\n",
|
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [TypeVarId(241)]\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: [\"B\"],\nfields: [\"aa\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:T], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:T], none]\",\nvar_id: []\n}\n",
|
||||||
|
@ -7,7 +7,7 @@ expression: res_vec
|
|||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[t:T], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[t:T], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[c:C], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.foo\",\nsig: \"fn[[c:C], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B[typevar235]\", \"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: [\"typevar235\"]\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B[typevar230]\", \"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: [\"typevar230\"]\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"C\",\nancestors: [\"C\", \"B[bool]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"C\",\nancestors: [\"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",
|
||||||
|
@ -5,8 +5,8 @@ expression: res_vec
|
|||||||
[
|
[
|
||||||
"Function {\nname: \"foo\",\nsig: \"fn[[a:list[int32], b:tuple[T, float]], A[B, bool]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"foo\",\nsig: \"fn[[a:list[int32], b:tuple[T, float]], A[B, bool]]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"A\",\nancestors: [\"A[T, V]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[v:V], none]\"), (\"fun\", \"fn[[a:T], V]\")],\ntype_vars: [\"T\", \"V\"]\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"A[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: [TypeVarId(248)]\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [TypeVarId(243)]\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(253)]\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(248)]\n}\n",
|
||||||
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[list[float], int32]], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[list[float], int32]], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
|
@ -3,7 +3,7 @@ source: nac3core/src/toplevel/test.rs
|
|||||||
expression: res_vec
|
expression: res_vec
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Class {\nname: \"A\",\nancestors: [\"A[typevar234, typevar235]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[float, bool], b:B], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\")],\ntype_vars: [\"typevar234\", \"typevar235\"]\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"A[typevar229, typevar230]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[float, bool], b:B], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\")],\ntype_vars: [\"typevar229\", \"typevar230\"]\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[float, bool], b:B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[float, bool], b:B], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[float, bool]], A[bool, int32]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[float, bool]], 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[float, bool]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[list[B], int32]], tuple[A[virtual[A[B, int32]], bool], B]]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B\", \"A[int64, bool]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[list[B], int32]], tuple[A[virtual[A[B, int32]], bool], B]]\")],\ntype_vars: []\n}\n",
|
||||||
|
@ -6,12 +6,12 @@ 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: [\"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [TypeVarId(254)]\n}\n",
|
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [TypeVarId(249)]\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: [\"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",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"C\",\nancestors: [\"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"C\",\nancestors: [\"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"C.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"C.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"foo\",\nsig: \"fn[[a:A], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"foo\",\nsig: \"fn[[a:A], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(262)]\n}\n",
|
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(257)]\n}\n",
|
||||||
]
|
]
|
||||||
|
@ -117,7 +117,8 @@ impl SymbolResolver for Resolver {
|
|||||||
"register"
|
"register"
|
||||||
)]
|
)]
|
||||||
fn test_simple_register(source: Vec<&str>) {
|
fn test_simple_register(source: Vec<&str>) {
|
||||||
let mut composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 64).0;
|
let mut composer =
|
||||||
|
TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0;
|
||||||
|
|
||||||
for s in source {
|
for s in source {
|
||||||
let ast = parse_program(s, FileName::default()).unwrap();
|
let ast = parse_program(s, FileName::default()).unwrap();
|
||||||
@ -137,7 +138,8 @@ fn test_simple_register(source: Vec<&str>) {
|
|||||||
"register"
|
"register"
|
||||||
)]
|
)]
|
||||||
fn test_simple_register_without_constructor(source: &str) {
|
fn test_simple_register_without_constructor(source: &str) {
|
||||||
let mut composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 64).0;
|
let mut composer =
|
||||||
|
TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0;
|
||||||
let ast = parse_program(source, FileName::default()).unwrap();
|
let ast = parse_program(source, FileName::default()).unwrap();
|
||||||
let ast = ast[0].clone();
|
let ast = ast[0].clone();
|
||||||
composer.register_top_level(ast, None, "", true).unwrap();
|
composer.register_top_level(ast, None, "", true).unwrap();
|
||||||
@ -171,7 +173,8 @@ fn test_simple_register_without_constructor(source: &str) {
|
|||||||
"function compose"
|
"function compose"
|
||||||
)]
|
)]
|
||||||
fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
|
fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
|
||||||
let mut composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 64).0;
|
let mut composer =
|
||||||
|
TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0;
|
||||||
|
|
||||||
let internal_resolver = Arc::new(ResolverInternal {
|
let internal_resolver = Arc::new(ResolverInternal {
|
||||||
id_to_def: Mutex::default(),
|
id_to_def: Mutex::default(),
|
||||||
@ -519,7 +522,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
|
|||||||
)]
|
)]
|
||||||
fn test_analyze(source: &[&str], res: &[&str]) {
|
fn test_analyze(source: &[&str], res: &[&str]) {
|
||||||
let print = false;
|
let print = false;
|
||||||
let mut composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 64).0;
|
let mut composer =
|
||||||
|
TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0;
|
||||||
|
|
||||||
let internal_resolver = make_internal_resolver_with_tvar(
|
let internal_resolver = make_internal_resolver_with_tvar(
|
||||||
vec![
|
vec![
|
||||||
@ -696,7 +700,8 @@ fn test_analyze(source: &[&str], res: &[&str]) {
|
|||||||
)]
|
)]
|
||||||
fn test_inference(source: Vec<&str>, res: &[&str]) {
|
fn test_inference(source: Vec<&str>, res: &[&str]) {
|
||||||
let print = true;
|
let print = true;
|
||||||
let mut composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 64).0;
|
let mut composer =
|
||||||
|
TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0;
|
||||||
|
|
||||||
let internal_resolver = make_internal_resolver_with_tvar(
|
let internal_resolver = make_internal_resolver_with_tvar(
|
||||||
vec![
|
vec![
|
||||||
|
@ -212,19 +212,23 @@ impl<'a> Inferencer<'a> {
|
|||||||
/// This is a workaround preventing the caller from using a variable `alloca`-ed in the body, which
|
/// This is a workaround preventing the caller from using a variable `alloca`-ed in the body, which
|
||||||
/// is freed when the function returns.
|
/// is freed when the function returns.
|
||||||
fn check_return_value_ty(&mut self, ret_ty: Type) -> bool {
|
fn check_return_value_ty(&mut self, ret_ty: Type) -> bool {
|
||||||
match &*self.unifier.get_ty_immutable(ret_ty) {
|
if cfg!(feature = "no-escape-analysis") {
|
||||||
TypeEnum::TObj { .. } => [
|
true
|
||||||
self.primitives.int32,
|
} else {
|
||||||
self.primitives.int64,
|
match &*self.unifier.get_ty_immutable(ret_ty) {
|
||||||
self.primitives.uint32,
|
TypeEnum::TObj { .. } => [
|
||||||
self.primitives.uint64,
|
self.primitives.int32,
|
||||||
self.primitives.float,
|
self.primitives.int64,
|
||||||
self.primitives.bool,
|
self.primitives.uint32,
|
||||||
]
|
self.primitives.uint64,
|
||||||
.iter()
|
self.primitives.float,
|
||||||
.any(|allowed_ty| self.unifier.unioned(ret_ty, *allowed_ty)),
|
self.primitives.bool,
|
||||||
TypeEnum::TTuple { ty, .. } => ty.iter().all(|t| self.check_return_value_ty(*t)),
|
]
|
||||||
_ => false,
|
.iter()
|
||||||
|
.any(|allowed_ty| self.unifier.unioned(ret_ty, *allowed_ty)),
|
||||||
|
TypeEnum::TTuple { ty, .. } => ty.iter().all(|t| self.check_return_value_ty(*t)),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use std::cmp::max;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::convert::{From, TryInto};
|
use std::convert::{From, TryInto};
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
@ -11,6 +12,7 @@ use super::{
|
|||||||
RecordField, RecordKey, Type, TypeEnum, TypeVar, Unifier, VarMap,
|
RecordField, RecordKey, Type, TypeEnum, TypeVar, Unifier, VarMap,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use crate::toplevel::type_annotation::TypeAnnotation;
|
||||||
use crate::{
|
use crate::{
|
||||||
symbol_resolver::{SymbolResolver, SymbolValue},
|
symbol_resolver::{SymbolResolver, SymbolValue},
|
||||||
toplevel::{
|
toplevel::{
|
||||||
@ -1069,6 +1071,58 @@ impl<'a> Inferencer<'a> {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if id == &"len".into() && args.len() == 1 {
|
||||||
|
let obj = self.fold_expr(args.remove(0))?;
|
||||||
|
let obj_ty = obj.custom.unwrap();
|
||||||
|
|
||||||
|
match &*self.unifier.get_ty(obj_ty) {
|
||||||
|
TypeEnum::TObj { obj_id, .. }
|
||||||
|
if *obj_id == self.primitives.range.obj_id(self.unifier).unwrap() => {}
|
||||||
|
TypeEnum::TObj { obj_id, .. }
|
||||||
|
if *obj_id == self.primitives.list.obj_id(self.unifier).unwrap() => {}
|
||||||
|
TypeEnum::TObj { obj_id, .. }
|
||||||
|
if *obj_id == self.primitives.ndarray.obj_id(self.unifier).unwrap() => {}
|
||||||
|
TypeEnum::TTuple { .. } => {}
|
||||||
|
_ => {
|
||||||
|
return report_error(
|
||||||
|
format!(
|
||||||
|
"len() only accepts range, list, ndarray, or tuple. Got {}",
|
||||||
|
self.unifier.stringify(obj_ty)
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
obj.location,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret_ty = self.primitives.int32;
|
||||||
|
|
||||||
|
let func_ty = self.unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
||||||
|
args: vec![FuncArg {
|
||||||
|
name: "obj".into(),
|
||||||
|
ty: obj_ty,
|
||||||
|
default_value: None,
|
||||||
|
is_vararg: false,
|
||||||
|
}],
|
||||||
|
ret: ret_ty,
|
||||||
|
vars: VarMap::new(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
return Ok(Some(Located {
|
||||||
|
location,
|
||||||
|
custom: Some(ret_ty),
|
||||||
|
node: ExprKind::Call {
|
||||||
|
func: Box::new(Located {
|
||||||
|
custom: Some(func_ty),
|
||||||
|
location: func.location,
|
||||||
|
node: ExprKind::Name { id: *id, ctx: *ctx },
|
||||||
|
}),
|
||||||
|
args: vec![obj],
|
||||||
|
keywords: vec![],
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
if ["int32", "float", "bool", "round", "round64", "np_isnan", "np_isinf"]
|
if ["int32", "float", "bool", "round", "round64", "np_isnan", "np_isinf"]
|
||||||
.iter()
|
.iter()
|
||||||
.any(|fun_id| id == &(*fun_id).into())
|
.any(|fun_id| id == &(*fun_id).into())
|
||||||
@ -1560,17 +1614,18 @@ impl<'a> Inferencer<'a> {
|
|||||||
keywords.iter().find(|kwarg| kwarg.node.arg.is_some_and(|id| id == "ndmin".into()));
|
keywords.iter().find(|kwarg| kwarg.node.arg.is_some_and(|id| id == "ndmin".into()));
|
||||||
|
|
||||||
let ty = arraylike_flatten_element_type(self.unifier, arg0.custom.unwrap());
|
let ty = arraylike_flatten_element_type(self.unifier, arg0.custom.unwrap());
|
||||||
|
let arg0_ndims = arraylike_get_ndims(self.unifier, arg0.custom.unwrap());
|
||||||
let ndims = if let Some(ndmin_kw) = ndmin_kw {
|
let ndims = if let Some(ndmin_kw) = ndmin_kw {
|
||||||
match &ndmin_kw.node.value.node {
|
match &ndmin_kw.node.value.node {
|
||||||
ExprKind::Constant { value, .. } => match value {
|
ExprKind::Constant { value, .. } => match value {
|
||||||
ast::Constant::Int(value) => *value as u64,
|
ast::Constant::Int(value) => max(*value as u64, arg0_ndims),
|
||||||
_ => return Err(HashSet::from(["Expected uint64 for ndims".to_string()])),
|
_ => return Err(HashSet::from(["Expected uint64 for ndims".to_string()])),
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => arraylike_get_ndims(self.unifier, arg0.custom.unwrap()),
|
_ => arg0_ndims,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
arraylike_get_ndims(self.unifier, arg0.custom.unwrap())
|
arg0_ndims
|
||||||
};
|
};
|
||||||
let ndims = self.unifier.get_fresh_literal(vec![SymbolValue::U64(ndims)], None);
|
let ndims = self.unifier.get_fresh_literal(vec![SymbolValue::U64(ndims)], None);
|
||||||
let ret = make_ndarray_ty(self.unifier, self.primitives, Some(ty), Some(ndims));
|
let ret = make_ndarray_ty(self.unifier, self.primitives, Some(ty), Some(ndims));
|
||||||
@ -1618,6 +1673,86 @@ impl<'a> Inferencer<'a> {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_overriding(
|
||||||
|
&mut self,
|
||||||
|
func: &ast::Expr<()>,
|
||||||
|
args: &mut [ast::Expr<()>],
|
||||||
|
) -> Result<Option<(ast::Expr<()>, Type)>, InferenceError> {
|
||||||
|
// Allow Overriding
|
||||||
|
|
||||||
|
// Must have self as first input
|
||||||
|
if args.is_empty() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
if let Located { node: ExprKind::Name { id, .. }, .. } = &args[0] {
|
||||||
|
if *id != "self".into() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let Located {
|
||||||
|
node: ExprKind::Attribute { value, attr: method_name, ctx }, location, ..
|
||||||
|
} = func
|
||||||
|
else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
let ExprKind::Name { id: class_name, ctx: class_ctx } = &value.node else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Do not Remove self from args (will move it class name instead after activating necessary flags)
|
||||||
|
let zelf = &self.fold_expr(args[0].clone())?;
|
||||||
|
let def_id = self.unifier.get_ty(zelf.custom.unwrap());
|
||||||
|
let TypeEnum::TObj { obj_id, .. } = def_id.as_ref() else { unreachable!() };
|
||||||
|
let defs = self.top_level.definitions.read();
|
||||||
|
let res = {
|
||||||
|
if let TopLevelDef::Class { ancestors, .. } = &*defs[obj_id.0].read() {
|
||||||
|
let res = ancestors.iter().find_map(|f| {
|
||||||
|
let TypeAnnotation::CustomClass { id, .. } = f else { unreachable!() };
|
||||||
|
let TopLevelDef::Class { name, methods, .. } = &*defs[id.0].read() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let name = name.to_string();
|
||||||
|
let (_, name) = name.split_once('.').unwrap();
|
||||||
|
if name == class_name.to_string() {
|
||||||
|
return methods.iter().find_map(|f| {
|
||||||
|
if f.0 == *method_name {
|
||||||
|
return Some(*f);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None
|
||||||
|
});
|
||||||
|
res
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(f) = res {
|
||||||
|
if let TopLevelDef::Class { virtual_table, .. } = &mut *defs[obj_id.0].write() {
|
||||||
|
virtual_table.insert(f.0, (f.1, f.2));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return report_error(
|
||||||
|
format!("No such function found in parent class {}", method_name).as_str(),
|
||||||
|
*location,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// let Located { node: ExprKind::Attribute { value, attr: method_name, .. }, location, .. } = func
|
||||||
|
// Change the class name to self to refer to correct part of code
|
||||||
|
// let new_func = Located { node: ExprKind::Attribute { value, attr: method_name, ctx: () }, location, custom}
|
||||||
|
let mut new_func = func.clone();
|
||||||
|
let mut new_value = value.clone();
|
||||||
|
new_value.node = ExprKind::Name { id: "self".into(), ctx: *class_ctx };
|
||||||
|
new_func.node = ExprKind::Attribute { value: new_value, attr: *method_name, ctx: *ctx };
|
||||||
|
|
||||||
|
Ok(Some((new_func, res.unwrap().1)))
|
||||||
|
}
|
||||||
|
|
||||||
fn fold_call(
|
fn fold_call(
|
||||||
&mut self,
|
&mut self,
|
||||||
location: Location,
|
location: Location,
|
||||||
@ -1631,14 +1766,32 @@ impl<'a> Inferencer<'a> {
|
|||||||
return Ok(spec_call_func);
|
return Ok(spec_call_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut first_arg = None;
|
||||||
|
let mut is_override = false;
|
||||||
|
let mut func_sign_key = None;
|
||||||
|
let override_res = self.try_overriding(&func, &mut args)?;
|
||||||
|
let func = match override_res {
|
||||||
|
Some(res) => {
|
||||||
|
is_override = true;
|
||||||
|
func_sign_key = Some(res.1);
|
||||||
|
res.0
|
||||||
|
}
|
||||||
|
None => func,
|
||||||
|
};
|
||||||
|
|
||||||
let func = Box::new(self.fold_expr(func)?);
|
let func = Box::new(self.fold_expr(func)?);
|
||||||
let args = args.into_iter().map(|v| self.fold_expr(v)).collect::<Result<Vec<_>, _>>()?;
|
let mut args =
|
||||||
|
args.into_iter().map(|v| self.fold_expr(v)).collect::<Result<Vec<_>, _>>()?;
|
||||||
|
if is_override {
|
||||||
|
first_arg = Some(args.remove(0));
|
||||||
|
}
|
||||||
let keywords = keywords
|
let keywords = keywords
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|v| fold::fold_keyword(self, v))
|
.map(|v| fold::fold_keyword(self, v))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
if let TypeEnum::TFunc(sign) = &*self.unifier.get_ty(func.custom.unwrap()) {
|
let func_key = if is_override { func_sign_key.unwrap() } else { func.custom.unwrap() };
|
||||||
|
if let TypeEnum::TFunc(sign) = &*self.unifier.get_ty(func_key) {
|
||||||
if sign.vars.is_empty() {
|
if sign.vars.is_empty() {
|
||||||
let call = Call {
|
let call = Call {
|
||||||
posargs: args.iter().map(|v| v.custom.unwrap()).collect(),
|
posargs: args.iter().map(|v| v.custom.unwrap()).collect(),
|
||||||
@ -1651,9 +1804,15 @@ impl<'a> Inferencer<'a> {
|
|||||||
loc: Some(location),
|
loc: Some(location),
|
||||||
operator_info: None,
|
operator_info: None,
|
||||||
};
|
};
|
||||||
self.unifier.unify_call(&call, func.custom.unwrap(), sign).map_err(|e| {
|
self.unifier.unify_call(&call, func_key, sign).map_err(|e| {
|
||||||
HashSet::from([e.at(Some(location)).to_display(self.unifier).to_string()])
|
HashSet::from([e.at(Some(location)).to_display(self.unifier).to_string()])
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
// First parameter is self to indicate override
|
||||||
|
if let Some(mut arg) = first_arg {
|
||||||
|
arg.node = ExprKind::Name { id: "self".into(), ctx: ExprContext::Load };
|
||||||
|
args.insert(0, arg);
|
||||||
|
}
|
||||||
return Ok(Located {
|
return Ok(Located {
|
||||||
location,
|
location,
|
||||||
custom: Some(sign.ret),
|
custom: Some(sign.ret),
|
||||||
@ -1677,7 +1836,10 @@ impl<'a> Inferencer<'a> {
|
|||||||
self.calls.insert(location.into(), call);
|
self.calls.insert(location.into(), call);
|
||||||
let call = self.unifier.add_ty(TypeEnum::TCall(vec![call]));
|
let call = self.unifier.add_ty(TypeEnum::TCall(vec![call]));
|
||||||
self.unify(func.custom.unwrap(), call, &func.location)?;
|
self.unify(func.custom.unwrap(), call, &func.location)?;
|
||||||
|
println!("Here");
|
||||||
|
for k in keywords.iter() {
|
||||||
|
println!("keyword {}", k.node.value.node.name());
|
||||||
|
}
|
||||||
Ok(Located { location, custom: Some(ret), node: ExprKind::Call { func, args, keywords } })
|
Ok(Located { location, custom: Some(ret), node: ExprKind::Call { func, args, keywords } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,6 +328,7 @@ impl TestEnvironment {
|
|||||||
fields: Vec::default(),
|
fields: Vec::default(),
|
||||||
attributes: Vec::default(),
|
attributes: Vec::default(),
|
||||||
methods: Vec::default(),
|
methods: Vec::default(),
|
||||||
|
virtual_table: HashMap::default(),
|
||||||
ancestors: Vec::default(),
|
ancestors: Vec::default(),
|
||||||
resolver: None,
|
resolver: None,
|
||||||
constructor: None,
|
constructor: None,
|
||||||
@ -372,6 +373,7 @@ impl TestEnvironment {
|
|||||||
fields: [("a".into(), tvar.ty, true)].into(),
|
fields: [("a".into(), tvar.ty, true)].into(),
|
||||||
attributes: Vec::default(),
|
attributes: Vec::default(),
|
||||||
methods: Vec::default(),
|
methods: Vec::default(),
|
||||||
|
virtual_table: HashMap::default(),
|
||||||
ancestors: Vec::default(),
|
ancestors: Vec::default(),
|
||||||
resolver: None,
|
resolver: None,
|
||||||
constructor: None,
|
constructor: None,
|
||||||
@ -407,6 +409,7 @@ impl TestEnvironment {
|
|||||||
fields: [("a".into(), int32, true), ("b".into(), fun, true)].into(),
|
fields: [("a".into(), int32, true), ("b".into(), fun, true)].into(),
|
||||||
attributes: Vec::default(),
|
attributes: Vec::default(),
|
||||||
methods: Vec::default(),
|
methods: Vec::default(),
|
||||||
|
virtual_table: HashMap::default(),
|
||||||
ancestors: Vec::default(),
|
ancestors: Vec::default(),
|
||||||
resolver: None,
|
resolver: None,
|
||||||
constructor: None,
|
constructor: None,
|
||||||
@ -436,6 +439,7 @@ impl TestEnvironment {
|
|||||||
fields: [("a".into(), bool, true), ("b".into(), fun, false)].into(),
|
fields: [("a".into(), bool, true), ("b".into(), fun, false)].into(),
|
||||||
attributes: Vec::default(),
|
attributes: Vec::default(),
|
||||||
methods: Vec::default(),
|
methods: Vec::default(),
|
||||||
|
virtual_table: HashMap::default(),
|
||||||
ancestors: Vec::default(),
|
ancestors: Vec::default(),
|
||||||
resolver: None,
|
resolver: None,
|
||||||
constructor: None,
|
constructor: None,
|
||||||
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
|||||||
authors = ["M-Labs"]
|
authors = ["M-Labs"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
no-escape-analysis = ["nac3core/no-escape-analysis"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
nac3parser = { path = "../nac3parser" }
|
nac3parser = { path = "../nac3parser" }
|
||||||
|
@ -8,12 +8,15 @@ if [ -z "$1" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
declare -a nac3args
|
declare -a nac3args
|
||||||
while [ $# -ge 2 ]; do
|
while [ $# -gt 1 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--help)
|
--help)
|
||||||
echo "Usage: check_demo.sh [-i686] -- demo [NAC3ARGS...]"
|
echo "Usage: check_demo.sh [--debug] [-i686] -- [NAC3ARGS...] demo"
|
||||||
exit
|
exit
|
||||||
;;
|
;;
|
||||||
|
--debug)
|
||||||
|
debug=1
|
||||||
|
;;
|
||||||
-i686)
|
-i686)
|
||||||
i686=1
|
i686=1
|
||||||
;;
|
;;
|
||||||
@ -22,18 +25,18 @@ while [ $# -ge 2 ]; do
|
|||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
break
|
echo "Unrecognized argument \"$1\""
|
||||||
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
demo="$1"
|
|
||||||
shift
|
|
||||||
while [ $# -gt 1 ]; do
|
while [ $# -gt 1 ]; do
|
||||||
nac3args+=("$1")
|
nac3args+=("$1")
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
demo="$1"
|
||||||
|
|
||||||
|
|
||||||
echo "### Checking $demo..."
|
echo "### Checking $demo..."
|
||||||
@ -43,12 +46,20 @@ echo ">>>>>> Running $demo with the Python interpreter"
|
|||||||
|
|
||||||
if [ -n "$i686" ]; then
|
if [ -n "$i686" ]; then
|
||||||
echo "...... Trying NAC3's 32-bit code generator output"
|
echo "...... Trying NAC3's 32-bit code generator output"
|
||||||
./run_demo.sh -i686 --out run_32.log "${nac3args[@]}" "$demo"
|
if [ -n "$debug" ]; then
|
||||||
|
./run_demo.sh --debug -i686 --out run_32.log -- "${nac3args[@]}" "$demo"
|
||||||
|
else
|
||||||
|
./run_demo.sh -i686 --out run_32.log -- "${nac3args[@]}" "$demo"
|
||||||
|
fi
|
||||||
diff -Nau interpreted.log run_32.log
|
diff -Nau interpreted.log run_32.log
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "...... Trying NAC3's 64-bit code generator output"
|
echo "...... Trying NAC3's 64-bit code generator output"
|
||||||
./run_demo.sh --out run_64.log "${nac3args[@]}" "$demo"
|
if [ -n "$debug" ]; then
|
||||||
|
./run_demo.sh --debug --out run_64.log -- "${nac3args[@]}" "$demo"
|
||||||
|
else
|
||||||
|
./run_demo.sh --out run_64.log -- "${nac3args[@]}" "$demo"
|
||||||
|
fi
|
||||||
diff -Nau interpreted.log run_64.log
|
diff -Nau interpreted.log run_64.log
|
||||||
|
|
||||||
echo "...... OK"
|
echo "...... OK"
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
if [ "$1" == "--help" ]; then
|
||||||
|
echo "Usage: check_demos.sh [CHECKARGS...] [--] [NAC3ARGS...]"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
count=0
|
count=0
|
||||||
for demo in src/*.py; do
|
for demo in src/*.py; do
|
||||||
./check_demo.sh "$@" "$demo"
|
./check_demo.sh "$@" "$demo"
|
||||||
|
3
nac3standalone/demo/interpreted.log
Normal file
3
nac3standalone/demo/interpreted.log
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
12
|
||||||
|
12
|
||||||
|
17
|
3
nac3standalone/demo/run_64.log
Normal file
3
nac3standalone/demo/run_64.log
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
12
|
||||||
|
12
|
||||||
|
15
|
@ -14,7 +14,7 @@ declare -a nac3args
|
|||||||
while [ $# -ge 1 ]; do
|
while [ $# -ge 1 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--help)
|
--help)
|
||||||
echo "Usage: run_demo.sh [--help] [--out OUTFILE] [--debug] [-i686] -- [NAC3ARGS...]"
|
echo "Usage: run_demo.sh [--help] [--out OUTFILE] [--debug] [-i686] -- [NAC3ARGS...] demo"
|
||||||
exit
|
exit
|
||||||
;;
|
;;
|
||||||
--out)
|
--out)
|
||||||
@ -32,7 +32,8 @@ while [ $# -ge 1 ]; do
|
|||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
break
|
echo "Unrecognized argument \"$1\""
|
||||||
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
shift
|
shift
|
||||||
@ -59,7 +60,7 @@ if [ -z "$i686" ]; then
|
|||||||
clang -c -std=gnu11 -Wall -Wextra -O3 -o demo.o demo.c
|
clang -c -std=gnu11 -Wall -Wextra -O3 -o demo.o demo.c
|
||||||
clang -o demo module.o demo.o $DEMO_LINALG_STUB -lm -Wl,--no-warn-search-mismatch
|
clang -o demo module.o demo.o $DEMO_LINALG_STUB -lm -Wl,--no-warn-search-mismatch
|
||||||
else
|
else
|
||||||
$nac3standalone --triple i686-unknown-linux-gnu "${nac3args[@]}"
|
$nac3standalone --triple i686-unknown-linux-gnu --target-features +sse2 "${nac3args[@]}"
|
||||||
clang -m32 -c -std=gnu11 -Wall -Wextra -O3 -msse2 -o demo.o demo.c
|
clang -m32 -c -std=gnu11 -Wall -Wextra -O3 -msse2 -o demo.o demo.c
|
||||||
clang -m32 -o demo module.o demo.o $DEMO_LINALG_STUB32 -lm -Wl,--no-warn-search-mismatch
|
clang -m32 -o demo module.o demo.o $DEMO_LINALG_STUB32 -lm -Wl,--no-warn-search-mismatch
|
||||||
fi
|
fi
|
||||||
|
@ -6,27 +6,44 @@ def output_int32(x: int32):
|
|||||||
|
|
||||||
class A:
|
class A:
|
||||||
a: int32
|
a: int32
|
||||||
|
|
||||||
def __init__(self, a: int32):
|
def __init__(self, param_a: int32):
|
||||||
self.a = a
|
self.a = param_a
|
||||||
|
|
||||||
def f1(self):
|
def f1(self):
|
||||||
self.f2()
|
output_int32(12)
|
||||||
|
|
||||||
def f2(self):
|
|
||||||
output_int32(self.a)
|
|
||||||
|
|
||||||
class B(A):
|
class B(A):
|
||||||
b: int32
|
b: int32
|
||||||
|
|
||||||
def __init__(self, b: int32):
|
def __init__(self, param_a: int32, param_b: int32):
|
||||||
self.a = b + 1
|
self.a = param_a
|
||||||
|
self.b = param_b
|
||||||
|
|
||||||
|
def f1(self):
|
||||||
|
output_int32(15)
|
||||||
|
|
||||||
|
def f2(self):
|
||||||
|
A.f1(self)
|
||||||
|
self.f1()
|
||||||
|
|
||||||
|
class C(B):
|
||||||
|
def __init__(self, a: int32, b: int32):
|
||||||
|
self.a = a
|
||||||
self.b = b
|
self.b = b
|
||||||
|
|
||||||
|
def f1(self):
|
||||||
|
output_int32(17)
|
||||||
|
|
||||||
|
def f3(self):
|
||||||
|
B.f2(self)
|
||||||
|
|
||||||
|
def f4(self):
|
||||||
|
A.f1(self)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def run() -> int32:
|
def run() -> int32:
|
||||||
aaa = A(5)
|
c = B(1, 2)
|
||||||
bbb = B(2)
|
c.f2()
|
||||||
aaa.f1()
|
|
||||||
bbb.f1()
|
|
||||||
return 0
|
return 0
|
||||||
|
@ -25,5 +25,12 @@ def run() -> int32:
|
|||||||
output_int32(tl[0][0])
|
output_int32(tl[0][0])
|
||||||
output_int32(tl[0][1])
|
output_int32(tl[0][1])
|
||||||
output_int32(tl[1])
|
output_int32(tl[1])
|
||||||
|
|
||||||
|
output_int32(len(()))
|
||||||
|
output_int32(len((1,)))
|
||||||
|
output_int32(len((1, 2)))
|
||||||
|
output_int32(len((1, 2, 3)))
|
||||||
|
output_int32(len((1, 2, 3, 4)))
|
||||||
|
output_int32(len((1, 2, 3, 4, 5)))
|
||||||
|
|
||||||
return 0
|
return 0
|
@ -301,7 +301,7 @@ fn main() {
|
|||||||
|
|
||||||
let primitive: PrimitiveStore = TopLevelComposer::make_primitives(size_t).0;
|
let primitive: PrimitiveStore = TopLevelComposer::make_primitives(size_t).0;
|
||||||
let (mut composer, builtins_def, builtins_ty) =
|
let (mut composer, builtins_def, builtins_ty) =
|
||||||
TopLevelComposer::new(vec![], ComposerConfig::default(), size_t);
|
TopLevelComposer::new(vec![], vec![], ComposerConfig::default(), size_t);
|
||||||
|
|
||||||
let internal_resolver: Arc<ResolverInternal> = ResolverInternal {
|
let internal_resolver: Arc<ResolverInternal> = ResolverInternal {
|
||||||
id_to_type: builtins_ty.into(),
|
id_to_type: builtins_ty.into(),
|
||||||
|
Loading…
Reference in New Issue
Block a user