tranfi 0.0.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +395 -0
- package/app/assets/index-6quYZ5Ap.css +5 -0
- package/app/assets/index-pDFMluyz.js +160 -0
- package/app/assets/materialdesignicons-webfont-B7mPwVP_.ttf +0 -0
- package/app/assets/materialdesignicons-webfont-CSr8KVlo.eot +0 -0
- package/app/assets/materialdesignicons-webfont-Dp5v-WZN.woff2 +0 -0
- package/app/assets/materialdesignicons-webfont-PXm3-2wK.woff +0 -0
- package/app/index.html +13 -0
- package/binding.gyp +69 -0
- package/csrc/arena.c +91 -0
- package/csrc/batch.c +229 -0
- package/csrc/buffer.c +78 -0
- package/csrc/cJSON.c +3143 -0
- package/csrc/cJSON.h +300 -0
- package/csrc/codec_csv.c +1058 -0
- package/csrc/codec_jsonl.c +374 -0
- package/csrc/codec_table.c +218 -0
- package/csrc/codec_text.c +229 -0
- package/csrc/compiler.c +102 -0
- package/csrc/date_utils.h +94 -0
- package/csrc/dsl.c +1180 -0
- package/csrc/dsl.h +22 -0
- package/csrc/expr.c +1245 -0
- package/csrc/expr.h +56 -0
- package/csrc/internal.h +250 -0
- package/csrc/ir.c +119 -0
- package/csrc/ir.h +167 -0
- package/csrc/ir_schema.c +60 -0
- package/csrc/ir_serialize.c +104 -0
- package/csrc/ir_sql.c +1211 -0
- package/csrc/ir_validate.c +120 -0
- package/csrc/main.c +392 -0
- package/csrc/op_acf.c +133 -0
- package/csrc/op_anomaly.c +120 -0
- package/csrc/op_bin.c +109 -0
- package/csrc/op_cast.c +195 -0
- package/csrc/op_clip.c +88 -0
- package/csrc/op_date_trunc.c +181 -0
- package/csrc/op_datetime.c +212 -0
- package/csrc/op_derive.c +248 -0
- package/csrc/op_diff.c +134 -0
- package/csrc/op_ewma.c +103 -0
- package/csrc/op_explode.c +108 -0
- package/csrc/op_fill_down.c +163 -0
- package/csrc/op_fill_null.c +123 -0
- package/csrc/op_filter.c +132 -0
- package/csrc/op_frequency.c +193 -0
- package/csrc/op_grep.c +163 -0
- package/csrc/op_group_agg.c +285 -0
- package/csrc/op_hash.c +126 -0
- package/csrc/op_head.c +149 -0
- package/csrc/op_interpolate.c +239 -0
- package/csrc/op_join.c +384 -0
- package/csrc/op_label_encode.c +144 -0
- package/csrc/op_lead.c +190 -0
- package/csrc/op_normalize.c +226 -0
- package/csrc/op_onehot.c +185 -0
- package/csrc/op_pivot.c +370 -0
- package/csrc/op_registry.c +1148 -0
- package/csrc/op_rename.c +138 -0
- package/csrc/op_replace.c +202 -0
- package/csrc/op_sample.c +101 -0
- package/csrc/op_select.c +140 -0
- package/csrc/op_skip.c +152 -0
- package/csrc/op_sort.c +273 -0
- package/csrc/op_split.c +114 -0
- package/csrc/op_split_data.c +87 -0
- package/csrc/op_stack.c +315 -0
- package/csrc/op_stats.c +779 -0
- package/csrc/op_step.c +171 -0
- package/csrc/op_tail.c +96 -0
- package/csrc/op_top.c +150 -0
- package/csrc/op_trim.c +109 -0
- package/csrc/op_unique.c +300 -0
- package/csrc/op_unpivot.c +159 -0
- package/csrc/op_validate.c +71 -0
- package/csrc/op_window.c +150 -0
- package/csrc/pipeline.c +315 -0
- package/csrc/plan.c +206 -0
- package/csrc/recipes.c +102 -0
- package/csrc/recipes.h +27 -0
- package/csrc/report.c +463 -0
- package/csrc/report.h +22 -0
- package/csrc/tranfi.h +123 -0
- package/csrc/wasm_api.c +157 -0
- package/napi_api.c +326 -0
- package/package.json +46 -57
- package/src/cli.js +193 -0
- package/src/engines/duckdb.js +109 -0
- package/src/index.js +306 -0
- package/src/native.js +22 -0
- package/src/pipeline.js +286 -0
- package/src/server.js +277 -0
- package/src/wasm.js +19 -0
- package/wasm/index.js +244 -0
- package/wasm/package.json +1 -0
- package/wasm/tranfi_core.js +0 -0
- package/LICENSE +0 -21
- package/dist/bundle.js +0 -1
- package/index.html +0 -18
- package/logo.png +0 -0
- package/src/app.css +0 -160
- package/src/app.js +0 -203
- package/src/app.vue +0 -253
- package/src/bulma-input.vue +0 -110
- package/src/common-inputs.js +0 -28
- package/src/main.js +0 -18
- package/src/transforms.js +0 -166
- package/webpack.config.js +0 -108
package/csrc/expr.h
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* expr.h — Expression AST types (shared between expr.c and ir_sql.c).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
#ifndef TF_EXPR_H
|
|
6
|
+
#define TF_EXPR_H
|
|
7
|
+
|
|
8
|
+
#include <stdint.h>
|
|
9
|
+
|
|
10
|
+
typedef enum {
|
|
11
|
+
EXPR_LIT_INT,
|
|
12
|
+
EXPR_LIT_FLOAT,
|
|
13
|
+
EXPR_LIT_STR,
|
|
14
|
+
EXPR_COL_REF,
|
|
15
|
+
EXPR_CMP,
|
|
16
|
+
EXPR_AND,
|
|
17
|
+
EXPR_OR,
|
|
18
|
+
EXPR_NOT,
|
|
19
|
+
EXPR_ADD,
|
|
20
|
+
EXPR_SUB,
|
|
21
|
+
EXPR_MUL,
|
|
22
|
+
EXPR_DIV,
|
|
23
|
+
EXPR_NEG,
|
|
24
|
+
EXPR_FUNC_CALL,
|
|
25
|
+
} expr_kind;
|
|
26
|
+
|
|
27
|
+
typedef enum {
|
|
28
|
+
CMP_GT, CMP_GE, CMP_LT, CMP_LE, CMP_EQ, CMP_NE,
|
|
29
|
+
} cmp_op;
|
|
30
|
+
|
|
31
|
+
struct tf_expr {
|
|
32
|
+
expr_kind kind;
|
|
33
|
+
union {
|
|
34
|
+
int64_t lit_int;
|
|
35
|
+
double lit_float;
|
|
36
|
+
char *lit_str;
|
|
37
|
+
char *col_name; /* for EXPR_COL_REF */
|
|
38
|
+
struct { /* for EXPR_CMP */
|
|
39
|
+
struct tf_expr *left;
|
|
40
|
+
struct tf_expr *right;
|
|
41
|
+
cmp_op op;
|
|
42
|
+
} cmp;
|
|
43
|
+
struct { /* for EXPR_AND, EXPR_OR, EXPR_ADD, EXPR_SUB, EXPR_MUL, EXPR_DIV */
|
|
44
|
+
struct tf_expr *left;
|
|
45
|
+
struct tf_expr *right;
|
|
46
|
+
} binary;
|
|
47
|
+
struct tf_expr *child; /* for EXPR_NOT, EXPR_NEG */
|
|
48
|
+
struct { /* for EXPR_FUNC_CALL */
|
|
49
|
+
char *name;
|
|
50
|
+
struct tf_expr **args;
|
|
51
|
+
int n_args;
|
|
52
|
+
} func;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
#endif /* TF_EXPR_H */
|
package/csrc/internal.h
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* internal.h — Internal types for the Tranfi core.
|
|
3
|
+
* Not part of the public API.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#ifndef TF_INTERNAL_H
|
|
7
|
+
#define TF_INTERNAL_H
|
|
8
|
+
|
|
9
|
+
#include "tranfi.h"
|
|
10
|
+
#include "ir.h"
|
|
11
|
+
#include <stddef.h>
|
|
12
|
+
#include <stdint.h>
|
|
13
|
+
#include <stdbool.h>
|
|
14
|
+
|
|
15
|
+
/* ---- Arena allocator ---- */
|
|
16
|
+
|
|
17
|
+
typedef struct tf_arena_block {
|
|
18
|
+
uint8_t *data;
|
|
19
|
+
size_t used;
|
|
20
|
+
size_t cap;
|
|
21
|
+
struct tf_arena_block *next;
|
|
22
|
+
} tf_arena_block;
|
|
23
|
+
|
|
24
|
+
typedef struct tf_arena {
|
|
25
|
+
tf_arena_block *head;
|
|
26
|
+
tf_arena_block *current;
|
|
27
|
+
size_t block_size; /* default block capacity */
|
|
28
|
+
} tf_arena;
|
|
29
|
+
|
|
30
|
+
tf_arena *tf_arena_create(size_t block_size);
|
|
31
|
+
void *tf_arena_alloc(tf_arena *a, size_t size);
|
|
32
|
+
char *tf_arena_strdup(tf_arena *a, const char *s);
|
|
33
|
+
void tf_arena_reset(tf_arena *a);
|
|
34
|
+
void tf_arena_free(tf_arena *a);
|
|
35
|
+
|
|
36
|
+
/* ---- Growable byte buffer ---- */
|
|
37
|
+
|
|
38
|
+
typedef struct tf_buffer {
|
|
39
|
+
uint8_t *data;
|
|
40
|
+
size_t len; /* bytes written */
|
|
41
|
+
size_t cap; /* allocated capacity */
|
|
42
|
+
size_t read_pos; /* consumer read position */
|
|
43
|
+
} tf_buffer;
|
|
44
|
+
|
|
45
|
+
void tf_buffer_init(tf_buffer *b);
|
|
46
|
+
int tf_buffer_write(tf_buffer *b, const uint8_t *data, size_t len);
|
|
47
|
+
size_t tf_buffer_read(tf_buffer *b, uint8_t *out, size_t len);
|
|
48
|
+
size_t tf_buffer_readable(const tf_buffer *b);
|
|
49
|
+
void tf_buffer_compact(tf_buffer *b);
|
|
50
|
+
int tf_buffer_write_str(tf_buffer *b, const char *s);
|
|
51
|
+
void tf_buffer_free(tf_buffer *b);
|
|
52
|
+
|
|
53
|
+
/* ---- Columnar batch ---- */
|
|
54
|
+
/* (tf_type is defined in ir.h, included above) */
|
|
55
|
+
|
|
56
|
+
typedef struct tf_batch {
|
|
57
|
+
char **col_names; /* array of column name strings (arena-allocated) */
|
|
58
|
+
tf_type *col_types; /* per-column type */
|
|
59
|
+
size_t n_cols;
|
|
60
|
+
size_t n_rows;
|
|
61
|
+
size_t capacity; /* allocated row slots per column */
|
|
62
|
+
void **columns; /* array of typed column arrays */
|
|
63
|
+
uint8_t **nulls; /* null bitmap per column (1 byte per row for simplicity) */
|
|
64
|
+
tf_arena *arena; /* owns all memory for this batch */
|
|
65
|
+
} tf_batch;
|
|
66
|
+
|
|
67
|
+
tf_batch *tf_batch_create(size_t n_cols, size_t capacity);
|
|
68
|
+
int tf_batch_set_schema(tf_batch *b, size_t col, const char *name, tf_type type);
|
|
69
|
+
int tf_batch_ensure_capacity(tf_batch *b, size_t min_rows);
|
|
70
|
+
|
|
71
|
+
/* Set a value in a specific cell. String values are copied into the arena. */
|
|
72
|
+
void tf_batch_set_null(tf_batch *b, size_t row, size_t col);
|
|
73
|
+
void tf_batch_set_bool(tf_batch *b, size_t row, size_t col, bool val);
|
|
74
|
+
void tf_batch_set_int64(tf_batch *b, size_t row, size_t col, int64_t val);
|
|
75
|
+
void tf_batch_set_float64(tf_batch *b, size_t row, size_t col, double val);
|
|
76
|
+
void tf_batch_set_string(tf_batch *b, size_t row, size_t col, const char *val);
|
|
77
|
+
void tf_batch_set_date(tf_batch *b, size_t row, size_t col, int32_t val);
|
|
78
|
+
void tf_batch_set_timestamp(tf_batch *b, size_t row, size_t col, int64_t val);
|
|
79
|
+
|
|
80
|
+
/* Get values from a cell. */
|
|
81
|
+
bool tf_batch_is_null(const tf_batch *b, size_t row, size_t col);
|
|
82
|
+
bool tf_batch_get_bool(const tf_batch *b, size_t row, size_t col);
|
|
83
|
+
int64_t tf_batch_get_int64(const tf_batch *b, size_t row, size_t col);
|
|
84
|
+
double tf_batch_get_float64(const tf_batch *b, size_t row, size_t col);
|
|
85
|
+
const char *tf_batch_get_string(const tf_batch *b, size_t row, size_t col);
|
|
86
|
+
int32_t tf_batch_get_date(const tf_batch *b, size_t row, size_t col);
|
|
87
|
+
int64_t tf_batch_get_timestamp(const tf_batch *b, size_t row, size_t col);
|
|
88
|
+
|
|
89
|
+
/* Find column index by name. Returns -1 if not found. */
|
|
90
|
+
int tf_batch_col_index(const tf_batch *b, const char *name);
|
|
91
|
+
|
|
92
|
+
/* Copy a single row from src to dst batch. */
|
|
93
|
+
int tf_batch_copy_row(tf_batch *dst, size_t dst_row,
|
|
94
|
+
const tf_batch *src, size_t src_row);
|
|
95
|
+
|
|
96
|
+
void tf_batch_free(tf_batch *b);
|
|
97
|
+
|
|
98
|
+
/* ---- Step interface (transforms) ---- */
|
|
99
|
+
|
|
100
|
+
/*
|
|
101
|
+
* Side-channel callback: steps call this to emit data to side channels.
|
|
102
|
+
* Owned by the pipeline and passed to steps during processing.
|
|
103
|
+
*/
|
|
104
|
+
typedef struct tf_side_channels {
|
|
105
|
+
tf_buffer *errors;
|
|
106
|
+
tf_buffer *stats;
|
|
107
|
+
tf_buffer *samples;
|
|
108
|
+
} tf_side_channels;
|
|
109
|
+
|
|
110
|
+
typedef struct tf_step {
|
|
111
|
+
/* Process one input batch, produce zero or one output batch.
|
|
112
|
+
* *out is set to a new batch (caller frees) or NULL if filtered away. */
|
|
113
|
+
int (*process)(struct tf_step *self, tf_batch *in, tf_batch **out,
|
|
114
|
+
tf_side_channels *side);
|
|
115
|
+
/* Flush any buffered state. */
|
|
116
|
+
int (*flush)(struct tf_step *self, tf_batch **out, tf_side_channels *side);
|
|
117
|
+
/* Free all resources. */
|
|
118
|
+
void (*destroy)(struct tf_step *self);
|
|
119
|
+
void *state;
|
|
120
|
+
} tf_step;
|
|
121
|
+
|
|
122
|
+
/* ---- Decoder interface (bytes → batches) ---- */
|
|
123
|
+
|
|
124
|
+
typedef struct tf_decoder {
|
|
125
|
+
/*
|
|
126
|
+
* Decode bytes. May produce 0..N batches.
|
|
127
|
+
* *out is set to a malloc'd array of tf_batch*, *n_out to its length.
|
|
128
|
+
* Caller frees the array and each batch.
|
|
129
|
+
*/
|
|
130
|
+
int (*decode)(struct tf_decoder *self, const uint8_t *data, size_t len,
|
|
131
|
+
tf_batch ***out, size_t *n_out);
|
|
132
|
+
/* Flush remaining data (e.g. last partial line). */
|
|
133
|
+
int (*flush)(struct tf_decoder *self, tf_batch ***out, size_t *n_out);
|
|
134
|
+
void (*destroy)(struct tf_decoder *self);
|
|
135
|
+
void *state;
|
|
136
|
+
} tf_decoder;
|
|
137
|
+
|
|
138
|
+
/* ---- Encoder interface (batches → bytes) ---- */
|
|
139
|
+
|
|
140
|
+
typedef struct tf_encoder {
|
|
141
|
+
/*
|
|
142
|
+
* Encode a batch to bytes. Appends to the provided buffer.
|
|
143
|
+
*/
|
|
144
|
+
int (*encode)(struct tf_encoder *self, tf_batch *in, tf_buffer *out);
|
|
145
|
+
/* Flush any trailing data. */
|
|
146
|
+
int (*flush)(struct tf_encoder *self, tf_buffer *out);
|
|
147
|
+
void (*destroy)(struct tf_encoder *self);
|
|
148
|
+
void *state;
|
|
149
|
+
} tf_encoder;
|
|
150
|
+
|
|
151
|
+
/* ---- Pipeline struct ---- */
|
|
152
|
+
|
|
153
|
+
struct tf_pipeline {
|
|
154
|
+
tf_decoder *decoder;
|
|
155
|
+
tf_step **steps;
|
|
156
|
+
size_t n_steps;
|
|
157
|
+
tf_encoder *encoder;
|
|
158
|
+
tf_buffer output[TF_NUM_CHANNELS];
|
|
159
|
+
tf_side_channels side;
|
|
160
|
+
size_t rows_in;
|
|
161
|
+
size_t rows_out;
|
|
162
|
+
size_t bytes_in;
|
|
163
|
+
size_t bytes_out;
|
|
164
|
+
char *error;
|
|
165
|
+
int finished;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/* ---- Codec constructors (used by plan parser) ---- */
|
|
169
|
+
|
|
170
|
+
typedef struct cJSON cJSON;
|
|
171
|
+
|
|
172
|
+
tf_decoder *tf_csv_decoder_create(const cJSON *args);
|
|
173
|
+
tf_encoder *tf_csv_encoder_create(const cJSON *args);
|
|
174
|
+
tf_decoder *tf_jsonl_decoder_create(const cJSON *args);
|
|
175
|
+
tf_encoder *tf_jsonl_encoder_create(const cJSON *args);
|
|
176
|
+
tf_decoder *tf_text_decoder_create(const cJSON *args);
|
|
177
|
+
tf_encoder *tf_text_encoder_create(const cJSON *args);
|
|
178
|
+
|
|
179
|
+
/* ---- Transform constructors ---- */
|
|
180
|
+
|
|
181
|
+
tf_step *tf_filter_create(const cJSON *args);
|
|
182
|
+
tf_step *tf_select_create(const cJSON *args);
|
|
183
|
+
tf_step *tf_rename_create(const cJSON *args);
|
|
184
|
+
tf_step *tf_head_create(const cJSON *args);
|
|
185
|
+
tf_step *tf_skip_create(const cJSON *args);
|
|
186
|
+
tf_step *tf_derive_create(const cJSON *args);
|
|
187
|
+
tf_step *tf_stats_create(const cJSON *args);
|
|
188
|
+
tf_step *tf_unique_create(const cJSON *args);
|
|
189
|
+
tf_step *tf_sort_create(const cJSON *args);
|
|
190
|
+
tf_step *tf_validate_create(const cJSON *args);
|
|
191
|
+
tf_step *tf_trim_create(const cJSON *args);
|
|
192
|
+
tf_step *tf_fill_null_create(const cJSON *args);
|
|
193
|
+
tf_step *tf_cast_create(const cJSON *args);
|
|
194
|
+
tf_step *tf_clip_create(const cJSON *args);
|
|
195
|
+
tf_step *tf_replace_create(const cJSON *args);
|
|
196
|
+
tf_step *tf_hash_create(const cJSON *args);
|
|
197
|
+
tf_step *tf_bin_create(const cJSON *args);
|
|
198
|
+
tf_step *tf_fill_down_create(const cJSON *args);
|
|
199
|
+
tf_step *tf_step_create(const cJSON *args);
|
|
200
|
+
tf_step *tf_window_create(const cJSON *args);
|
|
201
|
+
tf_step *tf_explode_create(const cJSON *args);
|
|
202
|
+
tf_step *tf_split_create(const cJSON *args);
|
|
203
|
+
tf_step *tf_unpivot_create(const cJSON *args);
|
|
204
|
+
tf_step *tf_tail_create(const cJSON *args);
|
|
205
|
+
tf_step *tf_top_create(const cJSON *args);
|
|
206
|
+
tf_step *tf_sample_create(const cJSON *args);
|
|
207
|
+
tf_step *tf_group_agg_create(const cJSON *args);
|
|
208
|
+
tf_step *tf_frequency_create(const cJSON *args);
|
|
209
|
+
tf_step *tf_datetime_create(const cJSON *args);
|
|
210
|
+
tf_step *tf_grep_create(const cJSON *args);
|
|
211
|
+
tf_step *tf_pivot_create(const cJSON *args);
|
|
212
|
+
tf_step *tf_join_create(const cJSON *args);
|
|
213
|
+
tf_step *tf_stack_create(const cJSON *args);
|
|
214
|
+
tf_step *tf_lead_create(const cJSON *args);
|
|
215
|
+
tf_step *tf_date_trunc_create(const cJSON *args);
|
|
216
|
+
tf_step *tf_onehot_create(const cJSON *args);
|
|
217
|
+
tf_step *tf_label_encode_create(const cJSON *args);
|
|
218
|
+
tf_step *tf_ewma_create(const cJSON *args);
|
|
219
|
+
tf_step *tf_diff_create(const cJSON *args);
|
|
220
|
+
tf_step *tf_anomaly_create(const cJSON *args);
|
|
221
|
+
tf_step *tf_split_data_create(const cJSON *args);
|
|
222
|
+
tf_step *tf_interpolate_create(const cJSON *args);
|
|
223
|
+
tf_step *tf_normalize_create(const cJSON *args);
|
|
224
|
+
tf_step *tf_acf_create(const cJSON *args);
|
|
225
|
+
|
|
226
|
+
/* ---- Table encoder ---- */
|
|
227
|
+
|
|
228
|
+
tf_encoder *tf_table_encoder_create(const cJSON *args);
|
|
229
|
+
|
|
230
|
+
/* ---- Expression evaluator ---- */
|
|
231
|
+
|
|
232
|
+
typedef struct tf_expr tf_expr;
|
|
233
|
+
|
|
234
|
+
tf_expr *tf_expr_parse(const char *text);
|
|
235
|
+
int tf_expr_eval(const tf_expr *e, const tf_batch *batch, size_t row, bool *result);
|
|
236
|
+
int tf_expr_eval_val(const tf_expr *e, const tf_batch *batch, size_t row,
|
|
237
|
+
tf_eval_result *result);
|
|
238
|
+
void tf_expr_free(tf_expr *e);
|
|
239
|
+
|
|
240
|
+
/* ---- Plan parser ---- */
|
|
241
|
+
|
|
242
|
+
int tf_plan_parse(const char *json, size_t len,
|
|
243
|
+
tf_decoder **decoder, tf_step ***steps, size_t *n_steps,
|
|
244
|
+
tf_encoder **encoder, char **error);
|
|
245
|
+
|
|
246
|
+
/* ---- Global error ---- */
|
|
247
|
+
|
|
248
|
+
void tf_set_last_error(const char *msg);
|
|
249
|
+
|
|
250
|
+
#endif /* TF_INTERNAL_H */
|
package/csrc/ir.c
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ir.c — IR plan construction, cloning, and memory management.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
#include "ir.h"
|
|
6
|
+
#include "cJSON.h"
|
|
7
|
+
#include <stdlib.h>
|
|
8
|
+
#include <string.h>
|
|
9
|
+
|
|
10
|
+
/* ---- Schema helpers ---- */
|
|
11
|
+
|
|
12
|
+
void tf_schema_free(tf_schema *s) {
|
|
13
|
+
if (!s) return;
|
|
14
|
+
for (size_t i = 0; i < s->n_cols; i++) {
|
|
15
|
+
free(s->col_names[i]);
|
|
16
|
+
}
|
|
17
|
+
free(s->col_names);
|
|
18
|
+
free(s->col_types);
|
|
19
|
+
s->col_names = NULL;
|
|
20
|
+
s->col_types = NULL;
|
|
21
|
+
s->n_cols = 0;
|
|
22
|
+
s->known = false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
void tf_schema_copy(tf_schema *dst, const tf_schema *src) {
|
|
26
|
+
dst->known = src->known;
|
|
27
|
+
dst->n_cols = src->n_cols;
|
|
28
|
+
if (src->n_cols == 0 || !src->known) {
|
|
29
|
+
dst->col_names = NULL;
|
|
30
|
+
dst->col_types = NULL;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
dst->col_names = calloc(src->n_cols, sizeof(char *));
|
|
34
|
+
dst->col_types = calloc(src->n_cols, sizeof(tf_type));
|
|
35
|
+
for (size_t i = 0; i < src->n_cols; i++) {
|
|
36
|
+
dst->col_names[i] = strdup(src->col_names[i]);
|
|
37
|
+
dst->col_types[i] = src->col_types[i];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* ---- IR node helpers ---- */
|
|
42
|
+
|
|
43
|
+
static void ir_node_clear(tf_ir_node *node) {
|
|
44
|
+
free((char *)node->op);
|
|
45
|
+
if (node->args) cJSON_Delete(node->args);
|
|
46
|
+
tf_schema_free(&node->input_schema);
|
|
47
|
+
tf_schema_free(&node->output_schema);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* ---- IR plan API ---- */
|
|
51
|
+
|
|
52
|
+
tf_ir_plan *tf_ir_plan_create(void) {
|
|
53
|
+
tf_ir_plan *plan = calloc(1, sizeof(tf_ir_plan));
|
|
54
|
+
if (!plan) return NULL;
|
|
55
|
+
plan->capacity = 8;
|
|
56
|
+
plan->nodes = calloc(plan->capacity, sizeof(tf_ir_node));
|
|
57
|
+
if (!plan->nodes) { free(plan); return NULL; }
|
|
58
|
+
return plan;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
int tf_ir_plan_add_node(tf_ir_plan *plan, const char *op, cJSON *args) {
|
|
62
|
+
if (plan->n_nodes >= plan->capacity) {
|
|
63
|
+
size_t new_cap = plan->capacity * 2;
|
|
64
|
+
tf_ir_node *new_nodes = realloc(plan->nodes, new_cap * sizeof(tf_ir_node));
|
|
65
|
+
if (!new_nodes) return -1;
|
|
66
|
+
memset(new_nodes + plan->capacity, 0,
|
|
67
|
+
(new_cap - plan->capacity) * sizeof(tf_ir_node));
|
|
68
|
+
plan->nodes = new_nodes;
|
|
69
|
+
plan->capacity = new_cap;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
tf_ir_node *node = &plan->nodes[plan->n_nodes];
|
|
73
|
+
memset(node, 0, sizeof(tf_ir_node));
|
|
74
|
+
node->op = strdup(op);
|
|
75
|
+
node->args = args ? cJSON_Duplicate(args, 1) : cJSON_CreateObject();
|
|
76
|
+
node->index = plan->n_nodes;
|
|
77
|
+
|
|
78
|
+
plan->n_nodes++;
|
|
79
|
+
plan->validated = false;
|
|
80
|
+
plan->schema_inferred = false;
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
tf_ir_plan *tf_ir_plan_clone(const tf_ir_plan *plan) {
|
|
85
|
+
tf_ir_plan *clone = tf_ir_plan_create();
|
|
86
|
+
if (!clone) return NULL;
|
|
87
|
+
|
|
88
|
+
for (size_t i = 0; i < plan->n_nodes; i++) {
|
|
89
|
+
const tf_ir_node *src = &plan->nodes[i];
|
|
90
|
+
if (tf_ir_plan_add_node(clone, src->op, src->args) != 0) {
|
|
91
|
+
tf_ir_plan_free(clone);
|
|
92
|
+
return NULL;
|
|
93
|
+
}
|
|
94
|
+
/* Copy schemas if they were inferred */
|
|
95
|
+
tf_ir_node *dst = &clone->nodes[i];
|
|
96
|
+
tf_schema_copy(&dst->input_schema, &src->input_schema);
|
|
97
|
+
tf_schema_copy(&dst->output_schema, &src->output_schema);
|
|
98
|
+
dst->caps = src->caps;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
tf_schema_copy(&clone->final_schema, &plan->final_schema);
|
|
102
|
+
clone->plan_caps = plan->plan_caps;
|
|
103
|
+
clone->validated = plan->validated;
|
|
104
|
+
clone->schema_inferred = plan->schema_inferred;
|
|
105
|
+
if (plan->error) clone->error = strdup(plan->error);
|
|
106
|
+
|
|
107
|
+
return clone;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
void tf_ir_plan_free(tf_ir_plan *plan) {
|
|
111
|
+
if (!plan) return;
|
|
112
|
+
for (size_t i = 0; i < plan->n_nodes; i++) {
|
|
113
|
+
ir_node_clear(&plan->nodes[i]);
|
|
114
|
+
}
|
|
115
|
+
free(plan->nodes);
|
|
116
|
+
tf_schema_free(&plan->final_schema);
|
|
117
|
+
free(plan->error);
|
|
118
|
+
free(plan);
|
|
119
|
+
}
|
package/csrc/ir.h
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ir.h — L2 Intermediate Representation types for the Tranfi compilation pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Defines the op registry, schema, IR node, and IR plan types.
|
|
5
|
+
* The IR is the contract between authoring (L3) and execution (L1).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#ifndef TF_IR_H
|
|
9
|
+
#define TF_IR_H
|
|
10
|
+
|
|
11
|
+
#include <stddef.h>
|
|
12
|
+
#include <stdint.h>
|
|
13
|
+
#include <stdbool.h>
|
|
14
|
+
|
|
15
|
+
/* Forward declarations */
|
|
16
|
+
typedef struct cJSON cJSON;
|
|
17
|
+
typedef struct tf_ir_node tf_ir_node;
|
|
18
|
+
typedef struct tf_schema tf_schema;
|
|
19
|
+
|
|
20
|
+
/* ---- Capability flags ---- */
|
|
21
|
+
|
|
22
|
+
#define TF_CAP_STREAMING (1 << 0) /* processes batches without buffering all data */
|
|
23
|
+
#define TF_CAP_BOUNDED_MEMORY (1 << 1) /* memory usage independent of input size */
|
|
24
|
+
#define TF_CAP_BROWSER_SAFE (1 << 2) /* no filesystem/network access */
|
|
25
|
+
#define TF_CAP_DETERMINISTIC (1 << 3) /* same input always produces same output */
|
|
26
|
+
#define TF_CAP_FS (1 << 4) /* requires filesystem access */
|
|
27
|
+
#define TF_CAP_NET (1 << 5) /* requires network access */
|
|
28
|
+
|
|
29
|
+
/* ---- Op tier ---- */
|
|
30
|
+
|
|
31
|
+
typedef enum {
|
|
32
|
+
TF_TIER_CORE, /* built into the C library */
|
|
33
|
+
TF_TIER_ECOSYSTEM, /* provided by host-side plugins */
|
|
34
|
+
} tf_op_tier;
|
|
35
|
+
|
|
36
|
+
/* ---- Op kind ---- */
|
|
37
|
+
|
|
38
|
+
typedef enum {
|
|
39
|
+
TF_OP_DECODER,
|
|
40
|
+
TF_OP_ENCODER,
|
|
41
|
+
TF_OP_TRANSFORM,
|
|
42
|
+
} tf_op_kind;
|
|
43
|
+
|
|
44
|
+
/* ---- Argument descriptor ---- */
|
|
45
|
+
|
|
46
|
+
typedef struct {
|
|
47
|
+
const char *name; /* "delimiter", "expr", "columns", etc. */
|
|
48
|
+
const char *type; /* "string", "int", "bool", "string[]", "map" */
|
|
49
|
+
bool required;
|
|
50
|
+
const char *default_val; /* JSON-encoded default, or NULL */
|
|
51
|
+
} tf_arg_desc;
|
|
52
|
+
|
|
53
|
+
/* ---- Value types (shared with batch system) ---- */
|
|
54
|
+
|
|
55
|
+
typedef enum tf_type {
|
|
56
|
+
TF_TYPE_NULL = 0,
|
|
57
|
+
TF_TYPE_BOOL,
|
|
58
|
+
TF_TYPE_INT64,
|
|
59
|
+
TF_TYPE_FLOAT64,
|
|
60
|
+
TF_TYPE_STRING,
|
|
61
|
+
TF_TYPE_DATE, /* int32_t: days since 1970-01-01 */
|
|
62
|
+
TF_TYPE_TIMESTAMP, /* int64_t: microseconds since 1970-01-01T00:00:00Z */
|
|
63
|
+
} tf_type;
|
|
64
|
+
|
|
65
|
+
/* ---- Schema ---- */
|
|
66
|
+
|
|
67
|
+
struct tf_schema {
|
|
68
|
+
char **col_names;
|
|
69
|
+
tf_type *col_types;
|
|
70
|
+
size_t n_cols;
|
|
71
|
+
bool known; /* false if schema can't be determined until runtime */
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
void tf_schema_free(tf_schema *s);
|
|
75
|
+
void tf_schema_copy(tf_schema *dst, const tf_schema *src);
|
|
76
|
+
|
|
77
|
+
/* ---- Op registry entry ---- */
|
|
78
|
+
|
|
79
|
+
typedef struct {
|
|
80
|
+
const char *name; /* "codec.csv.decode", "filter", etc. */
|
|
81
|
+
tf_op_kind kind;
|
|
82
|
+
tf_op_tier tier;
|
|
83
|
+
uint32_t caps; /* TF_CAP_* bitfield */
|
|
84
|
+
tf_arg_desc *args;
|
|
85
|
+
size_t n_args;
|
|
86
|
+
/* Schema transform: given input schema, compute output schema.
|
|
87
|
+
* Returns TF_OK or TF_ERROR. */
|
|
88
|
+
int (*infer_schema)(const tf_ir_node *node,
|
|
89
|
+
const tf_schema *in, tf_schema *out);
|
|
90
|
+
/* Native target constructor (NULL for ecosystem ops).
|
|
91
|
+
* Returns an opaque pointer (tf_decoder*, tf_step*, or tf_encoder*). */
|
|
92
|
+
void *(*create_native)(const cJSON *args);
|
|
93
|
+
} tf_op_entry;
|
|
94
|
+
|
|
95
|
+
/* ---- Op registry API ---- */
|
|
96
|
+
|
|
97
|
+
const tf_op_entry *tf_op_registry_find(const char *name);
|
|
98
|
+
size_t tf_op_registry_count(void);
|
|
99
|
+
const tf_op_entry *tf_op_registry_get(size_t index);
|
|
100
|
+
|
|
101
|
+
/* ---- IR node ---- */
|
|
102
|
+
|
|
103
|
+
struct tf_ir_node {
|
|
104
|
+
const char *op; /* op name (owned, freed with node) */
|
|
105
|
+
cJSON *args; /* argument values (owned, freed with node) */
|
|
106
|
+
tf_schema input_schema;
|
|
107
|
+
tf_schema output_schema;
|
|
108
|
+
uint32_t caps; /* resolved capability flags from registry */
|
|
109
|
+
size_t index; /* position in plan */
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/* ---- IR plan ---- */
|
|
113
|
+
|
|
114
|
+
typedef struct tf_ir_plan {
|
|
115
|
+
tf_ir_node *nodes;
|
|
116
|
+
size_t n_nodes;
|
|
117
|
+
size_t capacity; /* allocated node slots */
|
|
118
|
+
tf_schema final_schema; /* schema after last transform, before encoder */
|
|
119
|
+
uint32_t plan_caps; /* intersection of all node caps */
|
|
120
|
+
char *error; /* validation error, if any */
|
|
121
|
+
bool validated;
|
|
122
|
+
bool schema_inferred;
|
|
123
|
+
} tf_ir_plan;
|
|
124
|
+
|
|
125
|
+
/* ---- IR plan API ---- */
|
|
126
|
+
|
|
127
|
+
tf_ir_plan *tf_ir_plan_create(void);
|
|
128
|
+
int tf_ir_plan_add_node(tf_ir_plan *plan, const char *op, cJSON *args);
|
|
129
|
+
tf_ir_plan *tf_ir_plan_clone(const tf_ir_plan *plan);
|
|
130
|
+
void tf_ir_plan_free(tf_ir_plan *plan);
|
|
131
|
+
|
|
132
|
+
/* ---- IR serialization ---- */
|
|
133
|
+
|
|
134
|
+
tf_ir_plan *tf_ir_from_json(const char *json, size_t len, char **error);
|
|
135
|
+
char *tf_ir_to_json(const tf_ir_plan *plan);
|
|
136
|
+
char *tf_ir_to_sql(const tf_ir_plan *plan, char **error);
|
|
137
|
+
|
|
138
|
+
/* ---- IR passes ---- */
|
|
139
|
+
|
|
140
|
+
int tf_ir_validate(tf_ir_plan *plan);
|
|
141
|
+
int tf_ir_infer_schema(tf_ir_plan *plan);
|
|
142
|
+
|
|
143
|
+
/* ---- Expression eval result ---- */
|
|
144
|
+
|
|
145
|
+
typedef struct tf_eval_result {
|
|
146
|
+
tf_type type;
|
|
147
|
+
union {
|
|
148
|
+
int64_t i; /* INT64 or TIMESTAMP (microseconds since epoch) */
|
|
149
|
+
double f;
|
|
150
|
+
const char *s;
|
|
151
|
+
bool b;
|
|
152
|
+
int32_t date; /* DATE: days since epoch */
|
|
153
|
+
};
|
|
154
|
+
} tf_eval_result;
|
|
155
|
+
|
|
156
|
+
/* ---- Compiler ---- */
|
|
157
|
+
|
|
158
|
+
/* Forward declarations of internal types */
|
|
159
|
+
typedef struct tf_decoder tf_decoder;
|
|
160
|
+
typedef struct tf_step tf_step;
|
|
161
|
+
typedef struct tf_encoder tf_encoder;
|
|
162
|
+
|
|
163
|
+
int tf_compile_native(const tf_ir_plan *plan,
|
|
164
|
+
tf_decoder **decoder, tf_step ***steps,
|
|
165
|
+
size_t *n_steps, tf_encoder **encoder, char **error);
|
|
166
|
+
|
|
167
|
+
#endif /* TF_IR_H */
|
package/csrc/ir_schema.c
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ir_schema.c — Forward schema inference pass.
|
|
3
|
+
*
|
|
4
|
+
* Walks nodes in execution order, calling each op's infer_schema callback
|
|
5
|
+
* to propagate schema information forward through the plan.
|
|
6
|
+
* Best-effort and non-fatal — unknown schemas propagate as known=false.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "ir.h"
|
|
10
|
+
#include <stdlib.h>
|
|
11
|
+
|
|
12
|
+
#define TF_OK 0
|
|
13
|
+
#define TF_ERROR (-1)
|
|
14
|
+
|
|
15
|
+
int tf_ir_infer_schema(tf_ir_plan *plan) {
|
|
16
|
+
if (plan->n_nodes == 0) return TF_OK;
|
|
17
|
+
|
|
18
|
+
/* Start with an empty, unknown input schema for the first node (decoder) */
|
|
19
|
+
tf_schema current = {0};
|
|
20
|
+
current.known = false;
|
|
21
|
+
|
|
22
|
+
for (size_t i = 0; i < plan->n_nodes; i++) {
|
|
23
|
+
tf_ir_node *node = &plan->nodes[i];
|
|
24
|
+
const tf_op_entry *entry = tf_op_registry_find(node->op);
|
|
25
|
+
|
|
26
|
+
/* Copy current schema as this node's input */
|
|
27
|
+
tf_schema_free(&node->input_schema);
|
|
28
|
+
tf_schema_copy(&node->input_schema, ¤t);
|
|
29
|
+
|
|
30
|
+
if (entry && entry->infer_schema) {
|
|
31
|
+
/* Clear old output schema */
|
|
32
|
+
tf_schema_free(&node->output_schema);
|
|
33
|
+
entry->infer_schema(node, ¤t, &node->output_schema);
|
|
34
|
+
|
|
35
|
+
/* Advance current to this node's output */
|
|
36
|
+
tf_schema_free(¤t);
|
|
37
|
+
tf_schema_copy(¤t, &node->output_schema);
|
|
38
|
+
} else {
|
|
39
|
+
/* No schema inference available — propagate unknown */
|
|
40
|
+
tf_schema_free(&node->output_schema);
|
|
41
|
+
node->output_schema.known = false;
|
|
42
|
+
tf_schema_free(¤t);
|
|
43
|
+
current.known = false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Store final schema (schema before encoder, i.e., last transform's output) */
|
|
48
|
+
tf_schema_free(&plan->final_schema);
|
|
49
|
+
if (plan->n_nodes >= 2) {
|
|
50
|
+
/* The schema before the encoder is the second-to-last node's output */
|
|
51
|
+
tf_schema_copy(&plan->final_schema,
|
|
52
|
+
&plan->nodes[plan->n_nodes - 2].output_schema);
|
|
53
|
+
} else {
|
|
54
|
+
plan->final_schema.known = false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
tf_schema_free(¤t);
|
|
58
|
+
plan->schema_inferred = true;
|
|
59
|
+
return TF_OK;
|
|
60
|
+
}
|