Extension talk:StackFunctions

This extension is about a thousand degrees of awesome, and I'm starting to test it out on the wiki at http://nomicapolis.net with some customizations already:


 * Exception reporting disables caching of the output, so a simple reload is all that's necessary if any code is broken.
 * disables the cache automatically so you get a new random number each load. This has good and bad implications, so I might break out a new cache-control word instead.
 * The patch to Parser.php to add preprocess2 is not necessary -- I simply inlined it.
 * New words to get at template args (only works in the parserfunc) and tag args (only works in the tag of course). I'm not sure whether these should be in statusdict or not, right now they're separate words.

I really want to get at the template args when using the tag syntax, but $this->mParser->mArgStack is completely empty when using the tag! Perhaps someone with stronger wiki-fu than myself can figure out how and if this can be hooked.

67.98.226.13 18:12, 6 June 2007 (UTC)


 * Concerning the last point, to my understanding this is not possible. I spent quite some time on this because I'd be just as keen on getting the args, and my conclusion is: the args are replaced before passing the stuff to the extension, so within the extension code you never have a chance so see the mapping of args to their contents. You'd need to conserve mArgStack from the preceding level of recursion, which requires - if ever possible - really ugly hacks to Parser.php. RV1971 20:47, 9 June 2007 (UTC)

Some Thoughts
I really think this is a cool plugin, and I'm playing around with it to see what I can do. I tried out a Fibonacci function (perhaps not the most creative but somewhat traditional) and it worked fine.

Dynamic Strings
In order to print the results in a nice manner, I also tried my hand at concatenating a number to the end of a string. While I was at it, I noticed that a string created with the string function produces some very interesting looking text when its contents are printed with =. I tried this in Ghostscript (8.53) and saw interesting output there as well.

I checked the PostScript reference you supplied, and it does call for 0's to be written into every index. I guess my background in C at first led me to think this would cause the string printout to be truncated at the first 0 when written with =. Perhaps it's better this way.

It was a problem for me because attempts to produce something like "fib(4): 24" were looking something like "fib(4): 24XXXXXX" with the X's representing the problematic characters. Anyway, the issue was not hard to solve. I'll add some info here in case anyone wants to use strings made with string but replace all those characters for whatever reason. Feel free to correct me if I mess anything up or could do it better!


 * Use replace to replace weird characters in string
 * Use put to replace weird characters in string
 * Use concat to put together strings containing acceptable trailing characters, like whitespace.

% fill(character, length) % produce a string filled with % the given character and of the % given length /fill {     string dup 1 string 4 -1 roll replace }  def % fill(char, len) % uses dict keys for params % could be written using stack copying /fill {     string /ts exch def /ch exch def 0     ts length {        dup ts exch ch put 1 add }     repeat pop ts  } def

% fill(char, len) /fill {     2 1 roll /ch exch def exch {        ch concat }     repeat }  def

% Should produce yyyyy (y) 5 fill

Remember, I ran into a problem because I needed strings of unknown size to insert numbers into using cvs. Of course, it might have been worth just doing something like pre-calculating the number of digits, but then, maybe it would have been just as well to build the number string up from those digits at that point. Alternatively, I could have employed a solution using string literals of the desired size and composition if I knew in advance a limit on the number of digits I'd run into.

Infinitely recursive Functions
However, I did run into something I think is a potential problem. I tried an infinitely self-recursive function on for size:

/x { x } def x

In my test, it showed a blank page instead of the preview, and the same on submitting, although the submission doesn't go through, so viewing the page showed the original page.

Maybe it would be worth flagging this with an error message instead of the behavior I noticed, by doing some kind of counting of depth of calls? Then again, I'm not sure this is sufficient. I'm still thinking about it.

Misuse of loop is also pretty problematic!

Add to Math Extensions Category?
Also, would it be worth adding your main page to Category:Math extensions?

-- JG 76.104.101.162 05:22, 9 April 2009 (UTC)

Type operator Bug?
I think I found a bug: Applying type to an array returns "/dicttype". I tried it in gs for comparison, and gs returns "arraytype".

/d1 << /name /karl >> def /a1 [ (I'm a string) ] def

% doesn't talk like any array a1 type =

% but it walks like one a1 aload pop =

% talks like a dictionary, as it should d1 type =

Question about print operators
I'm a little unclear on the difference between '=' and '==' but from looking at the language reference and the output of gs, I'm thinking maybe something like

/blah =

should display "blah" rather than "/blah", which is the purpose of ==?

-- JG 9 April 2009 (UTC)

Database Query
The database query feature is very scary-looking, aside from the data exposure concerns you mention. I think there may be a risk of modification of the database by arbitrary users. In your recent source I don't see any sanitizing of user input. Also, you use the query command, which apparently doesn't do any escaping:

We provide a query function for raw SQL, but the wrapper functions like select and insert are usually more convenient. They take care of things like table prefixes and escaping for you. If you really need to make your own SQL, please read the documentation for tableName and addQuotes. You will need both of them. -- Mediawiki 1.9.3 docs/database.txt

It's true you use a DB_SLAVE interface, but this doesn't necessarily prevent writing to the database, from what I glean from the above reference. I'm not entirely clear on how the database functions are implemented. I may be wrong, but from what I do know, I feel concerned.

Also, the whole database querying doesn't fit in well with the overall concept I have formed of your extension as "an alternative to the combination of ParserFunctions with StringFunctions (and maybe other extensions) or to Winter", which places it mainly in a kind of mathematical and data structure processing domain. The query feature is very flexible, but perhaps too much, to the extent that it is not fixed to a clear purpose.

It sounds to me like prolog can enable a form of database for the extension anyway, but setting up shared data in prolog pages.

-- JG 20:17, 9 April 2009 (UTC)


 * Thank you very much for the detailed feedback.
 * 0's in strings: My implementation does indeed follow the PostScript reference, and I wouldn't care much about the output of =. But the problem also appears with the show operator, which is a bug. I fixed this in version 0.8. As the problem can occur in many operators (for instance, showtemplate), I decided to rtrim 0's in every string appended to the result text. The net result is what you expect.
 * For your example, you might also be interested in the vprintf or vsprintf operators introduced with version 0.8.
 * Infinitely recursive Functions: Ghostscript does not detect such recursions, either, so I guess PostScript does not define any such check (even though I did not scan the entire manual for that). Nevertheless, I agree such a check is useful, and I included it in version 0.8. On the other hand, for the moment I did not include any check about misuse of loop since I don't know of any programming language that attempts to detect infinite loops.
 * Type operator bug: This is indeed a bug. Now fixed.
 * Question about print operators: This is a bug in the sense that I follow the PostScript reference unless there are good reasons not to do that. Now fixed.
 * Database Query: I have slightly modified the motivation of my extension in order to make it fit. :-) You're right that providing common data for a number of pages can be done using the prolog feature (which is probably more efficient). Things become interesting when:
 * you refer to data entered by Extension:DataTable or other extensions writing data in additional tables (that's what I'm doing at work), or
 * the database user has read access to data from a different source. For instance, at home I have an address book in the same database, and I use StackFunction to dynamically display address data in wiki pages.
 * I'm unsure whether there is actually a risk of data modification. The query is built from the dictionary entries by inserting keywords ike select, from etc. so that the user does not have the ability to send an arbitrary SQL statement. But there might be a way to wrap data modification statements into this. If you can find an example, pls let me know! – RV1971 09:14, 16 April 2009 (UTC)

I was waiting to do some more tests to get back to you, and I still mean to run them, but so much time has passed, I realized I still haven't thanked you for getting back to me! I really appreciated it, and I'm glad you took time to deal with some of the questions I raised. I really want to do a few experiments with the database query, to see if I understand it properly. Anyway, despite my long hiatus, a bunch of thanks. -- JG 01:17, 7 May 2009 (UTC).