Compare commits
71 commits
master
...
topic-morp
Author | SHA1 | Date | |
---|---|---|---|
0c05d51ecd | |||
43dcb13f62 | |||
3938985b83 | |||
688ee303c4 | |||
bbbe54149e | |||
7ed2936024 | |||
410ba4019f | |||
557d345412 | |||
7375d14fcb | |||
1de4c7e7ad | |||
61ae353105 | |||
b83771594a | |||
bbaec58c83 | |||
dbe1a2c002 | |||
793ade4709 | |||
06b607eb6f | |||
89b730ea7d | |||
4674e75e99 | |||
64e8b96c92 | |||
6897b5e274 | |||
0564845951 | |||
1a3c194ec2 | |||
0d6378c72e | |||
cd53199dfb | |||
080e8b756c | |||
f8ef2d08a2 | |||
e5df94ebd1 | |||
74fc706c4b | |||
3d121fb57b | |||
d5fab37fca | |||
f03ebb2d2c | |||
8d7c60cfe0 | |||
76b64e583f | |||
7c17302f8b | |||
f9b0759f32 | |||
ff0fe2c877 | |||
3c04c7909c | |||
5f944fb403 | |||
9276336655 | |||
c40efda83b | |||
cff14cf096 | |||
edd3441511 | |||
dfa364bc0f | |||
62f0ff9eac | |||
76c005ac8b | |||
0eb8074644 | |||
0c9a4ccc8b | |||
24f9a0f5b5 | |||
7dd6352760 | |||
692a34c257 | |||
ea2504ff07 | |||
6f0a0f5927 | |||
4a705241fe | |||
efa584dfb5 | |||
783c70b2e2 | |||
a58ac1a69c | |||
1116457bcc | |||
27ea365755 | |||
923fe987dc | |||
3ed7a19270 | |||
6787e607a6 | |||
ef819b4711 | |||
3f1397735c | |||
67cec64dfc | |||
98592aa596 | |||
35b747ea15 | |||
39cba1ee57 | |||
583892f10d | |||
d98afc294d | |||
bce52e9fcf | |||
21bb33193a |
50 changed files with 4580 additions and 1014 deletions
Cargo.toml
examples
morphisms
angle.morphism-basecolor.morphism-basecomplex.morphism-basedelta-seq.morphism-basederef.morphism-basedigit.morphism-baseenergy.morphism-baselength_prefix.morphism-baseposint.morphism-basereal.morphism-base
runtime/include/array
temperature.morphism-basetimepoint.morphism-baseuint.morphism-baseunicode.morphism-basevalue_delim.morphism-basewheatstone.morphism-basezigzag.morphism-baseplatforms
src
test
todo.md
|
@ -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"
|
||||
|
|
1
examples/01-uint-example/.gitignore
vendored
Normal file
1
examples/01-uint-example/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
build/
|
14
examples/01-uint-example/main.c
Normal file
14
examples/01-uint-example/main.c
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
23
examples/01-uint-example/makefile
Normal file
23
examples/01-uint-example/makefile
Normal file
|
@ -0,0 +1,23 @@
|
|||
all: build/square
|
||||
.PHONY: build clean
|
||||
|
||||
build:
|
||||
mkdir -p build
|
||||
|
||||
build/morphisms.h: build
|
||||
ldmc \
|
||||
-m "marshal: \
|
||||
ℕ ~ <ℤ_ 0> ~ native.UInt64 \
|
||||
--> ℕ ~ <PosInt 10 BigEndian> ~ [~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8 ] \
|
||||
" \
|
||||
-m "demarshal: \
|
||||
ℕ ~ <PosInt 10 BigEndian> ~ [~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8 ] \
|
||||
--> ℕ ~ <ℤ_ 0> ~ 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
|
185
examples/02-farbfeld/main.c
Normal file
185
examples/02-farbfeld/main.c
Normal file
|
@ -0,0 +1,185 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <morphisms.h>
|
||||
|
||||
char * size = "\
|
||||
size ImageSize = Λwidth:ℕ ↦ Λheight:ℕ ↦ (width * height);\
|
||||
";
|
||||
|
||||
typedef float f32x4 __attribute__ ((vector_size (16)));
|
||||
|
||||
struct ColorRGBAu16 { uint16_t red; uint16_t green; uint16_t blue; uint16_t alpha; };
|
||||
struct ColorHSVAf32 { float hue; float saturation; float value; float alpha; };
|
||||
struct Image_SoA_HSV_f32x4 {
|
||||
uint64_t size;
|
||||
f32x4 * hue;
|
||||
f32x4 * saturation;
|
||||
f32x4 * value;
|
||||
f32x4 * alpha;
|
||||
};
|
||||
|
||||
uint64_t div_by_four(uint64_t x) {
|
||||
return (x/4) + (x&0b11);
|
||||
}
|
||||
|
||||
void filter_saturate(struct Image_SoA_HSV_f32x4 * image, float saturation_factor) {
|
||||
uint64_t vector_size = div_by_four(image->size);
|
||||
for( size_t i = 0; i < vector_size; ++i) {
|
||||
image->saturation[i] = image->saturation[i] * saturation_factor;
|
||||
}
|
||||
}
|
||||
|
||||
struct Farbfeld {
|
||||
uint64_t magic;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint16_t data[];
|
||||
};
|
||||
|
||||
struct Farbfeld *read_farbfeld(const char *filename) {
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if (!f) return NULL;
|
||||
|
||||
char magic_bytes[8];
|
||||
if (fread(magic_bytes, 1, 8, f) != 8 || memcmp(magic_bytes, "farbfeld", 8) != 0) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t width, height;
|
||||
if (fread(&width, 4, 1, f) != 1 || fread(&height, 4, 1, f) != 1) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
width = __builtin_bswap32(width);
|
||||
height = __builtin_bswap32(height);
|
||||
|
||||
size_t npixels = (size_t)width * height;
|
||||
size_t datasize = npixels * 4 * sizeof(uint16_t); // RGBA, 4 channels
|
||||
|
||||
struct Farbfeld *img = malloc(sizeof(struct Farbfeld) + datasize);
|
||||
if (!img) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
img->magic = 0x6661726266656c64ULL; // "farbfeld"
|
||||
img->width = width;
|
||||
img->height = height;
|
||||
|
||||
if (fread(img->data, 1, datasize, f) != datasize) {
|
||||
free(img);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Convert from big-endian to host byte order
|
||||
for (size_t i = 0; i < npixels * 4; ++i)
|
||||
img->data[i] = __builtin_bswap16(img->data[i]);
|
||||
|
||||
fclose(f);
|
||||
return img;
|
||||
}
|
||||
|
||||
int write_farbfeld(const char *filename, const struct Farbfeld *img) {
|
||||
FILE *f = fopen(filename, "wb");
|
||||
if (!f) return -1;
|
||||
|
||||
// Write magic bytes
|
||||
if (fwrite("farbfeld", 1, 8, f) != 8) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Convert and write width and height as big-endian
|
||||
uint32_t w_be = __builtin_bswap32(img->width);
|
||||
uint32_t h_be = __builtin_bswap32(img->height);
|
||||
if (fwrite(&w_be, 4, 1, f) != 1 || fwrite(&h_be, 4, 1, f) != 1) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Convert and write pixel data as big-endian
|
||||
size_t npixels = (size_t)img->width * img->height;
|
||||
for (size_t i = 0; i < npixels * 4; ++i) {
|
||||
uint16_t be_val = __builtin_bswap16(img->data[i]);
|
||||
if (fwrite(&be_val, 2, 1, f) != 1) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
/* read Farbfeld Format */
|
||||
struct Farbfeld * farbfeld;
|
||||
if( argc > 1 )
|
||||
farbfeld = read_farbfeld(argv[1]);
|
||||
else {
|
||||
fprintf(stderr, "Error: no input file specified!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* morph into SIMD friendly HSVf32 image */
|
||||
struct Image_SoA_HSV_f32x4 hsv_image;
|
||||
hsv_image.size = farbfeld->width * farbfeld->height;
|
||||
uint64_t vector_size = 1 + (hsv_image.size-1)/4 ;
|
||||
hsv_image.hue = malloc( vector_size * sizeof(f32x4) );
|
||||
hsv_image.saturation = malloc( vector_size * sizeof(f32x4) );
|
||||
hsv_image.value = malloc( vector_size * sizeof(f32x4) );
|
||||
hsv_image.alpha = malloc( vector_size * sizeof(f32x4) );
|
||||
|
||||
#define VECTOR_SIZE 4
|
||||
|
||||
for(uint64_t i = 0; i < farbfeld->width*farbfeld->height; i += VECTOR_SIZE) {
|
||||
struct ColorHSVAf32 hsv[VECTOR_SIZE];
|
||||
uint64_t vector_idx = i / VECTOR_SIZE;
|
||||
|
||||
for( unsigned j = 0; j < VECTOR_SIZE; ++j ) {
|
||||
if( (i+j) < farbfeld->width*farbfeld->height ) {
|
||||
morph_RGBAu16_to_HSVAf32( (void*)&farbfeld->data[4*(i+j)], (void*)&hsv[j] );
|
||||
|
||||
// morph AoS to SoA
|
||||
hsv_image.hue[vector_idx][j] = hsv[j].hue;
|
||||
hsv_image.saturation[vector_idx][j] = hsv[j].saturation;
|
||||
hsv_image.value[vector_idx][j] = hsv[j].value;
|
||||
hsv_image.alpha[vector_idx][j] = hsv[j].alpha;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply filter */
|
||||
filter_saturate(&hsv_image, 0.1);
|
||||
|
||||
/* morph back to RGBu16 */
|
||||
//memset(source_image.data, 0, source_image.size * sizeof(struct ColorRGBAu16));
|
||||
for(uint64_t i = 0; i < farbfeld->width*farbfeld->height; ++i) {
|
||||
// morph SoA to AoS
|
||||
struct ColorHSVAf32 hsv = {
|
||||
.hue = hsv_image.hue[i/4][i%4],
|
||||
.saturation = hsv_image.saturation[i/4][i%4],
|
||||
.value = hsv_image.value[i/4][i%4],
|
||||
.alpha = hsv_image.alpha[i/4][i%4],
|
||||
};
|
||||
|
||||
// morph Hsv to Rgb
|
||||
morph_HSVAf32_to_RGBAu16( (void*)&hsv, (void*)& farbfeld->data[i*4] );
|
||||
}
|
||||
|
||||
/* write farbfeld */
|
||||
if( argc > 2 ) {
|
||||
fprintf(stderr, "write farbfeld to %s\n", argv[2]);
|
||||
write_farbfeld(argv[2], farbfeld);
|
||||
} else {
|
||||
fprintf(stderr, "Error: no output file specified!");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
60
examples/02-farbfeld/makefile
Normal file
60
examples/02-farbfeld/makefile
Normal file
|
@ -0,0 +1,60 @@
|
|||
|
||||
all: build/color-filter
|
||||
.PHONY: all clean
|
||||
|
||||
build:
|
||||
mkdir -p build
|
||||
|
||||
build/morphisms.h: build
|
||||
ldmc \
|
||||
-m "morph_RGBAu16_to_HSVAf32 : \
|
||||
RgbaColor ~ RGB ~ { \
|
||||
red: ℝ ~ <QuantizedLinear 0 1 65535> \
|
||||
~ ℕ ~ <PosInt 256 BigEndian> \
|
||||
~ [~<StaticLength 2> <Digit 256>~<ℤ_ 256>~native.UInt8 ]; \
|
||||
green: ℝ ~ <QuantizedLinear 0 1 65535> \
|
||||
~ ℕ ~ <PosInt 256 BigEndian> \
|
||||
~ [~<StaticLength 2> <Digit 256>~<ℤ_ 256>~native.UInt8 ]; \
|
||||
blue: ℝ ~ <QuantizedLinear 0 1 65535> \
|
||||
~ ℕ ~ <PosInt 256 BigEndian> \
|
||||
~ [~<StaticLength 2> <Digit 256>~<ℤ_ 256>~native.UInt8 ]; \
|
||||
alpha: ℝ ~ <QuantizedLinear 0 1 65535> \
|
||||
~ ℕ ~ <PosInt 256 BigEndian> \
|
||||
~ [~<StaticLength 2> <Digit 256>~<ℤ_ 256>~native.UInt8 ]; \
|
||||
} \
|
||||
--> RgbaColor ~ HSV ~ { \
|
||||
hue: Angle ~ Turns ~ ℝ ~ native.Float32; \
|
||||
saturation: ℝ ~ native.Float32; \
|
||||
value: ℝ ~ native.Float32; \
|
||||
alpha: ℝ ~ native.Float32; \
|
||||
} \
|
||||
" \
|
||||
-m "morph_HSVAf32_to_RGBAu16 : \
|
||||
RgbaColor ~ HSV ~ { \
|
||||
hue: Angle~Turns~ℝ~native.Float32; \
|
||||
saturation: ℝ~native.Float32; \
|
||||
value: ℝ~native.Float32; \
|
||||
alpha: ℝ ~ native.Float32; \
|
||||
} \
|
||||
--> RgbaColor ~ RGB ~ <Struct \
|
||||
red: ℝ~<QuantizedLinear 0 1 65535> \
|
||||
~ ℕ ~ <PosInt 256 BigEndian> \
|
||||
~ [~<StaticLength 2> <Digit 256>~<ℤ_ 256>~native.UInt8]; \
|
||||
green: ℝ~<QuantizedLinear 0 1 65535> \
|
||||
~ ℕ ~ <PosInt 256 BigEndian> \
|
||||
~ [~<StaticLength 2> <Digit 256>~<ℤ_ 256>~native.UInt8]; \
|
||||
blue: ℝ~<QuantizedLinear 0 1 65535> \
|
||||
~ ℕ ~ <PosInt 256 BigEndian> \
|
||||
~ [~<StaticLength 2> <Digit 256>~<ℤ_ 256>~native.UInt8]; \
|
||||
alpha: ℝ~<QuantizedLinear 0 1 65535> \
|
||||
~ ℕ ~ <PosInt 256 BigEndian> \
|
||||
~ [~<StaticLength 2> <Digit 256>~<ℤ_ 256>~native.UInt8]; \
|
||||
> \
|
||||
" \
|
||||
-o build/morphisms.h
|
||||
|
||||
build/color-filter: build/morphisms.h
|
||||
gcc -g -O1 -lm -Ibuild -I../../morphisms/runtime/include/ main.c -o build/colorfilter
|
||||
|
||||
clean:
|
||||
rm build/ -rf
|
|
@ -2,71 +2,45 @@
|
|||
#define PHI 6.28318530718
|
||||
```
|
||||
|
||||
morph_angle_as_degrees_to_turns_float ()
|
||||
Angle ~ Degrees ~ ℝ ~ native.Float
|
||||
--> Angle ~ Turns ~ ℝ ~ native.Float
|
||||
```
|
||||
*dst = *src / 360.0;
|
||||
return 0;
|
||||
```
|
||||
morph angle_as_degrees_to_turns_float :
|
||||
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;
|
||||
```
|
||||
morph angle_as_degrees_to_turns_double :
|
||||
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;
|
||||
```
|
||||
morph angle_as_turns_to_degrees_float :
|
||||
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;
|
||||
```
|
||||
morph angle_as_turns_to_degrees_double :
|
||||
Angle ~ Turns ~ ℝ ~ native.Float64
|
||||
--> Angle ~ Degrees ~ ℝ ~ native.Float64
|
||||
= ```*dst = *src * 360.0;```;
|
||||
|
||||
|
||||
morph angle_as_radians_to_turns_float :
|
||||
Angle ~ Radians ~ ℝ ~ native.Float32
|
||||
--> Angle ~ Turns ~ ℝ ~ native.Float32
|
||||
= ```*dst = *src / PHI;```;
|
||||
|
||||
morph angle_as_radians_to_turns_double :
|
||||
Angle ~ Radians ~ ℝ ~ native.Float64
|
||||
--> Angle ~ Turns ~ ℝ ~ native.Float64
|
||||
= ```*dst = *src / PHI;```;
|
||||
|
||||
|
||||
morph_angle_as_radians_to_turns_float ()
|
||||
Angle ~ Radians ~ ℝ ~ native.Float
|
||||
--> Angle ~ Turns ~ ℝ ~ native.Float
|
||||
```
|
||||
*dst = *src / PHI;
|
||||
return 0;
|
||||
```
|
||||
morph angle_as_turns_to_radians_float :
|
||||
Angle ~ Turns ~ ℝ ~ native.Float32
|
||||
--> Angle ~ Radians ~ ℝ ~ 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;
|
||||
```
|
||||
|
||||
|
||||
morph_angle_as_turns_to_radians_float ()
|
||||
Angle ~ Turns ~ ℝ ~ native.Float
|
||||
--> Angle ~ Radians ~ ℝ ~ native.Float
|
||||
```
|
||||
*dst = *src * PHI;
|
||||
return 0;
|
||||
```
|
||||
|
||||
morph_angle_as_degrees_to_radians_double ()
|
||||
Angle ~ Turns ~ ℝ ~ native.Double
|
||||
--> Angle ~ Radians ~ ℝ ~ native.Double
|
||||
```
|
||||
*dst = *src * PHI;
|
||||
return 0;
|
||||
```
|
||||
morph angle_as_turns_to_radians_double :
|
||||
Angle ~ Turns ~ ℝ ~ native.Float64
|
||||
--> Angle ~ Radians ~ ℝ ~ native.Float64
|
||||
= ```*dst = *src * PHI;```;
|
||||
|
|
79
morphisms/color.morphism-base
Normal file
79
morphisms/color.morphism-base
Normal file
|
@ -0,0 +1,79 @@
|
|||
```
|
||||
#include <math.h>
|
||||
```
|
||||
|
||||
morph color_as_rgb_to_hsv :
|
||||
RgbaColor ~ RGB ~ {
|
||||
red: ℝ ~ native.Float32;
|
||||
green: ℝ ~ native.Float32;
|
||||
blue: ℝ ~ native.Float32;
|
||||
alpha: ℝ ~ native.Float32;
|
||||
}
|
||||
--> RgbaColor ~ HSV ~ {
|
||||
hue: Angle ~ Turns ~ ℝ ~ native.Float32;
|
||||
saturation: ℝ ~ native.Float32;
|
||||
value: ℝ ~ native.Float32;
|
||||
alpha: ℝ ~ native.Float32;
|
||||
}
|
||||
= ```
|
||||
float max = fmaxf(fmaxf(src->red, src->green), src->blue);
|
||||
float min = fminf(fminf(src->red, src->green), src->blue);
|
||||
float delta = max - min;
|
||||
|
||||
float hue_turns;
|
||||
if (delta == 0) {
|
||||
hue_turns = 0;
|
||||
} else if (max == src->red) {
|
||||
hue_turns = fmodf(((src->green - src->blue) / delta + 6), 6) / 6.0;
|
||||
} else if (max == src->green) {
|
||||
hue_turns = (((src->blue - src->red) / delta) + 2) / 6.0;
|
||||
} else {
|
||||
hue_turns = (((src->red - src->green) / delta) + 4) / 6.0;
|
||||
}
|
||||
|
||||
dst->hue = hue_turns;
|
||||
dst->saturation = (max == 0) ? 0 : (delta / max);
|
||||
dst->value = max;
|
||||
dst->alpha = src->alpha;
|
||||
```;
|
||||
|
||||
|
||||
morph color_as_hsv_to_rgb :
|
||||
RgbaColor ~ HSV ~ {
|
||||
hue: Angle ~ Turns ~ ℝ ~ native.Float32;
|
||||
saturation: ℝ ~ native.Float32;
|
||||
value: ℝ ~ native.Float32;
|
||||
alpha: ℝ ~ native.Float32;
|
||||
}
|
||||
--> RgbaColor ~ RGB ~ {
|
||||
red: ℝ ~ native.Float32;
|
||||
green: ℝ ~ native.Float32;
|
||||
blue: ℝ ~ native.Float32;
|
||||
alpha: ℝ ~ native.Float32;
|
||||
}
|
||||
= ```
|
||||
float C = src->value * src->saturation;
|
||||
float X = C * (1 - fabsf(fmodf(src->hue * 6.0, 2) - 1));
|
||||
float m = src->value - C;
|
||||
|
||||
float r, g, b;
|
||||
|
||||
if (src->hue >= 0 && src->hue < 1.0 / 6.0) {
|
||||
r = C; g = X; b = 0;
|
||||
} else if (src->hue >= 1.0 / 6.0 && src->hue < 2.0 / 6.0) {
|
||||
r = X; g = C; b = 0;
|
||||
} else if (src->hue >= 2.0 / 6.0 && src->hue < 3.0 / 6.0) {
|
||||
r = 0; g = C; b = X;
|
||||
} else if (src->hue >= 3.0 / 6.0 && src->hue < 4.0 / 6.0) {
|
||||
r = 0; g = X; b = C;
|
||||
} else if (src->hue >= 4.0 / 6.0 && src->hue < 5.0 / 6.0) {
|
||||
r = X; g = 0; b = C;
|
||||
} else {
|
||||
r = C; g = 0; b = X;
|
||||
}
|
||||
|
||||
dst->red = r + m;
|
||||
dst->green = g + m;
|
||||
dst->blue = b + m;
|
||||
dst->alpha = src->alpha;
|
||||
```;
|
32
morphisms/complex.morphism-base
Normal file
32
morphisms/complex.morphism-base
Normal file
|
@ -0,0 +1,32 @@
|
|||
```
|
||||
```
|
||||
|
||||
morph complex_as_polar_to_cartesian :
|
||||
ℂ ~ Polar
|
||||
~ {~Aligned
|
||||
phi: Angle~Radians~ℝ~native.Float64;
|
||||
val: ℝ~native.Float64;
|
||||
}
|
||||
--> ℂ ~ Cartesian
|
||||
~ {~Aligned
|
||||
x: ℝ~native.Float64;
|
||||
y: ℝ~native.Float64;
|
||||
}
|
||||
= ```
|
||||
return 0;
|
||||
```;
|
||||
|
||||
morph complex_as_cartesian_to_polar :
|
||||
ℂ ~ Cartesian
|
||||
~ {~Aligned
|
||||
x: ℝ~native.Float64;
|
||||
y: ℝ~native.Float64;
|
||||
}
|
||||
--> ℂ ~ Polar
|
||||
~ {~Aligned
|
||||
phi: Angle~Radians~ℝ~native.Float64;
|
||||
val: ℝ~native.Float64;
|
||||
}
|
||||
= ```
|
||||
return 0;
|
||||
```;
|
32
morphisms/delta-seq.morphism-base
Normal file
32
morphisms/delta-seq.morphism-base
Normal file
|
@ -0,0 +1,32 @@
|
|||
```
|
||||
#include <array/length-prefix.h>
|
||||
```
|
||||
|
||||
morph delta_seq_encode :
|
||||
[~<LengthPrefix native.UInt64> ℕ~native.UInt64 ]
|
||||
--> [~DeltaSeq ℕ]
|
||||
~ [~<LengthPrefix native.UInt64> ℤ~native.Int64 ]
|
||||
= ```
|
||||
PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, _ℤ_nativeInt64_, clear)( dst );
|
||||
for( size_t i = 0; i < src->len; ++i ) {
|
||||
uint64_t cur = src->items[i];
|
||||
uint64_t prev = 0;
|
||||
if (i > 0) {
|
||||
prev = src->items[i-1];
|
||||
}
|
||||
PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, _ℤ_nativeInt64_, push)( dst, cur-prev );
|
||||
}
|
||||
```;
|
||||
|
||||
morph delta_seq_decode :
|
||||
[~DeltaSeq ℕ]
|
||||
~ [~<LengthPrefix native.UInt64> ℤ~native.Int64 ]
|
||||
--> [~<LengthPrefix native.UInt64> ℕ~native.UInt64 ]
|
||||
= ```
|
||||
PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, _ℕ_nativeUInt64_, clear)( dst );
|
||||
uint64_t cur = 0;
|
||||
for( size_t i = 0; i < src->len; ++i ) {
|
||||
cur += src->items[i];
|
||||
PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, _ℕ_nativeUInt64_, push)( dst, cur );
|
||||
}
|
||||
```;
|
10
morphisms/deref.morphism-base
Normal file
10
morphisms/deref.morphism-base
Normal file
|
@ -0,0 +1,10 @@
|
|||
```
|
||||
```
|
||||
|
||||
morph ref_to_val8 : ∀T (T :<= native.UInt8)
|
||||
< Ref~Ptr T >
|
||||
~ native.Address
|
||||
--> T
|
||||
=```
|
||||
*dst = **src ;
|
||||
```;
|
|
@ -1,11 +1,10 @@
|
|||
```
|
||||
#include <stdio.h>
|
||||
```
|
||||
|
||||
morph_digit_as_char_to_uint8 (Radix:ℤ)
|
||||
morph digit_as_char_to_uint8 : ∀Radix:ℕ
|
||||
<Digit Radix> ~ Char ~ Ascii ~ native.UInt8
|
||||
--> <Digit Radix> ~ native.UInt8
|
||||
```
|
||||
--> <Digit Radix> ~ <ℤ_ Radix> ~ native.UInt8
|
||||
= ```
|
||||
if( *src >= '0' && *src <= '9' )
|
||||
*dst = *src - '0';
|
||||
else if( *src >= 'a' && *src <= 'f')
|
||||
|
@ -23,35 +22,13 @@ morph_digit_as_char_to_uint8 (Radix:ℤ)
|
|||
fprintf(stderr, "digit %u is out of range for radix %u\n", *dst, Radix);
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
```;
|
||||
|
||||
morph_digit_as_char_to_uint64 (Radix:ℤ)
|
||||
<Digit Radix> ~ Char ~ Ascii ~ native.UInt8
|
||||
--> <Digit Radix> ~ native.UInt64
|
||||
```
|
||||
if( *src >= '0' && *src <= '9' )
|
||||
*dst = *src - '0';
|
||||
else if( *src >= 'a' && *src <= 'f')
|
||||
*dst = 0xa + *src - 'a';
|
||||
else if( *src >= 'A' && *src <= 'F')
|
||||
*dst = 0xa + *src - 'A';
|
||||
else {
|
||||
fprintf(stderr, "invalid digit 0x%x\n", *src);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( *dst < Radix ) {
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr, "digit %u is out of range for radix %u\n", *dst, Radix);
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
morph_digit_as_uint8_to_char (Radix:ℤ_16)
|
||||
<Digit Radix> ~ native.UInt8
|
||||
morph digit_as_uint8_to_char : ∀Radix:ℕ
|
||||
<Digit Radix> ~ <ℤ_ Radix> ~ native.UInt8
|
||||
--> <Digit Radix> ~ Char ~ Ascii ~ native.UInt8
|
||||
```
|
||||
= ```
|
||||
if ( *src < 10 )
|
||||
*dst = *src + '0';
|
||||
else if( *dst < 16 )
|
||||
|
@ -60,22 +37,4 @@ 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)
|
||||
<Digit Radix> ~ native.UInt64
|
||||
--> <Digit Radix> ~ Char ~ Ascii ~ native.UInt8
|
||||
```
|
||||
if ( *src < 10 )
|
||||
*dst = *src + '0';
|
||||
else if( *dst < 16 )
|
||||
*dst = *src - 0xa + 'a';
|
||||
else {
|
||||
fprintf(stderr, "digit %u is out of rage for char\n", *dst);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
```
|
||||
```;
|
||||
|
|
16
morphisms/energy.morphism-base
Normal file
16
morphisms/energy.morphism-base
Normal file
|
@ -0,0 +1,16 @@
|
|||
```
|
||||
```
|
||||
|
||||
morph energy_as_wh_to_joule :
|
||||
Energy ~ Wh ~ ℝ ~ native.Float64
|
||||
--> Energy ~ Ws ~ ℝ ~ native.Float64
|
||||
= ```
|
||||
*dst = *src * 3600.0;
|
||||
```;
|
||||
|
||||
morph energy_as_joule_to_wh :
|
||||
Energy ~ Ws ~ ℝ ~ native.Float64
|
||||
--> Energy ~ Wh ~ ℝ ~ native.Float64
|
||||
= ```
|
||||
*dst = *src / 3600.0;
|
||||
```;
|
|
@ -3,45 +3,61 @@
|
|||
#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>
|
||||
```
|
||||
length_prefix_uint64_t_array_uint8_t_clear(dst);
|
||||
morph array_as_static_to_lenpfx : ∀Len:ℕ ∀T
|
||||
[~<StaticLength Len> T]
|
||||
--> [~<LengthPrefix native.UInt64> T]
|
||||
= ```
|
||||
//PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, clear)( dst );
|
||||
length_prefix_nativeUInt64_array_##T##_clear(dst);
|
||||
for( nativeUInt64 i = 0; i < Len; ++i )
|
||||
length_prefix_nativeUInt64_array_##T##_push(dst, src->items[i]);
|
||||
//PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, push)( dst, src->items[i] );
|
||||
```;
|
||||
|
||||
morph array_as_lenpfx_to_static : ∀Len:ℕ ∀T
|
||||
[~<LengthPrefix native.UInt64> T ]
|
||||
--> [~<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 ∀Terminator:T
|
||||
[~<ValueTerminated Terminator> T ]
|
||||
--> [~<LengthPrefix native.UInt64> T ]
|
||||
= ```
|
||||
PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, clear)( dst );
|
||||
while( *src != Terminator )
|
||||
length_prefix_uint64_t_array_uint8_t_push(dst, *src++);
|
||||
PRESCAN_LENGTH_PREFIX_CALL(nativeUInt64, T, push)( dst, *src++ );
|
||||
```;
|
||||
|
||||
return 0;
|
||||
```
|
||||
|
||||
|
||||
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 ∀Terminator:T
|
||||
[~<LengthPrefix native.UInt64> T ]
|
||||
--> [~<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)
|
||||
<Seq~<LengthPrefix native.UInt64> T>
|
||||
--> <Seq~MsbCont T>
|
||||
```
|
||||
morph array_as_lenpfx_to_continuation_bit : ∀T
|
||||
[~<LengthPrefix native.UInt64> T ]
|
||||
--> [~MsbCont T ]
|
||||
= ```
|
||||
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;
|
||||
```
|
||||
```;
|
||||
|
|
|
@ -2,37 +2,47 @@
|
|||
#include <array/length-prefix.h>
|
||||
```
|
||||
|
||||
morph_nat_as_u64_to_pos ()
|
||||
morph nat_as_u64_to_pos :
|
||||
ℕ
|
||||
~ <ℤ_ 0>
|
||||
~ native.UInt64
|
||||
--> ℕ
|
||||
~ <PosInt 0 LittleEndian>
|
||||
~ <Seq~<LengthPrefix native.UInt64> <Digit 0>~native.UInt64>
|
||||
```
|
||||
~ [~<LengthPrefix native.UInt64> <Digit 0> ~<ℤ_ 0>~ native.UInt64 ]
|
||||
= ```
|
||||
dst->len = 1;
|
||||
dst->items[0] = *src;
|
||||
return 0;
|
||||
```
|
||||
```;
|
||||
|
||||
morph_nat_as_pos_to_u64 (Endianness:Type)
|
||||
morph nat_as_pos_to_u64 : ∀Endianness
|
||||
ℕ
|
||||
~ <PosInt 0 Endianness>
|
||||
~ <Seq~<LengthPrefix native.UInt64> <Digit 0>~native.UInt64>
|
||||
--> ℕ
|
||||
~ [~<LengthPrefix native.UInt64> <Digit 0> ~<ℤ_ 0>~ native.UInt64 ]
|
||||
-->
|
||||
ℕ
|
||||
~ <ℤ_ 0>
|
||||
~ native.UInt64
|
||||
```
|
||||
*dst = src->items[0];
|
||||
return 0;
|
||||
```
|
||||
= ```
|
||||
if( src->len == 0 )
|
||||
*dst = 0;
|
||||
else if ( src->len == 1 )
|
||||
*dst = src->items[0];
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Variable Length Integer too large for UInt64");
|
||||
return -1;
|
||||
}
|
||||
```;
|
||||
|
||||
morph_posint_radix_le (SrcRadix:ℤ, DstRadix:ℤ)
|
||||
morph posint_radix_le : ∀SrcRadix:ℕ ∀DstRadix:ℕ
|
||||
ℕ
|
||||
~ <PosInt SrcRadix LittleEndian>
|
||||
~ <Seq~<LengthPrefix native.UInt64> <Digit SrcRadix>~native.UInt64>
|
||||
--> ℕ
|
||||
~ [~<LengthPrefix native.UInt64> <Digit SrcRadix> ~<ℤ_ SrcRadix>~ native.UInt64 ]
|
||||
-->
|
||||
ℕ
|
||||
~ <PosInt DstRadix LittleEndian>
|
||||
~ <Seq~<LenghtPrefix native.UInt64> <Digit DstRadix>~native.UInt64>
|
||||
```
|
||||
~ [~<LenghtPrefix native.UInt64> <Digit DstRadix> ~<ℤ_ DstRadix>~ native.UInt64 ]
|
||||
= ```
|
||||
uint64_t value = 0;
|
||||
|
||||
for( uint64_t i = 0; i < src->len; ++i ) {
|
||||
|
@ -40,30 +50,28 @@ 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:ℤ)
|
||||
morph posint_radix_be : ∀SrcRadix:ℕ ∀DstRadix:ℕ
|
||||
ℕ
|
||||
~ <PosInt SrcRadix BigEndian>
|
||||
~ <Seq~<LengthPrefix native.UInt64> <Digit SrcRadix>~native.UInt64>
|
||||
~ [~<LengthPrefix native.UInt64> <Digit SrcRadix> ~<ℤ_ SrcRadix>~ native.UInt64 ]
|
||||
--> ℕ
|
||||
~ <PosInt DstRadix BigEndian>
|
||||
~ <Seq~<LengthPrefix native.UInt64> <Digit DstRadix>~native.UInt64>
|
||||
```
|
||||
~ [~<LengthPrefix native.UInt64> <Digit DstRadix> ~<ℤ_ DstRadix>~ native.UInt64 ]
|
||||
= ```
|
||||
uint64_t value = 0;
|
||||
|
||||
for( uint64_t i = 0; i < src->len; ++i ) {
|
||||
|
@ -91,28 +99,48 @@ morph_posint_radix_be (SrcRadix:ℤ, DstRadix:ℤ)
|
|||
value /= DstRadix;
|
||||
}
|
||||
#endif
|
||||
```;
|
||||
|
||||
return 0;
|
||||
```
|
||||
|
||||
morph_posint_endianness (Radix:ℤ)
|
||||
morph posint_endianness_le_to_be : ∀Radix:ℕ
|
||||
ℕ
|
||||
~ <PosInt Radix LittleEndian>
|
||||
~ <Seq~<LengthPrefix native.UInt64> <Digit Radix> ~ native.UInt64>
|
||||
~ [~<LengthPrefix native.UInt64> <Digit Radix> ~<ℤ_ Radix>~ native.UInt64 ]
|
||||
--> ℕ
|
||||
~ <PosInt Radix BigEndian>
|
||||
~ <Seq~<LengthPrefix native.UInt64> <Digit Radix> ~ native.UInt64>
|
||||
```
|
||||
return length_prefix_uint64_t_array_uint64_t_reverse( src, dst );
|
||||
```
|
||||
~ [~<LengthPrefix native.UInt64> <Digit Radix> ~<ℤ_ Radix>~ native.UInt64 ]
|
||||
= ```
|
||||
return length_prefix_nativeUInt64_array_nativeUInt64_reverse( (void*)src, (void*)dst );
|
||||
```;
|
||||
|
||||
morph_posint_endianness (Radix:ℤ)
|
||||
morph posint_endianness_be_to_le : ∀Radix:ℕ
|
||||
ℕ
|
||||
~ <PosInt Radix BigEndian>
|
||||
~ <Seq~<LengthPrefix native.UInt64> <Digit Radix> ~ native.UInt64>
|
||||
~ [~<LengthPrefix native.UInt64> <Digit Radix> ~<ℤ_ Radix>~ native.UInt64 ]
|
||||
--> ℕ
|
||||
~ <PosInt Radix LittleEndian>
|
||||
~ <Seq~<LengthPrefix native.UInt64> <Digit Radix> ~ native.UInt64>
|
||||
```
|
||||
return length_prefix_uint64_t_array_uint64_t_reverse( src, dst );
|
||||
```
|
||||
~ [~<LengthPrefix native.UInt64> <Digit Radix> ~<ℤ_ Radix>~ native.UInt64 ]
|
||||
= ```
|
||||
return length_prefix_nativeUInt64_array_nativeUInt64_reverse( (void*)src, (void*)dst );
|
||||
```;
|
||||
|
||||
morph posint_uint32_endianness_be_to_le :
|
||||
ℕ
|
||||
~ <PosInt 256 BigEndian>
|
||||
~ [~<StaticLength 8> <Digit 256> ~<ℤ_ 256>~ native.UInt8 ]
|
||||
--> ℕ
|
||||
~ <PosInt 256 LittleEndian>
|
||||
~ [~<StaticLength 8> <Digit 256> ~<ℤ_ 256>~ native.UInt8 ]
|
||||
= ```
|
||||
*dst = __builtin_bswap32(*src);
|
||||
```;
|
||||
|
||||
morph posint_uint32_endianness_le_to_be :
|
||||
ℕ
|
||||
~ <PosInt 256 LittleEndian>
|
||||
~ [~<StaticLength 8> <Digit 256> ~<ℤ_ 256>~ native.UInt8 ]
|
||||
--> ℕ
|
||||
~ <PosInt 256 BigEndian>
|
||||
~ [~<StaticLength 8> <Digit 256> ~<ℤ_ 256>~ native.UInt8 ]
|
||||
= ```
|
||||
*dst = __builtin_bswap32(*src);
|
||||
```;
|
||||
|
|
|
@ -2,104 +2,87 @@
|
|||
#include <stdio.h>
|
||||
```
|
||||
|
||||
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;
|
||||
```
|
||||
morph real_as_decimalstr_to_float :
|
||||
ℝ ~ <PosInt 10 BigEndian> ~ [~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8 ]
|
||||
--> ℝ ~ 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;
|
||||
```
|
||||
morph real_as_decimalstr_to_double :
|
||||
ℝ ~ <PosInt 10 BigEndian> ~ [~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8 ]
|
||||
--> ℝ ~ native.Float64
|
||||
= ```sscanf(src, "%lf", dst);```;
|
||||
|
||||
morph_real_as_float_to_decimalstr ()
|
||||
ℝ ~ native.Float
|
||||
--> ℝ ~ <PosInt 10 BigEndian> ~ <Seq~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8>
|
||||
```
|
||||
sprintf(dst, "%f", *src);
|
||||
return 0;
|
||||
```
|
||||
morph real_as_float_to_decimalstr :
|
||||
ℝ ~ native.Float32
|
||||
--> ℝ ~ <PosInt 10 BigEndian> ~ [~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8 ]
|
||||
= ```sprintf(dst, "%f", *src);```;
|
||||
|
||||
morph_real_as_double_to_decimalstr ()
|
||||
ℝ ~ native.Double
|
||||
--> ℝ ~ <PosInt 10 BigEndian> ~ <Seq~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8>
|
||||
```
|
||||
sprintf(dst, "%f", *src);
|
||||
return 0;
|
||||
```
|
||||
morph real_as_double_to_decimalstr :
|
||||
ℝ ~ native.Float64
|
||||
--> ℝ ~ <PosInt 10 BigEndian> ~ [~<ValueTerminated 0> <Digit 10>~Char~Ascii~native.UInt8 ]
|
||||
= ```sprintf(dst, "%f", *src);```;
|
||||
|
||||
morph real_as_float_to_double :
|
||||
ℝ ~ native.Float32
|
||||
--> ℝ ~ native.Float64
|
||||
= ```*dst = *src;```;
|
||||
|
||||
morph_real_as_float_to_double ()
|
||||
ℝ ~ native.Float
|
||||
--> ℝ ~ native.Double
|
||||
```
|
||||
*dst = *src;
|
||||
return 0;
|
||||
```
|
||||
|
||||
morph_real_as_double_to_float ()
|
||||
ℝ ~ native.Double
|
||||
--> ℝ ~ native.Float
|
||||
```
|
||||
morph real_as_double_to_float :
|
||||
ℝ ~ native.Float64
|
||||
--> ℝ ~ native.Float32
|
||||
= ```
|
||||
fprintf(stderr, "Warning: morphin Double -> Float. Precision loss!");
|
||||
*dst = *src;
|
||||
return 0;
|
||||
```
|
||||
```;
|
||||
|
||||
morph_real_as_u64_to_float ()
|
||||
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 ()
|
||||
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_quantized_linear_to_float (Begin: ℝ, End: ℝ, Steps: ℤ)
|
||||
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
|
||||
morph real_as_float_to_quantized_linear : ∀Begin:ℝ ∀End:ℝ ∀Steps:ℕ
|
||||
ℝ ~ 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: ℤ)
|
||||
morph real_as_quantized_linear_to_double : ∀Begin:ℝ ∀End:ℝ ∀Steps:ℕ
|
||||
ℝ ~ <QuantizedLinear Begin End Steps> ~ ℕ ~ native.UInt64
|
||||
--> ℝ ~ native.Double
|
||||
```
|
||||
*dst = (double)Begin + ( *src * ((double)End - (double)Begin) ) / (double)Steps;
|
||||
return 0;
|
||||
```
|
||||
--> ℝ ~ native.Float64
|
||||
= ```
|
||||
*dst = (double)Begin + ( *src * ((double)End - (double)Begin) ) / (double)Steps;
|
||||
```;
|
||||
|
||||
morph_real_as_double_to_quantized_linear (Begin: ℝ, End: ℝ, Steps: ℤ)
|
||||
ℝ ~ native.Double
|
||||
morph real_as_double_to_quantized_linear : ∀Begin:ℝ ∀End:ℝ ∀Steps:ℕ
|
||||
ℝ ~ native.Float64
|
||||
--> ℝ ~ <QuantizedLinear Begin End Steps> ~ ℕ ~ native.UInt64
|
||||
```
|
||||
= ```
|
||||
*dst = ((*src - (double)Begin) * (double)Steps) / ((double)End - (double)Begin);
|
||||
return 0;
|
||||
```
|
||||
```;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,34 +1,49 @@
|
|||
```
|
||||
```
|
||||
|
||||
morph_celsius_to_kelvin ()
|
||||
Temperature ~ Celsius ~ ℝ ~ native.Float
|
||||
--> Temperature ~ Kelvin ~ ℝ ~ native.Float
|
||||
```
|
||||
*dst = *src + 273.15;
|
||||
return 0;
|
||||
```
|
||||
morph celsius_to_kelvin :
|
||||
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;
|
||||
```
|
||||
morph kelvin_to_celsius :
|
||||
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;
|
||||
```
|
||||
morph celsius_to_fahrenheit :
|
||||
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;
|
||||
```
|
||||
morph fahrenheit_to_celsius :
|
||||
Temperature ~ Fahrenheit ~ ℝ ~ native.Float32
|
||||
--> Temperature ~ Celsius ~ ℝ ~ native.Float32
|
||||
=```*dst = (*src - 32.0) * 5.0 / 9.0;```;
|
||||
|
||||
morph pt100_resistance_to_celsius :
|
||||
Temperature ~ PT100 ~ Resistance ~ Ohms ~ ℝ ~ native.Float64
|
||||
--> Temperature ~ Celsius ~ ℝ ~ native.Float64
|
||||
= ```
|
||||
double resistance = *src;
|
||||
|
||||
// Constants for PT100 (ITS-90 standard)
|
||||
#define R0 100.0
|
||||
#define A 3.9083e-3
|
||||
#define B -5.775e-7
|
||||
|
||||
// Solve the quadratic equation: R = R0 * (1 + A*T + B*T^2)
|
||||
// Rearranged: B*T^2 + A*T + (1 - R/R0) = 0
|
||||
double a = B;
|
||||
double b = A;
|
||||
double c = 1.0 - (resistance / R0);
|
||||
|
||||
double discriminant = b * b - 4 * a * c;
|
||||
|
||||
if (discriminant < 0) {
|
||||
fprintf(stderr, "invalid resistance");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*dst = (-b + sqrt(discriminant)) / (2 * a); // use positive root
|
||||
```;
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
#include <time.h>
|
||||
```
|
||||
|
||||
morph_unixtime_to_iso ()
|
||||
morph unixtime_to_iso :
|
||||
TimePoint ~ <TimeSince UnixEpoch> ~ Duration ~ Seconds ~ ℝ ~ <QuantizedLinear 0 1 1> ~ ℕ ~ native.UInt64
|
||||
--> TimePoint ~ ISO8601 ~ <Seq~<ValueTerminated 0> Char~Ascii~native.UInt8>
|
||||
```
|
||||
--> TimePoint ~ ISO8601 ~ [~<ValueTerminated 0> Char~Ascii~native.UInt8 ]
|
||||
= ```
|
||||
time_t rawtime = (time_t)(*src);
|
||||
struct tm *timeinfo = gmtime(&rawtime);
|
||||
if (!timeinfo) return -1;
|
||||
|
||||
strftime((char*)dst, 20, "%Y-%m-%dT%H:%M:%SZ", timeinfo);
|
||||
return 0;
|
||||
```
|
||||
```;
|
||||
|
|
20
morphisms/uint.morphism-base
Normal file
20
morphisms/uint.morphism-base
Normal file
|
@ -0,0 +1,20 @@
|
|||
```
|
||||
```
|
||||
|
||||
morph int_as_u8_to_u64 : ∀N:ℕ
|
||||
<ℤ_ N> ~ native.UInt8
|
||||
--> <ℤ_ N> ~ native.UInt64
|
||||
= ```*dst = *src;```;
|
||||
|
||||
morph int_as_u64_to_u8 : ∀N:ℕ
|
||||
<ℤ_ N> ~ native.UInt64
|
||||
--> <ℤ_ N> ~ native.UInt8
|
||||
= ```
|
||||
if ( N < 256 ) {
|
||||
*dst = *src % N;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "radix %u is out of rage for UInt8\n", N);
|
||||
return -1;
|
||||
}
|
||||
```;
|
|
@ -2,23 +2,19 @@
|
|||
#include <stdio.h>
|
||||
```
|
||||
|
||||
morph_string_as_ascii_to_utf8 ()
|
||||
<Seq ~ <ValueTerminated 0> Char~Ascii~native.UInt8>
|
||||
--> <Seq Char~Unicode>
|
||||
~ UTF-8
|
||||
~ <Seq~<ValueTerminated 0> native.UInt8>
|
||||
```
|
||||
morph string_as_ascii_to_utf8 :
|
||||
[~<ValueTerminated 0> Char~Ascii~native.UInt8 ]
|
||||
--> [Char~Unicode] ~ UTF-8 ~ [~<ValueTerminated 0> native.UInt8 ]
|
||||
= ```
|
||||
while( *src ) { *dst++ = *src++; }
|
||||
*dst = 0;
|
||||
return 0;
|
||||
```
|
||||
```;
|
||||
|
||||
morph_string_as_utf8_to_ascii ()
|
||||
<Seq Char~Unicode>
|
||||
~ UTF-8
|
||||
~ <Seq~<ValueTerminated 0> native.UInt8>
|
||||
--> <Seq ~ <ValueTerminated 0> Char~Ascii~native.UInt8>
|
||||
```
|
||||
morph string_as_utf8_to_ascii :
|
||||
[Char~Unicode] ~ UTF-8 ~ [~<ValueTerminated 0> native.UInt8 ]
|
||||
--> [~<ValueTerminated 0> Char~Ascii~native.UInt8 ]
|
||||
= ```
|
||||
while( *src ) {
|
||||
if( *src < 128 ) {
|
||||
*dst++ = *src++;
|
||||
|
@ -28,31 +24,20 @@ morph_string_as_utf8_to_ascii ()
|
|||
}
|
||||
}
|
||||
*dst = 0;
|
||||
return 0;
|
||||
```
|
||||
```;
|
||||
|
||||
morph_string_as_ascii_to_utf32 ()
|
||||
<Seq ~ <ValueTerminated 0> Char~Ascii~native.UInt8>
|
||||
--> <Seq Char~Unicode>
|
||||
~ UTF-32
|
||||
~ <Seq~<ValueTerminated 0> native.UInt32>
|
||||
```
|
||||
morph string_as_ascii_to_utf32 :
|
||||
[~<ValueTerminated 0> Char~Ascii~native.UInt8 ]
|
||||
--> [Char~Unicode] ~ UTF-32 ~ [~<ValueTerminated 0> native.UInt32 ]
|
||||
= ```
|
||||
while( *src ) { *dst++ = *src++; }
|
||||
*dst = 0;
|
||||
return 0;
|
||||
```
|
||||
```;
|
||||
|
||||
morph_string_as_utf8_to_utf32 ()
|
||||
|
||||
<Seq Char~Unicode>
|
||||
~ UTF-8
|
||||
~ <Seq~<ValueTerminated 0> native.UInt8>
|
||||
|
||||
--> <Seq Char~Unicode>
|
||||
~ UTF-32
|
||||
~ <Seq~<ValueTerminated 0> native.UInt32>
|
||||
|
||||
```
|
||||
morph string_as_utf8_to_utf32 :
|
||||
[Char~Unicode] ~ UTF-8 ~ [~<ValueTerminated 0> native.UInt8 ]
|
||||
--> [Char~Unicode] ~ UTF-32 ~ [~<ValueTerminated 0> native.UInt32 ]
|
||||
= ```
|
||||
bool has_multibyte = false;
|
||||
uint32_t val = 0;
|
||||
while( *src ) {
|
||||
|
@ -89,6 +74,4 @@ morph_string_as_utf8_to_utf32 ()
|
|||
*dst++ = val;
|
||||
|
||||
*dst++ = 0;
|
||||
|
||||
return 0;
|
||||
```
|
||||
```;
|
||||
|
|
|
@ -3,97 +3,93 @@
|
|||
#include <stdlib.h>
|
||||
```
|
||||
|
||||
morph_seqseq_valsep_uint8 (T: Type, SrcDelim: T, DstDelim: T)
|
||||
< Seq <Seq T> >
|
||||
morph valsep_delim : ∀T ∀SrcDelim:T ∀DstDelim:T
|
||||
[[T]]
|
||||
~ < ValueSep SrcDelim T >
|
||||
~ < Seq~<LengthPrefix native.UInt64> T >
|
||||
~ [~<LengthPrefix native.UInt64> T ]
|
||||
|
||||
--> < Seq <Seq T> >
|
||||
--> [[T]]
|
||||
~ < ValueSep DstDelim T >
|
||||
~ < Seq~<LengthPrefix native.UInt64> T >
|
||||
```
|
||||
length_prefix_uint64_t_array_uint8_t_clear( dst );
|
||||
~ [~<LengthPrefix native.UInt64> T ]
|
||||
=```
|
||||
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;
|
||||
```
|
||||
|
||||
|
||||
morph_seqseq_as_valsep_to_lenpfx (T: Type, Delim: T, EscKey: T)
|
||||
< Seq <Seq T> >
|
||||
morph seqseq_as_valsep_to_lenpfx : ∀T ∀Delim:T ∀EscKey:T
|
||||
[[T]]
|
||||
~ < ValueSep T Delim >
|
||||
~ < Seq~<LengthPrefix native.UInt64> T >
|
||||
~ [~<LengthPrefix native.UInt64> T ]
|
||||
|
||||
--> < Seq~<LengthPrefix native.UInt64>
|
||||
<Seq~<LengthPrefix native.UInt64> T >
|
||||
~ <RefMut < Seq~<LengthPrefix native.UInt64> T>>
|
||||
--> [~<LengthPrefix native.UInt64>
|
||||
[~<LengthPrefix native.UInt64> T ]
|
||||
~ <RefMut [~<LengthPrefix native.UInt64> T ] >
|
||||
~ native.Address
|
||||
~ 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)
|
||||
< Seq~<LengthPrefix native.UInt64>
|
||||
<Seq~<LengthPrefix native.UInt64> T >
|
||||
~ <RefMut < Seq~<LengthPrefix native.UInt64> T>>
|
||||
morph seqeq_as_lenpfx_to_valsep : ∀T ∀Delim:T ∀EscKey:T
|
||||
[~<LengthPrefix native.UInt64>
|
||||
[~<LengthPrefix native.UInt64> T ]
|
||||
~ <RefMut [~<LengthPrefix native.UInt64> T ]>
|
||||
~ native.Address
|
||||
~ native.UInt64
|
||||
>
|
||||
--> < Seq <Seq T> >
|
||||
]
|
||||
--> [[T]]
|
||||
~ < ValueSep T Delim >
|
||||
~ < Seq~<LengthPrefix native.UInt64> T >
|
||||
```
|
||||
length_prefix_uint64_t_array_uint8_t_clear( dst );
|
||||
~ [~<LengthPrefix native.UInt64> T ]
|
||||
= ```
|
||||
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;
|
||||
```
|
||||
```;
|
||||
|
|
39
morphisms/wheatstone.morphism-base
Normal file
39
morphisms/wheatstone.morphism-base
Normal file
|
@ -0,0 +1,39 @@
|
|||
```
|
||||
```
|
||||
|
||||
morph wheatstone_reading_to_ohms :
|
||||
∀Vcc: Potential ~ Volts ~ ℝ
|
||||
∀R1: Resistance ~ Ohms ~ ℝ
|
||||
∀R2: Resistance ~ Ohms ~ ℝ
|
||||
∀R3: Resistance ~ Ohms ~ ℝ
|
||||
Resistance ~ <WheatstoneBridge Vcc R1 R2 R3> ~ Potential ~ Volts ~ ℝ ~ native.Float64
|
||||
--> Resistance ~ Ohms ~ ℝ ~ native.Float64
|
||||
= ```
|
||||
// Voltage at midpoints of two voltage dividers:
|
||||
// o Vcc
|
||||
// _/ \_
|
||||
// R1 | | | | R3
|
||||
// |_| |_|
|
||||
// / \
|
||||
// v1 o––(*src)––o v2
|
||||
// \_ _/
|
||||
// R2 | | | | Rx = (*dst)
|
||||
// |_| |_|
|
||||
// \ /
|
||||
// o GND
|
||||
constexpr double v1 = Vcc * ((double)R2 / ((double)R1 + (double)R2));
|
||||
double v2 = v1 + *src;
|
||||
|
||||
printf("v1 = %f\n", v1);
|
||||
printf("v2 = %f\n", v2);
|
||||
|
||||
if( v2 < (double)Vcc ) {
|
||||
// voltage divider equation:
|
||||
// v2/Vcc = Rx/(Rx + R3)
|
||||
// Rx = (v2*R3) / (Vcc-v2)
|
||||
*dst = (v2 * (double)R3) / (Vcc - v2);
|
||||
printf("R = %f Ω \n", *dst);
|
||||
} else {
|
||||
fprintf(stderr, "Error");
|
||||
}
|
||||
```;
|
|
@ -1,26 +1,24 @@
|
|||
```
|
||||
```
|
||||
|
||||
morph_i64_as_twos_complement_to_zigzag ()
|
||||
morph i64_as_twos_complement_to_zigzag :
|
||||
ℤ ~ native.Int64
|
||||
--> ℤ ~ ZigZagInt ~ ℕ ~ native.UInt64
|
||||
```
|
||||
= ```
|
||||
if( *src >= 0 ) {
|
||||
*dst = (2 * (uint64_t)*src)
|
||||
} else {
|
||||
*dst = (2 * (uint64_t)(- *src)) - 1;
|
||||
}
|
||||
```;
|
||||
|
||||
return 0;
|
||||
```
|
||||
|
||||
morph_i64_as_zigzag_to_twos_complement ()
|
||||
morph i64_as_zigzag_to_twos_complement :
|
||||
ℤ ~ ZigZagInt ~ ℕ ~ native.UInt64
|
||||
--> ℤ ~ native.Int64
|
||||
```
|
||||
= ```
|
||||
if( *src % 2 == 0 ) {
|
||||
*dst = *src / 2;
|
||||
} else {
|
||||
*dst = - ((*src+1) / 2);
|
||||
}
|
||||
```
|
||||
```;
|
||||
|
|
100
platforms/json.lt
Normal file
100
platforms/json.lt
Normal file
|
@ -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
|
||||
);
|
||||
}
|
||||
```
|
0
platforms/json5.lt
Normal file
0
platforms/json5.lt
Normal file
3
platforms/protobuf.lt
Normal file
3
platforms/protobuf.lt
Normal file
|
@ -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> ;
|
0
platforms/spapod.lt
Normal file
0
platforms/spapod.lt
Normal file
5
platforms/x86.lt
Normal file
5
platforms/x86.lt
Normal file
|
@ -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>;
|
419
src/c_gen.rs
419
src/c_gen.rs
|
@ -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, σ),
|
||||
'}');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
85
src/c_gen/gen_lib.rs
Normal file
85
src/c_gen/gen_lib.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
use {
|
||||
super::types::get_c_repr_arg_type, crate::{c_gen::LdmcCTargetMorph, LdmcPrimMorph},
|
||||
laddertypes::{morphism::MorphismInstance, parser::*, Context, ContextPtr, LayeredContext, MorphismType, TypeDict},
|
||||
std::{collections::HashMap, sync::{Arc, RwLock}}
|
||||
};
|
||||
|
||||
pub fn generate_lib(
|
||||
ctx: &ContextPtr,
|
||||
include_blocks: Vec< String >,
|
||||
include_dependencies: HashMap< MorphismType, usize >,
|
||||
morphisms: Vec< (String, MorphismInstance<LdmcPrimMorph>) >
|
||||
) -> Result<String, ()> {
|
||||
let mut root_ctx = ctx.scope(laddertypes::AddressingMode::StackUp);
|
||||
let mut target = LdmcCTargetMorph::new( root_ctx.clone(), include_blocks, include_dependencies );
|
||||
let mut wrappers = String::new();
|
||||
|
||||
for (name, morph) in morphisms {
|
||||
match target.add_instantiation(HashMap::new(), morph) {
|
||||
Ok((σs, 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.apply_subst(&σs).src_type,
|
||||
&root_ctx.parse("[~<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(&root_ctx, &σs)
|
||||
));
|
||||
|
||||
if let Ok(ψ) = laddertypes::subtype_unify(
|
||||
&inst.ty.dst_type,
|
||||
&root_ctx.parse("[~<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(inst.ty.src_type.clone());
|
||||
target.add_type(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(root_ctx.clone(), &inst.ty.src_type),
|
||||
get_c_repr_arg_type(root_ctx.clone(), &inst.ty.dst_type),
|
||||
inst.instantiated_symbol_name(&root_ctx, &σs)
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(_err) => {
|
||||
eprintln!("failed to create morphism instatiation");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut c_source = target.into_c_source();
|
||||
c_source.push_str(&wrappers);
|
||||
|
||||
Ok(c_source)
|
||||
}
|
7
src/c_gen/mod.rs
Normal file
7
src/c_gen/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
pub mod types;
|
||||
pub mod morph;
|
||||
pub mod gen_lib;
|
||||
|
||||
pub use {
|
||||
morph::target_morph::LdmcCTargetMorph
|
||||
};
|
61
src/c_gen/morph/mod.rs
Normal file
61
src/c_gen/morph/mod.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
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::{unparser::UnparseLadderType, ContextPtr, HashMapSubst, Morphism, Substitution, TypeDict},
|
||||
};
|
||||
|
||||
impl LdmcPrimMorph {
|
||||
pub fn instantiated_symbol_name(&self, ctx: &ContextPtr, σs: &HashMapSubst) -> String {
|
||||
let mut s = self.symbol.clone();
|
||||
for (i,entry) in self.get_type().Γ.iter().enumerate() {
|
||||
if let Some(mut t) = σs.get(&(i as u64)).cloned() {
|
||||
t.apply_subst(ctx);
|
||||
let val_str = get_c_repr_type(ctx, &t);
|
||||
s.push_str(&format!("_{}_{}", entry.symbol, val_str));
|
||||
}
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
pub fn expected_c_type_signature(&self, ctx: &ContextPtr, σs: &HashMapSubst) -> String {
|
||||
let ty = self.get_type().apply_subst(σs).apply_subst(ctx);
|
||||
format!("int {} ({} const * restrict src, {} * restrict dst);",
|
||||
self.instantiated_symbol_name(ctx, σs),
|
||||
get_c_repr_definition(ctx.clone(), ty.src_type, true).expect("cant get c-repr type for src type"),
|
||||
get_c_repr_definition(ctx.clone(), ty.dst_type, true).expect("cant get c-repr type for dst type"))
|
||||
}
|
||||
|
||||
pub fn generate_instantiation(&mut self, ctx: &ContextPtr, σs: &HashMapSubst) -> Option<String> {
|
||||
let mut s = String::new();
|
||||
let symbol = self.instantiated_symbol_name(ctx, σs);
|
||||
|
||||
eprintln!("generate instantiation:");
|
||||
let ty = self.ty.clone().apply_subst(ctx);
|
||||
eprintln!("full type: {} ----> {}", ty.src_type.pretty(&mut ctx.clone(), 0), ty.dst_type.pretty(&mut ctx.clone(),0));
|
||||
//let ty = ty.strip_common_rungs();
|
||||
//eprintln!("stripped type: {} ----> {}", ty.src_type.pretty(&mut Γ.clone(), 0), ty.dst_type.pretty(&mut Γ.clone(),0));
|
||||
|
||||
let src_c_symbol = get_c_repr_arg_type(ctx.clone(), &ty.src_type);
|
||||
let dst_c_symbol = get_c_repr_arg_type(ctx.clone(), &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)
|
||||
}
|
||||
}
|
419
src/c_gen/morph/target_morph.rs
Normal file
419
src/c_gen/morph/target_morph.rs
Normal file
|
@ -0,0 +1,419 @@
|
|||
use {
|
||||
crate::{
|
||||
c_gen::types::{
|
||||
encode_morph_type_to_symbol, encode_type_to_value, get_c_repr_definition, get_c_repr_type
|
||||
},
|
||||
morphism::LdmcPrimMorph
|
||||
},
|
||||
laddertypes::{
|
||||
parser::*, ContextEntry, ContextPtr, HashMapSubst, LayeredContext, Morphism, MorphismInstance, MorphismType, SubstitutionMut, TypeDict, TypeKind, TypeTerm
|
||||
}, std::{collections::HashMap, ops::Deref}
|
||||
};
|
||||
|
||||
pub struct LdmcCTargetMorph {
|
||||
ctx: ContextPtr,
|
||||
header_blocks: Vec< String >,
|
||||
header_dependencies: HashMap< MorphismType, usize >,
|
||||
active_headers: Vec< usize >,
|
||||
active_types: Vec< TypeTerm >,
|
||||
active_morphisms: Vec< (HashMapSubst, 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) {
|
||||
if ! self.header_blocks.contains(&block) {
|
||||
let i = self.header_blocks.len();
|
||||
self.active_headers.push(i);
|
||||
self.header_blocks.push(block);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
Γ: ContextPtr,
|
||||
include_blocks: Vec< String >,
|
||||
include_dependencies: HashMap< MorphismType, usize >
|
||||
) -> Self {
|
||||
let mut m = LdmcCTargetMorph {
|
||||
ctx: Γ,
|
||||
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, ty: TypeTerm) {
|
||||
let ty = ty.strip();
|
||||
if ! self.active_types.contains(&ty) {
|
||||
eprintln!("add type {}", ty.pretty(&mut self.ctx,0));
|
||||
self.active_types.push(ty.clone());
|
||||
|
||||
let (ht,ft) = ty.get_floor_type();
|
||||
if ht.is_empty() {
|
||||
|
||||
match &ft {
|
||||
TypeTerm::Seq { seq_repr, item } => {
|
||||
let item_type = item.deref().clone();
|
||||
self.add_type(item_type.clone());
|
||||
|
||||
if let Some(seq_repr) = seq_repr {
|
||||
let mut ctx = self.ctx.scope(laddertypes::AddressingMode::StackUp);
|
||||
ctx.add_variable("LengthType", TypeKind::Type);
|
||||
if let Ok(σ) =
|
||||
laddertypes::constraint_system::unify(
|
||||
seq_repr.as_ref(),
|
||||
&ctx.parse("<LengthPrefix LengthType>").expect("")
|
||||
)
|
||||
{
|
||||
let length_type = σ.get(&ctx.get_varid("LengthType").expect("")).expect("cant get Length type");
|
||||
self.add_type(length_type.clone());
|
||||
self.macro_calls.push(
|
||||
format!("DEFINE_LENGTH_PREFIX_ARRAY({}, {})\n",
|
||||
get_c_repr_type(&ctx, &length_type),
|
||||
get_c_repr_type(&ctx, &item_type)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let Some(type_def) = get_c_repr_definition(self.ctx.clone(), ft, false) {
|
||||
let type_name = get_c_repr_type(&self.ctx, &ty);
|
||||
self.typedefs.push(format!("typedef {} {};\n", type_def, type_name));
|
||||
} else {
|
||||
eprintln!("cant get c-repr type for type '{}'", ty.pretty(&mut self.ctx,0));
|
||||
}
|
||||
} else {
|
||||
let type_name = get_c_repr_type(&self.ctx, &ty);
|
||||
let type_def = get_c_repr_type(&self.ctx, &ft);
|
||||
self.add_type(ft);
|
||||
self.typedefs.push(format!("typedef {} {};\n", type_def, type_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_instantiation(
|
||||
&mut self,
|
||||
σ: HashMapSubst,
|
||||
morph: MorphismInstance<LdmcPrimMorph>,
|
||||
) -> Result<(HashMapSubst, LdmcPrimMorph), ()> {
|
||||
let (σs, new_inst) = self.bake_morphism(TypeTerm::unit(), σ, morph)?;
|
||||
eprintln!("add inst: σs.len() = {}", σs.len());
|
||||
if ! self.active_morphisms.contains(&(σs.clone(), new_inst.clone())) {
|
||||
self.active_morphisms.push((σs.clone(), new_inst.clone()));
|
||||
}
|
||||
|
||||
let ty = new_inst.get_type();//.apply_subst(&new_inst.Γ);
|
||||
self.add_type(ty.src_type);
|
||||
self.add_type(ty.dst_type);
|
||||
|
||||
Ok((σs, new_inst))
|
||||
}
|
||||
|
||||
pub fn into_c_source(mut self) -> String {
|
||||
let mut source = String::new();
|
||||
self.active_headers.sort();
|
||||
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 (σs, mut m) in self.active_morphisms {
|
||||
source.push_str(&m.generate_instantiation(&self.ctx, &σs).expect("cant create function"));
|
||||
}
|
||||
source
|
||||
}
|
||||
|
||||
pub fn bake_morphism(
|
||||
&mut self,
|
||||
mut ψ: TypeTerm,
|
||||
mut σ0: HashMapSubst,
|
||||
morph_inst: MorphismInstance<LdmcPrimMorph>,
|
||||
) -> Result<(HashMapSubst, LdmcPrimMorph), ()> {
|
||||
|
||||
let ty = morph_inst.get_type();
|
||||
let symbol = encode_morph_type_to_symbol(&self.ctx, &ty.clone().apply_subst(&σ0));
|
||||
|
||||
eprintln!("BAKE {}", symbol);
|
||||
|
||||
match &morph_inst {
|
||||
MorphismInstance::Id { τ } => {
|
||||
self.add_required_header_block("#include <string.h>".into());
|
||||
Ok((HashMap::new(), LdmcPrimMorph {
|
||||
symbol,
|
||||
ty: MorphismType {
|
||||
Γ: Vec::new(),
|
||||
bounds: Vec::new(),
|
||||
src_type: τ.clone(),
|
||||
dst_type: τ.clone()
|
||||
},
|
||||
c_source: String::from("memcpy(dst, src, sizeof(*src));")
|
||||
}))
|
||||
}
|
||||
MorphismInstance::Sub { ψ:ψ1, m } => {
|
||||
ψ = TypeTerm::Ladder(vec![ ψ1.clone(), ψ.clone() ]).normalize();
|
||||
self.bake_morphism(ψ, σ0, m.deref().clone())
|
||||
}
|
||||
MorphismInstance::Specialize { σ, m } => {
|
||||
σ0.append(&σ);
|
||||
self.bake_morphism(ψ, σ0.clone(), m.deref().clone())
|
||||
}
|
||||
MorphismInstance::Primitive { σs, m: morph } => {
|
||||
|
||||
if let Some(i) = self.header_dependencies.get(&morph.get_type()) {
|
||||
self.active_headers.push(*i);
|
||||
}
|
||||
|
||||
let mut c_source = String::new();
|
||||
|
||||
for (i,entry) in morph.get_type().Γ.iter().enumerate() {
|
||||
if let Some(mut val) = σs.get(&(i as u64)).cloned() {
|
||||
val.apply_subst(&σ0);
|
||||
let type_var_value =
|
||||
match &entry.kind {
|
||||
TypeKind::Type => { get_c_repr_type(&self.ctx, &val) },
|
||||
TypeKind::Value(t) => { encode_type_to_value(&self.ctx, &val) },
|
||||
_ => "/* ERROR */".into()
|
||||
};
|
||||
c_source.push_str(&format!(" #define {} {}\n", entry.symbol, type_var_value));
|
||||
} else {
|
||||
// todo: add variable to new_ctx
|
||||
c_source.push_str(&format!("// Error: cannot '#define': missing variable name for Var({})", i));
|
||||
}
|
||||
}
|
||||
c_source.push_str(&morph.c_source);
|
||||
for entry in morph.get_type().Γ.iter() {
|
||||
c_source.push_str(&format!("\n #undef {}", entry.symbol));
|
||||
}
|
||||
|
||||
let mut ty = morph_inst.get_type().apply_subst(&σ0);
|
||||
ty.Γ = ty.Γ.iter().enumerate().filter_map(|(i,entry)| {
|
||||
if ty.src_type.contains_var(i as u64)
|
||||
|| ty.dst_type.contains_var(i as u64)
|
||||
{
|
||||
Some(entry.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect();
|
||||
|
||||
Ok((σs.clone(), LdmcPrimMorph{
|
||||
symbol: morph.instantiated_symbol_name(&self.ctx, σs),
|
||||
ty,
|
||||
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((σs, inst)) = self.add_instantiation(σ0.clone(), morph.clone()) {
|
||||
//let ty = inst.get_type().apply_subst(&inst.Γ).apply_subst(Γ0);
|
||||
let morph_symbol = inst.instantiated_symbol_name(&self.ctx, &σs);
|
||||
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((HashMap::new(), LdmcPrimMorph {
|
||||
symbol,
|
||||
ty: ty.apply_subst(&σ0),
|
||||
c_source
|
||||
}))
|
||||
}
|
||||
MorphismInstance::MapSeq { seq_repr, item_morph } => {
|
||||
if let Ok((σs, item_morph_inst)) = self.add_instantiation(σ0, item_morph.as_ref().clone()) {
|
||||
let item_type = item_morph_inst.ty.src_type.clone();
|
||||
|
||||
if let Some(seq_repr) = seq_repr {
|
||||
let mut ctx = self.ctx.scope(laddertypes::AddressingMode::StackUp);
|
||||
ctx.add_variable("Length", TypeKind::Value(self.ctx.clone().parse("ℕ").expect("")));
|
||||
ctx.add_variable("LengthType", TypeKind::Type);
|
||||
ctx.add_variable("TerminatorValue", TypeKind::Value(item_type));
|
||||
|
||||
if let Ok(γ) = laddertypes::constraint_system::unify(
|
||||
&ctx.parse("<StaticLength Length>").expect("parse type template"),
|
||||
seq_repr.as_ref()
|
||||
) {
|
||||
let length = γ.get(&ctx.get_varid("Length").expect("")).expect("cant get Length");
|
||||
match length {
|
||||
TypeTerm::Num(l) => {
|
||||
let item_morph_symbol = item_morph_inst.instantiated_symbol_name(&self.ctx, &σs);
|
||||
|
||||
let mty = morph_inst.get_type().strip_common_rungs().apply_subst(&σs);
|
||||
self.add_type( mty.src_type );
|
||||
self.add_type( mty.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((σs, LdmcPrimMorph{
|
||||
symbol, ty,
|
||||
c_source
|
||||
}))
|
||||
}
|
||||
_ => {
|
||||
eprintln!("invalid length '{}'", length.pretty(&mut ctx, 0));
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if let Ok(γ) = laddertypes::constraint_system::unify(
|
||||
&ctx.parse("<LengthPrefix LengthType>").expect("parse type template"),
|
||||
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(&self.ctx, &σs);
|
||||
|
||||
self.add_type( morph_inst.get_type().strip_common_rungs().src_type );
|
||||
self.add_type( morph_inst.get_type().strip_common_rungs().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((σs, LdmcPrimMorph{
|
||||
symbol, ty,
|
||||
c_source
|
||||
}))
|
||||
}
|
||||
|
||||
else if let Ok(γ) = laddertypes::constraint_system::unify(
|
||||
&ctx.parse("<ValueTerminated TerminatorValue>").expect("parse type template"),
|
||||
seq_repr.as_ref()
|
||||
) {
|
||||
let terminator_value = γ.get(&ctx.get_varid("TerminatorValue").expect("")).expect("cant get TerminatorValue");
|
||||
let item_morph_symbol = item_morph_inst.instantiated_symbol_name(&self.ctx, &σs);
|
||||
let terminator = encode_type_to_value(&self.ctx, terminator_value);
|
||||
|
||||
let c_source = format!(r#"
|
||||
while( *src != {} ) {{
|
||||
FUSE( {}, src, dst );
|
||||
++src;
|
||||
++dst;
|
||||
}}
|
||||
*dst = {};"#,
|
||||
terminator,
|
||||
item_morph_symbol,
|
||||
terminator
|
||||
);
|
||||
|
||||
Ok((σs.clone(), LdmcPrimMorph{
|
||||
symbol, 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 { struct_repr, member_morph } => {
|
||||
|
||||
let mut c_source = String::new();
|
||||
|
||||
let mut σs0 = HashMap::new();
|
||||
|
||||
for (name, morph) in member_morph.iter() {
|
||||
if let Ok((σs, inst)) = self.add_instantiation(σ0.clone(), morph.clone()) {
|
||||
σs0.append(&σs);
|
||||
let name = name.replace("-", "_").replace(".","_dot_");
|
||||
c_source.push_str(
|
||||
&format!("
|
||||
FUSE( {}, (void*)&src->{}, (void*)&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((σs0, LdmcPrimMorph{
|
||||
symbol,
|
||||
ty,
|
||||
c_source
|
||||
}))
|
||||
}
|
||||
MorphismInstance::MapEnum { enum_repr, variant_morph } => {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
326
src/c_gen/types/mod.rs
Normal file
326
src/c_gen/types/mod.rs
Normal file
|
@ -0,0 +1,326 @@
|
|||
use {
|
||||
crate::struct_layout::LayoutType,
|
||||
laddertypes::{
|
||||
morphism::MorphismType, parser::*, unparser::*, ContextPtr, EnumVariant, LayeredContext, StructMember, TypeDict, TypeID, TypeKind, TypeTerm
|
||||
},
|
||||
std::{ops::Deref}
|
||||
};
|
||||
|
||||
|
||||
/* for a given ladder type `t`, get the corresponding C type
|
||||
*/
|
||||
pub fn get_c_repr_definition(mut root_ctx: ContextPtr, t: TypeTerm, skip_pointer: bool) -> Option<String> {
|
||||
match t {
|
||||
TypeTerm::Id(tyid) => {
|
||||
if TypeID::Fun(tyid) == root_ctx.get_typeid_creat("native.UInt8") {
|
||||
Some("uint8_t".into())
|
||||
} else if TypeID::Fun(tyid) == root_ctx.get_typeid_creat("native.UInt16") {
|
||||
Some("uint16_t".into())
|
||||
} else if TypeID::Fun(tyid) == root_ctx.get_typeid_creat("native.UInt32") {
|
||||
Some("uint32_t".into())
|
||||
} else if TypeID::Fun(tyid) == root_ctx.get_typeid_creat("native.UInt64") {
|
||||
Some("uint64_t".into())
|
||||
} else if TypeID::Fun(tyid) == root_ctx.get_typeid_creat("native.Int8") {
|
||||
Some("int8_t".into())
|
||||
} else if TypeID::Fun(tyid) == root_ctx.get_typeid_creat("native.Int16") {
|
||||
Some("int16_t".into())
|
||||
} else if TypeID::Fun(tyid) == root_ctx.get_typeid_creat("native.Int32") {
|
||||
Some("int32_t".into())
|
||||
} else if TypeID::Fun(tyid) == root_ctx.get_typeid_creat("native.Int64") {
|
||||
Some("int64_t".into())
|
||||
} else if TypeID::Fun(tyid) == root_ctx.get_typeid_creat("native.Address") {
|
||||
Some("void*".into())
|
||||
} else if TypeID::Fun(tyid) == root_ctx.get_typeid_creat("native.Float32") {
|
||||
Some("float".into())
|
||||
} else if TypeID::Fun(tyid) == root_ctx.get_typeid_creat("native.Float64") {
|
||||
Some("double".into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
TypeTerm::Seq{ seq_repr, item } => {
|
||||
if let Some(seq_repr) = seq_repr {
|
||||
let item_type = item.deref().clone();
|
||||
let item_c_type : String = get_c_repr_type(&mut root_ctx, &item_type);
|
||||
|
||||
let mut ctx = root_ctx.scope(laddertypes::AddressingMode::StackUp);
|
||||
|
||||
ctx.add_variable("Length", TypeKind::Value(root_ctx.parse("ℕ").expect("")));
|
||||
ctx.add_variable("LengthType", TypeKind::Type);
|
||||
ctx.add_variable("TermValue", TypeKind::Value(item_type.clone()));
|
||||
|
||||
if let Ok((ψ, σ)) = laddertypes::constraint_system::subtype_unify(
|
||||
seq_repr.as_ref(),
|
||||
&ctx.parse("<StaticLength Length>").expect("parse template type")
|
||||
) {
|
||||
let length = match
|
||||
σ.get(
|
||||
&ctx.get_varid("Length").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(),
|
||||
&ctx.parse("<LengthPrefix LengthType>").expect("parse template type")
|
||||
) {
|
||||
let length_type = σ.get(
|
||||
&ctx.get_varid("LengthType").expect("no LengthType ID")
|
||||
).expect("no length type specified");
|
||||
|
||||
let length_c_type = get_c_repr_type(&ctx, &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(),
|
||||
&ctx.parse("<ValueTerminated TermValue>").expect("parse template type")
|
||||
) {
|
||||
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(),
|
||||
&ctx.parse("MsbCont").expect("parse template type")
|
||||
) {
|
||||
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(&mut ctx.clone(), 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 {
|
||||
if sr.deref() == &TypeTerm::Id(0x59742) {
|
||||
// native repr., no attributes
|
||||
""
|
||||
} else {
|
||||
match LayoutType::parse(&mut root_ctx, &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(root_ctx.clone(), 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(root_ctx.clone(), 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(root_ctx, t.clone(), false)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
_ => { None }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_c_repr_type(Γ: &ContextPtr, t: &laddertypes::TypeTerm)-> String {
|
||||
let t = t.clone().strip();
|
||||
|
||||
match t {
|
||||
TypeTerm::Char(c) => {
|
||||
match c {
|
||||
'.' => format!("_dot_"),
|
||||
'-' => format!("_minus_"),
|
||||
_ =>
|
||||
format!("{}", (c as u64))
|
||||
}
|
||||
},
|
||||
TypeTerm::Num(n) => {
|
||||
format!("{}", n)
|
||||
}
|
||||
TypeTerm::Id(ty_id) => {
|
||||
if let Some(name) = Γ.get_typename(ty_id) {
|
||||
name
|
||||
.replace("-", "_")
|
||||
.replace(".", "")
|
||||
} else {
|
||||
format!("")
|
||||
}
|
||||
}
|
||||
TypeTerm::Ladder(rs) |
|
||||
TypeTerm::Spec(rs) => {
|
||||
let mut s = String::new();
|
||||
s.push('_');
|
||||
for r in rs {
|
||||
s.push_str(&get_c_repr_type(Γ, &r));
|
||||
s.push('_');
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
TypeTerm::Struct { struct_repr, members } => {
|
||||
let mut s = String::new();
|
||||
s.push_str("_Struct_");
|
||||
if let Some(sr) = struct_repr.as_ref() {
|
||||
s.push('_');
|
||||
s.push_str(&get_c_repr_type(Γ, &sr));
|
||||
s.push('_');
|
||||
}
|
||||
for member in members.iter() {
|
||||
s.push('_');
|
||||
s.push_str(&member.symbol);
|
||||
s.push('_');
|
||||
s.push_str(&get_c_repr_type(Γ, &member.ty));
|
||||
s.push('_');
|
||||
}
|
||||
s
|
||||
},
|
||||
TypeTerm::Enum { enum_repr, variants } => {
|
||||
let mut s = String::new();
|
||||
s.push_str("_Enum_");
|
||||
if let Some(sr) = enum_repr.as_ref() {
|
||||
s.push('_');
|
||||
s.push_str(&get_c_repr_type(Γ, &sr));
|
||||
s.push('_');
|
||||
}
|
||||
for member in variants.iter() {
|
||||
s.push('_');
|
||||
s.push_str(&member.symbol);
|
||||
s.push('_');
|
||||
s.push_str(&get_c_repr_type(Γ, &member.ty));
|
||||
s.push('_');
|
||||
}
|
||||
s
|
||||
},
|
||||
TypeTerm::Seq { seq_repr, item } => {
|
||||
let mut s = String::new();
|
||||
s.push_str("_Seq_");
|
||||
if let Some(sr) = seq_repr.as_ref() {
|
||||
s.push('_');
|
||||
s.push_str(&get_c_repr_type(Γ, &sr));
|
||||
s.push('_');
|
||||
}
|
||||
|
||||
s.push('_');
|
||||
s.push_str(&get_c_repr_type(Γ, &item.deref()));
|
||||
s.push('_');
|
||||
s
|
||||
},
|
||||
|
||||
// ??
|
||||
TypeTerm::Func(type_terms) => todo!(),
|
||||
TypeTerm::Morph(type_term, type_term1) => todo!(),
|
||||
|
||||
// err
|
||||
TypeTerm::Var(_) => {
|
||||
"_VAR_".into()
|
||||
},
|
||||
TypeTerm::Univ{ Γ, bounds, τ } => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_c_repr_arg_type(mut ctx: ContextPtr, t: &laddertypes::TypeTerm)-> String {
|
||||
let t = t.clone().strip().get_floor_type().1;
|
||||
|
||||
let mut ctx = ctx.scope(laddertypes::AddressingMode::StackUp);
|
||||
ctx.add_variable("TerminatorValue", TypeKind::Value(TypeTerm::unit()));
|
||||
match &t {
|
||||
TypeTerm::Seq { seq_repr, item } => {
|
||||
if let Some(seq_repr) = seq_repr.as_ref() {
|
||||
if let Ok(ψ) = laddertypes::constraint_system::subtype_unify(
|
||||
seq_repr,
|
||||
&ctx.parse("<ValueTerminated TerminatorValue>").expect("")
|
||||
) {
|
||||
return get_c_repr_type(&ctx, &item.clone().strip().get_floor_type().1);
|
||||
}
|
||||
else if let Ok(ψ) = laddertypes::constraint_system::subtype_unify(
|
||||
seq_repr,
|
||||
&ctx.parse("MsbCont").expect("")
|
||||
) {
|
||||
return get_c_repr_type(&ctx, &item.clone().strip().get_floor_type().1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
get_c_repr_type(&ctx, &t)
|
||||
}
|
||||
|
||||
pub fn encode_morph_type_to_symbol(ctx: &ContextPtr, t: &MorphismType) -> String {
|
||||
eprintln!("encode morph_type_to symbol:");
|
||||
eprintln!("t = {} -> {}", t.src_type.pretty(&mut ctx.clone(), 0), t.dst_type.pretty(&mut ctx.clone(), 0));
|
||||
eprintln!("Γ = {}", ctx.pretty());
|
||||
//let t = t.apply_subst(&c);
|
||||
format!(
|
||||
"morph__{}___TO__{}",
|
||||
get_c_repr_type(&ctx, &t.src_type),
|
||||
get_c_repr_type(&ctx, &t.dst_type)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn encode_type_to_value(ctx: &ContextPtr, t: &laddertypes::TypeTerm) -> String {
|
||||
ctx.unparse(&t)
|
||||
}
|
174
src/main.rs
174
src/main.rs
|
@ -3,50 +3,113 @@
|
|||
mod morphism;
|
||||
mod parser;
|
||||
mod c_gen;
|
||||
mod struct_layout;
|
||||
mod viz;
|
||||
|
||||
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,
|
||||
}
|
||||
viz::{MorphbaseVisualizationPane, Visualization},
|
||||
},
|
||||
ariadne::{Color, Label, Report, ReportKind, Source}, clap::Parser, laddertypes::{
|
||||
morphism::*, BimapTypeDict, Context, Morphism
|
||||
},
|
||||
parser::morphism_type_parser, std::{io::Write, path::PathBuf, str::FromStr, 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>,
|
||||
|
||||
#[arg(long)]
|
||||
html: Option<PathBuf>
|
||||
}
|
||||
|
||||
fn main() {
|
||||
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 args = Args::parse();
|
||||
let mut ctx = Context::new();
|
||||
let mut morphism_base = laddertypes::morphism::base::MorphismBase::<LdmcPrimMorph>::new(ctx.clone());
|
||||
|
||||
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");
|
||||
let result = morphism_base_parser(type_dict.clone()).parse(src.clone());
|
||||
// 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();
|
||||
|
||||
let mut viz = viz::Visualization::new();
|
||||
let mut morphbase_pane = MorphbaseVisualizationPane::new(mb_paths.len());
|
||||
|
||||
for mb_path in mb_paths {
|
||||
let modname = mb_path.file_stem().unwrap().to_str().unwrap().to_string();
|
||||
viz.add_module(modname.clone());
|
||||
morphbase_pane.add_module(modname.clone());
|
||||
|
||||
let src = std::fs::read_to_string(mb_path.clone()).expect("failed to read morphism base");
|
||||
|
||||
use chumsky::Parser;
|
||||
let result = morphism_base_parser(ctx.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 );
|
||||
morphbase_pane.add_morphism( &modname, &m );
|
||||
|
||||
morphism_base.add_morphism(m);
|
||||
}
|
||||
}
|
||||
Err(errs) => {
|
||||
eprintln!("Error in {}:", mb_path.to_str().unwrap().bright_yellow());
|
||||
errs.into_iter().for_each(|e| {
|
||||
Report::build(ReportKind::Error, (), e.span().start)
|
||||
.with_message(e.to_string())
|
||||
.with_message(format!("in {} : {}", mb_path.display(), e.to_string()))
|
||||
.with_label(
|
||||
Label::new(e.span())
|
||||
.with_message(e)
|
||||
|
@ -60,22 +123,53 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
eprintln!("done loading");
|
||||
morphbase_pane.build_svg(&mut ctx);
|
||||
viz.add_pane( morphbase_pane );
|
||||
|
||||
let src_type = type_dict.parse( src_type_arg.as_str() ).expect("");
|
||||
let dst_type = type_dict.parse( dst_type_arg.as_str() ).expect("");
|
||||
// 2. Generate Morphisms
|
||||
let mut instances = Vec::new();
|
||||
let mut morph_graph = MorphismGraph::new(morphism_base);
|
||||
for morph_decl in args.morphisms.iter() {
|
||||
use chumsky::Parser;
|
||||
if let Ok((name, src_type, dst_type)) = morphism_type_parser(ctx.clone()).parse(morph_decl.as_str()) {
|
||||
let ty = MorphismType{ Γ: Vec::new(), bounds: vec![], src_type, dst_type };
|
||||
let (morph_inst,search) = morph_graph.search( ty );
|
||||
|
||||
let path = morphism_base.find_morphism_path(MorphismType {
|
||||
src_type: src_type.clone(),
|
||||
dst_type: dst_type.clone(),
|
||||
});
|
||||
if let Ok(morph_inst) = morph_inst {
|
||||
eprintln!("===========");
|
||||
eprintln!("{}", morph_inst.pretty(&ctx));
|
||||
eprintln!("===========");
|
||||
|
||||
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);
|
||||
viz.add_module(name.clone());
|
||||
viz.add_morph_inst(name.clone(), morph_inst.clone(), ctx.clone());
|
||||
|
||||
instances.push( (name.clone(), morph_inst) );
|
||||
}
|
||||
|
||||
let search_name = format!("search-{}",name);
|
||||
viz.add_module(search_name.clone());
|
||||
viz.add_search_graph(ctx.clone(), search_name, &search);
|
||||
}
|
||||
}
|
||||
|
||||
if instances.len() > 0 {
|
||||
let c_source = crate::c_gen::gen_lib::generate_lib(&ctx, 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);
|
||||
}
|
||||
} else {
|
||||
eprintln!("No instances");
|
||||
}
|
||||
|
||||
if let Some(html_path) = args.html {
|
||||
let html_src = viz.into_html(&mut ctx, vec![
|
||||
PathBuf::from_str("file:///home/micha/projects/syntaxAlchemist/ldmc/example-layout.csv").unwrap()
|
||||
]);
|
||||
let mut output = std::fs::File::create(html_path).expect("couldnt open file");
|
||||
write!(output, "{}", html_src);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,76 +1,26 @@
|
|||
|
||||
use laddertypes::morphism::Morphism;
|
||||
use {
|
||||
laddertypes::{
|
||||
context::{ContextPtr},
|
||||
morphism::{Morphism, MorphismType},
|
||||
}
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LdmcPrimCMorphism {
|
||||
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 PartialEq for LdmcPrimMorph {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.symbol == other.symbol
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
148
src/parser.rs
148
src/parser.rs
|
@ -1,15 +1,15 @@
|
|||
use {
|
||||
chumsky::{
|
||||
prelude::*, text::*
|
||||
},
|
||||
std::sync::{Arc, RwLock},
|
||||
|
||||
laddertypes::{TypeDict, BimapTypeDict, parser::*},
|
||||
crate::morphism::LdmcPrimCMorphism
|
||||
crate::morphism::LdmcPrimMorph, chumsky::{
|
||||
error::SimpleReason, prelude::*, text::*
|
||||
}, laddertypes::{morphism::MorphismType, parser::*, BimapTypeDict, ContextPtr, LayeredContext, TypeKind, TypeTerm}, std::sync::{Arc, RwLock}
|
||||
};
|
||||
|
||||
// todo: lexer with ladder-type tokens,
|
||||
// todo: parse type definitions
|
||||
|
||||
/* morphism-base text format:
|
||||
* NAME '(' [TYPE-ARG-NAME ':' KIND] ')'
|
||||
* NAME '(' [TYPE-ARG-NAME ':' Kind] ')'
|
||||
* where
|
||||
* SRC-TYPE
|
||||
* '-->' DST-TYPE
|
||||
* ```
|
||||
|
@ -17,64 +17,116 @@ use {
|
|||
* ```
|
||||
*/
|
||||
pub fn morphism_base_parser(
|
||||
type_dict: Arc<RwLock< BimapTypeDict >>
|
||||
) -> impl Parser<char, (String, Vec<LdmcPrimCMorphism>), Error = Simple<char>> {
|
||||
root_ctx: ContextPtr
|
||||
) -> impl Parser<char, (String, Vec<LdmcPrimMorph>), Error = Simple<char>> {
|
||||
|
||||
/* header block */
|
||||
just("```")
|
||||
.then(take_until(just("```")))
|
||||
.map(
|
||||
move |(a, (b, c))| {
|
||||
move |(_a, (b, _c))| {
|
||||
b.iter().collect()
|
||||
}
|
||||
)
|
||||
|
||||
// morph name
|
||||
.then(
|
||||
ident().padded()
|
||||
|
||||
// type args
|
||||
.then(
|
||||
ident().padded()
|
||||
.then_ignore(just(":").padded())
|
||||
.then(none_of(",)").repeated().padded())
|
||||
.separated_by(just(",").padded())
|
||||
.delimited_by(just("("), just(")"))
|
||||
just("morph").padded()
|
||||
|
||||
// morph name
|
||||
.then(ident().padded()
|
||||
|
||||
// type
|
||||
.then(
|
||||
just(":").padded()
|
||||
.then(none_of("=").repeated().padded())
|
||||
)
|
||||
|
||||
.then_ignore(just('=').padded())
|
||||
.then_ignore(just("```"))
|
||||
// c sourcecode template
|
||||
.then(take_until(just("```")))
|
||||
.then_ignore(just(";").padded())
|
||||
)
|
||||
|
||||
// newline
|
||||
.then_ignore(just('\n'))
|
||||
|
||||
// src type
|
||||
.then(take_until(just("-->").ignored()))
|
||||
// dst_type
|
||||
.then(take_until(just("```")))
|
||||
|
||||
// c sourcecode template
|
||||
.then(take_until(just("```")))
|
||||
|
||||
.map(
|
||||
move |((((symbol, type_args), (src_type, _)), (dst_type, _)), (c_source, _))| {
|
||||
move |(morph_keyword, ((symbol, (_dot, morphtype)), (c_source, _)))| {
|
||||
let mut ctx = root_ctx.clone();
|
||||
let c_source = c_source.iter().collect();
|
||||
let mut type_dict = type_dict.write().unwrap();
|
||||
let type_args : Vec<_> = type_args.into_iter().map(|(v,k)| (v,k.into_iter().collect())).collect();
|
||||
let mut ty_args = Vec::new();
|
||||
for (var, kind) in type_args.into_iter() {
|
||||
let var_id = type_dict.add_varname(var.clone());
|
||||
ty_args.push((var_id, kind));
|
||||
}
|
||||
let morphtype : String = morphtype.iter().collect();
|
||||
|
||||
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");
|
||||
let ty = match ctx.parse(&morphtype) {
|
||||
Ok(ty) => ty,
|
||||
Err(err) => {
|
||||
eprintln!("failed to parse morph type of `{}`", symbol);
|
||||
TypeTerm::unit()
|
||||
//return Err(SimpleReason::Custom("cant parse morph type".into()));
|
||||
}
|
||||
};
|
||||
eprintln!("read {}", ty.pretty(&ctx, 0));
|
||||
let ty = ty.into_morphism_type().expect("invalid morphism type");
|
||||
|
||||
LdmcPrimCMorphism {
|
||||
LdmcPrimMorph {
|
||||
symbol,
|
||||
type_args: ty_args,
|
||||
src_type,
|
||||
dst_type,
|
||||
ty,
|
||||
c_source
|
||||
}
|
||||
})
|
||||
.separated_by(text::newline())
|
||||
}
|
||||
/*
|
||||
move |((((symbol, type_args), (src_type, _)), (dst_type, _)), (c_source, _))| {
|
||||
let c_source = c_source.iter().collect();
|
||||
let mut ctx = root_ctx.scope();
|
||||
let type_args : Vec<_> = type_args.into_iter().map(|(v,k)| (v,k.into_iter().collect::<String>())).collect();
|
||||
for (var, bound) in type_args.into_iter() {
|
||||
let var_id = ctx.add_variable(var.as_str(),
|
||||
if bound == "Type" {
|
||||
TypeKind::Type
|
||||
} else if bound == "ℕ" {
|
||||
TypeKind::ValueUInt
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let src_type = ctx.parse(&src_type.iter().collect::<String>()).expect("couldnt parse src type");
|
||||
let dst_type = ctx.parse(&dst_type.iter().collect::<String>()).expect("couldnt parse dst type");
|
||||
|
||||
LdmcPrimMorph {
|
||||
symbol,
|
||||
Γ: ctx,
|
||||
ty: MorphismType{
|
||||
bounds: Vec::new(),
|
||||
src_type,
|
||||
dst_type
|
||||
},
|
||||
c_source
|
||||
}
|
||||
*/
|
||||
)
|
||||
|
||||
.repeated()
|
||||
)
|
||||
//.separated_by(text::newline())
|
||||
}
|
||||
|
||||
pub fn morphism_type_parser(
|
||||
ctx: ContextPtr
|
||||
) -> 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 ctx = ctx.clone();
|
||||
move |((name, src_type), dst_type)| {
|
||||
(
|
||||
name.0,
|
||||
ctx.clone().parse(&src_type.0.iter().collect::<String>()).expect("parse type"),
|
||||
ctx.clone().parse(&dst_type.0.iter().collect::<String>()).expect("parse type")
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
43
src/platform/x86.rs
Normal file
43
src/platform/x86.rs
Normal file
|
@ -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()
|
||||
);
|
||||
}
|
245
src/struct_layout.rs
Normal file
245
src/struct_layout.rs
Normal file
|
@ -0,0 +1,245 @@
|
|||
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use laddertypes::{parser::*, ContextPtr, LayeredContext, StructMember, TypeDict, TypeID, TypeTerm};
|
||||
|
||||
#[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 ContextPtr, ty: TypeTerm ) -> ObjectSize {
|
||||
match &ty {
|
||||
TypeTerm::Id(tyid) => {
|
||||
if TypeID::Fun(*tyid) == dict.get_typeid_creat("native.UInt8") { ObjectSize::Static(1) }
|
||||
else if TypeID::Fun(*tyid) == dict.get_typeid_creat("native.UInt16") { ObjectSize::Static(2) }
|
||||
else if TypeID::Fun(*tyid) == dict.get_typeid_creat("native.UInt32") { ObjectSize::Static(4) }
|
||||
else if TypeID::Fun(*tyid) == dict.get_typeid_creat("native.UInt64") { ObjectSize::Static(8) }
|
||||
else if TypeID::Fun(*tyid) == dict.get_typeid_creat("native.Address") { ObjectSize::Static(8) }
|
||||
else if TypeID::Fun(*tyid) == dict.get_typeid_creat("native.Float32") { ObjectSize::Static(4) }
|
||||
else if TypeID::Fun(*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, item } => {
|
||||
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_varid("Length").expect("")) {
|
||||
ObjectSize::Static(*len as u64) * get_type_size(dict, item.deref().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 LayeredContext, ty: &TypeTerm ) -> Option< LayoutType > {
|
||||
if ty == &dict.parse("Aligned").expect("parse") {
|
||||
Some(LayoutType::Aligned)
|
||||
} else if ty == &dict.parse("Packed").expect("parse") {
|
||||
Some(LayoutType::Packed)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unparse(&self, dict: &mut impl LayeredContext) -> TypeTerm {
|
||||
match self {
|
||||
LayoutType::Aligned => dict.parse("Aligned").unwrap(),
|
||||
LayoutType::Packed => dict.parse("Packed").unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StructLayout {
|
||||
pub ty: laddertypes::TypeTerm,
|
||||
pub layout: LayoutType,
|
||||
pub members: Vec< StructMember >,
|
||||
offsets: std::collections::HashMap< String, u64 >,
|
||||
size: ObjectSize
|
||||
}
|
||||
|
||||
impl StructLayout {
|
||||
pub fn get_type(&self) -> TypeTerm {
|
||||
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 ContextPtr) {
|
||||
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 ContextPtr, struct_type: &TypeTerm) -> Option <Self> {
|
||||
let st = struct_type.clone().strip().normalize();
|
||||
Self::parse_sugared(dict, st)
|
||||
}
|
||||
|
||||
pub fn parse_sugared(dict: &mut ContextPtr, st: TypeTerm) -> Option <Self> {
|
||||
eprintln!("{}", st.pretty(dict, 0));
|
||||
match st.clone() {
|
||||
TypeTerm::Struct{ struct_repr, members } => {
|
||||
let mut sl = StructLayout {
|
||||
ty: st,
|
||||
layout: if let Some(sr) = struct_repr {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
502
src/viz/gen_html.rs
Normal file
502
src/viz/gen_html.rs
Normal file
|
@ -0,0 +1,502 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use laddertypes::TypeDict;
|
||||
|
||||
use crate::{viz::Visualization};
|
||||
|
||||
impl Visualization {
|
||||
pub fn into_html(
|
||||
self,
|
||||
dict: &mut impl TypeDict,
|
||||
position_files: Vec<PathBuf>
|
||||
) -> String {
|
||||
let mut position_file_dropdown_options = String::new();
|
||||
for path in position_files {
|
||||
let name = path.file_stem().expect("cant get basename").to_str().unwrap();
|
||||
position_file_dropdown_options.push_str(&format!(r##"
|
||||
<option value="{}" data-src="{}">{}</option>
|
||||
"##, name,
|
||||
path.to_str().unwrap(),
|
||||
name
|
||||
));
|
||||
}
|
||||
|
||||
let mut html = String::new();
|
||||
html.push_str(
|
||||
r##"
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Morphism Base</title>
|
||||
"##
|
||||
);
|
||||
|
||||
html.push_str(&self.style());
|
||||
|
||||
html.push_str(
|
||||
r##"
|
||||
</head>
|
||||
<body>
|
||||
"##
|
||||
);
|
||||
|
||||
html.push_str(&self.toolbar());
|
||||
for pane in self.panes.iter() {
|
||||
html.push_str(&pane.svg());
|
||||
}
|
||||
|
||||
html.push_str(&self.script());
|
||||
html.push_str(
|
||||
r##"
|
||||
</body>
|
||||
</html>
|
||||
"##);
|
||||
|
||||
html
|
||||
}
|
||||
|
||||
pub fn pane_selector( &self ) -> String {
|
||||
let mut html = String::new();
|
||||
html.push_str(r##"<select id="paneSelector">"##);
|
||||
for (i, pane) in self.panes.iter().enumerate() {
|
||||
if i == 0 {
|
||||
html.push_str(&format!(r##"<option value="{}" selected>{}</option>"##,
|
||||
pane.id(),
|
||||
pane.display_name()));
|
||||
} else {
|
||||
html.push_str(&format!(r##"<option value="{}">{}</option>"##,
|
||||
pane.id(),
|
||||
pane.display_name()));
|
||||
}
|
||||
}
|
||||
html.push_str(r##"</select>"##);
|
||||
html
|
||||
}
|
||||
|
||||
pub fn toolbar(&self) -> String {
|
||||
format!(r##"
|
||||
<div id="toolbar">
|
||||
<select id="layoutSelector">
|
||||
<option value="" disabled selected>Choose layout…</option>
|
||||
<option value="browse">Browse local file…</option>
|
||||
</select>
|
||||
|
||||
<button id="saveCsvBtn">💾 Save</button>
|
||||
|
||||
<label id="themeToggle">
|
||||
<input type="checkbox" id="themeCheckbox" />
|
||||
🌙
|
||||
</label>
|
||||
|
||||
{}
|
||||
</div>
|
||||
<input type="file" id="csvInput" accept=".csv" style="display:none;" />
|
||||
"##,
|
||||
self.pane_selector()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn script(&self) -> String {
|
||||
|
||||
let mut js = String::new();
|
||||
|
||||
js.push_str(r##"
|
||||
<script>
|
||||
// --- Helpers ---
|
||||
function parseTranslate(transform) {
|
||||
const match = /translate\(\s*([-\d.]+)\s*,\s*([-\d.]+)\s*\)/.exec(transform);
|
||||
if (!match) return { x: 0, y: 0 }; // fallback if transform is malformed or missing
|
||||
return {
|
||||
x: parseFloat(match[1]),
|
||||
y: parseFloat(match[2])
|
||||
};
|
||||
}
|
||||
function getNodePosition(node) {
|
||||
const match = /translate\(([^,]+),([^)]+)\)/.exec(
|
||||
node.getAttribute("transform"),
|
||||
);
|
||||
return { x: parseFloat(match[1]), y: parseFloat(match[2]) };
|
||||
}
|
||||
function setNodePosition(node, x, y) {
|
||||
node.setAttribute("transform", `translate(${x},${y})`);
|
||||
}
|
||||
function getCanvasTransform(canvasGroup) {
|
||||
const match =
|
||||
/translate\(([^,]+),([^)]+)\)\s*scale\(([^)]+)\)/.exec(
|
||||
canvasGroup.getAttribute("transform"),
|
||||
);
|
||||
return {
|
||||
tx: parseFloat(match[1]),
|
||||
ty: parseFloat(match[2]),
|
||||
scale: parseFloat(match[3]),
|
||||
};
|
||||
}
|
||||
function getCanvasScale(canvasGroup) {
|
||||
return getCanvasTransform(canvasGroup).scale;
|
||||
}
|
||||
|
||||
|
||||
// --- Update Edges and Labels ---
|
||||
function updateAllEdges() {
|
||||
const edges = document.querySelectorAll('line.arrow');
|
||||
const labels = document.querySelectorAll('.edge-label');
|
||||
|
||||
edges.forEach(line => {
|
||||
const sourceId = line.getAttribute('data-source');
|
||||
const targetId = line.getAttribute('data-target');
|
||||
const source = document.getElementById(sourceId);
|
||||
const target = document.getElementById(targetId);
|
||||
|
||||
if (!source || !target) return;
|
||||
|
||||
const sourceParentPos = parseTranslate(source.parentNode.getAttribute('transform'));
|
||||
const targetParentPos = parseTranslate(target.parentNode.getAttribute('transform'));
|
||||
const sourcePos = parseTranslate(source.getAttribute('transform'));
|
||||
const targetPos = parseTranslate(target.getAttribute('transform'));
|
||||
|
||||
const offsetX = 200;
|
||||
const offsetY = 60;
|
||||
|
||||
const x1 = sourceParentPos.x + sourcePos.x + 390;
|
||||
const y1 = sourceParentPos.y + sourcePos.y + 80;
|
||||
const x2 = targetParentPos.x + targetPos.x + 10;
|
||||
const y2 = targetParentPos.y + targetPos.y + 50;
|
||||
|
||||
// Set edge line position
|
||||
line.setAttribute('x1', x1);
|
||||
line.setAttribute('y1', y1);
|
||||
line.setAttribute('x2', x2);
|
||||
line.setAttribute('y2', y2);
|
||||
|
||||
// Update matching label
|
||||
const label = findLabel(labels, sourceId, targetId);
|
||||
if (label) {
|
||||
const midX = (x1 + x2) / 2;
|
||||
const midY = (y1 + y2) / 2;
|
||||
label.setAttribute('transform', `translate(${midX}, ${midY})`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Find label by matching source and target
|
||||
function findLabel(labelElements, sourceId, targetId) {
|
||||
return Array.from(labelElements).find(label =>
|
||||
label.getAttribute('data-source') === sourceId &&
|
||||
label.getAttribute('data-target') === targetId
|
||||
);
|
||||
}
|
||||
|
||||
function centerPane(pane, targetWidth) {
|
||||
const canvasGroup = pane.getElementById("canvasGroup");
|
||||
const svgWidth = pane.clientWidth;
|
||||
const svgHeight = pane.clientHeight;
|
||||
|
||||
const scale = svgWidth / targetWidth;
|
||||
|
||||
// Center the canvasGroup at the middle of the screen
|
||||
const offsetX = svgWidth / 2;
|
||||
const offsetY = svgHeight / 2;
|
||||
|
||||
canvasGroup.setAttribute('transform', `translate(${offsetX},${offsetY}) scale(${scale})`);
|
||||
}
|
||||
|
||||
|
||||
//-- Event Listener Setup --
|
||||
function setupEventListenersForPane(pane) {
|
||||
let selectedNode = null;
|
||||
let dragStartScreen = null;
|
||||
let nodeStartPos = null;
|
||||
let panStart = null;
|
||||
|
||||
const canvasGroup = pane.getElementById("canvasGroup");
|
||||
|
||||
// --- Dragging Nodes ---
|
||||
|
||||
function onMouseDown(e) {
|
||||
const node = e.target.closest(".draggable");
|
||||
if (node) {
|
||||
selectedNode = node;
|
||||
dragStartScreen = { x: e.clientX, y: e.clientY };
|
||||
nodeStartPos = getNodePosition(selectedNode);
|
||||
|
||||
pane.style.cursor = "grabbing";
|
||||
window.addEventListener("mousemove", onMouseMoveNode);
|
||||
window.addEventListener("mouseup", onMouseUpNode);
|
||||
} else {
|
||||
panStart = { x: e.clientX, y: e.clientY };
|
||||
pane.style.cursor = "grabbing";
|
||||
window.addEventListener("mousemove", onPanMove);
|
||||
window.addEventListener("mouseup", endPan);
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseMoveNode(e) {
|
||||
if (!selectedNode) return;
|
||||
|
||||
const dx = e.clientX - dragStartScreen.x;
|
||||
const dy = e.clientY - dragStartScreen.y;
|
||||
const scale = getCanvasScale(canvasGroup);
|
||||
|
||||
const newX = nodeStartPos.x + dx / scale;
|
||||
const newY = nodeStartPos.y + dy / scale;
|
||||
|
||||
setNodePosition(selectedNode, newX, newY);
|
||||
updateAllEdges();
|
||||
}
|
||||
|
||||
function onMouseUpNode(e) {
|
||||
pane.style.cursor = "grab";
|
||||
window.removeEventListener("mousemove", onMouseMoveNode);
|
||||
window.removeEventListener("mouseup", onMouseUpNode);
|
||||
selectedNode = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// --- Panning ---
|
||||
|
||||
function onPanMove(e) {
|
||||
const dx = e.clientX - panStart.x;
|
||||
const dy = e.clientY - panStart.y;
|
||||
const { tx, ty, scale } = getCanvasTransform(canvasGroup);
|
||||
canvasGroup.setAttribute(
|
||||
"transform",
|
||||
`translate(${tx + dx},${ty + dy}) scale(${scale})`,
|
||||
);
|
||||
panStart = { x: e.clientX, y: e.clientY };
|
||||
}
|
||||
|
||||
function endPan(e) {
|
||||
pane.style.cursor = "grab";
|
||||
window.removeEventListener("mousemove", onPanMove);
|
||||
window.removeEventListener("mouseup", endPan);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -- Dragging --
|
||||
pane.addEventListener("mousedown", onMouseDown);
|
||||
|
||||
// --- Zoom ---
|
||||
pane.addEventListener("wheel", (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const zoomIntensity = 0.1;
|
||||
const { tx, ty, scale } = getCanvasTransform(canvasGroup);
|
||||
|
||||
const pt = pane.createSVGPoint();
|
||||
pt.x = e.clientX;
|
||||
pt.y = e.clientY;
|
||||
|
||||
const cursorpt = pt.matrixTransform(
|
||||
pane.getScreenCTM().inverse(),
|
||||
);
|
||||
|
||||
const direction = e.deltaY > 0 ? -1 : 1;
|
||||
const factor = 1 + direction * zoomIntensity;
|
||||
const newScale = scale * factor;
|
||||
|
||||
const dx = cursorpt.x - tx;
|
||||
const dy = cursorpt.y - ty;
|
||||
|
||||
const newTx = cursorpt.x - dx * factor;
|
||||
const newTy = cursorpt.y - dy * factor;
|
||||
|
||||
canvasGroup.setAttribute(
|
||||
"transform",
|
||||
`translate(${newTx},${newTy}) scale(${newScale})`,
|
||||
);
|
||||
|
||||
|
||||
// Adjust module-label font sizes
|
||||
const labels = document.querySelectorAll('tspan.module-label');
|
||||
labels.forEach(label => {
|
||||
const fontScale = 1.0/ newScale;
|
||||
|
||||
// Scale inversely so labels shrink as you zoom in, grow as you zoom out
|
||||
label.setAttribute("transform",
|
||||
`scale(${fontScale})`,
|
||||
);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// -- Load Positions --
|
||||
function updatePositionsFromCSV(csvText) {
|
||||
const lines = csvText.trim().split('\n');
|
||||
const [header, ...rows] = lines;
|
||||
|
||||
const [idHeader, xHeader, yHeader] = header.split(',').map(h => h.trim());
|
||||
|
||||
if (idHeader !== 'id' || xHeader !== 'x' || yHeader !== 'y') {
|
||||
console.warn('CSV header must be: id,x,y');
|
||||
return;
|
||||
}
|
||||
|
||||
rows.forEach(row => {
|
||||
const [id, xStr, yStr] = row.split(',').map(s => s.trim());
|
||||
const x = parseFloat(xStr);
|
||||
const y = parseFloat(yStr);
|
||||
|
||||
if (!id || isNaN(x) || isNaN(y)) {
|
||||
console.warn(`Skipping invalid row: "${row}"`);
|
||||
return;
|
||||
}
|
||||
|
||||
const node = document.getElementById(id);
|
||||
if (node) {
|
||||
node.setAttribute('transform', `translate(${x},${y})`);
|
||||
} else {
|
||||
console.warn(`Node not found: ${id}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const layoutSelector = document.getElementById('layoutSelector');
|
||||
const fileInput = document.getElementById('csvInput');
|
||||
|
||||
layoutSelector.addEventListener('input', (e) => {
|
||||
const selected = e.target.selectedOptions[0];
|
||||
const value = selected.value;
|
||||
|
||||
if (value === 'browse') {
|
||||
fileInput.click(); // Open file picker
|
||||
layoutSelector.selectedIndex = 0; // Reset to "Choose layout..."
|
||||
return;
|
||||
}
|
||||
|
||||
const src = selected.getAttribute('data-src');
|
||||
if (src) {
|
||||
fetch(src)
|
||||
.then(response => {
|
||||
if (!response.ok) throw new Error(`Failed to fetch: ${src}`);
|
||||
return response.text();
|
||||
})
|
||||
.then(csvText => {
|
||||
updatePositionsFromCSV(csvText);
|
||||
updateAllEdges();
|
||||
layoutSelector.selectedIndex = 0; // Reset to placeholder
|
||||
})
|
||||
.catch(err => {
|
||||
alert('Could not load layout: ' + err.message);
|
||||
console.error(err);
|
||||
layoutSelector.selectedIndex = 0;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Also reset after loading a local file
|
||||
fileInput.addEventListener('change', function (event) {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
updatePositionsFromCSV(e.target.result);
|
||||
updateAllEdges();
|
||||
layoutSelector.selectedIndex = 0; // Reset dropdown after use
|
||||
};
|
||||
reader.readAsText(file);
|
||||
});
|
||||
|
||||
// -- Save Positions --
|
||||
document.getElementById('saveCsvBtn').addEventListener('click', function () {
|
||||
const draggableNodes = document.querySelectorAll('g.draggable');
|
||||
let csvContent = 'id,x,y\n';
|
||||
|
||||
draggableNodes.forEach(node => {
|
||||
const id = node.id;
|
||||
const transform = node.getAttribute('transform');
|
||||
const match = /translate\(([-\d.]+),\s*([-\d.]+)\)/.exec(transform);
|
||||
if (match) {
|
||||
const x = parseFloat(match[1]);
|
||||
const y = parseFloat(match[2]);
|
||||
csvContent += `${id},${x},${y}\n`;
|
||||
}
|
||||
});
|
||||
|
||||
// Trigger download
|
||||
const blob = new Blob([csvContent], { type: 'text/csv' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'morphgraph-layout.csv';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
|
||||
// -- Theme --
|
||||
const themeCheckbox = document.getElementById('themeCheckbox');
|
||||
function setTheme(mode) {
|
||||
document.body.classList.remove('light', 'dark');
|
||||
document.body.classList.add(mode);
|
||||
themeCheckbox.checked = (mode === 'dark');
|
||||
localStorage.setItem('theme', mode);
|
||||
}
|
||||
|
||||
// Load saved theme or default to dark
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
if (savedTheme) {
|
||||
setTheme(savedTheme);
|
||||
} else {
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
setTheme(prefersDark ? 'dark' : 'light', false);
|
||||
}
|
||||
|
||||
themeCheckbox.addEventListener('change', () => {
|
||||
setTheme(themeCheckbox.checked ? 'dark' : 'light');
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// -- Pane Selector --
|
||||
function setPane(paneid) {
|
||||
// deactivate all
|
||||
const panes = document.querySelectorAll('svg');
|
||||
panes.forEach(pane => pane.style.display = 'none');
|
||||
|
||||
// activate current
|
||||
currentPane = document.getElementById(paneid);
|
||||
if (currentPane) currentPane.style.display = 'block';
|
||||
|
||||
localStorage.setItem('current-pane', paneid);
|
||||
}
|
||||
|
||||
document.getElementById('paneSelector').value = 'morphism-base';
|
||||
document.getElementById('paneSelector').addEventListener('change', function() {
|
||||
setPane(this.value);
|
||||
});
|
||||
|
||||
// Load saved pane selection
|
||||
const savedPaneId = localStorage.getItem('current-pane');
|
||||
if( savedPaneId ) {
|
||||
// selector.value = savedPaneId;
|
||||
//setPane(savedPaneId);
|
||||
}
|
||||
"##);
|
||||
|
||||
for pane in self.panes.iter() {
|
||||
let target_width = 4000;
|
||||
js.push_str(&format!(r##"
|
||||
pane = document.getElementById('{}');
|
||||
centerPane( pane, {} );
|
||||
setupEventListenersForPane( pane );
|
||||
"##, pane.id(), target_width));
|
||||
}
|
||||
|
||||
js.push_str(r##"
|
||||
updateAllEdges();
|
||||
|
||||
</script>
|
||||
"##);
|
||||
|
||||
js
|
||||
}
|
||||
}
|
13
src/viz/layout.rs
Normal file
13
src/viz/layout.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct PaneLayout {
|
||||
pub modules: HashMap< String, ModulePos >,
|
||||
}
|
||||
|
||||
pub struct ModulePos {
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub max_morphisms: u32,
|
||||
pub next_pos_count: u32,
|
||||
}
|
61
src/viz/mod.rs
Normal file
61
src/viz/mod.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
|
||||
pub mod type_to_svg;
|
||||
pub mod layout;
|
||||
pub mod morphbase_pane;
|
||||
pub mod morphinst_pane;
|
||||
pub mod search_pane;
|
||||
pub mod theme;
|
||||
pub mod gen_html;
|
||||
|
||||
pub use type_to_svg::unparse_type_to_svg;
|
||||
pub use layout::PaneLayout;
|
||||
pub use morphbase_pane::MorphbaseVisualizationPane;
|
||||
pub use morphinst_pane::MorphinstVizPane;
|
||||
pub use search_pane::SearchPane;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use laddertypes::{unparser::*, ContextPtr, GraphSearch, Morphism, MorphismInstance, StructMember, TypeDict, TypeID, TypeTerm};
|
||||
|
||||
use crate::morphism::LdmcPrimMorph;
|
||||
|
||||
pub struct Visualization {
|
||||
pub modules: Vec< String >,
|
||||
pub panes: Vec< Box<dyn VisualizationPane> >
|
||||
}
|
||||
|
||||
pub trait VisualizationPane {
|
||||
fn id(&self) -> String;
|
||||
fn display_name(&self) -> String;
|
||||
fn svg(&self) -> String;
|
||||
}
|
||||
|
||||
impl Visualization {
|
||||
pub fn new() -> Visualization {
|
||||
Visualization {
|
||||
modules: Vec::new(),
|
||||
panes: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_module(&mut self, modname: String) {
|
||||
self.modules.push(modname);
|
||||
}
|
||||
|
||||
pub fn add_pane(&mut self, pane: impl VisualizationPane + 'static) {
|
||||
self.panes.push(Box::new(pane));
|
||||
}
|
||||
|
||||
pub fn add_morph_inst(&mut self, name: String, morph: MorphismInstance<LdmcPrimMorph>, Γ0: ContextPtr) {
|
||||
let mut morph_pane = MorphinstVizPane::new(name, morph);
|
||||
morph_pane.build_svg(Γ0);
|
||||
self.modules.append( &mut morph_pane.get_subnames() );
|
||||
self.add_pane( morph_pane );
|
||||
}
|
||||
|
||||
pub fn add_search_graph(&mut self, ctx: ContextPtr, name: String, graph: &GraphSearch<LdmcPrimMorph>) {
|
||||
let mut search_pane = SearchPane::new(ctx, name);
|
||||
search_pane.build_svg(graph);
|
||||
self.modules.append( &mut search_pane.get_subnames() );
|
||||
self.add_pane( search_pane );
|
||||
}
|
||||
}
|
192
src/viz/morphbase_pane.rs
Normal file
192
src/viz/morphbase_pane.rs
Normal file
|
@ -0,0 +1,192 @@
|
|||
pub use {
|
||||
laddertypes::TypeDict,
|
||||
crate::morphism::LdmcPrimMorph,
|
||||
super::{VisualizationPane, PaneLayout, unparse_type_to_svg},
|
||||
std::collections::HashMap,
|
||||
};
|
||||
|
||||
|
||||
pub struct MorphbaseVisualizationPane {
|
||||
n_modules: usize,
|
||||
nodes: Vec< VizNode >,
|
||||
layout: PaneLayout,
|
||||
svg: Option< String >
|
||||
}
|
||||
|
||||
pub struct VizNode {
|
||||
pub module: String,
|
||||
pub morph: LdmcPrimMorph
|
||||
}
|
||||
|
||||
impl VisualizationPane for MorphbaseVisualizationPane {
|
||||
fn id(&self) -> String { "morphism-base".into() }
|
||||
fn display_name(&self) -> String { "Morphism Base".into() }
|
||||
fn svg(&self) -> String {
|
||||
self.svg.clone().unwrap_or(String::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl MorphbaseVisualizationPane {
|
||||
pub fn new(n_modules: usize) -> MorphbaseVisualizationPane {
|
||||
MorphbaseVisualizationPane {
|
||||
n_modules,
|
||||
nodes: Vec::new(),
|
||||
layout: PaneLayout { modules: HashMap::new() },
|
||||
svg: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_module( &mut self, modname: String ) {
|
||||
let i = self.layout.modules.len();
|
||||
let rot = 6.283 * (i as f64) / (self.n_modules as f64);
|
||||
|
||||
let radius = 1000.0 + 500.0 * f64::sin(3.0*rot);
|
||||
let modpos = (2.0*radius*rot.cos(), radius*rot.sin());
|
||||
|
||||
self.layout.modules.insert(
|
||||
modname,
|
||||
super::layout::ModulePos {
|
||||
x: modpos.0,
|
||||
y: modpos.1,
|
||||
max_morphisms: 0,
|
||||
next_pos_count: 0
|
||||
});
|
||||
}
|
||||
|
||||
pub fn add_morphism(
|
||||
&mut self,
|
||||
modname: &String,
|
||||
m: &LdmcPrimMorph
|
||||
) {
|
||||
self.nodes.push(VizNode{ module: modname.clone(), morph: m.clone() });
|
||||
if let Some(modpos) = self.layout.modules.get_mut(modname) {
|
||||
modpos.max_morphisms += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_edges(&self) -> Vec<(String, String, String)> {
|
||||
let mut edges = vec![];
|
||||
|
||||
for n1 in self.nodes.iter() {
|
||||
for n2 in self.nodes.iter() {
|
||||
if let Ok((σ,ψ)) = laddertypes::subtype_unify(&n1.morph.ty.dst_type, &n2.morph.ty.src_type) {
|
||||
edges.push((
|
||||
n1.morph.symbol.clone(),
|
||||
n2.morph.symbol.clone(),
|
||||
"".into()
|
||||
/*
|
||||
format!(r##"
|
||||
≤
|
||||
"##)
|
||||
*/
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
edges
|
||||
}
|
||||
|
||||
pub fn build_svg(&mut self, dict: &mut impl TypeDict) {
|
||||
let mut svg = String::new();
|
||||
svg.push_str(&format!(r##"
|
||||
<svg id="{}">
|
||||
<defs>
|
||||
<marker
|
||||
id="arrowhead"
|
||||
markerWidth="10"
|
||||
markerHeight="7"
|
||||
refX="10"
|
||||
refY="3.5"
|
||||
orient="auto"
|
||||
markerUnits="strokeWidth"
|
||||
>
|
||||
<polygon points="0 0, 10 3.5, 0 7" fill="#555" />
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
"##, self.id()));
|
||||
|
||||
svg.push_str(r##"<g id="canvasGroup" transform="translate(800,500) scale(0.4)">"##);
|
||||
|
||||
for edge in self.get_edges() {
|
||||
let srcid = edge.0;
|
||||
let dstid = edge.1;
|
||||
let text = edge.2;
|
||||
svg.push_str(&format!(r##"
|
||||
<line class="arrow" data-source="{}" data-target="{}" />
|
||||
|
||||
<text class="edge-label" data-source="{}" data-target="{}">
|
||||
{}
|
||||
</text>
|
||||
"##, srcid, dstid, srcid, dstid, text));
|
||||
}
|
||||
|
||||
for (modname, modpos) in self.layout.modules.iter_mut() {
|
||||
svg.push_str(&format!(r##"
|
||||
<g id="mod-{}" class="draggable" transform="translate({}, {})">
|
||||
<circle r="300" class="module-bg-{}" />
|
||||
|
||||
<!-- Module Label -->
|
||||
<text
|
||||
class="module-label module-{}"
|
||||
id="module-{}"
|
||||
text-anchor="middle"
|
||||
>
|
||||
{}
|
||||
</text>
|
||||
|
||||
<!-- Nodes in module Group -->
|
||||
|
||||
"##, modname, modpos.x as i32, modpos.y as i32, modname, modname, modname, modname));
|
||||
|
||||
for node in self.nodes.iter().filter(|n| &n.module == modname) {
|
||||
let mut radius = 400.0 + (modpos.max_morphisms as f64)*10.0;
|
||||
let rot = 6.283 * (modpos.next_pos_count as f64 / modpos.max_morphisms as f64);
|
||||
modpos.next_pos_count += 1;
|
||||
radius = radius + 50.0*(rot*modpos.max_morphisms as f64 / 3.0).sin();
|
||||
let posx = radius * rot.cos() - 200.0;
|
||||
let posy = radius * rot.sin() - 100.0;
|
||||
|
||||
svg.push_str(&format!(r##"<g class="draggable" id="{}" transform="translate({},{})">"##,
|
||||
node.morph.symbol,
|
||||
posx as i32,
|
||||
posy as i32
|
||||
));
|
||||
|
||||
svg.push_str(&format!(r##"
|
||||
<rect
|
||||
class="node-box module-{}"
|
||||
width="400"
|
||||
height="120"
|
||||
/>
|
||||
<text
|
||||
class="morph-name module-{}"
|
||||
x="60"
|
||||
y="25"
|
||||
text-anchor="left"
|
||||
> {} </text>
|
||||
<text x="50" y="50"> {} </text>
|
||||
<text x="10" y="80"> <tspan class="arrow">⟶</tspan> </text>
|
||||
<text x="50" y="80"> {} </text>
|
||||
"##,
|
||||
|
||||
node.module,
|
||||
node.module,
|
||||
node.morph.symbol,
|
||||
unparse_type_to_svg(dict, &node.morph.ty.src_type),
|
||||
unparse_type_to_svg(dict, &node.morph.ty.dst_type)
|
||||
));
|
||||
|
||||
svg.push_str(r##"</g>"##);
|
||||
}
|
||||
svg.push_str(r##"</g>"##);
|
||||
}
|
||||
|
||||
svg.push_str(r##"</g>"##);
|
||||
|
||||
svg.push_str(r##"</svg>"##);
|
||||
|
||||
self.svg = Some(svg);
|
||||
}
|
||||
}
|
460
src/viz/morphinst_pane.rs
Normal file
460
src/viz/morphinst_pane.rs
Normal file
|
@ -0,0 +1,460 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use laddertypes::{unparser::*, AddressingMode, ContextPtr, LayeredContext, Morphism, MorphismInstance, TypeDict, TypeTerm};
|
||||
|
||||
use crate::morphism::LdmcPrimMorph;
|
||||
use crate::viz::{type_to_svg, unparse_type_to_svg, VisualizationPane};
|
||||
|
||||
pub struct Edge {
|
||||
src_id: String,
|
||||
dst_id: String,
|
||||
label: String,
|
||||
width: f32,
|
||||
height: f32
|
||||
}
|
||||
|
||||
pub struct Node {
|
||||
id: String,
|
||||
pos: (f32, f32),
|
||||
ctx: ContextPtr,
|
||||
ψ: TypeTerm,
|
||||
τ: TypeTerm,
|
||||
}
|
||||
|
||||
pub struct MorphinstVizPane {
|
||||
name: String,//todo: displayname + ID
|
||||
inst: MorphismInstance<LdmcPrimMorph>,
|
||||
svg: Option< String >,
|
||||
extent: Extent,
|
||||
|
||||
subnames: Vec<String>,
|
||||
}
|
||||
|
||||
impl MorphinstVizPane {
|
||||
pub fn new( name: String, inst: MorphismInstance<LdmcPrimMorph>) -> Self {
|
||||
MorphinstVizPane { name, inst, svg: None, subnames: vec![ ], extent: Extent::empty() }
|
||||
}
|
||||
|
||||
pub fn get_subnames(&self) -> Vec<String> {
|
||||
self.subnames.clone()
|
||||
}
|
||||
|
||||
pub fn get_extent(&self) -> Extent {
|
||||
self.extent.clone()
|
||||
}
|
||||
|
||||
pub fn build_module_group(&mut self,
|
||||
svg: &mut String,
|
||||
mut ctx: ContextPtr,
|
||||
pos: (f32, f32)
|
||||
) {
|
||||
let mut layout = Layout::new(self.name.clone());
|
||||
let mut nodes = Vec::new();
|
||||
let mut edges = Vec::new();
|
||||
layout.add_type(&mut nodes, &ctx, TypeTerm::unit(), self.inst.get_type().src_type);
|
||||
let mut ctx0 = layout.add_morph_inst(&mut nodes, &mut edges, &self.inst, &ctx, TypeTerm::unit(), &mut self.subnames);
|
||||
self.extent = layout.extent.clone();
|
||||
// add some padding
|
||||
self.extent.begin.0 -= 100.0;
|
||||
self.extent.begin.1 -= 100.0;
|
||||
self.extent.end.0 += 100.0;
|
||||
self.extent.end.1 += 100.0;
|
||||
|
||||
svg.push_str(&format!(r##"
|
||||
<g id="mod-{}" class="draggable" transform="translate({}, {})">
|
||||
<rect x="{}" y="{}" width="{}" height="{}" class="module-bg-{}" />
|
||||
|
||||
<!-- Module Label -->
|
||||
<text
|
||||
class="module-label module-{}"
|
||||
id="module-{}"
|
||||
text-anchor="left"
|
||||
>
|
||||
{}
|
||||
</text>
|
||||
|
||||
<!-- Nodes in module Group -->
|
||||
|
||||
"##, self.name, pos.0, pos.1,
|
||||
self.extent.begin.0, self.extent.begin.1,
|
||||
self.extent.end.0 - self.extent.begin.0, self.extent.end.1 - self.extent.begin.1,
|
||||
self.name, self.name, self.name, self.display_name()));
|
||||
|
||||
for n in nodes.iter() {
|
||||
svg.push_str(&format!(r##"<g id="{}" class="draggable type-node" transform="translate({},{})" width=200 height=100 >"##,
|
||||
n.id,
|
||||
n.pos.0,
|
||||
n.pos.1
|
||||
));
|
||||
|
||||
svg.push_str(&format!(r##"<rect class="node-box module-{}" x="0" y="0" width=800 height=200 />"##, self.name));
|
||||
svg.push_str(r##"<text x="50" y="80">"##);
|
||||
svg.push_str(&unparse_type_to_svg(&mut n.ctx.clone(), &n.ψ.clone().apply_subst(&n.ctx).clone()));
|
||||
svg.push_str(r##"</text>"##);
|
||||
|
||||
svg.push_str(r##"<text x="50" y="150">"##);
|
||||
if !n.ψ.is_empty() {
|
||||
svg.push_str(r##"<tspan class="infix">~</tspan>"##);
|
||||
}
|
||||
svg.push_str(&unparse_type_to_svg(&mut n.ctx.clone(), &n.τ.clone().apply_subst(&n.ctx).clone()));
|
||||
|
||||
svg.push_str(r##"</text>"##);
|
||||
svg.push_str(r##"</g>"##);
|
||||
}
|
||||
|
||||
svg.push_str(r##"</g>"##);
|
||||
|
||||
|
||||
for e in edges.iter() {
|
||||
svg.push_str(&format!(r##"
|
||||
<line class="arrow arrow2" data-source="{}" data-target="{}" />
|
||||
|
||||
<g class="edge-label" data-source="{}" data-target="{}">
|
||||
<g class="draggable" transform="translate({},{})" >
|
||||
{}
|
||||
</g>
|
||||
</g>
|
||||
"##, e.src_id, e.dst_id, e.src_id, e.dst_id, 0., -e.height/2., e.label));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn build_svg(&mut self, Γ: ContextPtr) {
|
||||
let mut svg = String::new();
|
||||
svg.push_str(&format!(r##"
|
||||
<svg id="{}">
|
||||
<defs>
|
||||
<marker
|
||||
id="arrowhead2"
|
||||
markerWidth="10"
|
||||
markerHeight="7"
|
||||
refX="10"
|
||||
refY="3.5"
|
||||
orient="auto"
|
||||
markerUnits="strokeWidth"
|
||||
>
|
||||
<polygon points="0 0, 10 3.5, 0 7" fill="#555" />
|
||||
</marker>
|
||||
</defs>
|
||||
"##, self.id()));
|
||||
|
||||
svg.push_str(r##"<g id="canvasGroup" transform="translate(400,200) scale(1)">"##);
|
||||
self.build_module_group(&mut svg, Γ, (0.0, 0.0));
|
||||
|
||||
svg.push_str(r##"</g>"##);
|
||||
svg.push_str(r##"</svg>"##);
|
||||
|
||||
self.svg = Some(svg);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Extent {
|
||||
begin: (f32, f32),
|
||||
end: (f32, f32)
|
||||
}
|
||||
|
||||
impl Extent {
|
||||
fn empty() -> Self {
|
||||
Extent {
|
||||
begin: (0.,0.),
|
||||
end: (0.,0.)
|
||||
}
|
||||
}
|
||||
fn max(e1: &Extent, e2: &Extent) -> Self {
|
||||
Extent {
|
||||
begin: (f32::min(e1.begin.0, e2.begin.0), f32::min(e1.begin.1, e2.begin.1)),
|
||||
end: (f32::max(e1.end.0, e2.end.0), f32::max(e1.end.1, e2.end.1))
|
||||
}
|
||||
}
|
||||
fn offset(&self, offset: (f32, f32)) -> Self {
|
||||
Extent {
|
||||
begin: (self.begin.0 + offset.0, self.begin.1 + offset.1),
|
||||
end: (self.end.0 + offset.0, self.end.1 + offset.1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Layout {
|
||||
i: u32,
|
||||
pos: (f32, f32),
|
||||
nameprefix: String,
|
||||
|
||||
extent: Extent
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
pub fn new(nameprefix: String) -> Self {
|
||||
Layout {
|
||||
i: 0,
|
||||
pos: (50.0, 400.0),
|
||||
nameprefix,
|
||||
extent: Extent::empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_type(&mut self,
|
||||
nodes: &mut Vec<Node>,
|
||||
Γ: &ContextPtr,
|
||||
ψ: TypeTerm, mut τ: TypeTerm)
|
||||
{
|
||||
τ.apply_subst(Γ);
|
||||
nodes.push(Node {
|
||||
id: format!("type-{}-{}", self.nameprefix, self.i),
|
||||
pos: self.pos,
|
||||
ctx: Γ.clone(),
|
||||
ψ, τ
|
||||
});
|
||||
|
||||
self.extent = Extent::max(&self.extent, &Extent { begin: (0., 0.), end: (600.0, 400.0) }.offset(self.pos));
|
||||
}
|
||||
|
||||
pub fn add_chained_type(
|
||||
&mut self,
|
||||
nodes: &mut Vec<Node>,
|
||||
edges: &mut Vec<Edge>,
|
||||
σ: Vec<(u64, TypeTerm)>,
|
||||
ψ: TypeTerm,
|
||||
τ: TypeTerm,
|
||||
morphname: String,
|
||||
|
||||
mut Γ0: ContextPtr,
|
||||
) {
|
||||
let mut σ_str = "σ = {".to_string();
|
||||
|
||||
for (n,t) in σ {
|
||||
σ_str.push_str(&format!("{} -> {}",
|
||||
Γ0.get_varname(n).unwrap_or("??".into()),
|
||||
unparse_type_to_svg(&mut Γ0, &t)));
|
||||
}
|
||||
|
||||
σ_str.push_str("}");
|
||||
|
||||
let ψ_str =
|
||||
if ψ.is_empty() {
|
||||
"ψ = ε".into()
|
||||
} else {
|
||||
let mut ψ = ψ.clone();
|
||||
ψ.apply_subst(&Γ0);
|
||||
format!("ψ = {}", unparse_type_to_svg(&mut Γ0.clone(), &ψ))
|
||||
};
|
||||
|
||||
edges.push(Edge {
|
||||
src_id: format!("type-{}-{}", &self.nameprefix, self.i),
|
||||
dst_id: format!("type-{}-{}", &self.nameprefix, self.i+1),
|
||||
label: format!(r##"
|
||||
<text y="-80" class="halo" text-anchor="center">{}</text>
|
||||
<text y="0" class="morph-name" text-anchor="center" >{}</text>
|
||||
<text y="80" class="Γ" text-anchor="center">{}</text>
|
||||
"##, ψ_str, morphname, σ_str),
|
||||
width: 0.0,
|
||||
height: 0.,
|
||||
});
|
||||
|
||||
self.i += 1;
|
||||
self.pos.0 += 850.0;
|
||||
self.pos.1 += if self.pos.1 < 0. { 400.0} else {-400.0};
|
||||
|
||||
self.extent.begin.0 = f32::min( self.extent.begin.0, self.pos.0 );
|
||||
self.extent.begin.1 = f32::min( self.extent.begin.1, self.pos.1 );
|
||||
self.extent.end.0 = f32::max( self.extent.end.0, self.pos.0 );
|
||||
self.extent.end.1 = f32::max( self.extent.end.1, self.pos.1 );
|
||||
self.add_type(nodes, &Γ0, ψ, τ);
|
||||
}
|
||||
|
||||
pub fn sub_layout(&self, pfx: String, yoff: f32) -> Self {
|
||||
Layout {
|
||||
i: 0,
|
||||
nameprefix: format!("{}-{}", self.nameprefix, pfx),
|
||||
pos: (
|
||||
self.pos.0 + 600.0,
|
||||
self.pos.1 + yoff
|
||||
),
|
||||
extent: Extent::empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_morph_inst(
|
||||
&mut self,
|
||||
nodes: &mut Vec<Node>,
|
||||
edges: &mut Vec<Edge>,
|
||||
inst: &MorphismInstance<LdmcPrimMorph>,
|
||||
Γ0: &ContextPtr,
|
||||
ψ: TypeTerm,
|
||||
|
||||
subnames: &mut Vec<String>,
|
||||
) -> ContextPtr {
|
||||
match inst {
|
||||
MorphismInstance::Id { τ } => {
|
||||
|
||||
}
|
||||
MorphismInstance::Sub { ψ:ψ1, m } => {
|
||||
self.add_morph_inst(nodes, edges, m, Γ0,
|
||||
TypeTerm::Ladder(vec![ ψ1.clone(), ψ.clone() ]).normalize(),
|
||||
subnames
|
||||
);
|
||||
}
|
||||
MorphismInstance::Specialize { σ, m } => {
|
||||
//let mut c = Γ0.scope(AddressingMode::StackUp);
|
||||
for (v,t) in σ.iter() {
|
||||
Γ0.bind(*v,t.clone());
|
||||
}
|
||||
self.add_morph_inst(nodes, edges, m, &Γ0, ψ, subnames);
|
||||
return Γ0.clone();
|
||||
}
|
||||
MorphismInstance::Primitive { σs, m: morph } => {
|
||||
subnames.push( morph.symbol.clone() );
|
||||
let gamma = σs.iter().map(|(v,t)| (match t {
|
||||
TypeTerm::Var(v) => *v,
|
||||
_ => unreachable!()
|
||||
}, t.clone().apply_subst(Γ0).clone())).collect::<Vec<_>>();
|
||||
|
||||
Γ0.shift_variables(&morph.get_type().Γ);
|
||||
self.add_chained_type(nodes, edges,
|
||||
gamma,
|
||||
ψ,
|
||||
inst.get_type().dst_type,
|
||||
morph.symbol.clone(),
|
||||
Γ0.clone());
|
||||
},
|
||||
MorphismInstance::Chain { path } => {
|
||||
for m in path.iter() {
|
||||
self.add_morph_inst(nodes, edges, m, Γ0, ψ.clone(), subnames);
|
||||
}
|
||||
},
|
||||
MorphismInstance::MapSeq { seq_repr, item_morph } => {
|
||||
let mut map_group_svg = String::new();
|
||||
let name = format!("{}-{}-SeqItem", self.nameprefix, self.i);
|
||||
|
||||
let mut pane = MorphinstVizPane::new( name.clone(), item_morph.deref().clone() );
|
||||
pane.build_module_group(&mut map_group_svg, Γ0.clone(), (200.0, 200.0) );
|
||||
subnames.append(&mut pane.get_subnames());
|
||||
subnames.push(name);
|
||||
|
||||
let height = pane.get_extent().end.1 - pane.get_extent().begin.1 + 200.0;
|
||||
map_group_svg.push_str(&format!(r##"
|
||||
<path d="M0,0 C0,{} -50,{} 50,{}
|
||||
M0,0 C0,{} -50,{} 50,{}"
|
||||
fill="none" stroke-width="18" transform="translate(0,{})"/>
|
||||
|
||||
|
||||
"##,
|
||||
|
||||
-height/4.,
|
||||
-height/2.,
|
||||
-height/2.,
|
||||
|
||||
height/4.,
|
||||
height/2.,
|
||||
height/2.,
|
||||
|
||||
pane.get_extent().begin.1 + height/2. + 100.0
|
||||
));
|
||||
|
||||
map_group_svg.insert_str(0, &format!(r##"<g class="map-group" transform="translate({},{})">"##,
|
||||
0,
|
||||
0
|
||||
));
|
||||
map_group_svg.push_str(r##"</g>"##);
|
||||
|
||||
edges.push(Edge {
|
||||
src_id: format!("type-{}-{}", &self.nameprefix, self.i),
|
||||
dst_id: format!("type-{}-{}", &self.nameprefix, self.i+1),
|
||||
label: map_group_svg,
|
||||
width: pane.get_extent().end.0 - pane.get_extent().begin.0,
|
||||
height: pane.get_extent().end.1 - pane.get_extent().begin.1
|
||||
});
|
||||
|
||||
self.i += 1;
|
||||
|
||||
self.extent = Extent::max(&self.extent, &pane.get_extent());
|
||||
self.pos.0 += 400.0;
|
||||
self.pos.1 += pane.get_extent().end.1 - pane.get_extent().begin.1 + 500.0;
|
||||
|
||||
self.add_type(nodes, Γ0, ψ.clone(), inst.get_type().dst_type);
|
||||
|
||||
self.pos.0 += ( pane.get_extent().end.0 - pane.get_extent().begin.0 );
|
||||
},
|
||||
MorphismInstance::MapStruct { struct_repr, member_morph } => {
|
||||
let mut map_group_svg = String::new();
|
||||
|
||||
map_group_svg.push_str(&format!(r##"<g class="map-group" transform="translate({},{})">"##, self.pos.0, self.pos.1 ));
|
||||
|
||||
let mut members_extent = Extent::empty();
|
||||
let mut local_pos = (0.,0.);
|
||||
for (i,m) in member_morph.iter().enumerate() {
|
||||
let name = format!("{}-{}-{}", self.nameprefix, self.i, m.0);
|
||||
let mut pane = MorphinstVizPane::new( name.clone(), m.1.clone() );
|
||||
|
||||
pane.build_module_group( &mut map_group_svg, Γ0.clone(), local_pos );
|
||||
subnames.append(&mut pane.get_subnames());
|
||||
subnames.push(name.clone());
|
||||
|
||||
members_extent = Extent::max(&members_extent, &pane.get_extent().offset(local_pos));
|
||||
local_pos.1 += pane.get_extent().end.1 - pane.get_extent().begin.1;
|
||||
local_pos.1 += 200.0; // padding
|
||||
}
|
||||
|
||||
let height = members_extent.end.1 - members_extent.begin.1 + 100.0;
|
||||
map_group_svg.push_str(&format!(r##"
|
||||
<path d="M0,-50 C0,{} -50,{} 50,{}
|
||||
M0,-50 C0,0 -100,-25 -100,0
|
||||
M0,50 C0,0 -100,25 -100,0
|
||||
M0,50 C0,{} -50,{} 50,{}"
|
||||
fill="none" stroke-width="18" transform="translate(0,{})"/>
|
||||
|
||||
|
||||
"##,
|
||||
-height/4.,
|
||||
-height/2. -30.,
|
||||
-height/2. -15.,
|
||||
|
||||
height/4.,
|
||||
height/2. - 30.,
|
||||
height/2. - 15.,
|
||||
|
||||
height/2.
|
||||
));
|
||||
|
||||
map_group_svg.push_str(r##"</g>"##);
|
||||
|
||||
edges.push(Edge {
|
||||
src_id: format!("type-{}-{}", &self.nameprefix, self.i),
|
||||
dst_id: format!("type-{}-{}", &self.nameprefix, self.i+1),
|
||||
label: map_group_svg,
|
||||
width: members_extent.end.0 - members_extent.begin.0,
|
||||
height: members_extent.end.1 - members_extent.begin.1
|
||||
});
|
||||
|
||||
self.i += 1;
|
||||
self.extent = Extent::max(&self.extent, &members_extent.offset(self.pos));
|
||||
|
||||
self.pos.0 += 400.;
|
||||
self.pos.1 += members_extent.end.1 - members_extent.begin.1 + 500.;
|
||||
|
||||
self.add_type(nodes, Γ0, ψ.clone(), inst.get_type().dst_type);
|
||||
|
||||
self.pos.0 += ( members_extent.end.0 - members_extent.begin.0 );
|
||||
},
|
||||
MorphismInstance::MapEnum { enum_repr, variant_morph } => {
|
||||
todo!()
|
||||
},
|
||||
}
|
||||
Γ0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl VisualizationPane for MorphinstVizPane {
|
||||
fn id(&self) -> String {
|
||||
format!("morph-{}", self.name.clone())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> String {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
fn svg(&self) -> String {
|
||||
self.svg.clone().unwrap_or(String::new())
|
||||
}
|
||||
}
|
443
src/viz/search_pane.rs
Normal file
443
src/viz/search_pane.rs
Normal file
|
@ -0,0 +1,443 @@
|
|||
use std::collections::HashMap;
|
||||
use std::f32::consts::TAU;
|
||||
use std::ops::Deref;
|
||||
|
||||
use laddertypes::search_node::SearchNodeExt;
|
||||
use laddertypes::{unparser::*, AddressingMode, Context, ContextPtr, EnumVariant, GraphSearch, HashMapSubst, LayeredContext, Morphism, MorphismInstance, StructMember, TypeDict, TypeTerm};
|
||||
|
||||
use crate::morphism::LdmcPrimMorph;
|
||||
use crate::viz::{type_to_svg, unparse_type_to_svg, VisualizationPane};
|
||||
|
||||
pub struct Edge {
|
||||
src_id: String,
|
||||
dst_id: String,
|
||||
label: String,
|
||||
width: f32,
|
||||
height: f32
|
||||
}
|
||||
|
||||
pub struct Node {
|
||||
id_str: String,
|
||||
pos: (f32, f32),
|
||||
ctx: ContextPtr,
|
||||
ψ: TypeTerm,
|
||||
τ: TypeTerm,
|
||||
}
|
||||
|
||||
pub struct SearchPane {
|
||||
ctx: ContextPtr,
|
||||
name: String,//todo: displayname + ID
|
||||
svg: Option< String >,
|
||||
extent: Extent,
|
||||
|
||||
subnames: Vec<String>,
|
||||
}
|
||||
|
||||
impl SearchPane {
|
||||
pub fn new( ctx: ContextPtr, name: String ) -> Self {
|
||||
SearchPane { name, ctx, svg: None, subnames: vec![ ], extent: Extent::empty() }
|
||||
}
|
||||
|
||||
pub fn get_subnames(&self) -> Vec<String> {
|
||||
self.subnames.clone()
|
||||
}
|
||||
|
||||
pub fn get_extent(&self) -> Extent {
|
||||
self.extent.clone()
|
||||
}
|
||||
|
||||
pub fn build_module_group(&mut self,
|
||||
svg: &mut String,
|
||||
pos: (f32, f32),
|
||||
graph_search: &GraphSearch<LdmcPrimMorph>
|
||||
) {
|
||||
let mut layout = Layout::new(self.name.clone());
|
||||
let mut nodes = Vec::new();
|
||||
let mut edges :Vec<Edge> = Vec::new();
|
||||
|
||||
self.subnames.push(format!("module-{}",self.name.clone()));
|
||||
layout.add_graph_search(&mut nodes, &mut edges, &mut self.subnames, graph_search);
|
||||
|
||||
self.extent = layout.extent.clone();
|
||||
|
||||
// add some padding
|
||||
self.extent.begin.0 -= 100.0;
|
||||
self.extent.begin.1 -= 100.0;
|
||||
self.extent.end.0 += 100.0;
|
||||
self.extent.end.1 += 100.0;
|
||||
|
||||
svg.push_str(&format!(r##"
|
||||
<g id="mod-{}" class="draggable" transform="translate({}, {})">
|
||||
<rect x="{}" y="{}" width="{}" height="{}" class="module-bg-{}" />
|
||||
|
||||
<!-- Module Label -->
|
||||
<text
|
||||
class="module-label module-{}"
|
||||
id="module-{}"
|
||||
text-anchor="left"
|
||||
>
|
||||
{}
|
||||
</text>
|
||||
|
||||
<!-- Nodes in module Group -->
|
||||
|
||||
"##, self.name, pos.0, pos.1,
|
||||
self.extent.begin.0, self.extent.begin.1,
|
||||
self.extent.end.0 - self.extent.begin.0, self.extent.end.1 - self.extent.begin.1,
|
||||
self.name, self.name, self.name, self.display_name()));
|
||||
|
||||
for n in nodes.iter() {
|
||||
svg.push_str(&format!(r##"<g id="{}" class="draggable type-node" transform="translate({},{})" width=200 height=100 >"##,
|
||||
n.id_str,
|
||||
n.pos.0,
|
||||
n.pos.1
|
||||
));
|
||||
|
||||
svg.push_str(&format!(r##"<rect class="node-box module-{}" x="0" y="0" width=800 height=200 />"##, self.name));
|
||||
svg.push_str(r##"<text x="50" y="80">"##);
|
||||
svg.push_str(&unparse_type_to_svg(&mut n.ctx.clone(), &n.ψ.clone().apply_subst(&n.ctx).clone()));
|
||||
svg.push_str(r##"</text>"##);
|
||||
|
||||
svg.push_str(r##"<text x="50" y="150">"##);
|
||||
if !n.ψ.is_empty() {
|
||||
svg.push_str(r##"<tspan class="infix">~</tspan>"##);
|
||||
}
|
||||
svg.push_str(&unparse_type_to_svg(&mut n.ctx.clone(), &n.τ.clone().apply_subst(&n.ctx).clone()));
|
||||
|
||||
svg.push_str(r##"</text>"##);
|
||||
svg.push_str(r##"</g>"##);
|
||||
}
|
||||
|
||||
svg.push_str(r##"</g>"##);
|
||||
|
||||
|
||||
for e in edges.iter() {
|
||||
svg.push_str(&format!(r##"
|
||||
<line class="arrow arrow3" data-source="{}" data-target="{}" />
|
||||
<g class="edge-label" data-source="{}" data-target="{}">
|
||||
<g class="draggable" transform="translate({},{})" >
|
||||
{}
|
||||
</g>
|
||||
</g>
|
||||
"##, e.src_id, e.dst_id, e.src_id, e.dst_id, 0.0, -e.height/2., e.label));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn build_svg(&mut self, graph_search: &GraphSearch<LdmcPrimMorph>) {
|
||||
let mut svg = String::new();
|
||||
svg.push_str(&format!(r##"
|
||||
<svg id="{}">
|
||||
<defs>
|
||||
<marker
|
||||
id="arrowhead3"
|
||||
markerWidth="10"
|
||||
markerHeight="7"
|
||||
refX="10"
|
||||
refY="3.5"
|
||||
orient="auto"
|
||||
markerUnits="strokeWidth"
|
||||
>
|
||||
<polygon points="0 0, 10 3.5, 0 7" fill="#555" />
|
||||
</marker>
|
||||
</defs>
|
||||
"##, self.id()));
|
||||
|
||||
svg.push_str(r##"<g id="canvasGroup" transform="translate(0,0) scale(1)">"##);
|
||||
self.build_module_group(&mut svg, (0.0, 0.0), graph_search);
|
||||
|
||||
svg.push_str(r##"</g>"##);
|
||||
svg.push_str(r##"</svg>"##);
|
||||
|
||||
self.svg = Some(svg);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Extent {
|
||||
begin: (f32, f32),
|
||||
end: (f32, f32)
|
||||
}
|
||||
|
||||
impl Extent {
|
||||
fn empty() -> Self {
|
||||
Extent {
|
||||
begin: (0.,0.),
|
||||
end: (0.,0.)
|
||||
}
|
||||
}
|
||||
fn max(e1: &Extent, e2: &Extent) -> Self {
|
||||
Extent {
|
||||
begin: (f32::min(e1.begin.0, e2.begin.0), f32::min(e1.begin.1, e2.begin.1)),
|
||||
end: (f32::max(e1.end.0, e2.end.0), f32::max(e1.end.1, e2.end.1))
|
||||
}
|
||||
}
|
||||
fn offset(&self, offset: (f32, f32)) -> Self {
|
||||
Extent {
|
||||
begin: (self.begin.0 + offset.0, self.begin.1 + offset.1),
|
||||
end: (self.end.0 + offset.0, self.end.1 + offset.1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LayoutNodeProperties {
|
||||
pos: (f32, f32),
|
||||
angle: f32,
|
||||
next_child_angle: f32
|
||||
}
|
||||
|
||||
pub struct Layout {
|
||||
i: u32,
|
||||
positions: HashMap<u64, LayoutNodeProperties>,
|
||||
nameprefix: String,
|
||||
|
||||
extent: Extent
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
pub fn new(nameprefix: String) -> Self {
|
||||
Layout {
|
||||
i: 0,
|
||||
positions: HashMap::new(),
|
||||
nameprefix,
|
||||
extent: Extent::empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_type(
|
||||
&mut self,
|
||||
nodes: &mut Vec<Node>,
|
||||
ctx: &ContextPtr,
|
||||
ψ: TypeTerm,
|
||||
mut τ: TypeTerm,
|
||||
id_str: String,
|
||||
pos: (f32, f32)
|
||||
)
|
||||
{
|
||||
τ.apply_subst(ctx);
|
||||
nodes.push(Node {
|
||||
id_str,
|
||||
pos,
|
||||
ctx: ctx.clone(),
|
||||
ψ, τ
|
||||
});
|
||||
|
||||
self.extent = Extent::max(&self.extent, &Extent { begin: (0., 0.), end: (600.0, 400.0) }.offset(pos));
|
||||
}
|
||||
|
||||
pub fn sub_layout(&self, pfx: String, yoff: f32) -> Self {
|
||||
Layout {
|
||||
i: 0,
|
||||
nameprefix: format!("{}-{}", self.nameprefix, pfx),
|
||||
positions: HashMap::new(),
|
||||
extent: Extent::empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_graph_search(
|
||||
&mut self,
|
||||
nodes: &mut Vec<Node>,
|
||||
edges: &mut Vec<Edge>,
|
||||
subnames: &mut Vec<String>,
|
||||
|
||||
search: &GraphSearch<LdmcPrimMorph>
|
||||
) -> ContextPtr {
|
||||
let mut angle = 0.0;
|
||||
for node in search.history.iter() {
|
||||
let n = node.read().unwrap();
|
||||
|
||||
let mut path_len = 0;
|
||||
{
|
||||
let mut cur_node = Some(node.clone());
|
||||
while let Some(n) = cur_node.clone() {
|
||||
cur_node = n.read().unwrap().pred.clone();
|
||||
path_len += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let pos =
|
||||
if let Some(parent) = n.pred.as_ref() {
|
||||
let parent = parent.read().unwrap();
|
||||
let parent_prop = self.positions.get_mut( &parent.id ).unwrap();
|
||||
let angle = parent_prop.next_child_angle;
|
||||
parent_prop.next_child_angle +=
|
||||
0.35 *(1.5 / (path_len as f32)) * TAU;
|
||||
|
||||
let dist = 800.0 + 2000.0* (2.0/(1.0+2.0*path_len as f32));
|
||||
(
|
||||
parent_prop.pos.0 + dist*f32::cos(angle),
|
||||
parent_prop.pos.1 + dist*f32::sin(angle),
|
||||
)
|
||||
} else {
|
||||
(0.0, 0.0)
|
||||
};
|
||||
|
||||
self.extent.begin.0 = f32::min( self.extent.begin.0, pos.0 );
|
||||
self.extent.begin.1 = f32::min( self.extent.begin.1, pos.1 );
|
||||
self.extent.end.0 = f32::max( self.extent.end.0, pos.0 );
|
||||
self.extent.end.1 = f32::max( self.extent.end.1, pos.1 );
|
||||
|
||||
self.positions.insert( n.id, LayoutNodeProperties { pos, angle, next_child_angle:angle } );
|
||||
|
||||
let mut σ_str = "σ = {".to_string();
|
||||
|
||||
for (v,t) in n.ctx.0.read().unwrap().σ.iter() {
|
||||
σ_str.push_str(&format!("{} -> {}",
|
||||
n.ctx.get_varname(*v).unwrap_or("??".into()),
|
||||
unparse_type_to_svg(&mut n.ctx.clone(), &t)));
|
||||
}
|
||||
|
||||
σ_str.push_str("}");
|
||||
|
||||
let ψ_str =
|
||||
if n.ψ.is_empty() {
|
||||
"ψ = ε".into()
|
||||
} else {
|
||||
let mut ψ = n.ψ.clone();
|
||||
ψ.apply_subst(&n.ctx);
|
||||
format!("ψ = {}", unparse_type_to_svg(&mut n.ctx.clone(), &ψ))
|
||||
};
|
||||
|
||||
let node_id = format!("{}-{}", self.nameprefix, n.id);
|
||||
|
||||
match &n.step {
|
||||
laddertypes::search_node::Step::Id { τ:_ } |
|
||||
laddertypes::search_node::Step::Prim { σs:_, m:_ } => {
|
||||
self.add_type(
|
||||
nodes,
|
||||
&n.ctx,
|
||||
n.ψ.clone(),
|
||||
node.read().unwrap().ty.dst_type.clone(),
|
||||
node_id.clone(),
|
||||
pos
|
||||
);
|
||||
},
|
||||
laddertypes::search_node::Step::MapSeq { seq_repr, item } => {
|
||||
self.add_type(
|
||||
nodes,
|
||||
&n.ctx,
|
||||
n.ψ.clone(),
|
||||
TypeTerm::Seq { seq_repr: seq_repr.clone(), item: Box::new(item.goal.dst_type.clone()) },
|
||||
node_id.clone(),
|
||||
pos
|
||||
);
|
||||
},
|
||||
laddertypes::search_node::Step::MapStruct { struct_repr, members } => {
|
||||
self.add_type(
|
||||
nodes,
|
||||
&n.ctx,
|
||||
n.ψ.clone(),
|
||||
TypeTerm::Struct {
|
||||
struct_repr: struct_repr.clone(),
|
||||
members: members.iter().map(|(symbol,search)|
|
||||
StructMember{ symbol:symbol.clone(), ty: search.goal.dst_type.clone() }
|
||||
).collect()
|
||||
},
|
||||
node_id.clone(),
|
||||
pos
|
||||
);
|
||||
},
|
||||
laddertypes::search_node::Step::MapEnum { enum_repr, variants } => {
|
||||
self.add_type(
|
||||
nodes,
|
||||
&n.ctx,
|
||||
n.ψ.clone(),
|
||||
TypeTerm::Enum {
|
||||
enum_repr: enum_repr.clone(),
|
||||
variants: variants.iter().map(|(symbol,search)|
|
||||
EnumVariant{ symbol:symbol.clone(), ty: search.goal.dst_type.clone() }
|
||||
).collect()
|
||||
},
|
||||
node_id.clone(),
|
||||
pos
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
if let Some(parent) = n.pred.as_ref() {
|
||||
|
||||
let label = match &n.step {
|
||||
laddertypes::search_node::Step::Id { τ } => "<text>Id</text>".into(),
|
||||
laddertypes::search_node::Step::Prim { σs, m } => {
|
||||
format!(r##"
|
||||
<text y="-80" class="halo" text-anchor="center">{}</text>
|
||||
<text y="0" class="morph-name" text-anchor="center" >{}</text>
|
||||
<text y="80" class="Γ" text-anchor="center">{}</text>
|
||||
"##, ψ_str, m.symbol, σ_str)
|
||||
},
|
||||
laddertypes::search_node::Step::MapSeq { seq_repr, item } => {
|
||||
let label = format!("{}-MapSeq-{}-{}", self.nameprefix, parent.read().unwrap().id, n.id);
|
||||
let mut map_pane = SearchPane::new(n.ctx.clone(), label.clone());
|
||||
let mut svg = String::new();
|
||||
subnames.push(label);
|
||||
map_pane.build_module_group(&mut svg, (0.0, 0.0), item);
|
||||
subnames.append(&mut map_pane.get_subnames());
|
||||
self.extent = Extent::max(&self.extent, &map_pane.get_extent().offset(pos));
|
||||
svg
|
||||
},
|
||||
laddertypes::search_node::Step::MapStruct { struct_repr, members } => {
|
||||
let mut svg = String::new();
|
||||
let mut members_extent = Extent::empty();
|
||||
let mut local_pos = (0.,0.);
|
||||
for (symbol, search) in members.iter() {
|
||||
let label = format!("{}-MapStruct-{}-{}-{}", self.nameprefix, symbol, parent.read().unwrap().id, n.id);
|
||||
let mut member_pane = SearchPane::new(n.ctx.clone(), label.clone());
|
||||
subnames.push(label);
|
||||
member_pane.build_module_group(&mut svg, local_pos, search);
|
||||
subnames.append(&mut member_pane.get_subnames());
|
||||
|
||||
members_extent = Extent::max(&members_extent, &member_pane.get_extent().offset(local_pos));
|
||||
local_pos.1 += member_pane.get_extent().end.1 - member_pane.get_extent().begin.1;
|
||||
local_pos.1 += 200.0; // padding
|
||||
}
|
||||
self.extent = Extent::max(&self.extent, &members_extent.offset(pos));
|
||||
svg
|
||||
},
|
||||
laddertypes::search_node::Step::MapEnum { enum_repr, variants } => {
|
||||
let mut svg = String::new();
|
||||
let mut variants_extent = Extent::empty();
|
||||
let mut local_pos = (0.,0.);
|
||||
for (symbol, search) in variants.iter() {
|
||||
let label = format!("{}-MapEnum-{}-{}-{}", self.nameprefix, symbol, parent.read().unwrap().id, n.id);
|
||||
let mut variant_pane = SearchPane::new(n.ctx.clone(), label.clone());
|
||||
subnames.push(label);
|
||||
variant_pane.build_module_group(&mut svg, local_pos, search);
|
||||
subnames.append(&mut variant_pane.get_subnames());
|
||||
|
||||
variants_extent = Extent::max(&variants_extent, &variant_pane.get_extent().offset(local_pos));
|
||||
local_pos.1 += variant_pane.get_extent().end.1 - variant_pane.get_extent().begin.1;
|
||||
local_pos.1 += 200.0; // padding
|
||||
}
|
||||
self.extent = Extent::max(&self.extent, &variants_extent.offset(pos));
|
||||
svg
|
||||
}
|
||||
};
|
||||
|
||||
edges.push(Edge {
|
||||
src_id: format!("{}-{}", self.nameprefix, parent.read().unwrap().id),
|
||||
dst_id: node_id,
|
||||
label,
|
||||
width: 0.0,
|
||||
height: 0.,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Context::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl VisualizationPane for SearchPane {
|
||||
fn id(&self) -> String {
|
||||
format!("search-{}", self.name.clone())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> String {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
fn svg(&self) -> String {
|
||||
self.svg.clone().unwrap_or(String::new())
|
||||
}
|
||||
}
|
314
src/viz/theme.rs
Normal file
314
src/viz/theme.rs
Normal file
|
@ -0,0 +1,314 @@
|
|||
use crate::viz::Visualization;
|
||||
|
||||
fn generate_color(index: usize, total: usize) -> String {
|
||||
let hue = (360.0 * (index as f32 / total as f32)) as u16;
|
||||
let saturation = 60;
|
||||
|
||||
// Base lightness
|
||||
let mut lightness = 50;
|
||||
|
||||
// Increase lightness for violet hues (260° - 320°)
|
||||
if (260..=320).contains(&hue) {
|
||||
lightness = 65; // lighter for better contrast on dark bg
|
||||
}
|
||||
|
||||
format!("hsl({}, {}%, {}%)", hue, saturation, lightness)
|
||||
}
|
||||
|
||||
fn generate_css_theme(identifiers: &Vec<String>) -> String {
|
||||
let total = identifiers.len();
|
||||
let mut css = String::new();
|
||||
|
||||
for (i, ident) in identifiers.iter().enumerate() {
|
||||
let color = generate_color(i, total);
|
||||
css.push_str(&format!(r##"
|
||||
rect.module-bg-{ident}, circle.module-bg-{ident} {{
|
||||
stroke: {color};
|
||||
fill: {color};
|
||||
opacity: 0.4;
|
||||
filter: saturate(10%) blur(50px);
|
||||
}}
|
||||
text.module-{ident} {{
|
||||
fill: {color};
|
||||
stroke-width: 0.5;
|
||||
}}
|
||||
#mod-{ident} path {{
|
||||
stroke: {color};
|
||||
pointer-events: none;
|
||||
}}
|
||||
#mod-{ident} rect.struct-bg {{
|
||||
opacity: 0.5;
|
||||
fill: {color};
|
||||
filter: brightness(85%) saturate(20%) blur(150px);
|
||||
}}
|
||||
body.dark text.module-{ident} {{
|
||||
stroke: #ddd;
|
||||
}}
|
||||
body.light text.module-{ident} {{
|
||||
stroke: #555;
|
||||
}}
|
||||
"##));
|
||||
}
|
||||
|
||||
css
|
||||
}
|
||||
|
||||
|
||||
impl Visualization {
|
||||
|
||||
pub fn style(&self) -> String {
|
||||
let mut css = String::new();
|
||||
|
||||
css.push_str(r##"<style>
|
||||
/* Page */
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
#themeToggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#themeToggle input {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Light Theme */
|
||||
body.light {
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
body.light svg {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
body.light #toolbar {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
body.light select {
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
body.light button {
|
||||
background-color: #007acc;
|
||||
color: white;
|
||||
}
|
||||
|
||||
body.light button:hover {
|
||||
background-color: #005fa3;
|
||||
}
|
||||
|
||||
/* Dark Theme */
|
||||
body.dark {
|
||||
background: #121212;
|
||||
}
|
||||
|
||||
body.dark svg {
|
||||
background-color: #353535;
|
||||
}
|
||||
|
||||
body.dark #toolbar {
|
||||
background-color: #2b2b2b;
|
||||
}
|
||||
|
||||
body.dark select {
|
||||
background-color: #444;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark button {
|
||||
background-color: #569cd6;
|
||||
color: white;
|
||||
}
|
||||
|
||||
body.dark button:hover {
|
||||
background-color: #4a90c2;
|
||||
}
|
||||
|
||||
|
||||
/* SVG */
|
||||
svg {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
text {
|
||||
font-family: sans-serif;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
line.arrow {
|
||||
stroke: #111;
|
||||
stroke-width: 4;
|
||||
marker-end: url(#arrowhead);
|
||||
pointer-events: none;
|
||||
}
|
||||
line.arrow2 {
|
||||
stroke-width: 8;
|
||||
marker-end: url(#arrowhead2);
|
||||
pointer-events: none;
|
||||
}
|
||||
line.arrow3 {
|
||||
stroke-width: 8;
|
||||
marker-end: url(#arrowhead3);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Nodes */
|
||||
.node-box {
|
||||
fill: #444;
|
||||
stroke: #333;
|
||||
stroke-width: 1.5;
|
||||
rx: 6;
|
||||
ry: 6;
|
||||
pointer-events: all;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
body.light .node-box {
|
||||
fill: #eee;
|
||||
}
|
||||
|
||||
.draggable {
|
||||
cursor: grab;
|
||||
transition: transform 0.5s ease-in-out;
|
||||
}
|
||||
.draggable:active {
|
||||
transition: none !important;
|
||||
}
|
||||
.edge-label {
|
||||
font-size: 32px;
|
||||
fill: darkblue;
|
||||
pointer-events: none;
|
||||
}
|
||||
.module-label {
|
||||
font-weight: bold;
|
||||
font-size: 80px;
|
||||
fill: #222;
|
||||
pointer-events: none;
|
||||
}
|
||||
line.arrow {
|
||||
stroke: #777;
|
||||
stroke-width: 2;
|
||||
marker-end: url(#arrowhead);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.morph-edge-label {
|
||||
font-size: 42px;
|
||||
font-family: monospace;
|
||||
fill: darkblue;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Types */
|
||||
.halo {
|
||||
font-size: 48px;
|
||||
}
|
||||
.Γ {
|
||||
font-size: 48px;
|
||||
}
|
||||
.morph-name {
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
}
|
||||
.infix, .bracket {
|
||||
fill: #754000;
|
||||
font-size: 64px;
|
||||
}
|
||||
.type {
|
||||
fill: cadetblue;
|
||||
font-size: 48px;
|
||||
}
|
||||
.typevar {
|
||||
fill: #9cdcfe;
|
||||
font-size: 48px;
|
||||
font-style: smallcaps;
|
||||
fill: #bbb;
|
||||
}
|
||||
.value {
|
||||
fill: green;
|
||||
font-size: 48px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.complex-opening {
|
||||
font-size: 200px;
|
||||
}
|
||||
|
||||
|
||||
.type-box {
|
||||
stroke: #777;
|
||||
}
|
||||
|
||||
.type-node .type {
|
||||
}
|
||||
.type-node .typevar {
|
||||
font-family: monospace;
|
||||
}
|
||||
.type-node .infix,
|
||||
.type-node .bracket {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Toolbar */
|
||||
#toolbar {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 1000;
|
||||
border-radius: 8px;
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
#toolbar select,
|
||||
#toolbar button,
|
||||
#toolbar label {
|
||||
font-size: 14px;
|
||||
padding: 6px 10px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
transition: background 0.3s ease, color 0.3s ease;
|
||||
}
|
||||
|
||||
#toolbar select {
|
||||
background-color: #444;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#toolbar button {
|
||||
background-color: #569cd6;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#toolbar button:hover {
|
||||
background-color: #4a90c2;
|
||||
}
|
||||
|
||||
#themeToggle {
|
||||
background: #333;
|
||||
}
|
||||
"##);
|
||||
|
||||
css.push_str(&generate_css_theme(&self.modules));
|
||||
css.push_str(r##"</style>"##);
|
||||
css
|
||||
}
|
||||
}
|
110
src/viz/type_to_svg.rs
Normal file
110
src/viz/type_to_svg.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use laddertypes::{TypeTerm, TypeID, TypeDict};
|
||||
|
||||
pub fn unparse_type_to_svg(
|
||||
dict: &mut impl TypeDict,
|
||||
t: &TypeTerm
|
||||
) -> String {
|
||||
match t {
|
||||
TypeTerm::Char(c) => {
|
||||
format!(r##"
|
||||
<tspan class="value">'{}'</tspan>
|
||||
"##, c)
|
||||
}
|
||||
TypeTerm::Num(n) => {
|
||||
format!(r##"
|
||||
<tspan class="value">{}</tspan>
|
||||
"##, n)
|
||||
}
|
||||
TypeTerm::Id(id) => {
|
||||
format!(r##"
|
||||
<tspan class="type">{}</tspan>
|
||||
"##, dict.get_typename(*id).unwrap_or("?".into()))
|
||||
}
|
||||
TypeTerm::Var(var_id) => {
|
||||
format!(r##"
|
||||
<tspan class="typevar">{}</tspan>
|
||||
"##, dict.get_varname(*var_id).unwrap_or("?".into()))
|
||||
}
|
||||
TypeTerm::Spec(args) => {
|
||||
let mut s = String::new();
|
||||
|
||||
s.push_str(&r##"<tspan class="bracket">⟨</tspan>"##);
|
||||
|
||||
for a in args.iter() {
|
||||
s.push_str(&unparse_type_to_svg(dict, a));
|
||||
s.push_str(" ");
|
||||
}
|
||||
|
||||
s.push_str(&r##"<tspan class="bracket">⟩</tspan>"##);
|
||||
|
||||
s
|
||||
}
|
||||
TypeTerm::Func(args) => {
|
||||
let mut s = String::new();
|
||||
|
||||
for (i,a) in args.iter().enumerate() {
|
||||
s.push_str(&unparse_type_to_svg(dict, a));
|
||||
|
||||
if i+1 != args.len() {
|
||||
s.push_str(&r##"<tspan class="arrow">⟶</tspan>"##);
|
||||
}
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
TypeTerm::Seq { seq_repr, item } => {
|
||||
let mut s = String::new();
|
||||
s.push_str(&r##"<tspan class="bracket">[</tspan>"##);
|
||||
|
||||
if let Some(r) = seq_repr {
|
||||
s.push_str(&r##"<tspan class="infix">~</tspan>"##);
|
||||
s.push_str(&unparse_type_to_svg(dict, r));
|
||||
}
|
||||
|
||||
s.push_str(&unparse_type_to_svg(dict, item.deref()));
|
||||
|
||||
s.push_str(&r##"<tspan class="bracket">]</tspan>"##);
|
||||
s
|
||||
}
|
||||
TypeTerm::Struct { struct_repr, members } => {
|
||||
let mut s = String::new();
|
||||
s.push_str(&r##"<tspan class="bracket">{</tspan>"##);
|
||||
|
||||
if let Some(r) = struct_repr {
|
||||
s.push_str(&r##"<tspan class="infix">~</tspan>"##);
|
||||
s.push_str(&unparse_type_to_svg(dict, r));
|
||||
}
|
||||
|
||||
for m in members.iter() {
|
||||
s.push_str(&format!(r##"
|
||||
<tspan class="typevar">{}</tspan>
|
||||
<tspan class="infix">:</tspan>
|
||||
{}
|
||||
<tspan class="infix">;</tspan>
|
||||
"##,
|
||||
m.symbol,
|
||||
unparse_type_to_svg(dict, &m.ty)
|
||||
));
|
||||
}
|
||||
|
||||
s.push_str(&r##"<tspan class="bracket">}</tspan>"##);
|
||||
s
|
||||
}
|
||||
TypeTerm::Ladder(rungs) => {
|
||||
let mut s = String::new();
|
||||
|
||||
for (i,a) in rungs.iter().enumerate() {
|
||||
s.push_str(&unparse_type_to_svg(dict, a));
|
||||
|
||||
if i+1 != rungs.len() {
|
||||
s.push_str(&r##"<tspan class="infix">~</tspan>"##);
|
||||
}
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
_ => { "".into() }
|
||||
}
|
||||
}
|
|
@ -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})"
|
||||
|
||||
|
|
76
todo.md
Normal file
76
todo.md
Normal file
|
@ -0,0 +1,76 @@
|
|||
* 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
|
Loading…
Add table
Add a link
Reference in a new issue