Skip to content

Commit 7bdae28

Browse files
committed
fix bugs for windows
1 parent 192857e commit 7bdae28

File tree

9 files changed

+129
-48
lines changed

9 files changed

+129
-48
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ example/clean:
9898
.PHONY: example/gen
9999
example/gen:
100100
@echo "Running generate example..."
101+
@NEXT_NOCOPYBUILTIN=1 ${BUILD_BIN_DIR}/next -t ${EXAMPLE_DIR}/next/
101102
@NEXT_NOCOPYBUILTIN=1 ${BUILD_BIN_DIR}/next build ${EXAMPLE_DIR}
102103

103104
.PHONY: clean

cmd/nextls/server.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func (s *Server) Handle(ctx context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.
6666
}
6767
}
6868

69-
func (s *Server) handleInitialize(ctx context.Context, req *jsonrpc2.Request) (any, error) {
69+
func (s *Server) handleInitialize(_ context.Context, _ *jsonrpc2.Request) (any, error) {
7070
return map[string]any{
7171
"capabilities": &protocol.ServerCapabilities{
7272
SemanticTokensProvider: &protocol.SemanticTokensOptions{
@@ -81,7 +81,7 @@ func (s *Server) handleInitialize(ctx context.Context, req *jsonrpc2.Request) (a
8181
}, nil
8282
}
8383

84-
func (s *Server) handleDidOpen(ctx context.Context, req *jsonrpc2.Request) (any, error) {
84+
func (s *Server) handleDidOpen(_ context.Context, req *jsonrpc2.Request) (any, error) {
8585
var params struct {
8686
TextDocument protocol.TextDocumentItem
8787
}
@@ -93,7 +93,7 @@ func (s *Server) handleDidOpen(ctx context.Context, req *jsonrpc2.Request) (any,
9393
return nil, nil
9494
}
9595

96-
func (s *Server) handleDidClose(ctx context.Context, req *jsonrpc2.Request) (any, error) {
96+
func (s *Server) handleDidClose(_ context.Context, req *jsonrpc2.Request) (any, error) {
9797
var params struct {
9898
TextDocument protocol.TextDocumentIdentifier `json:"textDocument"`
9999
}
@@ -105,7 +105,7 @@ func (s *Server) handleDidClose(ctx context.Context, req *jsonrpc2.Request) (any
105105
return nil, nil
106106
}
107107

108-
func (s *Server) handleDidChange(ctx context.Context, req *jsonrpc2.Request) (any, error) {
108+
func (s *Server) handleDidChange(_ context.Context, req *jsonrpc2.Request) (any, error) {
109109
var params struct {
110110
TextDocument protocol.TextDocumentIdentifier `json:"textDocument"`
111111
ContentChanges []protocol.TextDocumentContentChangeEvent `json:"contentChanges"`

src/compile/compiler.go

+17-7
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func (c *Compiler) AddFile(f *ast.File) (*File, error) {
104104
c.addErrorf(f.Pos(), "file %s already exists", filename)
105105
return file, c.errors.Err()
106106
}
107-
path, err := filepath.Abs(filename)
107+
path, err := absolutePath(filename)
108108
if err != nil {
109109
return nil, fmt.Errorf("failed to get absolute path of %s: %w", filename, err)
110110
}
@@ -188,7 +188,7 @@ func (c *Compiler) addErrorf(pos token.Pos, format string, args ...any) {
188188

189189
// getFileByPos returns the file by position
190190
func (c *Compiler) getFileByPos(pos token.Pos) *File {
191-
path, err := filepath.Abs(c.fset.Position(pos).Filename)
191+
path, err := absolutePath(c.fset.Position(pos).Filename)
192192
if err != nil {
193193
c.addErrorf(pos, "failed to get absolute path of %s: %v", c.fset.Position(pos).Filename, err)
194194
return nil
@@ -203,12 +203,13 @@ func (c *Compiler) lookupFile(fullPath, relativePath string) *File {
203203
}
204204
if !filepath.IsAbs(relativePath) {
205205
var err error
206-
relativePath, err = filepath.Abs(filepath.Join(filepath.Dir(fullPath), relativePath))
206+
relativePath, err = absolutePath(filepath.Join(filepath.Dir(fullPath), relativePath))
207207
if err != nil {
208208
c.addErrorf(token.NoPos, "failed to get absolute path of %s: %v", relativePath, err)
209209
return nil
210210
}
211211
}
212+
relativePath = filepath.ToSlash(relativePath)
212213
return c.files[relativePath]
213214
}
214215

@@ -803,10 +804,10 @@ func (c *Compiler) validateAnnotations(node Node, annotations grammar.Annotation
803804
if !c.options.Strict {
804805
continue
805806
}
806-
s, score := stringutil.FindBestMatchFunc(slices.All(annotations), name, stringutil.DefaultSimilarityThreshold, func(i int, a grammar.Options[grammar.Annotation]) string {
807+
s := stringutil.FindBestMatchFunc(slices.All(annotations), name, stringutil.DefaultSimilarityThreshold, func(i int, a grammar.Options[grammar.Annotation]) string {
807808
return a.Value().Name
808809
})
809-
if score > 0 {
810+
if s != "" {
810811
c.addErrorf(annotation.Pos().pos, "unknown annotation %s, did you mean %s?", name, s)
811812
} else {
812813
c.addErrorf(annotation.Pos().pos, "unknown annotation %s", name)
@@ -830,7 +831,7 @@ func (c *Compiler) validateAnnotations(node Node, annotations grammar.Annotation
830831
if !c.options.Strict && name != "next" {
831832
continue
832833
}
833-
s, score := stringutil.FindBestMatchFunc(slices.All(ga.Parameters), p, stringutil.DefaultSimilarityThreshold, func(i int, a grammar.Options[grammar.AnnotationParameter]) string {
834+
s := stringutil.FindBestMatchFunc(slices.All(ga.Parameters), p, stringutil.DefaultSimilarityThreshold, func(i int, a grammar.Options[grammar.AnnotationParameter]) string {
834835
name := a.Value().Name
835836
if strings.HasPrefix(name, ".+_") {
836837
if index := strings.Index(p, "_"); index > 0 {
@@ -843,7 +844,7 @@ func (c *Compiler) validateAnnotations(node Node, annotations grammar.Annotation
843844
}
844845
return name
845846
})
846-
if score > 0 {
847+
if s != "" {
847848
c.addErrorf(annotation.NamePos(p).pos, "annotation %s: unknown parameter %s, did you mean %s?", name, p, s)
848849
} else {
849850
c.addErrorf(annotation.NamePos(p).pos, "annotation %s: unknown parameter %s", name, p)
@@ -886,6 +887,15 @@ func (c *Compiler) validateAnnotations(node Node, annotations grammar.Annotation
886887
c.addErrorf(annotation.NamePos(p).pos, "annotation %s: parameter %s: %s", name, p, pv.Value().Message)
887888
}
888889
}
890+
// Validate available expression
891+
if name == "next" && p == "available" {
892+
if pos, err := validateAvailable(c, annotation, v); err != nil {
893+
if !pos.IsValid() {
894+
pos = annotation.NamePos(name).pos
895+
}
896+
c.addError(pos, err.Error())
897+
}
898+
}
889899
}
890900
for _, gp := range ga.Parameters {
891901
if !gp.Value().Required {

src/compile/next.go

+31-11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"maps"
1212
"os"
1313
"path/filepath"
14+
"runtime"
1415
"slices"
1516
"strconv"
1617
"strings"
@@ -361,7 +362,7 @@ func doCompile(compiler *Compiler, files []string, source io.Reader) {
361362
if source == nil {
362363
seen := make(map[string]bool)
363364
for i := len(files) - 1; i >= 0; i-- {
364-
path, err := filepath.Abs(files[i])
365+
path, err := absolutePath(files[i])
365366
files[i] = result(stderr, path, err)
366367
if seen[files[i]] {
367368
files = append(files[:i], files[i+1:]...)
@@ -513,39 +514,58 @@ func printError(stderr io.Writer, err error) {
513514
}
514515

515516
func parseFilename(err string) string {
516-
parts := strings.SplitN(err, ":", 2)
517+
parts := splitError(err)
517518
if len(parts) < 2 {
518519
return ""
519520
}
520521
return parts[0]
521522
}
522523

524+
func splitError(err string) []string {
525+
var drive string
526+
if runtime.GOOS == "windows" {
527+
// try skip the drive letter on Windows
528+
if len(err) > 2 && err[1] == ':' {
529+
drive = err[:2]
530+
err = err[2:]
531+
}
532+
}
533+
parts := strings.SplitN(err, ":", 4)
534+
if len(parts) > 0 {
535+
parts[0] = drive + parts[0]
536+
}
537+
return parts
538+
}
539+
523540
// printErrorWithPosition tries to print template error in a more readable format.
524541
// template error format: "<filename>:<line>:<column>: <error message>"
525542
func printErrorWithPosition(stderr io.Writer, err string) {
526-
const fileColor = term.Color("")
543+
const fileColor = term.None
527544
const lineColor = term.BrightBlue
528545
const columnColor = term.BrightGreen
529546
const errorColor = term.BrightRed
530547

531548
if err == "" {
532549
return
533550
}
534-
parts := strings.SplitN(err, ":", 4)
551+
parts := splitError(err)
552+
filename := parts[0]
553+
if wd, err := os.Getwd(); err == nil {
554+
if rel, err := filepath.Rel(wd, filename); err == nil && !strings.HasPrefix(rel, "..") {
555+
filename = rel
556+
}
557+
}
558+
filename = filepath.ToSlash(filename)
559+
535560
if len(parts) < 3 {
536561
if len(parts) == 2 {
537-
term.Fprintf(stderr, "%s:%s\n", fileColor.Colorize(parts[0]), errorColor.Colorize(parts[1]))
562+
term.Fprintf(stderr, "%s:%s\n", fileColor.Colorize(filename), errorColor.Colorize(parts[1]))
538563
} else {
539564
term.Fprintln(stderr, errorColor.Colorize(err))
540565
}
541566
return
542567
}
543-
filename := parts[0]
544-
if wd, err := os.Getwd(); err == nil {
545-
if rel, err := filepath.Rel(wd, filename); err == nil && !strings.HasPrefix(rel, "..") {
546-
filename = rel
547-
}
548-
}
568+
549569
line := parts[1]
550570
column := ""
551571
if len(parts) > 3 {

src/compile/object.go

+50-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package compile
22

33
import (
44
"cmp"
5+
"errors"
56
"fmt"
67
"math"
78
"path/filepath"
@@ -241,7 +242,7 @@ func newImport(c *Compiler, file *File, src *ast.ImportDecl) *Import {
241242
}
242243
if len(path) > 0 && !filepath.IsAbs(path) {
243244
var err error
244-
path, err = filepath.Abs(filepath.Join(filepath.Dir(file.Path), path))
245+
path, err = absolutePath(filepath.Join(filepath.Dir(file.Path), path))
245246
if err != nil {
246247
c.addErrorf(token.NoPos, "failed to get absolute path of %s: %v", i.Path, err)
247248
} else {
@@ -1197,19 +1198,61 @@ func (t *InterfaceMethodResult) resolve(c *Compiler, file *File, scope Scope) {
11971198
t.Type = c.resolveType(0, t.Method, t.unresolved.typ, false)
11981199
}
11991200

1201+
type bailout struct {
1202+
pos Position
1203+
msg string
1204+
}
1205+
1206+
func (b bailout) Error() string {
1207+
if b.pos.IsValid() {
1208+
return fmt.Sprintf("%s: %s", b.pos, b.msg)
1209+
}
1210+
return b.msg
1211+
}
1212+
1213+
func validateAvailable(c *Compiler, a Annotation, v any) (pos token.Pos, err error) {
1214+
defer func() {
1215+
if r := recover(); r != nil {
1216+
switch r := r.(type) {
1217+
case string:
1218+
err = errors.New(r)
1219+
case bailout:
1220+
err = errors.New(r.msg)
1221+
pos = r.pos.pos
1222+
case error:
1223+
err = r
1224+
default:
1225+
err = fmt.Errorf("%v", r)
1226+
}
1227+
}
1228+
}()
1229+
const name = "available"
1230+
s, ok := v.(string)
1231+
if !ok {
1232+
return a.ValuePos(name).pos, errors.New("@next(available): should be a string")
1233+
}
1234+
valuePos := a.ValuePos(name)
1235+
expr, err := parser.ParseExpr(s)
1236+
if err != nil {
1237+
return valuePos.pos, errors.New("invalid @next(available) expression")
1238+
}
1239+
evalAvailableExpr(c, valuePos.pos, expr, "next")
1240+
return
1241+
}
1242+
12001243
// isAvailable reports whether the declaration is available in the current language.
12011244
func isAvailable(c *Compiler, decl Node, lang string) bool {
12021245
a := decl.Annotations().get("next")
12031246
s, ok := a.get("available").(string)
12041247
if !ok {
12051248
return true
12061249
}
1207-
pos := a.ValuePos("available")
1250+
valuePos := a.ValuePos("available")
12081251
expr, err := parser.ParseExpr(s)
12091252
if err != nil {
1210-
panic(fmt.Sprintf("%s: invalid @next(available) expression", pos))
1253+
panic(bailout{pos: valuePos, msg: "invalid @next(available) expression"})
12111254
}
1212-
return evalAvailableExpr(c, pos.pos, expr, lang)
1255+
return evalAvailableExpr(c, valuePos.pos, expr, lang)
12131256
}
12141257

12151258
func evalAvailableExpr(c *Compiler, pos token.Pos, expr ast.Expr, lang string) bool {
@@ -1226,7 +1269,7 @@ func evalAvailableExpr(c *Compiler, pos token.Pos, expr ast.Expr, lang string) b
12261269
if expr.Op == token.NOT {
12271270
return !evalAvailableExpr(c, pos, expr.X, lang)
12281271
}
1229-
panic(c.fset.Position(pos+expr.OpPos).String() + ": unexpected unary operator: " + expr.Op.String())
1272+
panic(bailout{pos: positionFor(c, pos+expr.OpPos), msg: "unexpected unary operator: " + expr.Op.String()})
12301273
case *ast.BinaryExpr:
12311274
switch expr.Op {
12321275
case token.OR:
@@ -1238,10 +1281,10 @@ func evalAvailableExpr(c *Compiler, pos token.Pos, expr ast.Expr, lang string) b
12381281
case token.NEQ:
12391282
return evalAvailableExpr(c, pos, expr.X, lang) != evalAvailableExpr(c, pos, expr.Y, lang)
12401283
default:
1241-
panic(c.fset.Position(pos+expr.OpPos).String() + ": unexpected binary operator: " + expr.Op.String())
1284+
panic(bailout{pos: positionFor(c, pos+expr.OpPos), msg: "unexpected binary operator: " + expr.Op.String()})
12421285
}
12431286
default:
1244-
panic(c.fset.Position(pos+expr.Pos()).String() + ": unexpected expression")
1287+
panic(bailout{pos: positionFor(c, pos+expr.Pos()), msg: "unexpected expression"})
12451288
}
12461289
}
12471290

src/compile/platform.go

+8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ import (
88
"path/filepath"
99
)
1010

11+
func absolutePath(name string) (string, error) {
12+
path, err := filepath.Abs(name)
13+
if err == nil {
14+
path = filepath.ToSlash(path)
15+
}
16+
return path, err
17+
}
18+
1119
// FileSystem is an interface that abstracts the file system functions.
1220
type FileSystem interface {
1321
fs.FS

src/compile/template.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func (m Meta) lookup(key string) pair.Pair[string, bool] {
4242
}
4343

4444
func validMetaKey(key string) error {
45-
if !stringutil.IsIdentifer(key) {
45+
if !stringutil.IsASCIIIdentifier(key) {
4646
return fmt.Errorf("must be a valid identifier")
4747
}
4848
if strings.HasPrefix(key, "_") || key == "this" || key == "path" || key == "skip" || key == "perm" {
@@ -621,7 +621,7 @@ func (tc *templateContext) lazyInit() error {
621621
}
622622
for i := range files {
623623
var err error
624-
files[i], err = filepath.Abs(files[i])
624+
files[i], err = absolutePath(files[i])
625625
if err != nil {
626626
return err
627627
}
@@ -914,7 +914,7 @@ func (tc *templateContext) loadTemplate(path string, fs FileSystem) (*template.T
914914
defer f.Close()
915915
content, err = io.ReadAll(f)
916916
} else {
917-
path, err = filepath.Abs(path)
917+
path, err = absolutePath(path)
918918
if err != nil {
919919
return nil, fmt.Errorf("failed to resolve template %q absolute path: %w", path, err)
920920
}
@@ -926,6 +926,7 @@ func (tc *templateContext) loadTemplate(path string, fs FileSystem) (*template.T
926926
if err != nil {
927927
return nil, err
928928
}
929+
path = filepath.ToSlash(path)
929930
t, err := createTemplate(path, string(content), tc.funcs)
930931
if err != nil {
931932
return nil, err

src/grammar/grammar.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,7 @@ func (p *AnnotationParameter) validate(_ *Grammar) error {
14391439
if p.Name == "" {
14401440
return fmt.Errorf("parameter: name is required")
14411441
}
1442-
if !stringutil.IsIdentifer(p.Name) {
1442+
if !stringutil.IsASCIIIdentifier(p.Name) {
14431443
pattern, err := regexp.Compile("^" + p.Name + "$")
14441444
if err != nil {
14451445
return fmt.Errorf("parameter: invalid name pattern %q: %w", p.Name, err)

0 commit comments

Comments
 (0)