aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/skylark/skylark.go1
-rw-r--r--doc/impl.md8
-rw-r--r--doc/spec.md28
-rw-r--r--eval_test.go1
-rw-r--r--library.go14
-rw-r--r--resolve/resolve.go4
-rw-r--r--resolve/resolve_test.go1
-rwxr-xr-xskylarkbin0 -> 3880822 bytes
-rw-r--r--skylarktest/assert.sky3
-rw-r--r--skylarktest/skylarktest.go13
-rw-r--r--testdata/assign.sky2
-rw-r--r--testdata/dict.sky2
-rw-r--r--testdata/function.sky4
-rw-r--r--testdata/list.sky2
14 files changed, 30 insertions, 53 deletions
diff --git a/cmd/skylark/skylark.go b/cmd/skylark/skylark.go
index d236269..e403f3b 100644
--- a/cmd/skylark/skylark.go
+++ b/cmd/skylark/skylark.go
@@ -55,7 +55,6 @@ var (
// non-standard dialect flags
func init() {
flag.BoolVar(&resolve.AllowFloat, "fp", resolve.AllowFloat, "allow floating-point numbers")
- flag.BoolVar(&resolve.AllowFreeze, "freeze", resolve.AllowFreeze, "add freeze built-in function")
flag.BoolVar(&resolve.AllowSet, "set", resolve.AllowSet, "allow set data type")
flag.BoolVar(&resolve.AllowLambda, "lambda", resolve.AllowLambda, "allow lambda expressions")
flag.BoolVar(&resolve.AllowNestedDef, "nesteddef", resolve.AllowNestedDef, "allow nested def statements")
diff --git a/doc/impl.md b/doc/impl.md
index 6ac20e0..588a59f 100644
--- a/doc/impl.md
+++ b/doc/impl.md
@@ -147,10 +147,10 @@ simple bit flip, no need to traverse the object graph---but coarser
grained. Also, it complicates the API slightly because to construct a
list, say, requires a reference to the frozen flag it should use.
-The Go implementation also permits the `freeze` built-in to be exposed
-to the program. (This requires the `-freeze` dialect flag.) This has
-proven valuable in writing tests of the freeze mechanism itself, but
-is mostly a curiosity.
+The Go implementation would also permit the freeze operation to be
+exposed to the program, for example as a built-in function.
+This has proven valuable in writing tests of the freeze mechanism
+itself, but is otherwise mostly a curiosity.
### Fail-fast iterators
diff --git a/doc/spec.md b/doc/spec.md
index b48d5d1..14a79a4 100644
--- a/doc/spec.md
+++ b/doc/spec.md
@@ -116,7 +116,6 @@ concurrency, and other such features of Python.
* [dir](#dir)
* [enumerate](#enumerate)
* [float](#float)
- * [freeze](#freeze)
* [getattr](#getattr)
* [hasattr](#hasattr)
* [hash](#hash)
@@ -916,6 +915,7 @@ If the function becomes frozen, its parameters' default values become
frozen too.
```python
+# module a.sky
def f(x, list=[]):
list.append(x)
return list
@@ -923,7 +923,9 @@ def f(x, list=[]):
f(4, [1,2,3]) # [1, 2, 3, 4]
f(1) # [1]
f(2) # [1, 2], not [2]!
-freeze(f)
+
+# module b.sky
+load("a.sky", "f")
f(3) # error: cannot append to frozen list
```
@@ -1235,7 +1237,6 @@ application-defined, implement a few basic behaviors:
```text
str(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
hash(x) -- return a hash code for x
```
@@ -1311,13 +1312,6 @@ and .bzl files in parallel, and two modules being executed
concurrently may freely access variables or call functions from a
third without the possibility of a race condition.
-<b>Implementation note:</b>
-The Go implementation of Skylark permits user code to freeze arbitrary
-values by calling the `freeze` built-in function.
-This feature must be enabled in the REPL by the `-freeze` flag.
-This function is not present in the Java implementation, which freezes
-values only _en masse_ at the end of module initialization.
-
### Hashing
The `dict` and `set` data types are implemented using hash tables, so
@@ -2850,19 +2844,6 @@ function, and the real division operator `/`.
The Java implementation does not yet support floating-point numbers.
-### freeze
-
-`freeze(x)` freezes x and all values transitively reachable from it.
-Subsequent attempts to modify any of those values will fail.
-
-At the end of module execution, the value of each global in the module
-dictionary is frozen as if by `freeze`.
-
-<b>Implementation note:</b>
-The `freeze` function is an optional feature of the Go implementation,
-and it must be enabled in the REPL using the `-freeze` flag.
-It is not present in the Java implementation.
-
### getattr
`getattr(x, name)` returns the value of the attribute (field or method) of x named `name`.
@@ -3922,7 +3903,6 @@ eventually to eliminate all such differences on a case-by-case basis.
* `assert` is a valid identifier.
* `&` is a token; `int & int` and `set & set` are supported.
* `int | int` is supported.
-* The `freeze` built-in function is provided (option: `-freeze`).
* The parser accepts unary `+` expressions.
* A method call `x.f()` may be separated into two steps: `y = x.f; y()`.
* Dot expressions may appear on the left side of an assignment: `x.f = 1`.
diff --git a/eval_test.go b/eval_test.go
index 6c24078..e74445c 100644
--- a/eval_test.go
+++ b/eval_test.go
@@ -24,7 +24,6 @@ func init() {
resolve.AllowLambda = true
resolve.AllowNestedDef = true
resolve.AllowFloat = true
- resolve.AllowFreeze = true
resolve.AllowSet = true
}
diff --git a/library.go b/library.go
index 7f1e7cb..1da0547 100644
--- a/library.go
+++ b/library.go
@@ -46,8 +46,7 @@ func init() {
"dict": NewBuiltin("dict", dict),
"dir": NewBuiltin("dir", dir),
"enumerate": NewBuiltin("enumerate", enumerate),
- "float": NewBuiltin("float", float), // requires resolve.AllowFloat
- "freeze": NewBuiltin("freeze", freeze), // requires resolve.AllowFreeze
+ "float": NewBuiltin("float", float), // requires resolve.AllowFloat
"getattr": NewBuiltin("getattr", getattr),
"hasattr": NewBuiltin("hasattr", hasattr),
"hash": NewBuiltin("hash", hash),
@@ -506,17 +505,6 @@ func float(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error
}
}
-func freeze(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
- if len(kwargs) > 0 {
- return nil, fmt.Errorf("freeze does not accept keyword arguments")
- }
- if len(args) != 1 {
- return nil, fmt.Errorf("freeze got %d arguments, wants 1", len(args))
- }
- args[0].Freeze()
- return args[0], nil
-}
-
// https://github.com/google/skylark/blob/master/doc/spec.md#getattr
func getattr(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
var object, dflt Value
diff --git a/resolve/resolve.go b/resolve/resolve.go
index d0c818a..4649914 100644
--- a/resolve/resolve.go
+++ b/resolve/resolve.go
@@ -84,7 +84,6 @@ var (
AllowNestedDef = false // allow def statements within function bodies
AllowLambda = false // allow lambda expressions
AllowFloat = false // allow floating point literals, the 'float' built-in, and x / y
- AllowFreeze = false // allow the 'freeze' built-in
AllowSet = false // allow the 'set' built-in
AllowGlobalReassign = false // allow reassignment to globals declared in same file (deprecated)
)
@@ -346,9 +345,6 @@ func (r *resolver) useGlobal(id *syntax.Ident) (scope Scope) {
if !AllowSet && id.Name == "set" {
r.errorf(id.NamePos, doesnt+"support sets")
}
- if !AllowFreeze && id.Name == "freeze" {
- r.errorf(id.NamePos, doesnt+"provide the 'freeze' built-in function")
- }
} else {
scope = Undefined
r.errorf(id.NamePos, "undefined: %s", id.Name)
diff --git a/resolve/resolve_test.go b/resolve/resolve_test.go
index 11e953c..cfd7ddf 100644
--- a/resolve/resolve_test.go
+++ b/resolve/resolve_test.go
@@ -27,7 +27,6 @@ func TestResolve(t *testing.T) {
resolve.AllowNestedDef = option(chunk.Source, "nesteddef")
resolve.AllowLambda = option(chunk.Source, "lambda")
resolve.AllowFloat = option(chunk.Source, "float")
- resolve.AllowFreeze = option(chunk.Source, "freeze")
resolve.AllowSet = option(chunk.Source, "set")
resolve.AllowGlobalReassign = option(chunk.Source, "global_reassign")
diff --git a/skylark b/skylark
new file mode 100755
index 0000000..886686d
--- /dev/null
+++ b/skylark
Binary files differ
diff --git a/skylarktest/assert.sky b/skylarktest/assert.sky
index d1dfeee..ca66a6f 100644
--- a/skylarktest/assert.sky
+++ b/skylarktest/assert.sky
@@ -5,6 +5,7 @@
# catch(f): evaluate f() and returns its evaluation error message, if any
# matches(str, pattern): report whether str matches regular expression pattern.
# struct: a constructor for a simple HasFields implementation.
+# freeze(x): freeze the value x and everything reachable from it.
#
# Clients may use these functions to define their own testing abstractions.
@@ -36,6 +37,8 @@ def _fails(f, pattern):
elif not matches(pattern, msg):
error("regular expression (%s) did not match error (%s)" % (pattern, msg))
+freeze = freeze # an exported global whose value is the built-in freeze function
+
assert = struct(
fail = error,
eq = _eq,
diff --git a/skylarktest/skylarktest.go b/skylarktest/skylarktest.go
index 3c09571..6db139d 100644
--- a/skylarktest/skylarktest.go
+++ b/skylarktest/skylarktest.go
@@ -64,6 +64,7 @@ func LoadAssertModule() (skylark.StringDict, error) {
"catch": skylark.NewBuiltin("catch", catch),
"matches": skylark.NewBuiltin("matches", matches),
"struct": skylark.NewBuiltin("struct", skylarkstruct.Make),
+ "freeze": skylark.NewBuiltin("freeze", freeze),
}
filename := DataFile("skylark/skylarktest", "assert.sky")
thread := new(skylark.Thread)
@@ -116,6 +117,18 @@ func error_(thread *skylark.Thread, _ *skylark.Builtin, args skylark.Tuple, kwar
return skylark.None, nil
}
+// freeze(x) freezes its operand.
+func freeze(thread *skylark.Thread, _ *skylark.Builtin, args skylark.Tuple, kwargs []skylark.Tuple) (skylark.Value, error) {
+ if len(kwargs) > 0 {
+ return nil, fmt.Errorf("freeze does not accept keyword arguments")
+ }
+ if len(args) != 1 {
+ return nil, fmt.Errorf("freeze got %d arguments, wants 1", len(args))
+ }
+ args[0].Freeze()
+ return args[0], nil
+}
+
// DataFile returns the effective filename of the specified
// test data resource. The function abstracts differences between
// 'go build', under which a test runs in its package directory,
diff --git a/testdata/assign.sky b/testdata/assign.sky
index 194165b..556041f 100644
--- a/testdata/assign.sky
+++ b/testdata/assign.sky
@@ -242,7 +242,7 @@ assert.eq(z[0], 1)
---
# assignment to/from fields.
-load("assert.sky", "assert")
+load("assert.sky", "assert", "freeze")
hf = hasfields()
hf.x = 1
diff --git a/testdata/dict.sky b/testdata/dict.sky
index 6e6f1e5..e948e72 100644
--- a/testdata/dict.sky
+++ b/testdata/dict.sky
@@ -1,6 +1,6 @@
# Tests of Skylark 'dict'
-load("assert.sky", "assert")
+load("assert.sky", "assert", "freeze")
# literals
assert.eq({}, {})
diff --git a/testdata/function.sky b/testdata/function.sky
index e936c16..a86c703 100644
--- a/testdata/function.sky
+++ b/testdata/function.sky
@@ -5,7 +5,7 @@
# and test that functions have correct position, free vars, names of locals, etc.
# - move the hard-coded tests of parameter passing from eval_test.go to here.
-load("assert.sky", "assert")
+load("assert.sky", "assert", "freeze")
# Test lexical scope and closures:
def outer(x):
@@ -104,7 +104,7 @@ assert.eq(len(hashes), 1)
---
# Default values of function parameters are mutable.
-load("assert.sky", "assert")
+load("assert.sky", "assert", "freeze")
def f(x=[0]):
return x
diff --git a/testdata/list.sky b/testdata/list.sky
index 2b50ce3..d2409df 100644
--- a/testdata/list.sky
+++ b/testdata/list.sky
@@ -1,6 +1,6 @@
# Tests of Skylark 'list'
-load("assert.sky", "assert")
+load("assert.sky", "assert", "freeze")
# literals
assert.eq([], [])