Parse error: `not` after a colon in a struct literal (`{ a: not b }`) doesn't compile

Title: Parse error: not after a colon in a struct literal ({ a: not b }) doesn’t compile

Versions

  • BoxLang 1.18.0+66 (MiniServer), Java 21 (Temurin 21.0.13), Windows 11
  • bx-compat-cfml 1.40.0+56

What happens
A struct literal whose value starts with the not operator, written with a colon, fails to compile. The same code compiles on Adobe ColdFusion and Lucee.

<cfset t = true>
<cfset item = { a: not t }>
Error compiling [ ...\Test.cfc ]. ...\Test.cfc: Line: 4 Col: 2 - 'cf' was unexpected
expecting one of: slash_prefix

In a tag-based component, the error points at the start of the function’s first tag, not at the struct literal, so it took a while to find. In script, it fails the same way:

component {
	function f() {
		var t = true;
		var item = { a: not t };   // fails
		return item;
	}
}

What compiles and what doesn’t (each tested alone in a component, BoxLang 1.18.0):

Value in the struct literal Result
{ a: not t } fails
{ "a": not t } fails
{ a: not t, b: 1 } fails
{ a: not t eq false } fails
{ a: not (t) } compiles
{ a: (not t) } compiles
{ a: !t } compiles
{ a = not t } compiles
x = not t compiles

So it seems to be not followed by an identifier, right after the : of a struct key.

Workaround
Wrap the value in parentheses, { a: (not t) }, or use !. I’ve done that in Galaxie Blog (one place: isPast: (not nowUtc.isBefore(...))).

Context
I am getting Galaxie Blog (GitHub - GregoryAlexander77/Galaxie-Blog: Free, open-source blog and CMS for Adobe ColdFusion and Lucee: themes, pages, scrolling scenes, a shop and bookings built in. · GitHub) running on BoxLang. Thank you for the very quick fix to <cfquery dbtype="hql"> (BLMODULES-306): with the 1.7.3 snapshot of bx-orm, the installer now gets past every HQL query and creates the whole database.

I believe this was fixed 2 weeks ago in this ticket
https://ortussolutions.atlassian.net/browse/BL-2754
Please try the 1.19 snapshot version of BoxLang

I just added this test to our suite and it passes

		// @formatter:off
		instance.executeSource(
			"""
				t = true
				result = {
					a: not t
				};
			""",
		    context, BoxSourceType.CFSCRIPT );
		// @formatter:on
		assertThat( variables.get( result ) ).isEqualTo( Struct.of( "a", false ) );

Thanks for checking, and for adding the test! I’m on 1.18, so that explains it. For now I put the value in parentheses (isPast: (not ...)), which works on 1.18. I’ll try the 1.19 snapshot and let you know if I still see it. I first ran into it in a tag-based component, so I’ll check that case too.

Quick follow-up: I tried the 1.19 snapshot and it works, in script, in a tag-based component, and in a .cfm page. Thanks again!

1 Like