1+ import { VersionExpressionSets as SlangVersionExpressionSets } from '@nomicfoundation/slang/ast' ;
12import { NonterminalKind , Query } from '@nomicfoundation/slang/cst' ;
23import { Parser } from '@nomicfoundation/slang/parser' ;
3- import strip from 'strip-comments ' ;
4+ import prettier from 'prettier ' ;
45import {
56 maxSatisfying ,
67 minSatisfying ,
@@ -9,6 +10,12 @@ import {
910 satisfies ,
1011 validRange
1112} from 'semver' ;
13+ import slangPrint from '../slangPrinter.js' ;
14+ import { locEnd , locStart } from './loc.js' ;
15+ import { VersionExpressionSets } from '../slang-nodes/VersionExpressionSets.js' ;
16+
17+ import type { NonterminalNode } from '@nomicfoundation/slang/cst' ;
18+ import type { Parser as PrettierParser } from 'prettier' ;
1219
1320const supportedVersions = Parser . supportedVersions ( ) ;
1421
@@ -25,15 +32,48 @@ const milestoneVersions = Array.from(
2532 return versions ;
2633 } , [ ] ) ;
2734
35+ const bypassParse =
36+ ( parseOutput : NonterminalNode ) => ( ) : VersionExpressionSets => {
37+ // We don't need to parse the text twice if we already have the
38+ // NonterminalNode.
39+ const parsed = new VersionExpressionSets (
40+ new SlangVersionExpressionSets ( parseOutput ) ,
41+ 0
42+ ) ;
43+ parsed . comments = [ ] ;
44+ return parsed ;
45+ } ;
46+
47+ const options = {
48+ plugins : [
49+ {
50+ languages : [ { name : 'SolidityPragma' , parsers : [ 'slangPragma' ] } ] ,
51+ parsers : {
52+ slangPragma : {
53+ astFormat : 'slang-ast' ,
54+ locStart,
55+ locEnd
56+ } as PrettierParser
57+ } ,
58+ printers : { [ 'slang-ast' ] : { print : slangPrint } }
59+ }
60+ ] ,
61+ parser : 'slangPragma'
62+ } ;
63+
64+ const query = Query . parse (
65+ '[VersionPragma @versionRanges [VersionExpressionSets]]'
66+ ) ;
67+
2868// TODO if we ended up selecting the same version that the pragmas were parsed with,
2969// should we be able to reuse/just return the already parsed CST, instead of
3070// returning a Parser and forcing user to parse it again?
31- export function createParser ( text : string ) : Parser {
71+ export async function createParser ( text : string ) : Promise < Parser > {
3272 let inferredRanges : string [ ] = [ ] ;
3373
3474 for ( const version of milestoneVersions ) {
3575 try {
36- inferredRanges = tryToCollectPragmas ( text , version ) ;
76+ inferredRanges = await tryToCollectPragmas ( text , version ) ;
3777 break ;
3878 } catch { }
3979 }
@@ -57,22 +97,22 @@ export function createParser(text: string): Parser {
5797 : Parser . create ( supportedVersions [ supportedVersions . length - 1 ] ) ;
5898}
5999
60- function tryToCollectPragmas ( text : string , version : string ) : string [ ] {
61- const language = Parser . create ( version ) ;
62- const parseOutput = language . parse ( NonterminalKind . SourceUnit , text ) ;
63- const query = Query . parse (
64- '[VersionPragma @versionRanges [VersionExpressionSets]]'
65- ) ;
100+ async function tryToCollectPragmas (
101+ text : string ,
102+ version : string
103+ ) : Promise < string [ ] > {
104+ const parser = Parser . create ( version ) ;
105+ const parseOutput = parser . parse ( NonterminalKind . SourceUnit , text ) ;
106+
66107 const matches = parseOutput . createTreeCursor ( ) . query ( [ query ] ) ;
67108 const ranges : string [ ] = [ ] ;
68109
69110 let match ;
70111 while ( ( match = matches . next ( ) ) ) {
71- ranges . push (
72- strip ( match . captures . versionRanges [ 0 ] . node . unparse ( ) , {
73- keepProtected : true
74- } )
112+ options . plugins [ 0 ] . parsers . slangPragma . parse = bypassParse (
113+ match . captures . versionRanges [ 0 ] . node . asNonterminalNode ( ) !
75114 ) ;
115+ ranges . push ( await prettier . format ( text , options ) ) ;
76116 }
77117
78118 if ( ranges . length === 0 ) {
0 commit comments