@@ -64,7 +64,7 @@ local type_map = {
6464}
6565
6666function PreProcessor :GetType (tp , trace )
67- tp = tp :Trim ():lower ()
67+ tp = self :Trim (tp ):lower ()
6868 local up = tp :upper ()
6969
7070 if tp == " normal" then
@@ -83,47 +83,110 @@ function PreProcessor:HandlePPCommand(comment, col)
8383 end
8484end
8585
86+ function PreProcessor :Trim (line )
87+ local length = # line
88+ local first
89+
90+ for i = 1 , length do
91+ local b = string.byte (line , i )
92+
93+ if b ~= 32 and (b < 9 or b > 13 ) then
94+ first = i
95+ break
96+ end
97+ end
98+
99+ if not first then
100+ return " "
101+ end
102+
103+ local last
104+
105+ for i = length , 1 , - 1 do
106+ local b = string.byte (line , i )
107+
108+ if b ~= 32 and (b < 9 or b > 13 ) then
109+ last = i
110+ break
111+ end
112+ end
113+
114+ return string.sub (line , first , last )
115+ end
116+
117+ function PreProcessor :TrimRight (line )
118+ for i = # line , 1 , - 1 do
119+ local b = string.byte (line , i )
120+
121+ if b ~= 32 and (b < 9 or b > 13 ) then
122+ return string.sub (line , 1 , i )
123+ end
124+ end
125+
126+ -- The line consists only of spaces
127+ return " "
128+ end
129+
86130function PreProcessor :FindComments (line )
87131 local isinput = not self .blockcomment and not self .multilinestring and line :match (" ^@inputs" ) ~= nil
88132 local isoutput = not self .blockcomment and not self .multilinestring and line :match (" ^@outputs" ) ~= nil
89133
90- local ret , count , pos , found = {}, 0 , 1
91- repeat
92- found = line :find ((isinput or isoutput ) and ' [#"\\ A-Z]' or ' [#"\\ ]' , pos )
93- if found then -- We found something
94- local char = line :sub (found , found )
95- if (isinput or isoutput ) and char :match (" [A-Z]" ) ~= nil then -- we found the start of an input/output variable definition
96- local varname , endpos = line :match (" ^([A-Z][A-Za-z0-9_]*)()" ,found )
97- count = count + 1
98- ret [count ] = {type = isinput and " inputs" or " outputs" , name = varname , pos = found , blockcomment = {}}
99- pos = endpos
100- elseif char == " #" then -- We found a comment
101- local before = line :sub (found - 1 , found - 1 )
102- if before == " ]" then -- We found an ending
103- count = count + 1
104- ret [count ] = { type = " end" , pos = found - 1 }
105- pos = found + 1
134+ local ret , count = {}, 0
135+ local len = # line
136+ local i = 1
137+
138+ while i <= len do
139+ local byte = string.byte (line , i )
140+
141+ -- We found the start of an input/output variable definition
142+ if (isinput or isoutput ) and byte >= 65 and byte <= 90 then
143+ local start = i
144+ i = i + 1
145+
146+ while i <= len do
147+ local b = string.byte (line , i )
148+
149+ if (b >= 65 and b <= 90 ) or (b >= 97 and b <= 122 ) or (b >= 48 and b <= 57 ) or b == 95 then
150+ i = i + 1
106151 else
107- local after = line :sub (found + 1 , found + 1 )
108- if after == " [" then -- We found a start
109- count = count + 1
110- ret [count ] = { type = " start" , pos = found }
111- pos = found + 2
112- else -- We found a normal comment
113- count = count + 1
114- ret [count ] = { type = " normal" , pos = found }
115- pos = found + 1
116- end
152+ break
117153 end
118- elseif char == ' "' then -- We found a string
154+ end
155+
156+ local varname = string.sub (line , start , i - 1 )
157+ count = count + 1
158+ ret [count ] = { type = isinput and " inputs" or " outputs" , name = varname , pos = start , blockcomment = {} }
159+ elseif byte == 92 then -- We found an escape character
160+ i = i + 2 -- Skip the escape character and the character following it
161+ elseif byte == 34 then -- We found a string
162+ count = count + 1
163+ ret [count ] = { type = " string" , pos = i }
164+ i = i + 1
165+ elseif byte == 35 then -- We found a comment
166+ local before = i > 1 and string.byte (line , i - 1 )
167+
168+ if before == 93 then -- We found an ending
119169 count = count + 1
120- ret [count ] = { type = " string" , pos = found }
121- pos = found + 1
122- elseif char == ' \\ ' then -- We found an escape character
123- pos = found + 2 -- Skip the escape character and the character following it
170+ ret [count ] = { type = " end" , pos = i - 1 }
171+ i = i + 1
172+ else
173+ local after = i < len and string.byte (line , i + 1 )
174+
175+ if after == 91 then -- We found a start
176+ count = count + 1
177+ ret [count ] = { type = " start" , pos = i }
178+ i = i + 2
179+ else -- We found a normal comment
180+ count = count + 1
181+ ret [count ] = { type = " normal" , pos = i }
182+ i = i + 1
183+ end
124184 end
185+ else
186+ i = i + 1
125187 end
126- until (not found )
188+ end
189+
127190 return ret , count
128191end
129192
@@ -265,7 +328,7 @@ local directive_handlers = {
265328 [" persist" ] = handleIO (" persist" ),
266329
267330 [" trigger" ] = function (self , value , trace )
268- local trimmed = string .Trim (value )
331+ local trimmed = PreProcessor .Trim (nil , value )
269332 if trimmed == " all" then
270333 if self .directives .trigger [1 ] ~= nil then
271334 self :Error (" Directive (@trigger) conflicts with previous directives" , trace )
@@ -311,7 +374,7 @@ local directive_handlers = {
311374 end
312375
313376 if CLIENT then
314- if # string .Trim (arg ) > 0 then
377+ if # PreProcessor .Trim (nil , arg ) > 0 then
315378 trace .start_col = trace .end_col + 1
316379 trace .end_line = trace .start_line + 1
317380 trace .end_col = 1
@@ -348,7 +411,7 @@ function PreProcessor:ParseDirectives(line)
348411 -- not a directive?
349412 if not directive then
350413 -- flag as "in code", if that is the case
351- if string . Trim (line ) ~= " " then
414+ if self : Trim (line ) ~= " " then
352415 self .incode = true
353416 end
354417 -- don't handle as a directive.
@@ -387,8 +450,6 @@ function PreProcessor:Process(buffer, directives, ent)
387450 self .ifdefStack = {}
388451 self .warnings , self .errors = {}, {}
389452
390- local lines = string .Explode (" \n " , buffer )
391-
392453 if not directives then
393454 self .directives = {
394455 name = nil ,
@@ -403,25 +464,28 @@ function PreProcessor:Process(buffer, directives, ent)
403464 self .ignorestuff = true
404465 end
405466
406- -- to avoid big hangs, 2 regex changed from 500 to 10000 to avoid false positives
407- local regex_limits = {[0 ] = 50000000 , 15000 , 10000 , 150 , 70 , 40 }
408- local timeout = SysTime () + 0.5
467+ local lines
409468
410- for i , line in ipairs (lines ) do
411- self .readline = i
469+ if # buffer > 5000000 then -- 5mb
470+ self :Error (" Code is too big (5mb max)" )
471+ lines = {}
472+ else
473+ -- to avoid big hangs
474+ local timeout = SysTime () + 0.5
475+ lines = string .Explode (" \n " , buffer )
412476
413- local ok = pcall ( function () WireLib . CheckRegex ( line , " ^(.-)%s*$ " , regex_limits ) end )
414- if not ok then self : Error ( " Line strip regex is too complex! " ) goto cont end
477+ for i , line in ipairs ( lines ) do
478+ self . readline = i
415479
416- line = string .TrimRight (line )
417- line = self :RemoveComments (line )
418- line = self :ParseDirectives (line )
419- lines [i ] = line
420- :: cont::
480+ line = self :TrimRight (line )
481+ line = self :RemoveComments (line )
482+ line = self :ParseDirectives (line )
483+ lines [i ] = line
421484
422- if SysTime () > timeout then
423- self :Error (" Preprocessing took too long!" )
424- break
485+ if SysTime () > timeout then
486+ self :Error (" Preprocessing took too long" )
487+ break
488+ end
425489 end
426490 end
427491
@@ -470,7 +534,7 @@ function PreProcessor:ParsePorts(ports, startoffset)
470534 column2 = column + column2
471535 local tr = Trace .new (self .readline , column2 , self .readline , column2 + # var )
472536
473- var = string . Trim (var )
537+ var = self : Trim (var )
474538 -- skip empty entries
475539 if var ~= " " then
476540 -- error on malformed variable names
@@ -615,7 +679,7 @@ function PreProcessor:PP_else(args, trace)
615679 local state = table.remove (self .ifdefStack )
616680 if state == nil then self :Error (" Found #else outside #ifdef/#ifndef block" , trace ) end
617681
618- if args :Trim () ~= " " then self :Error (" Must not pass an argument to #else" , trace ) end
682+ if self :Trim (args ) ~= " " then self :Error (" Must not pass an argument to #else" , trace ) end
619683
620684 if self :Disabled () then
621685 table.insert (self .ifdefStack , false )
@@ -628,7 +692,7 @@ function PreProcessor:PP_endif(args, trace)
628692 local state = table.remove (self .ifdefStack )
629693 if state == nil then self :Error (" Found #endif outside #ifdef/#ifndef block" , trace ) end
630694
631- if args :Trim () ~= " " then self :Error (" Must not pass an argument to #endif" , trace ) end
695+ if self :Trim (args ) ~= " " then self :Error (" Must not pass an argument to #endif" , trace ) end
632696end
633697
634698function PreProcessor :PP_error (args , trace )
0 commit comments