source: trunk/src/org/expeditee/actions/Javascript2.java@ 708

Last change on this file since 708 was 708, checked in by jts21, 10 years ago

Changes to javascript interpreter, implement detailed error messages

File size: 5.9 KB
Line 
1package org.expeditee.actions;
2
3import java.awt.Color;
4import java.util.Collection;
5import java.util.LinkedList;
6import java.util.List;
7
8import javax.script.ScriptEngine;
9import javax.script.ScriptEngineManager;
10import javax.script.ScriptException;
11
12import org.expeditee.gui.Frame;
13import org.expeditee.gui.FrameIO;
14import org.expeditee.gui.FrameUtils;
15import org.expeditee.gui.MessageBay;
16import org.expeditee.io.flowlayout.XGroupItem;
17import org.expeditee.items.Item;
18import org.expeditee.items.ItemUtils;
19import org.expeditee.items.Text;
20
21/**
22 * Javascript parser.
23 * Works differently to the other Javascript class in that it
24 * parses a frame as a whole rather than parsing individual text items as separate statements
25 *
26 * @author jts21
27 */
28public class Javascript2 {
29
30 public static final String ERROR_FRAMESET = "JavascriptErrors";
31
32 private static ScriptEngineManager sem = new ScriptEngineManager();
33 private static ScriptEngine se = sem.getEngineByMimeType("application/javascript");
34
35 public static synchronized void runFrame(Frame frame, boolean followLinks) throws Exception {
36 Javascript2 js = new Javascript2(frame, followLinks);
37 try {
38 se.eval(js.toString());
39 } catch (ScriptException e) {
40 int lineNumber = e.getLineNumber();
41 if(lineNumber != -1) {
42 CodeLine cl = js.lines.get(lineNumber - 1);
43 Frame errorSourceFrame = cl.item.getParent();
44 if(errorSourceFrame == null) {
45 throw new Exception("Failed to find frame on which error occurred");
46 }
47 Frame errorFrame;
48 String title = "Error parsing \"" + errorSourceFrame.getTitle() + "\" (" + errorSourceFrame.getName() + ")";
49 if(FrameIO.canAccessFrameset(ERROR_FRAMESET)) {
50 errorFrame = FrameIO.CreateFrame(ERROR_FRAMESET, title, null);
51 } else {
52 errorFrame = FrameIO.CreateFrameset(ERROR_FRAMESET, FrameIO.FRAME_PATH);
53 errorFrame.setTitle(title);
54 }
55 Collection<Item> toAdd = errorSourceFrame.getAllItems();
56 toAdd.remove(errorSourceFrame.getTitleItem());
57 toAdd.remove(cl.item);
58 errorFrame.addAllItems(ItemUtils.CopyItems(toAdd));
59 String errorItemText = cl.item.getText().trim();
60 String[] errorItemLines = errorItemText.split("[\\n|\\r]+");
61 int errorLinePos = 0;
62 for(int i = 0; i < cl.line; i++) {
63 errorLinePos += errorItemLines[i].length();
64 }
65 Text beforeErrorItem = errorFrame.addText(cl.item.getX(), cl.item.getY(),
66 errorItemText.substring(0, errorLinePos), null);
67 Text errorItem;
68 errorItem = errorFrame.addText(cl.item.getX(),
69 beforeErrorItem.getY() + beforeErrorItem.getBoundsHeight(),
70 errorItemLines[cl.line], null);
71 errorItem.setBackgroundColor(Color.RED);
72 // todo set width to 80 characters worth
73 for(String line : e.getMessage().split("[\\n|\\r]+")) {
74 errorItem.setTooltip("text: " + line);
75 }
76 errorItem.setTooltip("font: " + Text.MONOSPACED_FONT);
77 errorItem.setTooltip("width: " + 80 * 12);
78 errorLinePos += errorItemLines[cl.line].length();
79 if(++errorLinePos < errorItemText.length()) {
80 errorFrame.addText(cl.item.getX(), errorItem.getY() + errorItem.getBoundsHeight(),
81 errorItemText.substring(errorLinePos + 1), null);
82 }
83 errorFrame.change();
84 FrameIO.SaveFrame(errorFrame);
85 MessageBay.displayMessage("Script failed at line " + lineNumber + " - `" + cl.source + "`",
86 errorFrame.getName(), MessageBay.ERROR_COLOR, true, null);
87 FrameUtils.DisplayFrame(errorFrame, true, true);
88 }
89 }
90 }
91
92 private static final class CodeLine {
93 public Text item;
94 public int line;
95 public String source;
96
97 public CodeLine(Text item, int line, String source) {
98 this.item = item;
99 this.line = line;
100 this.source = source;
101 }
102 }
103
104 private List<Frame> seen = new LinkedList<Frame>();
105 private List<CodeLine> lines = new LinkedList<CodeLine>();
106 private StringBuffer sb = new StringBuffer();
107 private Javascript2(Frame frame, boolean followLinks) {
108 this.parseFrame(frame, followLinks);
109 }
110
111 private void parseFrame(Frame frame, boolean followLinks) {
112 if(frame == null) {
113 return;
114 }
115
116 // make sure we don't get into an infinite loop
117 // TODO: find a smarter way to do this that allows reusing frames but still stops infinite loops?
118 seen.add(frame);
119
120 // get all items on the frame
121 List<Item> y_ordered_items = (List<Item>)frame.getItems();
122 // remove the title item
123 y_ordered_items.remove(frame.getTitleItem());
124
125 XGroupItem toplevel_xgroup = new XGroupItem(frame,y_ordered_items);
126 // ... following on from Steps 1 and 2 in the Constructor in XGroupItem ...
127
128 // Step 3: Reposition any 'out-of-flow' XGroupItems
129 toplevel_xgroup.repositionOutOfFlowGroups(toplevel_xgroup);
130
131 // Step 4: Now add in the remaining (nested) XGroupItems
132 List<XGroupItem> grouped_item_list = toplevel_xgroup.getGroupedItemList();
133 toplevel_xgroup.mapInXGroupItemsRecursive(grouped_item_list);
134
135 // Finally, retrieve linear list of all Items, (ordered, Y by X, allowing for overlap, nested-boxing, and arrow flow)
136 List<Item> overlapping_y_ordered_items = toplevel_xgroup.getYXOverlappingItemList();
137
138 // Loop through the items looking for code and links to new frames
139 for(Item i : overlapping_y_ordered_items) {
140 if(followLinks && i.hasLink()) {
141 Frame child = i.getChild();
142 if(child != null && !seen.contains(child)) {
143 this.parseFrame(child, true);
144 }
145 }
146 if(i instanceof Text && !i.isAnnotation()) {
147 String text = ((Text)i).getText();
148 int lineNumber = 0;
149 for(String line : text.trim().split("[\\n|\\r]+")) {
150 sb.append(line).append("\n");
151 lines.add(new CodeLine((Text)i, lineNumber++, line));
152 }
153 }
154 }
155 }
156
157 public String toString() {
158 return this.sb.toString();
159 }
160
161}
Note: See TracBrowser for help on using the repository browser.