Skip to content

Commit

Permalink
Add node/scope stack tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
jbboehr committed Feb 10, 2024
1 parent 0cea0cc commit 47f201b
Show file tree
Hide file tree
Showing 12 changed files with 257 additions and 93 deletions.
3 changes: 2 additions & 1 deletion config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ if test "$PHP_VYRTUE" != "no"; then

PHP_VYRTUE_ADD_SOURCES([
src/compile.c
src/context.c
src/extension.c
src/preprocess.c
src/process.c
src/visitor.c
])

Expand Down
24 changes: 13 additions & 11 deletions php_vyrtue.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ extern zend_module_entry vyrtue_module_entry;
ZEND_TSRMLS_CACHE_EXTERN();
#endif

struct vyrtue_preprocess_context;
typedef zend_ast *(*vyrtue_ast_callback)(zend_ast *ast, struct vyrtue_preprocess_context *ctx);
struct vyrtue_context;
typedef zend_ast *(*vyrtue_ast_callback)(zend_ast *ast, struct vyrtue_context *ctx);

ZEND_BEGIN_MODULE_GLOBALS(vyrtue)
HashTable attribute_visitors;
Expand All @@ -84,6 +84,14 @@ ZEND_END_MODULE_GLOBALS(vyrtue)

ZEND_EXTERN_MODULE_GLOBALS(vyrtue);

VYRTUE_PUBLIC
VYRTUE_ATTR_NONNULL_ALL
zend_ast *vyrtue_context_node_stack_top(struct vyrtue_context *ctx);

VYRTUE_PUBLIC
VYRTUE_ATTR_NONNULL_ALL
zend_ast *vyrtue_context_scope_stack_top(struct vyrtue_context *ctx);

VYRTUE_PUBLIC
zend_never_inline void vyrtue_ast_process(zend_ast *ast);

Expand Down Expand Up @@ -118,13 +126,7 @@ VYRTUE_ATTR_RETURNS_NONNULL
VYRTUE_ATTR_WARN_UNUSED_RESULT
const struct vyrtue_visitor_array *vyrtue_get_kind_visitors(enum _zend_ast_kind kind);

#endif /* PHP_VYRTUE_H */
// backwards compatibility
#define vyrtue_preprocess_context vyrtue_context

/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: fdm=marker
* vim: et sw=4 ts=4
*/
#endif /* PHP_VYRTUE_H */
21 changes: 10 additions & 11 deletions src/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,12 @@

#include "Zend/zend_API.h"
#include "Zend/zend_compile.h"
#include "Zend/zend_exceptions.h"
#include "main/php.h"
#include "main/php_streams.h"
#include "ext/standard/php_var.h"

#include "php_vyrtue.h"
#include "context.h"
#include "compile.h"
#include "private.h"

static void str_dtor(zval *zv)
{
Expand All @@ -46,7 +45,7 @@ static void str_dtor(zval *zv)
VYRTUE_LOCAL
VYRTUE_ATTR_NONNULL_ALL
VYRTUE_ATTR_WARN_UNUSED_RESULT
HashTable *vyrtue_get_import_ht(uint32_t type, struct vyrtue_preprocess_context *ctx)
HashTable *vyrtue_get_import_ht(uint32_t type, struct vyrtue_context *ctx)
{
switch (type) {
case ZEND_SYMBOL_CLASS:
Expand Down Expand Up @@ -74,7 +73,7 @@ HashTable *vyrtue_get_import_ht(uint32_t type, struct vyrtue_preprocess_context

VYRTUE_LOCAL
VYRTUE_ATTR_NONNULL_ALL
void vyrtue_reset_import_tables(struct vyrtue_preprocess_context *ctx)
void vyrtue_reset_import_tables(struct vyrtue_context *ctx)
{
if (ctx->imports) {
zend_hash_destroy(ctx->imports);
Expand All @@ -97,7 +96,7 @@ void vyrtue_reset_import_tables(struct vyrtue_preprocess_context *ctx)

VYRTUE_LOCAL
VYRTUE_ATTR_NONNULL_ALL
void vyrtue_end_namespace(struct vyrtue_preprocess_context *ctx)
void vyrtue_end_namespace(struct vyrtue_context *ctx)
{
ctx->in_namespace = false;
vyrtue_reset_import_tables(ctx);
Expand All @@ -113,7 +112,7 @@ void vyrtue_end_namespace(struct vyrtue_preprocess_context *ctx)

VYRTUE_ATTR_NONNULL_ALL
VYRTUE_ATTR_WARN_UNUSED_RESULT
static zend_string *vyrtue_prefix_with_ns(zend_string *name, struct vyrtue_preprocess_context *ctx)
static zend_string *vyrtue_prefix_with_ns(zend_string *name, struct vyrtue_context *ctx)
{
if (ctx->current_namespace) {
zend_string *ns = ctx->current_namespace;
Expand All @@ -126,7 +125,7 @@ static zend_string *vyrtue_prefix_with_ns(zend_string *name, struct vyrtue_prepr
VYRTUE_ATTR_NONNULL(1, 3, 6)
VYRTUE_ATTR_WARN_UNUSED_RESULT
static zend_string *vyrtue_resolve_non_class_name(
zend_string *name, uint32_t type, bool *is_fully_qualified, bool case_sensitive, HashTable *current_import_sub, struct vyrtue_preprocess_context *ctx
zend_string *name, uint32_t type, bool *is_fully_qualified, bool case_sensitive, HashTable *current_import_sub, struct vyrtue_context *ctx
)
{
char *compound;
Expand Down Expand Up @@ -184,7 +183,7 @@ static zend_string *vyrtue_resolve_non_class_name(
VYRTUE_LOCAL
VYRTUE_ATTR_NONNULL_ALL
VYRTUE_ATTR_WARN_UNUSED_RESULT
zend_string *vyrtue_resolve_function_name(zend_string *name, uint32_t type, bool *is_fully_qualified, struct vyrtue_preprocess_context *ctx)
zend_string *vyrtue_resolve_function_name(zend_string *name, uint32_t type, bool *is_fully_qualified, struct vyrtue_context *ctx)
{
return vyrtue_resolve_non_class_name(name, type, is_fully_qualified, 0, ctx->imports_function, ctx);
}
Expand All @@ -207,7 +206,7 @@ static uint32_t vyrtue_get_class_fetch_type(zend_string *name)
VYRTUE_LOCAL
VYRTUE_ATTR_NONNULL(3)
VYRTUE_ATTR_WARN_UNUSED_RESULT
zend_string *vyrtue_resolve_class_name(zend_string *name, uint32_t type, struct vyrtue_preprocess_context *ctx)
zend_string *vyrtue_resolve_class_name(zend_string *name, uint32_t type, struct vyrtue_context *ctx)
{
char *compound;

Expand Down Expand Up @@ -269,7 +268,7 @@ zend_string *vyrtue_resolve_class_name(zend_string *name, uint32_t type, struct
VYRTUE_LOCAL
VYRTUE_ATTR_NONNULL_ALL
VYRTUE_ATTR_WARN_UNUSED_RESULT
zend_string *vyrtue_resolve_class_name_ast(zend_ast *ast, struct vyrtue_preprocess_context *ctx)
zend_string *vyrtue_resolve_class_name_ast(zend_ast *ast, struct vyrtue_context *ctx)
{
zval *class_name = zend_ast_get_zval(ast);
if (Z_TYPE_P(class_name) != IS_STRING) {
Expand Down
14 changes: 7 additions & 7 deletions src/compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
// These are all mostly based on zend_compile functions, so I suppose
// they are probably covered under the zend license

#include <Zend/zend_API.h>
#include <stdbool.h>
#include <Zend/zend_API.h>

static bool zend_get_unqualified_name(const zend_string *name, const char **result, size_t *result_len)
{
Expand All @@ -44,27 +44,27 @@ static zend_string *zend_concat_names(char *name1, size_t name1_len, char *name2
VYRTUE_LOCAL
VYRTUE_ATTR_NONNULL_ALL
VYRTUE_ATTR_WARN_UNUSED_RESULT
HashTable *vyrtue_get_import_ht(uint32_t type, struct vyrtue_preprocess_context *ctx);
HashTable *vyrtue_get_import_ht(uint32_t type, struct vyrtue_context *ctx);

VYRTUE_LOCAL
VYRTUE_ATTR_NONNULL_ALL
void vyrtue_reset_import_tables(struct vyrtue_preprocess_context *ctx);
void vyrtue_reset_import_tables(struct vyrtue_context *ctx);

VYRTUE_LOCAL
VYRTUE_ATTR_NONNULL_ALL
void vyrtue_end_namespace(struct vyrtue_preprocess_context *ctx);
void vyrtue_end_namespace(struct vyrtue_context *ctx);

VYRTUE_LOCAL
VYRTUE_ATTR_NONNULL_ALL
VYRTUE_ATTR_WARN_UNUSED_RESULT
zend_string *vyrtue_resolve_function_name(zend_string *name, uint32_t type, bool *is_fully_qualified, struct vyrtue_preprocess_context *ctx);
zend_string *vyrtue_resolve_function_name(zend_string *name, uint32_t type, bool *is_fully_qualified, struct vyrtue_context *ctx);

VYRTUE_LOCAL
VYRTUE_ATTR_NONNULL(3)
VYRTUE_ATTR_WARN_UNUSED_RESULT
zend_string *vyrtue_resolve_class_name(zend_string *name, uint32_t type, struct vyrtue_preprocess_context *ctx);
zend_string *vyrtue_resolve_class_name(zend_string *name, uint32_t type, struct vyrtue_context *ctx);

VYRTUE_LOCAL
VYRTUE_ATTR_NONNULL_ALL
VYRTUE_ATTR_WARN_UNUSED_RESULT
zend_string *vyrtue_resolve_class_name_ast(zend_ast *ast, struct vyrtue_preprocess_context *ctx);
zend_string *vyrtue_resolve_class_name_ast(zend_ast *ast, struct vyrtue_context *ctx);
45 changes: 45 additions & 0 deletions src/context.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright (C) 2024 John Boehr & contributors
*
* This file is part of php-vyrtue.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <string.h>
#include <stdbool.h>

#include "Zend/zend_API.h"
#include "main/php.h"

#include "php_vyrtue.h"
#include "context.h"

VYRTUE_PUBLIC
VYRTUE_ATTR_NONNULL_ALL
zend_ast *vyrtue_context_node_stack_top(struct vyrtue_context *ctx)
{
return vyrtue_context_stack_top(&ctx->node_stack);
}

VYRTUE_PUBLIC
VYRTUE_ATTR_NONNULL_ALL
zend_ast *vyrtue_context_scope_stack_top(struct vyrtue_context *ctx)
{
return vyrtue_context_stack_top(&ctx->scope_stack);
}
89 changes: 89 additions & 0 deletions src/context.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* Copyright (C) 2024 John Boehr & contributors
*
* This file is part of php-vyrtue.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef PHP_VYRTUE_CONTEXT_H
#define PHP_VYRTUE_CONTEXT_H

#include <Zend/zend_API.h>
#include <Zend/zend_hash.h>
#include <Zend/zend_errors.h>
#include "php_vyrtue.h"

#define VYRTUE_STACK_SIZE 256

struct vyrtue_context_stack
{
size_t i;
zend_ast *data[VYRTUE_STACK_SIZE];
};

struct vyrtue_context
{
bool in_namespace;
bool in_group_use;
zend_string *current_namespace;
HashTable *imports;
HashTable *imports_function;
HashTable *imports_const;
struct vyrtue_context_stack scope_stack;
struct vyrtue_context_stack node_stack;
};

VYRTUE_ATTR_NONNULL_ALL
static inline void vyrtue_context_stack_push(struct vyrtue_context_stack *stack, zend_ast *ast)
{
stack->data[stack->i] = ast;
stack->i++;
}

VYRTUE_ATTR_NONNULL_ALL
static inline void vyrtue_context_stack_pop(struct vyrtue_context_stack *stack, zend_ast *ast)
{
if (UNEXPECTED(stack->i <= 0)) {
zend_error(E_WARNING, "vyrtue: stack underflow");
return;
}

stack->i--;

if (UNEXPECTED(ast != stack->data[stack->i])) {
zend_error(E_WARNING, "vyrtue: stack pop mismatch");
}

stack->data[stack->i] = NULL;
}

VYRTUE_ATTR_NONNULL_ALL
static inline size_t vyrtue_context_stack_count(struct vyrtue_context_stack *stack)
{
return stack->i;
}

VYRTUE_ATTR_NONNULL_ALL
static inline zend_ast *vyrtue_context_stack_top(struct vyrtue_context_stack *stack)
{
if (UNEXPECTED(stack->i <= 0)) {
zend_error(E_WARNING, "vyrtue: stack underflow");
return NULL;
}

return stack->data[stack->i - 1];
}

#endif
12 changes: 6 additions & 6 deletions src/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,42 +29,42 @@

#include "php_vyrtue.h"

static zend_ast *vyrtue_debug_sample_replacement_enter(zend_ast *ast, struct vyrtue_preprocess_context *ctx)
static zend_ast *vyrtue_debug_sample_replacement_enter(zend_ast *ast, struct vyrtue_context *ctx)
{
fprintf(stderr, "entering sample function\n");

return zend_ast_create_zval_from_long(12345);
}

static zend_ast *vyrtue_debug_sample_replacement_leave(zend_ast *ast, struct vyrtue_preprocess_context *ctx)
static zend_ast *vyrtue_debug_sample_replacement_leave(zend_ast *ast, struct vyrtue_context *ctx)
{
fprintf(stderr, "leaving sample function\n");

return NULL;
}

static zend_ast *vyrtue_debug_sample_function_enter(zend_ast *ast, struct vyrtue_preprocess_context *ctx)
static zend_ast *vyrtue_debug_sample_function_enter(zend_ast *ast, struct vyrtue_context *ctx)
{
fprintf(stderr, "entering sample function\n");

return NULL;
}

static zend_ast *vyrtue_debug_sample_function_leave(zend_ast *ast, struct vyrtue_preprocess_context *ctx)
static zend_ast *vyrtue_debug_sample_function_leave(zend_ast *ast, struct vyrtue_context *ctx)
{
fprintf(stderr, "leaving sample function\n");

return NULL;
}

static zend_ast *vyrtue_debug_sample_attribute_enter(zend_ast *ast, struct vyrtue_preprocess_context *ctx)
static zend_ast *vyrtue_debug_sample_attribute_enter(zend_ast *ast, struct vyrtue_context *ctx)
{
fprintf(stderr, "entering sample attribute\n");

return NULL;
}

static zend_ast *vyrtue_debug_sample_attribute_leave(zend_ast *ast, struct vyrtue_preprocess_context *ctx)
static zend_ast *vyrtue_debug_sample_attribute_leave(zend_ast *ast, struct vyrtue_context *ctx)
{
fprintf(stderr, "leaving sample attribute\n");

Expand Down

0 comments on commit 47f201b

Please sign in to comment.