blob: 95a00543ad19ae1f80513a4f28c27232723b3a4b [file] [log] [blame]
Damien429d7192013-10-04 19:53:11 +01001#include <unistd.h>
2#include <stdio.h>
3#include <stdint.h>
4#include <string.h>
5#include <assert.h>
6
7#include "misc.h"
8#include "lexer.h"
9#include "machine.h"
10#include "parse.h"
11#include "scope.h"
12#include "runtime.h"
13#include "emit.h"
14
Damien415eb6f2013-10-05 12:19:06 +010015#define EMIT(fun, arg...) (emit_method_table->fun(emit, ##arg))
Damien429d7192013-10-04 19:53:11 +010016
Damien415eb6f2013-10-05 12:19:06 +010017void emit_common_load_id(pass_kind_t pass, scope_t *scope, emit_t *emit, const emit_method_table_t *emit_method_table, qstr qstr___class__, qstr qstr) {
Damien429d7192013-10-04 19:53:11 +010018 id_info_t *id_info = NULL;
19 if (pass == PASS_1) {
20 // name adding/lookup
21 bool added;
22 id_info = scope_find_or_add_id(scope, qstr, &added);
23 if (added) {
24 if (strcmp(qstr_str(qstr), "AssertionError") == 0) {
25 id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
26 // TODO how much of a hack is this?
27 } else if (strcmp(qstr_str(qstr), "super") == 0 && scope->kind == SCOPE_FUNCTION) {
28 // special case, super is a global, and also counts as use of __class__
29 id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
30 id_info_t *id_info2 = scope_find_local_in_parent(scope, qstr___class__);
31 if (id_info2 != NULL) {
32 id_info2 = scope_find_or_add_id(scope, qstr___class__, &added);
33 if (added) {
34 id_info2->kind = ID_INFO_KIND_FREE;
35 scope_close_over_in_parents(scope, qstr___class__);
36 }
37 }
38 } else {
39 id_info_t *id_info2 = scope_find_local_in_parent(scope, qstr);
40 if (id_info2 != NULL && (id_info2->kind == ID_INFO_KIND_LOCAL || id_info2->kind == ID_INFO_KIND_CELL || id_info2->kind == ID_INFO_KIND_FREE)) {
41 id_info->kind = ID_INFO_KIND_FREE;
42 scope_close_over_in_parents(scope, qstr);
43 } else {
44 id_info->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
45 }
46 }
47 }
48 } else {
49 id_info = scope_find(scope, qstr);
50 }
51
52 assert(id_info != NULL); // TODO can this ever fail?
53
54 // call the emit backend with the correct code
55 if (id_info == NULL || id_info->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
56 EMIT(load_name, qstr);
57 } else if (id_info->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
58 EMIT(load_global, qstr);
59 } else if (id_info->kind == ID_INFO_KIND_LOCAL) {
60 EMIT(load_fast, qstr, id_info->local_num);
61 } else if (id_info->kind == ID_INFO_KIND_CELL || id_info->kind == ID_INFO_KIND_FREE) {
62 EMIT(load_deref, qstr);
63 } else {
64 assert(0);
65 }
66}
67
Damien415eb6f2013-10-05 12:19:06 +010068static id_info_t *get_id_for_modification(pass_kind_t pass, scope_t *scope, qstr qstr) {
Damien429d7192013-10-04 19:53:11 +010069 id_info_t *id_info = NULL;
70 if (pass == PASS_1) {
71 // name adding/lookup
72 bool added;
73 id_info = scope_find_or_add_id(scope, qstr, &added);
74 if (added) {
75 if (scope->kind == SCOPE_MODULE || scope->kind == SCOPE_CLASS) {
76 id_info->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
77 } else {
78 id_info->kind = ID_INFO_KIND_LOCAL;
79 }
80 } else if (scope->kind >= SCOPE_FUNCTION && scope->kind <= SCOPE_GEN_EXPR && id_info->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
81 // rebind as a local variable
82 id_info->kind = ID_INFO_KIND_LOCAL;
83 }
84 } else {
85 id_info = scope_find(scope, qstr);
86 }
87
88 assert(id_info != NULL); // TODO can this ever fail?
89
90 return id_info;
91}
92
Damien415eb6f2013-10-05 12:19:06 +010093void emit_common_store_id(pass_kind_t pass, scope_t *scope, emit_t *emit, const emit_method_table_t *emit_method_table, qstr qstr) {
Damien429d7192013-10-04 19:53:11 +010094 // create/get the id info
Damien415eb6f2013-10-05 12:19:06 +010095 id_info_t *id = get_id_for_modification(pass, scope, qstr);
Damien429d7192013-10-04 19:53:11 +010096
97 // call the emit backend with the correct code
98 if (id == NULL || id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
99 EMIT(store_name, qstr);
100 } else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
101 EMIT(store_global, qstr);
102 } else if (id->kind == ID_INFO_KIND_LOCAL) {
103 EMIT(store_fast, qstr, id->local_num);
104 } else if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) {
105 EMIT(store_deref, qstr);
106 } else {
107 assert(0);
108 }
109}
110
Damien415eb6f2013-10-05 12:19:06 +0100111void emit_common_delete_id(pass_kind_t pass, scope_t *scope, emit_t *emit, const emit_method_table_t *emit_method_table, qstr qstr) {
Damien429d7192013-10-04 19:53:11 +0100112 // create/get the id info
Damien415eb6f2013-10-05 12:19:06 +0100113 id_info_t *id = get_id_for_modification(pass, scope, qstr);
Damien429d7192013-10-04 19:53:11 +0100114
115 // call the emit backend with the correct code
116 if (id == NULL || id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
117 EMIT(delete_name, qstr);
118 } else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
119 EMIT(delete_global, qstr);
120 } else if (id->kind == ID_INFO_KIND_LOCAL) {
121 EMIT(delete_fast, qstr, id->local_num);
122 } else if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) {
123 EMIT(delete_deref, qstr);
124 } else {
125 assert(0);
126 }
127}