Skip to content

Commit ed156cd

Browse files
committed
[pjs] Add support of for-loop statements
1 parent 21254bd commit ed156cd

File tree

4 files changed

+162
-4
lines changed

4 files changed

+162
-4
lines changed

src/pjs/expr.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ class Compound : public Expr {
216216
out = std::move(m_exprs);
217217
}
218218

219+
auto expression_count() const -> size_t { return m_exprs.size(); }
220+
auto expression(size_t i) const -> Expr* { return m_exprs[i].get(); }
221+
219222
virtual bool is_argument_list() const override;
220223
virtual bool is_comma_ended() const override { return m_is_comma_ended; }
221224
virtual bool eval(Context &ctx, Value &result) override;

src/pjs/parser.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,8 +1368,37 @@ Stmt* ScriptParser::statement() {
13681368
}
13691369
return locate(switch_case(cond.release(), std::move(cases)), l);
13701370
}
1371+
case Token::ID("for"): {
1372+
read(l);
1373+
bool is_var = false;
1374+
std::unique_ptr<Expr> init, cond, step;
1375+
if (!read(Token::ID("("), TokenExpected)) return nullptr;
1376+
if (read(Token::ID("var"))) is_var = true;
1377+
if (!read(Token::ID(";"))) {
1378+
auto e = expression();
1379+
if (!e) return nullptr;
1380+
init.reset(e);
1381+
}
1382+
if (!read(Token::ID(";"), TokenExpected)) return nullptr;
1383+
if (!read(Token::ID(";"))) {
1384+
auto e = expression();
1385+
if (!e) return nullptr;
1386+
cond.reset(e);
1387+
}
1388+
if (!read(Token::ID(";"), TokenExpected)) return nullptr;
1389+
if (!read(Token::ID(")"))) {
1390+
auto e = expression();
1391+
if (!e) return nullptr;
1392+
step.reset(e);
1393+
}
1394+
if (!read(Token::ID(")"), TokenExpected)) return nullptr;
1395+
auto s = statement();
1396+
if (!s) return nullptr;
1397+
return for_loop(is_var, init.release(), cond.release(), step.release(), s);
1398+
}
13711399
case Token::ID("break"): {
13721400
read(l);
1401+
if (peek_eol() || peek_end()) return locate(flow_break(), l);
13731402
if (auto name = read_identifier()) {
13741403
read_semicolons();
13751404
return locate(flow_break(name.release()), l);

src/pjs/stmt.cpp

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,107 @@ void Switch::dump(std::ostream &out, const std::string &indent) {
452452
}
453453
}
454454

455+
//
456+
// For
457+
//
458+
459+
bool For::declare(Module *module, Scope &scope, Error &error, bool is_lval) {
460+
if (m_is_var && m_init) {
461+
std::vector<Ref<Str>> names;
462+
if (auto assign = m_init->as<expr::Assignment>()) {
463+
auto lvalue = assign->lvalue();
464+
if (auto id = lvalue->as<expr::Identifier>()) {
465+
names.emplace_back(id->name());
466+
} else {
467+
error.tree = lvalue;
468+
error.message = "illegal left-value in assignment";
469+
return false;
470+
}
471+
} else if (auto comp = m_init->as<expr::Compound>()) {
472+
for (size_t i = 0, n = comp->expression_count(); i < n; i++) {
473+
auto expr = comp->expression(i);
474+
if (auto assign = expr->as<expr::Assignment>()) {
475+
auto lvalue = assign->lvalue();
476+
if (auto id = lvalue->as<expr::Identifier>()) {
477+
names.emplace_back(id->name());
478+
} else {
479+
error.tree = lvalue;
480+
error.message = "illegal left-value in assignment";
481+
return false;
482+
}
483+
}
484+
}
485+
}
486+
auto s = scope.parent();
487+
while (!s->is_root()) s = s->parent();
488+
for (const auto &name : names) {
489+
if (Var::is_fiber(name->str())) {
490+
if (!check_reserved(name->str(), error)) return false;
491+
s->declare_fiber_var(name, module);
492+
} else {
493+
s->declare_var(name);
494+
}
495+
}
496+
}
497+
498+
Tree::Scope s(Tree::Scope::LOOP, &scope);
499+
if (m_init && !m_init->declare(module, s, error, false)) return false;
500+
if (m_cond && !m_cond->declare(module, s, error, false)) return false;
501+
if (m_step && !m_step->declare(module, s, error, false)) return false;
502+
if (m_body && !m_body->declare(module, s, error, false)) return false;
503+
504+
return true;
505+
}
506+
507+
void For::resolve(Module *module, Context &ctx, int l, Tree::LegacyImports *imports) {
508+
if (m_init) m_init->resolve(module, ctx, l, imports);
509+
if (m_cond) m_cond->resolve(module, ctx, l, imports);
510+
if (m_step) m_step->resolve(module, ctx, l, imports);
511+
if (m_body) m_body->resolve(module, ctx, l, imports);
512+
}
513+
514+
void For::execute(Context &ctx, Result &result) {
515+
Value val;
516+
if (m_init && !m_init->eval(ctx, val)) return;
517+
for (;;) {
518+
if (m_cond) {
519+
if (!m_cond->eval(ctx, val)) return;
520+
if (!val.to_boolean()) break;
521+
}
522+
if (m_body) {
523+
m_body->execute(ctx, result);
524+
if (!ctx.ok()) return;
525+
if (result.is_break()) {
526+
if (result.label) return;
527+
break;
528+
}
529+
if (result.is_continue()) {
530+
if (m_step && !m_step->eval(ctx, val)) return;
531+
continue;
532+
}
533+
if (!result.is_done()) return;
534+
}
535+
if (m_step && !m_step->eval(ctx, val)) return;
536+
}
537+
result.set_done();
538+
}
539+
540+
bool For::check_reserved(const std::string &name, Error &error) {
541+
if (!Var::is_reserved(name)) return true;
542+
error.tree = this;
543+
error.message = "reserved variable name '" + name + "'";
544+
return false;
545+
}
546+
547+
void For::dump(std::ostream &out, const std::string &indent) {
548+
auto indent2 = indent + " ";
549+
out << indent << "for" << std::endl;
550+
out << indent << " init" << std::endl; if (m_init) m_init->dump(out, indent2);
551+
out << indent << " cond" << std::endl; if (m_cond) m_cond->dump(out, indent2);
552+
out << indent << " step" << std::endl; if (m_step) m_step->dump(out, indent2);
553+
out << indent << " body" << std::endl; if (m_body) m_body->dump(out, indent2);
554+
}
555+
455556
//
456557
// Break
457558
//
@@ -463,7 +564,7 @@ bool Break::declare(Module *module, Scope &scope, Error &error, bool is_lval) {
463564
s = s->parent();
464565
}
465566
} else {
466-
while (s && s->kind() != Tree::Scope::SWITCH) {
567+
while (s && s->kind() != Tree::Scope::SWITCH && s->kind() != Tree::Scope::LOOP) {
467568
s = s->parent();
468569
}
469570
}

src/pjs/stmt.hpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ class Var : public Exportable {
156156
Var(std::vector<std::unique_ptr<Expr>> &&list)
157157
: m_list(std::move(list)) {}
158158

159+
static bool is_fiber(const std::string &name);
160+
static bool is_reserved(const std::string &name);
161+
159162
virtual bool declare(Module *module, Scope &scope, Error &error, bool is_lval) override;
160163
virtual void resolve(Module *module, Context &ctx, int l, Tree::LegacyImports *imports) override;
161164
virtual void execute(Context &ctx, Result &result) override;
@@ -167,9 +170,6 @@ class Var : public Exportable {
167170
std::vector<expr::Assignment*> m_assignments;
168171

169172
bool check_reserved(const std::string &name, Error &error);
170-
171-
static bool is_fiber(const std::string &name);
172-
static bool is_reserved(const std::string &name);
173173
};
174174

175175
//
@@ -232,6 +232,30 @@ class Switch : public Stmt {
232232
std::list<std::pair<std::unique_ptr<Expr>, std::unique_ptr<Stmt>>> m_cases;
233233
};
234234

235+
//
236+
// For
237+
//
238+
239+
class For : public Stmt {
240+
public:
241+
For(bool is_var, Expr *init, Expr *cond, Expr *step, Stmt *body)
242+
: m_is_var(is_var), m_init(init), m_cond(cond), m_step(step), m_body(body) {}
243+
244+
virtual bool declare(Module *module, Scope &scope, Error &error, bool is_lval) override;
245+
virtual void resolve(Module *module, Context &ctx, int l, Tree::LegacyImports *imports) override;
246+
virtual void execute(Context &ctx, Result &result) override;
247+
virtual void dump(std::ostream &out, const std::string &indent) override;
248+
249+
private:
250+
bool m_is_var;
251+
std::unique_ptr<Expr> m_init;
252+
std::unique_ptr<Expr> m_cond;
253+
std::unique_ptr<Expr> m_step;
254+
std::unique_ptr<Stmt> m_body;
255+
256+
bool check_reserved(const std::string &name, Error &error);
257+
};
258+
235259
//
236260
// Break
237261
//
@@ -359,6 +383,7 @@ inline Stmt* var(std::vector<std::unique_ptr<Expr>> &&list) { return new stmt::V
359383
inline Stmt* function(expr::Identifier *name, Expr *expr) { return new stmt::Function(name, expr); }
360384
inline Stmt* if_else(Expr *cond, Stmt *then_clause, Stmt *else_clause = nullptr) { return new stmt::If(cond, then_clause, else_clause); }
361385
inline Stmt* switch_case(Expr *cond, std::list<std::pair<std::unique_ptr<Expr>, std::unique_ptr<Stmt>>> &&cases) { return new stmt::Switch(cond, std::move(cases)); }
386+
inline Stmt* for_loop(bool is_var, Expr *init, Expr *cond, Expr *step, Stmt *body) { return new stmt::For(is_var, init, cond, step, body); }
362387
inline Stmt* try_catch(Stmt *try_clause, Stmt *catch_clause, Stmt *finally_clause, Expr *exception_variable) { return new stmt::Try(try_clause, catch_clause, finally_clause, exception_variable); }
363388
inline Stmt* flow_break() { return new stmt::Break(); }
364389
inline Stmt* flow_break(expr::Identifier *label) { return new stmt::Break(label); }

0 commit comments

Comments
 (0)