Skip to content

Commit 17e5d78

Browse files
authored
index expression (#55)
1 parent e4851aa commit 17e5d78

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

include/evaluator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ class Evaluator {
5959
std::shared_ptr<object::Environment> extend_function_env(
6060
const object::Function* fn,
6161
std::vector<std::shared_ptr<object::Object>>& args) const;
62+
std::shared_ptr<object::Object> eval_index_expression(
63+
const object::Object* array,
64+
const object::Object* index) const;
6265
private:
6366
bool is_truthy(const object::Object* obj) const;
6467

src/evaluator.cc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,23 @@ std::shared_ptr<object::Object> Evaluator::eval(
4141
if (typeid(*node) == typeid(ast::Program)) {
4242
auto n = node->cast<ast::Program>();
4343
return eval_program(n->statments(), env);
44+
4445
} else if (typeid(*node) == typeid(ast::ExpressionStatment)) {
4546
auto n = node->cast<ast::ExpressionStatment>();
4647
return eval(n->expression(), env);
48+
4749
} else if (typeid(*node) == typeid(ast::BlockStatment)) {
4850
auto n = node->cast<ast::BlockStatment>();
4951
return eval_statments(n->statments(), env);
52+
5053
} else if (typeid(*node) == typeid(ast::ReturnStatment)) {
5154
auto n = node->cast<ast::ReturnStatment>();
5255
auto return_val = eval(n->expression(), env);
5356
if (is_error(return_val.get())) {
5457
return return_val;
5558
}
5659
return std::make_shared<object::ReturnValue>(return_val);
60+
5761
} else if (typeid(*node) == typeid(ast::LetStatment)) {
5862
auto n = node->cast<ast::LetStatment>();
5963
auto val = eval(n->expression(), env);
@@ -62,65 +66,117 @@ std::shared_ptr<object::Object> Evaluator::eval(
6266
}
6367

6468
env->set(n->identifier()->value(), val);
69+
6570
} else if (typeid(*node) == typeid(ast::IntegerLiteral)) {
6671
auto n = node->cast<ast::IntegerLiteral>();
6772
return std::shared_ptr<object::Integer>(
6873
new object::Integer(n->value()));
74+
6975
} else if (typeid(*node) == typeid(ast::BooleanLiteral)) {
7076
auto n = node->cast<ast::BooleanLiteral>();
7177
return n->value() ? _true : _false;
78+
7279
} else if (typeid(*node) == typeid(ast::StringLiteral)) {
7380
auto n = node->cast<ast::StringLiteral>();
7481
return std::make_shared<object::String>(n->value());
82+
7583
} else if (typeid(*node) == typeid(ast::ArrayLiteral)) {
7684
auto n = node->cast<ast::ArrayLiteral>();
7785
auto elems = eval_expressions(n->elements(), env);
7886
if (!elems.empty() && is_error(elems[0].get())) {
7987
return elems[0];
8088
}
8189
return std::make_shared<object::Array>(elems);
90+
8291
} else if (typeid(*node) == typeid(ast::PrefixExpression)) {
8392
auto n = node->cast<ast::PrefixExpression>();
8493
auto right = eval(n->right(), env);
8594
if (is_error(right.get())) {
8695
return right;
8796
}
8897
return eval_prefix_expression(n->op(), right.get(), env);
98+
8999
} else if (typeid(*node) == typeid(ast::InfixExpression)) {
90100
auto n = node->cast<ast::InfixExpression>();
91101
auto left = eval(n->left(), env);
92102
if (is_error(left.get())) {
93103
return left;
94104
}
105+
95106
auto right = eval(n->right(), env);
96107
if (is_error(right.get())) {
97108
return right;
98109
}
110+
99111
return eval_infix_expression(n->op(), left.get(), right.get(), env);
112+
100113
} else if (typeid(*node) == typeid(ast::IfExpression)) {
101114
return eval_if_expression(node->cast<ast::IfExpression>(), env);
115+
102116
} else if (typeid(*node) == typeid(ast::Identifier)) {
103117
return eval_identifier(node->cast<ast::Identifier>(), env);
118+
104119
} else if (typeid(*node) == typeid(ast::FunctionLiteral)) {
105120
auto n = node->cast<ast::FunctionLiteral>();
106121
return std::make_shared<object::Function>(
107122
n->parameters(), n->body(), env);
123+
108124
} else if (typeid(*node) == typeid(ast::CallExpression)) {
109125
auto n = node->cast<ast::CallExpression>();
110126
auto function = eval(n->function(), env);
111127
if (is_error(function.get())) {
112128
return function;
113129
}
130+
114131
auto args = eval_expressions(n->arguments(), env);
115132
if (!args.empty() && is_error(args[0].get())) {
116133
return args[0];
117134
}
135+
118136
return apply_function(function.get(), args);
137+
138+
} else if (typeid(*node) == typeid(ast::IndexExpression)) {
139+
auto n = node->cast<ast::IndexExpression>();
140+
auto array = eval(n->left(), env);
141+
if (is_error(array.get())) {
142+
return array;
143+
}
144+
145+
auto index = eval(n->index(), env);
146+
if (is_error(index.get())) {
147+
return index;
148+
}
149+
150+
return eval_index_expression(array.get(), index.get());
151+
119152
}
120153

121154
return nullptr;
122155
}
123156

157+
std::shared_ptr<object::Object> Evaluator::eval_index_expression(
158+
const object::Object* array,
159+
const object::Object* index) const {
160+
if (typeid(*array) == typeid(object::Array)
161+
&& typeid(*index) == typeid(object::Integer)) {
162+
auto a = array->cast<object::Array>();
163+
auto i = index->cast<object::Integer>();
164+
165+
auto& elems = a->elements();
166+
auto idx = i->value();
167+
168+
if (idx < 0) {
169+
idx += elems.size();
170+
}
171+
172+
if (idx < 0 || idx >= elems.size()) {
173+
return _null;
174+
}
175+
176+
return elems[idx];
177+
}
178+
return new_error("index operator not supported: `{}`", array->type());
179+
}
124180

125181
std::shared_ptr<object::Object> Evaluator::apply_function(
126182
const object::Object* fn,

unitest/evaluator_test.cc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,4 +356,36 @@ TEST(Evaluator, TestArrayLiteral) {
356356
test_integer_object(array_obj->elements()[2].get(), 9);
357357
}
358358

359+
TEST(Evaluator, TestIndexExpression) {
360+
std::vector<std::tuple<std::string, std::any>> tests = {
361+
{"[1, 2, 3][0]", 1},
362+
{"[1, 2, 3][1]", 2},
363+
{"[1, 2, 3][2]", 3},
364+
{"let i = 0; [1][i];", 1},
365+
{"[1, 2, 3][1 + 1];", 3},
366+
{"let myArray = [1, 2, 3]; myArray[2];", 3},
367+
{"let myArray = [1, 2, 3]; myArray[0] + myArray[1] + myArray[2];", 6},
368+
{"let myArray = [1, 2, 3]; let i = myArray[0]; myArray[i]", 2},
369+
{"[1, 2, 3][3]", nullptr},
370+
{"[1, 2, 3][-1]", 3},
371+
};
372+
373+
Evaluator evaluator;
374+
375+
for (auto& test : tests) {
376+
auto& input = std::get<0>(test);
377+
auto& expect = std::get<1>(test);
378+
379+
auto object = evaluator.eval(input);
380+
381+
if (expect.type() == typeid(int)) {
382+
test_integer_object(object.get(), std::any_cast<int>(expect));
383+
} else if (expect.type() == typeid(std::nullptr_t)) {
384+
test_null_object(object.get());
385+
} else {
386+
std::cout << object->inspect() << std::endl;
387+
}
388+
}
389+
}
390+
359391
}

0 commit comments

Comments
 (0)