Skip to main content

syntax - Extract what symbol is set by SetDelayed, Set, TagSet, UpSet, SetAttributes, etc


One of the recent features of the Mathematica Plugin for IntelliJ IDEA (www.mathematicaplugin.halirutan.de) is a Structure View which let's you see information about several definitions that are done in a source file. It currently looks like the left side of the image below:


enter image description here


To provide such a feature, I need to extract which symbol is set when the user uses things like




  • lhs = rhs or lhs := rhs

  • s /: patt = rhs or s /: patt := rhs

  • lhs ^= rhs or lhs ^:= rhs

  • Options[sym] = rhs, Attributes[sym] = rhs, SyntaxInformation[sym] = lhs, Format[sym] ] = rhs, N[sym] = rhs, Default[sym] = rhs

  • sym::tag = rhs


Since in IDEA I cannot evaluate code like one can in Mathematica, I have to extract all those information from inspecting the abstract syntax tree (TreeForm in Mathematica). For this, I have a so-called visitor which walks through the tree and collects information. One can easily write such a visitor (or expression parser) in Mathematica itself. I have written a very basic version of such a visitor, which takes a expression like f[x_]:=x^2 and extracts the symbols which is set and the type of the assignment. Partly, I have simply copied code from Leonids answer here. Before giving the code here are my


Questions: Can the visitor below be improved? Are there missing cases, things I haven't thought of, things that don't work correctly? Especially UpSet is interesting because there, more than one symbol can be set at the same time.




Here is a very basic visitor which uses simple pattern matching to check the structure of an expression:



ClearAll[visit];
SetAttributes[visit, {HoldAllComplete}];
visit[s_Symbol] := MakeBoxes[s];
visit[(h : (SetDelayed | Set))[lhs_, _]] := {MakeBoxes[h], visit[lhs]};
visit[(h : (TagSetDelayed | TagSet))[a_, _, _]] := {MakeBoxes[h], visit[a]};
visit[(h : (UpSetDelayed | UpSet))[_[args__], _]] := {MakeBoxes[h], visit[args]};
visit[HoldPattern[Options[sym_] = _]] := {MakeBoxes[Options], visit[sym]};
visit[HoldPattern[Attributes[sym_] = _]] := {MakeBoxes[Attributes], visit[sym]};
visit[HoldPattern[SetAttributes[sym_, _]]] := {MakeBoxes[Attributes], visit[sym]};
visit[HoldPattern[SyntaxInformation[sym_] = _]] := {MakeBoxes[SyntaxInformation], visit[sym]};

visit[HoldPattern[Default[sym_] = _]] := {MakeBoxes[DefaultValues], visit[sym]};
visit[HoldPattern[MessageName[sym_, tag_] = _]] := {MakeBoxes[Messages], visit[sym], MakeBoxes[tag]};
visit[Verbatim[Format][sym_] := _] := {MakeBoxes[FormatValues], visit[sym]};
visit[HoldPattern[(Set | SetDelayed)[N[sym_], _]]] := {MakeBoxes[NValues], visit[sym]};

visit[(Condition | PatternTest | Optional)[arg_, _]] := visit[arg];
visit[(HoldPattern | Optional)[arg_]] := $Failed;
visit[Verbatim[Pattern][sym_, _]] := $Failed
visit[Verbatim[Repeated][p_, ___]] := $Failed;
visit[(Blank | BlankSequence | BlankNullSequence)[___]] := $Failed;

visit[(Longest | Shortest)[arg_, ___]] := $Failed;
visit[Verbatim[PatternSequence][args___]] := $Failed;
visit[a_ /; AtomQ[Unevaluated[a]]] := $Failed;
visit[args___] := List @@ Map[visit, Hold[args]];
visit[f_[args___]] := visit[f];

SetAttributes[StructureView, {HoldAll}];
StructureView[sets_Hold] := Column[List @@ Map[visit, sets]]

And here are some positive test-cases that work



StructureView[Hold[
f[x_] := x^2,
SetAttributes[sym, {HoldAll}],
Options[Plot] = {PlotRange -> Automatic},
square /: area[square] = a^2,
area[rectangle] ^= a*b,
int /: rand[int] = Random[Integer],
h /: f[h[x_]] = x^2,
SyntaxInformation[
f] = {"ArgumentsPattern" -> {_, _, OptionsPattern[]}},

N[f[x_]] := Sum[x^-i/i^2, {i, 20}],
f::usage = "f[x] gives (x - 1)(x + 1)",
area[square1, square2] ^= s^2,
Format[bin[x_, y_]] := MatrixForm[{{x}, {y}}]]]

And here are some test-cases that (correctly) fail because they are semantically not valid


StructureView[Hold[
h_ /: f[h[x_]] = x^2,
f_[x] := x^2,
f_[x_] := x^2,

"f"[x_] := x
]]

Final notes



  • I haven't included vector-set like {a,b}={1,2} and the special notation a[[1]]=4 on purpose.

  • I someone doesn't want to post a complete answer, but wants to discuss something, then ping me in the plugin chatroom




Comments

Popular posts from this blog

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...