Skip to content

Commit

Permalink
fix(parser): compiler directives without args
Browse files Browse the repository at this point in the history
  • Loading branch information
emil14 committed Jan 11, 2024
1 parent bd6ffd8 commit a331509
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 423 deletions.
195 changes: 92 additions & 103 deletions internal/compiler/analyzer/component_nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

//nolint:lll
var (
ErrInterfaceWithStructInports = errors.New("Interface cannot use structs inports directive, only components can")
ErrStructInportsArgNonStruct = errors.New("Type argument for component with struct inports directive must be struct")
ErrStructInportsNodeTypeArgsCount = errors.New("Note that uses component with struct inports directive must pass exactly one type argument")
ErrStructInportsTypeParamConstr = errors.New("Component that uses struct inports directive must have type parameter with struct constraint")
Expand Down Expand Up @@ -132,144 +131,134 @@ func (a Analyzer) analyzeComponentNode(node src.Node, scope src.Scope) (src.Node
}, iface, nil
}

func (a Analyzer) getResolvedNodeInterface( //nolint:funlen,gocognit
func (a Analyzer) getResolvedNodeInterface( //nolint:funlen
entity src.Entity,
hasRuntimeMsg bool,
location src.Location,
node src.Node,
scope src.Scope,
) (src.Interface, *compiler.Error) {
var iface src.Interface

_, hasStructInportsDirective := node.Directives[compiler.StructInports]

if entity.Kind == src.ComponentEntity { //nolint:nestif
runtimeFuncArgs, isRuntimeFunc := entity.Component.Directives[compiler.RuntimeFuncDirective]

if hasRuntimeMsg && !isRuntimeFunc {
if entity.Kind == src.InterfaceEntity {
if hasRuntimeMsg {
return src.Interface{}, &compiler.Error{
Err: ErrNormNodeRuntimeMsg,
Err: ErrInterfaceNodeWithRuntimeMsg,
Location: &location,
Meta: entity.Meta(),
}
}

if len(runtimeFuncArgs) > 1 && len(node.TypeArgs) != 1 {
if node.Deps != nil {
return src.Interface{}, &compiler.Error{
Err: ErrRuntimeFuncOverloadingNodeArgs,
Err: ErrNonComponentNodeWithDI,
Location: &location,
Meta: entity.Meta(),
}
}

iface = entity.Component.Interface
return entity.Interface, nil
}

if !hasStructInportsDirective {
return iface, nil
runtimeFuncArgs, isRuntimeFunc := entity.Component.Directives[compiler.RuntimeFuncDirective]

if hasRuntimeMsg && !isRuntimeFunc {
return src.Interface{}, &compiler.Error{
Err: ErrNormNodeRuntimeMsg,
Location: &location,
Meta: entity.Meta(),
}
}

if hasStructInportsDirective {
if len(iface.IO.In) != 0 {
return src.Interface{}, &compiler.Error{
Err: ErrNormalInportsWithStructInportsDirective,
Location: &location,
Meta: entity.Meta(),
}
}
if len(runtimeFuncArgs) > 1 && len(node.TypeArgs) != 1 {
return src.Interface{}, &compiler.Error{
Err: ErrRuntimeFuncOverloadingNodeArgs,
Location: &location,
Meta: entity.Meta(),
}
}

if len(iface.TypeParams.Params) != 1 {
return src.Interface{}, &compiler.Error{
Err: ErrStructInportsTypeParamsCount,
Location: &location,
Meta: entity.Meta(),
}
}
iface := entity.Component.Interface

resolvedTypeParamConstr, err := a.resolver.ResolveExpr(*iface.TypeParams.Params[0].Constr, scope)
if err != nil {
return src.Interface{}, &compiler.Error{
Err: err,
Location: &location,
Meta: entity.Meta(),
}
}
_, hasStructInportsDirective := entity.Component.Directives[compiler.StructInports]

if resolvedTypeParamConstr.Lit == nil || resolvedTypeParamConstr.Lit.Struct == nil {
return src.Interface{}, &compiler.Error{
Err: ErrStructInportsTypeParamConstr,
Location: &location,
Meta: entity.Meta(),
}
}
if !hasStructInportsDirective {
return iface, nil
}

if len(node.TypeArgs) != 1 {
return src.Interface{}, &compiler.Error{
Err: ErrStructInportsNodeTypeArgsCount,
Location: &location,
Meta: entity.Meta(),
}
}
// handle struct inports directive case:

resolvedNodeArg, err := a.resolver.ResolveExpr(node.TypeArgs[0], scope)
if err != nil {
return src.Interface{}, &compiler.Error{
Err: err,
Location: &location,
Meta: entity.Meta(),
}
}
if len(iface.IO.In) != 0 {
return src.Interface{}, &compiler.Error{
Err: ErrNormalInportsWithStructInportsDirective,
Location: &location,
Meta: entity.Meta(),
}
}

if resolvedNodeArg.Lit == nil || resolvedNodeArg.Lit.Struct == nil {
return src.Interface{}, &compiler.Error{
Err: ErrStructInportsArgNonStruct,
Location: &location,
Meta: entity.Meta(),
}
}
if len(iface.TypeParams.Params) != 1 {
return src.Interface{}, &compiler.Error{
Err: ErrStructInportsTypeParamsCount,
Location: &location,
Meta: entity.Meta(),
}
}

structFields := resolvedNodeArg.Lit.Struct
inports := make(map[string]src.Port, len(structFields))
for fieldName, fieldTypeExpr := range structFields {
inports[fieldName] = src.Port{
TypeExpr: fieldTypeExpr,
}
}
resolvedTypeParamConstr, err := a.resolver.ResolveExpr(*iface.TypeParams.Params[0].Constr, scope)
if err != nil {
return src.Interface{}, &compiler.Error{
Err: err,
Location: &location,
Meta: entity.Meta(),
}
}

iface = src.Interface{
TypeParams: iface.TypeParams,
IO: src.IO{
In: inports,
Out: iface.IO.Out,
},
Meta: iface.Meta,
}
if resolvedTypeParamConstr.Lit == nil || resolvedTypeParamConstr.Lit.Struct == nil {
return src.Interface{}, &compiler.Error{
Err: ErrStructInportsTypeParamConstr,
Location: &location,
Meta: entity.Meta(),
}
} else {
if hasStructInportsDirective {
return src.Interface{}, &compiler.Error{
Err: ErrInterfaceWithStructInports,
Location: &location,
Meta: entity.Meta(),
}
}

if len(node.TypeArgs) != 1 {
return src.Interface{}, &compiler.Error{
Err: ErrStructInportsNodeTypeArgsCount,
Location: &location,
Meta: entity.Meta(),
}
}

if hasRuntimeMsg {
return src.Interface{}, &compiler.Error{
Err: ErrInterfaceNodeWithRuntimeMsg,
Location: &location,
Meta: entity.Meta(),
}
resolvedNodeArg, err := a.resolver.ResolveExpr(node.TypeArgs[0], scope)
if err != nil {
return src.Interface{}, &compiler.Error{
Err: err,
Location: &location,
Meta: entity.Meta(),
}
}

if node.Deps != nil {
return src.Interface{}, &compiler.Error{
Err: ErrNonComponentNodeWithDI,
Location: &location,
Meta: entity.Meta(),
}
if resolvedNodeArg.Lit == nil || resolvedNodeArg.Lit.Struct == nil {
return src.Interface{}, &compiler.Error{
Err: ErrStructInportsArgNonStruct,
Location: &location,
Meta: entity.Meta(),
}
}

structFields := resolvedNodeArg.Lit.Struct
inports := make(map[string]src.Port, len(structFields))
for fieldName, fieldTypeExpr := range structFields {
inports[fieldName] = src.Port{
TypeExpr: fieldTypeExpr,
}
}

iface = entity.Interface
iface = src.Interface{
TypeParams: iface.TypeParams,
IO: src.IO{
In: inports,
Out: iface.IO.Out,
},
Meta: iface.Meta,
}

return iface, nil
Expand Down
1 change: 1 addition & 0 deletions internal/compiler/parser/listener_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ func parseCompilerDirectives(actx generated.ICompilerDirectivesContext) map[src.
for _, directive := range directives {
id := directive.IDENTIFIER()
if directive.CompilerDirectivesArgs() == nil {
result[src.Directive(id.GetText())] = []string{}
continue
}
args := directive.CompilerDirectivesArgs().AllCompiler_directive_arg() //nolint:nosnakecase
Expand Down
Loading

0 comments on commit a331509

Please sign in to comment.