ANTLR4: Code generation for if statement - if-statement

How do I emit branching code for an "if" statement defined like this in ANTLR4?
statement
: // stuff
| If LPar cond=expression RPar trueBlock=statement (Else falseBlock=statement)? # IfStatement
;
Basically, it's just like in the Java.g4 example I used as a reference (see "statement" and "expression" rules).
The problem is that I can't figure out how to emit branching code for that in a listener and I'm trying to avoid adding any {code} in the grammar file. For example, if I EnterIfStatement, then it's too early to emit branching because the condition code is yet to be generated. And when I ExitIfStatement, it's too late because the whole if block code has already been created. ANTLR4 doesn't create any EnterTrueBlock event or something like that.
I think of a couple of possible workarounds using dictionaries to remember contexts and generate jump instructions when I catch related expressions but it just doesn't feel natural.

Today I learned the visitor pattern fits compilation tasks better.
public override string VisitIfStatement(MylangParser.IfStatementContext context)
{
var hash = context.GetHashCode();
Visit(context.cond);
var elseLabel = "else" + hash;
var endIfLabel = "end_if" + hash;
emitter.Emit(OpCode.Jiz, elseLabel);
if (context.trueBlock != null)
{
Visit(context.trueBlock);
}
emitter.Emit(OpCode.Jmp, endIfLabel);
emitter.Mark(elseLabel);
if (context.falseBlock != null)
{
Visit(context.falseBlock);
}
emitter.Mark(endIfLabel);
return null;
}

Related

Prettier putting if statement on one line

Prettier formats if statement without curley braces into one line.
This means that this :
function getErrorMessage(response) {
let errorMessage = null;
if (!response.originalError.response)
errorMessage = 'network error';
else
errorMessage = response.originalError.response.data.errorMessage;
return errorMessage;
}
becomes this :
function getErrorMessage(response) {
let errorMessage = null;
if (!response.originalError.response) errorMessage = 'network error';
else errorMessage = response.originalError.response.data.errorMessage;
return errorMessage;
}
which is FAR more unreadable.
Is there a way of disabling this?
As asked in a similar question, it turns out that the answer is that you can not and will not be able to.
As for the WFT that an average senses, well... Apparently, opinionated doesn't mean respected and well-considered in opinion of many. It means that it's implementing the author's opinion.
So, surprisingly, the unexpected thing isn't the lack of configurability but rather that there are any options to be set at all! Go figure... Someone should create a new package called EvenPrettier or FexiblyPrettier and fork in more options. If I only knew how, I'd do it.
I finally ended up using Beautify - HookyQR extension for vscode
https://marketplace.visualstudio.com/items?itemName=HookyQR.beautify
Example Settings
File: .jsbeautifyrc
{
"brace_style": "collapse,preserve-inline",
"max_preserve_newlines": 2,
"end_with_newline": false
}
Example Code
File: a.js
function dfs(start) {
if (start > n)
return;
ans.push(start);
for (let i = 0; i <= 9; i++)
dfs(start * 10 + i);
}

How do I query multiple IDs via the ContentSearchManager?

When I have an array of Sitecore IDs, for example TargetIDs from a MultilistField, how can I query the ContentSearchManager to return all the SearchResultItem objects?
I have tried the following which gives an "Only constant arguments is supported." error.
using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
rpt.DataSource = s.GetQueryable<SearchResultItem>().Where(x => f.TargetIDs.Contains(x.ItemId));
rpt.DataBind();
}
I suppose I could build up the Linq query manually with multiple OR queries. Is there a way I can use Sitecore.ContentSearch.Utilities.LinqHelper to build the query for me?
Assuming I got this technique to work, is it worth using it for only, say, 10 items? I'm just starting my first Sitecore 7 project and I have it in mind that I want to use the index as much as possible.
Finally, does the Page Editor support editing fields somehow with a SearchResultItem as the source?
Update 1
I wrote this function which utilises the predicate builder as dunston suggests. I don't know yet if this is actually worth using (instead of Items).
public static List<T> GetSearchResultItemsByIDs<T>(ID[] ids, bool mustHaveUrl = true)
where T : Sitecore.ContentSearch.SearchTypes.SearchResultItem, new()
{
Assert.IsNotNull(ids, "ids");
if (!ids.Any())
{
return new List<T>();
}
using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
var predicate = PredicateBuilder.True<T>();
predicate = ids.Aggregate(predicate, (current, id) => current.Or(p => p.ItemId == id));
var results = s.GetQueryable<T>().Where(predicate).ToDictionary(x => x.ItemId);
var query = from id in ids
let item = results.ContainsKey(id) ? results[id] : null
where item != null && (!mustHaveUrl || item.Url != null)
select item;
return query.ToList();
}
}
It forces the results to be in the same order as supplied in the IDs array, which in my case is important. (If anybody knows a better way of doing this, would love to know).
It also, by default, ensures that the Item has a URL.
My main code then becomes:
var f = (Sitecore.Data.Fields.MultilistField) rootItem.Fields["Main navigation links"];
rpt.DataSource = ContentSearchHelper.GetSearchResultItemsByIDs<SearchResultItem>(f.TargetIDs);
rpt.DataBind();
I'm still curious how the Page Editor copes with SearchResultItem or POCOs in general (my second question), am going to continue researching that now.
Thanks for reading,
Steve
You need to use the predicate builder to create multiple OR queries, or AND queries.
The code below should work.
using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
var predicate = PredicateBuilder.True<SearchResultItem>();
foreach (var targetId in f.Targetids)
{
var tempTargetId = targetId;
predicate = predicate.Or(x => x.ItemId == tempTargetId)
}
rpt.DataSource = s.GetQueryable<SearchResultItem>().Where(predicate);
rpt.DataBind();
}

Json regex deserialization with JSON.Net

I'm trying to read the following example json from a text file into a string using the JSON.Net parsing library.
Content of C:\temp\regeLib.json
{
"Regular Expressions Library":
{
"SampleRegex":"^(?<FIELD1>\d+)_(?<FIELD2>\d+)_(?<FIELD3>[\w\&-]+)_(?<FIELD4>\w+).txt$"
}
}
Example code to try and parse:
Newtonsoft.Json.Converters.RegexConverter rConv = new Newtonsoft.Json.Converters.RegexConverter();
using (StreamReader reader = File.OpenText(libPath))
{
string foo = reader.ReadToEnd();
JObject jo = JObject.Parse(foo);//<--ERROR
//How to use RegexConverter to parse??
Newtonsoft.Json.JsonTextReader jtr = new Newtonsoft.Json.JsonTextReader(reader);
JObject test = rConv.ReadJson(jtr);//<--Not sure what parameters to provide
string sampleRegex = test.ToString();
}
It seems I need to use the converter, I know the code above is wrong, but I can't find any examples that describe how / if this can be done. Is it possible to read a regular expression token from a text file to a string using JSON.Net? Any help is appreciated.
UPDATE:
Played with it more and figured out I had to escape the character classes, once I made the correction below I was able to parse to a JObject and use LINQ to query for the regex pattern.
Corrected content C:\temp\regeLib.json
{
"Regular Expressions Library":
{
"SampleRegex":"^(?<FIELD1>\\d+)_(?<FIELD2>\\d+)_(?<FIELD3>[\\w\\&-]+)_(?<FIELD4>\\w+).txt$"
}
}
Corrected code
using (StreamReader reader = File.OpenText(libPath))
{
string content = reader.ReadToEnd().Trim();
JObject regexLib = JObject.Parse(content);
string sampleRegex = regexLib["Regular Expressions Library"]["SampleRegex"].ToString();
//Which then lets me do the following...
Regex rSampleRegex = new Regex(sampleRegex);
foreach (string sampleFilePath in Directory.GetFiles(dirSampleFiles, "*"))
{
filename = Path.GetFileName(sampleFilePath);
if (rSampleRegex.IsMatch(filename))
{
//Do stuff...
}
}
}
Not sure if this is the best approach, but it seems to work for my case.
i don't understand why you have to store such a small regex in a json file, are you going to expand the regex in the future?
if so, rather than doing this
JObject regexLib = JObject.Parse(content);
string sampleRegex = regexLib["Regular Expressions Library"]["SampleRegex"].ToString();
Consider using json2csharp to make classes, at least it's strongly-typed and make it more maintainable.
I think a more appropriate json would look like this (assumptions):
{
"Regular Expressions Library": [
{
"SampleRegex": "^(?<FIELD1>\\d+)_(?<FIELD2>\\d+)_(?<FIELD3>[\\w\\&-]+)_(?<FIELD4>\\w+).txt$"
},
{
"SampleRegex2": "^(?<FIELD1>\\d+)_(?<FIELD2>\\d+)_(?<FIELD3>[\\w\\&-]+)_(?<FIELD4>\\w+).txt$"
}
]
}
It would make more sense this way to store a regex in a "settings" file

How can I create multiple action delegates at run time and add it in the list of action delegate?

My code is like this:
Dictionary<string, string> specialCharacters = new Dictionary<string, string>();
specialCharacters.Add("#", "%");
specialCharacters.Add("*", "^");
List<Action<Employee>> listOfDel = new List<Action<Employee>>();
foreach (KeyValuePair<string, string> character in specialCharacters)
{
Action<Employee> replace = (empData) => empData.EmpName = empData.EmpName.ToString().Replace(character.Key, character.Value);
listOfDel.Add(replace);
//listOfDel.Add(new Action<Employee>((empData) => empData.EmpName = empData.EmpName.ToString().Replace(character.Key, character.Value)));
}
The issue is the list listOfDel has the same action as it refers to same function replace which takes value of last pair of character.Key, character.Value (("", "^")
I want a result having different actions in the list of actions listOfDel , where each method will have different value present. ("#", "%"), ("", "^");
I also tried creating a new instance of action delegate and using it as anonymous method.Please see commented code, yet the problem is not solved.
The problem is that you're capturing the iterator variable. There's only one variable declared by the foreach loop, so by the time you execute the delegates, they'll all be using the same value (they all refer to the same delegate). For C# 4 and earlier, you just need to create a copy:
foreach (KeyValuePair<string, string> character in specialCharacters)
{
var copy = character;
Action<Employee> replace = empData => empData.EmpName =
empData.EmpName.ToString().Replace(copy.Key, copy.Value);
listOfDel.Add(replace);
}
C# 5 will render this unnecessary, as foreach will be fixed so that each iteration will have a separate variable as far as anonymous functions are concerned.
See Eric Lippert's blog post "Closing over the loop variable considered harmful" for more information.

Detect first pass through a do-while

I have a do-while loop that needs to log a message once (so it doesn't clutter the log) each time its status (e.g. pass/fail) changes, but still has to do other things each time it goes through the loop. Using a simple boolean variable can basically tell you if you've already logged that message, which works once you're in a known condition. However, if you want the message to be printed the first time in either case (pass/fail), you have to account for that. For example, if you default your condition to true, and it is, in fact, true the first time, it won't log the 'True' message b/c it thinks it was already true (and vice-versa for i.c. false).
This seems like it would be a good place for a nullable boolean with i.c.=Null, but in languages where those aren't present, what's one to do?
The simplest solution I could think of would be to use an extra boolean variable like 'firstTime = True', but using that always bothers me as an elementary workaround when I feel like there should be a more delicate way to handle it. Another option is to use the breakout condition of the do-while as your initial condition for whatever variable you're using as your conditional, but that can be confusing when someone reads int status = STATUS_QUIT, and it certainly requires more explanatory comments than bool firstTime = true. A third option would be to use an enum instead of a bool and have {firstTime, true, false} or something.
Are there other reasons for using one over the other, or are there better ways of doing this?
Code example with two options I came up with:
Using bool firsttime:
bool firstTime = true, infoFound = false;
do
{
if (getInfo())
{
if (!infoFound)
{
// log it (ONCE)(important)
infoFound = true;
}
// use info (every time)
}
else if (infoFound || firstTime)
{
// log it (ONCE)(important)
infoFound = false;
firstTime = false;
}
// FYI, WaitForStatusUpdate is a blocking call...
} while (STATUS_QUIT != WaitForStatusUpdate());
Use the while loop 'break-out condition' as the initial condition for a check variable:
(status is updated at the end of the do-while, so the do section will not be executed ever again if status == breakOutCondition; we can use this to our advantage here and set status = breakOutContition initially - the first time through it will be breakOutCondition but any subsequent loop will be something else... Still not sure I like this as it's kind of a hack...
bool infoFound = false;
int status = STATUS_QUIT;
do
{
if (getInfo())
{
if (!infoFound)
{
// log it (ONCE)(important)
infoFound = true;
}
// use info (every time)
}
else if (infoFound || firstTime)
{
// log it (ONCE)(important)
infoFound = false;
}
status = WaitForStatusUpdate();
} while (STATUS_QUIT != status);
(I'm tagging this as c++ since that's what I'm using, but this really could apply to any language with similar constructs)
Wouldn't an enum be clearer?
enum State { Unknown, Pass, Fail };
State state = Unknown;
...
State newState = getInfo() ? Pass : Fail;
if (newState != state) { log(); state = newState; }
C++ almost has nullable booleans, boost::optional<bool> would do the trick I believe.
One common way to do this in C++ is a stream wrapper that you create in the proper context, and it remembers for example how many times it's flushed and prevents further logging from happening. You just do your logging as normal and let the stream decide whether to send it on to the wrapped stream.