Browse Source

--- Merging r20054 into '.':
U utils/fpdoc/dw_html.pp
U utils/fpdoc/dw_htmlchm.inc
--- Merging r20091 into '.':
U utils/fpdoc/dwlinear.pp
U utils/fpdoc/dw_man.pp
U utils/fpdoc/dw_latex.pp
U utils/fpdoc/dw_lintmpl.pp
U utils/fpdoc/dw_txt.pp
U utils/fpdoc/dwriter.pp
U utils/fpdoc/dw_linrtf.pp
G utils/fpdoc/dw_html.pp
U utils/fpdoc/dw_template.pp
U utils/fpdoc/dw_ipflin.pas
--- Merging r20092 into '.':
G utils/fpdoc/dwlinear.pp
G utils/fpdoc/dw_html.pp
--- Merging r20100 into '.':
G utils/fpdoc/dw_htmlchm.inc
--- Merging r20169 into '.':
U packages/fcl-passrc/src/pscanner.pp
U packages/fcl-passrc/src/pparser.pp
--- Merging r20213 into '.':
U utils/fpdoc/fpdocxmlopts.pas
U utils/fpdoc/dglobals.pp
U utils/fpdoc/fpdocproj.pas
U utils/fpdoc/fpdoc.lpi
U utils/fpdoc/mkfpdoc.pp
--- Merging r20216 into '.':
G utils/fpdoc/mkfpdoc.pp
--- Merging r20304 into '.':
G utils/fpdoc/dwlinear.pp
G utils/fpdoc/dwriter.pp
G utils/fpdoc/fpdocxmlopts.pas
G utils/fpdoc/dglobals.pp
G utils/fpdoc/fpdocproj.pas
G utils/fpdoc/dw_html.pp
U utils/fpdoc/testunit.pp
G utils/fpdoc/mkfpdoc.pp
U utils/fpdoc/fpdoc.pp
U utils/fpdoc/testunit.xml
--- Merging r20335 into '.':
G utils/fpdoc/dwriter.pp
G utils/fpdoc/mkfpdoc.pp
--- Merging r20409 into '.':
G utils/fpdoc/dwlinear.pp
--- Merging r20862 into '.':
G packages/fcl-passrc/src/pparser.pp
--- Merging r20863 into '.':
U packages/fcl-passrc/src/pastree.pp
--- Merging r20864 into '.':
G packages/fcl-passrc/src/pparser.pp
--- Merging r20865 into '.':
G packages/fcl-passrc/src/pparser.pp
--- Merging r21828 into '.':
G packages/fcl-passrc/src/pparser.pp
--- Merging r21832 into '.':
G packages/fcl-passrc/src/pparser.pp
--- Merging r21835 into '.':
G packages/fcl-passrc/src/pastree.pp
--- Merging r21849 into '.':
G packages/fcl-passrc/src/pastree.pp
G packages/fcl-passrc/src/pparser.pp
--- Merging r21850 into '.':
G packages/fcl-passrc/src/pastree.pp
G packages/fcl-passrc/src/pscanner.pp
G packages/fcl-passrc/src/pparser.pp
--- Merging r21851 into '.':
G packages/fcl-passrc/src/pastree.pp
G packages/fcl-passrc/src/pparser.pp
--- Merging r21852 into '.':
G packages/fcl-passrc/src/pastree.pp
--- Merging r21868 into '.':
G utils/fpdoc/dw_html.pp
G utils/fpdoc/fpdoc.pp
--- Merging r21882 into '.':
G utils/fpdoc/dglobals.pp
G utils/fpdoc/dw_html.pp
--- Merging r21909 into '.':
G packages/fcl-passrc/src/pparser.pp
--- Merging r21910 into '.':
G packages/fcl-passrc/src/pastree.pp
G packages/fcl-passrc/src/pparser.pp
--- Merging r21915 into '.':
G packages/fcl-passrc/src/pastree.pp
G packages/fcl-passrc/src/pparser.pp
--- Merging r21922 into '.':
G packages/fcl-passrc/src/pastree.pp
G packages/fcl-passrc/src/pparser.pp
--- Merging r21929 into '.':
G packages/fcl-passrc/src/pastree.pp

# revisions: 20054,20091,20092,20100,20169,20213,20216,20304,20335,20409,20862,20863,20864,20865,21828,21832,21835,21849,21850,21851,21852,21868,21882,21909,21910,21915,21922,21929
r20054 | marco | 2012-01-11 20:19:25 +0100 (Wed, 11 Jan 2012) | 1 line
Changed paths:
M /trunk/utils/fpdoc/dw_html.pp
M /trunk/utils/fpdoc/dw_htmlchm.inc

* Patch from Darius to fix directories of images #21008
r20091 | michael | 2012-01-16 10:03:05 +0100 (Mon, 16 Jan 2012) | 1 line
Changed paths:
M /trunk/utils/fpdoc/dw_html.pp
M /trunk/utils/fpdoc/dw_ipflin.pas
M /trunk/utils/fpdoc/dw_latex.pp
M /trunk/utils/fpdoc/dw_linrtf.pp
M /trunk/utils/fpdoc/dw_lintmpl.pp
M /trunk/utils/fpdoc/dw_man.pp
M /trunk/utils/fpdoc/dw_template.pp
M /trunk/utils/fpdoc/dw_txt.pp
M /trunk/utils/fpdoc/dwlinear.pp
M /trunk/utils/fpdoc/dwriter.pp

* Patch from Hans-Peter Diettrich to extend and append filenameextension (bug 21101)
r20092 | michael | 2012-01-16 10:12:55 +0100 (Mon, 16 Jan 2012) | 1 line
Changed paths:
M /trunk/utils/fpdoc/dw_html.pp
M /trunk/utils/fpdoc/dwlinear.pp

* Actually use FileNameExtension
r20100 | michael | 2012-01-17 09:35:18 +0100 (Tue, 17 Jan 2012) | 1 line
Changed paths:
M /trunk/utils/fpdoc/dw_htmlchm.inc

* Patch from Hand-Peter Diettrich to fix CHM extension usage
r20169 | michael | 2012-01-25 09:48:07 +0100 (Wed, 25 Jan 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pparser.pp
M /trunk/packages/fcl-passrc/src/pscanner.pp

* Abstracted handling of defines
r20213 | michael | 2012-02-01 21:06:50 +0100 (Wed, 01 Feb 2012) | 1 line
Changed paths:
M /trunk/utils/fpdoc/dglobals.pp
M /trunk/utils/fpdoc/fpdoc.lpi
M /trunk/utils/fpdoc/fpdocproj.pas
M /trunk/utils/fpdoc/fpdocxmlopts.pas
M /trunk/utils/fpdoc/mkfpdoc.pp

* Recursive parsing
r20216 | michael | 2012-02-02 13:22:24 +0100 (Thu, 02 Feb 2012) | 1 line
Changed paths:
M /trunk/utils/fpdoc/mkfpdoc.pp

* Always store unit filename in FProcessedUnits
r20304 | michael | 2012-02-11 10:58:13 +0100 (Sat, 11 Feb 2012) | 1 line
Changed paths:
M /trunk/utils/fpdoc/dglobals.pp
M /trunk/utils/fpdoc/dw_html.pp
M /trunk/utils/fpdoc/dwlinear.pp
M /trunk/utils/fpdoc/dwriter.pp
M /trunk/utils/fpdoc/fpdoc.pp
M /trunk/utils/fpdoc/fpdocproj.pas
M /trunk/utils/fpdoc/fpdocxmlopts.pas
M /trunk/utils/fpdoc/mkfpdoc.pp
M /trunk/utils/fpdoc/testunit.pp
M /trunk/utils/fpdoc/testunit.xml

* Added functionality to add (and show) notes
r20335 | michael | 2012-02-13 14:45:37 +0100 (Mon, 13 Feb 2012) | 1 line
Changed paths:
M /trunk/utils/fpdoc/dwriter.pp
M /trunk/utils/fpdoc/mkfpdoc.pp

* Added support for conditional notes
r20409 | marco | 2012-02-23 13:15:03 +0100 (Thu, 23 Feb 2012) | 2 lines
Changed paths:
M /trunk/utils/fpdoc/dwlinear.pp

* Slightly modified patch from Graeme, Mantis #21357 which adds an assigned.
r20862 | michael | 2012-04-14 15:38:00 +0200 (Sat, 14 Apr 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pparser.pp

* Fixed parsing of set of range (bug 21642), removed some memory leaks
r20863 | michael | 2012-04-14 15:38:33 +0200 (Sat, 14 Apr 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pastree.pp

* Removed some memory leaks
r20864 | michael | 2012-04-14 16:00:49 +0200 (Sat, 14 Apr 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pparser.pp

* Fixed bug #21252 (range type with identifiers)
r20865 | michael | 2012-04-14 16:37:12 +0200 (Sat, 14 Apr 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pparser.pp

* Fixed case of range starting with negative identifier
r21828 | michael | 2012-07-09 15:26:53 +0200 (Mon, 09 Jul 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pparser.pp

*Fixed memory leak if an error occurs during argument parsing
r21832 | michael | 2012-07-09 16:53:27 +0200 (Mon, 09 Jul 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pparser.pp

* Parse complete expressions for default arguments
r21835 | michael | 2012-07-09 20:24:19 +0200 (Mon, 09 Jul 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pastree.pp

* Forgot to commit
r21849 | michael | 2012-07-10 17:02:39 +0200 (Tue, 10 Jul 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pastree.pp
M /trunk/packages/fcl-passrc/src/pparser.pp

* Fixed parsing of deprecated hint texts
r21850 | michael | 2012-07-10 17:14:14 +0200 (Tue, 10 Jul 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pastree.pp
M /trunk/packages/fcl-passrc/src/pparser.pp
M /trunk/packages/fcl-passrc/src/pscanner.pp

* Fixed parsing of constref and one more case of deprecated hint
r21851 | michael | 2012-07-10 17:59:53 +0200 (Tue, 10 Jul 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pastree.pp
M /trunk/packages/fcl-passrc/src/pparser.pp

* Support for Is Nested procedure declarations (Bug ID 21992)
r21852 | michael | 2012-07-10 18:01:52 +0200 (Tue, 10 Jul 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pastree.pp

GetDeclaration of "is nested" procedure type is now correct
r21868 | michael | 2012-07-11 13:15:09 +0200 (Wed, 11 Jul 2012) | 1 line
Changed paths:
M /trunk/utils/fpdoc/dw_html.pp
M /trunk/utils/fpdoc/fpdoc.pp

* Only one result section for overloaded functions
r21882 | michael | 2012-07-11 19:13:40 +0200 (Wed, 11 Jul 2012) | 1 line
Changed paths:
M /trunk/utils/fpdoc/dglobals.pp
M /trunk/utils/fpdoc/dw_html.pp

* Added option to remove brackets from menu header From AndrewH (Bug ID 21676)
r21909 | michael | 2012-07-13 15:37:39 +0200 (Fri, 13 Jul 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pparser.pp

* Use container to create statement elements so they get sourcefile information
r21910 | michael | 2012-07-13 20:17:52 +0200 (Fri, 13 Jul 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pastree.pp
M /trunk/packages/fcl-passrc/src/pparser.pp

* Parse program without program header and with complete header
r21915 | michael | 2012-07-15 18:55:18 +0200 (Sun, 15 Jul 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pastree.pp
M /trunk/packages/fcl-passrc/src/pparser.pp

* Fix parsing uses unit in filename, added library parsing and exports sections
r21922 | michael | 2012-07-16 22:52:22 +0200 (Mon, 16 Jul 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pastree.pp
M /trunk/packages/fcl-passrc/src/pparser.pp

* Fixed release problem and except (reported by Seth Grover)
r21929 | michael | 2012-07-17 23:51:13 +0200 (Tue, 17 Jul 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pastree.pp

* Some more reference count fixes

git-svn-id: branches/fixes_2_6@22302 -

marco 13 years ago
parent
commit
1902cc2dda

+ 196 - 12
packages/fcl-passrc/src/pastree.pp

@@ -28,6 +28,8 @@ resourcestring
   SPasTreeElement = 'generic element';
   SPasTreeSection = 'unit section';
   SPasTreeModule = 'module';
+  SPasTreeUnit = 'unit';
+  SPasTreeProgram = 'program';
   SPasTreePackage = 'package';
   SPasTreeResString = 'resource string';
   SPasTreeType = 'generic type';
@@ -103,6 +105,7 @@ type
     FName: string;
     FParent: TPasElement;
     FHints : TPasMemberHints;
+    FHintMessage : String;
   protected
     procedure ProcessHints(const ASemiColonPrefix: boolean; var AResult: string); virtual;
   public
@@ -125,6 +128,7 @@ type
     property Parent: TPasElement read FParent;
     Property Hints : TPasMemberHints Read FHints Write FHints;
     Property CustomData : TObject Read FData Write FData;
+    Property HintMessage : String Read FHintMessage Write FHintMessage;
   end;
 
   TPasExprKind = (pekIdent, pekNumber, pekString, pekSet, pekNil, pekBoolConst, pekRange,
@@ -245,7 +249,7 @@ type
     function ElementTypeName: string; override;
   public
     Declarations, ResStrings, Types, Consts, Classes,
-    Functions, Variables, Properties: TFPList;
+    Functions, Variables, Properties, ExportSymbols: TFPList;
   end;
 
   { TPasSection }
@@ -269,7 +273,10 @@ type
   TImplementationSection = class(TPasSection)
   end;
 
-  TProgramSection = class(TPasSection)
+  TProgramSection = class(TImplementationSection)
+  end;
+
+  TLibrarySection = class(TImplementationSection)
   end;
 
   TInitializationSection = class;
@@ -293,7 +300,31 @@ type
 
   { TPasProgram }
 
-  TPasProgram = class(TPasModule);
+  { TPasUnitModule }
+
+  TPasUnitModule = Class(TPasModule)
+    function ElementTypeName: string; override;
+  end;
+
+  TPasProgram = class(TPasModule)
+  Public
+    destructor Destroy; override;
+    function ElementTypeName: string; override;
+  Public
+    ProgramSection: TProgramSection;
+    InputFile,OutPutFile : String;
+  end;
+
+  { TPasLibrary }
+
+  TPasLibrary = class(TPasModule)
+  Public
+    destructor Destroy; override;
+    function ElementTypeName: string; override;
+  Public
+    LibrarySection: TLibrarySection;
+    InputFile,OutPutFile : String;
+  end;
 
   { TPasPackage }
 
@@ -494,7 +525,7 @@ type
 
 
 
-  TArgumentAccess = (argDefault, argConst, argVar, argOut);
+  TArgumentAccess = (argDefault, argConst, argVar, argOut, argConstRef);
 
   { TPasArgument }
 
@@ -506,7 +537,8 @@ type
   public
     Access: TArgumentAccess;
     ArgType: TPasType;
-    Value: string;
+    ValueExpr: TPasExpr;
+    Function Value : String;
   end;
 
   { TPasProcedureType }
@@ -522,6 +554,7 @@ type
     function CreateArgument(const AName, AUnresolvedTypeName: string):TPasArgument;
   public
     IsOfObject: Boolean;
+    IsNested : Boolean;
     Args: TFPList;        // List of TPasArgument objects
     CallingConvention : TCallingConvention;
   end;
@@ -548,13 +581,24 @@ type
     ResultEl: TPasResultElement;
   end;
 
-  TPasUnresolvedTypeRef = class(TPasType)
+  TPasUnresolvedSymbolRef = class(TPasType)
+  end;
+
+  TPasUnresolvedTypeRef = class(TPasUnresolvedSymbolRef)
   public
     // Typerefs cannot be parented! -> AParent _must_ be NIL
     constructor Create(const AName: string; AParent: TPasElement); override;
     function ElementTypeName: string; override;
   end;
 
+  { TPasUnresolvedUnitRef }
+
+  TPasUnresolvedUnitRef = Class(TPasUnresolvedSymbolRef)
+    function ElementTypeName: string; override;
+  Public
+    FileName : string;
+  end;
+
   { TPasStringType }
 
   TPasStringType = class(TPasUnresolvedTypeRef)
@@ -586,6 +630,16 @@ type
     Expr: TPasExpr;
   end;
 
+  { TPasExportSymbol }
+
+  TPasExportSymbol = class(TPasElement)
+    ExportName : TPasExpr;
+    Exportindex : TPasExpr;
+    Destructor Destroy; override;
+    function ElementTypeName: string; override;
+    function GetDeclaration(full : boolean) : string; override;
+  end;
+
   { TPasConst }
 
   TPasConst = class(TPasVariable)
@@ -728,6 +782,7 @@ type
     constructor Create(const AName: string; AParent: TPasElement); override;
     destructor Destroy; override;
   public
+
     Labels: TFPList;
     Body: TPasImplBlock;
   end;
@@ -956,6 +1011,7 @@ type
   public
     left  : TPasExpr;
     right : TPasExpr;
+    Destructor Destroy; override;
   end;
 
   { TPasImplSimple }
@@ -963,6 +1019,7 @@ type
   TPasImplSimple = class (TPasImplStatement)
   public
     expr  : TPasExpr;
+    Destructor Destroy; override;
   end;
 
   TPasImplTryHandler = class;
@@ -1029,7 +1086,7 @@ type
   end;
 
 const
-  AccessNames: array[TArgumentAccess] of string[6] = ('', 'const ', 'var ', 'out ');
+  AccessNames: array[TArgumentAccess] of string[9] = ('', 'const ', 'var ', 'out ','constref ');
   AllVisibilities: TPasMemberVisibilities =
      [visDefault, visPrivate, visProtected, visPublic,
       visPublished, visAutomated];
@@ -1059,6 +1116,87 @@ implementation
 
 uses SysUtils;
 
+{ TPasImplSimple }
+
+destructor TPasImplSimple.Destroy;
+begin
+  FreeAndNil(Expr);
+  inherited Destroy;
+end;
+
+{ TPasImplAssign }
+
+destructor TPasImplAssign.Destroy;
+begin
+  FreeAndNil(Left);
+  FreeAndNil(Right);
+  inherited Destroy;
+end;
+
+{ TPasExportSymbol }
+
+destructor TPasExportSymbol.Destroy;
+begin
+  FreeAndNil(ExportName);
+  FreeAndNil(ExportIndex);
+  inherited Destroy;
+end;
+
+function TPasExportSymbol.ElementTypeName: string;
+begin
+  Result:='Export'
+end;
+
+function TPasExportSymbol.GetDeclaration(full: boolean): string;
+begin
+  Result:=Name;
+  if (ExportName<>Nil) then
+    Result:=Result+' name '+ExportName.GetDeclaration(Full)
+  else if (ExportIndex<>Nil) then
+    Result:=Result+' index '+ExportIndex.GetDeclaration(Full);
+
+end;
+
+{ TPasUnresolvedUnitRef }
+
+function TPasUnresolvedUnitRef.ElementTypeName: string;
+begin
+  Result:=SPasTreeUnit;
+end;
+
+{ TPasLibrary }
+
+destructor TPasLibrary.Destroy;
+begin
+  FreeAndNil(LibrarySection);
+  inherited Destroy;
+end;
+
+function TPasLibrary.ElementTypeName: string;
+begin
+  Result:=inherited ElementTypeName;
+end;
+
+{ TPasProgram }
+
+destructor TPasProgram.Destroy;
+begin
+  FreeAndNil(ProgramSection);
+  inherited Destroy;
+end;
+
+function TPasProgram.ElementTypeName: string;
+begin
+  Result:=inherited ElementTypeName;
+end;
+
+{ TPasUnitModule }
+
+function TPasUnitModule.ElementTypeName: string;
+begin
+  Result:=SPasTreeUnit;
+end;
+
 { TPasStringType }
 
 
@@ -1173,12 +1311,28 @@ begin
   Inc(FRefCount);
 end;
 
+{ $define debugrefcount}
+
 procedure TPasElement.Release;
+
+{$ifdef debugrefcount}
+Var
+  Cn : String;
+  {$endif}
+
 begin
+{$ifdef debugrefcount}
+  CN:=ClassName;
+  CN:=CN+' '+IntToStr(FRefCount);
+  If Assigned(Parent) then
+    CN:=CN+' ('+Parent.ClassName+')';
+  Writeln('Release : ',Cn);
+{$endif}
   if FRefCount = 0 then
     Free
   else
     Dec(FRefCount);
+{$ifdef debugrefcount}  Writeln('Released : ',Cn); {$endif}
 end;
 
 function TPasElement.FullName: string;
@@ -1252,12 +1406,14 @@ begin
   Functions := TFPList.Create;
   Variables := TFPList.Create;
   Properties := TFPList.Create;
+  ExportSymbols := TFPList.Create;
 end;
 
 destructor TPasDeclarations.Destroy;
 var
   i: Integer;
 begin
+  ExportSymbols.Free;
   Variables.Free;
   Functions.Free;
   Classes.Free;
@@ -1278,7 +1434,9 @@ begin
     InterfaceSection.Release;
   if Assigned(ImplementationSection) then
     ImplementationSection.Release;
-  inherited Destroy;
+ FreeAndNil(InitializationSection);
+ FreeAndNil(FinalizationSection);
+ inherited Destroy;
 end;
 
 
@@ -1366,7 +1524,9 @@ end;
 destructor TPasSetType.Destroy;
 begin
   if Assigned(EnumType) then
+    begin
     EnumType.Release;
+    end;
   inherited Destroy;
 end;
 
@@ -1450,6 +1610,7 @@ destructor TPasArgument.Destroy;
 begin
   if Assigned(ArgType) then
     ArgType.Release;
+  FreeAndNil(ValueExpr);
   inherited Destroy;
 end;
 
@@ -1658,9 +1819,15 @@ procedure TPasImplIfElse.AddElement(Element: TPasImplElement);
 begin
   inherited AddElement(Element);
   if IfBranch=nil then
-    IfBranch:=Element
+    begin
+    IfBranch:=Element;
+    element.AddRef;
+    end
   else if ElseBranch=nil then
-    ElseBranch:=Element
+    begin
+    ElseBranch:=Element;
+    Element.AddRef;
+    end
   else
     raise Exception.Create('TPasImplIfElse.AddElement if and else already set - please report this bug');
 end;
@@ -1683,7 +1850,10 @@ procedure TPasImplForLoop.AddElement(Element: TPasImplElement);
 begin
   inherited AddElement(Element);
   if Body=nil then
-    Body:=Element
+    begin
+    Body:=Element;
+    Body.AddRef;
+    end
   else
     raise Exception.Create('TPasImplForLoop.AddElement body already set - please report this bug');
 end;
@@ -2126,7 +2296,9 @@ begin
     S.Add(TypeName);
     GetArguments(S);
     If IsOfObject then
-      S.Add(' of object');
+      S.Add(' of object')
+    else if IsNested then
+      S.Add(' is nested');
     If Full then
       Result:=IndentStrings(S,Length(S[0])+Length(S[1])+1)
     else
@@ -2444,6 +2616,14 @@ begin
     Result:='';
 end;
 
+function TPasArgument.Value: String;
+begin
+  If Assigned(ValueExpr) then
+    Result:=ValueExpr.GetDeclaration(true)
+  else
+    Result:='';
+end;
+
 
 
 { TPassTreeVisitor }
@@ -2637,7 +2817,10 @@ procedure TPasImplExceptOn.AddElement(Element: TPasImplElement);
 begin
   inherited AddElement(Element);
   if Body=nil then
+    begin
     Body:=Element;
+    Body.AddRef;
+    end;
 end;
 
 { TPasImplStatement }
@@ -2814,6 +2997,7 @@ destructor TParamsExpr.Destroy;
 var
   i : Integer;
 begin
+  FreeAndNil(Value);
   for i:=0 to length(Params)-1 do Params[i].Free;
   inherited Destroy;
 end;

+ 406 - 158
packages/fcl-passrc/src/pparser.pp

@@ -36,11 +36,13 @@ resourcestring
   SParserExpectedCommaRBracket = 'Expected "," or ")"';
   SParserExpectedCommaSemicolon = 'Expected "," or ";"';
   SParserExpectedCommaColon = 'Expected "," or ":"';
+  SParserOnlyOneArgumentCanHaveDefault = 'A default value can only be assigned to 1 parameter';
   SParserExpectedLBracketColon = 'Expected "(" or ":"';
   SParserExpectedLBracketSemicolon = 'Expected "(" or ";"';
   SParserExpectedColonSemicolon = 'Expected ":" or ";"';
   SParserExpectedSemiColonEnd = 'Expected ";" or "End"';
   SParserExpectedConstVarID = 'Expected "const", "var" or identifier';
+  SParserExpectedNested = 'Expected nested keyword';
   SParserExpectedColonID = 'Expected ":" or identifier';
   SParserSyntaxError = 'Syntax error';
   SParserTypeSyntaxError = 'Syntax error in type';
@@ -54,6 +56,7 @@ resourcestring
 
   SLogStartImplementation = 'Start parsing implementation section.';
   SLogStartInterface = 'Start parsing interface section';
+  SParsingUsedUnit = 'Parsing used unit "%s" with commandLine "%s"';
 
 type
   TPasParserLogHandler = Procedure (Sender : TObject; Const Msg : String) of object;
@@ -196,7 +199,8 @@ type
     function ParseSpecializeType(Parent: TPasElement; Const TypeName: String): TPasClassType;
     Function ParseClassDecl(Parent: TPasElement; const AClassName: String;   AObjKind: TPasObjKind; PackMode : TPackMode= pmNone): TPasType;
     Function ParseProperty(Parent : TPasElement; Const AName : String; AVisibility : TPasMemberVisibility; IsClass : Boolean) : TPasProperty;
-    function ParseRangeType(AParent: TPasElement; Const TypeName: String): TPasRangeType;
+    function ParseRangeType(AParent: TPasElement; Const TypeName: String; Full : Boolean = True): TPasRangeType;
+    procedure ParseExportDecl(Parent: TPasElement; List: TFPList);
     // Constant declarations
     function ParseConstDecl(Parent: TPasElement): TPasConst;
     function ParseResourcestringDecl(Parent: TPasElement): TPasResString;
@@ -206,7 +210,8 @@ type
     // Main scope parsing
     procedure ParseMain(var Module: TPasModule);
     procedure ParseUnit(var Module: TPasModule);
-    procedure ParseProgram(var Module: TPasModule);
+    procedure ParseProgram(var Module: TPasModule; SkipHeader : Boolean = False);
+    procedure ParseLibrary(var Module: TPasModule);
     procedure ParseUsesList(ASection: TPasSection);
     procedure ParseInterface;
     procedure ParseImplementation;
@@ -249,7 +254,8 @@ const
   WhitespaceTokensToIgnore = [tkWhitespace, tkComment, tkLineEnding, tkTab];
 
 type
-  TDeclType = (declNone, declConst, declResourcestring, declType, declVar, declThreadvar, declProperty);
+  TDeclType = (declNone, declConst, declResourcestring, declType,
+               declVar, declThreadvar, declProperty, declExports);
 
 Function IsHintToken(T : String; Out AHint : TPasMemberHint) : boolean;
 
@@ -348,7 +354,7 @@ var
     begin
       case s[2] of
         'd': // -d define
-          Scanner.Defines.Append(UpperCase(Copy(s, 3, Length(s))));
+          Scanner.AddDefine(UpperCase(Copy(s, 3, Length(s))));
         'F': // -F
           if (length(s)>2) and (s[3] = 'i') then // -Fi include path
             FileResolver.AddIncludePath(Copy(s, 4, Length(s)));
@@ -378,42 +384,42 @@ begin
     FileResolver := TFileResolver.Create;
     FileResolver.UseStreams:=UseStreams;
     Scanner := TPascalScanner.Create(FileResolver);
-    Scanner.Defines.Append('FPK');
-    Scanner.Defines.Append('FPC');
+    Scanner.AddDefine('FPK');
+    Scanner.AddDefine('FPC');
     SCanner.LogEvents:=AEngine.ScannerLogEvents;
     SCanner.OnLog:=AEngine.Onlog;
 
     // TargetOS
     s := UpperCase(OSTarget);
-    Scanner.Defines.Append(s);
+    Scanner.AddDefine(s);
     if s = 'LINUX' then
-      Scanner.Defines.Append('UNIX')
+      Scanner.AddDefine('UNIX')
     else if s = 'FREEBSD' then
     begin
-      Scanner.Defines.Append('BSD');
-      Scanner.Defines.Append('UNIX');
+      Scanner.AddDefine('BSD');
+      Scanner.AddDefine('UNIX');
     end else if s = 'NETBSD' then
     begin
-      Scanner.Defines.Append('BSD');
-      Scanner.Defines.Append('UNIX');
+      Scanner.AddDefine('BSD');
+      Scanner.AddDefine('UNIX');
     end else if s = 'SUNOS' then
     begin
-      Scanner.Defines.Append('SOLARIS');
-      Scanner.Defines.Append('UNIX');
+      Scanner.AddDefine('SOLARIS');
+      Scanner.AddDefine('UNIX');
     end else if s = 'GO32V2' then
-      Scanner.Defines.Append('DPMI')
+      Scanner.AddDefine('DPMI')
     else if s = 'BEOS' then
-      Scanner.Defines.Append('UNIX')
+      Scanner.AddDefine('UNIX')
     else if s = 'QNX' then
-      Scanner.Defines.Append('UNIX');
+      Scanner.AddDefine('UNIX');
 
     // TargetCPU
     s := UpperCase(CPUTarget);
-    Scanner.Defines.Append('CPU'+s);
+    Scanner.AddDefine('CPU'+s);
     if (s='x86_64') then
-      Scanner.Defines.Append('CPU64')
+      Scanner.AddDefine('CPU64')
     else
-      Scanner.Defines.Append('CPU32');
+      Scanner.AddDefine('CPU32');
 
     Parser := TPasParser.Create(Scanner, FileResolver, AEngine);
     Filename := '';
@@ -656,7 +662,17 @@ begin
     NextToken;
     Found:=IsCurTokenHint(h);
     If Found then
-      Include(Result,h)
+      begin
+      Include(Result,h);
+      if (h=hDeprecated) then
+        begin
+        NextToken;
+        if (Curtoken<>tkString) then
+          UnGetToken
+        else
+          Element.HintMessage:=CurTokenString;
+        end;
+      end;
   Until Not Found;
   UnGetToken;
   If Assigned(Element) then
@@ -783,7 +799,7 @@ begin
     stkRange:
       begin
       UnGetToken;
-      Result:=ParseRangeType(Parent,TypeName);
+      Result:=ParseRangeType(Parent,TypeName,False);
       end;
     stkAlias:
       begin
@@ -920,7 +936,7 @@ begin
       tkRecord: Result := ParseRecordDecl(Parent,TypeName,PM);
     else
       UngetToken;
-      Result:=ParseRangeType(Parent,TypeName);
+      Result:=ParseRangeType(Parent,TypeName,Full);
     end;
     if CH then
       CheckHint(Result,True);
@@ -1120,21 +1136,29 @@ begin
       NextToken;
       if (length(CurTokenText)>0) and (CurTokenText[1] in ['A'..'_']) then begin
         b:=TBinaryExpr.Create(AParent,x, DoParseExpression(AParent), eopNone);
-        if not Assigned(b.right) then Exit; // error
+        if not Assigned(b.right) then
+          begin
+          B.Free;
+          Exit; // error
+          end;
         x:=b;
         UngetToken;
       end
        else UngetToken;
     end;
     tkself: begin
-      x:=TPrimitiveExpr.Create(AParent,pekString, CurTokenText); //function(self);
+      //x:=TPrimitiveExpr.Create(AParent,pekString, CurTokenText); //function(self);
       x:=TSelfExpr.Create(AParent);
       NextToken;
       if CurToken = tkDot then begin // self.Write(EscapeText(AText));
         optk:=CurToken;
         NextToken;
         b:=TBinaryExpr.Create(AParent,x, ParseExpIdent(AParent), TokenToExprOp(optk));
-        if not Assigned(b.right) then Exit; // error
+        if not Assigned(b.right) then
+          begin
+          B.Free;
+          Exit; // error
+          end;
         x:=b;
       end
        else UngetToken;
@@ -1190,7 +1214,11 @@ begin
         optk:=CurToken;
         NextToken;
         b:=TBinaryExpr.Create(AParent,x, ParseExpIdent(AParent), TokenToExprOp(optk));
-        if not Assigned(b.right) then Exit; // error
+        if not Assigned(b.right) then
+          begin
+          b.free;
+          Exit; // error
+          end;
         x:=b;
       end;
     end;
@@ -1198,7 +1226,11 @@ begin
     if CurToken = tkDotDot then begin
       NextToken;
       b:=TBinaryExpr.CreateRange(AParent,x, DoParseExpression(AParent));
-      if not Assigned(b.right) then Exit; // error
+      if not Assigned(b.right) then
+        begin
+        b.free;
+        Exit; // error
+        end;
       x:=b;
     end;
 
@@ -1236,7 +1268,7 @@ var
   
 const
   PrefixSym = [tkPlus, tkMinus, tknot, tkAt]; // + - not @
-  BinaryOP  = [tkMul, tkDivision, tkdiv, tkmod,
+  BinaryOP  = [tkMul, tkDivision, tkdiv, tkmod, tkDotDot,
                tkand, tkShl,tkShr, tkas, tkPower,
                tkPlus, tkMinus, tkor, tkxor, tkSymmetricalDifference,
                tkEqual, tkNotEqual, tkLessThan, tkLessEqualThan,
@@ -1288,7 +1320,6 @@ begin
     repeat
       NotBinary:=True;
       pcount:=0;
-
       if not Assigned(InitExpr) then
       begin
         // the first part of the expression has been parsed externally.
@@ -1313,7 +1344,11 @@ begin
         if CurToken = tkBraceOpen then begin
           NextToken;
           x:=DoParseExpression(AParent);
-          if CurToken<>tkBraceClose then Exit;
+          if CurToken<>tkBraceClose then
+            begin
+            x.free;
+            Exit;
+            end;
           NextToken;
 
           // for the expression like  (TObject(m)).Free;
@@ -1328,9 +1363,17 @@ begin
 
         if not Assigned(x) then Exit;
         expstack.Add(x);
+
         for i:=1 to pcount do begin
           tempop:=PopOper;
-          expstack.Add( TUnaryExpr.Create(AParent, PopExp, TokenToExprOp(tempop) ));
+          x:=popexp;
+          if (tempop=tkMinus) and (X.Kind=pekRange) then
+            begin
+            TBinaryExpr(x).Left:=TUnaryExpr.Create(x, TBinaryExpr(X).left, eopSubtract);
+            expstack.Add(x);
+            end
+           else
+            expstack.Add( TUnaryExpr.Create(AParent, PopExp, TokenToExprOp(tempop) ));
         end;
 
       end else
@@ -1338,7 +1381,6 @@ begin
         expstack.Add(InitExpr);
         InitExpr:=nil;
       end;
-
       if (CurToken in BinaryOP) then begin
         // Adjusting order of the operations
         NotBinary:=False;
@@ -1591,10 +1633,16 @@ begin
   Module:=nil;
   NextToken;
   case CurToken of
-    tkUnit: ParseUnit(Module);
-    tkProgram: ParseProgram(Module);
-    else
-      ParseExc(Format(SParserExpectTokenError, ['unit']));
+    tkUnit:
+      ParseUnit(Module);
+    tkProgram:
+      ParseProgram(Module);
+    tkLibrary:
+      ParseLibrary(Module);
+  else
+    ungettoken;
+    ParseProgram(Module,True);
+  //    ParseExc(Format(SParserExpectTokenError, ['unit']));
   end;
 end;
 
@@ -1623,11 +1671,62 @@ begin
 end;
 
 // Starts after the "program" token
-procedure TPasParser.ParseProgram(var Module: TPasModule);
+procedure TPasParser.ParseProgram(var Module: TPasModule; SkipHeader : Boolean = False);
+
+Var
+  PP : TPasProgram;
+  Section : TProgramSection;
+  N : String;
+
 begin
+  if SkipHeader then
+    N:=ChangeFileExt(Scanner.CurFilename,'')
+  else
+    N:=ExpectIdentifier;
   Module := nil;
-  Module := TPasModule(CreateElement(TPasProgram, ExpectIdentifier,
-    Engine.Package));
+  PP:=TPasProgram(CreateElement(TPasProgram, N, Engine.Package));
+  Module :=PP;
+  FCurModule:=Module;
+  try
+    if Assigned(Engine.Package) then
+    begin
+      Module.PackageName := Engine.Package.Name;
+      Engine.Package.Modules.Add(Module);
+    end;
+    if not SkipHeader then
+      begin
+      NextToken;
+      If (CurToken=tkBraceOpen) then
+        begin
+        PP.InputFile:=ExpectIdentifier;
+        NextToken;
+        if Not (CurToken in [tkBraceClose,tkComma]) then
+          ParseExc(SParserExpectedCommaRBracket);
+        If (CurToken=tkComma) then
+          PP.OutPutFile:=ExpectIdentifier;
+        ExpectToken(tkBraceClose);
+        NextToken;
+        end;
+      if (CurToken<>tkSemicolon) then
+        ParseExc(Format(SParserExpectTokenError,[';']));
+      end;
+    Section := TProgramSection(CreateElement(TProgramSection, '', CurModule));
+    PP.ProgramSection := Section;
+    ParseDeclarations(Section);
+  finally
+    FCurModule:=nil;
+  end;
+end;
+
+procedure TPasParser.ParseLibrary(var Module: TPasModule);
+Var
+  PP : TPasLibrary;
+  Section : TLibrarySection;
+
+begin
+  Module := nil;
+  PP:=TPasLibrary(CreateElement(TPasLibrary, ExpectIdentifier, Engine.Package));
+  Module :=PP;
   FCurModule:=Module;
   try
     if Assigned(Engine.Package) then
@@ -1636,7 +1735,11 @@ begin
       Engine.Package.Modules.Add(Module);
     end;
     NextToken;
-    ParseImplementation;
+    if (CurToken<>tkSemicolon) then
+        ParseExc(Format(SParserExpectTokenError,[';']));
+    Section := TLibrarySection(CreateElement(TLibrarySection, '', CurModule));
+    PP.LibrarySection := Section;
+    ParseDeclarations(Section);
   finally
     FCurModule:=nil;
   end;
@@ -1751,6 +1854,7 @@ var
   List: TFPList;
   i,j: Integer;
   VarEl: TPasVariable;
+  ExpEl: TPasExportSymbol;
   PropEl : TPasProperty;
   TypeName: String;
   PT : TProcType;
@@ -1764,11 +1868,13 @@ begin
     case CurToken of
       tkend:
         begin
+        If (CurModule is TPasProgram) and (CurModule.InitializationSection=Nil) then
+          ParseExc(Format(SParserExpectTokenError,['begin']));
         ExpectToken(tkDot);
         break;
         end;
       tkimplementation:
-        if (CurToken = tkImplementation) and (Declarations is TInterfaceSection) then
+        if (Declarations is TInterfaceSection) then
           begin
           If Not Engine.InterfaceOnly then
             begin
@@ -1780,14 +1886,14 @@ begin
           end;
       tkinitialization:
         if (Declarations is TInterfaceSection)
-        or (Declarations is TImplementationSection) then
+        or ((Declarations is TImplementationSection) and not (Declarations is TProgramSection)) then
           begin
           ParseInitialization;
           break;
           end;
       tkfinalization:
         if (Declarations is TInterfaceSection)
-        or (Declarations is TImplementationSection) then
+        or ((Declarations is TImplementationSection) and not (Declarations is TProgramSection)) then
           begin
           ParseFinalization;
           break;
@@ -1799,6 +1905,8 @@ begin
           ParseExc(SParserSyntaxError);
       tkConst:
         CurBlock := declConst;
+      tkexports:
+        CurBlock := declExports;
       tkResourcestring:
         CurBlock := declResourcestring;
       tkType:
@@ -1874,6 +1982,27 @@ begin
                     Declarations.Types.Add(TypeEl);
                 end;
               end;
+            declExports:
+              begin
+              List := TFPList.Create;
+              try
+                try
+                  ParseExportDecl(Declarations, List);
+                except
+                  for i := 0 to List.Count - 1 do
+                    TPasExportSymbol(List[i]).Release;
+                  raise;
+                end;
+                for i := 0 to List.Count - 1 do
+                begin
+                  ExpEl := TPasExportSymbol(List[i]);
+                  Declarations.Declarations.Add(ExpEl);
+                  Declarations.ExportSymbols.Add(ExpEl);
+                end;
+              finally
+                List.Free;
+              end;
+              end;
             declVar, declThreadVar:
               begin
                 List := TFPList.Create;
@@ -1955,43 +2084,40 @@ end;
 // Starts after the "uses" token
 procedure TPasParser.ParseUsesList(ASection: TPasSection);
 
-function CheckUnit(AUnitName : string):TPasElement;
-begin
+  function CheckUnit(AUnitName : string):TPasElement;
+  begin
     result := Engine.FindModule(AUnitName);  // should we resolve module here when "IN" filename is not known yet?
     if Assigned(result) then
       result.AddRef
     else
-      Result := TPasType(CreateElement(TPasUnresolvedTypeRef, AUnitName,
+      Result := TPasType(CreateElement(TPasUnresolvedUnitRef, AUnitName,
         ASection));
     ASection.UsesList.Add(Result);
-end;
+  end;
 
 var
   AUnitName: String;
   Element: TPasElement;
 begin
-  If not (Asection is TImplementationSection) Then // interface,program,library,package
+  If not (Asection.ClassType=TImplementationSection) Then // interface,program,library,package
     Element:=CheckUnit('System'); // system always implicitely first.    
-  while True do
-  begin
+  Repeat
     AUnitName := ExpectIdentifier; 
     Element :=CheckUnit(AUnitName);
-
     NextToken;
+    if (CurToken=tkin) then
+      begin
+      ExpectToken(tkString);
+      if (Element is TPasModule) and (TPasmodule(Element).filename='')  then
+        TPasModule(Element).FileName:=curtokenstring
+      else if (Element is TPasUnresolvedUnitRef) then
+        TPasUnresolvedUnitRef(Element).FileName:=curtokenstring;
+      NextToken;
+      end;
 
-    if CurToken = tkin then begin
-      // todo: store unit's file name somewhere
-      NextToken; // skip in
-      ExpectToken(tkString); // skip unit's real file name
-      if (Element is TPasModule) and (TPasmodule(Element).filename<>'')  then
-        TPasModule(Element).FileName:=curtokenstring;
-    end;
-
-    if CurToken = tkSemicolon then
-      break
-    else if CurToken <> tkComma then
+    if Not (CurToken in [tkComma,tkSemicolon]) then
       ParseExc(SParserExpectedCommaSemicolon);
-  end;
+  Until (CurToken=tkSemicolon);
 end;
 
 // Starts after the variable name
@@ -2058,7 +2184,7 @@ begin
 end;
 
 // Starts after the type name
-Function TPasParser.ParseRangeType(AParent : TPasElement; Const TypeName : String) : TPasRangeType;
+Function TPasParser.ParseRangeType(AParent : TPasElement; Const TypeName : String; Full : Boolean = True) : TPasRangeType;
 
 Var
   PE : TPasExpr;
@@ -2066,8 +2192,11 @@ Var
 begin
   Result := TPasRangeType(CreateElement(TPasRangeType, TypeName, AParent));
   try
-    If not (CurToken=tkEqual) then
-      ParseExc(Format(SParserExpectTokenError,[TokenInfos[tkEqual]]));
+    if Full then
+      begin
+      If not (CurToken=tkEqual) then
+        ParseExc(Format(SParserExpectTokenError,[TokenInfos[tkEqual]]));
+      end;
     NextToken;
     PE:=DoParseExpression(Result,Nil);
     if not ((PE is TBinaryExpr) and (TBinaryExpr(PE).Kind=pekRange)) then
@@ -2083,6 +2212,30 @@ begin
   end;
 end;
 
+// Starts after Exports, on first identifier.
+procedure TPasParser.ParseExportDecl(Parent: TPasElement; List: TFPList);
+Var
+  E : TPasExportSymbol;
+begin
+  Repeat
+    E:=TPasExportSymbol(CreateElement(TPasExportSymbol,CurtokenString,Parent));
+    List.Add(E);
+    NextToken;
+    if CurTokenIsIdentifier('INDEX') then
+      begin
+      NextToken;
+      E.Exportindex:=DoParseExpression(E,Nil)
+      end
+    else if CurTokenIsIdentifier('NAME') then
+      begin
+      NextToken;
+      E.ExportName:=DoParseExpression(E,Nil)
+      end;
+    if not (CurToken in [tkComma,tkSemicolon]) then
+      ParseExc(SParserExpectedCommaSemicolon);
+  until (CurToken=tkSemicolon);
+end;
+
 Function TPasParser.ParseSpecializeType(Parent : TPasElement; Const TypeName : String) : TPasClassType;
 
 begin
@@ -2294,79 +2447,101 @@ procedure TPasParser.ParseArgList(Parent: TPasElement; Args: TFPList; EndToken:
 var
   ArgNames: TStringList;
   IsUntyped: Boolean;
-  Name, Value: String;
+  Name : String;
+  Value : TPasExpr;
   i: Integer;
   Arg: TPasArgument;
   Access: TArgumentAccess;
   ArgType: TPasType;
 begin
-  while True do
-  begin
-    ArgNames := TStringList.Create;
-    Access := argDefault;
-    IsUntyped := False;
-    ArgType := nil;
+  ArgNames := TStringList.Create;
+  try
     while True do
     begin
-      NextToken;
-      if CurToken = tkConst then
+      ArgNames.Clear;
+      Access := argDefault;
+      IsUntyped := False;
+      ArgType := nil;
+      while True do
       begin
-        Access := argConst;
-        Name := ExpectIdentifier;
-      end else if CurToken = tkVar then
-      begin
-        Access := ArgVar;
-        Name := ExpectIdentifier;
-      end else if (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'OUT') then
-      begin
-        Access := ArgOut;
-        Name := ExpectIdentifier;
-      end else if CurToken = tkIdentifier then
-        Name := CurTokenString
-      else
-        ParseExc(SParserExpectedConstVarID);
-      ArgNames.Add(Name);
-      NextToken;
-      if CurToken = tkColon then
-        break
-      else if ((CurToken = tkSemicolon) or (CurToken = tkBraceClose)) and
-        (Access <> argDefault) then
-      begin
-        // found an untyped const or var argument
-        UngetToken;
-        IsUntyped := True;
-        break
-      end
-      else if CurToken <> tkComma then
-        ParseExc(SParserExpectedCommaColon);
-    end;
-    SetLength(Value, 0);
-    if not IsUntyped then
-    begin
-      ArgType := ParseType(nil);
-      NextToken;
-      if CurToken = tkEqual then
+        NextToken;
+        if CurToken = tkConst then
+        begin
+          Access := argConst;
+          Name := ExpectIdentifier;
+        end else if CurToken = tkConstRef then
+        begin
+          Access := argConstref;
+          Name := ExpectIdentifier;
+        end else if CurToken = tkVar then
+        begin
+          Access := ArgVar;
+          Name := ExpectIdentifier;
+        end else if (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'OUT') then
+        begin
+          Access := ArgOut;
+          Name := ExpectIdentifier;
+        end else if CurToken = tkIdentifier then
+          Name := CurTokenString
+        else
+          ParseExc(SParserExpectedConstVarID);
+        ArgNames.Add(Name);
+        NextToken;
+        if CurToken = tkColon then
+          break
+        else if ((CurToken = tkSemicolon) or (CurToken = tkBraceClose)) and
+          (Access <> argDefault) then
+        begin
+          // found an untyped const or var argument
+          UngetToken;
+          IsUntyped := True;
+          break
+        end
+        else if CurToken <> tkComma then
+          ParseExc(SParserExpectedCommaColon);
+      end;
+      Value:=Nil;
+      if not IsUntyped then
+        begin
+        ArgType := ParseType(nil);
+        try
+          NextToken;
+          if CurToken = tkEqual then
+            begin
+            if (ArgNames.Count>1) then
+              begin
+              FreeAndNil(ArgType);
+              ParseExc(SParserOnlyOneArgumentCanHaveDefault);
+              end;
+            NextToken;
+            Value := DoParseExpression(Parent,Nil);
+            // After this, we're on ), which must be unget.
+            end;
+          UngetToken;
+        except
+          FreeAndNil(ArgType);
+          Raise;
+        end;
+        end;
+
+      for i := 0 to ArgNames.Count - 1 do
       begin
-        Value := ParseExpression(Parent);
-      end else
-        UngetToken;
-    end;
+        Arg := TPasArgument(CreateElement(TPasArgument, ArgNames[i], Parent));
+        Arg.Access := Access;
+        Arg.ArgType := ArgType;
+        if (i > 0) and Assigned(ArgType) then
+          ArgType.AddRef;
+        Arg.ValueExpr := Value;
+        Value:=Nil; // Only the first gets a value. OK, since Var A,B : Integer = 1 is not allowed.
+        Args.Add(Arg);
+      end;
 
-    for i := 0 to ArgNames.Count - 1 do
-    begin
-      Arg := TPasArgument(CreateElement(TPasArgument, ArgNames[i], Parent));
-      Arg.Access := Access;
-      Arg.ArgType := ArgType;
-      if (i > 0) and Assigned(ArgType) then
-        ArgType.AddRef;
-      Arg.Value := Value;
-      Args.Add(Arg);
+      NextToken;
+      if CurToken = EndToken then
+        break;
     end;
-
+  finally
     ArgNames.Free;
-    NextToken;
-    if CurToken = EndToken then
-      break;
   end;
 end;
 
@@ -2429,7 +2604,7 @@ begin
       begin
       NextToken;
       if (CurToken = tkSemicolon) or IsCurtokenHint
-        or (OfObjectPossible and (CurToken in [tkOf,tkEqual]))
+        or (OfObjectPossible and (CurToken in [tkOf,tkis,tkEqual]))
       then
         UngetToken
       else
@@ -2454,15 +2629,25 @@ begin
           ParseType(nil);
       end;
   end;
-
-  NextToken;
-  if OfObjectPossible and (CurToken = tkOf) then
-  begin
-    ExpectToken(tkObject);
-    Element.IsOfObject := True;
-  end else
-    UngetToken;
-
+  
+  if OfObjectPossible then
+    begin
+    NextToken;
+    if (curToken =tkOf) then
+      begin
+      ExpectToken(tkObject);
+      Element.IsOfObject := True;
+      end 
+    else if (curToken = tkIs) then
+      begin
+      expectToken(tkIdentifier);
+      if (lowerCase(CurTokenString)<>'nested') then
+        ParseExc(SParserExpectedNested);
+      Element.isNested:=True;
+      end
+    else
+      UnGetToken;  
+    end;  
   NextToken;
   if CurToken = tkEqual then
   begin
@@ -2538,6 +2723,14 @@ begin
       if IsCurTokenHint(ahint) then  // deprecated,platform,experimental,library, unimplemented etc
         begin
         element.hints:=element.hints+[ahint];
+        if aHint=hDeprecated then
+          begin
+          nextToken;
+          if (CurToken<>tkString) then
+            UnGetToken
+          else
+            element.HintMessage:=curtokenstring;
+          end;  
         consumesemi;
         end
       else if (tok = 'PUBLIC') then
@@ -2806,6 +2999,7 @@ var
 
   procedure CreateBlock(NewBlock: TPasImplBlock);
   begin
+    CurBlock.AddElement(NewBlock);
     CurBlock:=NewBlock;
     if NewImplElement=nil then NewImplElement:=CurBlock;
   end;
@@ -2822,6 +3016,8 @@ var
   ForDownTo: Boolean;
   left: TPasExpr;
   right: TPasExpr;
+  el : TPasImplElement;
+
 begin
   NewImplElement:=nil;
   CurBlock := Parent;
@@ -2831,14 +3027,22 @@ begin
     //WriteLn(i,'Token=',CurTokenText);
     case CurToken of
     tkbegin:
-      CreateBlock(CurBlock.AddBeginBlock);
+      begin
+      el:=TPasImplElement(CreateElement(TPasImplBeginBlock,'',CurBlock));
+      CreateBlock(TPasImplBeginBlock(el));
+      end;
     tkrepeat:
-      CreateBlock(CurBlock.AddRepeatUntil);
+      begin
+      el:=TPasImplRepeatUntil(CreateElement(TPasImplRepeatUntil,'',CurBlock));
+      CreateBlock(TPasImplRepeatUntil(el));
+      end;
     tkIf:
       begin
-        Condition:=ParseExpression(Parent);
+        Condition:=ParseExpression(CurBlock);
+        el:=TPasImplIfElse(CreateElement(TPasImplIfElse,'',CurBlock));
+        TPasImplIfElse(el).Condition:=Condition;
         //WriteLn(i,'IF Condition="',Condition,'" Token=',CurTokenText);
-        CreateBlock(CurBlock.AddIfElse(Condition));
+        CreateBlock(TPasImplIfElse(el));
         ExpectToken(tkthen);
       end;
     tkelse:
@@ -2846,8 +3050,8 @@ begin
       begin
         if TPasImplIfElse(CurBlock).IfBranch=nil then
         begin
-          // empty then => add dummy command
-          CurBlock.AddCommand('');
+        el:=TPasImplCommand(CreateElement(TPasImplCommand,'', CurBlock));
+        CurBlock.AddElement(el);
         end;
         if TPasImplIfElse(CurBlock).ElseBranch<>nil then
         begin
@@ -2873,7 +3077,9 @@ begin
       end else if (CurBlock is TPasImplTryExcept) then
       begin
         CloseBlock;
-        CurBlock:=TPasImplTry(CurBlock).AddExceptElse;
+        el:=TPasImplTryExceptElse(CreateElement(TPasImplTryExceptElse,'',CurBlock));
+        TPasImplTry(CurBlock).ElseBranch:=TPasImplTryExceptElse(el);
+        CurBlock:=TPasImplTryExceptElse(el);
       end else
         ParseExc(SParserSyntaxError);
     tkwhile:
@@ -2881,7 +3087,9 @@ begin
         // while Condition do
         Condition:=ParseExpression(Parent);
         //WriteLn(i,'WHILE Condition="',Condition,'" Token=',CurTokenText);
-        CreateBlock(CurBlock.AddWhileDo(Condition));
+        el:=TPasImplWhileDo(CreateElement(TPasImplWhileDo,'',CurBlock));
+        TPasImplWhileDo(el).Condition:=Condition;
+        CreateBlock(TPasImplWhileDo(el));
         ExpectToken(tkdo);
       end;
     tkgoto:
@@ -2906,7 +3114,12 @@ begin
         else
           ParseExc(Format(SParserExpectTokenError, [TokenInfos[tkTo]]));
         EndValue:=ParseExpression(Parent);
-        CreateBlock(CurBlock.AddForLoop(VarName,StartValue,EndValue,ForDownTo));
+        el:=TPasImplForLoop(CreateElement(TPasImplForLoop,'',CurBlock));
+        TPasImplForLoop(el).VariableName:=VarName;
+        TPasImplForLoop(el).StartValue:=StartValue;
+        TPasImplForLoop(el).EndValue:=EndValue;
+        TPasImplForLoop(el).Down:=forDownto;
+        CreateBlock(TPasImplForLoop(el));
         //WriteLn(i,'FOR "',VarName,'" := ',StartValue,' to ',EndValue,' Token=',CurTokenText);
         ExpectToken(tkdo);
       end;
@@ -2916,7 +3129,9 @@ begin
         // with Expr, Expr do
         Expr:=ParseExpression(Parent);
         //writeln(i,'WITH Expr="',Expr,'" Token=',CurTokenText);
-        CreateBlock(CurBlock.AddWithDo(Expr));
+        el:=TPasImplWithDo(CreateElement(TPasImplWithDo,'',CurBlock));
+        TPasImplWithDo(el).AddExpression(expr);
+        CreateBlock(TPasImplWithDo(el));
         repeat
           NextToken;
           if CurToken=tkdo then break;
@@ -2932,7 +3147,9 @@ begin
         Expr:=ParseExpression(Parent);
         //writeln(i,'CASE OF Expr="',Expr,'" Token=',CurTokenText);
         ExpectToken(tkof);
-        CreateBlock(CurBlock.AddCaseOf(Expr));
+        el:=TPasImplCaseOf(CreateElement(TPasImplCaseOf,'',CurBlock));
+        TPasImplCaseOf(el).Expression:=Expr;
+        CreateBlock(TPasImplCaseOf(el));
         repeat
           NextToken;
           //writeln(i,'CASE OF Token=',CurTokenText);
@@ -2961,7 +3178,12 @@ begin
               if CurBlock is TPasImplCaseStatement then
                 TPasImplCaseStatement(CurBlock).Expressions.Add(Expr)
               else
-                CurBlock:=TPasImplCaseOf(CurBlock).AddCase(Expr);
+                begin
+                el:=TPasImplCaseStatement(CreateElement(TPasImplCaseStatement,'',CurBlock));
+                TPasImplCaseStatement(el).AddExpression(Expr);
+                CurBlock.AddElement(el);
+                CurBlock:=TPasImplCaseStatement(el);
+                end;
               //writeln(i,'CASE after value Token=',CurTokenText);
               if CurToken=tkColon then break;
               if CurToken<>tkComma then
@@ -2987,7 +3209,10 @@ begin
         end;
       end;
     tktry:
-      CreateBlock(CurBlock.AddTry);
+      begin
+      el:=TPasImplTry(CreateElement(TPasImplTry,'',Curblock));
+      CreateBlock(TPasImplTry(el));
+      end;
     tkfinally:
       begin
         if CloseStatement(true) then
@@ -2997,7 +3222,10 @@ begin
         end;
         if CurBlock is TPasImplTry then
         begin
-          CurBlock:=TPasImplTry(CurBlock).AddFinally;
+          el:=TPasImplTryFinally(CreateElement(TPasImplTryFinally,'',Curblock));
+          TPasImplTry(CurBlock).FinallyExcept:=TPasImplTryFinally(el);
+          CurBlock.AddElement(el);
+          CurBlock:=TPasImplTryFinally(el);
         end else
           ParseExc(SParserSyntaxError);
       end;
@@ -3011,7 +3239,10 @@ begin
         if CurBlock is TPasImplTry then
         begin
           //writeln(i,'EXCEPT');
-          CurBlock:=TPasImplTry(CurBlock).AddExcept;
+          el:=TPasImplTryExcept(CreateElement(TPasImplTryExcept,'',CurBlock));
+          TPasImplTry(CurBlock).FinallyExcept:=TPasImplTryExcept(el);
+//          CurBlock.AddElement(el);
+          CurBlock:=TPasImplTryExcept(el);
         end else
           ParseExc(SParserSyntaxError);
       end;
@@ -3033,13 +3264,20 @@ begin
             //writeln(i,'ON v=',VarName,' t=',TypeName,' Token=',CurTokenText);
           end else
             UngetToken;
-          CurBlock:=TPasImplTryExcept(CurBlock).AddExceptOn(VarName,TypeName);
+          el:=TPasImplExceptOn(CreateElement(TPasImplExceptOn,'',CurBlock));
+          TPasImplExceptOn(el).VariableName:=VarName;
+          TPasImplExceptOn(el).TypeName:=TypeName;
+          CurBlock.AddElement(el);
+          CurBlock:=TPasImplExceptOn(el);
           ExpectToken(tkDo);
         end else
           ParseExc(SParserSyntaxError);
       end;
     tkraise:
-      CreateBlock(CurBlock.AddRaise);
+      begin
+      el:=TPasImplRaise(CreateElement(TPasImplRaise,'',CurBlock));
+      CreateBlock(TPasImplRaise(el));
+      end;
     tkend:
       begin
         if CloseStatement(true) then
@@ -3090,7 +3328,11 @@ begin
           // assign statement
           NextToken;
           right:=DoParseExpression(nil); // this may solve TPasImplWhileDo.AddElement BUG
-          CmdElem:=CurBlock.AddAssign(left, right);
+          el:=TPasImplAssign(CreateElement(TPasImplAssign,'',CurBlock));
+          TPasImplAssign(el).left:=Left;
+          TPasImplAssign(el).right:=Right;
+          CurBlock.AddElement(el);
+          CmdElem:=TPasImplAssign(el);
           UngetToken;
         end;
         tkColon:
@@ -3098,12 +3340,18 @@ begin
           if not (left is TPrimitiveExpr) then
             ParseExc(Format(SParserExpectTokenError, [TokenInfos[tkSemicolon]]));
           // label mark. todo: check mark identifier in the list of labels
-          CmdElem:=CurBlock.AddLabelMark(TPrimitiveExpr(left).Value);
+          el:=TPasImplLabelMark(CreateElement(TPasImplLabelMark,'', CurBlock));
+          TPasImplLabelMark(el).LabelId:=TPrimitiveExpr(left).Value;
+          CurBlock.AddElement(el);
+          CmdElem:=TPasImplLabelMark(el);
           left.Free;
         end;
       else
         // simple statement (function call)
-        CmdElem:=CurBlock.AddSimple(left);
+        el:=TPasImplSimple(CreateElement(TPasImplSimple,'',CurBlock));
+        TPasImplSimple(el).expr:=Left;
+        CurBlock.AddElement(el);
+        CmdElem:=TPasImplSimple(el);
         UngetToken;
       end;
 

+ 26 - 7
packages/fcl-passrc/src/pscanner.pp

@@ -87,6 +87,7 @@ type
     tkcase,
     tkclass,
     tkconst,
+    tkconstref,
     tkconstructor,
     tkdestructor,
     tkdiv,
@@ -345,6 +346,8 @@ type
     destructor Destroy; override;
     procedure OpenFile(const AFilename: string);
     function FetchToken: TToken;
+    Procedure AddDefine(S : String);
+    Procedure RemoveDefine(S : String);
 
     property FileResolver: TBaseFileResolver read FFileResolver;
     property CurSourceFile: TLineReader read FCurSourceFile;
@@ -410,6 +413,7 @@ const
     'case',
     'class',
     'const',
+    'constref',
     'constructor',
     'destructor',
     'div',
@@ -1184,10 +1188,7 @@ begin
   Param := UpperCase(Param);
   Index:=Pos(':=',Param);
   If (Index=0) then
-    begin
-    if Defines.IndexOf(Param) < 0 then
-      Defines.Add(Param);
-    end
+    AddDefine(Param)
   else
     begin
     MV:=Trim(Param);
@@ -1208,9 +1209,9 @@ Var
 
 begin
   Param := UpperCase(Param);
-  Index := Defines.IndexOf(Param);
-  if Index >= 0 then
-    Defines.Delete(Index)
+  Index:=FDefines.IndexOf(Param);
+  If (Index<0) then
+    RemoveDefine(Param)
   else
     begin
     Index := FMacros.IndexOf(Param);
@@ -1786,4 +1787,22 @@ begin
   FOptions:=AValue;
 end;
 
+Procedure TPascalScanner.AddDefine(S : String);
+
+begin
+  If FDefines.IndexOf(S)=-1 then
+    FDefines.Add(S);
+end;
+
+Procedure TPascalScanner.RemoveDefine(S : String);
+
+Var
+  I : Integer;
+
+begin
+  I:=FDefines.IndexOf(S);
+  if (I<>-1) then
+    FDefines.Delete(I);
+end;
+
 end.

+ 37 - 1
utils/fpdoc/dglobals.pp

@@ -82,6 +82,7 @@ resourcestring
   SDocVisibility             = 'Visibility';
   SDocOpaque                 = 'Opaque type';
   SDocDateGenerated          = 'Documentation generated on: %s';
+  SDocNotes                  = 'Notes';
   
   // Topics
   SDocRelatedTopics = 'Related topics';
@@ -109,6 +110,7 @@ resourcestring
   SHTMLHtmlSearch = 'Add search page with given name to the menu bar';
   SHTMLIndexColcount = 'Use N columns in the identifier index pages';
   SHTMLImageUrl = 'Prefix image URLs with url';
+  SHTMLDisableMenuBrackets = 'Disable ''['' and '']'' characters around menu items at the top of the page. Useful for custom css';
     
   // CHM usage
   SCHMUsageTOC     = 'Use [File] as the table of contents. Usually a .hhc file.';
@@ -172,6 +174,7 @@ resourcestring
   SErrCouldNotCreateOutputDir = 'Could not create output directory "%s"';
   SErrCouldNotCreateFile      = 'Could not create file "%s": %s';
   SSeeURL                     = '(See %s)';      // For linear text writers.
+  SParsingUsedUnit            = 'Parsing used unit "%s" with commandLine "%s"';
 
 Const
   SVisibility: array[TPasMemberVisibility] of string =
@@ -238,6 +241,7 @@ type
     FErrorsDoc: TDOMElement;
     FSeeAlso: TDOMElement;
     FFirstExample: TDOMElement;
+    FNotes : TDomElement;
     FLink: String;
     FTopicNode : Boolean;
     FRefCount : Integer;
@@ -262,6 +266,7 @@ type
     Property Version : TDomElement Read FVersion;
     property SeeAlso: TDOMElement read FSeeAlso;
     property FirstExample: TDOMElement read FFirstExample;
+    property Notes : TDOMElement read FNotes;
     property Link: String read FLink;
     Property TopicNode : Boolean Read FTopicNode;
     Property RefCount : Integer Read FRefCount;
@@ -272,11 +277,13 @@ type
   // The main FPDoc engine
   TFPDocLogLevel = (dleWarnNoNode);
   TFPDocLogLevels = set of TFPDocLogLevel;
+  TOnParseUnitEvent = Procedure (Sender : TObject; Const AUnitName : String; Out AInputFile,OSTarget,CPUTarget : String) of  Object;
 
   { TFPDocEngine }
   TFPDocEngine = class(TPasTreeContainer)
   private
     FDocLogLevels: TFPDocLogLevels;
+    FOnParseUnit: TOnParseUnitEvent;
   protected
     DescrDocs: TObjectList;             // List of XML documents
     DescrDocNames: TStringList;         // Names of the XML documents
@@ -285,6 +292,7 @@ type
     FPackages: TFPList;                   // List of TFPPackage objects
     CurModule: TPasModule;
     CurPackageDocNode: TDocNode;
+    function ParseUsedUnit(AName, AInputLine,AOSTarget,ACPUTarget: String): TPasModule; virtual;
     Function LogEvent(E : TFPDocLogLevel) : Boolean;
     Procedure DoLog(Const Msg : String);overload;
     Procedure DoLog(Const Fmt : String; Args : Array of const);overload;
@@ -328,6 +336,7 @@ type
     property RootLinkNode: TLinkNode read FRootLinkNode;
     property RootDocNode: TDocNode read FRootDocNode;
     Property DocLogLevels : TFPDocLogLevels Read FDocLogLevels Write FDocLogLevels;
+    Property OnParseUnit : TOnParseUnitEvent Read FOnParseUnit Write FOnParseUnit;
   end;
 
 
@@ -1168,6 +1177,8 @@ function TFPDocEngine.FindModule(const AName: String): TPasModule;
 
 var
   i: Integer;
+  AInPutLine,OSTarget,CPUTarget : String;
+
 begin
   Result := FindInPackage(Package);
   if not Assigned(Result) then
@@ -1179,6 +1190,29 @@ begin
       if Assigned(Result) then
         exit;
     end;
+  if Not Assigned(Result) and Assigned(FOnParseUnit) then
+    begin
+    FOnParseUnit(Self,AName,AInputLine,OSTarget,CPUTarget);
+    If (AInPutLine<>'') then
+      Result:=ParseUsedUnit(AName,AInputLine,OSTarget,CPUTarget);
+    end;
+end;
+
+Function TFPDocEngine.ParseUsedUnit(AName,AInputLine,AOSTarget,ACPUTarget : String) : TPasModule;
+
+Var
+  M : TPasModule;
+
+begin
+  DoLog(SParsingUsedUnit,[AName,AInputLine]);
+  M:=CurModule;
+  CurModule:=Nil;
+  try
+    ParseSource(Self,AInputLine,AOSTarget,ACPUTarget,True);
+    Result:=CurModule;
+  finally
+    CurModule:=M;
+  end;
 end;
 
 procedure TFPDocEngine.AddLink(const APathName, ALinkTo: String);
@@ -1336,7 +1370,9 @@ procedure TFPDocEngine.AddDocFile(const AFilename: String;DontTrim:boolean=false
           Result.FSeeAlso := TDOMElement(Subnode)
         else if (Subnode.NodeName = 'example') and
           not Assigned(Result.FirstExample) then
-          Result.FFirstExample := TDOMElement(Subnode);
+          Result.FFirstExample := TDOMElement(Subnode)
+        else if (Subnode.NodeName = 'notes') then
+          Result.FNotes := TDOMElement(Subnode);
       end;
       Subnode := Subnode.NextSibling;
     end;

+ 91 - 39
utils/fpdoc/dw_html.pp

@@ -83,6 +83,8 @@ type
 
   THTMLWriter = class(TFPDocWriter)
   private
+    FImageFileList: TStrings;
+
     FOnTest: TNotifyEvent;
     FPackage: TPasPackage;
     FCharSet : String;
@@ -111,6 +113,7 @@ type
     FIndexColCount : Integer;
     FSearchPage : String;
     FBaseImageURL : String;
+    FUseMenuBrackets: Boolean;
 
     Procedure CreateAllocator; virtual;
     function ResolveLinkID(const Name: String): DOMString;
@@ -135,6 +138,8 @@ type
     function CreateWarning(Parent: TDOMNode): THTMLElement;
 
     // Description node conversion
+    Procedure DescrEmitNotesHeader(AContext : TPasElement); override;
+    Procedure DescrEmitNotesFooter(AContext : TPasElement); override;
     procedure PushOutputNode(ANode: TDOMNode);
     procedure PopOutputNode;
     procedure DescrWriteText(const AText: DOMString); override;
@@ -186,7 +191,6 @@ type
     procedure DescrBeginTableCell; override;
     procedure DescrEndTableCell; override;
 
-
     procedure AppendText(Parent: TDOMNode; const AText: DOMString);
     procedure AppendNbSp(Parent: TDOMNode; ACount: Integer);
     procedure AppendSym(Parent: TDOMNode; const AText: DOMString);
@@ -210,7 +214,7 @@ type
     procedure AppendProcDecl(CodeEl, TableEl: TDOMElement;
       Element: TPasProcedureBase);
     procedure AppendProcArgsSection(Parent: TDOMNode;
-      Element: TPasProcedureType);
+      Element: TPasProcedureType; SkipResult : Boolean = False);
     function AppendRecordType(CodeEl, TableEl: TDOMElement;
       Element: TPasRecordType; NestingLevel: Integer): TDOMElement;
 
@@ -253,6 +257,7 @@ type
 
     Function InterPretOption(Const Cmd,Arg : String) : boolean; override;
     Procedure WriteDoc; override;
+    Class Function FileNameExtension : String; override;
     class procedure Usage(List: TStrings); override;
     Property SearchPage: String Read FSearchPage Write FSearchPage;
     property Allocator: TFileAllocator read FAllocator;
@@ -264,6 +269,7 @@ type
     Property CharSet : String Read FCharSet Write FCharSet;
     Property IndexColCount : Integer Read FIndexColCount write FIndexColCount;
     Property BaseImageURL : String Read FBaseImageURL Write FBaseImageURL;
+    Property UseMenuBrackets : Boolean Read FUseMenuBrackets write FUseMenuBrackets;
   end;
 
   THTMWriter = class(THTMLWriter)
@@ -614,6 +620,10 @@ var
 
 begin
   inherited ;
+
+  // should default to true since this is the old behavior
+  UseMenuBrackets:=True;
+
   IndexColCount:=3;
   Charset:='iso-8859-1';
   CreateAllocator;
@@ -621,6 +631,7 @@ begin
   OutputNodeStack := TList.Create;
 
   PageInfos := TObjectList.Create;
+  FImageFileList := TStringList.Create;
 
   // Allocate page for the package itself, if a name is given (i.e. <> '#')
   if Length(Package.Name) > 1 then
@@ -647,6 +658,7 @@ begin
   PageInfos.Free;
   OutputNodeStack.Free;
   FAllocator.Free;
+  FImageFileList.Free;
   inherited Destroy;
 end;
 
@@ -745,7 +757,7 @@ begin
         PageDoc.Free;
       end;
     end;
-  
+
   if FCSSFile <> '' then
   begin
     if not FileExists(FCSSFile) Then
@@ -971,6 +983,17 @@ begin
   Result['class'] := 'warning';
 end;
 
+procedure THTMLWriter.DescrEmitNotesHeader(AContext: TPasElement);
+begin
+  AppendText(CreateH2(BodyElement), SDocNotes);
+  PushOutputNode(BodyElement);
+end;
+
+procedure THTMLWriter.DescrEmitNotesFooter(AContext: TPasElement);
+begin
+  PopOutPutNode;
+end;
+
 procedure THTMLWriter.PushOutputNode(ANode: TDOMNode);
 begin
   OutputNodeStack.Add(CurOutputNode);
@@ -1042,27 +1065,23 @@ begin
       Cel:=CreateAnchor(Cel,ALinkName);
     AppendText(Cel,ACaption);
     end;
+
   // Determine URL for image.  
-  D:=BaseImageURL;
-  If (D='') then
-    begin
-    If (Module=Nil) then
-      D:=Allocator.GetRelativePathToTop(Package)
-    else 
-      D:=Allocator.GetRelativePathToTop(Module);
-    L:=Length(D);  
-    If (L>0) and (D[L]<>'/') then
-      D:=D+'/';
-    D:=D+'images/';
-    end
-  else  
-    L:=Length(D);  
-    If (L>0) and (D[L]<>'/') then
-      D:=D+'/';
+  If (Module=Nil) then
+    D:=Allocator.GetRelativePathToTop(Package)
+  else
+    D:=Allocator.GetRelativePathToTop(Module);
+  L:=Length(D);
+  If (L>0) and (D[L]<>'/') then
+    D:=D+'/';
+
   // Create image node.  
   El:=CreateEl(Pel,'img');
-  EL['src']:=D+AFileName;
+  EL['src']:=D + BaseImageURL + AFileName;
   El['alt']:=ACaption;
+
+  //cache image filename, so it can be used later (CHM)
+  FImageFileList.Add(BaseImageURL + AFileName);
 end;
 
 procedure THTMLWriter.DescrWriteFileEl(const AText: DOMString);
@@ -1731,9 +1750,9 @@ end;
 procedure THTMLWriter.AppendProcDecl(CodeEl, TableEl: TDOMElement;
   Element: TPasProcedureBase);
 
-  procedure WriteVariant(AProc: TPasProcedure);
+  procedure WriteVariant(AProc: TPasProcedure; SkipResult : Boolean);
   begin
-    AppendProcArgsSection(TableEl.ParentNode, AProc.ProcType);
+    AppendProcArgsSection(TableEl.ParentNode, AProc.ProcType, SkipResult);
 
     AppendKw(CodeEl, AProc.TypeName);
     if Element.Parent.ClassType = TPasClassType then
@@ -1750,24 +1769,29 @@ procedure THTMLWriter.AppendProcDecl(CodeEl, TableEl: TDOMElement;
   end;
 
 var
-  i: Integer;
+  i,fc: Integer;
+  P : TPasProcedure;
 begin
+  fc:=0;
   if Element.ClassType = TPasOverloadedProc then
     for i := 0 to TPasOverloadedProc(Element).Overloads.Count - 1 do
     begin
+      P:=TPasProcedure(TPasOverloadedProc(Element).Overloads[i]);
+      if (P.ProcType is TPasFunctionType) then
+        Inc(fc);
       if i > 0 then
       begin
         CreateEl(CodeEl, 'br');
         CreateEl(CodeEl, 'br');
       end;
-      WriteVariant(TPasProcedure(TPasOverloadedProc(Element).Overloads[i]));
+      WriteVariant(P,fc>1);
     end
   else
-    WriteVariant(TPasProcedure(Element));
+    WriteVariant(TPasProcedure(Element),False);
 end;
 
 procedure THTMLWriter.AppendProcArgsSection(Parent: TDOMNode;
-  Element: TPasProcedureType);
+  Element: TPasProcedureType; SkipResult : Boolean = False);
 var
   HasFullDescr, IsFirst: Boolean;
   ResultEl: TPasResultElement;
@@ -1793,7 +1817,7 @@ begin
     AppendShortDescrCell(TREl, Arg);
   end;
 
-  if Element.ClassType = TPasFunctionType then
+  if (Element.ClassType = TPasFunctionType) and not SkipResult then
   begin
     ResultEl := TPasFunctionType(Element).ResultEl;
     DocNode := Engine.FindDocNode(ResultEl);
@@ -1896,9 +1920,11 @@ var
 
   procedure AddLink(El : TPasElement; const AName: String);
   begin
-    AppendText(ParaEl, '[');
+    if FUseMenuBrackets then
+      AppendText(ParaEl, '[');
     AppendText(CreateLink(ParaEl, ResolveLinkWithinPackage(El,0)),AName);
-    AppendText(ParaEl, ']');
+    if FUseMenuBrackets then
+      AppendText(ParaEl, ']');
   end;
 
 begin
@@ -1918,9 +1944,11 @@ begin
     AddLink(Topic.Next,SDocNext);
   if Length(SearchPage) > 0 then
     begin
-    AppendText(ParaEl, '[');
+    if FUseMenuBrackets then
+      AppendText(ParaEl, '[');
     AppendText(CreateLink(ParaEl, SearchPage), SDocSearch);
-    AppendText(ParaEl, ']');
+    if FUseMenuBrackets then
+      AppendText(ParaEl, ']');
     end;
   ParaEl := CreateTD(TREl);
   ParaEl['align'] := 'right';
@@ -1943,14 +1971,16 @@ var
 
   procedure AddLink(ALinkSubpageIndex: Integer; const AName: String);
   begin
-    AppendText(ParaEl, '[');
+    if FUseMenuBrackets then
+      AppendText(ParaEl, '[');
     if ALinkSubpageIndex = ASubpageIndex then
       AppendText(ParaEl, AName)
     else
       AppendText(
         CreateLink(ParaEl, ResolveLinkWithinPackage(Module, ALinkSubpageIndex)),
         AName);
-    AppendText(ParaEl, ']');
+    if FUseMenuBrackets then
+      AppendText(ParaEl, ']');
   end;
 
 begin
@@ -1983,21 +2013,25 @@ begin
   else
     begin
     // Manually add link for package page
-    AppendText(ParaEl, '[');
+    if FUseMenuBrackets then
+      AppendText(ParaEl, '[');
     if (IndexSubIndex = ASubpageIndex) then
       AppendText(ParaEl, SDocIdentifierIndex)
     else
       AppendText(
         CreateLink(ParaEl, ResolveLinkWithinPackage(Package, IndexSubIndex)),
         SDocIdentifierIndex);
-    AppendText(ParaEl, ']');
+    if FUseMenuBrackets then
+      AppendText(ParaEl, ']');
     end;
 
   if Length(SearchPage) > 0 then
   begin
-    AppendText(ParaEl, '[');
+    if FUseMenuBrackets then
+      AppendText(ParaEl, '[');
     AppendText(CreateLink(ParaEl, SearchPage), SDocSearch);
-    AppendText(ParaEl, ']');
+    if FUseMenuBrackets then
+      AppendText(ParaEl, ']');
   end;
   ParaEl := CreateTD(TREl);
   ParaEl['align'] := 'right';
@@ -2186,6 +2220,8 @@ begin
 
     // Append examples, if present
     AppendExampleSection(AElement,DocNode);
+    // Append notes, if present
+    ConvertNotes(AElement,DocNode.Notes);
     end;
 end;
 
@@ -2209,6 +2245,7 @@ begin
     AppendSeeAlsoSection(AElement,DocNode);
     CreateTopicLinks(DocNode,AElement);
     AppendExampleSection(AElement,DocNode);
+    ConvertNotes(AElement,DocNode.Notes);
     end;
 end;
 
@@ -2544,6 +2581,7 @@ procedure THTMLWriter.CreateModulePageBody(AModule: TPasModule;
       begin
       if Assigned(DocNode.Descr) then
         AppendDescrSection(AModule, BodyElement, DocNode.Descr, SDocOverview);
+      ConvertNotes(AModule,DocNode.Notes);
       CreateTopicLinks(DocNode,AModule);
       end;
   end;
@@ -2819,7 +2857,8 @@ var
   var
     LinkEl: TDOMElement;
   begin
-    AppendText(ParaEl, '[');
+    if FUseMenuBrackets then
+      AppendText(ParaEl, '[');
     LinkEl := CreateEl(ParaEl, 'a');
     LinkEl['href'] :=
       FixHtmlPath(ResolveLinkWithinPackage(AClass, AListSubpageIndex));
@@ -2834,7 +2873,10 @@ var
      '''dependent=yes,resizable=yes,scrollbars=yes,height=400,width=300''); return false;';
     AppendText(LinkEl, SDocByName);
     AppendText(ParaEl, ')');
-    AppendText(ParaEl, '] ');
+    if FUseMenuBrackets then
+      AppendText(ParaEl, '] ')
+    else
+      AppendText(ParaEl, ' ');
   end;
 
   procedure AppendGenericTypes(CodeEl : TDomElement; AList : TFPList; isSpecialize : Boolean);
@@ -3411,6 +3453,7 @@ Function THTMLWriter.InterPretOption(Const Cmd,Arg : String) : boolean;
 
 begin
   Result:=True;
+
   if Cmd = '--html-search' then
     SearchPage := Arg
   else if Cmd = '--footer' then
@@ -3428,6 +3471,8 @@ begin
     FIDF:=True;
     FDateFormat:=Arg;
     end
+  else if Cmd = '--disable-menu-brackets' then
+    FUseMenuBrackets:=False
   else
     Result:=False;
 end;
@@ -3452,6 +3497,13 @@ begin
   List.Add(SHTMLIndexColcount);
   List.Add('--image-url=url');
   List.Add(SHTMLImageUrl);
+  List.Add('--disable-menu-brackets');
+  List.Add(SHTMLDisableMenuBrackets);
+end;
+
+Class Function THTMLWriter.FileNameExtension : String; 
+begin
+  result:='';
 end;
 
 // private methods

+ 41 - 23
utils/fpdoc/dw_htmlchm.inc

@@ -31,6 +31,8 @@ type
     function  InterPretOption(const Cmd,Arg : String): boolean; override;
 
     class procedure Usage(List: TStrings); override;
+    Class Function FileNameExtension : String; override;
+    
   end;
 {$ELSE} // implementation
 
@@ -44,16 +46,13 @@ begin
     FDefaultPage := 'index.html'
   else
   begin
-    WriteLn('Note: --index-page not assigned. Using default "index.html"');
+    DoLog('Note: --index-page not assigned. Using default "index.html"');
   end;
   
   if FCSSFile <> '' then
   begin
     if not FileExists(FCSSFile) Then
-      begin
-        Writeln(stderr,'Can''t find CSS file "',FCSSFILE,'"');
-        halt(1);
-      end;
+      Raise Exception.CreateFmt('Can''t find CSS file "%S"',[FCSSFILE]);
     TempStream := TMemoryStream.Create;
     TempStream.LoadFromFile(FCSSFile);
     TempStream.Position := 0;
@@ -117,7 +116,7 @@ begin
       FChm.AppendIndex(TmpStream);
     end;
   TmpStream.Free;
-  WriteLn('Finishing compressing...');
+  DoLog('Finishing compressing...');
 end;
 
 function TOCSort(Item1, Item2: TChmSiteMapItem): Integer;
@@ -158,7 +157,7 @@ var
   AlphaRoutinesItem: TChmSiteMapItem;
 
 begin
-  WriteLn('Generating Table of contents...');
+  DoLog('Generating Table of contents...');
   if Assigned(Package) then
   begin
     Toc := TChmSiteMap.Create(stTOC);
@@ -284,11 +283,10 @@ var
   MemberItem: TChmSiteMapItem;
   Stream: TMemoryStream;
 begin
-  WriteLn('Generating Index...');
+  DoLog('Generating Index...');
 
   if Assigned(Package) then
   begin
-  try
     Index := TChmSiteMap.Create(stIndex);
     Stream := TMemoryStream.Create;
     for i := 0 to Package.Modules.Count - 1 do
@@ -422,10 +420,6 @@ begin
     Stream.Position :=0 ;
     FChm.AppendIndex(Stream);
     Stream.Free;
-  except
-    Dump_Stack(StdOut, get_frame);
-    Halt(1);
-  end;
   end;
 end;
 
@@ -437,16 +431,14 @@ var
   FileName: String;
   FilePath: String;
 begin
-  if Engine.Output = '' then
-  begin
-    WriteLn('Error: no --output option used.');
-    Exit;
-  end;
+  FileName := Engine.Output;
+  if FileName = '' then
+    Raise Exception.Create('Error: no --output option used.'); 
   
-  if ExtractFileExt(Engine.Output) <> '.chm' then
-    ChangeFileExt(Engine.OutPut, '.chm');
+  if ExtractFileExt(FileName) <> FileNameExtension then
+    FileName := ChangeFileExt(FileName, FileNameExtension);
 
-  FOutChm := TFileStream.Create(Engine.Output, fmOpenReadWrite or fmCreate);
+  FOutChm := TFileStream.Create(FileName, fmOpenReadWrite or fmCreate);
 
   FTempUncompressedName := GetTempFileName+IntToStr(GetProcessID) +'.raw';
   FTempUncompressed := TFileStream.Create(FTempUncompressedName, fmOpenReadWrite  or fmCreate);
@@ -473,7 +465,7 @@ begin
           FChm.AddStreamToArchive(FileName, FilePath, FileStream, True);
         except
 	  on E: Exception do
-            WriteLn(Format(SErrCouldNotCreateFile, [FileName, e.Message]));
+            DoLog(Format(SErrCouldNotCreateFile, [FileName, e.Message]));
         end;
       finally
         PageDoc.Free;
@@ -481,7 +473,29 @@ begin
       end;
     end;
   FileStream.Free;
-  WriteLn('HTML Files written. Collecting other files and compressing...this could take some time');
+
+  DoLog('HTML Files written. Collecting other files and compressing...this could take some time');
+
+  //write any found images to CHM stream
+  FileStream := TMemoryStream.Create;
+  for i := 0 to FImageFileList.Count - 1 do
+  begin
+{$ifdef imagetest}    DoLog('  adding image: '+FImageFileList[i]); {$endif}
+    if FileExists(FImageFileList[i]) then
+    begin
+{$ifdef imagetest}    DoLog(' - found'); {$endif}
+      FileName := ExtractFileName(FImageFileList[i]);
+      FilePath := '/'+FixHTMLpath(ExtractFilePath(FImageFileList[i]));
+
+      FileStream.LoadFromFile(FImageFileList[i]);
+      FChm.AddStreamToArchive(FileName, FilePath, FileStream, True);
+      FileStream.Size := 0;
+    end
+    else
+      {$ifdef imagetest}  DoLog(' - not found'){$endif};
+  end;
+  FileStream.Free;
+
   FChm.Execute;
   FChm.Free;
   // we don't need to free FTempUncompressed
@@ -545,6 +559,10 @@ begin
   List.Add(SCHMUsageChmTitle);
 end;
 
+Class Function TCHMHTMLWriter.FileNameExtension : String; 
 
+begin
+  result:='.chm';
+end;
 
 {$ENDIF}

+ 1 - 1
utils/fpdoc/dw_ipflin.pas

@@ -89,7 +89,6 @@ type
     procedure EndOverview; override;
     procedure WriteOverviewMember(const ALabel,AName,Access,ADescr : String); override;
     procedure WriteOverviewMember(const ALabel,AName,ADescr : String); override;
-    class function FileNameExtension: string; override;
     procedure DescrBeginURL(const AURL: DOMString); override;
     procedure DescrEndURL; override;
     // Description node conversion. Overrides for TFPDocWriter.
@@ -141,6 +140,7 @@ type
     // TFPDocWriter class methods
   public
     constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override;
+    class function FileNameExtension: string; override;
   end;
 
 

+ 2 - 1
utils/fpdoc/dw_latex.pp

@@ -79,7 +79,6 @@ Type
     procedure EndOverview; override;
     procedure WriteOverviewMember(const ALabel,AName,Access,ADescr : String); override;
     procedure WriteOverviewMember(const ALabel,AName,ADescr : String); override;
-    Class Function FileNameExtension : String; override;
     // Description node conversion
     procedure DescrBeginBold; override;
     procedure DescrEndBold; override;
@@ -131,6 +130,8 @@ Type
     // TFPDocWriter class methods
     Function InterPretOption(Const Cmd,Arg : String) : boolean; override;
     Property ImageDir : String Read FImageDir Write FImageDir;
+  public
+    Class Function FileNameExtension : String; override;
   end;
 
 

+ 2 - 1
utils/fpdoc/dw_linrtf.pp

@@ -114,7 +114,6 @@ type
     procedure WriteOverviewMember(const ALabel,AName,Access,ADescr : String); override;
     procedure WriteOverviewMember(const ALabel,AName,ADescr : String); override;
     procedure EndOverview; override;
-    Class Function FileNameExtension : String; override;
     // Description node conversion
     procedure DescrBeginBold; override;
     procedure DescrEndBold; override;
@@ -162,6 +161,8 @@ type
     procedure DescrEndTableCell; override;
     // TFPDocWriter class methods
     Function InterPretOption(Const Cmd,Arg : String) : boolean; override;
+  public
+    Class Function FileNameExtension : String; override;
   end;
 
 

+ 2 - 1
utils/fpdoc/dw_lintmpl.pp

@@ -91,7 +91,6 @@ Type
     procedure EndOverview; override;
     procedure WriteOverviewMember(const ALabel,AName,Access,ADescr : String); override;
     procedure WriteOverviewMember(const ALabel,AName,ADescr : String); override;
-    Class Function FileNameExtension : String; override;
     // Description node conversion. Overrides for TFPDocWriter.
     procedure DescrBeginBold; override;
     procedure DescrEndBold; override;
@@ -139,6 +138,8 @@ Type
     procedure DescrEndTableCell; override;
     // TFPDocWriter class methods
     Function InterPretOption(Const Cmd,Arg : String) : boolean; override;
+  public
+    Class Function FileNameExtension : String; override;
     Class procedure Usage(List: TStrings); override;
   end;
 

+ 1 - 1
utils/fpdoc/dw_man.pp

@@ -97,7 +97,6 @@ Type
     procedure WriteCommentLine;
     procedure WriteComment(Comment : String);
     Procedure WriteExampleFile(FN : String); virtual;
-    Class Function FileNameExtension : String;virtual;
     procedure WriteExample(ADocNode: TDocNode);
     procedure WriteSeeAlso(ADocNode: TDocNode; Comma : Boolean);
   Public
@@ -178,6 +177,7 @@ Type
     procedure DescrBeginTableCell; override;
     procedure DescrEndTableCell; override;
     Function InterPretOption(Const Cmd,Arg : String) : boolean; override;
+    Class Function FileNameExtension : String; override;
     Class procedure Usage(List: TStrings); override;
   end;
 

+ 1 - 1
utils/fpdoc/dw_template.pp

@@ -161,7 +161,7 @@ Type
     // Provide feedback about usage of this backend.
     Class procedure Usage(List: TStrings); override;
     // For info only. See linear writer for an example.
-    Class Function FileNameExtension : String;virtual;
+    Class Function FileNameExtension : String; override;
   end;
 
 implementation

+ 1 - 1
utils/fpdoc/dw_txt.pp

@@ -82,7 +82,6 @@ Type
     procedure EndOverview; override;
     procedure WriteOverviewMember(const ALabel,AName,Access,ADescr : String); override;
     procedure WriteOverviewMember(const ALabel,AName,ADescr : String); override;
-    Class Function FileNameExtension : String; override;
     // Description node conversion
     procedure DescrBeginBold; override;
     procedure DescrEndBold; override;
@@ -130,6 +129,7 @@ Type
     procedure DescrEndTableCell; override;
   Public
     Constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override;
+    Class Function FileNameExtension : String; override;
     Class Procedure Usage(List : TStrings) ; override;
     Function InterpretOption(Const Cmd,Arg : String) : Boolean; override;
   end;

+ 12 - 2
utils/fpdoc/dwlinear.pp

@@ -85,7 +85,6 @@ Type
     procedure StartUnitOverview(AModuleName,AModuleLabel : String);virtual; Abstract;
     procedure WriteUnitEntry(UnitRef : TPasType);virtual; Abstract;
     procedure EndUnitOverview; virtual; Abstract;
-    Class Function FileNameExtension : String;virtual; Abstract;
     Property LastURL : DomString Read FLastURL Write FLastURL;
   Public
     Constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override;
@@ -413,6 +412,7 @@ begin
     begin
       WriteSeeAlso(DocNode);
     end;
+    ConvertNotes(ClassDecl,DocNode.Notes);
   end;
 
   // Write Interfaces Overview;
@@ -589,7 +589,9 @@ var
 begin
   PackageName := LowerCase(Copy(Package.Name, 2, 255));
   If (Engine.OutPut='') then
-    Engine.Output:=PackageName+FileNameExtension;
+    Engine.Output:=PackageName+FileNameExtension
+  else if (ExtractFileExt(Engine.output)='') and (FileNameExtension<>'') then
+    Engine.Output:=ChangeFileExt(Engine.output,FileNameExtension);  
   FStream:=TFileStream.Create(Engine.Output,fmCreate);
   try
     WriteBeginDocument;
@@ -713,6 +715,7 @@ begin
     begin
     StartSection(SDocOverview);
     WriteDescr(ASection.Parent, DocNode.Descr);
+    ConvertNotes(ASection.Parent,DocNode.Notes);
     end;
 end;
 
@@ -729,6 +732,7 @@ begin
     WriteDescr(Package, DocNode.Descr);
     end;
   WriteSeeAlso(DocNode);
+  ConvertNotes(Nil,DocNode.Notes);
   ProcessTopics(DocNode,1);
 end;
 
@@ -771,6 +775,7 @@ begin
   If Assigned(Node.Descr) then
     WriteDescr(Element,Node.Descr);
   WriteSeeAlso(Node);
+  ConvertNotes(Element,Node.Notes);
   If Level<3 then
     begin
     SubNode:=Node.FirstChild;
@@ -888,6 +893,8 @@ begin
         Writeln(Format('%s : ',[SDocVersion]));
         WriteDescr(TypeDecl, DocNode.Version);
         end;
+      if Assigned(DocNode) and assigned(DocNode.Notes) then
+        ConvertNotes(TypeDecl,DocNode.Notes);
       DescrEndParagraph;
       end;
   end;
@@ -918,6 +925,7 @@ begin
         begin
         Writeln(Format('%s : ',[SDocVersion]));
         WriteDescr(VarDecl, DocNode.Version);
+        ConvertNotes(VarDecl,DocNode.Notes);
         end;
       DescrEndParaGraph;
     end;
@@ -990,6 +998,7 @@ begin
       WriteSeeAlso(DocNode);
       EndProcedure;
       WriteExample(DocNode);
+      ConvertNotes(ProcDecl,DocNode.Notes);
       end
      else
       EndProcedure;
@@ -1104,6 +1113,7 @@ begin
         WriteDescr(PropDecl, lNode.Version);
         end;
       WriteSeeAlso(lNode);
+      ConvertNotes(PropDecl,lNode.Notes);
       EndProperty;
       WriteExample(lNode);
     end

+ 81 - 5
utils/fpdoc/dwriter.pp

@@ -64,15 +64,18 @@ type
   end;
 
   TWriterLogEvent = Procedure(Sender : TObject; Const Msg : String) of object;
-
+  TWriterNoteEvent = Procedure(Sender : TObject; Note : TDomElement; Var EmitNote : Boolean) of object;
+  
   { TFPDocWriter }
 
   TFPDocWriter = class
   private
+    FEmitNotes: Boolean;
     FEngine  : TFPDocEngine;
     FPackage : TPasPackage;
     FTopics  : TList;
     FImgExt : String;
+    FBeforeEmitNote : TWriterNoteEvent;
     procedure ConvertURL(AContext: TPasElement; El: TDOMElement);
     
   protected
@@ -88,6 +91,7 @@ type
     function IsDescrNodeEmpty(Node: TDOMNode): Boolean;
     function IsExtShort(Node: TDOMNode): Boolean;
     function ConvertShort(AContext: TPasElement; El: TDOMElement): Boolean;
+    function ConvertNotes(AContext: TPasElement; El: TDOMElement): Boolean; virtual;
     function ConvertBaseShort(AContext: TPasElement; Node: TDOMNode): Boolean;
     procedure ConvertBaseShortList(AContext: TPasElement; Node: TDOMNode;
       MayBeEmpty: Boolean);
@@ -102,7 +106,9 @@ type
     function ConvertSimpleBlock(AContext: TPasElement; Node: TDOMNode): Boolean;
     Function FindTopicElement(Node : TDocNode): TTopicElement;
     Procedure ConvertImage(El : TDomElement);
-    
+
+    Procedure DescrEmitNotesHeader(AContext : TPasElement); virtual;
+    Procedure DescrEmitNotesFooter(AContext : TPasElement); virtual;
     procedure DescrWriteText(const AText: DOMString); virtual; abstract;
     procedure DescrBeginBold; virtual; abstract;
     procedure DescrEndBold; virtual; abstract;
@@ -160,6 +166,7 @@ type
     Property ImageExtension : String Read FImgExt Write FImgExt;
     // Should return True if option was succesfully interpreted.
     Function InterpretOption(Const Cmd,Arg : String) : Boolean; Virtual;
+    Class Function FileNameExtension : String; virtual;
     Class Procedure Usage(List : TStrings); virtual;
     procedure WriteDoc; virtual; Abstract;
     Function WriteDescr(Element: TPasElement) : TDocNode;
@@ -169,6 +176,8 @@ type
     Procedure FPDocError(Fmt : String; Args : Array of Const);
     Function  ShowMember(M : TPasElement) : boolean;
     Procedure GetMethodList(ClassDecl: TPasClassType; List : TStringList);
+    Property EmitNotes : Boolean Read FEmitNotes Write FEmitNotes;
+    Property BeforeEmitNote : TWriterNoteEvent Read FBeforeEmitNote Write FBeforeEmitNote;
   end;
 
   TFPDocWriterClass = Class of TFPDocWriter;
@@ -345,12 +354,18 @@ begin
   Inherited;
 end;
 
-function TFPDocWriter.InterpretOption(Const Cmd,Arg : String): Boolean;
+function TFPDocWriter.InterpretOption(const Cmd, Arg: String): Boolean;
 begin
   Result:=False;
 end;
 
-Class procedure TFPDocWriter.Usage(List: TStrings);
+class function TFPDocWriter.FileNameExtension: String;
+begin
+//Override in linear writers with the expected extension.
+  Result := ''; //Output must not contain an extension.
+end;
+
+class procedure TFPDocWriter.Usage(List: TStrings);
 begin
   // Do nothing.
 end;
@@ -371,7 +386,8 @@ begin
     end;
 end;
 
-Procedure TFPDocWriter.DescrWriteImageEl(const AFileName, ACaption,ALinkName : DOMString); 
+procedure TFPDocWriter.DescrWriteImageEl(const AFileName, ACaption,
+  ALinkName: DOMString);
 
 begin
   DoLog('%s : No support for images yet: %s (caption: "%s")',[ClassName,AFileName,ACaption]);
@@ -475,6 +491,52 @@ begin
   Result := True;
 end;
 
+function TFPDocWriter.ConvertNotes(AContext: TPasElement; El: TDOMElement
+  ): Boolean;
+
+Var
+  L : TFPList;
+  N : TDomNode;
+  I : Integer;
+  B : Boolean;
+
+begin
+  Result:=Assigned(El) and EmitNotes;
+  If Not Result then
+    exit;
+  L:=TFPList.Create;
+  try
+    N:=El.FirstChild;
+    While Assigned(N) do
+      begin
+      If (N.NodeType=ELEMENT_NODE) and (N.NodeName='note') then
+        begin
+        B:=True;
+        if Assigned(FBeforeEmitNote) then
+          FBeforeEmitNote(Self,TDomElement(N),B);
+        If B then
+          L.Add(N);
+        end;
+      N:=N.NextSibling;
+      end;
+    Result:=L.Count>0;
+    If Not Result then
+      exit;
+    DescrEmitNotesHeader(AContext);
+    DescrBeginUnorderedList;
+    For i:=0 to L.Count-1 do
+      begin
+      DescrBeginListItem;
+      ConvertExtShortOrNonSectionBlocks(AContext, TDOMNode(L[i]).FirstChild);
+      DescrEndListItem;
+      end;
+    DescrEndUnorderedList;
+    DescrEmitNotesFooter(AContext);
+  finally
+    L.Free;
+  end;
+end;
+
 function TFPDocWriter.ConvertBaseShort(AContext: TPasElement;
   Node: TDOMNode): Boolean;
 
@@ -1037,6 +1099,20 @@ begin
   DescrWriteImageEl(FN,Cap,LinkName);
 end;
 
+procedure TFPDocWriter.DescrEmitNotesHeader(AContext: TPasElement);
+begin
+  DescrWriteLinebreak;
+  DescrBeginBold;
+  DescrWriteText(SDocNotes);
+  DescrEndBold;
+  DescrWriteLinebreak;
+end;
+
+procedure TFPDocWriter.DescrEmitNotesFooter(AContext: TPasElement);
+begin
+  DescrWriteLinebreak;
+end;
+
 
 Constructor TTopicElement.Create(const AName: String; AParent: TPasElement);
 

+ 1 - 1
utils/fpdoc/fpdoc.lpi

@@ -54,7 +54,7 @@
       <Unit2>
         <Filename Value="dw_dxml.pp"/>
         <IsPartOfProject Value="True"/>
-        <UnitName Value="dw_dxml"/>
+        <UnitName Value="dw_dXML"/>
       </Unit2>
       <Unit3>
         <Filename Value="dw_html.pp"/>

+ 5 - 0
utils/fpdoc/fpdoc.pp

@@ -16,6 +16,9 @@
 program FPDoc;
 
 uses
+{$ifdef unix}
+  cwstring,
+{$endif}
   SysUtils, Classes, Gettext, custapp,
   dGlobals,  // GLobal definitions, constants.
   dwriter,   // TFPDocWriter definition.
@@ -309,6 +312,8 @@ begin
       FCreator.Verbose:=true
     else if (Cmd = '-n') or (Cmd = '--dry-run') then
       FDryRun:=True
+    else if (Cmd = '-t') or (Cmd = '--emit-notes') then
+      FCreator.Options.EmitNotes := True
     else if Cmd = '--content' then
       SelectedPackage.ContentFile := Arg
     else if Cmd = '--import' then

+ 52 - 0
utils/fpdoc/fpdocproj.pas

@@ -50,6 +50,7 @@ Type
     FBackEndoptions: TStrings;
     FCPUTarget: String;
     FDefaultPackageName: String;
+    FEmitNotes: Boolean;
     FFormat: String;
     FHidePrivate: Boolean;
     FHideProtected: Boolean;
@@ -79,6 +80,7 @@ Type
     Property MoDir : String Read FMoDir Write FMODir;
     Property DefaultPackageName : String Read FDefaultPackageName Write FDefaultPackageName;
     Property DontTrim : Boolean Read FDontTrim Write FDontTrim;
+    Property EmitNotes : Boolean Read FEmitNotes Write FEmitNotes;
   end;
 
   { TFPDocProject }
@@ -96,8 +98,58 @@ Type
     Property Options : TEngineOptions Read FOptions Write setOptions;
   end;
 
+Procedure SplitInputFileOption(Const AInputFile : String; Out AFile,AOption : String);
+
 implementation
 
+Procedure SplitInputFileOption(Const AInputFile : String; Out AFile,AOption : String);
+
+  Function GetNextWord(Var s : string) : String;
+
+  Const
+    WhiteSpace = [' ',#9,#10,#13];
+
+  var
+    i,j: integer;
+
+  begin
+    I:=1;
+    While (I<=Length(S)) and (S[i] in WhiteSpace) do
+      Inc(I);
+    J:=I;
+    While (J<=Length(S)) and (not (S[J] in WhiteSpace)) do
+      Inc(J);
+    if (I<=Length(S)) then
+      Result:=Copy(S,I,J-I);
+    Delete(S,1,J);
+  end;
+
+Var
+  S,W,F,O : String;
+
+begin
+  S:=AInputFile;
+  O:='';
+  F:='';
+  While (S<>'') do
+    begin
+    W:=GetNextWord(S);
+    If (W<>'') then
+      begin
+      if W[1]='-' then
+        begin
+        if (O<>'') then
+          O:=O+' ';
+        o:=O+W;
+        end
+      else
+        F:=W;
+      end;
+    end;
+  AFile:=F;
+  AOption:=O;
+end;
+
 { TEngineOptions }
 
 procedure TEngineOptions.SetBackendOptions(const AValue: TStrings);

+ 7 - 42
utils/fpdoc/fpdocxmlopts.pas

@@ -34,12 +34,12 @@ Type
 Function IndexOfString(S : String; List : Array of string) : Integer;
 
 Const
-  OptionCount = 11;
+  OptionCount = 12;
   OptionNames : Array[0..OptionCount] of string
          = ('hide-protected','warn-no-node','show-private',
             'stop-on-parser-error', 'ostarget','cputarget',
             'mo-dir','parse-impl','format', 'language',
-            'package','dont-trim');
+            'package','dont-trim','emit-notes');
 
 implementation
 
@@ -216,6 +216,7 @@ begin
         9 : Options.Language:=v;
         10 : Options.DefaultPackageName:=V;
         11 : Options.DontTrim:=TrueValue(V);
+        12 : Options.EmitNotes:=TrueValue(V);
       else
         Options.BackendOptions.add('--'+n);
         Options.BackendOptions.add(v);
@@ -283,53 +284,17 @@ begin
   AddBool('stop-on-parser-error', Options.StopOnParseError);
   AddBool('parse-impl', Options.InterfaceOnly);
   AddBool('dont-trim', Options.DontTrim);
+  AddBool('emit-notes', Options.EmitNotes);
 end;
 
-Procedure TXMLFPDocOptions.SaveInputFile(Const AInputFile : String; XML : TXMLDocument; AParent: TDOMElement);
-
-  Function GetNextWord(Var s : string) : String;
-
-  Const
-    WhiteSpace = [' ',#9,#10,#13];
-
-  var
-    i,j: integer;
-
-  begin
-    I:=1;
-    While (I<=Length(S)) and (S[i] in WhiteSpace) do
-      Inc(I);
-    J:=I;
-    While (J<=Length(S)) and (not (S[J] in WhiteSpace)) do
-      Inc(J);
-    if (I<=Length(S)) then
-      Result:=Copy(S,I,J-I);
-    Delete(S,1,J);
-  end;
 
+Procedure TXMLFPDocOptions.SaveInputFile(Const AInputFile : String; XML : TXMLDocument; AParent: TDOMElement);
 
 Var
-  S,W,F,O : String;
+  F,O : String;
 
 begin
-  S:=AInputFile;
-  O:='';
-  F:='';
-  While (S<>'') do
-    begin
-    W:=GetNextWord(S);
-    If (W<>'') then
-      begin
-      if W[1]='-' then
-        begin
-        if (O<>'') then
-          O:=O+' ';
-        o:=O+W;
-        end
-      else
-        F:=W;
-      end;
-    end;
+  SplitInputFileOption(AInputFile,F,O);
   AParent['file']:=F;
   AParent['options']:=O;
 end;

+ 55 - 3
utils/fpdoc/mkfpdoc.pp

@@ -5,7 +5,7 @@ unit mkfpdoc;
 interface
 
 uses
-  Classes, SysUtils, dglobals, fpdocxmlopts, dwriter, pscanner, pparser, fpdocproj;
+  Classes, SysUtils, dglobals, DOM, fpdocxmlopts, dwriter, pscanner, pparser, fpdocproj;
 
 const
   DefOSTarget    = {$I %FPCTARGETOS%};
@@ -19,6 +19,8 @@ Type
 
   TFPDocCreator = Class(TComponent)
   Private
+    FCurPackage : TFPDocPackage;
+    FProcessedUnits : TStrings;
     FOnLog: TPasParserLogHandler;
     FPParserLogEvents: TPParserLogEvents;
     FProject : TFPDocProject;
@@ -27,6 +29,8 @@ Type
     function GetOptions: TEngineOptions;
     function GetPackages: TFPDocPackages;
   Protected
+    Procedure DoBeforeEmitNote(Sender : TObject; Note : TDomElement; Var EmitNote : Boolean); virtual;
+    procedure HandleOnParseUnit(Sender: TObject; const AUnitName: String; out AInputFile, OSTarget, CPUTarget: String);
     procedure SetVerbose(AValue: Boolean); virtual;
     Procedure DoLog(Const Msg : String);
     procedure DoLog(Const Fmt : String; Args : Array of Const);
@@ -45,11 +49,11 @@ Type
     // Easy access
     Property Options : TEngineOptions Read GetOptions;
     Property Packages : TFPDocPackages Read GetPackages;
-
   end;
 
 implementation
 
+
 { TFPDocCreator }
 
 procedure TFPDocCreator.SetVerbose(AValue: Boolean);
@@ -79,6 +83,36 @@ begin
   DoLog(Format(Fmt,Args));
 end;
 
+procedure TFPDocCreator.HandleOnParseUnit(Sender: TObject;
+  const AUnitName: String; out AInputFile, OSTarget, CPUTarget: String);
+
+Var
+  I : Integer;
+  S,un,opts : String;
+
+begin
+  AInputFile:='';
+  OSTarget:='';
+  CPUTarget:='';
+  if Assigned(FCurPackage) then
+    begin
+    I:=0;
+    While (AInputFIle='') and (I<FCurPackage.Inputs.Count) do
+       begin
+       S:=FCurPackage.Inputs[i];
+       SplitInputFIleOption(S,UN,Opts);
+       if CompareText(ChangeFileExt(ExtractFileName(Un),''),AUnitName)=0 then
+         begin
+         AInputFile:=S;
+         OSTarget:=FProject.Options.OSTarget;
+         CPUTarget:=FProject.Options.CPUTarget;
+         FProcessedUnits.Add(UN);
+         end;
+       Inc(I);
+       end;
+   end;
+end;
+
 function TFPDocCreator.GetOptions: TEngineOptions;
 begin
   Result:=FProject.Options;
@@ -89,6 +123,12 @@ begin
   Result:=FProject.Packages;
 end;
 
+procedure TFPDocCreator.DoBeforeEmitNote(Sender: TObject; Note: TDomElement;
+  var EmitNote: Boolean);
+begin
+  EmitNote:=True;
+end;
+
 constructor TFPDocCreator.Create(AOwner: TComponent);
 begin
   inherited Create(AOwner);
@@ -96,10 +136,12 @@ begin
   FProject.Options.StopOnParseError:=False;
   FProject.Options.CPUTarget:=DefCPUTarget;
   FProject.Options.OSTarget:=DefOSTarget;
+  FProcessedUnits:=TStringList.Create;
 end;
 
 destructor TFPDocCreator.Destroy;
 begin
+  FreeAndNil(FProcessedUnits);
   FreeAndNil(FProject);
   inherited Destroy;
 end;
@@ -120,6 +162,8 @@ begin
       If FVerbose then
         DoLog('Writing documentation');
       OnLog:=Self.OnLog;
+      BeforeEmitNote:[email protected];
+      EmitNotes:=Options.EmitNotes;
       If Options.BackendOptions.Count>0 then
         for I:=0 to ((Options.BackendOptions.Count-1) div 2) do
           begin
@@ -144,6 +188,7 @@ var
   Cmd,Arg : String;
 
 begin
+  FCurPackage:=APackage;
   Engine:=TFPDocEngine.Create;
   try
     For J:=0 to Apackage.Imports.Count-1 do
@@ -161,11 +206,17 @@ begin
     Engine.ParserLogEvents:=Self.ParserLogEvents;
     Engine.HideProtected:=Options.HideProtected;
     Engine.HidePrivate:=Not Options.ShowPrivate;
+    Engine.OnParseUnit:=@HandleOnParseUnit;
     if Length(Options.Language) > 0 then
       TranslateDocStrings(Options.Language);
     for i := 0 to APackage.Inputs.Count - 1 do
       try
-        ParseSource(Engine, APackage.Inputs[i], Options.OSTarget, Options.CPUTarget);
+        SplitInputFileOption(APackage.Inputs[i],Cmd,Arg);
+        if FProcessedUnits.IndexOf(Cmd)=-1 then
+          begin
+          FProcessedUnits.Add(Cmd);
+          ParseSource(Engine, APackage.Inputs[i], Options.OSTarget, Options.CPUTarget);
+          end;
       except
         on e: EParserError do
           If Options.StopOnParseError then
@@ -177,6 +228,7 @@ begin
       CreateOutput(APackage,Engine);
   finally
     FreeAndNil(Engine);
+    FCurPackage:=Nil;
   end;
 end;
 

+ 1 - 1
utils/fpdoc/testunit.pp

@@ -21,7 +21,7 @@ Type
   TAnEnumType         = (one,two,three);
   TASetType           = Set of TAnEnumType;
   TAnArrayType        = Array[1..10] of Integer;
-  TASubRangeType      = one..two;
+//  TASubRangeType      = one..two;
   TABooleanArrayType  = Array[Boolean] of Integer;  
   TARecordType        = Record
                          X,Y : Integer;

+ 19 - 0
utils/fpdoc/testunit.xml

@@ -12,6 +12,9 @@
 <short></short>
 <descr>
 </descr>
+<notes>
+  <note>Unit note</note>
+</notes>
 
 <!-- constant Visibility: default -->
 <element name="AnIntegerConst">
@@ -107,6 +110,9 @@ Appears in 2.0
 </version>
 <seealso>
 </seealso>
+<notes>
+<note>Type note 1</note>
+</notes>
 </element>
 
 <!-- enumeration value Visibility: default -->
@@ -427,6 +433,9 @@ Appears in 2.0
 </version>
 <seealso>
 </seealso>
+<notes>
+<note>Simpleproc note 1</note>
+</notes>
 </element>
 
 <!-- procedure Visibility: default -->
@@ -1013,6 +1022,9 @@ Appears in 2.0
 </errors>
 <seealso>
 </seealso>
+<notes>
+<note> this is class note 1</note>
+</notes>
 </element>
 
 <!-- procedure Visibility: public -->
@@ -1035,6 +1047,9 @@ Appears in 2.0
 </errors>
 <seealso>
 </seealso>
+<notes>
+<note> this is proc note 1</note>
+</notes>
 </element>
 
 <!-- property Visibility: published -->
@@ -1044,6 +1059,10 @@ Appears in 2.0
 </descr>
 <seealso>
 </seealso>
+<notes>
+<note> this is prop note 1</note>
+<note> this is prop note 2</note>
+</notes>
 </element>
 
 </module> <!-- testunit -->