clean up of files and fixed docs

This commit is contained in:
cozis
2023-06-29 19:38:44 +02:00
parent 2b138a8764
commit 56927aba1f
16 changed files with 161 additions and 1328 deletions
+2
View File
@@ -0,0 +1,2 @@
tt
tt.exe
View File
View File
+1 -1
View File
@@ -50,4 +50,4 @@ cat page.tt | ./tt params.json > page.html
``` ```
## Internals ## Internals
TinyTemplate works by compiling a template string into a bytecode program, and then evaluating the program to generate the output. TinyTemplate works by compiling a template string into a bytecode program, and then evaluating the program to generate the output. (TODO)
+5
View File
@@ -0,0 +1,5 @@
{
"name": "Francesco",
"fruits": ["Orange", "Peach", "Mango"],
"chocolate": false
}
+18
View File
@@ -0,0 +1,18 @@
<html>
<head>
<title>TinyTemplate example</title>
</head>
<body>
<a>Hello, my name is {{name}} and my favourite fruits are:</a>
<ul>
{% for fruit in fruits %}
<li>{{fruit}}</li>
{% end %}
</ul>
{% if chocolate %}
<a>but I also like chocolate!</a>
{% else %}
<a>and I do NOT like chocolate!</a>
{% end %}
</body>
</html>
+2 -2
View File
@@ -1,8 +1,8 @@
all: tt all: tt
tt: cli.c tinytemplate.c xjson.c tt: src/cli.c src/tinytemplate.c 3p/xjson.c
gcc $^ -o $@ -Wall -Wextra -g gcc $^ -o $@ -Wall -Wextra -g -I3p
clean: clean:
rm tt tt.exe rm tt tt.exe
-13
View File
@@ -1,13 +0,0 @@
<html>
<head>
<title>{{username}}s blog!</title>
</head>
<body>
<p>Hei, welcome to my blog! I'm {{name}} {{surname}} and I'm {{age}} years old!</p>
<ul>
{% for post in posts %}
<li>{{post.title}} - {{post.date}}</li>
{% end %}
</ul>
</body>
</html>
-19
View File
@@ -1,19 +0,0 @@
<html>
<head>
<title>coziss blog!</title>
</head>
<body>
<p>Hei, welcome to my blog! I'm Francesco Cozzuto and I'm 24 years old!</p>
<ul>
<li>Scriviamo un server TCP - 10/9/2023</li>
<li>Gli assert - 4/5/2022</li>
<li>Big e little endian: Ordinamento dei byte - 14/5/2022</li>
<li>Complessità computazionale - ???</li>
</ul>
</body>
</html>
-12
View File
@@ -1,12 +0,0 @@
{
"username": "cozis",
"name": "Francesco",
"surname": "Cozzuto",
"age": 24,
"posts": [
{"title": "Scriviamo un server TCP", "date": "10/9/2023"},
{"title": "Gli assert", "date": "4/5/2022"},
{"title": "Big e little endian: Ordinamento dei byte", "date": "14/5/2022"},
{"title": "Complessità computazionale", "date": "???"}
]
}
+40 -33
View File
@@ -6,28 +6,30 @@
#include "tinytemplate.h" #include "tinytemplate.h"
typedef struct wrap_t wrap_t; typedef struct wrap_t wrap_t;
typedef struct eval_context_t eval_context_t;
struct wrap_t { struct wrap_t {
eval_context_t *context; eval_context_t *context;
union { union {
xj_value *value; xj_value *value;
wrap_t *next; wrap_t *next;
}; };
}; };
typedef struct { struct eval_context_t {
FILE *stream; FILE *stream;
xj_value *params; wrap_t params;
wrap_t *free; wrap_t *free;
wrap_t pool[TINYTEMPLATE_MAX_ITER_DEPTH]; wrap_t pool[TINYTEMPLATE_MAX_ITER_DEPTH];
} eval_context_t; };
static bool query_json_array(void *data, static bool query_json_array(void *data,
tinytemplate_type_t *type, tinytemplate_type_t *type,
tinytemplate_value_t *value); tinytemplate_value_t *value);
static bool query_json_object(void *data, const char *key, size_t len, static bool query_json_object(void *data, const char *key, size_t len,
tinytemplate_type_t *type, tinytemplate_type_t *type,
tinytemplate_value_t *value); tinytemplate_value_t *value);
static void convert_json_object(eval_context_t *context, static void convert_json_object(eval_context_t *context,
xj_value *child, xj_value *child,
@@ -58,13 +60,14 @@ static void convert_json_object(eval_context_t *context,
case XJ_ARRAY: case XJ_ARRAY:
{ {
iter_t *iter = context->free; wrap_t *wrap = context->free;
*type = TINYTEMPLATE_TYPE_ARRAY; *type = TINYTEMPLATE_TYPE_ARRAY;
value->as_array.data = iter; value->as_array.data = wrap;
value->as_array.next = query_json_array; value->as_array.next = query_json_array;
if (iter) { if (wrap) {
context->free = iter->next; context->free = wrap->next;
iter->curs = child->as_array; wrap->value = child->as_array;
wrap->context = context;
} }
break; break;
} }
@@ -87,14 +90,12 @@ static bool query_json_array(void *data,
tinytemplate_type_t *type, tinytemplate_type_t *type,
tinytemplate_value_t *value) tinytemplate_value_t *value)
{ {
iter_t *iter = data; wrap_t *wrap = data;
if (iter->curs) { if (wrap->value) {
iter->curs = iter->curs->next; convert_json_object(wrap->context, wrap->value, type, value);
if (iter->curs) { wrap->value = wrap->value->next;
convert_json_object(iter->curs, type, value); return true;
return true;
}
} }
return false; return false;
} }
@@ -103,10 +104,11 @@ static bool query_json_object(void *data, const char *key, size_t len,
tinytemplate_type_t *type, tinytemplate_type_t *type,
tinytemplate_value_t *value) tinytemplate_value_t *value)
{ {
xj_value *json_value = data; wrap_t *wrap = data;
assert(json_value->type == XJ_OBJECT);
assert(wrap->value->type == XJ_OBJECT);
xj_value *child = json_value->as_object; xj_value *child = wrap->value->as_object;
while (child) { while (child) {
size_t keylen = strlen(child->key); size_t keylen = strlen(child->key);
if (keylen == len && !strncmp(key, child->key, len)) if (keylen == len && !strncmp(key, child->key, len))
@@ -116,12 +118,16 @@ static bool query_json_object(void *data, const char *key, size_t len,
if (!child) if (!child)
return false; return false;
convert_json_object(child, type, value); convert_json_object(wrap->context, child, type, value);
return true; return true;
} }
static void callback(void *userp, const char *str, size_t len) static void callback(void *userp, const char *lbl, size_t lbllen,
const char *str, size_t len)
{ {
(void) lbl;
(void) lbllen;
eval_context_t *context = userp; eval_context_t *context = userp;
fwrite(str, 1, len, context->stream); fwrite(str, 1, len, context->stream);
} }
@@ -131,8 +137,8 @@ static bool query_root_json_object(void *data, const char *key, size_t len,
tinytemplate_value_t *value) tinytemplate_value_t *value)
{ {
eval_context_t *context = data; eval_context_t *context = data;
if (context->params) if (context->params.value)
return query_json_object(context->params, key, len, type, value); return query_json_object(&context->params, key, len, type, value);
else else
return false; return false;
} }
@@ -140,9 +146,10 @@ static bool query_root_json_object(void *data, const char *key, size_t len,
static void init_context(eval_context_t *context, static void init_context(eval_context_t *context,
FILE *stream, xj_value *root) FILE *stream, xj_value *root)
{ {
context->stream=stdout; context->stream = stream;
context->params=root; context->params.context = context;
context->free = context->pool; context->params.value = root;
context->free = context->pool;
for (int i = 0; i < TINYTEMPLATE_MAX_ITER_DEPTH-1; i++) for (int i = 0; i < TINYTEMPLATE_MAX_ITER_DEPTH-1; i++)
context->pool[i].next = &context->pool[i+1]; context->pool[i].next = &context->pool[i+1];
@@ -217,7 +224,7 @@ int main(int argc, char **argv)
} while (status == TINYTEMPLATE_STATUS_EMEMORY); } while (status == TINYTEMPLATE_STATUS_EMEMORY);
eval_context_t context; eval_context_t context;
init_context(&context); init_context(&context, stdout, root);
if (tinytemplate_eval(buffer, program, &context, query_root_json_object, callback, message, sizeof(message)) != TINYTEMPLATE_STATUS_DONE) { if (tinytemplate_eval(buffer, program, &context, query_root_json_object, callback, message, sizeof(message)) != TINYTEMPLATE_STATUS_DONE) {
fprintf(stderr, "Failed to evaluate template (%s)\n", message); fprintf(stderr, "Failed to evaluate template (%s)\n", message);
+92 -11
View File
@@ -73,6 +73,7 @@ typedef enum {
OPCODE_NEXT, OPCODE_NEXT,
OPCODE_CHLD, OPCODE_CHLD,
OPCODE_IDX, OPCODE_IDX,
OPCODE_BLOCK,
} opcode_t; } opcode_t;
// Represents a substring of the template // Represents a substring of the template
@@ -85,15 +86,20 @@ typedef enum {
SCOPE_IF, SCOPE_IF,
SCOPE_IF_ELSE, SCOPE_IF_ELSE,
SCOPE_FOR, SCOPE_FOR,
SCOPE_BLOCK,
} scope_type_t; } scope_type_t;
typedef struct { typedef struct {
scope_type_t type; scope_type_t type;
size_t if_jcnd; size_t if_jcnd;
size_t if_jump; size_t if_jump;
size_t for_next;
size_t for_next;
slice_t for_child_label; slice_t for_child_label;
slice_t for_index_label; slice_t for_index_label;
slice_t block_name;
} scope_t; } scope_t;
typedef struct { typedef struct {
@@ -134,6 +140,7 @@ typedef enum {
TOKEN_KWORD_FOR, TOKEN_KWORD_FOR,
TOKEN_KWORD_ELSE, TOKEN_KWORD_ELSE,
TOKEN_KWORD_END, TOKEN_KWORD_END,
TOKEN_KWORD_BLOCK,
TOKEN_OPER_MOD, TOKEN_OPER_MOD,
} token_t; } token_t;
@@ -191,6 +198,7 @@ append_instr(compile_state_t *state,
case OPCODE_GETS: case OPCODE_GETS:
case OPCODE_PUSHV: case OPCODE_PUSHV:
case OPCODE_PUSHS: case OPCODE_PUSHS:
case OPCODE_BLOCK:
instr->operands[0].as_size = va_arg(operands, size_t); instr->operands[0].as_size = va_arg(operands, size_t);
instr->operands[1].as_size = va_arg(operands, size_t); instr->operands[1].as_size = va_arg(operands, size_t);
break; break;
@@ -372,6 +380,11 @@ next_token_kword_or_ident(scanner_t *scanner, slice_t *slice,
if (!strncmp(scanner->src + offset, "else", length)) if (!strncmp(scanner->src + offset, "else", length))
return TOKEN_KWORD_ELSE; return TOKEN_KWORD_ELSE;
break; break;
case 5: // block
if (!strncmp(scanner->src + offset, "block", length))
return TOKEN_KWORD_BLOCK;
break;
} }
return TOKEN_IDENT; return TOKEN_IDENT;
@@ -756,7 +769,6 @@ selection_construct_start(scanner_t *scanner,
return DONE; return DONE;
} }
static status_t static status_t
iteration_construct_start(scanner_t *scanner, iteration_construct_start(scanner_t *scanner,
compile_state_t *state, compile_state_t *state,
@@ -812,13 +824,48 @@ iteration_construct_start(scanner_t *scanner,
return DONE; return DONE;
} }
static status_t
block_construct_start(scanner_t *scanner,
compile_state_t *state,
error_t *error)
{
// This function is called after "{% block" is parsed
assert(scanner->src[scanner->cur-5] == 'b'
&& scanner->src[scanner->cur-4] == 'l'
&& scanner->src[scanner->cur-3] == 'o'
&& scanner->src[scanner->cur-2] == 'c'
&& scanner->src[scanner->cur-1] == 'k');
if (state->scope_depth == TINYTEMPLATE_MAX_SCOPE_DEPTH) {
report(error, "Scope depth limit reached");
return ESCOPE;
}
slice_t label;
if (next_token(scanner, &label, NULL) != TOKEN_IDENT) {
report(error, "Missing block label");
return ESYNTAX;
}
append_instr(state, OPCODE_BLOCK, label.offset, label.length);
tinytemplate_status_t status;
if ((status = close_construct(scanner, error, "block")) != DONE)
return status;
state->scope_stack[state->scope_depth].type = SCOPE_BLOCK;
state->scope_stack[state->scope_depth].block_name = label;
state->scope_depth++;
return DONE;
}
static void static void
resolve_scope(compile_state_t *state) resolve_scope(compile_state_t *state)
{ {
assert(state->scope_depth > 0); assert(state->scope_depth > 0);
scope_t *scope = state->scope_stack scope_t *scope = state->scope_stack
+ state->scope_depth - 1; + state->scope_depth-1;
switch (scope->type) { switch (scope->type) {
@@ -841,6 +888,17 @@ resolve_scope(compile_state_t *state)
instr = state->program + scope->if_jump; instr = state->program + scope->if_jump;
instr->operands[0].as_size = state->num_instr; instr->operands[0].as_size = state->num_instr;
break; break;
case SCOPE_BLOCK:
{
// Get parent block name
slice_t parent_label = {0, 0};
for (int i = state->scope_depth-2; i >= 0; i--)
if (state->scope_stack[i].type == SCOPE_BLOCK)
parent_label = state->scope_stack[i].block_name;
append_instr(state, OPCODE_BLOCK, parent_label.offset, parent_label.length);
break;
}
} }
state->scope_depth--; state->scope_depth--;
@@ -900,6 +958,10 @@ construct_else(scanner_t *scanner,
case SCOPE_FOR: case SCOPE_FOR:
report(error, "Bad {%% else %%} coupled with {%% for .. %%}"); report(error, "Bad {%% else %%} coupled with {%% for .. %%}");
return ESEMANT; return ESEMANT;
case SCOPE_BLOCK:
report(error, "Bad {%% else %%} coupled with {%% block .. %%}");
return ESEMANT;
} }
return DONE; return DONE;
@@ -918,7 +980,7 @@ control_flow_block(scanner_t *scanner,
case TOKEN_KWORD_FOR: return iteration_construct_start(scanner, state, error); case TOKEN_KWORD_FOR: return iteration_construct_start(scanner, state, error);
case TOKEN_KWORD_END: return construct_end(scanner, state, error); case TOKEN_KWORD_END: return construct_end(scanner, state, error);
case TOKEN_KWORD_ELSE: return construct_else(scanner, state, error); case TOKEN_KWORD_ELSE: return construct_else(scanner, state, error);
case TOKEN_KWORD_BLOCK: return block_construct_start(scanner, state, error);
default: default:
report(error, "Bad token [%.*s] after [{%%]", report(error, "Bad token [%.*s] after [{%%]",
(int) slice.length, scanner->src + slice.offset); (int) slice.length, scanner->src + slice.offset);
@@ -1050,13 +1112,28 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
tinytemplate_value_t stack[TINYTEMPLATE_MAX_EXPR_DEPTH]; tinytemplate_value_t stack[TINYTEMPLATE_MAX_EXPR_DEPTH];
size_t stack_depth = 0; size_t stack_depth = 0;
slice_t label = {0, 0};
bool done = false; bool done = false;
int index = 0; int index = 0;
while (!done) { while (!done) {
const tinytemplate_instr_t *instr = &program[index++]; const tinytemplate_instr_t *instr = &program[index++];
switch (instr->opcode) { switch (instr->opcode) {
case OPCODE_NOPE: /* Do nothing */ break;
case OPCODE_DONE: done = true; break; case OPCODE_NOPE:
/* Do nothing */
break;
case OPCODE_DONE:
done = true;
break;
case OPCODE_BLOCK:
label = (slice_t) {
.offset = instr->operands[0].as_size,
.length = instr->operands[1].as_size,
};
break;
case OPCODE_ITER: case OPCODE_ITER:
assert(stack_depth > 0); // ITER excepts a value on the stack assert(stack_depth > 0); // ITER excepts a value on the stack
@@ -1233,7 +1310,8 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
{ {
size_t offset = instr->operands[0].as_size; size_t offset = instr->operands[0].as_size;
size_t length = instr->operands[1].as_size; size_t length = instr->operands[1].as_size;
callback(userp, src + offset, length); callback(userp, src + label.offset, label.length,
src + offset, length);
break; break;
} }
@@ -1248,7 +1326,8 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
char text[128]; char text[128];
int num = snprintf(text, sizeof(text), "%lld", stack[stack_depth-1].as_int); int num = snprintf(text, sizeof(text), "%lld", stack[stack_depth-1].as_int);
assert(num > 0); assert(num > 0);
callback(userp, text, (size_t) num); callback(userp, src + label.offset, label.length,
text, (size_t) num);
break; break;
} }
@@ -1257,13 +1336,15 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
char text[128]; char text[128];
int num = snprintf(text, sizeof(text), "%lf", stack[stack_depth-1].as_float); int num = snprintf(text, sizeof(text), "%lf", stack[stack_depth-1].as_float);
assert(num > 0); assert(num > 0);
callback(userp, text, (size_t) num); callback(userp, src + label.offset, label.length,
text, (size_t) num);
break; break;
} }
case TINYTEMPLATE_TYPE_STRING: case TINYTEMPLATE_TYPE_STRING:
callback(userp, stack[stack_depth-1].as_string.str, callback(userp, src + label.offset, label.length,
stack[stack_depth-1].as_string.len); stack[stack_depth-1].as_string.str,
stack[stack_depth-1].as_string.len);
break; break;
default: default:
+1 -1
View File
@@ -29,7 +29,7 @@ typedef union tinytemplate_value_t tinytemplate_value_t;
typedef bool (*tinytemplate_nextcallback_t)(void*, tinytemplate_type_t*, tinytemplate_value_t*); typedef bool (*tinytemplate_nextcallback_t)(void*, tinytemplate_type_t*, tinytemplate_value_t*);
typedef bool (*tinytemplate_getter_t)(void*, const char*, size_t, tinytemplate_type_t*, tinytemplate_value_t*); typedef bool (*tinytemplate_getter_t)(void*, const char*, size_t, tinytemplate_type_t*, tinytemplate_value_t*);
typedef void (*tinytemplate_callback_t)(void *userp, const char *str, size_t len); typedef void (*tinytemplate_callback_t)(void *userp, const char *lbl, size_t lblen, const char *str, size_t len);
typedef struct { typedef struct {
void *data; void *data;
-1236
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.