| author | |
| committer | |
| log | 3b4a2afb65d4ebb5292c230bada84408758e564c |
| tree | a07801709a0b1531f742e16e83e77d73ce873de7 |
| parent | a22bc8d20a1ad9158a28f29f6f866b0008b11e3e |
8 files changed, 389 insertions(+), 22 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -29,6 +29,7 @@ set(ZIG_SOURCES |
| 29 | 29 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" |
| 30 | 30 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" |
| 31 | 31 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 32 | "${CMAKE_SOURCE_DIR}/src/codegen.cpp" | |
| 32 | 33 | ) |
| 33 | 34 | |
| 34 | 35 | set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h") |
src/buffer.hpp+9| ... | ... | @@ -149,5 +149,14 @@ static inline Buf *buf_dirname(Buf *buf) { |
| 149 | 149 | return buf_create_from_mem("", 0); |
| 150 | 150 | } |
| 151 | 151 | |
| 152 | static inline uint32_t buf_hash(Buf *buf) { | |
| 153 | // FNV 32-bit hash | |
| 154 | uint32_t h = 2166136261; | |
| 155 | for (int i = 0; i < buf_len(buf); i += 1) { | |
| 156 | h = h ^ ((uint8_t)buf->list.at(i)); | |
| 157 | h = h * 16777619; | |
| 158 | } | |
| 159 | return h; | |
| 160 | } | |
| 152 | 161 | |
| 153 | 162 | #endif |
src/codegen.cpp created+87| ... | ... | @@ -0,0 +1,87 @@ |
| 1 | #include "codegen.hpp" | |
| 2 | #include "hash_map.hpp" | |
| 3 | ||
| 4 | #include <stdio.h> | |
| 5 | ||
| 6 | struct CodeGen { | |
| 7 | AstNode *root; | |
| 8 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> fn_decls; | |
| 9 | ZigList<ErrorMsg> errors; | |
| 10 | }; | |
| 11 | ||
| 12 | CodeGen *create_codegen(AstNode *root) { | |
| 13 | CodeGen *g = allocate<CodeGen>(1); | |
| 14 | g->root = root; | |
| 15 | g->fn_decls.init(32); | |
| 16 | return g; | |
| 17 | } | |
| 18 | ||
| 19 | static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { | |
| 20 | g->errors.add_one(); | |
| 21 | ErrorMsg *last_msg = &g->errors.last(); | |
| 22 | last_msg->line_start = node->line; | |
| 23 | last_msg->column_start = node->column; | |
| 24 | last_msg->line_end = -1; | |
| 25 | last_msg->column_end = -1; | |
| 26 | last_msg->msg = msg; | |
| 27 | } | |
| 28 | ||
| 29 | static void analyze_node(CodeGen *g, AstNode *node) { | |
| 30 | switch (node->type) { | |
| 31 | case NodeTypeRoot: | |
| 32 | for (int i = 0; i < node->data.root.fn_decls.length; i += 1) { | |
| 33 | AstNode *child = node->data.root.fn_decls.at(i); | |
| 34 | analyze_node(g, child); | |
| 35 | } | |
| 36 | break; | |
| 37 | case NodeTypeFnDecl: | |
| 38 | { | |
| 39 | auto entry = g->fn_decls.maybe_get(&node->data.fn_decl.name); | |
| 40 | if (entry) { | |
| 41 | add_node_error(g, node, | |
| 42 | buf_sprintf("redefinition of '%s'", buf_ptr(&node->data.fn_decl.name))); | |
| 43 | } else { | |
| 44 | g->fn_decls.put(&node->data.fn_decl.name, node); | |
| 45 | for (int i = 0; i < node->data.fn_decl.params.length; i += 1) { | |
| 46 | AstNode *child = node->data.fn_decl.params.at(i); | |
| 47 | analyze_node(g, child); | |
| 48 | } | |
| 49 | analyze_node(g, node->data.fn_decl.return_type); | |
| 50 | analyze_node(g, node->data.fn_decl.body); | |
| 51 | } | |
| 52 | break; | |
| 53 | } | |
| 54 | case NodeTypeParamDecl: | |
| 55 | analyze_node(g, node->data.param_decl.type); | |
| 56 | break; | |
| 57 | case NodeTypeType: | |
| 58 | break; | |
| 59 | case NodeTypePointerType: | |
| 60 | break; | |
| 61 | case NodeTypeBlock: | |
| 62 | break; | |
| 63 | case NodeTypeStatement: | |
| 64 | break; | |
| 65 | case NodeTypeExpressionStatement: | |
| 66 | break; | |
| 67 | case NodeTypeReturnStatement: | |
| 68 | break; | |
| 69 | case NodeTypeExpression: | |
| 70 | break; | |
| 71 | case NodeTypeFnCall: | |
| 72 | break; | |
| 73 | } | |
| 74 | } | |
| 75 | ||
| 76 | void semantic_analyze(CodeGen *g) { | |
| 77 | // Pass 1. | |
| 78 | analyze_node(g, g->root); | |
| 79 | } | |
| 80 | ||
| 81 | void code_gen(CodeGen *g) { | |
| 82 | ||
| 83 | } | |
| 84 | ||
| 85 | ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g) { | |
| 86 | return &g->errors; | |
| 87 | } |
src/codegen.hpp created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | #ifndef ZIG_CODEGEN_HPP | |
| 2 | #define ZIG_CODEGEN_HPP | |
| 3 | ||
| 4 | #include "parser.hpp" | |
| 5 | ||
| 6 | struct CodeGen; | |
| 7 | ||
| 8 | struct ErrorMsg { | |
| 9 | int line_start; | |
| 10 | int column_start; | |
| 11 | int line_end; | |
| 12 | int column_end; | |
| 13 | Buf *msg; | |
| 14 | }; | |
| 15 | ||
| 16 | ||
| 17 | CodeGen *create_codegen(AstNode *root); | |
| 18 | ||
| 19 | void semantic_analyze(CodeGen *g); | |
| 20 | ||
| 21 | void code_gen(CodeGen *g); | |
| 22 | ||
| 23 | ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g); | |
| 24 | ||
| 25 | #endif |
src/hash_map.hpp created+220| ... | ... | @@ -0,0 +1,220 @@ |
| 1 | #ifndef ZIG_HASH_MAP_HPP | |
| 2 | #define ZIG_HASH_MAP_HPP | |
| 3 | ||
| 4 | #include "util.hpp" | |
| 5 | ||
| 6 | #include <stdint.h> | |
| 7 | ||
| 8 | template<typename K, typename V, uint32_t (*HashFunction)(K key), bool (*EqualFn)(K a, K b)> | |
| 9 | class HashMap { | |
| 10 | public: | |
| 11 | void init(int capacity) { | |
| 12 | init_capacity(capacity); | |
| 13 | } | |
| 14 | void deinit(void) { | |
| 15 | free(_entries); | |
| 16 | } | |
| 17 | ||
| 18 | struct Entry { | |
| 19 | bool used; | |
| 20 | int distance_from_start_index; | |
| 21 | K key; | |
| 22 | V value; | |
| 23 | }; | |
| 24 | ||
| 25 | void clear() { | |
| 26 | for (int i = 0; i < _capacity; i += 1) { | |
| 27 | _entries[i].used = false; | |
| 28 | } | |
| 29 | _size = 0; | |
| 30 | _max_distance_from_start_index = 0; | |
| 31 | _modification_count += 1; | |
| 32 | } | |
| 33 | ||
| 34 | int size() const { | |
| 35 | return _size; | |
| 36 | } | |
| 37 | ||
| 38 | void put(const K &key, const V &value) { | |
| 39 | _modification_count += 1; | |
| 40 | internal_put(key, value); | |
| 41 | ||
| 42 | // if we get too full (80%), double the capacity | |
| 43 | if (_size * 5 >= _capacity * 4) { | |
| 44 | Entry *old_entries = _entries; | |
| 45 | int old_capacity = _capacity; | |
| 46 | init_capacity(_capacity * 2); | |
| 47 | // dump all of the old elements into the new table | |
| 48 | for (int i = 0; i < old_capacity; i += 1) { | |
| 49 | Entry *old_entry = &old_entries[i]; | |
| 50 | if (old_entry->used) | |
| 51 | internal_put(old_entry->key, old_entry->value); | |
| 52 | } | |
| 53 | free(old_entries); | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | const V &get(const K &key) const { | |
| 58 | Entry *entry = internal_get(key); | |
| 59 | if (!entry) | |
| 60 | zig_panic("key not found"); | |
| 61 | return entry->value; | |
| 62 | } | |
| 63 | ||
| 64 | Entry *maybe_get(const K &key) const { | |
| 65 | return internal_get(key); | |
| 66 | } | |
| 67 | ||
| 68 | void remove(const K &key) { | |
| 69 | _modification_count += 1; | |
| 70 | int start_index = key_to_index(key); | |
| 71 | for (int roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { | |
| 72 | int index = (start_index + roll_over) % _capacity; | |
| 73 | Entry *entry = &_entries[index]; | |
| 74 | ||
| 75 | if (!entry->used) | |
| 76 | zig_panic("key not found"); | |
| 77 | ||
| 78 | if (!EqualFn(entry->key, key)) | |
| 79 | continue; | |
| 80 | ||
| 81 | for (; roll_over < _capacity; roll_over += 1) { | |
| 82 | int next_index = (start_index + roll_over + 1) % _capacity; | |
| 83 | Entry *next_entry = &_entries[next_index]; | |
| 84 | if (!next_entry->used || next_entry->distance_from_start_index == 0) { | |
| 85 | entry->used = false; | |
| 86 | _size -= 1; | |
| 87 | return; | |
| 88 | } | |
| 89 | *entry = *next_entry; | |
| 90 | entry->distance_from_start_index -= 1; | |
| 91 | entry = next_entry; | |
| 92 | } | |
| 93 | zig_panic("shifting everything in the table"); | |
| 94 | } | |
| 95 | zig_panic("key not found"); | |
| 96 | } | |
| 97 | ||
| 98 | class Iterator { | |
| 99 | public: | |
| 100 | Entry *next() { | |
| 101 | if (_inital_modification_count != _table->_modification_count) | |
| 102 | zig_panic("concurrent modification"); | |
| 103 | if (_count >= _table->size()) | |
| 104 | return NULL; | |
| 105 | for (; _index < _table->_capacity; _index += 1) { | |
| 106 | Entry *entry = &_table->_entries[_index]; | |
| 107 | if (entry->used) { | |
| 108 | _index += 1; | |
| 109 | _count += 1; | |
| 110 | return entry; | |
| 111 | } | |
| 112 | } | |
| 113 | zig_panic("no next item"); | |
| 114 | } | |
| 115 | private: | |
| 116 | const HashMap * _table; | |
| 117 | // how many items have we returned | |
| 118 | int _count = 0; | |
| 119 | // iterator through the entry array | |
| 120 | int _index = 0; | |
| 121 | // used to detect concurrent modification | |
| 122 | uint32_t _inital_modification_count; | |
| 123 | Iterator(const HashMap * table) : | |
| 124 | _table(table), _inital_modification_count(table->_modification_count) { | |
| 125 | } | |
| 126 | friend HashMap; | |
| 127 | }; | |
| 128 | ||
| 129 | // you must not modify the underlying HashMap while this iterator is still in use | |
| 130 | Iterator entry_iterator() const { | |
| 131 | return Iterator(this); | |
| 132 | } | |
| 133 | ||
| 134 | private: | |
| 135 | ||
| 136 | Entry *_entries; | |
| 137 | int _capacity; | |
| 138 | int _size; | |
| 139 | int _max_distance_from_start_index; | |
| 140 | // this is used to detect bugs where a hashtable is edited while an iterator is running. | |
| 141 | uint32_t _modification_count = 0; | |
| 142 | ||
| 143 | void init_capacity(int capacity) { | |
| 144 | _capacity = capacity; | |
| 145 | _entries = allocate<Entry>(_capacity); | |
| 146 | _size = 0; | |
| 147 | _max_distance_from_start_index = 0; | |
| 148 | for (int i = 0; i < _capacity; i += 1) { | |
| 149 | _entries[i].used = false; | |
| 150 | } | |
| 151 | } | |
| 152 | ||
| 153 | void internal_put(K key, V value) { | |
| 154 | int start_index = key_to_index(key); | |
| 155 | for (int roll_over = 0, distance_from_start_index = 0; | |
| 156 | roll_over < _capacity; roll_over += 1, distance_from_start_index += 1) | |
| 157 | { | |
| 158 | int index = (start_index + roll_over) % _capacity; | |
| 159 | Entry *entry = &_entries[index]; | |
| 160 | ||
| 161 | if (entry->used && !EqualFn(entry->key, key)) { | |
| 162 | if (entry->distance_from_start_index < distance_from_start_index) { | |
| 163 | // robin hood to the rescue | |
| 164 | Entry tmp = *entry; | |
| 165 | if (distance_from_start_index > _max_distance_from_start_index) | |
| 166 | _max_distance_from_start_index = distance_from_start_index; | |
| 167 | *entry = { | |
| 168 | true, | |
| 169 | distance_from_start_index, | |
| 170 | key, | |
| 171 | value, | |
| 172 | }; | |
| 173 | key = tmp.key; | |
| 174 | value = tmp.value; | |
| 175 | distance_from_start_index = tmp.distance_from_start_index; | |
| 176 | } | |
| 177 | continue; | |
| 178 | } | |
| 179 | ||
| 180 | if (!entry->used) { | |
| 181 | // adding an entry. otherwise overwriting old value with | |
| 182 | // same key | |
| 183 | _size += 1; | |
| 184 | } | |
| 185 | ||
| 186 | if (distance_from_start_index > _max_distance_from_start_index) | |
| 187 | _max_distance_from_start_index = distance_from_start_index; | |
| 188 | *entry = { | |
| 189 | true, | |
| 190 | distance_from_start_index, | |
| 191 | key, | |
| 192 | value, | |
| 193 | }; | |
| 194 | return; | |
| 195 | } | |
| 196 | zig_panic("put into a full HashMap"); | |
| 197 | } | |
| 198 | ||
| 199 | ||
| 200 | Entry *internal_get(const K &key) const { | |
| 201 | int start_index = key_to_index(key); | |
| 202 | for (int roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { | |
| 203 | int index = (start_index + roll_over) % _capacity; | |
| 204 | Entry *entry = &_entries[index]; | |
| 205 | ||
| 206 | if (!entry->used) | |
| 207 | return NULL; | |
| 208 | ||
| 209 | if (EqualFn(entry->key, key)) | |
| 210 | return entry; | |
| 211 | } | |
| 212 | return NULL; | |
| 213 | } | |
| 214 | ||
| 215 | int key_to_index(const K &key) const { | |
| 216 | return (int)(HashFunction(key) % ((uint32_t)_capacity)); | |
| 217 | } | |
| 218 | }; | |
| 219 | ||
| 220 | #endif |
src/main.cpp+24-6| ... | ... | @@ -12,6 +12,7 @@ |
| 12 | 12 | #include "parser.hpp" |
| 13 | 13 | #include "tokenizer.hpp" |
| 14 | 14 | #include "error.hpp" |
| 15 | #include "codegen.hpp" | |
| 15 | 16 | |
| 16 | 17 | #include <stdio.h> |
| 17 | 18 | #include <string.h> |
| ... | ... | @@ -75,24 +76,41 @@ static int build(const char *arg0, const char *in_file, const char *out_file, Zi |
| 75 | 76 | cur_dir_path = buf_dirname(buf_create_from_str(in_file)); |
| 76 | 77 | } |
| 77 | 78 | |
| 78 | Buf *in_data = fetch_file(in_f); | |
| 79 | ||
| 80 | 79 | fprintf(stderr, "Original source:\n"); |
| 81 | 80 | fprintf(stderr, "----------------\n"); |
| 81 | Buf *in_data = fetch_file(in_f); | |
| 82 | 82 | fprintf(stderr, "%s\n", buf_ptr(in_data)); |
| 83 | 83 | |
| 84 | ZigList<Token> *tokens = tokenize(in_data, cur_dir_path); | |
| 85 | ||
| 86 | 84 | fprintf(stderr, "\nTokens:\n"); |
| 87 | 85 | fprintf(stderr, "---------\n"); |
| 86 | ZigList<Token> *tokens = tokenize(in_data, cur_dir_path); | |
| 88 | 87 | print_tokens(in_data, tokens); |
| 89 | 88 | |
| 90 | AstNode *root = ast_parse(in_data, tokens); | |
| 91 | assert(root); | |
| 92 | 89 | fprintf(stderr, "\nAST:\n"); |
| 93 | 90 | fprintf(stderr, "------\n"); |
| 91 | AstNode *root = ast_parse(in_data, tokens); | |
| 92 | assert(root); | |
| 94 | 93 | ast_print(root, 0); |
| 95 | 94 | |
| 95 | fprintf(stderr, "\nSemantic Analysis:\n"); | |
| 96 | fprintf(stderr, "--------------------\n"); | |
| 97 | CodeGen *codegen = create_codegen(root); | |
| 98 | semantic_analyze(codegen); | |
| 99 | ZigList<ErrorMsg> *errors = codegen_error_messages(codegen); | |
| 100 | if (errors->length == 0) { | |
| 101 | fprintf(stderr, "OK\n"); | |
| 102 | } else { | |
| 103 | for (int i = 0; i < errors->length; i += 1) { | |
| 104 | ErrorMsg *err = &errors->at(i); | |
| 105 | fprintf(stderr, "Error: Line %d, column %d: %s\n", err->line_start, err->column_start, | |
| 106 | buf_ptr(err->msg)); | |
| 107 | } | |
| 108 | return 1; | |
| 109 | } | |
| 110 | ||
| 111 | fprintf(stderr, "\nCode Generation:\n"); | |
| 112 | fprintf(stderr, "------------------\n"); | |
| 113 | code_gen(codegen); | |
| 96 | 114 | |
| 97 | 115 | return 0; |
| 98 | 116 | } |
src/parser.cpp+21-16| ... | ... | @@ -133,9 +133,11 @@ struct ParseContext { |
| 133 | 133 | ZigList<Token> *tokens; |
| 134 | 134 | }; |
| 135 | 135 | |
| 136 | static AstNode *ast_create_node(NodeType type) { | |
| 136 | static AstNode *ast_create_node(NodeType type, Token *first_token) { | |
| 137 | 137 | AstNode *node = allocate<AstNode>(1); |
| 138 | 138 | node->type = type; |
| 139 | node->line = first_token->start_line; | |
| 140 | node->column = first_token->start_column; | |
| 139 | 141 | return node; |
| 140 | 142 | } |
| 141 | 143 | |
| ... | ... | @@ -163,11 +165,11 @@ Type : token(Symbol) | PointerType; |
| 163 | 165 | PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type; |
| 164 | 166 | */ |
| 165 | 167 | static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token_index) { |
| 166 | AstNode *node = ast_create_node(NodeTypeType); | |
| 167 | ||
| 168 | 168 | Token *token = &pc->tokens->at(token_index); |
| 169 | 169 | token_index += 1; |
| 170 | 170 | |
| 171 | AstNode *node = ast_create_node(NodeTypeType, token); | |
| 172 | ||
| 171 | 173 | if (token->id == TokenIdSymbol) { |
| 172 | 174 | node->data.type.type = AstNodeTypeTypePrimitive; |
| 173 | 175 | ast_buf_from_token(pc, token, &node->data.type.primitive_name); |
| ... | ... | @@ -197,12 +199,13 @@ ParamDecl<node> : token(Symbol) token(Colon) Type { |
| 197 | 199 | }; |
| 198 | 200 | */ |
| 199 | 201 | static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new_token_index) { |
| 200 | AstNode *node = ast_create_node(NodeTypeParamDecl); | |
| 201 | ||
| 202 | 202 | Token *param_name = &pc->tokens->at(token_index); |
| 203 | 203 | token_index += 1; |
| 204 | 204 | ast_expect_token(pc, param_name, TokenIdSymbol); |
| 205 | 205 | |
| 206 | AstNode *node = ast_create_node(NodeTypeParamDecl, param_name); | |
| 207 | ||
| 208 | ||
| 206 | 209 | ast_buf_from_token(pc, param_name, &node->data.param_decl.name); |
| 207 | 210 | |
| 208 | 211 | Token *colon = &pc->tokens->at(token_index); |
| ... | ... | @@ -280,12 +283,13 @@ static void ast_parse_fn_call_param_list(ParseContext *pc, int token_index, int |
| 280 | 283 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) ; |
| 281 | 284 | */ |
| 282 | 285 | static AstNode *ast_parse_fn_call(ParseContext *pc, int token_index, int *new_token_index) { |
| 283 | AstNode *node = ast_create_node(NodeTypeFnCall); | |
| 284 | ||
| 285 | 286 | Token *fn_name = &pc->tokens->at(token_index); |
| 286 | 287 | token_index += 1; |
| 287 | 288 | ast_expect_token(pc, fn_name, TokenIdSymbol); |
| 288 | 289 | |
| 290 | AstNode *node = ast_create_node(NodeTypeFnCall, fn_name); | |
| 291 | ||
| 292 | ||
| 289 | 293 | ast_buf_from_token(pc, fn_name, &node->data.fn_call.name); |
| 290 | 294 | |
| 291 | 295 | ast_parse_fn_call_param_list(pc, token_index, &token_index, &node->data.fn_call.params); |
| ... | ... | @@ -295,9 +299,8 @@ static AstNode *ast_parse_fn_call(ParseContext *pc, int token_index, int *new_to |
| 295 | 299 | } |
| 296 | 300 | |
| 297 | 301 | static AstNode *ast_parse_expression(ParseContext *pc, int token_index, int *new_token_index) { |
| 298 | AstNode *node = ast_create_node(NodeTypeExpression); | |
| 299 | ||
| 300 | 302 | Token *token = &pc->tokens->at(token_index); |
| 303 | AstNode *node = ast_create_node(NodeTypeExpression, token); | |
| 301 | 304 | if (token->id == TokenIdSymbol) { |
| 302 | 305 | node->data.expression.type = AstNodeExpressionTypeFnCall; |
| 303 | 306 | node->data.expression.data.fn_call = ast_parse_fn_call(pc, token_index, &token_index); |
| ... | ... | @@ -329,9 +332,9 @@ Expression : token(Number) | token(String) | FnCall ; |
| 329 | 332 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) ; |
| 330 | 333 | */ |
| 331 | 334 | static AstNode *ast_parse_statement(ParseContext *pc, int token_index, int *new_token_index) { |
| 332 | AstNode *node = ast_create_node(NodeTypeStatement); | |
| 333 | ||
| 334 | 335 | Token *token = &pc->tokens->at(token_index); |
| 336 | AstNode *node = ast_create_node(NodeTypeStatement, token); | |
| 337 | ||
| 335 | 338 | if (token->id == TokenIdKeywordReturn) { |
| 336 | 339 | token_index += 1; |
| 337 | 340 | node->data.statement.type = AstNodeStatementTypeReturn; |
| ... | ... | @@ -362,12 +365,13 @@ static AstNode *ast_parse_statement(ParseContext *pc, int token_index, int *new_ |
| 362 | 365 | Block : token(LBrace) many(Statement) token(RBrace); |
| 363 | 366 | */ |
| 364 | 367 | static AstNode *ast_parse_block(ParseContext *pc, int token_index, int *new_token_index) { |
| 365 | AstNode *node = ast_create_node(NodeTypeBlock); | |
| 366 | ||
| 367 | 368 | Token *l_brace = &pc->tokens->at(token_index); |
| 368 | 369 | token_index += 1; |
| 369 | 370 | ast_expect_token(pc, l_brace, TokenIdLBrace); |
| 370 | 371 | |
| 372 | AstNode *node = ast_create_node(NodeTypeBlock, l_brace); | |
| 373 | ||
| 374 | ||
| 371 | 375 | for (;;) { |
| 372 | 376 | Token *token = &pc->tokens->at(token_index); |
| 373 | 377 | if (token->id == TokenIdRBrace) { |
| ... | ... | @@ -386,12 +390,13 @@ static AstNode *ast_parse_block(ParseContext *pc, int token_index, int *new_toke |
| 386 | 390 | FnDecl : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) Block; |
| 387 | 391 | */ |
| 388 | 392 | static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) { |
| 389 | AstNode *node = ast_create_node(NodeTypeFnDecl); | |
| 390 | ||
| 391 | 393 | Token *fn_token = &pc->tokens->at(token_index); |
| 392 | 394 | token_index += 1; |
| 393 | 395 | ast_expect_token(pc, fn_token, TokenIdKeywordFn); |
| 394 | 396 | |
| 397 | AstNode *node = ast_create_node(NodeTypeFnDecl, fn_token); | |
| 398 | ||
| 399 | ||
| 395 | 400 | Token *fn_name = &pc->tokens->at(token_index); |
| 396 | 401 | token_index += 1; |
| 397 | 402 | ast_expect_token(pc, fn_name, TokenIdSymbol); |
| ... | ... | @@ -437,7 +442,7 @@ static void ast_parse_fn_decl_list(ParseContext *pc, int token_index, ZigList<As |
| 437 | 442 | AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { |
| 438 | 443 | ParseContext pc = {0}; |
| 439 | 444 | pc.buf = buf; |
| 440 | pc.root = ast_create_node(NodeTypeRoot); | |
| 445 | pc.root = ast_create_node(NodeTypeRoot, &tokens->at(0)); | |
| 441 | 446 | pc.tokens = tokens; |
| 442 | 447 | |
| 443 | 448 | int new_token_index; |
src/parser.hpp+2| ... | ... | @@ -97,6 +97,8 @@ struct AstNodeFnCall { |
| 97 | 97 | struct AstNode { |
| 98 | 98 | enum NodeType type; |
| 99 | 99 | AstNode *parent; |
| 100 | int line; | |
| 101 | int column; | |
| 100 | 102 | union { |
| 101 | 103 | AstNodeRoot root; |
| 102 | 104 | AstNodeFnDecl fn_decl; |