Slices and slice expressions

This commit is contained in:
gingerBill
2016-07-08 01:04:57 +01:00
parent 7430008fd7
commit 9ba2a6d02c
8 changed files with 327 additions and 48 deletions
+1
View File
@@ -24,6 +24,7 @@ set compiler_warnings= ^
-wd4505 -wd4512 -wd4550 ^ -wd4505 -wd4512 -wd4550 ^
set compiler_includes= ^ set compiler_includes= ^
rem -I"C:\Program Files\LLVM\include" rem -I"C:\Program Files\LLVM\include"
set libs= kernel32.lib user32.lib gdi32.lib opengl32.lib ^ set libs= kernel32.lib user32.lib gdi32.lib opengl32.lib ^
+6
View File
@@ -71,6 +71,9 @@ enum BuiltinProcedureId {
BuiltinProcedure_offset_of, BuiltinProcedure_offset_of,
BuiltinProcedure_offset_of_val, BuiltinProcedure_offset_of_val,
BuiltinProcedure_static_assert, BuiltinProcedure_static_assert,
BuiltinProcedure_len,
BuiltinProcedure_cap,
BuiltinProcedure_copy,
BuiltinProcedure_print, BuiltinProcedure_print,
BuiltinProcedure_println, BuiltinProcedure_println,
@@ -111,6 +114,9 @@ gb_global BuiltinProcedure builtin_procedures[BuiltinProcedure_Count] = {
{STR_LIT("offset_of"), 2, false, Expression_Expression}, {STR_LIT("offset_of"), 2, false, Expression_Expression},
{STR_LIT("offset_of_val"), 1, false, Expression_Expression}, {STR_LIT("offset_of_val"), 1, false, Expression_Expression},
{STR_LIT("static_assert"), 1, false, Expression_Statement}, {STR_LIT("static_assert"), 1, false, Expression_Statement},
{STR_LIT("len"), 1, false, Expression_Expression},
{STR_LIT("cap"), 1, false, Expression_Expression},
{STR_LIT("copy"), 2, false, Expression_Expression},
{STR_LIT("print"), 1, true, Expression_Statement}, {STR_LIT("print"), 1, true, Expression_Statement},
{STR_LIT("println"), 1, true, Expression_Statement}, {STR_LIT("println"), 1, true, Expression_Statement},
}; };
+217 -32
View File
@@ -252,8 +252,9 @@ Type *check_type_expression_extra(Checker *c, AstNode *expression, Type *named_t
set_base_type(named_type, t); set_base_type(named_type, t);
return t; return t;
} else { } else {
print_checker_error(c, ast_node_token(expression), "Empty array size"); Type *t = make_type_slice(check_type(c, expression->array_type.element));
return NULL; set_base_type(named_type, t);
return t;
} }
break; break;
@@ -335,12 +336,17 @@ Type *check_type(Checker *c, AstNode *expression, Type *named_type) {
case AstNode_ParenExpression: case AstNode_ParenExpression:
return check_type(c, expression->paren_expression.expression, named_type); return check_type(c, expression->paren_expression.expression, named_type);
case AstNode_ArrayType: case AstNode_ArrayType: {
type = make_type_array(check_type(c, expression->array_type.element), if (expression->array_type.count != NULL) {
check_array_count(c, expression->array_type.count)); type = make_type_array(check_type(c, expression->array_type.element),
set_base_type(named_type, type); check_array_count(c, expression->array_type.count));
set_base_type(named_type, type);
} else {
type = make_type_slice(check_type(c, expression->array_type.element));
set_base_type(named_type, type);
}
goto end; goto end;
break; } break;
case AstNode_StructType: { case AstNode_StructType: {
type = make_type_structure(); type = make_type_structure();
@@ -860,35 +866,43 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type) {
operand->type = target_type; operand->type = target_type;
} }
b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, b32 bound_checks) { b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *value) {
Operand operand = {Addressing_Invalid}; Operand operand = {Addressing_Invalid};
check_expression(c, &operand, index_value); check_expression(c, &operand, index_value);
if (operand.mode == Addressing_Invalid) if (operand.mode == Addressing_Invalid) {
if (value) *value = 0;
return false; return false;
}
convert_to_typed(c, &operand, &basic_types[Basic_int]); convert_to_typed(c, &operand, &basic_types[Basic_int]);
if (operand.mode == Addressing_Invalid) if (operand.mode == Addressing_Invalid) {
if (value) *value = 0;
return false; return false;
}
if (!is_type_integer(operand.type)) { if (!is_type_integer(operand.type)) {
gbString expr_str = expression_to_string(operand.expression); gbString expr_str = expression_to_string(operand.expression);
print_checker_error(c, ast_node_token(operand.expression), print_checker_error(c, ast_node_token(operand.expression),
"Index `%s` must be an integer", expr_str); "Index `%s` must be an integer", expr_str);
gb_string_free(expr_str); gb_string_free(expr_str);
if (value) *value = 0;
return false; return false;
} }
if (operand.mode == Addressing_Constant) { if (operand.mode == Addressing_Constant) {
if (bound_checks && max_count > 0) { // NOTE(bill): Do array bound checking if (max_count >= 0) { // NOTE(bill): Do array bound checking
i64 i = value_to_integer(operand.value).value_integer; i64 i = value_to_integer(operand.value).value_integer;
if (i < 0) { if (i < 0) {
gbString expr_str = expression_to_string(operand.expression); gbString expr_str = expression_to_string(operand.expression);
print_checker_error(c, ast_node_token(operand.expression), print_checker_error(c, ast_node_token(operand.expression),
"Index `%s` cannot be a negative value", expr_str); "Index `%s` cannot be a negative value", expr_str);
gb_string_free(expr_str); gb_string_free(expr_str);
if (value) *value = 0;
return false; return false;
} }
if (value) *value = i;
if (i >= max_count) { if (i >= max_count) {
gbString expr_str = expression_to_string(operand.expression); gbString expr_str = expression_to_string(operand.expression);
print_checker_error(c, ast_node_token(operand.expression), print_checker_error(c, ast_node_token(operand.expression),
@@ -896,10 +910,13 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, b32 bound
gb_string_free(expr_str); gb_string_free(expr_str);
return false; return false;
} }
return true;
} }
} }
// NOTE(bill): It's alright :D // NOTE(bill): It's alright :D
if (value) *value = -1;
return true; return true;
} }
@@ -920,10 +937,6 @@ Entity *lookup_field(Type *type, AstNode *field_node, isize *index = NULL) {
return f; return f;
} }
} }
} else {
// TODO(bill): Array.count
// TODO(bill): Array.elements
// TODO(bill): Or should these be functions?
} }
return NULL; return NULL;
@@ -960,7 +973,6 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) {
} }
b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) { b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
GB_ASSERT(call->kind == AstNode_CallExpression); GB_ASSERT(call->kind == AstNode_CallExpression);
auto *ce = &call->call_expression; auto *ce = &call->call_expression;
@@ -972,10 +984,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
if (ce->arg_list_count > bp->arg_count && !bp->variadic) if (ce->arg_list_count > bp->arg_count && !bp->variadic)
err = "Too many"; err = "Too many";
if (err) { if (err) {
gbString call_str = expression_to_string(call); print_checker_error(c, ce->close, "`%s` arguments for `%.*s`, expected %td, got %td",
defer (gb_string_free(call_str)); err, LIT(call->call_expression.proc->identifier.token.string),
print_checker_error(c, ce->close, "`%s` arguments for `%s`, expected %td, got %td", bp->arg_count, ce->arg_list_count);
err, call_str, bp->arg_count, ce->arg_list_count);
return false; return false;
} }
} }
@@ -1044,7 +1055,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
print_checker_error(c, ast_node_token(ce->arg_list), "Expected a structure type for `offset_of`"); print_checker_error(c, ast_node_token(ce->arg_list), "Expected a structure type for `offset_of`");
return false; return false;
} }
if (field_arg->kind != AstNode_Identifier) { if (field_arg == NULL ||
field_arg->kind != AstNode_Identifier) {
print_checker_error(c, ast_node_token(field_arg), "Expected an identifier for field argument"); print_checker_error(c, ast_node_token(field_arg), "Expected an identifier for field argument");
return false; return false;
} }
@@ -1055,7 +1067,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
if (entity == NULL) { if (entity == NULL) {
gbString type_str = type_to_string(type); gbString type_str = type_to_string(type);
print_checker_error(c, ast_node_token(ce->arg_list), print_checker_error(c, ast_node_token(ce->arg_list),
"`%s` has no field named `%s`", type_str, LIT(field_arg->identifier.token.string)); "`%s` has no field named `%.*s`", type_str, LIT(field_arg->identifier.token.string));
return false; return false;
} }
@@ -1089,7 +1101,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
if (entity == NULL) { if (entity == NULL) {
gbString type_str = type_to_string(type); gbString type_str = type_to_string(type);
print_checker_error(c, ast_node_token(arg), print_checker_error(c, ast_node_token(arg),
"`%s` has no field named `%s`", type_str, LIT(s->selector->identifier.token.string)); "`%s` has no field named `%.*s`", type_str, LIT(s->selector->identifier.token.string));
return false; return false;
} }
@@ -1099,6 +1111,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
} break; } break;
case BuiltinProcedure_static_assert: case BuiltinProcedure_static_assert:
// static_assert :: proc(cond: bool)
if (operand->mode != Addressing_Constant || if (operand->mode != Addressing_Constant ||
!is_type_boolean(operand->type)) { !is_type_boolean(operand->type)) {
gbString str = expression_to_string(ce->arg_list); gbString str = expression_to_string(ce->arg_list);
@@ -1116,6 +1130,92 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
} }
break; break;
case BuiltinProcedure_len:
case BuiltinProcedure_cap: {
Type *t = get_base_type(operand->type);
AddressingMode mode = Addressing_Invalid;
Value value = {};
switch (t->kind) {
case Type_Basic:
if (id == BuiltinProcedure_len) {
if (is_type_string(t)) {
if (operand->mode == Addressing_Constant) {
mode = Addressing_Constant;
value = make_value_integer(operand->value.value_string.len);
} else {
mode = Addressing_Value;
}
}
}
break;
case Type_Array:
mode = Addressing_Constant;
value = make_value_integer(t->array.count);
break;
case Type_Slice:
mode = Addressing_Value;
break;
}
if (mode == Addressing_Invalid) {
gbString str = expression_to_string(operand->expression);
print_checker_error(c, ast_node_token(operand->expression),
"Invalid expression `%s` for `%.*s`",
str, LIT(bp->name));
gb_string_free(str);
return false;
}
operand->mode = mode;
operand->type = &basic_types[Basic_int];
operand->value = value;
} break;
case BuiltinProcedure_copy: {
// copy :: proc(x, y: []Type) -> int
Type *dest_type = NULL, *src_type = NULL;
Type *d = get_base_type(operand->type);
if (d->kind == Type_Slice)
dest_type = d->slice.element;
Operand op = {};
check_expression(c, &op, ce->arg_list->next);
if (op.mode == Addressing_Invalid)
return false;
Type *s = get_base_type(op.type);
if (s->kind == Type_Slice)
src_type = s->slice.element;
if (dest_type == NULL || src_type == NULL) {
print_checker_error(c, ast_node_token(call), "`copy` only expects slices as arguments");
return false;
}
if (!are_types_identical(dest_type, src_type)) {
gbString d_arg = expression_to_string(ce->arg_list);
gbString s_arg = expression_to_string(ce->arg_list->next);
gbString d_str = type_to_string(dest_type);
gbString s_str = type_to_string(src_type);
defer (gb_string_free(d_arg));
defer (gb_string_free(s_arg));
defer (gb_string_free(d_str));
defer (gb_string_free(s_str));
print_checker_error(c, ast_node_token(call),
"Arguments to `copy`, %s, %s, have different element types: %s vs %s",
d_arg, s_arg, d_str, s_str);
return false;
}
operand->type = &basic_types[Basic_int]; // Returns number of elements copied
operand->mode = Addressing_Value;
} break;
case BuiltinProcedure_print: case BuiltinProcedure_print:
case BuiltinProcedure_println: { case BuiltinProcedure_println: {
for (AstNode *arg = ce->arg_list; arg != NULL; arg = arg->next) { for (AstNode *arg = ce->arg_list; arg != NULL; arg = arg->next) {
@@ -1170,7 +1270,6 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
operand->mode = Addressing_Value; operand->mode = Addressing_Value;
check_not_tuple(c, operand); check_not_tuple(c, operand);
check_assignment(c, operand, sig_params[param_index]->type, make_string("argument")); check_assignment(c, operand, sig_params[param_index]->type, make_string("argument"));
} }
if (i < tuple->variable_count && param_index == param_count) { if (i < tuple->variable_count && param_index == param_count) {
@@ -1179,7 +1278,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
} }
} }
if (param_index < param_count) if (param_index >= param_count)
break; break;
} }
@@ -1392,8 +1491,7 @@ ExpressionKind check_expression_base(Checker *c, Operand *operand, AstNode *expr
goto error; goto error;
b32 valid = false; b32 valid = false;
b32 bound_checks = false; i64 max_count = -1;
i64 max_count = 0;
Type *t = get_base_type(operand->type); Type *t = get_base_type(operand->type);
switch (t->kind) { switch (t->kind) {
case Type_Basic: case Type_Basic:
@@ -1401,7 +1499,6 @@ ExpressionKind check_expression_base(Checker *c, Operand *operand, AstNode *expr
valid = true; valid = true;
if (operand->mode == Addressing_Constant) { if (operand->mode == Addressing_Constant) {
max_count = operand->value.value_string.len; max_count = operand->value.value_string.len;
bound_checks = true;
} }
operand->mode = Addressing_Value; operand->mode = Addressing_Value;
operand->type = &basic_types[Basic_u8]; operand->type = &basic_types[Basic_u8];
@@ -1411,16 +1508,19 @@ ExpressionKind check_expression_base(Checker *c, Operand *operand, AstNode *expr
case Type_Array: case Type_Array:
valid = true; valid = true;
max_count = t->array.count; max_count = t->array.count;
bound_checks = max_count > 0;
if (operand->mode != Addressing_Variable) if (operand->mode != Addressing_Variable)
operand->mode = Addressing_Value; operand->mode = Addressing_Value;
operand->type = t->array.element; operand->type = t->array.element;
break; break;
case Type_Slice:
valid = true;
operand->type = t->slice.element;
operand->mode = Addressing_Variable;
break;
case Type_Pointer: case Type_Pointer:
valid = true; valid = true;
bound_checks = false;
max_count = 0;
operand->mode = Addressing_Variable; operand->mode = Addressing_Variable;
operand->type = get_base_type(t->pointer.element); operand->type = get_base_type(t->pointer.element);
break; break;
@@ -1442,7 +1542,92 @@ ExpressionKind check_expression_base(Checker *c, Operand *operand, AstNode *expr
goto error; goto error;
} }
check_index_value(c, expression->index_expression.value, max_count, bound_checks); check_index_value(c, expression->index_expression.value, max_count, NULL);
} break;
case AstNode_SliceExpression: {
auto *se = &expression->slice_expression;
check_expression(c, operand, se->expression);
if (operand->mode == Addressing_Invalid)
goto error;
b32 valid = false;
i64 max_count = -1;
Type *t = get_base_type(operand->type);
switch (t->kind) {
case Type_Basic:
if (is_type_string(t)) {
valid = true;
if (operand->mode == Addressing_Constant) {
max_count = operand->value.value_string.len;
}
operand->mode = Addressing_Value;
}
break;
case Type_Array:
valid = true;
max_count = t->array.count;
if (operand->mode != Addressing_Variable) {
gbString str = expression_to_string(expression);
print_checker_error(c, ast_node_token(expression), "Cannot slice array `%s`, value is not addressable", str);
gb_string_free(str);
goto error;
}
operand->type = make_type_slice(t->array.element);
operand->mode = Addressing_Value;
break;
case Type_Slice:
valid = true;
operand->mode = Addressing_Value;
break;
case Type_Pointer:
valid = true;
operand->type = make_type_slice(get_base_type(t->pointer.element));
operand->mode = Addressing_Value;
break;
}
if (!valid) {
gbString str = expression_to_string(operand->expression);
print_checker_error(c, ast_node_token(operand->expression),
"Cannot slice `%s`", str);
gb_string_free(str);
goto error;
}
i64 indices[3] = {};
AstNode *nodes[3] = {se->low, se->high, se->max};
for (isize i = 0; i < gb_count_of(nodes); i++) {
AstNode *node = nodes[i];
i64 index = max_count;
if (node != NULL) {
i64 capacity = -1;
if (max_count >= 0)
capacity = max_count;
i64 j = 0;
if (check_index_value(c, node, capacity, &j)) {
index = j;
}
} else if (i == 0) {
index = 0;
}
indices[i] = index;
}
for (isize i = 0; i < gb_count_of(indices); i++) {
i64 a = indices[i];
for (isize j = i+1; j < gb_count_of(indices); j++) {
i64 b = indices[j];
if (a > b && b >= 0) {
print_checker_error(c, se->close, "Invalid slice indices: [%td > %td]", a, b);
}
}
}
} break; } break;
case AstNode_CastExpression: { case AstNode_CastExpression: {
+8 -2
View File
@@ -38,8 +38,14 @@ b32 check_assignable_to(Checker *c, Operand *operand, Type *type) {
if (sb->kind == Type_Array && tb->kind == Type_Array) { if (sb->kind == Type_Array && tb->kind == Type_Array) {
if (are_types_identical(sb->array.element, tb->array.element)) { if (are_types_identical(sb->array.element, tb->array.element)) {
if (tb->array.count == 0) // NOTE(bill): Not static size return sb->array.count == tb->array.count;
return true; }
}
if ((sb->kind == Type_Array || sb->kind == Type_Slice) &&
tb->kind == Type_Slice) {
if (are_types_identical(sb->array.element, tb->slice.element)) {
return true;
} }
} }
+27 -6
View File
@@ -55,6 +55,7 @@ enum TypeKind {
Type_Basic, Type_Basic,
Type_Array, Type_Array,
Type_Slice,
Type_Structure, Type_Structure,
Type_Pointer, Type_Pointer,
Type_Named, Type_Named,
@@ -71,6 +72,9 @@ struct Type {
Type *element; Type *element;
i64 count; i64 count;
} array; } array;
struct {
Type *element;
} slice;
struct { struct {
// Theses are arrays // Theses are arrays
Entity **fields; // Entity_Variable Entity **fields; // Entity_Variable
@@ -111,6 +115,7 @@ void set_base_type(Type *t, Type *base) {
} }
// TODO(bill): Remove heap allocation
Type *alloc_type(TypeKind kind) { Type *alloc_type(TypeKind kind) {
Type *t = gb_alloc_item(gb_heap_allocator(), Type); Type *t = gb_alloc_item(gb_heap_allocator(), Type);
t->kind = kind; t->kind = kind;
@@ -123,6 +128,7 @@ Type *make_type_basic(BasicType basic) {
t->basic = basic; t->basic = basic;
return t; return t;
} }
Type *make_type_array(Type *element, i64 count) { Type *make_type_array(Type *element, i64 count) {
Type *t = alloc_type(Type_Array); Type *t = alloc_type(Type_Array);
t->array.element = element; t->array.element = element;
@@ -130,6 +136,12 @@ Type *make_type_array(Type *element, i64 count) {
return t; return t;
} }
Type *make_type_slice(Type *element) {
Type *t = alloc_type(Type_Slice);
t->array.element = element;
return t;
}
Type *make_type_structure(void) { Type *make_type_structure(void) {
Type *t = alloc_type(Type_Structure); Type *t = alloc_type(Type_Structure);
return t; return t;
@@ -166,7 +178,7 @@ Type *make_type_procedure(Scope *scope, Type *params, isize params_count, Type *
#define STR_LIT(x) {cast(u8 *)x, gb_size_of(x)-1} #define STR_LIT(x) {cast(u8 *)(x), gb_size_of(x)-1}
gb_global Type basic_types[] = { gb_global Type basic_types[] = {
{Type_Basic, {Basic_Invalid, 0, STR_LIT("invalid type")}}, {Type_Basic, {Basic_Invalid, 0, STR_LIT("invalid type")}},
{Type_Basic, {Basic_bool, BasicFlag_Boolean, STR_LIT("bool")}}, {Type_Basic, {Basic_bool, BasicFlag_Boolean, STR_LIT("bool")}},
@@ -483,10 +495,11 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
} }
i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, isize index) { i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, isize index) {
GB_ASSERT(t->kind == Type_Structure); if (t->kind == Type_Structure) {
type_set_offsets(s, allocator, t); type_set_offsets(s, allocator, t);
if (gb_is_between(index, 0, t->structure.field_count-1)) { if (gb_is_between(index, 0, t->structure.field_count-1)) {
return t->structure.offsets[index]; return t->structure.offsets[index];
}
} }
return 0; return 0;
} }
@@ -501,6 +514,7 @@ gbString write_type_to_string(gbString str, Type *type) {
case Type_Basic: case Type_Basic:
str = gb_string_append_length(str, type->basic.name.text, type->basic.name.len); str = gb_string_append_length(str, type->basic.name.text, type->basic.name.len);
break; break;
case Type_Array: case Type_Array:
if (type->array.count >= 0) { if (type->array.count >= 0) {
str = gb_string_appendc(str, gb_bprintf("[%td]", type->array.count)); str = gb_string_appendc(str, gb_bprintf("[%td]", type->array.count));
@@ -509,12 +523,18 @@ gbString write_type_to_string(gbString str, Type *type) {
} }
str = write_type_to_string(str, type->array.element); str = write_type_to_string(str, type->array.element);
break; break;
case Type_Slice:
str = gb_string_appendc(str, "[]");
str = write_type_to_string(str, type->array.element);
break;
case Type_Structure: { case Type_Structure: {
str = gb_string_appendc(str, "struct{"); str = gb_string_appendc(str, "struct{");
for (isize i = 0; i < type->structure.field_count; i++) { for (isize i = 0; i < type->structure.field_count; i++) {
Entity *f = type->structure.fields[i]; Entity *f = type->structure.fields[i];
GB_ASSERT(f->kind == Entity_Variable); GB_ASSERT(f->kind == Entity_Variable);
if (i < type->structure.field_count-1) if (i > 0)
str = gb_string_appendc(str, "; "); str = gb_string_appendc(str, "; ");
str = gb_string_append_length(str, f->token.string.text, f->token.string.len); str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": "); str = gb_string_appendc(str, ": ");
@@ -564,6 +584,7 @@ gbString write_type_to_string(gbString str, Type *type) {
} }
break; break;
} }
return str; return str;
} }
+55 -4
View File
@@ -47,6 +47,7 @@ AstNode__ExpressionBegin,
AstNode_CallExpression, AstNode_CallExpression,
AstNode_SelectorExpression, AstNode_SelectorExpression,
AstNode_IndexExpression, AstNode_IndexExpression,
AstNode_SliceExpression,
AstNode_CastExpression, AstNode_CastExpression,
AstNode_DereferenceExpression, AstNode_DereferenceExpression,
AstNode__ExpressionEnd, AstNode__ExpressionEnd,
@@ -117,7 +118,7 @@ struct AstNode {
struct { Token op; AstNode *left, *right; } binary_expression; struct { Token op; AstNode *left, *right; } binary_expression;
struct { AstNode *expression; Token open, close; } paren_expression; struct { AstNode *expression; Token open, close; } paren_expression;
struct { Token token; AstNode *operand, *selector; } selector_expression; struct { Token token; AstNode *operand, *selector; } selector_expression;
struct { AstNode *expression, *value; Token open, close; } index_expression; struct { AstNode *expression, *value; Token open, close; } index_expression;
struct { Token token; AstNode *type_expression, *operand; } cast_expression; struct { Token token; AstNode *type_expression, *operand; } cast_expression;
struct { struct {
AstNode *proc, *arg_list; AstNode *proc, *arg_list;
@@ -125,6 +126,12 @@ struct AstNode {
Token open, close; Token open, close;
} call_expression; } call_expression;
struct { Token op; AstNode *operand; } dereference_expression; struct { Token op; AstNode *operand; } dereference_expression;
struct {
AstNode *expression;
Token open, close;
AstNode *low, *high, *max;
b32 triple_indexed; // [(1st):2nd:3rd]
} slice_expression;
struct { Token begin, end; } bad_statement; struct { Token begin, end; } bad_statement;
struct { Token token; } empty_statement; struct { Token token; } empty_statement;
@@ -271,6 +278,8 @@ Token ast_node_token(AstNode *node) {
return ast_node_token(node->selector_expression.selector); return ast_node_token(node->selector_expression.selector);
case AstNode_IndexExpression: case AstNode_IndexExpression:
return node->index_expression.open; return node->index_expression.open;
case AstNode_SliceExpression:
return node->slice_expression.open;
case AstNode_CastExpression: case AstNode_CastExpression:
return node->cast_expression.token; return node->cast_expression.token;
case AstNode_DereferenceExpression: case AstNode_DereferenceExpression:
@@ -439,6 +448,19 @@ gb_inline AstNode *make_index_expression(Parser *p, AstNode *expression, AstNode
return result; return result;
} }
gb_inline AstNode *make_slice_expression(Parser *p, AstNode *expression, Token open, Token close, AstNode *low, AstNode *high, AstNode *max, b32 triple_indexed) {
AstNode *result = make_node(p, AstNode_SliceExpression);
result->slice_expression.expression = expression;
result->slice_expression.open = open;
result->slice_expression.close = close;
result->slice_expression.low = low;
result->slice_expression.high = high;
result->slice_expression.max = max;
result->slice_expression.triple_indexed = triple_indexed;
return result;
}
gb_inline AstNode *make_cast_expression(Parser *p, Token token, AstNode *type_expression, AstNode *operand) { gb_inline AstNode *make_cast_expression(Parser *p, Token token, AstNode *type_expression, AstNode *operand) {
AstNode *result = make_node(p, AstNode_CastExpression); AstNode *result = make_node(p, AstNode_CastExpression);
result->cast_expression.token = token; result->cast_expression.token = token;
@@ -865,14 +887,43 @@ AstNode *parse_atom_expression(Parser *p, b32 lhs) {
if (lhs) { if (lhs) {
// TODO(bill): Handle this // TODO(bill): Handle this
} }
AstNode *value;
Token open, close; Token open, close;
AstNode *indices[3] = {};
open = expect_token(p, Token_OpenBracket); open = expect_token(p, Token_OpenBracket);
value = parse_expression(p, false); if (p->cursor[0].kind != Token_Colon)
indices[0] = parse_expression(p, false);
isize colon_count = 0;
Token colons[2] = {};
while (p->cursor[0].kind == Token_Colon && colon_count < 2) {
colons[colon_count++] = p->cursor[0];
next_token(p);
if (p->cursor[0].kind != Token_Colon &&
p->cursor[0].kind != Token_CloseBracket &&
p->cursor[0].kind != Token_EOF) {
indices[colon_count] = parse_expression(p, false);
}
}
close = expect_token(p, Token_CloseBracket); close = expect_token(p, Token_CloseBracket);
operand = make_index_expression(p, operand, value, open, close); if (colon_count == 0) {
operand = make_index_expression(p, operand, indices[0], open, close);
} else {
b32 triple_indexed = false;
if (colon_count == 2) {
triple_indexed = true;
if (indices[1] == NULL) {
print_parse_error(p, colons[0], "Second index is required in a triple indexed slice");
indices[1] = make_bad_expression(p, colons[0], colons[1]);
}
if (indices[2] == NULL) {
print_parse_error(p, colons[1], "Third index is required in a triple indexed slice");
indices[2] = make_bad_expression(p, colons[1], close);
}
}
operand = make_slice_expression(p, operand, open, close, indices[0], indices[1], indices[2], triple_indexed);
}
} break; } break;
case Token_Pointer: // Deference case Token_Pointer: // Deference
+11 -2
View File
@@ -1,9 +1,18 @@
type float: f32; type Vec2: struct {
x, y: f32;
}
print_string_array :: proc(args: []string) {
args[0] = "";
}
main :: proc() { main :: proc() {
thing :: proc(n: int) -> int, f32 { thing :: proc(n: int) -> int, f32 {
return n*n, 13.37; return n*n, 13.37;
} }
_, _ := 1, 2; thang :: proc(a: int, b: f32, s: string) {
}
} }
+1 -1
View File
@@ -195,7 +195,7 @@ char const *TOKEN_STRINGS[] = {
"_KeywordBegin", "_KeywordBegin",
"type", "type",
"proc", "proc",
"switch", "match",
"break", "break",
"continue", "continue",
"fallthrough", "fallthrough",