src/eric7/Plugins/CheckerPlugins/SyntaxChecker/jsCheckSyntax.py

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

eric ide

mercurial