Fix anonymous procedures and their dependencies

This commit is contained in:
Ginger Bill
2016-12-21 15:20:33 +00:00
parent d0e1efe622
commit 923b039cf6
11 changed files with 367 additions and 354 deletions
+8 -15
View File
@@ -10,22 +10,15 @@ import (
"utf8.odin";
)
type Byte_Size f64;
const (
_ = iota; // ignore first value by assigning to blank identifier
KB Byte_Size = 1 << (10 * iota);
// Because there is no type or expression, the previous one is used but
// with `iota` incremented by one
MB;
GB;
TB;
PB;
EB;
)
proc main() {
fmt.println("Here");
var x = proc() -> int {
proc print_here() {
fmt.println("Here");
}
print_here();
return 1;
};
fmt.println(x());
}
+1 -1
View File
@@ -112,7 +112,7 @@ proc fmuladd64(a, b, c f64) -> f64 #foreign "llvm.fmuladd.f64"
type Allocator_Mode int;
type Allocator_Mode u8;
const (
ALLOCATOR_ALLOC Allocator_Mode = iota;
ALLOCATOR_FREE;
+137 -137
View File
@@ -1,158 +1,158 @@
#shared_global_scope;
/*
#import "fmt.odin"
__u128_mod :: proc(a, b: u128) -> u128 #link_name "__umodti3" {
_, r := __u128_quo_mod(a, b)
return r
}
// import "fmt.odin";
__u128_quo :: proc(a, b: u128) -> u128 #link_name "__udivti3" {
n, _ := __u128_quo_mod(a, b)
return n
}
// proc __u128_mod(a, b: u128) -> u128 #link_name "__umodti3" {
// var _, r := __u128_quo_mod(a, b)
// return r
// }
__i128_mod :: proc(a, b: i128) -> i128 #link_name "__modti3" {
_, r := __i128_quo_mod(a, b)
return r
}
// proc __u128_quo(a, b: u128) -> u128 #link_name "__udivti3" {
// var n, _ := __u128_quo_mod(a, b)
// return n
// }
__i128_quo :: proc(a, b: i128) -> i128 #link_name "__divti3" {
n, _ := __i128_quo_mod(a, b)
return n
}
// proc __i128_mod(a, b: i128) -> i128 #link_name "__modti3" {
// var _, r := __i128_quo_mod(a, b)
// return r
// }
__i128_quo_mod :: proc(a, b: i128) -> (i128, i128) #link_name "__divmodti4" {
s := b >> 127
b = (b ~ s) - s
s = a >> 127
a = (a ~ s) - s
// proc __i128_quo(a, b: i128) -> i128 #link_name "__divti3" {
// var n, _ := __i128_quo_mod(a, b)
// return n
// }
n, r := __u128_quo_mod(a as u128, b as u128)
return (n as i128 ~ s) - s, (r as i128 ~ s) - s
}
// proc __i128_quo_mod(a, b: i128) -> (i128, i128) #link_name "__divmodti4" {
// var s := b >> 127
// b = (b ~ s) - s
// s = a >> 127
// a = (a ~ s) - s
// var n, r := __u128_quo_mod(a as u128, b as u128)
// return (n as i128 ~ s) - s, (r as i128 ~ s) - s
// }
__u128_quo_mod :: proc(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" {
clz :: proc(x: u64) -> u64 {
clz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64"
return clz_u64(x, false)
}
ctz :: proc(x: u64) -> u64 {
ctz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64"
return ctz_u64(x, false)
}
// proc __u128_quo_mod(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" {
// proc clz(x: u64) -> u64 {
// proc clz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64"
// return clz_u64(x, false)
// }
// proc ctz(x: u64) -> u64 {
// proc ctz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64"
// return ctz_u64(x, false)
// }
u128_lo_hi :: raw_union {
all: u128
using _lohi: struct {lo, hi: u64;}
}
// u128_lo_hi :: raw_union {
// all: u128
// using _lohi: struct {lo, hi: u64;}
// }
n, d, q, r: u128_lo_hi
sr: u64
// n, d, q, r: u128_lo_hi
// sr: u64
n.all = a
d.all = b
// n.all = a
// d.all = b
if n.hi == 0 {
if d.hi == 0 {
return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128
}
return 0, n.lo as u128
}
if d.lo == 0 {
if d.hi == 0 {
return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128
}
if n.lo == 0 {
r.hi = n.hi % d.hi
r.lo = 0
return (n.hi / d.hi) as u128, r.all
}
if (d.hi & (d.hi-1)) == 0 {
r.lo = n.lo
r.hi = n.hi & (d.hi-1)
return (n.hi >> ctz(d.hi)) as u128, r.all
}
// if n.hi == 0 {
// if d.hi == 0 {
// return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128
// }
// return 0, n.lo as u128
// }
// if d.lo == 0 {
// if d.hi == 0 {
// return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128
// }
// if n.lo == 0 {
// r.hi = n.hi % d.hi
// r.lo = 0
// return (n.hi / d.hi) as u128, r.all
// }
// if (d.hi & (d.hi-1)) == 0 {
// r.lo = n.lo
// r.hi = n.hi & (d.hi-1)
// return (n.hi >> ctz(d.hi)) as u128, r.all
// }
sr = clz(d.hi) - clz(n.hi)
if sr > 64 - 2 {
return 0, n.all
}
sr++
q.lo = 0
q.hi = n.lo << (64-sr)
r.hi = n.hi >> sr
r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
} else {
if d.hi == 0 {
if (d.lo & (d.lo - 1)) == 0 {
rem := (n.lo % (d.lo - 1)) as u128
if d.lo == 1 {
return n.all, rem
}
sr = ctz(d.lo)
q.hi = n.hi >> sr
q.lo = (n.hi << (64-sr)) | (n.lo >> sr)
return q.all, rem
}
// sr = clz(d.hi) - clz(n.hi)
// if sr > 64 - 2 {
// return 0, n.all
// }
// sr++
// q.lo = 0
// q.hi = n.lo << (64-sr)
// r.hi = n.hi >> sr
// r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
// } else {
// if d.hi == 0 {
// if (d.lo & (d.lo - 1)) == 0 {
// var rem := (n.lo % (d.lo - 1)) as u128
// if d.lo == 1 {
// return n.all, rem
// }
// sr = ctz(d.lo)
// q.hi = n.hi >> sr
// q.lo = (n.hi << (64-sr)) | (n.lo >> sr)
// return q.all, rem
// }
sr = 1 + 64 + clz(d.lo) - clz(n.hi)
// sr = 1 + 64 + clz(d.lo) - clz(n.hi)
q.all = n.all << (128-sr)
r.all = n.all >> sr
if sr == 64 {
q.lo = 0
q.hi = n.lo
r.hi = 0
r.lo = n.hi
} else if sr < 64 {
q.lo = 0
q.hi = n.lo << (64-sr)
r.hi = n.hi >> sr
r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
} else {
q.lo = n.lo << (128-sr)
q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64))
r.hi = 0
r.lo = n.hi >> (sr-64)
}
} else {
sr = clz(d.hi) - clz(n.hi)
if sr > 64-1 {
return 0, n.all
}
sr++
q.lo = 0
q.hi = n.lo << (64-sr)
r.all = n.all >> sr
if sr < 64 {
r.hi = n.hi >> sr
r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
} else {
r.hi = 0
r.lo = n.hi
}
}
}
// q.all = n.all << (128-sr)
// r.all = n.all >> sr
// if sr == 64 {
// q.lo = 0
// q.hi = n.lo
// r.hi = 0
// r.lo = n.hi
// } else if sr < 64 {
// q.lo = 0
// q.hi = n.lo << (64-sr)
// r.hi = n.hi >> sr
// r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
// } else {
// q.lo = n.lo << (128-sr)
// q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64))
// r.hi = 0
// r.lo = n.hi >> (sr-64)
// }
// } else {
// sr = clz(d.hi) - clz(n.hi)
// if sr > 64-1 {
// return 0, n.all
// }
// sr++
// q.lo = 0
// q.hi = n.lo << (64-sr)
// r.all = n.all >> sr
// if sr < 64 {
// r.hi = n.hi >> sr
// r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
// } else {
// r.hi = 0
// r.lo = n.hi
// }
// }
// }
carry: u64
for ; sr > 0; sr-- {
r.hi = (r.hi << 1) | (r.lo >> (64-1))
r.lo = (r.lo << 1) | (r.hi >> (64-1))
q.hi = (q.hi << 1) | (q.lo >> (64-1))
q.lo = (q.lo << 1) | carry
// carry: u64
// for ; sr > 0; sr-- {
// r.hi = (r.hi << 1) | (r.lo >> (64-1))
// r.lo = (r.lo << 1) | (r.hi >> (64-1))
// q.hi = (q.hi << 1) | (q.lo >> (64-1))
// q.lo = (q.lo << 1) | carry
carry = 0
if r.all >= d.all {
r.all -= d.all
carry = 1
}
}
// carry = 0
// if r.all >= d.all {
// r.all -= d.all
// carry = 1
// }
// }
// q.all = (q.all << 1) | (carry as u128)
// return q.all, r.all
// }
q.all = (q.all << 1) | (carry as u128)
return q.all, r.all
}
*/
+1 -2
View File
@@ -93,8 +93,7 @@ const (
FILE_STANDARD_ERROR;
FILE_STANDARD_COUNT;
);
)
// NOTE(bill): Uses startup to initialize it
var (
__std_files = [FILE_STANDARD_COUNT]File{
+8 -6
View File
@@ -8,11 +8,11 @@ const (
SURROGATE_MIN = 0xd800;
SURROGATE_MAX = 0xdfff;
);
)
type Accept_Range struct {
lo, hi u8;
};
}
var (
accept_ranges = [5]Accept_Range{
@@ -99,10 +99,12 @@ proc decode_rune(s string) -> (rune, int) {
return RUNE_ERROR, 1;
}
const MASK_X = 0b00111111;
const MASK_2 = 0b00011111;
const MASK_3 = 0b00001111;
const MASK_4 = 0b00000111;
const (
MASK_X = 0b00111111;
MASK_2 = 0b00011111;
MASK_3 = 0b00001111;
MASK_4 = 0b00000111;
)
if size == 2 {
return (b0&MASK_2) as rune <<6 | (b1&MASK_X) as rune, 2;
+3 -1
View File
@@ -1142,6 +1142,8 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
for_array(iota, gd->specs) {
AstNode *spec = gd->specs.e[iota];
switch (spec->kind) {
case_ast_node(bd, BadDecl, decl);
case_end;
case_ast_node(is, ImportSpec, spec);
if (!parent_scope->is_file) {
// NOTE(bill): _Should_ be caught by the parser
@@ -1347,7 +1349,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
}
// NOTE(bill): Do not add other imported entities
add_entity(c, parent_scope, NULL, e);
if (!id->is_load) { // `#import`ed entities don't get exported
if (id->keyword == Token_import) { // `#import`ed entities don't get exported
HashKey key = hash_string(e->token.string);
map_entity_set(&parent_scope->implicit, key, e);
}
+63 -63
View File
@@ -87,6 +87,8 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
for_array(iota, gd->specs) {
AstNode *spec = gd->specs.e[iota];
switch (spec->kind) {
case_ast_node(bd, BadDecl, spec);
case_end;
case_ast_node(vs, ValueSpec, spec);
switch (vs->keyword) {
case Token_var:
@@ -453,15 +455,15 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
fields[field_index++] = make_entity_type_name(c->allocator, c->context.scope, empty_token, NULL);
for_array(decl_index, decls) {
AstNode *decl = decls.e[decl_index];
if (decl->kind != AstNode_Parameter) {
if (decl->kind != AstNode_Field) {
continue;
}
ast_node(p, Parameter, decl);
Type *base_type = check_type_extra(c, p->type, NULL);
ast_node(f, Field, decl);
Type *base_type = check_type_extra(c, f->type, NULL);
for_array(name_index, p->names) {
AstNode *name = p->names.e[name_index];
for_array(name_index, f->names) {
AstNode *name = f->names.e[name_index];
if (!ast_node_expect(name, AstNode_Ident)) {
continue;
}
@@ -493,28 +495,28 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
isize field_index = 0;
for_array(decl_index, decls) {
AstNode *decl = decls.e[decl_index];
if (decl->kind != AstNode_Parameter) {
if (decl->kind != AstNode_Field) {
continue;
}
ast_node(param, Parameter, decl);
ast_node(f, Field, decl);
Type *type = check_type_extra(c, param->type, NULL);
Type *type = check_type_extra(c, f->type, NULL);
if (param->is_using) {
if (param->names.count > 1) {
error_node(param->names.e[0], "Cannot apply `using` to more than one of the same type");
if (f->is_using) {
if (f->names.count > 1) {
error_node(f->names.e[0], "Cannot apply `using` to more than one of the same type");
}
}
for_array(name_index, param->names) {
AstNode *name = param->names.e[name_index];
for_array(name_index, f->names) {
AstNode *name = f->names.e[name_index];
if (!ast_node_expect(name, AstNode_Ident)) {
continue;
}
Token name_token = name->Ident;
Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, param->is_using, cast(i32)field_index);
Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, f->is_using, cast(i32)field_index);
e->identifier = name;
if (str_eq(name_token.string, str_lit("_"))) {
fields[field_index++] = e;
@@ -533,19 +535,19 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
}
if (param->is_using) {
if (f->is_using) {
Type *t = base_type(type_deref(type));
if (!is_type_struct(t) && !is_type_raw_union(t) &&
param->names.count >= 1 &&
param->names.e[0]->kind == AstNode_Ident) {
Token name_token = param->names.e[0]->Ident;
f->names.count >= 1 &&
f->names.e[0]->kind == AstNode_Ident) {
Token name_token = f->names.e[0]->Ident;
if (is_type_indexable(t)) {
bool ok = true;
for_array(emi, entity_map.entries) {
Entity *e = entity_map.entries.e[emi].value;
if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) {
if (is_type_indexable(e->type)) {
if (e->identifier != param->names.e[0]) {
if (e->identifier != f->names.e[0]) {
ok = false;
using_index_expr = e;
break;
@@ -613,8 +615,8 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
for_array(field_index, st->fields) {
AstNode *field = st->fields.e[field_index];
switch (field->kind) {
case_ast_node(p, Parameter, field);
field_count += p->names.count;
case_ast_node(f, Field, field);
field_count += f->names.count;
case_end;
}
}
@@ -662,8 +664,8 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
for_array(field_index, ut->fields) {
AstNode *field = ut->fields.e[field_index];
switch (field->kind) {
case_ast_node(p, Parameter, field);
field_count += p->names.count;
case_ast_node(f, Field, field);
field_count += f->names.count;
case_end;
}
}
@@ -685,8 +687,8 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
for_array(field_index, ut->fields) {
AstNode *field = ut->fields.e[field_index];
switch (field->kind) {
case_ast_node(p, Parameter, field);
field_count += p->names.count;
case_ast_node(f, Field, field);
field_count += f->names.count;
case_end;
}
}
@@ -699,51 +701,47 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
union_type->Record.field_count = field_count;
}
GB_COMPARE_PROC(cmp_enum_order) {
// Rule:
// Biggest to smallest alignment
// if same alignment: biggest to smallest size
// if same size: order by source order
Entity *x = *(Entity **)a;
Entity *y = *(Entity **)b;
GB_ASSERT(x != NULL);
GB_ASSERT(y != NULL);
GB_ASSERT(x->kind == Entity_Constant);
GB_ASSERT(y->kind == Entity_Constant);
GB_ASSERT(x->Constant.value.kind == ExactValue_Integer);
GB_ASSERT(y->Constant.value.kind == ExactValue_Integer);
i64 i = x->Constant.value.value_integer;
i64 j = y->Constant.value.value_integer;
// GB_COMPARE_PROC(cmp_enum_order) {
// // Rule:
// // Biggest to smallest alignment
// // if same alignment: biggest to smallest size
// // if same size: order by source order
// Entity *x = *(Entity **)a;
// Entity *y = *(Entity **)b;
// GB_ASSERT(x != NULL);
// GB_ASSERT(y != NULL);
// GB_ASSERT(x->kind == Entity_Constant);
// GB_ASSERT(y->kind == Entity_Constant);
// GB_ASSERT(x->Constant.value.kind == ExactValue_Integer);
// GB_ASSERT(y->Constant.value.kind == ExactValue_Integer);
// i64 i = x->Constant.value.value_integer;
// i64 j = y->Constant.value.value_integer;
return i < j ? -1 : i > j;
}
// return i < j ? -1 : i > j;
// }
Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_variadic_) {
if (params.count == 0) {
return NULL;
}
bool is_variadic = false;
Type *tuple = make_type_tuple(c->allocator);
isize variable_count = 0;
for_array(i, params) {
AstNode *field = params.e[i];
if (!ast_node_expect(field, AstNode_Parameter)) {
continue;
if (ast_node_expect(field, AstNode_Field)) {
ast_node(f, Field, field);
variable_count += f->names.count;
}
ast_node(p, Parameter, field);
variable_count += p->names.count;
}
bool is_variadic = false;
Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count);
isize variable_index = 0;
for_array(i, params) {
if (params.e[i]->kind != AstNode_Parameter) {
if (params.e[i]->kind != AstNode_Field) {
continue;
}
ast_node(p, Parameter, params.e[i]);
ast_node(p, Field, params.e[i]);
AstNode *type_expr = p->type;
if (type_expr) {
if (type_expr->kind == AstNode_Ellipsis) {
@@ -777,6 +775,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
end->type = make_type_slice(c->allocator, end->type);
}
Type *tuple = make_type_tuple(c->allocator);
tuple->Tuple.variables = variables;
tuple->Tuple.variable_count = variable_count;
@@ -3687,21 +3686,21 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
case_end;
case_ast_node(pl, ProcLit, node);
check_open_scope(c, pl->type);
c->context.decl = make_declaration_info(c->allocator, c->context.scope);
Type *proc_type = check_type(c, pl->type);
if (proc_type != NULL) {
check_proc_body(c, empty_token, c->context.decl, proc_type, pl->body);
o->mode = Addressing_Value;
o->type = proc_type;
check_close_scope(c);
} else {
if (proc_type == NULL) {
gbString str = expr_to_string(node);
error_node(node, "Invalid procedure literal `%s`", str);
gb_string_free(str);
check_close_scope(c);
goto error;
}
check_open_scope(c, pl->type);
check_proc_body(c, empty_token, c->context.decl, proc_type, pl->body);
check_close_scope(c);
o->mode = Addressing_Value;
o->type = proc_type;
case_end;
case_ast_node(cl, CompoundLit, node);
@@ -4240,7 +4239,7 @@ gbString write_expr_to_string(gbString str, AstNode *node);
gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) {
for_array(i, params) {
ast_node(p, Parameter, params.e[i]);
ast_node(p, Field, params.e[i]);
if (i > 0) {
str = gb_string_appendc(str, sep);
}
@@ -4390,14 +4389,15 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
str = write_expr_to_string(str, vt->elem);
case_end;
case_ast_node(p, Parameter, node);
case_ast_node(p, Field, node);
if (p->is_using) {
str = gb_string_appendc(str, "using ");
}
for_array(i, p->names) {
AstNode *name = p->names.e[i];
if (i > 0)
if (i > 0) {
str = gb_string_appendc(str, ", ");
}
str = write_expr_to_string(str, name);
}
+2
View File
@@ -1088,6 +1088,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
for_array(spec_index, gd->specs) {
AstNode *spec = gd->specs.e[spec_index];
switch (spec->kind) {
case_ast_node(bd, BadDecl, spec);
case_end;
case_ast_node(vs, ValueSpec, spec);
switch (vs->keyword) {
case Token_let:
+18 -9
View File
@@ -59,17 +59,26 @@ i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
return exit_code;
}
void print_usage_line(i32 indent, char *fmt, ...) {
while (indent --> 0) {
gb_printf_err("\t");
}
va_list va;
va_start(va, fmt);
gb_printf_err_va(fmt, va);
va_end(va);
gb_printf_err("\n");
}
void usage(char *argv0) {
gb_printf_err("%s is a tool for managing Odin source code\n", argv0);
gb_printf_err("Usage:");
gb_printf_err("\n\t%s command [arguments]\n", argv0);
gb_printf_err("Commands:");
gb_printf_err("\n\tbuild compile .odin file");
gb_printf_err("\n\tbuild_dll compile .odin file as dll");
gb_printf_err("\n\trun compile and run .odin file");
gb_printf_err("\n\tversion print Odin version");
gb_printf_err("\n\n");
print_usage_line(0, "%s is a tool for managing Odin source code", argv0);
print_usage_line(0, "Usage:");
print_usage_line(1, "%s command [arguments]", argv0);
print_usage_line(0, "Commands:");
print_usage_line(1, "build compile .odin file as executable");
print_usage_line(1, "build_dll compile .odin file as dll");
print_usage_line(1, "run compile and run .odin file");
print_usage_line(1, "version print version");
}
int main(int argc, char **argv) {
+116 -88
View File
@@ -57,6 +57,7 @@ typedef struct Parser {
Array(ImportedFile) imports;
gbAtomic32 import_index;
isize total_token_count;
isize total_line_count;
gbMutex mutex;
} Parser;
@@ -176,52 +177,56 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
AstNodeArray results; \
}) \
AST_NODE_KIND(ForStmt, "for statement", struct { \
Token token; \
AstNode *init, *cond, *post; \
Token token; \
AstNode *init; \
AstNode *cond; \
AstNode *post; \
AstNode *body; \
}) \
AST_NODE_KIND(CaseClause, "case clause", struct { \
Token token; \
AstNodeArray list, stmts; \
Token token; \
AstNodeArray list; \
AstNodeArray stmts; \
}) \
AST_NODE_KIND(MatchStmt, "match statement", struct { \
Token token; \
AstNode *init, *tag; \
Token token; \
AstNode *init; \
AstNode *tag; \
AstNode *body; \
}) \
AST_NODE_KIND(TypeMatchStmt, "type match statement", struct { \
Token token; \
AstNode *tag, *var; \
AstNode *body; \
Token token; \
AstNode *tag; \
AstNode *var; \
AstNode *body; \
}) \
AST_NODE_KIND(DeferStmt, "defer statement", struct { Token token; AstNode *stmt; }) \
AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; }) \
AST_NODE_KIND(UsingStmt, "using statement", struct { Token token; AstNode *node; }) \
AST_NODE_KIND(AsmOperand, "assembly operand", struct { \
Token string; \
Token string; \
AstNode *operand; \
}) \
AST_NODE_KIND(AsmStmt, "assembly statement", struct { \
Token token; \
bool is_volatile; \
Token open, close; \
Token code_string; \
AstNode *output_list; \
AstNode *input_list; \
Token token; \
bool is_volatile; \
Token open, close; \
Token code_string; \
AstNode *output_list; \
AstNode *input_list; \
AstNode *clobber_list; \
isize output_count, input_count, clobber_count; \
}) \
AST_NODE_KIND(PushAllocator, "push_allocator statement", struct { \
Token token; \
Token token; \
AstNode *expr; \
AstNode *body; \
}) \
AST_NODE_KIND(PushContext, "push_context statement", struct { \
Token token; \
Token token; \
AstNode *expr; \
AstNode *body; \
}) \
\
AST_NODE_KIND(_ComplexStmtEnd, "", i32) \
AST_NODE_KIND(_StmtEnd, "", i32) \
AST_NODE_KIND(_SpecBegin, "", i32) \
@@ -237,12 +242,12 @@ AST_NODE_KIND(_SpecBegin, "", i32) \
AstNode *note; \
}) \
AST_NODE_KIND(ImportSpec, "import specification", struct { \
Token relpath; \
String fullpath; \
Token import_name; \
bool is_load; \
AstNode *cond; \
AstNode *note; \
TokenKind keyword; \
Token relpath; \
String fullpath; \
Token import_name; \
AstNode *cond; \
AstNode *note; \
}) \
AST_NODE_KIND(_SpecEnd, "", i32) \
AST_NODE_KIND(_DeclBegin, "", i32) \
@@ -270,12 +275,12 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
bool is_system; \
}) \
AST_NODE_KIND(_DeclEnd, "", i32) \
AST_NODE_KIND(_TypeBegin, "", i32) \
AST_NODE_KIND(Parameter, "parameter", struct { \
AstNodeArray names; \
AstNode *type; \
bool is_using; \
AST_NODE_KIND(Field, "field", struct { \
AstNodeArray names; \
AstNode * type; \
bool is_using; \
}) \
AST_NODE_KIND(_TypeBegin, "", i32) \
AST_NODE_KIND(ProcType, "procedure type", struct { \
Token token; \
AstNodeArray params; \
@@ -477,11 +482,11 @@ Token ast_node_token(AstNode *node) {
case AstNode_ImportSpec:
return node->ImportSpec.relpath;
case AstNode_Parameter: {
if (node->Parameter.names.count > 0) {
return ast_node_token(node->Parameter.names.e[0]);
case AstNode_Field: {
if (node->Field.names.count > 0) {
return ast_node_token(node->Field.names.e[0]);
} else {
return ast_node_token(node->Parameter.type);
return ast_node_token(node->Field.type);
}
}
case AstNode_ProcType:
@@ -898,11 +903,11 @@ AstNode *make_bad_decl(AstFile *f, Token begin, Token end) {
return result;
}
AstNode *make_parameter(AstFile *f, AstNodeArray names, AstNode *type, bool is_using) {
AstNode *result = make_node(f, AstNode_Parameter);
result->Parameter.names = names;
result->Parameter.type = type;
result->Parameter.is_using = is_using;
AstNode *make_field(AstFile *f, AstNodeArray names, AstNode *type, bool is_using) {
AstNode *result = make_node(f, AstNode_Field);
result->Field.names = names;
result->Field.type = type;
result->Field.is_using = is_using;
return result;
}
@@ -1030,12 +1035,12 @@ AstNode *make_type_spec(AstFile *f, AstNode *name, AstNode *type) {
}
AstNode *make_import_spec(AstFile *f, Token relpath, Token import_name, AstNode *cond, bool is_load) {
AstNode *make_import_spec(AstFile *f, TokenKind keyword, Token relpath, Token import_name, AstNode *cond) {
AstNode *result = make_node(f, AstNode_ImportSpec);
result->ImportSpec.keyword = keyword;
result->ImportSpec.relpath = relpath;
result->ImportSpec.import_name = import_name;
result->ImportSpec.cond = cond;
result->ImportSpec.is_load = is_load;
return result;
}
@@ -1057,6 +1062,21 @@ bool next_token(AstFile *f) {
return false;
}
TokenKind look_ahead_token_kind(AstFile *f, isize amount) {
GB_ASSERT(amount > 0);
TokenKind kind = Token_Invalid;
isize index = f->curr_token_index;
while (amount > 0) {
index++;
kind = f->tokens.e[index].kind;
if (kind != Token_Comment) {
amount--;
}
}
return kind;
}
Token expect_token(AstFile *f, TokenKind kind) {
Token prev = f->curr_token;
if (prev.kind != kind) {
@@ -1859,17 +1879,17 @@ AstNodeArray parse_identfier_list(AstFile *f) {
}
void parse_check_name_list_for_reserves(AstFile *f, AstNodeArray names) {
// for_array(i, names) {
// AstNode *name = names.e[i];
// if (name->kind == AstNode_Ident) {
// String n = name->Ident.string;
// // NOTE(bill): Check for reserved identifiers
// if (str_eq(n, str_lit("context"))) {
// syntax_error_node(name, "`context` is a reserved identifier");
// break;
// }
// }
// }
for_array(i, names) {
AstNode *name = names.e[i];
if (name->kind == AstNode_Ident) {
String n = name->Ident.string;
// NOTE(bill): Check for reserved identifiers
if (str_eq(n, str_lit("context"))) {
syntax_error_node(name, "`context` is a reserved identifier");
break;
}
}
}
}
AstNode *parse_type_attempt(AstFile *f) {
@@ -1998,7 +2018,7 @@ PARSE_SPEC_PROC(parse_import_spec) {
syntax_error(import_name, "You cannot use `import` within a procedure. This must be done at the file scope");
spec = make_bad_decl(f, import_name, file_path);
} else {
spec = make_import_spec(f, file_path, import_name, cond, false);
spec = make_import_spec(f, Token_import, file_path, import_name, cond);
}
return spec;
}
@@ -2017,7 +2037,7 @@ PARSE_SPEC_PROC(parse_include_spec) {
syntax_error(import_name, "You cannot use `include` within a procedure. This must be done at the file scope");
spec = make_bad_decl(f, import_name, file_path);
} else {
spec = make_import_spec(f, file_path, import_name, cond, true);
spec = make_import_spec(f, Token_include, file_path, import_name, cond);
}
return spec;
}
@@ -2060,11 +2080,7 @@ AstNode *parse_simple_stmt(AstFile *f) {
return parse_decl(f);
}
isize lhs_count = 0, rhs_count = 0;
AstNodeArray lhs = parse_lhs_expr_list(f);
AstNode *statement = NULL;
Token token = f->curr_token;
switch (token.kind) {
case Token_Eq:
@@ -2096,7 +2112,7 @@ AstNode *parse_simple_stmt(AstFile *f) {
} break;
}
if (lhs_count > 1) {
if (lhs.count > 1) {
syntax_error(token, "Expected 1 expression");
return make_bad_stmt(f, token, f->curr_token);
}
@@ -2109,9 +2125,9 @@ AstNode *parse_simple_stmt(AstFile *f) {
syntax_error(f->curr_token, "You cannot use a simple statement in the file scope");
return make_bad_stmt(f, f->curr_token, f->curr_token);
}
statement = make_inc_dec_stmt(f, token, lhs.e[0]);
AstNode *stmt = make_inc_dec_stmt(f, token, lhs.e[0]);
next_token(f);
return statement;
return stmt;
}
return make_expr_stmt(f, lhs.e[0]);
@@ -2155,7 +2171,7 @@ AstNode *parse_proc_type(AstFile *f) {
}
AstNodeArray parse_parameter_list(AstFile *f, isize *name_count_, bool allow_using, TokenKind separator, TokenKind follow) {
AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using, TokenKind separator, TokenKind follow) {
AstNodeArray params = make_ast_node_array(f);
isize name_count = 0;
@@ -2210,10 +2226,9 @@ AstNodeArray parse_parameter_list(AstFile *f, isize *name_count_, bool allow_usi
syntax_error(f->curr_token, "Expected a type for this parameter declaration");
}
AstNode *param = make_parameter(f, names, type, is_using);
AstNode *param = make_field(f, names, type, is_using);
array_add(&params, param);
if (separator == Token_Semicolon) {
expect_semicolon(f, param);
} else {
@@ -2229,8 +2244,8 @@ AstNodeArray parse_parameter_list(AstFile *f, isize *name_count_, bool allow_usi
}
AstNodeArray parse_record_params(AstFile *f, isize *field_count_, bool allow_using, String context) {
return parse_parameter_list(f, field_count_, allow_using, Token_Semicolon, Token_CloseBrace);
AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, bool allow_using, String context) {
return parse_field_list(f, field_count_, allow_using, Token_Semicolon, Token_CloseBrace);
}
AstNode *parse_identifier_or_type(AstFile *f) {
@@ -2295,7 +2310,7 @@ AstNode *parse_identifier_or_type(AstFile *f) {
bool is_packed = false;
bool is_ordered = false;
while (allow_token(f, Token_Hash)) {
Token tag = expect_token_after(f, Token_Ident, "`#`");
Token tag = expect_token_after(f, Token_Ident, "#");
if (str_eq(tag.string, str_lit("packed"))) {
if (is_packed) {
syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string));
@@ -2315,9 +2330,9 @@ AstNode *parse_identifier_or_type(AstFile *f) {
syntax_error(token, "`#ordered` is not needed with `#packed` which implies ordering");
}
Token open = expect_token_after(f, Token_OpenBrace, "`struct`");
Token open = expect_token_after(f, Token_OpenBrace, "struct");
isize decl_count = 0;
AstNodeArray decls = parse_record_params(f, &decl_count, true, str_lit("struct"));
AstNodeArray decls = parse_record_fields(f, &decl_count, true, str_lit("struct"));
Token close = expect_token(f, Token_CloseBrace);
return make_struct_type(f, token, decls, decl_count, is_packed, is_ordered);
@@ -2325,9 +2340,9 @@ AstNode *parse_identifier_or_type(AstFile *f) {
case Token_union: {
Token token = expect_token(f, Token_union);
Token open = expect_token_after(f, Token_OpenBrace, "`union`");
Token open = expect_token_after(f, Token_OpenBrace, "union");
isize decl_count = 0;
AstNodeArray decls = parse_record_params(f, &decl_count, false, str_lit("union"));
AstNodeArray decls = parse_record_fields(f, &decl_count, false, str_lit("union"));
Token close = expect_token(f, Token_CloseBrace);
return make_union_type(f, token, decls, decl_count);
@@ -2335,9 +2350,9 @@ AstNode *parse_identifier_or_type(AstFile *f) {
case Token_raw_union: {
Token token = expect_token(f, Token_raw_union);
Token open = expect_token_after(f, Token_OpenBrace, "`raw_union`");
Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
isize decl_count = 0;
AstNodeArray decls = parse_record_params(f, &decl_count, true, str_lit("raw_union"));
AstNodeArray decls = parse_record_fields(f, &decl_count, true, str_lit("raw_union"));
Token close = expect_token(f, Token_CloseBrace);
return make_raw_union_type(f, token, decls, decl_count);
@@ -2391,7 +2406,7 @@ void parse_proc_signature(AstFile *f,
AstNodeArray *params,
AstNodeArray *results) {
expect_token(f, Token_OpenParen);
*params = parse_parameter_list(f, NULL, true, Token_Comma, Token_CloseParen);
*params = parse_field_list(f, NULL, true, Token_Comma, Token_CloseParen);
expect_token_after(f, Token_CloseParen, "parameter list");
*results = parse_results(f);
}
@@ -2409,8 +2424,14 @@ AstNode *parse_body(AstFile *f) {
AstNode *parse_proc_decl(AstFile *f) {
Token proc_token = expect_token(f, Token_proc);
if (look_ahead_token_kind(f, 1) == Token_OpenParen) {
// NOTE(bill): It's an anonymous procedure
// NOTE(bill): This look-ahead technically makes the grammar LALR(2)
// but is that a problem in practice?
return make_expr_stmt(f, parse_expr(f, true));
}
Token proc_token = expect_token(f, Token_proc);
AstNode *name = parse_identifier(f);
AstNodeArray params = {0};
@@ -2426,19 +2447,18 @@ AstNode *parse_proc_decl(AstFile *f) {
parse_proc_tags(f, &tags, &foreign_name, &link_name);
AstNode *curr_proc = f->curr_proc;
f->curr_proc = proc_type;
if (f->curr_token.kind == Token_OpenBrace) {
if ((tags & ProcTag_foreign) != 0) {
syntax_error_node(name, "A procedure tagged as `#foreign` cannot have a body");
syntax_error(proc_token, "A procedure tagged as `#foreign` cannot have a body");
}
AstNode *curr_proc = f->curr_proc;
f->curr_proc = proc_type;
body = parse_body(f);
f->curr_proc = curr_proc;
} else if ((tags & ProcTag_foreign) == 0) {
syntax_error_node(name, "Only a procedure tagged as `#foreign` cannot have a body");
syntax_error(proc_token, "Only a procedure tagged as `#foreign` cannot have a body");
}
f->curr_proc = curr_proc;
return make_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name);
}
@@ -2958,6 +2978,11 @@ AstNodeArray parse_stmt_list(AstFile *f) {
AstNode *stmt = parse_stmt(f);
if (stmt && stmt->kind != AstNode_EmptyStmt) {
array_add(&list, stmt);
if (stmt->kind == AstNode_ExprStmt &&
stmt->ExprStmt.expr != NULL &&
stmt->ExprStmt.expr->kind == AstNode_ProcLit) {
syntax_error_node(stmt, "Procedure literal evaluated but not used");
}
}
}
@@ -3031,7 +3056,7 @@ void destroy_parser(Parser *p) {
for_array(i, p->files) {
destroy_ast_file(&p->files.e[i]);
}
#if 1
#if 0
for_array(i, p->imports) {
// gb_free(heap_allocator(), p->imports[i].text);
}
@@ -3093,21 +3118,23 @@ bool is_import_path_valid(String path) {
u8 *start = path.text;
u8 *end = path.text + path.len;
u8 *curr = start;
Rune r = -1;
while (curr < end) {
isize width = 1;
r = curr[0];
Rune r = curr[0];
if (r >= 0x80) {
width = gb_utf8_decode(curr, end-curr, &r);
if (r == GB_RUNE_INVALID && width == 1)
if (r == GB_RUNE_INVALID && width == 1) {
return false;
else if (r == GB_RUNE_BOM && curr-start > 0)
}
else if (r == GB_RUNE_BOM && curr-start > 0) {
return false;
}
}
for (isize i = 0; i < gb_count_of(illegal_import_runes); i++) {
if (r == illegal_import_runes[i])
if (r == illegal_import_runes[i]) {
return false;
}
}
curr += width;
@@ -3135,7 +3162,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray
String file_str = is->relpath.string;
if (!is_import_path_valid(file_str)) {
if (is->is_load) {
if (is->keyword == Token_include) {
syntax_error_node(node, "Invalid #include path: `%.*s`", LIT(file_str));
} else {
syntax_error_node(node, "Invalid #import path: `%.*s`", LIT(file_str));
@@ -3266,6 +3293,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
gb_mutex_lock(&p->mutex);
file.id = p->files.count;
array_add(&p->files, file);
p->total_line_count += file.tokenizer.line_count;
gb_mutex_unlock(&p->mutex);
}
}
+10 -32
View File
@@ -2607,6 +2607,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
} else if (e != NULL && e->kind == Entity_Variable) {
return ssa_addr_load(proc, ssa_build_addr(proc, expr));
}
GB_PANIC("nil value for expression from identifier: %.*s", LIT(i->string));
return NULL;
case_end;
@@ -2714,9 +2715,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
proc->module, NULL, type, pl->type, pl->body, name);
value->Proc.tags = pl->tags;
value->Proc.parent = proc;
array_add(&proc->children, &value->Proc);
ssa_build_proc(value, proc);
array_add(&proc->module->procs_to_generate, value);
return value;
case_end;
@@ -2971,32 +2973,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
} break;
#if 0
case BuiltinProc_ptr_offset: {
ssa_emit_comment(proc, str_lit("ptr_offset"));
ssaValue *ptr = ssa_build_expr(proc, ce->args.e[0]);
ssaValue *offset = ssa_build_expr(proc, ce->args.e[1]);
return ssa_emit_ptr_offset(proc, ptr, offset);
} break;
case BuiltinProc_ptr_sub: {
ssa_emit_comment(proc, str_lit("ptr_sub"));
ssaValue *ptr_a = ssa_build_expr(proc, ce->args.e[0]);
ssaValue *ptr_b = ssa_build_expr(proc, ce->args.e[1]);
Type *ptr_type = base_type(ssa_type(ptr_a));
GB_ASSERT(ptr_type->kind == Type_Pointer);
isize elem_size = type_size_of(proc->module->sizes, proc->module->allocator, ptr_type->Pointer.elem);
ssaValue *v = ssa_emit_arith(proc, Token_Sub, ptr_a, ptr_b, t_int);
if (elem_size > 1) {
ssaValue *ez = ssa_make_const_int(proc->module->allocator, elem_size);
v = ssa_emit_arith(proc, Token_Quo, v, ez, t_int);
}
return v;
} break;
#endif
case BuiltinProc_slice_ptr: {
ssa_emit_comment(proc, str_lit("slice_ptr"));
ssaValue *ptr = ssa_build_expr(proc, ce->args.e[0]);
@@ -3095,9 +3071,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
}
}
// NOTE(bill): Regular call
ssaValue *value = ssa_build_expr(proc, ce->proc);
GB_ASSERT(value != NULL);
Type *proc_type_ = base_type(ssa_type(value));
GB_ASSERT(proc_type_->kind == Type_Proc);
TypeProc *type = &proc_type_->Proc;
@@ -3269,7 +3245,7 @@ ssaAddr ssa_build_addr_from_entity(ssaProcedure *proc, Entity *e, AstNode *expr)
}
if (v == NULL) {
GB_PANIC("Unknown value: %s, entity: %p %.*s\n", expr_to_string(expr), e, LIT(entity_strings[e->kind]));
GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind]));
}
return ssa_make_addr(v, expr);
@@ -3293,7 +3269,9 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
case_ast_node(se, SelectorExpr, expr);
ssa_emit_comment(proc, str_lit("SelectorExpr"));
String selector = unparen_expr(se->selector)->Ident.string;
AstNode *sel = unparen_expr(se->selector);
GB_ASSERT(sel->kind == AstNode_Ident);
String selector = sel->Ident.string;
Type *type = base_type(type_of_expr(proc->module->info, se->expr));
if (type == t_invalid) {
@@ -4958,7 +4936,7 @@ void ssa_gen_tree(ssaGen *s) {
array_add(&global_variables, var);
}
map_ssa_value_set(&m->values, hash_pointer(e), g);
ssa_module_add_value(m, e, g);
map_ssa_value_set(&m->members, hash_string(name), g);
} break;
@@ -4978,7 +4956,7 @@ void ssa_gen_tree(ssaGen *s) {
ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
p->Proc.tags = pd->tags;
map_ssa_value_set(&m->values, hash_pointer(e), p);
ssa_module_add_value(m, e, p);
HashKey hash_name = hash_string(name);
if (map_ssa_value_get(&m->members, hash_name) == NULL) {
map_ssa_value_set(&m->members, hash_name, p);