|
|
@ -1,8 +1,9 @@ |
|
|
|
#include <algorithm>
|
|
|
|
#include <iostream>
|
|
|
|
#include "molasses/parser_primitives.h"
|
|
|
|
#include "molasses/generator_primitives.h"
|
|
|
|
#include "molasses/errors.h"
|
|
|
|
#include "molasses/generator_primitives.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <iostream>
|
|
|
|
#include <span>
|
|
|
|
|
|
|
|
namespace molasses { |
|
|
|
std::vector<std::string> operator>>(std::vector<std::string> current_stack, const operation& next_op) { |
|
|
@ -90,24 +91,40 @@ namespace molasses { |
|
|
|
const lexed_output& lexer_state, |
|
|
|
const std::vector<symbol>& consumed_stream, |
|
|
|
std::vector<std::string> execution_input, |
|
|
|
const std::vector<std::string>& execution_output |
|
|
|
const std::vector<std::string>& execution_output, |
|
|
|
const std::vector<std::pair<size_t, size_t>>& sub_bodies |
|
|
|
) { |
|
|
|
auto& type_stack = execution_input; |
|
|
|
|
|
|
|
for(const auto& symbol : consumed_stream) { |
|
|
|
|
|
|
|
std::map<size_t, std::vector<std::string>> effective_snapshots; |
|
|
|
size_t idx = 0; |
|
|
|
|
|
|
|
for(auto it = consumed_stream.begin(); it != consumed_stream.end(); ++it, ++idx) { |
|
|
|
const auto& symbol = *it; |
|
|
|
const auto& symbol_text = lexer_state.dictionary.at(symbol); |
|
|
|
if(symbol.is_string) { |
|
|
|
// Skip GOTOs and LABELs
|
|
|
|
if(auto ahead = it; ++ahead != consumed_stream.end() and (lexer_state.dictionary.at(*ahead) == "__GOTO__" or lexer_state.dictionary.at(*ahead) == "__LABEL__")) { |
|
|
|
effective_snapshots[idx] = type_stack; |
|
|
|
it = ahead; |
|
|
|
++idx; |
|
|
|
} else if(symbol.is_string) { |
|
|
|
type_stack.emplace_back("u8 ptr"); |
|
|
|
} else if(auto is_int32 = try_parse_int32(symbol_text); is_int32) { |
|
|
|
type_stack.emplace_back("i32"); |
|
|
|
} else if(auto is_int64 = try_parse_int64(symbol_text); is_int64) { |
|
|
|
type_stack.emplace_back("i64"); |
|
|
|
} else if(auto is_op = parser_state.lookup_operation(symbol_text); is_op) { |
|
|
|
type_stack = type_stack >> *is_op; |
|
|
|
} |
|
|
|
type_stack = type_stack >> *is_op; |
|
|
|
} |
|
|
|
} |
|
|
|
if(type_stack != execution_output) return false; |
|
|
|
for(auto [start, end] : sub_bodies) { |
|
|
|
if(effective_snapshots[start] != effective_snapshots[end]) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return type_stack == execution_output; |
|
|
|
return b">true; |
|
|
|
} |
|
|
|
|
|
|
|
generate_context parse(parser_context ctx, const lexed_output& lexer_data) { |
|
|
@ -115,14 +132,19 @@ namespace molasses { |
|
|
|
DO_KW = 1, |
|
|
|
SEPARATOR_KW, |
|
|
|
PROC_KW, |
|
|
|
END_KW |
|
|
|
END_KW, |
|
|
|
LABEL_KW, |
|
|
|
GOTO_KW |
|
|
|
}; |
|
|
|
|
|
|
|
lexed_output fake; |
|
|
|
fake.dictionary[PROC_KW] = "__PROC__"; |
|
|
|
fake.dictionary[PROC_KW] = "__PROC__"; |
|
|
|
fake.dictionary[SEPARATOR_KW] = "__--__"; |
|
|
|
fake.dictionary[DO_KW] = "__DO__"; |
|
|
|
fake.dictionary[END_KW] = "__END__"; |
|
|
|
fake.dictionary[LABEL_KW] = "__LABEL__"; |
|
|
|
fake.dictionary[GOTO_KW] = "__GOTO__"; |
|
|
|
|
|
|
|
|
|
|
|
auto tokens = concatenate(fake, lexer_data); |
|
|
|
|
|
|
@ -197,16 +219,40 @@ namespace molasses { |
|
|
|
|
|
|
|
// Process body
|
|
|
|
std::vector<symbol> body; |
|
|
|
std::vector<std::pair<size_t, size_t>> sub_bodies; |
|
|
|
std::map<std::string, size_t> found_labels; |
|
|
|
std::map<std::string, size_t> found_gotos; |
|
|
|
while(*it != END_KW) { |
|
|
|
body.emplace_back(*it); |
|
|
|
last_valid = it; |
|
|
|
++it; |
|
|
|
if(auto ahead = it; ++ahead != tokens.symbols.end() and (*ahead == GOTO_KW or *ahead == LABEL_KW)) { |
|
|
|
if(*ahead == GOTO_KW) { |
|
|
|
found_gotos[tokens.dictionary[*it]] = body.size(); |
|
|
|
} else if(*ahead == LABEL_KW) { |
|
|
|
found_labels[tokens.dictionary[*it]] = body.size(); |
|
|
|
// TODO: Handle duplicate labels
|
|
|
|
} |
|
|
|
body.emplace_back(*it); |
|
|
|
body.emplace_back(*ahead); |
|
|
|
last_valid = ahead; |
|
|
|
it = ++ahead; |
|
|
|
} else { |
|
|
|
body.emplace_back(*it); |
|
|
|
last_valid = it; |
|
|
|
++it; |
|
|
|
} |
|
|
|
check_for_unexpected_stream_end("__DO__ block needs a matching __END__", details::concatenate_builder("Parsing procedure ",tokens.dictionary.at(name_symbol),", file ",last_valid->file_name, ":", last_valid->line, ":", last_valid->column)); |
|
|
|
} |
|
|
|
last_valid = it; |
|
|
|
++it; |
|
|
|
|
|
|
|
for(auto& [dest, index] : found_gotos) { |
|
|
|
if(not found_labels.contains(dest)) { |
|
|
|
throw orphan_goto_error(body[index], dest); |
|
|
|
} |
|
|
|
|
|
|
|
sub_bodies.emplace_back(std::min(index, found_labels[dest]), std::max(index, found_labels[dest])); |
|
|
|
} |
|
|
|
|
|
|
|
return std::make_pair(it, std::make_shared<procedure_operation>(name, argument_types, return_types, body)); |
|
|
|
return std::make_pair(it, std::make_shared<procedure_operation>(name, argument_types, return_types, body, sub_bodies)); |
|
|
|
#undef check_for_unexpected_stream_end
|
|
|
|
}; |
|
|
|
|
|
|
@ -220,7 +266,7 @@ namespace molasses { |
|
|
|
} while (progress != tokens.symbols.end()); |
|
|
|
|
|
|
|
for(auto& proc : parsed_procedures) { |
|
|
|
if(not type_check(ctx, tokens, proc->_body, proc->_args, proc->_rets)) { |
|
|
|
if(not type_check(ctx, tokens, proc->_body, proc->_args, proc->_rets, proc->_simple_sub_bodies)) { |
|
|
|
throw procedure_stack_error(); |
|
|
|
} |
|
|
|
} |
|
|
@ -239,9 +285,21 @@ namespace molasses { |
|
|
|
ops.push_back(instruction); |
|
|
|
} |
|
|
|
|
|
|
|
for(auto elem : _body) { |
|
|
|
for(auto it = _body.begin(); it != _body.end(); ++it) { |
|
|
|
auto elem = *it; |
|
|
|
auto token = lexer_data.dictionary.at(elem); |
|
|
|
if(elem.is_string) { |
|
|
|
if(auto ahead = it; ++ahead != _body.end() and (lexer_data.dictionary.at(*ahead) == "__GOTO__" or lexer_data.dictionary.at(*ahead) == "__LABEL__")) { |
|
|
|
if(lexer_data.dictionary.at(*ahead) == "__GOTO__") { |
|
|
|
for(auto&& instruction : generate_goto(name() + " in " + token)) { |
|
|
|
ops.push_back(instruction); |
|
|
|
} |
|
|
|
} else if(lexer_data.dictionary.at(*ahead) == "__LABEL__") { |
|
|
|
for(auto&& instruction : generate_label(name() + " in " + token)) { |
|
|
|
ops.push_back(instruction); |
|
|
|
} |
|
|
|
} |
|
|
|
it = ahead; |
|
|
|
} else if(elem.is_string) { |
|
|
|
for(auto&& instruction : generate_push_string_ptr(elem)) { |
|
|
|
ops.push_back(instruction); |
|
|
|
} |
|
|
|