Skip to content

Commit

Permalink
Extract smaller expressions into separate files (#355)
Browse files Browse the repository at this point in the history
* Rename conditional expr

* Extract template expressions into own file

* Extract operator expressions into own file
  • Loading branch information
dbanck authored Jan 3, 2024
1 parent 47e2378 commit 45db9fd
Show file tree
Hide file tree
Showing 7 changed files with 443 additions and 419 deletions.
134 changes: 0 additions & 134 deletions decoder/expr_any_completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import (
"github.com/hashicorp/hcl-lang/schema"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
)

func (a Any) CompletionAtPos(ctx context.Context, pos hcl.Pos) []lang.Candidate {
Expand Down Expand Up @@ -147,135 +145,3 @@ func (a Any) completeNonComplexExprAtPos(ctx context.Context, pos hcl.Pos) []lan

return candidates
}

func (a Any) completeOperatorExprAtPos(ctx context.Context, pos hcl.Pos) ([]lang.Candidate, bool) {
candidates := make([]lang.Candidate, 0)

switch eType := a.expr.(type) {
case *hclsyntax.BinaryOpExpr:
opReturnType := eType.Op.Type

// Check if such an operation is even allowed within the constraint
if _, err := convert.Convert(cty.UnknownVal(opReturnType), a.cons.OfType); err != nil {
// This could illustrate a situation such as `list_attr = 42 +`
// which is invalid syntax as add (+) op will never produce a list
return candidates, false
}

opFuncParams := eType.Op.Impl.Params()
if len(opFuncParams) != 2 {
// This should never happen if HCL implementation is correct
return candidates, false
}

if eType.LHS.Range().ContainsPos(pos) {
cons := schema.AnyExpression{
OfType: opFuncParams[0].Type,
}
return newExpression(a.pathCtx, eType.LHS, cons).CompletionAtPos(ctx, pos), true
}
if eType.RHS.Range().ContainsPos(pos) || eType.RHS.Range().End.Byte == pos.Byte {
cons := schema.AnyExpression{
OfType: opFuncParams[1].Type,
}
return newExpression(a.pathCtx, eType.RHS, cons).CompletionAtPos(ctx, pos), true
}

return candidates, false

case *hclsyntax.UnaryOpExpr:
opReturnType := eType.Op.Type

// Check if such an operation is even allowed within the constraint
if _, err := convert.Convert(cty.UnknownVal(opReturnType), a.cons.OfType); err != nil {
// This could illustrate a situation such as `list_attr = !`
// which is invalid syntax as negation (!) op will never produce a list
return candidates, false
}

opFuncParams := eType.Op.Impl.Params()
if len(opFuncParams) != 1 {
// This should never happen if HCL implementation is correct
return candidates, false
}

if eType.Val.Range().ContainsPos(pos) || eType.Val.Range().End.Byte == pos.Byte {
cons := schema.AnyExpression{
OfType: opFuncParams[0].Type,
}
return newExpression(a.pathCtx, eType.Val, cons).CompletionAtPos(ctx, pos), true
}

// Trailing dot may be ignored by the parser so we attempt to recover it
if pos.Byte-eType.Val.Range().End.Byte == 1 {
fileBytes := a.pathCtx.Files[eType.Range().Filename].Bytes
trailingRune := fileBytes[eType.Val.Range().End.Byte:pos.Byte][0]

if trailingRune == '.' {
cons := schema.AnyExpression{
OfType: opFuncParams[0].Type,
}
return newExpression(a.pathCtx, eType.Val, cons).CompletionAtPos(ctx, pos), true
}
}

return candidates, false
}

return candidates, true
}

func (a Any) completeTemplateExprAtPos(ctx context.Context, pos hcl.Pos) ([]lang.Candidate, bool) {
candidates := make([]lang.Candidate, 0)

switch eType := a.expr.(type) {
case *hclsyntax.TemplateExpr:
if eType.IsStringLiteral() {
return candidates, false
}

for _, partExpr := range eType.Parts {
// We overshot the position and stop
if partExpr.Range().Start.Byte > pos.Byte {
break
}

// We're not checking the end byte position here, because we don't
// allow completion after the }
if partExpr.Range().ContainsPos(pos) || partExpr.Range().End.Byte == pos.Byte {
cons := schema.AnyExpression{
OfType: cty.String,
}
return newExpression(a.pathCtx, partExpr, cons).CompletionAtPos(ctx, pos), true
}

// Trailing dot may be ignored by the parser so we attempt to recover it
if pos.Byte-partExpr.Range().End.Byte == 1 {
fileBytes := a.pathCtx.Files[partExpr.Range().Filename].Bytes
trailingRune := fileBytes[partExpr.Range().End.Byte:pos.Byte][0]

if trailingRune == '.' {
cons := schema.AnyExpression{
OfType: cty.String,
}
return newExpression(a.pathCtx, partExpr, cons).CompletionAtPos(ctx, pos), true
}
}
}

return candidates, false
case *hclsyntax.TemplateWrapExpr:
if eType.Wrapped.Range().ContainsPos(pos) {
cons := schema.AnyExpression{
OfType: cty.String,
}
return newExpression(a.pathCtx, eType.Wrapped, cons).CompletionAtPos(ctx, pos), true
}

return candidates, false
case *hclsyntax.TemplateJoinExpr:
// TODO: implement when support for expressions https://github.com/hashicorp/terraform-ls/issues/527 lands
}

return candidates, true
}
File renamed without changes.
91 changes: 0 additions & 91 deletions decoder/expr_any_hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import (
"github.com/hashicorp/hcl-lang/schema"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
)

func (a Any) HoverAtPos(ctx context.Context, pos hcl.Pos) *lang.HoverData {
Expand Down Expand Up @@ -140,92 +138,3 @@ func (a Any) hoverNonComplexExprAtPos(ctx context.Context, pos hcl.Pos) *lang.Ho
}
return lt.HoverAtPos(ctx, pos)
}

func (a Any) hoverOperatorExprAtPos(ctx context.Context, pos hcl.Pos) (*lang.HoverData, bool) {
switch eType := a.expr.(type) {
case *hclsyntax.BinaryOpExpr:
opReturnType := eType.Op.Type

// Check if such an operation is even allowed within the constraint
if _, err := convert.Convert(cty.UnknownVal(opReturnType), a.cons.OfType); err != nil {
return nil, true
}

opFuncParams := eType.Op.Impl.Params()
if len(opFuncParams) != 2 {
// This should never happen if HCL implementation is correct
return nil, true
}

if eType.LHS.Range().ContainsPos(pos) {
cons := schema.AnyExpression{
OfType: opFuncParams[0].Type,
}
return newExpression(a.pathCtx, eType.LHS, cons).HoverAtPos(ctx, pos), true
}
if eType.RHS.Range().ContainsPos(pos) {
cons := schema.AnyExpression{
OfType: opFuncParams[1].Type,
}
return newExpression(a.pathCtx, eType.RHS, cons).HoverAtPos(ctx, pos), true
}

return nil, true

case *hclsyntax.UnaryOpExpr:
opReturnType := eType.Op.Type

// Check if such an operation is even allowed within the constraint
if _, err := convert.Convert(cty.UnknownVal(opReturnType), a.cons.OfType); err != nil {
return nil, true
}

opFuncParams := eType.Op.Impl.Params()
if len(opFuncParams) != 1 {
// This should never happen if HCL implementation is correct
return nil, true
}

if eType.Val.Range().ContainsPos(pos) {
cons := schema.AnyExpression{
OfType: opFuncParams[0].Type,
}
return newExpression(a.pathCtx, eType.Val, cons).HoverAtPos(ctx, pos), true
}

return nil, true
}

return nil, false
}

func (a Any) hoverTemplateExprAtPos(ctx context.Context, pos hcl.Pos) (*lang.HoverData, bool) {
switch eType := a.expr.(type) {
case *hclsyntax.TemplateExpr:
if eType.IsStringLiteral() {
return nil, false
}

for _, partExpr := range eType.Parts {
if partExpr.Range().ContainsPos(pos) {
cons := schema.AnyExpression{
OfType: cty.String,
}
return newExpression(a.pathCtx, partExpr, cons).HoverAtPos(ctx, pos), true
}
}

return nil, true
case *hclsyntax.TemplateWrapExpr:
if eType.Wrapped.Range().ContainsPos(pos) {
cons := schema.AnyExpression{
OfType: cty.String,
}
return newExpression(a.pathCtx, eType.Wrapped, cons).HoverAtPos(ctx, pos), true
}

return nil, true
}

return nil, false
}
Loading

0 comments on commit 45db9fd

Please sign in to comment.