views:

290

answers:

6

I'm doing some work with code generation, and one of the things I need to do is create a function call where one of the parameters is a function call, like so:

result := Func1(x, y, Func2(a, b, c));

TStringList.CommaText is very useful for generating the parameter lists, but when I traverse the tree to build the outer function call, what I end up with looks like this:

result := Func1(x, y, "Func2(a, b, c)");

It's quoting the third argument because it contains commas, and that produced invalid code. But I can't do something simplistic like StringReplace all double quotes with empty strings, because it's quite possible that a function argument could be a string with double quotes inside. Is there any way to make it just not escape the lines that contain commas?

+1  A: 
  1. Build an array of "unlikely characters" : non-keyable like , or even non-printable like #129, #141, #143, #144.
  2. Verify you don't have the 1st unlikely anywhere in your StringList.CommaText. Or move to the next unlikely until you get one not used in your StringList.CommaText. (Assert that you find one)
  3. Use this unlikely char as the QuoteChar for your StringList
  4. Get StringList.DelimitedText. You'll get the QuoteChar around the function parameters like: result := Func1(x, y, †Func2(a, b, c)†);
  5. Replace the unlikely QuoteChar (here ) by empty strings...
François
I can't help but "an array of unlikely characters" reminds me of "A Series of Unfortunate Events". :-)
François
+1  A: 

Write your own method to export the contents of your TStringList to a string.

function MyStringListToString(const AStrings: TStrings): string;
var
    i: Integer;
begin
    Result := '';
    if AStrings.Count = 0 then
        Exit;
    Result := AStrings[0];
    for i := 1 to AStrings.Count - 1 do
        Result := Result + ',' + AStrings[i];
end;

Too obvious? :-)

Alternatively, what would happen if you set StringList.QuoteChar to #0 and then called StringList.DelimitedText?

afrazier
Looks like an AV happens with `QuoteChar = #0`. That was surprising.
cjrh
Or set QuoteChar to space
Gerry
+1  A: 

You could set QuoteChar to be a space, and you'd merely get some extra spaces in the output, which is generally OK since generated code isn't usually expected to look pretty. String literals would be affected, though; they would have extra spaces inserted, changing the value of the string.

Free Pascal's TStrings class uses StrictDelimiter to control whether quoting occurs when reading the DelimitedText property. When it's true, quoting does not occur at all. Perhaps Delphi treats that property the same way.

Rob Kennedy
Delphi 2010's VCL calls `AnsiQuotedStr` before adding an element to the output string. `StrictDelimiter` doesn't affect quoting at all in Delphi.
afrazier
Delphi has a StrictDelimiter property, but it works a little bit differently.
Mason Wheeler
A: 

We have written a descendant class of TStringList in which reimplemented the DelimitedText property. You can copy most of the code from the original implementation.

r4w8173
A: 
var
  LList: TStringList;
  s, LOutput: string;
begin
  LList := TStringList.Create;
  try
    LList.Add('x');
    LList.Add('y');
    LList.Add('Func2(a, b, c)');
    for s in LList do
      LOutput := LOutput + s + ', ';
    SetLength(LOutput, Length(LOutput) - 2);
    m1.AddLine('result := Func1(' + LOutput + ')');
  finally
    LList.Free;
  end;
end;
cjrh
+1  A: 

What about using the Unicode version of AnsiExtractQuotedStr to remove the quotes?

Jim McKeeth
+1 for pure kludge factor :D Heath Robinson style ftw!
MarkRobinson