@@ -10,6 +10,7 @@ import qualified Data.Graph as Graph
1010import qualified Data.Map.Strict as Map
1111import qualified Data.Set as Set
1212
13+import qualified AST.Binop as Binop
1314import qualified AST.Expression.Canonical as Can
1415import qualified AST.Expression.Valid as Valid
1516import qualified Canonicalize.Environment as Env
@@ -53,15 +54,15 @@ canonicalize env (A.A region expression) =
5354 Valid.List exprs ->
5455 Can.List <$> traverse (canonicalize env) exprs
5556
56− Valid.Op name ->
57− do (Env.Binop home func _ _) <- Env.findBinop region env name
58− return (Can.VarOperator name home func)
57+ Valid.Op op ->
58+ do (Env.Binop _ home name _ _) <- Env.findBinop region env op
59+ return (Can.VarOperator op home name)
5960
6061 Valid.Negate expr ->
6162 Can.Negate <$> canonicalize env expr
6263
6364 Valid.Binops ops final ->
64− error "TODO"
65+ A.drop <$> canonicalizeBinops region env ops final
6566
6667 Valid.Lambda args body ->
6768 addLocals $
@@ -145,6 +146,89 @@ canonicalizeBranch env (condition, branch) =
145146
146147
147148
149+-- CANONICALIZE BINOPS
150+
151+
152+canonicalizeBinops :: R.Region -> Env.Env -> [(Valid.Expr, A.Located N.Name)] -> Valid.Expr -> Result FreeLocals Can.Expr
153+canonicalizeBinops overallRegion env ops final =
154+ let
155+ canonicalizeHelp (expr, A.A region op) =
156+ (,)
157+ <$> canonicalize env expr
158+ <*> Env.findBinop region env op
159+ in
160+ runBinopStepper overallRegion =<< (
161+ More
162+ <$> traverse canonicalizeHelp ops
163+ <*> canonicalize env final
164+ )
165+
166+
167+data Step
168+ = Done Can.Expr
169+ | More [(Can.Expr, Env.Binop)] Can.Expr
170+ | Error Env.Binop Env.Binop
171+
172+
173+runBinopStepper :: R.Region -> Step -> Result FreeLocals Can.Expr
174+runBinopStepper overallRegion step =
175+ case step of
176+ Done expr ->
177+ Result.ok expr
178+
179+ More [] expr ->
180+ Result.ok expr
181+
182+ More ( (expr, op) : rest ) final ->
183+ runBinopStepper overallRegion $
184+ toBinopStep (toBinop op expr) op rest final
185+
186+ Error (Env.Binop op1 _ _ _ _) (Env.Binop op2 _ _ _ _) ->
187+ Result.throw overallRegion (Error.Binop op1 op2)
188+
189+
190+toBinopStep :: (Can.Expr -> Can.Expr) -> Env.Binop -> [(Can.Expr, Env.Binop)] -> Can.Expr -> Step
191+toBinopStep makeBinop rootOp@(Env.Binop _ _ _ rootAssociativity rootPrecedence) middle final =
192+ case middle of
193+ [] ->
194+ Done (makeBinop final)
195+
196+ ( expr, op@(Env.Binop _ _ _ associativity precedence) ) : rest ->
197+ if precedence < rootPrecedence then
198+
199+ More ((makeBinop expr, op) : rest) final
200+
201+ else if precedence > rootPrecedence then
202+
203+ case toBinopStep (toBinop op expr) op rest final of
204+ Done newLast ->
205+ Done (makeBinop newLast)
206+
207+ More newMiddle newLast ->
208+ toBinopStep makeBinop rootOp newMiddle newLast
209+
210+ Error a b ->
211+ Error a b
212+
213+ else
214+
215+ case (rootAssociativity, associativity) of
216+ (Binop.Left, Binop.Left) ->
217+ toBinopStep (\right -> toBinop op (makeBinop expr) right) op rest final
218+
219+ (Binop.Right, Binop.Right) ->
220+ toBinopStep (\right -> makeBinop (toBinop op expr right)) op rest final
221+
222+ (_, _) ->
223+ Error rootOp op
224+
225+
226+toBinop :: Env.Binop -> Can.Expr -> Can.Expr -> Can.Expr
227+toBinop (Env.Binop op home name _ _) left right =
228+ A.merge left right (Can.Binop op home name left right)
229+
230+
231+
148232-- CANONICALIZE LET
149233
150234