Antlr4 - gated semantic predicates - antlr4

Since Antlr4 no longer supports gated semantic predicates, I came up with a workaround. However, if anyone has run into this, I would like to know if there are any caveats to doing something like this and also am I following best practices.
I'm following the standard 'C' if statement in the form of:
if (evaluation) {
...code block
}
Here is the code in the code block:
if ($result == false) { // If the statement evealuates to false
// Consume tokens until the end of block marker
while (getCurrentToken().getText().compareTo("}") != 0){
consume();
}
// Set the parser state as if it had executed the tokens
_localctx.start = getCurrentToken();
_ctx.start = getCurrentToken();
setState(220);
_errHandler.sync(this);
consume(); // Consume the end of block marker
return _localctx; // Exit the rule
}
I figure that Terrance Parr must have had a good reason to take out the support for a gated semantic predicate and this seems like a simple workaround. I'm just wondering if I'm missing something.
I tested it and it works, even with an 'else'. I have not tried it with compound evaluation statements (ie conditions separated with '&&' or '||'. I have a high confidence that it will work though.

Related

DML Conditional top level "in each" statements

When trying to use in each statements like the following I get an unknown identifier error.
dml 1.4;
param MACRO = true;
#if (MACRO){
in each bank {
in each register {
param something = 1;
}
}
}
At compile time this errors out with the following message:
/modules/test-device/test-device.dml:179:6: error: unknown identifier: 'MACRO'
Despite the MACRO value being defined in the same file.
I know conditional in each statements are not allowed under DML and there is even an specific error for it: "conditional 'in each' is not allowed [ECONDINEACH]"
But I am getting a different error and the following snippet works with no problem:
dml 1.4;
#if (dml_1_2){
in each bank {
in each register {
param something = 1;
}
}
}
So why am I getting a different error and Is there a way to get around this?
As you mentioned, some statements like in each, but also others like typedef, template, import etc are generally disallowed directly inside an #if. There is a long-standing DML feature request to soften this restriction; in particular, this was critically needed during the DML 1.2 to DML 1.4 migration. The restriction was partially softened by adding a hack that permits top-level #if statements with forbidden statements, as long as the condition only refers to some known constants (true, false and dml_1_2).
Technically, this workaround is implemented by considering top-level #if statements as completely separate constructs depending on whether the body contains forbidden statements. If it does, the condition is evaluated in a special variable scope that only contains the three symbols true, false and dml_1_2. This explains why the error message changes from conditional 'in each' is not allowed into unknown identifier.
In your concrete #if (MACRO) example, I don't know a valid way to express that; however, in similar situations you can often solve the problem by making sure the in each statement appears in a subobject of the #if statement; e.g., if you have:
bank regs {
#if (MACRO) {
// compile error: 'in each' directly inside '#if'
in each register {
param something = 1;
}
}
}
then you can change it to:
#if (MACRO) {
bank regs {
// ok: 'in each' in a subobject of the '#if'
in each register {
param something = 1;
}
}
}
Another approach that sometimes is applicable, is if the MACRO param relates to the choice of code generator for bank skeletons; e.g., if you generate DML code for bank skeletons from IPXACT using two different frameworks, say X and Y, and MACRO determines which of these frameworks was used, then chances are that each of these frameworks instantiates a common template, say x_register vs y_register, on all generated registers, or a common template x_bank vs y_bank on all banks. If you can identify such a template, then you can write:
in each (x_register, register) {
// applied to all registers generated by the X framework
param something = 1;
}
or:
in each x_bank {
in each register {
param something = 1;
}
}

Determining whether a value is known at plan-time

Terraform allows values to be marked as "unknown" during the plan step, since many values may only be known after apply of certain resources.
Is there any way, during the plan step, to check if a value is known or unknown?
Specifically, I'd like to be able to do something like this:
locals {
foo = "hello world"
bar = uuid()
}
output "foo_known" {
value = knownatplan(local.foo)
}
output "bar_known" {
value = knownatplan(local.bar)
}
Outputs:
foo_known = true
bar_known = false
Where knownatplan would be a function, or some sort of other mechanism, to determine if the value is known at plan time.
There is no mechanism to do this because to do so would break an assumption that Terraform relies on to do its work: that replacing unknown values with known values during the final apply step can only add information, never change information. The above guarantee is fundamental to the concept of planning a change before taking any side-effects.
Other systems whose language doesn't have this mechanism can only provide a hypothetical "dry run" of changes that may not be complete or accurate, whereas Terraform aims to make the additional promise that it will either make the changes as shown in the plan or return an error explaining why it cannot. Any situation where applying the plan succeeds but generates a result other than what the plan reported is always considered to be a bug, either in Terraform Core itself or in the relevant provider. Unknown values are a big part of how Terraform keeps that promise.
I wrote about this in more detail in a blog article Unknown Values: The Secret to Terraform Plan.
I had a little bit time now, and could implement a cool "feature" the inventors of terraform would not much like. ^-^
I am author of terraform-provider-value (github) (terraform registry) and there I have two resources called value_is_fully_known (link) and value_is_known (link). Sounds good? Just look look in the documentation or look here for some examples.
Fundamentally they allow you to have a true or false for a value that might be "(known after apply)" before you actually apply! Here an example:
terraform {
required_providers {
value = {
source = "pseudo-dynamic/value"
version = "0.5.1"
}
}
}
locals {
foo = "hello world"
bar = uuid()
}
resource "value_unknown_proposer" "default" {}
resource "value_is_known" "foo" {
value = local.foo
guid_seed = "foo"
proposed_unknown = value_unknown_proposer.default.value
}
resource "value_is_known" "bar" {
value = local.bar
guid_seed = "bar"
proposed_unknown = value_unknown_proposer.default.value
}
output "foo_known" {
value = value_is_known.foo.result
}
output "bar_known" {
value = value_is_known.bar.result
}
which results into:
Outputs:
bar_known = false
foo_known = true
Before actual apply?
Concretely you are running through two plan-phases, one I call plan-phase and the other one I call apply-phase, which includes another, independent and implicit plan-phase.
The plan-phase is characteristical when you see the plan, the potencial results (most of the times with a lot of "known after apply"-values") and the message "Terraform will perform the following actions:".
The apply-phase on the other side is, when all values are calculated in the view of the provider author, terraform or you when you see "Apply complete!".
It was very challenging to implement an acceptable solution because during the plan-phase the provider has no chance to to save anything because nothing is persistent. Only changes in the implicit plan-phase are stored when apply-phase was successful.
My thoughts
To know before you apply whether a value is known or unknown, can enable you some cool workflows in terraform but they should be very limited. I can only encourage you to use this mechanism as rarely as possible. But if you have some cool usages for it, do you mind to share them? Feel free to open pull request to add an example or begin a discussion.
Any form of feedback (constructive critism, bugs and ideas) I appreciate a lot. =)

How to show the flow termination in Sequence Diagram

Basically, I'd like to depict the below logic in a Sequence Diagram:
if (ShopIsOpen) {
if (AccessTokenIsExpired) {
if (RefreshTokenInExpired) {
return "Not Authorized";
}
IdentityServer.RequestAccessTokenByRefreshToken();
return Resource.RequestResourceByAccessToken();
}
} else {
return "Shop is closed";
}
I've come up with the below diagram, but I am not sure if it is correct.
Mainly, I am not sure if break in the diagram correctly communicates the intention of termination of flow: does it imply jumping out of the outer opt or the outer alt?
Any help is much appreciated.
The break fragment leaves the immediately enclosing fragment. In your case that would be the opt fragment. So, it is not correct. Why don’t you use nested alt fragments?
Some additional remarks: The reply to a synchronous message is shown with a dashed line and the returned value is shown with a leading colon (and the name of the original message, but I think it is obvious here anyway).

How to prevent loops in jointjs / rappid

I'm building an application which uses jointjs / rappid and I want to be able to avoid loops from occuring across multiple cells.
Jointjs already has some examples on how to avoid this in a single cell (connecting an "out" port to an "in" port of the same cell) but has nothing on how to detect and prevent loops from occuring further up in the chain.
To help understand, imagine each cell in the paper is a step to be completed. Each step should only ever be run once. If the last step has an "out" port that connects to the "in" port of the first cell, it will just loop forever. This is what I want to avoid.
Any help is greatly appreciated.
I actually found a really easy way to do this for anyone else who wishes to achieve the same thing. Simply include the graphlib dependancy and use the following:
paper.on("link:connect", function(linkView) {
if(graphlib.alg.findCycles(graph.toGraphLib()).length > 0) {
linkView.model.remove();
// show some error message here
}
});
This line:
graphlib.alg.findCycles(graph.toGraphLib())
Returns an array that contains any loops, so by checking the length we can determine whether or not the paper contains any loops and if so, remove the link that the user is trying to create.
Note: This isn't completely full-proof because if the paper already contains a loop (before the user adds a link) then simply removing the link that the user is creating won't remove any loop that exists. For me this is fine because all of my papers will be created from scratch so as long as this logic is always in place, no loops can ever be created.
Solution through graphlib
Based on Adam's graphlib solution, instead of findCycles to test for loops, the graphlib docs suggests to use the isAcyclic function, which:
returns true if the graph has no cycles and returns false if it does. This algorithm returns as soon as it detects the first cycle.
Therefore this condition:
if(graphlib.alg.findCycles(graph.toGraphLib()).length > 0)
Can be shortened to:
if(!graphlib.alg.isAcyclic(graph))
JointJS functions solution
Look up the arrays of ancestors and successors of a newly connected element and intersect them:
// invoke inside an event which tests if a specific `connectedElement` is part of a loop
function isElementPartOfLoop (graph, connectedElement) {
var elemSuccessors = graph.getSuccessors(connectedElement, {deep: true});
var elemAncestors = connectedElement.getAncestors();
// *** OR *** graph.getPredecessors(connectedElement, {deep: true});
var commonElements = _.intersection(elemSuccessors, elemAncestors);
// if an element is repeated (non-empty intersection), then it's part of a loop
return !_.isEmpty(commonElements);
}
I haven't tested this, but the theory behind the test you are trying to accomplish should be similar.
This solution is not as efficient as using directly the graphlib functions.
Prevention
One way you could prevent the link from being added to the graph is by dealing with it in an event:
graph.on('add', _.bind(addCellOps, graph));
function addCellOps (cell, collection, opt) {
if (cell.isLink()){
// test link's target element: if it is part of a loop, remove the link
var linkTarget = cell.getTargetElement();
// `this` is the graph
if(target && isElementPartOfLoop(this, linkTarget)){
cell.remove();
}
}
// other operations ....
}

What's the mapping from Type.getSort() to the local and stack arrays in visitFrame(...)?

I need to adapt my code to the stricter Java 7 verifier and have to add visitFrame calls in my MethodNode (I'm using the tree api). I could not find any information on how Type maps to the Object[]s used in visitFrame, so please help me out here...
This is what I have so far:
private Object getFrameType(Type type) {
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return Opcodes.INTEGER;
case Type.LONG:
return Opcodes.LONG;
case Type.FLOAT:
return Opcodes.FLOAT;
case Type.DOUBLE:
return Opcodes.DOUBLE;
case Type.OBJECT:
case Type.ARRAY:
return type.getInternalName();
}
throw new RuntimeException(type + " can not be converted to frame type");
}
What I'd like to know is: what are Type.VOID and Type.METHOD?
When do I need Opcodes.TOP, Opcodes.NULL and Opcodes.UNINITIALIZED_THIS?
I'm guessing UNINITIALIZED_THIS is only used in the constructor and I can probably ignore VOID and METHOD, but I'm not sure and I don't have the slightest idea what TOP is.
If I understood your need correctly, you could just let ASM calculate the frames for you. This will probably slow down the class generation a bit, but certainly worth a try.
When creating the ClassWriter, just add COMPUTE_FRAMES to the flags argument of the constructor, e.g.
new ClassWriter(ClassWriter.COMPUTE_FRAMES);
Similarly, if you are transforming a class, the ClassReader can be asked to expand the frames like:
ClassReader cr = ...;
ClassNode cn = new ClassNode(ASM4);
cr.accept(cn, ClassReader.EXPAND_FRAMES);
The former option has the benefit that you can forget about the frames (and "maxs") altogether while the latter option might require you to patch the frames yourself depending on what kind of transformation you do.
The examples are for ASM version 4, but these features have been supported at least since version 3 - the parameters are just passed a bit differently.

Resources