3737import java .io .InputStream ;
3838import java .util .ArrayList ;
3939import java .util .Arrays ;
40+ import java .util .EnumSet ;
4041import java .util .List ;
42+ import java .util .stream .IntStream ;
4143
4244import static org .jruby .api .Convert .asSymbol ;
4345import static org .jruby .lexer .LexingCommon .DOLLAR_UNDERSCORE ;
@@ -57,7 +59,7 @@ public ParserPrismBase(Ruby runtime) {
5759 public ParseResult parse (String fileName , int lineNumber , ByteList content , DynamicScope existingScope , ParserType type ) {
5860 int sourceLength = content .realSize ();
5961 byte [] source = content .begin () == 0 ? content .unsafeBytes () : content .bytes ();
60- byte [] metadata = generateMetadata (fileName , lineNumber , content .getEncoding (), existingScope , type );
62+ byte [] metadata = generateMetadata (fileName , lineNumber , content .getEncoding (), existingScope );
6163 byte [] serialized = parse (source , sourceLength , metadata );
6264 return parseInternal (fileName , existingScope , source , serialized , type );
6365 }
@@ -152,7 +154,7 @@ private void populateScriptData(byte[] source, Encoding encoding, RubyArray line
152154 protected ParseResult parse (String fileName , int lineNumber , InputStream in , Encoding encoding ,
153155 DynamicScope existingScope , ParserType type ) {
154156 byte [] source = getSourceAsBytes (fileName , in );
155- byte [] metadata = generateMetadata (fileName , lineNumber , encoding , existingScope , type );
157+ byte [] metadata = generateMetadata (fileName , lineNumber , encoding , existingScope );
156158 byte [] serialized = parse (source , source .length , metadata );
157159 return parseInternal (fileName , existingScope , source , serialized , type );
158160 }
@@ -179,61 +181,57 @@ private byte[] loadFully(String fileName, InputStream in) {
179181 }
180182
181183 // lineNumber (0-indexed)
182- private byte [] generateMetadata (String fileName , int lineNumber , Encoding encoding , DynamicScope scope , ParserType type ) {
183- ByteList metadata = new ByteList ();
184-
185- // Filepath
186- byte [] name = fileName .getBytes ();
187- appendUnsignedInt (metadata , name .length );
188- metadata .append (name );
189-
190- // FIXME: I believe line number can be negative?
191- // Line Number (1-indexed)
192- appendUnsignedInt (metadata , lineNumber + 1 );
193-
194- // Encoding
195- name = encoding .getName ();
196- appendUnsignedInt (metadata , name .length );
197- metadata .append (name );
198-
199- // frozen string literal
200- Boolean frozen = runtime .getInstanceConfig ().isFrozenStringLiteral ();
201- metadata .append (frozen != null && frozen ? 1 : 0 );
202-
203- // command-line flags
204- RubyInstanceConfig config = runtime .getInstanceConfig ();
205- byte flags = 0 ;
206- if (config .isSplit ()) flags |= 1 ; // -a
207- if (config .isInlineScript ()) flags |= 2 ; // -e
208- if (config .isProcessLineEnds ()) flags |= 4 ; // -l
209- //if (config.isAssumeLoop()) flags |= 8; // -n
210- //if (config.isAssumePrinting()) flags |= 16; // -p
211- if (config .isXFlag ()) flags |= 32 ; // -x
212- metadata .append (flags );
213-
214- // version
215- metadata .append (ParsingOptions .SyntaxVersion .V4_0 .getValue ());
216-
217- // Do not lock encoding
218- metadata .append (0 );
219-
220- // main script
221- metadata .append (1 );
222-
223- // partial script
224- metadata .append (0 );
225-
226- // freeze
227- metadata .append (0 );
228-
229- // Eval scopes (or none for normal parses)
230- if (type == EVAL ) {
231- encodeEvalScopes (metadata , scope .getStaticScope ());
232- } else {
233- appendUnsignedInt (metadata , 0 );
184+ private byte [] generateMetadata (String fileName , int lineNumber , Encoding encoding , DynamicScope scope ) {
185+ return ParsingOptions .serialize (
186+ fileName .getBytes (),
187+ lineNumber + 1 ,
188+ encoding .getName (),
189+ (runtime .getInstanceConfig ().isFrozenStringLiteral () instanceof Boolean bool && bool ),
190+ commandLineFromConfig (runtime .getInstanceConfig ()),
191+ ParsingOptions .SyntaxVersion .V4_0 ,
192+ false ,
193+ true ,
194+ false ,
195+ evalScopes (scope ));
196+ }
197+
198+ private ParsingOptions .Scope [] evalScopes (DynamicScope scope ) {
199+ if (scope == null ) return new ParsingOptions .Scope [0 ];
200+
201+ var scopes = new ArrayList <ParsingOptions .Scope >();
202+
203+ evalScopesRecursive (scope .getStaticScope (), scopes );
204+
205+ return scopes .toArray (ParsingOptions .Scope []::new );
206+ }
207+
208+ private void evalScopesRecursive (StaticScope scope , ArrayList <ParsingOptions .Scope > scopes ) {
209+ if (scope .getEnclosingScope () != null && scope .isBlockScope ()) {
210+ evalScopesRecursive (scope .getEnclosingScope (), scopes );
234211 }
235212
236- return metadata .bytes (); // FIXME: extra arraycopy
213+ scopes .add (new ParsingOptions .Scope (
214+ Arrays
215+ .stream (scope .getVariables ())
216+ .map (String ::getBytes )
217+ .toArray (byte [][]::new ),
218+ IntStream
219+ .range (0 , scope .getVariables ().length )
220+ .mapToObj ((i ) -> ParsingOptions .Forwarding .NONE )
221+ .toArray (ParsingOptions .Forwarding []::new )));
222+ }
223+
224+ private EnumSet <ParsingOptions .CommandLine > commandLineFromConfig (RubyInstanceConfig config ) {
225+ var list = new ArrayList <ParsingOptions .CommandLine >();
226+
227+ if (config .isSplit ()) list .add (ParsingOptions .CommandLine .A ); // -a
228+ if (config .isInlineScript ()) list .add (ParsingOptions .CommandLine .E ); // -e
229+ if (config .isProcessLineEnds ()) list .add (ParsingOptions .CommandLine .L ); // -l
230+ if (config .isAssumeLoop ()) list .add (ParsingOptions .CommandLine .N ); // -n
231+ if (config .isAssumePrinting ()) list .add (ParsingOptions .CommandLine .P ); // -p
232+ if (config .isXFlag ()) list .add (ParsingOptions .CommandLine .X ); // -x
233+
234+ return EnumSet .copyOf (list );
237235 }
238236
239237 private void writeUnsignedInt (ByteList buf , int index , int value ) {
0 commit comments