Skip to content

Commit 342ba91

Browse files
committed
improve function performance (when return type is checked)
1 parent 3819d6c commit 342ba91

2 files changed

Lines changed: 55 additions & 24 deletions

File tree

src/ast/function.js

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,28 @@ var fn = AST.extends(function(parent, node) {
2222
fn.prototype.checkArgumentType = function (nullable, name, type, indent, errTrigger) {
2323
var checks = [];
2424
if (nullable) {
25-
checks.push(indent + 'if(' + name + ' != null) {\n');
25+
checks.push(indent + 'if (' + name + ' != null) {\n');
2626
indent += ' ';
2727
}
2828
if (type === 'self') {
29-
checks.push(indent + 'if(!(' + name + ' instanceof this))' + errTrigger);
29+
checks.push(indent + 'if (!(' + name + ' instanceof this))' + errTrigger);
3030
} else if (type === 'array') {
31-
checks.push(indent + 'if(!Array.isArray(' + name + '))' + errTrigger);
31+
checks.push(indent + 'if (!Array.isArray(' + name + '))' + errTrigger);
3232
} else if (type === 'callable') {
3333
// @fixme arrays / strings can also be valid callable
3434
// http://php.net/manual/en/language.types.callable.php
35-
checks.push(indent + 'if(typeof ' + name + ' !== \'function\')' + errTrigger);
35+
checks.push(indent + 'if (typeof ' + name + ' !== \'function\')' + errTrigger);
3636
} else if (type === 'bool') {
37-
checks.push(indent + 'if(typeof ' + name + ' !== \'boolean\' && !(' + name + ' instanceof Boolean))' + errTrigger);
37+
checks.push(indent + 'if (typeof ' + name + ' !== \'boolean\' && !(' + name + ' instanceof Boolean))' + errTrigger);
3838
} else if (type === 'float') {
39-
checks.push(indent + 'if(typeof ' + name + ' !== \'number\' || ' + name + ' % 1 === 0)' + errTrigger);
39+
checks.push(indent + 'if (typeof ' + name + ' !== \'number\' || ' + name + ' % 1 === 0)' + errTrigger);
4040
} else if (type === 'int') {
41-
checks.push(indent + 'if(typeof ' + name + ' !== \'number\' || ' + name + ' % 1 !== 0)' + errTrigger);
41+
checks.push(indent + 'if (typeof ' + name + ' !== \'number\' || ' + name + ' % 1 !== 0)' + errTrigger);
4242
} else if (type === 'string') {
43-
checks.push(indent + 'if(typeof ' + name + ' !== \'string\' && !(' + name + ' instanceof String))' + errTrigger);
43+
checks.push(indent + 'if (typeof ' + name + ' !== \'string\' && !(' + name + ' instanceof String))' + errTrigger);
4444
} else {
4545
// check the class
46-
checks.push(indent + 'if(!' + name + '.is(\'' + type + '\'))' + errTrigger);
46+
checks.push(indent + 'if (!' + name + '.is(\'' + type + '\'))' + errTrigger);
4747
}
4848
if (nullable) {
4949
indent = indent.substring(0, indent.length - 2);
@@ -68,15 +68,19 @@ fn.prototype.toString = function (indent) {
6868

6969
// arguments
7070
var parameters = [];
71-
var checks = [];
71+
var typeChecks = [];
72+
var defaultChecks = [];
73+
var argsReflection = [];
7274
indent += ' ';
7375

7476
for(var i = 0; i < this.node.arguments.length; i++) {
7577
var arg = this.node.arguments[i];
7678
parameters.push(arg.name);
79+
var argItem = { name: arg.name };
7780
if (!arg.variadic) {
7881
if (arg.type) {
79-
checks = checks.concat(
82+
argItem.type = arg.type;
83+
typeChecks = typeChecks.concat(
8084
this.checkArgumentType(
8185
arg.nullable || (
8286
arg.value && arg.value.kind === 'constref' &&
@@ -91,18 +95,19 @@ fn.prototype.toString = function (indent) {
9195
);
9296
}
9397
if (arg.value) {
98+
argItem.default = arg.value;
9499
// @todo sets a default value if not defined
95-
checks.push(indent + 'if (typeof ' + arg.name + ' === \'undefined\') ' + arg.name + ' = null;\n');
100+
defaultChecks.push(indent + 'if (typeof ' + arg.name + ' === \'undefined\') ' + arg.name + ' = null;\n');
96101
}
97102
} else {
98103
// handle variadic arguments
99-
checks.push(
104+
defaultChecks.push(
100105
indent + arg.name + ' = Array.prototype.slice.call(arguments, ' + i + ');'
101106
);
102107
if (arg.type) {
103108
// check each variadic argument
104-
checks.push(indent + 'for(var $i = 0; $i < ' + arg.name + '.length; $i++) {\n');
105-
checks = checks.concat(
109+
typeChecks.push(indent + 'for(var $i = 0; $i < ' + arg.name + '.length; $i++) {\n');
110+
typeChecks = typeChecks.concat(
106111
this.checkArgumentType(
107112
arg.nullable || (
108113
arg.value && arg.value.kind === 'constref' &&
@@ -115,39 +120,53 @@ fn.prototype.toString = function (indent) {
115120
' $php.type_error(' + i + ', \'' + arg.name + '\', \'' + name + '\', \'' + arg.type + '\', ' + arg.name + ');'
116121
)
117122
);
118-
checks.push(indent + '}');
123+
typeChecks.push(indent + '}');
119124
}
120125
}
126+
argsReflection.push(argItem);
121127
}
122128

123129
// function body
124130
buffer += parameters.join(', ') + ') {\n';
125-
if (checks.length > 0) {
126-
buffer += checks.join('\n') + '\n';
131+
if (defaultChecks.length > 0) {
132+
buffer += defaultChecks.join('\n') + '\n';
133+
}
134+
if (typeChecks.length > 0) {
135+
buffer += indent + 'if ($php.context.strictTypes) {\n';
136+
buffer += ' ' + typeChecks.join('\n ') + '\n';
137+
buffer += indent + '}\n';
127138
}
128139
buffer += this.variablesToString(indent);
140+
var returnType = 'null';
129141
if (this.node.type) {
130-
buffer += indent + 'var $result = (function() {\n';
142+
returnType = '\''+this.node.type+'\'';
143+
buffer += indent + 'var $result;\n';
144+
buffer += indent + 'do {\n';
131145
buffer += AST.prototype.toString.apply(this, [indent + ' ']);
132-
buffer += indent + '})();\n';
133-
buffer += this.checkArgumentType(
146+
buffer += indent + '} while(false);\n';
147+
buffer += indent + 'if ($php.context.strictTypes) {\n';
148+
buffer += ' ' + this.checkArgumentType(
134149
this.node.nullable,
135150
'$result',
136151
this.node.type,
137152
indent,
138153
' $php.type_error(-1, null, \'' + name + '\', \'' + this.node.type + '\', $result);'
139-
).join('\n');
140-
buffer += '\n' + indent + 'return $result;\n';
154+
).join('\n ') + '\n' + indent + '}\n';
141155
} else {
142156
buffer += AST.prototype.toString.apply(this, [indent]);
143157
}
158+
buffer += indent + 'return $result;\n';
144159
indent = indent.substring(0, indent.length - 2);
145160
buffer += indent + '}';
146161

147162
// encapsulate
148163
if (this.node.kind === 'function') {
149164
// global function
150-
buffer = indent + '$php.context.function.declare(\''+this.node.name+'\', ' + buffer + ');\n'
165+
var body = buffer;
166+
buffer = indent + '$php.context.function.declare(\n';
167+
buffer += indent + ' \''+this.node.name+'\',\n';
168+
buffer += indent + ' '+JSON.stringify(argsReflection)+',\n';
169+
buffer += indent + ' '+returnType+', ' + body + ');\n';
151170
} else if (this.node.kind === 'method') {
152171
// @todo method declaration
153172
} else if (!(this._parent instanceof Statement)) {

src/ast/return.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
'use strict';
77

88
var Statement = require('./statement');
9+
var Fn = require('./function');
910
var AST = require('../ast');
1011

1112
/**
@@ -19,8 +20,19 @@ var Return = Statement.extends(function(parent) {
1920
* Outputs the statement
2021
*/
2122
Return.prototype.toString = function (indent) {
23+
var fn = this.parent(Fn);
2224
var buffer = 'return ';
25+
if (fn && fn.node.type) {
26+
buffer = '$result = ';
27+
}
2328
buffer += AST.prototype.toString.apply(this, [indent]);
29+
if (fn && fn.node.type) {
30+
if (this._parent instanceof Statement) {
31+
buffer = '(' + buffer + ', break)';
32+
} else {
33+
buffer += ';\n' + indent + 'break';
34+
}
35+
}
2436
if (this._parent instanceof Statement) {
2537
return buffer;
2638
} else {

0 commit comments

Comments
 (0)