Skip to content

Commit

Permalink
[ysh proc] Word param types can only be Ref or Str
Browse files Browse the repository at this point in the history
Str is the default; Ref is special.

Also simplify type_expr_t sum type -> TypeExpr.
  • Loading branch information
Andy C committed Aug 28, 2023
1 parent 2c9b1ce commit 3e69d5c
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 29 deletions.
18 changes: 8 additions & 10 deletions frontend/syntax.asdl
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@

# Possible refactorings:
#
# # More %Token as first class variants:
# type_expr = Atom %Token | ...
# printf_part = Literal %Token | ...
#
# # %CompoundWord as first class variant:
Expand Down Expand Up @@ -379,7 +377,7 @@ module syntax
| TeaFunc(Token name,
List[Param] pos_params, Token? pos_splat,
List[Param] named_params, Token? named_splat,
List[type_expr] return_types, command body)
List[TypeExpr] return_types, command body)
| Data(Token name, List[Param] params)
| Enum(Token name, List[Variant] variants)
| Class(Token name, Token? extends, List[class_item] items)
Expand Down Expand Up @@ -414,7 +412,7 @@ module syntax

# prefix is : for out param, ... for splat
# procs only have types Ref, Expr, Block (and Str is implicit)
Param = (Token? prefix, Token name, type_expr? type, expr? default_val)
Param = (Token? prefix, Token name, TypeExpr? type, expr? default_val)

#
# Glob representation, for converting ${x//} to extended regexes.
Expand All @@ -441,19 +439,19 @@ module syntax
| Percent(List[Token] flags, Token? width, Token? precision, Token type)

#
# OIL LANGUAGE
# YSH Language
#
# Copied and modified from Python-3.7/Parser/Python.asdl !

expr_context = Load | Store | Del | AugLoad | AugStore | Param

# type expressions: Int Array[Int] Dict[Str, Any]
type_expr =
Simple(Token tok, str name)
| Compound(Token tok, str name, List[type_expr] params)
# Type expressions: Int List[Int] Dict[Str, Any]
# Do we have Func[Int, Int => Int] ? I guess we can parse that into this
# system.
TypeExpr = (Token tok, str name, List[TypeExpr] params)

# LHS binding in loops, list comprehensions, and var/const
NameType = (Token name, type_expr? typ)
NameType = (Token name, TypeExpr? typ)

# TODO: Inline this into GenExp and ListComp? Just use a flag there?
Comprehension = (List[NameType] lhs, expr iter, expr? cond)
Expand Down
8 changes: 1 addition & 7 deletions osh/cmd_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
for_iter_e,
pat,
pat_e,
type_expr, type_expr_e,
)
from _devbuild.gen.runtime_asdl import (
lvalue,
Expand Down Expand Up @@ -2020,12 +2019,7 @@ def RunProc(self, proc, argv, arg0_loc):
for i, p in enumerate(sig.words):

# proc p(out Ref)
is_out_param = False
if p.type is not None:
if p.type.tag() == type_expr_e.Simple:
typ = cast(type_expr.Simple, p.type)
if typ.tok.tval == 'Ref':
is_out_param = True
is_out_param = (p.type is not None and p.type.name == 'Ref')

param_name = p.name.tval
if i < n_args:
Expand Down
15 changes: 15 additions & 0 deletions test/ysh-parse-errors.sh
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ test-proc-sig() {
_should-parse 'proc p (a) { echo hi }'
_should-parse 'proc p (out Ref) { echo hi }'

# doesn't make sense I think -- they're all strings. Types don't do any
# dynamic validation, except 'out Ref' does change semantics
_error-case 'proc p (a Int) { echo hi }'

_error-case 'proc p (w, ...) { echo hi }'

_should-parse 'proc p (w, ...rest) { echo hi }'
Expand Down Expand Up @@ -134,6 +138,17 @@ test-proc-sig() {
_should-parse 'proc p (w, ...rest; t, ...rest; named, ...rest; {block}) { echo hi }'
}

test-func-sig() {
_error-case 'func f { echo hi }'

_should-parse 'func f () { echo hi }'

_should-parse 'func f (a List[Int] = [3,4]) { echo hi }'
_should-parse 'func f (a, b, ...rest; c) { echo hi }'
_should-parse 'func f (a, b, ...rest; c, ...rest) { echo hi }'
_error-case 'func f (a, b, ...rest; c, ...rest;) { echo hi }'
}

soil-run() {
# This is like run-test-funcs, except errexit is off here
run-test-funcs
Expand Down
33 changes: 21 additions & 12 deletions ysh/expr_to_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
place_expr,
place_expr_e,
place_expr_t,
type_expr_t,
Comprehension,
Subscript,
Attribute,
Expand All @@ -39,13 +38,12 @@
Param,
NamedArg,
ArgList,
#ProcParam,
Variant,
variant_type,
variant_type_t,
pat,
pat_t,
type_expr,
TypeExpr,
)
from _devbuild.gen import grammar_nt
from core.error import p_die
Expand Down Expand Up @@ -892,32 +890,34 @@ def ToArgList(self, pnode, arglist):
self._Arglist(p, arglist)

def _TypeExpr(self, pnode):
# type: (PNode) -> type_expr_t
# type: (PNode) -> TypeExpr
"""
type_expr: Expr_Name [ '[' type_expr (',' type_expr)* ']' ]
"""
assert pnode.typ == grammar_nt.type_expr, pnode.typ

#self.p_printer.Print(pnode)

tok = pnode.GetChild(0).tok
name = tok.tval
ty = TypeExpr.CreateNull() # don't allocate children

ty.tok = pnode.GetChild(0).tok
ty.name = ty.tok.tval # TODO: TokenVal()

n = pnode.NumChildren()
if n == 1:
return type_expr.Simple(tok, name)
return ty

type_params = [] # type: List[type_expr_t]
ty.params = []
i = 2
while i < n:
p = self._TypeExpr(pnode.GetChild(i))
type_params.append(p)
ty.params.append(p)
i += 2 # skip comma

return type_expr.Compound(tok, name, type_params)
return ty

def _TypeExprList(self, pnode):
# type: (PNode) -> List[type_expr_t]
# type: (PNode) -> List[TypeExpr]
"""
For return value annotation?
"""
Expand All @@ -940,7 +940,7 @@ def _Param(self, pnode):
prefix_tok = None # type: Token

default_val = None # type: expr_t
type_ = None # type: type_expr_t
type_ = None # type: TypeExpr

#self.p_printer.Print(pnode)

Expand Down Expand Up @@ -1014,6 +1014,7 @@ def Proc(self, p_node):
# proc f( three param groups, and block group )
sig = proc_sig.Closed.CreateNull(alloc_lists=True) # no params

# Word args
i = 1
child = p_node.GetChild(i)
if child.typ == grammar_nt.param_group:
Expand All @@ -1022,6 +1023,14 @@ def Proc(self, p_node):
else:
i += 1

for word in sig.words:
if word.type:
if word.type.name not in ('Str', 'Ref'):
p_die('Word params may only have type Str or Ref',
word.type.tok)
if word.type.params is not None:
p_die('Unexpected type parameters', word.type.tok)

#log('i %d n %d', i, n)
if i >= n:
return sig
Expand Down

0 comments on commit 3e69d5c

Please sign in to comment.