11use super :: generate:: parse_grammar:: GrammarJSON ;
2- use anyhow:: { anyhow, Context , Result } ;
3- use path_slash:: PathExt as _;
4- use std:: {
5- ffi:: { OsStr , OsString } ,
6- fs,
7- path:: Path ,
8- process:: Command ,
9- } ;
10- use tree_sitter_loader:: EMSCRIPTEN_TAG ;
11- use which:: which;
2+ use anyhow:: { Context , Result } ;
3+ use std:: { fs, path:: Path } ;
4+ use tree_sitter_loader:: Loader ;
125
136pub fn load_language_wasm_file ( language_dir : & Path ) -> Result < ( String , Vec < u8 > ) > {
147 let grammar_name = get_grammar_name ( & language_dir)
@@ -35,119 +28,23 @@ pub fn get_grammar_name(language_dir: &Path) -> Result<String> {
3528}
3629
3730pub fn compile_language_to_wasm (
31+ loader : & Loader ,
3832 language_dir : & Path ,
3933 output_dir : & Path ,
4034 force_docker : bool ,
4135) -> Result < ( ) > {
4236 let grammar_name = get_grammar_name ( & language_dir) ?;
4337 let output_filename = output_dir. join ( & format ! ( "tree-sitter-{}.wasm" , grammar_name) ) ;
44-
45- let emcc_bin = if cfg ! ( windows) { "emcc.bat" } else { "emcc" } ;
46- let emcc_path = which ( emcc_bin)
47- . ok ( )
48- . and_then ( |p| Command :: new ( & p) . output ( ) . and ( Ok ( p) ) . ok ( ) ) ;
49-
50- let mut command;
51- if !force_docker && emcc_path. is_some ( ) {
52- command = Command :: new ( emcc_path. unwrap ( ) ) ;
53- command. current_dir ( & language_dir) ;
54- } else if Command :: new ( "docker" ) . output ( ) . is_ok ( ) {
55- command = Command :: new ( "docker" ) ;
56- command. args ( & [ "run" , "--rm" ] ) ;
57-
58- // Mount the parser directory as a volume
59- let mut volume_string;
60- if let ( Some ( parent) , Some ( filename) ) = ( language_dir. parent ( ) , language_dir. file_name ( ) ) {
61- volume_string = OsString :: from ( parent) ;
62- volume_string. push ( ":/src:Z" ) ;
63- command. arg ( "--workdir" ) ;
64- command. arg ( Path :: new ( "/src" ) . join ( filename) . to_slash_lossy ( ) . as_ref ( ) ) ;
65- } else {
66- volume_string = OsString :: from ( language_dir) ;
67- volume_string. push ( ":/src:Z" ) ;
68- command. args ( & [ "--workdir" , "/src" ] ) ;
69- }
70-
71- command. args ( & [ OsStr :: new ( "--volume" ) , & volume_string] ) ;
72-
73- // Get the current user id so that files created in the docker container will have
74- // the same owner.
75- if cfg ! ( unix) {
76- let user_id_output = Command :: new ( "id" )
77- . arg ( "-u" )
78- . output ( )
79- . with_context ( || "Failed to get get current user id" ) ?;
80- let user_id = String :: from_utf8_lossy ( & user_id_output. stdout ) ;
81- let user_id = user_id. trim ( ) ;
82- command. args ( & [ "--user" , user_id] ) ;
83- }
84-
85- // Run `emcc` in a container using the `emscripten-slim` image
86- command. args ( & [ EMSCRIPTEN_TAG , "emcc" ] ) ;
87- } else {
88- if force_docker {
89- return Err ( anyhow ! (
90- "You must have docker on your PATH to run this command with --docker"
91- ) ) ;
92- }
93- return Err ( anyhow ! (
94- "You must have either emcc or docker on your PATH to run this command"
95- ) ) ;
96- }
97-
98- command. arg ( "-o" ) . arg ( & output_filename) ;
99- command. args ( & [
100- "-Os" ,
101- "-s" ,
102- "WASM=1" ,
103- "-s" ,
104- "SIDE_MODULE=1" ,
105- "-s" ,
106- "TOTAL_MEMORY=33554432" ,
107- "-s" ,
108- "NODEJS_CATCH_EXIT=0" ,
109- "-s" ,
110- "NODEJS_CATCH_REJECTION=0" ,
111- "-s" ,
112- & format ! ( "EXPORTED_FUNCTIONS=[\" _tree_sitter_{}\" ]" , grammar_name) ,
113- "-fno-exceptions" ,
114- "-I" ,
115- "src" ,
116- ] ) ;
117-
118- let src = Path :: new ( "src" ) ;
119- let parser_c_path = src. join ( "parser.c" ) ;
120- let scanner_c_path = src. join ( "scanner.c" ) ;
121- let scanner_cc_path = src. join ( "scanner.cc" ) ;
122- let scanner_cpp_path = src. join ( "scanner.cpp" ) ;
123-
124- if language_dir. join ( & scanner_cc_path) . exists ( ) {
125- command
126- . arg ( "-xc++" )
127- . arg ( scanner_cc_path. to_slash_lossy ( ) . as_ref ( ) ) ;
128- } else if language_dir. join ( & scanner_cpp_path) . exists ( ) {
129- command
130- . arg ( "-xc++" )
131- . arg ( scanner_cpp_path. to_slash_lossy ( ) . as_ref ( ) ) ;
132- } else if language_dir. join ( & scanner_c_path) . exists ( ) {
133- command. arg ( scanner_c_path. to_slash_lossy ( ) . as_ref ( ) ) ;
134- }
135-
136- command. arg ( parser_c_path. to_slash_lossy ( ) . as_ref ( ) ) ;
137-
138- let output = command
139- . output ( )
140- . with_context ( || "Failed to run emcc command" ) ?;
141- if !output. status . success ( ) {
142- return Err ( anyhow ! (
143- "emcc command failed - {}" ,
144- String :: from_utf8_lossy( & output. stderr)
145- ) ) ;
146- }
147-
148- // Move the created `.wasm` file into the current working directory.
149- fs:: rename ( & language_dir. join ( & output_filename) , & output_filename)
150- . with_context ( || format ! ( "Couldn't find output file {:?}" , output_filename) ) ?;
151-
38+ let src_path = language_dir. join ( "src" ) ;
39+ let scanner_path = loader. get_scanner_path ( & src_path) ;
40+ loader. compile_parser_to_wasm (
41+ & grammar_name,
42+ & src_path,
43+ scanner_path
44+ . as_ref ( )
45+ . and_then ( |p| Some ( Path :: new ( p. file_name ( ) ?) ) ) ,
46+ & output_filename,
47+ force_docker,
48+ ) ?;
15249 Ok ( ( ) )
15350}
0 commit comments