on master help sign in
Add the ability to define custom infix operators.
commit1ad6801328edfe98f798439ec46f288a1cdf969e authorevancz <info@elm-lang.org> dateThu 22 Nov 2012, 19:48 (14 years ago) parent2c7fed1
13 files changed+274−187
elm/src/Ast.hs+8−6 elm/src/Gen/CompileToJS.hs+102−79 elm/src/Gen/ExtractNoscript.hs+32−13 elm/src/Gen/GenerateHtml.hs+3−2 elm/src/Initialize.hs+1−2 elm/src/Language/Elm.hs+1−1 elm/src/Optimize.hs+17−8 elm/src/Parse/ParseExpr.hs+18−10 elm/src/Parse/ParseLib.hs+8−4 elm/src/Parse/Patterns.hs+9−4 elm/src/Rename.hs+47−35 elm/src/Substitute.hs+2−1 elm/src/Types/Constrain.hs+26−22
elm/src/Ast.hs+8−6
@@ -34,17 +34,18 @@ data Expr = IntNum Int
3434 | Fold Expr Expr Expr
3535 | Async Expr
3636 | Input String
37− | Let [Definition] Expr
37+ | Let [Def] Expr
3838 | Var String
3939 | Case Expr [(Pattern,Expr)]
4040 | Data String [Expr]
4141 | Markdown Pandoc.Pandoc
4242 deriving (Eq)
4343
44−data Definition = Definition String [String] Expr
44+data Def = FnDef String [String] Expr
45+ | OpDef String String String Expr
4546 deriving (Eq)
4647
47−data Statement = Def String [String] Expr
48+data Statement = Definition Def
4849 | Datatype String [X] [(String,[Type])]
4950 | ImportEvent String Expr String Type
5051 | ExportEvent String String Type
@@ -105,9 +106,10 @@ instance Show Expr where
105106 show (Markdown _) = "[markdown| ... |]"
106107
107108
108−instance Show Definition where
109− show (Definition v [] e) = v ++ " = " ++ show e
110− show (Definition f args e) = f ++ " " ++ intercalate " " args ++ " = " ++ show e
109+instance Show Def where
110+ show (FnDef v [] e) = v ++ " = " ++ show e
111+ show (FnDef f args e) = f ++ " " ++ intercalate " " args ++ " = " ++ show e
112+ show (OpDef op a1 a2 e) = intercalate " " [a1,op,a2] ++ " = " ++ show e
111113
112114getLambdas (Lambda x e) = (x:xs,e')
113115 where (xs,e') = getLambdas e
elm/src/Gen/CompileToJS.hs+102−79
@@ -7,7 +7,7 @@ import Control.Monad (liftM,(<=<),join,ap)
77import Data.Char (isAlpha,isDigit)
88import Data.List (intercalate,sortBy,inits,foldl')
99import Data.Map (toList)
10−import Data.Maybe (mapMaybe)
10+import Data.Either (partitionEithers)
1111import qualified Text.Pandoc as Pan
1212
1313import Initialize
@@ -16,7 +16,7 @@ import Cases
1616import Guid
1717
1818showErr :: String -> String
19−showErr err = mainEquals $ "text(monospace(" ++ msg ++ "))"
19+showErr err = mainEquals $ "Elm.Graphics.text(Elm.Text.monospace(" ++ msg ++ "))"
2020 where msg = show . concatMap (++"<br>") . lines $ err
2121
2222indent = concatMap f
@@ -55,7 +55,8 @@ tryBlock escapees names e =
5555
5656jsModule (escapees, Module names exports imports stmts) =
5757 tryBlock escapees (tail modNames) $ concat
58− [ "\nfor(this['i'] in Elm) { eval('var ' + this['i'] + '=Elm[this.i];'); }"
58+ [ assign "$op" "{}"
59+ , "\nfor(this['i'] in Elm){eval('var '+this['i']+'=Elm[this.i];');}"
5960 , concatMap (\n -> globalAssign n $ n ++ " || {}") .
6061 map (intercalate ".") . drop 2 . inits $
6162 take (length modNames - 1) modNames
@@ -71,22 +72,31 @@ jsModule (escapees, Module names exports imports stmts) =
7172 export = getExports exports stmts
7273 exps = if null exports then ["main"] else exports
7374
74−getExports names stmts = ret . braces $ intercalate "," pairs
75− where pairs = mapMaybe pair $ concatMap get stmts
76− pair x = if null names || y `elem` names then
77− Just $ y ++ ":" ++ x else Nothing
78− where y = derename x
79− get s = case s of Def x _ _ -> [x]
80− Datatype _ _ tcs -> map fst tcs
81− ImportEvent _ _ x _ -> [x]
75+getExports names stmts = ret . braces $ intercalate ",\n" (op : map fnPair fns)
76+ where exNames n = either id id n `elem` names
77+ exports | null names = concatMap get stmts
78+ | otherwise = filter exNames (concatMap get stmts)
79+
80+ (fns,ops) = partitionEithers exports
81+
82+ opPair op = "'" ++ op ++ "' : $op['" ++ op ++ "']"
83+ fnPair fn = let fn' = derename fn in fn' ++ ":" ++ fn
84+
85+ op = ("$op : "++) . braces . intercalate ", " $ map opPair ops
86+
87+ get' (FnDef x _ _) = Left x
88+ get' (OpDef op _ _ _) = Right op
89+ get s = case s of Definition d -> [ get' d ]
90+ Datatype _ _ tcs -> map (Left . fst) tcs
91+ ImportEvent _ _ x _ -> [ Left x ]
8292 ExportEvent _ _ _ -> []
8393
8494
8595jsImport (modul, how) =
86− concat [ "\ntry{if (!(" ++ modul ++ " instanceof Object)) throw 'module not found'; } catch(e) {throw \"Module '"
96+ concat [ "\ntry{\n if (!(" ++ modul ++ " instanceof Object)) throw 'module not found';\n} catch(e) {\n throw (\"Module '"
8797 , drop 1 (dropWhile (/='.') modul)
8898 , "' is missing. Compile with --make flag or load missing "
89− , "module in a separate JavaScript file.\";}" ] ++
99+ , "module in a separate JavaScript file.\");\n}" ] ++
90100 jsImport' (modul, how)
91101
92102jsImport' (modul, As name) = assign name modul
@@ -95,44 +105,56 @@ jsImport' (modul, Importing vs) =
95105jsImport' (modul, Hiding vs) =
96106 concat [ assign "hiddenVars" . ("{"++) . (++"}") . intercalate "," $
97107 map (\v -> v ++ ":true") vs
98− , "\nfor(this['i'] in " ++ modul ++ "){"
99− , indent $ "\nif (hiddenVars[i]) continue;"
100− , indent $ "\neval('var ' + this['i'] + ' = " ++ modul ++ "[this.i];');"
101− , "}" ]
108+ , "\nfor (this['i'] in " ++ modul ++ ") "
109+ , braces . indent . concat $
110+ [ "\nif (hiddenVars[this['i']]) continue;"
111+ , "\neval('var ' + this['i'] + ' = "
112+ , modul, "[this.i];');" ]
113+ ]
102114
103115stmtsToJS :: [Statement] -> String
104−stmtsToJS stmts = concatMap stmtToJS (sortBy cmpStmt stmts)
116+stmtsToJS stmts = run (concat `liftM` mapM toJS (sortBy cmpStmt stmts))
105117 where cmpStmt s1 s2 = compare (valueOf s1) (valueOf s2)
106− valueOf s = case s of Datatype _ _ _ -> 1
107− ImportEvent _ _ _ _ -> 3
108− Def _ [] _ -> 3
109− Def _ _ _ -> 4
110− ExportEvent _ _ _ -> 5
111−
112−stmtToJS :: Statement -> String
113−stmtToJS (Def name [] e) = assign name (toJS e)
114−stmtToJS (Def name (a:as) e) = "\nfunction " ++ name ++ parens a ++
115− braces (indent . ret . toJS $ foldr Lambda e as) ++ ";"
116−stmtToJS (Datatype _ _ tcs) = concatMap (stmtToJS . toDef) tcs
117− where toDef (name,args) = Def name vars $ Data (derename name) (map Var vars)
118− where vars = map (('a':) . show) [1..length args]
119−stmtToJS (ImportEvent js base elm _) =
120− concat [ "\nvar " ++ elm ++ " = Elm.Signal.constant(" ++ toJS base ++ ");"
121− , "\nValue.addListener(document, '" ++ js
122− , "', function(e) { Dispatcher.notify(" ++ elm
123− , ".id, e.value); });" ]
124−stmtToJS (ExportEvent js elm _) =
125− concat [ "\nlift(function(v) { var e = document.createEvent('Event');"
126− , "e.initEvent('" ++ js ++ "', true, true);"
127− , "e.value = v;"
128− , "document.dispatchEvent(e); return v; })(" ++ elm ++ ");"
129− ]
130−
131−
132−toJS = run . toJS'
133−
134−toJS' :: Expr -> GuidCounter String
135−toJS' expr =
118+ valueOf s = case s of Datatype _ _ _ -> 1
119+ ImportEvent _ _ _ _ -> 3
120+ Definition (FnDef _ [] _) -> 3
121+ Definition (OpDef _ _ _ _) -> 3
122+ Definition _ -> 4
123+ ExportEvent _ _ _ -> 5
124+
125+class ToJS a where
126+ toJS :: a -> GuidCounter String
127+
128+instance ToJS Def where
129+ toJS (FnDef x [] e) = assign x `liftM` toJS e
130+ toJS (FnDef f (a:as) e) =
131+ do body <- toJS (foldr Lambda e as)
132+ return $ concat ["\nfunction ",f,parens a, braces . indent $ ret body]
133+ toJS (OpDef op a1 a2 e) =
134+ do body <- toJS (foldr Lambda e [a1,a2])
135+ return $ concat [ "\n$op['", op, "'] = ", body, ";" ]
136+
137+instance ToJS Statement where
138+ toJS (Definition d) = toJS d
139+ toJS (Datatype _ _ tcs) = concat `liftM` mapM (toJS . toDef) tcs
140+ where toDef (name,args) =
141+ Definition . FnDef name vars $ Data (derename name) (map Var vars)
142+ where vars = map (('a':) . show) [1..length args]
143+ toJS (ImportEvent js base elm _) =
144+ do v <- toJS base
145+ return $ concat [ "\nvar " ++ elm ++ "=Elm.Signal.constant(" ++ v ++ ");"
146+ , "\nValue.addListener(document, '" ++ js
147+ , "', function(e) { Dispatcher.notify(" ++ elm
148+ , ".id, e.value); });" ]
149+ toJS (ExportEvent js elm _) =
150+ return $ concat [ "\nlift(function(v) { "
151+ , "var e = document.createEvent('Event');"
152+ , "e.initEvent('", js, "', true, true);"
153+ , "e.value = v;"
154+ , "document.dispatchEvent(e); return v; })(", elm, ");" ]
155+
156+instance ToJS Expr where
157+ toJS expr =
136158 case expr of
137159 IntNum n -> return $ show n
138160 FloatNum n -> return $ show n
@@ -140,18 +162,18 @@ toJS' expr =
140162 Chr c -> return $ show c
141163 Str s -> return $ "Value.str" ++ parens (show s)
142164 Boolean b -> return $ if b then "true" else "false"
143− Range lo hi -> jsRange `liftM` toJS' lo `ap` toJS' hi
144− Access e lbl -> (\s -> s ++ "." ++ lbl) `liftM` toJS' e
145− Binop op e1 e2 -> binop op `liftM` toJS' e1 `ap` toJS' e2
146− If eb et ef -> parens `liftM` (iff `liftM` toJS' eb `ap` toJS' et `ap` toJS' ef)
147− Lambda v e -> liftM (jsFunc v . ret) (toJS' e)
165+ Range lo hi -> jsRange `liftM` toJS lo `ap` toJS hi
166+ Access e lbl -> (\s -> s ++ "." ++ lbl) `liftM` toJS e
167+ Binop op e1 e2 -> binop op `liftM` toJS e1 `ap` toJS e2
168+ If eb et ef -> parens `liftM` (iff `liftM` toJS eb `ap` toJS et `ap` toJS ef)
169+ Lambda v e -> liftM (jsFunc v . ret) (toJS e)
148170 App (Var "toText") (Str s) -> return $ "toText" ++ parens (show s)
149171 App (Var "link") (Str s) -> return $ "link(" ++ show s ++ ")"
150172 App (Var "plainText") (Str s) -> return $ "plainText(" ++ show s ++ ")"
151− App e1 e2 -> (++) `liftM` (toJS' e1) `ap` (parens `liftM` toJS' e2)
173+ App e1 e2 -> (++) `liftM` (toJS e1) `ap` (parens `liftM` toJS e2)
152174 Let defs e -> jsLet defs e
153175 Case e cases -> caseToJS e cases
154− Data name es -> (\ss -> jsList $ show name : ss) `liftM` mapM toJS' es
176+ Data name es -> (\ss -> jsList $ show name : ss) `liftM` mapM toJS es
155177 Markdown doc -> return $ "text('" ++ pad ++ md ++ pad ++ "')"
156178 where md = formatMarkdown $ Pan.writeHtmlString Pan.defaultWriterOptions doc
157179 pad = "<div style=\"height:0;width:0;\">&nbsp;</div>"
@@ -163,20 +185,17 @@ formatMarkdown = concatMap f
163185 f c = [c]
164186
165187jsLet defs e' = do
166− body <- (++) `liftM` jsDefs defs `ap` (ret `liftM` toJS' e')
188+ body <- (++) `liftM` jsDefs defs `ap` (ret `liftM` toJS e')
167189 return $ jsFunc "" body ++ "()"
168190
169−jsDefs defs = concat `liftM` mapM toDef (sortBy f defs)
191+jsDefs defs = concat `liftM` mapM toJS (sortBy f defs)
170192 where f a b = compare (valueOf a) (valueOf b)
171− valueOf (Definition _ args _) = min 1 (length args)
172− toDef (Definition x [] e) = assign x `liftM` toJS' e
173− toDef (Definition f (a:as) e) = do
174− out <- toJS' $ foldr Lambda e as
175− return $ "\nfunction " ++ f ++ parens a ++ braces (indent $ ret out) ++ ";"
193+ valueOf (FnDef _ args _) = min 1 (length args)
194+ valueOf (OpDef _ _ _ _) = 1
176195
177196caseToJS e ps = do
178197 match <- caseToMatch ps
179− e' <- toJS' e
198+ e' <- toJS e
180199 (match',stmt) <- case (match,e) of
181200 (Match name _ _, Var x) -> return (matchSubst [(name,x)] match, "")
182201 (Match name _ _, _ ) -> return (match, assign name e')
@@ -190,7 +209,7 @@ matchToJS (Match name clauses def) = do
190209 return $ concat [ "\nswitch(", name, "[0]){", indent cases, "\n}", finally ]
191210matchToJS Fail = return "\nthrow \"Non-exhaustive pattern match in case\";"
192211matchToJS Break = return "break;"
193−matchToJS (Other e) = ret `liftM` toJS' e
212+matchToJS (Other e) = ret `liftM` toJS e
194213matchToJS (Seq ms) = concat `liftM` mapM matchToJS ms
195214
196215clauseToJS var (Clause name vars e) = do
@@ -207,20 +226,24 @@ jsRange e1 e2 = (++"()") . jsFunc "" $
207226
208227binop (o:p) e1 e2
209228 | isAlpha o || '_' == o = (o:p) ++ parens e1 ++ parens e2
210− | otherwise = case o:p of
211− ":" -> jsCons e1 e2
212− "++" -> append e1 e2
213− "$" -> e1 ++ parens e2
214− "." -> jsFunc "x" . ret $ e1 ++ parens (e2 ++ parens "x")
215− "^" -> "Math.pow(" ++ e1 ++ "," ++ e2 ++ ")"
216− "==" -> "eq(" ++ e1 ++ "," ++ e2 ++ ")"
217− "/=" -> "not(eq(" ++ e1 ++ "," ++ e2 ++ "))"
218− "<" -> "(compare(" ++ e1 ++ ")(" ++ e2 ++ ")[0] === 'LT')"
219− ">" -> "(compare(" ++ e1 ++ ")(" ++ e2 ++ ")[0] === 'GT')"
220− "<=" -> "function() { var ord = compare(" ++ e1 ++ ")(" ++ e2 ++ ")[0]; return ord === 'LT' || ord === 'EQ'; }()"
221− ">=" -> "function() { var ord = compare(" ++ e1 ++ ")(" ++ e2 ++ ")[0]; return ord === 'GT' || ord === 'EQ'; }()"
222− ">>>" -> "composeAuto(" ++ e1 ++ ")(" ++ e2 ++ ")"
223− "<<<" -> "composeAuto(" ++ e2 ++ ")(" ++ e1 ++ ")"
224− _ -> parens (e1 ++ (o:p) ++ e2)
229+ | otherwise =
230+ let ops = ["+","-","*","/","&&","||"] in
231+ case o:p of
232+ ":" -> jsCons e1 e2
233+ "++" -> append e1 e2
234+ "$" -> e1 ++ parens e2
235+ "." -> jsFunc "x" . ret $ e1 ++ parens (e2 ++ parens "x")
236+ "^" -> "Math.pow(" ++ e1 ++ "," ++ e2 ++ ")"
237+ "==" -> "eq(" ++ e1 ++ "," ++ e2 ++ ")"
238+ "/=" -> "not(eq(" ++ e1 ++ "," ++ e2 ++ "))"
239+ "<" -> "(compare(" ++ e1 ++ ")(" ++ e2 ++ ")[0] === 'LT')"
240+ ">" -> "(compare(" ++ e1 ++ ")(" ++ e2 ++ ")[0] === 'GT')"
241+ "<=" -> "function() { var ord = compare(" ++ e1 ++ ")(" ++
242+ e2 ++ ")[0]; return ord==='LT' || ord==='EQ'; }()"
243+ ">=" -> "function() { var ord = compare(" ++ e1 ++ ")(" ++
244+ e2 ++ ")[0]; return ord==='GT' || ord==='EQ'; }()"
245+ _ | elem (o:p) ops -> parens (e1 ++ (o:p) ++ e2)
246+ | otherwise -> concat [ "$op['", o:p, "']"
247+ , parens e1, parens e2 ]
225248
226249append e1 e2 = "Value.append" ++ parens (e1 ++ "," ++ e2)
elm/src/Gen/ExtractNoscript.hs+32−13
@@ -1,37 +1,56 @@
11
2−module ExtractNoscript (extract) where
2+module ExtractNoscript (extractNoscript) where
33
44import Ast
55import qualified Text.Pandoc as Pan
66
7−extract (Module _ _ _ stmts) =
8− concatMap (\s -> "<p>" ++ s ++ "</p>") (concatMap stmtExtract stmts)
9− where stmtExtract (Def _ _ e) = extract' e
10− stmtExtract _ = []
7+extractNoscript :: Module -> String
8+extractNoscript modul = concat (extract modul)
119
12−extract' expr =
13− let f = extract' in
10+class Extract a where
11+ extract :: a -> [String]
12+
13+instance Extract Module where
14+ extract (Module _ _ _ stmts) =
15+ map (\s -> "<p>" ++ s ++ "</p>") (concatMap extract stmts)
16+
17+instance Extract Statement where
18+ extract (Definition d) = extract d
19+ extract _ = []
20+
21+instance Extract Def where
22+ extract (FnDef _ _ e) = extract e
23+ extract (OpDef _ _ _ e) = extract e
24+
25+instance Extract Expr where
26+ extract expr =
27+ let f = extract in
1428 case expr of
1529 Str s -> [s]
1630 Binop op e1 e2 -> case (op, f e1, f e2) of
1731 ("++", [s1], [s2]) -> [s1 ++ s2]
1832 (_ , ss1 , ss2 ) -> ss1 ++ ss2
1933 Lambda v e -> f e
20− App (App (Var "link") src) txt ->
21− case (f src, f txt) of
22− ([s1],[s2]) -> [ "<a href=\"" ++ s1 ++ "\">" ++ s2 ++ "</a>" ]
23− ( ss1, ss2) -> ss1 ++ ss2
34+ App (App (Var "link") src) txt -> linkExtract src txt
35+ App (App (Var "Graphics.link") src) txt -> linkExtract src txt
36+ App (App (Var "Text.link") src) txt -> linkExtract src txt
2437 App (Var "header") e -> tag "h1" e
2538 App (Var "bold") e -> tag "b" e
2639 App (Var "italic") e -> tag "i" e
2740 App (Var "monospace") e -> tag "code" e
2841 App e1 e2 -> f e1 ++ f e2
2942 If eb et ef -> f et ++ f ef
30− Let defs e -> concatMap (\(Definition _ _ d) -> f d) defs ++ f e
43+ Let defs e -> concatMap extract defs ++ f e
3144 Var _ -> []
3245 Case e cases -> concatMap (f . snd) cases
3346 Data _ es -> concatMap f es
3447 Markdown doc -> [ Pan.writeHtmlString Pan.defaultWriterOptions doc ]
3548 _ -> []
3649
37−tag t e = map (\s -> concat [ "<", t, ">", s, "</", t, ">" ]) (extract' e)
50+linkExtract src txt =
51+ case (extract src, extract txt) of
52+ ([s1],[s2]) -> [ "<a href=\"" ++ s1 ++ "\">" ++ s2 ++ "</a>" ]
53+ ( ss1, ss2) -> ss1 ++ ss2
54+
55+
56+tag t e = map (\s -> concat [ "<", t, ">", s, "</", t, ">" ]) (extract e)
elm/src/Gen/GenerateHtml.hs+3−2
@@ -49,10 +49,11 @@ generateHtml libLoc title source =
4949 Right (escs, modul) -> modulesToHtml Readable title libLoc [] True [(escs,modul)]
5050
5151
52−modulesToHtml jsStyle title libLoc jss nscrpt pairs = createHtml jsStyle libLoc title' js noscript
52+modulesToHtml jsStyle title libLoc jss nscrpt pairs =
53+ createHtml jsStyle libLoc title' js noscript
5354 where modules = map snd pairs
5455 js = Right $ jss ++ concatMap jsModule pairs
55− noscript = if nscrpt then extract $ last modules else ""
56+ noscript = if nscrpt then extractNoscript $ last modules else ""
5657 title' = if null title then altTitle else title
5758 altTitle = (\(Module names _ _ _) -> intercalate "." names) $
5859 last modules
elm/src/Initialize.hs+1−2
@@ -14,10 +14,9 @@ import Optimize
1414
1515
1616initialize str =
17− let nameOf (Definition n _ _) = n in
1817 do modul@(Module name ex im stmts) <- parseProgram str
1918 (escapees, subs) <- unify hints modul
20− let modul' = optimize . rename $ Module name ex im' stmts
19+ let modul' = optimize . renameModule $ Module name ex im' stmts
2120 where im' | any ((=="Prelude") . fst) im = im
2221 | otherwise = ("Prelude", Hiding []) : im
2322 subs `seq` return (escapees, modul')
elm/src/Language/Elm.hs+1−1
@@ -79,4 +79,4 @@ toPartsHelper :: String -> (Html, Html, String)
7979toPartsHelper source = (html, css, js)
8080 where modul = initialize source
8181 js = either showErr jsModule modul
82− html = widgetBody $ either id (extract . snd) modul
82+ html = widgetBody $ either id (extractNoscript . snd) modul
elm/src/Optimize.hs+17−8
@@ -9,13 +9,23 @@ optimize (Module name ims exs stmts) =
99 Module name ims exs (map optimizeStmt stmts)
1010
1111optimizeStmt stmt = if stmt == stmt' then stmt' else optimizeStmt stmt'
12− where stmt' = simpStmt stmt
13− simpStmt (Def name args e) = Def name args (simp e)
14− simpStmt (ImportEvent js b elm t) = ImportEvent js (simp b) elm t
15− simpStmt stmt = stmt
12+ where stmt' = simp stmt
1613
17−simp :: Expr -> Expr
18−simp expr =
14+class Simplify a where
15+ simp :: a -> a
16+
17+instance Simplify Statement where
18+ simp (Definition def) = Definition (simp def)
19+ simp (ImportEvent js b elm t) = ImportEvent js (simp b) elm t
20+ simp stmt = stmt
21+
22+instance Simplify Def where
23+ simp (FnDef func args e) = FnDef func args (simp e)
24+ simp (OpDef op a1 a2 e) = OpDef op a1 a2 (simp e)
25+
26+
27+instance Simplify Expr where
28+ simp expr =
1929 let f = simp in
2030 case expr of
2131 Range e1 e2 -> Range (f e1) (f e2)
@@ -26,8 +36,7 @@ simp expr =
2636 where { e1' = f e1 ; e2' = f e2 }
2737 App e1 e2 -> App (f e1) (f e2)
2838 If e1 e2 e3 -> simp_if (f e1) (f e2) (f e3)
29− Let defs e -> Let (map simpDef defs) (f e)
30− where simpDef (Definition func args e) = Definition func args (f e)
39+ Let defs e -> Let (map simp defs) (f e)
3140 Data name es -> Data name (map f es)
3241 Case e cases -> Case (f e) (map (second f) cases)
3342 _ -> expr
elm/src/Parse/ParseExpr.hs+18−10
@@ -119,17 +119,25 @@ caseExpr = do
119119expr = choice [ ifExpr, letExpr, caseExpr
120120 , lambdaExpr, binaryExpr ] <?> "an expression"
121121
122+funcDef = do p1 <- try patternTerm ; infics p1 <|> func p1
123+ where func p@(PVar v) = (p:) <$> spacePrefix patternTerm
124+ func p = do try (lookAhead (whitespace >> string "="))
125+ return [p]
126+ infics p1 = do
127+ o:p <- try (whitespace >> anyOp)
128+ p2 <- (whitespace >> patternTerm)
129+ return $ if o == '`' then [ PVar $ takeWhile (/='`') p, p1, p2 ]
130+ else [ PVar (o:p), p1, p2 ]
131+
122132assignExpr = do
123− patterns <-
124− choice [ try $ do v <- PVar <$> lowVar
125− notFollowedBy (whitespace >> char ':')
126− (v:) <$> spacePrefix patternTerm
127− , (:[]) <$> patternExpr
128− ] <?> "the definition of a variable (x = ...)"
129− whitespace; string "="; whitespace; exp <- expr
130− flattenPatterns patterns exp
131−
132−def = map (\(Definition n as e) -> Def n as e) <$> assignExpr
133+ fDefs <- try funcDef
134+ <|> ((:[]) <$> patternExpr)
135+ <?> "the definition of a variable (x = ...)"
136+ whitespace; string "="; whitespace
137+ e <- expr
138+ flattenPatterns fDefs e
139+
140+def = map Definition <$> assignExpr
133141
134142
135143parseDef str =
elm/src/Parse/ParseLib.hs+8−4
@@ -40,10 +40,14 @@ reserved word =
4040 <?> "reserved word '" ++ word ++ "'"
4141
4242anyOp :: (Monad m) => ParsecT [Char] u m String
43−anyOp = betwixt '`' '`' var <|>
44− (do op <- many1 (satisfy isSymbol <|> oneOf "+-/*=.$<>:&|^?%#@~!")
45− guard (op `notElem` [ "=", "..", "->", "--" ])
46− return op) <?> "infix operator (e.g. +, *, ||)"
43+anyOp = betwixt '`' '`' var <|> symOp <?> "infix operator (e.g. +, *, ||)"
44+
45+isOp c = isSymbol c || elem c "+-/*=.$<>:&|^?%#@~!"
46+
47+symOp :: (Monad m) => ParsecT [Char] u m String
48+symOp = do op <- many1 (satisfy isOp)
49+ guard (op `notElem` [ "=", "..", "->", "--" ])
50+ return op
4751
4852arrow :: (Monad m) => ParsecT [Char] u m String
4953arrow = string "->" <|> string "\8594" <?> "arrow (->)"
elm/src/Parse/Patterns.hs+9−4
@@ -38,17 +38,22 @@ makeBody pats body = foldr func body pats
3838 func (PVar x) e = e
3939 func p e = Case (Var $ getName p) [(p,e)]
4040
41−flattenPatterns (PVar f : args) exp =
42− return [ Definition f (map getName args) (makeBody args exp) ]
41+flattenPatterns (PVar f : args) exp
42+ | isOp (head f) = let [a,b] = (map getName args) in
43+ return [ OpDef f a b (makeBody args exp) ]
44+ | otherwise = return [ FnDef f (map getName args) (makeBody args exp) ]
45+
46+
4347flattenPatterns [p] exp = return $ matchSingle p exp p
48+
4449flattenPatterns ps _ =
4550 fail $ "Pattern (" ++ unwords (map show ps) ++
4651 ") cannot be used on the left-hand side of an assign statement."
4752
4853matchSingle pat exp p@(PData _ ps) =
49− (Definition v [] exp) : concatMap (matchSingle p $ Var v) ps
54+ (FnDef v [] exp) : concatMap (matchSingle p $ Var v) ps
5055 where v = getName p
51−matchSingle pat exp (PVar x) = [ Definition x [] (Case exp [(pat,Var x)]) ]
56+matchSingle pat exp (PVar x) = [ FnDef x [] (Case exp [(pat,Var x)]) ]
5257matchSingle pat exp PAnything = []
5358
5459getName p = f p
elm/src/Rename.hs+47−35
@@ -1,5 +1,5 @@
11{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2−module Rename (rename, derename) where
2+module Rename (renameModule, derename) where
33
44import Ast
55import Control.Arrow (first)
@@ -12,29 +12,45 @@ derename var
1212 | isDigit (last var) = reverse . tail . dropWhile isDigit $ reverse var
1313 | otherwise = var
1414
15−rename :: Module -> Module
16−rename (Module name ex im stmts) =
17− Module name ex im . run $ renameStatements deprime stmts
18−
19−renameStatements env stmts = do env' <- extends env $ concatMap getNames stmts
20− mapM (renameStmt env') stmts
21− where getNames stmt = case stmt of Def n _ _ -> [n]
22− Datatype _ _ tcs -> map fst tcs
23− ImportEvent _ _ n _ -> [n]
24− ExportEvent _ _ _ -> []
25− renameStmt env (Def name args e) =
26− do env' <- extends env args
27− Def (env name) (map env' args) `liftM` rename' env' e
28− renameStmt env (Datatype name args tcs) =
29− return $ Datatype name args $ map (first env) tcs
30− renameStmt env (ImportEvent js base elm tipe) =
31− do base' <- rename' env base
32− return $ ImportEvent js base' (env elm) tipe
33− renameStmt env (ExportEvent js elm tipe) =
34− return $ ExportEvent js (env elm) tipe
35−
36−rename' :: (String -> String) -> Expr -> GuidCounter Expr
37−rename' env expr =
15+renameModule :: Module -> Module
16+renameModule modul = run (rename deprime modul)
17+
18+class Rename a where
19+ rename :: (String -> String) -> a -> GuidCounter a
20+
21+instance Rename Module where
22+ rename env (Module name ex im stmts) = do stmts' <- renameStmts env stmts
23+ return (Module name ex im stmts')
24+
25+instance Rename Def where
26+ rename env (OpDef op a1 a2 e) =
27+ do env' <- extends env [a1,a2]
28+ OpDef op (env' a1) (env' a2) `liftM` rename env' e
29+ rename env (FnDef f args e) =
30+ do env' <- extends env args
31+ FnDef (env f) (map env' args) `liftM` rename env' e
32+
33+instance Rename Statement where
34+ rename env (Definition def) = Definition `liftM` rename env def
35+ rename env (Datatype name args tcs) =
36+ return $ Datatype name args $ map (first env) tcs
37+ rename env (ImportEvent js base elm tipe) =
38+ do base' <- rename env base
39+ return $ ImportEvent js base' (env elm) tipe
40+ rename env (ExportEvent js elm tipe) =
41+ return $ ExportEvent js (env elm) tipe
42+
43+renameStmts env stmts = do env' <- extends env $ concatMap getNames stmts
44+ mapM (rename env') stmts
45+ where getNames stmt = case stmt of
46+ Definition (FnDef n _ _) -> [n]
47+ Datatype _ _ tcs -> map fst tcs
48+ ImportEvent _ _ n _ -> [n]
49+ _ -> []
50+
51+instance Rename Expr where
52+ rename env expr =
53+ let rnm = rename env in
3854 case expr of
3955
4056 Range e1 e2 -> Range `liftM` rnm e1
@@ -52,7 +68,7 @@ rename' env expr =
5268
5369 Lambda x e -> do
5470 (rx, env') <- extend env x
55− Lambda rx `liftM` rename' env' e
71+ Lambda rx `liftM` rename env' e
5672
5773 App e1 e2 -> App `liftM` rnm e1
5874 `ap` rnm e2
@@ -81,8 +97,6 @@ rename' env expr =
8197
8298 _ -> return expr
8399
84− where rnm = rename' env
85−
86100deprime = map (\c -> if c == '\'' then '_' else c)
87101
88102extend :: (String -> String) -> String -> GuidCounter (String, String -> String)
@@ -107,13 +121,11 @@ patternExtend pattern env =
107121patternRename :: (String -> String) -> (Pattern, Expr) -> GuidCounter (Pattern, Expr)
108122patternRename env (p,e) = do
109123 (rp,env') <- patternExtend p env
110− re <- rename' env' e
124+ re <- rename env' e
111125 return (rp,re)
112126
113−renameLet env defs e = do env' <- extends env $ map getNames defs
114− defs' <- mapM (renameDef env') defs
115− Let defs' `liftM` rename' env' e
116− where getNames (Definition n _ _) = n
117− renameDef env (Definition name args e) =
118− do env' <- extends env args
119− Definition (env name) (map env' args) `liftM` rename' env' e
127+renameLet env defs e = do env' <- extends env $ concatMap getNames defs
128+ defs' <- mapM (rename env') defs
129+ Let defs' `liftM` rename env' e
130+ where getNames (FnDef n _ _) = [n]
131+ getNames (OpDef _ _ _ _) = []
elm/src/Substitute.hs+2−1
@@ -19,7 +19,8 @@ subst old new expr =
1919 Async e -> Async (f e)
2020 Input _ -> expr
2121 Let defs e -> Let (map substDef defs) (f e)
22− where substDef (Definition name vs e) = Definition name vs (f e)
22+ where substDef (FnDef name vs e) = FnDef name vs (f e)
23+ substDef (OpDef op a1 a2 e) = OpDef op a1 a2 (f e)
2324 Var x -> if x == old then new else expr
2425 Case e cases -> Case (f e) $ map (second f) cases
2526 Data name es -> Data name (map f es)
elm/src/Types/Constrain.hs+26−22
@@ -81,8 +81,10 @@ gen (Let defs e) =
8181 do (as,cs,t) <- gen e
8282 (ass, schemes) <- liftM unzip (mapM defScheme defs)
8383 let assumptions = unionsA (as:ass)
84− let names = map (\(Definition x _ _) -> x) defs
85− let genCs name s = do
84+ getName (FnDef f _ _) = f
85+ getName (OpDef op _ _ _) = op
86+ names = map getName defs
87+ genCs name s = do
8688 v <- guid
8789 let vs = Map.findWithDefault [v] name assumptions
8890 return $ map (\x -> ctx (Var name) $ x :<<: s) vs
@@ -157,26 +159,28 @@ patternGen (as,cs,ts) p@(PData name ps) = do
157159 , ts ++ [output] )
158160
159161
160−defScheme :: Definition -> GuidCounter (Map.Map String [X], Scheme)
161−defScheme (Definition name args e) = do
162− (as,cs,hint) <- defGen name args e
163− return ( as, snd hint )
164−
165−defGen name args e = do
166− argDict <- mapM (\a -> liftM ((,) a) guid) args
167− (as,cs,t) <- gen e
168− let genCs (arg,x) = do
169− v <- guid
170− return . map (\y -> Context arg $ VarT x :=: VarT y) $ Map.findWithDefault [v] arg as
171− cs' <- concat `liftM` mapM genCs argDict
172− let as' = foldr Map.delete as args
173− let tipe = foldr (==>) t $ map (VarT . snd) argDict
174− scheme <- generalize (concat $ Map.elems as') $
175− Forall (map snd argDict) (cs' ++ Set.toList cs) tipe
176− return ( as', Set.empty, (name, scheme) )
177−
178−stmtGen (Def name args e) = do (as,cs,hint) <- defGen name args e
179− return ( as, cs, [hint] )
162+defScheme :: Def -> GuidCounter (Map.Map String [X], Scheme)
163+defScheme def = do (as,cs,hint) <- defGen def
164+ return ( as, snd hint )
165+
166+defGen def = case def of FnDef f args e -> defGen' f args e
167+ OpDef op a1 a2 e -> defGen' op [a1,a2] e
168+ where defGen' name args e = do
169+ argDict <- mapM (\a -> liftM ((,) a) guid) args
170+ (as,cs,t) <- gen e
171+ let as' = foldr Map.delete as args
172+ tipe = foldr (==>) t $ map (VarT . snd) argDict
173+ genCs (arg,x) = do
174+ v <- guid
175+ let as' = Map.findWithDefault [v] arg as
176+ return $ map (\y -> Context arg $ VarT x :=: VarT y) as'
177+ cs' <- concat `liftM` mapM genCs argDict
178+ scheme <- generalize (concat $ Map.elems as') $
179+ Forall (map snd argDict) (cs' ++ Set.toList cs) tipe
180+ return ( as', Set.empty, (name, scheme) )
181+
182+stmtGen (Definition def) = do (as,cs,hint) <- defGen def
183+ return ( as, cs, [hint] )
180184
181185stmtGen (Datatype name xs tcs) = do schemes <- mapM gen' tcs'
182186 return (Map.empty, Set.empty, schemes)