"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const ast = __importStar(require("./ast"));
const common_1 = require("./common");
const codeToString = {
    Identifier(node) {
        return node.name;
    },
    Declarator(node) {
        return node.name;
    },
    Reference(node) {
        var _a;
        return (_a = node.path) !== null && _a !== void 0 ? _a : node.name;
    },
    TypeExpression(node) {
        return s(node.value);
    },
    DotExpression(node) {
        return ".";
    },
    ThisExpression(node) {
        return "this";
    },
    AssignmentPattern(node) {
        return `${toCodeString(node.left)} = ${toCodeString(node.right)}`;
    },
    ObjectPattern(node) {
        return `{ ${node.properties.map(toCodeString).join(', ')} }`;
    },
    ObjectExpression(node) {
        return `{ ${node.properties.map(toCodeString).join(', ')} }`;
    },
    ArrayExpression(node) {
        return `[ ${node.elements.map(toCodeString).join(', ')} ]`;
    },
    Program(node) {
        return `program ${node.id.name}`;
    },
    FunctionExpression(node) {
        var _a, _b;
        return `function ${(_b = (_a = node.id) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : ''}(${node.params.map(toCodeString).join(',')})`;
    },
    ArrowFunctionExpression(node) {
        return `(${node.params.map(toCodeString).join(',')}) => {?}`;
    },
    FunctionType(node) {
        return `${node.async ? "async " : ""}(${node.params.map(toCodeString).join(',')}) => ${toCodeString(node.returnType)}`;
    },
    ClassDeclaration(node) {
        return `class ${node.id.name}`;
    },
    Property(node) {
        if (node.key != null) {
            if (ast.Identifier.is(node.key)) {
                return `${s(node.key)}:${s(node.value)}`;
            }
            else {
                return `[${s(node.key)}]:${s(node.value)}`;
            }
        }
        return `${s(node.value)}`;
    },
    Parameter(node) {
        let value = s(node.id);
        if (node.type) {
            value += `: ${s(node.type)}`;
        }
        if (node.value) {
            value += ` = ${s(node.value)}`;
        }
        return `${value}`;
    },
    Literal(node) {
        return JSON.stringify(node.value);
    },
    BinaryExpression(node) {
        return `(${s(node.left)} ${node.operator} ${s(node.right)})`;
    },
    UnaryExpression(node) {
        return `${node.operator}${s(node.argument)}`;
    },
    MemberExpression(node) {
        if (ast.Identifier.is(node.property)) {
            return `${s(node.object)}.${s(node.property)}`;
        }
        else {
            return `${s(node.object)}[${s(node.property)}]`;
        }
    },
    CallExpression(node) {
        return `${s(node.callee)}(${node.arguments.map(s).join(', ')})`;
    },
    VariableDeclaration(node) {
        return node.kind + " " + codeToString.Parameter(node);
    },
    IfStatement(node) {
        let result = `(if ${s(node.test)} then ${s(node.consequent)}`;
        if (node.alternate) {
            result += ` else ${s(node.alternate)} end`;
        }
        else {
            result += ` end)`;
        }
        return result;
    },
    BlockStatement(node) {
        return `{ ${node.body.map(s).join('; ')} }`;
    },
    ReturnStatement(node) {
        return `return ${toCodeString(node.argument)}`;
    },
    SpreadElement(node) {
        return `...${toCodeString(node.argument)}`;
    },
    RestElement(node) {
        return `...${toCodeString(node.argument)}`;
    },
    RegularExpression(node) {
        return `/${node.pattern}/${node.flags}`;
    }
};
const s = common_1.memoize(function (node) {
    let fn = codeToString[node.constructor.name];
    if (fn == null) {
        throw new Error(`codeToString function not found for type: ${node.constructor.name}`);
    }
    return fn(node);
});
function toCodeString(node) {
    if (node == null) {
        return "null";
    }
    return s(node);
}
exports.default = toCodeString;
