From 5d66c96a190a396a1535c89bed4e33c2a005fe8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yaroslav=20de=20la=20Pe=C3=B1a=20Smirnov?= Date: Thu, 24 Mar 2022 01:04:02 +0300 Subject: Initial commit Basically it works, just needs some polishing and maybe a couple of features that I could actually use. Also probably better docs. Not sure if it will be of use to anybody besides me. --- include/ast.h | 221 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 include/ast.h (limited to 'include/ast.h') diff --git a/include/ast.h b/include/ast.h new file mode 100644 index 0000000..fe722bf --- /dev/null +++ b/include/ast.h @@ -0,0 +1,221 @@ +#ifndef ROSCHA_AST_H +#define ROSCHA_AST_H + +#include "hmap.h" +#include "token.h" +#include "vector.h" + +#include "sds/sds.h" + +/* AST node structures */ + +enum block_type { + BLOCK_CONTENT, + BLOCK_VARIABLE, + BLOCK_TAG, +}; + +enum tag_type { + TAG_IF, + TAG_FOR, + TAG_BLOCK, + TAG_EXTENDS, + /* keyword-only tags */ + TAG_BREAK, + TAG_CLOSE, +}; + +enum expression_type { + EXPRESSION_IDENT, + EXPRESSION_INT, + EXPRESSION_BOOL, + EXPRESSION_STRING, + EXPRESSION_PREFIX, + EXPRESSION_INFIX, + EXPRESSION_MAPKEY, + EXPRESSION_INDEX, +}; + +struct ident { + struct token token; +}; + +struct integer { + struct token token; + int64_t value; +}; + +struct boolean { + struct token token; + bool value; +}; + +struct string { + struct token token; + struct slice value; +}; + +struct prefix { + struct token token; + struct slice operator; + struct expression *right; +}; + +struct infix { + struct token token; + struct slice operator; + struct expression *left; + struct expression *right; +}; + +/* Either a map key (map.k) or an array/vector index (arr[i]) */ +struct indexkey { + struct token token; + struct expression *left; + struct expression *key; +}; + +struct expression { + enum expression_type type; + union { + struct token token; + struct ident ident; + struct integer integer; + struct boolean boolean; + struct string string; + struct prefix prefix; + struct infix infix; + struct indexkey indexkey; + }; +}; + +/* if, elif, else branch */ +struct branch { + struct token token; + /* if condition is null it means it is an else branch */ + struct expression *condition; + struct vector *subblocks; + /* elif or else */ + struct branch *next; +}; + +/* start of if, elif, else */ +struct cond { + struct token token; + struct branch *root; +}; + +/* for loop */ +struct loop { + struct token token; + struct ident item; + struct expression *seq; + struct vector *subblocks; +}; + +/* template block {% block ... %} */ +struct tblock { + struct token token; + struct ident name; + struct vector *subblocks; +}; + +/* {% extends ... %} */ +struct parent { + struct token token; + struct string *name; +}; + +/* {% ... %} blocks */ +struct tag { + union{ + struct token token; + struct cond cond; + struct loop loop; + struct tblock tblock; + struct parent parent; + }; + enum tag_type type; +}; + +/* {{ ... }} blocks */ +struct variable { + struct token token; + struct expression *expression; +}; + +/* blocks with content that doesn't need evaluation */ +struct content { + struct token token; +}; + +/* + * The template is divided into blocks or chunks which are either plain text + * content, {% %} tags or {{ }} variables. Not to be confused with + * {% block ... %} tags. + */ +struct block { + union { + struct token token; + struct content content; + struct tag tag; + struct variable variable; + }; + enum block_type type; +}; + +/* Root of the AST */ +struct template { + /* + * The name of the template, might be a file name; used to identifiy the + * template in error messages. Will be free'd by template_destroy function + * so a copy should be made if it is needed after destroying the AST. + */ + char *name; + /* + * The source text of the template before parsing. Should be free'd manually + * by the caller of roscha_env_render. + */ + char *source; + /* + * struct that holds references to {% block ... %} tags, for easier/faster + * access to said blocks. + */ + struct hmap *tblocks; + /* + * Holds a child template if there is one. Populated during evaluation, + * NULL'ed after evaluation, since a parent template can have different + * children depending on the context. + */ + struct template *child; + /* vector of blocks */ + struct vector *blocks; +}; + +/* Concatenate to an SDS string a human friendly representation of the node */ + +sds expression_string(struct expression *, sds str); + +sds tag_string(struct tag *, sds str); + +sds variable_string(struct variable *, sds str); + +sds content_string(struct content *, sds str); + +sds block_string(struct block *, sds str); + +sds template_string(struct template *, sds str); + +/* Free all memory related with the objects */ + +void branch_destroy(struct branch *); + +void tag_destroy(struct tag *); + +void expression_destroy(struct expression *); + +void block_destroy(struct block *); + +void template_destroy(struct template *); + +#endif -- cgit v1.2.3