aboutsummaryrefslogtreecommitdiff
path: root/src/analyze.cpp
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/analyze.cpp
parent9278dbedd5242bf4253da29c0fab36eea9dda61b (diff)
parentdfb6682089ad758b7ba72733778a9aa8c544c164 (diff)
downloadzig-ab327344b671bff7f874f24691d7e3f19176167c.tar.gz
zig-ab327344b671bff7f874f24691d7e3f19176167c.zip
merge conflicts
Diffstat (limited to 'src/analyze.cpp')
-rw-r--r--src/analyze.cpp274
1 files changed, 129 insertions, 145 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);
- }
-}