eric6/Plugins/CheckerPlugins/SyntaxChecker/jsCheckSyntax.py

changeset 6942
2602857055c5
parent 6650
1dd52aa8897c
child 7192
a22eee00b052
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2014 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5 # pylint: disable=C0103
6
7 """
8 Module implementing the syntax check for Python 2/3.
9 """
10
11 from __future__ import unicode_literals
12
13 try: # Only for Py2
14 import Queue as queue
15 except ImportError:
16 import queue
17
18 import os
19 import sys
20 import multiprocessing
21
22
23 def initService():
24 """
25 Initialize the service and return the entry point.
26
27 @return the entry point for the background client (function)
28 """
29 path = __file__
30 for _ in range(4):
31 path = os.path.dirname(path)
32 sys.path.insert(2, os.path.join(path, "ThirdParty", "Jasy"))
33 return jsSyntaxCheck
34
35
36 def initBatchService():
37 """
38 Initialize the batch service and return the entry point.
39
40 @return the entry point for the background client (function)
41 """
42 return jsSyntaxBatchCheck
43
44
45 def normalizeCode(codestring):
46 """
47 Function to normalize the given code.
48
49 @param codestring code to be normalized (string)
50 @return normalized code (string)
51 """
52 codestring = codestring.replace("\r\n", "\n").replace("\r", "\n")
53
54 if codestring and codestring[-1] != '\n':
55 codestring = codestring + '\n'
56
57 # Check type for py2: if not str it's unicode
58 # if sys.version_info[0] == 2:
59 # try:
60 # codestring = codestring.encode('utf-8')
61 # except UnicodeError:
62 # pass
63
64 return codestring
65
66
67 def jsSyntaxCheck(file, codestring):
68 """
69 Function to check a Javascript source file for syntax errors.
70
71 @param file source filename (string)
72 @param codestring string containing the code to check (string)
73 @return dictionary with the keys 'error' and 'warnings' which
74 hold a list containing details about the error/ warnings
75 (file name, line number, column, codestring (only at syntax
76 errors), the message, a list with arguments for the message)
77 """
78 return __jsSyntaxCheck(file, codestring)
79
80
81 def jsSyntaxBatchCheck(argumentsList, send, fx, cancelled, maxProcesses=0):
82 """
83 Module function to check syntax for a batch of files.
84
85 @param argumentsList list of arguments tuples as given for jsSyntaxCheck
86 @type list
87 @param send reference to send function
88 @type func
89 @param fx registered service name
90 @type str
91 @param cancelled reference to function checking for a cancellation
92 @type func
93 @param maxProcesses number of processes to be used
94 @type int
95 """
96 if maxProcesses == 0:
97 # determine based on CPU count
98 try:
99 NumberOfProcesses = multiprocessing.cpu_count()
100 if NumberOfProcesses >= 1:
101 NumberOfProcesses -= 1
102 except NotImplementedError:
103 NumberOfProcesses = 1
104 else:
105 NumberOfProcesses = maxProcesses
106
107 # Create queues
108 taskQueue = multiprocessing.Queue()
109 doneQueue = multiprocessing.Queue()
110
111 # Submit tasks (initially two time number of processes
112 initialTasks = 2 * NumberOfProcesses
113 for task in argumentsList[:initialTasks]:
114 taskQueue.put(task)
115
116 # Start worker processes
117 for _ in range(NumberOfProcesses):
118 multiprocessing.Process(target=worker, args=(taskQueue, doneQueue))\
119 .start()
120
121 # Get and send results
122 endIndex = len(argumentsList) - initialTasks
123 for i in range(len(argumentsList)):
124 resultSent = False
125 wasCancelled = False
126
127 while not resultSent:
128 try:
129 # get result (waiting max. 3 seconds and send it to frontend
130 filename, result = doneQueue.get()
131 send(fx, filename, result)
132 resultSent = True
133 except queue.Empty:
134 # ignore empty queue, just carry on
135 if cancelled():
136 wasCancelled = True
137 break
138
139 if wasCancelled or cancelled():
140 # just exit the loop ignoring the results of queued tasks
141 break
142
143 if i < endIndex:
144 taskQueue.put(argumentsList[i + initialTasks])
145
146 # Tell child processes to stop
147 for _ in range(NumberOfProcesses):
148 taskQueue.put('STOP')
149
150
151 def worker(inputQueue, outputQueue):
152 """
153 Module function acting as the parallel worker for the style check.
154
155 @param inputQueue input queue (multiprocessing.Queue)
156 @param outputQueue output queue (multiprocessing.Queue)
157 """
158 for filename, args in iter(inputQueue.get, 'STOP'):
159 source = args[0]
160 result = __jsSyntaxCheck(filename, source)
161 outputQueue.put((filename, result))
162
163
164 def __jsSyntaxCheck(file, codestring):
165 """
166 Function to check a Javascript source file for syntax errors.
167
168 @param file source filename (string)
169 @param codestring string containing the code to check (string)
170 @return dictionary with the keys 'error' and 'warnings' which
171 hold a list containing details about the error/ warnings
172 (file name, line number, column, codestring (only at syntax
173 errors), the message, a list with arguments for the message)
174 """
175 import jasy.script.parse.Parser as jsParser
176 import jasy.script.tokenize.Tokenizer as jsTokenizer
177
178 codestring = normalizeCode(codestring)
179
180 try:
181 jsParser.parse(codestring, file)
182 except (jsParser.SyntaxError, jsTokenizer.ParseError) as exc:
183 details = exc.args[0]
184 error, details = details.splitlines()
185 fn, line = details.strip().rsplit(":", 1)
186 error = error.split(":", 1)[1].strip()
187
188 cline = min(len(codestring.splitlines()), int(line)) - 1
189 code = codestring.splitlines()[cline]
190 return [{'error': (fn, int(line), 0, code, error)}]
191 except IndexError:
192 error = "Incomplete source file"
193 splittedCode = codestring.splitlines()
194 return [{'error': (file, len(splittedCode) + 1, len(splittedCode[-1]),
195 splittedCode[-1], error)}]
196
197 return [{}]

eric ide

mercurial