Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

if-expression leads to "parse error" if it is last line in header #327

Open
TheChatty opened this issue Feb 12, 2024 · 10 comments
Open

if-expression leads to "parse error" if it is last line in header #327

TheChatty opened this issue Feb 12, 2024 · 10 comments

Comments

@TheChatty
Copy link

TheChatty commented Feb 12, 2024

I have the following input:

{
  "ADDRESS": "Streetname 1",
  "ADDRESS2": {
    "TYPE": "MB",
    "content": "Streetname 2"
  }
}

And the following JSLT:

let address = if(is-object(.ADDRESS)) .ADDRESS.content else .ADDRESS
let address2 = if(is-object(.ADDRESS2)) .ADDRESS2.content else .ADDRESS2
//let dummy = ""

[
  {
    "Address": $address
  },
  {
    "Address2": $address2
  }
]

If you reenable the commented out line the JSLT works. If you leave it as it is, you get:

com.schibsted.spt.data.jslt.JsltException: Parse error: Encountered " "," ", "" at line 8, column 4.
Was expecting one of:
    "]" ...
    ":" ...
    "or" ...
    "and" ...
    "==" ...
    "!=" ...
    ">=" ...
    ">" ...
    "<" ...
    "<=" ...
    "+" ...
    "-" ...
    "*" ...
    "/" ...
    "|" ...
     at <inline>:8:3
	at com.schibsted.spt.data.jslt.parser.ParserImpl.compileExpression(ParserImpl.java:62)
	at com.schibsted.spt.data.jslt.Parser.compile(Parser.java:226)
	at com.schibsted.spt.data.jslt.Parser.compileString(Parser.java:86)
	at com.schibsted.spt.data.jslt.Parser.compileString(Parser.java:74)
	at no.priv.garshol.jslt.playground.PlaygroundServer$JsltHandler.handle(PlaygroundServer.java:54)
	at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:59)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
	at org.eclipse.jetty.server.Server.handle(Server.java:516)
	at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487)
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
	at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
	at java.base/java.lang.Thread.run(Thread.java:829)

The problem can also be avoided if ... else .ADDRESS2 is changed to ... else "". Of course this changes the logic but might help tracking down the underneath error.

@catull
Copy link

catull commented Feb 12, 2024

The method/function you can use is fallback

Try:

[
  {
    "Address": fallback (.ADDRESS.content,.ADDRESS)
  },
  {
    "Address2": fallback (.ADDRESS2.content,.ADDRESS2)
  }
]

@catull
Copy link

catull commented Feb 12, 2024

Another variant:

let address  = fallback (.ADDRESS.content , .ADDRESS)
let address2 = fallback (.ADDRESS2.content, .ADDRESS2)

def process()
[
  {
    "Address": $address
  },
  {
    "Address2": $address2
  }
]

process()

@TheChatty
Copy link
Author

The method/function you can use is fallback

Try:

[
  {
    "Address": fallback (.ADDRESS.content,.ADDRESS)
  },
  {
    "Address2": fallback (.ADDRESS2.content,.ADDRESS2)
  }
]

Thank you. I had found this function myself in betweeen. I was merely reporting this as it proves there is some mistake in JSLT library.

@catull
Copy link

catull commented Feb 12, 2024

If have to disagree; your original version was syntactically incorrect.
You were using "let"-statements outside of a function, basically.

As soon as you use "let"-statements, you have to introduce a function body (def SOMETHING() .....).
This is the second variant I mention above.

@TheChatty
Copy link
Author

A quote from the tutorial:

Let statements are allowed at the top level, at the start of objects, inside for (before the expression), and inside if.

@larsga
Copy link
Collaborator

larsga commented Feb 13, 2024

Yes, sorry, @catull, but this is a problem with the JSLT grammar. It has nothing to do with function bodies. The question is how to solve it without breaking backward compatibility.

@catull
Copy link

catull commented Feb 13, 2024

Touché.

However, that stement is not correct.
The grammar specifies root production as

void Start() :
{}
{
  (Import())*
  (Let() | FunctionDecl())*
  Expr() <EOF>
}

Ignore the Import.
The rule states that you can have zero or any Let-statement or Function declarations at the start.
But then, one expression must follow.

Now "Expr()" does not include array production.

If the rule were this:

void Start() :
{}
{
  (Import())*
  (Let() | FunctionDecl())*
  Expr() | ArraySlicing() <EOF>
}

then your original code might work.
I am only an occasional JSLT user by now, my analysis might be off.

At any rate, either the statement you quote is inaccurate, or the implementation is incomplete.
Either way, you found a bug, I dare say.

@catull
Copy link

catull commented Feb 13, 2024

Yes, sorry, @catull, but this is a problem with the JSLT grammar. It has nothing to do with function bodies. The question is how to solve it without breaking backward compatibility.

You beat my to it.

@catull
Copy link

catull commented Feb 13, 2024

Actually, I am mistaken.

The rule would have to be:

void Start() :
{}
{
  (Import())*
  (Let() | FunctionDecl() | IfStatetement())*
  Expr() | ArraySlicing() <EOF>
}

Again, I am an amateur JSTL coder.

@larsga
Copy link
Collaborator

larsga commented Feb 13, 2024

Hey, no worries. Everyone makes mistakes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants