Walking through an nsIDOMNodeList - firefox-addon

I'm working on a C++ component for Firefox and I'm trying to wrap my mind around XPCOM and all of its parts. It's really confusing so I'm trying to work through it but I'm trying to walk through a page and get all its links. I'm trying to figure out what all the objects do. So if I have this interface:
interface nsIPageSummary : nsISupports {
boolean saveSummary(in nsIDOMDocument document,
out unsigned long numLinks,
out unsigned long numImages);
};
defined in the IDL, the method in my C++ code would look like:
SaveSummary(nsIDOMDocument* inDoc, PRBool* outSuccess)
{
*outSuccess = PR_FALSE;
nsCOMPtr<nsIDOMNodeList> nodeList;
inDoc->GetElementsByTagName(NS_LITERAL_STRING("A"), getter_AddRefs(nodeList));
}
I know the C++ method needs more parameters to match up with the one defined in the interface but I don't understand how all the typing works yet. In terms of the actual list, am I right in understanding that the
inDoc->GetElementsByTagName(NS_LITERAL_STRING("A"), getter_AddRefs(nodeList));
line puts all the "A" tags from the inDoc into the nodeList? And I would just have to walk through nodeList to get them all?

You compile your interface definition using xpidl to get a C++ header file - you can check that file to see how interface definitions are translated. Your method definition should actually look like thit:
nsresult SaveSummary(nsIDOMDocument* inDoc, PRUint32* outNumLinks, PRUint32* outNumImages, PRBool* outSuccess)
I would suggest to use the type PRUint32 instead of the ambiguous unsigned long in the interface definition as well. I would also suggest getting rid of the return value: XPCOM methods always return nsresult which is either NS_OK or an error code, this is enough to indicate success or failure. An error code is automatically translated into an exception when called from JavaScript. And finally I would recommend using lower-case tag names: while it won't matter in HTML (case-insensitive), in an XHTML document only lower-case tag names are accepted. So your interface definition should look like this:
interface nsIPageSummary : nsISupports {
void saveSummary(in nsIDOMDocument document,
out PRUint32 numLinks,
out PRUint32 numImages);
};
And the corresponding implementation:
nsresult
SaveSummary(nsIDOMDocument* inDoc, PRUint32* outNumLinks, PRUint32* outNumImages)
{
nsresult rv;
nsCOMPtr<nsIDOMNodeList> nodeList;
rv = inDoc->GetElementsByTagName(NS_LITERAL_STRING("a"), getter_AddRefs(nodeList));
if (NS_FAILED(rv))
return rv;
rv = nodeList->GetLength(outNumLinks);
if (NS_FAILED(rv))
return rv;
rv = inDoc->GetElementsByTagName(NS_LITERAL_STRING("img"), getter_AddRefs(nodeList));
if (NS_FAILED(rv))
return rv;
rv = nodeList->GetLength(outNumImages);
if (NS_FAILED(rv))
return rv;
return NS_OK;
}

Related

Null Assertions in null-safe mode and How to Avoid If Possible

Learning Dart and using dart_code_metrics to ensure that I write code that meets expectations. One of the rules that is active is avoid-non-null-assertion.
Note, the code below was created to recreate the problem encountered in a larger code base where the value of unitString is taken from a JSON file. As such the program cannot control what is specified in the JSON file.
From pubspec.yaml
environment:
sdk: '>=2.15.0 <3.0.0'
// ignore_for_file: avoid_print
import 'package:qty/qty.dart';
void main() {
const String unitString = 'in';
// unit.Width returns null if unitString is not a unit of Length.
if (Length().unitWith(symbol: unitString) == null) {
print('units $unitString not supported.');
} else {
// The following line triggers avoid-non-null-assertion with the use of !.
final Unit<Length> units = Length().unitWith(symbol: unitString)!;
final qty = Quantity(amount: 0.0, unit: units);
print('Qty = $qty');
}
}
If I don't use ! then I get the following type error:
A value of type 'Unit<Length>?' can't be assigned to a variable of type 'Unit<Length>'.
Try changing the type of the variable, or casting the right-hand type to 'Unit<Length>'.
Casting the right-hand side to
Unit<Length>
fixes the above error but cause a new error when instantiating Quantity() since the constructor expects
Unit<Length>
and not
Unit<Length>?
I assume there is an solution but I'm new to Dart and cannot formulate the correct search query to find the answer.
How can I modify the sample code to make Dart and dart_code_metrics happy?
Your idea of checking for null before using a value is good, it's just not implemented correctly. Dart does automatically promote nullable types to non-null ones when you check for null with an if, but in this case you need to use a temporary variable.
void main() {
const String unitString = 'in';
//Use a temp variable, you could specify the type instead of using just using final
final temp = Length().unitWith(symbol: unitString);
if (temp == null) {
print('units $unitString not supported.');
} else {
final Unit<Length> units = temp;
final qty = Quantity(amount: 0.0, unit: units);
print('Qty = $qty');
}
}
The basic reason for that when you call your unitWith function and see that it's not null the first time, there's no guarantee that the when you call it again that it will still return a non-null value. I think there's another SO question that details this better, but I can't seem to find.

mql4 } not all control paths return a value

I have taken this function from another mql4 script. The other script compiles absolutely fine with no error. Strangely, now that I have copied this function into my script I get the error } not all control paths return a value
I understand the concept of return a value but not sure when there is a compile difference between the scripts
int ModifyOrder(int ord_ticket,double op, double price,double tp, color mColor)
{
int CloseCnt, err;
CloseCnt=0;
while (CloseCnt < 3)
{
if (OrderModify(ord_ticket,op,price,tp,0,mColor))
{
CloseCnt = 3;
}
else
{
err=GetLastError();
Print(CloseCnt," Error modifying order : (", err , ") " + ErrorDescription(err));
if (err>0) CloseCnt++;
}
}
}
Most likely the difference is in #property strict. if using strict mode, you have to redeclare local variables, return value from every function (except void, of course) and some other differences.
In your example the function has to be ended with return CloseCnt; or maybe something else.
No way to declare non-strict mode - simply do not declare the strict one.
Once you declared it, it is applied to that file, and included into other files if importing.

Context dependent ANTLR4 ParseTreeVisitor implementation

I am working on a project where we migrate massive number (more than 12000) views to Hadoop/Impala from Oracle. I have written a small Java utility to extract view DDL from Oracle and would like to use ANTLR4 to traverse the AST and generate an Impala-compatible view DDL statement.
The most of the work is relatively simple, only involves re-writing some Oracle specific syntax quirks to Impala style. However, I am facing an issue, where I am not sure I have the best answer yet: we have a number of special cases, where values from a date field are extracted in multiple nested function calls. For example, the following extracts the day from a Date field:
TO_NUMBER(TO_CHAR(d.R_DATE , 'DD' ))
I have an ANTLR4 grammar declared for Oracle SQL and hence get the visitor callback when it reaches TO_NUMBER and TO_CHAR as well, but I would like to have special handling for this special case.
Is not there any other way than implementing the handler method for the outer function and then resorting to manual traversal of the nested structure to see
I have something like in the generated Visitor class:
#Override
public String visitNumber_function(PlSqlParser.Number_functionContext ctx) {
// FIXME: seems to be dodgy code, can it be improved?
String functionName = ctx.name.getText();
if (functionName.equalsIgnoreCase("TO_NUMBER")) {
final int childCount = ctx.getChildCount();
if (childCount == 4) {
final int functionNameIndex = 0;
final int openRoundBracketIndex = 1;
final int encapsulatedValueIndex = 2;
final int closeRoundBracketIndex = 3;
ParseTree encapsulated = ctx.getChild(encapsulatedValueIndex);
if (encapsulated instanceof TerminalNode) {
throw new IllegalStateException("TerminalNode is found at: " + encapsulatedValueIndex);
}
String customDateConversionOrNullOnOtherType =
customDateConversionFromToNumberAndNestedToChar(encapsulated);
if (customDateConversionOrNullOnOtherType != null) {
// the child node contained our expected child element, so return the converted value
return customDateConversionOrNullOnOtherType;
}
// otherwise the child was something unexpected, signalled by null
// so simply fall-back to the default handler
}
}
// some other numeric function, default handling
return super.visitNumber_function(ctx);
}
private String customDateConversionFromToNumberAndNestedToChar(ParseTree parseTree) {
// ...
}
For anyone hitting the same issue, the way to go seems to be:
changing the grammar definition and introducing custom sub-types for
the encapsulated expression of the nested function.
Then, I it is possible to hook into the processing at precisely the desired location of the Parse tree.
Using a second custom ParseTreeVisitor that captures the values of function call and delegates back the processing of the rest of the sub-tree to the main, "outer" ParseTreeVisitor.
Once the second custom ParseTreeVisitor has finished visiting all the sub-ParseTrees I had the context information I required and all the sub-tree visited properly.

Display template not called if TypeConverter exists

As soon as I register a TypeConverter for a complex type, it fails to load the correct (base type) display template for properties of a derived type, i.e., #Html.DisplayFor(m => m.My_Derived_ComplexTypeProp) fails to load the MyComplexType display template.
I've debugged the display template selection logic a little bit, and the problem seems to be very obvious:
// From TemplateHelpers:
internal static IEnumerable<string> GetViewNames(ModelMetadata metadata, params string[] templateHints)
{
[...]
yield return fieldType.Name; // TRY 1: Type, but no base type walking
if (!(fieldType == typeof (string))) // YEP ...
{
if (!metadata.IsComplexType) // Unfortunately YEP (see below...)
{
if (fieldType.IsEnum) // NOPE
yield return "Enum";
else if (fieldType == typeof (DateTimeOffset)) // NOPE
yield return "DateTime";
yield return "String"; // TRY 2: string => uh oh, string will be found, and we do not use the correct display template.
}
[...]
else
{
[...] // only in here we would have the base type walk
}
[...]
// From ModelMetadata:
public virtual bool IsComplexType
{
get
{
// !!! !!! WTF !!! !!!:
// Why is IsComplexType returning false if we cannot convert from string?
return !TypeDescriptor.GetConverter(this.ModelType).CanConvertFrom(typeof (string));
}
}
As soon as the logic detects "no complex type" it simply checks for enumerations, DateTimes and returns the template for string otherwise! But look at the implementation of IsComplexType -> if convertible to string it is treated like a simple type!
So, of course, as soon as you register a type converter for a complex type, the display template resolution fails to use the correct template.
Is there a known workaround? I cannot believe, I'm one of the few people running into this until now...
I have found Cannot use TypeConverter and custom display/editor template together?, however, the "solution" which is marked as answer, is not really a solution. It just hackarounds the problem...

how to implement string concatenation alike extension function with unknown arguments number using Saxon-HE?

I want to add a custom xpath extension function to the Saxon-HE transformer. This custom function should accept one or more arguments. Let's use the string concatenation analogy for concatenating one or more string arguments. Following the sample on the saxon page, i wrote the following code:
ExtensionFunction myconcat = new ExtensionFunction() {
public QName getName() {
return new QName("http://mycompany.com/", "myconcat");
}
public SequenceType getResultType() {
return SequenceType.makeSequenceType(
ItemType.STRING, OccurrenceIndicator.ONE
);
}
public net.sf.saxon.s9api.SequenceType[] getArgumentTypes() {
return new SequenceType[]{
SequenceType.makeSequenceType(
ItemType.STRING, OccurrenceIndicator.ONE_OR_MORE)};
}
public XdmValue call(XdmValue[] arguments) throws SaxonApiException {
//concatenate the strings here....
String result = "concatenated string";
return new XdmAtomicValue(result);
}
};
i have expected that the following xpath expression would work in an xsl file
<xsl:value-of select="myconcat('a','b','c','...')">
Unfortunately i got the following exception:
XPST0017: Function myconcat must have 1 argument
What is the right way of creating a custom function for this use case?
Thanks.
The standard mechanisms for creating extension functions don't allow a variable number of arguments (it's not really pukka to have such functions in the XPath view of the world - concat() is very much an exception).
You can do it by creating your own implementation of the class FunctionLibrary and adding your FunctionLibrary to the static context of the XSLT engine - but you're deep into Saxon internals if you attempt that, so be prepared for a rough ride.

Resources