* synchronized with trunk

git-svn-id: branches/wasm@48022 -
This commit is contained in:
nickysn 2021-01-04 02:57:44 +00:00
commit 052d1bc38a
51 changed files with 2311 additions and 1679 deletions

9
.gitattributes vendored
View File

@ -15229,6 +15229,10 @@ tests/test/tgenfunc20.pp svneol=native#text/pascal
tests/test/tgenfunc21.pp svneol=native#text/pascal tests/test/tgenfunc21.pp svneol=native#text/pascal
tests/test/tgenfunc22.pp svneol=native#text/pascal tests/test/tgenfunc22.pp svneol=native#text/pascal
tests/test/tgenfunc23.pp svneol=native#text/pascal tests/test/tgenfunc23.pp svneol=native#text/pascal
tests/test/tgenfunc24.pp svneol=native#text/pascal
tests/test/tgenfunc25.pp svneol=native#text/pascal
tests/test/tgenfunc26.pp svneol=native#text/pascal
tests/test/tgenfunc27.pp svneol=native#text/pascal
tests/test/tgenfunc3.pp svneol=native#text/pascal tests/test/tgenfunc3.pp svneol=native#text/pascal
tests/test/tgenfunc4.pp svneol=native#text/pascal tests/test/tgenfunc4.pp svneol=native#text/pascal
tests/test/tgenfunc5.pp svneol=native#text/pascal tests/test/tgenfunc5.pp svneol=native#text/pascal
@ -16745,6 +16749,8 @@ tests/webtbf/tw37476.pp svneol=native#text/pascal
tests/webtbf/tw37763.pp svneol=native#text/pascal tests/webtbf/tw37763.pp svneol=native#text/pascal
tests/webtbf/tw3790.pp svneol=native#text/plain tests/webtbf/tw3790.pp svneol=native#text/plain
tests/webtbf/tw3812.pp svneol=native#text/plain tests/webtbf/tw3812.pp svneol=native#text/plain
tests/webtbf/tw38289a.pp svneol=native#text/pascal
tests/webtbf/tw38289b.pp svneol=native#text/pascal
tests/webtbf/tw3930a.pp svneol=native#text/plain tests/webtbf/tw3930a.pp svneol=native#text/plain
tests/webtbf/tw3931b.pp svneol=native#text/plain tests/webtbf/tw3931b.pp svneol=native#text/plain
tests/webtbf/tw3969.pp svneol=native#text/plain tests/webtbf/tw3969.pp svneol=native#text/plain
@ -18672,6 +18678,8 @@ tests/webtbs/tw38267a.pp svneol=native#text/pascal
tests/webtbs/tw38267b.pp svneol=native#text/pascal tests/webtbs/tw38267b.pp svneol=native#text/pascal
tests/webtbs/tw3827.pp svneol=native#text/plain tests/webtbs/tw3827.pp svneol=native#text/plain
tests/webtbs/tw3829.pp svneol=native#text/plain tests/webtbs/tw3829.pp svneol=native#text/plain
tests/webtbs/tw38295.pp svneol=native#text/pascal
tests/webtbs/tw38299.pp svneol=native#text/pascal
tests/webtbs/tw3833.pp svneol=native#text/plain tests/webtbs/tw3833.pp svneol=native#text/plain
tests/webtbs/tw3840.pp svneol=native#text/plain tests/webtbs/tw3840.pp svneol=native#text/plain
tests/webtbs/tw3841.pp svneol=native#text/plain tests/webtbs/tw3841.pp svneol=native#text/plain
@ -19338,6 +19346,7 @@ utils/fpdoc/Makefile.fpc.fpcmake svneol=native#text/plain
utils/fpdoc/README.txt svneol=native#text/plain utils/fpdoc/README.txt svneol=native#text/plain
utils/fpdoc/css.inc svneol=native#text/plain utils/fpdoc/css.inc svneol=native#text/plain
utils/fpdoc/dglobals.pp svneol=native#text/plain utils/fpdoc/dglobals.pp svneol=native#text/plain
utils/fpdoc/dw_basehtml.pp svneol=native#text/plain
utils/fpdoc/dw_basemd.pp svneol=native#text/plain utils/fpdoc/dw_basemd.pp svneol=native#text/plain
utils/fpdoc/dw_chm.pp svneol=native#text/plain utils/fpdoc/dw_chm.pp svneol=native#text/plain
utils/fpdoc/dw_dxml.pp svneol=native#text/plain utils/fpdoc/dw_dxml.pp svneol=native#text/plain

View File

@ -480,6 +480,9 @@ implementation
begin begin
if tsym(p).typ = procsym then if tsym(p).typ = procsym then
begin begin
if (sp_generic_dummy in tsym(p).symoptions) and
(tprocsym(p).procdeflist.count=0) then
exit;
pd :=tprocdef(tprocsym(p).ProcdefList[0]); pd :=tprocdef(tprocsym(p).ProcdefList[0]);
if (po_virtualmethod in pd.procoptions) and if (po_virtualmethod in pd.procoptions) and
not is_objectpascal_helper(pd.struct) then not is_objectpascal_helper(pd.struct) then

View File

@ -536,12 +536,28 @@ implementation
function SwapLeftWithRightRight : tnode; function SwapLeftWithRightRight : tnode;
var var
hp: tnode; hp,hp2 : tnode;
begin begin
hp:=left; { keep the order of val+const else string operations might cause an error }
left:=taddnode(right).right; hp:=taddnode(right).right;
taddnode(right).right:=hp;
right:=right.simplify(false); taddnode(right).right:=taddnode(right).left;
taddnode(right).left:=left;
right.resultdef:=nil;
do_typecheckpass(right);
hp2:=right.simplify(forinline);
if assigned(hp2) then
right:=hp2;
if resultdef.typ<>pointerdef then
begin
{ ensure that the constant is not expanded to a larger type due to overflow,
but this is only useful if no pointer operation is done }
right:=ctypeconvnode.create_internal(right,resultdef);
do_typecheckpass(right);
end;
left:=right;
right:=hp;
result:=GetCopyAndTypeCheck; result:=GetCopyAndTypeCheck;
end; end;
@ -1207,23 +1223,7 @@ implementation
exit; exit;
end; end;
{ try to fold { set constant evaluation }
op
/ \
op const1
/ \
val const2
while operating on strings
}
if (cs_opt_level2 in current_settings.optimizerswitches) and (nodetype=addn) and ((rt=stringconstn) or is_constcharnode(right)) and (left.nodetype=nodetype) and
(compare_defs(resultdef,left.resultdef,nothingn)=te_exact) and ((taddnode(left).right.nodetype=stringconstn) or is_constcharnode(taddnode(left).right)) then
begin
Result:=SwapRightWithLeftLeft;
exit;
end;
{ set constant evaluation }
if (right.nodetype=setconstn) and if (right.nodetype=setconstn) and
not assigned(tsetconstnode(right).left) and not assigned(tsetconstnode(right).left) and
(left.nodetype=setconstn) and (left.nodetype=setconstn) and
@ -1381,9 +1381,44 @@ implementation
exit; exit;
end; end;
{ slow simplifications } { slow simplifications and/or more sophisticated transformations which might make debugging harder }
if cs_opt_level2 in current_settings.optimizerswitches then if cs_opt_level2 in current_settings.optimizerswitches then
begin begin
if nodetype=addn then
begin
{ try to fold
op
/ \
op const1
/ \
val const2
while operating on strings
}
if ((rt=stringconstn) or is_constcharnode(right)) and (left.nodetype=nodetype) and
(compare_defs(resultdef,left.resultdef,nothingn)=te_exact) and ((taddnode(left).right.nodetype=stringconstn) or is_constcharnode(taddnode(left).right)) then
begin
Result:=SwapRightWithLeftLeft;
exit;
end;
{ try to fold
op
/ \
const1 op
/ \
const2 val
while operating on strings
}
if ((lt=stringconstn) or is_constcharnode(left)) and (right.nodetype=nodetype) and
(compare_defs(resultdef,right.resultdef,nothingn)=te_exact) and ((taddnode(right).left.nodetype=stringconstn) or is_constcharnode(taddnode(right).left)) then
begin
Result:=SwapLeftWithRightRight;
exit;
end;
end;
{ the comparison is might be expensive and the nodes are usually only { the comparison is might be expensive and the nodes are usually only
equal if some previous optimizations were done so don't check equal if some previous optimizations were done so don't check
this simplification always this simplification always

View File

@ -1066,7 +1066,8 @@ implementation
end end
else if (srsym.typ=typesym) and else if (srsym.typ=typesym) and
(sp_generic_dummy in srsym.symoptions) and (sp_generic_dummy in srsym.symoptions) and
(ttypesym(srsym).typedef.typ=undefineddef) then (ttypesym(srsym).typedef.typ=undefineddef) and
not assigned(genericparams) then
begin begin
{ this is a generic dummy symbol that has not yet { this is a generic dummy symbol that has not yet
been used; so we rename the dummy symbol and continue been used; so we rename the dummy symbol and continue
@ -1162,13 +1163,26 @@ implementation
end; end;
if not assigned(dummysym) then if not assigned(dummysym) then
begin begin
dummysym:=ctypesym.create(orgspnongen,cundefineddef.create(true)); { overloading generic routines with non-generic types is not
allowed, so we create a procsym as dummy }
dummysym:=cprocsym.create(orgspnongen);
if assigned(astruct) then if assigned(astruct) then
astruct.symtable.insert(dummysym) astruct.symtable.insert(dummysym)
else else
symtablestack.top.insert(dummysym); symtablestack.top.insert(dummysym);
end
else if (dummysym.typ<>procsym) and
(
{ show error only for the declaration, not also the implementation }
not assigned(astruct) or
(symtablestack.top.symtablelevel<>main_program_level)
) then
Message1(sym_e_duplicate_id,dummysym.realname);
if not (sp_generic_dummy in dummysym.symoptions) then
begin
include(dummysym.symoptions,sp_generic_dummy);
add_generic_dummysym(dummysym);
end; end;
include(dummysym.symoptions,sp_generic_dummy);
{ start token recorder for the declaration } { start token recorder for the declaration }
pd.init_genericdecl; pd.init_genericdecl;
current_scanner.startrecordtokens(pd.genericdecltokenbuf); current_scanner.startrecordtokens(pd.genericdecltokenbuf);

View File

@ -149,7 +149,7 @@ implementation
else else
begin begin
index:=0; index:=0;
consume(_INTCONST); message(type_e_ordinal_expr_expected);
end; end;
include(options,eo_index); include(options,eo_index);
pt.free; pt.free;
@ -166,7 +166,7 @@ implementation
else if is_constcharnode(pt) then else if is_constcharnode(pt) then
hpname:=chr(tordconstnode(pt).value.svalue and $ff) hpname:=chr(tordconstnode(pt).value.svalue and $ff)
else else
consume(_CSTRING); message(type_e_string_expr_expected);
include(options,eo_name); include(options,eo_name);
pt.free; pt.free;
DefString:=hpname+'='+InternalProcName; DefString:=hpname+'='+InternalProcName;

View File

@ -1514,13 +1514,15 @@ implementation
begin begin
if srsym.typ=typesym then if srsym.typ=typesym then
spezdef:=ttypesym(srsym).typedef spezdef:=ttypesym(srsym).typedef
else if tprocsym(srsym).procdeflist.count>0 then
spezdef:=tdef(tprocsym(srsym).procdeflist[0])
else else
spezdef:=tdef(tprocsym(srsym).procdeflist[0]); spezdef:=nil;
if (spezdef.typ=errordef) and (sp_generic_dummy in srsym.symoptions) then if (not assigned(spezdef) or (spezdef.typ=errordef)) and (sp_generic_dummy in srsym.symoptions) then
symname:=srsym.RealName symname:=srsym.RealName
else else
symname:=''; symname:='';
spezdef:=generate_specialization_phase1(spezcontext,spezdef,symname); spezdef:=generate_specialization_phase1(spezcontext,spezdef,symname,srsym.owner);
case spezdef.typ of case spezdef.typ of
errordef: errordef:
begin begin
@ -2994,7 +2996,7 @@ implementation
begin begin
{$push} {$push}
{$warn 5036 off} {$warn 5036 off}
hdef:=generate_specialization_phase1(spezcontext,nil,nil,orgstoredpattern,dummypos); hdef:=generate_specialization_phase1(spezcontext,nil,nil,orgstoredpattern,nil,dummypos);
{$pop} {$pop}
if hdef=generrordef then if hdef=generrordef then
begin begin
@ -3048,12 +3050,20 @@ implementation
wasgenericdummy:=false; wasgenericdummy:=false;
if assigned(srsym) and if assigned(srsym) and
(sp_generic_dummy in srsym.symoptions) and (sp_generic_dummy in srsym.symoptions) and
(srsym.typ=typesym) and (srsym.typ in [procsym,typesym]) and
( (
( (
(m_delphi in current_settings.modeswitches) and (m_delphi in current_settings.modeswitches) and
not (token in [_LT, _LSHARPBRACKET]) and not (token in [_LT, _LSHARPBRACKET]) and
(ttypesym(srsym).typedef.typ=undefineddef) (
(
(srsym.typ=typesym) and
(ttypesym(srsym).typedef.typ=undefineddef)
) or (
(srsym.typ=procsym) and
(tprocsym(srsym).procdeflist.count=0)
)
)
) )
or or
( (
@ -3306,8 +3316,14 @@ implementation
procsym : procsym :
begin begin
p1:=nil; p1:=nil;
if (m_delphi in current_settings.modeswitches) and
(sp_generic_dummy in srsym.symoptions) and
(token in [_LT,_LSHARPBRACKET]) then
begin
p1:=cspecializenode.create(nil,getaddr,srsym)
end
{ check if it's a method/class method } { check if it's a method/class method }
if is_member_read(srsym,srsymtable,p1,hdef) then else if is_member_read(srsym,srsymtable,p1,hdef) then
begin begin
{ if we are accessing a owner procsym from the nested } { if we are accessing a owner procsym from the nested }
{ class we need to call it as a class member } { class we need to call it as a class member }
@ -3558,17 +3574,20 @@ implementation
(block_type=bt_body) and (block_type=bt_body) and
(token in [_LT,_LSHARPBRACKET]) then (token in [_LT,_LSHARPBRACKET]) then
begin begin
if p1.nodetype=typen then idstr:='';
idstr:=ttypenode(p1).typesym.name case p1.nodetype of
else typen:
if (p1.nodetype=loadvmtaddrn) and idstr:=ttypenode(p1).typesym.name;
(tloadvmtaddrnode(p1).left.nodetype=typen) then loadvmtaddrn:
idstr:=ttypenode(tloadvmtaddrnode(p1).left).typesym.name if tloadvmtaddrnode(p1).left.nodetype=typen then
idstr:=ttypenode(tloadvmtaddrnode(p1).left).typesym.name;
loadn:
idstr:=tloadnode(p1).symtableentry.name;
calln:
idstr:=tcallnode(p1).symtableprocentry.name;
else else
if (p1.nodetype=loadn) then ;
idstr:=tloadnode(p1).symtableentry.name end;
else
idstr:='';
{ if this is the case then the postfix handling is done in { if this is the case then the postfix handling is done in
sub_expr if necessary } sub_expr if necessary }
dopostfix:=not could_be_generic(idstr); dopostfix:=not could_be_generic(idstr);
@ -4211,7 +4230,8 @@ implementation
typesym: typesym:
result:=ttypesym(sym).typedef; result:=ttypesym(sym).typedef;
procsym: procsym:
result:=tdef(tprocsym(sym).procdeflist[0]); if not (sp_generic_dummy in sym.symoptions) or (tprocsym(sym).procdeflist.count>0) then
result:=tdef(tprocsym(sym).procdeflist[0]);
else else
internalerror(2015092701); internalerror(2015092701);
end; end;
@ -4230,6 +4250,8 @@ implementation
loadn: loadn:
if not searchsym_with_symoption(tloadnode(n).symtableentry.Name,srsym,srsymtable,sp_generic_dummy) then if not searchsym_with_symoption(tloadnode(n).symtableentry.Name,srsym,srsymtable,sp_generic_dummy) then
srsym:=nil; srsym:=nil;
calln:
srsym:=tcallnode(n).symtableprocentry;
specializen: specializen:
srsym:=tspecializenode(n).sym; srsym:=tspecializenode(n).sym;
{ TODO : handle const nodes } { TODO : handle const nodes }
@ -4264,7 +4286,7 @@ implementation
end; end;
if assigned(parseddef) and assigned(gensym) and assigned(p2) then if assigned(parseddef) and assigned(gensym) and assigned(p2) then
gendef:=generate_specialization_phase1(spezcontext,gendef,parseddef,gensym.realname,p2.fileinfo) gendef:=generate_specialization_phase1(spezcontext,gendef,parseddef,gensym.realname,gensym.owner,p2.fileinfo)
else else
gendef:=generate_specialization_phase1(spezcontext,gendef); gendef:=generate_specialization_phase1(spezcontext,gendef);
case gendef.typ of case gendef.typ of

View File

@ -39,8 +39,8 @@ uses
procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string;parsedtype:tdef;symname:string;parsedpos:tfileposinfo);inline; procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string;parsedtype:tdef;symname:string;parsedpos:tfileposinfo);inline;
procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string);inline; procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string);inline;
function generate_specialization_phase1(out context:tspecializationcontext;genericdef:tdef):tdef;inline; function generate_specialization_phase1(out context:tspecializationcontext;genericdef:tdef):tdef;inline;
function generate_specialization_phase1(out context:tspecializationcontext;genericdef:tdef;symname:string):tdef;inline; function generate_specialization_phase1(out context:tspecializationcontext;genericdef:tdef;symname:string;symtable:tsymtable):tdef;inline;
function generate_specialization_phase1(out context:tspecializationcontext;genericdef:tdef;parsedtype:tdef;symname:string;parsedpos:tfileposinfo):tdef; function generate_specialization_phase1(out context:tspecializationcontext;genericdef:tdef;parsedtype:tdef;symname:string;symtable:tsymtable;parsedpos:tfileposinfo):tdef;
function generate_specialization_phase2(context:tspecializationcontext;genericdef:tstoreddef;parse_class_parent:boolean;_prettyname:ansistring):tdef; function generate_specialization_phase2(context:tspecializationcontext;genericdef:tstoreddef;parse_class_parent:boolean;_prettyname:ansistring):tdef;
function check_generic_constraints(genericdef:tstoreddef;paramlist:tfpobjectlist;poslist:tfplist):boolean; function check_generic_constraints(genericdef:tstoreddef;paramlist:tfpobjectlist;poslist:tfplist):boolean;
function parse_generic_parameters(allowconstraints:boolean):tfphashobjectlist; function parse_generic_parameters(allowconstraints:boolean):tfphashobjectlist;
@ -613,23 +613,23 @@ uses
{$push} {$push}
{$warn 5036 off} {$warn 5036 off}
begin begin
result:=generate_specialization_phase1(context,genericdef,nil,'',dummypos); result:=generate_specialization_phase1(context,genericdef,nil,'',nil,dummypos);
end; end;
{$pop} {$pop}
function generate_specialization_phase1(out context:tspecializationcontext;genericdef:tdef;symname:string):tdef; function generate_specialization_phase1(out context:tspecializationcontext;genericdef:tdef;symname:string;symtable:tsymtable):tdef;
var var
dummypos : tfileposinfo; dummypos : tfileposinfo;
{$push} {$push}
{$warn 5036 off} {$warn 5036 off}
begin begin
result:=generate_specialization_phase1(context,genericdef,nil,symname,dummypos); result:=generate_specialization_phase1(context,genericdef,nil,symname,symtable,dummypos);
end; end;
{$pop} {$pop}
function generate_specialization_phase1(out context:tspecializationcontext;genericdef:tdef;parsedtype:tdef;symname:string;parsedpos:tfileposinfo):tdef; function generate_specialization_phase1(out context:tspecializationcontext;genericdef:tdef;parsedtype:tdef;symname:string;symtable:tsymtable;parsedpos:tfileposinfo):tdef;
var var
found, found,
err : boolean; err : boolean;
@ -637,6 +637,7 @@ uses
gencount : longint; gencount : longint;
countstr,genname,ugenname : string; countstr,genname,ugenname : string;
tmpstack : tfpobjectlist; tmpstack : tfpobjectlist;
symowner : tsymtable;
begin begin
context:=nil; context:=nil;
result:=nil; result:=nil;
@ -741,12 +742,17 @@ uses
context.genname:=genname; context.genname:=genname;
if assigned(genericdef) and (genericdef.owner.symtabletype in [objectsymtable,recordsymtable]) then if assigned(genericdef) then
symowner:=genericdef.owner
else
symowner:=symtable;
if assigned(symowner) and (symowner.symtabletype in [objectsymtable,recordsymtable]) then
begin begin
if genericdef.owner.symtabletype = objectsymtable then if symowner.symtabletype = objectsymtable then
found:=searchsym_in_class(tobjectdef(genericdef.owner.defowner),tobjectdef(genericdef.owner.defowner),ugenname,context.sym,context.symtable,[]) found:=searchsym_in_class(tobjectdef(symowner.defowner),tobjectdef(symowner.defowner),ugenname,context.sym,context.symtable,[])
else else
found:=searchsym_in_record(tabstractrecorddef(genericdef.owner.defowner),ugenname,context.sym,context.symtable); found:=searchsym_in_record(tabstractrecorddef(symowner.defowner),ugenname,context.sym,context.symtable);
if not found then if not found then
found:=searchsym(ugenname,context.sym,context.symtable); found:=searchsym(ugenname,context.sym,context.symtable);
end end
@ -1350,7 +1356,7 @@ uses
context : tspecializationcontext; context : tspecializationcontext;
genericdef : tstoreddef; genericdef : tstoreddef;
begin begin
genericdef:=tstoreddef(generate_specialization_phase1(context,tt,parsedtype,symname,parsedpos)); genericdef:=tstoreddef(generate_specialization_phase1(context,tt,parsedtype,symname,nil,parsedpos));
if genericdef<>generrordef then if genericdef<>generrordef then
genericdef:=tstoreddef(generate_specialization_phase2(context,genericdef,parse_class_parent,_prettyname)); genericdef:=tstoreddef(generate_specialization_phase2(context,genericdef,parse_class_parent,_prettyname));
tt:=genericdef; tt:=genericdef;
@ -1790,8 +1796,7 @@ uses
if not searchsym_with_flags(sym.name,srsym,srsymtable,[ssf_no_addsymref]) then if not searchsym_with_flags(sym.name,srsym,srsymtable,[ssf_no_addsymref]) then
srsym:=nil; srsym:=nil;
end end
else if (sym.typ=procsym) and else if sym.typ=procsym then
(tprocsym(sym).procdeflist.count>0) then
srsym:=sym srsym:=sym
else else
{ dummy symbol is already not so dummy anymore } { dummy symbol is already not so dummy anymore }

View File

@ -3374,6 +3374,8 @@ implementation
exit; exit;
end; end;
end; end;
if (tprocsym(sym).procdeflist.count=0) and (sp_generic_dummy in tprocsym(sym).symoptions) then
result:=is_visible_for_object(sym.owner,sym.visibility,contextobjdef);
end end
else else
result:=is_visible_for_object(sym.owner,sym.visibility,contextobjdef); result:=is_visible_for_object(sym.owner,sym.visibility,contextobjdef);
@ -4254,6 +4256,14 @@ implementation
result:=true; result:=true;
exit; exit;
end; end;
if (sp_generic_dummy in tprocsym(srsym).symoptions) and
(tprocsym(srsym).procdeflist.count=0) and
is_visible_for_object(srsym.owner,srsym.visibility,contextclassh) then
begin
srsymtable:=srsym.owner;
result:=true;
exit;
end;
end; end;
typesym, typesym,
fieldvarsym, fieldvarsym,

View File

@ -1223,7 +1223,9 @@ implementation
{ only one memory operand is allowed } { only one memory operand is allowed }
gotmem:=false; gotmem:=false;
memop:=0; memop:=0;
for i:=1 to 3 do { in case parameters come on the FPU stack, we have to pop them in reverse order as we
called secondpass }
for i:=3 downto 1 do
begin begin
if not(paraarray[i].location.loc in [LOC_MMREGISTER,LOC_CMMREGISTER]) then if not(paraarray[i].location.loc in [LOC_MMREGISTER,LOC_CMMREGISTER]) then
begin begin

View File

@ -208,6 +208,7 @@ const
nClassTypesAreNotRelatedXY = 3142; nClassTypesAreNotRelatedXY = 3142;
nDirectiveXNotAllowedHere = 3143; nDirectiveXNotAllowedHere = 3143;
nAwaitWithoutPromise = 3144; nAwaitWithoutPromise = 3144;
nSymbolCannotExportedFromALibrary = 3145;
// using same IDs as FPC // using same IDs as FPC
nVirtualMethodXHasLowerVisibility = 3250; // was 3050 nVirtualMethodXHasLowerVisibility = 3250; // was 3050
@ -363,6 +364,7 @@ resourcestring
sClassTypesAreNotRelatedXY = 'Class types "%s" and "%s" are not related'; sClassTypesAreNotRelatedXY = 'Class types "%s" and "%s" are not related';
sDirectiveXNotAllowedHere = 'Directive "%s" not allowed here'; sDirectiveXNotAllowedHere = 'Directive "%s" not allowed here';
sAwaitWithoutPromise = 'Await without promise'; sAwaitWithoutPromise = 'Await without promise';
sSymbolCannotExportedFromALibrary = 'The symbol cannot be exported from a library';
type type
{ TResolveData - base class for data stored in TPasElement.CustomData } { TResolveData - base class for data stored in TPasElement.CustomData }

View File

@ -1612,6 +1612,7 @@ type
procedure AddClassType(El: TPasClassType; TypeParams: TFPList); virtual; procedure AddClassType(El: TPasClassType; TypeParams: TFPList); virtual;
procedure AddVariable(El: TPasVariable); virtual; procedure AddVariable(El: TPasVariable); virtual;
procedure AddResourceString(El: TPasResString); virtual; procedure AddResourceString(El: TPasResString); virtual;
procedure AddExportSymbol(El: TPasExportSymbol); virtual;
procedure AddEnumType(El: TPasEnumType); virtual; procedure AddEnumType(El: TPasEnumType); virtual;
procedure AddEnumValue(El: TPasEnumValue); virtual; procedure AddEnumValue(El: TPasEnumValue); virtual;
procedure AddProperty(El: TPasProperty); virtual; procedure AddProperty(El: TPasProperty); virtual;
@ -9139,7 +9140,7 @@ end;
procedure TPasResolver.FinishExportSymbol(El: TPasExportSymbol); procedure TPasResolver.FinishExportSymbol(El: TPasExportSymbol);
procedure CheckExpExpr(Expr: TPasExpr; Kinds: TREVKinds; const Expected: string); procedure CheckConstExpr(Expr: TPasExpr; Kinds: TREVKinds; const Expected: string);
var var
Value: TResEvalValue; Value: TResEvalValue;
ResolvedEl: TPasResolverResult; ResolvedEl: TPasResolverResult;
@ -9157,9 +9158,40 @@ procedure TPasResolver.FinishExportSymbol(El: TPasExportSymbol);
RaiseXExpectedButYFound(20210101194628,Expected,GetTypeDescription(ResolvedEl),Expr); RaiseXExpectedButYFound(20210101194628,Expected,GetTypeDescription(ResolvedEl),Expr);
end; end;
var
Expr: TPasExpr;
DeclEl: TPasElement;
FindData: TPRFindData;
Ref: TResolvedReference;
ResolvedEl: TPasResolverResult;
begin begin
CheckExpExpr(El.ExportIndex,[revkInt,revkUInt],'integer'); Expr:=El.NameExpr;
CheckExpExpr(El.ExportName,[revkString,revkUnicodeString],'string'); if Expr<>nil then
begin
ResolveExpr(Expr,rraRead);
//ResolveGlobalSymbol(Expr);
ComputeElement(Expr,ResolvedEl,[rcConstant]);
DeclEl:=ResolvedEl.IdentEl;
if DeclEl=nil then
RaiseMsg(20210103012907,nXExpectedButYFound,sXExpectedButYFound,['symbol',GetTypeDescription(ResolvedEl)],Expr);
if not (DeclEl.Parent is TPasSection) then
RaiseMsg(20210103012908,nXExpectedButYFound,sXExpectedButYFound,['global symbol',GetElementTypeName(DeclEl)],Expr);
end
else
begin
FindFirstEl(El.Name,FindData,El);
DeclEl:=FindData.Found;
if DeclEl=nil then
RaiseMsg(20210103002747,nIdentifierNotFound,sIdentifierNotFound,[El.Name],El);
if not (DeclEl.Parent is TPasSection) then
RaiseMsg(20210103003244,nXExpectedButYFound,sXExpectedButYFound,['global symbol',GetObjPath(DeclEl)],El);
Ref:=CreateReference(DeclEl,El,rraRead,@FindData);
CheckFoundElement(FindData,Ref);
end;
// check index and name
CheckConstExpr(El.ExportIndex,[revkInt,revkUInt],'integer');
CheckConstExpr(El.ExportName,[revkString,revkUnicodeString],'string');
end; end;
procedure TPasResolver.FinishProcParamAccess(ProcType: TPasProcedureType; procedure TPasResolver.FinishProcParamAccess(ProcType: TPasProcedureType;
@ -10276,7 +10308,7 @@ begin
if ProcNeedsParams(Proc.ProcType) and not ExprIsAddrTarget(El) then if ProcNeedsParams(Proc.ProcType) and not ExprIsAddrTarget(El) then
begin begin
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
writeln('TPasResolver.ResolveNameExpr ',GetObjName(El)); writeln('TPasResolver.ResolveNameExpr ',GetObjPath(El));
{$ENDIF} {$ENDIF}
RaiseMsg(20170216152138,nWrongNumberOfParametersForCallTo, RaiseMsg(20170216152138,nWrongNumberOfParametersForCallTo,
sWrongNumberOfParametersForCallTo,[Proc.Name],El); sWrongNumberOfParametersForCallTo,[Proc.Name],El);
@ -12205,6 +12237,14 @@ begin
AddIdentifier(TPasIdentifierScope(TopScope),El.Name,El,pikSimple); AddIdentifier(TPasIdentifierScope(TopScope),El.Name,El,pikSimple);
end; end;
procedure TPasResolver.AddExportSymbol(El: TPasExportSymbol);
begin
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.AddExportSymbol ',GetObjName(El));
{$ENDIF}
// Note: export symbol is not added to scope
end;
procedure TPasResolver.AddEnumType(El: TPasEnumType); procedure TPasResolver.AddEnumType(El: TPasEnumType);
var var
CanonicalSet: TPasSetType; CanonicalSet: TPasSetType;
@ -17452,6 +17492,8 @@ begin
AddProcedureType(TPasProcedureType(SpecEl),nil); AddProcedureType(TPasProcedureType(SpecEl),nil);
SpecializeProcedureType(TPasProcedureType(GenEl),TPasProcedureType(SpecEl),nil); SpecializeProcedureType(TPasProcedureType(GenEl),TPasProcedureType(SpecEl),nil);
end end
else if C=TPasExportSymbol then
RaiseMsg(20210101234958,nSymbolCannotExportedFromALibrary,sSymbolCannotExportedFromALibrary,[],GenEl)
else else
RaiseNotYetImplemented(20190728151215,GenEl); RaiseNotYetImplemented(20190728151215,GenEl);
end; end;
@ -20866,6 +20908,7 @@ begin
// resolved when finished // resolved when finished
else if AClass=TPasAttributes then else if AClass=TPasAttributes then
else if AClass=TPasExportSymbol then else if AClass=TPasExportSymbol then
AddExportSymbol(TPasExportSymbol(El))
else if AClass=TPasUnresolvedUnitRef then else if AClass=TPasUnresolvedUnitRef then
RaiseMsg(20171018121900,nCantFindUnitX,sCantFindUnitX,[AName],El) RaiseMsg(20171018121900,nCantFindUnitX,sCantFindUnitX,[AName],El)
else else
@ -28209,10 +28252,12 @@ function TPasResolver.ExprIsAddrTarget(El: TPasExpr): boolean;
e.g. '@p().o[].El' or '@El[]' e.g. '@p().o[].El' or '@El[]'
b) mode delphi: the last element of a right side of an assignment b) mode delphi: the last element of a right side of an assignment
c) an accessor function, e.g. property P read El; c) an accessor function, e.g. property P read El;
d) an export
} }
var var
Parent: TPasElement; Parent: TPasElement;
Prop: TPasProperty; Prop: TPasProperty;
C: TClass;
begin begin
Result:=false; Result:=false;
if El=nil then exit; if El=nil then exit;
@ -28221,31 +28266,34 @@ begin
repeat repeat
Parent:=El.Parent; Parent:=El.Parent;
//writeln('TPasResolver.ExprIsAddrTarget El=',GetObjName(El),' Parent=',GetObjName(Parent)); //writeln('TPasResolver.ExprIsAddrTarget El=',GetObjName(El),' Parent=',GetObjName(Parent));
if Parent.ClassType=TUnaryExpr then C:=Parent.ClassType;
if C=TUnaryExpr then
begin begin
if TUnaryExpr(Parent).OpCode=eopAddress then exit(true); if TUnaryExpr(Parent).OpCode=eopAddress then exit(true);
end end
else if Parent.ClassType=TBinaryExpr then else if C=TBinaryExpr then
begin begin
if TBinaryExpr(Parent).right<>El then exit; if TBinaryExpr(Parent).right<>El then exit;
if TBinaryExpr(Parent).OpCode<>eopSubIdent then exit; if TBinaryExpr(Parent).OpCode<>eopSubIdent then exit;
end end
else if Parent.ClassType=TParamsExpr then else if C=TParamsExpr then
begin begin
if TParamsExpr(Parent).Value<>El then exit; if TParamsExpr(Parent).Value<>El then exit;
end end
else if Parent.ClassType=TPasProperty then else if C=TPasProperty then
begin begin
Prop:=TPasProperty(Parent); Prop:=TPasProperty(Parent);
Result:=(Prop.ReadAccessor=El) or (Prop.WriteAccessor=El) or (Prop.StoredAccessor=El); Result:=(Prop.ReadAccessor=El) or (Prop.WriteAccessor=El) or (Prop.StoredAccessor=El);
exit; exit;
end end
else if Parent.ClassType=TPasImplAssign then else if C=TPasImplAssign then
begin begin
if TPasImplAssign(Parent).right<>El then exit; if TPasImplAssign(Parent).right<>El then exit;
if (msDelphi in CurrentParser.CurrentModeswitches) then exit(true); if (msDelphi in CurrentParser.CurrentModeswitches) then exit(true);
exit; exit;
end end
else if C=TPasExportSymbol then
exit(true)
else else
exit; exit;
El:=TPasExpr(Parent); El:=TPasExpr(Parent);

View File

@ -975,6 +975,7 @@ type
TPasExportSymbol = class(TPasElement) TPasExportSymbol = class(TPasElement)
public public
NameExpr: TPasExpr; // only if name is not a simple identifier
ExportName : TPasExpr; ExportName : TPasExpr;
ExportIndex : TPasExpr; ExportIndex : TPasExpr;
Destructor Destroy; override; Destructor Destroy; override;
@ -2601,6 +2602,7 @@ end;
destructor TPasExportSymbol.Destroy; destructor TPasExportSymbol.Destroy;
begin begin
ReleaseAndNil(TPasElement(NameExpr){$IFDEF CheckPasTreeRefCount},'TPasExportSymbol.NameExpr'{$ENDIF});
ReleaseAndNil(TPasElement(ExportName){$IFDEF CheckPasTreeRefCount},'TPasExportSymbol.ExportName'{$ENDIF}); ReleaseAndNil(TPasElement(ExportName){$IFDEF CheckPasTreeRefCount},'TPasExportSymbol.ExportName'{$ENDIF});
ReleaseAndNil(TPasElement(ExportIndex){$IFDEF CheckPasTreeRefCount},'TPasExportSymbol.ExportIndex'{$ENDIF}); ReleaseAndNil(TPasElement(ExportIndex){$IFDEF CheckPasTreeRefCount},'TPasExportSymbol.ExportIndex'{$ENDIF});
inherited Destroy; inherited Destroy;
@ -2624,6 +2626,7 @@ procedure TPasExportSymbol.ForEachCall(const aMethodCall: TOnForEachPasElement;
const Arg: Pointer); const Arg: Pointer);
begin begin
inherited ForEachCall(aMethodCall, Arg); inherited ForEachCall(aMethodCall, Arg);
ForEachChildCall(aMethodCall,Arg,NameExpr,false);
ForEachChildCall(aMethodCall,Arg,ExportName,false); ForEachChildCall(aMethodCall,Arg,ExportName,false);
ForEachChildCall(aMethodCall,Arg,ExportIndex,false); ForEachChildCall(aMethodCall,Arg,ExportIndex,false);
end; end;

View File

@ -4341,27 +4341,43 @@ end;
procedure TPasParser.ParseExportDecl(Parent: TPasElement; List: TFPList); procedure TPasParser.ParseExportDecl(Parent: TPasElement; List: TFPList);
Var Var
E : TPasExportSymbol; E : TPasExportSymbol;
aName: String;
NameExpr: TPasExpr;
begin begin
Repeat try
if List.Count<>0 then Repeat
ExpectIdentifier; if List.Count>0 then
E:=TPasExportSymbol(CreateElement(TPasExportSymbol,CurtokenString,Parent)); ExpectIdentifier;
List.Add(E); aName:=ReadDottedIdentifier(Parent,NameExpr,true);
NextToken; E:=TPasExportSymbol(CreateElement(TPasExportSymbol,aName,Parent));
if CurTokenIsIdentifier('INDEX') then if NameExpr.Kind=pekIdent then
begin // simple identifier -> no need to store NameExpr
NextToken; NameExpr.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF}
E.Exportindex:=DoParseExpression(E,Nil) else
end begin
else if CurTokenIsIdentifier('NAME') then E.NameExpr:=NameExpr;
begin NameExpr.Parent:=E;
NextToken; end;
E.ExportName:=DoParseExpression(E,Nil) NameExpr:=nil;
end; List.Add(E);
if not (CurToken in [tkComma,tkSemicolon]) then if CurTokenIsIdentifier('INDEX') then
ParseExc(nParserExpectedCommaSemicolon,SParserExpectedCommaSemicolon); begin
Engine.FinishScope(stDeclaration,E); NextToken;
until (CurToken=tkSemicolon); 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(nParserExpectedCommaSemicolon,SParserExpectedCommaSemicolon);
Engine.FinishScope(stDeclaration,E);
until (CurToken=tkSemicolon);
finally
if NameExpr<>nil then
NameExpr.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF}
end;
end; end;
function TPasParser.ParseProcedureType(Parent: TPasElement; function TPasParser.ParseProcedureType(Parent: TPasElement;

View File

@ -986,6 +986,7 @@ type
Procedure TestLibrary_ExportFunc_IndexStringFail; Procedure TestLibrary_ExportFunc_IndexStringFail;
Procedure TestLibrary_ExportVar; // ToDo Procedure TestLibrary_ExportVar; // ToDo
Procedure TestLibrary_Initialization_Finalization; Procedure TestLibrary_Initialization_Finalization;
Procedure TestLibrary_ExportFuncOverloadFail; // ToDo
// ToDo Procedure TestLibrary_UnitExports; // ToDo Procedure TestLibrary_UnitExports;
end; end;
@ -18833,6 +18834,25 @@ begin
ParseLibrary; ParseLibrary;
end; end;
procedure TTestResolver.TestLibrary_ExportFuncOverloadFail;
begin
exit;
StartLibrary(false);
Add([
'procedure Run(w: word); overload;',
'begin',
'end;',
'procedure Run(d: double); overload;',
'begin',
'end;',
'exports',
' Run,',
' afile.run;',
'begin']);
CheckResolverException('The symbol cannot be exported from a library',123);
end;
initialization initialization
RegisterTests([TTestResolver]); RegisterTests([TTestResolver]);

View File

@ -4430,6 +4430,7 @@ procedure TPCUWriter.WriteExportSymbol(Obj: TJSONObject; El: TPasExportSymbol;
aContext: TPCUWriterContext); aContext: TPCUWriterContext);
begin begin
WritePasElement(Obj,El,aContext); WritePasElement(Obj,El,aContext);
WriteExpr(Obj,El,'NameExpr',El.NameExpr,aContext);
WriteExpr(Obj,El,'ExportName',El.ExportName,aContext); WriteExpr(Obj,El,'ExportName',El.ExportName,aContext);
WriteExpr(Obj,El,'ExportIndex',El.ExportIndex,aContext); WriteExpr(Obj,El,'ExportIndex',El.ExportIndex,aContext);
end; end;
@ -9256,6 +9257,7 @@ procedure TPCUReader.ReadExportSymbol(Obj: TJSONObject; El: TPasExportSymbol;
aContext: TPCUReaderContext); aContext: TPCUReaderContext);
begin begin
ReadPasElement(Obj,El,aContext); ReadPasElement(Obj,El,aContext);
El.NameExpr:=ReadExpr(Obj,El,'NameExpr',aContext);
El.ExportName:=ReadExpr(Obj,El,'ExportName',aContext); El.ExportName:=ReadExpr(Obj,El,'ExportName',aContext);
El.ExportIndex:=ReadExpr(Obj,El,'ExportIndex',aContext); El.ExportIndex:=ReadExpr(Obj,El,'ExportIndex',aContext);
end; end;

View File

@ -1935,6 +1935,7 @@ end;
procedure TCustomTestPrecompile.CheckRestoredExportSymbol(const Path: string; procedure TCustomTestPrecompile.CheckRestoredExportSymbol(const Path: string;
Orig, Rest: TPasExportSymbol; Flags: TPCCheckFlags); Orig, Rest: TPasExportSymbol; Flags: TPCCheckFlags);
begin begin
CheckRestoredElement(Path+'.NameExpr',Orig.NameExpr,Rest.NameExpr,Flags);
CheckRestoredElement(Path+'.ExportName',Orig.ExportName,Rest.ExportName,Flags); CheckRestoredElement(Path+'.ExportName',Orig.ExportName,Rest.ExportName,Flags);
CheckRestoredElement(Path+'.ExportIndex',Orig.ExportIndex,Rest.ExportIndex,Flags); CheckRestoredElement(Path+'.ExportIndex',Orig.ExportIndex,Rest.ExportIndex,Flags);
end; end;

View File

@ -1,3 +1,17 @@
{
This file is part of the Free Pascal run time library.
Copyright (C) 2020 Michael Van Canneyt
member of the Free Pascal development team.
Nullable generic type.
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
}
unit nullable; unit nullable;
{$mode objfpc} {$mode objfpc}

View File

@ -51,7 +51,7 @@ function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
rm2bits: array[TFPURoundingMode] of byte = (0,2,1,3); rm2bits: array[TFPURoundingMode] of byte = (0,2,1,3);
begin begin
softfloat_rounding_mode:=RoundMode; softfloat_rounding_mode:=RoundMode;
SetRoundMode:=RoundMode; SetRoundMode:=GetRoundMode;
setfpcr((getfpcr and $ff3fffff) or (rm2bits[RoundMode] shl 22)); setfpcr((getfpcr and $ff3fffff) or (rm2bits[RoundMode] shl 22));
end; end;

View File

@ -62,9 +62,10 @@ function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
var var
c: dword; c: dword;
begin begin
softfloat_rounding_mode:=RoundMode;
Reslut:=GetRoundMode;
c:=Ord(RoundMode) shl 16; c:=Ord(RoundMode) shl 16;
c:=_controlfp(c, _MCW_RC); c:=_controlfp(c, _MCW_RC);
Result:=TFPURoundingMode((c shr 16) and 3);
end; end;
function GetPrecisionMode: TFPUPrecisionMode; function GetPrecisionMode: TFPUPrecisionMode;

View File

@ -147,6 +147,7 @@ function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
var var
CtlWord: Word; CtlWord: Word;
begin begin
softfloat_rounding_mode:=RoundMode;
CtlWord := Get8087CW; CtlWord := Get8087CW;
Set8087CW((CtlWord and $F3FF) or (Ord(RoundMode) shl 10)); Set8087CW((CtlWord and $F3FF) or (Ord(RoundMode) shl 10));
if has_sse_support then if has_sse_support then

View File

@ -155,6 +155,7 @@ function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
var var
CtlWord: Word; CtlWord: Word;
begin begin
softfloat_rounding_mode:=RoundMode;
CtlWord := Get8087CW; CtlWord := Get8087CW;
Set8087CW((CtlWord and $F3FF) or (Ord(RoundMode) shl 10)); Set8087CW((CtlWord and $F3FF) or (Ord(RoundMode) shl 10));
{ if has_sse_support then { if has_sse_support then

View File

@ -137,10 +137,10 @@ const
var var
FPCR: DWord; FPCR: DWord;
begin begin
Result:=GetRoundMode;
FPCR:=GetFPCR and not FPU68K_ROUND_MASK; FPCR:=GetFPCR and not FPU68K_ROUND_MASK;
SetFPCR(FPCR or FPCToFPURoundingMode[RoundMode]); SetFPCR(FPCR or FPCToFPURoundingMode[RoundMode]);
softfloat_rounding_mode:=RoundMode; softfloat_rounding_mode:=RoundMode;
Result:=RoundMode;
end; end;
function GetPrecisionMode: TFPUPrecisionMode; function GetPrecisionMode: TFPUPrecisionMode;

View File

@ -62,6 +62,7 @@ function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
begin begin
fsr:=get_fsr; fsr:=get_fsr;
result:=fsr2roundmode[fsr and fpu_rounding_mask]; result:=fsr2roundmode[fsr and fpu_rounding_mask];
softfloat_rounding_mode:=RoundMode;
set_fsr((fsr and not fpu_rounding_mask) or roundmode2fsr[RoundMode]); set_fsr((fsr and not fpu_rounding_mask) or roundmode2fsr[RoundMode]);
end; end;

View File

@ -101,12 +101,12 @@ begin
mode := FP_RND_RM; mode := FP_RND_RM;
end; end;
end; end;
result := GetRoundMode;
{$ifndef aix} {$ifndef aix}
setFPSCR((getFPSCR and (not RoundModeMask)) or mode); setFPSCR((getFPSCR and (not RoundModeMask)) or mode);
{$else not aix} {$else not aix}
fp_swap_rnd(mode); fp_swap_rnd(mode);
{$endif not aix} {$endif not aix}
result := RoundMode;
end; end;

View File

@ -109,12 +109,12 @@ begin
mode := FP_RND_RM; mode := FP_RND_RM;
end; end;
end; end;
result := GetRoundMode;
{$ifndef aix} {$ifndef aix}
setFPSCR((getFPSCR and (not RoundModeMask)) or mode); setFPSCR((getFPSCR and (not RoundModeMask)) or mode);
{$else not aix} {$else not aix}
fp_swap_rnd(mode); fp_swap_rnd(mode);
{$endif not aix} {$endif not aix}
result := RoundMode;
end; end;

View File

@ -50,7 +50,7 @@ function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
rm2bits : array[TFPURoundingMode] of byte = (0,2,3,1); rm2bits : array[TFPURoundingMode] of byte = (0,2,3,1);
begin begin
softfloat_rounding_mode:=RoundMode; softfloat_rounding_mode:=RoundMode;
SetRoundMode:=RoundMode; SetRoundMode:=GetRoundMode;
setrm(rm2bits[RoundMode]); setrm(rm2bits[RoundMode]);
end; end;

View File

@ -32,6 +32,7 @@ function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
cw: dword; cw: dword;
begin begin
cw:=get_fsr; cw:=get_fsr;
softfloat_rounding_mode:=RoundMode;
result:=TFPURoundingMode(cw shr 30); result:=TFPURoundingMode(cw shr 30);
set_fsr((cw and $3fffffff) or (rm2bits[RoundMode] shl 30)); set_fsr((cw and $3fffffff) or (rm2bits[RoundMode] shl 30));
end; end;

View File

@ -31,6 +31,7 @@ function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
cw: dword; cw: dword;
begin begin
cw:=get_fsr; cw:=get_fsr;
softfloat_rounding_mode:=RoundMode;
result:=TFPURoundingMode(cw shr 30); result:=TFPURoundingMode(cw shr 30);
set_fsr((cw and $3fffffff) or (rm2bits[RoundMode] shl 30)); set_fsr((cw and $3fffffff) or (rm2bits[RoundMode] shl 30));
end; end;

View File

@ -609,6 +609,14 @@ procedure Win32Ansi2UnicodeMove(source:pchar;cp : TSystemCodePage;var dest:Unico
dwFlags:=MB_PRECOMPOSED; dwFlags:=MB_PRECOMPOSED;
end; end;
destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0); destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
{ destlen=0 means that Windows cannot convert, so call the default
handler. This is similiar to what unix does and is a good fallback
if rawbyte strings are passed }
if destlen=0 then
begin
DefaultAnsi2UnicodeMove(source,DefaultSystemCodePage,dest,len);
exit;
end;
// this will null-terminate // this will null-terminate
setlength(dest, destlen); setlength(dest, destlen);
if destlen>0 then if destlen>0 then

View File

@ -201,6 +201,7 @@ var
begin begin
CtlWord:=Get8087CW; CtlWord:=Get8087CW;
SSECSR:=GetMXCSR; SSECSR:=GetMXCSR;
softfloat_rounding_mode:=RoundMode;
Set8087CW((CtlWord and $F3FF) or (Ord(RoundMode) shl 10)); Set8087CW((CtlWord and $F3FF) or (Ord(RoundMode) shl 10));
SetMXCSR((SSECSR and $ffff9fff) or (dword(RoundMode) shl 13)); SetMXCSR((SSECSR and $ffff9fff) or (dword(RoundMode) shl 13));
{$ifdef FPC_HAS_TYPE_EXTENDED} {$ifdef FPC_HAS_TYPE_EXTENDED}

View File

@ -20,6 +20,7 @@ function GetRoundMode: TFPURoundingMode;
function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode; function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
begin begin
SetRoundMode:=softfloat_rounding_mode;
softfloat_rounding_mode:=RoundMode; softfloat_rounding_mode:=RoundMode;
end; end;

25
tests/test/tgenfunc24.pp Normal file
View File

@ -0,0 +1,25 @@
{ %FAIL }
program tgenfunc24;
{$mode delphi}
type
TTest = class
public type
Test = class
end;
public
procedure Test<T>;
end;
procedure TTest.Test<T>;
begin
end;
begin
end.

24
tests/test/tgenfunc25.pp Normal file
View File

@ -0,0 +1,24 @@
{ %FAIL }
program tgenfunc25;
{$mode delphi}
type
TTest = class
public
procedure Test<T>;
public type
Test = class
end;
end;
procedure TTest.Test<T>;
begin
end;
begin
end.

24
tests/test/tgenfunc26.pp Normal file
View File

@ -0,0 +1,24 @@
{ %FAIL }
unit tgenfunc26;
{$mode objfpc}{$H+}
interface
generic procedure Test<T>;
type
Test = record
end;
implementation
generic procedure Test<T>;
begin
end;
end.

24
tests/test/tgenfunc27.pp Normal file
View File

@ -0,0 +1,24 @@
{ %FAIL }
unit tgenfunc27;
{$mode objfpc}{$H+}
interface
type
Test = record
end;
generic procedure Test<T>;
implementation
generic procedure Test<T>;
begin
end;
end.

View File

@ -1,13 +1,34 @@
uses uses
Math; Math;
const
failure_count : longint = 0;
first_error : longint = 0;
{$ifndef SKIP_CURRENCY_TEST} {$ifndef SKIP_CURRENCY_TEST}
procedure testround(const c, expected: currency; error: longint); procedure testround(const c, expected: currency; error: longint);
begin begin
if round(c)<>expected then if round(c)<>expected then
begin begin
writeln('round(',c,') = ',round(c),' instead of ', expected); writeln('round(',c,') = ',round(c),' instead of ', expected);
halt(error); inc(failure_count);
if first_error=0 then
first_error:=error;
end;
end;
{$endif}
{$ifndef SKIP_SINGLE_TEST}
procedure testroundsingle(const c, expected: single; error: longint);
begin
if round(c)<>expected then
begin
writeln('round(',c,') = ',round(c),' instead of ', expected);
inc(failure_count);
if first_error=0 then
first_error:=error;
end; end;
end; end;
@ -16,6 +37,13 @@ end;
begin begin
{$ifndef SKIP_CURRENCY_TEST} {$ifndef SKIP_CURRENCY_TEST}
if GetRoundMode <> rmNearest then
begin
writeln('Starting rounding mode is not rmNearest');
inc(failure_count);
if first_error=0 then
first_error:=200;
end;
writeln('Rounding mode: rmNearest (even)'); writeln('Rounding mode: rmNearest (even)');
testround(0.5,0.0,1); testround(0.5,0.0,1);
testround(1.5,2.0,2); testround(1.5,2.0,2);
@ -31,7 +59,15 @@ begin
testround(-1.4,-1.0,154); testround(-1.4,-1.0,154);
writeln('Rounding mode: rmUp'); writeln('Rounding mode: rmUp');
SetRoundMode(rmUp); if SetRoundMode(rmUp)<>rmNearest then
writeln('Warning: previous mode was not rmNearest');
if GetRoundMode <> rmUp then
begin
writeln('Failed to set rounding mode to rmUp');
inc(failure_count);
if first_error=0 then
first_error:=201;
end;
testround(0.5,1.0,5); testround(0.5,1.0,5);
testround(1.5,2.0,6); testround(1.5,2.0,6);
testround(-0.5,0.0,7); testround(-0.5,0.0,7);
@ -46,7 +82,15 @@ begin
testround(-1.4,-1.0,158); testround(-1.4,-1.0,158);
writeln('Rounding mode: rmDown'); writeln('Rounding mode: rmDown');
SetRoundMode(rmDown); if SetRoundMode(rmDown)<>rmUp then
writeln('Warning: previous mode was not rmUp');
if GetRoundMode <> rmDown then
begin
writeln('Failed to set rounding mode to rmDown');
inc(failure_count);
if first_error=0 then
first_error:=202;
end;
testround(0.5,0.0,9); testround(0.5,0.0,9);
testround(1.5,1.0,10); testround(1.5,1.0,10);
testround(-0.5,-1.0,11); testround(-0.5,-1.0,11);
@ -61,7 +105,15 @@ begin
testround(-1.4,-2.0,162); testround(-1.4,-2.0,162);
writeln('Rounding mode: rmTruncate'); writeln('Rounding mode: rmTruncate');
SetRoundMode(rmTruncate); if SetRoundMode(rmTruncate)<>rmDown then
writeln('Warning: previous mode was not rmDown');
if GetRoundMode <> rmTruncate then
begin
writeln('Failed to set rounding mode to rmTruncate');
inc(failure_count);
if first_error=0 then
first_error:=203;
end;
testround(0.5,0.0,13); testround(0.5,0.0,13);
testround(1.5,1.0,14); testround(1.5,1.0,14);
testround(-0.5,0.0,15); testround(-0.5,0.0,15);
@ -75,4 +127,100 @@ begin
testround(-0.4,0.0,165); testround(-0.4,0.0,165);
testround(-1.4,-1.0,166); testround(-1.4,-1.0,166);
{$endif} {$endif}
{$ifndef SKIP_SINGLE_TEST}
SetRoundMode(rmNearest);
if GetRoundMode <> rmNearest then
begin
writeln('Starting rounding mode is not rmNearest');
inc(failure_count);
if first_error=0 then
first_error:=200;
end;
writeln('Rounding mode: rmNearest (even)');
testroundsingle(0.5,0.0,1);
testroundsingle(1.5,2.0,2);
testroundsingle(-0.5,0.0,3);
testroundsingle(-1.5,-2.0,4);
testroundsingle(0.6,1.0,101);
testroundsingle(1.6,2.0,102);
testroundsingle(-0.6,-1.0,103);
testroundsingle(-1.6,-2.0,104);
testroundsingle(0.4,0.0,151);
testroundsingle(1.4,1.0,152);
testroundsingle(-0.4,-0.0,153);
testroundsingle(-1.4,-1.0,154);
writeln('Rounding mode: rmUp');
if SetRoundMode(rmUp)<>rmNearest then
writeln('Warning: previous mode was not rmNearest');
if GetRoundMode <> rmUp then
begin
writeln('Failed to set rounding mode to rmUp');
inc(failure_count);
if first_error=0 then
first_error:=201;
end;
testroundsingle(0.5,1.0,5);
testroundsingle(1.5,2.0,6);
testroundsingle(-0.5,0.0,7);
testroundsingle(-1.5,-1.0,8);
testroundsingle(0.6,1.0,105);
testroundsingle(1.6,2.0,106);
testroundsingle(-0.6,0.0,107);
testroundsingle(-1.6,-1.0,108);
testroundsingle(0.4,1.0,155);
testroundsingle(1.4,2.0,156);
testroundsingle(-0.4,0.0,157);
testroundsingle(-1.4,-1.0,158);
writeln('Rounding mode: rmDown');
if SetRoundMode(rmDown)<>rmUp then
writeln('Warning: previous mode was not rmUp');
if GetRoundMode <> rmDown then
begin
writeln('Failed to set rounding mode to rmDown');
inc(failure_count);
if first_error=0 then
first_error:=202;
end;
testroundsingle(0.5,0.0,9);
testroundsingle(1.5,1.0,10);
testroundsingle(-0.5,-1.0,11);
testroundsingle(-1.5,-2.0,12);
testroundsingle(0.6,0.0,109);
testroundsingle(1.6,1.0,110);
testroundsingle(-0.6,-1.0,111);
testroundsingle(-1.6,-2.0,112);
testroundsingle(0.4,0.0,159);
testroundsingle(1.4,1.0,160);
testroundsingle(-0.4,-1.0,161);
testroundsingle(-1.4,-2.0,162);
writeln('Rounding mode: rmTruncate');
if SetRoundMode(rmTruncate)<>rmDown then
writeln('Warning: previous mode was not rmDown');
if GetRoundMode <> rmTruncate then
begin
writeln('Failed to set rounding mode to rmTruncate');
inc(failure_count);
if first_error=0 then
first_error:=203;
end;
testroundsingle(0.5,0.0,13);
testroundsingle(1.5,1.0,14);
testroundsingle(-0.5,0.0,15);
testroundsingle(-1.5,-1.0,16);
testroundsingle(0.6,0.0,113);
testroundsingle(1.6,1.0,114);
testroundsingle(-0.6,0.0,115);
testroundsingle(-1.6,-1.0,116);
testroundsingle(0.4,0.0,163);
testroundsingle(1.4,1.0,164);
testroundsingle(-0.4,0.0,165);
testroundsingle(-1.4,-1.0,166);
{$endif}
if failure_count=0 then
writeln('SetRoundMode test finished OK')
else
halt(first_error);
end. end.

8
tests/webtbf/tw38289a.pp Normal file
View File

@ -0,0 +1,8 @@
{ %FAIL }
library tw38289a;
procedure Test; begin end;
exports
Test index 3 'abc';
//------------^^^
end.

8
tests/webtbf/tw38289b.pp Normal file
View File

@ -0,0 +1,8 @@
{ %FAIL }
library tw38289b;
procedure Test; begin end;
exports
Test index 'abc' 3;
//------------^^^
end.

View File

@ -1,6 +1,6 @@
{ %opt=-O3 -Sg } { %opt=-O3 -Sg }
{$mode objfpc} {$longstrings+} {$mode objfpc} {$longstrings+}
label start1, end1, start2, end2, start3, end3; label start1, end1, start2, end2, start3, end3, start4, end4;
var var
s: string; s: string;
@ -88,5 +88,34 @@ end3:
if PtrUint(CodePointer(@end3) - CodePointer(@start3))>300 then if PtrUint(CodePointer(@end3) - CodePointer(@start3))>300 then
halt(3); halt(3);
writeln; writeln;
writeln('31 literals concatenated with 1 dynamic string, they could fold but didn''t at all:');
start4:
s := 'Once like a Great House' + (LineEnding +
('founded on sand,' + (LineEnding +
('Stood our Temple' + (LineEnding +
('whose pillars on troubles were based.' + (LineEnding +
('Now mischievous spirits, bound,' + (LineEnding +
('in dim corners stand,' + (LineEnding +
('Rotted columns, but' + (LineEnding +
('with iron-bound bands embraced' + (LineEnding +
('Cracked, crumbling marble,' + (LineEnding +
('tempered on every hand,' + (LineEnding +
('By strong steel' + (LineEnding +
('forged in fire and faith.' + (LineEnding +
('Shackled, these wayward servants' + (LineEnding +
('serve the land,' + (LineEnding +
('The Temple secured' + (LineEnding +
('by the Builders grace.' +
Copy('', 1, 0)))))))))))))))))))))))))))))));
end4:
writeln(Copy(s, 1, 0), PtrUint(CodePointer(@end4) - CodePointer(@start4)), ' b of code');
{ more than 100 bytes of code might point out that the constants are not folded,
example x86_64-linux: not folded: 1384 bytes; folded: 108 bytes
}
if PtrUint(CodePointer(@end4) - CodePointer(@start4))>300 then
halt(4);
writeln('ok'); writeln('ok');
end. end.

19
tests/webtbs/tw38295.pp Normal file
View File

@ -0,0 +1,19 @@
{ %cpu=i386 }
{ %opt=-CfAVX -CpCOREAVX2 -OoFASTMATH }
uses
cpu;
var
a, b: uint32; // or (u)int64; int32 works
r: single; // or double, or even extended
begin
if FMASupport then
begin
a := 1;
b := 3;
r := a + b / 10;
writeln(r:0:3);
if r>2.0 then
halt(1);
writeln('ok');
end;
end.

15
tests/webtbs/tw38299.pp Normal file
View File

@ -0,0 +1,15 @@
{ %opt=-O2 -Fcutf8 }
program bug;
const
cAnsiLineFeed = AnsiChar(#10);
cAnsiCarriageReturn = AnsiChar(#13);
var
test: RawByteString;
begin
test := '123';
test := test + UTF8Encode('456') + '789' + cAnsiCarriageReturn + cAnsiLineFeed;
writeln(test);
if test<>'123456789'#13#10 then
halt(1);
writeln('ok');
end.

View File

@ -139,7 +139,7 @@ resourcestring
SHTMLIndexColcount = 'Use N columns in the identifier index pages'; SHTMLIndexColcount = 'Use N columns in the identifier index pages';
SHTMLImageUrl = 'Prefix image URLs with url'; SHTMLImageUrl = 'Prefix image URLs with url';
SHTMLDisableMenuBrackets = 'Disable ''['' and '']'' characters around menu items at the top of the page. Useful for custom css'; SHTMLDisableMenuBrackets = 'Disable ''['' and '']'' characters around menu items at the top of the page. Useful for custom css';
// CHM usage // CHM usage
SCHMUsageTOC = 'Use [File] as the table of contents. Usually a .hhc file.'; SCHMUsageTOC = 'Use [File] as the table of contents. Usually a .hhc file.';
SCHMUsageIndex = 'Use [File] as the index. Usually a .hhk file.'; SCHMUsageIndex = 'Use [File] as the index. Usually a .hhk file.';
@ -151,6 +151,18 @@ resourcestring
SCHMUsageMakeSearch = 'Automatically generate a Search Index from filenames that match *.htm*'; SCHMUsageMakeSearch = 'Automatically generate a Search Index from filenames that match *.htm*';
SCHMUsageChmTitle= 'Title of the chm. Defaults to the value from --package'; SCHMUsageChmTitle= 'Title of the chm. Defaults to the value from --package';
// MarkDown usage
SMDUsageFooter = 'Append markdown (@filename reads from file) as footer to every markdown page';
SMDUsageHeader = 'Prepend markdown (@filename reads from file) as header to every markdown page';
SMDIndexColcount = 'Use N columns in the identifier index pages';
SMDImageUrl = 'Prefix image URLs with url';
SMDTheme = 'Use name as theme name';
SMDNavigation = 'Use scheme for navigation tree, here scheme is one of:';
SMDNavSubtree = ' UnitSubTree : put all units in a sub tree of a Units node';
SMDNavTree = ' UnitTree : put every units as a node on the same level as packages node';
SXMLUsageSource = 'Include source file and line info in generated XML'; SXMLUsageSource = 'Include source file and line info in generated XML';
// Linear usage // Linear usage

1060
utils/fpdoc/dw_basehtml.pp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,16 @@
{
FPDoc - Free Pascal Documentation Tool
Copyright (C) 2021 by Michael Van Canneyt
* Basic Markdown output generator. No assumptions about document/documentation structure
See the file COPYING, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
}
unit dw_basemd; unit dw_basemd;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
@ -32,7 +45,6 @@ Type
FFileRendering: TRender; FFileRendering: TRender;
FIndentSize: Byte; FIndentSize: Byte;
FKeywordRendering: TRender; FKeywordRendering: TRender;
FModule: TPasModule;
FPrefix : string; FPrefix : string;
FMetadata, FMetadata,
FMarkDown: TStrings; FMarkDown: TStrings;
@ -486,7 +498,7 @@ end;
procedure TBaseMarkdownWriter.DescrWriteImageEl(const AFileName, ACaption, ALinkName : DOMString); procedure TBaseMarkdownWriter.DescrWriteImageEl(const AFileName, ACaption, ALinkName : DOMString);
Var Var
D,FN : String; aLink,D,FN : String;
L : integer; L : integer;
begin begin
// Determine URL for image. // Determine URL for image.
@ -498,15 +510,16 @@ begin
If (L>0) and (D[L]<>'/') then If (L>0) and (D[L]<>'/') then
D:=D+'/'; D:=D+'/';
FN:=UTF8Decode(D + BaseImageURL) + AFileName; FN:=D + BaseImageURL+ Utf8Encode(AFileName);
EnsureEmptyLine; EnsureEmptyLine;
AppendToLine('!['+aCaption+']('+FN+')',False); aLink:='!['+UTF8Encode(aCaption)+']('+FN+')';
AppendToLine(aLink,False);
end; end;
procedure TBaseMarkdownWriter.DescrWriteFileEl(const AText: DOMString); procedure TBaseMarkdownWriter.DescrWriteFileEl(const AText: DOMString);
begin begin
AppendRendered(aText,FileRendering); AppendRendered(UTF8Encode(aText),FileRendering);
end; end;
procedure TBaseMarkdownWriter.DescrWriteKeywordEl(const AText: DOMString); procedure TBaseMarkdownWriter.DescrWriteKeywordEl(const AText: DOMString);
@ -516,7 +529,7 @@ end;
procedure TBaseMarkdownWriter.DescrWriteVarEl(const AText: DOMString); procedure TBaseMarkdownWriter.DescrWriteVarEl(const AText: DOMString);
begin begin
AppendRendered(aText,VarRendering); AppendRendered(UTF8Encode(aText),VarRendering);
end; end;
procedure TBaseMarkdownWriter.DescrBeginLink(const AId: DOMString); procedure TBaseMarkdownWriter.DescrBeginLink(const AId: DOMString);
@ -556,7 +569,7 @@ end;
procedure TBaseMarkdownWriter.DescrBeginURL(const AURL: DOMString); procedure TBaseMarkdownWriter.DescrBeginURL(const AURL: DOMString);
begin begin
FLink:=aURL; FLink:=UTF8Encode(aURL);
AppendToLine('['); AppendToLine('[');
end; end;

View File

@ -2,7 +2,7 @@ unit dw_chm;
interface interface
uses Classes, DOM, DOM_HTML, uses Classes, DOM,
dGlobals, PasTree, dwriter, dw_html, chmwriter, chmtypes, chmsitemap; dGlobals, PasTree, dwriter, dw_html, chmwriter, chmtypes, chmsitemap;
type type
@ -63,7 +63,7 @@ type
implementation implementation
uses SysUtils, HTMWrite; uses SysUtils, HTMWrite, dw_basehtml;
{ TCHmFileNameAllocator } { TCHmFileNameAllocator }
@ -152,11 +152,18 @@ end;
procedure TFpDocChmWriter.FileAdded ( AStream: TStream; procedure TFpDocChmWriter.FileAdded ( AStream: TStream;
const AEntry: TFileEntryRec ) ; const AEntry: TFileEntryRec ) ;
var FTsave : boolean;
begin begin
// Exclude Full text index for files starting from the dot // Exclude Full text index for files starting from the dot
if Pos('.', AEntry.Name) <> 1 then if Pos('.', AEntry.Name) <> 1 then
inherited FileAdded(AStream, AEntry); inherited FileAdded(AStream, AEntry)
else
begin
FTsave:=FullTextSearch;
FullTextSearch:=False;
inherited FileAdded(AStream, AEntry);
FullTextSearch:=FTsave;
end;
end; end;
{ TCHMHTMLWriter } { TCHMHTMLWriter }
@ -179,12 +186,12 @@ begin
DoLog('Note: --index-page not assigned. Using default "index.html"'); DoLog('Note: --index-page not assigned. Using default "index.html"');
end; end;
if FCSSFile <> '' then if CSSFile <> '' then
begin begin
if not FileExists(FCSSFile) Then if not FileExists(CSSFile) Then
Raise Exception.CreateFmt('Can''t find CSS file "%S"',[FCSSFILE]); Raise Exception.CreateFmt('Can''t find CSS file "%S"',[CSSFILE]);
TempStream := TMemoryStream.Create; TempStream := TMemoryStream.Create;
TempStream.LoadFromFile(FCSSFile); TempStream.LoadFromFile(CSSFile);
TempStream.Position := 0; TempStream.Position := 0;
FChm.AddStreamToArchive('fpdoc.css', '/', TempStream, True); FChm.AddStreamToArchive('fpdoc.css', '/', TempStream, True);
TempStream.Free; TempStream.Free;

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,8 @@
{ {
FPDoc - Free Pascal Documentation Tool FPDoc - Free Pascal Documentation Tool
Copyright (C) 2000 - 2005 by Copyright (C) 2021 by Michael Van Canneyt
Areca Systems GmbH / Sebastian Guenther, sg@freepascal.org
* HTML/XHTML output generator * Markdown generator, multi-file
See the file COPYING, included in this distribution, See the file COPYING, included in this distribution,
for details about the copyright. for details about the copyright.
@ -1909,13 +1908,19 @@ end;
class procedure TMarkdownWriter.Usage(List: TStrings); class procedure TMarkdownWriter.Usage(List: TStrings);
begin begin
List.add('--header=file'); List.add('--header=file');
List.Add(SHTMLUsageHeader); List.Add(SMDUsageHeader);
List.add('--footer=file'); List.add('--footer=file');
List.Add(SHTMLUsageFooter); List.Add(SMDUsageFooter);
List.Add('--index-colcount=N'); List.Add('--index-colcount=N');
List.Add(SHTMLIndexColcount); List.Add(SMDIndexColcount);
List.Add('--image-url=url'); List.Add('--image-url=url');
List.Add(SHTMLImageUrl); List.Add(SMDImageUrl);
List.Add('--theme=name');
List.Add(SMDTheme);
List.Add('--navigation=scheme');
List.Add(SMDNavigation);
List.Add(SMDNavSubtree);
List.Add(SMDNavTree);
end; end;
class procedure TMarkdownWriter.SplitImport(var AFilename, ALinkPrefix: String); class procedure TMarkdownWriter.SplitImport(var AFilename, ALinkPrefix: String);

View File

@ -186,10 +186,12 @@ type
procedure DescrEndTableRow; virtual; abstract; procedure DescrEndTableRow; virtual; abstract;
procedure DescrBeginTableCell; virtual; abstract; procedure DescrBeginTableCell; virtual; abstract;
procedure DescrEndTableCell; virtual; abstract; procedure DescrEndTableCell; virtual; abstract;
Property CurrentContext : TPasElement Read FContext ; Property CurrentContext : TPasElement Read FContext ;
public public
Constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); virtual; Constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); virtual;
destructor Destroy; override; destructor Destroy; override;
procedure AddModuleIdentifiers(AModule: TPasModule; L: TStrings);
property Engine : TFPDocEngine read FEngine; property Engine : TFPDocEngine read FEngine;
Property Package : TPasPackage read FPackage; Property Package : TPasPackage read FPackage;
Property Topics : TList Read FTopics; Property Topics : TList Read FTopics;
@ -526,6 +528,7 @@ begin
and (AModule.InterfaceSection.Classes.Count>0); and (AModule.InterfaceSection.Classes.Count>0);
end; end;
procedure TMultiFileDocWriter.AddPages(AElement: TPasElement; ASubpageIndex: Integer; procedure TMultiFileDocWriter.AddPages(AElement: TPasElement; ASubpageIndex: Integer;
AList: TFPList); AList: TFPList);
var var
@ -1028,6 +1031,22 @@ begin
Inherited; Inherited;
end; end;
procedure TFPDocWriter.AddModuleIdentifiers(AModule : TPasModule; L : TStrings);
begin
if assigned(AModule.InterfaceSection) Then
begin
AddElementsFromList(L,AModule.InterfaceSection.Consts);
AddElementsFromList(L,AModule.InterfaceSection.Types);
AddElementsFromList(L,AModule.InterfaceSection.Functions);
AddElementsFromList(L,AModule.InterfaceSection.Classes);
AddElementsFromList(L,AModule.InterfaceSection.Variables);
AddElementsFromList(L,AModule.InterfaceSection.ResStrings);
end;
end;
function TFPDocWriter.InterpretOption(const Cmd, Arg: String): Boolean; function TFPDocWriter.InterpretOption(const Cmd, Arg: String): Boolean;
begin begin
Result:=False; Result:=False;

View File

@ -46,7 +46,7 @@
<PackageName Value="FCL"/> <PackageName Value="FCL"/>
</Item1> </Item1>
</RequiredPackages> </RequiredPackages>
<Units Count="19"> <Units Count="20">
<Unit0> <Unit0>
<Filename Value="fpdoc.pp"/> <Filename Value="fpdoc.pp"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
@ -130,6 +130,10 @@
<Filename Value="dw_basemd.pp"/> <Filename Value="dw_basemd.pp"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit18> </Unit18>
<Unit19>
<Filename Value="dw_basehtml.pp"/>
<IsPartOfProject Value="True"/>
</Unit19>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

View File

@ -37,7 +37,7 @@ uses
dw_man, // Man page writer dw_man, // Man page writer
dw_linrtf, // linear RTF writer dw_linrtf, // linear RTF writer
dw_txt, // TXT writer dw_txt, // TXT writer
fpdocproj, mkfpdoc, dw_basemd; fpdocproj, mkfpdoc, dw_basemd, dw_basehtml;
Type Type

View File

@ -5,7 +5,7 @@ unit fpdocclasstree;
interface interface
uses uses
Classes, SysUtils, dGlobals, pastree, contnrs, DOM ,XMLWrite; Classes, SysUtils, dGlobals, pastree, contnrs{$IFDEF TREE_TEST}, DOM ,XMLWrite{$ENDIF};
Type Type