"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const traverse_1 = require("@glas/traverse");
const ast_1 = require("../ast");
const common_1 = require("../common");
const toCodeString_1 = __importDefault(require("../toCodeString"));
function semanticAnalysis(root, options) {
    return traverse_1.traverse(root, {
        enter(node, ancestors) {
            if (ast_1.VariableDeclaration.is(node)) {
                let container = ancestors[ancestors.length - 2];
                if (node.static && !ast_1.ClassDeclaration.is(container)) {
                    throw common_1.SemanticError("Static modifier only valid within class", node.static);
                }
                let parent = ancestors[ancestors.length - 1];
                if (node.kind !== "var" && !ast_1.ClassDeclaration.is(parent) && node.value == null) {
                    throw common_1.SemanticError("Variable must be initialized", node);
                }
            }
            if (ast_1.ClassDeclaration.is(node)) {
                if (!node.isData && node.baseClasses.length > 1) {
                    throw common_1.SemanticError("Only data classes support multiple inheritance", node.baseClasses[1]);
                }
            }
            if (ast_1.ElementExpression.is(node)) {
                if (node.close != null && toCodeString_1.default(node.kind) !== toCodeString_1.default(node.close)) {
                    throw common_1.SemanticError("Closing element does not match opening element", node.close);
                }
            }
            if (ast_1.YieldExpression.is(node)) {
                let func = ancestors.find(ast_1.FunctionExpression.is);
                if (func.bind) {
                    throw common_1.SemanticError("Cannot 'yield' from bound functions (=>) use normal functions (->)", node);
                }
                if (!func.generator) {
                    throw common_1.SemanticError("Can only 'yield' from generator functions. Add a * before the function parameters or name: *() -> ", node);
                }
            }
        },
        leave(node) {
            if (ast_1.ClassDeclaration.is(node) && node.export >= 2) {
                let { location } = node.id;
                return traverse_1.replace(node.patch({ export: 0 }), new ast_1.VariableDeclaration({
                    location,
                    id: new ast_1.Declarator({ location, name: "default" }),
                    kind: "let",
                    export: 2,
                    value: new ast_1.Reference(node.id)
                }));
            }
            if (ast_1.BinaryExpression.is(node)) {
                let { location } = node;
                if (node.operator === "isnt") {
                    return new ast_1.UnaryExpression({
                        location,
                        operator: "!",
                        prefix: true,
                        argument: node.patch({ operator: "is" }),
                    });
                }
            }
        }
    });
}
exports.default = semanticAnalysis;
