File: code.m2

package info (click to toggle)
macaulay2 1.21%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 133,096 kB
  • sloc: cpp: 110,377; ansic: 16,306; javascript: 4,193; makefile: 3,821; sh: 3,580; lisp: 764; yacc: 590; xml: 177; python: 140; perl: 114; lex: 65; awk: 3
file content (264 lines) | stat: -rw-r--r-- 11,889 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
--		Copyright 1993-1999, 2008 by Daniel R. Grayson

-- TODO: needs "document.m2" for formatDocumentTag, but this casues a loop
needs "gateway.m2"
needs "lists.m2"
needs "methods.m2"
needs "nets.m2"

-----------------------------------------------------------------------------
-- code
-----------------------------------------------------------------------------

getSourceLines = method(Dispatch => Thing) 
getSourceLines Nothing := null -> null
getSourceLines Sequence := x -> (
     (filename,start,startcol,stop,stopcol,pos,poscol) -> if filename =!= "stdio" then (
	  wp := set characters " \t\r);";
	  file := (
	       if match("startup.m2.in$", filename) then startupString
	       else if filename === "currentString" then currentString
	       else (
		    if not fileExists filename then error ("couldn't find file ", filename);
		    get filename
		    )
	       );
	  file = lines file;
	  while (
	       file#?stop 
	       and (				  -- can improve this
		    l := set characters file#stop;
		    l #? ")" and isSubset(l, wp)
		    )
	       ) do stop = stop + 1;
	  if #file < stop then error("line number ",toString stop, " not found in file ", filename);
	  while stop >= start and file#(stop-1) === "" do stop = stop-1;
	  stack prepend(
	       concatenate(filename, ":", 
		    toString start, ":", toString (startcol+1),
		    "-",
		    toString stop, ":", toString (stopcol+1),
		    ": --source code:"),
	       apply(start-1 .. stop-1, i -> file#i)
	       )
	  )) x

limit := 4
indent := n -> "| "^(height n, depth n) | n

codeFunction := (f,depth) -> (
     if depth <= limit then (
	  if locate f === null then concatenate("function ", toString f, ": source code not available")
	  else stack(
	       syms := flatten \\ sortByHash \ values \ drop(localDictionaries f,-1);
	       getSourceLines locate f,
	       if #syms > 0 then indent listSymbols syms,
	       if codeHelper#?(functionBody f) 
	       then toSequence apply(
		    codeHelper#(functionBody f) f, 
		    (comment,val) -> indent stack (
			      comment, 
			      if instance(val, Function) then codeFunction(val,depth+1) else net val
			      )))))

-- stores previously listed methods, hooks, or tests to be used by (code, ZZ)
previousMethodsFound = null

code = method(Dispatch => Thing)
code Nothing    := identity
code Symbol     :=
code Pseudocode := s -> getSourceLines locate s
code Sequence   := s -> (
    key := select(s, x -> not instance(x, Option));
    -- handle strategies
    func := if not #key === #s then (
	opts := new OptionTable from toList select(s, x -> instance(x, Option));
	if opts.?Strategy then (
	    strategy := opts.Strategy;
	    store := getHookStore(key, false);
	    if store =!= null and store#?key
	    and store#key.HookAlgorithms#?strategy
	    then store#key.HookAlgorithms#strategy));
    if func =!= null or (func = lookup key) =!= null
    then "-- code for method: "          | formatDocumentTag key || code func
    else "-- no method function found: " | formatDocumentTag key)
code Function   := f -> codeFunction(f, 0)
code Command    := C -> code C#0
code List       := L -> stack between_"---------------------------------" apply(L, code)
code ZZ         := i -> code previousMethodsFound#i

-----------------------------------------------------------------------------
-- edit
-----------------------------------------------------------------------------
-- TODO: update this

editMethod = method(Dispatch => Thing)
editMethod String := filename -> (
     editor := getViewer("EDITOR", "emacs");
     chkrun concatenate(
	  if getenv "DISPLAY" != "" and editor != "emacs" then "xterm -e ",
	  editor, " ", filename))
EDIT = method(Dispatch => Thing)
EDIT Nothing := arg -> (stderr << "--warning: source code not available" << endl;)
EDIT Sequence := x -> ((filename,start,startcol,stop,stopcol,pos,poscol) -> (
     editor := getViewer("EDITOR", "emacs");
     if 0 != chkrun concatenate(
	  if getenv "DISPLAY" != "" and editor != "emacs" then "xterm -e ",
	  editor,
	  " +",toString start,
	  " ",
	  filename
	  ) then error "command returned error code")) x
editMethod Command := c -> editMethod c#0
editMethod Function := args -> EDIT locate args
editMethod Sequence := args -> (
     editor := getViewer("EDITOR", "emacs");
     if args === () 
     then chkrun concatenate(
	  if getenv "DISPLAY" != "" and editor != "emacs" then "xterm -e ",
	  editor)
     else EDIT locate args
     )
editMethod ZZ := i -> editMethod previousMethodsFound#i
edit = Command editMethod

-----------------------------------------------------------------------------
-- methods
-----------------------------------------------------------------------------
-- TODO: https://github.com/Macaulay2/M2/issues/1331

searchAllDictionaries := (T, f) -> (
    seen := new MutableHashTable;
    scan(flatten \\ pairs \ dictionaryPath, (name, sym) -> (
	    if instance(v := value sym, T) and not seen#?v then ( seen#v = true; f(v)))))

isUnaryAssignmentOperator  = key -> (instance(key, Sequence) and #key === 2
    and(false and isUnaryAssignmentOperator key#0 and instance(key#1, Type) or key#1 === symbol=))
isBinaryAssignmentOperator = key -> (instance(key, Sequence) and #key === 3
    and isUnaryAssignmentOperator key#0 and instance(key#1, Type) and instance(key#2, Type))

thingMethods := (T, F) -> nonnull apply(pairs T, (key, func) -> if instance(func, Function) then
    -- TODO: unary methods are installed as T#f, change it to T#(f, T), then simplify this
    if key === F                                               then (key, T) else -- unary method, e.g quotient
    -- TODO: unary assignments operators are installed as T#(s, symbol=), change it to T#((s, symbol=), T), then simplify this
    if isUnaryAssignmentOperator key and member(F,        key) then (key, T) else -- unary assignment method, e.g symbol=
    if instance(key, Sequence)       and member(F, splice key) then  key)

sequenceMethods := (T, F, tallyF) -> nonnull apply(pairs T, (key, func) -> if instance(func, Function) then
    if isBinaryAssignmentOperator key and tallyF <= tally splice  key     then  key     else -- e.g T#((symbol SPACE, symbol=), T, T)
    if  isUnaryAssignmentOperator key and tallyF <= tally splice (key, T) then (key, T) else -- e.g T#(symbol+, symbol=)
    if instance(key, Keyword)         and tallyF <= tally splice (key, T) then (key, T) else -- e.g T#(symbol #)
    if instance(key, Function)        and tallyF <= tally splice (key, T) then (key, T) else -- e.g T#resolution
    if instance(key, Sequence)        and tallyF <= tally         key     then  key)

methods = method(Dispatch => Thing, TypicalValue => NumberedVerticalList)
methods Manipulator := M -> methods class M
methods Command  := c -> methods c#0
methods Type     := F -> methods sequence F
methods Sequence := F -> (
    found := new MutableHashTable;
    tallyF := tally splice F;
    searchAllDictionaries(Type, T -> scan(sequenceMethods(T, F, tallyF), key -> found#key = true));
    scan(select(F, e -> instance(e, Type)), T -> scan(sequenceMethods(T, F, tallyF), key -> found#key = true));
    previousMethodsFound = new NumberedVerticalList from sortByName keys found)

methods ScriptedFunctor := -- TODO: OO and other scripted functors aren't supported
methods Symbol :=
methods Thing  := F -> (
    if F === HH then return join(methods homology, methods cohomology);
    found := new MutableHashTable;
    -- TODO: either finish or remove nullaryMethods
    if nullaryMethods#?(1:F) then found#(1:F) = true;
    searchAllDictionaries(Type, T -> scan(thingMethods(T, F), key -> found#key = true));
    previousMethodsFound = new NumberedVerticalList from sortByName keys found)

-- this one is here because it needs previousMethodsFound
options ZZ := i -> options previousMethodsFound#i
locate  ZZ := i -> locate  previousMethodsFound#i

-----------------------------------------------------------------------------
-- hooks
-----------------------------------------------------------------------------

listHooks := (key, opts) -> (
    -- list global hooks
    if key === () then return hooks(GlobalHookStore, opts);
    if instance(key#0, MutableHashTable)
    -- get the store from the first argument
    then (store := key#0; key = if key#?1 then key#1 else null)
    -- get the store from the key
    else  store  = getHookStore(key, false);
    new NumberedVerticalList from (
	alg := if opts.?Strategy then opts.Strategy;
	type := class alg;
	store = if store#?key then store#key;
	-- if no hooks have been installed, return empty list
	if store === null then {} else
	-- if Strategy is not given, list all available hooks
	if alg === null then apply(store.HookPriority, alg -> splice(key, Strategy => alg)) else
	-- if Strategy is given, and it is among the known strategies, list only that hook
	if store.HookAlgorithms#?alg  then { splice(key, Strategy => alg)  } else
	-- otherwise, if the class of alg is a known strategy, list only that hook
	if store.HookAlgorithms#?type then { splice(key, Strategy => type) } else {}))

hooks = method(Dispatch => Thing, Options => {Strategy => null})
hooks ZZ        := opts -> i   -> hooks previousMethodsFound#i
hooks List      := opts -> L   -> previousMethodsFound = join apply(toSequence L, key -> listHooks(key, opts))
hooks Thing     := opts -> key -> previousMethodsFound = hooks(methods key, opts)
hooks Symbol    := opts -> sym -> previousMethodsFound = hooks(1:sym, opts)
hooks Sequence  := opts -> key -> previousMethodsFound = listHooks(key, opts)
hooks HashTable := opts -> store -> previousMethodsFound = join(
    if store.?cache then store = store.cache;
    if store.?Hooks then store = store.Hooks;
    apply(toSequence keys store, key -> listHooks((store, key), opts)))

-----------------------------------------------------------------------------
-- debugger
-----------------------------------------------------------------------------
-- TODO: move to debugging?

debuggerUsageMessage = ///--debugger activation depth control:
    errorDepth=3   	-- activate at positions in user code (default)
    errorDepth=2   	-- activate also at positions in packages
    errorDepth=1   	-- activate also at positions in Core
    errorDepth=0   	-- activate also at positions in the loader
--debugging control:
    return              -- bypass current expression, return null, stop
    return x            -- bypass current expression, return x, stop
    step                -- step 1 line
    step n              -- step n lines
    step (-n)           -- trace n microsteps
    end (or eof char)   -- enter debugger one level up
    continue            -- leave the debugger, continuing execution
                        -- with current expression
    break               -- leave the debugger, returning to top level
--debugging information:
    listLocalSymbols    -- display local symbols and their values
    listUserSymbols     -- display user symbols and their values
    current             -- the current expression; initially, the one
    	      	   	-- that produced an error
    code current        -- source code of current expression
    value current       -- execute current expression, obtain value
    disassemble current -- display microcode of current expression
    currentString       -- the string being evaluated by 'value', if
                        -- an error occurred within it
-- emacs commands in *M2* buffer:
    RET                 -- on an file/position line, go to source///

inDebugger = false
addStartFunction(() -> inDebugger = false)
-- This is called from interp.dd
debuggerHook = entering -> (
     if entering then (
	  pushvar(symbol inDebugger, true);
	  c := code current;
	  if c =!= null then << c << endl;
	  )
     else (
	  popvar symbol inDebugger;
	  )
     )

-- Local Variables:
-- compile-command: "make -C $M2BUILDDIR/Macaulay2/m2 "
-- End: