source: trunk/org.modelica.mdt/src/org/modelica/mdt/builder/SyntaxChecker.java @ 174

Last change on this file since 174 was 174, checked in by boris, 19 years ago
  • redone the code for opening modelica elements from projects view
File size: 9.5 KB
Line 
1/*
2 * This file is part of Modelica Development Tooling.
3 *
4 * Copyright (c) 2005, Link�pings universitet, Department of
5 * Computer and Information Science, PELAB
6 *
7 * All rights reserved.
8 *
9 * (The new BSD license, see also
10 * http://www.opensource.org/licenses/bsd-license.php)
11 *
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are
15 * met:
16 *
17 * * Redistributions of source code must retain the above copyright
18 *   notice, this list of conditions and the following disclaimer.
19 *
20 * * Redistributions in binary form must reproduce the above copyright
21 *   notice, this list of conditions and the following disclaimer in
22 *   the documentation and/or other materials provided with the
23 *   distribution.
24 *
25 * * Neither the name of Link�pings universitet nor the names of its
26 *   contributors may be used to endorse or promote products derived from
27 *   this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41
42package org.modelica.mdt.builder;
43
44import java.io.BufferedInputStream;
45import java.io.File;
46import java.io.FileInputStream;
47import java.io.FileNotFoundException;
48import java.io.IOException;
49import java.io.InputStream;
50import java.util.ArrayList;
51import java.util.Arrays;
52import java.util.List;
53import java.util.Map;
54
55import org.eclipse.core.resources.ICommand;
56import org.eclipse.core.resources.IFile;
57import org.eclipse.core.resources.IMarker;
58import org.eclipse.core.resources.IProject;
59import org.eclipse.core.resources.IProjectDescription;
60import org.eclipse.core.resources.IResourceDelta;
61import org.eclipse.core.resources.IncrementalProjectBuilder;
62import org.eclipse.core.runtime.CoreException;
63import org.eclipse.core.runtime.IProgressMonitor;
64import org.eclipse.jface.text.BadLocationException;
65import org.eclipse.jface.text.Document;
66import org.eclipse.jface.text.IRegion;
67import org.eclipse.jface.text.Region;
68import org.modelica.mdt.MdtPlugin;
69import org.modelica.mdt.internal.omcproxy.CompileError;
70import org.modelica.mdt.internal.omcproxy.ConnectionException;
71import org.modelica.mdt.internal.omcproxy.OMCProxy;
72import org.modelica.mdt.internal.omcproxy.ParseResults;
73import org.modelica.mdt.internal.omcproxy.UnexpectedReplyException;
74
75/**
76 * This builder loads all changed files into OMC in order to check for
77 * parse errors. If a loaded file have any parse error, then a problem
78 * markers are set to communicate the problem to the user.
79 *
80 * @author Andreas Remar
81 */
82public class SyntaxChecker extends IncrementalProjectBuilder
83{
84
85    public static final String BUILDER_ID = "org.modelica.mdt.syntaxChecker";
86
87    @Override
88    protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
89            throws CoreException
90    {
91
92        switch(kind)
93        {
94        case IncrementalProjectBuilder.FULL_BUILD:
95            fullBuild(monitor);
96            break;
97       
98        default:
99            IResourceDelta delta = getDelta(getProject());
100            if(delta == null)
101            {
102                fullBuild(monitor);
103            }
104            else
105            {
106                incrementalBuild(delta, monitor);
107            }
108            break;
109        }
110
111        return null;
112    }
113   
114    protected void fullBuild(final IProgressMonitor monitor)
115    {
116        try
117        {
118            getProject().accept(new FullBuildVisitor());
119        }
120        catch(CoreException e)
121        {
122            // TODO Some other error handling?
123            e.printStackTrace();
124        }
125    }
126   
127    protected void incrementalBuild(IResourceDelta delta,
128            IProgressMonitor monitor)
129    {
130        try
131        {
132            delta.accept(new PartialBuildVisitor());
133        }
134        catch(CoreException e)
135        {
136            // TODO Proper error handling, someone?
137            e.printStackTrace();
138        }
139    }
140   
141    public static void addBuilderToProject(IProject project)
142    {
143        if(!project.isOpen())
144        {
145            return;
146        }
147       
148        IProjectDescription description;
149        try
150        {
151            description = project.getDescription();
152        }
153        catch(CoreException e)
154        {
155            MdtPlugin.log(e);
156            return;
157        }
158       
159        /*
160         * Check if builder is already associated with this
161         * project.
162         */
163        ICommand[] cmds = description.getBuildSpec();
164        for(ICommand cmd : cmds)
165        {
166            if(cmd.getBuilderName().equals(BUILDER_ID))
167            {
168                return;
169            }
170        }
171       
172        /*
173         * Associate builder with project.
174         */
175        ICommand newCmd = description.newCommand();
176        newCmd.setBuilderName(BUILDER_ID);
177        List<ICommand> newCmds = new ArrayList<ICommand>();
178        newCmds.addAll(Arrays.asList(cmds));
179        newCmds.add(newCmd);
180        description.setBuildSpec(
181                (ICommand[])newCmds.toArray(
182                        new ICommand[newCmds.size()]));
183        try
184        {
185            project.setDescription(description, null);
186        }
187        catch(CoreException e)
188        {
189            MdtPlugin.log(e);
190        }
191    }
192   
193    public static void removeBuilderFromProject(IProject project)
194    {
195        if(!project.isOpen())
196        {
197            return;
198        }
199       
200        IProjectDescription description;
201        try
202        {
203            description = project.getDescription();
204        }
205        catch(CoreException e)
206        {
207            MdtPlugin.log(e);
208            return;
209        }
210       
211        int index = -1;
212        ICommand[] cmds = description.getBuildSpec();
213        for(int j = 0;j < cmds.length;j++)
214        {
215            if(cmds[j].getBuilderName().equals(BUILDER_ID))
216            {
217                index = j;
218                break;
219            }
220        }
221       
222        if(index == -1)
223        {
224            return;
225        }
226       
227        List<ICommand> newCmds = new ArrayList<ICommand>();
228        newCmds.addAll(Arrays.asList(cmds));
229        newCmds.remove(index);
230        description.setBuildSpec(
231                (ICommand[])newCmds.toArray(new ICommand[newCmds.size()]));
232        try
233        {
234            project.setDescription(description, null);
235        }
236        catch(CoreException e)
237        {
238            MdtPlugin.log(e);
239        }
240    }
241   
242    protected static void reportProblem(IFile file, int lineno, String msg)
243    {
244        createMarkerAtLine(file, lineno, msg, IMarker.PROBLEM);
245    }
246
247    /**
248     * Calculate where the particular line begins and how long it stretches.
249     * 
250     * @param filePath the full path to the file where to look for lines
251     * @param lineno line number to find
252     * @return region which line occupies or null if the does not
253     * have such a line number
254     * @throws CoreException if there were errors reading file contents
255     * @throws FileNotFoundException if the filePath does not exists
256     */
257   
258    public static IRegion getLineRegion(String filePath, int lineno)
259        throws CoreException, FileNotFoundException
260    {
261        // TODO this probably should be moved into ModelicaFile class,
262        // however that would require that IFile -> IModelicaFile mapping
263        // is implemented. such a mupping is probably needed anyway to
264        // know which other files that should be loaded into OMC and checked
265        // for errors. that is all dependant files, e.g. if file A defines foo
266        // and file B imports foo both A and B should be reshecked for errors
267        // when A is modified (saved), right now only A is checked. end of rant.
268
269        /*
270         * To find out where the line is in the file, we have to read it
271         * in to a Document and then use getLineOffset to convert from a
272         * line number to a character positions.
273         */
274
275        return getLineRegion(new FileInputStream(new File(filePath)), lineno);
276
277    }
278   
279    public static IRegion getLineRegion(IFile file, int lineno) 
280        throws CoreException
281    {
282        return getLineRegion(file.getContents(), lineno);
283    }
284
285   
286    private static IRegion getLineRegion(InputStream fileContents, int lineno)
287    {
288        BufferedInputStream bis = new BufferedInputStream(fileContents);
289        String contents = "";
290        while(true)
291        {
292            try
293            {
294                int avail = bis.available();
295                if(avail == 0)
296                    break;
297                byte[] buf = new byte[avail];
298                bis.read(buf, 0, avail);
299
300                contents += new String(buf);
301            }
302            catch(IOException e)
303            {
304                e.printStackTrace();
305            }
306        }
307
308        Document d = new Document(contents);
309        try
310        {
311            return new Region(d.getLineOffset(lineno - 1), 
312                    d.getLineLength(lineno - 1));
313        }
314        catch(BadLocationException e)
315        {
316            MdtPlugin.log(e);
317        }
318       
319        return null;
320    }
321
322    public static IMarker createMarkerAtLine(IFile file, int lineno,
323            String message, String type)
324    {
325        IMarker marker = null;
326        try
327        {
328            IRegion lineReg = getLineRegion(file, lineno);
329            int start = lineReg.getOffset();
330            int end = start + lineReg.getLength();
331           
332            marker = file.createMarker(type);
333
334            marker.setAttribute(IMarker.CHAR_START, start);
335            marker.setAttribute(IMarker.CHAR_END, end);
336            marker.setAttribute(IMarker.MESSAGE, message);
337            marker.setAttribute(IMarker.LINE_NUMBER, lineno);
338            marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
339            marker.setAttribute(IMarker.LOCATION, Integer.toString(lineno));
340           
341            marker.setAttribute(IMarker.CHAR_START, start);
342            marker.setAttribute(IMarker.CHAR_END, end);
343        }
344        catch(CoreException e)
345        {
346            MdtPlugin.log(e);
347        }
348        return marker;
349    }
350       
351    protected void startupOnInitialization()
352    {
353        // TODO Add builder init here
354    }
355   
356    protected void clean(IProgressMonitor monitor)
357    {
358        // TODO Add builder clean logic here
359    }
360
361    protected static void loadFileAndReportErrors(IFile file)
362        throws ConnectionException, UnexpectedReplyException
363    {
364        ParseResults res = OMCProxy.loadFileInteractive(file);
365
366        for (CompileError error : res.getCompileErrors())
367        {
368            reportProblem(file, error.getLine(), error.getErrorDescription());
369        }
370    }
371}
Note: See TracBrowser for help on using the repository browser.