on 42c3f75 help sign in
elk/src/Generate/JavaScript/Expression.hs
789 lines 20 kB history raw
1{-# LANGUAGE OverloadedStrings #-}
2module Generate.JavaScript.Expression
3 ( generateJsExpr
4 )
5 where
8import qualified Data.IntMap as IntMap
9import qualified Data.List as List
10import qualified Data.Map as Map
11import qualified Data.Text.Encoding as Text
13import qualified AST.Optimized as Opt
14import qualified AST.Module.Name as ModuleName
15import qualified Data.Index as Index
16import qualified Elm.Name as N
17import qualified Elm.Package as Pkg
18import qualified Generate.JavaScript.Builder as JS
19import qualified Generate.JavaScript.Name as Name
20import qualified Optimize.DecisionTree as DT
21import qualified Reporting.Region as R
25-- ENVIRONMENT
28type Mode = Name.Mode
32-- EXPRESSIONS
35generateJsExpr :: Mode -> Opt.Expr -> JS.Expr
36generateJsExpr mode expression =
37 codeToJsExpr (generateCode mode expression)
40generateCode :: Mode -> Opt.Expr -> Code
41generateCode mode expression =
42 case expression of
43 Opt.Chr char ->
44 JsExpr $
45 case mode of
46 Name.Debug ->
47 JS.Call toChar [ JS.String (Text.encodeUtf8Builder char) ]
49 Name.Prod _ ->
50 JS.String (Text.encodeUtf8Builder char)
52 Opt.Str string ->
53 JsExpr $ JS.String (Text.encodeUtf8Builder string)
55 Opt.Int int ->
56 JsExpr $ JS.Int int
58 Opt.Float float ->
59 JsExpr $ JS.Float float
61 Opt.VarLocal name ->
62 JsExpr $ JS.Ref (Name.fromLocal name)
64 Opt.VarGlobal (Opt.Global home name) ->
65 JsExpr $ JS.Ref (Name.fromGlobal home name)
67 Opt.VarCycle home name ->
68 JsExpr $ JS.Ref (Name.fromCycle home name)
70 Opt.VarDebug name home region unhandledValueName ->
71 JsExpr $ generateDebug name home region unhandledValueName
73 Opt.VarKernel home name ->
74 JsExpr $ JS.Ref (Name.fromKernel home name)
76 Opt.List entries ->
77 JsExpr $
78 JS.Call
79 (JS.Ref (Name.fromKernel N.list "fromArray"))
80 [ JS.Array $ map (generateJsExpr mode) entries
81 ]
83 Opt.Function args body ->
84 generateFunction args (generateCode mode body)
86 Opt.Call func args ->
87 JsExpr $ generateCall mode func args
89 Opt.TailCall name args ->
90 JsBlock $ generateTailCall mode name args
92 Opt.If branches final ->
93 generateIf mode branches final
95 Opt.Let def body ->
96 JsBlock $
97 generateDef mode def : codeToStatementList (generateCode mode body)
99 Opt.Case label root decider jumps ->
100 JsBlock $ generateCase mode label root decider jumps
102 Opt.Index expr index ->
103 JsExpr $ JS.Access (generateJsExpr mode expr) (Name.fromInt index)
105 Opt.Accessor field ->
106 JsExpr $ JS.Function Nothing [Name.dollar]
107 [ JS.Return $ Just $
108 JS.Access (JS.Ref Name.dollar) (Name.fromField mode field)
109 ]
111 Opt.Access record field ->
112 JsExpr $ JS.Access (generateJsExpr mode record) (Name.fromField mode field)
114 Opt.Update record fields ->
115 JsExpr $
116 JS.Call (JS.Ref (Name.fromKernel N.utils "update"))
117 [ generateJsExpr mode record
118 , generateRecord mode fields
119 ]
121 Opt.Record fields ->
122 JsExpr $ generateRecord mode fields
124 Opt.Unit ->
125 JsExpr $ JS.Ref (Name.fromKernel N.utils "Tuple0")
127 Opt.Tuple a b maybeC ->
128 JsExpr $
129 case maybeC of
130 Nothing ->
131 JS.Call (JS.Ref (Name.fromKernel N.utils "Tuple2"))
132 [ generateJsExpr mode a
133 , generateJsExpr mode b
134 ]
136 Just c ->
137 JS.Call (JS.Ref (Name.fromKernel N.utils "Tuple3"))
138 [ generateJsExpr mode a
139 , generateJsExpr mode b
140 , generateJsExpr mode c
141 ]
143 Opt.Shader src ->
144 let string = JS.String (Text.encodeUtf8Builder src) in
145 JsExpr $ JS.Object [ ( Name.fromLocal "src", string ) ]
149-- CODE CHUNKS
152data Code
153 = JsExpr JS.Expr
154 | JsBlock [JS.Stmt]
157codeToJsExpr :: Code -> JS.Expr
158codeToJsExpr code =
159 case code of
160 JsExpr expr ->
161 expr
163 JsBlock stmts ->
164 JS.Call (JS.Function Nothing [] stmts) []
167codeToStatementList :: Code -> [JS.Stmt]
168codeToStatementList code =
169 case code of
170 JsExpr expr ->
171 [ JS.Return (Just expr) ]
173 JsBlock stmts ->
174 stmts
177codeToStatement :: Code -> JS.Stmt
178codeToStatement code =
179 case code of
180 JsExpr expr ->
181 JS.Return (Just expr)
183 JsBlock [stmt] ->
184 stmt
186 JsBlock stmts ->
187 JS.Block stmts
191-- CHARS
194{-# NOINLINE toChar #-}
195toChar :: JS.Expr
196toChar =
197 JS.Ref (Name.fromKernel N.utils "chr")
201-- RECORDS
204generateRecord :: Mode -> Map.Map N.Name Opt.Expr -> JS.Expr
205generateRecord mode fields =
206 let
207 toPair (field, value) =
208 (Name.fromField mode field, generateJsExpr mode value)
209 in
210 JS.Object (map toPair (Map.toList fields))
214-- DEBUG
217generateDebug :: N.Name -> ModuleName.Canonical -> R.Region -> Maybe N.Name -> JS.Expr
218generateDebug name (ModuleName.Canonical _ home) region unhandledValueName =
219 if name /= "crash" then
220 JS.Ref (Name.fromGlobal ModuleName.debug name)
221 else
222 case unhandledValueName of
223 Nothing ->
224 JS.Call (JS.Ref (Name.fromKernel N.utils "crash")) $
225 [ JS.String (N.toBuilder home)
226 , regionToJsExpr region
227 ]
229 Just valueName ->
230 JS.Call (JS.Ref (Name.fromKernel N.utils "crashCase")) $
231 [ JS.String (N.toBuilder home)
232 , regionToJsExpr region
233 , JS.Ref (Name.fromLocal valueName)
234 ]
237regionToJsExpr :: R.Region -> JS.Expr
238regionToJsExpr (R.Region start end) =
239 JS.Object
240 [ ( Name.fromLocal "start", positionToJsExpr start )
241 , ( Name.fromLocal "end", positionToJsExpr end )
242 ]
245positionToJsExpr :: R.Position -> JS.Expr
246positionToJsExpr (R.Position line column) =
247 JS.Object
248 [ ( Name.fromLocal "line", JS.Int line )
249 , ( Name.fromLocal "column", JS.Int column )
250 ]
254-- FUNCTION
257generateFunction :: [N.Name] -> Code -> Code
258generateFunction args body =
259 case IntMap.lookup (length args) funcHelpers of
260 Just helper ->
261 JsExpr $
262 JS.Call helper
263 [ JS.Function Nothing (map Name.fromLocal args) $
264 codeToStatementList body
265 ]
267 Nothing ->
268 let
269 addArg arg code =
270 JsExpr $ JS.Function Nothing [Name.fromLocal arg] $
271 codeToStatementList code
272 in
273 foldr addArg body args
276{-# NOINLINE funcHelpers #-}
277funcHelpers :: IntMap.IntMap JS.Expr
278funcHelpers =
279 IntMap.fromList
280 [ (2, JS.Ref (Name.fromLocal "F2"))
281 , (3, JS.Ref (Name.fromLocal "F3"))
282 , (4, JS.Ref (Name.fromLocal "F4"))
283 , (5, JS.Ref (Name.fromLocal "F5"))
284 , (6, JS.Ref (Name.fromLocal "F6"))
285 , (7, JS.Ref (Name.fromLocal "F7"))
286 , (8, JS.Ref (Name.fromLocal "F8"))
287 , (9, JS.Ref (Name.fromLocal "F9"))
288 ]
292-- CALLS
295generateCall :: Mode -> Opt.Expr -> [Opt.Expr] -> JS.Expr
296generateCall mode func args =
297 case func of
298 Opt.VarGlobal global@(Opt.Global (ModuleName.Canonical pkg _) _) | pkg == Pkg.core ->
299 generateCoreCall mode global args
301 _ ->
302 generateNormalCall
303 (generateJsExpr mode func)
304 (map (generateJsExpr mode) args)
307generateNormalCall' :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
308generateNormalCall' home name args =
309 generateNormalCall (JS.Ref (Name.fromGlobal home name)) args
312generateNormalCall :: JS.Expr -> [JS.Expr] -> JS.Expr
313generateNormalCall func args =
314 case IntMap.lookup (length args) callHelpers of
315 Just helper ->
316 JS.Call helper (func:args)
318 Nothing ->
319 List.foldl' (\f a -> JS.Call f [a]) func args
322{-# NOINLINE callHelpers #-}
323callHelpers :: IntMap.IntMap JS.Expr
324callHelpers =
325 IntMap.fromList
326 [ (2, JS.Ref (Name.fromLocal "A2"))
327 , (3, JS.Ref (Name.fromLocal "A3"))
328 , (4, JS.Ref (Name.fromLocal "A4"))
329 , (5, JS.Ref (Name.fromLocal "A5"))
330 , (6, JS.Ref (Name.fromLocal "A6"))
331 , (7, JS.Ref (Name.fromLocal "A7"))
332 , (8, JS.Ref (Name.fromLocal "A8"))
333 , (9, JS.Ref (Name.fromLocal "A9"))
334 ]
338-- CORE CALLS
341generateCoreCall :: Mode -> Opt.Global -> [Opt.Expr] -> JS.Expr
342generateCoreCall mode (Opt.Global home@(ModuleName.Canonical _ moduleName) name) args =
343 if moduleName == N.basics then
344 generateBasicsCall mode home name args
346 else if moduleName == N.bitwise then
347 generateBitwiseCall home name (map (generateJsExpr mode) args)
349 else if moduleName == N.tuple then
350 generateTupleCall home name (map (generateJsExpr mode) args)
352 else
353 generateNormalCall' home name (map (generateJsExpr mode) args)
356generateTupleCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
357generateTupleCall home name args =
358 case args of
359 [value] ->
360 case name of
361 "first" -> JS.Access value (Name.fromLocal "a")
362 "second" -> JS.Access value (Name.fromLocal "b")
363 _ -> generateNormalCall' home name args
365 _ ->
366 generateNormalCall' home name args
369generateBitwiseCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
370generateBitwiseCall home name args =
371 case args of
372 [arg] ->
373 case name of
374 "complement" -> JS.Prefix JS.PrefixBNot arg
375 _ -> generateNormalCall' home name args
377 [left,right] ->
378 case name of
379 "and" -> JS.Infix JS.OpBAnd left right
380 "or" -> JS.Infix JS.OpBOr left right
381 "xor" -> JS.Infix JS.OpBXor left right
382 "shiftLeftBy" -> JS.Infix JS.OpLShift right left
383 "shiftRightBy" -> JS.Infix JS.OpSpRShift right left
384 "shiftRightZfBy" -> JS.Infix JS.OpZfRShift right left
385 _ -> generateNormalCall' home name args
387 _ ->
388 generateNormalCall' home name args
391generateBasicsCall :: Mode -> ModuleName.Canonical -> N.Name -> [Opt.Expr] -> JS.Expr
392generateBasicsCall mode home name args =
393 case args of
394 [elmArg] ->
395 let arg = generateJsExpr mode elmArg in
396 case name of
397 "not" -> JS.Prefix JS.PrefixLNot arg
398 "toFloat" -> arg
399 "truncate" -> JS.Infix JS.OpBOr arg (JS.Int 0)
400 _ -> generateNormalCall' home name [arg]
402 [elmLeft, elmRight] ->
403 case name of
404 "composeL" -> decomposeL mode elmLeft [elmRight]
405 "composeR" -> decomposeR mode [elmLeft] elmRight
406 "apL" -> generateJsExpr mode $ apply elmLeft elmRight
407 "apR" -> generateJsExpr mode $ apply elmRight elmLeft
408 _ ->
409 let
410 left = generateJsExpr mode elmLeft
411 right = generateJsExpr mode elmRight
412 in
413 case name of
414 "add" -> JS.Infix JS.OpAdd left right
415 "sub" -> JS.Infix JS.OpSub left right
416 "mul" -> JS.Infix JS.OpMul left right
417 "fdiv" -> JS.Infix JS.OpDiv left right
418 "idiv" -> JS.Infix JS.OpBOr (JS.Infix JS.OpDiv left right) (JS.Int 0)
419 "eq" -> equal left right
420 "neq" -> notEqual left right
421 "lt" -> cmp JS.OpLT JS.OpLT 0 left right
422 "gt" -> cmp JS.OpGT JS.OpGT 0 left right
423 "le" -> cmp JS.OpLEq JS.OpLT 1 left right
424 "ge" -> cmp JS.OpGEq JS.OpGT (-1) left right
425 "or" -> JS.Infix JS.OpLOr left right
426 "and" -> JS.Infix JS.OpLAnd left right
427 "xor" -> JS.Infix JS.OpStrictNEq left right
428 _ -> generateNormalCall' home name [left, right]
430 _ ->
431 generateNormalCall' home name (map (generateJsExpr mode) args)
434equal :: JS.Expr -> JS.Expr -> JS.Expr
435equal left right =
436 if isLiteral left || isLiteral right then
437 strictEq left right
438 else
439 JS.Call (JS.Ref (Name.fromKernel N.utils "eq")) [left, right]
442notEqual :: JS.Expr -> JS.Expr -> JS.Expr
443notEqual left right =
444 if isLiteral left || isLiteral right then
445 strictNEq left right
446 else
447 JS.Prefix JS.PrefixLNot $
448 JS.Call (JS.Ref (Name.fromKernel N.utils "eq")) [left, right]
451cmp :: JS.InfixOp -> JS.InfixOp -> Int -> JS.Expr -> JS.Expr -> JS.Expr
452cmp idealOp backupOp backupInt left right =
453 if isLiteral left || isLiteral right then
454 JS.Infix idealOp left right
455 else
456 JS.Infix backupOp
457 (JS.Call (JS.Ref (Name.fromKernel N.utils "cmp")) [left, right])
458 (JS.Int backupInt)
461isLiteral :: JS.Expr -> Bool
462isLiteral expr =
463 case expr of
464 JS.String _ ->
465 True
467 JS.Float _ ->
468 True
470 JS.Int _ ->
471 True
473 JS.Bool _ ->
474 True
476 _ ->
477 False
480decomposeL :: Mode -> Opt.Expr -> [Opt.Expr] -> JS.Expr
481decomposeL mode expr funcs =
482 case expr of
483 Opt.Call (Opt.VarGlobal (Opt.Global home "composeL")) [left, func]
484 | home == ModuleName.basics ->
485 decomposeL mode left (func:funcs)
487 _ ->
488 generateJsExpr mode $
489 Opt.Function [N.dollar] (foldr apply (Opt.VarLocal N.dollar) (expr:funcs))
492decomposeR :: Mode -> [Opt.Expr] -> Opt.Expr -> JS.Expr
493decomposeR mode funcs expr =
494 case expr of
495 Opt.Call (Opt.VarGlobal (Opt.Global home "composeR")) [func, right]
496 | home == ModuleName.basics ->
497 decomposeR mode (func:funcs) right
499 _ ->
500 generateJsExpr mode $
501 Opt.Function [N.dollar] (foldr apply (Opt.VarLocal N.dollar) (expr:funcs))
504apply :: Opt.Expr -> Opt.Expr -> Opt.Expr
505apply func value =
506 case func of
507 Opt.Accessor field ->
508 Opt.Access value field
510 Opt.Call f args ->
511 Opt.Call f (args ++ [value])
513 _ ->
514 Opt.Call func [value]
518-- SIMPLIFY INFIX OPERATORS
521strictEq :: JS.Expr -> JS.Expr -> JS.Expr
522strictEq left right =
523 case left of
524 JS.Int 0 ->
525 JS.Prefix JS.PrefixLNot right
527 JS.Bool bool ->
528 if bool then right else JS.Prefix JS.PrefixLNot right
530 _ ->
531 case right of
532 JS.Int 0 ->
533 JS.Prefix JS.PrefixLNot left
535 JS.Bool bool ->
536 if bool then left else JS.Prefix JS.PrefixLNot left
538 _ ->
539 JS.Infix JS.OpStrictEq left right
542strictNEq :: JS.Expr -> JS.Expr -> JS.Expr
543strictNEq left right =
544 case left of
545 JS.Int 0 ->
546 right
548 JS.Bool bool ->
549 if bool then JS.Prefix JS.PrefixLNot right else right
551 _ ->
552 case right of
553 JS.Int 0 ->
554 left
556 JS.Bool bool ->
557 if bool then JS.Prefix JS.PrefixLNot left else left
559 _ ->
560 JS.Infix JS.OpStrictNEq left right
564-- TAIL CALL
567-- TODO check if JS minifiers collapse unnecessary temporary variables
568--
569generateTailCall :: Mode -> N.Name -> [(N.Name, Opt.Expr)] -> [JS.Stmt]
570generateTailCall mode name args =
571 let
572 toTempVars (argName, arg) =
573 ( Name.makeTemp argName, Just (generateJsExpr mode arg) )
575 toRealVars (argName, _) =
576 JS.ExprStmt $
577 JS.Assign (JS.LVar (Name.fromLocal argName)) (JS.Ref (Name.makeTemp argName))
578 in
579 JS.Var (map toTempVars args)
580 : map toRealVars args
581 ++ [ JS.Continue (Just (Name.fromLocal name)) ]
585-- DEFINITIONS
588generateDef :: Mode -> Opt.Def -> JS.Stmt
589generateDef mode def =
590 case def of
591 Opt.Def name body ->
592 JS.Var [ (Name.fromLocal name, Just (generateJsExpr mode body)) ]
594 Opt.TailDef name argNames body ->
595 let
596 function =
597 JS.Function Nothing (map Name.fromLocal argNames)
598 [ JS.Labelled (Name.fromLocal name) $
599 JS.While (JS.Bool True) $
600 codeToStatement $ generateCode mode body
601 ]
602 in
603 JS.Var [ (Name.fromLocal name, Just function) ]
607-- GENERATE IFS
610generateIf :: Mode -> [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> Code
611generateIf mode givenBranches givenFinal =
612 let
613 (branches, final) =
614 crushIfs givenBranches givenFinal
616 convertBranch (condition, expr) =
617 ( generateJsExpr mode condition
618 , generateCode mode expr
619 )
621 branchExprs = map convertBranch branches
622 finalCode = generateCode mode final
623 in
624 if isBlock finalCode || any (isBlock . snd) branchExprs then
625 JsBlock [ foldr addStmtIf (codeToStatement finalCode) branchExprs ]
626 else
627 JsExpr $ foldr addExprIf (codeToJsExpr finalCode) branchExprs
630addExprIf :: (JS.Expr, Code) -> JS.Expr -> JS.Expr
631addExprIf (condition, branch) final =
632 JS.If condition (codeToJsExpr branch) final
635addStmtIf :: (JS.Expr, Code) -> JS.Stmt -> JS.Stmt
636addStmtIf (condition, branch) final =
637 JS.IfStmt condition (codeToStatement branch) final
640isBlock :: Code -> Bool
641isBlock code =
642 case code of
643 JsBlock _ -> True
644 JsExpr _ -> False
647crushIfs :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
648crushIfs branches final =
649 crushIfsHelp [] branches final
652crushIfsHelp
653 :: [(Opt.Expr, Opt.Expr)]
654 -> [(Opt.Expr, Opt.Expr)]
655 -> Opt.Expr
656 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
657crushIfsHelp visitedBranches unvisitedBranches final =
658 case unvisitedBranches of
659 [] ->
660 case final of
661 Opt.If subBranches subFinal ->
662 crushIfsHelp visitedBranches subBranches subFinal
664 _ ->
665 (reverse visitedBranches, final)
667 visiting : unvisited ->
668 crushIfsHelp (visiting : visitedBranches) unvisited final
672-- CASE EXPRESSIONS
675generateCase :: Mode -> N.Name -> N.Name -> Opt.Decider Opt.Choice -> [(Int, Opt.Expr)] -> [JS.Stmt]
676generateCase mode label root decider jumps =
677 foldr (goto mode label) (generateDecider mode label root decider) jumps
680goto :: Mode -> N.Name -> (Int, Opt.Expr) -> [JS.Stmt] -> [JS.Stmt]
681goto mode label (index, branch) stmts =
682 let
683 labeledDeciderStmt =
684 JS.Labelled
685 (Name.makeLabel label index)
686 (JS.While (JS.Bool True) (JS.Block stmts))
687 in
688 labeledDeciderStmt : codeToStatementList (generateCode mode branch)
691generateDecider :: Mode -> N.Name -> N.Name -> Opt.Decider Opt.Choice -> [JS.Stmt]
692generateDecider mode label root decisionTree =
693 case decisionTree of
694 Opt.Leaf (Opt.Inline branch) ->
695 codeToStatementList (generateCode mode branch)
697 Opt.Leaf (Opt.Jump index) ->
698 [ JS.Break (Just (Name.makeLabel label index)) ]
700 Opt.Chain testChain success failure ->
701 let
702 makeTest (path, test) =
703 strictEq
704 (pathToTestableExpr mode root path test)
705 (testToExpr mode test)
706 in
707 [ JS.IfStmt
708 (List.foldl1' (JS.Infix JS.OpLAnd) (map makeTest testChain))
709 (JS.Block $ generateDecider mode label root success)
710 (JS.Block $ generateDecider mode label root failure)
711 ]
713 Opt.FanOut path edges fallback ->
714 [ JS.Switch
715 (pathToTestableExpr mode root path (fst (head edges)))
716 ( foldr
717 (addCase mode label root)
718 [ JS.Default (generateDecider mode label root fallback) ]
719 edges
720 )
721 ]
724addCase :: Mode -> N.Name -> N.Name -> (DT.Test, Opt.Decider Opt.Choice) -> [JS.Case] -> [JS.Case]
725addCase mode label root (test, subTree) cases =
726 let stmts = generateDecider mode label root subTree in
727 JS.Case (testToExpr mode test) stmts : cases
730testToExpr :: Mode -> DT.Test -> JS.Expr
731testToExpr mode test =
732 case test of
733 DT.IsCtor _ tag index ->
734 case mode of
735 Name.Debug ->
736 JS.String (N.toBuilder tag)
738 Name.Prod _ ->
739 JS.Int (Index.toZeroBased index)
741 DT.IsInt int ->
742 JS.Int int
744 DT.IsChr char ->
745 JS.String (Text.encodeUtf8Builder char)
747 DT.IsStr string ->
748 JS.String (Text.encodeUtf8Builder string)
751pathToTestableExpr :: Mode -> N.Name -> DT.Path -> DT.Test -> JS.Expr
752pathToTestableExpr mode root path exampleTest =
753 let
754 expr =
755 pathToJsExpr mode (JS.Ref (Name.fromLocal root)) path
756 in
757 case exampleTest of
758 DT.IsCtor _ _ _ ->
759 JS.Access expr Name.dollar
761 DT.IsInt _ ->
762 expr
764 DT.IsStr _ ->
765 expr
767 DT.IsChr _ ->
768 case mode of
769 Name.Debug ->
770 JS.Call (JS.Access expr (Name.fromLocal "valueOf")) []
772 Name.Prod _ ->
773 expr
776pathToJsExpr :: Mode -> JS.Expr -> DT.Path -> JS.Expr
777pathToJsExpr mode expr path =
778 case path of
779 DT.Index index subpath ->
780 pathToJsExpr mode (JS.Access expr (Name.fromInt index)) subpath
782 DT.Field field subpath ->
783 pathToJsExpr mode (JS.Access expr (Name.fromField mode field)) subpath
785 DT.Empty ->
786 expr
788 DT.Alias ->
789 expr