Skip to content

Commit

Permalink
#14: Polishes and completes the REPL interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Altoids1 authored Nov 3, 2023
2 parents dc3058e + 2b910fe commit bfacd42
Show file tree
Hide file tree
Showing 14 changed files with 569 additions and 381 deletions.
3 changes: 1 addition & 2 deletions AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Value AssignmentStatement::resolve(Interpreter& interp)
if (lhs_val.t_vType == Value::vType::Function)
{
#if !defined(JOAO_SAFE) && defined(DEBUG)
std::cout << "WARNING: Overwriting a Value which stores a function pointer!\n";
std::cerr << "WARNING: Overwriting a Value which stores a function pointer!\n";
#else
return Value();
#endif
Expand Down Expand Up @@ -122,7 +122,6 @@ Value LocalAssignmentStatement::resolve(Interpreter& interp)
increment();
#endif
Value rhs_val = rhs->resolve(interp);
//std::cout << "Their name is " + id->get_str() + " and their value is " + std::to_string(rhs_val.t_value.as_int) + "\n";

if (t_op != aOps::Assign) UNLIKELY // This is mostly derelict code, but might come up later if composite assignment gets refactored at the AST layer, for some reason.
{
Expand Down
5 changes: 0 additions & 5 deletions AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ class Literal : public ASTNode { // A node which denotes a plain ol' literal.
Literal(Value V)
:heldval(V)
{
//std::cout << "Constructing literal...\n";
}

virtual Value resolve(Interpreter&) override;
Expand Down Expand Up @@ -80,7 +79,6 @@ class Identifier : public ASTNode
Identifier(const ImmutableString& s)
:t_name(s)
{
//std::cout << "I've been created with name " + s + "!\n";
}
const ImmutableString& get_str() const
{
Expand Down Expand Up @@ -114,8 +112,6 @@ class AssignmentStatement : public Expression
t_op(o)
{
my_line = linenum;

//std::cout << "My identifier has the name " + id->get_str() + "!\n";
}
virtual ~AssignmentStatement()
{
Expand Down Expand Up @@ -181,7 +177,6 @@ class LocalAssignmentStatement final : public AssignmentStatement // "Value x =
,ty(localtype)
{
my_line = linenum;
//std::cout << "My identifier has the name " + id->get_str() + "!\n";
}

virtual Value resolve(Interpreter&) override;
Expand Down
72 changes: 68 additions & 4 deletions Args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,65 @@ void Args::print_help()
#endif
std::cout << " -f\tDisables colour (and other formatting) when emitting errors or messages.\n";
}

//Helper function for interactive_mode, since it has a fancy output :^)
static void print_version_fancy() {
/*
The original ASCII art, provided by our friends at figlet:
_
| | ___ __ _ ___
_ | |/ _ \ / _` |/ _ \
| |_| | (_) | (_| | (_) |
\___/ \___/ \__,_|\___/
*/
/*
Adding the pizzazz:
======_
======| | ___ __ _ ___
=======| |/ _ \ / _' |/ _ \
====| |_| | (_) | (_| | (_) |
===== \___/ \___/ \__,_|\___/
*/
const std::string asciiArt = R"(
======_ | Reference: https://altoids1.github.io/Joao/index.html
======| | ___ __ _ ___ |
=======| |/ _ \ / _' |/ _ \ |
====| |_| | (_) | (_| | (_) | | Version 1.2.3
===== \___/ \___/ \__,_|\___/ |
)";
// NOTE: Printing this with colour codes *could* have been a heap of spaghetti,
// but I'm going to do it the *right* way and just have this for-loop. You're welcome.
size_t charsSinceNewline = 0; // This should be a for loop initializer but, we still support C++17 (for some reason)
for(char c : asciiArt) {
Terminal::SetBold(std::cout,true);
if(c == '\n') {
charsSinceNewline = 0;
} else {
++charsSinceNewline;
}
switch(c) {
case '=':
Terminal::SetBold(std::cout,false);
Terminal::SetColor(std::cout,
Terminal::Color::Red
);
std::cout << c;
Terminal::ClearFormatting(std::cout);
continue;
case '1':
std::cout << VERSION_MAJOR;
break;
case '2':
std::cout << VERSION_MINOR;
break;
case '3':
std::cout << VERSION_PATCH;
break;
default:
std::cout << c;
}
}
}

static Program interactive_default_program() {
Expand All @@ -97,7 +156,7 @@ static Program interactive_default_program() {
return ret;
}

static std::optional<Value> try_run_expression(Program& prog, std::string&& expr_str) {
static std::optional<Value> try_run_expression(Interpreter& interp, Program& prog, std::string&& expr_str) {
std::stringstream expr_ss(expr_str);
Scanner scn(true);
scn.scan(expr_ss);
Expand All @@ -106,13 +165,13 @@ static std::optional<Value> try_run_expression(Program& prog, std::string&& expr
Parser prs(scn);
ASTNode* ptr;
try {
ptr = prs.parse_repl_expression();
ptr = prs.parse_repl_expression(prog);
} catch (error::parser& err) {
return {};
}
if(ptr == nullptr)
return {};
Interpreter interp(prog,true);

Value ret = interp.evaluate_expression(ptr);
delete ptr; // FIXME: be RAII about this, come on.
if(interp.error) {
Expand Down Expand Up @@ -169,7 +228,10 @@ static void detail_get_line(std::string& ret)

void Args::interactive_mode()
{
print_version_fancy();
Program prog = interactive_default_program();
Interpreter interp(prog,true);
interp.push_stack("#repl");
while (true)
{
Terminal::SetColor(std::cout,Terminal::Color::Red);
Expand All @@ -185,7 +247,9 @@ void Args::interactive_mode()
continue;
if(input == "quit()") // FIXME: support quit() more generically
return;
auto result = try_run_expression(prog, std::move(input));
if(input.back() != ';')
input.push_back(';');
auto result = try_run_expression(interp, prog, std::move(input));
if(result)
std::cout << result.value().to_string() << std::endl;
}
Expand Down
59 changes: 29 additions & 30 deletions HashTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,14 @@ class HashTable
{
if (used) UNLIKELY
{
std::cout << "Bucket was deleted with un-deleted contents inside!\n";
std::cerr << "Bucket was deleted with un-deleted contents inside!\n";
}
}
#endif
inline void clear()
{
if(used)
{
//std::cout << "Deleting " << *key() << "\t" << value()->to_string() << "\n";
key()->~Key();
value()->~Value();
}
Expand Down Expand Up @@ -312,7 +311,7 @@ class HashTable
if (!shit) UNLIKELY // SHIT!!!
{
#ifdef HASHTABLE_DEBUG
std::cout << "Shit condition reached.\n";
std::cerr << "Shit condition reached.\n";
exit(1);
#endif
delete[] new_block; // FIXME: This doesn't exactly work correctly.
Expand Down Expand Up @@ -458,7 +457,7 @@ class HashTable
{
if(!bucket_block)
{
std::cout << "This HashTable is empty.";
std::cerr << "This HashTable is empty.";
return;
}
bool unprinted_collision_ptr = true;
Expand All @@ -467,78 +466,78 @@ class HashTable
Bucket& buck = bucket_block[i];
if (&buck == collision_data.begin)
{
std::cout << "There's more.\n"; // No!!
std::cerr << "There's more.\n"; // No!!
unprinted_collision_ptr = false;
}
std::cout << std::to_string(reinterpret_cast<size_t>(&buck));
std::cerr << std::to_string(reinterpret_cast<size_t>(&buck));
if(!buck.used)
{
if (buck.next_collision_bucket)
{
std::cout << " Empty Bucket WITH COLLISION BUCKET: " << std::to_string(reinterpret_cast<size_t>(buck.next_collision_bucket)) << '\n';
std::cerr << " Empty Bucket WITH COLLISION BUCKET: " << std::to_string(reinterpret_cast<size_t>(buck.next_collision_bucket)) << '\n';
continue;
}
std::cout << " Empty Bucket\n";
std::cerr << " Empty Bucket\n";
continue;
}

std::cout << "This is a bucket: {";
std::cerr << "This is a bucket: {";
if constexpr (std::is_same<Key, std::string>::value || std::is_same<Key,::Value>::value) // FIXME: Really need a more general solution to this.
{
std::cout << *buck.key();
std::cerr << *buck.key();
}
else if constexpr (std::is_enum<Key>::value)
{
std::cout << std::to_string(static_cast<size_t>(*buck.key()));
std::cerr << std::to_string(static_cast<size_t>(*buck.key()));
}
else if constexpr(std::is_pointer<Key>::value)
{
std::cout << std::to_string(reinterpret_cast<size_t>(*buck.key()));
std::cerr << std::to_string(reinterpret_cast<size_t>(*buck.key()));
}
else if constexpr(std::is_same<Key, ImmutableString>::value)
{
std::cout << buck.key()->to_string();
std::cerr << buck.key()->to_string();
}
else if constexpr (std::is_arithmetic<Value>::value)
{
std::cout << std::to_string(*buck.value());
std::cerr << std::to_string(*buck.value());
}
else
{
std::cout << "???";
std::cerr << "???";
}
std::cout << "\t";
std::cerr << "\t";
if constexpr (std::is_same<Value, std::string>::value || std::is_same<Value, ::Value>::value)
{
std::cout << *buck.value();
std::cerr << *buck.value();
}
else if constexpr (std::is_enum<Value>::value)
{
std::cout << std::to_string(static_cast<size_t>(*buck.value()));
std::cerr << std::to_string(static_cast<size_t>(*buck.value()));
}
else if constexpr (std::is_pointer<Value>::value)
{
std::cout << std::to_string(reinterpret_cast<size_t>(*buck.value()));
std::cerr << std::to_string(reinterpret_cast<size_t>(*buck.value()));
}
else if constexpr (std::is_integral<Value>::value)
{
std::cout << std::to_string(*buck.value());
std::cerr << std::to_string(*buck.value());
}
else
{
std::cout << "???";
std::cerr << "???";
}
if (buck.next_collision_bucket)
{
std::cout << '\t' << std::to_string(reinterpret_cast<size_t>(buck.next_collision_bucket));
std::cerr << '\t' << std::to_string(reinterpret_cast<size_t>(buck.next_collision_bucket));
}
std::cout << "}\n"; // Dear god...
std::cerr << "}\n"; // Dear god...
}
if(unprinted_collision_ptr)
{
std::cout << "Dangling collision_block_begin pointer!\n";
std::cout << std::to_string(reinterpret_cast<size_t>(collision_data.begin)) << std::endl;
std::cout << std::to_string(collision_data.begin - bucket_block) << std::endl;
std::cerr << "Dangling collision_block_begin pointer!\n";
std::cerr << std::to_string(reinterpret_cast<size_t>(collision_data.begin)) << std::endl;
std::cerr << std::to_string(collision_data.begin - bucket_block) << std::endl;
}
}
size_t hash_collisions = 0;
Expand Down Expand Up @@ -653,7 +652,7 @@ class HashTable
#ifdef HASHTABLE_DEBUG
if (buckets_left)
{
std::cout << "Hashtable failed to delete " << std::to_string(used_bucket_count) << " entries! Or something.\n";
std::cerr << "Hashtable failed to delete " << std::to_string(used_bucket_count) << " entries! Or something.\n";
}
#endif
}
Expand Down Expand Up @@ -738,13 +737,13 @@ class HashTable
}
if (fav_buck->used) UNLIKELY
{
std::cout << "Warning, overriding previously-used bucket!";
std::cerr << "Warning, overriding previously-used bucket!";
throw;
}
if (fav_buck->next_collision_bucket) UNLIKELY
{
std::cout << "fav_buck started out with fraudulent bucket pointer!";
dump();
std::cerr << "fav_buck started out with fraudulent bucket pointer!";
dump();
throw;
}
#endif
Expand Down
2 changes: 0 additions & 2 deletions Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ Value Interpreter::execute(Program& program, Value& jarg)
}

Value Interpreter::evaluate_expression(ASTNode* node) {
push_stack("#expr",nullptr);
Value ret = node->resolve(*this);
pop_stack();
return ret;
}

Expand Down
7 changes: 5 additions & 2 deletions JoaoGrammar.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Here is the complete syntax of João in extended BNF. As usual in extended BNF, {A} means 0 or more As, and [A] means an optional A. Brace characters are escaped with single-quotes.

program ::= {classdef | funcdef | includefile}

repl ::= {funcdef | stat | exp}

includefile ::== 'include ' LiteralString

Expand All @@ -19,12 +21,13 @@ Here is the complete syntax of João in extended BNF. As usual in extended BNF,
stat ::= ';' |
varstat ';' |
functioncall ';' |
return [exp] ';' |
'return' [exp] ';' |
'break' [PositiveInteger] ';' |
'continue;' |
'while(' exp '){' block '}' |
'if(' exp '){' block '}' {'elseif(' exp '){' block '}'} ['else(' exp '){' block '}'] |
'for('for_generic_init | for_each_init'){' block '}' |
'try{' block '}catch(' Name '){' block ')' |
'try{' block '}catch(' Name '){' block '}' |
'throw' [exp] ';'

for_generic_init ::= '[varstat | exp] ';' [exp] ';' [varstat | exp]
Expand Down
4 changes: 3 additions & 1 deletion ObjectTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ class ObjectTree
{
derived->typeproperties.insert(base->typeproperties.begin(), base->typeproperties.end());
derived->typefuncs.insert(base->typefuncs.begin(), base->typefuncs.end());
// Passively, this does not override (and thereby clobber) the properties already present in our objecttype, as just a behavior of the std::vector::insert() function.
// Passively, this does not override (and thereby clobber) the properties already present in our objecttype, as just a behavior of the HashTable::insert() function.
if (base->is_table_type)
derived->is_table_type = true;
}
for (Node* child : inheriter->children)
{
Expand Down
Loading

0 comments on commit bfacd42

Please sign in to comment.