]> gerrit.simantics Code Review - simantics/platform.git/blob
465c5c8ffac7f1981ccc50a42c7a09bfb94cf749
[simantics/platform.git] /
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import java.util.ArrayList;
4
5 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
6 import org.simantics.scl.compiler.common.names.Names;
7 import org.simantics.scl.compiler.common.precedence.Associativity;
8 import org.simantics.scl.compiler.common.precedence.Precedence;
9 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
10 import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
11 import org.simantics.scl.compiler.elaboration.expressions.lhstype.FunctionDefinitionLhs;
12 import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType;
13 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
14 import org.simantics.scl.compiler.errors.Locations;
15
16
17
18 public class EBinary extends ASTExpression {
19     public static final int NEGATION_LEVEL = 6;
20     
21     public Expression left;
22     public ArrayList<EBinaryRightSide> rights = new ArrayList<EBinaryRightSide>();
23     public EVar negation;
24
25     public EBinary(Expression left, EVar negation) {
26         this.left = left;
27         this.negation = negation;
28     }
29
30     private EBinary(Expression left, EVar operator, Expression right) {
31         this.left = left;
32         rights.add(new EBinaryRightSide(operator, right));
33     }
34
35     public static EBinary create(Expression left, EVar operator, Expression right) {
36         if(left instanceof EBinary) {
37             EBinary left_ = (EBinary)left;
38             left_.rights.add(new EBinaryRightSide(operator, right));
39             return left_;
40         }
41         else
42             return new EBinary(left, operator, right);
43     }
44
45     @Override
46     public Expression resolve(TranslationContext context) {
47         return parseOperators(context).resolve(context);
48     }
49     
50     public Expression parseOperators(TranslationContext context) {
51         ArrayList<Expression> output = new ArrayList<Expression>();
52         ArrayList<Expression> ops = new ArrayList<Expression>();
53         ArrayList<EVar> opAsts = new ArrayList<EVar>();
54         
55         EVar negation = this.negation;
56         
57         output.add(left);
58         for(EBinaryRightSide right : rights) {
59             // Read op
60             Expression op = context.resolveExpression(right.operator.location, right.operator.name);
61             if(op == null)
62                 return new EError(location);
63             Precedence opPrec = op.getPrecedence();
64             while(!ops.isEmpty()) {
65                 Expression oldOp = ops.get(ops.size()-1);
66                 Precedence oldOpPrecedence = oldOp.getPrecedence();
67                 
68                 if(oldOpPrecedence.level < opPrec.level)
69                     break;
70                 if(oldOpPrecedence.level == opPrec.level) {
71                     if(opPrec.associativity == Associativity.RIGHT)
72                         break;
73                     if(opPrec.associativity == Associativity.NONASSOC) {
74                         context.getErrorLog().log(right.operator.location, 
75                                 "Operator " + right.operator.name + " is not associative.");
76                         return new EError(location);    
77                     }
78                 }
79                 
80                 // Pop op                
81                 ops.remove(ops.size()-1);
82                 Expression r = output.remove(output.size()-1);
83                 Expression l = output.remove(output.size()-1);
84                 output.add(binary(l, oldOp, opAsts.remove(opAsts.size()-1), r));
85             }
86             if(negation != null && ops.isEmpty()) {
87                 if(opPrec.level <= NEGATION_LEVEL) {      
88                     SCLValue neg = context.getEnvironment().getValue(Names.Prelude_neg);
89                     if(neg == null) {
90                         context.getErrorLog().log(location, 
91                                 "Couldn't resolve variable neg.");
92                         return new EError(location);
93                     }
94                     output.set(0, unary(neg, negation, output.get(0)));
95                     negation = null;
96                 }
97             }
98             ops.add(op);
99             opAsts.add(right.operator);
100             
101             // Read value
102             output.add(right.right);
103         }
104         
105         // Pop rest
106         while(!ops.isEmpty()) {            
107             Expression oldOp = ops.remove(ops.size()-1);
108             Expression r = output.remove(output.size()-1);
109             Expression l = output.remove(output.size()-1);
110             output.add(binary(l, oldOp, opAsts.remove(opAsts.size()-1), r));
111         }
112         if(negation != null) {
113             SCLValue neg = context.getEnvironment().getValue(Names.Prelude_neg);
114             if(neg == null) {
115                 context.getErrorLog().log(location, 
116                         "Couldn't resolve variable neg.");
117                 return new EError(location);
118             }
119             output.set(0, unary(neg, negation, output.get(0)));
120         }
121         
122         return output.get(0);
123         
124         //System.out.println("parseOperators: " + this);
125         //return parse(context, left, rights.listIterator(), new Precedence(-1, Associativity.NONASSOC));
126     }
127
128     /*
129     private Expression parse(TranslationContext context,
130             Expression lhs, ListIterator<EBinaryRightSide> it, Precedence minPrec) {
131         while(it.hasNext()) {
132             EBinaryRightSide right = it.next();
133             SCLValue op = context.resolveValue(right.operator.name);
134             if(op == null) {
135                 context.getErrorLog().log(right.operator, 
136                         "Couldn't resolve variable " + right.operator.name + ".");
137                 return lhs;
138             }
139             Precedence opPrec = op.getPrecedence();
140             if(minPrec.level > opPrec.level)
141                 break;
142             Expression rhs = right.right;
143             while(it.hasNext()) {
144                 EVar var = it.next().operator;
145                 SCLValue nextOp = context.resolveValue(var.name);
146                 if(nextOp == null) {
147                     context.getErrorLog().log(var, 
148                             "Couldn't resolve variable " + var.name + ".");
149                     return lhs;
150                 }
151                 it.previous();
152                 Precedence nextPrec = nextOp.getPrecedence();
153                 int precDiff = opPrec.level - nextPrec.level;
154                 if(precDiff == 0) {
155                     if(opPrec.associativity == Associativity.LEFT)
156                         break;
157                     else if(opPrec.associativity == Associativity.NONASSOC) {
158                         context.getErrorLog().log(it.next().operator, "Nonassociative operator.");
159                         return lhs;
160                     }
161                 }
162                 else if(precDiff > 0)
163                     break;
164                 rhs = parse(context, rhs, it, nextPrec);
165             }
166             lhs = binary(lhs, op, right.operator, rhs);
167         }   
168         return lhs;
169     }
170     */
171     private Expression binary(Expression lhs, Expression op, EVar opAst, Expression rhs) {
172         return new EApply(Locations.combine(lhs.location, rhs.location), op, lhs, rhs);        
173     }
174     
175     private Expression unary(SCLValue operator, EVar opAst, Expression expression) {
176         EConstant op = new EConstant(opAst.location, operator);
177         return new EApply(expression.location /*wrong*/, op, expression);
178     }
179     
180     @Override
181     public EVar getPatternHead() throws NotPatternException {
182         if(rights.size() == 1)
183             return rights.get(0).operator;
184         else
185             throw new NotPatternException(this);
186     }
187     
188     @Override
189     public LhsType getLhsType() throws NotPatternException {
190         if(rights.size() == 1)
191             return new FunctionDefinitionLhs(rights.get(0).operator.name);
192         else
193             throw new InternalCompilerError();
194     }
195         
196     @Override
197     public void getParameters(TranslationContext context,
198             ArrayList<Expression> parameters) {
199         parseOperators(context).getParameters(context, parameters);
200     }
201
202     public static Expression negate(EVar op, Expression expression) {
203         if(expression instanceof EBinary) {
204             ((EBinary)expression).negation = op;
205             return expression;
206         }
207         /*else if(expression instanceof EIntegerLiteral) {
208             EIntegerLiteral literal = (EIntegerLiteral)expression;
209             literal.value = -literal.value;
210             return expression;
211         }*/
212         else
213             return new EBinary(expression, op);
214     }
215     
216     @Override
217     public int getFunctionDefinitionPatternArity() throws NotPatternException {
218         return 2;
219     }
220     
221     @Override
222     public void setLocationDeep(long loc) {
223         if(location == Locations.NO_LOCATION) {
224             location = loc;
225             left.setLocationDeep(loc);
226             if(negation != null)
227                 negation.setLocationDeep(loc);
228             for(EBinaryRightSide right : rights)
229                 right.setLocationDeep(loc);
230         }
231     }
232     
233     @Override
234     public Expression accept(ExpressionTransformer transformer) {
235         return transformer.transform(this);
236     }
237     
238     @Override
239     public void accept(ExpressionVisitor visitor) {
240         visitor.visit(this);
241     }
242 }