1 // Copyright 2018 The CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package build defines data types and utilities for defining CUE configuration 16 // instances. 17 // 18 // This package enforces the rules regarding packages and instances as defined 19 // in the spec, but it leaves any other details, as well as handling of modules, 20 // up to the implementation. 21 // 22 // A full implementation of instance loading can be found in the loader package. 23 // 24 // WARNING: this packages may change. It is fine to use load and cue, who both 25 // use this package. 26 package build 27 28 import ( 29 "cuelang.org/go/cue/ast" 30 ) 31 32 // A Context keeps track of state of building instances and caches work. 33 type Context struct { 34 loader LoadFunc 35 parseFunc func(str string, src interface{}) (*ast.File, error) 36 37 initialized bool 38 39 imports map[string]*Instance 40 } 41 42 // NewInstance creates an instance for this Context. 43 func (c *Context) NewInstance(dir string, f LoadFunc) *Instance { 44 if c == nil { 45 c = &Context{} 46 } 47 if f == nil { 48 f = c.loader 49 } 50 return &Instance{ 51 ctxt: c, 52 loadFunc: f, 53 Dir: dir, 54 } 55 } 56 57 // Complete finishes the initialization of an instance. All files must have 58 // been added with AddFile before this call. 59 func (inst *Instance) Complete() error { 60 if inst.done { 61 return inst.Err 62 } 63 inst.done = true 64 65 err := inst.complete() 66 if err != nil { 67 inst.ReportError(err) 68 } 69 if inst.Err != nil { 70 inst.Incomplete = true 71 return inst.Err 72 } 73 return nil 74 } 75 76 func (c *Context) init() { 77 if !c.initialized { 78 c.initialized = true 79 c.imports = map[string]*Instance{} 80 } 81 } 82 83 // Options: 84 // - certain parse modes 85 // - parallelism 86 // - error handler (allows cancelling the context) 87 // - file set. 88 89 // NewContext creates a new build context. 90 // 91 // All instances must be created with a context. 92 func NewContext(opts ...Option) *Context { 93 c := &Context{} 94 for _, o := range opts { 95 o(c) 96 } 97 c.init() 98 return c 99 } 100 101 // Option define build options. 102 type Option func(c *Context) 103 104 // Loader sets parsing options. 105 func Loader(f LoadFunc) Option { 106 return func(c *Context) { c.loader = f } 107 } 108 109 // ParseFile is called to read and parse each file 110 // when building syntax tree. 111 // It must be safe to call ParseFile simultaneously from multiple goroutines. 112 // If ParseFile is nil, the loader will uses parser.ParseFile. 113 // 114 // ParseFile should parse the source from src and use filename only for 115 // recording position information. 116 // 117 // An application may supply a custom implementation of ParseFile 118 // to change the effective file contents or the behavior of the parser, 119 // or to modify the syntax tree. For example, changing the backwards 120 // compatibility. 121 func ParseFile(f func(filename string, src interface{}) (*ast.File, error)) Option { 122 return func(c *Context) { c.parseFunc = f } 123 } 124