예제 #1
0
/*
   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) {
	g.SetCodeFile(g.astFiles[typeDeclFile[typeName]])
	_, found := typesBeingGenerated[typeName]
	if found {
		rterr.Stopf1(g, typeDeclaration, "Type '%s' declaration is involved in a type inheritance loop!", typeDeclaration.Spec.Name.Name)
	}
	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)

		parentType, parentFound := data.RT.Types[parentTypeName]
		if parentFound {
			if parentType.IsPrivate && parentType.Package != g.pkg {
				rterr.Stopf1(g, typeDeclaration, "Error creating type %s: Supertype %s is private (visible only inside its package).", typeName, parentTypeName)
			}
		} else {
			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 {
		rterr.Stopf1(g, typeDeclaration, "Error creating type %s: %s", typeName, err.Error())
	}

	if !theNewType.Less(data.CollectionType) {
		theNewType.IsStruct = true
	}

	theNewType.Package = g.pkg

	if strings.HasSuffix(typeDeclFile[typeName], "private") {
		theNewType.IsPrivate = 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
}
예제 #2
0
/*
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 {
		g.SetCodeFile(file)
		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.Stopf1(g, typeDeclaration, "Type '%s' declaration is 2nd declaration of this type found in package.", typeLocalName)
			}
			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)

	}
}
예제 #3
0
/*
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) string {

	typ, err := g.Interp.EnsureType(g.packagePath, typeSpec)
	if err != nil {
		// rterr.Stopf("Error in file %s: %s", fileNameRoot +".rel", err.Error())
		rterr.Stop1(g, typeSpec, err)
	}
	if typ.IsPrivate && typ.Package != g.pkg {
		rterr.Stopf1(g, typeSpec, "Type %s is private to its package. Not visible.", typ.Name)
	}
	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
	*/
}
예제 #4
0
/*
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 {
		g.SetCodeFile(file)
		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.Stopf1(g, importedPackageSpec, "Imported package %s is an incorrectly defined native extension package.", dependencyPackageName)
				}

				g.pkg.Dependencies[dependencyPackageName] = dependencyPackage

				g.updatePackageMultiMethodMap(dependencyPackage)
			}

		}
	}
}
예제 #5
0
/*
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 := range g.files {
		g.SetCodeFile(file)
		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,
				end1.PublicReadable,
				end1.PackageReadable,
				end1.SubtypeReadable,
				end1.PublicWriteable,
				end1.PackageWriteable,
				end1.SubtypeWriteable,
				end1.Reassignable,
				end1.CollectionMutable,
				end1.Mutable,
				end1.DeeplyMutable,
				end2.PublicReadable,
				end2.PackageReadable,
				end2.SubtypeReadable,
				end2.PublicWriteable,
				end2.PackageWriteable,
				end2.SubtypeWriteable,
				end2.Reassignable,
				end2.CollectionMutable,
				end2.Mutable,
				end2.DeeplyMutable)

			if err != nil {
				// panic(err)
				rterr.Stopf1(g, relationDeclaration, "Error creating relation %s %s -- %s %s: %s", typeName1, attributeName1, attributeName2, typeName2, err.Error())
			}

			if type1.IsPrivate && g.pkg != type1.Package {
				rterr.Stopf1(g, relationDeclaration, "Error creating relation %s %s -- %s %s: Type %s is private and not visible in this package.", typeName1, attributeName1, attributeName2, typeName2, typeName1)
			}
			if type2.IsPrivate && g.pkg != type2.Package {
				rterr.Stopf1(g, relationDeclaration, "Error creating attribute %s.%s (%s): Type %s is private and not visible in this package.", typeName1, attributeName1, attributeName2, typeName2, typeName2)
			}

			types[type1] = true
			types[type2] = true
		}
	}
}
예제 #6
0
func (g *Generator) generateMethods() {

	for file, fileNameRoot := range g.files {
		g.SetCodeFile(file)
		privateCode := g.isPrivateCodeFile(fileNameRoot)
		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)
						//			         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)
						//				     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))
				}
			}

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

			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

				isTraitAbstractMethod := methodDeclaration.Body == nil && g.pkg.IsTrait

				// 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,
					isTraitAbstractMethod,
					allowRedefinition,
					!privateCode)
			}

			if err != nil {
				// panic(err)
				rterr.Stopf1(g, methodDeclaration, "Error creating method %s: %s", methodName, err.Error())
			}

			rMethod.Code = methodDeclaration // abstract syntax tree

			Logln(GENERATE__, rMethod)
		}
	}
}
예제 #7
0
/*
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]
		g.SetCodeFile(g.astFiles[typeDeclFile[typeName]])

		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.Stopf1(g, attrDecl, "Error creating attribute %s.%s: %s", typeName, attributeName, "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)
			}

			/*"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
			*/

			attr, 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,
				attrDecl.PublicReadable,
				attrDecl.PackageReadable,
				attrDecl.SubtypeReadable,
				attrDecl.PublicWriteable,
				attrDecl.PackageWriteable,
				attrDecl.SubtypeWriteable,
				attrDecl.Reassignable,
				attrDecl.CollectionMutable,
				attrDecl.Mutable,
				attrDecl.DeeplyMutable)
			if err != nil {
				rterr.Stopf1(g, attrDecl, "Error creating attribute %s.%s (%s): %s", typeName, attributeName, err.Error())
			}
			if attr.Part.Type.IsPrivate && g.pkg != attr.Part.Type.Package {
				rterr.Stopf1(g, attrDecl, "Error creating attribute %s.%s (%s): Type %s is private and not visible in this package.", typeName, attributeName, attributeTypeName)
			}
		}
	}
}