this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

simplify and generalize `@extern` support

Currently `@extern` attribute support has a few limitations
and issues:

- it only allows a single `@extern` kind per file, which means we can't
mix different kinds of `@extern` attribute (for example injection and
embedding)
- it only allows a single extern attribute of a given kind in a field,
even though it's fine to define two instances of the same field, each
with an extern attribute.
- it allows embedding an extern attribute, but only when inside a field
definition
- it is not allowed to include an extern attribute at the top level of a
file or as the value of a pattern constraint or dynamic field.
- it gets the semantics wrong when injecting an external value into an
expression.

An example of the last issue:

```
exec cue mod init
exec cue export .
-- foo.cue --
@extern(embed)

package foo

a: {
blah: *false | bool
@embed(file=foo.json)
}.blah

-- foo.json --
{"blah": true}
```

One might expect the above example to succeed: the `foo.json` value
substituted at the position of the `@embed` attribute and unified with
the `blah: *false|bool` field before the `.blah` selector is applied.
Unfortunately we actually we an error in this case:

```
> exec cue export .
[stderr]
a: 2 errors in empty disjunction:
a: conflicting values {blah:true} and bool (mismatched types struct and bool):
./foo.cue:5:4
./foo.cue:6:20
foo.json:1:3
a: conflicting values {blah:true} and false (mismatched types struct and bool):
./foo.cue:5:4
./foo.cue:6:12
foo.json:1:3
[exit status 1]
FAIL: x.txtar:2: unexpected command failure
```

This error happens because the extern logic adds the conjunction to the
innermost field (`a` in this case) even when inside some other
expression.

This change fixes all the above issues, making extern support
significantly more general.

Specifically:
- when an extern attribute appears on a field, its value is unified with the field's value
- when an extern attribute appears as an embedded attribute, its value is included
at the site of the embedding.

There are no other restrictions.

Thus:
- it allows any number of `@extern` attributes in a file
- it allows any number of extern attributes on a field or at embedding
level
- it allows an extern attribute on any field, even a field without a
regular label name. The label name is there as a hint for the
interpreter, but it doesn't seem to me that it should be mandatory (and
indeed the `@embed` interpreter ignores it).
- an embedded extern attribute is _not_ associated with a field: its
value is substituted in place, and any name must be provided explicitly.
Technically this is a breaking change, but as `embed` is the only
interpreter currently in wide use and it ignores the field name, this
should not affect any users.

Thus the following test now passes:

```
exec cue mod init
exec cue export .
cmp stdout want-stdout
-- foo.cue --
@extern(embed)

package foo

@embed(file=foo.json)
@embed(file=foo2.json)

a: {
blah: *false | bool
@embed(file=foo.json)
}.blah

-- foo.json --
{"blah": true}
-- foo2.json --
{"other": true}
-- want-stdout --
{
"a": true,
"blah": true,
"other": true
}
```

We also remove support for the legacy (and never fully enabled) non-file-level `@extern`
syntax, which hopefully no-one is using - it's certainly never been documented.
So this code will no longer work:

```
@extern(embed)

package foo

x: _ @extern(file=foo.json)
```

Signed-off-by: Roger Peppe <rogpeppe@gmail.com>
Change-Id: I707778dd20bb69b4fb7a4d7327dbe7b9307a1850
Reviewed-on: https://cue.gerrithub.io/c/cue-lang/cue/+/1233920
Reviewed-by: Matthew Sackman <matthew@cue.works>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>

+242 -250
+45 -33
cmd/cue/cmd/testdata/script/embed_nonfield.txtar
··· 1 1 cd $WORK/toplevel 2 - ! exec cue export 3 - cmp stdout want-stderr 2 + exec cue export 3 + cmp stdout want-stdout 4 4 5 5 cd $WORK/toplevel_multi 6 - ! exec cue export 7 - cmp stderr want-stderr 6 + exec cue export 7 + cmp stdout want-stdout 8 8 9 9 cd $WORK/inside_expr 10 - ! exec cue export 11 - cmp stderr want-stderr 10 + exec cue export 11 + cmp stdout want-stdout 12 12 13 13 cd $WORK/field_multi 14 - ! exec cue export 15 - cmp stderr want-stderr 14 + exec cue export 15 + cmp stdout want-stdout 16 16 17 17 cd $WORK/dynamic_field 18 - ! exec cue export 19 - cmp stdout want-stderr 18 + exec cue export 19 + cmp stdout want-stdout 20 20 21 21 cd $WORK/pattern_field 22 - ! exec cue export 23 - cmp stdout want-stderr 22 + exec cue export 23 + cmp stdout want-stdout 24 24 25 25 -- cue.mod/module.cue -- 26 26 module: "cue.example" 27 27 language: version: "v0.11.0" 28 28 29 - -- toplevel/want-stderr -- 29 + -- toplevel/want-stdout -- 30 + { 31 + "x": true 32 + } 30 33 -- toplevel/x.cue -- 31 34 @extern(embed) 32 35 ··· 35 38 -- toplevel/x.json -- 36 39 {"x": true} 37 40 38 - -- toplevel_multi/want-stderr -- 39 - @embed attribute not associated with field: 40 - ./x.cue:3:1 41 - @embed attribute not associated with field: 42 - ./x.cue:4:1 41 + -- toplevel_multi/want-stdout -- 42 + { 43 + "x": true, 44 + "y": true 45 + } 43 46 -- toplevel_multi/x.cue -- 44 47 @extern(embed) 45 48 package toplevel_multi ··· 50 53 -- toplevel_multi/y.json -- 51 54 {"y": true} 52 55 53 - -- inside_expr/want-stderr -- 54 - a: 2 errors in empty disjunction: 55 - a: conflicting values {x:true} and bool (mismatched types struct and bool): 56 - ./x.cue:3:4 57 - ./x.cue:4:17 58 - x.json:1:3 59 - a: conflicting values {x:true} and false (mismatched types struct and bool): 60 - ./x.cue:3:4 61 - ./x.cue:4:9 62 - x.json:1:3 56 + -- inside_expr/want-stdout -- 57 + { 58 + "a": true 59 + } 63 60 -- inside_expr/x.cue -- 64 61 @extern(embed) 65 62 package inside_expr ··· 70 67 -- inside_expr/x.json -- 71 68 {"x": true} 72 69 73 - -- field_multi/want-stderr -- 74 - duplicate @embed attributes: 75 - ./x.cue:3:26 70 + -- field_multi/want-stdout -- 71 + { 72 + "a": { 73 + "x": true, 74 + "y": true 75 + } 76 + } 76 77 -- field_multi/x.cue -- 77 78 @extern(embed) 78 79 package field_multi ··· 82 83 -- field_multi/y.json -- 83 84 {"y": true} 84 85 85 - -- dynamic_field/want-stderr -- 86 + -- dynamic_field/want-stdout -- 87 + { 88 + "a": "foo", 89 + "foo": { 90 + "a": true 91 + } 92 + } 86 93 -- dynamic_field/x.cue -- 87 94 @extern(embed) 88 95 package dynamic_field ··· 92 99 -- dynamic_field/x.json -- 93 100 {"a": true} 94 101 95 - -- pattern_field/want-stderr -- 102 + -- pattern_field/want-stdout -- 103 + { 104 + "x": { 105 + "a": true 106 + } 107 + } 96 108 -- pattern_field/x.cue -- 97 109 @extern(embed) 98 110 package dynamic_field
+154 -166
internal/core/runtime/extern.go
··· 83 83 84 84 // externDecorator locates extern attributes and calls the relevant interpreters 85 85 // to inject builtins. 86 - // 87 - // This is a two-pass algorithm: in the first pass, all ast.Files are processed 88 - // to build an index from *ast.Fields to attributes. In the second phase, the 89 - // corresponding adt.Fields are located in the ADT and decorated with the 90 - // builtins. 91 86 type externDecorator struct { 92 87 runtime *Runtime 93 88 pkg *build.Instance 94 89 95 90 compilers map[string]Compiler 96 - fields map[*ast.Field]fieldInfo 97 91 98 - errs errors.Error 99 - } 92 + // fileKinds maps each AST file to the set of extern kinds declared in it. 93 + fileKinds map[*token.File]map[string]bool 100 94 101 - type fieldInfo struct { 102 - extern string 103 - funcName string 104 - attrBody string 105 - attr *ast.Attribute 95 + errs errors.Error 106 96 } 107 97 108 98 // addFile finds injection points in the given ast.File for external 109 99 // implementations of Builtins. 110 100 func (d *externDecorator) addFile(f *ast.File) (errs errors.Error) { 111 - kind, pos, decls, err := findExternFileAttr(f) 112 - if len(decls) == 0 { 101 + kinds, _, err := findExternFileAttrs(f) 102 + if err != nil { 113 103 return err 114 104 } 105 + if len(kinds) == 0 { 106 + return nil 107 + } 115 108 116 - ok, err := d.initCompiler(kind, pos) 117 - if !ok { 118 - return err 109 + if d.fileKinds == nil { 110 + d.fileKinds = map[*token.File]map[string]bool{} 119 111 } 112 + km := make(map[string]bool) 113 + for kind := range kinds { 114 + km[kind] = true 115 + } 116 + d.fileKinds[f.Pos().File()] = km 120 117 121 - return d.markExternFieldAttr(kind, decls) 118 + for kind, pos := range kinds { 119 + if err := d.initCompiler(kind, pos); err != nil { 120 + errs = errors.Append(errs, err) 121 + } 122 + } 123 + return errs 122 124 } 123 125 124 - // findExternFileAttr reports the extern kind of a file-level @extern(kind) 125 - // attribute in f, the position of the corresponding attribute, and f's 126 - // declarations from the package directive onwards. It's an error if more than 127 - // one @extern attribute is found. decls == nil signals that this file should be 128 - // skipped. 129 - func findExternFileAttr(f *ast.File) (kind string, pos token.Pos, decls []ast.Decl, err errors.Error) { 126 + // findExternFileAttrs reports all extern kinds from file-level @extern(kind) 127 + // attributes in f, the position of each corresponding attribute, and f's 128 + // declarations from the package directive onwards. It's an error if duplicate 129 + // @extern attributes for the same kind are found. decls == nil signals that 130 + // this file should be skipped. 131 + func findExternFileAttrs(f *ast.File) (kinds map[string]token.Pos, decls []ast.Decl, err errors.Error) { 130 132 var ( 131 - hasPkg bool 132 - p int 133 - fileAttr *ast.Attribute 133 + hasPkg bool 134 + p int 135 + fileAttrs []*ast.Attribute 134 136 ) 135 137 136 138 loop: ··· 141 143 break loop 142 144 143 145 case *ast.Attribute: 144 - pos = a.Pos() 146 + pos := a.Pos() 145 147 key, body := a.Split() 146 148 if key != "extern" { 147 149 continue 148 150 } 149 - fileAttr = a 151 + fileAttrs = append(fileAttrs, a) 150 152 151 153 attr := internal.ParseAttrBody(pos, body) 152 154 if attr.Err != nil { 153 - return "", pos, nil, attr.Err 155 + err = errors.Append(err, attr.Err) 156 + continue 154 157 } 155 - k, err := attr.String(0) 156 - if err != nil { 158 + k, e := attr.String(0) 159 + if e != nil { 157 160 // Unreachable. 158 - return "", pos, nil, errors.Newf(pos, "%s", err) 161 + err = errors.Append(err, errors.Newf(pos, "%s", e)) 162 + continue 159 163 } 160 164 161 165 if k == "" { 162 - return "", pos, nil, errors.Newf(pos, 163 - "interpreter name must be non-empty") 166 + err = errors.Append(err, errors.Newf(pos, 167 + "interpreter name must be non-empty")) 168 + continue 164 169 } 165 170 166 - if kind != "" { 167 - return "", pos, nil, errors.Newf(pos, 168 - "only one file-level extern attribute allowed per file") 169 - 171 + if kinds == nil { 172 + kinds = map[string]token.Pos{} 170 173 } 171 - kind = k 174 + if _, ok := kinds[k]; ok { 175 + err = errors.Append(err, errors.Newf(pos, 176 + "duplicate @extern attribute for kind %q", k)) 177 + continue 178 + } 179 + kinds[k] = pos 172 180 } 173 181 } 174 182 175 183 switch { 176 - case fileAttr == nil && !hasPkg: 177 - // Nothing to see here. 178 - return "", pos, nil, nil 184 + case len(fileAttrs) == 0 && !hasPkg: 185 + return nil, nil, err 179 186 180 - case fileAttr != nil && !hasPkg: 181 - return "", pos, nil, errors.Newf(fileAttr.Pos(), 182 - "extern attribute without package clause") 187 + case len(fileAttrs) > 0 && !hasPkg: 188 + for _, a := range fileAttrs { 189 + err = errors.Append(err, errors.Newf(a.Pos(), 190 + "extern attribute without package clause")) 191 + } 192 + return nil, nil, err 183 193 184 - case fileAttr == nil && hasPkg: 194 + case len(fileAttrs) == 0 && hasPkg: 185 195 // Check that there are no top-level extern attributes. 186 196 for p++; p < len(f.Decls); p++ { 187 197 x, ok := f.Decls[p].(*ast.Attribute) ··· 193 203 "extern attribute must appear before package clause")) 194 204 } 195 205 } 196 - return "", pos, nil, err 206 + return nil, nil, err 197 207 } 198 208 199 - return kind, pos, f.Decls[p:], nil 209 + return kinds, f.Decls[p:], err 200 210 } 201 211 202 212 // initCompiler initializes the runtime for kind, if applicable. The pos 203 213 // argument represents the position of the file-level @extern attribute. 204 - func (d *externDecorator) initCompiler(kind string, pos token.Pos) (ok bool, err errors.Error) { 205 - if c, ok := d.compilers[kind]; ok { 206 - return c != nil, nil 214 + func (d *externDecorator) initCompiler(kind string, pos token.Pos) errors.Error { 215 + if _, ok := d.compilers[kind]; ok { 216 + return nil 207 217 } 208 - 209 218 // initialize the compiler. 210 219 if d.compilers == nil { 211 220 d.compilers = map[string]Compiler{} 212 - d.fields = map[*ast.Field]fieldInfo{} 213 221 } 214 - 215 222 x := d.runtime.interpreters[kind] 216 223 if x == nil { 217 - return false, errors.Newf(pos, "no interpreter defined for %q", kind) 224 + return errors.Newf(pos, "no interpreter defined for %q", kind) 218 225 } 219 - 220 226 c, err := x.NewCompiler(d.pkg, d.runtime) 221 227 if err != nil { 222 - return false, err 228 + return err 223 229 } 224 - 225 230 d.compilers[kind] = c 226 - 227 - return c != nil, nil 228 - } 229 - 230 - // markExternFieldAttr collects all *ast.Fields with extern attributes into 231 - // d.fields. Both of the following forms are allowed: 232 - // 233 - // a: _ @extern(...) 234 - // a: { _, @extern(...) } 235 - // 236 - // consistent with attribute implementation recommendations. 237 - func (d *externDecorator) markExternFieldAttr(kind string, decls []ast.Decl) (errs errors.Error) { 238 - var fieldStack []*ast.Field 239 - 240 - ast.Walk(&ast.File{Decls: decls}, func(n ast.Node) bool { 241 - switch x := n.(type) { 242 - case *ast.Field: 243 - fieldStack = append(fieldStack, x) 244 - 245 - case *ast.Attribute: 246 - key, body := x.Split() 247 - // Support old-style and new-style extern attributes. 248 - if key != "extern" && key != kind { 249 - break 250 - } 251 - 252 - lastField := len(fieldStack) - 1 253 - if lastField < 0 { 254 - errs = errors.Append(errs, errors.Newf(x.Pos(), 255 - "@%s attribute not associated with field", kind)) 256 - return true 257 - } 258 - 259 - f := fieldStack[lastField] 260 - 261 - if _, ok := d.fields[f]; ok { 262 - errs = errors.Append(errs, errors.Newf(x.Pos(), 263 - "duplicate @%s attributes", kind)) 264 - return true 265 - } 266 - 267 - name, _, err := ast.LabelName(f.Label) 268 - if err != nil { 269 - b, _ := format.Node(f.Label) 270 - errs = errors.Append(errs, errors.Newf(x.Pos(), "external attribute has non-concrete label %s", b)) 271 - return true 272 - } 273 - 274 - d.fields[f] = fieldInfo{ 275 - extern: kind, 276 - funcName: name, 277 - attrBody: body, 278 - attr: x, 279 - } 280 - } 281 - 282 - return true 283 - 284 - }, func(n ast.Node) { 285 - switch n.(type) { 286 - case *ast.Field: 287 - fieldStack = fieldStack[:len(fieldStack)-1] 288 - } 289 - }) 290 - 291 - return errs 231 + return nil 292 232 } 293 233 294 234 // ExtractFieldAttrsByKind finds all the attributes of the given kind 295 235 // in the given AST, parsing their bodies into [internal.Attr]. 236 + // TODO this API does not fit the way that extern attributes can now 237 + // be used; in particular, there is no longer necessarily a field associated 238 + // with every extern attribute. 296 239 func ExtractFieldAttrsByKind(file *ast.File, kind string) (attrsByField map[*ast.Field]*internal.Attr, errs errors.Error) { 297 - k, _, decs, err := findExternFileAttr(file) 298 - if err != nil || len(decs) == 0 || k != kind { 240 + kinds, decls, err := findExternFileAttrs(file) 241 + if err != nil || len(decls) == 0 { 299 242 return nil, err 300 243 } 244 + if _, ok := kinds[kind]; !ok { 245 + return nil, nil 246 + } 301 247 302 248 var fieldStack []*ast.Field 303 249 304 - ast.Walk(&ast.File{Decls: decs}, func(n ast.Node) bool { 250 + ast.Walk(&ast.File{Decls: decls}, func(n ast.Node) bool { 305 251 switch n := n.(type) { 306 252 case *ast.Field: 307 253 fieldStack = append(fieldStack, n) ··· 357 303 } 358 304 359 305 func (d *externDecorator) decorateConjunct(e adt.Elem, scope *adt.Vertex) { 360 - w := walk.Visitor{Before: func(n adt.Node) bool { 361 - return d.processADTNode(n, scope) 362 - }} 306 + w := walk.Visitor{ 307 + Before: func(n adt.Node) bool { 308 + if s, ok := n.(*adt.StructLit); ok { 309 + // Only walk the tree for struct literals that 310 + // are from a file with some extern declarations. 311 + return s.Src != nil && len(d.fileKinds[s.Src.Pos().File()]) > 0 312 + } 313 + return true 314 + }, 315 + After: func(n adt.Node) { 316 + d.processNode(n, scope) 317 + }, 318 + } 363 319 w.Elem(e) 364 320 } 365 321 366 - // processADTNode injects a builtin conjunct into n if n is an adt.Field and 367 - // has a marked ast.Field associated with it. 368 - func (d *externDecorator) processADTNode(n adt.Node, scope *adt.Vertex) bool { 369 - f, ok := n.(*adt.Field) 322 + // processNode processes a single adt Node; if it's a struct literal, 323 + // it decorates both embedded and field-level attributes. 324 + func (d *externDecorator) processNode(n adt.Node, scope *adt.Vertex) { 325 + s, ok := n.(*adt.StructLit) 370 326 if !ok { 371 - return true 327 + return 372 328 } 373 - 374 - info, ok := d.fields[f.Src] 375 - if !ok { 376 - return true 329 + kinds := d.fileKinds[s.Src.Pos().File()] 330 + // Process attributes on fields. 331 + for _, decl := range s.Decls { 332 + var valuePtr *adt.Expr 333 + switch decl := decl.(type) { 334 + case *adt.Field: 335 + valuePtr = &decl.Value 336 + case *adt.BulkOptionalField: 337 + valuePtr = &decl.Value 338 + case *adt.DynamicField: 339 + valuePtr = &decl.Value 340 + default: 341 + continue 342 + } 343 + srcField := decl.Source().(*ast.Field) // We know all the above types come from ast.Field. 344 + name, _, _ := ast.LabelName(srcField.Label) 345 + for _, attr := range srcField.Attrs { 346 + if expr := d.externValue(attr, name, kinds, scope); expr != nil { 347 + *valuePtr = &adt.BinaryExpr{ 348 + Op: adt.AndOp, 349 + X: *valuePtr, 350 + Y: expr, 351 + } 352 + } 353 + } 377 354 } 378 355 379 - c, ok := d.compilers[info.extern] 380 - if !ok { 381 - // An error for a missing runtime was already reported earlier, 382 - // if applicable. 383 - return true 356 + // Process embedded attributes. 357 + var srcDecls []ast.Decl 358 + switch src := s.Src.(type) { 359 + case *ast.File: 360 + srcDecls = src.Decls 361 + case *ast.StructLit: 362 + srcDecls = src.Elts 363 + default: 364 + panic("unexpected type in adt.StructLit.Src") 365 + } 366 + for _, decl := range srcDecls { 367 + if attr, ok := decl.(*ast.Attribute); ok { 368 + if expr := d.externValue(attr, "", kinds, scope); expr != nil { 369 + s.Decls = append(s.Decls, expr) 370 + } 371 + } 384 372 } 373 + } 385 374 386 - attr := internal.ParseAttrBody(info.attr.Pos(), info.attrBody) 387 - if attr.Err != nil { 388 - d.errs = errors.Append(d.errs, attr.Err) 389 - return true 375 + func (d *externDecorator) externValue(attr *ast.Attribute, name string, kinds map[string]bool, scope *adt.Vertex) adt.Expr { 376 + kind, body := attr.Split() 377 + if !kinds[kind] { 378 + return nil 390 379 } 391 - name := info.funcName 392 - if str, ok, _ := attr.Lookup(1, "name"); ok { 393 - name = str 380 + parsed := internal.ParseAttrBody(attr.Pos(), body) 381 + if parsed.Err != nil { 382 + d.errs = errors.Append(d.errs, parsed.Err) 383 + return nil 394 384 } 395 - 396 - b, err := c.Compile(name, scope, &attr) 397 - if err != nil { 398 - err = errors.Wrap(errors.Newf(info.attr.Pos(), "@%s", info.extern), err) 399 - d.errs = errors.Append(d.errs, err) 400 - return true 385 + c := d.compilers[kind] 386 + if c == nil { 387 + return nil 401 388 } 402 - 403 - f.Value = &adt.BinaryExpr{ 404 - Op: adt.AndOp, 405 - X: f.Value, 406 - Y: b, 389 + if a, ok, _ := parsed.Lookup(1, "name"); ok { 390 + name = a 407 391 } 408 - 409 - return true 392 + b, err := c.Compile(name, scope, &parsed) 393 + if err != nil { 394 + d.errs = errors.Append(d.errs, errors.Wrap(errors.Newf(attr.Pos(), "@%s", kind), err)) 395 + return nil 396 + } 397 + return b 410 398 }
+1 -1
internal/core/runtime/testdata/_debug.txtar
··· 5 5 6 6 package foo 7 7 8 - Foo: _ @extern(file1.xx, abi=c, sig="func(int)int") 8 + Foo: _ @test(file1.xx, abi=c, sig="func(int)int") 9 9 10 10 -- out/extern -- 11 11 {
+1 -1
internal/core/runtime/testdata/basic.txtar
··· 26 26 -- extern/out -- 27 27 -- out/extern -- 28 28 { 29 - Bar: implBar2 29 + Bar: impl2 30 30 Foo: implFoo1 31 31 Rename: implEmaner1 32 32 "Quoted-Field": implEmaner1
+4 -12
internal/core/runtime/testdata/errors.txtar
··· 87 87 Foo: _ @test(file1.xx, abi=c, sig="func(int)int") 88 88 89 89 -- out/extern -- 90 - only one file-level extern attribute allowed per file: 90 + duplicate @extern attribute for kind "test": 91 91 ./double_extern_a.cue:2:1 92 - only one file-level extern attribute allowed per file: 92 + duplicate @extern attribute for kind "test": 93 93 ./double_extern_b.cue:2:1 94 - duplicate @test attributes: 95 - ./duplicate.cue:6:43 96 - duplicate @test attributes: 97 - ./duplicate.cue:11:3 94 + duplicate @extern attribute for kind "test": 95 + ./double_extern_b.cue:3:1 98 96 interpreter name must be non-empty: 99 97 ./empty_extern.cue:1:1 100 98 no interpreter defined for "\"test\" foo": 101 99 ./invalid_file_attr.cue:1:1 102 100 extern attribute must appear before package clause: 103 101 ./late_extern.cue:3:1 104 - external attribute has non-concrete label ("something"): 105 - ./non_ident.cue:6:18 106 - external attribute has non-concrete label [string]: 107 - ./non_ident.cue:8:13 108 - @test attribute not associated with field: 109 - ./package_attr.cue:5:1 110 102 no interpreter defined for "wazem": 111 103 ./unknown_interpreter.cue:1:1
-30
internal/core/runtime/testdata/legacy.txtar
··· 1 - -- cue.mod/modules.cue -- 2 - -- file1.cue -- 3 - @extern("test") 4 - 5 - package foo 6 - 7 - 8 - Foo: _ @extern(file1.xx, abi=c, sig="func(int)int") 9 - 10 - Rename: _ @extern(file1.xx, name=Emaner, abi=c, sig="func(int)int") 11 - 12 - -- file2.cue -- 13 - @extern("test") 14 - 15 - package foo 16 - 17 - 18 - Bar: { 19 - @other() 20 - @extern(file2.xx, abi=c, sig="func(int)int") 21 - _ 22 - } 23 - 24 - -- extern/out -- 25 - -- out/extern -- 26 - { 27 - Bar: implBar2 28 - Foo: implFoo1 29 - Rename: implEmaner1 30 - }
+1 -1
internal/core/runtime/testdata/nested.txtar
··· 28 28 Foo: implFoo1 29 29 Rename: implEmaner1 30 30 foo: { 31 - Bar: implBar2 31 + Bar: impl2 32 32 } 33 33 } 34 34 }
+1 -1
internal/core/runtime/testdata/nullinit.txtar
··· 6 6 package nullinit 7 7 8 8 9 - foo: _ @extern("file.xx") 9 + foo: _ @test("file.xx") 10 10 11 11 -- out/extern -- 12 12 {
+24
internal/core/runtime/testdata/package_attr.txtar
··· 1 + -- cue.mod/modules.cue -- 2 + -- file1.cue -- 3 + @extern("test") 4 + 5 + package foo 6 + 7 + Fn1: { 8 + @test("file1.xx") 9 + } 10 + 11 + -- file2.cue -- 12 + @extern("test") 13 + 14 + package foo 15 + 16 + Fn2: { 17 + @test("file2.xx") 18 + } 19 + 20 + -- out/extern -- 21 + { 22 + Fn1: impl1 23 + Fn2: impl2 24 + }
+4 -4
internal/core/runtime/testdata/scope.txtar
··· 10 10 spam: eggs: bool 11 11 } 12 12 13 - foo: _ @extern(int) 14 - bar: _ @extern(#Bar) 13 + foo: _ @test(int) 14 + bar: _ @test(#Bar) 15 15 baz: { 16 - quux: _ @extern(#Baz.#Quux) 17 - eggs: _ @extern(#Baz.spam.eggs) 16 + quux: _ @test(#Baz.#Quux) 17 + eggs: _ @test(#Baz.spam.eggs) 18 18 } 19 19 -- out/extern -- 20 20 {
+7 -1
internal/core/walk/walk.go
··· 35 35 // Feature is invoked for all field names. 36 36 Feature func(f adt.Feature, src adt.Node) 37 37 38 - // Before is invoked for all nodes in pre-order traversal. 38 + // Before, if non-nil, is invoked for all nodes in pre-order traversal. 39 39 // Returning false prevents the visitor from visiting the node's 40 40 // children. 41 41 Before func(adt.Node) bool 42 + 43 + // After, if non-nil, is invoked for all nodes in post-order traversal. 44 + After func(adt.Node) 42 45 } 43 46 44 47 func (w *Visitor) Elem(x adt.Elem) { ··· 194 197 195 198 default: 196 199 panic(fmt.Sprintf("unknown field %T", x)) 200 + } 201 + if n != nil && w.After != nil { 202 + w.After(n) 197 203 } 198 204 }