Skip to content

Commit

Permalink
implementation of isset(), unset(), empty() for ArrayAccess objects only
Browse files Browse the repository at this point in the history
  • Loading branch information
mkornaukhov03 committed Nov 1, 2024
1 parent 8df4d7e commit dc2cc92
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 63 deletions.
2 changes: 1 addition & 1 deletion compiler/compiler.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ prepend(KPHP_COMPILER_PIPES_SOURCES pipes/
file-to-tokens.cpp
filter-only-actually-used.cpp
final-check.cpp
fix-chaining-assignment-for-array-access.cpp
fix-array-access.cpp
fix-returns.cpp
gen-tree-postprocess.cpp
generate-virtual-methods.cpp
Expand Down
4 changes: 2 additions & 2 deletions compiler/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
#include "compiler/pipes/file-to-tokens.h"
#include "compiler/pipes/filter-only-actually-used.h"
#include "compiler/pipes/final-check.h"
#include "compiler/pipes/fix-chaining-assignment-for-array-access.h"
#include "compiler/pipes/fix-array-access.h"
#include "compiler/pipes/fix-returns.h"
#include "compiler/pipes/gen-tree-postprocess.h"
#include "compiler/pipes/generate-virtual-methods.h"
Expand Down Expand Up @@ -285,7 +285,7 @@ bool compiler_execute(CompilerSettings *settings) {
>> PassC<CheckClassesPass>{}
>> PassC<CheckConversionsPass>{}
>> PassC<OptimizationPass>{}
>> PassC<FixChainingAssignmentForArrayAccessPass>{}
>> PassC<FixArrayAccessPass>{}
>> PassC<FixReturnsPass>{}
>> PassC<CalcValRefPass>{}
>> PassC<CalcFuncDepPass>{}
Expand Down
143 changes: 143 additions & 0 deletions compiler/pipes/fix-array-access.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Compiler for PHP (aka KPHP)
// Copyright (c) 2024 LLC «V Kontakte»
// Distributed under the GPL v3 License, see LICENSE.notice.txt

#include "compiler/pipes/fix-array-access.h"

#include "auto/compiler/vertex/vertex-types.h"
#include "common/algorithms/contains.h"
#include "compiler/data/class-data.h"
#include "compiler/data/vertex-adaptor.h"
#include "compiler/inferring/primitive-type.h"
#include "compiler/inferring/public.h"
#include <cassert>

static VertexPtr on_set(VertexAdaptor<op_set> set) {
if (set->lhs()->type() != op_func_call) {
return set;
}

auto func_call = set->lhs().try_as<op_func_call>();
if (func_call->auto_inserted) {
if (func_call->func_id->local_name() == "offsetGet") {
auto obj_arg = func_call->args()[0];
const auto *tpe = tinf::get_type(obj_arg); // funny

assert(tpe);
assert(tpe->get_real_ptype() == tp_Class);

auto klass = tpe->class_type();

const auto *method = klass->get_instance_method("offsetSet");

if (!method) {
kphp_error(method, fmt_format("Class {} does not implement offsetSet", klass->name).c_str());
return set;
}

auto sub_val = set->rhs();

auto key = func_call->args()[1];

auto zzz = VertexAdaptor<op_set_with_ret>::create(key, sub_val, obj_arg);
zzz->set_method = method->function;

return zzz;
}
}
return set;
}

static VertexPtr on_unset(VertexAdaptor<op_unset> unset) {
if (auto func_call = unset->expr().try_as<op_func_call>()) {
if (func_call->func_id->name.find("offsetGet") != std::string::npos) {
auto klass = func_call->func_id->class_id;
// TODO assume here that all is good
assert(klass && "bad klass for unset");

const auto *unset_method = klass->get_instance_method("offsetUnset");
assert(unset_method && "bad method for unset");

func_call->str_val = unset_method->global_name();
func_call->func_id = unset_method->function;
return func_call;
}
}

return unset;
}

static VertexPtr on_isset(VertexAdaptor<op_isset> isset) {
if (auto func_call = isset->expr().try_as<op_func_call>()) {
if (func_call->func_id->name.find("offsetGet") != std::string::npos) {
auto klass = func_call->func_id->class_id;
// TODO assume here that all is good
assert(klass && "bad klass for isset");

const auto *isset_method = klass->get_instance_method("offsetExists");
assert(isset_method && "bad method for isset");

func_call->str_val = isset_method->global_name();
func_call->func_id = isset_method->function;
return func_call;
}
}

return isset;
}

static VertexPtr on_empty(VertexAdaptor<op_func_call> empty_call) {
if (auto offset_get_call = empty_call->args()[0].try_as<op_func_call>()) {
if (offset_get_call->func_id->name.find("offsetGet") != std::string::npos) {
auto klass = offset_get_call->func_id->class_id;
// TODO assume here that all is good
assert(klass && "bad klass for isset");

const auto *isset_method = klass->get_instance_method("offsetExists");
assert(isset_method && "bad method for isset");

auto exists_call = offset_get_call.clone();

exists_call->str_val = isset_method->global_name();
exists_call->func_id = isset_method->function;
/*
for empty smth like:
op_log_or
op_log_not
op_func_call f$ClassName$exists
...
op_func_call empty
op_func_call f$ClassName$get
...
*/

// TODO fix locations
auto as_or = VertexAdaptor<op_log_or>::create(VertexAdaptor<op_log_not>::create(exists_call), empty_call);

return as_or;
}
}

return empty_call;
}

// TODO maybe on_enter? Think about it
// on_exit now generates x2 warnings, but may be the only correct way (may be not xD)
VertexPtr FixArrayAccessPass::on_exit_vertex(VertexPtr root) {
if (auto set = root.try_as<op_set>()) {
return on_set(set);
}
if (auto unset = root.try_as<op_unset>()) {
return on_unset(unset);
}
if (auto isset = root.try_as<op_isset>()) {
return on_isset(isset);
}
if (auto func_call = root.try_as<op_func_call>()) {
if (func_call->func_id->is_extern() && func_call->func_id->name == "empty") {
return on_empty(func_call);
}
}

return root;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

#include "compiler/function-pass.h"

class FixChainingAssignmentForArrayAccessPass final : public FunctionPassBase {
class FixArrayAccessPass final : public FunctionPassBase {
public:
std::string get_description() override {
return "Fix chaining assignment for ArrayAccess";
return "Fix functions related to ArrayAccess";
}

VertexPtr on_exit_vertex(VertexPtr root) final;
Expand Down
58 changes: 0 additions & 58 deletions compiler/pipes/fix-chaining-assignment-for-array-access.cpp

This file was deleted.

0 comments on commit dc2cc92

Please sign in to comment.