@@ -3,39 +3,99 @@ import {GbnfGrammarGenerator} from "../GbnfGrammarGenerator.js";
33import { GbnfJsonScopeState } from "../utils/GbnfJsonScopeState.js" ;
44import { GbnfWhitespace } from "./GbnfWhitespace.js" ;
55import { GbnfGrammar } from "./GbnfGrammar.js" ;
6- import { GbnfOr } from "./GbnfOr.js" ;
6+ import { GbnfRepetition } from "./GbnfRepetition.js" ;
7+ import { GbnfCommaWhitespace } from "./GbnfCommaWhitespace.js" ;
8+ import { GbnfAnyJson } from "./GbnfAnyJson.js" ;
79
810
911export class GbnfArray extends GbnfTerminal {
10- public readonly items : GbnfTerminal ;
12+ public readonly items ?: GbnfTerminal ;
13+ public readonly prefixItems ?: GbnfTerminal [ ] ;
14+ public readonly minItems : number ;
15+ public readonly maxItems ?: number ;
1116 public readonly scopeState : GbnfJsonScopeState ;
1217
13- public constructor ( items : GbnfTerminal , scopeState : GbnfJsonScopeState = new GbnfJsonScopeState ( ) ) {
18+ public constructor ( {
19+ items, prefixItems, minItems = 0 , maxItems,
20+ scopeState = new GbnfJsonScopeState ( )
21+ } : {
22+ items ?: GbnfTerminal , prefixItems ?: GbnfTerminal [ ] , minItems ?: number , maxItems ?: number ,
23+ scopeState : GbnfJsonScopeState
24+ } ) {
1425 super ( ) ;
1526
1627 this . items = items ;
28+ this . prefixItems = prefixItems ;
29+ this . minItems = Math . floor ( minItems ) ;
30+ this . maxItems = maxItems == null ? undefined : Math . floor ( maxItems ) ;
1731 this . scopeState = scopeState ;
32+
33+ if ( this . prefixItems != null && this . minItems < this . prefixItems . length )
34+ this . minItems = this . prefixItems . length ;
35+ else if ( this . minItems < 0 )
36+ this . minItems = 0 ;
37+
38+ if ( this . maxItems != null && this . maxItems < this . minItems )
39+ this . maxItems = this . minItems ;
40+ else if ( this . maxItems != null && this . maxItems < 0 )
41+ this . maxItems = 0 ;
1842 }
1943
2044 public getGrammar ( grammarGenerator : GbnfGrammarGenerator ) : string {
45+ const getWhitespaceRule = ( newScope : boolean , newLine : "before" | "after" | false ) => (
46+ newScope
47+ ? new GbnfWhitespace ( this . scopeState . getForNewScope ( ) , { newLine} )
48+ : new GbnfWhitespace ( this . scopeState , { newLine} )
49+ ) ;
2150 const getWhitespaceRuleName = ( newScope : boolean , newLine : "before" | "after" | false ) => (
51+ getWhitespaceRule ( newScope , newLine ) . resolve ( grammarGenerator )
52+ ) ;
53+
54+ const getCommaWhitespaceRule = ( newScope : boolean , newLine : "before" | "after" | false ) => (
2255 newScope
23- ? new GbnfWhitespace ( this . scopeState . getForNewScope ( ) , { newLine} ) . resolve ( grammarGenerator )
24- : new GbnfWhitespace ( this . scopeState , { newLine} ) . resolve ( grammarGenerator )
56+ ? new GbnfCommaWhitespace ( this . scopeState . getForNewScope ( ) , { newLine} )
57+ : new GbnfCommaWhitespace ( this . scopeState , { newLine} )
58+ ) ;
59+ const getCommaWhitespaceRuleName = ( newScope : boolean , newLine : "before" | "after" | false ) => (
60+ getCommaWhitespaceRule ( newScope , newLine ) . resolve ( grammarGenerator )
2561 ) ;
26- const itemsGrammarRuleName = this . items . resolve ( grammarGenerator ) ;
62+
63+ const arrayItemsGrammar : string [ ] = [ ] ;
64+ if ( this . prefixItems != null && this . prefixItems . length > 0 ) {
65+ for ( const item of this . prefixItems ) {
66+ if ( arrayItemsGrammar . length > 0 ) {
67+ arrayItemsGrammar . push ( getCommaWhitespaceRuleName ( true , "before" ) ) ;
68+ }
69+
70+ arrayItemsGrammar . push ( item . resolve ( grammarGenerator ) ) ;
71+ }
72+
73+ if ( this . minItems > this . prefixItems . length || this . maxItems == null || this . maxItems > this . prefixItems . length ) {
74+ arrayItemsGrammar . push ( getCommaWhitespaceRuleName ( true , "before" ) ) ;
75+ arrayItemsGrammar . push (
76+ new GbnfRepetition ( {
77+ value : this . items ?? new GbnfAnyJson ( ) ,
78+ separator : getCommaWhitespaceRule ( true , "before" ) ,
79+ minRepetitions : this . minItems - this . prefixItems . length ,
80+ maxRepetitions : this . maxItems == null
81+ ? undefined
82+ : this . maxItems - this . prefixItems . length
83+ } ) . getGrammar ( grammarGenerator )
84+ ) ;
85+ }
86+ } else
87+ arrayItemsGrammar . push (
88+ new GbnfRepetition ( {
89+ value : this . items ?? new GbnfAnyJson ( ) ,
90+ separator : getCommaWhitespaceRule ( true , "before" ) ,
91+ minRepetitions : this . minItems ,
92+ maxRepetitions : this . maxItems
93+ } ) . getGrammar ( grammarGenerator )
94+ ) ;
2795
2896 return new GbnfGrammar ( [
2997 '"["' , getWhitespaceRuleName ( true , "before" ) ,
30- new GbnfOr ( [
31- new GbnfGrammar ( [
32- "(" , itemsGrammarRuleName , ")" ,
33- "(" , '","' , getWhitespaceRuleName ( true , "before" ) , itemsGrammarRuleName , ")*"
34- ] ) ,
35- new GbnfGrammar ( [
36- "(" , itemsGrammarRuleName , ")?"
37- ] )
38- ] ) . getGrammar ( grammarGenerator ) ,
98+ new GbnfGrammar ( arrayItemsGrammar ) . getGrammar ( ) ,
3999 getWhitespaceRuleName ( false , "before" ) , '"]"'
40100 ] ) . getGrammar ( ) ;
41101 }
0 commit comments