PageRenderTime 47ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/dotnet/Resolver.cs

https://bitbucket.org/bartwe/plukc
C# | 995 lines | 909 code | 85 blank | 1 comment | 144 complexity | cce5b82dfa9193ee5419444904174494 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using Compiler.Metadata;
  5. using System.Runtime.InteropServices;
  6. using System.IO;
  7. using System.Threading;
  8. namespace Compiler
  9. {
  10. public class Resolver : IDisposable
  11. {
  12. public class Context
  13. {
  14. public class Entry
  15. {
  16. public string id;
  17. public Identifier name;
  18. public int slot;
  19. public TypeReference type;
  20. public bool readOnly;
  21. }
  22. public Dictionary<Field, bool> fieldWritten = new Dictionary<Field, bool>();
  23. public Dictionary<string, Entry> variables = new Dictionary<string, Entry>();
  24. public Dictionary<int, Entry> varBySlot = new Dictionary<int, Entry>();
  25. public Dictionary<int, bool> variableIncomplete = new Dictionary<int, bool>();
  26. public Dictionary<int, bool> variableWrite = new Dictionary<int, bool>();
  27. public Dictionary<int, bool> variableRead = new Dictionary<int, bool>();
  28. public Dictionary<int, bool> variableUsed = new Dictionary<int, bool>();
  29. public Context parent;
  30. public bool parentReadOnly;
  31. public ImplicitField implicitSlot;
  32. public Dictionary<string, JumpToken> gotos = new Dictionary<string, JumpToken>();
  33. public bool tryContext;
  34. public Parameters contextParameters;
  35. public Context()
  36. {
  37. }
  38. public void Setup(Context parent, bool parentReadOnly)
  39. {
  40. this.parent = parent;
  41. this.parentReadOnly = parentReadOnly;
  42. if (parentReadOnly)
  43. Require.Assigned(parent);
  44. }
  45. public void Reset()
  46. {
  47. fieldWritten.Clear();
  48. variables.Clear();
  49. varBySlot.Clear();
  50. variableIncomplete.Clear();
  51. variableWrite.Clear();
  52. variableRead.Clear();
  53. variableUsed.Clear();
  54. parent = null;
  55. implicitSlot = null;
  56. gotos.Clear();
  57. tryContext = false;
  58. contextParameters = null;
  59. }
  60. public void CheckEmpty()
  61. {
  62. foreach (Field field in fieldWritten.Keys)
  63. Require.True(field.GetModifiers.Static);
  64. Require.True(variables.Count == 0);
  65. Require.True(varBySlot.Count == 0);
  66. Require.True(variableIncomplete.Count == 0);
  67. Require.True(variableWrite.Count == 0);
  68. Require.True(variableRead.Count == 0);
  69. }
  70. public void AddVariable(Identifier name, TypeReference type, int slot, bool readOnly)
  71. {
  72. Require.Assigned(name);
  73. Require.Assigned(type);
  74. if (variables.ContainsKey(name.Data))
  75. throw new CompilerException(name, string.Format(Resource.Culture,
  76. Resource.VariableWithThatNameAlreadyDefined, name.Data));
  77. Entry e = new Entry();
  78. e.id = name.Data;
  79. e.name = name;
  80. e.slot = slot;
  81. e.type = type;
  82. e.readOnly = readOnly;
  83. variables.Add(name.Data, e);
  84. varBySlot.Add(slot, e);
  85. }
  86. public void SetImplicitFields(int slot, TypeReference type)
  87. {
  88. Require.Assigned(type);
  89. Require.Unassigned(implicitSlot);
  90. implicitSlot = new ImplicitField();
  91. implicitSlot.slot = slot;
  92. implicitSlot.type = type;
  93. AssignSlot(slot);
  94. ReadSlot(slot);
  95. }
  96. public void AssignField(Field field)
  97. {
  98. fieldWritten[field] = true;
  99. }
  100. public bool IsFieldAssigned(Field field)
  101. {
  102. return fieldWritten.ContainsKey(field);
  103. }
  104. public void AssignSlot(int slot)
  105. {
  106. variableWrite[slot] = true;
  107. }
  108. public void WriteSlot(ILocation location, int slot)
  109. {
  110. Context c = this;
  111. Entry e = null;
  112. bool readOnly = false;
  113. while (c != null)
  114. {
  115. if (c.varBySlot.TryGetValue(slot, out e))
  116. {
  117. readOnly |= e.readOnly;
  118. break;
  119. }
  120. e = null;
  121. readOnly |= c.parentReadOnly;
  122. c = c.parent;
  123. }
  124. if (e == null)
  125. throw new CompilerException(location, "Internal compiler error, failed to resolve slot for marked as written: " + slot);
  126. if (readOnly)
  127. throw new CompilerException(location, string.Format(Resource.Culture, Resource.CannotAssignReadOnlyVar, e.name.Data));
  128. variableWrite[slot] = true;
  129. }
  130. public void IncompleteSlot(int slot, bool complete)
  131. {
  132. variableRead.Remove(slot);
  133. variableWrite.Remove(slot);
  134. variableIncomplete[slot] = complete;
  135. }
  136. public void ReadSlot(int slot)
  137. {
  138. variableRead[slot] = true;
  139. }
  140. public void Close()
  141. {
  142. if (Program.AllowUnreadAndUnusedVariablesFieldsAndExpressions)
  143. return;
  144. foreach (Entry e in variables.Values)
  145. {
  146. if (variableIncomplete.ContainsKey(e.slot))
  147. continue;
  148. if (!variableWrite.ContainsKey(e.slot))
  149. {
  150. if (!variableUsed.ContainsKey(e.slot))
  151. throw new CompilerException(e.name, string.Format(Resource.Culture, Resource.UnusedVariable, e.name.Data));
  152. }
  153. else if (!variableRead.ContainsKey(e.slot))
  154. throw new CompilerException(e.name, string.Format(Resource.Culture, Resource.VariableAssignedButUnused, e.name.Data));
  155. }
  156. }
  157. public void Merge(Context context)
  158. {
  159. foreach (Entry v in context.variables.Values)
  160. {
  161. context.variableWrite.Remove(v.slot);
  162. context.variableRead.Remove(v.slot);
  163. }
  164. foreach (KeyValuePair<int, bool> e in context.variableWrite)
  165. {
  166. variableWrite[e.Key] = e.Value;
  167. variableUsed[e.Key] = true;
  168. }
  169. foreach (KeyValuePair<int, bool> e in context.variableRead)
  170. {
  171. variableRead[e.Key] = e.Value;
  172. variableUsed[e.Key] = true;
  173. }
  174. foreach (KeyValuePair<Field, bool> e in context.fieldWritten)
  175. fieldWritten[e.Key] = e.Value;
  176. foreach (int key in context.variableUsed.Keys)
  177. variableUsed[key] = true;
  178. }
  179. public void MergeReads(Context context)
  180. {
  181. foreach (Entry v in context.variables.Values)
  182. {
  183. context.variableRead.Remove(v.slot);
  184. }
  185. foreach (Entry v in context.variables.Values)
  186. context.variableRead.Remove(v.slot);
  187. foreach (KeyValuePair<int, bool> e in context.variableWrite)
  188. variableUsed[e.Key] = true;
  189. foreach (KeyValuePair<int, bool> e in context.variableRead)
  190. {
  191. variableRead[e.Key] = e.Value;
  192. variableUsed[e.Key] = true;
  193. }
  194. foreach (int key in context.variableUsed.Keys)
  195. variableUsed[key] = true;
  196. }
  197. public void Intersects(Context left, Context right)
  198. {
  199. foreach (Entry v in left.variables.Values)
  200. {
  201. left.variableWrite.Remove(v.slot);
  202. left.variableRead.Remove(v.slot);
  203. }
  204. foreach (Entry v in right.variables.Values)
  205. {
  206. right.variableWrite.Remove(v.slot);
  207. right.variableRead.Remove(v.slot);
  208. }
  209. foreach (KeyValuePair<int, bool> e in left.variableRead)
  210. variableRead[e.Key] = e.Value;
  211. foreach (KeyValuePair<int, bool> e in right.variableRead)
  212. variableRead[e.Key] = e.Value;
  213. foreach (KeyValuePair<int, bool> e in left.variableWrite)
  214. {
  215. if (right.variableWrite.ContainsKey(e.Key))
  216. variableWrite[e.Key] = true;
  217. }
  218. foreach (KeyValuePair<Field, bool> e in left.fieldWritten)
  219. {
  220. if (right.fieldWritten.ContainsKey(e.Key))
  221. fieldWritten[e.Key] = true;
  222. }
  223. }
  224. public void RegisterTryContext()
  225. {
  226. Require.False(tryContext);
  227. tryContext = true;
  228. }
  229. public void RegisterGoto(string token, JumpToken gotoToken)
  230. {
  231. Require.False(gotos.ContainsKey(token));
  232. gotos.Add(token, gotoToken);
  233. }
  234. public void SetContextParameters(Parameters parameters)
  235. {
  236. Require.Assigned(parameters);
  237. Require.Unassigned(contextParameters);
  238. contextParameters = parameters;
  239. }
  240. }
  241. private DefinitionCollection store;
  242. private Stack<Context> contexts = new Stack<Context>();
  243. private Set<Definition> resolvedDefinitions = new Set<Definition>();
  244. private List<string> paths;
  245. private bool finisedResolving;
  246. private Set<string> imports = new Set<string>();
  247. private Dictionary<string, TypeReference> resolveCache = new Dictionary<string, TypeReference>();
  248. private Dictionary<string, TypeReference> localResolveCache = new Dictionary<string, TypeReference>();
  249. private Set<string> parsedFiles;
  250. private Stack<Context> recycledContexts = new Stack<Context>();
  251. private Prefetcher prefetcher;
  252. public Resolver(DefinitionCollection store, IEnumerable<string> paths, bool ignoreFileCase)
  253. {
  254. if (store == null)
  255. throw new ArgumentNullException("store");
  256. if (paths == null)
  257. throw new ArgumentNullException("paths");
  258. this.store = store;
  259. Set<string> dp = new Set<string>();
  260. foreach (string p in paths)
  261. dp.Put(Path.GetFullPath(p + Path.DirectorySeparatorChar));
  262. this.paths = new List<string>(dp);
  263. if (Program.CaseSensitiveFileSystem)
  264. parsedFiles = new Set<string>(StringComparer.Ordinal);
  265. else
  266. parsedFiles = new Set<string>(StringComparer.InvariantCultureIgnoreCase);
  267. SetupVoid();
  268. prefetcher = new Prefetcher(ignoreFileCase);
  269. }
  270. public void Dispose()
  271. {
  272. if (prefetcher != null)
  273. {
  274. prefetcher.Dispose();
  275. prefetcher = null;
  276. }
  277. }
  278. public void SetImportsContext(Set<string> imports)
  279. {
  280. this.imports = imports;
  281. localResolveCache.Clear();
  282. }
  283. private void LoadType(TypeName type)
  284. {
  285. if (!type.HasNamespace)
  286. throw new Exception("Should not load anything but namespaced types.");
  287. if (store.HasDefinition(type) || store.HasTemplateDefinition(type))
  288. return;
  289. if (finisedResolving)
  290. throw new InvalidOperationException("internal compiler error: Cannot load additional type: " + type.Data + " when the resolve phase has been completed.");
  291. string filename = type.PrimaryName.Data.Replace('.', Path.DirectorySeparatorChar) + ".pluk";
  292. Set<string> files = new Set<string>();
  293. foreach (string path in paths)
  294. {
  295. string fullFileName = path + filename;
  296. if (parsedFiles.Contains(fullFileName))
  297. continue;
  298. prefetcher.Enqueue(fullFileName);
  299. files.Add(fullFileName);
  300. }
  301. while (files.Count > 0)
  302. {
  303. string fullFileName = prefetcher.FirstFromSet(files);
  304. files.Remove(fullFileName);
  305. using (StreamReader sr = prefetcher.Request(fullFileName))
  306. {
  307. parsedFiles.Add(fullFileName);
  308. if (sr != null)
  309. {
  310. if (Program.WriteFileNameOnRead)
  311. Console.WriteLine("parsing: " + fullFileName);
  312. Syntax syntax = new Syntax(store, fullFileName, sr);
  313. syntax.Parse();
  314. }
  315. }
  316. }
  317. }
  318. public string ParseFile(string fileName)
  319. {
  320. fileName = Path.GetFullPath(fileName);
  321. if (parsedFiles.Contains(fileName))
  322. return null;
  323. parsedFiles.Add(fileName);
  324. using (StreamReader sr = prefetcher.Request(fileName))
  325. {
  326. Syntax syntax = new Syntax(store, fileName, sr);
  327. return syntax.Parse();
  328. }
  329. }
  330. public void ResolveEverything(Generator generator)
  331. {
  332. List<Definition> toVisit = new List<Definition>();
  333. do
  334. {
  335. toVisit.AddRange(store);
  336. toVisit.RemoveAll(resolvedDefinitions.Contains);
  337. foreach (Definition definition in toVisit)
  338. {
  339. definition.Resolve(generator);
  340. resolvedDefinitions.Add(definition);
  341. }
  342. } while (toVisit.Count > 0);
  343. }
  344. public void PrepareEverything(Generator generator)
  345. {
  346. finisedResolving = true;
  347. Set<Definition> visited = new Set<Definition>();
  348. List<Definition> toVisit = new List<Definition>();
  349. do
  350. {
  351. toVisit.AddRange(store);
  352. toVisit.RemoveAll(visited.Contains);
  353. foreach (Definition definition in toVisit)
  354. {
  355. definition.PrepareExtends();
  356. visited.Add(definition);
  357. }
  358. } while (toVisit.Count > 0);
  359. visited.Clear();
  360. toVisit.Clear();
  361. do
  362. {
  363. toVisit.AddRange(store);
  364. toVisit.RemoveAll(visited.Contains);
  365. foreach (Definition definition in toVisit)
  366. {
  367. definition.BeforePrepare();
  368. visited.Add(definition);
  369. }
  370. } while (toVisit.Count > 0);
  371. visited.Clear();
  372. toVisit.Clear();
  373. do
  374. {
  375. toVisit.AddRange(store);
  376. toVisit.RemoveAll(visited.Contains);
  377. foreach (Definition definition in toVisit)
  378. {
  379. definition.Prepare(generator);
  380. visited.Add(definition);
  381. }
  382. } while (toVisit.Count > 0);
  383. visited.Clear();
  384. toVisit.Clear();
  385. do
  386. {
  387. toVisit.AddRange(store);
  388. toVisit.RemoveAll(visited.Contains);
  389. foreach (Definition definition in toVisit)
  390. {
  391. definition.PrepareNestedConstructors(generator);
  392. visited.Add(definition);
  393. }
  394. } while (toVisit.Count > 0);
  395. }
  396. public void GenerateEverything(Generator generator)
  397. {
  398. finisedResolving = true;
  399. Set<Definition> visited = new Set<Definition>();
  400. Set<Definition> toVisit = new Set<Definition>();
  401. Set<DefinitionTypeReference> extends = new Set<DefinitionTypeReference>();
  402. do
  403. {
  404. toVisit.Clear();
  405. toVisit.AddRange(store);
  406. toVisit.RemoveAll(visited.Contains);
  407. foreach (Definition definition in toVisit)
  408. {
  409. extends.Clear();
  410. definition.GetExtends(extends);
  411. bool ready = true;
  412. foreach (DefinitionTypeReference tr in extends)
  413. if (!visited.Contains(tr.Definition))
  414. ready = false;
  415. if (ready)
  416. {
  417. definition.Generate(generator);
  418. visited.Add(definition);
  419. }
  420. }
  421. } while (toVisit.Count > 0);
  422. }
  423. public void CallStaticInitializers(Generator generator)
  424. {
  425. foreach (Definition definition in store.Definitions)
  426. {
  427. definition.UpdateDependsOrder();
  428. }
  429. List<Definition> sortedDefinitions = new List<Definition>(store.Definitions);
  430. sortedDefinitions.Sort(SortDefinitions);
  431. foreach (Definition def in sortedDefinitions)
  432. if (!def.StaticInitializerFunctionPointer.IsNull)
  433. generator.Assembler.CallDirect(def.StaticInitializerFunctionPointer);
  434. }
  435. private int SortDefinitions(Definition x, Definition y)
  436. {
  437. return -x.DependsOrder.CompareTo(y.DependsOrder);
  438. }
  439. public TypeReference ResolveType(ILocation location, TypeName type)
  440. {
  441. return InnerResolveType(location, type, true);
  442. }
  443. public TypeReference TryResolveType(TypeName type)
  444. {
  445. return InnerResolveType(type, type, false);
  446. }
  447. private TypeReference InnerResolveType(ILocation location, TypeName type, bool throwIfNoMatch)
  448. {
  449. Require.Assigned(location);
  450. if ( type.IsFunction || !type.HasNamespace || (type.TemplateParameters.Count > 0))
  451. {
  452. if (localResolveCache.ContainsKey(type.Data))
  453. {
  454. TypeReference t = localResolveCache[type.Data];
  455. if ((t != null) || (!throwIfNoMatch))
  456. return t;
  457. }
  458. }
  459. else
  460. {
  461. if (resolveCache.ContainsKey(type.Data))
  462. {
  463. TypeReference t = resolveCache[type.Data];
  464. if ((t != null) || (!throwIfNoMatch))
  465. return t;
  466. }
  467. }
  468. TypeReference result;
  469. TypeName original = type;
  470. if (type.Nullable)
  471. {
  472. result = InnerResolveType(location, new TypeName(type, Nullability.NotNullable), throwIfNoMatch);
  473. }
  474. else
  475. {
  476. if (type.IsFunction)
  477. {
  478. result = type.ResolveFunctionType(this);
  479. }
  480. else
  481. {
  482. if (type.HasNamespace)
  483. {
  484. if (type.TemplateParameters.Count > 0)
  485. {
  486. TypeName resolvedInnerName = new TypeName(type.PrimaryName);
  487. resolvedInnerName.SetHasNamespace();
  488. foreach (TypeName templateParameter in type.TemplateParameters)
  489. {
  490. TypeReference t = InnerResolveType(templateParameter, templateParameter, throwIfNoMatch);
  491. if ((!throwIfNoMatch) && (t == null)) return null;
  492. if (t.TypeName.Data.StartsWith("MapBucket"))
  493. {
  494. t = InnerResolveType(templateParameter, templateParameter, throwIfNoMatch);
  495. throw new Exception("boom");
  496. }
  497. resolvedInnerName.AddTemplateParameter(t.TypeName);
  498. }
  499. type = resolvedInnerName;
  500. }
  501. LoadType(type);
  502. if ((!store.HasDefinition(type)) && store.HasTemplateDefinition(type))
  503. {
  504. List<TypeReference> parameters = new List<TypeReference>();
  505. foreach (TypeName templateParameter in type.TemplateParameters)
  506. {
  507. TypeReference t = InnerResolveType(templateParameter, templateParameter, throwIfNoMatch);
  508. if ((!throwIfNoMatch) && (t == null))
  509. return null;
  510. parameters.Add(t);
  511. }
  512. store.InstantiateTemplate(type, parameters);
  513. }
  514. result = ResolveTypeFullyQualified(location, type, throwIfNoMatch);
  515. }
  516. else
  517. {
  518. if (type.TemplateParameters.Count > 0)
  519. {
  520. TypeName outerType = new TypeName(type.PrimaryName);
  521. foreach (TypeName innerName in type.TemplateParameters)
  522. {
  523. TypeReference t = InnerResolveType(location, innerName, throwIfNoMatch);
  524. if ((!throwIfNoMatch) && (t == null)) return null;
  525. outerType.AddTemplateParameter(t.TypeName);
  526. }
  527. type = outerType;
  528. }
  529. if (imports.Count == 0)
  530. imports.Put(""); // when no imports are found, assume baseline system
  531. if (!imports.Contains("pluk.base"))
  532. imports.Put("pluk.base"); // this may seem silly, bit if we come here recursively this avoids a concurrent modifiecation assertion
  533. result = null;
  534. foreach (string ns in imports)
  535. {
  536. TypeName fullname = type.Prefix(ns);
  537. result = InnerResolveType(location, fullname, false);
  538. if (result != null)
  539. {
  540. type = fullname;
  541. break;
  542. }
  543. }
  544. if (result == null)
  545. {
  546. if (throwIfNoMatch)
  547. throw new CompilerException(location, string.Format(Resource.Culture, Resource.NoDefinitionForType, type.DataModifierLess));
  548. }
  549. }
  550. }
  551. }
  552. if (original.Nullable && (!original.IsVoid) && (result != null))
  553. result = new NullableTypeReference(result, new TypeName(result.TypeName, Nullability.ExplicitNullable));
  554. if (result != null)
  555. resolveCache[result.TypeName.Data] = result;
  556. if ((result == null) || original.IsFunction || !original.HasNamespace || (original.TemplateParameters.Count > 0))
  557. {
  558. localResolveCache[original.Data] = result;
  559. }
  560. else
  561. resolveCache[original.Data] = result;
  562. return result;
  563. }
  564. public DefinitionTypeReference ResolveDefinitionType(ILocation location, TypeName type)
  565. {
  566. if (type.Nullable)
  567. type = new TypeName(type, Nullability.NotNullable);
  568. return (DefinitionTypeReference)ResolveType(location, type);
  569. }
  570. private TypeReference ResolveTypeFullyQualified(ILocation location, TypeName type, bool throwIfNoMatch)
  571. {
  572. if ((!type.HasNamespace) || (!store.HasDefinition(type)))
  573. {
  574. if (throwIfNoMatch)
  575. throw new CompilerException(location, string.Format(Resource.Culture, Resource.NoDefinitionForType, type.DataModifierLess));
  576. else
  577. return null;
  578. }
  579. Definition definition = store.FindDefinition(type);
  580. return definition.TypeReference;
  581. }
  582. private string currentFieldName;
  583. public string CurrentFieldName { get { return currentFieldName; } set { currentFieldName = value; } }
  584. Definition currentDefinition;
  585. Definition savedDefinition;
  586. public Definition CurrentDefinition { get { return currentDefinition; } }
  587. public void EnterFakeContext(Definition definition)
  588. {
  589. Require.Assigned(definition);
  590. Require.Assigned(currentDefinition);
  591. Require.Unassigned(savedDefinition);
  592. savedDefinition = currentDefinition;
  593. currentDefinition = definition;
  594. }
  595. public void LeaveFakeContext()
  596. {
  597. Require.Assigned(currentDefinition);
  598. Require.Assigned(savedDefinition);
  599. currentDefinition = savedDefinition;
  600. savedDefinition = null;
  601. }
  602. private Context CreateContext()
  603. {
  604. if (recycledContexts.Count > 0)
  605. return recycledContexts.Pop();
  606. return new Context();
  607. }
  608. public void EnterDefinitionContext(Definition definition)
  609. {
  610. Require.True(contexts.Count == 0);
  611. Require.Unassigned(currentDefinition);
  612. currentDefinition = definition;
  613. Context context = CreateContext();
  614. context.Setup(null, false);
  615. contexts.Push(context);
  616. }
  617. public void EnterContext()
  618. {
  619. Context context = CreateContext();
  620. context.Setup(contexts.Peek(), false);
  621. contexts.Push(context);
  622. }
  623. public void EnterContextParentReadOnly()
  624. {
  625. Context context = CreateContext();
  626. context.Setup(contexts.Peek(), true);
  627. contexts.Push(context);
  628. }
  629. public void LeaveContext()
  630. {
  631. Context context = contexts.Pop();
  632. context.Close();
  633. if (contexts.Count == 0)
  634. currentDefinition = null;
  635. else
  636. contexts.Peek().MergeReads(context);
  637. ReleaseContext(context);
  638. }
  639. public Context LeaveContextAcquire()
  640. {
  641. Context context = contexts.Pop();
  642. context.Close();
  643. if (contexts.Count == 0)
  644. currentDefinition = null;
  645. else
  646. contexts.Peek().MergeReads(context);
  647. return context;
  648. }
  649. public void MergeContext(Context context)
  650. {
  651. contexts.Peek().Merge(context);
  652. }
  653. public void ReleaseContext(Context context)
  654. {
  655. if (recycledContexts.Count < 64)
  656. {
  657. context.Reset();
  658. recycledContexts.Push(context);
  659. }
  660. }
  661. public void LeaveAndMergeContext()
  662. {
  663. Context context = contexts.Pop();
  664. context.Close();
  665. if (contexts.Count == 0)
  666. currentDefinition = null;
  667. else
  668. contexts.Peek().Merge(context);
  669. ReleaseContext(context);
  670. }
  671. public void IntersectContexts(Context left, Context right)
  672. {
  673. contexts.Peek().Intersects(left, right);
  674. }
  675. public void AddVariable(Identifier name, TypeReference type, int slot, bool readOnly)
  676. {
  677. if (name.Data == "this")
  678. Require.True(readOnly);
  679. contexts.Peek().AddVariable(name, type, slot, readOnly);
  680. }
  681. public void SetContextParameters(Parameters parameters)
  682. {
  683. contexts.Peek().SetContextParameters(parameters);
  684. }
  685. public Parameters CurrentContextParameters()
  686. {
  687. foreach (Context context in contexts)
  688. {
  689. if (context.contextParameters != null)
  690. return context.contextParameters;
  691. }
  692. return null;
  693. }
  694. public void RegisterTryContext()
  695. {
  696. contexts.Peek().RegisterTryContext();
  697. }
  698. public void RegisterGoto(string token, JumpToken gotoToken)
  699. {
  700. contexts.Peek().RegisterGoto(token, gotoToken);
  701. }
  702. // returns null if nosuch goto is found (or callable)
  703. public JumpToken FindGoto(string token, out bool tryContext)
  704. {
  705. tryContext = false;
  706. foreach (Context context in contexts)
  707. {
  708. JumpToken result;
  709. if (context.gotos.TryGetValue(token, out result))
  710. return result;
  711. if (context.tryContext)
  712. {
  713. tryContext = true;
  714. }
  715. }
  716. return null;
  717. }
  718. public IEnumerable<Field> AssignedFields
  719. {
  720. get
  721. {
  722. Set<Field> result = new Set<Field>();
  723. foreach (Context context in contexts)
  724. {
  725. foreach (Field f in context.fieldWritten.Keys)
  726. result.Put(f);
  727. }
  728. return result;
  729. }
  730. }
  731. public void SetImplicitFields(int slot, TypeReference type)
  732. {
  733. Require.True(type.IsDefinition || type.IsStatic);
  734. contexts.Peek().SetImplicitFields(slot, type);
  735. }
  736. public TypeReference ResolveSlotType(Identifier name)
  737. {
  738. return FindFirstContextContaining(name).variables[name.Data].type;
  739. }
  740. public int ResolveSlotOffset(Identifier name)
  741. {
  742. return FindFirstContextContaining(name).variables[name.Data].slot;
  743. }
  744. public bool ContainsSlot(Identifier name)
  745. {
  746. foreach (Context context in contexts)
  747. {
  748. if (context.variables.ContainsKey(name.Data))
  749. return true;
  750. }
  751. return false;
  752. }
  753. public class ImplicitField
  754. {
  755. public int slot;
  756. public TypeReference type;
  757. }
  758. public ImplicitField FindImplicitField(Identifier name)
  759. {
  760. foreach (Context context in contexts)
  761. {
  762. if (context.variables.ContainsKey(name.Data))
  763. return null;
  764. if (context.implicitSlot != null)
  765. {
  766. Definition definition;
  767. bool staticRef = false;
  768. if (context.implicitSlot.type is StaticTypeReference)
  769. {
  770. staticRef = true;
  771. definition = ((StaticTypeReference)context.implicitSlot.type).Parent.Definition;
  772. }
  773. else
  774. definition = ((DefinitionTypeReference)context.implicitSlot.type).Definition;
  775. if (definition.HasField(name, staticRef) ||
  776. definition.HasMethod(name, staticRef) ||
  777. definition.HasProperty(name, staticRef))
  778. {
  779. return context.implicitSlot;
  780. }
  781. }
  782. }
  783. return null;
  784. }
  785. private Context FindFirstContextContaining(Identifier name)
  786. {
  787. foreach (Context context in contexts)
  788. {
  789. if (context.variables.ContainsKey(name.Data))
  790. return context;
  791. }
  792. throw new CompilerException(name, string.Format(Resource.Culture, Resource.FailedToResolveVariable, name.Data));
  793. }
  794. public void AssignField(Field field)
  795. {
  796. contexts.Peek().AssignField(field);
  797. }
  798. public bool IsFieldAssigned(Field field)
  799. {
  800. foreach (Context context in contexts)
  801. if (context.fieldWritten.ContainsKey(field))
  802. return true;
  803. return false;
  804. }
  805. public void AssignSlot(int slot)
  806. {
  807. contexts.Peek().AssignSlot(slot);
  808. }
  809. public void CheckContextEmpty()
  810. {
  811. contexts.Peek().CheckEmpty();
  812. }
  813. public void WriteSlot(ILocation location, int slot)
  814. {
  815. contexts.Peek().WriteSlot(location, slot);
  816. }
  817. public void IncompleteSlot(int slot, bool complete)
  818. {
  819. contexts.Peek().IncompleteSlot(slot, complete);
  820. }
  821. public void RetrieveField(ILocation location, Field field)
  822. {
  823. if (currentDefinition == null)
  824. return;
  825. if (field.ParentDefinition != currentDefinition)
  826. return;
  827. if (field.GetModifiers.Static && currentDefinition.StaticFieldsInitialized)
  828. return;
  829. if (!field.GetModifiers.Static && currentDefinition.FieldsInitialized)
  830. return;
  831. foreach (Context context in contexts)
  832. if (context.fieldWritten.ContainsKey(field))
  833. return;
  834. throw new CompilerException(location, string.Format(Resource.Culture, Resource.ObjectNotFullyAssigned, field.ParentDefinition.Name.Data));
  835. }
  836. public void RetrieveSlot(ILocation location, int slot, bool allowIncomplete)
  837. {
  838. bool incomplete = false;
  839. foreach (Context context in contexts)
  840. if (context.variableIncomplete.ContainsKey(slot))
  841. {
  842. if (allowIncomplete)
  843. return;
  844. if (context.variableIncomplete[slot])
  845. return;
  846. incomplete = true;
  847. break;
  848. }
  849. bool written = false;
  850. if (!incomplete)
  851. {
  852. foreach (Context context in contexts)
  853. if (context.variableRead.ContainsKey(slot))
  854. return;
  855. foreach (Context context in contexts)
  856. if (context.variableWrite.ContainsKey(slot))
  857. {
  858. written = true;
  859. break;
  860. }
  861. }
  862. Context.Entry entry = null;
  863. foreach (Context context in contexts)
  864. foreach (Context.Entry v in context.variables.Values)
  865. if (v.slot == slot)
  866. {
  867. entry = v;
  868. break;
  869. }
  870. foreach (Context context in contexts)
  871. if (context.variableIncomplete.ContainsKey(slot))
  872. {
  873. incomplete = true;
  874. break;
  875. }
  876. Require.Assigned(entry);
  877. if (incomplete)
  878. {
  879. if (entry.type.IsDefinition)
  880. {
  881. Definition d = ((DefinitionTypeReference)entry.type).Definition;
  882. if (d.CheckAllFieldsAssigned(location, this, true))
  883. {
  884. IncompleteSlot(slot, true);
  885. return;
  886. }
  887. }
  888. throw new CompilerException(location, string.Format(Resource.Culture, Resource.ObjectNotFullyAssigned, entry.name.Data));
  889. }
  890. else
  891. {
  892. if (written)
  893. {
  894. contexts.Peek().ReadSlot(slot);
  895. }
  896. else
  897. {
  898. throw new CompilerException(location, string.Format(Resource.Culture, Resource.VariableMightNotBeAssigned, entry.name.Data));
  899. }
  900. }
  901. }
  902. private void SetupVoid()
  903. {
  904. Definition definition = new Definition(new NowhereLocation(), new Set<string>(), new Modifiers(new NowhereLocation()));
  905. definition.SetName(new Identifier(new NowhereLocation(), "void"));
  906. definition.Complete();
  907. store.Add(definition);
  908. }
  909. }
  910. }