mirror of
https://github.com/phpv8/v8js.git
synced 2024-12-22 23:51:51 +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:
parent
da89fa257b
commit
2b4d41abb1
@ -7,14 +7,3 @@ endif
|
|||||||
ifneq (,$(realpath $(EXTENSION_DIR)/pthreads.so))
|
ifneq (,$(realpath $(EXTENSION_DIR)/pthreads.so))
|
||||||
PHP_TEST_SHARED_EXTENSIONS+=-d extension=$(EXTENSION_DIR)/pthreads.so
|
PHP_TEST_SHARED_EXTENSIONS+=-d extension=$(EXTENSION_DIR)/pthreads.so
|
||||||
endif
|
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
6
TODO
@ -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
|
|
@ -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,'<');
|
|
||||||
}
|
|
||||||
|
|
||||||
function HtmlTagEscape(s) {
|
|
||||||
return s.replace(/&/g,'&').
|
|
||||||
replace(/>/g,'>').
|
|
||||||
replace(/</g,'<').
|
|
||||||
replace(/"/g,'"');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
};
|
|
||||||
|
|
||||||
}();
|
|
339
js/jstparser.js
339
js/jstparser.js
@ -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('&', '&');
|
|
||||||
s = s.replaceAll('"', '"');
|
|
||||||
s = s.replaceAll('<', '<');
|
|
||||||
s = s.replaceAll('>', '>');
|
|
||||||
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;
|
|
||||||
}();
|
|
18
package.xml
18
package.xml
@ -17,7 +17,7 @@
|
|||||||
<active>yes</active>
|
<active>yes</active>
|
||||||
</lead>
|
</lead>
|
||||||
<date>2016-03-25</date>
|
<date>2016-03-25</date>
|
||||||
<time>23:24:51</time>
|
<time>23:46:59</time>
|
||||||
<version>
|
<version>
|
||||||
<release>0.6.2</release>
|
<release>0.6.2</release>
|
||||||
<api>0.6.2</api>
|
<api>0.6.2</api>
|
||||||
@ -34,20 +34,6 @@
|
|||||||
</notes>
|
</notes>
|
||||||
<contents>
|
<contents>
|
||||||
<dir baseinstalldir="/" name="/">
|
<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="30d379088150c4d4dd0cd97ea21d8156" name="tests/array_access.phpt" role="test" />
|
||||||
<file baseinstalldir="/" md5sum="c91b16332cdc186ecf8a8dc5581f17c7" name="tests/array_access_001.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" />
|
<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="d686d8e52af92521d4b8b0e86d00c463" name="README.MacOS.md" role="doc" />
|
||||||
<file baseinstalldir="/" md5sum="6d8116bb5ab12cb5032c04315da06265" name="README.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="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="16c060e49d1b2c477531758e1de4850e" name="v8js.cc" role="src" />
|
||||||
<file baseinstalldir="/" md5sum="358c628b2627319e40fd7e5092f19872" name="v8js_array_access.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" />
|
<file baseinstalldir="/" md5sum="7baf3fe5b77d1374b39a1d8332e05df4" name="v8js_array_access.h" role="src" />
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
Ignore dlopen bug #1.
|
|
||||||
Memcheck:Leak
|
|
||||||
...
|
|
||||||
fun:_dl_open
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Ignore dlopen bug #2.
|
|
||||||
Memcheck:Leak
|
|
||||||
...
|
|
||||||
fun:_dl_close
|
|
||||||
...
|
|
||||||
}
|
|
@ -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";
|
|
||||||
}
|
|
@ -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"; } });');
|
|
||||||
|
|
@ -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";
|
|
||||||
}
|
|
@ -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 %>", {});'));
|
|
||||||
}
|
|
@ -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";
|
|
||||||
}
|
|
@ -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";
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
@ -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'));
|
|
||||||
|
|
@ -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
173
test.php
@ -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 & 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());
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user