~andyc/oil

139ecff57caf840484ba2bf45de84561656bdfea — Andy Chu a month ago 38c93d0
[oil-language] Implement the ~~ and !~~ operators for globs

Document them in the tour of the Oil language.

This is similar to shell's [[ $x == *.py ]].

It also somewhat relates to the enhanced case statement idea in #983,
although I think we may just settle on if-elif as a more familiar idiom.

Still it's nicer to have

    if (filename ~~ '*.py') {
      echo 'Python'
    } elif (filename ~~ '*.sh') {
      echo 'shell'
    }

than

    if (fnmatch(filename, '*.py')) {
      echo 'Python'
    } elif (fnmatch(filename, '*.sh')) {
      echo 'shell'
    }
2 files changed, 23 insertions(+), 15 deletions(-)

M doc/oil-language-tour.md
M oil_lang/expr_eval.py
M doc/oil-language-tour.md => doc/oil-language-tour.md +20 -13
@@ 415,7 415,7 @@ If it's neither, then it's assumed to be an external command:
<!-- 
leaving off: aliases

TODO: We also need lazy arg lists: qtt | where [size > 10]
TODO: We also need lazy arg lists: qtt | where (size > 10)
-->

You can **redirect** `stdin` and `stdout` of simple commands:


@@ 625,6 625,8 @@ Here are some categories of builtin:
- Meta: `command  builtin  runproc  type  eval`
- Modules: `source  module`

<!-- TODO: Link to a comprehensive list of builtins -->

Syntax quirk: builtins like `read` use the colon as a "pseudo-sigil":

    var x = ''


@@ 632,8 634,6 @@ Syntax quirk: builtins like `read` use the colon as a "pseudo-sigil":

It's just a visual indication that the string arg is a variable name.

<!-- TODO: Make a more comprehensive list. -->

## Expression Language: Python-like Types

Oil expressions are more like Python and JavaScript than traditional shell


@@ 744,7 744,7 @@ directly.
  `Expr`.
  - rarely-used literal: `^{42, f(x), verbose = true}`

<!-- TODO: implement these -->
<!-- TODO: implement Block, Expr, ArgList types (variants of value) -->

### Operators



@@ 773,14 773,17 @@ Equality can be approximate or exact:

Pattern matching can be done with globs (`~~` and `!~~`):

    # if (s ~~ '*.py') {
    #   echo 'Python'
    # }
    const filename = 'foo.py'
    if (filename ~~ '*.py') {
      echo 'Python'
    }  # => Python

or regular expressions (`~` and `!~`).  See the Eggex section below for an
example of these operators.
    if (filename !~~ '*.sh') {
      echo 'not shell'
    }  # => not shell

TODO: Implement `~==` and `~~`!
or regular expressions (`~` and `!~`).  See the Eggex section below for an
example of the latter.

Concatenation is `++` rather than `+` because it avoids confusion in the
presence of type conversion:


@@ 827,7 830,7 @@ are like the "standard library" for the expression language.  Examples:
- String and pattern: `find()  sub()`
- Collections: `len()  keys()  values()  items()  append()  extend()`

<!-- TODO: Make a more comprehensive list. -->
<!-- TODO: Make a comprehensive list of func builtins. -->

### Egg Expressions (Oil Regexes)



@@ 845,6 848,10 @@ It's designed to be readable and composable.  Example:
      echo "$z looks like an IP address"
    }  # => 192.168.0.1 looks like an IP address

    if (z !~ / '.255' %end /) {
      echo "doesn't end with .255"
    }  # => doesn't end with .255"

See the [Egg Expressions doc](eggex.html) for details.

## Languages for Data (Interchange Formats)


@@ 853,7 860,7 @@ In the sections above, we saw that Oil **code** consists of 3 interleaved
languages.  It's also useful to think of **data** as being described in a
language.  [JSON]($xref) is a prominent example of such a language.

<!-- TODO: Link to concepts and patterns -->
<!-- TODO: Link to slogans, fallacies, and concepts -->

### Lines of Text (traditional), and QSN



@@ 906,7 913,7 @@ Example:
<!--
TODO:
- Fix pp cell output
- Use json write [d] syntax
- Use json write (d) syntax
-->

**Table-shaped** data can be read and written as [QTT: Quoted, Typed

M oil_lang/expr_eval.py => oil_lang/expr_eval.py +3 -2
@@ 378,9 378,10 @@ class OilEvaluator(object):
          result = left is not right

        elif op.id == Id.Expr_DTilde:
          e_die('~~ not implemented')
          # no extglob in Oil language; use eggex
          return libc.fnmatch(right, left, False)
        elif op.id == Id.Expr_NotDTilde:
          e_die('!~~ not implemented')
          return not libc.fnmatch(right, left, False)

        elif op.id == Id.Expr_TildeDEqual:
          # Approximate equality