export default function readPartial ( parser, tag ) { var start, nameStart, expression, context, partial; start = parser.pos; if ( !parser.matchString( '>' ) ) { return null; } parser.allowWhitespace(); nameStart = parser.pos; // Partial names can include hyphens, so we can't use readExpression // blindly. Instead, we use the `relaxedNames` flag to indicate that // `foo-bar` should be read as a single name, rather than 'subtract // bar from foo' parser.relaxedNames = true; expression = readExpression( parser ); parser.relaxedNames = false; parser.allowWhitespace(); context = readExpression( parser ); parser.allowWhitespace(); if ( !expression ) { return null; } partial = { t: PARTIAL }; refineExpression( expression, partial ); // TODO... parser.allowWhitespace(); // if we have another expression - e.g. `{{>foo bar}}` - then // we turn it into `{{#with bar}}{{>foo}}{{/with}}` if ( context ) { partial = { t: SECTION, n: SECTION_WITH, f: [ partial ] }; refineExpression( context, partial ); } if ( !parser.matchString( tag.close ) ) { parser.error( `Expected closing delimiter '${tag.close}'` ); } return partial; }
export default function readBracketedExpression ( parser ) { var start, expr; start = parser.pos; if ( !parser.matchString( '(' ) ) { return null; } parser.allowWhitespace(); expr = readExpression( parser ); if ( !expr ) { parser.error( expectedExpression ); } parser.allowWhitespace(); if ( !parser.matchString( ')' ) ) { parser.error( expectedParen ); } return { t: BRACKETED, x: expr }; }
// The conditional operator is the lowest precedence operator, so we start here export default function getConditional ( parser ) { var start, expression, ifTrue, ifFalse; expression = readLogicalOr( parser ); if ( !expression ) { return null; } start = parser.pos; parser.allowWhitespace(); if ( !parser.matchString( '?' ) ) { parser.pos = start; return expression; } parser.allowWhitespace(); ifTrue = readExpression( parser ); if ( !ifTrue ) { parser.error( expectedExpression ); } parser.allowWhitespace(); if ( !parser.matchString( ':' ) ) { parser.error( 'Expected ":"' ); } parser.allowWhitespace(); ifFalse = readExpression( parser ); if ( !ifFalse ) { parser.error( expectedExpression ); } return { t: CONDITIONAL, o: [ expression, ifTrue, ifFalse ] }; }
export default function readTriple ( parser, tag ) { var expression = readExpression( parser ), triple; if ( !expression ) { return null; } if ( !parser.matchString( tag.close ) ) { parser.error( `Expected closing delimiter '${tag.close}'` ); } triple = { t: TRIPLE }; refineExpression( expression, triple ); // TODO handle this differently - it's mysterious return triple; }
export default function readRefinement ( parser ) { var start, name, expr; start = parser.pos; parser.allowWhitespace(); // "." name if ( parser.matchString( '.' ) ) { parser.allowWhitespace(); if ( name = parser.matchPattern( namePattern ) ) { return { t: REFINEMENT, n: name }; } parser.error( 'Expected a property name' ); } // "[" expression "]" if ( parser.matchString( '[' ) ) { parser.allowWhitespace(); expr = readExpression( parser ); if ( !expr ) { parser.error( expectedExpression ); } parser.allowWhitespace(); if ( !parser.matchString( ']' ) ) { parser.error( 'Expected \']\'' ); } return { t: REFINEMENT, x: expr }; } return null; }
export default function readKeyValuePair ( parser ) { var start, key, value; start = parser.pos; // allow whitespace between '{' and key parser.allowWhitespace(); key = readKey( parser ); if ( key === null ) { parser.pos = start; return null; } // allow whitespace between key and ':' parser.allowWhitespace(); // next character must be ':' if ( !parser.matchString( ':' ) ) { parser.pos = start; return null; } // allow whitespace between ':' and value parser.allowWhitespace(); // next expression must be a, well... expression value = readExpression( parser ); if ( value === null ) { parser.pos = start; return null; } return { t: KEY_VALUE_PAIR, k: key, v: value }; }
export default function readElse ( parser, tag ) { var start = parser.pos, expression; if ( !parser.matchString( tag.open ) ) { return null; } if ( !parser.matchPattern( elsePattern ) ) { parser.pos = start; return null; } expression = readExpression( parser ); if ( !parser.matchString( tag.close ) ) { parser.error( `Expected closing delimiter '${tag.close}'` ); } return { t: ELSEIF, x: expression }; }