Skip to content

Commit

Permalink
[ysh] Prepare for 3rd section in proc arg lists
Browse files Browse the repository at this point in the history
For a block expresssion:

    var b = ^(echo hi)
    p /tmp (42; a=99; b)

This is part of a solution for #1849 -- a language design bug!
  • Loading branch information
Andy Chu committed Apr 12, 2024
1 parent 991fd88 commit 1cd7a5e
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 13 deletions.
4 changes: 2 additions & 2 deletions frontend/parse_lib.py
Expand Up @@ -325,7 +325,7 @@ def ParseMutation(self, kw_token, lexer):

return ast_node, last_token

def ParseYshArgList(self, lx, out, start_symbol):
def ParseProcCallArgs(self, lx, out, start_symbol):
# type: (Lexer, ArgList, int) -> None
""" json write (x, foo=1) and assert [42 === x] """

Expand All @@ -336,7 +336,7 @@ def ParseYshArgList(self, lx, out, start_symbol):
if 0:
self.p_printer.Print(pnode)

self.tr.ToArgList(pnode, out)
self.tr.ProcCallArgs(pnode, out)
out.right = last_token

def ParseYshExpr(self, lx, start_symbol):
Expand Down
1 change: 1 addition & 0 deletions frontend/syntax.asdl
Expand Up @@ -209,6 +209,7 @@ module syntax
ArgList = (
Token left, List[expr] pos_args,
Token? semi_tok, List[NamedArg] named_args,
expr? block_expr,
Token right
)

Expand Down
2 changes: 1 addition & 1 deletion osh/word_parse.py
Expand Up @@ -1650,7 +1650,7 @@ def ParseProcCallArgs(self, start_symbol):

arg_list = ArgList.CreateNull(alloc_lists=True)
arg_list.left = self.cur_token
self.parse_ctx.ParseYshArgList(self.lexer, arg_list, start_symbol)
self.parse_ctx.ParseProcCallArgs(self.lexer, arg_list, start_symbol)
return arg_list

def _MaybeReadWordPart(self, is_first, lex_mode, parts):
Expand Down
52 changes: 51 additions & 1 deletion spec/ysh-proc.test.sh
@@ -1,3 +1,4 @@
## oils_failures_allowed: 2

#### Open proc (any number of args)
shopt --set parse_proc
Expand Down Expand Up @@ -269,7 +270,7 @@ g

#### Procs defined inside compound statements (with redefine_proc)

shopt --set oil:upgrade
shopt --set ysh:upgrade
shopt --set redefine_proc_func

for x in 1 2 {
Expand All @@ -291,3 +292,52 @@ loop
brace
## END

#### Pass through all 4 kinds of args

shopt --set ysh:upgrade

proc p2 (...words; ...typed; ...named; block) {
pp line (words)
pp line (typed)
pp line (named)
pp line (block)
}

proc p1 (...words; ...typed; ...named; block) {
p2 @words (...typed; ...named; block)
}

p2 a b ('c', 'd', n=99) {
echo block
}

# Same thing
var block = ^(echo hi)
p2 a b ('c', 'd', n=99; block)

# what happens when you do this?
p2 a b ('c', 'd', n=99; block) {
echo duplicate
}

## STDOUT:
## END

#### Block arg
shopt --set ysh:upgrade

proc p ( ; ; ; block) {
eval (block)
}

p { echo a }

var block = ^(echo b)

# Hm this is ignored? Duplicate? Doesn't take
p (block) { echo c }

## STDOUT:
a
## END

15 changes: 8 additions & 7 deletions ysh/expr_to_ast.py
Expand Up @@ -212,7 +212,7 @@ def _Trailer(self, base, p_trailer):
if op_tok.id == Id.Op_LParen:
lparen = op_tok
rparen = p_trailer.GetChild(-1).tok
arglist = ArgList(lparen, [], None, [], rparen)
arglist = ArgList(lparen, [], None, [], None, rparen)
if p_trailer.NumChildren() == 2: # ()
return expr.FuncCall(base, arglist)

Expand Down Expand Up @@ -1057,20 +1057,21 @@ def _ArgList(self, p_node, arglist):
arglist.semi_tok = p_node.GetChild(i).tok
self._ArgGroup(p_node.GetChild(i + 1), True, arglist)

def ToArgList(self, pnode, arglist):
def ProcCallArgs(self, pnode, arglist):
# type: (PNode, ArgList) -> None
"""
ysh_eager_arglist: '(' [arglist] ')'
ysh_lazy_arglist: '[' [arglist] ']'
"""
if pnode.NumChildren() == 2: # f()
n = pnode.NumChildren()
if n == 2: # f()
return

assert pnode.NumChildren() == 3
p = pnode.GetChild(1) # the X in '( X )'
if n >= 3:
p = pnode.GetChild(1) # the X in '( X )'

assert p.typ == grammar_nt.arglist
self._ArgList(p, arglist)
assert p.typ == grammar_nt.arglist
self._ArgList(p, arglist)

def _TypeExpr(self, pnode):
# type: (PNode) -> TypeExpr
Expand Down
9 changes: 7 additions & 2 deletions ysh/grammar.pgen2
Expand Up @@ -309,8 +309,13 @@ lhs_list: expr (',' expr)*
# TODO: allow -> to denote aliasing/mutation
ysh_mutation: lhs_list (augassign | '=') testlist end_stmt

# For json write (x)
ysh_eager_arglist: '(' [arglist] ')'
# proc arg lists, like:
# json write (x, indent=1)
# cd /tmp ( ; ; ^(echo hi))
#
# What about:
# myproc /tmp [ ; ; ^(echo hi)] - I guess this doesn't make sense?
ysh_eager_arglist: '(' [arglist] [';' argument] ')'
ysh_lazy_arglist: '[' [arglist] ']'

#
Expand Down

0 comments on commit 1cd7a5e

Please sign in to comment.