Implement multiline comments and be more forgiving of extra whitespace

This commit is contained in:
Matt Sherman 2023-10-04 15:47:06 -04:00
parent 1812a76f8d
commit 0646031217
2 changed files with 102 additions and 4 deletions

View File

@ -104,16 +104,22 @@ LineTerminatorSequence
/ "\\u2028"
/ "\\u2029"
Comment "comment"
= MultiLineComment
MultiLineComment
= "/*" (!"*/" SourceCharacter)* "*/"
__ "skipped"
= (WhiteSpace / LineTerminatorSequence )*
= (WhiteSpace / LineTerminatorSequence / Comment)*
IdentifierPath
= variable:Identifier accessor:("." Identifier)* {
= variable:Identifier accessor:(__ "." __ Identifier)* {
const path = variable.split( '.' );
let result = path.reduce( ( nextObject, propertyName ) => nextObject[ propertyName ], options.context );
for ( let i = 0; i < accessor.length; i++ ) {
result = result[ accessor[ i ][ 1 ] ];
result = result[ accessor[ i ][ 3 ] ];
}
return result;
@ -378,7 +384,9 @@ LogicalOrOperator
= "||"
Expression
= LogicalOrExpression
= __ expression:LogicalOrExpression __ {
return expression;
}
`;
export const parser = peggy.generate( grammar );

View File

@ -116,6 +116,12 @@ describe( 'evaluate', () => {
expect( result ).toEqual( "foo \\'bar\\'" );
} );
it( 'should evaluate a literal with whitespace around it', () => {
const result = evaluate( ' 23 ' );
expect( result ).toEqual( 23 );
} );
it( 'should evaluate a top-level context property', () => {
const result = evaluate( 'foo', {
foo: 'bar',
@ -124,6 +130,14 @@ describe( 'evaluate', () => {
expect( result ).toEqual( 'bar' );
} );
it( 'should evaluate a top-level context property with whitespace', () => {
const result = evaluate( ' foo ', {
foo: 'bar',
} );
expect( result ).toEqual( 'bar' );
} );
it( 'should evaluate a nested context property', () => {
const result = evaluate( 'foo.bar', {
foo: {
@ -134,6 +148,30 @@ describe( 'evaluate', () => {
expect( result ).toEqual( 'baz' );
} );
it( 'should evaluate a nested context property with whitespace', () => {
const result = evaluate( 'foo. bar', {
foo: {
bar: 'baz',
},
} );
expect( result ).toEqual( 'baz' );
} );
it( 'should evaluate a nested context property with multiple lines', () => {
const result = evaluate(
`foo.
bar`,
{
foo: {
bar: 'baz',
},
}
);
expect( result ).toEqual( 'baz' );
} );
it( 'should evaluate a NOT expression', () => {
const result = evaluate( '!foo', {
foo: true,
@ -158,6 +196,14 @@ describe( 'evaluate', () => {
expect( result ).toEqual( false );
} );
it( 'should evaluate a NOT expression with parentheses and spaces', () => {
const result = evaluate( '! ( foo ) ', {
foo: true,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a multiplication expression', () => {
const result = evaluate( 'foo * 2', {
foo: 2,
@ -351,6 +397,50 @@ describe( 'evaluate', () => {
expect( result ).toEqual( true );
} );
it( 'should evaluate an expression with a multiline comment at the end', () => {
const result = evaluate( 'foo /* + 23 */', {
foo: 5,
} );
expect( result ).toEqual( 5 );
} );
it( 'should evaluate an expression with a multiline comment at the beginning', () => {
const result = evaluate( '/* 23 + */ foo', {
foo: 5,
} );
expect( result ).toEqual( 5 );
} );
it( 'should evaluate an expression with a multiline comment in the middle', () => {
const result = evaluate( 'foo + /* 23 */ bar', {
foo: 5,
bar: 3,
} );
expect( result ).toEqual( 8 );
} );
it( 'should evaluate a multiline expression with a multiline comment', () => {
const result = evaluate(
`foo
/*
+ bar
+ boo
*/
+ baz`,
{
foo: 5,
bar: 23,
boo: 6,
baz: 3,
}
);
expect( result ).toEqual( 8 );
} );
it( 'should throw an error if the expression is invalid', () => {
expect( () => evaluate( '= 1' ) ).toThrow();
} );