| author | |
| committer | |
| log | ab327344b671bff7f874f24691d7e3f19176167c |
| tree | c437760bbc1f7059417b21e37c3d15a42534d4e8 |
| parent | 9278dbedd5242bf4253da29c0fab36eea9dda61b |
| parent | dfb6682089ad758b7ba72733778a9aa8c544c164 |
25 files changed, 565 insertions(+), 290 deletions(-)
CMakeLists.txt+1| ... | @@ -31,6 +31,7 @@ set(ZIG_SOURCES | ... | @@ -31,6 +31,7 @@ set(ZIG_SOURCES |
| 31 | "${CMAKE_SOURCE_DIR}/src/main.cpp" | 31 | "${CMAKE_SOURCE_DIR}/src/main.cpp" |
| 32 | "${CMAKE_SOURCE_DIR}/src/os.cpp" | 32 | "${CMAKE_SOURCE_DIR}/src/os.cpp" |
| 33 | "${CMAKE_SOURCE_DIR}/src/util.cpp" | 33 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 34 | "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" | ||
| 34 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" | 35 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" |
| 35 | ) | 36 | ) |
| 36 | 37 |
README.md-1| ... | @@ -43,7 +43,6 @@ make | ... | @@ -43,7 +43,6 @@ make |
| 43 | ## Roadmap | 43 | ## Roadmap |
| 44 | 44 | ||
| 45 | * variable declarations and assignment expressions | 45 | * variable declarations and assignment expressions |
| 46 | * Multiple files | ||
| 47 | * Type checking | 46 | * Type checking |
| 48 | * inline assembly and syscalls | 47 | * inline assembly and syscalls |
| 49 | * running code at compile time | 48 | * running code at compile time |
example/multiple_files/foo.zig+1-1| ... | @@ -6,6 +6,6 @@ fn private_function() { | ... | @@ -6,6 +6,6 @@ fn private_function() { |
| 6 | puts("it works!"); | 6 | puts("it works!"); |
| 7 | } | 7 | } |
| 8 | 8 | ||
| 9 | fn print_text() { | 9 | pub fn print_text() { |
| 10 | private_function(); | 10 | private_function(); |
| 11 | } | 11 | } |
example/multiple_files/libc.zig+2-2| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | #link("c") | 1 | #link("c") |
| 2 | extern { | 2 | extern { |
| 3 | fn puts(s: *mut u8) -> i32; | 3 | pub fn puts(s: *mut u8) -> i32; |
| 4 | fn exit(code: i32) -> unreachable; | 4 | pub fn exit(code: i32) -> unreachable; |
| 5 | } | 5 | } |
example/multiple_files/main.zig+2-2| ... | @@ -1,9 +1,9 @@ | ... | @@ -1,9 +1,9 @@ |
| 1 | export executable "test"; | 1 | export executable "test-multiple-files"; |
| 2 | 2 | ||
| 3 | use "libc.zig"; | 3 | use "libc.zig"; |
| 4 | use "foo.zig"; | 4 | use "foo.zig"; |
| 5 | 5 | ||
| 6 | fn _start() -> unreachable { | 6 | export fn _start() -> unreachable { |
| 7 | private_function(); | 7 | private_function(); |
| 8 | } | 8 | } |
| 9 | 9 |
src/analyze.cpp+129-145| ... | @@ -17,14 +17,18 @@ struct BlockContext { | ... | @@ -17,14 +17,18 @@ struct BlockContext { |
| 17 | BlockContext *parent; | 17 | BlockContext *parent; |
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| 20 | static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { | 20 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 21 | g->errors.add_one(); | 21 | ErrorMsg *err = allocate<ErrorMsg>(1); |
| 22 | ErrorMsg *last_msg = &g->errors.last(); | 22 | err->line_start = node->line; |
| 23 | last_msg->line_start = node->line; | 23 | err->column_start = node->column; |
| 24 | last_msg->column_start = node->column; | 24 | err->line_end = -1; |
| 25 | last_msg->line_end = -1; | 25 | err->column_end = -1; |
| 26 | last_msg->column_end = -1; | 26 | err->msg = msg; |
| 27 | last_msg->msg = msg; | 27 | err->path = node->owner->path; |
| 28 | err->source = node->owner->source_code; | ||
| 29 | err->line_offsets = node->owner->line_offsets; | ||
| 30 | |||
| 31 | g->errors.append(err); | ||
| 28 | } | 32 | } |
| 29 | 33 | ||
| 30 | static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) { | 34 | static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) { |
| ... | @@ -139,6 +143,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, | ... | @@ -139,6 +143,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 139 | AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i); | 143 | AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i); |
| 140 | assert(fn_decl->type == NodeTypeFnDecl); | 144 | assert(fn_decl->type == NodeTypeFnDecl); |
| 141 | AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto; | 145 | AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto; |
| 146 | bool is_pub = (fn_proto->data.fn_proto.visib_mod == FnProtoVisibModPub); | ||
| 142 | resolve_function_proto(g, fn_proto); | 147 | resolve_function_proto(g, fn_proto); |
| 143 | Buf *name = &fn_proto->data.fn_proto.name; | 148 | Buf *name = &fn_proto->data.fn_proto.name; |
| 144 | 149 | ||
| ... | @@ -147,7 +152,12 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, | ... | @@ -147,7 +152,12 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 147 | fn_table_entry->is_extern = true; | 152 | fn_table_entry->is_extern = true; |
| 148 | fn_table_entry->calling_convention = LLVMCCallConv; | 153 | fn_table_entry->calling_convention = LLVMCCallConv; |
| 149 | fn_table_entry->import_entry = import; | 154 | fn_table_entry->import_entry = import; |
| 150 | g->fn_table.put(name, fn_table_entry); | 155 | |
| 156 | g->fn_protos.append(fn_table_entry); | ||
| 157 | import->fn_table.put(name, fn_table_entry); | ||
| 158 | if (is_pub) { | ||
| 159 | g->fn_table.put(name, fn_table_entry); | ||
| 160 | } | ||
| 151 | } | 161 | } |
| 152 | break; | 162 | break; |
| 153 | case NodeTypeFnDef: | 163 | case NodeTypeFnDef: |
| ... | @@ -155,67 +165,89 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, | ... | @@ -155,67 +165,89 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 155 | AstNode *proto_node = node->data.fn_def.fn_proto; | 165 | AstNode *proto_node = node->data.fn_def.fn_proto; |
| 156 | assert(proto_node->type == NodeTypeFnProto); | 166 | assert(proto_node->type == NodeTypeFnProto); |
| 157 | Buf *proto_name = &proto_node->data.fn_proto.name; | 167 | Buf *proto_name = &proto_node->data.fn_proto.name; |
| 158 | auto entry = g->fn_table.maybe_get(proto_name); | 168 | auto entry = import->fn_table.maybe_get(proto_name); |
| 169 | bool skip = false; | ||
| 170 | bool is_internal = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport); | ||
| 171 | bool is_pub = (proto_node->data.fn_proto.visib_mod == FnProtoVisibModPub); | ||
| 159 | if (entry) { | 172 | if (entry) { |
| 160 | add_node_error(g, node, | 173 | add_node_error(g, node, |
| 161 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); | 174 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| 162 | assert(!node->codegen_node); | 175 | assert(!node->codegen_node); |
| 163 | node->codegen_node = allocate<CodeGenNode>(1); | 176 | node->codegen_node = allocate<CodeGenNode>(1); |
| 164 | node->codegen_node->data.fn_def_node.skip = true; | 177 | node->codegen_node->data.fn_def_node.skip = true; |
| 165 | } else { | 178 | skip = true; |
| 179 | } else if (is_pub) { | ||
| 180 | auto entry = g->fn_table.maybe_get(proto_name); | ||
| 181 | if (entry) { | ||
| 182 | add_node_error(g, node, | ||
| 183 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); | ||
| 184 | assert(!node->codegen_node); | ||
| 185 | node->codegen_node = allocate<CodeGenNode>(1); | ||
| 186 | node->codegen_node->data.fn_def_node.skip = true; | ||
| 187 | skip = true; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | if (!skip) { | ||
| 166 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); | 191 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); |
| 167 | fn_table_entry->import_entry = import; | 192 | fn_table_entry->import_entry = import; |
| 168 | fn_table_entry->proto_node = proto_node; | 193 | fn_table_entry->proto_node = proto_node; |
| 169 | fn_table_entry->fn_def_node = node; | 194 | fn_table_entry->fn_def_node = node; |
| 170 | fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport; | 195 | fn_table_entry->internal_linkage = is_internal; |
| 171 | if (fn_table_entry->internal_linkage) { | 196 | fn_table_entry->calling_convention = is_internal ? LLVMFastCallConv : LLVMCCallConv; |
| 172 | fn_table_entry->calling_convention = LLVMFastCallConv; | 197 | |
| 173 | } else { | 198 | g->fn_protos.append(fn_table_entry); |
| 174 | fn_table_entry->calling_convention = LLVMCCallConv; | ||
| 175 | } | ||
| 176 | g->fn_table.put(proto_name, fn_table_entry); | ||
| 177 | g->fn_defs.append(fn_table_entry); | 199 | g->fn_defs.append(fn_table_entry); |
| 178 | 200 | ||
| 201 | import->fn_table.put(proto_name, fn_table_entry); | ||
| 202 | if (is_pub) { | ||
| 203 | g->fn_table.put(proto_name, fn_table_entry); | ||
| 204 | } | ||
| 205 | |||
| 179 | resolve_function_proto(g, proto_node); | 206 | resolve_function_proto(g, proto_node); |
| 180 | } | 207 | } |
| 181 | } | 208 | } |
| 182 | break; | 209 | break; |
| 183 | case NodeTypeRootExportDecl: | 210 | case NodeTypeRootExportDecl: |
| 184 | for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) { | 211 | if (import == g->root_import) { |
| 185 | AstNode *directive_node = node->data.root_export_decl.directives->at(i); | 212 | for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) { |
| 186 | Buf *name = &directive_node->data.directive.name; | 213 | AstNode *directive_node = node->data.root_export_decl.directives->at(i); |
| 187 | Buf *param = &directive_node->data.directive.param; | 214 | Buf *name = &directive_node->data.directive.name; |
| 188 | if (buf_eql_str(name, "version")) { | 215 | Buf *param = &directive_node->data.directive.param; |
| 189 | set_root_export_version(g, param, directive_node); | 216 | if (buf_eql_str(name, "version")) { |
| 190 | } else { | 217 | set_root_export_version(g, param, directive_node); |
| 191 | add_node_error(g, directive_node, | 218 | } else { |
| 192 | buf_sprintf("invalid directive: '%s'", buf_ptr(name))); | 219 | add_node_error(g, directive_node, |
| 220 | buf_sprintf("invalid directive: '%s'", buf_ptr(name))); | ||
| 221 | } | ||
| 193 | } | 222 | } |
| 194 | } | ||
| 195 | 223 | ||
| 196 | if (g->root_export_decl) { | 224 | if (g->root_export_decl) { |
| 197 | add_node_error(g, node, | ||
| 198 | buf_sprintf("only one root export declaration allowed")); | ||
| 199 | } else { | ||
| 200 | g->root_export_decl = node; | ||
| 201 | |||
| 202 | if (!g->root_out_name) | ||
| 203 | g->root_out_name = &node->data.root_export_decl.name; | ||
| 204 | |||
| 205 | Buf *out_type = &node->data.root_export_decl.type; | ||
| 206 | OutType export_out_type; | ||
| 207 | if (buf_eql_str(out_type, "executable")) { | ||
| 208 | export_out_type = OutTypeExe; | ||
| 209 | } else if (buf_eql_str(out_type, "library")) { | ||
| 210 | export_out_type = OutTypeLib; | ||
| 211 | } else if (buf_eql_str(out_type, "object")) { | ||
| 212 | export_out_type = OutTypeObj; | ||
| 213 | } else { | ||
| 214 | add_node_error(g, node, | 225 | add_node_error(g, node, |
| 215 | buf_sprintf("invalid export type: '%s'", buf_ptr(out_type))); | 226 | buf_sprintf("only one root export declaration allowed")); |
| 227 | } else { | ||
| 228 | g->root_export_decl = node; | ||
| 229 | |||
| 230 | if (!g->root_out_name) | ||
| 231 | g->root_out_name = &node->data.root_export_decl.name; | ||
| 232 | |||
| 233 | Buf *out_type = &node->data.root_export_decl.type; | ||
| 234 | OutType export_out_type; | ||
| 235 | if (buf_eql_str(out_type, "executable")) { | ||
| 236 | export_out_type = OutTypeExe; | ||
| 237 | } else if (buf_eql_str(out_type, "library")) { | ||
| 238 | export_out_type = OutTypeLib; | ||
| 239 | } else if (buf_eql_str(out_type, "object")) { | ||
| 240 | export_out_type = OutTypeObj; | ||
| 241 | } else { | ||
| 242 | add_node_error(g, node, | ||
| 243 | buf_sprintf("invalid export type: '%s'", buf_ptr(out_type))); | ||
| 244 | } | ||
| 245 | if (g->out_type == OutTypeUnknown) | ||
| 246 | g->out_type = export_out_type; | ||
| 216 | } | 247 | } |
| 217 | if (g->out_type == OutTypeUnknown) | 248 | } else { |
| 218 | g->out_type = export_out_type; | 249 | add_node_error(g, node, |
| 250 | buf_sprintf("root export declaration only valid in root source file")); | ||
| 219 | } | 251 | } |
| 220 | break; | 252 | break; |
| 221 | case NodeTypeUse: | 253 | case NodeTypeUse: |
| ... | @@ -263,7 +295,7 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry * | ... | @@ -263,7 +295,7 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry * |
| 263 | add_node_error(g, node, buf_sprintf("type mismatch.")); | 295 | add_node_error(g, node, buf_sprintf("type mismatch.")); |
| 264 | } | 296 | } |
| 265 | 297 | ||
| 266 | static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { | 298 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { |
| 267 | switch (node->type) { | 299 | switch (node->type) { |
| 268 | case NodeTypeBlock: | 300 | case NodeTypeBlock: |
| 269 | { | 301 | { |
| ... | @@ -276,7 +308,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty | ... | @@ -276,7 +308,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty |
| 276 | buf_sprintf("unreachable code")); | 308 | buf_sprintf("unreachable code")); |
| 277 | break; | 309 | break; |
| 278 | } | 310 | } |
| 279 | return_type = analyze_expression(g, context, nullptr, child); | 311 | return_type = analyze_expression(g, import, context, nullptr, child); |
| 280 | } | 312 | } |
| 281 | return return_type; | 313 | return return_type; |
| 282 | } | 314 | } |
| ... | @@ -286,7 +318,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty | ... | @@ -286,7 +318,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty |
| 286 | TypeTableEntry *expected_return_type = get_return_type(context); | 318 | TypeTableEntry *expected_return_type = get_return_type(context); |
| 287 | TypeTableEntry *actual_return_type; | 319 | TypeTableEntry *actual_return_type; |
| 288 | if (node->data.return_expr.expr) { | 320 | if (node->data.return_expr.expr) { |
| 289 | actual_return_type = analyze_expression(g, context, expected_return_type, node->data.return_expr.expr); | 321 | actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr); |
| 290 | } else { | 322 | } else { |
| 291 | actual_return_type = g->builtin_types.entry_void; | 323 | actual_return_type = g->builtin_types.entry_void; |
| 292 | } | 324 | } |
| ... | @@ -304,8 +336,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty | ... | @@ -304,8 +336,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty |
| 304 | case NodeTypeBinOpExpr: | 336 | case NodeTypeBinOpExpr: |
| 305 | { | 337 | { |
| 306 | // TODO: think about expected types | 338 | // TODO: think about expected types |
| 307 | analyze_expression(g, context, expected_type, node->data.bin_op_expr.op1); | 339 | analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op1); |
| 308 | analyze_expression(g, context, expected_type, node->data.bin_op_expr.op2); | 340 | analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op2); |
| 309 | return expected_type; | 341 | return expected_type; |
| 310 | } | 342 | } |
| 311 | 343 | ||
| ... | @@ -313,14 +345,17 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty | ... | @@ -313,14 +345,17 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty |
| 313 | { | 345 | { |
| 314 | Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr); | 346 | Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr); |
| 315 | 347 | ||
| 316 | auto entry = g->fn_table.maybe_get(name); | 348 | auto entry = import->fn_table.maybe_get(name); |
| 349 | if (!entry) | ||
| 350 | entry = g->fn_table.maybe_get(name); | ||
| 351 | |||
| 317 | if (!entry) { | 352 | if (!entry) { |
| 318 | add_node_error(g, node, | 353 | add_node_error(g, node, |
| 319 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); | 354 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); |
| 320 | // still analyze the parameters, even though we don't know what to expect | 355 | // still analyze the parameters, even though we don't know what to expect |
| 321 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { | 356 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| 322 | AstNode *child = node->data.fn_call_expr.params.at(i); | 357 | AstNode *child = node->data.fn_call_expr.params.at(i); |
| 323 | analyze_expression(g, context, nullptr, child); | 358 | analyze_expression(g, import, context, nullptr, child); |
| 324 | } | 359 | } |
| 325 | 360 | ||
| 326 | return g->builtin_types.entry_invalid; | 361 | return g->builtin_types.entry_invalid; |
| ... | @@ -350,7 +385,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty | ... | @@ -350,7 +385,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty |
| 350 | if (param_type_node->codegen_node) | 385 | if (param_type_node->codegen_node) |
| 351 | expected_param_type = param_type_node->codegen_node->data.type_node.entry; | 386 | expected_param_type = param_type_node->codegen_node->data.type_node.entry; |
| 352 | } | 387 | } |
| 353 | analyze_expression(g, context, expected_param_type, child); | 388 | analyze_expression(g, import, context, expected_param_type, child); |
| 354 | } | 389 | } |
| 355 | 390 | ||
| 356 | TypeTableEntry *return_type = fn_proto->return_type->codegen_node->data.type_node.entry; | 391 | TypeTableEntry *return_type = fn_proto->return_type->codegen_node->data.type_node.entry; |
| ... | @@ -444,76 +479,7 @@ static void check_fn_def_control_flow(CodeGen *g, AstNode *node) { | ... | @@ -444,76 +479,7 @@ static void check_fn_def_control_flow(CodeGen *g, AstNode *node) { |
| 444 | } | 479 | } |
| 445 | } | 480 | } |
| 446 | 481 | ||
| 447 | static void analyze_expression(CodeGen *g, AstNode *node) { | 482 | static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 448 | switch (node->type) { | ||
| 449 | case NodeTypeBlock: | ||
| 450 | for (int i = 0; i < node->data.block.statements.length; i += 1) { | ||
| 451 | AstNode *child = node->data.block.statements.at(i); | ||
| 452 | analyze_expression(g, child); | ||
| 453 | } | ||
| 454 | break; | ||
| 455 | case NodeTypeReturnExpr: | ||
| 456 | if (node->data.return_expr.expr) { | ||
| 457 | analyze_expression(g, node->data.return_expr.expr); | ||
| 458 | } | ||
| 459 | break; | ||
| 460 | case NodeTypeBinOpExpr: | ||
| 461 | analyze_expression(g, node->data.bin_op_expr.op1); | ||
| 462 | analyze_expression(g, node->data.bin_op_expr.op2); | ||
| 463 | break; | ||
| 464 | case NodeTypeFnCallExpr: | ||
| 465 | { | ||
| 466 | Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr); | ||
| 467 | |||
| 468 | auto entry = g->fn_table.maybe_get(name); | ||
| 469 | if (!entry) { | ||
| 470 | add_node_error(g, node, | ||
| 471 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); | ||
| 472 | } else { | ||
| 473 | FnTableEntry *fn_table_entry = entry->value; | ||
| 474 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); | ||
| 475 | int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length; | ||
| 476 | int actual_param_count = node->data.fn_call_expr.params.length; | ||
| 477 | if (expected_param_count != actual_param_count) { | ||
| 478 | add_node_error(g, node, | ||
| 479 | buf_sprintf("wrong number of arguments. Expected %d, got %d.", | ||
| 480 | expected_param_count, actual_param_count)); | ||
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 484 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { | ||
| 485 | AstNode *child = node->data.fn_call_expr.params.at(i); | ||
| 486 | analyze_expression(g, child); | ||
| 487 | } | ||
| 488 | break; | ||
| 489 | } | ||
| 490 | case NodeTypeCastExpr: | ||
| 491 | zig_panic("TODO"); | ||
| 492 | break; | ||
| 493 | case NodeTypePrefixOpExpr: | ||
| 494 | zig_panic("TODO"); | ||
| 495 | break; | ||
| 496 | case NodeTypeNumberLiteral: | ||
| 497 | case NodeTypeStringLiteral: | ||
| 498 | case NodeTypeUnreachable: | ||
| 499 | case NodeTypeSymbol: | ||
| 500 | // nothing to do | ||
| 501 | break; | ||
| 502 | case NodeTypeDirective: | ||
| 503 | case NodeTypeFnDecl: | ||
| 504 | case NodeTypeFnProto: | ||
| 505 | case NodeTypeParamDecl: | ||
| 506 | case NodeTypeType: | ||
| 507 | case NodeTypeRoot: | ||
| 508 | case NodeTypeRootExportDecl: | ||
| 509 | case NodeTypeExternBlock: | ||
| 510 | case NodeTypeFnDef: | ||
| 511 | case NodeTypeUse: | ||
| 512 | zig_unreachable(); | ||
| 513 | } | ||
| 514 | } | ||
| 515 | |||
| 516 | static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { | ||
| 517 | switch (node->type) { | 483 | switch (node->type) { |
| 518 | case NodeTypeFnDef: | 484 | case NodeTypeFnDef: |
| 519 | { | 485 | { |
| ... | @@ -540,7 +506,7 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { | ... | @@ -540,7 +506,7 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { |
| 540 | context.root = &context; | 506 | context.root = &context; |
| 541 | context.parent = nullptr; | 507 | context.parent = nullptr; |
| 542 | TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry; | 508 | TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry; |
| 543 | analyze_expression(g, &context, expected_type, node->data.fn_def.body); | 509 | analyze_expression(g, import, &context, expected_type, node->data.fn_def.body); |
| 544 | } | 510 | } |
| 545 | break; | 511 | break; |
| 546 | 512 | ||
| ... | @@ -576,37 +542,55 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { | ... | @@ -576,37 +542,55 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { |
| 576 | } | 542 | } |
| 577 | } | 543 | } |
| 578 | 544 | ||
| 579 | static void analyze_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { | 545 | static void find_function_declarations_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 580 | assert(node->type == NodeTypeRoot); | 546 | assert(node->type == NodeTypeRoot); |
| 581 | 547 | ||
| 582 | // find function declarations | ||
| 583 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { | 548 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { |
| 584 | AstNode *child = node->data.root.top_level_decls.at(i); | 549 | AstNode *child = node->data.root.top_level_decls.at(i); |
| 585 | preview_function_declarations(g, import, child); | 550 | preview_function_declarations(g, import, child); |
| 586 | } | 551 | } |
| 587 | 552 | ||
| 553 | } | ||
| 554 | |||
| 555 | static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { | ||
| 556 | assert(node->type == NodeTypeRoot); | ||
| 557 | |||
| 588 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { | 558 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { |
| 589 | AstNode *child = node->data.root.top_level_decls.at(i); | 559 | AstNode *child = node->data.root.top_level_decls.at(i); |
| 590 | analyze_top_level_declaration(g, child); | 560 | analyze_top_level_declaration(g, import, child); |
| 591 | } | 561 | } |
| 562 | } | ||
| 563 | |||
| 564 | void semantic_analyze(CodeGen *g) { | ||
| 565 | { | ||
| 566 | auto it = g->import_table.entry_iterator(); | ||
| 567 | for (;;) { | ||
| 568 | auto *entry = it.next(); | ||
| 569 | if (!entry) | ||
| 570 | break; | ||
| 571 | |||
| 572 | ImportTableEntry *import = entry->value; | ||
| 573 | find_function_declarations_root(g, import, import->root); | ||
| 574 | } | ||
| 575 | } | ||
| 576 | { | ||
| 577 | auto it = g->import_table.entry_iterator(); | ||
| 578 | for (;;) { | ||
| 579 | auto *entry = it.next(); | ||
| 580 | if (!entry) | ||
| 581 | break; | ||
| 582 | |||
| 583 | ImportTableEntry *import = entry->value; | ||
| 584 | analyze_top_level_decls_root(g, import, import->root); | ||
| 585 | } | ||
| 586 | } | ||
| 587 | |||
| 592 | 588 | ||
| 593 | if (!g->root_out_name) { | 589 | if (!g->root_out_name) { |
| 594 | add_node_error(g, node, | 590 | add_node_error(g, g->root_import->root, |
| 595 | buf_sprintf("missing export declaration and output name not provided")); | 591 | buf_sprintf("missing export declaration and output name not provided")); |
| 596 | } else if (g->out_type == OutTypeUnknown) { | 592 | } else if (g->out_type == OutTypeUnknown) { |
| 597 | add_node_error(g, node, | 593 | add_node_error(g, g->root_import->root, |
| 598 | buf_sprintf("missing export declaration and export type not provided")); | 594 | buf_sprintf("missing export declaration and export type not provided")); |
| 599 | } | 595 | } |
| 600 | } | 596 | } |
| 601 | |||
| 602 | void semantic_analyze(CodeGen *g) { | ||
| 603 | auto it = g->import_table.entry_iterator(); | ||
| 604 | for (;;) { | ||
| 605 | auto *entry = it.next(); | ||
| 606 | if (!entry) | ||
| 607 | break; | ||
| 608 | |||
| 609 | ImportTableEntry *import = entry->value; | ||
| 610 | analyze_root(g, import, import->root); | ||
| 611 | } | ||
| 612 | } |
src/analyze.hpp+3| ... | @@ -9,7 +9,10 @@ | ... | @@ -9,7 +9,10 @@ |
| 9 | #define ZIG_ANALYZE_HPP | 9 | #define ZIG_ANALYZE_HPP |
| 10 | 10 | ||
| 11 | struct CodeGen; | 11 | struct CodeGen; |
| 12 | struct AstNode; | ||
| 13 | struct Buf; | ||
| 12 | 14 | ||
| 13 | void semantic_analyze(CodeGen *g); | 15 | void semantic_analyze(CodeGen *g); |
| 16 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg); | ||
| 14 | 17 | ||
| 15 | #endif | 18 | #endif |
src/buffer.cpp+10-4| ... | @@ -3,9 +3,8 @@ | ... | @@ -3,9 +3,8 @@ |
| 3 | #include <stdlib.h> | 3 | #include <stdlib.h> |
| 4 | #include <stdio.h> | 4 | #include <stdio.h> |
| 5 | 5 | ||
| 6 | Buf *buf_sprintf(const char *format, ...) { | 6 | Buf *buf_vprintf(const char *format, va_list ap) { |
| 7 | va_list ap, ap2; | 7 | va_list ap2; |
| 8 | va_start(ap, format); | ||
| 9 | va_copy(ap2, ap); | 8 | va_copy(ap2, ap); |
| 10 | 9 | ||
| 11 | int len1 = vsnprintf(nullptr, 0, format, ap); | 10 | int len1 = vsnprintf(nullptr, 0, format, ap); |
| ... | @@ -19,11 +18,18 @@ Buf *buf_sprintf(const char *format, ...) { | ... | @@ -19,11 +18,18 @@ Buf *buf_sprintf(const char *format, ...) { |
| 19 | assert(len2 == len1); | 18 | assert(len2 == len1); |
| 20 | 19 | ||
| 21 | va_end(ap2); | 20 | va_end(ap2); |
| 22 | va_end(ap); | ||
| 23 | 21 | ||
| 24 | return buf; | 22 | return buf; |
| 25 | } | 23 | } |
| 26 | 24 | ||
| 25 | Buf *buf_sprintf(const char *format, ...) { | ||
| 26 | va_list ap; | ||
| 27 | va_start(ap, format); | ||
| 28 | Buf *result = buf_vprintf(format, ap); | ||
| 29 | va_end(ap); | ||
| 30 | return result; | ||
| 31 | } | ||
| 32 | |||
| 27 | void buf_appendf(Buf *buf, const char *format, ...) { | 33 | void buf_appendf(Buf *buf, const char *format, ...) { |
| 28 | assert(buf->list.length); | 34 | assert(buf->list.length); |
| 29 | va_list ap, ap2; | 35 | va_list ap, ap2; |
src/buffer.hpp+2| ... | @@ -13,6 +13,7 @@ | ... | @@ -13,6 +13,7 @@ |
| 13 | #include <assert.h> | 13 | #include <assert.h> |
| 14 | #include <stdint.h> | 14 | #include <stdint.h> |
| 15 | #include <ctype.h> | 15 | #include <ctype.h> |
| 16 | #include <stdarg.h> | ||
| 16 | 17 | ||
| 17 | #define BUF_INIT {{0}} | 18 | #define BUF_INIT {{0}} |
| 18 | 19 | ||
| ... | @@ -24,6 +25,7 @@ struct Buf { | ... | @@ -24,6 +25,7 @@ struct Buf { |
| 24 | 25 | ||
| 25 | Buf *buf_sprintf(const char *format, ...) | 26 | Buf *buf_sprintf(const char *format, ...) |
| 26 | __attribute__ ((format (printf, 1, 2))); | 27 | __attribute__ ((format (printf, 1, 2))); |
| 28 | Buf *buf_vprintf(const char *format, va_list ap); | ||
| 27 | 29 | ||
| 28 | static inline int buf_len(Buf *buf) { | 30 | static inline int buf_len(Buf *buf) { |
| 29 | assert(buf->list.length); | 31 | assert(buf->list.length); |
src/codegen.cpp+51-22| ... | @@ -13,6 +13,7 @@ | ... | @@ -13,6 +13,7 @@ |
| 13 | #include "error.hpp" | 13 | #include "error.hpp" |
| 14 | #include "semantic_info.hpp" | 14 | #include "semantic_info.hpp" |
| 15 | #include "analyze.hpp" | 15 | #include "analyze.hpp" |
| 16 | #include "errmsg.hpp" | ||
| 16 | 17 | ||
| 17 | #include <stdio.h> | 18 | #include <stdio.h> |
| 18 | #include <errno.h> | 19 | #include <errno.h> |
| ... | @@ -41,6 +42,10 @@ void codegen_set_verbose(CodeGen *g, bool verbose) { | ... | @@ -41,6 +42,10 @@ void codegen_set_verbose(CodeGen *g, bool verbose) { |
| 41 | g->verbose = verbose; | 42 | g->verbose = verbose; |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 45 | void codegen_set_errmsg_color(CodeGen *g, ErrColor err_color) { | ||
| 46 | g->err_color = err_color; | ||
| 47 | } | ||
| 48 | |||
| 44 | void codegen_set_strip(CodeGen *g, bool strip) { | 49 | void codegen_set_strip(CodeGen *g, bool strip) { |
| 45 | g->strip_debug_symbols = strip; | 50 | g->strip_debug_symbols = strip; |
| 46 | } | 51 | } |
| ... | @@ -120,7 +125,13 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { | ... | @@ -120,7 +125,13 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 120 | 125 | ||
| 121 | Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr); | 126 | Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr); |
| 122 | 127 | ||
| 123 | FnTableEntry *fn_table_entry = g->fn_table.get(name); | 128 | FnTableEntry *fn_table_entry; |
| 129 | auto entry = g->cur_fn->import_entry->fn_table.maybe_get(name); | ||
| 130 | if (entry) | ||
| 131 | fn_table_entry = entry->value; | ||
| 132 | else | ||
| 133 | fn_table_entry = g->fn_table.get(name); | ||
| 134 | |||
| 124 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); | 135 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); |
| 125 | int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length; | 136 | int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length; |
| 126 | int actual_param_count = node->data.fn_call_expr.params.length; | 137 | int actual_param_count = node->data.fn_call_expr.params.length; |
| ... | @@ -473,13 +484,8 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -473,13 +484,8 @@ static void do_code_gen(CodeGen *g) { |
| 473 | 484 | ||
| 474 | 485 | ||
| 475 | // Generate function prototypes | 486 | // Generate function prototypes |
| 476 | auto it = g->fn_table.entry_iterator(); | 487 | for (int i = 0; i < g->fn_protos.length; i += 1) { |
| 477 | for (;;) { | 488 | FnTableEntry *fn_table_entry = g->fn_protos.at(i); |
| 478 | auto *entry = it.next(); | ||
| 479 | if (!entry) | ||
| 480 | break; | ||
| 481 | |||
| 482 | FnTableEntry *fn_table_entry = entry->value; | ||
| 483 | 489 | ||
| 484 | AstNode *proto_node = fn_table_entry->proto_node; | 490 | AstNode *proto_node = fn_table_entry->proto_node; |
| 485 | assert(proto_node->type == NodeTypeFnProto); | 491 | assert(proto_node->type == NodeTypeFnProto); |
| ... | @@ -542,6 +548,7 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -542,6 +548,7 @@ static void do_code_gen(CodeGen *g) { |
| 542 | assert(codegen_node); | 548 | assert(codegen_node); |
| 543 | 549 | ||
| 544 | FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node; | 550 | FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node; |
| 551 | assert(codegen_fn_def); | ||
| 545 | codegen_fn_def->params = allocate<LLVMValueRef>(LLVMCountParams(fn)); | 552 | codegen_fn_def->params = allocate<LLVMValueRef>(LLVMCountParams(fn)); |
| 546 | LLVMGetParams(fn, codegen_fn_def->params); | 553 | LLVMGetParams(fn, codegen_fn_def->params); |
| 547 | 554 | ||
| ... | @@ -664,7 +671,8 @@ static void init(CodeGen *g, Buf *source_path) { | ... | @@ -664,7 +671,8 @@ static void init(CodeGen *g, Buf *source_path) { |
| 664 | 671 | ||
| 665 | } | 672 | } |
| 666 | 673 | ||
| 667 | static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) { | 674 | static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) { |
| 675 | int err; | ||
| 668 | Buf full_path = BUF_INIT; | 676 | Buf full_path = BUF_INIT; |
| 669 | os_path_join(g->root_source_dir, source_path, &full_path); | 677 | os_path_join(g->root_source_dir, source_path, &full_path); |
| 670 | 678 | ||
| ... | @@ -681,24 +689,42 @@ static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) { | ... | @@ -681,24 +689,42 @@ static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) { |
| 681 | fprintf(stderr, "---------\n"); | 689 | fprintf(stderr, "---------\n"); |
| 682 | } | 690 | } |
| 683 | 691 | ||
| 684 | ZigList<Token> *tokens = tokenize(source_code); | 692 | Tokenization tokenization = {0}; |
| 693 | tokenize(source_code, &tokenization); | ||
| 694 | |||
| 695 | if (tokenization.err) { | ||
| 696 | ErrorMsg *err = allocate<ErrorMsg>(1); | ||
| 697 | err->line_start = tokenization.err_line; | ||
| 698 | err->column_start = tokenization.err_column; | ||
| 699 | err->line_end = -1; | ||
| 700 | err->column_end = -1; | ||
| 701 | err->msg = tokenization.err; | ||
| 702 | err->path = source_path; | ||
| 703 | err->source = source_code; | ||
| 704 | err->line_offsets = tokenization.line_offsets; | ||
| 705 | |||
| 706 | print_err_msg(err, g->err_color); | ||
| 707 | exit(1); | ||
| 708 | } | ||
| 685 | 709 | ||
| 686 | if (g->verbose) { | 710 | if (g->verbose) { |
| 687 | print_tokens(source_code, tokens); | 711 | print_tokens(source_code, tokenization.tokens); |
| 688 | 712 | ||
| 689 | fprintf(stderr, "\nAST:\n"); | 713 | fprintf(stderr, "\nAST:\n"); |
| 690 | fprintf(stderr, "------\n"); | 714 | fprintf(stderr, "------\n"); |
| 691 | } | 715 | } |
| 692 | 716 | ||
| 693 | ImportTableEntry *import_entry = allocate<ImportTableEntry>(1); | 717 | ImportTableEntry *import_entry = allocate<ImportTableEntry>(1); |
| 718 | import_entry->source_code = source_code; | ||
| 719 | import_entry->line_offsets = tokenization.line_offsets; | ||
| 720 | import_entry->path = source_path; | ||
| 694 | import_entry->fn_table.init(32); | 721 | import_entry->fn_table.init(32); |
| 695 | import_entry->root = ast_parse(source_code, tokens); | 722 | import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color); |
| 696 | assert(import_entry->root); | 723 | assert(import_entry->root); |
| 697 | if (g->verbose) { | 724 | if (g->verbose) { |
| 698 | ast_print(import_entry->root, 0); | 725 | ast_print(import_entry->root, 0); |
| 699 | } | 726 | } |
| 700 | 727 | ||
| 701 | import_entry->path = source_path; | ||
| 702 | import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&basename), buf_ptr(&dirname)); | 728 | import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&basename), buf_ptr(&dirname)); |
| 703 | g->import_table.put(source_path, import_entry); | 729 | g->import_table.put(source_path, import_entry); |
| 704 | 730 | ||
| ... | @@ -713,18 +739,23 @@ static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) { | ... | @@ -713,18 +739,23 @@ static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) { |
| 713 | if (!entry) { | 739 | if (!entry) { |
| 714 | Buf full_path = BUF_INIT; | 740 | Buf full_path = BUF_INIT; |
| 715 | os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path); | 741 | os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path); |
| 716 | Buf import_code = BUF_INIT; | 742 | Buf *import_code = buf_alloc(); |
| 717 | os_fetch_file_path(&full_path, &import_code); | 743 | if ((err = os_fetch_file_path(&full_path, import_code))) { |
| 718 | codegen_add_code(g, &top_level_decl->data.use.path, &import_code); | 744 | add_node_error(g, top_level_decl, |
| 745 | buf_sprintf("unable to open \"%s\": %s", buf_ptr(&full_path), err_str(err))); | ||
| 746 | break; | ||
| 747 | } | ||
| 748 | codegen_add_code(g, &top_level_decl->data.use.path, import_code); | ||
| 719 | } | 749 | } |
| 720 | } | 750 | } |
| 751 | |||
| 752 | return import_entry; | ||
| 721 | } | 753 | } |
| 722 | 754 | ||
| 723 | void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) { | 755 | void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) { |
| 724 | init(g, source_path); | 756 | init(g, source_path); |
| 725 | 757 | ||
| 726 | codegen_add_code(g, source_path, source_code); | 758 | g->root_import = codegen_add_code(g, source_path, source_code); |
| 727 | |||
| 728 | 759 | ||
| 729 | if (g->verbose) { | 760 | if (g->verbose) { |
| 730 | fprintf(stderr, "\nSemantic Analysis:\n"); | 761 | fprintf(stderr, "\nSemantic Analysis:\n"); |
| ... | @@ -738,10 +769,8 @@ void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) { | ... | @@ -738,10 +769,8 @@ void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) { |
| 738 | } | 769 | } |
| 739 | } else { | 770 | } else { |
| 740 | for (int i = 0; i < g->errors.length; i += 1) { | 771 | for (int i = 0; i < g->errors.length; i += 1) { |
| 741 | ErrorMsg *err = &g->errors.at(i); | 772 | ErrorMsg *err = g->errors.at(i); |
| 742 | fprintf(stderr, "Error: Line %d, column %d: %s\n", | 773 | print_err_msg(err, g->err_color); |
| 743 | err->line_start + 1, err->column_start + 1, | ||
| 744 | buf_ptr(err->msg)); | ||
| 745 | } | 774 | } |
| 746 | exit(1); | 775 | exit(1); |
| 747 | } | 776 | } |
src/codegen.hpp+2-10| ... | @@ -9,6 +9,7 @@ | ... | @@ -9,6 +9,7 @@ |
| 9 | #define ZIG_CODEGEN_HPP | 9 | #define ZIG_CODEGEN_HPP |
| 10 | 10 | ||
| 11 | #include "parser.hpp" | 11 | #include "parser.hpp" |
| 12 | #include "errmsg.hpp" | ||
| 12 | 13 | ||
| 13 | struct CodeGen; | 14 | struct CodeGen; |
| 14 | 15 | ||
| ... | @@ -19,16 +20,6 @@ enum OutType { | ... | @@ -19,16 +20,6 @@ enum OutType { |
| 19 | OutTypeObj, | 20 | OutTypeObj, |
| 20 | }; | 21 | }; |
| 21 | 22 | ||
| 22 | |||
| 23 | struct ErrorMsg { | ||
| 24 | int line_start; | ||
| 25 | int column_start; | ||
| 26 | int line_end; | ||
| 27 | int column_end; | ||
| 28 | Buf *msg; | ||
| 29 | }; | ||
| 30 | |||
| 31 | |||
| 32 | CodeGen *codegen_create(Buf *root_source_dir); | 23 | CodeGen *codegen_create(Buf *root_source_dir); |
| 33 | 24 | ||
| 34 | enum CodeGenBuildType { | 25 | enum CodeGenBuildType { |
| ... | @@ -39,6 +30,7 @@ void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type); | ... | @@ -39,6 +30,7 @@ void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type); |
| 39 | void codegen_set_is_static(CodeGen *codegen, bool is_static); | 30 | void codegen_set_is_static(CodeGen *codegen, bool is_static); |
| 40 | void codegen_set_strip(CodeGen *codegen, bool strip); | 31 | void codegen_set_strip(CodeGen *codegen, bool strip); |
| 41 | void codegen_set_verbose(CodeGen *codegen, bool verbose); | 32 | void codegen_set_verbose(CodeGen *codegen, bool verbose); |
| 33 | void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color); | ||
| 42 | void codegen_set_out_type(CodeGen *codegen, OutType out_type); | 34 | void codegen_set_out_type(CodeGen *codegen, OutType out_type); |
| 43 | void codegen_set_out_name(CodeGen *codegen, Buf *out_name); | 35 | void codegen_set_out_name(CodeGen *codegen, Buf *out_name); |
| 44 | 36 |
src/errmsg.cpp created+38| ... | @@ -0,0 +1,38 @@ | ||
| 1 | #include "errmsg.hpp" | ||
| 2 | #include "os.hpp" | ||
| 3 | |||
| 4 | #include <stdio.h> | ||
| 5 | |||
| 6 | #define RED "\x1b[31;1m" | ||
| 7 | #define WHITE "\x1b[37;1m" | ||
| 8 | #define GREEN "\x1b[32;1m" | ||
| 9 | #define RESET "\x1b[0m" | ||
| 10 | |||
| 11 | void print_err_msg(ErrorMsg *err, ErrColor color) { | ||
| 12 | if (color == ErrColorOn || (color == ErrColorAuto && os_stderr_tty())) { | ||
| 13 | fprintf(stderr, WHITE "%s:%d:%d: " RED "error:" WHITE " %s" RESET "\n", | ||
| 14 | buf_ptr(err->path), | ||
| 15 | err->line_start + 1, err->column_start + 1, | ||
| 16 | buf_ptr(err->msg)); | ||
| 17 | |||
| 18 | assert(err->source); | ||
| 19 | assert(err->line_offsets); | ||
| 20 | |||
| 21 | int line_start_offset = err->line_offsets->at(err->line_start); | ||
| 22 | int line_end_offset = err->line_offsets->at(err->line_start + 1); | ||
| 23 | |||
| 24 | fwrite(buf_ptr(err->source) + line_start_offset, 1, line_end_offset - line_start_offset - 1, stderr); | ||
| 25 | fprintf(stderr, "\n"); | ||
| 26 | for (int i = 0; i < err->column_start; i += 1) { | ||
| 27 | fprintf(stderr, " "); | ||
| 28 | } | ||
| 29 | fprintf(stderr, GREEN "^" RESET "\n"); | ||
| 30 | |||
| 31 | } else { | ||
| 32 | fprintf(stderr, "%s:%d:%d: error: %s\n", | ||
| 33 | buf_ptr(err->path), | ||
| 34 | err->line_start + 1, err->column_start + 1, | ||
| 35 | buf_ptr(err->msg)); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
src/errmsg.hpp created+33| ... | @@ -0,0 +1,33 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2015 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef ZIG_ERRMSG_HPP | ||
| 9 | #define ZIG_ERRMSG_HPP | ||
| 10 | |||
| 11 | #include "buffer.hpp" | ||
| 12 | #include "list.hpp" | ||
| 13 | |||
| 14 | enum ErrColor { | ||
| 15 | ErrColorAuto, | ||
| 16 | ErrColorOff, | ||
| 17 | ErrColorOn, | ||
| 18 | }; | ||
| 19 | |||
| 20 | struct ErrorMsg { | ||
| 21 | int line_start; | ||
| 22 | int column_start; | ||
| 23 | int line_end; | ||
| 24 | int column_end; | ||
| 25 | Buf *msg; | ||
| 26 | Buf *path; | ||
| 27 | Buf *source; | ||
| 28 | ZigList<int> *line_offsets; | ||
| 29 | }; | ||
| 30 | |||
| 31 | void print_err_msg(ErrorMsg *msg, ErrColor color); | ||
| 32 | |||
| 33 | #endif | ||
src/error.cpp+6| ... | @@ -6,6 +6,12 @@ const char *err_str(int err) { | ... | @@ -6,6 +6,12 @@ const char *err_str(int err) { |
| 6 | case ErrorNoMem: return "out of memory"; | 6 | case ErrorNoMem: return "out of memory"; |
| 7 | case ErrorInvalidFormat: return "invalid format"; | 7 | case ErrorInvalidFormat: return "invalid format"; |
| 8 | case ErrorSemanticAnalyzeFail: return "semantic analyze failed"; | 8 | case ErrorSemanticAnalyzeFail: return "semantic analyze failed"; |
| 9 | case ErrorAccess: return "access denied"; | ||
| 10 | case ErrorInterrupted: return "interrupted"; | ||
| 11 | case ErrorSystemResources: return "lack of system resources"; | ||
| 12 | case ErrorFileNotFound: return "file not found"; | ||
| 13 | case ErrorFileSystem: return "file system error"; | ||
| 14 | case ErrorFileTooBig: return "file too big"; | ||
| 9 | } | 15 | } |
| 10 | return "(invalid error)"; | 16 | return "(invalid error)"; |
| 11 | } | 17 | } |
src/error.hpp+6| ... | @@ -13,6 +13,12 @@ enum Error { | ... | @@ -13,6 +13,12 @@ enum Error { |
| 13 | ErrorNoMem, | 13 | ErrorNoMem, |
| 14 | ErrorInvalidFormat, | 14 | ErrorInvalidFormat, |
| 15 | ErrorSemanticAnalyzeFail, | 15 | ErrorSemanticAnalyzeFail, |
| 16 | ErrorAccess, | ||
| 17 | ErrorInterrupted, | ||
| 18 | ErrorSystemResources, | ||
| 19 | ErrorFileNotFound, | ||
| 20 | ErrorFileSystem, | ||
| 21 | ErrorFileTooBig, | ||
| 16 | }; | 22 | }; |
| 17 | 23 | ||
| 18 | const char *err_str(int err); | 24 | const char *err_str(int err); |
src/main.cpp+16-1| ... | @@ -25,6 +25,7 @@ static int usage(const char *arg0) { | ... | @@ -25,6 +25,7 @@ static int usage(const char *arg0) { |
| 25 | " --name [name] override output name\n" | 25 | " --name [name] override output name\n" |
| 26 | " --output [file] override destination path\n" | 26 | " --output [file] override destination path\n" |
| 27 | " --verbose turn on compiler debug output\n" | 27 | " --verbose turn on compiler debug output\n" |
| 28 | " --color [auto|off|on] enable or disable colored error messages\n" | ||
| 28 | , arg0); | 29 | , arg0); |
| 29 | return EXIT_FAILURE; | 30 | return EXIT_FAILURE; |
| 30 | } | 31 | } |
| ... | @@ -43,6 +44,7 @@ struct Build { | ... | @@ -43,6 +44,7 @@ struct Build { |
| 43 | OutType out_type; | 44 | OutType out_type; |
| 44 | const char *out_name; | 45 | const char *out_name; |
| 45 | bool verbose; | 46 | bool verbose; |
| 47 | ErrColor color; | ||
| 46 | }; | 48 | }; |
| 47 | 49 | ||
| 48 | static int build(const char *arg0, Build *b) { | 50 | static int build(const char *arg0, Build *b) { |
| ... | @@ -73,6 +75,7 @@ static int build(const char *arg0, Build *b) { | ... | @@ -73,6 +75,7 @@ static int build(const char *arg0, Build *b) { |
| 73 | if (b->out_name) | 75 | if (b->out_name) |
| 74 | codegen_set_out_name(g, buf_create_from_str(b->out_name)); | 76 | codegen_set_out_name(g, buf_create_from_str(b->out_name)); |
| 75 | codegen_set_verbose(g, b->verbose); | 77 | codegen_set_verbose(g, b->verbose); |
| 78 | codegen_set_errmsg_color(g, b->color); | ||
| 76 | codegen_add_root_code(g, &root_source_name, &root_source_code); | 79 | codegen_add_root_code(g, &root_source_name, &root_source_code); |
| 77 | codegen_link(g, b->out_file); | 80 | codegen_link(g, b->out_file); |
| 78 | 81 | ||
| ... | @@ -106,7 +109,9 @@ int main(int argc, char **argv) { | ... | @@ -106,7 +109,9 @@ int main(int argc, char **argv) { |
| 106 | return usage(arg0); | 109 | return usage(arg0); |
| 107 | } else { | 110 | } else { |
| 108 | i += 1; | 111 | i += 1; |
| 109 | if (strcmp(arg, "--output") == 0) { | 112 | if (i >= argc) { |
| 113 | return usage(arg0); | ||
| 114 | } else if (strcmp(arg, "--output") == 0) { | ||
| 110 | b.out_file = argv[i]; | 115 | b.out_file = argv[i]; |
| 111 | } else if (strcmp(arg, "--export") == 0) { | 116 | } else if (strcmp(arg, "--export") == 0) { |
| 112 | if (strcmp(argv[i], "exe") == 0) { | 117 | if (strcmp(argv[i], "exe") == 0) { |
| ... | @@ -118,6 +123,16 @@ int main(int argc, char **argv) { | ... | @@ -118,6 +123,16 @@ int main(int argc, char **argv) { |
| 118 | } else { | 123 | } else { |
| 119 | return usage(arg0); | 124 | return usage(arg0); |
| 120 | } | 125 | } |
| 126 | } else if (strcmp(arg, "--color") == 0) { | ||
| 127 | if (strcmp(argv[i], "auto") == 0) { | ||
| 128 | b.color = ErrColorAuto; | ||
| 129 | } else if (strcmp(argv[i], "on") == 0) { | ||
| 130 | b.color = ErrColorOn; | ||
| 131 | } else if (strcmp(argv[i], "off") == 0) { | ||
| 132 | b.color = ErrColorOff; | ||
| 133 | } else { | ||
| 134 | return usage(arg0); | ||
| 135 | } | ||
| 121 | } else if (strcmp(arg, "--name") == 0) { | 136 | } else if (strcmp(arg, "--name") == 0) { |
| 122 | b.out_name = argv[i]; | 137 | b.out_name = argv[i]; |
| 123 | } else { | 138 | } else { |
src/os.cpp+52-8| ... | @@ -7,6 +7,7 @@ | ... | @@ -7,6 +7,7 @@ |
| 7 | 7 | ||
| 8 | #include "os.hpp" | 8 | #include "os.hpp" |
| 9 | #include "util.hpp" | 9 | #include "util.hpp" |
| 10 | #include "error.hpp" | ||
| 10 | 11 | ||
| 11 | #include <unistd.h> | 12 | #include <unistd.h> |
| 12 | #include <errno.h> | 13 | #include <errno.h> |
| ... | @@ -143,26 +144,65 @@ void os_write_file(Buf *full_path, Buf *contents) { | ... | @@ -143,26 +144,65 @@ void os_write_file(Buf *full_path, Buf *contents) { |
| 143 | int os_fetch_file(FILE *f, Buf *out_contents) { | 144 | int os_fetch_file(FILE *f, Buf *out_contents) { |
| 144 | int fd = fileno(f); | 145 | int fd = fileno(f); |
| 145 | struct stat st; | 146 | struct stat st; |
| 146 | if (fstat(fd, &st)) | 147 | if (fstat(fd, &st)) { |
| 147 | zig_panic("unable to stat file: %s", strerror(errno)); | 148 | switch (errno) { |
| 149 | case EACCES: | ||
| 150 | return ErrorAccess; | ||
| 151 | case ENOENT: | ||
| 152 | return ErrorFileNotFound; | ||
| 153 | case ENOMEM: | ||
| 154 | return ErrorSystemResources; | ||
| 155 | case EINTR: | ||
| 156 | return ErrorInterrupted; | ||
| 157 | case EINVAL: | ||
| 158 | zig_unreachable(); | ||
| 159 | default: | ||
| 160 | return ErrorFileSystem; | ||
| 161 | } | ||
| 162 | } | ||
| 148 | off_t big_size = st.st_size; | 163 | off_t big_size = st.st_size; |
| 149 | if (big_size > INT_MAX) | 164 | if (big_size > INT_MAX) { |
| 150 | zig_panic("file too big"); | 165 | return ErrorFileTooBig; |
| 166 | } | ||
| 151 | int size = (int)big_size; | 167 | int size = (int)big_size; |
| 152 | 168 | ||
| 153 | buf_resize(out_contents, size); | 169 | buf_resize(out_contents, size); |
| 154 | ssize_t ret = read(fd, buf_ptr(out_contents), size); | 170 | ssize_t ret = read(fd, buf_ptr(out_contents), size); |
| 155 | 171 | ||
| 156 | if (ret != size) | 172 | if (ret != size) { |
| 157 | zig_panic("unable to read file: %s", strerror(errno)); | 173 | switch (errno) { |
| 174 | case EINTR: | ||
| 175 | return ErrorInterrupted; | ||
| 176 | case EINVAL: | ||
| 177 | case EISDIR: | ||
| 178 | zig_unreachable(); | ||
| 179 | default: | ||
| 180 | return ErrorFileSystem; | ||
| 181 | } | ||
| 182 | } | ||
| 158 | 183 | ||
| 159 | return 0; | 184 | return 0; |
| 160 | } | 185 | } |
| 161 | 186 | ||
| 162 | int os_fetch_file_path(Buf *full_path, Buf *out_contents) { | 187 | int os_fetch_file_path(Buf *full_path, Buf *out_contents) { |
| 163 | FILE *f = fopen(buf_ptr(full_path), "rb"); | 188 | FILE *f = fopen(buf_ptr(full_path), "rb"); |
| 164 | if (!f) | 189 | if (!f) { |
| 165 | zig_panic("unable to open %s: %s\n", buf_ptr(full_path), strerror(errno)); | 190 | switch (errno) { |
| 191 | case EACCES: | ||
| 192 | return ErrorAccess; | ||
| 193 | case EINTR: | ||
| 194 | return ErrorInterrupted; | ||
| 195 | case EINVAL: | ||
| 196 | zig_unreachable(); | ||
| 197 | case ENFILE: | ||
| 198 | case ENOMEM: | ||
| 199 | return ErrorSystemResources; | ||
| 200 | case ENOENT: | ||
| 201 | return ErrorFileNotFound; | ||
| 202 | default: | ||
| 203 | return ErrorFileSystem; | ||
| 204 | } | ||
| 205 | } | ||
| 166 | int result = os_fetch_file(f, out_contents); | 206 | int result = os_fetch_file(f, out_contents); |
| 167 | fclose(f); | 207 | fclose(f); |
| 168 | return result; | 208 | return result; |
| ... | @@ -180,3 +220,7 @@ int os_get_cwd(Buf *out_cwd) { | ... | @@ -180,3 +220,7 @@ int os_get_cwd(Buf *out_cwd) { |
| 180 | 220 | ||
| 181 | return 0; | 221 | return 0; |
| 182 | } | 222 | } |
| 223 | |||
| 224 | bool os_stderr_tty(void) { | ||
| 225 | return isatty(STDERR_FILENO); | ||
| 226 | } |
src/os.hpp+2| ... | @@ -29,4 +29,6 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents); | ... | @@ -29,4 +29,6 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents); |
| 29 | int os_get_cwd(Buf *out_cwd); | 29 | int os_get_cwd(Buf *out_cwd); |
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | bool os_stderr_tty(void); | ||
| 33 | |||
| 32 | #endif | 34 | #endif |
src/parser.cpp+67-53| ... | @@ -6,6 +6,8 @@ | ... | @@ -6,6 +6,8 @@ |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include "parser.hpp" | 8 | #include "parser.hpp" |
| 9 | #include "errmsg.hpp" | ||
| 10 | #include "semantic_info.hpp" | ||
| 9 | 11 | ||
| 10 | #include <stdarg.h> | 12 | #include <stdarg.h> |
| 11 | #include <stdio.h> | 13 | #include <stdio.h> |
| ... | @@ -45,21 +47,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) { | ... | @@ -45,21 +47,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) { |
| 45 | zig_unreachable(); | 47 | zig_unreachable(); |
| 46 | } | 48 | } |
| 47 | 49 | ||
| 48 | __attribute__ ((format (printf, 2, 3))) | ||
| 49 | __attribute__ ((noreturn)) | ||
| 50 | static void ast_error(Token *token, const char *format, ...) { | ||
| 51 | int line = token->start_line + 1; | ||
| 52 | int column = token->start_column + 1; | ||
| 53 | |||
| 54 | va_list ap; | ||
| 55 | va_start(ap, format); | ||
| 56 | fprintf(stderr, "Error: Line %d, column %d: ", line, column); | ||
| 57 | vfprintf(stderr, format, ap); | ||
| 58 | fprintf(stderr, "\n"); | ||
| 59 | va_end(ap); | ||
| 60 | exit(EXIT_FAILURE); | ||
| 61 | } | ||
| 62 | |||
| 63 | const char *node_type_str(NodeType node_type) { | 50 | const char *node_type_str(NodeType node_type) { |
| 64 | switch (node_type) { | 51 | switch (node_type) { |
| 65 | case NodeTypeRoot: | 52 | case NodeTypeRoot: |
| ... | @@ -254,11 +241,36 @@ struct ParseContext { | ... | @@ -254,11 +241,36 @@ struct ParseContext { |
| 254 | AstNode *root; | 241 | AstNode *root; |
| 255 | ZigList<Token> *tokens; | 242 | ZigList<Token> *tokens; |
| 256 | ZigList<AstNode *> *directive_list; | 243 | ZigList<AstNode *> *directive_list; |
| 244 | ImportTableEntry *owner; | ||
| 245 | ErrColor err_color; | ||
| 257 | }; | 246 | }; |
| 258 | 247 | ||
| 259 | static AstNode *ast_create_node_no_line_info(NodeType type) { | 248 | __attribute__ ((format (printf, 3, 4))) |
| 249 | __attribute__ ((noreturn)) | ||
| 250 | static void ast_error(ParseContext *pc, Token *token, const char *format, ...) { | ||
| 251 | ErrorMsg *err = allocate<ErrorMsg>(1); | ||
| 252 | err->line_start = token->start_line; | ||
| 253 | err->column_start = token->start_column; | ||
| 254 | err->line_end = -1; | ||
| 255 | err->column_end = -1; | ||
| 256 | |||
| 257 | va_list ap; | ||
| 258 | va_start(ap, format); | ||
| 259 | err->msg = buf_vprintf(format, ap); | ||
| 260 | va_end(ap); | ||
| 261 | |||
| 262 | err->path = pc->owner->path; | ||
| 263 | err->source = pc->owner->source_code; | ||
| 264 | err->line_offsets = pc->owner->line_offsets; | ||
| 265 | |||
| 266 | print_err_msg(err, pc->err_color); | ||
| 267 | exit(EXIT_FAILURE); | ||
| 268 | } | ||
| 269 | |||
| 270 | static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) { | ||
| 260 | AstNode *node = allocate<AstNode>(1); | 271 | AstNode *node = allocate<AstNode>(1); |
| 261 | node->type = type; | 272 | node->type = type; |
| 273 | node->owner = pc->owner; | ||
| 262 | return node; | 274 | return node; |
| 263 | } | 275 | } |
| 264 | 276 | ||
| ... | @@ -267,21 +279,21 @@ static void ast_update_node_line_info(AstNode *node, Token *first_token) { | ... | @@ -267,21 +279,21 @@ static void ast_update_node_line_info(AstNode *node, Token *first_token) { |
| 267 | node->column = first_token->start_column; | 279 | node->column = first_token->start_column; |
| 268 | } | 280 | } |
| 269 | 281 | ||
| 270 | static AstNode *ast_create_node(NodeType type, Token *first_token) { | 282 | static AstNode *ast_create_node(ParseContext *pc, NodeType type, Token *first_token) { |
| 271 | AstNode *node = ast_create_node_no_line_info(type); | 283 | AstNode *node = ast_create_node_no_line_info(pc, type); |
| 272 | ast_update_node_line_info(node, first_token); | 284 | ast_update_node_line_info(node, first_token); |
| 273 | return node; | 285 | return node; |
| 274 | } | 286 | } |
| 275 | 287 | ||
| 276 | static AstNode *ast_create_node_with_node(NodeType type, AstNode *other_node) { | 288 | static AstNode *ast_create_node_with_node(ParseContext *pc, NodeType type, AstNode *other_node) { |
| 277 | AstNode *node = ast_create_node_no_line_info(type); | 289 | AstNode *node = ast_create_node_no_line_info(pc, type); |
| 278 | node->line = other_node->line; | 290 | node->line = other_node->line; |
| 279 | node->column = other_node->column; | 291 | node->column = other_node->column; |
| 280 | return node; | 292 | return node; |
| 281 | } | 293 | } |
| 282 | 294 | ||
| 283 | static AstNode *ast_create_void_type_node(ParseContext *pc, Token *token) { | 295 | static AstNode *ast_create_void_type_node(ParseContext *pc, Token *token) { |
| 284 | AstNode *node = ast_create_node(NodeTypeType, token); | 296 | AstNode *node = ast_create_node(pc, NodeTypeType, token); |
| 285 | node->data.type.type = AstNodeTypeTypePrimitive; | 297 | node->data.type.type = AstNodeTypeTypePrimitive; |
| 286 | buf_init_from_str(&node->data.type.primitive_name, "void"); | 298 | buf_init_from_str(&node->data.type.primitive_name, "void"); |
| 287 | return node; | 299 | return node; |
| ... | @@ -331,7 +343,7 @@ __attribute__ ((noreturn)) | ... | @@ -331,7 +343,7 @@ __attribute__ ((noreturn)) |
| 331 | static void ast_invalid_token_error(ParseContext *pc, Token *token) { | 343 | static void ast_invalid_token_error(ParseContext *pc, Token *token) { |
| 332 | Buf token_value = BUF_INIT; | 344 | Buf token_value = BUF_INIT; |
| 333 | ast_buf_from_token(pc, token, &token_value); | 345 | ast_buf_from_token(pc, token, &token_value); |
| 334 | ast_error(token, "invalid token: '%s'", buf_ptr(&token_value)); | 346 | ast_error(pc, token, "invalid token: '%s'", buf_ptr(&token_value)); |
| 335 | } | 347 | } |
| 336 | 348 | ||
| 337 | static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool mandatory); | 349 | static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool mandatory); |
| ... | @@ -349,7 +361,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_ | ... | @@ -349,7 +361,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_ |
| 349 | token_index += 1; | 361 | token_index += 1; |
| 350 | ast_expect_token(pc, number_sign, TokenIdNumberSign); | 362 | ast_expect_token(pc, number_sign, TokenIdNumberSign); |
| 351 | 363 | ||
| 352 | AstNode *node = ast_create_node(NodeTypeDirective, number_sign); | 364 | AstNode *node = ast_create_node(pc, NodeTypeDirective, number_sign); |
| 353 | 365 | ||
| 354 | Token *name_symbol = &pc->tokens->at(token_index); | 366 | Token *name_symbol = &pc->tokens->at(token_index); |
| 355 | token_index += 1; | 367 | token_index += 1; |
| ... | @@ -399,7 +411,7 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token | ... | @@ -399,7 +411,7 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token |
| 399 | Token *token = &pc->tokens->at(token_index); | 411 | Token *token = &pc->tokens->at(token_index); |
| 400 | token_index += 1; | 412 | token_index += 1; |
| 401 | 413 | ||
| 402 | AstNode *node = ast_create_node(NodeTypeType, token); | 414 | AstNode *node = ast_create_node(pc, NodeTypeType, token); |
| 403 | 415 | ||
| 404 | if (token->id == TokenIdKeywordUnreachable) { | 416 | if (token->id == TokenIdKeywordUnreachable) { |
| 405 | node->data.type.type = AstNodeTypeTypePrimitive; | 417 | node->data.type.type = AstNodeTypeTypePrimitive; |
| ... | @@ -437,7 +449,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new | ... | @@ -437,7 +449,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new |
| 437 | token_index += 1; | 449 | token_index += 1; |
| 438 | ast_expect_token(pc, param_name, TokenIdSymbol); | 450 | ast_expect_token(pc, param_name, TokenIdSymbol); |
| 439 | 451 | ||
| 440 | AstNode *node = ast_create_node(NodeTypeParamDecl, param_name); | 452 | AstNode *node = ast_create_node(pc, NodeTypeParamDecl, param_name); |
| 441 | 453 | ||
| 442 | 454 | ||
| 443 | ast_buf_from_token(pc, param_name, &node->data.param_decl.name); | 455 | ast_buf_from_token(pc, param_name, &node->data.param_decl.name); |
| ... | @@ -544,21 +556,21 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool | ... | @@ -544,21 +556,21 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 544 | Token *token = &pc->tokens->at(*token_index); | 556 | Token *token = &pc->tokens->at(*token_index); |
| 545 | 557 | ||
| 546 | if (token->id == TokenIdNumberLiteral) { | 558 | if (token->id == TokenIdNumberLiteral) { |
| 547 | AstNode *node = ast_create_node(NodeTypeNumberLiteral, token); | 559 | AstNode *node = ast_create_node(pc, NodeTypeNumberLiteral, token); |
| 548 | ast_buf_from_token(pc, token, &node->data.number); | 560 | ast_buf_from_token(pc, token, &node->data.number); |
| 549 | *token_index += 1; | 561 | *token_index += 1; |
| 550 | return node; | 562 | return node; |
| 551 | } else if (token->id == TokenIdStringLiteral) { | 563 | } else if (token->id == TokenIdStringLiteral) { |
| 552 | AstNode *node = ast_create_node(NodeTypeStringLiteral, token); | 564 | AstNode *node = ast_create_node(pc, NodeTypeStringLiteral, token); |
| 553 | parse_string_literal(pc, token, &node->data.string); | 565 | parse_string_literal(pc, token, &node->data.string); |
| 554 | *token_index += 1; | 566 | *token_index += 1; |
| 555 | return node; | 567 | return node; |
| 556 | } else if (token->id == TokenIdKeywordUnreachable) { | 568 | } else if (token->id == TokenIdKeywordUnreachable) { |
| 557 | AstNode *node = ast_create_node(NodeTypeUnreachable, token); | 569 | AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token); |
| 558 | *token_index += 1; | 570 | *token_index += 1; |
| 559 | return node; | 571 | return node; |
| 560 | } else if (token->id == TokenIdSymbol) { | 572 | } else if (token->id == TokenIdSymbol) { |
| 561 | AstNode *node = ast_create_node(NodeTypeSymbol, token); | 573 | AstNode *node = ast_create_node(pc, NodeTypeSymbol, token); |
| 562 | ast_buf_from_token(pc, token, &node->data.symbol); | 574 | ast_buf_from_token(pc, token, &node->data.symbol); |
| 563 | *token_index += 1; | 575 | *token_index += 1; |
| 564 | return node; | 576 | return node; |
| ... | @@ -592,7 +604,7 @@ static AstNode *ast_parse_fn_call_expr(ParseContext *pc, int *token_index, bool | ... | @@ -592,7 +604,7 @@ static AstNode *ast_parse_fn_call_expr(ParseContext *pc, int *token_index, bool |
| 592 | if (l_paren->id != TokenIdLParen) | 604 | if (l_paren->id != TokenIdLParen) |
| 593 | return primary_expr; | 605 | return primary_expr; |
| 594 | 606 | ||
| 595 | AstNode *node = ast_create_node_with_node(NodeTypeFnCallExpr, primary_expr); | 607 | AstNode *node = ast_create_node_with_node(pc, NodeTypeFnCallExpr, primary_expr); |
| 596 | node->data.fn_call_expr.fn_ref_expr = primary_expr; | 608 | node->data.fn_call_expr.fn_ref_expr = primary_expr; |
| 597 | ast_parse_fn_call_param_list(pc, *token_index, token_index, &node->data.fn_call_expr.params); | 609 | ast_parse_fn_call_param_list(pc, *token_index, token_index, &node->data.fn_call_expr.params); |
| 598 | 610 | ||
| ... | @@ -635,7 +647,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo | ... | @@ -635,7 +647,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo |
| 635 | return ast_parse_fn_call_expr(pc, token_index, mandatory); | 647 | return ast_parse_fn_call_expr(pc, token_index, mandatory); |
| 636 | 648 | ||
| 637 | AstNode *primary_expr = ast_parse_fn_call_expr(pc, token_index, true); | 649 | AstNode *primary_expr = ast_parse_fn_call_expr(pc, token_index, true); |
| 638 | AstNode *node = ast_create_node(NodeTypePrefixOpExpr, token); | 650 | AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token); |
| 639 | node->data.prefix_op_expr.primary_expr = primary_expr; | 651 | node->data.prefix_op_expr.primary_expr = primary_expr; |
| 640 | node->data.prefix_op_expr.prefix_op = prefix_op; | 652 | node->data.prefix_op_expr.prefix_op = prefix_op; |
| 641 | 653 | ||
| ... | @@ -656,7 +668,7 @@ static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bo | ... | @@ -656,7 +668,7 @@ static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bo |
| 656 | return prefix_op_expr; | 668 | return prefix_op_expr; |
| 657 | *token_index += 1; | 669 | *token_index += 1; |
| 658 | 670 | ||
| 659 | AstNode *node = ast_create_node(NodeTypeCastExpr, as_kw); | 671 | AstNode *node = ast_create_node(pc, NodeTypeCastExpr, as_kw); |
| 660 | node->data.cast_expr.prefix_op_expr = prefix_op_expr; | 672 | node->data.cast_expr.prefix_op_expr = prefix_op_expr; |
| 661 | 673 | ||
| 662 | node->data.cast_expr.type = ast_parse_type(pc, *token_index, token_index); | 674 | node->data.cast_expr.type = ast_parse_type(pc, *token_index, token_index); |
| ... | @@ -705,7 +717,7 @@ static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool man | ... | @@ -705,7 +717,7 @@ static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool man |
| 705 | 717 | ||
| 706 | AstNode *operand_2 = ast_parse_cast_expression(pc, token_index, true); | 718 | AstNode *operand_2 = ast_parse_cast_expression(pc, token_index, true); |
| 707 | 719 | ||
| 708 | AstNode *node = ast_create_node(NodeTypeBinOpExpr, token); | 720 | AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); |
| 709 | node->data.bin_op_expr.op1 = operand_1; | 721 | node->data.bin_op_expr.op1 = operand_1; |
| 710 | node->data.bin_op_expr.bin_op = mult_op; | 722 | node->data.bin_op_expr.bin_op = mult_op; |
| 711 | node->data.bin_op_expr.op2 = operand_2; | 723 | node->data.bin_op_expr.op2 = operand_2; |
| ... | @@ -753,7 +765,7 @@ static AstNode *ast_parse_add_expr(ParseContext *pc, int *token_index, bool mand | ... | @@ -753,7 +765,7 @@ static AstNode *ast_parse_add_expr(ParseContext *pc, int *token_index, bool mand |
| 753 | 765 | ||
| 754 | AstNode *operand_2 = ast_parse_mult_expr(pc, token_index, true); | 766 | AstNode *operand_2 = ast_parse_mult_expr(pc, token_index, true); |
| 755 | 767 | ||
| 756 | AstNode *node = ast_create_node(NodeTypeBinOpExpr, token); | 768 | AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); |
| 757 | node->data.bin_op_expr.op1 = operand_1; | 769 | node->data.bin_op_expr.op1 = operand_1; |
| 758 | node->data.bin_op_expr.bin_op = add_op; | 770 | node->data.bin_op_expr.bin_op = add_op; |
| 759 | node->data.bin_op_expr.op2 = operand_2; | 771 | node->data.bin_op_expr.op2 = operand_2; |
| ... | @@ -801,7 +813,7 @@ static AstNode *ast_parse_bit_shift_expr(ParseContext *pc, int *token_index, boo | ... | @@ -801,7 +813,7 @@ static AstNode *ast_parse_bit_shift_expr(ParseContext *pc, int *token_index, boo |
| 801 | 813 | ||
| 802 | AstNode *operand_2 = ast_parse_add_expr(pc, token_index, true); | 814 | AstNode *operand_2 = ast_parse_add_expr(pc, token_index, true); |
| 803 | 815 | ||
| 804 | AstNode *node = ast_create_node(NodeTypeBinOpExpr, token); | 816 | AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); |
| 805 | node->data.bin_op_expr.op1 = operand_1; | 817 | node->data.bin_op_expr.op1 = operand_1; |
| 806 | node->data.bin_op_expr.bin_op = bit_shift_op; | 818 | node->data.bin_op_expr.bin_op = bit_shift_op; |
| 807 | node->data.bin_op_expr.op2 = operand_2; | 819 | node->data.bin_op_expr.op2 = operand_2; |
| ... | @@ -825,7 +837,7 @@ static AstNode *ast_parse_bin_and_expr(ParseContext *pc, int *token_index, bool | ... | @@ -825,7 +837,7 @@ static AstNode *ast_parse_bin_and_expr(ParseContext *pc, int *token_index, bool |
| 825 | 837 | ||
| 826 | AstNode *operand_2 = ast_parse_bit_shift_expr(pc, token_index, true); | 838 | AstNode *operand_2 = ast_parse_bit_shift_expr(pc, token_index, true); |
| 827 | 839 | ||
| 828 | AstNode *node = ast_create_node(NodeTypeBinOpExpr, token); | 840 | AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); |
| 829 | node->data.bin_op_expr.op1 = operand_1; | 841 | node->data.bin_op_expr.op1 = operand_1; |
| 830 | node->data.bin_op_expr.bin_op = BinOpTypeBinAnd; | 842 | node->data.bin_op_expr.bin_op = BinOpTypeBinAnd; |
| 831 | node->data.bin_op_expr.op2 = operand_2; | 843 | node->data.bin_op_expr.op2 = operand_2; |
| ... | @@ -848,7 +860,7 @@ static AstNode *ast_parse_bin_xor_expr(ParseContext *pc, int *token_index, bool | ... | @@ -848,7 +860,7 @@ static AstNode *ast_parse_bin_xor_expr(ParseContext *pc, int *token_index, bool |
| 848 | 860 | ||
| 849 | AstNode *operand_2 = ast_parse_bin_and_expr(pc, token_index, true); | 861 | AstNode *operand_2 = ast_parse_bin_and_expr(pc, token_index, true); |
| 850 | 862 | ||
| 851 | AstNode *node = ast_create_node(NodeTypeBinOpExpr, token); | 863 | AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); |
| 852 | node->data.bin_op_expr.op1 = operand_1; | 864 | node->data.bin_op_expr.op1 = operand_1; |
| 853 | node->data.bin_op_expr.bin_op = BinOpTypeBinXor; | 865 | node->data.bin_op_expr.bin_op = BinOpTypeBinXor; |
| 854 | node->data.bin_op_expr.op2 = operand_2; | 866 | node->data.bin_op_expr.op2 = operand_2; |
| ... | @@ -871,7 +883,7 @@ static AstNode *ast_parse_bin_or_expr(ParseContext *pc, int *token_index, bool m | ... | @@ -871,7 +883,7 @@ static AstNode *ast_parse_bin_or_expr(ParseContext *pc, int *token_index, bool m |
| 871 | 883 | ||
| 872 | AstNode *operand_2 = ast_parse_bin_xor_expr(pc, token_index, true); | 884 | AstNode *operand_2 = ast_parse_bin_xor_expr(pc, token_index, true); |
| 873 | 885 | ||
| 874 | AstNode *node = ast_create_node(NodeTypeBinOpExpr, token); | 886 | AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); |
| 875 | node->data.bin_op_expr.op1 = operand_1; | 887 | node->data.bin_op_expr.op1 = operand_1; |
| 876 | node->data.bin_op_expr.bin_op = BinOpTypeBinOr; | 888 | node->data.bin_op_expr.bin_op = BinOpTypeBinOr; |
| 877 | node->data.bin_op_expr.op2 = operand_2; | 889 | node->data.bin_op_expr.op2 = operand_2; |
| ... | @@ -920,7 +932,7 @@ static AstNode *ast_parse_comparison_expr(ParseContext *pc, int *token_index, bo | ... | @@ -920,7 +932,7 @@ static AstNode *ast_parse_comparison_expr(ParseContext *pc, int *token_index, bo |
| 920 | 932 | ||
| 921 | AstNode *operand_2 = ast_parse_bin_or_expr(pc, token_index, true); | 933 | AstNode *operand_2 = ast_parse_bin_or_expr(pc, token_index, true); |
| 922 | 934 | ||
| 923 | AstNode *node = ast_create_node(NodeTypeBinOpExpr, token); | 935 | AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); |
| 924 | node->data.bin_op_expr.op1 = operand_1; | 936 | node->data.bin_op_expr.op1 = operand_1; |
| 925 | node->data.bin_op_expr.bin_op = cmp_op; | 937 | node->data.bin_op_expr.bin_op = cmp_op; |
| 926 | node->data.bin_op_expr.op2 = operand_2; | 938 | node->data.bin_op_expr.op2 = operand_2; |
| ... | @@ -943,7 +955,7 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc, int *token_index, bool | ... | @@ -943,7 +955,7 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc, int *token_index, bool |
| 943 | 955 | ||
| 944 | AstNode *operand_2 = ast_parse_comparison_expr(pc, token_index, true); | 956 | AstNode *operand_2 = ast_parse_comparison_expr(pc, token_index, true); |
| 945 | 957 | ||
| 946 | AstNode *node = ast_create_node(NodeTypeBinOpExpr, token); | 958 | AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); |
| 947 | node->data.bin_op_expr.op1 = operand_1; | 959 | node->data.bin_op_expr.op1 = operand_1; |
| 948 | node->data.bin_op_expr.bin_op = BinOpTypeBoolAnd; | 960 | node->data.bin_op_expr.bin_op = BinOpTypeBoolAnd; |
| 949 | node->data.bin_op_expr.op2 = operand_2; | 961 | node->data.bin_op_expr.op2 = operand_2; |
| ... | @@ -958,7 +970,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m | ... | @@ -958,7 +970,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m |
| 958 | Token *return_tok = &pc->tokens->at(*token_index); | 970 | Token *return_tok = &pc->tokens->at(*token_index); |
| 959 | if (return_tok->id == TokenIdKeywordReturn) { | 971 | if (return_tok->id == TokenIdKeywordReturn) { |
| 960 | *token_index += 1; | 972 | *token_index += 1; |
| 961 | AstNode *node = ast_create_node(NodeTypeReturnExpr, return_tok); | 973 | AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, return_tok); |
| 962 | node->data.return_expr.expr = ast_parse_expression(pc, token_index, false); | 974 | node->data.return_expr.expr = ast_parse_expression(pc, token_index, false); |
| 963 | return node; | 975 | return node; |
| 964 | } else if (mandatory) { | 976 | } else if (mandatory) { |
| ... | @@ -983,7 +995,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool | ... | @@ -983,7 +995,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool |
| 983 | 995 | ||
| 984 | AstNode *operand_2 = ast_parse_bool_and_expr(pc, token_index, true); | 996 | AstNode *operand_2 = ast_parse_bool_and_expr(pc, token_index, true); |
| 985 | 997 | ||
| 986 | AstNode *node = ast_create_node(NodeTypeBinOpExpr, token); | 998 | AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); |
| 987 | node->data.bin_op_expr.op1 = operand_1; | 999 | node->data.bin_op_expr.op1 = operand_1; |
| 988 | node->data.bin_op_expr.bin_op = BinOpTypeBoolOr; | 1000 | node->data.bin_op_expr.bin_op = BinOpTypeBoolOr; |
| 989 | node->data.bin_op_expr.op2 = operand_2; | 1001 | node->data.bin_op_expr.op2 = operand_2; |
| ... | @@ -1046,7 +1058,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato | ... | @@ -1046,7 +1058,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato |
| 1046 | } | 1058 | } |
| 1047 | *token_index += 1; | 1059 | *token_index += 1; |
| 1048 | 1060 | ||
| 1049 | AstNode *node = ast_create_node(NodeTypeBlock, l_brace); | 1061 | AstNode *node = ast_create_node(pc, NodeTypeBlock, l_brace); |
| 1050 | 1062 | ||
| 1051 | for (;;) { | 1063 | for (;;) { |
| 1052 | Token *token = &pc->tokens->at(*token_index); | 1064 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -1092,7 +1104,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand | ... | @@ -1092,7 +1104,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand |
| 1092 | return nullptr; | 1104 | return nullptr; |
| 1093 | } | 1105 | } |
| 1094 | 1106 | ||
| 1095 | AstNode *node = ast_create_node(NodeTypeFnProto, token); | 1107 | AstNode *node = ast_create_node(pc, NodeTypeFnProto, token); |
| 1096 | node->data.fn_proto.visib_mod = visib_mod; | 1108 | node->data.fn_proto.visib_mod = visib_mod; |
| 1097 | node->data.fn_proto.directives = pc->directive_list; | 1109 | node->data.fn_proto.directives = pc->directive_list; |
| 1098 | pc->directive_list = nullptr; | 1110 | pc->directive_list = nullptr; |
| ... | @@ -1125,7 +1137,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandat | ... | @@ -1125,7 +1137,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandat |
| 1125 | AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory); | 1137 | AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory); |
| 1126 | if (!fn_proto) | 1138 | if (!fn_proto) |
| 1127 | return nullptr; | 1139 | return nullptr; |
| 1128 | AstNode *node = ast_create_node_with_node(NodeTypeFnDef, fn_proto); | 1140 | AstNode *node = ast_create_node_with_node(pc, NodeTypeFnDef, fn_proto); |
| 1129 | 1141 | ||
| 1130 | node->data.fn_def.fn_proto = fn_proto; | 1142 | node->data.fn_def.fn_proto = fn_proto; |
| 1131 | node->data.fn_def.body = ast_parse_block(pc, token_index, true); | 1143 | node->data.fn_def.body = ast_parse_block(pc, token_index, true); |
| ... | @@ -1138,7 +1150,7 @@ FnDecl : FnProto token(Semicolon) | ... | @@ -1138,7 +1150,7 @@ FnDecl : FnProto token(Semicolon) |
| 1138 | */ | 1150 | */ |
| 1139 | static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) { | 1151 | static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) { |
| 1140 | AstNode *fn_proto = ast_parse_fn_proto(pc, &token_index, true); | 1152 | AstNode *fn_proto = ast_parse_fn_proto(pc, &token_index, true); |
| 1141 | AstNode *node = ast_create_node_with_node(NodeTypeFnDecl, fn_proto); | 1153 | AstNode *node = ast_create_node_with_node(pc, NodeTypeFnDecl, fn_proto); |
| 1142 | 1154 | ||
| 1143 | node->data.fn_decl.fn_proto = fn_proto; | 1155 | node->data.fn_decl.fn_proto = fn_proto; |
| 1144 | 1156 | ||
| ... | @@ -1166,7 +1178,7 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool | ... | @@ -1166,7 +1178,7 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool |
| 1166 | } | 1178 | } |
| 1167 | *token_index += 1; | 1179 | *token_index += 1; |
| 1168 | 1180 | ||
| 1169 | AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw); | 1181 | AstNode *node = ast_create_node(pc, NodeTypeExternBlock, extern_kw); |
| 1170 | 1182 | ||
| 1171 | node->data.extern_block.directives = pc->directive_list; | 1183 | node->data.extern_block.directives = pc->directive_list; |
| 1172 | pc->directive_list = nullptr; | 1184 | pc->directive_list = nullptr; |
| ... | @@ -1184,7 +1196,7 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool | ... | @@ -1184,7 +1196,7 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool |
| 1184 | Token *token = &pc->tokens->at(*token_index); | 1196 | Token *token = &pc->tokens->at(*token_index); |
| 1185 | if (token->id == TokenIdRBrace) { | 1197 | if (token->id == TokenIdRBrace) { |
| 1186 | if (pc->directive_list->length > 0) { | 1198 | if (pc->directive_list->length > 0) { |
| 1187 | ast_error(directive_token, "invalid directive"); | 1199 | ast_error(pc, directive_token, "invalid directive"); |
| 1188 | } | 1200 | } |
| 1189 | pc->directive_list = nullptr; | 1201 | pc->directive_list = nullptr; |
| 1190 | 1202 | ||
| ... | @@ -1216,7 +1228,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b | ... | @@ -1216,7 +1228,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b |
| 1216 | 1228 | ||
| 1217 | *token_index += 2; | 1229 | *token_index += 2; |
| 1218 | 1230 | ||
| 1219 | AstNode *node = ast_create_node(NodeTypeRootExportDecl, export_kw); | 1231 | AstNode *node = ast_create_node(pc, NodeTypeRootExportDecl, export_kw); |
| 1220 | node->data.root_export_decl.directives = pc->directive_list; | 1232 | node->data.root_export_decl.directives = pc->directive_list; |
| 1221 | pc->directive_list = nullptr; | 1233 | pc->directive_list = nullptr; |
| 1222 | 1234 | ||
| ... | @@ -1254,7 +1266,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory | ... | @@ -1254,7 +1266,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory |
| 1254 | *token_index += 1; | 1266 | *token_index += 1; |
| 1255 | ast_expect_token(pc, semicolon, TokenIdSemicolon); | 1267 | ast_expect_token(pc, semicolon, TokenIdSemicolon); |
| 1256 | 1268 | ||
| 1257 | AstNode *node = ast_create_node(NodeTypeUse, use_kw); | 1269 | AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw); |
| 1258 | 1270 | ||
| 1259 | parse_string_literal(pc, use_name, &node->data.use.path); | 1271 | parse_string_literal(pc, use_name, &node->data.use.path); |
| 1260 | 1272 | ||
| ... | @@ -1299,7 +1311,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis | ... | @@ -1299,7 +1311,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis |
| 1299 | } | 1311 | } |
| 1300 | 1312 | ||
| 1301 | if (pc->directive_list->length > 0) { | 1313 | if (pc->directive_list->length > 0) { |
| 1302 | ast_error(directive_token, "invalid directive"); | 1314 | ast_error(pc, directive_token, "invalid directive"); |
| 1303 | } | 1315 | } |
| 1304 | pc->directive_list = nullptr; | 1316 | pc->directive_list = nullptr; |
| 1305 | 1317 | ||
| ... | @@ -1312,7 +1324,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis | ... | @@ -1312,7 +1324,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis |
| 1312 | Root : many(TopLevelDecl) token(EOF) | 1324 | Root : many(TopLevelDecl) token(EOF) |
| 1313 | */ | 1325 | */ |
| 1314 | static AstNode *ast_parse_root(ParseContext *pc, int *token_index) { | 1326 | static AstNode *ast_parse_root(ParseContext *pc, int *token_index) { |
| 1315 | AstNode *node = ast_create_node(NodeTypeRoot, &pc->tokens->at(*token_index)); | 1327 | AstNode *node = ast_create_node(pc, NodeTypeRoot, &pc->tokens->at(*token_index)); |
| 1316 | 1328 | ||
| 1317 | ast_parse_top_level_decls(pc, token_index, &node->data.root.top_level_decls); | 1329 | ast_parse_top_level_decls(pc, token_index, &node->data.root.top_level_decls); |
| 1318 | 1330 | ||
| ... | @@ -1323,8 +1335,10 @@ static AstNode *ast_parse_root(ParseContext *pc, int *token_index) { | ... | @@ -1323,8 +1335,10 @@ static AstNode *ast_parse_root(ParseContext *pc, int *token_index) { |
| 1323 | return node; | 1335 | return node; |
| 1324 | } | 1336 | } |
| 1325 | 1337 | ||
| 1326 | AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { | 1338 | AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color) { |
| 1327 | ParseContext pc = {0}; | 1339 | ParseContext pc = {0}; |
| 1340 | pc.err_color = err_color; | ||
| 1341 | pc.owner = owner; | ||
| 1328 | pc.buf = buf; | 1342 | pc.buf = buf; |
| 1329 | pc.tokens = tokens; | 1343 | pc.tokens = tokens; |
| 1330 | int token_index = 0; | 1344 | int token_index = 0; |
src/parser.hpp+4-2| ... | @@ -11,9 +11,11 @@ | ... | @@ -11,9 +11,11 @@ |
| 11 | #include "list.hpp" | 11 | #include "list.hpp" |
| 12 | #include "buffer.hpp" | 12 | #include "buffer.hpp" |
| 13 | #include "tokenizer.hpp" | 13 | #include "tokenizer.hpp" |
| 14 | #include "errmsg.hpp" | ||
| 14 | 15 | ||
| 15 | struct AstNode; | 16 | struct AstNode; |
| 16 | struct CodeGenNode; | 17 | struct CodeGenNode; |
| 18 | struct ImportTableEntry; | ||
| 17 | 19 | ||
| 18 | enum NodeType { | 20 | enum NodeType { |
| 19 | NodeTypeRoot, | 21 | NodeTypeRoot, |
| ... | @@ -166,10 +168,10 @@ struct AstNodeUse { | ... | @@ -166,10 +168,10 @@ struct AstNodeUse { |
| 166 | 168 | ||
| 167 | struct AstNode { | 169 | struct AstNode { |
| 168 | enum NodeType type; | 170 | enum NodeType type; |
| 169 | AstNode *parent; | ||
| 170 | int line; | 171 | int line; |
| 171 | int column; | 172 | int column; |
| 172 | CodeGenNode *codegen_node; | 173 | CodeGenNode *codegen_node; |
| 174 | ImportTableEntry *owner; | ||
| 173 | union { | 175 | union { |
| 174 | AstNodeRoot root; | 176 | AstNodeRoot root; |
| 175 | AstNodeRootExportDecl root_export_decl; | 177 | AstNodeRootExportDecl root_export_decl; |
| ... | @@ -198,7 +200,7 @@ void ast_token_error(Token *token, const char *format, ...); | ... | @@ -198,7 +200,7 @@ void ast_token_error(Token *token, const char *format, ...); |
| 198 | 200 | ||
| 199 | 201 | ||
| 200 | // This function is provided by generated code, generated by parsergen.cpp | 202 | // This function is provided by generated code, generated by parsergen.cpp |
| 201 | AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens); | 203 | AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color); |
| 202 | 204 | ||
| 203 | const char *node_type_str(NodeType node_type); | 205 | const char *node_type_str(NodeType node_type); |
| 204 | 206 |
src/semantic_info.hpp+13-1| ... | @@ -11,6 +11,7 @@ | ... | @@ -11,6 +11,7 @@ |
| 11 | #include "codegen.hpp" | 11 | #include "codegen.hpp" |
| 12 | #include "hash_map.hpp" | 12 | #include "hash_map.hpp" |
| 13 | #include "zig_llvm.hpp" | 13 | #include "zig_llvm.hpp" |
| 14 | #include "errmsg.hpp" | ||
| 14 | 15 | ||
| 15 | struct FnTableEntry; | 16 | struct FnTableEntry; |
| 16 | 17 | ||
| ... | @@ -30,6 +31,8 @@ struct ImportTableEntry { | ... | @@ -30,6 +31,8 @@ struct ImportTableEntry { |
| 30 | AstNode *root; | 31 | AstNode *root; |
| 31 | Buf *path; // relative to root_source_dir | 32 | Buf *path; // relative to root_source_dir |
| 32 | LLVMZigDIFile *di_file; | 33 | LLVMZigDIFile *di_file; |
| 34 | Buf *source_code; | ||
| 35 | ZigList<int> *line_offsets; | ||
| 33 | 36 | ||
| 34 | // reminder: hash tables must be initialized before use | 37 | // reminder: hash tables must be initialized before use |
| 35 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | 38 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; |
| ... | @@ -47,7 +50,7 @@ struct FnTableEntry { | ... | @@ -47,7 +50,7 @@ struct FnTableEntry { |
| 47 | 50 | ||
| 48 | struct CodeGen { | 51 | struct CodeGen { |
| 49 | LLVMModuleRef module; | 52 | LLVMModuleRef module; |
| 50 | ZigList<ErrorMsg> errors; | 53 | ZigList<ErrorMsg*> errors; |
| 51 | LLVMBuilderRef builder; | 54 | LLVMBuilderRef builder; |
| 52 | LLVMZigDIBuilder *dbuilder; | 55 | LLVMZigDIBuilder *dbuilder; |
| 53 | LLVMZigDICompileUnit *compile_unit; | 56 | LLVMZigDICompileUnit *compile_unit; |
| ... | @@ -77,7 +80,14 @@ struct CodeGen { | ... | @@ -77,7 +80,14 @@ struct CodeGen { |
| 77 | Buf *root_source_dir; | 80 | Buf *root_source_dir; |
| 78 | Buf *root_out_name; | 81 | Buf *root_out_name; |
| 79 | ZigList<LLVMZigDIScope *> block_scopes; | 82 | ZigList<LLVMZigDIScope *> block_scopes; |
| 83 | |||
| 84 | // The function definitions this module includes. There must be a corresponding | ||
| 85 | // fn_protos entry. | ||
| 80 | ZigList<FnTableEntry *> fn_defs; | 86 | ZigList<FnTableEntry *> fn_defs; |
| 87 | // The function prototypes this module includes. In the case of external declarations, | ||
| 88 | // there will not be a corresponding fn_defs entry. | ||
| 89 | ZigList<FnTableEntry *> fn_protos; | ||
| 90 | |||
| 81 | OutType out_type; | 91 | OutType out_type; |
| 82 | FnTableEntry *cur_fn; | 92 | FnTableEntry *cur_fn; |
| 83 | bool c_stdint_used; | 93 | bool c_stdint_used; |
| ... | @@ -86,6 +96,8 @@ struct CodeGen { | ... | @@ -86,6 +96,8 @@ struct CodeGen { |
| 86 | int version_minor; | 96 | int version_minor; |
| 87 | int version_patch; | 97 | int version_patch; |
| 88 | bool verbose; | 98 | bool verbose; |
| 99 | ErrColor err_color; | ||
| 100 | ImportTableEntry *root_import; | ||
| 89 | }; | 101 | }; |
| 90 | 102 | ||
| 91 | struct TypeNode { | 103 | struct TypeNode { |
src/tokenizer.cpp+26-17| ... | @@ -104,6 +104,7 @@ enum TokenizeState { | ... | @@ -104,6 +104,7 @@ enum TokenizeState { |
| 104 | TokenizeStateBang, | 104 | TokenizeStateBang, |
| 105 | TokenizeStateLessThan, | 105 | TokenizeStateLessThan, |
| 106 | TokenizeStateGreaterThan, | 106 | TokenizeStateGreaterThan, |
| 107 | TokenizeStateError, | ||
| 107 | }; | 108 | }; |
| 108 | 109 | ||
| 109 | 110 | ||
| ... | @@ -116,27 +117,25 @@ struct Tokenize { | ... | @@ -116,27 +117,25 @@ struct Tokenize { |
| 116 | int column; | 117 | int column; |
| 117 | Token *cur_tok; | 118 | Token *cur_tok; |
| 118 | int multi_line_comment_count; | 119 | int multi_line_comment_count; |
| 120 | Tokenization *out; | ||
| 119 | }; | 121 | }; |
| 120 | 122 | ||
| 121 | __attribute__ ((format (printf, 2, 3))) | 123 | __attribute__ ((format (printf, 2, 3))) |
| 122 | static void tokenize_error(Tokenize *t, const char *format, ...) { | 124 | static void tokenize_error(Tokenize *t, const char *format, ...) { |
| 123 | int line; | 125 | t->state = TokenizeStateError; |
| 124 | int column; | 126 | |
| 125 | if (t->cur_tok) { | 127 | if (t->cur_tok) { |
| 126 | line = t->cur_tok->start_line + 1; | 128 | t->out->err_line = t->cur_tok->start_line; |
| 127 | column = t->cur_tok->start_column + 1; | 129 | t->out->err_column = t->cur_tok->start_column; |
| 128 | } else { | 130 | } else { |
| 129 | line = t->line + 1; | 131 | t->out->err_line = t->line; |
| 130 | column = t->column + 1; | 132 | t->out->err_column = t->column; |
| 131 | } | 133 | } |
| 132 | 134 | ||
| 133 | va_list ap; | 135 | va_list ap; |
| 134 | va_start(ap, format); | 136 | va_start(ap, format); |
| 135 | fprintf(stderr, "Error: Line %d, column %d: ", line, column); | 137 | t->out->err = buf_vprintf(format, ap); |
| 136 | vfprintf(stderr, format, ap); | ||
| 137 | fprintf(stderr, "\n"); | ||
| 138 | va_end(ap); | 138 | va_end(ap); |
| 139 | exit(EXIT_FAILURE); | ||
| 140 | } | 139 | } |
| 141 | 140 | ||
| 142 | static void begin_token(Tokenize *t, TokenId id) { | 141 | static void begin_token(Tokenize *t, TokenId id) { |
| ... | @@ -187,13 +186,20 @@ static void end_token(Tokenize *t) { | ... | @@ -187,13 +186,20 @@ static void end_token(Tokenize *t) { |
| 187 | t->cur_tok = nullptr; | 186 | t->cur_tok = nullptr; |
| 188 | } | 187 | } |
| 189 | 188 | ||
| 190 | ZigList<Token> *tokenize(Buf *buf) { | 189 | void tokenize(Buf *buf, Tokenization *out) { |
| 191 | Tokenize t = {0}; | 190 | Tokenize t = {0}; |
| 192 | t.tokens = allocate<ZigList<Token>>(1); | 191 | t.out = out; |
| 192 | t.tokens = out->tokens = allocate<ZigList<Token>>(1); | ||
| 193 | t.buf = buf; | 193 | t.buf = buf; |
| 194 | |||
| 195 | out->line_offsets = allocate<ZigList<int>>(1); | ||
| 196 | |||
| 197 | out->line_offsets->append(0); | ||
| 194 | for (t.pos = 0; t.pos < buf_len(t.buf); t.pos += 1) { | 198 | for (t.pos = 0; t.pos < buf_len(t.buf); t.pos += 1) { |
| 195 | uint8_t c = buf_ptr(t.buf)[t.pos]; | 199 | uint8_t c = buf_ptr(t.buf)[t.pos]; |
| 196 | switch (t.state) { | 200 | switch (t.state) { |
| 201 | case TokenizeStateError: | ||
| 202 | break; | ||
| 197 | case TokenizeStateStart: | 203 | case TokenizeStateStart: |
| 198 | switch (c) { | 204 | switch (c) { |
| 199 | case WHITESPACE: | 205 | case WHITESPACE: |
| ... | @@ -509,6 +515,7 @@ ZigList<Token> *tokenize(Buf *buf) { | ... | @@ -509,6 +515,7 @@ ZigList<Token> *tokenize(Buf *buf) { |
| 509 | break; | 515 | break; |
| 510 | } | 516 | } |
| 511 | if (c == '\n') { | 517 | if (c == '\n') { |
| 518 | out->line_offsets->append(t.pos + 1); | ||
| 512 | t.line += 1; | 519 | t.line += 1; |
| 513 | t.column = 0; | 520 | t.column = 0; |
| 514 | } else { | 521 | } else { |
| ... | @@ -518,6 +525,7 @@ ZigList<Token> *tokenize(Buf *buf) { | ... | @@ -518,6 +525,7 @@ ZigList<Token> *tokenize(Buf *buf) { |
| 518 | // EOF | 525 | // EOF |
| 519 | switch (t.state) { | 526 | switch (t.state) { |
| 520 | case TokenizeStateStart: | 527 | case TokenizeStateStart: |
| 528 | case TokenizeStateError: | ||
| 521 | break; | 529 | break; |
| 522 | case TokenizeStateString: | 530 | case TokenizeStateString: |
| 523 | tokenize_error(&t, "unterminated string"); | 531 | tokenize_error(&t, "unterminated string"); |
| ... | @@ -544,11 +552,12 @@ ZigList<Token> *tokenize(Buf *buf) { | ... | @@ -544,11 +552,12 @@ ZigList<Token> *tokenize(Buf *buf) { |
| 544 | tokenize_error(&t, "unterminated multi-line comment"); | 552 | tokenize_error(&t, "unterminated multi-line comment"); |
| 545 | break; | 553 | break; |
| 546 | } | 554 | } |
| 547 | t.pos = -1; | 555 | if (t.state != TokenizeStateError) { |
| 548 | begin_token(&t, TokenIdEof); | 556 | t.pos = -1; |
| 549 | end_token(&t); | 557 | begin_token(&t, TokenIdEof); |
| 550 | assert(!t.cur_tok); | 558 | end_token(&t); |
| 551 | return t.tokens; | 559 | assert(!t.cur_tok); |
| 560 | } | ||
| 552 | } | 561 | } |
| 553 | 562 | ||
| 554 | static const char * token_name(Token *token) { | 563 | static const char * token_name(Token *token) { |
src/tokenizer.hpp+11-1| ... | @@ -65,7 +65,17 @@ struct Token { | ... | @@ -65,7 +65,17 @@ struct Token { |
| 65 | int start_column; | 65 | int start_column; |
| 66 | }; | 66 | }; |
| 67 | 67 | ||
| 68 | ZigList<Token> *tokenize(Buf *buf); | 68 | struct Tokenization { |
| 69 | ZigList<Token> *tokens; | ||
| 70 | ZigList<int> *line_offsets; | ||
| 71 | |||
| 72 | // if an error occurred | ||
| 73 | Buf *err; | ||
| 74 | int err_line; | ||
| 75 | int err_column; | ||
| 76 | }; | ||
| 77 | |||
| 78 | void tokenize(Buf *buf, Tokenization *out_tokenization); | ||
| 69 | 79 | ||
| 70 | void print_tokens(Buf *buf, ZigList<Token> *tokens); | 80 | void print_tokens(Buf *buf, ZigList<Token> *tokens); |
| 71 | 81 |
src/util.hpp-2| ... | @@ -16,8 +16,6 @@ | ... | @@ -16,8 +16,6 @@ |
| 16 | 16 | ||
| 17 | #define BREAKPOINT __asm("int $0x03") | 17 | #define BREAKPOINT __asm("int $0x03") |
| 18 | 18 | ||
| 19 | static const int COMPILE_FAILED_ERR_CODE = 10; // chosen with a random number generator | ||
| 20 | |||
| 21 | void zig_panic(const char *format, ...) | 19 | void zig_panic(const char *format, ...) |
| 22 | __attribute__((cold)) | 20 | __attribute__((cold)) |
| 23 | __attribute__ ((noreturn)) | 21 | __attribute__ ((noreturn)) |
test/run_tests.cpp+88-18| ... | @@ -14,13 +14,13 @@ | ... | @@ -14,13 +14,13 @@ |
| 14 | 14 | ||
| 15 | struct TestSourceFile { | 15 | struct TestSourceFile { |
| 16 | const char *relative_path; | 16 | const char *relative_path; |
| 17 | const char *text; | 17 | const char *source_code; |
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| 20 | struct TestCase { | 20 | struct TestCase { |
| 21 | const char *case_name; | 21 | const char *case_name; |
| 22 | const char *output; | 22 | const char *output; |
| 23 | const char *source; | 23 | ZigList<TestSourceFile> source_files; |
| 24 | ZigList<const char *> compile_errors; | 24 | ZigList<const char *> compile_errors; |
| 25 | ZigList<const char *> compiler_args; | 25 | ZigList<const char *> compiler_args; |
| 26 | ZigList<const char *> program_args; | 26 | ZigList<const char *> program_args; |
| ... | @@ -31,11 +31,20 @@ static const char *tmp_source_path = ".tmp_source.zig"; | ... | @@ -31,11 +31,20 @@ static const char *tmp_source_path = ".tmp_source.zig"; |
| 31 | static const char *tmp_exe_path = "./.tmp_exe"; | 31 | static const char *tmp_exe_path = "./.tmp_exe"; |
| 32 | static const char *zig_exe = "./zig"; | 32 | static const char *zig_exe = "./zig"; |
| 33 | 33 | ||
| 34 | static void add_simple_case(const char *case_name, const char *source, const char *output) { | 34 | static void add_source_file(TestCase *test_case, const char *path, const char *source) { |
| 35 | test_case->source_files.add_one(); | ||
| 36 | test_case->source_files.last().relative_path = path; | ||
| 37 | test_case->source_files.last().source_code = source; | ||
| 38 | } | ||
| 39 | |||
| 40 | static TestCase *add_simple_case(const char *case_name, const char *source, const char *output) { | ||
| 35 | TestCase *test_case = allocate<TestCase>(1); | 41 | TestCase *test_case = allocate<TestCase>(1); |
| 36 | test_case->case_name = case_name; | 42 | test_case->case_name = case_name; |
| 37 | test_case->output = output; | 43 | test_case->output = output; |
| 38 | test_case->source = source; | 44 | |
| 45 | test_case->source_files.resize(1); | ||
| 46 | test_case->source_files.at(0).relative_path = tmp_source_path; | ||
| 47 | test_case->source_files.at(0).source_code = source; | ||
| 39 | 48 | ||
| 40 | test_case->compiler_args.append("build"); | 49 | test_case->compiler_args.append("build"); |
| 41 | test_case->compiler_args.append(tmp_source_path); | 50 | test_case->compiler_args.append(tmp_source_path); |
| ... | @@ -48,17 +57,23 @@ static void add_simple_case(const char *case_name, const char *source, const cha | ... | @@ -48,17 +57,23 @@ static void add_simple_case(const char *case_name, const char *source, const cha |
| 48 | test_case->compiler_args.append("--release"); | 57 | test_case->compiler_args.append("--release"); |
| 49 | test_case->compiler_args.append("--strip"); | 58 | test_case->compiler_args.append("--strip"); |
| 50 | test_case->compiler_args.append("--verbose"); | 59 | test_case->compiler_args.append("--verbose"); |
| 60 | test_case->compiler_args.append("--color"); | ||
| 61 | test_case->compiler_args.append("on"); | ||
| 51 | 62 | ||
| 52 | test_cases.append(test_case); | 63 | test_cases.append(test_case); |
| 64 | |||
| 65 | return test_case; | ||
| 53 | } | 66 | } |
| 54 | 67 | ||
| 55 | static void add_compile_fail_case(const char *case_name, const char *source, int count, ...) { | 68 | static TestCase *add_compile_fail_case(const char *case_name, const char *source, int count, ...) { |
| 56 | va_list ap; | 69 | va_list ap; |
| 57 | va_start(ap, count); | 70 | va_start(ap, count); |
| 58 | 71 | ||
| 59 | TestCase *test_case = allocate<TestCase>(1); | 72 | TestCase *test_case = allocate<TestCase>(1); |
| 60 | test_case->case_name = case_name; | 73 | test_case->case_name = case_name; |
| 61 | test_case->source = source; | 74 | test_case->source_files.resize(1); |
| 75 | test_case->source_files.at(0).relative_path = tmp_source_path; | ||
| 76 | test_case->source_files.at(0).source_code = source; | ||
| 62 | 77 | ||
| 63 | for (int i = 0; i < count; i += 1) { | 78 | for (int i = 0; i < count; i += 1) { |
| 64 | const char *arg = va_arg(ap, const char *); | 79 | const char *arg = va_arg(ap, const char *); |
| ... | @@ -76,6 +91,8 @@ static void add_compile_fail_case(const char *case_name, const char *source, int | ... | @@ -76,6 +91,8 @@ static void add_compile_fail_case(const char *case_name, const char *source, int |
| 76 | test_cases.append(test_case); | 91 | test_cases.append(test_case); |
| 77 | 92 | ||
| 78 | va_end(ap); | 93 | va_end(ap); |
| 94 | |||
| 95 | return test_case; | ||
| 79 | } | 96 | } |
| 80 | 97 | ||
| 81 | static void add_compiling_test_cases(void) { | 98 | static void add_compiling_test_cases(void) { |
| ... | @@ -133,13 +150,52 @@ static void add_compiling_test_cases(void) { | ... | @@ -133,13 +150,52 @@ static void add_compiling_test_cases(void) { |
| 133 | exit(0); | 150 | exit(0); |
| 134 | } | 151 | } |
| 135 | )SOURCE", "OK\n"); | 152 | )SOURCE", "OK\n"); |
| 153 | |||
| 154 | { | ||
| 155 | TestCase *tc = add_simple_case("multiple files with private function", R"SOURCE( | ||
| 156 | use "libc.zig"; | ||
| 157 | use "foo.zig"; | ||
| 158 | |||
| 159 | export fn _start() -> unreachable { | ||
| 160 | private_function(); | ||
| 161 | } | ||
| 162 | |||
| 163 | fn private_function() -> unreachable { | ||
| 164 | print_text(); | ||
| 165 | exit(0); | ||
| 166 | } | ||
| 167 | )SOURCE", "OK\n"); | ||
| 168 | |||
| 169 | add_source_file(tc, "libc.zig", R"SOURCE( | ||
| 170 | #link("c") | ||
| 171 | extern { | ||
| 172 | pub fn puts(s: *mut u8) -> i32; | ||
| 173 | pub fn exit(code: i32) -> unreachable; | ||
| 174 | } | ||
| 175 | )SOURCE"); | ||
| 176 | |||
| 177 | add_source_file(tc, "foo.zig", R"SOURCE( | ||
| 178 | use "libc.zig"; | ||
| 179 | |||
| 180 | // purposefully conflicting function with main source file | ||
| 181 | // but it's private so it should be OK | ||
| 182 | fn private_function() { | ||
| 183 | puts("OK"); | ||
| 184 | } | ||
| 185 | |||
| 186 | pub fn print_text() { | ||
| 187 | private_function(); | ||
| 188 | } | ||
| 189 | )SOURCE"); | ||
| 190 | } | ||
| 191 | |||
| 136 | } | 192 | } |
| 137 | 193 | ||
| 138 | static void add_compile_failure_test_cases(void) { | 194 | static void add_compile_failure_test_cases(void) { |
| 139 | add_compile_fail_case("multiple function definitions", R"SOURCE( | 195 | add_compile_fail_case("multiple function definitions", R"SOURCE( |
| 140 | fn a() {} | 196 | fn a() {} |
| 141 | fn a() {} | 197 | fn a() {} |
| 142 | )SOURCE", 1, "Line 3, column 1: redefinition of 'a'"); | 198 | )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'a'"); |
| 143 | 199 | ||
| 144 | add_compile_fail_case("bad directive", R"SOURCE( | 200 | add_compile_fail_case("bad directive", R"SOURCE( |
| 145 | #bogus1("") | 201 | #bogus1("") |
| ... | @@ -148,37 +204,37 @@ extern { | ... | @@ -148,37 +204,37 @@ extern { |
| 148 | } | 204 | } |
| 149 | #bogus2("") | 205 | #bogus2("") |
| 150 | fn a() {} | 206 | fn a() {} |
| 151 | )SOURCE", 2, "Line 2, column 1: invalid directive: 'bogus1'", | 207 | )SOURCE", 2, ".tmp_source.zig:2:1: error: invalid directive: 'bogus1'", |
| 152 | "Line 6, column 1: invalid directive: 'bogus2'"); | 208 | ".tmp_source.zig:6:1: error: invalid directive: 'bogus2'"); |
| 153 | 209 | ||
| 154 | add_compile_fail_case("unreachable with return", R"SOURCE( | 210 | add_compile_fail_case("unreachable with return", R"SOURCE( |
| 155 | fn a() -> unreachable {return;} | 211 | fn a() -> unreachable {return;} |
| 156 | )SOURCE", 1, "Line 2, column 24: return statement in function with unreachable return type"); | 212 | )SOURCE", 1, ".tmp_source.zig:2:24: error: return statement in function with unreachable return type"); |
| 157 | 213 | ||
| 158 | add_compile_fail_case("control reaches end of non-void function", R"SOURCE( | 214 | add_compile_fail_case("control reaches end of non-void function", R"SOURCE( |
| 159 | fn a() -> i32 {} | 215 | fn a() -> i32 {} |
| 160 | )SOURCE", 1, "Line 2, column 1: control reaches end of non-void function"); | 216 | )SOURCE", 1, ".tmp_source.zig:2:1: error: control reaches end of non-void function"); |
| 161 | 217 | ||
| 162 | add_compile_fail_case("undefined function call", R"SOURCE( | 218 | add_compile_fail_case("undefined function call", R"SOURCE( |
| 163 | fn a() { | 219 | fn a() { |
| 164 | b(); | 220 | b(); |
| 165 | } | 221 | } |
| 166 | )SOURCE", 1, "Line 3, column 5: undefined function: 'b'"); | 222 | )SOURCE", 1, ".tmp_source.zig:3:5: error: undefined function: 'b'"); |
| 167 | 223 | ||
| 168 | add_compile_fail_case("wrong number of arguments", R"SOURCE( | 224 | add_compile_fail_case("wrong number of arguments", R"SOURCE( |
| 169 | fn a() { | 225 | fn a() { |
| 170 | b(1); | 226 | b(1); |
| 171 | } | 227 | } |
| 172 | fn b(a: i32, b: i32, c: i32) { } | 228 | fn b(a: i32, b: i32, c: i32) { } |
| 173 | )SOURCE", 1, "Line 3, column 5: wrong number of arguments. Expected 3, got 1."); | 229 | )SOURCE", 1, ".tmp_source.zig:3:5: error: wrong number of arguments. Expected 3, got 1."); |
| 174 | 230 | ||
| 175 | add_compile_fail_case("invalid type", R"SOURCE( | 231 | add_compile_fail_case("invalid type", R"SOURCE( |
| 176 | fn a() -> bogus {} | 232 | fn a() -> bogus {} |
| 177 | )SOURCE", 1, "Line 2, column 11: invalid type name: 'bogus'"); | 233 | )SOURCE", 1, ".tmp_source.zig:2:11: error: invalid type name: 'bogus'"); |
| 178 | 234 | ||
| 179 | add_compile_fail_case("pointer to unreachable", R"SOURCE( | 235 | add_compile_fail_case("pointer to unreachable", R"SOURCE( |
| 180 | fn a() -> *mut unreachable {} | 236 | fn a() -> *mut unreachable {} |
| 181 | )SOURCE", 1, "Line 2, column 11: pointer to unreachable not allowed"); | 237 | )SOURCE", 1, ".tmp_source.zig:2:11: error: pointer to unreachable not allowed"); |
| 182 | 238 | ||
| 183 | add_compile_fail_case("unreachable code", R"SOURCE( | 239 | add_compile_fail_case("unreachable code", R"SOURCE( |
| 184 | fn a() { | 240 | fn a() { |
| ... | @@ -187,12 +243,16 @@ fn a() { | ... | @@ -187,12 +243,16 @@ fn a() { |
| 187 | } | 243 | } |
| 188 | 244 | ||
| 189 | fn b() {} | 245 | fn b() {} |
| 190 | )SOURCE", 1, "Line 4, column 5: unreachable code"); | 246 | )SOURCE", 1, ".tmp_source.zig:4:5: error: unreachable code"); |
| 191 | 247 | ||
| 192 | add_compile_fail_case("bad version string", R"SOURCE( | 248 | add_compile_fail_case("bad version string", R"SOURCE( |
| 193 | #version("aoeu") | 249 | #version("aoeu") |
| 194 | export executable "test"; | 250 | export executable "test"; |
| 195 | )SOURCE", 1, "Line 2, column 1: invalid version string"); | 251 | )SOURCE", 1, ".tmp_source.zig:2:1: error: invalid version string"); |
| 252 | |||
| 253 | add_compile_fail_case("bad import", R"SOURCE( | ||
| 254 | use "bogus-does-not-exist.zig"; | ||
| 255 | )SOURCE", 1, ".tmp_source.zig:2:1: error: unable to open \"./bogus-does-not-exist.zig\": file not found"); | ||
| 196 | } | 256 | } |
| 197 | 257 | ||
| 198 | static void print_compiler_invokation(TestCase *test_case, Buf *zig_stderr) { | 258 | static void print_compiler_invokation(TestCase *test_case, Buf *zig_stderr) { |
| ... | @@ -205,7 +265,12 @@ static void print_compiler_invokation(TestCase *test_case, Buf *zig_stderr) { | ... | @@ -205,7 +265,12 @@ static void print_compiler_invokation(TestCase *test_case, Buf *zig_stderr) { |
| 205 | } | 265 | } |
| 206 | 266 | ||
| 207 | static void run_test(TestCase *test_case) { | 267 | static void run_test(TestCase *test_case) { |
| 208 | os_write_file(buf_create_from_str(tmp_source_path), buf_create_from_str(test_case->source)); | 268 | for (int i = 0; i < test_case->source_files.length; i += 1) { |
| 269 | TestSourceFile *test_source = &test_case->source_files.at(i); | ||
| 270 | os_write_file( | ||
| 271 | buf_create_from_str(test_source->relative_path), | ||
| 272 | buf_create_from_str(test_source->source_code)); | ||
| 273 | } | ||
| 209 | 274 | ||
| 210 | Buf zig_stderr = BUF_INIT; | 275 | Buf zig_stderr = BUF_INIT; |
| 211 | Buf zig_stdout = BUF_INIT; | 276 | Buf zig_stdout = BUF_INIT; |
| ... | @@ -263,6 +328,11 @@ static void run_test(TestCase *test_case) { | ... | @@ -263,6 +328,11 @@ static void run_test(TestCase *test_case) { |
| 263 | printf("=======================================\n"); | 328 | printf("=======================================\n"); |
| 264 | exit(1); | 329 | exit(1); |
| 265 | } | 330 | } |
| 331 | |||
| 332 | for (int i = 0; i < test_case->source_files.length; i += 1) { | ||
| 333 | TestSourceFile *test_source = &test_case->source_files.at(i); | ||
| 334 | remove(test_source->relative_path); | ||
| 335 | } | ||
| 266 | } | 336 | } |
| 267 | 337 | ||
| 268 | static void run_all_tests(void) { | 338 | static void run_all_tests(void) { |