function compileAST()

in packages/core/nano/src/compiler.ts [119:176]


function compileAST(gensym: () => number, scope: Record<string, string>, f: ExpressionNode<string>): string {
    switch (f.kind) {
        case NodeKind.Literal:
            return simpleSink.lit(f.value);

        case NodeKind.Ident:
            if (scope[f.value] !== undefined) {
                return scope[f.value];
            }
            return simpleSink.ident(f.value, undefined, /* fieldAccess */ false);

        case NodeKind.Paren:
            return simpleSink.paren(compileAST(gensym, scope, f.value));

        case NodeKind.Fun:
            const children = f.children;
            assert(children.length > 0);
            const name = `$args${gensym()}`;
            const freshScope = { ...scope };
            for (let i = 0; i < children.length - 1; i += 1) {
                const ident = children[i];
                if (ident.kind === NodeKind.Ident) {
                    freshScope[ident.value] = `${name}[${i}]`;
                    continue;
                }
                return assertNever(ident as never, "FUN arg should be ident");
            }
            const body = compileAST(gensym, freshScope, children[children.length - 1]);
            return `function(ef, origin, ${name}){return ${name}.length>=${children.length - 1}?${body}:err.functionArity;}`;

        case NodeKind.App:
            const head = compileAST(gensym, scope, f.children[0]);
            const args = f.children.slice(1).map(child => compileAST(gensym, scope, child));
            return simpleSink.app(head, args);

        case NodeKind.Conditional:
            return outputConditional(f.children.map(child => compileAST(gensym, scope, child)));

        case NodeKind.Dot:
            if (f.operand2.kind === NodeKind.Ident) {
                return simpleSink.dot(compileAST(gensym, scope, f.operand1), JSON.stringify(f.operand2.value));
            }
            return assertNever(f.operand2.kind as never, "DOT field should be ident");

        case NodeKind.BinaryOp:
            return simpleSink.binOp(
                f.op,
                compileAST(gensym, scope, f.operand1),
                compileAST(gensym, scope, f.operand2)
            );

        case NodeKind.UnaryOp:
            return simpleSink.unaryOp(f.op, compileAST(gensym, scope, f.operand1));

        default:
            return assertNever(f as never, "Missing should not be compiled");
    }
}