root/trunk/blade/BladeVisitor.d

Revision 176, 5.8 kB (checked in by Don Clugston, 9 months ago)

SyntaxTree? now creates a tuple of the types. This opens the way to significant simplification of some of the code (eg, I should be able to remove the rank stuff from SyntaxTree?).

  • Property svn:mime-type set to text/x-dsrc
  • Property svn:eol-style set to native
Line 
1 //  Written in the D programming language 1.0
2 /**
3 * Traverse a syntax tree in text form.
4 * Part of BLADE : Basic Linear Algebra D Expressions
5 *
6 * Author:
7 *   Don Clugston.
8 * License:
9 *   Public domain.
10 */
11
12 module blade.BladeVisitor;
13
14 public:
15 //--------------------------------------------------------
16 //      BLADE Visitor -- walk the syntax tree
17 //--------------------------------------------------------
18
19 // The lowest level doesn't need to have parens around it.
20 V.ReturnType beginVisit(V)(V visitor, char [] expr)
21 {
22     if (isSimpleExpr(expr)) {
23         return doVisit(visitor, expr);
24     } else return doVisit(visitor, "(" ~ expr ~ ")");
25 }
26
27 // Walk the tree, invoking 'visitor' at each node
28 V.ReturnType doVisit(V)(V visitor, char [] expr)
29 {
30     // BUG: also need to deal with comma, ?:, &&, ||, is, !is, in,
31     // unary &, unary !
32
33     if (expr.length>1 && expr[0]=='(') expr = expr[1..$-1];
34     else if (expr.length==1 && ((expr[0]>='A' && expr[0]<='Z') || expr[0]=='$')){
35         return visitor.onVisitSymbol(visitor, expr);
36     }
37     if (expr[0]>='a' && expr[0]<='z' && exprLength(expr)==expr.length) { // function
38         char [][] args;
39         int z=1;
40         while(z<expr.length && expr[z]!='(') ++z;
41         int x = z+1;
42         while (x<expr.length) {
43             int y = exprLength(expr[x..$-1]);
44             args ~= expr[x..x+y];
45             x = x+y+1; // skip the comma
46         }
47         return visitor.onVisitFunction(visitor, expr[0..z], args);
48     }
49     if (expr.length>2 && (expr[0..2]=="++" || expr[0..2]=="--")) {
50         return visitor.onVisitPrefix(visitor, expr[0..2], expr[2..$]);
51     }
52     if (expr.length>1 && (expr[0]=='+' || expr[0]=='-')) {
53         return visitor.onVisitPrefix(visitor, expr[0..1], expr[1..$]);
54     }
55     if (expr.length>2 && (expr[$-2..$]=="++" || expr[$-2..$]=="--")) {
56         return visitor.onVisitPostfix(visitor, expr[$-2..$], expr[0..$-2]);
57     }
58     int x = exprLength(expr);
59     int y = x;
60     assert(y < expr.length, "BLADE ICE:" ~ expr);
61     // Deal with shifts, op=, and NCEG operators
62     while (expr[y+1]=='<' || expr[y+1]=='>' || expr[y+1]=='=') ++y;
63     char [] op = expr[x..y+1];   
64     char [] left = expr[0..x];
65     char [] right = expr[y+1..$];
66     if (op=="[") {
67         right = right[0..$-1];
68         char [][2][] allslices=[];       
69         int z = 0;
70         while (z<right.length) {
71             if (right[z]==',') { // null dimension
72                 allslices ~= ["",""];
73                 ++z;
74             } else {
75                     int w = exprLength(right[z..$]);
76                     if (z+w+2 < right.length && right[z+w..z+w+2]=="..") {
77                         int q = z+w+2;
78                         int t = exprLength(right[q..$]);
79                         allslices ~= [ right[z..z+w], right[q..q+t]];
80                         z = q+t+1; // no comma to skip
81                     } else {
82  
83                      if (right.length>z+1 && right[z+1]=='[') { // fake slice -- support this for now
84                             int w2 = exprLength(right[z+2..$-2]);
85                             int q = z+w2+1; // skip the ,
86                             int t = exprLength(right[q+2..$]);
87                             allslices ~= [ right[z+2..q+1], right[q+2..q+2+t]];
88                             z = z+w+2;
89                     } else {
90                         allslices ~= [ right[z..z+w], ""];
91                         z = z+w+1; // skip the comma, if any
92                     }
93                 }
94              }
95         }
96        return visitor.onVisitIndex(visitor, left, allslices);
97     }
98     return visitor.onVisitBinaryOp(visitor, op, left, right);
99 }
100
101 /** Return the length of a sub-expression
102  * The sub-expression must be one of:
103  *  - a single character (eg "X"), OR
104  *  - a lower-case intrinsic function (eg "abc(B,(C*D))"), OR
105  *  - an expression in parenthesis, OR
106  *  - an array literal
107  */
108 int exprLength(char [] s)
109 {
110     if ((s[0]>='A' && s[0]<='Z') || s[0]=='$') return 1;
111     int i = 0;   
112     while (s[i]>='a' && s[i]<='z'){ // intrinsic function call
113         ++i; // next char will be '(' so code below works
114     }
115     int numParens = 0;
116     int numBrack = 0;
117     for (; i<s.length; ++i) {
118         if (s[i]=='(')  ++numParens;
119         if (s[i]==')') numParens--;       
120         if (s[i]=='[') ++numBrack;
121         if (s[i]==']') --numBrack;
122         if (numParens == 0 && numBrack == 0) {
123             return i+1;
124         }
125     }
126     assert(0, "BLADE ICE: " ~ s);   
127 }
128
129 // Return true if the function is a single variable, or an intrinsic.
130 bool isSimpleExpr(char [] s)
131 {
132     if (s.length==1) return true;
133     if (s[0]<'a' || s[0]>'z') return false;
134     return exprLength(s)==s.length;
135 }
136
137 unittest {
138     assert(exprLength("A*B")==1);
139     assert(exprLength("dot(A,B)*C")==8);
140 }
141
142 /* Wrap parentheses around the expression, if required
143 */
144 char [] wrapInParens(char [] a)
145 {
146     return (a.length==1 || (a[0]>='a' && a[0]<='z' && exprLength(a)==a.length))? a : "(" ~ a ~ ")";
147 }
148
149 // Return true if this expression contains an assignment.
150 bool expressionContainsAssignment(char [] expr)
151 {
152     if (isSimpleExpr(expr)) return false;
153     // BUG: also need to deal with comma, ?:, &&, ||, is, !is, in,
154     // unary &, unary !
155     if (expr.length>1 && expr[0]=='(') expr = expr[1..$-1];
156     if (expr.length>2 && (expr[0..2]=="++" || expr[0..2]=="--")) {
157         return false;
158     }
159     if (expr.length>1 && (expr[0]=='+' || expr[0]=='-')) {
160         return false;
161     }
162     if (expr.length>2 && (expr[$-2..$]=="++" || expr[$-2..$]=="--")) {
163         return false; // BUG: actually this _is_ an assignment
164     }
165     int y = exprLength(expr);
166     assert(y < expr.length, "BLADE ICE:" ~ expr);
167     // Deal with shifts, op=, and NCEG operators
168     if (expr[y+1]=='<' || expr[y+1]=='>') return false;
169     if (expr[y]=='=' && expr[y+1]=='=') return false;
170     if (expr[y]=='=') return true;
171     if (expr[y+1]!='=') return false;
172     if (expr[y]=='<' || expr[y]=='<' || expr[y]=='!') return false;
173     return true;
174 }
Note: See TracBrowser for help on using the browser.