| 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,6 +29,7 @@ set(ZIG_SOURCES |
| 29 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" | 29 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" |
| 30 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" | 30 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" |
| 31 | "${CMAKE_SOURCE_DIR}/src/util.cpp" | 31 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 32 | "${CMAKE_SOURCE_DIR}/src/codegen.cpp" | ||
| 32 | ) | 33 | ) |
| 33 | 34 | ||
| 34 | set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h") | 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,5 +149,14 @@ static inline Buf *buf_dirname(Buf *buf) { |
| 149 | return buf_create_from_mem("", 0); | 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 | #endif | 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,6 +12,7 @@ |
| 12 | #include "parser.hpp" | 12 | #include "parser.hpp" |
| 13 | #include "tokenizer.hpp" | 13 | #include "tokenizer.hpp" |
| 14 | #include "error.hpp" | 14 | #include "error.hpp" |
| 15 | #include "codegen.hpp" | ||
| 15 | 16 | ||
| 16 | #include <stdio.h> | 17 | #include <stdio.h> |
| 17 | #include <string.h> | 18 | #include <string.h> |
| ... | @@ -75,24 +76,41 @@ static int build(const char *arg0, const char *in_file, const char *out_file, Zi | ... | @@ -75,24 +76,41 @@ static int build(const char *arg0, const char *in_file, const char *out_file, Zi |
| 75 | cur_dir_path = buf_dirname(buf_create_from_str(in_file)); | 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 | fprintf(stderr, "Original source:\n"); | 79 | fprintf(stderr, "Original source:\n"); |
| 81 | fprintf(stderr, "----------------\n"); | 80 | fprintf(stderr, "----------------\n"); |
| 81 | Buf *in_data = fetch_file(in_f); | ||
| 82 | fprintf(stderr, "%s\n", buf_ptr(in_data)); | 82 | fprintf(stderr, "%s\n", buf_ptr(in_data)); |
| 83 | 83 | ||
| 84 | ZigList<Token> *tokens = tokenize(in_data, cur_dir_path); | ||
| 85 | |||
| 86 | fprintf(stderr, "\nTokens:\n"); | 84 | fprintf(stderr, "\nTokens:\n"); |
| 87 | fprintf(stderr, "---------\n"); | 85 | fprintf(stderr, "---------\n"); |
| 86 | ZigList<Token> *tokens = tokenize(in_data, cur_dir_path); | ||
| 88 | print_tokens(in_data, tokens); | 87 | print_tokens(in_data, tokens); |
| 89 | 88 | ||
| 90 | AstNode *root = ast_parse(in_data, tokens); | ||
| 91 | assert(root); | ||
| 92 | fprintf(stderr, "\nAST:\n"); | 89 | fprintf(stderr, "\nAST:\n"); |
| 93 | fprintf(stderr, "------\n"); | 90 | fprintf(stderr, "------\n"); |
| 91 | AstNode *root = ast_parse(in_data, tokens); | ||
| 92 | assert(root); | ||
| 94 | ast_print(root, 0); | 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 | return 0; | 115 | return 0; |
| 98 | } | 116 | } |
src/parser.cpp+21-16| ... | @@ -133,9 +133,11 @@ struct ParseContext { | ... | @@ -133,9 +133,11 @@ struct ParseContext { |
| 133 | ZigList<Token> *tokens; | 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 | AstNode *node = allocate<AstNode>(1); | 137 | AstNode *node = allocate<AstNode>(1); |
| 138 | node->type = type; | 138 | node->type = type; |
| 139 | node->line = first_token->start_line; | ||
| 140 | node->column = first_token->start_column; | ||
| 139 | return node; | 141 | return node; |
| 140 | } | 142 | } |
| 141 | 143 | ||
| ... | @@ -163,11 +165,11 @@ Type : token(Symbol) | PointerType; | ... | @@ -163,11 +165,11 @@ Type : token(Symbol) | PointerType; |
| 163 | PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type; | 165 | PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type; |
| 164 | */ | 166 | */ |
| 165 | static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token_index) { | 167 | static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token_index) { |
| 166 | AstNode *node = ast_create_node(NodeTypeType); | ||
| 167 | |||
| 168 | Token *token = &pc->tokens->at(token_index); | 168 | Token *token = &pc->tokens->at(token_index); |
| 169 | token_index += 1; | 169 | token_index += 1; |
| 170 | 170 | ||
| 171 | AstNode *node = ast_create_node(NodeTypeType, token); | ||
| 172 | |||
| 171 | if (token->id == TokenIdSymbol) { | 173 | if (token->id == TokenIdSymbol) { |
| 172 | node->data.type.type = AstNodeTypeTypePrimitive; | 174 | node->data.type.type = AstNodeTypeTypePrimitive; |
| 173 | ast_buf_from_token(pc, token, &node->data.type.primitive_name); | 175 | ast_buf_from_token(pc, token, &node->data.type.primitive_name); |
| ... | @@ -197,12 +199,13 @@ ParamDecl<node> : token(Symbol) token(Colon) Type { | ... | @@ -197,12 +199,13 @@ ParamDecl<node> : token(Symbol) token(Colon) Type { |
| 197 | }; | 199 | }; |
| 198 | */ | 200 | */ |
| 199 | static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new_token_index) { | 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 | Token *param_name = &pc->tokens->at(token_index); | 202 | Token *param_name = &pc->tokens->at(token_index); |
| 203 | token_index += 1; | 203 | token_index += 1; |
| 204 | ast_expect_token(pc, param_name, TokenIdSymbol); | 204 | ast_expect_token(pc, param_name, TokenIdSymbol); |
| 205 | 205 | ||
| 206 | AstNode *node = ast_create_node(NodeTypeParamDecl, param_name); | ||
| 207 | |||
| 208 | |||
| 206 | ast_buf_from_token(pc, param_name, &node->data.param_decl.name); | 209 | ast_buf_from_token(pc, param_name, &node->data.param_decl.name); |
| 207 | 210 | ||
| 208 | Token *colon = &pc->tokens->at(token_index); | 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,12 +283,13 @@ static void ast_parse_fn_call_param_list(ParseContext *pc, int token_index, int |
| 280 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) ; | 283 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) ; |
| 281 | */ | 284 | */ |
| 282 | static AstNode *ast_parse_fn_call(ParseContext *pc, int token_index, int *new_token_index) { | 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 | Token *fn_name = &pc->tokens->at(token_index); | 286 | Token *fn_name = &pc->tokens->at(token_index); |
| 286 | token_index += 1; | 287 | token_index += 1; |
| 287 | ast_expect_token(pc, fn_name, TokenIdSymbol); | 288 | ast_expect_token(pc, fn_name, TokenIdSymbol); |
| 288 | 289 | ||
| 290 | AstNode *node = ast_create_node(NodeTypeFnCall, fn_name); | ||
| 291 | |||
| 292 | |||
| 289 | ast_buf_from_token(pc, fn_name, &node->data.fn_call.name); | 293 | ast_buf_from_token(pc, fn_name, &node->data.fn_call.name); |
| 290 | 294 | ||
| 291 | ast_parse_fn_call_param_list(pc, token_index, &token_index, &node->data.fn_call.params); | 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,9 +299,8 @@ static AstNode *ast_parse_fn_call(ParseContext *pc, int token_index, int *new_to |
| 295 | } | 299 | } |
| 296 | 300 | ||
| 297 | static AstNode *ast_parse_expression(ParseContext *pc, int token_index, int *new_token_index) { | 301 | static AstNode *ast_parse_expression(ParseContext *pc, int token_index, int *new_token_index) { |
| 298 | AstNode *node = ast_create_node(NodeTypeExpression); | ||
| 299 | |||
| 300 | Token *token = &pc->tokens->at(token_index); | 302 | Token *token = &pc->tokens->at(token_index); |
| 303 | AstNode *node = ast_create_node(NodeTypeExpression, token); | ||
| 301 | if (token->id == TokenIdSymbol) { | 304 | if (token->id == TokenIdSymbol) { |
| 302 | node->data.expression.type = AstNodeExpressionTypeFnCall; | 305 | node->data.expression.type = AstNodeExpressionTypeFnCall; |
| 303 | node->data.expression.data.fn_call = ast_parse_fn_call(pc, token_index, &token_index); | 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,9 +332,9 @@ Expression : token(Number) | token(String) | FnCall ; |
| 329 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) ; | 332 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) ; |
| 330 | */ | 333 | */ |
| 331 | static AstNode *ast_parse_statement(ParseContext *pc, int token_index, int *new_token_index) { | 334 | static AstNode *ast_parse_statement(ParseContext *pc, int token_index, int *new_token_index) { |
| 332 | AstNode *node = ast_create_node(NodeTypeStatement); | ||
| 333 | |||
| 334 | Token *token = &pc->tokens->at(token_index); | 335 | Token *token = &pc->tokens->at(token_index); |
| 336 | AstNode *node = ast_create_node(NodeTypeStatement, token); | ||
| 337 | |||
| 335 | if (token->id == TokenIdKeywordReturn) { | 338 | if (token->id == TokenIdKeywordReturn) { |
| 336 | token_index += 1; | 339 | token_index += 1; |
| 337 | node->data.statement.type = AstNodeStatementTypeReturn; | 340 | node->data.statement.type = AstNodeStatementTypeReturn; |
| ... | @@ -362,12 +365,13 @@ static AstNode *ast_parse_statement(ParseContext *pc, int token_index, int *new_ | ... | @@ -362,12 +365,13 @@ static AstNode *ast_parse_statement(ParseContext *pc, int token_index, int *new_ |
| 362 | Block : token(LBrace) many(Statement) token(RBrace); | 365 | Block : token(LBrace) many(Statement) token(RBrace); |
| 363 | */ | 366 | */ |
| 364 | static AstNode *ast_parse_block(ParseContext *pc, int token_index, int *new_token_index) { | 367 | static AstNode *ast_parse_block(ParseContext *pc, int token_index, int *new_token_index) { |
| 365 | AstNode *node = ast_create_node(NodeTypeBlock); | ||
| 366 | |||
| 367 | Token *l_brace = &pc->tokens->at(token_index); | 368 | Token *l_brace = &pc->tokens->at(token_index); |
| 368 | token_index += 1; | 369 | token_index += 1; |
| 369 | ast_expect_token(pc, l_brace, TokenIdLBrace); | 370 | ast_expect_token(pc, l_brace, TokenIdLBrace); |
| 370 | 371 | ||
| 372 | AstNode *node = ast_create_node(NodeTypeBlock, l_brace); | ||
| 373 | |||
| 374 | |||
| 371 | for (;;) { | 375 | for (;;) { |
| 372 | Token *token = &pc->tokens->at(token_index); | 376 | Token *token = &pc->tokens->at(token_index); |
| 373 | if (token->id == TokenIdRBrace) { | 377 | if (token->id == TokenIdRBrace) { |
| ... | @@ -386,12 +390,13 @@ static AstNode *ast_parse_block(ParseContext *pc, int token_index, int *new_toke | ... | @@ -386,12 +390,13 @@ static AstNode *ast_parse_block(ParseContext *pc, int token_index, int *new_toke |
| 386 | FnDecl : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) Block; | 390 | FnDecl : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) Block; |
| 387 | */ | 391 | */ |
| 388 | static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) { | 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 | Token *fn_token = &pc->tokens->at(token_index); | 393 | Token *fn_token = &pc->tokens->at(token_index); |
| 392 | token_index += 1; | 394 | token_index += 1; |
| 393 | ast_expect_token(pc, fn_token, TokenIdKeywordFn); | 395 | ast_expect_token(pc, fn_token, TokenIdKeywordFn); |
| 394 | 396 | ||
| 397 | AstNode *node = ast_create_node(NodeTypeFnDecl, fn_token); | ||
| 398 | |||
| 399 | |||
| 395 | Token *fn_name = &pc->tokens->at(token_index); | 400 | Token *fn_name = &pc->tokens->at(token_index); |
| 396 | token_index += 1; | 401 | token_index += 1; |
| 397 | ast_expect_token(pc, fn_name, TokenIdSymbol); | 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,7 +442,7 @@ static void ast_parse_fn_decl_list(ParseContext *pc, int token_index, ZigList<As |
| 437 | AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { | 442 | AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { |
| 438 | ParseContext pc = {0}; | 443 | ParseContext pc = {0}; |
| 439 | pc.buf = buf; | 444 | pc.buf = buf; |
| 440 | pc.root = ast_create_node(NodeTypeRoot); | 445 | pc.root = ast_create_node(NodeTypeRoot, &tokens->at(0)); |
| 441 | pc.tokens = tokens; | 446 | pc.tokens = tokens; |
| 442 | 447 | ||
| 443 | int new_token_index; | 448 | int new_token_index; |
src/parser.hpp+2| ... | @@ -97,6 +97,8 @@ struct AstNodeFnCall { | ... | @@ -97,6 +97,8 @@ struct AstNodeFnCall { |
| 97 | struct AstNode { | 97 | struct AstNode { |
| 98 | enum NodeType type; | 98 | enum NodeType type; |
| 99 | AstNode *parent; | 99 | AstNode *parent; |
| 100 | int line; | ||
| 101 | int column; | ||
| 100 | union { | 102 | union { |
| 101 | AstNodeRoot root; | 103 | AstNodeRoot root; |
| 102 | AstNodeFnDecl fn_decl; | 104 | AstNodeFnDecl fn_decl; |