source | all docs for version 0.10.0 | all versions | oilshell.org
Warning: Work in progress! Leave feedback on Zulip or Github if you'd like this doc to be updated.
Recall that Oil is composed of three interleaved languages: words, commands, and expressions.
This doc describes expressions, but only the things that are not in:
#expr-lang
section of Oil Help
Topics. A reference.TODO: This doc should have example shell sessions, like the tour does.
For a short summary, see Oil vs. Python.
All Substitutions: $myvar
, $(hostname)
, etc.
Variable subs:
echo $myvar
var x = $myvar
Command subs:
echo $(hostname)
var x = $(hostname) # no quotes necessary
var y = "name is $(hostname)"
String Literals:
echo 'foo'
var x = 'foo'
echo "hello $name"
Oil has 3 kinds of string literal. See the docs in the intro for detail, as well as the Strings doc.
As a detail, Oil disallows this case:
$ var x = '\n'
var x = '\n'
^~
[ interactive ]:1: Strings with backslashes should look like r'\n' or $'\n'
In expression mode, you're forced to specify an explicit r
or $
when the
string has backslashes. This is because shell has the opposite default as
Python: In shell, unadorned strings are raw. In Python, unadorned strings
respect C escapes.
1.23e-10
. Except:
.
now1_000_000.123_456
because that was hard to implement as a hand-written
Python regex.Those last two caveats about floats are TODOs: https://github.com/oilshell/oil/issues/483
There is a single list type, but it has two syntaxes:
%(one two three)
for an "array" of strings. This is equivalent to ['one', 'two', 'three']
.[1, [2, 'three', {}]]
for arbitrary Python-like "lists".Longer example:
var x = %(a b c)
var x = %(
'single quoted'
"double quoted"
$'c string'
glob/*.py
brace-{a,b,c}-{1..3}
)
Dict literals use JavaScript's rules, which are similar but not identical to Python.
The key can be either a bare word or bracketed expression.
(1) For example, {age: 30}
means what {'age': 30}
does in Python. That is,
age
is not the name of a variable. This fits more with the "dict as ad
hoc struct" philosophy.
(2) In {[age]: 30}
, age
is a variable. You can put an arbitrary expression
in there like {['age'.upper()]: 30}
. (Note: Lua also has this bracketed key
syntax.)
(3) {age, key2}
is the same as {age: age, key2: key2}
. That is, if the
name is a bare word, you can leave off the value, and it will be looked up in
the context where the dictionary is defined.
This is what ES2015 calls "shorthand object properties":
TODO:
var myblock = ^(ls | wc -l)
Like JavaScript, Oil has two types of equality, but uses ===
and ~==
rather
than ===
and ==
.
=== !==
'42' === 42
is not just false, but it's an
error.~==
!==
. Use not (a ~== b)
instead.Str
onlyStr
, Int
, Bool
Examples:
' foo ' ~== 'foo' # whitespace stripped on LEFT only
' 42 ' ~== 42
' TRue ' ~== true # true, false, 0, 1, and I think T, F
Currently, there are no semantics for floats, so none of these work:
' 42.0 ' ~== 42
' 42 ' ~== 42.0
42.0 ~== 42
42 ~== 42.0
(Should float_equals()
be a separate function?)
var result = add(x, y)
var result = foo(x, named='default')
if (s.startswith('prefix')) {
echo yes
}
Use Cases:
var d = {1: 2, 3: 4}
const k = keys(d)
not
and
or
Like Python.
var cond = true
var x = 'yes' if cond else 'no'
TODO: All of these do string -> int conversion, like
'1_000' => 1000
'0xff' => 255
'0o010' => 8
'0b0001_0000' => 32
+ - * / // %
and **
Like Python.
~ & | ^ << >>
Like Python.
< <= > >=
is
and is not
? Not sure I want identity in the language?https://github.com/oilshell/oil/blob/master/spec/oil-expr.test.sh#L550
if (1 < 2 <= 2 <= 3 < 4) {
echo '123'
}
This syntax is directly from Python. That is,
x op y op z
is a shortcut for
x op y and y op z
Comments welcome!
~
and ~~
~
!~
[[ $x =~ $pat ]]
~~
!~~
[[ $x == *.py ]]
In addition to pattern matching.
++
s ++ 'suffix'
L ++ [1, 2] ++ %(a b)
a[i]
var s = 'foo'
var second = s[1] # are these integers though? maybe slicing gives you things of length 1
echo $second # 'o'
var a = %(spam eggs ham)
var second = a[1]
echo $second # => 'eggs'
echo $[a[-1]] # => ham
Semantics are like Python: Out of bounds is an error.
a[i:j]
var s = 'food'
var slice = s[1:3]
echo $second # 'oo'
var a = %(spam eggs ham)
var slice = a[1:3]
write -- @slice # eggs, ham
Semantics are like Python: Out of bounds is not an error.
in
not in
d->key
is a shortcut for d['key']
the distinction between attributes and dictionary members always seemed weird and unnecessary to me.
I've been thinking about this for the Oil language, which is heavily influenced by Python.
The problem is that dictionary attributes come from user data, i.e. from JSON,
while methods like .keys()
come from the interpreter, and Python allows you
to provide user-defined methods like mydict.mymethod()
too.
Mixing all of those things in the same namespace seems like a bad idea.
In Oil I might do introduce an ->
operator, so d->mykey
is a shortcut for
d['mykey']
.
d.keys(), d.values(), d.items() # methods
d->mykey
d['mykey']
Maybe you could disallow user-defined attributes on dictionaries, and make them free:
keys(d), values(d), items(d)
d.mykey # The whole namespace is available for users
However I don't like that this makes dictionaries a special case. Thoughts?
List comprehensions might be useful for a "faster" for loop? It only does expressions?
*
and **
Python allows splatting into lists:
a = [1, 2]
b = [*a, 3]
And dicts:
d = {'name': 'alice'}
d2 = {**d, age: 42}
1:n
(vs slices)Deferred because you can use
for i in @(seq $n) {
echo $i
}
This gives you strings but that's OK for now. We don't yet have a "fast" for loop.
Notes:
start:end
, it doesn't have start:end:step
start:step:end
!a[::2]
.range(0, n)
.a[:n]
and a[3:]
.Str*
is a problem. Nul, etc.
if (mystr)
vs if (len(mystr))
42
and 3.14
and 1e100
value = ... | dict[str, value]