Skip to content

File stdioFeature.h

File List > features > stdioFeature.h

Go to the documentation of this file

#pragma once

#include <jac/machine/functionFactory.h>
#include <jac/machine/machine.h>
#include <jac/machine/values.h>

#include <memory>
#include <string>

#include "types/streams.h"

namespace jac {


template<class Next>
class StdioFeature : public Next {
private:
    class Stdio {
    public:
        std::unique_ptr<Writable> out;
        std::unique_ptr<Writable> err;
        std::unique_ptr<Readable> in;
    };

    static std::string joinArgs(ValueVectorWeak args) {
        std::string line;
        for (std::size_t i = 0; i < args.size(); ++i) {
            if (i != 0) {
                line += ' ';
            }
            line += args[i].isString() ? args[i].to<std::string>() : args[i].inspect();
        }
        return line;
    }
public:
    Stdio stdio;

    void initialize() {
        Next::initialize();

        FunctionFactory ff(this->context());

        if (!this->stdio.out) {
            throw std::runtime_error("StdioFeature: stdio.out is not set");
        }
        if (!this->stdio.err) {
            throw std::runtime_error("StdioFeature: stdio.err is not set");
        }

        Object console = Object::create(this->context());
        console.set("debug", ff.newFunctionVariadic([this](ValueVectorWeak args) {
            this->stdio.out->write(joinArgs(args) + "\n");
        }));
        console.set("log", ff.newFunctionVariadic([this](ValueVectorWeak args) {
            this->stdio.out->write(joinArgs(args) + "\n");
        }));
        console.set("info", ff.newFunctionVariadic([this](ValueVectorWeak args) {
            this->stdio.out->write(joinArgs(args) + "\n");
        }));
        console.set("warn", ff.newFunctionVariadic([this](ValueVectorWeak args) {
            this->stdio.err->write(joinArgs(args) + "\n");
        }));
        console.set("error", ff.newFunctionVariadic([this](ValueVectorWeak args) {
            this->stdio.err->write(joinArgs(args) + "\n");
        }));
        Object global = this->context().getGlobalObject();
        global.defineProperty("console", console);

        this->newModule("stdio", [this](Module& mdl) {
            mdl.addExport("stdout", Next::WritableClass::createInstance(this->context(), new WritableRef(stdio.out.get())));
            mdl.addExport("stderr", Next::WritableClass::createInstance(this->context(), new WritableRef(stdio.err.get())));
            if (stdio.in) {
                mdl.addExport("stdin", Next::ReadableClass::createInstance(this->context(), new ReadableRef(stdio.in.get())));
            }
        });
    }
};


} // namespace jac