forked from M-Labs/nac3
core: irrt ErrorContext
This commit is contained in:
parent
9e78139373
commit
8863cd64a9
|
@ -163,7 +163,10 @@
|
||||||
clippy
|
clippy
|
||||||
pre-commit
|
pre-commit
|
||||||
rustfmt
|
rustfmt
|
||||||
|
rust-analyzer
|
||||||
];
|
];
|
||||||
|
# https://nixos.wiki/wiki/Rust#Shell.nix_example
|
||||||
|
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
|
||||||
};
|
};
|
||||||
devShells.x86_64-linux.msys2 = pkgs.mkShell {
|
devShells.x86_64-linux.msys2 = pkgs.mkShell {
|
||||||
name = "nac3-dev-shell-msys2";
|
name = "nac3-dev-shell-msys2";
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "int_defs.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// nac3core's "str" struct type definition
|
||||||
|
template <typename SizeT>
|
||||||
|
struct Str {
|
||||||
|
const char* content;
|
||||||
|
SizeT length;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ErrorContext {
|
||||||
|
const char* message_template; // MUST BE `&'static`
|
||||||
|
uint64_t param1;
|
||||||
|
uint64_t param2;
|
||||||
|
uint64_t param3;
|
||||||
|
|
||||||
|
void initialize() {
|
||||||
|
clear_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_error() {
|
||||||
|
// Point the message_template to an empty str. Don't set it to nullptr as a sentinel
|
||||||
|
set_error("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_error(const char* message, uint64_t param1 = 0, uint64_t param2 = 0, uint64_t param3 = 0) {
|
||||||
|
this->message_template = message;
|
||||||
|
this->param1 = param1;
|
||||||
|
this->param2 = param2;
|
||||||
|
this->param3 = param3;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_error() {
|
||||||
|
return !cstr_utils::is_empty(message_template);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename SizeT>
|
||||||
|
void set_error_str(Str<SizeT> *dst_str) {
|
||||||
|
dst_str->content = message_template;
|
||||||
|
dst_str->length = (SizeT) cstr_utils::length(message_template);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
void __nac3_error_context_initialize(ErrorContext* errctx) {
|
||||||
|
errctx->initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t __nac3_error_context_has_no_error(ErrorContext* errctx) {
|
||||||
|
return !errctx->has_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __nac3_error_context_get_error_str(ErrorContext* errctx, Str<int32_t> *dst_str) {
|
||||||
|
errctx->set_error_str<int32_t>(dst_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __nac3_error_context_get_error_str64(ErrorContext* errctx, Str<int64_t> *dst_str) {
|
||||||
|
errctx->set_error_str<int64_t>(dst_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __nac3_error_dummy_raise(ErrorContext* errctx) {
|
||||||
|
errctx->set_error("THROWN FROM __nac3_error_dummy_raise!!!!!!");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "int_defs.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
namespace string {
|
||||||
|
bool is_empty(const char* str) {
|
||||||
|
return str[0] == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t compare(const char* a, const char* b) {
|
||||||
|
uint32_t i = 0;
|
||||||
|
while (true) {
|
||||||
|
if (a[i] < b[i]) {
|
||||||
|
return -1;
|
||||||
|
} else if (a[i] > b[i]) {
|
||||||
|
return 1;
|
||||||
|
} else { // a[i] == b[i]
|
||||||
|
if (a[i] == '\0') {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t equal(const char* a, const char* b) {
|
||||||
|
return compare(a, b) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t length(const char* str) {
|
||||||
|
uint32_t length = 0;
|
||||||
|
while (*str != '\0') {
|
||||||
|
length++;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool copy(const char* src, char* dst, uint32_t dst_max_size) {
|
||||||
|
for (uint32_t i = 0; i < dst_max_size; i++) {
|
||||||
|
bool is_last = i + 1 == dst_max_size;
|
||||||
|
if (is_last && src[i] != '\0') {
|
||||||
|
dst[i] = '\0';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src[i] == '\0') {
|
||||||
|
dst[i] = '\0';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst[i] = src[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "int_defs.hpp"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const T& max(const T& a, const T& b) {
|
const T& max(const T& a, const T& b) {
|
||||||
|
@ -18,4 +20,69 @@ bool arrays_match(int len, T* as, T* bs) {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
uint32_t int_log_floor(T value, T base) {
|
||||||
|
uint32_t result = 0;
|
||||||
|
while (value >= base) {
|
||||||
|
result++;
|
||||||
|
value /= base;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace cstr_utils {
|
||||||
|
bool is_empty(const char* str) {
|
||||||
|
return str[0] == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t compare(const char* a, const char* b) {
|
||||||
|
uint32_t i = 0;
|
||||||
|
while (true) {
|
||||||
|
if (a[i] < b[i]) {
|
||||||
|
return -1;
|
||||||
|
} else if (a[i] > b[i]) {
|
||||||
|
return 1;
|
||||||
|
} else { // a[i] == b[i]
|
||||||
|
if (a[i] == '\0') {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t equal(const char* a, const char* b) {
|
||||||
|
return compare(a, b) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t length(const char* str) {
|
||||||
|
uint32_t length = 0;
|
||||||
|
while (*str != '\0') {
|
||||||
|
length++;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool copy(const char* src, char* dst, uint32_t dst_max_size) {
|
||||||
|
for (uint32_t i = 0; i < dst_max_size; i++) {
|
||||||
|
bool is_last = i + 1 == dst_max_size;
|
||||||
|
if (is_last && src[i] != '\0') {
|
||||||
|
dst[i] = '\0';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src[i] == '\0') {
|
||||||
|
dst[i] = '\0';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst[i] = src[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include "irrt/core.hpp"
|
#include "irrt/core.hpp"
|
||||||
|
#include "irrt/error_context.hpp"
|
||||||
#include "irrt/int_defs.hpp"
|
#include "irrt/int_defs.hpp"
|
||||||
#include "irrt/utils.hpp"
|
#include "irrt/utils.hpp"
|
|
@ -9,8 +9,11 @@
|
||||||
|
|
||||||
#include "test/core.hpp"
|
#include "test/core.hpp"
|
||||||
#include "test/test_core.hpp"
|
#include "test/test_core.hpp"
|
||||||
|
#include "test/test_utils.hpp"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
test_int_exp();
|
run_test_core();
|
||||||
|
run_test_print();
|
||||||
|
run_test_utils();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -4,39 +4,39 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void print_value(const T& value) {}
|
void print_value(T value);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void print_value(const int8_t& value) {
|
void print_value(char value) {
|
||||||
|
printf("'%c' (ord=%d)", value, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void print_value(int8_t value) {
|
||||||
printf("%d", value);
|
printf("%d", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void print_value(const int32_t& value) {
|
void print_value(int32_t value) {
|
||||||
printf("%d", value);
|
printf("%d", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void print_value(const uint8_t& value) {
|
void print_value(uint8_t value) {
|
||||||
printf("%u", value);
|
printf("%u", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void print_value(const uint32_t& value) {
|
void print_value(uint32_t value) {
|
||||||
printf("%u", value);
|
printf("%u", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void print_value(const double& value) {
|
void print_value(double value) {
|
||||||
printf("%f", value);
|
printf("%f", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// template <double>
|
template <>
|
||||||
// void print_value(const double& value) {
|
void print_value(char* value) {
|
||||||
// printf("%f", value);
|
printf("%s", value);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// template <char *>
|
|
||||||
// void print_value(const char*& value) {
|
|
||||||
// printf("%f", value);
|
|
||||||
// }
|
|
|
@ -8,4 +8,8 @@ void test_int_exp() {
|
||||||
|
|
||||||
assert_values_match(125, __nac3_int_exp_impl<int32_t>(5, 3));
|
assert_values_match(125, __nac3_int_exp_impl<int32_t>(5, 3));
|
||||||
assert_values_match(3125, __nac3_int_exp_impl<int32_t>(5, 5));
|
assert_values_match(3125, __nac3_int_exp_impl<int32_t>(5, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_test_core() {
|
||||||
|
test_int_exp();
|
||||||
}
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core.hpp"
|
||||||
|
#include "../irrt/utils.hpp"
|
||||||
|
|
||||||
|
void test_int_log_10() {
|
||||||
|
BEGIN_TEST();
|
||||||
|
|
||||||
|
assert_values_match((uint32_t) 0, int_log_floor(0, 10));
|
||||||
|
assert_values_match((uint32_t) 0, int_log_floor(9, 10));
|
||||||
|
assert_values_match((uint32_t) 1, int_log_floor(10, 10));
|
||||||
|
assert_values_match((uint32_t) 1, int_log_floor(11, 10));
|
||||||
|
assert_values_match((uint32_t) 1, int_log_floor(99, 10));
|
||||||
|
assert_values_match((uint32_t) 2, int_log_floor(100, 10));
|
||||||
|
assert_values_match((uint32_t) 2, int_log_floor(101, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_cstr_utils() {
|
||||||
|
BEGIN_TEST();
|
||||||
|
|
||||||
|
assert_values_match((uint32_t) 42, (uint32_t) cstr_utils::length("THROWN FROM __nac3_error_dummy_raise!!!!!!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_test_utils() {
|
||||||
|
test_int_log_10();
|
||||||
|
test_cstr_utils();
|
||||||
|
}
|
|
@ -1,10 +1,32 @@
|
||||||
use inkwell::types::{BasicTypeEnum, IntType};
|
use inkwell::types::{BasicTypeEnum, IntType};
|
||||||
|
|
||||||
use crate::codegen::optics::{AddressLens, GepGetter, IntLens, StructureOptic};
|
use crate::codegen::optics::{AddressLens, FieldBuilder, GepGetter, IntLens, StructureOptic};
|
||||||
|
|
||||||
// use crate::codegen::structure::{
|
#[derive(Debug, Clone)]
|
||||||
// FieldLensBuilder, IntLens, LensWithFieldInfo, PointerLens, StructFieldLens,
|
pub struct StrLens<'ctx> {
|
||||||
// };
|
pub size_type: IntType<'ctx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: nac3core has hardcoded a lot of "str"
|
||||||
|
pub struct StrFields<'ctx> {
|
||||||
|
pub content: GepGetter<AddressLens<IntLens<'ctx>>>,
|
||||||
|
pub length: GepGetter<IntLens<'ctx>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructureOptic<'ctx> for StrLens<'ctx> {
|
||||||
|
type Fields = StrFields<'ctx>;
|
||||||
|
|
||||||
|
fn struct_name(&self) -> &'static str {
|
||||||
|
"str"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields {
|
||||||
|
StrFields {
|
||||||
|
content: builder.add_field("content", AddressLens(IntLens(builder.ctx.i8_type()))),
|
||||||
|
length: builder.add_field("length", IntLens(self.size_type)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct NpArrayFields<'ctx> {
|
pub struct NpArrayFields<'ctx> {
|
||||||
pub data: GepGetter<AddressLens<IntLens<'ctx>>>,
|
pub data: GepGetter<AddressLens<IntLens<'ctx>>>,
|
||||||
|
@ -54,7 +76,7 @@ impl<'ctx> StructureOptic<'ctx> for IrrtStringLens {
|
||||||
type Fields = IrrtStringFields<'ctx>;
|
type Fields = IrrtStringFields<'ctx>;
|
||||||
|
|
||||||
fn struct_name(&self) -> &'static str {
|
fn struct_name(&self) -> &'static str {
|
||||||
todo!()
|
"String"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_fields(
|
fn build_fields(
|
||||||
|
@ -71,15 +93,18 @@ impl<'ctx> StructureOptic<'ctx> for IrrtStringLens {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ErrorContextFields {
|
pub struct ErrorContextFields<'ctx> {
|
||||||
pub message: GepGetter<IrrtStringLens>,
|
pub message_template: GepGetter<AddressLens<IntLens<'ctx>>>,
|
||||||
|
pub param1: GepGetter<IntLens<'ctx>>,
|
||||||
|
pub param2: GepGetter<IntLens<'ctx>>,
|
||||||
|
pub param3: GepGetter<IntLens<'ctx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct ErrorContextLens;
|
pub struct ErrorContextLens;
|
||||||
|
|
||||||
impl<'ctx> StructureOptic<'ctx> for ErrorContextLens {
|
impl<'ctx> StructureOptic<'ctx> for ErrorContextLens {
|
||||||
type Fields = ErrorContextFields;
|
type Fields = ErrorContextFields<'ctx>;
|
||||||
|
|
||||||
fn struct_name(&self) -> &'static str {
|
fn struct_name(&self) -> &'static str {
|
||||||
"ErrorContext"
|
"ErrorContext"
|
||||||
|
@ -89,6 +114,12 @@ impl<'ctx> StructureOptic<'ctx> for ErrorContextLens {
|
||||||
&self,
|
&self,
|
||||||
builder: &mut crate::codegen::optics::FieldBuilder<'ctx>,
|
builder: &mut crate::codegen::optics::FieldBuilder<'ctx>,
|
||||||
) -> Self::Fields {
|
) -> Self::Fields {
|
||||||
ErrorContextFields { message: builder.add_field("message", IrrtStringLens) }
|
ErrorContextFields {
|
||||||
|
message_template: builder
|
||||||
|
.add_field("message_template", AddressLens(IntLens(builder.ctx.i8_type()))),
|
||||||
|
param1: builder.add_field("param1", IntLens(builder.ctx.i64_type())),
|
||||||
|
param2: builder.add_field("param2", IntLens(builder.ctx.i64_type())),
|
||||||
|
param3: builder.add_field("param3", IntLens(builder.ctx.i64_type())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,9 @@ use inkwell::{
|
||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
use nac3parser::ast::Expr;
|
use nac3parser::ast::Expr;
|
||||||
|
|
||||||
|
pub mod classes;
|
||||||
|
pub mod new;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn load_irrt(ctx: &Context) -> Module {
|
pub fn load_irrt(ctx: &Context) -> Module {
|
||||||
let bitcode_buf = MemoryBuffer::create_from_memory_range(
|
let bitcode_buf = MemoryBuffer::create_from_memory_range(
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
use inkwell::{
|
||||||
|
types::{BasicMetadataTypeEnum, BasicType, IntType},
|
||||||
|
values::{AnyValue, BasicMetadataValueEnum, IntValue},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
codegen::{
|
||||||
|
optics::{Address, AddressLens, IntLens, Optic, OpticValue, Prism},
|
||||||
|
CodeGenContext, CodeGenerator,
|
||||||
|
},
|
||||||
|
util::SizeVariant,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::classes::{ErrorContextLens, StrLens};
|
||||||
|
|
||||||
|
fn get_size_variant(ty: IntType) -> SizeVariant {
|
||||||
|
match ty.get_bit_width() {
|
||||||
|
32 => SizeVariant::Bits32,
|
||||||
|
64 => SizeVariant::Bits64,
|
||||||
|
_ => unreachable!("Unsupported int type bit width {}", ty.get_bit_width()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_sized_dependent_function_name(ty: IntType, fn_name: &str) -> String {
|
||||||
|
let mut fn_name = fn_name.to_owned();
|
||||||
|
match get_size_variant(ty) {
|
||||||
|
SizeVariant::Bits32 => {
|
||||||
|
// Do nothing, `fn_name` already has the correct name
|
||||||
|
}
|
||||||
|
SizeVariant::Bits64 => {
|
||||||
|
// Append "64", this is the naming convention
|
||||||
|
fn_name.push_str("64");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn_name
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Variadic argument?
|
||||||
|
pub struct FunctionBuilder<'ctx, 'a> {
|
||||||
|
ctx: &'a CodeGenContext<'ctx, 'a>,
|
||||||
|
fn_name: &'a str,
|
||||||
|
arguments: Vec<(BasicMetadataTypeEnum<'ctx>, BasicMetadataValueEnum<'ctx>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, 'a> FunctionBuilder<'ctx, 'a> {
|
||||||
|
pub fn begin(ctx: &'a CodeGenContext<'ctx, 'a>, fn_name: &'a str) -> Self {
|
||||||
|
FunctionBuilder { ctx, fn_name, arguments: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// The name is for self-documentation
|
||||||
|
#[must_use]
|
||||||
|
pub fn arg<S: Optic<'ctx>>(mut self, _name: &'static str, optic: &S, arg: &S::Value) -> Self {
|
||||||
|
self.arguments
|
||||||
|
.push((optic.get_llvm_type(self.ctx.ctx).into(), arg.get_llvm_value().into()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn returning<S: Prism<'ctx>>(self, name: &'static str, return_prism: &S) -> S::Value {
|
||||||
|
let (param_tys, param_vals): (Vec<_>, Vec<_>) = self.arguments.into_iter().unzip();
|
||||||
|
|
||||||
|
let function = self.ctx.module.get_function(self.fn_name).unwrap_or_else(|| {
|
||||||
|
let return_type = return_prism.get_llvm_type(self.ctx.ctx);
|
||||||
|
let fn_type = return_type.fn_type(¶m_tys, false);
|
||||||
|
self.ctx.module.add_function(self.fn_name, fn_type, None)
|
||||||
|
});
|
||||||
|
|
||||||
|
let ret = self.ctx.builder.build_call(function, ¶m_vals, name).unwrap();
|
||||||
|
return_prism.review(ret.as_any_value_enum())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Code duplication, but otherwise returning<S: Optic<'ctx>> cannot resolve S if return_optic = None
|
||||||
|
pub fn returning_void(self) {
|
||||||
|
let (param_tys, param_vals): (Vec<_>, Vec<_>) = self.arguments.into_iter().unzip();
|
||||||
|
|
||||||
|
let function = self.ctx.module.get_function(self.fn_name).unwrap_or_else(|| {
|
||||||
|
let return_type = self.ctx.ctx.void_type();
|
||||||
|
let fn_type = return_type.fn_type(¶m_tys, false);
|
||||||
|
self.ctx.module.add_function(self.fn_name, fn_type, None)
|
||||||
|
});
|
||||||
|
|
||||||
|
self.ctx.builder.build_call(function, ¶m_vals, "").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_nac3_error_context_initialize<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
errctx: &Address<'ctx, ErrorContextLens>,
|
||||||
|
) {
|
||||||
|
FunctionBuilder::begin(ctx, "__nac3_error_context_initialize")
|
||||||
|
.arg("errctx", &AddressLens(ErrorContextLens), errctx)
|
||||||
|
.returning_void();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_nac3_error_context_has_no_error<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
errctx: &Address<'ctx, ErrorContextLens>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
FunctionBuilder::begin(ctx, "__nac3_error_context_has_no_error")
|
||||||
|
.arg("errctx", &AddressLens(ErrorContextLens), errctx)
|
||||||
|
.returning("has_error", &IntLens(ctx.ctx.bool_type()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_nac3_error_context_get_error_str<'ctx>(
|
||||||
|
size_type: IntType<'ctx>,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
errctx: &Address<'ctx, ErrorContextLens>,
|
||||||
|
dst_str: &Address<'ctx, StrLens<'ctx>>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
FunctionBuilder::begin(
|
||||||
|
ctx,
|
||||||
|
&get_sized_dependent_function_name(size_type, "__nac3_error_context_get_error_str"),
|
||||||
|
)
|
||||||
|
.arg("errctx", &AddressLens(ErrorContextLens), errctx)
|
||||||
|
.arg("dst_str", &AddressLens(StrLens { size_type }), dst_str)
|
||||||
|
.returning("has_error", &IntLens(ctx.ctx.bool_type()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_nac3_dummy_raise<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
errctx: &Address<'ctx, ErrorContextLens>,
|
||||||
|
) {
|
||||||
|
FunctionBuilder::begin(ctx, "__nac3_error_dummy_raise")
|
||||||
|
.arg("errctx", &AddressLens(ErrorContextLens), errctx)
|
||||||
|
.returning_void();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn test_dummy_raise<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'_, '_>,
|
||||||
|
) {
|
||||||
|
let size_type = generator.get_size_type(ctx.ctx);
|
||||||
|
|
||||||
|
let errctx_ptr = ErrorContextLens.alloca(ctx, "errctx");
|
||||||
|
|
||||||
|
call_nac3_error_context_initialize(ctx, &errctx_ptr);
|
||||||
|
call_nac3_dummy_raise(ctx, &errctx_ptr);
|
||||||
|
|
||||||
|
let has_error = call_nac3_error_context_has_no_error(ctx, &errctx_ptr);
|
||||||
|
let error_str_ptr = StrLens { size_type }.alloca(ctx, "error_str");
|
||||||
|
call_nac3_error_context_get_error_str(size_type, ctx, &errctx_ptr, &error_str_ptr);
|
||||||
|
|
||||||
|
let error_str = error_str_ptr.load(ctx, "error_str");
|
||||||
|
let param1 = errctx_ptr.view(ctx, |fields| &fields.param1).load(ctx, "param1");
|
||||||
|
let param2 = errctx_ptr.view(ctx, |fields| &fields.param2).load(ctx, "param2");
|
||||||
|
let param3 = errctx_ptr.view(ctx, |fields| &fields.param3).load(ctx, "param3");
|
||||||
|
ctx.make_assert_impl(
|
||||||
|
generator,
|
||||||
|
has_error,
|
||||||
|
"0:RuntimeError", // TODO: Make this dynamic (within IRRT), but this is probably not trivial
|
||||||
|
error_str.get_llvm_value(),
|
||||||
|
[Some(param1), Some(param2), Some(param3)],
|
||||||
|
ctx.current_loc,
|
||||||
|
);
|
||||||
|
}
|
|
@ -11,7 +11,6 @@ mod tests {
|
||||||
|
|
||||||
let irrt_test_out_path = Path::new(concat!(env!("OUT_DIR"), "/irrt_test.out"));
|
let irrt_test_out_path = Path::new(concat!(env!("OUT_DIR"), "/irrt_test.out"));
|
||||||
let output = Command::new(irrt_test_out_path.to_str().unwrap()).output().unwrap();
|
let output = Command::new(irrt_test_out_path.to_str().unwrap()).output().unwrap();
|
||||||
|
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
eprintln!("irrt_test failed with status {}:", output.status);
|
eprintln!("irrt_test failed with status {}:", output.status);
|
||||||
eprintln!("====== stdout ======");
|
eprintln!("====== stdout ======");
|
||||||
|
|
|
@ -23,8 +23,10 @@ use inkwell::{
|
||||||
values::{BasicValueEnum, FunctionValue, IntValue, PhiValue, PointerValue},
|
values::{BasicValueEnum, FunctionValue, IntValue, PhiValue, PointerValue},
|
||||||
AddressSpace, IntPredicate, OptimizationLevel,
|
AddressSpace, IntPredicate, OptimizationLevel,
|
||||||
};
|
};
|
||||||
|
use irrt::classes::StrLens;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nac3parser::ast::{Location, Stmt, StrRef};
|
use nac3parser::ast::{Location, Stmt, StrRef};
|
||||||
|
use optics::Optic;
|
||||||
use parking_lot::{Condvar, Mutex};
|
use parking_lot::{Condvar, Mutex};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
|
@ -647,6 +649,8 @@ pub fn gen_func_impl<
|
||||||
..primitives
|
..primitives
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let llvm_str_ty =
|
||||||
|
StrLens { size_type: generator.get_size_type(context) }.get_llvm_type(context);
|
||||||
let mut type_cache: HashMap<_, _> = [
|
let mut type_cache: HashMap<_, _> = [
|
||||||
(primitives.int32, context.i32_type().into()),
|
(primitives.int32, context.i32_type().into()),
|
||||||
(primitives.int64, context.i64_type().into()),
|
(primitives.int64, context.i64_type().into()),
|
||||||
|
@ -654,21 +658,7 @@ pub fn gen_func_impl<
|
||||||
(primitives.uint64, context.i64_type().into()),
|
(primitives.uint64, context.i64_type().into()),
|
||||||
(primitives.float, context.f64_type().into()),
|
(primitives.float, context.f64_type().into()),
|
||||||
(primitives.bool, context.i8_type().into()),
|
(primitives.bool, context.i8_type().into()),
|
||||||
(primitives.str, {
|
(primitives.str, llvm_str_ty),
|
||||||
let name = "str";
|
|
||||||
match module.get_struct_type(name) {
|
|
||||||
None => {
|
|
||||||
let str_type = context.opaque_struct_type("str");
|
|
||||||
let fields = [
|
|
||||||
context.i8_type().ptr_type(AddressSpace::default()).into(),
|
|
||||||
generator.get_size_type(context).into(),
|
|
||||||
];
|
|
||||||
str_type.set_body(&fields, false);
|
|
||||||
str_type.into()
|
|
||||||
}
|
|
||||||
Some(t) => t.as_basic_type_enum(),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
(primitives.range, RangeType::new(context).as_base_type().into()),
|
(primitives.range, RangeType::new(context).as_base_type().into()),
|
||||||
(primitives.exception, {
|
(primitives.exception, {
|
||||||
let name = "Exception";
|
let name = "Exception";
|
||||||
|
@ -678,7 +668,7 @@ pub fn gen_func_impl<
|
||||||
let exception = context.opaque_struct_type("Exception");
|
let exception = context.opaque_struct_type("Exception");
|
||||||
let int32 = context.i32_type().into();
|
let int32 = context.i32_type().into();
|
||||||
let int64 = context.i64_type().into();
|
let int64 = context.i64_type().into();
|
||||||
let str_ty = module.get_struct_type("str").unwrap().as_basic_type_enum();
|
let str_ty = llvm_str_ty;
|
||||||
let fields = [int32, str_ty, int32, int32, str_ty, str_ty, int64, int64, int64];
|
let fields = [int32, str_ty, int32, int32, str_ty, str_ty, int64, int64, int64];
|
||||||
exception.set_body(&fields, false);
|
exception.set_body(&fields, false);
|
||||||
exception.ptr_type(AddressSpace::default()).as_basic_type_enum()
|
exception.ptr_type(AddressSpace::default()).as_basic_type_enum()
|
||||||
|
|
|
@ -173,7 +173,7 @@ impl<'ctx, AddresseeOptic: MemoryGetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||||
// To make [`Address`] convenient to use
|
// To make [`Address`] convenient to use
|
||||||
impl<'ctx, AddresseeOptic: MemorySetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
impl<'ctx, AddresseeOptic: MemorySetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||||
pub fn set(&self, ctx: &CodeGenContext<'ctx, '_>, value: &AddresseeOptic::Value) {
|
pub fn set(&self, ctx: &CodeGenContext<'ctx, '_>, value: &AddresseeOptic::Value) {
|
||||||
self.addressee_optic.set(ctx, self.address, value)
|
self.addressee_optic.set(ctx, self.address, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ impl<'ctx, AddresseeOptic: MemorySetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct GepGetter<ElementOptic> {
|
pub struct GepGetter<ElementOptic> {
|
||||||
/// The LLVM GEP index
|
/// The LLVM GEP index
|
||||||
pub gep_index: u32, // TODO: I think I'm not supposed to *just* use i32 for GEP like that
|
pub gep_index: u64,
|
||||||
/// Element (or field in the context of `struct`s) name. Used for cosmetics.
|
/// Element (or field in the context of `struct`s) name. Used for cosmetics.
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
/// The lens to view the actual value after applying this [`FieldLens<T>`]
|
/// The lens to view the actual value after applying this [`FieldLens<T>`]
|
||||||
|
@ -208,7 +208,7 @@ impl<'ctx, ElementOptic: Optic<'ctx>> MemoryGetter<'ctx> for GepGetter<ElementOp
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_in_bounds_gep(
|
.build_in_bounds_gep(
|
||||||
pointer,
|
pointer,
|
||||||
&[llvm_i32.const_zero(), llvm_i32.const_int(self.gep_index as u64, false)],
|
&[llvm_i32.const_zero(), llvm_i32.const_int(self.gep_index, false)],
|
||||||
name,
|
name,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -220,7 +220,7 @@ impl<'ctx, ElementOptic: Optic<'ctx>> MemoryGetter<'ctx> for GepGetter<ElementOp
|
||||||
// Only used by [`FieldBuilder`]
|
// Only used by [`FieldBuilder`]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct FieldInfo<'ctx> {
|
struct FieldInfo<'ctx> {
|
||||||
gep_index: u32,
|
gep_index: u64,
|
||||||
name: &'ctx str,
|
name: &'ctx str,
|
||||||
llvm_type: BasicTypeEnum<'ctx>,
|
llvm_type: BasicTypeEnum<'ctx>,
|
||||||
}
|
}
|
||||||
|
@ -228,17 +228,18 @@ struct FieldInfo<'ctx> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FieldBuilder<'ctx> {
|
pub struct FieldBuilder<'ctx> {
|
||||||
pub ctx: &'ctx Context,
|
pub ctx: &'ctx Context,
|
||||||
gep_index_counter: u32,
|
gep_index_counter: u64,
|
||||||
struct_name: &'ctx str,
|
struct_name: &'ctx str,
|
||||||
fields: Vec<FieldInfo<'ctx>>,
|
fields: Vec<FieldInfo<'ctx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> FieldBuilder<'ctx> {
|
impl<'ctx> FieldBuilder<'ctx> {
|
||||||
|
#[must_use]
|
||||||
pub fn new(ctx: &'ctx Context, struct_name: &'ctx str) -> Self {
|
pub fn new(ctx: &'ctx Context, struct_name: &'ctx str) -> Self {
|
||||||
FieldBuilder { ctx, gep_index_counter: 0, struct_name, fields: Vec::new() }
|
FieldBuilder { ctx, gep_index_counter: 0, struct_name, fields: Vec::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_gep_index(&mut self) -> u32 {
|
fn next_gep_index(&mut self) -> u64 {
|
||||||
let index = self.gep_index_counter;
|
let index = self.gep_index_counter;
|
||||||
self.gep_index_counter += 1;
|
self.gep_index_counter += 1;
|
||||||
index
|
index
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
|
||||||
|
use crate::util::SizeVariant;
|
||||||
use helper::{debug_assert_prim_is_allowed, make_exception_fields, PrimDefDetails};
|
use helper::{debug_assert_prim_is_allowed, make_exception_fields, PrimDefDetails};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
|
@ -23,7 +24,6 @@ use crate::{
|
||||||
symbol_resolver::SymbolValue,
|
symbol_resolver::SymbolValue,
|
||||||
toplevel::{helper::PrimDef, numpy::make_ndarray_ty},
|
toplevel::{helper::PrimDef, numpy::make_ndarray_ty},
|
||||||
typecheck::typedef::{into_var_map, iter_type_vars, TypeVar, VarMap},
|
typecheck::typedef::{into_var_map, iter_type_vars, TypeVar, VarMap},
|
||||||
util::SizeVariant,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Reference in New Issue