You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

ContainerEntity.java 14 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /*
  2. MIT License
  3. Copyright (c) 2018-2019 Gang ZHANG
  4. Permission is hereby granted, free of charge, to any person obtaining a copy
  5. of this software and associated documentation files (the "Software"), to deal
  6. in the Software without restriction, including without limitation the rights
  7. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the Software is
  9. furnished to do so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in all
  11. copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18. SOFTWARE.
  19. */
  20. package depends.entity;
  21. import depends.entity.repo.EntityRepo;
  22. import depends.relations.IBindingResolver;
  23. import depends.relations.Relation;
  24. import multilang.depends.util.file.TemporaryFile;
  25. import org.slf4j.Logger;
  26. import org.slf4j.LoggerFactory;
  27. import java.io.*;
  28. import java.lang.ref.WeakReference;
  29. import java.util.*;
  30. /**
  31. * ContainerEntity for example file, class, method, etc. they could contain
  32. * vars, functions, ecpressions, type parameters, etc.
  33. */
  34. public abstract class ContainerEntity extends DecoratedEntity {
  35. private static final Logger logger = LoggerFactory.getLogger(ContainerEntity.class);
  36. private ArrayList<VarEntity> vars;
  37. private ArrayList<FunctionEntity> functions;
  38. WeakReference<HashMap<Object, Expression>> expressionWeakReference;
  39. private ArrayList<Expression> expressionList;
  40. private int expressionCount = 0;
  41. private Collection<GenericName> mixins;
  42. private Collection<ContainerEntity> resolvedMixins;
  43. private ArrayList<VarEntity> vars() {
  44. if (vars==null)
  45. vars = new ArrayList<>();
  46. return this.vars;
  47. }
  48. private Collection<GenericName> mixins() {
  49. if (mixins==null)
  50. mixins = new ArrayList<>();
  51. return this.mixins;
  52. }
  53. private ArrayList<FunctionEntity> functions() {
  54. if (functions==null)
  55. functions = new ArrayList<>();
  56. return this.functions;
  57. }
  58. public ContainerEntity() {
  59. }
  60. public ContainerEntity(GenericName rawName, Entity parent, Integer id) {
  61. super(rawName, parent, id);
  62. }
  63. public void addVar(VarEntity var) {
  64. if (logger.isDebugEnabled()) {
  65. logger.debug("var found: " + var.getRawName() + ":" + var.getRawType());
  66. }
  67. this.vars().add(var);
  68. }
  69. public ArrayList<VarEntity> getVars() {
  70. if (vars==null)
  71. return new ArrayList<>();
  72. return this.vars();
  73. }
  74. public void addFunction(FunctionEntity functionEntity) {
  75. this.functions().add(functionEntity);
  76. }
  77. public ArrayList<FunctionEntity> getFunctions() {
  78. if (functions==null)
  79. return new ArrayList<>();
  80. return this.functions;
  81. }
  82. public HashMap<Object, Expression> expressions() {
  83. if (expressionWeakReference==null)
  84. expressionWeakReference= new WeakReference<HashMap<Object, Expression>>(new HashMap<>());
  85. HashMap<Object, Expression> r = expressionWeakReference.get();
  86. if (r==null) return new HashMap<>();
  87. return r;
  88. }
  89. public void addExpression(Object key, Expression expression) {
  90. expressions().put(key, expression);
  91. expressionList().add(expression);
  92. expressionCount = expressionList.size();
  93. }
  94. public boolean containsExpression(Object key) {
  95. return expressions().containsKey(key);
  96. }
  97. /**
  98. * For all data in the class, infer their types. Should be override in
  99. * sub-classes
  100. */
  101. public void inferLocalLevelEntities(IBindingResolver bindingResolver) {
  102. super.inferLocalLevelEntities(bindingResolver);
  103. for (VarEntity var : this.vars()) {
  104. if (var.getParent()!=this) {
  105. var.inferLocalLevelEntities(bindingResolver);
  106. }
  107. }
  108. for (FunctionEntity func : this.getFunctions()) {
  109. if (func.getParent()!=this) {
  110. func.inferLocalLevelEntities(bindingResolver);
  111. }
  112. }
  113. if (bindingResolver.isEagerExpressionResolve()) {
  114. reloadExpression(bindingResolver.getRepo());
  115. resolveExpressions(bindingResolver);
  116. cacheExpressions();
  117. }
  118. resolvedMixins = identiferToContainerEntity(bindingResolver, getMixins());
  119. }
  120. private Collection<GenericName> getMixins() {
  121. if (mixins==null)
  122. return new ArrayList<>();
  123. return mixins;
  124. }
  125. private Collection<ContainerEntity> identiferToContainerEntity(IBindingResolver bindingResolver, Collection<GenericName> identifiers) {
  126. if (identifiers.size()==0) return null;
  127. ArrayList<ContainerEntity> r = new ArrayList<>();
  128. for (GenericName identifier : identifiers) {
  129. Entity entity = bindingResolver.resolveName(this, identifier, true);
  130. if (entity == null) {
  131. continue;
  132. }
  133. if (entity instanceof ContainerEntity)
  134. r.add((ContainerEntity) entity);
  135. }
  136. return r;
  137. }
  138. /**
  139. * Resolve all expression's type
  140. *
  141. * @param bindingResolver
  142. */
  143. public void resolveExpressions(IBindingResolver bindingResolver) {
  144. if (this instanceof FunctionEntity) {
  145. ((FunctionEntity)this).linkReturnToLastExpression();
  146. }
  147. if (expressionList==null) return;
  148. if(expressionList.size()>10000) return;
  149. for (Expression expression : expressionList) {
  150. // 1. if expression's type existed, break;
  151. if (expression.getType() != null)
  152. continue;
  153. if (expression.isDot()) { // wait for previous
  154. continue;
  155. }
  156. if (expression.getRawType() == null && expression.getIdentifier() == null)
  157. continue;
  158. // 2. if expression's rawType existed, directly infer type by rawType
  159. // if expression's rawType does not existed, infer type based on identifiers
  160. if (expression.getRawType() != null) {
  161. expression.setType(bindingResolver.inferTypeFromName(this, expression.getRawType()), null, bindingResolver);
  162. if (expression.getType() != null) {
  163. continue;
  164. }
  165. }
  166. if (expression.getIdentifier() != null) {
  167. Entity entity = bindingResolver.resolveName(this, expression.getIdentifier(), true);
  168. String composedName = expression.getIdentifier().toString();
  169. Expression theExpr = expression;
  170. if (entity==null) {
  171. while(theExpr.getParent()!=null && theExpr.getParent().isDot()) {
  172. theExpr = theExpr.getParent();
  173. if (theExpr.getIdentifier()==null) break;
  174. composedName = composedName + "." + theExpr.getIdentifier().toString();
  175. entity = bindingResolver.resolveName(this, GenericName.build(composedName), true);
  176. if (entity!=null)
  177. break;
  178. }
  179. }
  180. if (entity != null) {
  181. expression.setType(entity.getType(), entity, bindingResolver);
  182. continue;
  183. }
  184. if (expression.isCall()) {
  185. List<Entity> funcs = this.lookupFunctionInVisibleScope(expression.getIdentifier());
  186. if (funcs != null) {
  187. for (Entity func:funcs) {
  188. expression.setType(func.getType(), func, bindingResolver);
  189. }
  190. }
  191. } else {
  192. Entity varEntity = this.lookupVarInVisibleScope(expression.getIdentifier());
  193. if (varEntity != null) {
  194. expression.setType(varEntity.getType(), varEntity, bindingResolver);
  195. }
  196. }
  197. }
  198. }
  199. }
  200. public void cacheChildExpressions() {
  201. cacheExpressions();
  202. for (Entity child:getChildren()) {
  203. if (child instanceof ContainerEntity) {
  204. ((ContainerEntity)child).cacheChildExpressions();
  205. }
  206. }
  207. }
  208. public void cacheExpressions() {
  209. if (expressionWeakReference==null) return;
  210. if (expressionList==null) return;
  211. this.expressions().clear();
  212. this.expressionWeakReference.clear();
  213. cacheExpressionListToFile();
  214. this.expressionList.clear();
  215. this.expressionList=null;
  216. this.expressionList = new ArrayList<>();
  217. }
  218. public void clearExpressions() {
  219. if (expressionWeakReference==null) return;
  220. if (expressionList==null) return;
  221. this.expressions().clear();
  222. this.expressionWeakReference.clear();
  223. this.expressionList.clear();
  224. this.expressionList=null;
  225. this.expressionList = new ArrayList<>();
  226. this.expressionUseList = null;
  227. }
  228. private void cacheExpressionListToFile() {
  229. if (expressionCount ==0) return;
  230. try {
  231. FileOutputStream fileOut = new FileOutputStream(TemporaryFile.getInstance().exprPath(this.id));
  232. ObjectOutputStream out = new ObjectOutputStream(fileOut);
  233. out.writeObject(this.expressionList);
  234. out.close();
  235. fileOut.close();
  236. } catch (IOException e) {
  237. e.printStackTrace();
  238. }
  239. }
  240. @SuppressWarnings("unchecked")
  241. public void reloadExpression(EntityRepo repo) {
  242. if (expressionCount ==0) return;
  243. try
  244. {
  245. FileInputStream fileIn = new FileInputStream(TemporaryFile.getInstance().exprPath(this.id));
  246. ObjectInputStream in = new ObjectInputStream(fileIn);
  247. expressionList = (ArrayList<Expression>) in.readObject();
  248. if (expressionList==null) expressionList = new ArrayList<>();
  249. for (Expression expr:expressionList) {
  250. expr.reload(repo,expressionList);
  251. }
  252. in.close();
  253. fileIn.close();
  254. }catch(IOException | ClassNotFoundException i)
  255. {
  256. return;
  257. }
  258. }
  259. public List<Expression> expressionList() {
  260. if (expressionList==null)
  261. expressionList = new ArrayList<>();
  262. return expressionList;
  263. }
  264. public boolean containsExpression() {
  265. return expressions().size() > 0;
  266. }
  267. /**
  268. * The entry point of lookup functions. It will treat multi-declare entities and
  269. * normal entity differently. - for multiDeclare entity, it means to lookup all
  270. * entities - for normal entity, it means to lookup entities from current scope
  271. * still root
  272. *
  273. * @param functionName
  274. * @return
  275. */
  276. public List<Entity> lookupFunctionInVisibleScope(GenericName functionName) {
  277. List<Entity> functions = new ArrayList<>();
  278. if (this.getMutliDeclare() != null) {
  279. for (Entity fromEntity : this.getMutliDeclare().getEntities()) {
  280. Entity f = lookupFunctionBottomUpTillTopContainer(functionName, fromEntity);
  281. if (f != null) {
  282. functions.add(f);
  283. return functions;
  284. }
  285. }
  286. } else {
  287. ContainerEntity fromEntity = this;
  288. Entity f = lookupFunctionBottomUpTillTopContainer(functionName, fromEntity);
  289. if (f != null) {
  290. functions.add(f);
  291. return functions;
  292. }
  293. }
  294. return null;
  295. }
  296. /**
  297. * lookup function bottom up till the most outside container
  298. *
  299. * @param functionName
  300. * @param fromEntity
  301. * @return
  302. */
  303. private Entity lookupFunctionBottomUpTillTopContainer(GenericName functionName, Entity fromEntity) {
  304. while (fromEntity != null) {
  305. if (fromEntity instanceof ContainerEntity) {
  306. FunctionEntity func = ((ContainerEntity) fromEntity).lookupFunctionLocally(functionName);
  307. if (func != null)
  308. return func;
  309. }
  310. for (Entity child:this.getChildren()) {
  311. if (child instanceof AliasEntity) {
  312. if (child.getRawName().equals(functionName))
  313. return child;
  314. }
  315. }
  316. fromEntity = (ContainerEntity) this.getAncestorOfType(ContainerEntity.class);
  317. }
  318. return null;
  319. }
  320. /**
  321. * lookup function in local entity. It could be override such as the type entity
  322. * (it should also lookup the inherit/implemented types
  323. *
  324. * @param functionName
  325. * @return
  326. */
  327. public FunctionEntity lookupFunctionLocally(GenericName functionName) {
  328. for (FunctionEntity func : getFunctions()) {
  329. if (func.getRawName().equals(functionName))
  330. return func;
  331. }
  332. return null;
  333. }
  334. /**
  335. * The entry point of lookup var. It will treat multi-declare entities and
  336. * normal entity differently. - for multiDeclare entity, it means to lookup all
  337. * entities - for normal entity, it means to lookup entities from current scope
  338. * still root
  339. *
  340. * @param varName
  341. * @return
  342. */
  343. public Entity lookupVarInVisibleScope(GenericName varName) {
  344. ContainerEntity fromEntity = this;
  345. return lookupVarBottomUpTillTopContainer(varName, fromEntity);
  346. }
  347. /**
  348. * To found the var.
  349. *
  350. * @param fromEntity
  351. * @param varName
  352. * @return
  353. */
  354. private Entity lookupVarBottomUpTillTopContainer(GenericName varName, ContainerEntity fromEntity) {
  355. while (fromEntity != null) {
  356. if (fromEntity instanceof ContainerEntity) {
  357. VarEntity var = ((ContainerEntity) fromEntity).lookupVarLocally(varName);
  358. if (var != null)
  359. return var;
  360. }
  361. for (Entity child:this.getChildren()) {
  362. if (child instanceof AliasEntity) {
  363. if (child.getRawName().equals(varName))
  364. return child;
  365. }
  366. }
  367. fromEntity = (ContainerEntity) this.getAncestorOfType(ContainerEntity.class);
  368. }
  369. return null;
  370. }
  371. public VarEntity lookupVarLocally(GenericName varName) {
  372. for (VarEntity var : getVars()) {
  373. if (var.getRawName().equals(varName))
  374. return var;
  375. }
  376. return null;
  377. }
  378. public VarEntity lookupVarLocally(String varName) {
  379. return this.lookupVarLocally(GenericName.build(varName));
  380. }
  381. public void addMixin(GenericName moduleName) {
  382. mixins().add(moduleName);
  383. }
  384. public Collection<ContainerEntity> getResolvedMixins() {
  385. if (resolvedMixins==null) return new ArrayList<>();
  386. return resolvedMixins;
  387. }
  388. HashMap<String,Set<Expression>> expressionUseList = null;
  389. public void addRelation(Expression expression, Relation relation) {
  390. String key = relation.getEntity().qualifiedName+relation.getType();
  391. if (this.expressionUseList==null)
  392. expressionUseList = new HashMap<>();
  393. if (expressionUseList.containsKey(key)){
  394. Set<Expression> expressions = expressionUseList.get(key);
  395. for (Expression expr:expressions){
  396. if (linkedExpr(expr,expression)) return;
  397. }
  398. }else{
  399. expressionUseList.put(key,new HashSet<>());
  400. }
  401. expressionUseList.get(key).add(expression);
  402. super.addRelation(relation);
  403. }
  404. private boolean linkedExpr(Expression a, Expression b) {
  405. Expression parent = a.getParent();
  406. while(parent!=null){
  407. if (parent==b) return true;
  408. parent = parent.getParent();
  409. }
  410. parent = b.getParent();
  411. while(parent!=null){
  412. if (parent==a) return true;
  413. parent = parent.getParent();
  414. }
  415. return false;
  416. }
  417. }

人工智能研发终端

Contributors (2)