Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ RSS=\
$(SRC)/b.rs \
$(SRC)/ir.rs \
$(SRC)/crust.rs \
$(SRC)/fighting_consteval.rs \
$(SRC)/flag.rs \
$(SRC)/glob.rs \
$(SRC)/lexer.rs \
Expand Down
1 change: 1 addition & 0 deletions src/b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub mod nob;
pub mod flag;
#[macro_use]
pub mod crust;
pub mod fighting_consteval;
pub mod arena;
pub mod codegen;
pub mod lexer;
Expand Down
1 change: 1 addition & 0 deletions src/bgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#[macro_use]
pub mod crust;
pub mod nob;
pub mod fighting_consteval;

use core::ffi::*;
use core::mem::zeroed;
Expand Down
33 changes: 17 additions & 16 deletions src/btest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#[macro_use]
pub mod crust;
pub mod fighting_consteval;
#[macro_use]
pub mod nob;
pub mod targets;
Expand Down Expand Up @@ -38,7 +39,7 @@ const GARBAGE_FOLDER: *const c_char = c!("./build/tests/");

enum_with_order! {
#[derive(Copy, Clone)]
enum TestState in TEST_STATE_ORDER {
enum TestState {
Enabled,
Disabled,
}
Expand All @@ -53,8 +54,8 @@ impl TestState {
}

unsafe fn from_name(name: *const c_char) -> Option<Self> {
for i in 0..TEST_STATE_ORDER.len() {
let state = (*TEST_STATE_ORDER)[i];
for i in 0..TestState::VARIANT_COUNT {
let state = (*TestState::ORDER_SLICE)[i];
if strcmp(state.name(), name) == 0 {
return Some(state)
}
Expand All @@ -75,7 +76,7 @@ pub enum Outcome {

enum_with_order! {
#[derive(Copy, Clone)]
enum ReportStatus in REPORT_STATUS_ORDER {
enum ReportStatus {
OK,
NeverRecorded,
StdoutMismatch,
Expand Down Expand Up @@ -200,7 +201,7 @@ pub unsafe fn usage() {

#[derive(Clone, Copy)]
pub struct ReportStats {
entries: [usize; REPORT_STATUS_ORDER.len()]
entries: [usize; ReportStatus::ORDER_SLICE.len()]
}

const RESET: *const c_char = c!("\x1b[0m");
Expand All @@ -211,15 +212,15 @@ const RED: *const c_char = c!("\x1b[31m");
const BLUE: *const c_char = c!("\x1b[94m");

pub unsafe fn print_legend(row_width: usize) {
for i in 0..REPORT_STATUS_ORDER.len() {
let status = (*REPORT_STATUS_ORDER)[i];
for i in 0..ReportStatus::VARIANT_COUNT {
let status = (*ReportStatus::ORDER_SLICE)[i];
printf(c!("%*s%s%s%s - %s\n"), row_width + 2, c!(""), status.color(), status.letter(), RESET, status.description());
}
}

pub unsafe fn print_report_stats(stats: ReportStats) {
for i in 0..REPORT_STATUS_ORDER.len() {
let status = (*REPORT_STATUS_ORDER)[i];
for i in 0..ReportStatus::VARIANT_COUNT {
let status = (*ReportStatus::ORDER_SLICE)[i];
printf(c!(" %s%s%s: %-3zu"), status.color(), status.letter(), RESET, stats.entries[i]);
}
printf(c!("\n"));
Expand Down Expand Up @@ -652,7 +653,7 @@ pub unsafe fn replay_tests(

enum_with_order! {
#[derive(Copy, Clone)]
enum Action in ACTION_ORDER {
enum Action {
Replay,
Record,
Prune,
Expand All @@ -673,8 +674,8 @@ impl Action {
}

unsafe fn from_name(name: *const c_char) -> Option<Self> {
for i in 0..ACTION_ORDER.len() {
let action = (*ACTION_ORDER)[i];
for i in 0..Action::VARIANT_COUNT {
let action = (*Action::ORDER_SLICE)[i];
if strcmp(name, action.name()) == 0 {
return Some(action)
}
Expand Down Expand Up @@ -726,11 +727,11 @@ pub unsafe fn main(argc: i32, argv: *mut*mut c_char) -> Option<()> {
if *list_actions {
fprintf(stderr(), c!("Available actions:\n"));
let mut width = 0;
for i in 0..ACTION_ORDER.len() {
width = cmp::max(width, strlen((*ACTION_ORDER)[i].name()));
for i in 0..Action::VARIANT_COUNT {
width = cmp::max(width, strlen((*Action::ORDER_SLICE)[i].name()));
}
for i in 0..ACTION_ORDER.len() {
let action = (*ACTION_ORDER)[i];
for i in 0..Action::VARIANT_COUNT {
let action = (*Action::ORDER_SLICE)[i];
match action {
Action::Replay => {
printf(c!(" %-*s - Replay the selected Test Matrix slice with expected outputs from %s.\n"), width, action.name(), json_path);
Expand Down
78 changes: 35 additions & 43 deletions src/codegen/mos6502.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,10 @@ use crate::arena::{self, Arena};
use crate::targets::TargetAPI;
use crate::params::*;

// TODO: does this have to be a macro?
macro_rules! instr_enum {
(enum $n:ident { $($instr:ident),* }) => {
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum $n {
$($instr),*,
COUNT
}

// TODO: maybe not search linearly, if this is too slow
pub unsafe fn instr_from_string(s: *const c_char) -> Option<Instr> {
$(
let curr = c!(stringify!($instr));
if (strcmp(s, curr) == 0) {
return Some($n::$instr);
}
)*
return None;
}
}
}

instr_enum! {
enum_with_order! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
enum Instr {
ADC,
AND,
Expand Down Expand Up @@ -70,33 +50,45 @@ instr_enum! {
}
}

#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum AddrMode {
IMM = 0,
ZP,
ZP_X,
ZP_Y,
ABS,
ABS_X,
ABS_Y,
IND_X,
IND_Y,

ACC,
REL,
IND,
IMPL, // implied, no arg

COUNT
// TODO: maybe not search linearly, if this is too slow
pub unsafe fn instr_from_string(s: *const c_char) -> Option<Instr> {
for i in 0..Instr::VARIANT_COUNT {
let curr: *const c_char = (*Instr::NAMES_SLICE)[i];
if strcmp(s, curr) == 0 {
return Some((*Instr::ORDER_SLICE)[i]);
}
}
return None;
}

enum_with_order! {
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
enum AddrMode {
IMM = 0,
ZP,
ZP_X,
ZP_Y,
ABS,
ABS_X,
ABS_Y,
IND_X,
IND_Y,

ACC,
REL,
IND,
IMPL, // implied, no arg
}
}

use Instr::*;
use AddrMode::*;

// TODO: we currently use 0xFF for invalid opcode, because Some() and None
// make this table way too big/hard to read
const INVL: u8 = 0xFF;
const OPCODES: [[u8; AddrMode::COUNT as usize]; Instr::COUNT as usize] =
const OPCODES: [[u8; AddrMode::VARIANT_COUNT]; Instr::VARIANT_COUNT] =
[// IMM ZP ZP_X ZP_Y, ABS ABS_X ABS_Y IND_X IND_Y ACC REL IND, IMPL
/*ADC*/[ 0x69, 0x65, 0x75, INVL, 0x6D, 0x7D, 0x79, 0x61, 0x71, INVL, INVL, INVL, INVL],
/*AND*/[ 0x29, 0x25, 0x35, INVL, 0x2D, 0x3D, 0x39, 0x21, 0x31, INVL, INVL, INVL, INVL],
Expand Down
10 changes: 5 additions & 5 deletions src/codegen/uxn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ pub unsafe fn usage(params: *const [Param]) {

enum_with_order! {
#[derive(Clone, Copy)]
enum Uxn_Runner in UXN_RUNNER_ORDER {
enum Uxn_Runner {
Uxncli,
Uxnemu,
}
Expand All @@ -148,8 +148,8 @@ impl Uxn_Runner {
}

unsafe fn from_name(name: *const c_char) -> Option<Self> {
for i in 0..UXN_RUNNER_ORDER.len() {
let runner = (*UXN_RUNNER_ORDER)[i];
for i in 0..Uxn_Runner::VARIANT_COUNT {
let runner = (*Uxn_Runner::ORDER_SLICE)[i];
if strcmp(runner.name(), name) == 0 {
return Some(runner);
}
Expand Down Expand Up @@ -210,8 +210,8 @@ pub unsafe fn new(a: *mut arena::Arena, args: *const [*const c_char]) -> Option<
usage(params);
log(Log_Level::ERROR, c!("Invalid Uxn runner name `%s`!"), runner_name);
log(Log_Level::ERROR, c!("Valid names:"));
for i in 0..UXN_RUNNER_ORDER.len() {
let runner = (*UXN_RUNNER_ORDER)[i];
for i in 0..Uxn_Runner::VARIANT_COUNT {
let runner = (*Uxn_Runner::ORDER_SLICE)[i];
log(Log_Level::ERROR, c!(" %s - %s"), runner.name(), runner.description());
}
return None;
Expand Down
88 changes: 77 additions & 11 deletions src/crust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,86 @@ macro_rules! c {
#[macro_export]
macro_rules! enum_with_order {
(
#[derive($($traits:tt)*)]
enum $name:ident in $order_name:ident {
$($items:tt)*
$( #[$attr:meta $($attr_args:tt)*] )*
enum $Ident:ident {
$(
$Item:ident $(= $init:expr)?
),* $(,)?
}
) => {
#[derive($($traits)*)]
pub enum $name {
$($items)*
$( #[$attr $($attr_args)*] )*
pub enum $Ident {
$($Item $(= $init)?),*
}
pub const $order_name: *const [$name] = {
use $name::*;
&[$($items)*]
};
}

impl $Ident {
/*
Explanation:
Rust enums have the ability to specify their variants' values, like `A` in this enum:
enum Either {
A = 1,
B,
}
in order to make the ordered slice of variants, we need compile time buffers of unknown sizes.
we take this const fn approach from crates like `const_str`:
we have a const function with a const-generic array width (named order_variants_properly) to have an actual array
on the const stack which we can modify freely and return by-value. this is all it does.
*/
const __ORDER_AND_NAMES_SLICES: (*const [$Ident], *const [*const c_char]) = {
#[allow(unused_imports)]
use $crate::fighting_consteval::*;
#[allow(unused_imports)]
use $crate::c;
// we assert that $Ident must be Copy here (as Crust requires us to do so!)
const fn _assert_copy<T: Copy>() {}
const _: () = _assert_copy::<$Ident>(); // your enum must derive Copy to have an ordered slice!
// this is the slice of declarations in declaration order. declaration order does not mean
// order of appearance in the ORDER_SLICE, as rust allows explicit discriminants.
const DECLS_AMOUNT: usize = UNORDERED_DECLS.len();
const UNORDERED_DECLS: *const [($Ident, *const c_char)] = {
&[
$(
($Ident::$Item, c!(stringify!($Item)))
),*
]
};
// this is the slice of declarations that have a specified enum discriminant requirement.
// the order of elements inside this slice doesn't really matter.
// we don't have to worry about clashing requirements as the enum declaration itself handles that for us.
const AMOUNT_SPECIFIED: usize = SPECIFIED_DISCRIMINANTS.len();
const SPECIFIED_DISCRIMINANTS: *const [($Ident, *const c_char, u128)] = {
&[
$( $(
($Ident::$Item, c!(stringify!($Item)), $init), // negative discriminants are not supported, as Self::ORDER_SLICE would need to go backwards.
)? )*
]
};
// we pass the unordered declarations and the discriminant requirements to `order_decls_properly`,
// which handles the discriminant resolution in a const fn that is fully evaluated at const.
const RES: ([$Ident; DECLS_AMOUNT], [*const c_char; DECLS_AMOUNT]) = unsafe {
match const { order_decls_properly::<$Ident, DECLS_AMOUNT, AMOUNT_SPECIFIED>(
&*mkarray::<_, DECLS_AMOUNT>(UNORDERED_DECLS),
&*mkarray::<_, AMOUNT_SPECIFIED>(SPECIFIED_DISCRIMINANTS)
) } {
Ok(v) => v,
Err(OrderDeclsError::RanOutOfDecls) =>
panic!("enum_with_order: failed to order enum variants properly.\n\tthis is likely due to discriminant requirements leaving holes in the resulting ORDER_SLICE, which is not supported"),
Err(OrderDeclsError::FinalSliceMissingEntries) =>
panic!("enum_with_order: critical sanity check failed at compile time. this is a bug.\n\tthere were entries in your declaration that did not end up in the resulting `Self::ORDER_SLICE`"),
}
};
// as constants don't allow destructuring (as in `const (ORDER, NAMES) = ...;`), we unpack RES
// manually and "return" it as the constant.
(
&RES.0,
&RES.1
)
};
pub const ORDER_SLICE: *const [$Ident] = $Ident::__ORDER_AND_NAMES_SLICES.0;
pub const NAMES_SLICE: *const [*const c_char] = $Ident::__ORDER_AND_NAMES_SLICES.1;
pub const VARIANT_COUNT: usize = unsafe { (&*$Ident::ORDER_SLICE).len() };
}
};
}

pub unsafe fn slice_contains<Value: PartialEq>(slice: *const [Value], needle: *const Value) -> bool {
Expand Down
Loading