~andyc/oil

eb9c60f070a1c96162e51a948550c8cc8b1be33e — Andy Chu a month ago 1d197ea dev/andy-vb6
[oil-language] Implement \u{3bc} as a 3rd type of char/rune literal

Document it.

Addresses part of #980.
M doc/oil-language-tour.md => doc/oil-language-tour.md +8 -7
@@ 611,19 611,20 @@ There are many ways to write integers:
    var hex, octal, binary = 0x0001_0000, 0o755, 0b0001_0101
    echo "$hex $octal $binary"           # => 65536 493 21

There are three ways to write characters, but they're actually **integers**:
"Runes" are integers that represent Unicode code points.  The'yre not common in
Oil code, but can make certain string algorithms more readable.

    # Pound char literal
    # Pound rune literals are similar to ord('A')
    const a = #'A'

    # Backslash char literals
    const newline = \n  # no quotes because it's a char/int, not a string
    # Backslash rune literals can appear outside of quotes
    const newline = \n  # Remember this is an integer
    const backslash = \\  # ditto

    # Unicode char literals
    #const mu = \u{3bc}
    # Unicode rune literal is syntactic sugar for 0x3bc
    const mu = \u{3bc}

    echo "chars $a $newline $backslash"  # => chars 65 10 92
    echo "chars $a $newline $backslash $mu"  # => chars 65 10 92 956

#### Float


M oil_lang/expr_eval.py => oil_lang/expr_eval.py +3 -0
@@ 235,6 235,9 @@ class OilEvaluator(object):
      # These two could be done at COMPILE TIME
      if id_ == Id.Char_OneChar:
        return consts.LookupCharInt(node.c.val[1])  # It's an integer
      if id_ == Id.Char_UBraced:
        s = node.c.val[3:-1]  # \u{123}
        return int(s, 16)
      if id_ == Id.Char_Pound:
        # TODO: accept UTF-8 code point instead of single byte
        byte = node.c.val[2]  # the a in #'a'

M oil_lang/expr_to_ast.py => oil_lang/expr_to_ast.py +2 -1
@@ 618,7 618,8 @@ class Transformer(object):
          Id.Expr_Float):
        return expr.Const(tok)

      if id_ in (Id.Expr_Null, Id.Expr_True, Id.Expr_False, Id.Char_OneChar, Id.Char_Pound):
      if id_ in (Id.Expr_Null, Id.Expr_True, Id.Expr_False,
                 Id.Char_OneChar, Id.Char_UBraced, Id.Char_Pound):
        return expr.Const(tok)

      raise NotImplementedError(Id_str(id_))

M oil_lang/grammar.pgen2 => oil_lang/grammar.pgen2 +1 -0
@@ 95,6 95,7 @@ atom: (
  | Expr_Float | Expr_DecInt | Expr_BinInt | Expr_OctInt | Expr_HexInt 

  | Char_OneChar  # char literal \n \\ etc.
  | Char_UBraced  # char literal \u{3bc}
  | Char_Pound    # char literal #'a' etc.

    # TODO: Expr_Symbol for %mykey

M spec/oil-expr.test.sh => spec/oil-expr.test.sh +13 -0
@@ 354,6 354,19 @@ echo "$newline $backslash $sq $dq"
10 92 39 34
## END

#### \u{3bc} is char literal
shopt -s oil:all

var mu = \u{3bc}
if (mu == 0x3bc) {  # this is the same!
  echo 'yes'
}
echo "mu $mu"
## STDOUT:
yes
mu 956
## END

#### Pound char literal (is an integer)
const a  = #'a'
const A = #'A'