Avoid depending on stdlib variable for desugaring.

The fix is easy – we just use "$std" which the user cannot access,
because it's not a valid identifier.
This commit is contained in:
Stanisław Barzowski 2021-08-08 15:48:47 +01:00
parent 51daeb3229
commit b00b56c335
8 changed files with 10818 additions and 10472 deletions

File diff suppressed because it is too large Load Diff

View File

@ -251,7 +251,7 @@ func buildSimpleIndex(obj ast.Node, member ast.Identifier) ast.Node {
} }
func buildStdCall(builtinName ast.Identifier, loc ast.LocationRange, args ...ast.Node) ast.Node { func buildStdCall(builtinName ast.Identifier, loc ast.LocationRange, args ...ast.Node) ast.Node {
std := &ast.Var{Id: "std"} std := &ast.Var{Id: "$std"}
builtin := buildSimpleIndex(std, builtinName) builtin := buildSimpleIndex(std, builtinName)
positional := make([]ast.CommaSeparatedExpr, len(args)) positional := make([]ast.CommaSeparatedExpr, len(args))
for i := range args { for i := range args {

View File

@ -164,5 +164,5 @@ func analyzeVisit(a ast.Node, inObject bool, vars ast.IdentifierSet) error {
// It enriches the AST with additional information about free variables in every node, // It enriches the AST with additional information about free variables in every node,
// so it is necessary to always run it before executing the AST. // so it is necessary to always run it before executing the AST.
func analyze(node ast.Node) error { func analyze(node ast.Node) error {
return analyzeVisit(node, false, ast.NewIdentifierSet("std")) return analyzeVisit(node, false, ast.NewIdentifierSet("std", "$std"))
} }

View File

@ -1183,8 +1183,16 @@ func buildStdObject(i *interpreter) (*valueObject, error) {
} }
func evaluateStd(i *interpreter) (value, error) { func evaluateStd(i *interpreter) (value, error) {
// We are bootstrapping std before it is properly available.
// We need "$std" for desugaring.
// So, we're creating an empty thunk (evaluating will panic).
// We will fill it manually before it's evaluated, though.
// This "std" does not have std.thisFile.
stdThunk := &cachedThunk{}
beforeStdEnv := makeEnvironment( beforeStdEnv := makeEnvironment(
bindingFrame{}, bindingFrame{
"$std": stdThunk,
},
makeUnboundSelfBinding(), makeUnboundSelfBinding(),
) )
evalLoc := ast.MakeLocationRangeMessage("During evaluation of std") evalLoc := ast.MakeLocationRangeMessage("During evaluation of std")
@ -1192,7 +1200,12 @@ func evaluateStd(i *interpreter) (value, error) {
node := astgen.StdAst node := astgen.StdAst
i.stack.setCurrentTrace(evalTrace) i.stack.setCurrentTrace(evalTrace)
defer i.stack.clearCurrentTrace() defer i.stack.clearCurrentTrace()
return i.EvalInCleanEnv(&beforeStdEnv, node, false) content, err := i.EvalInCleanEnv(&beforeStdEnv, node, false)
if err != nil {
return nil, err
}
stdThunk.content = content
return content, nil
} }
func prepareExtVars(i *interpreter, ext vmExtMap, kind string) map[string]*cachedThunk { func prepareExtVars(i *interpreter, ext vmExtMap, kind string) map[string]*cachedThunk {
@ -1243,9 +1256,13 @@ func makeInitialEnv(filename string, baseStd *valueObject) environment {
fileSpecific := buildObject(ast.ObjectFieldHidden, map[string]value{ fileSpecific := buildObject(ast.ObjectFieldHidden, map[string]value{
"thisFile": makeValueString(filename), "thisFile": makeValueString(filename),
}) })
stdThunk := readyThunk(makeValueExtendedObject(baseStd, fileSpecific))
return makeEnvironment( return makeEnvironment(
bindingFrame{ bindingFrame{
"std": readyThunk(makeValueExtendedObject(baseStd, fileSpecific)), "std": stdThunk,
"$std": stdThunk, // Unavailable to the user. To be used with desugaring.
}, },
makeUnboundSelfBinding(), makeUnboundSelfBinding(),
) )

View File

@ -62,7 +62,7 @@ func lint(vm *jsonnet.VM, nodes []nodeWithLocation, errWriter *ErrorWriter) {
} }
findVariables := func(node nodeWithLocation) *common.VariableInfo { findVariables := func(node nodeWithLocation) *common.VariableInfo {
return variables.FindVariables(node.node, variables.Environment{"std": &std}) return variables.FindVariables(node.node, variables.Environment{"std": &std, "$std": &std})
} }
for importedPath, rootNode := range roots { for importedPath, rootNode := range roots {

View File

@ -0,0 +1,6 @@
[
{ },
[ ],
42,
false
]

View File

@ -0,0 +1,8 @@
// Make sure shadowing std does not cause problems for desugaring.
local std = {};
[
{ [x]: 17 for x in [] },
[ x for x in [] ],
42 % 2137,
"foo" in {},
]

View File

@ -0,0 +1,5 @@
../testdata/overriding_stdlib_desugared:2:7-15 Unused variable: std
local std = {};