1 using System;
2 using System.Windows;
3 using System.IO;
4 using System.Collections;
5 using System.Xml.Serialization;
6 using Cm.Views;
7
8 class MainWindow : Window
9 {
10 public MainWindow() : base("Abstract Syntax Tree Viewer")
11 {
12 UniquePtr<MenuBar> menuBar(new MenuBar());
13 UniquePtr<MenuItem> fileItem(new MenuItem("&File"));
14 UniquePtr<MenuItem> openItem(new MenuItem("&Open..."));
15 openItem->SetShortcut(Keys.f3);
16 openItem->ClickEvent().AddHandler(OpenClick);
17 fileItem->AddMenuItem(openItem.Release());
18 fileItem->AddMenuItem(new MenuItemSeparator());
19 UniquePtr<MenuItem> exitMenuItem(new MenuItem("E&xit"));
20 exitMenuItem->SetShortcut(cast<Keys>(Keys.altModifier | Keys.f4));
21 exitMenuItem->ClickEvent().AddHandler(ExitClick);
22 fileItem->AddMenuItem(exitMenuItem.Release());
23 menuBar->AddMenuItem(fileItem.Release());
24 UniquePtr<MenuItem> viewItem(new MenuItem("&View"));
25 UniquePtr<MenuItem> updateItem(new MenuItem("&Update tree view"));
26 updateItem->SetShortcut(cast<Keys>(Keys.controlModifier | Keys.u));
27 updateItem->ClickEvent().AddHandler(UpdateClick);
28 viewItem->AddMenuItem(updateItem.Release());
29 menuBar->AddMenuItem(viewItem.Release());
30 AddChild(menuBar.Release());
31 UniquePtr<SplitContainer> verticalSplitContainer;
32 UniquePtr<LogView> logView;
33 if (Debug.Log())
34 {
35 verticalSplitContainer.Reset(new SplitContainer(Orientation.vertical, 400, Point(0, 0), Size(0, 0), Dock.fill, Anchors.none));
36 logView.Reset(new LogView());
37 logView->SetScrollSubject();
38 Application.SetLogView(logView.Get());
39 UniquePtr<Control> borderedLogView(new BorderedControl(logView.Release(), BorderStyle.style3D, Point(0, 0), Size(0, 0), Dock.none, Anchors.none));
40 UniquePtr<Control> scrollableLogView(new ScrollableControl(borderedLogView.Release(), Point(0, 0), Size(0, 0), Dock.fill, Anchors.none));
41 verticalSplitContainer->Pane2Container()->AddChild(scrollableLogView.Release());
42 }
43 UniquePtr<SplitContainer> horizontalSplitContainer(new SplitContainer(Orientation.horizontal, 600, Point(0, 0), Size(0, 0), Dock.fill, Anchors.none));
44 treeView = new TreeView(TreeViewCreateParams(TreeViewControlCreateParams(ControlCreateParams().Defaults())).Defaults());
45
46 treeView->NodeDoubleClickEvent().AddHandler(TreeViewNodeDoubleClick);
47 treeView->SetScrollSubject();
48 treeView->NodeEnterEvent().AddHandler(TreeViewNodeEnter);
49 treeView->NodeLeaveEvent().AddHandler(TreeViewNodeLeave);
50 treeView->NodeSelectedEvent().AddHandler(TreeViewNodeSelected);
51 UniquePtr<Control> paddedTreeView(new PaddedControl(treeView, Padding(4, 4, 4, 4), Point(0, 0), Size(0, 0), Dock.none, Anchors.none));
52 UniquePtr<Control> borderedTreeView(new BorderedControl(paddedTreeView.Release(), BorderStyle.style3D, Point(0, 0), Size(0, 0), Dock.none, Anchors.none));
53 UniquePtr<Control> scrollableTreeView(new ScrollableControl(borderedTreeView.Release(), Point(0, 0), Size(0, 0), Dock.fill, Anchors.none));
54 horizontalSplitContainer->Pane1Container()->AddChild(scrollableTreeView.Release());
55 sourceCodeView = new CmajorSourceCodeView(Point(0, 0), Size(0, 0), Dock.fill, Anchors.none);
56 sourceCodeView->SetScrollSubject();
57 sourceCodeView->CaretPosChangedEvent().AddHandler(CaretPosChanged);
58 UniquePtr<Control> paddedSourceCodeView(new PaddedControl(sourceCodeView, Padding(4, 4, 4, 4), Point(0, 0), Size(0, 0), Dock.none, Anchors.none));
59 UniquePtr<Control> borderedSourceCodeView(new BorderedControl(paddedSourceCodeView.Release(), BorderStyle.style3D, Point(0, 0), Size(0, 0), Dock.none, Anchors.none));
60 UniquePtr<Control> scrollableSourceCodeView(new ScrollableControl(borderedSourceCodeView.Release(), Point(0, 0), Size(0, 0), Dock.fill, Anchors.none));
61 horizontalSplitContainer->Pane2Container()->AddChild(scrollableSourceCodeView.Release());
62 if (verticalSplitContainer.IsNull())
63 {
64 AddChild(horizontalSplitContainer.Release());
65 }
66 else
67 {
68 verticalSplitContainer->Pane1Container()->AddChild(horizontalSplitContainer.Release());
69 AddChild(verticalSplitContainer.Release());
70 }
71 }
72 public override void PrintWindowTree(int level)
73 {
74 LogView* log = Application.GetLogView();
75 if (log != null)
76 {
77 log->WriteLine("MainWindow." + Text() + ".handle=" + ToHexString(cast<ulong>(Handle())) + ParentText() + "[" + Rect(Location(), GetSize()).ToString() + "]");
78 }
79 Component* child = Children().FirstChild();
80 while (child != null)
81 {
82 if (child is Control*)
83 {
84 Control* childControl = cast<Control*>(child);
85 childControl->PrintWindowTree(level + 1);
86 }
87 child = child->NextSibling();
88 }
89 }
90 protected override void OnKeyDown(KeyEventArgs& args)
91 {
92 base->OnKeyDown(args);
93 if (!args.handled && args.key == cast<Keys>(Keys.altModifier | Keys.c))
94 {
95 LogView* logView = Application.GetLogView();
96 if (logView != null)
97 {
98 logView->Clear();
99 }
100 }
101 }
102 private void ExitClick()
103 {
104 Close();
105 }
106 private void OpenClick()
107 {
108 try
109 {
110 List<Pair<string, string>> descriptionFilterPairs;
111 descriptionFilterPairs.Add(Pair<string, string>("Cmajor source files (*.cm)", "*.cm"));
112 string initialDirectory;
113 const char* cmajorRoot = RtGetEnvironmentVariable("CMAJOR_ROOT");
114 string defaultFilePath;
115 if (cmajorRoot != null && *cmajorRoot != '\0')
116 {
117 initialDirectory = cmajorRoot;
118 }
119 string filePath;
120 string currentDirectory;
121 List<string> fileNames;
122 bool selected = System.Windows.API.GetOpenFileName(Handle(), descriptionFilterPairs, initialDirectory, defaultFilePath, ".cm",
123 OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST, currentDirectory, fileNames);
124 if (selected)
125 {
126 if (!fileNames.IsEmpty())
127 {
128 filePath = Path.Combine(currentDirectory, fileNames[0]);
129 }
130 if (!filePath.IsEmpty() && File.Exists(filePath))
131 {
132 treeView->SetRoot(null);
133 content = ToUtf32(File.ReadAllText(filePath));
134 lexer = CmajorLexer(content.Chars(), content.Chars() + content.Length(), filePath, 0);
135 Cm.Parser.ParsingContext ctx;
136 compileUnit = CompileUnitParser.Parse(lexer, &ctx);
137 SyntaxTreeBuilder syntaxTreeBuilder(lexer);
138 compileUnit->Accept(syntaxTreeBuilder);
139 indexNodeMap = syntaxTreeBuilder.GetIndexNodeMap();
140 for (const Pair<int, TreeViewNode*>& p : indexNodeMap)
141 {
142 indexNodeList.Add(p);
143 }
144 Sort(indexNodeList.Begin(), indexNodeList.End());
145 nodeIndexMap = syntaxTreeBuilder.GetNodeIndexMap();
146 treeView->SetRoot(syntaxTreeBuilder.GetRoot());
147 sourceCodeView->SetTextContent(content);
148 sourceCodeView->SetFocus();
149 }
150 else
151 {
152 throw Exception("file path is empty or does not exist");
153 }
154 }
155 }
156 catch (const Exception& ex)
157 {
158 MessageBox.Show(ex.Message());
159 }
160 }
161 private void TreeViewNodeDoubleClick(TreeViewNodeMouseClickEventArgs& args)
162 {
163 TreeViewNode* node = args.node;
164 switch (node->GetState())
165 {
166 case TreeViewNode.State.collapsed: node->ExpandAll(); break;
167 case TreeViewNode.State.expanded: node->CollapseAll(); break;
168 }
169 }
170 private void TreeViewNodeEnter(TreeViewNodeEventArgs& args)
171 {
172 TreeViewNode* treeViewNode = args.node;
173 if (treeViewNode->Data() != null)
174 {
175 Cm.Ast.Node* node = cast<Cm.Ast.Node*>(treeViewNode->Data());
176 SyntaxNodeAttributeExtractor attributeExtractor;
177 node->Accept(attributeExtractor);
178 treeView->ShowToolTipWindow(attributeExtractor.s, treeViewNode);
179 }
180 }
181 private void TreeViewNodeLeave(TreeViewNodeEventArgs& args)
182 {
183 TreeViewNode* node = args.node;
184 treeView->HideToolTipWindow();
185 }
186 private void TreeViewNodeSelected(TreeViewNodeEventArgs& args)
187 {
188 TreeViewNode* node = args.node;
189 HashMap<TreeViewNode*, int>.ConstIterator it = nodeIndexMap.CFind(node);
190 if (it != nodeIndexMap.CEnd())
191 {
192 int index = it->second;
193 LogView* logView = Application.GetLogView();
194 if (logView != null)
195 {
196 logView->WriteLine("index=" + ToString(index));
197 }
198 sourceCodeView->SetFocus();
199 sourceCodeView->SetCaretPosByCharIndex(index);
200 }
201 }
202 private void UpdateClick()
203 {
204 int caretLine = sourceCodeView->CaretLine();
205 int caretColumn = sourceCodeView->CaretColumn();
206 int index = sourceCodeView->GetCharIndex(caretLine, caretColumn);
207 if (index != -1)
208 {
209 Pair<int, TreeViewNode*> x(index, null);
210 List<Pair<int, TreeViewNode*>>.ConstIterator it = LowerBound(indexNodeList.CBegin(), indexNodeList.CEnd(), x);
211 if (it != indexNodeList.CBegin() && it == indexNodeList.CEnd())
212 {
213 --it;
214 }
215 int i = -1;
216 if (it != indexNodeList.CEnd())
217 {
218 int i = it->first;
219 if (i > index)
220 {
221 if (it != indexNodeList.CBegin())
222 {
223 --it;
224 }
225 }
226 }
227 if (it != indexNodeList.CEnd())
228 {
229 TreeViewNode* node = it->second;
230 treeView->Root()->CollapseAll();
231 TreeViewNode* p = node;
232 while (p != null)
233 {
234 p->Expand();
235 p = p->Parent();
236 }
237 treeView->Invalidate();
238 treeView->Update();
239 node->EnsureVisible();
240 treeView->Invalidate();
241 }
242 }
243 }
244 private void CaretPosChanged()
245 {
246 int caretLine = sourceCodeView->CaretLine();
247 int caretColumn = sourceCodeView->CaretColumn();
248 LogView* logView = Application.GetLogView();
249 if (logView != null)
250 {
251 logView->WriteLine("caret: (" + ToString(caretLine) + ", " + ToString(caretColumn) + ")");
252 }
253 }
254 private TreeView* treeView;
255 private CmajorSourceCodeView* sourceCodeView;
256 private ustring content;
257 private CmajorLexer lexer;
258 private UniquePtr<Cm.Ast.CompileUnitNode> compileUnit;
259 private HashMap<int, TreeViewNode*> indexNodeMap;
260 private List<Pair<int, TreeViewNode*>> indexNodeList;
261 private HashMap<TreeViewNode*, int> nodeIndexMap;
262 }
263
264 int main()
265 {
266 try
267 {
268
269
270
271
272
273 MainWindow mainWindow;
274 mainWindow.SetSmallIcon(Application.GetResourceManager().GetIcon("astviewer.icon"));
275 if (Debug.WindowTree())
276 {
277 mainWindow.PrintWindowTree(0);
278 }
279 int exitCode = Application.Run(mainWindow);
280 return exitCode;
281 }
282 catch (const Exception& ex)
283 {
284 MessageBox.Show(ex.Message(), "Error", null, cast<MessageBoxType>(MessageBoxType.MB_OK | MessageBoxType.MB_ICONSTOP));
285 try
286 {
287 StreamWriter errorWriter = File.CreateText("error.txt");
288 errorWriter << ex.ToString() << endl();
289 }
290 catch (const Exception&)
291 {
292 }
293 return 1;
294 }
295 return 0;
296 }