/*
Processes the TypeDecls from a set of ast.File objects (which have been created by the parser.)
Generates the runtime environment's objects for datatypes and attributes, and also ensures that db tables exist for these.

Runtime *data.RType's are placed into the argument hashtable once created here.

Note. This function has to operate recursively, since a given supertype (parent type) might not yet exist as a generated
RType object, but might be in this same package so needs to be generated now anyway.

Note. This function does not create the attribute specification part of the runtime RType objects.

Attribute generation has to wait til all of the RTtypes for the package are generated and put in the RT.types map,
so attribute generation will be done as a separate pass.


	allTypeDecls := make(map[string]*ast.TypeDecl)

*/
func (g *Generator) generateTypesWithoutAttributes(allTypeDecls map[string]*ast.TypeDecl, types map[*data.RType]bool, typeDeclFile map[string]string) {

	typesBeingGenerated := make(map[string]bool) // full names of types in the middle of being generated. Use to avoid inheritance loops.

	// Collect all type declarations from all files into a map by full type name
	//
	for file, fileRoot := range g.files {
		for _, typeDeclaration := range file.TypeDecls {
			// egh Nov 12, 12
			//typeName := g.packagePath + typeDeclaration.Spec.Name.Name
			typeName := typeDeclaration.Spec.Name.Name
			if allTypeDecls[typeName] != nil {
				slashPos := strings.LastIndex(typeName, "/")
				typeLocalName := typeName[slashPos+1:]
				rterr.Stopf("Type '%s' declaration in file %s.rel is 2nd declaration of this type found in package.", typeLocalName, fileRoot)
			}
			allTypeDecls[typeName] = typeDeclaration
			typeDeclFile[typeName] = fileRoot
		}
	}

	// Generate the runtime RType objects, recursively.

	for typeName, typeDecl := range allTypeDecls {

		_, found := data.RT.Types[typeName]
		if found {
			continue // the recursion has already generated this type.
		}
		g.generateTypeWithoutAttributes(typeName, typeDecl, allTypeDecls, types, typesBeingGenerated, typeDeclFile)

	}
}
Example #2
0
/*
Give the attribute its sorting attribute or sorting method.
This had to be delayed until all attributes and methods in the package were
generated.
*/
func (g *Generator) configureAttributeSorting(orderFuncOrAttrName string, attr *data.AttributeSpec) {

	var orderAttr *data.AttributeSpec
	var attrFound bool
	var orderMethod *data.RMultiMethod

	// TODO Find out which of attribute or method it is. How????
	// Should be along the lines of:
	// If there is a method of that name defined which takes only typ2 as arg signature, then use that function,
	// Otherwise could check if there is an attribute of that name on typ2 or its supertypes, and if not,
	// throw a type compatibility panic.

	var orderMethodArity int32 = 0

	orderMethod, methodFound := g.pkg.MultiMethods[orderFuncOrAttrName]

	if methodFound {

		dispatcher := g.Interp.Dispatcher()

		// Find out if there is an arity 1 method
		unaryMethod, _ := dispatcher.GetMethodForTypes(orderMethod, attr.Part.Type)
		// Find out if there is an arity 2 method
		binaryMethod, _ := dispatcher.GetMethodForTypes(orderMethod, attr.Part.Type, attr.Part.Type)

		if unaryMethod != nil && binaryMethod != nil {
			rterr.Stopf("Can't order collection because ambiguous unary and binary method '%s' for type %s.", orderFuncOrAttrName, attr.Part.Type.Name)
		}

		if unaryMethod != nil {
			orderMethodArity = 1
		} else if binaryMethod != nil {
			orderMethodArity = 2
		} else {
			rterr.Stopf("Can't order collection. No unary or binary method '%s' found for type %s.", orderFuncOrAttrName, attr.Part.Type.Name)
		}
	} else {
		orderAttr, attrFound = attr.Part.Type.GetAttribute(orderFuncOrAttrName)
		if !attrFound {
			rterr.Stopf("Can't order collection. No method or attribute '%s' found in type %s or supertypes.", orderFuncOrAttrName, attr.Part.Type.Name)
		}
	}

	attr.Part.OrderAttr = orderAttr
	attr.Part.OrderMethod = orderMethod
	attr.Part.OrderMethodArity = orderMethodArity // 1 or 2
}
/*
   Generate a runtime RType object for the type declaration.
   If the parent types are not already generated and are in this package, recurse to generate the parent type before finishing generating this one.
*/
func (g *Generator) generateTypeWithoutAttributes(typeName string, typeDeclaration *ast.TypeDecl, allTypeDecls map[string]*ast.TypeDecl, types map[*data.RType]bool, typesBeingGenerated map[string]bool, typeDeclFile map[string]string) {

	_, found := typesBeingGenerated[typeName]
	if found {
		rterr.Stopf("Type '%s' declaration in file %s.rel is involved in a type inheritance loop!", typeDeclaration.Spec.Name.Name, typeDeclFile[typeName])
	}
	typesBeingGenerated[typeName] = true

	typeSpec := typeDeclaration.Spec
	slashPos := strings.LastIndex(typeSpec.Name.Name, "/")
	typeLocalName := typeSpec.Name.Name[slashPos+1:]
	typeShortName := g.pkg.ShortName + "/" + typeLocalName

	var parentTypeNames []string

	for _, parentTypeSpec := range typeSpec.SuperTypes {

		parentTypeName := g.qualifyTypeName(parentTypeSpec.Name.Name)

		_, parentFound := data.RT.Types[parentTypeName]
		if !parentFound {
			parentTypeDecl, parentDeclaredInPackage := allTypeDecls[parentTypeName]
			if parentDeclaredInPackage {
				g.generateTypeWithoutAttributes(parentTypeName, parentTypeDecl, allTypeDecls, types, typesBeingGenerated, typeDeclFile)
			}

			// If the parent type was not declared in this package but is not already declared in some other package, then the
			// parent type is missing in action.
			// Ignore this problem for the moment here. Let the rt.CreateType method report this error.
		}
		parentTypeNames = append(parentTypeNames, parentTypeName)
	}

	theNewType, err := data.RT.CreateType(typeName, typeShortName, parentTypeNames)
	if err != nil {

		sourceFilename := typeDeclFile[typeName] + ".rel"
		rterr.Stopf("Error creating type %s (%s): %s", typeName, sourceFilename, err.Error())
	}
	if !theNewType.Less(data.CollectionType) {
		theNewType.IsStruct = true
	}

	types[theNewType] = true // record that this is one of the new RTypes we generated !

	delete(typesBeingGenerated, typeName) // remove from the inheritance loop detection map
}
Example #4
0
/*
  Generate a special method just to be a context for executing the constant assignment expressions of a package.
  This method has no code.
*/
func (g *Generator) generatePackageInitMethod() (rMethod *data.RMethod) {

	var methodName string = g.packagePath + "__init__"

	var parameterNames []string
	var nilArgAllowed []bool
	var parameterTypes []string

	var wildcardKeywordsParameterName string
	var wildcardKeywordsParameterType string
	var variadicParameterName string
	var variadicParameterType string

	var returnValTypes []string
	var returnArgsAreNamed bool

	var err error

	allowRedefinition := false

	isTraitAbstractMethod := false

	numLocalVars := 0

	isExported := false

	rMethod, err = data.RT.CreateMethodV(g.packageName,
		nil, // file
		methodName,
		parameterNames,
		nilArgAllowed,
		parameterTypes,
		wildcardKeywordsParameterName,
		wildcardKeywordsParameterType,
		variadicParameterName,
		variadicParameterType,
		returnValTypes,
		returnArgsAreNamed,
		numLocalVars,
		isTraitAbstractMethod,
		allowRedefinition,
		isExported)

	if err != nil {
		// panic(err)
		rterr.Stopf("Error creating method %s: %s", methodName, err.Error())
	}
	Logln(GENERATE__, rMethod)

	return
}
func (g *Generator) generateConstants() {
	for file, fileNameRoot := range g.files {
		for _, constDeclaration := range file.ConstantDecls {

			constantName := g.qualifyConstName(constDeclaration.Name.Name)
			g.Interp.EvalExpr(g.th, constDeclaration.Value)
			obj := g.th.Pop()
			err := data.RT.CreateConstant(constantName, obj)
			if err != nil {
				// panic(err)
				rterr.Stopf("Error in file %s: %s", fileNameRoot+".rel", err.Error())
			}
		}
	}
}
Example #6
0
/*
Checks to see if the package which this source code file says its in already
exists in the runtime. If not, creates it. Sets the pkg variable of the Generator
to refer to the package.
*/
func (g *Generator) generatePackage() {

	relish.EnsureDatabase()
	// creates and/or creates a connection to the running artifact's database.
	// Amongst other things, initializes from db the maps between package names and shortnames in the runtime.

	g.pkg = data.RT.Packages[g.packageName]
	if g.pkg != nil {
		rterr.Stopf("Package %s has already been loaded. Error to load it again.", g.packageName)
	}
	g.pkg = data.RT.CreatePackage(g.packageName, false) // This should init MMMap from core/builtin package

	g.updatePackageDependenciesAndMultiMethodMap()

	g.th.ExecutingPackage = g.pkg
}
/*
Go through the (already loaded) packages that the newly generated package is dependent on, and update the new package's
multimethod map to incorporate multimethods and methods from the dependency packages.
Now does this all at once for all files in the current package being loaded.
IMPORTANT NOTE: That means every file in the current package has access to method-implementations declared in packages which
are not explicitly imported into that particular code file of the current package, but are imported into another
file of the current package. Anyway, currently, the particular code file also has access (through dispatch) to method-implementations
declared even in indirect dependency packages of any of the packages explicitly imported into the current package.
*/
func (g *Generator) updatePackageDependenciesAndMultiMethodMap() {
	for file := range g.files {
		imports := file.RelishImports // package specifications
		for _, importedPackageSpec := range imports {
			dependencyPackageName := importedPackageSpec.OriginAndArtifactName + "/pkg/" + importedPackageSpec.PackageName
			dependencyPackage, dependencyAlreadyProcessed := g.pkg.Dependencies[dependencyPackageName]
			if !dependencyAlreadyProcessed {
				var dependencyPackageExists bool
				dependencyPackage, dependencyPackageExists = data.RT.Packages[dependencyPackageName]
				if !dependencyPackageExists {
					rterr.Stopf("Package %s imported in file %s is an incorrectly defined native extension package.", dependencyPackageName, g.files[file])
				}

				g.pkg.Dependencies[dependencyPackageName] = dependencyPackage

				g.updatePackageMultiMethodMap(dependencyPackage)
			}

		}
	}
}
/*
Returns the fully qualified name of the type.
If the type spec is of a collection type, then ensures that the composite type exists in the runtime,
and if not, creates it.
TODO Handle Maps
TODO Handle nested collection types, like [] [] String

TypeSpec struct {
	Doc            *CommentGroup       // associated documentation; or nil
	Name           *Ident              // type name (or type variable name)
	Type           Expr                // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
	Comment        *CommentGroup       // line comments; or nil
	Params         []*TypeSpec         // Type parameters (egh)
	SuperTypes     []*TypeSpec         // Only valid if this is a type variable (egh)
	CollectionSpec *CollectionTypeSpec // nil or a collection specification
	typ interface{}  // The actual *RType - associated at generation time.
}

type CollectionTypeSpec struct {
	Kind        token.Token
	LDelim      token.Pos
	RDelim      token.Pos
	IsSorting   bool
	IsAscending bool
	OrderFunc   string
}
*/
func (g *Generator) ensureTypeName(typeSpec *ast.TypeSpec, fileNameRoot string) string {

	typ, err := g.Interp.EnsureType(g.packagePath, typeSpec)
	if err != nil {
		rterr.Stopf("Error in file %s: %s", fileNameRoot+".rel", err.Error())
	}
	return typ.Name

	/*
	      var typ *data.RType
	      var err error
	      baseTypeName := g.qualifyTypeName(typeSpec.Name.Name)
	      baseType, baseTypeFound := data.RT.Types[baseTypeName]

	      if ! baseTypeFound {
	         rterr.Stopf("Error in file %s: Type %s not found.", fileNameRoot +".rel", baseTypeName)
	         // panic(fmt.Sprintf("Error in file %s: Type %s not found.", fileNameRoot +".rel", baseTypeName))
	      }

	      if typeSpec.CollectionSpec == nil {
	   	  typ = baseType
	      } else {
	   	    switch typeSpec.CollectionSpec.Kind {
	   	    case token.LIST:
	   			typ, err = data.RT.GetListType(baseType)
	   			if err != nil {
	   			   rterr.Stopf("Error in file %s: %s", fileNameRoot +".rel", err.Error())
	   			}
	   	    case token.SET:
	   			typ, err = data.RT.GetSetType(baseType)
	   			if err != nil {
	   			   rterr.Stopf("Error in file %s: %s", fileNameRoot +".rel", err.Error())
	   			}
	   	    case token.MAP:
	   	       panic("I don't handle Map types yet.")
	   	    }
	   	}
	       return typ.Name
	*/
}
Example #9
0
/*
Update the package's multimethod map to incorporate exported multimethods and methods from a dependency package.
Helper for updatePackageDependenciesAndMultiMethodMap.
*/
func (g *Generator) updatePackageMultiMethodMap(dependencyPackage *data.RPackage) {
	//   if strings.HasSuffix(g.pkg.Name,"basic_tests") {
	//      defer Un(Trace(ALWAYS_, "updatePackageMultiMethodMap of", g.pkg.Name,"from",dependencyPackage.Name))
	//   }

	for multiMethodName, multiMethod := range dependencyPackage.MultiMethods {
		// Loop through all of the dependency package's multimethods.

		// Consider only those multi-methods which are actually owned directly by the dependency package

		if multiMethod.Pkg != dependencyPackage {
			//	      if strings.HasSuffix(g.pkg.Name,"basic_tests") && multiMethod.Pkg != data.RT.InbuiltFunctionsPackage {
			//		     fmt.Println("multimethod is not owned by dependency package!")
			//		     fmt.Println("it is owned by",multiMethod.Pkg)
			//		  }

			continue // must be a multimethod owned by a dependency of the dependency - ignore
		}

		////      if strings.HasSuffix(dependencyPackage.Name,"config") && multiMethod.Name == "dbg" && strings.HasSuffix(g.pkg.Name,"controller") {
		////         fmt.Println("Adding dbg multimethod from config package to controller package during generation.")
		////      }

		// And consider only the exported multimethods of the dependency package

		if !multiMethod.IsExported {
			continue
		}

		////      if strings.HasSuffix(dependencyPackage.Name,"config") && multiMethod.Name == "dbg" && strings.HasSuffix(g.pkg.Name,"controller") {
		////         fmt.Println("multimethod was exported. All ok so far.")
		////         fmt.Println(multiMethod.Debug())
		////      }

		//      if multiMethodName == multiMethod.Name {
		//         fmt.Println(multiMethodName)
		//      } else {
		//	     fmt.Println(multiMethodName,"->",multiMethod.Name)
		//      }

		if multiMethod.MaxArity == 0 {

			// This multimethod from the imported package takes no arguments, so we need to find it
			// it by its package-qualified name. In source code, a name like vehicles.startRace
			// will be needed to invoke this method.
			multiMethod = multiMethod.Clone(g.pkg)
			multiMethod.IsExported = false // This cloned multimethod is still not "owned" by current package,
			// and it should not be re-exported, so mark it as non-exportable.
			qualifiedMethodName := dependencyPackage.Name + "/" + multiMethodName
			g.pkg.MultiMethods[qualifiedMethodName] = multiMethod

			////      	 if strings.HasSuffix(dependencyPackage.Name,"config") && multiMethod.Name == "dbg" && strings.HasSuffix(g.pkg.Name,"controller") {
			////        	 fmt.Println("cloned a zero MaxArity method and set IsExported false.")
			////     	 }

			continue
		}

		myMultiMethod := g.pkg.MultiMethods[multiMethodName]

		if myMultiMethod == nil {
			// If current package does not yet have this multimethod at all...

			g.pkg.MultiMethods[multiMethodName] = multiMethod // use the mm from dependency package

			////      	    if strings.HasSuffix(dependencyPackage.Name,"config") && multiMethod.Name == "dbg" && strings.HasSuffix(g.pkg.Name,"controller") {
			////        	   fmt.Println("using multimethod from config package since controller package has no multimethod yet.")
			////     	    }

		} else if myMultiMethod != multiMethod {
			// Current package has a different mm instance than the dependency package's mm

			////      	    if strings.HasSuffix(dependencyPackage.Name,"config") && multiMethod.Name == "dbg" && strings.HasSuffix(g.pkg.Name,"controller") {
			////        	   fmt.Println("controller package has a different multimethod of same name.")
			////        	   fmt.Println(myMultiMethod.Debug())
			////     	    }

			// Merge them if possible, else complain!! throw runtime error!

			if myMultiMethod.NumReturnArgs != multiMethod.NumReturnArgs {
				rterr.Stopf("Package %s defines %s to return %d values so can't be imported directly or indirectly into package %s which defines %s to return %d values.", dependencyPackage.Name, multiMethod.Name, multiMethod.NumReturnArgs, g.pkg.Name, myMultiMethod.Name, myMultiMethod.NumReturnArgs)

				// TODO Shit! I'm inheriting methods indirectly!!! Not allowed !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

				// Will have to actually create new multimethods for EACH new package right up front,
				// putting in ONLY those methods which are defined in the DIRECT dependency packages.
			}

			// To merge them, I have to know if my multiMethod really belongs to me or if borrowing
			// it so I have to copy it.

			if myMultiMethod.Pkg != g.pkg {
				// The mm in current package's list does not belong to current package
				// So create a clone mm which is owned by the current package

				myMultiMethod = myMultiMethod.Clone(g.pkg)
				myMultiMethod.IsExported = false // This merged multimethod is still not "owned" by current package,
				// and it should not be re-exported, so mark it as non-exportable.

				g.pkg.MultiMethods[multiMethodName] = myMultiMethod

				////      	      if strings.HasSuffix(dependencyPackage.Name,"config") && multiMethod.Name == "dbg" && strings.HasSuffix(g.pkg.Name,"controller") {
				////        	     fmt.Println("controller package's method is from a different package:")
				////        	     fmt.Println("So cloned it into controller package and set IsExported = false")
				////        	     fmt.Println(myMultiMethod.Debug())
				////     	      }

			}

			// Merge in methods from the dependency package's mm into current-package-owned mm of the same name.
			myMultiMethod.MergeInNewMethodsFrom(multiMethod)

			////      	      if strings.HasSuffix(dependencyPackage.Name,"config") && multiMethod.Name == "dbg" && strings.HasSuffix(g.pkg.Name,"controller") {
			////        	     fmt.Println("After merging methods in from config multimethod:")
			////        	     fmt.Println(myMultiMethod.Debug())
			////     	      }

		}
		// else I've (current package has) already got the multimethod - everything's cool
	}
	////    if strings.HasSuffix(dependencyPackage.Name,"config") && strings.HasSuffix(g.pkg.Name,"controller") {
	////       g.pkg.ListMethod("dbg")
	////   }
}
/*
Processes the RelationDecls list of a ast.File object (which has been created by the parser.)
Generates the runtime environment's objects for relations between datatypes, and also ensures
that db tables exist for these.
*/
func (g *Generator) generateRelations(types map[*data.RType]bool, orderings map[string]*data.AttributeSpec) {

	for file, fileNameRoot := range g.files {
		for _, relationDeclaration := range file.RelationDecls {

			end1 := relationDeclaration.End1
			end2 := relationDeclaration.End2

			var minCard1 int32 = 1
			var maxCard1 int32 = 1

			attributeName1 := end1.Name.Name
			multiValuedAttribute1 := (end1.Arity != nil)
			if multiValuedAttribute1 {
				minCard1 = int32(end1.Arity.MinCard)
				maxCard1 = int32(end1.Arity.MaxCard) // -1 means N
			}

			var collectionType1 string

			var orderFuncOrAttrName1 string = ""
			var isAscending1 bool

			if end1.Type.CollectionSpec != nil {
				switch end1.Type.CollectionSpec.Kind {
				case token.SET:
					if end1.Type.CollectionSpec.IsSorting {
						collectionType1 = "sortedset"
						orderFuncOrAttrName1 = end1.Type.CollectionSpec.OrderFunc
						isAscending1 = end1.Type.CollectionSpec.IsAscending
					} else {
						collectionType1 = "set"
					}
				case token.LIST:
					if end1.Type.CollectionSpec.IsSorting {
						collectionType1 = "sortedlist"
						orderFuncOrAttrName1 = end1.Type.CollectionSpec.OrderFunc
						isAscending1 = end1.Type.CollectionSpec.IsAscending
					} else {
						collectionType1 = "list"
					}
				case token.MAP:
					if end1.Type.CollectionSpec.IsSorting {
						collectionType1 = "sortedmap"
						orderFuncOrAttrName1 = end1.Type.CollectionSpec.OrderFunc
						isAscending1 = end1.Type.CollectionSpec.IsAscending
					} else {
						collectionType1 = "map"
					}
				}
			}

			var minCard2 int32 = 1
			var maxCard2 int32 = 1

			attributeName2 := end2.Name.Name
			multiValuedAttribute2 := (end2.Arity != nil)
			if multiValuedAttribute2 {
				minCard2 = int32(end2.Arity.MinCard)
				maxCard2 = int32(end2.Arity.MaxCard) // -1 means N
			}

			var collectionType2 string

			var orderFuncOrAttrName2 string = ""
			var isAscending2 bool

			if end2.Type.CollectionSpec != nil {
				switch end2.Type.CollectionSpec.Kind {
				case token.SET:
					if end2.Type.CollectionSpec.IsSorting {
						collectionType2 = "sortedset"
						orderFuncOrAttrName2 = end2.Type.CollectionSpec.OrderFunc
						isAscending2 = end2.Type.CollectionSpec.IsAscending
					} else {
						collectionType2 = "set"
					}
				case token.LIST:
					if end2.Type.CollectionSpec.IsSorting {
						collectionType2 = "sortedlist"
						orderFuncOrAttrName2 = end2.Type.CollectionSpec.OrderFunc
						isAscending2 = end2.Type.CollectionSpec.IsAscending
					} else {
						collectionType2 = "list"
					}
				case token.MAP:
					if end2.Type.CollectionSpec.IsSorting {
						collectionType2 = "sortedmap"
						orderFuncOrAttrName2 = end2.Type.CollectionSpec.OrderFunc
						isAscending2 = end2.Type.CollectionSpec.IsAscending
					} else {
						collectionType2 = "map"
					}
				}
			}

			typeName1 := g.qualifyTypeName(end1.Type.Name.Name)
			typeName2 := g.qualifyTypeName(end2.Type.Name.Name)

			type1, type2, err := data.RT.CreateRelation(typeName1,
				attributeName1,
				minCard1,
				maxCard1,
				collectionType1,
				orderFuncOrAttrName1,
				isAscending1,
				typeName2,
				attributeName2,
				minCard2,
				maxCard2,
				collectionType2,
				orderFuncOrAttrName2,
				isAscending2,
				false,
				orderings)

			if err != nil {
				// panic(err)
				rterr.Stopf("Error creating relation %s %s -- %s %s (%s): %s", typeName1, attributeName1, attributeName2, typeName2, fileNameRoot+".rel", err.Error())
			}

			types[type1] = true
			types[type2] = true
		}
	}
}
func (g *Generator) generateMethods() {

	for file, fileNameRoot := range g.files {
		for _, methodDeclaration := range file.MethodDecls {

			methodName := methodDeclaration.Name.Name

			// main functions and init<TypeName> functions and web dialog handler functions are explicitly package name qualified.
			//
			// TODO   OOPS Which package are we executing when looking for web handler methods?????

			// TODO TODO Do we really need to prepend package name to init... method names?
			// This implies we cannot add constructors of type package1.Type1 in package2

			if (methodName == "main") ||
				/* Now done at parser.go: 1877
				   (strings.HasPrefix(methodName,"init") && len(methodName) > 5 && 'A' <= methodName[4] && methodName[4] <= 'Z' && !BuiltinTypeName[methodName[4:]]) ||
				*/
				(g.isWebDialogHandlerMethod(fileNameRoot)) {
				methodName = g.packagePath + methodName
			}

			var parameterNames []string
			var nilArgAllowed []bool
			var parameterTypes []string

			var wildcardKeywordsParameterName string
			var wildcardKeywordsParameterType string
			var variadicParameterName string
			var variadicParameterType string

			var returnValTypes []string
			var returnArgsAreNamed bool
			for _, inputArgDecl := range methodDeclaration.Type.Params {

				nilArgAllowed = append(nilArgAllowed, inputArgDecl.Type.NilAllowed)

				if inputArgDecl.IsVariadic {
					if inputArgDecl.Type.CollectionSpec.Kind == token.LIST {
						variadicParameterName = inputArgDecl.Name.Name
						variadicParameterType = g.ensureTypeName(inputArgDecl.Type, fileNameRoot)
						//			         variadicParameterType = g.qualifyTypeName(inputArgDecl.Type.Name.Name)  // g.ensureTypeName(inputArgDecl.Type, fileNameRoot) ???

					} else { // inputArgDecl.Type..CollectionSpec.Kind == token.MAP
						wildcardKeywordsParameterName = inputArgDecl.Name.Name
						wildcardKeywordsParameterType = g.ensureTypeName(inputArgDecl.Type, fileNameRoot)
						//				     wildcardKeywordsParameterType = g.qualifyTypeName(inputArgDecl.Type.Name.Name)  // g.ensureTypeName(inputArgDecl.Type, fileNameRoot)

					}
				} else {
					parameterNames = append(parameterNames, inputArgDecl.Name.Name)
					parameterTypes = append(parameterTypes, g.ensureTypeName(inputArgDecl.Type, fileNameRoot))
				}
			}

			for _, returnArgDecl := range methodDeclaration.Type.Results {
				if returnArgDecl.Name != nil {
					returnArgsAreNamed = true
				}
				returnValTypes = append(returnValTypes, g.ensureTypeName(returnArgDecl.Type, fileNameRoot))
			}

			var rMethod *data.RMethod
			var err error

			if methodDeclaration.IsClosureMethod {
				rMethod, err = data.RT.CreateClosureMethod(g.packageName,
					file,
					methodName,
					parameterNames,
					nilArgAllowed,
					parameterTypes,
					returnValTypes,
					returnArgsAreNamed,
					methodDeclaration.NumLocalVars,
					methodDeclaration.NumFreeVars)
			} else {
				allowRedefinition := false

				// FuncType.	Params  []*InputArgDecl // input parameter declarations. Can be empty list.
				// 	        Results []*ReturnArgDecl // (outgoing) result declarations; Can be empty list.

				rMethod, err = data.RT.CreateMethodV(g.packageName,
					file,
					methodName,
					parameterNames,
					nilArgAllowed,
					parameterTypes,
					wildcardKeywordsParameterName,
					wildcardKeywordsParameterType,
					variadicParameterName,
					variadicParameterType,
					returnValTypes,
					returnArgsAreNamed,
					methodDeclaration.NumLocalVars,
					allowRedefinition)
			}

			if err != nil {
				// panic(err)
				rterr.Stopf("Error creating method %s (%s): %s", methodName, fileNameRoot+".rel", err.Error())
			}

			rMethod.Code = methodDeclaration // abstract syntax tree

			Logln(GENERATE__, rMethod)
		}
	}
}
/*
Processes the TypeDecls list of a ast.File object (which has been created by the parser.)
Generates the runtime environment's objects for attributes of datatypes.
Assumes the RType objects have already been created in the runtime for each datatype by a previous pass over the intermediate-code files.
*/
func (g *Generator) generateAttributes(allTypeDecls map[string]*ast.TypeDecl, types map[*data.RType]bool, typeDeclFile map[string]string, orderings map[string]*data.AttributeSpec) {
	for theNewType := range types {
		typeName := theNewType.Name
		typeDeclaration := allTypeDecls[typeName]
		sourceFilename := typeDeclFile[typeName] + ".rel"

		for _, attrDecl := range typeDeclaration.Attributes {
			var minCard int32 = 1
			var maxCard int32 = 1

			attributeName := attrDecl.Name.Name
			multiValuedAttribute := (attrDecl.Arity != nil)
			if multiValuedAttribute {
				minCard = int32(attrDecl.Arity.MinCard)
				maxCard = int32(attrDecl.Arity.MaxCard) // -1 means N
			} else if attrDecl.Type.NilAllowed {
				minCard = 0
			}

			var collectionType string

			var orderFuncOrAttrName string = ""
			var isAscending bool

			if multiValuedAttribute { // && attrDecl.Type.CollectionSpec != nil {
				switch attrDecl.Type.CollectionSpec.Kind {
				case token.SET:
					if attrDecl.Type.CollectionSpec.IsSorting {
						collectionType = "sortedset"
						orderFuncOrAttrName = attrDecl.Type.CollectionSpec.OrderFunc
						isAscending = attrDecl.Type.CollectionSpec.IsAscending
					} else {
						collectionType = "set"
					}
				case token.LIST:
					if attrDecl.Type.CollectionSpec.IsSorting {
						collectionType = "sortedlist"
						orderFuncOrAttrName = attrDecl.Type.CollectionSpec.OrderFunc
						isAscending = attrDecl.Type.CollectionSpec.IsAscending
					} else {
						collectionType = "list"
					}
				case token.MAP:
					if attrDecl.Type.CollectionSpec.IsSorting {
						collectionType = "sortedmap"
						orderFuncOrAttrName = attrDecl.Type.CollectionSpec.OrderFunc
						isAscending = attrDecl.Type.CollectionSpec.IsAscending
					} else {
						collectionType = "map"
					}
				}
			}

			/*	type CollectionTypeSpec struct {
				   Kind token.Token
				   LDelim token.Pos
				   RDelim token.Pos
				   IsSorting bool
				   IsAscending bool
				   OrderFunc string
				}
			*/

			// If the attribute is a non-owned collection, we should use g.ensureTypeName(...) here.

			// But if it is a multivalued attribute (owned collection with cardinality specified),
			// we should check if there is a Type.Name. If so, use qualifyTypeName on it.
			// If not, use the Name of Type.params[0] and use qualifyTypeName on that.
			// If there is no Name on the params[0], that is the error of using a non-simple type at end of a multi-valued
			// attribute and should be reported as such.

			var attributeTypeName string

			if multiValuedAttribute {
				if attrDecl.Type.Name == nil {
					if attrDecl.Type.Params[0].Name == nil {
						rterr.Stopf("Error creating attribute %s.%s (%s): %s", typeName, attributeName, sourceFilename, "A Multi-valued attribute (with arity specification) must have a simple type, not a collection of collections.")
					} else {
						attributeTypeName = g.qualifyTypeName(attrDecl.Type.Params[0].Name.Name)
					}
				} else {
					attributeTypeName = g.qualifyTypeName(attrDecl.Type.Name.Name)
				}
			} else {
				attributeTypeName = g.ensureTypeName(attrDecl.Type, sourceFilename)
			}

			/*"vector"
			  RelEnd
			     ...
			     CollectionType string // "list", "sortedlist","set", "sortedset", "map", "stringmap", "sortedmap","sortedstringmap",""
			     OrderAttrName string   // which primitive attribute of other is it ordered by when retrieving? "" if none

			     OrderMethod *RMultiMethod
			*/

			_, err := data.RT.CreateAttribute(typeName,
				attributeTypeName,
				attributeName,
				minCard,
				maxCard, // Is the -1 meaning N respected in here???? TODO
				collectionType,
				orderFuncOrAttrName,
				isAscending,
				false,
				false,
				false,
				orderings)
			if err != nil {
				rterr.Stopf("Error creating attribute %s.%s (%s): %s", typeName, attributeName, sourceFilename, err.Error())
			}
		}
	}
}