diff --git a/lib/gaptypes.g b/lib/gaptypes.g index 68080a7eaa5bbbffb7c27796012b68ae6394acb6..04e987f74f7edf4bea953ce468894a90de038ce9 100644 --- a/lib/gaptypes.g +++ b/lib/gaptypes.g @@ -10,6 +10,45 @@ LoadPackage("json"); LoadPackage("io"); +___debug___ := true; + + +# Returns the first global variable that this is assigned +# to +GVarNameForObject := function( obj ) + local n, res; + return "Markus fix this you lazy git"; + + n := NameFunction(obj); + if IsBoundGlobal(n) and ValueGlobal(n) = obj then + return n; + else + for n in NamesGVars() do + if IsBoundGlobal(n) then + if ValueGlobal(n) = obj then + return n; + fi; + fi; + od; + fi; + return ""; +end; + +FindFilterId := function( filter ) + local i; + + if IsFilter(filter) then + for i in [1..Length(FILTERS)] do + if FILTERS[i] = filter then + return i; + fi; + od; + else + Error("not a filter"); + fi; + return fail; +end; + FindOperationId := function( oper ) local i; @@ -53,7 +92,7 @@ GAPAndFilterUnpack := function(t) if IsOperation(t) then if (IsInt(FLAG1_FILTER(t)) and IsInt(FLAG2_FILTER(t))) then - Add(res, NAME_FUNC(t)); + Add(res, NameFunction(t)); else Append(res, GAPAndFilterUnpack(FLAG1_FILTER(t))); Append(res, GAPAndFilterUnpack(FLAG2_FILTER(t))); @@ -78,57 +117,142 @@ GAPFilterToFilterType := function(fid) fi; end; + +GAPFilterInfo := function(res, name, f) + local lres, ff, i; + + lres := rec(); + i := FindFilterId(f); + if i = fail then + Print("Cannot find filter ", name, " ", f); + else + + lres.type := GAPFilterToFilterType(i); + # if the filter is an attribute and FLAG1_FILTER of the filter + # is not equal to it, then this is a tester. + ff := TRUES_FLAGS(WITH_IMPS_FLAGS(FLAGS_FILTER(f))); + ff := List(ff, function(f) + if IsBound(FILTERS[f]) then + return GVarNameForObject(FILTERS[f]); + else + if ___debug___ then + Error("Unable to find a global variable name for"); + fi; + return "<<unknown>>"; + fi; + end); + if lres.type = "GAP_Attribute" then + if (FLAG1_FILTER(f)) <> 0 and (FLAG1_FILTER(f) <> i) then + lres.testerfor := GVarNameForObject(FILTERS[FLAG1_FILTER(f)]); + fi; + lres.filters := ff; + elif lres.type = "GAP_Property" then + lres.filters := ff; + else + lres.implied := ff; + fi; + lres.name := name; + lres.name_func := NameFunction(FILTERS[i]); + Add(res, lres); + fi; +end; + +GAPTypesInfoByGlobalVariables := function() + local name, names, n, obj, res, lres, f; + + res := [ rec( name := "IsObject", type := "GAP_Category", implied := [] ) ]; + + names := NamesGVars(); + for name in names do + if IsBoundGlobal(name) then + obj := ValueGlobal(name); + + if IsFilter(obj) then + GAPFilterInfo(res, name, obj); + else + fi; + fi; + od; +end; + # Make GAP Type graph as a record GAPTypesInfo := function() - local res, lres, i, j, f, ff, a, meths, mpos; + local res, lres, i, j, f, ff, a, meths, mpos, objs, m, mres, n, t, notcovered, v; + objs := NewDictionary(IsObject, true); res := [ rec( name := "IsObject", type := "GAP_Category", implied := [] ) ]; + Print("exporting filters...\n"); for i in [1..Length(FILTERS)] do if IsBound(FILTERS[i]) then lres := rec(); f := FILTERS[i]; lres.type := GAPFilterToFilterType(i); - # if the filter is an attribute and FLAG1_FILTER of the filter - # is not equal to it, then this is a tester. - ff := TRUES_FLAGS(WITH_IMPS_FLAGS(FLAGS_FILTER(FILTERS[i]))); - ff := List(ff, function(f) - if IsBound(FILTERS[f]) then - return NAME_FUNC(FILTERS[f]); - else - return "<<unknown>>"; - fi; - end); - if lres.type = "GAP_Attribute" then - if (FLAG1_FILTER(f)) <> 0 and (FLAG1_FILTER(f) <> i) then - lres.testerfor := NAME_FUNC(FILTERS[FLAG1_FILTER(f)]); + # Attributes and Properties are exported below + if lres.type in [ "GAP_Attribute", "GAP_Property" ] then + # if the filter is an attribute and FLAG1_FILTER of the filter + # is not equal to it, then this is a tester. + if lres.type = "GAP_Attribute" then + if (FLAG1_FILTER(f)) <> 0 and (FLAG1_FILTER(f) <> i) then + lres.testerfor := NameFunction(FILTERS[FLAG1_FILTER(f)]); + fi; + elif lres.type = "GAP_Property" then + lres.filters := ff; + else fi; - lres.filters := ff; - elif lres.type = "GAP_Property" then - lres.filters := ff; else + AddDictionary(objs, f, lres); + ff := TRUES_FLAGS(WITH_IMPS_FLAGS(FLAGS_FILTER(FILTERS[i]))); + ff := List(ff, function(f) + if IsBound(FILTERS[f]) then + return NameFunction(FILTERS[f]); + else + return "<<unknown>>"; + fi; + end); lres.implied := ff; + if IsBound(FILTERS_LOCATIONS[i]) then + lres.location := FILTERS_LOCATIONS[i]; + fi; + lres.name := (NameFunction(FILTERS[i])); + Add(res, lres); fi; - lres.name := (NAME_FUNC(FILTERS[i])); - Add(res, lres); fi; od; + Print(" done\n"); + Print("exporting attributes...\n"); for i in [1..Length(ATTRIBUTES)] do lres := rec(); - lres.type := "GAP_Attribute"; + + if LookupDictionary(objs, ATTRIBUTES[i][3]) <> fail then + Print("obj: ", ATTRIBUTES[i][1], " ", ATTRIBUTES[i][3]," already there \n"); + else + AddDictionary(objs, ATTRIBUTES[i][3], lres); + fi; + + if FLAG1_FILTER(ATTRIBUTES[i][3]) = 0 then + lres.type := "GAP_Attribute"; + else + lres.type := "GAP_Property"; + fi; + lres.filters := GAPAndFilterUnpack(ATTRIBUTES[i][2]); - lres.name := ATTRIBUTES[i][1]; + lres.name := NameFunction(ATTRIBUTES[i][3]); + lres.location := ATTRIBUTES[i][7]; Add(res, lres); od; + Print(" done\n"); + Print("exporting operations...\n"); for i in [1..Length(OPERATIONS)/2] do lres := rec(); + AddDictionary(objs, OPERATIONS[2*i - 1], lres); lres.type := "GAP_Operation"; - lres.name := NAME_FUNC(OPERATIONS[2*i - 1]); + lres.name := NameFunction(OPERATIONS[2*i - 1]); lres.locations := OPERATIONS_LOCATIONS[2*i]; lres.filters := FiltersForOperation(OPERATIONS[2*i - 1]); - lres.filters := List(lres.filters, x->List(x,y -> List(y,NAME_FUNC))); + lres.filters := List(lres.filters, x->List(x,y -> List(y,NameFunction))); lres.methods := rec( 0args := [], 1args := [], 2args := [], 3args := [], 4args := [], 5args := [], @@ -136,39 +260,98 @@ GAPTypesInfo := function() for a in [1..6] do meths := METHODS_OPERATION(OPERATIONS[2*i - 1], a); - + for j in [1..Int(Length(meths)/(a + 4))] do mpos := (j - 1) * (a + 4) + 1; - Add(lres.methods.(Concatenation(String(a),"args")), - rec( - filters := List([1..a], - argnum -> - List(TRUES_FLAGS(meths[mpos + argnum]), x -> NAME_FUNC(FILTERS[x])) - ), - rank := meths[mpos + a + 2], - comment := meths[mpos + a + 3] - ) - ); + mres := rec( filters := List([1..a], + argnum -> + List(TRUES_FLAGS(meths[mpos + argnum]), x -> NameFunction(FILTERS[x])) + ), + rank := meths[mpos + a + 2], + comment := meths[mpos + a + 3] + ); + + # Methods are not bound to global variables directly (usually...) + # but some methods might be global functions + AddDictionary(objs, meths[mpos + a + 1], mres); + + Add(lres.methods.(Concatenation(String(a),"args")), mres); od; od; Add(res, lres); od; - return res; + Print(" done\n"); + Print("exporting global functions...\n"); + for f in [1..Length(GLOBAL_FUNCTION_NAMES)] do + lres := rec(); + lres.type := "GAP_Function"; + lres.name := GLOBAL_FUNCTION_NAMES[f]; + lres.location := rec(); + AddDictionary(objs, ValueGlobal(GLOBAL_FUNCTION_NAMES[f]), lres); + Add(res, lres); + od; + Print(" done\n"); + Print("collecting global variable references...\n"); + notcovered := []; + for n in NamesGVars() do + if IsBoundGlobal(n) then + v := ValueGlobal(n); + t := LookupDictionary(objs, v); + if t <> fail then + if IsBound(t.aka) then + Add(t.aka, n); + else + t.aka := [n]; + fi; + else + v := ValueGlobal(n); + if IsFilter(v) then + lres := rec(); + lres.type := "GAP_AndFilter"; + ff := FLAGS_FILTER(v); + if ff <> false then + ff := TRUES_FLAGS(FLAGS_FILTER(v)); + ff := List(ff, function(f) + if IsBound(FILTERS[f]) then + return NameFunction(FILTERS[f]); + else + return "<<unknown>>"; + fi; + end); + lres.conjunction_of := ff; + lres.name := (NameFunction(v)); + lres.aka := [n]; + AddDictionary(objs, v, lres); + Add(res, lres); + else + # Print("strange: ", n, " ", v); + fi; + else + Add(notcovered, n); + fi; + fi; + fi; + od; + Print(" done\n"); + return [res, notcovered]; end; # Write the graph of type info to JSon file GAPTypesToJson := function(file) - local fd, n; + local fd, n, typeinfo; fd := IO_File(file, "w"); if fd = fail then Error("Opening file ", file, "failed."); fi; - n := IO_Write(fd, GapToJsonString(GAPTypesInfo())); + typeinfo := GAPTypesInfo(); + n := IO_Write(fd, GapToJsonString(typeinfo[1])); IO_Close(fd); return n; end; +GAPTypesToJson("gaptypes.json"); +QUIT_GAP(0);