hydra-typescript-0.17.3: src/main/haskell/Hydra/TypeScript/Serde.hs
-- Note: this is an automatically generated file. Do not edit.
-- | Serialization functions for converting TypeScript AST to abstract expressions
module Hydra.TypeScript.Serde where
import qualified Hydra.Ast as Ast
import qualified Hydra.Coders as Coders
import qualified Hydra.Constants as Constants
import qualified Hydra.Core as Core
import qualified Hydra.Docs as Docs
import qualified Hydra.Error.Checking as Checking
import qualified Hydra.Error.Core as ErrorCore
import qualified Hydra.Error.File as ErrorFile
import qualified Hydra.Error.Packaging as ErrorPackaging
import qualified Hydra.Error.System as ErrorSystem
import qualified Hydra.Errors as Errors
import qualified Hydra.File as File
import qualified Hydra.Graph as Graph
import qualified Hydra.Json.Model as Model
import qualified Hydra.Overlay.Haskell.Lib.Equality as Equality
import qualified Hydra.Overlay.Haskell.Lib.Lists as Lists
import qualified Hydra.Overlay.Haskell.Lib.Literals as Literals
import qualified Hydra.Overlay.Haskell.Lib.Logic as Logic
import qualified Hydra.Overlay.Haskell.Lib.Math as Math
import qualified Hydra.Overlay.Haskell.Lib.Optionals as Optionals
import qualified Hydra.Overlay.Haskell.Lib.Ordering as Ordering
import qualified Hydra.Overlay.Haskell.Lib.Pairs as Pairs
import qualified Hydra.Overlay.Haskell.Lib.Strings as Strings
import qualified Hydra.Packaging as Packaging
import qualified Hydra.Parsing as Parsing
import qualified Hydra.Paths as Paths
import qualified Hydra.Query as Query
import qualified Hydra.Regex as Regex
import qualified Hydra.Relational as Relational
import qualified Hydra.Serialization as Serialization
import qualified Hydra.System as System
import qualified Hydra.Tabular as Tabular
import qualified Hydra.Testing as Testing
import qualified Hydra.Time as Time
import qualified Hydra.Topology as Topology
import qualified Hydra.TypeScript.Operators as Operators
import qualified Hydra.TypeScript.Syntax as Syntax
import qualified Hydra.Typed as Typed
import qualified Hydra.Typing as Typing
import qualified Hydra.Util as Util
import qualified Hydra.Validation as Validation
import qualified Hydra.Variants as Variants
import Prelude hiding (Enum, Ordering, decodeFloat, encodeFloat, fail, map, pure, sum)
import qualified Data.Scientific as Sci
-- | True iff every codepoint is an ASCII digit 0-9, and the list is non-empty
allDigits :: [Int] -> Bool
allDigits cps =
Logic.and (Ordering.gt (Lists.length cps) 0) (Lists.foldl (\acc -> \c -> Logic.and acc (Logic.and (Ordering.gte c 48) (Ordering.lte c 57))) True cps)
-- | Convert an array element to an AST expression
arrayElementToExpr :: Syntax.ArrayElement -> Ast.Expr
arrayElementToExpr elem =
case elem of
Syntax.ArrayElementExpression v0 -> expressionToExpr v0
Syntax.ArrayElementSpread v0 -> Serialization.prefix "..." (expressionToExpr (Syntax.unSpreadElement v0))
Syntax.ArrayElementHole -> Serialization.cst ""
-- | Convert an array expression to an AST expression
arrayExpressionToExpr :: [Syntax.ArrayElement] -> Ast.Expr
arrayExpressionToExpr arr = Serialization.bracketList Serialization.inlineStyle (Lists.map arrayElementToExpr arr)
-- | Convert an array pattern to an AST expression
arrayPatternToExpr :: [Maybe Syntax.Pattern] -> Ast.Expr
arrayPatternToExpr arr =
Serialization.bracketList Serialization.inlineStyle (Lists.map (\maybeP -> Optionals.cases maybeP (Serialization.cst "") patternToExpr) arr)
-- | Convert an arrow function expression to an AST expression
arrowFunctionExpressionToExpr :: Syntax.ArrowFunctionExpression -> Ast.Expr
arrowFunctionExpressionToExpr arrow =
let params = Syntax.arrowFunctionExpressionParams arrow
body = Syntax.arrowFunctionExpressionBody arrow
async = Syntax.arrowFunctionExpressionAsync arrow
asyncKw = Logic.ifElse async [
Serialization.cst "async"] []
paramsExpr = Serialization.parenListAdaptive (Lists.map patternToExpr params)
bodyExpr =
case body of
Syntax.ArrowFunctionBodyExpression v0 -> case v0 of
Syntax.ExpressionObject _ -> Serialization.parens (expressionToExpr v0)
Syntax.ExpressionSequence _ -> Serialization.parens (expressionToExpr v0)
_ -> expressionToExpr v0
Syntax.ArrowFunctionBodyBlock v0 -> blockStatementToExpr v0
in (Serialization.spaceSep (Lists.concat [
asyncKw,
[
Serialization.ifx Operators.arrowOp paramsExpr bodyExpr]]))
-- | Convert an assignment expression to an AST expression
assignmentExpressionToExpr :: Syntax.AssignmentExpression -> Ast.Expr
assignmentExpressionToExpr assign =
let op = Syntax.assignmentExpressionOperator assign
left = Syntax.assignmentExpressionLeft assign
right = Syntax.assignmentExpressionRight assign
opStr = assignmentOperatorToString op
in (Serialization.spaceSep [
patternToExpr left,
(Serialization.cst opStr),
(expressionToExpr right)])
-- | Convert an assignment operator to a string
assignmentOperatorToString :: Syntax.AssignmentOperator -> String
assignmentOperatorToString op =
case op of
Syntax.AssignmentOperatorAssign -> "="
Syntax.AssignmentOperatorAddAssign -> "+="
Syntax.AssignmentOperatorSubtractAssign -> "-="
Syntax.AssignmentOperatorMultiplyAssign -> "*="
Syntax.AssignmentOperatorDivideAssign -> "/="
Syntax.AssignmentOperatorModuloAssign -> "%="
Syntax.AssignmentOperatorExponentiateAssign -> "**="
Syntax.AssignmentOperatorLeftShiftAssign -> "<<="
Syntax.AssignmentOperatorRightShiftAssign -> ">>="
Syntax.AssignmentOperatorUnsignedRightShiftAssign -> ">>>="
Syntax.AssignmentOperatorBitwiseAndAssign -> "&="
Syntax.AssignmentOperatorBitwiseOrAssign -> "|="
Syntax.AssignmentOperatorBitwiseXorAssign -> "^="
Syntax.AssignmentOperatorAndAssign -> "&&="
Syntax.AssignmentOperatorOrAssign -> "||="
Syntax.AssignmentOperatorNullishAssign -> "??="
-- | Convert an assignment pattern to an AST expression
assignmentPatternToExpr :: Syntax.AssignmentPattern -> Ast.Expr
assignmentPatternToExpr assign =
let left = Syntax.assignmentPatternLeft assign
right = Syntax.assignmentPatternRight assign
in (Serialization.ifx Operators.defineOp (patternToExpr left) (expressionToExpr right))
-- | Convert a binary expression to an AST expression
binaryExpressionToExpr :: Syntax.BinaryExpression -> Ast.Expr
binaryExpressionToExpr bin =
let op = Syntax.binaryExpressionOperator bin
left = Syntax.binaryExpressionLeft bin
right = Syntax.binaryExpressionRight bin
in (Serialization.ifx (binaryOperatorToExpr op) (expressionToExpr left) (expressionToExpr right))
-- | Convert a binary operator to an Op
binaryOperatorToExpr :: Syntax.BinaryOperator -> Ast.Op
binaryOperatorToExpr op =
case op of
Syntax.BinaryOperatorAdd -> Operators.addOp
Syntax.BinaryOperatorSubtract -> Operators.subtractOp
Syntax.BinaryOperatorMultiply -> Operators.multiplyOp
Syntax.BinaryOperatorDivide -> Operators.divideOp
Syntax.BinaryOperatorModulo -> Operators.moduloOp
Syntax.BinaryOperatorExponentiate -> Operators.exponentiateOp
Syntax.BinaryOperatorEqual -> Operators.equalOp
Syntax.BinaryOperatorNotEqual -> Operators.notEqualOp
Syntax.BinaryOperatorStrictEqual -> Operators.strictEqualOp
Syntax.BinaryOperatorStrictNotEqual -> Operators.strictNotEqualOp
Syntax.BinaryOperatorLessThan -> Operators.lessThanOp
Syntax.BinaryOperatorLessThanOrEqual -> Operators.lessThanOrEqualOp
Syntax.BinaryOperatorGreaterThan -> Operators.greaterThanOp
Syntax.BinaryOperatorGreaterThanOrEqual -> Operators.greaterThanOrEqualOp
Syntax.BinaryOperatorAnd -> Operators.logicalAndOp
Syntax.BinaryOperatorOr -> Operators.logicalOrOp
Syntax.BinaryOperatorNullishCoalescing -> Operators.nullishCoalescingOp
Syntax.BinaryOperatorBitwiseAnd -> Operators.bitwiseAndOp
Syntax.BinaryOperatorBitwiseOr -> Operators.bitwiseOrOp
Syntax.BinaryOperatorBitwiseXor -> Operators.bitwiseXorOp
Syntax.BinaryOperatorLeftShift -> Operators.leftShiftOp
Syntax.BinaryOperatorRightShift -> Operators.rightShiftOp
Syntax.BinaryOperatorUnsignedRightShift -> Operators.unsignedRightShiftOp
Syntax.BinaryOperatorIn -> Operators.inOp
Syntax.BinaryOperatorInstanceof -> Operators.instanceOfOp
-- | Convert a block statement to an AST expression. Renders as `{ stmt1\n stmt2\n ... }` using curlyBlock + newlineSep: statements are separated by newlines, NOT by commas (which curlyBracesList's default would insert and which TypeScript rejects between block statements).
blockStatementToExpr :: [Syntax.Statement] -> Ast.Expr
blockStatementToExpr block =
Serialization.curlyBlock Serialization.fullBlockStyle (Serialization.newlineSep (Lists.map statementToExpr block))
-- | Convert a break statement to an AST expression
breakStatementToExpr :: Maybe Syntax.Identifier -> Ast.Expr
breakStatementToExpr b =
Optionals.cases b (Serialization.cst "break;") (\label -> Serialization.suffix ";" (Serialization.spaceSep [
Serialization.cst "break",
(identifierToExpr label)]))
-- | Convert a call expression to an AST expression
callExpressionToExpr :: Syntax.CallExpression -> Ast.Expr
callExpressionToExpr call =
let callee = Syntax.callExpressionCallee call
args = Syntax.callExpressionArguments call
optional = Syntax.callExpressionOptional call
calleeExpr =
case callee of
Syntax.ExpressionArrow _ -> Serialization.parens (expressionToExpr callee)
Syntax.ExpressionConditional _ -> Serialization.parens (expressionToExpr callee)
Syntax.ExpressionBinary _ -> Serialization.parens (expressionToExpr callee)
Syntax.ExpressionUnary _ -> Serialization.parens (expressionToExpr callee)
Syntax.ExpressionAssignment _ -> Serialization.parens (expressionToExpr callee)
Syntax.ExpressionSequence _ -> Serialization.parens (expressionToExpr callee)
Syntax.ExpressionObject _ -> Serialization.parens (expressionToExpr callee)
Syntax.ExpressionFunction _ -> Serialization.parens (expressionToExpr callee)
_ -> expressionToExpr callee
argsExpr = Serialization.parenListAdaptive (Lists.map expressionToExpr args)
optionalDot = Logic.ifElse optional "?." ""
in (Serialization.spaceSep [
calleeExpr,
(Serialization.cst optionalDot),
argsExpr])
-- | Convert a catch clause to an AST expression
catchClauseToExpr :: Syntax.CatchClause -> Ast.Expr
catchClauseToExpr c =
let param = Syntax.catchClauseParam c
body = Syntax.catchClauseBody c
catchKw =
Optionals.cases param (Serialization.cst "catch") (\p -> Serialization.spaceSep [
Serialization.cst "catch",
(Serialization.parens (patternToExpr p))])
in (Serialization.spaceSep [
catchKw,
(blockStatementToExpr body)])
-- | Convert a class declaration to an AST expression
classDeclarationToExpr :: Syntax.ClassDeclaration -> Ast.Expr
classDeclarationToExpr cls =
let id = Syntax.classDeclarationId cls
superClass = Syntax.classDeclarationSuperClass cls
body = Syntax.classDeclarationBody cls
extendsClause =
Optionals.cases superClass [] (\s -> [
Serialization.cst "extends",
(expressionToExpr s)])
bodyExpr =
Serialization.curlyBlock Serialization.fullBlockStyle (Serialization.newlineSep (Lists.map methodDefinitionToExpr body))
in (Serialization.spaceSep (Lists.concat [
[
Serialization.cst "class",
(identifierToExpr id)],
extendsClause,
[
bodyExpr]]))
-- | Convert a class declaration with comments to an AST expression
classDeclarationWithCommentsToExpr :: Syntax.ClassDeclarationWithComments -> Ast.Expr
classDeclarationWithCommentsToExpr cdwc =
let body = Syntax.classDeclarationWithCommentsBody cdwc
mc = Syntax.classDeclarationWithCommentsComments cdwc
in (Optionals.cases mc (classDeclarationToExpr body) (\c -> Serialization.newlineSep [
documentationCommentToExpr c,
(classDeclarationToExpr body)]))
-- | Convert a conditional expression to an AST expression
conditionalExpressionToExpr :: Syntax.ConditionalExpression -> Ast.Expr
conditionalExpressionToExpr cond =
let test = Syntax.conditionalExpressionTest cond
consequent = Syntax.conditionalExpressionConsequent cond
alternate = Syntax.conditionalExpressionAlternate cond
consExpr =
case consequent of
Syntax.ExpressionObject _ -> Serialization.parens (expressionToExpr consequent)
Syntax.ExpressionSequence _ -> Serialization.parens (expressionToExpr consequent)
_ -> expressionToExpr consequent
altExpr =
case alternate of
Syntax.ExpressionObject _ -> Serialization.parens (expressionToExpr alternate)
Syntax.ExpressionSequence _ -> Serialization.parens (expressionToExpr alternate)
_ -> expressionToExpr alternate
in (Serialization.spaceSep [
expressionToExpr test,
(Serialization.cst "?"),
consExpr,
(Serialization.cst ":"),
altExpr])
-- | Convert a continue statement to an AST expression
continueStatementToExpr :: Maybe Syntax.Identifier -> Ast.Expr
continueStatementToExpr c =
Optionals.cases c (Serialization.cst "continue;") (\label -> Serialization.suffix ";" (Serialization.spaceSep [
Serialization.cst "continue",
(identifierToExpr label)]))
-- | Convert a do-while statement to an AST expression
doWhileStatementToExpr :: Syntax.DoWhileStatement -> Ast.Expr
doWhileStatementToExpr d =
let body = Syntax.doWhileStatementBody d
test = Syntax.doWhileStatementTest d
in (Serialization.suffix ";" (Serialization.spaceSep [
Serialization.cst "do",
(statementToExpr body),
(Serialization.cst "while"),
(Serialization.parens (expressionToExpr test))]))
-- | Convert a documentation comment to an AST expression
documentationCommentToExpr :: Syntax.DocumentationComment -> Ast.Expr
documentationCommentToExpr doc =
let description = Syntax.documentationCommentDescription doc
tags = Syntax.documentationCommentTags doc
in (Serialization.cst (toTypeScriptComments description tags))
-- | Convert a documentation tag to a JSDoc line. Built by joining non-empty parts with spaces so that absent type/param/description components don't introduce trailing whitespace.
documentationTagToLine :: Syntax.DocumentationTag -> String
documentationTagToLine tag =
let name = Syntax.documentationTagName tag
mtype = Syntax.documentationTagType tag
mparamName = Syntax.documentationTagParamName tag
description = Syntax.documentationTagDescription tag
typePart =
Optionals.cases mtype "" (\t -> Strings.concat [
"{",
(typeExpressionToString t),
"}"])
paramPart = Optionals.cases mparamName "" (\p -> Syntax.unIdentifier p)
parts =
[
Strings.concat2 "@" name,
typePart,
paramPart,
description]
nonEmpty = Lists.filter (\p -> Logic.not (Equality.equal p "")) parts
in (Strings.concat2 " * " (Strings.join " " nonEmpty))
-- | Escape special characters in a string for TypeScript
escapeString :: String -> Bool -> String
escapeString s singleQuote =
let replace = \old -> \new_ -> \str -> Strings.join new_ (Strings.splitOn old str)
s1 = replace "\\" "\\\\" s
s2 = replace "\n" "\\n" s1
s3 = replace "\r" "\\r" s2
s4 = replace "\t" "\\t" s3
in (Logic.ifElse singleQuote (replace "'" "\\'" s4) (replace "\"" "\\\"" s4))
-- | Convert an export all declaration to an AST expression
exportAllToExpr :: Syntax.ExportAllDeclaration -> Ast.Expr
exportAllToExpr a =
let exported = Syntax.exportAllDeclarationExported a
source = Syntax.exportAllDeclarationSource a
exportedClause =
Optionals.cases exported (Serialization.cst "*") (\e -> Serialization.spaceSep [
Serialization.cst "*",
(Serialization.cst "as"),
(identifierToExpr e)])
in (Serialization.suffix ";" (Serialization.spaceSep [
Serialization.cst "export",
exportedClause,
(Serialization.cst "from"),
(stringLiteralToExpr source)]))
-- | Convert an export declaration to an AST expression
exportDeclarationToExpr :: Syntax.ExportDeclaration -> Ast.Expr
exportDeclarationToExpr exp =
case exp of
Syntax.ExportDeclarationNamed v0 -> namedExportToExpr v0
Syntax.ExportDeclarationDefault v0 -> Serialization.suffix ";" (Serialization.spaceSep [
Serialization.cst "export",
(Serialization.cst "default"),
(expressionToExpr v0)])
Syntax.ExportDeclarationDeclaration v0 -> Serialization.spaceSep [
Serialization.cst "export",
(statementToExpr v0)]
Syntax.ExportDeclarationAll v0 -> exportAllToExpr v0
-- | Convert an export specifier to an AST expression
exportSpecifierToExpr :: Syntax.ExportSpecifier -> Ast.Expr
exportSpecifierToExpr spec =
let local = Syntax.exportSpecifierLocal spec
exported = Syntax.exportSpecifierExported spec
in (Logic.ifElse (Equality.equal (Syntax.unIdentifier local) (Syntax.unIdentifier exported)) (identifierToExpr local) (Serialization.spaceSep [
identifierToExpr local,
(Serialization.cst "as"),
(identifierToExpr exported)]))
-- | Convert a TypeScript expression to an AST expression
expressionToExpr :: Syntax.Expression -> Ast.Expr
expressionToExpr expr =
case expr of
Syntax.ExpressionIdentifier v0 -> identifierToExpr v0
Syntax.ExpressionLiteral v0 -> literalToExpr v0
Syntax.ExpressionArray v0 -> arrayExpressionToExpr v0
Syntax.ExpressionObject v0 -> objectExpressionToExpr v0
Syntax.ExpressionFunction v0 -> functionExpressionToExpr v0
Syntax.ExpressionArrow v0 -> arrowFunctionExpressionToExpr v0
Syntax.ExpressionCall v0 -> callExpressionToExpr v0
Syntax.ExpressionMember v0 -> memberExpressionToExpr v0
Syntax.ExpressionConditional v0 -> conditionalExpressionToExpr v0
Syntax.ExpressionBinary v0 -> binaryExpressionToExpr v0
Syntax.ExpressionUnary v0 -> unaryExpressionToExpr v0
Syntax.ExpressionAssignment v0 -> assignmentExpressionToExpr v0
Syntax.ExpressionSequence v0 -> Serialization.parenListAdaptive (Lists.map expressionToExpr v0)
Syntax.ExpressionThis -> Serialization.cst "this"
Syntax.ExpressionNew v0 -> Serialization.spaceSep [
Serialization.cst "new",
(callExpressionToExpr v0)]
Syntax.ExpressionYield v0 -> Optionals.cases v0 (Serialization.cst "yield") (\e -> Serialization.spaceSep [
Serialization.cst "yield",
(expressionToExpr e)])
Syntax.ExpressionAwait v0 -> Serialization.spaceSep [
Serialization.cst "await",
(expressionToExpr v0)]
Syntax.ExpressionSpread v0 -> Serialization.prefix "..." (expressionToExpr (Syntax.unSpreadElement v0))
Syntax.ExpressionParenthesized v0 -> Serialization.parens (expressionToExpr v0)
Syntax.ExpressionAsExpression v0 ->
let innerE = Syntax.asExpressionExpression v0
typ = Syntax.asExpressionType v0
in (Serialization.parens (Serialization.spaceSep [
expressionToExpr innerE,
(Serialization.cst "as"),
(Serialization.cst (tsTypeExpressionToString typ))]))
-- | Convert a for-in statement to an AST expression
forInStatementToExpr :: Syntax.ForInStatement -> Ast.Expr
forInStatementToExpr f =
let left = Syntax.forInStatementLeft f
right = Syntax.forInStatementRight f
body = Syntax.forInStatementBody f
leftExpr =
case left of
Syntax.ForInLeftVariable v0 -> variableDeclarationToExpr v0
Syntax.ForInLeftPattern v0 -> patternToExpr v0
in (Serialization.spaceSep [
Serialization.cst "for",
(Serialization.parens (Serialization.spaceSep [
leftExpr,
(Serialization.cst "in"),
(expressionToExpr right)])),
(statementToExpr body)])
-- | Convert a for-of statement to an AST expression
forOfStatementToExpr :: Syntax.ForOfStatement -> Ast.Expr
forOfStatementToExpr f =
let await = Syntax.forOfStatementAwait f
left = Syntax.forOfStatementLeft f
right = Syntax.forOfStatementRight f
body = Syntax.forOfStatementBody f
forKw = Logic.ifElse await (Serialization.cst "for await") (Serialization.cst "for")
leftExpr =
case left of
Syntax.ForInLeftVariable v0 -> variableDeclarationToExpr v0
Syntax.ForInLeftPattern v0 -> patternToExpr v0
in (Serialization.spaceSep [
forKw,
(Serialization.parens (Serialization.spaceSep [
leftExpr,
(Serialization.cst "of"),
(expressionToExpr right)])),
(statementToExpr body)])
-- | Convert a for statement to an AST expression
forStatementToExpr :: Syntax.ForStatement -> Ast.Expr
forStatementToExpr f =
let init = Syntax.forStatementInit f
test = Syntax.forStatementTest f
update = Syntax.forStatementUpdate f
body = Syntax.forStatementBody f
initExpr =
Optionals.cases init (Serialization.cst "") (\i -> case i of
Syntax.ForInitVariable v0 -> variableDeclarationToExpr v0
Syntax.ForInitExpression v0 -> expressionToExpr v0)
testExpr = Optionals.cases test (Serialization.cst "") expressionToExpr
updateExpr = Optionals.cases update (Serialization.cst "") expressionToExpr
in (Serialization.spaceSep [
Serialization.cst "for",
(Serialization.parenListAdaptive [
initExpr,
testExpr,
updateExpr]),
(statementToExpr body)])
-- | Format import specifiers, handling default vs named imports
formatImportSpecifiers :: [Ast.Expr] -> Ast.Expr
formatImportSpecifiers specs = Serialization.curlyBracesList Nothing Serialization.inlineStyle specs
-- | Convert a function declaration to an AST expression
functionDeclarationToExpr :: Syntax.FunctionDeclaration -> Ast.Expr
functionDeclarationToExpr fn =
let id = Syntax.functionDeclarationId fn
params = Syntax.functionDeclarationParams fn
body = Syntax.functionDeclarationBody fn
async = Syntax.functionDeclarationAsync fn
generator = Syntax.functionDeclarationGenerator fn
asyncKw = Logic.ifElse async [
Serialization.cst "async"] []
funcKw = Logic.ifElse generator (Serialization.cst "function*") (Serialization.cst "function")
paramsExpr = Serialization.parenListAdaptive (Lists.map patternToExpr params)
retAnnot = Serialization.cst ": any"
in (Serialization.spaceSep (Lists.concat [
asyncKw,
[
funcKw,
(identifierToExpr id),
paramsExpr,
retAnnot,
(blockStatementToExpr body)]]))
-- | Convert a function declaration with comments to an AST expression
functionDeclarationWithCommentsToExpr :: Syntax.FunctionDeclarationWithComments -> Ast.Expr
functionDeclarationWithCommentsToExpr fdwc =
let body = Syntax.functionDeclarationWithCommentsBody fdwc
mc = Syntax.functionDeclarationWithCommentsComments fdwc
in (Optionals.cases mc (functionDeclarationToExpr body) (\c -> Serialization.newlineSep [
documentationCommentToExpr c,
(functionDeclarationToExpr body)]))
-- | Convert a function expression to an AST expression
functionExpressionToExpr :: Syntax.FunctionExpression -> Ast.Expr
functionExpressionToExpr fn =
let mid = Syntax.functionExpressionId fn
params = Syntax.functionExpressionParams fn
body = Syntax.functionExpressionBody fn
async = Syntax.functionExpressionAsync fn
generator = Syntax.functionExpressionGenerator fn
asyncKw = Logic.ifElse async [
Serialization.cst "async"] []
funcKw = Logic.ifElse generator (Serialization.cst "function*") (Serialization.cst "function")
nameExpr = Optionals.cases mid [] (\id -> [
identifierToExpr id])
paramsExpr = Serialization.parenListAdaptive (Lists.map patternToExpr params)
in (Serialization.spaceSep (Lists.concat [
asyncKw,
[
funcKw],
nameExpr,
[
paramsExpr,
(blockStatementToExpr body)]]))
-- | Convert an identifier to an AST expression
identifierToExpr :: Syntax.Identifier -> Ast.Expr
identifierToExpr id = Serialization.cst (Syntax.unIdentifier id)
-- | Convert an if statement to an AST expression
ifStatementToExpr :: Syntax.IfStatement -> Ast.Expr
ifStatementToExpr ifStmt =
let test = Syntax.ifStatementTest ifStmt
consequent = Syntax.ifStatementConsequent ifStmt
alternate = Syntax.ifStatementAlternate ifStmt
ifPart =
Serialization.spaceSep [
Serialization.cst "if",
(Serialization.parens (expressionToExpr test)),
(statementToExpr consequent)]
in (Optionals.cases alternate ifPart (\alt -> Serialization.spaceSep [
ifPart,
(Serialization.cst "else"),
(statementToExpr alt)]))
-- | Convert an import declaration to an AST expression
importDeclarationToExpr :: Syntax.ImportDeclaration -> Ast.Expr
importDeclarationToExpr imp =
let specifiers = Syntax.importDeclarationSpecifiers imp
source = Syntax.importDeclarationSource imp
sourceExpr = stringLiteralToExpr source
specExprs = Lists.map importSpecifierToExpr specifiers
in (Logic.ifElse (Lists.null specifiers) (Serialization.suffix ";" (Serialization.spaceSep [
Serialization.cst "import",
sourceExpr])) (Serialization.suffix ";" (Serialization.spaceSep [
Serialization.cst "import",
(formatImportSpecifiers specExprs),
(Serialization.cst "from"),
sourceExpr])))
-- | Convert an import specifier to an AST expression
importSpecifierToExpr :: Syntax.ImportClause -> Ast.Expr
importSpecifierToExpr spec =
case spec of
Syntax.ImportClauseNamed v0 ->
let imported = Syntax.importSpecifierImported v0
local = Syntax.importSpecifierLocal v0
in (Logic.ifElse (Equality.equal (Syntax.unIdentifier imported) (Syntax.unIdentifier local)) (identifierToExpr local) (Serialization.spaceSep [
identifierToExpr imported,
(Serialization.cst "as"),
(identifierToExpr local)]))
Syntax.ImportClauseDefault v0 -> identifierToExpr (Syntax.unImportDefaultSpecifier v0)
Syntax.ImportClauseNamespace v0 -> Serialization.spaceSep [
Serialization.cst "*",
(Serialization.cst "as"),
(identifierToExpr (Syntax.unImportNamespaceSpecifier v0))]
-- | Detect a kernel-synthesized type-variable name like T0 or T12, which is unbound in inline type annotations
isKernelTypeVarName :: String -> Bool
isKernelTypeVarName s =
let cps = Strings.toList s
len = Lists.length cps
first = Optionals.withDefault 0 (Lists.head cps)
rest = Logic.ifElse (Ordering.gt len 0) (Lists.drop 1 cps) []
in (Logic.and (Ordering.gt len 1) (Logic.and (Equality.equal first 84) (allDigits rest)))
-- | Convert a labeled statement to an AST expression
labeledStatementToExpr :: Syntax.LabeledStatement -> Ast.Expr
labeledStatementToExpr l =
let label = Syntax.labeledStatementLabel l
body = Syntax.labeledStatementBody l
in (Serialization.spaceSep [
Serialization.suffix ":" (identifierToExpr label),
(statementToExpr body)])
-- | Convert a literal to an AST expression
literalToExpr :: Syntax.Literal -> Ast.Expr
literalToExpr lit =
case lit of
Syntax.LiteralString v0 -> stringLiteralToExpr v0
Syntax.LiteralNumber v0 -> numericLiteralToExpr v0
Syntax.LiteralBoolean v0 -> Serialization.cst (Logic.ifElse v0 "true" "false")
Syntax.LiteralNull -> Serialization.cst "null"
Syntax.LiteralUndefined -> Serialization.cst "undefined"
Syntax.LiteralBigInt v0 -> Serialization.cst (Strings.concat2 (Literals.showBigint v0) "n")
Syntax.LiteralTemplate v0 -> templateLiteralToExpr v0
-- | Convert a member expression to an AST expression
memberExpressionToExpr :: Syntax.MemberExpression -> Ast.Expr
memberExpressionToExpr mem =
let obj = Syntax.memberExpressionObject mem
prop = Syntax.memberExpressionProperty mem
computed = Syntax.memberExpressionComputed mem
optional = Syntax.memberExpressionOptional mem
objExpr =
case obj of
Syntax.ExpressionArrow _ -> Serialization.parens (expressionToExpr obj)
Syntax.ExpressionConditional _ -> Serialization.parens (expressionToExpr obj)
Syntax.ExpressionBinary _ -> Serialization.parens (expressionToExpr obj)
Syntax.ExpressionUnary _ -> Serialization.parens (expressionToExpr obj)
Syntax.ExpressionAssignment _ -> Serialization.parens (expressionToExpr obj)
Syntax.ExpressionSequence _ -> Serialization.parens (expressionToExpr obj)
Syntax.ExpressionObject _ -> Serialization.parens (expressionToExpr obj)
Syntax.ExpressionFunction _ -> Serialization.parens (expressionToExpr obj)
_ -> expressionToExpr obj
propExpr = expressionToExpr prop
in (Logic.ifElse computed (Serialization.spaceSep [
objExpr,
(Logic.ifElse optional (Serialization.cst "?.") (Serialization.cst "")),
(Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle propExpr)]) (Serialization.ifx (Logic.ifElse optional Operators.optionalChainOp Operators.memberOp) objExpr propExpr))
-- | Convert a method definition to an AST expression
methodDefinitionToExpr :: Syntax.MethodDefinition -> Ast.Expr
methodDefinitionToExpr method =
let key = Syntax.methodDefinitionKey method
value = Syntax.methodDefinitionValue method
kind = Syntax.methodDefinitionKind method
computed = Syntax.methodDefinitionComputed method
static = Syntax.methodDefinitionStatic method
staticKw = Logic.ifElse static [
Serialization.cst "static"] []
kindKw =
case kind of
Syntax.MethodKindConstructor -> []
Syntax.MethodKindMethod -> []
Syntax.MethodKindGet -> [
Serialization.cst "get"]
Syntax.MethodKindSet -> [
Serialization.cst "set"]
keyExpr =
Logic.ifElse computed (Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (expressionToExpr key)) (expressionToExpr key)
params = Syntax.functionExpressionParams value
body = Syntax.functionExpressionBody value
paramsExpr = Serialization.parenListAdaptive (Lists.map patternToExpr params)
in (Serialization.spaceSep (Lists.concat [
staticKw,
kindKw,
[
keyExpr,
paramsExpr,
(blockStatementToExpr body)]]))
-- | Convert a module item to an AST expression
moduleItemToExpr :: Syntax.ModuleItem -> Ast.Expr
moduleItemToExpr item =
case item of
Syntax.ModuleItemStatement v0 -> statementToExpr v0
Syntax.ModuleItemImport v0 -> importDeclarationToExpr v0
Syntax.ModuleItemExport v0 -> exportDeclarationToExpr v0
-- | Convert a module item with comments to an AST expression
moduleItemWithCommentsToExpr :: Syntax.ModuleItemWithComments -> Ast.Expr
moduleItemWithCommentsToExpr miwc =
let body = Syntax.moduleItemWithCommentsBody miwc
mc = Syntax.moduleItemWithCommentsComments miwc
in (Optionals.cases mc (moduleItemToExpr body) (\c -> Serialization.newlineSep [
documentationCommentToExpr c,
(moduleItemToExpr body)]))
-- | Convert a named export to an AST expression
namedExportToExpr :: Syntax.NamedExport -> Ast.Expr
namedExportToExpr n =
let specifiers = Syntax.namedExportSpecifiers n
source = Syntax.namedExportSource n
specExprs = Lists.map exportSpecifierToExpr specifiers
fromClause =
Optionals.cases source [] (\s -> [
Serialization.cst "from",
(stringLiteralToExpr s)])
in (Serialization.suffix ";" (Serialization.spaceSep (Lists.concat [
[
Serialization.cst "export"],
[
Serialization.curlyBracesList Nothing Serialization.inlineStyle specExprs],
fromClause])))
-- | Convert a numeric literal to an AST expression
numericLiteralToExpr :: Syntax.NumericLiteral -> Ast.Expr
numericLiteralToExpr n =
case n of
Syntax.NumericLiteralInteger v0 -> Serialization.cst (Literals.showInt64 v0)
Syntax.NumericLiteralFloat v0 -> Serialization.cst (Literals.showFloat64 v0)
-- | Convert an object expression to an AST expression
objectExpressionToExpr :: [Syntax.Property] -> Ast.Expr
objectExpressionToExpr obj =
Serialization.curlyBracesList Nothing Serialization.halfBlockStyle (Lists.map propertyToExpr obj)
-- | Convert an object pattern property to an AST expression
objectPatternPropertyToExpr :: Syntax.ObjectPatternProperty -> Ast.Expr
objectPatternPropertyToExpr prop =
case prop of
Syntax.ObjectPatternPropertyProperty v0 -> propertyToExpr v0
Syntax.ObjectPatternPropertyRest v0 -> Serialization.prefix "..." (patternToExpr (Syntax.unRestElement v0))
-- | Convert an object pattern to an AST expression
objectPatternToExpr :: Syntax.ObjectPattern -> Ast.Expr
objectPatternToExpr obj =
let props = Syntax.objectPatternProperties obj
in (Serialization.curlyBracesList Nothing Serialization.inlineStyle (Lists.map objectPatternPropertyToExpr props))
-- | Convert a pattern to an AST expression
patternToExpr :: Syntax.Pattern -> Ast.Expr
patternToExpr pat =
case pat of
Syntax.PatternIdentifier v0 -> identifierToExpr v0
Syntax.PatternObject v0 -> objectPatternToExpr v0
Syntax.PatternArray v0 -> arrayPatternToExpr v0
Syntax.PatternAssignment v0 -> assignmentPatternToExpr v0
Syntax.PatternRest v0 -> Serialization.prefix "..." (patternToExpr (Syntax.unRestElement v0))
Syntax.PatternTyped v0 -> typedPatternToExpr v0
-- | Render a TS.Pattern as a plain string
patternToString :: Syntax.Pattern -> String
patternToString pat =
case pat of
Syntax.PatternIdentifier v0 -> Syntax.unIdentifier v0
Syntax.PatternRest v0 -> Strings.concat2 "..." (patternToString (Syntax.unRestElement v0))
Syntax.PatternTyped v0 -> Strings.concat [
patternToString (Syntax.typedPatternPattern v0),
": ",
(tsTypeExpressionToString (Syntax.typedPatternType v0))]
_ -> "_"
-- | Convert a TypeScript program to an AST expression
programToExpr :: Syntax.Program -> Ast.Expr
programToExpr prog =
let body = Syntax.programBody prog
warning = [
Serialization.cst (toLineComment Constants.warningAutoGeneratedFile)]
items = Lists.map moduleItemToExpr body
in (Serialization.doubleNewlineSep (Lists.concat [
warning,
items]))
-- | Convert an object property to an AST expression
propertyToExpr :: Syntax.Property -> Ast.Expr
propertyToExpr prop =
let key = Syntax.propertyKey prop
value = Syntax.propertyValue prop
shorthand = Syntax.propertyShorthand prop
computed = Syntax.propertyComputed prop
keyExpr =
Logic.ifElse computed (Serialization.brackets Serialization.squareBrackets Serialization.inlineStyle (expressionToExpr key)) (expressionToExpr key)
in (Logic.ifElse shorthand keyExpr (Serialization.ifx Operators.colonOp keyExpr (expressionToExpr value)))
-- | Convert a return statement to an AST expression
returnStatementToExpr :: Maybe Syntax.Expression -> Ast.Expr
returnStatementToExpr r =
Optionals.cases r (Serialization.cst "return;") (\e -> Serialization.suffix ";" (Serialization.spaceSep [
Serialization.cst "return",
(expressionToExpr e)]))
-- | Convert a statement to an AST expression
statementToExpr :: Syntax.Statement -> Ast.Expr
statementToExpr stmt =
case stmt of
Syntax.StatementExpression v0 -> Serialization.suffix ";" (expressionToExpr v0)
Syntax.StatementBlock v0 -> blockStatementToExpr v0
Syntax.StatementEmpty -> Serialization.cst ";"
Syntax.StatementDebugger -> Serialization.cst "debugger;"
Syntax.StatementReturn v0 -> returnStatementToExpr v0
Syntax.StatementBreak v0 -> breakStatementToExpr v0
Syntax.StatementContinue v0 -> continueStatementToExpr v0
Syntax.StatementIf v0 -> ifStatementToExpr v0
Syntax.StatementSwitch v0 -> switchStatementToExpr v0
Syntax.StatementThrow v0 -> throwStatementToExpr v0
Syntax.StatementTry v0 -> tryStatementToExpr v0
Syntax.StatementWhile v0 -> whileStatementToExpr v0
Syntax.StatementDoWhile v0 -> doWhileStatementToExpr v0
Syntax.StatementFor v0 -> forStatementToExpr v0
Syntax.StatementForIn v0 -> forInStatementToExpr v0
Syntax.StatementForOf v0 -> forOfStatementToExpr v0
Syntax.StatementVariableDeclaration v0 -> variableDeclarationToExpr v0
Syntax.StatementFunctionDeclaration v0 -> functionDeclarationToExpr v0
Syntax.StatementClassDeclaration v0 -> classDeclarationToExpr v0
Syntax.StatementLabeled v0 -> labeledStatementToExpr v0
-- | Convert a string literal to an AST expression
stringLiteralToExpr :: Syntax.StringLiteral -> Ast.Expr
stringLiteralToExpr s =
let value = Syntax.stringLiteralValue s
singleQuote = Syntax.stringLiteralSingleQuote s
quote = Logic.ifElse singleQuote "'" "\""
escaped = escapeString value singleQuote
in (Serialization.cst (Strings.concat [
quote,
escaped,
quote]))
-- | Convert a switch case to an AST expression
switchCaseToExpr :: Syntax.SwitchCase -> Ast.Expr
switchCaseToExpr c =
let test = Syntax.switchCaseTest c
consequent = Syntax.switchCaseConsequent c
caseLabel =
Optionals.cases test (Serialization.cst "default:") (\t -> Serialization.spaceSep [
Serialization.cst "case",
(expressionToExpr t),
(Serialization.cst ":")])
in (Serialization.newlineSep (Lists.cons caseLabel (Lists.map statementToExpr consequent)))
-- | Convert a switch statement to an AST expression
switchStatementToExpr :: Syntax.SwitchStatement -> Ast.Expr
switchStatementToExpr switchStmt =
let discriminant = Syntax.switchStatementDiscriminant switchStmt
cases = Syntax.switchStatementCases switchStmt
in (Serialization.spaceSep [
Serialization.cst "switch",
(Serialization.parens (expressionToExpr discriminant)),
(Serialization.curlyBlock Serialization.fullBlockStyle (Serialization.newlineSep (Lists.map switchCaseToExpr cases)))])
-- | Convert a template literal to an AST expression
templateLiteralToExpr :: Syntax.TemplateLiteral -> Ast.Expr
templateLiteralToExpr t =
let quasis = Syntax.templateLiteralQuasis t
exprs = Syntax.templateLiteralExpressions t
in (Serialization.cst (Strings.concat [
"`",
(Strings.join "" (Lists.map (\q -> Syntax.templateElementValue q) quasis)),
"`"]))
-- | Convert a throw statement to an AST expression
throwStatementToExpr :: Syntax.ThrowStatement -> Ast.Expr
throwStatementToExpr t =
Serialization.suffix ";" (Serialization.spaceSep [
Serialization.cst "throw",
(expressionToExpr (Syntax.unThrowStatement t))])
-- | Convert a string to a TypeScript line comment. Empty source lines emit `//` (no trailing space).
toLineComment :: String -> String
toLineComment s =
Strings.join "\n" (Lists.map (\line -> Logic.ifElse (Equality.equal line "") "//" (Strings.concat2 "// " line)) (Strings.lines s))
-- | Format a description and tags as a JSDoc comment. Empty doc lines emit ` *` (no trailing space) so blank lines don't carry trailing whitespace.
toTypeScriptComments :: String -> [Syntax.DocumentationTag] -> String
toTypeScriptComments desc tags =
let descLines =
Logic.ifElse (Equality.equal desc "") [] (Lists.map (\line -> Logic.ifElse (Equality.equal line "") " *" (Strings.concat2 " * " line)) (Strings.lines desc))
tagLines = Lists.map documentationTagToLine tags
allLines =
Lists.concat [
descLines,
tagLines]
in (Logic.ifElse (Lists.null allLines) "" (Strings.join "\n" (Lists.concat [
[
"/**"],
allLines,
[
" */"]])))
-- | Convert a try statement to an AST expression
tryStatementToExpr :: Syntax.TryStatement -> Ast.Expr
tryStatementToExpr t =
let block = Syntax.tryStatementBlock t
handler = Syntax.tryStatementHandler t
finalizer = Syntax.tryStatementFinalizer t
tryPart =
Serialization.spaceSep [
Serialization.cst "try",
(blockStatementToExpr block)]
catchPart = Optionals.cases handler [] (\c -> [
catchClauseToExpr c])
finallyPart =
Optionals.cases finalizer [] (\f -> [
Serialization.spaceSep [
Serialization.cst "finally",
(blockStatementToExpr f)]])
in (Serialization.spaceSep (Lists.concat [
[
tryPart],
catchPart,
finallyPart]))
-- | Render a TypeScript type expression as a string in TS syntax
tsTypeExpressionToString :: Syntax.TypeExpression -> String
tsTypeExpressionToString t =
case t of
Syntax.TypeExpressionIdentifier v0 ->
let raw = Syntax.unIdentifier v0
in (Logic.ifElse (isKernelTypeVarName raw) "any" raw)
Syntax.TypeExpressionAny -> "any"
Syntax.TypeExpressionVoid -> "void"
Syntax.TypeExpressionNever -> "never"
Syntax.TypeExpressionArray v0 -> Strings.concat [
"ReadonlyArray<",
(tsTypeExpressionToString (Syntax.unArrayTypeExpression v0)),
">"]
Syntax.TypeExpressionTuple v0 -> Strings.concat [
"readonly [",
(Strings.join ", " (Lists.map tsTypeExpressionToString v0)),
"]"]
Syntax.TypeExpressionUnion v0 -> Strings.join " | " (Lists.map tsTypeExpressionToString v0)
Syntax.TypeExpressionIntersection v0 -> Strings.join " & " (Lists.map tsTypeExpressionToString v0)
Syntax.TypeExpressionParameterized v0 -> Strings.concat [
tsTypeExpressionToString (Syntax.parameterizedTypeExpressionBase v0),
"<",
(Strings.join ", " (Lists.map tsTypeExpressionToString (Syntax.parameterizedTypeExpressionArguments v0))),
">"]
Syntax.TypeExpressionOptional v0 -> Strings.concat [
tsTypeExpressionToString v0,
" | undefined"]
Syntax.TypeExpressionReadonly v0 -> Strings.concat2 "readonly " (tsTypeExpressionToString v0)
Syntax.TypeExpressionUnknown -> "unknown"
Syntax.TypeExpressionFunction _ -> "((...args: any[]) => any)"
_ -> "unknown"
-- | Convert a type expression to a string for JSDoc
typeExpressionToString :: Syntax.TypeExpression -> String
typeExpressionToString typ =
case typ of
Syntax.TypeExpressionIdentifier v0 -> Syntax.unIdentifier v0
Syntax.TypeExpressionAny -> "*"
Syntax.TypeExpressionVoid -> "void"
Syntax.TypeExpressionNever -> "never"
Syntax.TypeExpressionLiteral _ -> "literal"
Syntax.TypeExpressionArray v0 -> Strings.concat2 (typeExpressionToString (Syntax.unArrayTypeExpression v0)) "[]"
Syntax.TypeExpressionFunction v0 ->
let params = Syntax.functionTypeExpressionParameters v0
rt = Syntax.functionTypeExpressionReturnType v0
rendered =
Pairs.second (Lists.foldl (\acc -> \p ->
let i = Pairs.first acc
soFar = Pairs.second acc
this =
Strings.concat [
"_a",
(Literals.showInt32 i),
": ",
(typeExpressionToString p)]
in (Math.add i 1, (Lists.concat2 soFar (Lists.pure this)))) (0, []) params)
in (Strings.concat [
"(",
(Strings.join ", " rendered),
") => ",
(typeExpressionToString rt)])
Syntax.TypeExpressionObject _ -> "Object"
Syntax.TypeExpressionUnion v0 -> Strings.join "|" (Lists.map typeExpressionToString v0)
Syntax.TypeExpressionParameterized v0 ->
let base = Syntax.parameterizedTypeExpressionBase v0
args = Syntax.parameterizedTypeExpressionArguments v0
in (Strings.concat [
typeExpressionToString base,
"<",
(Strings.join ", " (Lists.map typeExpressionToString args)),
">"])
Syntax.TypeExpressionOptional v0 -> Strings.concat2 "?" (typeExpressionToString v0)
-- | Render `<pattern>: <type>` (TypeScript parameter / variable type annotation)
typedPatternToExpr :: Syntax.TypedPattern -> Ast.Expr
typedPatternToExpr tp =
let innerPat = Syntax.typedPatternPattern tp
typ = Syntax.typedPatternType tp
innerStr = patternToString innerPat
typeStr = tsTypeExpressionToString typ
in (Serialization.cst (Strings.concat [
innerStr,
": ",
typeStr]))
-- | Convert a unary expression to an AST expression
unaryExpressionToExpr :: Syntax.UnaryExpression -> Ast.Expr
unaryExpressionToExpr un =
let op = Syntax.unaryExpressionOperator un
arg = Syntax.unaryExpressionArgument un
prefix = Syntax.unaryExpressionPrefix un
opStr = unaryOperatorToString op
argExpr = expressionToExpr arg
in (Logic.ifElse prefix (Serialization.prefix opStr argExpr) (Serialization.suffix opStr argExpr))
-- | Convert a unary operator to a string
unaryOperatorToString :: Syntax.UnaryOperator -> String
unaryOperatorToString op =
case op of
Syntax.UnaryOperatorNegate -> "-"
Syntax.UnaryOperatorPlus -> "+"
Syntax.UnaryOperatorNot -> "!"
Syntax.UnaryOperatorBitwiseNot -> "~"
Syntax.UnaryOperatorTypeof -> "typeof "
Syntax.UnaryOperatorVoid -> "void "
Syntax.UnaryOperatorDelete -> "delete "
Syntax.UnaryOperatorIncrement -> "++"
Syntax.UnaryOperatorDecrement -> "--"
-- | Convert a variable declaration to an AST expression
variableDeclarationToExpr :: Syntax.VariableDeclaration -> Ast.Expr
variableDeclarationToExpr decl =
let kind = Syntax.variableDeclarationKind decl
declarations = Syntax.variableDeclarationDeclarations decl
in (Serialization.suffix ";" (Serialization.spaceSep [
variableKindToExpr kind,
(Serialization.commaSep Serialization.inlineStyle (Lists.map variableDeclaratorToExpr declarations))]))
-- | Convert a variable declarator to an AST expression
variableDeclaratorToExpr :: Syntax.VariableDeclarator -> Ast.Expr
variableDeclaratorToExpr decl =
let id = Syntax.variableDeclaratorId decl
init = Syntax.variableDeclaratorInit decl
in (Optionals.cases init (patternToExpr id) (\e -> Serialization.ifx Operators.defineOp (patternToExpr id) (expressionToExpr e)))
-- | Convert a variable kind to an AST expression
variableKindToExpr :: Syntax.VariableKind -> Ast.Expr
variableKindToExpr kind =
case kind of
Syntax.VariableKindVar -> Serialization.cst "var"
Syntax.VariableKindLet -> Serialization.cst "let"
Syntax.VariableKindConst -> Serialization.cst "const"
-- | Convert a while statement to an AST expression
whileStatementToExpr :: Syntax.WhileStatement -> Ast.Expr
whileStatementToExpr w =
let test = Syntax.whileStatementTest w
body = Syntax.whileStatementBody w
in (Serialization.spaceSep [
Serialization.cst "while",
(Serialization.parens (expressionToExpr test)),
(statementToExpr body)])