diff --git a/osh/osh.asdl b/osh/osh.asdl index 03d99c2..a474560 100644 --- a/osh/osh.asdl +++ b/osh/osh.asdl @@ -15,16 +15,21 @@ -- * Brace expansion: should this be another kind of 'word'? It can be -- expanded at compile time. -- * let arithmetic (rarely used) --- * coprocesses +-- * coprocesses -- two kinds +-- * time builtin can take a block -- TODO: Preserve these source differences: --- * $foo vs. ${foo}. VarSub vs. BracedVarSub --- * 1 + 2*3 vs. 1 + (2*3) or even 1 + ((2*3)) --- * [[ (1 == 1) ]] vs [[ 1 == 1 ]] +-- * order of redirects: 'echo >out.txt hi' vs echo hi >out.txt +-- * In the printer, I want to preserve line breaks! foo \bar? +-- * parens +-- * 1 + 2*3 vs. 1 + (2*3) or even 1 + ((2*3)) +-- * [[ (1 == 1) ]] vs [[ 1 == 1 ]] -- * HereDoc vs HereWord. I collapsed them. -- * $(( 1 + 2 )) vs $[1 + 2] (bash-specific, used by Aboriginal) --- * Don't fill in file descriptor unless user specified it, e.g. echo < in.txt --- vs. echo 1< in.txt +-- +-- Found to be not strictly necessary for oil conversion +-- * foo() { } vs function foo { } -- ksh +-- * $'n' vs 'n' -- one of them just has EscapedLiteralPart module osh { @@ -47,20 +52,23 @@ module osh -- begin is optional with ${array::1} | Slice(arith_expr? begin, arith_expr? length) + -- TODO: Constructors should be scoped? array_item::Pair? array_item = - ArrayWord(word w) -- # TODO: make them scoped? array_item::Pair? + ArrayWord(word w) | ArrayPair(word key, word value) word_part = - ArrayLiteralPart(word* words) -- TODO: should be array_item* items + -- TODO: should be array_item* items. They CAN be mixed, like a=([x]=y z) + ArrayLiteralPart(word* words) | LiteralPart(token token) | EscapedLiteralPart(token token) | SingleQuotedPart(token* tokens) | DoubleQuotedPart(word_part* parts) - | VarSubPart(string name, - id? prefix_op, -- prefix # or ! operators - bracket_op? bracket_op - suffix_op? suffix_op) + | SimpleVarSub(token token) + | BracedVarSub(token token, + id? prefix_op, -- prefix # or ! operators + bracket_op? bracket_op + suffix_op? suffix_op) | TildeSubPart(string prefix) | CommandSubPart(command command_list) | ArithSubPart(arith_expr anode) @@ -104,41 +112,54 @@ module osh | HereDoc(id op_id, word? arg_word, int fd, int do_expansion, string here_end, bool was_filled) - assign_scope = Global | Local - assign_flags = Export | ReadOnly - assign_pair = (lvalue lhs, word rhs) + assign_pair = (lvalue lhs, word? rhs) env_pair = (string name, word val) - -- Homogeneous version + -- Each arm tests one word against multiple words + case_arm = (word* pat_list, command action) + if_arm = (command cond, command action) + + iterable = + IterArgv + | IterArray(word* words) + + -- TODO: Make field names consistent: child vs expr, etc. + command = NoOp + -- TODO: respect order | SimpleCommand(word* words, redir* redirects, env_pair* more_env) - | Assignment(assign_scope scope, - assign_flags* flags, - word* words, -- names mentioned without a binding - assign_pair* pairs) -- empty redirects for polymorphism? - | Fork(command* children) -- shell only allows one command + | Sentence(command command, token terminator) + -- TODO: parse flags -r -x; -a and -A aren't needed + | Assignment(id keyword, assign_pair* pairs) | Pipeline(command* children, bool negated, int* stderr_indices) - -- | AndOr(command* children, and_or* ops) + -- TODO: Should be left and right | AndOr(command* children, id op_id) - -- A command list is used for for/if/while conditions and bodies. No redirects. + -- TODO: Get rid of CommandList? No redirects, so can be a plain list. | CommandList(command* children) - -- A brace group is a compound command, with redirects. + -- Part of for/while/until. Can have one or more children. + | DoGroup(command child, redir* redirects) + -- A brace group is a compound command, with redirects. Can have one or more + -- children. | BraceGroup(command* children, redir* redirects) + -- Can have one or more children. | Subshell(command* children, redir* redirects) | DParen(arith_expr child, redir* redirects) | DBracket(bool_expr expr, redir* redirects) -- do_arg_iter: whether to implicitly loop over "$@" + -- TODO: Make iter_words a sum type. iterable for_words | ForEach(string iter_name, word* iter_words, bool do_arg_iter, - command* children, redir* redirects) + command body, redir* redirects) -- C-style for loop. Any of the 3 expressions can be omitted. + -- TODO: body is required, but only optional here because of initialization + -- order. | ForExpr(arith_expr? init, arith_expr? cond, arith_expr? update, - command* children, redir* redirects) - | While(command* children, redir* redirects) - | Until(command* children, redir* redirects) - | If(command* children, redir* redirects) - | Case(word to_match, word* pat_word_list, command* children, redir* redirects) - | FuncDef(string name, command* children, redir* redirects) + command? body, redir* redirects) + | While(command cond, command body, redir* redirects) + | Until(command cond, command body, redir* redirects) + | If(if_arm* arms, command? else_action, redir* redirects) + | Case(word to_match, case_arm* arms, redir* redirects) + | FuncDef(string name, command body, redir* redirects) and_or = DAmp | DPipe @@ -146,6 +167,11 @@ module osh -- |& in osh; |- in oil. -- pipe_op = Pipe | PipeAndStderr + -- NOTE: Do we even need these types? Arena already has methods. They can + -- We just need to go from text -> text. For execution, we'll be compiling + -- to a different format. We also won't bootstrap with osh code -- only oil + -- code. shell can call oil builtins if necessary. + -- A node with full debug info -- All other nodes should have span_id? int _loc or int _begin, int _end. -- It can be further compressed perhaps, like a varint.