diff --git a/Cargo.toml b/Cargo.toml index 8eace12..c4ca5d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,5 @@ chumsky = "0.9.0" ariadne = "0.2" laddertypes = { path = "../lib-laddertypes", features = ["pretty"] } tiny-ansi = { version = "0.1.0" } +clap = { version = "4.5.37", features = ["derive"] } +walkdir = "2.5.0" diff --git a/examples/01-uint-example/.gitignore b/examples/01-uint-example/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/examples/01-uint-example/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/examples/01-uint-example/main.c b/examples/01-uint-example/main.c new file mode 100644 index 0000000..2db8422 --- /dev/null +++ b/examples/01-uint-example/main.c @@ -0,0 +1,14 @@ +#include "morphisms.h" + +int main(int argc, char* argv[]) { + if( argc > 1 ) { + uint64_t value; + demarshal( argv[1], &value ); + + uint64_t result = value * value; + + char buf[256]; + marshal( &result, buf ); + printf("%s\n", buf); + } +} diff --git a/examples/01-uint-example/makefile b/examples/01-uint-example/makefile new file mode 100644 index 0000000..915101b --- /dev/null +++ b/examples/01-uint-example/makefile @@ -0,0 +1,23 @@ +all: build/square +.PHONY: build clean + +build: + mkdir -p build + +build/morphisms.h: build + ldmc \ + -m "marshal: \ + ℕ ~ native.UInt64 \ + --> ℕ ~ <PosInt 10 BigEndian> ~ <Seq~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8> \ + " \ + -m "demarshal: \ + ℕ ~ <PosInt 10 BigEndian> ~ <Seq~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8> \ + --> ℕ ~ native.UInt64 \ + " \ + -o build/morphisms.h + +build/square: build build/morphisms.h + gcc -Os -I../../morphisms/runtime/include/ -Ibuild main.c -o build/square + +clean: + rm build/ -rf diff --git a/morphisms/angle.morphism-base b/morphisms/angle.morphism-base index 71aba96..e678dde 100644 --- a/morphisms/angle.morphism-base +++ b/morphisms/angle.morphism-base @@ -3,70 +3,44 @@ ``` morph_angle_as_degrees_to_turns_float () - Angle ~ Degrees ~ ℝ ~ native.Float ---> Angle ~ Turns ~ ℝ ~ native.Float -``` - *dst = *src / 360.0; - return 0; -``` + Angle ~ Degrees ~ ℝ ~ native.Float32 +--> Angle ~ Turns ~ ℝ ~ native.Float32 +```*dst = *src / 360.0;``` morph_angle_as_degrees_to_turns_double () - Angle ~ Degrees ~ ℝ ~ native.Double ---> Angle ~ Turns ~ ℝ ~ native.Double -``` - *dst = *src / 360.0; - return 0; -``` + Angle ~ Degrees ~ ℝ ~ native.Float64 +--> Angle ~ Turns ~ ℝ ~ native.Float64 +```*dst = *src / 360.0;``` morph_angle_as_turns_to_degrees_float () - Angle ~ Turns ~ ℝ ~ native.Float ---> Angle ~ Degrees ~ ℝ ~ native.Float -``` - *dst = *src * 360.0; - return 0; -``` + Angle ~ Turns ~ ℝ ~ native.Float32 +--> Angle ~ Degrees ~ ℝ ~ native.Float32 +```*dst = *src * 360.0;``` morph_angle_as_turns_to_degrees_double () - Angle ~ Turns ~ ℝ ~ native.Double ---> Angle ~ Degrees ~ ℝ ~ native.Double -``` - *dst = *src * 360.0; - return 0; -``` - - + Angle ~ Turns ~ ℝ ~ native.Float64 +--> Angle ~ Degrees ~ ℝ ~ native.Float64 +```*dst = *src * 360.0;``` morph_angle_as_radians_to_turns_float () - Angle ~ Radians ~ ℝ ~ native.Float ---> Angle ~ Turns ~ ℝ ~ native.Float -``` - *dst = *src / PHI; - return 0; -``` + Angle ~ Radians ~ ℝ ~ native.Float32 +--> Angle ~ Turns ~ ℝ ~ native.Float32 +```*dst = *src / PHI;``` morph_angle_as_radians_to_turns_double () - Angle ~ Radians ~ ℝ ~ native.Double ---> Angle ~ Turns ~ ℝ ~ native.Double -``` - *dst = *src / PHI; - return 0; -``` + Angle ~ Radians ~ ℝ ~ native.Float64 +--> Angle ~ Turns ~ ℝ ~ native.Float64 +```*dst = *src / PHI;``` morph_angle_as_turns_to_radians_float () - Angle ~ Turns ~ ℝ ~ native.Float ---> Angle ~ Radians ~ ℝ ~ native.Float -``` - *dst = *src * PHI; - return 0; -``` + Angle ~ Turns ~ ℝ ~ native.Float32 +--> Angle ~ Radians ~ ℝ ~ native.Float32 +```*dst = *src * PHI;``` morph_angle_as_degrees_to_radians_double () - Angle ~ Turns ~ ℝ ~ native.Double ---> Angle ~ Radians ~ ℝ ~ native.Double -``` - *dst = *src * PHI; - return 0; -``` + Angle ~ Turns ~ ℝ ~ native.Float64 +--> Angle ~ Radians ~ ℝ ~ native.Float64 +```*dst = *src * PHI;``` diff --git a/morphisms/digit.morphism-base b/morphisms/digit.morphism-base index a92fe61..75ab631 100644 --- a/morphisms/digit.morphism-base +++ b/morphisms/digit.morphism-base @@ -36,7 +36,7 @@ morph_digit_as_char_to_uint64 (Radix:ℤ) else if( *src >= 'A' && *src <= 'F') *dst = 0xa + *src - 'A'; else { - fprintf(stderr, "invalid digit 0x%x\n", *src); + fprintf(stderr, "invalid digit 0x%x (radix %u)\n", *src, Radix); return -1; } @@ -60,8 +60,6 @@ morph_digit_as_uint8_to_char (Radix:ℤ_16) fprintf(stderr, "digit %u is out of rage for char\n", *dst); return -1; } - - return 0; ``` morph_digit_as_uint64_to_char (Radix:ℤ_16) @@ -76,6 +74,4 @@ morph_digit_as_uint64_to_char (Radix:ℤ_16) fprintf(stderr, "digit %u is out of rage for char\n", *dst); return -1; } - - return 0; ``` diff --git a/morphisms/length_prefix.morphism-base b/morphisms/length_prefix.morphism-base index 6718c16..70cd3b7 100644 --- a/morphisms/length_prefix.morphism-base +++ b/morphisms/length_prefix.morphism-base @@ -3,28 +3,44 @@ #include <array/length-prefix.h> ``` -morph_array_as_valterm_to_lenpfx (Terminator:native.UInt8) - <Seq~<ValueTerminated Terminator> native.UInt8> ---> <Seq~<LengthPrefix native.UInt64> native.UInt8> +morph_array_as_static_to_lenpfx (Len: ℤ, T: Type) + <Seq~<StaticLength Len> T> +--> <Seq~<LengthPrefix native.UInt64> T> ``` - length_prefix_uint64_t_array_uint8_t_clear(dst); + PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, clear)( dst ); + for( nativeUInt64 i = 0; i < Len; ++i ) + PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, push)( dst, src->items[i] ); +``` + +morph_array_as_lenpfx_to_static (Len: ℤ, T: Type) + <Seq~<LengthPrefix native.UInt64> T> +--> <Seq~<StaticLength Len> T> +``` + nativeUInt64 i; + for( i = 0; i < Len && i < src->len; ++i ) + dst->items[i] = src->items[i]; + + if( i < Len ) + memset( &dst[i], 0, (Len-i) * sizeof(T) ); +``` + +morph_array_as_valterm_to_lenpfx (T: Type, Terminator:T) + <Seq~<ValueTerminated Terminator> T> +--> <Seq~<LengthPrefix native.UInt64> T> +``` + PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, push)( dst ); while( *src != Terminator ) - length_prefix_uint64_t_array_uint8_t_push(dst, *src++); - - return 0; + PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, push)( dst, *src++ ); ``` - -morph_array_as_lenpfx_to_valterm (Terminator:native.UInt8) - <Seq~<LengthPrefix native.UInt64> native.UInt8> ---> <Seq~<ValueTerminated Terminator> native.UInt8> +morph_array_as_lenpfx_to_valterm (T: Type, Terminator: T) + <Seq~<LengthPrefix native.UInt64> T> +--> <Seq~<ValueTerminated Terminator> T> ``` for( uint64_t i = 0; i < src->len; ++i ) *dst++ = src->items[i]; *dst = Terminator; - - return 0; ``` morph_array_as_lenpfx_to_continuation_bit (T:Type) @@ -33,15 +49,13 @@ morph_array_as_lenpfx_to_continuation_bit (T:Type) ``` for( uint64_t i = 0; i < src->len; ++i ) { const size_t n_bits = 8*sizeof(T); - if( src->items[i] & (1<<(n_bits-1)) ) { - fprintf(stderr, "error: value to high for MsbContinuation\n"); + if( src->items[i] & ((uint64_t)1<<(n_bits-1)) ) { + fprintf(stderr, "error: value has MSB set, while being used in MsbContinuation sequence!\n"); return -1; } dst[i] = src->items[i]; if( i+1 < src->len ) - dst[i] |= (1<<(n_bits-1)); + dst[i] |= ((uint64_t)1<<(n_bits-1)); } - - return 0; ``` diff --git a/morphisms/posint.morphism-base b/morphisms/posint.morphism-base index 194399b..9036520 100644 --- a/morphisms/posint.morphism-base +++ b/morphisms/posint.morphism-base @@ -11,7 +11,6 @@ morph_nat_as_u64_to_pos () ``` dst->len = 1; dst->items[0] = *src; - return 0; ``` morph_nat_as_pos_to_u64 (Endianness:Type) @@ -22,7 +21,6 @@ morph_nat_as_pos_to_u64 (Endianness:Type) ~ native.UInt64 ``` *dst = src->items[0]; - return 0; ``` morph_posint_radix_le (SrcRadix:ℤ, DstRadix:ℤ) @@ -40,20 +38,18 @@ morph_posint_radix_le (SrcRadix:ℤ, DstRadix:ℤ) value += src->items[src->len - i - 1]; } - length_prefix_uint64_t_array_uint64_t_clear( dst ); + length_prefix_nativeUInt64_array_nativeUInt64_clear( dst ); #if DstRadix==0 - length_prefix_uint64_t_array_uint64_t_push( dst, value ); + length_prefix_nativeUInt64_array_nativeUInt64_push( dst, value ); #else if( value == 0 ) { - length_prefix_uint64_t_array_uint64_t_push( dst, 0 ); + length_prefix_nativeUInt64_array_nativeUInt64_push( dst, 0 ); } else while( value > 0 ) { - length_prefix_uint64_t_array_uint64_t_push( dst, value % DstRadix ); + length_prefix_nativeUInt64_array_nativeUInt64_push( dst, value % DstRadix ); value /= DstRadix; } #endif - - return 0; ``` morph_posint_radix_be (SrcRadix:ℤ, DstRadix:ℤ) @@ -91,8 +87,6 @@ morph_posint_radix_be (SrcRadix:ℤ, DstRadix:ℤ) value /= DstRadix; } #endif - - return 0; ``` morph_posint_endianness (Radix:ℤ) @@ -103,7 +97,7 @@ morph_posint_endianness (Radix:ℤ) ~ <PosInt Radix BigEndian> ~ <Seq~<LengthPrefix native.UInt64> <Digit Radix> ~ native.UInt64> ``` - return length_prefix_uint64_t_array_uint64_t_reverse( src, dst ); + return length_prefix_nativeUInt64_array_nativeUInt64_reverse( src, dst ); ``` morph_posint_endianness (Radix:ℤ) @@ -114,5 +108,5 @@ morph_posint_endianness (Radix:ℤ) ~ <PosInt Radix LittleEndian> ~ <Seq~<LengthPrefix native.UInt64> <Digit Radix> ~ native.UInt64> ``` - return length_prefix_uint64_t_array_uint64_t_reverse( src, dst ); + return length_prefix_nativeUInt64_array_nativeUInt64_reverse( src, dst ); ``` diff --git a/morphisms/real.morphism-base b/morphisms/real.morphism-base index 3302f80..5b5b2f7 100644 --- a/morphisms/real.morphism-base +++ b/morphisms/real.morphism-base @@ -4,102 +4,87 @@ morph_real_as_decimalstr_to_float () ℝ ~ <PosInt 10 BigEndian> ~ <Seq~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8> ---> ℝ ~ native.Float -``` - sscanf(src, "%f", dst); - return 0; -``` +--> ℝ ~ native.Float32 +```sscanf(src, "%f", dst);``` morph_real_as_decimalstr_to_double () ℝ ~ <PosInt 10 BigEndian> ~ <Seq~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8> ---> ℝ ~ native.Double -``` - sscanf(src, "%lf", dst); - return 0; -``` +--> ℝ ~ native.Float64 +```sscanf(src, "%lf", dst);``` morph_real_as_float_to_decimalstr () - ℝ ~ native.Float + ℝ ~ native.Float32 --> ℝ ~ <PosInt 10 BigEndian> ~ <Seq~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8> -``` - sprintf(dst, "%f", *src); - return 0; -``` +```sprintf(dst, "%f", *src);``` morph_real_as_double_to_decimalstr () - ℝ ~ native.Double + ℝ ~ native.Float64 --> ℝ ~ <PosInt 10 BigEndian> ~ <Seq~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8> -``` - sprintf(dst, "%f", *src); - return 0; -``` - +```sprintf(dst, "%f", *src);``` morph_real_as_float_to_double () - ℝ ~ native.Float ---> ℝ ~ native.Double -``` - *dst = *src; - return 0; -``` + ℝ ~ native.Float32 +--> ℝ ~ native.Float64 +```*dst = *src;``` morph_real_as_double_to_float () - ℝ ~ native.Double ---> ℝ ~ native.Float + ℝ ~ native.Float64 +--> ℝ ~ native.Float32 ``` fprintf(stderr, "Warning: morphin Double -> Float. Precision loss!"); *dst = *src; - return 0; ``` morph_real_as_u64_to_float () ℝ ~ ℕ ~ native.UInt64 ---> ℝ ~ native.Float +--> ℝ ~ native.Float32 ``` fprintf(stderr, "Warning: morphin UInt64 -> Float. Precision loss!"); *dst = *src; - return 0; ``` morph_real_as_u64_to_double () ℝ ~ ℕ ~ native.UInt64 ---> ℝ ~ native.Double +--> ℝ ~ native.Float64 ``` fprintf(stderr, "Warning: morphin UInt64 -> Double. Precision loss!"); *dst = *src; - return 0; +``` + + +morph_real_as_nat_to_quantized_linear () + ℝ ~ ℕ ~ native.UInt64 +--> ℝ ~ <QuantizedLinear 0 1 1> ~ ℕ ~ native.UInt64 +``` + *dst = *src; ``` morph_real_as_quantized_linear_to_float (Begin: ℝ, End: ℝ, Steps: ℤ) ℝ ~ <QuantizedLinear Begin End Steps> ~ ℕ ~ native.UInt64 ---> ℝ ~ native.Float +--> ℝ ~ native.Float32 ``` *dst = (float)Begin + ( *src * ((float)End - (float)Begin) ) / (float)Steps; - return 0; ``` morph_real_as_float_to_quantized_linear (Begin: ℝ, End: ℝ, Steps: ℤ) - ℝ ~ native.Float + ℝ ~ native.Float32 --> ℝ ~ <QuantizedLinear Begin End Steps> ~ ℕ ~ native.UInt64 ``` *dst = ((*src - (float)Begin) * (float)Steps) / ((float)End - (float)Begin); - return 0; ``` morph_real_as_quantized_linear_to_double (Begin: ℝ, End: ℝ, Steps: ℤ) ℝ ~ <QuantizedLinear Begin End Steps> ~ ℕ ~ native.UInt64 ---> ℝ ~ native.Double +--> ℝ ~ native.Float64 ``` *dst = (double)Begin + ( *src * ((double)End - (double)Begin) ) / (double)Steps; - return 0; ``` morph_real_as_double_to_quantized_linear (Begin: ℝ, End: ℝ, Steps: ℤ) - ℝ ~ native.Double + ℝ ~ native.Float64 --> ℝ ~ <QuantizedLinear Begin End Steps> ~ ℕ ~ native.UInt64 ``` *dst = ((*src - (double)Begin) * (double)Steps) / ((double)End - (double)Begin); - return 0; ``` diff --git a/morphisms/runtime/include/array/length-prefix.h b/morphisms/runtime/include/array/length-prefix.h index 35a4aec..e61f8ac 100644 --- a/morphisms/runtime/include/array/length-prefix.h +++ b/morphisms/runtime/include/array/length-prefix.h @@ -2,27 +2,37 @@ #include <stdio.h> #include <stdint.h> +/* +typedef struct { \ + LEN_TYPE len; \ + ITEM_TYPE items[]; \ +} __Seq__LengthPrefix_##LEN_TYPE##___##ITEM_TYPE##_; \ + */ \ + +#define LENGTH_PREFIX_ARRAY_TYPE(LEN_TYPE, ITEM_TYPE) \ + __Seq__LengthPrefix_##LEN_TYPE##___##ITEM_TYPE##_ + +#define LENGTH_PREFIX_ARRAY_CALL(LEN_TYPE, ITEM_TYPE, METHOD) \ + length_prefix_##LEN_TYPE##_array_##ITEM_TYPE##_ ## METHOD + +#define PRESCAN_LENGTH_PREFIX_CALL(LEN, ITEM, METHOD) \ + LENGTH_PREFIX_ARRAY_CALL(LEN, ITEM, METHOD) #define DEFINE_LENGTH_PREFIX_ARRAY(LEN_TYPE, ITEM_TYPE) \ - typedef struct { \ - LEN_TYPE len; \ - ITEM_TYPE items[]; \ - } LengthPrefix_##LEN_TYPE##_Array_##ITEM_TYPE; \ - \ - static inline void length_prefix_##LEN_TYPE##_array_##ITEM_TYPE##_clear( \ - LengthPrefix_##LEN_TYPE##_Array_##ITEM_TYPE *data) { \ + static inline void PRESCAN_LENGTH_PREFIX_CALL(LEN_TYPE, ITEM_TYPE, clear) \ + (__Seq__LengthPrefix_##LEN_TYPE##___##ITEM_TYPE##_ *data) { \ data->len = 0; \ } \ \ - static inline void length_prefix_##LEN_TYPE##_array_##ITEM_TYPE##_push( \ - LengthPrefix_##LEN_TYPE##_Array_##ITEM_TYPE *data, \ + static inline void PRESCAN_LENGTH_PREFIX_CALL(LEN_TYPE, ITEM_TYPE, push) \ + (__Seq__LengthPrefix_##LEN_TYPE##___##ITEM_TYPE##_ *data, \ ITEM_TYPE value) { \ data->items[data->len++] = value; \ } \ \ - static inline int length_prefix_##LEN_TYPE##_array_##ITEM_TYPE##_reverse( \ - LengthPrefix_##LEN_TYPE##_Array_##ITEM_TYPE const * restrict src, \ - LengthPrefix_##LEN_TYPE##_Array_##ITEM_TYPE *restrict dst) { \ + static inline int PRESCAN_LENGTH_PREFIX_CALL(LEN_TYPE, ITEM_TYPE, reverse) \ + ( __Seq__LengthPrefix_##LEN_TYPE##___##ITEM_TYPE##_ const * restrict src, \ + __Seq__LengthPrefix_##LEN_TYPE##___##ITEM_TYPE##_ *restrict dst) { \ for (LEN_TYPE i = 0; i < src->len; i++) { \ dst->items[i] = src->items[src->len - 1 - i]; \ } \ @@ -30,60 +40,11 @@ return 0; \ } \ \ - static inline void length_prefix_##LEN_TYPE##_array_##ITEM_TYPE##_dump( \ - LengthPrefix_##LEN_TYPE##_Array_##ITEM_TYPE const * data) { \ + static inline void PRESCAN_LENGTH_PREFIX_CALL(LEN_TYPE, ITEM_TYPE, dump) \ + ( __Seq__LengthPrefix_##LEN_TYPE##___##ITEM_TYPE##_ const * data) { \ printf("Length: %llu\n", (unsigned long long) data->len); \ for (LEN_TYPE i = 0; i < data->len; i++) { \ printf("%llu ", (unsigned long long) data->items[i]); \ } \ printf("\n"); \ } - -#define DEFINE_ALL_LENGTH_PREFIX_ARRAYS(LEN_TYPE) \ - DEFINE_LENGTH_PREFIX_ARRAY(LEN_TYPE, uint8_t) \ - DEFINE_LENGTH_PREFIX_ARRAY(LEN_TYPE, uint16_t) \ - DEFINE_LENGTH_PREFIX_ARRAY(LEN_TYPE, uint32_t) \ - DEFINE_LENGTH_PREFIX_ARRAY(LEN_TYPE, uint64_t) - -DEFINE_ALL_LENGTH_PREFIX_ARRAYS(uint8_t) -DEFINE_ALL_LENGTH_PREFIX_ARRAYS(uint16_t) -DEFINE_ALL_LENGTH_PREFIX_ARRAYS(uint32_t) -DEFINE_ALL_LENGTH_PREFIX_ARRAYS(uint64_t) - - -#define DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, SRC_ITEM_TYPE, DST_ITEM_TYPE) \ - static inline int length_prefix_##LEN_TYPE##_array_map_##SRC_ITEM_TYPE##_to_##DST_ITEM_TYPE( \ - int (*f)(SRC_ITEM_TYPE const * restrict, DST_ITEM_TYPE * restrict), \ - LengthPrefix_##LEN_TYPE##_Array_##SRC_ITEM_TYPE const * restrict src, \ - LengthPrefix_##LEN_TYPE##_Array_##DST_ITEM_TYPE * restrict dst) \ - { \ - if (dst->len < src->len) return -1; /* Ensure enough space */ \ - for (LEN_TYPE i = 0; i < src->len; i++) { \ - if (f(&src->items[i], &dst->items[i]) != 0) return -1; \ - } \ - dst->len = src->len; \ - return 0; \ - } - -#define DEFINE_ALL_MAPS(LEN_TYPE) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint8_t, uint8_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint8_t, uint16_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint8_t, uint32_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint8_t, uint64_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint16_t, uint8_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint16_t, uint16_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint16_t, uint32_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint16_t, uint64_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint32_t, uint8_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint32_t, uint16_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint32_t, uint32_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint32_t, uint64_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint64_t, uint8_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint64_t, uint16_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint64_t, uint32_t) \ - DEFINE_LENGTH_PREFIX_ARRAY_MAP(LEN_TYPE, uint64_t, uint64_t) - -DEFINE_ALL_MAPS(uint8_t) -DEFINE_ALL_MAPS(uint16_t) -DEFINE_ALL_MAPS(uint32_t) -DEFINE_ALL_MAPS(uint64_t) diff --git a/morphisms/temperature.morphism-base b/morphisms/temperature.morphism-base index 7831292..329a6b0 100644 --- a/morphisms/temperature.morphism-base +++ b/morphisms/temperature.morphism-base @@ -2,33 +2,21 @@ ``` morph_celsius_to_kelvin () - Temperature ~ Celsius ~ ℝ ~ native.Float ---> Temperature ~ Kelvin ~ ℝ ~ native.Float -``` - *dst = *src + 273.15; - return 0; -``` + Temperature ~ Celsius ~ ℝ ~ native.Float32 +--> Temperature ~ Kelvin ~ ℝ ~ native.Float32 +```*dst = *src + 273.15;``` morph_kelvin_to_celsius () - Temperature ~ Kelvin ~ ℝ ~ native.Float ---> Temperature ~ Celsius ~ ℝ ~ native.Float -``` - *dst = *src - 273.15; - return 0; -``` + Temperature ~ Kelvin ~ ℝ ~ native.Float32 +--> Temperature ~ Celsius ~ ℝ ~ native.Float32 +```*dst = *src - 273.15;``` morph_celsius_to_fahrenheit () - Temperature ~ Celsius ~ ℝ ~ native.Float ---> Temperature ~ Fahrenheit ~ ℝ ~ native.Float -``` - *dst = (*src * 9.0 / 5.0) + 32.0; - return 0; -``` + Temperature ~ Celsius ~ ℝ ~ native.Float32 +--> Temperature ~ Fahrenheit ~ ℝ ~ native.Float32 +```*dst = (*src * 9.0 / 5.0) + 32.0;``` morph_fahrenheit_to_celsius () - Temperature ~ Fahrenheit ~ ℝ ~ native.Float ---> Temperature ~ Celsius ~ ℝ ~ native.Float -``` - *dst = (*src - 32.0) * 5.0 / 9.0; - return 0; -``` + Temperature ~ Fahrenheit ~ ℝ ~ native.Float32 +--> Temperature ~ Celsius ~ ℝ ~ native.Float32 +```*dst = (*src - 32.0) * 5.0 / 9.0;``` diff --git a/morphisms/timepoint.morphism-base b/morphisms/timepoint.morphism-base index bb66aec..505ed37 100644 --- a/morphisms/timepoint.morphism-base +++ b/morphisms/timepoint.morphism-base @@ -11,5 +11,4 @@ morph_unixtime_to_iso () if (!timeinfo) return -1; strftime((char*)dst, 20, "%Y-%m-%dT%H:%M:%SZ", timeinfo); - return 0; ``` diff --git a/morphisms/uint.morphism-base b/morphisms/uint.morphism-base new file mode 100644 index 0000000..89f8f79 --- /dev/null +++ b/morphisms/uint.morphism-base @@ -0,0 +1,17 @@ +``` +``` + +morph_nat_as_u8_to_u16 () + ℕ ~ native.UInt8 +--> ℕ ~ native.UInt16 +```*dst = *src;``` + +morph_nat_as_u16_to_u32 () + ℕ ~ native.UInt16 +--> ℕ ~ native.UInt32 +```*dst = *src;``` + +morph_nat_as_u32_to_u64 () + ℕ ~ native.UInt32 +--> ℕ ~ native.UInt64 +```*dst = *src;``` diff --git a/morphisms/unicode.morphism-base b/morphisms/unicode.morphism-base index c2854e5..659357b 100644 --- a/morphisms/unicode.morphism-base +++ b/morphisms/unicode.morphism-base @@ -28,7 +28,6 @@ morph_string_as_utf8_to_ascii () } } *dst = 0; - return 0; ``` morph_string_as_ascii_to_utf32 () @@ -39,7 +38,6 @@ morph_string_as_ascii_to_utf32 () ``` while( *src ) { *dst++ = *src++; } *dst = 0; - return 0; ``` morph_string_as_utf8_to_utf32 () @@ -89,6 +87,4 @@ morph_string_as_utf8_to_utf32 () *dst++ = val; *dst++ = 0; - - return 0; ``` diff --git a/morphisms/value_delim.morphism-base b/morphisms/value_delim.morphism-base index a370682..d4ab039 100644 --- a/morphisms/value_delim.morphism-base +++ b/morphisms/value_delim.morphism-base @@ -3,7 +3,7 @@ #include <stdlib.h> ``` -morph_seqseq_valsep_uint8 (T: Type, SrcDelim: T, DstDelim: T) +morph_valsep_delim (T: Type, SrcDelim: T, DstDelim: T) < Seq <Seq T> > ~ < ValueSep SrcDelim T > ~ < Seq~<LengthPrefix native.UInt64> T > @@ -12,23 +12,24 @@ morph_seqseq_valsep_uint8 (T: Type, SrcDelim: T, DstDelim: T) ~ < ValueSep DstDelim T > ~ < Seq~<LengthPrefix native.UInt64> T > ``` - length_prefix_uint64_t_array_uint8_t_clear( dst ); + PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, clear)( dst ); uint8_t * dst_items = dst->items; for( uint64_t i = 0; i < src->len; ++i ) { if( src->items[i] == SrcDelim ) { - length_prefix_uint64_t_array_uint8_t_push( dst, DstDelim ); + PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, push)( dst, DstDelim ); } else if( src->items[i] == DstDelim ) { if( DstDelim == '\n' ) { - length_prefix_uint64_t_array_uint8_t_push( dst, '\\' ); - length_prefix_uint64_t_array_uint8_t_push( dst, 'n' ); + PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, push)( dst, '\\' ); + PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, push)( dst, 'n' ); + } else { + PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, push)( dst, '\\' ); + PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, push)( dst, DstDelim ); } } else { - length_prefix_uint64_t_array_uint8_t_push( dst, src->items[i] ); + PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, push)( dst, src->items[i] ); } } - - return 0; ``` @@ -44,30 +45,28 @@ morph_seqseq_as_valsep_to_lenpfx (T: Type, Delim: T, EscKey: T) ~ native.UInt64 > ``` - length_prefix_uint64_t_array_uint64_t_clear( dst ); + length_prefix_nativeUInt64_array_nativeUInt64_clear( dst ); - struct LengthPrefix_uint64_t_Array_uint8_t * cur_item = NULL; + LENGTH_PREFIX_ARRAY_TYPE( nativeUInt64, T ) * cur_item = NULL; - uint8_t const * start = &src->items[0]; - uint8_t const * cur = start; - uint8_t const * end = &src->items[src->len]; + T const * start = &src->items[0]; + T const * cur = start; + T const * end = &src->items[src->len]; while( cur < end ) { if( *cur == Delim || cur+1 == end ) { uint64_t len = cur - start; - cur_item = malloc( sizeof(uint64_t) + sizeof(uint8_t) * len ); + cur_item = malloc( sizeof(uint64_t) + sizeof(T) * len ); cur_item->len = len; memcpy( cur_item->items, start, len ); - length_prefix_uint64_t_array_uint64_t_push( dst, (uint64_t)cur_item ); + length_prefix_nativeUInt64_array_nativeUInt64_push( dst, (uint64_t)cur_item ); start = ++cur; } else { cur++; } } - - return 0; ``` morph_seqeq_as_lenpfx_to_valsep (T: Type, Delim: T, EscKey: T) @@ -81,19 +80,17 @@ morph_seqeq_as_lenpfx_to_valsep (T: Type, Delim: T, EscKey: T) ~ < ValueSep T Delim > ~ < Seq~<LengthPrefix native.UInt64> T > ``` - length_prefix_uint64_t_array_uint8_t_clear( dst ); + PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, clear)( dst ); for( uint64_t i = 0; i < src->len; ++i ) { - LengthPrefix_uint64_t_Array_uint8_t * item = src->items[i]; + LENGTH_PREFIX_ARRAY_TYPE( nativeUInt64, T ) * item = src->items[i]; for( uint64_t j = 0; j < item->len; ++j ) { - length_prefix_uint64_t_array_uint8_t_push( items->items[j] ); + PRESCAN_LENGTH_PREFIX_CALL( nativeUInt64, T, push )( items->items[j] ); } if( i+1 < src->len ) { - length_prefix_uint64_t_array_uint8_t_push( Delim ); + PRESCAN_LENGTH_PREFIX_CALL( nativeUInt64, T, push )( Delim ); } } - - return 0; ``` diff --git a/morphisms/zigzag.morphism-base b/morphisms/zigzag.morphism-base index 5a293e2..4196e72 100644 --- a/morphisms/zigzag.morphism-base +++ b/morphisms/zigzag.morphism-base @@ -10,8 +10,6 @@ morph_i64_as_twos_complement_to_zigzag () } else { *dst = (2 * (uint64_t)(- *src)) - 1; } - - return 0; ``` morph_i64_as_zigzag_to_twos_complement () diff --git a/platforms/json.lt b/platforms/json.lt new file mode 100644 index 0000000..8e69138 --- /dev/null +++ b/platforms/json.lt @@ -0,0 +1,100 @@ + +type UTF8-String = <Seq Char~Unicode> ~ UTF-8 ~ <Seq~<ValueTerminated 0> native.UInt8> ; + +type SerializedJson.Value = json.Value + ~ <Enum + <Null json.Null ~ SerializedJson.Null > + <String json.String ~ SerializedJson.String > + <Number json.Number ~ SerializedJson.Number > + <Bool json.Bool ~ SerializedJson.Bool > + <Array json.Array ~ SerializedJson.Array > + <Object json.Object ~ SerializedJson.Object >> + ~ <Seq Char> ; + +type SerializedJson.Null = < Struct~<Seq Char> "\"null\"" > ; + +type SerializedJson.String = <Seq Char> + ~ <Struct~<Seq Char> "\"" <Seq Char> "\""> + ~ <Seq Char> ; + +type SerializedJson.Number = ℝ + ~ <PosInt 10 BigEndian> + ~ <Seq <Digit 10> ~ Char> ; + +type SerializedJson.Bool = Bool + ~ <Enum~<Seq Char> + <True~"\"true\"" <>> + <False~"\"false\"" <>>> + ~ <Seq Char> ; + +type SerializedJson.Array = <Struct~<Seq Char> + "[" + <Seq json.Value> + ~ <ValueSep ',' Char> + ~ <Seq Char> + "]" > + ~ <Seq Char> ; + +type SerializedJson.Object = <Struct~<Seq Char> + "{" + <members <Seq + <Struct~<Seq Char> + <key json.String> + ":" + <value json.Value>>>> + "}" + > + ~ <Seq Char>; + +type parsedJson.Value = json.Value ~ <Enum~native.UInt8 + < parsedJson_Null~0 <> > + < parsedJson_String~1 <Ref UTF8-String> ~ native.Address > + < parsedJson_Int~2 ℝ~ℕ~native.UInt64 > + < parsedJson_Float~2 ℝ~native.Float64 > + < parsedJson_Bool~3 Bool ~ native.UInt8 > + + < parsedJson_Array~4 <Ref <Seq ~ <LengthPrefix native.UInt64> + parsedJsonValue + > + > + ~ native.Address > + + < parsedJson_Object~5 <Ref <Seq ~ <LengthPrefix native.UInt64> + <Struct + <key <Ref UTF8-String> ~ native.Address> + <val parsedJsonValue> + > + > + ~ native.Address >> + ~ <Struct + <tag native.UInt8> + native.UInt64 >; + +parse_json_value () + json.Value ~ UTF8-String +--> json.Value ~ parsedJsonValue +``` + + { + dst->tag = PARSED_JSON_NULL; + dst->parsedJson_Null; + } + + { + dst->tag = PARSED_JSON_STRING; + dst->parsedJson_String = malloc(len); + strncpy(dst->parsedJson_String, src, len); + src += len; + } + + { + dst->tag = PARSED_JSON_NUMBER; + + MORPH( + "ℝ ~ ℕ ~ <PosInt 10 BigEndian> ~ <Seq <Digit 10> ~ Char> ~ UTF8-String", + "ℝ ~ ℕ ~ native.UInt64", + src, + &dst->parsedJson_Number + ); + } +``` diff --git a/platforms/json5.lt b/platforms/json5.lt new file mode 100644 index 0000000..e69de29 diff --git a/platforms/protobuf.lt b/platforms/protobuf.lt new file mode 100644 index 0000000..ce273f6 --- /dev/null +++ b/platforms/protobuf.lt @@ -0,0 +1,3 @@ + +type protobuf.Varint = ℕ ~ <PosInt 128 LittleEndian> ~ <Seq~MsbCont <Digit 128> ~ ℤ_128 ~ native.UInt8> ; +type protobuf.String = <Seq Char ~ Unicode> ~ UTF-8 ~ <Seq ~ <LengthPrefix protobuf.Varint> Byte> ; diff --git a/platforms/spapod.lt b/platforms/spapod.lt new file mode 100644 index 0000000..e69de29 diff --git a/platforms/x86.lt b/platforms/x86.lt new file mode 100644 index 0000000..0348efc --- /dev/null +++ b/platforms/x86.lt @@ -0,0 +1,5 @@ + +type x86.UInt64 = ℤ_2/\64 ~ <PosInt 256 LittleEndian> ~ <Seq~<StaticLength 8> <Digit 256> ~ x86.UInt8 >; +type x86.UInt32 = ℤ_2/\32 ~ <PosInt 256 LittleEndian> ~ <Seq~<StaticLength 4> <Digit 256> ~ x86.UInt8 >; +type x86.UInt16 = ℤ_2^16 ~ <PosInt 256 LittleEndian> ~ <Seq~<StaticLength 2> <Digit 256> ~ x86.UInt8 >; +type x86.UInt8 = ℤ_256 ~ <Posint 2 BigEndian> ~ <Seq~<StaticLength 8> <Digit 2> ~ Bit>; diff --git a/src/c_gen.rs b/src/c_gen.rs deleted file mode 100644 index ac68a93..0000000 --- a/src/c_gen.rs +++ /dev/null @@ -1,419 +0,0 @@ -use { - laddertypes::{TypeDict, TypeTerm, parser::*, unparser::*, morphism::{Morphism, MorphismInstance}}, - crate::morphism::{LdmcPrimCMorphism, LdmcMorphism} -}; - -/* -*/ -pub fn get_c_repr_kind(kind: String) -> Option<String> { - match kind.as_str() { - "ℤ" => Some("uint64_t".into()), - _ => None - } -} - -/* for a given ladder type `t`, get the corresponding C type - */ -pub fn get_c_repr_type(dict: &mut impl TypeDict, t: laddertypes::TypeTerm, skip_pointer: bool) -> Option<String> { - let lnf = t.normalize().decurry().get_lnf_vec(); - - match lnf.last() { - Some(t) => { - if t == &dict.parse("Byte").expect("parse") - || t == &dict.parse("native.UInt8").expect("parse") - || t == &dict.parse("<StaticLength 8 Bit>").expect("parse") - { - Some("uint8_t".into()) - } else if t == &dict.parse("native.UInt16").expect("parse") { - Some("uint16_t".into()) - } else if t == &dict.parse("native.UInt32").expect("parse") { - Some("uint32_t".into()) - } else if t == &dict.parse("native.UInt64").expect("parse") { - Some("uint64_t".into()) - } else if t == &dict.parse("native.Float").expect("parse") { - Some("float".into()) - } else if t == &dict.parse("native.Double").expect("parse") { - Some("double".into()) - } else { - match t { - laddertypes::TypeTerm::App(args) => { - if args[0] == laddertypes::TypeTerm::TypeID(dict.get_typeid(&"LengthPrefix".into()).unwrap()) - { - let length_c_type : String = get_c_repr_type(dict, args[1].clone(), false)?; - let item_c_type : String = get_c_repr_type(dict, args[2].clone(), false)?; - - match length_c_type.as_str() { - "uint8_t" | - "uint16_t" | - "uint32_t" | - "uint64_t" => {} - _ => { - eprintln!("invalid length type!"); - return None; - } - } - match item_c_type.as_str() { - "uint8_t" | - "uint16_t" | - "uint32_t" | - "uint64_t" => {} - _ => { - eprintln!("invalid item type!"); - return None; - } - } - - Some(format!("LengthPrefix_{}_Array_{}", length_c_type, item_c_type)) - } - else if args[0] == laddertypes::TypeTerm::TypeID(dict.get_typeid(&"ValueTerminated".into()).unwrap()) - { - let _delim_val = args[1].clone(); - let c_type = get_c_repr_type(dict, args[2].clone(), false)?; - if skip_pointer { - Some(c_type) - } else { - Some(format!("{} *", c_type)) - } - } - else if args[0] == laddertypes::TypeTerm::TypeID(dict.get_typeid(&"MsbCont".into()).unwrap()) - { - let c_type = get_c_repr_type(dict, args[1].clone(), false)?; - if skip_pointer { - Some(c_type) - } else { - Some(format!("{} *", c_type)) - } - } - else { - None - } - } - - _ => None - } - } - } - None => None - } -} - - -pub fn encode_type_to_symbol(dict: &mut impl TypeDict, t: &laddertypes::TypeTerm)-> String { - match t { - laddertypes::TypeTerm::Char(c) => { - match c { - '.' => format!("_dot_"), - _ => - format!("{}", (*c as u64)) - } - }, - laddertypes::TypeTerm::Num(n) => { - format!("{}", n) - } - laddertypes::TypeTerm::TypeID(ty_id) => { - if let Some(name) = dict.get_typename(ty_id) { - format!("{}", name.replace(".", "_dot_")) - } else { - format!("") - } - } - laddertypes::TypeTerm::Ladder(rs) | - laddertypes::TypeTerm::App(rs) => { - let mut s = String::new(); - for r in rs { - s.push('_'); - s.push_str(&encode_type_to_symbol(dict, r)); - } - s - } - } -} - -pub fn encode_type_to_value(dict: &mut impl TypeDict, t: &laddertypes::TypeTerm) -> String { - dict.unparse(t) -} - - -pub fn generate_main(type_dict: &mut impl TypeDict, path: Vec<MorphismInstance<LdmcMorphism>>, src_type: TypeTerm, dst_type: TypeTerm) { - let mut i = 0; - - /* todo: collect include files from morphism base */ - println!(r#" -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> -#include <stdbool.h> -"#); - - let mut existing_instantiations = Vec::new(); - for morph_inst in path.iter() { - match &morph_inst.m { - LdmcMorphism::Primitive( item_morph ) => { - let name = item_morph.instantiated_symbol_name(type_dict, &morph_inst.σ); - if ! existing_instantiations.contains(&name) { - if let Some(s) = item_morph.generate_instantiation(type_dict, &morph_inst.σ) { - println!("{}", s); - } else { - eprintln!("couldnt generate instance {}", name); - } - existing_instantiations.push( name ); - } - } - LdmcMorphism::LengthPrefixMap { length_prefix_type, item_morph } => { - let name = item_morph.instantiated_symbol_name(type_dict, &morph_inst.σ); - if ! existing_instantiations.contains(&name) { - if let Some(s) = item_morph.generate_instantiation(type_dict, &morph_inst.σ) { - println!("{}", s); - } else { - eprintln!("couldnt generate instance {}", name); - } - - existing_instantiations.push( name ); - } - } - _ => {} - } - } - - println!(r#" -int main() {{ -uint8_t bufA[128]; -uint8_t bufB[128]; - -memset(bufA, 0, sizeof(bufA)); -memset(bufB, 0, sizeof(bufB)); - -char in_str[] = "read :: {} \n"; -char out_str[]= "write:: {} \n"; -write(2, in_str, strlen(in_str)); -write(2, out_str, strlen(out_str)); - -int l = read(0, bufA, sizeof(bufA)); -//fprintf(stderr, "read %d bytes\n", l); - - "#, - type_dict.unparse(&src_type).replace("\\", "\\\\"), - type_dict.unparse(&dst_type).replace("\\", "\\\\") ); - - for morph_inst in path.iter() { - println!(r#" -/* morph to {} - -...with -morph {} ----> {}, -subst σ = {:?}, -halo Ψ = {} -*/"#, - type_dict.unparse(&morph_inst.get_type().dst_type.param_normalize().decurry()), - type_dict.unparse(&morph_inst.m.get_type().src_type), - type_dict.unparse(&morph_inst.m.get_type().dst_type), - morph_inst.σ, - type_dict.unparse(&morph_inst.halo), - ); - morph_inst.m.generate_call(type_dict, &morph_inst.σ, i); - i += 1; - } - - let out_buf = if i%2==0 { "bufA" } else { "bufB" }; - - let is_string = false; - if let Ok((halo, σ)) = laddertypes::subtype_unify( - &dst_type, - &type_dict.parse("<Seq~<ValueTerminated 0> native.UInt8>").unwrap() - ) { - println!(r#" -printf("%s\n", {});"#, out_buf); - } else if let Ok((halo, σ)) = laddertypes::subtype_unify( - &dst_type, - &type_dict.parse("<Seq~<LengthPrefix native.UInt64> native.UInt8>").unwrap() - ) { - println!(r#" - /* write output - */ - {{ - LengthPrefix_uint64_t_Array_uint8_t * buf = (void*){}; - write(1, {}, sizeof(uint64_t) + buf->len); - }}"#, out_buf, out_buf); - } else { - println!(r#" -write(1, {}, sizeof({}));"#, - out_buf, - out_buf - ); - } - - - println!(r#" -return 0; -}} - "#); - - eprintln!("Success: generated C code"); -} - -impl LdmcPrimCMorphism { - pub fn instantiated_symbol_name(&self, dict: &mut impl TypeDict, - σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm>) -> String { - let mut s = self.symbol.clone(); - for (k_id,v) in self.type_args.iter() { - if let Some(val_trm) = σ.get(k_id) { - if let laddertypes::TypeID::Var(var_id) = k_id { - let name = dict.get_varname(*var_id).unwrap(); - let val_str = encode_type_to_symbol(dict, val_trm); - s.push_str(&format!("_{}_{}", name, val_str)); - } - } else { - if let laddertypes::TypeID::Var(var_id) = k_id { - let k = dict.get_varname(*var_id).unwrap(); - s.push_str(&format!("_{:?}_MISSING", k)); - eprintln!("INCOMPLETE MORPHISM INSTANTIATION, missing {} ({})", k, var_id); - } - } - } - s - } - - pub fn expected_c_type_signature(&self, dict: &mut impl TypeDict, - σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm>) -> String { - format!("int {} ({} const * restrict src, {} * restrict dst);", - self.instantiated_symbol_name(dict, σ), - get_c_repr_type(dict, self.src_type.clone(), true).expect("cant get c-repr type for src type"), - get_c_repr_type(dict, self.dst_type.clone(), true).expect("cant get c-repr type for dst type")) - } - - pub fn generate_instantiation(&self, dict: &mut impl TypeDict, σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm>) -> Option<String> { - let mut s = String::new(); - - s.push_str(&format!(r#" -int {} ( {} const * restrict src, {} * restrict dst ) {{ -"#, - self.instantiated_symbol_name(dict, &σ), - get_c_repr_type(dict, self.src_type.clone().apply_substitution(&|k| σ.get(k).cloned()).clone(), true).expect("cant get c-repr-type"), - get_c_repr_type(dict, self.dst_type.clone().apply_substitution(&|k| σ.get(k).cloned()).clone(), true).expect("cant get c-repr-type"), - )); - for (ty_id, kind) in self.type_args.iter() { - if let Some(val) = σ.get(ty_id) { - eprintln!("val = {}", dict.unparse(&val)); - - let type_var_value = - if let Some(c_repr_type) = get_c_repr_type(dict, val.clone(), true) { - c_repr_type - } else { - encode_type_to_value(dict, val) - }; - - s.push_str(&format!(" #define {} {}\n", dict.get_typename(&ty_id).unwrap(), type_var_value)); - } - } - - s.push_str(&self.c_source); - - for (ty_id, kind) in self.type_args.iter() { - s.push_str(&format!("\n #undef {}", dict.get_typename(&ty_id).unwrap())); - } - - s.push_str(&format!(r#" -}} -"#)); - Some(s) - } -} - -impl LdmcMorphism { - pub fn generate_call(&self, dict: &mut impl TypeDict, σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm>, i: u64) { - match self { - LdmcMorphism::Primitive(prim_morph) => { - let src_c_type = get_c_repr_type(dict, prim_morph.src_type.clone().apply_substitution(&|k| σ.get(k).cloned()).clone(), true).expect("cant get c-repr type for src type"); - let dst_c_type = get_c_repr_type(dict, prim_morph.dst_type.clone().apply_substitution(&|k| σ.get(k).cloned()).clone(), true).expect("cant get c-repr type for dst type"); - - let src_buf = if i%2 == 0 { "bufA" } else { "bufB" }; - let dst_buf = if i%2 == 0 { "bufB" } else { "bufA" }; - - println!(r#" - {} - {} const * restrict src = (void*) {}; - {} * restrict dst = (void*) {}; - {} ( src, dst ); - {}"#, - '{', - src_c_type, src_buf, - dst_c_type, dst_buf, - prim_morph.instantiated_symbol_name(dict, σ), - '}'); - } - LdmcMorphism::LengthPrefixMap { length_prefix_type, item_morph } => { - let src_type = self.get_type().src_type.clone().apply_substitution(&|k| σ.get(k).cloned()).clone(); - let dst_type = self.get_type().dst_type.clone().apply_substitution(&|k| σ.get(k).cloned()).clone(); - - eprintln!("length prefix type ={:?}", length_prefix_type); - eprintln!("src_type ={:?}", src_type); - eprintln!("dst_type = {:?}", dst_type); - - dict.add_varname("S".into()); - - let γ_src = laddertypes::unify( - &dict.parse("<Seq~<LengthPrefix S> T>").expect("parse template"), - &src_type - ).expect("cant get src item type"); - - let γ_dst = laddertypes::unify( - &dict.parse("<Seq~<LengthPrefix S> T>").expect("parse template"), - &dst_type - ).expect("cant get dst item type"); - - let src_length_type = γ_src.get(&dict.get_typeid(&"S".into()).unwrap()).expect("cant get src-length type").clone(); - let dst_length_type = γ_src.get(&dict.get_typeid(&"S".into()).unwrap()).expect("cant get dst-length type").clone(); - - let length_type = src_length_type; - - let src_item_type = γ_src.get(&dict.get_typeid(&"T".into()).unwrap()).expect("cant get src-item type").clone(); - let dst_item_type = γ_dst.get(&dict.get_typeid(&"T".into()).unwrap()).expect("cant get src-item type").clone(); - - let length_c_type = get_c_repr_type(dict, length_type, true).expect("cant c-repr type for array length"); - let src_item_c_type = get_c_repr_type(dict, src_item_type, true).expect("cant c-repr type for src item"); - let dst_item_c_type = get_c_repr_type(dict, dst_item_type, true).expect("cant c-repr type for dst item"); - let src_c_type = get_c_repr_type(dict, src_type, true).expect("cant get c-repr type for src type"); - let dst_c_type = get_c_repr_type(dict, dst_type, true).expect("cant get c-repr type for dst type"); - - let map_fn = format!("length_prefix_{}_array_map_{}_to_{}", - length_c_type, src_item_c_type, dst_item_c_type - ); - - let src_buf = if i%2 == 0 { "bufA" } else { "bufB" }; - let dst_buf = if i%2 == 0 { "bufB" } else { "bufA" }; - println!(r#" - {} - {} const * restrict src = (void*) {}; - {} * restrict dst = (void*) {}; - {} ( {}, src, dst ); - {}"#, - '{', - src_c_type, src_buf, - dst_c_type, dst_buf, - map_fn, - item_morph.instantiated_symbol_name(dict, σ), - '}'); - } - LdmcMorphism::ValueDelimMap { delim, item_morph } => { - let src_c_type = get_c_repr_type(dict, item_morph.src_type.clone(), false).expect("cant get c-repr type for src type"); - let dst_c_type = get_c_repr_type(dict, item_morph.dst_type.clone(), false).expect("cant get c-repr type for dst type"); - - let src_buf = if i%2 == 0 { "bufA" } else { "bufB" }; - let dst_buf = if i%2 == 0 { "bufB" } else { "bufA" }; - println!(r#" - {} - {} const * restrict src = (void*) {}; - {} * restrict dst = (void*) {}; - value_delim_array_map_8_to_64( {}, src, dst ); - {}"#, - '{', - src_c_type, src_buf, - dst_c_type, dst_buf, - item_morph.instantiated_symbol_name(dict, σ), - '}'); - } - } - } -} diff --git a/src/c_gen/gen_lib.rs b/src/c_gen/gen_lib.rs new file mode 100644 index 0000000..13ffa3e --- /dev/null +++ b/src/c_gen/gen_lib.rs @@ -0,0 +1,82 @@ +use { + super::types::get_c_repr_arg_type, crate::{c_gen::LdmcCTargetMorph, LdmcPrimMorph}, laddertypes::{morphism::MorphismInstance, parser::*, MorphismType, TypeDict}, std::collections::HashMap +}; + +pub fn generate_lib( + dict: &mut impl TypeDict, + include_blocks: Vec< String >, + include_dependencies: HashMap< MorphismType, usize >, + morphisms: Vec< (String, MorphismInstance<LdmcPrimMorph>) > +) -> Result<String, ()> { + let mut target = LdmcCTargetMorph::new( include_blocks, include_dependencies ); + let mut wrappers = String::new(); + + for (name, morph) in morphisms { + match target.add_instantiation(dict, morph) { + Ok(inst) => { + if name == "main" { + let mut c_source = String::new(); + c_source.push_str(&format!(r#" + #include <unistd.h> + + int main() {{ + uint8_t bufIn[4096]; + uint8_t bufOut[4096];"#)); + + if let Ok(_) = laddertypes::subtype_unify( + &inst.ty.src_type, + &dict.parse("<Seq~<ValueTerminated '\\n'> Char~Ascii~native.UInt8>").expect("") + ) { + c_source.push_str("scanf(\"%s\", bufIn);\n"); + } else { + c_source.push_str("read(0, bufIn, sizeof(bufIn));\n"); + } + + c_source.push_str( + &format!(r#"FUSE( {}, (void const*)bufIn, (void*)bufOut ); +"#, + inst.instantiated_symbol_name(dict, &HashMap::new())) + ); + + if let Ok(ψ) = laddertypes::subtype_unify( + &inst.ty.dst_type, + &dict.parse("<Seq~<ValueTerminated 0> native.UInt8>").expect("") + ) { + c_source.push_str("printf(\"%s\\n\", bufOut);\n"); + } else { + c_source.push_str("write(1, bufOut, sizeof(bufOut));\n"); + } + c_source.push_str(" + return 0; + }"); + wrappers.push_str(&c_source); + } else { + target.add_type(dict, inst.ty.src_type.clone()); + target.add_type(dict, inst.ty.dst_type.clone()); + + wrappers.push_str(&format!(" + int {} ( + {} const * restrict src, + {} * restrict dst + ) {{ + return {}( (void*)src, (void*)dst ); + }} + ", name, + get_c_repr_arg_type(dict, &inst.ty.src_type), + get_c_repr_arg_type(dict, &inst.ty.dst_type), + inst.instantiated_symbol_name(dict, &HashMap::new()) + )); + } + } + Err(_err) => { + eprintln!("failed to create morphism instatiation"); + return Err(()); + } + } + } + + let mut c_source = target.into_c_source(dict); + c_source.push_str(&wrappers); + + Ok(c_source) +} diff --git a/src/c_gen/mod.rs b/src/c_gen/mod.rs new file mode 100644 index 0000000..cf994c5 --- /dev/null +++ b/src/c_gen/mod.rs @@ -0,0 +1,7 @@ +pub mod types; +pub mod morph; +pub mod gen_lib; + +pub use { + morph::target_morph::LdmcCTargetMorph +}; diff --git a/src/c_gen/morph/mod.rs b/src/c_gen/morph/mod.rs new file mode 100644 index 0000000..49510e5 --- /dev/null +++ b/src/c_gen/morph/mod.rs @@ -0,0 +1,76 @@ +pub mod target_morph; + +use { + crate::{ + c_gen::types::{ + get_c_repr_arg_type, + get_c_repr_definition, + get_c_repr_type + }, + morphism::LdmcPrimMorph + }, + laddertypes::{TypeDict, Substitution}, +}; + +impl LdmcPrimMorph { + pub fn instantiated_symbol_name(&self, dict: &mut impl TypeDict, σ: &impl Substitution) -> String { + let mut s = self.symbol.clone(); + for (k_id,v) in self.type_args.iter() { + if let Some(val_trm) = σ.get(k_id) { + if let laddertypes::TypeID::Var(var_id) = k_id { + + //if self.get_type().strip_halo().src_type.contains_var(*var_id) || + //self.get_type().strip_halo().dst_type.contains_var(*var_id) { + + let name = dict.get_varname(*var_id).unwrap(); + let val_str = get_c_repr_type(dict, &val_trm); + s.push_str(&format!("_{}_{}", name, val_str)); + + //} + } + } else { + if let laddertypes::TypeID::Var(var_id) = k_id { + let k = dict.get_varname(*var_id).unwrap(); + s.push_str(&format!("_{:?}_MISSING", k)); + eprintln!("INCOMPLETE MORPHISM INSTANTIATION, missing type parameter {} ({})", k, var_id); + } + } + } + s + } + + pub fn expected_c_type_signature(&self, dict: &mut impl TypeDict, + σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm> + ) -> String { + format!("int {} ({} const * restrict src, {} * restrict dst);", + self.instantiated_symbol_name(dict, σ), + get_c_repr_definition(dict, self.ty.src_type.clone(), true).expect("cant get c-repr type for src type"), + get_c_repr_definition(dict, self.ty.dst_type.clone(), true).expect("cant get c-repr type for dst type")) + } + + pub fn generate_instantiation(&self, dict: &mut impl TypeDict, σ: &impl Substitution) -> Option<String> { + let mut s = String::new(); + let symbol = self.instantiated_symbol_name(dict, σ); + + eprintln!("generate instantiation:"); + let ty = self.ty.clone(); + eprintln!("full type: {} ----> {}", ty.src_type.pretty(dict, 0), ty.dst_type.pretty(dict,0)); + let ty = ty.strip_halo().apply_subst(σ); + eprintln!("stripped type: {} ----> {}", ty.src_type.pretty(dict, 0), ty.dst_type.pretty(dict,0)); + + let src_c_symbol = get_c_repr_arg_type(dict, &ty.src_type); + let dst_c_symbol = get_c_repr_arg_type(dict, &ty.dst_type); + + s.push_str(&format!(r#" +int {} ( {} const * restrict src, {} * restrict dst ) {{ +"#, + symbol, src_c_symbol, dst_c_symbol, + )); + s.push_str(&self.c_source); + s.push_str(&format!(r#" + return 0; +}} +"#)); + Some(s) + } +} diff --git a/src/c_gen/morph/target_morph.rs b/src/c_gen/morph/target_morph.rs new file mode 100644 index 0000000..cea7ed4 --- /dev/null +++ b/src/c_gen/morph/target_morph.rs @@ -0,0 +1,375 @@ +use { + crate::{ + c_gen::types::{ + encode_morph_type_to_symbol, encode_type_to_value, get_c_repr_definition, get_c_repr_kind, get_c_repr_type + }, + morphism::LdmcPrimMorph + }, + laddertypes::{ + parser::*, Morphism, MorphismInstance, MorphismType, TypeDict, TypeTerm + }, + std::collections::HashMap +}; + +pub struct LdmcCTargetMorph { + header_blocks: Vec< String >, + header_dependencies: HashMap< MorphismType, usize >, + active_headers: Vec< usize >, + active_types: Vec< TypeTerm >, + active_morphisms: Vec< LdmcPrimMorph >, + active_lenpfx_types: Vec< (TypeTerm, TypeTerm) >, + typedefs: Vec< String >, + macro_calls: Vec< String > +} + +impl LdmcCTargetMorph { + pub fn add_required_header_block(&mut self, block: String) { + let i = self.header_blocks.len(); + self.active_headers.push(i); + self.header_blocks.push(block); + } + + pub fn new( + include_blocks: Vec< String >, + include_dependencies: HashMap< MorphismType, usize > + ) -> Self { + let mut m = LdmcCTargetMorph { + header_blocks: include_blocks, + header_dependencies: include_dependencies, + active_headers: Vec::new(), + active_morphisms: Vec::new(), + active_types: Vec::new(), + active_lenpfx_types: Vec::new(), + typedefs: Vec::new(), + macro_calls: Vec::new() + }; + + m.add_required_header_block( + "/* default ldmc header */ +#include <stdint.h> +#define FUSE(morph, src, dst) { int result = morph(src,dst); if(result) return result; } + +".into() + ); + m + } + + pub fn add_type(&mut self, dict: &mut impl TypeDict, ty: TypeTerm) { + let ty = ty.strip(); + if ! self.active_types.contains(&ty) { + eprintln!("add type {}", ty.pretty(dict,0)); + + let (ht,ft) = ty.get_floor_type(); + if ht.is_empty() { + + match &ft { + TypeTerm::Seq { seq_repr, items } => { + let item_type = items.first().unwrap().clone(); + self.add_type(dict, item_type.clone()); + + if let Some(seq_repr) = seq_repr { + dict.add_varname("LengthType".into()); + if let Ok(σ) = + laddertypes::constraint_system::unify( + seq_repr.as_ref(), + &dict.parse_desugared("<LengthPrefix LengthType>").expect("").sugar(dict) + ) + { + let length_type = σ.get(&dict.get_typeid(&"LengthType".into()).expect("")).expect("cant get Length type"); + self.add_type(dict, length_type.clone()); + self.macro_calls.push( + format!("DEFINE_LENGTH_PREFIX_ARRAY({}, {})\n", + get_c_repr_type(dict, &length_type), + get_c_repr_type(dict, &item_type) + ) + ); + } + } + } + _ => {} + } + + self.active_types.push(ty.clone()); + if let Some(type_def) = get_c_repr_definition(dict, ft, false) { + let type_name = get_c_repr_type(dict, &ty); + self.typedefs.push(format!("typedef {} {};\n", type_def, type_name)); + } else { + eprintln!("cant get c-repr type for type '{}'", ty.pretty(dict,0)); + } + } else { + let type_name = get_c_repr_type(dict, &ty); + let type_def = get_c_repr_type(dict, &ft); + self.add_type(dict, ft); + self.typedefs.push(format!("typedef {} {};\n", type_def, type_name)); + } + } + } + + pub fn add_instantiation( + &mut self, + dict: &mut impl TypeDict, + morph: MorphismInstance<LdmcPrimMorph>, + ) -> Result<LdmcPrimMorph, ()> { + let new_inst = self.bake_morphism(dict, morph)?; + if ! self.active_morphisms.contains(&new_inst) { + self.active_morphisms.push(new_inst.clone()); + } + + let ty = new_inst.get_type().strip_halo(); + self.add_type(dict, ty.src_type); + self.add_type(dict, ty.dst_type); + + Ok(new_inst) + } + + pub fn into_c_source(mut self, dict: &mut impl TypeDict) -> String { + let mut source = String::new(); + self.active_headers.dedup(); + self.typedefs.dedup(); + self.macro_calls.dedup(); + + for i in self.active_headers { + source.push_str( &self.header_blocks[i] ); + source.push('\n'); + } + source.push('\n'); + + for typedef in self.typedefs { + source.push_str(&typedef); + } + + source.push('\n'); + + + for m in self.macro_calls { + source.push_str(&m); + source.push('\n'); + } + source.push('\n'); + + for m in self.active_morphisms { + source.push_str(&m.generate_instantiation(dict, &HashMap::new()).expect("cant create function")); + } + source + } + + pub fn bake_morphism( + &mut self, + dict: &mut impl laddertypes::TypeDict, + morph_inst: MorphismInstance<LdmcPrimMorph>, + ) -> Result<LdmcPrimMorph, ()> { + let ty = morph_inst.get_type(); + let symbol = encode_morph_type_to_symbol(dict, &ty); + + match &morph_inst { + MorphismInstance::Id { ψ } => { + self.add_required_header_block("#include <string.h>".into()); + Ok(LdmcPrimMorph { + symbol, + type_args: Vec::new(), + ty: MorphismType { src_type: ψ.clone(), dst_type: ψ.clone() }, + c_source: String::from("memcpy(dst, src, sizeof(*src));") + }) + } + MorphismInstance::Primitive { ψ, σ, morph } => { + if let Some(i) = self.header_dependencies.get(&morph.get_type()) { + self.active_headers.push(*i); + } + + + let mut c_source = String::new(); + for (ty_id, kind) in morph.type_args.iter() { + if let laddertypes::TypeID::Var(var_id) = ty_id { + if let Some(val) = σ.get(ty_id) { + let type_var_value = + if kind == "Type" { + get_c_repr_type(dict, val) + } else { + encode_type_to_value(dict, val) + }; + c_source.push_str(&format!(" #define {} {}\n", dict.get_typename(&ty_id).unwrap(), type_var_value)); + } + } + } + c_source.push_str(&morph.c_source); + for (ty_id, kind) in morph.type_args.iter() { + if let laddertypes::TypeID::Var(var_id) = ty_id { + c_source.push_str(&format!("\n #undef {}", dict.get_typename(&ty_id).unwrap())); + } + } + + Ok(LdmcPrimMorph{ + symbol: morph.instantiated_symbol_name(dict, σ), + type_args: Vec::new(), + ty: morph_inst.get_type().apply_subst(σ).strip_halo(), + c_source + }) + }, + MorphismInstance::Chain { path } => { + let mut c_source = String::new(); + + if path.len() > 1 { + c_source.push_str(r#" + uint8_t bufA[4096]; + uint8_t bufB[4096]; + "#); + } + + for (i,morph) in path.iter().enumerate() { + if let Ok(inst) = self.add_instantiation(dict, morph.clone()) { + let morph_symbol = inst.instantiated_symbol_name(dict, &morph.get_subst()); + let src_buf = if i == 0 { "(void*)src" } else if i%2 == 0 { "(void*)bufA" } else { "(void*)bufB" }; + let dst_buf = if i+1 == path.len() { "(void*)dst" } else if i%2 == 0 { "(void*)bufB" } else { "(void*)bufA" }; + + c_source.push_str(&format!(r#" + FUSE( {}, {}, {} );"#, + morph_symbol, src_buf, dst_buf, + )); + } else { + c_source.push_str(&format!("/* ERROR: missing morphism */")); + eprintln!("failed to add instantiation of item morphism"); + } + } + + Ok(LdmcPrimMorph { + symbol, type_args: Vec::new(), ty, + c_source + }) + } + MorphismInstance::MapSeq { ψ, seq_repr, item_morph } => { + if let Ok(item_morph_inst) = self.add_instantiation(dict, item_morph.as_ref().clone()) { + if let Some(seq_repr) = seq_repr { + dict.add_varname("Length".into()); + dict.add_varname("LengthType".into()); + dict.add_varname("TerminatorValue".into()); + + if let Ok(γ) = laddertypes::constraint_system::unify( + &dict.parse_desugared("<StaticLength Length>").expect("parse type template").sugar(dict), + seq_repr.as_ref() + ) { + let length = γ.get(&dict.get_typeid(&"Length".into()).expect("")).expect("cant get Length"); + match length { + TypeTerm::Num(l) => { + let item_morph_symbol = item_morph_inst.instantiated_symbol_name(dict, &HashMap::new()); + + self.add_type( dict, morph_inst.get_type().strip_halo().src_type ); + self.add_type( dict, morph_inst.get_type().strip_halo().dst_type ); + + let c_source = format!(r#" + for( size_t i = 0; i < {}; ++i ) {{ + FUSE( {}, &src->items[i], &dst->items[i] ); + }} + "#, + l, + item_morph_symbol, + ); + + Ok(LdmcPrimMorph{ + symbol, type_args: Vec::new(), ty, + c_source + }) + } + _ => { + eprintln!("invalid length '{}'", length.pretty(dict, 0)); + Err(()) + } + } + } + + else if let Ok(γ) = laddertypes::constraint_system::unify( + &dict.parse_desugared("<LengthPrefix LengthType>").expect("parse type template").sugar(dict), + seq_repr.as_ref() + ) { + // todo: assert that length type is native.UIntX + //let length_type = γ.get(&dict.get_typeid(&"LengthType".into()).expect("")).expect("cant get LengthType"); + let item_morph_symbol = item_morph_inst.instantiated_symbol_name(dict, &HashMap::new()); + + self.add_type( dict, morph_inst.get_type().strip_halo().src_type ); + self.add_type( dict, morph_inst.get_type().strip_halo().dst_type ); + + let c_source = format!(r#" + for( size_t i = 0; i < src->len; ++i ) {{ + FUSE( {}, &src->items[i], &dst->items[i] ); + }} + dst->len = src->len; + "#, + item_morph_symbol, + ); + + Ok(LdmcPrimMorph{ + symbol, type_args: Vec::new(), ty, + c_source + }) + } + + else if let Ok(γ) = laddertypes::constraint_system::unify( + &dict.parse_desugared("<ValueTerminated TerminatorValue>").expect("parse type template").sugar(dict), + seq_repr.as_ref() + ) { + let terminator_value = γ.get(&dict.get_typeid(&"TerminatorValue".into()).expect("")).expect("cant get TerminatorValue"); + let item_morph_symbol = item_morph_inst.instantiated_symbol_name(dict, &HashMap::new()); + let terminator = encode_type_to_value(dict, terminator_value); + + let c_source = format!(r#" + while( *src != {} ) {{ + FUSE( {}, src, dst ); + ++src; + ++dst; + }} + *dst = {};"#, + terminator, + item_morph_symbol, + terminator + ); + + Ok(LdmcPrimMorph{ + symbol, type_args: Vec::new(), ty, + c_source + }) + } + + + else { + eprintln!("Error: Unknown Seq- Representation!!"); + Err(()) + } + } else { + eprintln!("Error: missing Seq- Representation!!"); + Err(()) + } + } else { + eprintln!("failed to add item-morph instantiation"); + Err(()) + } + }, + MorphismInstance::MapStruct { ψ, src_struct_repr, dst_struct_repr, member_morph } => { + + let mut c_source = String::new(); + + for (name, morph) in member_morph.iter() { + if let Ok(inst) = self.add_instantiation(dict, morph.clone()) { + let name = name.replace("-", "_").replace(".","_dot_"); + c_source.push_str( + &format!(" + FUSE( {}, &src->{}, &dst->{} );", + inst.symbol, + name, name + )); + } else { + c_source.push_str(&format!("/* ERROR: missing morphism for struct member '{}' */", name)); + eprintln!("failed to create morphism instantiation for struct member"); + return Err(()); + } + } + + Ok(LdmcPrimMorph{ + symbol, type_args: Vec::new(), ty, + c_source + }) + } + MorphismInstance::MapEnum { ψ, enum_repr, variant_morph } => { + todo!(); + } + } + } +} diff --git a/src/c_gen/types/mod.rs b/src/c_gen/types/mod.rs new file mode 100644 index 0000000..29cb4ec --- /dev/null +++ b/src/c_gen/types/mod.rs @@ -0,0 +1,257 @@ +use { + crate::struct_layout::LayoutType, + chumsky::chain::Chain, laddertypes::{morphism::MorphismType, + parser::*, + substitution::Substitution, + unparser::*, EnumVariant, StructMember, TypeTerm, TypeDict} +}; + +/* +*/ +pub fn get_c_repr_kind(kind: String) -> Option<String> { + match kind.as_str() { + "ℤ" => Some("uint64_t".into()), + _ => None + } +} + +/* for a given ladder type `t`, get the corresponding C type + */ +pub fn get_c_repr_definition(dict: &mut impl TypeDict, t: TypeTerm, skip_pointer: bool) -> Option<String> { + match t { + TypeTerm::TypeID(tyid) => { + if tyid == dict.get_typeid_creat("native.UInt8") { + Some("uint8_t".into()) + } else if tyid == dict.get_typeid_creat("native.UInt16") { + Some("uint16_t".into()) + } else if tyid == dict.get_typeid_creat("native.UInt32") { + Some("uint32_t".into()) + } else if tyid == dict.get_typeid_creat("native.UInt64") { + Some("uint64_t".into()) + } else if tyid == dict.get_typeid_creat("native.Address") { + Some("void*".into()) + } else if tyid == dict.get_typeid_creat("native.Float32") { + Some("float".into()) + } else if tyid == dict.get_typeid_creat("native.Float64") { + Some("double".into()) + } else { + None + } + } + + TypeTerm::Seq{ seq_repr, items } => { + if let Some(seq_repr) = seq_repr { + let item_type = items.first().expect("no item type specified!").clone(); + let item_c_type : String = get_c_repr_type(dict, &item_type); + + dict.add_varname("Length".into()); // Kind: Num + dict.add_varname("LengthType".into()); // Kind: Type + dict.add_varname("TermValue".into()); // Kind: Value of Type ItemType + + if let Ok((ψ, σ)) = laddertypes::constraint_system::subtype_unify( + seq_repr.as_ref(), + &dict.parse_desugared("<StaticLength Length>").expect("parse template type").sugar(dict) + ) { + let length = match + σ.get( + &dict.get_typeid(&"Length".into()).expect("no Length ID") + ).expect("no length specified!") + { + TypeTerm::Num(l) => l, + _ => { + eprintln!("invalid Length!"); + return None; + } + }; + Some(format!("struct {{ {} items[{}]; }} ", item_c_type, length)) + } + else if let Ok((ψ, σ)) = laddertypes::constraint_system::subtype_unify( + seq_repr.as_ref(), + &dict.parse_desugared("<LengthPrefix LengthType>").expect("parse template type").sugar(dict) + ) { + let length_type = σ.get( + &dict.get_typeid(&"LengthType".into()).expect("no LengthType ID") + ).expect("no length type specified"); + + let length_c_type = get_c_repr_type(dict, &length_type); + + Some(format!("struct {{ {} len; {} items[]; }} ", length_c_type, item_c_type)) + } + else if let Ok((ψ, σ)) = laddertypes::constraint_system::subtype_unify( + seq_repr.as_ref(), + &dict.parse_desugared("<ValueTerminated TermValue>").expect("parse template type").sugar(dict) + ) { + if skip_pointer { + Some(item_c_type) + } else { + Some(format!("{} *", item_c_type)) + } + } + else if let Ok((ψ, σ)) = laddertypes::constraint_system::subtype_unify( + seq_repr.as_ref(), + &dict.parse_desugared("MsbCont").expect("parse template type").sugar(dict) + ) { + if skip_pointer { + Some(item_c_type) + } else { + Some(format!("{} *", item_c_type)) + } + } + else { + eprintln!("can't get C-repr for sequence type `{}`!", seq_repr.pretty(dict, 0)); + None + } + } else { + eprintln!("no sequence-representation type specified!"); + None + } + } + + TypeTerm::Struct{ struct_repr, members } => { + let c_struct_attribute = + if let Some(sr) = struct_repr { + let sr = sr.desugar(dict); + match LayoutType::parse(dict, &sr).expect("layout type") { + LayoutType::Aligned => "", + LayoutType::Packed => "__attribute((packed))__" + } + } else {""}; + + let mut c_type = format!("struct {} {{\n", c_struct_attribute); + + for StructMember{ symbol, ty } in members { + let field_c_type = get_c_repr_definition(dict, ty, false).expect(""); + c_type.push_str(&format!(" {} {};\n", + field_c_type, + symbol.replace("-", "_").replace(".","_dot_") + )); + } + + c_type.push_str("}"); + Some(c_type) + } + + TypeTerm::Enum { enum_repr, variants } => { + let mut c_type = format!(" +struct {{ + enum {{ +"); + + for (i, EnumVariant{ symbol, ty }) in variants.iter().enumerate() { + c_type.push_str(&format!( + " {} = {}", symbol.replace("-", "_").replace(".","_dot_").to_uppercase(), i + )); + + if i+1 < variants.len() { + c_type.push_str(",\n"); + } + } + + c_type.push_str(" + } tag; + + union { +"); + + for EnumVariant{ symbol, ty } in variants { + let variant_c_type = get_c_repr_definition(dict, ty, false).expect("cant get C-Repr type for variant"); + c_type.push_str(&format!( + " {} {};\n", variant_c_type, symbol.replace("-", "_").replace(".","_dot_") + )); + } + + c_type.push_str(" + }; +}"); + + Some(c_type) + } + + TypeTerm::Ladder(rungs) => { + if let Some(t) = rungs.last() { + get_c_repr_definition(dict, t.clone(), false) + } else { + None + } + } + + _ => { None } + } +} + +pub fn get_c_repr_type(dict: &mut impl TypeDict, t: &laddertypes::TypeTerm)-> String { + let t = t.clone().strip(); + + match t.desugar(dict) { + laddertypes::DesugaredTypeTerm::Char(c) => { + match c { + '.' => format!("_dot_"), + '-' => format!("_minus_"), + _ => + format!("{}", (c as u64)) + } + }, + laddertypes::DesugaredTypeTerm::Num(n) => { + format!("{}", n) + } + laddertypes::DesugaredTypeTerm::TypeID(ty_id) => { + if let Some(name) = dict.get_typename(&ty_id) { + name + .replace("-", "_") + .replace(".", "") + } else { + format!("") + } + } + laddertypes::DesugaredTypeTerm::Ladder(rs) | + laddertypes::DesugaredTypeTerm::App(rs) => { + let mut s = String::new(); + s.push('_'); + for r in rs { + let r = r.sugar(dict); + s.push_str(&get_c_repr_type(dict, &r)); + s.push('_'); + } + s + } + } +} + +pub fn get_c_repr_arg_type(dict: &mut impl TypeDict, t: &laddertypes::TypeTerm)-> String { + let t = t.clone().strip().get_floor_type().1; + dict.add_varname("TerminatorValue".into()); + match &t { + TypeTerm::Seq { seq_repr, items } => { + if let Some(seq_repr) = seq_repr.as_ref() { + if let Ok(ψ) = laddertypes::constraint_system::subtype_unify( + seq_repr, + &dict.parse_desugared("<ValueTerminated TerminatorValue>").expect("").sugar(dict) + ) { + return get_c_repr_type(dict, &items[0].clone().strip().get_floor_type().1); + } + else if let Ok(ψ) = laddertypes::constraint_system::subtype_unify( + seq_repr, + &dict.parse_desugared("MsbCont").expect("").sugar(dict) + ) { + return get_c_repr_type(dict, &items[0].clone().strip().get_floor_type().1); + } + } + } + + _ => {} + } + get_c_repr_type(dict, &t) +} + +pub fn encode_morph_type_to_symbol(dict: &mut impl TypeDict, t: &MorphismType) -> String { + format!( + "morph__{}___TO__{}", + get_c_repr_type(dict, &t.strip_halo().src_type), + get_c_repr_type(dict, &t.strip_halo().dst_type) + ) +} + +pub fn encode_type_to_value(dict: &mut impl TypeDict, t: &laddertypes::TypeTerm) -> String { + let t = t.clone().desugar(dict); + dict.unparse(&t) +} diff --git a/src/main.rs b/src/main.rs index 13b8629..675c12d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,44 +3,88 @@ mod morphism; mod parser; mod c_gen; +mod struct_layout; use { - ariadne::{Color, Label, Report, ReportKind, Source}, - chumsky::prelude::*, - laddertypes::{ - parser::ParseLadderType, BimapTypeDict, MorphismType - }, - std::sync::{Arc, RwLock}, - tiny_ansi::TinyAnsi, - - crate::{ - morphism::LdmcMorphism, + morphism::LdmcPrimMorph, parser::morphism_base_parser, - } + }, ariadne::{Color, Label, Report, ReportKind, Source}, clap::Parser, laddertypes::{ + morphism::MorphismType, BimapTypeDict, Morphism + }, parser::morphism_type_parser, std::{io::Write, path::PathBuf, sync::{Arc, RwLock}}, tiny_ansi::TinyAnsi, walkdir::WalkDir }; +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + #[arg(short='b', long)] + morphism_base: Vec<PathBuf>, + + #[arg(short='m', long="morph")] + morphisms: Vec<String>, + + #[arg(short='o', long)] + output: Option<PathBuf> +} + fn main() { + let args = Args::parse(); let mut type_dict = Arc::new(RwLock::new(BimapTypeDict::new())); - let mut morphism_base = laddertypes::MorphismBase::<LdmcMorphism>::new(vec![ - //type_dict.parse("Seq~MsbCont").expect(""), - //type_dict.parse("Seq~<ValueTerminated '\\0'>").expect(""), - type_dict.parse("Seq~<LengthPrefix native.UInt64>").expect("") - ]); + let mut morphism_base = laddertypes::morphism_base::MorphismBase::<LdmcPrimMorph>::new(); - let mut args = std::env::args().skip(1); - let src_type_arg = args.next().expect("src type expected"); - let dst_type_arg = args.next().expect("dst type expected"); + // 1. load morphism base + let mut mb_paths = args.morphism_base; - for mb_path in args { - let src = std::fs::read_to_string(mb_path.clone()).expect("read"); + // 1.1. pfade ermitteln + let env_var = "MORPHISM_BASE"; + let suffix = "morphism-base"; + + match std::env::var(env_var) { + Ok(path_str) => { + let path = std::path::Path::new(&path_str); + if path.is_dir() { + for entry in WalkDir::new(path) + .into_iter() + .filter_map(Result::ok) + .filter(|e| + e.path().is_file() && + e.path().extension().map_or(false, |ext| ext == suffix) + ) + { + mb_paths.push(entry.path().into()); + } + } else { + eprintln!("morphism-base path is not a directory: {:?}", path); + } + } + Err(e) => { + eprintln!("failed to read environment variable {}: {}", env_var, e); + } + } + + // 1.2. read files + + let mut include_blocks = Vec::new(); + let mut include_dependencies = std::collections::HashMap::new(); + + for mb_path in mb_paths { + let src = std::fs::read_to_string(mb_path.clone()).expect("failed to read morphism base"); + + use chumsky::Parser; let result = morphism_base_parser(type_dict.clone()).parse(src.clone()); match result { Ok((includes, morphisms)) => { - eprintln!("[{}] parse ok.", mb_path.bright_yellow()); - println!("{}", includes); + eprintln!("[{}] parse ok.", mb_path.to_str().unwrap().bright_yellow()); + + let include_idx = include_blocks.len(); + + let mut includes_prefixed = format!("/* from `{}` */", mb_path.display()); + includes_prefixed.push_str(&includes); + include_blocks.push(includes_prefixed); + for m in morphisms { - morphism_base.add_morphism(LdmcMorphism::Primitive(m)); + include_dependencies.insert( m.get_type(), include_idx ); + morphism_base.add_morphism(m); } } Err(errs) => { @@ -60,22 +104,21 @@ fn main() { } } - - let src_type = type_dict.parse( src_type_arg.as_str() ).expect(""); - let dst_type = type_dict.parse( dst_type_arg.as_str() ).expect(""); - - let path = morphism_base.find_morphism_path(MorphismType { - src_type: src_type.clone(), - dst_type: dst_type.clone(), - }); - - match path { - Some(path) => { - c_gen::generate_main(&mut type_dict, path, src_type, dst_type); - } - None => { - eprintln!("Error: could not find morphism path"); - std::process::exit(-1); + // 2. Generate Morphisms + let mut instances = Vec::new(); + for morph_decl in args.morphisms.iter() { + use chumsky::Parser; + if let Ok((name, src_type, dst_type)) = morphism_type_parser(type_dict.clone()).parse(morph_decl.as_str()) { + let ty = MorphismType{ src_type, dst_type }; + instances.push( (name, morphism_base.get_morphism_instance( &ty ).expect("failed to find morphism")) ); } } + + let c_source = crate::c_gen::gen_lib::generate_lib(&mut type_dict, include_blocks, include_dependencies, instances).expect("failed to generate library"); + if let Some(out_path) = args.output { + let mut file = std::fs::File::create(out_path).expect("failed to open output file"); + file.write_all(c_source.as_bytes()).expect("failed to write output file"); + } else { + println!("{}", c_source); + } } diff --git a/src/morphism.rs b/src/morphism.rs index a1f2aab..28ea01e 100644 --- a/src/morphism.rs +++ b/src/morphism.rs @@ -1,76 +1,16 @@ -use laddertypes::morphism::Morphism; +use laddertypes::morphism::{Morphism, MorphismType}; -#[derive(Clone, Debug)] -pub struct LdmcPrimCMorphism { +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct LdmcPrimMorph { pub symbol: String, pub type_args: Vec<(laddertypes::TypeID, String)>, - pub src_type: laddertypes::TypeTerm, - pub dst_type: laddertypes::TypeTerm, + pub ty: MorphismType, pub c_source: String } -#[derive(Clone)] -pub enum LdmcMorphism { - Primitive( LdmcPrimCMorphism ), - LengthPrefixMap{ - length_prefix_type: laddertypes::TypeTerm, - item_morph: Box<LdmcPrimCMorphism> - }, - ValueDelimMap{ - delim: u64, - item_morph: Box<LdmcPrimCMorphism> - } -} - -impl Morphism for LdmcMorphism { - fn weight(&self) -> u64 { - 1 - } - - fn get_type(&self) -> laddertypes::MorphismType { - match self { - LdmcMorphism::Primitive(prim_morph) => - laddertypes::MorphismType { - src_type: prim_morph.src_type.clone().normalize(), - dst_type: prim_morph.dst_type.clone().normalize() - }, - LdmcMorphism::LengthPrefixMap{ length_prefix_type, item_morph } => { - laddertypes::MorphismType { - src_type: laddertypes::TypeTerm::App(vec![ length_prefix_type.clone(), item_morph.src_type.clone() ]), - dst_type: laddertypes::TypeTerm::App(vec![ length_prefix_type.clone(), item_morph.dst_type.clone() ]), - } - }, - LdmcMorphism::ValueDelimMap{ delim, item_morph } => { - let value_delim_type = laddertypes::TypeTerm::App(vec![]); - laddertypes::MorphismType { - src_type: laddertypes::TypeTerm::App(vec![ value_delim_type.clone(), item_morph.src_type.clone() ]), - dst_type: laddertypes::TypeTerm::App(vec![ value_delim_type.clone(), item_morph.dst_type.clone() ]), - } - } - }.normalize() - } - - fn map_morphism(&self, seq_type: laddertypes::TypeTerm) -> Option< Self > { - match self { - LdmcMorphism::Primitive(prim) => { - let item_morph = Box::new(prim.clone()); -/* - if seq_type == self.length_prefix_type { - */ - Some(LdmcMorphism::LengthPrefixMap{ - length_prefix_type: seq_type, - item_morph, - }) - /* - } else if seq_type == self.value_delim_type { - Some(LdmcMorphism::ValueDelimMap { delim, item_morph }) - } else { - None - } - */ - } - _ => None - } +impl Morphism for LdmcPrimMorph { + fn get_type(&self) -> MorphismType { + self.ty.clone() } } diff --git a/src/parser.rs b/src/parser.rs index f45fddf..24ca0a9 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,11 +1,7 @@ use { - chumsky::{ + crate::morphism::LdmcPrimMorph, chumsky::{ prelude::*, text::* - }, - std::sync::{Arc, RwLock}, - - laddertypes::{TypeDict, BimapTypeDict, parser::*}, - crate::morphism::LdmcPrimCMorphism + }, laddertypes::{TypeTerm, morphism::MorphismType, parser::*, BimapTypeDict, TypeDict}, std::sync::{Arc, RwLock} }; /* morphism-base text format: @@ -18,12 +14,12 @@ use { */ pub fn morphism_base_parser( type_dict: Arc<RwLock< BimapTypeDict >> -) -> impl Parser<char, (String, Vec<LdmcPrimCMorphism>), Error = Simple<char>> { +) -> impl Parser<char, (String, Vec<LdmcPrimMorph>), Error = Simple<char>> { just("```") .then(take_until(just("```"))) .map( - move |(a, (b, c))| { + move |(_a, (b, _c))| { b.iter().collect() } ) @@ -66,11 +62,13 @@ pub fn morphism_base_parser( let src_type = type_dict.parse(&src_type.iter().collect::<String>()).expect("couldnt parse src type"); let dst_type = type_dict.parse(&dst_type.iter().collect::<String>()).expect("couldnt parse dst type"); - LdmcPrimCMorphism { + LdmcPrimMorph { symbol, type_args: ty_args, - src_type, - dst_type, + ty: MorphismType{ + src_type, + dst_type + }, c_source } }) @@ -78,3 +76,25 @@ pub fn morphism_base_parser( ) } + +pub fn morphism_type_parser( + mut type_dict: Arc<RwLock< BimapTypeDict >> +) -> impl Parser<char, (String, TypeTerm, TypeTerm), Error = Simple<char>> { + ident() + .padded() + .then(just(":").ignored()) + .then( + take_until(just("-->").ignored()) + ) + .then(take_until(end())) + .map({ + let type_dict = type_dict.clone(); + move |((name, src_type), dst_type)| { + ( + name.0, + type_dict.clone().parse(&src_type.0.iter().collect::<String>()).expect("parse type"), + type_dict.clone().parse(&dst_type.0.iter().collect::<String>()).expect("parse type") + ) + } + }) +} diff --git a/src/platform/x86.rs b/src/platform/x86.rs new file mode 100644 index 0000000..aaae9c2 --- /dev/null +++ b/src/platform/x86.rs @@ -0,0 +1,43 @@ +use std::collections::HashMap; + +pub fn example_substitution() { + let mut γ = HashMap::new(); + γ.insert( + type_dict.get_typeid_creat(&"Byte"), + type_dict.parse("<Seq~<StaticLength 8> Bit>").expect("parse") + .apply_subst(&γ) + .clone() + ); + γ.insert( + type_dict.get_typeid_creat(&"x86.UInt8"), + type_dict.parse("ℤ_2^8 ~ <PosInt 2 LittleEndian> ~ <Seq~<StaticLength 8> <Digit 2> ~ Bit>").expect("parse") + .apply_subst(&γ) + .clone() + ); + γ.insert( + type_dict.get_typeid_creat(&"x86.UInt16"), + type_dict.parse("ℤ_2^16 ~ <PosInt 256 LittleEndian> ~ <Seq~<StaticLength 2> <Digit 256> ~ x86.UInt8 >").expect("parse") + .apply_subst(&γ) + .clone() + ); + γ.insert( + type_dict.get_typeid_creat(&"x86.UInt32"), + type_dict.parse("ℤ_2^32 ~ <PosInt 256 LittleEndian> ~ <Seq~<StaticLength 4> <Digit 256> ~ x86.UInt8 >").expect("parse") + .apply_subst(&γ).clone() + ); + γ.insert( + type_dict.get_typeid_creat(&"x86.UInt64"), + type_dict.parse("ℤ_2^64 ~ <PosInt 256 LittleEndian> ~ <Seq~<StaticLength 8> <Digit 256> ~ x86.UInt8 >").expect("parse") + .apply_subst(&γ).clone() + ); + γ.insert( + type_dict.get_typeid_creat(&"x86.Float32"), + type_dict.parse("ℝ ~ IEEE-754.Float32 ~ <Seq~<StaticLength 4> Byte>").expect("parse") + .apply_subst(&γ).clone() + ); + γ.insert( + type_dict.get_typeid_creat(&"x86.Float64"), + type_dict.parse("ℝ ~ IEEE-754.Float64 ~ <Seq~<StaticLength 4> Byte>").expect("parse") + .apply_subst(&γ).clone() + ); +} diff --git a/src/struct_layout.rs b/src/struct_layout.rs new file mode 100644 index 0000000..b8816e9 --- /dev/null +++ b/src/struct_layout.rs @@ -0,0 +1,244 @@ + + +use laddertypes::{parser::*, StructMember, TypeTerm, TypeDict, DesugaredTypeTerm}; + +#[derive(Clone, Copy, Debug)] +pub enum ObjectSize { + Static(u64), + Dynamic(/* function to get size at runtime */), + Unknown +} + +impl std::ops::Add for ObjectSize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + match (self, rhs) { + (ObjectSize::Unknown, _) | + (_, ObjectSize::Unknown) + => ObjectSize::Unknown, + + (ObjectSize::Dynamic(), _) | + (_, ObjectSize::Dynamic()) + => ObjectSize::Dynamic(), + + (ObjectSize::Static(s1), ObjectSize::Static(s2)) => ObjectSize::Static(s1 + s2), + } + } +} + +impl std::ops::Mul for ObjectSize { + type Output = Self; + + fn mul(self, rhs: Self) -> Self { + match (self, rhs) { + (ObjectSize::Unknown, _) | + (_, ObjectSize::Unknown) + => ObjectSize::Unknown, + + (ObjectSize::Dynamic(), _) | + (_, ObjectSize::Dynamic()) + => ObjectSize::Dynamic(), + + (ObjectSize::Static(s1), ObjectSize::Static(s2)) => ObjectSize::Static(s1 * s2), + } + } +} + +pub fn get_type_size( dict: &mut impl TypeDict, ty: TypeTerm ) -> ObjectSize { + match &ty { + TypeTerm::TypeID(tyid) => { + if tyid == &dict.get_typeid_creat("native.UInt8") { ObjectSize::Static(1) } + else if tyid == &dict.get_typeid_creat("native.UInt16") { ObjectSize::Static(2) } + else if tyid == &dict.get_typeid_creat("native.UInt32") { ObjectSize::Static(4) } + else if tyid == &dict.get_typeid_creat("native.UInt64") { ObjectSize::Static(8) } + else if tyid == &dict.get_typeid_creat("native.Address") { ObjectSize::Static(8) } + else if tyid == &dict.get_typeid_creat("native.Float32") { ObjectSize::Static(4) } + else if tyid == &dict.get_typeid_creat("native.Float64") { ObjectSize::Static(8) } + else { + ObjectSize::Unknown + } + }, + + TypeTerm::Ladder(rungs) => { + get_type_size(dict, rungs.last().unwrap().clone() ) + } + + TypeTerm::Struct { struct_repr, members } => { + let layout = StructLayout::parse_sugared(dict, ty).expect("invalid struct"); + layout.get_size() + } + + TypeTerm::Seq { seq_repr, items } => { + if let Some(seq_repr) = seq_repr { + dict.add_typename("Length".into()); + dict.add_typename("LengthType".into()); + dict.add_typename("TerminatorValue".into()); + + if let Ok(σ) = laddertypes::unify( + &seq_repr.clone(), + &dict.parse("<StaticLength Length>").expect("") + ) { + if let Some(TypeTerm::Num(len)) = σ.get(&dict.get_typeid(&"Length".into()).expect("")) { + ObjectSize::Static(*len as u64) * get_type_size(dict, items.first().unwrap().clone()) + } else { + ObjectSize::Unknown + } + } + else if let Ok(σ) = laddertypes::unify( + &seq_repr.clone(), + &dict.parse("<LengthPrefix LengthType>").expect("") + ) { + ObjectSize::Dynamic() + } + else if let Ok(σ) = laddertypes::unify( + &seq_repr.clone(), + &dict.parse("<ValueTerminated TerminatorValue>").expect("") + ) { + ObjectSize::Dynamic() + } + else { + ObjectSize::Unknown + } + } else { + ObjectSize::Unknown + } + } + + _ => ObjectSize::Unknown + } + +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum LayoutType { + Aligned, + Packed +} + +impl LayoutType { + pub fn parse( dict: &mut impl TypeDict, ty: &DesugaredTypeTerm ) -> Option< LayoutType > { + if ty == &dict.parse_desugared("Aligned").expect("parse") { + Some(LayoutType::Aligned) + } else if ty == &dict.parse_desugared("Packed").expect("parse") { + Some(LayoutType::Packed) + } else { + None + } + } + + pub fn unparse(&self, dict: &mut impl TypeDict) -> DesugaredTypeTerm { + match self { + LayoutType::Aligned => dict.parse_desugared("Aligned").unwrap(), + LayoutType::Packed => dict.parse_desugared("Packed").unwrap() + } + } +} + +#[derive(Clone)] +pub struct StructLayout { + pub ty: laddertypes::DesugaredTypeTerm, + pub layout: LayoutType, + pub members: Vec< StructMember >, + offsets: std::collections::HashMap< String, u64 >, + size: ObjectSize +} + +impl StructLayout { + pub fn get_type(&self) -> DesugaredTypeTerm { + self.ty.clone() + } + + pub fn get_size(&self) -> ObjectSize { + self.size + } + + pub fn get_offset(&self, name: &String) -> u64 { + *self.offsets.get(name).expect("") + } + + pub fn init_offsets(&mut self, dict: &mut impl TypeDict) { + let mut offset = 0; + + for StructMember{symbol: field_name, ty: field_type} in self.members.iter() { + //let field_c_type = crate::c_gen::get_c_repr_type(dict, field_type.clone(), true).expect("cant get c-repr for struct field"); + match get_type_size( dict, field_type.clone() ) { + ObjectSize::Static(field_size) => { + match self.layout { + LayoutType::Aligned => { + // add padding to get natural alignment of current member + if offset % field_size > 0 { + offset = field_size * ((offset / field_size)+1); + } + } + LayoutType::Packed => { + // no padding + } + } + + // take offset + self.offsets.insert(field_name.clone(), offset); + + // advance by current size + offset += field_size; + } + ObjectSize::Dynamic() => { + eprintln!("dynamically sized Field in struct!"); + self.offsets.insert(field_name.clone(), offset); + self.size = ObjectSize::Dynamic(); + return; + } + ObjectSize::Unknown => { + eprintln!("Struct member `{}` has unknown size!", field_name); + self.offsets.insert(field_name.clone(), offset); + self.size = ObjectSize::Unknown; + return; + } + } + } + + match self.size { + ObjectSize::Dynamic() => { + + } + _ => { + self.size = ObjectSize::Static(offset); + } + } + } + + pub fn parse(dict: &mut impl TypeDict, struct_type: &DesugaredTypeTerm) -> Option <Self> { + let st = struct_type.clone().strip().sugar(dict).normalize(); + Self::parse_sugared(dict, st) + } + + pub fn parse_sugared(dict: &mut impl TypeDict, st: TypeTerm) -> Option <Self> { + eprintln!("{}", st.pretty(dict, 0)); + match st.clone() { + TypeTerm::Struct{ struct_repr, members } => { + let mut sl = StructLayout { + ty: st.desugar(dict), + layout: if let Some(sr) = struct_repr { + let sr = sr.desugar(dict); + LayoutType::parse( dict, &sr ).expect("invalid struct layout type") + } else { + eprintln!("choose default struct repr"); + LayoutType::Aligned + }, + + members, + offsets: std::collections::HashMap::new(), + size: ObjectSize::Unknown + }; + sl.init_offsets(dict); + + Some(sl) + } + + _ => { + eprintln!("not a struct"); + None + } + } + } +} diff --git a/test/test.sh b/test/test.sh index 0e3fc9b..f33ab02 100755 --- a/test/test.sh +++ b/test/test.sh @@ -8,13 +8,12 @@ run_test_case() { ----------------------------------------------------------------------------- Running test case ${TEST_NAME}" - ldmc "${SRC_TYPE}" "${DST_TYPE}" ../morphisms/*.morphism-base 2>|.tmp/ldmc_err 1>| target/src/${TEST_NAME}.c \ + ldmc -m "main : ${SRC_TYPE} --> ${DST_TYPE}" -o target/src/${TEST_NAME}.c 2>|.tmp/ldmc_err \ || (echo "... error at generation:"; cat .tmp/ldmc_err; return -1); gcc -I../morphisms/runtime/include target/src/${TEST_NAME}.c -o target/${TEST_NAME} \ || (echo "... error at compilation:"; return -2); - LEN="$(echo -n "${EXPECT}" | wc -c)" RESULT="$(echo -n ${INPUT} | ./target/${TEST_NAME} 2>.tmp/target_err | head -c ${LEN})" diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..39dd24f --- /dev/null +++ b/todo.md @@ -0,0 +1,79 @@ +* BUG: cant find morphism when path is trivial, or when + *some* members of a struct have trivial morphism + +* BUG: -O3 kills some Morphisms + +* BUG: erroneous code generation with Packed struct layout + +* type Aliases / typedefs (load from input file) + -- platform specializations + -- shortcuts + +* add highest-common-rung to generated morphism names + (to avoid potential ambiguities) + +* add bounds to Morphism type: + - subtype bounds + - trait bounds + - value bounds + +* data dependence: + - Each Struct creates a Context, + where a struct member becomes a type-variable, + available after it has been parsed from the input buffer. + - need some kind of partial Order over the member data fields, + to express parsing dependencies. + +* bounds: + -> ℕ ~ UInt64 ---> ℕ ~ UInt8 + - know that value fits into UInt8 ? + + -> <Digit 128> ~ UInt64 --> <Digit 128> ~ UInt8 + allows the following path: + <Digit 128> ~ UInt64 + -> <Digit 128> ~ Char ~ Ascii ~ native.UInt8 + -> <Digit 128> ~ native.UInt8 + + this will result in 'invalid digits' that are out of the ascii range + and is not wanted. + maybe the Morphism from digit to char should not exist for radix 128 (->value bounds on type vars)? + -fixed by adding explicit <Digit R>~UInt64 -morph-> <Digit R>~UInt8 + +* type descriptions: signed posints? + - Include minus sign '-' into the <Digit Radix> type ? + - or use [<Digit Radix> | Sign] ? + - or rather <SignedPosInt Radix Endianness> ~ { + sign: <Option Sign~Char>; + digits: <Seq <Digit 10>~Char> + }; + - ? + +* size estimation & memory allocation + - from each type definition, we need to derive + a form for an "allocation schema", + of which a value instance of that type defines + concrete length values for arrays and members + and thus the total required buffer size. + + - in parallel to each morphism we need to know + the output-allocation schema in accordance to + a given allocation schema of the input data. + + - Complex morphisms allocate a double buffering + with maximum required size at each point in the chain + + - optional: allocation free morphisms for members in struct morphism ? + - In-Place Morphisms + + +* improve debugability of "no morphism path found" + - find a heuristic to guess "implementation overhead" of + a missing morphism by its type + - Step 1: Calculate Connected Components of src and dst Type ; + - Step 2: For each combination of a vertex-pair from src and dst Components, + calculate the implementation overhead heuristic ; + - Step 3: suggest to the developer the n smallest morphism types that would + bridge the two components + + +* allow to define (ladder-typed) functions, not just morphisms