1
1
import { ParseResult , deserialize } from "./deserialize.js" ;
2
+ import os from "os" ;
2
3
3
4
/**
4
5
* Parse the given source code.
5
6
*
6
7
* @param {WebAssembly.Exports } prism
7
8
* @param {string } source
9
+ * @param {Object } options
8
10
* @returns {ParseResult }
9
11
*/
10
- export function parsePrism ( prism , source ) {
12
+ export function parsePrism ( prism , source , options = { } ) {
11
13
const sourceArray = new TextEncoder ( ) . encode ( source ) ;
12
14
const sourcePointer = prism . calloc ( 1 , sourceArray . length ) ;
13
15
16
+ const packedOptions = dumpOptions ( options ) ;
17
+ const optionsPointer = prism . calloc ( 1 , packedOptions . length ) ;
18
+
14
19
const bufferPointer = prism . calloc ( prism . pm_buffer_sizeof ( ) , 1 ) ;
15
20
prism . pm_buffer_init ( bufferPointer ) ;
16
21
17
22
const sourceView = new Uint8Array ( prism . memory . buffer , sourcePointer , sourceArray . length ) ;
18
23
sourceView . set ( sourceArray ) ;
19
24
20
- prism . pm_serialize_parse ( bufferPointer , sourcePointer , sourceArray . length ) ;
25
+ const optionsView = new Uint8Array ( prism . memory . buffer , optionsPointer , packedOptions . length ) ;
26
+ optionsView . set ( packedOptions ) ;
27
+
28
+ prism . pm_serialize_parse ( bufferPointer , sourcePointer , sourceArray . length , optionsPointer ) ;
21
29
const serializedView = new Uint8Array ( prism . memory . buffer , prism . pm_buffer_value ( bufferPointer ) , prism . pm_buffer_length ( bufferPointer ) ) ;
22
30
const result = deserialize ( sourceArray , serializedView ) ;
23
31
24
32
prism . pm_buffer_free ( bufferPointer ) ;
25
33
prism . free ( sourcePointer ) ;
26
34
prism . free ( bufferPointer ) ;
35
+ prism . free ( optionsPointer ) ;
27
36
return result ;
28
37
}
38
+
39
+ // Converts the given options into a serialized options string.
40
+ function dumpOptions ( options ) {
41
+ const values = [ ] ;
42
+ const template = [ ] ;
43
+ const encoder = new TextEncoder ( ) ;
44
+
45
+ template . push ( "L" )
46
+ if ( options . filepath ) {
47
+ const filepath = encoder . encode ( options . filepath ) ;
48
+ values . push ( filepath . length ) ;
49
+ values . push ( filepath ) ;
50
+ template . push ( "A" ) ;
51
+ } else {
52
+ values . push ( 0 ) ;
53
+ }
54
+
55
+ template . push ( "l" ) ;
56
+ values . push ( options . line || 1 ) ;
57
+
58
+ template . push ( "L" ) ;
59
+ if ( options . encoding ) {
60
+ const encoding = encoder . encode ( options . encoding ) ;
61
+ values . push ( encoding . length ) ;
62
+ values . push ( encoding ) ;
63
+ template . push ( "A" ) ;
64
+ } else {
65
+ values . push ( 0 ) ;
66
+ }
67
+
68
+ template . push ( "C" ) ;
69
+ values . push ( options . frozen_string_literal === undefined ? 0 : 1 ) ;
70
+
71
+ template . push ( "C" ) ;
72
+ values . push ( options . verbose === undefined ? 0 : 1 ) ;
73
+
74
+ template . push ( "C" ) ;
75
+ if ( ! options . version || options . version === "latest" ) {
76
+ values . push ( 0 ) ;
77
+ } else if ( options . version === "3.3.0" ) {
78
+ values . push ( 1 ) ;
79
+ } else {
80
+ throw new Error ( `Unsupported version '${ options . version } ' in compiler options` ) ;
81
+ }
82
+
83
+ template . push ( "L" ) ;
84
+ if ( options . scopes ) {
85
+ const scopes = options . scopes ;
86
+ values . push ( scopes . length ) ;
87
+
88
+ for ( const scope of scopes ) {
89
+ template . push ( "L" ) ;
90
+ values . push ( scope . length ) ;
91
+
92
+ for ( const local of scope ) {
93
+ const name = local . name ;
94
+ template . push ( "L" ) ;
95
+ values . push ( name . length ) ;
96
+
97
+ template . push ( "A" )
98
+ values . push ( encoder . encode ( name ) ) ;
99
+ }
100
+ }
101
+ } else {
102
+ values . push ( 0 ) ;
103
+ }
104
+
105
+ return pack ( values , template ) ;
106
+ }
107
+
108
+ function totalSizeOf ( values , template ) {
109
+ let size = 0 ;
110
+
111
+ for ( let i = 0 ; i < values . length ; i ++ ) {
112
+ size += sizeOf ( values , template , i ) ;
113
+ }
114
+
115
+ return size ;
116
+ }
117
+
118
+ function sizeOf ( values , template , index ) {
119
+ switch ( template [ index ] ) {
120
+ // arbitrary binary string
121
+ case "A" :
122
+ return values [ index ] . length ;
123
+
124
+ // l: signed 32-bit integer, L: unsigned 32-bit integer
125
+ case "l" :
126
+ case "L" :
127
+ return 4 ;
128
+
129
+ // 8-bit unsigned integer
130
+ case "C" :
131
+ return 1 ;
132
+ }
133
+ }
134
+
135
+ function pack ( values , template ) {
136
+ const littleEndian = os . endianness ( ) === "LE" ;
137
+ const buffer = new ArrayBuffer ( totalSizeOf ( values , template ) ) ;
138
+ const data_view = new DataView ( buffer ) ;
139
+ let offset = 0 ;
140
+
141
+ for ( let i = 0 ; i < values . length ; i ++ ) {
142
+ switch ( template [ i ] ) {
143
+ case "A" :
144
+ for ( let c = 0 ; c < values [ i ] . length ; c ++ ) {
145
+ data_view . setUint8 ( offset + c , values [ i ] [ c ] ) ;
146
+ }
147
+
148
+ break ;
149
+
150
+ case "l" :
151
+ data_view . setInt32 ( offset , values [ i ] , littleEndian ) ;
152
+ break ;
153
+
154
+ case "L" :
155
+ data_view . setUint32 ( offset , values [ i ] , littleEndian ) ;
156
+ break ;
157
+
158
+ case "C" :
159
+ data_view . setUint8 ( offset , values [ i ] , littleEndian ) ;
160
+ break ;
161
+ }
162
+
163
+ offset += sizeOf ( values , template , i ) ;
164
+ }
165
+
166
+ return new Uint8Array ( buffer ) ;
167
+ }
0 commit comments