Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added errors for unimplemented features #981

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions compiler/code-gen/vertex-compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,12 @@ void compile_throw(VertexAdaptor<op_throw> root, CodeGenerator &W) {
}

void compile_try(VertexAdaptor<op_try> root, CodeGenerator &W) {
bool is_exist_finally = root->finally_cmd_ref()->type() != Operation::op_empty;
if (is_exist_finally) {
stage::set_location(root->finally_cmd()->location);
kphp_error(0, "`finally` construct is not implemented");
}

auto move_exception = [&](ClassPtr caught_class, VertexAdaptor<op_var> dst) {
if (caught_class->name == "Throwable") {
W << dst << " = std::move(CurException);" << NL;
Expand Down
6 changes: 6 additions & 0 deletions compiler/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ std::string debugTokenName(TokenType t) {
{tok_array, "tok_array"},
{tok_tuple, "tok_tuple"},
{tok_shape, "tok_shape"},
{tok_iterable, "tok_iterable"},
{tok_as, "tok_as"},
{tok_case, "tok_case"},
{tok_switch, "tok_switch"},
Expand All @@ -73,6 +74,8 @@ std::string debugTokenName(TokenType t) {
{tok_do, "tok_do"},
{tok_eval, "tok_eval"},
{tok_return, "tok_return"},
{tok_yield, "tok_yield"},
{tok_from, "tok_from"},
{tok_list, "tok_list"},
{tok_include, "tok_include"},
{tok_include_once, "tok_include_once"},
Expand All @@ -85,6 +88,7 @@ std::string debugTokenName(TokenType t) {
{tok_static, "tok_static"},
{tok_final, "tok_final"},
{tok_abstract, "tok_abstract"},
{tok_readonly, "tok_readonly"},
{tok_goto, "tok_goto"},
{tok_isset, "tok_isset"},
{tok_declare, "tok_declare"},
Expand Down Expand Up @@ -176,6 +180,7 @@ std::string debugTokenName(TokenType t) {
{tok_conv_array, "tok_conv_array"},
{tok_conv_object, "tok_conv_object"},
{tok_conv_bool, "tok_conv_bool"},
{tok_conv_iterable, "tok_conv_iterable"},
{tok_false, "tok_false"},
{tok_true, "tok_true"},
{tok_define, "tok_define"},
Expand All @@ -185,6 +190,7 @@ std::string debugTokenName(TokenType t) {
{tok_new, "tok_new"},
{tok_try, "tok_try"},
{tok_catch, "tok_catch"},
{tok_finally, "tok_finally"},
{tok_public, "tok_public"},
{tok_private, "tok_private"},
{tok_protected, "tok_protected"},
Expand Down
120 changes: 105 additions & 15 deletions compiler/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,14 +534,25 @@ VertexPtr GenTree::get_expr_top(bool was_arrow, const PhpDocComment *phpdoc) {
break;
}
case tok_varg: {
bool good_prefix = cur != tokens.begin() && vk::any_of_equal(std::prev(cur)->type(), tok_comma, tok_oppar, tok_opbrk);
auto prev_tok_type = std::prev(cur)->type();
bool good_prefix = cur != tokens.begin() && vk::any_of_equal(prev_tok_type, tok_comma, tok_oppar, tok_opbrk);
CE (!kphp_error(good_prefix, "It's not allowed using `...` in this place"));

next_cur();
auto next_tok_type = cur->type(); // next relative to tok_varg
res = get_expression();
// since the argument for the spread operator can be anything,
// we do not check the type of the expression here
res = VertexAdaptor<op_varg>::create(res).set_location(res);
if (res) {
res = VertexAdaptor<op_varg>::create(res).set_location(res);
} else {
if (prev_tok_type == tok_oppar && next_tok_type == tok_clpar) { // f(...) - only this syntax is possible
res = VertexAdaptor<op_ellipsis>::create();
kphp_error(0, "First class callable syntax is not supported");
} else {
kphp_error(0, "Сan not parse first class callable syntax");
}
}
break;
}
case tok_str:
Expand Down Expand Up @@ -625,6 +636,12 @@ VertexPtr GenTree::get_expr_top(bool was_arrow, const PhpDocComment *phpdoc) {
return_flag = was_arrow;
break;
}
case tok_yield: {
next_cur();
res = get_yield();
kphp_error(false, "yield isn't supported");
break;
}
case tok_static:
next_cur();
res = get_lambda_function(phpdoc, FunctionModifiers::static_lambda());
Expand Down Expand Up @@ -689,6 +706,14 @@ VertexPtr GenTree::get_expr_top(bool was_arrow, const PhpDocComment *phpdoc) {
res = VertexAdaptor<op_clone>::create(get_expr_top(false)).set_location(auto_location());
break;
}
case tok_throw: {
auto location = auto_location();
next_cur();
auto throw_expr = get_expression();
CE (!kphp_error(throw_expr, "Empty expression in throw"));
res = VertexAdaptor<op_throw>::create(throw_expr).set_location(location);
break;
}
default:
return {};
}
Expand Down Expand Up @@ -1009,7 +1034,8 @@ VertexAdaptor<op_return> GenTree::get_return() {
auto location = auto_location();
next_cur();
skip_phpdoc_tokens();
VertexPtr return_val = get_expression();
VertexPtr return_val;
return_val = get_expression();
if (!return_val && cur_function->is_main_function()) {
return_val = VertexAdaptor<op_null>::create();
}
Expand All @@ -1024,10 +1050,33 @@ VertexAdaptor<op_return> GenTree::get_return() {
}
ret = VertexAdaptor<op_return>::create(return_val);
}

CE (expect(tok_semicolon, "';'"));
return ret.set_location(location);
}

VertexAdaptor<op_yield> GenTree::get_yield() {
auto location = auto_location();
next_cur();

bool is_yield_from = test_expect(tok_from); // processing the construction "yield from ..."
if (is_yield_from) {
next_cur();
}

VertexPtr yield_val = get_expression();
if (!yield_val) {
yield_val = VertexAdaptor<op_null>::create();
}

VertexAdaptor<op_yield> yield;
if (is_yield_from) {
yield = VertexAdaptor<op_yield_from>::create(yield_val);
} else {
yield = VertexAdaptor<op_yield>::create(yield_val);
}
return yield.set_location(location);
}

template<Operation Op>
VertexAdaptor<Op> GenTree::get_break_or_continue() {
Expand Down Expand Up @@ -1669,15 +1718,21 @@ void GenTree::parse_extends_implements() {

VertexPtr GenTree::get_class(const PhpDocComment *phpdoc, ClassType class_type) {
ClassModifiers modifiers;
if (test_expect(tok_abstract)) {
modifiers.set_abstract();
} else if (test_expect(tok_final)) {
modifiers.set_final();
}

if (modifiers.is_abstract() || modifiers.is_final()) {
while (vk::any_of_equal(cur->type(), tok_final, tok_abstract, tok_readonly)) {
if (test_expect(tok_abstract)) {
modifiers.set_abstract();
} else if (test_expect(tok_final)) {
modifiers.set_final();
} else if (test_expect(tok_readonly)) {
cur_class->is_immutable = true;
kphp_error(0, "`readonly` classes is not supported");
}
next_cur();
CE(!kphp_error(cur->type() == tok_class, "`class` epxtected after abstract/final keyword"));
}

if (modifiers.is_abstract() || modifiers.is_final() || cur_class->is_immutable) {
CE(!kphp_error(cur->type() == tok_class, "`class` epxtected after abstract/final/readonly keyword"));
}

CE(vk::any_of_equal(cur->type(), tok_class, tok_interface, tok_trait));
Expand Down Expand Up @@ -1720,7 +1775,7 @@ VertexPtr GenTree::get_class(const PhpDocComment *phpdoc, ClassType class_type)
cur_class->file_id = processing_file;
cur_class->set_name_and_src_name(full_class_name); // with full namespaces and slashes
cur_class->phpdoc = phpdoc;
cur_class->is_immutable = phpdoc && phpdoc->has_tag(PhpDocType::kphp_immutable_class);
cur_class->is_immutable = cur_class->is_immutable || (phpdoc && phpdoc->has_tag(PhpDocType::kphp_immutable_class));
cur_class->location_line_num = line_num;

bool registered = G->register_class(cur_class);
Expand Down Expand Up @@ -1991,10 +2046,19 @@ GenericsInstantiationPhpComment *GenTree::parse_php_commentTs(vk::string_view st
}

VertexAdaptor<op_catch> GenTree::get_catch() {
auto location = auto_location();

CE (expect(tok_catch, "'catch'"));
CE (expect(tok_oppar, "'('"));
auto exception_class = cur->str_val;
CE (expect(tok_func_name, "type that implements Throwable"));
bool is_multiple_exception_types = false;
while (cur->type() == tok_or) { // processing catching multiple exception types (ExceptionType1 | ExceptionType2 | ...)
expect(tok_or, "union types");
CE (expect(tok_func_name, "type that implements Throwable"));
is_multiple_exception_types = true;
}
kphp_error(!is_multiple_exception_types, "Catching multiple exception types isn't supported");
auto exception_var_name = get_expression();
CE (!kphp_error(exception_var_name, "Cannot parse catch"));
CE (!kphp_error(exception_var_name->type() == op_var, "Expected variable name in 'catch'"));
Expand All @@ -2003,12 +2067,24 @@ VertexAdaptor<op_catch> GenTree::get_catch() {
auto catch_body = get_statement();
CE (!kphp_error(catch_body, "Cannot parse catch block"));

auto catch_op = VertexAdaptor<op_catch>::create(exception_var_name.as<op_var>(), VertexUtil::embrace(catch_body));
auto catch_op = VertexAdaptor<op_catch>::create(exception_var_name.as<op_var>(), VertexUtil::embrace(catch_body)).set_location(location);
catch_op->type_declaration = resolve_uses(cur_function, static_cast<std::string>(exception_class));

return catch_op;
}

VertexAdaptor<op_finally> GenTree::get_finally() {
auto location = auto_location();

CE (expect(tok_finally, "'finally'"));
auto finally_body = get_statement();
CE (!kphp_error(finally_body, "Cannot parse finally block"));

auto finally_op = VertexAdaptor<op_finally>::create(finally_body.as<op_seq>()).set_location(location);

return finally_op;
}

VertexPtr GenTree::get_statement(const PhpDocComment *phpdoc) {
TokenType type = cur->type();

Expand All @@ -2024,6 +2100,11 @@ VertexPtr GenTree::get_statement(const PhpDocComment *phpdoc) {
}
case tok_return:
return get_return();
case tok_yield: {
auto res = get_yield();
CE(expect(tok_semicolon, "';'"));
return res;
}
case tok_continue:
return get_break_or_continue<op_continue>();
case tok_break:
Expand Down Expand Up @@ -2064,6 +2145,9 @@ VertexPtr GenTree::get_statement(const PhpDocComment *phpdoc) {
case tok_public:
case tok_private:
if (std::next(cur, 1)->type() == tok_const) {
if (cur_class->class_type == ClassType::trait) {
kphp_error(0, "`const` member is not supported in trait");
}
next_cur();

auto access = AccessModifiers::public_;
Expand All @@ -2075,11 +2159,12 @@ VertexPtr GenTree::get_statement(const PhpDocComment *phpdoc) {
return get_const_after_explicit_access_modifier(access);
}
// fall through
case tok_readonly:
case tok_final:
case tok_abstract:
if (cur_function->type == FunctionData::func_class_holder) {
return get_class_member(phpdoc);
} else if (vk::any_of_equal(cur->type(), tok_final, tok_abstract)) {
} else if (vk::any_of_equal(cur->type(), tok_final, tok_abstract, tok_readonly)) {
return get_class(phpdoc, ClassType::klass);
}
next_cur();
Expand Down Expand Up @@ -2179,12 +2264,17 @@ VertexPtr GenTree::get_statement(const PhpDocComment *phpdoc) {
while (test_expect(tok_catch)) {
auto catch_op = get_catch();
CE (!kphp_error(catch_op, "Cannot parse catch statement"));
catch_op.set_location(location);
catch_list.emplace_back(catch_op);
}
CE (!kphp_error(!catch_list.empty(), "Expected at least 1 'catch' statement"));

return VertexAdaptor<op_try>::create(VertexUtil::embrace(try_body), std::move(catch_list)).set_location(location);
VertexPtr finally_op = VertexAdaptor<op_empty>::create();
if (test_expect(tok_finally)) {
finally_op = get_finally();
CE(!kphp_error(finally_op, "Cannot parse finally statement"));
}

return VertexAdaptor<op_try>::create(VertexUtil::embrace(try_body), std::move(catch_list), finally_op).set_location(location);
}
case tok_inline_html: {
auto html_code = VertexAdaptor<op_string>::create().set_location(auto_location());
Expand Down
3 changes: 2 additions & 1 deletion compiler/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class GenTree {
VertexPtr get_expression();
VertexPtr get_statement(const PhpDocComment *phpdoc = nullptr);
VertexAdaptor<op_catch> get_catch();
VertexAdaptor<op_finally> get_finally();
void get_instance_var_list(const PhpDocComment *phpdoc, FieldModifiers modifiers, const TypeHint *type_hint);
void get_traits_uses();
void get_use();
Expand All @@ -92,6 +93,7 @@ class GenTree {
template<Operation Op, Operation EmptyOp, class FuncT, class ResultType = typename vk::function_traits<FuncT>::ResultType>
VertexAdaptor<op_seq> get_multi_call(FuncT &&f, bool parenthesis = false);
VertexAdaptor<op_return> get_return();
VertexAdaptor<op_yield> get_yield();
template<Operation Op>
VertexAdaptor<Op> get_break_or_continue();
VertexAdaptor<op_foreach> get_foreach();
Expand Down Expand Up @@ -152,4 +154,3 @@ class GenTree {
FunctionPtr cur_function; // = functions_stack.back()
SrcFilePtr processing_file;
};

13 changes: 11 additions & 2 deletions compiler/inferring/expr-node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,13 @@ void ExprNodeRecalc::recalc_c2php(VertexAdaptor<op_ffi_c2php_conv> conv) {
}

void ExprNodeRecalc::recalc_ternary(VertexAdaptor<op_ternary> ternary) {
set_lca(ternary->true_expr());
set_lca(ternary->false_expr());
auto true_expr = ternary->true_expr();
auto false_expr = ternary->false_expr();
if (true_expr->type() == op_throw || false_expr->type() == op_throw) { // while throw expression isn't implemented
kphp_error(false, TermStringFormat::paint("throw expression ", TermStringFormat::blue) + "isn't supported");
}
set_lca(true_expr);
set_lca(false_expr);
}

void ExprNodeRecalc::recalc_func_call(VertexAdaptor<op_func_call> call) {
Expand Down Expand Up @@ -492,6 +497,10 @@ void ExprNodeRecalc::recalc_expr(VertexPtr expr) {
recalc_ptype<tp_bool>();
break;

case op_throw:
recalc_ptype<tp_void>();
break;

default:
break;
}
Expand Down
1 change: 1 addition & 0 deletions compiler/inferring/primitive-type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const char *ptype_name(PrimitiveType id) {
case tp_int: return "int";
case tp_float: return "float";
case tp_array: return "array";
case tp_iterable: return "iterable";
case tp_string: return "string";
case tp_tmp_string: return "tmp_string";
case tp_mixed: return "mixed";
Expand Down
1 change: 1 addition & 0 deletions compiler/inferring/primitive-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ enum PrimitiveType {
tp_string,
tp_tmp_string,
tp_array,
tp_iterable,
tp_mixed,
tp_void,
tp_tuple,
Expand Down
4 changes: 4 additions & 0 deletions compiler/inferring/type-data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ PrimitiveType TypeData::get_real_ptype() const {
if (p == tp_any && (or_null_flag() || or_false_flag())) {
return tp_bool;
}
if (p == tp_iterable) {
kphp_error(false, "Iterable type isn't supported");
}
return p;
}

Expand Down Expand Up @@ -781,6 +784,7 @@ int type_strlen(const TypeData *type) {
return STRLEN_INT;
case tp_float:
return STRLEN_FLOAT;
case tp_iterable: // STRLEN_ARRAY_(array), because STRLEN_CLASS(Traversable) not implemented (will be subject to change)
case tp_array:
case tp_tuple:
case tp_shape:
Expand Down
Loading