2013-02-19 11:27:20 -05:00
/ *
Copyright ( C ) 2011 by Yehuda Katz
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 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 .
* /
2013-02-05 14:16:51 -05:00
// lib/handlebars/base.js
/*jshint eqnull:true*/
this . Handlebars = { } ;
( function ( Handlebars ) {
2013-02-19 11:27:20 -05:00
Handlebars . VERSION = "1.0.0-rc.3" ;
Handlebars . COMPILER _REVISION = 2 ;
Handlebars . REVISION _CHANGES = {
1 : '<= 1.0.rc.2' , // 1.0.rc.2 is actually rev2 but doesn't report it
2 : '>= 1.0.0-rc.3'
} ;
2013-02-05 14:16:51 -05:00
Handlebars . helpers = { } ;
Handlebars . partials = { } ;
Handlebars . registerHelper = function ( name , fn , inverse ) {
if ( inverse ) { fn . not = inverse ; }
this . helpers [ name ] = fn ;
} ;
Handlebars . registerPartial = function ( name , str ) {
this . partials [ name ] = str ;
} ;
Handlebars . registerHelper ( 'helperMissing' , function ( arg ) {
if ( arguments . length === 2 ) {
return undefined ;
} else {
throw new Error ( "Could not find property '" + arg + "'" ) ;
}
} ) ;
var toString = Object . prototype . toString , functionType = "[object Function]" ;
Handlebars . registerHelper ( 'blockHelperMissing' , function ( context , options ) {
var inverse = options . inverse || function ( ) { } , fn = options . fn ;
var ret = "" ;
var type = toString . call ( context ) ;
if ( type === functionType ) { context = context . call ( this ) ; }
if ( context === true ) {
return fn ( this ) ;
} else if ( context === false || context == null ) {
return inverse ( this ) ;
} else if ( type === "[object Array]" ) {
if ( context . length > 0 ) {
return Handlebars . helpers . each ( context , options ) ;
} else {
return inverse ( this ) ;
}
} else {
return fn ( context ) ;
}
} ) ;
Handlebars . K = function ( ) { } ;
Handlebars . createFrame = Object . create || function ( object ) {
Handlebars . K . prototype = object ;
var obj = new Handlebars . K ( ) ;
Handlebars . K . prototype = null ;
return obj ;
} ;
Handlebars . logger = {
DEBUG : 0 , INFO : 1 , WARN : 2 , ERROR : 3 , level : 3 ,
methodMap : { 0 : 'debug' , 1 : 'info' , 2 : 'warn' , 3 : 'error' } ,
// can be overridden in the host environment
log : function ( level , obj ) {
if ( Handlebars . logger . level <= level ) {
var method = Handlebars . logger . methodMap [ level ] ;
if ( typeof console !== 'undefined' && console [ method ] ) {
console [ method ] . call ( console , obj ) ;
}
}
}
} ;
Handlebars . log = function ( level , obj ) { Handlebars . logger . log ( level , obj ) ; } ;
Handlebars . registerHelper ( 'each' , function ( context , options ) {
var fn = options . fn , inverse = options . inverse ;
var i = 0 , ret = "" , data ;
if ( options . data ) {
data = Handlebars . createFrame ( options . data ) ;
}
if ( context && typeof context === 'object' ) {
if ( context instanceof Array ) {
for ( var j = context . length ; i < j ; i ++ ) {
if ( data ) { data . index = i ; }
ret = ret + fn ( context [ i ] , { data : data } ) ;
}
} else {
for ( var key in context ) {
if ( context . hasOwnProperty ( key ) ) {
if ( data ) { data . key = key ; }
ret = ret + fn ( context [ key ] , { data : data } ) ;
i ++ ;
}
}
}
}
if ( i === 0 ) {
ret = inverse ( this ) ;
}
return ret ;
} ) ;
Handlebars . registerHelper ( 'if' , function ( context , options ) {
var type = toString . call ( context ) ;
if ( type === functionType ) { context = context . call ( this ) ; }
if ( ! context || Handlebars . Utils . isEmpty ( context ) ) {
return options . inverse ( this ) ;
} else {
return options . fn ( this ) ;
}
} ) ;
Handlebars . registerHelper ( 'unless' , function ( context , options ) {
var fn = options . fn , inverse = options . inverse ;
options . fn = inverse ;
options . inverse = fn ;
return Handlebars . helpers [ 'if' ] . call ( this , context , options ) ;
} ) ;
Handlebars . registerHelper ( 'with' , function ( context , options ) {
return options . fn ( context ) ;
} ) ;
Handlebars . registerHelper ( 'log' , function ( context , options ) {
var level = options . data && options . data . level != null ? parseInt ( options . data . level , 10 ) : 1 ;
Handlebars . log ( level , context ) ;
} ) ;
} ( this . Handlebars ) ) ;
;
// lib/handlebars/compiler/parser.js
/* Jison generated parser */
var handlebars = ( function ( ) {
var parser = { trace : function trace ( ) { } ,
yy : { } ,
symbols _ : { "error" : 2 , "root" : 3 , "program" : 4 , "EOF" : 5 , "simpleInverse" : 6 , "statements" : 7 , "statement" : 8 , "openInverse" : 9 , "closeBlock" : 10 , "openBlock" : 11 , "mustache" : 12 , "partial" : 13 , "CONTENT" : 14 , "COMMENT" : 15 , "OPEN_BLOCK" : 16 , "inMustache" : 17 , "CLOSE" : 18 , "OPEN_INVERSE" : 19 , "OPEN_ENDBLOCK" : 20 , "path" : 21 , "OPEN" : 22 , "OPEN_UNESCAPED" : 23 , "OPEN_PARTIAL" : 24 , "partialName" : 25 , "params" : 26 , "hash" : 27 , "DATA" : 28 , "param" : 29 , "STRING" : 30 , "INTEGER" : 31 , "BOOLEAN" : 32 , "hashSegments" : 33 , "hashSegment" : 34 , "ID" : 35 , "EQUALS" : 36 , "PARTIAL_NAME" : 37 , "pathSegments" : 38 , "SEP" : 39 , "$accept" : 0 , "$end" : 1 } ,
terminals _ : { 2 : "error" , 5 : "EOF" , 14 : "CONTENT" , 15 : "COMMENT" , 16 : "OPEN_BLOCK" , 18 : "CLOSE" , 19 : "OPEN_INVERSE" , 20 : "OPEN_ENDBLOCK" , 22 : "OPEN" , 23 : "OPEN_UNESCAPED" , 24 : "OPEN_PARTIAL" , 28 : "DATA" , 30 : "STRING" , 31 : "INTEGER" , 32 : "BOOLEAN" , 35 : "ID" , 36 : "EQUALS" , 37 : "PARTIAL_NAME" , 39 : "SEP" } ,
productions _ : [ 0 , [ 3 , 2 ] , [ 4 , 2 ] , [ 4 , 3 ] , [ 4 , 2 ] , [ 4 , 1 ] , [ 4 , 1 ] , [ 4 , 0 ] , [ 7 , 1 ] , [ 7 , 2 ] , [ 8 , 3 ] , [ 8 , 3 ] , [ 8 , 1 ] , [ 8 , 1 ] , [ 8 , 1 ] , [ 8 , 1 ] , [ 11 , 3 ] , [ 9 , 3 ] , [ 10 , 3 ] , [ 12 , 3 ] , [ 12 , 3 ] , [ 13 , 3 ] , [ 13 , 4 ] , [ 6 , 2 ] , [ 17 , 3 ] , [ 17 , 2 ] , [ 17 , 2 ] , [ 17 , 1 ] , [ 17 , 1 ] , [ 26 , 2 ] , [ 26 , 1 ] , [ 29 , 1 ] , [ 29 , 1 ] , [ 29 , 1 ] , [ 29 , 1 ] , [ 29 , 1 ] , [ 27 , 1 ] , [ 33 , 2 ] , [ 33 , 1 ] , [ 34 , 3 ] , [ 34 , 3 ] , [ 34 , 3 ] , [ 34 , 3 ] , [ 34 , 3 ] , [ 25 , 1 ] , [ 21 , 1 ] , [ 38 , 3 ] , [ 38 , 1 ] ] ,
performAction : function anonymous ( yytext , yyleng , yylineno , yy , yystate , $$ , _$ ) {
var $0 = $$ . length - 1 ;
switch ( yystate ) {
case 1 : return $$ [ $0 - 1 ] ;
break ;
case 2 : this . $ = new yy . ProgramNode ( [ ] , $$ [ $0 ] ) ;
break ;
case 3 : this . $ = new yy . ProgramNode ( $$ [ $0 - 2 ] , $$ [ $0 ] ) ;
break ;
case 4 : this . $ = new yy . ProgramNode ( $$ [ $0 - 1 ] , [ ] ) ;
break ;
case 5 : this . $ = new yy . ProgramNode ( $$ [ $0 ] ) ;
break ;
case 6 : this . $ = new yy . ProgramNode ( [ ] , [ ] ) ;
break ;
case 7 : this . $ = new yy . ProgramNode ( [ ] ) ;
break ;
case 8 : this . $ = [ $$ [ $0 ] ] ;
break ;
case 9 : $$ [ $0 - 1 ] . push ( $$ [ $0 ] ) ; this . $ = $$ [ $0 - 1 ] ;
break ;
case 10 : this . $ = new yy . BlockNode ( $$ [ $0 - 2 ] , $$ [ $0 - 1 ] . inverse , $$ [ $0 - 1 ] , $$ [ $0 ] ) ;
break ;
case 11 : this . $ = new yy . BlockNode ( $$ [ $0 - 2 ] , $$ [ $0 - 1 ] , $$ [ $0 - 1 ] . inverse , $$ [ $0 ] ) ;
break ;
case 12 : this . $ = $$ [ $0 ] ;
break ;
case 13 : this . $ = $$ [ $0 ] ;
break ;
case 14 : this . $ = new yy . ContentNode ( $$ [ $0 ] ) ;
break ;
case 15 : this . $ = new yy . CommentNode ( $$ [ $0 ] ) ;
break ;
case 16 : this . $ = new yy . MustacheNode ( $$ [ $0 - 1 ] [ 0 ] , $$ [ $0 - 1 ] [ 1 ] ) ;
break ;
case 17 : this . $ = new yy . MustacheNode ( $$ [ $0 - 1 ] [ 0 ] , $$ [ $0 - 1 ] [ 1 ] ) ;
break ;
case 18 : this . $ = $$ [ $0 - 1 ] ;
break ;
case 19 : this . $ = new yy . MustacheNode ( $$ [ $0 - 1 ] [ 0 ] , $$ [ $0 - 1 ] [ 1 ] ) ;
break ;
case 20 : this . $ = new yy . MustacheNode ( $$ [ $0 - 1 ] [ 0 ] , $$ [ $0 - 1 ] [ 1 ] , true ) ;
break ;
case 21 : this . $ = new yy . PartialNode ( $$ [ $0 - 1 ] ) ;
break ;
case 22 : this . $ = new yy . PartialNode ( $$ [ $0 - 2 ] , $$ [ $0 - 1 ] ) ;
break ;
case 23 :
break ;
case 24 : this . $ = [ [ $$ [ $0 - 2 ] ] . concat ( $$ [ $0 - 1 ] ) , $$ [ $0 ] ] ;
break ;
case 25 : this . $ = [ [ $$ [ $0 - 1 ] ] . concat ( $$ [ $0 ] ) , null ] ;
break ;
case 26 : this . $ = [ [ $$ [ $0 - 1 ] ] , $$ [ $0 ] ] ;
break ;
case 27 : this . $ = [ [ $$ [ $0 ] ] , null ] ;
break ;
case 28 : this . $ = [ [ new yy . DataNode ( $$ [ $0 ] ) ] , null ] ;
break ;
case 29 : $$ [ $0 - 1 ] . push ( $$ [ $0 ] ) ; this . $ = $$ [ $0 - 1 ] ;
break ;
case 30 : this . $ = [ $$ [ $0 ] ] ;
break ;
case 31 : this . $ = $$ [ $0 ] ;
break ;
case 32 : this . $ = new yy . StringNode ( $$ [ $0 ] ) ;
break ;
case 33 : this . $ = new yy . IntegerNode ( $$ [ $0 ] ) ;
break ;
case 34 : this . $ = new yy . BooleanNode ( $$ [ $0 ] ) ;
break ;
case 35 : this . $ = new yy . DataNode ( $$ [ $0 ] ) ;
break ;
case 36 : this . $ = new yy . HashNode ( $$ [ $0 ] ) ;
break ;
case 37 : $$ [ $0 - 1 ] . push ( $$ [ $0 ] ) ; this . $ = $$ [ $0 - 1 ] ;
break ;
case 38 : this . $ = [ $$ [ $0 ] ] ;
break ;
case 39 : this . $ = [ $$ [ $0 - 2 ] , $$ [ $0 ] ] ;
break ;
case 40 : this . $ = [ $$ [ $0 - 2 ] , new yy . StringNode ( $$ [ $0 ] ) ] ;
break ;
case 41 : this . $ = [ $$ [ $0 - 2 ] , new yy . IntegerNode ( $$ [ $0 ] ) ] ;
break ;
case 42 : this . $ = [ $$ [ $0 - 2 ] , new yy . BooleanNode ( $$ [ $0 ] ) ] ;
break ;
case 43 : this . $ = [ $$ [ $0 - 2 ] , new yy . DataNode ( $$ [ $0 ] ) ] ;
break ;
case 44 : this . $ = new yy . PartialNameNode ( $$ [ $0 ] ) ;
break ;
case 45 : this . $ = new yy . IdNode ( $$ [ $0 ] ) ;
break ;
case 46 : $$ [ $0 - 2 ] . push ( $$ [ $0 ] ) ; this . $ = $$ [ $0 - 2 ] ;
break ;
case 47 : this . $ = [ $$ [ $0 ] ] ;
break ;
}
} ,
table : [ { 3 : 1 , 4 : 2 , 5 : [ 2 , 7 ] , 6 : 3 , 7 : 4 , 8 : 6 , 9 : 7 , 11 : 8 , 12 : 9 , 13 : 10 , 14 : [ 1 , 11 ] , 15 : [ 1 , 12 ] , 16 : [ 1 , 13 ] , 19 : [ 1 , 5 ] , 22 : [ 1 , 14 ] , 23 : [ 1 , 15 ] , 24 : [ 1 , 16 ] } , { 1 : [ 3 ] } , { 5 : [ 1 , 17 ] } , { 5 : [ 2 , 6 ] , 7 : 18 , 8 : 6 , 9 : 7 , 11 : 8 , 12 : 9 , 13 : 10 , 14 : [ 1 , 11 ] , 15 : [ 1 , 12 ] , 16 : [ 1 , 13 ] , 19 : [ 1 , 19 ] , 20 : [ 2 , 6 ] , 22 : [ 1 , 14 ] , 23 : [ 1 , 15 ] , 24 : [ 1 , 16 ] } , { 5 : [ 2 , 5 ] , 6 : 20 , 8 : 21 , 9 : 7 , 11 : 8 , 12 : 9 , 13 : 10 , 14 : [ 1 , 11 ] , 15 : [ 1 , 12 ] , 16 : [ 1 , 13 ] , 19 : [ 1 , 5 ] , 20 : [ 2 , 5 ] , 22 : [ 1 , 14 ] , 23 : [ 1 , 15 ] , 24 : [ 1 , 16 ] } , { 17 : 23 , 18 : [ 1 , 22 ] , 21 : 24 , 28 : [ 1 , 25 ] , 35 : [ 1 , 27 ] , 38 : 26 } , { 5 : [ 2 , 8 ] , 14 : [ 2 , 8 ] , 15 : [ 2 , 8 ] , 16 : [ 2 , 8 ] , 19 : [ 2 , 8 ] , 20 : [ 2 , 8 ] , 22 : [ 2 , 8 ] , 23 : [ 2 , 8 ] , 24 : [ 2 , 8 ] } , { 4 : 28 , 6 : 3 , 7 : 4 , 8 : 6 , 9 : 7 , 11 : 8 , 12 : 9 , 13 : 10 , 14 : [ 1 , 11 ] , 15 : [ 1 , 12 ] , 16 : [ 1 , 13 ] , 19 : [ 1 , 5 ] , 20 : [ 2 , 7 ] , 22 : [ 1 , 14 ] , 23 : [ 1 , 15 ] , 24 : [ 1 , 16 ] } , { 4 : 29 , 6 : 3 , 7 : 4 , 8 : 6 , 9 : 7 , 11 : 8 , 12 : 9 , 13 : 10 , 14 : [ 1 , 11 ] , 15 : [ 1 , 12 ] , 16 : [ 1 , 13 ] , 19 : [ 1 , 5 ] , 20 : [ 2 , 7 ] , 22 : [ 1 , 14 ] , 23 : [ 1 , 15 ] , 24 : [ 1 , 16 ] } , { 5 : [ 2 , 12 ] , 14 : [ 2 , 12 ] , 15 : [ 2 , 12 ] , 16 : [ 2 , 12 ] , 19 : [ 2 , 12 ] , 20 : [ 2 , 12 ] , 22 : [ 2 , 12 ] , 23 : [ 2 , 12 ] , 24 : [ 2 , 12 ] } , { 5 : [ 2 , 13 ] , 14 : [ 2 , 13 ] , 15 : [ 2 , 13 ] , 16 : [ 2 , 13 ] , 19 : [ 2 , 13 ] , 20 : [ 2 , 13 ] , 22 : [ 2 , 13 ] , 23 : [ 2 , 13 ] , 24 : [ 2 , 13 ] } , { 5 : [ 2 , 14 ] , 14 : [ 2 , 14 ] , 15 : [ 2 , 14 ] , 16 : [ 2 , 14 ] , 19 : [ 2 , 14 ] , 20 : [ 2 , 14 ] , 22 : [ 2 , 14 ] , 23 : [ 2 , 14 ] , 24 : [ 2 , 14 ] } , { 5 : [ 2 , 15 ] , 14 : [ 2 , 15 ] , 15 : [ 2 , 15 ] , 16 : [ 2 , 15 ] , 19 : [ 2 , 15 ] , 20 : [ 2 , 15 ] , 22 : [ 2 , 15 ] , 23 : [ 2 , 15 ] , 24 : [ 2 , 15 ] } , { 17 : 30 , 21 : 24 , 28 : [ 1 , 25 ] , 35 : [ 1 , 27 ] , 38 : 26 } , { 17 : 31 , 21 : 24 , 28 : [ 1 , 25 ] , 35 : [ 1 , 27 ] , 38 : 26 } , { 17 : 32 , 21 : 24 , 28 : [ 1 , 25 ] , 35 : [ 1 , 27 ] , 38 : 26 } , { 25 : 33 , 37 : [ 1 , 34 ] } , { 1 : [ 2 , 1 ] } , { 5 : [ 2 , 2 ] , 8 : 21 , 9 : 7 , 11 : 8 , 12 : 9 , 13 : 10 , 14 : [ 1 , 11 ] , 15 : [ 1 , 12 ] , 16 : [ 1 , 13 ] , 19 : [ 1 , 19 ] , 20 : [ 2 , 2 ] , 22 : [ 1 , 14 ] , 23 : [ 1 , 15 ] , 24 : [ 1 , 16 ] } , { 17 : 23 , 21 : 24 , 28 : [ 1 , 25 ] , 35 : [ 1 , 27 ] , 38 : 26 } , { 5 : [ 2 , 4 ] , 7 : 35 , 8 : 6 , 9 : 7 , 11 : 8 , 12 : 9 , 13 : 10 , 14 : [ 1 , 11 ] , 15 : [ 1 , 12 ] , 16 : [ 1 , 13 ] , 19 : [ 1 , 19 ] , 20 : [ 2 , 4 ] , 22 : [ 1 , 14 ] , 23 : [ 1 , 15 ] , 24 : [ 1 , 16 ] } , { 5 : [ 2 , 9 ] , 14 : [ 2 , 9 ] , 15 : [ 2 , 9 ] , 16 : [ 2 , 9 ] , 19 : [ 2 , 9 ] , 20 : [ 2 , 9 ] , 22 : [ 2 , 9 ] , 23 : [ 2 , 9 ] , 24 : [ 2 , 9 ] } , { 5 : [ 2 , 23 ] , 14 : [ 2 , 23 ] , 15 : [ 2 , 23 ] , 16 : [ 2 , 23 ] , 19 : [ 2 , 23 ] , 20 : [ 2 , 23 ] , 22 : [ 2 , 23 ] , 23 : [ 2 , 23 ] , 24 : [ 2 , 23 ] } , { 18 : [ 1 , 36 ] } , { 18 : [ 2 , 27 ] , 21 : 41 , 26 : 37 , 27 : 38 , 28 : [ 1 , 45 ] , 29 : 39 , 30 : [ 1 , 42 ] , 31 : [ 1 , 43 ] , 32 : [ 1 , 44 ] , 33 : 40 , 34 : 46 , 35 : [ 1 , 47 ] , 38 : 26 } , { 18 : [ 2 , 28 ] } , { 18 : [ 2 , 45 ] , 28 : [ 2 , 45 ] , 30 : [ 2 , 45 ] , 31 : [ 2 , 45 ] , 32 : [ 2 , 45 ] , 35 : [ 2 , 45 ] , 39 : [ 1 , 48 ] } , { 18 : [ 2 , 47 ] , 28 : [ 2 , 47 ] , 30 : [ 2 , 47 ] , 31 : [ 2 , 47 ] , 32 : [ 2 , 47 ] , 35 : [ 2 , 47 ] , 39 : [ 2 , 47 ] } , { 10 : 49 , 20 : [ 1 , 50 ] } , { 10 : 51 , 20 : [ 1 , 50 ] } , { 18 : [ 1 , 52 ] } , { 18 : [ 1 , 53 ] } , { 18 : [ 1 , 54 ] } , { 18 : [ 1 , 55 ] , 21 : 56 , 35 : [ 1 , 27 ] , 38 : 26 } , { 18 : [ 2 , 44 ] , 35 : [ 2 , 44 ] } , { 5 : [ 2 , 3 ] , 8 : 21 , 9 : 7 , 11 : 8 , 12 : 9 , 13 : 10 , 14 : [ 1 , 11 ] , 15 : [ 1 , 12 ] , 16 : [ 1 , 13 ] , 19 : [ 1 , 19 ] , 20 : [ 2 , 3 ] , 22 : [ 1 , 14 ] , 23 : [ 1 , 15 ] , 24 : [ 1 , 16 ] } , { 14 : [ 2 , 17 ] , 15 : [ 2 , 17 ] , 16 : [ 2 , 17 ] , 19 : [ 2 , 17 ] , 20 : [ 2 , 17 ] , 22 : [ 2 , 17 ] , 23 : [ 2 , 17 ] , 24 : [ 2 , 17 ] } , { 18 : [ 2 , 25 ] , 21 : 41 , 27 : 57 , 28 : [ 1 , 45 ] , 29 : 58 , 30 : [ 1 , 42 ] , 31 : [ 1 , 43 ] , 32 : [ 1 , 44 ] , 33 : 40 , 34 : 46 , 35 : [ 1 , 47 ] , 38 : 26 } , { 18 : [ 2 , 26 ] } , { 18 : [ 2 , 30 ] , 28 : [ 2 , 30 ] , 30 : [ 2 , 30 ] , 31 : [ 2 , 30 ] , 32 : [ 2 , 30 ] , 35 : [ 2 , 30 ] } , { 18 : [ 2 , 36 ] , 34 : 59 , 35 : [ 1 , 60 ] } , { 18 : [ 2 , 31 ] , 28 : [ 2 , 31 ] , 30 : [ 2 , 31 ] , 31 : [ 2 , 31 ] , 32 : [ 2 , 31 ] , 35 : [ 2 , 31 ] } , { 18 : [ 2 , 32 ] , 28 : [ 2 , 32 ] , 30 : [ 2 , 32 ] , 31 : [ 2 , 32 ] , 32 : [ 2 , 32 ] , 35 : [ 2 , 32 ] } , { 18 : [ 2 , 33 ] , 28 : [ 2 , 33 ] , 30 : [ 2 , 33 ] , 31 : [ 2 , 33 ] , 32 : [ 2 , 33 ] , 35 : [ 2 , 33 ] } , { 18 : [ 2 , 34 ] , 28 : [ 2 , 34 ] , 30 : [ 2 , 34 ] , 31 : [ 2 , 34 ] , 32 : [ 2 , 34 ] , 35 : [ 2 , 34 ] } , { 18 : [ 2 , 35 ] , 28 : [ 2 , 35 ] , 30 : [ 2 , 35 ] , 31 : [ 2 , 35 ] , 32 : [ 2 , 35 ] , 35 : [ 2 , 35 ] } , { 18 : [ 2 , 38 ] , 35 : [ 2 , 38 ] } , { 18 : [ 2 , 47 ] , 28 : [ 2 , 47 ] , 30 : [ 2 , 47 ] , 31 : [ 2 , 47 ] , 32 : [ 2 , 47 ] , 35 : [ 2 , 47 ] , 36 : [ 1 , 61 ] , 39 : [ 2 , 47 ] } , { 35 : [ 1 , 62 ] } , { 5 : [ 2 , 10 ] , 14 : [ 2 , 10 ] , 15 : [ 2 , 10 ] , 16 : [ 2 , 10 ] , 19 : [ 2 , 10 ] , 20 : [ 2 , 10 ] , 22 : [ 2 , 10 ] , 23 : [ 2 , 10 ] , 24 : [ 2 , 10 ] } , { 21 : 63 , 35 : [ 1 , 27 ] , 38 : 26 } , { 5 : [ 2 , 11 ] , 14 : [ 2 , 11 ] , 15 : [ 2 , 11 ] , 16 : [ 2 , 11 ] , 19 : [ 2 , 11 ] , 20 : [ 2 , 11 ] , 22 : [ 2 , 11 ] , 23 : [ 2 , 11 ] , 24 : [ 2 , 11 ] } , { 14 : [ 2 , 16 ] , 15 : [ 2 , 16 ] , 16 : [ 2 , 16 ] , 19 : [ 2 , 16 ] , 20 : [ 2 , 16 ] , 22 : [ 2 , 16 ] , 23 : [ 2 , 16 ] , 24 : [ 2 , 16 ] } , { 5 : [ 2 , 19 ] , 14 : [ 2 , 19 ] , 15 : [ 2 , 19 ] , 16 : [ 2 , 19 ] , 19 : [ 2 , 19 ] , 20 : [ 2 , 19 ] , 22 : [ 2 , 19 ] , 23 : [ 2 , 19 ] , 24 : [ 2 , 19 ] } , { 5 : [ 2 , 20 ] , 14 : [ 2 , 20 ] , 15 : [ 2 , 20 ] , 16 : [ 2 , 20 ] , 19 : [ 2 , 20 ] , 20 : [ 2 , 20 ] , 22 : [ 2 , 20 ] , 23 : [ 2 , 20 ] , 24 : [ 2 , 20 ] } , { 5 : [ 2 , 21 ] , 14 : [ 2 , 21 ] , 15 : [ 2 , 21 ] , 16 : [ 2 , 21 ] , 19 : [ 2 , 21 ] , 20 : [ 2 , 21 ] , 22 : [ 2 , 21 ] , 23 : [ 2 , 21 ] , 24 : [ 2 , 21 ] } , { 18 : [ 1 , 64 ] } , { 18 : [ 2 , 24 ] } , { 18 : [ 2 , 29 ] , 28 : [ 2 , 29 ] , 30 : [ 2 , 29 ] , 31 : [ 2 , 29 ] , 32 : [ 2 , 29 ] , 35 : [ 2 , 29 ] } , { 18 : [ 2 , 37 ] , 35 : [ 2 , 37 ] } , { 36 : [ 1 , 61 ] } , { 21 : 65 , 28 : [ 1 , 69 ] , 30 : [ 1 , 66 ] , 31 : [ 1 , 67 ] , 32 : [ 1 , 68 ] , 35 : [ 1 , 27 ] , 38 : 26 } , { 18 : [ 2 , 46 ] , 28 : [ 2 , 46 ] , 30 : [ 2 , 46 ] , 31 : [ 2 , 46 ] , 32 : [ 2 , 46 ] , 35 : [ 2 , 46 ] , 39 : [ 2 , 46 ] } , { 18 : [ 1 , 70 ] } , { 5 : [ 2 , 22 ] , 14 : [ 2 , 22 ] , 15 : [ 2 , 22 ] , 16 : [ 2 , 22 ] , 19 : [ 2 , 22 ] , 20 : [ 2 , 22 ] , 22 : [ 2 , 22 ] , 23 : [ 2 , 22 ] , 24 : [ 2 , 22 ] } , { 18 : [ 2 , 39 ] , 35 : [ 2 , 39 ] } , { 18 : [ 2 , 40 ] , 35 : [ 2 , 40 ] } , { 18 : [ 2 , 41 ] , 35 : [ 2 , 41 ] } , { 18 : [ 2 , 42 ] , 35 : [ 2 , 42 ] } , { 18 : [ 2 , 43 ] , 35 : [ 2 , 43 ] } , { 5 : [ 2 , 18 ] , 14 : [ 2 , 18 ] , 15 : [ 2 , 18 ] , 16 : [ 2 , 18 ] , 19 : [ 2 , 18 ] , 20 : [ 2 , 18 ] , 22 : [ 2 , 18 ] , 23 : [ 2 , 18 ] , 24 : [ 2 , 18 ] } ] ,
defaultActions : { 17 : [ 2 , 1 ] , 25 : [ 2 , 28 ] , 38 : [ 2 , 26 ] , 57 : [ 2 , 24 ] } ,
parseError : function parseError ( str , hash ) {
throw new Error ( str ) ;
} ,
parse : function parse ( input ) {
var self = this , stack = [ 0 ] , vstack = [ null ] , lstack = [ ] , table = this . table , yytext = "" , yylineno = 0 , yyleng = 0 , recovering = 0 , TERROR = 2 , EOF = 1 ;
this . lexer . setInput ( input ) ;
this . lexer . yy = this . yy ;
this . yy . lexer = this . lexer ;
this . yy . parser = this ;
if ( typeof this . lexer . yylloc == "undefined" )
this . lexer . yylloc = { } ;
var yyloc = this . lexer . yylloc ;
lstack . push ( yyloc ) ;
var ranges = this . lexer . options && this . lexer . options . ranges ;
if ( typeof this . yy . parseError === "function" )
this . parseError = this . yy . parseError ;
function popStack ( n ) {
stack . length = stack . length - 2 * n ;
vstack . length = vstack . length - n ;
lstack . length = lstack . length - n ;
}
function lex ( ) {
var token ;
token = self . lexer . lex ( ) || 1 ;
if ( typeof token !== "number" ) {
token = self . symbols _ [ token ] || token ;
}
return token ;
}
var symbol , preErrorSymbol , state , action , a , r , yyval = { } , p , len , newState , expected ;
while ( true ) {
state = stack [ stack . length - 1 ] ;
if ( this . defaultActions [ state ] ) {
action = this . defaultActions [ state ] ;
} else {
if ( symbol === null || typeof symbol == "undefined" ) {
symbol = lex ( ) ;
}
action = table [ state ] && table [ state ] [ symbol ] ;
}
if ( typeof action === "undefined" || ! action . length || ! action [ 0 ] ) {
var errStr = "" ;
if ( ! recovering ) {
expected = [ ] ;
for ( p in table [ state ] )
if ( this . terminals _ [ p ] && p > 2 ) {
expected . push ( "'" + this . terminals _ [ p ] + "'" ) ;
}
if ( this . lexer . showPosition ) {
errStr = "Parse error on line " + ( yylineno + 1 ) + ":\n" + this . lexer . showPosition ( ) + "\nExpecting " + expected . join ( ", " ) + ", got '" + ( this . terminals _ [ symbol ] || symbol ) + "'" ;
} else {
errStr = "Parse error on line " + ( yylineno + 1 ) + ": Unexpected " + ( symbol == 1 ? "end of input" : "'" + ( this . terminals _ [ symbol ] || symbol ) + "'" ) ;
}
this . parseError ( errStr , { text : this . lexer . match , token : this . terminals _ [ symbol ] || symbol , line : this . lexer . yylineno , loc : yyloc , expected : expected } ) ;
}
}
if ( action [ 0 ] instanceof Array && action . length > 1 ) {
throw new Error ( "Parse Error: multiple actions possible at state: " + state + ", token: " + symbol ) ;
}
switch ( action [ 0 ] ) {
case 1 :
stack . push ( symbol ) ;
vstack . push ( this . lexer . yytext ) ;
lstack . push ( this . lexer . yylloc ) ;
stack . push ( action [ 1 ] ) ;
symbol = null ;
if ( ! preErrorSymbol ) {
yyleng = this . lexer . yyleng ;
yytext = this . lexer . yytext ;
yylineno = this . lexer . yylineno ;
yyloc = this . lexer . yylloc ;
if ( recovering > 0 )
recovering -- ;
} else {
symbol = preErrorSymbol ;
preErrorSymbol = null ;
}
break ;
case 2 :
len = this . productions _ [ action [ 1 ] ] [ 1 ] ;
yyval . $ = vstack [ vstack . length - len ] ;
yyval . _$ = { first _line : lstack [ lstack . length - ( len || 1 ) ] . first _line , last _line : lstack [ lstack . length - 1 ] . last _line , first _column : lstack [ lstack . length - ( len || 1 ) ] . first _column , last _column : lstack [ lstack . length - 1 ] . last _column } ;
if ( ranges ) {
yyval . _$ . range = [ lstack [ lstack . length - ( len || 1 ) ] . range [ 0 ] , lstack [ lstack . length - 1 ] . range [ 1 ] ] ;
}
r = this . performAction . call ( yyval , yytext , yyleng , yylineno , this . yy , action [ 1 ] , vstack , lstack ) ;
if ( typeof r !== "undefined" ) {
return r ;
}
if ( len ) {
stack = stack . slice ( 0 , - 1 * len * 2 ) ;
vstack = vstack . slice ( 0 , - 1 * len ) ;
lstack = lstack . slice ( 0 , - 1 * len ) ;
}
stack . push ( this . productions _ [ action [ 1 ] ] [ 0 ] ) ;
vstack . push ( yyval . $ ) ;
lstack . push ( yyval . _$ ) ;
newState = table [ stack [ stack . length - 2 ] ] [ stack [ stack . length - 1 ] ] ;
stack . push ( newState ) ;
break ;
case 3 :
return true ;
}
}
return true ;
}
} ;
/* Jison generated lexer */
var lexer = ( function ( ) {
var lexer = ( { EOF : 1 ,
parseError : function parseError ( str , hash ) {
if ( this . yy . parser ) {
this . yy . parser . parseError ( str , hash ) ;
} else {
throw new Error ( str ) ;
}
} ,
setInput : function ( input ) {
this . _input = input ;
this . _more = this . _less = this . done = false ;
this . yylineno = this . yyleng = 0 ;
this . yytext = this . matched = this . match = '' ;
this . conditionStack = [ 'INITIAL' ] ;
this . yylloc = { first _line : 1 , first _column : 0 , last _line : 1 , last _column : 0 } ;
if ( this . options . ranges ) this . yylloc . range = [ 0 , 0 ] ;
this . offset = 0 ;
return this ;
} ,
input : function ( ) {
var ch = this . _input [ 0 ] ;
this . yytext += ch ;
this . yyleng ++ ;
this . offset ++ ;
this . match += ch ;
this . matched += ch ;
var lines = ch . match ( /(?:\r\n?|\n).*/g ) ;
if ( lines ) {
this . yylineno ++ ;
this . yylloc . last _line ++ ;
} else {
this . yylloc . last _column ++ ;
}
if ( this . options . ranges ) this . yylloc . range [ 1 ] ++ ;
this . _input = this . _input . slice ( 1 ) ;
return ch ;
} ,
unput : function ( ch ) {
var len = ch . length ;
var lines = ch . split ( /(?:\r\n?|\n)/g ) ;
this . _input = ch + this . _input ;
this . yytext = this . yytext . substr ( 0 , this . yytext . length - len - 1 ) ;
//this.yyleng -= len;
this . offset -= len ;
var oldLines = this . match . split ( /(?:\r\n?|\n)/g ) ;
this . match = this . match . substr ( 0 , this . match . length - 1 ) ;
this . matched = this . matched . substr ( 0 , this . matched . length - 1 ) ;
if ( lines . length - 1 ) this . yylineno -= lines . length - 1 ;
var r = this . yylloc . range ;
this . yylloc = { first _line : this . yylloc . first _line ,
last _line : this . yylineno + 1 ,
first _column : this . yylloc . first _column ,
last _column : lines ?
( lines . length === oldLines . length ? this . yylloc . first _column : 0 ) + oldLines [ oldLines . length - lines . length ] . length - lines [ 0 ] . length :
this . yylloc . first _column - len
} ;
if ( this . options . ranges ) {
this . yylloc . range = [ r [ 0 ] , r [ 0 ] + this . yyleng - len ] ;
}
return this ;
} ,
more : function ( ) {
this . _more = true ;
return this ;
} ,
less : function ( n ) {
this . unput ( this . match . slice ( n ) ) ;
} ,
pastInput : function ( ) {
var past = this . matched . substr ( 0 , this . matched . length - this . match . length ) ;
return ( past . length > 20 ? '...' : '' ) + past . substr ( - 20 ) . replace ( /\n/g , "" ) ;
} ,
upcomingInput : function ( ) {
var next = this . match ;
if ( next . length < 20 ) {
next += this . _input . substr ( 0 , 20 - next . length ) ;
}
return ( next . substr ( 0 , 20 ) + ( next . length > 20 ? '...' : '' ) ) . replace ( /\n/g , "" ) ;
} ,
showPosition : function ( ) {
var pre = this . pastInput ( ) ;
var c = new Array ( pre . length + 1 ) . join ( "-" ) ;
return pre + this . upcomingInput ( ) + "\n" + c + "^" ;
} ,
next : function ( ) {
if ( this . done ) {
return this . EOF ;
}
if ( ! this . _input ) this . done = true ;
var token ,
match ,
tempMatch ,
index ,
col ,
lines ;
if ( ! this . _more ) {
this . yytext = '' ;
this . match = '' ;
}
var rules = this . _currentRules ( ) ;
for ( var i = 0 ; i < rules . length ; i ++ ) {
tempMatch = this . _input . match ( this . rules [ rules [ i ] ] ) ;
if ( tempMatch && ( ! match || tempMatch [ 0 ] . length > match [ 0 ] . length ) ) {
match = tempMatch ;
index = i ;
if ( ! this . options . flex ) break ;
}
}
if ( match ) {
lines = match [ 0 ] . match ( /(?:\r\n?|\n).*/g ) ;
if ( lines ) this . yylineno += lines . length ;
this . yylloc = { first _line : this . yylloc . last _line ,
last _line : this . yylineno + 1 ,
first _column : this . yylloc . last _column ,
last _column : lines ? lines [ lines . length - 1 ] . length - lines [ lines . length - 1 ] . match ( /\r?\n?/ ) [ 0 ] . length : this . yylloc . last _column + match [ 0 ] . length } ;
this . yytext += match [ 0 ] ;
this . match += match [ 0 ] ;
this . matches = match ;
this . yyleng = this . yytext . length ;
if ( this . options . ranges ) {
this . yylloc . range = [ this . offset , this . offset += this . yyleng ] ;
}
this . _more = false ;
this . _input = this . _input . slice ( match [ 0 ] . length ) ;
this . matched += match [ 0 ] ;
token = this . performAction . call ( this , this . yy , this , rules [ index ] , this . conditionStack [ this . conditionStack . length - 1 ] ) ;
if ( this . done && this . _input ) this . done = false ;
if ( token ) return token ;
else return ;
}
if ( this . _input === "" ) {
return this . EOF ;
} else {
return this . parseError ( 'Lexical error on line ' + ( this . yylineno + 1 ) + '. Unrecognized text.\n' + this . showPosition ( ) ,
{ text : "" , token : null , line : this . yylineno } ) ;
}
} ,
lex : function lex ( ) {
var r = this . next ( ) ;
if ( typeof r !== 'undefined' ) {
return r ;
} else {
return this . lex ( ) ;
}
} ,
begin : function begin ( condition ) {
this . conditionStack . push ( condition ) ;
} ,
popState : function popState ( ) {
return this . conditionStack . pop ( ) ;
} ,
_currentRules : function _currentRules ( ) {
return this . conditions [ this . conditionStack [ this . conditionStack . length - 1 ] ] . rules ;
} ,
topState : function ( ) {
return this . conditionStack [ this . conditionStack . length - 2 ] ;
} ,
pushState : function begin ( condition ) {
this . begin ( condition ) ;
} } ) ;
lexer . options = { } ;
lexer . performAction = function anonymous ( yy , yy _ , $avoiding _name _collisions , YY _START ) {
var YYSTATE = YY _START
switch ( $avoiding _name _collisions ) {
case 0 :
if ( yy _ . yytext . slice ( - 1 ) !== "\\" ) this . begin ( "mu" ) ;
if ( yy _ . yytext . slice ( - 1 ) === "\\" ) yy _ . yytext = yy _ . yytext . substr ( 0 , yy _ . yyleng - 1 ) , this . begin ( "emu" ) ;
if ( yy _ . yytext ) return 14 ;
break ;
case 1 : return 14 ;
break ;
case 2 :
if ( yy _ . yytext . slice ( - 1 ) !== "\\" ) this . popState ( ) ;
if ( yy _ . yytext . slice ( - 1 ) === "\\" ) yy _ . yytext = yy _ . yytext . substr ( 0 , yy _ . yyleng - 1 ) ;
return 14 ;
break ;
case 3 : yy _ . yytext = yy _ . yytext . substr ( 0 , yy _ . yyleng - 4 ) ; this . popState ( ) ; return 15 ;
break ;
case 4 : this . begin ( "par" ) ; return 24 ;
break ;
case 5 : return 16 ;
break ;
case 6 : return 20 ;
break ;
case 7 : return 19 ;
break ;
case 8 : return 19 ;
break ;
case 9 : return 23 ;
break ;
case 10 : return 23 ;
break ;
case 11 : this . popState ( ) ; this . begin ( 'com' ) ;
break ;
case 12 : yy _ . yytext = yy _ . yytext . substr ( 3 , yy _ . yyleng - 5 ) ; this . popState ( ) ; return 15 ;
break ;
case 13 : return 22 ;
break ;
case 14 : return 36 ;
break ;
case 15 : return 35 ;
break ;
case 16 : return 35 ;
break ;
case 17 : return 39 ;
break ;
case 18 : /*ignore whitespace*/
break ;
case 19 : this . popState ( ) ; return 18 ;
break ;
case 20 : this . popState ( ) ; return 18 ;
break ;
case 21 : yy _ . yytext = yy _ . yytext . substr ( 1 , yy _ . yyleng - 2 ) . replace ( /\\"/g , '"' ) ; return 30 ;
break ;
case 22 : yy _ . yytext = yy _ . yytext . substr ( 1 , yy _ . yyleng - 2 ) . replace ( /\\'/g , "'" ) ; return 30 ;
break ;
case 23 : yy _ . yytext = yy _ . yytext . substr ( 1 ) ; return 28 ;
break ;
case 24 : return 32 ;
break ;
case 25 : return 32 ;
break ;
case 26 : return 31 ;
break ;
case 27 : return 35 ;
break ;
case 28 : yy _ . yytext = yy _ . yytext . substr ( 1 , yy _ . yyleng - 2 ) ; return 35 ;
break ;
case 29 : return 'INVALID' ;
break ;
case 30 : /*ignore whitespace*/
break ;
case 31 : this . popState ( ) ; return 37 ;
break ;
case 32 : return 5 ;
break ;
}
} ;
lexer . rules = [ /^(?:[^\x00]*?(?=(\{\{)))/ , /^(?:[^\x00]+)/ , /^(?:[^\x00]{2,}?(?=(\{\{|$)))/ , /^(?:[\s\S]*?--\}\})/ , /^(?:\{\{>)/ , /^(?:\{\{#)/ , /^(?:\{\{\/)/ , /^(?:\{\{\^)/ , /^(?:\{\{\s*else\b)/ , /^(?:\{\{\{)/ , /^(?:\{\{&)/ , /^(?:\{\{!--)/ , /^(?:\{\{![\s\S]*?\}\})/ , /^(?:\{\{)/ , /^(?:=)/ , /^(?:\.(?=[} ]))/ , /^(?:\.\.)/ , /^(?:[\/.])/ , /^(?:\s+)/ , /^(?:\}\}\})/ , /^(?:\}\})/ , /^(?:"(\\["]|[^"])*")/ , /^(?:'(\\[']|[^'])*')/ , /^(?:@[a-zA-Z]+)/ , /^(?:true(?=[}\s]))/ , /^(?:false(?=[}\s]))/ , /^(?:[0-9]+(?=[}\s]))/ , /^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/ , /^(?:\[[^\]]*\])/ , /^(?:.)/ , /^(?:\s+)/ , /^(?:[a-zA-Z0-9_$-/]+)/ , /^(?:$)/ ] ;
lexer . conditions = { "mu" : { "rules" : [ 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 32 ] , "inclusive" : false } , "emu" : { "rules" : [ 2 ] , "inclusive" : false } , "com" : { "rules" : [ 3 ] , "inclusive" : false } , "par" : { "rules" : [ 30 , 31 ] , "inclusive" : false } , "INITIAL" : { "rules" : [ 0 , 1 , 32 ] , "inclusive" : true } } ;
return lexer ; } ) ( )
parser . lexer = lexer ;
function Parser ( ) { this . yy = { } ; } Parser . prototype = parser ; parser . Parser = Parser ;
return new Parser ;
} ) ( ) ; ;
// lib/handlebars/compiler/base.js
Handlebars . Parser = handlebars ;
2013-02-19 11:27:20 -05:00
Handlebars . parse = function ( input ) {
// Just return if an already-compile AST was passed in.
if ( input . constructor === Handlebars . AST . ProgramNode ) { return input ; }
2013-02-05 14:16:51 -05:00
Handlebars . Parser . yy = Handlebars . AST ;
2013-02-19 11:27:20 -05:00
return Handlebars . Parser . parse ( input ) ;
2013-02-05 14:16:51 -05:00
} ;
Handlebars . print = function ( ast ) {
return new Handlebars . PrintVisitor ( ) . accept ( ast ) ;
} ; ;
// lib/handlebars/compiler/ast.js
( function ( ) {
Handlebars . AST = { } ;
Handlebars . AST . ProgramNode = function ( statements , inverse ) {
this . type = "program" ;
this . statements = statements ;
if ( inverse ) { this . inverse = new Handlebars . AST . ProgramNode ( inverse ) ; }
} ;
Handlebars . AST . MustacheNode = function ( rawParams , hash , unescaped ) {
this . type = "mustache" ;
this . escaped = ! unescaped ;
this . hash = hash ;
var id = this . id = rawParams [ 0 ] ;
var params = this . params = rawParams . slice ( 1 ) ;
// a mustache is an eligible helper if:
// * its id is simple (a single part, not `this` or `..`)
var eligibleHelper = this . eligibleHelper = id . isSimple ;
// a mustache is definitely a helper if:
// * it is an eligible helper, and
// * it has at least one parameter or hash segment
this . isHelper = eligibleHelper && ( params . length || hash ) ;
// if a mustache is an eligible helper but not a definite
// helper, it is ambiguous, and will be resolved in a later
// pass or at runtime.
} ;
Handlebars . AST . PartialNode = function ( partialName , context ) {
this . type = "partial" ;
this . partialName = partialName ;
this . context = context ;
} ;
var verifyMatch = function ( open , close ) {
if ( open . original !== close . original ) {
throw new Handlebars . Exception ( open . original + " doesn't match " + close . original ) ;
}
} ;
Handlebars . AST . BlockNode = function ( mustache , program , inverse , close ) {
verifyMatch ( mustache . id , close ) ;
this . type = "block" ;
this . mustache = mustache ;
this . program = program ;
this . inverse = inverse ;
if ( this . inverse && ! this . program ) {
this . isInverse = true ;
}
} ;
Handlebars . AST . ContentNode = function ( string ) {
this . type = "content" ;
this . string = string ;
} ;
Handlebars . AST . HashNode = function ( pairs ) {
this . type = "hash" ;
this . pairs = pairs ;
} ;
Handlebars . AST . IdNode = function ( parts ) {
this . type = "ID" ;
this . original = parts . join ( "." ) ;
var dig = [ ] , depth = 0 ;
for ( var i = 0 , l = parts . length ; i < l ; i ++ ) {
var part = parts [ i ] ;
2013-02-19 11:27:20 -05:00
if ( part === ".." || part === "." || part === "this" ) {
if ( dig . length > 0 ) { throw new Handlebars . Exception ( "Invalid path: " + this . original ) ; }
else if ( part === ".." ) { depth ++ ; }
else { this . isScoped = true ; }
}
2013-02-05 14:16:51 -05:00
else { dig . push ( part ) ; }
}
this . parts = dig ;
this . string = dig . join ( '.' ) ;
this . depth = depth ;
// an ID is simple if it only has one part, and that part is not
// `..` or `this`.
this . isSimple = parts . length === 1 && ! this . isScoped && depth === 0 ;
this . stringModeValue = this . string ;
} ;
Handlebars . AST . PartialNameNode = function ( name ) {
this . type = "PARTIAL_NAME" ;
this . name = name ;
} ;
Handlebars . AST . DataNode = function ( id ) {
this . type = "DATA" ;
this . id = id ;
} ;
Handlebars . AST . StringNode = function ( string ) {
this . type = "STRING" ;
this . string = string ;
this . stringModeValue = string ;
} ;
Handlebars . AST . IntegerNode = function ( integer ) {
this . type = "INTEGER" ;
this . integer = integer ;
this . stringModeValue = Number ( integer ) ;
} ;
Handlebars . AST . BooleanNode = function ( bool ) {
this . type = "BOOLEAN" ;
this . bool = bool ;
this . stringModeValue = bool === "true" ;
} ;
Handlebars . AST . CommentNode = function ( comment ) {
this . type = "comment" ;
this . comment = comment ;
} ;
} ) ( ) ; ;
// lib/handlebars/utils.js
var errorProps = [ 'description' , 'fileName' , 'lineNumber' , 'message' , 'name' , 'number' , 'stack' ] ;
Handlebars . Exception = function ( message ) {
var tmp = Error . prototype . constructor . apply ( this , arguments ) ;
// Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
for ( var idx = 0 ; idx < errorProps . length ; idx ++ ) {
this [ errorProps [ idx ] ] = tmp [ errorProps [ idx ] ] ;
}
} ;
Handlebars . Exception . prototype = new Error ( ) ;
// Build out our basic SafeString type
Handlebars . SafeString = function ( string ) {
this . string = string ;
} ;
Handlebars . SafeString . prototype . toString = function ( ) {
return this . string . toString ( ) ;
} ;
( function ( ) {
var escape = {
"&" : "&" ,
"<" : "<" ,
">" : ">" ,
'"' : """ ,
"'" : "'" ,
"`" : "`"
} ;
var badChars = /[&<>"'`]/g ;
var possible = /[&<>"'`]/ ;
var escapeChar = function ( chr ) {
return escape [ chr ] || "&" ;
} ;
Handlebars . Utils = {
escapeExpression : function ( string ) {
// don't escape SafeStrings, since they're already safe
if ( string instanceof Handlebars . SafeString ) {
return string . toString ( ) ;
} else if ( string == null || string === false ) {
return "" ;
}
if ( ! possible . test ( string ) ) { return string ; }
return string . replace ( badChars , escapeChar ) ;
} ,
isEmpty : function ( value ) {
if ( ! value && value !== 0 ) {
return true ;
} else if ( Object . prototype . toString . call ( value ) === "[object Array]" && value . length === 0 ) {
return true ;
} else {
return false ;
}
}
} ;
} ) ( ) ; ;
// lib/handlebars/compiler/compiler.js
/*jshint eqnull:true*/
Handlebars . Compiler = function ( ) { } ;
Handlebars . JavaScriptCompiler = function ( ) { } ;
( function ( Compiler , JavaScriptCompiler ) {
// the foundHelper register will disambiguate helper lookup from finding a
// function in a context. This is necessary for mustache compatibility, which
// requires that context functions in blocks are evaluated by blockHelperMissing,
// and then proceed as if the resulting value was provided to blockHelperMissing.
Compiler . prototype = {
compiler : Compiler ,
disassemble : function ( ) {
var opcodes = this . opcodes , opcode , out = [ ] , params , param ;
for ( var i = 0 , l = opcodes . length ; i < l ; i ++ ) {
opcode = opcodes [ i ] ;
if ( opcode . opcode === 'DECLARE' ) {
out . push ( "DECLARE " + opcode . name + "=" + opcode . value ) ;
} else {
params = [ ] ;
for ( var j = 0 ; j < opcode . args . length ; j ++ ) {
param = opcode . args [ j ] ;
if ( typeof param === "string" ) {
param = "\"" + param . replace ( "\n" , "\\n" ) + "\"" ;
}
params . push ( param ) ;
}
out . push ( opcode . opcode + " " + params . join ( " " ) ) ;
}
}
return out . join ( "\n" ) ;
} ,
2013-02-19 11:27:20 -05:00
equals : function ( other ) {
var len = this . opcodes . length ;
if ( other . opcodes . length !== len ) {
return false ;
}
for ( var i = 0 ; i < len ; i ++ ) {
var opcode = this . opcodes [ i ] ,
otherOpcode = other . opcodes [ i ] ;
if ( opcode . opcode !== otherOpcode . opcode || opcode . args . length !== otherOpcode . args . length ) {
return false ;
}
for ( var j = 0 ; j < opcode . args . length ; j ++ ) {
if ( opcode . args [ j ] !== otherOpcode . args [ j ] ) {
return false ;
}
}
}
return true ;
} ,
2013-02-05 14:16:51 -05:00
guid : 0 ,
compile : function ( program , options ) {
this . children = [ ] ;
this . depths = { list : [ ] } ;
this . options = options ;
// These changes will propagate to the other compiler components
var knownHelpers = this . options . knownHelpers ;
this . options . knownHelpers = {
'helperMissing' : true ,
'blockHelperMissing' : true ,
'each' : true ,
'if' : true ,
'unless' : true ,
'with' : true ,
'log' : true
} ;
if ( knownHelpers ) {
for ( var name in knownHelpers ) {
this . options . knownHelpers [ name ] = knownHelpers [ name ] ;
}
}
return this . program ( program ) ;
} ,
accept : function ( node ) {
return this [ node . type ] ( node ) ;
} ,
program : function ( program ) {
var statements = program . statements , statement ;
this . opcodes = [ ] ;
for ( var i = 0 , l = statements . length ; i < l ; i ++ ) {
statement = statements [ i ] ;
this [ statement . type ] ( statement ) ;
}
this . isSimple = l === 1 ;
this . depths . list = this . depths . list . sort ( function ( a , b ) {
return a - b ;
} ) ;
return this ;
} ,
compileProgram : function ( program ) {
var result = new this . compiler ( ) . compile ( program , this . options ) ;
var guid = this . guid ++ , depth ;
this . usePartial = this . usePartial || result . usePartial ;
this . children [ guid ] = result ;
for ( var i = 0 , l = result . depths . list . length ; i < l ; i ++ ) {
depth = result . depths . list [ i ] ;
if ( depth < 2 ) { continue ; }
else { this . addDepth ( depth - 1 ) ; }
}
return guid ;
} ,
block : function ( block ) {
var mustache = block . mustache ,
program = block . program ,
inverse = block . inverse ;
if ( program ) {
program = this . compileProgram ( program ) ;
}
if ( inverse ) {
inverse = this . compileProgram ( inverse ) ;
}
var type = this . classifyMustache ( mustache ) ;
if ( type === "helper" ) {
this . helperMustache ( mustache , program , inverse ) ;
} else if ( type === "simple" ) {
this . simpleMustache ( mustache ) ;
// now that the simple mustache is resolved, we need to
// evaluate it by executing `blockHelperMissing`
this . opcode ( 'pushProgram' , program ) ;
this . opcode ( 'pushProgram' , inverse ) ;
2013-02-19 11:27:20 -05:00
this . opcode ( 'emptyHash' ) ;
2013-02-05 14:16:51 -05:00
this . opcode ( 'blockValue' ) ;
} else {
this . ambiguousMustache ( mustache , program , inverse ) ;
// now that the simple mustache is resolved, we need to
// evaluate it by executing `blockHelperMissing`
this . opcode ( 'pushProgram' , program ) ;
this . opcode ( 'pushProgram' , inverse ) ;
2013-02-19 11:27:20 -05:00
this . opcode ( 'emptyHash' ) ;
2013-02-05 14:16:51 -05:00
this . opcode ( 'ambiguousBlockValue' ) ;
}
this . opcode ( 'append' ) ;
} ,
hash : function ( hash ) {
var pairs = hash . pairs , pair , val ;
this . opcode ( 'pushHash' ) ;
for ( var i = 0 , l = pairs . length ; i < l ; i ++ ) {
pair = pairs [ i ] ;
val = pair [ 1 ] ;
if ( this . options . stringParams ) {
this . opcode ( 'pushStringParam' , val . stringModeValue , val . type ) ;
} else {
this . accept ( val ) ;
}
this . opcode ( 'assignToHash' , pair [ 0 ] ) ;
}
2013-02-19 11:27:20 -05:00
this . opcode ( 'popHash' ) ;
2013-02-05 14:16:51 -05:00
} ,
partial : function ( partial ) {
var partialName = partial . partialName ;
this . usePartial = true ;
if ( partial . context ) {
this . ID ( partial . context ) ;
} else {
this . opcode ( 'push' , 'depth0' ) ;
}
this . opcode ( 'invokePartial' , partialName . name ) ;
this . opcode ( 'append' ) ;
} ,
content : function ( content ) {
this . opcode ( 'appendContent' , content . string ) ;
} ,
mustache : function ( mustache ) {
var options = this . options ;
var type = this . classifyMustache ( mustache ) ;
if ( type === "simple" ) {
this . simpleMustache ( mustache ) ;
} else if ( type === "helper" ) {
this . helperMustache ( mustache ) ;
} else {
this . ambiguousMustache ( mustache ) ;
}
if ( mustache . escaped && ! options . noEscape ) {
this . opcode ( 'appendEscaped' ) ;
} else {
this . opcode ( 'append' ) ;
}
} ,
ambiguousMustache : function ( mustache , program , inverse ) {
2013-02-19 11:27:20 -05:00
var id = mustache . id ,
name = id . parts [ 0 ] ,
isBlock = program != null || inverse != null ;
2013-02-05 14:16:51 -05:00
this . opcode ( 'getContext' , id . depth ) ;
this . opcode ( 'pushProgram' , program ) ;
this . opcode ( 'pushProgram' , inverse ) ;
2013-02-19 11:27:20 -05:00
this . opcode ( 'invokeAmbiguous' , name , isBlock ) ;
2013-02-05 14:16:51 -05:00
} ,
2013-02-19 11:27:20 -05:00
simpleMustache : function ( mustache ) {
2013-02-05 14:16:51 -05:00
var id = mustache . id ;
if ( id . type === 'DATA' ) {
this . DATA ( id ) ;
} else if ( id . parts . length ) {
this . ID ( id ) ;
} else {
// Simplified ID for `this`
this . addDepth ( id . depth ) ;
this . opcode ( 'getContext' , id . depth ) ;
this . opcode ( 'pushContext' ) ;
}
this . opcode ( 'resolvePossibleLambda' ) ;
} ,
helperMustache : function ( mustache , program , inverse ) {
var params = this . setupFullMustacheParams ( mustache , program , inverse ) ,
name = mustache . id . parts [ 0 ] ;
if ( this . options . knownHelpers [ name ] ) {
this . opcode ( 'invokeKnownHelper' , params . length , name ) ;
} else if ( this . knownHelpersOnly ) {
throw new Error ( "You specified knownHelpersOnly, but used the unknown helper " + name ) ;
} else {
this . opcode ( 'invokeHelper' , params . length , name ) ;
}
} ,
ID : function ( id ) {
this . addDepth ( id . depth ) ;
this . opcode ( 'getContext' , id . depth ) ;
var name = id . parts [ 0 ] ;
if ( ! name ) {
this . opcode ( 'pushContext' ) ;
} else {
this . opcode ( 'lookupOnContext' , id . parts [ 0 ] ) ;
}
for ( var i = 1 , l = id . parts . length ; i < l ; i ++ ) {
this . opcode ( 'lookup' , id . parts [ i ] ) ;
}
} ,
DATA : function ( data ) {
this . options . data = true ;
this . opcode ( 'lookupData' , data . id ) ;
} ,
STRING : function ( string ) {
this . opcode ( 'pushString' , string . string ) ;
} ,
INTEGER : function ( integer ) {
this . opcode ( 'pushLiteral' , integer . integer ) ;
} ,
BOOLEAN : function ( bool ) {
this . opcode ( 'pushLiteral' , bool . bool ) ;
} ,
comment : function ( ) { } ,
// HELPERS
opcode : function ( name ) {
this . opcodes . push ( { opcode : name , args : [ ] . slice . call ( arguments , 1 ) } ) ;
} ,
declare : function ( name , value ) {
this . opcodes . push ( { opcode : 'DECLARE' , name : name , value : value } ) ;
} ,
addDepth : function ( depth ) {
if ( isNaN ( depth ) ) { throw new Error ( "EWOT" ) ; }
if ( depth === 0 ) { return ; }
if ( ! this . depths [ depth ] ) {
this . depths [ depth ] = true ;
this . depths . list . push ( depth ) ;
}
} ,
classifyMustache : function ( mustache ) {
var isHelper = mustache . isHelper ;
var isEligible = mustache . eligibleHelper ;
var options = this . options ;
// if ambiguous, we can possibly resolve the ambiguity now
if ( isEligible && ! isHelper ) {
var name = mustache . id . parts [ 0 ] ;
if ( options . knownHelpers [ name ] ) {
isHelper = true ;
} else if ( options . knownHelpersOnly ) {
isEligible = false ;
}
}
if ( isHelper ) { return "helper" ; }
else if ( isEligible ) { return "ambiguous" ; }
else { return "simple" ; }
} ,
pushParams : function ( params ) {
var i = params . length , param ;
while ( i -- ) {
param = params [ i ] ;
if ( this . options . stringParams ) {
if ( param . depth ) {
this . addDepth ( param . depth ) ;
}
this . opcode ( 'getContext' , param . depth || 0 ) ;
this . opcode ( 'pushStringParam' , param . stringModeValue , param . type ) ;
} else {
this [ param . type ] ( param ) ;
}
}
} ,
setupMustacheParams : function ( mustache ) {
var params = mustache . params ;
this . pushParams ( params ) ;
if ( mustache . hash ) {
this . hash ( mustache . hash ) ;
} else {
2013-02-19 11:27:20 -05:00
this . opcode ( 'emptyHash' ) ;
2013-02-05 14:16:51 -05:00
}
return params ;
} ,
// this will replace setupMustacheParams when we're done
setupFullMustacheParams : function ( mustache , program , inverse ) {
var params = mustache . params ;
this . pushParams ( params ) ;
this . opcode ( 'pushProgram' , program ) ;
this . opcode ( 'pushProgram' , inverse ) ;
if ( mustache . hash ) {
this . hash ( mustache . hash ) ;
} else {
2013-02-19 11:27:20 -05:00
this . opcode ( 'emptyHash' ) ;
2013-02-05 14:16:51 -05:00
}
return params ;
}
} ;
var Literal = function ( value ) {
this . value = value ;
} ;
JavaScriptCompiler . prototype = {
// PUBLIC API: You can override these methods in a subclass to provide
// alternative compiled forms for name lookup and buffering semantics
2013-02-19 11:27:20 -05:00
nameLookup : function ( parent , name /* , type*/ ) {
2013-02-05 14:16:51 -05:00
if ( /^[0-9]+$/ . test ( name ) ) {
return parent + "[" + name + "]" ;
} else if ( JavaScriptCompiler . isValidJavaScriptVariableName ( name ) ) {
return parent + "." + name ;
}
else {
return parent + "['" + name + "']" ;
}
} ,
appendToBuffer : function ( string ) {
if ( this . environment . isSimple ) {
return "return " + string + ";" ;
} else {
2013-02-19 11:27:20 -05:00
return {
appendToBuffer : true ,
content : string ,
toString : function ( ) { return "buffer += " + string + ";" ; }
} ;
2013-02-05 14:16:51 -05:00
}
} ,
initializeBuffer : function ( ) {
return this . quotedString ( "" ) ;
} ,
namespace : "Handlebars" ,
// END PUBLIC API
compile : function ( environment , options , context , asObject ) {
this . environment = environment ;
this . options = options || { } ;
Handlebars . log ( Handlebars . logger . DEBUG , this . environment . disassemble ( ) + "\n\n" ) ;
this . name = this . environment . name ;
this . isChild = ! ! context ;
this . context = context || {
programs : [ ] ,
2013-02-19 11:27:20 -05:00
environments : [ ] ,
2013-02-05 14:16:51 -05:00
aliases : { }
} ;
this . preamble ( ) ;
this . stackSlot = 0 ;
this . stackVars = [ ] ;
this . registers = { list : [ ] } ;
this . compileStack = [ ] ;
2013-02-19 11:27:20 -05:00
this . inlineStack = [ ] ;
2013-02-05 14:16:51 -05:00
this . compileChildren ( environment , options ) ;
var opcodes = environment . opcodes , opcode ;
this . i = 0 ;
for ( l = opcodes . length ; this . i < l ; this . i ++ ) {
opcode = opcodes [ this . i ] ;
if ( opcode . opcode === 'DECLARE' ) {
this [ opcode . name ] = opcode . value ;
} else {
this [ opcode . opcode ] . apply ( this , opcode . args ) ;
}
}
return this . createFunctionContext ( asObject ) ;
} ,
nextOpcode : function ( ) {
2013-02-19 11:27:20 -05:00
var opcodes = this . environment . opcodes ;
2013-02-05 14:16:51 -05:00
return opcodes [ this . i + 1 ] ;
} ,
2013-02-19 11:27:20 -05:00
eat : function ( ) {
2013-02-05 14:16:51 -05:00
this . i = this . i + 1 ;
} ,
preamble : function ( ) {
var out = [ ] ;
if ( ! this . isChild ) {
var namespace = this . namespace ;
var copies = "helpers = helpers || " + namespace + ".helpers;" ;
if ( this . environment . usePartial ) { copies = copies + " partials = partials || " + namespace + ".partials;" ; }
if ( this . options . data ) { copies = copies + " data = data || {};" ; }
out . push ( copies ) ;
} else {
out . push ( '' ) ;
}
if ( ! this . environment . isSimple ) {
out . push ( ", buffer = " + this . initializeBuffer ( ) ) ;
} else {
out . push ( "" ) ;
}
// track the last context pushed into place to allow skipping the
// getContext opcode when it would be a noop
this . lastContext = 0 ;
this . source = out ;
} ,
createFunctionContext : function ( asObject ) {
var locals = this . stackVars . concat ( this . registers . list ) ;
if ( locals . length > 0 ) {
this . source [ 1 ] = this . source [ 1 ] + ", " + locals . join ( ", " ) ;
}
// Generate minimizer alias mappings
if ( ! this . isChild ) {
for ( var alias in this . context . aliases ) {
this . source [ 1 ] = this . source [ 1 ] + ', ' + alias + '=' + this . context . aliases [ alias ] ;
}
}
if ( this . source [ 1 ] ) {
this . source [ 1 ] = "var " + this . source [ 1 ] . substring ( 2 ) + ";" ;
}
// Merge children
if ( ! this . isChild ) {
this . source [ 1 ] += '\n' + this . context . programs . join ( '\n' ) + '\n' ;
}
if ( ! this . environment . isSimple ) {
this . source . push ( "return buffer;" ) ;
}
var params = this . isChild ? [ "depth0" , "data" ] : [ "Handlebars" , "depth0" , "helpers" , "partials" , "data" ] ;
for ( var i = 0 , l = this . environment . depths . list . length ; i < l ; i ++ ) {
params . push ( "depth" + this . environment . depths . list [ i ] ) ;
}
2013-02-19 11:27:20 -05:00
// Perform a second pass over the output to merge content when possible
var source = this . mergeSource ( ) ;
if ( ! this . isChild ) {
var revision = Handlebars . COMPILER _REVISION ,
versions = Handlebars . REVISION _CHANGES [ revision ] ;
source = "this.compilerInfo = [" + revision + ",'" + versions + "'];\n" + source ;
}
2013-02-05 14:16:51 -05:00
if ( asObject ) {
2013-02-19 11:27:20 -05:00
params . push ( source ) ;
2013-02-05 14:16:51 -05:00
return Function . apply ( this , params ) ;
} else {
2013-02-19 11:27:20 -05:00
var functionSource = 'function ' + ( this . name || '' ) + '(' + params . join ( ',' ) + ') {\n ' + source + '}' ;
2013-02-05 14:16:51 -05:00
Handlebars . log ( Handlebars . logger . DEBUG , functionSource + "\n\n" ) ;
return functionSource ;
}
} ,
2013-02-19 11:27:20 -05:00
mergeSource : function ( ) {
// WARN: We are not handling the case where buffer is still populated as the source should
// not have buffer append operations as their final action.
var source = '' ,
buffer ;
for ( var i = 0 , len = this . source . length ; i < len ; i ++ ) {
var line = this . source [ i ] ;
if ( line . appendToBuffer ) {
if ( buffer ) {
buffer = buffer + '\n + ' + line . content ;
} else {
buffer = line . content ;
}
} else {
if ( buffer ) {
source += 'buffer += ' + buffer + ';\n ' ;
buffer = undefined ;
}
source += line + '\n ' ;
}
}
return source ;
} ,
2013-02-05 14:16:51 -05:00
// [blockValue]
//
// On stack, before: hash, inverse, program, value
// On stack, after: return value of blockHelperMissing
//
// The purpose of this opcode is to take a block of the form
// `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and
// replace it on the stack with the result of properly
// invoking blockHelperMissing.
blockValue : function ( ) {
this . context . aliases . blockHelperMissing = 'helpers.blockHelperMissing' ;
var params = [ "depth0" ] ;
this . setupParams ( 0 , params ) ;
this . replaceStack ( function ( current ) {
params . splice ( 1 , 0 , current ) ;
return "blockHelperMissing.call(" + params . join ( ", " ) + ")" ;
} ) ;
} ,
// [ambiguousBlockValue]
//
// On stack, before: hash, inverse, program, value
// Compiler value, before: lastHelper=value of last found helper, if any
// On stack, after, if no lastHelper: same as [blockValue]
// On stack, after, if lastHelper: value
ambiguousBlockValue : function ( ) {
this . context . aliases . blockHelperMissing = 'helpers.blockHelperMissing' ;
var params = [ "depth0" ] ;
this . setupParams ( 0 , params ) ;
var current = this . topStack ( ) ;
params . splice ( 1 , 0 , current ) ;
2013-02-19 11:27:20 -05:00
// Use the options value generated from the invocation
params [ params . length - 1 ] = 'options' ;
2013-02-05 14:16:51 -05:00
this . source . push ( "if (!" + this . lastHelper + ") { " + current + " = blockHelperMissing.call(" + params . join ( ", " ) + "); }" ) ;
} ,
// [appendContent]
//
// On stack, before: ...
// On stack, after: ...
//
// Appends the string value of `content` to the current buffer
appendContent : function ( content ) {
this . source . push ( this . appendToBuffer ( this . quotedString ( content ) ) ) ;
} ,
// [append]
//
// On stack, before: value, ...
// On stack, after: ...
//
// Coerces `value` to a String and appends it to the current buffer.
//
// If `value` is truthy, or 0, it is coerced into a string and appended
// Otherwise, the empty string is appended
append : function ( ) {
2013-02-19 11:27:20 -05:00
// Force anything that is inlined onto the stack so we don't have duplication
// when we examine local
this . flushInline ( ) ;
2013-02-05 14:16:51 -05:00
var local = this . popStack ( ) ;
this . source . push ( "if(" + local + " || " + local + " === 0) { " + this . appendToBuffer ( local ) + " }" ) ;
if ( this . environment . isSimple ) {
this . source . push ( "else { " + this . appendToBuffer ( "''" ) + " }" ) ;
}
} ,
// [appendEscaped]
//
// On stack, before: value, ...
// On stack, after: ...
//
// Escape `value` and append it to the buffer
appendEscaped : function ( ) {
this . context . aliases . escapeExpression = 'this.escapeExpression' ;
2013-02-19 11:27:20 -05:00
this . source . push ( this . appendToBuffer ( "escapeExpression(" + this . popStack ( ) + ")" ) ) ;
2013-02-05 14:16:51 -05:00
} ,
// [getContext]
//
// On stack, before: ...
// On stack, after: ...
// Compiler value, after: lastContext=depth
//
// Set the value of the `lastContext` compiler value to the depth
getContext : function ( depth ) {
if ( this . lastContext !== depth ) {
this . lastContext = depth ;
}
} ,
// [lookupOnContext]
//
// On stack, before: ...
// On stack, after: currentContext[name], ...
//
// Looks up the value of `name` on the current context and pushes
// it onto the stack.
lookupOnContext : function ( name ) {
2013-02-19 11:27:20 -05:00
this . push ( this . nameLookup ( 'depth' + this . lastContext , name , 'context' ) ) ;
2013-02-05 14:16:51 -05:00
} ,
// [pushContext]
//
// On stack, before: ...
// On stack, after: currentContext, ...
//
// Pushes the value of the current context onto the stack.
pushContext : function ( ) {
this . pushStackLiteral ( 'depth' + this . lastContext ) ;
} ,
// [resolvePossibleLambda]
//
// On stack, before: value, ...
// On stack, after: resolved value, ...
//
// If the `value` is a lambda, replace it on the stack by
// the return value of the lambda
resolvePossibleLambda : function ( ) {
this . context . aliases . functionType = '"function"' ;
this . replaceStack ( function ( current ) {
return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current ;
} ) ;
} ,
// [lookup]
//
// On stack, before: value, ...
// On stack, after: value[name], ...
//
// Replace the value on the stack with the result of looking
// up `name` on `value`
lookup : function ( name ) {
this . replaceStack ( function ( current ) {
return current + " == null || " + current + " === false ? " + current + " : " + this . nameLookup ( current , name , 'context' ) ;
} ) ;
} ,
// [lookupData]
//
// On stack, before: ...
// On stack, after: data[id], ...
//
// Push the result of looking up `id` on the current data
lookupData : function ( id ) {
2013-02-19 11:27:20 -05:00
this . push ( this . nameLookup ( 'data' , id , 'data' ) ) ;
2013-02-05 14:16:51 -05:00
} ,
// [pushStringParam]
//
// On stack, before: ...
// On stack, after: string, currentContext, ...
//
// This opcode is designed for use in string mode, which
// provides the string value of a parameter along with its
// depth rather than resolving it immediately.
pushStringParam : function ( string , type ) {
this . pushStackLiteral ( 'depth' + this . lastContext ) ;
this . pushString ( type ) ;
if ( typeof string === 'string' ) {
this . pushString ( string ) ;
} else {
this . pushStackLiteral ( string ) ;
}
} ,
2013-02-19 11:27:20 -05:00
emptyHash : function ( ) {
this . pushStackLiteral ( '{}' ) ;
2013-02-05 14:16:51 -05:00
if ( this . options . stringParams ) {
this . register ( 'hashTypes' , '{}' ) ;
}
} ,
2013-02-19 11:27:20 -05:00
pushHash : function ( ) {
this . hash = { values : [ ] , types : [ ] } ;
} ,
popHash : function ( ) {
var hash = this . hash ;
this . hash = undefined ;
if ( this . options . stringParams ) {
this . register ( 'hashTypes' , '{' + hash . types . join ( ',' ) + '}' ) ;
}
this . push ( '{\n ' + hash . values . join ( ',\n ' ) + '\n }' ) ;
} ,
2013-02-05 14:16:51 -05:00
// [pushString]
//
// On stack, before: ...
// On stack, after: quotedString(string), ...
//
// Push a quoted version of `string` onto the stack
pushString : function ( string ) {
this . pushStackLiteral ( this . quotedString ( string ) ) ;
} ,
// [push]
//
// On stack, before: ...
// On stack, after: expr, ...
//
// Push an expression onto the stack
push : function ( expr ) {
2013-02-19 11:27:20 -05:00
this . inlineStack . push ( expr ) ;
return expr ;
2013-02-05 14:16:51 -05:00
} ,
// [pushLiteral]
//
// On stack, before: ...
// On stack, after: value, ...
//
// Pushes a value onto the stack. This operation prevents
// the compiler from creating a temporary variable to hold
// it.
pushLiteral : function ( value ) {
this . pushStackLiteral ( value ) ;
} ,
// [pushProgram]
//
// On stack, before: ...
// On stack, after: program(guid), ...
//
// Push a program expression onto the stack. This takes
// a compile-time guid and converts it into a runtime-accessible
// expression.
pushProgram : function ( guid ) {
if ( guid != null ) {
this . pushStackLiteral ( this . programExpression ( guid ) ) ;
} else {
this . pushStackLiteral ( null ) ;
}
} ,
// [invokeHelper]
//
// On stack, before: hash, inverse, program, params..., ...
// On stack, after: result of helper invocation
//
// Pops off the helper's parameters, invokes the helper,
// and pushes the helper's return value onto the stack.
//
// If the helper is not found, `helperMissing` is called.
invokeHelper : function ( paramSize , name ) {
this . context . aliases . helperMissing = 'helpers.helperMissing' ;
2013-02-19 11:27:20 -05:00
var helper = this . lastHelper = this . setupHelper ( paramSize , name , true ) ;
2013-02-05 14:16:51 -05:00
2013-02-19 11:27:20 -05:00
this . push ( helper . name ) ;
this . replaceStack ( function ( name ) {
return name + ' ? ' + name + '.call(' +
helper . callParams + ") " + ": helperMissing.call(" +
helper . helperMissingParams + ")" ;
} ) ;
2013-02-05 14:16:51 -05:00
} ,
// [invokeKnownHelper]
//
// On stack, before: hash, inverse, program, params..., ...
// On stack, after: result of helper invocation
//
// This operation is used when the helper is known to exist,
// so a `helperMissing` fallback is not required.
invokeKnownHelper : function ( paramSize , name ) {
var helper = this . setupHelper ( paramSize , name ) ;
2013-02-19 11:27:20 -05:00
this . push ( helper . name + ".call(" + helper . callParams + ")" ) ;
2013-02-05 14:16:51 -05:00
} ,
// [invokeAmbiguous]
//
// On stack, before: hash, inverse, program, params..., ...
// On stack, after: result of disambiguation
//
// This operation is used when an expression like `{{foo}}`
// is provided, but we don't know at compile-time whether it
// is a helper or a path.
//
// This operation emits more code than the other options,
// and can be avoided by passing the `knownHelpers` and
// `knownHelpersOnly` flags at compile-time.
2013-02-19 11:27:20 -05:00
invokeAmbiguous : function ( name , helperCall ) {
2013-02-05 14:16:51 -05:00
this . context . aliases . functionType = '"function"' ;
2013-02-19 11:27:20 -05:00
this . pushStackLiteral ( '{}' ) ; // Hash value
var helper = this . setupHelper ( 0 , name , helperCall ) ;
2013-02-05 14:16:51 -05:00
var helperName = this . lastHelper = this . nameLookup ( 'helpers' , name , 'helper' ) ;
var nonHelper = this . nameLookup ( 'depth' + this . lastContext , name , 'context' ) ;
var nextStack = this . nextStack ( ) ;
2013-02-19 11:27:20 -05:00
this . source . push ( 'if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper . callParams + '); }' ) ;
2013-02-05 14:16:51 -05:00
this . source . push ( 'else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.apply(depth0) : ' + nextStack + '; }' ) ;
} ,
// [invokePartial]
//
// On stack, before: context, ...
// On stack after: result of partial invocation
//
// This operation pops off a context, invokes a partial with that context,
// and pushes the result of the invocation back.
invokePartial : function ( name ) {
var params = [ this . nameLookup ( 'partials' , name , 'partial' ) , "'" + name + "'" , this . popStack ( ) , "helpers" , "partials" ] ;
if ( this . options . data ) {
params . push ( "data" ) ;
}
this . context . aliases . self = "this" ;
2013-02-19 11:27:20 -05:00
this . push ( "self.invokePartial(" + params . join ( ", " ) + ")" ) ;
2013-02-05 14:16:51 -05:00
} ,
// [assignToHash]
//
// On stack, before: value, hash, ...
// On stack, after: hash, ...
//
// Pops a value and hash off the stack, assigns `hash[key] = value`
// and pushes the hash back onto the stack.
assignToHash : function ( key ) {
2013-02-19 11:27:20 -05:00
var value = this . popStack ( ) ,
type ;
2013-02-05 14:16:51 -05:00
if ( this . options . stringParams ) {
2013-02-19 11:27:20 -05:00
type = this . popStack ( ) ;
2013-02-05 14:16:51 -05:00
this . popStack ( ) ;
}
2013-02-19 11:27:20 -05:00
var hash = this . hash ;
if ( type ) {
hash . types . push ( "'" + key + "': " + type ) ;
}
hash . values . push ( "'" + key + "': (" + value + ")" ) ;
2013-02-05 14:16:51 -05:00
} ,
// HELPERS
compiler : JavaScriptCompiler ,
compileChildren : function ( environment , options ) {
var children = environment . children , child , compiler ;
for ( var i = 0 , l = children . length ; i < l ; i ++ ) {
child = children [ i ] ;
compiler = new this . compiler ( ) ;
2013-02-19 11:27:20 -05:00
var index = this . matchExistingProgram ( child ) ;
if ( index == null ) {
this . context . programs . push ( '' ) ; // Placeholder to prevent name conflicts for nested children
index = this . context . programs . length ;
child . index = index ;
child . name = 'program' + index ;
this . context . programs [ index ] = compiler . compile ( child , options , this . context ) ;
this . context . environments [ index ] = child ;
} else {
child . index = index ;
child . name = 'program' + index ;
}
}
} ,
matchExistingProgram : function ( child ) {
for ( var i = 0 , len = this . context . environments . length ; i < len ; i ++ ) {
var environment = this . context . environments [ i ] ;
if ( environment && environment . equals ( child ) ) {
return i ;
}
2013-02-05 14:16:51 -05:00
}
} ,
programExpression : function ( guid ) {
this . context . aliases . self = "this" ;
if ( guid == null ) {
return "self.noop" ;
}
var child = this . environment . children [ guid ] ,
depths = child . depths . list , depth ;
var programParams = [ child . index , child . name , "data" ] ;
for ( var i = 0 , l = depths . length ; i < l ; i ++ ) {
depth = depths [ i ] ;
if ( depth === 1 ) { programParams . push ( "depth0" ) ; }
else { programParams . push ( "depth" + ( depth - 1 ) ) ; }
}
if ( depths . length === 0 ) {
return "self.program(" + programParams . join ( ", " ) + ")" ;
} else {
programParams . shift ( ) ;
return "self.programWithDepth(" + programParams . join ( ", " ) + ")" ;
}
} ,
register : function ( name , val ) {
this . useRegister ( name ) ;
this . source . push ( name + " = " + val + ";" ) ;
} ,
useRegister : function ( name ) {
if ( ! this . registers [ name ] ) {
this . registers [ name ] = true ;
this . registers . list . push ( name ) ;
}
} ,
pushStackLiteral : function ( item ) {
2013-02-19 11:27:20 -05:00
return this . push ( new Literal ( item ) ) ;
2013-02-05 14:16:51 -05:00
} ,
pushStack : function ( item ) {
2013-02-19 11:27:20 -05:00
this . flushInline ( ) ;
2013-02-05 14:16:51 -05:00
var stack = this . incrStack ( ) ;
2013-02-19 11:27:20 -05:00
if ( item ) {
this . source . push ( stack + " = " + item + ";" ) ;
}
2013-02-05 14:16:51 -05:00
this . compileStack . push ( stack ) ;
return stack ;
} ,
replaceStack : function ( callback ) {
2013-02-19 11:27:20 -05:00
var prefix = '' ,
inline = this . isInline ( ) ,
stack ;
// If we are currently inline then we want to merge the inline statement into the
// replacement statement via ','
if ( inline ) {
var top = this . popStack ( true ) ;
if ( top instanceof Literal ) {
// Literals do not need to be inlined
stack = top . value ;
} else {
// Get or create the current stack name for use by the inline
var name = this . stackSlot ? this . topStackName ( ) : this . incrStack ( ) ;
2013-02-05 14:16:51 -05:00
2013-02-19 11:27:20 -05:00
prefix = '(' + this . push ( name ) + ' = ' + top + '),' ;
stack = this . topStack ( ) ;
}
} else {
stack = this . topStack ( ) ;
2013-02-05 14:16:51 -05:00
}
2013-02-19 11:27:20 -05:00
var item = callback . call ( this , stack ) ;
if ( inline ) {
if ( this . inlineStack . length || this . compileStack . length ) {
this . popStack ( ) ;
}
this . push ( '(' + prefix + item + ')' ) ;
} else {
// Prevent modification of the context depth variable. Through replaceStack
if ( ! /^stack/ . test ( stack ) ) {
stack = this . nextStack ( ) ;
}
this . source . push ( stack + " = (" + prefix + item + ");" ) ;
}
2013-02-05 14:16:51 -05:00
return stack ;
} ,
2013-02-19 11:27:20 -05:00
nextStack : function ( ) {
return this . pushStack ( ) ;
2013-02-05 14:16:51 -05:00
} ,
incrStack : function ( ) {
this . stackSlot ++ ;
if ( this . stackSlot > this . stackVars . length ) { this . stackVars . push ( "stack" + this . stackSlot ) ; }
2013-02-19 11:27:20 -05:00
return this . topStackName ( ) ;
} ,
topStackName : function ( ) {
2013-02-05 14:16:51 -05:00
return "stack" + this . stackSlot ;
} ,
2013-02-19 11:27:20 -05:00
flushInline : function ( ) {
var inlineStack = this . inlineStack ;
if ( inlineStack . length ) {
this . inlineStack = [ ] ;
for ( var i = 0 , len = inlineStack . length ; i < len ; i ++ ) {
var entry = inlineStack [ i ] ;
if ( entry instanceof Literal ) {
this . compileStack . push ( entry ) ;
} else {
this . pushStack ( entry ) ;
}
}
}
} ,
isInline : function ( ) {
return this . inlineStack . length ;
} ,
2013-02-05 14:16:51 -05:00
2013-02-19 11:27:20 -05:00
popStack : function ( wrapped ) {
var inline = this . isInline ( ) ,
item = ( inline ? this . inlineStack : this . compileStack ) . pop ( ) ;
2013-02-05 14:16:51 -05:00
2013-02-19 11:27:20 -05:00
if ( ! wrapped && ( item instanceof Literal ) ) {
2013-02-05 14:16:51 -05:00
return item . value ;
} else {
2013-02-19 11:27:20 -05:00
if ( ! inline ) {
this . stackSlot -- ;
}
2013-02-05 14:16:51 -05:00
return item ;
}
} ,
2013-02-19 11:27:20 -05:00
topStack : function ( wrapped ) {
var stack = ( this . isInline ( ) ? this . inlineStack : this . compileStack ) ,
item = stack [ stack . length - 1 ] ;
2013-02-05 14:16:51 -05:00
2013-02-19 11:27:20 -05:00
if ( ! wrapped && ( item instanceof Literal ) ) {
2013-02-05 14:16:51 -05:00
return item . value ;
} else {
return item ;
}
} ,
quotedString : function ( str ) {
return '"' + str
. replace ( /\\/g , '\\\\' )
. replace ( /"/g , '\\"' )
. replace ( /\n/g , '\\n' )
. replace ( /\r/g , '\\r' ) + '"' ;
} ,
2013-02-19 11:27:20 -05:00
setupHelper : function ( paramSize , name , missingParams ) {
2013-02-05 14:16:51 -05:00
var params = [ ] ;
2013-02-19 11:27:20 -05:00
this . setupParams ( paramSize , params , missingParams ) ;
2013-02-05 14:16:51 -05:00
var foundHelper = this . nameLookup ( 'helpers' , name , 'helper' ) ;
return {
params : params ,
name : foundHelper ,
callParams : [ "depth0" ] . concat ( params ) . join ( ", " ) ,
2013-02-19 11:27:20 -05:00
helperMissingParams : missingParams && [ "depth0" , this . quotedString ( name ) ] . concat ( params ) . join ( ", " )
2013-02-05 14:16:51 -05:00
} ;
} ,
// the params and contexts arguments are passed in arrays
// to fill in
2013-02-19 11:27:20 -05:00
setupParams : function ( paramSize , params , useRegister ) {
2013-02-05 14:16:51 -05:00
var options = [ ] , contexts = [ ] , types = [ ] , param , inverse , program ;
options . push ( "hash:" + this . popStack ( ) ) ;
inverse = this . popStack ( ) ;
program = this . popStack ( ) ;
// Avoid setting fn and inverse if neither are set. This allows
// helpers to do a check for `if (options.fn)`
if ( program || inverse ) {
if ( ! program ) {
this . context . aliases . self = "this" ;
program = "self.noop" ;
}
if ( ! inverse ) {
this . context . aliases . self = "this" ;
inverse = "self.noop" ;
}
options . push ( "inverse:" + inverse ) ;
options . push ( "fn:" + program ) ;
}
for ( var i = 0 ; i < paramSize ; i ++ ) {
param = this . popStack ( ) ;
params . push ( param ) ;
if ( this . options . stringParams ) {
types . push ( this . popStack ( ) ) ;
contexts . push ( this . popStack ( ) ) ;
}
}
if ( this . options . stringParams ) {
options . push ( "contexts:[" + contexts . join ( "," ) + "]" ) ;
options . push ( "types:[" + types . join ( "," ) + "]" ) ;
options . push ( "hashTypes:hashTypes" ) ;
}
if ( this . options . data ) {
options . push ( "data:data" ) ;
}
2013-02-19 11:27:20 -05:00
options = "{" + options . join ( "," ) + "}" ;
if ( useRegister ) {
this . register ( 'options' , options ) ;
params . push ( 'options' ) ;
} else {
params . push ( options ) ;
}
2013-02-05 14:16:51 -05:00
return params . join ( ", " ) ;
}
} ;
var reservedWords = (
"break else new var" +
" case finally return void" +
" catch for switch while" +
" continue function this with" +
" default if throw" +
" delete in try" +
" do instanceof typeof" +
" abstract enum int short" +
" boolean export interface static" +
" byte extends long super" +
" char final native synchronized" +
" class float package throws" +
" const goto private transient" +
" debugger implements protected volatile" +
" double import public let yield"
) . split ( " " ) ;
var compilerWords = JavaScriptCompiler . RESERVED _WORDS = { } ;
for ( var i = 0 , l = reservedWords . length ; i < l ; i ++ ) {
compilerWords [ reservedWords [ i ] ] = true ;
}
JavaScriptCompiler . isValidJavaScriptVariableName = function ( name ) {
if ( ! JavaScriptCompiler . RESERVED _WORDS [ name ] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/ . test ( name ) ) {
return true ;
}
return false ;
} ;
} ) ( Handlebars . Compiler , Handlebars . JavaScriptCompiler ) ;
2013-02-19 11:27:20 -05:00
Handlebars . precompile = function ( input , options ) {
if ( ! input || ( typeof input !== 'string' && input . constructor !== Handlebars . AST . ProgramNode ) ) {
throw new Handlebars . Exception ( "You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input ) ;
2013-02-05 14:16:51 -05:00
}
options = options || { } ;
if ( ! ( 'data' in options ) ) {
options . data = true ;
}
2013-02-19 11:27:20 -05:00
var ast = Handlebars . parse ( input ) ;
2013-02-05 14:16:51 -05:00
var environment = new Handlebars . Compiler ( ) . compile ( ast , options ) ;
return new Handlebars . JavaScriptCompiler ( ) . compile ( environment , options ) ;
} ;
2013-02-19 11:27:20 -05:00
Handlebars . compile = function ( input , options ) {
if ( ! input || ( typeof input !== 'string' && input . constructor !== Handlebars . AST . ProgramNode ) ) {
throw new Handlebars . Exception ( "You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input ) ;
2013-02-05 14:16:51 -05:00
}
options = options || { } ;
if ( ! ( 'data' in options ) ) {
options . data = true ;
}
var compiled ;
function compile ( ) {
2013-02-19 11:27:20 -05:00
var ast = Handlebars . parse ( input ) ;
2013-02-05 14:16:51 -05:00
var environment = new Handlebars . Compiler ( ) . compile ( ast , options ) ;
var templateSpec = new Handlebars . JavaScriptCompiler ( ) . compile ( environment , options , undefined , true ) ;
return Handlebars . template ( templateSpec ) ;
}
// Template is only compiled on first use and cached after that point.
return function ( context , options ) {
if ( ! compiled ) {
compiled = compile ( ) ;
}
return compiled . call ( this , context , options ) ;
} ;
} ;
;
// lib/handlebars/runtime.js
Handlebars . VM = {
template : function ( templateSpec ) {
// Just add water
var container = {
escapeExpression : Handlebars . Utils . escapeExpression ,
invokePartial : Handlebars . VM . invokePartial ,
programs : [ ] ,
program : function ( i , fn , data ) {
var programWrapper = this . programs [ i ] ;
if ( data ) {
return Handlebars . VM . program ( fn , data ) ;
} else if ( programWrapper ) {
return programWrapper ;
} else {
programWrapper = this . programs [ i ] = Handlebars . VM . program ( fn ) ;
return programWrapper ;
}
} ,
programWithDepth : Handlebars . VM . programWithDepth ,
2013-02-19 11:27:20 -05:00
noop : Handlebars . VM . noop ,
compilerInfo : null
2013-02-05 14:16:51 -05:00
} ;
return function ( context , options ) {
options = options || { } ;
2013-02-19 11:27:20 -05:00
var result = templateSpec . call ( container , Handlebars , context , options . helpers , options . partials , options . data ) ;
var compilerInfo = container . compilerInfo || [ ] ,
compilerRevision = compilerInfo [ 0 ] || 1 ,
currentRevision = Handlebars . COMPILER _REVISION ;
if ( compilerRevision !== currentRevision ) {
if ( compilerRevision < currentRevision ) {
var runtimeVersions = Handlebars . REVISION _CHANGES [ currentRevision ] ,
compilerVersions = Handlebars . REVISION _CHANGES [ compilerRevision ] ;
throw "Template was precompiled with an older version of Handlebars than the current runtime. " +
"Please update your precompiler to a newer version (" + runtimeVersions + ") or downgrade your runtime to an older version (" + compilerVersions + ")." ;
} else {
// Use the embedded version info since the runtime doesn't know about this revision yet
throw "Template was precompiled with a newer version of Handlebars than the current runtime. " +
"Please update your runtime to a newer version (" + compilerInfo [ 1 ] + ")." ;
}
}
return result ;
2013-02-05 14:16:51 -05:00
} ;
} ,
programWithDepth : function ( fn , data , $depth ) {
var args = Array . prototype . slice . call ( arguments , 2 ) ;
return function ( context , options ) {
options = options || { } ;
return fn . apply ( this , [ context , options . data || data ] . concat ( args ) ) ;
} ;
} ,
program : function ( fn , data ) {
return function ( context , options ) {
options = options || { } ;
return fn ( context , options . data || data ) ;
} ;
} ,
noop : function ( ) { return "" ; } ,
invokePartial : function ( partial , name , context , helpers , partials , data ) {
var options = { helpers : helpers , partials : partials , data : data } ;
if ( partial === undefined ) {
throw new Handlebars . Exception ( "The partial " + name + " could not be found" ) ;
} else if ( partial instanceof Function ) {
return partial ( context , options ) ;
} else if ( ! Handlebars . compile ) {
throw new Handlebars . Exception ( "The partial " + name + " could not be compiled when running in runtime-only mode" ) ;
} else {
partials [ name ] = Handlebars . compile ( partial , { data : data !== undefined } ) ;
return partials [ name ] ( context , options ) ;
}
}
} ;
Handlebars . template = Handlebars . VM . template ;
;