$(CC) -o $@ $<
$(PHP_PSI_SRCDIR)/src/parser_proc.h: $(PHP_PSI_SRCDIR)/src/parser_proc.y
-
+
$(PHP_PSI_SRCDIR)/src/%.c: $(PHP_PSI_SRCDIR)/src/parser.h $(PHP_PSI_SRCDIR)/src/parser_proc.h
touch $@
$(PHP_PSI_SRCDIR)/src/parser_proc.y: $(PHP_PSI_SRCDIR)/src/parser.h
#include "TSRM.h"
#endif
-#include "parser.h"
#include "context.h"
void psi_error(int type, const char *msg, ...);
let stream = objval($stream);
return void(rewind);
}
+
+extern int printf(const char *fmt, ...);
+function psi\printf(string $fmt, mixed ...$args) : int {
+ let fmt = strval($fmt);
+ return to_int(printf);
+}
#include "php.h"
#include "php_scandir.h"
#include "php_psi.h"
-#include "context.h"
-#include "parser.h"
#include "libjit.h"
#include "libffi.h"
static inline int validate_decl_arg(PSI_Data *data, decl_arg *arg) {
if (!validate_decl_type(data, arg->type)) {
- data->error(PSI_WARNING, "Cannot use '%s'(%d) as type for '%s'",
- arg->type->name, arg->type->type, arg->var->name);
+ data->error(PSI_WARNING, "Cannot use '%s'(%d) as type for decl var '%s'"
+ " in %s on line %zu at col %zu",
+ arg->type->name, arg->type->type, arg->var->name,
+ arg->type->token->file, arg->type->token->line, arg->type->token->col);
return 0;
}
return 1;
dprintf(fd, "%s ", decl->abi->convention);
dump_decl_arg(fd, decl->func);
dprintf(fd, "(");
- if (decl->args) for (j = 0; j < decl->args->count; ++j) {
- if (j) {
- dprintf(fd, ", ");
+ if (decl->args) {
+ for (j = 0; j < decl->args->count; ++j) {
+ if (j) {
+ dprintf(fd, ", ");
+ }
+ dump_decl_arg(fd, decl->args->args[j]);
+ }
+ if (decl->args->varargs) {
+ dprintf(fd, ", ...");
}
- dump_decl_arg(fd, decl->args->args[j]);
}
dprintf(fd, ");\n");
}
impl *impl = C->impls->list[i];
dprintf(fd, "function %s(", impl->func->name);
- if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) {
- impl_arg *iarg = impl->func->args->args[j];
-
- dprintf(fd, "%s%s %s$%s",
- j ? ", " : "",
- iarg->type->name,
- iarg->var->reference ? "&" : "",
- iarg->var->name);
- if (iarg->def) {
- dprintf(fd, " = %s", iarg->def->text);
+ if (impl->func->args) {
+ for (j = 0; j < impl->func->args->count; ++j) {
+ impl_arg *iarg = impl->func->args->args[j];
+
+ dprintf(fd, "%s%s %s$%s",
+ j ? ", " : "",
+ iarg->type->name,
+ iarg->var->reference ? "&" : "",
+ iarg->var->name);
+ if (iarg->def) {
+ dprintf(fd, " = %s", iarg->def->text);
+ }
+ }
+ if (impl->func->args->vararg) {
+ impl_arg *vararg = impl->func->args->vararg;
+
+ dprintf(fd, ", %s %s...$%s",
+ vararg->type->name,
+ vararg->var->reference ? "&" : "",
+ vararg->var->name);
}
}
dprintf(fd, ") : %s%s {\n",
#include "zend_operators.h"
#include "php_psi.h"
-#include "parser.h"
-#include "context.h"
#if HAVE_LIBJIT
# include "libjit.h"
zend_internal_arg_info *aip;
zend_internal_function_info *fi;
- aip = calloc(impl->func->args->count + 1, sizeof(*aip));
+ aip = calloc(impl->func->args->count + 1 + !!impl->func->args->vararg, sizeof(*aip));
fi = (zend_internal_function_info *) &aip[0];
+ fi->allow_null = 1;
fi->required_num_args = psi_num_min_args(impl);
fi->return_reference = impl->func->return_reference;
fi->type_hint = psi_internal_type(impl->func->return_type);
+ if (impl->func->args->vararg) {
+ impl_arg *vararg = impl->func->args->vararg;
+ zend_internal_arg_info *ai = &aip[impl->func->args->count];
+
+ ai->name = vararg->var->name;
+ ai->type_hint = psi_internal_type(vararg->type);
+ if (vararg->var->reference) {
+ ai->pass_by_reference = 1;
+ }
+ ai->is_variadic = 1;
+ }
+
for (i = 0; i < impl->func->args->count; ++i) {
impl_arg *iarg = impl->func->args->args[i];
zend_internal_arg_info *ai = &aip[i+1];
return rv;
}
- ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->count)
+ ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->vararg ? -1 : impl->func->args->count)
nextarg:
iarg = impl->func->args->args[_i];
if (iarg->def) {
error_code = ZPP_ERROR_FAILURE;
break;
}
+ if (impl->func->args->vararg) {
+ iarg = impl->func->args->vararg;
+
+ if (_i == impl->func->args->count) {
+ zval *ptr = iarg->_zv = calloc(_num_args - _i + 1, sizeof(zval));
+
+ _optional = 1;
+ while (_i < _num_args) {
+ Z_PARAM_PROLOGUE(0);
+ ZVAL_COPY_VALUE(ptr++, _arg);
+ }
+ break;
+ }
+ }
if (_i < _num_args) {
goto nextarg;
}
typedef struct PSI_Token {
token_t type;
- unsigned line;
- size_t size;
- char text[1];
+ size_t size, line, col;
+ char *text, *file;
+ char buf[1];
} PSI_Token;
typedef union impl_val {
} impl_val;
typedef struct decl_type {
+ PSI_Token *token;
char *name;
token_t type;
struct decl_type *real;
typedef struct decl_args {
decl_arg **args;
size_t count;
+ unsigned varargs:1;
} decl_args;
static inline decl_args *init_decl_args(decl_arg *arg) {
typedef struct impl_args {
impl_arg **args;
size_t count;
+ impl_arg *vararg;
} impl_args;
static inline impl_args *init_impl_args(impl_arg *arg) {
unsigned flags;
unsigned errors;
void *proc;
- size_t line;
+ size_t line, col;
token_t num;
char *cur, *tok, *lim, *eof, *ctx, *mrk, buf[BSIZE];
} PSI_Parser;
static inline PSI_Token *PSI_TokenAlloc(PSI_Parser *P) {
PSI_Token *T;
- size_t token_len;
+ size_t token_len, fname_len;
+ token_t token_typ;
if (P->cur < P->tok) {
return NULL;
}
+ token_typ = P->num;
token_len = P->cur - P->tok;
+ fname_len = strlen(P->psi.file.fn);
- T = calloc(1, sizeof(*T) + token_len);
- T->type = P->num;
- T->line = P->line;
+ T = calloc(1, sizeof(*T) + token_len + fname_len + 1);
+ T->type = token_typ;
T->size = token_len;
- T->text[token_len] = 0;
+ T->line = P->line;
+ T->col = P->col;
+ T->file = &T->buf[0];
+ T->text = &T->buf[fname_len + 1];
+
+ memcpy(T->file, P->psi.file.fn, fname_len);
memcpy(T->text, P->tok, token_len);
return T;
}
+static inline PSI_Token *PSI_TokenCopy(PSI_Token *src) {
+ size_t fname_len = strlen(src->file);
+ size_t strct_len = sizeof(*src) + src->size + fname_len + 1;
+ PSI_Token *ptr = malloc(strct_len);
+
+ memcpy(ptr, src, strct_len);
+
+ ptr->file = &ptr->buf[0];
+ ptr->text = &ptr->buf[fname_len + 1];
+
+ return ptr;
+}
+
#define PSI_PARSER_DEBUG 0x1
PSI_Parser *PSI_ParserInit(PSI_Parser *P, const char *filename, psi_error_cb error, unsigned flags);
void PSI_ParserSyntaxError(PSI_Parser *P, const char *fn, size_t ln, const char *msg, ...);
size_t PSI_ParserFill(PSI_Parser *P, size_t n);
token_t PSI_ParserScan(PSI_Parser *P);
-void PSI_ParserParse(PSI_Parser *P, PSI_Token *T);
+void PSI_ParserParse(PSI_Parser *P, PSI_Token *src);
void PSI_ParserDtor(PSI_Parser *P);
void PSI_ParserFree(PSI_Parser **P);
P->psi.file.fn = strdup(filename);
P->fp = fp;
+ P->col = 1;
P->line = 1;
P->error = error;
P->flags = flags;
# error BSIZE must be greater than YYMAXFILL
#endif
+#define PSI_T(n) \
+(n) == PSI_T_NAME ? "NAME" : \
+(n) == PSI_T_PLUS ? "PLUS" : \
+(n) == PSI_T_MINUS ? "MINUS" : \
+(n) == PSI_T_SLASH ? "SLASH" : \
+(n) == PSI_T_ASTERISK ? "ASTERISK" : \
+(n) == PSI_T_TEMP ? "TEMP" : \
+(n) == PSI_T_FREE ? "FREE" : \
+(n) == PSI_T_SET ? "SET" : \
+(n) == PSI_T_LET ? "LET" : \
+(n) == PSI_T_RETURN ? "RETURN" : \
+(n) == PSI_T_LIB ? "LIB" : \
+(n) == PSI_T_INT ? "INT" : \
+(n) == PSI_T_UNSIGNED ? "UNSIGNED" : \
+(n) == PSI_T_EOF ? "EOF" : \
+(n) == PSI_T_QUOTED_STRING ? "QUOTED_STRING" : \
+(n) == PSI_T_EOS ? "EOS" : \
+(n) == PSI_T_STRUCT ? "STRUCT" : \
+(n) == PSI_T_LBRACE ? "LBRACE" : \
+(n) == PSI_T_RBRACE ? "RBRACE" : \
+(n) == PSI_T_COLON ? "COLON" : \
+(n) == PSI_T_LPAREN ? "LPAREN" : \
+(n) == PSI_T_NUMBER ? "NUMBER" : \
+(n) == PSI_T_RPAREN ? "RPAREN" : \
+(n) == PSI_T_BOOL ? "BOOL" : \
+(n) == PSI_T_FLOAT ? "FLOAT" : \
+(n) == PSI_T_STRING ? "STRING" : \
+(n) == PSI_T_CONST ? "CONST" : \
+(n) == PSI_T_NSNAME ? "NSNAME" : \
+(n) == PSI_T_EQUALS ? "EQUALS" : \
+(n) == PSI_T_TYPEDEF ? "TYPEDEF" : \
+(n) == PSI_T_VOID ? "VOID" : \
+(n) == PSI_T_LBRACKET ? "LBRACKET" : \
+(n) == PSI_T_RBRACKET ? "RBRACKET" : \
+(n) == PSI_T_COMMA ? "COMMA" : \
+(n) == PSI_T_ELLIPSIS ? "ELLIPSIS" : \
+(n) == PSI_T_DOUBLE ? "DOUBLE" : \
+(n) == PSI_T_INT8 ? "INT8" : \
+(n) == PSI_T_UINT8 ? "UINT8" : \
+(n) == PSI_T_INT16 ? "INT16" : \
+(n) == PSI_T_UINT16 ? "UINT16" : \
+(n) == PSI_T_INT32 ? "INT32" : \
+(n) == PSI_T_UINT32 ? "UINT32" : \
+(n) == PSI_T_INT64 ? "INT64" : \
+(n) == PSI_T_UINT64 ? "UINT64" : \
+(n) == PSI_T_FUNCTION ? "FUNCTION" : \
+(n) == PSI_T_NULL ? "NULL" : \
+(n) == PSI_T_TRUE ? "TRUE" : \
+(n) == PSI_T_FALSE ? "FALSE" : \
+(n) == PSI_T_DOLLAR ? "DOLLAR" : \
+(n) == PSI_T_CALLOC ? "CALLOC" : \
+(n) == PSI_T_OBJVAL ? "OBJVAL" : \
+(n) == PSI_T_ARRVAL ? "ARRVAL" : \
+(n) == PSI_T_PATHVAL ? "PATHVAL" : \
+(n) == PSI_T_STRLEN ? "STRLEN" : \
+(n) == PSI_T_STRVAL ? "STRVAL" : \
+(n) == PSI_T_FLOATVAL ? "FLOATVAL" : \
+(n) == PSI_T_INTVAL ? "INTVAL" : \
+(n) == PSI_T_BOOLVAL ? "BOOLVAL" : \
+(n) == PSI_T_TO_OBJECT ? "TO_OBJECT" : \
+(n) == PSI_T_TO_ARRAY ? "TO_ARRAY" : \
+(n) == PSI_T_TO_STRING ? "TO_STRING" : \
+(n) == PSI_T_TO_INT ? "TO_INT" : \
+(n) == PSI_T_TO_FLOAT ? "TO_FLOAT" : \
+(n) == PSI_T_TO_BOOL ? "TO_BOOL" : \
+(n) == PSI_T_MIXED ? "MIXED" : \
+(n) == PSI_T_ARRAY ? "ARRAY" : \
+(n) == PSI_T_OBJECT ? "OBJECT" : \
+(n) == PSI_T_AMPERSAND ? "AMPERSAND" : \
+<UNKNOWN>
+
#define RETURN(t) do { \
P->num = t; \
if (P->flags & PSI_PARSER_DEBUG) { \
- fprintf(stderr, "PSI> TOKEN: %d %.*s (EOF=%d)\n", P->num, (int) (P->cur-P->tok), P->tok, P->num == PSI_T_EOF); \
+ fprintf(stderr, "PSI> TOKEN: %d %.*s (EOF=%d %s:%zu:%zu)\n", \
+ P->num, (int) (P->cur-P->tok), P->tok, P->num == PSI_T_EOF, \
+ P->psi.file.fn, P->line, P->col); \
} \
return t; \
} while(1)
+#define ADDCOLS \
+ P->col += P->cur - P->tok
+
+#define NEWLINE \
+ P->col = 1; \
+ ++P->line; \
+ goto nextline
+
token_t PSI_ParserScan(PSI_Parser *P)
{
for (;;) {
+ ADDCOLS;
+ nextline:
P->tok = P->cur;
/*!re2c
re2c:indent:top = 2;
QUOTED_STRING = "\"" ([^\"])+ "\"";
NUMBER = [+-]? [0-9]* "."? [0-9]+ ([eE] [+-]? [0-9]+)?;
- ("#"|"//") .* "\n" { ++P->line; continue;}
+ ("#"|"//") .* "\n" { NEWLINE; }
"(" {RETURN(PSI_T_LPAREN);}
")" {RETURN(PSI_T_RPAREN);}
";" {RETURN(PSI_T_EOS);}
"+" {RETURN(PSI_T_PLUS);}
"-" {RETURN(PSI_T_MINUS);}
"/" {RETURN(PSI_T_SLASH);}
- [\r\n] { ++P->line; continue; }
+ "..." {RETURN(PSI_T_ELLIPSIS);}
+ [\r\n] { NEWLINE; }
[\t ]+ { continue; }
'TRUE' {RETURN(PSI_T_TRUE);}
'FALSE' {RETURN(PSI_T_FALSE);}
#define PSI_T_LBRACKET 32
#define PSI_T_RBRACKET 33
#define PSI_T_COMMA 34
-#define PSI_T_DOUBLE 35
-#define PSI_T_INT8 36
-#define PSI_T_UINT8 37
-#define PSI_T_INT16 38
-#define PSI_T_UINT16 39
-#define PSI_T_INT32 40
-#define PSI_T_UINT32 41
-#define PSI_T_INT64 42
-#define PSI_T_UINT64 43
-#define PSI_T_FUNCTION 44
-#define PSI_T_NULL 45
-#define PSI_T_TRUE 46
-#define PSI_T_FALSE 47
-#define PSI_T_DOLLAR 48
-#define PSI_T_CALLOC 49
-#define PSI_T_OBJVAL 50
-#define PSI_T_ARRVAL 51
-#define PSI_T_PATHVAL 52
-#define PSI_T_STRLEN 53
-#define PSI_T_STRVAL 54
-#define PSI_T_FLOATVAL 55
-#define PSI_T_INTVAL 56
-#define PSI_T_BOOLVAL 57
-#define PSI_T_TO_OBJECT 58
-#define PSI_T_TO_ARRAY 59
-#define PSI_T_TO_STRING 60
-#define PSI_T_TO_INT 61
-#define PSI_T_TO_FLOAT 62
-#define PSI_T_TO_BOOL 63
-#define PSI_T_MIXED 64
-#define PSI_T_ARRAY 65
-#define PSI_T_OBJECT 66
-#define PSI_T_AMPERSAND 67
+#define PSI_T_ELLIPSIS 35
+#define PSI_T_DOUBLE 36
+#define PSI_T_INT8 37
+#define PSI_T_UINT8 38
+#define PSI_T_INT16 39
+#define PSI_T_UINT16 40
+#define PSI_T_INT32 41
+#define PSI_T_UINT32 42
+#define PSI_T_INT64 43
+#define PSI_T_UINT64 44
+#define PSI_T_FUNCTION 45
+#define PSI_T_NULL 46
+#define PSI_T_TRUE 47
+#define PSI_T_FALSE 48
+#define PSI_T_DOLLAR 49
+#define PSI_T_CALLOC 50
+#define PSI_T_OBJVAL 51
+#define PSI_T_ARRVAL 52
+#define PSI_T_PATHVAL 53
+#define PSI_T_STRLEN 54
+#define PSI_T_STRVAL 55
+#define PSI_T_FLOATVAL 56
+#define PSI_T_INTVAL 57
+#define PSI_T_BOOLVAL 58
+#define PSI_T_TO_OBJECT 59
+#define PSI_T_TO_ARRAY 60
+#define PSI_T_TO_STRING 61
+#define PSI_T_TO_INT 62
+#define PSI_T_TO_FLOAT 63
+#define PSI_T_TO_BOOL 64
+#define PSI_T_MIXED 65
+#define PSI_T_ARRAY 66
+#define PSI_T_OBJECT 67
+#define PSI_T_AMPERSAND 68
/* support opaque types */
decl_typedef(def) ::= TYPEDEF VOID(V) NAME(ALIAS) EOS. {
def = init_decl_typedef(ALIAS->text, init_decl_type(V->type, V->text));
- free(V);
+ def->type->token = V;
+ //free(V);
free(ALIAS);
}
decl_typedef(def) ::= TYPEDEF STRUCT(S) NAME(N) NAME(ALIAS) EOS. {
def = init_decl_typedef(ALIAS->text, init_decl_type(S->type, N->text));
+ def->type->token = N;
free(ALIAS);
free(S);
- free(N);
+ //free(N);
}
decl_typedef(def) ::= TYPEDEF decl_struct(s) NAME(ALIAS) EOS. {
def = init_decl_typedef(ALIAS->text, init_decl_type(PSI_T_STRUCT, s->name));
+ def->type->token = ALIAS;
def->type->strct = s;
- free(ALIAS);
+ //free(ALIAS);
}
%type decl {decl*}
%destructor decl {free_decl($$);}
decl(decl) ::= decl_abi(abi) decl_func(func) LPAREN decl_args(args) RPAREN EOS. {
decl = init_decl(abi, func, args);
+
}
%type decl_func {decl_arg*}
init_decl_type(T->type, T->text),
init_decl_var(N->text, 0, 0)
);
- free(T);
+ func->type->token = T;
+ //free(T);
free(N);
}
init_decl_type(T->type, T->text),
init_decl_var(N->text, p, 0)
);
- free(T);
+ arg_->type->token = T;
+ //free(T);
free(N);
}
decl_arg(arg_) ::= CONST VOID(T) pointers(p) NAME(N). {
init_decl_type(T->type, T->text),
init_decl_var(N->text, p, 0)
);
- free(T);
+ arg_->type->token = T;
+ //free(T);
free(N);
}
decl_args(args) ::= decl_args(args_) COMMA decl_arg(arg). {
args = add_decl_arg(args_, arg);
}
+decl_args(args) ::= decl_args(args_) COMMA ELLIPSIS. {
+ args = args_;
+ args->varargs = 1;
+}
%type struct_args {decl_args*}
%destructor struct_args {free_decl_args($$);}
struct_args(args) ::= struct_arg(arg). {
%destructor decl_type {free_decl_type($$);}
decl_type(type_) ::= decl_type_token(T). {
type_ = init_decl_type(T->type, T->text);
- free(T);
+ type_->token = T;
+ //free(T);
}
/* unsigned, urgh */
decl_type(type_) ::= UNSIGNED NAME(T). {
type_ = init_decl_type(T->type, T->text);
+ type_->token = T;
type_->name = realloc(type_->name, T->size + sizeof("unsigned"));
memmove(type_->name + sizeof("unsigned"), type_->name, T->size);
memcpy(type_->name, "unsigned", sizeof("unsigned")-1);
type_->name[sizeof("unsigned")] = ' ';
type_->name[T->size + sizeof("unsigned")] = 0;
- free(T);
+ //free(T);
}
/* we have to support plain int here because we have it in our lexer rules */
decl_type(type_) ::= INT(T). {
type_ = init_decl_type(PSI_T_NAME, T->text);
- free(T);
+ type_->token = T;
+ //free(T);
}
/* structs ! */
decl_type(type_) ::= STRUCT(S) NAME(T). {
type_ = init_decl_type(S->type, T->text);
+ type_->token = T;
free(S);
- free(T);
+ //free(T);
}
%type const_decl_type {decl_type*}
impl_args(args) ::= LPAREN impl_arg_list(args_) RPAREN. {
args = args_;
}
+impl_args(args) ::= LPAREN impl_arg_list(args_) COMMA impl_vararg(va) RPAREN. {
+ args = args_;
+ args->vararg = va;
+}
+
+%type impl_vararg {impl_arg*}
+%destructor impl_vararg {free_impl_arg($$);}
+impl_vararg(va) ::= impl_type(type) reference(r) ELLIPSIS DOLLAR NAME(T). {
+ va = init_impl_arg(type, init_impl_var(T->text, r), NULL);
+}
+
%type impl_arg_list {impl_args*}
%destructor impl_arg_list {free_impl_args($$);}
impl_arg_list(args) ::= impl_arg(arg). {