-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcrb_exec.c
More file actions
156 lines (139 loc) · 3.88 KB
/
crb_exec.c
File metadata and controls
156 lines (139 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "crb_exec.h"
#include "crb_eval_exp.h"
#include "util/crb_util.h"
#include <stdio.h>
#include <assert.h>
enum {
CRB_CONTROL_TYPE_NORMAL,
CRB_CONTROL_TYPE_CONTINUE,
CRB_CONTROL_TYPE_BREAK,
CRB_CONTROL_TYPE_RETURN
};
struct crb_block_result {
struct crb_value value;
int control_type;
};
static struct crb_block_result exec_statement(
struct crb_interpreter *itp,
struct crb_statement *statement);
static struct crb_block_result exec_block(
struct crb_interpreter *itp,
const struct crb_block *block);
static struct crb_block_result exec_statement(
struct crb_interpreter *itp,
struct crb_statement *statement)
{
struct crb_block_result result = { .value = CRB_NULL };
switch (statement->type) {
case CRB_EXP_STATEMENT:
result.value = crb_eval_exp(itp, statement->u.exp_statement.expression);
break;
case CRB_DEFINE_STATEMENT:
{
struct crb_stack *exps = &statement->u.define_statement.expressions;
struct crb_expression *exp = NULL;
struct crb_assign_expression *assign = NULL;
for (int i = 0; i < exps->count; ++i) {
exp = ((struct crb_expression **)exps->data)[i];
assign = &exp->u.assign_expression;
struct crb_value v = crb_eval_exp(itp, assign->exprand);
int r = crb_scope_push_variable(itp->top_scope, assign->variable, v);
assert(!r);
}
}
break;
case CRB_IF_STATEMENT:
{
struct crb_if_statement *if_statement = &statement->u.if_statement;
struct crb_value condition_result = crb_eval_exp(itp, if_statement->condition);
if (!crb_is_boolean_value(condition_result)) {
assert(0);
}
if (crb_is_true(condition_result)) {
result = exec_block(itp, &if_statement->main_block);
break;
}
switch (if_statement->else_branch.type) {
case CRB_ELSE_BRANCH:
result = exec_block(itp, &if_statement->else_branch.u.else_block);
break;
case CRB_ELSE_IF_BRANCH:
result = exec_statement(itp, if_statement->else_branch.u.else_if_statement);
break;
default:
break;
}
}
break;
case CRB_FOR_STATEMENT:
{
struct crb_for_statement *for_statement = &statement->u.for_statement;
if (for_statement->init != NULL) {
crb_eval_exp(itp, for_statement->init);
}
while (1) {
if (for_statement->condition != NULL) {
struct crb_value v = crb_eval_exp(itp, for_statement->condition);
if (!crb_is_boolean_value(v)) {
assert(0);
}
if (crb_is_false(v)) {
break;
}
}
result = exec_block(itp, &for_statement->block);
if (result.control_type == CRB_CONTROL_TYPE_BREAK
|| result.control_type == CRB_CONTROL_TYPE_RETURN) {
break;
}
if (for_statement->post != NULL) {
crb_eval_exp(itp, for_statement->post);
}
}
if (result.control_type != CRB_CONTROL_TYPE_RETURN) {
//handled by for-statement, reset to normal
result.control_type = CRB_CONTROL_TYPE_NORMAL;
}
}
break;
case CRB_CONTINUE_STATEMENT:
result.control_type = CRB_CONTROL_TYPE_CONTINUE;
break;
case CRB_BREAK_STATEMENT:
result.control_type = CRB_CONTROL_TYPE_BREAK;
break;
case CRB_RETURN_STATEMENT:
result.control_type = CRB_CONTROL_TYPE_RETURN;
struct crb_expression *exp = statement->u.return_statement.expression;
if (exp != NULL) {
result.value = crb_eval_exp(itp, exp);
}
break;
default:
break;
}
return result;
}
static struct crb_block_result exec_block(
struct crb_interpreter *itp,
const struct crb_block *block)
{
struct crb_block_result result = {0};
struct crb_statement *statement = NULL;
for (int i = 0; i < block->statements.count; ++i) {
statement = ((struct crb_statement **)block->statements.data)[i];
result = exec_statement(itp, statement);
if (result.control_type != CRB_CONTROL_TYPE_NORMAL) {
break;
}
}
return result;
}
struct crb_value crb_exec_block(
struct crb_interpreter *itp,
const struct crb_block *block)
{
crb_assert(itp != NULL && block != NULL && block->statements.count > 0,
crb_do_nothing);
return exec_block(itp, block).value;
}