diff --git a/doc/spec.md b/doc/spec.md
index 08b97b0..75f8859 100644
--- a/doc/spec.md
+++ b/doc/spec.md
@@ -297,7 +297,7 @@ has string, integer, and floating-point literals.
0 # int
123 # decimal int
0x7f # hexadecimal int
-0755 # octal int
+0o755 # octal int
0.0 0. .0 # float
1e10 1e+10 1e-10
@@ -313,7 +313,7 @@ Integer and floating-point literal tokens are defined by the following grammar:
```grammar {.good}
int = decimal_lit | octal_lit | hex_lit .
decimal_lit = ('1' … '9') {decimal_digit} .
-octal_lit = '0' {octal_digit} .
+octal_lit = '0' ('o'|'O') octal_digit {octal_digit} .
hex_lit = '0' ('x'|'X') hex_digit {hex_digit} .
float = decimals '.' [decimals] [exponent]
@@ -361,7 +361,10 @@ every value has a type string that can be obtained with the expression
expression `str(x)`, or to a Boolean truth value using the expression
`bool(x)`. Other operations apply only to certain types. For
example, the indexing operation `a[i]` works only with strings, lists,
-and tuples, and any application-defined types that are _indexable_.
+and tuples, dictionaries, and any application-defined types that are
+_indexable_.
+
The [_value concepts_](#value-concepts) section explains the groupings of
types by the operators they support.
@@ -415,14 +418,13 @@ The `*` operator performs multiplication.
The `//` and `%` operations on integers compute floored division and
remainder of floored division, respectively.
If the signs of the operands differ, the sign of the remainder `x % y`
-matches that of the dividend, `x`.
+matches that of the divisor, `y`.
For all finite x and y (y ≠ 0), `(x // y) * y + (x % y) == x`.
The `/` operator implements real division, and
yields a `float` result even when its operands are both of type `int`.
Integers, including negative values, may be interpreted as bit vectors.
The `|` and `&` operators implement bitwise OR and AND, respectively.
-(This feature is not part of the Java implementation.)
Any bool, number, or string may be interpreted as an integer by using
the `int` built-in function.
@@ -446,6 +448,9 @@ of protocol messages which may contain signed and unsigned 64-bit
integers.
The Java implementation currently supports only signed 32-bit integers.
+Implementation note:
+Bitwise OR and AND operators are not part of the Java implementation.
+
### Floating-point numbers
@@ -454,7 +459,8 @@ double-precision floating-point number. Its [type](#type) is `"float"`.
Arithmetic on floats using the `+`, `-`, `*`, `/`, `//`, and `%`
operators follows the IEE 754 standard.
-However, computing the division or remainder of division by zero is a dynamic error.
+However, computing the division or remainder of division by zero is a dynamic
+error.
An arithmetic operation applied to a mixture of `float` and `int`
operands works as if the `int` operand is first converted to a
@@ -515,8 +521,9 @@ The built-in `len` function returns the number of bytes in a string.
Strings may be concatenated with the `+` operator.
The substring expression `s[i:j]` returns the substring of `s` from
-index `i` up to index `j`. The index expression `s[i]` returns the
-1-byte substring `s[i:i+1]`.
+index `i` up to but not including index `j`. The index expression `s[i]`
+returns the 1-byte substring `s[i:i+1]`. See [Slice expressions
+](#slice-expressions) for more on how substring bounds are interpreted.
Strings are hashable, and thus may be used as keys in a dictionary.
@@ -532,7 +539,7 @@ values, 1-byte substrings, numeric Unicode code points, or 1-code
point substrings, you must explicitly call one of its four methods:
`bytes`, `split_bytes`, `codepoints`, or `split_codepoints`.
-Any value may formatted as a string using the `str` or `repr` built-in
+Any value may be formatted as a string using the `str` or `repr` built-in
functions, the `str % tuple` operator, or the `str.format` method.
A string used in a Boolean context is considered true if it is
@@ -613,7 +620,7 @@ the elements at indices from i to j.
List elements may be added using the `append` or `extend` methods,
removed using the `remove` method, or reordered by assignments such as
-`list[i] = list[j]`.
+`list[i] = list[j]`. (Unlike in Python, slice assignment is not supported.)
The concatenation operation `x + y` yields a new list containing all
the elements of the two lists x and y.
@@ -763,10 +770,14 @@ words = ["able", "baker", "charlie"]
Dictionaries are iterable sequences, so they may be used as the
operand of a `for`-loop, a list comprehension, or various built-in
-functions.
-Iteration yields the dictionary's keys in the order in which they were
-inserted; updating the value associated with an existing key does not
-affect the iteration order.
+functions. Iteration yields the dictionary's keys; the order is deterministic
+but otherwise unspecified.
+
+
```python
x = dict([("a", 1), ("b", 2)]) # {"a": 1, "b": 2}
@@ -824,13 +835,12 @@ Two sets compare equal if they contain the same elements.
Sets are iterable sequences, so they may be used as the operand of a
`for`-loop, a list comprehension, or various built-in functions.
-Iteration yields the set's elements in the order in which they were
-inserted.
+Iteration yields the set's elements, in a deterministic but unspecified order.
+
+
The binary `|` and `&` operators compute union and intersection when
-applied to sets. The right operand of the `|` operator may be any
-iterable value. The binary `in` operator performs a set membership
-test when its right operand is a set.
+applied to sets.
Sets are instantiated by calling the built-in `set` function, which
returns a set containing all the elements of its optional argument,
@@ -855,7 +865,11 @@ A function value used in a Boolean context is always considered true.
Functions defined by a [`def` statement](#function-definitions) are named;
functions defined by a [`lambda` expression](#lambda-expressions) are anonymous.
-Function definitions may be nested, and an inner function may refer to a local variable of an outer function.
+Function definitions may be nested, and an inner function may refer to a local
+variable of an outer function.
+
+Implementation note:
+The Java implementation does not allow lambdas or nested function definitions.
A function definition defines zero or more named parameters.
Skylark has a rich mechanism for passing arguments to functions.
@@ -878,9 +892,9 @@ idiv(6, 3) # 2
```
A call may provide arguments to function parameters either by
-position, as in the example above, or by name, as in first two calls
-below, or by a mixture of the two forms, as in the third call below.
-All the positional arguments must precede all the named arguments.
+position, as in the example above, or by name (also called "keyword"), as in
+the first two calls below, or by a mixture of the two forms, as in the third
+call below. All the positional arguments must precede all the named arguments.
Named arguments may improve clarity, especially in functions of
several parameters.
@@ -909,12 +923,13 @@ f(1, 2) # (1, 2)
f(1) # (1, 3)
```
-If a function parameter's default value is a mutable expression,
-modifications to the value during one call may be observed by
-subsequent calls.
-Beware of this when using lists or dicts as default values.
-If the function becomes frozen, its parameters' default values become
-frozen too.
+If a function parameter's default value is mutable, modifications to the value
+during one call may be observed by subsequent calls. Beware of this when using
+lists or dicts as default values: If the function becomes frozen, its
+parameters' default values become frozen too. It is generally poor style for a
+function to mutate its own parameters' default values. Not only can it harm
+readability, but it is illegal when the function is used from outside its own
+module.
```python
def f(x, list=[]):
@@ -931,10 +946,11 @@ f(3) # error: cannot append to frozen list
Variadic functions: Some functions allow callers to provide an
arbitrary number of arguments.
After all required and optional parameters, a function definition may
-specify a _variadic arguments_ or _varargs_ parameter, indicated by a
-star preceding the parameter name: `*args`.
+specify a _varargs_ ("variadic arguments") parameter, indicated by a star
+preceding the parameter name: `*args`.
Any surplus positional arguments provided by the caller are formed
-into a tuple and assigned to the `args` parameter.
+into a tuple and assigned to the `args` parameter. (If there are no surplus
+positional arguments, the empty tuple is assigned to `args`.)
```python
def f(x, y, *args):
@@ -946,9 +962,8 @@ f(1, 2, 3, 4) # (1, 2, (3, 4))
Keyword-variadic functions: Some functions allow callers to
provide an arbitrary sequence of `name=value` keyword arguments.
-A function definition may include a final _keyworded arguments_ or
-_kwargs_ parameter, indicated by a double-star preceding the parameter
-name: `**kwargs`.
+A function definition may include a final _kwargs_ ("keyword arguments")
+parameter, indicated by a double-star preceding the parameter name: `**kwargs`.
Any surplus named arguments that do not correspond to named parameters
are collected in a new dictionary and assigned to the `kwargs` parameter:
@@ -961,25 +976,40 @@ f(x=2, y=1) # (2, 1, {})
f(x=2, y=1, z=3) # (2, 1, {"z": 3})
```
-It is a static error if any two parameters of a function have the same name.
+It is a static error if any two parameters of a function definition have the
+same name.
-Just as a function definition may accept an arbitrary number of
-positional or keyworded arguments, a function call may provide an
-arbitrary number of positional or keyworded arguments supplied by a
-list or dictionary:
+Just as a function definition may accept an arbitrary number of positional or
+keyword arguments, a function call may provide an arbitrary number of positional
+or keyword arguments. Positional arguments are given by a star-prefixed
+expression that evaluates to a sequence; it must appear after all other
+positional arguments. Keyword arguments are given by a double-star-prefixed
+expression that evaluates to a mapping; it can only appear as the very last
+argument.
```python
def f(a, b, c=5):
return a * b + c
-f(*[2, 3]) # 11
-f(*[2, 3, 7]) # 13
+nums = [2, 3]
+f(*nums) # 11
+f(2, *[3, 7]) # 13
f(*[2]) # error: f takes at least 2 arguments (1 given)
-f(**dict(b=3, a=2)) # 11
-f(**dict(c=7, a=2, b=3)) # 13
-f(**dict(a=2)) # error: f takes at least 2 arguments (1 given)
-f(**dict(d=4)) # error: f got unexpected keyword argument "d"
+nums = {"b": 3, "a": 2}
+f(**nums) # 11
+f(c=7, **{"a": 2, "b": 3}) # 13
+f(**{"a": 2}) # error: f takes at least 2 arguments (1 given)
+f(**{"d": 4}) # error: f got unexpected keyword argument "d"
+```
+
+Positional arguments are bound to parameters before keyword arguments are
+considered. It is a dynamic error if the same argument is specified within a
+call in more than one way.
+
+```python
+f(1, 2, b=2) # error: b given both positionally and as keyword
+f(1, b=2, *[2, 3], {"c": 3}) # error: b and c are both given twice
```
Once the parameters have been successfully bound to the arguments
@@ -1006,8 +1036,8 @@ f(-1) # returns 1 without printing
```
-It is a dynamic error for a function to call itself or another
-function value with the same declaration.
+It is a dynamic error for a function to call itself either directly or
+indirectly.
```python
def fib(x):
@@ -1032,14 +1062,13 @@ over finite sequences, implies that Skylark programs are not Turing-complete.
### Built-ins
-A Built-in is a function or method implemented in Go by the interpreter
-or the application into which the interpreter is embedded.
+A built-in is a function or method implemented by the interpreter or by the
+application into which the interpreter is embedded.
The [type](#type) of a built-in is `"builtin"`.
A builtin value used in a Boolean context is always considered true.
Many built-ins are defined in the "universe" block of the environment
-(see [Name Resolution](#name-resolution)), and are thus available to
-all Skylark programs.
+(see [Name Resolution](#name-resolution)), and are thus available by default.
Except where noted, built-ins accept only positional arguments.
The parameter names serve merely as documentation.
@@ -1220,7 +1249,7 @@ The [dot expression](#dot-expressions) `.split` is a dynamic operation
on the value returned by `get_filename()`.
-## Value concepts {#value-concepts}
+## Value concepts (#value-concepts)
Skylark has eleven core [data types](#data-types). An application
that embeds the Skylark intepreter may define additional types that
@@ -1228,7 +1257,8 @@ behave like Skylark values. All values, whether core or
application-defined, implement a few basic behaviors:
```text
-str(x) -- return a string representation of x
+str(x) -- return a string description of x
+repr(x) -- return a string representation of x
type(x) -- return a string describing the type of x
freeze(x) -- make x, and everything it transitively refers to, immutable
bool(x) -- convert x to a Boolean truth value
@@ -1247,20 +1277,19 @@ Values of some data types, such as `NoneType`, `bool`, `int`, `float`, and
`string`, are _immutable_; they can never change.
Immutable values have no notion of _identity_: it is impossible for a
Skylark program to tell whether two integers, for instance, are
-represented by the same object; it can tell only whether they are
+represented by the same object in memory; it can tell only whether they are
equal.
Values of other data types, such as `list`, `dict`, and `set`, are
_mutable_: they may be modified by a statement such as `a[i] = 0` or
`items.clear()`. Although `tuple` and `function` values are not
directly mutable, they may refer to mutable values indirectly, so for
-this reason we consider them mutable too. Skylark values of these
-types are actually _references_ to variables.
+this reason we consider them mutable too.
-Copying a reference to a variable, using an assignment statement for
-instance, creates an _alias_ for the variable, and the effects of
-operations applied to the variable through one alias are visible
-through all others.
+Skylark values are held in variables and in other values via _references_.
+For instance, when the assignment statement binds a variable to a value, it
+creates an _alias_ for the value. The effects of operations applied to the
+value through one alias are visible through all others.
```python
x = [] # x refers to a new empty list variable
@@ -1521,7 +1550,7 @@ Primary = int | float | string
Evaluation of a literal yields a value of the given type (string, int,
or float) with the given value.
-See [Literals](#lexical elements) for details.
+See [Literals](#lexical-elements) for details.
### Parenthesized expressions
@@ -2984,6 +3013,9 @@ See also: `chr`.
Arguments are formatted as if by `str(x)` and separated with a space.
Keyword arguments are preceded by their name.
+
+
Example:
```python
@@ -3018,7 +3050,12 @@ range(10, 3, -2) # [10, 8, 6, 4]
`repr(x)` formats its argument as a string.
-All strings in the result are double-quoted.
+The exact result is implementation-dependent. By convention, application-defined
+types should choose a repr format that, if executed as a source code expression,
+can reproduce the given value. If that is not possible, the repr result should
+ideally be enclosed in angled brackets.
+
+
```python
repr(1) # '1'
@@ -3076,10 +3113,24 @@ The Java implementation does not support the `cmp`, `key`, and
### str
-`str(x)` formats its argument as a string.
+`str(x)` formats its argument as a human-readable string.
+
+The exact result is implementation-dependent.
-If x is a string, the result is x (without quotation).
-All other strings, such as elements of a list of strings, are double-quoted.
+
```python
str(1) # '1'
@@ -3893,7 +3944,7 @@ eventually to eliminate all such differences on a case-by-case basis.
* The `set` built-in is provided (option: `-set`).
* `x += y` rebindings are permitted at top level.
* `assert` is a valid identifier.
-* `&` is a token; `int & int` and `set & set` are supported.
+* `&` is a token; `int & int` is supported.
* `int | int` is supported.
* The `freeze` built-in is provided (option: `-freeze`).
* The parser accepts unary `+` expressions.
@@ -3901,4 +3952,5 @@ eventually to eliminate all such differences on a case-by-case basis.
* Dot expressions may appear on the left side of an assignment: `x.f = 1`.
* `hash` accepts operands besides strings.
* `sorted` accepts the additional parameters `cmp`, `key`, and `reversed`.
+* The `cmp` builtin exists.
* The `dict` type has a `clear` method.