diff --git a/Makefile b/Makefile index 0273ff3..646a4ff 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ Obj= \ context.o \ environment.o \ errors.o \ + format.o \ interpreter.o \ lexer.o \ lines.o \ diff --git a/include/musique.hh b/include/musique.hh index 9aa1ac8..97499f8 100644 --- a/include/musique.hh +++ b/include/musique.hh @@ -6,9 +6,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -784,7 +784,7 @@ struct Block Result operator()(Interpreter &i, std::vector params); /// Indexing block - Result index(Interpreter &i, unsigned position); + Result index(Interpreter &i, unsigned position) const; /// Count of elements in block usize size() const; @@ -845,7 +845,7 @@ struct Array std::vector elements; /// Index element of an array - Result index(Interpreter &i, unsigned position); + Result index(Interpreter &i, unsigned position) const; /// Count of elements usize size() const; @@ -923,7 +923,7 @@ struct Value Result operator()(Interpreter &i, std::vector args); /// Index contained value if it can be called - Result index(Interpreter &i, unsigned position); + Result index(Interpreter &i, unsigned position) const; /// Return elements count of contained value if it can be measured usize size() const; @@ -1137,4 +1137,22 @@ template<> struct std::hash { std::size_t operator()(Ast const&) cons template<> struct std::hash { std::size_t operator()(Number const&) const; }; template<> struct std::hash { std::size_t operator()(Value const&) const; }; +struct Value_Formatter +{ + enum Context + { + Free, + Inside_Block + }; + + Context context = Free; + unsigned indent = 0; + + Value_Formatter nest(Context nested = Free) const; + + Result format(std::ostream& os, Interpreter &interpreter, Value const& value); +}; + +Result format(Interpreter &i, Value const& value); + #endif diff --git a/src/format.cc b/src/format.cc new file mode 100644 index 0000000..4af2118 --- /dev/null +++ b/src/format.cc @@ -0,0 +1,70 @@ +#include +#include + +Result format(Interpreter &i, Value const& value) +{ + std::stringstream ss; + Try(Value_Formatter{}.format(ss, i, value)); + return ss.str(); +} + +Value_Formatter Value_Formatter::nest(Context nested) const +{ + return Value_Formatter { .context = nested, .indent = indent + 2 }; +} + +std::optional Value_Formatter::format(std::ostream& os, Interpreter &interpreter, Value const& value) +{ + switch (value.type) { + break; case Value::Type::Nil: + os << "nil"; + + break; case Value::Type::Symbol: + os << value.s; + + break; case Value::Type::Bool: + os << std::boolalpha << value.b; + + break; case Value::Type::Number: + if (auto n = value.n.simplify(); n.den == 1) { + os << n.num << '/' << n.den; + } else { + os << n.num; + } + + break; case Value::Type::Intrinsic: + for (auto const& [key, val] : Env::global->variables) { + if (val.type == Value::Type::Intrinsic && val.intr == value.intr) { + os << ""; + return {}; + } + } + os << ""; + + + break; case Value::Type::Array: + os << '['; + for (auto i = 0u; i < value.array.elements.size(); ++i) { + if (i > 0) { + os << "; "; + } + Try(nest(Inside_Block).format(os, interpreter, value.array.elements[i])); + } + os << ']'; + + break; case Value::Type::Block: + os << '['; + for (auto i = 0u; i < value.blk.size(); ++i) { + if (i > 0) { + os << "; "; + } + Try(nest(Inside_Block).format(os, interpreter, Try(value.index(interpreter, i)))); + } + os << ']'; + + break; case Value::Type::Music: + os << value.chord; + } + + return {}; +} diff --git a/src/main.cc b/src/main.cc index 9b3409c..0fdb772 100644 --- a/src/main.cc +++ b/src/main.cc @@ -126,9 +126,9 @@ struct Runner midi_input_event_loop.detach(); } - Env::global->force_define("say", +[](Interpreter&, std::vector args) -> Result { + Env::global->force_define("say", +[](Interpreter &interpreter, std::vector args) -> Result { for (auto it = args.begin(); it != args.end(); ++it) { - std::cout << *it; + Try(format(interpreter, *it)); if (std::next(it) != args.end()) std::cout << ' '; } @@ -162,7 +162,7 @@ struct Runner return {}; } if (auto result = Try(interpreter.eval(std::move(ast))); output && result.type != Value::Type::Nil) { - std::cout << result << std::endl; + std::cout << Try(format(interpreter, result)) << std::endl; } return {}; } diff --git a/src/value.cc b/src/value.cc index 2923903..57477bc 100644 --- a/src/value.cc +++ b/src/value.cc @@ -169,7 +169,7 @@ Result Value::operator()(Interpreter &i, std::vector args) } } -Result Value::index(Interpreter &i, unsigned position) +Result Value::index(Interpreter &i, unsigned position) const { switch (type) { case Type::Block: @@ -361,7 +361,7 @@ static inline Result guard_index(unsigned index, unsigned size) } // TODO Add memoization -Result Block::index(Interpreter &i, unsigned position) +Result Block::index(Interpreter &i, unsigned position) const { assert(parameters.size() == 0, "cannot index into block with parameters (for now)"); if (body.type != Ast::Type::Sequence) { @@ -378,7 +378,7 @@ usize Block::size() const return body.type == Ast::Type::Sequence ? body.arguments.size() : 1; } -Result Array::index(Interpreter &, unsigned position) +Result Array::index(Interpreter &, unsigned position) const { Try(guard_index(position, elements.size())); return elements[position];