Skip to content

Commit c7c75e6

Browse files
authored
Merge pull request #684 from binpash/future
New PaSh release
2 parents 768961a + 15f75fb commit c7c75e6

File tree

201 files changed

+1022
-2377
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

201 files changed

+1022
-2377
lines changed

.github/workflows/tests.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ jobs:
8181
runs-on: ubuntu-latest
8282
if: github.event.pull_request.draft == false
8383
steps:
84-
- uses: actions/checkout@v3
84+
- uses: actions/checkout@v3
85+
with:
86+
ref: ${{ github.event.pull_request.head.sha }}
8587

8688
- uses: ludeeus/action-shellcheck@master
8789
env:

compiler/annotations_utils/util_cmd_invocations.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ def construct_property_container_from_list_of_properties(list_properties):
9696
# this function is needed to wrap a node in `r_wrap`
9797
def to_arg_from_cmd_inv_with_io_vars_without_streaming_inputs_or_outputs_for_wrapping(cmd_inv, edges):
9898
# we already expand here
99-
whole_cmd = Arg(string_to_argument("\'"))
100-
arg_cmd_name = Arg(string_to_argument(cmd_inv.cmd_name))
99+
whole_cmd = Arg.string_to_arg("\'")
100+
arg_cmd_name = Arg.string_to_arg(cmd_inv.cmd_name)
101101
arg_flagoptions = []
102102
for flagoption in cmd_inv.flag_option_list:
103103
arg_flagoptions += to_arg_flagoption(flagoption, edges)
@@ -107,14 +107,14 @@ def to_arg_from_cmd_inv_with_io_vars_without_streaming_inputs_or_outputs_for_wra
107107
all_cmd_parts_arg.extend(arg_operands)
108108
for part in all_cmd_parts_arg:
109109
whole_cmd.concatenate(part)
110-
whole_cmd.concatenate(Arg(string_to_argument("\'")))
110+
whole_cmd.concatenate(Arg.string_to_arg("\'"))
111111
return whole_cmd
112112

113113
def to_arg_flagoption(flagoption, edges):
114114
if isinstance(flagoption, Flag):
115-
return [Arg(string_to_argument(flagoption.get_name()))]
115+
return [Arg.string_to_arg(flagoption.get_name())]
116116
elif isinstance(flagoption, OptionWithIO):
117-
opt_name_arg = Arg(string_to_argument(flagoption.get_name()))
117+
opt_name_arg = Arg.string_to_arg(flagoption.get_name())
118118
opt_arg_arg = translate_io_var_to_arg_if_applicable(flagoption.get_arg(), edges)
119119
return [opt_name_arg, opt_arg_arg]
120120

compiler/ast_to_ir.py

Lines changed: 57 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1+
import subprocess
2+
3+
from shasta.ast_node import *
4+
from sh_expand.expand import expand_command, ExpansionState
5+
16
from shell_ast.ast_util import *
27
from ir import *
3-
from shell_ast.ast_node import *
4-
from shell_ast.ast_node_c import *
58
from util import *
69
from 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.
@@ -40,22 +40,25 @@
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

147148
def 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

210180
def 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-
265221
def 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

392348
def 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

399353
def compile_redirections(redirections, fileIdGen, config):
400354
compiled_redirections = [compile_redirection(redirection, fileIdGen, config)

0 commit comments

Comments
 (0)