aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJosh Wolfe <thejoshwolfe@gmail.com>2015-12-01 10:44:30 -0700
committerJosh Wolfe <thejoshwolfe@gmail.com>2015-12-01 10:44:30 -0700
commitab327344b671bff7f874f24691d7e3f19176167c (patch)
treec437760bbc1f7059417b21e37c3d15a42534d4e8 /src
parent9278dbedd5242bf4253da29c0fab36eea9dda61b (diff)
parentdfb6682089ad758b7ba72733778a9aa8c544c164 (diff)
downloadzig-ab327344b671bff7f874f24691d7e3f19176167c.tar.gz
zig-ab327344b671bff7f874f24691d7e3f19176167c.zip
merge conflicts
Diffstat (limited to 'src')
-rw-r--r--src/analyze.cpp274
-rw-r--r--src/analyze.hpp3
-rw-r--r--src/buffer.cpp14
-rw-r--r--src/buffer.hpp2
-rw-r--r--src/codegen.cpp73
-rw-r--r--src/codegen.hpp12
-rw-r--r--src/errmsg.cpp38
-rw-r--r--src/errmsg.hpp33
-rw-r--r--src/error.cpp6
-rw-r--r--src/error.hpp6
-rw-r--r--src/main.cpp17
-rw-r--r--src/os.cpp60
-rw-r--r--src/os.hpp2
-rw-r--r--src/parser.cpp120
-rw-r--r--src/parser.hpp6
-rw-r--r--src/semantic_info.hpp14
-rw-r--r--src/tokenizer.cpp43
-rw-r--r--src/tokenizer.hpp12
-rw-r--r--src/util.hpp2
19 files changed, 471 insertions, 266 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp
index c04d349504..2ae0b42a29 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -17,14 +17,18 @@ struct BlockContext {
BlockContext *parent;
};
-static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
- g->errors.add_one();
- ErrorMsg *last_msg = &g->errors.last();
- last_msg->line_start = node->line;
- last_msg->column_start = node->column;
- last_msg->line_end = -1;
- last_msg->column_end = -1;
- last_msg->msg = msg;
+void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
+ ErrorMsg *err = allocate<ErrorMsg>(1);
+ err->line_start = node->line;
+ err->column_start = node->column;
+ err->line_end = -1;
+ err->column_end = -1;
+ err->msg = msg;
+ err->path = node->owner->path;
+ err->source = node->owner->source_code;
+ err->line_offsets = node->owner->line_offsets;
+
+ g->errors.append(err);
}
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,
AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
assert(fn_decl->type == NodeTypeFnDecl);
AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto;
+ bool is_pub = (fn_proto->data.fn_proto.visib_mod == FnProtoVisibModPub);
resolve_function_proto(g, fn_proto);
Buf *name = &fn_proto->data.fn_proto.name;
@@ -147,7 +152,12 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
fn_table_entry->is_extern = true;
fn_table_entry->calling_convention = LLVMCCallConv;
fn_table_entry->import_entry = import;
- g->fn_table.put(name, fn_table_entry);
+
+ g->fn_protos.append(fn_table_entry);
+ import->fn_table.put(name, fn_table_entry);
+ if (is_pub) {
+ g->fn_table.put(name, fn_table_entry);
+ }
}
break;
case NodeTypeFnDef:
@@ -155,67 +165,89 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
AstNode *proto_node = node->data.fn_def.fn_proto;
assert(proto_node->type == NodeTypeFnProto);
Buf *proto_name = &proto_node->data.fn_proto.name;
- auto entry = g->fn_table.maybe_get(proto_name);
+ auto entry = import->fn_table.maybe_get(proto_name);
+ bool skip = false;
+ bool is_internal = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport);
+ bool is_pub = (proto_node->data.fn_proto.visib_mod == FnProtoVisibModPub);
if (entry) {
add_node_error(g, node,
buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
assert(!node->codegen_node);
node->codegen_node = allocate<CodeGenNode>(1);
node->codegen_node->data.fn_def_node.skip = true;
- } else {
+ skip = true;
+ } else if (is_pub) {
+ auto entry = g->fn_table.maybe_get(proto_name);
+ if (entry) {
+ add_node_error(g, node,
+ buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
+ assert(!node->codegen_node);
+ node->codegen_node = allocate<CodeGenNode>(1);
+ node->codegen_node->data.fn_def_node.skip = true;
+ skip = true;
+ }
+ }
+ if (!skip) {
FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
fn_table_entry->import_entry = import;
fn_table_entry->proto_node = proto_node;
fn_table_entry->fn_def_node = node;
- fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport;
- if (fn_table_entry->internal_linkage) {
- fn_table_entry->calling_convention = LLVMFastCallConv;
- } else {
- fn_table_entry->calling_convention = LLVMCCallConv;
- }
- g->fn_table.put(proto_name, fn_table_entry);
+ fn_table_entry->internal_linkage = is_internal;
+ fn_table_entry->calling_convention = is_internal ? LLVMFastCallConv : LLVMCCallConv;
+
+ g->fn_protos.append(fn_table_entry);
g->fn_defs.append(fn_table_entry);
+ import->fn_table.put(proto_name, fn_table_entry);
+ if (is_pub) {
+ g->fn_table.put(proto_name, fn_table_entry);
+ }
+
resolve_function_proto(g, proto_node);
}
}
break;
case NodeTypeRootExportDecl:
- for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) {
- AstNode *directive_node = node->data.root_export_decl.directives->at(i);
- Buf *name = &directive_node->data.directive.name;
- Buf *param = &directive_node->data.directive.param;
- if (buf_eql_str(name, "version")) {
- set_root_export_version(g, param, directive_node);
- } else {
- add_node_error(g, directive_node,
- buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
+ if (import == g->root_import) {
+ for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) {
+ AstNode *directive_node = node->data.root_export_decl.directives->at(i);
+ Buf *name = &directive_node->data.directive.name;
+ Buf *param = &directive_node->data.directive.param;
+ if (buf_eql_str(name, "version")) {
+ set_root_export_version(g, param, directive_node);
+ } else {
+ add_node_error(g, directive_node,
+ buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
+ }
}
- }
- if (g->root_export_decl) {
- add_node_error(g, node,
- buf_sprintf("only one root export declaration allowed"));
- } else {
- g->root_export_decl = node;
-
- if (!g->root_out_name)
- g->root_out_name = &node->data.root_export_decl.name;
-
- Buf *out_type = &node->data.root_export_decl.type;
- OutType export_out_type;
- if (buf_eql_str(out_type, "executable")) {
- export_out_type = OutTypeExe;
- } else if (buf_eql_str(out_type, "library")) {
- export_out_type = OutTypeLib;
- } else if (buf_eql_str(out_type, "object")) {
- export_out_type = OutTypeObj;
- } else {
+ if (g->root_export_decl) {
add_node_error(g, node,
- buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
+ buf_sprintf("only one root export declaration allowed"));
+ } else {
+ g->root_export_decl = node;
+
+ if (!g->root_out_name)
+ g->root_out_name = &node->data.root_export_decl.name;
+
+ Buf *out_type = &node->data.root_export_decl.type;
+ OutType export_out_type;
+ if (buf_eql_str(out_type, "executable")) {
+ export_out_type = OutTypeExe;
+ } else if (buf_eql_str(out_type, "library")) {
+ export_out_type = OutTypeLib;
+ } else if (buf_eql_str(out_type, "object")) {
+ export_out_type = OutTypeObj;
+ } else {
+ add_node_error(g, node,
+ buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
+ }
+ if (g->out_type == OutTypeUnknown)
+ g->out_type = export_out_type;
}
- if (g->out_type == OutTypeUnknown)
- g->out_type = export_out_type;
+ } else {
+ add_node_error(g, node,
+ buf_sprintf("root export declaration only valid in root source file"));
}
break;
case NodeTypeUse:
@@ -263,7 +295,7 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *
add_node_error(g, node, buf_sprintf("type mismatch."));
}
-static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) {
+static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) {
switch (node->type) {
case NodeTypeBlock:
{
@@ -276,7 +308,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
buf_sprintf("unreachable code"));
break;
}
- return_type = analyze_expression(g, context, nullptr, child);
+ return_type = analyze_expression(g, import, context, nullptr, child);
}
return return_type;
}
@@ -286,7 +318,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
TypeTableEntry *expected_return_type = get_return_type(context);
TypeTableEntry *actual_return_type;
if (node->data.return_expr.expr) {
- actual_return_type = analyze_expression(g, context, expected_return_type, node->data.return_expr.expr);
+ actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr);
} else {
actual_return_type = g->builtin_types.entry_void;
}
@@ -304,8 +336,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
case NodeTypeBinOpExpr:
{
// TODO: think about expected types
- analyze_expression(g, context, expected_type, node->data.bin_op_expr.op1);
- analyze_expression(g, context, expected_type, node->data.bin_op_expr.op2);
+ analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op1);
+ analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op2);
return expected_type;
}
@@ -313,14 +345,17 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
{
Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);
- auto entry = g->fn_table.maybe_get(name);
+ auto entry = import->fn_table.maybe_get(name);
+ if (!entry)
+ entry = g->fn_table.maybe_get(name);
+
if (!entry) {
add_node_error(g, node,
buf_sprintf("undefined function: '%s'", buf_ptr(name)));
// still analyze the parameters, even though we don't know what to expect
for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
AstNode *child = node->data.fn_call_expr.params.at(i);
- analyze_expression(g, context, nullptr, child);
+ analyze_expression(g, import, context, nullptr, child);
}
return g->builtin_types.entry_invalid;
@@ -350,7 +385,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
if (param_type_node->codegen_node)
expected_param_type = param_type_node->codegen_node->data.type_node.entry;
}
- analyze_expression(g, context, expected_param_type, child);
+ analyze_expression(g, import, context, expected_param_type, child);
}
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) {
}
}
-static void analyze_expression(CodeGen *g, AstNode *node) {
- switch (node->type) {
- case NodeTypeBlock:
- for (int i = 0; i < node->data.block.statements.length; i += 1) {
- AstNode *child = node->data.block.statements.at(i);
- analyze_expression(g, child);
- }
- break;
- case NodeTypeReturnExpr:
- if (node->data.return_expr.expr) {
- analyze_expression(g, node->data.return_expr.expr);
- }
- break;
- case NodeTypeBinOpExpr:
- analyze_expression(g, node->data.bin_op_expr.op1);
- analyze_expression(g, node->data.bin_op_expr.op2);
- break;
- case NodeTypeFnCallExpr:
- {
- Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);
-
- auto entry = g->fn_table.maybe_get(name);
- if (!entry) {
- add_node_error(g, node,
- buf_sprintf("undefined function: '%s'", buf_ptr(name)));
- } else {
- FnTableEntry *fn_table_entry = entry->value;
- assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
- int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length;
- int actual_param_count = node->data.fn_call_expr.params.length;
- if (expected_param_count != actual_param_count) {
- add_node_error(g, node,
- buf_sprintf("wrong number of arguments. Expected %d, got %d.",
- expected_param_count, actual_param_count));
- }
- }
-
- for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
- AstNode *child = node->data.fn_call_expr.params.at(i);
- analyze_expression(g, child);
- }
- break;
- }
- case NodeTypeCastExpr:
- zig_panic("TODO");
- break;
- case NodeTypePrefixOpExpr:
- zig_panic("TODO");
- break;
- case NodeTypeNumberLiteral:
- case NodeTypeStringLiteral:
- case NodeTypeUnreachable:
- case NodeTypeSymbol:
- // nothing to do
- break;
- case NodeTypeDirective:
- case NodeTypeFnDecl:
- case NodeTypeFnProto:
- case NodeTypeParamDecl:
- case NodeTypeType:
- case NodeTypeRoot:
- case NodeTypeRootExportDecl:
- case NodeTypeExternBlock:
- case NodeTypeFnDef:
- case NodeTypeUse:
- zig_unreachable();
- }
-}
-
-static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
+static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, AstNode *node) {
switch (node->type) {
case NodeTypeFnDef:
{
@@ -540,7 +506,7 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
context.root = &context;
context.parent = nullptr;
TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry;
- analyze_expression(g, &context, expected_type, node->data.fn_def.body);
+ analyze_expression(g, import, &context, expected_type, node->data.fn_def.body);
}
break;
@@ -576,37 +542,55 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
}
}
-static void analyze_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
+static void find_function_declarations_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
assert(node->type == NodeTypeRoot);
- // find function declarations
for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
AstNode *child = node->data.root.top_level_decls.at(i);
preview_function_declarations(g, import, child);
}
+}
+
+static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
+ assert(node->type == NodeTypeRoot);
+
for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
AstNode *child = node->data.root.top_level_decls.at(i);
- analyze_top_level_declaration(g, child);
+ analyze_top_level_declaration(g, import, child);
}
+}
+
+void semantic_analyze(CodeGen *g) {
+ {
+ auto it = g->import_table.entry_iterator();
+ for (;;) {
+ auto *entry = it.next();
+ if (!entry)
+ break;
+
+ ImportTableEntry *import = entry->value;
+ find_function_declarations_root(g, import, import->root);
+ }
+ }
+ {
+ auto it = g->import_table.entry_iterator();
+ for (;;) {
+ auto *entry = it.next();
+ if (!entry)
+ break;
+
+ ImportTableEntry *import = entry->value;
+ analyze_top_level_decls_root(g, import, import->root);
+ }
+ }
+
if (!g->root_out_name) {
- add_node_error(g, node,
+ add_node_error(g, g->root_import->root,
buf_sprintf("missing export declaration and output name not provided"));
} else if (g->out_type == OutTypeUnknown) {
- add_node_error(g, node,
+ add_node_error(g, g->root_import->root,
buf_sprintf("missing export declaration and export type not provided"));
}
}
-
-void semantic_analyze(CodeGen *g) {
- auto it = g->import_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
-
- ImportTableEntry *import = entry->value;
- analyze_root(g, import, import->root);
- }
-}
diff --git a/src/analyze.hpp b/src/analyze.hpp
index 0dca23194d..110a3614e0 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -9,7 +9,10 @@
#define ZIG_ANALYZE_HPP
struct CodeGen;
+struct AstNode;
+struct Buf;
void semantic_analyze(CodeGen *g);
+void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
#endif
diff --git a/src/buffer.cpp b/src/buffer.cpp
index 1978371034..a03ab333f3 100644
--- a/src/buffer.cpp
+++ b/src/buffer.cpp
@@ -3,9 +3,8 @@
#include <stdlib.h>
#include <stdio.h>
-Buf *buf_sprintf(const char *format, ...) {
- va_list ap, ap2;
- va_start(ap, format);
+Buf *buf_vprintf(const char *format, va_list ap) {
+ va_list ap2;
va_copy(ap2, ap);
int len1 = vsnprintf(nullptr, 0, format, ap);
@@ -19,11 +18,18 @@ Buf *buf_sprintf(const char *format, ...) {
assert(len2 == len1);
va_end(ap2);
- va_end(ap);
return buf;
}
+Buf *buf_sprintf(const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ Buf *result = buf_vprintf(format, ap);
+ va_end(ap);
+ return result;
+}
+
void buf_appendf(Buf *buf, const char *format, ...) {
assert(buf->list.length);
va_list ap, ap2;
diff --git a/src/buffer.hpp b/src/buffer.hpp
index f9b2497548..3670332038 100644
--- a/src/buffer.hpp
+++ b/src/buffer.hpp
@@ -13,6 +13,7 @@
#include <assert.h>
#include <stdint.h>
#include <ctype.h>
+#include <stdarg.h>
#define BUF_INIT {{0}}
@@ -24,6 +25,7 @@ struct Buf {
Buf *buf_sprintf(const char *format, ...)
__attribute__ ((format (printf, 1, 2)));
+Buf *buf_vprintf(const char *format, va_list ap);
static inline int buf_len(Buf *buf) {
assert(buf->list.length);
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 7f636ab367..692e23ad73 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -13,6 +13,7 @@
#include "error.hpp"
#include "semantic_info.hpp"
#include "analyze.hpp"
+#include "errmsg.hpp"
#include <stdio.h>
#include <errno.h>
@@ -41,6 +42,10 @@ void codegen_set_verbose(CodeGen *g, bool verbose) {
g->verbose = verbose;
}
+void codegen_set_errmsg_color(CodeGen *g, ErrColor err_color) {
+ g->err_color = err_color;
+}
+
void codegen_set_strip(CodeGen *g, bool strip) {
g->strip_debug_symbols = strip;
}
@@ -120,7 +125,13 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);
- FnTableEntry *fn_table_entry = g->fn_table.get(name);
+ FnTableEntry *fn_table_entry;
+ auto entry = g->cur_fn->import_entry->fn_table.maybe_get(name);
+ if (entry)
+ fn_table_entry = entry->value;
+ else
+ fn_table_entry = g->fn_table.get(name);
+
assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length;
int actual_param_count = node->data.fn_call_expr.params.length;
@@ -473,13 +484,8 @@ static void do_code_gen(CodeGen *g) {
// Generate function prototypes
- auto it = g->fn_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
-
- FnTableEntry *fn_table_entry = entry->value;
+ for (int i = 0; i < g->fn_protos.length; i += 1) {
+ FnTableEntry *fn_table_entry = g->fn_protos.at(i);
AstNode *proto_node = fn_table_entry->proto_node;
assert(proto_node->type == NodeTypeFnProto);
@@ -542,6 +548,7 @@ static void do_code_gen(CodeGen *g) {
assert(codegen_node);
FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node;
+ assert(codegen_fn_def);
codegen_fn_def->params = allocate<LLVMValueRef>(LLVMCountParams(fn));
LLVMGetParams(fn, codegen_fn_def->params);
@@ -664,7 +671,8 @@ static void init(CodeGen *g, Buf *source_path) {
}
-static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
+static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
+ int err;
Buf full_path = BUF_INIT;
os_path_join(g->root_source_dir, source_path, &full_path);
@@ -681,24 +689,42 @@ static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
fprintf(stderr, "---------\n");
}
- ZigList<Token> *tokens = tokenize(source_code);
+ Tokenization tokenization = {0};
+ tokenize(source_code, &tokenization);
+
+ if (tokenization.err) {
+ ErrorMsg *err = allocate<ErrorMsg>(1);
+ err->line_start = tokenization.err_line;
+ err->column_start = tokenization.err_column;
+ err->line_end = -1;
+ err->column_end = -1;
+ err->msg = tokenization.err;
+ err->path = source_path;
+ err->source = source_code;
+ err->line_offsets = tokenization.line_offsets;
+
+ print_err_msg(err, g->err_color);
+ exit(1);
+ }
if (g->verbose) {
- print_tokens(source_code, tokens);
+ print_tokens(source_code, tokenization.tokens);
fprintf(stderr, "\nAST:\n");
fprintf(stderr, "------\n");
}
ImportTableEntry *import_entry = allocate<ImportTableEntry>(1);
+ import_entry->source_code = source_code;
+ import_entry->line_offsets = tokenization.line_offsets;
+ import_entry->path = source_path;
import_entry->fn_table.init(32);
- import_entry->root = ast_parse(source_code, tokens);
+ import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color);
assert(import_entry->root);
if (g->verbose) {
ast_print(import_entry->root, 0);
}
- import_entry->path = source_path;
import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&basename), buf_ptr(&dirname));
g->import_table.put(source_path, import_entry);
@@ -713,18 +739,23 @@ static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
if (!entry) {
Buf full_path = BUF_INIT;
os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path);
- Buf import_code = BUF_INIT;
- os_fetch_file_path(&full_path, &import_code);
- codegen_add_code(g, &top_level_decl->data.use.path, &import_code);
+ Buf *import_code = buf_alloc();
+ if ((err = os_fetch_file_path(&full_path, import_code))) {
+ add_node_error(g, top_level_decl,
+ buf_sprintf("unable to open \"%s\": %s", buf_ptr(&full_path), err_str(err)));
+ break;
+ }
+ codegen_add_code(g, &top_level_decl->data.use.path, import_code);
}
}
+
+ return import_entry;
}
void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) {
init(g, source_path);
- codegen_add_code(g, source_path, source_code);
-
+ g->root_import = codegen_add_code(g, source_path, source_code);
if (g->verbose) {
fprintf(stderr, "\nSemantic Analysis:\n");
@@ -738,10 +769,8 @@ void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) {
}
} else {
for (int i = 0; i < g->errors.length; i += 1) {
- ErrorMsg *err = &g->errors.at(i);
- fprintf(stderr, "Error: Line %d, column %d: %s\n",
- err->line_start + 1, err->column_start + 1,
- buf_ptr(err->msg));
+ ErrorMsg *err = g->errors.at(i);
+ print_err_msg(err, g->err_color);
}
exit(1);
}
diff --git a/src/codegen.hpp b/src/codegen.hpp
index 4476017840..8c83e2144a 100644
--- a/src/codegen.hpp
+++ b/src/codegen.hpp
@@ -9,6 +9,7 @@
#define ZIG_CODEGEN_HPP
#include "parser.hpp"
+#include "errmsg.hpp"
struct CodeGen;
@@ -19,16 +20,6 @@ enum OutType {
OutTypeObj,
};
-
-struct ErrorMsg {
- int line_start;
- int column_start;
- int line_end;
- int column_end;
- Buf *msg;
-};
-
-
CodeGen *codegen_create(Buf *root_source_dir);
enum CodeGenBuildType {
@@ -39,6 +30,7 @@ void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type);
void codegen_set_is_static(CodeGen *codegen, bool is_static);
void codegen_set_strip(CodeGen *codegen, bool strip);
void codegen_set_verbose(CodeGen *codegen, bool verbose);
+void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color);
void codegen_set_out_type(CodeGen *codegen, OutType out_type);
void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
diff --git a/src/errmsg.cpp b/src/errmsg.cpp
new file mode 100644
index 0000000000..00557e0214
--- /dev/null
+++ b/src/errmsg.cpp
@@ -0,0 +1,38 @@
+#include "errmsg.hpp"
+#include "os.hpp"
+
+#include <stdio.h>
+
+#define RED "\x1b[31;1m"
+#define WHITE "\x1b[37;1m"
+#define GREEN "\x1b[32;1m"
+#define RESET "\x1b[0m"
+
+void print_err_msg(ErrorMsg *err, ErrColor color) {
+ if (color == ErrColorOn || (color == ErrColorAuto && os_stderr_tty())) {
+ fprintf(stderr, WHITE "%s:%d:%d: " RED "error:" WHITE " %s" RESET "\n",
+ buf_ptr(err->path),
+ err->line_start + 1, err->column_start + 1,
+ buf_ptr(err->msg));
+
+ assert(err->source);
+ assert(err->line_offsets);
+
+ int line_start_offset = err->line_offsets->at(err->line_start);
+ int line_end_offset = err->line_offsets->at(err->line_start + 1);
+
+ fwrite(buf_ptr(err->source) + line_start_offset, 1, line_end_offset - line_start_offset - 1, stderr);
+ fprintf(stderr, "\n");
+ for (int i = 0; i < err->column_start; i += 1) {
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, GREEN "^" RESET "\n");
+
+ } else {
+ fprintf(stderr, "%s:%d:%d: error: %s\n",
+ buf_ptr(err->path),
+ err->line_start + 1, err->column_start + 1,
+ buf_ptr(err->msg));
+ }
+}
+
diff --git a/src/errmsg.hpp b/src/errmsg.hpp
new file mode 100644
index 0000000000..1f31020902
--- /dev/null
+++ b/src/errmsg.hpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015 Andrew Kelley
+ *
+ * This file is part of zig, which is MIT licensed.
+ * See http://opensource.org/licenses/MIT
+ */
+
+#ifndef ZIG_ERRMSG_HPP
+#define ZIG_ERRMSG_HPP
+
+#include "buffer.hpp"
+#include "list.hpp"
+
+enum ErrColor {
+ ErrColorAuto,
+ ErrColorOff,
+ ErrColorOn,
+};
+
+struct ErrorMsg {
+ int line_start;
+ int column_start;
+ int line_end;
+ int column_end;
+ Buf *msg;
+ Buf *path;
+ Buf *source;
+ ZigList<int> *line_offsets;
+};
+
+void print_err_msg(ErrorMsg *msg, ErrColor color);
+
+#endif
diff --git a/src/error.cpp b/src/error.cpp
index 7c3064c143..7690dd0776 100644
--- a/src/error.cpp
+++ b/src/error.cpp
@@ -6,6 +6,12 @@ const char *err_str(int err) {
case ErrorNoMem: return "out of memory";
case ErrorInvalidFormat: return "invalid format";
case ErrorSemanticAnalyzeFail: return "semantic analyze failed";
+ case ErrorAccess: return "access denied";
+ case ErrorInterrupted: return "interrupted";
+ case ErrorSystemResources: return "lack of system resources";
+ case ErrorFileNotFound: return "file not found";
+ case ErrorFileSystem: return "file system error";
+ case ErrorFileTooBig: return "file too big";
}
return "(invalid error)";
}
diff --git a/src/error.hpp b/src/error.hpp
index 7da2cf8322..742f30700e 100644
--- a/src/error.hpp
+++ b/src/error.hpp
@@ -13,6 +13,12 @@ enum Error {
ErrorNoMem,
ErrorInvalidFormat,
ErrorSemanticAnalyzeFail,
+ ErrorAccess,
+ ErrorInterrupted,
+ ErrorSystemResources,
+ ErrorFileNotFound,
+ ErrorFileSystem,
+ ErrorFileTooBig,
};
const char *err_str(int err);
diff --git a/src/main.cpp b/src/main.cpp
index d96cb92e40..f0060c2c1d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -25,6 +25,7 @@ static int usage(const char *arg0) {
" --name [name] override output name\n"
" --output [file] override destination path\n"
" --verbose turn on compiler debug output\n"
+ " --color [auto|off|on] enable or disable colored error messages\n"
, arg0);
return EXIT_FAILURE;
}
@@ -43,6 +44,7 @@ struct Build {
OutType out_type;
const char *out_name;
bool verbose;
+ ErrColor color;
};
static int build(const char *arg0, Build *b) {
@@ -73,6 +75,7 @@ static int build(const char *arg0, Build *b) {
if (b->out_name)
codegen_set_out_name(g, buf_create_from_str(b->out_name));
codegen_set_verbose(g, b->verbose);
+ codegen_set_errmsg_color(g, b->color);
codegen_add_root_code(g, &root_source_name, &root_source_code);
codegen_link(g, b->out_file);
@@ -106,7 +109,9 @@ int main(int argc, char **argv) {
return usage(arg0);
} else {
i += 1;
- if (strcmp(arg, "--output") == 0) {
+ if (i >= argc) {
+ return usage(arg0);
+ } else if (strcmp(arg, "--output") == 0) {
b.out_file = argv[i];
} else if (strcmp(arg, "--export") == 0) {
if (strcmp(argv[i], "exe") == 0) {
@@ -118,6 +123,16 @@ int main(int argc, char **argv) {
} else {
return usage(arg0);
}
+ } else if (strcmp(arg, "--color") == 0) {
+ if (strcmp(argv[i], "auto") == 0) {
+ b.color = ErrColorAuto;
+ } else if (strcmp(argv[i], "on") == 0) {
+ b.color = ErrColorOn;
+ } else if (strcmp(argv[i], "off") == 0) {
+ b.color = ErrColorOff;
+ } else {
+ return usage(arg0);
+ }
} else if (strcmp(arg, "--name") == 0) {
b.out_name = argv[i];
} else {
diff --git a/src/os.cpp b/src/os.cpp
index 61dd1c01ee..be0b01f8a7 100644
--- a/src/os.cpp
+++ b/src/os.cpp
@@ -7,6 +7,7 @@
#include "os.hpp"
#include "util.hpp"
+#include "error.hpp"
#include <unistd.h>
#include <errno.h>
@@ -143,26 +144,65 @@ void os_write_file(Buf *full_path, Buf *contents) {
int os_fetch_file(FILE *f, Buf *out_contents) {
int fd = fileno(f);
struct stat st;
- if (fstat(fd, &st))
- zig_panic("unable to stat file: %s", strerror(errno));
+ if (fstat(fd, &st)) {
+ switch (errno) {
+ case EACCES:
+ return ErrorAccess;
+ case ENOENT:
+ return ErrorFileNotFound;
+ case ENOMEM:
+ return ErrorSystemResources;
+ case EINTR:
+ return ErrorInterrupted;
+ case EINVAL:
+ zig_unreachable();
+ default:
+ return ErrorFileSystem;
+ }
+ }
off_t big_size = st.st_size;
- if (big_size > INT_MAX)
- zig_panic("file too big");
+ if (big_size > INT_MAX) {
+ return ErrorFileTooBig;
+ }
int size = (int)big_size;
buf_resize(out_contents, size);
ssize_t ret = read(fd, buf_ptr(out_contents), size);
- if (ret != size)
- zig_panic("unable to read file: %s", strerror(errno));
+ if (ret != size) {
+ switch (errno) {
+ case EINTR:
+ return ErrorInterrupted;
+ case EINVAL:
+ case EISDIR:
+ zig_unreachable();
+ default:
+ return ErrorFileSystem;
+ }
+ }
return 0;
}
int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
FILE *f = fopen(buf_ptr(full_path), "rb");
- if (!f)
- zig_panic("unable to open %s: %s\n", buf_ptr(full_path), strerror(errno));
+ if (!f) {
+ switch (errno) {
+ case EACCES:
+ return ErrorAccess;
+ case EINTR:
+ return ErrorInterrupted;
+ case EINVAL:
+ zig_unreachable();
+ case ENFILE:
+ case ENOMEM:
+ return ErrorSystemResources;
+ case ENOENT:
+ return ErrorFileNotFound;
+ default:
+ return ErrorFileSystem;
+ }
+ }
int result = os_fetch_file(f, out_contents);
fclose(f);
return result;
@@ -180,3 +220,7 @@ int os_get_cwd(Buf *out_cwd) {
return 0;
}
+
+bool os_stderr_tty(void) {
+ return isatty(STDERR_FILENO);
+}
diff --git a/src/os.hpp b/src/os.hpp
index 8bb5d8ea4f..7b71437852 100644
--- a/src/os.hpp
+++ b/src/os.hpp
@@ -29,4 +29,6 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents);
int os_get_cwd(Buf *out_cwd);
+bool os_stderr_tty(void);
+
#endif
diff --git a/src/parser.cpp b/src/parser.cpp
index 3ac4c5ec09..e17e3c83fe 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -6,6 +6,8 @@
*/
#include "parser.hpp"
+#include "errmsg.hpp"
+#include "semantic_info.hpp"
#include <stdarg.h>
#include <stdio.h>
@@ -45,21 +47,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
zig_unreachable();
}
-__attribute__ ((format (printf, 2, 3)))
-__attribute__ ((noreturn))
-static void ast_error(Token *token, const char *format, ...) {
- int line = token->start_line + 1;
- int column = token->start_column + 1;
-
- va_list ap;
- va_start(ap, format);
- fprintf(stderr, "Error: Line %d, column %d: ", line, column);
- vfprintf(stderr, format, ap);
- fprintf(stderr, "\n");
- va_end(ap);
- exit(EXIT_FAILURE);
-}
-
const char *node_type_str(NodeType node_type) {
switch (node_type) {
case NodeTypeRoot:
@@ -254,11 +241,36 @@ struct ParseContext {
AstNode *root;
ZigList<Token> *tokens;
ZigList<AstNode *> *directive_list;
+ ImportTableEntry *owner;
+ ErrColor err_color;
};
-static AstNode *ast_create_node_no_line_info(NodeType type) {
+__attribute__ ((format (printf, 3, 4)))
+__attribute__ ((noreturn))
+static void ast_error(ParseContext *pc, Token *token, const char *format, ...) {
+ ErrorMsg *err = allocate<ErrorMsg>(1);
+ err->line_start = token->start_line;
+ err->column_start = token->start_column;
+ err->line_end = -1;
+ err->column_end = -1;
+
+ va_list ap;
+ va_start(ap, format);
+ err->msg = buf_vprintf(format, ap);
+ va_end(ap);
+
+ err->path = pc->owner->path;
+ err->source = pc->owner->source_code;
+ err->line_offsets = pc->owner->line_offsets;
+
+ print_err_msg(err, pc->err_color);
+ exit(EXIT_FAILURE);
+}
+
+static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) {
AstNode *node = allocate<AstNode>(1);
node->type = type;
+ node->owner = pc->owner;
return node;
}
@@ -267,21 +279,21 @@ static void ast_update_node_line_info(AstNode *node, Token *first_token) {
node->column = first_token->start_column;
}
-static AstNode *ast_create_node(NodeType type, Token *first_token) {
- AstNode *node = ast_create_node_no_line_info(type);
+static AstNode *ast_create_node(ParseContext *pc, NodeType type, Token *first_token) {
+ AstNode *node = ast_create_node_no_line_info(pc, type);
ast_update_node_line_info(node, first_token);
return node;
}
-static AstNode *ast_create_node_with_node(NodeType type, AstNode *other_node) {
- AstNode *node = ast_create_node_no_line_info(type);
+static AstNode *ast_create_node_with_node(ParseContext *pc, NodeType type, AstNode *other_node) {
+ AstNode *node = ast_create_node_no_line_info(pc, type);
node->line = other_node->line;
node->column = other_node->column;
return node;
}
static AstNode *ast_create_void_type_node(ParseContext *pc, Token *token) {
- AstNode *node = ast_create_node(NodeTypeType, token);
+ AstNode *node = ast_create_node(pc, NodeTypeType, token);
node->data.type.type = AstNodeTypeTypePrimitive;
buf_init_from_str(&node->data.type.primitive_name, "void");
return node;
@@ -331,7 +343,7 @@ __attribute__ ((noreturn))
static void ast_invalid_token_error(ParseContext *pc, Token *token) {
Buf token_value = BUF_INIT;
ast_buf_from_token(pc, token, &token_value);
- ast_error(token, "invalid token: '%s'", buf_ptr(&token_value));
+ ast_error(pc, token, "invalid token: '%s'", buf_ptr(&token_value));
}
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_
token_index += 1;
ast_expect_token(pc, number_sign, TokenIdNumberSign);
- AstNode *node = ast_create_node(NodeTypeDirective, number_sign);
+ AstNode *node = ast_create_node(pc, NodeTypeDirective, number_sign);
Token *name_symbol = &pc->tokens->at(token_index);
token_index += 1;
@@ -399,7 +411,7 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token
Token *token = &pc->tokens->at(token_index);
token_index += 1;
- AstNode *node = ast_create_node(NodeTypeType, token);
+ AstNode *node = ast_create_node(pc, NodeTypeType, token);
if (token->id == TokenIdKeywordUnreachable) {
node->data.type.type = AstNodeTypeTypePrimitive;
@@ -437,7 +449,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new
token_index += 1;
ast_expect_token(pc, param_name, TokenIdSymbol);
- AstNode *node = ast_create_node(NodeTypeParamDecl, param_name);
+ AstNode *node = ast_create_node(pc, NodeTypeParamDecl, param_name);
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
Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdNumberLiteral) {
- AstNode *node = ast_create_node(NodeTypeNumberLiteral, token);
+ AstNode *node = ast_create_node(pc, NodeTypeNumberLiteral, token);
ast_buf_from_token(pc, token, &node->data.number);
*token_index += 1;
return node;
} else if (token->id == TokenIdStringLiteral) {
- AstNode *node = ast_create_node(NodeTypeStringLiteral, token);
+ AstNode *node = ast_create_node(pc, NodeTypeStringLiteral, token);
parse_string_literal(pc, token, &node->data.string);
*token_index += 1;
return node;
} else if (token->id == TokenIdKeywordUnreachable) {
- AstNode *node = ast_create_node(NodeTypeUnreachable, token);
+ AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token);
*token_index += 1;
return node;
} else if (token->id == TokenIdSymbol) {
- AstNode *node = ast_create_node(NodeTypeSymbol, token);
+ AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
ast_buf_from_token(pc, token, &node->data.symbol);
*token_index += 1;
return node;
@@ -592,7 +604,7 @@ static AstNode *ast_parse_fn_call_expr(ParseContext *pc, int *token_index, bool
if (l_paren->id != TokenIdLParen)
return primary_expr;
- AstNode *node = ast_create_node_with_node(NodeTypeFnCallExpr, primary_expr);
+ AstNode *node = ast_create_node_with_node(pc, NodeTypeFnCallExpr, primary_expr);
node->data.fn_call_expr.fn_ref_expr = primary_expr;
ast_parse_fn_call_param_list(pc, *token_index, token_index, &node->data.fn_call_expr.params);
@@ -635,7 +647,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo
return ast_parse_fn_call_expr(pc, token_index, mandatory);
AstNode *primary_expr = ast_parse_fn_call_expr(pc, token_index, true);
- AstNode *node = ast_create_node(NodeTypePrefixOpExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
node->data.prefix_op_expr.primary_expr = primary_expr;
node->data.prefix_op_expr.prefix_op = prefix_op;
@@ -656,7 +668,7 @@ static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bo
return prefix_op_expr;
*token_index += 1;
- AstNode *node = ast_create_node(NodeTypeCastExpr, as_kw);
+ AstNode *node = ast_create_node(pc, NodeTypeCastExpr, as_kw);
node->data.cast_expr.prefix_op_expr = prefix_op_expr;
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
AstNode *operand_2 = ast_parse_cast_expression(pc, token_index, true);
- AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = operand_1;
node->data.bin_op_expr.bin_op = mult_op;
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
AstNode *operand_2 = ast_parse_mult_expr(pc, token_index, true);
- AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = operand_1;
node->data.bin_op_expr.bin_op = add_op;
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
AstNode *operand_2 = ast_parse_add_expr(pc, token_index, true);
- AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = operand_1;
node->data.bin_op_expr.bin_op = bit_shift_op;
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
AstNode *operand_2 = ast_parse_bit_shift_expr(pc, token_index, true);
- AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = operand_1;
node->data.bin_op_expr.bin_op = BinOpTypeBinAnd;
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
AstNode *operand_2 = ast_parse_bin_and_expr(pc, token_index, true);
- AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = operand_1;
node->data.bin_op_expr.bin_op = BinOpTypeBinXor;
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
AstNode *operand_2 = ast_parse_bin_xor_expr(pc, token_index, true);
- AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = operand_1;
node->data.bin_op_expr.bin_op = BinOpTypeBinOr;
node->data.bin_op_expr.op2 = operand_2;
@@ -920,7 +932,7 @@ static AstNode *ast_parse_comparison_expr(ParseContext *pc, int *token_index, bo
AstNode *operand_2 = ast_parse_bin_or_expr(pc, token_index, true);
- AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = operand_1;
node->data.bin_op_expr.bin_op = cmp_op;
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
AstNode *operand_2 = ast_parse_comparison_expr(pc, token_index, true);
- AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = operand_1;
node->data.bin_op_expr.bin_op = BinOpTypeBoolAnd;
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
Token *return_tok = &pc->tokens->at(*token_index);
if (return_tok->id == TokenIdKeywordReturn) {
*token_index += 1;
- AstNode *node = ast_create_node(NodeTypeReturnExpr, return_tok);
+ AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, return_tok);
node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);
return node;
} else if (mandatory) {
@@ -983,7 +995,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool
AstNode *operand_2 = ast_parse_bool_and_expr(pc, token_index, true);
- AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = operand_1;
node->data.bin_op_expr.bin_op = BinOpTypeBoolOr;
node->data.bin_op_expr.op2 = operand_2;
@@ -1046,7 +1058,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
}
*token_index += 1;
- AstNode *node = ast_create_node(NodeTypeBlock, l_brace);
+ AstNode *node = ast_create_node(pc, NodeTypeBlock, l_brace);
for (;;) {
Token *token = &pc->tokens->at(*token_index);
@@ -1092,7 +1104,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
return nullptr;
}
- AstNode *node = ast_create_node(NodeTypeFnProto, token);
+ AstNode *node = ast_create_node(pc, NodeTypeFnProto, token);
node->data.fn_proto.visib_mod = visib_mod;
node->data.fn_proto.directives = pc->directive_list;
pc->directive_list = nullptr;
@@ -1125,7 +1137,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandat
AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory);
if (!fn_proto)
return nullptr;
- AstNode *node = ast_create_node_with_node(NodeTypeFnDef, fn_proto);
+ AstNode *node = ast_create_node_with_node(pc, NodeTypeFnDef, fn_proto);
node->data.fn_def.fn_proto = fn_proto;
node->data.fn_def.body = ast_parse_block(pc, token_index, true);
@@ -1138,7 +1150,7 @@ FnDecl : FnProto token(Semicolon)
*/
static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) {
AstNode *fn_proto = ast_parse_fn_proto(pc, &token_index, true);
- AstNode *node = ast_create_node_with_node(NodeTypeFnDecl, fn_proto);
+ AstNode *node = ast_create_node_with_node(pc, NodeTypeFnDecl, fn_proto);
node->data.fn_decl.fn_proto = fn_proto;
@@ -1166,7 +1178,7 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool
}
*token_index += 1;
- AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw);
+ AstNode *node = ast_create_node(pc, NodeTypeExternBlock, extern_kw);
node->data.extern_block.directives = pc->directive_list;
pc->directive_list = nullptr;
@@ -1184,7 +1196,7 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool
Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdRBrace) {
if (pc->directive_list->length > 0) {
- ast_error(directive_token, "invalid directive");
+ ast_error(pc, directive_token, "invalid directive");
}
pc->directive_list = nullptr;
@@ -1216,7 +1228,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
*token_index += 2;
- AstNode *node = ast_create_node(NodeTypeRootExportDecl, export_kw);
+ AstNode *node = ast_create_node(pc, NodeTypeRootExportDecl, export_kw);
node->data.root_export_decl.directives = pc->directive_list;
pc->directive_list = nullptr;
@@ -1254,7 +1266,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory
*token_index += 1;
ast_expect_token(pc, semicolon, TokenIdSemicolon);
- AstNode *node = ast_create_node(NodeTypeUse, use_kw);
+ AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw);
parse_string_literal(pc, use_name, &node->data.use.path);
@@ -1299,7 +1311,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
}
if (pc->directive_list->length > 0) {
- ast_error(directive_token, "invalid directive");
+ ast_error(pc, directive_token, "invalid directive");
}
pc->directive_list = nullptr;
@@ -1312,7 +1324,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
Root : many(TopLevelDecl) token(EOF)
*/
static AstNode *ast_parse_root(ParseContext *pc, int *token_index) {
- AstNode *node = ast_create_node(NodeTypeRoot, &pc->tokens->at(*token_index));
+ AstNode *node = ast_create_node(pc, NodeTypeRoot, &pc->tokens->at(*token_index));
ast_parse_top_level_decls(pc, token_index, &node->data.root.top_level_decls);
@@ -1323,8 +1335,10 @@ static AstNode *ast_parse_root(ParseContext *pc, int *token_index) {
return node;
}
-AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) {
+AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color) {
ParseContext pc = {0};
+ pc.err_color = err_color;
+ pc.owner = owner;
pc.buf = buf;
pc.tokens = tokens;
int token_index = 0;
diff --git a/src/parser.hpp b/src/parser.hpp
index cc7b3dd0b6..4f433fe8eb 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -11,9 +11,11 @@
#include "list.hpp"
#include "buffer.hpp"
#include "tokenizer.hpp"
+#include "errmsg.hpp"
struct AstNode;
struct CodeGenNode;
+struct ImportTableEntry;
enum NodeType {
NodeTypeRoot,
@@ -166,10 +168,10 @@ struct AstNodeUse {
struct AstNode {
enum NodeType type;
- AstNode *parent;
int line;
int column;
CodeGenNode *codegen_node;
+ ImportTableEntry *owner;
union {
AstNodeRoot root;
AstNodeRootExportDecl root_export_decl;
@@ -198,7 +200,7 @@ void ast_token_error(Token *token, const char *format, ...);
// This function is provided by generated code, generated by parsergen.cpp
-AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens);
+AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color);
const char *node_type_str(NodeType node_type);
diff --git a/src/semantic_info.hpp b/src/semantic_info.hpp
index ec2d2403e3..f0a79d685d 100644
--- a/src/semantic_info.hpp
+++ b/src/semantic_info.hpp
@@ -11,6 +11,7 @@
#include "codegen.hpp"
#include "hash_map.hpp"
#include "zig_llvm.hpp"
+#include "errmsg.hpp"
struct FnTableEntry;
@@ -30,6 +31,8 @@ struct ImportTableEntry {
AstNode *root;
Buf *path; // relative to root_source_dir
LLVMZigDIFile *di_file;
+ Buf *source_code;
+ ZigList<int> *line_offsets;
// reminder: hash tables must be initialized before use
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
@@ -47,7 +50,7 @@ struct FnTableEntry {
struct CodeGen {
LLVMModuleRef module;
- ZigList<ErrorMsg> errors;
+ ZigList<ErrorMsg*> errors;
LLVMBuilderRef builder;
LLVMZigDIBuilder *dbuilder;
LLVMZigDICompileUnit *compile_unit;
@@ -77,7 +80,14 @@ struct CodeGen {
Buf *root_source_dir;
Buf *root_out_name;
ZigList<LLVMZigDIScope *> block_scopes;
+
+ // The function definitions this module includes. There must be a corresponding
+ // fn_protos entry.
ZigList<FnTableEntry *> fn_defs;
+ // The function prototypes this module includes. In the case of external declarations,
+ // there will not be a corresponding fn_defs entry.
+ ZigList<FnTableEntry *> fn_protos;
+
OutType out_type;
FnTableEntry *cur_fn;
bool c_stdint_used;
@@ -86,6 +96,8 @@ struct CodeGen {
int version_minor;
int version_patch;
bool verbose;
+ ErrColor err_color;
+ ImportTableEntry *root_import;
};
struct TypeNode {
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index 94f3966f0f..0a61bb9168 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -104,6 +104,7 @@ enum TokenizeState {
TokenizeStateBang,
TokenizeStateLessThan,
TokenizeStateGreaterThan,
+ TokenizeStateError,
};
@@ -116,27 +117,25 @@ struct Tokenize {
int column;
Token *cur_tok;
int multi_line_comment_count;
+ Tokenization *out;
};
__attribute__ ((format (printf, 2, 3)))
static void tokenize_error(Tokenize *t, const char *format, ...) {
- int line;
- int column;
+ t->state = TokenizeStateError;
+
if (t->cur_tok) {
- line = t->cur_tok->start_line + 1;
- column = t->cur_tok->start_column + 1;
+ t->out->err_line = t->cur_tok->start_line;
+ t->out->err_column = t->cur_tok->start_column;
} else {
- line = t->line + 1;
- column = t->column + 1;
+ t->out->err_line = t->line;
+ t->out->err_column = t->column;
}
va_list ap;
va_start(ap, format);
- fprintf(stderr, "Error: Line %d, column %d: ", line, column);
- vfprintf(stderr, format, ap);
- fprintf(stderr, "\n");
+ t->out->err = buf_vprintf(format, ap);
va_end(ap);
- exit(EXIT_FAILURE);
}
static void begin_token(Tokenize *t, TokenId id) {
@@ -187,13 +186,20 @@ static void end_token(Tokenize *t) {
t->cur_tok = nullptr;
}
-ZigList<Token> *tokenize(Buf *buf) {
+void tokenize(Buf *buf, Tokenization *out) {
Tokenize t = {0};
- t.tokens = allocate<ZigList<Token>>(1);
+ t.out = out;
+ t.tokens = out->tokens = allocate<ZigList<Token>>(1);
t.buf = buf;
+
+ out->line_offsets = allocate<ZigList<int>>(1);
+
+ out->line_offsets->append(0);
for (t.pos = 0; t.pos < buf_len(t.buf); t.pos += 1) {
uint8_t c = buf_ptr(t.buf)[t.pos];
switch (t.state) {
+ case TokenizeStateError:
+ break;
case TokenizeStateStart:
switch (c) {
case WHITESPACE:
@@ -509,6 +515,7 @@ ZigList<Token> *tokenize(Buf *buf) {
break;
}
if (c == '\n') {
+ out->line_offsets->append(t.pos + 1);
t.line += 1;
t.column = 0;
} else {
@@ -518,6 +525,7 @@ ZigList<Token> *tokenize(Buf *buf) {
// EOF
switch (t.state) {
case TokenizeStateStart:
+ case TokenizeStateError:
break;
case TokenizeStateString:
tokenize_error(&t, "unterminated string");
@@ -544,11 +552,12 @@ ZigList<Token> *tokenize(Buf *buf) {
tokenize_error(&t, "unterminated multi-line comment");
break;
}
- t.pos = -1;
- begin_token(&t, TokenIdEof);
- end_token(&t);
- assert(!t.cur_tok);
- return t.tokens;
+ if (t.state != TokenizeStateError) {
+ t.pos = -1;
+ begin_token(&t, TokenIdEof);
+ end_token(&t);
+ assert(!t.cur_tok);
+ }
}
static const char * token_name(Token *token) {
diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp
index 94cbb15d43..45bc011e03 100644
--- a/src/tokenizer.hpp
+++ b/src/tokenizer.hpp
@@ -65,7 +65,17 @@ struct Token {
int start_column;
};
-ZigList<Token> *tokenize(Buf *buf);
+struct Tokenization {
+ ZigList<Token> *tokens;
+ ZigList<int> *line_offsets;
+
+ // if an error occurred
+ Buf *err;
+ int err_line;
+ int err_column;
+};
+
+void tokenize(Buf *buf, Tokenization *out_tokenization);
void print_tokens(Buf *buf, ZigList<Token> *tokens);
diff --git a/src/util.hpp b/src/util.hpp
index b3180528dd..74fcf85020 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -16,8 +16,6 @@
#define BREAKPOINT __asm("int $0x03")
-static const int COMPILE_FAILED_ERR_CODE = 10; // chosen with a random number generator
-
void zig_panic(const char *format, ...)
__attribute__((cold))
__attribute__ ((noreturn))