From d84e95a3fe63d59c8f3cf9a3b26d7d235a1fadd6 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 15 May 2012 14:07:20 +0800 Subject: [PATCH 001/127] Enable OcaIDE debugging with variables relating to Camlp4 module. - fix bug 0013 in Mantis bug tracker --- Ocaml/src/ocaml/debugging/OcamlDebugger.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Ocaml/src/ocaml/debugging/OcamlDebugger.java b/Ocaml/src/ocaml/debugging/OcamlDebugger.java index 2bda078..f68a846 100644 --- a/Ocaml/src/ocaml/debugging/OcamlDebugger.java +++ b/Ocaml/src/ocaml/debugging/OcamlDebugger.java @@ -240,6 +240,10 @@ public synchronized void start( commandLineArgs.add("-I"); commandLineArgs.add("_build"); + // add module Camlp4 + commandLineArgs.add("-I"); + commandLineArgs.add("+camlp4"); + // add the root of the project commandLineArgs.add("-I"); commandLineArgs.add(project.getLocation().toOSString()); From 79e71ffa721101817c81f8c30aa5bd599b1bcc98 Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 16 May 2012 14:15:55 +0800 Subject: [PATCH 002/127] set high priority for parsing file in order to find function name --- Ocaml/src/ocaml/debugging/OcamlDebugger.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ocaml/src/ocaml/debugging/OcamlDebugger.java b/Ocaml/src/ocaml/debugging/OcamlDebugger.java index f68a846..4ab1c24 100644 --- a/Ocaml/src/ocaml/debugging/OcamlDebugger.java +++ b/Ocaml/src/ocaml/debugging/OcamlDebugger.java @@ -1125,7 +1125,7 @@ private synchronized String findFunctionContainLine(String filepath, int line) { String functionName = ""; OcamlNewInterfaceParser parser = OcamlNewInterfaceParser.getInstance(); File file = new File(filepath); - Def root = parser.parseFile(file, false); + Def root = parser.parseFile(file, true); List childs = root.children; int i = 0; for (i = 0; i < childs.size(); i++) { From ab47ad285435849e04673c5867ea6beb37e9f6e7 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 29 Oct 2012 10:51:28 +0800 Subject: [PATCH 003/127] merge with upstream --- Ocaml/icons/markOccurrence.gif | Bin Ocaml/icons/shiftLeft.png | Bin Ocaml/icons/shiftRight.png | Bin 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 Ocaml/icons/markOccurrence.gif mode change 100755 => 100644 Ocaml/icons/shiftLeft.png mode change 100755 => 100644 Ocaml/icons/shiftRight.png diff --git a/Ocaml/icons/markOccurrence.gif b/Ocaml/icons/markOccurrence.gif old mode 100755 new mode 100644 diff --git a/Ocaml/icons/shiftLeft.png b/Ocaml/icons/shiftLeft.png old mode 100755 new mode 100644 diff --git a/Ocaml/icons/shiftRight.png b/Ocaml/icons/shiftRight.png old mode 100755 new mode 100644 From a33a7040adfe90d41daa2a6984f635f549642e01 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 30 Oct 2012 20:04:28 +0800 Subject: [PATCH 004/127] fix exception StackOverFlow in pattern maching --- Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java b/Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java index 0e8c683..fe88b67 100644 --- a/Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java +++ b/Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java @@ -24,7 +24,7 @@ public class OcamlAnnotParser { private static final Pattern patternAnnot = Pattern - .compile("\".*.\" (\\d+) (\\d+) (\\d+) \".*?\" (\\d+) (\\d+) (\\d+)\\ntype\\(\\n((?:.|\\n)*?)\\n\\)\\n"); + .compile("\".*.\" (\\d+) (\\d+) (\\d+) \".*?\" (\\d+) (\\d+) (\\d+)\\ntype\\(\\n((?:.)*?)\\n\\)\\n"); /** The type definitions cache */ private static LinkedList cache = new LinkedList(); From e13c1be6bd1413ee274a4bb28de85e5eaec19c99 Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 31 Oct 2012 14:20:20 +0800 Subject: [PATCH 005/127] StackOverFlow exception when parsing annot file that has class definition --- Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java b/Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java index fe88b67..df2228a 100644 --- a/Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java +++ b/Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java @@ -24,7 +24,7 @@ public class OcamlAnnotParser { private static final Pattern patternAnnot = Pattern - .compile("\".*.\" (\\d+) (\\d+) (\\d+) \".*?\" (\\d+) (\\d+) (\\d+)\\ntype\\(\\n((?:.)*?)\\n\\)\\n"); + .compile("\".*.\" (\\d+) (\\d+) (\\d+) \".*?\" (\\d+) (\\d+) (\\d+)\\ntype\\(\\n((?:.*?\\n){0,50}?)\\)\\n"); /** The type definitions cache */ private static LinkedList cache = new LinkedList(); From d2d586f39661cfc9bc32fa396a6c0c348ba07cf1 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 6 Nov 2012 15:13:33 +0800 Subject: [PATCH 006/127] Allow converting spaces <--> tabs in a selected text --- .../actions/ConvertSpacesToTabsAction.java | 36 ++++++++++++++---- .../actions/ConvertTabsToSpacesAction.java | 37 ++++++++++++++----- 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/ConvertSpacesToTabsAction.java b/Ocaml/src/ocaml/editor/actions/ConvertSpacesToTabsAction.java index 93281a3..2836f0f 100644 --- a/Ocaml/src/ocaml/editor/actions/ConvertSpacesToTabsAction.java +++ b/Ocaml/src/ocaml/editor/actions/ConvertSpacesToTabsAction.java @@ -7,7 +7,9 @@ import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; @@ -27,15 +29,33 @@ public void run(IAction action) { IEditorPart editorPart = page.getActiveEditor(); if (editorPart != null) { if (editorPart instanceof OcamlEditor) { - TextEditor editor = (TextEditor) editorPart; - - IEditorInput input = editor.getEditorInput(); - IDocument doc = editor.getDocumentProvider().getDocument(input); - - String result = replaceSpacesByTabs(OcamlEditor.getTabSize(), doc.get()); - try { - doc.replace(0, doc.getLength(), result); + TextEditor editor = (TextEditor) editorPart; + IEditorInput input = editor.getEditorInput(); + IDocument doc = editor.getDocumentProvider().getDocument(input); + + // collect text in the selection and convert + ISelectionProvider selectionProvider = editor.getSelectionProvider(); + TextSelection textSelection = (TextSelection) selectionProvider.getSelection(); + String selectedText = textSelection.getText(); + String newSelectedText = replaceSpacesByTabs(OcamlEditor.getTabSize(), selectedText); + int selectedOffset = textSelection.getOffset(); + + // collect text before the selection + int beforeLength = selectedOffset; + String beforeSelectedText = doc.get(0, beforeLength); + + // collect the text after the selection + int afterOffset = selectedOffset + textSelection.getLength(); + String afterSelectedText = doc.get(afterOffset, doc.getLength() - afterOffset); + + // replace data of document + String newText = beforeSelectedText + newSelectedText + afterSelectedText; + doc.replace(0, doc.getLength(), newText); + + // set the converted text to be selected + TextSelection newTextSelection = new TextSelection(selectedOffset, newSelectedText.length()); + selectionProvider.setSelection(newTextSelection); } catch (BadLocationException e1) { OcamlPlugin.logError("bad location while converting spaces to tabs", e1); return; diff --git a/Ocaml/src/ocaml/editor/actions/ConvertTabsToSpacesAction.java b/Ocaml/src/ocaml/editor/actions/ConvertTabsToSpacesAction.java index 01b3cb1..ef70df3 100644 --- a/Ocaml/src/ocaml/editor/actions/ConvertTabsToSpacesAction.java +++ b/Ocaml/src/ocaml/editor/actions/ConvertTabsToSpacesAction.java @@ -7,7 +7,9 @@ import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; @@ -27,20 +29,37 @@ public void run(IAction action) { IEditorPart editorPart = page.getActiveEditor(); if (editorPart != null) { if (editorPart instanceof TextEditor) { - TextEditor editor = (TextEditor) editorPart; - - IEditorInput input = editor.getEditorInput(); - IDocument document = editor.getDocumentProvider().getDocument(input); - - String result = replaceTabsBySpaces(OcamlEditor.getTabSize(), document.get()); - try { - document.replace(0, document.getLength(), result); + TextEditor editor = (TextEditor) editorPart; + IEditorInput input = editor.getEditorInput(); + IDocument doc = editor.getDocumentProvider().getDocument(input); + + // collect text in the selection and convert + ISelectionProvider selectionProvider = editor.getSelectionProvider(); + TextSelection textSelection = (TextSelection) selectionProvider.getSelection(); + String selectedText = textSelection.getText(); + String newSelectedText = replaceTabsBySpaces(OcamlEditor.getTabSize(), selectedText); + int selectedOffset = textSelection.getOffset(); + + // collect text before the selection + int beforeLength = selectedOffset; + String beforeSelectedText = doc.get(0, beforeLength); + + // collect the text after the selection + int afterOffset = selectedOffset + textSelection.getLength(); + String afterSelectedText = doc.get(afterOffset, doc.getLength() - afterOffset); + + // replace data of document + String newText = beforeSelectedText + newSelectedText + afterSelectedText; + doc.replace(0, doc.getLength(), newText); + + // set the converted text to be selected + TextSelection newTextSelection = new TextSelection(selectedOffset, newSelectedText.length()); + selectionProvider.setSelection(newTextSelection); } catch (BadLocationException e1) { OcamlPlugin.logError("bad location while converting tabs to spaces", e1); return; } - } else MessageDialog.openInformation(window.getShell(), "Ocaml Plugin", "Not implemented for this editor."); From b6a6336820d229ea905253e1d5a76e17047ceb3d Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 6 Nov 2012 15:25:31 +0800 Subject: [PATCH 007/127] check for a valid selection in converting spaces <--> tabs --- Ocaml/src/ocaml/editor/actions/ConvertSpacesToTabsAction.java | 4 ++++ Ocaml/src/ocaml/editor/actions/ConvertTabsToSpacesAction.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Ocaml/src/ocaml/editor/actions/ConvertSpacesToTabsAction.java b/Ocaml/src/ocaml/editor/actions/ConvertSpacesToTabsAction.java index 2836f0f..e6f85c2 100644 --- a/Ocaml/src/ocaml/editor/actions/ConvertSpacesToTabsAction.java +++ b/Ocaml/src/ocaml/editor/actions/ConvertSpacesToTabsAction.java @@ -38,6 +38,10 @@ public void run(IAction action) { ISelectionProvider selectionProvider = editor.getSelectionProvider(); TextSelection textSelection = (TextSelection) selectionProvider.getSelection(); String selectedText = textSelection.getText(); + if (selectedText.equals("")) { + MessageDialog.openInformation(window.getShell(), "Ocaml Plugin", "Please make a selection first!"); + return; + } String newSelectedText = replaceSpacesByTabs(OcamlEditor.getTabSize(), selectedText); int selectedOffset = textSelection.getOffset(); diff --git a/Ocaml/src/ocaml/editor/actions/ConvertTabsToSpacesAction.java b/Ocaml/src/ocaml/editor/actions/ConvertTabsToSpacesAction.java index ef70df3..426aedc 100644 --- a/Ocaml/src/ocaml/editor/actions/ConvertTabsToSpacesAction.java +++ b/Ocaml/src/ocaml/editor/actions/ConvertTabsToSpacesAction.java @@ -38,6 +38,10 @@ public void run(IAction action) { ISelectionProvider selectionProvider = editor.getSelectionProvider(); TextSelection textSelection = (TextSelection) selectionProvider.getSelection(); String selectedText = textSelection.getText(); + if (selectedText.equals("")) { + MessageDialog.openInformation(window.getShell(), "Ocaml Plugin", "Please make a selection first!"); + return; + } String newSelectedText = replaceTabsBySpaces(OcamlEditor.getTabSize(), selectedText); int selectedOffset = textSelection.getOffset(); From 421e9686236d44e780c934ddcc81dd3fe5e267c4 Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 7 Nov 2012 12:46:43 +0800 Subject: [PATCH 008/127] no appending newline character to the last line of template --- .../editor/completion/OcamlTemplateCompletionProcessor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlTemplateCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlTemplateCompletionProcessor.java index 3871e09..01afe39 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlTemplateCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlTemplateCompletionProcessor.java @@ -83,7 +83,8 @@ private String indentTemplatePattern(String pattern) { for (int i = 0; i < lines.length; i++) { String initialIndent = (i == 0 ? "" : indent(currentIndent)); - result.append(initialIndent + lines[i] + OcamlPlugin.newline); + String appendage = (i >= lines.length - 1 ? "" : OcamlPlugin.newline); + result.append(initialIndent + lines[i] + appendage); } return result.toString(); From cbc430ba46ab38131a3ddfbfc577b0fb50c3b0a2 Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 7 Dec 2012 12:55:07 +0800 Subject: [PATCH 009/127] Provide the subdirectory paths of '_build' folder to OcamlDebugger when debugging --- Ocaml/src/ocaml/debugging/OcamlDebugger.java | 70 ++++++++++---------- Ocaml/src/ocaml/util/FileUtil.java | 26 +++++++- 2 files changed, 58 insertions(+), 38 deletions(-) diff --git a/Ocaml/src/ocaml/debugging/OcamlDebugger.java b/Ocaml/src/ocaml/debugging/OcamlDebugger.java index 4ab1c24..39fc9b7 100644 --- a/Ocaml/src/ocaml/debugging/OcamlDebugger.java +++ b/Ocaml/src/ocaml/debugging/OcamlDebugger.java @@ -237,8 +237,12 @@ public synchronized void start( } // add the _build folder (for the cases making project by using Ocamlbuild) - commandLineArgs.add("-I"); - commandLineArgs.add("_build"); + String buildpath = project.getLocation().toOSString() + "/_build"; + ArrayList buildFolders = FileUtil.findSubdirectories(buildpath); + for (String s: buildFolders) { + commandLineArgs.add("-I"); + commandLineArgs.add(s); + } // add module Camlp4 commandLineArgs.add("-I"); @@ -801,7 +805,6 @@ public void run() { refreshEditor(); state = State.Idle; } - else if (state.equals(State.Frame)) { processFrame(output); debuggerOutput.setLength(0); @@ -1039,7 +1042,7 @@ public void run() { } Pattern patternFrame = Pattern.compile("\\A#\\d+ Pc : \\d+ (\\w+) char (\\d+)"); - + private void processFrame(String output) { Matcher matcher = patternFrame.matcher(output); if (matcher.find()) { @@ -1047,20 +1050,19 @@ private void processFrame(String output) { int offset = Integer.parseInt(matcher.group(2)); String filename = Character.toLowerCase(module.charAt(0)) + module.substring(1) + ".ml"; - String filepath = getFilePath(filename); - int newOffset = FileUtil.refineOffset(filepath, offset); - highlight(filename, newOffset); + highlight(filename, offset); } else if (output.equals("(ocd) ")) { } else OcamlPlugin.logError("ocamldebugger: couldn't parse frame"); } + Pattern patternCallstack = Pattern.compile("\\A#(\\d+) Pc : (\\d+) (\\w+) char (\\d+)"); + private void processCallStack(final String output) { Display.getDefault().asyncExec(new Runnable() { public void run() { try { - final IWorkbenchPage activePage = PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getActivePage(); OcamlCallStackView stackview = (OcamlCallStackView) activePage @@ -1077,29 +1079,27 @@ public void run() { System.arraycopy(elements, 1, backtrace, 0, elements.length - 2); for (int i = 0; i < backtrace.length; i++) { String output = backtrace[i]; - Pattern p = Pattern.compile("\\A#(\\d+) Pc : (\\d+) (\\w+) char (\\d+)"); - Matcher matcher = p.matcher(output); + Matcher matcher = patternCallstack.matcher(output); if (matcher.find()) { String s1 = matcher.group(1); - String moudule = matcher.group(3); + String moudule = matcher.group(3); // module name int offset = Integer.parseInt(matcher.group(4)); String filename = Character.toLowerCase(moudule.charAt(0)) + moudule.substring(1) + ".ml"; - String filepath = getFilePath(filename); - // get line and column corresponding with the offset in stack - int newOffset = FileUtil.refineOffset(filepath, offset); - List position = FileUtil.findLineColumnOfOffset(filepath, newOffset); - int line = -1; - int column = -1; - if (position.size() > 0) { + String functionName = "_"; // function name + int line = -1; // line number + int column = -1; // column number + try { + String filepath = getFilePath(filename); + List position = FileUtil.findLineColumnOfOffset(filepath, offset); line = position.get(0); column = position.get(1); - } - // get function name corresponding with the offset in stack - String functionName = ""; - if (i == backtrace.length - 1) - functionName = "_"; - else { - functionName = findFunctionContainLine(filepath, line); + if (i == backtrace.length - 1) + functionName = "_"; + else + functionName = findFunctionContainLine(filepath, line); + } catch (Exception e) { + // TODO: handle exception + e.printStackTrace(); } // prettier stackview String newOutput = "#" + s1 + " - " + moudule + "." + functionName @@ -1242,6 +1242,7 @@ private synchronized String getFilePath(final String filename) return null; } + public void highlight(final String filename, final int offset) { final IFileStore fileStore = getFileStore(filename); if (fileStore != null && fileStore.fetchInfo().exists()) { @@ -1257,7 +1258,7 @@ public void run() { OcamlEditor editor = (OcamlEditor) part; DebugMarkers.getInstance().setCurrentPosition(filename, offset); editor.redraw(); - editor.highlightLineAtOffset(offset); + editor.highlight(offset); } } catch (PartInitException e) { OcamlPlugin.logError("ocaml plugin error", e); @@ -1279,8 +1280,8 @@ public void run() { } } - // opens file in editor and jumps to specific offset - public void jumpToFileOffset(final String filename, final int offset) { + // + public void highlight(final String filename, final int line, final int column1, final int column2) { final IFileStore fileStore = getFileStore(filename); if (fileStore != null && fileStore.fetchInfo().exists()) { Display.getDefault().asyncExec(new Runnable() { @@ -1293,9 +1294,8 @@ public void run() { IEditorPart part = IDE.openEditorOnFileStore(page, fileStore); if (part instanceof OcamlEditor) { OcamlEditor editor = (OcamlEditor) part; - DebugMarkers.getInstance().setCurrentPosition(filename, offset); editor.redraw(); - editor.highlightLineAtOffset(offset); + editor.highlight(line, column1, column2); } } catch (PartInitException e) { OcamlPlugin.logError("ocaml plugin error", e); @@ -1308,7 +1308,7 @@ public void run() { else { if (!missingSourceFiles.contains(filename)) { missingSourceFiles.add(filename); - message("jumpToFileOffset: Source file " + filename + " not found. \n" + message("highlightBreakpoint: Source file " + filename + " not found. \n" + "You will not be able to see the current instruction pointer\n" + "but you can still use step, backstep, etc."); } @@ -1317,8 +1317,8 @@ public void run() { } } - // opens file in editor and jumps to specific line - public void jumpToFileLine(final String filename, final int line) { + // opens file in editor and jumps to specific breakpoint location + public void highlight(final String filename, final int line, final int column) { final IFileStore fileStore = getFileStore(filename); if (fileStore != null && fileStore.fetchInfo().exists()) { Display.getDefault().asyncExec(new Runnable() { @@ -1332,7 +1332,7 @@ public void run() { if (part instanceof OcamlEditor) { OcamlEditor editor = (OcamlEditor) part; editor.redraw(); - editor.highlightLine(line); + editor.highlight(line, column); } } catch (PartInitException e) { OcamlPlugin.logError("ocaml plugin error", e); @@ -1345,7 +1345,7 @@ public void run() { else { if (!missingSourceFiles.contains(filename)) { missingSourceFiles.add(filename); - message("jumpToFileLine: Source file " + filename + " not found. \n" + message("highlightCallpoint: Source file " + filename + " not found. \n" + "You will not be able to see the current instruction pointer\n" + "but you can still use step, backstep, etc."); } diff --git a/Ocaml/src/ocaml/util/FileUtil.java b/Ocaml/src/ocaml/util/FileUtil.java index 4793cb5..ca60e45 100644 --- a/Ocaml/src/ocaml/util/FileUtil.java +++ b/Ocaml/src/ocaml/util/FileUtil.java @@ -22,6 +22,8 @@ import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; +import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader.Array; + public class FileUtil { /** @@ -48,7 +50,6 @@ public static int refineOffset(String filepath, int offset) { if ((ch == ' ') || (ch == '\t') || (ch == '\n') || (ch == '\r')) { // meets separation character pos--; - continue; } else if (ch == ')') { raf.seek(pos - 2); int ch2 = raf.read(); @@ -56,7 +57,6 @@ public static int refineOffset(String filepath, int offset) { // meets end comment block symbols commentBlocks++; pos = pos - 2; - continue; } else if (commentBlocks > 0) pos--; else @@ -68,7 +68,6 @@ public static int refineOffset(String filepath, int offset) { // meets begin comments block symbols commentBlocks--; pos = pos - 2; - continue; } else if (commentBlocks > 0) pos--; else @@ -128,6 +127,27 @@ public static List findLineColumnOfOffset(String filepath, int offset) } return position; } + + /** + * Find all the subdirectories of a directory + */ + public static ArrayList findSubdirectories (String path) + { + ArrayList dirs = new ArrayList(); + File root = new File(path); + if (root.isDirectory()) { + File[] list = root.listFiles(); + for (File f: list){ + if (f.isDirectory()){ + String fpath = f.getAbsolutePath(); + dirs.add(fpath); + ArrayList subdirs = findSubdirectories(fpath); + dirs.addAll(subdirs); + } + } + } + return dirs; + } /** * Delete a file From 0087a656f288e6272ef098c7c117aeb02d830043 Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 12 Dec 2012 16:13:23 +0800 Subject: [PATCH 010/127] jump to the exact source code location from call stack frame, high light the source code range of break point --- Ocaml/src/ocaml/debugging/OcamlDebugger.java | 4 +-- .../debugging/views/OcamlBreakpointsView.java | 4 ++- .../debugging/views/OcamlCallStackView.java | 5 ++-- Ocaml/src/ocaml/editors/OcamlEditor.java | 28 +++++++++++-------- Ocaml/src/ocaml/util/FileUtil.java | 2 +- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/Ocaml/src/ocaml/debugging/OcamlDebugger.java b/Ocaml/src/ocaml/debugging/OcamlDebugger.java index 39fc9b7..8081548 100644 --- a/Ocaml/src/ocaml/debugging/OcamlDebugger.java +++ b/Ocaml/src/ocaml/debugging/OcamlDebugger.java @@ -239,9 +239,9 @@ public synchronized void start( // add the _build folder (for the cases making project by using Ocamlbuild) String buildpath = project.getLocation().toOSString() + "/_build"; ArrayList buildFolders = FileUtil.findSubdirectories(buildpath); - for (String s: buildFolders) { + for (String path: buildFolders) { commandLineArgs.add("-I"); - commandLineArgs.add(s); + commandLineArgs.add(path); } // add module Camlp4 diff --git a/Ocaml/src/ocaml/debugging/views/OcamlBreakpointsView.java b/Ocaml/src/ocaml/debugging/views/OcamlBreakpointsView.java index c67300e..4c6fdce 100644 --- a/Ocaml/src/ocaml/debugging/views/OcamlBreakpointsView.java +++ b/Ocaml/src/ocaml/debugging/views/OcamlBreakpointsView.java @@ -85,8 +85,10 @@ public void mouseDoubleClick(MouseEvent e) { filename = filename + ".ml"; filename = filename.substring(0,1).toLowerCase() + filename.substring(1); int line = Integer.parseInt(matcher.group(3)); + int column1 = Integer.parseInt(matcher.group(4)); + int column2 = Integer.parseInt(matcher.group(5)); OcamlDebugger debugger = OcamlDebugger.getInstance(); - debugger.jumpToFileLine(filename, line); + debugger.highlight(filename, line, column1, column2); //debugger.highlight(file, offset); } } diff --git a/Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java b/Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java index 5f45bb7..cab2795 100644 --- a/Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java +++ b/Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java @@ -57,9 +57,10 @@ public void mouseDoubleClick(MouseEvent e) { if (matcher.find()) { String module = matcher.group(2); int line = Integer.parseInt( matcher.group(3)); - String file = Character.toLowerCase(module.charAt(0)) + module.substring(1) + ".ml"; + int column = Integer.parseInt(matcher.group(4)); + String filename = Character.toLowerCase(module.charAt(0)) + module.substring(1) + ".ml"; OcamlDebugger debugger = OcamlDebugger.getInstance(); - debugger.jumpToFileLine(file, line); + debugger.highlight(filename, line, column); } } }); diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index 3a3c476..ebbd142 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -488,34 +488,40 @@ public synchronized Def getOutlineDefinitionsTree() { return this.codeOutlineDefinitionsTree; } - public void highlightLineAtOffset(int offset) { + public void highlight(int offset) { IDocument document = this.getDocumentProvider().getDocument(this.getEditorInput()); IRegion region = null; try { region = document.getLineInformationOfOffset(offset); + this.selectAndReveal(region.getOffset(), 0); } catch (BadLocationException e) { OcamlPlugin.logError("ocaml plugin error (bad location)", e); return; } - - if (region != null) - this.selectAndReveal(region.getOffset(), 0); - } - public void highlightLine(int line) { + public void highlight(int line, int column1, int column2) { IDocument document = this.getDocumentProvider().getDocument(this.getEditorInput()); - IRegion region = null; + try { - region = document.getLineInformation(line - 1); + int offset = document.getLineOffset(line - 1) + column1 - 1; + int length = column2 - column1; + this.selectAndReveal(offset, length); } catch (BadLocationException e) { OcamlPlugin.logError("ocaml plugin error (bad location)", e); - return; } + } - if (region != null) { - this.selectAndReveal(region.getOffset(), 0); + public void highlight(int line, int column) { + IDocument document = this.getDocumentProvider().getDocument(this.getEditorInput()); + + try { + int offset = document.getLineOffset(line - 1) + column - 1; + int length = 0; + this.selectAndReveal(offset, length); + } catch (BadLocationException e) { + OcamlPlugin.logError("ocaml plugin error (bad location)", e); } } diff --git a/Ocaml/src/ocaml/util/FileUtil.java b/Ocaml/src/ocaml/util/FileUtil.java index ca60e45..a80475a 100644 --- a/Ocaml/src/ocaml/util/FileUtil.java +++ b/Ocaml/src/ocaml/util/FileUtil.java @@ -129,7 +129,7 @@ public static List findLineColumnOfOffset(String filepath, int offset) } /** - * Find all the subdirectories of a directory + * Find all the recursive subdirectories of a directory */ public static ArrayList findSubdirectories (String path) { From a689bab458d715c8a39b484281698f89ac4e3376 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 4 Jun 2013 13:53:32 +0800 Subject: [PATCH 011/127] add build folder --- Ocaml/src/ocaml/debugging/OcamlDebugger.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Ocaml/src/ocaml/debugging/OcamlDebugger.java b/Ocaml/src/ocaml/debugging/OcamlDebugger.java index 8081548..c367205 100644 --- a/Ocaml/src/ocaml/debugging/OcamlDebugger.java +++ b/Ocaml/src/ocaml/debugging/OcamlDebugger.java @@ -236,8 +236,11 @@ public synchronized void start( } } - // add the _build folder (for the cases making project by using Ocamlbuild) + // add the _build folder and its children folders (for the cases making project by using Ocamlbuild) String buildpath = project.getLocation().toOSString() + "/_build"; + commandLineArgs.add("-I"); + commandLineArgs.add(buildpath); + ArrayList buildFolders = FileUtil.findSubdirectories(buildpath); for (String path: buildFolders) { commandLineArgs.add("-I"); From 685eb6a4dea38f525b8e943be53c917d2a977923 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 15 May 2012 14:07:20 +0800 Subject: [PATCH 012/127] Enable OcaIDE debugging with variables relating to Camlp4 module. - fix bug 0013 in Mantis bug tracker --- Ocaml/src/ocaml/debugging/OcamlDebugger.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Ocaml/src/ocaml/debugging/OcamlDebugger.java b/Ocaml/src/ocaml/debugging/OcamlDebugger.java index 871855c..944ae5f 100644 --- a/Ocaml/src/ocaml/debugging/OcamlDebugger.java +++ b/Ocaml/src/ocaml/debugging/OcamlDebugger.java @@ -252,6 +252,10 @@ public synchronized void start( commandLineArgs.add("-I"); commandLineArgs.add("+camlp4"); + // add module Camlp4 + commandLineArgs.add("-I"); + commandLineArgs.add("+camlp4"); + // add the root of the project commandLineArgs.add("-I"); commandLineArgs.add(project.getLocation().toOSString()); From b02395cf4961c6542c29d26e2aa8f7d37bdc53f2 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 29 Oct 2012 10:51:28 +0800 Subject: [PATCH 013/127] merge with upstream --- Ocaml/icons/markOccurrence.gif | Bin Ocaml/icons/shiftLeft.png | Bin Ocaml/icons/shiftRight.png | Bin 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 Ocaml/icons/markOccurrence.gif mode change 100755 => 100644 Ocaml/icons/shiftLeft.png mode change 100755 => 100644 Ocaml/icons/shiftRight.png diff --git a/Ocaml/icons/markOccurrence.gif b/Ocaml/icons/markOccurrence.gif old mode 100755 new mode 100644 diff --git a/Ocaml/icons/shiftLeft.png b/Ocaml/icons/shiftLeft.png old mode 100755 new mode 100644 diff --git a/Ocaml/icons/shiftRight.png b/Ocaml/icons/shiftRight.png old mode 100755 new mode 100644 From a7517c64ca96e1233fe1f517198d31344f741439 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sun, 4 May 2014 01:08:27 +0800 Subject: [PATCH 014/127] support multiple-lines-comment style like Eclipse for Java --- .../ocaml/editors/OcamlAutoEditStrategy.java | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java b/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java index 360c4f9..dd5ba8a 100644 --- a/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java +++ b/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java @@ -9,12 +9,17 @@ import ocaml.preferences.PreferenceConstants; import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.BadPartitioningException; import org.eclipse.jface.text.DocumentCommand; import org.eclipse.jface.text.IAutoEditStrategy; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IDocumentExtension3; +import org.eclipse.jface.text.IDocumentPartitioner; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITypedRegion; +import org.eclipse.jface.text.Position; import org.eclipse.jface.text.TextUtilities; +import org.eclipse.jface.viewers.IDoubleClickListener; //TODO: linked mode @@ -34,6 +39,8 @@ public class OcamlAutoEditStrategy implements IAutoEditStrategy { /** A comment opened at the beginning of the line */ private Pattern patternCommentOpen = Pattern.compile("^\\(\\*"); + + private Pattern patternCommentMultipleLines = Pattern.compile("^\\*"); /** A "no-format" comment opened at the beginning of the line */ private Pattern patternCommentOpenNoFormat = Pattern.compile("^\\(\\*\\|"); @@ -164,7 +171,7 @@ else if (command.text.equals(eol)) { PreferenceConstants.P_EDITOR_CONTINUE_COMMENTS)) { Matcher matcher = patternCommentOpenNoFormat.matcher(beforeCursor); if (matcher.find() && !beforeCursor.contains("*)")) { - command.text = "*)" + eol + makeIndent(indent) + "(*| "; + command.text = " *)" + eol + makeIndent(indent) + "(*| "; return; } @@ -173,9 +180,50 @@ else if (command.text.equals(eol)) { if (matcher.find()) return; + // support multiple-lines comment like Ecipse for Java matcher = patternCommentOpen.matcher(beforeCursor); - if (matcher.find() && !beforeCursor.contains("*)")) { - command.text = "*)" + eol + makeIndent(indent) + "(* "; + if (matcher.find()) { + try { + IDocumentExtension3 extension = (IDocumentExtension3) document; + ITypedRegion partition; + partition = extension.getPartition(OcamlPartitionScanner.OCAML_PARTITIONING, + command.offset, false); + if(OcamlPartitionScanner.OCAML_DOCUMENTATION_COMMENT.equals(partition.getType())|| + OcamlPartitionScanner.OCAML_MULTILINE_COMMENT.equals(partition.getType())) { + command.text = " " + eol + makeIndent(indent) + " * "; + } + else { + String strIndent = makeIndent(indent); + command.text = eol + makeIndent(indent) + " * " + eol + makeIndent(indent) + " *)"; + command.shiftsCaret = false; + command.caretOffset = command.offset + eol.length() + strIndent.length() + 3; + } + } catch (BadLocationException e) { + OcamlPlugin.logError("bad location in OcamlAutoEditStrategy", e); + } catch (BadPartitioningException e) { + OcamlPlugin.logError("bad partitioning in OcamlAutoEditStrategy", e); + } + return; + } + + // support multiple-lines comment like Eclipse for Java + matcher = patternCommentMultipleLines.matcher(trimmed); + if (matcher.find()) { + try { + IDocumentExtension3 extension = (IDocumentExtension3) document; + ITypedRegion partition = extension.getPartition(OcamlPartitionScanner.OCAML_PARTITIONING, + command.offset, false); + if(OcamlPartitionScanner.OCAML_DOCUMENTATION_COMMENT.equals(partition.getType())|| + OcamlPartitionScanner.OCAML_MULTILINE_COMMENT.equals(partition.getType())) { + if (trimmed.startsWith("*") && !trimmed.startsWith("*)")) { + command.text = " " + eol + makeIndent(indent) + " * "; + } + } + } catch (BadLocationException e) { + OcamlPlugin.logError("bad location in OcamlAutoEditStrategy", e); + } catch (BadPartitioningException e) { + OcamlPlugin.logError("bad partitioning in OcamlAutoEditStrategy", e); + } return; } } From 5f08dfd8866cf7056148aab7467034d4086f340d Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 7 May 2014 10:32:18 +0800 Subject: [PATCH 015/127] enhance comment at the end of file --- Ocaml/src/ocaml/editor/syntaxcoloring/OcamlCommentRule.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Ocaml/src/ocaml/editor/syntaxcoloring/OcamlCommentRule.java b/Ocaml/src/ocaml/editor/syntaxcoloring/OcamlCommentRule.java index a6ecc04..83912a5 100644 --- a/Ocaml/src/ocaml/editor/syntaxcoloring/OcamlCommentRule.java +++ b/Ocaml/src/ocaml/editor/syntaxcoloring/OcamlCommentRule.java @@ -40,10 +40,13 @@ public IToken evaluate(ICharacterScanner scanner, boolean resume) { ch = scanner.read(); nRead++; + /* //Commented out by Trung if (ch == -1) return token; - else if (ch == ')') { + else + */ + if (ch == ')') { if (bStar) { nestingLevel--; if (nestingLevel <= 0) From 37ee9efb0eff446d2f03426f3ed89f3bbbaa4a9c Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 7 May 2014 12:13:49 +0800 Subject: [PATCH 016/127] more enhancements for comment feature --- Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java b/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java index dd5ba8a..7b5af1a 100644 --- a/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java +++ b/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java @@ -95,8 +95,8 @@ public void customizeDocumentCommand(IDocument document, DocumentCommand command int offsetInLine = command.offset - lineRegion.getOffset(); - String beforeCursor = line.substring(0, offsetInLine).trim(); - String afterCursor = line.substring(offsetInLine, line.length()).trim(); + String beforeCursor = line.substring(0, offsetInLine); + String afterCursor = line.substring(offsetInLine, line.length()); try { ITypedRegion region = document.getPartition(offsetInLine); @@ -190,9 +190,9 @@ else if (command.text.equals(eol)) { command.offset, false); if(OcamlPartitionScanner.OCAML_DOCUMENTATION_COMMENT.equals(partition.getType())|| OcamlPartitionScanner.OCAML_MULTILINE_COMMENT.equals(partition.getType())) { - command.text = " " + eol + makeIndent(indent) + " * "; + command.text = eol + makeIndent(indent) + " * "; } - else { + else if (partition.getOffset() <= matcher.end() + lineRegion.getOffset()) { String strIndent = makeIndent(indent); command.text = eol + makeIndent(indent) + " * " + eol + makeIndent(indent) + " *)"; command.shiftsCaret = false; @@ -216,7 +216,7 @@ else if (command.text.equals(eol)) { if(OcamlPartitionScanner.OCAML_DOCUMENTATION_COMMENT.equals(partition.getType())|| OcamlPartitionScanner.OCAML_MULTILINE_COMMENT.equals(partition.getType())) { if (trimmed.startsWith("*") && !trimmed.startsWith("*)")) { - command.text = " " + eol + makeIndent(indent) + " * "; + command.text = eol + makeIndent(indent) + " * "; } } } catch (BadLocationException e) { From c9422729879e63798fd2670da0e48c2dc9946cc3 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sun, 5 Oct 2014 03:32:26 +0800 Subject: [PATCH 017/127] improve code completion feature --- Ocaml/lib/beaver-cc.jar | Bin 0 -> 122339 bytes .../completion/OcamlCompletionProcessor.java | 68 +++++++++++++----- Ocaml/src/ocaml/parser/Def.java | 5 +- Ocaml/src/ocaml/parser/OcamlParser.g | 6 +- Ocaml/src/ocaml/parser/OcamlParser.java | 6 +- Ocaml/src/ocaml/util/FileUtil.java | 2 - 6 files changed, 65 insertions(+), 22 deletions(-) create mode 100644 Ocaml/lib/beaver-cc.jar diff --git a/Ocaml/lib/beaver-cc.jar b/Ocaml/lib/beaver-cc.jar new file mode 100644 index 0000000000000000000000000000000000000000..fab999eee2fe19b9a5bef9d12afaf9ed0b1df94a GIT binary patch literal 122339 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%0A;=BAJ$( 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 literal 0 HcmV?d00001 diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index e0db003..c405bfb 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -198,14 +198,32 @@ private OcamlCompletionProposal[] findCompletionProposals(String completion, Def // look in the module before the dot what's after the dot if (completion.contains(".")) { - int index = completion.indexOf('.'); - String prefix = completion.substring(0, index); - String suffix = completion.substring(index + 1); - - for (Def def : definitions) { - if (def.name.equals(prefix)) - return findCompletionProposals(suffix, def, offset); + int dotIndex = completion.lastIndexOf('.'); + int prefixIndex = completion.lastIndexOf('.', dotIndex - 1); + prefixIndex = (prefixIndex < 0) ? 0 : prefixIndex + 1; + String prefix = completion.substring(prefixIndex, dotIndex); + String suffix = completion.substring(dotIndex + 1); + + Def candidate = definitionsRoot; + String moduleName = prefix; + boolean stop = false; + while (!stop) { + for (Def def : definitions) { + if (def.name.equals(moduleName)) { + if (def.type == Def.Type.Module) { + candidate = def; + stop = true; + break; + } + else if (def.type == Def.Type.ModuleAlias) { + Def aliasedDef = def.children.get(0); + moduleName = aliasedDef.name; + break; + } + } + } } + return findCompletionProposals(suffix, candidate, offset); } // find elements starting by in the list of elements else { @@ -397,17 +415,35 @@ private IContextInformation[] findContextInformation(String expression, Def defi // search in the module before the dot the element after the dot if (expression.contains(".")) { - int index = expression.indexOf('.'); - String prefix = expression.substring(0, index); - String suffix = expression.substring(index + 1); - - for (Def def : definitions) { - if (def.name.equals(prefix)) { - IContextInformation[] informations = findContextInformation(suffix, def); - for (IContextInformation i : informations) - infos.add(i); + int dotIndex = expression.lastIndexOf('.'); + int prefixIndex = expression.lastIndexOf('.', dotIndex - 1); + prefixIndex = (prefixIndex < 0) ? 0 : prefixIndex + 1; + String prefix = expression.substring(prefixIndex, dotIndex); + String suffix = expression.substring(dotIndex + 1); + + Def candidate = definitionsRoot; // default use definitionRoot + String moduleName = prefix; + boolean stop = false; + while (!stop) { + for (Def def : definitions) { + if (def.name.equals(moduleName)) { + if (def.type == Def.Type.Module) { + candidate = def; + stop = true; + break; + } + else if (def.type == Def.Type.ModuleAlias) { + Def aliasedDef = def.children.get(0); + moduleName = aliasedDef.name; + break; + } + } } } + IContextInformation[] informations = findContextInformation(suffix, candidate); + for (IContextInformation i : informations) + infos.add(i); + return infos.toArray(new IContextInformation[0]); } diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index 3099d46..9d8640a 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -24,7 +24,7 @@ public enum Type { /** the root of the definitions tree (module implementation) */ Root, /** a variable name, with its position */ - Identifier, Let, LetIn, Type, Module, ModuleType, Exception, External, Class, Sig, + Identifier, Let, LetIn, Type, Module, ModuleAlias, ModuleType, Exception, External, Class, Sig, Open, Object, Method, Struct, Functor, Include, Val, Constraint, Initializer, @@ -371,7 +371,8 @@ private void cleanCopyAux(Def node, Def newNode) { } private void findRealChildren(Def node, ArrayList nodes, boolean root) { - if (node.type == Type.Dummy || node.type == Type.Identifier || node.type == Type.Parameter + if (node.type == Type.Dummy || node.type == Type.Parameter + /* || node.type == Type.Identifier */ // Trung: this is to handle ModuleAlias || node.type == Type.Functor || node.type == Type.Sig || node.type == Type.Object || node.type == Type.Struct || node.type == Type.In || root || "_".equals(node.name) || "()".equals(node.name)) { diff --git a/Ocaml/src/ocaml/parser/OcamlParser.g b/Ocaml/src/ocaml/parser/OcamlParser.g index fa3a102..fe77a8b 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.g +++ b/Ocaml/src/ocaml/parser/OcamlParser.g @@ -389,7 +389,11 @@ structure_item= :} | MODULE UIDENT.id module_binding.a {: - Def def = new Def((String)id.value, Def.Type.Module, id.getStart(), id.getEnd()); + Def.Type type = Def.Type.Module; + assert a instanceof Def; + Def.Type aType = ((Def)a).type; + type = (aType == Def.Type.Identifier) ? Def.Type.ModuleAlias : type; + Def def = new Def((String)id.value, type, id.getStart(), id.getEnd()); def.add(a); def.collapse(); backup(def); diff --git a/Ocaml/src/ocaml/parser/OcamlParser.java b/Ocaml/src/ocaml/parser/OcamlParser.java index 0887530..09cf717 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.java +++ b/Ocaml/src/ocaml/parser/OcamlParser.java @@ -1099,7 +1099,11 @@ public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 2]; final Symbol a = _symbols[offset + 3]; - Def def = new Def((String)id.value, Def.Type.Module, id.getStart(), id.getEnd()); + Def.Type type = Def.Type.Module; + assert a instanceof Def; + Def.Type aType = ((Def)a).type; + type = (aType == Def.Type.Identifier) ? Def.Type.ModuleAlias : type; + Def def = new Def((String)id.value, type, id.getStart(), id.getEnd()); def.add(a); def.collapse(); backup(def); diff --git a/Ocaml/src/ocaml/util/FileUtil.java b/Ocaml/src/ocaml/util/FileUtil.java index fc8a449..f0baaa3 100644 --- a/Ocaml/src/ocaml/util/FileUtil.java +++ b/Ocaml/src/ocaml/util/FileUtil.java @@ -27,8 +27,6 @@ import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; -import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader.Array; - public class FileUtil { /** From 4312d22996f5683cd87e2778687e1813dbb1ea25 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sun, 5 Oct 2014 04:02:03 +0800 Subject: [PATCH 018/127] improvement on code completion feature --- .../completion/OcamlCompletionProcessor.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index c405bfb..c382ec9 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -204,26 +204,27 @@ private OcamlCompletionProposal[] findCompletionProposals(String completion, Def String prefix = completion.substring(prefixIndex, dotIndex); String suffix = completion.substring(dotIndex + 1); - Def candidate = definitionsRoot; String moduleName = prefix; + int aliasLevel = 0; boolean stop = false; - while (!stop) { + // allow the deepest level of module aliasing is 5 + while (!stop && (aliasLevel < 5)) { + stop = true; for (Def def : definitions) { if (def.name.equals(moduleName)) { if (def.type == Def.Type.Module) { - candidate = def; - stop = true; - break; + return findCompletionProposals(suffix, def, offset); } else if (def.type == Def.Type.ModuleAlias) { Def aliasedDef = def.children.get(0); moduleName = aliasedDef.name; + stop = false; + aliasLevel++; break; } } } } - return findCompletionProposals(suffix, candidate, offset); } // find elements starting by in the list of elements else { @@ -421,28 +422,31 @@ private IContextInformation[] findContextInformation(String expression, Def defi String prefix = expression.substring(prefixIndex, dotIndex); String suffix = expression.substring(dotIndex + 1); - Def candidate = definitionsRoot; // default use definitionRoot String moduleName = prefix; + int aliasLevel = 0; boolean stop = false; - while (!stop) { + // allow the deepest level of module aliasing is 5 + while (!stop && (aliasLevel < 5)) { + stop = true; for (Def def : definitions) { if (def.name.equals(moduleName)) { - if (def.type == Def.Type.Module) { - candidate = def; + if (def.type == Def.Type.Module) { + IContextInformation[] informations = findContextInformation(suffix, def); + for (IContextInformation i : informations) + infos.add(i); stop = true; break; } else if (def.type == Def.Type.ModuleAlias) { Def aliasedDef = def.children.get(0); moduleName = aliasedDef.name; + aliasLevel++; + stop = false; break; } } } } - IContextInformation[] informations = findContextInformation(suffix, candidate); - for (IContextInformation i : informations) - infos.add(i); return infos.toArray(new IContextInformation[0]); } From 061161d638a5473666eac7583cffa4d82ef86c43 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 6 Oct 2014 18:40:47 +0800 Subject: [PATCH 019/127] improvement on 'jump to definition' --- .../completion/OcamlCompletionProcessor.java | 78 ++++-- .../ocaml/editors/OcamlHyperlinkDetector.java | 253 ++++++++++++++++-- Ocaml/src/ocaml/parser/Def.java | 16 +- 3 files changed, 295 insertions(+), 52 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index c382ec9..b1f961c 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -195,20 +195,30 @@ private OcamlCompletionProposal[] findCompletionProposals(String completion, Def ArrayList definitions = definitionsRoot.children; ArrayList proposals = new ArrayList(); - + // look in the module before the dot what's after the dot + // The module can be like "A.B." or "c.D.E." if (completion.contains(".")) { - int dotIndex = completion.lastIndexOf('.'); - int prefixIndex = completion.lastIndexOf('.', dotIndex - 1); - prefixIndex = (prefixIndex < 0) ? 0 : prefixIndex + 1; - String prefix = completion.substring(prefixIndex, dotIndex); - String suffix = completion.substring(dotIndex + 1); + //find the name of root module + int index = completion.lastIndexOf('.'); + String[] parts = completion.substring(0,index).split("\\."); + String prefix = parts[parts.length - 1]; + String suffix = completion.substring(index+1); + int i = parts.length - 2; + while (i >= 0) { + if (parts[i].isEmpty()) + break; + char firstLetter = parts[i].charAt(0); + if (( firstLetter < 'A') || (firstLetter > 'Z')) + break; + suffix = prefix + "." + suffix; + prefix = parts[i]; + i--; + } String moduleName = prefix; - int aliasLevel = 0; boolean stop = false; - // allow the deepest level of module aliasing is 5 - while (!stop && (aliasLevel < 5)) { + while (!stop) { stop = true; for (Def def : definitions) { if (def.name.equals(moduleName)) { @@ -216,10 +226,13 @@ private OcamlCompletionProposal[] findCompletionProposals(String completion, Def return findCompletionProposals(suffix, def, offset); } else if (def.type == Def.Type.ModuleAlias) { - Def aliasedDef = def.children.get(0); - moduleName = aliasedDef.name; - stop = false; - aliasLevel++; + String aliasedName = def.children.get(0).name; + if (moduleName.equals(aliasedName)) + stop = true; + else { + moduleName = aliasedName; + stop = false; + } break; } } @@ -416,32 +429,43 @@ private IContextInformation[] findContextInformation(String expression, Def defi // search in the module before the dot the element after the dot if (expression.contains(".")) { - int dotIndex = expression.lastIndexOf('.'); - int prefixIndex = expression.lastIndexOf('.', dotIndex - 1); - prefixIndex = (prefixIndex < 0) ? 0 : prefixIndex + 1; - String prefix = expression.substring(prefixIndex, dotIndex); - String suffix = expression.substring(dotIndex + 1); + int index = expression.lastIndexOf('.'); + String[] parts = expression.substring(0,index).split("\\."); + String prefix = parts[parts.length - 1]; + String suffix = expression.substring(index+1); + int i = parts.length - 2; + while (i >= 0) { + if (parts[i].isEmpty()) + break; + char firstLetter = parts[i].charAt(0); + if (( firstLetter < 'A') || (firstLetter > 'Z')) + break; + suffix = prefix + "." + suffix; + prefix = parts[i]; + i--; + } String moduleName = prefix; - int aliasLevel = 0; boolean stop = false; - // allow the deepest level of module aliasing is 5 - while (!stop && (aliasLevel < 5)) { + while (!stop) { stop = true; for (Def def : definitions) { if (def.name.equals(moduleName)) { if (def.type == Def.Type.Module) { IContextInformation[] informations = findContextInformation(suffix, def); - for (IContextInformation i : informations) - infos.add(i); + for (IContextInformation d : informations) + infos.add(d); stop = true; break; } else if (def.type == Def.Type.ModuleAlias) { - Def aliasedDef = def.children.get(0); - moduleName = aliasedDef.name; - aliasLevel++; - stop = false; + String aliasedName = def.children.get(0).name; + if (moduleName.equals(aliasedName)) + stop = true; + else { + moduleName = aliasedName; + stop = false; + } break; } } diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index a7316a8..4701358 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -16,9 +16,12 @@ import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; import org.eclipse.ui.IEditorPart; @@ -99,45 +102,146 @@ public IHyperlink[] detectHyperlinks(final ITextViewer textViewer, final IRegion if (searchedDef.name.equals("_")) return null; + // open selective defs + if (searchedDef.type != Def.Type.Identifier + && searchedDef.type != Def.Type.Open + && searchedDef.type != Def.Type.Include) + return null; + if (searchedDef.type == Def.Type.Open || searchedDef.type == Def.Type.Include) { return makeOpenHyperlink(textViewer, searchedDef, interfacesDefinitionsRoot); } return new IHyperlink[] { - new IHyperlink() { + new IHyperlink() { + + public void open() { + + Def target = findDefinitionOf(searchedDef, modulesDefinitionsRoot, + interfacesDefinitionsRoot); + + if (target == null) + return; + + IRegion region = target.getRegion(textViewer.getDocument()); + editor.selectAndReveal(region.getOffset(), region.getLength()); + } + + public String getTypeLabel() { + return null; + } + + public String getHyperlinkText() { + return searchedDef.name; + } + + public IRegion getHyperlinkRegion() { + return searchedDef.getRegion(textViewer.getDocument()); + } + + } - public void open() { + }; - Def target = findDefinitionOf(searchedDef, modulesDefinitionsRoot, - interfacesDefinitionsRoot); + } + // find definition by text its self + else { + time = System.currentTimeMillis(); - if (target == null) - return; + /* Find which definition in the tree is at the hovered offset */ + final Def def = (time - lastTime < 1000 && lastOffset == region.getOffset() && lastDef != null) ? lastDef + : findDefAt(modulesDefinitionsRoot, region.getOffset(), textViewer.getDocument()); - IRegion region = target.getRegion(textViewer.getDocument()); - editor.selectAndReveal(region.getOffset(), region.getLength()); - } + lastTime = time; - public String getTypeLabel() { - return null; - } + lastOffset = region.getOffset(); + lastDef = def; + + if (def == null) + return null; - public String getHyperlinkText() { - return searchedDef.name; + // get hovered text + IDocument doc = textViewer.getDocument(); + int docLen = doc.getLength(); + String text = ""; + int offset = region.getOffset(); + while (offset < docLen) { + char ch; + try { + ch = doc.getChar(offset); + if (ch == '.' || ch == '_' + || (ch >= '0' && ch <= '9') + || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z')) { + text = text + ch; + offset++; + } + else break; + } catch (BadLocationException e) { + break; } - - public IRegion getHyperlinkRegion() { - return searchedDef.getRegion(textViewer.getDocument()); + } + final int endOffset = (offset < docLen) ? offset - 1 : docLen; + + offset = region.getOffset() - 1; + if (!text.isEmpty()) { + while (offset >= 0) { + char ch; + try { + ch = doc.getChar(offset); + if (ch == '.' || ch == '_' || Character.isLetterOrDigit(ch)) { + text = ch + text; + offset--; + } + else break; + } catch (BadLocationException e) { + break; + } } - } + final int beginOffset = (offset >= 0) ? offset + 1 : 0; + final String hoveredText = text; + + if (hoveredText.isEmpty() || Character.isDigit(hoveredText.charAt(0))) + return null; + + + OcamlPlugin.logInfo("hoveredTex = " + hoveredText); + + + return new IHyperlink[] { + + new IHyperlink() { + + public void open() { + + Def target = findDefinitionOf(hoveredText, modulesDefinitionsRoot, interfacesDefinitionsRoot); + + if (target == null) + return; + + IRegion region = target.getRegion(textViewer.getDocument()); + editor.selectAndReveal(region.getOffset(), region.getLength()); + } + + public String getTypeLabel() { + return null; + } + + public String getHyperlinkText() { + return hoveredText; + } + + public IRegion getHyperlinkRegion() { + return new Region(beginOffset, endOffset - beginOffset + 1); + } + + } }; } - - return null; } /** @@ -219,6 +323,66 @@ private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitions return def; } + /** + * Find the definition of searchedDef in modulesDefinitionsRoot, + * and in interfacesDefinitionsRoot + */ + private Def findDefinitionOf(final String searchedDef, final Def modulesDefinitionsRoot, + final Def interfacesDefinitionsRoot) { + Def def = null; + + /* + * if this is a compound name "A.B.c", then we extract the first component to know what + * module to look for, and then we get the definition by entering the module + */ + if (searchedDef.indexOf('.') != -1) { + String[] parts = searchedDef.split("\\."); + if (parts.length > 1) { + // find possible alias module + boolean stop = false; + String moduleName = parts[0]; + while (!stop) { + stop = true; + for (Def d : modulesDefinitionsRoot.children) { + if (d.name.equals(moduleName) && (d.type == Def.Type.ModuleAlias)) { + String aliasedName = d.children.get(0).name; + if (moduleName.equals(aliasedName)) + stop = true; + else { + moduleName = aliasedName; + stop = false; + } + break; + } + } + } + // rectify full path in case of there exist aliased module + if (!moduleName.equals(parts[0])) + parts[0] = moduleName; + + openDefInInterfaces(0, parts, interfacesDefinitionsRoot); + return null; + } + } + else { + // find in current module + for (Def d : modulesDefinitionsRoot.children) { + if (d.name.equals(searchedDef)) { + def = d; + break; + } + } + + // if we didn't find it, look in Pervasives (which is always opened by default) + if (def == null) { + String[] pervasivesPath = new String[] { "Pervasives", searchedDef }; + if (openDefInInterfaces(0, pervasivesPath, interfacesDefinitionsRoot)) + return null; + } + } + return def; + } + /** Find the definition whose complete path is given, starting at index */ private Def findDefFromPath(int index, String[] path, Def def, Def lastPartFound) { if (index == path.length) @@ -287,7 +451,28 @@ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, /* if we are at root, we cannot go further up in this module. */ if (node.type == Def.Type.Root) { - // openDefInInterfaces(0, new String[] { name }, interfacesDefinitionsRoot); + // find possible alias module + boolean stop = false; + String moduleName = name; + while (!stop) { + stop = true; + for (Def def : node.children) { + if (def.name.equals(name) && (def.type == Def.Type.ModuleAlias)) { + String aliasedName = def.children.get(0).name; + if (moduleName.equals(aliasedName)) + stop = true; + else { + moduleName = aliasedName; + stop = false; + } + break; + } + } + } + // rectify full path in case of there exist aliased module + if (!moduleName.equals(name)) + fullpath[0] = moduleName; + return null; } @@ -509,9 +694,7 @@ private Def findIdentAt(Def def, int offset, IDocument doc) { int startOffset = region.getOffset(); int endOffset = startOffset + region.getLength() - 1; - if (startOffset <= offset - && endOffset >= offset - && (def.type == Def.Type.Identifier || def.type == Def.Type.Open || def.type == Def.Type.Include)) + if (startOffset <= offset && endOffset >= offset) return def; for (Def d : def.children) { @@ -522,6 +705,28 @@ private Def findIdentAt(Def def, int offset, IDocument doc) { return null; } + + /** Find a smallest def at a position in the document */ + private Def findDefAt(Def def, int offset, IDocument doc) { + + if (def == null || doc == null) + return null; + + int startOffset = def.defOffsetStart; + int endOffset = def.defOffsetEnd; + + if (startOffset <= offset && endOffset >= offset) { + for (Def d : def.children) { + Def cd = findDefAt(d, offset, doc); + if (cd != null) + return cd; + } + return def; + } + + return null; + } + /** * make an hyperlink for an open directive (to open the interface in an editor) diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index 9d8640a..ba0a4e9 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -125,7 +125,21 @@ public Def(String name, Type type, int start, int end) { this.defPosStart = 0; // this.defPosEnd = 0; } - + + /** Create a definition node: let, type,... */ + public Def(String name, Type type, int start, int end, int offsetStart, int offsetEnd) { + super(); + children = new ArrayList(); + this.name = name; + this.type = type; + this.posStart = start; + this.posEnd = end; + this.defPosStart = 0; + this.defOffsetStart = offsetStart; + this.defOffsetEnd = offsetEnd; + // this.defPosEnd = 0; + } + /** copy constructor */ public Def(Def def) { this.bAlt = def.bAlt; From bda3ba8a1ab9c10fe54fa7af7c2b688078966bb5 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 6 Oct 2014 19:17:48 +0800 Subject: [PATCH 020/127] minor changes --- Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index 4701358..092bda0 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -150,6 +150,10 @@ public IRegion getHyperlinkRegion() { time = System.currentTimeMillis(); /* Find which definition in the tree is at the hovered offset */ + // TODO Trung: need to update correct location of defOffsetStart, + // defOffsetEnd field before using it to find def + /* + // Activate later final Def def = (time - lastTime < 1000 && lastOffset == region.getOffset() && lastDef != null) ? lastDef : findDefAt(modulesDefinitionsRoot, region.getOffset(), textViewer.getDocument()); @@ -160,7 +164,7 @@ public IRegion getHyperlinkRegion() { if (def == null) return null; - + */ // get hovered text IDocument doc = textViewer.getDocument(); int docLen = doc.getLength(); @@ -712,6 +716,7 @@ private Def findDefAt(Def def, int offset, IDocument doc) { if (def == null || doc == null) return null; + //TODO Trung: currently, defOffsetStart and defOffsetEnd are incorrect int startOffset = def.defOffsetStart; int endOffset = def.defOffsetEnd; From 5cfa1620101b262e323a6fd7632947ac23c751b3 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 6 Oct 2014 19:40:35 +0800 Subject: [PATCH 021/127] minor changes --- Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index 092bda0..966ca8e 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -210,10 +210,6 @@ public IRegion getHyperlinkRegion() { if (hoveredText.isEmpty() || Character.isDigit(hoveredText.charAt(0))) return null; - - OcamlPlugin.logInfo("hoveredTex = " + hoveredText); - - return new IHyperlink[] { new IHyperlink() { From 8e643a80c685bba654ce2e3eb32ff94c932f1483 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 6 Oct 2014 19:49:25 +0800 Subject: [PATCH 022/127] m --- Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java index 6b716b7..f661b72 100644 --- a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java +++ b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java @@ -419,9 +419,7 @@ private void findDefinitionsEnd(Def def, String doc, int index, Def parent) { boolean skip = false; if (def.defOffsetStart > def.defOffsetEnd || def.defOffsetStart < 0) { - OcamlPlugin - .logError("OcamlNewParser: findDefinitionsEnd: wrong offset (" - + def.name + ")"); + OcamlPlugin.logWarning("OcamlNewParser: findDefinitionsEnd: wrong offset (" + def.name + ")"); skip = true; } From da13750b60582f0256efd7c70fc248a0cd8b1b85 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 6 Oct 2014 23:00:15 +0800 Subject: [PATCH 023/127] restructure --- .../ocaml/editors/OcamlHyperlinkDetector.java | 291 ++++++++---------- 1 file changed, 124 insertions(+), 167 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index 966ca8e..75979b5 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -21,6 +21,7 @@ import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; @@ -51,19 +52,16 @@ public OcamlHyperlinkDetector(OcamlEditor editor) { public IHyperlink[] detectHyperlinks(final ITextViewer textViewer, final IRegion region, boolean canShowMultipleHyperlinks) { + IHyperlink hyperlink = makeHyperlink(textViewer, region.getOffset()); + return new IHyperlink[] {hyperlink}; + } + + public IHyperlink makeHyperlink (final ITextViewer textViewer, int offset) { IProject project = editor.getProject(); // get the definitions from the current module final Def modulesDefinitionsRoot = editor.getDefinitionsTree(); - /* - * get the definitions from all the mli files in the project paths (which should include the - * ocaml standard library) - */ - // long before = System.currentTimeMillis(); - - // long after = System.currentTimeMillis(); - // System.err.println("parsing for hyperlinks: " + (after - before) + " ms"); - + final Def interfacesDefinitionsRoot; if(project != null) @@ -88,12 +86,12 @@ public IHyperlink[] detectHyperlinks(final ITextViewer textViewer, final IRegion long time = System.currentTimeMillis(); /* Find which definition in the tree is at the hovered offset */ - final Def searchedDef = (time - lastTime < 1000 && lastOffset == region.getOffset() && lastDef != null) ? lastDef - : findIdentAt(modulesDefinitionsRoot, region.getOffset(), textViewer.getDocument()); + final Def searchedDef = (time - lastTime < 1000 && lastOffset == offset && lastDef != null) ? lastDef + : findIdentAt(modulesDefinitionsRoot, offset, textViewer.getDocument()); lastTime = time; - lastOffset = region.getOffset(); + lastOffset = offset; lastDef = searchedDef; if (searchedDef != null) { @@ -102,146 +100,93 @@ public IHyperlink[] detectHyperlinks(final ITextViewer textViewer, final IRegion if (searchedDef.name.equals("_")) return null; - // open selective defs - if (searchedDef.type != Def.Type.Identifier - && searchedDef.type != Def.Type.Open - && searchedDef.type != Def.Type.Include) - return null; - if (searchedDef.type == Def.Type.Open || searchedDef.type == Def.Type.Include) { return makeOpenHyperlink(textViewer, searchedDef, interfacesDefinitionsRoot); } - - return new IHyperlink[] { - - new IHyperlink() { - - public void open() { - - Def target = findDefinitionOf(searchedDef, modulesDefinitionsRoot, - interfacesDefinitionsRoot); - - if (target == null) - return; - - IRegion region = target.getRegion(textViewer.getDocument()); - editor.selectAndReveal(region.getOffset(), region.getLength()); - } - - public String getTypeLabel() { - return null; - } - - public String getHyperlinkText() { - return searchedDef.name; - } - - public IRegion getHyperlinkRegion() { - return searchedDef.getRegion(textViewer.getDocument()); - } - - } - - }; + + if (searchedDef.type == Def.Type.Identifier) + return makeDefinitionHyperlink(textViewer, searchedDef, + modulesDefinitionsRoot, interfacesDefinitionsRoot); + + return null; } // find definition by text its self else { time = System.currentTimeMillis(); - /* Find which definition in the tree is at the hovered offset */ - // TODO Trung: need to update correct location of defOffsetStart, - // defOffsetEnd field before using it to find def - /* - // Activate later - final Def def = (time - lastTime < 1000 && lastOffset == region.getOffset() && lastDef != null) ? lastDef - : findDefAt(modulesDefinitionsRoot, region.getOffset(), textViewer.getDocument()); + // TODO Trung: currently, this create a hyperlink for even Ocaml's + // keywords or text occurring inside comment. + // Need to fix this! - lastTime = time; + IDocument doc = textViewer.getDocument(); + TextSelection ident = findIdentAt(doc, offset); + String hoveredText = ident.getText(); + int beginOffset = ident.getOffset(); - lastOffset = region.getOffset(); - lastDef = def; - - if (def == null) + if (hoveredText.isEmpty() || Character.isDigit(hoveredText.charAt(0))) return null; - */ - // get hovered text - IDocument doc = textViewer.getDocument(); - int docLen = doc.getLength(); - String text = ""; - int offset = region.getOffset(); - while (offset < docLen) { - char ch; - try { - ch = doc.getChar(offset); - if (ch == '.' || ch == '_' - || (ch >= '0' && ch <= '9') - || (ch >= 'a' && ch <= 'z') - || (ch >= 'A' && ch <= 'Z')) { - text = text + ch; - offset++; - } - else break; - } catch (BadLocationException e) { - break; - } + + return makeDefinitionHyperlink(textViewer, hoveredText, beginOffset, + modulesDefinitionsRoot, interfacesDefinitionsRoot); + } + } + + private IHyperlink makeDefinitionHyperlink(final ITextViewer textViewer, + final Def def, final Def moudulesRoot, final Def interfacesRoot) { + IHyperlink hyperlink = new IHyperlink() { + public void open() { + Def target = findDefinitionOf(def, moudulesRoot, interfacesRoot); + if (target == null) + return; + IRegion region = target.getRegion(textViewer.getDocument()); + editor.selectAndReveal(region.getOffset(), region.getLength()); } - final int endOffset = (offset < docLen) ? offset - 1 : docLen; - - offset = region.getOffset() - 1; - if (!text.isEmpty()) { - while (offset >= 0) { - char ch; - try { - ch = doc.getChar(offset); - if (ch == '.' || ch == '_' || Character.isLetterOrDigit(ch)) { - text = ch + text; - offset--; - } - else break; - } catch (BadLocationException e) { - break; - } - } + + public String getTypeLabel() { + return null; } - final int beginOffset = (offset >= 0) ? offset + 1 : 0; - final String hoveredText = text; - if (hoveredText.isEmpty() || Character.isDigit(hoveredText.charAt(0))) + public String getHyperlinkText() { + return def.name; + } + + public IRegion getHyperlinkRegion() { + return def.getRegion(textViewer.getDocument()); + } + }; + + return hyperlink; + + } + + private IHyperlink makeDefinitionHyperlink(final ITextViewer textViewer, + final String strDef, final int offset, + final Def moudulesRoot, final Def interfacesRoot) { + IHyperlink hyperlink = new IHyperlink() { + public void open() { + Def target = findDefinitionOf(strDef, moudulesRoot, interfacesRoot); + if (target == null) + return; + IRegion region = target.getRegion(textViewer.getDocument()); + editor.selectAndReveal(region.getOffset(), region.getLength()); + } + + public String getTypeLabel() { return null; + } - return new IHyperlink[] { + public String getHyperlinkText() { + return strDef; + } - new IHyperlink() { - - public void open() { - - Def target = findDefinitionOf(hoveredText, modulesDefinitionsRoot, interfacesDefinitionsRoot); - - if (target == null) - return; - - IRegion region = target.getRegion(textViewer.getDocument()); - editor.selectAndReveal(region.getOffset(), region.getLength()); - } - - public String getTypeLabel() { - return null; - } - - public String getHyperlinkText() { - return hoveredText; - } - - public IRegion getHyperlinkRegion() { - return new Region(beginOffset, endOffset - beginOffset + 1); - } - - } + public IRegion getHyperlinkRegion() { + return new Region(offset, strDef.length()); + } + }; - }; + return hyperlink; - } } /** @@ -313,10 +258,9 @@ private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitions // if it still wasn't found, try to open it as a module if (def == null && searchedDef.name.length() > 0 && Character.isUpperCase(searchedDef.name.charAt(0))) { - IHyperlink[] hyperlinks = makeOpenHyperlink(null, searchedDef, + IHyperlink hyperlink = makeOpenHyperlink(null, searchedDef, interfacesDefinitionsRoot); - if (hyperlinks.length > 0) - hyperlinks[0].open(); + hyperlink.open(); } } @@ -327,7 +271,7 @@ private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitions * Find the definition of searchedDef in modulesDefinitionsRoot, * and in interfacesDefinitionsRoot */ - private Def findDefinitionOf(final String searchedDef, final Def modulesDefinitionsRoot, + private Def findDefinitionOf(final String strDef, final Def modulesDefinitionsRoot, final Def interfacesDefinitionsRoot) { Def def = null; @@ -335,8 +279,8 @@ private Def findDefinitionOf(final String searchedDef, final Def modulesDefiniti * if this is a compound name "A.B.c", then we extract the first component to know what * module to look for, and then we get the definition by entering the module */ - if (searchedDef.indexOf('.') != -1) { - String[] parts = searchedDef.split("\\."); + if (strDef.indexOf('.') != -1) { + String[] parts = strDef.split("\\."); if (parts.length > 1) { // find possible alias module boolean stop = false; @@ -367,7 +311,7 @@ private Def findDefinitionOf(final String searchedDef, final Def modulesDefiniti else { // find in current module for (Def d : modulesDefinitionsRoot.children) { - if (d.name.equals(searchedDef)) { + if (d.name.equals(strDef)) { def = d; break; } @@ -375,7 +319,7 @@ private Def findDefinitionOf(final String searchedDef, final Def modulesDefiniti // if we didn't find it, look in Pervasives (which is always opened by default) if (def == null) { - String[] pervasivesPath = new String[] { "Pervasives", searchedDef }; + String[] pervasivesPath = new String[] { "Pervasives", strDef }; if (openDefInInterfaces(0, pervasivesPath, interfacesDefinitionsRoot)) return null; } @@ -707,42 +651,59 @@ private Def findIdentAt(Def def, int offset, IDocument doc) { } /** Find a smallest def at a position in the document */ - private Def findDefAt(Def def, int offset, IDocument doc) { - - if (def == null || doc == null) - return null; + private TextSelection findIdentAt(IDocument doc, int offset) { + int docLen = doc.getLength(); + String text = ""; + int i = offset; + while (i < docLen) { + char ch; + try { + ch = doc.getChar(i); + if (ch == '.' || ch == '_' + || (ch >= '0' && ch <= '9') + || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z')) { + text = text + ch; + i++; + } + else break; + } catch (BadLocationException e) { + break; + } + } - //TODO Trung: currently, defOffsetStart and defOffsetEnd are incorrect - int startOffset = def.defOffsetStart; - int endOffset = def.defOffsetEnd; - - if (startOffset <= offset && endOffset >= offset) { - for (Def d : def.children) { - Def cd = findDefAt(d, offset, doc); - if (cd != null) - return cd; + i = offset - 1; + if (!text.isEmpty()) { + while (i >= 0) { + char ch; + try { + ch = doc.getChar(i); + if (ch == '.' || ch == '_' || Character.isLetterOrDigit(ch)) { + text = ch + text; + i--; + } + else break; + } catch (BadLocationException e) { + break; + } } - return def; } - - return null; + int beginOffset = (i >= 0) ? i + 1 : 0; + + return new TextSelection(doc, beginOffset, text.length()); } + /** * make an hyperlink for an open directive (to open the interface in an editor) */ - private IHyperlink[] makeOpenHyperlink(final ITextViewer textViewer, final Def searchedDef, + private IHyperlink makeOpenHyperlink(final ITextViewer textViewer, final Def searchedDef, final Def interfacesDefinitionsRoot) { - return new IHyperlink[] { - - new IHyperlink() { - + return new IHyperlink() { public void open() { - try { - // extract the first part of a multipart name (A.B.C) String[] fragments = searchedDef.name.split("\\."); @@ -842,11 +803,7 @@ public String getHyperlinkText() { public IRegion getHyperlinkRegion() { return searchedDef.getRegion(textViewer.getDocument()); } - - } - }; - } } From 4f51d43b578923d362b59fd7b97312feb2d3d649 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 7 Oct 2014 00:50:54 +0800 Subject: [PATCH 024/127] restructure code --- .../ocaml/editors/OcamlHyperlinkDetector.java | 111 ++++++++++-------- 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index 75979b5..83f4dce 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -3,12 +3,14 @@ import java.io.File; import java.io.FilenameFilter; import java.net.URI; +import java.util.ArrayList; import java.util.List; import ocaml.OcamlPlugin; import ocaml.editor.completion.CompletionJob; import ocaml.parser.Def; import ocaml.parsers.OcamlNewInterfaceParser; +import ocaml.util.FileUtil; import ocaml.util.Misc; import ocaml.util.OcamlPaths; @@ -271,60 +273,73 @@ private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitions * Find the definition of searchedDef in modulesDefinitionsRoot, * and in interfacesDefinitionsRoot */ - private Def findDefinitionOf(final String strDef, final Def modulesDefinitionsRoot, + private Def findDefinitionOf(final String strDef, + final Def modulesDefinitionsRoot, final Def interfacesDefinitionsRoot) { - Def def = null; + // use direct name + String[] directPath = strDef.split("\\."); + if (openDefInInterfaces(0, directPath, interfacesDefinitionsRoot)) + return null; - /* - * if this is a compound name "A.B.c", then we extract the first component to know what - * module to look for, and then we get the definition by entering the module - */ - if (strDef.indexOf('.') != -1) { - String[] parts = strDef.split("\\."); - if (parts.length > 1) { - // find possible alias module - boolean stop = false; - String moduleName = parts[0]; - while (!stop) { - stop = true; - for (Def d : modulesDefinitionsRoot.children) { - if (d.name.equals(moduleName) && (d.type == Def.Type.ModuleAlias)) { - String aliasedName = d.children.get(0).name; - if (moduleName.equals(aliasedName)) - stop = true; - else { - moduleName = aliasedName; - stop = false; - } - break; - } + // look in current module + Def def = modulesDefinitionsRoot; + for (int index = 0; index < directPath.length; index++) { + boolean stop = true; + for (Def d : def.children) { + if (d.name.equals(directPath[index])) { + def = d; + if (index == directPath.length - 1) + return def; + else { + stop = false; + break; } } - // rectify full path in case of there exist aliased module - if (!moduleName.equals(parts[0])) - parts[0] = moduleName; - - openDefInInterfaces(0, parts, interfacesDefinitionsRoot); - return null; } - } - else { - // find in current module + if (stop) + break; + } + + // lookup in opened module + for (Def d : modulesDefinitionsRoot.children) { + if (d.type == Def.Type.Open) { + String fullStrDef = d.name + "." + strDef; + String[] openedPath = fullStrDef.split("\\."); + if (openDefInInterfaces(0, openedPath, interfacesDefinitionsRoot)) + return null; + } + } + + // lookup in aliased module + String[] path = strDef.split("\\."); + String moduleName = path[0]; + boolean stop = false; + while (!stop) { + stop = true; for (Def d : modulesDefinitionsRoot.children) { - if (d.name.equals(strDef)) { - def = d; + if (d.name.equals(moduleName) && (d.type == Def.Type.ModuleAlias)) { + String aliasedName = d.children.get(0).name; + if (moduleName.equals(aliasedName)) + stop = true; + else { + moduleName = aliasedName; + stop = false; + } break; } } - - // if we didn't find it, look in Pervasives (which is always opened by default) - if (def == null) { - String[] pervasivesPath = new String[] { "Pervasives", strDef }; - if (openDefInInterfaces(0, pervasivesPath, interfacesDefinitionsRoot)) - return null; - } } - return def; + if (!moduleName.equals(path[0])) { + String[] aliasedPath = path.clone(); + aliasedPath[0] = moduleName; + if (openDefInInterfaces(0, aliasedPath, interfacesDefinitionsRoot)) + return null; + } + + // finally, look in Pervasives (which is always opened by default) + String[] pervasivesPath = ("Pervasives" + strDef).split("\\."); + openDefInInterfaces(0, pervasivesPath, interfacesDefinitionsRoot); + return null; } /** Find the definition whose complete path is given, starting at index */ @@ -523,14 +538,6 @@ private boolean openDefInInterfaces(int index, final String[] path, Def interfac return true; } - /* - * if we couldn't go all the way down to the definition, but we could find the beginning of - * the path, open it - */ - if (index > 1) - if (openDefInInterfaces(path.length, path, interfaceDef)) - return true; - return false; } From 5d1579b014013e19973bd653469b3ff4c07b725c Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 7 Oct 2014 02:08:30 +0800 Subject: [PATCH 025/127] add 'go to definition' feature --- .../ocaml/editor/actions/GotoDefinition.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 Ocaml/src/ocaml/editor/actions/GotoDefinition.java diff --git a/Ocaml/src/ocaml/editor/actions/GotoDefinition.java b/Ocaml/src/ocaml/editor/actions/GotoDefinition.java new file mode 100644 index 0000000..1a5e943 --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/GotoDefinition.java @@ -0,0 +1,80 @@ +package ocaml.editor.actions; + +import ocaml.OcamlPlugin; +import ocaml.editors.OcamlEditor; +import ocaml.editors.OcamlHyperlinkDetector; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.FindReplaceDocumentAdapter; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.text.hyperlink.IHyperlink; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.editors.text.TextEditor; +import org.eclipse.ui.part.FileEditorInput; + +/** This action marks occurrences of the text currently selected in the editor. */ +public class GotoDefinition implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + private static final String OCAML_GOTO_DEFINITION_ID = "ocaml.marker.gotodefinition"; + + public void run(IAction action) { + + IWorkbenchPage page = window.getActivePage(); + + if (page == null) { + OcamlPlugin.logWarning(GotoDefinition.class.getSimpleName() + + ": page is null"); + return; + } + + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart == null) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": editorPart is null"); + return; + } + + if (!(editorPart instanceof TextEditor)) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": only works on ml and mli files"); + return; + } + + if (editorPart instanceof OcamlEditor) { + OcamlEditor editor = (OcamlEditor) editorPart; + TextSelection selection = + (TextSelection) editor.getSelectionProvider().getSelection(); + int offset = selection.getOffset(); + OcamlHyperlinkDetector hyperlinkdetector = new OcamlHyperlinkDetector(editor); + ITextViewer textViewer = editor.getTextViewer(); + IHyperlink hyperlink = hyperlinkdetector.makeHyperlink(textViewer, offset); + if (hyperlink != null) + hyperlink.open(); + } + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} From b0d6142e94a83a7fa75a44dd1680dc663359f3e4 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 7 Oct 2014 02:18:53 +0800 Subject: [PATCH 026/127] some changes --- Ocaml/plugin.xml | 21 ++++++++++++++++++- .../editor/completion/CompletionJob.java | 2 -- .../ocaml/editors/OcamlHyperlinkDetector.java | 8 ++++--- .../ocaml/typeHovers/OcamlAnnotParser.java | 7 +++++-- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index 0b50421..a70b0eb 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -739,6 +739,14 @@ + + + + + sequence="M1+M3+N"/> + + = 1) && (beginLine <= document.getNumberOfLines())) + beginOffset += document.getLineOffset(beginLine - 1) - beginLineOffset; + + if ((endLine >= 1) && (endLine <= document.getNumberOfLines())) + endOffset += document.getLineOffset(endLine - 1) - endLineOffset; String type = matcher.group(7); From 3a049f7b1aa4ba23530b450184819ca11d13fbf9 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 7 Oct 2014 02:54:19 +0800 Subject: [PATCH 027/127] chaneg priority of parsing mli files to the highest --- Ocaml/src/ocaml/editors/OcamlEditor.java | 4 ++-- Ocaml/src/ocaml/editors/lex/OcamllexEditor.java | 2 +- Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index df94793..f09a444 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -134,7 +134,7 @@ protected void createActions() { // parse the OCaml libraries in a background thread try { CompletionJob job = new CompletionJob("Parsing ocaml library mli files", null); - job.setPriority(CompletionJob.DECORATE); + job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority job.schedule(); } catch (Exception e) { OcamlPlugin.logError("ocaml plugin error", e); @@ -176,7 +176,7 @@ public void doSetInput(IEditorInput input) throws CoreException { // parse the project interfaces in a background thread CompletionJob job = new CompletionJob("Parsing ocaml project mli files", project); - job.setPriority(CompletionJob.DECORATE); + job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority job.schedule(); if (input instanceof IFileEditorInput) { diff --git a/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java b/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java index 9781bcd..744d12a 100644 --- a/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java +++ b/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java @@ -49,7 +49,7 @@ protected void createActions() { // effectue le parsing des bibliothèques ocaml en arrière plan CompletionJob job = new CompletionJob("Parsing ocaml library mli files", null); - job.setPriority(CompletionJob.DECORATE); + job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority job.schedule(); } diff --git a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java index 67b774c..5403a1a 100644 --- a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java +++ b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java @@ -55,7 +55,7 @@ protected void createActions() { // effectue le parsing des bibliothèques ocaml en arrière plan CompletionJob job = new CompletionJob("Parsing ocaml library mli files", null); - job.setPriority(CompletionJob.DECORATE); + job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority job.schedule(); From 2bf27af101278d899b1222442e921653c0acd6b6 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 7 Oct 2014 10:35:21 +0800 Subject: [PATCH 028/127] improvements --- .../completion/OcamlCompletionProcessor.java | 6 ++---- .../ocaml/editors/OcamlHyperlinkDetector.java | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index b1f961c..6a606e1 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -208,8 +208,7 @@ private OcamlCompletionProposal[] findCompletionProposals(String completion, Def while (i >= 0) { if (parts[i].isEmpty()) break; - char firstLetter = parts[i].charAt(0); - if (( firstLetter < 'A') || (firstLetter > 'Z')) + if (!Character.isUpperCase(parts[i].charAt(0))) break; suffix = prefix + "." + suffix; prefix = parts[i]; @@ -437,8 +436,7 @@ private IContextInformation[] findContextInformation(String expression, Def defi while (i >= 0) { if (parts[i].isEmpty()) break; - char firstLetter = parts[i].charAt(0); - if (( firstLetter < 'A') || (firstLetter > 'Z')) + if (!Character.isUpperCase(parts[i].charAt(0))) break; suffix = prefix + "." + suffix; prefix = parts[i]; diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index 513f141..121fba4 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -699,7 +699,21 @@ private TextSelection findIdentAt(IDocument doc, int offset) { } int beginOffset = (i >= 0) ? i + 1 : 0; - return new TextSelection(doc, beginOffset, text.length()); + + String[] parts = text.split("\\."); + String hoveredText = parts[parts.length - 1]; + i = parts.length - 2; + while (i >= 0) { + if (parts[i].isEmpty()) + break; + if (!Character.isUpperCase(parts[i].charAt(0))) + break; + hoveredText = parts[i] + "." + hoveredText; + i--; + } + beginOffset = beginOffset + (text.length() - hoveredText.length()); + + return new TextSelection(doc, beginOffset, hoveredText.length()); } From adccf9bbe651ccdb13b30e5ba98d0bdf21c3ea6d Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 7 Oct 2014 14:33:57 +0800 Subject: [PATCH 029/127] quick jump to next, prev block of code --- Ocaml/plugin.xml | 73 +++++++++- .../ocaml/editor/actions/GotoDefinition.java | 12 -- .../actions/MoveCursorDownwardOneBlock.java | 114 ++++++++++++++++ .../actions/MoveCursorUpwardOneBlock.java | 116 ++++++++++++++++ .../actions/SelectDownwardOneBlock.java | 121 +++++++++++++++++ .../editor/actions/SelectUpwardOneBlock.java | 125 ++++++++++++++++++ 6 files changed, 548 insertions(+), 13 deletions(-) create mode 100644 Ocaml/src/ocaml/editor/actions/MoveCursorDownwardOneBlock.java create mode 100644 Ocaml/src/ocaml/editor/actions/MoveCursorUpwardOneBlock.java create mode 100644 Ocaml/src/ocaml/editor/actions/SelectDownwardOneBlock.java create mode 100644 Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index a70b0eb..ab27070 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -739,12 +739,39 @@ + + + + + + + + + + + + + + + + @@ -997,6 +1044,30 @@ contextId="Ocaml.editor.context" schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" sequence="M1+M3+D"> + + + + + + + + diff --git a/Ocaml/src/ocaml/editor/actions/GotoDefinition.java b/Ocaml/src/ocaml/editor/actions/GotoDefinition.java index 1a5e943..1ccccab 100644 --- a/Ocaml/src/ocaml/editor/actions/GotoDefinition.java +++ b/Ocaml/src/ocaml/editor/actions/GotoDefinition.java @@ -4,33 +4,21 @@ import ocaml.editors.OcamlEditor; import ocaml.editors.OcamlHyperlinkDetector; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; import org.eclipse.jface.action.IAction; -import org.eclipse.jface.text.FindReplaceDocumentAdapter; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.jface.viewers.ISelection; -import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; import org.eclipse.ui.editors.text.TextEditor; -import org.eclipse.ui.part.FileEditorInput; -/** This action marks occurrences of the text currently selected in the editor. */ public class GotoDefinition implements IWorkbenchWindowActionDelegate { private IWorkbenchWindow window; - private static final String OCAML_GOTO_DEFINITION_ID = "ocaml.marker.gotodefinition"; - public void run(IAction action) { IWorkbenchPage page = window.getActivePage(); diff --git a/Ocaml/src/ocaml/editor/actions/MoveCursorDownwardOneBlock.java b/Ocaml/src/ocaml/editor/actions/MoveCursorDownwardOneBlock.java new file mode 100644 index 0000000..e57aff9 --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/MoveCursorDownwardOneBlock.java @@ -0,0 +1,114 @@ +package ocaml.editor.actions; + +import ocaml.OcamlPlugin; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.editors.text.TextEditor; + +public class MoveCursorDownwardOneBlock implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + + IWorkbenchPage page = window.getActivePage(); + + if (page == null) { + OcamlPlugin.logWarning(GotoDefinition.class.getSimpleName() + + ": page is null"); + return; + } + + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart == null) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": editorPart is null"); + return; + } + + if (!(editorPart instanceof TextEditor)) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": only works on ml and mli files"); + return; + } + + TextEditor editor = (TextEditor) editorPart; + IEditorInput editorInput = editor.getEditorInput(); + IDocument doc = editor.getDocumentProvider().getDocument(editorInput); + Control control = (Control)editor.getAdapter(Control.class); + + if (!(control instanceof StyledText)) + { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": Cannot get caret position"); + return; + } + + final StyledText styledText = (StyledText) control; + int cursorOffset = styledText.getCaretOffset(); + + try { + int lineNum= doc.getLineOfOffset(cursorOffset); + int numOfLine = doc.getNumberOfLines(); + + if (lineNum == (numOfLine - 2)) { + int lastLineOffset = doc.getLineOffset(lineNum+1); + editor.selectAndReveal(lastLineOffset, 0); + return; + } + + if (lineNum >= (numOfLine - 1)) { + editor.selectAndReveal(doc.getLength(), 0); + return; + } + + int beginOffset = doc.getLineOffset(lineNum); + int endOffset = doc.getLineOffset(lineNum+1) - 1; + String currentLine = doc.get(beginOffset, endOffset - beginOffset + 1); + boolean isCurrentLineEmpty = currentLine.trim().isEmpty(); + + // find next non-empty line which follows an empty line + lineNum++; + while (lineNum < numOfLine - 1) { + beginOffset = doc.getLineOffset(lineNum); + endOffset = doc.getLineOffset(lineNum+1) - 1; + String nextLine = doc.get(beginOffset, endOffset - beginOffset + 1); + if (nextLine.trim().isEmpty()) { + isCurrentLineEmpty = true; + lineNum++; + } + else if (!isCurrentLineEmpty) + lineNum++; + else + break; + } + int newOffset = doc.getLineOffset(lineNum); + editor.selectAndReveal(newOffset, 0); + } catch (BadLocationException e) { + e.printStackTrace(); + return; + } + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} diff --git a/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardOneBlock.java b/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardOneBlock.java new file mode 100644 index 0000000..2d22584 --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardOneBlock.java @@ -0,0 +1,116 @@ +package ocaml.editor.actions; + +import ocaml.OcamlPlugin; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.editors.text.TextEditor; + +public class MoveCursorUpwardOneBlock implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + + IWorkbenchPage page = window.getActivePage(); + + if (page == null) { + OcamlPlugin.logWarning(GotoDefinition.class.getSimpleName() + + ": page is null"); + return; + } + + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart == null) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": editorPart is null"); + return; + } + + if (!(editorPart instanceof TextEditor)) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": only works on ml and mli files"); + return; + } + + TextEditor editor = (TextEditor) editorPart; + IEditorInput editorInput = editor.getEditorInput(); + IDocument doc = editor.getDocumentProvider().getDocument(editorInput); + Control control = (Control)editor.getAdapter(Control.class); + + if (!(control instanceof StyledText)) + { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": Cannot get caret position"); + return; + } + + final StyledText styledText = (StyledText) control; + int cursorOffset = styledText.getCaretOffset(); + + try { + int lineNum= doc.getLineOfOffset(cursorOffset); + int numOfLine = doc.getNumberOfLines(); + + if (lineNum <= 0) { + editor.selectAndReveal(0, 0); + return; + } + + int currentLineOffset = doc.getLineOffset(lineNum); + + // if previous line is empty and cursor is not in beginning of + // current block, then go to the beginning. + int beginOffset = doc.getLineOffset(lineNum-1); + int endOffset = doc.getLineOffset(lineNum) - 1; + String prevLine= doc.get(beginOffset, endOffset - beginOffset + 1); + boolean isPrevLineEmpty = prevLine.trim().isEmpty(); + if (isPrevLineEmpty && (cursorOffset != currentLineOffset)) { + editor.selectAndReveal(currentLineOffset, 0); + return; + } + + // find previous non-empty line which follows an empty line + lineNum--; + while (lineNum > 0) { + beginOffset = doc.getLineOffset(lineNum-1); + endOffset = doc.getLineOffset(lineNum) - 1; + prevLine = doc.get(beginOffset, endOffset - beginOffset + 1); + if (!prevLine.trim().isEmpty()) { + isPrevLineEmpty = false; + lineNum--; + } + else if (isPrevLineEmpty) + lineNum--; + else { + break; // stop at this non-empty line + } + } + int newOffset = doc.getLineOffset(lineNum); + editor.selectAndReveal(newOffset, 0); + } catch (BadLocationException e) { + return; + } + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} diff --git a/Ocaml/src/ocaml/editor/actions/SelectDownwardOneBlock.java b/Ocaml/src/ocaml/editor/actions/SelectDownwardOneBlock.java new file mode 100644 index 0000000..12edc2a --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/SelectDownwardOneBlock.java @@ -0,0 +1,121 @@ +package ocaml.editor.actions; + +import ocaml.OcamlPlugin; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.editors.text.TextEditor; + +public class SelectDownwardOneBlock implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + + IWorkbenchPage page = window.getActivePage(); + + if (page == null) { + OcamlPlugin.logWarning(GotoDefinition.class.getSimpleName() + + ": page is null"); + return; + } + + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart == null) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": editorPart is null"); + return; + } + + if (!(editorPart instanceof TextEditor)) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": only works on ml and mli files"); + return; + } + + TextEditor editor = (TextEditor) editorPart; + IEditorInput editorInput = editor.getEditorInput(); + IDocument doc = editor.getDocumentProvider().getDocument(editorInput); + Control control = (Control)editor.getAdapter(Control.class); + + if (!(control instanceof StyledText)) + { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": Cannot get caret position"); + return; + } + + final StyledText styledText = (StyledText) control; + int cursorOffset = styledText.getCaretOffset(); + + TextSelection selection = + (TextSelection) editor.getSelectionProvider().getSelection(); + int startSelectionOffset; + if (selection.getOffset() < cursorOffset) + startSelectionOffset = selection.getOffset(); + else + startSelectionOffset = selection.getOffset() + selection.getLength(); + + try { + int lineNum= doc.getLineOfOffset(cursorOffset); + int numOfLine = doc.getNumberOfLines(); + + if (lineNum == (numOfLine - 2)) { + int lastLineOffset = doc.getLineOffset(lineNum+1); + editor.selectAndReveal(startSelectionOffset, lastLineOffset - startSelectionOffset); + return; + } + + if (lineNum >= (numOfLine - 1)) { + editor.selectAndReveal(startSelectionOffset, doc.getLength() - startSelectionOffset ); + return; + } + + int beginOffset = doc.getLineOffset(lineNum); + int endOffset = doc.getLineOffset(lineNum+1) - 1; + String currentLine = doc.get(beginOffset, endOffset - beginOffset + 1); + boolean isCurrentLineEmpty = currentLine.trim().isEmpty(); + + // find next non-empty line which follows an empty line + lineNum++; + while (lineNum < numOfLine - 1) { + beginOffset = doc.getLineOffset(lineNum); + endOffset = doc.getLineOffset(lineNum+1) - 1; + String nextLine = doc.get(beginOffset, endOffset - beginOffset + 1); + if (nextLine.trim().isEmpty()) { + isCurrentLineEmpty = true; + lineNum++; + } + else if (!isCurrentLineEmpty) + lineNum++; + else + break; + } + int newOffset = doc.getLineOffset(lineNum); + editor.selectAndReveal(startSelectionOffset, newOffset - startSelectionOffset); + } catch (BadLocationException e) { + return; + } + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} diff --git a/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java b/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java new file mode 100644 index 0000000..3a9e374 --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java @@ -0,0 +1,125 @@ +package ocaml.editor.actions; + +import ocaml.OcamlPlugin; +import ocaml.editors.OcamlEditor; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.editors.text.TextEditor; +import org.eclipse.ui.texteditor.ITextEditor; + +public class SelectUpwardOneBlock implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + + IWorkbenchPage page = window.getActivePage(); + + if (page == null) { + OcamlPlugin.logWarning(GotoDefinition.class.getSimpleName() + + ": page is null"); + return; + } + + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart == null) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": editorPart is null"); + return; + } + + if (!(editorPart instanceof TextEditor)) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": only works on ml and mli files"); + return; + } + + TextEditor editor = (TextEditor) editorPart; + IEditorInput editorInput = editor.getEditorInput(); + IDocument doc = editor.getDocumentProvider().getDocument(editorInput); + Control control = (Control)editor.getAdapter(Control.class); + + if (!(control instanceof StyledText)) + { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": Cannot get caret position"); + return; + } + + final StyledText styledText = (StyledText) control; + int cursorOffset = styledText.getCaretOffset(); + + TextSelection selection = + (TextSelection) editor.getSelectionProvider().getSelection(); + int startSelectionOffset; + if (selection.getOffset() < cursorOffset) + startSelectionOffset = selection.getOffset(); + else + startSelectionOffset = selection.getOffset() + selection.getLength(); + + try { + int lineNum= doc.getLineOfOffset(cursorOffset); + int numOfLine = doc.getNumberOfLines(); + + if (lineNum <= 0) { + editor.selectAndReveal(startSelectionOffset, -startSelectionOffset); + return; + } + + int currentLineOffset = doc.getLineOffset(lineNum); + + // if previous line is empty and cursor is not in beginning of + // current block, then go to the beginning. + int beginOffset = doc.getLineOffset(lineNum-1); + int endOffset = doc.getLineOffset(lineNum) - 1; + String prevLine= doc.get(beginOffset, endOffset - beginOffset + 1); + boolean isPrevLineEmpty = prevLine.trim().isEmpty(); + if (isPrevLineEmpty && (cursorOffset != currentLineOffset)) { + editor.selectAndReveal(startSelectionOffset, currentLineOffset - startSelectionOffset); + return; + } + + // find previous non-empty line which follows an empty line + lineNum--; + while (lineNum > 0) { + beginOffset = doc.getLineOffset(lineNum-1); + endOffset = doc.getLineOffset(lineNum) - 1; + prevLine = doc.get(beginOffset, endOffset - beginOffset + 1); + if (!prevLine.trim().isEmpty()) { + isPrevLineEmpty = false; + lineNum--; + } + else if (isPrevLineEmpty) + lineNum--; + else { + break; // stop at this non-empty line + } + } + int newOffset = doc.getLineOffset(lineNum); + editor.selectAndReveal(startSelectionOffset, newOffset - startSelectionOffset); + } catch (BadLocationException e) { + return; + } + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } +} From 20dcf503cbc21ce9547cbdbcf7e69c39e8e25ddb Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 8 Oct 2014 03:54:19 +0800 Subject: [PATCH 030/127] at least can make auto-completion works --- .../completion/OcamlCompletionProcessor.java | 270 +++++++++++++++--- Ocaml/src/ocaml/editors/OcamlEditor.java | 8 +- 2 files changed, 241 insertions(+), 37 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 6a606e1..2ab54a0 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -1,6 +1,9 @@ package ocaml.editor.completion; +import java.io.File; import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; import ocaml.OcamlPlugin; import ocaml.editor.syntaxcoloring.OcamlPartitionScanner; @@ -8,17 +11,22 @@ import ocaml.editors.lex.OcamllexEditor; import ocaml.editors.yacc.OcamlyaccEditor; import ocaml.parser.Def; +import ocaml.parser.Def.Type; +import ocaml.parsers.OcamlNewInterfaceParser; import ocaml.util.Misc; import org.eclipse.core.resources.IProject; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.contentassist.ContextInformation; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.contentassist.IContextInformationValidator; +import org.eclipse.jface.text.hyperlink.IHyperlink; +import org.eclipse.ui.editors.text.TextEditor; /** * This class is responsible for managing completion in the OCaml editor. @@ -28,29 +36,24 @@ */ public class OcamlCompletionProcessor implements IContentAssistProcessor { - // private final OcamlEditor ocamlEditor; - - private final IProject project; + private final TextEditor editor; /** The partition type in which completion was triggered. */ private final String partitionType; public OcamlCompletionProcessor(OcamlEditor edit, String regionType) { - // this.ocamlEditor = edit; + this.editor = (TextEditor)edit; this.partitionType = regionType; - this.project = edit.getProject(); } public OcamlCompletionProcessor(OcamllexEditor edit, String regionType) { - // this.ocamlEditor = null; + this.editor = (TextEditor)edit; this.partitionType = regionType; - this.project = edit.getProject(); } public OcamlCompletionProcessor(OcamlyaccEditor edit, String regionType) { - // this.ocamlEditor = null; + this.editor = (TextEditor)edit; this.partitionType = regionType; - this.project = edit.getProject(); } /** @@ -99,19 +102,45 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int String completion = completionExpression(viewer, documentOffset); - OcamlCompletionProposal[] proposals; - /* - * If the interfaces parsing Job isn't done, we return an empty list to avoid blocking the graphical - * interface by doing a potentially long search (should be quick normally, but not on a network file - * system for example). - */ + OcamlCompletionProposal[] proposals = new OcamlCompletionProposal[0]; + + IProject project = null; + + IDocument document = viewer.getDocument(); + + // must wait parsing job finish first. if (CompletionJob.isParsingFinished()) { - Def definitionsRoot = CompletionJob.buildDefinitionsTree(this.project, true); - proposals = findCompletionProposals(completion, definitionsRoot, documentOffset); + // lookup in module definition provided in editor first + Def outlineDefinitionsRoot = null; + if (editor instanceof OcamlEditor) { + OcamlEditor ocamlEditor = (OcamlEditor) editor; + project = ocamlEditor.getProject(); + outlineDefinitionsRoot = ocamlEditor.getOutlineDefinitionsTree(); + } + else if (editor instanceof OcamllexEditor) { + OcamllexEditor ocamllexEditor = (OcamllexEditor) editor; + project = ocamllexEditor.getProject(); + outlineDefinitionsRoot = null; + } + else if (editor instanceof OcamlyaccEditor) { + OcamlyaccEditor ocamlyaccEditor = (OcamlyaccEditor) editor; + project = ocamlyaccEditor.getProject(); + outlineDefinitionsRoot = null; + } + else { + project = null; + outlineDefinitionsRoot = null; + } + + Def interfacesDefinitionsRoot = null; + if (project != null) + interfacesDefinitionsRoot = CompletionJob.buildDefinitionsTree(project, false); + + proposals = findCompletionProposals(completion, outlineDefinitionsRoot, interfacesDefinitionsRoot, document, documentOffset); } else { proposals = new OcamlCompletionProposal[0]; OcamlPlugin.logInfo("Completion proposals skipped (background job not done yet)"); - } + } ICompletionProposal[] templateCompletionProposals; @@ -189,13 +218,30 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int * * @return the completions found */ - private OcamlCompletionProposal[] findCompletionProposals(String completion, Def definitionsRoot, + private OcamlCompletionProposal[] findCompletionProposals(String completion, + Def outlineDefinitionsRoot, + Def definitionsRoot, + IDocument document, int offset) { - ArrayList definitions = definitionsRoot.children; + // look in the module before the dot what's after the dot + // The module can be like "A.B." or "c.D.E." + if (completion.contains(".")) + return findDottedCompletionProposals(completion, outlineDefinitionsRoot, definitionsRoot, document, offset); + // find elements starting by in the list of elements + else + return findNondottedCompletionProposals(completion, outlineDefinitionsRoot, definitionsRoot, document, offset); + } + + // completion string must contained dots + private OcamlCompletionProposal[] findDottedCompletionProposals(String completion, + Def moduleDefinitionsRoot, + Def interfacesDefinitionsRoot, + IDocument document, + int offset) { ArrayList proposals = new ArrayList(); - + // look in the module before the dot what's after the dot // The module can be like "A.B." or "c.D.E." if (completion.contains(".")) { @@ -214,15 +260,23 @@ private OcamlCompletionProposal[] findCompletionProposals(String completion, Def prefix = parts[i]; i--; } - + String moduleName = prefix; + + // look into current module first boolean stop = false; while (!stop) { stop = true; - for (Def def : definitions) { + if (moduleDefinitionsRoot == null) + break; + + for (Def def : moduleDefinitionsRoot.children) { + if (def == null || def.name == null) + break; + if (def.name.equals(moduleName)) { if (def.type == Def.Type.Module) { - return findCompletionProposals(suffix, def, offset); + return findDottedCompletionProposals(suffix, moduleDefinitionsRoot, def, document, offset); } else if (def.type == Def.Type.ModuleAlias) { String aliasedName = def.children.get(0).name; @@ -237,11 +291,22 @@ else if (def.type == Def.Type.ModuleAlias) { } } } + + // then look into interface definitions + if (interfacesDefinitionsRoot == null) + return proposals.toArray(new OcamlCompletionProposal[0]); + for (Def def: interfacesDefinitionsRoot.children) { + if (def == null || def.name == null) + continue; + + if (def.name.equals(moduleName) && (def.type == Def.Type.Module)) + return findDottedCompletionProposals(suffix, def, interfacesDefinitionsRoot, document, offset); + } + } // find elements starting by in the list of elements else { - - for (Def def : definitions) { + for (Def def : moduleDefinitionsRoot.children) { if (def.name.startsWith(completion) && isCompletionDef(def)) proposals.add(new OcamlCompletionProposal(def, offset, completion.length())); @@ -250,20 +315,155 @@ else if (def.type == Def.Type.ModuleAlias) { return proposals.toArray(new OcamlCompletionProposal[0]); } + + private OcamlCompletionProposal[] findNondottedCompletionProposals(String completion, + Def outlineDefinitionsRoot, + Def interfacesDefinitionsRoot, + IDocument document, + int offset) { + + ArrayList proposals = new ArrayList(); + + // look up for definition + final Def nearestDef = findNearestDefAt(outlineDefinitionsRoot, offset, document); + proposals.addAll(lookCompletionProposalsUp(completion, nearestDef, offset)); + + proposals = removeDuplicatedCompletionProposal(proposals); + // look in current module + if (outlineDefinitionsRoot == null) + return proposals.toArray(new OcamlCompletionProposal[0]); + + for (Def def : outlineDefinitionsRoot.children) { + if (def.name.startsWith(completion) && isCompletionDef(def)) + proposals.add(new OcamlCompletionProposal(def, offset, completion.length())); + } + + proposals = removeDuplicatedCompletionProposal(proposals); + // look in all opened or included modules + if (interfacesDefinitionsRoot == null) + return proposals.toArray(new OcamlCompletionProposal[0]); + + for (Def def : outlineDefinitionsRoot.children) { + if (def == null || def.name == null) + break; + + if (def.type == Def.Type.Open) { + for (Def idef: interfacesDefinitionsRoot.children) { + if (idef == null || idef.name == null) + break; + + if (idef.name.equals(def.name)) { + for (Def d: idef.children) { + if (d == null || d.name == null) + break; + + if (d.name.startsWith(completion) && isCompletionDef(d)) + proposals.add(new OcamlCompletionProposal(d, offset, completion.length())); + } + } + } + } + } + + proposals = removeDuplicatedCompletionProposal(proposals); + return proposals.toArray(new OcamlCompletionProposal[0]); + } + + + + private ArrayList lookCompletionProposalsUp(String completion, Def node, int offset) { + ArrayList proposals = new ArrayList(); + + if (node == null) + return proposals; + + Def travelNode = node.parent; + while (true) { + if (travelNode == null || travelNode.name == null) + break; + + if (travelNode.name.startsWith(completion) + && (travelNode.name.length() > completion.length()) + && isCompletionDef(travelNode)) + proposals.add(new OcamlCompletionProposal(travelNode, offset, completion.length())); + + for (Def def : travelNode.children) { + if (def == null || def.name == null) + continue; + if (def.name.startsWith(completion) + && (def.name.length() > completion.length()) + && isCompletionDef(def)) + proposals.add(new OcamlCompletionProposal(def, offset, completion.length())); + } + + if (travelNode.type == Def.Type.Root) + break; + + travelNode = travelNode.parent; + } + + return proposals; + } + + private ArrayList removeDuplicatedCompletionProposal(ArrayList proposals) { + + ArrayList newProposals = new ArrayList(); + HashSet names = new HashSet<>(); + for (OcamlCompletionProposal p: proposals) { + String s = p.getDisplayString(); + if (!names.contains(s)) { + newProposals.add(p); + names.add(s); + } + } + + return newProposals; + } + + + /** Find an identifier (or an open directive) at a position in the document */ + private Def findNearestDefAt(Def def, int offset, IDocument doc) { + + if (def == null || doc == null) + return null; + + if (def.children.size() == 0) + return def; + + Def firstChild = def.children.get(0); + IRegion region = firstChild.getRegion(doc); + if (region != null) { + if (region.getOffset() > offset) + return def; + } + else return null; + + + Def nearestChild = null; + for (Def d : def.children) { + region = d.getRegion(doc); + if (region != null) { + if (region.getOffset() < offset) + nearestChild = d; + } + } + + return findNearestDefAt(nearestChild, offset, doc); + } private boolean isCompletionDef(Def def) { switch (def.type) { - case Parameter: - case Object: - case LetIn: +// case Parameter: +// case Object: +// case LetIn: case Open: case Include: case In: - case Identifier: +// case Identifier: case Dummy: case Root: - case Sig: - case Struct: +// case Sig: +// case Struct: return false; default: return true; @@ -401,10 +601,14 @@ private String expressionAtOffset(ITextViewer viewer, int documentOffset) { /** Return context informations available at a given position in the editor (at documentOffset) */ public IContextInformation[] computeContextInformation(ITextViewer viewer, int documentOffset) { + IProject project = null; + if (editor instanceof OcamlEditor) { + project = ((OcamlEditor) editor).getProject(); + } IContextInformation[] infos; if (CompletionJob.isParsingFinished()) { - Def definitionsRoot = CompletionJob.buildDefinitionsTree(this.project, true); + Def definitionsRoot = CompletionJob.buildDefinitionsTree(project, true); String expression = expressionAtOffset(viewer, documentOffset); diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index f09a444..b351956 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -150,7 +150,7 @@ protected void createActions() { public void textChanged(TextEvent event) { if (event.getDocumentEvent() != null) - rebuildOutline(500); + rebuildOutline(50); } }); } @@ -167,7 +167,7 @@ public void doSetInput(IEditorInput input) throws CoreException { super.doSetInput(input); if (this.outline != null) { - rebuildOutline(100); + rebuildOutline(50); } IProject project = this.getProject(); @@ -205,7 +205,7 @@ public Object getAdapter(@SuppressWarnings("unchecked") Class required) { if (this.outline == null) this.outline = new OcamlOutlineControl(this); - rebuildOutline(100); + rebuildOutline(50); return this.outline; } return super.getAdapter(required); @@ -464,7 +464,7 @@ public void rebuildOutline(int delay) { else outlineJob.cancel(); - outlineJob.setPriority(CompletionJob.DECORATE); + outlineJob.setPriority(CompletionJob.INTERACTIVE); outlineJob.setOutline(this.outline); outlineJob.setDoc(document); outlineJob.setEditor(this); From d531659da37e42fd36659e132bf7aedb9584058d Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 8 Oct 2014 06:50:50 +0800 Subject: [PATCH 031/127] minor changes --- .../completion/OcamlCompletionProcessor.java | 14 ++++++++++++-- .../src/ocaml/editors/OcamlSourceViewerConfig.java | 4 ++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 2ab54a0..2e24a73 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -405,14 +405,24 @@ && isCompletionDef(def)) return proposals; } + // remove and sort private ArrayList removeDuplicatedCompletionProposal(ArrayList proposals) { - + ArrayList newProposals = new ArrayList(); HashSet names = new HashSet<>(); for (OcamlCompletionProposal p: proposals) { String s = p.getDisplayString(); if (!names.contains(s)) { - newProposals.add(p); + int index = 0; + for (OcamlCompletionProposal q: newProposals) { + if (q.getDisplayString().compareTo(p.getDisplayString()) > 0) + break; + index++; + } + if (index < newProposals.size()) + newProposals.add(index,p); + else + newProposals.add(p); names.add(s); } } diff --git a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java index 889f476..242808c 100644 --- a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java +++ b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java @@ -149,7 +149,7 @@ public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceVie public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { ContentAssistant assistant = new ContentAssistant(); assistant.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)); - + assistant.enablePrefixCompletion(true); assistant.setContentAssistProcessor(new OcamlCompletionProcessor(this.ocamlEditor, OcamlPartitionScanner.OCAML_DOCUMENTATION_COMMENT), OcamlPartitionScanner.OCAML_DOCUMENTATION_COMMENT); @@ -162,7 +162,7 @@ public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { PreferenceConstants.P_EDITOR_AUTOCOMPLETION); assistant.enableAutoActivation(autoActivation); - + assistant.setAutoActivationDelay(100); assistant.setProposalPopupOrientation(IContentAssistant.PROPOSAL_STACKED); assistant.setContextInformationPopupOrientation(IContentAssistant.CONTEXT_INFO_ABOVE); From b3bf14e4272931e1ce6d0f23b7f5ebb528277c27 Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 8 Oct 2014 20:54:29 +0800 Subject: [PATCH 032/127] significant changes, and I'm happy with them --- .../ocaml/build/graph/CompilerVisitor.java | 7 ---- .../debugging/views/OcamlCallStackView.java | 2 - .../actions/MoveCursorDownwardOneBlock.java | 1 - .../actions/MoveCursorUpwardOneBlock.java | 1 - .../editor/actions/SelectUpwardOneBlock.java | 2 - .../completion/OcamlCompletionProcessor.java | 5 --- .../ocaml/editors/OcamlAutoEditStrategy.java | 3 -- Ocaml/src/ocaml/editors/OcamlEditor.java | 37 ++++++++++++++----- .../ocaml/editors/OcamlHyperlinkDetector.java | 3 -- .../editors/OcamlSourceViewerConfig.java | 25 +++++++++++++ .../ocaml/editors/yacc/OcamlyaccEditor.java | 4 ++ Ocaml/src/ocaml/views/ast/Indexer.java | 4 -- .../views/outline/OcamlOutlineControl.java | 2 +- .../views/outline/OutlineBuildListener.java | 2 +- Ocaml/src/ocaml/views/outline/OutlineJob.java | 9 ++++- 15 files changed, 65 insertions(+), 42 deletions(-) diff --git a/Ocaml/src/ocaml/build/graph/CompilerVisitor.java b/Ocaml/src/ocaml/build/graph/CompilerVisitor.java index 9a3d187..79bfadb 100644 --- a/Ocaml/src/ocaml/build/graph/CompilerVisitor.java +++ b/Ocaml/src/ocaml/build/graph/CompilerVisitor.java @@ -22,13 +22,6 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorReference; -import org.eclipse.ui.IFileEditorInput; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.part.FileEditorInput; /** * Visit a graph layer by layer, to compile all vertices in the right order.
diff --git a/Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java b/Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java index 850f42b..e3cc996 100644 --- a/Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java +++ b/Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java @@ -6,8 +6,6 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.MouseAdapter; -import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Rectangle; diff --git a/Ocaml/src/ocaml/editor/actions/MoveCursorDownwardOneBlock.java b/Ocaml/src/ocaml/editor/actions/MoveCursorDownwardOneBlock.java index e57aff9..3d82fd2 100644 --- a/Ocaml/src/ocaml/editor/actions/MoveCursorDownwardOneBlock.java +++ b/Ocaml/src/ocaml/editor/actions/MoveCursorDownwardOneBlock.java @@ -5,7 +5,6 @@ import org.eclipse.jface.action.IAction; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.widgets.Control; diff --git a/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardOneBlock.java b/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardOneBlock.java index 2d22584..5e47909 100644 --- a/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardOneBlock.java +++ b/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardOneBlock.java @@ -5,7 +5,6 @@ import org.eclipse.jface.action.IAction; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.widgets.Control; diff --git a/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java b/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java index 3a9e374..983b79e 100644 --- a/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java +++ b/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java @@ -1,7 +1,6 @@ package ocaml.editor.actions; import ocaml.OcamlPlugin; -import ocaml.editors.OcamlEditor; import org.eclipse.jface.action.IAction; import org.eclipse.jface.text.BadLocationException; @@ -16,7 +15,6 @@ import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; import org.eclipse.ui.editors.text.TextEditor; -import org.eclipse.ui.texteditor.ITextEditor; public class SelectUpwardOneBlock implements IWorkbenchWindowActionDelegate { diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 2e24a73..a815a26 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -1,9 +1,7 @@ package ocaml.editor.completion; -import java.io.File; import java.util.ArrayList; import java.util.HashSet; -import java.util.List; import ocaml.OcamlPlugin; import ocaml.editor.syntaxcoloring.OcamlPartitionScanner; @@ -11,8 +9,6 @@ import ocaml.editors.lex.OcamllexEditor; import ocaml.editors.yacc.OcamlyaccEditor; import ocaml.parser.Def; -import ocaml.parser.Def.Type; -import ocaml.parsers.OcamlNewInterfaceParser; import ocaml.util.Misc; import org.eclipse.core.resources.IProject; @@ -25,7 +21,6 @@ import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.contentassist.IContextInformationValidator; -import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.ui.editors.text.TextEditor; /** diff --git a/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java b/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java index 7b5af1a..95be336 100644 --- a/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java +++ b/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java @@ -14,12 +14,9 @@ import org.eclipse.jface.text.IAutoEditStrategy; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension3; -import org.eclipse.jface.text.IDocumentPartitioner; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITypedRegion; -import org.eclipse.jface.text.Position; import org.eclipse.jface.text.TextUtilities; -import org.eclipse.jface.viewers.IDoubleClickListener; //TODO: linked mode diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index b351956..3646eca 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -27,6 +27,7 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextListener; @@ -35,6 +36,7 @@ import org.eclipse.jface.text.TextEvent; import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.text.TextViewer; +import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.MatchingCharacterPainter; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.custom.StyledText; @@ -145,12 +147,24 @@ protected void createActions() { } catch (Exception e) { OcamlPlugin.logError("ocaml plugin error", e); } - - this.getSourceViewer().addTextListener(new ITextListener() { - + + + final ISourceViewer viewer = this.getSourceViewer(); + final OcamlSourceViewerConfig viewerConfig = (OcamlSourceViewerConfig) this.getSourceViewerConfiguration(); + viewer.addTextListener(new ITextListener() { + public void textChanged(TextEvent event) { - if (event.getDocumentEvent() != null) - rebuildOutline(50); + // Trung: rebuild only when content assistant is inactive + if (viewerConfig.isContentAssistantActive() || event != null) + return; + + DocumentEvent docEvent = event.getDocumentEvent(); + if (docEvent == null) + return; + + String text = docEvent.getText().trim(); + if (!text.isEmpty()) + rebuildOutline(50, false); // don't sync outline with editor } }); } @@ -167,7 +181,7 @@ public void doSetInput(IEditorInput input) throws CoreException { super.doSetInput(input); if (this.outline != null) { - rebuildOutline(50); + rebuildOutline(50, false); } IProject project = this.getProject(); @@ -205,7 +219,7 @@ public Object getAdapter(@SuppressWarnings("unchecked") Class required) { if (this.outline == null) this.outline = new OcamlOutlineControl(this); - rebuildOutline(50); + rebuildOutline(50, false); return this.outline; } return super.getAdapter(required); @@ -446,7 +460,7 @@ public void doSave(IProgressMonitor monitor) { * this.fOutlinePage; } */ - public void rebuildOutline(int delay) { + public void rebuildOutline(int delay, boolean syncWithEditor) { // invalidate previous definitions this.codeDefinitionsTree = null; @@ -457,7 +471,7 @@ public void rebuildOutline(int delay) { // String doc = document.get(); if (outlineJob == null) - outlineJob = new OutlineJob("Rebuilding outline"); + outlineJob = new OutlineJob("Rebuilding outline", syncWithEditor); // else if (outlineJob.getState() == OutlineJob.RUNNING) // return; // only one Job at a time @@ -479,7 +493,10 @@ public void rebuildOutline(int delay) { @Override public void handleCursorPositionChanged() { super.handleCursorPositionChanged(); - synchronizeOutline(); + + // Trung: don't synchronize outline job when cursor position change + // synchronizeOutline(); + fireCursorPositionChanged(getTextViewer().getSelectedRange()); if (OcamlPlugin.getInstance().getPreferenceStore().getBoolean( diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index 121fba4..aebb5cc 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -3,14 +3,12 @@ import java.io.File; import java.io.FilenameFilter; import java.net.URI; -import java.util.ArrayList; import java.util.List; import ocaml.OcamlPlugin; import ocaml.editor.completion.CompletionJob; import ocaml.parser.Def; import ocaml.parsers.OcamlNewInterfaceParser; -import ocaml.util.FileUtil; import ocaml.util.Misc; import ocaml.util.OcamlPaths; @@ -24,7 +22,6 @@ import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextSelection; -import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; import org.eclipse.ui.IEditorPart; diff --git a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java index 242808c..d6114d9 100644 --- a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java +++ b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java @@ -18,7 +18,10 @@ import org.eclipse.jface.text.ITextDoubleClickStrategy; import org.eclipse.jface.text.ITextHover; import org.eclipse.jface.text.TextAttribute; +import org.eclipse.jface.text.contentassist.ContentAssistEvent; import org.eclipse.jface.text.contentassist.ContentAssistant; +import org.eclipse.jface.text.contentassist.ICompletionListener; +import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContentAssistant; import org.eclipse.jface.text.formatter.IContentFormatter; import org.eclipse.jface.text.formatter.MultiPassContentFormatter; @@ -52,9 +55,11 @@ */ public class OcamlSourceViewerConfig extends SourceViewerConfiguration { private OcamlEditor ocamlEditor; + private boolean contentAssistantActived; public OcamlSourceViewerConfig(OcamlEditor ocamlEditor) { this.ocamlEditor = ocamlEditor; + this.contentAssistantActived = false; } /** @@ -157,6 +162,22 @@ public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { IDocument.DEFAULT_CONTENT_TYPE), IDocument.DEFAULT_CONTENT_TYPE); assistant.enableAutoInsert(true); + assistant.addCompletionListener(new ICompletionListener() { + @Override + public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) { + contentAssistantActived = true; + } + + @Override + public void assistSessionStarted(ContentAssistEvent event) { + contentAssistantActived = true; + } + + @Override + public void assistSessionEnded(ContentAssistEvent event) { + contentAssistantActived = false; + } + }); boolean autoActivation = OcamlPlugin.getInstance().getPreferenceStore().getBoolean( PreferenceConstants.P_EDITOR_AUTOCOMPLETION); @@ -245,6 +266,10 @@ public void propertyChange(PropertyChangeEvent event) { else return null; } + + public boolean isContentAssistantActive() { + return contentAssistantActived; + } } diff --git a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java index 5403a1a..b36bc8b 100644 --- a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java +++ b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java @@ -135,6 +135,10 @@ public Object getAdapter(@SuppressWarnings("unchecked") Class required) { } public void rebuildOutline(int delay) { + /* + * Trung: rebuilding outline will dispose all completion proposal + * pop-up windows if existing. + */ IEditorInput input = this.getEditorInput(); IDocument document = this.getDocumentProvider().getDocument(input); diff --git a/Ocaml/src/ocaml/views/ast/Indexer.java b/Ocaml/src/ocaml/views/ast/Indexer.java index 5acfbc4..4477052 100644 --- a/Ocaml/src/ocaml/views/ast/Indexer.java +++ b/Ocaml/src/ocaml/views/ast/Indexer.java @@ -3,11 +3,7 @@ import static org.eclipse.core.runtime.Status.OK_STATUS; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.net.URL; import ocaml.OcamlPlugin; diff --git a/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java b/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java index ae8047c..8caef5a 100644 --- a/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java +++ b/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java @@ -101,7 +101,7 @@ public void run() { public void run() { OcamlOutlineControl.bDebug = this.isChecked(); super.run(); - editor.rebuildOutline(0); + editor.rebuildOutline(0, false); outline.update(); } }; diff --git a/Ocaml/src/ocaml/views/outline/OutlineBuildListener.java b/Ocaml/src/ocaml/views/outline/OutlineBuildListener.java index bd13ee0..3a3e806 100644 --- a/Ocaml/src/ocaml/views/outline/OutlineBuildListener.java +++ b/Ocaml/src/ocaml/views/outline/OutlineBuildListener.java @@ -95,7 +95,7 @@ public void run() { return; IEditorPart editorPart = workbenchPage.getActiveEditor(); if (editorPart instanceof OcamlEditor) - ((OcamlEditor) editorPart).rebuildOutline(500); + ((OcamlEditor) editorPart).rebuildOutline(500,false); } catch (Throwable e) { OcamlPlugin.logError("rebuilding outline after build", e); } diff --git a/Ocaml/src/ocaml/views/outline/OutlineJob.java b/Ocaml/src/ocaml/views/outline/OutlineJob.java index 8573290..b5e25d8 100644 --- a/Ocaml/src/ocaml/views/outline/OutlineJob.java +++ b/Ocaml/src/ocaml/views/outline/OutlineJob.java @@ -49,8 +49,9 @@ public class OutlineJob extends Job { - public OutlineJob(String name) { + public OutlineJob(String name, boolean syncWithEditor) { super(name); + this.syncEditor = syncWithEditor; } /** The outline. Can be null if the outline view is closed */ @@ -59,6 +60,8 @@ public OutlineJob(String name) { private IDocument doc; private OcamlEditor editor; + + private boolean syncEditor; public void setDoc(IDocument doc) { this.doc = doc; @@ -435,7 +438,9 @@ public void run() { } else outline.setInput(fOutlineDefinitions); - editor.synchronizeOutline(); + // synchronize outline with editor + if (syncEditor) + editor.synchronizeOutline(); } } From 999e8319a28566a79eccc86b43fbbf32a94fe5bb Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 8 Oct 2014 22:28:47 +0800 Subject: [PATCH 033/127] improve on selection feature --- .../actions/SelectDownwardOneBlock.java | 19 ++++++++----------- .../editor/actions/SelectUpwardOneBlock.java | 16 ++++++---------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/SelectDownwardOneBlock.java b/Ocaml/src/ocaml/editor/actions/SelectDownwardOneBlock.java index 12edc2a..e2203de 100644 --- a/Ocaml/src/ocaml/editor/actions/SelectDownwardOneBlock.java +++ b/Ocaml/src/ocaml/editor/actions/SelectDownwardOneBlock.java @@ -1,6 +1,7 @@ package ocaml.editor.actions; import ocaml.OcamlPlugin; +import ocaml.editors.OcamlEditor; import org.eclipse.jface.action.IAction; import org.eclipse.jface.text.BadLocationException; @@ -8,6 +9,7 @@ import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; @@ -57,14 +59,9 @@ public void run(IAction action) { final StyledText styledText = (StyledText) control; int cursorOffset = styledText.getCaretOffset(); - - TextSelection selection = - (TextSelection) editor.getSelectionProvider().getSelection(); - int startSelectionOffset; - if (selection.getOffset() < cursorOffset) - startSelectionOffset = selection.getOffset(); - else - startSelectionOffset = selection.getOffset() + selection.getLength(); + + Point selection = styledText.getSelection(); + int startOffset = (selection.x < cursorOffset) ? selection.x : selection.y; try { int lineNum= doc.getLineOfOffset(cursorOffset); @@ -72,12 +69,12 @@ public void run(IAction action) { if (lineNum == (numOfLine - 2)) { int lastLineOffset = doc.getLineOffset(lineNum+1); - editor.selectAndReveal(startSelectionOffset, lastLineOffset - startSelectionOffset); + styledText.setSelection(startOffset, lastLineOffset); return; } if (lineNum >= (numOfLine - 1)) { - editor.selectAndReveal(startSelectionOffset, doc.getLength() - startSelectionOffset ); + styledText.setSelection(startOffset, doc.getLength()); return; } @@ -102,7 +99,7 @@ else if (!isCurrentLineEmpty) break; } int newOffset = doc.getLineOffset(lineNum); - editor.selectAndReveal(startSelectionOffset, newOffset - startSelectionOffset); + styledText.setSelection(startOffset, newOffset); } catch (BadLocationException e) { return; } diff --git a/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java b/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java index 983b79e..0c1dc59 100644 --- a/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java +++ b/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java @@ -8,6 +8,7 @@ import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; @@ -58,20 +59,15 @@ public void run(IAction action) { final StyledText styledText = (StyledText) control; int cursorOffset = styledText.getCaretOffset(); - TextSelection selection = - (TextSelection) editor.getSelectionProvider().getSelection(); - int startSelectionOffset; - if (selection.getOffset() < cursorOffset) - startSelectionOffset = selection.getOffset(); - else - startSelectionOffset = selection.getOffset() + selection.getLength(); + Point selection = styledText.getSelection(); + int startOffset = (selection.x < cursorOffset) ? selection.x : selection.y; try { int lineNum= doc.getLineOfOffset(cursorOffset); int numOfLine = doc.getNumberOfLines(); if (lineNum <= 0) { - editor.selectAndReveal(startSelectionOffset, -startSelectionOffset); + styledText.setSelection(startOffset, 0); return; } @@ -84,7 +80,7 @@ public void run(IAction action) { String prevLine= doc.get(beginOffset, endOffset - beginOffset + 1); boolean isPrevLineEmpty = prevLine.trim().isEmpty(); if (isPrevLineEmpty && (cursorOffset != currentLineOffset)) { - editor.selectAndReveal(startSelectionOffset, currentLineOffset - startSelectionOffset); + styledText.setSelection(startOffset, currentLineOffset); return; } @@ -105,7 +101,7 @@ else if (isPrevLineEmpty) } } int newOffset = doc.getLineOffset(lineNum); - editor.selectAndReveal(startSelectionOffset, newOffset - startSelectionOffset); + styledText.setSelection(startOffset, newOffset); } catch (BadLocationException e) { return; } From ba0e20290d83bd378c5b3d6080b073a1a26ad23b Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 8 Oct 2014 22:59:54 +0800 Subject: [PATCH 034/127] improvements --- .../completion/OcamlCompletionProcessor.java | 133 ++++++++---------- .../editors/OcamlSourceViewerConfig.java | 14 +- 2 files changed, 71 insertions(+), 76 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index a815a26..ae434b3 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -214,24 +214,26 @@ else if (editor instanceof OcamlyaccEditor) { * @return the completions found */ private OcamlCompletionProposal[] findCompletionProposals(String completion, - Def outlineDefinitionsRoot, - Def definitionsRoot, - IDocument document, + Def outlineDefsRoot, + Def defsRoot, + IDocument doc, int offset) { - // look in the module before the dot what's after the dot - // The module can be like "A.B." or "c.D.E." + ArrayList proposals; if (completion.contains(".")) - return findDottedCompletionProposals(completion, outlineDefinitionsRoot, definitionsRoot, document, offset); - // find elements starting by in the list of elements + proposals = processDottedCompletion(completion, outlineDefsRoot, defsRoot, doc, offset); else - return findNondottedCompletionProposals(completion, outlineDefinitionsRoot, definitionsRoot, document, offset); + proposals = processNondottedCompletion(completion, outlineDefsRoot, defsRoot, doc, offset); + + proposals = removeDuplicatedCompletionProposal(proposals); + + return proposals.toArray(new OcamlCompletionProposal[0]); } // completion string must contained dots - private OcamlCompletionProposal[] findDottedCompletionProposals(String completion, - Def moduleDefinitionsRoot, - Def interfacesDefinitionsRoot, + private ArrayList processDottedCompletion(String completion, + Def outlineDefsRoot, + Def defsRoot, IDocument document, int offset) { @@ -262,110 +264,109 @@ private OcamlCompletionProposal[] findDottedCompletionProposals(String completio boolean stop = false; while (!stop) { stop = true; - if (moduleDefinitionsRoot == null) + if (outlineDefsRoot == null) break; - for (Def def : moduleDefinitionsRoot.children) { + for (Def def : outlineDefsRoot.children) { if (def == null || def.name == null) break; - if (def.name.equals(moduleName)) { - if (def.type == Def.Type.Module) { - return findDottedCompletionProposals(suffix, moduleDefinitionsRoot, def, document, offset); - } - else if (def.type == Def.Type.ModuleAlias) { - String aliasedName = def.children.get(0).name; - if (moduleName.equals(aliasedName)) - stop = true; - else { - moduleName = aliasedName; - stop = false; - } - break; + if (!def.name.equals(moduleName)) + continue; + + if (def.type == Def.Type.Module) { + return processDottedCompletion(suffix, outlineDefsRoot, def, document, offset); + } + else if (def.type == Def.Type.ModuleAlias) { + String aliasedName = def.children.get(0).name; + if (moduleName.equals(aliasedName)) + stop = true; + else { + moduleName = aliasedName; + stop = false; } + break; } } } // then look into interface definitions - if (interfacesDefinitionsRoot == null) - return proposals.toArray(new OcamlCompletionProposal[0]); - for (Def def: interfacesDefinitionsRoot.children) { + if (defsRoot == null) + return proposals; + for (Def def: defsRoot.children) { if (def == null || def.name == null) continue; if (def.name.equals(moduleName) && (def.type == Def.Type.Module)) - return findDottedCompletionProposals(suffix, def, interfacesDefinitionsRoot, document, offset); + return processDottedCompletion(suffix, def, defsRoot, document, offset); } } // find elements starting by in the list of elements else { - for (Def def : moduleDefinitionsRoot.children) { + for (Def def : outlineDefsRoot.children) { if (def.name.startsWith(completion) && isCompletionDef(def)) proposals.add(new OcamlCompletionProposal(def, offset, completion.length())); } } - return proposals.toArray(new OcamlCompletionProposal[0]); + return proposals; } - private OcamlCompletionProposal[] findNondottedCompletionProposals(String completion, - Def outlineDefinitionsRoot, - Def interfacesDefinitionsRoot, + private ArrayList processNondottedCompletion(String completion, + Def outlineDefsRoot, + Def defsRoot, IDocument document, int offset) { ArrayList proposals = new ArrayList(); // look up for definition - final Def nearestDef = findNearestDefAt(outlineDefinitionsRoot, offset, document); + final Def nearestDef = findNearestDefAt(outlineDefsRoot, offset, document); proposals.addAll(lookCompletionProposalsUp(completion, nearestDef, offset)); - proposals = removeDuplicatedCompletionProposal(proposals); // look in current module - if (outlineDefinitionsRoot == null) - return proposals.toArray(new OcamlCompletionProposal[0]); + if (outlineDefsRoot == null) + return proposals; - for (Def def : outlineDefinitionsRoot.children) { + for (Def def : outlineDefsRoot.children) { if (def.name.startsWith(completion) && isCompletionDef(def)) proposals.add(new OcamlCompletionProposal(def, offset, completion.length())); } - proposals = removeDuplicatedCompletionProposal(proposals); // look in all opened or included modules - if (interfacesDefinitionsRoot == null) - return proposals.toArray(new OcamlCompletionProposal[0]); + if (defsRoot == null) + return proposals; - for (Def def : outlineDefinitionsRoot.children) { + for (Def def : outlineDefsRoot.children) { if (def == null || def.name == null) break; - if (def.type == Def.Type.Open) { - for (Def idef: interfacesDefinitionsRoot.children) { - if (idef == null || idef.name == null) + if (def.type != Def.Type.Open) + continue; + + for (Def idef: defsRoot.children) { + if (idef == null || idef.name == null) + break; + + if (!idef.name.equals(def.name)) + continue; + + for (Def d: idef.children) { + if (d == null || d.name == null) break; - if (idef.name.equals(def.name)) { - for (Def d: idef.children) { - if (d == null || d.name == null) - break; - - if (d.name.startsWith(completion) && isCompletionDef(d)) - proposals.add(new OcamlCompletionProposal(d, offset, completion.length())); - } - } + if (d.name.startsWith(completion) && isCompletionDef(d)) + proposals.add(new OcamlCompletionProposal(d, offset, completion.length())); } } } - proposals = removeDuplicatedCompletionProposal(proposals); - return proposals.toArray(new OcamlCompletionProposal[0]); + return proposals; } - - + private ArrayList lookCompletionProposalsUp(String completion, Def node, int offset) { ArrayList proposals = new ArrayList(); @@ -400,7 +401,6 @@ && isCompletionDef(def)) return proposals; } - // remove and sort private ArrayList removeDuplicatedCompletionProposal(ArrayList proposals) { ArrayList newProposals = new ArrayList(); @@ -408,16 +408,7 @@ private ArrayList removeDuplicatedCompletionProposal(Ar for (OcamlCompletionProposal p: proposals) { String s = p.getDisplayString(); if (!names.contains(s)) { - int index = 0; - for (OcamlCompletionProposal q: newProposals) { - if (q.getDisplayString().compareTo(p.getDisplayString()) > 0) - break; - index++; - } - if (index < newProposals.size()) - newProposals.add(index,p); - else - newProposals.add(p); + newProposals.add(p); names.add(s); } } diff --git a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java index d6114d9..bb68fd1 100644 --- a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java +++ b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java @@ -22,6 +22,7 @@ import org.eclipse.jface.text.contentassist.ContentAssistant; import org.eclipse.jface.text.contentassist.ICompletionListener; import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.ICompletionProposalSorter; import org.eclipse.jface.text.contentassist.IContentAssistant; import org.eclipse.jface.text.formatter.IContentFormatter; import org.eclipse.jface.text.formatter.MultiPassContentFormatter; @@ -161,30 +162,33 @@ public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { assistant.setContentAssistProcessor(new OcamlCompletionProcessor(this.ocamlEditor, IDocument.DEFAULT_CONTENT_TYPE), IDocument.DEFAULT_CONTENT_TYPE); - assistant.enableAutoInsert(true); assistant.addCompletionListener(new ICompletionListener() { @Override public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) { contentAssistantActived = true; } - @Override public void assistSessionStarted(ContentAssistEvent event) { contentAssistantActived = true; } - @Override public void assistSessionEnded(ContentAssistEvent event) { contentAssistantActived = false; } }); + + assistant.setSorter(new ICompletionProposalSorter() { + @Override + public int compare(ICompletionProposal p1, ICompletionProposal p2) { + return p1.getDisplayString().compareTo(p2.getDisplayString()); + } + }); boolean autoActivation = OcamlPlugin.getInstance().getPreferenceStore().getBoolean( PreferenceConstants.P_EDITOR_AUTOCOMPLETION); - assistant.enableAutoActivation(autoActivation); - assistant.setAutoActivationDelay(100); + assistant.enableAutoInsert(true); assistant.setProposalPopupOrientation(IContentAssistant.PROPOSAL_STACKED); assistant.setContextInformationPopupOrientation(IContentAssistant.CONTEXT_INFO_ABOVE); assistant.setInformationControlCreator(new OcamlInformationControlCreator()); From 5d0eaa9013ecc16ae53ef1d7bc96a721b17fdff5 Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 8 Oct 2014 23:20:38 +0800 Subject: [PATCH 035/127] improvements --- Ocaml/src/ocaml/editors/OcamlEditor.java | 2 +- Ocaml/src/ocaml/views/outline/OutlineJob.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index 3646eca..2c393c6 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -155,7 +155,7 @@ protected void createActions() { public void textChanged(TextEvent event) { // Trung: rebuild only when content assistant is inactive - if (viewerConfig.isContentAssistantActive() || event != null) + if (viewerConfig.isContentAssistantActive() || event == null) return; DocumentEvent docEvent = event.getDocumentEvent(); diff --git a/Ocaml/src/ocaml/views/outline/OutlineJob.java b/Ocaml/src/ocaml/views/outline/OutlineJob.java index b5e25d8..fd7eb1c 100644 --- a/Ocaml/src/ocaml/views/outline/OutlineJob.java +++ b/Ocaml/src/ocaml/views/outline/OutlineJob.java @@ -51,7 +51,7 @@ public class OutlineJob extends Job { public OutlineJob(String name, boolean syncWithEditor) { super(name); - this.syncEditor = syncWithEditor; + this.syncWithEditor = syncWithEditor; } /** The outline. Can be null if the outline view is closed */ @@ -61,7 +61,7 @@ public OutlineJob(String name, boolean syncWithEditor) { private OcamlEditor editor; - private boolean syncEditor; + private boolean syncWithEditor; public void setDoc(IDocument doc) { this.doc = doc; @@ -439,7 +439,7 @@ public void run() { outline.setInput(fOutlineDefinitions); // synchronize outline with editor - if (syncEditor) + if (syncWithEditor) editor.synchronizeOutline(); } From a357deae1ee89c78a5a90fc3e011cb32ad27ed4f Mon Sep 17 00:00:00 2001 From: trungtq Date: Thu, 9 Oct 2014 14:28:35 +0800 Subject: [PATCH 036/127] improve hover feature --- Ocaml/plugin.xml | 18 ++ .../ocaml/editor/actions/ShowTextHover.java | 93 ++++++ Ocaml/src/ocaml/editors/OcamlEditor.java | 47 +-- Ocaml/src/ocaml/editors/OcamlTextHover.java | 282 +++++++++++++----- .../preferences/PreferenceConstants.java | 1 + .../preferences/PreferenceInitializer.java | 1 + .../ocaml/preferences/RootPreferencePage.java | 5 + 7 files changed, 352 insertions(+), 95 deletions(-) create mode 100644 Ocaml/src/ocaml/editor/actions/ShowTextHover.java diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index ab27070..78d7fee 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -858,6 +858,13 @@ definitionId="Ocaml.openQuickOutlineCommand" id="Ocaml_sourceActions_QuickOutline" label="Quick Outline" menubarPath="Ocaml_sourceMenu/slot1" style="push"/> + +
@@ -949,6 +956,11 @@ categoryId="Ocaml.commandscategory" id="Ocaml.selectDownwardOneBlock" name="Select Downward One Block"> + + @@ -1068,6 +1080,12 @@ contextId="org.eclipse.ui.textEditorScope" schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" sequence="M1+M2+ARROW_DOWN"> + + diff --git a/Ocaml/src/ocaml/editor/actions/ShowTextHover.java b/Ocaml/src/ocaml/editor/actions/ShowTextHover.java new file mode 100644 index 0000000..4e4b9e8 --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/ShowTextHover.java @@ -0,0 +1,93 @@ +package ocaml.editor.actions; + +import ocaml.OcamlPlugin; +import ocaml.editors.OcamlEditor; +import ocaml.editors.OcamlTextHover; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.editors.text.TextEditor; + +public class ShowTextHover implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + + IWorkbenchPage page = window.getActivePage(); + + if (page == null) { + OcamlPlugin.logWarning(GotoDefinition.class.getSimpleName() + + ": page is null"); + return; + } + + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart == null) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": editorPart is null"); + return; + } + + if (!(editorPart instanceof OcamlEditor)) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": only works on ml and mli files"); + return; + } + + final OcamlEditor editor = (OcamlEditor) editorPart; + ITextViewer viewer = editor.getTextViewer(); + IEditorInput editorInput = editor.getEditorInput(); + IDocument doc = editor.getDocumentProvider().getDocument(editorInput); + Control control = (Control)editor.getAdapter(Control.class); + + if (!(control instanceof StyledText)) + { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": Cannot get caret position"); + return; + } + + final StyledText styledText = (StyledText) control; + int offset = styledText.getCaretOffset(); + + OcamlTextHover hover = new OcamlTextHover(editor); + IRegion region = hover.getHoverRegion(viewer, offset); + final String hoverInfo = hover.getHoverInfoOneLine(viewer, region); + + Display.getCurrent().asyncExec(new Runnable() { + public void run() { + if (!hoverInfo.equals("")) + editor.setStatusLineMessage(hoverInfo); + else + editor.setStatusLineMessage(""); + } + }); + + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index 2c393c6..ca28596 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -494,28 +494,39 @@ public void rebuildOutline(int delay, boolean syncWithEditor) { public void handleCursorPositionChanged() { super.handleCursorPositionChanged(); - // Trung: don't synchronize outline job when cursor position change - // synchronizeOutline(); - fireCursorPositionChanged(getTextViewer().getSelectedRange()); + final OcamlEditor editor = this; + OcamlTextHover hover = new OcamlTextHover(editor); + ITextViewer viewer = this.getTextViewer(); + int offset = this.getCaretOffset(); + IRegion region = hover.getHoverRegion(viewer, offset); + + String message = ""; + if (OcamlPlugin.getInstance().getPreferenceStore().getBoolean( - PreferenceConstants.P_SHOW_TYPES_IN_STATUS_BAR)) { - final String annot = OcamlTextHover.getAnnotAt(this, - (TextViewer) this.getSourceViewer(), this.getCaretOffset()).trim(); - final OcamlEditor editor = this; - Display.getCurrent().asyncExec(new Runnable() { - - public void run() { - if (editor == null) - return; - if (!annot.equals("")) - editor.setStatusLineMessage(annot); - else - editor.setStatusLineMessage(null); // clear - } - }); + PreferenceConstants.P_SHOW_MARKERS_IN_STATUS_BAR)) { + message = hover.getMarkerInfoOneLine(viewer, region); } + + // only display type info when there isn't any markers + if (message.isEmpty() + && OcamlPlugin.getInstance().getPreferenceStore().getBoolean( + PreferenceConstants.P_SHOW_TYPES_IN_STATUS_BAR)) { + message = hover.getTypeInfoOneLine(viewer, region); + } + + final String statusMessage = message; + Display.getCurrent().asyncExec(new Runnable() { + public void run() { + editor.setStatusLineMessage(statusMessage); + } + }); + } + + @Override + public void setStatusLineMessage(String message) { + super.setStatusLineMessage(message); } private Def codeDefinitionsTree = null; diff --git a/Ocaml/src/ocaml/editors/OcamlTextHover.java b/Ocaml/src/ocaml/editors/OcamlTextHover.java index 90f32e7..48a1134 100644 --- a/Ocaml/src/ocaml/editors/OcamlTextHover.java +++ b/Ocaml/src/ocaml/editors/OcamlTextHover.java @@ -28,35 +28,85 @@ */ public class OcamlTextHover implements ITextHover { private OcamlEditor ocamlEditor; + public OcamlTextHover(OcamlEditor ocamlEditor) { this.ocamlEditor = ocamlEditor; } /** - * Returns the string to display in a pop-up which gives informations about the element currently under - * the mouse cursor in the editor + * Returns the string to display in a pop-up which gives informations + * about the element currently under the mouse cursor in the editor */ + @Override public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { - // the file in the workspace. null if the file is external - IFile file = ocamlEditor.getFileBeingEdited(); + String markersInfo = getMarkerInfo(textViewer, hoverRegion); + String valueInfo = getExpressionValue(textViewer, hoverRegion); + String typeInfo = getTypeInfo(textViewer, hoverRegion); + + String hoverInfo = ""; + + if (!markersInfo.isEmpty()) { + hoverInfo = markersInfo; + } + + if (!valueInfo.isEmpty()) { + if (hoverInfo.isEmpty()) + hoverInfo = valueInfo; + else + hoverInfo = hoverInfo + "\n\n" + "Value info: " + "\n" + valueInfo; + } + + if (!typeInfo.isEmpty()) { + if (hoverInfo.isEmpty()) + hoverInfo = typeInfo; + else + hoverInfo = hoverInfo + "\n\n" + "Type info: " + "\n" + typeInfo; + } + + return hoverInfo; + } + + // get HoverInfo in 1 line format + public String getHoverInfoOneLine(ITextViewer textViewer, IRegion hoverRegion) { + // display only marker info, value info, or type info + String hoverInfo = getMarkerInfo(textViewer, hoverRegion); + + if (hoverInfo.isEmpty()) + hoverInfo = getExpressionValue(textViewer, hoverRegion); + + if (hoverInfo.isEmpty()) + hoverInfo = getTypeInfo(textViewer, hoverRegion); + + String[] lines = hoverInfo.split(System.lineSeparator()); + String hoverInfoOneLine = ""; + for (String line: lines) + hoverInfoOneLine = hoverInfoOneLine + " " + line.trim(); + return hoverInfoOneLine.trim(); + } - // the full system path of the file + + /** + * Returns the string to display in a pop-up which gives marker informations + * about the element currently under the mouse cursor in the editor + */ + public String getMarkerInfo(ITextViewer textViewer, IRegion region) { + IFile file = ocamlEditor.getFileBeingEdited(); IPath filePath = ocamlEditor.getPathOfFileBeingEdited(); if (filePath == null) - return ""; + return ""; - if (hoverRegion == null) { + if (region == null) { ocaml.OcamlPlugin.logError("OcamlTextHover:getHoverInfo null region"); return ""; } try { // error message string, if we found one in the hovered region - String hoverMessage = ""; + String markerInfo = ""; - int hoverOffset = hoverRegion.getOffset(); + int hoverOffset = region.getOffset(); if (file != null) { IMarker[] markers = file.findMarkers(null, true, 1); @@ -66,102 +116,180 @@ public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { if (hoverOffset >= markerStart && hoverOffset <= markerEnd) { String message = marker.getAttribute(IMarker.MESSAGE, ""); - hoverMessage = hoverMessage + message.trim() + "\n"; + markerInfo = markerInfo + message.trim() + "\n\n"; } } + return markerInfo.trim(); } + } catch (Throwable e) { + // ocaml.OcamlPlugin.logError("Erreur dans OcamlTextHover:getHoverInfo", e); + } - // if the debugger is started, we ask it for the value of the variable under the cursor - if (OcamlDebugger.getInstance().isStarted()) { - String text = textViewer.getDocument().get(); - String expression = expressionAtOffset(text, hoverOffset).trim(); + return ""; + } + + // get markerInfo in 1 line format + public String getMarkerInfoOneLine(ITextViewer textViewer, IRegion region) { + String markerInfo = getMarkerInfo(textViewer, region); + String[] lines = markerInfo.split(System.lineSeparator()); + String markerInfoOneLine = ""; + for (String line: lines) + markerInfoOneLine = markerInfoOneLine + " " + line.trim(); + return markerInfoOneLine.trim(); + } + + /** + * Returns the string to display in a pop-up which gives type informations + * about the element currently under the mouse cursor in the editor + */ + public String getTypeInfo(ITextViewer textViewer, IRegion region) { + IFile file = ocamlEditor.getFileBeingEdited(); + IPath filePath = ocamlEditor.getPathOfFileBeingEdited(); - if (!expression.equals("")) { - String value = OcamlDebugger.getInstance().display(expression).trim(); + if (filePath == null) + return ""; - if (!value.equals("")) - return (hoverMessage + Misc.beautify(value)).trim(); - } - } + if (region == null) { + ocaml.OcamlPlugin.logError("OcamlTextHover:getHoverInfo null region"); + return ""; + } - if (OcamlPlugin.getInstance().getPreferenceStore().getBoolean( - PreferenceConstants.P_SHOW_TYPES_IN_POPUPS)) { + try { + String typeInfo = ""; + int offset = region.getOffset(); + + File annotFile = null; + + // workspace file + if (file != null) + annotFile = Misc.getOtherFileFor(file.getProject(), file.getFullPath(), ".annot"); + else + annotFile = Misc.getOtherFileFor(filePath, ".annot"); - File annotFile = null; + if (annotFile != null && annotFile.exists()) { + boolean bUpToDate = false; - // workspace file if (file != null) - annotFile = Misc.getOtherFileFor(file.getProject(), file.getFullPath(), ".annot"); + bUpToDate = file.getLocation().toFile().lastModified() <= annotFile.lastModified(); else - annotFile = Misc.getOtherFileFor(filePath, ".annot"); - - if (annotFile != null && annotFile.exists()) { - boolean bUpToDate = false; - - if (file != null) - bUpToDate = file.getLocation().toFile().lastModified() <= annotFile.lastModified(); - else - bUpToDate = filePath.toFile().lastModified() <= annotFile.lastModified(); - - if (!ocamlEditor.isDirty() && bUpToDate) { - ArrayList found = new ArrayList(); - - TypeAnnotation[] annotations = OcamlAnnotParser.parseFile(annotFile, textViewer - .getDocument()); - if (annotations != null) { - for (TypeAnnotation annot : annotations) - if (annot.getBegin() <= hoverOffset && hoverOffset < annot.getEnd()) - found.add(annot); - - /* - * Search for the smallest hovered type annotation - */ - TypeAnnotation annot = null; - int minSize = Integer.MAX_VALUE; - - for (TypeAnnotation a : found) { - int size = a.getEnd() - a.getBegin(); - if (size < minSize) { - annot = a; - minSize = size; - } - } + bUpToDate = filePath.toFile().lastModified() <= annotFile.lastModified(); + + if (!ocamlEditor.isDirty() && bUpToDate) { + ArrayList found = new ArrayList(); + + TypeAnnotation[] annotations = OcamlAnnotParser.parseFile(annotFile, textViewer + .getDocument()); + if (annotations != null) { + for (TypeAnnotation annot : annotations) + if (annot.getBegin() <= offset && offset < annot.getEnd()) + found.add(annot); - if (annot != null) { - - String doc = ocamlEditor.getDocumentProvider().getDocument( - ocamlEditor.getEditorInput()).get(); - String expr = doc.substring(annot.getBegin(), annot.getEnd()); - String[] lines = expr.split("\\n"); - if (expr.length() < 50 && lines.length <= 6) - return (hoverMessage + expr + ": " + annot.getType()).trim(); - else if (lines.length > 6) { - int l = lines.length; - - return (hoverMessage + lines[0] + "\n" + lines[1] + "\n" + lines[2] - + "\n" + "..." + (l - 6) + " more lines...\n" + lines[l - 3] - + "\n" + lines[l - 2] + "\n" + lines[l - 1] + "\n:" + annot - .getType()).trim(); - } else - return (hoverMessage + expr + "\n:" + annot.getType()).trim(); + /* + * Search for the smallest hovered type annotation + */ + TypeAnnotation annot = null; + int minSize = Integer.MAX_VALUE; + + for (TypeAnnotation a : found) { + int size = a.getEnd() - a.getBegin(); + if (size < minSize) { + annot = a; + minSize = size; } } + + if (annot != null) { + String doc = ocamlEditor.getDocumentProvider().getDocument( + ocamlEditor.getEditorInput()).get(); + String expr = doc.substring(annot.getBegin(), annot.getEnd()); + String[] lines = expr.split("\\n"); + if (expr.length() < 50 && lines.length <= 6) + return (typeInfo + expr + ": " + annot.getType()).trim(); + else if (lines.length > 6) { + int l = lines.length; + + return (typeInfo + lines[0] + "\n" + lines[1] + "\n" + lines[2] + + "\n" + "..." + (l - 6) + " more lines...\n" + lines[l - 3] + + "\n" + lines[l - 2] + "\n" + lines[l - 1] + "\n:" + annot + .getType()).trim(); + } else + return (typeInfo + expr + "\n:" + annot.getType()).trim(); + } } } } - return hoverMessage.trim(); + return typeInfo.trim(); /* * if (!this.ocamlEditor.isDirty()) return this.ocamlEditor.getTypeInfoAt(hoverOffset).trim(); */ } catch (Throwable e) { - ocaml.OcamlPlugin.logError("Erreur dans OcamlTextHover:getHoverInfo", e); + // ocaml.OcamlPlugin.logError("Erreur dans OcamlTextHover:getHoverInfo", e); } return ""; } + + // get HoverInfo in 1 line format + public String getTypeInfoOneLine(ITextViewer textViewer, IRegion region) { + String typeInfo = getTypeInfo(textViewer, region); + String[] lines = typeInfo.split(System.lineSeparator()); + String typeInfoOneLine = ""; + for (String line: lines) + typeInfoOneLine = typeInfoOneLine + " " + line.trim(); + return typeInfoOneLine.trim(); + } + + /** + * Returns the string to display in a pop-up which gives value of expression + * currently under the mouse cursor in the editor in debug mode + */ + public String getExpressionValue(ITextViewer textViewer, IRegion region) { + IPath filePath = ocamlEditor.getPathOfFileBeingEdited(); + + if (filePath == null) + return ""; + + if (region == null) { + ocaml.OcamlPlugin.logError("OcamlTextHover:getHoverInfo null region"); + return ""; + } + + String value = ""; + + try { + int offset = region.getOffset(); + + // if the debugger is started, we ask it for the value of the variable under the cursor + if (OcamlDebugger.getInstance().isStarted()) { + String text = textViewer.getDocument().get(); + String expression = expressionAtOffset(text, offset).trim(); + + if (!expression.equals("")) { + value = OcamlDebugger.getInstance().display(expression).trim(); + if (!value.equals("")) + value = Misc.beautify(value).trim(); + } + } + } catch (Throwable e) { + // ocaml.OcamlPlugin.logInfo("Erreur dans OcamlTextHover:getHoverInfo", e); + } + + return value; + } + + // get expression value in 1 line format + public String getExpressionValueOneLine(ITextViewer textViewer, IRegion region) { + String value = getExpressionValue(textViewer, region); + String[] lines = value.split(System.lineSeparator()); + String valueOneLine = ""; + for (String line: lines) + valueOneLine = valueOneLine + " " + line.trim(); + return valueOneLine.trim(); + } + @Override public IRegion getHoverRegion(ITextViewer textViewer, int offset) { return new Region(offset, 0); } diff --git a/Ocaml/src/ocaml/preferences/PreferenceConstants.java b/Ocaml/src/ocaml/preferences/PreferenceConstants.java index b49b140..dcd9933 100644 --- a/Ocaml/src/ocaml/preferences/PreferenceConstants.java +++ b/Ocaml/src/ocaml/preferences/PreferenceConstants.java @@ -65,6 +65,7 @@ public class PreferenceConstants public static final String P_DISABLE_UNICODE_CHARS = "DisableUnicodeChars"; public static final String P_SHOW_TYPES_IN_OUTLINE = "ShowTypesInOutline"; public static final String P_SHOW_TYPES_IN_STATUS_BAR = "ShowTypesInStatusBar"; + public static final String P_SHOW_MARKERS_IN_STATUS_BAR = "ShowMarkersInStatusBar"; public static final String P_SHOW_TYPES_IN_POPUPS = "ShowTypesInPopups"; public static final String P_FORMATTER_INDENT_IN = "FormatterIndentIn"; diff --git a/Ocaml/src/ocaml/preferences/PreferenceInitializer.java b/Ocaml/src/ocaml/preferences/PreferenceInitializer.java index cd374f4..7dbb164 100644 --- a/Ocaml/src/ocaml/preferences/PreferenceInitializer.java +++ b/Ocaml/src/ocaml/preferences/PreferenceInitializer.java @@ -75,6 +75,7 @@ public void initializeDefaultPreferences() { store.setDefault(PreferenceConstants.P_SHOW_TYPES_IN_OUTLINE, true); store.setDefault(PreferenceConstants.P_SHOW_TYPES_IN_POPUPS, true); store.setDefault(PreferenceConstants.P_SHOW_TYPES_IN_STATUS_BAR, true); + store.setDefault(PreferenceConstants.P_SHOW_MARKERS_IN_STATUS_BAR, true); // set the defaults for the formatter store.setDefault(PreferenceConstants.P_FORMATTER_INDENT_IN, false); diff --git a/Ocaml/src/ocaml/preferences/RootPreferencePage.java b/Ocaml/src/ocaml/preferences/RootPreferencePage.java index cbc27d0..c670bec 100644 --- a/Ocaml/src/ocaml/preferences/RootPreferencePage.java +++ b/Ocaml/src/ocaml/preferences/RootPreferencePage.java @@ -43,6 +43,11 @@ public void createFieldEditors() { PreferenceConstants.P_SHOW_TYPES_IN_POPUPS, "Show the types in popups when hovering over the editor", this .getFieldEditorParent())); + + this.addField(new BooleanFieldEditor( + PreferenceConstants.P_SHOW_MARKERS_IN_STATUS_BAR, + "Show markers' information in the editor's status bar", this + .getFieldEditorParent())); } @Override From d4bffb165e3a0f3f6907a8fc6fb23a46de3dbbaf Mon Sep 17 00:00:00 2001 From: trungtq Date: Thu, 9 Oct 2014 14:37:25 +0800 Subject: [PATCH 037/127] improvements --- Ocaml/src/ocaml/editors/OcamlEditor.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index ca28596..67a493c 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -514,6 +514,8 @@ public void handleCursorPositionChanged() { && OcamlPlugin.getInstance().getPreferenceStore().getBoolean( PreferenceConstants.P_SHOW_TYPES_IN_STATUS_BAR)) { message = hover.getTypeInfoOneLine(viewer, region); + if (message.contains("more lines...")) + message = ""; } final String statusMessage = message; From 0357810d9b703fad9eb5d9844e22d5f0e66d3f21 Mon Sep 17 00:00:00 2001 From: trungtq Date: Thu, 9 Oct 2014 22:53:27 +0800 Subject: [PATCH 038/127] always show type even souce code is modified --- Ocaml/src/ocaml/editors/OcamlTextHover.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ocaml/src/ocaml/editors/OcamlTextHover.java b/Ocaml/src/ocaml/editors/OcamlTextHover.java index 48a1134..561a8b5 100644 --- a/Ocaml/src/ocaml/editors/OcamlTextHover.java +++ b/Ocaml/src/ocaml/editors/OcamlTextHover.java @@ -174,7 +174,7 @@ public String getTypeInfo(ITextViewer textViewer, IRegion region) { else bUpToDate = filePath.toFile().lastModified() <= annotFile.lastModified(); - if (!ocamlEditor.isDirty() && bUpToDate) { + if (!ocamlEditor.isDirty() /*&& bUpToDate*/) { ArrayList found = new ArrayList(); TypeAnnotation[] annotations = OcamlAnnotParser.parseFile(annotFile, textViewer From c7cf8264570c790bc5dd3f0b492484caf06b36b1 Mon Sep 17 00:00:00 2001 From: trungtq Date: Thu, 9 Oct 2014 23:05:46 +0800 Subject: [PATCH 039/127] minor changes --- .../completion/OcamlCompletionProcessor.java | 6 ++--- .../completion/OcamlCompletionProposal.java | 12 ++++----- .../ocaml/editors/OcamlHyperlinkDetector.java | 2 +- Ocaml/src/ocaml/parser/Def.java | 26 +++++++++++++++---- .../parsers/OcamlNewInterfaceParser.java | 9 +++---- Ocaml/src/ocaml/views/OcamlBrowserView.java | 4 +-- 6 files changed, 37 insertions(+), 22 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index ae434b3..f0882a7 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -683,7 +683,7 @@ else if (def.type == Def.Type.ModuleAlias) { */ if (def.name.equals(expression)) { - String body = def.body; + String body = def.getBody(); // if (!def.getParentName().equals("")) // body = body + " (constructor of type " + def.getParentName() + ")"; @@ -697,12 +697,12 @@ else if (def.type == Def.Type.ModuleAlias) { else message = message + "\u00A0"; - String filename = def.filename; + String filename = def.getFileName(); message = message + "\u00A0\n\n" + filename; message = message.trim(); if (!message.equals("")) { - String context = def.filename + " : " + def.body; + String context = def.getFileName() + " : " + body; infos.add(new ContextInformation(context, message)); } } diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java index 0442fe5..2ab2996 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java @@ -64,17 +64,17 @@ public IContextInformation getContextInformation() { * We display context information only for functions (to help the user with the types of the expected * arguments), an exception with arguments, or a constructor with arguments. */ - boolean bArrow = definition.body.contains("->") || definition.body.contains("\u2192"); + final String body = definition.getBody(); + boolean bArrow = body.contains("->") || body.contains("\u2192"); boolean bFun = type.equals(Def.Type.Let) && bArrow; boolean bExtFun = type.equals(Def.Type.External) && bArrow; boolean bExceptionArgs = type.equals(Def.Type.Exception) - && definition.body.contains(" of "); + && body.contains(" of "); boolean bConstructorArgs = type.equals(Def.Type.TypeConstructor) - && definition.body.contains(" of "); + && body.contains(" of "); if (!(bFun || bExtFun || bExceptionArgs || bConstructorArgs)) return null; - final String body = definition.body; if (body.trim().equals("")) return null; @@ -121,9 +121,9 @@ public String getAdditionalProposalInfo(IProgressMonitor monitor) { * encodes as a string the informations that will be read back by OcamlInformationPresenter to format * them */ - return definition.parentName + " $@| " + definition.body + " $@| " + return definition.parentName + " $@| " + definition.getBody() + " $@| " + definition.sectionComment + " $@| " + definition.comment + " $@| " - + definition.filename; + + definition.getFileName(); } } \ No newline at end of file diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index aebb5cc..d5ff661 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -485,7 +485,7 @@ private boolean openDefInInterfaces(int index, final String[] path, Def interfac if (index == path.length) { try { - String filename = interfaceDef.filename; + String filename = interfaceDef.getFileName(); // open the file containing the definition IProject project = editor.getProject(); diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index ba0a4e9..8b2a02e 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -531,9 +531,6 @@ public void setComment(String text) { this.comment = clean(text); } - public void setBody(String text) { - this.body = Misc.beautify(clean(text)); - } private static String clean(String str) { if (str == null) @@ -552,9 +549,28 @@ private static String clean(String str) { return stringBuilder.toString().trim(); } - public String body = ""; + private String body = ""; - public String filename = ""; + private String filename = ""; + + public void setBody(String body) { + this.body = body; +// this.body = Misc.beautify(clean(text)); + } + + public String getBody() { + return this.body; + } + + + public void setFileName(String filename) { + this.filename = filename; + } + + public String getFileName() { + return filename; + } + public String parentName = ""; diff --git a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java index f661b72..148bd1f 100644 --- a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java +++ b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java @@ -198,7 +198,7 @@ protected IStatus run(IProgressMonitor monitor) { String errors = preprocessor.getErrorOutput().trim(); if (!"".equals(errors)) { Def def = new Def(moduleName, Def.Type.ParserError, 0, 0); - def.filename = filename; + def.setFileName(filename); def .setComment("ERROR: The camlp4 preprocessor encountered an error " @@ -222,10 +222,9 @@ protected IStatus run(IProgressMonitor monitor) { // next file // OcamlPlugin.logError("Error parsing '" + moduleName + "'", e); Def def = new Def(moduleName, Def.Type.ParserError, 0, 0); - def.filename = filename; + def.setFileName(filename); - def - .setComment("ERROR: The parser encountered an error while parsing this file.\n\n" + def.setComment("ERROR: The parser encountered an error while parsing this file.\n\n" + "Please make sure that it is syntactically correct.\n\n"); // System.err.println("ERROR:" + filename); @@ -268,7 +267,7 @@ protected IStatus run(IProgressMonitor monitor) { } private void setFilenames(Def definition, String filename) { - definition.filename = filename; + definition.setFileName(filename); for (Def child : definition.children) setFilenames(child, filename); } diff --git a/Ocaml/src/ocaml/views/OcamlBrowserView.java b/Ocaml/src/ocaml/views/OcamlBrowserView.java index 999fcfd..e30cc54 100644 --- a/Ocaml/src/ocaml/views/OcamlBrowserView.java +++ b/Ocaml/src/ocaml/views/OcamlBrowserView.java @@ -445,9 +445,9 @@ protected void treeItemSelected() { } private void addFormatedText(StyledText text, Def def) { - String body = def.body; + String body = def.getBody(); String comment = def.comment; - String filename = def.filename; + String filename = def.getFileName(); // String name = def.getName(); String parentName = def.parentName; String sectionComment = def.sectionComment; From d55f9d6dcc5b8f6a6089a9bc5e10fb8d48461364 Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 10 Oct 2014 01:08:41 +0800 Subject: [PATCH 040/127] still need to be improved --- .../completion/OcamlCompletionProcessor.java | 234 +++++++++++++++--- .../completion/OcamlCompletionProposal.java | 2 +- Ocaml/src/ocaml/parser/Def.java | 67 ++++- .../parsers/OcamlNewInterfaceParser.java | 8 +- 4 files changed, 275 insertions(+), 36 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index f0882a7..4d619f6 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -1,5 +1,6 @@ package ocaml.editor.completion; +import java.io.File; import java.util.ArrayList; import java.util.HashSet; @@ -10,8 +11,13 @@ import ocaml.editors.yacc.OcamlyaccEditor; import ocaml.parser.Def; import ocaml.util.Misc; +import ocaml.typeHovers.OcamlAnnotParser; +import ocaml.typeHovers.TypeAnnotation; +import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.IPath; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; @@ -22,6 +28,8 @@ import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.contentassist.IContextInformationValidator; import org.eclipse.ui.editors.text.TextEditor; +import org.eclipse.ui.editors.text.TextFileDocumentProvider; +import org.eclipse.ui.texteditor.IDocumentProvider; /** * This class is responsible for managing completion in the OCaml editor. @@ -31,23 +39,28 @@ */ public class OcamlCompletionProcessor implements IContentAssistProcessor { - private final TextEditor editor; + private final TextEditor editor; + + private final IProject project; /** The partition type in which completion was triggered. */ private final String partitionType; public OcamlCompletionProcessor(OcamlEditor edit, String regionType) { this.editor = (TextEditor)edit; + this.project = edit.getProject(); this.partitionType = regionType; } public OcamlCompletionProcessor(OcamllexEditor edit, String regionType) { this.editor = (TextEditor)edit; + this.project = edit.getProject(); this.partitionType = regionType; } public OcamlCompletionProcessor(OcamlyaccEditor edit, String regionType) { this.editor = (TextEditor)edit; + this.project = edit.getProject(); this.partitionType = regionType; } @@ -56,7 +69,7 @@ public OcamlCompletionProcessor(OcamlyaccEditor edit, String regionType) { * completion box when he types a space */ private int lastOffset = -1; - + /** * Compute and return completion proposals available at the offset documentOffset. */ @@ -99,8 +112,6 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int OcamlCompletionProposal[] proposals = new OcamlCompletionProposal[0]; - IProject project = null; - IDocument document = viewer.getDocument(); // must wait parsing job finish first. @@ -109,23 +120,12 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int Def outlineDefinitionsRoot = null; if (editor instanceof OcamlEditor) { OcamlEditor ocamlEditor = (OcamlEditor) editor; - project = ocamlEditor.getProject(); outlineDefinitionsRoot = ocamlEditor.getOutlineDefinitionsTree(); + String filename = ocamlEditor.getFileBeingEdited().getLocation().toOSString(); + updateDefFileName(outlineDefinitionsRoot, filename); } - else if (editor instanceof OcamllexEditor) { - OcamllexEditor ocamllexEditor = (OcamllexEditor) editor; - project = ocamllexEditor.getProject(); + else outlineDefinitionsRoot = null; - } - else if (editor instanceof OcamlyaccEditor) { - OcamlyaccEditor ocamlyaccEditor = (OcamlyaccEditor) editor; - project = ocamlyaccEditor.getProject(); - outlineDefinitionsRoot = null; - } - else { - project = null; - outlineDefinitionsRoot = null; - } Def interfacesDefinitionsRoot = null; if (project != null) @@ -305,9 +305,10 @@ else if (def.type == Def.Type.ModuleAlias) { // find elements starting by in the list of elements else { for (Def def : outlineDefsRoot.children) { - if (def.name.startsWith(completion) && isCompletionDef(def)) - proposals.add(new OcamlCompletionProposal(def, offset, completion.length())); - + if (def.name.startsWith(completion) && isCompletionDef(def)) { + Def proposedDef = createProposalDef(project, def); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } } } @@ -331,8 +332,10 @@ private ArrayList processNondottedCompletion(String com return proposals; for (Def def : outlineDefsRoot.children) { - if (def.name.startsWith(completion) && isCompletionDef(def)) - proposals.add(new OcamlCompletionProposal(def, offset, completion.length())); + if (def.name.startsWith(completion) && isCompletionDef(def)) { + Def proposedDef = createProposalDef(project, def); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } } // look in all opened or included modules @@ -357,8 +360,10 @@ private ArrayList processNondottedCompletion(String com if (d == null || d.name == null) break; - if (d.name.startsWith(completion) && isCompletionDef(d)) - proposals.add(new OcamlCompletionProposal(d, offset, completion.length())); + if (d.name.startsWith(completion) && isCompletionDef(d)) { + Def proposedDef = createProposalDef(project, d); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } } } } @@ -380,16 +385,20 @@ private ArrayList lookCompletionProposalsUp(String comp if (travelNode.name.startsWith(completion) && (travelNode.name.length() > completion.length()) - && isCompletionDef(travelNode)) - proposals.add(new OcamlCompletionProposal(travelNode, offset, completion.length())); + && isCompletionDef(travelNode)) { + Def proposedDef = createProposalDef(project, travelNode); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } for (Def def : travelNode.children) { if (def == null || def.name == null) continue; if (def.name.startsWith(completion) && (def.name.length() > completion.length()) - && isCompletionDef(def)) - proposals.add(new OcamlCompletionProposal(def, offset, completion.length())); + && isCompletionDef(def)) { + Def proposedDef = createProposalDef(project, def); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } } if (travelNode.type == Def.Type.Root) @@ -716,4 +725,171 @@ else if (def.type == Def.Type.ModuleAlias) { public String getErrorMessage() { return null; } + + private Def createProposalDef(IProject project, Def def) { + Def newDef = new Def(def); + if (newDef.getBody().equals(newDef.name)) { + String filename = newDef.getFileName(); + TypeAnnotation[] annotations = parseModuleAnnotation(project, filename); + IDocument document = getDocument(project, filename); + String typeInfo = computeTypeInfo(newDef, annotations, document); + if (newDef.type == Def.Type.Let + || newDef.type == Def.Type.LetIn) { + if (typeInfo.isEmpty()) + typeInfo = newDef.name + " - "; + newDef.setBody(typeInfo); + } + else if (def.type == Def.Type.Type) { + String newBody = newDef.name + " 't"; + newDef.setBody(newBody); + } + else + newDef.setBody(newDef.getBody() + " -- def type: " + newDef.getTypeName()); + } + // newDef.setBody(newDef.getBody() + " -- def type: " + newDef.getTypeName()); + + return newDef; + } + + private IDocument getDocument(IProject project, String filename) { + if (project == null) + return null; + + if (filename.isEmpty()) + return null; + + try { + IFile[] files = project.getWorkspace().getRoot().findFilesForLocationURI(URIUtil.toURI(filename)); + if (files.length == 0) + return null; + + IFile file = files[0]; + IDocumentProvider provider = new TextFileDocumentProvider(); + provider.connect(file); + IDocument document = provider.getDocument(file); + + return document; + } catch (Exception e) { + return null; + } + } + + + private TypeAnnotation[] parseModuleAnnotation(IProject project, String filename) { + if (project == null) + return new TypeAnnotation[0]; + + if (filename.isEmpty()) + return new TypeAnnotation[0]; + + try { + IFile[] files = project.getWorkspace().getRoot().findFilesForLocationURI(URIUtil.toURI(filename)); + if (files.length == 0) + return new TypeAnnotation[0]; + + IFile file = files[0]; + IPath relativeProjectPath = file.getFullPath(); + IDocumentProvider provider = new TextFileDocumentProvider(); + provider.connect(file); + IDocument document = provider.getDocument(file); + + File annotFile = null; + + annotFile = Misc.getOtherFileFor(file.getProject(), relativeProjectPath, ".annot"); + + if (annotFile != null && annotFile.exists()) { + TypeAnnotation[] annotations = OcamlAnnotParser.parseFile(annotFile, document); + + return annotations; + } + } catch (Exception e) { +// e.printStackTrace(); + return new TypeAnnotation[0]; + } + + return new TypeAnnotation[0]; + + } + + private String computeTypeInfo(Def def, TypeAnnotation[] annotations, IDocument document) { + try { + String typeInfo = ""; + IRegion region = def.getRegion(document); + int offset = region.getOffset(); + + ArrayList found = new ArrayList(); + + if (annotations != null) { + for (TypeAnnotation annot : annotations) + if (annot.getBegin() <= offset && offset < annot.getEnd()) + found.add(annot); + + /* + * Search for the smallest hovered type annotation + */ + TypeAnnotation annot = null; + int minSize = Integer.MAX_VALUE; + + for (TypeAnnotation a : found) { + int size = a.getEnd() - a.getBegin(); + if (size < minSize) { + annot = a; + minSize = size; + } + } + + String docContent = document.get(); + if (annot != null) { + String expr = docContent.substring(annot.getBegin(), annot.getEnd()); + String[] lines = expr.split("\\n"); + if (expr.length() < 50 && lines.length <= 6) + typeInfo = expr + ": " + annot.getType(); + else if (lines.length > 6) { + int l = lines.length; + typeInfo = lines[0] + "\n" + lines[1] + "\n" + lines[2] + + "\n" + "..." + (l - 6) + " more lines...\n" + lines[l - 3] + + "\n" + lines[l - 2] + "\n" + lines[l - 1] + "\n:" + annot + .getType(); + } else + typeInfo = expr + "\n:" + annot.getType(); + } + } + return typeInfo.trim(); + } catch (Exception e) { + return ""; + } + + } + + private void updateDefFileName(Def def, String filename) { + if (def != null) { + def.setFileName(filename); + for (Def d: def.children) { + updateDefFileName(d, filename); + } + } + } + + ArrayList lineOffsets = null; + + private void computeLinesStartOffset(String doc) { + lineOffsets = new ArrayList(); + lineOffsets.add(0); + for (int i = 0; i < doc.length(); i++) { + + /* + * if(doc.charAt(i) == '\r') System.err.print("\n"); + * if(doc.charAt(i) == '\n') System.err.print("\n"); else + * System.err.print(doc.charAt(i)); + */ + + if (doc.charAt(i) == '\n') { + lineOffsets.add(i + 1); + // System.err.println(i); + } + + } + } + + } diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java index 2ab2996..df93d43 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java @@ -43,7 +43,7 @@ public OcamlCompletionProposal(Def definition, int replacementOffset, int typedW this.typedLength = typedWordLength; } - + public void apply(IDocument document) { String name = this.definition.name; diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index 8b2a02e..d64d6e5 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -554,8 +554,8 @@ private static String clean(String str) { private String filename = ""; public void setBody(String body) { - this.body = body; -// this.body = Misc.beautify(clean(text)); +// this.body = body; + this.body = Misc.beautify(clean(body)); } public String getBody() { @@ -571,6 +571,69 @@ public String getFileName() { return filename; } + public String getTypeName() { + + + if (type == Type.Dummy) + return "Dummy"; + else if (type == Type.In) + return "In"; + else if (type == Type.Root) + return "Root"; + else if (type == Type.Identifier) + return "Identifier"; + else if (type == Type.Let) + return "Let"; + else if (type == Type.LetIn) + return "LetIn"; + else if (type == Type.Type) + return "Type"; + else if (type == Type.Module) + return "Module"; + else if (type == Type.ModuleAlias) + return "ModuleAlias"; + else if (type == Type.ModuleType) + return "ModuleType"; + else if (type == Type.Exception) + return "Exception"; + else if (type == Type.External) + return "External"; + else if (type == Type.Class) + return "Class"; + else if (type == Type.Sig) + return "Sig"; + else if (type == Type.Open) + return "Open"; + else if (type == Type.Object) + return "Object"; + else if (type == Type.Method) + return "Method"; + else if (type == Type.Struct) + return "Struct"; + else if (type == Type.Functor) + return "Functor"; + else if (type == Type.Include) + return "Include"; + else if (type == Type.Val) + return "Val"; + else if (type == Type.Constraint) + return "Constraint"; + else if (type == Type.Initializer) + return "Initializer"; + else if (type == Type.ClassType) + return "ClassType"; + else if (type == Type.TypeConstructor) + return "TypeConstructor"; + else if (type == Type.RecordTypeConstructor) + return "RecordTypeConstructor"; + else if (type == Type.Parameter) + return "Parameter"; + else if (type == Type.ParserError) + return "ParserError"; + else + return "Unknown"; + } + public String parentName = ""; diff --git a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java index 148bd1f..5a02597 100644 --- a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java +++ b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java @@ -216,7 +216,7 @@ protected IStatus run(IProgressMonitor monitor) { // parse the .mli interface file or the .ml module file try { // System.err.println("parsing:" + filename); - definition = parseModule(lines, moduleName, bInterface); + definition = parseModule(lines, filename, moduleName, bInterface); } catch (Throwable e) { // if there was a parsing error, we log it and we continue on to the // next file @@ -272,7 +272,7 @@ private void setFilenames(Def definition, String filename) { setFilenames(child, filename); } - private Def parseModule(String doc, String moduleName, + private Def parseModule(String doc, String filename, String moduleName, boolean parseInterface) throws Throwable { /* @@ -307,7 +307,7 @@ private Def parseModule(String doc, String moduleName, // set the start offset from the packed (line, column) positions computeLinesStartOffset(doc); computeDefinitionsStartOffset(root); - + // parse the comments and remove them from the text if (parseInterface) { doc = parseComments(doc); @@ -389,7 +389,7 @@ private void computeDefinitionsStartOffset(Def def) { for (Def child : def.children) computeDefinitionsStartOffset(child); } - + /** * Find the end of each definition, knowing the start of the next * definition. From f062019843748492708f7273dc3427019a170000 Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 10 Oct 2014 01:33:35 +0800 Subject: [PATCH 041/127] in progress --- .../completion/OcamlCompletionProcessor.java | 64 ++++++++++++++----- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 4d619f6..2fd77a1 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -223,9 +223,9 @@ private OcamlCompletionProposal[] findCompletionProposals(String completion, if (completion.contains(".")) proposals = processDottedCompletion(completion, outlineDefsRoot, defsRoot, doc, offset); else - proposals = processNondottedCompletion(completion, outlineDefsRoot, defsRoot, doc, offset); + proposals = processNondottedCompletion(completion, defsRoot, doc, offset); - proposals = removeDuplicatedCompletionProposal(proposals); +// proposals = removeDuplicatedCompletionProposal(proposals); return proposals.toArray(new OcamlCompletionProposal[0]); } @@ -316,46 +316,76 @@ else if (def.type == Def.Type.ModuleAlias) { } private ArrayList processNondottedCompletion(String completion, - Def outlineDefsRoot, Def defsRoot, IDocument document, int offset) { ArrayList proposals = new ArrayList(); - - // look up for definition - final Def nearestDef = findNearestDefAt(outlineDefsRoot, offset, document); - proposals.addAll(lookCompletionProposalsUp(completion, nearestDef, offset)); - // look in current module - if (outlineDefsRoot == null) + if (defsRoot == null) return proposals; - for (Def def : outlineDefsRoot.children) { - if (def.name.startsWith(completion) && isCompletionDef(def)) { + /* + * look in def root + */ + for (Def def: defsRoot.children) { + if (def.name.startsWith(completion)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } } - // look in all opened or included modules - if (defsRoot == null) + /* + * looked in current module + */ + String moduleName = editor.getEditorInput().getName(); + if (moduleName.endsWith(".ml")) + moduleName = moduleName.substring(0, moduleName.length() - 3); + else if (moduleName.endsWith(".mli")) + moduleName = moduleName.substring(0, moduleName.length() - 4); + if (moduleName.length() > 0) + moduleName = Character.toUpperCase(moduleName.charAt(0)) + + moduleName.substring(1); + + Def currentDef = null; + for (Def def: defsRoot.children) { + if (def.name.equals(moduleName)) { + currentDef = def; + break; + } + } + + if (currentDef == null) return proposals; - for (Def def : outlineDefsRoot.children) { + // look down from top of current module + final Def nearestDef = findNearestDefAt(currentDef, offset, document); + proposals.addAll(lookCompletionProposalsUp(completion, nearestDef, offset)); + + for (Def def: currentDef.children) { + if (def.name.startsWith(completion)) { + Def proposedDef = createProposalDef(project, def); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } + } + + /* + * look in opened module of current module + */ + for (Def def : currentDef.children) { if (def == null || def.name == null) break; if (def.type != Def.Type.Open) continue; - + for (Def idef: defsRoot.children) { if (idef == null || idef.name == null) break; if (!idef.name.equals(def.name)) continue; - + for (Def d: idef.children) { if (d == null || d.name == null) break; @@ -367,7 +397,7 @@ private ArrayList processNondottedCompletion(String com } } } - + return proposals; } From 7d628057fa3e1ff97cba7ed10d34098583c9c51d Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 10 Oct 2014 02:13:06 +0800 Subject: [PATCH 042/127] so far so good --- .../completion/OcamlCompletionProcessor.java | 188 ++++++++++++------ 1 file changed, 126 insertions(+), 62 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 2fd77a1..1ea8692 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -116,22 +116,11 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int // must wait parsing job finish first. if (CompletionJob.isParsingFinished()) { - // lookup in module definition provided in editor first - Def outlineDefinitionsRoot = null; - if (editor instanceof OcamlEditor) { - OcamlEditor ocamlEditor = (OcamlEditor) editor; - outlineDefinitionsRoot = ocamlEditor.getOutlineDefinitionsTree(); - String filename = ocamlEditor.getFileBeingEdited().getLocation().toOSString(); - updateDefFileName(outlineDefinitionsRoot, filename); - } - else - outlineDefinitionsRoot = null; - Def interfacesDefinitionsRoot = null; if (project != null) interfacesDefinitionsRoot = CompletionJob.buildDefinitionsTree(project, false); - proposals = findCompletionProposals(completion, outlineDefinitionsRoot, interfacesDefinitionsRoot, document, documentOffset); + proposals = findCompletionProposals(completion, interfacesDefinitionsRoot, document, documentOffset); } else { proposals = new OcamlCompletionProposal[0]; OcamlPlugin.logInfo("Completion proposals skipped (background job not done yet)"); @@ -214,35 +203,47 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int * @return the completions found */ private OcamlCompletionProposal[] findCompletionProposals(String completion, - Def outlineDefsRoot, Def defsRoot, IDocument doc, int offset) { ArrayList proposals; + + String moduleName = editor.getEditorInput().getName(); + if (moduleName.endsWith(".ml")) + moduleName = moduleName.substring(0, moduleName.length() - 3); + else if (moduleName.endsWith(".mli")) + moduleName = moduleName.substring(0, moduleName.length() - 4); + if (moduleName.length() > 0) + moduleName = Character.toUpperCase(moduleName.charAt(0)) + + moduleName.substring(1); + if (completion.contains(".")) - proposals = processDottedCompletion(completion, outlineDefsRoot, defsRoot, doc, offset); + proposals = processDottedCompletion(completion, defsRoot, moduleName, doc, offset); else - proposals = processNondottedCompletion(completion, defsRoot, doc, offset); + proposals = processNondottedCompletion(completion, defsRoot, moduleName, doc, offset); -// proposals = removeDuplicatedCompletionProposal(proposals); + proposals = removeDuplicatedCompletionProposal(proposals); return proposals.toArray(new OcamlCompletionProposal[0]); } // completion string must contained dots private ArrayList processDottedCompletion(String completion, - Def outlineDefsRoot, Def defsRoot, + String moduleName, IDocument document, int offset) { ArrayList proposals = new ArrayList(); + + if (defsRoot == null) + return proposals; // look in the module before the dot what's after the dot // The module can be like "A.B." or "c.D.E." if (completion.contains(".")) { - //find the name of root module + // find the first module in completion string int index = completion.lastIndexOf('.'); String[] parts = completion.substring(0,index).split("\\."); String prefix = parts[parts.length - 1]; @@ -258,31 +259,37 @@ private ArrayList processDottedCompletion(String comple i--; } - String moduleName = prefix; + /* + * look into current module first + */ + Def currentDef = null; + for (Def def: defsRoot.children) { + if (def.name.equals(moduleName)) { + currentDef = def; + break; + } + } - // look into current module first + // look in sub-module or aliased module of current modules boolean stop = false; while (!stop) { stop = true; - if (outlineDefsRoot == null) + if (currentDef == null) break; - for (Def def : outlineDefsRoot.children) { - if (def == null || def.name == null) - break; - - if (!def.name.equals(moduleName)) + for (Def def : currentDef.children) { + if (!def.name.equals(prefix)) continue; if (def.type == Def.Type.Module) { - return processDottedCompletion(suffix, outlineDefsRoot, def, document, offset); + return lookupCompletionInDef(suffix, def, document, offset); } else if (def.type == Def.Type.ModuleAlias) { String aliasedName = def.children.get(0).name; - if (moduleName.equals(aliasedName)) + if (prefix.equals(aliasedName)) stop = true; else { - moduleName = aliasedName; + prefix = aliasedName; stop = false; } break; @@ -290,21 +297,95 @@ else if (def.type == Def.Type.ModuleAlias) { } } - // then look into interface definitions - if (defsRoot == null) - return proposals; + // look in opened module of current module + Def openedModule = null; + for (Def def : currentDef.children) { + if (def.type == Def.Type.Open) { + for (Def otherDef: defsRoot.children) { + if (otherDef == null || otherDef.name == null) + break; + + if (otherDef.name.equals(def.name)) { + openedModule = otherDef; + break; + } + } + } + } + if (openedModule != null) + for (Def def: openedModule.children) { + if (def == null || def.name == null) + break; + + if (def.name.startsWith(completion) && isCompletionDef(def)) { + Def proposedDef = createProposalDef(project, def); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } + } + + + /* + * then look into other modules + */ for (Def def: defsRoot.children) { if (def == null || def.name == null) continue; - if (def.name.equals(moduleName) && (def.type == Def.Type.Module)) - return processDottedCompletion(suffix, def, defsRoot, document, offset); + if (def.name.equals(prefix)) + return lookupCompletionInDef(suffix, def, document, offset); } } // find elements starting by in the list of elements else { - for (Def def : outlineDefsRoot.children) { + for (Def def : defsRoot.children) { + if (def.name.startsWith(completion) && isCompletionDef(def)) { + Def proposedDef = createProposalDef(project, def); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } + } + } + + return proposals; + } + + // completion string must contained dots + private ArrayList lookupCompletionInDef(String completion, + Def defsRoot, + IDocument document, + int offset) { + + ArrayList proposals = new ArrayList(); + + if (defsRoot == null) + return proposals; + + if (completion.contains(".")) { + // find the first module in completion string + int index = completion.lastIndexOf('.'); + String[] parts = completion.substring(0,index).split("\\."); + String prefix = parts[parts.length - 1]; + String suffix = completion.substring(index+1); + int i = parts.length - 2; + while (i >= 0) { + if (parts[i].isEmpty()) + break; + if (!Character.isUpperCase(parts[i].charAt(0))) + break; + suffix = prefix + "." + suffix; + prefix = parts[i]; + i--; + } + + for (Def def: defsRoot.children) { + if (def.name.equals(prefix)) + return lookupCompletionInDef(suffix, def, document, offset); + } + + } + // find elements starting by in the list of elements + else { + for (Def def : defsRoot.children) { if (def.name.startsWith(completion) && isCompletionDef(def)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); @@ -317,6 +398,7 @@ else if (def.type == Def.Type.ModuleAlias) { private ArrayList processNondottedCompletion(String completion, Def defsRoot, + String moduleName, IDocument document, int offset) { @@ -338,15 +420,6 @@ private ArrayList processNondottedCompletion(String com /* * looked in current module */ - String moduleName = editor.getEditorInput().getName(); - if (moduleName.endsWith(".ml")) - moduleName = moduleName.substring(0, moduleName.length() - 3); - else if (moduleName.endsWith(".mli")) - moduleName = moduleName.substring(0, moduleName.length() - 4); - if (moduleName.length() > 0) - moduleName = Character.toUpperCase(moduleName.charAt(0)) - + moduleName.substring(1); - Def currentDef = null; for (Def def: defsRoot.children) { if (def.name.equals(moduleName)) { @@ -359,8 +432,8 @@ else if (moduleName.endsWith(".mli")) return proposals; // look down from top of current module - final Def nearestDef = findNearestDefAt(currentDef, offset, document); - proposals.addAll(lookCompletionProposalsUp(completion, nearestDef, offset)); + final Def nearestDef = findSmallestDefAtOffset(currentDef, offset, document); + proposals.addAll(bottomUpFindProposals(completion, nearestDef, offset)); for (Def def: currentDef.children) { if (def.name.startsWith(completion)) { @@ -402,7 +475,7 @@ else if (moduleName.endsWith(".mli")) } - private ArrayList lookCompletionProposalsUp(String completion, Def node, int offset) { + private ArrayList bottomUpFindProposals(String completion, Def node, int offset) { ArrayList proposals = new ArrayList(); if (node == null) @@ -443,12 +516,12 @@ && isCompletionDef(def)) { private ArrayList removeDuplicatedCompletionProposal(ArrayList proposals) { ArrayList newProposals = new ArrayList(); - HashSet names = new HashSet<>(); + HashSet proposalHashSet = new HashSet<>(); for (OcamlCompletionProposal p: proposals) { - String s = p.getDisplayString(); - if (!names.contains(s)) { + String s = p.getAdditionalProposalInfo(null); + if (!proposalHashSet.contains(s)) { newProposals.add(p); - names.add(s); + proposalHashSet.add(s); } } @@ -457,7 +530,7 @@ private ArrayList removeDuplicatedCompletionProposal(Ar /** Find an identifier (or an open directive) at a position in the document */ - private Def findNearestDefAt(Def def, int offset, IDocument doc) { + private Def findSmallestDefAtOffset(Def def, int offset, IDocument doc) { if (def == null || doc == null) return null; @@ -483,7 +556,7 @@ private Def findNearestDefAt(Def def, int offset, IDocument doc) { } } - return findNearestDefAt(nearestChild, offset, doc); + return findSmallestDefAtOffset(nearestChild, offset, doc); } private boolean isCompletionDef(Def def) { @@ -890,15 +963,6 @@ else if (lines.length > 6) { } } - - private void updateDefFileName(Def def, String filename) { - if (def != null) { - def.setFileName(filename); - for (Def d: def.children) { - updateDefFileName(d, filename); - } - } - } ArrayList lineOffsets = null; From b63b4d0dddc12f5867b7f66798a37976ee574276 Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 10 Oct 2014 02:42:06 +0800 Subject: [PATCH 043/127] significant improvements --- .../actions/SelectDownwardOneBlock.java | 2 -- .../editor/actions/SelectUpwardOneBlock.java | 1 - .../ocaml/editor/actions/ShowTextHover.java | 4 --- .../completion/OcamlCompletionProcessor.java | 31 +++++++++++++++---- Ocaml/src/ocaml/editors/OcamlEditor.java | 1 - Ocaml/src/ocaml/editors/OcamlTextHover.java | 1 - Ocaml/src/ocaml/parser/Def.java | 4 +-- 7 files changed, 27 insertions(+), 17 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/SelectDownwardOneBlock.java b/Ocaml/src/ocaml/editor/actions/SelectDownwardOneBlock.java index e2203de..c2a77aa 100644 --- a/Ocaml/src/ocaml/editor/actions/SelectDownwardOneBlock.java +++ b/Ocaml/src/ocaml/editor/actions/SelectDownwardOneBlock.java @@ -1,12 +1,10 @@ package ocaml.editor.actions; import ocaml.OcamlPlugin; -import ocaml.editors.OcamlEditor; import org.eclipse.jface.action.IAction; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Point; diff --git a/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java b/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java index 0c1dc59..37b7a56 100644 --- a/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java +++ b/Ocaml/src/ocaml/editor/actions/SelectUpwardOneBlock.java @@ -5,7 +5,6 @@ import org.eclipse.jface.action.IAction; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Point; diff --git a/Ocaml/src/ocaml/editor/actions/ShowTextHover.java b/Ocaml/src/ocaml/editor/actions/ShowTextHover.java index 4e4b9e8..58d5c1b 100644 --- a/Ocaml/src/ocaml/editor/actions/ShowTextHover.java +++ b/Ocaml/src/ocaml/editor/actions/ShowTextHover.java @@ -5,14 +5,11 @@ import ocaml.editors.OcamlTextHover; import org.eclipse.jface.action.IAction; -import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; -import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.custom.StyledText; -import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorInput; @@ -20,7 +17,6 @@ import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; -import org.eclipse.ui.editors.text.TextEditor; public class ShowTextHover implements IWorkbenchWindowActionDelegate { diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 1ea8692..1188539 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -42,6 +42,9 @@ public class OcamlCompletionProcessor implements IContentAssistProcessor { private final TextEditor editor; private final IProject project; + + private TypeAnnotation[] lastUsedAnnotations; + private String lastParsedAnnotFileName; /** The partition type in which completion was triggered. */ private final String partitionType; @@ -50,18 +53,24 @@ public OcamlCompletionProcessor(OcamlEditor edit, String regionType) { this.editor = (TextEditor)edit; this.project = edit.getProject(); this.partitionType = regionType; + this.lastUsedAnnotations = new TypeAnnotation[0]; + this.lastParsedAnnotFileName = ""; } public OcamlCompletionProcessor(OcamllexEditor edit, String regionType) { this.editor = (TextEditor)edit; this.project = edit.getProject(); this.partitionType = regionType; + this.lastUsedAnnotations = new TypeAnnotation[0]; + this.lastParsedAnnotFileName = ""; } public OcamlCompletionProcessor(OcamlyaccEditor edit, String regionType) { this.editor = (TextEditor)edit; this.project = edit.getProject(); this.partitionType = regionType; + this.lastUsedAnnotations = new TypeAnnotation[0]; + this.lastParsedAnnotFileName = ""; } /** @@ -832,12 +841,23 @@ public String getErrorMessage() { private Def createProposalDef(IProject project, Def def) { Def newDef = new Def(def); if (newDef.getBody().equals(newDef.name)) { - String filename = newDef.getFileName(); - TypeAnnotation[] annotations = parseModuleAnnotation(project, filename); - IDocument document = getDocument(project, filename); - String typeInfo = computeTypeInfo(newDef, annotations, document); if (newDef.type == Def.Type.Let || newDef.type == Def.Type.LetIn) { + String filename = newDef.getFileName(); + + // store last used annotation for caching + TypeAnnotation[] annotations; + if (filename.equals(lastParsedAnnotFileName)) { + annotations = lastUsedAnnotations; + } + else { + annotations = parseModuleAnnotation(project, filename); + lastUsedAnnotations = annotations; + lastParsedAnnotFileName = filename; + } + + IDocument document = getDocument(project, filename); + String typeInfo = computeTypeInfo(newDef, annotations, document); if (typeInfo.isEmpty()) typeInfo = newDef.name + " - "; newDef.setBody(typeInfo); @@ -846,9 +866,8 @@ else if (def.type == Def.Type.Type) { String newBody = newDef.name + " 't"; newDef.setBody(newBody); } - else - newDef.setBody(newDef.getBody() + " -- def type: " + newDef.getTypeName()); } + // Trung: uncomment to debug def type // newDef.setBody(newDef.getBody() + " -- def type: " + newDef.getTypeName()); return newDef; diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index 67a493c..b61b11a 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -35,7 +35,6 @@ import org.eclipse.jface.text.PaintManager; import org.eclipse.jface.text.TextEvent; import org.eclipse.jface.text.TextSelection; -import org.eclipse.jface.text.TextViewer; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.MatchingCharacterPainter; import org.eclipse.jface.viewers.ISelection; diff --git a/Ocaml/src/ocaml/editors/OcamlTextHover.java b/Ocaml/src/ocaml/editors/OcamlTextHover.java index 561a8b5..0d86d02 100644 --- a/Ocaml/src/ocaml/editors/OcamlTextHover.java +++ b/Ocaml/src/ocaml/editors/OcamlTextHover.java @@ -5,7 +5,6 @@ import ocaml.OcamlPlugin; import ocaml.debugging.OcamlDebugger; -import ocaml.preferences.PreferenceConstants; import ocaml.typeHovers.OcamlAnnotParser; import ocaml.typeHovers.TypeAnnotation; import ocaml.util.Misc; diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index d64d6e5..55c8832 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -554,8 +554,8 @@ private static String clean(String str) { private String filename = ""; public void setBody(String body) { -// this.body = body; - this.body = Misc.beautify(clean(body)); +// this.body = Misc.beautify(clean(body)); + this.body = Misc.beautify(body); } public String getBody() { From fba111c876085f8ac42a5fa1b4f234ae6e786244 Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 10 Oct 2014 03:16:50 +0800 Subject: [PATCH 044/127] acceptable, (so sleepy) --- .../completion/OcamlCompletionProcessor.java | 2 +- .../completion/OcamlInformationPresenter.java | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 1188539..1c50f6a 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -507,7 +507,7 @@ && isCompletionDef(travelNode)) { continue; if (def.name.startsWith(completion) && (def.name.length() > completion.length()) - && isCompletionDef(def)) { + && (def.type == Def.Type.Let || def.type == Def.Type.LetIn)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } diff --git a/Ocaml/src/ocaml/editor/completion/OcamlInformationPresenter.java b/Ocaml/src/ocaml/editor/completion/OcamlInformationPresenter.java index 87eac47..5915c17 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlInformationPresenter.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlInformationPresenter.java @@ -1,5 +1,6 @@ package ocaml.editor.completion; +import java.io.File; import java.util.ArrayList; import ocaml.OcamlPlugin; @@ -26,6 +27,7 @@ public String updatePresentation(Display display, String infoText, final Color colorSection = new Color(display, 150, 50, 191); final Color colorParent = new Color(display, 191, 100, 50); final Color colorCode = new Color(display, 0, 0, 255); + final Color colorModuleName = new Color(display, 119, 131, 112); final Color colorFilename = new Color(display, 64, 64, 64); String[] infos = infoText.split("\\$\\@\\|"); @@ -251,16 +253,28 @@ else if (bAnnotation) } if (!filename.equals("")) { + // attach module name + String[] parts = filename.split(File.separator); + String moduleName = ""; + if (parts.length > 1) { + moduleName = "Module: " + parts[parts.length - 1]; + } String strResult = result.toString(); if (strResult.endsWith("\n\n")) - text = filename; + text = moduleName; else if (strResult.endsWith("\n")) - text = "\n" + filename; + text = "\n" + moduleName; else - text = "\n\n" + filename; + text = "\n\n" + moduleName; result.append(text); + presentation.addStyleRange(new StyleRange(offset, text.length(), colorModuleName, null, + SWT.ITALIC)); + offset += text.length(); + // attach file name + text = "\n" + filename; + result.append(text); presentation.addStyleRange(new StyleRange(offset, text.length(), colorFilename, null, SWT.ITALIC)); offset += text.length(); From c6a5da26550e78d326044367d7f7d4b8cad28dbf Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 10 Oct 2014 03:33:20 +0800 Subject: [PATCH 045/127] wonderful, go home and sleep now! --- .../completion/OcamlCompletionProcessor.java | 1 - .../completion/OcamlCompletionProposal.java | 16 +++++++++++++++- Ocaml/src/ocaml/parser/Def.java | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 1c50f6a..e56630b 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -989,7 +989,6 @@ private void computeLinesStartOffset(String doc) { lineOffsets = new ArrayList(); lineOffsets.add(0); for (int i = 0; i < doc.length(); i++) { - /* * if(doc.charAt(i) == '\r') System.err.print("\n"); * if(doc.charAt(i) == '\n') System.err.print("\n"); else diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java index df93d43..08b0276 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java @@ -1,7 +1,10 @@ package ocaml.editor.completion; +import java.io.File; + import ocaml.OcamlPlugin; import ocaml.parser.Def; +import ocaml.util.Misc; import ocaml.views.outline.OcamlOutlineLabelProvider; import org.eclipse.core.runtime.IProgressMonitor; @@ -107,7 +110,17 @@ public Image getImage() { } public String getDisplayString() { - return definition.name; + String displayString = definition.name; + + if (!definition.getBody().equals(definition.name)) { + String newBody = Misc.beautify(Def.clean(definition.getBody())); + if (newBody.startsWith(displayString)) + displayString = newBody; + else + displayString = displayString + " - " + newBody; + } + + return displayString; } /** @deprecated replaced by the same name function in ICompletionProposalExtension5 */ @@ -121,6 +134,7 @@ public String getAdditionalProposalInfo(IProgressMonitor monitor) { * encodes as a string the informations that will be read back by OcamlInformationPresenter to format * them */ + return definition.parentName + " $@| " + definition.getBody() + " $@| " + definition.sectionComment + " $@| " + definition.comment + " $@| " + definition.getFileName(); diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index 55c8832..d8a77e4 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -532,7 +532,7 @@ public void setComment(String text) { } - private static String clean(String str) { + public static String clean(String str) { if (str == null) return ""; From 6b509d18eedab7ed495996b18523a596caba5c4e Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 10 Oct 2014 12:55:04 +0800 Subject: [PATCH 046/127] cache last parsed annotation --- .../completion/OcamlCompletionProcessor.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index e56630b..e370f97 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -43,8 +43,11 @@ public class OcamlCompletionProcessor implements IContentAssistProcessor { private final IProject project; - private TypeAnnotation[] lastUsedAnnotations; - private String lastParsedAnnotFileName; + // cache last parsed annotation file for speed up + private TypeAnnotation[] lastUsedAnnotations = new TypeAnnotation[0]; + private String lastParsedFileName = ""; + private long lastParsedTime = 0; + private static int cacheTime = 2000; /** The partition type in which completion was triggered. */ private final String partitionType; @@ -53,24 +56,18 @@ public OcamlCompletionProcessor(OcamlEditor edit, String regionType) { this.editor = (TextEditor)edit; this.project = edit.getProject(); this.partitionType = regionType; - this.lastUsedAnnotations = new TypeAnnotation[0]; - this.lastParsedAnnotFileName = ""; } public OcamlCompletionProcessor(OcamllexEditor edit, String regionType) { this.editor = (TextEditor)edit; this.project = edit.getProject(); this.partitionType = regionType; - this.lastUsedAnnotations = new TypeAnnotation[0]; - this.lastParsedAnnotFileName = ""; } public OcamlCompletionProcessor(OcamlyaccEditor edit, String regionType) { this.editor = (TextEditor)edit; this.project = edit.getProject(); this.partitionType = regionType; - this.lastUsedAnnotations = new TypeAnnotation[0]; - this.lastParsedAnnotFileName = ""; } /** @@ -847,13 +844,16 @@ private Def createProposalDef(IProject project, Def def) { // store last used annotation for caching TypeAnnotation[] annotations; - if (filename.equals(lastParsedAnnotFileName)) { + long currentTime = System.currentTimeMillis(); + if (filename.equals(lastParsedFileName) + && (currentTime - lastParsedTime < cacheTime)) { annotations = lastUsedAnnotations; } else { annotations = parseModuleAnnotation(project, filename); lastUsedAnnotations = annotations; - lastParsedAnnotFileName = filename; + lastParsedFileName = filename; + lastParsedTime = System.currentTimeMillis(); } IDocument document = getDocument(project, filename); From 9bdd7dcf0954a49026b1d055c89342ac0836384d Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 10 Oct 2014 15:44:03 +0800 Subject: [PATCH 047/127] Go to next/previous annotation --- Ocaml/plugin.xml | 47 ++++++++++--------- Ocaml/src/ocaml/editors/OcamlEditor.java | 5 +- .../editors/OcamlEditorActionContributor.java | 10 ++++ .../editors/OcamlSourceViewerConfig.java | 15 +++--- 4 files changed, 49 insertions(+), 28 deletions(-) create mode 100644 Ocaml/src/ocaml/editors/OcamlEditorActionContributor.java diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index 78d7fee..4cdacc7 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -70,30 +70,30 @@ point="org.eclipse.ui.editors"> @@ -1278,22 +1278,27 @@ + annotationType="ocaml.marker.occurrences" + colorPreferenceKey="ocaml.marker.occurrences.color" + colorPreferenceValue="192,255,192" + contributesToHeader="false" + highlightPreferenceKey="ocaml.marker.occurrences.highlight" + highlightPreferenceValue="true" + includeOnPreferencePage="true" + isGoToNextNavigationTarget="true" + isGoToNextNavigationTargetKey="true" + isGoToPreviousNavigationTarget="true" + isGoToPreviousNavigationTargetKey="true" + label="Ocaml Occurrences Marker" + overviewRulerPreferenceKey="ocaml.marker.occurrences.overview" + overviewRulerPreferenceValue="true" + presentationLayer="0" + showInNextPrevDropdownToolbarAction="true" + textPreferenceKey="ocaml.marker.occurrences.text" + textPreferenceValue="true" + textStylePreferenceValue="BOX" + verticalRulerPreferenceKey="ocaml.marker.occurrences.ruler" + verticalRulerPreferenceValue="true"> diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index b61b11a..a3c2a48 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -50,6 +50,7 @@ import org.eclipse.ui.ide.FileStoreEditorInput; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; /** @@ -87,7 +88,7 @@ public OcamlEditor() { this.setSourceViewerConfiguration(new OcamlSourceViewerConfig(this)); // this.setRangeIndicator(new DefaultRangeIndicator()); } - + /** The debug cursor (as a red I-beam) */ private DebugVisuals caret; @@ -203,6 +204,8 @@ public void doSetInput(IEditorInput input) throws CoreException { * if (this.fOutlinePage != null) this.fOutlinePage.setInput(input); */ } + + /** * We give the outline to Eclipse when it asks for an adapter with the diff --git a/Ocaml/src/ocaml/editors/OcamlEditorActionContributor.java b/Ocaml/src/ocaml/editors/OcamlEditorActionContributor.java new file mode 100644 index 0000000..2023258 --- /dev/null +++ b/Ocaml/src/ocaml/editors/OcamlEditorActionContributor.java @@ -0,0 +1,10 @@ +package ocaml.editors; + +import org.eclipse.ui.editors.text.TextEditorActionContributor; + +/* + * Trung: add code here to support editor action + */ +public class OcamlEditorActionContributor extends TextEditorActionContributor { + +} diff --git a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java index bb68fd1..70844e9 100644 --- a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java +++ b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java @@ -56,11 +56,11 @@ */ public class OcamlSourceViewerConfig extends SourceViewerConfiguration { private OcamlEditor ocamlEditor; - private boolean contentAssistantActived; + private boolean isContentAssistantActive; public OcamlSourceViewerConfig(OcamlEditor ocamlEditor) { this.ocamlEditor = ocamlEditor; - this.contentAssistantActived = false; + this.isContentAssistantActive = false; } /** @@ -165,15 +165,15 @@ public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { assistant.addCompletionListener(new ICompletionListener() { @Override public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) { - contentAssistantActived = true; + isContentAssistantActive = true; } @Override public void assistSessionStarted(ContentAssistEvent event) { - contentAssistantActived = true; + isContentAssistantActive = true; } @Override public void assistSessionEnded(ContentAssistEvent event) { - contentAssistantActived = false; + isContentAssistantActive = false; } }); @@ -204,6 +204,7 @@ public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) { public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer) { return new OcamlAnnotationHover(); } + @Override public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) { @@ -272,8 +273,10 @@ public void propertyChange(PropertyChangeEvent event) { } public boolean isContentAssistantActive() { - return contentAssistantActived; + return isContentAssistantActive; } + + } From 9503b7bb1674e07ec13eb51e00ca7bf7832e6dcf Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 10 Oct 2014 16:07:33 +0800 Subject: [PATCH 048/127] improvement on annotation navigating --- Ocaml/plugin.xml | 75 +++++++++---------- .../editor/actions/MarkOccurrencesAction.java | 1 + 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index 4cdacc7..72750af 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -1198,6 +1198,10 @@ markerType="Ocaml.ocamlSyntaxErrorMarker" name="Ocaml.ocamlSyntaxErrorAnnotationType"> + + @@ -1207,22 +1211,50 @@ colorPreferenceValue="255,140,0" contributesToHeader="true" highlightPreferenceKey="syntaxerror.highlight" - highlightPreferenceValue="false" + highlightPreferenceValue="true" includeOnPreferencePage="true" - isGoToNextNavigationTarget="false" - isGoToPreviousNavigationTarget="false" + isGoToNextNavigationTarget="true" + isGoToNextNavigationTargetKey="true" + isGoToPreviousNavigationTarget="true" + isGoToPreviousNavigationTargetKey="true" label="Ocaml Syntax Error" overviewRulerPreferenceKey="syntaxerror.rulers.overview" overviewRulerPreferenceValue="true" presentationLayer="1" - showInNextPrevDropdownToolbarAction="false" + showInNextPrevDropdownToolbarAction="true" + showInNextPrevDropdownToolbarActionKey="true" symbolicIcon="error" textPreferenceKey="syntaxerror.text" textPreferenceValue="true" textStylePreferenceKey="syntaxerror.textstyle" textStylePreferenceValue="SQUIGGLES" verticalRulerPreferenceKey="syntaxerror.rulers.vertical" - verticalRulerPreferenceValue="false"> + verticalRulerPreferenceValue="true"> + + - - - - - - - - diff --git a/Ocaml/src/ocaml/editor/actions/MarkOccurrencesAction.java b/Ocaml/src/ocaml/editor/actions/MarkOccurrencesAction.java index 317ee48..36c5d44 100644 --- a/Ocaml/src/ocaml/editor/actions/MarkOccurrencesAction.java +++ b/Ocaml/src/ocaml/editor/actions/MarkOccurrencesAction.java @@ -55,6 +55,7 @@ public void run(IAction action) { int endOffset = region.getOffset() + region.getLength(); marker.setAttribute(IMarker.CHAR_START, startOffset); marker.setAttribute(IMarker.CHAR_END, endOffset); + marker.setAttribute(IMarker.MESSAGE, ""); region = docFind.find(endOffset + 1, text, true, true, false, false); } } From 1a0a1dbebe356c216b5749154b9bbd5b7a8af14e Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 10 Oct 2014 23:29:20 +0800 Subject: [PATCH 049/127] improve build actions --- Ocaml/plugin.xml | 71 +++++++++- Ocaml/src/ocaml/OcamlPlugin.java | 4 + .../CancelCompileAllProjectsAction.java | 91 ++++++++++++ .../editor/actions/CleanProjectAction.java | 129 +++++++++++++++++ .../editor/actions/CompileProjectAction.java | 130 ++++++++++++++++++ Ocaml/src/ocaml/editors/OcamlEditor.java | 4 +- .../src/ocaml/editors/lex/OcamllexEditor.java | 4 +- .../ocaml/editors/yacc/OcamlyaccEditor.java | 4 +- .../CancelCompileProjectPopupAction.java | 72 ++++++++++ ...tion.java => CleanProjectPopupAction.java} | 49 ++++++- ...on.java => CompileProjectPopupAction.java} | 40 +++++- 11 files changed, 581 insertions(+), 17 deletions(-) create mode 100644 Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java create mode 100644 Ocaml/src/ocaml/editor/actions/CleanProjectAction.java create mode 100644 Ocaml/src/ocaml/editor/actions/CompileProjectAction.java create mode 100644 Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java rename Ocaml/src/ocaml/popup/actions/{CleanProjectAction.java => CleanProjectPopupAction.java} (55%) rename Ocaml/src/ocaml/popup/actions/{CompileProjectAction.java => CompileProjectPopupAction.java} (66%) diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index 72750af..1c2a401 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -866,6 +866,33 @@ style="push">
+ + + + + + + + @@ -961,6 +988,21 @@ categoryId="Ocaml.commandscategory" id="Ocaml.showTextHover" name="Show Text Hover"> + + + + + + @@ -1086,6 +1128,24 @@ contextId="org.eclipse.ui.textEditorScope" schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" sequence="M1+M3+H"> + + + + + + @@ -1119,16 +1179,23 @@ + + ActiveBuildJobs = new HashMap<>(); /** The directory in which the plug-in was started. */ private final String pluginDirectory; diff --git a/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java b/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java new file mode 100644 index 0000000..16b3216 --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java @@ -0,0 +1,91 @@ +package ocaml.editor.actions; + +import java.util.Collection; + +import ocaml.OcamlPlugin; +import ocaml.editors.OcamlEditor; +import ocaml.editors.lex.OcamllexEditor; +import ocaml.editors.yacc.OcamlyaccEditor; +import ocaml.util.Misc; +import ocaml.views.OcamlCompilerOutput; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +/** This action activates completion in the OCaml editor. */ +public class CancelCompileAllProjectsAction implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + IWorkbenchPage page = window.getActivePage(); + if (page != null) { + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart != null) { + IProject project = null; + if (editorPart instanceof OcamlEditor) { + OcamlEditor editor = (OcamlEditor) editorPart; + project = editor.getProject(); + + } else if (editorPart instanceof OcamllexEditor) { + OcamllexEditor editor = (OcamllexEditor) editorPart; + project = editor.getProject(); + + } else if (editorPart instanceof OcamlyaccEditor) { + OcamlyaccEditor editor = (OcamlyaccEditor) editorPart; + project = editor.getProject(); + } + + if (project == null) + return; + + final String jobName = "Cancelling compiling jobs"; + + Job job = new Job(jobName) { + @Override + protected IStatus run(IProgressMonitor monitor) { + if (!OcamlPlugin.ActiveBuildJobs.isEmpty()) { + Misc.appendToOcamlConsole("Cancelled all compiling jobs..."); + Collection monitors = OcamlPlugin.ActiveBuildJobs.values(); + for (IProgressMonitor m: monitors) { + m.setCanceled(true); + } + } + return Status.OK_STATUS; + } + }; + + // open the "OCaml compiler output" view to show the output of the make + Misc.showView(OcamlCompilerOutput.ID); + + job.setPriority(Job.BUILD); + job.setUser(action != null); + job.schedule(500); + + }else + OcamlPlugin.logError("ContentAssistAction: editorPart is null"); + } else + OcamlPlugin.logError("ContentAssistAction: page is null"); + + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} diff --git a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java new file mode 100644 index 0000000..ae55fdb --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java @@ -0,0 +1,129 @@ +package ocaml.editor.actions; + +import java.util.Calendar; +import java.util.Collection; + +import ocaml.OcamlPlugin; +import ocaml.build.makefile.OcamlMakefileBuilder; +import ocaml.editors.OcamlEditor; +import ocaml.editors.lex.OcamllexEditor; +import ocaml.editors.yacc.OcamlyaccEditor; +import ocaml.util.Misc; +import ocaml.views.OcamlCompilerOutput; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.IJobChangeListener; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.ITextOperationTarget; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +/** This action activates completion in the OCaml editor. */ +public class CleanProjectAction implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + IWorkbenchPage page = window.getActivePage(); + if (page != null) { + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart != null) { + IProject project = null; + if (editorPart instanceof OcamlEditor) { + OcamlEditor editor = (OcamlEditor) editorPart; + project = editor.getProject(); + + } else if (editorPart instanceof OcamllexEditor) { + OcamllexEditor editor = (OcamllexEditor) editorPart; + project = editor.getProject(); + + } else if (editorPart instanceof OcamlyaccEditor) { + OcamlyaccEditor editor = (OcamlyaccEditor) editorPart; + project = editor.getProject(); + } + + if (project == null) + return; + + final IProject buildProject = project; + + String timeStamp = String.valueOf(Calendar.getInstance().getTime()); + final String jobName = "Cleaning project " + project.getName(); + + Job job = new Job(jobName) { + @Override + protected IStatus run(IProgressMonitor monitor) { + // save progress monitor for later use + OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); + OcamlMakefileBuilder builder = new OcamlMakefileBuilder(); + builder.clean(buildProject, monitor); + return Status.OK_STATUS; + } + }; + + // open the "OCaml compiler output" view to show the output of the make + Misc.showView(OcamlCompilerOutput.ID); + + job.setPriority(Job.BUILD); + /* + * If the action is directly called by the user, then we display a dialog box. Else, the launch is silent. + */ + job.setUser(action != null); + job.schedule(500); + job.addJobChangeListener(new IJobChangeListener() { + @Override + public void sleeping(IJobChangeEvent event) { + } + + @Override + public void scheduled(IJobChangeEvent event) { + } + + @Override + public void running(IJobChangeEvent event) { + } + + @Override + public void done(IJobChangeEvent event) { + // remove finished job from store + OcamlPlugin.ActiveBuildJobs.remove(jobName); + } + + @Override + public void awake(IJobChangeEvent event) { + } + + @Override + public void aboutToRun(IJobChangeEvent event) { + } + }); + + }else + OcamlPlugin.logError("ContentAssistAction: editorPart is null"); + } else + OcamlPlugin.logError("ContentAssistAction: page is null"); + + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} diff --git a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java new file mode 100644 index 0000000..fd95c92 --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java @@ -0,0 +1,130 @@ +package ocaml.editor.actions; + +import java.util.Calendar; +import java.util.Collection; + +import ocaml.OcamlPlugin; +import ocaml.editors.OcamlEditor; +import ocaml.editors.lex.OcamllexEditor; +import ocaml.editors.yacc.OcamlyaccEditor; +import ocaml.util.Misc; +import ocaml.views.OcamlCompilerOutput; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.IJobChangeListener; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.ITextOperationTarget; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +/** This action activates completion in the OCaml editor. */ +public class CompileProjectAction implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + IWorkbenchPage page = window.getActivePage(); + if (page != null) { + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart != null) { + IProject project = null; + if (editorPart instanceof OcamlEditor) { + OcamlEditor editor = (OcamlEditor) editorPart; + project = editor.getProject(); + + } else if (editorPart instanceof OcamllexEditor) { + OcamllexEditor editor = (OcamllexEditor) editorPart; + project = editor.getProject(); + + } else if (editorPart instanceof OcamlyaccEditor) { + OcamlyaccEditor editor = (OcamlyaccEditor) editorPart; + project = editor.getProject(); + } + + if (project == null) + return; + + final IProject buildProject = project; + + final String jobName = "Compiling project " + project.getName(); + + Job job = new Job(jobName) { + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + // save progress monitor for later use + OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); + buildProject.build(IncrementalProjectBuilder.FULL_BUILD, monitor); + } catch (CoreException e) { + OcamlPlugin.logError("ocaml plugin error", e); + } + return Status.OK_STATUS; + } + }; + + // open the "OCaml compiler output" view to show the output of the make + Misc.showView(OcamlCompilerOutput.ID); + + job.setPriority(Job.BUILD); + /* + * If the action is directly called by the user, then we display a dialog box. Else, the launch is silent. + */ + job.setUser(action != null); + job.schedule(500); + job.addJobChangeListener(new IJobChangeListener() { + @Override + public void sleeping(IJobChangeEvent event) { + } + + @Override + public void scheduled(IJobChangeEvent event) { + } + + @Override + public void running(IJobChangeEvent event) { + } + + @Override + public void done(IJobChangeEvent event) { + // remove finished job from store + OcamlPlugin.ActiveBuildJobs.remove(jobName); + } + + @Override + public void awake(IJobChangeEvent event) { + } + + @Override + public void aboutToRun(IJobChangeEvent event) { + } + }); + + }else + OcamlPlugin.logError("ContentAssistAction: editorPart is null"); + } else + OcamlPlugin.logError("ContentAssistAction: page is null"); + + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index a3c2a48..5b612ab 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -10,7 +10,7 @@ import ocaml.editors.util.OcamlCharacterPairMatcher; import ocaml.natures.OcamlNatureMakefile; import ocaml.parser.Def; -import ocaml.popup.actions.CompileProjectAction; +import ocaml.popup.actions.CompileProjectPopupAction; import ocaml.preferences.PreferenceConstants; import ocaml.views.outline.OcamlOutlineControl; import ocaml.views.outline.OutlineJob; @@ -441,7 +441,7 @@ public void doSave(IProgressMonitor monitor) { IWorkspace ws = ResourcesPlugin.getWorkspace(); IWorkspaceDescription desc = ws.getDescription(); if (desc.isAutoBuilding()) - CompileProjectAction.compileProject(this.getProject()); + CompileProjectPopupAction.compileProject(this.getProject()); } } diff --git a/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java b/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java index 744d12a..1001b45 100644 --- a/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java +++ b/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java @@ -4,7 +4,7 @@ import ocaml.editor.completion.CompletionJob; import ocaml.editors.util.OcamlCharacterPairMatcher; import ocaml.natures.OcamlNatureMakefile; -import ocaml.popup.actions.CompileProjectAction; +import ocaml.popup.actions.CompileProjectPopupAction; import ocaml.preferences.PreferenceConstants; import org.eclipse.core.resources.IProject; @@ -97,7 +97,7 @@ public void doSave(IProgressMonitor monitor) { IWorkspace ws = ResourcesPlugin.getWorkspace(); IWorkspaceDescription desc = ws.getDescription(); if (desc.isAutoBuilding()) - CompileProjectAction.compileProject(this.getProject()); + CompileProjectPopupAction.compileProject(this.getProject()); } } diff --git a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java index b36bc8b..7532e93 100644 --- a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java +++ b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java @@ -6,7 +6,7 @@ import ocaml.editors.yacc.outline.OcamlYaccOutlineControl; import ocaml.editors.yacc.outline.YaccOutlineJob; import ocaml.natures.OcamlNatureMakefile; -import ocaml.popup.actions.CompileProjectAction; +import ocaml.popup.actions.CompileProjectPopupAction; import ocaml.preferences.PreferenceConstants; import org.eclipse.core.resources.IProject; @@ -112,7 +112,7 @@ public void doSave(IProgressMonitor monitor) { IWorkspace ws = ResourcesPlugin.getWorkspace(); IWorkspaceDescription desc = ws.getDescription(); if (desc.isAutoBuilding()) - CompileProjectAction.compileProject(this.getProject()); + CompileProjectPopupAction.compileProject(this.getProject()); } } diff --git a/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java new file mode 100644 index 0000000..c229110 --- /dev/null +++ b/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java @@ -0,0 +1,72 @@ +package ocaml.popup.actions; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; + +import ocaml.OcamlPlugin; +import ocaml.util.Misc; +import ocaml.views.OcamlCompilerOutput; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.IObjectActionDelegate; +import org.eclipse.ui.IWorkbenchPart; + +/** + * This action is called when the user clicks on the "make project" menu item in the contextual menu for + * OCaml makefile projects. Calls the Builder to build the project. + */ +public class CancelCompileProjectPopupAction implements IObjectActionDelegate { + + public CancelCompileProjectPopupAction() { + } + + /** This method is used to call the action directly, without having to instantiate it */ + public static void cancelCompileProject(IProject project) { + CancelCompileProjectPopupAction action = new CancelCompileProjectPopupAction(); + action.run(null); + } + + @Override + public void run(IAction action) { + final String jobName = "Cancelling compiling jobs"; + + Job job = new Job(jobName) { + @Override + protected IStatus run(IProgressMonitor monitor) { + if (!OcamlPlugin.ActiveBuildJobs.isEmpty()) { + Misc.appendToOcamlConsole("Cancelled all compiling jobs..."); + Collection monitors = OcamlPlugin.ActiveBuildJobs.values(); + for (IProgressMonitor m: monitors) { + m.setCanceled(true); + } + } + return Status.OK_STATUS; + } + }; + + // open the "OCaml compiler output" view to show the output of the make + Misc.showView(OcamlCompilerOutput.ID); + + job.setPriority(Job.BUILD); + job.setUser(action != null); + job.schedule(500); + } + + @Override + public void setActivePart(IAction action, IWorkbenchPart targetPart) { + } + + @Override + public void selectionChanged(IAction action, ISelection selection) { + } +} diff --git a/Ocaml/src/ocaml/popup/actions/CleanProjectAction.java b/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java similarity index 55% rename from Ocaml/src/ocaml/popup/actions/CleanProjectAction.java rename to Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java index f5e7f8e..1f86683 100644 --- a/Ocaml/src/ocaml/popup/actions/CleanProjectAction.java +++ b/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java @@ -1,13 +1,18 @@ package ocaml.popup.actions; +import ocaml.OcamlPlugin; import ocaml.build.makefile.OcamlMakefileBuilder; import ocaml.util.Misc; import ocaml.views.OcamlCompilerOutput; import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; @@ -16,30 +21,64 @@ import org.eclipse.ui.IWorkbenchPart; /** This action is called when the user clicks on the "Clean Project" contextual pop-up menu item on OCaml makefile projects */ -public class CleanProjectAction implements IObjectActionDelegate { +public class CleanProjectPopupAction implements IObjectActionDelegate { private IProject project = null; - public CleanProjectAction() { + public CleanProjectPopupAction() { } public void run(IAction action) { if (project != null) { - Job job = new Job("Cleaning Project") { + final String jobName = "Cleaning project " + project.getName(); + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { + // save progress monitor for later use + OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); + OcamlMakefileBuilder builder = new OcamlMakefileBuilder(); builder.clean(project, monitor); return Status.OK_STATUS; } }; - + // open the "OCaml compiler output" view to show the output of the make Misc.showView(OcamlCompilerOutput.ID); job.setPriority(Job.BUILD); - job.setUser(true); + /* + * If the action is directly called by the user, then we display a dialog box. Else, the launch is silent. + */ + job.setUser(action != null); job.schedule(500); + job.addJobChangeListener(new IJobChangeListener() { + @Override + public void sleeping(IJobChangeEvent event) { + } + + @Override + public void scheduled(IJobChangeEvent event) { + } + + @Override + public void running(IJobChangeEvent event) { + } + + @Override + public void done(IJobChangeEvent event) { + // remove finished job from store + OcamlPlugin.ActiveBuildJobs.remove(jobName); + } + + @Override + public void awake(IJobChangeEvent event) { + } + + @Override + public void aboutToRun(IJobChangeEvent event) { + } + }); } } diff --git a/Ocaml/src/ocaml/popup/actions/CompileProjectAction.java b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java similarity index 66% rename from Ocaml/src/ocaml/popup/actions/CompileProjectAction.java rename to Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java index f95e5ec..a624335 100644 --- a/Ocaml/src/ocaml/popup/actions/CompileProjectAction.java +++ b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java @@ -10,6 +10,8 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; @@ -21,25 +23,28 @@ * This action is called when the user clicks on the "make project" menu item in the contextual menu for * OCaml makefile projects. Calls the Builder to build the project. */ -public class CompileProjectAction implements IObjectActionDelegate { +public class CompileProjectPopupAction implements IObjectActionDelegate { private IProject project = null; - public CompileProjectAction() { + public CompileProjectPopupAction() { } /** This method is used to call the action directly, without having to instantiate it */ public static void compileProject(IProject project) { - CompileProjectAction compileProjectAction = new CompileProjectAction(); + CompileProjectPopupAction compileProjectAction = new CompileProjectPopupAction(); compileProjectAction.project = project; compileProjectAction.run(null); } public void run(IAction action) { if (project != null) { - Job job = new Job("Building Project") { + final String jobName = "Compiling project " + project.getName(); + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { try { + // save progress monitor for later use + OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); project.build(IncrementalProjectBuilder.FULL_BUILD, monitor); } catch (CoreException e) { OcamlPlugin.logError("ocaml plugin error", e); @@ -57,6 +62,33 @@ protected IStatus run(IProgressMonitor monitor) { */ job.setUser(action != null); job.schedule(500); + job.addJobChangeListener(new IJobChangeListener() { + @Override + public void sleeping(IJobChangeEvent event) { + } + + @Override + public void scheduled(IJobChangeEvent event) { + } + + @Override + public void running(IJobChangeEvent event) { + } + + @Override + public void done(IJobChangeEvent event) { + // remove finished job from store + OcamlPlugin.ActiveBuildJobs.remove(jobName); + } + + @Override + public void awake(IJobChangeEvent event) { + } + + @Override + public void aboutToRun(IJobChangeEvent event) { + } + }); } } From b7193ad24314fe87a06e175e14d861233d3e0e28 Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 10 Oct 2014 23:31:09 +0800 Subject: [PATCH 050/127] minor changes --- Ocaml/plugin.xml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index 1c2a401..fe945f9 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -777,18 +777,15 @@ + id="Ocaml_sourceActions_markOccurrences" label="Mark Occurrences" style="push"/> + id="Ocaml_sourceActions_shiftLeft" label="Shift Left" style="push"/> + id="Ocaml_sourceActions_shiftRight" label="Shift Right" style="push"/> Date: Fri, 10 Oct 2014 23:40:46 +0800 Subject: [PATCH 051/127] minor changes --- Ocaml/plugin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index fe945f9..25b61fc 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -1094,7 +1094,7 @@ commandId="Ocaml.gotoDefinitionCommand" contextId="Ocaml.editor.context" schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" - sequence="M1+M3+D"> + sequence="F3"> Date: Sat, 11 Oct 2014 16:17:44 +0800 Subject: [PATCH 052/127] minor changes --- Ocaml/src/ocaml/preferences/PreferenceInitializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ocaml/src/ocaml/preferences/PreferenceInitializer.java b/Ocaml/src/ocaml/preferences/PreferenceInitializer.java index 7dbb164..6bf165a 100644 --- a/Ocaml/src/ocaml/preferences/PreferenceInitializer.java +++ b/Ocaml/src/ocaml/preferences/PreferenceInitializer.java @@ -74,7 +74,7 @@ public void initializeDefaultPreferences() { store.setDefault(PreferenceConstants.P_SHOW_TYPES_IN_OUTLINE, true); store.setDefault(PreferenceConstants.P_SHOW_TYPES_IN_POPUPS, true); - store.setDefault(PreferenceConstants.P_SHOW_TYPES_IN_STATUS_BAR, true); + store.setDefault(PreferenceConstants.P_SHOW_TYPES_IN_STATUS_BAR, false); store.setDefault(PreferenceConstants.P_SHOW_MARKERS_IN_STATUS_BAR, true); // set the defaults for the formatter From 4edd4050123f16f87d434dfffa0e70c37a4d34da Mon Sep 17 00:00:00 2001 From: trungtq Date: Sat, 11 Oct 2014 17:36:03 +0800 Subject: [PATCH 053/127] improvement on completion --- .../completion/OcamlCompletionProcessor.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index e370f97..dbc70e0 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -477,6 +477,27 @@ private ArrayList processNondottedCompletion(String com } } + /* + * look in Pervasives module, which is always opended + */ + for (Def def: defsRoot.children) { + if (def == null || def.name == null) + break; + + if (!def.name.equals("Pervasives")) + continue; + + for (Def d: def.children) { + if (d == null || d.name == null) + break; + + if (d.name.startsWith(completion) && isCompletionDef(d)) { + Def proposedDef = createProposalDef(project, d); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } + } + } + return proposals; } From 9ff55827054fd7cb7add18078b30e4aae6267c21 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sat, 11 Oct 2014 18:43:55 +0800 Subject: [PATCH 054/127] improvement on completion --- Ocaml/plugin.xml | 3 - .../completion/OcamlCompletionProcessor.java | 186 +++++++++++------- 2 files changed, 114 insertions(+), 75 deletions(-) diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index 25b61fc..b6c643b 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -1048,9 +1048,6 @@ contextId="Ocaml.editor.context" schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" sequence="CTRL+SPACE"/> - diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index dbc70e0..b838ffc 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -236,14 +236,14 @@ else if (moduleName.endsWith(".mli")) // completion string must contained dots private ArrayList processDottedCompletion(String completion, - Def defsRoot, + Def interfacesDefsRoot, String moduleName, IDocument document, int offset) { ArrayList proposals = new ArrayList(); - if (defsRoot == null) + if (interfacesDefsRoot == null) return proposals; // look in the module before the dot what's after the dot @@ -269,14 +269,14 @@ private ArrayList processDottedCompletion(String comple * look into current module first */ Def currentDef = null; - for (Def def: defsRoot.children) { + for (Def def: interfacesDefsRoot.children) { if (def.name.equals(moduleName)) { currentDef = def; break; } } - // look in sub-module or aliased module of current modules + // look for prefix in sub-module or aliased module of current modules boolean stop = false; while (!stop) { stop = true; @@ -288,7 +288,7 @@ private ArrayList processDottedCompletion(String comple continue; if (def.type == Def.Type.Module) { - return lookupCompletionInDef(suffix, def, document, offset); + proposals.addAll(processDottedCompletionSuffix(suffix, def, interfacesDefsRoot, document, offset)); } else if (def.type == Def.Type.ModuleAlias) { String aliasedName = def.children.get(0).name; @@ -303,48 +303,49 @@ else if (def.type == Def.Type.ModuleAlias) { } } - // look in opened module of current module - Def openedModule = null; - for (Def def : currentDef.children) { - if (def.type == Def.Type.Open) { - for (Def otherDef: defsRoot.children) { - if (otherDef == null || otherDef.name == null) - break; - - if (otherDef.name.equals(def.name)) { - openedModule = otherDef; - break; + // look for completion in opened or included module of current module + for (Def def1 : currentDef.children) { + if (def1.type == Def.Type.Open || def1.type == Def.Type.Include) { + Def involvedDef = def1; + // search in current module first + for (Def def2: currentDef.children) { + if (def2.name.equals(involvedDef.name)) { + Def involvedDefRoot = def2; + for (Def def3: involvedDefRoot.children) { + if (def3.name.startsWith(completion) && isCompletionDef(def3)) { + Def proposedDef = createProposalDef(project, def3); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } + } } } - } - } - if (openedModule != null) - for (Def def: openedModule.children) { - if (def == null || def.name == null) - break; - - if (def.name.startsWith(completion) && isCompletionDef(def)) { - Def proposedDef = createProposalDef(project, def); - proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + for (Def def2: interfacesDefsRoot.children) { + if (def2.name.equals(involvedDef.name)) { + Def involvedDefRoot = def2; + for (Def def3: involvedDefRoot.children) { + if (def3.name.startsWith(completion) && isCompletionDef(def3)) { + Def proposedDef = createProposalDef(project, def3); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } + } + } } } + } /* * then look into other modules */ - for (Def def: defsRoot.children) { - if (def == null || def.name == null) - continue; - + for (Def def: interfacesDefsRoot.children) { if (def.name.equals(prefix)) - return lookupCompletionInDef(suffix, def, document, offset); + proposals.addAll(processDottedCompletionSuffix(suffix, def, interfacesDefsRoot, document, offset)); } } // find elements starting by in the list of elements else { - for (Def def : defsRoot.children) { + for (Def def : interfacesDefsRoot.children) { if (def.name.startsWith(completion) && isCompletionDef(def)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); @@ -355,9 +356,10 @@ else if (def.type == Def.Type.ModuleAlias) { return proposals; } - // completion string must contained dots - private ArrayList lookupCompletionInDef(String completion, + // process the completion suffix after 'dot' symbol + private ArrayList processDottedCompletionSuffix(String completion, Def defsRoot, + Def interfacesDefRoot, IDocument document, int offset) { @@ -383,20 +385,67 @@ private ArrayList lookupCompletionInDef(String completi i--; } + // look inside def roots first for (Def def: defsRoot.children) { if (def.name.equals(prefix)) - return lookupCompletionInDef(suffix, def, document, offset); + proposals.addAll(processDottedCompletionSuffix(suffix, def, interfacesDefRoot, document, offset)); + } + + // look inside included module + for (Def def1: defsRoot.children) { + if (def1.type == Def.Type.Include) { + Def includedDef = def1; + // look for included def in current defs + for (Def def2: defsRoot.children) { + if (def2.name.equals(includedDef.name)) { + Def includedDefRoot = def2; + proposals.addAll(processDottedCompletionSuffix(completion, includedDefRoot, interfacesDefRoot, document, offset)); + } + + } + // look for included def in interfaces root defs + for (Def def2: interfacesDefRoot.children) { + if (def2.name.equals(includedDef.name)) { + Def includedDefRoot = def2; + proposals.addAll(processDottedCompletionSuffix(completion, includedDefRoot, interfacesDefRoot, document, offset)); + } + + } + } } - } // find elements starting by in the list of elements else { + // look inside def roots first for (Def def : defsRoot.children) { if (def.name.startsWith(completion) && isCompletionDef(def)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } } + // look inside included module + for (Def def1: defsRoot.children) { + if (def1.type == Def.Type.Include) { + Def includedDef = def1; + // look for included def in current defs + for (Def def2: defsRoot.children) { + if (def2.name.equals(includedDef.name)) { + Def includedDefRoot = def2; + proposals.addAll(processDottedCompletionSuffix(completion, includedDefRoot, interfacesDefRoot, document, offset)); + } + + } + // look for included def in interfaces root defs + for (Def def2: interfacesDefRoot.children) { + if (def2.name.equals(includedDef.name)) { + Def includedDefRoot = def2; + proposals.addAll(processDottedCompletionSuffix(completion, includedDefRoot, interfacesDefRoot, document, offset)); + } + + } + } + } + } return proposals; @@ -434,44 +483,40 @@ private ArrayList processNondottedCompletion(String com } } - if (currentDef == null) - return proposals; - - // look down from top of current module - final Def nearestDef = findSmallestDefAtOffset(currentDef, offset, document); - proposals.addAll(bottomUpFindProposals(completion, nearestDef, offset)); - - for (Def def: currentDef.children) { - if (def.name.startsWith(completion)) { - Def proposedDef = createProposalDef(project, def); - proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); - } - } - - /* - * look in opened module of current module - */ - for (Def def : currentDef.children) { - if (def == null || def.name == null) - break; + if (currentDef != null) { + // look down from top of current module + final Def nearestDef = findSmallestDefAtOffset(currentDef, offset, document); + proposals.addAll(bottomUpFindProposals(completion, nearestDef, offset)); - if (def.type != Def.Type.Open) - continue; + for (Def def: currentDef.children) { + if (def.name.startsWith(completion)) { + Def proposedDef = createProposalDef(project, def); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } + } - for (Def idef: defsRoot.children) { - if (idef == null || idef.name == null) - break; - - if (!idef.name.equals(def.name)) + /* + * look in opened module of current module + */ + for (Def def : currentDef.children) { + if (def.type != Def.Type.Open && def.type != Def.Type.Include) continue; - - for (Def d: idef.children) { - if (d == null || d.name == null) + + for (Def idef: defsRoot.children) { + if (idef == null || idef.name == null) break; - if (d.name.startsWith(completion) && isCompletionDef(d)) { - Def proposedDef = createProposalDef(project, d); - proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + if (!idef.name.equals(def.name)) + continue; + + for (Def d: idef.children) { + if (d == null || d.name == null) + break; + + if (d.name.startsWith(completion) && isCompletionDef(d)) { + Def proposedDef = createProposalDef(project, d); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } } } } @@ -481,9 +526,6 @@ private ArrayList processNondottedCompletion(String com * look in Pervasives module, which is always opended */ for (Def def: defsRoot.children) { - if (def == null || def.name == null) - break; - if (!def.name.equals("Pervasives")) continue; From 4c56def7e2615c88cad572259bf5e1a486d0fb01 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sat, 11 Oct 2014 19:04:01 +0800 Subject: [PATCH 055/127] more improvements --- .../completion/OcamlCompletionProcessor.java | 208 +++++++++--------- 1 file changed, 103 insertions(+), 105 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index b838ffc..7ee3a01 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -209,7 +209,7 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int * @return the completions found */ private OcamlCompletionProposal[] findCompletionProposals(String completion, - Def defsRoot, + Def interfacesDefsRoot, IDocument doc, int offset) { @@ -225,9 +225,9 @@ else if (moduleName.endsWith(".mli")) + moduleName.substring(1); if (completion.contains(".")) - proposals = processDottedCompletion(completion, defsRoot, moduleName, doc, offset); + proposals = processDottedCompletion(completion, interfacesDefsRoot, moduleName, doc, offset); else - proposals = processNondottedCompletion(completion, defsRoot, moduleName, doc, offset); + proposals = processNondottedCompletion(completion, interfacesDefsRoot, moduleName, doc, offset); proposals = removeDuplicatedCompletionProposal(proposals); @@ -288,7 +288,7 @@ private ArrayList processDottedCompletion(String comple continue; if (def.type == Def.Type.Module) { - proposals.addAll(processDottedCompletionSuffix(suffix, def, interfacesDefsRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef(suffix, def, interfacesDefsRoot, document, offset)); } else if (def.type == Def.Type.ModuleAlias) { String aliasedName = def.children.get(0).name; @@ -339,7 +339,7 @@ else if (def.type == Def.Type.ModuleAlias) { */ for (Def def: interfacesDefsRoot.children) { if (def.name.equals(prefix)) - proposals.addAll(processDottedCompletionSuffix(suffix, def, interfacesDefsRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef(suffix, def, interfacesDefsRoot, document, offset)); } } @@ -356,8 +356,99 @@ else if (def.type == Def.Type.ModuleAlias) { return proposals; } - // process the completion suffix after 'dot' symbol - private ArrayList processDottedCompletionSuffix(String completion, + + private ArrayList processNondottedCompletion(String completion, + Def interfacesDefsRoot, + String moduleName, + IDocument document, + int offset) { + + ArrayList proposals = new ArrayList(); + + if (interfacesDefsRoot == null) + return proposals; + + /* + * look in def root + */ + for (Def def: interfacesDefsRoot.children) { + if (def.name.startsWith(completion)) { + Def proposedDef = createProposalDef(project, def); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } + } + + /* + * looked in current module + */ + Def currentDef = null; + for (Def def: interfacesDefsRoot.children) { + if (def.name.equals(moduleName)) { + currentDef = def; + break; + } + } + + if (currentDef != null) { + // look down from top of current module + final Def nearestDef = findSmallestDefAtOffset(currentDef, offset, document); + proposals.addAll(bottomUpFindProposals(completion, nearestDef, offset)); + + for (Def def: currentDef.children) { + if (def.name.startsWith(completion)) { + Def proposedDef = createProposalDef(project, def); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } + } + + /* + * look in opened module of current module + */ + for (Def def : currentDef.children) { + if (def.type != Def.Type.Open && def.type != Def.Type.Include) + continue; + + for (Def idef: interfacesDefsRoot.children) { + if (!idef.name.equals(def.name)) + continue; + + proposals.addAll(lookupProposalsCompletionInDef(completion, idef, interfacesDefsRoot, document, offset)); + +// for (Def d: idef.children) { +// if (d == null || d.name == null) +// break; +// +// if (d.name.startsWith(completion) && isCompletionDef(d)) { +// Def proposedDef = createProposalDef(project, d); +// proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); +// } +// } + } + } + } + + /* + * look in Pervasives module, which is always opended + */ + for (Def def: interfacesDefsRoot.children) { + if (!def.name.equals("Pervasives")) + continue; + + for (Def d: def.children) { + if (d == null || d.name == null) + break; + + if (d.name.startsWith(completion) && isCompletionDef(d)) { + Def proposedDef = createProposalDef(project, d); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + } + } + } + + return proposals; + } + + private ArrayList lookupProposalsCompletionInDef(String completion, Def defsRoot, Def interfacesDefRoot, IDocument document, @@ -388,7 +479,7 @@ private ArrayList processDottedCompletionSuffix(String // look inside def roots first for (Def def: defsRoot.children) { if (def.name.equals(prefix)) - proposals.addAll(processDottedCompletionSuffix(suffix, def, interfacesDefRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef(suffix, def, interfacesDefRoot, document, offset)); } // look inside included module @@ -399,7 +490,7 @@ private ArrayList processDottedCompletionSuffix(String for (Def def2: defsRoot.children) { if (def2.name.equals(includedDef.name)) { Def includedDefRoot = def2; - proposals.addAll(processDottedCompletionSuffix(completion, includedDefRoot, interfacesDefRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef(completion, includedDefRoot, interfacesDefRoot, document, offset)); } } @@ -407,7 +498,7 @@ private ArrayList processDottedCompletionSuffix(String for (Def def2: interfacesDefRoot.children) { if (def2.name.equals(includedDef.name)) { Def includedDefRoot = def2; - proposals.addAll(processDottedCompletionSuffix(completion, includedDefRoot, interfacesDefRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef(completion, includedDefRoot, interfacesDefRoot, document, offset)); } } @@ -431,7 +522,7 @@ private ArrayList processDottedCompletionSuffix(String for (Def def2: defsRoot.children) { if (def2.name.equals(includedDef.name)) { Def includedDefRoot = def2; - proposals.addAll(processDottedCompletionSuffix(completion, includedDefRoot, interfacesDefRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef(completion, includedDefRoot, interfacesDefRoot, document, offset)); } } @@ -439,7 +530,7 @@ private ArrayList processDottedCompletionSuffix(String for (Def def2: interfacesDefRoot.children) { if (def2.name.equals(includedDef.name)) { Def includedDefRoot = def2; - proposals.addAll(processDottedCompletionSuffix(completion, includedDefRoot, interfacesDefRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef(completion, includedDefRoot, interfacesDefRoot, document, offset)); } } @@ -451,99 +542,6 @@ private ArrayList processDottedCompletionSuffix(String return proposals; } - private ArrayList processNondottedCompletion(String completion, - Def defsRoot, - String moduleName, - IDocument document, - int offset) { - - ArrayList proposals = new ArrayList(); - - if (defsRoot == null) - return proposals; - - /* - * look in def root - */ - for (Def def: defsRoot.children) { - if (def.name.startsWith(completion)) { - Def proposedDef = createProposalDef(project, def); - proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); - } - } - - /* - * looked in current module - */ - Def currentDef = null; - for (Def def: defsRoot.children) { - if (def.name.equals(moduleName)) { - currentDef = def; - break; - } - } - - if (currentDef != null) { - // look down from top of current module - final Def nearestDef = findSmallestDefAtOffset(currentDef, offset, document); - proposals.addAll(bottomUpFindProposals(completion, nearestDef, offset)); - - for (Def def: currentDef.children) { - if (def.name.startsWith(completion)) { - Def proposedDef = createProposalDef(project, def); - proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); - } - } - - /* - * look in opened module of current module - */ - for (Def def : currentDef.children) { - if (def.type != Def.Type.Open && def.type != Def.Type.Include) - continue; - - for (Def idef: defsRoot.children) { - if (idef == null || idef.name == null) - break; - - if (!idef.name.equals(def.name)) - continue; - - for (Def d: idef.children) { - if (d == null || d.name == null) - break; - - if (d.name.startsWith(completion) && isCompletionDef(d)) { - Def proposedDef = createProposalDef(project, d); - proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); - } - } - } - } - } - - /* - * look in Pervasives module, which is always opended - */ - for (Def def: defsRoot.children) { - if (!def.name.equals("Pervasives")) - continue; - - for (Def d: def.children) { - if (d == null || d.name == null) - break; - - if (d.name.startsWith(completion) && isCompletionDef(d)) { - Def proposedDef = createProposalDef(project, d); - proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); - } - } - } - - return proposals; - } - - private ArrayList bottomUpFindProposals(String completion, Def node, int offset) { ArrayList proposals = new ArrayList(); From dc76b8ce8f9d0231f003e0d03a20cc15d39510ce Mon Sep 17 00:00:00 2001 From: trungtq Date: Sat, 11 Oct 2014 23:02:10 +0800 Subject: [PATCH 056/127] minor changes --- .../CancelCompileAllProjectsAction.java | 34 ++++++++++++++++-- .../editor/actions/CleanProjectAction.java | 1 + .../editor/actions/CompileProjectAction.java | 1 + .../CancelCompileProjectPopupAction.java | 35 +++++++++++++++++-- .../actions/CleanProjectPopupAction.java | 2 +- .../actions/CompileProjectPopupAction.java | 1 + 6 files changed, 69 insertions(+), 5 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java b/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java index 16b3216..72b035b 100644 --- a/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java +++ b/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java @@ -13,6 +13,8 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; @@ -54,11 +56,13 @@ public void run(IAction action) { @Override protected IStatus run(IProgressMonitor monitor) { if (!OcamlPlugin.ActiveBuildJobs.isEmpty()) { - Misc.appendToOcamlConsole("Cancelled all compiling jobs..."); + Misc.appendToOcamlConsole(""); + Misc.appendToOcamlConsole("Cancelling all compiling jobs..."); Collection monitors = OcamlPlugin.ActiveBuildJobs.values(); for (IProgressMonitor m: monitors) { m.setCanceled(true); } + Misc.appendToOcamlConsole("Cancellation finished!"); } return Status.OK_STATUS; } @@ -69,7 +73,33 @@ protected IStatus run(IProgressMonitor monitor) { job.setPriority(Job.BUILD); job.setUser(action != null); - job.schedule(500); + job.schedule(50); + job.addJobChangeListener(new IJobChangeListener() { + + @Override + public void sleeping(IJobChangeEvent event) { + } + + @Override + public void scheduled(IJobChangeEvent event) { + } + + @Override + public void running(IJobChangeEvent event) { + } + + @Override + public void done(IJobChangeEvent event) { + } + + @Override + public void awake(IJobChangeEvent event) { + } + + @Override + public void aboutToRun(IJobChangeEvent event) { + } + }); }else OcamlPlugin.logError("ContentAssistAction: editorPart is null"); diff --git a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java index ae55fdb..bc1a447 100644 --- a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java +++ b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java @@ -64,6 +64,7 @@ public void run(IAction action) { Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { + Misc.appendToOcamlConsole(""); // save progress monitor for later use OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); OcamlMakefileBuilder builder = new OcamlMakefileBuilder(); diff --git a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java index fd95c92..56f0fcd 100644 --- a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java +++ b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java @@ -63,6 +63,7 @@ public void run(IAction action) { @Override protected IStatus run(IProgressMonitor monitor) { try { + Misc.appendToOcamlConsole(""); // save progress monitor for later use OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); buildProject.build(IncrementalProjectBuilder.FULL_BUILD, monitor); diff --git a/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java index c229110..5d16dc3 100644 --- a/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java @@ -14,6 +14,8 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; @@ -44,11 +46,13 @@ public void run(IAction action) { @Override protected IStatus run(IProgressMonitor monitor) { if (!OcamlPlugin.ActiveBuildJobs.isEmpty()) { - Misc.appendToOcamlConsole("Cancelled all compiling jobs..."); + Misc.appendToOcamlConsole(""); + Misc.appendToOcamlConsole("Cancelling all compiling jobs..."); Collection monitors = OcamlPlugin.ActiveBuildJobs.values(); for (IProgressMonitor m: monitors) { m.setCanceled(true); } + Misc.appendToOcamlConsole("Cancellation finished!"); } return Status.OK_STATUS; } @@ -59,7 +63,34 @@ protected IStatus run(IProgressMonitor monitor) { job.setPriority(Job.BUILD); job.setUser(action != null); - job.schedule(500); + job.schedule(50); + + job.addJobChangeListener(new IJobChangeListener() { + + @Override + public void sleeping(IJobChangeEvent event) { + } + + @Override + public void scheduled(IJobChangeEvent event) { + } + + @Override + public void running(IJobChangeEvent event) { + } + + @Override + public void done(IJobChangeEvent event) { + } + + @Override + public void awake(IJobChangeEvent event) { + } + + @Override + public void aboutToRun(IJobChangeEvent event) { + } + }); } @Override diff --git a/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java index 1f86683..d8de37f 100644 --- a/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java @@ -34,9 +34,9 @@ public void run(IAction action) { Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { + Misc.appendToOcamlConsole(""); // save progress monitor for later use OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); - OcamlMakefileBuilder builder = new OcamlMakefileBuilder(); builder.clean(project, monitor); return Status.OK_STATUS; diff --git a/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java index a624335..2ac1a87 100644 --- a/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java @@ -43,6 +43,7 @@ public void run(IAction action) { @Override protected IStatus run(IProgressMonitor monitor) { try { + Misc.appendToOcamlConsole(""); // save progress monitor for later use OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); project.build(IncrementalProjectBuilder.FULL_BUILD, monitor); From 680fbd76ab89660048f7c707f4444385d72a20a1 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sun, 12 Oct 2014 23:23:59 +0800 Subject: [PATCH 057/127] minor changes --- .../ocaml/editor/completion/OcamlCompletionProposal.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java index 08b0276..948f73b 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java @@ -112,11 +112,9 @@ public Image getImage() { public String getDisplayString() { String displayString = definition.name; - if (!definition.getBody().equals(definition.name)) { + if (definition.type == Def.Type.Let || definition.type == Def.Type.LetIn) { String newBody = Misc.beautify(Def.clean(definition.getBody())); - if (newBody.startsWith(displayString)) - displayString = newBody; - else + if (!newBody.equals(definition.name)) displayString = displayString + " - " + newBody; } From 41fb49d3be1766c981f81cdef04461ac60f72f39 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sun, 12 Oct 2014 23:27:19 +0800 Subject: [PATCH 058/127] minor changes --- .../src/ocaml/editor/completion/OcamlCompletionProposal.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java index 948f73b..15fd735 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java @@ -114,7 +114,9 @@ public String getDisplayString() { if (definition.type == Def.Type.Let || definition.type == Def.Type.LetIn) { String newBody = Misc.beautify(Def.clean(definition.getBody())); - if (!newBody.equals(definition.name)) + if (newBody.startsWith(definition.name)) + displayString = newBody; + else displayString = displayString + " - " + newBody; } From 6369ad17189e514cf9c713eb8dafb75b68dbb4a8 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 13 Oct 2014 00:40:41 +0800 Subject: [PATCH 059/127] print compiling time --- .../CancelCompileAllProjectsAction.java | 33 ++----------- .../editor/actions/CleanProjectAction.java | 46 +++++++++++++------ .../editor/actions/CompileProjectAction.java | 40 ++++++++++++---- .../CancelCompileProjectPopupAction.java | 40 ++-------------- .../actions/CleanProjectPopupAction.java | 40 +++++++++++++--- .../actions/CompileProjectPopupAction.java | 38 +++++++++++++-- 6 files changed, 140 insertions(+), 97 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java b/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java index 72b035b..9511ce6 100644 --- a/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java +++ b/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java @@ -56,13 +56,13 @@ public void run(IAction action) { @Override protected IStatus run(IProgressMonitor monitor) { if (!OcamlPlugin.ActiveBuildJobs.isEmpty()) { - Misc.appendToOcamlConsole(""); - Misc.appendToOcamlConsole("Cancelling all compiling jobs..."); + // cancel all jobs Collection monitors = OcamlPlugin.ActiveBuildJobs.values(); for (IProgressMonitor m: monitors) { m.setCanceled(true); } - Misc.appendToOcamlConsole("Cancellation finished!"); + // clear them from store + OcamlPlugin.ActiveBuildJobs.clear(); } return Status.OK_STATUS; } @@ -74,33 +74,6 @@ protected IStatus run(IProgressMonitor monitor) { job.setPriority(Job.BUILD); job.setUser(action != null); job.schedule(50); - job.addJobChangeListener(new IJobChangeListener() { - - @Override - public void sleeping(IJobChangeEvent event) { - } - - @Override - public void scheduled(IJobChangeEvent event) { - } - - @Override - public void running(IJobChangeEvent event) { - } - - @Override - public void done(IJobChangeEvent event) { - } - - @Override - public void awake(IJobChangeEvent event) { - } - - @Override - public void aboutToRun(IJobChangeEvent event) { - } - }); - }else OcamlPlugin.logError("ContentAssistAction: editorPart is null"); } else diff --git a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java index bc1a447..a1e79f5 100644 --- a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java +++ b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java @@ -1,7 +1,6 @@ package ocaml.editor.actions; -import java.util.Calendar; -import java.util.Collection; +import java.util.concurrent.TimeUnit; import ocaml.OcamlPlugin; import ocaml.build.makefile.OcamlMakefileBuilder; @@ -12,8 +11,6 @@ import ocaml.views.OcamlCompilerOutput; import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IncrementalProjectBuilder; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; @@ -21,8 +18,6 @@ import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.IAction; -import org.eclipse.jface.text.ITextOperationTarget; -import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.viewers.ISelection; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; @@ -57,16 +52,19 @@ public void run(IAction action) { return; final IProject buildProject = project; + final String jobName = "Cleaning project " + project.getName(); - String timeStamp = String.valueOf(Calendar.getInstance().getTime()); - final String jobName = "Cleaning project " + project.getName(); - + final long[] executedTime = new long[1]; + executedTime[0] = -1; + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { - Misc.appendToOcamlConsole(""); // save progress monitor for later use - OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); + OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); + + // cleaning + executedTime[0] = System.currentTimeMillis(); OcamlMakefileBuilder builder = new OcamlMakefileBuilder(); builder.clean(buildProject, monitor); return Status.OK_STATUS; @@ -97,8 +95,30 @@ public void running(IJobChangeEvent event) { @Override public void done(IJobChangeEvent event) { - // remove finished job from store - OcamlPlugin.ActiveBuildJobs.remove(jobName); + // cleaning job was cancelled + if (!OcamlPlugin.ActiveBuildJobs.containsKey(jobName)) { + Misc.appendToOcamlConsole("Cleaning was cancelled!"); + } + // cleaning job terminates normally + else { + OcamlPlugin.ActiveBuildJobs.remove(jobName); + } + + // time + long cleaningTime = -1; + if (executedTime[0] > 0) + cleaningTime = System.currentTimeMillis() - executedTime[0]; + if (cleaningTime >= 0) { + long minutes = TimeUnit.MILLISECONDS.toMinutes(cleaningTime); + long seconds = TimeUnit.MILLISECONDS.toSeconds(cleaningTime) - + TimeUnit.MINUTES.toSeconds(minutes); + String time = String.format("%d min, %d sec", minutes, seconds); + Misc.appendToOcamlConsole("Time: " + time); + } + else + Misc.appendToOcamlConsole("Time: unknown"); + + Misc.appendToOcamlConsole(""); } @Override diff --git a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java index 56f0fcd..6674369 100644 --- a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java +++ b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java @@ -1,7 +1,6 @@ package ocaml.editor.actions; -import java.util.Calendar; -import java.util.Collection; +import java.util.concurrent.TimeUnit; import ocaml.OcamlPlugin; import ocaml.editors.OcamlEditor; @@ -20,8 +19,6 @@ import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.IAction; -import org.eclipse.jface.text.ITextOperationTarget; -import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.viewers.ISelection; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; @@ -58,14 +55,19 @@ public void run(IAction action) { final IProject buildProject = project; final String jobName = "Compiling project " + project.getName(); + + final long[] executedTime = new long[1]; + executedTime[0] = -1; Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { try { - Misc.appendToOcamlConsole(""); // save progress monitor for later use - OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); + OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); + + // compile + executedTime[0] = System.currentTimeMillis(); buildProject.build(IncrementalProjectBuilder.FULL_BUILD, monitor); } catch (CoreException e) { OcamlPlugin.logError("ocaml plugin error", e); @@ -98,8 +100,30 @@ public void running(IJobChangeEvent event) { @Override public void done(IJobChangeEvent event) { - // remove finished job from store - OcamlPlugin.ActiveBuildJobs.remove(jobName); + // compiling job was cancelled + if (!OcamlPlugin.ActiveBuildJobs.containsKey(jobName)) { + Misc.appendToOcamlConsole("Compilation was cancelled!"); + } + // compiling job terminates normally + else { + OcamlPlugin.ActiveBuildJobs.remove(jobName); + } + + // time + long compilingTime = -1; + if (executedTime[0] > 0) + compilingTime = System.currentTimeMillis() - executedTime[0]; + if (compilingTime >= 0) { + long minutes = TimeUnit.MILLISECONDS.toMinutes(compilingTime); + long seconds = TimeUnit.MILLISECONDS.toSeconds(compilingTime) - + TimeUnit.MINUTES.toSeconds(minutes); + String time = String.format("%d min, %d sec", minutes, seconds); + Misc.appendToOcamlConsole("Time: " + time); + } + else + Misc.appendToOcamlConsole("Time: unknown"); + + Misc.appendToOcamlConsole(""); } @Override diff --git a/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java index 5d16dc3..e7fb774 100644 --- a/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java @@ -1,16 +1,12 @@ package ocaml.popup.actions; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; import ocaml.OcamlPlugin; import ocaml.util.Misc; import ocaml.views.OcamlCompilerOutput; import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IncrementalProjectBuilder; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; @@ -19,7 +15,6 @@ import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.ui.IObjectActionDelegate; import org.eclipse.ui.IWorkbenchPart; @@ -41,18 +36,18 @@ public static void cancelCompileProject(IProject project) { @Override public void run(IAction action) { final String jobName = "Cancelling compiling jobs"; - + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { if (!OcamlPlugin.ActiveBuildJobs.isEmpty()) { - Misc.appendToOcamlConsole(""); - Misc.appendToOcamlConsole("Cancelling all compiling jobs..."); + // cancel all jobs Collection monitors = OcamlPlugin.ActiveBuildJobs.values(); for (IProgressMonitor m: monitors) { m.setCanceled(true); } - Misc.appendToOcamlConsole("Cancellation finished!"); + // clear them from store + OcamlPlugin.ActiveBuildJobs.clear(); } return Status.OK_STATUS; } @@ -64,33 +59,6 @@ protected IStatus run(IProgressMonitor monitor) { job.setPriority(Job.BUILD); job.setUser(action != null); job.schedule(50); - - job.addJobChangeListener(new IJobChangeListener() { - - @Override - public void sleeping(IJobChangeEvent event) { - } - - @Override - public void scheduled(IJobChangeEvent event) { - } - - @Override - public void running(IJobChangeEvent event) { - } - - @Override - public void done(IJobChangeEvent event) { - } - - @Override - public void awake(IJobChangeEvent event) { - } - - @Override - public void aboutToRun(IJobChangeEvent event) { - } - }); } @Override diff --git a/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java index d8de37f..f2defa6 100644 --- a/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java @@ -1,13 +1,13 @@ package ocaml.popup.actions; +import java.util.concurrent.TimeUnit; + import ocaml.OcamlPlugin; import ocaml.build.makefile.OcamlMakefileBuilder; import ocaml.util.Misc; import ocaml.views.OcamlCompilerOutput; import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IncrementalProjectBuilder; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; @@ -31,12 +31,18 @@ public CleanProjectPopupAction() { public void run(IAction action) { if (project != null) { final String jobName = "Cleaning project " + project.getName(); + + final long[] executedTime = new long[1]; + executedTime[0] = -1; + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { - Misc.appendToOcamlConsole(""); // save progress monitor for later use - OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); + OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); + + // cleaning + executedTime[0] = System.currentTimeMillis(); OcamlMakefileBuilder builder = new OcamlMakefileBuilder(); builder.clean(project, monitor); return Status.OK_STATUS; @@ -67,8 +73,30 @@ public void running(IJobChangeEvent event) { @Override public void done(IJobChangeEvent event) { - // remove finished job from store - OcamlPlugin.ActiveBuildJobs.remove(jobName); + // cleaning job was cancelled + if (!OcamlPlugin.ActiveBuildJobs.containsKey(jobName)) { + Misc.appendToOcamlConsole("Cleaning was cancelled!"); + } + // cleaning job terminates normally + else { + OcamlPlugin.ActiveBuildJobs.remove(jobName); + } + + // time + long cleaningTime = -1; + if (executedTime[0] > 0) + cleaningTime = System.currentTimeMillis() - executedTime[0]; + if (cleaningTime >= 0) { + long minutes = TimeUnit.MILLISECONDS.toMinutes(cleaningTime); + long seconds = TimeUnit.MILLISECONDS.toSeconds(cleaningTime) - + TimeUnit.MINUTES.toSeconds(minutes); + String time = String.format("%d min, %d sec", minutes, seconds); + Misc.appendToOcamlConsole("Time: " + time); + } + else + Misc.appendToOcamlConsole("Time: unknown"); + + Misc.appendToOcamlConsole(""); } @Override diff --git a/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java index 2ac1a87..be3dcad 100644 --- a/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java @@ -1,5 +1,7 @@ package ocaml.popup.actions; +import java.util.concurrent.TimeUnit; + import ocaml.OcamlPlugin; import ocaml.util.Misc; import ocaml.views.OcamlCompilerOutput; @@ -38,14 +40,20 @@ public static void compileProject(IProject project) { public void run(IAction action) { if (project != null) { + final long[] executedTime = new long[1]; + executedTime[0] = -1; + final String jobName = "Compiling project " + project.getName(); + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { try { - Misc.appendToOcamlConsole(""); // save progress monitor for later use - OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); + OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); + + // compile + executedTime[0] = System.currentTimeMillis(); project.build(IncrementalProjectBuilder.FULL_BUILD, monitor); } catch (CoreException e) { OcamlPlugin.logError("ocaml plugin error", e); @@ -78,8 +86,30 @@ public void running(IJobChangeEvent event) { @Override public void done(IJobChangeEvent event) { - // remove finished job from store - OcamlPlugin.ActiveBuildJobs.remove(jobName); + // compiling job was cancelled + if (!OcamlPlugin.ActiveBuildJobs.containsKey(jobName)) { + Misc.appendToOcamlConsole("Compilation was cancelled!"); + } + // compiling job terminates normally + else { + OcamlPlugin.ActiveBuildJobs.remove(jobName); + } + + // time + long compilingTime = -1; + if (executedTime[0] > 0) + compilingTime = System.currentTimeMillis() - executedTime[0]; + if (compilingTime >= 0) { + long minutes = TimeUnit.MILLISECONDS.toMinutes(compilingTime); + long seconds = TimeUnit.MILLISECONDS.toSeconds(compilingTime) - + TimeUnit.MINUTES.toSeconds(minutes); + String time = String.format("%d min, %d sec", minutes, seconds); + Misc.appendToOcamlConsole("Time: " + time); + } + else + Misc.appendToOcamlConsole("Time: unknown"); + + Misc.appendToOcamlConsole(""); } @Override From 8c638453625afed9b55a57c3a3a6c55d1a11cb27 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 13 Oct 2014 02:26:04 +0800 Subject: [PATCH 060/127] some changes --- Ocaml/src/ocaml/editor/actions/CleanProjectAction.java | 10 +++++++++- .../src/ocaml/editor/actions/CompileProjectAction.java | 10 +++++++++- .../ocaml/popup/actions/CleanProjectPopupAction.java | 10 +++++++++- .../ocaml/popup/actions/CompileProjectPopupAction.java | 10 +++++++++- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java index a1e79f5..8775970 100644 --- a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java +++ b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java @@ -112,7 +112,15 @@ public void done(IJobChangeEvent event) { long minutes = TimeUnit.MILLISECONDS.toMinutes(cleaningTime); long seconds = TimeUnit.MILLISECONDS.toSeconds(cleaningTime) - TimeUnit.MINUTES.toSeconds(minutes); - String time = String.format("%d min, %d sec", minutes, seconds); + String time = ""; + if (minutes > 1) + time = time + String.valueOf(minutes) + " mins"; + else + time = time + String.valueOf(minutes) + " min"; + if (seconds > 1) + time = time + ", " + String.valueOf(seconds) + " secs"; + else + time = time + ", " + String.valueOf(seconds) + " sec"; Misc.appendToOcamlConsole("Time: " + time); } else diff --git a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java index 6674369..e75b543 100644 --- a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java +++ b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java @@ -117,7 +117,15 @@ public void done(IJobChangeEvent event) { long minutes = TimeUnit.MILLISECONDS.toMinutes(compilingTime); long seconds = TimeUnit.MILLISECONDS.toSeconds(compilingTime) - TimeUnit.MINUTES.toSeconds(minutes); - String time = String.format("%d min, %d sec", minutes, seconds); + String time = ""; + if (minutes > 1) + time = time + String.valueOf(minutes) + " mins"; + else + time = time + String.valueOf(minutes) + " min"; + if (seconds > 1) + time = time + ", " + String.valueOf(seconds) + " secs"; + else + time = time + ", " + String.valueOf(seconds) + " sec"; Misc.appendToOcamlConsole("Time: " + time); } else diff --git a/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java index f2defa6..023404c 100644 --- a/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java @@ -90,7 +90,15 @@ public void done(IJobChangeEvent event) { long minutes = TimeUnit.MILLISECONDS.toMinutes(cleaningTime); long seconds = TimeUnit.MILLISECONDS.toSeconds(cleaningTime) - TimeUnit.MINUTES.toSeconds(minutes); - String time = String.format("%d min, %d sec", minutes, seconds); + String time = ""; + if (minutes > 1) + time = time + String.valueOf(minutes) + " mins"; + else + time = time + String.valueOf(minutes) + " min"; + if (seconds > 1) + time = time + ", " + String.valueOf(seconds) + " secs"; + else + time = time + ", " + String.valueOf(seconds) + " sec"; Misc.appendToOcamlConsole("Time: " + time); } else diff --git a/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java index be3dcad..cc79d4e 100644 --- a/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java @@ -103,7 +103,15 @@ public void done(IJobChangeEvent event) { long minutes = TimeUnit.MILLISECONDS.toMinutes(compilingTime); long seconds = TimeUnit.MILLISECONDS.toSeconds(compilingTime) - TimeUnit.MINUTES.toSeconds(minutes); - String time = String.format("%d min, %d sec", minutes, seconds); + String time = ""; + if (minutes > 1) + time = time + String.valueOf(minutes) + " mins"; + else + time = time + String.valueOf(minutes) + " min"; + if (seconds > 1) + time = time + ", " + String.valueOf(seconds) + " secs"; + else + time = time + ", " + String.valueOf(seconds) + " sec"; Misc.appendToOcamlConsole("Time: " + time); } else From 7c8f35310bb319310775eb1d79d5102c50c9217b Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 13 Oct 2014 02:26:22 +0800 Subject: [PATCH 061/127] improve going to definition --- .../completion/OcamlCompletionProcessor.java | 42 +++++++++++++++---- .../ocaml/editors/OcamlHyperlinkDetector.java | 41 ++++++++++-------- 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 7ee3a01..69a58c2 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -307,12 +307,26 @@ else if (def.type == Def.Type.ModuleAlias) { for (Def def1 : currentDef.children) { if (def1.type == Def.Type.Open || def1.type == Def.Type.Include) { Def involvedDef = def1; + String involvedModuleName = ""; + String newCompletion = ""; + // opened module is like A.B.C + if (involvedDef.name.contains(".")) { + index = involvedDef.name.indexOf("."); + involvedModuleName = involvedDef.name.substring(0, index); + String subModuleName = involvedDef.name.substring(index + 1); + newCompletion = subModuleName + "." + completion; + } + else { + involvedModuleName = involvedDef.name; + newCompletion = completion; + } + // search in current module first for (Def def2: currentDef.children) { - if (def2.name.equals(involvedDef.name)) { + if (def2.name.equals(involvedModuleName)) { Def involvedDefRoot = def2; for (Def def3: involvedDefRoot.children) { - if (def3.name.startsWith(completion) && isCompletionDef(def3)) { + if (def3.name.startsWith(newCompletion) && isCompletionDef(def3)) { Def proposedDef = createProposalDef(project, def3); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } @@ -320,10 +334,10 @@ else if (def.type == Def.Type.ModuleAlias) { } } for (Def def2: interfacesDefsRoot.children) { - if (def2.name.equals(involvedDef.name)) { + if (def2.name.equals(involvedModuleName)) { Def involvedDefRoot = def2; for (Def def3: involvedDefRoot.children) { - if (def3.name.startsWith(completion) && isCompletionDef(def3)) { + if (def3.name.startsWith(newCompletion) && isCompletionDef(def3)) { Def proposedDef = createProposalDef(project, def3); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } @@ -407,12 +421,26 @@ private ArrayList processNondottedCompletion(String com for (Def def : currentDef.children) { if (def.type != Def.Type.Open && def.type != Def.Type.Include) continue; - + + String openedModuleName = ""; + String newCompletion = ""; + // opened module is like A.B.C + if (def.name.contains(".")) { + int index = def.name.indexOf("."); + openedModuleName = def.name.substring(0, index); + String subModuleName = def.name.substring(index + 1); + newCompletion = subModuleName + "." + completion; + } + else { + openedModuleName = def.name; + newCompletion = completion; + } + for (Def idef: interfacesDefsRoot.children) { - if (!idef.name.equals(def.name)) + if (!idef.name.equals(openedModuleName)) continue; - proposals.addAll(lookupProposalsCompletionInDef(completion, idef, interfacesDefsRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef(newCompletion, idef, interfacesDefsRoot, document, offset)); // for (Def d: idef.children) { // if (d == null || d.name == null) diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index d5ff661..403691f 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -203,10 +203,11 @@ private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitions * if this is a compound name "A.B.c", then we extract the first component to know what * module to look for, and then we get the definition by entering the module */ + StringBuilder fullDefName = new StringBuilder(searchedDef.name); if (searchedDef.name.indexOf('.') != -1) { String[] parts = searchedDef.name.split("\\."); if (parts.length > 1) { - Def firstPart = lookForDefinitionUp(null, parts[0], searchedDef, interfacesDefinitionsRoot, parts, true); + Def firstPart = lookForDefinitionUp(null, parts[0], searchedDef, interfacesDefinitionsRoot, fullDefName, true); // don't find it in the current module, look in the other ones if (firstPart == null) { if (openDefInInterfaces(0, parts, interfacesDefinitionsRoot)) @@ -224,7 +225,7 @@ private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitions searchedDef2.name = parts[0]; for (int i = 1; i < parts.length; i++) searchedDef2.name = "." + searchedDef2.name; - firstPart = lookForDefinitionUp(null, parts[0], searchedDef2, interfacesDefinitionsRoot, parts, true); + firstPart = lookForDefinitionUp(null, parts[0], searchedDef2, interfacesDefinitionsRoot, fullDefName, true); } else break; } @@ -247,7 +248,7 @@ private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitions } else { def = lookForDefinitionUp(searchedDef, searchedDef.name, searchedDef, - interfacesDefinitionsRoot, new String[] { searchedDef.name }, true); + interfacesDefinitionsRoot, fullDefName, true); // if we didn't find it, look in Pervasives (which is always opened by default) if (def == null) { @@ -329,8 +330,14 @@ private Def findDefinitionOf(final String strDef, } } if (!moduleName.equals(path[0])) { - String[] aliasedPath = path.clone(); - aliasedPath[0] = moduleName; +// String[] aliasedPath = path.clone(); +// aliasedPath[0] = moduleName; + + String newFullDefName = moduleName; + for (String s: path) + newFullDefName = newFullDefName + "." + s; + String[] aliasedPath = newFullDefName.split("\\."); + if (openDefInInterfaces(0, aliasedPath, interfacesDefinitionsRoot)) return null; } @@ -376,20 +383,20 @@ private Def findDefFromPath(int index, String[] path, Def def, Def lastPartFound * the node from which to start * @param interfacesDefinitionsRoot * the root of the interfaces definitions tree - * @param fullpath + * @param fullDefName * the full path of the searched definition (used to look for it in other modules) * @param otherBranch * are we in another branch relative to the definition from which we started? (this * is used to manage the non-rec definitions) */ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, - Def interfacesDefinitionsRoot, String[] fullpath, boolean otherBranch) { + Def interfacesDefinitionsRoot, StringBuilder fullDefName, boolean otherBranch) { Def test = null; if (node.type == Def.Type.In) { /* If this is an 'in' node (in a 'let in'), go directly to the parent */ return lookForDefinitionUp(searchedNode, name, node.parent, interfacesDefinitionsRoot, - fullpath, false); + fullDefName, false); } // is it this node? @@ -399,9 +406,8 @@ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, // if it is an "open" node, look inside the interface of this module if (node.type == Def.Type.Open || node.type == Def.Type.Include) { - String[] path = new String[fullpath.length + 1]; - System.arraycopy(fullpath, 0, path, 1, fullpath.length); - path[0] = node.name; + String newFullDefName = node.name + "." + fullDefName.toString(); + String[] path = newFullDefName.split("\\."); if (openDefInInterfaces(0, path, interfacesDefinitionsRoot)) return null; @@ -428,8 +434,10 @@ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, } } // rectify full path in case of there exist aliased module - if (!moduleName.equals(name)) - fullpath[0] = moduleName; + if (!moduleName.equals(name)) { + fullDefName.delete(0, name.length() - 1); + fullDefName.insert(0, moduleName); + } return null; } @@ -459,9 +467,8 @@ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, // if it is an "open" node, look inside the interface of this module if (before.type == Def.Type.Open || before.type == Def.Type.Include) { - String[] path = new String[fullpath.length + 1]; - System.arraycopy(fullpath, 0, path, 1, fullpath.length); - path[0] = before.name; + String newFullDefName = before.name + "." + fullDefName.toString(); + String[] path = newFullDefName.split("\\."); if (openDefInInterfaces(0, path, interfacesDefinitionsRoot)) return null; @@ -474,7 +481,7 @@ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, /* Now, go one step up */ return lookForDefinitionUp(searchedNode, name, node.parent, interfacesDefinitionsRoot, - fullpath, false); + fullDefName, false); } /** From b5b5142611c8d9d5bb64d649fd2dcdffd3761008 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 13 Oct 2014 12:33:39 +0800 Subject: [PATCH 062/127] some changes --- Ocaml/src/ocaml/parser/Def.java | 19 ++++--------------- .../parsers/OcamlNewInterfaceParser.java | 19 +++++-------------- 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index d8a77e4..94f1571 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -118,25 +118,14 @@ public Def() { public Def(String name, Type type, int start, int end) { super(); children = new ArrayList(); - this.name = name; - this.type = type; - this.posStart = start; - this.posEnd = end; - this.defPosStart = 0; - // this.defPosEnd = 0; - } - - /** Create a definition node: let, type,... */ - public Def(String name, Type type, int start, int end, int offsetStart, int offsetEnd) { - super(); - children = new ArrayList(); - this.name = name; + if (name != null) + this.name = name; + else + this.name = ""; this.type = type; this.posStart = start; this.posEnd = end; this.defPosStart = 0; - this.defOffsetStart = offsetStart; - this.defOffsetEnd = offsetEnd; // this.defPosEnd = 0; } diff --git a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java index 5a02597..aec53be 100644 --- a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java +++ b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java @@ -199,11 +199,8 @@ protected IStatus run(IProgressMonitor monitor) { if (!"".equals(errors)) { Def def = new Def(moduleName, Def.Type.ParserError, 0, 0); def.setFileName(filename); - - def - .setComment("ERROR: The camlp4 preprocessor encountered an error " + def.setComment("ERROR: The camlp4 preprocessor encountered an error " + "while parsing this file:\n" + errors); - cache.addFirst(new CachedDef(file, def)); return def; } @@ -218,17 +215,12 @@ protected IStatus run(IProgressMonitor monitor) { // System.err.println("parsing:" + filename); definition = parseModule(lines, filename, moduleName, bInterface); } catch (Throwable e) { - // if there was a parsing error, we log it and we continue on to the - // next file - // OcamlPlugin.logError("Error parsing '" + moduleName + "'", e); + // if there was a parsing error, we log it and we continue on to the next file + // e.printStackTrace(); Def def = new Def(moduleName, Def.Type.ParserError, 0, 0); def.setFileName(filename); - - def.setComment("ERROR: The parser encountered an error while parsing this file.\n\n" + def.setComment("ERROR 2: The parser encountered an error while parsing this file.\n\n" + "Please make sure that it is syntactically correct.\n\n"); - - // System.err.println("ERROR:" + filename); - cache.addFirst(new CachedDef(file, def)); return def; } @@ -327,8 +319,7 @@ private Def parseModule(String doc, String filename, String moduleName, if (parser.errorReporting.errors.size() != 0) { root.type = Def.Type.ParserError; - root - .setComment("ERROR: The parser encountered an error while parsing this file.\n\n" + root.setComment("ERROR 1: The parser encountered an error while parsing this file.\n\n" + "Please make sure that it is syntactically correct.\n\n"); } else root.type = Def.Type.Module; From bf400a4c32366af7935ce4faf2e83e38c0b29378 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 13 Oct 2014 14:21:18 +0800 Subject: [PATCH 063/127] minor changes --- .../ocaml/editors/OcamlHyperlinkDetector.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index 403691f..a48588a 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -208,6 +208,8 @@ private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitions String[] parts = searchedDef.name.split("\\."); if (parts.length > 1) { Def firstPart = lookForDefinitionUp(null, parts[0], searchedDef, interfacesDefinitionsRoot, fullDefName, true); + // since fullDefName is updated, we need to updata parts variable + parts = fullDefName.toString().split("\\."); // don't find it in the current module, look in the other ones if (firstPart == null) { if (openDefInInterfaces(0, parts, interfacesDefinitionsRoot)) @@ -276,12 +278,16 @@ private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitions private Def findDefinitionOf(final String strDef, final Def modulesDefinitionsRoot, final Def interfacesDefinitionsRoot) { - // use direct name + /* + * use direct name + */ String[] directPath = strDef.split("\\."); if (openDefInInterfaces(0, directPath, interfacesDefinitionsRoot)) return null; - // look in current module + /* + * look in current module + */ Def def = modulesDefinitionsRoot; for (int index = 0; index < directPath.length; index++) { boolean stop = true; @@ -300,7 +306,9 @@ private Def findDefinitionOf(final String strDef, break; } - // lookup in opened module + /* + * lookup in opened module + */ for (Def d : modulesDefinitionsRoot.children) { if (d.type == Def.Type.Open) { String fullStrDef = d.name + "." + strDef; @@ -310,7 +318,9 @@ private Def findDefinitionOf(final String strDef, } } - // lookup in aliased module + /* + * lookup in module nam or possible aliased module + */ String[] path = strDef.split("\\."); String moduleName = path[0]; boolean stop = false; @@ -330,9 +340,6 @@ private Def findDefinitionOf(final String strDef, } } if (!moduleName.equals(path[0])) { -// String[] aliasedPath = path.clone(); -// aliasedPath[0] = moduleName; - String newFullDefName = moduleName; for (String s: path) newFullDefName = newFullDefName + "." + s; @@ -342,7 +349,9 @@ private Def findDefinitionOf(final String strDef, return null; } - // finally, look in Pervasives (which is always opened by default) + /* + * finally, look in Pervasives (which is always opened by default) + */ String[] pervasivesPath = ("Pervasives" + strDef).split("\\."); openDefInInterfaces(0, pervasivesPath, interfacesDefinitionsRoot); return null; @@ -435,7 +444,7 @@ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, } // rectify full path in case of there exist aliased module if (!moduleName.equals(name)) { - fullDefName.delete(0, name.length() - 1); + fullDefName.delete(0, name.length()); fullDefName.insert(0, moduleName); } From a713da4509a5518bf2ac1412868263757fe74f40 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 13 Oct 2014 15:46:24 +0800 Subject: [PATCH 064/127] Add recovery ability to parser --- .../parsers/OcamlNewInterfaceParser.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java index aec53be..6c2b39d 100644 --- a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java +++ b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java @@ -216,7 +216,7 @@ protected IStatus run(IProgressMonitor monitor) { definition = parseModule(lines, filename, moduleName, bInterface); } catch (Throwable e) { // if there was a parsing error, we log it and we continue on to the next file - // e.printStackTrace(); + e.printStackTrace(); Def def = new Def(moduleName, Def.Type.ParserError, 0, 0); def.setFileName(filename); def.setComment("ERROR 2: The parser encountered an error while parsing this file.\n\n" @@ -266,7 +266,6 @@ private void setFilenames(Def definition, String filename) { private Def parseModule(String doc, String filename, String moduleName, boolean parseInterface) throws Throwable { - /* * "Sanitize" the document by replacing extended characters, which * otherwise would crash the parser @@ -287,10 +286,24 @@ private Def parseModule(String doc, String filename, String moduleName, Def root = null; - if (parseInterface) - root = (Def) parser.parse(scanner, OcamlParser.AltGoals.interfaces); - else - root = (Def) parser.parse(scanner); + try { + if (parseInterface) + root = (Def) parser.parse(scanner, OcamlParser.AltGoals.interfaces); + else + root = (Def) parser.parse(scanner); + } catch (Exception e) { + // recover pieces from the AST (which couldn't be built completely + // because of an unrecoverable error) + if (root == null || !parser.errorReporting.errors.isEmpty()) { + root = new Def(moduleName, Def.Type.Module, 0, 0); + for (Def def : parser.recoverDefs) + if (def.bTop && def.name != null && !"".equals(def.name.trim())) { + def.bTop = false; + root.children.add(def); + } + } + } + root = root.cleanCopy(); From 78882c1816d4b84ec4c9254363c444707864e8e4 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 13 Oct 2014 16:38:18 +0800 Subject: [PATCH 065/127] minor changes --- Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index a48588a..2018b7a 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -340,9 +340,9 @@ private Def findDefinitionOf(final String strDef, } } if (!moduleName.equals(path[0])) { - String newFullDefName = moduleName; - for (String s: path) - newFullDefName = newFullDefName + "." + s; + String newFullDefName = moduleName; + for (int i = 1; i < path.length; i++) + newFullDefName = newFullDefName + "." + path[i]; String[] aliasedPath = newFullDefName.split("\\."); if (openDefInInterfaces(0, aliasedPath, interfacesDefinitionsRoot)) From 6e637af2826b58940f08c1b69281c36356f43499 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 13 Oct 2014 23:26:51 +0800 Subject: [PATCH 066/127] fix bug: new navigation shortcuts doesn't work after starting to compile --- .../ocaml/editor/actions/CancelCompileAllProjectsAction.java | 3 --- Ocaml/src/ocaml/editor/actions/CleanProjectAction.java | 3 --- Ocaml/src/ocaml/editor/actions/CompileProjectAction.java | 3 --- .../ocaml/popup/actions/CancelCompileProjectPopupAction.java | 3 --- Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java | 3 --- Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java | 3 --- Ocaml/src/ocaml/popup/actions/GenDocAction.java | 3 --- 7 files changed, 21 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java b/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java index 9511ce6..6671c35 100644 --- a/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java +++ b/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java @@ -68,9 +68,6 @@ protected IStatus run(IProgressMonitor monitor) { } }; - // open the "OCaml compiler output" view to show the output of the make - Misc.showView(OcamlCompilerOutput.ID); - job.setPriority(Job.BUILD); job.setUser(action != null); job.schedule(50); diff --git a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java index 8775970..76040db 100644 --- a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java +++ b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java @@ -71,9 +71,6 @@ protected IStatus run(IProgressMonitor monitor) { } }; - // open the "OCaml compiler output" view to show the output of the make - Misc.showView(OcamlCompilerOutput.ID); - job.setPriority(Job.BUILD); /* * If the action is directly called by the user, then we display a dialog box. Else, the launch is silent. diff --git a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java index e75b543..29e6898 100644 --- a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java +++ b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java @@ -76,9 +76,6 @@ protected IStatus run(IProgressMonitor monitor) { } }; - // open the "OCaml compiler output" view to show the output of the make - Misc.showView(OcamlCompilerOutput.ID); - job.setPriority(Job.BUILD); /* * If the action is directly called by the user, then we display a dialog box. Else, the launch is silent. diff --git a/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java index e7fb774..70928aa 100644 --- a/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java @@ -53,9 +53,6 @@ protected IStatus run(IProgressMonitor monitor) { } }; - // open the "OCaml compiler output" view to show the output of the make - Misc.showView(OcamlCompilerOutput.ID); - job.setPriority(Job.BUILD); job.setUser(action != null); job.schedule(50); diff --git a/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java index 023404c..5f888e2 100644 --- a/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java @@ -49,9 +49,6 @@ protected IStatus run(IProgressMonitor monitor) { } }; - // open the "OCaml compiler output" view to show the output of the make - Misc.showView(OcamlCompilerOutput.ID); - job.setPriority(Job.BUILD); /* * If the action is directly called by the user, then we display a dialog box. Else, the launch is silent. diff --git a/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java index cc79d4e..b6a3efd 100644 --- a/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java @@ -62,9 +62,6 @@ protected IStatus run(IProgressMonitor monitor) { } }; - // open the "OCaml compiler output" view to show the output of the make - Misc.showView(OcamlCompilerOutput.ID); - job.setPriority(Job.BUILD); /* * If the action is directly called by the user, then we display a dialog box. Else, the launch is silent. diff --git a/Ocaml/src/ocaml/popup/actions/GenDocAction.java b/Ocaml/src/ocaml/popup/actions/GenDocAction.java index 035702a..b3169f9 100644 --- a/Ocaml/src/ocaml/popup/actions/GenDocAction.java +++ b/Ocaml/src/ocaml/popup/actions/GenDocAction.java @@ -73,9 +73,6 @@ public void run() { } }; - // open the "OCaml compiler output" view to show the output of the make command - Misc.showView(OcamlCompilerOutput.ID); - job.setPriority(Job.BUILD); job.setUser(true); job.schedule(500); From 2fd3da022e7dabd3e216f35452b9c104b26bc163 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 14 Oct 2014 12:08:07 +0800 Subject: [PATCH 067/127] add type information in auto-completion --- .../completion/OcamlCompletionProcessor.java | 52 +++++++++---------- .../completion/OcamlCompletionProposal.java | 8 +-- Ocaml/src/ocaml/parser/Def.java | 14 ++++- 3 files changed, 42 insertions(+), 32 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 69a58c2..f011e8c 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -926,35 +926,33 @@ public String getErrorMessage() { private Def createProposalDef(IProject project, Def def) { Def newDef = new Def(def); - if (newDef.getBody().equals(newDef.name)) { - if (newDef.type == Def.Type.Let - || newDef.type == Def.Type.LetIn) { - String filename = newDef.getFileName(); - - // store last used annotation for caching - TypeAnnotation[] annotations; - long currentTime = System.currentTimeMillis(); - if (filename.equals(lastParsedFileName) - && (currentTime - lastParsedTime < cacheTime)) { - annotations = lastUsedAnnotations; - } - else { - annotations = parseModuleAnnotation(project, filename); - lastUsedAnnotations = annotations; - lastParsedFileName = filename; - lastParsedTime = System.currentTimeMillis(); - } - - IDocument document = getDocument(project, filename); - String typeInfo = computeTypeInfo(newDef, annotations, document); - if (typeInfo.isEmpty()) - typeInfo = newDef.name + " - "; - newDef.setBody(typeInfo); + if (newDef.type == Def.Type.Let + || newDef.type == Def.Type.LetIn) { + String filename = newDef.getFileName(); + + // store last used annotation for caching + TypeAnnotation[] annotations; + long currentTime = System.currentTimeMillis(); + if (filename.equals(lastParsedFileName) + && (currentTime - lastParsedTime < cacheTime)) { + annotations = lastUsedAnnotations; } - else if (def.type == Def.Type.Type) { - String newBody = newDef.name + " 't"; - newDef.setBody(newBody); + else { + annotations = parseModuleAnnotation(project, filename); + lastUsedAnnotations = annotations; + lastParsedFileName = filename; + lastParsedTime = System.currentTimeMillis(); } + + IDocument document = getDocument(project, filename); + String typeInfo = computeTypeInfo(newDef, annotations, document); + if (typeInfo.isEmpty()) + typeInfo = newDef.name + " - "; + newDef.setOcamlType(typeInfo); + } + else if (def.type == Def.Type.Type) { + String typeInfo = newDef.name + " 't"; + newDef.setOcamlType(typeInfo); } // Trung: uncomment to debug def type // newDef.setBody(newDef.getBody() + " -- def type: " + newDef.getTypeName()); diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java index 15fd735..53fd99c 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java @@ -113,11 +113,11 @@ public String getDisplayString() { String displayString = definition.name; if (definition.type == Def.Type.Let || definition.type == Def.Type.LetIn) { - String newBody = Misc.beautify(Def.clean(definition.getBody())); - if (newBody.startsWith(definition.name)) - displayString = newBody; + String typeInfo = Misc.beautify(Def.clean(definition.getOcamlType())); + if (typeInfo.startsWith(definition.name)) + displayString = typeInfo; else - displayString = displayString + " - " + newBody; + displayString = displayString + " - " + typeInfo; } return displayString; diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index 94f1571..d6b6fef 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -72,7 +72,17 @@ public enum Type { * The type inferred by the OCaml compiler for this definition (this is retrieved and displayed * in the outline when a ".annot" file is present and up-to-date) */ - public String ocamlType; + private String ocamlType; + + public String getOcamlType() { + return ocamlType; + } + + public void setOcamlType(String type) { + if (type == null) + this.ocamlType = ""; + else this.ocamlType = type; + } /** The parent of this node. This is required by the outline's ContentProvider */ public Def parent; @@ -111,6 +121,7 @@ public Def() { this.posStart = 0; this.posEnd = 0; this.defPosStart = 0; + this.ocamlType = ""; // this.defPosEnd = 0; } @@ -126,6 +137,7 @@ public Def(String name, Type type, int start, int end) { this.posStart = start; this.posEnd = end; this.defPosStart = 0; + this.ocamlType = ""; // this.defPosEnd = 0; } From 099f1ca4d4b45ae3c4fd98cbe05d1786e035b744 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 14 Oct 2014 12:08:43 +0800 Subject: [PATCH 068/127] allow search type information in outline --- .../outline/OcamlOutlineLabelProvider.java | 4 ++-- Ocaml/src/ocaml/views/outline/OutlineJob.java | 2 +- .../src/ocaml/views/outline/QuickOutline.java | 22 +++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Ocaml/src/ocaml/views/outline/OcamlOutlineLabelProvider.java b/Ocaml/src/ocaml/views/outline/OcamlOutlineLabelProvider.java index 14be1a7..bbdb55c 100644 --- a/Ocaml/src/ocaml/views/outline/OcamlOutlineLabelProvider.java +++ b/Ocaml/src/ocaml/views/outline/OcamlOutlineLabelProvider.java @@ -89,8 +89,8 @@ public String getText(Object element) { if (OcamlOutlineControl.bOutlineDebugButton && OcamlOutlineControl.bDebug) return def.name + " (" + def.type + ")"; - if (def.ocamlType != null && !"".equals(def.ocamlType)) - return def.name + " : " + def.ocamlType; + if (!def.getOcamlType().isEmpty()) + return def.name + " : " + def.getOcamlType(); else return def.name; } diff --git a/Ocaml/src/ocaml/views/outline/OutlineJob.java b/Ocaml/src/ocaml/views/outline/OutlineJob.java index fd7eb1c..a58095c 100644 --- a/Ocaml/src/ocaml/views/outline/OutlineJob.java +++ b/Ocaml/src/ocaml/views/outline/OutlineJob.java @@ -499,7 +499,7 @@ private void addTypeRec(TypeAnnotation[] annotations, Def def, boolean root) { if (index >= 0) { TypeAnnotation annot = annotations[index]; String type = annot.getType().replaceAll("\r?\n", " "); - def.ocamlType = type; + def.setOcamlType(type); } } diff --git a/Ocaml/src/ocaml/views/outline/QuickOutline.java b/Ocaml/src/ocaml/views/outline/QuickOutline.java index 89999cc..e09ff51 100644 --- a/Ocaml/src/ocaml/views/outline/QuickOutline.java +++ b/Ocaml/src/ocaml/views/outline/QuickOutline.java @@ -3,6 +3,7 @@ import ocaml.OcamlPlugin; import ocaml.editors.OcamlEditor; import ocaml.parser.Def; +import ocaml.util.Misc; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogSettings; @@ -327,6 +328,27 @@ private boolean matchesFilter(Object element) { Def def = (Def) element; String matchName = ((ILabelProvider) fTreeViewer.getLabelProvider()).getText(def); String filterText = getFilterText().getText(); + /* + * allow to search special characters in type information: + * In raw text: + * use "a -> b" for function type "a → b" + * use "a x b" to search a tuple type (a * b) + * use 'a, 'b, 'c,... for α, β, γ,... + */ + filterText = filterText.replaceAll("->", "\u2192"); + filterText = filterText.replaceAll(" x ", " \u00d7 "); + filterText = filterText.replaceAll("\\B'a\\b", "\u03b1"); + filterText = filterText.replaceAll("\\B'b\\b", "\u03b2"); + filterText = filterText.replaceAll("\\B'c\\b", "\u03b3"); + filterText = filterText.replaceAll("\\B'd\\b", "\u03b4"); + filterText = filterText.replaceAll("\\B'e\\b", "\u03b5"); + filterText = filterText.replaceAll("\\B'f\\b", "\u03b6"); + filterText = filterText.replaceAll("\\B'g\\b", "\u03b7"); + filterText = filterText.replaceAll("\\B'h\\b", "\u03b8"); + filterText = filterText.replaceAll("\\B'i\\b", "\u03b9"); + filterText = filterText.replaceAll("\\B'j\\b", "\u03ba"); + filterText = filterText.replaceAll("\\B'k\\b", "\u03bb"); + filterText = filterText.replaceAll("\\B'l\\b", "\u03bc"); if(matchName != null) { if(filterText.startsWith("*")) { From dd1bb50df1066673a5dc6f771f593e80cefa7325 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 14 Oct 2014 14:15:07 +0800 Subject: [PATCH 069/127] hyperlink detector and go to defintion is more precise --- .../ocaml/editors/OcamlHyperlinkDetector.java | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index 2018b7a..7590520 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -658,7 +658,7 @@ private Def findIdentAt(Def def, int offset, IDocument doc) { return null; int startOffset = region.getOffset(); - int endOffset = startOffset + region.getLength() - 1; + int endOffset = startOffset + region.getLength(); if (startOffset <= offset && endOffset >= offset) return def; @@ -681,10 +681,7 @@ private TextSelection findIdentAt(IDocument doc, int offset) { char ch; try { ch = doc.getChar(i); - if (ch == '.' || ch == '_' - || (ch >= '0' && ch <= '9') - || (ch >= 'a' && ch <= 'z') - || (ch >= 'A' && ch <= 'Z')) { + if (ch == '.' || ch == '_' || Character.isLetterOrDigit(ch)) { text = text + ch; i++; } @@ -695,19 +692,17 @@ private TextSelection findIdentAt(IDocument doc, int offset) { } i = offset - 1; - if (!text.isEmpty()) { - while (i >= 0) { - char ch; - try { - ch = doc.getChar(i); - if (ch == '.' || ch == '_' || Character.isLetterOrDigit(ch)) { - text = ch + text; - i--; - } - else break; - } catch (BadLocationException e) { - break; + while (i >= 0) { + char ch; + try { + ch = doc.getChar(i); + if (ch == '.' || ch == '_' || Character.isLetterOrDigit(ch)) { + text = ch + text; + i--; } + else break; + } catch (BadLocationException e) { + break; } } int beginOffset = (i >= 0) ? i + 1 : 0; From ce9ed6c672c27acb3d45b70db31c29fdce3fd6f1 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 14 Oct 2014 14:15:30 +0800 Subject: [PATCH 070/127] testing scripts --- plugins-install.sh | 4 ++++ plugins-prepare.sh | 3 +++ 2 files changed, 7 insertions(+) create mode 100755 plugins-install.sh create mode 100755 plugins-prepare.sh diff --git a/plugins-install.sh b/plugins-install.sh new file mode 100755 index 0000000..afc607e --- /dev/null +++ b/plugins-install.sh @@ -0,0 +1,4 @@ +#!/bin/sh +rm ~/Programs/OcaIDE/dropins/Ocaml* +cp ~/Desktop/plugins/Ocaml* ~/Programs/OcaIDE/dropins/ + diff --git a/plugins-prepare.sh b/plugins-prepare.sh new file mode 100755 index 0000000..bbec19b --- /dev/null +++ b/plugins-prepare.sh @@ -0,0 +1,3 @@ +#!/bin/sh +rm -rf ~/Desktop/plugins/ + From 84974474d8a9336a9d4d76782d6ab7d114f1ae41 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 14 Oct 2014 23:03:30 +0800 Subject: [PATCH 071/127] improve outline feature --- .../completion/OcamlCompletionProposal.java | 1 + .../completion/OcamlInformationPresenter.java | 24 ++++++++++++------- Ocaml/src/ocaml/parser/Def.java | 5 ++-- .../outline/OcamlOutlineLabelProvider.java | 2 ++ 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java index 53fd99c..bd01970 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java @@ -136,6 +136,7 @@ public String getAdditionalProposalInfo(IProgressMonitor monitor) { */ return definition.parentName + " $@| " + definition.getBody() + " $@| " + + definition.getOcamlType() + " $@| " + definition.sectionComment + " $@| " + definition.comment + " $@| " + definition.getFileName(); } diff --git a/Ocaml/src/ocaml/editor/completion/OcamlInformationPresenter.java b/Ocaml/src/ocaml/editor/completion/OcamlInformationPresenter.java index 5915c17..a1a46d6 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlInformationPresenter.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlInformationPresenter.java @@ -33,8 +33,8 @@ public String updatePresentation(Display display, String infoText, String[] infos = infoText.split("\\$\\@\\|"); // templates don't respect the same format - if (infos.length != 5) - infos = new String[] { "", "", "", infoText, "" }; + if (infos.length != 6) + infos = new String[] { "", "", "", "", infoText, "" }; // the offset in the generated text, in number of characters int offset = 0; @@ -42,19 +42,25 @@ public String updatePresentation(Display display, String infoText, // the result string StringBuilder result = new StringBuilder(); - String text; + String text = ""; String parentName = infos[0].trim(); String body = infos[1].trim(); - String sectionComment = infos[2].trim(); - String comment = infos[3].trim(); - String filename = infos[4].trim(); + String ocamlType = infos[2].trim(); + String sectionComment = infos[3].trim(); + String comment = infos[4].trim(); + String filename = infos[5].trim(); - if (!body.equals("")) { + // if there is type info, then no need to print body + if (!ocamlType.equals("")) { + text = body + "\n"; + result.append(text); + presentation.addStyleRange(new StyleRange(offset, text.length(), null, null, SWT.BOLD)); + offset += text.length(); + } + else if (!body.equals("")) { text = body + "\n"; result.append(text); - - // Color colorBody = new Color(display, 50, 150, 200); presentation.addStyleRange(new StyleRange(offset, text.length(), null, null, SWT.BOLD)); offset += text.length(); } diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index d6b6fef..f2b5b68 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -387,10 +387,11 @@ private void cleanCopyAux(Def node, Def newNode) { private void findRealChildren(Def node, ArrayList nodes, boolean root) { if (node.type == Type.Dummy || node.type == Type.Parameter - /* || node.type == Type.Identifier */ // Trung: this is to handle ModuleAlias + /* || node.type == Type.Identifier */ // Trung: this is to handle ModuleAlias || node.type == Type.Functor || node.type == Type.Sig || node.type == Type.Object || node.type == Type.Struct || node.type == Type.In || root - || "_".equals(node.name) || "()".equals(node.name)) { + /* || "_".equals(node.name) */ // Trung: this is to handle _ + || "()".equals(node.name)) { for (Def d : node.children) findRealChildren(d, nodes, false); } else { diff --git a/Ocaml/src/ocaml/views/outline/OcamlOutlineLabelProvider.java b/Ocaml/src/ocaml/views/outline/OcamlOutlineLabelProvider.java index bbdb55c..6dc849b 100644 --- a/Ocaml/src/ocaml/views/outline/OcamlOutlineLabelProvider.java +++ b/Ocaml/src/ocaml/views/outline/OcamlOutlineLabelProvider.java @@ -41,6 +41,8 @@ public static Image retrieveImage(Object element) { return ImageRepository.getImage(ImageRepository.ICON_EXTERNAL); if (type.equals(Def.Type.Module)) return ImageRepository.getImage(ImageRepository.ICON_OCAML_MODULE); + if (type.equals(Def.Type.ModuleAlias)) + return ImageRepository.getImage(ImageRepository.ICON_OCAML_MODULE); if (type.equals(Def.Type.ModuleType)) return ImageRepository.getImage(ImageRepository.ICON_OCAML_MODULE_TYPE); if (type.equals(Def.Type.Open)) From a6a5694036009dbcf52c69609badd2961f3c539e Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 14 Oct 2014 23:24:46 +0800 Subject: [PATCH 072/127] don't show identifer, paramter in quick outline --- .../src/ocaml/views/outline/QuickOutline.java | 61 ++++++++++--------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/Ocaml/src/ocaml/views/outline/QuickOutline.java b/Ocaml/src/ocaml/views/outline/QuickOutline.java index e09ff51..b2a1324 100644 --- a/Ocaml/src/ocaml/views/outline/QuickOutline.java +++ b/Ocaml/src/ocaml/views/outline/QuickOutline.java @@ -326,35 +326,38 @@ private boolean matchesFilter(Object element) { if (element instanceof Def) { Def def = (Def) element; - String matchName = ((ILabelProvider) fTreeViewer.getLabelProvider()).getText(def); - String filterText = getFilterText().getText(); - /* - * allow to search special characters in type information: - * In raw text: - * use "a -> b" for function type "a → b" - * use "a x b" to search a tuple type (a * b) - * use 'a, 'b, 'c,... for α, β, γ,... - */ - filterText = filterText.replaceAll("->", "\u2192"); - filterText = filterText.replaceAll(" x ", " \u00d7 "); - filterText = filterText.replaceAll("\\B'a\\b", "\u03b1"); - filterText = filterText.replaceAll("\\B'b\\b", "\u03b2"); - filterText = filterText.replaceAll("\\B'c\\b", "\u03b3"); - filterText = filterText.replaceAll("\\B'd\\b", "\u03b4"); - filterText = filterText.replaceAll("\\B'e\\b", "\u03b5"); - filterText = filterText.replaceAll("\\B'f\\b", "\u03b6"); - filterText = filterText.replaceAll("\\B'g\\b", "\u03b7"); - filterText = filterText.replaceAll("\\B'h\\b", "\u03b8"); - filterText = filterText.replaceAll("\\B'i\\b", "\u03b9"); - filterText = filterText.replaceAll("\\B'j\\b", "\u03ba"); - filterText = filterText.replaceAll("\\B'k\\b", "\u03bb"); - filterText = filterText.replaceAll("\\B'l\\b", "\u03bc"); - - if(matchName != null) { - if(filterText.startsWith("*")) { - return matchName.contains(filterText.substring(1)); - } else { - return matchName.startsWith(filterText); + // don't show identifier and parameter in quick outline + if (def.type != Def.Type.Parameter && def.type != Def.Type.Identifier) { + String matchName = ((ILabelProvider) fTreeViewer.getLabelProvider()).getText(def); + String filterText = getFilterText().getText(); + /* + * allow to search special characters in type information: + * In raw text: + * use "a -> b" for function type "a → b" + * use "a x b" to search a tuple type (a * b) + * use 'a, 'b, 'c,... for α, β, γ,... + */ + filterText = filterText.replaceAll("->", "\u2192"); + filterText = filterText.replaceAll(" x ", " \u00d7 "); + filterText = filterText.replaceAll("\\B'a\\b", "\u03b1"); + filterText = filterText.replaceAll("\\B'b\\b", "\u03b2"); + filterText = filterText.replaceAll("\\B'c\\b", "\u03b3"); + filterText = filterText.replaceAll("\\B'd\\b", "\u03b4"); + filterText = filterText.replaceAll("\\B'e\\b", "\u03b5"); + filterText = filterText.replaceAll("\\B'f\\b", "\u03b6"); + filterText = filterText.replaceAll("\\B'g\\b", "\u03b7"); + filterText = filterText.replaceAll("\\B'h\\b", "\u03b8"); + filterText = filterText.replaceAll("\\B'i\\b", "\u03b9"); + filterText = filterText.replaceAll("\\B'j\\b", "\u03ba"); + filterText = filterText.replaceAll("\\B'k\\b", "\u03bb"); + filterText = filterText.replaceAll("\\B'l\\b", "\u03bc"); + + if(matchName != null) { + if(filterText.startsWith("*")) { + return matchName.contains(filterText.substring(1)); + } else { + return matchName.startsWith(filterText); + } } } } From 4c823447ab9f29c7f0c4b710648a6f468b75d212 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 14 Oct 2014 23:54:11 +0800 Subject: [PATCH 073/127] support regex in quick outline --- Ocaml/src/ocaml/views/outline/QuickOutline.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Ocaml/src/ocaml/views/outline/QuickOutline.java b/Ocaml/src/ocaml/views/outline/QuickOutline.java index b2a1324..363caf1 100644 --- a/Ocaml/src/ocaml/views/outline/QuickOutline.java +++ b/Ocaml/src/ocaml/views/outline/QuickOutline.java @@ -352,12 +352,18 @@ private boolean matchesFilter(Object element) { filterText = filterText.replaceAll("\\B'k\\b", "\u03bb"); filterText = filterText.replaceAll("\\B'l\\b", "\u03bc"); - if(matchName != null) { - if(filterText.startsWith("*")) { + try { + // use regex when filterText start with "^" (regex is slow) + if (filterText.startsWith("^")) + return matchName.matches(filterText); + // search for substring when filterText start with "*" + else if (filterText.startsWith("*")) return matchName.contains(filterText.substring(1)); - } else { + // otherwise, search for static string + else return matchName.startsWith(filterText); - } + } catch (Exception e) { + return false; } } } From a260e5d1c6b86fa2bbb8d809026bdf92e23c32ae Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 17 Oct 2014 01:58:53 +0800 Subject: [PATCH 074/127] add foreground color to preference --- Ocaml/src/ocaml/OcamlPlugin.java | 5 ++++ .../syntaxcoloring/OcamlEditorColors.java | 7 +++++ Ocaml/src/ocaml/editors/OcamlEditor.java | 28 ++++++++++++++++++- .../editors/OcamlSourceViewerConfig.java | 6 +++- .../src/ocaml/editors/lex/OcamllexEditor.java | 26 +++++++++++++++-- .../ocaml/editors/yacc/OcamlyaccEditor.java | 28 +++++++++++++++++-- .../parsers/OcamlNewInterfaceParser.java | 6 ++-- .../preferences/PreferenceConstants.java | 1 + .../preferences/PreferenceInitializer.java | 1 + .../SyntaxColoringPreferencePage.java | 6 ++++ 10 files changed, 104 insertions(+), 10 deletions(-) diff --git a/Ocaml/src/ocaml/OcamlPlugin.java b/Ocaml/src/ocaml/OcamlPlugin.java index dfa17af..33d05d7 100644 --- a/Ocaml/src/ocaml/OcamlPlugin.java +++ b/Ocaml/src/ocaml/OcamlPlugin.java @@ -395,6 +395,11 @@ public static RGB getPointedUppercaseColor() { PreferenceConstants.P_POINTED_UPPERCASE_COLOR)); } + public static RGB getForegroundColor() { + return string2RGB(instance.getPreferenceStore().getString( + PreferenceConstants.P_FOREGROUND_COLOR)); + } + /** Returns whether comments should appear in bold (from the user preferences) */ public static boolean getCommentIsBold() { return instance.getPreferenceStore().getBoolean(PreferenceConstants.P_BOLD_COMMENTS); diff --git a/Ocaml/src/ocaml/editor/syntaxcoloring/OcamlEditorColors.java b/Ocaml/src/ocaml/editor/syntaxcoloring/OcamlEditorColors.java index 2dce3d0..6b3ecd5 100644 --- a/Ocaml/src/ocaml/editor/syntaxcoloring/OcamlEditorColors.java +++ b/Ocaml/src/ocaml/editor/syntaxcoloring/OcamlEditorColors.java @@ -22,6 +22,7 @@ public class OcamlEditorColors { private static Color PUNCTUATION_COLOR; private static Color UPPERCASE_COLOR; private static Color POINTED_UPPERCASE_COLOR; + private static Color FOREGROUND_COLOR; private static boolean initialized = false; @@ -43,6 +44,7 @@ private static void init(){ PUNCTUATION_COLOR = new Color(display, OcamlPlugin.getPunctuationColor()); UPPERCASE_COLOR = new Color(display, OcamlPlugin.getUppercaseColor()); POINTED_UPPERCASE_COLOR = new Color(display, OcamlPlugin.getPointedUppercaseColor()); + FOREGROUND_COLOR = new Color(display, OcamlPlugin.getForegroundColor()); initialized = true; } @@ -143,4 +145,9 @@ public static Color getPointedUppercaseColor() { return POINTED_UPPERCASE_COLOR; } + public static Color getForegroundColor() { + if(!initialized) + init(); + return FOREGROUND_COLOR; + } } \ No newline at end of file diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index 5b612ab..bba234c 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -2,11 +2,13 @@ import java.io.File; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import ocaml.OcamlPlugin; import ocaml.debugging.DebugVisuals; import ocaml.editor.completion.CompletionJob; +import ocaml.editor.syntaxcoloring.OcamlEditorColors; import ocaml.editors.util.OcamlCharacterPairMatcher; import ocaml.natures.OcamlNatureMakefile; import ocaml.parser.Def; @@ -26,6 +28,7 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; +import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; @@ -35,8 +38,12 @@ import org.eclipse.jface.text.PaintManager; import org.eclipse.jface.text.TextEvent; import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.MatchingCharacterPainter; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; @@ -51,6 +58,7 @@ import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; +import org.eclipse.ui.texteditor.spelling.SpellingAnnotation; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; /** @@ -123,6 +131,7 @@ protected void createActions() { try { StyledText text = this.getSourceViewer().getTextWidget(); + caret = new DebugVisuals(text); text.addPaintListener(caret); @@ -167,6 +176,18 @@ public void textChanged(TextEvent event) { rebuildOutline(50, false); // don't sync outline with editor } }); + + IPreferenceStore prefStore = OcamlPlugin.getInstance().getPreferenceStore(); + prefStore.addPropertyChangeListener(new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) { + if (event.getProperty().equals(PreferenceConstants.P_FOREGROUND_COLOR)) { + Display display = Display.getCurrent(); + RGB rgbColor = (RGB) event.getNewValue(); + Color foregroundColor = new Color(display, rgbColor); + viewer.getTextWidget().setForeground(foregroundColor); + } + } + }); } @Override @@ -237,7 +258,12 @@ public void createPartControl(Composite parent) { super.createPartControl(parent); StyledText styledText = this.getSourceViewer().getTextWidget(); styledText.setTabs(getTabSize()); + + Color foregroundColor = OcamlEditorColors.getForegroundColor(); + styledText.setForeground(foregroundColor); } + + public static int getTabSize() { return OcamlPlugin.getInstance().getPreferenceStore().getInt( @@ -266,7 +292,7 @@ public static String getTab() { } public void redraw() { - getSourceViewer().getTextWidget().redraw(); + Color foregroundColor = OcamlEditorColors.getForegroundColor(); } /** Return the caret position in the editor */ diff --git a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java index 70844e9..0331149 100644 --- a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java +++ b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java @@ -46,6 +46,8 @@ import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Color; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.texteditor.spelling.SpellingAnnotation; import org.eclipse.ui.texteditor.spelling.SpellingService; @@ -233,7 +235,7 @@ public IReconciler getReconciler(final ISourceViewer sourceViewer) { reconciler.setIsIncrementalReconciler(false); reconciler.setProgressMonitor(new NullProgressMonitor()); reconciler.setDelay(500); - + OcamlPlugin.getInstance().getPreferenceStore().addPropertyChangeListener( new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { @@ -272,6 +274,8 @@ public void propertyChange(PropertyChangeEvent event) { return null; } + + public boolean isContentAssistantActive() { return isContentAssistantActive; } diff --git a/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java b/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java index 1001b45..db831d9 100644 --- a/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java +++ b/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java @@ -2,6 +2,7 @@ import ocaml.OcamlPlugin; import ocaml.editor.completion.CompletionJob; +import ocaml.editor.syntaxcoloring.OcamlEditorColors; import ocaml.editors.util.OcamlCharacterPairMatcher; import ocaml.natures.OcamlNatureMakefile; import ocaml.popup.actions.CompileProjectPopupAction; @@ -13,8 +14,12 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.PaintManager; +import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.MatchingCharacterPainter; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; @@ -39,13 +44,27 @@ public OcamllexEditor() { protected void createActions() { super.createActions(); - paintManager = new PaintManager(getSourceViewer()); + final ISourceViewer viewer = getSourceViewer(); + + paintManager = new PaintManager(viewer); matchingCharacterPainter = - new MatchingCharacterPainter(getSourceViewer(), new OcamlCharacterPairMatcher()); + new MatchingCharacterPainter(viewer, new OcamlCharacterPairMatcher()); matchingCharacterPainter.setColor(new Color(Display.getCurrent(), new RGB(160, 160, 160))); paintManager.addPainter(matchingCharacterPainter); OcamlPlugin.getInstance().checkPaths(); + + IPreferenceStore prefStore = OcamlPlugin.getInstance().getPreferenceStore(); + prefStore.addPropertyChangeListener(new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) { + if (event.getProperty().equals(PreferenceConstants.P_FOREGROUND_COLOR)) { + Display display = Display.getCurrent(); + RGB rgbColor = (RGB) event.getNewValue(); + Color foregroundColor = new Color(display, rgbColor); + viewer.getTextWidget().setForeground(foregroundColor); + } + } + }); // effectue le parsing des bibliothèques ocaml en arrière plan CompletionJob job = new CompletionJob("Parsing ocaml library mli files", null); @@ -58,6 +77,9 @@ public void createPartControl(Composite parent) { super.createPartControl(parent); StyledText styledText = this.getSourceViewer().getTextWidget(); styledText.setTabs(getTabSize()); + + Color foregroundColor = OcamlEditorColors.getForegroundColor(); + styledText.setForeground(foregroundColor); } @Override diff --git a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java index 7532e93..1ec429f 100644 --- a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java +++ b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java @@ -2,6 +2,7 @@ import ocaml.OcamlPlugin; import ocaml.editor.completion.CompletionJob; +import ocaml.editor.syntaxcoloring.OcamlEditorColors; import ocaml.editors.util.OcamlCharacterPairMatcher; import ocaml.editors.yacc.outline.OcamlYaccOutlineControl; import ocaml.editors.yacc.outline.YaccOutlineJob; @@ -15,11 +16,15 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextListener; import org.eclipse.jface.text.PaintManager; import org.eclipse.jface.text.TextEvent; +import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.MatchingCharacterPainter; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; @@ -44,10 +49,12 @@ public OcamlyaccEditor() { @Override protected void createActions() { super.createActions(); + + final ISourceViewer viewer = getSourceViewer(); - paintManager = new PaintManager(getSourceViewer()); + paintManager = new PaintManager(viewer); matchingCharacterPainter = - new MatchingCharacterPainter(getSourceViewer(), new OcamlCharacterPairMatcher()); + new MatchingCharacterPainter(viewer, new OcamlCharacterPairMatcher()); matchingCharacterPainter.setColor(new Color(Display.getCurrent(), new RGB(160, 160, 160))); paintManager.addPainter(matchingCharacterPainter); @@ -59,13 +66,25 @@ protected void createActions() { job.schedule(); - this.getSourceViewer().addTextListener(new ITextListener() { + viewer.addTextListener(new ITextListener() { public void textChanged(TextEvent event) { if (event.getDocumentEvent() != null) rebuildOutline(500); } }); + + IPreferenceStore prefStore = OcamlPlugin.getInstance().getPreferenceStore(); + prefStore.addPropertyChangeListener(new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) { + if (event.getProperty().equals(PreferenceConstants.P_FOREGROUND_COLOR)) { + Display display = Display.getCurrent(); + RGB rgbColor = (RGB) event.getNewValue(); + Color foregroundColor = new Color(display, rgbColor); + viewer.getTextWidget().setForeground(foregroundColor); + } + } + }); } @Override @@ -73,6 +92,9 @@ public void createPartControl(Composite parent) { super.createPartControl(parent); StyledText styledText = this.getSourceViewer().getTextWidget(); styledText.setTabs(getTabSize()); + + Color foregroundColor = OcamlEditorColors.getForegroundColor(); + styledText.setForeground(foregroundColor); } @Override diff --git a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java index 6c2b39d..4e5e67b 100644 --- a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java +++ b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java @@ -64,7 +64,8 @@ public static OcamlNewInterfaceParser getInstance() { * interpreting a keyword inside a comment, and to attach comments to * definitions. */ - private LinkedList comments; + private LinkedList comments = new LinkedList(); + /** Section comments */ private LinkedList sectionComments; @@ -216,7 +217,7 @@ protected IStatus run(IProgressMonitor monitor) { definition = parseModule(lines, filename, moduleName, bInterface); } catch (Throwable e) { // if there was a parsing error, we log it and we continue on to the next file - e.printStackTrace(); + // e.printStackTrace(); Def def = new Def(moduleName, Def.Type.ParserError, 0, 0); def.setFileName(filename); def.setComment("ERROR 2: The parser encountered an error while parsing this file.\n\n" @@ -497,7 +498,6 @@ public Comment(int begin, int end, String text) { private String parseComments(String lines) { StringBuilder result = new StringBuilder(lines); - comments = new LinkedList(); sectionComments = new LinkedList(); boolean bParL = false; diff --git a/Ocaml/src/ocaml/preferences/PreferenceConstants.java b/Ocaml/src/ocaml/preferences/PreferenceConstants.java index dcd9933..53fec64 100644 --- a/Ocaml/src/ocaml/preferences/PreferenceConstants.java +++ b/Ocaml/src/ocaml/preferences/PreferenceConstants.java @@ -33,6 +33,7 @@ public class PreferenceConstants public static final String P_PUNCTUATION_COLOR = "PunctuationColor"; public static final String P_UPPERCASE_COLOR = "UppercaseColor"; public static final String P_POINTED_UPPERCASE_COLOR = "PointedUppercaseColor"; + public static final String P_FOREGROUND_COLOR = "ForeGroundColor"; public static final String P_BOLD_KEYWORDS = "boldKeywords"; public static final String P_BOLD_COMMENTS = "boldComments"; diff --git a/Ocaml/src/ocaml/preferences/PreferenceInitializer.java b/Ocaml/src/ocaml/preferences/PreferenceInitializer.java index 6bf165a..0771a03 100644 --- a/Ocaml/src/ocaml/preferences/PreferenceInitializer.java +++ b/Ocaml/src/ocaml/preferences/PreferenceInitializer.java @@ -37,6 +37,7 @@ public void initializeDefaultPreferences() { store.setDefault(PreferenceConstants.P_PUNCTUATION_COLOR, "128,0,0"); store.setDefault(PreferenceConstants.P_UPPERCASE_COLOR, "82,112,180"); store.setDefault(PreferenceConstants.P_POINTED_UPPERCASE_COLOR, "162,0,185"); + store.setDefault(PreferenceConstants.P_FOREGROUND_COLOR, "216,207,200"); // set the default syntax coloring bold attributes store.setDefault(PreferenceConstants.P_BOLD_CHARACTERS, false); diff --git a/Ocaml/src/ocaml/preferences/SyntaxColoringPreferencePage.java b/Ocaml/src/ocaml/preferences/SyntaxColoringPreferencePage.java index 4804434..b1c51a4 100644 --- a/Ocaml/src/ocaml/preferences/SyntaxColoringPreferencePage.java +++ b/Ocaml/src/ocaml/preferences/SyntaxColoringPreferencePage.java @@ -49,6 +49,8 @@ public SyntaxColoringPreferencePage() { private ColorFieldEditor colorFieldUppercase; private ColorFieldEditor colorFieldPointedUppercase; + + private ColorFieldEditor colorFieldForeground; @Override public void createFieldEditors() { @@ -88,6 +90,9 @@ public void createFieldEditors() { colorFieldPointedUppercase = new ColorFieldEditor(PreferenceConstants.P_POINTED_UPPERCASE_COLOR, "Pointed uppercase identifier Color:", this.getFieldEditorParent()); + colorFieldForeground = new ColorFieldEditor(PreferenceConstants.P_FOREGROUND_COLOR, + "Foreground Color:", this.getFieldEditorParent()); + this.addField(colorFieldKeywords); this.addField(colorFieldLetinKeywords); this.addField(colorFieldFunFunctionKeywords); @@ -103,6 +108,7 @@ public void createFieldEditors() { this.addField(colorFieldPunctuation); this.addField(colorFieldUppercase); this.addField(colorFieldPointedUppercase); + this.addField(colorFieldForeground); this.addField(new BooleanFieldEditor(PreferenceConstants.P_BOLD_KEYWORDS, "Bold k&eywords", this From 440540cbb267cb38a833dec395cd61b134f4e045 Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 17 Oct 2014 22:41:07 +0800 Subject: [PATCH 075/127] remove foreground setting from preferences --- Ocaml/src/ocaml/OcamlPlugin.java | 5 ----- .../syntaxcoloring/OcamlEditorColors.java | 7 ------- Ocaml/src/ocaml/editors/OcamlEditor.java | 18 ++---------------- .../src/ocaml/editors/lex/OcamllexEditor.java | 15 --------------- .../ocaml/editors/yacc/OcamlyaccEditor.java | 14 -------------- .../ocaml/preferences/PreferenceConstants.java | 1 - .../preferences/PreferenceInitializer.java | 1 - .../SyntaxColoringPreferencePage.java | 7 ------- 8 files changed, 2 insertions(+), 66 deletions(-) diff --git a/Ocaml/src/ocaml/OcamlPlugin.java b/Ocaml/src/ocaml/OcamlPlugin.java index 33d05d7..dfa17af 100644 --- a/Ocaml/src/ocaml/OcamlPlugin.java +++ b/Ocaml/src/ocaml/OcamlPlugin.java @@ -395,11 +395,6 @@ public static RGB getPointedUppercaseColor() { PreferenceConstants.P_POINTED_UPPERCASE_COLOR)); } - public static RGB getForegroundColor() { - return string2RGB(instance.getPreferenceStore().getString( - PreferenceConstants.P_FOREGROUND_COLOR)); - } - /** Returns whether comments should appear in bold (from the user preferences) */ public static boolean getCommentIsBold() { return instance.getPreferenceStore().getBoolean(PreferenceConstants.P_BOLD_COMMENTS); diff --git a/Ocaml/src/ocaml/editor/syntaxcoloring/OcamlEditorColors.java b/Ocaml/src/ocaml/editor/syntaxcoloring/OcamlEditorColors.java index 6b3ecd5..2dce3d0 100644 --- a/Ocaml/src/ocaml/editor/syntaxcoloring/OcamlEditorColors.java +++ b/Ocaml/src/ocaml/editor/syntaxcoloring/OcamlEditorColors.java @@ -22,7 +22,6 @@ public class OcamlEditorColors { private static Color PUNCTUATION_COLOR; private static Color UPPERCASE_COLOR; private static Color POINTED_UPPERCASE_COLOR; - private static Color FOREGROUND_COLOR; private static boolean initialized = false; @@ -44,7 +43,6 @@ private static void init(){ PUNCTUATION_COLOR = new Color(display, OcamlPlugin.getPunctuationColor()); UPPERCASE_COLOR = new Color(display, OcamlPlugin.getUppercaseColor()); POINTED_UPPERCASE_COLOR = new Color(display, OcamlPlugin.getPointedUppercaseColor()); - FOREGROUND_COLOR = new Color(display, OcamlPlugin.getForegroundColor()); initialized = true; } @@ -145,9 +143,4 @@ public static Color getPointedUppercaseColor() { return POINTED_UPPERCASE_COLOR; } - public static Color getForegroundColor() { - if(!initialized) - init(); - return FOREGROUND_COLOR; - } } \ No newline at end of file diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index bba234c..647054b 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -176,18 +176,7 @@ public void textChanged(TextEvent event) { rebuildOutline(50, false); // don't sync outline with editor } }); - - IPreferenceStore prefStore = OcamlPlugin.getInstance().getPreferenceStore(); - prefStore.addPropertyChangeListener(new IPropertyChangeListener() { - public void propertyChange(PropertyChangeEvent event) { - if (event.getProperty().equals(PreferenceConstants.P_FOREGROUND_COLOR)) { - Display display = Display.getCurrent(); - RGB rgbColor = (RGB) event.getNewValue(); - Color foregroundColor = new Color(display, rgbColor); - viewer.getTextWidget().setForeground(foregroundColor); - } - } - }); + } @Override @@ -258,9 +247,6 @@ public void createPartControl(Composite parent) { super.createPartControl(parent); StyledText styledText = this.getSourceViewer().getTextWidget(); styledText.setTabs(getTabSize()); - - Color foregroundColor = OcamlEditorColors.getForegroundColor(); - styledText.setForeground(foregroundColor); } @@ -292,7 +278,7 @@ public static String getTab() { } public void redraw() { - Color foregroundColor = OcamlEditorColors.getForegroundColor(); + getSourceViewer().getTextWidget().redraw(); } /** Return the caret position in the editor */ diff --git a/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java b/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java index db831d9..43127d5 100644 --- a/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java +++ b/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java @@ -54,18 +54,6 @@ protected void createActions() { OcamlPlugin.getInstance().checkPaths(); - IPreferenceStore prefStore = OcamlPlugin.getInstance().getPreferenceStore(); - prefStore.addPropertyChangeListener(new IPropertyChangeListener() { - public void propertyChange(PropertyChangeEvent event) { - if (event.getProperty().equals(PreferenceConstants.P_FOREGROUND_COLOR)) { - Display display = Display.getCurrent(); - RGB rgbColor = (RGB) event.getNewValue(); - Color foregroundColor = new Color(display, rgbColor); - viewer.getTextWidget().setForeground(foregroundColor); - } - } - }); - // effectue le parsing des bibliothèques ocaml en arrière plan CompletionJob job = new CompletionJob("Parsing ocaml library mli files", null); job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority @@ -77,9 +65,6 @@ public void createPartControl(Composite parent) { super.createPartControl(parent); StyledText styledText = this.getSourceViewer().getTextWidget(); styledText.setTabs(getTabSize()); - - Color foregroundColor = OcamlEditorColors.getForegroundColor(); - styledText.setForeground(foregroundColor); } @Override diff --git a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java index 1ec429f..1bfcd3e 100644 --- a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java +++ b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java @@ -74,17 +74,6 @@ public void textChanged(TextEvent event) { } }); - IPreferenceStore prefStore = OcamlPlugin.getInstance().getPreferenceStore(); - prefStore.addPropertyChangeListener(new IPropertyChangeListener() { - public void propertyChange(PropertyChangeEvent event) { - if (event.getProperty().equals(PreferenceConstants.P_FOREGROUND_COLOR)) { - Display display = Display.getCurrent(); - RGB rgbColor = (RGB) event.getNewValue(); - Color foregroundColor = new Color(display, rgbColor); - viewer.getTextWidget().setForeground(foregroundColor); - } - } - }); } @Override @@ -92,9 +81,6 @@ public void createPartControl(Composite parent) { super.createPartControl(parent); StyledText styledText = this.getSourceViewer().getTextWidget(); styledText.setTabs(getTabSize()); - - Color foregroundColor = OcamlEditorColors.getForegroundColor(); - styledText.setForeground(foregroundColor); } @Override diff --git a/Ocaml/src/ocaml/preferences/PreferenceConstants.java b/Ocaml/src/ocaml/preferences/PreferenceConstants.java index 53fec64..dcd9933 100644 --- a/Ocaml/src/ocaml/preferences/PreferenceConstants.java +++ b/Ocaml/src/ocaml/preferences/PreferenceConstants.java @@ -33,7 +33,6 @@ public class PreferenceConstants public static final String P_PUNCTUATION_COLOR = "PunctuationColor"; public static final String P_UPPERCASE_COLOR = "UppercaseColor"; public static final String P_POINTED_UPPERCASE_COLOR = "PointedUppercaseColor"; - public static final String P_FOREGROUND_COLOR = "ForeGroundColor"; public static final String P_BOLD_KEYWORDS = "boldKeywords"; public static final String P_BOLD_COMMENTS = "boldComments"; diff --git a/Ocaml/src/ocaml/preferences/PreferenceInitializer.java b/Ocaml/src/ocaml/preferences/PreferenceInitializer.java index 0771a03..6bf165a 100644 --- a/Ocaml/src/ocaml/preferences/PreferenceInitializer.java +++ b/Ocaml/src/ocaml/preferences/PreferenceInitializer.java @@ -37,7 +37,6 @@ public void initializeDefaultPreferences() { store.setDefault(PreferenceConstants.P_PUNCTUATION_COLOR, "128,0,0"); store.setDefault(PreferenceConstants.P_UPPERCASE_COLOR, "82,112,180"); store.setDefault(PreferenceConstants.P_POINTED_UPPERCASE_COLOR, "162,0,185"); - store.setDefault(PreferenceConstants.P_FOREGROUND_COLOR, "216,207,200"); // set the default syntax coloring bold attributes store.setDefault(PreferenceConstants.P_BOLD_CHARACTERS, false); diff --git a/Ocaml/src/ocaml/preferences/SyntaxColoringPreferencePage.java b/Ocaml/src/ocaml/preferences/SyntaxColoringPreferencePage.java index b1c51a4..1832742 100644 --- a/Ocaml/src/ocaml/preferences/SyntaxColoringPreferencePage.java +++ b/Ocaml/src/ocaml/preferences/SyntaxColoringPreferencePage.java @@ -49,8 +49,6 @@ public SyntaxColoringPreferencePage() { private ColorFieldEditor colorFieldUppercase; private ColorFieldEditor colorFieldPointedUppercase; - - private ColorFieldEditor colorFieldForeground; @Override public void createFieldEditors() { @@ -90,9 +88,6 @@ public void createFieldEditors() { colorFieldPointedUppercase = new ColorFieldEditor(PreferenceConstants.P_POINTED_UPPERCASE_COLOR, "Pointed uppercase identifier Color:", this.getFieldEditorParent()); - colorFieldForeground = new ColorFieldEditor(PreferenceConstants.P_FOREGROUND_COLOR, - "Foreground Color:", this.getFieldEditorParent()); - this.addField(colorFieldKeywords); this.addField(colorFieldLetinKeywords); this.addField(colorFieldFunFunctionKeywords); @@ -108,9 +103,7 @@ public void createFieldEditors() { this.addField(colorFieldPunctuation); this.addField(colorFieldUppercase); this.addField(colorFieldPointedUppercase); - this.addField(colorFieldForeground); - this.addField(new BooleanFieldEditor(PreferenceConstants.P_BOLD_KEYWORDS, "Bold k&eywords", this .getFieldEditorParent())); this.addField(new BooleanFieldEditor(PreferenceConstants.P_BOLD_COMMENTS, "Bold co&mments", this From ccb12ed69117b3ac891ed9f256d12b615859cda6 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 20 Oct 2014 18:41:59 +0800 Subject: [PATCH 076/127] update correct path of projects. Always add current dir '.' to project paths --- Ocaml/src/ocaml/FolderChangeListener.java | 25 ++++++++++++++----- .../completion/OcamlCompletionProcessor.java | 7 ++++-- Ocaml/src/ocaml/util/OcamlPaths.java | 14 ++++++++--- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Ocaml/src/ocaml/FolderChangeListener.java b/Ocaml/src/ocaml/FolderChangeListener.java index 0ed759e..e1bc0d7 100644 --- a/Ocaml/src/ocaml/FolderChangeListener.java +++ b/Ocaml/src/ocaml/FolderChangeListener.java @@ -43,10 +43,11 @@ public boolean visit(IResourceDelta delta) throws CoreException { switch (delta.getKind()) { case IResourceDelta.ADDED: { - // ignore special directories (.settings, .git, .cvsignore, etc.) + // ignore special directories (.settings, .git, .cvsignore, etc.) but not "." IResource r = res; while (r != null) { - if (r.getName().startsWith(".")) + String rName = r.getName(); + if ((rName.length() > 1) && rName.startsWith(".")) return false; r = r.getParent(); } @@ -55,12 +56,24 @@ public boolean visit(IResourceDelta delta) throws CoreException { if(res.getName().equals("_build")) return false; - // add this path to the project paths + // add this path to the project paths when necessary OcamlPaths paths = new OcamlPaths(project); String[] strPaths = paths.getPaths(); - String[] newPaths = new String[strPaths.length + 1]; - System.arraycopy(strPaths, 0, newPaths, 0, strPaths.length); - newPaths[strPaths.length] = res.getProjectRelativePath().toPortableString(); + String resPath = res.getProjectRelativePath().toPortableString(); + + boolean needAdd = true; + for (String s: strPaths) { + if (s.compareTo(resPath) == 0) { + needAdd = false; + break; + } + } + String[] newPaths = strPaths; + if (needAdd) { + newPaths = new String[strPaths.length + 1]; + System.arraycopy(strPaths, 0, newPaths, 0, strPaths.length); + newPaths[strPaths.length] = resPath; + } paths.setPaths(newPaths); break; diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index f011e8c..df0e9f7 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -304,7 +304,10 @@ else if (def.type == Def.Type.ModuleAlias) { } // look for completion in opened or included module of current module - for (Def def1 : currentDef.children) { + ArrayList currentChildren = new ArrayList<>(); + if (currentDef != null) + currentChildren = currentDef.children; + for (Def def1 : currentChildren) { if (def1.type == Def.Type.Open || def1.type == Def.Type.Include) { Def involvedDef = def1; String involvedModuleName = ""; @@ -322,7 +325,7 @@ else if (def.type == Def.Type.ModuleAlias) { } // search in current module first - for (Def def2: currentDef.children) { + for (Def def2: currentChildren) { if (def2.name.equals(involvedModuleName)) { Def involvedDefRoot = def2; for (Def def3: involvedDefRoot.children) { diff --git a/Ocaml/src/ocaml/util/OcamlPaths.java b/Ocaml/src/ocaml/util/OcamlPaths.java index 8dbf09c..b4102ae 100644 --- a/Ocaml/src/ocaml/util/OcamlPaths.java +++ b/Ocaml/src/ocaml/util/OcamlPaths.java @@ -36,13 +36,13 @@ public class OcamlPaths { public OcamlPaths(IProject project) { this.project = project; } - + public void setPaths(String[] paths) { IPath pathsPath = project.getLocation().append(PATHS_FILE); File file = pathsPath.toFile(); try { - BufferedWriter writer = new BufferedWriter(new FileWriter(file)); + BufferedWriter writer = new BufferedWriter(new FileWriter(file, false)); for (String path : paths) if (path != null && path.trim().length() > 0) @@ -95,12 +95,16 @@ public String[] getPaths() { if (!file.exists()) restoreDefaults(); + boolean hasCurrentDir = false; try { BufferedReader reader = new BufferedReader(new FileReader(file)); String path = ""; - while ((path = reader.readLine()) != null) + while ((path = reader.readLine()) != null) { + if (path.compareTo(".") == 0) + hasCurrentDir = true; paths.add(path); + } reader.close(); @@ -108,6 +112,10 @@ public String[] getPaths() { OcamlPlugin.logError("ocaml plugin error", e); return new String[0]; } + + // always add "." to project paths + if (!hasCurrentDir) + paths.add("."); addReferencedProjectsPaths(paths); From fc2422da19f65fc4c8e9608526e1eafe835732c6 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 20 Oct 2014 22:19:00 +0800 Subject: [PATCH 077/127] allow Parameter typ in Def structure --- Ocaml/src/ocaml/parser/Def.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index f2b5b68..0c107d2 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -386,7 +386,8 @@ private void cleanCopyAux(Def node, Def newNode) { } private void findRealChildren(Def node, ArrayList nodes, boolean root) { - if (node.type == Type.Dummy || node.type == Type.Parameter + if (node.type == Type.Dummy + /* || node.type == Type.Parameter */ // Trung: this is to handle Parameter /* || node.type == Type.Identifier */ // Trung: this is to handle ModuleAlias || node.type == Type.Functor || node.type == Type.Sig || node.type == Type.Object || node.type == Type.Struct || node.type == Type.In || root From 1de9d57ebad5a522b8de6f379ac5717c7bca33b0 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 21 Oct 2014 00:53:06 +0800 Subject: [PATCH 078/127] jump by indentation --- Ocaml/plugin.xml | 4 +- .../actions/MoveCursorDownwardByIndent.java | 174 ++++++++++++++++ .../actions/MoveCursorUpwardByIndent.java | 192 ++++++++++++++++++ 3 files changed, 368 insertions(+), 2 deletions(-) create mode 100644 Ocaml/src/ocaml/editor/actions/MoveCursorDownwardByIndent.java create mode 100644 Ocaml/src/ocaml/editor/actions/MoveCursorUpwardByIndent.java diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index b6c643b..e442c29 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -754,14 +754,14 @@ style="push"> = (numOfLine - 1)) { + editor.selectAndReveal(doc.getLength(), 0); + return; + } + + // ignore empty lines while going down, go to the first non empty line + int beginOffset = doc.getLineOffset(lineNum); + int endOffset = doc.getLineOffset(lineNum+1) - 1; + String currentLine = doc.get(beginOffset, endOffset - beginOffset + 1); + + if (currentLine.trim().isEmpty()) { + lineNum++; + while (lineNum < numOfLine) { + beginOffset = doc.getLineOffset(lineNum); + endOffset = doc.getLineOffset(lineNum+1) - 1; + currentLine = doc.get(beginOffset, endOffset - beginOffset + 1); + if (currentLine.trim().isEmpty()) + lineNum++; + else + break; + } + if (lineNum >= numOfLine) + lineNum = numOfLine - 1; + int newOffset = doc.getLineOffset(lineNum); + while (newOffset < docLen) { + Character ch = doc.getChar(newOffset); + if (ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r') + break; + else + newOffset++; + } + if (newOffset >= docLen) + newOffset = beginOffset; + editor.selectAndReveal(newOffset, 0); + return; + } + + // find next line which has different identation + int currentIndent = computeIndent(currentLine); + lineNum++; + while (lineNum < numOfLine - 1) { + beginOffset = doc.getLineOffset(lineNum); + endOffset = doc.getLineOffset(lineNum+1) - 1; + String nextLine = doc.get(beginOffset, endOffset - beginOffset + 1); + int nextIndent = computeIndent(nextLine); + if (currentIndent != nextIndent) { + break; + } + else if (nextLine.trim().isEmpty()) { + currentIndent = -1; + lineNum++; + } + else { + lineNum++; + currentLine = nextLine; + currentIndent = nextIndent; + } + } + + // find location to jump to + int newLineOffset = doc.getLineOffset(lineNum); + int newOffset = newLineOffset; + while (newOffset < docLen) { + Character ch = doc.getChar(newOffset); + if (ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r') + break; + else + newOffset++; + } + if (newOffset >= docLen) + newOffset = newLineOffset; + + editor.selectAndReveal(newOffset, 0); + } catch (BadLocationException e) { + e.printStackTrace(); + return; + } + } + + private int computeIndent(String line) { + if (line.trim().isEmpty()) + return 0; + + if (line.charAt(0) == ' ') + return 1 + computeIndent(line.substring(1)); + + if (line.charAt(0) == '\t') + return OcamlEditor.getTabSize() + computeIndent(line.substring(1)); + + return 0; + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} diff --git a/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardByIndent.java b/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardByIndent.java new file mode 100644 index 0000000..f4e9a95 --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardByIndent.java @@ -0,0 +1,192 @@ +package ocaml.editor.actions; + +import ocaml.OcamlPlugin; +import ocaml.editors.OcamlEditor; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.editors.text.TextEditor; + +public class MoveCursorUpwardByIndent implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + + IWorkbenchPage page = window.getActivePage(); + + if (page == null) { + OcamlPlugin.logWarning(GotoDefinition.class.getSimpleName() + + ": page is null"); + return; + } + + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart == null) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": editorPart is null"); + return; + } + + if (!(editorPart instanceof TextEditor)) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": only works on ml and mli files"); + return; + } + + TextEditor editor = (TextEditor) editorPart; + IEditorInput editorInput = editor.getEditorInput(); + IDocument doc = editor.getDocumentProvider().getDocument(editorInput); + Control control = (Control)editor.getAdapter(Control.class); + + if (!(control instanceof StyledText)) + { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": Cannot get caret position"); + return; + } + + final StyledText styledText = (StyledText) control; + int cursorOffset = styledText.getCaretOffset(); + + try { + int lineNum = doc.getLineOfOffset(cursorOffset); + int numOfLine = doc.getNumberOfLines(); + int docLen = doc.getLength(); + + if (lineNum <= 0) { + editor.selectAndReveal(0, 0); + return; + } + + // ignore empty lines when going back; + int beginOffsetCurrentLine = 0; + int endOffsetCurrentLine = 0; + String currentLine = ""; + while (lineNum > 0) { + beginOffsetCurrentLine = doc.getLineOffset(lineNum); + endOffsetCurrentLine = (lineNum < numOfLine-1) ? doc.getLineOffset(lineNum+1) - 1 : docLen - 1; + currentLine = doc.get(beginOffsetCurrentLine, endOffsetCurrentLine - beginOffsetCurrentLine + 1); + if (currentLine.trim().isEmpty()) { + lineNum--; + } + else + break; + } + if (lineNum == 0) + editor.selectAndReveal(0, 0); + + + // if previous line has different indentation and cursor is not + // in the beginning of current block, then go to the beginning. + beginOffsetCurrentLine = doc.getLineOffset(lineNum); + int cursorColumn = cursorOffset - beginOffsetCurrentLine; + int newOffset = beginOffsetCurrentLine; + while (newOffset < docLen) { + Character ch = doc.getChar(newOffset); + if (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n') + break; + else + newOffset++; + } + int currentIndent = newOffset - beginOffsetCurrentLine; + + + int beginOffsetPrevLine = doc.getLineOffset(lineNum-1); + int endOffsetPrevLine = doc.getLineOffset(lineNum) - 1; + String prevLine = doc.get(beginOffsetPrevLine, endOffsetPrevLine - beginOffsetPrevLine + 1); + int prevIndent = computeIndent(prevLine); + if (prevLine.trim().isEmpty() && cursorColumn > currentIndent) { + newOffset = beginOffsetCurrentLine + currentIndent; + editor.selectAndReveal(newOffset, 0); + return; + } + else if ((prevIndent != currentIndent) && (cursorColumn > currentIndent)) { + newOffset = beginOffsetCurrentLine + currentIndent; + editor.selectAndReveal(newOffset, 0); + return; + } + + // ignore empty lines when going back; + lineNum--; + endOffsetCurrentLine = 0; + currentLine = ""; + while (lineNum > 0) { + beginOffsetCurrentLine = doc.getLineOffset(lineNum); + endOffsetCurrentLine = (lineNum < numOfLine-1) ? doc.getLineOffset(lineNum+1) - 1 : docLen; + currentLine = doc.get(beginOffsetCurrentLine, endOffsetCurrentLine - beginOffsetCurrentLine + 1); + if (currentLine.trim().isEmpty()) { + lineNum--; + } + else + break; + } + if (lineNum == 0) + editor.selectAndReveal(0, 0); + + + // search back to find the last line has different indentation + currentIndent = computeIndent(currentLine); + while (lineNum > 0) { + beginOffsetPrevLine = doc.getLineOffset(lineNum-1); + endOffsetPrevLine = doc.getLineOffset(lineNum) - 1; + prevLine = doc.get(beginOffsetPrevLine, endOffsetPrevLine - beginOffsetPrevLine + 1); + prevIndent = computeIndent(prevLine); + + if (prevLine.trim().isEmpty()) { + break; + } + else if (prevIndent == currentIndent) { + lineNum--; + currentLine = prevLine; + } + else + break; + } + newOffset = doc.getLineOffset(lineNum); + while (newOffset < docLen) { + Character ch = doc.getChar(newOffset); + if (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n') + break; + else + newOffset++; + } + editor.selectAndReveal(newOffset, 0); + } catch (BadLocationException e) { + return; + } + } + + private int computeIndent(String line) { + if (line.trim().isEmpty()) + return 0; + + if (line.charAt(0) == ' ') + return 1 + computeIndent(line.substring(1)); + + if (line.charAt(0) == '\t') + return OcamlEditor.getTabSize() + computeIndent(line.substring(1)); + + return 0; + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} From 4fe484f797a2da73295d1e61c2bedb32b9861a33 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 21 Oct 2014 01:40:55 +0800 Subject: [PATCH 079/127] selection by indentation --- Ocaml/plugin.xml | 52 ++--- .../actions/MoveCursorDownwardByIndent.java | 4 +- .../actions/MoveCursorUpwardByIndent.java | 8 +- .../actions/SelectDownwardByIndent.java | 182 ++++++++++++++++ .../editor/actions/SelectUpwardByIndent.java | 200 ++++++++++++++++++ 5 files changed, 416 insertions(+), 30 deletions(-) create mode 100644 Ocaml/src/ocaml/editor/actions/SelectDownwardByIndent.java create mode 100644 Ocaml/src/ocaml/editor/actions/SelectUpwardByIndent.java diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index e442c29..b32eebc 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -740,31 +740,31 @@ + id="Ocaml.moveCursorDownwardByIndent" + name="Move Cursor Downward By Indent"> + id="Ocaml.moveCursorUpwardByIndent" + name="Move Cursor Upward By Indent"> + id="Ocaml.selectUpwardByIndent" + name="Select Upward By Indent"> + id="Ocaml.selectDownwardByIndent" + name="Select Downward By Indent"> diff --git a/Ocaml/src/ocaml/editor/actions/MoveCursorDownwardByIndent.java b/Ocaml/src/ocaml/editor/actions/MoveCursorDownwardByIndent.java index 2ad77af..93c7de9 100644 --- a/Ocaml/src/ocaml/editor/actions/MoveCursorDownwardByIndent.java +++ b/Ocaml/src/ocaml/editor/actions/MoveCursorDownwardByIndent.java @@ -83,7 +83,7 @@ public void run(IAction action) { lineNum++; while (lineNum < numOfLine) { beginOffset = doc.getLineOffset(lineNum); - endOffset = doc.getLineOffset(lineNum+1) - 1; + endOffset = (lineNum < numOfLine - 1) ? doc.getLineOffset(lineNum+1) - 1 : docLen - 1; currentLine = doc.get(beginOffset, endOffset - beginOffset + 1); if (currentLine.trim().isEmpty()) lineNum++; @@ -111,7 +111,7 @@ public void run(IAction action) { lineNum++; while (lineNum < numOfLine - 1) { beginOffset = doc.getLineOffset(lineNum); - endOffset = doc.getLineOffset(lineNum+1) - 1; + endOffset = (lineNum < numOfLine - 1) ? doc.getLineOffset(lineNum+1) - 1 : docLen - 1; String nextLine = doc.get(beginOffset, endOffset - beginOffset + 1); int nextIndent = computeIndent(nextLine); if (currentIndent != nextIndent) { diff --git a/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardByIndent.java b/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardByIndent.java index f4e9a95..9373c72 100644 --- a/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardByIndent.java +++ b/Ocaml/src/ocaml/editor/actions/MoveCursorUpwardByIndent.java @@ -82,8 +82,10 @@ public void run(IAction action) { else break; } - if (lineNum == 0) + if (lineNum == 0) { editor.selectAndReveal(0, 0); + return; + } // if previous line has different indentation and cursor is not @@ -130,8 +132,10 @@ else if ((prevIndent != currentIndent) && (cursorColumn > currentIndent)) { else break; } - if (lineNum == 0) + if (lineNum == 0) { editor.selectAndReveal(0, 0); + return; + } // search back to find the last line has different indentation diff --git a/Ocaml/src/ocaml/editor/actions/SelectDownwardByIndent.java b/Ocaml/src/ocaml/editor/actions/SelectDownwardByIndent.java new file mode 100644 index 0000000..2c7ddd0 --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/SelectDownwardByIndent.java @@ -0,0 +1,182 @@ +package ocaml.editor.actions; + +import ocaml.OcamlPlugin; +import ocaml.editors.OcamlEditor; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.editors.text.TextEditor; + +public class SelectDownwardByIndent implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + + IWorkbenchPage page = window.getActivePage(); + + if (page == null) { + OcamlPlugin.logWarning(GotoDefinition.class.getSimpleName() + + ": page is null"); + return; + } + + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart == null) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": editorPart is null"); + return; + } + + if (!(editorPart instanceof TextEditor)) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": only works on ml and mli files"); + return; + } + + TextEditor editor = (TextEditor) editorPart; + IEditorInput editorInput = editor.getEditorInput(); + IDocument doc = editor.getDocumentProvider().getDocument(editorInput); + Control control = (Control)editor.getAdapter(Control.class); + + if (!(control instanceof StyledText)) + { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": Cannot get caret position"); + return; + } + + final StyledText styledText = (StyledText) control; + int cursorOffset = styledText.getCaretOffset(); + + Point selection = styledText.getSelection(); + int startOffset = (selection.x < cursorOffset) ? selection.x : selection.y; + + try { + int lineNum= doc.getLineOfOffset(cursorOffset); + int numOfLine = doc.getNumberOfLines(); + int docLen = doc.getLength(); + + if (lineNum == (numOfLine - 2)) { + int lastLineOffset = doc.getLineOffset(lineNum+1); + styledText.setSelection(startOffset, lastLineOffset); + return; + } + + if (lineNum >= (numOfLine - 1)) { + styledText.setSelection(startOffset, doc.getLength()); + return; + } + + // ignore empty lines while going down, go to the first non empty line + int beginOffset = doc.getLineOffset(lineNum); + int endOffset = doc.getLineOffset(lineNum+1) - 1; + String currentLine = doc.get(beginOffset, endOffset - beginOffset + 1); + + if (currentLine.trim().isEmpty()) { + lineNum++; + while (lineNum < numOfLine) { + beginOffset = doc.getLineOffset(lineNum); + endOffset = (lineNum < numOfLine - 1) ? doc.getLineOffset(lineNum+1) - 1 : docLen - 1; + currentLine = doc.get(beginOffset, endOffset - beginOffset + 1); + if (currentLine.trim().isEmpty()) + lineNum++; + else + break; + } + if (lineNum >= numOfLine) + lineNum = numOfLine - 1; + int newOffset = doc.getLineOffset(lineNum); + int k = newOffset; + while (k < docLen) { + Character ch = doc.getChar(k); + if (ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r') + break; + else { + if (ch == '\n' || ch == '\r') + newOffset = k + 1; + k++; + } + } + + styledText.setSelection(startOffset, newOffset); + return; + } + + // find next line which has different identation + int currentIndent = computeIndent(currentLine); + lineNum++; + while (lineNum < numOfLine - 1) { + beginOffset = doc.getLineOffset(lineNum); + endOffset = (lineNum < numOfLine - 1) ? doc.getLineOffset(lineNum+1) - 1 : docLen - 1; + String nextLine = doc.get(beginOffset, endOffset - beginOffset + 1); + int nextIndent = computeIndent(nextLine); + if (currentIndent != nextIndent) { + break; + } + else if (nextLine.trim().isEmpty()) { + currentIndent = -1; + lineNum++; + } + else { + lineNum++; + currentLine = nextLine; + currentIndent = nextIndent; + } + } + + // find location to jump to + int newOffset = doc.getLineOffset(lineNum); + int k = newOffset; + while (k < docLen) { + Character ch = doc.getChar(k); + if (ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r') + break; + else { + if (ch == '\n' || ch == '\r') + newOffset = k + 1; + k++; + } + } + + styledText.setSelection(startOffset, newOffset); + } catch (BadLocationException e) { + e.printStackTrace(); + return; + } + } + + private int computeIndent(String line) { + if (line.trim().isEmpty()) + return 0; + + if (line.charAt(0) == ' ') + return 1 + computeIndent(line.substring(1)); + + if (line.charAt(0) == '\t') + return OcamlEditor.getTabSize() + computeIndent(line.substring(1)); + + return 0; + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} diff --git a/Ocaml/src/ocaml/editor/actions/SelectUpwardByIndent.java b/Ocaml/src/ocaml/editor/actions/SelectUpwardByIndent.java new file mode 100644 index 0000000..3a9c351 --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/SelectUpwardByIndent.java @@ -0,0 +1,200 @@ +package ocaml.editor.actions; + +import ocaml.OcamlPlugin; +import ocaml.editors.OcamlEditor; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.editors.text.TextEditor; + +public class SelectUpwardByIndent implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + + IWorkbenchPage page = window.getActivePage(); + + if (page == null) { + OcamlPlugin.logWarning(GotoDefinition.class.getSimpleName() + + ": page is null"); + return; + } + + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart == null) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": editorPart is null"); + return; + } + + if (!(editorPart instanceof TextEditor)) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": only works on ml and mli files"); + return; + } + + TextEditor editor = (TextEditor) editorPart; + IEditorInput editorInput = editor.getEditorInput(); + IDocument doc = editor.getDocumentProvider().getDocument(editorInput); + Control control = (Control)editor.getAdapter(Control.class); + + if (!(control instanceof StyledText)) + { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": Cannot get caret position"); + return; + } + + final StyledText styledText = (StyledText) control; + int cursorOffset = styledText.getCaretOffset(); + + Point selection = styledText.getSelection(); + int startOffset = (selection.x < cursorOffset) ? selection.x : selection.y; + + try { + int lineNum = doc.getLineOfOffset(cursorOffset); + int numOfLine = doc.getNumberOfLines(); + int docLen = doc.getLength(); + + if (lineNum <= 0) { + styledText.setSelection(startOffset, 0); + return; + } + + // ignore empty lines when going back; + int beginOffsetCurrentLine = 0; + int endOffsetCurrentLine = 0; + String currentLine = ""; + while (lineNum > 0) { + beginOffsetCurrentLine = doc.getLineOffset(lineNum); + endOffsetCurrentLine = (lineNum < numOfLine-1) ? doc.getLineOffset(lineNum+1) - 1 : docLen - 1; + currentLine = doc.get(beginOffsetCurrentLine, endOffsetCurrentLine - beginOffsetCurrentLine + 1); + if (currentLine.trim().isEmpty()) { + lineNum--; + } + else + break; + } + if (lineNum == 0) { + styledText.setSelection(startOffset, 0); + return; + } + + + // if previous line has different indentation and cursor is not + // in the beginning of current block, then go to the beginning. + beginOffsetCurrentLine = doc.getLineOffset(lineNum); + int cursorColumn = cursorOffset - beginOffsetCurrentLine; + int newOffset = beginOffsetCurrentLine; + while (newOffset < docLen) { + Character ch = doc.getChar(newOffset); + if (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n') + break; + else + newOffset++; + } + int currentIndent = newOffset - beginOffsetCurrentLine; + + + int beginOffsetPrevLine = doc.getLineOffset(lineNum-1); + int endOffsetPrevLine = doc.getLineOffset(lineNum) - 1; + String prevLine = doc.get(beginOffsetPrevLine, endOffsetPrevLine - beginOffsetPrevLine + 1); + int prevIndent = computeIndent(prevLine); + if (prevLine.trim().isEmpty() && cursorColumn > currentIndent) { + newOffset = beginOffsetCurrentLine;// + currentIndent; + styledText.setSelection(startOffset, newOffset); + return; + } + else if ((prevIndent != currentIndent) && (cursorColumn > currentIndent)) { + newOffset = beginOffsetCurrentLine;// + currentIndent; + styledText.setSelection(startOffset, newOffset); + return; + } + + // ignore empty lines when going back; + lineNum--; + endOffsetCurrentLine = 0; + currentLine = ""; + while (lineNum > 0) { + beginOffsetCurrentLine = doc.getLineOffset(lineNum); + endOffsetCurrentLine = (lineNum < numOfLine-1) ? doc.getLineOffset(lineNum+1) - 1 : docLen; + currentLine = doc.get(beginOffsetCurrentLine, endOffsetCurrentLine - beginOffsetCurrentLine + 1); + if (currentLine.trim().isEmpty()) { + lineNum--; + } + else + break; + } + if (lineNum == 0) { + styledText.setSelection(startOffset, 0); + return; + } + + + // search back to find the last line has different indentation + currentIndent = computeIndent(currentLine); + while (lineNum > 0) { + beginOffsetPrevLine = doc.getLineOffset(lineNum-1); + endOffsetPrevLine = doc.getLineOffset(lineNum) - 1; + prevLine = doc.get(beginOffsetPrevLine, endOffsetPrevLine - beginOffsetPrevLine + 1); + prevIndent = computeIndent(prevLine); + + if (prevLine.trim().isEmpty()) { + break; + } + else if (prevIndent == currentIndent) { + lineNum--; + currentLine = prevLine; + } + else + break; + } + newOffset = doc.getLineOffset(lineNum); +// while (newOffset < docLen) { +// Character ch = doc.getChar(newOffset); +// if (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n') +// break; +// else +// newOffset++; +// } + styledText.setSelection(startOffset, newOffset); + } catch (BadLocationException e) { + return; + } + } + + private int computeIndent(String line) { + if (line.trim().isEmpty()) + return 0; + + if (line.charAt(0) == ' ') + return 1 + computeIndent(line.substring(1)); + + if (line.charAt(0) == '\t') + return OcamlEditor.getTabSize() + computeIndent(line.substring(1)); + + return 0; + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} From a8a4e6e278c82f69e39f12fa8a7550dd41257d68 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 21 Oct 2014 01:49:58 +0800 Subject: [PATCH 080/127] move cursor and select text by blocks --- Ocaml/plugin.xml | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index b32eebc..1dee840 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -861,6 +861,34 @@ id="Ocaml_sourceActions_showTextHover" label="Show Text Hover" style="push"> + + + + + + + + + + + + + + + + @@ -1140,6 +1188,30 @@ contextId="org.eclipse.ui.contexts.window" schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" sequence="M1+F9"> + + + + + + + + From 16c2877300920fbe07d50a19b03c4d09c6f852a0 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 21 Oct 2014 13:30:22 +0800 Subject: [PATCH 081/127] precisify Def data structure by adding more information --- Ocaml/src/ocaml/parser/Def.java | 39 +++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index 0c107d2..44d17a6 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -377,6 +377,7 @@ private void cleanCopyAux(Def node, Def newNode) { def.sectionComment = d.sectionComment; def.filename = d.filename; def.body = d.body; + def.parent = newNode; newNode.add(def); } @@ -386,16 +387,40 @@ private void cleanCopyAux(Def node, Def newNode) { } private void findRealChildren(Def node, ArrayList nodes, boolean root) { - if (node.type == Type.Dummy - /* || node.type == Type.Parameter */ // Trung: this is to handle Parameter - /* || node.type == Type.Identifier */ // Trung: this is to handle ModuleAlias - || node.type == Type.Functor || node.type == Type.Sig || node.type == Type.Object - || node.type == Type.Struct || node.type == Type.In || root - /* || "_".equals(node.name) */ // Trung: this is to handle _ + // always go down when is in root + if (root) { + for (Def d : node.children) + findRealChildren(d, nodes, false); + } + // find parameter + else if (node.type == Type.Parameter) { + // created a cloned node without children to add into nodes + Def simpleNode = new Def(node); + simpleNode.children = new ArrayList(); + nodes.add(simpleNode); + + // find children + for (Def d : node.children) + findRealChildren(d, nodes, false); + } + // find aliased module + else if (node.type == Type.Identifier && node.parent.type == Type.ModuleAlias) { + nodes.add(node); + } + // go down to find real children + else if (node.type == Type.Dummy + || node.type == Type.Functor + || node.type == Type.Sig + || node.type == Type.Object + || node.type == Type.Struct + || node.type == Type.In + || node.type == Type.Identifier + /* || "_".equals(node.name) */ || "()".equals(node.name)) { for (Def d : node.children) findRealChildren(d, nodes, false); - } else { + } + else { nodes.add(node); } } From 0c321ecf01be53b059adce554eac8f265fb9a1de Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 21 Oct 2014 16:25:42 +0800 Subject: [PATCH 082/127] delete trailing whitespaces --- Ocaml/plugin.xml | 18 +++ .../actions/DeleteTrailingWhitespaces.java | 120 ++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 Ocaml/src/ocaml/editor/actions/DeleteTrailingWhitespaces.java diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index 1dee840..4f42029 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -889,6 +889,13 @@ id="Ocaml_sourceActions_moveCursorDownwardOneBlock" label="Move Cursor Downward One Block" style="push"> + + + + @@ -1212,6 +1224,12 @@ contextId="org.eclipse.ui.textEditorScope" schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" sequence="M1+["> + + diff --git a/Ocaml/src/ocaml/editor/actions/DeleteTrailingWhitespaces.java b/Ocaml/src/ocaml/editor/actions/DeleteTrailingWhitespaces.java new file mode 100644 index 0000000..5c1e047 --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/DeleteTrailingWhitespaces.java @@ -0,0 +1,120 @@ +package ocaml.editor.actions; + +import ocaml.OcamlPlugin; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.editors.text.TextEditor; + +public class DeleteTrailingWhitespaces implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + + IWorkbenchPage page = window.getActivePage(); + + if (page == null) { + OcamlPlugin.logWarning(GotoDefinition.class.getSimpleName() + + ": page is null"); + return; + } + + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart == null) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": editorPart is null"); + return; + } + + if (!(editorPart instanceof TextEditor)) { + OcamlPlugin.logError(GotoDefinition.class.getSimpleName() + + ": only works on ml and mli files"); + return; + } + + TextEditor editor = (TextEditor) editorPart; + IEditorInput editorInput = editor.getEditorInput(); + IDocument doc = editor.getDocumentProvider().getDocument(editorInput); + + TextSelection selection = (TextSelection) editor.getSelectionProvider().getSelection(); + + try { + int startLine = 0; + int endLine = 0; + if (selection.getLength() > 0) { + startLine = doc.getLineOfOffset(selection.getOffset()); + endLine = doc.getLineOfOffset(selection.getOffset() + selection.getLength()); + } + else { + startLine = 0; + endLine = doc.getNumberOfLines() - 1; + } + String newContent = removeTrailingWhitespaces(doc, startLine, endLine); + int startOffset = doc.getLineOffset(startLine); + int length = 0; + if (endLine < doc.getNumberOfLines() - 1) + length = doc.getLineOffset(endLine + 1) - doc.getLineDelimiter(endLine).length() - startOffset + 1; + else + length = doc.getLength() - startOffset; + doc.replace(startOffset, length, newContent); + editor.selectAndReveal(startOffset, newContent.length() - 1); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + private String removeTrailingWhitespaces(IDocument doc, int startLine, int endLine) throws Exception { + int line = startLine; + String newContent = ""; + while (line <= endLine) { + + int offset1 = doc.getLineOffset(line); + + if (line < doc.getNumberOfLines() - 1) { + String lineDelimiter = doc.getLineDelimiter(line); + int offset2 = doc.getLineOffset(line+1) - lineDelimiter.length(); + + String lineContent = doc.get(offset1, offset2 - offset1 + 1); + lineContent = "L" + lineContent; + lineContent = lineContent.trim(); + lineContent = lineContent.substring(1); + newContent = newContent + lineContent + lineDelimiter; + } + else { + String lineContent = doc.get(offset1, doc.getLength() - offset1); + lineContent = "L" + lineContent; + lineContent = lineContent.trim(); + lineContent = lineContent.substring(1); + newContent = newContent + lineContent; + } + + line++; + } + + return newContent; + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} From 541023fa64f808a2a25d7919c239a681c2d2e6cd Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 21 Oct 2014 22:43:16 +0800 Subject: [PATCH 083/127] improve on auto-completion --- .../completion/OcamlCompletionProcessor.java | 22 +++++++++------- Ocaml/src/ocaml/parser/Def.java | 13 ++++++---- .../parsers/OcamlNewInterfaceParser.java | 26 +++++++++++-------- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index df0e9f7..e21f103 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -291,14 +291,16 @@ private ArrayList processDottedCompletion(String comple proposals.addAll(lookupProposalsCompletionInDef(suffix, def, interfacesDefsRoot, document, offset)); } else if (def.type == Def.Type.ModuleAlias) { - String aliasedName = def.children.get(0).name; - if (prefix.equals(aliasedName)) - stop = true; - else { - prefix = aliasedName; - stop = false; + if (def.children.size() > 0) { + String aliasedName = def.children.get(0).name; + if (prefix.equals(aliasedName)) + stop = true; + else { + prefix = aliasedName; + stop = false; + } + break; } - break; } } } @@ -595,8 +597,10 @@ && isCompletionDef(travelNode)) { if (def == null || def.name == null) continue; if (def.name.startsWith(completion) - && (def.name.length() > completion.length()) - && (def.type == Def.Type.Let || def.type == Def.Type.LetIn)) { + && (def.name.length() > completion.length())) { +// && (def.type == Def.Type.Let +// || def.type == Def.Type.LetIn +// || def.type == Def.Type.Parameter)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index 44d17a6..9c13d75 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -353,9 +353,10 @@ public void buildSiblingOffsets() { } public Def cleanCopy() { + this.buildParents(); Def def = new Def("", Def.Type.Root, 0, 0); cleanCopyAux(this, def); - def.buildParents(); +// def.buildParents(); return def; } @@ -398,14 +399,18 @@ else if (node.type == Type.Parameter) { Def simpleNode = new Def(node); simpleNode.children = new ArrayList(); nodes.add(simpleNode); +// nodes.add(node); // find children for (Def d : node.children) findRealChildren(d, nodes, false); } // find aliased module - else if (node.type == Type.Identifier && node.parent.type == Type.ModuleAlias) { - nodes.add(node); + else if (node.type == Type.Identifier) { + Def parent = node.parent; + if (parent != null) + if (parent.type == Type.ModuleAlias) + nodes.add(node); } // go down to find real children else if (node.type == Type.Dummy @@ -414,8 +419,6 @@ else if (node.type == Type.Dummy || node.type == Type.Object || node.type == Type.Struct || node.type == Type.In - || node.type == Type.Identifier - /* || "_".equals(node.name) */ || "()".equals(node.name)) { for (Def d : node.children) findRealChildren(d, nodes, false); diff --git a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java index 4e5e67b..cdb5dac 100644 --- a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java +++ b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java @@ -217,7 +217,7 @@ protected IStatus run(IProgressMonitor monitor) { definition = parseModule(lines, filename, moduleName, bInterface); } catch (Throwable e) { // if there was a parsing error, we log it and we continue on to the next file - // e.printStackTrace(); + e.printStackTrace(); Def def = new Def(moduleName, Def.Type.ParserError, 0, 0); def.setFileName(filename); def.setComment("ERROR 2: The parser encountered an error while parsing this file.\n\n" @@ -329,7 +329,7 @@ private Def parseModule(String doc, String filename, String moduleName, setBodies(root, doc, parseInterface); - root.unnestTypes(null, 0); +// root.unnestTypes(null, 0); if (parser.errorReporting.errors.size() != 0) { root.type = Def.Type.ParserError; @@ -686,17 +686,21 @@ private boolean nextTo(String text, int offset1, int offset2, boolean bNewline = false; for (int i = offset1; i < offset2; i++) { - if (text.charAt(i) == '\n') { - if (bNewline) - return false; - else { - if (noNewLines) + try { + if (text.charAt(i) == '\n') { + if (bNewline) return false; - bNewline = true; - } - } else if (!Character.isWhitespace(text.charAt(i)) - && text.charAt(i) != ';') + else { + if (noNewLines) + return false; + bNewline = true; + } + } else if (!Character.isWhitespace(text.charAt(i)) + && text.charAt(i) != ';') + return false; + } catch (Exception e) { return false; + } } return true; From 871d24ae5cbe3220384fe4a0eb51e4156f6f44e8 Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 22 Oct 2014 00:11:29 +0800 Subject: [PATCH 084/127] add all identifiers to Def tree when parsing error --- Ocaml/src/ocaml/parser/Def.java | 36 +++++++++++-------- Ocaml/src/ocaml/parser/OcamlParser.g | 18 ++++++++-- Ocaml/src/ocaml/parser/OcamlParser.java | 15 ++++++-- .../parsers/OcamlNewInterfaceParser.java | 4 +-- Ocaml/src/ocaml/views/outline/OutlineJob.java | 5 ++- 5 files changed, 55 insertions(+), 23 deletions(-) diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index 9c13d75..1825175 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -352,17 +352,17 @@ public void buildSiblingOffsets() { } } - public Def cleanCopy() { + public Def cleanCopy(boolean parserError) { this.buildParents(); Def def = new Def("", Def.Type.Root, 0, 0); - cleanCopyAux(this, def); + cleanCopyAux(this, def, parserError); // def.buildParents(); return def; } - private void cleanCopyAux(Def node, Def newNode) { + private void cleanCopyAux(Def node, Def newNode, boolean parserError) { ArrayList realNodes = new ArrayList(); - findRealChildren(node, realNodes, true); + findRealChildren(node, realNodes, true, parserError); for (Def d : realNodes) { Def def = new Def(d.name, d.type, d.posStart, d.posEnd); @@ -384,14 +384,14 @@ private void cleanCopyAux(Def node, Def newNode) { } for (int i = 0; i < realNodes.size(); i++) - cleanCopyAux(realNodes.get(i), newNode.children.get(i)); + cleanCopyAux(realNodes.get(i), newNode.children.get(i), parserError); } - private void findRealChildren(Def node, ArrayList nodes, boolean root) { + private void findRealChildren(Def node, ArrayList nodes, boolean root, boolean parserError) { // always go down when is in root if (root) { for (Def d : node.children) - findRealChildren(d, nodes, false); + findRealChildren(d, nodes, false, parserError); } // find parameter else if (node.type == Type.Parameter) { @@ -399,18 +399,26 @@ else if (node.type == Type.Parameter) { Def simpleNode = new Def(node); simpleNode.children = new ArrayList(); nodes.add(simpleNode); -// nodes.add(node); // find children for (Def d : node.children) - findRealChildren(d, nodes, false); + findRealChildren(d, nodes, false, parserError); } // find aliased module else if (node.type == Type.Identifier) { - Def parent = node.parent; - if (parent != null) - if (parent.type == Type.ModuleAlias) - nodes.add(node); + // add all identifiers when parser error + if (parserError) { + nodes.add(node); + } + // if no parser error, add selected identifiers + else { + Def parent = node.parent; + if (parent != null) { + if (parent.type == Type.ModuleAlias) + nodes.add(node); + } + } + } // go down to find real children else if (node.type == Type.Dummy @@ -421,7 +429,7 @@ else if (node.type == Type.Dummy || node.type == Type.In || "()".equals(node.name)) { for (Def d : node.children) - findRealChildren(d, nodes, false); + findRealChildren(d, nodes, false, parserError); } else { nodes.add(node); diff --git a/Ocaml/src/ocaml/parser/OcamlParser.g b/Ocaml/src/ocaml/parser/OcamlParser.g index fe77a8b..e3784b7 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.g +++ b/Ocaml/src/ocaml/parser/OcamlParser.g @@ -2237,13 +2237,25 @@ signed_constant= ident= UIDENT.id /*{ $1 }*/ - {: return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); :} + {: + Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + backup(def); + return def; + :} | LIDENT.id /*{ $1 }*/ - {: return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); :} + {: + Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + backup(def); + return def; + :} ; val_ident= LIDENT.id /*{ $1 }*/ - {: return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); :} + {: + Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + backup(def); + return def; + :} | LPAREN operator.o RPAREN /*{ $2 }*/ {: Def op = (Def)o; diff --git a/Ocaml/src/ocaml/parser/OcamlParser.java b/Ocaml/src/ocaml/parser/OcamlParser.java index 09cf717..5aefbc2 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.java +++ b/Ocaml/src/ocaml/parser/OcamlParser.java @@ -4386,19 +4386,28 @@ public Symbol reduce(Symbol[] _symbols, int offset) { new Action() { // [465] ident = UIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; - return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + + Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + backup(def); + return def; } }, new Action() { // [466] ident = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; - return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + + Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + backup(def); + return def; } }, new Action() { // [467] val_ident = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; - return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + + Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + backup(def); + return def; } }, new Action() { // [468] val_ident = LPAREN operator.o RPAREN diff --git a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java index cdb5dac..4419386 100644 --- a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java +++ b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java @@ -292,6 +292,7 @@ private Def parseModule(String doc, String filename, String moduleName, root = (Def) parser.parse(scanner, OcamlParser.AltGoals.interfaces); else root = (Def) parser.parse(scanner); + root = root.cleanCopy(false); } catch (Exception e) { // recover pieces from the AST (which couldn't be built completely // because of an unrecoverable error) @@ -302,12 +303,11 @@ private Def parseModule(String doc, String filename, String moduleName, def.bTop = false; root.children.add(def); } + root = root.cleanCopy(true); } } - root = root.cleanCopy(); - root.name = moduleName; // set the start offset from the packed (line, column) positions diff --git a/Ocaml/src/ocaml/views/outline/OutlineJob.java b/Ocaml/src/ocaml/views/outline/OutlineJob.java index a58095c..e6d2cf0 100644 --- a/Ocaml/src/ocaml/views/outline/OutlineJob.java +++ b/Ocaml/src/ocaml/views/outline/OutlineJob.java @@ -285,6 +285,7 @@ else if (!("ml4".equals(extension) || "mlp".equals(extension))) * recover pieces from the AST (which couldn't be built completely because of an * unrecoverable error) */ + boolean parserError = false; if (root == null || !parser.errorReporting.errors.isEmpty()) { // System.err.println("recovering"); // System.err.println("recovering AST"); @@ -295,6 +296,8 @@ else if (!("ml4".equals(extension) || "mlp".equals(extension))) def.bTop = false; root.children.add(def); } + + parserError = true; } /* @@ -324,7 +327,7 @@ else if (!("ml4".equals(extension) || "mlp".equals(extension))) definitions.setInInAttribute(); - Def outlineDefinitions = definitions.cleanCopy(); + Def outlineDefinitions = definitions.cleanCopy(parserError); // remove the definitions the user has chosen not to display initPreferences(); cleanOutline(outlineDefinitions); From 7e9e9e23583be04a092b88365acedfa3cb62dd8e Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 22 Oct 2014 00:44:51 +0800 Subject: [PATCH 085/127] show type of functions in built-in library and external functions --- .../completion/OcamlCompletionProcessor.java | 57 ++++++++++++------- .../completion/OcamlCompletionProposal.java | 5 +- Ocaml/src/ocaml/parser/Def.java | 8 +-- 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index e21f103..9b55122 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -27,6 +27,7 @@ import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.contentassist.IContextInformationValidator; +import org.eclipse.ui.dialogs.NewFolderDialog; import org.eclipse.ui.editors.text.TextEditor; import org.eclipse.ui.editors.text.TextFileDocumentProvider; import org.eclipse.ui.texteditor.IDocumentProvider; @@ -934,35 +935,49 @@ public String getErrorMessage() { private Def createProposalDef(IProject project, Def def) { Def newDef = new Def(def); if (newDef.type == Def.Type.Let - || newDef.type == Def.Type.LetIn) { - String filename = newDef.getFileName(); + || newDef.type == Def.Type.LetIn + || newDef.type == Def.Type.External) { - // store last used annotation for caching - TypeAnnotation[] annotations; - long currentTime = System.currentTimeMillis(); - if (filename.equals(lastParsedFileName) - && (currentTime - lastParsedTime < cacheTime)) { - annotations = lastUsedAnnotations; + String typeInfo = ""; + + // look for type infor in body first + String body = newDef.getBody(); + int index = body.indexOf(newDef.name); + if (index >= 0 && body.length() > newDef.name.length()) { + typeInfo = body.substring(index); + newDef.setOcamlType(typeInfo); } - else { - annotations = parseModuleAnnotation(project, filename); - lastUsedAnnotations = annotations; - lastParsedFileName = filename; - lastParsedTime = System.currentTimeMillis(); + + // not found type in body + if (typeInfo.isEmpty()) { + String filename = newDef.getFileName(); + + // store last used annotation for caching + TypeAnnotation[] annotations; + long currentTime = System.currentTimeMillis(); + if (filename.equals(lastParsedFileName) + && (currentTime - lastParsedTime < cacheTime)) { + annotations = lastUsedAnnotations; + } + else { + annotations = parseModuleAnnotation(project, filename); + lastUsedAnnotations = annotations; + lastParsedFileName = filename; + lastParsedTime = System.currentTimeMillis(); + } + + IDocument document = getDocument(project, filename); + typeInfo = computeTypeInfo(newDef, annotations, document); + if (!typeInfo.isEmpty()) { + newDef.setOcamlType(typeInfo); + newDef.setBody("val " + typeInfo); + } } - - IDocument document = getDocument(project, filename); - String typeInfo = computeTypeInfo(newDef, annotations, document); - if (typeInfo.isEmpty()) - typeInfo = newDef.name + " - "; - newDef.setOcamlType(typeInfo); } else if (def.type == Def.Type.Type) { String typeInfo = newDef.name + " 't"; newDef.setOcamlType(typeInfo); } - // Trung: uncomment to debug def type - // newDef.setBody(newDef.getBody() + " -- def type: " + newDef.getTypeName()); return newDef; } diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java index bd01970..2166f7b 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProposal.java @@ -112,8 +112,9 @@ public Image getImage() { public String getDisplayString() { String displayString = definition.name; - if (definition.type == Def.Type.Let || definition.type == Def.Type.LetIn) { - String typeInfo = Misc.beautify(Def.clean(definition.getOcamlType())); + String typeInfo = Misc.beautify(Def.cleanString(definition.getOcamlType())); + + if (!typeInfo.isEmpty()) { if (typeInfo.startsWith(definition.name)) displayString = typeInfo; else diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index 1825175..09e14cd 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -554,24 +554,24 @@ public void appendToComment(String comment) { this.comment = this.comment + "\n________________________________________\n\n" + comment; - this.comment = clean(this.comment); + this.comment = cleanString(this.comment); } public String sectionComment = ""; public void setSectionComment(String text) { - this.sectionComment = clean(text); + this.sectionComment = cleanString(text); } public void setComment(String text) { if (text.equals("/*")) return; - this.comment = clean(text); + this.comment = cleanString(text); } - public static String clean(String str) { + public static String cleanString(String str) { if (str == null) return ""; From 8bb60bdd7458466c7f74626c0249b241c29df2b7 Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 22 Oct 2014 14:13:54 +0800 Subject: [PATCH 086/127] suggest proposals which are longer than completion text --- .../completion/OcamlCompletionProcessor.java | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 9b55122..02f9cea 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -332,7 +332,7 @@ else if (def.type == Def.Type.ModuleAlias) { if (def2.name.equals(involvedModuleName)) { Def involvedDefRoot = def2; for (Def def3: involvedDefRoot.children) { - if (def3.name.startsWith(newCompletion) && isCompletionDef(def3)) { + if (checkCompletion(def3, newCompletion) && isCompletionDef(def3)) { Def proposedDef = createProposalDef(project, def3); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } @@ -343,7 +343,7 @@ else if (def.type == Def.Type.ModuleAlias) { if (def2.name.equals(involvedModuleName)) { Def involvedDefRoot = def2; for (Def def3: involvedDefRoot.children) { - if (def3.name.startsWith(newCompletion) && isCompletionDef(def3)) { + if (checkCompletion(def3, newCompletion) && isCompletionDef(def3)) { Def proposedDef = createProposalDef(project, def3); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } @@ -366,7 +366,7 @@ else if (def.type == Def.Type.ModuleAlias) { // find elements starting by in the list of elements else { for (Def def : interfacesDefsRoot.children) { - if (def.name.startsWith(completion) && isCompletionDef(def)) { + if (checkCompletion(def, completion) && isCompletionDef(def)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } @@ -392,7 +392,7 @@ private ArrayList processNondottedCompletion(String com * look in def root */ for (Def def: interfacesDefsRoot.children) { - if (def.name.startsWith(completion)) { + if (checkCompletion(def, completion)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } @@ -415,7 +415,7 @@ private ArrayList processNondottedCompletion(String com proposals.addAll(bottomUpFindProposals(completion, nearestDef, offset)); for (Def def: currentDef.children) { - if (def.name.startsWith(completion)) { + if (checkCompletion(def, completion)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } @@ -472,7 +472,7 @@ private ArrayList processNondottedCompletion(String com if (d == null || d.name == null) break; - if (d.name.startsWith(completion) && isCompletionDef(d)) { + if (checkCompletion(d, completion) && isCompletionDef(d)) { Def proposedDef = createProposalDef(project, d); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } @@ -543,7 +543,7 @@ private ArrayList lookupProposalsCompletionInDef(String else { // look inside def roots first for (Def def : defsRoot.children) { - if (def.name.startsWith(completion) && isCompletionDef(def)) { + if (checkCompletion(def, completion) && isCompletionDef(def)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } @@ -587,9 +587,7 @@ private ArrayList bottomUpFindProposals(String completi if (travelNode == null || travelNode.name == null) break; - if (travelNode.name.startsWith(completion) - && (travelNode.name.length() > completion.length()) - && isCompletionDef(travelNode)) { + if (checkCompletion(travelNode, completion) && isCompletionDef(travelNode)) { Def proposedDef = createProposalDef(project, travelNode); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); } @@ -597,8 +595,7 @@ && isCompletionDef(travelNode)) { for (Def def : travelNode.children) { if (def == null || def.name == null) continue; - if (def.name.startsWith(completion) - && (def.name.length() > completion.length())) { + if (checkCompletion(def, completion)) { // && (def.type == Def.Type.Let // || def.type == Def.Type.LetIn // || def.type == Def.Type.Parameter)) { @@ -661,6 +658,19 @@ private Def findSmallestDefAtOffset(Def def, int offset, IDocument doc) { return findSmallestDefAtOffset(nearestChild, offset, doc); } + + private boolean checkCompletion(Def def, String completion) { + if (def == null) + return false; + + if (def.name == null) + return false; + + if (def.name.startsWith(completion) && def.name.length() > completion.length()) + return true; + + return false; + } private boolean isCompletionDef(Def def) { switch (def.type) { From 12b84ddbd63737077a5730bc4215ff619e5240b5 Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 22 Oct 2014 14:54:23 +0800 Subject: [PATCH 087/127] unnest type constructors --- Ocaml/src/ocaml/parser/Def.java | 2 +- Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index 09e14cd..c6c7a54 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -529,7 +529,7 @@ public IRegion getRegion(IDocument doc) { try { lineOffset = doc.getLineOffset(getLine(posStart)); } catch (BadLocationException e) { - OcamlPlugin.logError("offset error", e); +// OcamlPlugin.logError("offset error", e); return null; } diff --git a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java index 4419386..877085b 100644 --- a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java +++ b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java @@ -329,7 +329,7 @@ private Def parseModule(String doc, String filename, String moduleName, setBodies(root, doc, parseInterface); -// root.unnestTypes(null, 0); + root.unnestTypes(null, 0); if (parser.errorReporting.errors.size() != 0) { root.type = Def.Type.ParserError; From d68541116794f504747b72e90011bb6d4858681f Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 22 Oct 2014 18:03:54 +0800 Subject: [PATCH 088/127] recover more information of Def tree when parsing error --- .../completion/OcamlCompletionProcessor.java | 6 +- .../ocaml/editors/OcamlHyperlinkDetector.java | 12 +- Ocaml/src/ocaml/parser/Def.java | 31 +++- Ocaml/src/ocaml/parser/OcamlParser.g | 150 ++++++++++-------- Ocaml/src/ocaml/parser/OcamlParser.java | 150 ++++++++++-------- .../src/ocaml/parsers/Camlp4Preprocessor.java | 2 +- .../parsers/OcamlNewInterfaceParser.java | 5 + .../views/outline/OcamlOutlineControl.java | 2 +- Ocaml/src/ocaml/views/outline/OutlineJob.java | 7 +- .../src/ocaml/views/outline/QuickOutline.java | 2 +- 10 files changed, 221 insertions(+), 146 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 02f9cea..ee8e25b 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -639,7 +639,7 @@ private Def findSmallestDefAtOffset(Def def, int offset, IDocument doc) { return def; Def firstChild = def.children.get(0); - IRegion region = firstChild.getRegion(doc); + IRegion region = firstChild.getNameRegion(doc); if (region != null) { if (region.getOffset() > offset) return def; @@ -649,7 +649,7 @@ private Def findSmallestDefAtOffset(Def def, int offset, IDocument doc) { Def nearestChild = null; for (Def d : def.children) { - region = d.getRegion(doc); + region = d.getNameRegion(doc); if (region != null) { if (region.getOffset() < offset) nearestChild = d; @@ -1055,7 +1055,7 @@ private TypeAnnotation[] parseModuleAnnotation(IProject project, String filename private String computeTypeInfo(Def def, TypeAnnotation[] annotations, IDocument document) { try { String typeInfo = ""; - IRegion region = def.getRegion(document); + IRegion region = def.getNameRegion(document); int offset = region.getOffset(); ArrayList found = new ArrayList(); diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index 7590520..3c65412 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -140,7 +140,7 @@ public void open() { Def target = findDefinitionOf(def, moudulesRoot, interfacesRoot); if (target == null) return; - IRegion region = target.getRegion(textViewer.getDocument()); + IRegion region = target.getNameRegion(textViewer.getDocument()); editor.selectAndReveal(region.getOffset(), region.getLength()); } @@ -153,7 +153,7 @@ public String getHyperlinkText() { } public IRegion getHyperlinkRegion() { - return def.getRegion(textViewer.getDocument()); + return def.getNameRegion(textViewer.getDocument()); } }; @@ -169,7 +169,7 @@ public void open() { Def target = findDefinitionOf(strDef, moudulesRoot, interfacesRoot); if (target == null) return; - IRegion region = target.getRegion(textViewer.getDocument()); + IRegion region = target.getNameRegion(textViewer.getDocument()); editor.selectAndReveal(region.getOffset(), region.getLength()); } @@ -532,7 +532,7 @@ private boolean openDefInInterfaces(int index, final String[] path, Def interfac ITextViewer textViewer = editor.getTextViewer(); if (interfaceDef != null) { - IRegion region = interfaceDef.getRegion(textViewer.getDocument()); + IRegion region = interfaceDef.getNameRegion(textViewer.getDocument()); editor.selectAndReveal(region.getOffset(), region.getLength()); } } else @@ -652,7 +652,7 @@ private Def findIdentAt(Def def, int offset, IDocument doc) { if (def == null || doc == null) return null; - IRegion region = def.getRegion(doc); + IRegion region = def.getNameRegion(doc); if (region == null) return null; @@ -832,7 +832,7 @@ public String getHyperlinkText() { } public IRegion getHyperlinkRegion() { - return searchedDef.getRegion(textViewer.getDocument()); + return searchedDef.getNameRegion(textViewer.getDocument()); } }; } diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index c6c7a54..50d8183 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -301,6 +301,13 @@ void findIdents(ArrayList idents) { for (Def child : children) child.findIdents(idents); } + + void findDefNames(ArrayList defNames) { + if (this.name != null && !this.name.isEmpty()) + defNames.add(this.name); + for (Def child: children) + child.findDefNames(defNames); + } /** Find all the "lets" in the tree rooted at this definition (and do not go further down) */ void findLets(ArrayList idents) { @@ -524,7 +531,7 @@ public void unnestTypes(Def parent, int index) { } /** Returns the region in the document covered by the name of the definition */ - public IRegion getRegion(IDocument doc) { + public IRegion getNameRegion(IDocument doc) { int lineOffset = 0; try { lineOffset = doc.getLineOffset(getLine(posStart)); @@ -539,6 +546,28 @@ public IRegion getRegion(IDocument doc) { return new Region(startOffset, endOffset - startOffset + 1); } + + /** Returns the region in the document covered by this definition and its body */ + public Region getFullRegion() { + // startOffset is computed by def name + int startOffset = posStart; + + // endOffset is computed by def's full definition + Def lastDescendant = this; + while (lastDescendant.children != null & lastDescendant.children.size() > 0) { + ArrayList children = lastDescendant.children; + for (int i = children.size() - 1; i >= 0; i--) { + if (children.get(i) != null) { + lastDescendant = children.get(i); + break; + } + } + } + int endOffset = lastDescendant.posEnd; + + return new Region(startOffset, endOffset - startOffset + 1); + } + /** The ocamldoc comment associated with this definition */ public String comment = ""; diff --git a/Ocaml/src/ocaml/parser/OcamlParser.g b/Ocaml/src/ocaml/parser/OcamlParser.g index e3784b7..1999c10 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.g +++ b/Ocaml/src/ocaml/parser/OcamlParser.g @@ -4,6 +4,7 @@ %package "ocaml.parser"; %import "java.util.ArrayList"; +%import "org.eclipse.jface.text.Region"; %embed {: public ErrorReporting errorReporting; @@ -16,12 +17,29 @@ we use the "bTop" boolean to know if this definition should be added to the outline */ public ArrayList recoverDefs = new ArrayList(); + public ArrayList recoverIdents = new ArrayList(); + /** backup a node, so as to be able to later recover from a parsing error */ - private void backup(Def def){ + private void backupDef(Def def){ recoverDefs.add(def); for(Def child: def.children) //child.bTop = false; unsetTop(child); + + // remove all identifiers that is used to build this def + Region region = def.getFullRegion(); + ArrayList usedIdents = new ArrayList(); + for (Def ident: recoverIdents) + if (ident.posStart >= region.getOffset() + && (ident.posEnd <= region.getOffset() + region.getLength())) + usedIdents.add(ident); + recoverIdents.removeAll(usedIdents); + } + + // backup identifiers for later recovering from a parsing error, + // some will be removed when they are used to build a Def sucessfully + private void backupIdent(Def def) { + recoverIdents.add(def); } private void unsetTop(Def def){ @@ -285,7 +303,7 @@ module_expr= Def def = new Def("", Def.Type.Struct, s.getStart(), s.getEnd()); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; :} | STRUCT.a structure.s error @@ -293,7 +311,7 @@ module_expr= Def def = new Def("", Def.Type.Struct, a.getStart(), a.getEnd()); def.add(s); def.collapse(); - backup(def); + backupDef(def); return def; :} | FUNCTOR LPAREN UIDENT.i COLON module_type.a RPAREN MINUSGREATER module_expr.b @@ -302,7 +320,7 @@ module_expr= def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; :} | module_expr.a LPAREN module_expr.b RPAREN @@ -366,7 +384,7 @@ structure_item= def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; :} | TYPE type_declarations.t @@ -376,7 +394,7 @@ structure_item= Def def = new Def((String)id.value, Def.Type.Exception, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} | EXCEPTION UIDENT.id EQUAL constr_longident.a @@ -384,7 +402,7 @@ structure_item= Def def = new Def((String)id.value, Def.Type.Exception, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} | MODULE UIDENT.id module_binding.a @@ -396,7 +414,7 @@ structure_item= Def def = new Def((String)id.value, type, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} | MODULE REC module_rec_bindings.a @@ -407,14 +425,14 @@ structure_item= Def def = new Def(ident.name, Def.Type.ModuleType, ident.posStart, ident.posEnd); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} | OPEN mod_longident.id {: Def ident = (Def)id; Def def = new Def(ident.name, Def.Type.Open, ident.posStart, ident.posEnd); - backup(def); + backupDef(def); return def; :} | CLASS class_declarations.a @@ -426,7 +444,7 @@ structure_item= Def ident = (Def)id; if(ident.type == Def.Type.Identifier){ Def def = new Def(ident.name, Def.Type.Include, ident.posStart, ident.posEnd); - backup(def); + backupDef(def); return def; } return new Def(); @@ -460,7 +478,7 @@ module_rec_binding= def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; :} ; @@ -475,7 +493,7 @@ module_type= Def def = new Def("", Def.Type.Sig, s.getStart(), s.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} | SIG signature error @@ -487,7 +505,7 @@ module_type= def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; :} | module_type.a WITH with_constraints.b @@ -518,7 +536,7 @@ signature_item= // add the start position of the definition def.defPosStart = v.getStart(); - backup(def); + backupDef(def); return def; :} | EXTERNAL.e val_ident.id COLON core_type.a EQUAL primitive_declaration.b @@ -529,7 +547,7 @@ signature_item= def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; :} | TYPE.t type_declarations.a @@ -546,7 +564,7 @@ signature_item= def.defPosStart = e.getStart(); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} | MODULE.m UIDENT.id module_declaration.a @@ -555,7 +573,7 @@ signature_item= def.defPosStart = m.getStart(); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} | MODULE.m REC module_rec_declarations.a @@ -571,7 +589,7 @@ signature_item= Def ident = (Def)id; Def def = new Def(ident.name, Def.Type.ModuleType, ident.posStart, ident.posEnd); def.defPosStart = m.getStart(); - backup(def); + backupDef(def); return def; :} | MODULE.m TYPE ident.id EQUAL module_type.a @@ -581,7 +599,7 @@ signature_item= def.defPosStart = m.getStart(); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} | OPEN.o mod_longident.id @@ -589,7 +607,7 @@ signature_item= Def ident = (Def)id; Def def = new Def(ident.name, Def.Type.Open, ident.posStart, ident.posEnd); def.defPosStart = o.getStart(); - backup(def); + backupDef(def); return def; :} | INCLUDE.i module_type.id @@ -598,7 +616,7 @@ signature_item= if(ident.type == Def.Type.Identifier){ Def def = new Def(ident.name, Def.Type.Include, ident.posStart, ident.posEnd); def.defPosStart = i.getStart(); - backup(def); + backupDef(def); return def; } return new Def(); @@ -646,7 +664,7 @@ module_rec_declaration= Def def = new Def((String)id.value, Def.Type.Module, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} ; @@ -670,7 +688,7 @@ class_declaration= def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; :} ; @@ -722,7 +740,7 @@ class_expr= in.collapse(); last.children.add(in); last.collapse(); - backup(last); + backupDef(last); return a; } @@ -739,7 +757,7 @@ class_simple_expr= Def def = new Def("", Def.Type.Object, o.getStart(), o.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} @@ -777,7 +795,7 @@ class_fields= if(ident.type == Def.Type.Identifier){ Def def = new Def(ident.name, Def.Type.Val, ident.posStart, ident.posEnd); def.defPosStart = v.getStart(); - backup(def); + backupDef(def); return Def.root(a, def); } return Def.root(a,id); @@ -788,7 +806,7 @@ class_fields= if(ident.type == Def.Type.Identifier){ Def def = new Def(ident.name, Def.Type.Val, ident.posStart, ident.posEnd); def.defPosStart = v.getStart(); - backup(def); + backupDef(def); return Def.root(a, def); } return Def.root(a,id); @@ -802,7 +820,7 @@ class_fields= Def def = new Def("", Def.Type.Constraint, c.getStart(), c.getEnd()); def.add(b); def.collapse(); - backup(def); + backupDef(def); return Def.root(a, def); :} | class_fields.a INITIALIZER.i seq_expr.b @@ -811,7 +829,7 @@ class_fields= def.defPosStart = i.getStart(); def.add(b); def.collapse(); - backup(def); + backupDef(def); return Def.root(a, def); :} ; @@ -834,7 +852,7 @@ virtual_value= def.add(a); def.collapse(); def.bAlt = true; - backup(def); + backupDef(def); return def; :} | VIRTUAL.v mutable_flag.m label.id COLON core_type.a @@ -846,7 +864,7 @@ virtual_value= def.add(a); def.collapse(); def.bAlt = ((Def)m).bAlt; - backup(def); + backupDef(def); return def; :} ; @@ -862,7 +880,7 @@ value= def.add(a); def.collapse(); def.bAlt = ((Def)o).bAlt || ((Def)m).bAlt; - backup(def); + backupDef(def); return def; :} | override_flag.o mutable_flag.m label.id type_constraint.a EQUAL seq_expr.b @@ -877,7 +895,7 @@ value= def.add(b); def.collapse(); def.bAlt = ((Def)o).bAlt || ((Def)m).bAlt; - backup(def); + backupDef(def); return def; :} ; @@ -891,7 +909,7 @@ virtual_method= def.add(a); def.collapse(); def.bAlt = true; - backup(def); + backupDef(def); return def; :} | METHOD.m override_flag.o VIRTUAL private_flag.p label.id COLON poly_type.a @@ -903,7 +921,7 @@ virtual_method= def.add(a); def.collapse(); def.bAlt = ((Def)o).bAlt || ((Def)p).bAlt; - backup(def); + backupDef(def); return def; :} ; @@ -917,7 +935,7 @@ concrete_method = def.add(a); def.collapse(); def.bAlt = ((Def)o).bAlt || ((Def)p).bAlt; - backup(def); + backupDef(def); return def; :} | METHOD.m override_flag.o private_flag.p label.id COLON poly_type.a EQUAL seq_expr.b @@ -930,7 +948,7 @@ concrete_method = def.add(b); def.collapse(); def.bAlt = ((Def)o).bAlt || ((Def)p).bAlt; - backup(def); + backupDef(def); return def; :} ; @@ -960,7 +978,7 @@ class_signature= Def def = new Def("", Def.Type.Object, o.getStart(), o.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} | OBJECT class_sig_body error @@ -1003,7 +1021,7 @@ value_type= def.add(a); def.collapse(); def.bAlt = ((Def)m).bAlt; - backup(def); + backupDef(def); return def; :} | MUTABLE virtual_flag label.id COLON core_type.a @@ -1014,7 +1032,7 @@ value_type= def.add(a); def.collapse(); def.bAlt = true; - backup(def); + backupDef(def); return def; :} | label.id COLON core_type.a @@ -1024,7 +1042,7 @@ value_type= Def def = new Def(ident.name, Def.Type.Val, ident.posStart, ident.posEnd); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} ; @@ -1037,7 +1055,7 @@ method_type= def.defPosStart = m.getStart(); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} ; @@ -1050,7 +1068,7 @@ virtual_method_type= def.defPosStart = m.getStart(); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} | METHOD.m VIRTUAL private_flag label.id COLON poly_type.a @@ -1061,7 +1079,7 @@ virtual_method_type= def.defPosStart = m.getStart(); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} ; @@ -1086,7 +1104,7 @@ class_description= Def def = new Def((String)id.value, Def.Type.Class, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} ; @@ -1107,7 +1125,7 @@ class_type_declaration= Def def = new Def((String)id.value, Def.Type.ClassType, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} ; @@ -1212,7 +1230,7 @@ expr= in.collapse(); last.children.add(in); last.collapse(); - backup(last); + backupDef(last); return a; } @@ -1224,7 +1242,7 @@ expr= def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; :} | LET OPEN mod_longident.id IN seq_expr.a @@ -1236,7 +1254,7 @@ expr= in.collapse(); def.children.add(in); def.collapse(); - backup(def); + backupDef(def); return def; :} | FUNCTION opt_bar.a match_cases.b @@ -1376,7 +1394,7 @@ expr= Def def = new Def("", Def.Type.Object, o.getStart(), o.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} | OBJECT class_structure error @@ -1499,7 +1517,7 @@ let_binding= Def def = new Def(ident.name, Def.Type.Let, ident.posStart, ident.posEnd); def.add(f); def.collapse(); - backup(def); + backupDef(def); return def; :} | val_ident.i COLON typevar_list DOT core_type EQUAL seq_expr.b @@ -1508,7 +1526,7 @@ let_binding= Def def = new Def(ident.name, Def.Type.Let, ident.posStart, ident.posEnd); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; :} | pattern.p EQUAL seq_expr.b @@ -1538,7 +1556,7 @@ let_binding= if(last != null){ last.add(b); last.collapse(); - backup(root); + backupDef(root); return root; } @@ -1583,7 +1601,7 @@ strict_binding= if(last != null){ last.add(b); last.collapse(); - backup(root); + backupDef(root); return root; } @@ -1897,7 +1915,7 @@ type_declaration= Def def = new Def((String)id.value, Def.Type.Type, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; :} ; @@ -2238,23 +2256,23 @@ signed_constant= ident= UIDENT.id /*{ $1 }*/ {: - Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); - backup(def); - return def; + Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + backupIdent(def); + return def; :} | LIDENT.id /*{ $1 }*/ {: - Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); - backup(def); - return def; + Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + backupIdent(def); + return def; :} ; val_ident= LIDENT.id /*{ $1 }*/ - {: - Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); - backup(def); - return def; + {: + Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + backupIdent(def); + return def; :} | LPAREN operator.o RPAREN /*{ $2 }*/ {: diff --git a/Ocaml/src/ocaml/parser/OcamlParser.java b/Ocaml/src/ocaml/parser/OcamlParser.java index 5aefbc2..89fd166 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.java +++ b/Ocaml/src/ocaml/parser/OcamlParser.java @@ -1,6 +1,7 @@ package ocaml.parser; import java.util.ArrayList; +import org.eclipse.jface.text.Region; import beaver.*; /** @@ -749,12 +750,29 @@ the root node (typically, when the user is changing code). In this case, we use we use the "bTop" boolean to know if this definition should be added to the outline */ public ArrayList recoverDefs = new ArrayList(); + public ArrayList recoverIdents = new ArrayList(); + /** backup a node, so as to be able to later recover from a parsing error */ - private void backup(Def def){ + private void backupDef(Def def){ recoverDefs.add(def); for(Def child: def.children) //child.bTop = false; unsetTop(child); + + // remove all identifiers that is used to build this def + Region region = def.getFullRegion(); + ArrayList usedIdents = new ArrayList(); + for (Def ident: recoverIdents) + if (ident.posStart >= region.getOffset() + && (ident.posEnd <= region.getOffset() + region.getLength())) + usedIdents.add(ident); + recoverIdents.removeAll(usedIdents); + } + + // backup identifiers for later recovering from a parsing error, + // some will be removed when they are used to build a Def sucessfully + private void backupIdent(Def def) { + recoverIdents.add(def); } private void unsetTop(Def def){ @@ -905,7 +923,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def("", Def.Type.Struct, s.getStart(), s.getEnd()); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -917,7 +935,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def("", Def.Type.Struct, a.getStart(), a.getEnd()); def.add(s); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -931,7 +949,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1060,7 +1078,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1078,7 +1096,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def((String)id.value, Def.Type.Exception, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1090,7 +1108,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def((String)id.value, Def.Type.Exception, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1106,7 +1124,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def((String)id.value, type, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1125,7 +1143,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def(ident.name, Def.Type.ModuleType, ident.posStart, ident.posEnd); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1135,7 +1153,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def ident = (Def)id; Def def = new Def(ident.name, Def.Type.Open, ident.posStart, ident.posEnd); - backup(def); + backupDef(def); return def; } }, @@ -1158,7 +1176,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def ident = (Def)id; if(ident.type == Def.Type.Identifier){ Def def = new Def(ident.name, Def.Type.Include, ident.posStart, ident.posEnd); - backup(def); + backupDef(def); return def; } return new Def(); @@ -1210,7 +1228,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1228,7 +1246,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def("", Def.Type.Sig, s.getStart(), s.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1247,7 +1265,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1308,7 +1326,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { // add the start position of the definition def.defPosStart = v.getStart(); - backup(def); + backupDef(def); return def; } }, @@ -1325,7 +1343,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1351,7 +1369,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.defPosStart = e.getStart(); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1365,7 +1383,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.defPosStart = m.getStart(); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1389,7 +1407,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def ident = (Def)id; Def def = new Def(ident.name, Def.Type.ModuleType, ident.posStart, ident.posEnd); def.defPosStart = m.getStart(); - backup(def); + backupDef(def); return def; } }, @@ -1404,7 +1422,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.defPosStart = m.getStart(); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1416,7 +1434,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def ident = (Def)id; Def def = new Def(ident.name, Def.Type.Open, ident.posStart, ident.posEnd); def.defPosStart = o.getStart(); - backup(def); + backupDef(def); return def; } }, @@ -1429,7 +1447,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { if(ident.type == Def.Type.Identifier){ Def def = new Def(ident.name, Def.Type.Include, ident.posStart, ident.posEnd); def.defPosStart = i.getStart(); - backup(def); + backupDef(def); return def; } return new Def(); @@ -1498,7 +1516,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def((String)id.value, Def.Type.Module, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1528,7 +1546,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1621,7 +1639,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { in.collapse(); last.children.add(in); last.collapse(); - backup(last); + backupDef(last); return a; } @@ -1649,7 +1667,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def("", Def.Type.Object, o.getStart(), o.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -1730,7 +1748,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { if(ident.type == Def.Type.Identifier){ Def def = new Def(ident.name, Def.Type.Val, ident.posStart, ident.posEnd); def.defPosStart = v.getStart(); - backup(def); + backupDef(def); return Def.root(a, def); } return Def.root(a,id); @@ -1746,7 +1764,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { if(ident.type == Def.Type.Identifier){ Def def = new Def(ident.name, Def.Type.Val, ident.posStart, ident.posEnd); def.defPosStart = v.getStart(); - backup(def); + backupDef(def); return Def.root(a, def); } return Def.root(a,id); @@ -1775,7 +1793,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def("", Def.Type.Constraint, c.getStart(), c.getEnd()); def.add(b); def.collapse(); - backup(def); + backupDef(def); return Def.root(a, def); } }, @@ -1789,7 +1807,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.defPosStart = i.getStart(); def.add(b); def.collapse(); - backup(def); + backupDef(def); return Def.root(a, def); } }, @@ -1820,7 +1838,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.collapse(); def.bAlt = true; - backup(def); + backupDef(def); return def; } }, @@ -1838,7 +1856,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.collapse(); def.bAlt = ((Def)m).bAlt; - backup(def); + backupDef(def); return def; } }, @@ -1858,7 +1876,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.collapse(); def.bAlt = ((Def)o).bAlt || ((Def)m).bAlt; - backup(def); + backupDef(def); return def; } }, @@ -1880,7 +1898,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(b); def.collapse(); def.bAlt = ((Def)o).bAlt || ((Def)m).bAlt; - backup(def); + backupDef(def); return def; } }, @@ -1898,7 +1916,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.collapse(); def.bAlt = true; - backup(def); + backupDef(def); return def; } }, @@ -1917,7 +1935,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.collapse(); def.bAlt = ((Def)o).bAlt || ((Def)p).bAlt; - backup(def); + backupDef(def); return def; } }, @@ -1936,7 +1954,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.collapse(); def.bAlt = ((Def)o).bAlt || ((Def)p).bAlt; - backup(def); + backupDef(def); return def; } }, @@ -1957,7 +1975,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(b); def.collapse(); def.bAlt = ((Def)o).bAlt || ((Def)p).bAlt; - backup(def); + backupDef(def); return def; } }, @@ -2009,7 +2027,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def("", Def.Type.Object, o.getStart(), o.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -2092,7 +2110,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.collapse(); def.bAlt = ((Def)m).bAlt; - backup(def); + backupDef(def); return def; } }, @@ -2107,7 +2125,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.collapse(); def.bAlt = true; - backup(def); + backupDef(def); return def; } }, @@ -2121,7 +2139,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def(ident.name, Def.Type.Val, ident.posStart, ident.posEnd); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -2137,7 +2155,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.defPosStart = m.getStart(); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -2153,7 +2171,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.defPosStart = m.getStart(); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -2169,7 +2187,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.defPosStart = m.getStart(); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -2206,7 +2224,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def((String)id.value, Def.Type.Class, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -2236,7 +2254,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def((String)id.value, Def.Type.ClassType, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -2414,7 +2432,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { in.collapse(); last.children.add(in); last.collapse(); - backup(last); + backupDef(last); return a; } @@ -2431,7 +2449,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { def.add(a); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -2447,7 +2465,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { in.collapse(); def.children.add(in); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -2800,7 +2818,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def("", Def.Type.Object, o.getStart(), o.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -3115,7 +3133,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def(ident.name, Def.Type.Let, ident.posStart, ident.posEnd); def.add(f); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -3128,7 +3146,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def(ident.name, Def.Type.Let, ident.posStart, ident.posEnd); def.add(b); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -3162,7 +3180,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { if(last != null){ last.add(b); last.collapse(); - backup(root); + backupDef(root); return root; } @@ -3220,7 +3238,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { if(last != null){ last.add(b); last.collapse(); - backup(root); + backupDef(root); return root; } @@ -3782,7 +3800,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def((String)id.value, Def.Type.Type, id.getStart(), id.getEnd()); def.add(a); def.collapse(); - backup(def); + backupDef(def); return def; } }, @@ -4387,27 +4405,27 @@ public Symbol reduce(Symbol[] _symbols, int offset) { public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; - Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); - backup(def); - return def; + Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + backupIdent(def); + return def; } }, new Action() { // [466] ident = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; - Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); - backup(def); - return def; + Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + backupIdent(def); + return def; } }, new Action() { // [467] val_ident = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; - - Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); - backup(def); - return def; + + Def def = new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); + backupIdent(def); + return def; } }, new Action() { // [468] val_ident = LPAREN operator.o RPAREN diff --git a/Ocaml/src/ocaml/parsers/Camlp4Preprocessor.java b/Ocaml/src/ocaml/parsers/Camlp4Preprocessor.java index 6150015..636f8dd 100644 --- a/Ocaml/src/ocaml/parsers/Camlp4Preprocessor.java +++ b/Ocaml/src/ocaml/parsers/Camlp4Preprocessor.java @@ -196,7 +196,7 @@ public void associateCamlp4Locations(IDocument oldDocument, String strOldDocumen if (def.type != Def.Type.Root) { - IRegion region = def.getRegion(newDocument); + IRegion region = def.getNameRegion(newDocument); // String doc = newDocument.get(); int pos = region.getOffset() - 1; diff --git a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java index 877085b..88d23d2 100644 --- a/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java +++ b/Ocaml/src/ocaml/parsers/OcamlNewInterfaceParser.java @@ -303,6 +303,11 @@ private Def parseModule(String doc, String filename, String moduleName, def.bTop = false; root.children.add(def); } + for (Def def : parser.recoverIdents) + if (def.bTop && def.name != null && !"".equals(def.name.trim())) { + def.bTop = false; + root.children.add(def); + } root = root.cleanCopy(true); } } diff --git a/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java b/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java index 8caef5a..6b30187 100644 --- a/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java +++ b/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java @@ -141,7 +141,7 @@ public void selectionChanged(SelectionChangedEvent event) { IDocument document = editor.getDocumentProvider().getDocument( editor.getEditorInput()); - IRegion region = def.getRegion(document); + IRegion region = def.getNameRegion(document); if (region != null) { ISelection editorSel = editor.getSelectionProvider().getSelection(); diff --git a/Ocaml/src/ocaml/views/outline/OutlineJob.java b/Ocaml/src/ocaml/views/outline/OutlineJob.java index e6d2cf0..b8b0d26 100644 --- a/Ocaml/src/ocaml/views/outline/OutlineJob.java +++ b/Ocaml/src/ocaml/views/outline/OutlineJob.java @@ -296,6 +296,11 @@ else if (!("ml4".equals(extension) || "mlp".equals(extension))) def.bTop = false; root.children.add(def); } + for (Def def : parser.recoverIdents) + if (def.bTop && def.name != null && !"".equals(def.name.trim())) { + def.bTop = false; + root.children.add(def); + } parserError = true; } @@ -491,7 +496,7 @@ private void addTypes(IFile file, Def root) { private void addTypeRec(TypeAnnotation[] annotations, Def def, boolean root) { if (!root) { - IRegion region = def.getRegion(doc); + IRegion region = def.getNameRegion(doc); int startOffset = region.getOffset(); int endOffset = startOffset + region.getLength() - 1; diff --git a/Ocaml/src/ocaml/views/outline/QuickOutline.java b/Ocaml/src/ocaml/views/outline/QuickOutline.java index 363caf1..ed3a0c9 100644 --- a/Ocaml/src/ocaml/views/outline/QuickOutline.java +++ b/Ocaml/src/ocaml/views/outline/QuickOutline.java @@ -186,7 +186,7 @@ protected void gotoSelectedElement() { IDocument document = editor.getDocumentProvider().getDocument( editor.getEditorInput()); - IRegion region = def.getRegion(document); + IRegion region = def.getNameRegion(document); if (region != null) { editor.selectAndReveal(region.getOffset(), region.getLength()); From 6a7d023cb7dcb11865f01d9b589e06b6b3e31552 Mon Sep 17 00:00:00 2001 From: trungtq Date: Thu, 23 Oct 2014 00:14:00 +0800 Subject: [PATCH 089/127] reset .paths file when create a new project --- Ocaml/src/ocaml/FolderChangeListener.java | 2 +- .../editor/completion/OcamlCompletionProcessor.java | 7 ++++++- Ocaml/src/ocaml/util/Misc.java | 7 +++++-- Ocaml/src/ocaml/util/OcamlPaths.java | 11 ++--------- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Ocaml/src/ocaml/FolderChangeListener.java b/Ocaml/src/ocaml/FolderChangeListener.java index e1bc0d7..923b77e 100644 --- a/Ocaml/src/ocaml/FolderChangeListener.java +++ b/Ocaml/src/ocaml/FolderChangeListener.java @@ -47,7 +47,7 @@ public boolean visit(IResourceDelta delta) throws CoreException { IResource r = res; while (r != null) { String rName = r.getName(); - if ((rName.length() > 1) && rName.startsWith(".")) + if (rName.startsWith(".")) return false; r = r.getParent(); } diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index ee8e25b..b2f65de 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -666,8 +666,13 @@ private boolean checkCompletion(Def def, String completion) { if (def.name == null) return false; - if (def.name.startsWith(completion) && def.name.length() > completion.length()) + if (def.name.startsWith(completion)){ +// if (def.type != Def.Type.Identifier) +// return true; +// else if (def.name.length() > completion.length()) +// return true; return true; + } return false; } diff --git a/Ocaml/src/ocaml/util/Misc.java b/Ocaml/src/ocaml/util/Misc.java index bb26d5f..8022a88 100644 --- a/Ocaml/src/ocaml/util/Misc.java +++ b/Ocaml/src/ocaml/util/Misc.java @@ -13,6 +13,7 @@ import ocaml.preferences.PreferenceConstants; import ocaml.views.OcamlCompilerOutput; +import org.eclipse.core.internal.resources.ResourceException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; @@ -637,8 +638,10 @@ public static void setShareableProperty(IResource resource, QualifiedName name, resource.setPersistentProperty(name, value); } catch (BackingStoreException e) { - OcamlPlugin.logError("error in OcamlPlugin.setPersistentProperty", e); - } catch (CoreException e) { + // OcamlPlugin.logError("error in OcamlPlugin.setPersistentProperty", e); + } catch (ResourceException e) { + + } catch (Exception e) { } } diff --git a/Ocaml/src/ocaml/util/OcamlPaths.java b/Ocaml/src/ocaml/util/OcamlPaths.java index b4102ae..9c367be 100644 --- a/Ocaml/src/ocaml/util/OcamlPaths.java +++ b/Ocaml/src/ocaml/util/OcamlPaths.java @@ -35,6 +35,7 @@ public class OcamlPaths { public OcamlPaths(IProject project) { this.project = project; + restoreDefaults(); } public void setPaths(String[] paths) { @@ -95,16 +96,12 @@ public String[] getPaths() { if (!file.exists()) restoreDefaults(); - boolean hasCurrentDir = false; try { BufferedReader reader = new BufferedReader(new FileReader(file)); String path = ""; - while ((path = reader.readLine()) != null) { - if (path.compareTo(".") == 0) - hasCurrentDir = true; + while ((path = reader.readLine()) != null) paths.add(path); - } reader.close(); @@ -113,10 +110,6 @@ public String[] getPaths() { return new String[0]; } - // always add "." to project paths - if (!hasCurrentDir) - paths.add("."); - addReferencedProjectsPaths(paths); return paths.toArray(new String[paths.size()]); From b406ff6e242c97adb8fbf649da34e9a4b7ef5ea2 Mon Sep 17 00:00:00 2001 From: trungtq Date: Thu, 23 Oct 2014 11:13:43 +0800 Subject: [PATCH 090/127] do not rebuild outline when text is changed because it slows down the system --- Ocaml/src/ocaml/editors/OcamlEditor.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index 647054b..40b5234 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -158,6 +158,9 @@ protected void createActions() { } + // Trung: don't rebuild outline when text is changed because it + // slow down the system + /* final ISourceViewer viewer = this.getSourceViewer(); final OcamlSourceViewerConfig viewerConfig = (OcamlSourceViewerConfig) this.getSourceViewerConfiguration(); viewer.addTextListener(new ITextListener() { @@ -176,6 +179,7 @@ public void textChanged(TextEvent event) { rebuildOutline(50, false); // don't sync outline with editor } }); + */ } @@ -434,6 +438,9 @@ public IProgressMonitor getMonitor() { @Override public void doSave(IProgressMonitor monitor) { super.doSave(monitor); + + // rebuild Outline when file is saved + rebuildOutline(50, false); boolean bMakefileNature = false; try { From 96431acef7bc1255b5fc0a8187dfd56f88ceeb15 Mon Sep 17 00:00:00 2001 From: trungtq Date: Thu, 23 Oct 2014 14:29:49 +0800 Subject: [PATCH 091/127] improve on auto-completion --- .../completion/OcamlCompletionProcessor.java | 217 ++++++++---------- 1 file changed, 101 insertions(+), 116 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index b2f65de..8ed1fb0 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -226,9 +226,11 @@ else if (moduleName.endsWith(".mli")) + moduleName.substring(1); if (completion.contains(".")) - proposals = processDottedCompletion(completion, interfacesDefsRoot, moduleName, doc, offset); + proposals = processDottedCompletion(completion, interfacesDefsRoot, + moduleName, doc, offset, completion.length()); else - proposals = processNondottedCompletion(completion, interfacesDefsRoot, moduleName, doc, offset); + proposals = processNondottedCompletion(completion, interfacesDefsRoot, + moduleName, doc, offset, completion.length()); proposals = removeDuplicatedCompletionProposal(proposals); @@ -240,7 +242,8 @@ private ArrayList processDottedCompletion(String comple Def interfacesDefsRoot, String moduleName, IDocument document, - int offset) { + int offset, + int length) { ArrayList proposals = new ArrayList(); @@ -266,9 +269,10 @@ private ArrayList processDottedCompletion(String comple i--; } - /* - * look into current module first - */ + boolean isLowerCasePrefix= false; + if (prefix.length() > 0 && Character.isLowerCase(prefix.charAt(0))) + isLowerCasePrefix = true; + Def currentDef = null; for (Def def: interfacesDefsRoot.children) { if (def.name.equals(moduleName)) { @@ -277,89 +281,85 @@ private ArrayList processDottedCompletion(String comple } } - // look for prefix in sub-module or aliased module of current modules - boolean stop = false; - while (!stop) { - stop = true; - if (currentDef == null) - break; + /* + * prefix is a lower-case identifier, hence look for suffix completion + * in the current module, sub-modules, included modules or opened modules + */ + if (isLowerCasePrefix) { + // find in current def for (Def def : currentDef.children) { - if (!def.name.equals(prefix)) - continue; + // look for completion of suffix in the current module + if (checkCompletion(def, suffix) && isCompletionDef(def)) { + Def proposedDef = createProposalDef(project, def); + proposals.add(new OcamlCompletionProposal(proposedDef, + offset, suffix.length())); + } - if (def.type == Def.Type.Module) { - proposals.addAll(lookupProposalsCompletionInDef(suffix, def, interfacesDefsRoot, document, offset)); + // look for completion in opened or included module of current module + // by attach the involved module name to suffix and find new completion + if (def.type == Def.Type.Open || def.type == Def.Type.Include) { + String newCompletion = def.name + "." + suffix; + proposals.addAll(processDottedCompletion(newCompletion, + interfacesDefsRoot, moduleName, document, + offset, suffix.length())); } - else if (def.type == Def.Type.ModuleAlias) { - if (def.children.size() > 0) { - String aliasedName = def.children.get(0).name; - if (prefix.equals(aliasedName)) - stop = true; - else { - prefix = aliasedName; - stop = false; - } - break; - } + } + + // completion maybe modules's name + for (Def def : interfacesDefsRoot.children) { + if (checkCompletion(def, suffix) && isCompletionDef(def)) { + Def proposedDef = createProposalDef(project, def); + proposals.add(new OcamlCompletionProposal(proposedDef, + offset, suffix.length())); } } } - - // look for completion in opened or included module of current module - ArrayList currentChildren = new ArrayList<>(); - if (currentDef != null) - currentChildren = currentDef.children; - for (Def def1 : currentChildren) { - if (def1.type == Def.Type.Open || def1.type == Def.Type.Include) { - Def involvedDef = def1; - String involvedModuleName = ""; - String newCompletion = ""; - // opened module is like A.B.C - if (involvedDef.name.contains(".")) { - index = involvedDef.name.indexOf("."); - involvedModuleName = involvedDef.name.substring(0, index); - String subModuleName = involvedDef.name.substring(index + 1); - newCompletion = subModuleName + "." + completion; - } - else { - involvedModuleName = involvedDef.name; - newCompletion = completion; - } - - // search in current module first - for (Def def2: currentChildren) { - if (def2.name.equals(involvedModuleName)) { - Def involvedDefRoot = def2; - for (Def def3: involvedDefRoot.children) { - if (checkCompletion(def3, newCompletion) && isCompletionDef(def3)) { - Def proposedDef = createProposalDef(project, def3); - proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); - } - } + /* + * prefix is upper-case identifier, hence look for a module which has + * name is or aliased by 'prefix' + */ + else { + // look for prefix in sub-module or aliased module of current modules + String realPrefix = prefix; + boolean stop = false; + while (!stop) { + stop = true; + if (currentDef == null) + break; + + for (Def def : currentDef.children) { + if (!def.name.equals(realPrefix)) + continue; + + if (def.type == Def.Type.Module) { + // find in sub-modules + proposals.addAll(lookupProposalsCompletionInDef( + suffix, def, interfacesDefsRoot, document, + offset, length)); } - } - for (Def def2: interfacesDefsRoot.children) { - if (def2.name.equals(involvedModuleName)) { - Def involvedDefRoot = def2; - for (Def def3: involvedDefRoot.children) { - if (checkCompletion(def3, newCompletion) && isCompletionDef(def3)) { - Def proposedDef = createProposalDef(project, def3); - proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + else if (def.type == Def.Type.ModuleAlias) { + if (def.children.size() > 0) { + String aliasedName = def.children.get(0).name; + if (realPrefix.equals(aliasedName)) + stop = true; + else { + realPrefix = aliasedName; + stop = false; } + break; } } } } - } - - - /* - * then look into other modules - */ - for (Def def: interfacesDefsRoot.children) { - if (def.name.equals(prefix)) - proposals.addAll(lookupProposalsCompletionInDef(suffix, def, interfacesDefsRoot, document, offset)); + + // find in other modules + for (Def def: interfacesDefsRoot.children) { + if (def.name.equals(realPrefix)) + proposals.addAll(lookupProposalsCompletionInDef( + suffix, def, interfacesDefsRoot, document, + offset, length)); + } } } @@ -381,7 +381,8 @@ private ArrayList processNondottedCompletion(String com Def interfacesDefsRoot, String moduleName, IDocument document, - int offset) { + int offset, + int length) { ArrayList proposals = new ArrayList(); @@ -394,7 +395,7 @@ private ArrayList processNondottedCompletion(String com for (Def def: interfacesDefsRoot.children) { if (checkCompletion(def, completion)) { Def proposedDef = createProposalDef(project, def); - proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, length)); } } @@ -417,7 +418,7 @@ private ArrayList processNondottedCompletion(String com for (Def def: currentDef.children) { if (checkCompletion(def, completion)) { Def proposedDef = createProposalDef(project, def); - proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + proposals.add(new OcamlCompletionProposal(proposedDef, offset, length)); } } @@ -428,36 +429,9 @@ private ArrayList processNondottedCompletion(String com if (def.type != Def.Type.Open && def.type != Def.Type.Include) continue; - String openedModuleName = ""; - String newCompletion = ""; - // opened module is like A.B.C - if (def.name.contains(".")) { - int index = def.name.indexOf("."); - openedModuleName = def.name.substring(0, index); - String subModuleName = def.name.substring(index + 1); - newCompletion = subModuleName + "." + completion; - } - else { - openedModuleName = def.name; - newCompletion = completion; - } - - for (Def idef: interfacesDefsRoot.children) { - if (!idef.name.equals(openedModuleName)) - continue; - - proposals.addAll(lookupProposalsCompletionInDef(newCompletion, idef, interfacesDefsRoot, document, offset)); - -// for (Def d: idef.children) { -// if (d == null || d.name == null) -// break; -// -// if (d.name.startsWith(completion) && isCompletionDef(d)) { -// Def proposedDef = createProposalDef(project, d); -// proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); -// } -// } - } + String newCompletion = def.name + "." + completion; + proposals.addAll(processDottedCompletion(newCompletion, + interfacesDefsRoot, moduleName, document, offset, length)); } } @@ -486,7 +460,8 @@ private ArrayList lookupProposalsCompletionInDef(String Def defsRoot, Def interfacesDefRoot, IDocument document, - int offset) { + int offset, + int length) { ArrayList proposals = new ArrayList(); @@ -513,7 +488,8 @@ private ArrayList lookupProposalsCompletionInDef(String // look inside def roots first for (Def def: defsRoot.children) { if (def.name.equals(prefix)) - proposals.addAll(lookupProposalsCompletionInDef(suffix, def, interfacesDefRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef(suffix, def, + interfacesDefRoot, document, offset, length)); } // look inside included module @@ -524,7 +500,9 @@ private ArrayList lookupProposalsCompletionInDef(String for (Def def2: defsRoot.children) { if (def2.name.equals(includedDef.name)) { Def includedDefRoot = def2; - proposals.addAll(lookupProposalsCompletionInDef(completion, includedDefRoot, interfacesDefRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef( + completion,includedDefRoot, interfacesDefRoot, + document, offset, length)); } } @@ -532,7 +510,9 @@ private ArrayList lookupProposalsCompletionInDef(String for (Def def2: interfacesDefRoot.children) { if (def2.name.equals(includedDef.name)) { Def includedDefRoot = def2; - proposals.addAll(lookupProposalsCompletionInDef(completion, includedDefRoot, interfacesDefRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef( + completion, includedDefRoot, interfacesDefRoot, + document, offset, length)); } } @@ -545,7 +525,8 @@ private ArrayList lookupProposalsCompletionInDef(String for (Def def : defsRoot.children) { if (checkCompletion(def, completion) && isCompletionDef(def)) { Def proposedDef = createProposalDef(project, def); - proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); + proposals.add(new OcamlCompletionProposal(proposedDef, + offset, completion.length())); } } // look inside included module @@ -556,7 +537,9 @@ private ArrayList lookupProposalsCompletionInDef(String for (Def def2: defsRoot.children) { if (def2.name.equals(includedDef.name)) { Def includedDefRoot = def2; - proposals.addAll(lookupProposalsCompletionInDef(completion, includedDefRoot, interfacesDefRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef( + completion, includedDefRoot, interfacesDefRoot, + document, offset, length)); } } @@ -564,7 +547,9 @@ private ArrayList lookupProposalsCompletionInDef(String for (Def def2: interfacesDefRoot.children) { if (def2.name.equals(includedDef.name)) { Def includedDefRoot = def2; - proposals.addAll(lookupProposalsCompletionInDef(completion, includedDefRoot, interfacesDefRoot, document, offset)); + proposals.addAll(lookupProposalsCompletionInDef( + completion, includedDefRoot, interfacesDefRoot, + document, offset, length)); } } From 8a12534f46068c3904105b606967ba6aaba7741c Mon Sep 17 00:00:00 2001 From: trungtq Date: Thu, 23 Oct 2014 21:36:23 +0800 Subject: [PATCH 092/127] update Def position when parsing --- Ocaml/src/ocaml/parser/OcamlParser.g | 13 +++++++++++++ Ocaml/src/ocaml/parser/OcamlParser.java | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/Ocaml/src/ocaml/parser/OcamlParser.g b/Ocaml/src/ocaml/parser/OcamlParser.g index 1999c10..67ca9a0 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.g +++ b/Ocaml/src/ocaml/parser/OcamlParser.g @@ -1540,6 +1540,12 @@ let_binding= pat.findIdents(idents); Def root = new Def(); + + // update root position + int identsSize = idents.size(); + if (identsSize > 1) + root.posStart = idents.get(0).posStart; + root.posEnd = idents.get(identsSize - 1).posEnd; Def last = null; for(int i = 0; i < idents.size(); i++){ @@ -1557,6 +1563,7 @@ let_binding= last.add(b); last.collapse(); backupDef(root); + return root; } @@ -1581,6 +1588,12 @@ strict_binding= Def root = new Def(); + // update root position + int identsSize = idents.size(); + if (identsSize > 1) + root.posStart = idents.get(0).posStart; + root.posEnd = idents.get(identsSize - 1).posEnd; + Def last = null; boolean bFirst = true; for(int i = 0; i < idents.size(); i++){ diff --git a/Ocaml/src/ocaml/parser/OcamlParser.java b/Ocaml/src/ocaml/parser/OcamlParser.java index 89fd166..30d1323 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.java +++ b/Ocaml/src/ocaml/parser/OcamlParser.java @@ -3164,6 +3164,12 @@ public Symbol reduce(Symbol[] _symbols, int offset) { pat.findIdents(idents); Def root = new Def(); + + // update root position + int identsSize = idents.size(); + if (identsSize > 1) + root.posStart = idents.get(0).posStart; + root.posEnd = idents.get(identsSize - 1).posEnd; Def last = null; for(int i = 0; i < idents.size(); i++){ @@ -3181,6 +3187,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { last.add(b); last.collapse(); backupDef(root); + return root; } @@ -3218,6 +3225,12 @@ public Symbol reduce(Symbol[] _symbols, int offset) { Def root = new Def(); + // update root position + int identsSize = idents.size(); + if (identsSize > 1) + root.posStart = idents.get(0).posStart; + root.posEnd = idents.get(identsSize - 1).posEnd; + Def last = null; boolean bFirst = true; for(int i = 0; i < idents.size(); i++){ From 0458a7382f9bba6882d3411449bc6b52f813f6fe Mon Sep 17 00:00:00 2001 From: trungtq Date: Thu, 23 Oct 2014 22:05:10 +0800 Subject: [PATCH 093/127] synchronize editor with outline when double clickous --- Ocaml/src/ocaml/editors/OcamlEditor.java | 33 +++++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index 40b5234..72b4460 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -46,6 +46,8 @@ import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; @@ -107,6 +109,12 @@ public ITextViewer getTextViewer() { @Override protected void createActions() { super.createActions(); + + final ISourceViewer sourceViewer = this.getSourceViewer(); + final StyledText textWidget = sourceViewer.getTextWidget(); + final OcamlSourceViewerConfig sourceViewerConfig = + (OcamlSourceViewerConfig) this.getSourceViewerConfiguration(); + try { paintManager = new PaintManager(getSourceViewer()); @@ -130,10 +138,8 @@ protected void createActions() { } try { - StyledText text = this.getSourceViewer().getTextWidget(); - - caret = new DebugVisuals(text); - text.addPaintListener(caret); + caret = new DebugVisuals(textWidget); + textWidget.addPaintListener(caret); IPath file = getPathOfFileBeingEdited(); if (file != null) @@ -157,6 +163,25 @@ protected void createActions() { OcamlPlugin.logError("ocaml plugin error", e); } + // synchronize with outline when double-click mouse + textWidget.addMouseListener(new MouseListener() { + @Override + public void mouseUp(MouseEvent e) { + } + + @Override + public void mouseDown(MouseEvent e) { + } + + @Override + public void mouseDoubleClick(MouseEvent e) { + if (sourceViewerConfig.isContentAssistantActive() || e == null) + return; + + synchronizeOutline(); + } + }); + // Trung: don't rebuild outline when text is changed because it // slow down the system From fd4abd2e98ddf7c454cb619534b3b4ab31b89a44 Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 24 Oct 2014 01:54:55 +0800 Subject: [PATCH 094/127] indent next line by indentation of the nearest and prior non-whitespace line --- .../ocaml/editors/OcamlAutoEditStrategy.java | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java b/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java index 95be336..b87fe1f 100644 --- a/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java +++ b/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java @@ -291,8 +291,33 @@ else if (trimmed.startsWith("|") && trimmed.equals(beforeCursor)) { } else if (OcamlPlugin.getInstance().getPreferenceStore().getBoolean( - PreferenceConstants.P_EDITOR_KEEP_INDENT)) - command.text = eol + makeIndent(indent); + PreferenceConstants.P_EDITOR_KEEP_INDENT)) { + if (trimmed.isEmpty()) { + // if current line contains only whitespace, then + // then trim it and indent next line by indentation + // of nearest non-whitespace line + try { + int lineNum = document.getLineOfOffset(command.offset); + int priorIndent = 0; + for (int l = lineNum - 1; l >= 0; l--) { + int x = document.getLineOffset(l); + int y = document.getLineOffset(l+1); + String priorLine = document.get(x, y - x + 1); + int i = OcamlFormatter.getLineIndent(priorLine); + if (i > 0) { + priorIndent = i; + break; + } + } + command.offset = lineRegion.getOffset(); + command.length = lineRegion.getLength(); + command.text = eol + makeIndent(priorIndent); + } catch (BadLocationException e) { + } + } else { + command.text = eol + makeIndent(indent); + } + } } } else if (command.text.equals("\t")) { From 7e0b0e7a0507e773b1494ecff8059d30470f4752 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sun, 26 Oct 2014 02:00:20 +0800 Subject: [PATCH 095/127] show selected item in call stack --- Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java b/Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java index e3cc996..1de777b 100644 --- a/Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java +++ b/Ocaml/src/ocaml/debugging/views/OcamlCallStackView.java @@ -28,10 +28,10 @@ public void setCallStack(String elements[]){ list.removeAll(); for(String e : elements) list.add(e); + list.setRedraw(true); if (selectionIndex >= 0 && selectionIndex < elements.length) { list.setSelection(selectionIndex); } - list.setRedraw(true); } public void empty(){ From 86504cbfe09f4b6bae1ef9014831ddb7d544c219 Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 31 Oct 2014 00:36:18 +0800 Subject: [PATCH 096/127] change priority of some tasks --- Ocaml/src/ocaml/editors/OcamlEditor.java | 6 +++--- Ocaml/src/ocaml/editors/lex/OcamllexEditor.java | 2 +- Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index 72b4460..be79e10 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -151,7 +151,7 @@ protected void createActions() { // parse the OCaml libraries in a background thread try { CompletionJob job = new CompletionJob("Parsing ocaml library mli files", null); - job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority + job.setPriority(CompletionJob.LONG); // Trung changes priority job.schedule(); } catch (Exception e) { OcamlPlugin.logError("ocaml plugin error", e); @@ -229,7 +229,7 @@ public void doSetInput(IEditorInput input) throws CoreException { // parse the project interfaces in a background thread CompletionJob job = new CompletionJob("Parsing ocaml project mli files", project); - job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority + job.setPriority(CompletionJob.LONG); // Trung changes priority job.schedule(); if (input instanceof IFileEditorInput) { @@ -524,7 +524,7 @@ public void rebuildOutline(int delay, boolean syncWithEditor) { else outlineJob.cancel(); - outlineJob.setPriority(CompletionJob.INTERACTIVE); + outlineJob.setPriority(CompletionJob.DECORATE); outlineJob.setOutline(this.outline); outlineJob.setDoc(document); outlineJob.setEditor(this); diff --git a/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java b/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java index 43127d5..3d45dc3 100644 --- a/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java +++ b/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java @@ -56,7 +56,7 @@ protected void createActions() { // effectue le parsing des bibliothèques ocaml en arrière plan CompletionJob job = new CompletionJob("Parsing ocaml library mli files", null); - job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority + job.setPriority(CompletionJob.LONG); // Trung changes priority job.schedule(); } diff --git a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java index 1bfcd3e..380bdc4 100644 --- a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java +++ b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java @@ -62,7 +62,7 @@ protected void createActions() { // effectue le parsing des bibliothèques ocaml en arrière plan CompletionJob job = new CompletionJob("Parsing ocaml library mli files", null); - job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority + job.setPriority(CompletionJob.LONG); // Trung changes priority job.schedule(); From fb4d98dc67b89067357bc0a03963ec08bf87212b Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 31 Oct 2014 01:30:19 +0800 Subject: [PATCH 097/127] add path to debugger --- Ocaml/src/ocaml/debugging/OcamlDebugger.java | 38 ++++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/Ocaml/src/ocaml/debugging/OcamlDebugger.java b/Ocaml/src/ocaml/debugging/OcamlDebugger.java index b0c1158..0b565ec 100644 --- a/Ocaml/src/ocaml/debugging/OcamlDebugger.java +++ b/Ocaml/src/ocaml/debugging/OcamlDebugger.java @@ -76,7 +76,7 @@ public enum State { /** The project containing the debugged executable */ private IProject project; - + /** list of paths of project */ private String[] projectPaths; @@ -240,7 +240,7 @@ public synchronized void start( pathStr = pathStr.trim(); if (!".".equals(pathStr)) { commandLineArgs.add("-I"); - + //These paths are either absolute or relative to the project //directory. We must convert them to absolute paths in case //we are running a bytecode within a nested directory. @@ -248,12 +248,14 @@ public synchronized void start( if (!path.isAbsolute()) { path = Paths.get(projectLocation.append(pathStr).toOSString()); } - commandLineArgs.add(path.toString()); + commandLineArgs.add(path.toString()); } } // add the _build folder (for the cases making project by using Ocamlbuild) String buildpath = projectLocation.append("_build").toOSString(); + commandLineArgs.add("-I"); + commandLineArgs.add(buildpath); ArrayList buildFolders = FileUtil.findSubdirectories(buildpath); for (String path: buildFolders) { commandLineArgs.add("-I"); @@ -264,10 +266,6 @@ public synchronized void start( commandLineArgs.add("-I"); commandLineArgs.add("+camlp4"); - // add module Camlp4 - commandLineArgs.add("-I"); - commandLineArgs.add("+camlp4"); - // add the root of the project commandLineArgs.add("-I"); commandLineArgs.add(projectLocation.toOSString()); @@ -433,7 +431,7 @@ public synchronized void backstepReturn() { send("start"); } } - + public synchronized void setFrame(int frame) { if (!checkStarted()) return; @@ -906,7 +904,7 @@ else if (state.equals(State.Quitting)) { } } - + private void getFrame() { state = State.Frame; send("frame"); @@ -1094,7 +1092,7 @@ private void processFrame(String output) { public static final Pattern patternCallstack = Pattern .compile("\\A#(\\d+)\\s+Pc\\s*:\\s+(\\d+)\\s+(\\w+)\\s+char\\s+(\\d+)"); - + private void processCallStack(final String output) { Display.getDefault().asyncExec(new Runnable() { public void run() { @@ -1141,7 +1139,7 @@ public void run() { // prettier stackview String newOutput = "#" + s1 + " - " + module + "." + functionName - + " - (" + line + ": " + column + ")"; + + " - (" + line + ": " + column + ")"; backtrace[i] = newOutput; } else { OcamlPlugin.logError("ocamldebugger: couldn't parse call stack"); @@ -1159,7 +1157,7 @@ public void run() { } }); } - + // get function that contains line private synchronized String findFunctionContainingLine(String filepath, int line) { String functionName = ""; @@ -1170,20 +1168,20 @@ private synchronized String findFunctionContainingLine(String filepath, int line int i = 0; for (i = 0; i < childs.size(); i++) { Def def = childs.get(i); - int l = Symbol.getLine(def.posStart); - if (l >= line ) + int l = Symbol.getLine(def.posStart); + if (l >= line ) break; } if (i > 0) { Def child = childs.get(i-1); if (child.type == Def.Type.Let) functionName = child.name; - else if (child.type == Def.Type.Module) { + else if (child.type == Def.Type.Module) { List grandChilds = child.children; int j = 0; for (j = 0; j < grandChilds.size(); j++) { Def def = grandChilds.get(j); - int l = Symbol.getLine(def.posStart); + int l = Symbol.getLine(def.posStart); if (l > line) break; } @@ -1195,7 +1193,7 @@ else if (child.type == Def.Type.Module) { } return functionName; } - + private void indicateRunningState(final String message) { Display.getDefault().asyncExec(new Runnable() { public void run() { @@ -1216,7 +1214,7 @@ public void run() { DebugMarkers.getInstance().clearCurrentPosition(); refreshEditor(); } - + private synchronized IEditorInput getEditorInput(final String filename) { String ufilename = filename.substring(0, 1).toUpperCase() + filename.substring(1); @@ -1280,7 +1278,7 @@ private synchronized String getFilePath(final String filename) return null; } - + public void highlight(final String filename, final int offset) { final IEditorInput editorInput = getEditorInput(filename); if (editorInput != null) { @@ -1450,7 +1448,7 @@ public void run() { } }); } - + public void printMessage(final String message) { final IOConsoleOutputStream console = this.console; From fa65769941016c2fa97d1bf9a3fde23cc95648a7 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sun, 2 Nov 2014 22:42:12 +0800 Subject: [PATCH 098/127] save all files before compiling --- .../CancelCompileAllProjectsAction.java | 23 +++--- .../editor/actions/CleanProjectAction.java | 43 +++++------ .../editor/actions/CompileProjectAction.java | 72 ++++++++++++------- .../actions/CompileProjectPopupAction.java | 22 +++--- 4 files changed, 84 insertions(+), 76 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java b/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java index 6671c35..308f9aa 100644 --- a/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java +++ b/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java @@ -12,6 +12,7 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.IJobChangeListener; @@ -19,9 +20,11 @@ import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.part.FileEditorInput; /** This action activates completion in the OCaml editor. */ public class CancelCompileAllProjectsAction implements IWorkbenchWindowActionDelegate { @@ -34,24 +37,16 @@ public void run(IAction action) { IEditorPart editorPart = page.getActiveEditor(); if (editorPart != null) { IProject project = null; - if (editorPart instanceof OcamlEditor) { - OcamlEditor editor = (OcamlEditor) editorPart; - project = editor.getProject(); - - } else if (editorPart instanceof OcamllexEditor) { - OcamllexEditor editor = (OcamllexEditor) editorPart; - project = editor.getProject(); - - } else if (editorPart instanceof OcamlyaccEditor) { - OcamlyaccEditor editor = (OcamlyaccEditor) editorPart; - project = editor.getProject(); + FileEditorInput editorInput = (FileEditorInput) editorPart.getEditorInput(); + if (editorInput != null && editorInput.getFile() != null) { + project = editorInput.getFile().getProject(); } - + if (project == null) return; - + final String jobName = "Cancelling compiling jobs"; - + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { diff --git a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java index 76040db..a343912 100644 --- a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java +++ b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java @@ -13,6 +13,7 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.IJobChangeListener; @@ -20,9 +21,11 @@ import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.part.FileEditorInput; /** This action activates completion in the OCaml editor. */ public class CleanProjectAction implements IWorkbenchWindowActionDelegate { @@ -35,25 +38,17 @@ public void run(IAction action) { IEditorPart editorPart = page.getActiveEditor(); if (editorPart != null) { IProject project = null; - if (editorPart instanceof OcamlEditor) { - OcamlEditor editor = (OcamlEditor) editorPart; - project = editor.getProject(); - - } else if (editorPart instanceof OcamllexEditor) { - OcamllexEditor editor = (OcamllexEditor) editorPart; - project = editor.getProject(); - - } else if (editorPart instanceof OcamlyaccEditor) { - OcamlyaccEditor editor = (OcamlyaccEditor) editorPart; - project = editor.getProject(); + FileEditorInput editorInput = (FileEditorInput) editorPart.getEditorInput(); + if (editorInput != null && editorInput.getFile() != null) { + project = editorInput.getFile().getProject(); } - + if (project == null) return; - + final IProject buildProject = project; final String jobName = "Cleaning project " + project.getName(); - + final long[] executedTime = new long[1]; executedTime[0] = -1; @@ -62,7 +57,7 @@ public void run(IAction action) { protected IStatus run(IProgressMonitor monitor) { // save progress monitor for later use OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); - + // cleaning executedTime[0] = System.currentTimeMillis(); OcamlMakefileBuilder builder = new OcamlMakefileBuilder(); @@ -81,15 +76,15 @@ protected IStatus run(IProgressMonitor monitor) { @Override public void sleeping(IJobChangeEvent event) { } - + @Override public void scheduled(IJobChangeEvent event) { } - + @Override public void running(IJobChangeEvent event) { } - + @Override public void done(IJobChangeEvent event) { // cleaning job was cancelled @@ -100,14 +95,14 @@ public void done(IJobChangeEvent event) { else { OcamlPlugin.ActiveBuildJobs.remove(jobName); } - + // time long cleaningTime = -1; - if (executedTime[0] > 0) + if (executedTime[0] > 0) cleaningTime = System.currentTimeMillis() - executedTime[0]; if (cleaningTime >= 0) { long minutes = TimeUnit.MILLISECONDS.toMinutes(cleaningTime); - long seconds = TimeUnit.MILLISECONDS.toSeconds(cleaningTime) - + long seconds = TimeUnit.MILLISECONDS.toSeconds(cleaningTime) - TimeUnit.MINUTES.toSeconds(minutes); String time = ""; if (minutes > 1) @@ -122,14 +117,14 @@ public void done(IJobChangeEvent event) { } else Misc.appendToOcamlConsole("Time: unknown"); - + Misc.appendToOcamlConsole(""); } - + @Override public void awake(IJobChangeEvent event) { } - + @Override public void aboutToRun(IJobChangeEvent event) { } diff --git a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java index 29e6898..534b3c4 100644 --- a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java +++ b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java @@ -14,6 +14,7 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.IJobChangeListener; @@ -21,9 +22,11 @@ import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.part.FileEditorInput; /** This action activates completion in the OCaml editor. */ public class CompileProjectAction implements IWorkbenchWindowActionDelegate { @@ -31,34 +34,46 @@ public class CompileProjectAction implements IWorkbenchWindowActionDelegate { private IWorkbenchWindow window; public void run(IAction action) { - IWorkbenchPage page = window.getActivePage(); + final IWorkbenchPage page = window.getActivePage(); if (page != null) { + /* + * Save all source code file before compiling + */ + IEditorReference[] editorReferences = page.getEditorReferences(); + NullProgressMonitor monitor = new NullProgressMonitor(); + if ( editorReferences != null ){ + for (IEditorReference iEditorReference : editorReferences) { + IEditorPart editor = iEditorReference.getEditor(false); + if (editor != null && editor.isDirty() + && ((editor instanceof OcamlEditor) + || (editor instanceof OcamllexEditor) + || (editor instanceof OcamlyaccEditor))) { + editor.doSave(monitor); + } + } + } + + /* + * Now build the project of current opened file + */ IEditorPart editorPart = page.getActiveEditor(); if (editorPart != null) { IProject project = null; - if (editorPart instanceof OcamlEditor) { - OcamlEditor editor = (OcamlEditor) editorPart; - project = editor.getProject(); - - } else if (editorPart instanceof OcamllexEditor) { - OcamllexEditor editor = (OcamllexEditor) editorPart; - project = editor.getProject(); - - } else if (editorPart instanceof OcamlyaccEditor) { - OcamlyaccEditor editor = (OcamlyaccEditor) editorPart; - project = editor.getProject(); + FileEditorInput editorInput = (FileEditorInput) editorPart.getEditorInput(); + if (editorInput != null && editorInput.getFile() != null) { + project = editorInput.getFile().getProject(); } - + if (project == null) return; - + final IProject buildProject = project; - + final String jobName = "Compiling project " + project.getName(); - + final long[] executedTime = new long[1]; executedTime[0] = -1; - + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { @@ -69,6 +84,7 @@ protected IStatus run(IProgressMonitor monitor) { // compile executedTime[0] = System.currentTimeMillis(); buildProject.build(IncrementalProjectBuilder.FULL_BUILD, monitor); + } catch (CoreException e) { OcamlPlugin.logError("ocaml plugin error", e); } @@ -76,6 +92,8 @@ protected IStatus run(IProgressMonitor monitor) { } }; +// Misc.showView(OcamlCompilerOutput.ID); + job.setPriority(Job.BUILD); /* * If the action is directly called by the user, then we display a dialog box. Else, the launch is silent. @@ -86,15 +104,15 @@ protected IStatus run(IProgressMonitor monitor) { @Override public void sleeping(IJobChangeEvent event) { } - + @Override public void scheduled(IJobChangeEvent event) { } - + @Override public void running(IJobChangeEvent event) { } - + @Override public void done(IJobChangeEvent event) { // compiling job was cancelled @@ -105,15 +123,15 @@ public void done(IJobChangeEvent event) { else { OcamlPlugin.ActiveBuildJobs.remove(jobName); } - + // time long compilingTime = -1; - if (executedTime[0] > 0) + if (executedTime[0] > 0) compilingTime = System.currentTimeMillis() - executedTime[0]; if (compilingTime >= 0) { long minutes = TimeUnit.MILLISECONDS.toMinutes(compilingTime); - long seconds = TimeUnit.MILLISECONDS.toSeconds(compilingTime) - - TimeUnit.MINUTES.toSeconds(minutes); + long seconds = TimeUnit.MILLISECONDS.toSeconds(compilingTime) - + TimeUnit.MINUTES.toSeconds(minutes); String time = ""; if (minutes > 1) time = time + String.valueOf(minutes) + " mins"; @@ -127,14 +145,14 @@ public void done(IJobChangeEvent event) { } else Misc.appendToOcamlConsole("Time: unknown"); - + Misc.appendToOcamlConsole(""); } - + @Override public void awake(IJobChangeEvent event) { } - + @Override public void aboutToRun(IJobChangeEvent event) { } diff --git a/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java index b6a3efd..73bdda5 100644 --- a/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java @@ -44,14 +44,14 @@ public void run(IAction action) { executedTime[0] = -1; final String jobName = "Compiling project " + project.getName(); - + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { try { // save progress monitor for later use OcamlPlugin.ActiveBuildJobs.put(jobName, monitor); - + // compile executedTime[0] = System.currentTimeMillis(); project.build(IncrementalProjectBuilder.FULL_BUILD, monitor); @@ -72,15 +72,15 @@ protected IStatus run(IProgressMonitor monitor) { @Override public void sleeping(IJobChangeEvent event) { } - + @Override public void scheduled(IJobChangeEvent event) { } - + @Override public void running(IJobChangeEvent event) { } - + @Override public void done(IJobChangeEvent event) { // compiling job was cancelled @@ -91,14 +91,14 @@ public void done(IJobChangeEvent event) { else { OcamlPlugin.ActiveBuildJobs.remove(jobName); } - + // time long compilingTime = -1; - if (executedTime[0] > 0) + if (executedTime[0] > 0) compilingTime = System.currentTimeMillis() - executedTime[0]; if (compilingTime >= 0) { long minutes = TimeUnit.MILLISECONDS.toMinutes(compilingTime); - long seconds = TimeUnit.MILLISECONDS.toSeconds(compilingTime) - + long seconds = TimeUnit.MILLISECONDS.toSeconds(compilingTime) - TimeUnit.MINUTES.toSeconds(minutes); String time = ""; if (minutes > 1) @@ -113,14 +113,14 @@ public void done(IJobChangeEvent event) { } else Misc.appendToOcamlConsole("Time: unknown"); - + Misc.appendToOcamlConsole(""); } - + @Override public void awake(IJobChangeEvent event) { } - + @Override public void aboutToRun(IJobChangeEvent event) { } From 57b437a0ca8b3dd771655ec5725ce9f2f9ee82ab Mon Sep 17 00:00:00 2001 From: trungtq Date: Sun, 2 Nov 2014 23:28:36 +0800 Subject: [PATCH 099/127] show CompilerOutput without affecting shortcut keys --- .../CancelCompileAllProjectsAction.java | 5 ++++ .../editor/actions/CleanProjectAction.java | 5 ++++ .../editor/actions/CompileProjectAction.java | 5 +++- .../CancelCompileProjectPopupAction.java | 3 +++ .../actions/CleanProjectPopupAction.java | 23 +++++++++++-------- .../actions/CompileProjectPopupAction.java | 3 +++ 6 files changed, 33 insertions(+), 11 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java b/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java index 308f9aa..9f28683 100644 --- a/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java +++ b/Ocaml/src/ocaml/editor/actions/CancelCompileAllProjectsAction.java @@ -45,6 +45,11 @@ public void run(IAction action) { if (project == null) return; + // show compiler output + Misc.showView(OcamlCompilerOutput.ID); + // then activate current editor (to resolve shortcut-key issues) + page.activate(editorPart); + final String jobName = "Cancelling compiling jobs"; Job job = new Job(jobName) { diff --git a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java index a343912..09fb562 100644 --- a/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java +++ b/Ocaml/src/ocaml/editor/actions/CleanProjectAction.java @@ -52,6 +52,11 @@ public void run(IAction action) { final long[] executedTime = new long[1]; executedTime[0] = -1; + // show compiler output + Misc.showView(OcamlCompilerOutput.ID); + // then activate current editor (to resolve shortcut-key issues) + page.activate(editorPart); + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { diff --git a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java index 534b3c4..3d3cec3 100644 --- a/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java +++ b/Ocaml/src/ocaml/editor/actions/CompileProjectAction.java @@ -92,7 +92,10 @@ protected IStatus run(IProgressMonitor monitor) { } }; -// Misc.showView(OcamlCompilerOutput.ID); + // show compiler output + Misc.showView(OcamlCompilerOutput.ID); + // then activate current editor (to resolve shortcut-key issues) + page.activate(editorPart); job.setPriority(Job.BUILD); /* diff --git a/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java index 70928aa..3c1306a 100644 --- a/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CancelCompileProjectPopupAction.java @@ -37,6 +37,9 @@ public static void cancelCompileProject(IProject project) { public void run(IAction action) { final String jobName = "Cancelling compiling jobs"; + // show compiler output + Misc.showView(OcamlCompilerOutput.ID); + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { diff --git a/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java index 5f888e2..b8cad5a 100644 --- a/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CleanProjectPopupAction.java @@ -31,10 +31,13 @@ public CleanProjectPopupAction() { public void run(IAction action) { if (project != null) { final String jobName = "Cleaning project " + project.getName(); - + final long[] executedTime = new long[1]; executedTime[0] = -1; + // show compiler output + Misc.showView(OcamlCompilerOutput.ID); + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { @@ -59,15 +62,15 @@ protected IStatus run(IProgressMonitor monitor) { @Override public void sleeping(IJobChangeEvent event) { } - + @Override public void scheduled(IJobChangeEvent event) { } - + @Override public void running(IJobChangeEvent event) { } - + @Override public void done(IJobChangeEvent event) { // cleaning job was cancelled @@ -78,14 +81,14 @@ public void done(IJobChangeEvent event) { else { OcamlPlugin.ActiveBuildJobs.remove(jobName); } - + // time long cleaningTime = -1; - if (executedTime[0] > 0) + if (executedTime[0] > 0) cleaningTime = System.currentTimeMillis() - executedTime[0]; if (cleaningTime >= 0) { long minutes = TimeUnit.MILLISECONDS.toMinutes(cleaningTime); - long seconds = TimeUnit.MILLISECONDS.toSeconds(cleaningTime) - + long seconds = TimeUnit.MILLISECONDS.toSeconds(cleaningTime) - TimeUnit.MINUTES.toSeconds(minutes); String time = ""; if (minutes > 1) @@ -100,14 +103,14 @@ public void done(IJobChangeEvent event) { } else Misc.appendToOcamlConsole("Time: unknown"); - + Misc.appendToOcamlConsole(""); } - + @Override public void awake(IJobChangeEvent event) { } - + @Override public void aboutToRun(IJobChangeEvent event) { } diff --git a/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java index 73bdda5..04052c3 100644 --- a/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java +++ b/Ocaml/src/ocaml/popup/actions/CompileProjectPopupAction.java @@ -45,6 +45,9 @@ public void run(IAction action) { final String jobName = "Compiling project " + project.getName(); + // show compiler output + Misc.showView(OcamlCompilerOutput.ID); + Job job = new Job(jobName) { @Override protected IStatus run(IProgressMonitor monitor) { From 3a65883f7914b9ca9c70c362a78620109741ba94 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sun, 2 Nov 2014 23:35:03 +0800 Subject: [PATCH 100/127] minor changes --- Ocaml/src/ocaml/util/Misc.java | 63 ++++++++++++++++------------------ 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/Ocaml/src/ocaml/util/Misc.java b/Ocaml/src/ocaml/util/Misc.java index 8022a88..05ebb95 100644 --- a/Ocaml/src/ocaml/util/Misc.java +++ b/Ocaml/src/ocaml/util/Misc.java @@ -220,7 +220,7 @@ public static IFile[] getMliFiles(final IProject project) { /** * Keep all the mli files in the list and the ml files when there is no corresponding mli - * + * * @return the mli files and the ml files which don't have a corresponding mli file */ public static String[] filterInterfaces(String[] mlmliFiles) { @@ -303,7 +303,7 @@ public static boolean isGeneratedFile(IFile file) { /** * Return a persistent property associated with the project. The qualified name uses the "ocaml" * qualifier. - * + * * @return the value of the property, or an empty string if it couldn't be retrieved */ public static String getProjectProperty(IProject project, String propertyName) { @@ -321,7 +321,7 @@ public static String getProjectProperty(IProject project, String propertyName) { /** * Return a file persistent property - * + * * @see getProjectProperty */ public static String getFileProperty(IFile file, String propertyName) { @@ -339,7 +339,7 @@ public static String getFileProperty(IFile file, String propertyName) { /** * Return a folder persistent property - * + * * @see getProjectProperty */ public static String getFolderProperty(IFolder folder, String propertyName) { @@ -373,7 +373,7 @@ public static String getResourceProperty(IResource resource, String propertyName /** * set a project persistent property - * + * * @see getProjectProperty */ public static void setProjectProperty(IProject project, String propertyName, String value) { @@ -387,7 +387,7 @@ public static void setProjectProperty(IProject project, String propertyName, Str /** * set a file persistent property - * + * * @see getProjectProperty */ public static void setFileProperty(IFile file, String propertyName, String value) { @@ -401,7 +401,7 @@ public static void setFileProperty(IFile file, String propertyName, String value /** * set a folder persistent property - * + * * @see getProjectProperty */ public static void setFolderProperty(IFolder folder, String propertyName, String value) { @@ -417,9 +417,7 @@ public static void setFolderProperty(IFolder folder, String propertyName, String * Append text to the OCaml compiler output (in a UI-Thread) */ public static void appendToOcamlConsole(final String msg) { - Display.getDefault().syncExec(new Runnable() { - public void run() { try { final IWorkbenchPage activePage = PlatformUI.getWorkbench() @@ -428,7 +426,6 @@ public void run() { .findView(OcamlCompilerOutput.ID); if (console == null) { console = (OcamlCompilerOutput) activePage.showView(OcamlCompilerOutput.ID); - } console.appendln(msg); } catch (PartInitException pe) { @@ -481,7 +478,7 @@ public static void refreshFileSystem(IProject proj, IProgressMonitor monitor) { /** * Create an icon from a filename - * + * * @return an image, or null if there was an error */ public static Image createIcon(String name) { @@ -499,7 +496,7 @@ public static Image createIcon(String name) { /** * Get the file with the given extension corresponding to the given ml file. - * + * * @param project * the project in which the ml file resides * @param mlPath @@ -537,10 +534,10 @@ public static File getOtherFileFor(IProject project, IPath mlPath, String extens return null; } - + /** * Get the file with the given extension corresponding to the given ml file. - * + * * @param mlPath * the full absolute filesystem path of the ml file * @param extension @@ -566,14 +563,14 @@ public static File getOtherFileFor(IPath mlPath, String extension) { return null; } - + /** Remove carriage returns */ public static String CRLFtoLF(String str){ return str.replace("\r", ""); } - + private static HashSet keywordsHashset; - + /** Can this character be part of an OCaml identifier */ public static boolean isOcamlIdentifierChar(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_' || c == '\''); @@ -586,13 +583,13 @@ public static boolean isOcamlIdentifierFirstChar(char c) { /** Test whether this string is a valid OCaml identifier (lowercase) */ public static boolean isValidOcamlIdentifier(String str) { - + if(str.length() < 1) return false; - + char[] chars = new char[str.length()]; str.getChars(0, str.length(), chars, 0); - + if(!isOcamlIdentifierFirstChar(chars[0])) return false; @@ -605,10 +602,10 @@ public static boolean isValidOcamlIdentifier(String str) { for(String word : ILanguageWords.keywords) keywordsHashset.add(word); } - + if(keywordsHashset.contains(str)) return false; - + return true; } @@ -620,10 +617,10 @@ public static boolean isValidOcamlIdentifier(String str) { public static void setShareableProperty(IResource resource, String name, String value) { setShareableProperty(resource, new QualifiedName(OcamlPlugin.QUALIFIER, name), value); } - + public static void setShareableProperty(IResource resource, QualifiedName name, String value) { String preferenceName = name.getLocalName(); - IPath resourcePath = resource.getFullPath(); + IPath resourcePath = resource.getFullPath(); try { // 1. save in /.settings/ocaml.pref Preferences settings = getPreferences(resource.getProject(), preferenceName, true); @@ -633,20 +630,20 @@ public static void setShareableProperty(IResource resource, QualifiedName name, settings.put(getKeyFor(resourcePath), value); // TODO disable the listener (if any) so we don't react to changes made by ourselves settings.flush(); - - // 2. also save in /.medatada to decorate icons (see plugin.xml) + + // 2. also save in /.medatada to decorate icons (see plugin.xml) resource.setPersistentProperty(name, value); - + } catch (BackingStoreException e) { // OcamlPlugin.logError("error in OcamlPlugin.setPersistentProperty", e); } catch (ResourceException e) { - + } catch (Exception e) { - + } } - /** Load a property from /.settings/. + /** Load a property from /.settings/. * If it does not exist, fallback to see /.metadata/ */ public static String getShareableProperty(IResource resource, String name) { return getShareableProperty(resource, new QualifiedName(OcamlPlugin.QUALIFIER, name)); @@ -667,7 +664,7 @@ public static String getShareablePropertyNull(IResource resource, QualifiedName if (prefs == null) { return migrateOldSettingIfAny(resource, name); } - + String value = prefs.get(getKeyFor(resource.getFullPath()), null); if(value!=null) { return value; @@ -675,7 +672,7 @@ public static String getShareablePropertyNull(IResource resource, QualifiedName return migrateOldSettingIfAny(resource, name); } } - + // for backward compatibility static String migrateOldSettingIfAny(IResource resource, QualifiedName name) { String oldVerSetting = null; @@ -708,7 +705,7 @@ private static Preferences getPreferences(IProject project, String preferenceNam } return null; } - + private static String getKeyFor(IPath resourcePath) { return resourcePath.segmentCount() > 1 ? resourcePath.removeFirstSegments(1).toString() : ""; } From 278df3cee0d1803a85a5a60ba109a39a6a40948a Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 3 Nov 2014 23:51:43 +0800 Subject: [PATCH 101/127] change completion priority --- Ocaml/src/ocaml/editors/OcamlEditor.java | 66 +++++++++---------- .../src/ocaml/editors/lex/OcamllexEditor.java | 6 +- .../ocaml/editors/yacc/OcamlyaccEditor.java | 20 +++--- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index be79e10..daf1801 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -98,7 +98,7 @@ public OcamlEditor() { this.setSourceViewerConfiguration(new OcamlSourceViewerConfig(this)); // this.setRangeIndicator(new DefaultRangeIndicator()); } - + /** The debug cursor (as a red I-beam) */ private DebugVisuals caret; @@ -109,10 +109,10 @@ public ITextViewer getTextViewer() { @Override protected void createActions() { super.createActions(); - + final ISourceViewer sourceViewer = this.getSourceViewer(); final StyledText textWidget = sourceViewer.getTextWidget(); - final OcamlSourceViewerConfig sourceViewerConfig = + final OcamlSourceViewerConfig sourceViewerConfig = (OcamlSourceViewerConfig) this.getSourceViewerConfiguration(); @@ -129,7 +129,7 @@ protected void createActions() { * AnnotationPainter(getSourceViewer(), null); * annotationPainter.addAnnotationType * ("Ocaml.ocamlSyntaxErrorMarker"); - * + * * paintManager.addPainter(annotationPainter); */ @@ -151,7 +151,7 @@ protected void createActions() { // parse the OCaml libraries in a background thread try { CompletionJob job = new CompletionJob("Parsing ocaml library mli files", null); - job.setPriority(CompletionJob.LONG); // Trung changes priority + job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority job.schedule(); } catch (Exception e) { OcamlPlugin.logError("ocaml plugin error", e); @@ -162,43 +162,43 @@ protected void createActions() { } catch (Exception e) { OcamlPlugin.logError("ocaml plugin error", e); } - + // synchronize with outline when double-click mouse textWidget.addMouseListener(new MouseListener() { @Override public void mouseUp(MouseEvent e) { } - + @Override public void mouseDown(MouseEvent e) { } - + @Override public void mouseDoubleClick(MouseEvent e) { - if (sourceViewerConfig.isContentAssistantActive() || e == null) + if (sourceViewerConfig.isContentAssistantActive() || e == null) return; - + synchronizeOutline(); } }); - - - // Trung: don't rebuild outline when text is changed because it + + + // Trung: don't rebuild outline when text is changed because it // slow down the system /* final ISourceViewer viewer = this.getSourceViewer(); final OcamlSourceViewerConfig viewerConfig = (OcamlSourceViewerConfig) this.getSourceViewerConfiguration(); viewer.addTextListener(new ITextListener() { - + public void textChanged(TextEvent event) { // Trung: rebuild only when content assistant is inactive - if (viewerConfig.isContentAssistantActive() || event == null) + if (viewerConfig.isContentAssistantActive() || event == null) return; - + DocumentEvent docEvent = event.getDocumentEvent(); if (docEvent == null) return; - + String text = docEvent.getText().trim(); if (!text.isEmpty()) rebuildOutline(50, false); // don't sync outline with editor @@ -229,7 +229,7 @@ public void doSetInput(IEditorInput input) throws CoreException { // parse the project interfaces in a background thread CompletionJob job = new CompletionJob("Parsing ocaml project mli files", project); - job.setPriority(CompletionJob.LONG); // Trung changes priority + job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority job.schedule(); if (input instanceof IFileEditorInput) { @@ -243,8 +243,8 @@ public void doSetInput(IEditorInput input) throws CoreException { * if (this.fOutlinePage != null) this.fOutlinePage.setInput(input); */ } - - + + /** * We give the outline to Eclipse when it asks for an adapter with the @@ -277,8 +277,8 @@ public void createPartControl(Composite parent) { StyledText styledText = this.getSourceViewer().getTextWidget(); styledText.setTabs(getTabSize()); } - - + + public static int getTabSize() { return OcamlPlugin.getInstance().getPreferenceStore().getInt( @@ -321,7 +321,7 @@ public int getCaretOffset() { OcamlPlugin.logError("selection is not instanceof TextSelection"); return -1; } - + public static class LineColumn { private final int line; private final int column; @@ -339,7 +339,7 @@ public int getColumn() { return column; } } - + /** @return the current selection offset in the editor, as a (line,column) position. */ public LineColumn getSelectionLineColumn() { ISelection sel = getSelectionProvider().getSelection(); @@ -355,7 +355,7 @@ public LineColumn getSelectionLineColumn() { OcamlPlugin.logError(e); return null; } - + } OcamlPlugin.logError("selection is not instanceof TextSelection"); return null; @@ -463,7 +463,7 @@ public IProgressMonitor getMonitor() { @Override public void doSave(IProgressMonitor monitor) { super.doSave(monitor); - + // rebuild Outline when file is saved rebuildOutline(50, false); @@ -493,7 +493,7 @@ public void doSave(IProgressMonitor monitor) { * @Override protected void editorContextMenuAboutToShow(IMenuManager menu) * { IFile file = this.getFileBeingEdited(); * super.editorContextMenuAboutToShow(menu); - * + * * MenuManager ocamlGroup = new MenuManager("OCaml"); menu.add(new * Separator()); menu.add(ocamlGroup); ocamlGroup.add(new * GenDocAction("GenDoc", file)); } @@ -539,7 +539,7 @@ public void rebuildOutline(int delay, boolean syncWithEditor) { @Override public void handleCursorPositionChanged() { super.handleCursorPositionChanged(); - + fireCursorPositionChanged(getTextViewer().getSelectedRange()); final OcamlEditor editor = this; @@ -549,21 +549,21 @@ public void handleCursorPositionChanged() { IRegion region = hover.getHoverRegion(viewer, offset); String message = ""; - + if (OcamlPlugin.getInstance().getPreferenceStore().getBoolean( PreferenceConstants.P_SHOW_MARKERS_IN_STATUS_BAR)) { message = hover.getMarkerInfoOneLine(viewer, region); } - + // only display type info when there isn't any markers - if (message.isEmpty() + if (message.isEmpty() && OcamlPlugin.getInstance().getPreferenceStore().getBoolean( PreferenceConstants.P_SHOW_TYPES_IN_STATUS_BAR)) { message = hover.getTypeInfoOneLine(viewer, region); if (message.contains("more lines...")) message = ""; } - + final String statusMessage = message; Display.getCurrent().asyncExec(new Runnable() { public void run() { @@ -571,7 +571,7 @@ public void run() { } }); } - + @Override public void setStatusLineMessage(String message) { super.setStatusLineMessage(message); diff --git a/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java b/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java index 3d45dc3..d7b3e53 100644 --- a/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java +++ b/Ocaml/src/ocaml/editors/lex/OcamllexEditor.java @@ -45,7 +45,7 @@ protected void createActions() { super.createActions(); final ISourceViewer viewer = getSourceViewer(); - + paintManager = new PaintManager(viewer); matchingCharacterPainter = new MatchingCharacterPainter(viewer, new OcamlCharacterPairMatcher()); @@ -53,10 +53,10 @@ protected void createActions() { paintManager.addPainter(matchingCharacterPainter); OcamlPlugin.getInstance().checkPaths(); - + // effectue le parsing des bibliothèques ocaml en arrière plan CompletionJob job = new CompletionJob("Parsing ocaml library mli files", null); - job.setPriority(CompletionJob.LONG); // Trung changes priority + job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority job.schedule(); } diff --git a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java index 380bdc4..6e96bd1 100644 --- a/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java +++ b/Ocaml/src/ocaml/editors/yacc/OcamlyaccEditor.java @@ -49,7 +49,7 @@ public OcamlyaccEditor() { @Override protected void createActions() { super.createActions(); - + final ISourceViewer viewer = getSourceViewer(); paintManager = new PaintManager(viewer); @@ -62,10 +62,10 @@ protected void createActions() { // effectue le parsing des bibliothèques ocaml en arrière plan CompletionJob job = new CompletionJob("Parsing ocaml library mli files", null); - job.setPriority(CompletionJob.LONG); // Trung changes priority + job.setPriority(CompletionJob.INTERACTIVE); // Trung changes priority job.schedule(); - - + + viewer.addTextListener(new ITextListener() { public void textChanged(TextEvent event) { @@ -123,11 +123,11 @@ public void doSave(IProgressMonitor monitor) { CompileProjectPopupAction.compileProject(this.getProject()); } } - - + + private OcamlYaccOutlineControl outline; private YaccOutlineJob outlineJob = null; - + /** * We give the outline to Eclipse when it asks for an adapter with the outline class. */ @@ -141,7 +141,7 @@ public Object getAdapter(@SuppressWarnings("unchecked") Class required) { } return super.getAdapter(required); } - + public void rebuildOutline(int delay) { /* * Trung: rebuilding outline will dispose all completion proposal @@ -166,6 +166,6 @@ public void rebuildOutline(int delay) { outlineJob.schedule(delay); } - - + + } From 1cb716e8ac02914be97b30394b3a6ab3a2f22188 Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 5 Nov 2014 00:27:33 +0800 Subject: [PATCH 102/127] keep empty trailing lines when comment/uncomment block of code --- .../src/ocaml/editor/actions/CommentSelectionAction.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java b/Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java index 16d831f..1a82fa9 100644 --- a/Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java +++ b/Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java @@ -63,7 +63,7 @@ public void run(IAction action) { endLineInfo = document.getLineInformation(endLine); endOffset = endLineInfo.getOffset() + endLineInfo.getLength(); - TextSelection sel = new TextSelection(startOffset, endOffset - startOffset); + TextSelection sel = new TextSelection(startOffset, endOffset - startOffset + 1); editor.getSelectionProvider().setSelection(sel); } catch (BadLocationException e) { @@ -86,7 +86,7 @@ private String switchComment(String input) { final int tabSize = OcamlEditor.getTabSize(); // split the string into lines - String[] lines = input.split("\\r?\\n"); + String[] lines = input.split("\\r?\\n", -1); // uncomment if (isCommented(lines)) { @@ -163,8 +163,8 @@ else if (line.charAt(i) == ' ') // comment character should be inserted at the shortest indentation position // and at the end of longest line. private String comment(String line, int indent, int length, int tabSize) { - - if (line.trim().equals("")) + + if (line.trim().equals("")) return line; StringBuilder builder = new StringBuilder(); From 6c8353a9ab38291e2f8b10a3d8ca782c744e9190 Mon Sep 17 00:00:00 2001 From: trungtq Date: Thu, 20 Nov 2014 01:23:31 +0800 Subject: [PATCH 103/127] update location in parser --- Ocaml/src/ocaml/parser/Def.java | 83 +++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/Ocaml/src/ocaml/parser/Def.java b/Ocaml/src/ocaml/parser/Def.java index 50d8183..3bcc5ac 100644 --- a/Ocaml/src/ocaml/parser/Def.java +++ b/Ocaml/src/ocaml/parser/Def.java @@ -73,11 +73,11 @@ public enum Type { * in the outline when a ".annot" file is present and up-to-date) */ private String ocamlType; - + public String getOcamlType() { return ocamlType; } - + public void setOcamlType(String type) { if (type == null) this.ocamlType = ""; @@ -171,15 +171,26 @@ public Def(Def def) { void add(Symbol s) { assert s instanceof Def; - children.add((Def) s); + + Def def = (Def) s; + children.add(def); + + // update location + this.defOffsetEnd = def.defOffsetEnd; } /** Creates a new dummy node as root of a and b, and return this node */ public static Def root(Symbol a) { assert a instanceof Def; + Def def = new Def(); Def defa = (Def) a; def.children.add(defa); + + // update location + def.defOffsetStart = defa.defOffsetStart; + def.defOffsetEnd = defa.defOffsetEnd; + return def; } @@ -196,6 +207,10 @@ public static Def root(Symbol a, Symbol b) { def.children.add(defa); def.children.add(defb); + // update location + def.defOffsetStart = defa.defOffsetStart; + def.defOffsetEnd = defb.defOffsetEnd; + return def; } @@ -215,6 +230,10 @@ public static Def root(Symbol a, Symbol b, Symbol c) { def.children.add(defb); def.children.add(defc); + // update location + def.defOffsetStart = defa.defOffsetStart; + def.defOffsetEnd = defc.defOffsetEnd; + return def; } @@ -237,6 +256,10 @@ public static Def root(Symbol a, Symbol b, Symbol c, Symbol d) { def.children.add(defc); def.children.add(defd); + // update location + def.defOffsetStart = defa.defOffsetStart; + def.defOffsetEnd = defd.defOffsetEnd; + return def; } @@ -266,7 +289,7 @@ private void collapseAux(Def node, ArrayList nodes, boolean bClean) { flatList.add(node); while(!flatList.isEmpty()) { Def def = flatList.removeFirst(); - + if (def.type == Type.Dummy || bClean && def.type == Type.Identifier) { for (int i = def.children.size() - 1; i>=0; i--) { Def child = def.children.get(i); @@ -278,8 +301,8 @@ private void collapseAux(Def node, ArrayList nodes, boolean bClean) { def.clean(); } } - - + + } /** @@ -301,7 +324,7 @@ void findIdents(ArrayList idents) { for (Def child : children) child.findIdents(idents); } - + void findDefNames(ArrayList defNames) { if (this.name != null && !this.name.isEmpty()) defNames.add(this.name); @@ -406,7 +429,7 @@ else if (node.type == Type.Parameter) { Def simpleNode = new Def(node); simpleNode.children = new ArrayList(); nodes.add(simpleNode); - + // find children for (Def d : node.children) findRealChildren(d, nodes, false, parserError); @@ -425,10 +448,10 @@ else if (node.type == Type.Identifier) { nodes.add(node); } } - + } // go down to find real children - else if (node.type == Type.Dummy + else if (node.type == Type.Dummy || node.type == Type.Functor || node.type == Type.Sig || node.type == Type.Object @@ -446,17 +469,17 @@ else if (node.type == Type.Dummy /** completely unnest the 'in' definitions */ /* * public void completelyUnnestIn(Def parent, int index) { - * + * * for(int i = 0; i < children.size(); i++){ Def child = children.get(i); * child.completelyUnnestIn(this, i); } - * + * * ArrayList newChildren = new ArrayList(); - * + * * int j = 1; for(int i = 0; i < children.size(); i++){ Def child = children.get(i); - * + * * if(type == Type.LetIn && child.type == Type.LetIn){ parent.children.add(index + j++, child); * }else newChildren.add(child); } - * + * * children = newChildren; } */ @@ -546,12 +569,12 @@ public IRegion getNameRegion(IDocument doc) { return new Region(startOffset, endOffset - startOffset + 1); } - + /** Returns the region in the document covered by this definition and its body */ public Region getFullRegion() { // startOffset is computed by def name int startOffset = posStart; - + // endOffset is computed by def's full definition Def lastDescendant = this; while (lastDescendant.children != null & lastDescendant.children.size() > 0) { @@ -567,7 +590,7 @@ public Region getFullRegion() { return new Region(startOffset, endOffset - startOffset + 1); } - + /** The ocamldoc comment associated with this definition */ public String comment = ""; @@ -603,7 +626,7 @@ public void setComment(String text) { public static String cleanString(String str) { if (str == null) return ""; - + // remove all redundant spaces String[] lines = str.split("\\n"); StringBuilder stringBuilder = new StringBuilder(); @@ -620,28 +643,28 @@ public static String cleanString(String str) { private String body = ""; private String filename = ""; - + public void setBody(String body) { // this.body = Misc.beautify(clean(body)); this.body = Misc.beautify(body); } - + public String getBody() { return this.body; } - - + + public void setFileName(String filename) { this.filename = filename; } - + public String getFileName() { return filename; } - + public String getTypeName() { - - + + if (type == Type.Dummy) return "Dummy"; else if (type == Type.In) @@ -701,7 +724,7 @@ else if (type == Type.ParserError) else return "Unknown"; } - + public String parentName = ""; @@ -711,10 +734,10 @@ else if (type == Type.ParserError) * 0; try { firstLineOffset = doc.getLineOffset(getLine(defPosStart)); lastLineOffset = * doc.getLineOffset(getLine(defPosEnd)); } catch (BadLocationException e) { * OcamlPlugin.logError("offset error", e); return null; } - * + * * int startOffset = firstLineOffset + getColumn(defPosStart); int endOffset = lastLineOffset + * getColumn(defPosEnd); - * + * * return new Region(startOffset, endOffset - startOffset + 1); } */ } From 14f0cd73c40a07fbbf97877ae212d2da0e50551c Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 24 Nov 2014 17:30:32 +0800 Subject: [PATCH 104/127] search definitions in a locally aliased module --- .../completion/OcamlCompletionProcessor.java | 178 +++++++++--------- .../ocaml/editors/OcamlHyperlinkDetector.java | 94 +++++---- Ocaml/src/ocaml/parser/OcamlParser.g | 6 +- Ocaml/src/ocaml/parser/OcamlParser.java | 6 +- 4 files changed, 152 insertions(+), 132 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 8ed1fb0..307f46a 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -41,9 +41,9 @@ public class OcamlCompletionProcessor implements IContentAssistProcessor { private final TextEditor editor; - + private final IProject project; - + // cache last parsed annotation file for speed up private TypeAnnotation[] lastUsedAnnotations = new TypeAnnotation[0]; private String lastParsedFileName = ""; @@ -76,7 +76,7 @@ public OcamlCompletionProcessor(OcamlyaccEditor edit, String regionType) { * completion box when he types a space */ private int lastOffset = -1; - + /** * Compute and return completion proposals available at the offset documentOffset. */ @@ -126,12 +126,12 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int Def interfacesDefinitionsRoot = null; if (project != null) interfacesDefinitionsRoot = CompletionJob.buildDefinitionsTree(project, false); - + proposals = findCompletionProposals(completion, interfacesDefinitionsRoot, document, documentOffset); } else { proposals = new OcamlCompletionProposal[0]; OcamlPlugin.logInfo("Completion proposals skipped (background job not done yet)"); - } + } ICompletionProposal[] templateCompletionProposals; @@ -157,7 +157,7 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int * ocamlEditor.getOutlineDefinitionsTree(); if (def != null) { ICompletionProposal[] * moduleCompletionProposals = findModuleCompletionProposals( def, documentOffset, lastWord.length(), * lastWord); - * + * * for (int j = 0; j < moduleCompletionProposals.length; j++) * allProposals.add(moduleCompletionProposals[j]); } else OcamlPlugin * .logError("OcamlCompletionProcessor:computeCompletionProposals : module definitions=null"); } @@ -170,7 +170,7 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int /* * if (allProposals.size() == 2) { ICompletionProposal prop1 = allProposals.get(0); * ICompletionProposal prop2 = allProposals.get(1); - * + * * if (prop1 instanceof OcamlCompletionProposal && prop2 instanceof SimpleCompletionProposal && * prop1.getDisplayString().equals(prop2.getDisplayString())) allProposals.remove(1); } */ @@ -206,7 +206,7 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int /** * Find the completions matching the argument completion from all the definitions found in * the definitionsRoot tree. - * + * * @return the completions found */ private OcamlCompletionProposal[] findCompletionProposals(String completion, @@ -215,7 +215,7 @@ private OcamlCompletionProposal[] findCompletionProposals(String completion, int offset) { ArrayList proposals; - + String moduleName = editor.getEditorInput().getName(); if (moduleName.endsWith(".ml")) moduleName = moduleName.substring(0, moduleName.length() - 3); @@ -225,18 +225,18 @@ else if (moduleName.endsWith(".mli")) moduleName = Character.toUpperCase(moduleName.charAt(0)) + moduleName.substring(1); - if (completion.contains(".")) + if (completion.contains(".")) proposals = processDottedCompletion(completion, interfacesDefsRoot, moduleName, doc, offset, completion.length()); else proposals = processNondottedCompletion(completion, interfacesDefsRoot, moduleName, doc, offset, completion.length()); - + proposals = removeDuplicatedCompletionProposal(proposals); - + return proposals.toArray(new OcamlCompletionProposal[0]); } - + // completion string must contained dots private ArrayList processDottedCompletion(String completion, Def interfacesDefsRoot, @@ -246,7 +246,7 @@ private ArrayList processDottedCompletion(String comple int length) { ArrayList proposals = new ArrayList(); - + if (interfacesDefsRoot == null) return proposals; @@ -264,15 +264,15 @@ private ArrayList processDottedCompletion(String comple break; if (!Character.isUpperCase(parts[i].charAt(0))) break; - suffix = prefix + "." + suffix; + suffix = prefix + "." + suffix; prefix = parts[i]; i--; } - + boolean isLowerCasePrefix= false; if (prefix.length() > 0 && Character.isLowerCase(prefix.charAt(0))) isLowerCasePrefix = true; - + Def currentDef = null; for (Def def: interfacesDefsRoot.children) { if (def.name.equals(moduleName)) { @@ -280,13 +280,13 @@ private ArrayList processDottedCompletion(String comple break; } } - + /* * prefix is a lower-case identifier, hence look for suffix completion * in the current module, sub-modules, included modules or opened modules */ if (isLowerCasePrefix) { - + // find in current def for (Def def : currentDef.children) { // look for completion of suffix in the current module @@ -295,9 +295,9 @@ private ArrayList processDottedCompletion(String comple proposals.add(new OcamlCompletionProposal(proposedDef, offset, suffix.length())); } - + // look for completion in opened or included module of current module - // by attach the involved module name to suffix and find new completion + // by attach the involved module name to suffix and find new completion if (def.type == Def.Type.Open || def.type == Def.Type.Include) { String newCompletion = def.name + "." + suffix; proposals.addAll(processDottedCompletion(newCompletion, @@ -305,7 +305,7 @@ private ArrayList processDottedCompletion(String comple offset, suffix.length())); } } - + // completion maybe modules's name for (Def def : interfacesDefsRoot.children) { if (checkCompletion(def, suffix) && isCompletionDef(def)) { @@ -327,11 +327,11 @@ private ArrayList processDottedCompletion(String comple stop = true; if (currentDef == null) break; - + for (Def def : currentDef.children) { - if (!def.name.equals(realPrefix)) + if (!def.name.equals(realPrefix)) continue; - + if (def.type == Def.Type.Module) { // find in sub-modules proposals.addAll(lookupProposalsCompletionInDef( @@ -341,7 +341,7 @@ private ArrayList processDottedCompletion(String comple else if (def.type == Def.Type.ModuleAlias) { if (def.children.size() > 0) { String aliasedName = def.children.get(0).name; - if (realPrefix.equals(aliasedName)) + if (realPrefix.equals(aliasedName)) stop = true; else { realPrefix = aliasedName; @@ -352,7 +352,7 @@ else if (def.type == Def.Type.ModuleAlias) { } } } - + // find in other modules for (Def def: interfacesDefsRoot.children) { if (def.name.equals(realPrefix)) @@ -375,7 +375,7 @@ else if (def.type == Def.Type.ModuleAlias) { return proposals; } - + private ArrayList processNondottedCompletion(String completion, Def interfacesDefsRoot, @@ -385,10 +385,10 @@ private ArrayList processNondottedCompletion(String com int length) { ArrayList proposals = new ArrayList(); - + if (interfacesDefsRoot == null) return proposals; - + /* * look in def root */ @@ -398,7 +398,7 @@ private ArrayList processNondottedCompletion(String com proposals.add(new OcamlCompletionProposal(proposedDef, offset, length)); } } - + /* * looked in current module */ @@ -414,21 +414,21 @@ private ArrayList processNondottedCompletion(String com // look down from top of current module final Def nearestDef = findSmallestDefAtOffset(currentDef, offset, document); proposals.addAll(bottomUpFindProposals(completion, nearestDef, offset)); - + for (Def def: currentDef.children) { if (checkCompletion(def, completion)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, offset, length)); } } - + /* * look in opened module of current module */ for (Def def : currentDef.children) { - if (def.type != Def.Type.Open && def.type != Def.Type.Include) + if (def.type != Def.Type.Open && def.type != Def.Type.Include) continue; - + String newCompletion = def.name + "." + completion; proposals.addAll(processDottedCompletion(newCompletion, interfacesDefsRoot, moduleName, document, offset, length)); @@ -439,13 +439,13 @@ private ArrayList processNondottedCompletion(String com * look in Pervasives module, which is always opended */ for (Def def: interfacesDefsRoot.children) { - if (!def.name.equals("Pervasives")) + if (!def.name.equals("Pervasives")) continue; - + for (Def d: def.children) { if (d == null || d.name == null) break; - + if (checkCompletion(d, completion) && isCompletionDef(d)) { Def proposedDef = createProposalDef(project, d); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); @@ -455,7 +455,7 @@ private ArrayList processNondottedCompletion(String com return proposals; } - + private ArrayList lookupProposalsCompletionInDef(String completion, Def defsRoot, Def interfacesDefRoot, @@ -464,7 +464,7 @@ private ArrayList lookupProposalsCompletionInDef(String int length) { ArrayList proposals = new ArrayList(); - + if (defsRoot == null) return proposals; @@ -480,18 +480,18 @@ private ArrayList lookupProposalsCompletionInDef(String break; if (!Character.isUpperCase(parts[i].charAt(0))) break; - suffix = prefix + "." + suffix; + suffix = prefix + "." + suffix; prefix = parts[i]; i--; } - + // look inside def roots first for (Def def: defsRoot.children) { if (def.name.equals(prefix)) proposals.addAll(lookupProposalsCompletionInDef(suffix, def, interfacesDefRoot, document, offset, length)); } - + // look inside included module for (Def def1: defsRoot.children) { if (def1.type == Def.Type.Include) { @@ -504,7 +504,7 @@ private ArrayList lookupProposalsCompletionInDef(String completion,includedDefRoot, interfacesDefRoot, document, offset, length)); } - + } // look for included def in interfaces root defs for (Def def2: interfacesDefRoot.children) { @@ -514,7 +514,7 @@ private ArrayList lookupProposalsCompletionInDef(String completion, includedDefRoot, interfacesDefRoot, document, offset, length)); } - + } } } @@ -541,7 +541,7 @@ private ArrayList lookupProposalsCompletionInDef(String completion, includedDefRoot, interfacesDefRoot, document, offset, length)); } - + } // look for included def in interfaces root defs for (Def def2: interfacesDefRoot.children) { @@ -551,7 +551,7 @@ private ArrayList lookupProposalsCompletionInDef(String completion, includedDefRoot, interfacesDefRoot, document, offset, length)); } - + } } } @@ -560,10 +560,10 @@ private ArrayList lookupProposalsCompletionInDef(String return proposals; } - + private ArrayList bottomUpFindProposals(String completion, Def node, int offset) { ArrayList proposals = new ArrayList(); - + if (node == null) return proposals; @@ -581,7 +581,7 @@ private ArrayList bottomUpFindProposals(String completi if (def == null || def.name == null) continue; if (checkCompletion(def, completion)) { -// && (def.type == Def.Type.Let +// && (def.type == Def.Type.Let // || def.type == Def.Type.LetIn // || def.type == Def.Type.Parameter)) { Def proposedDef = createProposalDef(project, def); @@ -591,15 +591,15 @@ private ArrayList bottomUpFindProposals(String completi if (travelNode.type == Def.Type.Root) break; - + travelNode = travelNode.parent; } - + return proposals; } - + private ArrayList removeDuplicatedCompletionProposal(ArrayList proposals) { - + ArrayList newProposals = new ArrayList(); HashSet proposalHashSet = new HashSet<>(); for (OcamlCompletionProposal p: proposals) { @@ -609,20 +609,20 @@ private ArrayList removeDuplicatedCompletionProposal(Ar proposalHashSet.add(s); } } - + return newProposals; } - - + + /** Find an identifier (or an open directive) at a position in the document */ private Def findSmallestDefAtOffset(Def def, int offset, IDocument doc) { if (def == null || doc == null) return null; - + if (def.children.size() == 0) return def; - + Def firstChild = def.children.get(0); IRegion region = firstChild.getNameRegion(doc); if (region != null) { @@ -630,7 +630,7 @@ private Def findSmallestDefAtOffset(Def def, int offset, IDocument doc) { return def; } else return null; - + Def nearestChild = null; for (Def d : def.children) { @@ -640,17 +640,17 @@ private Def findSmallestDefAtOffset(Def def, int offset, IDocument doc) { nearestChild = d; } } - + return findSmallestDefAtOffset(nearestChild, offset, doc); } - + private boolean checkCompletion(Def def, String completion) { if (def == null) return false; - + if (def.name == null) return false; - + if (def.name.startsWith(completion)){ // if (def.type != Def.Type.Identifier) // return true; @@ -658,7 +658,7 @@ private boolean checkCompletion(Def def, String completion) { // return true; return true; } - + return false; } @@ -853,7 +853,7 @@ private IContextInformation[] findContextInformation(String expression, Def defi break; if (!Character.isUpperCase(parts[i].charAt(0))) break; - suffix = prefix + "." + suffix; + suffix = prefix + "." + suffix; prefix = parts[i]; i--; } @@ -873,7 +873,7 @@ private IContextInformation[] findContextInformation(String expression, Def defi } else if (def.type == Def.Type.ModuleAlias) { String aliasedName = def.children.get(0).name; - if (moduleName.equals(aliasedName)) + if (moduleName.equals(aliasedName)) stop = true; else { moduleName = aliasedName; @@ -931,15 +931,15 @@ else if (def.type == Def.Type.ModuleAlias) { public String getErrorMessage() { return null; } - + private Def createProposalDef(IProject project, Def def) { Def newDef = new Def(def); if (newDef.type == Def.Type.Let || newDef.type == Def.Type.LetIn || newDef.type == Def.Type.External) { - + String typeInfo = ""; - + // look for type infor in body first String body = newDef.getBody(); int index = body.indexOf(newDef.name); @@ -951,11 +951,11 @@ private Def createProposalDef(IProject project, Def def) { // not found type in body if (typeInfo.isEmpty()) { String filename = newDef.getFileName(); - + // store last used annotation for caching TypeAnnotation[] annotations; long currentTime = System.currentTimeMillis(); - if (filename.equals(lastParsedFileName) + if (filename.equals(lastParsedFileName) && (currentTime - lastParsedTime < cacheTime)) { annotations = lastUsedAnnotations; } @@ -965,7 +965,7 @@ private Def createProposalDef(IProject project, Def def) { lastParsedFileName = filename; lastParsedTime = System.currentTimeMillis(); } - + IDocument document = getDocument(project, filename); typeInfo = computeTypeInfo(newDef, annotations, document); if (!typeInfo.isEmpty()) { @@ -981,7 +981,7 @@ else if (def.type == Def.Type.Type) { return newDef; } - + private IDocument getDocument(IProject project, String filename) { if (project == null) return null; @@ -991,21 +991,21 @@ private IDocument getDocument(IProject project, String filename) { try { IFile[] files = project.getWorkspace().getRoot().findFilesForLocationURI(URIUtil.toURI(filename)); - if (files.length == 0) + if (files.length == 0) return null; - + IFile file = files[0]; IDocumentProvider provider = new TextFileDocumentProvider(); provider.connect(file); IDocument document = provider.getDocument(file); - + return document; } catch (Exception e) { return null; } } - + private TypeAnnotation[] parseModuleAnnotation(IProject project, String filename) { if (project == null) return new TypeAnnotation[0]; @@ -1015,9 +1015,9 @@ private TypeAnnotation[] parseModuleAnnotation(IProject project, String filename try { IFile[] files = project.getWorkspace().getRoot().findFilesForLocationURI(URIUtil.toURI(filename)); - if (files.length == 0) + if (files.length == 0) return new TypeAnnotation[0]; - + IFile file = files[0]; IPath relativeProjectPath = file.getFullPath(); IDocumentProvider provider = new TextFileDocumentProvider(); @@ -1030,37 +1030,37 @@ private TypeAnnotation[] parseModuleAnnotation(IProject project, String filename if (annotFile != null && annotFile.exists()) { TypeAnnotation[] annotations = OcamlAnnotParser.parseFile(annotFile, document); - + return annotations; } } catch (Exception e) { // e.printStackTrace(); return new TypeAnnotation[0]; } - + return new TypeAnnotation[0]; - + } - + private String computeTypeInfo(Def def, TypeAnnotation[] annotations, IDocument document) { try { String typeInfo = ""; IRegion region = def.getNameRegion(document); int offset = region.getOffset(); - + ArrayList found = new ArrayList(); - + if (annotations != null) { for (TypeAnnotation annot : annotations) if (annot.getBegin() <= offset && offset < annot.getEnd()) found.add(annot); - + /* * Search for the smallest hovered type annotation */ TypeAnnotation annot = null; int minSize = Integer.MAX_VALUE; - + for (TypeAnnotation a : found) { int size = a.getEnd() - a.getBegin(); if (size < minSize) { @@ -1068,7 +1068,7 @@ private String computeTypeInfo(Def def, TypeAnnotation[] annotations, IDocument minSize = size; } } - + String docContent = document.get(); if (annot != null) { String expr = docContent.substring(annot.getBegin(), annot.getEnd()); diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index 3c65412..5d36ad6 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -42,7 +42,7 @@ public class OcamlHyperlinkDetector implements IHyperlinkDetector { public OcamlHyperlinkDetector(OcamlEditor editor) { this.editor = editor; } - + /** Caching to speed up consecutive lookups */ private long lastTime = 0; private int lastOffset = -1; @@ -53,10 +53,10 @@ public IHyperlink[] detectHyperlinks(final ITextViewer textViewer, final IRegion IHyperlink hyperlink = makeHyperlink(textViewer, region.getOffset()); if (hyperlink != null) return new IHyperlink[] {hyperlink}; - else + else return null; } - + public IHyperlink makeHyperlink (final ITextViewer textViewer, int offset) { IProject project = editor.getProject(); @@ -64,17 +64,17 @@ public IHyperlink makeHyperlink (final ITextViewer textViewer, int offset) { final Def modulesDefinitionsRoot = editor.getDefinitionsTree(); final Def interfacesDefinitionsRoot; - + if(project != null) interfacesDefinitionsRoot = CompletionJob.buildDefinitionsTree(project, false); - /* If the project is null, that means the file is external (not in a project). In this case, + /* If the project is null, that means the file is external (not in a project). In this case, * parse only the file to be able to show hyperlinks for this file. - */ - /* TODO: Provide hyperlinks to other modules referenced by this file */ + */ + /* TODO: Provide hyperlinks to other modules referenced by this file */ else { interfacesDefinitionsRoot = new Def("", Def.Type.Root, 0, 0); OcamlNewInterfaceParser parser = OcamlNewInterfaceParser.getInstance(); - + File file = editor.getPathOfFileBeingEdited().toFile(); Def def = parser.parseFile(file, false); if (def != null) @@ -82,7 +82,7 @@ public IHyperlink makeHyperlink (final ITextViewer textViewer, int offset) { else return null; } - + long time = System.currentTimeMillis(); @@ -104,11 +104,11 @@ public IHyperlink makeHyperlink (final ITextViewer textViewer, int offset) { if (searchedDef.type == Def.Type.Open || searchedDef.type == Def.Type.Include) { return makeOpenHyperlink(textViewer, searchedDef, interfacesDefinitionsRoot); } - + if (searchedDef.type == Def.Type.Identifier) - return makeDefinitionHyperlink(textViewer, searchedDef, + return makeDefinitionHyperlink(textViewer, searchedDef, modulesDefinitionsRoot, interfacesDefinitionsRoot); - + return null; } @@ -132,7 +132,7 @@ public IHyperlink makeHyperlink (final ITextViewer textViewer, int offset) { modulesDefinitionsRoot, interfacesDefinitionsRoot); } } - + private IHyperlink makeDefinitionHyperlink(final ITextViewer textViewer, final Def def, final Def moudulesRoot, final Def interfacesRoot) { IHyperlink hyperlink = new IHyperlink() { @@ -210,7 +210,7 @@ private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitions Def firstPart = lookForDefinitionUp(null, parts[0], searchedDef, interfacesDefinitionsRoot, fullDefName, true); // since fullDefName is updated, we need to updata parts variable parts = fullDefName.toString().split("\\."); - // don't find it in the current module, look in the other ones + // don't find it in the current module, look in the other ones if (firstPart == null) { if (openDefInInterfaces(0, parts, interfacesDefinitionsRoot)) return null; @@ -226,17 +226,17 @@ private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitions Def searchedDef2 = new Def(searchedDef); searchedDef2.name = parts[0]; for (int i = 1; i < parts.length; i++) - searchedDef2.name = "." + searchedDef2.name; + searchedDef2.name = "." + searchedDef2.name; firstPart = lookForDefinitionUp(null, parts[0], searchedDef2, interfacesDefinitionsRoot, fullDefName, true); - } else + } else break; } // if the original definition of firstPart is not in current module, look in the other ones if (firstPart == null) { if (openDefInInterfaces(0, parts, interfacesDefinitionsRoot)) return null; - - } + + } // look for the whole parts in current module. else { Def defFromPath = findDefFromPath(1, parts, firstPart, null); @@ -275,7 +275,7 @@ private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitions * Find the definition of searchedDef in modulesDefinitionsRoot, * and in interfacesDefinitionsRoot */ - private Def findDefinitionOf(final String strDef, + private Def findDefinitionOf(final String strDef, final Def modulesDefinitionsRoot, final Def interfacesDefinitionsRoot) { /* @@ -305,9 +305,9 @@ private Def findDefinitionOf(final String strDef, if (stop) break; } - + /* - * lookup in opened module + * lookup in opened module */ for (Def d : modulesDefinitionsRoot.children) { if (d.type == Def.Type.Open) { @@ -344,11 +344,11 @@ private Def findDefinitionOf(final String strDef, for (int i = 1; i < path.length; i++) newFullDefName = newFullDefName + "." + path[i]; String[] aliasedPath = newFullDefName.split("\\."); - + if (openDefInInterfaces(0, aliasedPath, interfacesDefinitionsRoot)) return null; } - + /* * finally, look in Pervasives (which is always opened by default) */ @@ -356,7 +356,7 @@ private Def findDefinitionOf(final String strDef, openDefInInterfaces(0, pervasivesPath, interfacesDefinitionsRoot); return null; } - + /** Find the definition whose complete path is given, starting at index */ private Def findDefFromPath(int index, String[] path, Def def, Def lastPartFound) { if (index == path.length) @@ -383,7 +383,7 @@ private Def findDefFromPath(int index, String[] path, Def def, Def lastPartFound /** * Look for a definition in the node node, its previous siblings, its associated * nodes ("and"), and recurse on its parent - * + * * @param searchedNode * the node we are looking for * @param name @@ -422,6 +422,26 @@ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, return null; } + // if it is an ModuleAlias, find the real module with new name + if (node.type == Def.Type.ModuleAlias) { + if (node.children.size() > 0) { + Def def = node.children.get(0); + String newName = def.name; + // rectify full path in case of there exist aliased module + if (fullDefName.length() >= name.length()) { + String str = fullDefName.substring(0, name.length()); + if (str.compareTo(name) == 0) { + fullDefName.delete(0, name.length()); + fullDefName.insert(0, newName); + } + } + return null; + +// return lookForDefinitionUp(searchedNode, newName, node, interfacesDefinitionsRoot, +// fullDefName, false); + } + } + /* if we are at root, we cannot go further up in this module. */ if (node.type == Def.Type.Root) { // find possible alias module @@ -476,8 +496,8 @@ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, // if it is an "open" node, look inside the interface of this module if (before.type == Def.Type.Open || before.type == Def.Type.Include) { - String newFullDefName = before.name + "." + fullDefName.toString(); - String[] path = newFullDefName.split("\\."); + String newFullDefName = before.name + "." + fullDefName.toString(); + String[] path = newFullDefName.split("\\."); if (openDefInInterfaces(0, path, interfacesDefinitionsRoot)) return null; @@ -512,9 +532,9 @@ private boolean openDefInInterfaces(int index, final String[] path, Def interfac .getActivePage(); if (page != null) { - + File file = new File(filename); - + final IFileStore fileStore; try { URI uri = file.toURI(); @@ -525,7 +545,7 @@ private boolean openDefInInterfaces(int index, final String[] path, Def interfac } IEditorPart part = IDE.openEditorOnFileStore(page, fileStore); - + if (part instanceof OcamlEditor) { final OcamlEditor editor = (OcamlEditor) part; @@ -559,7 +579,7 @@ private boolean openDefInInterfaces(int index, final String[] path, Def interfac /** * Is node the definition of name? If true, returns the node (or * the constructor in a type). If false, returns null. - * + * * @param bIn * whether to accept "let in" (or parameter) nodes * @param otherBranch @@ -671,7 +691,7 @@ private Def findIdentAt(Def def, int offset, IDocument doc) { return null; } - + /** Find a smallest def at a position in the document */ private TextSelection findIdentAt(IDocument doc, int offset) { int docLen = doc.getLength(); @@ -690,7 +710,7 @@ private TextSelection findIdentAt(IDocument doc, int offset) { break; } } - + i = offset - 1; while (i >= 0) { char ch; @@ -706,8 +726,8 @@ private TextSelection findIdentAt(IDocument doc, int offset) { } } int beginOffset = (i >= 0) ? i + 1 : 0; - - + + String[] parts = text.split("\\."); String hoveredText = parts[parts.length - 1]; i = parts.length - 2; @@ -720,10 +740,10 @@ private TextSelection findIdentAt(IDocument doc, int offset) { i--; } beginOffset = beginOffset + (text.length() - hoveredText.length()); - + return new TextSelection(doc, beginOffset, hoveredText.length()); } - + /** diff --git a/Ocaml/src/ocaml/parser/OcamlParser.g b/Ocaml/src/ocaml/parser/OcamlParser.g index 67ca9a0..be43d7e 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.g +++ b/Ocaml/src/ocaml/parser/OcamlParser.g @@ -1238,7 +1238,7 @@ expr= :} | LET MODULE UIDENT.id module_binding.a IN seq_expr.b {: - Def def = new Def((String)id.value, Def.Type.Module, id.getStart(), id.getEnd()); + Def def = new Def((String)id.value, Def.Type.ModuleAlias, id.getStart(), id.getEnd()); def.add(a); def.add(b); def.collapse(); @@ -1540,7 +1540,7 @@ let_binding= pat.findIdents(idents); Def root = new Def(); - + // update root position int identsSize = idents.size(); if (identsSize > 1) @@ -1563,7 +1563,7 @@ let_binding= last.add(b); last.collapse(); backupDef(root); - + return root; } diff --git a/Ocaml/src/ocaml/parser/OcamlParser.java b/Ocaml/src/ocaml/parser/OcamlParser.java index 30d1323..d846917 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.java +++ b/Ocaml/src/ocaml/parser/OcamlParser.java @@ -2445,7 +2445,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 4]; final Symbol b = _symbols[offset + 6]; - Def def = new Def((String)id.value, Def.Type.Module, id.getStart(), id.getEnd()); + Def def = new Def((String)id.value, Def.Type.ModuleAlias, id.getStart(), id.getEnd()); def.add(a); def.add(b); def.collapse(); @@ -3164,7 +3164,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { pat.findIdents(idents); Def root = new Def(); - + // update root position int identsSize = idents.size(); if (identsSize > 1) @@ -3187,7 +3187,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { last.add(b); last.collapse(); backupDef(root); - + return root; } From 03ce5e6d2c43683ca476b3970d33f4e1c2ad315d Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 24 Nov 2014 17:48:55 +0800 Subject: [PATCH 105/127] improve search defns of locally aliased modules --- .../ocaml/editors/OcamlHyperlinkDetector.java | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index 5d36ad6..7899ba0 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -422,23 +422,20 @@ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, return null; } - // if it is an ModuleAlias, find the real module with new name + // if it is an ModuleAlias, then using the aliased module to find def if (node.type == Def.Type.ModuleAlias) { if (node.children.size() > 0) { Def def = node.children.get(0); - String newName = def.name; // rectify full path in case of there exist aliased module - if (fullDefName.length() >= name.length()) { - String str = fullDefName.substring(0, name.length()); - if (str.compareTo(name) == 0) { - fullDefName.delete(0, name.length()); - fullDefName.insert(0, newName); + String aliasModule = node.name + "."; + String newModule = def.name + "."; + if (fullDefName.length() >= aliasModule.length()) { + String str = fullDefName.substring(0, aliasModule.length()); + if (str.compareTo(aliasModule) == 0) { + fullDefName.delete(0, aliasModule.length()); + fullDefName.insert(0, newModule); } } - return null; - -// return lookForDefinitionUp(searchedNode, newName, node, interfacesDefinitionsRoot, -// fullDefName, false); } } From 954de548c79dd9b420fc71b72c213d6995fd9727 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 24 Nov 2014 22:07:02 +0800 Subject: [PATCH 106/127] search for auto-completion in locally aliased modules --- .../completion/OcamlCompletionProcessor.java | 99 ++++++++++++------- 1 file changed, 65 insertions(+), 34 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 307f46a..7c1e0db 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -320,44 +320,25 @@ private ArrayList processDottedCompletion(String comple * name is or aliased by 'prefix' */ else { - // look for prefix in sub-module or aliased module of current modules - String realPrefix = prefix; - boolean stop = false; - while (!stop) { - stop = true; - if (currentDef == null) - break; - - for (Def def : currentDef.children) { - if (!def.name.equals(realPrefix)) - continue; - - if (def.type == Def.Type.Module) { - // find in sub-modules - proposals.addAll(lookupProposalsCompletionInDef( - suffix, def, interfacesDefsRoot, document, - offset, length)); - } - else if (def.type == Def.Type.ModuleAlias) { - if (def.children.size() > 0) { - String aliasedName = def.children.get(0).name; - if (realPrefix.equals(aliasedName)) - stop = true; - else { - realPrefix = aliasedName; - stop = false; - } - break; - } - } - } + // bottom-up search to look for prefix in sub-module + // or aliased module of current modules + final Def nearestDef = findSmallestDefAtOffset(currentDef, offset, document); + String newPrefix = bottomUpFindAliasedModule(prefix, "", nearestDef); + String newSuffix = suffix; + + // compute prefix, suffix + if (newPrefix.contains(".")) { + index = newPrefix.indexOf('.'); + newSuffix = newPrefix.substring(index+1); + newSuffix = combineModuleNameParts(newSuffix, suffix); + newPrefix = newPrefix.substring(0,index); } // find in other modules for (Def def: interfacesDefsRoot.children) { - if (def.name.equals(realPrefix)) + if (def.name.equals(newPrefix)) proposals.addAll(lookupProposalsCompletionInDef( - suffix, def, interfacesDefsRoot, document, + newSuffix, def, interfacesDefsRoot, document, offset, length)); } } @@ -411,10 +392,11 @@ private ArrayList processNondottedCompletion(String com } if (currentDef != null) { - // look down from top of current module + // search defns from current def to its parents (bottom-up search) final Def nearestDef = findSmallestDefAtOffset(currentDef, offset, document); proposals.addAll(bottomUpFindProposals(completion, nearestDef, offset)); + // looking in children of current module for (Def def: currentDef.children) { if (checkCompletion(def, completion)) { Def proposedDef = createProposalDef(project, def); @@ -598,6 +580,55 @@ private ArrayList bottomUpFindProposals(String completi return proposals; } + private String combineModuleNameParts(String prefix, String suffix) { + if (suffix.isEmpty()) + return prefix; + else + return prefix + "." + suffix; + } + + private String bottomUpFindAliasedModule(String prefixAlias, String suffixAlias, Def node) { + if (node == null) + return combineModuleNameParts(prefixAlias, suffixAlias); + + Def travelNode = node.parent; + String newPrefixAlias = prefixAlias; + while (true) { + if (travelNode == null || travelNode.name == null) + break; + + if (travelNode.type == Def.Type.ModuleAlias + && (travelNode.name.compareTo(newPrefixAlias) == 0)) { + if (travelNode.children.size() > 0) { + newPrefixAlias = travelNode.children.get(0).name; + if (newPrefixAlias.contains(".")) // stop when name has "." + break; + } + } + + if (travelNode.type == Def.Type.Root) + break; + + travelNode = travelNode.parent; + } + // if aliased module is a sub-module (containing "."), then find + // the first part. Otherwise, continue to search aliased module + if (newPrefixAlias.contains(".")) { + String[] parts = newPrefixAlias.split("\\."); + String newSuffixAlias = ""; + for (int i = parts.length-1; i > 0; i--) + newSuffixAlias = parts[i] + "." + newSuffixAlias ; + if (newSuffixAlias.length() > 0) { + newSuffixAlias = newSuffixAlias + suffixAlias; + } else + newSuffixAlias = suffixAlias; + newPrefixAlias = parts[0]; + return bottomUpFindAliasedModule(newPrefixAlias, newSuffixAlias, travelNode); + } + else + return combineModuleNameParts(newPrefixAlias, suffixAlias); + } + private ArrayList removeDuplicatedCompletionProposal(ArrayList proposals) { ArrayList newProposals = new ArrayList(); From 801d0b6e507fdbcb195d9a52a1aafc20052cb5f2 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 25 Nov 2014 13:40:39 +0800 Subject: [PATCH 107/127] improve auto-completion --- .../completion/OcamlCompletionProcessor.java | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 7c1e0db..60480dc 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -591,26 +591,43 @@ private String bottomUpFindAliasedModule(String prefixAlias, String suffixAlias, if (node == null) return combineModuleNameParts(prefixAlias, suffixAlias); - Def travelNode = node.parent; + // search for parent from current def until meeting root + Def currentNode = node.parent; String newPrefixAlias = prefixAlias; while (true) { - if (travelNode == null || travelNode.name == null) + if (currentNode == null || currentNode.name == null) break; - if (travelNode.type == Def.Type.ModuleAlias - && (travelNode.name.compareTo(newPrefixAlias) == 0)) { - if (travelNode.children.size() > 0) { - newPrefixAlias = travelNode.children.get(0).name; + if (currentNode.type == Def.Type.ModuleAlias + && (currentNode.name.compareTo(newPrefixAlias) == 0)) { + if (currentNode.children.size() > 0) { + newPrefixAlias = currentNode.children.get(0).name; if (newPrefixAlias.contains(".")) // stop when name has "." break; } } - if (travelNode.type == Def.Type.Root) + if (currentNode.type == Def.Type.Root) break; - travelNode = travelNode.parent; + if (currentNode.parent == null) + break; + + ArrayList currentSiblings = currentNode.parent.children; + int currentIndex = -1; + for (int i = 0; i < currentSiblings.size(); i++) + if (currentSiblings.get(i).equals(currentNode)) { + currentIndex = i; + break; + } + // if current node has a prior sibling, go to that node + if (currentIndex > 0) + currentNode = currentSiblings.get(currentIndex-1); + // otherwise, go to its parent + else + currentNode = currentNode.parent; } + // if aliased module is a sub-module (containing "."), then find // the first part. Otherwise, continue to search aliased module if (newPrefixAlias.contains(".")) { @@ -623,7 +640,7 @@ private String bottomUpFindAliasedModule(String prefixAlias, String suffixAlias, } else newSuffixAlias = suffixAlias; newPrefixAlias = parts[0]; - return bottomUpFindAliasedModule(newPrefixAlias, newSuffixAlias, travelNode); + return bottomUpFindAliasedModule(newPrefixAlias, newSuffixAlias, currentNode); } else return combineModuleNameParts(newPrefixAlias, suffixAlias); From c7ae8fcfc2f2d48396c25ac07c6bc723957e5cd6 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sat, 24 Jan 2015 13:31:23 +0800 Subject: [PATCH 108/127] Improve new-line-and-indent --- .../ocaml/editors/OcamlAutoEditStrategy.java | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java b/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java index b87fe1f..393d0b9 100644 --- a/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java +++ b/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java @@ -292,30 +292,38 @@ else if (trimmed.startsWith("|") && trimmed.equals(beforeCursor)) { else if (OcamlPlugin.getInstance().getPreferenceStore().getBoolean( PreferenceConstants.P_EDITOR_KEEP_INDENT)) { - if (trimmed.isEmpty()) { - // if current line contains only whitespace, then - // then trim it and indent next line by indentation - // of nearest non-whitespace line - try { - int lineNum = document.getLineOfOffset(command.offset); - int priorIndent = 0; - for (int l = lineNum - 1; l >= 0; l--) { - int x = document.getLineOffset(l); - int y = document.getLineOffset(l+1); - String priorLine = document.get(x, y - x + 1); + // if current line contains only whitespace, then + // then trim it and indent next line by indentation + // of nearest non-whitespace line + try { + int lineNum = document.getLineOfOffset(command.offset); + int startLineFindIndent = lineNum - 1; + String firstPartCurrentLine = + document.get(lineRegion.getOffset(), + command.offset - lineRegion.getOffset()); + if (firstPartCurrentLine.trim().isEmpty()) { + startLineFindIndent = lineNum - 1; + command.length = command.offset - lineRegion.getOffset(); + command.offset = lineRegion.getOffset(); + } + else + startLineFindIndent = lineNum; + int priorIndent = 0; + for (int l = startLineFindIndent; l >= 0; l--) { + int x = document.getLineOffset(l); + int y = document.getLineOffset(l+1); + String priorLine = document.get(x, y - x + 1); + // pr + if (!priorLine.trim().isEmpty()) { int i = OcamlFormatter.getLineIndent(priorLine); if (i > 0) { priorIndent = i; break; } } - command.offset = lineRegion.getOffset(); - command.length = lineRegion.getLength(); - command.text = eol + makeIndent(priorIndent); - } catch (BadLocationException e) { } - } else { - command.text = eol + makeIndent(indent); + command.text = eol + makeIndent(priorIndent); + } catch (BadLocationException e) { } } From 540cebc9b6f1ee68314a799ae032f42f2ca5dce3 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sat, 24 Jan 2015 13:46:51 +0800 Subject: [PATCH 109/127] Improve new-line-and-indent --- .../ocaml/editors/OcamlAutoEditStrategy.java | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java b/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java index 393d0b9..76138cf 100644 --- a/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java +++ b/Ocaml/src/ocaml/editors/OcamlAutoEditStrategy.java @@ -301,28 +301,32 @@ else if (OcamlPlugin.getInstance().getPreferenceStore().getBoolean( String firstPartCurrentLine = document.get(lineRegion.getOffset(), command.offset - lineRegion.getOffset()); - if (firstPartCurrentLine.trim().isEmpty()) { - startLineFindIndent = lineNum - 1; - command.length = command.offset - lineRegion.getOffset(); - command.offset = lineRegion.getOffset(); + // if enter is pressed at beginning of line, just start a new line + if (firstPartCurrentLine.isEmpty()) { + command.text = eol; } - else - startLineFindIndent = lineNum; - int priorIndent = 0; - for (int l = startLineFindIndent; l >= 0; l--) { - int x = document.getLineOffset(l); - int y = document.getLineOffset(l+1); - String priorLine = document.get(x, y - x + 1); - // pr - if (!priorLine.trim().isEmpty()) { - int i = OcamlFormatter.getLineIndent(priorLine); - if (i > 0) { - priorIndent = i; + // if enter is pressed at middle or end of line, + // then new-line-and-indent + else { + if (firstPartCurrentLine.trim().isEmpty()) { + startLineFindIndent = lineNum - 1; + command.length = command.offset - lineRegion.getOffset(); + command.offset = lineRegion.getOffset(); + } + else + startLineFindIndent = lineNum; + int priorIndent = 0; + for (int l = startLineFindIndent; l >= 0; l--) { + int x = document.getLineOffset(l); + int y = document.getLineOffset(l+1); + String priorLine = document.get(x, y - x + 1); + if (!priorLine.trim().isEmpty()) { + priorIndent = OcamlFormatter.getLineIndent(priorLine); break; } } + command.text = eol + makeIndent(priorIndent); } - command.text = eol + makeIndent(priorIndent); } catch (BadLocationException e) { } } From 90f0c3e3936153ba577474ca1e6a5cc687bda4e4 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sat, 24 Jan 2015 16:34:08 +0800 Subject: [PATCH 110/127] using outline tree to enhance auto-completion --- .../completion/OcamlCompletionProcessor.java | 78 ++++++++++++++----- 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 60480dc..5900f6d 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -1,6 +1,7 @@ package ocaml.editor.completion; import java.io.File; +import java.lang.reflect.Array; import java.util.ArrayList; import java.util.HashSet; @@ -126,13 +127,18 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int Def interfacesDefinitionsRoot = null; if (project != null) interfacesDefinitionsRoot = CompletionJob.buildDefinitionsTree(project, false); + + Def outlineDefinitionsRoot = null; // definitions of current editting file + if (editor instanceof OcamlEditor) { + outlineDefinitionsRoot = ((OcamlEditor) editor).getOutlineDefinitionsTree(); + } - proposals = findCompletionProposals(completion, interfacesDefinitionsRoot, document, documentOffset); + proposals = findCompletionProposals(completion, interfacesDefinitionsRoot, outlineDefinitionsRoot, document, documentOffset); } else { proposals = new OcamlCompletionProposal[0]; OcamlPlugin.logInfo("Completion proposals skipped (background job not done yet)"); } - + ICompletionProposal[] templateCompletionProposals; OcamlTemplateCompletionProcessor tcp = new OcamlTemplateCompletionProcessor(); @@ -211,6 +217,7 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int */ private OcamlCompletionProposal[] findCompletionProposals(String completion, Def interfacesDefsRoot, + Def outlineDefsRoot, IDocument doc, int offset) { @@ -227,10 +234,10 @@ else if (moduleName.endsWith(".mli")) if (completion.contains(".")) proposals = processDottedCompletion(completion, interfacesDefsRoot, - moduleName, doc, offset, completion.length()); + outlineDefsRoot, moduleName, doc, offset, completion.length()); else proposals = processNondottedCompletion(completion, interfacesDefsRoot, - moduleName, doc, offset, completion.length()); + outlineDefsRoot, moduleName, doc, offset, completion.length()); proposals = removeDuplicatedCompletionProposal(proposals); @@ -240,6 +247,7 @@ else if (moduleName.endsWith(".mli")) // completion string must contained dots private ArrayList processDottedCompletion(String completion, Def interfacesDefsRoot, + Def outlineDefsRoot, String moduleName, IDocument document, int offset, @@ -274,7 +282,10 @@ private ArrayList processDottedCompletion(String comple isLowerCasePrefix = true; Def currentDef = null; - for (Def def: interfacesDefsRoot.children) { + ArrayList searchDefs = interfacesDefsRoot.children; + if (outlineDefsRoot != null) + searchDefs.addAll(outlineDefsRoot.children); + for (Def def: searchDefs) { if (def.name.equals(moduleName)) { currentDef = def; break; @@ -301,13 +312,17 @@ private ArrayList processDottedCompletion(String comple if (def.type == Def.Type.Open || def.type == Def.Type.Include) { String newCompletion = def.name + "." + suffix; proposals.addAll(processDottedCompletion(newCompletion, - interfacesDefsRoot, moduleName, document, + interfacesDefsRoot, outlineDefsRoot, + moduleName, document, offset, suffix.length())); } } // completion maybe modules's name - for (Def def : interfacesDefsRoot.children) { + searchDefs = interfacesDefsRoot.children; + if (outlineDefsRoot != null) + searchDefs.addAll(outlineDefsRoot.children); + for (Def def : searchDefs) { if (checkCompletion(def, suffix) && isCompletionDef(def)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, @@ -335,10 +350,14 @@ private ArrayList processDottedCompletion(String comple } // find in other modules - for (Def def: interfacesDefsRoot.children) { + searchDefs = interfacesDefsRoot.children; + if (outlineDefsRoot != null) + searchDefs.addAll(outlineDefsRoot.children); + for (Def def: searchDefs) { if (def.name.equals(newPrefix)) proposals.addAll(lookupProposalsCompletionInDef( - newSuffix, def, interfacesDefsRoot, document, + newSuffix, def, interfacesDefsRoot, + outlineDefsRoot, document, offset, length)); } } @@ -346,7 +365,10 @@ private ArrayList processDottedCompletion(String comple } // find elements starting by in the list of elements else { - for (Def def : interfacesDefsRoot.children) { + ArrayList searchDefs = interfacesDefsRoot.children; + if (outlineDefsRoot != null) + searchDefs.addAll(outlineDefsRoot.children); + for (Def def : searchDefs) { if (checkCompletion(def, completion) && isCompletionDef(def)) { Def proposedDef = createProposalDef(project, def); proposals.add(new OcamlCompletionProposal(proposedDef, offset, completion.length())); @@ -360,6 +382,7 @@ private ArrayList processDottedCompletion(String comple private ArrayList processNondottedCompletion(String completion, Def interfacesDefsRoot, + Def outlineDefsRoot, String moduleName, IDocument document, int offset, @@ -413,7 +436,8 @@ private ArrayList processNondottedCompletion(String com String newCompletion = def.name + "." + completion; proposals.addAll(processDottedCompletion(newCompletion, - interfacesDefsRoot, moduleName, document, offset, length)); + interfacesDefsRoot, outlineDefsRoot, + moduleName, document, offset, length)); } } @@ -441,6 +465,7 @@ private ArrayList processNondottedCompletion(String com private ArrayList lookupProposalsCompletionInDef(String completion, Def defsRoot, Def interfacesDefRoot, + Def outlineDefRoot, IDocument document, int offset, int length) { @@ -471,7 +496,8 @@ private ArrayList lookupProposalsCompletionInDef(String for (Def def: defsRoot.children) { if (def.name.equals(prefix)) proposals.addAll(lookupProposalsCompletionInDef(suffix, def, - interfacesDefRoot, document, offset, length)); + interfacesDefRoot, outlineDefRoot, + document, offset, length)); } // look inside included module @@ -483,7 +509,8 @@ private ArrayList lookupProposalsCompletionInDef(String if (def2.name.equals(includedDef.name)) { Def includedDefRoot = def2; proposals.addAll(lookupProposalsCompletionInDef( - completion,includedDefRoot, interfacesDefRoot, + completion, includedDefRoot, + interfacesDefRoot, outlineDefRoot, document, offset, length)); } @@ -493,7 +520,8 @@ private ArrayList lookupProposalsCompletionInDef(String if (def2.name.equals(includedDef.name)) { Def includedDefRoot = def2; proposals.addAll(lookupProposalsCompletionInDef( - completion, includedDefRoot, interfacesDefRoot, + completion, includedDefRoot, + interfacesDefRoot, outlineDefRoot, document, offset, length)); } @@ -520,7 +548,8 @@ private ArrayList lookupProposalsCompletionInDef(String if (def2.name.equals(includedDef.name)) { Def includedDefRoot = def2; proposals.addAll(lookupProposalsCompletionInDef( - completion, includedDefRoot, interfacesDefRoot, + completion, includedDefRoot, + interfacesDefRoot, outlineDefRoot, document, offset, length)); } @@ -530,7 +559,8 @@ private ArrayList lookupProposalsCompletionInDef(String if (def2.name.equals(includedDef.name)) { Def includedDefRoot = def2; proposals.addAll(lookupProposalsCompletionInDef( - completion, includedDefRoot, interfacesDefRoot, + completion, includedDefRoot, + interfacesDefRoot, outlineDefRoot, document, offset, length)); } @@ -607,6 +637,15 @@ private String bottomUpFindAliasedModule(String prefixAlias, String suffixAlias, } } + if (currentNode.type == Def.Type.ModuleAlias + && (currentNode.name.compareTo(newPrefixAlias) == 0)) { + if (currentNode.children.size() > 0) { + newPrefixAlias = currentNode.children.get(0).name; + if (newPrefixAlias.contains(".")) // stop when name has "." + break; + } + } + if (currentNode.type == Def.Type.Root) break; @@ -651,17 +690,16 @@ private ArrayList removeDuplicatedCompletionProposal(Ar ArrayList newProposals = new ArrayList(); HashSet proposalHashSet = new HashSet<>(); for (OcamlCompletionProposal p: proposals) { - String s = p.getAdditionalProposalInfo(null); - if (!proposalHashSet.contains(s)) { + String hashStr = p.getDisplayString() + p.getAdditionalProposalInfo(null); + if (!proposalHashSet.contains(hashStr)) { newProposals.add(p); - proposalHashSet.add(s); + proposalHashSet.add(hashStr); } } return newProposals; } - /** Find an identifier (or an open directive) at a position in the document */ private Def findSmallestDefAtOffset(Def def, int offset, IDocument doc) { From 4b093d80513f36fb145ee2b25332be4f549f71e5 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 26 Jan 2015 00:35:53 +0800 Subject: [PATCH 111/127] jump to definition: nested and aliased module is supported --- .../completion/OcamlCompletionProcessor.java | 9 -- .../ocaml/editors/OcamlHyperlinkDetector.java | 108 +++++++++++------- 2 files changed, 67 insertions(+), 50 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 5900f6d..75f21fc 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -637,15 +637,6 @@ private String bottomUpFindAliasedModule(String prefixAlias, String suffixAlias, } } - if (currentNode.type == Def.Type.ModuleAlias - && (currentNode.name.compareTo(newPrefixAlias) == 0)) { - if (currentNode.children.size() > 0) { - newPrefixAlias = currentNode.children.get(0).name; - if (newPrefixAlias.contains(".")) // stop when name has "." - break; - } - } - if (currentNode.type == Def.Type.Root) break; diff --git a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java index 7899ba0..de60514 100644 --- a/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java +++ b/Ocaml/src/ocaml/editors/OcamlHyperlinkDetector.java @@ -8,6 +8,7 @@ import ocaml.OcamlPlugin; import ocaml.editor.completion.CompletionJob; import ocaml.parser.Def; +import ocaml.parser.Def.Type; import ocaml.parsers.OcamlNewInterfaceParser; import ocaml.util.Misc; import ocaml.util.OcamlPaths; @@ -134,7 +135,9 @@ public IHyperlink makeHyperlink (final ITextViewer textViewer, int offset) { } private IHyperlink makeDefinitionHyperlink(final ITextViewer textViewer, - final Def def, final Def moudulesRoot, final Def interfacesRoot) { + final Def def, + final Def moudulesRoot, + final Def interfacesRoot) { IHyperlink hyperlink = new IHyperlink() { public void open() { Def target = findDefinitionOf(def, moudulesRoot, interfacesRoot); @@ -163,7 +166,8 @@ public IRegion getHyperlinkRegion() { private IHyperlink makeDefinitionHyperlink(final ITextViewer textViewer, final String strDef, final int offset, - final Def moudulesRoot, final Def interfacesRoot) { + final Def moudulesRoot, + final Def interfacesRoot) { IHyperlink hyperlink = new IHyperlink() { public void open() { Def target = findDefinitionOf(strDef, moudulesRoot, interfacesRoot); @@ -194,7 +198,8 @@ public IRegion getHyperlinkRegion() { * Find the definition of searchedDef in modulesDefinitionsRoot, * and in interfacesDefinitionsRoot */ - private Def findDefinitionOf(final Def searchedDef, final Def modulesDefinitionsRoot, + private Def findDefinitionOf(final Def searchedDef, + final Def modulesDefinitionsRoot, final Def interfacesDefinitionsRoot) { Def def = null; @@ -401,6 +406,13 @@ private Def findDefFromPath(int index, String[] path, Def def, Def lastPartFound private Def lookForDefinitionUp(Def searchedNode, String name, Def node, Def interfacesDefinitionsRoot, StringBuilder fullDefName, boolean otherBranch) { Def test = null; + + // extract first part and search again + if (name.indexOf('.') > -1) { + String[] parts = name.split("\\."); + return lookForDefinitionUp(searchedNode, parts[0], node, interfacesDefinitionsRoot, + fullDefName, otherBranch); + } if (node.type == Def.Type.In) { /* If this is an 'in' node (in a 'let in'), go directly to the parent */ @@ -425,48 +437,24 @@ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, // if it is an ModuleAlias, then using the aliased module to find def if (node.type == Def.Type.ModuleAlias) { if (node.children.size() > 0) { - Def def = node.children.get(0); - // rectify full path in case of there exist aliased module - String aliasModule = node.name + "."; - String newModule = def.name + "."; - if (fullDefName.length() >= aliasModule.length()) { - String str = fullDefName.substring(0, aliasModule.length()); - if (str.compareTo(aliasModule) == 0) { + String aliasModule = node.name; + String aliasedModule = node.children.get(0).name; + if (fullDefName.length() > aliasModule.length()) { + String str = fullDefName.substring(0, aliasModule.length()+1); + if (str.compareTo(aliasModule+".") == 0) { fullDefName.delete(0, aliasModule.length()); - fullDefName.insert(0, newModule); + fullDefName.insert(0, aliasedModule); } } + return lookForDefinitionUp(searchedNode, aliasedModule, + node, interfacesDefinitionsRoot, + fullDefName, false); } } /* if we are at root, we cannot go further up in this module. */ - if (node.type == Def.Type.Root) { - // find possible alias module - boolean stop = false; - String moduleName = name; - while (!stop) { - stop = true; - for (Def def : node.children) { - if (def.name.equals(name) && (def.type == Def.Type.ModuleAlias)) { - String aliasedName = def.children.get(0).name; - if (moduleName.equals(aliasedName)) - stop = true; - else { - moduleName = aliasedName; - stop = false; - } - break; - } - } - } - // rectify full path in case of there exist aliased module - if (!moduleName.equals(name)) { - fullDefName.delete(0, name.length()); - fullDefName.insert(0, moduleName); - } - + if (node.type == Def.Type.Root) return null; - } // look in the associated "and" nodes after it for (int i = node.getSiblingsOffset() + 1; i < node.parent.children.size(); i++) { @@ -475,8 +463,26 @@ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, break; test = isDef(searchedNode, name, after, true, false); - if (test != null) - return test; + if (test != null) { + if (test.type == Type.ModuleAlias) { + if (test.children.size() > 0) { + String aliasModule = test.name; + String aliasedModule = test.children.get(0).name; + if (fullDefName.length() > aliasModule.length()) { + String str = fullDefName.substring(0, aliasModule.length()+1); + if (str.compareTo(aliasModule+".") == 0) { + fullDefName.delete(0, aliasModule.length()); + fullDefName.insert(0, aliasedModule); + } + } + return lookForDefinitionUp(searchedNode, aliasedModule, + node, interfacesDefinitionsRoot, + fullDefName, false); + } + } + else + return test; + } } /* look in the associated "and" nodes that precede it and also in the other (not "and") */ @@ -501,8 +507,26 @@ private Def lookForDefinitionUp(Def searchedNode, String name, Def node, } test = isDef(searchedNode, name, before, bAnd, !bAnd); - if (test != null) - return test; + if (test != null) { + if (test.type == Type.ModuleAlias) { + if (test.children.size() > 0) { + String aliasModule = test.name; + String aliasedModule = test.children.get(0).name; + if (fullDefName.length() > aliasModule.length()) { + String str = fullDefName.substring(0, aliasModule.length()+1); + if (str.compareTo(aliasModule+".") == 0) { + fullDefName.delete(0, aliasModule.length()); + fullDefName.insert(0, aliasedModule); + } + } + return lookForDefinitionUp(searchedNode, aliasedModule, + node, interfacesDefinitionsRoot, + fullDefName, false); + } + } + else + return test; + } } /* Now, go one step up */ @@ -634,6 +658,8 @@ else if (!searchedNode.bInIn) { return node; case ModuleType: return node; + case ModuleAlias: + return node; case External: return node; case Class: From 7b18f7addd494231fa96e5b5ba9c1a1b9cf2abd2 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 26 Jan 2015 17:47:46 +0800 Subject: [PATCH 112/127] use both ml & mli files (even for the same module) to find completion proposals --- .../ocaml/editor/completion/CompletionJob.java | 7 ++++++- .../completion/OcamlCompletionProcessor.java | 15 +++++++++------ Ocaml/src/ocaml/editors/OcamlEditor.java | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/CompletionJob.java b/Ocaml/src/ocaml/editor/completion/CompletionJob.java index 0ccbbfa..1be467f 100644 --- a/Ocaml/src/ocaml/editor/completion/CompletionJob.java +++ b/Ocaml/src/ocaml/editor/completion/CompletionJob.java @@ -146,11 +146,16 @@ public static Def buildDefinitionsTree(IProject project, boolean bUsingEditor) { // get all the ml and mli files from the directory String[] mlmliFiles = dir.list(mlmliFilter); + /* * keep all the mli files, and discard the ml files when there is a mli file with * the same name */ - String[] files = Misc.filterInterfaces(mlmliFiles); + // String[] files = Misc.filterInterfaces(mlmliFiles); + + // Trung: use both ml & mli files + String[] files = mlmliFiles; + // for each file for (String mlmlifile : files) { diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 75f21fc..972a891 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -223,6 +223,7 @@ private OcamlCompletionProposal[] findCompletionProposals(String completion, ArrayList proposals; + String fileName = editor.getEditorInput().getName(); String moduleName = editor.getEditorInput().getName(); if (moduleName.endsWith(".ml")) moduleName = moduleName.substring(0, moduleName.length() - 3); @@ -234,10 +235,10 @@ else if (moduleName.endsWith(".mli")) if (completion.contains(".")) proposals = processDottedCompletion(completion, interfacesDefsRoot, - outlineDefsRoot, moduleName, doc, offset, completion.length()); + outlineDefsRoot, moduleName, fileName, doc, offset, completion.length()); else proposals = processNondottedCompletion(completion, interfacesDefsRoot, - outlineDefsRoot, moduleName, doc, offset, completion.length()); + outlineDefsRoot, moduleName, fileName, doc, offset, completion.length()); proposals = removeDuplicatedCompletionProposal(proposals); @@ -249,6 +250,7 @@ private ArrayList processDottedCompletion(String comple Def interfacesDefsRoot, Def outlineDefsRoot, String moduleName, + String fileName, IDocument document, int offset, int length) { @@ -286,7 +288,7 @@ private ArrayList processDottedCompletion(String comple if (outlineDefsRoot != null) searchDefs.addAll(outlineDefsRoot.children); for (Def def: searchDefs) { - if (def.name.equals(moduleName)) { + if (def.name.equals(moduleName) && def.getFileName().endsWith(fileName)) { currentDef = def; break; } @@ -313,7 +315,7 @@ private ArrayList processDottedCompletion(String comple String newCompletion = def.name + "." + suffix; proposals.addAll(processDottedCompletion(newCompletion, interfacesDefsRoot, outlineDefsRoot, - moduleName, document, + moduleName, fileName, document, offset, suffix.length())); } } @@ -384,6 +386,7 @@ private ArrayList processNondottedCompletion(String com Def interfacesDefsRoot, Def outlineDefsRoot, String moduleName, + String fileName, IDocument document, int offset, int length) { @@ -408,7 +411,7 @@ private ArrayList processNondottedCompletion(String com */ Def currentDef = null; for (Def def: interfacesDefsRoot.children) { - if (def.name.equals(moduleName)) { + if (def.name.equals(moduleName) && def.getFileName().endsWith(fileName)) { currentDef = def; break; } @@ -437,7 +440,7 @@ private ArrayList processNondottedCompletion(String com String newCompletion = def.name + "." + completion; proposals.addAll(processDottedCompletion(newCompletion, interfacesDefsRoot, outlineDefsRoot, - moduleName, document, offset, length)); + moduleName, fileName, document, offset, length)); } } diff --git a/Ocaml/src/ocaml/editors/OcamlEditor.java b/Ocaml/src/ocaml/editors/OcamlEditor.java index daf1801..13937ef 100644 --- a/Ocaml/src/ocaml/editors/OcamlEditor.java +++ b/Ocaml/src/ocaml/editors/OcamlEditor.java @@ -524,7 +524,7 @@ public void rebuildOutline(int delay, boolean syncWithEditor) { else outlineJob.cancel(); - outlineJob.setPriority(CompletionJob.DECORATE); + outlineJob.setPriority(CompletionJob.SHORT); outlineJob.setOutline(this.outline); outlineJob.setDoc(document); outlineJob.setEditor(this); From 360e0f5a1658cc62e7e304d9cbdc06eb69ae7065 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 26 Jan 2015 23:13:24 +0800 Subject: [PATCH 113/127] improve completion proposals --- .../src/ocaml/editor/completion/OcamlCompletionProcessor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java index 972a891..dbbd5c6 100644 --- a/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java +++ b/Ocaml/src/ocaml/editor/completion/OcamlCompletionProcessor.java @@ -624,8 +624,8 @@ private String bottomUpFindAliasedModule(String prefixAlias, String suffixAlias, if (node == null) return combineModuleNameParts(prefixAlias, suffixAlias); - // search for parent from current def until meeting root - Def currentNode = node.parent; + // search for aliasedModuel from current def, and go upper until meeting root + Def currentNode = node; String newPrefixAlias = prefixAlias; while (true) { if (currentNode == null || currentNode.name == null) From 6d379687c9ab4914d8dd9435a4ec20f4c9eb92b3 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 27 Jan 2015 16:09:28 +0800 Subject: [PATCH 114/127] disable log --- .../editor/actions/MarkOccurrencesAction.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/MarkOccurrencesAction.java b/Ocaml/src/ocaml/editor/actions/MarkOccurrencesAction.java index 36c5d44..5fefa8d 100644 --- a/Ocaml/src/ocaml/editor/actions/MarkOccurrencesAction.java +++ b/Ocaml/src/ocaml/editor/actions/MarkOccurrencesAction.java @@ -60,15 +60,17 @@ public void run(IAction action) { } } } catch (Exception e) { - OcamlPlugin.logError(e); +// OcamlPlugin.logError(e); } - } else - OcamlPlugin.logError(MarkOccurrencesAction.class.getSimpleName() + ": only works on ml and mli files"); - - } else - OcamlPlugin.logError(MarkOccurrencesAction.class.getSimpleName() + ": editorPart is null"); - } else - OcamlPlugin.logError(MarkOccurrencesAction.class.getSimpleName() + ": page is null"); + } +// else +// OcamlPlugin.logError(MarkOccurrencesAction.class.getSimpleName() + ": only works on ml and mli files"); + } +// else +// OcamlPlugin.logError(MarkOccurrencesAction.class.getSimpleName() + ": editorPart is null"); + } +// else +// OcamlPlugin.logError(MarkOccurrencesAction.class.getSimpleName() + ": page is null"); } public void dispose() { From 40b659c75306e3fdc756e5ce4e0ba15cf196d83d Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 27 Jan 2015 23:02:19 +0800 Subject: [PATCH 115/127] provide hyperlink presenter for OcamlEditor --- .../editors/OcamlSourceViewerConfig.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java index 0331149..0abecfd 100644 --- a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java +++ b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java @@ -13,6 +13,10 @@ import ocaml.preferences.PreferenceConstants; import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.JFacePreferences; +import org.eclipse.jface.resource.ColorRegistry; import org.eclipse.jface.text.IAutoEditStrategy; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextDoubleClickStrategy; @@ -26,7 +30,9 @@ import org.eclipse.jface.text.contentassist.IContentAssistant; import org.eclipse.jface.text.formatter.IContentFormatter; import org.eclipse.jface.text.formatter.MultiPassContentFormatter; +import org.eclipse.jface.text.hyperlink.DefaultHyperlinkPresenter; import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; +import org.eclipse.jface.text.hyperlink.IHyperlinkPresenter; import org.eclipse.jface.text.presentation.IPresentationReconciler; import org.eclipse.jface.text.presentation.PresentationReconciler; import org.eclipse.jface.text.reconciler.IReconciler; @@ -48,9 +54,13 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; import org.eclipse.ui.editors.text.EditorsUI; +import org.eclipse.ui.internal.WorkbenchPlugin; import org.eclipse.ui.texteditor.spelling.SpellingAnnotation; import org.eclipse.ui.texteditor.spelling.SpellingService; +import org.eclipse.ui.themes.ITheme; +import org.eclipse.ui.themes.IThemeManager; /** * Configures the OCaml code editor: auto edit strategies, formatter, partitioning, completion assistant, @@ -212,6 +222,17 @@ public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer) { public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) { return new IHyperlinkDetector[] { new OcamlHyperlinkDetector(this.ocamlEditor) }; } + + @Override + public IHyperlinkPresenter getHyperlinkPresenter(ISourceViewer sourceViewer) { + IThemeManager themeManager = WorkbenchPlugin.getDefault().getWorkbench().getThemeManager(); + ITheme currentTheme = themeManager.getCurrentTheme(); + ColorRegistry colorRegistry = currentTheme.getColorRegistry(); + // use hyperlink color from current preference of Eclipse + Color color = colorRegistry.get(JFacePreferences.HYPERLINK_COLOR); + DefaultHyperlinkPresenter hyperlinkPresenter = new DefaultHyperlinkPresenter(color); + return hyperlinkPresenter; + } @Override public IReconciler getReconciler(final ISourceViewer sourceViewer) { From 96d5abb1c39171db8d379fec61ad73b246ffbd6d Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 4 Feb 2015 12:54:39 +0800 Subject: [PATCH 116/127] disable error log --- Ocaml/src/ocaml/build/makefile/OcamlMakefileBuilder.java | 4 ++-- Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java | 2 +- Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Ocaml/src/ocaml/build/makefile/OcamlMakefileBuilder.java b/Ocaml/src/ocaml/build/makefile/OcamlMakefileBuilder.java index a9de21c..27a570f 100644 --- a/Ocaml/src/ocaml/build/makefile/OcamlMakefileBuilder.java +++ b/Ocaml/src/ocaml/build/makefile/OcamlMakefileBuilder.java @@ -258,8 +258,8 @@ protected IStatus run(IProgressMonitor monitor) { public void run() { try { project.refreshLocal(IProject.DEPTH_INFINITE, null); - } catch (CoreException e1) { - OcamlPlugin.logError("ocaml plugin error", e1); + } catch (Exception e) { +// OcamlPlugin.logError("ocaml plugin error", e); } } }); diff --git a/Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java b/Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java index 1a82fa9..0fc7e14 100644 --- a/Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java +++ b/Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java @@ -67,7 +67,7 @@ public void run(IAction action) { editor.getSelectionProvider().setSelection(sel); } catch (BadLocationException e) { - OcamlPlugin.logError("Wrong offset", e); +// OcamlPlugin.logError("Wrong offset", e); return; } diff --git a/Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java b/Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java index 6471fc3..c24ec52 100644 --- a/Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java +++ b/Ocaml/src/ocaml/typeHovers/OcamlAnnotParser.java @@ -92,8 +92,8 @@ public static TypeAnnotation[] parseFile(File file, IDocument document) try { while ((line = inputStream.readLine()) != null) text.append(line + "\n"); - } catch (IOException e) { - OcamlPlugin.logError("ocaml plugin error", e); + } catch (Exception e) { +// OcamlPlugin.logError("ocaml plugin error", e); return null; } From 4b744e3d04166b2619db9e2c3fec07d44ea03c53 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sun, 8 Feb 2015 23:44:30 +0800 Subject: [PATCH 117/127] improve switch comment --- Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java b/Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java index 0fc7e14..fef7ec7 100644 --- a/Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java +++ b/Ocaml/src/ocaml/editor/actions/CommentSelectionAction.java @@ -39,7 +39,7 @@ public void run(IAction action) { int selEnd = selStart + selection.getLength(); // the last selected character can be a newline - if (selEnd > 1) + if (selEnd - selStart > 1) selEnd--; IEditorInput input = editor.getEditorInput(); @@ -63,7 +63,7 @@ public void run(IAction action) { endLineInfo = document.getLineInformation(endLine); endOffset = endLineInfo.getOffset() + endLineInfo.getLength(); - TextSelection sel = new TextSelection(startOffset, endOffset - startOffset + 1); + TextSelection sel = new TextSelection(startOffset, endOffset - startOffset); editor.getSelectionProvider().setSelection(sel); } catch (BadLocationException e) { From 2351d5be5e85fdde2b560da12bbab237986c3cf7 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 9 Feb 2015 17:02:19 +0800 Subject: [PATCH 118/127] improve outline, support * --- .../src/ocaml/views/outline/QuickOutline.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Ocaml/src/ocaml/views/outline/QuickOutline.java b/Ocaml/src/ocaml/views/outline/QuickOutline.java index ed3a0c9..e460bac 100644 --- a/Ocaml/src/ocaml/views/outline/QuickOutline.java +++ b/Ocaml/src/ocaml/views/outline/QuickOutline.java @@ -357,11 +357,28 @@ private boolean matchesFilter(Object element) { if (filterText.startsWith("^")) return matchName.matches(filterText); // search for substring when filterText start with "*" - else if (filterText.startsWith("*")) - return matchName.contains(filterText.substring(1)); - // otherwise, search for static string - else + // or by converting to regex + if (filterText.startsWith("*")) { + if (filterText.lastIndexOf("*") == 0) + return matchName.contains(filterText.substring(1)); + else { + // convert to regex + String newText = filterText.replaceAll("\\*", ".*"); + newText = "^" + newText + ".*"; + System.out.println(newText); + return matchName.matches(newText); + } + } + // otherwise, search for static string or by converting to reged + if (filterText.lastIndexOf("*") < 0) return matchName.startsWith(filterText); + else { + // convert to regex + String newText = filterText.replaceAll("\\*", ".*"); + newText = "^" + newText + ".*"; + System.out.println(newText); + return matchName.matches(newText); + } } catch (Exception e) { return false; } From 217ed11684901aabe92a71d0bb61328e6b76b1a5 Mon Sep 17 00:00:00 2001 From: trungtq Date: Mon, 9 Feb 2015 17:03:35 +0800 Subject: [PATCH 119/127] minor --- Ocaml/src/ocaml/views/outline/QuickOutline.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Ocaml/src/ocaml/views/outline/QuickOutline.java b/Ocaml/src/ocaml/views/outline/QuickOutline.java index e460bac..1b65c58 100644 --- a/Ocaml/src/ocaml/views/outline/QuickOutline.java +++ b/Ocaml/src/ocaml/views/outline/QuickOutline.java @@ -365,7 +365,6 @@ private boolean matchesFilter(Object element) { // convert to regex String newText = filterText.replaceAll("\\*", ".*"); newText = "^" + newText + ".*"; - System.out.println(newText); return matchName.matches(newText); } } @@ -376,7 +375,6 @@ private boolean matchesFilter(Object element) { // convert to regex String newText = filterText.replaceAll("\\*", ".*"); newText = "^" + newText + ".*"; - System.out.println(newText); return matchName.matches(newText); } } catch (Exception e) { From 943e7f9518df0192d0dd53c5fcaacbd917354206 Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 1 Apr 2015 15:02:38 +0800 Subject: [PATCH 120/127] support cppo syntax --- Ocaml/src/ocaml/parser/OcamlParser.g | 13 + Ocaml/src/ocaml/parser/OcamlParser.java | 2038 ++++++++++++----------- 2 files changed, 1040 insertions(+), 1011 deletions(-) diff --git a/Ocaml/src/ocaml/parser/OcamlParser.g b/Ocaml/src/ocaml/parser/OcamlParser.g index be43d7e..3a51b37 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.g +++ b/Ocaml/src/ocaml/parser/OcamlParser.g @@ -359,6 +359,10 @@ structure_tail= {: return Def.root(a,b); :} | structure_item.a structure_tail.b {: return Def.root(a,b); :} + | SEMISEMI cppo_directive.a structure_tail.b + {: return Def.root(a,b); :} + | cppo_directive.a structure_tail.b + {: return Def.root(a,b); :} | error {: return new Def(); :} ; @@ -2466,6 +2470,15 @@ toplevel_directive= {: return new Def(); :} ; +/* CPPO directives: http://mjambon.com/cppo.html*/ +// This is temporarily. Should support more CPPO's syntax. +cppo_directive= + SHARP ident + {: return new Def(); :} + | SHARP ident STRING + {: return new Def(); :} +; + /* Miscellaneous */ name_tag= diff --git a/Ocaml/src/ocaml/parser/OcamlParser.java b/Ocaml/src/ocaml/parser/OcamlParser.java index d846917..897be36 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.java +++ b/Ocaml/src/ocaml/parser/OcamlParser.java @@ -13,8 +13,8 @@ public class OcamlParser extends Parser { static public class Terminals { static public final short EOF = 0; static public final short LIDENT = 1; - static public final short UIDENT = 2; - static public final short SHARP = 3; + static public final short SHARP = 2; + static public final short UIDENT = 3; static public final short LPAREN = 4; static public final short LET = 5; static public final short END = 6; @@ -27,8 +27,8 @@ static public class Terminals { static public final short EXCEPTION = 13; static public final short CLASS = 14; static public final short INCLUDE = 15; - static public final short EQUAL = 16; - static public final short SEMISEMI = 17; + static public final short SEMISEMI = 16; + static public final short EQUAL = 17; static public final short MINUS = 18; static public final short PLUS = 19; static public final short VAL = 20; @@ -38,11 +38,11 @@ static public class Terminals { static public final short TRUE = 24; static public final short LBRACE = 25; static public final short INT = 26; - static public final short FLOAT = 27; - static public final short INT32 = 28; - static public final short INT64 = 29; - static public final short NATIVEINT = 30; - static public final short STRING = 31; + static public final short STRING = 27; + static public final short FLOAT = 28; + static public final short INT32 = 29; + static public final short INT64 = 30; + static public final short NATIVEINT = 31; static public final short CHAR = 32; static public final short LBRACKETBAR = 33; static public final short BAR = 34; @@ -123,8 +123,8 @@ static public class Terminals { static public final String[] NAMES = { "EOF", "LIDENT", - "UIDENT", "SHARP", + "UIDENT", "LPAREN", "LET", "END", @@ -137,8 +137,8 @@ static public class Terminals { "EXCEPTION", "CLASS", "INCLUDE", - "EQUAL", "SEMISEMI", + "EQUAL", "MINUS", "PLUS", "VAL", @@ -148,11 +148,11 @@ static public class Terminals { "TRUE", "LBRACE", "INT", + "STRING", "FLOAT", "INT32", "INT64", "NATIVEINT", - "STRING", "CHAR", "LBRACKETBAR", "BAR", @@ -238,501 +238,493 @@ static public class AltGoals { } static final ParsingTables PARSING_TABLES = new ParsingTables( - "U9piVGUS54NsVtNt26j614GbRa8HYRBWWYuW1XGHYMPG512H922YWdZeOGvWEi#SSpenufc" + - "pdbdlr3FdVEVfUJfT$#zxLTLTtTCzExF0hllxxxnFLtplrRTUlQgkxkdf4UB4Tdxtna5YFx" + - "#xSnNYyTcltLFT7kxVtExkjjcl$UvkDtVhxAVWsRPnaEZjR#lrH3nEZ0vxubpXRukUJ12eo" + - "VwdSP1SXKFALJQ9QyMWx7$4TKZjXDe3tHT5DS9Zd5a8Lye3SybzrdsUOj7RkTUvpptNUSfv" + - "nddMUSvvtddQVSczF8V$1VUvU9a$n1cBcbMKTaQx3xeJtKVSl$f3ajhpznUnSlTIzpfdB#S" + - "3SP8xoptCFSBvtldPcUSkyzTf72HzVvtGayGducruqYdYBTGrQnmaSEJqu1pnA#esQ1paRE" + - "9lOArBtsVsHGyk4#kYRlt6GM8zV$sm1vczlI4q1juEgDkeSL2cnDyeCWQjq8E71DLjs3X8R" + - "EnlQ8t1Uju5wC4RthcewzOOo1adslZTnC1CSy$FjFN#cn6PBJBzHLVv7zHkqnX8x2SsyxUn" + - "rg9DH0kCmRjYSzGEQWma#efgVv3LWt5Y7vu7xL6xOsCWCL2K#Ziw3pghd8USlpeFYxt5rg9" + - "Sj1ARedQ7na3emRR#3iwZpcFEuyuJpfD13zgYTc1Z8FIWDy81OgWOHdCWwC4Mg1tG60Wzw8" + - "NmMj5V7EoUBYO4FMY7skh6GEX17x$Qkmyzg7PFTuS7FUZWLsSRu2E#BbfY4t5XDkkESeUAx" + - "T6BViuWyOCpJ7o6gj$gdqHLqH83dVxPt$pZd9x#SQ8RvWAFWEUYR71Z8B6Zg46yNlrJPjEY" + - "PQxozz7XLVvLcVN5G8f34hjHdHZCkVNyTUkVOCjYPQxsn#lmQlzgFZDVRPFOW#h4TfnRr$#" + - "HoEsguleXiLVH4Zt466UQtBZ#ILnTj0JEN8Wtg7$oTovMWh5k8DUlV$9tAbQ2F1bolzG$YV" + - "sBbi0voFz5Rbx$92OMBV47iHHns$edzvLY9SJ9mDfMRbR$90uhMc8xzr74RUgVn9nY9J8xY" + - "RCHjwv$oWmfLW9pwtp4hUgVnD55Iz3wsagsg7yI9nGjyG$njcpX$xV#IVonM8dif#9Bn3yt" + - "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" + - "RwIFfp2Dn5NULjxMNZV4sthTlTxUzaXLUmFooLYoDMXb4AMzdP0Rwkti3VCcsZn0oJ5GJeZ" + - "9zmBAVMGlRr$P2#d55ARIIEzmxr3lC6yMTfOplKLewrZlECo0V3AQlCNUYGZ$87kvhRoJ8V" + - "b7xnnlcVVda8D7d5EeNH6Jx#cTvrqeUwAjdaXVH64QUN#2$2NU5TuDtYtUhTxT$j#zUxt7l" + - "IVooGIoJtlF87nLzWJAPxtNl3T5jVTtxxsGWr4gtdzw7yVaUtXVEJCHlYTx8Fo5mZJollV#" + - "v$qc7lUo6IVZEYyuxsJMpMoKsIYVZA7CXfcD4RQMFTnMcJQYEhDvfcEcKwOov62KAdrbfdT" + - "CldjckqmVX3l8xWY7KfX6cPqpksI6PqPczioC1Ot9ZCli9xEPYVba0lflvX24FylkG7ce$4" + - "d#c9cQcUdT6t8mIfN#JVux9hsj$9Vy7k4tEBQLNtEOHj$9R#MlcINoVoBooIkZIV4ftZHPe" + - "BHu8zIDoxhHOS8uyQhUJN4cVNBuQLMtyy9knMsLAnkiwjrCEp6Tst3PDdIOC4wCSXl5cOWo" + - "payexRomMucXL1m6vJQcdPZEhbpMbGuJnebHTbMSYIZZ$8JIpWkxbHXAnM5GTZNjn7HkpML" + - "Rqs52czmsE0Zbreep4MLSXb1It5RdwSuWFcuduesXfFhudS5SdLjnsLPqcD0ceDoAKMwbE1" + - "DHncK89SLjTTv6kLKC9TKdeOpgxC9bNUWmeKr0sOLHTb6SYIZZCeIIuhOwRwFi4aD9zG5Ap" + - "fKcwApaiaewJ6WJK5Oooah5cOWoBaCeAMwhypRAoXXAgWzHKguqGMS5brNGOKARWBA2KLOe" + - "paIKXhTInuIIuhOwRwEiYA6iIBXZBU8u$BUfZ4B$RHFQXEkUj$cwvst5cVJ9aQ7h7ehRwho" + - "54hbMSTaab56DSW0Z7q272Ms2BGUmBGSepaHR6jvA7PCjAMwhyxOj1yHiEI35bZQ6m#L0BX" + - "j8Xmbj0ig1Z7AWuan4QNWhTKmeAMwhypRAWJ6K0rDGHd5KSrar7IPCerIKUMHisR2L$B89v" + - "TjpsVPqc32DKb7caR5bmrRoooQKz#EoVdIOC8rIKUQHiMN3LlBB9fINSrav7IPCerIKUMHi" + - "sR2L$B89vMLSLaQ72TCe5MKU6LisR2M$R49v1oxhG8S9RS8Sxy1pl8FYJ4HfU2jrJ7ESuhO" + - "wRy$n3h4vtY5bZaTnRCbbMz9XmZHAHPb7nfODMyalcr3ElQHGRc72D4f5cKV6bWrRoI#RKB" + - "uJb#r4XmdJA1Lb7XbRDcmblsn2#QvSjYiT9aoZL9HvP6pPi9NyiWdbkt3PBdIOC8rIKUQHi" + - "MN3LlBB9fIh6LLAXmbjmXmlvJbUgZWJKHhUIXtJ7AUuhSxRSxmqDiTBK#Pu54TdBkjCXmbj" + - "0ihEZBApuan4QNWhTKmeAMwhypRApZ6KdLDGHd5quZAIxsH2cu2o4wFif3WJKHhUIXqJIeh" + - "RwhoDibCCPQTSb9cTij$6S7HatevqcD0ceEp8A3igJhGLlY7u4#IwEOS7l9Kw9fGKjzLveC" + - "pixcpDA3l6K7PCiMKKnOi2EoLw2tfcaBlIUSVTqVsdUxVudZYptukLsU#zXxm77RgIJtacJ" + - "t4I2U5iwqpnLdb$PG3tP5cBkr3So$a7l0VGrjtkSFTi$KmUrQyIDucRnItYLd6Rk4$SBnwq" + - "tWyhb1NeBUZG$G5oaRUWC$Q1X1qrZ1q2vasKdSLA8GWxolwL3xi$LipYK8Y18NQsmjvY9c5" + - "77M6V2#n33NRW6PQBtTZU$Gj7buWfQTWBVZC78SnR7wQTUvm$E#Sv5pltKwctgx#ndCFbzA" + - "t$nivqulRUyOvoBa1gXPp3JurC4iS2smTYij94DlNUvxVYpt5NWc#viwrO8dh3R#P0OgL$F" + - "lk3WveKczBtis8KR4f#DJomQJLiEboCD3PL$k3k8#uMYqERkk#dsdI4ZeyKCzYcys7Jqw8s" + - "bUyQRyuC98$mpuszxLau8#cT$gmdZqVeCHoAepUzqv$6sXsQ$Jhxeo9d6ANTLTvJiETRmRF" + - "aD0zG2wagmnad5rUInYFagYXwM7XLvFyAM1#L2YzpO6QMl8oVdxtCxIalGxYIGfkodzEH$P" + - "7IQRtpUYhExEVYK$zyZELens5##fohOdf#5Y7Qfv4qlIEfX9b9pyzUmhWk0QvB4Awaq2Rqu" + - "19UToYTvZEzgTPf8PvqjXCFEHjcQfmg9OjFYRp4FpV4vKp5p1G1haliTJE2w#By14GNCwvQ" + - "U1IN#ZYBLOcpnB$Hlp6Kfv1mESU7ijalirzY17Ne71kqzQVy1Au$CMyjFF9FuNptvgeIyPv" + - "$ldWVDOxE8wJvRclZKVr0V2G#PWzZT5npKNw2Zel4XnIcK$PhnScQlwOZiwqfeJeXChi5kW" + - "RwvtfZBFrcvTv0l1ISmwZcmlm4hWkPjnOU2kqLKfKeIR52$CtmUJt9Og6irnC#jLD6tK5TZ" + - "cE9Rkk2$0Ik2rXxBJmKXhZSmLIImUxA7ucQ5HGQNOpBalL7kWTcjl97MhYevlpy1Axp6LS#" + - "hjaKsjPozwUI3DqBdqto$jwKfr3xboMB$dn877pksXlyh4sUbv#Wupp6LGiFXP5nF4$9sVA" + - "S7kYiWBr2sS2$NBwVuLRhjbRa9t2jOBsryCWLDYfLmXOOGp65Yi#R0rGFMD8F#6DG$a24KC" + - "x$J$C0dSjmNiDUflXp6V2S0Zn$19xPt6C#b#63zTgvn7cDPgXpW$C7vm9tLVPhvnXdgLbLd" + - "GUSHqBDpcMsPkT2vtQIP8qubq4oPtSZtmdFn4YlTCwFeqTThMTY$rIstwbq#ASIUef3odZ#" + - "gJmxLsaqmPdOPtmK#b#Rj4sKzteIUZy1FM7FJ36xY5pBP#RLXjt$MjYVT#EMf$E8SmEE9S1" + - "UxRo7FN74ylJhX6JBg$D8k8l8iVmFKVIvbdU#hjtoyadsu2UTeV99#IJ$hz6JDXaETnLgXu" + - "QMTuRvNz5AJw7$bKdRHEKAlVzLyPQltMj8EpqZpdjFu$FXcUL0inCZx1JQNYCEulCKrHxWz" + - "KpTmwLONe$jQMfidNUmHxZPlrbKGsAuU0zN8#yx$tJUhNLiSLw6n53kuvtYBtoTSOyQS#Tq" + - "itCMjoEyspbVt8YpmcYaiTucxfmr9fOcJCkTpv7SHE1CvuwYAoJ2v0nAd#dkK9$F5hIZ01A" + - "D2Pzx0k##btVy5YPh7So3YSuR2fDtin1gn9nF3APygmyuo8y$Tdfg104csYTgJ1z5xLGqfi" + - "TCzmh3XEk3Bx9VE1zpE2pxHSnEinZJf$3CoDZnrP187BlOo25SpfpluNW$GBHGp4YrajxXu" + - "JCjj1AGtPFzGivLLefx4se$zCgf3xc8p1jnl2hCOSG6aTVVezrAZIbLSHhPjNn#sf$FJrhU" + - "wF2xcJnQmVc9Kjv8PwbyrbyNQy#pM9UUHHgy58T4TOpWKKtqfdl4IfUpdzzDrIeEb5mKS2Q" + - "GfUTHbkjcj7DDDrKktqMy7ckZNy2X9lTChJKzeed#Km2n$jM6O5JL$YFkS2uL5cS2eJxCZM" + - "CyS$mvN3e7HpV5Gtbrg0$dveGM9mcjwM55dEUOBCuZ2ujJNfM6d4c4TI98EyFC2kFjfUITG" + - "Lo#ZxDOvvVmoBwdMWtd9jP6ZSB$goBE8tQELVjCtPk$gbBlcf0pYHIN8aUVaxthZRntNTW2" + - "7nervNY56UJqT0u8smGzf8ZpEWu$b5Ub8MSIAIwJflC5Icx1#U8X$vPGXz6dRA9pjzXpXiu" + - "Nh6ML8a9DCL3R8uXoLHjo9f7YCcdpmGXoZQfrvfXqqETLUWG3LAeKzA0YpdCSGVMWAGqvaq" + - "Xn1Pf2l#8Q#1NAtKyfhGxT$eDHlpAbe0SKSPxZY5yze4hXLm5d4YckK5FWLrm3lmfQuCFur" + - "GEXNtdNXcs2xbV4UHrRVdM$AGqvaqXncRJsgrlXL$VxjuOwZBx0h#vdBijMx5UavJv5x5U8" + - "dPuHMzr7XtyVR1Lm9f7YCcdBLbm3M#bobGziTPyQRMSGHlis9ONH9YttAc8P7LkskjUKXfn" + - "9fBX2JL5vemDhkyxhjVtUnBMTjDoZY6s5MErD7DwpEZsfNDM6d4cak4pQGdMFELIvoOUr2N" + - "EGjDojYFCSH#RWtQOqv4mYnHLgqcEubwfHjPaTJJf0TRV6T5w8IMjQgOZpY0qcvp$EKYfHf" + - "SoxCfqKLwWfQ66bhSEai$$3tkT$pj6Ko$xF9igpbkqLiOoEBQtRczAGCuaKboAxzwecrApp" + - "0$N#1Zbd9NflNQbeJVqLiOoEXRvIeHBndIeDEPD8oIgAeEfl3fJV6EGDglw9g4XBFqMCGSS" + - "MgdxUG5KQSYQHaWqr1RRc6ZcBofqxJDwkbRDordRIKgM8wbLirYivYqh0XLBdav0pYHIN8k" + - "TZ2rMLEIYasFbAfKnjWhUJbhwAE8yuvkrzLIdpzaqdnHLg2bheQ#i8yzp2ZvHAG4LQjbF4U" + - "SGnLDkfKkRTBfqKLwWfQ64xMqUOvnP#LQauBjRIHn7dEGxMgybOh$gOqf0pYHHNg2b0nJLo" + - "PjY2Ei9QEJF7hqXBRqLKh#B0hsPI2RXG2hyAE9D8SIcA#5LlS$YzlKaKUq$wlRE$O5twHTL" + - "aVx69ygobboBMeMDBQozJ6d8caU8ADKNbGyqgdVqlMl#locN$QnFbMKjFHIoZOqjhJrCQSY" + - "QHuWerHUL3pIgT$Hcj$wnosPzjeZnhwQ68PNHiQUrXIaFE959SeQQeVAXPfRC$eVMVL2xxa" + - "qsKPor$KSGoEhQq$iMKXfn9fBX2JL7vKBDAPwRGNaRbSkzhifQx5B6CZYsjTvdIa3E955Ue" + - "AIeVQbRf0DLTYQX8ovsAM4R7bjOxJMd8cKIAAzGKbGyrgtI0wiv4LAJb3aKiesDBwnscDEH" + - "C8iKLQehAXvfDNWoa#wJ#7UR91#kRZO74w#vGoDrrqaNFcQYFkKDDtmtpzyESvffLYYjuar" + - "9Gcqn2tuEh$QaDzr2wnylQmXt6HRLZL#s7dm2xkRUxY$hct7lANUMz5S7#exhdctPlDz1Oq" + - "1CdgfKYiV#OZ3suttUS#cQ0xExTJlTs2$rEHkbpNYWKktD#1FlwjMDNz$kS5tAms$Y9uuRS" + - "RsHGMW3#DEpP3xCVmjewzCkSkpN#uAFgL9n4Z61vU7OF#8tNql$1VkwE8Wry5tXG8Cl#xbr" + - "JcxyRT3aOFiX#u5rA8Me#y4j96psH0vrVa9pthQgZsXJwtFjtfA#6Fp9NwLep#u6wxWmb2v" + - "kh1bqEXe#p7uk178hintxd#5przbPrL9j2dwlx4FHTb#4p$e9HxYbsSOvtL$fTgKPZqPBgF" + - "aIwDvex1GOTHYpQyaVPZr2E42lOHtwdg3ToIyoXuYIAxr03VckroFv8ErGgTnOvImFPWjOP" + - "fp#tqjFW36djhZDaT$TBVaAgN7rxQgypWKWjTZTprHcKiCxm4uNkAdTbV1NWVE7VM#TWjxu" + - "JuU#jaJgXyE#jZTq9kzEpw3Mo0BlhRsaIxSxVCBKCrtVDKIZsGkoUZdtFrSVEz#Dke3LIOG" + - "U2#h7x8Mi0k$AP$lm4MSzwjFkyDOMzJZwpUdO$jU6n5xuNYs5$f15ZVwNnOdVQDsBidHenz" + - "ecD6FlV6ozsT$j6ZFsdnelTwzg8iVTOFUnytIIKvbpiWKWjlt38YtsjxD#z#stimVxzn73$" + - "$ll57hLxWFtaHenzMIF6VceZndvM8yP#JcF1dd2VuFfYxnFKUNtlquZFJRlL7NlstufKEWb" + - "xM9jCnM9dYH3xGRLZpqRkfFwEx3wr4VlCyOLWbszIDONoJVac$wRWJPjK7M5tzhMn2#5$IN" + - "aA$IzDsYPLnxyf#B9sxFm9iPzIEtR$I$awOt#T3lawOt$T9bN7Td$QnkwUwXxa$itTojqM2" + - "4vokpcJdKbErbtY$i52yAl2xlRAY$tw7Epy9f42VilnCcD$cGxvCcD$sIR3uQxAR922NSIm" + - "Hxqm7tOHmnwLh1txKupzAJhaKupzAPiCXxjAntN1ViPQmiwUGA5yMZxDs9#soN00UyHduCt" + - "Vi8z$GuT9swJgsD#$oOizz7VrI##TEJsvLd$$Hl8lC2cKBycN6FjBDgawzlTHCUpydHR2aV" + - "uN9cqJvPtMZFsB5EmZOjZdupYjKBlxNyWN6VkBTCWN6VkBDgawzlTsKUpH5KgbSrSelfUwR" + - "u5sByfddACahzuKoXla3Opz1fjK7VlC3L7iiEirg3sBGlyQ2bKS4jMntQz9nYxFYcANPycp" + - "JAeWVx#EUQ#ZGrx7sA#poN00#tKszcBcgdF8sh0xaF7Js1JAQ#MrZFrQcmm7i5zRP#o7hIN" + - "iFDOKoclaDOpz6fiC1x1VKsViHwubx5Spzglfa5SpzgjjCXp0VdMTiSzTIzZvEGWAvGlo1S" + - "R#Was60#jCZpfZVtyjOR#UiLzFXxoUiLzla#60tQ#lC$QrScu2CgwNppj3vVFoUSR#l4s68" + - "tvkih2Fh1NxTslZt0HaRp3sD#YGRp3sDsmo7F7zUr5s$s4jsVqrnluQ7V8rnlwQJOPZjUp#" + - "tuHdV#ZvZX7cAOyakzVs30gGlShONwL3lafb58TaEEBFe1HgT#OzM25CVWQ5mYIxr$OC2f2" + - "zmjXVeKE#GcKKXsGum3lArbIetPbtSkupAFmyquZmgQO4kzVsp1NzwfMEWUem$FohrxszpS" + - "EdAen#8rcBtUbNhvU8AOhVdPxzq6kP#yoLM10#rPHWzrgUkJ9zDC#0KbdkCw1AWxQxbYpOx" + - "iGx8$UPgpMnpaInqrnDnhuwwunxrDfPPuh0NkTrnfstTjPtpCLVh9RKkwCYRpNIDQj4IGhs" + - "rFi4z5OSndxqMjaJpDACUgugx5u$DLVjDwUugzpgPEpEGGgx#q1ihWPsJxstTCRgxMSKPhd" + - "SidliRK8UFOTpHRg$UwT7iNjdkxSeNk$CMh0dsDqxeqvs3tn6X6y6C7hkANAkHkpkZKh1Vj" + - "bgNQ#ctN#FV8BxxxU5zz#BMMUy$TVAjNPns5#j8$Ob3O$T$NSTiIzTEzSUuFaNvkhPwTXLN" + - "Rg$oxEZsENPHXl5ZFsiX7talx9eruH9s5MTYfCeZjsKvM8tvKQoKEp4wrrfS5hqG$O7bEam" + - "4ViFgfpY90hmdHdbZs0$KzM474GMzZDZsCyqsYWcNkzgWpEaDUCptCeVDN#Ipt1T7f$vOmp" + - "x7uqsYjbdRbnR$Xvy1iQmX#UeYrTlB#Ozr$3hZFEwzTtmKV8PjkqpT22yNiKXgRfYpwk5Or" + - "VjenNpQwGad#6wF3vpRindpZNQA6QxlxqsVKQUamVxERLWFoU6$HoZZMB6$kvQnNv67kndr" + - "8BzZ1ZsCumsYXbxslTyQmRxwNcmdruBzjDZs4ytsYXcx6dtbXfehig$CRg$oPDmKFfwYaDI" + - "TVddgZmfn2w7upY995ZlIN9uxNPt5djJ6D#IPEpgNINEjeHTtXZQNTv8ln6IDzgaE5HfOBs" + - "2rncdTN5spncdHBjp3M6$ryBExnsHzzgaE3XykdZiEItM0Nlksm8CTexDymJm8tcdyYF6Uw" + - "SARO8VtKdOvPq9RxykKIH46CQ9D9euwOEQJidyeMvv18NEjimj$16QIYYKHmHvYrWBnoHhV" + - "#GHh6s4fIV2R$AcB0mrNal6baXhF#VJtMXijEtF2TvufjvODYUNc5F7YUt7v49#a$Vdo6cA" + - "JtCVgMaEXN9QaBU8UJcMqsAZFesr7MdfYV2RF3GVhlWqzrHDHr8e3m$o5Z4lnoGRQVLmrZR" + - "LqXFXDtbedg7uDFTUcgPIA6S4UOkObsCv8zRg3DQsbwKdmc$oq7oaujFSitbSXw5sjZzR7a" + - "bXd9YNOtbahDKZMTjiLP$BR$BGF5tnQUxfccPJAAVx2SIy7ClfiLQdixRfbfu8lyb3yrJ5f" + - "xcdQ9fEePmQv2rYNexbr5YhKrdR54jFXD$aeNcAujFSipHDeL1E2V8MCI$7SagiLQLjbgKd" + - "mc$oq3nPyMdkcPfcKIWd1tcBc9TZaesqEfcrpRJqHFXD7fgFKdoQUuQccHJAeuAyHSpBCSb" + - "6MZsAjSsmz4JuJTwKcT0$GjCC2gsyHSohuwHFN2xaDtbJ5d1FqtG4XLRU8kRLSMAhCRcGt#" + - "HDMS1zkAPf55fvYvXNnucjnkH2VfCtPG7tP4s7KsZbBM9U7IUs6fCB#KtUb0NSXscQJA6Lj" + - "uXvTPpOQamkv3TvKnPmJz9q68LMtYBcrN5Ygp6vaD$aJLd0FK7J90gjl4NCg#F4LcDo8R$9" + - "cxA0#s1D4oYqyXOnhuuJMut9XVmcRye2xecQ3gRGobl4l3fER3Kc5$ARl2aBk0$HD952Asy" + - "Hy#euiTMONCXlygOiu3vKqo4KMdcBwDwIgjMVyDuIlmaWBgVAmbB5OON1CyN#eSuDrfjEFn" + - "7qZvuFYV$KzannxfjEeyyfsszFvVUWdc$U4O9StkUKpLjhdEKnZQjiVTbF$5NE#RMYfBUT3" + - "WpVVChFM8UsUyr#5og$OPNVEkBlGJaEzp1XdCGlgjnwQfjjXyz$bGxIOF6Bg3RLYcvhTr71" + - "8GxG7Xp6Y7brdEXtHZg7t#HD6OvTH1SESO1svp16pAlZnFQCT0w$oPio7Bkga5D8SnWZvjL" + - "nOdj6EeVVv4qPZcDKo2caEOmHy#euiJqZhRXRXln6tkZ0mRiK2lsZ46v8OPmKXtzKQdjQMd" + - "Et3FcDlDNAqPmwcWxGKHp6I76eEB4z8vt3R$9MA$CvDPyEqD4SnaXng3YnFIEjk5k6$4RUQ" + - "eMV0A3GdmUQps6C58UAhLP6AUAwKHPtov3Vo5kjyFlIAVJdWkPn6ATHgjQq8lviMjInaMRI" + - "xSqDIwrMU5NpRY99#Zs7AbUQ$57ULRM$Iyb$r3cG9HxDjJFz1nMLUsEzu7mSlal9VrJkgOX" + - "o9lQcUxDLFUNjsYHINEPZfqtEzuZFznI5APiK7sW1yov0Re49uyIy79D#9HiPzOYSAGjB5G" + - "U5Sdz5Z7N$k2ug2MkJYMh2ksYArvOtiaA$snBShpjBvNwAk7O$I#HwrheVbPhQPEAQeBM8Z" + - "Y1dT8HbSbz5AXsL0UshE6pEE75Dg3MgOryJX#LQspwAL3eg0zf7STYSSUAQK6jKnpuc3ikr" + - "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" + - "aq0MslqdTFefag9GaTN2xVuJeASuV4Ad7miqZE8QpjDTOgDFNOTHBcZxCVynRnCA5LajS6k" + - "e3UuIXxNGC1#vq#G9mPrkmNUwwMEUiZb1jHrmZ0muTBtIP#hb2T2sYP5KUgXjkLYCYEcP3p" + - "vQzqV9uDiDSoyyxALTxst9zIFaOYuPoLh3QwPHuRrmvkiOjeHvVvhIeAqGlpEYD0Ib7bzHw" + - "zaOyXez2LVV0UBakb6eIouL6f6#vwDBxQll4J7jgYvPGfN6UvxMttHRZD1liZes9f7Rkr6Y" + - "Tp1M8I8gEJoFBSBF20ljA6xfYl2#0t$ceoP46tvYjl17Aw9U8rHeHmJ$$WWEX8f$PApF$45" + - "jydYVwuVFlOtW5ZG$Kf5tPYbKq9FFD$W3oSWu8J$P7wtF0a7xo4zcL26YKTPOn7r3YCXSy1" + - "SfOjii2YmV7xqHiT5Biz0LOHTPcxOyjw1xZjHyw4iUlMWVp4VpiOwHyhQm1NaRogwGjzaav" + - "kEWxxHkozZ$IJtAyef87nBk0RPMUuA4cisiAut4it22pEQfshPChMcVMjCnjQPpQarPQar5" + - "QasN#Bv8c3bGIqc2hdtrTolHNsACikw1gX4PPNbfK8BTnqZUVGJUufNOQuFLtWZTtbIDtVY" + - "PFKQv9ScZDYtLCiUdrYnEhJanjMPfQiqVKsikIQsvDhNccTIQr#ewqWMNv7vh4OoqN9G#zd" + - "9HhZVe4bxBfLbJHgfnbOjCYLnKuDYFYAqwvjnT3pslOyc8sFapgLTN55poVwtdQtNCiNwPa" + - "e5SejSlbDjtW6Bh6jQlKRn#KHyEuf8DnIXlbzYwHYjT2ohnZutra$OJQeSbT9mwdghUFnOn" + - "bt3AICx7aR3IUNUbhGpU1zv7AJMVfyfyarhphzIQ7rFR#JcwDib9mTW8JYECqDrMwTsSkji" + - "coglIZDcjcIkOcmAFK#cHyYQRg5JUp24$5Knf2ctIfICuzvTmR92c$SXVRChiZ$0kAjNjtw" + - "N223reId4yoAa7RK91SrNAeVL#6aexhUNzDXaEXD5TUxuSxTh3ajue6HWqqjjVA4J4ytjZT" + - "xTG#zj2OQy18#7vEkUTprxEzVv2nEewTQ4bETAaHNoNDI9sLHBTMUkvBU#pR7#VAedGFOg3" + - "GdaFf#w9q4fJYeFV8uGIcsunfJZudQWeiKWCDAL2lSNKjb7aNd5iHtHGiA9SB0uoTTxbkZP" + - "OLSBxCUQJgJ2fX3hwZQSZNE69Z5X7D8FFb8XrnNfYVM3OK6maDXOjn2QYfTWKg5gBDc8pqL" + - "PiBhR0N6WdseiEc7kTH6THAig0kq9KYYvYAo3fAhOHtSIsehle8NgANXZxFc8xqLTKYNwYl" + - "zXULCDl1eeTn8wYHWmIWyKGiHFyQ6UnYzXLx2Q6YTt57cAus1CZjXSyO6zunsWnJumLPuZn" + - "qE#8cMAMc2tcYAE0To96zcZeFxJHzAGDUZ89FVcdUC$goQ#w9nMDg2VD1Fq29uhD0Ug9E5e" + - "1TVtrP2knDEZ9AK5F#YJsf0IeupqP8wuMuu1X7x6ls4$iBmx033oeqOo3G8z2JxfUtC2UT3" + - "F6eR7quFb6tmCtqWC76Aa7injH3yeYFPY6DOfwCBaHzI1v3COteXuiQ#HZi0vGZXLpOzYE0" + - "xR6qeDviNb0c6aCjcuqFN1Yyu3s6Osh1tEXTQpLxd7YUB58B1OdDA8UtDleUq3xL8MKmiRO" + - "Wrcw1sE1T7oZxC4otGCNI3CDteDBwxWMPSGXEhMkU5XC5O#A2Gs2VsOTHk0Ge1uh3eF$d6d" + - "DWeR1NzTpGKDWVRPeh09jZ0NA2aRvPU8keWzA2UNX3T8dTpNxH8YZAE$bFirgm3ujAxfFJq" + - "53m$ZK6Ot8$$iqOLqhMCiQ4TRYvzRRufq6mZgl4M6zjsYiiyGd3OJrywAnNe0Ljc6mljQ8v" + - "jOLZGXhIT5OwGvems1ThsYifBUnsBNXi3RPTUrWTHeHrXQDQCrgJEjhcwAn$abSt41OPpKY" + - "knQ$VoLC3OErj15XBTwkJTU6XM1TqOYm5d#ERKnOc$OkJJxmUy0wgE3xj6FvUmfgendaar3" + - "Idg7XxjF#lMZxKzZGzczCll9$SRruHRpQQB1#BtveD5WRax#IxiQ2jJ7PjJ7DhIOVA0JhqW" + - "3hAKLzlpiMROm7ogiJKVP1QSFj6#hQfwtGHYPFd$etO9z2dnfRS9$egUysUd$d9AAiQD1n2" + - "ljKKd2VQDSwHVUfsUzwpvhvtS$ziNLujgCXlQHGY$vB$Bl1BLeerf$4pmsEjN6C$kyPvUn6" + - "WRBuvqWQnpT63O6oOu3IQK2K6OI4iYG7fT1FJ$Rdrjh0bj7MIj1Q6QCKq3Sfm7KtMezobeB" + - "J0S$QUVvsAQn7FPYPseDIRgqYfmTN27fZ4lN04sVgPmtp8Pg47X3#AOo$1V3V3Vwv1OqyrL" + - "H1MdthKYREWXTKYdCJHxut#XuV#S$uYSWQtPFyA4l4635PZ6EiZp3M4c0j12NLLg571kK5q" + - "5mfZaj1ULaEofaMoXPvKHAsAnZR660RnvZE57yh22NzLwMn9UssrVF5toIYfBrSlgTBRyoB" + - "SWpyJzdn8SRgi1qp1Q9yAx1b2$5NZJBPbk#AItDGPXXbTO6s70oi3mFhe#0aJ6M82qDvAL2" + - "MCCeA7clrh7OooZCIhX0gWV9XHZctLfGpsOhBOCLJnMcG9Ao5e2JPSFRGc99Vdf$YbpVce2" + - "JDnY#xr3BYM#aHVuAnbWBhFA0hp9Q4CiCecmD3FblIsXP7#HVn7FzkX51cygASomZ7m9xZi" + - "7DehbkQNn3AB6PrQCjlnNT8Lq8ksPOpyzhomRmeQHroz8fFr$CjC6Al5xXUEfOjIy5v5lXx" + - "fgoNKy0VHta4P3sqMRjVXkUNPU9Jzajgkwm8b7FrY5TWVZZWJPxZIIlHJEWsAFElH27AXz3" + - "kJBH3lwqeR2KQmolHKZt7bubJU0JFAHZb4UYX9wuk0EKoj4eMd0cKCtdiI$WtE8NRShpUPv" + - "u9VBJ#BKr4IUt5KRPWb7CBcEC6PJMabdAxPw6aMK4ed#TpZrelwUxLUA2y5jeBHJcJKSufm" + - "2#NeVPKVXV7Cc2aL8PtA8MWF0MoLT16AF#1$er7kWVEGKaeoyHNEIXVO9Gz2zWJBSDgekPC" + - "2$IDKBN6J7Yc89IqZpAsx07f1x4dEYV5beF06qTPXjN40p#XFBEMFL4Pz5#E5cU2BX3NyAW" + - "NPiiIMB1AVCWe7u5q2s0y9#NSapJYOx6hCNwP7sK9j2y3IhBdYpZhN8EoGb5Ipwh0JIY$Hd" + - "eywivFkR8ObB2gpxLcJsqeImAKT4Q$Xjjn2qH9StmuetoELuWUeEILw3ze9uwIsYiC9UasA" + - "6V28wz1Eva2KGu7ZrdLj#PLx7nWJ5xLrqlmowLionO5pV4oFNkM0IMb3WNMmbQY4fxZ9Vf#" + - "DVbbYzJPCmaKHtaBU0kpvUtMYCz4#XhKBeLy8IZf3PPcjz4Cqc#WV#U8AnDHtfumuhDHLkY" + - "8XoWpQ8T6l0kk60kxEgCtePoXpv1BUSHx89#4yfI44LyEIJFY5#L5UG7GB0N76GYxy7bgAQ" + - "#TXQ0iun7VMg#N3yAoLo9EdkEd98puSgmfPd#P7sK9dxTf5qJNrqJD66aXAFT2grLeLztLQ" + - "Y4#GBu4#S9jUNY1A2UpTopbqJi38OtVqW9dprBn4L3#XL5#ZDREu75F6$7X2IYN0kMyWb3I" + - "p7J4#tpSmWYN5cXBDSSTlIVQMbEp59HB4r3#29IN5e3IuNSuNA3ZCbpRgrHXExTvG5d6A8r" + - "S2MPpCaed0UMRmIwu5hzq17X9D#rABjLj5NQ6d8TzcjaJASc$S3#JK59jxcxZii0lv#L5MS" + - "RoQjHBs3DdSweGbAwuFpYF3mB$$NpEIzu5LoICU0dxvL96EJiloWfeRo4wYhlHmb$vdjBz$" + - "9lvGb0#osV8PVhU1Y5SoQjOiYrN9kpL7Q2yXL6khCKlow3$1GvTx8hA1FtZpYO5ddis2Uu2" + - "Ri8vUZF0x4IKzCdzfb00fM2K8YzAzLagX8ny2a79V5KuW38Ycu2IosCekSp30PG8yw2KAPy" + - "cb4qecr0seMn2sOIo2MKJoYQKJIYRK3QXR4BPXB89PUD7oNVrLXEbzMRKBiZHcr4BkGFp6Z" + - "JLtPQES556Js7yLpyhTgUuIqnXJXUQCunnC78fpuen9zSW7YjU9enSrbsKSXnOKlI3HdgQo" + - "3oJrnkbkPOChC1IP8NHOWnIut14tu9EtuZD9UoeOUo8mpTHja0Es15EpekzLCn2M85ZheMT" + - "h42wW1qs9knLm7w8mOxIgSdsPVcNEVopk2GLUu5FwR6UF4$f4VB0EopBmJioi7mpVahFuNk" + - "T6L7DTZfH$47KyDiADGAKdYwQ8wIdzAXiSqPL3bxrtkTJHHlKaj$HFKNo1tgJVXeggkyE9C" + - "glj4sXjJiXC3RL$j0ADhtFikbBQJOLutMiRIecY77Yu2IRAc$cdewFsXHbjThKcZ#7y9nLw" + - "AVoUqBDY4s5xkP0J$wsVeW#yBUoLDlqHAts2A2De4TP32rAQCHQYUdYI36ZLeznqRiCjETx" + - "hdCIhoUgZhHDWmJ6LS#3NXp3On3sKxsndlBjdJ0prPEfUN6HrPa$7wvcZ2lQ7uEh5TQvyI4" + - "kcfc80rpskhccSV5Objjd3JqFr8oBs8jNZDwMlQA#MCEyQnINTRxeft7HammPs2jZuS9yj#" + - "t5etewwULMb2yMY8jNx7pZw8JsuXM5tdHlnh4vsGjvWsikvkTB5gvmvLuIs7iDZsDaXTIua" + - "Ee5B0y4k2Rn2XdYceJIfU9qvbo6uzIrYGkh8OtZOse#0bU5DHyZkFYy15nyxb$3kFHyjAqL" + - "uch5urZAPvQA1F#Y$fnEwFGgJtBrD8wH#JWtDeun$n9BrzvyPFx8kXgE8wCI5gvclCU8hdt" + - "cJDpAeCezEnImFmYzwb3cCxiRqryds0$qGtoo#6E0gZRDZhRuQFLaUVBkHgr#RDFgX7DRhM" + - "VYw0wQzxwvUwH9QcumPxYFYEsz4wqtYT6tJjbNUcRbhfFb1qdh8mxDiNofrbp9U#AjhJsns" + - "a7qJjLS4rfUrhAlvD7DiJnsRWLRNezVZkM3ET4FzZl4clrJIPA#TpQM1u84oRfQldQl8SlJ" + - "C#BaUyRdxPblxNdxKGiHhpdRj23EWtUajP3lQYGOMtvcd$O8BaOW4rv9rJQsN3EQR6hcAsp" + - "QNO#vTIM5aD#wZdWQrSY4AwdGt$JvjmIQrrEbF3Vr5HBlOzCm7QBcEbjighM6T0#ykm$hi3" + - "1PwquUJBpkX9WKejF3gxQy$aa#TwKuJ2C8hzh61vZkYDgfBfYqhe8mwVyHk99d35qVHEp4L" + - "vZ01C#CZXqya#kJdkY8Z1pD6Kv7HuwkXj8GwHqUE6#pl6aCh3HEhuavtWIlxurppcGn9HqH" + - "dtzjH7oUAyX6UQzNjHUhiwGd#ak##f5grqCpWyvFWjinwnAT9PFN9OELsb5O9#AuJlJWsl3" + - "Em165OjNh8Q$h2YkkYnLMUlQb1L#fgHMl9d75CsTq2vNAeww7b94L8ltQEcv1TOS5UKA5V8" + - "0A#S22dAlXCGvd0Pz7R5IMf$6EJbiyj5LULF3$4DNKO8MvJjjgNTujtWfEHaLu4M#jKOIeU" + - "gUXWbKrAdi4CJSBjzL4BNjjC88tHMqLeAxHAyowuZ2nAcWpqLRsfr1RHVqg74ECu5RX70XG" + - "zRP6i7zapjJ4KM4Ko5Q7rMK4uzwkMxtEdfdYrYI$ah4hy3NfLp5RfVZLca1LLxyAPFy$ygj" + - "wiXMrloxIsbP8hoLRMVBHyv0mVbNesXxQYhMfVTnXQnPLmyx1eDK2LeOufcHKDgOrFOA1Nw" + - "ahadiOLUxrt5hng$JzJO1ghepkRoBtAD9HgIiLGeKhbJM4IZpPaAXoHr1$Tn6WYlXLg$pUp" + - "jzTsDxEtrqKlrw9A$Fv5VRplrDlrtNt$7vHrVzw5VMhEAhVXr#9NunVgVLAewgdzQhs4Mn2" + - "rOIg2LN3ef9IlvcY9hZ7Qz$V95HBPG7tq1XLHT1Mx0wrwX67$QXTAGl#Rg1KQwprgGtzlGR" + - "rABh3gAs5qJ4xn##kNoNDtUD#OlrYi0SQ2thYP6rYLtRdUxj5OOSdhMNikJwJwpUvtyWKw9" + - "5viClmk$IIw9cx2EtXdQQSxy8GDzVV2z3UTztODpAdhvQ$tsHXhvR1VGnjhLhjJizMfVkCr" + - "d88OpzixSnL2xkzshGe0BjfepAEdKVqAkp8r9ugzrkychoQZGRpFCswQJx3tswMHBsn49$9" + - "sGicsvs$FvMocEzFjRv3#7kmm#fxdL5sDsSinZujmJfhnExnLU3$Pxl7r$UelzV#dNljTb$" + - "BsAqrailNRJnsrpvJbpMomUskiDV5PtulTgyxzaBFJKtOcx0tOM$2teIz2Vl$TUnIviCUIA" + - "m6ThdMzkyXzgJzUnFs9knDs9kmhpxsDN6VeEdSr8Iz2VkQmbxRhpcazPi26xiiwDSSClzl2" + - "YpiB5ySza5rnMvztp1NpEDV9YuGnuY5ujWO0i9#KjxlobRaOkVSQl#AfdRiA8jWZtbX7knw" + - "VG#mnoIRiAybVvSovk$HC#AQzFVkoTZLVseaOnSzyixLyJ7i4t0SNAZTwpvNruRTY$EPrS6" + - "kq4Cc5Rre1SiJzbOfTY#FsJtokyh6C5VhQlScx4tOcx0t5FRYpasocD#cTa$6ZdDJ7R6lth" + - "cf6BjhZRz3knVWCqrsRx8xxMVeLwzqpDM7kLwbAvZezKzHTkTVlU88iOkh4h3VjdfsrrBc6" + - "T16PFTYiF$#$Brnszr#Ext#nNNEEmmOUwiKx7M#Jn2tUwpN1SnLhe$CLV50qbobvuiJiP#T" + - "F5T3kykqUqkthTv#HcDk5jezvsqliBTuFDtVSVKJjNlqwgUWvr8jn0$KnUwXpyZWpG21dZp" + - "OqzR8qEwf$hvQTa#x$nxJadJ$lS7tm4tO6#hQGwftYLXpDKU7MXjNOwusOKyzhpPXRn3ip3" + - "CtYdrrzi2Mrj$ZElD5xAfbXKozbrhCURK8xFeDN8tPPvgmDs4l5Fjgp5LpFwsPViV5YeHlR" + - "5hbdwlsTmVycnBxtPgr$aP8IlKhI1dxZP25MxqNQ2nZ5vRTcoN$DbEDLFZsxyBN6VM6gE9z" + - "9k1Fj3lNv63dqZM8FQV5Ec3FVLk0mSwnmSxli9JwRG5cniI#RrgHv$ic$PP2cUVTw74xvA2" + - "DlHkTozIxoFZTw9BUk4QwgyHOXDkJzVMz2FM$wgtojsg$zzVIJM$tgwLLBglYq7eZErfThL" + - "xJlOYczWjfNuswQR##HhsfrQPMcrfjFAroMKghnQvDkkscLfjQRMgrgTK6Q9NlBTbN3V7lF" + - "ufiDVpM3grQRxOHruiR9BtXxURQtosHzFPEwvl0tfPDp9jjrBisQcfxnucEHySqXYZfRR$y" + - "Ljv2KFA$B9WtSusEsYu9fLJNSJMr$BVJPMf4mgUsbUqGtwn6H4miT4JW0UG7vcvQpThskwR" + - "srdHxd6fghy7RizQrKgmOQx0zUXh1jCVlyglIBPht7XRSFuEH$$M8xgZLQ0qJS1nS#9lMfR" + - "wV5hD0xArYDaPUrHBML7ghcAulxFtyPLPxEUyqu$b75ZBFy5Nd6p$mqZlD2hnhm2j$x1vUt" + - "FQwBA$jLUznZ8teAR3trltWXDuRs#j$pgdckx4vl#7Hd2kuzuMsEp6VrPF6FArTDUPDxJQr" + - "szJk$o$j9loEq6etUCzjTIswSjwBcTG7lTElhcMdd$kEpU2$SAoUreegOXTjMRClL$yP4rf" + - "MJ02gWzFjAlNPiDPpiDepACisu#kVtE$LoAvcpr2ThqrjYyBQz71bGUVLhHFtAP4sKyQzt6" + - "epV8jfZzfyAA$L2XfttGDbuRnMqrgBcWMrzo2lhZKm2zQsDLRVXmBUrKPljQd#VyvQZQAQx" + - "B7abFf76#pKxFzHOasn$sMEwap$HzuqdHpNMQUKPaUPh9F#cPcz9VBFpCawywChJfCONci$" + - "Mw2VaR58#xVeslee4xxhIzPNo3zYCmVj#lCy$HJUyzVVEvkTlE2TlBcgoFlD0TBbRCzmfqx" + - "lSgTsojJ$I3Ad$LH23$v#l2RQVtxQmTmp6oJEXzvcUbuaZOoPfsD3lRPTLS#i$taZJ6nNxj" + - "aJTREhJ7Yg87T#s$zqA$vdsPNkTVNACserSUtXVyE5yvk$gu##iRS8xM9y3Fi4QJ#NFpdwB" + - "xt5QUToSpwChL3wQPz4xJmhog7TNg6eNCtNNXYzca9dcV86#jVtskT$x5z6a#T$5tv2W$oL" + - "hYtJDAs8z2dVsXbwgBatGPgQc$#Emp4WdwReR$QIPtxy$Wd7D7xLmOmkIvxHc9cn#ppqn8m" + - "C$pEyJFzlsmIi40TRAqIFskuR1KyHHdzpc1T7#ifbSEJeQyBHg744Uq8ZNPRo2$mUyF9AVV" + - "v9dkM3#DnSNiYvr3nB8sNTpwNn#tHYgJX9vqx9iSRsjTnvexbwTVuv7h5TZpoudYvkBCJOG" + - "bQOa5lgUuJYDzDxnudQCx2Aq5XRQ3ktIjY1ZxLwfSxWiJkyKePt6PcRRBMzXJRnVyLaulro" + - "bgSxmwNmWVBQ#mmkwdFXus8isOFjFZQl9Gy5L#n#CVsRR6W9WnaewDoO$nkpiT4U9#uZgCV" + - "XTK81MYDz6nz3Em7y1ylOKoJ5Qar3gtsXkgvQpVahq3f1qlt$EcCjP4yTVDTCMclrATDgpa" + - "etrsgLrXNzZQgCVmTS3hbWhHDdSQldidwraxymHV#WXETakuVQ#PguUTnRhDbez3TBrm$Tr" + - "gwJjRFzxT6rzxICNUqwUndzgVOX$UDZ#BLsAMj$chmG$RPzObRFgrzVomVNG1fTQIGtA7X6" + - "theVnrONt6hm$f$4ULuUwtdq6NbrFowy5Wdj8h3QJAxBywEnSqbv8geUSQykRgMiTVtjaU#" + - "jGZ6BaBOU8NQizHvGhvDs1egWIhfMuNE5VIMK3uMPaT7p8DRwUaKX4pvn5FdbRVo1XaCrYb" + - "RvKHWV3LOKmg$kZVPIMXBwo3D7fyCvLfhmwzn3xPbZlWrLUF9$6nhHV6XizkQSB#Xw1tvNY" + - "qVNZz$$dhK6jisp9ytn9EoLQSr0wfG2px$HfmYkBc07K00UsYjhNcll7gxvzFiGv9OdpvJG" + - "Sn5k4UGx5lf60kQEj8lu6GxFPjii1uRpj6qkIbXrXJLMUUUYFPg1jVtQhZ4qehXSUK8hjI3" + - "1F0QImF$gl895L$Cc#VgHByG36agki7svqeSrH#ax9S63bvjvecN2ETmnDeV3fw04xvDJzO" + - "esAUjfQShEixlLBxqVbBMy3v9NJRN#cZMBhhRDzyR9Lq5jaluv4NhqlvvBEg$E9JsSxy$xT" + - "xDorLZQgdF#c$KiBgUh4FNiKszneUPjeVu9KT8$9vRWwi3MqqBZolT$ZlIiQM#hfVwin$oE" + - "huRtq05YqpxdQcXDGXjgRnv7NAfNnuc9RPGWNww$sqGRR5jrdK9rlI9jj0YH9lS2Y1DQC7M" + - "cXM0SgONcQx85#9VkWrJN6sP4geCMJDkafNbo2tfSWxl4HWktC04j70nhvtuhRdPihNJRfg" + - "Lg6NrcgppwJN9qxwZqy6ywcy678dhGTdE#mkmUpkEaRqZDDqMaXpMCroDQhTe8hbHrIzJBv" + - "9Qi#jYT4QqXN2d6y4entkuPjMGGovohRuCukGvzg4ukrPBZhMSoYDSWulx6j7DTiaHopzFw" + - "cswBL0lbz0vjjmayCZ9wyCbKMrZ#Czv2svtlKeqFxpim1p#ZOhWjoPWj4ZrhV0ojuazySW2" + - "hRE9ugtxa7oSRLT98XwDdwyaTfyJshR5G5ahs3MMhj75AnaOMYevUceNoMTwsHzheHViGQ3" + - "9tEXb5#3unI3LZxT7pxGISzqbNx5vaY2tMX$HxxldV9vLy5gw3jjzrJUwQNqj97brpOtCWl" + - "0UgHgHxwALXYJYBPyMvbhTS65aRmZtT#5Xxsi$iCSej#JyvQlKoqWMNv7uF48mqPd3gsFEk" + - "eZfHIgsCveolLvJ8EpOA6dkz3kMUk#kXvtKhiTVIiEU5zREfvwlNS$qlytHUdCihdRbwcXl" + - "vVLniNSFwrPtNB#h3sLno8NZEYwvhp7EXFIDCFxddvXgXLIsz2hzhJPeHVHhjIcViBcIu4q" + - "kwrXRMjNP1zqA2AnWXmtr6C$Qlek#7AUtgExBuBYK7QN2dhv3Uv6jFHku4Xjf4ZzI#Hy$N#" + - "N9j8ZEb3Kg2SpXor8hj#MtWrvQdMZlPQdY#iVHvxDDq1xCxUwgQxRQdLgkd$JWNsMN1jXEa" + - "VLLYvQnPK9ljQx7hQjVFjUhdncmKVSDTT4TqTb1x7jBc$QVdwJXSLOBxCO7aXK4geKw8p8a" + - "d2Fhqsbm8fnFYMOW$56BS$aASy5yXjfk1V1SXN9GT1PubwEDXtONmje3iMK9CoGZrEKo8XJ" + - "SWcepZKjH19eFqmdiG7u7uKPI$WVW5v9z7$9OGapSIui1laVvKY7LA4V#0ibs4E7I447jTW" + - "$Xa8KRz6$53GXpqXH0JoY7xET9R8pq1CZ#ZtQkG$fCGRISAqGppHZmhHBj9IB#3umCXclS1" + - "$ZCH3qJy7Ue6W7SzvD5kkp#ZFSJDLw2kGeWInBCUmG5iSxeAqG4w9xmknCGMgBiRxHwEz1v" + - "275ifnAQ72B4kR3CH62T2Pk9lGdH4Vqi#4#BWVZZc04jF8Jfj0BvZSFnDYFNwGhO7sWA6nT" + - "y0NtkKFuxsTq0vZYL3m0Ex7WGx7dmBodO3ndb8eyyzRqSQ60uf0n#E4jYY1FtgU1x627AJW" + - "VVOiU1hYNYw47qE4cB1B#15UVjLa4D#iqNervVer$5e6xPV3sEzmOsekqY8pjiWxGknuJZW" + - "cuqOvHkvE63dZQw5JiYqMuZuPkZi1Lt0TCXhGcmy7Fg1UHByul1tXPYxlH2ReuyRT11Oi97" + - "V6$5ciFaeyEmENDIlAuHe0SnBSCNMuLMKdmJ#kU23tPfZJ5f0pw4$mSUWVmRoc$m5umxRjS" + - "IujSIOj5m9#yEkhU0phHRWU568rh17Q#1h$P8GRJ0#ROx3yGfmReK3VMaBcxH5$zjYh3R7M" + - "6m1cVP8RxalyC17j$mh#kS14tnWmH#568cvqHE#TE0q8Nh3lqfs1l#MGio7Jys2p8Br8VU4" + - "4DDGrnw#VonyU3fyz2ZuxT70sGFwUfqFMUWv6dYg3aKCtvbBCUR3wDkGNehZEjW0Tfdx50w" + - "CpJp8pjiMFAS1A$ncW$#X7hWNO3xr68zn6Ody$HXtp9DZKRSXngOZC6y8$plcACZ2hWjsWl" + - "nDi2VySpRiU$Hpm8ZvqEyKfBy2Fsou4SQZ8yPx0OqlRD7fLkJFnNZ2ZfqTjFqWyk3T6FRiW" + - "BOwmIywOUpRxmfR07jd#DeH9y9ULsDjk18yM1EMO9oQ8vxsAyOGupyFlji2upeFzRqWqmBZ" + - "qQ54YEFMWPtUHd$NHHf#E0z#VIJgZyEyRlulwCQuR89nApb0Y5BCtnxmZrBOQFOvYD7cRBH" + - "PUZ7ai9RCUn$#sXRwlqSQwzLyZ4ifx7CWS5S1xtoi7wLlulW73l3tXs#LOlwKOWtQlZ$gAG" + - "syfSzWJhmCJ1Yh7l3jJT7E38pfJCo18x7kRRTOY3BWcudvD1FsQFjF#0lcUFk7KKTfsBdJn" + - "z0$1Z7ishaAxODtAFgx9$GDnThG5pQP3B$iYxuVjntySa$4cEDbeuNO2VDh1EpI0NFBmVpf" + - "0Dze#oFy4hARe#ybJy8VqUzrsu4NycNpaKRxwpwDlaF7KAmZdU4lGp7$Eg2$Ws23dJ4$EWB" + - "3pbZY#sAUTaGR7U5R2x3cxGpCns2js0NhuZ6GsGL#V0p6zXZuvZ7GimjiUGpctYIilSTW$X" + - "oAjVKOsAyAFbW6Noc3$NQ5JtI4l#sASUy0tcE0QplO$1Zqlp$MjlvJSTm5luDlbs6C#wDy#" + - "s4uuA#RmAUtVmynvdXBd4FAi2vK0siPnhuQVjC9Qs0x#C9kmDWRlZ0O$Us8yIZ3E5N3vWCm" + - "pfDWc#tXnuDnNjaCjY$3#0q0fW5ONmPy3JwqqNCc$1Dpnhr3Y85ONzQ1Fmt4s0v4NtQ0t#o" + - "0SyKEwCywmBG3riiTX#B0UMr7#4iDpWaPpE4CpZFhx8FZFlW8rhfcns9j0gwM#w5DpBkoBF" + - "m0EdV3Ubg5DQqVscs7iXhaQnx062CkXpq6DSE1zT33FEq8#tNgYF6w06duwX6m$pIiFvtWZ" + - "vtGrsax8aPVgz2NSlXaEVnb6jQwpXZ$eVz17ll8dU4tdT6$dT6tSk0PqXiOC9SxurpR7tvH" + - "2fvTi2wNjq7TsK8CwuOoZ4afC9LXtkro9EA34MDzACCOxWh$Bc#E6EjVEVgswoU8CIwxOJs" + - "1ASHkm5A1DdV3Fge2wywm0n73PiEWhnB#jJlcIULbY8z6ZB7R7UVEBbWtzu3Dks0Tt0Fpjm" + - "lMb3rm7juA$HiE$zyAPSEnLcs5yTiJwy7M6ACzfo0#5J7MrwqnNpU$1FOaBD2r7kRGUbXJr" + - "iFQl3xsA#l3LZrnVku5kwyFcsu0doz77pU0hOw7NtV4EdeyVBGJ$BapVEzuhC6TiJ$fZ3dG" + - "4pexmbujuJ$bEBTlWFI6MF$AiMwMu#HLZh6g1gPIj56E$lN5V9k9kfuqts6tQgpbfUZhJ62" + - "TUIVoM8zBqPVviD5yw9i9VJDn7Xk1CJqIOxqfx5yE7RCmLhE0TtEiJUsn1Ws2JShX4nlY$B" + - "KXV64ZZFU89IYhGOmvqXNxYBsmF#Zw1yHOzyhHdxrWztACIrTWxpG8QQoH8p4tDuMjHcAkb" + - "MFDs7jJnEZlDXZN7i1N3XyennZkZRxDWYttnddmIAh7cZGAwy8so8#2lRgH3R76ZSBvh1lc" + - "uZ3qhptADm9VC$XRJwmjvTXJR8JrV6FCpI6mvSRm#M6OZ#MN8uqvtG9pkHFs7As0jHNwN8v" + - "zMWUSPpk0VpJMcUbeRtUqqHws78nnQGT$ACSSR86rgWNwDEWCp8c$2x4FC9J3bxlXs1Rdtv" + - "7W6Oz#zSPvgntctf7O1#oBSsuvzbtxOVxqMeO3xMy1dODnRkq4#vR3ZpQ1xJV179qEdjsnZ" + - "kw1TNqJxFDQOzwrn3ch56FM0MjiETQlbbXxMzBv0fWhC1z6G$zqh3DZ83i6upu6v$QncC#R" + - "ObmsXVocEFUqGbygiDQFnTem7Jwn1ywnhR0cLc2DsGBn5l3v2gmTMy8UUs1DRONviINsRaT" + - "0rv4KWxyzsZWIw$XEyBNXcEUby9dsiEUHy9D5mDWQ$jq6xVI6t$V6VcPVsB42SwxtlTXNOG" + - "qT3lzfZxLkVs1RX7bKWJxl3ppjuOETOCyPc3CLi7iVyFG1fatXJnKuJrLWVpO6wtu5$F8Op" + - "BVDC8V7OhzH0JilXCtROWxCmfeuzYEKjK8P$B8j$BK2wyj2w6eBcGLO9zh0tpV3kMWszWwp" + - "CHwRmxwR0#ySwEsFDN0EVBWdsGJpSWxcw9pbm07i$Qx7F8GF3yJyMOIu7TQA7J47EkFSL06" + - "#2kXSXF4y23PfX$8AzBq2Dbe4Uqq0ziuOymgi9OimzoPG6Vew0Vwo26lQH8oPY$DN1No#0l" + - "Dv4Vns8doj56je1VRk5LXh5c7S9#ASLqxh6MGhi2ukmboO2Fd5yDSAx9icOlosm1XqXA$Fm" + - "NhN1xw#7TRalN1E7OBrTYnyTI#S$uQZppCmVpfXBrM1kLY6ULw1$SyKnEDeJA2p73wn6EVv" + - "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" + - "9X2XvpuIDGX2$0EYVtZ4r016GjiKDD6$m3zK506hy7Yj25WW862a8BUK2dB8BI9odoae88S" + - "SAeWYLmLHG53nCpE$rvqb5KsKvCldTytCxlRjpimMddhIiZlhmA9BqLo9$2nISemfkTObOu" + - "Hdmzf0vfRIplPzQ#aSwvTbXpLFT0ljbAojKkLEJEwxL5ydbhQCzNV6wavV2$Mxg30MssVv$" + - "4RYZqRF8xSDCVay5ChzcXfbwSdQi8nzIA3V0ptkZ3tHibahlJyFuqNNY9KIQwVd4DYuXh3v" + - "jkpZxvij$RAs3fv6lQCrNWsITMZUCikRsJC5pw31phdAjKxDTjlVIDGkiVHbdWywEVt9TOY" + - "t36FjvFdQddL$WJoB0$Rz7NjRk#2evIEoJiyl2jlUmLudc1JwvRcXNTmkj0lPXmQJkN$Pnm" + - "LJcZxkx3ijA#PRjfBdxo1dJPWhzsdQUIQboorBPAx9xz5q$uM3BPkpjm#sEDU4FNGBzdCjn" + - "ybvRWtdkO0zLI3pVd7csZ3N1VApAsuyDkjtFXprosIz7kn6Clyzu7p6ahTR3f3xC6ZGx#ha" + - "lBfPTcdy#Tr8FFiBedwWtxsmPmjsEJNfqEvISrtzQfxF#jtlYMYyInFhdUIj#dTNqLY7Kr4" + - "$rzc$9PD2ES#k9U9ptoNlvxYEXBNbibv9FgpVXqdzucZVPRBMAvTxDDaMFIQshFigTuhF$P" + - "SSQUsgPoN6P$6XLHBh9NrTiknHQjdnkZ5xo7tLoraFTogErgIb9bdjd7jTj2QUSlrexiLMe" + - "VrWlTD7FykUjraMofgje5RyvwBz55oMTWE5icxlkSFogNlq#q3dkDSwOwsrB98vFfrfKqrk" + - "kyGEIkm4CLcdfKy86#SV$ev9dx8Vx7f1V9bVyogTSMNEo5$WdakqFbkUtydbOQvGvfB2LKw" + - "zx4aB9rksRc7PyeXbGR7KxR5iBv#5GZclAbb$5BMnx23tSVFIS8nSkQP5ifvEkdkMkwF7No" + - "JhbJoPfv8NMK$UPUrxvNhVqbvovy9sLKCiyni$Syvvpv1wMPiKo1edsU3Kd0$jrl9#9RF#7" + - "j3i#ZwZ$UTlaNObdElUlwzh$KBc#INzoxMhoCAMQnJ8ipsGzKiWUzHaC#bZkAN#u#NfRtb1" + - "NaRgTnL3dle3$WapseQ$3Uf$3tODJeGJbU$8CnfBV2o#LGwAYnAYJ2xB#5kftqgxMHpEB6p" + - "zVJbMdl6hiQkfhSQtTboebP1u9kUfJupYA4kTelqfujkf6uaz4jigHnXlZ36x8W$vgfvuFU" + - "thyUkDxoeXSQynlmFkeFuCOvp1tudE6iNKv$IrWVm6uNB6MKxk2oDFJQTckg5MGjLILqkib" + - "hnLGcJztTJjWNk8iP9Ktnaba2$oHDO$ZdsScWQEhu6wduoor3cLRNGU$ppNeuOnQuZNCBx#" + - "Zf4Qsex37aTydB5zzJDzNO2imDKlHhx84$dgLzfQ#UeIl4YVMglmBnl5r9V4zsBlnVuKUoW" + - "SIlkXn4RXZy8E6HTgyH6rKliPVp#nVTZxQFSH$Ct8LnMmWbm5VLGmjgKlolXQSQVMarnSSZ" + - "T9VOxJzhygCuxkFzkHcxErht9SKVcEF65ScFW7#KvzNDgxjjT4JDTdcVQx67yNiSLGQmcsg" + - "s#9BJ3oLHr#7UTKXxsQs6hu8J6hX5e1Lp368dABi1SHcmbd4dkDMgqhs5U8RSBUHDqcQhJz" + - "lL52RIIs4NisDREfjRGQHcuOEKjFfFqSeQVU81VATsoTYpUXJDmN9Oo6Osjjfkrc#8DH32M" + - "CVHNxAbm6bz770NW0$pFwMWVNyHa#OUGXts4SPObor5ngvj9sBhdtq2JyIVXQNndvQXwS1p" + - "#WZpNary3rnDOJMqj$fx5FOn#apuCStq5YMiU87wFsRIFzpGGnvAigM4M#4bRIfjBO2UIhm" + - "SG6mnHjKjXMsewZJDmNFykn4qBFoSNLIjglfEOmzY7iGzWBuK8u6MfD8JS5$cYar4bualp7" + - "HafjmTz2lscO9lO#V1yUWKVWDqOUYgcliVl3LswW8KRUlz9Rr6gzREIhT#3$gJb6dj1gW96" + - "l#iA#vAnYHkyQ#MeG70Jxm3vG$$#5VePnDG9x1FOOE0QEXgFXUFePRnZLIyJdSvtdKtTKD0" + - "r$6fmAfy89S09S2fV26N06P9UEOkfrqK3Hcty14LzYs0=="); + "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" + + "v4#1XbDPptdU5OXVw5tYNMJB0AMHlJHMleztcUo3z2jb7uHlftCQUTTwDtj$yUxr$#4zu3t" + + "jFUEzu3tl$TrxCL#PeEoRtbkefvR3xtWVUXzvAxnldRcs350gsP#yZsBbgxt$uVZTysMrh1" + + "PFqZcDF9dnCXdd5UVzp3gP5g0DCcMP3JFjyfKn96ep6ylgJ5TPZJ5UdkaXhyhqpmp830mbk" + + "CSvbDaYCo9MldTcHnoZCpl9tk3ZwPn6cGcPIPczG7jczixiAxEP0#MlcOFbB$dA16KFaVy1" + + "$vVi3PIplGSo2#JlycVvKoZ1A5Nu1$bjhFncyXiStyllSDvC$e$FAPHPAlyh4ZxvoXXISdH" + + "Wz2IMPPIMR8Hw8QKNf$TIuNHAGcXA5Y8bHqSCPI31A2tP26sAb4qvVLCLJgTKb7dAs6MD$h" + + "IoG6d9HcWJf6p2wPkeS2xnhBw9aaf46PUdMTsEkwO6EcAsL19cLj$4r1FJsHCfFJczfmhd4" + + "gFigQGIKSRb2QKTTqqDTCHGAWc3igUf9wQp1r9wS7eF5SubHjb3IIMYZCiJIZlkcXheYA5K" + + "4WPb3rDFJ6Ttf7JdzEug72TzPx2xaaf46Iz1A8ctrt6wCuYFMqwoCPIK7zkv9UZiXfHkdDv" + + "DXUEaKNPJKeaeuoK89V7sEcwZx1P3IVb9AACwgv1InUbLAXmdZR9AIIMYZ9SWbCJRwxYDiY" + + "g6al83b1ohJD29DAdIArKuJXfbfP9AH1alGIY9jzTn6sLb32NbXoWfLfcWim8f5PnUeS9nq" + + "YWhb5GYIYFPGtD2IRozZjieAs8eAtBlMDiw5Vbl2K47dLKuJlgwvoqbbVJ9AK7NFSJRwxY5" + + "4h6syR99AACQvUR0lJcZtro5uwHjkRcIIhIbaUoXETcIU7iTjssvUSoMcwVOqaPmYAn5IYs" + + "drwfmd3JAMYMLYD98zj2SK19lh#CsojeOojeKb54KWv4ocDC7gt0wfQBCKyOkQ$GNAfkGFW" + + "WfWpXza0gdKohAF6NiiaP$eR89wGEGCe3J1wXmEgMYp5F6Bclq5ogRa4w#KixfvIgSJgaey" + + "vInonhzXSecf7T5IbTExwh2wPIACayPkwpHNwXiGZf6d#GHA3keS9pq6E#Wf19H6iaUcjCO" + + "9zvUn#qntY4snZkaZF4eYesGiX6dRwJ2wPIACayPkwpHNwXiGdexfBJZz7Ogd4wfAFEKiSi" + + "Q$ONA9gHlXPIjE7qh5KwdL9HvojXbZVv2PHFIjqNAjfo#hGgdKohAF6NiiaP$eR89wIEGCe" + + "BJHwXmEgMYp5F6Bclq5ogRaDu5ALqulOiAnqcFyIvAAX6baUoXEOrnukrrt1xZNM9Zl4lA6" + + "8#Yw8oKpfpUMONZf55sLbA9A8ra3yq99V7sEcwZx1n3sJa5PHH59wHqulHEAXmdZRAJaaf4" + + "QIHxQ4ueYRVNSHjbfnZAJYaeeoWwPdQG7Jcz8t4wHqcZxAYahBUxKgotSqXO1YWL9vJ4s#k" + + "uZR8ZeQJdheN8xCBnN9JFnt6uhuevwateOgXxd$E#EzpzqBtNMHTATX6pCzk9Uxn7lKU4y8" + + "vFUoxFgSWi5hNEBF6CEzXxtpdOM#uz1WJ7YNkXut9neBjGtETkaJbQFEWzZ9IxlO$TS$KJk" + + "FHvMDmiRX6tYjl4NyJzuW7nKAuT#4temla4iSYRq85zgCOk5FRWNPJhYbTHM6F79mKxa0jw" + + "asNsAnBAVa7OWLo8UxDVa1qorUA#p37k7WOxwicBNRm2BHynxdj87xZ63dtHjxWN#tOEVFB" + + "bkoF3iBCz#gb6$E3sfpBceBDypb#F3cU4V4u#Hwd4RGBImQmluW$#UbwDivcx1RSM$X3QbD" + + "uRakOF$ZXHwtsDi$1#K3Ob$MHJCLFCokmixgEym1$#7TeK$P5ZK#eFkLCu#ZB7aatbJhd#8" + + "DzpNysmHsIs4NFT#xp9qVzbSCRwvzDx$HqdtIFuEKJXtEzSuLpaNEuyHE$rXqtnSIPbFrNa" + + "Z4VVVkekTovqBWO6yvJfH4hDVWh9dOradCIveKV81wFeqSh8VnRuPvC#IXLUPchcyB1jQET" + + "zi4EiRT2Cjb69rBRTxvo6LftYFAGiIMtZm0tEbHZ1RzBSuTpidEXSx2u7mgETauAsFUmyGN" + + "E7qknSRMjsBd7kD7r3RNFMJUYPTotqxsAiBekYppWAVRwn2fzRwe$tbuBZx2ybzCHjogpbZ" + + "yyi1lfvZEQHmA#Eay$2aZWm0fwLpsQEfrYKmfx9GN#vk047FRrykRpSlO$EKTBh0eNIdbv#" + + "bdDhCyqW#5wcQI3FyuxYzFGovWcoFUdGw55Zmih0JozV2boNCgvBvQN0TMcSrEp6eJIVuB9" + + "E2$6qqryyugoN6UaCr2M5QAOuuS9vkJFTlJUqAcgqS7ar5gwB2n6KVY0#p2z1PtUa#4Hyog" + + "FlE6TxId5Ey6$oRs8DmiWHBcTnM3QxGdoSNK44swvm5XbPkQmGwNxCAq7dS7xm5gWKtQ9bf" + + "dnciLpcpQVv8InBCrbc4zEYx8hCakmAphce447yOsZAAq7d41VZG4g6xWEUpng4aTEuWhBk" + + "jenBYFDm7ATjG3aN5gBiDzbl89j7GkMI74d2FxPHAPbDOO5lA5$5wUnKq7fkQm$NSvVlmRb" + + "3EUU2GgHMuVmIT7PUvSR#HFwbKqxm$#p$cJLyOUJ4qEmNyA#mR8XgIvHSv0xJTPrVYBHjyq" + + "hGETQFdEvpdkFuOoXEPzsFGLbQknpubZ#6TmrZQ5Hopdc5IArR#IHKBikjCBEzIiVdNEHyO" + + "U8KnjerrDREkmTxPwRgEhSGwNhoIgYpRJ6xf2dlROxmK6#USx5LDiJqBvAZTPxIiLRDqhi8" + + "aRlIPXOMiLPz9jxnTqR#l$cSkzB2svoR$PsT4zpbE7zaxI9efHNEuhILLircUTQg7wFeuoi" + + "jodnNUAMLJwe3g#MJyad#RwCdewIkCzpb96MljFvNV3nFPvztrSHjCkZzhu3#kVYEFf$bkI" + + "Im#vkaOqSDJJ6ByBf71ri#xEUzipye8kpP7#Xjs25siGzfLhbYBoCPfpJBwxuzWrUhcvttV" + + "VrTC6l3sY3kSJvqFc1SANsBtI#l3QXZ9BIF57UAlsQmxebxQMSFhMVYQkGa11uKj#DyjxDC" + + "$1bUEv7M1f5mDU9CCfXenqgOd0iSidyP3dhp$KI5oHdkZ4lVsVayz$2UMMFYsZGcZFlxUCy" + + "CJ0Wp9ciivbuXcJ5m1irU2fDt6sk4PPpFmPMT0lzCmkJmtNsdZwFceW0JxPdv0zznFhFjb0" + + "yJndqkfgVCB5SS9kenBR#2BHDWCkd0DDJv8j9tnY#x9jWfvaquqvhqDHrqBeo8v5ZIV1WHK" + + "kxrW4$EKLQAUnFop#Uy74JchJZkP3c7tuvp7X3nRa7EeHBwdJd2X5BUgIFiiFducwWSbGkD" + + "V$UteCFTM$uTl1d5ecJgSVRakVyqPszrNKFlxCVvKKMiMV4jwBg6IddZd9DChdEfaKoYK0#" + + "5IPT6#wYpbya5rcVyH#cWa7o6KedRfCg0bYlYkERsn#I6aabav8m6fPzIpK5d#Ro$d0xCuC" + + "zBcesN4xSfgF4HHHpNF89AvuQIIMJauXfKZj4it$CVoGobaBERV8zISwzYjQQ75N5SyuXUd" + + "HjA9f6HYsjGEKOpK3qCL0y7g1vEH4LQ7bB4SSqZUdLkA9b4HYwkGUKOpK3r450z5A1wA14L" + + "QNbG4SSrZ#ZLkQ5a4Xcvk0QLOpG3rOD0zM20wi54LAJb0KKSrpoYL#U6aabavE8QL8xHBD$" + + "m7w23Gl8DIYLkKr3Z$Oeuhdb4hyuD9PF8oCKrg1oZMVxDlvyE2ic$KIfncu8QxrF4SSqZUd" + + "LkA9b4HYwkGUKOpV8r$puwA2HVerJYDWKrtgk8uvf7zEhSK3A9Z5nSWyenckMh$hrqK4Y#I" + + "gd4RGfgl4SHnpMFwDMveMGI6Rcu1fLZD6T$yk#XWqBPdoYLk4r1ZNShuhZc4RqwDvHC8YCN" + + "rw1oZ6QCmRin1kyEnk3TYMEGjDobYEEQH$Jgt50oYOnSN8FACPg1wYwWkYj0TLSYAjBoLqK" + + "SrpoYL#U6aabavE8QL4wesV#hSvmAEITmx2Dxly3fYrdB84LS1fps2tIrHVi5aqQveMGI6J" + + "cZoVcEpjukAaThtiE40yo3ehiOameQg8ZZuFOkngHHRYYPH4REQ58VeE8ShNcU2GVr3qn4H" + + "Le6AE8uU0ugdHjA9f6HOmtX7RLTL8xATRymOTQF$Jc5R5Jk9q6D$HLn73m7bSuD9PF8oEam" + + "txDn7A3Y79MRsTQ4aSVV6538$JX#Xvsrz5F4SUO6b$CBuJAveMGI6JaYknQLetFF3kEg5iW" + + "UwVp3EIcAYsLh58cR42SkB5ptOOUiSaKecKIghA88gXfpACqchb7Lg3fYg4XBNqNEBOY3Hr" + + "0T2rHzLMeecKIghDPae#fh3ZexTvcuHaLfkROYBNqKiQs8swYE1ogLAqB9959b5KLGzJ67q" + + "cpY6bMVH5IafLeHeo8kefwbSqKecKIgh0bRisYrELIwYOUvpdzol9sqz5R4SUOnRzUveMGI" + + "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" + + "xVJ$igPXp$vRda5dxJF$Zf8yG$cCUt#ApvmHyvapL0cqz0o5tPkm6h7$Ivv3PutzNr7o3bV" + + "OjSOSx5xCtxrpNTsBtjaQ#zwh3tjcbZnT26StXJt#fXVAopjMJu$P$NHL0dO$NMC$ORLYFp" + + "4FzXCBO3ynXlr4gJsUE6C$QRLYFpiFzhCBO3yxXlrigT$y8OtFd9EmZ$mENleT4V4ax2hFI" + + "ELIWFqiXPtISh2VfJI46eaix6V5i9#bIW3xMKhUkov46j2tIFcMY7WYzczLkfBAfG3xQHex" + + "qdAmdwOqX1g9BEodnR2Vfae0#sbAthiXH1gKNtK#SseUdpcrWC#S6iD#gYe1xATgdxbbTVc" + + "x$0t72LgUlxE9lN7l18szMGhs4sBOJp3QY3FsbrRdkigVeIBylea#aNUpOMqQcepTcL9e7#" + + "czjrht1CVPTez#L5uUdpakPlVZZ3RYZFs3rOhzs3pOZos0$TWOzcEDDkAC$PlwynbnwKhTd" + + "r7oXFt7rMhtEqAxgx2y8qg4NTu4Rjw6UPCuZ5CYfBK5eLBsaKwRFs1t4SmpaJS9wXp2Vaze" + + "TtaF$MP8tXCbJts3Se$wBjPWB#OxUVNnhlgZs1DxaB3VRc7dtslAswEaxMxznhCqx2jZTtb" + + "yBdPdCpilprWzNbzvE7gi7c#q4L$zs8kpUp9sSq$FzNBkwRsHZjrleaY8y1mdyPl9rP$F13" + + "$bB7vLKUHqYSYBg3RYSZRBAMdXZzRKXCvoTX2tY6MPKrdx8sUpjj6M7bj#ZeuFDMdwhDwRB" + + "UnIfeRyzLkVeyGid7iRlOdoqqFTaVg3pn#eNttorrzC##U88M9JCGBXEVuSTOuJIsgUsFvO" + + "kK3#21FtvyX3bPoMFaJJ73fxtOAuHIpBt8lzGv5NwrLGdgKd8c$Y$Y5obfBJqjCq7K9dEIk" + + "8MyIopAbinDTciRPfbfw8l8b3yqmbfwLtqZIDpd9c4BU8PPbJsKYjCrdRJfQUYBo9G$F1Ia" + + "vBpqQ$RYz687UsFriUJESuiInpUN2ireDPssoLdojluj1ya9BJqjCrpQQpF2Y8MyIopAbif" + + "DQ3MDjqIqz4tiIX#K0bfwKFq3ITplB086uHopAdif5Q3sHj1rXw8l8c3iqpb9oMdgNf03hB" + + "6K7S8fPbJcKZjSvWRRCiFH5v4uVcGvISbfwfQHQTvI51t2AMPIuFYTLw26kRQUc9o9iuD4z" + + "NSbfwXgQPT9RJWxX5BCjSJe$LEfsrpR3qHEHD79gdAJajVR2c6NIMquAuHIpBN4wBrJgDjH" + + "riwOd8cpWq7w3ajFH1cWwcipmWY5l4iipb0R5Q3s1j1rbw8l8c3irJbPoMFb3JGNIMKuEuH" + + "IpBdCf6QftAsWwqz4JaJHoQvoevBJrLqu5qbdE3k4KiovpAHcgTozgcMdeYyYPkqipPtr$J" + + "L3fRSOjOLlEaJxnSA6$Y9YsGtbVJ$dIsuXQnhEQ9jSRAXV8cRj82wRqrxKjdAsuHosgUM6k" + + "iN2XluYOja9wiQMywMt6BM5Rpn5fZvK9v4pTfWVG#cYRJsOfRnBAQ9zOQAnVAcxX92wIdQD" + + "g7pbRS8fRLFB7MMBbGtiHDMY2zdwOfTBRY5h6ivecrnig5yYPkqlGvUAROty#vEUbTfuMUA" + + "SxthbEb8HfsbadwDuK559CBL3YNIDfmvuBeay$#Wsf$AHSOtVw3X9Bbqr36tdtgJ#1ouSxI" + + "UXigl$TqMHZpjqS#lmSR8Gxd4g7KFETQd6lUNfVMnE#uspvC9KxNuXmQ9QfyVbR97mNQdiy" + + "nChdOkVxPrEFzoMh3A5qw9k$iO#8c3SS8qTtdVpFpHu16yJb69ZVvNWFh4BOyjsz4c4gSsq" + + "UXRP72$$6648TpoUIcjczRNJecxzrauYODn#58uU#d4E9mBfdSrFOThaihwPRSliF3LEBSF" + + "WhDLGUTmTUZSvo2tBJspLNvMhgbaVVkCEMD3XpprK5dq5m#nyZaYfIFqf4aR#8c3SSyTT0P" + + "D9$FCJAvgVNDqwMLTCjGtfGtEd0SfWuwW#RnEKOcDrRBM4MSDzQIRXdAc$961uv3rK5dq65" + + "yZjDObMjg4PUP6ZK$L9TcqlKT6gQ6DQYvpRkLIjAlEbIwqaI7Ttt16VXHHwsNZqPRx#7QdF" + + "xLYzAzITx#wfwDryAQsnwLEogYcE9U1s#MTvYd9KokcpMISIAPi4uxh6BoJgCv2DyPfSn#A" + + "i#dDM41oVeBL3YN6BNcyTfKdbtEf8MfIeBhsLqHwzaz$hmXfN7kBcAsaOmJbmlRQeN36Ckf" + + "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" + + "IdS0ZVOIkfpdU4qziz#AFjsH8wKrHAGy$gyNCSR2CGxwzDK1bGkanXQIIj4#BYodqQfoO#D" + + "IPgPWVTFYKZPQQquP5qZce4sMulsYoI7jqz9mi6GY3fOo7xN$D58q9qNBZx7iCaw851nZOd" + + "DZU7sMhnqYejqkbuiZft$amlJM8a$ex#$KVPrfaRbn7F9j73Lo8PT0EvWRAnsSqjfnyPL0N" + + "9tOZlZQeJ24gNgNJkq8PdBKXBDkXx#B8YhcwzMEvz4a#voBL8DWJ7XT0VcnaUjbeRI5CpdN" + + "CCQ4XTtFOs8jPyGe6MaPQS9ClaiqbJGPp7bQ7c$7ECkIuRKHMkOlL4IflkcbiK6##Oo9ba9" + + "DOon$Ktqp5YbNM$S$5eP#oJLen0Z54O#9zMcENLMz1X$sAUeUmq8#neRxb8HxQa7BiKz1Yd" + + "bIbDi8$yfqjqe4zLhxfJ7wVdWhlTynBO#LIhY3taQLICZPC3LdezISZLDpEgRcT4xDwPgQK" + + "v6QKvMQqpqrfwUsMkv#hq1AWguzzRkOehy27cVrVgp7xHJqFlb0xCv09fY$4dfyUfuUBzO7" + + "PgHQPd5gpd6fEKjISqvApJabDUVAr9oRKdDUICrvSsLxkkYKF6Dx9LF6HBsXo9vEIycTXnj" + + "sowykEkN$jvRNVP$dVlvWo$qZuzyfyThBztdKERq$ZHGuft18w98BS2JCTDxTQJE3zudtMK" + + "hELwbbla$D#LTgpdzIw$ajEZV9AQ7TEOnpZ6urgJYhyArHqgLlLMy0DxqbzmrwGeN7odsZX" + + "FIxA8zpEKpdAB6gCVAkp1uo$8tL0eJfhiEVOiHFdr08PnN#SvGqCWf5z#xvOlGFIs5AJII$" + + "HjdE3##qrOJUYbJ4WhonmlRaO5$9#MFz8vYFer8gHMdby1YM3fuM3CONsoQsGpIZCLdQxEk" + + "6H4RTE4jUXFuGkwOpdt69gVOLd8XU2mcp8qwIZqk76DDp4tSSE1pXObkJ4Mk99gAfQ2RM5i" + + "t5Ec9TiPvONsmWMeWoqLAq4gtXbMt5XgATs4YqXtzs41r59uo7BgAhA1SLeb9KYMwYk#Y1l" + + "TGcObFHIsmcUejgqKVqHN$s4$t5035G31A3nUQY5dORAhOGMufXOhZOIcmjjc4hZXJRYL5Y" + + "Ux63s56C5Zi1ySwyDnydnWCT$NfYKWwwAHh$r0RJaXveYOEM4DBPOewOAmuLXq7l5FJ8uOW" + + "td9OqGKkUZM5pW7eAZjP0NNSjkGercPQy5BIaHs9B#W5rl2KJn6DYL$64s4tiBlOGUugznD" + + "vYdmRJ3tFHej2J$YJ#p9vqA$gXeRIWei6tO5wa1OvOo2sOr81Qi3JMWlsv1TCQK0kSI0ig6" + + "c0BebwKqLxKhC6qO1wqsYrOY3gf1LMDBQYp5lG4Ghi5pHjS2#QXpeb1dTFH1ul4CMAnEBQ1" + + "jk3#1jc2jcW1eNJWILw3RC5#kWNlYlV4GOqj#CCjMBgIBN1qAqmBrXQJwmM$Lp9#seaI$lq" + + "OwG4O2Ovu7#7wmL#w1ptBEuhwmDgiPApqcIZcSnrDG4aevwCLXFBWUcdJ$IlH9jfLVo0#1D" + + "ecG9k4adBhhqtzIcvJTxw3KHzOpsX0M1kINHiIree6XBNqzV8oSNazOIrzRYDCzOFromQ4j" + + "I7DMTUMZFLtuAeVhCqRa5rBtmlHkT6kgzwkhuitwWchKpBM7yLFzOIrh6IifBkXp5drvmDj" + + "6v1TvvICzMVnhmQpp$f5$5fFMCiRqFnQkbthprzBluPP9Ywe9wn$BnbhithRPvM#nZPYRSJ" + + "QYBKHwrn#ggC#iBuGO6rMz7tQShxFNmMaJSJNYIZxeRRwkqzR#fvyOt5FFTd$dfAnEkABUi" + + "BwUCbOoyJL3UPQvz5wcozMvhwNKqzOvvUCjQBUiAwCNPVM4zP99MET1AeVhAL$D$oeUBcUi" + + "BvJCjPFCC$L3zQ99MFrnEnwmZfl9VSDyr179lNxtVhTDuH#FN6bza9fRNgn7jiKxaNlAB9D" + + "6$6p1IxNiHQtgZm7vp$usxVMzTIcjuCspIwoJHdT9a9DE1rG7ASZRkPsr4#R9fRiU$k3wcV" + + "iPrRYsOxw7CsPedSgFUjzvYyMQtCnjTwnhiczlwH1e6pI850s35lUrY1Gbgt4lcdLeymWXL" + + "1MvQ0iqqzFEaYXEeTXnpOF7h2sXQA2KSPHB8NKgU8qna8epc8Kvwwcvs#ReR#f1SroMj1Mj" + + "s0$N1#z90v02zgBkmDTLK3J3MYe1OIcB2yQuWvQeB3F1lPh8UyKrUlVYn#0PYlzJLQ5E1Er" + + "TiDUCAdNQt9#PzTFxrY60GtXd9GNPxMO05IxQfm#S5vNDCwji3CSA0u9SD9#jXiq9UFC5C3" + + "vZxmuAo8u7U3qn5oKA0RdFCWPd3rGGZqVtIqHvs2KYEBifd4s0rB2sJOlpge8pcR0kOpH5O" + + "VJ0KwFSPAaUH8z2UVxEVPifd6#gktPlKHxpaFekv9ndeMI#N3IlVJuh5G6bBN0eFRJ#L3Ih" + + "jl6MOxQ#W1TSIWd06L6xpkR5K3PDWVbsq1PeL5MvKNfe2uFjHq8d5T1iapNLGnAoXc8#S7q" + + "kIiUmwprH2BAsP1EikMPG51uHghckjHyEfl35u7FBn9bsEFK1nCXVmxgJKAv1F9nb1dKIgE" + + "mS8#tXnNDZFivwZaByrS5re9YK9PnZtlwIQ0p41g4UbOaeYGjSPGqUYO19w6SbnVb$h3SKZ" + + "4DgzPIoD7QvI3NAmhb4fGTYBcBK7P3kGKeLus#I4BvW9YUWxAARTcZ29JBW6uUeriAlrGe5" + + "nQ9iYhIumzZV3m6#JDIvlQg79HlCifXHQ1qWCxJA1tc6TvB56TBn#hnsGWvo4rUWQY#ECeb" + + "ZF96HdbcNfIpWvw#HjTq0rRqig9GDkFVpS$MTnLfHIv3Vv#JY7AP#2Qnny$KFPv$z2m3Ele" + + "y3NGFeqRwXKUR8bTpwZE3iWbAJyJecPI2akwUn54sOvHBYa2vFwCSZP5#0z$ZRm9hP8f4UG" + + "QlvRDrZple1m#QbwIWJ5vxp7oPAOYItXr1A5MFNoHUAHBbWJp6ApJASr2sk$WsnPRT4r2UQ" + + "SsN#KTFiy0lbs8k9rxDTYaEfJrwUl0yj0H7iYq7vw2SpIWFBG9b3w0R7HdZ5p7sucsfUdnq" + + "qESz4r7#9y4lpxHwFBzVEkXnZtStDmJpI5F#RN9Xb1DZVkdmB9PyJoPjJtGcPfJ2AAS1PJE" + + "SPmFbRCPv7TTLt4n4jbp6AAlPCyjmp4z4IMjSqXYVXnB5h92XNxwgrvwBYbnx7FPBmIYRWj" + + "IlkfBzibdEFfW#Bl$2VAtKNxZPQyziHkUXdapWNSMWhC1O6OY3K9u3Ne6QcgJCH3i3OHpb6" + + "A2Sg$Vg7#T5UGfacw4qtM6cQvubGBK4Cs5nExSpW7AmlXj3#3x5DUrdYIXfpvIqzYmHppFA" + + "C$AY70sv#OYNGSz7VDp6DHRdbsJBPXgbm$TJUwQCyPxGcRIE$njxdCAZPpvqBuCCyGfnjGu" + + "LDr#Iv42KKMDyFlVu7GWbeVndmXZ7w74SvAp5NfaFvHtSYgku5hB6VEnHoX0lRlJC3zQUkt" + + "KBhqOykSVdvw2iW2qflJ1ArTTd0CjSnliWZvtXHOwU1uErPpPabu2QfOmUoesZdCjNPshqR" + + "9mNvJsevL6#WbFuNa2vfKNEbnxFb$Vg7gVMtiiy2ULI#7iSvRriomhzRLZ#w$6N6TqhZ4w8" + + "5lee1cKBtb#sq4yJpnNcVzMJK0hUUUNEb$GXb28loYL2o8HFCIXPRY0Ee8oKJK39wJ6KI74" + + "v7IXnpeCo2M4ZoaQKZIWRKJQYR4JPYB8HPIFAHfIDA1jHDg9iHDc8iX5b8yh2ACMoKb26xq" + + "Rbs09n#CgWf2T0SFvxCafnSmvAzHvDUbPaddvUx2xnLx4SSlHCncyA8s9bgS#BEU8Krl0Mi" + + "3OLVoECa3zFzCRv2d4btt7h8owbv$AGiZaqwEVo67dIDsSnEz2Rq17Q5KVqJUZgEH9WHux2" + + "7hwByZZ6pDWHIiD#2lBuRQ8ivR1zpqEeD$IH7Pe3#wNe8OqTHtxi3o6rE#VzZVJXqDYXRwN" + + "UufuNFNd7VfPt70JP$SM1eXbu7nmrEFgB0LBoTqFq3556##AmU6r8KyyQHlrXF3$vteTHmB" + + "QXJSMKFFvGpXggk5UKJOThcv8$a4txaS$c#WCyATUcr1$DhD5tARyPlop17soRJaLj5Gc$F" + + "A0HbybZKzMwy3t5X7v$hdT9eFqKRjaWSRmu8VG8SJx2glJ5wJrcUOI8eaTQ5EqafDJYQ2rc" + + "Y9bYLjHVSgHRgDh5#3njYumioF58PRzNckdfiQRKAkwPayJ9GTj8yytfceE#ePvPNg1doDj" + + "hO#ZVChRBLmVVtSUC2eydBTGpIRy1EWKzCv0rXNvrdbapD89B4#sNDiyK7AkwzVcUgXtECx" + + "d7lZUL#WySCxcsVr$cz5HjKxOzwGYViKvQ6MYi5e6BS$FXQiAuekKChjOXBfm7qOne#Ni4b" + + "tgh$Qh3nVDH9MOtvEhr#Y1U#THSbuCBgqo8oq4iN1U6iMoHk0hreyOLpW#3J3#oth0VJycP" + + "7uRnJ7PwqA89cCbsBTfUDQNXClubdWIV5xDN7DSImeLZAOvJjGsAmgNzkJ0kpcEz3rYuocE" + + "ur7eUugg9hkSy1nThh#v5uQfbhTC8YyOL#1VgCBXe9RJzAxhBKFPRJVuLpXEyc#ZBloSW$w" + + "fAw4UQfQaVmptX$gkh7oFp5$gHqHbxDUMdGgr#LBk7I4#kKdl9oExPu29x1UFn8Uv7MjjI#" + + "f6ifN45g6Z#I5jfy#xCw0tTv56tqYueOQKjvvcf7xmDQvNeQVMYsa7Kf6eU5gwqXTOghYEs" + + "qahQkHMnqaPMowILLbrd3DBNBk5AooLvhy0xpIJhwNr26yn#otDsz7aipoN9nzqybX#EFS0" + + "yFHlJGTYjVZOrQ3#biHvYFrjKcxuL5wRMa7ureZLBTJKoKVTKhKQZhlOeb7erejO6rB0Vpl" + + "kfgn6iUxrfPyzUqOztBcRdN2k6W4#dyIMJhaRYEzPcqDnSpoIKUhx6j7RwZZMKvZhs2ppPO" + + "A9VBv6EWMnFzJRuS7LCk4uECD5O331fH3Hx5Rpk8HoSVu2uBZAwUjEUcKDqVN6dRQTyc31B" + + "fc1YNKLXKeXOuZg#3Wim1Udq2uiefj0lavuqYdWJUONT5qKWYipL1X7cwjvSlacuJaIygGO" + + "eMoTwax7H4gm3JVavsl5gjw3NfwAkLwKChrSjR6xAzUe3#dSQ2TUhUgvk4vlxeJdqCOIgjV" + + "McgDLIgkiQSnLxI2bOWn7THzoKYzNCU7cmvlHfz5F4jNKIgk46LQ85yrpnhqvKGUb4LFLbg" + + "qPKZQWQKJMYQaJrVmMLbFpBE7MTturHzSov3rgJX8htWiCaxnTM7fMOmkURR5JYBuHAIeMA" + + "ywcU6AfaMzcxc3zggpK9bRK$puCgw1DxntVwwhIL$cOeauvAwoHKh#LuLgAtHt7z4Lj5lPs" + + "$COZPIjp7#zte$IJx7iS5uHXCt27$OLHg3ERqO7vKpwn#LEAPab6jcRPQPQYazKb75SmCzz" + + "MDjvU2AXVJwfz53QhWlcmth3Wz32hKF4pVuQnHt$eet94U72PNqJgOEZFyDyslT4tcZbQYN" + + "#dlFwU90rSjgZNPsyrEHllL6hAJ2MmrB$GhhZcyamHKkdJXksXJgEQWjjWzQjKcFW#YccNi" + + "7dK#pPnRLVYv3VrDTctEdNYwerYMNWFT2vFydGtpRhdOnVNydStQmBvEBdROBlNf1QdkH9f" + + "lwTVEzyn96lPyrb7OPNWNrc0Ft$jqlTPDxx6QBksxwqLONkp7TzSFIBAxhb7vJ6JkBDfdne" + + "S#e#zG7v3hCsbspsELakoE6NobxPxkx#GpojznJ2y1UtaXkwyQxD6dKjAmnxuLLFv#UdxiC" + + "ltxf5LiT#oH0#nIMcErcRAxxJD1cPNs6UFl$Dr4imJDXR0NU696#NlQ4pE5HchnFhDoymnz" + + "BwthESN67jZzV6DtSN5qdbcLTa$iqV#JTW$6wld1MBtOjiwgdIFNBEoDTi#FNKO##VPYMc8" + + "DillgmjvezqQxDzgzOM1lj7kZtLSEkoposkF$7dPzNLd5trlrIDY$rrZNguEbVPzWs1$3Bb" + + "VR$bs6pv8bxj#36XgnDs9lnDw8lLxl4pIkJMiUTYcZsAMCVkzIx7S7zBsBJFpkW7sc9Wrx#" + + "dS7$t$RVHNiPoA$sqxwLO76aFAh0bEIUPvV5HJ2BdD$ZL88#$3$czXbz4cR#Vnhx2F4aU8e" + + "SRJbXUQwwSG2O$K26ViK$qkK$x#nQruITb6zPc1VrVuUnPxxMPF7QYFsbS5kVQyvB#hhiLz" + + "Q4lOJ4#V8iwtlA2yi7VlA#tiZzaRi3H6xbjDl9sRiYNE6Mfj4wpK7kvYZvUPPsAVAd7rHxh" + + "fQn9fwXRWon2wkNzLpP4EsUtrYNrrs5myLZptDPxJ6EiTUYjqRiJTYJy9kviWr3RkW$p#Zy" + + "RcMnXwtU6kMIftVHMLidecy4Q8H#whrTrdKbRR6NbtVsCLJQoBsudo6iAzvFjEG$RqHUoFs" + + "HkoDs5Vpde3k53JHykezB57qPdvllUPX3sJdoU3x9ev7hzq6gQTl4x2VNSzxu8ZTOphMO9z" + + "fwDXPfe3Ff66NQ$Xraze32s5TDpKHN#LAcPuAtqDT$3wItaMsidOts6N2x$ULtNb62h7J4n" + + "Bn5fwUX5qMyPsybhxbZs9FxC4Sx4czO#nkbIi9#yhOFMci1c#C#iDZTVLYByxkATWBtjDBn" + + "AxVKoZplHtzwfZ$$KdycVcjEXvxEpgdgNUHyTlH9RrpZNIhjm5lpYDMFIcX$cUxTLAjgh$u" + + "lMALCHietVJkneHQOG$rJlPvuVitgLRrtcmE3okcrM7zLitgllHarUgK#cyFMstNRsbPwVf" + + "r#Vprhq7jhxjUhnzVQworiTR6MXjhRQmrgLPEIwbLbhZcwReRQssizVzOhTRlfeVbUxUDN8" + + "dt$MeDDLQOtqOIl7Uyo7RYwYB#PYSLhrJltJCeUNzOxDkAh5zTWVVCHHd4Q3#xkVK4qB1al" + + "43PElwUOgrXIcw$yBLuV1uzNVLBSVK5C#YDGJtsjNZQ$lcHN3yeiRw4UmsDxOksJygwRLyf" + + "zIL$Ifat6avzrknMZdbZ5TR7$tjcvYTwzzf0NQDv8rpHxGlU1qNlTQJdk8Tf3PDnx5ly32o" + + "bcikirjDzMVlzSEQUZJstvRx9xon#vzcvMiAys#oIF4z8LbXrvhxRJCZmtMOqsyV$5IhiFV" + + "Ml4bHxaUkVcV$J$4gdvRMxRddiUKFJShRPIhOyy0s#hw5y8wrMSRjKxvehijPWvLk9MYtvI" + + "AsSyWTh3TBorChnnbeRQssiTRNNcgGfCakO#RssWAQSzs0cuUUvgpOVAgKfPnxK$vyIsOKN" + + "eolyVeBUuip$8gfBJuhQLKn62$SjQDUB2gwrQesY7Jtj3NecxWt8hcPlK6ljGPwslZUhj6e" + + "jTErYhfUcg3fbxlUKyJh$bzZlTfr$o8E2LgXtB1VmeEYwNWp#v16mUl3$iH4GjKHXhsLRwB" + + "Ut9jj2eqhmdrpyeV$ajuIMNSKzAPE$poi2VIdUhoNfVsRLtYZFymFw$e9#buhC#N#c#3yfQ" + + "urcpaZ$DoJQJpOjNcFGpiH$a5RbpGurgX7eQs9tQ0fe3AyVeXWnu$McwuSenc8qSkfeXJ79" + + "ZgLZ33HEYhOw7MFCEtDRNSI$WtCk$QjWFez9kFyi1AuLNFuNnYAkGw9jjpHLnCFwNbErRdi" + + "JsuVuoijOSpZ$DvUPbvB#NSsCdubAhxx2eUTO#YRx9kiTLfnDWIojtVGiZCisJPEev6$hmo" + + "iqigT2rrUQVsgiIBGwerCIGNe4KUAL#2f5PAqgZ8Yle2r4vWgQRTvTqlLpmdmWpYARqnMqF" + + "JB49Oas3tSmtVH$YYTffBjDiR6cdzn9dM4Cnc2iNPVc5pZkpEiN#SQFGQDMXYNYHDqFfoJ#" + + "Blbyz8D2Sp7VGTcOKyqLUV3lwqLvQTxHAPxBUReW#c#N5IdbglFF62WtFA8rgtcruyhO9rR" + + "ZyAAVWrZ5I6FwgWlURqykruYZtd7e$KhmV0tFZ8auCFOLZjJz2k4mwwovAaqRRPXrYbWBYn" + + "kPjYmmhZ9PCR5KMJDoRMl6np3BKWcrpj0$nwQyTu7$dtXYx6uzvZVxhgFMkBdIorg7sHRBr" + + "QfBg9q6bPWKGoT4EN1Lhgx#CUr5orAH0SDKjddwlg4CSjhcET$bhSsXIcdjnI2hLsdexblq" + + "Fg#tPPVu7PLGjsePwIwiCMxjoLAg$MgeCVZMbZGMsGFfNiHfFPCiHRB6V$AqfczU3p8pJ#$" + + "Gq$MLNsLWAUNfUJHgsK0ZoqvIig6bu9F6KYkbKPVjQzq$gJHMAARLBACrfepOtknrIaPPGN" + + "bSBUt#ytaSOwJ#ZFUGvI#is$ONTNLR7VjsgJnbXkgjSLd$lCTj3lzvhpBHTwhJldNZxvVAB" + + "RzbRC6SCAtKPmvYgrTbefsgPS4hi9XMx21rEqv9RCNvGRqN5p$Z5JLxn6UyvtAlDLWYlDQe" + + "pf5GtpwbVkzfPklqyH#jWtV31Uh8yS6fg4D08kyy4szBKZqqFkplE8DMrDARE6BU5BVqr4J" + + "ld1GTDPWbcl9tdFEY#e9lAgUgKPDZH$NqnbbS3tzJgTj0rnINXACcQ6Ljtjs0RSsfiTadiW" + + "B0hfEXRryzTlFksFwGxpNA5liDS7K9Sqkrcbka3ESMw$hxlDItnvaP9y#rhJWlEaUAI#CU6" + + "nsJulcL6vFvvvVSUd3#W$Ku8g6M4kUnujkICsfoLhd2cZbjDMikxfwYdjS2hxFk7uL#TtvE" + + "#RDO#joetubBylbTtdlxqHr7svHsbIVxLNnN7Q2gBUQQHOUZU$vySsfUTA8gUFOl#EPGpGW" + + "vgAt$FCjvzizwof4zeKRFAhHw30w$EKIDmwJvvZ3fNtyhhLwi0JAzRa17Nvwxoh3UJS4Ldl" + + "a7mx9mFyZFYatBVIen5g$X#yBqRUDr$Dq6rQAm3bF$riTQxvJ1KqE9xKtLAcMebMknjAfQr" + + "Zojt6AjbVyXqNv#rUmRubgYFdCMQpatrChy4gKrGDOxz5ls1lCjPEJVz7AbjDQer0G#JxBG" + + "zeQazeRWkyC9FAeAI2LhX#Ia60ukPpthLPJKgaGRr5HhpqabuEWTpXJw6aXB9LXzKcWNpat" + + "4WLgZtzfE3iPZtjRQskronVW8VS#Jrbh#dYTrRkJzjzsEjlfx2sf7NqkgFAMrlNDMWiHs95" + + "$59kpIqzkHz6rzssJxy7M5UKfoalM41bBjw#KmrVO1On$sgQ2VbHwhvOpOxbEshP5DI8tO9" + + "w7bEVxMExHah0rv$25SItDRZfJ8ADVhJg5HE4b6dp79qt8P#uJZ2$DeT7o5#vISUsfXop6F" + + "KXlDawAr6iqbLecWNckbd1Ix7wvR7Y#LvmvwOyxH2SzY5KZ9esjUnFgzhTwFzRYTWjwd7Zy" + + "tTcSWwFtIUhpH1rPTJnUTacTihroAFQknDnJLqsaf2VDmOyiRMrvKIkxdZxOS#xZuTqgqsk" + + "dxKGLQfUvgqhK8fqJkC4uM$HhiJ6VsEYAqU$hz86c#QodYha7mVNN1Nuz8wvkUVBhrlUVWR" + + "XRiteJxvWyWZQsm#M9j8xxTriwdM8YTGssjdM8PnSnRRio#DumfQ$6zk5hzR1sjplfAGKhp" + + "xJFQRprNYvWUNzesawMrGuoFngYqJBnkiFV8AYMACVgnHsCalJRCZLuBIRqZJfAFIuSOqtD" + + "JTXmYSygnWZvzDyPfL$13XN2c2h77GKACdoF4nEiGxow4sqM8UTSWxMKX3kYF#6v2D87t7D" + + "XCgCy1GXpv0DWC72ZZ8UxjWBHNmE6pHtwCz7V1lqUTKy1z8QQr5cBl7uKugXFI7WNlXxJHG" + + "aoT8CICiU2dWwFEgKyAiSytGam6ZgON8TmBuVs4MEiN8JeyZF3bGdHyLOXcTm77yq9qUX3O" + + "K5UJzuLeTIBmduboGy5HTuSXGcnubH3jra7uCY7c$0rvXo6l2kKd8lu53c0xz2paFmBT$nH" + + "YIYleXym#QDkKCS0v4hALIBiHyLDm0DyKjB6ZX$INXDYt5iTyO3a7QPE4MFj87B13ym4e2z" + + "mEoY$UHOZEs#6u3ySnI8VyiSSZ$0FgkGNbRqSQufdr4VuQUR1PPhOG#tL3#42q2tesHBdE8" + + "uJe0njCwmFvFwF$lW9$GeZ#m7hulo0x2#LWc$tGrnkYROUr12RKAQ2loxf2hDiEUR13A#XS" + + "TnmEwEW4BEl21kl17zQ3JTVx3JhHxvsU1NyBEW#7RL3lVlyGOdtOiikEGkmFlGSZFWz#r0u" + + "oNROHOYxwTrvVy4sG1jtxxoJ4WE7GyQaG6rm8FS3V2MtSVodaTuSSoZG5bXOeC$Lt#CqRGi" + + "nw3V4Nq0ROhiMBGfJ1tygwuYZ7iGyEO2ax0iTVSS3sPS3PiZcE2XpeevPePqlOl#LHEEx1W" + + "Nve2NkqGjkxd0SEFpZg9t3Oh1LyOG9yQzOAu9q7Msugn5vtm9ReuxdGstfh8QQVByI2xs1R" + + "r74q$F4mjBqry1yD#y#47n#6#gR3xls0k$$TGjH0zZ3uR3$umGBuzJpq#G9WFlP#X366vW5" + + "RQ$JBl5Dnt8e3FZSFzI#0paxm$sR0rWPw3uTT#mo27ur2V5iSQFFHyEMrhq3uKd3KEUWqbF" + + "qVP26tu6PWFWx7Vn5#2EtPGuY169CBteFFLCCNCJRROAmS3drTpa1$GhOpwkq2t#lmENpaR" + + "UIZFxkW$PtGXZRmopOOgnrHp#5d2z4MykDWymd0dO5yvuK8enrDqNUxeWtheE$d8xpET73q" + + "xS2de0lo7U4BHyDcXnsDut64uMFpuTT7j4SOiatHthRlG1POckq5dyLOwG1$sl1Qj0LpmOR" + + "VWiD$sws7SXZRyz5s1pvSynU4WNN#CyY3RVRU0ENWnvCw2B4HfhYDu4iRmJy6tWOT9o0CNz" + + "uASy9ysACz#4QVOBw0Jnps0VXC#1viCnisdmrRpiISr1S#i35yQZRcnDdKBy0r67DILvexq" + + "UxD8TTr83ZykIl2cwEkhl3vhYWt43ur0dus6B8Z3iOOG9tJ83S6ldpqkP1P2nnpPeSo8RO1" + + "rZ7JO7FCXGxwgTD9Q0zilZ7gs0Xzrknf8Qh$Zlv6kxR1$DQXCyAOizUczW3l2BI$QqzmjAa" + + "JxDONPRR5tDOP6BP5kmTW$kgy63BeyoCmPhVz21pp#SXXu9F1CPSUWRdW2FJh4S0s4lvq1F" + + "nu$yV0CSzCHRyUyI7QX3xjXBxi1D$Q3k4kMu3VY$v5Euu0rhuOQqTIcu5lCFfrC7GCUWxol" + + "z3Fqt701pR77D0LyytcmD0L$heE#hTJLeXQOEqCeLgCatxmtqxmXL7OozJ0puO3GnS71p3N" + + "md#6m0yEWLyEWt6tmXZl2FnTCDSDmTWQ0fyP0j$T7l4#Sx5cOKrnuID3eNij#ERG9JWm7sm" + + "1tzi2OsCBpBbheSrReCrRed#tnFoz9TQHOHZd6M3D0FjQqBiMncuJb6a27$PWmtLXqwuOBr" + + "rf7A1VHc6jwByXsek#x01Tmz0$mu3xQ8plSgmbmz7lmyUZBEGwe0sTeMV49U2OVmv1$GV31" + + "btGPrtWnzFHhYwO$mQYBUNmztBquNJewuevOSIlYAEERJ66kg9zss9ybSEEMsEk78NvfolM" + + "fQ7mhN9W6GcS5V2FhJ7dRG#$AaUVb0DJ1TRmaV3fYlt1CSTLeD#sW$qhrmQ73rHY36w7$gp" + + "4#1e5crIvuEZZAgoLsoDSTHCuvhmgj7DxZFjkiCKEi46tgy7H7ztWkpjW3UsEUMz7Z8$kQE" + + "UEc4ExOnplYB7U0#l1QFHB3#0QZR7P0tsz4yPXJ$JHJi3O4sDj9$XsJupBZT2t7J1EA#3Jp" + + "T7#vfYZcsESheEzoJeBqCTeOn$CjUjWdLWNwqC5iAyB6ov4kKx8NtW3R4bp2$fn8ThJ5NDd" + + "LzYi2ThT5HYxeewAwr46yVMmTbJ0Dol89XXJMy6#vKqHXa$Km4zdermVZD5Ey8Mjg1$GNxE" + + "nhin6U1lWA8VFpFyPyotiE0TZPWx6unYitJDfJa3$Lc1DdmDVcaDp4#GwOiuO3b#jmB4UxB" + + "OUTAqF#J7mqGhux1ZidpQf4M9ds6iJ#C7Em5u133jZdQp06Do4y0Dd1U9ZCTUl2vyQYtco0" + + "dF5Bct1uLkROZshHfdAZN1WNEu2#yt1EhCBycPYBTuKnpYiOvl2TyPXpzIBR82zr3ZCSxqm" + + "5hV7dD4HQypwcEi5zdfzK6yb#c5zbD#W1tmBut03wDWURQl46Dq0SsuBp14T8LEEyRuknd8" + + "bi7J26EYC$XcFVfo1kME7xI43ss#5UROSyfKO7orWbnPlmYPOQsR0xXFHhiejWGFzlLb7pE" + + "l0FWdrzeFk3j0x4#leRi1U2Vlk1kmryBSQ#5HxwDuA$TY5wiPOAeDlbs7kdG7P7R1$sn7Ze" + + "mosAuSFjkmD6wAESlHB9MpV4hPlYN5T3h#jn9vuF7nz1ifEQ883yGaOknFXUwsWgnNykXNM" + + "oDOO8vMOIoR23ZCm5dV4k6gDFKqb$AyzU7liGIlXanjZBx4ZvjJM60CRNu1nZxbp9lpy4DJ" + + "T4MDe9kRkRNR6c40$bMCTwmYVcuNrOH7cX$MmDol76Ao1pVgXJtT5VrVIN4a7zZ6Z5q4UPN" + + "T3lot2#bY9FjuTjkxu7xGFO#f8B5gLwCV#M2Fxxuar1Vk9IinlbRG7XTzLOZuu4lDhCuoHO" + + "r579Np$IDYd5UQUEMZ3iJGVO0uw4ctRy4g4KT#HQ5Cx#FhX63$hmzxbuFkZpwO3sqPaNvhR" + + "qAQfc1lcOlyt2BQfn1nnACRAeTZ7x8DsJiQSsWbhpsJCBOlGlgvepsJqVrUCkKgi7vMO0nT" + + "X3fsC#R0TT5J2tolHXuimPqr1dvJ3NohHHyUWNLEsmW4$dGAx7eFzmHJOsGMkIimDbTZZ70" + + "CRxBiPz7o6EDQ0IlJ5CV2zVN7TKuvhaKfg8$hZ68pnVL7lCPY7Ab7dlbXpsyDFoj6cGz7#$" + + "gY$FyRlpaWV3l#VYFLYBCRwQCmpi#3ZvR1v9UQwSkpBAu7XGFZNhhW#gFmVFUeBlUXxR2l4" + + "DDH$87ou4$fj9ynz5V2hAeoX0p5UTq9xZg7n3hq7mdyE0iw3u6Fbc6kgqBOgsF0WxCCFGfq" + + "33i7wWJ5sCAulXi57ks8CxmwRx07xT0N#SinzLLW7Aj4tnm3x7f2fmdYgnbonwp8XzgHwuM" + + "Ux0lUUyE5op4jLM4#geFCOh8zxOmyx4tkGMS2q6Fqz5$FI9AGTIjSnc9SyhFaLaAt2Vg0AO" + + "tCnzI$MztBuPHNcW2hOSp7gdq$rO4yy7Vrv1Dgr63Yhu2kJxiH#7FkltR0k7Gfx70ox7mhV" + + "FnHzNWLVtGtNCuTYJHa8crRX6gSATH#C#V4mjA4DzhAT8RiR#dW6vfuDqDzLb8RvfYbyg0r" + + "iE13xXK5espQeTslCCrjZhxKrribjq5UxmwwxOwmCeZPZ35HXh4o7tsv6OOo13jX7L64ks1" + + "rhr6Pepq2qhmzikmtMYCveuq2qgGPxhogCZIhe7O7rivok2s77mLYZgx0NBCVusGFNJhrXe" + + "ps0jGhzrGRjQOlnYUQ9MPYZsg8lPw6kji3P1tl53J4lxebhdTxOE#w9ERSAOtT3#FnU62#z" + + "4TyBOwyAQqOxrByNna0r#cPlZDzPgByTZhqnPrJZUh42SryLshSO#xSgp0jLM8ThuJzR0Cz" + + "EcBEheAi6$LSBlwv1NRLOZwk0jmfpVMTS1tR2d5YBQy4g#EeOpAjLcF$6m8UgC5QtnRpNvM" + + "JO03ORWF6pC#RL2bmZLC4lHcAVi3DqLc7yjyCuwGF$tnaw#W3JM8px2imzLR3V8UYRiPXBE" + + "i4MO#7BHwATLR1$9$JRBXWJXs3zsmNhUnVuOGlQUs0lK8DvTPT$OmnYl1#EiLA1$2gCwIhO" + + "eJFs9OT3pn6uBX#7$TP0#FvWp3aLq3SN$J44xHw2w$mApDr3CCzNOAxO2jSyEq77MAJrmNW" + + "v17RjZx5#6FPC5UI3MBkhw3u6shqOzGo4dor6FnqBFwz2NrTX$Hw9VL05zdOLc5ScmYxTuC" + + "l7mh#xOLmTYxPNORxO3dht0gPZCIOgNiVuHzee#DPUMDy7O6xeXdxfXl7L3NtS3NtIZVPKi" + + "5Kth3K2SqGtsj#WxWxmhU7Okqz4tRlkZV63ENCIrlmgZCjsm380yqqt#5Gts6ytZBrkg7y0" + + "zaExOJnqmxo$6#QJRi2uEwxDkq7lxfYNks7ks8FgnbhQ3NDnjmFKFQ9PcdVOLN5n6N4LTkO" + + "glitw9at5tKNHUEPDEwxIrXga#JBDVrEyoHwXpC1V51$U8Knhyg3YdHRgklfeV6XRHkiGj5" + + "#$nYfpPhp#OWxC7mjpquRhUhtn6WTyg#bxsWxFAzwiHqpFwz5uCrmJDVqucZRWvcYyUJV5H" + + "$JGzM1EQBwZ2bUF3ENs$YeCznaJXhsxj1xCONlEqRfEKdmTZCjzfiVQzRRY6UnRE#yNpLlh" + + "GYlyIpHlnAUAhqVtezuCqvjYBxp#PRQiIb$$xNXQhio1PM5uWvEIPJRuif2UbJsm$tj8yMs" + + "tLhpLOCtdALxjA3vWG5Yc5QuxMZsYywyAqxUzIl6zzzDoc4jRqtN#S1LliaBnrjMATzonC3" + + "w1TQZrbM6yyzMAjrbFyR5BSylqlpSQtyhgKqUNxuHntsR7gDo6bdyrtpGCjuduJxHCc$Uiy" + + "AkATsYgU9TDTBfKl1tceywO5zjYljmMUzosDIfzv5xvRT3s7OslfUQzSsKsnFwrmxfXlDqU" + + "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"); static final Action RETURN2 = new Action() { public Symbol reduce(Symbol[] _symbols, int offset) { @@ -1044,12 +1036,26 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b); } }, - new Action() { // [39] structure_tail = error + new Action() { // [39] structure_tail = SEMISEMI cppo_directive.a structure_tail.b + public Symbol reduce(Symbol[] _symbols, int offset) { + final Symbol a = _symbols[offset + 2]; + final Symbol b = _symbols[offset + 3]; + return Def.root(a,b); + } + }, + new Action() { // [40] structure_tail = cppo_directive.a structure_tail.b + public Symbol reduce(Symbol[] _symbols, int offset) { + final Symbol a = _symbols[offset + 1]; + final Symbol b = _symbols[offset + 2]; + return Def.root(a,b); + } + }, + new Action() { // [41] structure_tail = error public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [40] structure_item = LET.l rec_flag.r let_bindings.a + new Action() { // [42] structure_item = LET.l rec_flag.r let_bindings.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol l = _symbols[offset + 1]; final Symbol r = _symbols[offset + 2]; @@ -1067,7 +1073,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return a; } }, - new Action() { // [41] structure_item = EXTERNAL val_ident.i COLON core_type.a EQUAL primitive_declaration.b + new Action() { // [43] structure_item = EXTERNAL val_ident.i COLON core_type.a EQUAL primitive_declaration.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol i = _symbols[offset + 2]; final Symbol a = _symbols[offset + 4]; @@ -1082,13 +1088,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [42] structure_item = TYPE type_declarations.t + new Action() { // [44] structure_item = TYPE type_declarations.t public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol t = _symbols[offset + 2]; return t; } }, - new Action() { // [43] structure_item = EXCEPTION UIDENT.id constructor_arguments.a + new Action() { // [45] structure_item = EXCEPTION UIDENT.id constructor_arguments.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 2]; final Symbol a = _symbols[offset + 3]; @@ -1100,7 +1106,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [44] structure_item = EXCEPTION UIDENT.id EQUAL constr_longident.a + new Action() { // [46] structure_item = EXCEPTION UIDENT.id EQUAL constr_longident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 2]; final Symbol a = _symbols[offset + 4]; @@ -1112,7 +1118,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [45] structure_item = MODULE UIDENT.id module_binding.a + new Action() { // [47] structure_item = MODULE UIDENT.id module_binding.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 2]; final Symbol a = _symbols[offset + 3]; @@ -1128,13 +1134,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [46] structure_item = MODULE REC module_rec_bindings.a + new Action() { // [48] structure_item = MODULE REC module_rec_bindings.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 3]; return a; } }, - new Action() { // [47] structure_item = MODULE TYPE ident.id EQUAL module_type.a + new Action() { // [49] structure_item = MODULE TYPE ident.id EQUAL module_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 3]; final Symbol a = _symbols[offset + 5]; @@ -1147,7 +1153,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [48] structure_item = OPEN mod_longident.id + new Action() { // [50] structure_item = OPEN mod_longident.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 2]; @@ -1157,19 +1163,19 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [49] structure_item = CLASS class_declarations.a + new Action() { // [51] structure_item = CLASS class_declarations.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [50] structure_item = CLASS TYPE class_type_declarations.a + new Action() { // [52] structure_item = CLASS TYPE class_type_declarations.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 3]; return a; } }, - new Action() { // [51] structure_item = INCLUDE module_expr.id + new Action() { // [53] structure_item = INCLUDE module_expr.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 2]; @@ -1182,33 +1188,33 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [52] module_binding = EQUAL module_expr.a + new Action() { // [54] module_binding = EQUAL module_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [53] module_binding = COLON module_type.a EQUAL module_expr.b + new Action() { // [55] module_binding = COLON module_type.a EQUAL module_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [54] module_binding = LPAREN UIDENT COLON module_type.a RPAREN module_binding.b + new Action() { // [56] module_binding = LPAREN UIDENT COLON module_type.a RPAREN module_binding.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 4]; final Symbol b = _symbols[offset + 6]; return Def.root(a,b); } }, - new Action() { // [55] module_rec_bindings = module_rec_binding.a + new Action() { // [57] module_rec_bindings = module_rec_binding.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [56] module_rec_bindings = module_rec_bindings.a AND module_rec_binding.b + new Action() { // [58] module_rec_bindings = module_rec_bindings.a AND module_rec_binding.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -1218,7 +1224,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b); } }, - new Action() { // [57] module_rec_binding = UIDENT.id COLON module_type.a EQUAL module_expr.b + new Action() { // [59] module_rec_binding = UIDENT.id COLON module_type.a EQUAL module_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; final Symbol a = _symbols[offset + 3]; @@ -1232,13 +1238,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [58] module_type = mty_longident.id + new Action() { // [60] module_type = mty_longident.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return id; } }, - new Action() { // [59] module_type = SIG.s signature.a END + new Action() { // [61] module_type = SIG.s signature.a END public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol s = _symbols[offset + 1]; final Symbol a = _symbols[offset + 2]; @@ -1250,12 +1256,12 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [60] module_type = SIG signature error + new Action() { // [62] module_type = SIG signature error public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [61] module_type = FUNCTOR LPAREN UIDENT.id COLON module_type.a RPAREN MINUSGREATER module_type.b + new Action() { // [63] module_type = FUNCTOR LPAREN UIDENT.id COLON module_type.a RPAREN MINUSGREATER module_type.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 3]; final Symbol a = _symbols[offset + 5]; @@ -1269,50 +1275,50 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [62] module_type = module_type.a WITH with_constraints.b + new Action() { // [64] module_type = module_type.a WITH with_constraints.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [63] module_type = MODULE TYPE OF module_expr.a + new Action() { // [65] module_type = MODULE TYPE OF module_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 4]; return a; } }, - new Action() { // [64] module_type = LPAREN module_type.a RPAREN + new Action() { // [66] module_type = LPAREN module_type.a RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [65] module_type = LPAREN module_type error + new Action() { // [67] module_type = LPAREN module_type error public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [66] signature = + new Action() { // [68] signature = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [67] signature = signature.a signature_item.b + new Action() { // [69] signature = signature.a signature_item.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [68] signature = signature.a signature_item.b SEMISEMI + new Action() { // [70] signature = signature.a signature_item.b SEMISEMI public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [69] signature_item = VAL.v val_ident.id COLON core_type.a + new Action() { // [71] signature_item = VAL.v val_ident.id COLON core_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol v = _symbols[offset + 1]; final Symbol id = _symbols[offset + 2]; @@ -1330,7 +1336,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [70] signature_item = EXTERNAL.e val_ident.id COLON core_type.a EQUAL primitive_declaration.b + new Action() { // [72] signature_item = EXTERNAL.e val_ident.id COLON core_type.a EQUAL primitive_declaration.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol e = _symbols[offset + 1]; final Symbol id = _symbols[offset + 2]; @@ -1347,7 +1353,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [71] signature_item = TYPE.t type_declarations.a + new Action() { // [73] signature_item = TYPE.t type_declarations.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol t = _symbols[offset + 1]; final Symbol a = _symbols[offset + 2]; @@ -1359,7 +1365,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return a; } }, - new Action() { // [72] signature_item = EXCEPTION.e UIDENT.id constructor_arguments.a + new Action() { // [74] signature_item = EXCEPTION.e UIDENT.id constructor_arguments.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol e = _symbols[offset + 1]; final Symbol id = _symbols[offset + 2]; @@ -1373,7 +1379,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [73] signature_item = MODULE.m UIDENT.id module_declaration.a + new Action() { // [75] signature_item = MODULE.m UIDENT.id module_declaration.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; final Symbol id = _symbols[offset + 2]; @@ -1387,7 +1393,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [74] signature_item = MODULE.m REC module_rec_declarations.a + new Action() { // [76] signature_item = MODULE.m REC module_rec_declarations.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; final Symbol a = _symbols[offset + 3]; @@ -1399,7 +1405,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return a; } }, - new Action() { // [75] signature_item = MODULE.m TYPE ident.id + new Action() { // [77] signature_item = MODULE.m TYPE ident.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; final Symbol id = _symbols[offset + 3]; @@ -1411,7 +1417,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [76] signature_item = MODULE.m TYPE ident.id EQUAL module_type.a + new Action() { // [78] signature_item = MODULE.m TYPE ident.id EQUAL module_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; final Symbol id = _symbols[offset + 3]; @@ -1426,7 +1432,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [77] signature_item = OPEN.o mod_longident.id + new Action() { // [79] signature_item = OPEN.o mod_longident.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol o = _symbols[offset + 1]; final Symbol id = _symbols[offset + 2]; @@ -1438,7 +1444,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [78] signature_item = INCLUDE.i module_type.id + new Action() { // [80] signature_item = INCLUDE.i module_type.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol i = _symbols[offset + 1]; final Symbol id = _symbols[offset + 2]; @@ -1453,7 +1459,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [79] signature_item = CLASS.c class_descriptions.a + new Action() { // [81] signature_item = CLASS.c class_descriptions.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol c = _symbols[offset + 1]; final Symbol a = _symbols[offset + 2]; @@ -1465,7 +1471,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return a; } }, - new Action() { // [80] signature_item = CLASS.c TYPE class_type_declarations.a + new Action() { // [82] signature_item = CLASS.c TYPE class_type_declarations.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol c = _symbols[offset + 1]; final Symbol a = _symbols[offset + 3]; @@ -1477,26 +1483,26 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return a; } }, - new Action() { // [81] module_declaration = COLON module_type.a + new Action() { // [83] module_declaration = COLON module_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [82] module_declaration = LPAREN UIDENT COLON module_type.a RPAREN module_declaration.b + new Action() { // [84] module_declaration = LPAREN UIDENT COLON module_type.a RPAREN module_declaration.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 4]; final Symbol b = _symbols[offset + 6]; return Def.root(a,b); } }, - new Action() { // [83] module_rec_declarations = module_rec_declaration.a + new Action() { // [85] module_rec_declarations = module_rec_declaration.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [84] module_rec_declarations = module_rec_declarations.a AND.n module_rec_declaration.b + new Action() { // [86] module_rec_declarations = module_rec_declarations.a AND.n module_rec_declaration.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol n = _symbols[offset + 2]; @@ -1508,7 +1514,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b); } }, - new Action() { // [85] module_rec_declaration = UIDENT.id COLON module_type.a + new Action() { // [87] module_rec_declaration = UIDENT.id COLON module_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; final Symbol a = _symbols[offset + 3]; @@ -1520,7 +1526,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [86] class_declarations = class_declarations.a AND class_declaration.b + new Action() { // [88] class_declarations = class_declarations.a AND class_declaration.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -1530,13 +1536,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b); } }, - new Action() { // [87] class_declarations = class_declaration.a + new Action() { // [89] class_declarations = class_declaration.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [88] class_declaration = virtual_flag class_type_parameters.a LIDENT.id class_fun_binding.b + new Action() { // [90] class_declaration = virtual_flag class_type_parameters.a LIDENT.id class_fun_binding.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol id = _symbols[offset + 3]; @@ -1550,71 +1556,71 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [89] class_fun_binding = EQUAL class_expr.a + new Action() { // [91] class_fun_binding = EQUAL class_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [90] class_fun_binding = COLON class_type.a EQUAL class_expr.b + new Action() { // [92] class_fun_binding = COLON class_type.a EQUAL class_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [91] class_fun_binding = labeled_simple_pattern.a class_fun_binding.b + new Action() { // [93] class_fun_binding = labeled_simple_pattern.a class_fun_binding.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [92] class_type_parameters = + new Action() { // [94] class_type_parameters = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [93] class_type_parameters = LBRACKET type_parameter_list.a RBRACKET + new Action() { // [95] class_type_parameters = LBRACKET type_parameter_list.a RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [94] class_fun_def = labeled_simple_pattern.a MINUSGREATER class_expr.b + new Action() { // [96] class_fun_def = labeled_simple_pattern.a MINUSGREATER class_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [95] class_fun_def = labeled_simple_pattern.a class_fun_def.b + new Action() { // [97] class_fun_def = labeled_simple_pattern.a class_fun_def.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [96] class_expr = class_simple_expr.a + new Action() { // [98] class_expr = class_simple_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [97] class_expr = FUN class_fun_def.a + new Action() { // [99] class_expr = FUN class_fun_def.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [98] class_expr = class_simple_expr.a simple_labeled_expr_list.b + new Action() { // [100] class_expr = class_simple_expr.a simple_labeled_expr_list.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [99] class_expr = LET rec_flag.r let_bindings.a IN class_expr.b + new Action() { // [101] class_expr = LET rec_flag.r let_bindings.a IN class_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol r = _symbols[offset + 2]; final Symbol a = _symbols[offset + 3]; @@ -1646,20 +1652,20 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b); } }, - new Action() { // [100] class_simple_expr = LBRACKET core_type_comma_list.a RBRACKET class_longident.b + new Action() { // [102] class_simple_expr = LBRACKET core_type_comma_list.a RBRACKET class_longident.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [101] class_simple_expr = class_longident.a + new Action() { // [103] class_simple_expr = class_longident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [102] class_simple_expr = OBJECT.o class_structure.a END + new Action() { // [104] class_simple_expr = OBJECT.o class_structure.a END public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol o = _symbols[offset + 1]; final Symbol a = _symbols[offset + 2]; @@ -1671,65 +1677,65 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [103] class_simple_expr = OBJECT class_structure error + new Action() { // [105] class_simple_expr = OBJECT class_structure error public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [104] class_simple_expr = LPAREN class_expr.a COLON class_type.b RPAREN + new Action() { // [106] class_simple_expr = LPAREN class_expr.a COLON class_type.b RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [105] class_simple_expr = LPAREN class_expr COLON class_type error + new Action() { // [107] class_simple_expr = LPAREN class_expr COLON class_type error public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [106] class_simple_expr = LPAREN class_expr.a RPAREN + new Action() { // [108] class_simple_expr = LPAREN class_expr.a RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [107] class_simple_expr = LPAREN class_expr error + new Action() { // [109] class_simple_expr = LPAREN class_expr error public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [108] class_structure = class_self_pattern.a class_fields.b + new Action() { // [110] class_structure = class_self_pattern.a class_fields.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [109] class_self_pattern = LPAREN pattern.a RPAREN + new Action() { // [111] class_self_pattern = LPAREN pattern.a RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [110] class_self_pattern = LPAREN pattern.a COLON core_type.b RPAREN + new Action() { // [112] class_self_pattern = LPAREN pattern.a COLON core_type.b RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [111] class_self_pattern = + new Action() { // [113] class_self_pattern = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [112] class_fields = + new Action() { // [114] class_fields = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [113] class_fields = class_fields.a INHERIT override_flag.b class_expr.c parent_binder.d + new Action() { // [115] class_fields = class_fields.a INHERIT override_flag.b class_expr.c parent_binder.d public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -1738,7 +1744,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b,c,d); } }, - new Action() { // [114] class_fields = class_fields.a VAL.v virtual_value.id + new Action() { // [116] class_fields = class_fields.a VAL.v virtual_value.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol v = _symbols[offset + 2]; @@ -1754,7 +1760,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,id); } }, - new Action() { // [115] class_fields = class_fields.a VAL.v value.id + new Action() { // [117] class_fields = class_fields.a VAL.v value.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol v = _symbols[offset + 2]; @@ -1770,21 +1776,21 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,id); } }, - new Action() { // [116] class_fields = class_fields.a virtual_method.b + new Action() { // [118] class_fields = class_fields.a virtual_method.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [117] class_fields = class_fields.a concrete_method.b + new Action() { // [119] class_fields = class_fields.a concrete_method.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [118] class_fields = class_fields.a CONSTRAINT.c constrain.b + new Action() { // [120] class_fields = class_fields.a CONSTRAINT.c constrain.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol c = _symbols[offset + 2]; @@ -1797,7 +1803,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a, def); } }, - new Action() { // [119] class_fields = class_fields.a INITIALIZER.i seq_expr.b + new Action() { // [121] class_fields = class_fields.a INITIALIZER.i seq_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol i = _symbols[offset + 2]; @@ -1811,19 +1817,19 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a, def); } }, - new Action() { // [120] parent_binder = AS LIDENT.id + new Action() { // [122] parent_binder = AS LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 2]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [121] parent_binder = + new Action() { // [123] parent_binder = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [122] virtual_value = override_flag.o MUTABLE.m VIRTUAL label.id COLON core_type.a + new Action() { // [124] virtual_value = override_flag.o MUTABLE.m VIRTUAL label.id COLON core_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol o = _symbols[offset + 1]; final Symbol m = _symbols[offset + 2]; @@ -1842,7 +1848,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [123] virtual_value = VIRTUAL.v mutable_flag.m label.id COLON core_type.a + new Action() { // [125] virtual_value = VIRTUAL.v mutable_flag.m label.id COLON core_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol v = _symbols[offset + 1]; final Symbol m = _symbols[offset + 2]; @@ -1860,7 +1866,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [124] value = override_flag.o mutable_flag.m label.id EQUAL seq_expr.a + new Action() { // [126] value = override_flag.o mutable_flag.m label.id EQUAL seq_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol o = _symbols[offset + 1]; final Symbol m = _symbols[offset + 2]; @@ -1880,7 +1886,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [125] value = override_flag.o mutable_flag.m label.id type_constraint.a EQUAL seq_expr.b + new Action() { // [127] value = override_flag.o mutable_flag.m label.id type_constraint.a EQUAL seq_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol o = _symbols[offset + 1]; final Symbol m = _symbols[offset + 2]; @@ -1902,7 +1908,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [126] virtual_method = METHOD.m override_flag.o PRIVATE VIRTUAL label.id COLON poly_type.a + new Action() { // [128] virtual_method = METHOD.m override_flag.o PRIVATE VIRTUAL label.id COLON poly_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; final Symbol o = _symbols[offset + 2]; @@ -1920,7 +1926,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [127] virtual_method = METHOD.m override_flag.o VIRTUAL private_flag.p label.id COLON poly_type.a + new Action() { // [129] virtual_method = METHOD.m override_flag.o VIRTUAL private_flag.p label.id COLON poly_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; final Symbol o = _symbols[offset + 2]; @@ -1939,7 +1945,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [128] concrete_method = METHOD.m override_flag.o private_flag.p label.id strict_binding.a + new Action() { // [130] concrete_method = METHOD.m override_flag.o private_flag.p label.id strict_binding.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; final Symbol o = _symbols[offset + 2]; @@ -1958,7 +1964,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [129] concrete_method = METHOD.m override_flag.o private_flag.p label.id COLON poly_type.a EQUAL seq_expr.b + new Action() { // [131] concrete_method = METHOD.m override_flag.o private_flag.p label.id COLON poly_type.a EQUAL seq_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; final Symbol o = _symbols[offset + 2]; @@ -1979,47 +1985,47 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [130] class_type = class_signature.s + new Action() { // [132] class_type = class_signature.s public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol s = _symbols[offset + 1]; return s; } }, - new Action() { // [131] class_type = QUESTION LIDENT COLON simple_core_type_or_tuple MINUSGREATER class_type.c + new Action() { // [133] class_type = QUESTION LIDENT COLON simple_core_type_or_tuple MINUSGREATER class_type.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol c = _symbols[offset + 6]; return c; } }, - new Action() { // [132] class_type = OPTLABEL simple_core_type_or_tuple MINUSGREATER class_type.c + new Action() { // [134] class_type = OPTLABEL simple_core_type_or_tuple MINUSGREATER class_type.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol c = _symbols[offset + 4]; return c; } }, - new Action() { // [133] class_type = LIDENT COLON simple_core_type_or_tuple MINUSGREATER class_type.c + new Action() { // [135] class_type = LIDENT COLON simple_core_type_or_tuple MINUSGREATER class_type.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol c = _symbols[offset + 5]; return c; } }, - new Action() { // [134] class_type = simple_core_type_or_tuple MINUSGREATER class_type.c + new Action() { // [136] class_type = simple_core_type_or_tuple MINUSGREATER class_type.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol c = _symbols[offset + 3]; return c; } }, - new Action() { // [135] class_signature = LBRACKET core_type_comma_list RBRACKET clty_longident + new Action() { // [137] class_signature = LBRACKET core_type_comma_list RBRACKET clty_longident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [136] class_signature = clty_longident + new Action() { // [138] class_signature = clty_longident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [137] class_signature = OBJECT.o class_sig_body.a END + new Action() { // [139] class_signature = OBJECT.o class_sig_body.a END public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol o = _symbols[offset + 1]; final Symbol a = _symbols[offset + 2]; @@ -2031,42 +2037,42 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [138] class_signature = OBJECT class_sig_body error + new Action() { // [140] class_signature = OBJECT class_sig_body error public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [139] class_sig_body = class_self_type.a class_sig_fields.b + new Action() { // [141] class_sig_body = class_self_type.a class_sig_fields.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [140] class_self_type = LPAREN core_type.a RPAREN + new Action() { // [142] class_self_type = LPAREN core_type.a RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return Def.root(a); } }, - new Action() { // [141] class_self_type = + new Action() { // [143] class_self_type = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [142] class_sig_fields = + new Action() { // [144] class_sig_fields = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [143] class_sig_fields = class_sig_fields.s INHERIT class_signature.a + new Action() { // [145] class_sig_fields = class_sig_fields.s INHERIT class_signature.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol s = _symbols[offset + 1]; final Symbol a = _symbols[offset + 3]; return Def.root(s,a); } }, - new Action() { // [144] class_sig_fields = class_sig_fields.s VAL.v value_type.a + new Action() { // [146] class_sig_fields = class_sig_fields.s VAL.v value_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol s = _symbols[offset + 1]; final Symbol v = _symbols[offset + 2]; @@ -2077,28 +2083,28 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(s,a); } }, - new Action() { // [145] class_sig_fields = class_sig_fields.s virtual_method_type.a + new Action() { // [147] class_sig_fields = class_sig_fields.s virtual_method_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol s = _symbols[offset + 1]; final Symbol a = _symbols[offset + 2]; return Def.root(s,a); } }, - new Action() { // [146] class_sig_fields = class_sig_fields.s method_type.a + new Action() { // [148] class_sig_fields = class_sig_fields.s method_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol s = _symbols[offset + 1]; final Symbol a = _symbols[offset + 2]; return Def.root(s,a); } }, - new Action() { // [147] class_sig_fields = class_sig_fields.s CONSTRAINT constrain.a + new Action() { // [149] class_sig_fields = class_sig_fields.s CONSTRAINT constrain.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol s = _symbols[offset + 1]; final Symbol a = _symbols[offset + 3]; return Def.root(s,a); } }, - new Action() { // [148] value_type = VIRTUAL mutable_flag.m label.id COLON core_type.a + new Action() { // [150] value_type = VIRTUAL mutable_flag.m label.id COLON core_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 2]; final Symbol id = _symbols[offset + 3]; @@ -2114,7 +2120,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [149] value_type = MUTABLE virtual_flag label.id COLON core_type.a + new Action() { // [151] value_type = MUTABLE virtual_flag label.id COLON core_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 3]; final Symbol a = _symbols[offset + 5]; @@ -2129,7 +2135,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [150] value_type = label.id COLON core_type.a + new Action() { // [152] value_type = label.id COLON core_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; final Symbol a = _symbols[offset + 3]; @@ -2143,7 +2149,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [151] method_type = METHOD.m private_flag label.id COLON poly_type.a + new Action() { // [153] method_type = METHOD.m private_flag label.id COLON poly_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; final Symbol id = _symbols[offset + 3]; @@ -2159,7 +2165,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [152] virtual_method_type = METHOD.m PRIVATE VIRTUAL label.id COLON poly_type.a + new Action() { // [154] virtual_method_type = METHOD.m PRIVATE VIRTUAL label.id COLON poly_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; final Symbol id = _symbols[offset + 4]; @@ -2175,7 +2181,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [153] virtual_method_type = METHOD.m VIRTUAL private_flag label.id COLON poly_type.a + new Action() { // [155] virtual_method_type = METHOD.m VIRTUAL private_flag label.id COLON poly_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; final Symbol id = _symbols[offset + 4]; @@ -2191,14 +2197,14 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [154] constrain = core_type.a EQUAL core_type.b + new Action() { // [156] constrain = core_type.a EQUAL core_type.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [155] class_descriptions = class_descriptions.a AND.n class_description.b + new Action() { // [157] class_descriptions = class_descriptions.a AND.n class_description.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol n = _symbols[offset + 2]; @@ -2210,13 +2216,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b); } }, - new Action() { // [156] class_descriptions = class_description.a + new Action() { // [158] class_descriptions = class_description.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [157] class_description = virtual_flag class_type_parameters LIDENT.id COLON class_type.a + new Action() { // [159] class_description = virtual_flag class_type_parameters LIDENT.id COLON class_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 3]; final Symbol a = _symbols[offset + 5]; @@ -2228,7 +2234,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [158] class_type_declarations = class_type_declarations.a AND.n class_type_declaration.b + new Action() { // [160] class_type_declarations = class_type_declarations.a AND.n class_type_declaration.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol n = _symbols[offset + 2]; @@ -2240,13 +2246,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b); } }, - new Action() { // [159] class_type_declarations = class_type_declaration.a + new Action() { // [161] class_type_declarations = class_type_declaration.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [160] class_type_declaration = virtual_flag class_type_parameters LIDENT.id EQUAL class_signature.a + new Action() { // [162] class_type_declaration = virtual_flag class_type_parameters LIDENT.id EQUAL class_signature.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 3]; final Symbol a = _symbols[offset + 5]; @@ -2258,39 +2264,39 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [161] seq_expr = expr.a + new Action() { // [163] seq_expr = expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [162] seq_expr = expr.a SEMI + new Action() { // [164] seq_expr = expr.a SEMI public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [163] seq_expr = expr.a SEMI seq_expr.b + new Action() { // [165] seq_expr = expr.a SEMI seq_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [164] labeled_simple_pattern = QUESTION LPAREN label_let_pattern.a opt_default.b RPAREN + new Action() { // [166] labeled_simple_pattern = QUESTION LPAREN label_let_pattern.a opt_default.b RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 3]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [165] labeled_simple_pattern = QUESTION label_var.a + new Action() { // [167] labeled_simple_pattern = QUESTION label_var.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [166] labeled_simple_pattern = OPTLABEL.id LPAREN let_pattern.a opt_default.b RPAREN + new Action() { // [168] labeled_simple_pattern = OPTLABEL.id LPAREN let_pattern.a opt_default.b RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; final Symbol a = _symbols[offset + 3]; @@ -2300,7 +2306,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(ident,a,b); } }, - new Action() { // [167] labeled_simple_pattern = OPTLABEL.id pattern_var.a + new Action() { // [169] labeled_simple_pattern = OPTLABEL.id pattern_var.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; final Symbol a = _symbols[offset + 2]; @@ -2309,19 +2315,19 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(ident,a); } }, - new Action() { // [168] labeled_simple_pattern = TILDE LPAREN label_let_pattern.a RPAREN + new Action() { // [170] labeled_simple_pattern = TILDE LPAREN label_let_pattern.a RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 3]; return a; } }, - new Action() { // [169] labeled_simple_pattern = TILDE label_var.a + new Action() { // [171] labeled_simple_pattern = TILDE label_var.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [170] labeled_simple_pattern = LABEL.id simple_pattern.a + new Action() { // [172] labeled_simple_pattern = LABEL.id simple_pattern.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; final Symbol a = _symbols[offset + 2]; @@ -2330,84 +2336,84 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(ident,a); } }, - new Action() { // [171] labeled_simple_pattern = simple_pattern.a + new Action() { // [173] labeled_simple_pattern = simple_pattern.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [172] pattern_var = LIDENT.id + new Action() { // [174] pattern_var = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [173] pattern_var = UNDERSCORE.id + new Action() { // [175] pattern_var = UNDERSCORE.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def("_", Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [174] opt_default = + new Action() { // [176] opt_default = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [175] opt_default = EQUAL seq_expr.a + new Action() { // [177] opt_default = EQUAL seq_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [176] label_let_pattern = label_var.a + new Action() { // [178] label_let_pattern = label_var.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [177] label_let_pattern = label_var.a COLON core_type.b + new Action() { // [179] label_let_pattern = label_var.a COLON core_type.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [178] label_var = LIDENT.id + new Action() { // [180] label_var = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [179] let_pattern = pattern.a + new Action() { // [181] let_pattern = pattern.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [180] let_pattern = pattern.a COLON core_type.b + new Action() { // [182] let_pattern = pattern.a COLON core_type.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [181] expr = simple_expr.a + new Action() { // [183] expr = simple_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [182] expr = simple_expr.a simple_labeled_expr_list.b + new Action() { // [184] expr = simple_expr.a simple_labeled_expr_list.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [183] expr = LET rec_flag.r let_bindings.a IN seq_expr.b + new Action() { // [185] expr = LET rec_flag.r let_bindings.a IN seq_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol r = _symbols[offset + 2]; final Symbol a = _symbols[offset + 3]; @@ -2439,7 +2445,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b); } }, - new Action() { // [184] expr = LET MODULE UIDENT.id module_binding.a IN seq_expr.b + new Action() { // [186] expr = LET MODULE UIDENT.id module_binding.a IN seq_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 3]; final Symbol a = _symbols[offset + 4]; @@ -2453,7 +2459,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [185] expr = LET OPEN mod_longident.id IN seq_expr.a + new Action() { // [187] expr = LET OPEN mod_longident.id IN seq_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 3]; final Symbol a = _symbols[offset + 5]; @@ -2469,14 +2475,14 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [186] expr = FUNCTION opt_bar.a match_cases.b + new Action() { // [188] expr = FUNCTION opt_bar.a match_cases.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [187] expr = FUN labeled_simple_pattern.a fun_def.b + new Action() { // [189] expr = FUN labeled_simple_pattern.a fun_def.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 3]; @@ -2515,7 +2521,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { } } }, - new Action() { // [188] expr = FUN LPAREN TYPE LIDENT.id RPAREN fun_def.a + new Action() { // [190] expr = FUN LPAREN TYPE LIDENT.id RPAREN fun_def.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 4]; final Symbol a = _symbols[offset + 6]; @@ -2528,7 +2534,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return root; } }, - new Action() { // [189] expr = MATCH seq_expr.a WITH opt_bar.b match_cases.c + new Action() { // [191] expr = MATCH seq_expr.a WITH opt_bar.b match_cases.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; @@ -2536,7 +2542,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b,c); } }, - new Action() { // [190] expr = TRY seq_expr.a WITH opt_bar.b match_cases.c + new Action() { // [192] expr = TRY seq_expr.a WITH opt_bar.b match_cases.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; @@ -2544,32 +2550,32 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b,c); } }, - new Action() { // [191] expr = TRY seq_expr WITH error + new Action() { // [193] expr = TRY seq_expr WITH error public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [192] expr = expr_comma_list.a + new Action() { // [194] expr = expr_comma_list.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [193] expr = constr_longident.a simple_expr.b + new Action() { // [195] expr = constr_longident.a simple_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [194] expr = name_tag.a simple_expr.b + new Action() { // [196] expr = name_tag.a simple_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [195] expr = IF seq_expr.a THEN expr.b ELSE expr.c + new Action() { // [197] expr = IF seq_expr.a THEN expr.b ELSE expr.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; @@ -2577,21 +2583,21 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b,c); } }, - new Action() { // [196] expr = IF seq_expr.a THEN expr.b + new Action() { // [198] expr = IF seq_expr.a THEN expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [197] expr = WHILE seq_expr.a DO seq_expr.b DONE + new Action() { // [199] expr = WHILE seq_expr.a DO seq_expr.b DONE public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [198] expr = FOR val_ident.ident EQUAL seq_expr.b direction_flag seq_expr.c DO seq_expr.d DONE + new Action() { // [200] expr = FOR val_ident.ident EQUAL seq_expr.b direction_flag seq_expr.c DO seq_expr.d DONE public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol ident = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; @@ -2607,159 +2613,159 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [199] expr = expr.a COLONCOLON expr.b + new Action() { // [201] expr = expr.a COLONCOLON expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [200] expr = LPAREN COLONCOLON RPAREN LPAREN expr.a COMMA expr.b RPAREN + new Action() { // [202] expr = LPAREN COLONCOLON RPAREN LPAREN expr.a COMMA expr.b RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 5]; final Symbol b = _symbols[offset + 7]; return Def.root(a,b); } }, - new Action() { // [201] expr = expr.a INFIXOP0 expr.b + new Action() { // [203] expr = expr.a INFIXOP0 expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [202] expr = expr.a INFIXOP1 expr.b + new Action() { // [204] expr = expr.a INFIXOP1 expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [203] expr = expr.a INFIXOP2 expr.b + new Action() { // [205] expr = expr.a INFIXOP2 expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [204] expr = expr.a INFIXOP3 expr.b + new Action() { // [206] expr = expr.a INFIXOP3 expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [205] expr = expr.a INFIXOP4 expr.b + new Action() { // [207] expr = expr.a INFIXOP4 expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [206] expr = expr.a PLUS expr.b + new Action() { // [208] expr = expr.a PLUS expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [207] expr = expr.a PLUSDOT expr.b + new Action() { // [209] expr = expr.a PLUSDOT expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [208] expr = expr.a MINUS expr.b + new Action() { // [210] expr = expr.a MINUS expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [209] expr = expr.a MINUSDOT expr.b + new Action() { // [211] expr = expr.a MINUSDOT expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [210] expr = expr.a STAR expr.b + new Action() { // [212] expr = expr.a STAR expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [211] expr = expr.a EQUAL expr.b + new Action() { // [213] expr = expr.a EQUAL expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [212] expr = expr.a LESS expr.b + new Action() { // [214] expr = expr.a LESS expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [213] expr = expr.a GREATER expr.b + new Action() { // [215] expr = expr.a GREATER expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [214] expr = expr.a OR expr.b + new Action() { // [216] expr = expr.a OR expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [215] expr = expr.a BARBAR expr.b + new Action() { // [217] expr = expr.a BARBAR expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [216] expr = expr.a AMPERSAND expr.b + new Action() { // [218] expr = expr.a AMPERSAND expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [217] expr = expr.a AMPERAMPER expr.b + new Action() { // [219] expr = expr.a AMPERAMPER expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [218] expr = expr.a COLONEQUAL expr.b + new Action() { // [220] expr = expr.a COLONEQUAL expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [219] expr = subtractive expr.a + new Action() { // [221] expr = subtractive expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [220] expr = additive expr.a + new Action() { // [222] expr = additive expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [221] expr = simple_expr.a DOT label_longident.b LESSMINUS expr.c + new Action() { // [223] expr = simple_expr.a DOT label_longident.b LESSMINUS expr.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -2767,7 +2773,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b,c); } }, - new Action() { // [222] expr = simple_expr.a DOT LPAREN seq_expr.b RPAREN LESSMINUS expr.c + new Action() { // [224] expr = simple_expr.a DOT LPAREN seq_expr.b RPAREN LESSMINUS expr.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 4]; @@ -2775,7 +2781,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b,c); } }, - new Action() { // [223] expr = simple_expr.a DOT LBRACKET seq_expr.b RBRACKET LESSMINUS expr.c + new Action() { // [225] expr = simple_expr.a DOT LBRACKET seq_expr.b RBRACKET LESSMINUS expr.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 4]; @@ -2783,7 +2789,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b,c); } }, - new Action() { // [224] expr = simple_expr.a DOT LBRACE expr.b RBRACE LESSMINUS expr.c + new Action() { // [226] expr = simple_expr.a DOT LBRACE expr.b RBRACE LESSMINUS expr.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 4]; @@ -2791,26 +2797,26 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b,c); } }, - new Action() { // [225] expr = label.a LESSMINUS expr.b + new Action() { // [227] expr = label.a LESSMINUS expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [226] expr = ASSERT simple_expr.a + new Action() { // [228] expr = ASSERT simple_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [227] expr = LAZY simple_expr.a + new Action() { // [229] expr = LAZY simple_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [228] expr = OBJECT.o class_structure.a END + new Action() { // [230] expr = OBJECT.o class_structure.a END public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol o = _symbols[offset + 1]; final Symbol a = _symbols[offset + 2]; @@ -2822,299 +2828,299 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [229] expr = OBJECT class_structure error + new Action() { // [231] expr = OBJECT class_structure error public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [230] simple_expr = val_longident.a + new Action() { // [232] simple_expr = val_longident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [231] simple_expr = constant.a + new Action() { // [233] simple_expr = constant.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [232] simple_expr = constr_longident.a + new Action() { // [234] simple_expr = constr_longident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [233] simple_expr = name_tag.a + new Action() { // [235] simple_expr = name_tag.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [234] simple_expr = LPAREN seq_expr.a RPAREN + new Action() { // [236] simple_expr = LPAREN seq_expr.a RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [235] simple_expr = LPAREN seq_expr.a error + new Action() { // [237] simple_expr = LPAREN seq_expr.a error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [236] simple_expr = BEGIN seq_expr.a END + new Action() { // [238] simple_expr = BEGIN seq_expr.a END public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [237] simple_expr = BEGIN END + new Action() { // [239] simple_expr = BEGIN END public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [238] simple_expr = BEGIN seq_expr.a error + new Action() { // [240] simple_expr = BEGIN seq_expr.a error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [239] simple_expr = LPAREN seq_expr.a type_constraint.b RPAREN + new Action() { // [241] simple_expr = LPAREN seq_expr.a type_constraint.b RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [240] simple_expr = simple_expr.a DOT label_longident.b + new Action() { // [242] simple_expr = simple_expr.a DOT label_longident.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [241] simple_expr = mod_longident.a DOT LPAREN seq_expr.b RPAREN + new Action() { // [243] simple_expr = mod_longident.a DOT LPAREN seq_expr.b RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [242] simple_expr = mod_longident.a DOT LPAREN seq_expr.b error + new Action() { // [244] simple_expr = mod_longident.a DOT LPAREN seq_expr.b error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [243] simple_expr = simple_expr.a DOT LPAREN seq_expr.b RPAREN + new Action() { // [245] simple_expr = simple_expr.a DOT LPAREN seq_expr.b RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [244] simple_expr = simple_expr.a DOT LPAREN seq_expr.b error + new Action() { // [246] simple_expr = simple_expr.a DOT LPAREN seq_expr.b error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [245] simple_expr = simple_expr.a DOT LBRACKET seq_expr.b RBRACKET + new Action() { // [247] simple_expr = simple_expr.a DOT LBRACKET seq_expr.b RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [246] simple_expr = simple_expr.a DOT LBRACKET seq_expr.b error + new Action() { // [248] simple_expr = simple_expr.a DOT LBRACKET seq_expr.b error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [247] simple_expr = simple_expr.a DOT LBRACE expr.b RBRACE + new Action() { // [249] simple_expr = simple_expr.a DOT LBRACE expr.b RBRACE public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [248] simple_expr = simple_expr.a DOT LBRACE expr_comma_list.b error + new Action() { // [250] simple_expr = simple_expr.a DOT LBRACE expr_comma_list.b error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [249] simple_expr = LBRACE record_expr.a RBRACE + new Action() { // [251] simple_expr = LBRACE record_expr.a RBRACE public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [250] simple_expr = LBRACE record_expr.a error + new Action() { // [252] simple_expr = LBRACE record_expr.a error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [251] simple_expr = LBRACKETBAR expr_semi_list.a opt_semi.b BARRBRACKET + new Action() { // [253] simple_expr = LBRACKETBAR expr_semi_list.a opt_semi.b BARRBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [252] simple_expr = LBRACKETBAR expr_semi_list.a opt_semi.b error + new Action() { // [254] simple_expr = LBRACKETBAR expr_semi_list.a opt_semi.b error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [253] simple_expr = LBRACKETBAR BARRBRACKET + new Action() { // [255] simple_expr = LBRACKETBAR BARRBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [254] simple_expr = LBRACKET expr_semi_list.a opt_semi.b RBRACKET + new Action() { // [256] simple_expr = LBRACKET expr_semi_list.a opt_semi.b RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [255] simple_expr = LBRACKET expr_semi_list.a opt_semi.b error + new Action() { // [257] simple_expr = LBRACKET expr_semi_list.a opt_semi.b error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [256] simple_expr = PREFIXOP simple_expr.a + new Action() { // [258] simple_expr = PREFIXOP simple_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [257] simple_expr = BANG simple_expr.a + new Action() { // [259] simple_expr = BANG simple_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [258] simple_expr = NEW class_longident.a + new Action() { // [260] simple_expr = NEW class_longident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [259] simple_expr = LBRACELESS field_expr_list.a opt_semi.b GREATERRBRACE + new Action() { // [261] simple_expr = LBRACELESS field_expr_list.a opt_semi.b GREATERRBRACE public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [260] simple_expr = LBRACELESS field_expr_list.a opt_semi.b error + new Action() { // [262] simple_expr = LBRACELESS field_expr_list.a opt_semi.b error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [261] simple_expr = LBRACELESS GREATERRBRACE + new Action() { // [263] simple_expr = LBRACELESS GREATERRBRACE public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [262] simple_expr = simple_expr.a SHARP label.b + new Action() { // [264] simple_expr = simple_expr.a SHARP label.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [263] simple_expr = LPAREN MODULE module_expr.a COLON package_type.b RPAREN + new Action() { // [265] simple_expr = LPAREN MODULE module_expr.a COLON package_type.b RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 3]; final Symbol b = _symbols[offset + 5]; return Def.root(a,b); } }, - new Action() { // [264] simple_expr = LPAREN MODULE module_expr.a COLON error + new Action() { // [266] simple_expr = LPAREN MODULE module_expr.a COLON error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 3]; return a; } }, - new Action() { // [265] simple_labeled_expr_list = labeled_simple_expr.a + new Action() { // [267] simple_labeled_expr_list = labeled_simple_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [266] simple_labeled_expr_list = simple_labeled_expr_list.a labeled_simple_expr.b + new Action() { // [268] simple_labeled_expr_list = simple_labeled_expr_list.a labeled_simple_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [267] labeled_simple_expr = simple_expr.a + new Action() { // [269] labeled_simple_expr = simple_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [268] labeled_simple_expr = label_expr.a + new Action() { // [270] labeled_simple_expr = label_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [269] label_expr = LABEL simple_expr.a + new Action() { // [271] label_expr = LABEL simple_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [270] label_expr = TILDE label_ident.a + new Action() { // [272] label_expr = TILDE label_ident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [271] label_expr = QUESTION label_ident.a + new Action() { // [273] label_expr = QUESTION label_ident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [272] label_expr = OPTLABEL simple_expr.a + new Action() { // [274] label_expr = OPTLABEL simple_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [273] label_ident = LIDENT.id + new Action() { // [275] label_ident = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [274] let_bindings = let_binding.b + new Action() { // [276] let_bindings = let_binding.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol b = _symbols[offset + 1]; return b; } }, - new Action() { // [275] let_bindings = let_bindings.a AND let_binding.b + new Action() { // [277] let_bindings = let_bindings.a AND let_binding.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -3124,7 +3130,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b); } }, - new Action() { // [276] let_binding = val_ident.i fun_binding.f + new Action() { // [278] let_binding = val_ident.i fun_binding.f public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol i = _symbols[offset + 1]; final Symbol f = _symbols[offset + 2]; @@ -3137,7 +3143,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [277] let_binding = val_ident.i COLON typevar_list DOT core_type EQUAL seq_expr.b + new Action() { // [279] let_binding = val_ident.i COLON typevar_list DOT core_type EQUAL seq_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol i = _symbols[offset + 1]; final Symbol b = _symbols[offset + 7]; @@ -3150,7 +3156,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [278] let_binding = pattern.p EQUAL seq_expr.b + new Action() { // [280] let_binding = pattern.p EQUAL seq_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol p = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -3194,26 +3200,26 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(p, b); } }, - new Action() { // [279] fun_binding = strict_binding.a + new Action() { // [281] fun_binding = strict_binding.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [280] fun_binding = type_constraint.a EQUAL seq_expr.b + new Action() { // [282] fun_binding = type_constraint.a EQUAL seq_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [281] strict_binding = EQUAL seq_expr.a + new Action() { // [283] strict_binding = EQUAL seq_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [282] strict_binding = labeled_simple_pattern.p fun_binding.b + new Action() { // [284] strict_binding = labeled_simple_pattern.p fun_binding.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol p = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; @@ -3258,7 +3264,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(p, b); } }, - new Action() { // [283] strict_binding = LPAREN TYPE LIDENT.id RPAREN fun_binding.a + new Action() { // [285] strict_binding = LPAREN TYPE LIDENT.id RPAREN fun_binding.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 3]; final Symbol a = _symbols[offset + 5]; @@ -3271,7 +3277,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return root; } }, - new Action() { // [284] match_cases = pattern.p match_action.b + new Action() { // [286] match_cases = pattern.p match_action.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol p = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; @@ -3312,7 +3318,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(p, b); } }, - new Action() { // [285] match_cases = match_cases.a BAR pattern.b match_action.c + new Action() { // [287] match_cases = match_cases.a BAR pattern.b match_action.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -3354,13 +3360,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a, b, c); } }, - new Action() { // [286] fun_def = match_action.a + new Action() { // [288] fun_def = match_action.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [287] fun_def = labeled_simple_pattern.p fun_def.b + new Action() { // [289] fun_def = labeled_simple_pattern.p fun_def.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol p = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; @@ -3401,7 +3407,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(root, b); } }, - new Action() { // [288] fun_def = LPAREN TYPE LIDENT.id RPAREN fun_def.a + new Action() { // [290] fun_def = LPAREN TYPE LIDENT.id RPAREN fun_def.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 3]; final Symbol a = _symbols[offset + 5]; @@ -3414,34 +3420,34 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return root; } }, - new Action() { // [289] match_action = MINUSGREATER seq_expr.a + new Action() { // [291] match_action = MINUSGREATER seq_expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [290] match_action = WHEN seq_expr.a MINUSGREATER seq_expr.b + new Action() { // [292] match_action = WHEN seq_expr.a MINUSGREATER seq_expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [291] expr_comma_list = expr_comma_list.a COMMA expr.b + new Action() { // [293] expr_comma_list = expr_comma_list.a COMMA expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [292] expr_comma_list = expr.a COMMA expr.b + new Action() { // [294] expr_comma_list = expr.a COMMA expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [293] record_expr = simple_expr.a WITH lbl_expr_list.b opt_semi.c + new Action() { // [295] record_expr = simple_expr.a WITH lbl_expr_list.b opt_semi.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -3449,27 +3455,27 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b,c); } }, - new Action() { // [294] record_expr = lbl_expr_list.a opt_semi.b + new Action() { // [296] record_expr = lbl_expr_list.a opt_semi.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [295] lbl_expr_list = label_longident.a EQUAL expr.b + new Action() { // [297] lbl_expr_list = label_longident.a EQUAL expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [296] lbl_expr_list = label_longident.a + new Action() { // [298] lbl_expr_list = label_longident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [297] lbl_expr_list = lbl_expr_list.a SEMI label_longident.b EQUAL expr.c + new Action() { // [299] lbl_expr_list = lbl_expr_list.a SEMI label_longident.b EQUAL expr.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -3477,21 +3483,21 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b,c); } }, - new Action() { // [298] lbl_expr_list = lbl_expr_list.a SEMI label_longident.b + new Action() { // [300] lbl_expr_list = lbl_expr_list.a SEMI label_longident.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [299] field_expr_list = label.a EQUAL expr.b + new Action() { // [301] field_expr_list = label.a EQUAL expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [300] field_expr_list = field_expr_list.a SEMI label.b EQUAL expr.c + new Action() { // [302] field_expr_list = field_expr_list.a SEMI label.b EQUAL expr.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -3499,257 +3505,257 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b,c); } }, - new Action() { // [301] expr_semi_list = expr.a + new Action() { // [303] expr_semi_list = expr.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [302] expr_semi_list = expr_semi_list.a SEMI expr.b + new Action() { // [304] expr_semi_list = expr_semi_list.a SEMI expr.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [303] type_constraint = COLON core_type.a + new Action() { // [305] type_constraint = COLON core_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [304] type_constraint = COLON core_type.a COLONGREATER core_type.b + new Action() { // [306] type_constraint = COLON core_type.a COLONGREATER core_type.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [305] type_constraint = COLONGREATER core_type.a + new Action() { // [307] type_constraint = COLONGREATER core_type.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [306] type_constraint = COLON error + new Action() { // [308] type_constraint = COLON error public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [307] type_constraint = COLONGREATER error + new Action() { // [309] type_constraint = COLONGREATER error public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [308] pattern = simple_pattern.a + new Action() { // [310] pattern = simple_pattern.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [309] pattern = pattern.a AS val_ident.b + new Action() { // [311] pattern = pattern.a AS val_ident.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [310] pattern = pattern_comma_list.a + new Action() { // [312] pattern = pattern_comma_list.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [311] pattern = constr_longident.a pattern.b + new Action() { // [313] pattern = constr_longident.a pattern.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [312] pattern = name_tag.a pattern.b + new Action() { // [314] pattern = name_tag.a pattern.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return Def.root(a,b); } }, - new Action() { // [313] pattern = pattern.a COLONCOLON pattern.b + new Action() { // [315] pattern = pattern.a COLONCOLON pattern.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [314] pattern = LPAREN COLONCOLON RPAREN LPAREN pattern.a COMMA pattern.b RPAREN + new Action() { // [316] pattern = LPAREN COLONCOLON RPAREN LPAREN pattern.a COMMA pattern.b RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 5]; final Symbol b = _symbols[offset + 7]; return Def.root(a,b); } }, - new Action() { // [315] pattern = pattern.a BAR pattern.b + new Action() { // [317] pattern = pattern.a BAR pattern.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [316] pattern = LAZY simple_pattern.a + new Action() { // [318] pattern = LAZY simple_pattern.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [317] simple_pattern = val_ident.a + new Action() { // [319] simple_pattern = val_ident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [318] simple_pattern = UNDERSCORE.id + new Action() { // [320] simple_pattern = UNDERSCORE.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def("_", Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [319] simple_pattern = signed_constant.a + new Action() { // [321] simple_pattern = signed_constant.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [320] simple_pattern = CHAR DOTDOT CHAR + new Action() { // [322] simple_pattern = CHAR DOTDOT CHAR public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [321] simple_pattern = constr_longident.a + new Action() { // [323] simple_pattern = constr_longident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [322] simple_pattern = name_tag.a + new Action() { // [324] simple_pattern = name_tag.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [323] simple_pattern = SHARP type_longident.a + new Action() { // [325] simple_pattern = SHARP type_longident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [324] simple_pattern = LBRACE lbl_pattern_list.a record_pattern_end RBRACE + new Action() { // [326] simple_pattern = LBRACE lbl_pattern_list.a record_pattern_end RBRACE public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [325] simple_pattern = LBRACE lbl_pattern_list.a opt_semi error + new Action() { // [327] simple_pattern = LBRACE lbl_pattern_list.a opt_semi error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [326] simple_pattern = LBRACKET pattern_semi_list.a opt_semi RBRACKET + new Action() { // [328] simple_pattern = LBRACKET pattern_semi_list.a opt_semi RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [327] simple_pattern = LBRACKET pattern_semi_list.a opt_semi error + new Action() { // [329] simple_pattern = LBRACKET pattern_semi_list.a opt_semi error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [328] simple_pattern = LBRACKETBAR pattern_semi_list.a opt_semi BARRBRACKET + new Action() { // [330] simple_pattern = LBRACKETBAR pattern_semi_list.a opt_semi BARRBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [329] simple_pattern = LBRACKETBAR BARRBRACKET + new Action() { // [331] simple_pattern = LBRACKETBAR BARRBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [330] simple_pattern = LBRACKETBAR pattern_semi_list.a opt_semi error + new Action() { // [332] simple_pattern = LBRACKETBAR pattern_semi_list.a opt_semi error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [331] simple_pattern = LPAREN pattern.a RPAREN + new Action() { // [333] simple_pattern = LPAREN pattern.a RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [332] simple_pattern = LPAREN pattern.a error + new Action() { // [334] simple_pattern = LPAREN pattern.a error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [333] simple_pattern = LPAREN pattern.a COLON core_type.b RPAREN + new Action() { // [335] simple_pattern = LPAREN pattern.a COLON core_type.b RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [334] simple_pattern = LPAREN pattern.a COLON core_type.b error + new Action() { // [336] simple_pattern = LPAREN pattern.a COLON core_type.b error public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; final Symbol b = _symbols[offset + 4]; return Def.root(a,b); } }, - new Action() { // [335] pattern_comma_list = pattern_comma_list.a COMMA pattern.b + new Action() { // [337] pattern_comma_list = pattern_comma_list.a COMMA pattern.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [336] pattern_comma_list = pattern.a COMMA pattern.b + new Action() { // [338] pattern_comma_list = pattern.a COMMA pattern.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [337] pattern_semi_list = pattern.a + new Action() { // [339] pattern_semi_list = pattern.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [338] pattern_semi_list = pattern_semi_list.a SEMI pattern.b + new Action() { // [340] pattern_semi_list = pattern_semi_list.a SEMI pattern.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [339] lbl_pattern_list = label_longident.a EQUAL pattern.b + new Action() { // [341] lbl_pattern_list = label_longident.a EQUAL pattern.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [340] lbl_pattern_list = label_longident.a + new Action() { // [342] lbl_pattern_list = label_longident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [341] lbl_pattern_list = lbl_pattern_list.a SEMI label_longident.b EQUAL pattern.c + new Action() { // [343] lbl_pattern_list = lbl_pattern_list.a SEMI label_longident.b EQUAL pattern.c public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -3757,43 +3763,43 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b,c); } }, - new Action() { // [342] lbl_pattern_list = lbl_pattern_list.a SEMI label_longident.b + new Action() { // [344] lbl_pattern_list = lbl_pattern_list.a SEMI label_longident.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [343] record_pattern_end = opt_semi.a + new Action() { // [345] record_pattern_end = opt_semi.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [344] record_pattern_end = SEMI UNDERSCORE opt_semi.a + new Action() { // [346] record_pattern_end = SEMI UNDERSCORE opt_semi.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 3]; return a; } }, - new Action() { // [345] primitive_declaration = STRING + new Action() { // [347] primitive_declaration = STRING public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [346] primitive_declaration = STRING primitive_declaration.a + new Action() { // [348] primitive_declaration = STRING primitive_declaration.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [347] type_declarations = type_declaration.a + new Action() { // [349] type_declarations = type_declaration.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [348] type_declarations = type_declarations.a AND.n type_declaration.b + new Action() { // [350] type_declarations = type_declarations.a AND.n type_declaration.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol n = _symbols[offset + 2]; @@ -3805,7 +3811,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return Def.root(a,b); } }, - new Action() { // [349] type_declaration = type_parameters LIDENT.id type_kind.a constraints + new Action() { // [351] type_declaration = type_parameters LIDENT.id type_kind.a constraints public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 2]; final Symbol a = _symbols[offset + 3]; @@ -3817,155 +3823,155 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [350] constraints = constraints CONSTRAINT constrain + new Action() { // [352] constraints = constraints CONSTRAINT constrain public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [351] constraints = + new Action() { // [353] constraints = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [352] type_kind = + new Action() { // [354] type_kind = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [353] type_kind = EQUAL core_type + new Action() { // [355] type_kind = EQUAL core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [354] type_kind = EQUAL PRIVATE core_type + new Action() { // [356] type_kind = EQUAL PRIVATE core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [355] type_kind = EQUAL constructor_declarations.a + new Action() { // [357] type_kind = EQUAL constructor_declarations.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [356] type_kind = EQUAL PRIVATE constructor_declarations.a + new Action() { // [358] type_kind = EQUAL PRIVATE constructor_declarations.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 3]; return a; } }, - new Action() { // [357] type_kind = EQUAL private_flag BAR constructor_declarations.a + new Action() { // [359] type_kind = EQUAL private_flag BAR constructor_declarations.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 4]; return a; } }, - new Action() { // [358] type_kind = EQUAL private_flag LBRACE label_declarations.a opt_semi RBRACE + new Action() { // [360] type_kind = EQUAL private_flag LBRACE label_declarations.a opt_semi RBRACE public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 4]; return a; } }, - new Action() { // [359] type_kind = EQUAL core_type EQUAL private_flag opt_bar constructor_declarations.a + new Action() { // [361] type_kind = EQUAL core_type EQUAL private_flag opt_bar constructor_declarations.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 6]; return a; } }, - new Action() { // [360] type_kind = EQUAL core_type EQUAL private_flag LBRACE label_declarations.a opt_semi RBRACE + new Action() { // [362] type_kind = EQUAL core_type EQUAL private_flag LBRACE label_declarations.a opt_semi RBRACE public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 6]; return a; } }, - new Action() { // [361] type_parameters = + new Action() { // [363] type_parameters = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [362] type_parameters = type_parameter + new Action() { // [364] type_parameters = type_parameter public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [363] type_parameters = LPAREN type_parameter_list RPAREN + new Action() { // [365] type_parameters = LPAREN type_parameter_list RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [364] type_parameter = type_variance QUOTE ident + new Action() { // [366] type_parameter = type_variance QUOTE ident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [365] type_variance = + new Action() { // [367] type_variance = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [366] type_variance = PLUS + new Action() { // [368] type_variance = PLUS public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [367] type_variance = MINUS + new Action() { // [369] type_variance = MINUS public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [368] type_parameter_list = type_parameter + new Action() { // [370] type_parameter_list = type_parameter public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [369] type_parameter_list = type_parameter_list COMMA type_parameter + new Action() { // [371] type_parameter_list = type_parameter_list COMMA type_parameter public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [370] constructor_declarations = constructor_declaration.a + new Action() { // [372] constructor_declarations = constructor_declaration.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [371] constructor_declarations = constructor_declarations.a BAR constructor_declaration.b + new Action() { // [373] constructor_declarations = constructor_declarations.a BAR constructor_declaration.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [372] constructor_declaration = constr_ident.a constructor_arguments + new Action() { // [374] constructor_declaration = constr_ident.a constructor_arguments public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [373] constructor_arguments = + new Action() { // [375] constructor_arguments = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [374] constructor_arguments = OF core_type_list + new Action() { // [376] constructor_arguments = OF core_type_list public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [375] label_declarations = label_declaration.a + new Action() { // [377] label_declarations = label_declaration.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [376] label_declarations = label_declarations.a SEMI label_declaration.b + new Action() { // [378] label_declarations = label_declarations.a SEMI label_declaration.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; return Def.root(a,b); } }, - new Action() { // [377] label_declaration = mutable_flag.m label.a COLON poly_type + new Action() { // [379] label_declaration = mutable_flag.m label.a COLON poly_type public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; final Symbol a = _symbols[offset + 2]; @@ -3978,443 +3984,443 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return da; } }, - new Action() { // [378] with_constraints = with_constraint + new Action() { // [380] with_constraints = with_constraint public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [379] with_constraints = with_constraints AND with_constraint + new Action() { // [381] with_constraints = with_constraints AND with_constraint public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [380] with_constraint = TYPE type_parameters label_longident with_type_binder core_type constraints + new Action() { // [382] with_constraint = TYPE type_parameters label_longident with_type_binder core_type constraints public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [381] with_constraint = TYPE type_parameters label_longident COLONEQUAL core_type + new Action() { // [383] with_constraint = TYPE type_parameters label_longident COLONEQUAL core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [382] with_constraint = MODULE mod_longident EQUAL mod_ext_longident + new Action() { // [384] with_constraint = MODULE mod_longident EQUAL mod_ext_longident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [383] with_constraint = MODULE mod_longident COLONEQUAL mod_ext_longident + new Action() { // [385] with_constraint = MODULE mod_longident COLONEQUAL mod_ext_longident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [384] with_type_binder = EQUAL + new Action() { // [386] with_type_binder = EQUAL public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [385] with_type_binder = EQUAL PRIVATE + new Action() { // [387] with_type_binder = EQUAL PRIVATE public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [386] typevar_list = QUOTE ident + new Action() { // [388] typevar_list = QUOTE ident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [387] typevar_list = typevar_list QUOTE ident + new Action() { // [389] typevar_list = typevar_list QUOTE ident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [388] poly_type = core_type + new Action() { // [390] poly_type = core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [389] poly_type = typevar_list DOT core_type + new Action() { // [391] poly_type = typevar_list DOT core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [390] core_type = core_type2 + new Action() { // [392] core_type = core_type2 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [391] core_type = core_type2 AS QUOTE ident + new Action() { // [393] core_type = core_type2 AS QUOTE ident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [392] core_type2 = simple_core_type_or_tuple + new Action() { // [394] core_type2 = simple_core_type_or_tuple public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [393] core_type2 = QUESTION LIDENT COLON core_type2 MINUSGREATER core_type2 + new Action() { // [395] core_type2 = QUESTION LIDENT COLON core_type2 MINUSGREATER core_type2 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [394] core_type2 = OPTLABEL core_type2 MINUSGREATER core_type2 + new Action() { // [396] core_type2 = OPTLABEL core_type2 MINUSGREATER core_type2 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [395] core_type2 = LIDENT COLON core_type2 MINUSGREATER core_type2 + new Action() { // [397] core_type2 = LIDENT COLON core_type2 MINUSGREATER core_type2 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [396] core_type2 = core_type2 MINUSGREATER core_type2 + new Action() { // [398] core_type2 = core_type2 MINUSGREATER core_type2 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [397] simple_core_type = simple_core_type2 + new Action() { // [399] simple_core_type = simple_core_type2 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [398] simple_core_type = LPAREN core_type_comma_list RPAREN + new Action() { // [400] simple_core_type = LPAREN core_type_comma_list RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [399] simple_core_type2 = QUOTE ident + new Action() { // [401] simple_core_type2 = QUOTE ident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [400] simple_core_type2 = UNDERSCORE + new Action() { // [402] simple_core_type2 = UNDERSCORE public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [401] simple_core_type2 = type_longident + new Action() { // [403] simple_core_type2 = type_longident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [402] simple_core_type2 = simple_core_type2 type_longident + new Action() { // [404] simple_core_type2 = simple_core_type2 type_longident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [403] simple_core_type2 = LPAREN core_type_comma_list RPAREN type_longident + new Action() { // [405] simple_core_type2 = LPAREN core_type_comma_list RPAREN type_longident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [404] simple_core_type2 = LESS meth_list GREATER + new Action() { // [406] simple_core_type2 = LESS meth_list GREATER public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [405] simple_core_type2 = LESS GREATER + new Action() { // [407] simple_core_type2 = LESS GREATER public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [406] simple_core_type2 = SHARP class_longident opt_present + new Action() { // [408] simple_core_type2 = SHARP class_longident opt_present public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [407] simple_core_type2 = simple_core_type2 SHARP class_longident opt_present + new Action() { // [409] simple_core_type2 = simple_core_type2 SHARP class_longident opt_present public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [408] simple_core_type2 = LPAREN core_type_comma_list RPAREN SHARP class_longident opt_present + new Action() { // [410] simple_core_type2 = LPAREN core_type_comma_list RPAREN SHARP class_longident opt_present public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [409] simple_core_type2 = LBRACKET tag_field RBRACKET + new Action() { // [411] simple_core_type2 = LBRACKET tag_field RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [410] simple_core_type2 = LBRACKET BAR row_field_list RBRACKET + new Action() { // [412] simple_core_type2 = LBRACKET BAR row_field_list RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [411] simple_core_type2 = LBRACKET row_field BAR row_field_list RBRACKET + new Action() { // [413] simple_core_type2 = LBRACKET row_field BAR row_field_list RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [412] simple_core_type2 = LBRACKETGREATER opt_bar row_field_list RBRACKET + new Action() { // [414] simple_core_type2 = LBRACKETGREATER opt_bar row_field_list RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [413] simple_core_type2 = LBRACKETGREATER RBRACKET + new Action() { // [415] simple_core_type2 = LBRACKETGREATER RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [414] simple_core_type2 = LBRACKETLESS opt_bar row_field_list RBRACKET + new Action() { // [416] simple_core_type2 = LBRACKETLESS opt_bar row_field_list RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [415] simple_core_type2 = LBRACKETLESS opt_bar row_field_list GREATER name_tag_list RBRACKET + new Action() { // [417] simple_core_type2 = LBRACKETLESS opt_bar row_field_list GREATER name_tag_list RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [416] simple_core_type2 = LPAREN MODULE package_type RPAREN + new Action() { // [418] simple_core_type2 = LPAREN MODULE package_type RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [417] package_type = mty_longident + new Action() { // [419] package_type = mty_longident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [418] package_type = mty_longident WITH package_type_cstrs + new Action() { // [420] package_type = mty_longident WITH package_type_cstrs public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [419] package_type_cstr = TYPE LIDENT EQUAL core_type + new Action() { // [421] package_type_cstr = TYPE LIDENT EQUAL core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [420] package_type_cstrs = package_type_cstr + new Action() { // [422] package_type_cstrs = package_type_cstr public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [421] package_type_cstrs = package_type_cstr AND package_type_cstrs + new Action() { // [423] package_type_cstrs = package_type_cstr AND package_type_cstrs public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [422] row_field_list = row_field + new Action() { // [424] row_field_list = row_field public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [423] row_field_list = row_field_list BAR row_field + new Action() { // [425] row_field_list = row_field_list BAR row_field public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [424] row_field = tag_field + new Action() { // [426] row_field = tag_field public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [425] row_field = simple_core_type2 + new Action() { // [427] row_field = simple_core_type2 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [426] tag_field = name_tag OF opt_ampersand amper_type_list + new Action() { // [428] tag_field = name_tag OF opt_ampersand amper_type_list public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [427] tag_field = name_tag + new Action() { // [429] tag_field = name_tag public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [428] opt_ampersand = AMPERSAND + new Action() { // [430] opt_ampersand = AMPERSAND public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [429] opt_ampersand = + new Action() { // [431] opt_ampersand = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [430] amper_type_list = core_type + new Action() { // [432] amper_type_list = core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [431] amper_type_list = amper_type_list AMPERSAND core_type + new Action() { // [433] amper_type_list = amper_type_list AMPERSAND core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [432] opt_present = LBRACKETGREATER name_tag_list RBRACKET + new Action() { // [434] opt_present = LBRACKETGREATER name_tag_list RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [433] opt_present = + new Action() { // [435] opt_present = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [434] name_tag_list = name_tag + new Action() { // [436] name_tag_list = name_tag public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [435] name_tag_list = name_tag_list name_tag + new Action() { // [437] name_tag_list = name_tag_list name_tag public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [436] simple_core_type_or_tuple = simple_core_type + new Action() { // [438] simple_core_type_or_tuple = simple_core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [437] simple_core_type_or_tuple = simple_core_type STAR core_type_list + new Action() { // [439] simple_core_type_or_tuple = simple_core_type STAR core_type_list public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [438] core_type_comma_list = core_type + new Action() { // [440] core_type_comma_list = core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [439] core_type_comma_list = core_type_comma_list COMMA core_type + new Action() { // [441] core_type_comma_list = core_type_comma_list COMMA core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [440] core_type_list = simple_core_type + new Action() { // [442] core_type_list = simple_core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [441] core_type_list = core_type_list STAR simple_core_type + new Action() { // [443] core_type_list = core_type_list STAR simple_core_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [442] meth_list = field SEMI meth_list + new Action() { // [444] meth_list = field SEMI meth_list public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [443] meth_list = field opt_semi + new Action() { // [445] meth_list = field opt_semi public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [444] meth_list = DOTDOT + new Action() { // [446] meth_list = DOTDOT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [445] field = label COLON poly_type + new Action() { // [447] field = label COLON poly_type public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [446] label = LIDENT.id + new Action() { // [448] label = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [447] constant = INT + new Action() { // [449] constant = INT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [448] constant = CHAR + new Action() { // [450] constant = CHAR public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [449] constant = STRING + new Action() { // [451] constant = STRING public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [450] constant = FLOAT + new Action() { // [452] constant = FLOAT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [451] constant = INT32 + new Action() { // [453] constant = INT32 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [452] constant = INT64 + new Action() { // [454] constant = INT64 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [453] constant = NATIVEINT + new Action() { // [455] constant = NATIVEINT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [454] signed_constant = constant + new Action() { // [456] signed_constant = constant public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [455] signed_constant = MINUS INT + new Action() { // [457] signed_constant = MINUS INT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [456] signed_constant = MINUS FLOAT + new Action() { // [458] signed_constant = MINUS FLOAT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [457] signed_constant = MINUS INT32 + new Action() { // [459] signed_constant = MINUS INT32 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [458] signed_constant = MINUS INT64 + new Action() { // [460] signed_constant = MINUS INT64 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [459] signed_constant = MINUS NATIVEINT + new Action() { // [461] signed_constant = MINUS NATIVEINT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [460] signed_constant = PLUS INT + new Action() { // [462] signed_constant = PLUS INT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [461] signed_constant = PLUS FLOAT + new Action() { // [463] signed_constant = PLUS FLOAT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [462] signed_constant = PLUS INT32 + new Action() { // [464] signed_constant = PLUS INT32 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [463] signed_constant = PLUS INT64 + new Action() { // [465] signed_constant = PLUS INT64 public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [464] signed_constant = PLUS NATIVEINT + new Action() { // [466] signed_constant = PLUS NATIVEINT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [465] ident = UIDENT.id + new Action() { // [467] ident = UIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; @@ -4423,7 +4429,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [466] ident = LIDENT.id + new Action() { // [468] ident = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; @@ -4432,7 +4438,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [467] val_ident = LIDENT.id + new Action() { // [469] val_ident = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; @@ -4441,7 +4447,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [468] val_ident = LPAREN operator.o RPAREN + new Action() { // [470] val_ident = LPAREN operator.o RPAREN public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol o = _symbols[offset + 2]; @@ -4449,127 +4455,127 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(op.name, Def.Type.Identifier, op.posStart, op.posEnd); } }, - new Action() { // [469] operator = PREFIXOP.id + new Action() { // [471] operator = PREFIXOP.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [470] operator = INFIXOP0.id + new Action() { // [472] operator = INFIXOP0.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [471] operator = INFIXOP1.id + new Action() { // [473] operator = INFIXOP1.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [472] operator = INFIXOP2.id + new Action() { // [474] operator = INFIXOP2.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [473] operator = INFIXOP3.id + new Action() { // [475] operator = INFIXOP3.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [474] operator = INFIXOP4.id + new Action() { // [476] operator = INFIXOP4.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [475] operator = BANG.id + new Action() { // [477] operator = BANG.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [476] operator = PLUS.id + new Action() { // [478] operator = PLUS.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [477] operator = PLUSDOT.id + new Action() { // [479] operator = PLUSDOT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [478] operator = MINUS.id + new Action() { // [480] operator = MINUS.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [479] operator = MINUSDOT.id + new Action() { // [481] operator = MINUSDOT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [480] operator = STAR.id + new Action() { // [482] operator = STAR.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [481] operator = EQUAL.id + new Action() { // [483] operator = EQUAL.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [482] operator = LESS.id + new Action() { // [484] operator = LESS.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [483] operator = GREATER.id + new Action() { // [485] operator = GREATER.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [484] operator = OR.id + new Action() { // [486] operator = OR.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [485] operator = BARBAR.id + new Action() { // [487] operator = BARBAR.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [486] operator = AMPERSAND.id + new Action() { // [488] operator = AMPERSAND.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [487] operator = AMPERAMPER.id + new Action() { // [489] operator = AMPERAMPER.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [488] operator = COLONEQUAL.id + new Action() { // [490] operator = COLONEQUAL.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [489] constr_ident = UIDENT.id + new Action() { // [491] constr_ident = UIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; @@ -4578,38 +4584,38 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return def; } }, - new Action() { // [490] constr_ident = LPAREN.a RPAREN.b + new Action() { // [492] constr_ident = LPAREN.a RPAREN.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return new Def("()", Def.Type.TypeConstructor, a.getStart(), b.getEnd()); } }, - new Action() { // [491] constr_ident = COLONCOLON.a + new Action() { // [493] constr_ident = COLONCOLON.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return new Def("::", Def.Type.TypeConstructor, a.getStart(), a.getEnd()); } }, - new Action() { // [492] constr_ident = FALSE.id + new Action() { // [494] constr_ident = FALSE.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def("false", Def.Type.TypeConstructor, id.getStart(), id.getEnd()); } }, - new Action() { // [493] constr_ident = TRUE.id + new Action() { // [495] constr_ident = TRUE.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def("true", Def.Type.TypeConstructor, id.getStart(), id.getEnd()); } }, - new Action() { // [494] val_longident = val_ident.a + new Action() { // [496] val_longident = val_ident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [495] val_longident = mod_longident.a DOT val_ident.b + new Action() { // [497] val_longident = mod_longident.a DOT val_ident.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -4619,41 +4625,41 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(da.name + "." + db.name, Def.Type.Identifier, da.posStart, db.posEnd); } }, - new Action() { // [496] constr_longident = mod_longident.a + new Action() { // [498] constr_longident = mod_longident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [497] constr_longident = LBRACKET RBRACKET + new Action() { // [499] constr_longident = LBRACKET RBRACKET public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [498] constr_longident = LPAREN.a RPAREN.b + new Action() { // [500] constr_longident = LPAREN.a RPAREN.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 2]; return new Def("()", Def.Type.Identifier, a.getStart(), b.getEnd()); } }, - new Action() { // [499] constr_longident = FALSE + new Action() { // [501] constr_longident = FALSE public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [500] constr_longident = TRUE + new Action() { // [502] constr_longident = TRUE public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [501] label_longident = LIDENT.id + new Action() { // [503] label_longident = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [502] label_longident = mod_longident.a DOT LIDENT.id + new Action() { // [504] label_longident = mod_longident.a DOT LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol id = _symbols[offset + 3]; @@ -4662,13 +4668,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(da.name + "." + (String)id.value, Def.Type.Identifier, da.posStart, id.getEnd()); } }, - new Action() { // [503] type_longident = LIDENT.id + new Action() { // [505] type_longident = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [504] type_longident = mod_ext_longident.a DOT LIDENT.id + new Action() { // [506] type_longident = mod_ext_longident.a DOT LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol id = _symbols[offset + 3]; @@ -4677,13 +4683,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(da.name + "." + (String)id.value, Def.Type.Identifier, da.posStart, id.getEnd()); } }, - new Action() { // [505] mod_longident = UIDENT.id + new Action() { // [507] mod_longident = UIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [506] mod_longident = mod_longident.a DOT UIDENT.id + new Action() { // [508] mod_longident = mod_longident.a DOT UIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol id = _symbols[offset + 3]; @@ -4692,13 +4698,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(da.name + "." + (String)id.value, Def.Type.Identifier, da.posStart, id.getEnd()); } }, - new Action() { // [507] mod_ext_longident = UIDENT.id + new Action() { // [509] mod_ext_longident = UIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [508] mod_ext_longident = mod_ext_longident.a DOT UIDENT.id + new Action() { // [510] mod_ext_longident = mod_ext_longident.a DOT UIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol id = _symbols[offset + 3]; @@ -4707,7 +4713,7 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(da.name + "." + (String)id.value, Def.Type.Identifier, da.posStart, id.getEnd()); } }, - new Action() { // [509] mod_ext_longident = mod_ext_longident.a LPAREN mod_ext_longident.b RPAREN.par + new Action() { // [511] mod_ext_longident = mod_ext_longident.a LPAREN mod_ext_longident.b RPAREN.par public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -4718,13 +4724,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(da.name + "(" + db.name + ")", Def.Type.Identifier, da.posStart, par.getEnd()); } }, - new Action() { // [510] mty_longident = ident.a + new Action() { // [512] mty_longident = ident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; return a; } }, - new Action() { // [511] mty_longident = mod_ext_longident.a DOT ident.b + new Action() { // [513] mty_longident = mod_ext_longident.a DOT ident.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol b = _symbols[offset + 3]; @@ -4734,13 +4740,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(da.name + "." + db.name, Def.Type.Identifier, da.posStart, db.posEnd); } }, - new Action() { // [512] clty_longident = LIDENT.id + new Action() { // [514] clty_longident = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [513] clty_longident = mod_ext_longident.a DOT LIDENT.id + new Action() { // [515] clty_longident = mod_ext_longident.a DOT LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol id = _symbols[offset + 3]; @@ -4749,13 +4755,13 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(da.name + "." + (String)id.value, Def.Type.Identifier, da.posStart, id.getEnd()); } }, - new Action() { // [514] class_longident = LIDENT.id + new Action() { // [516] class_longident = LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol id = _symbols[offset + 1]; return new Def((String)id.value, Def.Type.Identifier, id.getStart(), id.getEnd()); } }, - new Action() { // [515] class_longident = mod_longident.a DOT LIDENT.id + new Action() { // [517] class_longident = mod_longident.a DOT LIDENT.id public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 1]; final Symbol id = _symbols[offset + 3]; @@ -4764,142 +4770,152 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(da.name + "." + (String)id.value, Def.Type.Identifier, da.posStart, id.getEnd()); } }, - new Action() { // [516] toplevel_directive = SHARP ident + new Action() { // [518] toplevel_directive = SHARP ident + public Symbol reduce(Symbol[] _symbols, int offset) { + return new Def(); + } + }, + new Action() { // [519] toplevel_directive = SHARP ident STRING + public Symbol reduce(Symbol[] _symbols, int offset) { + return new Def(); + } + }, + new Action() { // [520] toplevel_directive = SHARP ident INT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [517] toplevel_directive = SHARP ident STRING + new Action() { // [521] toplevel_directive = SHARP ident val_longident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [518] toplevel_directive = SHARP ident INT + new Action() { // [522] toplevel_directive = SHARP ident FALSE public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [519] toplevel_directive = SHARP ident val_longident + new Action() { // [523] toplevel_directive = SHARP ident TRUE public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [520] toplevel_directive = SHARP ident FALSE + new Action() { // [524] cppo_directive = SHARP ident public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [521] toplevel_directive = SHARP ident TRUE + new Action() { // [525] cppo_directive = SHARP ident STRING public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [522] name_tag = BACKQUOTE ident.a + new Action() { // [526] name_tag = BACKQUOTE ident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [523] rec_flag = + new Action() { // [527] rec_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [524] rec_flag = REC + new Action() { // [528] rec_flag = REC public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def(); def.bRec = true; return def; } }, - new Action() { // [525] direction_flag = TO + new Action() { // [529] direction_flag = TO public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [526] direction_flag = DOWNTO + new Action() { // [530] direction_flag = DOWNTO public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [527] private_flag = + new Action() { // [531] private_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [528] private_flag = PRIVATE.p + new Action() { // [532] private_flag = PRIVATE.p public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol p = _symbols[offset + 1]; Def def = new Def(); def.bAlt=true; def.posStart = p.getStart(); return def; } }, - new Action() { // [529] mutable_flag = + new Action() { // [533] mutable_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [530] mutable_flag = MUTABLE.m + new Action() { // [534] mutable_flag = MUTABLE.m public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; Def def = new Def(); def.bAlt=true; def.posStart = m.getStart(); return def; } }, - new Action() { // [531] virtual_flag = + new Action() { // [535] virtual_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [532] virtual_flag = VIRTUAL.v + new Action() { // [536] virtual_flag = VIRTUAL.v public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol v = _symbols[offset + 1]; Def def = new Def(); def.bAlt=true; def.posStart = v.getStart(); return def; } }, - new Action() { // [533] override_flag = + new Action() { // [537] override_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [534] override_flag = BANG.b + new Action() { // [538] override_flag = BANG.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol b = _symbols[offset + 1]; Def def = new Def(); def.bAlt=true; def.posStart = b.getStart(); return def; } }, - new Action() { // [535] opt_bar = + new Action() { // [539] opt_bar = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [536] opt_bar = BAR + new Action() { // [540] opt_bar = BAR public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [537] opt_semi = + new Action() { // [541] opt_semi = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [538] opt_semi = SEMI + new Action() { // [542] opt_semi = SEMI public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [539] subtractive = MINUS + new Action() { // [543] subtractive = MINUS public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [540] subtractive = MINUSDOT + new Action() { // [544] subtractive = MINUSDOT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [541] additive = PLUS + new Action() { // [545] additive = PLUS public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [542] additive = PLUSDOT + new Action() { // [546] additive = PLUSDOT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } From 5e2b52fb5475a93248b71264395dc23f807f67d8 Mon Sep 17 00:00:00 2001 From: trungtq Date: Wed, 1 Apr 2015 15:28:06 +0800 Subject: [PATCH 121/127] improve cppo parser --- Ocaml/src/ocaml/parser/OcamlParser.g | 4 + Ocaml/src/ocaml/parser/OcamlParser.java | 1058 ++++++++++++----------- 2 files changed, 543 insertions(+), 519 deletions(-) diff --git a/Ocaml/src/ocaml/parser/OcamlParser.g b/Ocaml/src/ocaml/parser/OcamlParser.g index 3a51b37..23756eb 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.g +++ b/Ocaml/src/ocaml/parser/OcamlParser.g @@ -2477,6 +2477,10 @@ cppo_directive= {: return new Def(); :} | SHARP ident STRING {: return new Def(); :} + | SHARP ident ident STRING + {: return new Def(); :} + | SHARP ident ident seq_expr + {: return new Def(); :} ; /* Miscellaneous */ diff --git a/Ocaml/src/ocaml/parser/OcamlParser.java b/Ocaml/src/ocaml/parser/OcamlParser.java index 897be36..34e20cb 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.java +++ b/Ocaml/src/ocaml/parser/OcamlParser.java @@ -19,8 +19,8 @@ static public class Terminals { static public final short LET = 5; static public final short END = 6; static public final short LBRACKET = 7; - static public final short RPAREN = 8; - static public final short MODULE = 9; + static public final short MODULE = 8; + static public final short RPAREN = 9; static public final short TYPE = 10; static public final short OPEN = 11; static public final short EXTERNAL = 12; @@ -69,8 +69,8 @@ static public class Terminals { static public final short BANG = 55; static public final short BARRBRACKET = 56; static public final short STAR = 57; - static public final short UNDERSCORE = 58; - static public final short PREFIXOP = 59; + static public final short PREFIXOP = 58; + static public final short UNDERSCORE = 59; static public final short BEGIN = 60; static public final short LBRACELESS = 61; static public final short NEW = 62; @@ -91,10 +91,10 @@ static public class Terminals { static public final short DO = 77; static public final short DONE = 78; static public final short THEN = 79; - static public final short TO = 80; - static public final short DOWNTO = 81; - static public final short ELSE = 82; - static public final short LAZY = 83; + static public final short LAZY = 80; + static public final short TO = 81; + static public final short DOWNTO = 82; + static public final short ELSE = 83; static public final short OBJECT = 84; static public final short DOT = 85; static public final short FUN = 86; @@ -129,8 +129,8 @@ static public class Terminals { "LET", "END", "LBRACKET", - "RPAREN", "MODULE", + "RPAREN", "TYPE", "OPEN", "EXTERNAL", @@ -179,8 +179,8 @@ static public class Terminals { "BANG", "BARRBRACKET", "STAR", - "UNDERSCORE", "PREFIXOP", + "UNDERSCORE", "BEGIN", "LBRACELESS", "NEW", @@ -201,10 +201,10 @@ static public class Terminals { "DO", "DONE", "THEN", + "LAZY", "TO", "DOWNTO", "ELSE", - "LAZY", "OBJECT", "DOT", "FUN", @@ -238,493 +238,508 @@ static public class AltGoals { } static final ParsingTables PARSING_TABLES = new ParsingTables( - "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" + - "v4#1XbDPptdU5OXVw5tYNMJB0AMHlJHMleztcUo3z2jb7uHlftCQUTTwDtj$yUxr$#4zu3t" + - "jFUEzu3tl$TrxCL#PeEoRtbkefvR3xtWVUXzvAxnldRcs350gsP#yZsBbgxt$uVZTysMrh1" + - "PFqZcDF9dnCXdd5UVzp3gP5g0DCcMP3JFjyfKn96ep6ylgJ5TPZJ5UdkaXhyhqpmp830mbk" + - "CSvbDaYCo9MldTcHnoZCpl9tk3ZwPn6cGcPIPczG7jczixiAxEP0#MlcOFbB$dA16KFaVy1" + - "$vVi3PIplGSo2#JlycVvKoZ1A5Nu1$bjhFncyXiStyllSDvC$e$FAPHPAlyh4ZxvoXXISdH" + - "Wz2IMPPIMR8Hw8QKNf$TIuNHAGcXA5Y8bHqSCPI31A2tP26sAb4qvVLCLJgTKb7dAs6MD$h" + - "IoG6d9HcWJf6p2wPkeS2xnhBw9aaf46PUdMTsEkwO6EcAsL19cLj$4r1FJsHCfFJczfmhd4" + - "gFigQGIKSRb2QKTTqqDTCHGAWc3igUf9wQp1r9wS7eF5SubHjb3IIMYZCiJIZlkcXheYA5K" + - "4WPb3rDFJ6Ttf7JdzEug72TzPx2xaaf46Iz1A8ctrt6wCuYFMqwoCPIK7zkv9UZiXfHkdDv" + - "DXUEaKNPJKeaeuoK89V7sEcwZx1P3IVb9AACwgv1InUbLAXmdZR9AIIMYZ9SWbCJRwxYDiY" + - "g6al83b1ohJD29DAdIArKuJXfbfP9AH1alGIY9jzTn6sLb32NbXoWfLfcWim8f5PnUeS9nq" + - "YWhb5GYIYFPGtD2IRozZjieAs8eAtBlMDiw5Vbl2K47dLKuJlgwvoqbbVJ9AK7NFSJRwxY5" + - "4h6syR99AACQvUR0lJcZtro5uwHjkRcIIhIbaUoXETcIU7iTjssvUSoMcwVOqaPmYAn5IYs" + - "drwfmd3JAMYMLYD98zj2SK19lh#CsojeOojeKb54KWv4ocDC7gt0wfQBCKyOkQ$GNAfkGFW" + - "WfWpXza0gdKohAF6NiiaP$eR89wGEGCe3J1wXmEgMYp5F6Bclq5ogRa4w#KixfvIgSJgaey" + - "vInonhzXSecf7T5IbTExwh2wPIACayPkwpHNwXiGZf6d#GHA3keS9pq6E#Wf19H6iaUcjCO" + - "9zvUn#qntY4snZkaZF4eYesGiX6dRwJ2wPIACayPkwpHNwXiGdexfBJZz7Ogd4wfAFEKiSi" + - "Q$ONA9gHlXPIjE7qh5KwdL9HvojXbZVv2PHFIjqNAjfo#hGgdKohAF6NiiaP$eR89wIEGCe" + - "BJHwXmEgMYp5F6Bclq5ogRaDu5ALqulOiAnqcFyIvAAX6baUoXEOrnukrrt1xZNM9Zl4lA6" + - "8#Yw8oKpfpUMONZf55sLbA9A8ra3yq99V7sEcwZx1n3sJa5PHH59wHqulHEAXmdZRAJaaf4" + - "QIHxQ4ueYRVNSHjbfnZAJYaeeoWwPdQG7Jcz8t4wHqcZxAYahBUxKgotSqXO1YWL9vJ4s#k" + - "uZR8ZeQJdheN8xCBnN9JFnt6uhuevwateOgXxd$E#EzpzqBtNMHTATX6pCzk9Uxn7lKU4y8" + - "vFUoxFgSWi5hNEBF6CEzXxtpdOM#uz1WJ7YNkXut9neBjGtETkaJbQFEWzZ9IxlO$TS$KJk" + - "FHvMDmiRX6tYjl4NyJzuW7nKAuT#4temla4iSYRq85zgCOk5FRWNPJhYbTHM6F79mKxa0jw" + - "asNsAnBAVa7OWLo8UxDVa1qorUA#p37k7WOxwicBNRm2BHynxdj87xZ63dtHjxWN#tOEVFB" + - "bkoF3iBCz#gb6$E3sfpBceBDypb#F3cU4V4u#Hwd4RGBImQmluW$#UbwDivcx1RSM$X3QbD" + - "uRakOF$ZXHwtsDi$1#K3Ob$MHJCLFCokmixgEym1$#7TeK$P5ZK#eFkLCu#ZB7aatbJhd#8" + - "DzpNysmHsIs4NFT#xp9qVzbSCRwvzDx$HqdtIFuEKJXtEzSuLpaNEuyHE$rXqtnSIPbFrNa" + - "Z4VVVkekTovqBWO6yvJfH4hDVWh9dOradCIveKV81wFeqSh8VnRuPvC#IXLUPchcyB1jQET" + - "zi4EiRT2Cjb69rBRTxvo6LftYFAGiIMtZm0tEbHZ1RzBSuTpidEXSx2u7mgETauAsFUmyGN" + - "E7qknSRMjsBd7kD7r3RNFMJUYPTotqxsAiBekYppWAVRwn2fzRwe$tbuBZx2ybzCHjogpbZ" + - "yyi1lfvZEQHmA#Eay$2aZWm0fwLpsQEfrYKmfx9GN#vk047FRrykRpSlO$EKTBh0eNIdbv#" + - "bdDhCyqW#5wcQI3FyuxYzFGovWcoFUdGw55Zmih0JozV2boNCgvBvQN0TMcSrEp6eJIVuB9" + - "E2$6qqryyugoN6UaCr2M5QAOuuS9vkJFTlJUqAcgqS7ar5gwB2n6KVY0#p2z1PtUa#4Hyog" + - "FlE6TxId5Ey6$oRs8DmiWHBcTnM3QxGdoSNK44swvm5XbPkQmGwNxCAq7dS7xm5gWKtQ9bf" + - "dnciLpcpQVv8InBCrbc4zEYx8hCakmAphce447yOsZAAq7d41VZG4g6xWEUpng4aTEuWhBk" + - "jenBYFDm7ATjG3aN5gBiDzbl89j7GkMI74d2FxPHAPbDOO5lA5$5wUnKq7fkQm$NSvVlmRb" + - "3EUU2GgHMuVmIT7PUvSR#HFwbKqxm$#p$cJLyOUJ4qEmNyA#mR8XgIvHSv0xJTPrVYBHjyq" + - "hGETQFdEvpdkFuOoXEPzsFGLbQknpubZ#6TmrZQ5Hopdc5IArR#IHKBikjCBEzIiVdNEHyO" + - "U8KnjerrDREkmTxPwRgEhSGwNhoIgYpRJ6xf2dlROxmK6#USx5LDiJqBvAZTPxIiLRDqhi8" + - "aRlIPXOMiLPz9jxnTqR#l$cSkzB2svoR$PsT4zpbE7zaxI9efHNEuhILLircUTQg7wFeuoi" + - "jodnNUAMLJwe3g#MJyad#RwCdewIkCzpb96MljFvNV3nFPvztrSHjCkZzhu3#kVYEFf$bkI" + - "Im#vkaOqSDJJ6ByBf71ri#xEUzipye8kpP7#Xjs25siGzfLhbYBoCPfpJBwxuzWrUhcvttV" + - "VrTC6l3sY3kSJvqFc1SANsBtI#l3QXZ9BIF57UAlsQmxebxQMSFhMVYQkGa11uKj#DyjxDC" + - "$1bUEv7M1f5mDU9CCfXenqgOd0iSidyP3dhp$KI5oHdkZ4lVsVayz$2UMMFYsZGcZFlxUCy" + - "CJ0Wp9ciivbuXcJ5m1irU2fDt6sk4PPpFmPMT0lzCmkJmtNsdZwFceW0JxPdv0zznFhFjb0" + - "yJndqkfgVCB5SS9kenBR#2BHDWCkd0DDJv8j9tnY#x9jWfvaquqvhqDHrqBeo8v5ZIV1WHK" + - "kxrW4$EKLQAUnFop#Uy74JchJZkP3c7tuvp7X3nRa7EeHBwdJd2X5BUgIFiiFducwWSbGkD" + - "V$UteCFTM$uTl1d5ecJgSVRakVyqPszrNKFlxCVvKKMiMV4jwBg6IddZd9DChdEfaKoYK0#" + - "5IPT6#wYpbya5rcVyH#cWa7o6KedRfCg0bYlYkERsn#I6aabav8m6fPzIpK5d#Ro$d0xCuC" + - "zBcesN4xSfgF4HHHpNF89AvuQIIMJauXfKZj4it$CVoGobaBERV8zISwzYjQQ75N5SyuXUd" + - "HjA9f6HYsjGEKOpK3qCL0y7g1vEH4LQ7bB4SSqZUdLkA9b4HYwkGUKOpK3r450z5A1wA14L" + - "QNbG4SSrZ#ZLkQ5a4Xcvk0QLOpG3rOD0zM20wi54LAJb0KKSrpoYL#U6aabavE8QL8xHBD$" + - "m7w23Gl8DIYLkKr3Z$Oeuhdb4hyuD9PF8oCKrg1oZMVxDlvyE2ic$KIfncu8QxrF4SSqZUd" + - "LkA9b4HYwkGUKOpV8r$puwA2HVerJYDWKrtgk8uvf7zEhSK3A9Z5nSWyenckMh$hrqK4Y#I" + - "gd4RGfgl4SHnpMFwDMveMGI6Rcu1fLZD6T$yk#XWqBPdoYLk4r1ZNShuhZc4RqwDvHC8YCN" + - "rw1oZ6QCmRin1kyEnk3TYMEGjDobYEEQH$Jgt50oYOnSN8FACPg1wYwWkYj0TLSYAjBoLqK" + - "SrpoYL#U6aabavE8QL4wesV#hSvmAEITmx2Dxly3fYrdB84LS1fps2tIrHVi5aqQveMGI6J" + - "cZoVcEpjukAaThtiE40yo3ehiOameQg8ZZuFOkngHHRYYPH4REQ58VeE8ShNcU2GVr3qn4H" + - "Le6AE8uU0ugdHjA9f6HOmtX7RLTL8xATRymOTQF$Jc5R5Jk9q6D$HLn73m7bSuD9PF8oEam" + - "txDn7A3Y79MRsTQ4aSVV6538$JX#Xvsrz5F4SUO6b$CBuJAveMGI6JaYknQLetFF3kEg5iW" + - "UwVp3EIcAYsLh58cR42SkB5ptOOUiSaKecKIghA88gXfpACqchb7Lg3fYg4XBNqNEBOY3Hr" + - "0T2rHzLMeecKIghDPae#fh3ZexTvcuHaLfkROYBNqKiQs8swYE1ogLAqB9959b5KLGzJ67q" + - "cpY6bMVH5IafLeHeo8kefwbSqKecKIgh0bRisYrELIwYOUvpdzol9sqz5R4SUOnRzUveMGI" + - "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" + - "xVJ$igPXp$vRda5dxJF$Zf8yG$cCUt#ApvmHyvapL0cqz0o5tPkm6h7$Ivv3PutzNr7o3bV" + - "OjSOSx5xCtxrpNTsBtjaQ#zwh3tjcbZnT26StXJt#fXVAopjMJu$P$NHL0dO$NMC$ORLYFp" + - "4FzXCBO3ynXlr4gJsUE6C$QRLYFpiFzhCBO3yxXlrigT$y8OtFd9EmZ$mENleT4V4ax2hFI" + - "ELIWFqiXPtISh2VfJI46eaix6V5i9#bIW3xMKhUkov46j2tIFcMY7WYzczLkfBAfG3xQHex" + - "qdAmdwOqX1g9BEodnR2Vfae0#sbAthiXH1gKNtK#SseUdpcrWC#S6iD#gYe1xATgdxbbTVc" + - "x$0t72LgUlxE9lN7l18szMGhs4sBOJp3QY3FsbrRdkigVeIBylea#aNUpOMqQcepTcL9e7#" + - "czjrht1CVPTez#L5uUdpakPlVZZ3RYZFs3rOhzs3pOZos0$TWOzcEDDkAC$PlwynbnwKhTd" + - "r7oXFt7rMhtEqAxgx2y8qg4NTu4Rjw6UPCuZ5CYfBK5eLBsaKwRFs1t4SmpaJS9wXp2Vaze" + - "TtaF$MP8tXCbJts3Se$wBjPWB#OxUVNnhlgZs1DxaB3VRc7dtslAswEaxMxznhCqx2jZTtb" + - "yBdPdCpilprWzNbzvE7gi7c#q4L$zs8kpUp9sSq$FzNBkwRsHZjrleaY8y1mdyPl9rP$F13" + - "$bB7vLKUHqYSYBg3RYSZRBAMdXZzRKXCvoTX2tY6MPKrdx8sUpjj6M7bj#ZeuFDMdwhDwRB" + - "UnIfeRyzLkVeyGid7iRlOdoqqFTaVg3pn#eNttorrzC##U88M9JCGBXEVuSTOuJIsgUsFvO" + - "kK3#21FtvyX3bPoMFaJJ73fxtOAuHIpBt8lzGv5NwrLGdgKd8c$Y$Y5obfBJqjCq7K9dEIk" + - "8MyIopAbinDTciRPfbfw8l8b3yqmbfwLtqZIDpd9c4BU8PPbJsKYjCrdRJfQUYBo9G$F1Ia" + - "vBpqQ$RYz687UsFriUJESuiInpUN2ireDPssoLdojluj1ya9BJqjCrpQQpF2Y8MyIopAbif" + - "DQ3MDjqIqz4tiIX#K0bfwKFq3ITplB086uHopAdif5Q3sHj1rXw8l8c3iqpb9oMdgNf03hB" + - "6K7S8fPbJcKZjSvWRRCiFH5v4uVcGvISbfwfQHQTvI51t2AMPIuFYTLw26kRQUc9o9iuD4z" + - "NSbfwXgQPT9RJWxX5BCjSJe$LEfsrpR3qHEHD79gdAJajVR2c6NIMquAuHIpBN4wBrJgDjH" + - "riwOd8cpWq7w3ajFH1cWwcipmWY5l4iipb0R5Q3s1j1rbw8l8c3irJbPoMFb3JGNIMKuEuH" + - "IpBdCf6QftAsWwqz4JaJHoQvoevBJrLqu5qbdE3k4KiovpAHcgTozgcMdeYyYPkqipPtr$J" + - "L3fRSOjOLlEaJxnSA6$Y9YsGtbVJ$dIsuXQnhEQ9jSRAXV8cRj82wRqrxKjdAsuHosgUM6k" + - "iN2XluYOja9wiQMywMt6BM5Rpn5fZvK9v4pTfWVG#cYRJsOfRnBAQ9zOQAnVAcxX92wIdQD" + - "g7pbRS8fRLFB7MMBbGtiHDMY2zdwOfTBRY5h6ivecrnig5yYPkqlGvUAROty#vEUbTfuMUA" + - "SxthbEb8HfsbadwDuK559CBL3YNIDfmvuBeay$#Wsf$AHSOtVw3X9Bbqr36tdtgJ#1ouSxI" + - "UXigl$TqMHZpjqS#lmSR8Gxd4g7KFETQd6lUNfVMnE#uspvC9KxNuXmQ9QfyVbR97mNQdiy" + - "nChdOkVxPrEFzoMh3A5qw9k$iO#8c3SS8qTtdVpFpHu16yJb69ZVvNWFh4BOyjsz4c4gSsq" + - "UXRP72$$6648TpoUIcjczRNJecxzrauYODn#58uU#d4E9mBfdSrFOThaihwPRSliF3LEBSF" + - "WhDLGUTmTUZSvo2tBJspLNvMhgbaVVkCEMD3XpprK5dq5m#nyZaYfIFqf4aR#8c3SSyTT0P" + - "D9$FCJAvgVNDqwMLTCjGtfGtEd0SfWuwW#RnEKOcDrRBM4MSDzQIRXdAc$961uv3rK5dq65" + - "yZjDObMjg4PUP6ZK$L9TcqlKT6gQ6DQYvpRkLIjAlEbIwqaI7Ttt16VXHHwsNZqPRx#7QdF" + - "xLYzAzITx#wfwDryAQsnwLEogYcE9U1s#MTvYd9KokcpMISIAPi4uxh6BoJgCv2DyPfSn#A" + - "i#dDM41oVeBL3YN6BNcyTfKdbtEf8MfIeBhsLqHwzaz$hmXfN7kBcAsaOmJbmlRQeN36Ckf" + - "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" + - "IdS0ZVOIkfpdU4qziz#AFjsH8wKrHAGy$gyNCSR2CGxwzDK1bGkanXQIIj4#BYodqQfoO#D" + - "IPgPWVTFYKZPQQquP5qZce4sMulsYoI7jqz9mi6GY3fOo7xN$D58q9qNBZx7iCaw851nZOd" + - "DZU7sMhnqYejqkbuiZft$amlJM8a$ex#$KVPrfaRbn7F9j73Lo8PT0EvWRAnsSqjfnyPL0N" + - "9tOZlZQeJ24gNgNJkq8PdBKXBDkXx#B8YhcwzMEvz4a#voBL8DWJ7XT0VcnaUjbeRI5CpdN" + - "CCQ4XTtFOs8jPyGe6MaPQS9ClaiqbJGPp7bQ7c$7ECkIuRKHMkOlL4IflkcbiK6##Oo9ba9" + - "DOon$Ktqp5YbNM$S$5eP#oJLen0Z54O#9zMcENLMz1X$sAUeUmq8#neRxb8HxQa7BiKz1Yd" + - "bIbDi8$yfqjqe4zLhxfJ7wVdWhlTynBO#LIhY3taQLICZPC3LdezISZLDpEgRcT4xDwPgQK" + - "v6QKvMQqpqrfwUsMkv#hq1AWguzzRkOehy27cVrVgp7xHJqFlb0xCv09fY$4dfyUfuUBzO7" + - "PgHQPd5gpd6fEKjISqvApJabDUVAr9oRKdDUICrvSsLxkkYKF6Dx9LF6HBsXo9vEIycTXnj" + - "sowykEkN$jvRNVP$dVlvWo$qZuzyfyThBztdKERq$ZHGuft18w98BS2JCTDxTQJE3zudtMK" + - "hELwbbla$D#LTgpdzIw$ajEZV9AQ7TEOnpZ6urgJYhyArHqgLlLMy0DxqbzmrwGeN7odsZX" + - "FIxA8zpEKpdAB6gCVAkp1uo$8tL0eJfhiEVOiHFdr08PnN#SvGqCWf5z#xvOlGFIs5AJII$" + - "HjdE3##qrOJUYbJ4WhonmlRaO5$9#MFz8vYFer8gHMdby1YM3fuM3CONsoQsGpIZCLdQxEk" + - "6H4RTE4jUXFuGkwOpdt69gVOLd8XU2mcp8qwIZqk76DDp4tSSE1pXObkJ4Mk99gAfQ2RM5i" + - "t5Ec9TiPvONsmWMeWoqLAq4gtXbMt5XgATs4YqXtzs41r59uo7BgAhA1SLeb9KYMwYk#Y1l" + - "TGcObFHIsmcUejgqKVqHN$s4$t5035G31A3nUQY5dORAhOGMufXOhZOIcmjjc4hZXJRYL5Y" + - "Ux63s56C5Zi1ySwyDnydnWCT$NfYKWwwAHh$r0RJaXveYOEM4DBPOewOAmuLXq7l5FJ8uOW" + - "td9OqGKkUZM5pW7eAZjP0NNSjkGercPQy5BIaHs9B#W5rl2KJn6DYL$64s4tiBlOGUugznD" + - "vYdmRJ3tFHej2J$YJ#p9vqA$gXeRIWei6tO5wa1OvOo2sOr81Qi3JMWlsv1TCQK0kSI0ig6" + - "c0BebwKqLxKhC6qO1wqsYrOY3gf1LMDBQYp5lG4Ghi5pHjS2#QXpeb1dTFH1ul4CMAnEBQ1" + - "jk3#1jc2jcW1eNJWILw3RC5#kWNlYlV4GOqj#CCjMBgIBN1qAqmBrXQJwmM$Lp9#seaI$lq" + - "OwG4O2Ovu7#7wmL#w1ptBEuhwmDgiPApqcIZcSnrDG4aevwCLXFBWUcdJ$IlH9jfLVo0#1D" + - "ecG9k4adBhhqtzIcvJTxw3KHzOpsX0M1kINHiIree6XBNqzV8oSNazOIrzRYDCzOFromQ4j" + - "I7DMTUMZFLtuAeVhCqRa5rBtmlHkT6kgzwkhuitwWchKpBM7yLFzOIrh6IifBkXp5drvmDj" + - "6v1TvvICzMVnhmQpp$f5$5fFMCiRqFnQkbthprzBluPP9Ywe9wn$BnbhithRPvM#nZPYRSJ" + - "QYBKHwrn#ggC#iBuGO6rMz7tQShxFNmMaJSJNYIZxeRRwkqzR#fvyOt5FFTd$dfAnEkABUi" + - "BwUCbOoyJL3UPQvz5wcozMvhwNKqzOvvUCjQBUiAwCNPVM4zP99MET1AeVhAL$D$oeUBcUi" + - "BvJCjPFCC$L3zQ99MFrnEnwmZfl9VSDyr179lNxtVhTDuH#FN6bza9fRNgn7jiKxaNlAB9D" + - "6$6p1IxNiHQtgZm7vp$usxVMzTIcjuCspIwoJHdT9a9DE1rG7ASZRkPsr4#R9fRiU$k3wcV" + - "iPrRYsOxw7CsPedSgFUjzvYyMQtCnjTwnhiczlwH1e6pI850s35lUrY1Gbgt4lcdLeymWXL" + - "1MvQ0iqqzFEaYXEeTXnpOF7h2sXQA2KSPHB8NKgU8qna8epc8Kvwwcvs#ReR#f1SroMj1Mj" + - "s0$N1#z90v02zgBkmDTLK3J3MYe1OIcB2yQuWvQeB3F1lPh8UyKrUlVYn#0PYlzJLQ5E1Er" + - "TiDUCAdNQt9#PzTFxrY60GtXd9GNPxMO05IxQfm#S5vNDCwji3CSA0u9SD9#jXiq9UFC5C3" + - "vZxmuAo8u7U3qn5oKA0RdFCWPd3rGGZqVtIqHvs2KYEBifd4s0rB2sJOlpge8pcR0kOpH5O" + - "VJ0KwFSPAaUH8z2UVxEVPifd6#gktPlKHxpaFekv9ndeMI#N3IlVJuh5G6bBN0eFRJ#L3Ih" + - "jl6MOxQ#W1TSIWd06L6xpkR5K3PDWVbsq1PeL5MvKNfe2uFjHq8d5T1iapNLGnAoXc8#S7q" + - "kIiUmwprH2BAsP1EikMPG51uHghckjHyEfl35u7FBn9bsEFK1nCXVmxgJKAv1F9nb1dKIgE" + - "mS8#tXnNDZFivwZaByrS5re9YK9PnZtlwIQ0p41g4UbOaeYGjSPGqUYO19w6SbnVb$h3SKZ" + - "4DgzPIoD7QvI3NAmhb4fGTYBcBK7P3kGKeLus#I4BvW9YUWxAARTcZ29JBW6uUeriAlrGe5" + - "nQ9iYhIumzZV3m6#JDIvlQg79HlCifXHQ1qWCxJA1tc6TvB56TBn#hnsGWvo4rUWQY#ECeb" + - "ZF96HdbcNfIpWvw#HjTq0rRqig9GDkFVpS$MTnLfHIv3Vv#JY7AP#2Qnny$KFPv$z2m3Ele" + - "y3NGFeqRwXKUR8bTpwZE3iWbAJyJecPI2akwUn54sOvHBYa2vFwCSZP5#0z$ZRm9hP8f4UG" + - "QlvRDrZple1m#QbwIWJ5vxp7oPAOYItXr1A5MFNoHUAHBbWJp6ApJASr2sk$WsnPRT4r2UQ" + - "SsN#KTFiy0lbs8k9rxDTYaEfJrwUl0yj0H7iYq7vw2SpIWFBG9b3w0R7HdZ5p7sucsfUdnq" + - "qESz4r7#9y4lpxHwFBzVEkXnZtStDmJpI5F#RN9Xb1DZVkdmB9PyJoPjJtGcPfJ2AAS1PJE" + - "SPmFbRCPv7TTLt4n4jbp6AAlPCyjmp4z4IMjSqXYVXnB5h92XNxwgrvwBYbnx7FPBmIYRWj" + - "IlkfBzibdEFfW#Bl$2VAtKNxZPQyziHkUXdapWNSMWhC1O6OY3K9u3Ne6QcgJCH3i3OHpb6" + - "A2Sg$Vg7#T5UGfacw4qtM6cQvubGBK4Cs5nExSpW7AmlXj3#3x5DUrdYIXfpvIqzYmHppFA" + - "C$AY70sv#OYNGSz7VDp6DHRdbsJBPXgbm$TJUwQCyPxGcRIE$njxdCAZPpvqBuCCyGfnjGu" + - "LDr#Iv42KKMDyFlVu7GWbeVndmXZ7w74SvAp5NfaFvHtSYgku5hB6VEnHoX0lRlJC3zQUkt" + - "KBhqOykSVdvw2iW2qflJ1ArTTd0CjSnliWZvtXHOwU1uErPpPabu2QfOmUoesZdCjNPshqR" + - "9mNvJsevL6#WbFuNa2vfKNEbnxFb$Vg7gVMtiiy2ULI#7iSvRriomhzRLZ#w$6N6TqhZ4w8" + - "5lee1cKBtb#sq4yJpnNcVzMJK0hUUUNEb$GXb28loYL2o8HFCIXPRY0Ee8oKJK39wJ6KI74" + - "v7IXnpeCo2M4ZoaQKZIWRKJQYR4JPYB8HPIFAHfIDA1jHDg9iHDc8iX5b8yh2ACMoKb26xq" + - "Rbs09n#CgWf2T0SFvxCafnSmvAzHvDUbPaddvUx2xnLx4SSlHCncyA8s9bgS#BEU8Krl0Mi" + - "3OLVoECa3zFzCRv2d4btt7h8owbv$AGiZaqwEVo67dIDsSnEz2Rq17Q5KVqJUZgEH9WHux2" + - "7hwByZZ6pDWHIiD#2lBuRQ8ivR1zpqEeD$IH7Pe3#wNe8OqTHtxi3o6rE#VzZVJXqDYXRwN" + - "UufuNFNd7VfPt70JP$SM1eXbu7nmrEFgB0LBoTqFq3556##AmU6r8KyyQHlrXF3$vteTHmB" + - "QXJSMKFFvGpXggk5UKJOThcv8$a4txaS$c#WCyATUcr1$DhD5tARyPlop17soRJaLj5Gc$F" + - "A0HbybZKzMwy3t5X7v$hdT9eFqKRjaWSRmu8VG8SJx2glJ5wJrcUOI8eaTQ5EqafDJYQ2rc" + - "Y9bYLjHVSgHRgDh5#3njYumioF58PRzNckdfiQRKAkwPayJ9GTj8yytfceE#ePvPNg1doDj" + - "hO#ZVChRBLmVVtSUC2eydBTGpIRy1EWKzCv0rXNvrdbapD89B4#sNDiyK7AkwzVcUgXtECx" + - "d7lZUL#WySCxcsVr$cz5HjKxOzwGYViKvQ6MYi5e6BS$FXQiAuekKChjOXBfm7qOne#Ni4b" + - "tgh$Qh3nVDH9MOtvEhr#Y1U#THSbuCBgqo8oq4iN1U6iMoHk0hreyOLpW#3J3#oth0VJycP" + - "7uRnJ7PwqA89cCbsBTfUDQNXClubdWIV5xDN7DSImeLZAOvJjGsAmgNzkJ0kpcEz3rYuocE" + - "ur7eUugg9hkSy1nThh#v5uQfbhTC8YyOL#1VgCBXe9RJzAxhBKFPRJVuLpXEyc#ZBloSW$w" + - "fAw4UQfQaVmptX$gkh7oFp5$gHqHbxDUMdGgr#LBk7I4#kKdl9oExPu29x1UFn8Uv7MjjI#" + - "f6ifN45g6Z#I5jfy#xCw0tTv56tqYueOQKjvvcf7xmDQvNeQVMYsa7Kf6eU5gwqXTOghYEs" + - "qahQkHMnqaPMowILLbrd3DBNBk5AooLvhy0xpIJhwNr26yn#otDsz7aipoN9nzqybX#EFS0" + - "yFHlJGTYjVZOrQ3#biHvYFrjKcxuL5wRMa7ureZLBTJKoKVTKhKQZhlOeb7erejO6rB0Vpl" + - "kfgn6iUxrfPyzUqOztBcRdN2k6W4#dyIMJhaRYEzPcqDnSpoIKUhx6j7RwZZMKvZhs2ppPO" + - "A9VBv6EWMnFzJRuS7LCk4uECD5O331fH3Hx5Rpk8HoSVu2uBZAwUjEUcKDqVN6dRQTyc31B" + - "fc1YNKLXKeXOuZg#3Wim1Udq2uiefj0lavuqYdWJUONT5qKWYipL1X7cwjvSlacuJaIygGO" + - "eMoTwax7H4gm3JVavsl5gjw3NfwAkLwKChrSjR6xAzUe3#dSQ2TUhUgvk4vlxeJdqCOIgjV" + - "McgDLIgkiQSnLxI2bOWn7THzoKYzNCU7cmvlHfz5F4jNKIgk46LQ85yrpnhqvKGUb4LFLbg" + - "qPKZQWQKJMYQaJrVmMLbFpBE7MTturHzSov3rgJX8htWiCaxnTM7fMOmkURR5JYBuHAIeMA" + - "ywcU6AfaMzcxc3zggpK9bRK$puCgw1DxntVwwhIL$cOeauvAwoHKh#LuLgAtHt7z4Lj5lPs" + - "$COZPIjp7#zte$IJx7iS5uHXCt27$OLHg3ERqO7vKpwn#LEAPab6jcRPQPQYazKb75SmCzz" + - "MDjvU2AXVJwfz53QhWlcmth3Wz32hKF4pVuQnHt$eet94U72PNqJgOEZFyDyslT4tcZbQYN" + - "#dlFwU90rSjgZNPsyrEHllL6hAJ2MmrB$GhhZcyamHKkdJXksXJgEQWjjWzQjKcFW#YccNi" + - "7dK#pPnRLVYv3VrDTctEdNYwerYMNWFT2vFydGtpRhdOnVNydStQmBvEBdROBlNf1QdkH9f" + - "lwTVEzyn96lPyrb7OPNWNrc0Ft$jqlTPDxx6QBksxwqLONkp7TzSFIBAxhb7vJ6JkBDfdne" + - "S#e#zG7v3hCsbspsELakoE6NobxPxkx#GpojznJ2y1UtaXkwyQxD6dKjAmnxuLLFv#UdxiC" + - "ltxf5LiT#oH0#nIMcErcRAxxJD1cPNs6UFl$Dr4imJDXR0NU696#NlQ4pE5HchnFhDoymnz" + - "BwthESN67jZzV6DtSN5qdbcLTa$iqV#JTW$6wld1MBtOjiwgdIFNBEoDTi#FNKO##VPYMc8" + - "DillgmjvezqQxDzgzOM1lj7kZtLSEkoposkF$7dPzNLd5trlrIDY$rrZNguEbVPzWs1$3Bb" + - "VR$bs6pv8bxj#36XgnDs9lnDw8lLxl4pIkJMiUTYcZsAMCVkzIx7S7zBsBJFpkW7sc9Wrx#" + - "dS7$t$RVHNiPoA$sqxwLO76aFAh0bEIUPvV5HJ2BdD$ZL88#$3$czXbz4cR#Vnhx2F4aU8e" + - "SRJbXUQwwSG2O$K26ViK$qkK$x#nQruITb6zPc1VrVuUnPxxMPF7QYFsbS5kVQyvB#hhiLz" + - "Q4lOJ4#V8iwtlA2yi7VlA#tiZzaRi3H6xbjDl9sRiYNE6Mfj4wpK7kvYZvUPPsAVAd7rHxh" + - "fQn9fwXRWon2wkNzLpP4EsUtrYNrrs5myLZptDPxJ6EiTUYjqRiJTYJy9kviWr3RkW$p#Zy" + - "RcMnXwtU6kMIftVHMLidecy4Q8H#whrTrdKbRR6NbtVsCLJQoBsudo6iAzvFjEG$RqHUoFs" + - "HkoDs5Vpde3k53JHykezB57qPdvllUPX3sJdoU3x9ev7hzq6gQTl4x2VNSzxu8ZTOphMO9z" + - "fwDXPfe3Ff66NQ$Xraze32s5TDpKHN#LAcPuAtqDT$3wItaMsidOts6N2x$ULtNb62h7J4n" + - "Bn5fwUX5qMyPsybhxbZs9FxC4Sx4czO#nkbIi9#yhOFMci1c#C#iDZTVLYByxkATWBtjDBn" + - "AxVKoZplHtzwfZ$$KdycVcjEXvxEpgdgNUHyTlH9RrpZNIhjm5lpYDMFIcX$cUxTLAjgh$u" + - "lMALCHietVJkneHQOG$rJlPvuVitgLRrtcmE3okcrM7zLitgllHarUgK#cyFMstNRsbPwVf" + - "r#Vprhq7jhxjUhnzVQworiTR6MXjhRQmrgLPEIwbLbhZcwReRQssizVzOhTRlfeVbUxUDN8" + - "dt$MeDDLQOtqOIl7Uyo7RYwYB#PYSLhrJltJCeUNzOxDkAh5zTWVVCHHd4Q3#xkVK4qB1al" + - "43PElwUOgrXIcw$yBLuV1uzNVLBSVK5C#YDGJtsjNZQ$lcHN3yeiRw4UmsDxOksJygwRLyf" + - "zIL$Ifat6avzrknMZdbZ5TR7$tjcvYTwzzf0NQDv8rpHxGlU1qNlTQJdk8Tf3PDnx5ly32o" + - "bcikirjDzMVlzSEQUZJstvRx9xon#vzcvMiAys#oIF4z8LbXrvhxRJCZmtMOqsyV$5IhiFV" + - "Ml4bHxaUkVcV$J$4gdvRMxRddiUKFJShRPIhOyy0s#hw5y8wrMSRjKxvehijPWvLk9MYtvI" + - "AsSyWTh3TBorChnnbeRQssiTRNNcgGfCakO#RssWAQSzs0cuUUvgpOVAgKfPnxK$vyIsOKN" + - "eolyVeBUuip$8gfBJuhQLKn62$SjQDUB2gwrQesY7Jtj3NecxWt8hcPlK6ljGPwslZUhj6e" + - "jTErYhfUcg3fbxlUKyJh$bzZlTfr$o8E2LgXtB1VmeEYwNWp#v16mUl3$iH4GjKHXhsLRwB" + - "Ut9jj2eqhmdrpyeV$ajuIMNSKzAPE$poi2VIdUhoNfVsRLtYZFymFw$e9#buhC#N#c#3yfQ" + - "urcpaZ$DoJQJpOjNcFGpiH$a5RbpGurgX7eQs9tQ0fe3AyVeXWnu$McwuSenc8qSkfeXJ79" + - "ZgLZ33HEYhOw7MFCEtDRNSI$WtCk$QjWFez9kFyi1AuLNFuNnYAkGw9jjpHLnCFwNbErRdi" + - "JsuVuoijOSpZ$DvUPbvB#NSsCdubAhxx2eUTO#YRx9kiTLfnDWIojtVGiZCisJPEev6$hmo" + - "iqigT2rrUQVsgiIBGwerCIGNe4KUAL#2f5PAqgZ8Yle2r4vWgQRTvTqlLpmdmWpYARqnMqF" + - "JB49Oas3tSmtVH$YYTffBjDiR6cdzn9dM4Cnc2iNPVc5pZkpEiN#SQFGQDMXYNYHDqFfoJ#" + - "Blbyz8D2Sp7VGTcOKyqLUV3lwqLvQTxHAPxBUReW#c#N5IdbglFF62WtFA8rgtcruyhO9rR" + - "ZyAAVWrZ5I6FwgWlURqykruYZtd7e$KhmV0tFZ8auCFOLZjJz2k4mwwovAaqRRPXrYbWBYn" + - "kPjYmmhZ9PCR5KMJDoRMl6np3BKWcrpj0$nwQyTu7$dtXYx6uzvZVxhgFMkBdIorg7sHRBr" + - "QfBg9q6bPWKGoT4EN1Lhgx#CUr5orAH0SDKjddwlg4CSjhcET$bhSsXIcdjnI2hLsdexblq" + - "Fg#tPPVu7PLGjsePwIwiCMxjoLAg$MgeCVZMbZGMsGFfNiHfFPCiHRB6V$AqfczU3p8pJ#$" + - "Gq$MLNsLWAUNfUJHgsK0ZoqvIig6bu9F6KYkbKPVjQzq$gJHMAARLBACrfepOtknrIaPPGN" + - "bSBUt#ytaSOwJ#ZFUGvI#is$ONTNLR7VjsgJnbXkgjSLd$lCTj3lzvhpBHTwhJldNZxvVAB" + - "RzbRC6SCAtKPmvYgrTbefsgPS4hi9XMx21rEqv9RCNvGRqN5p$Z5JLxn6UyvtAlDLWYlDQe" + - "pf5GtpwbVkzfPklqyH#jWtV31Uh8yS6fg4D08kyy4szBKZqqFkplE8DMrDARE6BU5BVqr4J" + - "ld1GTDPWbcl9tdFEY#e9lAgUgKPDZH$NqnbbS3tzJgTj0rnINXACcQ6Ljtjs0RSsfiTadiW" + - "B0hfEXRryzTlFksFwGxpNA5liDS7K9Sqkrcbka3ESMw$hxlDItnvaP9y#rhJWlEaUAI#CU6" + - "nsJulcL6vFvvvVSUd3#W$Ku8g6M4kUnujkICsfoLhd2cZbjDMikxfwYdjS2hxFk7uL#TtvE" + - "#RDO#joetubBylbTtdlxqHr7svHsbIVxLNnN7Q2gBUQQHOUZU$vySsfUTA8gUFOl#EPGpGW" + - "vgAt$FCjvzizwof4zeKRFAhHw30w$EKIDmwJvvZ3fNtyhhLwi0JAzRa17Nvwxoh3UJS4Ldl" + - "a7mx9mFyZFYatBVIen5g$X#yBqRUDr$Dq6rQAm3bF$riTQxvJ1KqE9xKtLAcMebMknjAfQr" + - "Zojt6AjbVyXqNv#rUmRubgYFdCMQpatrChy4gKrGDOxz5ls1lCjPEJVz7AbjDQer0G#JxBG" + - "zeQazeRWkyC9FAeAI2LhX#Ia60ukPpthLPJKgaGRr5HhpqabuEWTpXJw6aXB9LXzKcWNpat" + - "4WLgZtzfE3iPZtjRQskronVW8VS#Jrbh#dYTrRkJzjzsEjlfx2sf7NqkgFAMrlNDMWiHs95" + - "$59kpIqzkHz6rzssJxy7M5UKfoalM41bBjw#KmrVO1On$sgQ2VbHwhvOpOxbEshP5DI8tO9" + - "w7bEVxMExHah0rv$25SItDRZfJ8ADVhJg5HE4b6dp79qt8P#uJZ2$DeT7o5#vISUsfXop6F" + - "KXlDawAr6iqbLecWNckbd1Ix7wvR7Y#LvmvwOyxH2SzY5KZ9esjUnFgzhTwFzRYTWjwd7Zy" + - "tTcSWwFtIUhpH1rPTJnUTacTihroAFQknDnJLqsaf2VDmOyiRMrvKIkxdZxOS#xZuTqgqsk" + - "dxKGLQfUvgqhK8fqJkC4uM$HhiJ6VsEYAqU$hz86c#QodYha7mVNN1Nuz8wvkUVBhrlUVWR" + - "XRiteJxvWyWZQsm#M9j8xxTriwdM8YTGssjdM8PnSnRRio#DumfQ$6zk5hzR1sjplfAGKhp" + - "xJFQRprNYvWUNzesawMrGuoFngYqJBnkiFV8AYMACVgnHsCalJRCZLuBIRqZJfAFIuSOqtD" + - "JTXmYSygnWZvzDyPfL$13XN2c2h77GKACdoF4nEiGxow4sqM8UTSWxMKX3kYF#6v2D87t7D" + - "XCgCy1GXpv0DWC72ZZ8UxjWBHNmE6pHtwCz7V1lqUTKy1z8QQr5cBl7uKugXFI7WNlXxJHG" + - "aoT8CICiU2dWwFEgKyAiSytGam6ZgON8TmBuVs4MEiN8JeyZF3bGdHyLOXcTm77yq9qUX3O" + - "K5UJzuLeTIBmduboGy5HTuSXGcnubH3jra7uCY7c$0rvXo6l2kKd8lu53c0xz2paFmBT$nH" + - "YIYleXym#QDkKCS0v4hALIBiHyLDm0DyKjB6ZX$INXDYt5iTyO3a7QPE4MFj87B13ym4e2z" + - "mEoY$UHOZEs#6u3ySnI8VyiSSZ$0FgkGNbRqSQufdr4VuQUR1PPhOG#tL3#42q2tesHBdE8" + - "uJe0njCwmFvFwF$lW9$GeZ#m7hulo0x2#LWc$tGrnkYROUr12RKAQ2loxf2hDiEUR13A#XS" + - "TnmEwEW4BEl21kl17zQ3JTVx3JhHxvsU1NyBEW#7RL3lVlyGOdtOiikEGkmFlGSZFWz#r0u" + - "oNROHOYxwTrvVy4sG1jtxxoJ4WE7GyQaG6rm8FS3V2MtSVodaTuSSoZG5bXOeC$Lt#CqRGi" + - "nw3V4Nq0ROhiMBGfJ1tygwuYZ7iGyEO2ax0iTVSS3sPS3PiZcE2XpeevPePqlOl#LHEEx1W" + - "Nve2NkqGjkxd0SEFpZg9t3Oh1LyOG9yQzOAu9q7Msugn5vtm9ReuxdGstfh8QQVByI2xs1R" + - "r74q$F4mjBqry1yD#y#47n#6#gR3xls0k$$TGjH0zZ3uR3$umGBuzJpq#G9WFlP#X366vW5" + - "RQ$JBl5Dnt8e3FZSFzI#0paxm$sR0rWPw3uTT#mo27ur2V5iSQFFHyEMrhq3uKd3KEUWqbF" + - "qVP26tu6PWFWx7Vn5#2EtPGuY169CBteFFLCCNCJRROAmS3drTpa1$GhOpwkq2t#lmENpaR" + - "UIZFxkW$PtGXZRmopOOgnrHp#5d2z4MykDWymd0dO5yvuK8enrDqNUxeWtheE$d8xpET73q" + - "xS2de0lo7U4BHyDcXnsDut64uMFpuTT7j4SOiatHthRlG1POckq5dyLOwG1$sl1Qj0LpmOR" + - "VWiD$sws7SXZRyz5s1pvSynU4WNN#CyY3RVRU0ENWnvCw2B4HfhYDu4iRmJy6tWOT9o0CNz" + - "uASy9ysACz#4QVOBw0Jnps0VXC#1viCnisdmrRpiISr1S#i35yQZRcnDdKBy0r67DILvexq" + - "UxD8TTr83ZykIl2cwEkhl3vhYWt43ur0dus6B8Z3iOOG9tJ83S6ldpqkP1P2nnpPeSo8RO1" + - "rZ7JO7FCXGxwgTD9Q0zilZ7gs0Xzrknf8Qh$Zlv6kxR1$DQXCyAOizUczW3l2BI$QqzmjAa" + - "JxDONPRR5tDOP6BP5kmTW$kgy63BeyoCmPhVz21pp#SXXu9F1CPSUWRdW2FJh4S0s4lvq1F" + - "nu$yV0CSzCHRyUyI7QX3xjXBxi1D$Q3k4kMu3VY$v5Euu0rhuOQqTIcu5lCFfrC7GCUWxol" + - "z3Fqt701pR77D0LyytcmD0L$heE#hTJLeXQOEqCeLgCatxmtqxmXL7OozJ0puO3GnS71p3N" + - "md#6m0yEWLyEWt6tmXZl2FnTCDSDmTWQ0fyP0j$T7l4#Sx5cOKrnuID3eNij#ERG9JWm7sm" + - "1tzi2OsCBpBbheSrReCrRed#tnFoz9TQHOHZd6M3D0FjQqBiMncuJb6a27$PWmtLXqwuOBr" + - "rf7A1VHc6jwByXsek#x01Tmz0$mu3xQ8plSgmbmz7lmyUZBEGwe0sTeMV49U2OVmv1$GV31" + - "btGPrtWnzFHhYwO$mQYBUNmztBquNJewuevOSIlYAEERJ66kg9zss9ybSEEMsEk78NvfolM" + - "fQ7mhN9W6GcS5V2FhJ7dRG#$AaUVb0DJ1TRmaV3fYlt1CSTLeD#sW$qhrmQ73rHY36w7$gp" + - "4#1e5crIvuEZZAgoLsoDSTHCuvhmgj7DxZFjkiCKEi46tgy7H7ztWkpjW3UsEUMz7Z8$kQE" + - "UEc4ExOnplYB7U0#l1QFHB3#0QZR7P0tsz4yPXJ$JHJi3O4sDj9$XsJupBZT2t7J1EA#3Jp" + - "T7#vfYZcsESheEzoJeBqCTeOn$CjUjWdLWNwqC5iAyB6ov4kKx8NtW3R4bp2$fn8ThJ5NDd" + - "LzYi2ThT5HYxeewAwr46yVMmTbJ0Dol89XXJMy6#vKqHXa$Km4zdermVZD5Ey8Mjg1$GNxE" + - "nhin6U1lWA8VFpFyPyotiE0TZPWx6unYitJDfJa3$Lc1DdmDVcaDp4#GwOiuO3b#jmB4UxB" + - "OUTAqF#J7mqGhux1ZidpQf4M9ds6iJ#C7Em5u133jZdQp06Do4y0Dd1U9ZCTUl2vyQYtco0" + - "dF5Bct1uLkROZshHfdAZN1WNEu2#yt1EhCBycPYBTuKnpYiOvl2TyPXpzIBR82zr3ZCSxqm" + - "5hV7dD4HQypwcEi5zdfzK6yb#c5zbD#W1tmBut03wDWURQl46Dq0SsuBp14T8LEEyRuknd8" + - "bi7J26EYC$XcFVfo1kME7xI43ss#5UROSyfKO7orWbnPlmYPOQsR0xXFHhiejWGFzlLb7pE" + - "l0FWdrzeFk3j0x4#leRi1U2Vlk1kmryBSQ#5HxwDuA$TY5wiPOAeDlbs7kdG7P7R1$sn7Ze" + - "mosAuSFjkmD6wAESlHB9MpV4hPlYN5T3h#jn9vuF7nz1ifEQ883yGaOknFXUwsWgnNykXNM" + - "oDOO8vMOIoR23ZCm5dV4k6gDFKqb$AyzU7liGIlXanjZBx4ZvjJM60CRNu1nZxbp9lpy4DJ" + - "T4MDe9kRkRNR6c40$bMCTwmYVcuNrOH7cX$MmDol76Ao1pVgXJtT5VrVIN4a7zZ6Z5q4UPN" + - "T3lot2#bY9FjuTjkxu7xGFO#f8B5gLwCV#M2Fxxuar1Vk9IinlbRG7XTzLOZuu4lDhCuoHO" + - "r579Np$IDYd5UQUEMZ3iJGVO0uw4ctRy4g4KT#HQ5Cx#FhX63$hmzxbuFkZpwO3sqPaNvhR" + - "qAQfc1lcOlyt2BQfn1nnACRAeTZ7x8DsJiQSsWbhpsJCBOlGlgvepsJqVrUCkKgi7vMO0nT" + - "X3fsC#R0TT5J2tolHXuimPqr1dvJ3NohHHyUWNLEsmW4$dGAx7eFzmHJOsGMkIimDbTZZ70" + - "CRxBiPz7o6EDQ0IlJ5CV2zVN7TKuvhaKfg8$hZ68pnVL7lCPY7Ab7dlbXpsyDFoj6cGz7#$" + - "gY$FyRlpaWV3l#VYFLYBCRwQCmpi#3ZvR1v9UQwSkpBAu7XGFZNhhW#gFmVFUeBlUXxR2l4" + - "DDH$87ou4$fj9ynz5V2hAeoX0p5UTq9xZg7n3hq7mdyE0iw3u6Fbc6kgqBOgsF0WxCCFGfq" + - "33i7wWJ5sCAulXi57ks8CxmwRx07xT0N#SinzLLW7Aj4tnm3x7f2fmdYgnbonwp8XzgHwuM" + - "Ux0lUUyE5op4jLM4#geFCOh8zxOmyx4tkGMS2q6Fqz5$FI9AGTIjSnc9SyhFaLaAt2Vg0AO" + - "tCnzI$MztBuPHNcW2hOSp7gdq$rO4yy7Vrv1Dgr63Yhu2kJxiH#7FkltR0k7Gfx70ox7mhV" + - "FnHzNWLVtGtNCuTYJHa8crRX6gSATH#C#V4mjA4DzhAT8RiR#dW6vfuDqDzLb8RvfYbyg0r" + - "iE13xXK5espQeTslCCrjZhxKrribjq5UxmwwxOwmCeZPZ35HXh4o7tsv6OOo13jX7L64ks1" + - "rhr6Pepq2qhmzikmtMYCveuq2qgGPxhogCZIhe7O7rivok2s77mLYZgx0NBCVusGFNJhrXe" + - "ps0jGhzrGRjQOlnYUQ9MPYZsg8lPw6kji3P1tl53J4lxebhdTxOE#w9ERSAOtT3#FnU62#z" + - "4TyBOwyAQqOxrByNna0r#cPlZDzPgByTZhqnPrJZUh42SryLshSO#xSgp0jLM8ThuJzR0Cz" + - "EcBEheAi6$LSBlwv1NRLOZwk0jmfpVMTS1tR2d5YBQy4g#EeOpAjLcF$6m8UgC5QtnRpNvM" + - "JO03ORWF6pC#RL2bmZLC4lHcAVi3DqLc7yjyCuwGF$tnaw#W3JM8px2imzLR3V8UYRiPXBE" + - "i4MO#7BHwATLR1$9$JRBXWJXs3zsmNhUnVuOGlQUs0lK8DvTPT$OmnYl1#EiLA1$2gCwIhO" + - "eJFs9OT3pn6uBX#7$TP0#FvWp3aLq3SN$J44xHw2w$mApDr3CCzNOAxO2jSyEq77MAJrmNW" + - "v17RjZx5#6FPC5UI3MBkhw3u6shqOzGo4dor6FnqBFwz2NrTX$Hw9VL05zdOLc5ScmYxTuC" + - "l7mh#xOLmTYxPNORxO3dht0gPZCIOgNiVuHzee#DPUMDy7O6xeXdxfXl7L3NtS3NtIZVPKi" + - "5Kth3K2SqGtsj#WxWxmhU7Okqz4tRlkZV63ENCIrlmgZCjsm380yqqt#5Gts6ytZBrkg7y0" + - "zaExOJnqmxo$6#QJRi2uEwxDkq7lxfYNks7ks8FgnbhQ3NDnjmFKFQ9PcdVOLN5n6N4LTkO" + - "glitw9at5tKNHUEPDEwxIrXga#JBDVrEyoHwXpC1V51$U8Knhyg3YdHRgklfeV6XRHkiGj5" + - "#$nYfpPhp#OWxC7mjpquRhUhtn6WTyg#bxsWxFAzwiHqpFwz5uCrmJDVqucZRWvcYyUJV5H" + - "$JGzM1EQBwZ2bUF3ENs$YeCznaJXhsxj1xCONlEqRfEKdmTZCjzfiVQzRRY6UnRE#yNpLlh" + - "GYlyIpHlnAUAhqVtezuCqvjYBxp#PRQiIb$$xNXQhio1PM5uWvEIPJRuif2UbJsm$tj8yMs" + - "tLhpLOCtdALxjA3vWG5Yc5QuxMZsYywyAqxUzIl6zzzDoc4jRqtN#S1LliaBnrjMATzonC3" + - "w1TQZrbM6yyzMAjrbFyR5BSylqlpSQtyhgKqUNxuHntsR7gDo6bdyrtpGCjuduJxHCc$Uiy" + - "AkATsYgU9TDTBfKl1tceywO5zjYljmMUzosDIfzv5xvRT3s7OslfUQzSsKsnFwrmxfXlDqU" + - "YdS#85Usyr#jy7tHl4vlQUpOcxGV5yqxx2Ia$HfDw$EquWimpmxihCBR6FvEABSnzgD37bN" + - "XGJSfll$lYk#XvzkH3oWUzYd2scUgiKRKj0lJk#ZvRvSHqFrRcDu1rtv3rz5vr#YqoKZxLe" + - "NxOY$MuKuLxbYh#1PBD7z5yM7dHDkuzTzrUyvHV7kz5cpH9PJPNfVTORCmhSzhjfwq0ttmd" + - "EATiBwlKn6cT$f9yQwZjUxJTBrOwpfZRz$v#51sXozr7lPRdUc#ve$5rBsg3c1i5utlk9t6" + - "WtrSrrvX#dPOzxicsWLx63D#iOyOE2TC7wZzOaidJ9lLIfVPHtCzZurlhtWvre8jJLZRRVm" + - "HYdV1dddBgT6wzyvehkUkGsvHVCPJkhxt5P$TJ$F3DTThz6mzney#MNCz5nvzg#Qw3KS$e$" + - "aRcd#a#NUQ$q$nXSqqRwDvkU9Yh6vJujg2$IhsVLrwvARtMwhuTWkijDV3S9SNTLg$9BrQf" + - "caOxZfBSrmBLE2QjWjT5nrioU9Qfs9chew5enGVj4CqtPcl#7ZiQolcHlCczDTbZzLSZ#i9" + - "vsh#GoXRSQdY4ySWZElOYReVTsqUoeonvh#5Vz7y8IjDZyU5rXg$y1EDqqhZ#rDqt$7QCCt" + - "LUxs3xwHxRT5sT25RNQx2NVNONlY3BgVtXhiUhEw7LIotwiuglkvrI7$CgX$N5#jYhrw1wv" + - "yk8#WUPxI#QkpzQwPglS#e#tmLxqHbNApHdbuhkfwgU2TS3rHGFtnlrQNzUr5pkto#0x8RA" + - "kxfCL9naQNlOiKprdvtgAv$wmxqtPMMUmdfUdteejU2hVwbU7cViEnwDq3srp2#u$LXUBit" + - "md1Np9sLk0wRXdMWicKoxevNAZvJxtKx$gpul7D2cKuZ5L#G3TEEq6Dzt1MwtFl9#ilr7BC" + - "#hlSghRcn0llAzPTWVT9ZVskwbwhtMPMung$KOt#KtZTKufgjSe9EEpjQnwZlel7#CtMPJN" + - "7ihi9gRTNfUZplCaB7wPwP7fDc7Ttn$xLkRh5L564SdxENKXyKOqnyGQ7bREABrM8qCI7Y0" + - "xuXYKyKCV65#61CK11RRQ55B0WKAlSMK2w5KgkDMA5K44IWvTOYOWMn5K742nHHH5HQBx#P" + - "#RPdbjPBeYI$$F$VPMPtozdTcPES0Q#d$$MDIoVZD7$hMzXhftES7kVTDMRaDVq1psVTdvV" + - "CZqciFQINPy#GxTTSQtqo7dAxqryiAckGX#IpbTRVrx4s6tSgqrjmlzHcmcxfxtjss3X#fn" + - "IiajxP47lP8yNljRJ#Bl4JoSbxIt$dzkYzCfUyhmgkMXrVO7NYaybZZc#oEifPQqpiIlQKo" + - "hsNFkrS#n$9dY2nTqtMHXLbVE4bPuvcgu$SR3LNxksSMebt9EV9gPTniZwAXiduoQ97o5tl" + - "d7SwuwCRPCvkgULRdS1pFRfHSl9$DA62t139oTwnjC2PL$RsaUnlnifQEf9xBN#eSzput7l" + - "TQqdstoJFY7IFSwso9irrtX7H0rAJPtWazzcjZqkll7yYsVkEaFL0hjpZnGzBN6xrxZkitk" + - "QSqz0QgyFaSnVbERLhlgyO$fZqF979ZRvFTBdKkFT7oZufxv3LmMVZMcPSYJoFXlNx776#y" + - "dwBHilropecSlRpkLSoFggKytlGwjJ4VTP$$k7BP5m3rrZrrtrH2tCvwvmxnrej78n$tVgx" + - "fbZDNsfrXDoZzyJNSCgg$kSDJtag1LwC#asbm5E$e$eNXp47YG$Imw81FBMIUANo7Jp3Gl8" + - "BYItP40YX4DUoJ7o0$WECg#Pqgl7Lr2oUeoar1p#7CNE8hGz4DQ7auvgdjXi2o5Bd6N#U$2" + - "7wvk7duItPea5VhetpQ6Di6xwTV3lZsudRJUmIIjxhgnz63zD$WMDS8Fu0lZEar17csajzh" + - "#XMZhELseS6JwsZPvrHJQXgwQibLqlT4Wes$eY#3hI3N0TpVMa8mHSymSPdyMVfkSZvNQJl" + - "UqEM#a4DCbmYliJVOmN7N65#qHb02BvQX5z4Vf7nllgHkIwZbvdl9uClU8AlhZ3MugjVq9#" + - "PK$CkyQ#6bFgO$37yCVmEV3bQplXoSXN45VYC1gAQ51z2Ws9r1vuwZZ$EkBVGgmPV5Q55r8" + - "gOeuXZM$M5EDO4JgydjK1grqb$jZFsln8VHyy$oC6jsTv2pYk9x#291gBXF#0x$O6CTxqtG" + - "4xtPvdnHpd#KN9levhDU9VJvDuq#AgEk8vhgiFl9BSJVOES9LJDQ3F7QAJMY6yajnvTJ#uv" + - "UZKz#1vohVXM#bhfqVuhGwXQoBNWDzApaLwhbbdKPb6pwWawpXRrr0lKClYErxLW0EAyBuI" + - "6sNZDFiRkGxysf20qlXVVYpQXJSnn0Zr1$1vpxKPtynd#nk21xsW0MKAsObK7AV3LAx2AU1" + - "MnvbE3hnhG1lGrvjX5VHUwXzmUSkypNpU#6z$9d9sSNoSvpHdoP#XzsU2hPSJBq1de3EfbQ" + - "1bZoemFmLVJoKr7fp5c6jwYVG1ntfSuo$6XgEVK0hMDyTle#GpVXU$2Rq8teQ#YcjNKLgFV" + - "6fGwXvwZ$ev1gVt4#vct52qbjm7TW9v4JwAd31warEVugUYKls6cmVjNl4Ilvcc3hvQY$oV" + - "r1a$Kygp1LvFHoTGiASDoWwzAq19q4Ze9rRzCViPeeERYv#8hqKfq0Re0NSmyYuqcMK9#2V" + - "eKogu6KkeBOItnMdGDkWQjGglGBUWMj0QjGUUZyz7dXMBXnJy185NLY0=="); + "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" + + "ZpvrdOfpJvA3mGtcdC6AZvF6ELX99U8qaZrqI3WfRAVZDix1CPo3y#3KTGRS8723E6UGulD" + + "JNfm5ojXbJVt5ojhf0JSGt43E6QZu$9GNPu4oTbbJVx6oTdh0xGnkPyxPMV7vAI$E0cNiig" + + "R#OcNjz80Zc#d6ETqKdv$ouYnGnYvhwYzMrauFkAxWkd9ELyNdfxmu2vInovhwYvMrqmCEC" + + "r7oR9GT51ydFTyxAAb4d4QoXmvflbFOJiVj#TuXDjyxv9dlkiw0smxSTfopdUBpKrwS1ShO" + + "PKtznShQwG6tBRXjEMTRnUUdl3WBbB7BclgBbRNJ0svNSBjopgwApqzvSHOeOvSrzHShQwS" + + "7t1xWzk2SFHIVd$BYB536BclgBrRMJW#uaU16Siv8nUUdl3WBbB7BclgBbRNJ0wuBk2wSqq" + + "NnSTBplOkIIiHf97leaEOxXUrqt9xlNMBplKkU#Qxh3BZEu3fpJcV5nqdZxAoa4d4QoHuw9" + + "9mKjjDn6sVd6CxEUN3gEWEk4xXEdDD9yN7IE3ifgKISHhA73WadXUrqtCRPAOQpKnwSkiw0" + + "wmYk8#TqL7oSDCwEIWgjXK#9KAotSr8WsKE7X9F2TZfku#oeSD8JxAhLH9o$CNKQHEwROeP" + + "w1xiOwZxbZd1MkX#uJpgRG$P0CTqxLppXlU0jvohpF0Neukpb7uJyNvFldEYjy7x1A9vqXu" + + "cRn6JtBF4KIpphFI$gnUFkbU8t#Ybb#ZmlxXNtYVl50#91yRHuHZndwU5LzrRI0tfuDsfUZ" + + "J3o3dPW7wgn2uNTUWRlJTHT53jghV17Yy7EDFZ2MqdOnLB8FucSAIvynZwQiCC7Tk$3GjZ5" + + "6zvJmJCqjz8ekakIiQTzruVtADelz2uGAzTvshdPkSwvoNdEww5ol1qvVNxsKuJtEWl8zsO" + + "vrrEkCnyzVWBX0cUkTwUpIjTqBtKiCn#bvYBlRFTDPqUbuym2zodAotxWd4socREzUuoElR" + + "iBwFXgjj5hdAEKdRDzVALqp3bxa8x5LMmVyza#H44TVsCzftIhcYd9EfRlkMzcs48oUv25P" + + "ChStUstu3jZaFgQ#xj25WATBePEBtIUqsZVS5yNoy0CTllHJ26T#3sSyvphtHN0yAExt3dV" + + "Gf$Nxb3J4uJUFu2ispyW5trs3KkjO8db$W6cLkTquMKcPKuF#uP#ecyOjRNkcpVRtKdtZJx" + + "Bd5im9$vCizYvr$JDEo7ic$Eyyn9cyI1LitERNRDpW$E8EupwXZABtBkTpPtLsJMnaNdNGl" + + "ykeNUMsEWpJd7qdFU##00hsTF1o32lN4X0lrfyv2u7fvu#ljWz6lQpFQsqxYBOpmdEyOvq5" + + "xZdCURZaShenOT0Fp71hcuIo#3esUcRv4tkK#H7IUyLnEL5JxdXZ0taTKdkqRlkIh80vrgC" + + "m78pAz1Ypau1dvwTlX6uRcHSDyeRWUl6E6LNPz4RuWhWCd9$3$OyagVFbIeCS6651AwX6jU" + + "DL3Vl6#PjkEzeNDSN8zrEGGdoGtrbFrOfl29zJ66cniZH2WTkg5sxkph4vGxHRIqfHXfNGG" + + "doO#EeIi8s4GxEjA1ufhbSmhYMk1#Qibu$nWNRnAp6Q0HjNLUCo3OXMr22$1WkLP9mNMVYc" + + "VdoEiPrdNUmAPjP06rkht3nRZ1FjtLjCTAu2agG7yE5b8owztcjYPFFkAx5E8Qr4wvm7F#b" + + "sxgc66K$ptuEsG8IAfVaI38pdt4W9RC3xEjpoiyiC7B86egSSyFQBKnyDz4ToZbN5oDjNmK" + + "bbE$KGV1RadOEiakQyivuy4E9Tmu8oeQeXZEgMjtMLSL8rrvGWlpOE7AwJvYlSXmJbrVnE5" + + "u5dUcozBoLyr68pkkbsxgo66bS1IL2kM3zqYbE1SB1tkSKzxu1FzI$t9HWcV3q#1tl1D#hF" + + "EnLC#nJH7IdpPoJOgzQ8zxX$E$PXkVdxBJpCmkSU#aingU8LUxop49hfnKuY#NPQN52KtjL" + + "dZEo$4SSVNIdHPclYk#qQZvaQRvTalqNeS$#AxCW#o#RCkVBImWzdLRi4rouso8$ijlAIv3" + + "2w14oUhT$$8GVq$nTKUp#MCBkZysFdVD4QATQyyjWfTWdoKhv1DUDzZEltjvd#StqXKzmIl" + + "CpapMlnvPrujoBizDAwrn8doUS3vptGxtdZgtMUxb$kLZYZWFtY7ZC6O7LMP#SdKl5Kzv#c" + + "Gl4i#8XH1yNzpXBzFFiBKNIoTdOsoLU1#SQvrvFE2kTpp2kxBAVkTdYc4YEvFapGs4IGv7o" + + "PD2lf#ZAqSRa3A8IJfyaJ5ZND2Rd8C84kPNU0v0yMKpZFevNcB9hdB7vzHJx42RwM9Yy$U2" + + "dr9CtErTFtY$3whrcQSOk5nEVw9zKv$g6OaeQExjwRzCKcCgHfoo9D3iYr1ETflpj5IRmm9" + + "GvC8h9Rvw4oRofXp31HvogutVR4oRpXg7jGyaaidFvckH8TRsbSwxcT8TuPv2$FVm#T4r2k" + + "HvcjtC#pTJiZtIQolv8ijaVYRE9KRsWIF4SPxJUWKeVAjSvpBdHI2PHM0zahMj3dNEvtGBx" + + "GnahOivV2AjzXu9hMQ58t0Nf5ShP7vqhGiaaCd944LGhZ5Fr#YkyNJX5eQALwQaSL5JBSaL" + + "SPhbo4LGwDvHC8YD7546rt3ZodVlyvTvbdA9GBSz5vVNbMfvNn0YULow2IkU6aabav8WYg9" + + "utZdpdqQ0TXUhvt17qTkPQdbF48$YSSX5KAbU4aabav3H$DJcs#UUylVtdv0oLRchtdrEx4" + + "yNaZEWfJDVqh2BA9zz$bavXb2jdo1aK9t8#3YMJoCWf7htNruGgHqxddCjLt5cZP5HCJiz1" + + "HRBFAA9yylrd0bJJvNIA4m5L89b4Haxn5gfdZ5Ffv3kVA5x5#2GGkP$3jJojYEDFawCHP#a" + + "VQSHDRYYPH5JEKCIkdZOkR85zPLTFEp$asDK#NCjJYjYkdb8kObSgLuIIIMJa56#NDawbir" + + "yEd$S7YZaZSaQGQdbI4SUV96T6KCjmBaOma4mY8sTg2aRmIUF25fml$IV3t8GHf5gUKEJGl" + + "UWdd3vmqH7aN9Pz8ZzHsQ0cUmIVC8vynRElHl099vipWaTpBOyhuX5yNBd86AXS4KecaP5J" + + "l5sQd3EVS#vp5f1lsiX#v3#U$OZ8cPlzIEYhHVy#bdrK4T$5fRlBZxeJE5jTzSrNkTpge$c" + + "9oWKrsRfwr3Zo5QzyrjMZxf7GLJbq1Ji3CY1rHd0jZobYNJr6BlkHweaATQu89PF8o2dUqj" + + "LZngbqzilXAsj$BD7QgPQ1YZW#a9ooTeUVFO6TSIwiFP1C8YfdrnHO#q3ZWXQ6Ug$u0yDSQ" + + "ry#qgI21YXYQny050F4KLPdZr2vB3iWFr7PaBTqnJdo59DEVlO7vLCi#uDNdVt19btJpefm" + + "eXf4lXyyR#8DzYeehd93oIGoSegtK76Ed6RIoSz#htoAPR#NqxBVswHhsaaHTfXfv9DJ7pb" + + "DJgEuoWqbayZ8ATv2nJdoP9DEVlOxvLCi#vqyEVkTJRgc$eg0ucJooMbK9ykJAQvoGyaaCd" + + "AAjr1nZZpHf9EVcK6#SmZ5CcNonFWT3AwbdoAWE95ySXhLYV94YglSK3A9Z9pYBLIS8qymw" + + "UG3LJ#DgXzGdP23YchfgmWeJY2Vd4PrWZo1uYetb4mY8wTu2nNdoCacdNoWwgjHzGMgoJce" + + "g9O#Ye1YCldaDAh9SZB5LMuecKH6Jl4MAiwHKqqw#K3LHwFg0rHJSr1HBJMAW68g#NvDW6g" + + "gd4fnbHjA9f6HKxo5YdFaIIQTVA2gqQXgWEga75HKIsz5G74I#UGqgfFaIHHNkQ5a4XavnL" + + "keE4TECUda0rLlZQetK4t9GKMrxAW8AAQGJqwZcYAdK5pbXf99PEGq7$ncmDIeqfaVwhSmR" + + "N2OkxPJBOzeed#zUmHfZwYrNTVyjSfbsKVo4vKBUKjNAcTxamv$g4erkRbtihcMXnMnrCFa" + + "dACZzUhSK3A9Z1nHvCpmi75X2#ohynLYpfcnyzKKhkKXHIpza78HL3etb4mY8qSKGVMGSM4" + + "Bx2jKY3dpOgZcSYqFAcBf1vMBeDAveMGI6Jdco#KaSz$6Vn3d9PshuiZJRRXl8WoUXr2$bu" + + "SrJpAowZwrd8GIUUzgacJs0vIYAxnnTBVKd#7FeBW$GpuRahk2fDpbuFHTJNz6UASNVEHEB" + + "vrKt5lv3g38TwVNFClXJkBd3EwozBhOOETE5BWZA$yTwfcmEtGlxLVEJcAviqLcbAFFEUuA" + + "qIB$NUhSxuJTDzrRDRQxtQUSrSxas9tUujXYTzxKNMY7zhuOGdU5zmXZQx6MsAOt61jzXZf" + + "loED3lLcwpx9UZ#SHN44Z6EhDkhD$lCBbFg$lx1zFjMNVSs$DlaVatfrzprdjTurZepogNq" + + "dbaZKVXnevFRm6uRPY1ir7f0zrpaM9yrL9bfWU8dINHX5ctuNKkqmKlkTtYRQCjf0dpX3Jj" + + "5GEARt1JL4SfnbKxGAk0zK43Jv1lYefdw0uEPjSlY#0z5UoxqFgVIOAt$KxnrkcFDR7#yaK" + + "O1CQ6wKPH9q2hYlLW3OV8b#Lb0zHd9nDgXeAioiXjPA9mlVzJl6MAO#nhKocd37LyjQOLgY" + + "hHKft5gB4#QeaOZiMdWkGuRcGNUa#XNApeoslvTC#EP$WQPyBea$xD6YUVjZGUTf0R1Vz16" + + "nVhsTi5$y4RFzOpzYk#0dO$hcUiLtr4x3zPprZksVjiRd7hMTi3$y4R2UiPsn$#WdOfgrVR" + + "ExtFm7RZ8QVGvmwisSv1yNF8NIDv8pNg5SuusBdjwD2RDxmejXchLTi1nV0jdjHRAUjJsoP" + + "tGfW6rKKs#dh5Tl80jYM5CFcZLkxSszezRdOWfpSfrfiR3SLnNRaMinJwrwqevyNSXRuT$b" + + "tXRZeNZIl8ND3RDwTzZnrpYwARK4KctVh1jFRxKMndRyMzZPVMzi2$nx$djprZPvgJyO6NJ" + + "LWVVEkM3VNW4cVmazHfS3sy$M3BUaQiC7ObZLYRFSrOcolDs9ixpLYREytOcnVhDMUPNtM8" + + "xO6NsUbmyOvFt5zounOQsn3OzZ2VUlwP6ovk5md$Ar8BZQnPqcnUGMndLLIR9iqOhqrBuJD" + + "NVjvkYwmbHN2vhLUMsnoOWoRzL5v#R79YHhRPlf#xqGgaJEcyIUYqsERMG3Rp2BOPcfiMsX" + + "iCwd4kiDcFkdNjuGntQhWN2Wjjl96ZArL8yRMfX5ZswOHOzkk4MDhtuYnTMp4s3etOcnT6p" + + "6sYaQChSh6bdtVlLLzu#VUdNq$2LkgxoYjJrAQoJ6#RZ4NM$S8jjXtb74CnR#Zp46Ga6PoZ" + + "AzA9c3h6S7s7gJKTymKhenZAFwTU0w2X3IJOtpzBNmkjiCZs6BVYSSnwE$4XVaUEyztuZQ2" + + "X3IJOtnLCW7RbEXSoBwhlzjzrtqgB1Usl47dmjH6F4$dDc9iyninjeMD6DlvZHZRXOqOsos" + + "D6DjTZHZRRninjZz7zgmlSGxvaWZda2yJpo78KvB954UGb6PoZAzRpC7cFHx1zWMalc2YyC" + + "iu1fRuGaicKWw2X3IJOtnLCW7RQczDP3$zGk#dNs0$$IAEOSEEgVTPuxKtx#j6ZEsxHepjX" + + "wYzDIfi$swutho3Yc4BltlEyxtCN8LDFc2zpUa1YZjdomTiKlBoWSm#6rflybWBsx4K9sUJ" + + "nWPkWsCxsi9sDCN9sQInWTlWsEwtiDrFSN8sQMptP$fkS6p7MDYEeJWvcpGsS1i8smoDRQW" + + "zJmK$ims$ipXEZ1JglR2Jn3bYbQuf7ROpnBIysCRgzkV0jH7jBMnZ4lJsgAMtHobEpYO8Zg" + + "Qqp172l0rcjdktM9pmlaVp3zCYz7F#VLgOtEGFSheaouTrQpdj#$jfQaQ#5RU8PNMOs6giN" + + "20$GyU7cZJjgp4KTYdJGkhsp#2tl$GksFubOTsHzYtaQzs##XHkFqt$PvXVuQXVqP0V9vRK" + + "OMB$O#K2#LjCtAG5qYTfca6#5RU8PNMOEEgnSg6yYPkqG7gIffF8j#8MiQmE4rkDbGlbJTo" + + "a1TBxQvf4lXMtY6LrcDXgh5meR#8cBP2UZd7TMun4xdIVtbinFPTOLeU9hSRAXV8cRj82wI" + + "cQffDlnIrYMHqcjXeh5ygRk4aBf8$ND8LyAsuHo#emiTLOkL3Un4rQ83rDq$7aMt6BM5Q7Y" + + "Qt6oeNo9cxI0kcJDKqZtufRnB8wJ6mrLYwKDt6J5aXFrNGo#LRS8fRLOMAhiNAXl8cRj43w" + + "H4rJoRVY5h6i3XDRZPKBvKtSf0NI9sWwaNmhRX7BwZ2nrLYvKDx4JLeWFLdJ2UHRSOjOLeU" + + "9hSRAXV8cRj82wOcQ9fDlnIrYMHqcjXeh5ygRk4aBf8$JD95yAsuHo#emiTLOkL3Un4rQ87" + + "sCfkF8j#8MiQmE4rkDbGlbJToa1T97QZg6V2jk4SlgCB7LMBbGtiHDMY0zGTEHv5jnYrXMX" + + "ucjnig5yYPkqWBfepHD8D#AMyIoEaniDLOkb3TnanP87wtfAFAjk4KigyF4LcFbGdaJDsc1" + + "zB6QZYRVYbl4iZfCR3LMBfGtSPEcVVr#FUBfFOIvx$5Ix#8KUT#lb$iUhtWDAfHt6zvPGho" + + "ystzEtcsJaGDdtevu3Rr5KWZpZgsWpcSLAjIN3rN2UxoYDUZm0iCxIvY$0D8NsCHIUuFRMt" + + "DxEzUG7oUJcujMjxItoa#Gtzk4WTmeKGL7iL6WlTcFaSdLrUTy6qevoV8cRjBWHehkFl#JX" + + "pyID8hz69bS#xsYaVP6wjAQ#8tx8yDK2kbt6ipjWHI#qWN7V2wPN27uZVlyyUwssjj3bux9" + + "UtUPk4c3Emqfft7iDCNdaidDsx$JT6ablJNtxxGmbKBk7t4pbICVuHRanod8pTU$cIfVIsz" + + "jvBs7JNbJ1zmivSW7pMG$HYOtoJPLdYwT8s$Y9WskNZdoGRFOZv79pTjUlIwjfBSEvKrvKm" + + "VSgSgH3wfdFqOcDzRA64MSDyQItZgKD#LD7N2dA4S#w5JsupH6vPfMnC$2DbL9NPf9jtTAc" + + "1gse5OxxtugnwlTAM4zvBmxYgx1BpXgntmXsdjwrwexJALxTTvnuRjM7VsMT$y5kQyYYf4l" + + "z$KwUDEyKprTXydrjZQISLBbH21l8#3S#rGj72V#FiJkiqdBtkVF1gBP9ElFLdmkCMeTKhr" + + "EczY8HygPj31LIN0xXohYUWwrCE#ZGvqhzp6ISJBbdFdUYSGx2y8tkPeQISwPAm$HH6KECU" + + "$fyyOwPpldivJE1HsIJ2HZOJp4rEyS4UPekJfDp8kSZya5rILJj9ogAOo5jS0$M1Fp2MtfN" + + "D31oHGjfseAOs4jy0$Kn7n2MpeNT60oHSkfci9OM0lyCPgOJsXBvuB695EqdAefZ8Mrm1#l" + + "YVc4jdGkQ7moHSkfci9OM0lySPgOJsXBvuB69LEqdAefZ8Mrm3z84$C9RUbSq47952sdQWf" + + "ZOItmnsfY7ib38dVJJJxLEZQPT3bJ#zX8osE3rB5Yh5clATMvr#gGrhfQhrasxtkoNVj$Fa" + + "VRBMEzflLfCQ$NmhH5wtMaBM6tHUjryRQo7ofIl6vBrQBQ4YhNMM8auyIor5RietB24AlhB" + + "SfbF$HlKNmkAJaLwhBgtFyfnLHlxLp6fixzj#JhhNmLemJdZ9IlobUTLIfkKz1RtLQkPjL$" + + "bAcsYcYsX$z7$uy8MxgjdLNELsuxgX$nu3$Ag2stRRIjfFyeAzwM$Q6sz3jXZmpVQv1iCU5" + + "Um#$jIcKntcsHrhuAh2rOmwWjftuTwV3F$f#D3X6sqpKaw$3F#NIOgIpULYRox#75T6ZQoj" + + "LXWzhITN6BzyPrw7vYR1fjvRFfHy9P9nznFwAuVCIcp4IgIpwI$LeHuSv#xR4jUd#p#qovL" + + "9UHZ9CbgkpePOCxzwDmeqnU7MJ$AShXMX87#XgyuW9AqdTcUDY6DpviAztyi7iIrK6mod4k" + + "Lha2Ej3w3kwEhBqEkCKFGdJXt0Zwk9yjPVtxm1jk3wnrRtZZQMvGdZqtwDy7C3UGxxODQyn" + + "qHsxYVpNInt#JQtnJpRPuZHnsOwcsKIqcrHZc5hCa#byjzHzSn8kSlLb9S4shaqbSgUxDS1" + + "yky2$8VgtlrSJkquYnXaEPwDYDySQ7TKJ6RdN1iHljl16nWzceQt4#EyW$XmD1VP$6kIP7A" + + "s5TwetVIyBSV5efNfUn3AtXF3LHNMmPlpUMaLsTP1dmsvewLJl9jaRrS2xL#HRgAc1jgiu8" + + "vkGwtuhQPEuO5BT9YValUGsGnoa#by9SquvyHJcSALvHFF9VYH3agNRvEJb8V4vamYXn$Je" + + "qgrlKLbLU#E6swKH9wGNjYoLIhLdEZWLiDVOaYdDDiJgT9SNkK6Z1iLPTRKHxgoxhYYNrNA" + + "BFQBB$OlCpDJvHlAyfy3NfxoVfppzR4ScIl#xqvvyTraKjX7MfrXgklpW#gZEio#bM2ltbo" + + "EVM6Tk1q#1Jgpvz8vF$hHNk4VIi6QtwL2Uj#fafQjNFJ1DZugj#Pcg0JoIj#kwvd3tQz4Fl" + + "PNnrNFZVJFstTGdUTvm36S49cLqrWcL0GFzaItlPKvdTWx5yEsVVoV#qdzBWcKg37bqze4P" + + "kywcCzMswkqBqYppjL#WTTUewHDqBM6RNg2iR4$mhxLZh7NN5COxcKGvhd8qQ5uVN8OGnir" + + "TnZ9P95S2eQnHfUctLE3fM8sECwB6XDOgy61jSe$oPTbV8doa#JXYJqzmLn4NVy19#l4kLN" + + "12$qdsGozxYNIvluLflaRSeFqO$atUPN8Ht6HSXLVOk6RmfpSWJbtzD8HcwWrvi$iiR87i3" + + "bxX1yN52seCcbtXd2SSVZ50W5xIF53N$aPCVvGtfK8ObibyfKdoELMW9FcL$bKnHQNcpSus" + + "yMN4KaXyb$xRiL$vjYlDlmsh2pYPLYhYmTbMRuWhq$sQz#gRelzl3u$#EANRcbiE8pFT0#Q" + + "yPaIVaC5gbIPxHwBk6qRWS5hskLVNRPDNOm$in3SQeHlBTDokaaOBxn1FYKV6mQjdRpwbpU" + + "0t2NaXtViD$9TGVVcSZ$tUWix$wZqNd6gy3$OkxP$sV8QLdp5aivxy39Vr$CpiY4qO9vIzK" + + "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" + + "qPj8UPCbtZGySI5blyNUzor9PByrF74M$GCf$s29VnYUk93MoHuGUGOp5hF#grFGIIBy3we" + + "$1YUgy1F$HShOIAxzUz8nuj$6XkIzR7Dhn3lC$miEeKri8NCvZ7w$ELhD5ZcN9SxHenX7CG" + + "Pbpv7Mayc8pzMhvbo97LgU7PGr4kSWPJJddKFvd3WRFM09o7EAF2keTOoEw$rUXlj#uK$Ez" + + "xKQXIDSuM6WDX7DH7FHGfI9JSLcqFeMOaknbMWfoiNMeXN6eOreAxOHsuhjH3lCYmwYe#Y4" + + "kTP5T1NTH0L6gafKY#wY1qPjUx63w2Ls5Br5ZUWZ#cBq#ekTnCvYW1We1ebTn63eRQWO9eQ" + + "BMZ52x2fs4xkp5lSKUubHOc#nZzXNx2Vs1#83qDi3eOk3n3WnNXmiwiGXub1nc3XS726E5F" + + "JsdwCr$eaRUKySz8ImYuse9ytGanPYOGHRHlUaDJ1lk9xSAbwtUlAwxabPOa$6ewtSCVa5n" + + "kIb7ElQECPX4$J90JelXkxeZQO7Cz63wM86mbF4gU9kSGzMfzF4$HjH3oes#XxKHNhWWAW7" + + "cOse1ujYFJYEUp1f8#g14#b1nKRKWtgh1uJoB76sE4VC5VF4VF6kUA#f1nkm1ztGWtgqOVV" + + "WB5ZLnjE3dkZ1AuZPFUY9sCRJ0sL5$zTwyFH6s8EsaHxGphonzM16f0S$4pULh0T$Qt0FQ4" + + "yc77OFnei99S9VjvOZu4NmrvSCVteByZJ#9M9yYR3#AJLMeR6s1TPcM6EIyCr2suHl5jl$Y" + + "OtU$eMr5pT36qdutXSVC3uA5vMiJvUaxbD$tQTBIcPJ8r9Z7Q#n$gzaMFkdndgXnjg$P5X$" + + "anfhXRMkbmRhqwcnVggnBYqPrhBKM3VLMCjAXdNJr5ZBhBsnD5ZBKsDTQkqjfS4w8pNMHTQ" + + "UKHgiYngy5rop4SojifBFhIQiJLYRi3PXdTdWSrPvoR2sJutr2OtrYP9XTL9Z$KHZVN4ZEB" + + "lSLlBpwmiDdbkbkpRidXghex7EAXdMYWPZtHZqQiwlTIN3clx#Nft6wcq4S#jt6kix9SEwE" + + "ZNM5pNMyIN3wgN6EhtaDb3VuFkvzHk1NbyhkLwdQwoP1jvxRfk8RuQ#zrp5xPVgFcrw$RzY" + + "FPDI6gmz6tpVQsB9i2vCZRMPnhgmP5WVI8srlEJNEkdr#a39pxa$JurrPidrcacDjOl6sdq" + + "ZE3ikBFavjseZmZfe8yAQtWQwbtnzDVUIfZVmtD0Z4Lz$VMuOBwx3zKQfpWrc7NRMoNVMX9" + + "xmKUjBIjOdysp1EqNxz4NaMlzOOANd1mZh2S3wxnoizvQiJsMfnscYxfD0drnkWt3#7JZhO" + + "pZLKokjIzQdoGMVnBVxr5FtgQPaStzfwdNgvu7#Iu6p9hMTp2hvMQKizNMOjn5TiomiwVYd" + + "FrUN5cVwxsMQRIJwFA2aEFTFZNDqIN6QxxZAY#ByS3tYB4CAuQpAmTcDSLQ98KZP7$NK1lL" + + "KM3W8PxxzL3q5IZWSnh5#diQjHntKW$uvFHZDFQX73non2AtMYel4OWkRG1qkzu3Gb1T4Gs" + + "4P$uhoCut$9E0lIpNkb3i0OqneI9xscMgST9F6lH$opBWFZ9nVQd4w8Pnr1N4woFF4E8G7Q" + + "voPr3YhKMe0IXcStN5ohHQlvS4vFS0v98Qpdd5sBu9p4UEy23Z72n#Iro7rpLGuwosS9Ab6" + + "zAj4dCyWrU3i4S5P1YAS$GlY37zbz37QfLyPKOlLAN4#3foNCSuhKKBXh4x4kH8b3CubCPo" + + "rZ3EJ4kVNufi0v$CfVnKQwhCThCNCjcISItA#5n3Y5y3v4j0s1EUbG4SuPo8jdNsE4ty6pb" + + "krVJeevq7#qZpscSdvpbMW1DddBnZdfIbntewQ2ESob4Y7qxPF1$9cnKd2wLaumtD8FN1I$" + + "OIpTK6Sr5P$FTClmzYPjXgAiymgMmpdIG7EOosS9nJ4QQz8zMZBuNAPbEE#dJMFw1UN7ieb" + + "dvLjd4jYE8Sq4ET2u2pdw#1qyuXo1eZVCiu$QvnE2fpr4PoVOnpIu2m3pj1Aoq5afUbnbcd" + + "xl0HONEGbdqDid9FNOjnhz3mrEr4vukKyVcbnAlkyWgzuMg2TJOlYtFKdsgSQznRWDsqmpc" + + "wuFkuE#KrHBWdd5CZdhak4ynAqcGRdTE1KfoXbOUgAC0tEXIWx0FQYS5R1NgeWUrrHdE4wN" + + "uLsxzJwB2koVWx2Nb8Mx2LNOFGMukoI1cSPMXg0kXHEEfbL0MLD8audKPyrmDbCwxCmpWeW" + + "RIT#5U0qEas3qs6ScG3dTDPFiZvjdCq3d0iXNo#EIx4VBKAxPNn#lHrrBG72POmi3Kx1EDL" + + "yRyOunoCtURvJUmRdHm7EDnk0apuAvtHkRPduW$XZAfmzhFteSTZATCIlGBpOV9yUsT$haP" + + "u6Pnca5Sv$Y6$H3ktlQrAEksEjIoHRm#Vkv75lap3knpBEIrBCzqLyJYMSQjqaNP9Uqitt$" + + "GBxh87KTFWrUSvB3gHoSLOrODpfUa3fiugl99O1xIMfS8wtzFbFyHrg#b7yAyyyiiTzlxMQ" + + "Hmua5SvPw6a6ECyIRwHSb#npNG$Kca4TNpP0dshSqwppYyJ3Y17EyS5PgKtASL#5ik7#JlG" + + "Njfvad2CISAwozFcN8ZX$2EnpEYY3qqYvUA31#YJ9SiPwHIBEuyIaX7D8niBff9plZZwHD0" + + "F2vYddaHFeyme#kzRanJaTQ79n2iQva74sAxf#JcAST5NK3BF0GRcq#r4PS3gCipdVfQ7Li" + + "sSUVVPCmDcCSVPad3L5SFO4BiBvFLy$pa9xIrBQ9yaEW2ESj#cov2VXh814$1bF0Ld2MP5Y" + + "VwTvv33Elz9AwZW87qvv7QVqUQkUHmRbdOauRqMRXN4#NWJdRHhdBEwpQI#TFik3yn9XlWI" + + "oC$Dyxr5chPzUWFDPuApGwzA88kSb3z8UdtKMWihWY4k3SoQFkyBPNZo1Mbv0YUHzyzb4d7" + + "IbybkDiw88paMyNquNJ$BQv#Wm3Sv5e05OmmZdatm5Jxt#NIBED$BYDFfSL0Id42qZRX6$v" + + "IdzkKumJlkJX9FUnwvnIcbmWdCbFeGJVW6SCiyd3KwM6m07d96o2JWvlGbd4yucd4quct0s" + + "uMp2sOIp2MSJpYQSJJYRS3RXRCBv$m7Ey7jjZgNyNZkEaxwvpuzJt9k3qq6huHCAXF9HyPX" + + "OWNnwCg9SeUGQypsRLa4QXNjRLC5$Yr7IymEzWV5cSOj2AVhpKu03#2d0UzLJW5nhqjray$" + + "t#2a7$GtGQfCR17GmNVoz#lSAE78NTUWOFQKMn8uVkDb8TLLm7ONV0zOQ37WXt3Fjs1R4$P" + + "w4VeqSn6NlQfmAlAw3vRgpxq3x2jeyJVP3JJqpcfmAxyVrnaXi2kNF50b6hn#nNSDMGkrZq" + + "14TF1GxYdbq8pVT3M2lC6uyt4LU9vfpNdKiVBMuKTneTY$iAeApdKlyLoxMTauwFLZhc#4B" + + "MyIBMyKMaOyGAwNZoskXOMyWpKHqZjPXrHsQbHayMGhNIJ85EC7Aaqu7WpeU5N62XpsjtF5" + + "F6w54OXx59i6wM6iZQ6Gpjw5h5KsAgE5bCYziFSjQwRsYbJFMDvKtDD8kR9$MDn$nUh4xvQ" + + "kv3VKEPuz2t5U9WZ5anwnyIGVzsSVISXnhW2pCoy7cjZUbY8DSm66kj#GLNCAPY5jlF776w" + + "E4ESoVNy1qwXxmVqvwtDtDMsKk29NkJIsXvTyx6swv9zsSVSPGkW4GXc1UPapawXvsxnDKN" + + "fgpWkpWlsF8qBwqWK5zc$$Pw2VfmRNODJuMguldWE6bpD2HTgZEWhnCKo5syONA6#kDw#xD" + + "CQt3p0zVj0NySnBjIBaFtqk7Xr$Wcup3XYfS$5TLM8Y#LkNF#unClvx7vTZ6D3xLvSQEDIT" + + "e$zJ#E2gmUk6qExZsBYFMsTsXVL23T9xyq9wuIu6lggvvtY#W1N3geDOlSqC$kollEC8#yU" + + "wtK#oiWdM2USs7oi5tMHTJMkh#qqhjWfOYrsshl5FPn$lnx1#4xRJPskS1OZw#ffMHVN30l" + + "BLtEjsgjalZDoxXaeijDAEiaLFoMh#U3I$egneJDG2o2Eph4RCIu3MIvwWWlNxCheRilpI#" + + "sqVHLwxBRn4tuK#pKnxDtObgeAQBv$38Cw9QWd7ZDifNo2IzXdbUOBdJuKzebvhquKze6CF" + + "VZDMs2LQQvEBcIiTNhzCdet9sVrFFkDT796JBq3NjkmJ3WvM$Ps6SxtpSMLDB$qZANK6r9S" + + "xLad0p53Owh7EFGE#jMVCTYOZkLTuVWaJFoSaS94rnpgD4sOSEN8jLsjhp0Sh6i5nY8otyt" + + "iiZ7HsfXIJx24H3q5jQNGKn8ctkzxgrMyePYInYvIVvgnq#EiIxG8zSGvhiA4kkbARDCe9j" + + "IU6XDTZTgOH4q1J7clOP6ghc4TNg$9$WV1aiO3q$71DUpvS1Tm6ovhL$ysBtU53h4oh#piQ" + + "ERlikUZU52Sz1EmrgazZx2oFmJwZ6ArVoLexotNX2jHP5prg6ALNcjKPYTc3JxN45IXhjOV" + + "Al7hneggL2COhiY42ZNtmwuRjojL9w5gdNEF8g8hxBh1FGhELQUqSdqAQm0gn7wkMr3MpgX" + + "4dK8b7X53T6v9KTdM7aSbPM5KmSfWKAaHNyTpC6fNugaDPrTMwIHTEK2bHgUMzuS6wSf6LQ" + + "eH5CSIAkmF$z#C82He3fB48DfrbQxGSgs#Zke7VTJh4eCYg6g34Lp8kOlOlsZzw0fEwUePS" + + "JuGNC08r9c$HRAkQ3z7E4bCRdpMJdO6$$XrRUsmgEWg6hiYpMljbrjzlNQTs5Lanq5xD89q" + + "5LOBJRNEkVvDNDk36gsrlGbL4wecL4se$c#YKj$uXwXaT6qlRy3QJZMg7OVNThg6bkjgRHz" + + "levAo42fz9pjt7xmyKkzwFL$9Hd0zM59K3gpRrDW7zXorgzOovzH7BIiSRDr0fTkcqmhTTS" + + "r$nv6#cQVxgVJyIZU#QmKSaiv7FMFVgT8y2xvJbNGFAxpBMXkxqqidbJ5q1r3Al7TwwyCx$" + + "v2u9iSIqtmVB2mzyzrIAQDtZ3bd8EiiprrgcVETCB2DqTZ6GQyvs8jZIxxpbkUxwfXUrpSs" + + "pgD$X6vcwIsk#zOyWWFv7cvuXxpWdVq4R6KDrblOGht1fb6626Ue9nJGXyZJ5omHblzb364" + + "gRFpyKa6zmJsaDHZLMy19zOsXiFIMDEujnI#rfjlyTBqPR5fNFncRhgVrXXfJAPEVgC7EjN" + + "xdQSBJFZBda$TfdoPiJTYQi3LXQyAsLkSGN6kOEvKN9fr3nDKwTw2uNaRER#9oQrUvjWbR4" + + "xOqsAHrHah25kJaFDMolh75dglgfgyNgiqtwx5vsiywlrripzFuTLXnREA#ZLblaf#dPWbr" + + "xPoplgbdL1EnrQxdjJVFqnUvdy9FKPKEMz8rO1Es9cnDs3RalPe8YeqE6#TiyFKjQDcSHSo" + + "JRxdtu6FO2lzM907R7KtOch1j5DYQHR7P7xhJLmXRklkzKlvVn1RWIBs#DNHCcx0rOMl2re" + + "Ij2LiJjYPiJTYQi3LXQyBMXAq9MnEs9cnDs9gmDM5hmhQXiOdoOjYixvwJlvVf9$CyRobgy" + + "xxdP0FhBVspe4tOch2jBJPwSmXXKsyiCjWaVpyYOszgeBS0wLBfvcc1PxQ3DwSy9DLRay9d" + + "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" + + "UdyrMZB1BceAsuL#1YllqtzcvTSZj4jI6po63MmZzYrHjzmxzLfEsSp4jId5dBcpCb6QRx1" + + "Ytoq5Y2OgUqvi9QyzerJudymvJr8apa8wCLdF08VVeKPNLcX#0h0VayOk6c93vkpI99jUri" + + "ox1gmHDMgDa39tZS38NXKRhHjJxEIvOnp$RcljIgtL$8trg1lwL4djE2B$MhH#red6MQzr$" + + "p6dNlg5Gi5wAwFrgZC0ex7lFJOOBzTLMMolopbndgTrT642qglGcpB8jB5mbSTap0hS9bo1" + + "at$nGVVVEJI$#A0hs44oU6#539wtrh7UChngJha21y$YjacS6tKnwGdetp7KlwBNJW8oBYD" + + "ERVyuDJNKuefBv6WxhystJIXTfhID#la$5Z6MBhT3yhqJ4BVct$mFoVVh7LXRF#j$ImUn9Q" + + "jLgY#kINEk9AHwSf3gB8izZrzkoHdxE5gQ9p36wrArSIHMw$t2UdGfzQrL1gMQcJnnTCw$M" + + "zhtmAcDVbRU8E2ibFgvEzJJ3nepL#I3pAawQha9$yeQOgGUzGlxIlM7UNnllJovZi8OxJgY" + + "zRCV#yVrXcAqQZXQ$JOjmD7RmX6$LkvdnGPP$D7sBnrGWwbl77yFN1UTuvYXBJ13uzUFX35" + + "obqNLmFNn6p4uhjOCCyU755XRpPYsWTsEiEkJqa9KcmzH855aPgyRYVnhK80yP$MZ#uBh1L" + + "Em7l7rP96hbMArHV3dtjb8TVusvQNzhDWu$cwzBgQJPDjIQt317O5tfZnFBmJfpOBPblkKN" + + "MkhF5bjStkjX0rN1ckbwhcwJk#DsisLl4etzsE7IEjU5QCR4f6h2#KuDBNdt9b2oZ4ovocx" + + "V7Um4dgMCBEBO4lRXzxwc#b0JZz$K1TzTqxwFYJBMICJZA2kkQs5hNM83IjXJXzurx3xe4T" + + "GyhqO#eKhbmoU2q0A$pP2MKV#Fd2#kXj2goxBHRwvd23wSya25Xhq8PAV#mIvrNfRsq8Hwy" + + "s8CcWx$D$pEZvPXBLFG3#EKJ6h9jLFTO#rqj9NdTAHBjytRc7c5taQGLsGtpiSSti7GieGf" + + "3JOFhdk8KbM8UdCdxHlcIU#yzYdJWd7hBTb3rHI$LwrTsZ7mRvLPqgRFh6zfpZLwdbHTBKh" + + "lgEaa2YWuuQav7x27S1OMS8ywwttUYl5oEWvLXbQDlsMHMk#jPujTT5dx0AjLqPJedDCIcF" + + "P#MVPMkebiWzODcHRQ6$B9XBxdAGfNbVgeiY25SzQL$BrETzg6H#nzFjYL0Cqe#nLLNDruG" + + "n8lozgQJsZ0fsOiaEiTRTrP8Kt4i5UmUjuSpEZfCnZ1mLMbPnViCJEDV6rCQvH2ujQfyDUc" + + "36kYza7httvHYEgqQY5MMqDaJBwJPKg6nklo6Z4QxSrolBDyja6ssQ1dahhcmjbFxnNr37V" + + "DwXTxpXQxwsjzRYrtf4ghVnAgNSSjgk#zegiQcST6xlAlLkRkEe6UjemQszZaOWzWnc9MV$" + + "LAUdiO7zNspR7tkFFm$QEvDeMFKJS5kp1WaVvRd4Fp$Rxay$izEsxZD#5hzCdXTR6XdYcvp" + + "wLI$VLh2jEOo6y3ZHZ2wkCVJ#bBBIrib3p3HRQECRaSbWPMDWGErrA##v2eK$oNHOXCeld2" + + "VhqFPfjLupm4RuYnAw72Z5p5o7wZHF2srm8TxuGPur6sjb27FqPuWy8uVGGujZbGdsEH$vX" + + "k8Jk1eVG#nNSlKWxJeXDa7RMDAHVYV1Xn7iXV0xntmXnw3BmlqJQ9GZVH7qkwjzKY8aV8jn" + + "DY1CUGdY648VT1lSksboDCgk4E7mR8PeTBaIBFk372j4AzM#2zWJgR3KJUP1jjWOEs9rBST" + + "4v5E7NGdH0dHtHjsOdWr#A$a2c#UN8gqJuAUB$5UAKSY6cG2qTWEjmu3eS#cZsExJVLOWZF" + + "E1yMuXjWR$vPOWFXpiTxZ78tmmym7S4sZboUo6sELE8pks5A0F#iglWlXVYx4ve$nc49o3$" + + "I9HP2VSMujs5E8UmGM#7OLoEX3xFxeVnGTj7tYh4oLkZRlJZo7V0JqIPVONeygqGNVSKOa0" + + "DTFbto0yHekQV26S8qUT08Kw$4Fo3QESJ8Ovg2zaRX3Yf2zhO3th2U7T2tPj2$qT1jYl6Pb" + + "FWsdG5T86sDuKUDeCUDki8jm$gWJugMY1yGeZvVuJyLoXtCVAEGlqNWVyrJ62g4BFsHxt3q" + + "6#qTmhwD0lZVmhY7VuDyyBOzeMkpxu5vUv2FUXB1wo14qZ#PSWT39t#37aOXwCVWVsWdUaV" + + "2R4vR32pCy8JuJ1kczy31voRloGmSU7Qm6q7X$9Rd0Gt7Uu#k5$0OGotHBjRmbwsn5XiUGW" + + "SwjWIDjAPyku67jIr9JdeyrHWcZqAuujnsRcT4Bj1FmCWFxs345iTAyHfHmWn1$gUGpe1jk" + + "DXGrkXB#SuGfm8dTIZljDE4s8doFR3cFJ3d3aDkksFVfq6sHD#Yn1ZF1Njpu9EPrqXH4lWc" + + "eN#pa9$Pg7TMT3LQNy11enFAunbIzZO7DXw7xIt3Moe9UojvHAqYR7i3Bje#GR2IS29iP#D" + + "CPip6#NHbrEknbo1JSo1pNP6F$h33kR0$hgWlSxdeXpcyPn5Y6yBlPDTO5vrWVuwe1yTFq3" + + "#7n3$EVWxXIZ7#bvUXR7T2VLYJCkn3apu4Vr5sIwmcowm$NhOse0NCOUXWoxF0WlcUPT$8C" + + "Hux8BvqdLlnAy1xfwGnNZNexrpCFQppuDTlW0UUcyEtENeUrVejmLqlJNwrG5OjfwBTXz7#" + + "7k4q64hz7lsZN1OJnnWs1KsCHisEFizvEs0SVjEY84V2p7j9iJHfrQOOwrGRZ0mTyEwrXes" + + "CHHoiw6prWEGXpQsXHtDWluwes#T$YJ4ZDvmm345EkkB#TyQjZjZ0Hpij#kJmBiOTMs6CTu" + + "HFEPeDyo5Su2d6zRHSw27RkXhjsinvj3r5BHvEiPi2l9EWLqSEmYwnzfs3d1rnNmy1tRN6c" + + "vtp8SvADjfCFe5E#k4ERyj#j8UOx8TwGIsqmUsKmPxtFqEb44Voqw1WwrCndeo1NE#8$gyE" + + "$hL2Mle2R3DAHYNpkZZ5AnRVLu7Z$dQ1VDb3iPj2dR5qu7z98p9wLWxJpe08TR4CyhWC6TE" + + "WgsT0UmJO5Ddm0OdO4wTWNau0EFT1cjQ6#Zf9EYZ8#evwLMq2Jix0thfY$NZZFk568Jn6mI" + + "T3FeV76oe3VIuorvmc1ExOAow0kTWx2DTqSSkc3DjQ8nE5Q8jrfh1s5iw7WIydwDkhAbxtO" + + "x#O7tjEXBvMB#60ECGh0qdR89#GMSd8bu1h6qnpuO0qn3Ozr2i6qEWvpxOhzmnSC0obDPsu" + + "1gAjePXdHg6zNOOrejXi8rEsBk6OnqUZdL$#5#5gAs0mzwImJXcaBy9rezDdiP#WBMX6TPt" + + "3tRO1MlYDjYpjkaClXPp6xeTXV4TYB7g23khXVo83CQOvkyvuA7Z4LYBFVIpAx1qnJetSbV" + + "q4tD$Ckph#ETH3zR#BkU3Xtww$0twnjpT1ZhQ3llA98nLLzZcIEm$ss4kZoGzmiRsW3rlXx" + + "PFx0yCmD7rprZ3C4RTK6OFZEDsc2CdOk#RYl7h1XpTO7iLrSZ3lAd07hKdxBy2uxCdvdSbz" + + "kmzeQjAZFkU6DjAsCPUMDkhC1VsmhohWitjXNMw2dqSDL28QkXZ5EPnDNGr2kj6DSPZR#oN" + + "tQ7VlJ7$kqz1Y7vrnvZkWpdJ0thR1rXwO1psmVhI0xQu3zQsdbiAiU$k264B#s9jx0dTxlk" + + "#4Dj3lzl1vZfWJBV3thufS6nQ3mTScs7jsWmu#q2lVRy4$nhs1k3V3lWsdmEz8wtB227cOY" + + "oxm6ww0jTSd1cwmZwxOJmxOqtfyWFuFOHe1tri3XriWVD0Eyo$TXYNTbZtXg9VtR16jCEQr" + + "0Nn6T1PPun3f$zWBB5kLs1Td07Rd8c#xOerim9sTnhiyJJOn4piWpE1RJ#i4rDXCzsmrhT7" + + "$JEnBit4#6o7SUs8DNvNb6cFSyeM68ijS1RQ4bZsWtnxp9VzCBUsn$goF#RazYY$F$RezXS" + + "WV1GXzfOTcg5UjDS1wy9ex4LTiWZHPWVOqMYi1nsmL#y0swx1UjmHUtedw7OqvjLCZEK1c3" + + "DJiJxlW3bo0FQ3Nh3P0p2lUs4$xO0rOmpqrWksC$KRbCMytV8iRBheSr#qqtaouh2ZhJ27#" + + "sBURmMxEXass1dZkHNikYLihmlspsw8ToFzOnvtXErqGR$7O1qx7dMUJESUh8cxmlOhi2Tq" + + "nNniYNdH4lOx0dl12HZVCw37hh2hNZYVxeYn6u3vD0rhH4ViRHsnPfw9ljTZ7QY0cuDzf1$" + + "wsm$pjntMp5qnlbsXkmhqfnnxKZdcoWdOYqw6$a$67baEkGheRslCgOgjW1FhOmNwiVL2EC" + + "oz2fonAZ4tnk2CS2BgE127ZWEn5Xw8VUv0h0cjS0PjXVdS2drfJRAmYx6mfHFHXvDXywqnF" + + "fNeOplORpliRvMmeVQGEnbzReruUvITZ3LY6cnyCcobC$Q3QLW$JeGTJyDShOJTTCOQFGtw" + + "dOj#TCDQK05xxWyRwe$pmTcGguJjzSSOxWITJ4FO4JXFXttFnVXK$WjdLiorph2p3fZRfm9" + + "$LL$8OktS2VMs0BOgy5NO8#RZx545MpuLPymMM1FF1QOgj7K6rjHMwCzCx2NdmaQhi1QSWJ" + + "ry6$Ij2dFgZ2#mJq67SsXDmRXMN8Tz3hev5NEb0crNmBPEnLbe1DQuKt4#sWMwh89Td8hsJ" + + "uLj3qOxGu6p4#RPCCp$kNI6nJmOXlsl4djc5S8gvCt56NyORB8hrkugs68LncWkoW#7BYgm" + + "lbPXpPoBCHkEDMSuRAuMzZ0NUgx5skzXRbQXJrMmZRcO1oE0eH9xPXNwL7Mz4FDW6xiYlH9" + + "ZMuLzhWhhqZoSJ$R3EZAFz8F#xe#rhWBwhyGSEHMoEw7VEsEiJeVzrM4D6WkxFXtsEWrxxt" + + "IqLzaSvR0#Lv1UWVjOZC5Os7WLC7O5xdbOvog1xLZev3ZCbSveSphqMucrj0gwEWwwFHPwc" + + "OSvKubheEEm3ns7yPw8zYk1hOhgXGrD18Q9qC$EsEicOlsPYFg7O9tiY$NsR9mbpg4r76j5" + + "9TQEAl1LM5FdORxDnRfTZRfgOBi7ORsRY$c0PKSSX3FGN9m3ge2$6hPVXVry7jgVXtLt7le" + + "s7tgT1vkTZpuUXB6OZtFJGDYyXsk0AkHLmxwgMq46VJmNQt4brhDgsYUmVis3$ix57bKDN9" + + "CmjkV2$kQXZzLO0yTXxJWNTZ8ETbkFje$7cQ4Uws8zvairx70Spe3rMFS7ObshnjcW6dFbU" + + "EJLGrzjCE#xu3mq7cl29DX69Sw5rPYRtR3NP32lsc3#3SGUKmlR702Sks5DsGqsk1lEghjZ" + + "$CRZEcWypWq3iRvLOr#eXXrCmXbkHvnfge6d6kjIDR2Cntwo8zRzBjXJZuSUHo6$AyvPNN2" + + "sce9wgh6#LACFep3MbLXRge7v3EYl6hPQXluVZ3DvR#GVZBDQDUPP6yYrnJfrCDQwwT19My" + + "o9wPYdRR4dxOnsjq4Vwp2FUkFyKuSpGpN6RHliYtMmqTwGEGHhLZNMYMrXTuV0dcjGro6O9" + + "zDXvzjYBJi4DbA3lbVY$5gDEJmVyxIQnXbddFdGtI3e$qpCdshOthQmuVbOO$f33$CnXwgn" + + "7rJ3dhfYN#wElir7#MhewqoSmQfnPZzpF4BqVs$KKO4nxuPhgjCnDcTYNw$4db6DyTyRxPu" + + "9#ww6Baw7VVR7sd4czgvkqF#PQASIyxOQSsGIxEXCv7V1cd8c#dOcrkrgxCLTO9jdGZUJiT" + + "#S2TlfHdC6Qs4rT5#1yyzPMFCgWFLqMdknFrHZVbLZ7UgCCyVfs1jEnxNsMLYJAr3dMT1z9" + + "UnwCZ3FnnvuAFRM#T3hVCoDAk2PZpbUXJ6UZBgdKrymnWCnFdLODoenTdKOzohOIJNEizKu" + + "hv#5CeV0xYgnbno2kNa8zGLxRpNctjwOlrKOYqgS5Sx57EgESJeK#klU6kTer5UDiTi7Qyu" + + "qoCp0MQiAytuozgLziExDW9qEWBrtnzhV7NEkE#PcTunlT#YuE#PJTymV1phhZd6hmlhQ0U" + + "lU08ph8AnJms3$ms1Vmx2cLMEkPg3hdM4ptT5EztsH3epTCGOx8syurOlrPpZQx8v#3KUVk" + + "sD$hSMywuxvLOivq1rrTiSuTpz6tIkQFaU57HvMeRYEGiKxRwdGUyYagRZxVZJUuKGxhj9s" + + "rMLtwwZ3RZeyAPJPROOEdmlJEevLuRQdgZ2ZyNM2RMnob4x3#j3isB1CixlZxQTnk3wjpat" + + "RvtlTnjzqkxLqJqcdbQkmnR1OFJ5zjC1SRBuwcZPqZsYyx1fTvocw7Qo3PRSglcP1ABVhwf" + + "0VS6l8Rp94rmDTT6Ylw$g3Jdi3jljyjBrzTzVbC1yxTelcUGTR$9FHl4rsKk6cM0yFlILCR" + + "mMxtMnNMrQbRrORJykLEQop9JylMMQpnSNgMLk7C#wUkczw3BQSgaDjZpN3TJZVAeDrRyjd" + + "TFfxOVecFwXm$dGLReKvlXNceNERpdz3fn#WmexBYkEZy$XMDuRnJbKgR5ccmjh#kMLs#by" + + "qlkyL8V$$MZiNuAgACuxlEUVUcz2E1HGIH4YuJwUr0taGI0WTUUG1n1TIw6FQgRHHHmS6HC" + + "IWY505HIa8AfeWeY01j3n4i14hJON0W46B8c11VA0Y8ZwGQXMe$dU$$ytPOrBgJ6NcFx$l#" + + "$RRtNFElNVtsni2hikviVvsg0pcHNxcsxcZVRl3OZilsAV3QT$k619s#vKm#tRcdAIFTIqR" + + "vvYEsBiZMByxNiLv6yxy3CvkJrQHrMtawF$ZQ97bdn96dscT6plBiaS7sthqOZ#iwUUS3hP" + + "DR41TdnMCzHua75EDp#HgiSlN2ojSFwyJzgc#BuZz#xN2l6k45quLPdGHvblFT626i1Vseb" + + "xDrdNkOJlMxquh$NWdxFzNlYVseFsCeSRFFuTpeJRkz8ROdSyN3lW1nqglqorhiFY3sJxub" + + "sIzi3XgvPmGbWtoOmKjzfcapvJ2xgXPCoVwySwDmYYVJndNtcBKU9rHgsHb#Rbb1zds5yHH" + + "isQD#IvpVr$2V5S7$VAV2ajGWsTjjPu9wgBiiMsFCVZ7mjweMqgkzECbVB$qw#d7#irZdnl" + + "99Zu7livTK0EKy7FNXUjI6VVv7ZXpz3iGdBkA$QgOKxM6F2syY9#zYsh9myABYyZRo5t2It" + + "B9iUIpmakvRbtw2t8P#Pdmie7aNF9ruV0BX0xVz#TEjg$Vlu#YzRY$WwtZlSyL5XorOjM#7" + + "UFuUMlQ6fSv6opxT#JDEFjdeGP53TrrfDyUHxtUzThMOmoVB2mT7uoxVOLbEBDs$TQwKyRN" + + "OFWsuUMTXULyJSfh$Tpp6XZ3UUcyts0DukjJOTKH0wprul8$a4zQiQ#58oxsOoCMyZeVz6C" + + "vg6l7uQoSizgwZo#5UHVWSpqfU1zHh86vR$Bvi0OSSKJe$Leuy57vsKGqn#$tSpuR$Tr0TB" + + "ar7khoA6ho6EhY7DIpiHy5vyl3VbFmMuwBitHi4RGdcDFzJ$hd8sB7geNPE4V7SIwAL$bvy" + + "HjuBJFi$cSISbc3vHJPOz1UmBPPVgo0TMOX3khHfSmxWlFJdRpVBuHLNBzZU$s#iUjm7hd9" + + "zyijk$0bAm$dX0JEZ7smNoOsjdtTEKk4VOxJtoVisz$AuPhITwOV6yty2LmZSZQtFNwSTMv" + + "CVnSJyUE91n5hnEinHtpzlMhy0RPzX5pMjhsVOaoVsVB5BjuIdAEaVT0lxYbCwk#AIlYCcl" + + "psP7zX1TV19EgK9CyV5LmJ#vMsTJ#jxwzYLz1FuYmOnrajsSwFLLfrRsctOBx#pYz$ElBF2" + + "iOlRBPzZeqpRRm#62lwFEXtlyhAv#SXELiu89l#N0ZlYSgnVcubr#paU8Xx$e30QuhdolLi" + + "2DVrfFwUYFjqif7FWtj9Se7#heqnhcdwkxFAIpWVtpT3k3SCuTvmnRVEA4EuLvIszsDNp0$" + + "cZ8no$EtMlHyEvkG6zi1WM#aot#wVQOt1scuezwb4GXZdcJbnVN2SH9ZzMFkbk0yDvVus56" + + "jKoleCZ1pdsodMVWa#Xv7F2OTXRKtnUO$w8MEJ4QCzYlNtA6kj7CMpR8gVbu7JULrybldLr" + + "ZqUvRnn#rxOnjSjTnZzhwnxvRo96kiU#1bAhABFUg3R8M6KxurKIbYONXjuNLUphebNidsJ" + + "CAFbJ8ltzp7oOOxr4xyjjo1u$OaTpD7VWV6CDupxQiLbP7eSh9LZciNEdibvMGEdMixms0F" + + "lu5ojwbqy7uVvXRoF7lIjirRIgXjIt1UIAuLZ0k$zrkEturgMMerzyyH$pqirAJLfX#$dJH" + + "JMzCGpvJcaa3LyKPoS8knJp34E2FKVD#6uoe7SjDHfvK2k#W#eVuSYhHtmTo07nHlageNm5" + + "ohFaciq3$5vy4MPK8WAK#csYF6t8tyx#jNYScfXrw9Dv5fqr2pOiynlEBgqGwHMcF5qcwkU" + + "DGf14NKK$OyY$WBoxePzDsnH9XbgYJNZEfhHjndsJiHtelzE#3kDRolCkDlI$YBu8lAFOOv" + + "Zy5#2FZ9or3ymrXQqRo5nme4yjSl8LKkGiyHGAwpgaLUFM3tQHM5A$5UGjnlSZTXkZFMEKH" + + "ZoA9SI$rtOxoBdOrpVnyZxn2YYFbKPHiVX7yVpgCESTOZNOVuwnEhGTpxi#OZFDxQdFiDO9" + + "y0J6EzVHXxbKfxw77r5dlet#0N6rFeh$2#D7FKgudjWxu7z7EmPu0pzswo8pOO$6xRF4Adb" + + "u4refFPX$ds8xOMz5$sU1ByoybGDM8Es6enHWxc57fNsjK9Mhiks4DlQCJ$Jwll$AZsF7Z$" + + "3ajqckJVYkeBoBBbaY0p$3tbMVeZzRTjj8wRp8wR$ovZ$PSIU0hNMmxRr5c9hZ3or0luAtD" + + "CAs9iGsmJ#6J5HM3M03PXZ7ThMmLw7s6FWOuXDHgxMITWd4TiAUolojY97s#yPXLKJOasmb" + + "oDdENA5efbecuaseKjfFvDqrH$HvikpRDqMQaFfk4U5ZUw4hRKDVRU1XuqSA6piKx1FWK#3" + + "JsECry3NuFyDOpqFFe$tyFj6BkHP344HAbFflq7v1Fe#WRP5q4Fm7uAlzKyZJwq2Lu4hCKO" + + "ZsXl1pOXjHkpl6Ez3s1$2teynz#FwzYEcTGZnGyYznyXJ2#0l0AU3qz4#3Po6FjEC7OOyDH" + + "MngU0jw7CBR96sGr0wxj6FM7QOTAssaDg8$XkHyphi0x0Fm5uBhWKV1hKMesqnUCH8gG$03" + + "z3#Z97#sx4EvAfRmLiHMmOk0m#21y4tZLp8KM$0lW6y$WowpSZzJhe3kLhN6NdgVl3xrED6" + + "BYcQPEIf2U04j8aSemUCF3K5d0AE0yU1#b$UccWOKdV1lWlsN70kE0US0zwBSUur3Ee#nEy" + + "p3Adni56nG8vwcyB97tBK8#0Z84w3aACsW1l0fU1I42Tso54tKJTJjty3r0iiv0=="); static final Action RETURN2 = new Action() { public Symbol reduce(Symbol[] _symbols, int offset) { @@ -4810,112 +4825,117 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [526] name_tag = BACKQUOTE ident.a + new Action() { // [526] cppo_directive = SHARP ident ident seq_expr + public Symbol reduce(Symbol[] _symbols, int offset) { + return new Def(); + } + }, + new Action() { // [527] name_tag = BACKQUOTE ident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [527] rec_flag = + new Action() { // [528] rec_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [528] rec_flag = REC + new Action() { // [529] rec_flag = REC public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def(); def.bRec = true; return def; } }, - new Action() { // [529] direction_flag = TO + new Action() { // [530] direction_flag = TO public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [530] direction_flag = DOWNTO + new Action() { // [531] direction_flag = DOWNTO public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [531] private_flag = + new Action() { // [532] private_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [532] private_flag = PRIVATE.p + new Action() { // [533] private_flag = PRIVATE.p public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol p = _symbols[offset + 1]; Def def = new Def(); def.bAlt=true; def.posStart = p.getStart(); return def; } }, - new Action() { // [533] mutable_flag = + new Action() { // [534] mutable_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [534] mutable_flag = MUTABLE.m + new Action() { // [535] mutable_flag = MUTABLE.m public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; Def def = new Def(); def.bAlt=true; def.posStart = m.getStart(); return def; } }, - new Action() { // [535] virtual_flag = + new Action() { // [536] virtual_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [536] virtual_flag = VIRTUAL.v + new Action() { // [537] virtual_flag = VIRTUAL.v public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol v = _symbols[offset + 1]; Def def = new Def(); def.bAlt=true; def.posStart = v.getStart(); return def; } }, - new Action() { // [537] override_flag = + new Action() { // [538] override_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [538] override_flag = BANG.b + new Action() { // [539] override_flag = BANG.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol b = _symbols[offset + 1]; Def def = new Def(); def.bAlt=true; def.posStart = b.getStart(); return def; } }, - new Action() { // [539] opt_bar = + new Action() { // [540] opt_bar = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [540] opt_bar = BAR + new Action() { // [541] opt_bar = BAR public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [541] opt_semi = + new Action() { // [542] opt_semi = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [542] opt_semi = SEMI + new Action() { // [543] opt_semi = SEMI public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [543] subtractive = MINUS + new Action() { // [544] subtractive = MINUS public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [544] subtractive = MINUSDOT + new Action() { // [545] subtractive = MINUSDOT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [545] additive = PLUS + new Action() { // [546] additive = PLUS public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [546] additive = PLUSDOT + new Action() { // [547] additive = PLUSDOT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } From 6ce3faaf08952b0ab4bf767266eb4ce9a57084a7 Mon Sep 17 00:00:00 2001 From: trungtq Date: Fri, 12 Jun 2015 18:46:30 +0800 Subject: [PATCH 122/127] fix cppo grammar --- Ocaml/src/ocaml/parser/OcamlParser.g | 6 +- Ocaml/src/ocaml/parser/OcamlParser.java | 1072 ++++++++++++----------- 2 files changed, 542 insertions(+), 536 deletions(-) diff --git a/Ocaml/src/ocaml/parser/OcamlParser.g b/Ocaml/src/ocaml/parser/OcamlParser.g index 23756eb..a08b9be 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.g +++ b/Ocaml/src/ocaml/parser/OcamlParser.g @@ -2475,10 +2475,12 @@ toplevel_directive= cppo_directive= SHARP ident {: return new Def(); :} - | SHARP ident STRING + | SHARP INCLUDE STRING {: return new Def(); :} - | SHARP ident ident STRING + | SHARP ident STRING {: return new Def(); :} +// | SHARP ident ident STRING +// {: return new Def(); :} | SHARP ident ident seq_expr {: return new Def(); :} ; diff --git a/Ocaml/src/ocaml/parser/OcamlParser.java b/Ocaml/src/ocaml/parser/OcamlParser.java index 34e20cb..c8d005e 100644 --- a/Ocaml/src/ocaml/parser/OcamlParser.java +++ b/Ocaml/src/ocaml/parser/OcamlParser.java @@ -1,8 +1,8 @@ package ocaml.parser; -import java.util.ArrayList; import org.eclipse.jface.text.Region; import beaver.*; +import java.util.ArrayList; /** * This class is a LALR parser generated by @@ -23,10 +23,10 @@ static public class Terminals { static public final short RPAREN = 9; static public final short TYPE = 10; static public final short OPEN = 11; - static public final short EXTERNAL = 12; - static public final short EXCEPTION = 13; - static public final short CLASS = 14; - static public final short INCLUDE = 15; + static public final short INCLUDE = 12; + static public final short EXTERNAL = 13; + static public final short EXCEPTION = 14; + static public final short CLASS = 15; static public final short SEMISEMI = 16; static public final short EQUAL = 17; static public final short MINUS = 18; @@ -37,8 +37,8 @@ static public class Terminals { static public final short FALSE = 23; static public final short TRUE = 24; static public final short LBRACE = 25; - static public final short INT = 26; - static public final short STRING = 27; + static public final short STRING = 26; + static public final short INT = 27; static public final short FLOAT = 28; static public final short INT32 = 29; static public final short INT64 = 30; @@ -133,10 +133,10 @@ static public class Terminals { "RPAREN", "TYPE", "OPEN", + "INCLUDE", "EXTERNAL", "EXCEPTION", "CLASS", - "INCLUDE", "SEMISEMI", "EQUAL", "MINUS", @@ -147,8 +147,8 @@ static public class Terminals { "FALSE", "TRUE", "LBRACE", - "INT", "STRING", + "INT", "FLOAT", "INT32", "INT64", @@ -238,508 +238,507 @@ static public class AltGoals { } static final ParsingTables PARSING_TABLES = new ParsingTables( - "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" + - "ZpvrdOfpJvA3mGtcdC6AZvF6ELX99U8qaZrqI3WfRAVZDix1CPo3y#3KTGRS8723E6UGulD" + - "JNfm5ojXbJVt5ojhf0JSGt43E6QZu$9GNPu4oTbbJVx6oTdh0xGnkPyxPMV7vAI$E0cNiig" + - "R#OcNjz80Zc#d6ETqKdv$ouYnGnYvhwYzMrauFkAxWkd9ELyNdfxmu2vInovhwYvMrqmCEC" + - "r7oR9GT51ydFTyxAAb4d4QoXmvflbFOJiVj#TuXDjyxv9dlkiw0smxSTfopdUBpKrwS1ShO" + - "PKtznShQwG6tBRXjEMTRnUUdl3WBbB7BclgBbRNJ0svNSBjopgwApqzvSHOeOvSrzHShQwS" + - "7t1xWzk2SFHIVd$BYB536BclgBrRMJW#uaU16Siv8nUUdl3WBbB7BclgBbRNJ0wuBk2wSqq" + - "NnSTBplOkIIiHf97leaEOxXUrqt9xlNMBplKkU#Qxh3BZEu3fpJcV5nqdZxAoa4d4QoHuw9" + - "9mKjjDn6sVd6CxEUN3gEWEk4xXEdDD9yN7IE3ifgKISHhA73WadXUrqtCRPAOQpKnwSkiw0" + - "wmYk8#TqL7oSDCwEIWgjXK#9KAotSr8WsKE7X9F2TZfku#oeSD8JxAhLH9o$CNKQHEwROeP" + - "w1xiOwZxbZd1MkX#uJpgRG$P0CTqxLppXlU0jvohpF0Neukpb7uJyNvFldEYjy7x1A9vqXu" + - "cRn6JtBF4KIpphFI$gnUFkbU8t#Ybb#ZmlxXNtYVl50#91yRHuHZndwU5LzrRI0tfuDsfUZ" + - "J3o3dPW7wgn2uNTUWRlJTHT53jghV17Yy7EDFZ2MqdOnLB8FucSAIvynZwQiCC7Tk$3GjZ5" + - "6zvJmJCqjz8ekakIiQTzruVtADelz2uGAzTvshdPkSwvoNdEww5ol1qvVNxsKuJtEWl8zsO" + - "vrrEkCnyzVWBX0cUkTwUpIjTqBtKiCn#bvYBlRFTDPqUbuym2zodAotxWd4socREzUuoElR" + - "iBwFXgjj5hdAEKdRDzVALqp3bxa8x5LMmVyza#H44TVsCzftIhcYd9EfRlkMzcs48oUv25P" + - "ChStUstu3jZaFgQ#xj25WATBePEBtIUqsZVS5yNoy0CTllHJ26T#3sSyvphtHN0yAExt3dV" + - "Gf$Nxb3J4uJUFu2ispyW5trs3KkjO8db$W6cLkTquMKcPKuF#uP#ecyOjRNkcpVRtKdtZJx" + - "Bd5im9$vCizYvr$JDEo7ic$Eyyn9cyI1LitERNRDpW$E8EupwXZABtBkTpPtLsJMnaNdNGl" + - "ykeNUMsEWpJd7qdFU##00hsTF1o32lN4X0lrfyv2u7fvu#ljWz6lQpFQsqxYBOpmdEyOvq5" + - "xZdCURZaShenOT0Fp71hcuIo#3esUcRv4tkK#H7IUyLnEL5JxdXZ0taTKdkqRlkIh80vrgC" + - "m78pAz1Ypau1dvwTlX6uRcHSDyeRWUl6E6LNPz4RuWhWCd9$3$OyagVFbIeCS6651AwX6jU" + - "DL3Vl6#PjkEzeNDSN8zrEGGdoGtrbFrOfl29zJ66cniZH2WTkg5sxkph4vGxHRIqfHXfNGG" + - "doO#EeIi8s4GxEjA1ufhbSmhYMk1#Qibu$nWNRnAp6Q0HjNLUCo3OXMr22$1WkLP9mNMVYc" + - "VdoEiPrdNUmAPjP06rkht3nRZ1FjtLjCTAu2agG7yE5b8owztcjYPFFkAx5E8Qr4wvm7F#b" + - "sxgc66K$ptuEsG8IAfVaI38pdt4W9RC3xEjpoiyiC7B86egSSyFQBKnyDz4ToZbN5oDjNmK" + - "bbE$KGV1RadOEiakQyivuy4E9Tmu8oeQeXZEgMjtMLSL8rrvGWlpOE7AwJvYlSXmJbrVnE5" + - "u5dUcozBoLyr68pkkbsxgo66bS1IL2kM3zqYbE1SB1tkSKzxu1FzI$t9HWcV3q#1tl1D#hF" + - "EnLC#nJH7IdpPoJOgzQ8zxX$E$PXkVdxBJpCmkSU#aingU8LUxop49hfnKuY#NPQN52KtjL" + - "dZEo$4SSVNIdHPclYk#qQZvaQRvTalqNeS$#AxCW#o#RCkVBImWzdLRi4rouso8$ijlAIv3" + - "2w14oUhT$$8GVq$nTKUp#MCBkZysFdVD4QATQyyjWfTWdoKhv1DUDzZEltjvd#StqXKzmIl" + - "CpapMlnvPrujoBizDAwrn8doUS3vptGxtdZgtMUxb$kLZYZWFtY7ZC6O7LMP#SdKl5Kzv#c" + - "Gl4i#8XH1yNzpXBzFFiBKNIoTdOsoLU1#SQvrvFE2kTpp2kxBAVkTdYc4YEvFapGs4IGv7o" + - "PD2lf#ZAqSRa3A8IJfyaJ5ZND2Rd8C84kPNU0v0yMKpZFevNcB9hdB7vzHJx42RwM9Yy$U2" + - "dr9CtErTFtY$3whrcQSOk5nEVw9zKv$g6OaeQExjwRzCKcCgHfoo9D3iYr1ETflpj5IRmm9" + - "GvC8h9Rvw4oRofXp31HvogutVR4oRpXg7jGyaaidFvckH8TRsbSwxcT8TuPv2$FVm#T4r2k" + - "HvcjtC#pTJiZtIQolv8ijaVYRE9KRsWIF4SPxJUWKeVAjSvpBdHI2PHM0zahMj3dNEvtGBx" + - "GnahOivV2AjzXu9hMQ58t0Nf5ShP7vqhGiaaCd944LGhZ5Fr#YkyNJX5eQALwQaSL5JBSaL" + - "SPhbo4LGwDvHC8YD7546rt3ZodVlyvTvbdA9GBSz5vVNbMfvNn0YULow2IkU6aabav8WYg9" + - "utZdpdqQ0TXUhvt17qTkPQdbF48$YSSX5KAbU4aabav3H$DJcs#UUylVtdv0oLRchtdrEx4" + - "yNaZEWfJDVqh2BA9zz$bavXb2jdo1aK9t8#3YMJoCWf7htNruGgHqxddCjLt5cZP5HCJiz1" + - "HRBFAA9yylrd0bJJvNIA4m5L89b4Haxn5gfdZ5Ffv3kVA5x5#2GGkP$3jJojYEDFawCHP#a" + - "VQSHDRYYPH5JEKCIkdZOkR85zPLTFEp$asDK#NCjJYjYkdb8kObSgLuIIIMJa56#NDawbir" + - "yEd$S7YZaZSaQGQdbI4SUV96T6KCjmBaOma4mY8sTg2aRmIUF25fml$IV3t8GHf5gUKEJGl" + - "UWdd3vmqH7aN9Pz8ZzHsQ0cUmIVC8vynRElHl099vipWaTpBOyhuX5yNBd86AXS4KecaP5J" + - "l5sQd3EVS#vp5f1lsiX#v3#U$OZ8cPlzIEYhHVy#bdrK4T$5fRlBZxeJE5jTzSrNkTpge$c" + - "9oWKrsRfwr3Zo5QzyrjMZxf7GLJbq1Ji3CY1rHd0jZobYNJr6BlkHweaATQu89PF8o2dUqj" + - "LZngbqzilXAsj$BD7QgPQ1YZW#a9ooTeUVFO6TSIwiFP1C8YfdrnHO#q3ZWXQ6Ug$u0yDSQ" + - "ry#qgI21YXYQny050F4KLPdZr2vB3iWFr7PaBTqnJdo59DEVlO7vLCi#uDNdVt19btJpefm" + - "eXf4lXyyR#8DzYeehd93oIGoSegtK76Ed6RIoSz#htoAPR#NqxBVswHhsaaHTfXfv9DJ7pb" + - "DJgEuoWqbayZ8ATv2nJdoP9DEVlOxvLCi#vqyEVkTJRgc$eg0ucJooMbK9ykJAQvoGyaaCd" + - "AAjr1nZZpHf9EVcK6#SmZ5CcNonFWT3AwbdoAWE95ySXhLYV94YglSK3A9Z9pYBLIS8qymw" + - "UG3LJ#DgXzGdP23YchfgmWeJY2Vd4PrWZo1uYetb4mY8wTu2nNdoCacdNoWwgjHzGMgoJce" + - "g9O#Ye1YCldaDAh9SZB5LMuecKH6Jl4MAiwHKqqw#K3LHwFg0rHJSr1HBJMAW68g#NvDW6g" + - "gd4fnbHjA9f6HKxo5YdFaIIQTVA2gqQXgWEga75HKIsz5G74I#UGqgfFaIHHNkQ5a4XavnL" + - "keE4TECUda0rLlZQetK4t9GKMrxAW8AAQGJqwZcYAdK5pbXf99PEGq7$ncmDIeqfaVwhSmR" + - "N2OkxPJBOzeed#zUmHfZwYrNTVyjSfbsKVo4vKBUKjNAcTxamv$g4erkRbtihcMXnMnrCFa" + - "dACZzUhSK3A9Z1nHvCpmi75X2#ohynLYpfcnyzKKhkKXHIpza78HL3etb4mY8qSKGVMGSM4" + - "Bx2jKY3dpOgZcSYqFAcBf1vMBeDAveMGI6Jdco#KaSz$6Vn3d9PshuiZJRRXl8WoUXr2$bu" + - "SrJpAowZwrd8GIUUzgacJs0vIYAxnnTBVKd#7FeBW$GpuRahk2fDpbuFHTJNz6UASNVEHEB" + - "vrKt5lv3g38TwVNFClXJkBd3EwozBhOOETE5BWZA$yTwfcmEtGlxLVEJcAviqLcbAFFEUuA" + - "qIB$NUhSxuJTDzrRDRQxtQUSrSxas9tUujXYTzxKNMY7zhuOGdU5zmXZQx6MsAOt61jzXZf" + - "loED3lLcwpx9UZ#SHN44Z6EhDkhD$lCBbFg$lx1zFjMNVSs$DlaVatfrzprdjTurZepogNq" + - "dbaZKVXnevFRm6uRPY1ir7f0zrpaM9yrL9bfWU8dINHX5ctuNKkqmKlkTtYRQCjf0dpX3Jj" + - "5GEARt1JL4SfnbKxGAk0zK43Jv1lYefdw0uEPjSlY#0z5UoxqFgVIOAt$KxnrkcFDR7#yaK" + - "O1CQ6wKPH9q2hYlLW3OV8b#Lb0zHd9nDgXeAioiXjPA9mlVzJl6MAO#nhKocd37LyjQOLgY" + - "hHKft5gB4#QeaOZiMdWkGuRcGNUa#XNApeoslvTC#EP$WQPyBea$xD6YUVjZGUTf0R1Vz16" + - "nVhsTi5$y4RFzOpzYk#0dO$hcUiLtr4x3zPprZksVjiRd7hMTi3$y4R2UiPsn$#WdOfgrVR" + - "ExtFm7RZ8QVGvmwisSv1yNF8NIDv8pNg5SuusBdjwD2RDxmejXchLTi1nV0jdjHRAUjJsoP" + - "tGfW6rKKs#dh5Tl80jYM5CFcZLkxSszezRdOWfpSfrfiR3SLnNRaMinJwrwqevyNSXRuT$b" + - "tXRZeNZIl8ND3RDwTzZnrpYwARK4KctVh1jFRxKMndRyMzZPVMzi2$nx$djprZPvgJyO6NJ" + - "LWVVEkM3VNW4cVmazHfS3sy$M3BUaQiC7ObZLYRFSrOcolDs9ixpLYREytOcnVhDMUPNtM8" + - "xO6NsUbmyOvFt5zounOQsn3OzZ2VUlwP6ovk5md$Ar8BZQnPqcnUGMndLLIR9iqOhqrBuJD" + - "NVjvkYwmbHN2vhLUMsnoOWoRzL5v#R79YHhRPlf#xqGgaJEcyIUYqsERMG3Rp2BOPcfiMsX" + - "iCwd4kiDcFkdNjuGntQhWN2Wjjl96ZArL8yRMfX5ZswOHOzkk4MDhtuYnTMp4s3etOcnT6p" + - "6sYaQChSh6bdtVlLLzu#VUdNq$2LkgxoYjJrAQoJ6#RZ4NM$S8jjXtb74CnR#Zp46Ga6PoZ" + - "AzA9c3h6S7s7gJKTymKhenZAFwTU0w2X3IJOtpzBNmkjiCZs6BVYSSnwE$4XVaUEyztuZQ2" + - "X3IJOtnLCW7RbEXSoBwhlzjzrtqgB1Usl47dmjH6F4$dDc9iyninjeMD6DlvZHZRXOqOsos" + - "D6DjTZHZRRninjZz7zgmlSGxvaWZda2yJpo78KvB954UGb6PoZAzRpC7cFHx1zWMalc2YyC" + - "iu1fRuGaicKWw2X3IJOtnLCW7RQczDP3$zGk#dNs0$$IAEOSEEgVTPuxKtx#j6ZEsxHepjX" + - "wYzDIfi$swutho3Yc4BltlEyxtCN8LDFc2zpUa1YZjdomTiKlBoWSm#6rflybWBsx4K9sUJ" + - "nWPkWsCxsi9sDCN9sQInWTlWsEwtiDrFSN8sQMptP$fkS6p7MDYEeJWvcpGsS1i8smoDRQW" + - "zJmK$ims$ipXEZ1JglR2Jn3bYbQuf7ROpnBIysCRgzkV0jH7jBMnZ4lJsgAMtHobEpYO8Zg" + - "Qqp172l0rcjdktM9pmlaVp3zCYz7F#VLgOtEGFSheaouTrQpdj#$jfQaQ#5RU8PNMOs6giN" + - "20$GyU7cZJjgp4KTYdJGkhsp#2tl$GksFubOTsHzYtaQzs##XHkFqt$PvXVuQXVqP0V9vRK" + - "OMB$O#K2#LjCtAG5qYTfca6#5RU8PNMOEEgnSg6yYPkqG7gIffF8j#8MiQmE4rkDbGlbJTo" + - "a1TBxQvf4lXMtY6LrcDXgh5meR#8cBP2UZd7TMun4xdIVtbinFPTOLeU9hSRAXV8cRj82wI" + - "cQffDlnIrYMHqcjXeh5ygRk4aBf8$ND8LyAsuHo#emiTLOkL3Un4rQ83rDq$7aMt6BM5Q7Y" + - "Qt6oeNo9cxI0kcJDKqZtufRnB8wJ6mrLYwKDt6J5aXFrNGo#LRS8fRLOMAhiNAXl8cRj43w" + - "H4rJoRVY5h6i3XDRZPKBvKtSf0NI9sWwaNmhRX7BwZ2nrLYvKDx4JLeWFLdJ2UHRSOjOLeU" + - "9hSRAXV8cRj82wOcQ9fDlnIrYMHqcjXeh5ygRk4aBf8$JD95yAsuHo#emiTLOkL3Un4rQ87" + - "sCfkF8j#8MiQmE4rkDbGlbJToa1T97QZg6V2jk4SlgCB7LMBbGtiHDMY0zGTEHv5jnYrXMX" + - "ucjnig5yYPkqWBfepHD8D#AMyIoEaniDLOkb3TnanP87wtfAFAjk4KigyF4LcFbGdaJDsc1" + - "zB6QZYRVYbl4iZfCR3LMBfGtSPEcVVr#FUBfFOIvx$5Ix#8KUT#lb$iUhtWDAfHt6zvPGho" + - "ystzEtcsJaGDdtevu3Rr5KWZpZgsWpcSLAjIN3rN2UxoYDUZm0iCxIvY$0D8NsCHIUuFRMt" + - "DxEzUG7oUJcujMjxItoa#Gtzk4WTmeKGL7iL6WlTcFaSdLrUTy6qevoV8cRjBWHehkFl#JX" + - "pyID8hz69bS#xsYaVP6wjAQ#8tx8yDK2kbt6ipjWHI#qWN7V2wPN27uZVlyyUwssjj3bux9" + - "UtUPk4c3Emqfft7iDCNdaidDsx$JT6ablJNtxxGmbKBk7t4pbICVuHRanod8pTU$cIfVIsz" + - "jvBs7JNbJ1zmivSW7pMG$HYOtoJPLdYwT8s$Y9WskNZdoGRFOZv79pTjUlIwjfBSEvKrvKm" + - "VSgSgH3wfdFqOcDzRA64MSDyQItZgKD#LD7N2dA4S#w5JsupH6vPfMnC$2DbL9NPf9jtTAc" + - "1gse5OxxtugnwlTAM4zvBmxYgx1BpXgntmXsdjwrwexJALxTTvnuRjM7VsMT$y5kQyYYf4l" + - "z$KwUDEyKprTXydrjZQISLBbH21l8#3S#rGj72V#FiJkiqdBtkVF1gBP9ElFLdmkCMeTKhr" + - "EczY8HygPj31LIN0xXohYUWwrCE#ZGvqhzp6ISJBbdFdUYSGx2y8tkPeQISwPAm$HH6KECU" + - "$fyyOwPpldivJE1HsIJ2HZOJp4rEyS4UPekJfDp8kSZya5rILJj9ogAOo5jS0$M1Fp2MtfN" + - "D31oHGjfseAOs4jy0$Kn7n2MpeNT60oHSkfci9OM0lyCPgOJsXBvuB695EqdAefZ8Mrm1#l" + - "YVc4jdGkQ7moHSkfci9OM0lySPgOJsXBvuB69LEqdAefZ8Mrm3z84$C9RUbSq47952sdQWf" + - "ZOItmnsfY7ib38dVJJJxLEZQPT3bJ#zX8osE3rB5Yh5clATMvr#gGrhfQhrasxtkoNVj$Fa" + - "VRBMEzflLfCQ$NmhH5wtMaBM6tHUjryRQo7ofIl6vBrQBQ4YhNMM8auyIor5RietB24AlhB" + - "SfbF$HlKNmkAJaLwhBgtFyfnLHlxLp6fixzj#JhhNmLemJdZ9IlobUTLIfkKz1RtLQkPjL$" + - "bAcsYcYsX$z7$uy8MxgjdLNELsuxgX$nu3$Ag2stRRIjfFyeAzwM$Q6sz3jXZmpVQv1iCU5" + - "Um#$jIcKntcsHrhuAh2rOmwWjftuTwV3F$f#D3X6sqpKaw$3F#NIOgIpULYRox#75T6ZQoj" + - "LXWzhITN6BzyPrw7vYR1fjvRFfHy9P9nznFwAuVCIcp4IgIpwI$LeHuSv#xR4jUd#p#qovL" + - "9UHZ9CbgkpePOCxzwDmeqnU7MJ$AShXMX87#XgyuW9AqdTcUDY6DpviAztyi7iIrK6mod4k" + - "Lha2Ej3w3kwEhBqEkCKFGdJXt0Zwk9yjPVtxm1jk3wnrRtZZQMvGdZqtwDy7C3UGxxODQyn" + - "qHsxYVpNInt#JQtnJpRPuZHnsOwcsKIqcrHZc5hCa#byjzHzSn8kSlLb9S4shaqbSgUxDS1" + - "yky2$8VgtlrSJkquYnXaEPwDYDySQ7TKJ6RdN1iHljl16nWzceQt4#EyW$XmD1VP$6kIP7A" + - "s5TwetVIyBSV5efNfUn3AtXF3LHNMmPlpUMaLsTP1dmsvewLJl9jaRrS2xL#HRgAc1jgiu8" + - "vkGwtuhQPEuO5BT9YValUGsGnoa#by9SquvyHJcSALvHFF9VYH3agNRvEJb8V4vamYXn$Je" + - "qgrlKLbLU#E6swKH9wGNjYoLIhLdEZWLiDVOaYdDDiJgT9SNkK6Z1iLPTRKHxgoxhYYNrNA" + - "BFQBB$OlCpDJvHlAyfy3NfxoVfppzR4ScIl#xqvvyTraKjX7MfrXgklpW#gZEio#bM2ltbo" + - "EVM6Tk1q#1Jgpvz8vF$hHNk4VIi6QtwL2Uj#fafQjNFJ1DZugj#Pcg0JoIj#kwvd3tQz4Fl" + - "PNnrNFZVJFstTGdUTvm36S49cLqrWcL0GFzaItlPKvdTWx5yEsVVoV#qdzBWcKg37bqze4P" + - "kywcCzMswkqBqYppjL#WTTUewHDqBM6RNg2iR4$mhxLZh7NN5COxcKGvhd8qQ5uVN8OGnir" + - "TnZ9P95S2eQnHfUctLE3fM8sECwB6XDOgy61jSe$oPTbV8doa#JXYJqzmLn4NVy19#l4kLN" + - "12$qdsGozxYNIvluLflaRSeFqO$atUPN8Ht6HSXLVOk6RmfpSWJbtzD8HcwWrvi$iiR87i3" + - "bxX1yN52seCcbtXd2SSVZ50W5xIF53N$aPCVvGtfK8ObibyfKdoELMW9FcL$bKnHQNcpSus" + - "yMN4KaXyb$xRiL$vjYlDlmsh2pYPLYhYmTbMRuWhq$sQz#gRelzl3u$#EANRcbiE8pFT0#Q" + - "yPaIVaC5gbIPxHwBk6qRWS5hskLVNRPDNOm$in3SQeHlBTDokaaOBxn1FYKV6mQjdRpwbpU" + - "0t2NaXtViD$9TGVVcSZ$tUWix$wZqNd6gy3$OkxP$sV8QLdp5aivxy39Vr$CpiY4qO9vIzK" + - "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" + - "qPj8UPCbtZGySI5blyNUzor9PByrF74M$GCf$s29VnYUk93MoHuGUGOp5hF#grFGIIBy3we" + - "$1YUgy1F$HShOIAxzUz8nuj$6XkIzR7Dhn3lC$miEeKri8NCvZ7w$ELhD5ZcN9SxHenX7CG" + - "Pbpv7Mayc8pzMhvbo97LgU7PGr4kSWPJJddKFvd3WRFM09o7EAF2keTOoEw$rUXlj#uK$Ez" + - "xKQXIDSuM6WDX7DH7FHGfI9JSLcqFeMOaknbMWfoiNMeXN6eOreAxOHsuhjH3lCYmwYe#Y4" + - "kTP5T1NTH0L6gafKY#wY1qPjUx63w2Ls5Br5ZUWZ#cBq#ekTnCvYW1We1ebTn63eRQWO9eQ" + - "BMZ52x2fs4xkp5lSKUubHOc#nZzXNx2Vs1#83qDi3eOk3n3WnNXmiwiGXub1nc3XS726E5F" + - "JsdwCr$eaRUKySz8ImYuse9ytGanPYOGHRHlUaDJ1lk9xSAbwtUlAwxabPOa$6ewtSCVa5n" + - "kIb7ElQECPX4$J90JelXkxeZQO7Cz63wM86mbF4gU9kSGzMfzF4$HjH3oes#XxKHNhWWAW7" + - "cOse1ujYFJYEUp1f8#g14#b1nKRKWtgh1uJoB76sE4VC5VF4VF6kUA#f1nkm1ztGWtgqOVV" + - "WB5ZLnjE3dkZ1AuZPFUY9sCRJ0sL5$zTwyFH6s8EsaHxGphonzM16f0S$4pULh0T$Qt0FQ4" + - "yc77OFnei99S9VjvOZu4NmrvSCVteByZJ#9M9yYR3#AJLMeR6s1TPcM6EIyCr2suHl5jl$Y" + - "OtU$eMr5pT36qdutXSVC3uA5vMiJvUaxbD$tQTBIcPJ8r9Z7Q#n$gzaMFkdndgXnjg$P5X$" + - "anfhXRMkbmRhqwcnVggnBYqPrhBKM3VLMCjAXdNJr5ZBhBsnD5ZBKsDTQkqjfS4w8pNMHTQ" + - "UKHgiYngy5rop4SojifBFhIQiJLYRi3PXdTdWSrPvoR2sJutr2OtrYP9XTL9Z$KHZVN4ZEB" + - "lSLlBpwmiDdbkbkpRidXghex7EAXdMYWPZtHZqQiwlTIN3clx#Nft6wcq4S#jt6kix9SEwE" + - "ZNM5pNMyIN3wgN6EhtaDb3VuFkvzHk1NbyhkLwdQwoP1jvxRfk8RuQ#zrp5xPVgFcrw$RzY" + - "FPDI6gmz6tpVQsB9i2vCZRMPnhgmP5WVI8srlEJNEkdr#a39pxa$JurrPidrcacDjOl6sdq" + - "ZE3ikBFavjseZmZfe8yAQtWQwbtnzDVUIfZVmtD0Z4Lz$VMuOBwx3zKQfpWrc7NRMoNVMX9" + - "xmKUjBIjOdysp1EqNxz4NaMlzOOANd1mZh2S3wxnoizvQiJsMfnscYxfD0drnkWt3#7JZhO" + - "pZLKokjIzQdoGMVnBVxr5FtgQPaStzfwdNgvu7#Iu6p9hMTp2hvMQKizNMOjn5TiomiwVYd" + - "FrUN5cVwxsMQRIJwFA2aEFTFZNDqIN6QxxZAY#ByS3tYB4CAuQpAmTcDSLQ98KZP7$NK1lL" + - "KM3W8PxxzL3q5IZWSnh5#diQjHntKW$uvFHZDFQX73non2AtMYel4OWkRG1qkzu3Gb1T4Gs" + - "4P$uhoCut$9E0lIpNkb3i0OqneI9xscMgST9F6lH$opBWFZ9nVQd4w8Pnr1N4woFF4E8G7Q" + - "voPr3YhKMe0IXcStN5ohHQlvS4vFS0v98Qpdd5sBu9p4UEy23Z72n#Iro7rpLGuwosS9Ab6" + - "zAj4dCyWrU3i4S5P1YAS$GlY37zbz37QfLyPKOlLAN4#3foNCSuhKKBXh4x4kH8b3CubCPo" + - "rZ3EJ4kVNufi0v$CfVnKQwhCThCNCjcISItA#5n3Y5y3v4j0s1EUbG4SuPo8jdNsE4ty6pb" + - "krVJeevq7#qZpscSdvpbMW1DddBnZdfIbntewQ2ESob4Y7qxPF1$9cnKd2wLaumtD8FN1I$" + - "OIpTK6Sr5P$FTClmzYPjXgAiymgMmpdIG7EOosS9nJ4QQz8zMZBuNAPbEE#dJMFw1UN7ieb" + - "dvLjd4jYE8Sq4ET2u2pdw#1qyuXo1eZVCiu$QvnE2fpr4PoVOnpIu2m3pj1Aoq5afUbnbcd" + - "xl0HONEGbdqDid9FNOjnhz3mrEr4vukKyVcbnAlkyWgzuMg2TJOlYtFKdsgSQznRWDsqmpc" + - "wuFkuE#KrHBWdd5CZdhak4ynAqcGRdTE1KfoXbOUgAC0tEXIWx0FQYS5R1NgeWUrrHdE4wN" + - "uLsxzJwB2koVWx2Nb8Mx2LNOFGMukoI1cSPMXg0kXHEEfbL0MLD8audKPyrmDbCwxCmpWeW" + - "RIT#5U0qEas3qs6ScG3dTDPFiZvjdCq3d0iXNo#EIx4VBKAxPNn#lHrrBG72POmi3Kx1EDL" + - "yRyOunoCtURvJUmRdHm7EDnk0apuAvtHkRPduW$XZAfmzhFteSTZATCIlGBpOV9yUsT$haP" + - "u6Pnca5Sv$Y6$H3ktlQrAEksEjIoHRm#Vkv75lap3knpBEIrBCzqLyJYMSQjqaNP9Uqitt$" + - "GBxh87KTFWrUSvB3gHoSLOrODpfUa3fiugl99O1xIMfS8wtzFbFyHrg#b7yAyyyiiTzlxMQ" + - "Hmua5SvPw6a6ECyIRwHSb#npNG$Kca4TNpP0dshSqwppYyJ3Y17EyS5PgKtASL#5ik7#JlG" + - "Njfvad2CISAwozFcN8ZX$2EnpEYY3qqYvUA31#YJ9SiPwHIBEuyIaX7D8niBff9plZZwHD0" + - "F2vYddaHFeyme#kzRanJaTQ79n2iQva74sAxf#JcAST5NK3BF0GRcq#r4PS3gCipdVfQ7Li" + - "sSUVVPCmDcCSVPad3L5SFO4BiBvFLy$pa9xIrBQ9yaEW2ESj#cov2VXh814$1bF0Ld2MP5Y" + - "VwTvv33Elz9AwZW87qvv7QVqUQkUHmRbdOauRqMRXN4#NWJdRHhdBEwpQI#TFik3yn9XlWI" + - "oC$Dyxr5chPzUWFDPuApGwzA88kSb3z8UdtKMWihWY4k3SoQFkyBPNZo1Mbv0YUHzyzb4d7" + - "IbybkDiw88paMyNquNJ$BQv#Wm3Sv5e05OmmZdatm5Jxt#NIBED$BYDFfSL0Id42qZRX6$v" + - "IdzkKumJlkJX9FUnwvnIcbmWdCbFeGJVW6SCiyd3KwM6m07d96o2JWvlGbd4yucd4quct0s" + - "uMp2sOIp2MSJpYQSJJYRS3RXRCBv$m7Ey7jjZgNyNZkEaxwvpuzJt9k3qq6huHCAXF9HyPX" + - "OWNnwCg9SeUGQypsRLa4QXNjRLC5$Yr7IymEzWV5cSOj2AVhpKu03#2d0UzLJW5nhqjray$" + - "t#2a7$GtGQfCR17GmNVoz#lSAE78NTUWOFQKMn8uVkDb8TLLm7ONV0zOQ37WXt3Fjs1R4$P" + - "w4VeqSn6NlQfmAlAw3vRgpxq3x2jeyJVP3JJqpcfmAxyVrnaXi2kNF50b6hn#nNSDMGkrZq" + - "14TF1GxYdbq8pVT3M2lC6uyt4LU9vfpNdKiVBMuKTneTY$iAeApdKlyLoxMTauwFLZhc#4B" + - "MyIBMyKMaOyGAwNZoskXOMyWpKHqZjPXrHsQbHayMGhNIJ85EC7Aaqu7WpeU5N62XpsjtF5" + - "F6w54OXx59i6wM6iZQ6Gpjw5h5KsAgE5bCYziFSjQwRsYbJFMDvKtDD8kR9$MDn$nUh4xvQ" + - "kv3VKEPuz2t5U9WZ5anwnyIGVzsSVISXnhW2pCoy7cjZUbY8DSm66kj#GLNCAPY5jlF776w" + - "E4ESoVNy1qwXxmVqvwtDtDMsKk29NkJIsXvTyx6swv9zsSVSPGkW4GXc1UPapawXvsxnDKN" + - "fgpWkpWlsF8qBwqWK5zc$$Pw2VfmRNODJuMguldWE6bpD2HTgZEWhnCKo5syONA6#kDw#xD" + - "CQt3p0zVj0NySnBjIBaFtqk7Xr$Wcup3XYfS$5TLM8Y#LkNF#unClvx7vTZ6D3xLvSQEDIT" + - "e$zJ#E2gmUk6qExZsBYFMsTsXVL23T9xyq9wuIu6lggvvtY#W1N3geDOlSqC$kollEC8#yU" + - "wtK#oiWdM2USs7oi5tMHTJMkh#qqhjWfOYrsshl5FPn$lnx1#4xRJPskS1OZw#ffMHVN30l" + - "BLtEjsgjalZDoxXaeijDAEiaLFoMh#U3I$egneJDG2o2Eph4RCIu3MIvwWWlNxCheRilpI#" + - "sqVHLwxBRn4tuK#pKnxDtObgeAQBv$38Cw9QWd7ZDifNo2IzXdbUOBdJuKzebvhquKze6CF" + - "VZDMs2LQQvEBcIiTNhzCdet9sVrFFkDT796JBq3NjkmJ3WvM$Ps6SxtpSMLDB$qZANK6r9S" + - "xLad0p53Owh7EFGE#jMVCTYOZkLTuVWaJFoSaS94rnpgD4sOSEN8jLsjhp0Sh6i5nY8otyt" + - "iiZ7HsfXIJx24H3q5jQNGKn8ctkzxgrMyePYInYvIVvgnq#EiIxG8zSGvhiA4kkbARDCe9j" + - "IU6XDTZTgOH4q1J7clOP6ghc4TNg$9$WV1aiO3q$71DUpvS1Tm6ovhL$ysBtU53h4oh#piQ" + - "ERlikUZU52Sz1EmrgazZx2oFmJwZ6ArVoLexotNX2jHP5prg6ALNcjKPYTc3JxN45IXhjOV" + - "Al7hneggL2COhiY42ZNtmwuRjojL9w5gdNEF8g8hxBh1FGhELQUqSdqAQm0gn7wkMr3MpgX" + - "4dK8b7X53T6v9KTdM7aSbPM5KmSfWKAaHNyTpC6fNugaDPrTMwIHTEK2bHgUMzuS6wSf6LQ" + - "eH5CSIAkmF$z#C82He3fB48DfrbQxGSgs#Zke7VTJh4eCYg6g34Lp8kOlOlsZzw0fEwUePS" + - "JuGNC08r9c$HRAkQ3z7E4bCRdpMJdO6$$XrRUsmgEWg6hiYpMljbrjzlNQTs5Lanq5xD89q" + - "5LOBJRNEkVvDNDk36gsrlGbL4wecL4se$c#YKj$uXwXaT6qlRy3QJZMg7OVNThg6bkjgRHz" + - "levAo42fz9pjt7xmyKkzwFL$9Hd0zM59K3gpRrDW7zXorgzOovzH7BIiSRDr0fTkcqmhTTS" + - "r$nv6#cQVxgVJyIZU#QmKSaiv7FMFVgT8y2xvJbNGFAxpBMXkxqqidbJ5q1r3Al7TwwyCx$" + - "v2u9iSIqtmVB2mzyzrIAQDtZ3bd8EiiprrgcVETCB2DqTZ6GQyvs8jZIxxpbkUxwfXUrpSs" + - "pgD$X6vcwIsk#zOyWWFv7cvuXxpWdVq4R6KDrblOGht1fb6626Ue9nJGXyZJ5omHblzb364" + - "gRFpyKa6zmJsaDHZLMy19zOsXiFIMDEujnI#rfjlyTBqPR5fNFncRhgVrXXfJAPEVgC7EjN" + - "xdQSBJFZBda$TfdoPiJTYQi3LXQyAsLkSGN6kOEvKN9fr3nDKwTw2uNaRER#9oQrUvjWbR4" + - "xOqsAHrHah25kJaFDMolh75dglgfgyNgiqtwx5vsiywlrripzFuTLXnREA#ZLblaf#dPWbr" + - "xPoplgbdL1EnrQxdjJVFqnUvdy9FKPKEMz8rO1Es9cnDs3RalPe8YeqE6#TiyFKjQDcSHSo" + - "JRxdtu6FO2lzM907R7KtOch1j5DYQHR7P7xhJLmXRklkzKlvVn1RWIBs#DNHCcx0rOMl2re" + - "Ij2LiJjYPiJTYQi3LXQyBMXAq9MnEs9cnDs9gmDM5hmhQXiOdoOjYixvwJlvVf9$CyRobgy" + - "xxdP0FhBVspe4tOch2jBJPwSmXXKsyiCjWaVpyYOszgeBS0wLBfvcc1PxQ3DwSy9DLRay9d" + - "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" + - "UdyrMZB1BceAsuL#1YllqtzcvTSZj4jI6po63MmZzYrHjzmxzLfEsSp4jId5dBcpCb6QRx1" + - "Ytoq5Y2OgUqvi9QyzerJudymvJr8apa8wCLdF08VVeKPNLcX#0h0VayOk6c93vkpI99jUri" + - "ox1gmHDMgDa39tZS38NXKRhHjJxEIvOnp$RcljIgtL$8trg1lwL4djE2B$MhH#red6MQzr$" + - "p6dNlg5Gi5wAwFrgZC0ex7lFJOOBzTLMMolopbndgTrT642qglGcpB8jB5mbSTap0hS9bo1" + - "at$nGVVVEJI$#A0hs44oU6#539wtrh7UChngJha21y$YjacS6tKnwGdetp7KlwBNJW8oBYD" + - "ERVyuDJNKuefBv6WxhystJIXTfhID#la$5Z6MBhT3yhqJ4BVct$mFoVVh7LXRF#j$ImUn9Q" + - "jLgY#kINEk9AHwSf3gB8izZrzkoHdxE5gQ9p36wrArSIHMw$t2UdGfzQrL1gMQcJnnTCw$M" + - "zhtmAcDVbRU8E2ibFgvEzJJ3nepL#I3pAawQha9$yeQOgGUzGlxIlM7UNnllJovZi8OxJgY" + - "zRCV#yVrXcAqQZXQ$JOjmD7RmX6$LkvdnGPP$D7sBnrGWwbl77yFN1UTuvYXBJ13uzUFX35" + - "obqNLmFNn6p4uhjOCCyU755XRpPYsWTsEiEkJqa9KcmzH855aPgyRYVnhK80yP$MZ#uBh1L" + - "Em7l7rP96hbMArHV3dtjb8TVusvQNzhDWu$cwzBgQJPDjIQt317O5tfZnFBmJfpOBPblkKN" + - "MkhF5bjStkjX0rN1ckbwhcwJk#DsisLl4etzsE7IEjU5QCR4f6h2#KuDBNdt9b2oZ4ovocx" + - "V7Um4dgMCBEBO4lRXzxwc#b0JZz$K1TzTqxwFYJBMICJZA2kkQs5hNM83IjXJXzurx3xe4T" + - "GyhqO#eKhbmoU2q0A$pP2MKV#Fd2#kXj2goxBHRwvd23wSya25Xhq8PAV#mIvrNfRsq8Hwy" + - "s8CcWx$D$pEZvPXBLFG3#EKJ6h9jLFTO#rqj9NdTAHBjytRc7c5taQGLsGtpiSSti7GieGf" + - "3JOFhdk8KbM8UdCdxHlcIU#yzYdJWd7hBTb3rHI$LwrTsZ7mRvLPqgRFh6zfpZLwdbHTBKh" + - "lgEaa2YWuuQav7x27S1OMS8ywwttUYl5oEWvLXbQDlsMHMk#jPujTT5dx0AjLqPJedDCIcF" + - "P#MVPMkebiWzODcHRQ6$B9XBxdAGfNbVgeiY25SzQL$BrETzg6H#nzFjYL0Cqe#nLLNDruG" + - "n8lozgQJsZ0fsOiaEiTRTrP8Kt4i5UmUjuSpEZfCnZ1mLMbPnViCJEDV6rCQvH2ujQfyDUc" + - "36kYza7httvHYEgqQY5MMqDaJBwJPKg6nklo6Z4QxSrolBDyja6ssQ1dahhcmjbFxnNr37V" + - "DwXTxpXQxwsjzRYrtf4ghVnAgNSSjgk#zegiQcST6xlAlLkRkEe6UjemQszZaOWzWnc9MV$" + - "LAUdiO7zNspR7tkFFm$QEvDeMFKJS5kp1WaVvRd4Fp$Rxay$izEsxZD#5hzCdXTR6XdYcvp" + - "wLI$VLh2jEOo6y3ZHZ2wkCVJ#bBBIrib3p3HRQECRaSbWPMDWGErrA##v2eK$oNHOXCeld2" + - "VhqFPfjLupm4RuYnAw72Z5p5o7wZHF2srm8TxuGPur6sjb27FqPuWy8uVGGujZbGdsEH$vX" + - "k8Jk1eVG#nNSlKWxJeXDa7RMDAHVYV1Xn7iXV0xntmXnw3BmlqJQ9GZVH7qkwjzKY8aV8jn" + - "DY1CUGdY648VT1lSksboDCgk4E7mR8PeTBaIBFk372j4AzM#2zWJgR3KJUP1jjWOEs9rBST" + - "4v5E7NGdH0dHtHjsOdWr#A$a2c#UN8gqJuAUB$5UAKSY6cG2qTWEjmu3eS#cZsExJVLOWZF" + - "E1yMuXjWR$vPOWFXpiTxZ78tmmym7S4sZboUo6sELE8pks5A0F#iglWlXVYx4ve$nc49o3$" + - "I9HP2VSMujs5E8UmGM#7OLoEX3xFxeVnGTj7tYh4oLkZRlJZo7V0JqIPVONeygqGNVSKOa0" + - "DTFbto0yHekQV26S8qUT08Kw$4Fo3QESJ8Ovg2zaRX3Yf2zhO3th2U7T2tPj2$qT1jYl6Pb" + - "FWsdG5T86sDuKUDeCUDki8jm$gWJugMY1yGeZvVuJyLoXtCVAEGlqNWVyrJ62g4BFsHxt3q" + - "6#qTmhwD0lZVmhY7VuDyyBOzeMkpxu5vUv2FUXB1wo14qZ#PSWT39t#37aOXwCVWVsWdUaV" + - "2R4vR32pCy8JuJ1kczy31voRloGmSU7Qm6q7X$9Rd0Gt7Uu#k5$0OGotHBjRmbwsn5XiUGW" + - "SwjWIDjAPyku67jIr9JdeyrHWcZqAuujnsRcT4Bj1FmCWFxs345iTAyHfHmWn1$gUGpe1jk" + - "DXGrkXB#SuGfm8dTIZljDE4s8doFR3cFJ3d3aDkksFVfq6sHD#Yn1ZF1Njpu9EPrqXH4lWc" + - "eN#pa9$Pg7TMT3LQNy11enFAunbIzZO7DXw7xIt3Moe9UojvHAqYR7i3Bje#GR2IS29iP#D" + - "CPip6#NHbrEknbo1JSo1pNP6F$h33kR0$hgWlSxdeXpcyPn5Y6yBlPDTO5vrWVuwe1yTFq3" + - "#7n3$EVWxXIZ7#bvUXR7T2VLYJCkn3apu4Vr5sIwmcowm$NhOse0NCOUXWoxF0WlcUPT$8C" + - "Hux8BvqdLlnAy1xfwGnNZNexrpCFQppuDTlW0UUcyEtENeUrVejmLqlJNwrG5OjfwBTXz7#" + - "7k4q64hz7lsZN1OJnnWs1KsCHisEFizvEs0SVjEY84V2p7j9iJHfrQOOwrGRZ0mTyEwrXes" + - "CHHoiw6prWEGXpQsXHtDWluwes#T$YJ4ZDvmm345EkkB#TyQjZjZ0Hpij#kJmBiOTMs6CTu" + - "HFEPeDyo5Su2d6zRHSw27RkXhjsinvj3r5BHvEiPi2l9EWLqSEmYwnzfs3d1rnNmy1tRN6c" + - "vtp8SvADjfCFe5E#k4ERyj#j8UOx8TwGIsqmUsKmPxtFqEb44Voqw1WwrCndeo1NE#8$gyE" + - "$hL2Mle2R3DAHYNpkZZ5AnRVLu7Z$dQ1VDb3iPj2dR5qu7z98p9wLWxJpe08TR4CyhWC6TE" + - "WgsT0UmJO5Ddm0OdO4wTWNau0EFT1cjQ6#Zf9EYZ8#evwLMq2Jix0thfY$NZZFk568Jn6mI" + - "T3FeV76oe3VIuorvmc1ExOAow0kTWx2DTqSSkc3DjQ8nE5Q8jrfh1s5iw7WIydwDkhAbxtO" + - "x#O7tjEXBvMB#60ECGh0qdR89#GMSd8bu1h6qnpuO0qn3Ozr2i6qEWvpxOhzmnSC0obDPsu" + - "1gAjePXdHg6zNOOrejXi8rEsBk6OnqUZdL$#5#5gAs0mzwImJXcaBy9rezDdiP#WBMX6TPt" + - "3tRO1MlYDjYpjkaClXPp6xeTXV4TYB7g23khXVo83CQOvkyvuA7Z4LYBFVIpAx1qnJetSbV" + - "q4tD$Ckph#ETH3zR#BkU3Xtww$0twnjpT1ZhQ3llA98nLLzZcIEm$ss4kZoGzmiRsW3rlXx" + - "PFx0yCmD7rprZ3C4RTK6OFZEDsc2CdOk#RYl7h1XpTO7iLrSZ3lAd07hKdxBy2uxCdvdSbz" + - "kmzeQjAZFkU6DjAsCPUMDkhC1VsmhohWitjXNMw2dqSDL28QkXZ5EPnDNGr2kj6DSPZR#oN" + - "tQ7VlJ7$kqz1Y7vrnvZkWpdJ0thR1rXwO1psmVhI0xQu3zQsdbiAiU$k264B#s9jx0dTxlk" + - "#4Dj3lzl1vZfWJBV3thufS6nQ3mTScs7jsWmu#q2lVRy4$nhs1k3V3lWsdmEz8wtB227cOY" + - "oxm6ww0jTSd1cwmZwxOJmxOqtfyWFuFOHe1tri3XriWVD0Eyo$TXYNTbZtXg9VtR16jCEQr" + - "0Nn6T1PPun3f$zWBB5kLs1Td07Rd8c#xOerim9sTnhiyJJOn4piWpE1RJ#i4rDXCzsmrhT7" + - "$JEnBit4#6o7SUs8DNvNb6cFSyeM68ijS1RQ4bZsWtnxp9VzCBUsn$goF#RazYY$F$RezXS" + - "WV1GXzfOTcg5UjDS1wy9ex4LTiWZHPWVOqMYi1nsmL#y0swx1UjmHUtedw7OqvjLCZEK1c3" + - "DJiJxlW3bo0FQ3Nh3P0p2lUs4$xO0rOmpqrWksC$KRbCMytV8iRBheSr#qqtaouh2ZhJ27#" + - "sBURmMxEXass1dZkHNikYLihmlspsw8ToFzOnvtXErqGR$7O1qx7dMUJESUh8cxmlOhi2Tq" + - "nNniYNdH4lOx0dl12HZVCw37hh2hNZYVxeYn6u3vD0rhH4ViRHsnPfw9ljTZ7QY0cuDzf1$" + - "wsm$pjntMp5qnlbsXkmhqfnnxKZdcoWdOYqw6$a$67baEkGheRslCgOgjW1FhOmNwiVL2EC" + - "oz2fonAZ4tnk2CS2BgE127ZWEn5Xw8VUv0h0cjS0PjXVdS2drfJRAmYx6mfHFHXvDXywqnF" + - "fNeOplORpliRvMmeVQGEnbzReruUvITZ3LY6cnyCcobC$Q3QLW$JeGTJyDShOJTTCOQFGtw" + - "dOj#TCDQK05xxWyRwe$pmTcGguJjzSSOxWITJ4FO4JXFXttFnVXK$WjdLiorph2p3fZRfm9" + - "$LL$8OktS2VMs0BOgy5NO8#RZx545MpuLPymMM1FF1QOgj7K6rjHMwCzCx2NdmaQhi1QSWJ" + - "ry6$Ij2dFgZ2#mJq67SsXDmRXMN8Tz3hev5NEb0crNmBPEnLbe1DQuKt4#sWMwh89Td8hsJ" + - "uLj3qOxGu6p4#RPCCp$kNI6nJmOXlsl4djc5S8gvCt56NyORB8hrkugs68LncWkoW#7BYgm" + - "lbPXpPoBCHkEDMSuRAuMzZ0NUgx5skzXRbQXJrMmZRcO1oE0eH9xPXNwL7Mz4FDW6xiYlH9" + - "ZMuLzhWhhqZoSJ$R3EZAFz8F#xe#rhWBwhyGSEHMoEw7VEsEiJeVzrM4D6WkxFXtsEWrxxt" + - "IqLzaSvR0#Lv1UWVjOZC5Os7WLC7O5xdbOvog1xLZev3ZCbSveSphqMucrj0gwEWwwFHPwc" + - "OSvKubheEEm3ns7yPw8zYk1hOhgXGrD18Q9qC$EsEicOlsPYFg7O9tiY$NsR9mbpg4r76j5" + - "9TQEAl1LM5FdORxDnRfTZRfgOBi7ORsRY$c0PKSSX3FGN9m3ge2$6hPVXVry7jgVXtLt7le" + - "s7tgT1vkTZpuUXB6OZtFJGDYyXsk0AkHLmxwgMq46VJmNQt4brhDgsYUmVis3$ix57bKDN9" + - "CmjkV2$kQXZzLO0yTXxJWNTZ8ETbkFje$7cQ4Uws8zvairx70Spe3rMFS7ObshnjcW6dFbU" + - "EJLGrzjCE#xu3mq7cl29DX69Sw5rPYRtR3NP32lsc3#3SGUKmlR702Sks5DsGqsk1lEghjZ" + - "$CRZEcWypWq3iRvLOr#eXXrCmXbkHvnfge6d6kjIDR2Cntwo8zRzBjXJZuSUHo6$AyvPNN2" + - "sce9wgh6#LACFep3MbLXRge7v3EYl6hPQXluVZ3DvR#GVZBDQDUPP6yYrnJfrCDQwwT19My" + - "o9wPYdRR4dxOnsjq4Vwp2FUkFyKuSpGpN6RHliYtMmqTwGEGHhLZNMYMrXTuV0dcjGro6O9" + - "zDXvzjYBJi4DbA3lbVY$5gDEJmVyxIQnXbddFdGtI3e$qpCdshOthQmuVbOO$f33$CnXwgn" + - "7rJ3dhfYN#wElir7#MhewqoSmQfnPZzpF4BqVs$KKO4nxuPhgjCnDcTYNw$4db6DyTyRxPu" + - "9#ww6Baw7VVR7sd4czgvkqF#PQASIyxOQSsGIxEXCv7V1cd8c#dOcrkrgxCLTO9jdGZUJiT" + - "#S2TlfHdC6Qs4rT5#1yyzPMFCgWFLqMdknFrHZVbLZ7UgCCyVfs1jEnxNsMLYJAr3dMT1z9" + - "UnwCZ3FnnvuAFRM#T3hVCoDAk2PZpbUXJ6UZBgdKrymnWCnFdLODoenTdKOzohOIJNEizKu" + - "hv#5CeV0xYgnbno2kNa8zGLxRpNctjwOlrKOYqgS5Sx57EgESJeK#klU6kTer5UDiTi7Qyu" + - "qoCp0MQiAytuozgLziExDW9qEWBrtnzhV7NEkE#PcTunlT#YuE#PJTymV1phhZd6hmlhQ0U" + - "lU08ph8AnJms3$ms1Vmx2cLMEkPg3hdM4ptT5EztsH3epTCGOx8syurOlrPpZQx8v#3KUVk" + - "sD$hSMywuxvLOivq1rrTiSuTpz6tIkQFaU57HvMeRYEGiKxRwdGUyYagRZxVZJUuKGxhj9s" + - "rMLtwwZ3RZeyAPJPROOEdmlJEevLuRQdgZ2ZyNM2RMnob4x3#j3isB1CixlZxQTnk3wjpat" + - "RvtlTnjzqkxLqJqcdbQkmnR1OFJ5zjC1SRBuwcZPqZsYyx1fTvocw7Qo3PRSglcP1ABVhwf" + - "0VS6l8Rp94rmDTT6Ylw$g3Jdi3jljyjBrzTzVbC1yxTelcUGTR$9FHl4rsKk6cM0yFlILCR" + - "mMxtMnNMrQbRrORJykLEQop9JylMMQpnSNgMLk7C#wUkczw3BQSgaDjZpN3TJZVAeDrRyjd" + - "TFfxOVecFwXm$dGLReKvlXNceNERpdz3fn#WmexBYkEZy$XMDuRnJbKgR5ccmjh#kMLs#by" + - "qlkyL8V$$MZiNuAgACuxlEUVUcz2E1HGIH4YuJwUr0taGI0WTUUG1n1TIw6FQgRHHHmS6HC" + - "IWY505HIa8AfeWeY01j3n4i14hJON0W46B8c11VA0Y8ZwGQXMe$dU$$ytPOrBgJ6NcFx$l#" + - "$RRtNFElNVtsni2hikviVvsg0pcHNxcsxcZVRl3OZilsAV3QT$k619s#vKm#tRcdAIFTIqR" + - "vvYEsBiZMByxNiLv6yxy3CvkJrQHrMtawF$ZQ97bdn96dscT6plBiaS7sthqOZ#iwUUS3hP" + - "DR41TdnMCzHua75EDp#HgiSlN2ojSFwyJzgc#BuZz#xN2l6k45quLPdGHvblFT626i1Vseb" + - "xDrdNkOJlMxquh$NWdxFzNlYVseFsCeSRFFuTpeJRkz8ROdSyN3lW1nqglqorhiFY3sJxub" + - "sIzi3XgvPmGbWtoOmKjzfcapvJ2xgXPCoVwySwDmYYVJndNtcBKU9rHgsHb#Rbb1zds5yHH" + - "isQD#IvpVr$2V5S7$VAV2ajGWsTjjPu9wgBiiMsFCVZ7mjweMqgkzECbVB$qw#d7#irZdnl" + - "99Zu7livTK0EKy7FNXUjI6VVv7ZXpz3iGdBkA$QgOKxM6F2syY9#zYsh9myABYyZRo5t2It" + - "B9iUIpmakvRbtw2t8P#Pdmie7aNF9ruV0BX0xVz#TEjg$Vlu#YzRY$WwtZlSyL5XorOjM#7" + - "UFuUMlQ6fSv6opxT#JDEFjdeGP53TrrfDyUHxtUzThMOmoVB2mT7uoxVOLbEBDs$TQwKyRN" + - "OFWsuUMTXULyJSfh$Tpp6XZ3UUcyts0DukjJOTKH0wprul8$a4zQiQ#58oxsOoCMyZeVz6C" + - "vg6l7uQoSizgwZo#5UHVWSpqfU1zHh86vR$Bvi0OSSKJe$Leuy57vsKGqn#$tSpuR$Tr0TB" + - "ar7khoA6ho6EhY7DIpiHy5vyl3VbFmMuwBitHi4RGdcDFzJ$hd8sB7geNPE4V7SIwAL$bvy" + - "HjuBJFi$cSISbc3vHJPOz1UmBPPVgo0TMOX3khHfSmxWlFJdRpVBuHLNBzZU$s#iUjm7hd9" + - "zyijk$0bAm$dX0JEZ7smNoOsjdtTEKk4VOxJtoVisz$AuPhITwOV6yty2LmZSZQtFNwSTMv" + - "CVnSJyUE91n5hnEinHtpzlMhy0RPzX5pMjhsVOaoVsVB5BjuIdAEaVT0lxYbCwk#AIlYCcl" + - "psP7zX1TV19EgK9CyV5LmJ#vMsTJ#jxwzYLz1FuYmOnrajsSwFLLfrRsctOBx#pYz$ElBF2" + - "iOlRBPzZeqpRRm#62lwFEXtlyhAv#SXELiu89l#N0ZlYSgnVcubr#paU8Xx$e30QuhdolLi" + - "2DVrfFwUYFjqif7FWtj9Se7#heqnhcdwkxFAIpWVtpT3k3SCuTvmnRVEA4EuLvIszsDNp0$" + - "cZ8no$EtMlHyEvkG6zi1WM#aot#wVQOt1scuezwb4GXZdcJbnVN2SH9ZzMFkbk0yDvVus56" + - "jKoleCZ1pdsodMVWa#Xv7F2OTXRKtnUO$w8MEJ4QCzYlNtA6kj7CMpR8gVbu7JULrybldLr" + - "ZqUvRnn#rxOnjSjTnZzhwnxvRo96kiU#1bAhABFUg3R8M6KxurKIbYONXjuNLUphebNidsJ" + - "CAFbJ8ltzp7oOOxr4xyjjo1u$OaTpD7VWV6CDupxQiLbP7eSh9LZciNEdibvMGEdMixms0F" + - "lu5ojwbqy7uVvXRoF7lIjirRIgXjIt1UIAuLZ0k$zrkEturgMMerzyyH$pqirAJLfX#$dJH" + - "JMzCGpvJcaa3LyKPoS8knJp34E2FKVD#6uoe7SjDHfvK2k#W#eVuSYhHtmTo07nHlageNm5" + - "ohFaciq3$5vy4MPK8WAK#csYF6t8tyx#jNYScfXrw9Dv5fqr2pOiynlEBgqGwHMcF5qcwkU" + - "DGf14NKK$OyY$WBoxePzDsnH9XbgYJNZEfhHjndsJiHtelzE#3kDRolCkDlI$YBu8lAFOOv" + - "Zy5#2FZ9or3ymrXQqRo5nme4yjSl8LKkGiyHGAwpgaLUFM3tQHM5A$5UGjnlSZTXkZFMEKH" + - "ZoA9SI$rtOxoBdOrpVnyZxn2YYFbKPHiVX7yVpgCESTOZNOVuwnEhGTpxi#OZFDxQdFiDO9" + - "y0J6EzVHXxbKfxw77r5dlet#0N6rFeh$2#D7FKgudjWxu7z7EmPu0pzswo8pOO$6xRF4Adb" + - "u4refFPX$ds8xOMz5$sU1ByoybGDM8Es6enHWxc57fNsjK9Mhiks4DlQCJ$Jwll$AZsF7Z$" + - "3ajqckJVYkeBoBBbaY0p$3tbMVeZzRTjj8wRp8wR$ovZ$PSIU0hNMmxRr5c9hZ3or0luAtD" + - "CAs9iGsmJ#6J5HM3M03PXZ7ThMmLw7s6FWOuXDHgxMITWd4TiAUolojY97s#yPXLKJOasmb" + - "oDdENA5efbecuaseKjfFvDqrH$HvikpRDqMQaFfk4U5ZUw4hRKDVRU1XuqSA6piKx1FWK#3" + - "JsECry3NuFyDOpqFFe$tyFj6BkHP344HAbFflq7v1Fe#WRP5q4Fm7uAlzKyZJwq2Lu4hCKO" + - "ZsXl1pOXjHkpl6Ez3s1$2teynz#FwzYEcTGZnGyYznyXJ2#0l0AU3qz4#3Po6FjEC7OOyDH" + - "MngU0jw7CBR96sGr0wxj6FM7QOTAssaDg8$XkHyphi0x0Fm5uBhWKV1hKMesqnUCH8gG$03" + - "z3#Z97#sx4EvAfRmLiHMmOk0m#21y4tZLp8KM$0lW6y$WowpSZzJhe3kLhN6NdgVl3xrED6" + - "BYcQPEIf2U04j8aSemUCF3K5d0AE0yU1#b$UccWOKdV1lWlsN70kE0US0zwBSUur3Ee#nEy" + - "p3Adni56nG8vwcyB97tBK8#0Z84w3aACsW1l0fU1I42Tso54tKJTJjty3r0iiv0=="); + "U9piVGUS54NsVtNt4DR84WM96m6H9KYGjAYeO414SCqO41IGe820A20evXmm1nHpJfZ0T6P" + + "FpxlppeGYvdoUuT9q$R#lGdTrckb5O9RVV#TzgkfLrQjNtwfw5RgdfuUnqvzokstEnBdRZG" + + "ra8zWmn7ROd8cjWEjlNy1TTuVi3vi7yIV9MRtvapwneQmu#mDh0cutv1vglyKFPGFiKwmJm" + + "Q$aXqR9Vjt#8uMib$M4zQHzcVMgzOhrclMwzORrH$jj##Q8$9ls6#4qzYrhY9pL8dyLQsWV" + + "RJzlF#iU75SVsvMTuUcwKOLti7zOwzWNzedsHFi4woVhtzR9zZckitcGTP3hi3wP8ZOWmp9" + + "jCWES$sJiJ5l#2$8ocmUn8ZTZdsVtjFzazx2hs6ViVRkxlGFxE$Ass3o8mKLQS1JxB$AADW" + + "zYsxX5VWkoNxCLQC6vx3RaRRLv4DlMtSfiWJCCBRZKgKRUbfi7iPRkbeOLjNAkGWjkSYv3N" + + "jUwJMoG39qdmMCVO$kpBgoCDMTRiItPOhO4ULtgDg45CYo6Qy9Q6otObxNBx8Ay8NMRq08P" + + "he3hpsupMd0qEnDZCCGTLBU9QMuiyUmuemMpM5Us4t86rcrY2Y4hWQj26$mMdCDsPCEHDw1" + + "k4reWmsAu9e4MFCjwiQx8sxbk4reWGtBz0oruc$N46Epizg$RX1R8S0XSDUljjy1gPpMqjd" + + "JxP$zR2BBij99ia0hxeTGMLf7HWevi67B#KmXoBqeh2Vmox0CtWErYu3#QLKDJTTqcjhSCC" + + "oFXDou4PVPDAybFaI7hHJpRZvyI9NO8wo53OV#DtKQ5eCoEQINvF1coASIpoNnUbDY1x00L" + + "7iJ6GFedzoUx6$cRagnRqqgoMnItcpM5Rrq8SZv8AsdjgCBbyBSe1Bcxf9NCJ9SXEnH#KI4" + + "eCoEj93jIXSVo8lUtGX0xCRNaoIfSwFx6MnM2sDAqakwXHecMXI3teBIIx2mLdWs$HI68dP" + + "TQifSAUy9lNWXYLwQMl5w5DyDlLWXoTqqhoMvNuHtmcnQ2tCwf9IjLM05$cqAGMvvQiao5f" + + "N2$5eHAKajsKc57k5yAGXrIIxPNOJlt5rvS27BRffRSNeLju6zR279RfvRSJeMju3Sf1Baj" + + "Kqksa25R3NxhGX1x9hNaSofymJwVRrK8Oi#dblo32b#3lsKXYBsUMl8D5Vw9R#bc2q7idTI" + + "IVrFX1swMPmf1R6rgoIzL#1Lyfn34bgUM$4w5tyEt2q7PBz9ACbU57BvL2B8QfvPi94FtGZ" + + "XU4BeWhQIrZGgtXL#GZzKqjUHsAcmBxt#58AjzQibo6R81yFzR2B8wfvLamrI9hl3$KmW2W" + + "fIILZTLeZ$yVnU2h9vf9J7siaGV#1lvU#TuidPMuO1yadokulOI$DvyRfJOJkvU5Bfxi$VO" + + "#swrksqXo1gOLf9Tf4eCWJ#u46JjabfoLnNk2VzVXI1hxzII#wZmOFW$kZ$QtSZVb6GTarf" + + "okWfdM5FSxzplWFMxJKlMIQabvwXmlZM5iqAGTLfgoGjLU15dxZQ58ElQr9AtA6w5kmrlN0" + + "YoLgIMl4U5zy9lL0Yoxaij#R0A7u7Vi11aFPfQyayoT6#5tw0GbFqehQJrhWe$W5#GxnUj3" + + "rLObbTsZWnPB#9P3U8HodxCBgQG5LlRioRELuNv7jBwHeNVvfKzMNqFEOLuDXVn2B41zaWA" + + "qRQlCoETxmkphcJ6gjMYUzvrfQKCxR$mnkvPzXxkMLP3Yxbd8HpXdfNPcpYVCWsiDiu$2pE" + + "dtJracFqodoJxK9LOJixT0xJSNMw$u2vdWuZpIJorqjbTxloB3sShx6uOlLvyE1zkhoG$YH" + + "AVnCzHHfFzWRq6$ch1hs8$oYVnhHzZPT#r$wPvwsSL$k9yuVwp46JzAxNaVsN8Mx0LSDIdB" + + "NWBz6dExo4J#ZJrTvxeK$9NiUMoJ#qTyvRefy9XzDqdi3ONM9lpvi2Qwtl89Aofl$C4Ll9N" + + "sNighCFpbXYXmdruS$SVXI3xuDII1oZkXqAGNPDQyWZ5VLi8iiUdbZnMSTyNWkpZKqjEKzp" + + "FXI1xHch9asJ8zyIStrFC#JtvdfZpUoPJufpFKKQJMFFtn9mdVfKzKyvvDZHMbjPypS#MeT" + + "jmmvCznpr4S9qYUIATJO4Rp6wqvxaDhHUiFrWlMYzPBxCLsN#p0UosxBz91loWxBzDCfual" + + "YPpScOEMvwPcPa5sGORdjXbR4yHZWtdsAUAz45mHx5BsJYtWLLbDVUmDUE3s3wuteSC7yG7" + + "MLt8Jo9wDjT5FTbFsKdPJudOmTbFhR$dAgC9vVQ4XXs4daNMU$PfEEakParYwrbWxQXvPxR" + + "Y1bfJx6xMgVPPV20Vw5v4VX9PfUnKDW3e#i0DiFzZVyw6sj$Ol#OgeudjOvN27o3qBB9$ot" + + "wKwGYS3MBhMO2pl#RVKjps4YUxZ6$FjyVrpFR9v5xCBdKljdzaY#orx7AMSI#s$cmTcjavL" + + "nbDR13h0t#0r0DDDAAtPjh5oYwmPdbr3bLS6yBfdcSvl0rlWzGsoUJ$oiYwsTcEVYVbdeUI" + + "cLnbDB51pZpUncbBl5DcBP8uhKjYPIki1Pftdb3SOTOKVfXxldKgFumVvkn7Vf3ixUoczZQ" + + "2yt0wSvovmFcCUxvxllq$Jx8pj4r0sCHkBk9jLBfjjsNVklFi4dSUOYsjLTPgwndhMUiv#o" + + "B4A#oCtT1kR6zXRsMtjplQPMmDnbtfP7qLTmZx1rmMg#WX26yZFucCNsrrOzy2vz#j4rXVw" + + "x9SPRoo5pkje7yOyUuzJZdhoxvnxs5xnSbQ2pAzDSy6AMuF8Dx3lSUwaU$1zx1$83#9V9ps" + + "0vd#mFcH$GWRpvRdAgF9QPVfWNhU8DvVCsKyJE8wKV7MCCNjPi6vPxXdyDtuRlOXv2SHpGN" + + "xptAcmpw$aQkRax7cvIgbo$AF#6wmJ$2PVlmZLRPnh2pXLBnzXGpTZt6T#B6x1FIn#p6k4p" + + "zE9ipqFfZf4kVRzZVE5FTCzqndVAuocZ2FMi4V9cffWN6NEBUEbGLEhyuh5VS1S7vWN#ESu" + + "7xWVW2S7oIJYTCQXlvSJbVmza6vocZ2kC#5XZyHd#beZyhCPiLiA5iM9ojmAZxxaGpvhlOU" + + "V5TSTpVWko8SGNuIsJ#wVxJN#bQQwO0uPdskCfhOmQmO$XM2BtPQioPsDtj0zkjOMHftnMD" + + "6YT3z2FtvKVPZwpRt8$SZzET7oMHVnVguVrSxqGhx6#iETblcm4p$N6KykWtqaLLCV6QCUw" + + "arnRqqCzvg5YSh#bFpFobk3N2k0SwttJNk6k1Saqo1SNU1yo$k9LOdzv9SPJow0xJ6laNm1" + + "rh$otxi7fZzqhe$JZPpc7kWvgqEYliGE3zqddEUTpzqFmJE3vC9EFy7d0FP3coOtSVTshuU" + + "DlOVrYHN6O$#3FemiuNWnzYtihxkc4nBks#ixDRk6Csp7nNtlbK9rzhjuBxllc$$G7uI6Vl" + + "8PyxZrd3dOViH#qxxdbnbFFehw7qsLF1ZsGhW7CjkitQBayrivOxrOg$9a0$5IZgKNUQ#ne" + + "VoeLZdXoOJJY67MODnBkndVsrLMiEjri2vgxq2wsUEKfASVN5U6efp2FZin$Qrs8zEjrfOk" + + "yVMG$D8yPX78dJNmbBMiiliszorxbhqvzfaOfVoDUxhm3d8$gzLmTUm$lOZxkkPNhdAQB9V" + + "vkyZV5N4QlZxrb5k3Kx3hyR9PZztQmnUXBmQwr8rkopxCQ$crLYNgfC9ED$5VbvbLVE$MSF" + + "13yoqm8xzD$HdZbAIxBluE$2V4tgcy7VGdnVOksIsZfFDViukz7d53R7lvaFOPKulFWJy3#" + + "Gd4RlKAhFtjghilJBbLgbzByRd4USyv$nSPJHbFyFwEOGjqpnmBiEutnvR3usxuj4VaXkCS" + + "yXWWNCm7moSWvE9NMgFXbLMsVjdkjZVuNfbNzZdzpY7g7oR9PUrxuTz3ePz4h#V$I3hOxLW" + + "0vpUSR9qVUFLEKY6xdjObzx3zLLNzpttFQnBxuL9dZ#90yu3iny1vrYiem#ZrV#mxt5Qi7q" + + "Y9N3#564R5SVvqtx2QMMNO7z$psxfRETUvBG1pchxAP4VEdzcFyUwgdJ1FaN8#pejUL$Ceo" + + "TvNzuNLjetIkASZ936tQcqgfm$EUsTJavVfvypCjECLKVawPninctKSfHp1Fo346lf76NVP" + + "l$1cMQriA$pP0HEoMS$zt70FYMta$qYtqcC#qvy9#TWyiCaS2B4FDgFnjtv6wqicMFO2kSm" + + "wr2ShSFoXDECst0l0UTEV1zmBPqtCuS3orVPBoak95H$obZsS$ihNHOu9TVRVeNt5ZXxyzx" + + "ETFB3970Y99nyX5MLQMezdZdG6fvfw1p6HzYlHkG9fnctuT#4UTGRry6zxPQPRbQpx1U4q$" + + "cpaj0uHSpfvGpLPTcFYkjb$vNt4ZX1EB$qIYPsgVDtwizCwqntAsCDnwmjParGTuuockpt#" + + "KtmtuDhcMcUwMQ$RxN8VfaPQ4WGJi4vyvtBTQfpYk9wylTuJzZdX#04dqnad#mdu3oO$zt#" + + "mlx9$gVzRsSK$tkkCXxTb3c4zxHTue6IExRZE0sSBqqPu1IXK#HiuzNve#9wE1ru3$HdCU$" + + "1UrWjo4yYz6T7fmGuZtQwiELELwUximF2gbnbD3azd9tW3nHwbZk3dC7mTt5sDMM0KyhkZh" + + "LEbzj3SLNEdhmAEFVcLU2F9Z#9n7m$2ZWdEeSuX$AHpcHdWdEYCp5N6KsOxpFWB#HLTaiWF" + + "DKv3VuYvo5VGeoxb5tYdE6bxwl2xivPl3lmxykxWp#R$2HonZddE9SwrzjNeuuhd2iT2gzn" + + "hirLHXCaRu26vRmxvljTpdtEOyxzxj#S9tm9WLFMywBp5w$ELnMte$CIt6lE7$cE25ydFuc" + + "Sjvo$Ekywxs0VUT$vs5dhVEvyPyrmVifLnYkxrlalV9VlYFvymVcVmpDE9cEzwKi8d8AprW" + + "2dIirigRXkcIPmsm9dDyada$DMfZZJAhCT6v3PFjCfKvBfp6$Cx9JfawkCfapVp63urRmRv" + + "llmpAwP$JAZCljd3lKb14ufUn1mwd8rYjiXSoJSEE3SGVB919n7POxbsSna$g$C2Votp3J#" + + "A$yvSrAkCfeoyp36E$3$YTW$#K$yH$uT$vR$OCe0f#I#v$$rofsdkAxyFxmhmmTSL#c7IQp" + + "pNQLKt2SYJ#ky6RTr3UGmxf6otZhVLTUZotfS5t1TH4uNoKT9uEmYfM9nXkK9fnctTGtaGZ" + + "YbXCRPHTUZotfSPt2THKvdoKT9uEmifM9nXkK9fnctTGtaGZYbXCRPMTUZotfS9RXAaLCf#" + + "J2f#ugLKYeMPxW4uQImZOhJVKLySAw3R0WdvOVlAnewFQu2N8N8gP1yc1JE2YaLYpDSWd1I" + + "s4R5JPmL8PoK7uTJwVAuSd3b8gTSyc5IECkbL2pES0d2IM4R5JTnbeTmKhw7KyJAJ9qUXrG" + + "kSyea7oQ5iqnAnU8Cbo2S5BPHSHDdMGWdvViuALPcwlIuKd2b8gTKyc5IE4kbL2nEBTbPXO" + + "IJmZOgRk8i3U4iZRdlRUZKdFikO#J8btoOrFNHkr8gxXCfGTT75BPHSGCdOYt3PUDmQbsQu" + + "pi3ySwY1JjBFaogFtUMKh7zgIKxgv3way8sAcxsvywX$jmveJ#LJidPa$a0S0D4pW39XqdX" + + "722bOd5goSug99mKjb5n4#U04Cu12JYLJe$h3ww$oEal#MHAn9cZZ5bMwyzNraptk7xW#ec" + + "SVf9FfaISESgOPRN#V6NDT8$h0wwFoEaZ#MHAn9cZZ5bMwyzNraptEBAP4f5J8lbaIiIPeu" + + "nPLklFLzPCzxXEu3g9d4wIJwP4d3dAc6Mr$dnbpNIFmqpaOZRojf8FavhlRQLKB4ujsLc5D" + + "DyfRAFYvdnl6vhlRHFckzBfSQt1jHOvhIMVJ8auSvGnoshz#SgQwHwt7RZjHCvsaa#cH9mv" + + "ofXbjVvyPSrqZzi5t2uYPnV99rCYpXnbpB9QVxwoPhh7xGvkTv6pk#IJAH5dZZ9cMQq$Nra" + + "ptUE6WHicSeP9FfaISUOeOvRL#lELDTCzhYEuZYAde#J3fEPxHoaLYrDBTbOXpNSAswYuET" + + "yxXkPxnuJvhdHwN0Tm7KHE1yc7IU7i8ALYSMh9pYead1IsKN4JPuSGpWu9E9LEZsiFhht8Q" + + "I$vC2cSxQLKB4ujsLc5X9F2DYfkucmVmja#0QVIwN7jmBKJEUqa7oQ5ivsKGct#Ko8KwsvD" + + "zYGxgv1mKjX6nKsSxIHEUe9TrXgByrMjKoEotsBJvJlOsI1xfJtKMcD$R3zcRGNP$TaqvtJ" + + "sgFECiqgeJ7WAqCRPopq0#I#HRntlh7QU5IWUimUpwzX4UpvRAIIUT9vcCzaZzYNiLVKK87" + + "sUPdUnkzazx5vs7tkSFS6UClhX5Vj6wWUqy0veNeSmy0vsO1#ai3E9tNW6xotepeiTMalTa" + + "Mo0DHK#SzOGThOSyeyXPv8DNs0VITZX0xlpIIxix4rdfVSCpOqqYlQoUEnft$NXF8JwSxqB" + + "nCYr7hUkjwwqhhEUSZhB76T7aRue#oN2kwp5v3kphAierrg45Z#ASB6rmBdDMgiqtKKDoq3" + + "IMe2yK#sth1rb7sVEi5TINlOZwrIIpInmxjHzxDoHeuyl4pPwkNM4j7DX7z$BFXOvkrCViq" + + "k5VImIzi5ozl6FndDADygP4j$7$4FxhOomaCoUP26P8dityoturYYalcx$CPU5e4$FHP#UR" + + "JsbqBvfly5MW1bWzwAPGdtYThREiAwoLmF3R$Ogwqm3VQBTGTEZXDxTZwpRtI#AFlkfa5ej" + + "95Qv#scjrbpcP8xBdEAt3Ur4sp1gwzqsPxQzaseRVLPODs1El4EpsBfBjyqvpc#RzRJrF6P" + + "nVwdPkidKR5rjFMWFfhQXp5Bx3cihQrtsqz38V62W$u3GMyjCz1ahFtgHzn7x62lPuzx825" + + "uwdu1#7VlKNWLE$kBWFFj8s4zNMcdjfR2VuwnZBMuljiyGc8z5ga3FFW7wyJ5sTHrR0KVFJ" + + "b$7hxDNaXyajLSGbuYUSlqPwychag957zXho0AiAp02g$IiG8sHdG8#FJjz3N1T8t1Tmwy1" + + "hcl2bFqa#mcqWyk1Iyjzxkrv94#VIsJeuS8A2Lo35AvhIBVOD$JRSDzNkAxAHwgUd1Ba#$s" + + "L$LocY1NfSmepLLgELZXmWqpjzZeVbprGrRKi7obSEIN83usZB0dRH3WWqvZYcKPycS2rpF" + + "v4btLw2LomJSngZ8PNrvNvY6mJiZabo0$XaYK9rvKwdbdChnIuhdGEr6Kpc0UPhXANs0rEL" + + "tLTaOyKhfmIv8Tm8IKZxtrUeUFa2rnNO1nzxOJB7yT$gRekpqVPhxDVGpQ7XCmbEPBCB1Ou" + + "a9BP0VRrDULdpj1oo1g4d2M#TWEJk9je3n8vb#KZPLyv9QHlrK3m9vAs3Z1BwlBMMF23YBV" + + "syyhwg8O8LDMghalpaTAUKuByq3YAT9SmNsfPEiul5UDuAVfCbQNdRgnFVNHEDrNN9Vb8uS" + + "efuSjvwvTAiKeH3d2#eRZp8$X1xaMwX93nJuy$YvtW5vc7lUf4ynGHt6ap2rFiLP#nzqN#B" + + "yA65qTssaMPCwoxw2mcJX5hxLKPSwTbE8ibxBGueSczAk6CpFyHHX$SQL7c#$mxhPmFMPfl" + + "vsV$HUYp$ygSaVsNIPcp#Fc4dauhvWdEtssH7zXj#Vb84UWH2lHsx$09FzJpjmUnkwC9kpi" + + "w6Rl8OxwTgfvV0Il5FabMAavm9RIVEJFDVLQycJxt2Kxs$8pudbTZA$h4kWjdfpN6kP0#Zr" + + "eVMn$v$HuTMzNlnUv5R9az1jo3x65hA5PdTNAsBc0hdNqovx0dsVs8FiBkj9QfvyIRiBYJi" + + "xQtyvssrkNMNGwprbXOxR9VaSj#PMVpOo8vaXUVwH8J6uIKnxnshQGhHnEJrPzAM3tYC65T" + + "KvYi0mWJvDOuzqBo13PLj76in9Jzr1gTt4#X3s6YZu79sGT#odvoPaVxoVc3hzvfc6RiefZ" + + "4YVwnxAVhWobkx4prpXOfC1KZJreIzUnGlv$eDELsbPZ00rFcW20cjr4S9lsc7i847t5I9z" + + "vjJvZq6uQw#f9nPEQAQvB3vVMMohbCf5l4M$tThl1xq3K9vJgOtTQPD5Eplz5fAliRoMP$8" + + "yuaWUePIP8NSO7MsL$sXyor3h6kqP9nvEk1h75jg78kCciG$Y215J7hRuJLl4CXjAoMn6w7" + + "z6hfp8$APRva76aveW2grTf9lUvgPsUH8b7HohGoWegqh98aogoIBe1AvVgISQJbY0AeLcb" + + "7ldMtkygvKAH8LAkYg9oUGilJaWI2fwKBe5AvlcGSQJcY0AgdjIFVUiYhHw9wEZg2JX#XvI" + + "b9OWIVaYw0IkOoNpAEj9pYBoCdRFufPuJx59ykqxLszocvEr6CJm#UmfIc9oLHFldkatGAe" + + "rm#dK#dE97rXIyPHrfEycYzkYQKENoQoBb8ngtFf8oCyMaHL2JxX2JA9zzzmaCrZK#ZE15G" + + "UP9nfEKaRw1wGZkPJhxrfUHbJ9m40lTpX9R79Oduu#Hen8NqRpJYEjUNZ2CgfobWLuzhvzS" + + "WV6bNZrk$HkngBw5bfIHXLokb2zYLp6M#P1nfEScRfRMJwS8lXY$s1ufPGoCZI5eUaoJYZv" + + "7J8wXaH2v6q9EC8osdDNaZ#9XsVWtMT#vZVcxC29AMHoLPT2$wKQi7N704HQwGVJIPgAodo" + + "Hp1HxKZN$B2boFug9MDZE2HGiiZaiG8FY9TO0naBlCbuqZBITuiJSvQ97BkjXQJh#l8hdCV" + + "oQuZiXParp5rjUZUBMGVaYJkujBTvOViSI9RNlKjahcYreUIYSfvcio#UaWxyYKlVT5N3zc" + + "7ew#AqLUmCo03KckeqFAm9D5N3vEZNCgNeSfblcGSQJd96ttri7OoNVZ5yAMrFnnhxQIbdo" + + "GHxqTEMhibdZs1dObSMBid6KTKpjJaMNi$xRmQ1Zalk$tyN6DVFbodWlfA4jRU5oZwiYECn" + + "XucSuLitsIYiZvlz9N8uIVgTFAplqgVOjbVdOhihoOfJNqauKJLdtpNUzx46U2KKbpc#f9n" + + "fEKaRw0IENogJYS$#ulqAPRzXK$D$cAIqhIJ9EmmKyad9pzyAfzASPdhIyQHbfEyWKhay1D" + + "qEldPdwLFiUpF$8JipoOfJRqb0SK9v9DJg4xW9r1SvlgISQJb96#W4ZdyU9rEVkP4ygs3A9" + + "OfuiU7xs08BRqa0SNnv9DJg8xdnrDSvlgISQJb96#W4ZdyE9rEFb3rKgXw0TLn4LIafQSae" + + "3YEV78ArN7yE8hBN5yoZhISv0rK8eTFrEda0rLFXQedK4sCe28jFIG1nKJooIbK4$b4YijS" + + "NpAEj9pa3LGYXq$HwUG3LG#5gWTGJOcW8YrLae1Y2lbkbOTg2fz2SPdhIyQHbfEyWKhayCa" + + "wdNoWgbAege1gSWGLQUak2IWcaqzEePhC9rDSvlgISQJb96#W4Zbyaaud7wYwArJTWMfI11" + + "LfsL4IK4mYdvn2DObFehZCzINZICiftllDWDOeqmK$o6siwn1XT6qdBGyged#zUn1f3ygrN" + + "Md#GUOAsGUJYShvlD5NCgUhJeS$IARgtEYTRA7b0Kb2wW5orf41lIhNbumZBKSKE3Cye9rV" + + "W$3b#GenwvJG#MgIq7A$925zltG1L2hNbumZBKSKG7M$TduDmfUe4BCMXb0j45hkaoIaxvC" + + "kW4hb#f9nfEK4NymdwFisxdquBwbS6KUUgiD#2w7tF8JylJoiUOAMbVUf#GIKIBohIPBPZr" + + "2Ahl36qDrITxexdUBkTFwaJ$Pgah9NWLDtDTtf$frUy84xlNHIiMyKTm1PqfrU$Io7FK4yP" + + "t2xqQ$dQkoY4JdkoF9$#$rCs2swb$QYjPFLbwsojixifN9MiyR9TwcZtmdRRzatAcnts2kj" + + "TTR4q9tU$DX2TzxaNMYBzhuGGdkryw30rdWziKshDJRw3BBUvCVw$MRqVLRqwx5Y15VJ2Fh" + + "zPjpPFrRYifzMT$QF9MtP3#mRinyGsNTaFx3MkPt2s2YFz4kfA1dpSP2MKyEh4Mx7fjDyHF" + + "eWwtIKE5EM51BJV8JsyY32xFkGUbyGXH#u7OCreoxaiNbigfAAaEmtk4cI4saQLHkFQqkQq" + + "8EFaYzByaSfJiuaMzmNGFhBsJMGMYE8mlVT3k6QAK$qnvfuyh0nXOtIDABs7jU9DA3E#ycN" + + "9Vdz52TdabH3OVP3I7qeYC8rRljmpPGdi7qOJv4nLVB6c9RAgqLAjvQWn9co968xvfuBa15" + + "p8VkXlHBbPWThNi#dVI8VxscViu9F#zHgddvIstbQIspd$0viFsnaREVz3cp$sCZOBluTsF" + + "wvaR5T#Zkm$MSZOxjp$R7PnsnaR0$y3cp7RMHiV$qTsAPkN6psBxy3s$JQdqEi6hrdMGU4p" + + "o5qZMIDLQXNMsD2vxSZV6pEaBpOPcrKR0VcmBPRNcmdRqnicM4vi0tFYstkHiMsHmvio$9X" + + "SyQitxdNj$eeDYyd#bIBYUswlDWENuzvQjoBjXQfwuN5xktkxJukkXSjrf05FZRdDdEUMgV" + + "cnROuYCsvSPFrsyrviPsv7lQsI5dROlTEzyxe#aPFjSTZGr$LOdrpBjumru1ndznFKQN0Ti" + + "l6mHPt3LXhR2lgCBQxwp2sD#emjW$hCBQFwZ2sRzThpp8#6n5RhQ#pqc4JERzpVSiCNMziW" + + "qBO$7thgdXiKLosvVzM98gDxL5GR4vERFCBYgr17UwtHhcmsUi$JpS4jg9Ss9pcwukDZmzX" + + "CpuoBnaR7w#mRQdkzuwd4f4n3JyHdHxRZ1pOPkJ1DaDXsrfXcq4bDXms$Kc$liMCwROvvq9" + + "XiHNNOMpDwZ2s5dKOMwiwZArr7SQsVHt6rguEO#jGXx5rgiFOIkimjd8JMtQDVQFyni##8x" + + "ic3bkgxoYDJroQpj6#gZ6AhJA0BVGTPHX3$kye8mXYqdIEzcN966nT0jW#W9JyZfd23yCOy" + + "dyd7a4GawPpjA##XOzYEpI0BVITU1Y3#awSwU#n4xuJDn74fEaSxSkICTWc1US2PELtk#$R" + + "A$roVisRT2vCgSFpT44TnhQe3cDRKeUndLc7iPrTXx7TK8UntLw7iRrMXx6z4zYpliKvv5i" + + "Yd4E#ZJs784zAnbCOGLoQpj6#gZ62pNaaWEqRI7qZYC9lmnY4n3TACfOY26BIT8xsPSaORE" + + "kSpmBxwJTgF$q6##atOGoRTaoTh#kklJa$r65iFzTXRBy6xQrEOVjtxVlDEI0VDl#xvuJlP" + + "HP8RFnUusrEzrBSEfNVQvAKv$TczjdK$SQFDh0TJN5o9Ybiu3OvjYCDR4TId9n92XkuJOxj" + + "7WFRFHGdPvB2Ta#cvoR7TfI1xIYAapD9OGEtYR1DLzW6cVEKYMUsuNTWnx1XJBuNTW8xZQr" + + "Lcj9XcyUc9c8RhUgV0zU2RMzW6nNJRmyP$VOGnScP1C6Hb9OvWkctmSosxs3dnhplKVt3D6" + + "E#7oOghiEu3t8wnilxkfMSyjrz53KatuWR96HL65jhg9mdFrt51#aqvSinP6OfNKFg#kU9j" + + "xzqprd$#RxkGFq6ylMkNtvorv#c$TFrht3ahsZ83vEGL65i#qFbFFaRT5odUTAJ5KqdtuWR" + + "96HL63lgeNA#l8xhD4zwWgB9v1jnWuIi2cDh3PNpvNLSftdI#ogQGBuHDqZ8gZ2srb0vNrx" + + "7TPedFGtZEe8DG#uqbzvRCIrAGbQ5iRM6oldoEgxJFEb9YgQHRyGD4h8gZAqrLCwNrt6Tva" + + "aVgsWI#KRS826hmjXQG#LyUHtNQPxqL4N7ac$43HAoAeojDLJEbzTndUP9dw1eAlb6t20Xg" + + "yBOMaFbV7aTrscUz1H59v1ln0qIiYgChJLKpfVNSPtcIH#lQ0hvHjmW8Ql2s5f3vNnv7TTf" + + "dlHnYeudtuWR96HL65jhg9mlh#CwpPEUgEWuyesuGK9MXR6rXihvyZgkqppfyOecac$43HA" + + "oAeojDLJEbzTndUP97wDeFFb6t20XgyBOMaFbV7aTrscUz56AZY7VY1iaP5KOMsked2#lup" + + "hDapvSqL7a6t63XAmAOsiDbVFbTLodUTBZ51rElX4tICYgCBRMK3bVNiTrcYTzXA9nv1jnW" + + "uIi2cDh3PNpvNLSftdIHoewWdmZRf2GLM5ihQ5olhoEwpHF#cX5Hv9ln0qIiYgChJLKpfVN" + + "SPscVFL#FUBfFOJHztZ9Tt6onFVhHT$Z5TOWGtw7vgrbnFCxtAVu7IPfEN3wxOYNqria6TF" + + "lsF9qFYbHGLyIgfZtU0KrgF0ipLlB17yMfCyoIKYD03T2SIEioyaFaywDebKrZP3vCV8ZTE" + + "Z93MVbS1GR3XeX$13fNAK#yaqjvSJBwxXEWnl6AbtnJnxkCD1muOT8vvhl5GtKDqoLLYJUk" + + "3$CJwMGVgSXkDsH8gvqmGa#IZgNCV76VV5nxZ3gsrsL3iaxj#kuJeCx6IadYzZ9ae#Ipari" + + "tycgj9HkAjftifzAeMWVSJEa8n$XrkI7oSjDQjyCcQ#acsfvvm5TNkk0coKT#Q0PmW#Hpes" + + "pJPcdIaVaTLodmSsKZdpGBE67IEScrZTJbPRIJNrvNLxhW3j9El91CuKV8fqRgcMK994tof" + + "1kwilhybe7t8dIaGywIVXX6YLpTItiMhzEMLAL5gJgEz5FzMkGgvrp3vKJgzs9lXvopgrvr" + + "#1dBBbZFXDiFRrhrHuiqvqQvnZ$NQkMUikx#mpVMnB5oETxEssTgSv9ZjAXSvscMZ9CiXpp" + + "v4q48lTkgKN4YRyRiRjDKh9tkxE1Q3R9khCb7oM1MeMarseH6l50EPtcfqe9KS$1aeIUWmt" + + "CweqPEfVlfIN3fCjPYvpZYRSM#szorHf9pbh03r94PGxIx#bpHbkdMcSAAPKBEYYUICR0U9" + + "3MRntcvoYv6aM2Pv6FpWNLn5EmdDJantmjy0zK9FYOkbGkwC1u2fQJcloOhmN#$ee47rENo" + + "WNj7q$1SbAJ7$Erm1#bIF0nTQbSqAXu2fQJcloOhmN#M4M2ZwbBvOB6nbEmdDJantmjyCSe" + + "4dnCNIeND2QUWkMa9Z$cQu5$W2B1nzIbSa47n5EmdDJantmjy4Sh4ZoI1mRkfkjyqZewdbG" + + "vhNrqeERHNkfeDbglrvHgtMKqIFMwNA#5RE9xictpVpv7cZLZlQRrwLonNZDT5wtNWRgOMH" + + "Ujr$dhogwL97bLbzGYws8orrgc9SCaPAckq2UxDXXYTRr1kknQzmR9HqdAoL2LbUT#UZFxM" + + "jbQCrTWa#V#6nBVrFvFLWo77Ixxp#m$hRNW1UUJrrfLbxKiCoJOi$8$ocHTUNgsi$iNzoy8" + + "czZDhRNMztORfS7xZpAgosxfroNUYX$p7sNvwp8$L9Tw9#pX$diDuYt6tsl4UxjIMOnpKw2" + + "sxprhyzOmgikQ6MpNUlVXE#uxkWyHvkx3TvBwC5EMlwvCuD$3y$MXhYlQXxMgI#aIDTuLxa" + + "FxIstJg2j15t$GdtNyGVjJYlC7JSfC85tymUptaWXtzdld5L7BUsQRAPTqQSam6QBIZbxGk" + + "ACVYHjb4lk0logTDOo$ob$DVY$Z9iNtj$znnlfrfPiVPak2VU2jSY8NgroEFb3zxTqTMVy#" + + "43L#vAFpvuRNndrCAUFV1zwqEsEjUzCPItE3yiovGVy#WBc1VBkbhp5JYTpO$sgaZ$kMqFY" + + "Md6rXZI8i4L8jWxqOfz7FpMT9zBzQyZ#uY6UHlLbA24sVn1ExHDwR4Mquopqh#xswLnEwJy" + + "D6QmvbWcCtoXdhwmYCtISvnswazMR03cP3rxb9Tf0yXpr1TP$6kZpIAxuk#SRlPNvkKg$ar" + + "wKjG$LmWYRI9IpZJzeoif$4MGRybbgdh2VUraYFo2MTRqDN3ckJEWEOutM#7RJ9w1ZajqcE" + + "#S$56i2FaNoK$5nT3tz5EgnYhqWU#Qy42FAadNz33XBV4EamI4A$2lNg5hHL7dhQKTHD9qf" + + "ApsbVGYBLccNjcCDMGq#YM9VdqsajotU7GWcEDdIrODiRkemhbjHpYJuZoVxppS$K#5Z#jg" + + "R0Lzz$lwl$t5CbaIpv6wx$t5DzNLI3hqlMLll#2#CZdRukgwGG$HUHZ#eCxS1fyCbLdxwHI" + + "NvhXNqOFMj6gpxff5K$CqMk#fdfR5HurSzCzV2nk5NVFbraZzJjK7kPk3hE$M#cxhkgXDXt" + + "hFq5WacPtHI25K10$sHBUzdAZFTFxEwxaNqd#Ma$sOEdo1vqwEe16aMTApF6amFsQjOhyBH" + + "VhdVKoUiGUIzWXQbHAHlb$IljQECTTVanZXIZx6kS3Otd#jSXX34p8Zz6mwHoO5GQMPfM6n" + + "f7XZGAZ85#hAr6beYnrXhvjSfTpA#LV9Wm9YVRguaBlk75$pWNI3alVebzdoXxWtCHlq5el" + + "O7V8FqGNSjlrxa8RzSkGBBixTnxKvgM9ovvJI4PkeEUR$xpgo5xjIXnjUJ3XBJxT2xnrZ8H" + + "loz0dfnNFrBa$4TECighqw7qIsI$aoJvY5Ke2N7A$YwUWjByUkjoVhtaA2G$IEujsU$SMoJ" + + "dteBLH3YJP2aAFUqlI6rIRuxsNwzMtnJjjpixyZ#qyvov#M0Y$JrGyZKZyXWVJAiqoGiqwg" + + "vXCCu71wzhfNwJ38sTdT$IO0psID9zirmzadEVU9Gzn1wGDJlxM3MMM8Em5zATN$zV2TL7l" + + "BDH$7UWjQ$yZqNhSgSj$OkxO$oV8QLdzDtSo7y7yY$GBy8HwJ18A7#k38tn$rmxGL#eC412" + + "6yBa5bD9Kokw#qAfFHkuHoJIlXRkTlwreCzL620f9qElt5VQ2VfQXK6wKwOB#Jkr2z1Nedx" + + "YlaJufRZs#XBqbV139FJeKFrB9$zCEq5VgZ183yXq8V#0TW7wJDHFwPzg9#Wp5GP8wD7XP$" + + "9xIRvEEq6VgZ18JyXq8V#4TZwnHbHIfN#YdQ1rAWoGqAF3TQe$rcedw1CL1ccbJ1VoAxKBq" + + "5fHDwL$h9sWjIeCaD2ZmxNgha7MVue$c#KVPsC#zaAPdhmwE5lnZ$LT0$tBWUZguD8$2Lge" + + "pI8IV8I41k8e5CurmY0ndMuZj5769X9yX8GiSTqGTdEfZcwAZn1JkIfVbCeXosGeQkXcFkD" + + "hpaFt9dBGD1N#JSBl9ZYFj9oGd2emH9ulDfyNLl8odLhT7BdDHIkRYr0uarG9cNkAT06C2v" + + "07nuR2No3Y4L9o2zpJ4C91zZJ9Hqd8gf1AmNrDJg3zMlAIyudFTfl3dKOSnvK5#M5Yqzck8" + + "XpaREbVDpdDsFxEzlgzPdosrwnTXRr37hR#TJOhBPt2E5jdrx698XHxXYFwpB6SHaOtZP8w" + + "X9x$aHC5$wVu2A5yEn6E3A4Lrqs#7ldXiyYHF9yb#IX9EMu#EMHyNodHUhcZ#4p4PegICnK" + + "V8Q5HXKuxKMua2tvc8rUXvIUH4oLFKdoK7fFfGlunxKnIUXwZrhiDY4W#kHTbkejrbnm$p$" + + "rKyyJvn1z1NWEPon$HBa0Ydtl$OyZFazhSTGZN2Otht7NaIywWpo7rkUBetug5CqbO#ZhDA" + + "SiNsYIdGYDNna6VGUupeV4pzpFo9MVG9v3wH75OzwKpIUZwJ7DAjz0cEHL#8kw8$SfmvkCF" + + "imbAssVyOVSJn95c4bl7Fir#ZRph8IVEnk2kptvDVfZ84bL825gmxONy8k7ewQb5eEk57wR" + + "hPIwBVdnBbB$uC#ODFlzq5t5SuP73cMILvACanXbXxliKvaUVF$agA#PP2Jf$PZbiajFvCy" + + "ib7oMI51osgwpOihAkvAFavyfIQhIMMdkvIoL7eNG1QfvriN8BBdxbLsMyFI3ySPiXhvaer" + + "ynjnYhX16TGKwGqbPpaHTmaMKRaUdgBfICVr5GvWxISaDGxL1Ffo0SLAsUGbjESjcV28B$1" + + "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" + + "dpHFd4yRP9S8F9EPCzOBhJpJimrwEd2G6KEU$vzLVs71#KHsSARt1AquE$4pbRPHXbPje$z" + + "MCLtYC$O#48na$z9YV05YmPEUYl6x#09jt$mkQBzBf9cqGE2vIsld2v0oGMabF7I$MAttN3" + + "#NhBMBUybyVY1FsPP8EutFLssVZVnp4LTtdy6TYfHHb6#MvFEbDgqruPDmtc0Mivc3GMt06" + + "h96h34hObkmBJ42MxDjsBQi2IjcJLapZ4aBrfArOjknrgmDPbbRrewrnypjo3gn4bQAKIjd" + + "5QoITSO8TcKxi6viHzQTLR4Uh2V6jZVRYVLXVLa$rf$jp0QWtmQnmMm8gsP3sIviLxQR6AC" + + "zs9viE1l1zc9xittOla2y7qPpV$J50MmC6yiEP3Ni87OmEuGToWvZXpDwSz2H2l$upRmb5b" + + "f2sDbcr9A6Q4bZjYI0BQDQqXoODrrBRcHl62rvGxMaABObOr5NT4oUnPWy7x6kpMCS6g1D5" + + "j0v8NH7RZOjc84MJ6FJ4Px8Jc9ti3knEftCxjcCMb2wsRUW9j022qGjo6n6BLWQQi4neWKJ" + + "DgCMM84Mb6v6BPXfj81GpcUdijFO0hQGBM8Vi0ytknPq2RIW2r1kRYtOdCUW12sOYJhC5ip" + + "7lDXyMj05BNWPCRC5ZoEs#RH0Mb6m1Iqt#nPCtmnRi3JGWclPTGLhmNkrRi5O4E4mM#2mSG" + + "N2NxD1RAXm#DDRqECA$p8sja1O$veQArDOMm9hGrXx7BvPg9lmpHBsVtoTjtzcx6GDKKSSl" + + "e$Onm8VXRqBrgRpKxVfVDMctWMpgQ6fiOvLMFzNCAozKsCzsxY6B0pMLrDZNQgmFbumh5#b" + + "nhfSOIqg6DOjKcCjKbYtA1ZMejHOBOMrk61ObwV6sb9XdLumh4jJOoqnxcFKzJNhyeBFhVJ" + + "sMbIFjHvhFTPwhCQt3ON1MfeQQx72sgPWM1zDZVLHurgvC5Y$J8trkOAVNMwgzVdrcSrWRk" + + "bhmyg2ORLIOvrLyEkjz5WBtw$fpwyrnZU9TVt#dbFmkVN7r5ZVLrZN5GphSxM#x#8K3EkqM" + + "jl0p89XTMfzFxfm$VfwhVjrMi6mPXHMfvRtdbl6ufkkxZsNY#Sw2dMVDltPyMNZEyYwVjzh" + + "lCAwf61O6wR6kaHXlRTWM8jhVQrJk7wzjzRdt5iAXdL6hVirKp2i7LDZhIpusN59hS#vvPi" + + "HrlwR4TR2sK1bhTVNmjrBqlqwhPRdXiwn#7ghSuF5haHB2dLkqDUQyKz3r$OxQq9F#AZsPG" + + "LhatwsuFsyRVfMjMcMiAcZWPMU7o2inm7hloDOxofOc$Iz5YlrcOcXJRQeWt1#3fmpGpZbK" + + "olD2zQcYQfDNVAsgKgrQNd1vlujgTUfAg$$2pcVPsq6z#RJNuUL5loQ9VsUkgIWuvyUPr51" + + "STR#kgemEFTBZNFVWk8ScHhdZ8BYrDUecRmuFzc8EFU53i9P5C7PGk0iOGEnqfG3HxMXoST" + + "1E9FsK$aKAE6m18wDypJkJDM2tf4M58aMp1GjMCfgq89psBa6DWOTjcW1eIdEYOR28l4hog" + + "yL$id0NvHgt2ctByPOzcUf#ErVHS9QtmjOzRZt2vnVgd4w8PmrEN5Qo7FO68G7AfoPr3WhK" + + "AelIccSbJYvLh3N4t1Eyt0E3E6SAN1Mvi6vLE0y1pZ7CXUILoBrhLGuPneuILAEwFUnE9z0" + + "giRPEO2p24GuU#V4wV$Aw0lKIxyoeXehKk9y13Wl53WlGGc9io8MvngKYAvB4cUrm5cK4kS" + + "Fx4SFPsdANuME1SuQWTEVQ$7NGMkCSP$cuNmME9$7g13EJ4gS5w1UmdabqjBPvvA0VJP2kM" + + "SXVq62VIwBV2V0K8BiSxx0UK5Ad3UpfmNE5IXXfS8vXhtZhJv#VnR7ugGvgd5cF9n5m4dw2" + + "MVpd3XfBkoZPlfCz8bUtTBP9pFiiw5NDX$EIW$dqGREutBYD5UaOk2qHBbChUTxbT76V3YN" + + "172UZtMgTZWp7ivqzZa6LjCNLaCubq5#Dafd4jPv4sVl04xpkZiNpYBWzAtqBUIHbQR1ETd" + + "eJ$cx3HjvyTVJ9ivbwp7kLQ87PNzQwCzYUYq6PbGQd9IZSRwZa6w1SlbmJlYTzhb4uBJ4NP" + + "pqECzNwz9oI9UZTETOd9CWht7k4i19V1gShO5JdgAMm2yMQr9jSEhrip#ifnprt1QBiyh0E" + + "T73sHWrRg7spTphfx$ktIn#grkCzVFFx2#rm9bHE2s1CyCkpjkV$dLS1ZXdeixyE9UASm2T" + + "2s#6t3J8hG329QbmZZNc4KbDGrvL0ixuULGkS7PEXPDvE2r8Ey1Pd78UTHRhV97gpuRYF5#" + + "Ji1zPHdys2jZdJAJdjy#bOfSzHxmnPHgaBVOQi3PCXREXm7c1XvF6$MBsJIrmBX4uZqdLdz" + + "EC$lnKzES$s4#fS5h6k3SIzkaWzygyupujS0v9YxD8zUVD0jN5jJY7F6BWl9XzXbWLOl7tm" + + "wY#w7b9ZllyLEDUXFA4ath74NEzFEKv#Nm3vqnOfiIv967SEyUC#uK2Pxd0sJ$lkFygSFwJ" + + "$Sn#O$#gnJfliGUyTObmd0y#QTmjI4LnxcEC#zzIZZlXULEWR97olBH4u2nIu$wT614hSRu" + + "FZS4vgrOuvJoQ1dJJS1Of5bJxULIgSCQldyU0eljHiO7JIjcVX6cQijAququurwh#R2Jiit" + + "OucS2vLk1icDS#9wZryrx8Be7iafJh9rtxwt5l9AwMIY4PRvzTG56S3GNEBW9dLHwSIzWl0" + + "kUDg6UMEEzIc0PdAQWlkqdDercgPFovxYPnVHDy7fL1rXRtVGZd0tdxqn8u$qwMQba87qXv" + + "dfVzUMC8Ptn$teOwe#UG6u7JKkUGMJbnKfyyWjQ#g6gwIONfSCu2pcA1ayw3vwEUIbmNnCz" + + "tVpzo0jURJogSG$FWT219FktEIvHzbgTSbsPuEDj0$b5eUGPbud0M6JYVz73IbSfh2gUJjp" + + "#NYfLz6djCZ84bmZGuYr6oBnpXl1T87nCpwO#nE4jZ#vDmlbaBd8mr2RYbAS#Vr9zCu3G$S" + + "JYPs7t2ryLObpW#X1D#3fmyuPC6fv3h2mUSWR8nE4MwmWbEuGHNZxCUPptEUfprEEjnrkEi" + + "nrcFinvdFSvwdFKuwt7Mu$m$XjF$Nbl4Kdwl7SP9twGdusHtHN1QgDL$ae9GFiGUPgkHJqy" + + "S54kKGcFIiscbrADmxx9o#6yBbFHzVdTWl9xT856otk8fmBxYAS2xv5E0Gclqhet$$VvgDe" + + "hw0L9Zu0w42xyNVwR4ZXo9tNW63sbviID7VfES4TWR2UmMkEvmw0V27SBUEYVsfmpqezGen" + + "cDF#rJWbJbwlaJqlMyVVjt7i1x8wSKcYgS2IyGtCoGt47AdiyMiMetPYt0La3kFTG57JmNs" + + "5osZ$qVfXR2QwVS5Ds2NiaOYhrAKFf9TmsxJVSpkpe5ofYZrNxPAsJdryP6oZqLyYUZZfQA" + + "Fpw4#HYnN7qzSdpvM5l94i8#Hci#w0xDIeISB8QqqKz0d63dgqtxWpeI5d6MWJxGxCLD6gL" + + "4OWx69iMuXrK$qpW3qZjBALh8fx0GsDMm$o5dljg6M8jas8Qyrqonk5DSsCUPtONLAqjo3s" + + "eOonw1jgzc16BDyrZymWFxT$EX57ZJ0Ptfau8krDjGN$OI60LXhzI#ul35biuJzp65psJns" + + "Yj3p7pY9lXVGdx4#SrVPIeudUf5BQtjmpSVQhahs53xchh006W5lLc1EHdOADNVphocol$B" + + "Z4ddUdgTmOHq9uYBx7u0rMEFg9NA3Qt0gNBNlBp47DQv6X0iQ0$tbun8ovsqQN7v$2RqzXK" + + "zhS2CFrv#y$Zf6u89UXC9FZqkiphy3bnv7hFHHN9Vwk8JSDHiV5tiXoUutn3ZMrkxPsIOkQ" + + "VVO$nGkk9d0TOrlzq5COa$ReFP56k4cgBqvPfrWbw6$PegTuYeFLmJL9h5xcfazHNydZAFO" + + "FJRgVEI1ZxTEMA7vIC$TcEjgkBzQAroXKyHwxBHti3j5$Zrg1CCxROayNU4iHjRLnR0keHa" + + "MbgIvMkvLFEcC73q31NPQJYUv$ATaEHzisbynDdG6QWp4mJbs3SQbdv0Bdk3yDRiikDkA#I" + + "LtsfuIFNRRy0a$YFto4FOIOKlbENg#TmY3F2N89s4omah52IvcdvKzd#lq8R6FJxmwaTZx2" + + "UpURtWzgqnpTNAsm5gZrY$Tx$haB9yJluPEpeZ9Ty0h6#On9sV3tYx4#RuHkuJcbvgnb7fr" + + "YgizusJ0fYjCCp4EtRrszHOOJ4n7YrtXs3XCueaTYOckEUHfcZ3Xob5ekqnTOLXOrtACHM2" + + "#wzbbOgArCMK$mH9Y#ydJbgAVuZ29$RwxNCLhYobkx0BwquoT6cTLeh7VJoB7bfYWcwx4jW" + + "XYWlRKcEXgrCJ4gd9WIho6HQgyXhN4Uatstn#MD1QOZlMkOS#4EqlKOOlULR$DYwxGFbR1I" + + "pixKl2tc$EHtSSc$mwiDNBF8wp27uZ#368rVoLexYsN#ojHO5pLg6ALNczKUYSMFVXKRL3v" + + "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" + + "bB6JqB$Jsc9yrp3M1$spA#opBsHFH3ksBMVivCCOcuF#dhCNohs6DgCjswA#Ks6Jnt$FsCm" + + "x87CoOpiTZRc3CUar4d7OVM#qwsJ87eSo9sECfy16Py76PW53auO8qTvPQCiir3iBVNNotu" + + "01TjSASw89x7mERA47#g83xA09ng49ugSL8Ov#RW9xwd0wS6BiPyE6vin6UTZ7YMZRmGCHX" + + "yrswWOCi8CvxS6Z7pgyWtBt8BuKVO$sDoAxG1iw$WjZWdQq#nZvRq8MjjBkDl1$PgmO#q7x" + + "dL06Sx8ODZ$kDxHtEvH1$Hrl1dyVC3o7EOm#w0JRduqwEs6CPsCiTiPyAS6yxlWLSAF#cI$" + + "0eRxJi5xCnXen6HXEwmuSm5sCkafsXxsZhvl2$ji2IrFeE$4HXD1p8lgmwLzHxXeup44B67" + + "Q1FSo63Sx#4FCVThVhpuprmxoRUXtY4#5WcytGnmE0kHFcV3FOnA0T88y#QuvvtGppP3lOq" + + "2pqNmUiSHs0PJevZFCaz5bFh1VDWM4wrgdfDo0VOtxQcS2v2yPuH$1OEqgmVfvsEyBB4JwE" + + "y2guXp3c69j9M4ldmWOcGUP4sCNH$L7t2CYz0XdKUThRq0#xs0qdZ3a8smz0ks1dxJ7djqD" + + "RjiUOj0QMniZh0TifWetkXldQ77Enw4GusCh4mw7$R8mNshmRsjKUQ#Xnm3C9uzAXBy9tKV" + + "ODy9Yl7R6UpiKSd8JzRYxQDXdzF1TZCta$nkPXGit3F9c7UJaPupmFcCV1fkPX7ep3V9g7j" + + "R0lrheM25iiWmpwentqJ4PRscE#pCEOzCIwDm$pip$iip$Y$R6Mz8Vzj42$xBmd7ER4pXYh" + + "4epX0EmZ9Ty14#PC2upXW9CGOem7O0rgTm3IBuLkhAbxmiQEGtix$eEnbbW$1yB#1s9DEAu" + + "1sWMxEnxnKhIz9UeS24m3ONk3i6uCXBtsm7vbZu83ba6OT#snHWr27OEnBWx6UZiOQyLWs4" + + "O7pBKXM2U7OEqSydV6gb5FDVQM3DQx3F8ROEreW3OqnDhG4FRWO3vsnBhH4ltQYkmRDZS5w" + + "z1mZ6y$Z5Kxh3lLa1#QmHXZRMa5UncAFXwAjTj1Ezl2DZl1teOXlGFc$aJOrx5FGqylEDZN" + + "iHZ7Zk#Xlp5tM$q8zorZ4p1MdM2Rmz3$hL7dCFHZ9zZOxh3drh3Xux77JAb66kPu7$HT2VQ" + + "YtJ6EhM6pnwFTKx26bfm61vihnVwpE$gy5FlJ7YXR2blO0sjT6URb7kYhCepx7XZRCkohUs" + + "9jByTSs1DZLWwRsnFsKeus3iV#MO7#68vvN86#6exvMu7n685vLOd#7O7vNuazVmJQLOant" + + "MjBnZgZt$O2biuOgxsmldJ66h8Nrheksp2szsu8OGjxOstiWhxT#oF6kgAThM5pRJ6chJ4k" + + "Mm375jZdjW2kBR5sRGcSFT2lFM57MxwEVG7uMsEURpK7$Ovri#DGxA$0s04ss0bskW1phmH" + + "piWJZsU5FI0FcKgp3hT6chT07M#Cyq0RzsGRdYpPeno2qgmJhLPiEq8LzO3hwh0F6eSEl64" + + "kiswLO5wV3DcUWRRjWNfMUXJKOzdWov6TWFPe1RFjWdPW2cod5EQKDiCsWynJ6fpNcTpli$" + + "xl0LhU7xDOOYwrnJje6OxCFvBU7BUm3p5sFO6nVh9rTiOxjYprwUxHXNwmlssCDtm7OEs5j" + + "R8krS2Hik2FMp96eiotg7uavqHOwTi1UMuMvqnRjROV#6VaDwiTOxeT#c8AoEs2Ex0TTtM2" + + "p#s5zxOQzj2tMZ56O0zsmlaw1$RN3lDrcFZPSjBadwca$7N7OqRQOmptFHGYxEW7stm5hnh" + + "ROlvl0zZfYtIX5tPtGjnsnDxQ3xNJ2lZGAwzYnq7a2vbixh8cxmFPBqSUTUg8SvcWJsEzGx" + + "8F7ONpd0KC9vcWtd4ztn7clB#RJrCOeXxsj7TRC#Kkmds0TACNQEsSurcISJNh1JjfWpTm5" + + "xIr1$vHYlol6dbICkN8S#ku4zFy9s2EB8LUADQ0fvbG7jBq4QsKfwcqAdKqnzqfnnYh3N1o" + + "5zUnuzCd#M1$tn$wxF$Qv$R4cD8EDDCDyReQsD2TPsF9ex5$7emqdmEQROzqlom8BxBSDzh" + + "TouDmUSYUWpSqHtnvb9sADc0eRduZnxu0zTohMZ#DXnrCnLyjWDnrm1foA$bqm5dXm$Ym5x" + + "jwmqTxe$zCmFyjXExqnXZkXJwOYR0USSp5$5y1coc6Ryz3l7M1dxQ7t9E0lHnqxOUtS2NeR" + + "e$$BCHVBaNSwvcKvre#JSCPeZFu#7NEW76l9FE1iXlRCm5voEiQo7FDf7iQY5TfMZdNXb4R" + + "Ofz37Sp1cfRFWO4ideczEmbpf29iinTvz4iv2Gx76dGGiEwClos4N9w7#as3R0z3sGJXxjC" + + "UwCHZpVm7MnHwO1uEn$vN1bign7fTZ3Yx07Z0ODbc6lQuSwqCvR6O1pWv3q1UbwDToZDa2Z" + + "FSGh3b3C0xLI5k0zR4QQx#3kLcEQv9owaUifqE1eOpw1rZBKSz2sDWkc1yTqQVbwCDopEE5" + + "wBjzOBSBzqOSUz##MEiweIsbM8TFWknE2FkWt#PWFjTW3HgD#JmN$JiLU#yqr5U6ELAE#ij" + + "W8#N0VJJ6O3Hil1nsLG6vXUZtCc0x6dro3EPA1wo5qt2jKePsbAElZi4v$MZqoqAo0wolns" + + "0VEWPsCHvsMeO#ByTPiHnZCnuOngD$#c2l6m$Suw5$8CuqFR7UdaRd4unN6TQACjX4ETaBr" + + "jI5wDy5w8iAwAg2xHw0yyO2bC6ommx0dhGG#q4vwgZ0MQC2w$92xFKBqOQ5sCiNeSn2rBK8" + + "zdO0zj55E9$qWyqxE6ULONsgGBzLD8SCnkPqs5CPrhCAOAo0BIn4tQTZlbN0RYPWR4$7M2$" + + "4$bu1Z6EmTfoEzM4CqcQYxcEnNi#4RS$4VAc0NOn1ty$4kjyFwra5xBS2DdKiycQYRrfWtd" + + "V2dZWMQy84h5Dbs7igi9PqmbpFO5wrmFphXpsc6cUrli2vAzR6NM63k#BilnlMwh6u3XgBS" + + "qC$h6yLs0Chi3TDm7go8yuq5S1JGPY1PIpsc1t$0pl1dZe9vOOZlmFaEk8CC1TsM87rfGBp" + + "PpZ6kWnhImKmduAnhW368gpV1sBjwmxS1#AiLe5rl0NaMcATEX1hpZIS#rfYJan3$Isnj$H" + + "1lQqmLsimZxh3zcjmPgY0RRJ2lbW3U#mEcOEsHHhsr#smJXw4UL45NGV1pgTX3TmEPxs3O2" + + "DLQ7iPvd45rh65M8igi7vKmEONuOpN7$F$5E2em5bnEzZm8gmnlT4FYz3#2knZ5PZpdR0VL" + + "wAjYs2d5HZJKo1NWRt$5EmN5S0o0ZfAwJo7jMakrizJO2jbs3Cgi3#Fm3NVALWhAs0xSt6T" + + "t9lM2ypD4hJb5CpLCig3hK#07Ps2UTCHQyefEFVCnpXMu1ga8snpFkgUYBaq7tjuAUPi6J1" + + "KO8yhmJuy7trMYlreBjfTXZMf0ZegC1yxmFRdOfsUYx6UZx0KjZKHOvL1cuw53Iv2U33Eee" + + "jmJg$0thq8U1V15ifX5uimnygnBqw4t3HSAyp5VEY7SQh1cbY6CQp1#9V3NYgeFhHxFlKvx" + + "AyCUyf1cAC7uSnHIUE2jMC4sbPEsD3VfyDMAp4l3iPQMecsZ8E#IgnzUs5VcWgPwNJcmXbo" + + "8cnsBypFwR3NlfWNbPYRbHZVIjXp9VRkIiofIjXQ9UpHGlsLcBHbMDFQOdpxOXtkZxan6Fq" + + "t67OscDe7FHbWwOFriXBzNuarPp1XH1lweB#6a7xigqDGPoNEt4FGvahegCRyguGzLAF$Ah" + + "4MLM8EL4wMzuocpP5XsmTaoAwaKFBMsp9qxjTfCcv$58otFTwCoxHTLDbTswcmH8MJVPbTf" + + "wlmAJ#jtMWPRdUI33Floh0zhcKoMPM6FRTXOxzCmxt3zQTnk4xj44tRwnSPDXYewiLyQzHR" + + "rLkioZqNqXFgZyPO4ngj2wODsZqOBxfOwJnHrOFriEWOoLSjzkLsMUVpVM$q#GRNAZtOvzf" + + "khtJzMQLX3XxqTB2#lNTJvR9qRWpcEGVwV6QxO5w3dMIunKhO#mr#UZFOxvOPKrQcRzard1" + + "QLEQI38RzRlCoMI$FfML#7iswHQjlbAbwZmYaoh1gYmaL6cLFetf9A$z1FR$2h31SjbU6ss" + + "1ktnNdBkad6ctwlqflAiDsA$FZeNBwjCG$RRo739WraMDqxMcQd$mNZUr$iyxQjwiOrKPFT" + + "Wd8D1$jyXwjyliavoVYQF6FmFyYmxS4oRBL4fV#cubZNMk7iqGHxGKESyOltL$MkpDq7nV#" + + "HOTDjL7XaLAOfrbTsdH5VBSDEnqPbEptkyoLRX$9wg709xFgPODvCs7tpfi6qdNQLuPJnc9" + + "F$hvKp3uwYYC9uxynk4ie$$4CE3P1ZTsSjImj38428fI0a754YfvQbLUAD9KOHCI1ogA0eW" + + "iO322Y29A388Q3YXSeH2WmeY8Y2AE09UA7YWTVN$RwaUoGYLMhLLx$NxxtkdfsTxNuz6XUB" + + "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"); static final Action RETURN2 = new Action() { public Symbol reduce(Symbol[] _symbols, int offset) { @@ -4820,122 +4819,127 @@ public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [525] cppo_directive = SHARP ident STRING + new Action() { // [525] cppo_directive = SHARP INCLUDE STRING + public Symbol reduce(Symbol[] _symbols, int offset) { + return new Def(); + } + }, + new Action() { // [526] cppo_directive = SHARP ident STRING public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [526] cppo_directive = SHARP ident ident seq_expr + new Action() { // [527] cppo_directive = SHARP ident ident seq_expr public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [527] name_tag = BACKQUOTE ident.a + new Action() { // [528] name_tag = BACKQUOTE ident.a public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol a = _symbols[offset + 2]; return a; } }, - new Action() { // [528] rec_flag = + new Action() { // [529] rec_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [529] rec_flag = REC + new Action() { // [530] rec_flag = REC public Symbol reduce(Symbol[] _symbols, int offset) { Def def = new Def(); def.bRec = true; return def; } }, - new Action() { // [530] direction_flag = TO + new Action() { // [531] direction_flag = TO public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [531] direction_flag = DOWNTO + new Action() { // [532] direction_flag = DOWNTO public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [532] private_flag = + new Action() { // [533] private_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [533] private_flag = PRIVATE.p + new Action() { // [534] private_flag = PRIVATE.p public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol p = _symbols[offset + 1]; Def def = new Def(); def.bAlt=true; def.posStart = p.getStart(); return def; } }, - new Action() { // [534] mutable_flag = + new Action() { // [535] mutable_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [535] mutable_flag = MUTABLE.m + new Action() { // [536] mutable_flag = MUTABLE.m public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol m = _symbols[offset + 1]; Def def = new Def(); def.bAlt=true; def.posStart = m.getStart(); return def; } }, - new Action() { // [536] virtual_flag = + new Action() { // [537] virtual_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [537] virtual_flag = VIRTUAL.v + new Action() { // [538] virtual_flag = VIRTUAL.v public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol v = _symbols[offset + 1]; Def def = new Def(); def.bAlt=true; def.posStart = v.getStart(); return def; } }, - new Action() { // [538] override_flag = + new Action() { // [539] override_flag = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [539] override_flag = BANG.b + new Action() { // [540] override_flag = BANG.b public Symbol reduce(Symbol[] _symbols, int offset) { final Symbol b = _symbols[offset + 1]; Def def = new Def(); def.bAlt=true; def.posStart = b.getStart(); return def; } }, - new Action() { // [540] opt_bar = + new Action() { // [541] opt_bar = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [541] opt_bar = BAR + new Action() { // [542] opt_bar = BAR public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [542] opt_semi = + new Action() { // [543] opt_semi = public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [543] opt_semi = SEMI + new Action() { // [544] opt_semi = SEMI public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [544] subtractive = MINUS + new Action() { // [545] subtractive = MINUS public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [545] subtractive = MINUSDOT + new Action() { // [546] subtractive = MINUSDOT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [546] additive = PLUS + new Action() { // [547] additive = PLUS public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } }, - new Action() { // [547] additive = PLUSDOT + new Action() { // [548] additive = PLUSDOT public Symbol reduce(Symbol[] _symbols, int offset) { return new Def(); } From c17ea2a1313bae79e143aa04fdca4becb6e20d33 Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 16 Jun 2015 13:33:52 +0800 Subject: [PATCH 123/127] syntax highlight bold docs comment --- Ocaml/src/ocaml/OcamlPlugin.java | 5 +++++ Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java | 5 +++-- Ocaml/src/ocaml/preferences/PreferenceConstants.java | 1 + Ocaml/src/ocaml/preferences/PreferenceInitializer.java | 1 + .../src/ocaml/preferences/SyntaxColoringPreferencePage.java | 2 ++ 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Ocaml/src/ocaml/OcamlPlugin.java b/Ocaml/src/ocaml/OcamlPlugin.java index dfa17af..15fa911 100644 --- a/Ocaml/src/ocaml/OcamlPlugin.java +++ b/Ocaml/src/ocaml/OcamlPlugin.java @@ -400,6 +400,11 @@ public static boolean getCommentIsBold() { return instance.getPreferenceStore().getBoolean(PreferenceConstants.P_BOLD_COMMENTS); } + /** Returns whether comments should appear in bold (from the user preferences) */ + public static boolean getDocsCommentIsBold() { + return instance.getPreferenceStore().getBoolean(PreferenceConstants.P_BOLD_DOCS_COMMENTS); + } + /** Returns whether constants should appear in bold (from the user preferences) */ public static boolean getConstantIsBold() { return instance.getPreferenceStore().getBoolean(PreferenceConstants.P_BOLD_CONSTANTS); diff --git a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java index 0abecfd..79d1f81 100644 --- a/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java +++ b/Ocaml/src/ocaml/editors/OcamlSourceViewerConfig.java @@ -125,6 +125,7 @@ public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) { public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) { int styleComment = ocaml.OcamlPlugin.getCommentIsBold() ? SWT.BOLD : SWT.NONE; + int styleDocsComment = ocaml.OcamlPlugin.getDocsCommentIsBold() ? SWT.BOLD : SWT.NONE; int styleString = ocaml.OcamlPlugin.getStringIsBold() ? SWT.BOLD : SWT.NONE; PresentationReconciler reconciler = new PresentationReconciler(); @@ -139,10 +140,10 @@ public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceVie // a damager-repairer for doc comments and doc annotations RuleBasedScanner scannerAnnot = new RuleBasedScanner(); IToken tokenAnnot = new Token(new TextAttribute(OcamlEditorColors.getDocAnnotationColor(), null, - styleComment)); + styleDocsComment)); IToken tokenDocComment = new Token(new TextAttribute(OcamlEditorColors.getDocCommentColor(), null, - styleComment)); + styleDocsComment)); scannerAnnot.setRules(new IRule[] { new DocumentAnnotationRule(tokenAnnot, tokenDocComment) }); dr = new DefaultDamagerRepairer(scannerAnnot); diff --git a/Ocaml/src/ocaml/preferences/PreferenceConstants.java b/Ocaml/src/ocaml/preferences/PreferenceConstants.java index dcd9933..dce9844 100644 --- a/Ocaml/src/ocaml/preferences/PreferenceConstants.java +++ b/Ocaml/src/ocaml/preferences/PreferenceConstants.java @@ -36,6 +36,7 @@ public class PreferenceConstants public static final String P_BOLD_KEYWORDS = "boldKeywords"; public static final String P_BOLD_COMMENTS = "boldComments"; + public static final String P_BOLD_DOCS_COMMENTS = "boldDocumentationComments"; public static final String P_BOLD_CONSTANTS = "boldConstants"; public static final String P_BOLD_STRINGS = "boldStrings"; public static final String P_BOLD_NUMBERS = "boldNumbers"; diff --git a/Ocaml/src/ocaml/preferences/PreferenceInitializer.java b/Ocaml/src/ocaml/preferences/PreferenceInitializer.java index 6bf165a..a7a27db 100644 --- a/Ocaml/src/ocaml/preferences/PreferenceInitializer.java +++ b/Ocaml/src/ocaml/preferences/PreferenceInitializer.java @@ -41,6 +41,7 @@ public void initializeDefaultPreferences() { // set the default syntax coloring bold attributes store.setDefault(PreferenceConstants.P_BOLD_CHARACTERS, false); store.setDefault(PreferenceConstants.P_BOLD_COMMENTS, false); + store.setDefault(PreferenceConstants.P_BOLD_DOCS_COMMENTS, false); store.setDefault(PreferenceConstants.P_BOLD_CONSTANTS, false); store.setDefault(PreferenceConstants.P_BOLD_KEYWORDS, true); store.setDefault(PreferenceConstants.P_BOLD_NUMBERS, false); diff --git a/Ocaml/src/ocaml/preferences/SyntaxColoringPreferencePage.java b/Ocaml/src/ocaml/preferences/SyntaxColoringPreferencePage.java index 1832742..679e2fb 100644 --- a/Ocaml/src/ocaml/preferences/SyntaxColoringPreferencePage.java +++ b/Ocaml/src/ocaml/preferences/SyntaxColoringPreferencePage.java @@ -108,6 +108,8 @@ public void createFieldEditors() { .getFieldEditorParent())); this.addField(new BooleanFieldEditor(PreferenceConstants.P_BOLD_COMMENTS, "Bold co&mments", this .getFieldEditorParent())); + this.addField(new BooleanFieldEditor(PreferenceConstants.P_BOLD_DOCS_COMMENTS, "Bold documentation comments", this + .getFieldEditorParent())); this.addField(new BooleanFieldEditor(PreferenceConstants.P_BOLD_STRINGS, "Bold stri&ngs", this .getFieldEditorParent())); this.addField(new BooleanFieldEditor(PreferenceConstants.P_BOLD_CONSTANTS, "Bold con&stants", this From d7900fde65a32e69432f3b622a494c8023bc099d Mon Sep 17 00:00:00 2001 From: trungtq Date: Tue, 16 Jun 2015 18:31:48 +0800 Subject: [PATCH 124/127] improve shift-left indentation --- .../ocaml/editor/actions/ShiftLeftAction.java | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/Ocaml/src/ocaml/editor/actions/ShiftLeftAction.java b/Ocaml/src/ocaml/editor/actions/ShiftLeftAction.java index cb7f626..38f9041 100644 --- a/Ocaml/src/ocaml/editor/actions/ShiftLeftAction.java +++ b/Ocaml/src/ocaml/editor/actions/ShiftLeftAction.java @@ -85,39 +85,38 @@ private String decreaseIndentation(String input) { String[] lines = input.split("\\r?\\n"); if (lines.length > 0) { - // find the shortest indentation - int shortest = lines[0].length(); + // compute decrease size + int decrease = tabSize; for (String line : lines) { - int indent = calculateIndent(line, tabSize); - if (indent < shortest) - shortest = indent; + if (!line.trim().isEmpty()) { + int indent = calculateIndent(line, tabSize); + if (indent < decrease) + decrease = indent; + } } - if (shortest == 0) // nothing left to decrease + if (decrease == 0) // nothing left to decrease return input; - // the size of indentation will be decreased - int decrease = tabSize; - if (shortest < tabSize) - decrease = shortest; - // subtract 1 indentation from each lines for (int i = 0; i < lines.length; i++) { String line = lines[i]; - int d = 0; - int u = 0; - for (u = 0; u < line.length(); u++) { - if (line.charAt(u) == ' ') - d++; - else if (line.charAt(u) == '\t') - d = d + tabSize; - if (d >= decrease) - break; + if (line.length() >= decrease) { + int d = 0; + int u = 0; + for (u = 0; u < line.length(); u++) { + if (line.charAt(u) == ' ') + d++; + else if (line.charAt(u) == '\t') + d = d + tabSize; + if (d >= decrease) + break; + } + String newline = ""; + for (int j = 0; j < d - decrease; j++) + newline = newline + ' '; + newline = newline + line.substring(u + 1); + lines[i] = newline; } - String newline = ""; - for (int j = 0; j < d - decrease; j++) - newline = newline + ' '; - newline = newline + line.substring(u + 1); - lines[i] = newline; } // rebuild a string from the lines From 7bad5b1e0f05b1d9b0e678d901c3303f8fd615f4 Mon Sep 17 00:00:00 2001 From: trungtq Date: Thu, 18 Jun 2015 16:16:27 +0800 Subject: [PATCH 125/127] Improve OcamlPath --- .../preferences/PathsPreferencePage.java | 1 + Ocaml/src/ocaml/util/OcamlPaths.java | 37 ++++++++++++++++--- .../wizards/OcamlNewMakeProjectWizard.java | 5 ++- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/Ocaml/src/ocaml/preferences/PathsPreferencePage.java b/Ocaml/src/ocaml/preferences/PathsPreferencePage.java index 9adcd08..03fd043 100644 --- a/Ocaml/src/ocaml/preferences/PathsPreferencePage.java +++ b/Ocaml/src/ocaml/preferences/PathsPreferencePage.java @@ -4,6 +4,7 @@ import ocaml.OcamlPlugin; +import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; diff --git a/Ocaml/src/ocaml/util/OcamlPaths.java b/Ocaml/src/ocaml/util/OcamlPaths.java index 9c367be..2d74141 100644 --- a/Ocaml/src/ocaml/util/OcamlPaths.java +++ b/Ocaml/src/ocaml/util/OcamlPaths.java @@ -3,10 +3,12 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; +import java.io.FileFilter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import ocaml.OcamlPlugin; @@ -35,7 +37,7 @@ public class OcamlPaths { public OcamlPaths(IProject project) { this.project = project; - restoreDefaults(); +// restoreDefaults(); } public void setPaths(String[] paths) { @@ -55,6 +57,22 @@ public void setPaths(String[] paths) { return; } } + + List getSubdirs(File file) { + List subdirs = Arrays.asList(file.listFiles(new FileFilter() { + public boolean accept(File f) { + return f.isDirectory(); + } + })); + subdirs = new ArrayList(subdirs); + + List deepSubdirs = new ArrayList(); + for(File subdir : subdirs) { + deepSubdirs.addAll(getSubdirs(subdir)); + } + subdirs.addAll(deepSubdirs); + return subdirs; + } public void restoreDefaults() { ArrayList paths = new ArrayList(); @@ -70,7 +88,9 @@ public void restoreDefaults() { IPath path = folder.getFullPath(); for (String segment : path.segments()) { - if ("_build".equals(segment)) + if (segment.equals("_build") + || segment.equals(".hg") + || segment.equals(".git")) continue mainLoop; } @@ -82,7 +102,14 @@ public void restoreDefaults() { } } - paths.add(OcamlPlugin.getLibFullPath()); + // add lib path and its sub-folder + String libPath = OcamlPlugin.getLibFullPath(); + paths.add(libPath); + List subpaths = getSubdirs(new File(libPath)); + for (File file : subpaths) + paths.add(file.toPath().toString()); + + this.setPaths(paths.toArray(new String[paths.size()])); } @@ -187,9 +214,9 @@ public static boolean isRelativePath(IProject project, String strPath) { * relative to the project. * * @param paths - * the list of paths to add + * the list of paths to add * @param project - * the project to add them to + * the project to add them to */ public static void addToPaths(final List paths, final IProject project) { final OcamlPaths oPaths = new OcamlPaths(project); diff --git a/Ocaml/src/ocaml/wizards/OcamlNewMakeProjectWizard.java b/Ocaml/src/ocaml/wizards/OcamlNewMakeProjectWizard.java index 43a88ed..f40c4e6 100644 --- a/Ocaml/src/ocaml/wizards/OcamlNewMakeProjectWizard.java +++ b/Ocaml/src/ocaml/wizards/OcamlNewMakeProjectWizard.java @@ -53,6 +53,9 @@ public boolean performFinish() { project.setDefaultCharset("ISO-8859-1", null); + OcamlPaths opaths = new OcamlPaths(project); + opaths.restoreDefaults(); + URL url = OcamlPlugin.getInstance().getBundle().getEntry("/resources/OCamlMakefile"); IFile file = project.getFile("OCamlMakefile"); @@ -63,8 +66,6 @@ public boolean performFinish() { file = project.getFile("Makefile"); file.create(url.openStream(), true, null); - OcamlPaths opaths = new OcamlPaths(project); - opaths.restoreDefaults(); } catch (Exception e) { OcamlPlugin.logError("Error in OcamlNewMakeProjectWizard:performFinish()", e); From 9b7f8abbdd3303eab05df0a725949df67e662c8f Mon Sep 17 00:00:00 2001 From: trungtq Date: Sat, 26 Dec 2015 12:41:37 +0800 Subject: [PATCH 126/127] Synchronize and Goto Outline --- Ocaml/plugin.xml | 18 +++++ .../actions/SynchronizeAndGotoOutline.java | 65 +++++++++++++++++++ .../views/outline/OcamlOutlineControl.java | 1 + 3 files changed, 84 insertions(+) create mode 100644 Ocaml/src/ocaml/editor/actions/SynchronizeAndGotoOutline.java diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index 4f42029..2e7d707 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -896,6 +896,13 @@ id="Ocaml_sourceActions_deleteTrailingWhitespaces" label="Delete Trailing Whitespaces" style="push"> + + + + @@ -1230,6 +1242,12 @@ contextId="org.eclipse.ui.contexts.window" schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" sequence="M1+\"> + + diff --git a/Ocaml/src/ocaml/editor/actions/SynchronizeAndGotoOutline.java b/Ocaml/src/ocaml/editor/actions/SynchronizeAndGotoOutline.java new file mode 100644 index 0000000..7a9993c --- /dev/null +++ b/Ocaml/src/ocaml/editor/actions/SynchronizeAndGotoOutline.java @@ -0,0 +1,65 @@ +package ocaml.editor.actions; + +import ocaml.OcamlPlugin; +import ocaml.editors.OcamlEditor; +import ocaml.editors.OcamlHyperlinkDetector; +import ocaml.util.Misc; +import ocaml.views.OcamlCompilerOutput; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.text.hyperlink.IHyperlink; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.editors.text.TextEditor; + +public class SynchronizeAndGotoOutline implements IWorkbenchWindowActionDelegate { + + private IWorkbenchWindow window; + + public void run(IAction action) { + + IWorkbenchPage page = window.getActivePage(); + + if (page == null) { + OcamlPlugin.logWarning(SynchronizeAndGotoOutline.class.getSimpleName() + + ": page is null"); + return; + } + + IEditorPart editorPart = page.getActiveEditor(); + if (editorPart == null) { + OcamlPlugin.logError(SynchronizeAndGotoOutline.class.getSimpleName() + + ": editorPart is null"); + return; + } + + if (!(editorPart instanceof TextEditor)) { + OcamlPlugin.logError(SynchronizeAndGotoOutline.class.getSimpleName() + + ": only works on ml and mli files"); + return; + } + + if (editorPart instanceof OcamlEditor) { + OcamlEditor editor = (OcamlEditor) editorPart; + editor.synchronizeOutline(); + // show compiler output + Misc.showView(OcamlCompilerOutput.ID); + } + } + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.window = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + } + +} diff --git a/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java b/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java index 6b30187..55eb174 100644 --- a/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java +++ b/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java @@ -27,6 +27,7 @@ /** Implements the outline view for the OCaml editor */ public final class OcamlOutlineControl extends ContentOutlinePage { + public static final String ID = "ocaml.OutlinePage"; protected Object input; From 2cda1be0980430a3238cdaaca3c9388f6f9b9a41 Mon Sep 17 00:00:00 2001 From: trungtq Date: Sat, 26 Dec 2015 13:19:36 +0800 Subject: [PATCH 127/127] improve Synchronize and Goto Outline --- Ocaml/plugin.xml | 5 +++-- .../src/ocaml/editor/actions/SynchronizeAndGotoOutline.java | 3 ++- Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java | 1 - 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Ocaml/plugin.xml b/Ocaml/plugin.xml index 2e7d707..982b8ed 100644 --- a/Ocaml/plugin.xml +++ b/Ocaml/plugin.xml @@ -898,10 +898,11 @@ style="push"> diff --git a/Ocaml/src/ocaml/editor/actions/SynchronizeAndGotoOutline.java b/Ocaml/src/ocaml/editor/actions/SynchronizeAndGotoOutline.java index 7a9993c..01e3936 100644 --- a/Ocaml/src/ocaml/editor/actions/SynchronizeAndGotoOutline.java +++ b/Ocaml/src/ocaml/editor/actions/SynchronizeAndGotoOutline.java @@ -5,6 +5,7 @@ import ocaml.editors.OcamlHyperlinkDetector; import ocaml.util.Misc; import ocaml.views.OcamlCompilerOutput; +import ocaml.views.outline.OcamlOutlineControl; import org.eclipse.jface.action.IAction; import org.eclipse.jface.text.ITextViewer; @@ -48,7 +49,7 @@ public void run(IAction action) { OcamlEditor editor = (OcamlEditor) editorPart; editor.synchronizeOutline(); // show compiler output - Misc.showView(OcamlCompilerOutput.ID); + editor.getOutline().setFocus(); } } diff --git a/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java b/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java index 55eb174..6b30187 100644 --- a/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java +++ b/Ocaml/src/ocaml/views/outline/OcamlOutlineControl.java @@ -27,7 +27,6 @@ /** Implements the outline view for the OCaml editor */ public final class OcamlOutlineControl extends ContentOutlinePage { - public static final String ID = "ocaml.OutlinePage"; protected Object input;