1717package parser
1818
1919import (
20+ "fmt"
21+
2022 "cuelang.org/go/cue/ast"
2123 "cuelang.org/go/cue/ast/astutil"
2224 "cuelang.org/go/cue/errors"
2325 "cuelang.org/go/cue/token"
24- "cuelang.org/go/internal"
26+ "cuelang.org/go/internal/cueversion"
27+ "cuelang.org/go/internal/mod/semver"
2528 "cuelang.org/go/internal/source"
2629)
2730
2831// Option specifies a parse option.
29- type Option func (p * parser )
32+ type Option interface {
33+ apply (cfg * Config )
34+ }
3035
31- var (
32- // PackageClauseOnly causes parsing to stop after the package clause.
33- PackageClauseOnly Option = packageClauseOnly
34- packageClauseOnly = func (p * parser ) {
35- p .mode |= packageClauseOnlyMode
36+ var _ Option = Config {}
37+
38+ // Config represents the end result of applying a set of options.
39+ // The zero value is not OK to use: use [NewConfig] to construct
40+ // a Config value before using it.
41+ //
42+ // Config itself implements [Option] by overwriting the
43+ // entire configuration.
44+ //
45+ // Config is comparable.
46+ type Config struct {
47+ // valid is set by NewConfig and is used to check
48+ // that a Config has been created correctly.
49+ valid bool
50+
51+ // Mode holds a bitmask of boolean parser options.
52+ Mode Mode
53+
54+ // Version holds the language version to use when
55+ // parsing the CUE syntax.
56+ Version string
57+ }
58+
59+ // Ensure that Config is comparable.
60+ var _ = Config {} == Config {}
61+
62+ // apply implements [Option]
63+ func (cfg Config ) apply (cfg1 * Config ) {
64+ if ! cfg .valid {
65+ panic ("zero parser.Config value used; use parser.NewConfig!" )
3666 }
67+ * cfg1 = cfg
68+ }
3769
38- // ImportsOnly causes parsing to stop parsing after the import declarations.
39- ImportsOnly Option = importsOnly
40- importsOnly = func (p * parser ) {
41- p .mode |= importsOnlyMode
70+ // NewConfig returns the configuration containing all default values
71+ // with the given options applied.
72+ func NewConfig (opts ... Option ) Config {
73+ return Config {
74+ valid : true ,
75+ Version : cueversion .LanguageVersion (),
76+ }.Apply (opts ... )
77+ }
78+
79+ // Apply applies all the given options to cfg and
80+ // returns the resulting configuration.
81+ func (cfg Config ) Apply (opts ... Option ) Config {
82+ for _ , opt := range opts {
83+ opt .apply (& cfg )
4284 }
85+ return cfg
86+ }
87+
88+ // optionFunc implements [Option] for a function.
89+ type optionFunc func (cfg * Config )
90+
91+ func (f optionFunc ) apply (cfg * Config ) {
92+ f (cfg )
93+ }
94+
95+ // A Mode value is a set of flags (or 0).
96+ // It controls the amount of source code parsed and other optional
97+ // parser functionality.
98+ //
99+ // Mode implements [Option] by or-ing all its bits
100+ // with [Config.Mode].
101+ type Mode uint
102+
103+ const (
104+ // PackageClauseOnly causes parsing to stop after the package clause.
105+ PackageClauseOnly Mode = 1 << iota
106+
107+ // ImportsOnly causes parsing to stop parsing after the import declarations.
108+ ImportsOnly
43109
44110 // ParseComments causes comments to be parsed.
45- ParseComments Option = parseComments
46- parseComments = func (p * parser ) {
47- p .mode |= parseCommentsMode
48- }
111+ ParseComments
49112
50113 // ParseFuncs causes function declarations to be parsed.
51114 //
52115 // This is an experimental function and the API is likely to
53116 // change or dissapear.
54- ParseFuncs Option = parseFuncs
55- parseFuncs = func (p * parser ) {
56- p .mode |= parseFuncsMode
57- }
117+ ParseFuncs
58118
59119 // Trace causes parsing to print a trace of parsed productions.
60- Trace Option = traceOpt
61- traceOpt = func (p * parser ) {
62- p .mode |= traceMode
63- }
120+ Trace
64121
65122 // DeclarationErrors causes parsing to report declaration errors.
66- DeclarationErrors Option = declarationErrors
67- declarationErrors = func (p * parser ) {
68- p .mode |= declarationErrorsMode
69- }
123+ DeclarationErrors
70124
71125 // AllErrors causes all errors to be reported (not just the first 10 on different lines).
72- AllErrors Option = allErrors
73- allErrors = func (p * parser ) {
74- p .mode |= allErrorsMode
75- }
126+ AllErrors
76127
77128 // AllowPartial allows the parser to be used on a prefix buffer.
78- AllowPartial Option = allowPartial
79- allowPartial = func (p * parser ) {
80- p .mode |= partialMode
81- }
129+ AllowPartial
82130)
83131
132+ // apply implements [Option].
133+ func (m Mode ) apply (c * Config ) {
134+ c .Mode |= m
135+ }
136+
137+ // Version specifies the language version to use when parsing
138+ // the CUE. The argument must be a valid semantic version, as
139+ // checked by [semver.IsValid].
140+ func Version (v string ) Option {
141+ if ! semver .IsValid (v ) {
142+ panic (fmt .Errorf ("invalid language version %q" , v ))
143+ }
144+ return optionFunc (func (c * Config ) {
145+ c .Version = v
146+ })
147+ }
148+
84149// FromVersion specifies until which legacy version the parser should provide
85150// backwards compatibility.
151+ // Deprecated: use [Version] instead.
86152func FromVersion (version int ) Option {
87- if version >= 0 {
88- version ++
89- }
90- // Versions:
91- // <0: major version 0 (counting -1000 + x, where x = 100*m+p in 0.m.p
92- // >=0: x+1 in 1.x.y
93- return func (p * parser ) { p .version = version }
153+ return optionFunc (func (cfg * Config ) {})
94154}
95155
96156// DeprecationError is a sentinel error to indicate that an error is
@@ -104,42 +164,20 @@ func (e *DeprecationError) Error() string {
104164}
105165
106166const (
107- // Latest specifies the latest version of the parser, effectively setting
108- // the strictest implementation.
109- Latest = latest
110-
111- latest = - 1000 + (100 * internal .MinorCurrent ) + 0
112-
113- // FullBackwardCompatibility enables all deprecated features that are
114- // currently still supported by the parser.
115- FullBackwardCompatibility = fullCompatibility
167+ // Deprecated: see [Version].
168+ Latest = 0
116169
117- fullCompatibility = - 1000
170+ // Deprecated: see [Version].
171+ FullBackwardCompatibility = 0
118172)
119173
120174// FileOffset specifies the File position info to use.
121175//
122176// Deprecated: this has no effect.
123177func FileOffset (pos int ) Option {
124- return func (p * parser ) {}
178+ return optionFunc ( func (* Config ) {})
125179}
126180
127- // A mode value is a set of flags (or 0).
128- // They control the amount of source code parsed and other optional
129- // parser functionality.
130- type mode uint
131-
132- const (
133- packageClauseOnlyMode mode = 1 << iota // stop parsing after package clause
134- importsOnlyMode // stop parsing after import declarations
135- parseCommentsMode // parse comments and add them to AST
136- parseFuncsMode // parse function declarations (experimental)
137- partialMode
138- traceMode // print a trace of parsed productions
139- declarationErrorsMode // report declaration errors
140- allErrorsMode // report all errors (not just the first 10 on different lines)
141- )
142-
143181// ParseFile parses the source code of a single CUE source file and returns
144182// the corresponding File node. The source code may be provided via
145183// the filename of the source file, or via the src parameter.
@@ -228,7 +266,7 @@ func ParseExpr(filename string, src interface{}, mode ...Option) (ast.Expr, erro
228266 if p .tok == token .COMMA && p .lit == "\n " {
229267 p .next ()
230268 }
231- if p .mode & partialMode == 0 {
269+ if p .cfg . Mode & AllowPartial == 0 {
232270 p .expect (token .EOF )
233271 }
234272
0 commit comments