Add dqn_cgen, reorganise files into standalone/external dirs
This commit is contained in:
parent
6aec2ca4cf
commit
f6dd762e8d
@ -1,20 +1,34 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$$$$$\ $$$$$$$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$\ $$$$$$$$\
|
||||
// $$ __$$\ $$ __$$\ $$ __$$\ $$ _____|\_$$ _|$$ | $$ _____|
|
||||
// $$ / \__|$$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |
|
||||
// $$ | $$$$$$$ |$$$$$$$ | $$$$$\ $$ | $$ | $$$$$\
|
||||
// $$ | $$ ____/ $$ ____/ $$ __| $$ | $$ | $$ __|
|
||||
// $$ | $$\ $$ | $$ | $$ | $$ | $$ | $$ |
|
||||
// \$$$$$$ |$$ | $$ | $$ | $$$$$$\ $$$$$$$$\ $$$$$$$$\
|
||||
// \______/ \__| \__| \__| \______|\________|\________|
|
||||
//
|
||||
// dqn_cpp_file.h -- Functions to emit C++ formatted code
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#if !defined(DQN_CPP_FILE_H)
|
||||
#define DQN_CPP_FILE_H
|
||||
|
||||
// NOTE: Dqn_CppFile: Helper functions to generate C++ files
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
#include <stdio.h> /// printf, fputc
|
||||
#include <stdarg.h> /// va_list...
|
||||
#include <assert.h> /// assert
|
||||
|
||||
typedef struct Dqn_CppFile { ///< Maintains state for printing C++ style formatted files
|
||||
FILE *file; ///< (Write) File to print to
|
||||
int indent; ///< Current indent level of the printer
|
||||
int space_per_indent; ///< (Write) Number of spaces per indent
|
||||
unsigned char if_chain[256]; ///
|
||||
unsigned char if_chain_size; ///
|
||||
FILE *file; ///< (Write) File to print to
|
||||
int indent; ///< Current indent level of the printer
|
||||
int space_per_indent; ///< (Write) Number of spaces per indent
|
||||
unsigned char if_chain[256]; ///
|
||||
unsigned char if_chain_size; ///
|
||||
} Dqn_CppFile;
|
||||
|
||||
#define Dqn_CppSpacePerIndent(cpp) ((cpp) && (cpp)->space_per_indent) ? ((cpp)->space_per_indent) : 4
|
||||
|
||||
/// Print the format string indented and terminate the string with a new-line.
|
||||
void Dqn_CppLineV(Dqn_CppFile *cpp, char const *fmt, va_list args);
|
||||
void Dqn_CppLine(Dqn_CppFile *cpp, char const *fmt, ...);
|
||||
@ -160,7 +174,7 @@ void Dqn_CppLine(Dqn_CppFile *cpp, char const *fmt, ...)
|
||||
|
||||
void Dqn_CppPrintV(Dqn_CppFile *cpp, char const *fmt, va_list args)
|
||||
{
|
||||
int space_per_indent = cpp->space_per_indent == 0 ? 4 : cpp->space_per_indent;
|
||||
int space_per_indent = Dqn_CppSpacePerIndent(cpp);
|
||||
int spaces = fmt ? (cpp->indent * space_per_indent) : 0;
|
||||
fprintf(cpp->file, "%*s", spaces, "");
|
||||
vfprintf(cpp->file, fmt, args);
|
@ -1,17 +1,30 @@
|
||||
#if !defined(DQN_KECCAK_H)
|
||||
#define DQN_KECCAK_H
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Overview
|
||||
// -----------------------------------------------------------------------------
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\
|
||||
// $$ | $$ |$$ _____|$$ __$$\ $$ __$$\ $$ __$$\ $$ | $$ |
|
||||
// $$ |$$ / $$ | $$ / \__|$$ / \__|$$ / $$ |$$ |$$ /
|
||||
// $$$$$ / $$$$$\ $$ | $$ | $$$$$$$$ |$$$$$ /
|
||||
// $$ $$< $$ __| $$ | $$ | $$ __$$ |$$ $$<
|
||||
// $$ |\$$\ $$ | $$ | $$\ $$ | $$\ $$ | $$ |$$ |\$$\
|
||||
// $$ | \$$\ $$$$$$$$\ \$$$$$$ |\$$$$$$ |$$ | $$ |$$ | \$$\
|
||||
// \__| \__|\________| \______/ \______/ \__| \__|\__| \__|
|
||||
//
|
||||
// dqn_keccak.h -- FIPS202 SHA3 + non-finalized SHA3 (aka. Keccak) hashing algorithms
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Implementation of the Keccak hashing algorithms from the Keccak and SHA3
|
||||
// families (including the FIPS202 published algorithms and the non-finalized
|
||||
// ones, i.e. the ones used in Ethereum and Monero which adopted SHA3 before it
|
||||
// was finalized. The only difference between the 2 is a different delimited
|
||||
// suffix).
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: MIT License
|
||||
// -----------------------------------------------------------------------------
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2021 github.com/doy-lee
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -32,12 +45,25 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Macros
|
||||
// -----------------------------------------------------------------------------
|
||||
// #define DQN_KECCAK_IMPLEMENTATION
|
||||
// Define this in one and only one C++ file to enable the implementation
|
||||
// code of the header file.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$$$$$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$\
|
||||
// $$ __$$\ $$ __$$\\__$$ __|\_$$ _|$$ __$$\ $$$\ $$ |$$ __$$\
|
||||
// $$ / $$ |$$ | $$ | $$ | $$ | $$ / $$ |$$$$\ $$ |$$ / \__|
|
||||
// $$ | $$ |$$$$$$$ | $$ | $$ | $$ | $$ |$$ $$\$$ |\$$$$$$\
|
||||
// $$ | $$ |$$ ____/ $$ | $$ | $$ | $$ |$$ \$$$$ | \____$$\
|
||||
// $$ | $$ |$$ | $$ | $$ | $$ | $$ |$$ |\$$$ |$$\ $$ |
|
||||
// $$$$$$ |$$ | $$ | $$$$$$\ $$$$$$ |$$ | \$$ |\$$$$$$ |
|
||||
// \______/ \__| \__| \______| \______/ \__| \__| \______/
|
||||
//
|
||||
// Options -- Compile time build customisation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// - Define this in one and only one C++ file to enable the implementation
|
||||
// code of the header file.
|
||||
//
|
||||
// #define DQN_KECCAK_IMPLEMENTATION
|
||||
|
||||
#if !defined(DQN_KECCAK_MEMCPY)
|
||||
#include <string.h>
|
||||
@ -54,7 +80,6 @@
|
||||
#define DQN_KECCAK_MEMSET(dest, byte, count) memset(dest, byte, count)
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(DQN_KECCAK_ASSERT)
|
||||
#if defined(NDEBUG)
|
||||
#define DQN_KECCAK_ASSERT(expr)
|
||||
@ -80,9 +105,6 @@
|
||||
#define DQN_KECCAK_STRING96_FMT(string) 96, string
|
||||
#define DQN_KECCAK_STRING128_FMT(string) 128, string
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: API
|
||||
// -----------------------------------------------------------------------------
|
||||
typedef unsigned char Dqn_KeccakU8;
|
||||
typedef unsigned short Dqn_KeccakU16;
|
||||
typedef unsigned int Dqn_KeccakU32;
|
||||
@ -93,9 +115,6 @@ typedef unsigned int Dqn_KeccakUint;
|
||||
typedef unsigned long long Dqn_KeccakU64;
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Data structures
|
||||
// -----------------------------------------------------------------------------
|
||||
typedef struct Dqn_KeccakBytes28 { char data[28]; } Dqn_KeccakBytes28; // 224 bit
|
||||
typedef struct Dqn_KeccakBytes32 { char data[32]; } Dqn_KeccakBytes32; // 256 bit
|
||||
typedef struct Dqn_KeccakBytes48 { char data[48]; } Dqn_KeccakBytes48; // 384 bit
|
||||
@ -116,9 +135,7 @@ typedef struct Dqn_KeccakState
|
||||
char delimited_suffix; // The delimited suffix of the current hash
|
||||
} Dqn_KeccakState;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: SHA3/Keccak Streaming API
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: SHA3/Keccak Streaming API /////////////////////////////////////////////////////////////////
|
||||
// Setup a hashing state for either
|
||||
// - FIPS 202 SHA3
|
||||
// - Non-finalized SHA3 (only difference is delimited suffix of 0x1 instead of 0x6 in SHA3)
|
||||
@ -140,9 +157,7 @@ Dqn_KeccakState Dqn_KeccakSHA3Init(bool sha3, int hash_size_bits);
|
||||
void Dqn_KeccakUpdate(Dqn_KeccakState *keccak, void const *data, Dqn_KeccakU64 data_size);
|
||||
void Dqn_KeccakFinish(Dqn_KeccakState *keccak, void *dest, int dest_size);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Simple API
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Simple API ////////////////////////////////////////////////////////////////////////////////
|
||||
// Helper function that combines the Init, Update and Finish step in one shot,
|
||||
// i.e. hashing a singlular contiguous buffer. Use the streaming API if data
|
||||
// is split across different buffers.
|
||||
@ -160,43 +175,33 @@ void Dqn_KeccakSHA3Hash(bool sha3, int hash_size_bits, void const *sr
|
||||
#define Dqn_Keccak384(src, src_size, dest, dest_size) Dqn_KeccakHash(384, src, src_size, dest, dest_size)
|
||||
#define Dqn_Keccak512(src, src_size, dest, dest_size) Dqn_KeccakHash(512, src, src_size, dest, dest_size)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: SHA3 Helpers
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: SHA3 Helpers //////////////////////////////////////////////////////////////////////////////
|
||||
Dqn_KeccakBytes28 Dqn_SHA3_224ToBytes28(void *bytes, Dqn_KeccakU64 bytes_size);
|
||||
Dqn_KeccakBytes32 Dqn_SHA3_256ToBytes32(void *bytes, Dqn_KeccakU64 bytes_size);
|
||||
Dqn_KeccakBytes48 Dqn_SHA3_384ToBytes48(void *bytes, Dqn_KeccakU64 bytes_size);
|
||||
Dqn_KeccakBytes64 Dqn_SHA3_512ToBytes64(void *bytes, Dqn_KeccakU64 bytes_size);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Keccak Helpers
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Keccak Helpers ////////////////////////////////////////////////////////////////////////////
|
||||
Dqn_KeccakBytes28 Dqn_Keccak224ToBytes28(void *bytes, Dqn_KeccakU64 bytes_size);
|
||||
Dqn_KeccakBytes32 Dqn_Keccak256ToBytes32(void *bytes, Dqn_KeccakU64 bytes_size);
|
||||
Dqn_KeccakBytes48 Dqn_Keccak384ToBytes48(void *bytes, Dqn_KeccakU64 bytes_size);
|
||||
Dqn_KeccakBytes64 Dqn_Keccak512ToBytes64(void *bytes, Dqn_KeccakU64 bytes_size);
|
||||
|
||||
#if defined(DQN_H)
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: SHA3 - Helpers for Dqn data structures
|
||||
// -----------------------------------------------------------------------------
|
||||
Dqn_KeccakBytes28 Dqn_SHA3_224StringToBytes28(Dqn_String8 string);
|
||||
Dqn_KeccakBytes32 Dqn_SHA3_256StringToBytes32(Dqn_String8 string);
|
||||
Dqn_KeccakBytes48 Dqn_SHA3_384StringToBytes48(Dqn_String8 string);
|
||||
Dqn_KeccakBytes64 Dqn_SHA3_512StringToBytes64(Dqn_String8 string);
|
||||
// NOTE: SHA3 - Helpers for Dqn data structures ////////////////////////////////////////////////////
|
||||
Dqn_KeccakBytes28 Dqn_SHA3_224StringToBytes28(Dqn_Str8 string);
|
||||
Dqn_KeccakBytes32 Dqn_SHA3_256StringToBytes32(Dqn_Str8 string);
|
||||
Dqn_KeccakBytes48 Dqn_SHA3_384StringToBytes48(Dqn_Str8 string);
|
||||
Dqn_KeccakBytes64 Dqn_SHA3_512StringToBytes64(Dqn_Str8 string);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Keccak - Helpers for Dqn data structures
|
||||
// -----------------------------------------------------------------------------
|
||||
Dqn_KeccakBytes28 Dqn_Keccak224StringToBytes28(Dqn_String8 string);
|
||||
Dqn_KeccakBytes32 Dqn_Keccak256StringToBytes32(Dqn_String8 string);
|
||||
Dqn_KeccakBytes48 Dqn_Keccak384StringToBytes48(Dqn_String8 string);
|
||||
Dqn_KeccakBytes64 Dqn_Keccak512StringToBytes64(Dqn_String8 string);
|
||||
// NOTE: Keccak - Helpers for Dqn data structures //////////////////////////////////////////////////
|
||||
Dqn_KeccakBytes28 Dqn_Keccak224StringToBytes28(Dqn_Str8 string);
|
||||
Dqn_KeccakBytes32 Dqn_Keccak256StringToBytes32(Dqn_Str8 string);
|
||||
Dqn_KeccakBytes48 Dqn_Keccak384StringToBytes48(Dqn_Str8 string);
|
||||
Dqn_KeccakBytes64 Dqn_Keccak512StringToBytes64(Dqn_Str8 string);
|
||||
#endif // DQN_H
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Helper functions
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Helper functions //////////////////////////////////////////////////////////////////////////
|
||||
// Convert a binary buffer into its hex representation into dest. The dest
|
||||
// buffer must be large enough to contain the hex representation, i.e.
|
||||
// atleast src_size * 2). This function does *not* null-terminate the buffer.
|
||||
@ -218,13 +223,11 @@ int Dqn_KeccakBytes48Equals(Dqn_KeccakBytes48 const *a, Dqn_KeccakBytes48 const
|
||||
int Dqn_KeccakBytes64Equals(Dqn_KeccakBytes64 const *a, Dqn_KeccakBytes64 const *b);
|
||||
|
||||
#if defined(DQN_H) && defined(DQN_WITH_HEX)
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Other helper functions for Dqn data structures
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Other helper functions for Dqn data structures ////////////////////////////////////////////
|
||||
// Converts a 64 character hex string into the 32 byte binary representation.
|
||||
// Invalid hex characters in the string will be represented as 0.
|
||||
// hex: Must be exactly a 64 character hex string.
|
||||
Dqn_KeccakBytes32 Dqn_KeccakHex64StringToBytes(Dqn_String8 hex);
|
||||
Dqn_KeccakBytes32 Dqn_KeccakHex64StringToBytes(Dqn_Str8 hex);
|
||||
#endif // DQN_H && DQN_WITH_HEX
|
||||
#endif // DQN_KECCAK_H
|
||||
|
||||
@ -257,9 +260,7 @@ static void Dqn_Keccak__Permute(void *state)
|
||||
for (int round_index = 0; round_index < 24; round_index++)
|
||||
{
|
||||
#define LANE_INDEX(x, y) ((x) + ((y) * DQN_KECCAK_LANE_SIZE_U64))
|
||||
// ---------------------------------------------------------------------
|
||||
// θ step
|
||||
// ---------------------------------------------------------------------
|
||||
// θ step //////////////////////////////////////////////////////////////////////////////////
|
||||
#if 1
|
||||
Dqn_KeccakU64 c[DQN_KECCAK_LANE_SIZE_U64];
|
||||
for (int x = 0; x < DQN_KECCAK_LANE_SIZE_U64; x++)
|
||||
@ -293,9 +294,7 @@ static void Dqn_Keccak__Permute(void *state)
|
||||
d[4] = c[3] ^ DQN_KECCAK_ROL64(c[0], 1);
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// ρ and π steps
|
||||
// ---------------------------------------------------------------------
|
||||
// ρ and π steps ///////////////////////////////////////////////////////////////////////////
|
||||
Dqn_KeccakU64 b[DQN_KECCAK_LANE_SIZE_U64 * DQN_KECCAK_LANE_SIZE_U64];
|
||||
for (int y = 0; y < DQN_KECCAK_LANE_SIZE_U64; y++)
|
||||
{
|
||||
@ -308,9 +307,7 @@ static void Dqn_Keccak__Permute(void *state)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// χ step
|
||||
// ---------------------------------------------------------------------
|
||||
// χ step //////////////////////////////////////////////////////////////////////////////////
|
||||
for (int y = 0; y < DQN_KECCAK_LANE_SIZE_U64; y++)
|
||||
{
|
||||
for (int x = 0; x < DQN_KECCAK_LANE_SIZE_U64; x++)
|
||||
@ -322,18 +319,14 @@ static void Dqn_Keccak__Permute(void *state)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// ι step
|
||||
// ---------------------------------------------------------------------
|
||||
// ι step //////////////////////////////////////////////////////////////////////////////////
|
||||
lanes_u64[LANE_INDEX(0, 0)] ^= DQN_KECCAK_ROUNDS[round_index];
|
||||
#undef LANE_INDEX
|
||||
#undef DQN_KECCAK_ROL64
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Streaming API
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Streaming API /////////////////////////////////////////////////////////////////////////////
|
||||
Dqn_KeccakState Dqn_KeccakSHA3Init(bool sha3, int hash_size_bits)
|
||||
{
|
||||
char const SHA3_DELIMITED_SUFFIX = 0x06;
|
||||
@ -382,9 +375,7 @@ void Dqn_KeccakFinish(Dqn_KeccakState *keccak, void *dest, int dest_size)
|
||||
{
|
||||
DQN_KECCAK_ASSERT(dest_size >= keccak->hash_size_bits / 8);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Sponge Finalization Step: Final padding bit
|
||||
// ---------------------------------------------------------------------
|
||||
// Sponge Finalization Step: Final padding bit /////////////////////////////////////////////////
|
||||
int const INDEX_OF_0X80_BYTE = keccak->absorb_size - 1;
|
||||
int const delimited_suffix_index = keccak->state_size;
|
||||
DQN_KECCAK_ASSERT(delimited_suffix_index < keccak->absorb_size);
|
||||
@ -404,9 +395,7 @@ void Dqn_KeccakFinish(Dqn_KeccakState *keccak, void *dest, int dest_size)
|
||||
state[INDEX_OF_0X80_BYTE] ^= 0x80;
|
||||
Dqn_Keccak__Permute(state);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Squeeze Step: Squeeze bytes from the state into our hash
|
||||
// ---------------------------------------------------------------------
|
||||
// Squeeze Step: Squeeze bytes from the state into our hash ////////////////////////////////////
|
||||
Dqn_KeccakU8 *dest_u8 = (Dqn_KeccakU8 *)dest;
|
||||
int const squeeze_count = dest_size / keccak->absorb_size;
|
||||
int squeeze_index = 0;
|
||||
@ -417,9 +406,7 @@ void Dqn_KeccakFinish(Dqn_KeccakState *keccak, void *dest, int dest_size)
|
||||
dest_u8 += keccak->absorb_size;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Squeeze Finalisation Step: Remainder bytes in hash
|
||||
// ---------------------------------------------------------------------
|
||||
// Squeeze Finalisation Step: Remainder bytes in hash //////////////////////////////////////////
|
||||
int const remainder = dest_size % keccak->absorb_size;
|
||||
if (remainder)
|
||||
{
|
||||
@ -435,9 +422,7 @@ void Dqn_KeccakSHA3Hash(bool sha3, int hash_size_bits, void const *src, Dqn_Kecc
|
||||
Dqn_KeccakFinish(&keccak, dest, dest_size);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: SHA3 Helpers
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: SHA3 Helpers //////////////////////////////////////////////////////////////////////////////
|
||||
Dqn_KeccakBytes28 Dqn_SHA3_224ToBytes28(void *bytes, Dqn_KeccakU64 bytes_size)
|
||||
{
|
||||
Dqn_KeccakBytes28 result;
|
||||
@ -466,9 +451,7 @@ Dqn_KeccakBytes64 Dqn_SHA3_512ToBytes64(void *bytes, Dqn_KeccakU64 bytes_size)
|
||||
return result;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Keccak Helpers
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Keccak Helpers ////////////////////////////////////////////////////////////////////////////
|
||||
Dqn_KeccakBytes28 Dqn_Keccak224ToBytes28(void *bytes, Dqn_KeccakU64 bytes_size)
|
||||
{
|
||||
Dqn_KeccakBytes28 result;
|
||||
@ -499,31 +482,29 @@ Dqn_KeccakBytes64 Dqn_Keccak512ToBytes64(void *bytes, Dqn_KeccakU64 bytes_size)
|
||||
|
||||
|
||||
#if defined(DQN_H)
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: SHA3 - Helpers for Dqn data structures
|
||||
// -----------------------------------------------------------------------------
|
||||
Dqn_KeccakBytes28 Dqn_SHA3_224StringToBytes28(Dqn_String8 string)
|
||||
// NOTE: SHA3 - Helpers for Dqn data structures ////////////////////////////////////////////////////
|
||||
Dqn_KeccakBytes28 Dqn_SHA3_224StringToBytes28(Dqn_Str8 string)
|
||||
{
|
||||
Dqn_KeccakBytes28 result;
|
||||
Dqn_SHA3_224(string.data, string.size, result.data, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_KeccakBytes32 Dqn_SHA3_256StringToBytes32(Dqn_String8 string)
|
||||
Dqn_KeccakBytes32 Dqn_SHA3_256StringToBytes32(Dqn_Str8 string)
|
||||
{
|
||||
Dqn_KeccakBytes32 result;
|
||||
Dqn_SHA3_256(string.data, string.size, result.data, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_KeccakBytes48 Dqn_SHA3_384StringToBytes48(Dqn_String8 string)
|
||||
Dqn_KeccakBytes48 Dqn_SHA3_384StringToBytes48(Dqn_Str8 string)
|
||||
{
|
||||
Dqn_KeccakBytes48 result;
|
||||
Dqn_SHA3_384(string.data, string.size, result.data, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_KeccakBytes64 Dqn_SHA3_512StringToBytes64(Dqn_String8 string)
|
||||
Dqn_KeccakBytes64 Dqn_SHA3_512StringToBytes64(Dqn_Str8 string)
|
||||
{
|
||||
Dqn_KeccakBytes64 result;
|
||||
Dqn_SHA3_512(string.data, string.size, result.data, sizeof(result));
|
||||
@ -532,31 +513,29 @@ Dqn_KeccakBytes64 Dqn_SHA3_512StringToBytes64(Dqn_String8 string)
|
||||
#endif // DQN_H
|
||||
|
||||
#if defined(DQN_H)
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Keccak - Helpers for Dqn data structures
|
||||
// -----------------------------------------------------------------------------
|
||||
Dqn_KeccakBytes28 Dqn_Keccak224StringToBytes28(Dqn_String8 string)
|
||||
// NOTE: Keccak - Helpers for Dqn data structures //////////////////////////////////////////////////
|
||||
Dqn_KeccakBytes28 Dqn_Keccak224StringToBytes28(Dqn_Str8 string)
|
||||
{
|
||||
Dqn_KeccakBytes28 result;
|
||||
Dqn_Keccak224(string.data, string.size, result.data, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_KeccakBytes32 Dqn_Keccak256StringToBytes32(Dqn_String8 string)
|
||||
Dqn_KeccakBytes32 Dqn_Keccak256StringToBytes32(Dqn_Str8 string)
|
||||
{
|
||||
Dqn_KeccakBytes32 result;
|
||||
Dqn_Keccak256(string.data, string.size, result.data, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_KeccakBytes48 Dqn_Keccak384StringToBytes48(Dqn_String8 string)
|
||||
Dqn_KeccakBytes48 Dqn_Keccak384StringToBytes48(Dqn_Str8 string)
|
||||
{
|
||||
Dqn_KeccakBytes48 result;
|
||||
Dqn_Keccak384(string.data, string.size, result.data, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_KeccakBytes64 Dqn_Keccak512StringToBytes64(Dqn_String8 string)
|
||||
Dqn_KeccakBytes64 Dqn_Keccak512StringToBytes64(Dqn_Str8 string)
|
||||
{
|
||||
Dqn_KeccakBytes64 result;
|
||||
Dqn_Keccak512(string.data, string.size, result.data, sizeof(result));
|
||||
@ -564,9 +543,7 @@ Dqn_KeccakBytes64 Dqn_Keccak512StringToBytes64(Dqn_String8 string)
|
||||
}
|
||||
#endif // DQN_H
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Helper functions
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Helper functions //////////////////////////////////////////////////////////////////////////
|
||||
void Dqn_KeccakBytesToHex(void const *src, Dqn_KeccakU64 src_size, char *dest, Dqn_KeccakU64 dest_size)
|
||||
{
|
||||
(void)src_size; (void)dest_size;
|
||||
@ -642,10 +619,8 @@ int Dqn_KeccakBytes64Equals(Dqn_KeccakBytes64 const *a, Dqn_KeccakBytes64 const
|
||||
}
|
||||
|
||||
#if defined(DQN_H) && defined(DQN_WITH_HEX)
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Other helper functions for Dqn data structures
|
||||
// -----------------------------------------------------------------------------
|
||||
Dqn_KeccakBytes32 Dqn_KeccakHex64StringToBytes(Dqn_String8 hex)
|
||||
// NOTE: Other helper functions for Dqn data structures ////////////////////////////////////////////
|
||||
Dqn_KeccakBytes32 Dqn_KeccakHex64StringToBytes(Dqn_Str8 hex)
|
||||
{
|
||||
DQN_KECCAK_ASSERT(hex.size == 64);
|
||||
Dqn_KeccakBytes32 result;
|
@ -147,7 +147,7 @@ typedef struct Dqn_UTest {
|
||||
int num_tests_ok_in_group;
|
||||
Dqn_UTestState state;
|
||||
bool finished;
|
||||
char name[1024];
|
||||
char name[256];
|
||||
size_t name_size;
|
||||
} Dqn_UTest;
|
||||
|
@ -13,7 +13,7 @@ pushd Build
|
||||
REM O2 Optimisation Level 2
|
||||
REM Oi Use CPU Intrinsics
|
||||
REM Z7 Combine multi-debug files to one debug file
|
||||
set common_flags=-D DQN_TEST_WITH_MAIN -D DQN_IMPLEMENTATION -D DQN_USE_STD_PRINTF /Tp %script_dir%\dqn.h
|
||||
set common_flags=-D DQN_UNIT_TESTS_WITH_MAIN -D DQN_UNIT_TESTS_WITH_KECCAK -D DQN_IMPLEMENTATION -D DQN_USE_STD_PRINTF /Tp %script_dir%\dqn.h
|
||||
|
||||
set msvc_driver_flags=%common_flags% -MT -EHa -GR- -Od -Oi -Z7 -wd4201 -W4 -nologo
|
||||
|
||||
|
48
dqn.h
48
dqn.h
@ -184,6 +184,36 @@
|
||||
//
|
||||
// #define DQN_ASAN_POISON_GUARD_SIZE 128
|
||||
//
|
||||
// - Enable 'Dqn_CGen' a parser that can emit run-time type information and
|
||||
// allow arbitrary querying of data definitions expressed in Excel-like tables
|
||||
// using text files encoded in Dion-System's Metadesk grammar.
|
||||
//
|
||||
// This option requires the standalone 'dqn_cpp_file.h' to be included prior
|
||||
// to 'dqn.h' as well as Metadesk's 'md.h' and similarly the implementation of
|
||||
// these files to be defined before the implementation of 'dqn.h' is defined.
|
||||
//
|
||||
// #define DQN_WITH_CGEN
|
||||
//
|
||||
// For example in your header file
|
||||
//
|
||||
// #include "metadesk/md.h"
|
||||
// #include "dqn/Standalone/dqn_cpp_file.h"
|
||||
// #define DQN_STB_SPRINTF_HEADER_ONLY // Metadesk includes 'stb_sprintf.h' already
|
||||
// #define DQN_WITH_CGEN
|
||||
// #include "dqn.h"
|
||||
//
|
||||
// Then in your implementation file
|
||||
//
|
||||
// #include "metadesk/md.c"
|
||||
// #define DQN_CPP_FILE_IMPLEMENTATION
|
||||
// #include "dqn/Standalone/dqn_cpp_file.h"
|
||||
// #define DQN_IMPLEMENTATION
|
||||
// #include "dqn.h"
|
||||
//
|
||||
// - Enable 'Dqn_JSON' a json parser. This option requires Sheredom's 'json.h'
|
||||
// to be included prior to this file.
|
||||
//
|
||||
// #define DQN_WITH_JSON
|
||||
|
||||
#if defined(DQN_ONLY_VARRAY) || \
|
||||
defined(DQN_ONLY_SARRAY) || \
|
||||
@ -285,6 +315,14 @@
|
||||
#include "dqn_hash.h"
|
||||
#include "dqn_helpers.h"
|
||||
#include "dqn_type_info.h"
|
||||
|
||||
#if defined(DQN_WITH_CGEN)
|
||||
#include "dqn_cgen.h"
|
||||
#endif
|
||||
|
||||
#if defined(DQN_WITH_JSON)
|
||||
#include "dqn_json.h"
|
||||
#endif
|
||||
#endif // DQN_H
|
||||
|
||||
#if defined(DQN_IMPLEMENTATION)
|
||||
@ -323,6 +361,16 @@
|
||||
#include "dqn_math.cpp"
|
||||
#include "dqn_hash.cpp"
|
||||
#include "dqn_helpers.cpp"
|
||||
|
||||
#if defined(DQN_WITH_CGEN)
|
||||
#include "dqn_cgen.cpp"
|
||||
#endif
|
||||
|
||||
#if defined(DQN_WITH_JSON)
|
||||
#define DQN_JSON_IMPLEMENTATION
|
||||
#include "dqn_json.h"
|
||||
#endif
|
||||
|
||||
#include "dqn_unit_tests.cpp"
|
||||
#include "dqn_docs.cpp"
|
||||
#endif // DQN_IMPLEMENTATION
|
||||
|
804
dqn_cgen.cpp
Normal file
804
dqn_cgen.cpp
Normal file
@ -0,0 +1,804 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$$$$$\ $$$$$$\ $$$$$$$$\ $$\ $$\
|
||||
// $$ __$$\ $$ __$$\ $$ _____|$$$\ $$ |
|
||||
// $$ / \__|$$ / \__|$$ | $$$$\ $$ |
|
||||
// $$ | $$ |$$$$\ $$$$$\ $$ $$\$$ |
|
||||
// $$ | $$ |\_$$ |$$ __| $$ \$$$$ |
|
||||
// $$ | $$\ $$ | $$ |$$ | $$ |\$$$ |
|
||||
// \$$$$$$ |\$$$$$$ |$$$$$$$$\ $$ | \$$ |
|
||||
// \______/ \______/ \________|\__| \__|
|
||||
//
|
||||
// dqn_cgen.cpp
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Dqn_CGenMapNodeToEnum const DQN_CGEN_TABLE_KEY_LIST[] =
|
||||
{
|
||||
{Dqn_CGenTableKeyType_Name, DQN_STR8("name")},
|
||||
{Dqn_CGenTableKeyType_Type, DQN_STR8("type")},
|
||||
};
|
||||
|
||||
Dqn_CGenMapNodeToEnum const DQN_CGEN_TABLE_TYPE_LIST[] =
|
||||
{
|
||||
{Dqn_CGenTableType_Data, DQN_STR8("data") },
|
||||
{Dqn_CGenTableType_CodeGenBuiltinTypes, DQN_STR8("code_gen_builtin_types")},
|
||||
{Dqn_CGenTableType_CodeGenStruct, DQN_STR8("code_gen_struct") },
|
||||
{Dqn_CGenTableType_CodeGenEnum, DQN_STR8("code_gen_enum") },
|
||||
};
|
||||
|
||||
Dqn_CGenMapNodeToEnum const DQN_CGEN_TABLE_ROW_TAG_LIST[] =
|
||||
{
|
||||
{Dqn_CGenTableRowTagType_CommentDivider, DQN_STR8("comment_divider")},
|
||||
{Dqn_CGenTableRowTagType_EmptyLine, DQN_STR8("empty_line")},
|
||||
};
|
||||
|
||||
Dqn_CGenMapNodeToEnum const DQN_CGEN_TABLE_ROW_TAG_COMMENT_DIVIDER_KEY_LIST[] =
|
||||
{
|
||||
{Dqn_CGenTableRowTagCommentDivider_Label, DQN_STR8("label")},
|
||||
};
|
||||
|
||||
Dqn_CGenTableHeaderType const DQN_CGEN_TABLE_CODE_GEN_STRUCT_HEADER_LIST[] =
|
||||
{
|
||||
Dqn_CGenTableHeaderType_Name,
|
||||
Dqn_CGenTableHeaderType_Table,
|
||||
Dqn_CGenTableHeaderType_CppType,
|
||||
Dqn_CGenTableHeaderType_CppName,
|
||||
Dqn_CGenTableHeaderType_CppIsPtr,
|
||||
Dqn_CGenTableHeaderType_CppArraySize,
|
||||
Dqn_CGenTableHeaderType_CppArraySizeField,
|
||||
Dqn_CGenTableHeaderType_GenTypeInfo,
|
||||
};
|
||||
|
||||
Dqn_CGenTableHeaderType const DQN_CGEN_TABLE_CODE_GEN_ENUM_HEADER_LIST[] =
|
||||
{
|
||||
Dqn_CGenTableHeaderType_Name,
|
||||
Dqn_CGenTableHeaderType_Table,
|
||||
Dqn_CGenTableHeaderType_CppName,
|
||||
Dqn_CGenTableHeaderType_CppValue,
|
||||
Dqn_CGenTableHeaderType_GenTypeInfo,
|
||||
Dqn_CGenTableHeaderType_GenEnumCount,
|
||||
};
|
||||
|
||||
Dqn_CGenTableHeaderType const DQN_CGEN_TABLE_CODE_GEN_BUILTIN_TYPES_HEADER_LIST[] =
|
||||
{
|
||||
Dqn_CGenTableHeaderType_Name,
|
||||
};
|
||||
|
||||
static bool Dqn_CGen_GatherTables_(Dqn_CGen *cgen, Dqn_ErrorSink *error)
|
||||
{
|
||||
bool result = false;
|
||||
if (!cgen || !cgen->file_list || !cgen->arena)
|
||||
return result;
|
||||
|
||||
// NOTE: Gather the tables /////////////////////////////////////////////////////////////////////
|
||||
for (MD_EachNode(ref, cgen->file_list->first_child)) {
|
||||
MD_Node *root = MD_ResolveNodeFromReference(ref);
|
||||
for (MD_EachNode(node, root->first_child)) {
|
||||
|
||||
MD_Node *table_tag = MD_TagFromString(node, MD_S8Lit("table"), 0);
|
||||
if (MD_NodeIsNil(table_tag))
|
||||
continue;
|
||||
|
||||
Dqn_CGenTable *table = MD_PushArray(cgen->arena, Dqn_CGenTable, 1);
|
||||
table->node = node;
|
||||
table->name = table_tag->first_child->first_child->string;
|
||||
MD_MapInsert(cgen->arena, &cgen->table_map, MD_MapKeyStr(table->name), table);
|
||||
MD_QueuePush(cgen->first_table, cgen->last_table, table);
|
||||
|
||||
for (MD_EachNode(key, table_tag->first_child)) {
|
||||
Dqn_CGenMapNodeToEnum key_mapping = Dqn_CGen_MapNodeToEnumOrExit(key,
|
||||
DQN_CGEN_TABLE_KEY_LIST,
|
||||
DQN_ARRAY_UCOUNT(DQN_CGEN_TABLE_KEY_LIST),
|
||||
"Table specified invalid key");
|
||||
switch (DQN_CAST(Dqn_CGenTableKeyType)key_mapping.enum_val) {
|
||||
case Dqn_CGenTableKeyType_Nil: DQN_INVALID_CODE_PATH;
|
||||
|
||||
case Dqn_CGenTableKeyType_Name: {
|
||||
table->name = key->first_child->string;
|
||||
} break;
|
||||
|
||||
case Dqn_CGenTableKeyType_Type: {
|
||||
MD_Node *table_type_value = key->first_child;
|
||||
Dqn_CGenMapNodeToEnum table_type_validator = Dqn_CGen_MapNodeToEnumOrExit(table_type_value,
|
||||
DQN_CGEN_TABLE_TYPE_LIST,
|
||||
DQN_ARRAY_UCOUNT(DQN_CGEN_TABLE_TYPE_LIST),
|
||||
"Table 'type' specified invalid value");
|
||||
table->type = DQN_CAST(Dqn_CGenTableType) table_type_validator.enum_val;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Parse the tables //////////////////////////////////////////////////////////////////////
|
||||
Dqn_usize const BEGIN_COLUMN_INDEX = 1; /*Reserve 0th slot for nil-entry*/
|
||||
for (Dqn_CGenTable *table = cgen->first_table; table; table = table->next) {
|
||||
table->column_count = BEGIN_COLUMN_INDEX;
|
||||
table->headers_node = table->node->first_child;
|
||||
for (MD_EachNode(column_node, table->headers_node->first_child))
|
||||
table->column_count++;
|
||||
|
||||
if (table->column_count == BEGIN_COLUMN_INDEX)
|
||||
continue;
|
||||
|
||||
MD_Node *row_it = table->headers_node->next;
|
||||
for (MD_EachNode(row_node, row_it))
|
||||
table->row_count++;
|
||||
|
||||
table->rows = MD_PushArray(cgen->arena, Dqn_CGenTableRow, table->row_count);
|
||||
table->headers = MD_PushArray(cgen->arena, Dqn_CGenTableHeader, table->column_count);
|
||||
for (Dqn_usize index = 0; index < table->row_count; index++) {
|
||||
Dqn_CGenTableRow *row = table->rows + index;
|
||||
row->columns = MD_PushArray(cgen->arena, Dqn_CGenTableColumn, table->column_count);
|
||||
}
|
||||
|
||||
// NOTE: Collect table headers /////////////////////////////////////////////////////////////
|
||||
table->headers_map = MD_MapMake(cgen->arena);
|
||||
Dqn_usize column_index = BEGIN_COLUMN_INDEX;
|
||||
for (MD_EachNode(header_column, table->headers_node->first_child)) {
|
||||
DQN_ASSERT(column_index < table->column_count);
|
||||
|
||||
// NOTE: Detect builtin headers and cache the index for that table /////////////////////
|
||||
for (Dqn_usize enum_index = 0; enum_index < Dqn_CGenTableHeaderType_Count; enum_index++) {
|
||||
Dqn_Str8 decl_str8 = Dqn_CGen_TableHeaderTypeToDeclStr8(DQN_CAST(Dqn_CGenTableHeaderType)enum_index);
|
||||
if (decl_str8 != Dqn_Str8_Init(header_column->string.str, header_column->string.size))
|
||||
continue;
|
||||
table->column_indexes[enum_index] = column_index;
|
||||
break;
|
||||
}
|
||||
|
||||
MD_MapInsert(cgen->arena, &table->headers_map, MD_MapKeyStr(header_column->string), DQN_CAST(void *)column_index);
|
||||
table->headers[column_index++].name = header_column->string;
|
||||
}
|
||||
|
||||
// NOTE: Validate table headers ////////////////////////////////////////////////////////////
|
||||
switch (table->type) {
|
||||
case Dqn_CGenTableType_Nil: DQN_INVALID_CODE_PATH;
|
||||
|
||||
case Dqn_CGenTableType_Data: {
|
||||
} break;
|
||||
|
||||
case Dqn_CGenTableType_CodeGenStruct: {
|
||||
for (Dqn_CGenTableHeaderType enum_val : DQN_CGEN_TABLE_CODE_GEN_STRUCT_HEADER_LIST) {
|
||||
if (table->column_indexes[enum_val] == 0) {
|
||||
Dqn_Str8 expected_value = Dqn_CGen_TableHeaderTypeToDeclStr8(enum_val);
|
||||
Dqn_CGen_LogF(MD_MessageKind_Error, table->headers_node, error, "Struct code generation table is missing column '%.*s'", DQN_STR_FMT(expected_value));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case Dqn_CGenTableType_CodeGenEnum: {
|
||||
for (Dqn_CGenTableHeaderType enum_val : DQN_CGEN_TABLE_CODE_GEN_ENUM_HEADER_LIST) {
|
||||
if (table->column_indexes[enum_val] == 0) {
|
||||
Dqn_Str8 expected_value = Dqn_CGen_TableHeaderTypeToDeclStr8(enum_val);
|
||||
Dqn_CGen_LogF(MD_MessageKind_Error, table->headers_node, error, "Enum code generation table is missing column '%.*s'", DQN_STR_FMT(expected_value));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case Dqn_CGenTableType_CodeGenBuiltinTypes: {
|
||||
for (Dqn_CGenTableHeaderType enum_val : DQN_CGEN_TABLE_CODE_GEN_BUILTIN_TYPES_HEADER_LIST) {
|
||||
if (table->column_indexes[enum_val] == 0) {
|
||||
Dqn_Str8 expected_value = Dqn_CGen_TableHeaderTypeToDeclStr8(enum_val);
|
||||
Dqn_CGen_LogF(MD_MessageKind_Error, table->headers_node, error, "Enum code generation table is missing column '%.*s'", DQN_STR_FMT(expected_value));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
// NOTE: Parse each row in table ///////////////////////////////////////////////////////////
|
||||
Dqn_usize row_index = 0;
|
||||
for (MD_EachNode(row_node, row_it)) {
|
||||
column_index = BEGIN_COLUMN_INDEX;
|
||||
DQN_ASSERT(row_index < table->row_count);
|
||||
|
||||
// NOTE: Parse any tags set on the row /////////////////////////////////////////////////
|
||||
Dqn_CGenTableRow *row = table->rows + row_index++;
|
||||
for (MD_EachNode(row_tag, row_node->first_tag)) {
|
||||
Dqn_CGenMapNodeToEnum row_mapping = Dqn_CGen_MapNodeToEnumOrExit(row_tag,
|
||||
DQN_CGEN_TABLE_ROW_TAG_LIST,
|
||||
DQN_ARRAY_UCOUNT(DQN_CGEN_TABLE_ROW_TAG_LIST),
|
||||
"Table specified invalid row tag");
|
||||
Dqn_CGenTableRowTag *tag = MD_PushArray(cgen->arena, Dqn_CGenTableRowTag, 1);
|
||||
tag->type = DQN_CAST(Dqn_CGenTableRowTagType) row_mapping.enum_val;
|
||||
MD_QueuePush(row->first_tag, row->last_tag, tag);
|
||||
|
||||
switch (tag->type) {
|
||||
case Dqn_CGenTableRowTagType_Nil: DQN_INVALID_CODE_PATH;
|
||||
|
||||
case Dqn_CGenTableRowTagType_CommentDivider: {
|
||||
for (MD_EachNode(tag_key, row_tag->first_child)) {
|
||||
Dqn_CGenMapNodeToEnum tag_mapping = Dqn_CGen_MapNodeToEnumOrExit(tag_key,
|
||||
DQN_CGEN_TABLE_ROW_TAG_COMMENT_DIVIDER_KEY_LIST,
|
||||
DQN_ARRAY_UCOUNT(DQN_CGEN_TABLE_ROW_TAG_COMMENT_DIVIDER_KEY_LIST),
|
||||
"Table specified invalid row tag");
|
||||
switch (DQN_CAST(Dqn_CGenTableRowTagCommentDivider)tag_mapping.enum_val) {
|
||||
case Dqn_CGenTableRowTagCommentDivider_Nil: DQN_INVALID_CODE_PATH;
|
||||
case Dqn_CGenTableRowTagCommentDivider_Label: {
|
||||
tag->comment = tag_key->first_child->string;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case Dqn_CGenTableRowTagType_EmptyLine: break;
|
||||
}
|
||||
}
|
||||
|
||||
for (MD_EachNode(column_node, row_node->first_child)) {
|
||||
table->headers[column_index].longest_string = DQN_MAX(table->headers[column_index].longest_string, DQN_CAST(int) column_node->string.size);
|
||||
row->columns[column_index].string = Dqn_CGen_MDToDqnStr8(column_node->string);
|
||||
row->columns[column_index].node = column_node;
|
||||
column_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Validate codegen //////////////////////////////////////////////////////////////////////
|
||||
Dqn_CGenTableHeaderType const CHECK_COLUMN_LINKS[] = {
|
||||
Dqn_CGenTableHeaderType_CppName,
|
||||
Dqn_CGenTableHeaderType_CppType,
|
||||
Dqn_CGenTableHeaderType_CppValue,
|
||||
Dqn_CGenTableHeaderType_CppIsPtr,
|
||||
Dqn_CGenTableHeaderType_CppArraySize,
|
||||
Dqn_CGenTableHeaderType_CppArraySizeField,
|
||||
};
|
||||
|
||||
result = true;
|
||||
for (Dqn_CGenTable *table = cgen->first_table; table; table = table->next) {
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it);) {
|
||||
for (Dqn_CGenTableHeaderType check_column : CHECK_COLUMN_LINKS) {
|
||||
Dqn_CGenTableColumn column = it.cgen_table_row->columns[table->column_indexes[check_column]];
|
||||
if (column.string.size == 0) {
|
||||
// NOTE: The code generation table did not bind a code generation parameter to
|
||||
// a column in the target table. We skip it.
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: Check if the column to bind to exists in the target table.
|
||||
if (!MD_MapLookup(&it.table->headers_map, MD_MapKeyStr(Dqn_CGen_DqnToMDStr8(column.string)))) {
|
||||
result = false;
|
||||
Dqn_Str8 header_type_str8 = Dqn_CGen_TableHeaderTypeToDeclStr8(check_column);
|
||||
Dqn_CGen_LogF(MD_MessageKind_Error, column.node, error,
|
||||
"Code generation table binds '%.*s' to '%.*s', but the column '%.*s' does not exist in table '%.*s'\n"
|
||||
"NOTE: If you want '%.*s' to omit the column '%.*s' you can bind to the empty string `` to skip it, otherwise, please ensure the table '%.*s' has the column '%.*s'"
|
||||
,
|
||||
DQN_STR_FMT(column.string),
|
||||
DQN_STR_FMT(header_type_str8),
|
||||
DQN_STR_FMT(column.string),
|
||||
MD_S8VArg(it.table->name),
|
||||
MD_S8VArg(it.table->name),
|
||||
DQN_STR_FMT(header_type_str8),
|
||||
MD_S8VArg(it.table->name),
|
||||
DQN_STR_FMT(header_type_str8));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_CGen Dqn_CGen_InitFilesArgV(int argc, char const **argv, Dqn_ErrorSink *error)
|
||||
{
|
||||
Dqn_CGen result = {};
|
||||
result.arena = MD_ArenaAlloc();
|
||||
result.file_list = MD_MakeList(result.arena);
|
||||
result.table_map = MD_MapMake(result.arena);
|
||||
|
||||
bool has_error = false;
|
||||
for (Dqn_isize arg_index = 0; arg_index < argc; arg_index++) {
|
||||
MD_String8 file_name = MD_S8CString(DQN_CAST(char *)argv[arg_index]);
|
||||
MD_ParseResult parse_result = MD_ParseWholeFile(result.arena, file_name);
|
||||
for (MD_Message *message = parse_result.errors.first; message != 0; message = message->next) {
|
||||
MD_CodeLoc code_loc = MD_CodeLocFromNode(message->node);
|
||||
has_error = true;
|
||||
Dqn_CGen_LogF(message->kind, message->node, error, "%.*s", MD_S8VArg(message->string));
|
||||
}
|
||||
MD_PushNewReference(result.arena, result.file_list, parse_result.node);
|
||||
}
|
||||
|
||||
if (!has_error)
|
||||
Dqn_CGen_GatherTables_(&result, error);
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_Str8 Dqn_CGen_TableHeaderTypeToDeclStr8(Dqn_CGenTableHeaderType type)
|
||||
{
|
||||
Dqn_Str8 result = {};
|
||||
switch (type) {
|
||||
case Dqn_CGenTableHeaderType_Name: result = DQN_STR8("name"); break;
|
||||
case Dqn_CGenTableHeaderType_Table: result = DQN_STR8("table"); break;
|
||||
case Dqn_CGenTableHeaderType_CppType: result = DQN_STR8("cpp_type"); break;
|
||||
case Dqn_CGenTableHeaderType_CppName: result = DQN_STR8("cpp_name"); break;
|
||||
case Dqn_CGenTableHeaderType_CppValue: result = DQN_STR8("cpp_value"); break;
|
||||
case Dqn_CGenTableHeaderType_CppIsPtr: result = DQN_STR8("cpp_is_ptr"); break;
|
||||
case Dqn_CGenTableHeaderType_CppArraySize: result = DQN_STR8("cpp_array_size"); break;
|
||||
case Dqn_CGenTableHeaderType_CppArraySizeField: result = DQN_STR8("cpp_array_size_field"); break;
|
||||
case Dqn_CGenTableHeaderType_GenTypeInfo: result = DQN_STR8("gen_type_info"); break;
|
||||
case Dqn_CGenTableHeaderType_GenEnumCount: result = DQN_STR8("gen_enum_count"); break;
|
||||
case Dqn_CGenTableHeaderType_Count: result = DQN_STR8("XX BAD ENUM VALUE XX"); break;
|
||||
default: result = DQN_STR8("XX INVALID ENUM VALUE XX"); break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_CGenMapNodeToEnum Dqn_CGen_MapNodeToEnumOrExit(MD_Node const *node, Dqn_CGenMapNodeToEnum const *valid_keys, Dqn_usize valid_keys_size, char const *fmt, ...)
|
||||
{
|
||||
Dqn_CGenMapNodeToEnum result = {};
|
||||
for (Dqn_usize index = 0; index < valid_keys_size; index++) {
|
||||
Dqn_CGenMapNodeToEnum const *validator = valid_keys + index;
|
||||
if (Dqn_Str8_Init(node->string.str, node->string.size) == validator->node_string) {
|
||||
result = *validator;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.enum_val == 0) {
|
||||
MD_CodeLoc loc = MD_CodeLocFromNode(DQN_CAST(MD_Node *)node);
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Dqn_Str8 user_msg = Dqn_Str8_InitFV(scratch.arena, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
Dqn_Str8Builder builder = {};
|
||||
builder.arena = scratch.arena;
|
||||
|
||||
Dqn_Str8Builder_AppendF(&builder, "%.*s: '%.*s' is not recognised, the supported values are ", DQN_STR_FMT(user_msg), MD_S8VArg(node->string));
|
||||
for (Dqn_usize index = 0; index < valid_keys_size; index++) {
|
||||
Dqn_CGenMapNodeToEnum const *validator = valid_keys + index;
|
||||
Dqn_Str8Builder_AppendF(&builder, DQN_CAST(char *)"%s'%.*s'", index ? ", " : "", DQN_STR_FMT(validator->node_string));
|
||||
}
|
||||
|
||||
Dqn_Str8 error_msg = Dqn_Str8Builder_Build(&builder, scratch.arena);
|
||||
MD_PrintMessageFmt(stderr, loc, MD_MessageKind_Error, DQN_CAST(char *) "%.*s", DQN_STR_FMT(error_msg));
|
||||
Dqn_OS_Exit(DQN_CAST(uint32_t)-1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API void Dqn_CGen_LogF(MD_MessageKind kind, MD_Node *node, Dqn_ErrorSink *error, char const *fmt, ...)
|
||||
{
|
||||
if (!error)
|
||||
return;
|
||||
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8Builder builder = {};
|
||||
builder.arena = scratch.arena;
|
||||
|
||||
MD_String8 kind_string = MD_StringFromMessageKind(kind);
|
||||
MD_CodeLoc loc = MD_CodeLocFromNode(node);
|
||||
Dqn_Str8Builder_AppendF(&builder, "" MD_FmtCodeLoc " %.*s: ", MD_CodeLocVArg(loc), MD_S8VArg(kind_string));
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Dqn_Str8Builder_AppendFV(&builder, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
Dqn_Str8 msg = Dqn_Str8Builder_Build(&builder, scratch.arena);
|
||||
Dqn_ErrorSink_MakeF(error, DQN_CAST(uint32_t)-1, "%.*s", DQN_STR_FMT(msg));
|
||||
}
|
||||
|
||||
DQN_API bool Dqn_CGen_TableHasHeaders(Dqn_CGenTable const *table, Dqn_Str8 const *headers, Dqn_usize header_count, Dqn_ErrorSink *error)
|
||||
{
|
||||
bool result = true;
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8Builder builder = {};
|
||||
builder.arena = scratch.arena;
|
||||
|
||||
for (Dqn_usize index = 0; index < header_count; index++) {
|
||||
Dqn_Str8 header = headers[index];
|
||||
MD_String8 header_md = {DQN_CAST(MD_u8 *) header.data, header.size};
|
||||
MD_MapSlot *slot = MD_MapLookup(DQN_CAST(MD_Map *)&table->headers_map, MD_MapKeyStr(header_md));
|
||||
if (!slot) {
|
||||
result = false;
|
||||
Dqn_Str8Builder_AppendF(&builder, "%s%.*s", builder.count ? ", " : "", DQN_STR_FMT(header));
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
Dqn_Str8 missing_headers = Dqn_Str8Builder_Build(&builder, scratch.arena);
|
||||
Dqn_CGen_LogF(MD_MessageKind_Error, table->headers_node, error, "Table '%.*s' is missing the header(s): %.*s", MD_S8VArg(table->name), DQN_STR_FMT(missing_headers));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_CGenLookupColumnAtHeader Dqn_CGen_LookupColumnAtHeader(Dqn_CGenTable *table, Dqn_Str8 header, Dqn_CGenTableRow const *row)
|
||||
{
|
||||
Dqn_CGenLookupColumnAtHeader result = {};
|
||||
if (!table || !row)
|
||||
return result;
|
||||
|
||||
MD_String8 header_md = {DQN_CAST(MD_u8 *) header.data, header.size};
|
||||
MD_MapSlot *slot = MD_MapLookup(&table->headers_map, MD_MapKeyStr(header_md));
|
||||
if (!slot)
|
||||
return result;
|
||||
|
||||
Dqn_usize column_index = DQN_CAST(Dqn_usize) slot->val;
|
||||
DQN_ASSERT(column_index < table->column_count);
|
||||
{
|
||||
Dqn_usize begin = DQN_CAST(uintptr_t)(table->rows);
|
||||
Dqn_usize end = DQN_CAST(uintptr_t)(table->rows + table->row_count);
|
||||
Dqn_usize ptr = DQN_CAST(uintptr_t)row;
|
||||
DQN_ASSERTF(ptr >= begin && ptr <= end, "The row to lookup does not belong to the table passed in");
|
||||
}
|
||||
|
||||
result.index = column_index;
|
||||
result.column = row->columns[column_index];
|
||||
result.header = table->headers[column_index];
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API bool Dqn_CGen_LookupNextTableInCodeGenTable(Dqn_CGen *cgen, Dqn_CGenTable *cgen_table, Dqn_CGenLookupTableIterator *it)
|
||||
{
|
||||
if (!cgen_table)
|
||||
return false;
|
||||
|
||||
if (it->row_index >= cgen_table->row_count)
|
||||
return false;
|
||||
|
||||
if (cgen_table->type != Dqn_CGenTableType_CodeGenEnum && cgen_table->type != Dqn_CGenTableType_CodeGenStruct && cgen_table->type != Dqn_CGenTableType_CodeGenBuiltinTypes)
|
||||
return false;
|
||||
|
||||
// NOTE: Lookup the table in this row that we will code generate from. Not
|
||||
// applicable when we are doing builtin types as the types are just put
|
||||
// in-line into the code generation table itself.
|
||||
it->cgen_table_row = cgen_table->rows + it->row_index++;
|
||||
if (cgen_table->type != Dqn_CGenTableType_CodeGenBuiltinTypes) {
|
||||
Dqn_CGenTableColumn cgen_table_column = it->cgen_table_row->columns[cgen_table->column_indexes[Dqn_CGenTableHeaderType_Table]];
|
||||
MD_String8 key = {DQN_CAST(MD_u8 *)cgen_table_column.string.data, cgen_table_column.string.size};
|
||||
MD_MapSlot *table_slot = MD_MapLookup(&cgen->table_map, MD_MapKeyStr(key));
|
||||
if (!table_slot) {
|
||||
MD_CodeLoc loc = MD_CodeLocFromNode(cgen_table_column.node);
|
||||
MD_PrintMessageFmt(stderr,
|
||||
loc,
|
||||
MD_MessageKind_Warning,
|
||||
DQN_CAST(char *) "Code generation table references non-existent table '%.*s'",
|
||||
DQN_STR_FMT(cgen_table_column.string));
|
||||
return false;
|
||||
}
|
||||
it->table = DQN_CAST(Dqn_CGenTable *) table_slot->val;
|
||||
}
|
||||
|
||||
for (Dqn_usize type = 0; type < Dqn_CGenTableHeaderType_Count; type++)
|
||||
it->cgen_table_column[type] = it->cgen_table_row->columns[cgen_table->column_indexes[type]];
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Dqn_CGen_EmitRowWhitespace_(Dqn_CGenTableRow const *row, Dqn_CppFile *cpp)
|
||||
{
|
||||
for (Dqn_CGenTableRowTag *tag = row->first_tag; tag; tag = tag->next) {
|
||||
switch (tag->type) {
|
||||
case Dqn_CGenTableRowTagType_Nil: DQN_INVALID_CODE_PATH;
|
||||
|
||||
case Dqn_CGenTableRowTagType_CommentDivider: {
|
||||
if (tag->comment.size <= 0)
|
||||
break;
|
||||
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8 prefix = Dqn_Str8_InitF(scratch.arena, "// NOTE: %.*s ", MD_S8VArg(tag->comment));
|
||||
int line_padding = DQN_MAX(100 - (DQN_CAST(int) prefix.size + (Dqn_CppSpacePerIndent(cpp) * cpp->indent)), 0);
|
||||
Dqn_CppPrint(cpp, "%.*s", DQN_STR_FMT(prefix));
|
||||
for (int index = 0; index < line_padding; index++)
|
||||
Dqn_CppAppend(cpp, "/");
|
||||
Dqn_CppAppend(cpp, "\n");
|
||||
} break;
|
||||
|
||||
case Dqn_CGenTableRowTagType_EmptyLine: {
|
||||
Dqn_CppAppend(cpp, "\n");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_CppFile *cpp, Dqn_Str8 emit_prefix)
|
||||
{
|
||||
DQN_ASSERT(Dqn_Str8_HasData(emit_prefix));
|
||||
|
||||
if (emit & Dqn_CGenEmit_Prototypes) {
|
||||
// NOTE: Generate type info enums //////////////////////////////////////////////////////////
|
||||
Dqn_CppEnumBlock(cpp, "%.*s_Type", DQN_STR_FMT(emit_prefix)) {
|
||||
Dqn_CppLine(cpp, "%.*s_Type_Nil,", DQN_STR_FMT(emit_prefix));
|
||||
for (Dqn_CGenTable *table = cgen->first_table; table != 0; table = table->next) {
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it);)
|
||||
Dqn_CppLine(cpp, "%.*s_Type_%.*s,", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string));
|
||||
}
|
||||
Dqn_CppLine(cpp, "%.*s_Type_Count,", DQN_STR_FMT(emit_prefix));
|
||||
}
|
||||
|
||||
// NOTE: Generate structs + enums //////////////////////////////////////////////////////////////
|
||||
for (Dqn_CGenTable *table = cgen->first_table; table != 0; table = table->next) {
|
||||
switch (table->type) {
|
||||
case Dqn_CGenTableType_Nil: DQN_INVALID_CODE_PATH;
|
||||
case Dqn_CGenTableType_Data: continue;
|
||||
|
||||
case Dqn_CGenTableType_CodeGenStruct: {
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it); ) {
|
||||
// TODO(doyle): Verify the codegen table has the headers from the table it references
|
||||
Dqn_CppStructBlock(cpp, "%.*s", DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string)) {
|
||||
for (Dqn_usize row_index = 0; row_index < it.table->row_count; row_index++) {
|
||||
Dqn_CGenTableRow const *row = it.table->rows + row_index;
|
||||
Dqn_CGenLookupColumnAtHeader cpp_name = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppName].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_type = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppType].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_array_size = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppArraySize].string, row);
|
||||
int name_to_type_padding = 1 + it.table->headers[cpp_type.index].longest_string - DQN_CAST(int) cpp_type.column.string.size;
|
||||
if (cpp_name.column.string.size <= 0 || cpp_type.column.string.size <= 0)
|
||||
continue;
|
||||
Dqn_CGen_EmitRowWhitespace_(row, cpp);
|
||||
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8 array_size = {};
|
||||
if (cpp_array_size.column.string.size)
|
||||
array_size = Dqn_Str8_InitF(scratch.arena, "[%.*s]", DQN_STR_FMT(cpp_array_size.column.string));
|
||||
|
||||
Dqn_CppLine(cpp,
|
||||
"%.*s%*s%.*s%.*s;",
|
||||
DQN_STR_FMT(cpp_type.column.string),
|
||||
name_to_type_padding,
|
||||
"",
|
||||
DQN_STR_FMT(cpp_name.column.string),
|
||||
DQN_STR_FMT(array_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case Dqn_CGenTableType_CodeGenEnum: {
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it); ) {
|
||||
Dqn_CppEnumBlock(cpp, "%.*s", DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string)) {
|
||||
Dqn_usize enum_count = 0;
|
||||
for (Dqn_usize row_index = 0; row_index < it.table->row_count; row_index++) {
|
||||
Dqn_CGenTableRow const *row = it.table->rows + row_index;
|
||||
Dqn_CGenLookupColumnAtHeader cpp_name = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppName].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_value = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppValue].string, row);
|
||||
|
||||
if (cpp_name.column.string.size <= 0)
|
||||
continue;
|
||||
|
||||
Dqn_CGen_EmitRowWhitespace_(row, cpp);
|
||||
if (cpp_value.column.string.size) {
|
||||
Dqn_CppLine(cpp,
|
||||
"%.*s_%.*s = %.*s,",
|
||||
DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string),
|
||||
DQN_STR_FMT(cpp_name.column.string),
|
||||
DQN_STR_FMT(cpp_value.column.string));
|
||||
} else {
|
||||
Dqn_CppLine(cpp,
|
||||
"%.*s_%.*s = %zu,",
|
||||
DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string),
|
||||
DQN_STR_FMT(cpp_name.column.string),
|
||||
row_index);
|
||||
}
|
||||
enum_count++;
|
||||
}
|
||||
|
||||
Dqn_CGenTableColumn gen_enum_count_column = it.cgen_table_column[Dqn_CGenTableHeaderType_GenEnumCount];
|
||||
if (gen_enum_count_column.string.size)
|
||||
Dqn_CppLine(cpp,
|
||||
"%.*s_%.*s = %zu,",
|
||||
DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string),
|
||||
DQN_STR_FMT(gen_enum_count_column.string),
|
||||
enum_count);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Generate enums for struct fields //////////////////////////////////////////////////
|
||||
for (Dqn_CGenTable *table = cgen->first_table; table != 0; table = table->next) {
|
||||
switch (table->type) {
|
||||
case Dqn_CGenTableType_Nil: DQN_INVALID_CODE_PATH;
|
||||
case Dqn_CGenTableType_Data: continue;
|
||||
case Dqn_CGenTableType_CodeGenEnum: continue;
|
||||
|
||||
case Dqn_CGenTableType_CodeGenStruct: {
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it); ) {
|
||||
Dqn_Str8 struct_name = it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string;
|
||||
Dqn_CppEnumBlock(cpp, "%.*sTypeField", DQN_STR_FMT(struct_name)) {
|
||||
for (Dqn_usize row_index = 0; row_index < it.table->row_count; row_index++) {
|
||||
Dqn_CGenTableRow const *row = it.table->rows + row_index;
|
||||
Dqn_CGenLookupColumnAtHeader cpp_name = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppName].string, row);
|
||||
if (cpp_name.column.string.size <= 0)
|
||||
continue;
|
||||
Dqn_CGen_EmitRowWhitespace_(row, cpp);
|
||||
Dqn_CppLine(cpp, "%.*sTypeField_%.*s,", DQN_STR_FMT(struct_name), DQN_STR_FMT(cpp_name.column.string));
|
||||
}
|
||||
Dqn_CppLine(cpp, "%.*sTypeField_Count,", DQN_STR_FMT(struct_name));
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (emit & Dqn_CGenEmit_Implementation) {
|
||||
// NOTE: Generate type info ////////////////////////////////////////////////////////////////////
|
||||
for (Dqn_CGenTable *table = cgen->first_table; table != 0; table = table->next) {
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it);) {
|
||||
|
||||
if (table->type == Dqn_CGenTableType_CodeGenBuiltinTypes)
|
||||
continue;
|
||||
|
||||
Dqn_Str8 struct_or_enum_name = it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string;
|
||||
Dqn_CppBlock(cpp, ";\n\n", "Dqn_TypeField const g_%.*s_type_fields[] =", DQN_STR_FMT(struct_or_enum_name)) {
|
||||
if (table->type == Dqn_CGenTableType_CodeGenStruct) {
|
||||
for (Dqn_usize row_index = 0; row_index < it.table->row_count; row_index++) {
|
||||
Dqn_CGenTableRow const *row = it.table->rows + row_index;
|
||||
Dqn_CGenLookupColumnAtHeader cpp_name = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppName].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_type = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppType].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_is_ptr = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppIsPtr].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_array_size = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppArraySize].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_array_size_field = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppArraySizeField].string, row);
|
||||
|
||||
bool cpp_is_ptr_b32 = cpp_is_ptr.column.string == DQN_STR8("true");
|
||||
Dqn_Str8 cpp_array_size_str8 = Dqn_Str8_HasData(cpp_array_size.column.string) ? cpp_array_size.column.string : DQN_STR8("0");
|
||||
|
||||
Dqn_CGenTableColumn struct_name = it.cgen_table_row->columns[table->column_indexes[Dqn_CGenTableHeaderType_Name]];
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8 cpp_array_size_field_str8 = DQN_STR8("NULL");
|
||||
if (cpp_array_size_field.column.string.size) {
|
||||
|
||||
// TODO(doyle): Check that array_size_field references a valid field in the table
|
||||
// NOTE: We use a raw index for the reference because the struct might
|
||||
// not have type info being generated so we can't rely on the enum.
|
||||
Dqn_usize index_the_field_references = 0;
|
||||
for (Dqn_usize sub_row_index = 0; sub_row_index < it.table->row_count; sub_row_index++) {
|
||||
Dqn_CGenTableRow const *sub_row = it.table->rows + sub_row_index;
|
||||
Dqn_CGenTableColumn sub_cpp_name = sub_row->columns[cpp_name.index];
|
||||
if (sub_cpp_name.string == cpp_array_size_field.column.string)
|
||||
index_the_field_references = sub_row_index;
|
||||
}
|
||||
cpp_array_size_field_str8 = Dqn_Str8_InitF(scratch.arena,
|
||||
"&g_%.*s_type_fields[%zu]",
|
||||
DQN_STR_FMT(struct_name.string),
|
||||
index_the_field_references);
|
||||
}
|
||||
|
||||
Dqn_Str8 orig_cpp_type_info = Dqn_Str8_InitF(scratch.arena, "%.*s", DQN_STR_FMT(cpp_type.column.string));
|
||||
Dqn_Str8 cpp_type_info = orig_cpp_type_info;
|
||||
cpp_type_info = Dqn_Str8_Replace(cpp_type_info, /*find*/ DQN_STR8("*"), /*replace*/ DQN_STR8(""), /*start_index*/ 0, scratch.arena, Dqn_Str8EqCase_Sensitive);
|
||||
cpp_type_info = Dqn_Str8_Replace(cpp_type_info, /*find*/ DQN_STR8("constexpr"), /*replace*/ DQN_STR8(""), /*start_index*/ 0, scratch.arena, Dqn_Str8EqCase_Sensitive);
|
||||
cpp_type_info = Dqn_Str8_Replace(cpp_type_info, /*find*/ DQN_STR8("const"), /*replace*/ DQN_STR8(""), /*start_index*/ 0, scratch.arena, Dqn_Str8EqCase_Sensitive);
|
||||
cpp_type_info = Dqn_Str8_Replace(cpp_type_info, /*find*/ DQN_STR8("static"), /*replace*/ DQN_STR8(""), /*start_index*/ 0, scratch.arena, Dqn_Str8EqCase_Sensitive);
|
||||
cpp_type_info = Dqn_Str8_Replace(cpp_type_info, /*find*/ DQN_STR8(" "), /*replace*/ DQN_STR8(""), /*start_index*/ 0, scratch.arena, Dqn_Str8EqCase_Sensitive);
|
||||
|
||||
Dqn_Str8 cpp_type_enum = Dqn_Str8_InitF(scratch.arena, "%.*s_Type_%.*s", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(cpp_type_info));
|
||||
Dqn_usize cpp_name_padding = 1 + it.table->headers[cpp_name.index].longest_string - cpp_name.column.string.size;
|
||||
Dqn_usize cpp_type_padding = 1 + it.table->headers[cpp_type.index].longest_string - cpp_type.column.string.size;
|
||||
Dqn_usize cpp_type_enum_padding = cpp_type_padding + (orig_cpp_type_info.size - cpp_type_info.size);
|
||||
|
||||
Dqn_CppLine(cpp,
|
||||
"{%2d, DQN_STR8(\"%.*s\"),%*s/*value*/ 0, offsetof(%.*s, %.*s),%*ssizeof(((%.*s*)0)->%.*s),%*sDQN_STR8(\"%.*s\"),%*s%.*s,%*s/*is_pointer*/ %s,%s /*array_size*/ %.*s, /*array_size_field*/ %.*s},",
|
||||
row_index,
|
||||
DQN_STR_FMT(cpp_name.column.string),
|
||||
cpp_name_padding, "",
|
||||
|
||||
// NOTE: offsetof(a, b)
|
||||
DQN_STR_FMT(struct_or_enum_name),
|
||||
DQN_STR_FMT(cpp_name.column.string),
|
||||
cpp_name_padding, "",
|
||||
|
||||
// NOTE: sizeof(a->b)
|
||||
DQN_STR_FMT(struct_or_enum_name),
|
||||
DQN_STR_FMT(cpp_name.column.string),
|
||||
cpp_name_padding, "",
|
||||
|
||||
// NOTE: Type string
|
||||
DQN_STR_FMT(cpp_type.column.string),
|
||||
cpp_type_padding, "",
|
||||
|
||||
// NOTE: Type as enum
|
||||
DQN_STR_FMT(cpp_type_enum),
|
||||
cpp_type_enum_padding, "",
|
||||
|
||||
cpp_is_ptr_b32 ? "true" : "false",
|
||||
cpp_is_ptr_b32 ? " " : "",
|
||||
DQN_STR_FMT(cpp_array_size_str8),
|
||||
DQN_STR_FMT(cpp_array_size_field_str8));
|
||||
}
|
||||
} else {
|
||||
DQN_ASSERT(table->type == Dqn_CGenTableType_CodeGenEnum);
|
||||
for (Dqn_usize row_index = 0; row_index < it.table->row_count; row_index++) {
|
||||
Dqn_CGenTableRow const *row = it.table->rows + row_index;
|
||||
Dqn_CGenLookupColumnAtHeader cpp_name = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppName].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_value = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppValue].string, row);
|
||||
if (cpp_name.column.string.size <= 0)
|
||||
continue;
|
||||
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_usize cpp_name_padding = 1 + it.table->headers[cpp_name.index].longest_string - cpp_name.column.string.size;
|
||||
Dqn_Str8 cpp_value_str8 = Dqn_Str8_HasData(cpp_value.column.string) ? cpp_value.column.string : Dqn_Str8_InitF(scratch.arena, "%zu", row_index);
|
||||
Dqn_CppLine(cpp,
|
||||
"{%2d, DQN_STR8(\"%.*s\"),%*s/*value*/ %.*s, /*offset_of*/ 0, sizeof(%.*s), DQN_STR8(\"\"), %.*s_Type_%.*s, /*is_pointer*/ false, /*array_size*/ 0, /*array_size_field*/ NULL},",
|
||||
row_index,
|
||||
|
||||
// NOTE: Name string
|
||||
DQN_STR_FMT(cpp_name.column.string),
|
||||
cpp_name_padding, "",
|
||||
|
||||
// NOTE: Value
|
||||
DQN_STR_FMT(cpp_value_str8),
|
||||
|
||||
// NOTE: sizeof(a)
|
||||
DQN_STR_FMT(struct_or_enum_name),
|
||||
|
||||
// NOTE: ..._Type_...
|
||||
DQN_STR_FMT(emit_prefix),
|
||||
DQN_STR_FMT(struct_or_enum_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int longest_name_across_all_tables = 0;
|
||||
for (Dqn_CGenTable *table = cgen->first_table; table != 0; table = table->next) {
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it);) {
|
||||
longest_name_across_all_tables = DQN_MAX(longest_name_across_all_tables, DQN_CAST(int)it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string.size);
|
||||
}
|
||||
}
|
||||
|
||||
Dqn_CppBlock(cpp, ";\n\n", "Dqn_TypeInfo const g_%.*s_types[] =", DQN_STR_FMT(emit_prefix)) {
|
||||
Dqn_CppLine(cpp, "{DQN_STR8(\"\"),%*sDqn_TypeKind_Nil, /*fields*/ NULL, /*count*/ 0},", 1 + longest_name_across_all_tables, "");
|
||||
for (Dqn_CGenTable *table = cgen->first_table; table != 0; table = table->next) {
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it);) {
|
||||
Dqn_Str8 type_name = it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string;
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
int name_padding = 1 + longest_name_across_all_tables - DQN_CAST(int) type_name.size;
|
||||
|
||||
Dqn_Str8 type_info_kind = {};
|
||||
char const *type_info_kind_padding = "";
|
||||
if (table->type == Dqn_CGenTableType_CodeGenEnum) {
|
||||
type_info_kind = DQN_STR8("Dqn_TypeKind_Enum");
|
||||
type_info_kind_padding = " ";
|
||||
} else if (table->type == Dqn_CGenTableType_CodeGenStruct) {
|
||||
type_info_kind = DQN_STR8("Dqn_TypeKind_Struct");
|
||||
} else {
|
||||
DQN_ASSERT(table->type == Dqn_CGenTableType_CodeGenBuiltinTypes);
|
||||
type_info_kind = DQN_STR8("Dqn_TypeKind_Basic");
|
||||
type_info_kind_padding = " ";
|
||||
}
|
||||
|
||||
Dqn_Str8 fields_count = {};
|
||||
if (table->type == Dqn_CGenTableType_CodeGenBuiltinTypes) {
|
||||
fields_count = DQN_STR8("0");
|
||||
} else {
|
||||
DQN_ASSERT(table->type == Dqn_CGenTableType_CodeGenStruct || table->type == Dqn_CGenTableType_CodeGenEnum);
|
||||
int fields_count_int = 0;
|
||||
for (Dqn_usize row_index = 0; row_index < it.table->row_count; row_index++) {
|
||||
Dqn_CGenTableRow const *row = it.table->rows + row_index;
|
||||
Dqn_CGenLookupColumnAtHeader cpp_name = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppName].string, row);
|
||||
fields_count_int += Dqn_Str8_HasData(cpp_name.column.string);
|
||||
}
|
||||
fields_count = Dqn_Str8_InitF(scratch.arena, "%d", fields_count_int);
|
||||
}
|
||||
|
||||
Dqn_Str8 fields = DQN_STR8("NULL");
|
||||
int fields_padding = 1;
|
||||
if (table->type != Dqn_CGenTableType_CodeGenBuiltinTypes) {
|
||||
fields_padding = name_padding;
|
||||
fields = Dqn_Str8_InitF(scratch.arena, "g_%.*s_type_fields", DQN_STR_FMT(type_name));
|
||||
}
|
||||
|
||||
Dqn_CppLine(cpp,
|
||||
"{DQN_STR8(\"%.*s\"),%*s%.*s, %s/*fields*/ %.*s,%*s/*count*/ %.*s},",
|
||||
DQN_STR_FMT(type_name),
|
||||
name_padding, "",
|
||||
DQN_STR_FMT(type_info_kind),
|
||||
type_info_kind_padding,
|
||||
DQN_STR_FMT(fields),
|
||||
fields_padding, "",
|
||||
DQN_STR_FMT(fields_count));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
166
dqn_cgen.h
Normal file
166
dqn_cgen.h
Normal file
@ -0,0 +1,166 @@
|
||||
#if !defined(DQN_CGEN_H)
|
||||
#define DQN_CGEN_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$$$$$\ $$$$$$\ $$$$$$$$\ $$\ $$\
|
||||
// $$ __$$\ $$ __$$\ $$ _____|$$$\ $$ |
|
||||
// $$ / \__|$$ / \__|$$ | $$$$\ $$ |
|
||||
// $$ | $$ |$$$$\ $$$$$\ $$ $$\$$ |
|
||||
// $$ | $$ |\_$$ |$$ __| $$ \$$$$ |
|
||||
// $$ | $$\ $$ | $$ |$$ | $$ |\$$$ |
|
||||
// \$$$$$$ |\$$$$$$ |$$$$$$$$\ $$ | \$$ |
|
||||
// \______/ \______/ \________|\__| \__|
|
||||
//
|
||||
// dqn_cgen.h -- C/C++ code generation from table data in Metadesk files
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// NOTE: [$CGEN] Dqn_CGen //////////////////////////////////////////////////////////////////////////
|
||||
#if !defined(MD_H)
|
||||
#error Metadesk 'md.h' must be included before 'dqn_cgen.h'
|
||||
#endif
|
||||
|
||||
#if !defined(DQN_H)
|
||||
#error 'dqn.h' must be included before 'dqn_cgen.h'
|
||||
#endif
|
||||
|
||||
#if !defined(DQN_CPP_FILE_H)
|
||||
#error 'dqn_cpp_file.h' must be included before 'dqn_cgen.h'
|
||||
#endif
|
||||
|
||||
enum Dqn_CGenTableKeyType
|
||||
{
|
||||
Dqn_CGenTableKeyType_Nil,
|
||||
Dqn_CGenTableKeyType_Name,
|
||||
Dqn_CGenTableKeyType_Type,
|
||||
};
|
||||
|
||||
enum Dqn_CGenTableType
|
||||
{
|
||||
Dqn_CGenTableType_Nil,
|
||||
Dqn_CGenTableType_Data,
|
||||
Dqn_CGenTableType_CodeGenBuiltinTypes,
|
||||
Dqn_CGenTableType_CodeGenStruct,
|
||||
Dqn_CGenTableType_CodeGenEnum,
|
||||
};
|
||||
|
||||
enum Dqn_CGenTableRowTagType
|
||||
{
|
||||
Dqn_CGenTableRowTagType_Nil,
|
||||
Dqn_CGenTableRowTagType_CommentDivider,
|
||||
Dqn_CGenTableRowTagType_EmptyLine,
|
||||
};
|
||||
|
||||
enum Dqn_CGenTableRowTagCommentDivider
|
||||
{
|
||||
Dqn_CGenTableRowTagCommentDivider_Nil,
|
||||
Dqn_CGenTableRowTagCommentDivider_Label,
|
||||
};
|
||||
|
||||
enum Dqn_CGenTableHeaderType
|
||||
{
|
||||
Dqn_CGenTableHeaderType_Name,
|
||||
Dqn_CGenTableHeaderType_Table,
|
||||
Dqn_CGenTableHeaderType_CppType,
|
||||
Dqn_CGenTableHeaderType_CppName,
|
||||
Dqn_CGenTableHeaderType_CppValue,
|
||||
Dqn_CGenTableHeaderType_CppIsPtr,
|
||||
Dqn_CGenTableHeaderType_CppArraySize,
|
||||
Dqn_CGenTableHeaderType_CppArraySizeField,
|
||||
Dqn_CGenTableHeaderType_GenTypeInfo,
|
||||
Dqn_CGenTableHeaderType_GenEnumCount,
|
||||
Dqn_CGenTableHeaderType_Count,
|
||||
};
|
||||
|
||||
struct Dqn_CGenTableHeader
|
||||
{
|
||||
MD_String8 name;
|
||||
int longest_string;
|
||||
};
|
||||
|
||||
struct Dqn_CGenTableRowTag
|
||||
{
|
||||
Dqn_CGenTableRowTagType type;
|
||||
MD_String8 comment;
|
||||
Dqn_CGenTableRowTag *next;
|
||||
};
|
||||
|
||||
|
||||
struct Dqn_CGenTableColumn
|
||||
{
|
||||
MD_Node *node;
|
||||
Dqn_Str8 string;
|
||||
};
|
||||
|
||||
struct Dqn_CGenTableRow
|
||||
{
|
||||
Dqn_CGenTableRowTag *first_tag;
|
||||
Dqn_CGenTableRowTag *last_tag;
|
||||
Dqn_CGenTableColumn *columns;
|
||||
};
|
||||
|
||||
struct Dqn_CGenTable
|
||||
{
|
||||
Dqn_CGenTableType type;
|
||||
MD_String8 name;
|
||||
MD_Map headers_map;
|
||||
Dqn_CGenTableHeader *headers;
|
||||
Dqn_CGenTableRow *rows;
|
||||
size_t column_count;
|
||||
size_t row_count;
|
||||
|
||||
MD_Node *node;
|
||||
MD_Node *headers_node;
|
||||
Dqn_usize column_indexes[Dqn_CGenTableHeaderType_Count];
|
||||
Dqn_CGenTable *next;
|
||||
};
|
||||
|
||||
struct Dqn_CGen
|
||||
{
|
||||
MD_Arena *arena;
|
||||
MD_Node *file_list;
|
||||
MD_Map table_map;
|
||||
Dqn_CGenTable *first_table;
|
||||
Dqn_CGenTable *last_table;
|
||||
};
|
||||
|
||||
struct Dqn_CGenMapNodeToEnum
|
||||
{
|
||||
uint32_t enum_val;
|
||||
Dqn_Str8 node_string;
|
||||
};
|
||||
|
||||
struct Dqn_CGenLookupTableIterator
|
||||
{
|
||||
Dqn_CGenTableRow *cgen_table_row;
|
||||
Dqn_CGenTableColumn cgen_table_column[Dqn_CGenTableHeaderType_Count];
|
||||
Dqn_CGenTable *table;
|
||||
Dqn_usize row_index;
|
||||
};
|
||||
|
||||
struct Dqn_CGenLookupColumnAtHeader
|
||||
{
|
||||
Dqn_usize index;
|
||||
Dqn_CGenTableHeader header;
|
||||
Dqn_CGenTableColumn column;
|
||||
};
|
||||
|
||||
enum Dqn_CGenEmit
|
||||
{
|
||||
Dqn_CGenEmit_Prototypes = 1 << 0,
|
||||
Dqn_CGenEmit_Implementation = 1 << 1,
|
||||
};
|
||||
|
||||
// NOTE: [$CGEN] Dqn_CGen //////////////////////////////////////////////////////////////////////////
|
||||
#define Dqn_CGen_MDToDqnStr8(str8) Dqn_Str8_Init((str8).str, (str8).size)
|
||||
#define Dqn_CGen_DqnToMDStr8(str8) {DQN_CAST(MD_u8 *)(str8).data, (str8).size}
|
||||
DQN_API Dqn_CGen Dqn_CGen_InitFilesArgV (int argc, char const **argv, Dqn_ErrorSink *error);
|
||||
DQN_API Dqn_Str8 Dqn_CGen_TableHeaderTypeToDeclStr8 (Dqn_CGenTableHeaderType type);
|
||||
DQN_API Dqn_CGenMapNodeToEnum Dqn_CGen_MapNodeToEnumOrExit (MD_Node const *node, Dqn_CGenMapNodeToEnum const *valid_keys, Dqn_usize valid_keys_size, char const *fmt, ...);
|
||||
DQN_API void Dqn_CGen_LogF (MD_MessageKind kind, MD_Node *node, Dqn_ErrorSink *error, char const *fmt, ...);
|
||||
DQN_API bool Dqn_CGen_TableHasHeaders (Dqn_CGenTable const *table, Dqn_Str8 const *headers, Dqn_usize header_count, Dqn_ErrorSink *error);
|
||||
DQN_API Dqn_CGenLookupColumnAtHeader Dqn_CGen_LookupColumnAtHeader (Dqn_CGenTable *table, Dqn_Str8 header, Dqn_CGenTableRow const *row);
|
||||
DQN_API bool Dqn_CGen_LookupNextTableInCodeGenTable(Dqn_CGen *cgen, Dqn_CGenTable *cgen_table, Dqn_CGenLookupTableIterator *it);
|
||||
DQN_API void Dqn_CGen_EmitCodeForTables (Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_CppFile *cpp, Dqn_Str8 emit_prefix);
|
||||
#endif // DQN_CGEN_H
|
@ -16,7 +16,9 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdlib.h> // exit
|
||||
#if !defined(DQN_H)
|
||||
#error 'dqn.h' must be included before 'dqn_cppbuild.h'
|
||||
#endif
|
||||
|
||||
struct Dqn_CPPBuildCompileFile
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
#define DQN_UTEST_IMPLEMENTATION
|
||||
#include "dqn_utest.h"
|
||||
#include "Standalone/dqn_utest.h"
|
||||
|
||||
static Dqn_UTest Dqn_Test_Arena()
|
||||
{
|
||||
@ -875,7 +875,71 @@ static Dqn_UTest Dqn_Test_Intrinsics()
|
||||
return test;
|
||||
}
|
||||
|
||||
#if defined(DQN_TEST_WITH_KECCAK)
|
||||
#if defined(DQN_UNIT_TESTS_WITH_KECCAK)
|
||||
DQN_GCC_WARNING_PUSH
|
||||
DQN_GCC_WARNING_DISABLE(-Wunused-parameter)
|
||||
DQN_GCC_WARNING_DISABLE(-Wsign-compare)
|
||||
|
||||
DQN_MSVC_WARNING_PUSH
|
||||
DQN_MSVC_WARNING_DISABLE(4244)
|
||||
DQN_MSVC_WARNING_DISABLE(4100)
|
||||
DQN_MSVC_WARNING_DISABLE(6385)
|
||||
// NOTE: Keccak Reference Implementation ///////////////////////////////////////////////////////////
|
||||
// A very compact Keccak implementation taken from the reference implementation
|
||||
// repository
|
||||
//
|
||||
// https://github.com/XKCP/XKCP/blob/master/Standalone/CompactFIPS202/C/Keccak-more-compact.c
|
||||
|
||||
#define FOR(i,n) for(i=0; i<n; ++i)
|
||||
void Dqn_RefImpl_Keccak_(int r, int c, const uint8_t *in, uint64_t inLen, uint8_t sfx, uint8_t *out, uint64_t outLen);
|
||||
void Dqn_RefImpl_FIPS202_SHAKE128_(const uint8_t *in, uint64_t inLen, uint8_t *out, uint64_t outLen) { Dqn_RefImpl_Keccak_(1344, 256, in, inLen, 0x1F, out, outLen); }
|
||||
void Dqn_RefImpl_FIPS202_SHAKE256_(const uint8_t *in, uint64_t inLen, uint8_t *out, uint64_t outLen) { Dqn_RefImpl_Keccak_(1088, 512, in, inLen, 0x1F, out, outLen); }
|
||||
void Dqn_RefImpl_FIPS202_SHA3_224_(const uint8_t *in, uint64_t inLen, uint8_t *out) { Dqn_RefImpl_Keccak_(1152, 448, in, inLen, 0x06, out, 28); }
|
||||
void Dqn_RefImpl_FIPS202_SHA3_256_(const uint8_t *in, uint64_t inLen, uint8_t *out) { Dqn_RefImpl_Keccak_(1088, 512, in, inLen, 0x06, out, 32); }
|
||||
void Dqn_RefImpl_FIPS202_SHA3_384_(const uint8_t *in, uint64_t inLen, uint8_t *out) { Dqn_RefImpl_Keccak_(832, 768, in, inLen, 0x06, out, 48); }
|
||||
void Dqn_RefImpl_FIPS202_SHA3_512_(const uint8_t *in, uint64_t inLen, uint8_t *out) { Dqn_RefImpl_Keccak_(576, 1024, in, inLen, 0x06, out, 64); }
|
||||
|
||||
int Dqn_RefImpl_LFSR86540_(uint8_t *R) { (*R)=((*R)<<1)^(((*R)&0x80)?0x71:0); return ((*R)&2)>>1; }
|
||||
#define ROL(a,o) ((((uint64_t)a)<<o)^(((uint64_t)a)>>(64-o)))
|
||||
|
||||
static uint64_t Dqn_RefImpl_load64_ (const uint8_t *x) { int i; uint64_t u=0; FOR(i,8) { u<<=8; u|=x[7-i]; } return u; }
|
||||
static void Dqn_RefImpl_store64_(uint8_t *x, uint64_t u) { int i; FOR(i,8) { x[i]=u; u>>=8; } }
|
||||
static void Dqn_RefImpl_xor64_ (uint8_t *x, uint64_t u) { int i; FOR(i,8) { x[i]^=u; u>>=8; } }
|
||||
|
||||
#define rL(x,y) Dqn_RefImpl_load64_((uint8_t*)s+8*(x+5*y))
|
||||
#define wL(x,y,l) Dqn_RefImpl_store64_((uint8_t*)s+8*(x+5*y),l)
|
||||
#define XL(x,y,l) Dqn_RefImpl_xor64_((uint8_t*)s+8*(x+5*y),l)
|
||||
|
||||
void Dqn_RefImpl_Keccak_F1600(void *s)
|
||||
{
|
||||
int r,x,y,i,j,Y; uint8_t R=0x01; uint64_t C[5],D;
|
||||
for(i=0; i<24; i++) {
|
||||
/*θ*/ FOR(x,5) C[x]=rL(x,0)^rL(x,1)^rL(x,2)^rL(x,3)^rL(x,4); FOR(x,5) { D=C[(x+4)%5]^ROL(C[(x+1)%5],1); FOR(y,5) XL(x,y,D); }
|
||||
/*ρπ*/ x=1; y=r=0; D=rL(x,y); FOR(j,24) { r+=j+1; Y=(2*x+3*y)%5; x=y; y=Y; C[0]=rL(x,y); wL(x,y,ROL(D,r%64)); D=C[0]; }
|
||||
/*χ*/ FOR(y,5) { FOR(x,5) C[x]=rL(x,y); FOR(x,5) wL(x,y,C[x]^((~C[(x+1)%5])&C[(x+2)%5])); }
|
||||
/*ι*/ FOR(j,7) if (Dqn_RefImpl_LFSR86540_(&R)) XL(0,0,(uint64_t)1<<((1<<j)-1));
|
||||
}
|
||||
}
|
||||
|
||||
void Dqn_RefImpl_Keccak_(int r, int c, const uint8_t *in, uint64_t inLen, uint8_t sfx, uint8_t *out, uint64_t outLen)
|
||||
{
|
||||
/*initialize*/ uint8_t s[200]; int R=r/8; int i,b=0; FOR(i,200) s[i]=0;
|
||||
/*absorb*/ while(inLen>0) { b=(inLen<R)?inLen:R; FOR(i,b) s[i]^=in[i]; in+=b; inLen-=b; if (b==R) { Dqn_RefImpl_Keccak_F1600(s); b=0; } }
|
||||
/*pad*/ s[b]^=sfx; if((sfx&0x80)&&(b==(R-1))) Dqn_RefImpl_Keccak_F1600(s); s[R-1]^=0x80; Dqn_RefImpl_Keccak_F1600(s);
|
||||
/*squeeze*/ while(outLen>0) { b=(outLen<R)?outLen:R; FOR(i,b) out[i]=s[i]; out+=b; outLen-=b; if(outLen>0) Dqn_RefImpl_Keccak_F1600(s); }
|
||||
}
|
||||
|
||||
#undef XL
|
||||
#undef wL
|
||||
#undef rL
|
||||
#undef ROL
|
||||
#undef FOR
|
||||
DQN_MSVC_WARNING_POP
|
||||
DQN_GCC_WARNING_POP
|
||||
|
||||
#define DQN_KECCAK_IMPLEMENTATION
|
||||
#include "Standalone/dqn_keccak.h"
|
||||
|
||||
#define DQN_UTEST_HASH_X_MACRO \
|
||||
DQN_UTEST_HASH_X_ENTRY(SHA3_224, "SHA3-224") \
|
||||
DQN_UTEST_HASH_X_ENTRY(SHA3_256, "SHA3-256") \
|
||||
@ -903,8 +967,8 @@ Dqn_Str8 const DQN_UTEST_HASH_STRING_[] =
|
||||
|
||||
void Dqn_Test_KeccakDispatch_(Dqn_UTest *test, int hash_type, Dqn_Str8 input)
|
||||
{
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8 input_hex = Dqn_Hex_BytesToStr8Arena(scratch.arena, input.data, input.size);
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8 input_hex = Dqn_Bin_BytesToHexArena(scratch.arena, input.data, input.size);
|
||||
|
||||
switch(hash_type)
|
||||
{
|
||||
@ -912,7 +976,7 @@ void Dqn_Test_KeccakDispatch_(Dqn_UTest *test, int hash_type, Dqn_Str8 input)
|
||||
{
|
||||
Dqn_KeccakBytes28 hash = Dqn_SHA3_224StringToBytes28(input);
|
||||
Dqn_KeccakBytes28 expect;
|
||||
FIPS202_SHA3_224(DQN_CAST(u8 *)input.data, input.size, (u8 *)expect.data);
|
||||
Dqn_RefImpl_FIPS202_SHA3_224_(DQN_CAST(uint8_t *)input.data, input.size, (uint8_t *)expect.data);
|
||||
DQN_UTEST_ASSERTF(test,
|
||||
Dqn_KeccakBytes28Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
@ -929,7 +993,7 @@ void Dqn_Test_KeccakDispatch_(Dqn_UTest *test, int hash_type, Dqn_Str8 input)
|
||||
{
|
||||
Dqn_KeccakBytes32 hash = Dqn_SHA3_256StringToBytes32(input);
|
||||
Dqn_KeccakBytes32 expect;
|
||||
FIPS202_SHA3_256(DQN_CAST(u8 *)input.data, input.size, (u8 *)expect.data);
|
||||
Dqn_RefImpl_FIPS202_SHA3_256_(DQN_CAST(uint8_t *)input.data, input.size, (uint8_t *)expect.data);
|
||||
DQN_UTEST_ASSERTF(test,
|
||||
Dqn_KeccakBytes32Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
@ -946,7 +1010,7 @@ void Dqn_Test_KeccakDispatch_(Dqn_UTest *test, int hash_type, Dqn_Str8 input)
|
||||
{
|
||||
Dqn_KeccakBytes48 hash = Dqn_SHA3_384StringToBytes48(input);
|
||||
Dqn_KeccakBytes48 expect;
|
||||
FIPS202_SHA3_384(DQN_CAST(u8 *)input.data, input.size, (u8 *)expect.data);
|
||||
Dqn_RefImpl_FIPS202_SHA3_384_(DQN_CAST(uint8_t *)input.data, input.size, (uint8_t *)expect.data);
|
||||
DQN_UTEST_ASSERTF(test,
|
||||
Dqn_KeccakBytes48Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
@ -963,7 +1027,7 @@ void Dqn_Test_KeccakDispatch_(Dqn_UTest *test, int hash_type, Dqn_Str8 input)
|
||||
{
|
||||
Dqn_KeccakBytes64 hash = Dqn_SHA3_512StringToBytes64(input);
|
||||
Dqn_KeccakBytes64 expect;
|
||||
FIPS202_SHA3_512(DQN_CAST(u8 *)input.data, input.size, (u8 *)expect.data);
|
||||
Dqn_RefImpl_FIPS202_SHA3_512_(DQN_CAST(uint8_t *)input.data, input.size, (uint8_t *)expect.data);
|
||||
DQN_UTEST_ASSERTF(test,
|
||||
Dqn_KeccakBytes64Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
@ -980,7 +1044,7 @@ void Dqn_Test_KeccakDispatch_(Dqn_UTest *test, int hash_type, Dqn_Str8 input)
|
||||
{
|
||||
Dqn_KeccakBytes28 hash = Dqn_Keccak224StringToBytes28(input);
|
||||
Dqn_KeccakBytes28 expect;
|
||||
Keccak(1152, 448, DQN_CAST(u8 *)input.data, input.size, 0x01, (u8 *)expect.data, sizeof(expect));
|
||||
Dqn_RefImpl_Keccak_(1152, 448, DQN_CAST(uint8_t *)input.data, input.size, 0x01, (uint8_t *)expect.data, sizeof(expect));
|
||||
DQN_UTEST_ASSERTF(test,
|
||||
Dqn_KeccakBytes28Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
@ -997,7 +1061,7 @@ void Dqn_Test_KeccakDispatch_(Dqn_UTest *test, int hash_type, Dqn_Str8 input)
|
||||
{
|
||||
Dqn_KeccakBytes32 hash = Dqn_Keccak256StringToBytes32(input);
|
||||
Dqn_KeccakBytes32 expect;
|
||||
Keccak(1088, 512, DQN_CAST(u8 *)input.data, input.size, 0x01, (u8 *)expect.data, sizeof(expect));
|
||||
Dqn_RefImpl_Keccak_(1088, 512, DQN_CAST(uint8_t *)input.data, input.size, 0x01, (uint8_t *)expect.data, sizeof(expect));
|
||||
DQN_UTEST_ASSERTF(test,
|
||||
Dqn_KeccakBytes32Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
@ -1014,7 +1078,7 @@ void Dqn_Test_KeccakDispatch_(Dqn_UTest *test, int hash_type, Dqn_Str8 input)
|
||||
{
|
||||
Dqn_KeccakBytes48 hash = Dqn_Keccak384StringToBytes48(input);
|
||||
Dqn_KeccakBytes48 expect;
|
||||
Keccak(832, 768, DQN_CAST(u8 *)input.data, input.size, 0x01, (u8 *)expect.data, sizeof(expect));
|
||||
Dqn_RefImpl_Keccak_(832, 768, DQN_CAST(uint8_t *)input.data, input.size, 0x01, (uint8_t *)expect.data, sizeof(expect));
|
||||
DQN_UTEST_ASSERTF(test,
|
||||
Dqn_KeccakBytes48Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
@ -1031,7 +1095,7 @@ void Dqn_Test_KeccakDispatch_(Dqn_UTest *test, int hash_type, Dqn_Str8 input)
|
||||
{
|
||||
Dqn_KeccakBytes64 hash = Dqn_Keccak512StringToBytes64(input);
|
||||
Dqn_KeccakBytes64 expect;
|
||||
Keccak(576, 1024, DQN_CAST(u8 *)input.data, input.size, 0x01, (u8 *)expect.data, sizeof(expect));
|
||||
Dqn_RefImpl_Keccak_(576, 1024, DQN_CAST(uint8_t *)input.data, input.size, 0x01, (uint8_t *)expect.data, sizeof(expect));
|
||||
DQN_UTEST_ASSERTF(test,
|
||||
Dqn_KeccakBytes64Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
@ -1061,9 +1125,7 @@ Dqn_UTest Dqn_Test_Keccak()
|
||||
DQN_UTEST_GROUP(test, "Dqn_Keccak")
|
||||
{
|
||||
for (int hash_type = 0; hash_type < Hash_Count; hash_type++) {
|
||||
pcg32_random_t rng = {};
|
||||
pcg32_srandom_r(&rng, 0xd48e'be21'2af8'733d, 0x3f89'3bd2'd6b0'4eef);
|
||||
|
||||
Dqn_PCG32 rng = Dqn_PCG32_Init(0xd48e'be21'2af8'733d);
|
||||
for (Dqn_Str8 input : INPUTS) {
|
||||
Dqn_UTest_Begin(&test, "%.*s - Input: %.*s", DQN_STR_FMT(DQN_UTEST_HASH_STRING_[hash_type]), DQN_CAST(int)DQN_MIN(input.size, 54), input.data);
|
||||
Dqn_Test_KeccakDispatch_(&test, hash_type, input);
|
||||
@ -1071,22 +1133,22 @@ Dqn_UTest Dqn_Test_Keccak()
|
||||
}
|
||||
|
||||
Dqn_UTest_Begin(&test, "%.*s - Deterministic random inputs", DQN_STR_FMT(DQN_UTEST_HASH_STRING_[hash_type]));
|
||||
for (int index = 0; index < 128; index++) {
|
||||
for (Dqn_usize index = 0; index < 128; index++) {
|
||||
char src[4096] = {};
|
||||
uint32_t src_size = pcg32_boundedrand_r(&rng, sizeof(src));
|
||||
uint32_t src_size = Dqn_PCG32_Range(&rng, 0, sizeof(src));
|
||||
|
||||
for (int src_index = 0; src_index < src_size; src_index++)
|
||||
src[src_index] = pcg32_boundedrand_r(&rng, 255);
|
||||
for (Dqn_usize src_index = 0; src_index < src_size; src_index++)
|
||||
src[src_index] = DQN_CAST(char)Dqn_PCG32_Range(&rng, 0, 255);
|
||||
|
||||
Dqn_Str8 input = Dqn_Str8_Init(src, src_size);
|
||||
TestKeccakDispatch_(&test, hash_type, input);
|
||||
Dqn_Test_KeccakDispatch_(&test, hash_type, input);
|
||||
}
|
||||
Dqn_UTest_End(&test);
|
||||
}
|
||||
}
|
||||
return test;
|
||||
}
|
||||
#endif // defined(DQN_TEST_WITH_KECCAK)
|
||||
#endif // defined(DQN_UNIT_TESTS_WITH_KECCAK)
|
||||
|
||||
static Dqn_UTest Dqn_Test_M4()
|
||||
{
|
||||
@ -1836,7 +1898,7 @@ void Dqn_Test_RunSuite()
|
||||
Dqn_Test_Fs(),
|
||||
Dqn_Test_FixedArray(),
|
||||
Dqn_Test_Intrinsics(),
|
||||
#if defined(DQN_TEST_WITH_KECCAK)
|
||||
#if defined(DQN_UNIT_TESTS_WITH_KECCAK)
|
||||
Dqn_Test_Keccak(),
|
||||
#endif
|
||||
Dqn_Test_M4(),
|
||||
@ -1860,7 +1922,7 @@ void Dqn_Test_RunSuite()
|
||||
fprintf(stdout, "Summary: %d/%d tests succeeded\n", total_good_tests, total_tests);
|
||||
}
|
||||
|
||||
#if defined(DQN_TEST_WITH_MAIN)
|
||||
#if defined(DQN_UNIT_TESTS_WITH_MAIN)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
(void)argv; (void)argc;
|
||||
|
Loading…
Reference in New Issue
Block a user