github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/cue/parser/interface.go (about) 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 // This file contains the exported entry points for invoking the 16 17 package parser 18 19 import ( 20 "github.com/joomcode/cue/cue/ast" 21 "github.com/joomcode/cue/cue/ast/astutil" 22 "github.com/joomcode/cue/cue/errors" 23 "github.com/joomcode/cue/cue/token" 24 "github.com/joomcode/cue/internal/source" 25 ) 26 27 // Option specifies a parse option. 28 type Option func(p *parser) 29 30 var ( 31 // PackageClauseOnly causes parsing to stop after the package clause. 32 PackageClauseOnly Option = packageClauseOnly 33 packageClauseOnly = func(p *parser) { 34 p.mode |= packageClauseOnlyMode 35 } 36 37 // ImportsOnly causes parsing to stop parsing after the import declarations. 38 ImportsOnly Option = importsOnly 39 importsOnly = func(p *parser) { 40 p.mode |= importsOnlyMode 41 } 42 43 // ParseComments causes comments to be parsed. 44 ParseComments Option = parseComments 45 parseComments = func(p *parser) { 46 p.mode |= parseCommentsMode 47 } 48 49 // Trace causes parsing to print a trace of parsed productions. 50 Trace Option = traceOpt 51 traceOpt = func(p *parser) { 52 p.mode |= traceMode 53 } 54 55 // DeclarationErrors causes parsing to report declaration errors. 56 DeclarationErrors Option = declarationErrors 57 declarationErrors = func(p *parser) { 58 p.mode |= declarationErrorsMode 59 } 60 61 // AllErrors causes all errors to be reported (not just the first 10 on different lines). 62 AllErrors Option = allErrors 63 allErrors = func(p *parser) { 64 p.mode |= allErrorsMode 65 } 66 67 // AllowPartial allows the parser to be used on a prefix buffer. 68 AllowPartial Option = allowPartial 69 allowPartial = func(p *parser) { 70 p.mode |= partialMode 71 } 72 ) 73 74 // FromVersion specifies until which legacy version the parser should provide 75 // backwards compatibility. 76 func FromVersion(version int) Option { 77 if version >= 0 { 78 version++ 79 } 80 // Versions: 81 // <0: major version 0 (counting -1000 + x, where x = 100*m+p in 0.m.p 82 // >=0: x+1 in 1.x.y 83 return func(p *parser) { p.version = version } 84 } 85 86 func version0(minor, patch int) int { 87 return -1000 + 100*minor + patch 88 } 89 90 // DeprecationError is a sentinel error to indicate that an error is 91 // related to an unsupported old CUE syntax. 92 type DeprecationError struct { 93 Version int 94 } 95 96 func (e *DeprecationError) Error() string { 97 return "try running `cue fix` (possibly with an earlier version, like v0.2.2) to upgrade" 98 } 99 100 // Latest specifies the latest version of the parser, effectively setting 101 // the strictest implementation. 102 const Latest = latest 103 104 const latest = -600 105 106 // FileOffset specifies the File position info to use. 107 func FileOffset(pos int) Option { 108 return func(p *parser) { p.offset = pos } 109 } 110 111 // A mode value is a set of flags (or 0). 112 // They control the amount of source code parsed and other optional 113 // parser functionality. 114 type mode uint 115 116 const ( 117 packageClauseOnlyMode mode = 1 << iota // stop parsing after package clause 118 importsOnlyMode // stop parsing after import declarations 119 parseCommentsMode // parse comments and add them to AST 120 partialMode 121 traceMode // print a trace of parsed productions 122 declarationErrorsMode // report declaration errors 123 allErrorsMode // report all errors (not just the first 10 on different lines) 124 ) 125 126 // ParseFile parses the source code of a single CUE source file and returns 127 // the corresponding File node. The source code may be provided via 128 // the filename of the source file, or via the src parameter. 129 // 130 // If src != nil, ParseFile parses the source from src and the filename is 131 // only used when recording position information. The type of the argument 132 // for the src parameter must be string, []byte, or io.Reader. 133 // If src == nil, ParseFile parses the file specified by filename. 134 // 135 // The mode parameter controls the amount of source text parsed and other 136 // optional parser functionality. Position information is recorded in the 137 // file set fset, which must not be nil. 138 // 139 // If the source couldn't be read, the returned AST is nil and the error 140 // indicates the specific failure. If the source was read but syntax 141 // errors were found, the result is a partial AST (with Bad* nodes 142 // representing the fragments of erroneous source code). Multiple errors 143 // are returned via a ErrorList which is sorted by file position. 144 func ParseFile(filename string, src interface{}, mode ...Option) (f *ast.File, err error) { 145 146 // get source 147 text, err := source.Read(filename, src) 148 if err != nil { 149 return nil, err 150 } 151 152 var pp parser 153 defer func() { 154 if pp.panicking { 155 _ = recover() 156 } 157 158 // set result values 159 if f == nil { 160 // source is not a valid Go source file - satisfy 161 // ParseFile API and return a valid (but) empty 162 // *File 163 f = &ast.File{ 164 // Scope: NewScope(nil), 165 } 166 } 167 168 err = errors.Sanitize(pp.errors) 169 }() 170 171 // parse source 172 pp.init(filename, text, mode) 173 f = pp.parseFile() 174 if f == nil { 175 return nil, pp.errors 176 } 177 f.Filename = filename 178 astutil.Resolve(f, pp.errf) 179 180 return f, pp.errors 181 } 182 183 // ParseExpr is a convenience function for parsing an expression. 184 // The arguments have the same meaning as for Parse, but the source must 185 // be a valid CUE (type or value) expression. Specifically, fset must not 186 // be nil. 187 func ParseExpr(filename string, src interface{}, mode ...Option) (ast.Expr, error) { 188 // get source 189 text, err := source.Read(filename, src) 190 if err != nil { 191 return nil, err 192 } 193 194 var p parser 195 defer func() { 196 if p.panicking { 197 _ = recover() 198 } 199 err = errors.Sanitize(p.errors) 200 }() 201 202 // parse expr 203 p.init(filename, text, mode) 204 // Set up pkg-level scopes to avoid nil-pointer errors. 205 // This is not needed for a correct expression x as the 206 // parser will be ok with a nil topScope, but be cautious 207 // in case of an erroneous x. 208 e := p.parseRHS() 209 210 // If a comma was inserted, consume it; 211 // report an error if there's more tokens. 212 if p.tok == token.COMMA && p.lit == "\n" { 213 p.next() 214 } 215 if p.mode&partialMode == 0 { 216 p.expect(token.EOF) 217 } 218 219 if p.errors != nil { 220 return nil, p.errors 221 } 222 astutil.ResolveExpr(e, p.errf) 223 224 return e, p.errors 225 } 226 227 // parseExprString is a convenience function for obtaining the AST of an 228 // expression x. The position information recorded in the AST is undefined. The 229 // filename used in error messages is the empty string. 230 func parseExprString(x string) (ast.Expr, error) { 231 return ParseExpr("", []byte(x)) 232 }