Skip to content

Commit

Permalink
cuepls: implement parsecue package
Browse files Browse the repository at this point in the history
WIP
DO NOT REVIEW
DO NOT SUBMIT

For #142

Signed-off-by: Paul Jolly <paul@myitcv.io>
Change-Id: Iaa3e7beedecd7d5d7cbf5337e70020556556d45a
  • Loading branch information
myitcv committed Feb 14, 2024
1 parent d185263 commit dec2a20
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 0 deletions.
86 changes: 86 additions & 0 deletions internal/golangorgx/gopls/lsp/cache/parsecue/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package parsego

import (
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/parser"
"cuelang.org/go/cue/token"
"cuelang.org/go/internal/golangorgx/gopls/protocol"
)

// A File contains the results of parsing a Go file.
type File struct {
URI protocol.DocumentURI
Options []parser.Option
File *ast.File
Tok *token.File
// Source code used to build the AST. It may be different from the
// actual content of the file if we have fixed the AST.
Src []byte

// Mapper is a mapping wrapper around Src
Mapper *protocol.Mapper

ParseErr error
}

// Fixed reports whether p was "Fixed", meaning that its source or positions
// may not correlate with the original file.
func (p File) Fixed() bool {
return false
}

// -- go/token domain convenience helpers --

// PositionPos returns the token.Pos of protocol position p within the file.
func (pgf *File) PositionPos(p protocol.Position) (token.Pos, error) {
offset, err := pgf.Mapper.PositionOffset(p)
if err != nil {
return token.NoPos, err
}
return pgf.Tok.Pos(offset, 0), nil
}

// PosRange returns a protocol Range for the token.Pos interval in this file.
func (pgf *File) PosRange(start, end token.Pos) (protocol.Range, error) {
return pgf.Mapper.PosRangeCUE(pgf.Tok, start, end)
}

// PosMappedRange returns a MappedRange for the token.Pos interval in this file.
// A MappedRange can be converted to any other form.
func (pgf *File) PosMappedRange(start, end token.Pos) (protocol.MappedRange, error) {
return pgf.Mapper.PosMappedRangeCUE(pgf.Tok, start, end)
}

// PosLocation returns a protocol Location for the token.Pos interval in this file.
func (pgf *File) PosLocation(start, end token.Pos) (protocol.Location, error) {
return pgf.Mapper.PosLocationCUE(pgf.Tok, start, end)
}

// NodeRange returns a protocol Range for the ast.Node interval in this file.
func (pgf *File) NodeRange(node ast.Node) (protocol.Range, error) {
return pgf.Mapper.NodeRangeCUE(pgf.Tok, node)
}

// NodeMappedRange returns a MappedRange for the ast.Node interval in this file.
// A MappedRange can be converted to any other form.
func (pgf *File) NodeMappedRange(node ast.Node) (protocol.MappedRange, error) {
return pgf.Mapper.NodeMappedRangeCUE(pgf.Tok, node)
}

// NodeLocation returns a protocol Location for the ast.Node interval in this file.
func (pgf *File) NodeLocation(node ast.Node) (protocol.Location, error) {
return pgf.Mapper.PosLocationCUE(pgf.Tok, node.Pos(), node.End())
}

// RangePos parses a protocol Range back into the go/token domain.
func (pgf *File) RangePos(r protocol.Range) (token.Pos, token.Pos, error) {
start, end, err := pgf.Mapper.RangeOffsets(r)
if err != nil {
return token.NoPos, token.NoPos, err
}
return pgf.Tok.Pos(start, 0), pgf.Tok.Pos(end, 0), nil
}
36 changes: 36 additions & 0 deletions internal/golangorgx/gopls/lsp/cache/parsecue/parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package parsego

import (
"context"

"cuelang.org/go/cue/parser"

"cuelang.org/go/internal/golangorgx/gopls/protocol"
"cuelang.org/go/internal/golangorgx/tools/event"
"cuelang.org/go/internal/golangorgx/tools/event/tag"
)

// Parse parses a buffer of Go source, repairing the tree if necessary.
//
// The provided ctx is used only for logging.
func Parse(ctx context.Context, uri protocol.DocumentURI, src []byte, options ...parser.Option) (res *File) {
ctx, done := event.Start(ctx, "cache.ParseGoSrc", tag.File.Of(uri.Path()))
defer done()

file, parseErr := parser.ParseFile(uri.Path(), src, options...)
tok := file.Pos().File()

return &File{
URI: uri,
Options: options,
Src: src,
File: file,
Tok: tok,
Mapper: protocol.NewMapper(uri, src),
ParseErr: parseErr,
}
}
34 changes: 34 additions & 0 deletions internal/golangorgx/gopls/protocol/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ import (
"sync"
"unicode/utf8"

cueast "cuelang.org/go/cue/ast"
cuetoken "cuelang.org/go/cue/token"
"cuelang.org/go/internal/golangorgx/gopls/util/safetoken"
)

Expand Down Expand Up @@ -334,6 +336,16 @@ func (m *Mapper) PosLocation(tf *token.File, start, end token.Pos) (Location, er
return m.RangeLocation(rng), nil
}

// PosLocationCUE converts a token range to a protocol (UTF-16) location.
func (m *Mapper) PosLocationCUE(tf *cuetoken.File, start, end cuetoken.Pos) (Location, error) {
startOffset, endOffset := tf.Offset(start), tf.Offset(end)
rng, err := m.OffsetRange(startOffset, endOffset)
if err != nil {
return Location{}, err
}
return m.RangeLocation(rng), nil
}

// PosRange converts a token range to a protocol (UTF-16) range.
func (m *Mapper) PosRange(tf *token.File, start, end token.Pos) (Range, error) {
startOffset, endOffset, err := safetoken.Offsets(tf, start, end)
Expand All @@ -343,11 +355,22 @@ func (m *Mapper) PosRange(tf *token.File, start, end token.Pos) (Range, error) {
return m.OffsetRange(startOffset, endOffset)
}

// PosRangeCUE converts a token range to a protocol (UTF-16) range.
func (m *Mapper) PosRangeCUE(tf *cuetoken.File, start, end cuetoken.Pos) (Range, error) {
startOffset, endOffset := tf.Offset(start), tf.Offset(end)
return m.OffsetRange(startOffset, endOffset)
}

// NodeRange converts a syntax node range to a protocol (UTF-16) range.
func (m *Mapper) NodeRange(tf *token.File, node ast.Node) (Range, error) {
return m.PosRange(tf, node.Pos(), node.End())
}

// NodeRangeCUE converts a syntax node range to a protocol (UTF-16) range.
func (m *Mapper) NodeRangeCUE(tf *cuetoken.File, node cueast.Node) (Range, error) {
return m.PosRangeCUE(tf, node.Pos(), node.End())
}

// RangeLocation pairs a protocol Range with its URI, in a Location.
func (m *Mapper) RangeLocation(rng Range) Location {
return Location{URI: m.URI, Range: rng}
Expand All @@ -362,11 +385,22 @@ func (m *Mapper) PosMappedRange(tf *token.File, start, end token.Pos) (MappedRan
return m.OffsetMappedRange(startOffset, endOffset)
}

// PosMappedRangeCUE returns a MappedRange for the given token.Pos range.
func (m *Mapper) PosMappedRangeCUE(tf *cuetoken.File, start, end cuetoken.Pos) (MappedRange, error) {
startOffset, endOffset := tf.Offset(start), tf.Offset(end)
return m.OffsetMappedRange(startOffset, endOffset)
}

// NodeMappedRange returns a MappedRange for the given node range.
func (m *Mapper) NodeMappedRange(tf *token.File, node ast.Node) (MappedRange, error) {
return m.PosMappedRange(tf, node.Pos(), node.End())
}

// NodeMappedRangeCUE returns a MappedRange for the given node range.
func (m *Mapper) NodeMappedRangeCUE(tf *cuetoken.File, node cueast.Node) (MappedRange, error) {
return m.PosMappedRangeCUE(tf, node.Pos(), node.End())
}

// -- MappedRange --

// A MappedRange represents a valid byte-offset range of a file.
Expand Down

0 comments on commit dec2a20

Please sign in to comment.