1+ import subprocess
2+
3+ from shasta .ast_node import *
4+ from sh_expand .expand import expand_command , ExpansionState
5+
16from shell_ast .ast_util import *
27from ir import *
3- from shell_ast .ast_node import *
4- from shell_ast .ast_node_c import *
58from util import *
69from parse import from_ast_objects_to_shell
7- from shell_ast .expand import *
8- import subprocess
9- import config
1010
1111## TODO: Separate the ir stuff to the bare minimum and
1212## try to move this to the shell_ast folder.
4040 lambda ast_node : compile_node_redir_subshell (ast_node , fileIdGen , config )),
4141 "Background" : (lambda fileIdGen , config :
4242 lambda ast_node : compile_node_background (ast_node , fileIdGen , config )),
43- "Defun" : (lambda fileIdGen , config :
44- lambda ast_node : compile_node_defun (ast_node , fileIdGen , config )),
4543 "For" : (lambda fileIdGen , config :
4644 lambda ast_node : compile_node_for (ast_node , fileIdGen , config ))
4745 }
4846
4947
50- def compile_asts (ast_objects , fileIdGen , config ):
48+ def compile_asts (ast_objects : "list[AstNode]" , fileIdGen , config ):
5149 compiled_asts = []
5250 acc_ir = None
5351 for i , ast_object in enumerate (ast_objects ):
5452 # log("Compiling AST {}".format(i))
5553 # log(ast_object)
54+ assert (isinstance (ast_object , AstNode ))
5655
5756 ## Compile subtrees of the AST to out intermediate representation
58- expanded_ast = expand_command (ast_object , config )
57+ ## KK 2023-05-25: Would we ever want to pass this state to the expansion
58+ ## of the next object? I don't think so.
59+ exp_state = ExpansionState (config ['shell_variables' ])
60+ expanded_ast = expand_command (ast_object , exp_state )
61+ # log("Expanded:", expanded_ast)
5962 compiled_ast = compile_node (expanded_ast , fileIdGen , config )
6063
6164 # log("Compiled AST:")
@@ -112,14 +115,12 @@ def compile_node_pipe(ast_node, fileIdGen, config):
112115 ## pipeline) the compiled_pipe_nodes should always
113116 ## be one IR
114117 compiled_ir = compiled_pipe_nodes [0 ]
115- ## Note: Save the old ast for the end-to-end prototype
116- old_ast_node = make_kv ( ast_node .construct . value , [ ast_node . is_background , ast_node . items ] )
117- compiled_ir .set_ast (old_ast_node )
118+ ## Save the old ast for the end-to-end prototype
119+ old_untyped_ast_node = ast_node .json ( )
120+ compiled_ir .set_ast (old_untyped_ast_node )
118121 ## Set the IR background so that it can be parallelized with
119122 ## the next command if the pipeline was run in background
120123 compiled_ir .set_background (ast_node .is_background )
121- ## TODO: If the pipeline is in background, I also have to
122- ## redirect its stdin, stdout
123124 compiled_ast = compiled_ir
124125 return compiled_ast
125126
@@ -145,70 +146,39 @@ def combine_pipe(ast_nodes):
145146 return [combined_nodes ]
146147
147148def compile_node_command (ast_node , fileIdGen , config ):
148- construct_str = ast_node .construct .value
149- old_ast_node = make_kv (construct_str , [ast_node .line_number ,
150- ast_node .assignments , ast_node .arguments , ast_node .redir_list ])
151-
152- ## TODO: Do we need the line number?
153-
154149 ## Compile assignments and redirection list
155150 compiled_assignments = compile_assignments (ast_node .assignments , fileIdGen , config )
156151 compiled_redirections = compile_redirections (ast_node .redir_list , fileIdGen , config )
157152
158- ## If there are no arguments, the command is just an
159- ## assignment
160- ##
161- ## TODO: The if-branch of this conditional should never be possible since the preprocessor
162- ## wouldn't replace a call without arguments (simple assignment).
163- ##
164- ## Also the return is not in the correct indentation so probably it never gets called
165- ## in our tests.
166- ##
167- ## We should remove it and add the following assert:
168- ## assert len(ast_node.arguments) > 0
169- if (len (ast_node .arguments ) == 0 ):
170- ## Just compile the assignments. Specifically compile the
171- ## assigned values, because they might have command
172- ## substitutions etc..
173- compiled_ast = make_kv (construct_str , [ast_node .line_number ] +
174- [compiled_assignments ] + [ast_node .arguments , compiled_redirections ])
175- else :
176- arguments = ast_node .arguments
177- command_name = arguments [0 ]
178- options = compile_command_arguments (arguments [1 :], fileIdGen , config )
153+ ## This should never be possible since the preprocessor
154+ ## wouldn't replace a call without arguments (simple assignment).
155+ assert len (ast_node .arguments ) > 0
156+
157+ arguments = ast_node .arguments
158+ command_name = arguments [0 ]
159+ options = compile_command_arguments (arguments [1 :], fileIdGen , config )
160+
161+ try :
162+ ## If the command is not compileable to a DFG the following call will fail
163+ ir = compile_command_to_DFG (fileIdGen ,
164+ command_name ,
165+ options ,
166+ redirections = compiled_redirections )
167+ compiled_ast = ir
168+ except ValueError as err :
169+ log ("Command not compiled to DFG:" , err )
170+ ## TODO: Maybe we want to fail here instead of waiting for later?
171+ ## Is there any case where a non-compiled command is fine?
172+ # log(traceback.format_exc())
173+ compiled_arguments = compile_command_arguments (arguments , fileIdGen , config )
174+ compiled_ast = make_kv (type (ast_node ).NodeName ,
175+ [ast_node .line_number , compiled_assignments ,
176+ compiled_arguments , compiled_redirections ])
179177
180- ## Question: Should we return the command in an IR if one of
181- ## its arguments is a command substitution? Meaning that we
182- ## will have to wait for its command to execute first?
183- ##
184- ## ANSWER: Kind of. If a command has a command substitution or
185- ## anything that evaluates we should add it to the IR, but we
186- ## should also make sure that its category is set to the most
187- ## general one. That means that it can be executed
188- ## concurrently with other commands, but it cannot be
189- ## parallelized.
190- try :
191- ## If the command is not compileable to a DFG the following call will fail
192- ir = compile_command_to_DFG (fileIdGen ,
193- command_name ,
194- options ,
195- redirections = compiled_redirections )
196- compiled_ast = ir
197- except ValueError as err :
198- ## TODO: Delete this log from here
199- log (err )
200- ## TODO: Maybe we want to fail here instead of waiting for later?
201- ## Is there any case where a non-compiled command is fine?
202- # log(traceback.format_exc())
203- compiled_arguments = compile_command_arguments (arguments , fileIdGen , config )
204- compiled_ast = make_kv (construct_str ,
205- [ast_node .line_number , compiled_assignments ,
206- compiled_arguments , compiled_redirections ])
207-
208- return compiled_ast
178+ return compiled_ast
209179
210180def compile_node_and_or_semi (ast_node , fileIdGen , config ):
211- compiled_ast = make_kv (ast_node . construct . value ,
181+ compiled_ast = make_kv (type ( ast_node ). NodeName ,
212182 [compile_node (ast_node .left_operand , fileIdGen , config ),
213183 compile_node (ast_node .right_operand , fileIdGen , config )])
214184 return compiled_ast
@@ -221,7 +191,7 @@ def compile_node_redir_subshell(ast_node, fileIdGen, config):
221191 ## the IR accordingly
222192 compiled_ast = compiled_node
223193 else :
224- compiled_ast = make_kv (ast_node . construct . value , [ast_node .line_number ,
194+ compiled_ast = make_kv (type ( ast_node ). NodeName , [ast_node .line_number ,
225195 compiled_node , ast_node .redir_list ])
226196
227197 return compiled_ast
@@ -248,24 +218,10 @@ def compile_node_background(ast_node, fileIdGen, config):
248218
249219 return compiled_ast
250220
251- def compile_node_defun (ast_node , fileIdGen , config ):
252- ## It is not clear how we should handle functions.
253- ##
254- ## - Should we transform their body to IR?
255- ## - Should we handle calls to the functions as commands?
256- ##
257- ## It seems that we should do both. But we have to think if
258- ## this introduces any possible problem.
259-
260- ## TODO: Investigate whether it is fine to just compile the
261- ## body of functions.
262- compiled_body = compile_node (ast_node .body , fileIdGen , config )
263- return make_kv (construct , [ast_node .line_number , ast_node .name , compiled_body ])
264-
265221def compile_node_for (ast_node , fileIdGen , config ):
266222 ## TODO: Investigate what kind of check could we do to make a for
267223 ## loop parallel
268- compiled_ast = make_kv (ast_node . construct . value ,
224+ compiled_ast = make_kv (type ( ast_node ). NodeName ,
269225 [ast_node .line_number ,
270226 compile_command_argument (ast_node .argument , fileIdGen , config ),
271227 compile_node (ast_node .body , fileIdGen , config ),
@@ -352,25 +308,25 @@ def expand_command_argument(argument, config):
352308## This function compiles an arg char by recursing if it contains quotes or command substitution.
353309##
354310## It is currently being extended to also expand any arguments that are safe to expand.
355- def compile_arg_char (arg_char , fileIdGen , config ):
311+ def compile_arg_char (arg_char : ArgChar , fileIdGen , config ):
356312 ## Compile the arg char
357- key , val = get_kv (arg_char )
358- if ( key in [ 'C' , # Single character
359- 'E' ]): # Escape
313+ if isinstance (arg_char , CArgChar ) \
314+ or isinstance ( arg_char , EArgChar ):
315+ # Single character or escape
360316 return arg_char
361- elif ( key == 'B' ):
317+ elif isinstance ( arg_char , BArgChar ):
362318 ## TODO: I probably have to redirect the input of the compiled
363319 ## node (IR) to be closed, and the output to be
364320 ## redirected to some file that we will use to write to
365321 ## the command argument to complete the command
366322 ## substitution.
367- compiled_node = compile_node (val , fileIdGen , config )
368- return [ key , compiled_node ]
369- elif ( key == 'Q' ):
370- compiled_val = compile_command_argument (val , fileIdGen , config )
371- return [ key , compiled_val ]
323+ arg_char . node = compile_node (arg_char . node , fileIdGen , config )
324+ return arg_char
325+ elif isinstance ( arg_char , QArgChar ):
326+ arg_char . arg = compile_command_argument (arg_char . arg , fileIdGen , config )
327+ return arg_char
372328 else :
373- log (" Unknown arg_char:" , arg_char )
329+ log (f' Unknown arg_char: { arg_char } ' )
374330 ## TODO: Complete this
375331 return arg_char
376332
@@ -390,11 +346,9 @@ def compile_assignments(assignments, fileIdGen, config):
390346 return compiled_assignments
391347
392348def compile_redirection (redirection , fileIdGen , config ):
393- redir_type = redirection [0 ]
394- redir_subtype = redirection [1 ][0 ]
395- stream_id = redirection [1 ][1 ]
396- file_arg = compile_command_argument (redirection [1 ][2 ], fileIdGen , config )
397- return [redir_type , [redir_subtype , stream_id , file_arg ]]
349+ file_arg = compile_command_argument (redirection .arg , fileIdGen , config )
350+ redirection .arg = file_arg
351+ return redirection
398352
399353def compile_redirections (redirections , fileIdGen , config ):
400354 compiled_redirections = [compile_redirection (redirection , fileIdGen , config )
0 commit comments