add this keyword refers to thing in immediate scope

See #169
This commit is contained in:
Andrew Kelley 2016-09-26 23:47:30 -04:00
parent f4d7c91363
commit 183976b242
16 changed files with 167 additions and 16 deletions

View File

@ -151,7 +151,7 @@ GotoExpression = "goto" Symbol
GroupedExpression = "(" Expression ")"
KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "zeroes" | "error" | "type"
KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "zeroes" | "error" | "type" | "this"
```
## Operator Precedence

View File

@ -14,7 +14,7 @@ syn keyword zigStatement goto break return continue asm defer
syn keyword zigConditional if else switch
syn keyword zigRepeat while for
syn keyword zigConstant null undefined zeroes
syn keyword zigConstant null undefined zeroes this
syn keyword zigKeyword fn use
syn keyword zigType bool f32 f64 void unreachable type error
syn keyword zigType i8 u8 i16 u16 i32 u32 i64 u64 isize usize

View File

@ -85,6 +85,7 @@ struct ConstExprValue {
ConstArrayValue x_array;
ConstPtrValue x_ptr;
ImportTableEntry *x_import;
BlockContext *x_block;
} data;
};
@ -174,6 +175,7 @@ enum NodeType {
NodeTypeNullLiteral,
NodeTypeUndefinedLiteral,
NodeTypeZeroesLiteral,
NodeTypeThisLiteral,
NodeTypeIfBoolExpr,
NodeTypeIfVarExpr,
NodeTypeWhileExpr,
@ -719,6 +721,11 @@ struct AstNodeZeroesLiteral {
Expr resolved_expr;
};
struct AstNodeThisLiteral {
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNodeSymbolExpr {
Buf *symbol;
@ -822,6 +829,7 @@ struct AstNode {
AstNodeNullLiteral null_literal;
AstNodeUndefinedLiteral undefined_literal;
AstNodeZeroesLiteral zeroes_literal;
AstNodeThisLiteral this_literal;
AstNodeSymbolExpr symbol_expr;
AstNodeBoolLiteral bool_literal;
AstNodeBreakExpr break_expr;
@ -1005,6 +1013,7 @@ enum TypeTableEntryId {
TypeTableEntryIdFn,
TypeTableEntryIdTypeDecl,
TypeTableEntryIdNamespace,
TypeTableEntryIdBlock,
TypeTableEntryIdGenericFn,
};
@ -1102,7 +1111,6 @@ struct FnTableEntry {
AstNode *want_pure_return_type;
bool safety_off;
FnInline fn_inline;
BlockContext *parent_block_context;
FnAnalState anal_state;
ZigList<AstNode *> cast_alloca_list;
@ -1209,6 +1217,7 @@ struct CodeGen {
TypeTableEntry *entry_type;
TypeTableEntry *entry_invalid;
TypeTableEntry *entry_namespace;
TypeTableEntry *entry_block;
TypeTableEntry *entry_num_lit_int;
TypeTableEntry *entry_num_lit_float;
TypeTableEntry *entry_undef;
@ -1340,7 +1349,6 @@ struct LabelTableEntry {
};
struct BlockContext {
// One of: NodeTypeFnDef, NodeTypeBlock, NodeTypeRoot, NodeTypeDefer, NodeTypeVariableDeclaration
AstNode *node;
// any variables that are introduced by this scope

View File

@ -91,6 +91,7 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeNullLiteral:
case NodeTypeUndefinedLiteral:
case NodeTypeZeroesLiteral:
case NodeTypeThisLiteral:
case NodeTypeIfBoolExpr:
case NodeTypeIfVarExpr:
case NodeTypeLabel:
@ -246,6 +247,7 @@ static bool type_is_complete(TypeTableEntry *type_entry) {
case TypeTableEntryIdFn:
case TypeTableEntryIdTypeDecl:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
return true;
}
@ -962,6 +964,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
case TypeTableEntryIdNullLit:
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
fn_proto->skip = true;
add_node_error(g, child->data.param_decl.type,
@ -1012,6 +1015,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdVar:
fn_proto->skip = true;
@ -1896,6 +1900,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only)
case NodeTypeNullLiteral:
case NodeTypeUndefinedLiteral:
case NodeTypeZeroesLiteral:
case NodeTypeThisLiteral:
case NodeTypeSymbol:
case NodeTypePrefixOpExpr:
case NodeTypeIfBoolExpr:
@ -1960,6 +1965,7 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) {
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
return false;
@ -2745,6 +2751,7 @@ static bool is_container(TypeTableEntry *type_entry) {
case TypeTableEntryIdFn:
case TypeTableEntryIdTypeDecl:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
return false;
}
@ -2791,6 +2798,7 @@ static void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
case TypeTableEntryIdFn:
case TypeTableEntryIdTypeDecl:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdInvalid:
case TypeTableEntryIdVar:
@ -2965,7 +2973,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
}
if (decl_node) {
TopLevelDecl *tld = get_as_top_level_decl(decl_node);
if (tld->visib_mod == VisibModPrivate) {
if (tld->visib_mod == VisibModPrivate && decl_node->owner != import) {
ErrorMsg *msg = add_node_error(g, node,
buf_sprintf("'%s' is private", buf_ptr(field_name)));
add_error_note(g, msg, decl_node, buf_sprintf("declared here"));
@ -3093,6 +3101,16 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node,
return g->builtin_types.entry_type;
}
static TypeTableEntry *resolve_expr_const_val_as_block(CodeGen *g, AstNode *node, BlockContext *block_context,
bool depends_on_compile_var)
{
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_block = block_context;
expr->const_val.depends_on_compile_var = depends_on_compile_var;
return g->builtin_types.entry_block;
}
static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode *node, AstNode *other,
bool depends_on_compile_var)
{
@ -3221,6 +3239,13 @@ static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, As
return g->builtin_types.entry_num_lit_int;
}
static TypeTableEntry *resolve_expr_const_val_as_import(CodeGen *g, AstNode *node, ImportTableEntry *import) {
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_import = import;
return g->builtin_types.entry_namespace;
}
static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *node, Buf *err_name)
{
@ -3497,6 +3522,7 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im
case TypeTableEntryIdFn:
case TypeTableEntryIdTypeDecl:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
if (!is_equality_cmp) {
add_node_error(g, node,
@ -4120,6 +4146,25 @@ static TypeTableEntry *analyze_zeroes_literal_expr(CodeGen *g, ImportTableEntry
return expected_type ? expected_type : g->builtin_types.entry_undef;
}
static TypeTableEntry *analyze_this_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
if (!context->parent) {
return resolve_expr_const_val_as_import(g, node, import);
}
if (context->fn_entry && (!context->parent->fn_entry ||
(context->parent->parent && !context->parent->parent->fn_entry)))
{
return resolve_expr_const_val_as_fn(g, node, context->fn_entry, false);
}
if (context->node->type == NodeTypeContainerDecl) {
return resolve_expr_const_val_as_type(g, node, context->node->data.struct_decl.type_entry, false);
}
if (context->node->type == NodeTypeBlock) {
return resolve_expr_const_val_as_block(g, node, context, false);
}
zig_unreachable();
}
static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import,
BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
@ -4793,13 +4838,6 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
return g->builtin_types.entry_invalid;
}
static TypeTableEntry *resolve_expr_const_val_as_import(CodeGen *g, AstNode *node, ImportTableEntry *import) {
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_import = import;
return g->builtin_types.entry_namespace;
}
static TypeTableEntry *analyze_import(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node)
{
@ -5394,6 +5432,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdVar:
add_node_error(g, expr_node,
@ -6796,6 +6835,9 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
case NodeTypeZeroesLiteral:
return_type = analyze_zeroes_literal_expr(g, import, context, expected_type, node);
break;
case NodeTypeThisLiteral:
return_type = analyze_this_literal_expr(g, import, context, expected_type, node);
break;
case NodeTypeSymbol:
return_type = analyze_symbol_expr(g, import, context, expected_type, node, pointer_only);
break;
@ -7085,6 +7127,7 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
case NodeTypeNullLiteral:
case NodeTypeUndefinedLiteral:
case NodeTypeZeroesLiteral:
case NodeTypeThisLiteral:
case NodeTypeSymbol:
case NodeTypePrefixOpExpr:
case NodeTypeIfBoolExpr:
@ -7347,6 +7390,8 @@ Expr *get_resolved_expr(AstNode *node) {
return &node->data.undefined_literal.resolved_expr;
case NodeTypeZeroesLiteral:
return &node->data.zeroes_literal.resolved_expr;
case NodeTypeThisLiteral:
return &node->data.this_literal.resolved_expr;
case NodeTypeGoto:
return &node->data.goto_expr.resolved_expr;
case NodeTypeBreak:
@ -7432,6 +7477,7 @@ static TopLevelDecl *get_as_top_level_decl(AstNode *node) {
case NodeTypeNullLiteral:
case NodeTypeUndefinedLiteral:
case NodeTypeZeroesLiteral:
case NodeTypeThisLiteral:
case NodeTypeLabel:
case NodeTypeGoto:
case NodeTypeBreak:
@ -7499,6 +7545,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdVar:
zig_unreachable();
@ -7640,6 +7687,8 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val)
return hash_ptr(const_val->data.x_type);
case TypeTableEntryIdNamespace:
return hash_ptr(const_val->data.x_import);
case TypeTableEntryIdBlock:
return hash_ptr(const_val->data.x_block);
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdInvalid:
case TypeTableEntryIdUnreachable:
@ -7715,6 +7764,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry)
case TypeTableEntryIdMetaType:
case TypeTableEntryIdVoid:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdVar:
zig_unreachable();

View File

@ -173,6 +173,8 @@ static const char *node_type_str(NodeType node_type) {
return "UndefinedLiteral";
case NodeTypeZeroesLiteral:
return "ZeroesLiteral";
case NodeTypeThisLiteral:
return "ThisLiteral";
case NodeTypeIfBoolExpr:
return "IfBoolExpr";
case NodeTypeIfVarExpr:
@ -597,6 +599,8 @@ static void render_node(AstRender *ar, AstNode *node) {
zig_panic("TODO");
case NodeTypeZeroesLiteral:
zig_panic("TODO");
case NodeTypeThisLiteral:
zig_panic("TODO");
case NodeTypeIfBoolExpr:
zig_panic("TODO");
case NodeTypeIfVarExpr:

View File

@ -3605,6 +3605,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeNullLiteral:
case NodeTypeUndefinedLiteral:
case NodeTypeZeroesLiteral:
case NodeTypeThisLiteral:
case NodeTypeErrorType:
case NodeTypeTypeLiteral:
case NodeTypeArrayType:
@ -3826,6 +3827,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
case TypeTableEntryIdNullLit:
case TypeTableEntryIdVoid:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdVar:
zig_unreachable();
@ -4349,6 +4351,13 @@ static void define_builtin_types(CodeGen *g) {
entry->deep_const = true;
g->builtin_types.entry_namespace = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBlock);
buf_init_from_str(&entry->name, "(block)");
entry->zero_bits = true;
entry->deep_const = true;
g->builtin_types.entry_block = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat);
buf_init_from_str(&entry->name, "(float literal)");
@ -5145,6 +5154,7 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
case TypeTableEntryIdMetaType:
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdUndefLit:

View File

@ -83,6 +83,7 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty
zig_panic("TODO");
case TypeTableEntryIdNamespace:
zig_panic("TODO");
case TypeTableEntryIdBlock:
zig_panic("TODO");
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdInvalid:
@ -1373,6 +1374,7 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
case NodeTypeNullLiteral:
case NodeTypeUndefinedLiteral:
case NodeTypeZeroesLiteral:
case NodeTypeThisLiteral:
case NodeTypeIfVarExpr:
case NodeTypeSwitchExpr:
case NodeTypeSwitchProng:

View File

@ -620,7 +620,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m
/*
PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." "Symbol")
KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "zeroes" | "error" | "type"
KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "zeroes" | "error" | "type" | "this"
*/
static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
@ -672,6 +672,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
AstNode *node = ast_create_node(pc, NodeTypeZeroesLiteral, token);
*token_index += 1;
return node;
} else if (token->id == TokenIdKeywordThis) {
AstNode *node = ast_create_node(pc, NodeTypeThisLiteral, token);
*token_index += 1;
return node;
} else if (token->id == TokenIdKeywordType) {
AstNode *node = ast_create_node(pc, NodeTypeTypeLiteral, token);
*token_index += 1;
@ -2560,6 +2564,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeZeroesLiteral:
// none
break;
case NodeTypeThisLiteral:
// none
break;
case NodeTypeIfBoolExpr:
visit_field(&node->data.if_bool_expr.condition, visit, context);
visit_field(&node->data.if_bool_expr.then_block, visit, context);
@ -2840,6 +2847,9 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
case NodeTypeZeroesLiteral:
// none
break;
case NodeTypeThisLiteral:
// none
break;
case NodeTypeIfBoolExpr:
clone_subtree_field(&new_node->data.if_bool_expr.condition, old_node->data.if_bool_expr.condition, next_node_index);
clone_subtree_field(&new_node->data.if_bool_expr.then_block, old_node->data.if_bool_expr.then_block, next_node_index);

View File

@ -129,6 +129,7 @@ static const struct ZigKeyword zig_keywords[] = {
{"return", TokenIdKeywordReturn},
{"struct", TokenIdKeywordStruct},
{"switch", TokenIdKeywordSwitch},
{"this", TokenIdKeywordThis},
{"true", TokenIdKeywordTrue},
{"type", TokenIdKeywordType},
{"undefined", TokenIdKeywordUndefined},
@ -1470,6 +1471,7 @@ const char * token_name(TokenId id) {
case TokenIdKeywordSwitch: return "switch";
case TokenIdKeywordUndefined: return "undefined";
case TokenIdKeywordZeroes: return "zeroes";
case TokenIdKeywordThis: return "this";
case TokenIdKeywordError: return "error";
case TokenIdKeywordType: return "type";
case TokenIdKeywordInline: return "inline";

View File

@ -45,6 +45,7 @@ enum TokenId {
TokenIdKeywordType,
TokenIdKeywordInline,
TokenIdKeywordDefer,
TokenIdKeywordThis,
TokenIdLParen,
TokenIdRParen,
TokenIdComma,

View File

@ -24,7 +24,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
// this is used to detect bugs where a hashtable is edited while an iterator is running.
modification_count: debug_u32,
const Self = SmallHashMap(K, V, hash, eql, static_size);
const Self = this;
pub struct Entry {
used: bool,

View File

@ -4,7 +4,7 @@ const mem = @import("mem.zig");
const Allocator = mem.Allocator;
pub struct List(T: type) {
const Self = List(T);
const Self = this;
items: []T,
len: usize,

View File

@ -101,7 +101,7 @@ struct MersenneTwister(
t: int, c: int,
l: int, f: int)
{
const Self = MersenneTwister(int, n, m, r, a, u, d, s, b, t, c, l, f);
const Self = this;
array: [n]int,
index: usize,

47
test/cases/this.zig Normal file
View File

@ -0,0 +1,47 @@
const assert = @import("std").debug.assert;
const module = this;
struct Point(inline T: type) {
const Self = this;
x: T,
y: T,
fn addOne(self: &Self) {
self.x += 1;
self.y += 1;
}
}
fn add(x: i32, y: i32) -> i32 {
x + y
}
fn factorial(x: i32) -> i32 {
const selfFn = this;
if (x == 0) {
1
} else {
x * selfFn(x - 1)
}
}
#attribute("test")
fn thisReferToModuleCallPrivateFn() {
assert(module.add(1, 2) == 3);
}
#attribute("test")
fn thisReferToContainer() {
var pt = Point(i32) {
.x = 12,
.y = 34,
};
pt.addOne();
assert(pt.x == 13);
assert(pt.y == 35);
}
#attribute("test")
fn thisReferToFn() {
assert(factorial(5) == 120);
}

View File

@ -1597,6 +1597,22 @@ const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT;
var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1);
)SOURCE", 1, ".tmp_source.zig:4:60: error: unable to perform binary not operation on type '(integer literal)'");
{
TestCase *tc = add_compile_fail_case("multiple files with private function error", R"SOURCE(
const foo = @import("foo.zig");
fn callPrivFunction() {
foo.privateFunction();
}
)SOURCE", 2,
".tmp_source.zig:5:8: error: 'privateFunction' is private",
"foo.zig:2:1: note: declared here");
add_source_file(tc, "foo.zig", R"SOURCE(
fn privateFunction() { }
)SOURCE");
}
}
//////////////////////////////////////////////////////////////////////////////

View File

@ -15,6 +15,7 @@ const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cas
const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig");
const test_enum_with_members = @import("cases/enum_with_members.zig");
const test_struct_contains_slice_of_itself = @import("cases/struct_contains_slice_of_itself.zig");
const test_this = @import("cases/this.zig");
// normal comment
/// this is a documentation comment