You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: resolver.go
    path of file: ./repos/gauge/parser
    
    the code of the file until where you have to start completion: /*----------------------------------------------------------------
 *  Copyright (c) ThoughtWorks, Inc.
 *  Licensed under the Apache License, Version 2.0
 *  See LICENSE in the project root for license information.
 *----------------------------------------------------------------*/

package parser

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/getgauge/gauge-proto/go/gauge_messages"
	"github.com/getgauge/gauge/gauge"
	"github.com/getgauge/gauge/util"
)

type invalidSpecialParamError struct {
	message string
}

type resolverFn func(string) (*gauge.StepArg, error)
type specialTypeResolver struct {
	predefinedResolvers map[string]resolverFn
}

func (invalidSpecialParamError invalidSpecialParamError) Error() string {
	return invalidSpecialParamError.message
}

//Resolve takes a step, a lookup and updates the target after reconciling the dynamic paramters from the given lookup
func Resolve(step *gauge.Step, parent *gauge.Step, lookup *gauge.ArgLookup, target *gauge_messages.ProtoStep) error {
	stepParameters, err := getResolvedParams(step, parent, lookup)
	if err != nil {
		return err
	}
	paramIndex := 0
	for fragmentIndex, fragment := range target.Fragments {
		if fragment.GetFragmentType() == gauge_messages.Fragment_Parameter {
			target.Fragments[fragmentIndex].Parameter = stepParameters[paramIndex]
			paramIndex++
		}
	}
	return nil
}

// getResolvedParams based on the arg type(static, dynamic, table, special_string, special_table) resolves the parameter of a step.
func getResolvedParams(step *gauge.Step, parent *gauge.Step, lookup *gauge.ArgLookup) ([]*gauge_messages.Parameter, error) {
	parameters := make([]*gauge_messages.Parameter, 0)
	for _, arg := range step.Args {
		parameter := new(gauge_messages.Parameter)
		parameter.Name = arg.Name
		if arg.ArgType == gauge.Static {
			pa
    
func getResolvedParams(step *gauge.Step, parent *gauge.Step, lookup *gauge.ArgLookup) ([]*gauge_messages.Parameter, error) {
	parameters := make([]*gauge_messages.Parameter, 0)
	for _, arg := range step.Args {
		parameter := new(gauge_messages.Parameter)
		parameter.Name = arg.Name
		if arg.ArgType == gauge.Static {
			parameter.ParameterType = gauge_messages.Parameter_Static
			parameter.Value = arg.Value
		} else if arg.ArgType == gauge.Dynamic {
			var resolvedArg *gauge.StepArg
			var err error
			if parent != nil {
				resolvedArg, err = parent.GetArg(arg.Value)
			} else {
				resolvedArg, err = lookup.GetArg(arg.Value)
			}
			if err != nil {
				return nil, err
			}
			//In case a special table used in a concept, you will get a dynamic table value which has to be resolved from the concept lookup
			parameter.Name = resolvedArg.Name
			if resolvedArg.Table.IsInitialized() {
				parameter.ParameterType = gauge_messages.Parameter_Special_Table
				table, err := createProtoStepTable(&resolvedArg.Table, lookup)
				if err != nil {
					return nil, err
				}
				parameter.Table = table
			} else {
				parameter.ParameterType = gauge_messages.Parameter_Dynamic
				parameter.Value = resolvedArg.Value
			}
		} else if arg.ArgType == gauge.SpecialString {
			parameter.ParameterType = gauge_messages.Parameter_Special_String
			parameter.Value = arg.Value
		} else if arg.ArgType == gauge.SpecialTable {
			parameter.ParameterType = gauge_messages.Parameter_Special_Table
			table, err := createProtoStepTable(&arg.Table, lookup)
			if err != nil {
				return nil, err
			}
			parameter.Table = table
		} else {
			parameter.ParameterType = gauge_messages.Parameter_Table
			table, err := createProtoStepTable(&arg.Table, lookup)
			if err != nil {
				return nil, err
			}
			parameter.Table = table
		}
		parameters = append(parameters, parameter)
	}

	return parameters, nil
}