11// Copyright © 2023, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
22// SPDX-License-Identifier: Apache-2.0
33import { Lexer , Token as RealToken } from "../Lexer" ;
4- import type { FoldingBlock } from "../LexerEx" ;
4+ import { type FoldingBlock , LexerEx } from "../LexerEx" ;
55import type { Model } from "../Model" ;
66import type { SyntaxProvider } from "../SyntaxProvider" ;
7+ import { isSamePosition } from "../utils" ;
78
89interface FakeToken extends Omit < RealToken , "type" > {
910 type : "raw-data" ;
@@ -33,6 +34,11 @@ export type SASAST = Program | Region | Statement | Token;
3334export const isComment = ( token : Token ) =>
3435 token . type === "comment" || token . type === "macro-comment" ;
3536
37+ const isAtBlockEnd = ( block : FoldingBlock | undefined , token : Token ) =>
38+ block &&
39+ block . endLine === token . end . line &&
40+ block . endCol === token . end . column ;
41+
3642const removePrevStatement = ( parent : Program | Region ) => {
3743 if ( parent . children . length <= 1 ) {
3844 return ;
@@ -167,6 +173,58 @@ const preserveProcs = (
167173 return current ;
168174} ;
169175
176+ const preserveCustomRegion = (
177+ current : number ,
178+ statement : Statement ,
179+ model : Model ,
180+ syntaxProvider : SyntaxProvider ,
181+ ) => {
182+ const token = statement . children [ statement . children . length - 1 ] ;
183+ if ( current === - 1 ) {
184+ if ( isComment ( token ) && / \* \s * r e g i o n \s + f o r m a t - i g n o r e \b / . test ( token . text ) ) {
185+ const block = syntaxProvider . getFoldingBlock (
186+ token . start . line ,
187+ token . start . column ,
188+ true ,
189+ false ,
190+ true ,
191+ ) ;
192+ if (
193+ block &&
194+ block . type === LexerEx . SEC_TYPE . CUSTOM &&
195+ block . startLine === token . start . line &&
196+ block . startCol === token . start . column
197+ ) {
198+ current = 0 ;
199+ const start = token . start ;
200+ const end = { line : block . endLine , column : block . endCol } ;
201+ statement . children . pop ( ) ;
202+ statement . children . push ( {
203+ type : "raw-data" ,
204+ text : model . getText ( { start, end } ) ,
205+ start,
206+ end,
207+ } ) ;
208+ }
209+ }
210+ } else if ( current === 0 ) {
211+ statement . children . pop ( ) ;
212+ if (
213+ statement &&
214+ statement . children . length > 0 &&
215+ isSamePosition (
216+ token . end ,
217+ statement . children [ statement . children . length - 1 ] . end ,
218+ )
219+ ) {
220+ current = 1 ;
221+ }
222+ } else if ( current === 1 ) {
223+ return - 1 ;
224+ }
225+ return current ;
226+ } ;
227+
170228const preserveQuoting = (
171229 current : number ,
172230 statement : Statement ,
@@ -222,11 +280,13 @@ export const getParser =
222280 let prevStatement : Statement | undefined = undefined ;
223281 let quoting = - 1 ;
224282 let preserveProc = - 1 ;
283+ let preserveCustom = - 1 ;
225284
226285 for ( let i = 0 ; i < tokens . length ; i ++ ) {
227286 const node = tokens [ i ] ;
228287 let parent = parents . length ? parents [ parents . length - 1 ] : root ;
229288
289+ //#region --- Preserve Python/Lua
230290 if ( region && region . block ) {
231291 preserveProc = preserveProcs ( preserveProc , region , node , model ) ;
232292 if ( preserveProc === 0 && i === tokens . length - 1 ) {
@@ -245,8 +305,9 @@ export const getParser =
245305 if ( node . type === "embedded-code" ) {
246306 continue ;
247307 }
308+ //#endregion ---
248309
249- // --- Check for block start: DATA, PROC, %MACRO ---
310+ //#region --- Check for block start: DATA, PROC, %MACRO
250311 if ( node . type === "sec-keyword" || node . type === "macro-sec-keyword" ) {
251312 const block = syntaxProvider . getFoldingBlock (
252313 node . start . line ,
@@ -276,9 +337,9 @@ export const getParser =
276337 }
277338 }
278339 }
279- // --- ---
340+ //#endregion ---
280341
281- // --- Check for statement start ---
342+ //#region --- Check for statement start
282343 if ( ! currentStatement ) {
283344 currentStatement = {
284345 type : "statement" ,
@@ -301,16 +362,30 @@ export const getParser =
301362 parent . children . push ( currentStatement ) ;
302363 }
303364 }
304- // --- ---
365+ //#endregion ---
305366
306367 currentStatement . children . push ( node ) ;
307368
369+ preserveCustom = preserveCustomRegion (
370+ preserveCustom ,
371+ currentStatement ,
372+ model ,
373+ syntaxProvider ,
374+ ) ;
375+ if ( preserveCustom >= 0 ) {
376+ if ( preserveCustom === 1 ) {
377+ prevStatement = currentStatement ;
378+ currentStatement = undefined ;
379+ }
380+ continue ;
381+ }
382+
308383 quoting = preserveQuoting ( quoting , currentStatement , model ) ;
309384 if ( quoting >= 0 ) {
310385 continue ;
311386 }
312387
313- // --- Check for statement end ---
388+ //#region --- Check for statement end
314389 if ( node . type === "sep" && node . text === ";" ) {
315390 if (
316391 currentStatement . children [ 0 ] . type === "cards-data" &&
@@ -353,12 +428,7 @@ export const getParser =
353428 // put `end` out of region children to outdent
354429 parent . children . push ( region . children . pop ( ) ! ) ;
355430 region = parents . pop ( ) ;
356- } else if (
357- region &&
358- region . block &&
359- region . block . endLine === node . end . line &&
360- region . block . endCol === node . end . column
361- ) {
431+ } else if ( region && isAtBlockEnd ( region . block , node ) ) {
362432 // block end
363433 if ( / ^ ( r u n | q u i t | % m e n d ) \b / i. test ( currentStatement . children [ 0 ] . text ) ) {
364434 // put `run` out of section children to outdent
@@ -389,12 +459,7 @@ export const getParser =
389459 // standalone comment, treat as a whole statement
390460 prevStatement = currentStatement ;
391461 currentStatement = undefined ;
392- if (
393- region &&
394- region . block &&
395- region . block . endLine === node . end . line &&
396- region . block . endCol === node . end . column
397- ) {
462+ if ( isAtBlockEnd ( region ?. block , node ) ) {
398463 region = parents . pop ( ) ;
399464 }
400465 } else if (
@@ -411,7 +476,7 @@ export const getParser =
411476 prevStatement = currentStatement ;
412477 currentStatement = undefined ;
413478 }
414- // --- ---
479+ //#endregion ---
415480 }
416481
417482 return root ;
0 commit comments