Skip to content

Commit 9e55783

Browse files
committed
internal/cueimports: copy code from cue/load
This CL is a no-op, just adding ignored files which will be adjusted in the next CL. This will make it easier to see the changes being made from the original. In a future CL we'll change the original cue/load code to use this package instead of the internal version. Signed-off-by: Roger Peppe <[email protected]> Change-Id: I5aa3e21461c1473dcb40ee68330017e21349ca88 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1172689 Unity-Result: CUE porcuepine <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Reviewed-by: Daniel Martí <[email protected]>
1 parent b727189 commit 9e55783

File tree

2 files changed

+461
-0
lines changed

2 files changed

+461
-0
lines changed

internal/cueimports/read.go

+249
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
//go:build ignore
2+
3+
// Copyright 2018 The CUE Authors
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package load
18+
19+
import (
20+
"bufio"
21+
"io"
22+
"unicode/utf8"
23+
24+
"cuelang.org/go/cue/errors"
25+
"cuelang.org/go/cue/token"
26+
)
27+
28+
type importReader struct {
29+
b *bufio.Reader
30+
buf []byte
31+
peek byte
32+
err errors.Error
33+
eof bool
34+
nerr int
35+
}
36+
37+
func isIdent(c byte) bool {
38+
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf
39+
}
40+
41+
var (
42+
errSyntax = errors.Newf(token.NoPos, "syntax error") // TODO: remove
43+
errNUL = errors.Newf(token.NoPos, "unexpected NUL in input")
44+
)
45+
46+
// syntaxError records a syntax error, but only if an I/O error has not already been recorded.
47+
func (r *importReader) syntaxError() {
48+
if r.err == nil {
49+
r.err = errSyntax
50+
}
51+
}
52+
53+
// readByte reads the next byte from the input, saves it in buf, and returns it.
54+
// If an error occurs, readByte records the error in r.err and returns 0.
55+
func (r *importReader) readByte() byte {
56+
c, err := r.b.ReadByte()
57+
if err == nil {
58+
r.buf = append(r.buf, c)
59+
if c == 0 {
60+
err = errNUL
61+
}
62+
}
63+
if err != nil {
64+
if err == io.EOF {
65+
r.eof = true
66+
} else if r.err == nil {
67+
r.err = errors.Wrapf(err, token.NoPos, "readByte")
68+
}
69+
c = 0
70+
}
71+
return c
72+
}
73+
74+
// peekByte returns the next byte from the input reader but does not advance beyond it.
75+
// If skipSpace is set, peekByte skips leading spaces and comments.
76+
func (r *importReader) peekByte(skipSpace bool) byte {
77+
if r.err != nil {
78+
if r.nerr++; r.nerr > 10000 {
79+
panic("go/build: import reader looping")
80+
}
81+
return 0
82+
}
83+
84+
// Use r.peek as first input byte.
85+
// Don't just return r.peek here: it might have been left by peekByte(false)
86+
// and this might be peekByte(true).
87+
c := r.peek
88+
if c == 0 {
89+
c = r.readByte()
90+
}
91+
for r.err == nil && !r.eof {
92+
if skipSpace {
93+
// For the purposes of this reader, semicolons are never necessary to
94+
// understand the input and are treated as spaces.
95+
switch c {
96+
case ' ', '\f', '\t', '\r', '\n', ';':
97+
c = r.readByte()
98+
continue
99+
100+
case '/':
101+
c = r.readByte()
102+
if c == '/' {
103+
for c != '\n' && r.err == nil && !r.eof {
104+
c = r.readByte()
105+
}
106+
} else if c == '*' {
107+
var c1 byte
108+
for (c != '*' || c1 != '/') && r.err == nil {
109+
if r.eof {
110+
r.syntaxError()
111+
}
112+
c, c1 = c1, r.readByte()
113+
}
114+
} else {
115+
r.syntaxError()
116+
}
117+
c = r.readByte()
118+
continue
119+
}
120+
}
121+
break
122+
}
123+
r.peek = c
124+
return r.peek
125+
}
126+
127+
// nextByte is like peekByte but advances beyond the returned byte.
128+
func (r *importReader) nextByte(skipSpace bool) byte {
129+
c := r.peekByte(skipSpace)
130+
r.peek = 0
131+
return c
132+
}
133+
134+
// readKeyword reads the given keyword from the input.
135+
// If the keyword is not present, readKeyword records a syntax error.
136+
func (r *importReader) readKeyword(kw string) {
137+
r.peekByte(true)
138+
for i := 0; i < len(kw); i++ {
139+
if r.nextByte(false) != kw[i] {
140+
r.syntaxError()
141+
return
142+
}
143+
}
144+
if isIdent(r.peekByte(false)) {
145+
r.syntaxError()
146+
}
147+
}
148+
149+
// readIdent reads an identifier from the input.
150+
// If an identifier is not present, readIdent records a syntax error.
151+
func (r *importReader) readIdent() {
152+
c := r.peekByte(true)
153+
if !isIdent(c) {
154+
r.syntaxError()
155+
return
156+
}
157+
for isIdent(r.peekByte(false)) {
158+
r.peek = 0
159+
}
160+
}
161+
162+
// readString reads a quoted string literal from the input.
163+
// If an identifier is not present, readString records a syntax error.
164+
func (r *importReader) readString(save *[]string) {
165+
switch r.nextByte(true) {
166+
case '`':
167+
start := len(r.buf) - 1
168+
for r.err == nil {
169+
if r.nextByte(false) == '`' {
170+
if save != nil {
171+
*save = append(*save, string(r.buf[start:]))
172+
}
173+
break
174+
}
175+
if r.eof {
176+
r.syntaxError()
177+
}
178+
}
179+
case '"':
180+
start := len(r.buf) - 1
181+
for r.err == nil {
182+
c := r.nextByte(false)
183+
if c == '"' {
184+
if save != nil {
185+
*save = append(*save, string(r.buf[start:]))
186+
}
187+
break
188+
}
189+
if r.eof || c == '\n' {
190+
r.syntaxError()
191+
}
192+
if c == '\\' {
193+
r.nextByte(false)
194+
}
195+
}
196+
default:
197+
r.syntaxError()
198+
}
199+
}
200+
201+
// readImport reads an import clause - optional identifier followed by quoted string -
202+
// from the input.
203+
func (r *importReader) readImport(imports *[]string) {
204+
c := r.peekByte(true)
205+
if c == '.' {
206+
r.peek = 0
207+
} else if isIdent(c) {
208+
r.readIdent()
209+
}
210+
r.readString(imports)
211+
}
212+
213+
// readImports is like io.ReadAll, except that it expects a CUE file as
214+
// input and stops reading the input once the imports have completed.
215+
func readImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, errors.Error) {
216+
r := &importReader{b: bufio.NewReader(f)}
217+
218+
r.readKeyword("package")
219+
r.readIdent()
220+
for r.peekByte(true) == 'i' {
221+
r.readKeyword("import")
222+
if r.peekByte(true) == '(' {
223+
r.nextByte(false)
224+
for r.peekByte(true) != ')' && r.err == nil {
225+
r.readImport(imports)
226+
}
227+
r.nextByte(false)
228+
} else {
229+
r.readImport(imports)
230+
}
231+
}
232+
233+
// If we stopped successfully before EOF, we read a byte that told us we were done.
234+
// Return all but that last byte, which would cause a syntax error if we let it through.
235+
if r.err == nil && !r.eof {
236+
return r.buf[:len(r.buf)-1], nil
237+
}
238+
239+
// If we stopped for a syntax error, consume the whole file so that
240+
// we are sure we don't change the errors that go/parser returns.
241+
if r.err == errSyntax && !reportSyntaxError {
242+
r.err = nil
243+
for r.err == nil && !r.eof {
244+
r.readByte()
245+
}
246+
}
247+
248+
return r.buf, r.err
249+
}

0 commit comments

Comments
 (0)