cleaned up interfaces and unused code
This commit is contained in:
@@ -23,47 +23,27 @@ struct eval_context_t {
|
|||||||
wrap_t pool[TINYTEMPLATE_MAX_ITER_DEPTH];
|
wrap_t pool[TINYTEMPLATE_MAX_ITER_DEPTH];
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool query_json_array(void *data,
|
static bool query_json_array(void *data, tinytemplate_value_t *value);
|
||||||
tinytemplate_type_t *type,
|
|
||||||
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_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,
|
|
||||||
tinytemplate_type_t *type,
|
|
||||||
tinytemplate_value_t *value)
|
tinytemplate_value_t *value)
|
||||||
{
|
{
|
||||||
switch (child->type) {
|
switch (child->type) {
|
||||||
|
|
||||||
case XJ_NULL:
|
case XJ_NULL : tinytemplate_set_int(value, 0); break;
|
||||||
*type = TINYTEMPLATE_TYPE_INT;
|
case XJ_INT : tinytemplate_set_int(value, child->as_int); break;
|
||||||
value->as_int = 0;
|
case XJ_FLOAT: tinytemplate_set_float(value, child->as_float); break;
|
||||||
break;
|
case XJ_BOOL : tinytemplate_set_int(value, child->as_bool); break;
|
||||||
|
case XJ_OBJECT: tinytemplate_set_dict(value, child, query_json_object); break;
|
||||||
case XJ_INT:
|
case XJ_STRING: tinytemplate_set_string(value, child->as_string, child->size); break;
|
||||||
*type = TINYTEMPLATE_TYPE_INT;
|
|
||||||
value->as_int = child->as_int;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case XJ_FLOAT:
|
|
||||||
*type = TINYTEMPLATE_TYPE_INT;
|
|
||||||
value->as_float = child->as_float;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case XJ_BOOL:
|
|
||||||
*type = TINYTEMPLATE_TYPE_INT;
|
|
||||||
value->as_int = child->as_bool;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case XJ_ARRAY:
|
case XJ_ARRAY:
|
||||||
{
|
{
|
||||||
wrap_t *wrap = context->free;
|
wrap_t *wrap = context->free;
|
||||||
*type = TINYTEMPLATE_TYPE_ARRAY;
|
tinytemplate_set_array(value, wrap, query_json_array);
|
||||||
value->as_array.data = wrap;
|
|
||||||
value->as_array.next = query_json_array;
|
|
||||||
if (wrap) {
|
if (wrap) {
|
||||||
context->free = wrap->next;
|
context->free = wrap->next;
|
||||||
wrap->value = child->as_array;
|
wrap->value = child->as_array;
|
||||||
@@ -71,29 +51,15 @@ static void convert_json_object(eval_context_t *context,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case XJ_OBJECT:
|
|
||||||
*type = TINYTEMPLATE_TYPE_DICT;
|
|
||||||
value->as_dict.data = child;
|
|
||||||
value->as_dict.get = query_json_object;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case XJ_STRING:
|
|
||||||
*type = TINYTEMPLATE_TYPE_STRING;
|
|
||||||
value->as_string.str = child->as_string;
|
|
||||||
value->as_string.len = child->size;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool query_json_array(void *data,
|
static bool query_json_array(void *data, tinytemplate_value_t *value)
|
||||||
tinytemplate_type_t *type,
|
|
||||||
tinytemplate_value_t *value)
|
|
||||||
{
|
{
|
||||||
wrap_t *wrap = data;
|
wrap_t *wrap = data;
|
||||||
|
|
||||||
if (wrap->value) {
|
if (wrap->value) {
|
||||||
convert_json_object(wrap->context, wrap->value, type, value);
|
convert_json_object(wrap->context, wrap->value, value);
|
||||||
wrap->value = wrap->value->next;
|
wrap->value = wrap->value->next;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -101,7 +67,6 @@ static bool query_json_array(void *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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_value_t *value)
|
tinytemplate_value_t *value)
|
||||||
{
|
{
|
||||||
wrap_t *wrap = data;
|
wrap_t *wrap = data;
|
||||||
@@ -118,27 +83,22 @@ static bool query_json_object(void *data, const char *key, size_t len,
|
|||||||
if (!child)
|
if (!child)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
convert_json_object(wrap->context, child, type, value);
|
convert_json_object(wrap->context, child, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void callback(void *userp, const char *lbl, size_t lbllen,
|
static void callback(void *userp, const char *str, size_t len)
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool query_root_json_object(void *data, const char *key, size_t len,
|
static bool query_root_json_object(void *data, const char *key, size_t len,
|
||||||
tinytemplate_type_t *type,
|
|
||||||
tinytemplate_value_t *value)
|
tinytemplate_value_t *value)
|
||||||
{
|
{
|
||||||
eval_context_t *context = data;
|
eval_context_t *context = data;
|
||||||
if (context->params.value)
|
if (context->params.value)
|
||||||
return query_json_object(&context->params, key, len, type, value);
|
return query_json_object(&context->params, key, len, value);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+113
-122
@@ -73,7 +73,6 @@ 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
|
||||||
@@ -86,7 +85,6 @@ 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 {
|
||||||
@@ -99,7 +97,6 @@ typedef struct {
|
|||||||
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 {
|
||||||
@@ -140,7 +137,6 @@ 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;
|
||||||
|
|
||||||
@@ -198,7 +194,6 @@ 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;
|
||||||
@@ -255,11 +250,58 @@ static bool is_printable(char c)
|
|||||||
&& (unsigned char) c <= 126;
|
&& (unsigned char) c <= 126;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
follows_digit(scanner_t *s)
|
||||||
|
{
|
||||||
|
return s->cur < s->len && is_digit(s->src[s->cur]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
follows_alpha(scanner_t *s)
|
||||||
|
{
|
||||||
|
return s->cur < s->len && is_alpha(s->src[s->cur]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
follows_space(scanner_t *s)
|
||||||
|
{
|
||||||
|
return s->cur < s->len && is_space(s->src[s->cur]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
follows_char(scanner_t *s, char c)
|
||||||
|
{
|
||||||
|
return s->cur < s->len && s->src[s->cur] == c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
follows_pair(scanner_t *s, char pair[static 2])
|
||||||
|
{
|
||||||
|
return s->cur+1 < s->len
|
||||||
|
&& s->src[s->cur+0] == pair[0]
|
||||||
|
&& s->src[s->cur+1] == pair[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
consume_pair(scanner_t *s, char pair[static 2])
|
||||||
|
{
|
||||||
|
bool ok = follows_pair(s, pair);
|
||||||
|
if (ok) s->cur += 2;
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
consume_spaces(scanner_t *s)
|
||||||
|
{
|
||||||
|
while (follows_space(s))
|
||||||
|
s->cur++;
|
||||||
|
}
|
||||||
|
|
||||||
static token_t
|
static token_t
|
||||||
next_token_int(scanner_t *scanner, slice_t *slice,
|
next_token_int(scanner_t *scanner, slice_t *slice,
|
||||||
token_payload_t *payload)
|
token_payload_t *payload)
|
||||||
{
|
{
|
||||||
assert(scanner->cur < scanner->len && is_digit(scanner->src[scanner->cur]));
|
assert(follows_digit(scanner));
|
||||||
|
|
||||||
size_t offset = scanner->cur;
|
size_t offset = scanner->cur;
|
||||||
|
|
||||||
@@ -272,7 +314,7 @@ next_token_int(scanner_t *scanner, slice_t *slice,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
buf = buf * 10 + d;
|
buf = buf * 10 + d;
|
||||||
} while (scanner->cur < scanner->len && is_digit(scanner->src[scanner->cur]));
|
} while (follows_digit(scanner));
|
||||||
|
|
||||||
if (slice) {
|
if (slice) {
|
||||||
slice->offset = offset;
|
slice->offset = offset;
|
||||||
@@ -291,7 +333,7 @@ next_token_float(scanner_t *scanner, slice_t *slice,
|
|||||||
// The caller made sure that follows a float:
|
// The caller made sure that follows a float:
|
||||||
// a string of digits followed by a dot and
|
// a string of digits followed by a dot and
|
||||||
// another string of digits.
|
// another string of digits.
|
||||||
assert(scanner->cur < scanner->len && is_digit(scanner->src[scanner->cur]));
|
assert(follows_digit(scanner));
|
||||||
|
|
||||||
size_t offset = scanner->cur;
|
size_t offset = scanner->cur;
|
||||||
|
|
||||||
@@ -308,7 +350,7 @@ next_token_float(scanner_t *scanner, slice_t *slice,
|
|||||||
q /= 10;
|
q /= 10;
|
||||||
int d = scanner->src[scanner->cur++] - '0';
|
int d = scanner->src[scanner->cur++] - '0';
|
||||||
buf += d * q;
|
buf += d * q;
|
||||||
} while (scanner->cur < scanner->len && is_digit(scanner->src[scanner->cur]));
|
} while (follows_digit(scanner));
|
||||||
|
|
||||||
if (slice) {
|
if (slice) {
|
||||||
slice->offset = offset;
|
slice->offset = offset;
|
||||||
@@ -325,7 +367,7 @@ next_token_numeric(scanner_t *scanner, slice_t *slice,
|
|||||||
token_payload_t *payload)
|
token_payload_t *payload)
|
||||||
{
|
{
|
||||||
// Scanner points to a digit
|
// Scanner points to a digit
|
||||||
assert(scanner->cur < scanner->len && is_digit(scanner->src[scanner->cur]));
|
assert(follows_digit(scanner));
|
||||||
|
|
||||||
// Is it a float or an int? Check if at the end
|
// Is it a float or an int? Check if at the end
|
||||||
// of the first sequence of digit there's a dot
|
// of the first sequence of digit there's a dot
|
||||||
@@ -346,12 +388,12 @@ next_token_kword_or_ident(scanner_t *scanner, slice_t *slice,
|
|||||||
{
|
{
|
||||||
(void) payload;
|
(void) payload;
|
||||||
|
|
||||||
assert(scanner->cur < scanner->len && is_alpha(scanner->src[scanner->cur]));
|
assert(follows_alpha(scanner));
|
||||||
|
|
||||||
size_t offset = scanner->cur;
|
size_t offset = scanner->cur;
|
||||||
do
|
do
|
||||||
scanner->cur++;
|
scanner->cur++;
|
||||||
while (scanner->cur < scanner->len && is_alpha(scanner->src[scanner->cur]));
|
while (follows_alpha(scanner));
|
||||||
size_t length = scanner->cur - offset;
|
size_t length = scanner->cur - offset;
|
||||||
|
|
||||||
if (slice) {
|
if (slice) {
|
||||||
@@ -380,11 +422,6 @@ 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;
|
||||||
@@ -394,8 +431,7 @@ static token_t
|
|||||||
next_token(scanner_t *scanner, slice_t *slice,
|
next_token(scanner_t *scanner, slice_t *slice,
|
||||||
token_payload_t *payload)
|
token_payload_t *payload)
|
||||||
{
|
{
|
||||||
while (scanner->cur < scanner->len && is_space(scanner->src[scanner->cur]))
|
consume_spaces(scanner);
|
||||||
scanner->cur++;
|
|
||||||
|
|
||||||
if (scanner->cur == scanner->len) {
|
if (scanner->cur == scanner->len) {
|
||||||
if (slice) {
|
if (slice) {
|
||||||
@@ -709,11 +745,7 @@ expr_block(scanner_t *scanner,
|
|||||||
append_instr(state, OPCODE_WRTOP);
|
append_instr(state, OPCODE_WRTOP);
|
||||||
append_instr(state, OPCODE_POP, 1);
|
append_instr(state, OPCODE_POP, 1);
|
||||||
|
|
||||||
if (scanner->cur+1 < scanner->len
|
if (!consume_pair(scanner, "}}")) {
|
||||||
&& scanner->src[scanner->cur+0] == '}'
|
|
||||||
&& scanner->src[scanner->cur+1] == '}')
|
|
||||||
scanner->cur += 2;
|
|
||||||
else {
|
|
||||||
report(error, "No closing [}}] after expression block");
|
report(error, "No closing [}}] after expression block");
|
||||||
return ESYNTAX;
|
return ESYNTAX;
|
||||||
}
|
}
|
||||||
@@ -726,12 +758,8 @@ close_construct(scanner_t *scanner,
|
|||||||
const char *block_name)
|
const char *block_name)
|
||||||
{
|
{
|
||||||
// Consume the following "%}"
|
// Consume the following "%}"
|
||||||
|
consume_spaces(scanner);
|
||||||
while (scanner->cur < scanner->len && is_space(scanner->src[scanner->cur]))
|
if (!consume_pair(scanner, "%}")) {
|
||||||
scanner->cur++;
|
|
||||||
if (scanner->cur+1 < scanner->len && scanner->src[scanner->cur] == '%' && scanner->src[scanner->cur+1] == '}')
|
|
||||||
scanner->cur += 2;
|
|
||||||
else {
|
|
||||||
report(error, "Missing closing %%} in {%% %s %%} block", block_name);
|
report(error, "Missing closing %%} in {%% %s %%} block", block_name);
|
||||||
return ESYNTAX;
|
return ESYNTAX;
|
||||||
}
|
}
|
||||||
@@ -824,41 +852,6 @@ 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)
|
||||||
{
|
{
|
||||||
@@ -888,17 +881,6 @@ 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--;
|
||||||
@@ -958,10 +940,6 @@ 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;
|
||||||
@@ -980,7 +958,6 @@ 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);
|
||||||
@@ -1024,7 +1001,7 @@ tinytemplate_compile(const char *src, size_t len,
|
|||||||
size_t raw_off = scanner.cur; // Start offset of the raw block
|
size_t raw_off = scanner.cur; // Start offset of the raw block
|
||||||
while (scanner.cur < scanner.len) {
|
while (scanner.cur < scanner.len) {
|
||||||
// Look for a "{" or the end
|
// Look for a "{" or the end
|
||||||
while (scanner.cur < scanner.len && scanner.src[scanner.cur] != '{')
|
while (follows_char(&scanner, '{'))
|
||||||
scanner.cur++;
|
scanner.cur++;
|
||||||
|
|
||||||
// If the end wasn't reached (a "{" was found)
|
// If the end wasn't reached (a "{" was found)
|
||||||
@@ -1076,15 +1053,15 @@ tinytemplate_compile(const char *src, size_t len,
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
value_can_be_considered_true(tinytemplate_type_t type,
|
value_can_be_considered_true(tinytemplate_type_t type,
|
||||||
tinytemplate_value_t value)
|
tinytemplate_union_t data)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
||||||
case TINYTEMPLATE_TYPE_INT:
|
case TINYTEMPLATE_TYPE_INT:
|
||||||
return value.as_int != 0;
|
return data.as_int != 0;
|
||||||
|
|
||||||
case TINYTEMPLATE_TYPE_FLOAT:
|
case TINYTEMPLATE_TYPE_FLOAT:
|
||||||
return value.as_float != 0;
|
return data.as_float != 0;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -1094,14 +1071,14 @@ value_can_be_considered_true(tinytemplate_type_t type,
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
tinytemplate_array_t iter;
|
tinytemplate_array_t iter;
|
||||||
tinytemplate_value_t child;
|
tinytemplate_value_t child;
|
||||||
tinytemplate_type_t ctype;
|
|
||||||
size_t next_index;
|
size_t next_index;
|
||||||
} iter_state_t;
|
} iter_state_t;
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
tinytemplate_eval(const char *src, const instr_t *program, void *userp,
|
tinytemplate_eval(const char *src, const instr_t *program,
|
||||||
tinytemplate_getter_t params,
|
void *userp, tinytemplate_getter_t params,
|
||||||
tinytemplate_callback_t callback, char *errmsg, size_t errmax)
|
tinytemplate_callback_t callback,
|
||||||
|
char *errmsg, size_t errmax)
|
||||||
{
|
{
|
||||||
error_t error = {.dst=errmsg, .max=errmax};
|
error_t error = {.dst=errmsg, .max=errmax};
|
||||||
|
|
||||||
@@ -1109,11 +1086,9 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
|
|||||||
size_t iter_depth = 0;
|
size_t iter_depth = 0;
|
||||||
|
|
||||||
tinytemplate_type_t types[TINYTEMPLATE_MAX_EXPR_DEPTH];
|
tinytemplate_type_t types[TINYTEMPLATE_MAX_EXPR_DEPTH];
|
||||||
tinytemplate_value_t stack[TINYTEMPLATE_MAX_EXPR_DEPTH];
|
tinytemplate_union_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) {
|
||||||
@@ -1128,13 +1103,6 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
|
|||||||
done = true;
|
done = true;
|
||||||
break;
|
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
|
||||||
// as an iteration target
|
// as an iteration target
|
||||||
@@ -1157,12 +1125,9 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
|
|||||||
// be run outside of an iteration.
|
// be run outside of an iteration.
|
||||||
|
|
||||||
iter_state_t *top_iter = &iter_stack[iter_depth-1];
|
iter_state_t *top_iter = &iter_stack[iter_depth-1];
|
||||||
|
|
||||||
tinytemplate_type_t type;
|
|
||||||
tinytemplate_value_t value;
|
tinytemplate_value_t value;
|
||||||
if (top_iter->iter.next(top_iter->iter.data, &type, &value)) {
|
if (top_iter->iter.next(top_iter->iter.data, &value)) {
|
||||||
top_iter->child = value;
|
top_iter->child = value;
|
||||||
top_iter->ctype = type;
|
|
||||||
top_iter->next_index++;
|
top_iter->next_index++;
|
||||||
} else {
|
} else {
|
||||||
index = instr->operands[0].as_size;
|
index = instr->operands[0].as_size;
|
||||||
@@ -1191,8 +1156,8 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
|
|||||||
assert(iter->next_index > 0); // CHLD can only be executed after
|
assert(iter->next_index > 0); // CHLD can only be executed after
|
||||||
// the iteration started.
|
// the iteration started.
|
||||||
|
|
||||||
stack[stack_depth] = iter->child;
|
stack[stack_depth] = iter->child.data;
|
||||||
types[stack_depth] = iter->ctype;
|
types[stack_depth] = iter->child.type;
|
||||||
stack_depth++;
|
stack_depth++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1237,14 +1202,13 @@ 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;
|
||||||
tinytemplate_type_t type;
|
|
||||||
tinytemplate_value_t value;
|
tinytemplate_value_t value;
|
||||||
if (!stack[stack_depth-1].as_dict.get(stack[stack_depth-1].as_dict.data, src + offset, length, &type, &value)) {
|
if (!stack[stack_depth-1].as_dict.get(stack[stack_depth-1].as_dict.data, src + offset, length, &value)) {
|
||||||
report(&error, "Key %.*s not in dict", (int) length, src + offset);
|
report(&error, "Key %.*s not in dict", (int) length, src + offset);
|
||||||
return ESYMBOL;
|
return ESYMBOL;
|
||||||
}
|
}
|
||||||
types[stack_depth-1] = type;
|
types[stack_depth-1] = value.type;
|
||||||
stack[stack_depth-1] = value;
|
stack[stack_depth-1] = value.data;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1279,11 +1243,10 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
|
|||||||
size_t varname_offset = instr->operands[0].as_size;
|
size_t varname_offset = instr->operands[0].as_size;
|
||||||
size_t varname_length = instr->operands[1].as_size;
|
size_t varname_length = instr->operands[1].as_size;
|
||||||
|
|
||||||
tinytemplate_type_t type;
|
|
||||||
tinytemplate_value_t value;
|
tinytemplate_value_t value;
|
||||||
if (params(userp, src + varname_offset, varname_length, &type, &value)) {
|
if (params(userp, src + varname_offset, varname_length, &value)) {
|
||||||
types[stack_depth] = type;
|
types[stack_depth] = value.type;
|
||||||
stack[stack_depth] = value;
|
stack[stack_depth] = value.data;
|
||||||
stack_depth++;
|
stack_depth++;
|
||||||
} else {
|
} else {
|
||||||
report(&error, "Undefined variable [%.*s]",
|
report(&error, "Undefined variable [%.*s]",
|
||||||
@@ -1310,8 +1273,7 @@ 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 + label.offset, label.length,
|
callback(userp, src + offset, length);
|
||||||
src + offset, length);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1326,8 +1288,7 @@ 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, src + label.offset, label.length,
|
callback(userp, text, (size_t) num);
|
||||||
text, (size_t) num);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1336,15 +1297,12 @@ 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, src + label.offset, label.length,
|
callback(userp, text, (size_t) num);
|
||||||
text, (size_t) num);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TINYTEMPLATE_TYPE_STRING:
|
case TINYTEMPLATE_TYPE_STRING:
|
||||||
callback(userp, src + label.offset, label.length,
|
callback(userp, stack[stack_depth-1].as_string.str, 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:
|
||||||
@@ -1672,3 +1630,36 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
|
|||||||
}
|
}
|
||||||
return DONE;
|
return DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tinytemplate_set_int(tinytemplate_value_t *dst, int64_t value)
|
||||||
|
{
|
||||||
|
dst->type = TINYTEMPLATE_TYPE_INT;
|
||||||
|
dst->data.as_int = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tinytemplate_set_float(tinytemplate_value_t *dst, float value)
|
||||||
|
{
|
||||||
|
dst->type = TINYTEMPLATE_TYPE_FLOAT;
|
||||||
|
dst->data.as_float = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tinytemplate_set_string(tinytemplate_value_t *dst, const char *str, size_t len)
|
||||||
|
{
|
||||||
|
dst->type = TINYTEMPLATE_TYPE_STRING;
|
||||||
|
dst->data.as_string.str = str;
|
||||||
|
dst->data.as_string.len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tinytemplate_set_array(tinytemplate_value_t *dst, void *data, tinytemplate_nextcallback_t next)
|
||||||
|
{
|
||||||
|
dst->type = TINYTEMPLATE_TYPE_ARRAY;
|
||||||
|
dst->data.as_array.data = data;
|
||||||
|
dst->data.as_array.next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tinytemplate_set_dict(tinytemplate_value_t *dst, void *data, tinytemplate_getter_t get)
|
||||||
|
{
|
||||||
|
dst->type = TINYTEMPLATE_TYPE_DICT;
|
||||||
|
dst->data.as_dict.data = data;
|
||||||
|
dst->data.as_dict.get = get;
|
||||||
|
}
|
||||||
+17
-5
@@ -25,11 +25,11 @@ typedef enum {
|
|||||||
TINYTEMPLATE_TYPE_STRING,
|
TINYTEMPLATE_TYPE_STRING,
|
||||||
} tinytemplate_type_t;
|
} tinytemplate_type_t;
|
||||||
|
|
||||||
typedef union tinytemplate_value_t tinytemplate_value_t;
|
typedef struct 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_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_value_t*);
|
||||||
typedef void (*tinytemplate_callback_t)(void *userp, const char *lbl, size_t lblen, const char *str, size_t len);
|
typedef void (*tinytemplate_callback_t)(void *userp, const char *str, size_t len);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *data;
|
void *data;
|
||||||
@@ -46,12 +46,17 @@ typedef struct {
|
|||||||
size_t len;
|
size_t len;
|
||||||
} tinytemplate_string_t;
|
} tinytemplate_string_t;
|
||||||
|
|
||||||
union tinytemplate_value_t {
|
typedef union {
|
||||||
int64_t as_int;
|
int64_t as_int;
|
||||||
double as_float;
|
double as_float;
|
||||||
tinytemplate_dict_t as_dict;
|
tinytemplate_dict_t as_dict;
|
||||||
tinytemplate_array_t as_array;
|
tinytemplate_array_t as_array;
|
||||||
tinytemplate_string_t as_string;
|
tinytemplate_string_t as_string;
|
||||||
|
} tinytemplate_union_t;
|
||||||
|
|
||||||
|
struct tinytemplate_value_t {
|
||||||
|
tinytemplate_type_t type;
|
||||||
|
tinytemplate_union_t data;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -86,4 +91,11 @@ tinytemplate_compile(const char *src, size_t len,
|
|||||||
tinytemplate_instr_t *program,
|
tinytemplate_instr_t *program,
|
||||||
size_t max_instr, size_t *num_instr,
|
size_t max_instr, size_t *num_instr,
|
||||||
char *errmsg, size_t errmax);
|
char *errmsg, size_t errmax);
|
||||||
|
|
||||||
|
void tinytemplate_set_int(tinytemplate_value_t *dst, int64_t value);
|
||||||
|
void tinytemplate_set_float(tinytemplate_value_t *dst, float value);
|
||||||
|
void tinytemplate_set_string(tinytemplate_value_t *dst, const char *str, size_t len);
|
||||||
|
void tinytemplate_set_array(tinytemplate_value_t *dst, void *data, tinytemplate_nextcallback_t next);
|
||||||
|
void tinytemplate_set_dict(tinytemplate_value_t *dst, void *data, tinytemplate_getter_t get);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user