pasresolver.pp 76 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535
  1. {
  2. This file is part of the Free Component Library
  3. Pascal source parser
  4. Copyright (c) 2000-2005 by
  5. Areca Systems GmbH / Sebastian Guenther, [email protected]
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************
  12. Abstract:
  13. Resolves references by setting TPasElement.CustomData as TResolvedReference.
  14. Creates search scopes for elements with sub identifiers by setting
  15. TPasElement.CustomData as TPasScope: unit, program, library, interface,
  16. implementation, procs
  17. Works:
  18. - built-in types as TPasUnresolvedSymbolRef: longint, int64, string, pointer, ...
  19. - references in statements, error if not found
  20. - interface and implementation types, vars, const
  21. - params, local types, vars, const
  22. - nested procedures
  23. - search in used units
  24. - unitname.identifier
  25. - alias types, 'type a=b'
  26. - type alias type 'type a=type b'
  27. - choose the compatible overloaded procedure
  28. - while do
  29. - repeat until
  30. - if then else
  31. - binary operators
  32. - case of
  33. - try..finally..except, on, else, raise
  34. - for loop
  35. - spot duplicates
  36. ToDo:
  37. - records - TPasRecordType,
  38. - variant - TPasVariant
  39. - const TRecordValues
  40. - check if types only refer types
  41. - nested forward procs, nested must be resolved before proc body
  42. - program/library/implementation forward procs
  43. - check if constant is longint or int64
  44. - built-in functions
  45. - enums - TPasEnumType, TPasEnumValue
  46. - propagate to parent scopes
  47. - ranges TPasRangeType
  48. - arrays TPasArrayType
  49. - const TArrayValues
  50. - pointer TPasPointerType
  51. - untyped parameters
  52. - sets - TPasSetType
  53. - forwards of ^pointer and class of - must be queued and resolved at end of type section
  54. - with - TPasImplWithDo
  55. - classes - TPasClassType
  56. - interfaces
  57. - properties - TPasProperty
  58. - read, write, index properties, implements, stored
  59. - default property
  60. - TPasResString
  61. - TPasFileType
  62. - generics, nested param lists
  63. - visibility (private, protected, strict private, strict protected)
  64. - check const expression types, e.g. bark on "const c:string=3;"
  65. - dotted unitnames
  66. - labels
  67. - helpers
  68. - generics
  69. - many more: search for "ToDo:"
  70. Debug flags: -d<x>
  71. VerbosePasResolver
  72. }
  73. unit PasResolver;
  74. {$mode objfpc}{$H+}
  75. {$inline on}
  76. interface
  77. uses
  78. Classes, SysUtils, contnrs, PasTree, PParser, PScanner;
  79. const
  80. ParserMaxEmbeddedColumn = 2048;
  81. ParserMaxEmbeddedRow = $7fffffff div ParserMaxEmbeddedColumn;
  82. // message numbers
  83. const
  84. nIdentifierNotFound = 3001;
  85. nNotYetImplemented = 3002;
  86. nIllegalQualifier = 3003;
  87. nSyntaxErrorExpectedButFound = 3004;
  88. nWrongNumberOfParametersForCallTo = 3005;
  89. nIncompatibleTypeArgNo = 3006;
  90. nIncompatibleTypeArgNoVarParamMustMatchExactly = 3007;
  91. nVariableIdentifierExpected = 3008;
  92. nDuplicateIdentifier = 3009;
  93. // resourcestring patterns of messages
  94. resourcestring
  95. sIdentifierNotFound = 'identifier not found "%s"';
  96. sNotYetImplemented = 'not yet implemented: %s';
  97. sIllegalQualifier = 'illegal qualifier "%s"';
  98. sSyntaxErrorExpectedButFound = 'Syntax error, "%s" expected but "%s" found';
  99. sWrongNumberOfParametersForCallTo = 'Wrong number of parameters specified for call to "%s"';
  100. sIncompatibleTypeArgNo = 'Incompatible type arg no. %s: Got "%s", expected "%s"';
  101. sIncompatibleTypeArgNoVarParamMustMatchExactly = 'Incompatible type arg no. %s: Got "%s", expected "%s". Var param must match exactly.';
  102. sVariableIdentifierExpected = 'Variable identifier expected';
  103. sDuplicateIdentifier = 'Duplicate identifier "%s" at %s';
  104. type
  105. TResolveBaseType = (
  106. btNone, // undefined
  107. btContext, // a TPasType
  108. btUntyped, // TPasArgument without ArgType
  109. btChar, // char
  110. btWideChar, // widechar
  111. btString, // string
  112. btAnsiString, // ansistring
  113. btShortString, // shortstring
  114. btWideString, // widestring
  115. btUnicodeString,// unicodestring
  116. btReal, // real platform, single or double
  117. btSingle, // single 1.5E-45..3.4E38, digits 7-8, bytes 4
  118. btDouble, // double 5.0E-324..1.7E308, digits 15-16, bytes 8
  119. btExtended, // extended platform, double or 1.9E-4932..1.1E4932, digits 19-20, bytes 10
  120. btCExtended, // cextended
  121. btComp, // comp -2E64+1..2E63-1, digits 19-20, bytes 8
  122. btCurrency, // currency ?, bytes 8
  123. btBoolean, // boolean
  124. btByteBool, // bytebool true=not zero
  125. btWordBool, // wordbool true=not zero
  126. btLongBool, // longbool true=not zero
  127. btQWordBool, // qwordbool true=not zero
  128. btByte, // byte 0..255
  129. btShortInt, // shortint -128..127
  130. btWord, // word unsigned 2 bytes
  131. btSmallInt, // smallint signed 2 bytes
  132. btLongWord, // longword unsigned 4 bytes
  133. btCardinal, // cardinal see longword
  134. btLongint, // longint signed 4 bytes
  135. btQWord, // qword 0..18446744073709551615, bytes 8
  136. btInt64, // int64 -9223372036854775808..9223372036854775807, bytes 8
  137. btPointer, // pointer
  138. btFile, // file
  139. btText, // text
  140. btVariant, // variant
  141. btNil, // nil = pointer, class, procedure, method, ...
  142. btCompilerFunc// SUCC, PREC, LOW, HIGH, ORD, LENGTH, COPY
  143. );
  144. TResolveBaseTypes = set of TResolveBaseType;
  145. const
  146. btAllNumbers = [btComp,btCurrency,btByte,btShortInt,btWord,btSmallInt,
  147. btLongWord,btCardinal,btLongint,btQWord,btInt64];
  148. btAllStrings = [btChar,btWideChar,btString,btAnsiString,btShortString,
  149. btWideString,btUnicodeString];
  150. btAllFloats = [btReal,btSingle,btDouble,btExtended,btCExtended];
  151. btAllBooleans = [btBoolean,btByteBool,btWordBool,btLongBool,btQWordBool];
  152. btAllStandardTypes = [
  153. btChar,
  154. btWideChar,
  155. btString,
  156. btAnsiString,
  157. btShortString,
  158. btWideString,
  159. btUnicodeString,
  160. btReal,
  161. btSingle,
  162. btDouble,
  163. btExtended,
  164. btCExtended,
  165. btComp,
  166. btCurrency,
  167. btBoolean,
  168. btByteBool,
  169. btWordBool,
  170. btLongBool,
  171. btQWordBool,
  172. btByte,
  173. btShortInt,
  174. btWord,
  175. btSmallInt,
  176. btLongWord,
  177. btCardinal,
  178. btLongint,
  179. btQWord,
  180. btInt64,
  181. btPointer,
  182. btFile,
  183. btText,
  184. btVariant
  185. ];
  186. BaseTypeNames: array[TResolveBaseType] of shortstring =(
  187. 'None',
  188. 'Context',
  189. 'Untyped',
  190. 'Char',
  191. 'WideChar',
  192. 'String',
  193. 'AnsiString',
  194. 'ShortString',
  195. 'WideString',
  196. 'UnicodeString',
  197. 'Real',
  198. 'Single',
  199. 'Double',
  200. 'Extended',
  201. 'CExtended',
  202. 'Comp',
  203. 'Currency',
  204. 'Boolean',
  205. 'ByteBool',
  206. 'WordBool',
  207. 'LongBool',
  208. 'QWordBool',
  209. 'Byte',
  210. 'ShortInt',
  211. 'Word',
  212. 'SmallInt',
  213. 'LongWord',
  214. 'Cardinal',
  215. 'Longint',
  216. 'QWord',
  217. 'Int64',
  218. 'Pointer',
  219. 'File',
  220. 'Text',
  221. 'Variant',
  222. 'Nil',
  223. 'CompilerFunc'
  224. );
  225. const
  226. ResolverResultVar = 'Result';
  227. type
  228. { EPasResolve }
  229. EPasResolve = class(Exception)
  230. private
  231. FPasElement: TPasElement;
  232. procedure SetPasElement(AValue: TPasElement);
  233. public
  234. MsgNumber: integer;
  235. Args: TMessageArgs;
  236. destructor Destroy; override;
  237. property PasElement: TPasElement read FPasElement write SetPasElement;
  238. end;
  239. { TResolveData - base class for data stored in TPasElement.CustomData }
  240. TResolveData = Class
  241. private
  242. FElement: TPasElement;
  243. procedure SetElement(AValue: TPasElement);
  244. public
  245. Owner: TObject; // e.g. a TPasResolver
  246. Next: TResolveData;
  247. CustomData: TObject;
  248. constructor Create; virtual;
  249. destructor Destroy; override;
  250. property Element: TPasElement read FElement write SetElement;
  251. end;
  252. TResolveDataClass = class of TResolveData;
  253. { TResolvedReference - CustomData for normal references }
  254. TResolvedReference = Class(TResolveData)
  255. private
  256. FDeclaration: TPasElement;
  257. procedure SetDeclaration(AValue: TPasElement);
  258. public
  259. destructor Destroy; override;
  260. property Declaration: TPasElement read FDeclaration write SetDeclaration;
  261. end;
  262. { TResolvedCustom - CustomData for compiler built-in identifiers like 'length' }
  263. TResolvedCustom = Class(TResolveData)
  264. public
  265. //pas2js creates descendants of this
  266. end;
  267. TPasScope = class;
  268. TIterateScopeElement = procedure(El: TPasElement; Scope: TPasScope;
  269. Data: Pointer; var Abort: boolean) of object;
  270. { TPasScope - CustomData for elements with sub identifiers }
  271. TPasScope = Class(TResolveData)
  272. public
  273. class function IsStoredInElement: boolean; virtual;
  274. procedure IterateElements(const aName: string;
  275. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  276. var Abort: boolean); virtual;
  277. procedure WriteIdentifiers(Prefix: string); virtual;
  278. end;
  279. TPasScopeClass = class of TPasScope;
  280. { TPasModuleScope }
  281. TPasModuleScope = class(TPasScope)
  282. public
  283. procedure IterateElements(const aName: string;
  284. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  285. var Abort: boolean); override;
  286. end;
  287. TPasIdentifierKind = (
  288. pikNone, // not yet initialized
  289. pikCustom, // built-in identifiers
  290. pikSimple, // simple vars, consts, types, enums
  291. pikProc // may need parameter list with round brackets
  292. {
  293. pikIndexedProperty, // may need parameter list with edged brackets
  294. pikGeneric, // may need parameter list with angle brackets
  295. pikDottedUses // namespace, needs dotted identifierss }
  296. );
  297. TPasIdentifierKinds = set of TPasIdentifierKind;
  298. { TPasIdentifier }
  299. TPasIdentifier = Class(TObject)
  300. private
  301. FElement: TPasElement;
  302. procedure SetElement(AValue: TPasElement);
  303. public
  304. Identifier: String;
  305. NextSameIdentifier: TPasIdentifier; // next identifier with same name
  306. Kind: TPasIdentifierKind;
  307. destructor Destroy; override;
  308. property Element: TPasElement read FElement write SetElement;
  309. end;
  310. { TPasIdentifierScope - elements with a list of sub identifiers }
  311. TPasIdentifierScope = Class(TPasScope)
  312. private
  313. FItems: TFPHashList;
  314. procedure InternalAdd(Item: TPasIdentifier);
  315. procedure OnClearItem(Item, Dummy: pointer);
  316. procedure OnWriteItem(Item, Dummy: pointer);
  317. public
  318. constructor Create; override;
  319. destructor Destroy; override;
  320. function FindIdentifier(const Identifier: String): TPasIdentifier; virtual;
  321. function AddIdentifier(const Identifier: String; El: TPasElement;
  322. const Kind: TPasIdentifierKind): TPasIdentifier;
  323. function FindElement(const aName: string): TPasElement;
  324. procedure IterateElements(const aName: string;
  325. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  326. var Abort: boolean); override;
  327. procedure WriteIdentifiers(Prefix: string); override;
  328. end;
  329. { TPasDefaultScope - root scope }
  330. TPasDefaultScope = class(TPasIdentifierScope)
  331. public
  332. class function IsStoredInElement: boolean; override;
  333. end;
  334. { TPasSectionScope - e.g. interface, implementation, program, library }
  335. TPasSectionScope = Class(TPasIdentifierScope)
  336. public
  337. UsesList: TFPList; // list of TPasSectionScope
  338. constructor Create; override;
  339. destructor Destroy; override;
  340. function FindIdentifierInSection(const Identifier: String): TPasIdentifier;
  341. function FindIdentifier(const Identifier: String): TPasIdentifier; override;
  342. procedure IterateElements(const aName: string;
  343. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  344. var Abort: boolean); override;
  345. end;
  346. { TPasProcedureScope }
  347. TPasProcedureScope = Class(TPasIdentifierScope)
  348. end;
  349. { TPasRecordScope }
  350. TPasRecordScope = Class(TPasIdentifierScope)
  351. end;
  352. { TPasExceptOnScope }
  353. TPasExceptOnScope = Class(TPasIdentifierScope)
  354. end;
  355. { TPasSubScope - base class for sub scopes }
  356. TPasSubScope = Class(TPasIdentifierScope)
  357. public
  358. class function IsStoredInElement: boolean; override;
  359. end;
  360. { TPasIterateFilterData }
  361. TPasIterateFilterData = record
  362. OnIterate: TIterateScopeElement;
  363. Data: Pointer;
  364. end;
  365. PPasIterateFilterData = ^TPasIterateFilterData;
  366. { TPasSubModuleScope - scope for searching unitname.<identifier> }
  367. TPasSubModuleScope = Class(TPasSubScope)
  368. private
  369. FCurModule: TPasModule;
  370. procedure OnInternalIterate(El: TPasElement; Scope: TPasScope;
  371. Data: Pointer; var Abort: boolean);
  372. procedure SetCurModule(AValue: TPasModule);
  373. public
  374. InterfaceScope: TPasSectionScope;
  375. ImplementationScope: TPasSectionScope;
  376. destructor Destroy; override;
  377. function FindIdentifier(const Identifier: String): TPasIdentifier; override;
  378. procedure IterateElements(const aName: string;
  379. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  380. var Abort: boolean); override;
  381. property CurModule: TPasModule read FCurModule write SetCurModule;
  382. end;
  383. { TPasSubRecordScope }
  384. TPasSubRecordScope = Class(TPasSubScope)
  385. public
  386. RecordScope: TPasRecordScope;
  387. function FindIdentifier(const Identifier: String): TPasIdentifier; override;
  388. procedure IterateElements(const aName: string;
  389. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  390. var Abort: boolean); override;
  391. end;
  392. TPasResolvedKind = (
  393. rkNone,
  394. rkIdentifier, // IdentEl is a type, var, const, property, proc, etc, built-in types have IdentEl=nil
  395. // TypeEl is the resolved type
  396. rkExpr, // ExprEl is a const, e.g. 3, 'pas', 1..2, [1,2+3]
  397. rkArrayOf, // array of <TypeEl>, IdentEl might be nil
  398. rkPointer // @<IdentEl>, pointer of TypeEl
  399. );
  400. TPasResolvedType = record
  401. Kind: TPasResolvedKind;
  402. BaseType: TResolveBaseType;
  403. IdentEl: TPasElement;
  404. TypeEl: TPasType;
  405. ExprEl: TPasExpr;
  406. end;
  407. PPasResolvedType = ^TPasResolvedType;
  408. { TPasResolver }
  409. TPasResolver = Class(TPasTreeContainer)
  410. private
  411. FDefaultScope: TPasDefaultScope;
  412. FLastElement: TPasElement;
  413. FLastCreatedData: TResolveData;
  414. FLastMsg: string;
  415. FLastMsgArgs: TMessageArgs;
  416. FLastMsgElement: TPasElement;
  417. FLastMsgNumber: integer;
  418. FLastMsgPattern: string;
  419. FLastMsgType: TMessageType;
  420. FScopes: array of TPasScope; // stack of scopes
  421. FScopeCount: integer;
  422. FStoreSrcColumns: boolean;
  423. FRootElement: TPasElement;
  424. FTopScope: TPasScope;
  425. function GetScopes(Index: integer): TPasScope; inline;
  426. protected
  427. type
  428. TFindFirstElementData = record
  429. ErrorPosEl: TPasElement;
  430. Found: TPasElement;
  431. end;
  432. PFindFirstElementData = ^TFindFirstElementData;
  433. procedure OnFindFirstElement(El: TPasElement; Scope: TPasScope;
  434. FindFirstElementData: Pointer; var Abort: boolean); virtual;
  435. protected
  436. type
  437. TProcCompatibility = (
  438. pcIncompatible,
  439. pcCompatible, // e.g. assign a longint to an int64
  440. pcExact
  441. );
  442. TFindProcsData = record
  443. Params: TParamsExpr;
  444. Found: TPasProcedure;
  445. Compatible: TProcCompatibility;
  446. Count: integer;
  447. end;
  448. PFindProcsData = ^TFindProcsData;
  449. procedure OnFindProc(El: TPasElement; Scope: TPasScope;
  450. FindProcsData: Pointer; var Abort: boolean); virtual;
  451. protected
  452. procedure SetCurrentParser(AValue: TPasParser); override;
  453. procedure CheckTopScope(ExpectedClass: TPasScopeClass);
  454. function AddIdentifier(Scope: TPasIdentifierScope;
  455. const aName: String; El: TPasElement;
  456. const Kind: TPasIdentifierKind): TPasIdentifier; virtual;
  457. procedure AddModule(El: TPasModule);
  458. procedure AddSection(El: TPasSection);
  459. procedure AddType(El: TPasType);
  460. Procedure AddRecordType(El: TPasRecordType);
  461. procedure AddVariable(El: TPasVariable);
  462. procedure AddProcedure(El: TPasProcedure);
  463. procedure AddArgument(El: TPasArgument);
  464. procedure AddFunctionResult(El: TPasResultElement);
  465. procedure AddExceptOn(El: TPasImplExceptOn);
  466. procedure StartProcedureBody(El: TProcedureBody);
  467. procedure FinishModule(CurModule: TPasModule);
  468. procedure FinishUsesList;
  469. procedure FinishTypeSection;
  470. procedure FinishTypeDef(El: TPasType);
  471. procedure FinishProcedure;
  472. procedure FinishProcedureHeader;
  473. procedure FinishExceptOnExpr;
  474. procedure FinishExceptOnStatement;
  475. procedure ResolveImplBlock(Block: TPasImplBlock);
  476. procedure ResolveImplElement(El: TPasImplElement);
  477. procedure ResolveImplCaseOf(CaseOf: TPasImplCaseOf);
  478. procedure ResolveImplLabelMark(Mark: TPasImplLabelMark);
  479. procedure ResolveImplForLoop(Loop: TPasImplForLoop);
  480. procedure ResolveExpr(El: TPasExpr);
  481. procedure ResolveBinaryExpr(El: TBinaryExpr);
  482. procedure ResolveSubIdent(El: TBinaryExpr);
  483. procedure ResolveParamsExpr(Params: TParamsExpr);
  484. procedure WriteScopes;
  485. public
  486. constructor Create;
  487. destructor Destroy; override;
  488. function CreateElement(AClass: TPTreeElement; const AName: String;
  489. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  490. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  491. overload; override;
  492. function CreateElement(AClass: TPTreeElement; const AName: String;
  493. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  494. const ASrcPos: TPasSourcePos): TPasElement;
  495. overload; override;
  496. function FindElement(const AName: String): TPasElement; override;
  497. function FindFirstElement(const AName: String; ErrorPosEl: TPasElement): TPasElement;
  498. procedure IterateElements(const aName: string;
  499. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  500. var Abort: boolean); virtual;
  501. procedure FinishScope(ScopeType: TPasScopeType; El: TPasElement); override;
  502. class procedure UnmangleSourceLineNumber(LineNumber: integer;
  503. out Line, Column: integer);
  504. class function GetElementSourcePosStr(El: TPasElement): string;
  505. procedure Clear; virtual;
  506. procedure AddObjFPCBuiltInIdentifiers(BaseTypes: TResolveBaseTypes = btAllStandardTypes);
  507. function CreateReference(DeclEl, RefEl: TPasElement): TResolvedReference; virtual;
  508. function CreateScope(El: TPasElement; ScopeClass: TPasScopeClass): TPasScope; virtual;
  509. procedure PopScope;
  510. procedure PushScope(Scope: TPasScope); overload;
  511. function PushScope(El: TPasElement; ScopeClass: TPasScopeClass): TPasScope; inline; overload;
  512. procedure SetLastMsg(MsgType: TMessageType; MsgNumber: integer;
  513. Const Fmt : String; Args : Array of const; Element: TPasElement);
  514. procedure RaiseMsg(MsgNumber: integer; const Fmt: String;
  515. Args: Array of const; ErrorPosEl: TPasElement);
  516. procedure RaiseNotYetImplemented(El: TPasElement; Msg: string = ''); virtual;
  517. procedure RaiseInternalError(const Msg: string);
  518. procedure RaiseInvalidScopeForElement(El: TPasElement; const Msg: string = '');
  519. procedure RaiseIdentifierNotFound(Identifier: string; El: TPasElement);
  520. function CheckProcCompatibility(Proc: TPasProcedure;
  521. Params: TParamsExpr; RaiseOnError: boolean): TProcCompatibility;
  522. function CheckParamCompatibility(Expr: TPasExpr; Param: TPasArgument;
  523. ParamNo: integer; RaiseOnError: boolean): TProcCompatibility;
  524. procedure GetResolvedType(El: TPasElement; SkipTypeAlias: boolean;
  525. out ResolvedType: TPasResolvedType);
  526. public
  527. property LastElement: TPasElement read FLastElement;
  528. property StoreSrcColumns: boolean read FStoreSrcColumns write FStoreSrcColumns; {
  529. If true Line and Column is mangled together in TPasElement.SourceLineNumber.
  530. Use method UnmangleSourceLineNumber to extract. }
  531. property Scopes[Index: integer]: TPasScope read GetScopes;
  532. property ScopeCount: integer read FScopeCount;
  533. property TopScope: TPasScope read FTopScope;
  534. property RootElement: TPasElement read FRootElement;
  535. property DefaultScope: TPasDefaultScope read FDefaultScope write FDefaultScope;
  536. property LastMsg: string read FLastMsg write FLastMsg;
  537. property LastMsgNumber: integer read FLastMsgNumber write FLastMsgNumber;
  538. property LastMsgType: TMessageType read FLastMsgType write FLastMsgType;
  539. property LastMsgPattern: string read FLastMsgPattern write FLastMsgPattern;
  540. property LastMsgArgs: TMessageArgs read FLastMsgArgs write FLastMsgArgs;
  541. property LastMsgElement: TPasElement read FLastMsgElement write FLastMsgElement;
  542. end;
  543. function GetObjName(o: TObject): string;
  544. function GetProcDesc(Proc: TPasProcedure): string;
  545. function GetTypeDesc(aType: TPasType): string;
  546. function GetTreeDesc(El: TPasElement; Indent: integer = 0): string;
  547. function GetResolvedTypeDesc(const T: TPasResolvedType): string;
  548. procedure SetResolvedType(out ResolvedType: TPasResolvedType;
  549. Kind: TPasResolvedKind; BaseType: TResolveBaseType; IdentEl: TPasElement;
  550. TypeEl: TPasType); overload;
  551. procedure SetResolvedTypeExpr(out ResolvedType: TPasResolvedType;
  552. BaseType: TResolveBaseType; ExprEl: TPasExpr); overload;
  553. implementation
  554. function GetObjName(o: TObject): string;
  555. begin
  556. if o=nil then
  557. Result:='nil'
  558. else if o is TPasElement then
  559. Result:=TPasElement(o).Name+':'+o.ClassName
  560. else
  561. Result:=o.ClassName;
  562. end;
  563. function GetProcDesc(Proc: TPasProcedure): string;
  564. var
  565. Args: TFPList;
  566. i: Integer;
  567. Arg: TPasArgument;
  568. begin
  569. if Proc=nil then exit('nil');
  570. Result:=Proc.Name+'(';
  571. Args:=Proc.ProcType.Args;
  572. for i:=0 to Args.Count-1 do
  573. begin
  574. if i>0 then Result:=Result+';';
  575. Arg:=TPasArgument(Args[i]);
  576. if AccessNames[Arg.Access]<>'' then
  577. Result:=Result+AccessNames[Arg.Access]+' ';
  578. if Arg.ArgType=nil then
  579. Result:=Result+'untyped'
  580. else
  581. Result:=Result+GetTypeDesc(Arg.ArgType);
  582. end;
  583. Result:=Result+')';
  584. if cCallingConventions[Proc.ProcType.CallingConvention]<>'' then
  585. Result:=Result+';'+cCallingConventions[Proc.ProcType.CallingConvention];
  586. end;
  587. function GetTypeDesc(aType: TPasType): string;
  588. begin
  589. if aType=nil then exit('nil');
  590. if (aType.ClassType=TPasUnresolvedSymbolRef)
  591. or (aType.ClassType=TPasUnresolvedTypeRef) then
  592. Result:=aType.Name
  593. else if aType.ClassType=TPasPointerType then
  594. Result:='^'+GetTypeDesc(TPasPointerType(aType).DestType)
  595. else if aType.ClassType=TPasAliasType then
  596. Result:=GetTypeDesc(TPasAliasType(aType).DestType)
  597. else if aType.ClassType=TPasTypeAliasType then
  598. Result:='type '+GetTypeDesc(TPasTypeAliasType(aType).DestType)
  599. else if aType.ClassType=TPasClassOfType then
  600. Result:='class of '+TPasClassOfType(aType).DestType.Name
  601. else if aType.ClassType=TPasArrayType then
  602. Result:='array['+TPasArrayType(aType).IndexRange+'] of '+GetTypeDesc(TPasArrayType(aType).ElType)
  603. else
  604. Result:=aType.ElementTypeName;
  605. end;
  606. function GetTreeDesc(El: TPasElement; Indent: integer): string;
  607. procedure LineBreak(SubIndent: integer);
  608. begin
  609. Inc(Indent,SubIndent);
  610. Result:=Result+LineEnding+Space(Indent);
  611. end;
  612. var
  613. i, l: Integer;
  614. begin
  615. if El=nil then exit('nil');
  616. Result:=El.Name+':'+El.ClassName+'=';
  617. if El is TPasExpr then
  618. begin
  619. if El.ClassType<>TBinaryExpr then
  620. Result:=Result+OpcodeStrings[TPasExpr(El).OpCode];
  621. if El.ClassType=TUnaryExpr then
  622. Result:=Result+GetTreeDesc(TUnaryExpr(El).Operand,Indent)
  623. else if El.ClassType=TBinaryExpr then
  624. Result:=Result+GetTreeDesc(TBinaryExpr(El).left,Indent)
  625. +OpcodeStrings[TPasExpr(El).OpCode]
  626. +GetTreeDesc(TBinaryExpr(El).right,Indent)
  627. else if El.ClassType=TPrimitiveExpr then
  628. Result:=Result+TPrimitiveExpr(El).Value
  629. else if El.ClassType=TBoolConstExpr then
  630. Result:=Result+BoolToStr(TBoolConstExpr(El).Value,'true','false')
  631. else if El.ClassType=TNilExpr then
  632. Result:=Result+'nil'
  633. else if El.ClassType=TInheritedExpr then
  634. Result:=Result+'inherited'
  635. else if El.ClassType=TSelfExpr then
  636. Result:=Result+'Self'
  637. else if El.ClassType=TParamsExpr then
  638. begin
  639. LineBreak(2);
  640. Result:=Result+GetTreeDesc(TParamsExpr(El).Value,Indent)+'(';
  641. l:=length(TParamsExpr(El).Params);
  642. if l>0 then
  643. begin
  644. inc(Indent,2);
  645. for i:=0 to l-1 do
  646. begin
  647. LineBreak(0);
  648. Result:=Result+GetTreeDesc(TParamsExpr(El).Params[i],Indent);
  649. if i<l-1 then
  650. Result:=Result+','
  651. end;
  652. dec(Indent,2);
  653. end;
  654. Result:=Result+')';
  655. end
  656. else if El.ClassType=TRecordValues then
  657. begin
  658. Result:=Result+'(';
  659. l:=length(TRecordValues(El).Fields);
  660. if l>0 then
  661. begin
  662. inc(Indent,2);
  663. for i:=0 to l-1 do
  664. begin
  665. LineBreak(0);
  666. Result:=Result+TRecordValues(El).Fields[i].Name+':'
  667. +GetTreeDesc(TRecordValues(El).Fields[i].ValueExp,Indent);
  668. if i<l-1 then
  669. Result:=Result+','
  670. end;
  671. dec(Indent,2);
  672. end;
  673. Result:=Result+')';
  674. end
  675. else if El.ClassType=TArrayValues then
  676. begin
  677. Result:=Result+'[';
  678. l:=length(TArrayValues(El).Values);
  679. if l>0 then
  680. begin
  681. inc(Indent,2);
  682. for i:=0 to l-1 do
  683. begin
  684. LineBreak(0);
  685. Result:=Result+GetTreeDesc(TArrayValues(El).Values[i],Indent);
  686. if i<l-1 then
  687. Result:=Result+','
  688. end;
  689. dec(Indent,2);
  690. end;
  691. Result:=Result+']';
  692. end;
  693. end
  694. else if El is TPasProcedure then
  695. begin
  696. Result:=Result+GetTreeDesc(TPasProcedure(El).ProcType,Indent);
  697. end
  698. else if El is TPasProcedureType then
  699. begin
  700. Result:=Result+'(';
  701. l:=TPasProcedureType(El).Args.Count;
  702. if l>0 then
  703. begin
  704. inc(Indent,2);
  705. for i:=0 to l-1 do
  706. begin
  707. LineBreak(0);
  708. Result:=Result+GetTreeDesc(TPasArgument(TPasProcedureType(El).Args[i]),Indent);
  709. if i<l-1 then
  710. Result:=Result+';'
  711. end;
  712. dec(Indent,2);
  713. end;
  714. Result:=Result+')';
  715. if El is TPasFunction then
  716. Result:=Result+':'+GetTreeDesc(TPasFunctionType(TPasFunction(El).ProcType).ResultEl,Indent);
  717. if TPasProcedureType(El).IsOfObject then
  718. Result:=Result+' of object';
  719. if TPasProcedureType(El).IsNested then
  720. Result:=Result+' of nested';
  721. if cCallingConventions[TPasProcedureType(El).CallingConvention]<>'' then
  722. Result:=Result+'; '+cCallingConventions[TPasProcedureType(El).CallingConvention];
  723. end
  724. else if El.ClassType=TPasResultElement then
  725. Result:=Result+GetTreeDesc(TPasResultElement(El).ResultType,Indent)
  726. else if El.ClassType=TPasArgument then
  727. begin
  728. if AccessNames[TPasArgument(El).Access]<>'' then
  729. Result:=Result+AccessNames[TPasArgument(El).Access]+' ';
  730. if TPasArgument(El).ArgType=nil then
  731. Result:=Result+'untyped'
  732. else
  733. Result:=Result+GetTreeDesc(TPasArgument(El).ArgType,Indent);
  734. end;
  735. end;
  736. function GetResolvedTypeDesc(const T: TPasResolvedType): string;
  737. begin
  738. case T.Kind of
  739. rkNone: Result:='<none>';
  740. rkIdentifier: Result:=GetObjName(T.IdentEl)+':'+GetTypeDesc(T.TypeEl as TPasType)+'='+BaseTypeNames[T.BaseType];
  741. rkExpr: Result:=GetTreeDesc(T.ExprEl)+'='+BaseTypeNames[T.BaseType];
  742. rkArrayOf: Result:='array of '+GetTypeDesc(T.TypeEl as TPasType)+'='+BaseTypeNames[T.BaseType];
  743. rkPointer: Result:='^'+GetTypeDesc(T.TypeEl as TPasType)+'='+BaseTypeNames[T.BaseType];
  744. else Result:='<Ouch, unknown kind>';
  745. end;
  746. end;
  747. procedure SetResolvedType(out ResolvedType: TPasResolvedType;
  748. Kind: TPasResolvedKind; BaseType: TResolveBaseType; IdentEl: TPasElement;
  749. TypeEl: TPasType);
  750. begin
  751. ResolvedType.Kind:=Kind;
  752. ResolvedType.BaseType:=BaseType;
  753. ResolvedType.IdentEl:=IdentEl;
  754. ResolvedType.TypeEl:=TypeEl;
  755. ResolvedType.ExprEl:=nil;
  756. end;
  757. procedure SetResolvedTypeExpr(out ResolvedType: TPasResolvedType;
  758. BaseType: TResolveBaseType; ExprEl: TPasExpr);
  759. begin
  760. ResolvedType.Kind:=rkExpr;
  761. ResolvedType.BaseType:=BaseType;
  762. ResolvedType.IdentEl:=nil;
  763. ResolvedType.TypeEl:=nil;
  764. ResolvedType.ExprEl:=ExprEl;
  765. end;
  766. { TPasSubRecordScope }
  767. function TPasSubRecordScope.FindIdentifier(const Identifier: String
  768. ): TPasIdentifier;
  769. begin
  770. Result:=RecordScope.FindIdentifier(Identifier);
  771. end;
  772. procedure TPasSubRecordScope.IterateElements(const aName: string;
  773. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  774. var Abort: boolean);
  775. begin
  776. RecordScope.IterateElements(aName, OnIterateElement, Data, Abort);
  777. end;
  778. { TPasIdentifier }
  779. procedure TPasIdentifier.SetElement(AValue: TPasElement);
  780. begin
  781. if FElement=AValue then Exit;
  782. if Element<>nil then
  783. Element.Release;
  784. FElement:=AValue;
  785. if Element<>nil then
  786. Element.AddRef;
  787. end;
  788. destructor TPasIdentifier.Destroy;
  789. begin
  790. Element:=nil;
  791. inherited Destroy;
  792. end;
  793. { EPasResolve }
  794. procedure EPasResolve.SetPasElement(AValue: TPasElement);
  795. begin
  796. if FPasElement=AValue then Exit;
  797. if PasElement<>nil then
  798. PasElement.Release;
  799. FPasElement:=AValue;
  800. if PasElement<>nil then
  801. PasElement.AddRef;
  802. end;
  803. destructor EPasResolve.Destroy;
  804. begin
  805. PasElement:=nil;
  806. inherited Destroy;
  807. end;
  808. { TResolvedReference }
  809. procedure TResolvedReference.SetDeclaration(AValue: TPasElement);
  810. begin
  811. if FDeclaration=AValue then Exit;
  812. if Declaration<>nil then
  813. Declaration.Release;
  814. FDeclaration:=AValue;
  815. if Declaration<>nil then
  816. Declaration.AddRef;
  817. end;
  818. destructor TResolvedReference.Destroy;
  819. begin
  820. Declaration:=nil;
  821. inherited Destroy;
  822. end;
  823. { TPasSubScope }
  824. class function TPasSubScope.IsStoredInElement: boolean;
  825. begin
  826. Result:=false;
  827. end;
  828. { TPasSubModuleScope }
  829. procedure TPasSubModuleScope.OnInternalIterate(El: TPasElement;
  830. Scope: TPasScope; Data: Pointer; var Abort: boolean);
  831. var
  832. FilterData: PPasIterateFilterData absolute Data;
  833. begin
  834. if El.ClassType=TPasModule then
  835. exit; // skip used units
  836. // call the original iterator
  837. FilterData^.OnIterate(El,Scope,FilterData^.Data,Abort);
  838. end;
  839. procedure TPasSubModuleScope.SetCurModule(AValue: TPasModule);
  840. begin
  841. if FCurModule=AValue then Exit;
  842. if CurModule<>nil then
  843. CurModule.Release;
  844. FCurModule:=AValue;
  845. if CurModule<>nil then
  846. CurModule.AddRef;
  847. end;
  848. destructor TPasSubModuleScope.Destroy;
  849. begin
  850. CurModule:=nil;
  851. inherited Destroy;
  852. end;
  853. function TPasSubModuleScope.FindIdentifier(const Identifier: String
  854. ): TPasIdentifier;
  855. begin
  856. if ImplementationScope<>nil then
  857. begin
  858. Result:=ImplementationScope.FindIdentifierInSection(Identifier);
  859. if (Result<>nil) and (Result.Element.ClassType<>TPasModule) then
  860. exit;
  861. end;
  862. if InterfaceScope<>nil then
  863. Result:=InterfaceScope.FindIdentifierInSection(Identifier)
  864. else
  865. Result:=nil;
  866. end;
  867. procedure TPasSubModuleScope.IterateElements(const aName: string;
  868. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  869. var Abort: boolean);
  870. var
  871. FilterData: TPasIterateFilterData;
  872. begin
  873. FilterData.OnIterate:=OnIterateElement;
  874. FilterData.Data:=Data;
  875. if ImplementationScope<>nil then
  876. begin
  877. ImplementationScope.IterateElements(aName,@OnInternalIterate,@FilterData,Abort);
  878. if Abort then exit;
  879. end;
  880. if InterfaceScope<>nil then
  881. InterfaceScope.IterateElements(aName,@OnInternalIterate,@FilterData,Abort);
  882. end;
  883. { TPasSectionScope }
  884. constructor TPasSectionScope.Create;
  885. begin
  886. inherited Create;
  887. UsesList:=TFPList.Create;
  888. end;
  889. destructor TPasSectionScope.Destroy;
  890. begin
  891. FreeAndNil(UsesList);
  892. inherited Destroy;
  893. end;
  894. function TPasSectionScope.FindIdentifierInSection(const Identifier: String
  895. ): TPasIdentifier;
  896. begin
  897. Result:=inherited FindIdentifier(Identifier);
  898. end;
  899. function TPasSectionScope.FindIdentifier(const Identifier: String
  900. ): TPasIdentifier;
  901. var
  902. i: Integer;
  903. UsesScope: TPasIdentifierScope;
  904. begin
  905. Result:=inherited FindIdentifier(Identifier);
  906. if Result<>nil then
  907. exit;
  908. for i:=0 to UsesList.Count-1 do
  909. begin
  910. UsesScope:=TPasIdentifierScope(UsesList[i]);
  911. {$IFDEF VerbosePasResolver}
  912. writeln('TPasSectionScope.FindIdentifier "',Identifier,'" in used unit ',GetObjName(UsesScope.Element));
  913. {$ENDIF}
  914. Result:=UsesScope.FindIdentifier(Identifier);
  915. if Result<>nil then exit;
  916. end;
  917. end;
  918. procedure TPasSectionScope.IterateElements(const aName: string;
  919. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  920. var Abort: boolean);
  921. var
  922. i: Integer;
  923. UsesScope: TPasIdentifierScope;
  924. begin
  925. inherited IterateElements(aName, OnIterateElement, Data, Abort);
  926. if Abort then exit;
  927. for i:=0 to UsesList.Count-1 do
  928. begin
  929. UsesScope:=TPasIdentifierScope(UsesList[i]);
  930. {$IFDEF VerbosePasResolver}
  931. writeln('TPasSectionScope.IterateElements "',aName,'" in used unit ',GetObjName(UsesScope.Element));
  932. {$ENDIF}
  933. UsesScope.IterateElements(aName,OnIterateElement,Data,Abort);
  934. if Abort then exit;
  935. end;
  936. end;
  937. { TPasModuleScope }
  938. procedure TPasModuleScope.IterateElements(const aName: string;
  939. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  940. var Abort: boolean);
  941. begin
  942. if CompareText(aName,Element.Name)<>0 then exit;
  943. OnIterateElement(Element,Self,Data,Abort);
  944. end;
  945. { TPasDefaultScope }
  946. class function TPasDefaultScope.IsStoredInElement: boolean;
  947. begin
  948. Result:=false;
  949. end;
  950. { TResolveData }
  951. procedure TResolveData.SetElement(AValue: TPasElement);
  952. begin
  953. if FElement=AValue then Exit;
  954. if Element<>nil then
  955. Element.Release;
  956. FElement:=AValue;
  957. if Element<>nil then
  958. Element.AddRef;
  959. end;
  960. constructor TResolveData.Create;
  961. begin
  962. end;
  963. destructor TResolveData.Destroy;
  964. begin
  965. Element:=nil;
  966. inherited Destroy;
  967. end;
  968. { TPasScope }
  969. class function TPasScope.IsStoredInElement: boolean;
  970. begin
  971. Result:=true;
  972. end;
  973. procedure TPasScope.IterateElements(const aName: string;
  974. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  975. var Abort: boolean);
  976. begin
  977. if aName='' then ;
  978. if Data=nil then ;
  979. if OnIterateElement=nil then ;
  980. if Abort then ;
  981. end;
  982. procedure TPasScope.WriteIdentifiers(Prefix: string);
  983. begin
  984. writeln(Prefix,'Element: ',GetObjName(Element));
  985. end;
  986. { TPasResolver }
  987. // inline
  988. function TPasResolver.PushScope(El: TPasElement; ScopeClass: TPasScopeClass
  989. ): TPasScope;
  990. begin
  991. Result:=CreateScope(El,ScopeClass);
  992. PushScope(Result);
  993. end;
  994. // inline
  995. function TPasResolver.GetScopes(Index: integer): TPasScope;
  996. begin
  997. Result:=FScopes[Index];
  998. end;
  999. procedure TPasResolver.OnFindFirstElement(El: TPasElement; Scope: TPasScope;
  1000. FindFirstElementData: Pointer; var Abort: boolean);
  1001. var
  1002. Data: PFindFirstElementData absolute FindFirstElementData;
  1003. begin
  1004. Data^.Found:=El;
  1005. Abort:=true;
  1006. if Scope=nil then ;
  1007. end;
  1008. procedure TPasResolver.OnFindProc(El: TPasElement; Scope: TPasScope;
  1009. FindProcsData: Pointer; var Abort: boolean);
  1010. var
  1011. Data: PFindProcsData absolute FindProcsData;
  1012. Proc: TPasProcedure;
  1013. Compatible: TProcCompatibility;
  1014. begin
  1015. if not (El is TPasProcedure) then
  1016. begin
  1017. // identifier is not a proc
  1018. Abort:=true;
  1019. if Data^.Found=nil then
  1020. begin
  1021. // ToDo: use the ( as error position
  1022. RaiseMsg(nSyntaxErrorExpectedButFound,sSyntaxErrorExpectedButFound,[';','('],
  1023. Data^.Params.Value);
  1024. end
  1025. else
  1026. exit;
  1027. end;
  1028. // identifier is a proc
  1029. {$IFDEF VerbosePasResolver}
  1030. writeln('TPasResolver.OnFindProc ',GetTreeDesc(El,2));
  1031. {$ENDIF}
  1032. Proc:=TPasProcedure(El);
  1033. if Scope=nil then ;
  1034. Compatible:=CheckProcCompatibility(Proc,Data^.Params,false);
  1035. if (Data^.Found=nil) or (ord(Compatible)>ord(Data^.Compatible)) then
  1036. begin
  1037. Data^.Found:=Proc;
  1038. Data^.Compatible:=Compatible;
  1039. Data^.Count:=1;
  1040. end
  1041. else if Compatible=Data^.Compatible then
  1042. inc(Data^.Count);
  1043. end;
  1044. procedure TPasResolver.SetCurrentParser(AValue: TPasParser);
  1045. begin
  1046. //writeln('TPasResolver.SetCurrentParser ',AValue<>nil);
  1047. if AValue=CurrentParser then exit;
  1048. Clear;
  1049. inherited SetCurrentParser(AValue);
  1050. if CurrentParser<>nil then
  1051. CurrentParser.Options:=CurrentParser.Options+[po_resolvestandardtypes];
  1052. end;
  1053. procedure TPasResolver.CheckTopScope(ExpectedClass: TPasScopeClass);
  1054. begin
  1055. if TopScope=nil then
  1056. RaiseInternalError('Expected TopScope='+ExpectedClass.ClassName+' but found nil');
  1057. if TopScope.ClassType<>ExpectedClass then
  1058. RaiseInternalError('Expected TopScope='+ExpectedClass.ClassName+' but found '+TopScope.ClassName);
  1059. end;
  1060. function TPasResolver.AddIdentifier(Scope: TPasIdentifierScope;
  1061. const aName: String; El: TPasElement; const Kind: TPasIdentifierKind
  1062. ): TPasIdentifier;
  1063. var
  1064. Identifier, OlderIdentifier: TPasIdentifier;
  1065. begin
  1066. Identifier:=Scope.AddIdentifier(aName,El,Kind);
  1067. OlderIdentifier:=Identifier.NextSameIdentifier;
  1068. // check duplicate
  1069. if OlderIdentifier<>nil then
  1070. if (Identifier.Kind=pikSimple) or (OlderIdentifier.Kind=pikSimple) then
  1071. RaiseMsg(nDuplicateIdentifier,sDuplicateIdentifier,
  1072. [aName,GetElementSourcePosStr(OlderIdentifier.Element)],El);
  1073. Result:=Identifier;
  1074. end;
  1075. procedure TPasResolver.FinishModule(CurModule: TPasModule);
  1076. var
  1077. CurModuleClass: TClass;
  1078. begin
  1079. {$IFDEF VerbosePasResolver}
  1080. writeln('TPasResolver.FinishModule START ',CurModule.Name);
  1081. {$ENDIF}
  1082. CurModuleClass:=CurModule.ClassType;
  1083. if (CurModuleClass=TPasProgram) or (CurModuleClass=TPasLibrary) then
  1084. begin
  1085. // resolve begin..end block
  1086. ResolveImplBlock(CurModule.InitializationSection);
  1087. end
  1088. else if (CurModuleClass=TPasModule) then
  1089. begin
  1090. if CurModule.FinalizationSection<>nil then
  1091. // finalization section finished -> resolve
  1092. ResolveImplBlock(CurModule.FinalizationSection)
  1093. else if CurModule.InitializationSection<>nil then
  1094. // initialization section finished -> resolve
  1095. ResolveImplBlock(CurModule.InitializationSection)
  1096. else
  1097. begin
  1098. // ToDo: check if all forward procs are implemented
  1099. end;
  1100. end
  1101. else
  1102. RaiseInternalError(''); // unknown module
  1103. // close all sections
  1104. while (TopScope<>nil) and (TopScope.ClassType=TPasSectionScope) do
  1105. PopScope;
  1106. CheckTopScope(TPasModuleScope);
  1107. PopScope;
  1108. {$IFDEF VerbosePasResolver}
  1109. writeln('TPasResolver.FinishModule END ',CurModule.Name);
  1110. {$ENDIF}
  1111. end;
  1112. procedure TPasResolver.FinishUsesList;
  1113. var
  1114. Section: TPasSection;
  1115. i: Integer;
  1116. El, PublicEl: TPasElement;
  1117. Scope: TPasSectionScope;
  1118. UsesScope: TPasIdentifierScope;
  1119. begin
  1120. CheckTopScope(TPasSectionScope);
  1121. Scope:=TPasSectionScope(TopScope);
  1122. Section:=TPasSection(Scope.Element);
  1123. {$IFDEF VerbosePasResolver}
  1124. writeln('TPasResolver.FinishUsesList Section=',Section.ClassName,' Section.UsesList.Count=',Section.UsesList.Count);
  1125. {$ENDIF}
  1126. for i:=0 to Section.UsesList.Count-1 do
  1127. begin
  1128. El:=TPasElement(Section.UsesList[i]);
  1129. {$IFDEF VerbosePasResolver}
  1130. writeln('TPasResolver.FinishUsesList ',GetObjName(El));
  1131. {$ENDIF}
  1132. if (El.ClassType=TProgramSection) then
  1133. RaiseInternalError('used unit is a program: '+GetObjName(El));
  1134. AddIdentifier(Scope,El.Name,El,pikSimple);
  1135. // check used unit
  1136. PublicEl:=nil;
  1137. if (El.ClassType=TLibrarySection) then
  1138. PublicEl:=El
  1139. else if (El.ClassType=TPasModule) then
  1140. PublicEl:=TPasModule(El).InterfaceSection;
  1141. if PublicEl=nil then
  1142. RaiseInternalError('uses element has no interface section: '+GetObjName(El));
  1143. if PublicEl.CustomData=nil then
  1144. RaiseInternalError('uses element has no resolver data: '
  1145. +El.Name+'->'+GetObjName(PublicEl));
  1146. if not (PublicEl.CustomData is TPasIdentifierScope) then
  1147. RaiseInternalError('uses element has invalid resolver data: '
  1148. +El.Name+'->'+GetObjName(PublicEl)+'->'+PublicEl.CustomData.ClassName);
  1149. UsesScope:=TPasIdentifierScope(PublicEl.CustomData);
  1150. Scope.UsesList.Add(UsesScope);
  1151. end;
  1152. end;
  1153. procedure TPasResolver.FinishTypeSection;
  1154. begin
  1155. // ToDo: resolve pending forwards
  1156. end;
  1157. procedure TPasResolver.FinishTypeDef(El: TPasType);
  1158. begin
  1159. {$IFDEF VerbosePasResolver}
  1160. writeln('TPasResolver.FinishTypeDef El=',GetObjName(El));
  1161. {$ENDIF}
  1162. if TopScope.Element=El then
  1163. begin
  1164. if TopScope.ClassType=TPasRecordScope then
  1165. PopScope;
  1166. end;
  1167. end;
  1168. procedure TPasResolver.FinishProcedure;
  1169. var
  1170. aProc: TPasProcedure;
  1171. begin
  1172. {$IFDEF VerbosePasResolver}
  1173. writeln('TPasResolver.FinishProcedure START');
  1174. {$ENDIF}
  1175. CheckTopScope(TPasProcedureScope);
  1176. aProc:=TPasProcedureScope(TopScope).Element as TPasProcedure;
  1177. if aProc.Body<>nil then
  1178. ResolveImplBlock(aProc.Body.Body);
  1179. PopScope;
  1180. end;
  1181. procedure TPasResolver.FinishProcedureHeader;
  1182. begin
  1183. CheckTopScope(TPasProcedureScope);
  1184. // ToDo: check class
  1185. // ToDo: check duplicate
  1186. end;
  1187. procedure TPasResolver.FinishExceptOnExpr;
  1188. var
  1189. El: TPasImplExceptOn;
  1190. Expr: TPrimitiveExpr;
  1191. begin
  1192. CheckTopScope(TPasExceptOnScope);
  1193. El:=TPasImplExceptOn(FTopScope.Element);
  1194. if El.VarExpr<>nil then
  1195. begin
  1196. if El.VarExpr.ClassType<>TPrimitiveExpr then
  1197. RaiseNotYetImplemented(El.VarExpr);
  1198. Expr:=TPrimitiveExpr(El.VarExpr);
  1199. if Expr.Kind<>pekIdent then
  1200. RaiseNotYetImplemented(Expr);
  1201. AddIdentifier(TPasExceptOnScope(FTopScope),Expr.Value,Expr,pikSimple);
  1202. end;
  1203. if El.TypeExpr<>nil then
  1204. ResolveExpr(El.TypeExpr);
  1205. end;
  1206. procedure TPasResolver.FinishExceptOnStatement;
  1207. begin
  1208. //writeln('TPasResolver.FinishExceptOnStatement START');
  1209. CheckTopScope(TPasExceptOnScope);
  1210. ResolveImplElement(TPasImplExceptOn(FTopScope.Element).Body);
  1211. PopScope;
  1212. end;
  1213. procedure TPasResolver.ResolveImplBlock(Block: TPasImplBlock);
  1214. var
  1215. i: Integer;
  1216. begin
  1217. if Block=nil then exit;
  1218. for i:=0 to Block.Elements.Count-1 do
  1219. ResolveImplElement(TPasImplElement(Block.Elements[i]));
  1220. end;
  1221. procedure TPasResolver.ResolveImplElement(El: TPasImplElement);
  1222. begin
  1223. //writeln('TPasResolver.ResolveImplElement ',GetObjName(El));
  1224. if El=nil then
  1225. else if El.ClassType=TPasImplBeginBlock then
  1226. ResolveImplBlock(TPasImplBeginBlock(El))
  1227. else if El.ClassType=TPasImplAssign then
  1228. begin
  1229. ResolveExpr(TPasImplAssign(El).left);
  1230. ResolveExpr(TPasImplAssign(El).right);
  1231. end
  1232. else if El.ClassType=TPasImplSimple then
  1233. ResolveExpr(TPasImplSimple(El).expr)
  1234. else if El.ClassType=TPasImplBlock then
  1235. ResolveImplBlock(TPasImplBlock(El))
  1236. else if El.ClassType=TPasImplRepeatUntil then
  1237. begin
  1238. ResolveImplBlock(TPasImplBlock(El));
  1239. ResolveExpr(TPasImplRepeatUntil(El).ConditionExpr);
  1240. end
  1241. else if El.ClassType=TPasImplIfElse then
  1242. begin
  1243. ResolveExpr(TPasImplIfElse(El).ConditionExpr);
  1244. ResolveImplElement(TPasImplIfElse(El).IfBranch);
  1245. ResolveImplElement(TPasImplIfElse(El).ElseBranch);
  1246. end
  1247. else if El.ClassType=TPasImplWhileDo then
  1248. begin
  1249. ResolveExpr(TPasImplWhileDo(El).ConditionExpr);
  1250. ResolveImplElement(TPasImplWhileDo(El).Body);
  1251. end
  1252. else if El.ClassType=TPasImplCaseOf then
  1253. ResolveImplCaseOf(TPasImplCaseOf(El))
  1254. else if El.ClassType=TPasImplLabelMark then
  1255. ResolveImplLabelMark(TPasImplLabelMark(El))
  1256. else if El.ClassType=TPasImplForLoop then
  1257. ResolveImplForLoop(TPasImplForLoop(El))
  1258. else if El.ClassType=TPasImplTry then
  1259. begin
  1260. ResolveImplBlock(TPasImplTry(El));
  1261. ResolveImplBlock(TPasImplTry(El).FinallyExcept);
  1262. ResolveImplBlock(TPasImplTry(El).ElseBranch);
  1263. end
  1264. else if El.ClassType=TPasImplExceptOn then
  1265. // handled in FinishExceptOnStatement
  1266. else if El.ClassType=TPasImplRaise then
  1267. begin
  1268. ResolveExpr(TPasImplRaise(El).ExceptObject);
  1269. ResolveExpr(TPasImplRaise(El).ExceptAddr);
  1270. end
  1271. else if El.ClassType=TPasImplCommand then
  1272. begin
  1273. if TPasImplCommand(El).Command<>'' then
  1274. RaiseNotYetImplemented(El,'TPasResolver.ResolveImplElement');
  1275. end
  1276. else if El.ClassType=TPasImplAsmStatement then
  1277. else
  1278. RaiseNotYetImplemented(El,'TPasResolver.ResolveImplElement');
  1279. end;
  1280. procedure TPasResolver.ResolveImplCaseOf(CaseOf: TPasImplCaseOf);
  1281. var
  1282. i, j: Integer;
  1283. El: TPasElement;
  1284. Stat: TPasImplCaseStatement;
  1285. begin
  1286. ResolveExpr(CaseOf.CaseExpr);
  1287. for i:=0 to CaseOf.Elements.Count-1 do
  1288. begin
  1289. El:=TPasElement(CaseOf.Elements[i]);
  1290. if El.ClassType=TPasImplCaseStatement then
  1291. begin
  1292. Stat:=TPasImplCaseStatement(El);
  1293. for j:=0 to Stat.Expressions.Count-1 do
  1294. begin
  1295. //writeln('TPasResolver.ResolveImplCaseOf Stat.Expr[',j,']=',GetObjName(El));
  1296. ResolveExpr(TPasExpr(Stat.Expressions[j]));
  1297. end;
  1298. ResolveImplElement(Stat.Body);
  1299. end
  1300. else if El.ClassType=TPasImplCaseElse then
  1301. ResolveImplBlock(TPasImplCaseElse(El))
  1302. else
  1303. RaiseNotYetImplemented(El);
  1304. end;
  1305. // CaseOf.ElseBranch was already resolved via Elements
  1306. end;
  1307. procedure TPasResolver.ResolveImplLabelMark(Mark: TPasImplLabelMark);
  1308. var
  1309. DeclEl: TPasElement;
  1310. begin
  1311. DeclEl:=FindFirstElement(Mark.LabelId,Mark);
  1312. // ToDo: check if DeclEl is a label and check duplicate
  1313. CreateReference(DeclEl,Mark);
  1314. end;
  1315. procedure TPasResolver.ResolveImplForLoop(Loop: TPasImplForLoop);
  1316. begin
  1317. ResolveExpr(Loop.VariableName);
  1318. ResolveExpr(Loop.StartExpr);
  1319. ResolveExpr(Loop.EndExpr);
  1320. ResolveImplElement(Loop.Body);
  1321. end;
  1322. procedure TPasResolver.ResolveExpr(El: TPasExpr);
  1323. var
  1324. Primitive: TPrimitiveExpr;
  1325. DeclEl: TPasElement;
  1326. begin
  1327. {$IFDEF VerbosePasResolver}
  1328. writeln('TPasResolver.ResolveExpr ',GetObjName(El));
  1329. {$ENDIF}
  1330. if El=nil then
  1331. else if El.ClassType=TPrimitiveExpr then
  1332. begin
  1333. Primitive:=TPrimitiveExpr(El);
  1334. case Primitive.Kind of
  1335. pekIdent:
  1336. begin
  1337. DeclEl:=FindFirstElement(Primitive.Value,El);
  1338. //writeln('TPasResolver.ResolveExpr Ref=',GetObjName(El)+' Decl='+GetObjName(DeclEl));
  1339. CreateReference(DeclEl,El);
  1340. end;
  1341. pekNumber,pekString,pekNil,pekBoolConst: exit;
  1342. else
  1343. RaiseNotYetImplemented(El);
  1344. end;
  1345. end
  1346. else if El.ClassType=TUnaryExpr then
  1347. ResolveExpr(TUnaryExpr(El).Operand)
  1348. else if El.ClassType=TBinaryExpr then
  1349. ResolveBinaryExpr(TBinaryExpr(El))
  1350. else if El.ClassType=TParamsExpr then
  1351. ResolveParamsExpr(TParamsExpr(El))
  1352. else if El.ClassType=TBoolConstExpr then
  1353. else if El.ClassType=TNilExpr then
  1354. else
  1355. RaiseNotYetImplemented(El);
  1356. end;
  1357. procedure TPasResolver.ResolveBinaryExpr(El: TBinaryExpr);
  1358. begin
  1359. //writeln('TPasResolver.ResolveBinaryExpr left=',GetObjName(El.left),' right=',GetObjName(El.right),' opcode=',OpcodeStrings[El.OpCode]);
  1360. ResolveExpr(El.left);
  1361. if El.right=nil then exit;
  1362. case El.OpCode of
  1363. eopNone,
  1364. eopAdd,
  1365. eopSubtract,
  1366. eopMultiply,
  1367. eopDivide,
  1368. eopDiv,
  1369. eopMod,
  1370. eopPower,
  1371. eopShr,
  1372. eopShl,
  1373. eopNot,
  1374. eopAnd,
  1375. eopOr,
  1376. eopXor,
  1377. eopEqual,
  1378. eopNotEqual,
  1379. eopLessThan,
  1380. eopGreaterThan,
  1381. eopLessthanEqual,
  1382. eopGreaterThanEqual,
  1383. eopIn,
  1384. eopIs,
  1385. eopAs,
  1386. eopSymmetricaldifference:
  1387. begin
  1388. // ToDo: check if left operand supports operator
  1389. ResolveExpr(El.right);
  1390. // ToDo: check if operator fits
  1391. end;
  1392. //eopAddress: ;
  1393. //eopDeref: ;
  1394. eopSubIdent:
  1395. ResolveSubIdent(El);
  1396. else
  1397. RaiseNotYetImplemented(El,OpcodeStrings[El.OpCode]);
  1398. end;
  1399. end;
  1400. procedure TPasResolver.ResolveSubIdent(El: TBinaryExpr);
  1401. var
  1402. DeclEl: TPasElement;
  1403. ModuleScope: TPasSubModuleScope;
  1404. aModule: TPasModule;
  1405. VarType: TPasType;
  1406. RecScope: TPasRecordScope;
  1407. SubScope: TPasSubRecordScope;
  1408. begin
  1409. //writeln('TPasResolver.ResolveSubIdent El.left=',GetObjName(El.left));
  1410. if El.left.ClassType=TPrimitiveExpr then
  1411. begin
  1412. //writeln('TPasResolver.ResolveSubIdent El.left.CustomData=',GetObjName(El.left.CustomData));
  1413. if El.left.CustomData is TResolvedReference then
  1414. begin
  1415. DeclEl:=TResolvedReference(El.left.CustomData).Declaration;
  1416. //writeln('TPasResolver.ResolveSubIdent Decl=',GetObjName(DeclEl));
  1417. if DeclEl is TPasModule then
  1418. begin
  1419. // e.g. unitname.identifier
  1420. // => search in interface and if this is our module in the implementation
  1421. aModule:=TPasModule(DeclEl);
  1422. ModuleScope:=TPasSubModuleScope.Create;
  1423. ModuleScope.Owner:=Self;
  1424. ModuleScope.CurModule:=aModule;
  1425. if aModule is TPasProgram then
  1426. begin // program
  1427. if TPasProgram(aModule).ProgramSection<>nil then
  1428. ModuleScope.InterfaceScope:=
  1429. TPasProgram(aModule).ProgramSection.CustomData as TPasSectionScope;
  1430. end
  1431. else if aModule is TPasLibrary then
  1432. begin // library
  1433. if TPasLibrary(aModule).LibrarySection<>nil then
  1434. ModuleScope.InterfaceScope:=
  1435. TPasLibrary(aModule).LibrarySection.CustomData as TPasSectionScope;
  1436. end
  1437. else
  1438. begin // unit
  1439. if aModule.InterfaceSection<>nil then
  1440. ModuleScope.InterfaceScope:=
  1441. aModule.InterfaceSection.CustomData as TPasSectionScope;
  1442. if (aModule=CurrentParser.CurModule)
  1443. and (aModule.ImplementationSection<>nil)
  1444. and (aModule.ImplementationSection.CustomData<>nil)
  1445. then
  1446. ModuleScope.ImplementationScope:=aModule.ImplementationSection.CustomData as TPasSectionScope;
  1447. end;
  1448. PushScope(ModuleScope);
  1449. ResolveExpr(El.right);
  1450. PopScope;
  1451. exit;
  1452. end
  1453. else if DeclEl.ClassType=TPasVariable then
  1454. begin
  1455. VarType:=TPasVariable(DeclEl).VarType;
  1456. if VarType.ClassType=TPasRecordType then
  1457. begin
  1458. RecScope:=TPasRecordType(VarType).CustomData as TPasRecordScope;
  1459. SubScope:=TPasSubRecordScope.Create;
  1460. SubScope.Owner:=Self;
  1461. SubScope.RecordScope:=RecScope;
  1462. PushScope(SubScope);
  1463. ResolveExpr(El.right);
  1464. PopScope;
  1465. exit;
  1466. end
  1467. else
  1468. begin
  1469. {$IFDEF VerbosePasResolver}
  1470. writeln('TPasResolver.ResolveSubIdent DeclEl=',GetObjName(DeclEl),' VarType=',GetObjName(VarType));
  1471. {$ENDIF}
  1472. end;
  1473. end;
  1474. end
  1475. else
  1476. begin
  1477. {$IFDEF VerbosePasResolver}
  1478. writeln('TPasResolver.ResolveSubIdent DeclEl=',GetObjName(DeclEl));
  1479. {$ENDIF}
  1480. end;
  1481. end;
  1482. RaiseMsg(nIllegalQualifier,sIllegalQualifier,['.'],El);
  1483. end;
  1484. procedure TPasResolver.ResolveParamsExpr(Params: TParamsExpr);
  1485. var
  1486. i: Integer;
  1487. ProcName: String;
  1488. FindData: TFindProcsData;
  1489. Abort: boolean;
  1490. begin
  1491. // first resolve params
  1492. for i:=0 to length(Params.Params)-1 do
  1493. ResolveExpr(Params.Params[i]);
  1494. // then search the best fitting proc
  1495. if Params.Value.ClassType=TPrimitiveExpr then
  1496. begin
  1497. ProcName:=TPrimitiveExpr(Params.Value).Value;
  1498. FindData:=Default(TFindProcsData);
  1499. FindData.Params:=Params;
  1500. Abort:=false;
  1501. IterateElements(ProcName,@OnFindProc,@FindData,Abort);
  1502. if FindData.Found=nil then
  1503. RaiseIdentifierNotFound(ProcName,Params.Value);
  1504. if FindData.Compatible=pcIncompatible then
  1505. begin
  1506. // found one proc, but it was incompatible => raise error
  1507. {$IFDEF VerbosePasResolver}
  1508. writeln('TPasResolver.ResolveParamsExpr found one proc, but it was incompatible => check again to raise error');
  1509. {$ENDIF}
  1510. CheckProcCompatibility(FindData.Found,Params,true);
  1511. end;
  1512. if FindData.Count>1 then
  1513. begin
  1514. // ToDo: multiple overloads fit => search again and list the candidates
  1515. RaiseMsg(nIdentifierNotFound,sIdentifierNotFound,[],Params.Value);
  1516. end;
  1517. // found compatible proc
  1518. CreateReference(FindData.Found,Params.Value);
  1519. end
  1520. else
  1521. RaiseNotYetImplemented(Params,'with parameters');
  1522. end;
  1523. procedure TPasResolver.AddModule(El: TPasModule);
  1524. begin
  1525. if TopScope<>DefaultScope then
  1526. RaiseInvalidScopeForElement(El);
  1527. PushScope(El,TPasModuleScope);
  1528. end;
  1529. procedure TPasResolver.AddSection(El: TPasSection);
  1530. // TInterfaceSection, TImplementationSection, TProgramSection, TLibrarySection
  1531. // Note: implementation scope is within the interface scope
  1532. var
  1533. CurModuleClass: TClass;
  1534. begin
  1535. CurModuleClass:=CurrentParser.CurModule.ClassType;
  1536. if (CurModuleClass=TPasProgram) or (CurModuleClass=TPasLibrary) then
  1537. begin
  1538. if El.ClassType=TInitializationSection then
  1539. ; // ToDo: check if all forward procs are implemented
  1540. end
  1541. else if CurModuleClass=TPasModule then
  1542. begin
  1543. if El.ClassType=TInitializationSection then
  1544. begin
  1545. // finished implementation
  1546. // ToDo: check if all forward procs are implemented
  1547. end
  1548. else if El.ClassType=TFinalizationSection then
  1549. begin
  1550. if CurrentParser.CurModule.InitializationSection<>nil then
  1551. begin
  1552. // resolve initialization section
  1553. ResolveImplBlock(CurrentParser.CurModule.InitializationSection);
  1554. end
  1555. else
  1556. begin
  1557. // finished implementation
  1558. // ToDo: check if all forward procs are implemented
  1559. end;
  1560. end;
  1561. end
  1562. else
  1563. RaiseInternalError(''); // unknown module
  1564. PushScope(El,TPasSectionScope);
  1565. end;
  1566. procedure TPasResolver.AddType(El: TPasType);
  1567. begin
  1568. if (El.Name='') then exit; // sub type
  1569. if El is TPasUnresolvedTypeRef then exit; // built-in type
  1570. {$IFDEF VerbosePasResolver}
  1571. writeln('TPasResolver.AddType El=',GetObjName(El),' El.Parent=',GetObjName(El.Parent));
  1572. {$ENDIF}
  1573. if not (TopScope is TPasIdentifierScope) then
  1574. RaiseInvalidScopeForElement(El);
  1575. AddIdentifier(TPasIdentifierScope(TopScope),El.Name,El,pikSimple);
  1576. end;
  1577. procedure TPasResolver.AddRecordType(El: TPasRecordType);
  1578. begin
  1579. {$IFDEF VerbosePasResolver}
  1580. writeln('TPasResolver.AddRecordType ',GetObjName(El),' Parent=',GetObjName(El.Parent));
  1581. {$ENDIF}
  1582. if not (TopScope is TPasIdentifierScope) then
  1583. RaiseInvalidScopeForElement(El);
  1584. if El.Name<>'' then
  1585. AddIdentifier(TPasIdentifierScope(TopScope),El.Name,El,pikSimple);
  1586. if El.Parent.ClassType<>TPasVariant then
  1587. PushScope(El,TPasRecordScope);
  1588. end;
  1589. procedure TPasResolver.AddVariable(El: TPasVariable);
  1590. begin
  1591. if (El.Name='') then exit; // anonymous var
  1592. {$IFDEF VerbosePasResolver}
  1593. writeln('TPasResolver.AddVariable ',GetObjName(El));
  1594. {$ENDIF}
  1595. if not (TopScope is TPasIdentifierScope) then
  1596. RaiseInvalidScopeForElement(El);
  1597. AddIdentifier(TPasIdentifierScope(TopScope),El.Name,El,pikSimple);
  1598. end;
  1599. procedure TPasResolver.AddProcedure(El: TPasProcedure);
  1600. begin
  1601. {$IFDEF VerbosePasResolver}
  1602. writeln('TPasResolver.AddProcedure ',GetObjName(El));
  1603. {$ENDIF}
  1604. if not (TopScope is TPasIdentifierScope) then
  1605. RaiseInvalidScopeForElement(El);
  1606. AddIdentifier(TPasIdentifierScope(TopScope),El.Name,El,pikProc);
  1607. PushScope(El,TPasProcedureScope);
  1608. end;
  1609. procedure TPasResolver.AddArgument(El: TPasArgument);
  1610. begin
  1611. if (El.Name='') then
  1612. RaiseInternalError(GetObjName(El));
  1613. {$IFDEF VerbosePasResolver}
  1614. writeln('TPasResolver.AddArgument ',GetObjName(El));
  1615. {$ENDIF}
  1616. if not (TopScope is TPasProcedureScope) then
  1617. RaiseInvalidScopeForElement(El);
  1618. AddIdentifier(TPasProcedureScope(TopScope),El.Name,El,pikSimple);
  1619. end;
  1620. procedure TPasResolver.AddFunctionResult(El: TPasResultElement);
  1621. begin
  1622. if TopScope.ClassType<>TPasProcedureScope then
  1623. RaiseInvalidScopeForElement(El);
  1624. AddIdentifier(TPasProcedureScope(TopScope),ResolverResultVar,El,pikSimple);
  1625. end;
  1626. procedure TPasResolver.AddExceptOn(El: TPasImplExceptOn);
  1627. begin
  1628. PushScope(El,TPasExceptOnScope);
  1629. end;
  1630. procedure TPasResolver.StartProcedureBody(El: TProcedureBody);
  1631. begin
  1632. if El=nil then ;
  1633. // ToDo: check if all nested forward procs are resolved
  1634. CheckTopScope(TPasProcedureScope);
  1635. end;
  1636. procedure TPasResolver.WriteScopes;
  1637. var
  1638. i: Integer;
  1639. Scope: TPasScope;
  1640. begin
  1641. writeln('TPasResolver.WriteScopes ScopeCount=',ScopeCount);
  1642. for i:=ScopeCount-1 downto 0 do
  1643. begin
  1644. Scope:=Scopes[i];
  1645. writeln(' ',i,'/',ScopeCount,' ',GetObjName(Scope));
  1646. Scope.WriteIdentifiers(' ');
  1647. end;
  1648. end;
  1649. constructor TPasResolver.Create;
  1650. begin
  1651. inherited Create;
  1652. FDefaultScope:=TPasDefaultScope.Create;
  1653. PushScope(FDefaultScope);
  1654. end;
  1655. function TPasResolver.CreateElement(AClass: TPTreeElement; const AName: String;
  1656. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  1657. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  1658. var
  1659. aScanner: TPascalScanner;
  1660. SrcPos: TPasSourcePos;
  1661. begin
  1662. // get source position for good error messages
  1663. aScanner:=CurrentParser.Scanner;
  1664. if (ASourceFilename='') or StoreSrcColumns then
  1665. begin
  1666. SrcPos.FileName:=aScanner.CurFilename;
  1667. SrcPos.Row:=aScanner.CurRow;
  1668. SrcPos.Column:=aScanner.CurColumn;
  1669. end
  1670. else
  1671. begin
  1672. SrcPos.FileName:=ASourceFilename;
  1673. SrcPos.Row:=ASourceLinenumber;
  1674. SrcPos.Column:=0;
  1675. end;
  1676. Result:=CreateElement(AClass,AName,AParent,AVisibility,SrcPos);
  1677. end;
  1678. function TPasResolver.CreateElement(AClass: TPTreeElement; const AName: String;
  1679. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  1680. const ASrcPos: TPasSourcePos): TPasElement;
  1681. var
  1682. El: TPasElement;
  1683. SrcY: integer;
  1684. begin
  1685. {$IFDEF VerbosePasResolver}
  1686. writeln('TPasResolver.CreateElement ',AClass.ClassName,' Name=',AName,' Parent=',GetObjName(AParent),' (',ASrcPos.Row,',',ASrcPos.Column,')');
  1687. {$ENDIF}
  1688. if (AParent=nil) and (FRootElement<>nil)
  1689. and (AClass<>TPasUnresolvedTypeRef) then
  1690. RaiseInternalError('TPasResolver.CreateElement more than one root element Class="'+AClass.ClassName+'" Root='+GetObjName(FRootElement));
  1691. if ASrcPos.FileName='' then
  1692. RaiseInternalError('TPasResolver.CreateElement missing filename');
  1693. SrcY:=ASrcPos.Row;
  1694. if StoreSrcColumns then
  1695. begin
  1696. if (ASrcPos.Column<ParserMaxEmbeddedColumn)
  1697. and (SrcY<ParserMaxEmbeddedRow) then
  1698. SrcY:=-(SrcY*ParserMaxEmbeddedColumn+ASrcPos.Column);
  1699. end;
  1700. // create element
  1701. El:=AClass.Create(AName,AParent);
  1702. FLastElement:=El;
  1703. Result:=FLastElement;
  1704. El.Visibility:=AVisibility;
  1705. El.SourceFilename:=ASrcPos.FileName;
  1706. El.SourceLinenumber:=SrcY;
  1707. if FRootElement=nil then
  1708. FRootElement:=Result;
  1709. // create scope
  1710. if (AClass=TPasVariable)
  1711. or (AClass=TPasConst)
  1712. or (AClass=TPasProperty) then
  1713. AddVariable(TPasVariable(El))
  1714. else if AClass=TPasArgument then
  1715. AddArgument(TPasArgument(El))
  1716. else if AClass=TPasUnresolvedTypeRef then
  1717. else if (AClass=TPasAliasType)
  1718. or (AClass=TPasProcedureType)
  1719. or (AClass=TPasFunctionType) then
  1720. AddType(TPasType(El))
  1721. else if AClass=TPasRecordType then
  1722. AddRecordType(TPasRecordType(El))
  1723. else if AClass=TPasVariant then
  1724. else if AClass.InheritsFrom(TPasProcedure) then
  1725. AddProcedure(TPasProcedure(El))
  1726. else if AClass=TPasResultElement then
  1727. AddFunctionResult(TPasResultElement(El))
  1728. else if AClass=TProcedureBody then
  1729. StartProcedureBody(TProcedureBody(El))
  1730. else if AClass=TPasImplExceptOn then
  1731. AddExceptOn(TPasImplExceptOn(El))
  1732. else if AClass=TPasImplLabelMark then
  1733. else if AClass=TPasOverloadedProc then
  1734. else if (AClass=TInterfaceSection)
  1735. or (AClass=TImplementationSection)
  1736. or (AClass=TProgramSection)
  1737. or (AClass=TLibrarySection) then
  1738. AddSection(TPasSection(El))
  1739. else if (AClass=TPasModule)
  1740. or (AClass=TPasProgram)
  1741. or (AClass=TPasLibrary) then
  1742. AddModule(TPasModule(El))
  1743. else if AClass.InheritsFrom(TPasExpr) then
  1744. else if AClass.InheritsFrom(TPasImplBlock) then
  1745. else
  1746. RaiseNotYetImplemented(El);
  1747. end;
  1748. function TPasResolver.FindElement(const AName: String): TPasElement;
  1749. begin
  1750. //writeln('TPasResolver.FindElement Name="',AName,'"');
  1751. Result:=FindFirstElement(AName,LastElement);
  1752. end;
  1753. function TPasResolver.FindFirstElement(const AName: String;
  1754. ErrorPosEl: TPasElement): TPasElement;
  1755. var
  1756. FindFirstData: TFindFirstElementData;
  1757. Abort: boolean;
  1758. begin
  1759. //writeln('TPasResolver.FindIdentifier Name="',AName,'"');
  1760. Result:=Nil;
  1761. Abort:=false;
  1762. FindFirstData:=Default(TFindFirstElementData);
  1763. IterateElements(AName,@OnFindFirstElement,@FindFirstData,Abort);
  1764. Result:=FindFirstData.Found;
  1765. if Result<>nil then exit;
  1766. RaiseIdentifierNotFound(AName,ErrorPosEl);
  1767. end;
  1768. procedure TPasResolver.IterateElements(const aName: string;
  1769. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  1770. var Abort: boolean);
  1771. var
  1772. i: Integer;
  1773. Scope: TPasScope;
  1774. begin
  1775. for i:=FScopeCount-1 downto 0 do
  1776. begin
  1777. Scope:=Scopes[i];
  1778. Scope.IterateElements(AName,OnIterateElement,Data,Abort);
  1779. if Abort then
  1780. exit;
  1781. if Scope is TPasSubScope then break;
  1782. end;
  1783. end;
  1784. procedure TPasResolver.FinishScope(ScopeType: TPasScopeType; El: TPasElement);
  1785. begin
  1786. case ScopeType of
  1787. stModule: FinishModule(El as TPasModule);
  1788. stUsesList: FinishUsesList;
  1789. stTypeSection: FinishTypeSection;
  1790. stTypeDef: FinishTypeDef(El as TPasType);
  1791. stProcedure: FinishProcedure;
  1792. stProcedureHeader: FinishProcedureHeader;
  1793. stExceptOnExpr: FinishExceptOnExpr;
  1794. stExceptOnStatement: FinishExceptOnStatement;
  1795. else
  1796. RaiseMsg(nNotYetImplemented,sNotYetImplemented+' FinishScope',[IntToStr(ord(ScopeType))],nil);
  1797. end;
  1798. end;
  1799. class procedure TPasResolver.UnmangleSourceLineNumber(LineNumber: integer; out
  1800. Line, Column: integer);
  1801. begin
  1802. Line:=Linenumber;
  1803. Column:=0;
  1804. if Line<0 then begin
  1805. Line:=-Line;
  1806. Column:=Line mod ParserMaxEmbeddedColumn;
  1807. Line:=Line div ParserMaxEmbeddedColumn;
  1808. end;
  1809. end;
  1810. class function TPasResolver.GetElementSourcePosStr(El: TPasElement): string;
  1811. var
  1812. Line, Column: integer;
  1813. begin
  1814. if El=nil then exit('nil');
  1815. UnmangleSourceLineNumber(El.SourceLinenumber,Line,Column);
  1816. Result:=El.SourceFilename+'('+IntToStr(Line);
  1817. if Column>0 then
  1818. Result:=Result+','+IntToStr(Column);
  1819. Result:=Result+')';
  1820. end;
  1821. destructor TPasResolver.Destroy;
  1822. begin
  1823. Clear;
  1824. PopScope; // free default scope
  1825. inherited Destroy;
  1826. end;
  1827. procedure TPasResolver.Clear;
  1828. var
  1829. Data: TResolveData;
  1830. begin
  1831. // clear stack, keep DefaultScope
  1832. while (FScopeCount>0) and (FTopScope<>DefaultScope) do
  1833. PopScope;
  1834. // clear CustomData
  1835. while FLastCreatedData<>nil do
  1836. begin
  1837. Data:=FLastCreatedData;
  1838. Data.Element.CustomData:=nil;
  1839. FLastCreatedData:=Data.Next;
  1840. Data.Free;
  1841. end;
  1842. end;
  1843. procedure TPasResolver.AddObjFPCBuiltInIdentifiers(BaseTypes: TResolveBaseTypes
  1844. );
  1845. var
  1846. bt: TResolveBaseType;
  1847. begin
  1848. for bt in BaseTypes do
  1849. AddIdentifier(FDefaultScope,BaseTypeNames[bt],
  1850. TPasUnresolvedSymbolRef.Create(BaseTypeNames[bt],nil),pikCustom);
  1851. end;
  1852. function TPasResolver.CreateReference(DeclEl, RefEl: TPasElement
  1853. ): TResolvedReference;
  1854. procedure RaiseAlreadySet;
  1855. var
  1856. FormerDeclEl: TPasElement;
  1857. begin
  1858. writeln('RaiseAlreadySet RefEl=',GetObjName(RefEl),' DeclEl=',GetObjName(DeclEl));
  1859. writeln(' RefEl at ',GetElementSourcePosStr(RefEl));
  1860. writeln(' RefEl.CustomData=',GetObjName(RefEl.CustomData));
  1861. if RefEl.CustomData is TResolvedReference then
  1862. begin
  1863. FormerDeclEl:=TResolvedReference(RefEl.CustomData).Declaration;
  1864. writeln(' TResolvedReference(RefEl.CustomData).Declaration=',GetObjName(FormerDeclEl),
  1865. ' IsSame=',FormerDeclEl=DeclEl);
  1866. end;
  1867. RaiseInternalError('TPasResolver.CreateReference customdata<>nil');
  1868. end;
  1869. begin
  1870. if RefEl.CustomData<>nil then
  1871. RaiseAlreadySet;
  1872. {$IFDEF VerbosePasResolver}
  1873. writeln('TPasResolver.CreateReference RefEl=',GetObjName(RefEl),' DeclEl=',GetObjName(DeclEl));
  1874. {$ENDIF}
  1875. Result:=TResolvedReference.Create;
  1876. Result.Element:=RefEl;
  1877. Result.Owner:=Self;
  1878. Result.Next:=FLastCreatedData;
  1879. Result.Declaration:=DeclEl;
  1880. FLastCreatedData:=Result;
  1881. RefEl.CustomData:=Result;
  1882. end;
  1883. function TPasResolver.CreateScope(El: TPasElement; ScopeClass: TPasScopeClass
  1884. ): TPasScope;
  1885. begin
  1886. if El.CustomData<>nil then
  1887. raise EPasResolve.Create('TPasResolver.CreateScope customdata<>nil');
  1888. {$IFDEF VerbosePasResolver}
  1889. writeln('TPasResolver.CreateScope El=',GetObjName(El),' ScopeClass=',ScopeClass.ClassName);
  1890. {$ENDIF}
  1891. Result:=ScopeClass.Create;
  1892. Result.Element:=El;
  1893. Result.Owner:=Self;
  1894. Result.Next:=FLastCreatedData;
  1895. FLastCreatedData:=Result;
  1896. El.CustomData:=Result;
  1897. end;
  1898. procedure TPasResolver.PopScope;
  1899. var
  1900. Scope: TPasScope;
  1901. begin
  1902. if FScopeCount=0 then
  1903. RaiseInternalError('PopScope');
  1904. {$IFDEF VerbosePasResolver}
  1905. //writeln('TPasResolver.PopScope ',FScopeCount,' ',FTopScope<>nil,' IsDefault=',FTopScope=FDefaultScope);
  1906. writeln('TPasResolver.PopScope ',FTopScope.ClassName,' IsStoredInElement=',FTopScope.IsStoredInElement,' Element=',GetObjName(FTopScope.Element));
  1907. {$ENDIF}
  1908. dec(FScopeCount);
  1909. if not FTopScope.IsStoredInElement then
  1910. begin
  1911. Scope:=FScopes[FScopeCount];
  1912. if Scope.Element<>nil then
  1913. Scope.Element.CustomData:=nil;
  1914. if Scope=FDefaultScope then
  1915. FDefaultScope:=nil;
  1916. Scope.Free;
  1917. FScopes[FScopeCount]:=nil;
  1918. end;
  1919. if FScopeCount>0 then
  1920. FTopScope:=FScopes[FScopeCount-1]
  1921. else
  1922. FTopScope:=nil;
  1923. end;
  1924. procedure TPasResolver.PushScope(Scope: TPasScope);
  1925. begin
  1926. if Scope=nil then
  1927. RaiseInternalError('TPasResolver.PushScope nil');
  1928. if length(FScopes)=FScopeCount then
  1929. SetLength(FScopes,FScopeCount*2+10);
  1930. FScopes[FScopeCount]:=Scope;
  1931. inc(FScopeCount);
  1932. FTopScope:=Scope;
  1933. {$IFDEF VerbosePasResolver}
  1934. writeln('TPasResolver.PushScope ScopeCount=',ScopeCount,' ',GetObjName(FTopScope),' IsDefault=',FDefaultScope=FTopScope);
  1935. {$ENDIF}
  1936. end;
  1937. procedure TPasResolver.SetLastMsg(MsgType: TMessageType; MsgNumber: integer;
  1938. const Fmt: String; Args: array of const; Element: TPasElement);
  1939. begin
  1940. FLastMsgType := MsgType;
  1941. FLastMsgNumber := MsgNumber;
  1942. FLastMsgPattern := Fmt;
  1943. FLastMsg := Format(Fmt,Args);
  1944. FLastElement := Element;
  1945. CreateMsgArgs(FLastMsgArgs,Args);
  1946. end;
  1947. procedure TPasResolver.RaiseMsg(MsgNumber: integer; const Fmt: String;
  1948. Args: array of const; ErrorPosEl: TPasElement);
  1949. var
  1950. E: EPasResolve;
  1951. begin
  1952. SetLastMsg(mtError,MsgNumber,Fmt,Args,ErrorPosEl);
  1953. E:=EPasResolve.Create(FLastMsg);
  1954. E.PasElement:=ErrorPosEl;
  1955. E.MsgNumber:=MsgNumber;
  1956. E.Args:=FLastMsgArgs;
  1957. raise E;
  1958. end;
  1959. procedure TPasResolver.RaiseNotYetImplemented(El: TPasElement; Msg: string);
  1960. var
  1961. s: String;
  1962. begin
  1963. s:=sNotYetImplemented;
  1964. if Msg<>'' then
  1965. s:=s+Msg;
  1966. RaiseMsg(nNotYetImplemented,s,[GetObjName(El)],El);
  1967. end;
  1968. procedure TPasResolver.RaiseInternalError(const Msg: string);
  1969. begin
  1970. raise Exception.Create('Internal error: '+Msg);
  1971. end;
  1972. procedure TPasResolver.RaiseInvalidScopeForElement(El: TPasElement;
  1973. const Msg: string);
  1974. var
  1975. i: Integer;
  1976. s: String;
  1977. begin
  1978. s:='invalid scope for "'+GetObjName(El)+'": ';
  1979. for i:=0 to ScopeCount-1 do
  1980. begin
  1981. if i>0 then s:=s+',';
  1982. s:=s+Scopes[i].ClassName;
  1983. end;
  1984. if Msg<>'' then
  1985. s:=s+': '+Msg;
  1986. RaiseInternalError(s);
  1987. end;
  1988. procedure TPasResolver.RaiseIdentifierNotFound(Identifier: string;
  1989. El: TPasElement);
  1990. begin
  1991. {$IFDEF VerbosePasResolver}
  1992. writeln('TPasResolver.RaiseIdentifierNotFound START "',Identifier,'"');
  1993. WriteScopes;
  1994. {$ENDIF}
  1995. RaiseMsg(nIdentifierNotFound,sIdentifierNotFound,[Identifier],El);
  1996. end;
  1997. function TPasResolver.CheckProcCompatibility(Proc: TPasProcedure;
  1998. Params: TParamsExpr; RaiseOnError: boolean): TProcCompatibility;
  1999. var
  2000. ProcArgs: TFPList;
  2001. i, ParamCnt: Integer;
  2002. Param: TPasExpr;
  2003. ParamCompatibility: TProcCompatibility;
  2004. begin
  2005. Result:=pcExact;
  2006. ProcArgs:=Proc.ProcType.Args;
  2007. // check args
  2008. ParamCnt:=length(Params.Params);
  2009. i:=0;
  2010. while i<ParamCnt do
  2011. begin
  2012. Param:=Params.Params[i];
  2013. if i>=ProcArgs.Count then
  2014. begin
  2015. // too many arguments
  2016. if RaiseOnError then
  2017. RaiseMsg(nWrongNumberOfParametersForCallTo,
  2018. sWrongNumberOfParametersForCallTo,[GetProcDesc(Proc)],Param);
  2019. exit(pcIncompatible);
  2020. end;
  2021. {$IFDEF VerbosePasResolver}
  2022. writeln('TPasResolver.CheckProcCompatibility ',i,'/',ParamCnt);
  2023. {$ENDIF}
  2024. ParamCompatibility:=CheckParamCompatibility(Param,TPasArgument(ProcArgs[i]),i+1,RaiseOnError);
  2025. if ParamCompatibility=pcIncompatible then
  2026. exit(pcIncompatible);
  2027. if ord(ParamCompatibility)<ord(Result) then
  2028. Result:=ParamCompatibility;
  2029. inc(i);
  2030. end;
  2031. if (i<ProcArgs.Count) and (TPasArgument(ProcArgs[i]).ValueExpr=nil) then
  2032. begin
  2033. // not enough arguments
  2034. if RaiseOnError then
  2035. // ToDo: position cursor on identifier
  2036. RaiseMsg(nWrongNumberOfParametersForCallTo,
  2037. sWrongNumberOfParametersForCallTo,[GetProcDesc(Proc)],Params.Value);
  2038. exit(pcIncompatible);
  2039. end;
  2040. end;
  2041. function TPasResolver.CheckParamCompatibility(Expr: TPasExpr;
  2042. Param: TPasArgument; ParamNo: integer; RaiseOnError: boolean
  2043. ): TProcCompatibility;
  2044. var
  2045. ExprType, ParamType: TPasResolvedType;
  2046. function ExprCanBeVarParam: boolean;
  2047. begin
  2048. Result:=false;
  2049. if (ExprType.Kind<>rkIdentifier) then exit;
  2050. if ExprType.IdentEl=nil then exit;
  2051. if ExprType.IdentEl.ClassType=TPasVariable then exit(true);
  2052. if (ExprType.IdentEl.ClassType=TPasConst)
  2053. and (TPasConst(ExprType.IdentEl).VarType<>nil) then
  2054. exit(true); // typed const are writable
  2055. end;
  2056. var
  2057. MustFitExactly: Boolean;
  2058. begin
  2059. Result:=pcIncompatible;
  2060. MustFitExactly:=Param.Access in [argVar, argOut];
  2061. GetResolvedType(Expr,not MustFitExactly,ExprType);
  2062. {$IFDEF VerbosePasResolver}
  2063. writeln('TPasResolver.CheckParamCompatibility Expr=',GetTreeDesc(Expr,2),' ResolvedExpr=',GetResolvedTypeDesc(ExprType));
  2064. {$ENDIF}
  2065. if ExprType.Kind=rkNone then
  2066. RaiseInternalError('GetResolvedType returned rkNone for '+GetTreeDesc(Expr));
  2067. if MustFitExactly then
  2068. begin
  2069. // Expr must be a variable
  2070. if not ExprCanBeVarParam then
  2071. begin
  2072. if RaiseOnError then
  2073. RaiseMsg(nVariableIdentifierExpected,sVariableIdentifierExpected,[],Expr);
  2074. exit;
  2075. end;
  2076. end;
  2077. GetResolvedType(Param,not MustFitExactly,ParamType);
  2078. {$IFDEF VerbosePasResolver}
  2079. writeln('TPasResolver.CheckParamCompatibility Param=',GetTreeDesc(Param,2),' ResolvedParam=',GetResolvedTypeDesc(ParamType));
  2080. {$ENDIF}
  2081. if ExprType.Kind=rkNone then
  2082. RaiseInternalError('GetResolvedType returned rkNone for '+GetTreeDesc(Param));
  2083. if (ParamType.TypeEl=nil) and (Param.ArgType<>nil) then
  2084. RaiseInternalError('GetResolvedType returned TypeEl=nil for '+GetTreeDesc(Param));
  2085. if MustFitExactly then
  2086. begin
  2087. if (ParamType.Kind=ExprType.Kind)
  2088. or (ParamType.BaseType=ExprType.BaseType) then
  2089. begin
  2090. if (ParamType.TypeEl<>nil) and (ParamType.TypeEl=ExprType.TypeEl) then
  2091. exit(pcExact);
  2092. end;
  2093. if RaiseOnError then
  2094. RaiseMsg(nIncompatibleTypeArgNoVarParamMustMatchExactly,
  2095. sIncompatibleTypeArgNoVarParamMustMatchExactly,
  2096. [ParamNo,GetTypeDesc(ExprType.TypeEl),GetTypeDesc(ParamType.TypeEl)],
  2097. Expr);
  2098. exit(pcIncompatible);
  2099. end;
  2100. // check if the Expr can be converted to Param
  2101. case ParamType.Kind of
  2102. rkIdentifier,
  2103. rkExpr:
  2104. if ExprType.Kind in [rkExpr,rkIdentifier] then
  2105. begin
  2106. if ParamType.TypeEl=nil then
  2107. begin
  2108. // ToDo: untyped parameter
  2109. end
  2110. else if ParamType.BaseType=ExprType.BaseType then
  2111. begin
  2112. // ToDo: check btFile, btText
  2113. exit(pcExact); // same base type, maybe not same type name (e.g. longint and integer)
  2114. end
  2115. else if (ParamType.BaseType in btAllNumbers)
  2116. and (ExprType.BaseType in btAllNumbers) then
  2117. exit(pcCompatible) // ToDo: range check for Expr
  2118. else if (ParamType.BaseType in btAllBooleans)
  2119. and (ExprType.BaseType in btAllBooleans) then
  2120. exit(pcCompatible)
  2121. else if (ParamType.BaseType in btAllStrings)
  2122. and (ExprType.BaseType in btAllStrings) then
  2123. exit(pcCompatible) // ToDo: check Expr if Param=btChar/btWideChar
  2124. else if (ParamType.BaseType in btAllFloats)
  2125. and (ExprType.BaseType in btAllFloats) then
  2126. exit(pcCompatible)
  2127. else if ExprType.BaseType=btNil then
  2128. begin
  2129. if ParamType.BaseType=btPointer then
  2130. exit(pcExact);
  2131. // ToDo: allow classes and custom pointers
  2132. end
  2133. else
  2134. exit(pcIncompatible);
  2135. end;
  2136. //rkArrayOf: ;
  2137. //rkPointer: ;
  2138. else
  2139. end;
  2140. RaiseNotYetImplemented(Expr,':TPasResolver.CheckParamCompatibility: Param='+GetResolvedTypeDesc(ParamType)+' '+GetResolvedTypeDesc(ExprType));
  2141. end;
  2142. procedure TPasResolver.GetResolvedType(El: TPasElement; SkipTypeAlias: boolean; out
  2143. ResolvedType: TPasResolvedType);
  2144. var
  2145. bt: TResolveBaseType;
  2146. begin
  2147. ResolvedType:=Default(TPasResolvedType);
  2148. if El=nil then
  2149. exit;
  2150. if El.ClassType=TPrimitiveExpr then
  2151. begin
  2152. case TPrimitiveExpr(El).Kind of
  2153. pekIdent:
  2154. begin
  2155. if El.CustomData is TResolvedReference then
  2156. GetResolvedType(TResolvedReference(El.CustomData).Declaration,SkipTypeAlias,ResolvedType)
  2157. else
  2158. RaiseNotYetImplemented(El,': cannot resolve this');
  2159. end;
  2160. pekNumber:
  2161. // ToDo: check if btByte, btSmallInt, ...
  2162. SetResolvedTypeExpr(ResolvedType,btLongint,TPrimitiveExpr(El));
  2163. pekString:
  2164. SetResolvedTypeExpr(ResolvedType,btString,TPrimitiveExpr(El));
  2165. //pekSet:
  2166. pekNil:
  2167. SetResolvedTypeExpr(ResolvedType,btNil,TPrimitiveExpr(El));
  2168. pekBoolConst:
  2169. SetResolvedTypeExpr(ResolvedType,btBoolean,TPrimitiveExpr(El));
  2170. //pekRange:
  2171. //pekUnary:
  2172. //pekBinary:
  2173. //pekFuncParams:
  2174. //pekArrayParams:
  2175. //pekListOfExp:
  2176. //pekInherited:
  2177. //pekSelf:
  2178. else
  2179. RaiseNotYetImplemented(El,': cannot resolve this');
  2180. end;
  2181. end
  2182. else if El.ClassType=TPasUnresolvedSymbolRef then
  2183. begin
  2184. // built-in type
  2185. for bt in TResolveBaseType do
  2186. if CompareText(BaseTypeNames[bt],El.Name)=0 then
  2187. begin
  2188. SetResolvedType(ResolvedType,rkIdentifier,bt,nil,TPasUnresolvedSymbolRef(El));
  2189. break;
  2190. end;
  2191. end
  2192. else if El.ClassType=TPasAliasType then
  2193. // e.f. 'var a: b' -> resolve b
  2194. GetResolvedType(TPasTypeAliasType(El).DestType,true,ResolvedType)
  2195. else if (El.ClassType=TPasTypeAliasType) and SkipTypeAlias then
  2196. // e.g. 'type a = type b;' -> resolve b
  2197. GetResolvedType(TPasTypeAliasType(El).DestType,true,ResolvedType)
  2198. else if (El.ClassType=TPasVariable) or (El.ClassType=TPasConst)
  2199. or (El.ClassType=TPasProperty) then
  2200. begin
  2201. // e.g. 'var a:b' -> resolve b, use a as IdentEl
  2202. GetResolvedType(TPasVariable(El).VarType,SkipTypeAlias,ResolvedType);
  2203. ResolvedType.IdentEl:=El;
  2204. end
  2205. else if El.ClassType=TPasArgument then
  2206. begin
  2207. if TPasArgument(El).ArgType=nil then
  2208. // untyped parameter
  2209. SetResolvedType(ResolvedType,rkIdentifier,btUntyped,El,nil)
  2210. else
  2211. begin
  2212. // typed parameter -> use param as IdentEl, resolve type
  2213. GetResolvedType(TPasArgument(El).ArgType,SkipTypeAlias,ResolvedType);
  2214. ResolvedType.IdentEl:=El;
  2215. end;
  2216. end
  2217. else
  2218. RaiseNotYetImplemented(El,': cannot resolve this');
  2219. end;
  2220. { TPasIdentifierScope }
  2221. procedure TPasIdentifierScope.OnClearItem(Item, Dummy: pointer);
  2222. var
  2223. PasIdentifier: TPasIdentifier absolute Item;
  2224. Ident: TPasIdentifier;
  2225. begin
  2226. if Dummy=nil then ;
  2227. //writeln('TPasIdentifierScope.OnClearItem ',PasIdentifier.Identifier+':'+PasIdentifier.ClassName);
  2228. while PasIdentifier<>nil do
  2229. begin
  2230. Ident:=PasIdentifier;
  2231. PasIdentifier:=PasIdentifier.NextSameIdentifier;
  2232. Ident.Free;
  2233. end;
  2234. end;
  2235. procedure TPasIdentifierScope.OnWriteItem(Item, Dummy: pointer);
  2236. var
  2237. PasIdentifier: TPasIdentifier absolute Item;
  2238. Prefix: String;
  2239. begin
  2240. Prefix:=AnsiString(Dummy);
  2241. while PasIdentifier<>nil do
  2242. begin
  2243. writeln(Prefix,'Identifier="',PasIdentifier.Identifier,'" Element=',GetObjName(PasIdentifier.Element));
  2244. PasIdentifier:=PasIdentifier.NextSameIdentifier;
  2245. end;
  2246. end;
  2247. procedure TPasIdentifierScope.InternalAdd(Item: TPasIdentifier);
  2248. var
  2249. Index: Integer;
  2250. OldItem: TPasIdentifier;
  2251. LoName: ShortString;
  2252. begin
  2253. LoName:=lowercase(Item.Identifier);
  2254. Index:=FItems.FindIndexOf(LoName);
  2255. //writeln(' Index=',Index);
  2256. if Index>=0 then
  2257. begin
  2258. // insert LIFO - last in, first out
  2259. OldItem:=TPasIdentifier(FItems.List^[Index].Data);
  2260. Item.NextSameIdentifier:=OldItem;
  2261. FItems.List^[Index].Data:=Item;
  2262. end
  2263. else
  2264. FItems.Add(LoName, Item);
  2265. end;
  2266. constructor TPasIdentifierScope.Create;
  2267. begin
  2268. FItems:=TFPHashList.Create;
  2269. end;
  2270. destructor TPasIdentifierScope.Destroy;
  2271. begin
  2272. FItems.ForEachCall(@OnClearItem,nil);
  2273. FItems.Clear;
  2274. FreeAndNil(FItems);
  2275. inherited Destroy;
  2276. end;
  2277. function TPasIdentifierScope.FindIdentifier(const Identifier: String
  2278. ): TPasIdentifier;
  2279. var
  2280. LoName: ShortString;
  2281. begin
  2282. LoName:=lowercase(Identifier);
  2283. Result:=TPasIdentifier(FItems.Find(LoName));
  2284. end;
  2285. function TPasIdentifierScope.AddIdentifier(const Identifier: String;
  2286. El: TPasElement; const Kind: TPasIdentifierKind): TPasIdentifier;
  2287. var
  2288. Item: TPasIdentifier;
  2289. begin
  2290. //writeln('TPasIdentifierScope.AddIdentifier Identifier="',Identifier,'" El=',GetObjName(El));
  2291. Item:=TPasIdentifier.Create;
  2292. Item.Identifier:=Identifier;
  2293. Item.Element:=El;
  2294. Item.Kind:=Kind;
  2295. InternalAdd(Item);
  2296. //writeln('TPasIdentifierScope.AddIdentifier END');
  2297. Result:=Item;
  2298. end;
  2299. function TPasIdentifierScope.FindElement(const aName: string): TPasElement;
  2300. var
  2301. Item: TPasIdentifier;
  2302. begin
  2303. //writeln('TPasIdentifierScope.FindElement "',aName,'"');
  2304. Item:=FindIdentifier(aName);
  2305. if Item=nil then
  2306. Result:=nil
  2307. else
  2308. Result:=Item.Element;
  2309. //writeln('TPasIdentifierScope.FindElement Found="',GetObjName(Result),'"');
  2310. end;
  2311. procedure TPasIdentifierScope.IterateElements(const aName: string;
  2312. const OnIterateElement: TIterateScopeElement; Data: Pointer;
  2313. var Abort: boolean);
  2314. var
  2315. Item: TPasIdentifier;
  2316. begin
  2317. Item:=FindIdentifier(aName);
  2318. while Item<>nil do
  2319. begin
  2320. // writeln('TPasIdentifierScope.IterateElements ',Item.Identifier,' ',GetObjName(Item.Element));
  2321. OnIterateElement(Item.Element,Self,Data,Abort);
  2322. if Abort then exit;
  2323. Item:=Item.NextSameIdentifier;
  2324. end;
  2325. end;
  2326. procedure TPasIdentifierScope.WriteIdentifiers(Prefix: string);
  2327. begin
  2328. inherited WriteIdentifiers(Prefix);
  2329. Prefix:=Prefix+' ';
  2330. FItems.ForEachCall(@OnWriteItem,Pointer(Prefix));
  2331. end;
  2332. end.