+ if (!(I = psi_parser_open_file(&P, file->val, true))) {
+ psi_parser_dtor(&P);
+ RETURN_FALSE;
+ }
+
+ psi_parser_parse(&P, I);
+ psi_data_ctor(&D, P.error, P.flags);
+ psi_validate_scope_ctor(&S);
+ S.defs = &P.preproc->defs;
+ RETVAL_BOOL(psi_validate(&S, &D, PSI_DATA(&P)) && !P.errors);
+ psi_validate_scope_dtor(&S);
+ psi_data_dtor(&D);
+ psi_parser_dtor(&P);
+ free(I);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_psi_validate_string, 0, 0, 1)
+ ZEND_ARG_INFO(0, string)
+ZEND_END_ARG_INFO();
+static PHP_FUNCTION(psi_validate_string)
+{
+ zend_string *string;
+ struct psi_parser_input *I;
+ struct psi_parser P;
+ struct psi_data D = {0};
+ struct psi_validate_scope S = {0};
+ zend_long flags = 0;
+
+#if PHP_DEBUG
+ if (psi_check_env("PSI_DEBUG")) {
+ flags |= PSI_DEBUG;
+ }
+#endif
+
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &string, &flags)) {
+ return;
+ }
+
+ if (!psi_parser_init(&P, psi_error_wrapper, flags)) {
+ RETURN_FALSE;
+ }
+ if (!(I = psi_parser_open_string(&P, string->val, string->len))) {
+ psi_parser_dtor(&P);
+ RETURN_FALSE;
+ }
+
+ psi_parser_parse(&P, I);
+ psi_data_ctor(&D, P.error, P.flags);
+ psi_validate_scope_ctor(&S);
+ S.defs = &P.preproc->defs;
+ RETVAL_BOOL(psi_validate(&S, &D, PSI_DATA(&P)) && !P.errors);
+ psi_validate_scope_dtor(&S);
+ psi_data_dtor(&D);
+ psi_parser_dtor(&P);
+ free(I);
+}
+
+static ZEND_RESULT_CODE psi_ops_load()
+{
+ struct psi_context_ops *ops = NULL;
+#ifdef HAVE_LIBJIT
+ if (!strcasecmp(PSI_G(engine), "jit")) {
+ ops = psi_libjit_ops();
+ } else
+#endif
+#ifdef HAVE_LIBFFI
+ ops = psi_libffi_ops();
+#endif
+
+ if (!ops) {
+ php_error(E_WARNING, "No PSI engine found");
+ return FAILURE;
+ }
+
+ PSI_G(ops) = ops;
+ if (ops->load) {
+ return ops->load();