Major documentation of source code improvement

This commit is contained in:
Robert Bendun 2022-05-29 02:28:51 +02:00
parent 563786312c
commit dc1322e4ea
3 changed files with 245 additions and 116 deletions

View File

@ -952,7 +952,7 @@ RECURSIVE = YES
# Note that relative paths are relative to the directory from which doxygen is # Note that relative paths are relative to the directory from which doxygen is
# run. # run.
EXCLUDE = tests EXCLUDE = tests src/main.cc
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded # directories that are symbolic links (a Unix file system feature) are excluded

View File

@ -17,6 +17,7 @@ static bool enable_repl = false;
#define Ignore(Call) do { auto const ignore_ ## __LINE__ = (Call); (void) ignore_ ## __LINE__; } while(0) #define Ignore(Call) do { auto const ignore_ ## __LINE__ = (Call); (void) ignore_ ## __LINE__; } while(0)
/// Pop string from front of an array
static std::string_view pop(std::span<char const*> &span) static std::string_view pop(std::span<char const*> &span)
{ {
auto element = span.front(); auto element = span.front();
@ -24,8 +25,8 @@ static std::string_view pop(std::span<char const*> &span)
return element; return element;
} }
[[noreturn]] /// Print usage and exit
void usage() [[noreturn]] void usage()
{ {
std::cerr << std::cerr <<
"usage: musique <options> [filename]\n" "usage: musique <options> [filename]\n"
@ -42,6 +43,7 @@ void usage()
std::exit(1); std::exit(1);
} }
/// Trim spaces from left an right
static void trim(std::string_view &s) static void trim(std::string_view &s)
{ {
// left trim // left trim
@ -61,11 +63,13 @@ static void trim(std::string_view &s)
} }
} }
/// Runs interpreter on given source code
struct Runner struct Runner
{ {
midi::ALSA alsa; midi::ALSA alsa;
Interpreter interpreter; Interpreter interpreter;
/// Setup interpreter and midi connection with given port
Runner(std::string port) Runner(std::string port)
: alsa("musique") : alsa("musique")
{ {
@ -84,6 +88,7 @@ struct Runner
}); });
} }
/// Run given source
Result<void> run(std::string_view source, std::string_view filename) Result<void> run(std::string_view source, std::string_view filename)
{ {
auto ast = Try(Parser::parse(source, filename)); auto ast = Try(Parser::parse(source, filename));
@ -99,17 +104,20 @@ struct Runner
} }
}; };
// We make sure that through life of interpreter source code is allways allocated /// All source code through life of the program should stay allocated, since
/// some of the strings are only views into source
std::vector<std::string> eternal_sources; std::vector<std::string> eternal_sources;
/// Fancy main that supports Result forwarding on error (Try macro)
static Result<void> Main(std::span<char const*> args)
{
/// Describes all arguments that will be run
struct Run struct Run
{ {
bool is_file = true; bool is_file = true;
std::string_view argument; std::string_view argument;
}; };
static Result<void> Main(std::span<char const*> args)
{
std::vector<Run> runnables; std::vector<Run> runnables;
while (not args.empty()) { while (not args.empty()) {

View File

@ -39,8 +39,10 @@ using i64 = std::int64_t;
using usize = std::size_t; using usize = std::size_t;
using isize = std::ptrdiff_t; using isize = std::ptrdiff_t;
// Error handling mechanism inspired by Andrew Kelly approach, that was implemented /// Error handling related functions and definitions
// as first class feature in Zig programming language. ///
/// Error handling mechanism inspired by Andrew Kelly approach, that was implemented
/// as first class feature in Zig programming language.
namespace errors namespace errors
{ {
enum Type enum Type
@ -100,12 +102,13 @@ struct Location
std::ostream& operator<<(std::ostream& os, Location const& location); std::ostream& operator<<(std::ostream& os, Location const& location);
/// Guards that program exits if condition does not hold
void assert(bool condition, std::string message, Location loc = Location::caller()); void assert(bool condition, std::string message, Location loc = Location::caller());
// Marks part of code that was not implemented yet /// Marks part of code that was not implemented yet
[[noreturn]] void unimplemented(std::string_view message = {}, Location loc = Location::caller()); [[noreturn]] void unimplemented(std::string_view message = {}, Location loc = Location::caller());
// Marks location that should not be reached /// Marks location that should not be reached
[[noreturn]] void unreachable(Location loc = Location::caller()); [[noreturn]] void unreachable(Location loc = Location::caller());
struct Error struct Error
@ -189,10 +192,11 @@ struct [[nodiscard("This value may contain critical error, so it should NOT be i
using Storage::and_then; using Storage::and_then;
}; };
// NOTE This implementation requires C++ language extension: statement expressions /// Shorthand for forwarding error values with Result type family.
// It's supported by GCC and Clang, other compilers i don't know ///
// /// This implementation requires C++ language extension: statement expressions
// Inspired by SerenityOS TRY macro /// It's supported by GCC and Clang, other compilers i don't know.
/// Inspired by SerenityOS TRY macro
#define Try(Value) \ #define Try(Value) \
({ \ ({ \
auto try_value = (Value); \ auto try_value = (Value); \
@ -218,6 +222,7 @@ struct Explicit_Bool
} }
}; };
/// All unicode related operations
namespace unicode namespace unicode
{ {
inline namespace special_runes inline namespace special_runes
@ -227,29 +232,32 @@ namespace unicode
[[maybe_unused]] constexpr u32 Max_Bytes = 4; [[maybe_unused]] constexpr u32 Max_Bytes = 4;
} }
// is_digit returns true if `digit` is ASCII digit /// is_digit returns true if `digit` is ASCII digit
bool is_digit(u32 digit); bool is_digit(u32 digit);
// is_space return true if `space` is ASCII blank character /// is_space return true if `space` is ASCII blank character
bool is_space(u32 space); bool is_space(u32 space);
// is_letter returns true if `letter` is considered a letter by Unicode /// is_letter returns true if `letter` is considered a letter by Unicode
bool is_letter(u32 letter); bool is_letter(u32 letter);
// is_identifier returns true if `letter` is valid character for identifier. /// is_identifier returns true if `letter` is valid character for identifier.
// ///
// It's modifier by is_first_character flag to determine some character classes /// It's modifier by is_first_character flag to determine some character classes
// allowance like numbers, which are only allowed NOT at the front of the identifier /// allowance like numbers, which are only allowed NOT at the front of the identifier
enum class First_Character : bool { Yes = true, No = false }; enum class First_Character : bool { Yes = true, No = false };
bool is_identifier(u32 letter, First_Character is_first_character); bool is_identifier(u32 letter, First_Character is_first_character);
} }
/// utf8 encoding and decoding
namespace utf8 namespace utf8
{ {
using namespace unicode::special_runes; using namespace unicode::special_runes;
// Decodes rune and returns remaining string /// Decodes rune and returns remaining string
auto decode(std::string_view s) -> std::pair<u32, std::string_view>; auto decode(std::string_view s) -> std::pair<u32, std::string_view>;
/// Returns length of the first rune in the provided string
auto length(std::string_view s) -> usize; auto length(std::string_view s) -> usize;
struct Print { u32 rune; }; struct Print { u32 rune; };
@ -257,167 +265,231 @@ namespace utf8
std::ostream& operator<<(std::ostream& os, utf8::Print const& print); std::ostream& operator<<(std::ostream& os, utf8::Print const& print);
/// Lexical token representation for Musique language
struct Token struct Token
{ {
/// Type of Token
enum class Type enum class Type
{ {
// like repeat or choose or chord Symbol, ///< like repeat or choose or chord
Symbol, Keyword, ///< like true, false, nil
Operator, ///< like "+", "-", "++", "<"
// like true, false, nil Chord, ///< chord or single note literal, like "c125"
Keyword, Numeric, ///< numeric literal (floating point or integer)
Parameter_Separator, ///< "|" separaters arguments from block body
// like + - ++ < > Expression_Separator, ///< ";" separates expressions. Used mainly to separate calls, like `foo 1 2; bar 3 4`
Operator, Open_Block, ///< "[" delimits anonymous block of code (potentially a function)
Close_Block, ///< "]" delimits anonymous block of code (potentially a function)
// chord literal, like c125 Open_Paren, ///< "(" used in arithmetic or as function invocation sarrounding
Chord, Close_Paren ///< ")" used in arithmetic or as function invocation sarrounding
// numeric literal (floating point or integer)
Numeric,
// "|" separaters arguments from block body, and provides variable introduction syntax
Parameter_Separator,
// ";" separates expressions. Used to separate calls, like `foo 1 2; bar 3 4`
Expression_Separator,
// "[" and "]", delimit anonymous block of code (potentially a function)
Open_Block,
Close_Block,
// "(" and ")", used in arithmetic or as function invocation sarrounding (like in Haskell)
Open_Paren,
Close_Paren
}; };
/// Type of token
Type type; Type type;
/// Matched source code to the token type
std::string_view source; std::string_view source;
/// Location of encountered token
Location location; Location location;
}; };
/// Token debug printing
std::ostream& operator<<(std::ostream& os, Token const& tok); std::ostream& operator<<(std::ostream& os, Token const& tok);
/// Token type debug printing
std::ostream& operator<<(std::ostream& os, Token::Type type); std::ostream& operator<<(std::ostream& os, Token::Type type);
/// Lexer takes source code and turns it into list of tokens
///
/// It allows for creating sequence of tokens by using next_token() method.
/// On each call to next_token() when source is non empty token is lexed and
/// source is beeing advanced by removing matched token from string.
struct Lexer struct Lexer
{ {
// Source that is beeing lexed /// Source that is beeing lexed
std::string_view source; std::string_view source;
// Used for rewinding /// Location in source of the last rune
///
/// Used only for rewinding
u32 last_rune_length = 0; u32 last_rune_length = 0;
/// Start of the token that is currently beeing matched
char const* token_start = nullptr; char const* token_start = nullptr;
/// Bytes matched so far
usize token_length = 0; usize token_length = 0;
/// Location of the start of a token that is currently beeing matched
Location token_location{}; Location token_location{};
Location prev_location{}; /// Current location of Lexer in source
Location location{}; Location location{};
/// Previous location of Lexer in source
///
/// Used only for rewinding
Location prev_location{};
/// Try to tokenize next token
auto next_token() -> Result<Token>; auto next_token() -> Result<Token>;
// Utility function for next_token() /// Skip whitespace and comments from the beggining of the source
///
/// Utility function for next_token()
void skip_whitespace_and_comments(); void skip_whitespace_and_comments();
// Finds next rune in source /// Finds next rune in source
auto peek() const -> u32; auto peek() const -> u32;
// Finds next rune in source and returns it, advancing the string /// Finds next rune in source and returns it, advancing the string
auto consume() -> u32; auto consume() -> u32;
// For test beeing /// For test beeing
// callable, current rune is passed to test /// callable, current rune is passed to test
// integral, current rune is tested for equality with test /// integral, current rune is tested for equality with test
// string, current rune is tested for beeing in it /// string, current rune is tested for beeing in it
// otherwise, current rune is tested for beeing in test /// otherwise, current rune is tested for beeing in test
// ///
// When testing above yields truth, current rune is consumed. /// When testing above yields truth, current rune is consumed.
// Returns if rune was consumed /// Returns if rune was consumed
auto consume_if(auto test) -> bool; auto consume_if(auto test) -> bool;
// Consume two runes with given tests otherwise backtrack /// Consume two runes with given tests otherwise backtrack
auto consume_if(auto first, auto second) -> bool; auto consume_if(auto first, auto second) -> bool;
// Goes back last rune /// Goes back last rune
void rewind(); void rewind();
// Marks begin of token /// Marks begin of token
void start(); void start();
// Marks end of token and returns it's matching source /// Marks end of token and returns it's matching source
std::string_view finish(); std::string_view finish();
}; };
/// Representation of a node in program tree
struct Ast struct Ast
{ {
// Named constructors of AST structure /// Constructs binary operator
static Ast binary(Token, Ast lhs, Ast rhs); static Ast binary(Token, Ast lhs, Ast rhs);
/// Constructs block
static Ast block(Location location, Ast seq = sequence({})); static Ast block(Location location, Ast seq = sequence({}));
/// Constructs call expression
static Ast call(std::vector<Ast> call); static Ast call(std::vector<Ast> call);
/// Constructs block with parameters
static Ast lambda(Location location, Ast seq = sequence({}), std::vector<Ast> parameters = {}); static Ast lambda(Location location, Ast seq = sequence({}), std::vector<Ast> parameters = {});
/// Constructs constants, literals and variable identifiers
static Ast literal(Token); static Ast literal(Token);
/// Constructs sequence of operations
static Ast sequence(std::vector<Ast> call); static Ast sequence(std::vector<Ast> call);
/// Constructs variable declaration
static Ast variable_declaration(Location loc, std::vector<Ast> lvalues, std::optional<Ast> rvalue); static Ast variable_declaration(Location loc, std::vector<Ast> lvalues, std::optional<Ast> rvalue);
/// Available ASt types
enum class Type enum class Type
{ {
Binary, // Binary operator application like `1` + `2` Binary, ///< Binary operator application like `1` + `2`
Block, // Block expressions like `[42; hello]` Block, ///< Block expressions like `[42; hello]`
Lambda, // Block expression beeing functions like `[i|i+1]` Lambda, ///< Block expression beeing functions like `[i|i+1]`
Call, // Function call application like `print 42` Call, ///< Function call application like `print 42`
Literal, // Compile time known constant like `c` or `1` Literal, ///< Compile time known constant like `c` or `1`
Sequence, // Several expressions sequences like `42`, `42; 32` Sequence, ///< Several expressions sequences like `42`, `42; 32`
Variable_Declaration, // Declaration of a variable with optional value assigment like `var x = 10` or `var y` Variable_Declaration, ///< Declaration of a variable with optional value assigment like `var x = 10` or `var y`
}; };
/// Type of AST node
Type type; Type type;
/// Location that introduced this node
Location location; Location location;
/// Associated token
Token token; Token token;
/// Child nodes
std::vector<Ast> arguments{}; std::vector<Ast> arguments{};
}; };
bool operator==(Ast const& lhs, Ast const& rhs); bool operator==(Ast const& lhs, Ast const& rhs);
std::ostream& operator<<(std::ostream& os, Ast::Type type); std::ostream& operator<<(std::ostream& os, Ast::Type type);
std::ostream& operator<<(std::ostream& os, Ast const& tree); std::ostream& operator<<(std::ostream& os, Ast const& tree);
/// Pretty print program tree for debugging purposes
void dump(Ast const& ast, unsigned indent = 0); void dump(Ast const& ast, unsigned indent = 0);
/// Source code to program tree converter
///
/// Intended to be used by library user only by Parser::parse() static function.
struct Parser struct Parser
{ {
/// List of tokens yielded from source
std::vector<Token> tokens; std::vector<Token> tokens;
/// Current token id (offset in tokens array)
unsigned token_id = 0; unsigned token_id = 0;
// Parses whole source code producing Ast or Error /// Parses whole source code producing Ast or Error
// using Parser structure internally /// using Parser structure internally
static Result<Ast> parse(std::string_view source, std::string_view filename); static Result<Ast> parse(std::string_view source, std::string_view filename);
/// Parse sequence, collection of expressions
Result<Ast> parse_sequence(); Result<Ast> parse_sequence();
/// Parse either infix expression or variable declaration
Result<Ast> parse_expression(); Result<Ast> parse_expression();
/// Parse infix expression
Result<Ast> parse_infix_expression(); Result<Ast> parse_infix_expression();
/// Parse function call, literal etc
Result<Ast> parse_atomic_expression(); Result<Ast> parse_atomic_expression();
/// Parse variable declaration
Result<Ast> parse_variable_declaration(); Result<Ast> parse_variable_declaration();
/// Utility function for identifier parsing
Result<Ast> parse_identifier_with_trailing_separators(); Result<Ast> parse_identifier_with_trailing_separators();
/// Utility function for identifier parsing
Result<Ast> parse_identifier(); Result<Ast> parse_identifier();
/// Peek current token
Result<Token> peek() const; Result<Token> peek() const;
/// Peek type of the current token
Result<Token::Type> peek_type() const; Result<Token::Type> peek_type() const;
/// Consume current token
Token consume(); Token consume();
// Tests if current token has given type /// Tests if current token has given type
bool expect(Token::Type type) const; bool expect(Token::Type type) const;
/// Tests if current token has given type and source
bool expect(Token::Type type, std::string_view lexeme) const; bool expect(Token::Type type, std::string_view lexeme) const;
// Ensures that current token has one of types given. /// Ensures that current token has one of types given, otherwise returns error
// Otherwise returns error
Result<void> ensure(Token::Type type) const; Result<void> ensure(Token::Type type) const;
}; };
// Number type supporting integer and fractional constants /// Number type supporting integer and fractional constants
// Invariant: gcd(num, den) == 1, after any operation ///
/// \invariant gcd(num, den) == 1, after any operation
struct Number struct Number
{ {
/// Type that represents numerator and denominator values
using value_type = i64; using value_type = i64;
value_type num = 0, den = 1;
value_type num = 0; ///< Numerator of a fraction beeing represented
value_type den = 1; ///< Denominator of a fraction beeing represented
constexpr Number() = default; constexpr Number() = default;
constexpr Number(Number const&) = default; constexpr Number(Number const&) = default;
@ -425,12 +497,12 @@ struct Number
constexpr Number& operator=(Number const&) = default; constexpr Number& operator=(Number const&) = default;
constexpr Number& operator=(Number &&) = default; constexpr Number& operator=(Number &&) = default;
explicit Number(value_type v); explicit Number(value_type v); ///< Creates Number as fraction v / 1
Number(value_type num, value_type den); Number(value_type num, value_type den); ///< Creates Number as fraction num / den
auto as_int() const -> value_type; // Returns self as int auto as_int() const -> value_type; ///< Returns self as int
auto simplify() const -> Number; // Returns self, but with gcd(num, den) == 1 auto simplify() const -> Number; ///< Returns self, but with gcd(num, den) == 1
void simplify_inplace(); // Update self, to have gcd(num, den) == 1 void simplify_inplace(); ///< Update self, to have gcd(num, den) == 1
bool operator==(Number const&) const; bool operator==(Number const&) const;
bool operator!=(Number const&) const; bool operator!=(Number const&) const;
@ -445,6 +517,7 @@ struct Number
Number operator/(Number const& rhs) const; Number operator/(Number const& rhs) const;
Number& operator/=(Number const& rhs); Number& operator/=(Number const& rhs);
/// Parses source contained by token into a Number instance
static Result<Number> from(Token token); static Result<Number> from(Token token);
}; };
@ -459,16 +532,29 @@ using Intrinsic = Result<Value>(*)(Interpreter &i, std::vector<Value>);
/// Lazy Array / Continuation / Closure type thingy /// Lazy Array / Continuation / Closure type thingy
struct Block struct Block
{ {
/// Location of definition / creation
Location location; Location location;
/// Names of expected parameters
std::vector<std::string> parameters; std::vector<std::string> parameters;
/// Body that will be executed
Ast body; Ast body;
/// Context from which block was created. Used for closures
std::shared_ptr<Env> context; std::shared_ptr<Env> context;
/// Calling block
Result<Value> operator()(Interpreter &i, std::vector<Value> params); Result<Value> operator()(Interpreter &i, std::vector<Value> params);
/// Indexing block
Result<Value> index(Interpreter &i, unsigned position); Result<Value> index(Interpreter &i, unsigned position);
/// Count of elements in block
usize size() const; usize size() const;
}; };
/// Representation of musical note
struct Note struct Note
{ {
/// Base of a note, like `c` (=0), `c#` (=1) `d` (=2) /// Base of a note, like `c` (=0), `c#` (=1) `d` (=2)
@ -491,15 +577,18 @@ struct Note
bool operator==(Note const&) const; bool operator==(Note const&) const;
/// Simplify note by adding base to octave if octave is present
void simplify_inplace(); void simplify_inplace();
}; };
std::ostream& operator<<(std::ostream& os, Note note); std::ostream& operator<<(std::ostream& os, Note note);
/// Represantation of simultaneously played notes, aka musical chord
struct Chord struct Chord
{ {
std::vector<Note> notes; std::vector<Note> notes; ///< Notes composing a chord
/// Parse chord literal from provided source
static Chord from(std::string_view source); static Chord from(std::string_view source);
bool operator==(Chord const&) const = default; bool operator==(Chord const&) const = default;
@ -513,7 +602,10 @@ struct Array
/// Elements that are stored in array /// Elements that are stored in array
std::vector<Value> elements; std::vector<Value> elements;
/// Index element of an array
Result<Value> index(Interpreter &i, unsigned position); Result<Value> index(Interpreter &i, unsigned position);
/// Count of elements
usize size() const; usize size() const;
bool operator==(Array const&) const = default; bool operator==(Array const&) const = default;
@ -521,33 +613,37 @@ struct Array
std::ostream& operator<<(std::ostream& os, Array const& v); std::ostream& operator<<(std::ostream& os, Array const& v);
// TODO Add location /// Representation of any value in language
struct Value struct Value
{ {
/// Creates value from literal contained in Token
static Result<Value> from(Token t); static Result<Value> from(Token t);
/// Create value holding provided boolean
///
/// Using Explicit_Bool to prevent from implicit casts
static Value from(Explicit_Bool b); static Value from(Explicit_Bool b);
static Value from(Number n);
// Symbol creating functions
static Value from(std::string s);
static Value from(std::string_view s);
static Value from(char const* s);
static Value from(Block &&l); static Value from(Number n); ///< Create value of type number holding provided number
static Value from(Array &&array); static Value from(std::string s); ///< Create value of type symbol holding provided symbol
static Value from(Note n); static Value from(std::string_view s); ///< Create value of type symbol holding provided symbol
static Value from(Chord chord); static Value from(char const* s); ///< Create value of type symbol holding provided symbol
static Value from(Block &&l); ///< Create value of type block holding provided block
static Value from(Array &&array); ///< Create value of type array holding provided array
static Value from(Note n); ///< Create value of type music holding provided note
static Value from(Chord chord); ///< Create value of type music holding provided chord
enum class Type enum class Type
{ {
Nil, Nil, ///< Unit type, used for denoting emptiness and result of some side effect only functions
Bool, Bool, ///< Boolean type, used for logic computations
Number, Number, ///< Number type, representing only rational numbers
Symbol, Symbol, ///< Symbol type, used to represent identifiers
Intrinsic, Intrinsic, ///< Intrinsic functions that are implemented in C++
Block, Block, ///< Block type, containing block value (lazy array/closure/lambda like)
Array, Array, ///< Array type, eager array
Music, Music, ///< Music type,
}; };
Value() = default; Value() = default;
@ -556,6 +652,7 @@ struct Value
Value& operator=(Value const&) = default; Value& operator=(Value const&) = default;
Value& operator=(Value &&) = default; Value& operator=(Value &&) = default;
/// Contructs Intrinsic, used to simplify definition of intrinsics
inline Value(Intrinsic intr) : type{Type::Intrinsic}, intr(intr) inline Value(Intrinsic intr) : type{Type::Intrinsic}, intr(intr)
{ {
} }
@ -574,26 +671,42 @@ struct Value
// std::string_view - not-owning string type // std::string_view - not-owning string type
std::string s{}; std::string s{};
/// Returns truth judgment for current type, used primarly for if function
bool truthy() const; bool truthy() const;
/// Returns false judgment for current type, used primarly for if function
bool falsy() const; bool falsy() const;
/// Calls contained value if it can be called
Result<Value> operator()(Interpreter &i, std::vector<Value> args); Result<Value> operator()(Interpreter &i, std::vector<Value> args);
/// Index contained value if it can be called
Result<Value> index(Interpreter &i, unsigned position); Result<Value> index(Interpreter &i, unsigned position);
/// Return elements count of contained value if it can be measured
usize size() const; usize size() const;
bool operator==(Value const& other) const; bool operator==(Value const& other) const;
}; };
/// Returns type name of Value type
std::string_view type_name(Value::Type t); std::string_view type_name(Value::Type t);
std::ostream& operator<<(std::ostream& os, Value const& v); std::ostream& operator<<(std::ostream& os, Value const& v);
/// Collection holding all variables in given scope.
struct Env : std::enable_shared_from_this<Env> struct Env : std::enable_shared_from_this<Env>
{ {
// Constructor of Env class /// Constructor of Env class
static std::shared_ptr<Env> make(); static std::shared_ptr<Env> make();
/// Global scope that is beeing set by Interpreter
static std::shared_ptr<Env> global; static std::shared_ptr<Env> global;
/// Variables in current scope
std::unordered_map<std::string, Value> variables; std::unordered_map<std::string, Value> variables;
/// Parent scope
std::shared_ptr<Env> parent; std::shared_ptr<Env> parent;
Env(Env const&) = delete; Env(Env const&) = delete;
@ -603,14 +716,18 @@ struct Env : std::enable_shared_from_this<Env>
/// Defines new variable regardless of it's current existance /// Defines new variable regardless of it's current existance
Env& force_define(std::string name, Value new_value); Env& force_define(std::string name, Value new_value);
/// Finds variable in current or parent scopes
Value* find(std::string const& name); Value* find(std::string const& name);
// Scope menagment /// Create new scope with self as parent
std::shared_ptr<Env> enter(); std::shared_ptr<Env> enter();
/// Leave current scope returning parent
std::shared_ptr<Env> leave(); std::shared_ptr<Env> leave();
private: private:
// Ensure that all values of this class are behind shared_ptr /// Ensure that all values of this class are behind shared_ptr
Env() = default; Env() = default;
}; };
@ -633,6 +750,7 @@ struct Context
std::chrono::duration<float> length_to_duration(std::optional<Number> length) const; std::chrono::duration<float> length_to_duration(std::optional<Number> length) const;
}; };
/// Given program tree evaluates it into Value
struct Interpreter struct Interpreter
{ {
/// MIDI connection that is used to play music. /// MIDI connection that is used to play music.
@ -654,10 +772,13 @@ struct Interpreter
Interpreter(Interpreter const&) = delete; Interpreter(Interpreter const&) = delete;
Interpreter(Interpreter &&) = default; Interpreter(Interpreter &&) = default;
/// Try to evaluate given program tree
Result<Value> eval(Ast &&ast); Result<Value> eval(Ast &&ast);
// Scope managment // Enter scope by changing current environment
void enter_scope(); void enter_scope();
// Leave scope by changing current environment
void leave_scope(); void leave_scope();
/// Play note resolving any missing parameters with context via `midi_connection` member. /// Play note resolving any missing parameters with context via `midi_connection` member.