0
0
mirror of https://github.com/phpv8/v8js.git synced 2024-09-19 00:25:18 +00:00

Remove old-age test.php & samples files

These date back to the initial checkin and mostly haven't been
updated ever since.  Besides the provided code samples aren't
really suitable as a getting started guide.
This commit is contained in:
Stefan Siegl 2016-03-25 23:48:26 +01:00
parent da89fa257b
commit 2b4d41abb1
18 changed files with 1 additions and 1731 deletions

View File

@ -7,14 +7,3 @@ endif
ifneq (,$(realpath $(EXTENSION_DIR)/pthreads.so))
PHP_TEST_SHARED_EXTENSIONS+=-d extension=$(EXTENSION_DIR)/pthreads.so
endif
testv8: all
$(PHP_EXECUTABLE) -n -d extension_dir=./modules -d extension=v8js.so test.php
debugv8: all
gdb --arg $(PHP_EXECUTABLE) -n -d extension_dir=./modules -d extension=v8js.so test.php
valgrindv8: all
USE_ZEND_ALLOC=0 valgrind --leak-check=full --show-reachable=yes --track-origins=yes $(PHP_EXECUTABLE) -n -d extension_dir=./modules -d extension=v8js.so test.php 2> valgrind.dump

6
TODO
View File

@ -1,6 +0,0 @@
- Feature: Extension registering from php.ini
- Feature: Thread safety
- Missing: Indexed property handlers
- Missing: static properties of PHP objects (on instance.constructor?)
- Bug: exception propagation fails when property getter is set
- Bug: method_exists() leaks when used with V8 objects

View File

@ -1,839 +0,0 @@
// Copyright (C) 2009 Andy Chu
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// $Id$
//
// JavaScript implementation of json-template.
//
// This is predefined in tests, shouldn't be defined anywhere else. TODO: Do
// something nicer.
var log = log || function() {};
var repr = repr || function() {};
// The "module" exported by this script is called "jsontemplate":
var jsontemplate = function() {
// Regex escaping for metacharacters
function EscapeMeta(meta) {
return meta.replace(/([\{\}\(\)\[\]\|\^\$\-\+\?])/g, '\\$1');
}
var token_re_cache = {};
function _MakeTokenRegex(meta_left, meta_right) {
var key = meta_left + meta_right;
var regex = token_re_cache[key];
if (regex === undefined) {
var str = '(' + EscapeMeta(meta_left) + '.*?' + EscapeMeta(meta_right) +
'\n?)';
regex = new RegExp(str, 'g');
}
return regex;
}
//
// Formatters
//
function HtmlEscape(s) {
return s.replace(/&/g,'&').
replace(/>/g,'>').
replace(/</g,'&lt;');
}
function HtmlTagEscape(s) {
return s.replace(/&/g,'&amp;').
replace(/>/g,'&gt;').
replace(/</g,'&lt;').
replace(/"/g,'&quot;');
}
// Default ToString can be changed
function ToString(s) {
if (s === null) {
return 'null';
}
return s.toString();
}
// Formatter to pluralize words
function _Pluralize(value, unused_context, args) {
var s, p;
switch (args.length) {
case 0:
s = ''; p = 's';
break;
case 1:
s = ''; p = args[0];
break;
case 2:
s = args[0]; p = args[1];
break;
default:
// Should have been checked at compile time
throw {
name: 'EvaluationError', message: 'pluralize got too many args'
};
}
return (value > 1) ? p : s;
}
function _Cycle(value, unused_context, args) {
// Cycle between various values on consecutive integers.
// @index starts from 1, so use 1-based indexing.
return args[(value - 1) % args.length];
}
var DEFAULT_FORMATTERS = {
'html': HtmlEscape,
'htmltag': HtmlTagEscape,
'html-attr-value': HtmlTagEscape,
'str': ToString,
'raw': function(x) { return x; },
'AbsUrl': function(value, context) {
// TODO: Normalize leading/trailing slashes
return context.get('base-url') + '/' + value;
}
};
var DEFAULT_PREDICATES = {
'singular?': function(x) { return x == 1; },
'plural?': function(x) { return x > 1; },
'Debug?': function(unused, context) {
try {
return context.get('debug');
} catch(err) {
if (err.name == 'UndefinedVariable') {
return false;
} else {
throw err;
}
}
}
};
var FunctionRegistry = function() {
return {
lookup: function(user_str) {
return [null, null];
}
};
};
var SimpleRegistry = function(obj) {
return {
lookup: function(user_str) {
var func = obj[user_str] || null;
return [func, null];
}
};
};
var CallableRegistry = function(callable) {
return {
lookup: function(user_str) {
var func = callable(user_str);
return [func, null];
}
};
};
// Default formatters which can't be expressed in DEFAULT_FORMATTERS
var PrefixRegistry = function(functions) {
return {
lookup: function(user_str) {
for (var i = 0; i < functions.length; i++) {
var name = functions[i].name, func = functions[i].func;
if (user_str.slice(0, name.length) == name) {
// Delimiter is usually a space, but could be something else
var args;
var splitchar = user_str.charAt(name.length);
if (splitchar === '') {
args = []; // No arguments
} else {
args = user_str.split(splitchar).slice(1);
}
return [func, args];
}
}
return [null, null]; // No formatter
}
};
};
var ChainedRegistry = function(registries) {
return {
lookup: function(user_str) {
for (var i=0; i<registries.length; i++) {
var result = registries[i].lookup(user_str);
if (result[0]) {
return result;
}
}
return [null, null]; // Nothing found
}
};
};
//
// Template implementation
//
function _ScopedContext(context, undefined_str) {
// The stack contains:
// The current context (an object).
// An iteration index. -1 means we're NOT iterating.
var stack = [{context: context, index: -1}];
return {
PushSection: function(name) {
if (name === undefined || name === null) {
return null;
}
var new_context;
if (name == '@') {
new_context = stack[stack.length-1].context;
} else {
new_context = stack[stack.length-1].context[name] || null;
}
stack.push({context: new_context, index: -1});
return new_context;
},
Pop: function() {
stack.pop();
},
next: function() {
var stacktop = stack[stack.length-1];
// Now we're iterating -- push a new mutable object onto the stack
if (stacktop.index == -1) {
stacktop = {context: null, index: 0};
stack.push(stacktop);
}
// The thing we're iterating over
var context_array = stack[stack.length-2].context;
// We're already done
if (stacktop.index == context_array.length) {
stack.pop();
return undefined; // sentinel to say that we're done
}
stacktop.context = context_array[stacktop.index++];
return true; // OK, we mutated the stack
},
_Undefined: function(name) {
if (undefined_str === undefined) {
throw {
name: 'UndefinedVariable', message: name + ' is not defined'
};
} else {
return undefined_str;
}
},
_LookUpStack: function(name) {
var i = stack.length - 1;
while (true) {
var frame = stack[i];
if (name == '@index') {
if (frame.index != -1) { // -1 is undefined
return frame.index;
}
} else {
var context = frame.context;
if (typeof context === 'object') {
var value = context[name];
if (value !== undefined) {
return value;
}
}
}
i--;
if (i <= -1) {
return this._Undefined(name);
}
}
},
get: function(name) {
if (name == '@') {
return stack[stack.length-1].context;
}
var parts = name.split('.');
var value = this._LookUpStack(parts[0]);
if (parts.length > 1) {
for (var i=1; i<parts.length; i++) {
value = value[parts[i]];
if (value === undefined) {
return this._Undefined(parts[i]);
}
}
}
return value;
}
};
}
// Crockford's "functional inheritance" pattern
var _AbstractSection = function(spec) {
var that = {};
that.current_clause = [];
that.Append = function(statement) {
that.current_clause.push(statement);
};
that.AlternatesWith = function() {
throw {
name: 'TemplateSyntaxError',
message:
'{.alternates with} can only appear with in {.repeated section ...}'
};
};
that.NewOrClause = function(pred) {
throw { name: 'NotImplemented' }; // "Abstract"
};
return that;
};
var _Section = function(spec) {
var that = _AbstractSection(spec);
that.statements = {'default': that.current_clause};
that.section_name = spec.section_name;
that.Statements = function(clause) {
clause = clause || 'default';
return that.statements[clause] || [];
};
that.NewOrClause = function(pred) {
if (pred) {
throw {
name: 'TemplateSyntaxError',
message: '{.or} clause only takes a predicate inside predicate blocks'
};
}
that.current_clause = [];
that.statements['or'] = that.current_clause;
};
return that;
};
// Repeated section is like section, but it supports {.alternates with}
var _RepeatedSection = function(spec) {
var that = _Section(spec);
that.AlternatesWith = function() {
that.current_clause = [];
that.statements['alternate'] = that.current_clause;
};
return that;
};
// Represents a sequence of predicate clauses.
var _PredicateSection = function(spec) {
var that = _AbstractSection(spec);
// Array of func, statements
that.clauses = [];
that.NewOrClause = function(pred) {
// {.or} always executes if reached, so use identity func with no args
pred = pred || [function(x) { return true; }, null];
that.current_clause = [];
that.clauses.push([pred, that.current_clause]);
};
return that;
};
function _Execute(statements, context, callback) {
for (var i=0; i<statements.length; i++) {
var statement = statements[i];
if (typeof(statement) == 'string') {
callback(statement);
} else {
var func = statement[0];
var args = statement[1];
func(args, context, callback);
}
}
}
function _DoSubstitute(statement, context, callback) {
var value;
value = context.get(statement.name);
// Format values
for (var i=0; i<statement.formatters.length; i++) {
var pair = statement.formatters[i];
var formatter = pair[0];
var args = pair[1];
value = formatter(value, context, args);
}
callback(value);
}
// for [section foo]
function _DoSection(args, context, callback) {
var block = args;
var value = context.PushSection(block.section_name);
var do_section = false;
// "truthy" values should have their sections executed.
if (value) {
do_section = true;
}
// Except: if the value is a zero-length array (which is "truthy")
if (value && value.length === 0) {
do_section = false;
}
if (do_section) {
_Execute(block.Statements(), context, callback);
context.Pop();
} else { // Empty list, None, False, etc.
context.Pop();
_Execute(block.Statements('or'), context, callback);
}
}
// {.pred1?} A {.or pred2?} B ... {.or} Z {.end}
function _DoPredicates(args, context, callback) {
// Here we execute the first clause that evaluates to true, and then stop.
var block = args;
var value = context.get('@');
for (var i=0; i<block.clauses.length; i++) {
var clause = block.clauses[i];
var predicate = clause[0][0];
var pred_args = clause[0][1];
var statements = clause[1];
var do_clause = predicate(value, context, pred_args);
if (do_clause) {
_Execute(statements, context, callback);
break;
}
}
}
function _DoRepeatedSection(args, context, callback) {
var block = args;
items = context.PushSection(block.section_name);
pushed = true;
if (items && items.length > 0) {
// TODO: check that items is an array; apparently this is hard in JavaScript
//if type(items) is not list:
// raise EvaluationError('Expected a list; got %s' % type(items))
// Execute the statements in the block for every item in the list.
// Execute the alternate block on every iteration except the last. Each
// item could be an atom (string, integer, etc.) or a dictionary.
var last_index = items.length - 1;
var statements = block.Statements();
var alt_statements = block.Statements('alternate');
for (var i=0; context.next() !== undefined; i++) {
_Execute(statements, context, callback);
if (i != last_index) {
_Execute(alt_statements, context, callback);
}
}
} else {
_Execute(block.Statements('or'), context, callback);
}
context.Pop();
}
var _SECTION_RE = /(repeated)?\s*(section)\s+(\S+)?/;
var _OR_RE = /or(?:\s+(.+))?/;
var _IF_RE = /if(?:\s+(.+))?/;
// Turn a object literal, function, or Registry into a Registry
function MakeRegistry(obj) {
if (!obj) {
// if null/undefined, use a totally empty FunctionRegistry
return new FunctionRegistry();
} else if (typeof obj === 'function') {
return new CallableRegistry(obj);
} else if (obj.lookup !== undefined) {
// TODO: Is this a good pattern? There is a namespace conflict where get
// could be either a formatter or a method on a FunctionRegistry.
// instanceof might be more robust.
return obj;
} else if (typeof obj === 'object') {
return new SimpleRegistry(obj);
}
}
// TODO: The compile function could be in a different module, in case we want to
// compile on the server side.
function _Compile(template_str, options) {
var more_formatters = MakeRegistry(options.more_formatters);
// default formatters with arguments
var default_formatters = PrefixRegistry([
{name: 'pluralize', func: _Pluralize},
{name: 'cycle', func: _Cycle}
]);
var all_formatters = new ChainedRegistry([
more_formatters,
SimpleRegistry(DEFAULT_FORMATTERS),
default_formatters
]);
var more_predicates = MakeRegistry(options.more_predicates);
// TODO: Add defaults
var all_predicates = new ChainedRegistry([
more_predicates, SimpleRegistry(DEFAULT_PREDICATES)
]);
// We want to allow an explicit null value for default_formatter, which means
// that an error is raised if no formatter is specified.
var default_formatter;
if (options.default_formatter === undefined) {
default_formatter = 'str';
} else {
default_formatter = options.default_formatter;
}
function GetFormatter(format_str) {
var pair = all_formatters.lookup(format_str);
if (!pair[0]) {
throw {
name: 'BadFormatter',
message: format_str + ' is not a valid formatter'
};
}
return pair;
}
function GetPredicate(pred_str) {
var pair = all_predicates.lookup(pred_str);
if (!pair[0]) {
throw {
name: 'BadPredicate',
message: pred_str + ' is not a valid predicate'
};
}
return pair;
}
var format_char = options.format_char || '|';
if (format_char != ':' && format_char != '|') {
throw {
name: 'ConfigurationError',
message: 'Only format characters : and | are accepted'
};
}
var meta = options.meta || '{}';
var n = meta.length;
if (n % 2 == 1) {
throw {
name: 'ConfigurationError',
message: meta + ' has an odd number of metacharacters'
};
}
var meta_left = meta.substring(0, n/2);
var meta_right = meta.substring(n/2, n);
var token_re = _MakeTokenRegex(meta_left, meta_right);
var current_block = _Section({});
var stack = [current_block];
var strip_num = meta_left.length; // assume they're the same length
var token_match;
var last_index = 0;
while (true) {
token_match = token_re.exec(template_str);
if (token_match === null) {
break;
} else {
var token = token_match[0];
}
// Add the previous literal to the program
if (token_match.index > last_index) {
var tok = template_str.slice(last_index, token_match.index);
current_block.Append(tok);
}
last_index = token_re.lastIndex;
var had_newline = false;
if (token.slice(-1) == '\n') {
token = token.slice(null, -1);
had_newline = true;
}
token = token.slice(strip_num, -strip_num);
if (token.charAt(0) == '#') {
continue; // comment
}
if (token.charAt(0) == '.') { // Keyword
token = token.substring(1, token.length);
var literal = {
'meta-left': meta_left,
'meta-right': meta_right,
'space': ' ',
'tab': '\t',
'newline': '\n'
}[token];
if (literal !== undefined) {
current_block.Append(literal);
continue;
}
var new_block, func;
var section_match = token.match(_SECTION_RE);
if (section_match) {
var repeated = section_match[1];
var section_name = section_match[3];
if (repeated) {
func = _DoRepeatedSection;
new_block = _RepeatedSection({section_name: section_name});
} else {
func = _DoSection;
new_block = _Section({section_name: section_name});
}
current_block.Append([func, new_block]);
stack.push(new_block);
current_block = new_block;
continue;
}
var pred_str, pred;
// Check {.or pred?} before {.pred?}
var or_match = token.match(_OR_RE);
if (or_match) {
pred_str = or_match[1];
pred = pred_str ? GetPredicate(pred_str) : null;
current_block.NewOrClause(pred);
continue;
}
// Match either {.pred?} or {.if pred?}
var matched = false;
var if_match = token.match(_IF_RE);
if (if_match) {
pred_str = if_match[1];
matched = true;
} else if (token.charAt(token.length-1) == '?') {
pred_str = token;
matched = true;
}
if (matched) {
pred = pred_str ? GetPredicate(pred_str) : null;
new_block = _PredicateSection();
new_block.NewOrClause(pred);
current_block.Append([_DoPredicates, new_block]);
stack.push(new_block);
current_block = new_block;
continue;
}
if (token == 'alternates with') {
current_block.AlternatesWith();
continue;
}
if (token == 'end') {
// End the block
stack.pop();
if (stack.length > 0) {
current_block = stack[stack.length-1];
} else {
throw {
name: 'TemplateSyntaxError',
message: 'Got too many {end} statements'
};
}
continue;
}
}
// A variable substitution
var parts = token.split(format_char);
var formatters;
var name;
if (parts.length == 1) {
if (default_formatter === null) {
throw {
name: 'MissingFormatter',
message: 'This template requires explicit formatters.'
};
}
// If no formatter is specified, use the default.
formatters = [GetFormatter(default_formatter)];
name = token;
} else {
formatters = [];
for (var j=1; j<parts.length; j++) {
formatters.push(GetFormatter(parts[j]));
}
name = parts[0];
}
current_block.Append([_DoSubstitute, {name: name, formatters: formatters}]);
if (had_newline) {
current_block.Append('\n');
}
}
// Add the trailing literal
current_block.Append(template_str.slice(last_index));
if (stack.length !== 1) {
throw {
name: 'TemplateSyntaxError',
message: 'Got too few {end} statements'
};
}
return current_block;
}
// The Template class is defined in the traditional style so that users can add
// methods by mutating the prototype attribute. TODO: Need a good idiom for
// inheritance without mutating globals.
function Template(template_str, options) {
// Add 'new' if we were not called with 'new', so prototyping works.
if(!(this instanceof Template)) {
return new Template(template_str, options);
}
this._options = options || {};
this._program = _Compile(template_str, this._options);
}
Template.prototype.render = function(data_dict, callback) {
// options.undefined_str can either be a string or undefined
var context = _ScopedContext(data_dict, this._options.undefined_str);
_Execute(this._program.Statements(), context, callback);
};
Template.prototype.expand = function(data_dict) {
var tokens = [];
this.render(data_dict, function(x) { tokens.push(x); });
return tokens.join('');
};
// fromString is a construction method that allows metadata to be written at the
// beginning of the template string. See Python's FromFile for a detailed
// description of the format.
//
// The argument 'options' takes precedence over the options in the template, and
// can be used for non-serializable options like template formatters.
var OPTION_RE = /^([a-zA-Z\-]+):\s*(.*)/;
var OPTION_NAMES = [
'meta', 'format-char', 'default-formatter', 'undefined-str'];
// Use this "linear search" instead of Array.indexOf, which is nonstandard
var OPTION_NAMES_RE = new RegExp(OPTION_NAMES.join('|'));
function fromString(s, options) {
var parsed = {};
var begin = 0, end = 0;
while (true) {
var parsedOption = false;
end = s.indexOf('\n', begin);
if (end == -1) {
break;
}
var line = s.slice(begin, end);
begin = end+1;
var match = line.match(OPTION_RE);
if (match !== null) {
var name = match[1].toLowerCase(), value = match[2];
if (name.match(OPTION_NAMES_RE)) {
name = name.replace('-', '_');
value = value.replace(/^\s+/, '').replace(/\s+$/, '');
if (name == 'default_formatter' && value.toLowerCase() == 'none') {
value = null;
}
parsed[name] = value;
parsedOption = true;
}
}
if (!parsedOption) {
break;
}
}
// TODO: This doesn't enforce the blank line between options and template, but
// that might be more trouble than it's worth
if (parsed !== {}) {
body = s.slice(begin);
} else {
body = s;
}
for (var o in options) {
parsed[o] = options[o];
}
return Template(body, parsed);
}
// We just export one name for now, the Template "class".
// We need HtmlEscape in the browser tests, so might as well export it.
return {
Template: Template, HtmlEscape: HtmlEscape,
FunctionRegistry: FunctionRegistry, SimpleRegistry: SimpleRegistry,
CallableRegistry: CallableRegistry, ChainedRegistry: ChainedRegistry,
fromString: fromString,
// Private but exposed for testing
_Section: _Section
};
}();

View File

@ -1,339 +0,0 @@
/*
Copyright 2008, mark turansky (www.markturansky.com)
Copyright 2010, Andrew Kelley (superjoesoftware.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
(This is the license from www.json.org and I think it's awesome)
*/
String.prototype.endsWith = function endsWith(c) {
if (this.charAt(this.length - 1) == c) {
return true;
} else {
return false;
}
};
String.prototype.startsWith = function startsWith(c) {
if (this.charAt(0) == c) {
return true;
} else {
return false;
}
};
RegExp.quote = function(str) {
return str.replace(/([.?*+\^$\[\]\\(){}\-])/g, "\\$1");
};
String.prototype.replaceAll = function replaceAll(a, b) {
return this.replace(new RegExp(RegExp.quote(a), 'g'), b);
};
var Jst = function () {
// private variables:
var that; // reference to the public object
// all write and writeln functions eval'd by Jst
// concatenate to this internal variable
var html = "";
// private functions
function CharacterStack(str) {
var i;
this.characters = [];
this.peek = function peek() {
return this.characters[this.characters.length - 1];
};
this.pop = function pop() {
return this.characters.pop();
};
this.push = function push(c) {
this.characters.push(c);
};
this.hasMore = function hasMore() {
if (this.characters.length > 0) {
return true;
} else {
return false;
}
};
for (i = str.length; i >= 0; i -= 1) {
this.characters.push(str.charAt(i));
}
}
function StringWriter() {
this.str = "";
this.write = function write(s) {
this.str += s;
};
this.toString = function toString() {
return this.str;
};
}
function parseScriptlet(stack) {
var fragment = new StringWriter();
var c; // character
while (stack.hasMore()) {
if (stack.peek() == '%') { //possible end delimiter
c = stack.pop();
if (stack.peek() == '>') { //end delimiter
// pop > so that it is not available to main parse loop
stack.pop();
if (stack.peek() == '\n') {
fragment.write(stack.pop());
}
break;
} else {
fragment.write(c);
}
} else {
fragment.write(stack.pop());
}
}
return fragment.toString();
}
function isOpeningDelimiter(c) {
if (c == "<" || c == "%lt;") {
return true;
} else {
return false;
}
}
function isClosingDelimiter(c) {
if (c == ">" || c == "%gt;") {
return true;
} else {
return false;
}
}
function appendExpressionFragment(writer, fragment, jstWriter) {
var i,j;
var c;
// check to be sure quotes are on both ends of a string literal
if (fragment.startsWith("\"") && !fragment.endsWith("\"")) {
//some scriptlets end with \n, especially if the script ends the file
if (fragment.endsWith("\n") && fragment.charAt(fragment.length - 2) == '"') {
//we're ok...
} else {
throw { "message":"'" + fragment + "' is not properly quoted"};
}
}
if (!fragment.startsWith("\"") && fragment.endsWith("\"")) {
throw { "message":"'" + fragment + "' is not properly quoted"};
}
// print or println?
if (fragment.endsWith("\n")) {
writer.write(jstWriter + "ln(");
//strip the newline
fragment = fragment.substring(0, fragment.length - 1);
} else {
writer.write(jstWriter + "(");
}
if (fragment.startsWith("\"") && fragment.endsWith("\"")) {
//strip the quotes
fragment = fragment.substring(1, fragment.length - 1);
writer.write("\"");
for (i = 0; i < fragment.length; i += 1) {
c = fragment.charAt(i);
if (c == '"') {
writer.write("\\");
writer.write(c);
}
}
writer.write("\"");
} else {
for (j = 0; j < fragment.length; j += 1) {
writer.write(fragment.charAt(j));
}
}
writer.write(");");
}
function appendTextFragment(writer, fragment) {
var i;
var c;
if (fragment.endsWith("\n")) {
writer.write("writeln(\"");
} else {
writer.write("write(\"");
}
for (i = 0; i < fragment.length; i += 1) {
c = fragment.charAt(i);
if (c == '"') {
writer.write("\\");
}
// we took care of the line break with print vs. println
if (c != '\n' && c != '\r') {
writer.write(c);
}
}
writer.write("\");");
}
function parseExpression(stack) {
var fragment = new StringWriter();
var c;
while (stack.hasMore()) {
if (stack.peek() == '%') { //possible end delimiter
c = stack.pop();
if (isClosingDelimiter(stack.peek())) { //end delimiter
//pop > so that it is not available to main parse loop
stack.pop();
if (stack.peek() == '\n') {
fragment.write(stack.pop());
}
break;
} else {
fragment.write("%");
}
} else {
fragment.write(stack.pop());
}
}
return fragment.toString();
}
function parseText(stack) {
var fragment = new StringWriter();
var c,d;
while (stack.hasMore()) {
if (isOpeningDelimiter(stack.peek())) { //possible delimiter
c = stack.pop();
if (stack.peek() == '%') { // delimiter!
// push c onto the stack to be used in main parse loop
stack.push(c);
break;
} else {
fragment.write(c);
}
} else {
d = stack.pop();
fragment.write(d);
if (d == '\n') { //done with this fragment. println it.
break;
}
}
}
return fragment.toString();
}
function safeWrite(s) {
s = s.toString();
s = s.replaceAll('&', '&amp;');
s = s.replaceAll('"', '&quot;');
s = s.replaceAll('<', '&lt;');
s = s.replaceAll('>', '&gt;');
html += s;
}
function safeWriteln(s) {
safeWrite(s + "\n");
}
function write(s) {
html += s;
}
function writeln(s) {
write(s + "\n");
}
that = {
// public methods:
// pre-compile a template for quicker rendering. save the return value and
// pass it to evaluate.
compile: function (src) {
var stack = new CharacterStack(src);
var writer = new StringWriter();
var c;
var fragment;
while (stack.hasMore()) {
if (isOpeningDelimiter(stack.peek())) { //possible delimiter
c = stack.pop();
if (stack.peek() == '%') { //delimiter!
c = stack.pop();
if (stack.peek() == "=") {
// expression, escape all html
stack.pop();
fragment = parseExpression(stack);
appendExpressionFragment(writer, fragment,
"safeWrite");
} else if (stack.peek() == "+") {
// expression, don't escape html
stack.pop();
fragment = parseExpression(stack);
appendExpressionFragment(writer, fragment,
"write");
} else {
fragment = parseScriptlet(stack);
writer.write(fragment);
}
} else { //not a delimiter
stack.push(c);
fragment = parseText(stack);
appendTextFragment(writer, fragment);
}
} else {
fragment = parseText(stack);
appendTextFragment(writer, fragment);
}
}
return writer.toString();
},
// evaluate a pre-compiled script. recommended approach
evaluate: function (script, args) {
with(args) {
html = "";
eval(script);
return html;
}
},
// if you're lazy, you can use this
evaluateSingleShot: function (src, args) {
return this.evaluate(this.compile(src), args);
}
};
return that;
}();

View File

@ -17,7 +17,7 @@
<active>yes</active>
</lead>
<date>2016-03-25</date>
<time>23:24:51</time>
<time>23:46:59</time>
<version>
<release>0.6.2</release>
<api>0.6.2</api>
@ -34,20 +34,6 @@
</notes>
<contents>
<dir baseinstalldir="/" name="/">
<file baseinstalldir="/" md5sum="9532b5359069afc8bdccb5e01c288493" name="js/json-template.js" role="data" />
<file baseinstalldir="/" md5sum="a490e5a575deeceab9872035fbe74eb1" name="js/jstparser.js" role="data" />
<file baseinstalldir="/" md5sum="ddbae43f7979c5fe082e08ff4f2e8765" name="samples/dlopen.supp" role="src" />
<file baseinstalldir="/" md5sum="045e094122747e8e71f02ffc1ba88d4a" name="samples/test_call.php" role="php" />
<file baseinstalldir="/" md5sum="87cb416c6bc17d657abbbf314a41ff85" name="samples/test_callback.php" role="php" />
<file baseinstalldir="/" md5sum="ce6958537730e437aecf4f99044a78ce" name="samples/test_closure.php" role="php" />
<file baseinstalldir="/" md5sum="07f6c82a56280bfe86dce8feecf52c45" name="samples/test_crash.php" role="php" />
<file baseinstalldir="/" md5sum="0e89021f07fd28bef6d8444b9fda3f9a" name="samples/test_date.php" role="php" />
<file baseinstalldir="/" md5sum="8e224fd19d8fda0c532d410153cc5b01" name="samples/test_dumper.php" role="php" />
<file baseinstalldir="/" md5sum="220347fdf7c1c14f2c346fd97b55a025" name="samples/test_exception.php" role="php" />
<file baseinstalldir="/" md5sum="6432eedc51c3dd34abd0b0986c6268da" name="samples/test_exception2.php" role="php" />
<file baseinstalldir="/" md5sum="194dab9bb37e8456afd7eb5dd9f7a81e" name="samples/test_extend.php" role="php" />
<file baseinstalldir="/" md5sum="f9af8067e0113ca3048573813eee7272" name="samples/test_extension.php" role="php" />
<file baseinstalldir="/" md5sum="b9491aff4c5647784f0c7ae9e0638c18" name="samples/test_method.php" role="php" />
<file baseinstalldir="/" md5sum="30d379088150c4d4dd0cd97ea21d8156" name="tests/array_access.phpt" role="test" />
<file baseinstalldir="/" md5sum="c91b16332cdc186ecf8a8dc5581f17c7" name="tests/array_access_001.phpt" role="test" />
<file baseinstalldir="/" md5sum="2f1e1a8788439173b4629d63e7bbe083" name="tests/array_access_002.phpt" role="test" />
@ -206,8 +192,6 @@
<file baseinstalldir="/" md5sum="d686d8e52af92521d4b8b0e86d00c463" name="README.MacOS.md" role="doc" />
<file baseinstalldir="/" md5sum="6d8116bb5ab12cb5032c04315da06265" name="README.md" role="doc" />
<file baseinstalldir="/" md5sum="9839870e001306943797003e8828d855" name="README.Win32.md" role="doc" />
<file baseinstalldir="/" md5sum="542f52c54898f33ac53b173970cba305" name="test.php" role="php" />
<file baseinstalldir="/" md5sum="65294fadb5ed766094b1f587fc20ad37" name="TODO" role="doc" />
<file baseinstalldir="/" md5sum="16c060e49d1b2c477531758e1de4850e" name="v8js.cc" role="src" />
<file baseinstalldir="/" md5sum="358c628b2627319e40fd7e5092f19872" name="v8js_array_access.cc" role="src" />
<file baseinstalldir="/" md5sum="7baf3fe5b77d1374b39a1d8332e05df4" name="v8js_array_access.h" role="src" />

View File

@ -1,15 +0,0 @@
{
Ignore dlopen bug #1.
Memcheck:Leak
...
fun:_dl_open
...
}
{
Ignore dlopen bug #2.
Memcheck:Leak
...
fun:_dl_close
...
}

View File

@ -1,75 +0,0 @@
<?php
class Foo {
var $bar = 'foobar';
function MyOwnFunc() {}
function __Get($name) {
echo "Called __get(): ";
var_dump($name);
return "xyz";
}
function __Set($name, $args) {
echo "Called __set(): ";
var_dump($name, $args);
}
function __Isset($name) {
echo "Called __isset(): ";
var_dump($name);
return true;
}
function __call($name, $args) {
echo "Called __call(): ";
var_dump($name, $args);
}
function __Invoke($name, $arg1, $arg2) {
echo "Called __invoke(): ";
var_dump(func_get_args());
return 'foobar';
}
function __toString() {
echo "Called __tostring: ";
return $this->bar;
}
}
$blaa = new V8Js();
$blaa->obj = new Foo;
try {
echo "__invoke()\n";
$blaa->executeString("var_dump(PHP.obj('arg1','arg2','arg3'));", "invoke_test1 #1.js");
echo "------------\n";
echo " __invoke() with new\n";
$blaa->executeString("myobj = new PHP.obj('arg1','arg2','arg3'); var_dump(myobj);", "invoke_test2 #2.js");
echo "------------\n";
echo " __tostring()\n";
$blaa->executeString('print(PHP.obj + "\n");', "tostring_test #3.js");
echo "------------\n";
echo " __isset() not called with existing property\n";
$blaa->executeString('if ("bar" in PHP.obj) print("bar exists\n");', "isset_test1 #4.js");
echo "------------\n";
echo " __isset() with non-existing property\n";
$blaa->executeString('if (!("foobar" in PHP.obj)) print("foobar does not exist\n"); else print("We called __isset and it said yes!\n");', "isset_test2 #5.js");
echo "------------\n";
echo " __get() not called with existing property\n";
$blaa->executeString('var_dump(PHP.obj.bar);', "get_test1 #6.js");
echo "------------\n";
echo " __get() with non-existing property\n";
$blaa->executeString('var_dump(PHP.obj.foo);', "get_test2 #7.js");
echo "------------\n";
echo " __call()\n";
$blaa->executeString('PHP.obj.foo(1,2,3);', "call_test1 #8.js");
echo "------------\n";
} catch (V8JsScriptException $e) {
echo $e->getMessage(), "\n";
}

View File

@ -1,32 +0,0 @@
<?php
$a = new V8Js();
// Should not work with closure
$a->test = function ($params) { return (method_exists($params, 'cb1')) ? $params->cb1("hello") : false; };
$ret = $a->executeString('PHP.test(function (foo) { return foo + " world"; });');
var_dump(__LINE__, $ret);
// Test is_a()
$a->test = function ($params) { return (is_a($params, 'V8Object')) ? $params->cb1("hello") : false; };
$ret = $a->executeString('PHP.test({ "cb1" : function (foo) { return foo + " world"; } });');
var_dump(__LINE__, $ret);
// Test is_a()
$a->test = function ($params) { return (is_a($params, 'V8Function')) ? $params("hello") : false; };
$ret = $a->executeString('PHP.test(function (foo) { return foo + " world"; });');
var_dump(__LINE__, $ret);
// Should not work with object
$a->test = function ($params) { return (is_a($params, 'Closure')) ? $params("hello") : false; };
$ret = $a->executeString('PHP.test({ "cb1" : function (foo) { return foo + " world"; } });');
var_dump(__LINE__, $ret);
$a->test = function ($params) { var_dump($params); return $params->cb1("hello"); };
$ret = $a->executeString('PHP.test({ "cb1" : function (foo) { return foo + " world"; } });');
var_dump(__LINE__, $ret);
// FIX! method_exists() Leaks!
$a->test = function ($params) { var_dump($params, method_exists($params, 'cb1'), $params->cb1); };
$ret = $a->executeString('PHP.test({ "cb1" : function (foo) { return foo + " world"; } });');

View File

@ -1,11 +0,0 @@
<?php
$a = new V8Js();
$a->func = function ($a) { echo "Closure..\n"; };
try {
$a->executeString("print(PHP.func); PHP.func(1);", "closure_test.js");
$a->executeString("print(PHP.func); PHP.func(1);", "closure_test.js");
} catch (V8JsScriptException $e) {
echo $e->getMessage(), "\n";
}

View File

@ -1,5 +0,0 @@
<?php {
$a = new V8Js();
var_dump($a->executeString('Jst.write = function(s) { html += "EI TOIMI"; };' ."\n" .' Jst.evaluate("lol testi <%= 1 %>", {});'));
}

View File

@ -1,9 +0,0 @@
<?php
$a = new V8Js();
try {
var_dump($a->executeString("date = new Date('September 8, 1975 09:00:00'); print(date + '\\n'); date;", "test.js"));
} catch (V8JsScriptException $e) {
echo $e->getMessage(), "\n";
}

View File

@ -1,59 +0,0 @@
<?php
class Foo {
var $foo = 'bar';
var $true = true;
var $false = false;
var $bar = array(1,2,3,1.23456789);
var $ass = array("life" => 42, "foo" => "bar");
function __set($name, $value)
{
echo "I'm setter!\n";
var_dump($name, $value);
}
function __get($name)
{
echo "I'm getter!\n";
var_dump($name);
}
function __call($name, $args)
{
echo "I'm caller!\n";
var_dump($name, $args);
}
}
$a = new V8Js();
$obj = new Foo;
$a->arr = array("foobar" => $obj);
$JS = <<< 'EOF'
var example = new Object;
example.foo = function () {
print("this is foo");
}
example.bar = function () {
print("this is bar");
}
example.__noSuchMethod__ = function (id, args) {
print("tried to handle unknown method " + id);
if (args.length != 0)
print("it had arguments: " + args);
}
example.foo(); // alerts "this is foo"
example.bar(); // alerts "this is bar"
example.grill(); // alerts "tried to handle unknown method grill"
example.ding("dong"); // alerts "tried to handle unknown method ding"
EOF;
try {
$a->executeString("var myarr = new Array(); myarr[0] = 'foo'; myarr[1] = 'bar'; var_dump(myarr); var_dump(new Date('September 8, 1975 09:00:00'))", "call_test1.js");
$a->executeString("var_dump(PHP.arr.foobar.bar);", "call_test2.js");
$a->executeString("var_dump(PHP.arr.foobar.bar[0]);", "call_test3.js");
$a->executeString("var_dump(var_dump(PHP.arr));", "call_test4.js");
$a->executeString("var patt1=/[^a-h]/g; var_dump(patt1);", "call_test5.js");
$a->executeString("var_dump(Math.PI, Infinity, null, undefined);", "call_test6.js");
// $a->executeString($JS);
} catch (V8JsScriptException $e) {
echo $e->getMessage(), "\n";
}

View File

@ -1,26 +0,0 @@
<?php {
class Foo {
private $v8 = NULL;
public function __construct()
{
$this->v8 = new V8Js();
$this->v8->foo = $this;
var_dump($this->v8->executeString('throw 1; PHP.foo.bar();', 'trycatch1'));
var_dump($this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print("catched!\n"); }', 'trycatch2'));
}
public function bar()
{
echo "To Bar!\n";
var_dump($this->v8->executeString('throw new Error();', 'throw'));
}
}
try {
$foo = new Foo();
} catch (V8JsScriptException $e) {
echo "PHP Exception: ", $e->getMessage(), "\n"; //var_dump($e);
}
}

View File

@ -1,34 +0,0 @@
<?php {
class Foo {
private $v8 = NULL;
public function __construct()
{
$this->v8 = new V8Js(null, array(), false);
$this->v8->foo = $this;
// $this->v8->executeString('asdasda< / sd', 'trycatch0');
// $this->v8->executeString('blahnothere', 'trycatch1');
// $this->v8->executeString('throw new SyntaxError();', 'throw');
// $this->v8->executeString('function foo() {throw new SyntaxError();}', 'trycatch2');
// $this->v8->executeString('try { foo(); } catch (e) { print(e + " catched by pure JS!\n"); }', 'trycatch3');
// $this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print(e + " catched via PHP callback!\n"); }', 'trycatch4');
// $this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print("catched!\n"); }', 'trycatch5');
// $this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print("catched!\n"); }', 'trycatch5');
var_dump($this->v8->getPendingException());
}
public function bar()
{
// $this->v8->executeString('asdasda< / sd', 'trycatch0');
// $this->v8->executeString('blahnothere', 'trycatch1');
$this->v8->executeString('throw new Error();', 'throw');
}
}
try {
$foo = new Foo();
} catch (V8JsScriptException $e) {
echo "PHP Exception: ", $e->getMessage(), "\n";
}
}

View File

@ -1,23 +0,0 @@
<?php
// Test class
class Testing extends V8Js
{
public $foo = 'ORIGINAL';
private $my_private = 'arf'; // Should not show in JS side
protected $my_protected = 'argh'; // Should not show in JS side
public function mytest($a, $b, $c = NULL)
{
var_dump(func_get_args());
}
}
$a = new Testing();
echo $a;
try {
$a->executeString("PHP.mytest(PHP.foo, PHP.my_private, PHP.my_protected);", "test7.js");
} catch (V8JsScriptException $e) {
var_dump($e);
}

View File

@ -1,9 +0,0 @@
<?php
V8Js::registerExtension('a', file_get_contents('js/json-template.js'), array('b'));
V8Js::registerExtension('b', file_get_contents('js/jstparser.js'), array('a'));
var_dump(V8JS::getExtensions());
$a = new V8Js('myobj', array(), array('b'));

View File

@ -1,48 +0,0 @@
<?php
// Test class
class Testing
{
public $foo = 'ORIGINAL';
private $my_private = 'arf'; // Should not show in JS side
protected $my_protected = 'argh'; // Should not show in JS side
function mytest($a, $b, $c = NULL)
{
var_dump(func_get_args());
}
}
$a = new V8Js();
$a->myobj = new Testing();
$a->executeString("PHP.myobj.mytest('arg1', 'arg2');", "test1.js");
$a->executeString("PHP.myobj.mytest(true, false, 1234567890);", "test2.js");
$a->executeString("PHP.myobj.mytest(3.14, 42, null);", "test3.js");
// Invalid parameters
try {
$a->executeString("PHP.myobj.mytest();", "test4.js");
} catch (V8JsScriptException $e) {
echo $e->getMessage(), "\n";
}
try {
$a->executeString("PHP.myobj.mytest('arg1', 'arg2', 'arg3', 'extra_arg');", "test5.js");
} catch (V8JsScriptException $e) {
echo $e->getMessage(), "\n";
}
// Array / Object
try {
// date_default_timezone_set("UTC");
$a->executeString("date = new Date('September 8, 1975 09:00:00'); PHP.print(date); PHP.myobj.mytest(date, PHP.myobj, new Array(1,2,3));", "test6.js");
} catch (V8JsScriptException $e) {
var_dump($e);
}
try {
$a->executeString("PHP.myobj.mytest(PHP.myobj, new Array(1,2,3), new Array('foo', 'bar', PHP.myobj));", "test7.js");
} catch (V8JsScriptException $e) {
var_dump($e);
}

173
test.php
View File

@ -1,173 +0,0 @@
<?php
/*
$v8 = new V8Js;
$v8->func = function ($a) { return var_export(func_get_args(), TRUE); };
$v8->executeString("PHP.func();", "arg_test1.js");
exit;
*/
var_dump(V8Js::registerExtension('myparser.js', 'function foo() { print("foobar!\n"}', array('jstparser.js', 'json-template.js'), false));
var_dump(V8Js::registerExtension('myparser.js', 'function foo() { print("foobar!\n"}', array('jstparser.js', 'json-template.js'), false));
var_dump(V8Js::registerExtension('jstparser.js', file_get_contents('js/jstparser.js'), array(), false));
//V8Js::registerExtension('json-template.js', file_get_contents('js/json-template.js'), array(), false);
var_dump(V8JS::getExtensions());
$a = new V8Js('myobj', array(), array('jstparser.js'));
$jstparser = <<< 'EOT'
var template = 'Gold &amp; Hot Rod Red, as seen in the new <a href="http://blog.markturansky.com/archives/51">Iron Man trailer</a>!' + "\n" +
'<table cellspacing="0" cellpadding="4">' + "\n" +
' <% for(var i = 0; i < 10; i++){ %> ' + "\n" +
' <tr>' + "\n" +
' <td style="background-color: <%= i % 2 == 0 ? \'red\' : \'gold\' %>">' + "\n" +
' Hi, <%=name%>! i is <%= i %>' + "\n" +
' </td>' + "\n" +
' </tr>' + "\n" +
' <% } %>' + "\n" +
'</table>' + "\n" +
'Note that name is HTML escaped by default. Here it is without escaping:'+
'<%+ name %>';
Jst.evaluateSingleShot(template, {"name":"foobar"});
EOT;
echo($a->executeString($jstparser, "ext_test1.js")), "\n";
$a->_SERVER = $_SERVER;
$a->func = function ($a) { echo "Closure..\n"; };
$a->executeString("print(myobj._SERVER['HOSTNAME']);", "test1.js");
$a->executeString("print(myobj.func); myobj.func(1);", "closure_test.js");
$JS = <<<'EOT'
function dump(a)
{
for (var i in a) {
var val = a[i];
print(i + ' => ' + val + "\n");
}
}
function foo()
{
var bar = 'bar';
var foo = 'foo';
return foo + bar;
}
function test()
{
var a = 'PHP version: ' + PHP.phpver;
phpver = 'changed in JS!';
return a;
}
function loop()
{
var foo = 'foo';
while(true)
{
foo + 'bar';
}
}
function output()
{
while(true)
{
print("output:foo\n");
sleep(5);
exit();
}
};
function simplearray()
{
print(myarray.a + "\n");
print(myarray.b + "\n");
print(myarray.c + "\n");
print(myarray.d + "\n");
}
function bigarray()
{
print(PHP.$_SERVER['HOSTNAME'] + "\n");
print(PHP.$_SERVER.argv + "\n");
}
EOT;
$jsontemplate = <<< EOT
var t = jsontemplate.Template("{# This is a comment and will be removed from the output.}{.section songs}<h2>Songs in '{playlist-name}'</h2><table width=\"100%\">{.repeated section @}<tr><td><a href=\"{url-base|htmltag}{url|htmltag}\">Play</a><td><i>{title}</i></td><td>{artist}</td></tr>{.end}</table>{.or}<p><em>(No page content matches)</em></p>{.end}");
t.expand({
"url-base": "http://example.com/music/",
"playlist-name": "Epic Playlist",
"songs": [
{
"url": "1.mp3",
"artist": "Grayceon",
"title": "Sounds Like Thunder"
},
{
"url": "2.mp3",
"artist": "Thou",
"title": "Their Hooves Carve Craters in the Earth"
}]});
EOT;
class tester
{
public $foo = 'bar';
private $my_private = 'arf';
protected $my_protected = 'argh';
function mytest() { echo 'Here be monsters..', "\n"; }
}
$a = new V8Js();
$a->obj = new tester();
$a->phpver = phpversion();
$a->argv = $_SERVER['argv'];
$a->integer = 1;
$a->float = 3.14;
$a->{'$'._SERVER} = $_SERVER;
$a->GLOBALS = $GLOBALS;
$a->myarray = array(
'a' => 'Array value for key A',
'b' => 'Array value for key B',
'c' => 'Array value for key C',
'd' => 'Array value for key D',
);
$a->arr = array("first", "second", "third");
$a->executeString($JS, "test1.js");
$a->executeString("bigarray()", "test1.js");
try {
echo($a->executeString($jstparser, "test2.js")), "\n";
var_dump($a->executeString($jsontemplate, "test1.js"));
} catch (V8JsScriptException $e) {
echo $e->getMessage();
}
// Test for context handling
$a->executeString($JS, "test1.js");
$a->executeString("bigarray();");
echo '$a->obj: ', "\n"; $a->executeString("dump(PHP.obj);");
echo '$a->arr: ', "\n"; $a->executeString("dump(PHP.arr);");
echo '$a->argv: ', "\n"; $a->executeString("dump(PHP.argv);");
var_dump($a->argv);
var_dump($a->executeString("test();"));
var_dump($a->executeString("test();"));
$b = new V8Js();
var_dump($a->phpver, $a->executeString("test();"));
$b->executeString($JS, "test2.js");
var_dump($b->executeString("test();"));
var_dump($b->executeString("print('foobar\\n');"));
// Exception methods
try {
$b->executeString("foobar; foo();", "extest.js");
} catch (V8JsScriptException $e) {
var_dump($e, $e->getJsFileName(), $e->getJsLineNumber(), $e->getJsSourceLine(), $e->getJsTrace());
}