A few more opcodes to finish
This commit is contained in:
parent
1465805a82
commit
36aeb4f85e
@ -147,6 +147,7 @@
|
||||
<ClCompile Include="codes.cpp" />
|
||||
<ClCompile Include="DMS.cpp" />
|
||||
<ClCompile Include="dms_state.cpp" />
|
||||
<ClCompile Include="dms_state_interpret.cpp" />
|
||||
<ClCompile Include="LineParserBuilds.cpp" />
|
||||
<ClCompile Include="LineParserMatchProcess.cpp" />
|
||||
<ClCompile Include="LineParserParse.cpp" />
|
||||
|
||||
@ -63,6 +63,9 @@
|
||||
<ClCompile Include="LineParserBuilds.cpp">
|
||||
<Filter>Source Files\DMS</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dms_state_interpret.cpp">
|
||||
<Filter>Source Files\DMS</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="value.h">
|
||||
|
||||
@ -1,3 +1,21 @@
|
||||
LineParserMatchProcess.cpp
|
||||
F:\VSCWorkspace\DMS\DMS\LineParserMatchProcess.cpp(803): warning C4715: 'dms::LineParser::match_process_expression': not all control paths return a value
|
||||
DMS.cpp
|
||||
dms_state.cpp
|
||||
dms_state_interpret.cpp
|
||||
LineParserBuilds.cpp
|
||||
LineParserMatchProcess.cpp
|
||||
LineParserParse.cpp
|
||||
string_utils.cpp
|
||||
F:\VSCWorkspace\DMS\DMS\string_utils.cpp(9,45): warning C4244: 'initializing': conversion from 'double' to 'unsigned int', possible loss of data
|
||||
F:\VSCWorkspace\DMS\DMS\string_utils.cpp(36,17): warning C4244: 'initializing': conversion from 'double' to 'size_t', possible loss of data
|
||||
F:\VSCWorkspace\DMS\DMS\string_utils.cpp(37,16): warning C4244: 'initializing': conversion from 'double' to 'size_t', possible loss of data
|
||||
F:\VSCWorkspace\DMS\DMS\string_utils.cpp(93,22): warning C4018: '<': signed/unsigned mismatch
|
||||
F:\VSCWorkspace\DMS\DMS\string_utils.cpp(134,22): warning C4018: '<': signed/unsigned mismatch
|
||||
F:\VSCWorkspace\DMS\DMS\string_utils.cpp(135,25): warning C4018: '<': signed/unsigned mismatch
|
||||
LineParserUtils.cpp
|
||||
number_utils.cpp
|
||||
F:\VSCWorkspace\DMS\DMS\number_utils.cpp(21,21): warning C4018: '<': signed/unsigned mismatch
|
||||
utils.cpp
|
||||
value.cpp
|
||||
Generating Code...
|
||||
F:\VSCWorkspace\DMS\DMS\LineParserMatchProcess.cpp(773): warning C4715: 'dms::LineParser::match_process_expression': not all control paths return a value
|
||||
DMS.vcxproj -> F:\VSCWorkspace\DMS\Debug\DMS.exe
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,13 +1,14 @@
|
||||
#include "LineParser.h"
|
||||
using namespace dms::tokens;
|
||||
using namespace dms::utils;
|
||||
// TODO: process if elseif else statements, for loops and while loops
|
||||
namespace dms {
|
||||
bool LineParser::match_process_standard(tokenstream* stream, value* v) {
|
||||
if (match_process_expression(stream,v)) {
|
||||
return true; // Nothing todo
|
||||
return true;
|
||||
}
|
||||
else if (match_process_function(stream, v)) {
|
||||
return true; // Nothing todo
|
||||
return true;
|
||||
}
|
||||
else if (match_process_list(stream, v)) {
|
||||
return true;
|
||||
@ -56,51 +57,66 @@ namespace dms {
|
||||
bool LineParser::match_process_list(tokenstream* stream, value* v) {
|
||||
if (stream->match(tokens::cbracketo)) {
|
||||
token start = stream->peek();
|
||||
token ancor = start;
|
||||
std::vector<token> t = stream->next(tokens::cbracketo, tokens::cbracketc);
|
||||
tokenstream tempstream;
|
||||
tempstream.init(&t);
|
||||
value* ref = buildVariable();
|
||||
value* length = new value;
|
||||
value* dict = nullptr;
|
||||
size_t count = 0;
|
||||
cmd* c = new cmd;
|
||||
c->opcode = codes::LIST;
|
||||
c->args.push(v);
|
||||
c->args.push(length);
|
||||
current_chunk->addCmd(c);
|
||||
bool ready = true;
|
||||
while (tempstream.peek().type != tokens::none) {
|
||||
print(tempstream.peek());
|
||||
if (tempstream.match(tokens::cbracketc)) {
|
||||
ready = true;
|
||||
c = new cmd;
|
||||
c->opcode = codes::INST;
|
||||
c->args.push(v);
|
||||
c->args.push(ref);
|
||||
if (dict != nullptr) {
|
||||
c->args.push(dict);
|
||||
dict = nullptr;
|
||||
}
|
||||
current_chunk->addCmd(c);
|
||||
break;
|
||||
}
|
||||
// Match Dict
|
||||
else if (tempstream.match(tokens::name,tokens::colon)) {
|
||||
dict = buildVariable(tempstream.next().name);
|
||||
tempstream.next();
|
||||
if (!match_process_standard(&tempstream,ref)) {
|
||||
badSymbol();
|
||||
}
|
||||
}
|
||||
// This will modify the ref!!!
|
||||
else if (match_process_standard(&tempstream, ref)) {
|
||||
count++;
|
||||
print(">>",tempstream.peek());
|
||||
|
||||
// TODO: make sure each statement is properly seperated by a comma n such
|
||||
|
||||
/*if (tempstream.match(tokens::seperator) || tempstream.match(tokens::newline,tokens::seperator)) {
|
||||
print("Good!");
|
||||
}*/
|
||||
/*if (!(tempstream.match(tokens::seperator) || tempstream.match(tokens::cbracketc) || tempstream.match(tokens::newline))) {
|
||||
state->push_error(errors::error{ errors::badtoken,concat("Unexpected symbol '",tempstream.next().toString(),"' Expected '}' to close list at ",start.line_num),true,tempstream.peek().line_num,current_chunk });
|
||||
return false;
|
||||
}*/
|
||||
if (ready) {
|
||||
ancor = tempstream.last();
|
||||
ready = false;
|
||||
}
|
||||
else
|
||||
state->push_error(errors::error{ errors::badtoken,concat("Unexpected symbol '",ancor.toString(),"' Expected '}' to close list (line: ",start.line_num,") Did you forget a comma?"),true,ancor.line_num,current_chunk });
|
||||
}
|
||||
else if (tempstream.match(tokens::newline)) {
|
||||
tempstream.next(); // this is fine
|
||||
}
|
||||
else if (tempstream.match(tokens::seperator)) {
|
||||
// Handle the next piece
|
||||
ready = true;
|
||||
c = new cmd;
|
||||
c->opcode = codes::INST;
|
||||
c->args.push(v);
|
||||
c->args.push(ref);
|
||||
if (dict != nullptr) {
|
||||
c->args.push(dict);
|
||||
dict = nullptr;
|
||||
}
|
||||
current_chunk->addCmd(c);
|
||||
// Build new value
|
||||
ref = buildVariable();
|
||||
@ -120,22 +136,13 @@ namespace dms {
|
||||
return false;
|
||||
}
|
||||
bool LineParser::match_process_disp(tokenstream* stream) {
|
||||
/*
|
||||
DISP, "msg"
|
||||
DISP, "msg" speaker
|
||||
|
||||
Compound DISP
|
||||
*/
|
||||
//lastCall.push("MP_disp");
|
||||
if ((isBlock(bt_block) || isBlock(bt_method)) && stream->match(tokens::newline, tokens::string, tokens::newline)) {
|
||||
stream->next(); // Standard consumption
|
||||
std::string msg = stream->next().name;
|
||||
cmd* c = new cmd;
|
||||
c->opcode = codes::DISP;
|
||||
//c->args.push(buildValue());
|
||||
c->args.push(buildValue(msg));
|
||||
current_chunk->addCmd(c); // Add the cmd to the current chunk
|
||||
//lastCall.pop();
|
||||
return true;
|
||||
}
|
||||
else if ((isBlock(bt_block) || isBlock(bt_method)) && stream->match(tokens::newline, tokens::name, tokens::colon, tokens::string, tokens::newline)) {
|
||||
@ -151,26 +158,18 @@ namespace dms {
|
||||
current_chunk->addCmd(c);
|
||||
c = new cmd;
|
||||
c->opcode = codes::DISP;
|
||||
//c->args.push(buildValue());
|
||||
c->args.push(buildValue(msg));
|
||||
current_chunk->addCmd(c); // Add the cmd to the current chunk
|
||||
// We might have to consume a newline... Depends on what's next
|
||||
//lastCall.pop();
|
||||
return true;
|
||||
}
|
||||
else if ((isBlock(bt_block) || isBlock(bt_method)) && stream->match(tokens::name,tokens::colon,tokens::cbracketo)) {
|
||||
std::string name = stream->next().name;
|
||||
// Command to set the speaker
|
||||
cmd* c = new cmd;
|
||||
c->opcode = codes::SSPK;
|
||||
c->args.push(buildVariable(name));
|
||||
current_chunk->addCmd(c);
|
||||
// Reset the display for the new speaker. Append can be used!
|
||||
//c = new cmd;
|
||||
//c->opcode = codes::DISP;
|
||||
//c->args.push(buildValue());
|
||||
//c->args.push(buildValue(std::string("")));
|
||||
//current_chunk->addCmd(c);
|
||||
// Command to set the speaker
|
||||
stream->next();
|
||||
stream->next();
|
||||
while (stream->peek().type != tokens::cbracketc) {
|
||||
@ -235,74 +234,21 @@ namespace dms {
|
||||
// emotion: "path"
|
||||
// looks like a simple disp command
|
||||
else if (isBlock(bt_character) && stream->match(tokens::tab, tokens::name, tokens::colon, tokens::string, tokens::newline)) {
|
||||
//lastCall.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: We still have to implement the compound disp
|
||||
//lastCall.pop();
|
||||
return false;
|
||||
}
|
||||
bool LineParser::match_process_assignment(tokenstream* stream) {
|
||||
// something equals something else lets go
|
||||
//lastCall.push("MP_assignment");
|
||||
if (stream->match(tokens::name,tokens::equal)) {
|
||||
value* var = buildVariable(stream->next().name); // The variable that we will be setting stuff to
|
||||
stream->next(); // Consume the equal
|
||||
cmd* c = new cmd;
|
||||
c->opcode = codes::ASGN;
|
||||
c->args.push(var);
|
||||
if (match_process_list(stream, var)) {
|
||||
return true;
|
||||
}
|
||||
else if (match_process_expression(stream, var)) {
|
||||
// Expressions can internally set variables
|
||||
// We actually need to clean up our cmds
|
||||
return true;
|
||||
}
|
||||
else if (match_process_function(stream, var)) {
|
||||
// Functions can internally set variables
|
||||
// We actually need to clean up our cmds
|
||||
return true;
|
||||
}
|
||||
else if (stream->match(tokens::True)) {
|
||||
stream->next();
|
||||
c->args.push(buildValue(true));
|
||||
current_chunk->addCmd(c);
|
||||
return true;
|
||||
}
|
||||
else if (stream->match(tokens::False)) {
|
||||
stream->next();
|
||||
c->args.push(buildValue(false));
|
||||
current_chunk->addCmd(c);
|
||||
return true;
|
||||
}
|
||||
else if (stream->match(tokens::string)) {
|
||||
c->args.push(buildValue(stream->next().name));
|
||||
current_chunk->addCmd(c);
|
||||
return true;
|
||||
}
|
||||
else if (stream->match(tokens::nil)) {
|
||||
stream->next();
|
||||
c->args.push(buildValue());
|
||||
current_chunk->addCmd(c);
|
||||
return true;
|
||||
}
|
||||
else if (stream->match(tokens::number)) {
|
||||
c->args.push(buildValue(std::stod(stream->next().name)));
|
||||
current_chunk->addCmd(c);
|
||||
return true;
|
||||
}
|
||||
else if (stream->match(tokens::bracketo, tokens::name, tokens::bracketc)) {
|
||||
// We are assigning a block as a variable
|
||||
stream->next();
|
||||
c->args.push(buildBlock(stream->next().name));
|
||||
current_chunk->addCmd(c);
|
||||
stream->next();
|
||||
return true;
|
||||
}
|
||||
else if (stream->match(tokens::name)) {
|
||||
c->args.push(buildVariable(stream->next().name));
|
||||
value* ref = buildVariable();
|
||||
print(stream->peek());
|
||||
if (match_process_standard(stream,ref)) {
|
||||
c->args.push(ref);
|
||||
current_chunk->addCmd(c);
|
||||
return true;
|
||||
}
|
||||
@ -336,7 +282,6 @@ namespace dms {
|
||||
return false;
|
||||
}
|
||||
bool LineParser::match_process_choice(tokenstream* stream) {
|
||||
//lastCall.push("MP_choice");
|
||||
token temp = stream->peek();
|
||||
if (temp.raw == codes::CHOI && stream->match(tokens::control,tokens::string)) {
|
||||
// Let's parse choice blocks.
|
||||
@ -383,7 +328,6 @@ namespace dms {
|
||||
The NOOP ensures the pattern stays.
|
||||
If we are provided with a number greater than 3 then we can push an execption.
|
||||
*/
|
||||
std::string str = concat("$",stream->peek().line_num);
|
||||
while (!stream->match(tokens::cbracketc)) {
|
||||
if (stream->match(tokens::cbracketo) && !start) {
|
||||
start = true;
|
||||
@ -400,7 +344,7 @@ namespace dms {
|
||||
if (match_process_function(stream,nullptr,false)) { // No returns and also no nesting of functions!
|
||||
// We cannot have a nested function here, but if we dont have that then we add our goto
|
||||
hasfunc = true;
|
||||
buildGoto(str);
|
||||
buildGoto(choicelabel);
|
||||
}
|
||||
else if (match_process_goto(stream)) {
|
||||
buildNoop(); // Add noop to post-goto command
|
||||
@ -424,11 +368,9 @@ namespace dms {
|
||||
current_chunk->cmds.pop_back();
|
||||
delete cc;
|
||||
if (hasfunc)
|
||||
buildLabel(str);
|
||||
//lastCall.pop();
|
||||
buildLabel(choicelabel);
|
||||
return true;
|
||||
}
|
||||
//lastCall.pop();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -437,7 +379,6 @@ namespace dms {
|
||||
delete[] v; // We didn't need it, lets clean it up!
|
||||
}
|
||||
bool LineParser::match_process_function(tokenstream* stream, value* v, bool nested) {
|
||||
//lastCall.push("MP_function");
|
||||
/*
|
||||
Functions should be able to handle function calls as arguments,
|
||||
HOWEVER functions cannot be passed as values since they aren't values like they are in other languages!
|
||||
@ -504,9 +445,9 @@ namespace dms {
|
||||
tempstream.init(&t); // Turn tokens we consumed into a tokenstream
|
||||
value* tempval;
|
||||
token tok;
|
||||
value* ref = buildVariable();
|
||||
// This part we add values to the opcodes for the bytecode FUNC val a1 a2 a3 ... an
|
||||
while (tempstream.peek().type != tokens::none) { // End of stream
|
||||
print("> ", tempstream.peek());
|
||||
tempval = buildVariable();
|
||||
tok = tempstream.peek();
|
||||
if (tempstream.match(tokens::seperator)) {
|
||||
@ -576,7 +517,6 @@ namespace dms {
|
||||
}
|
||||
}
|
||||
}
|
||||
//lastCall.pop();
|
||||
return false;
|
||||
}
|
||||
bool LineParser::match_process_goto(tokenstream* stream) {
|
||||
@ -637,21 +577,10 @@ namespace dms {
|
||||
// I will have to consume for this to work so we need to keep track of what was incase we return false!
|
||||
stream->store(current_chunk);
|
||||
cmd* lastcmd = nullptr;
|
||||
/*if(!current_chunk->cmds.empty())
|
||||
lastcmd = current_chunk->cmds.back();*/
|
||||
// It has to start with one of these 3 to even be considered an expression
|
||||
if (stream->match(tokens::number) || stream->match(tokens::name) || stream->match(tokens::parao)) {
|
||||
// What do we know, math expressions can only be on a single line. We know where to stop looking if we have to
|
||||
cmd* c = new cmd;
|
||||
/*
|
||||
* We have a few built-in methods we will have to handle
|
||||
* ADD val v1 v2
|
||||
* SUB val v1 v2
|
||||
* MUL val v1 v2
|
||||
* DIV val v1 v2
|
||||
* POW val v1 v2
|
||||
* MOD val v1 v2
|
||||
*/
|
||||
value* wv = nullptr;
|
||||
value* left; // lefthand
|
||||
codes::op op; // opperator
|
||||
@ -761,7 +690,7 @@ namespace dms {
|
||||
else
|
||||
badSymbol(stream);
|
||||
}
|
||||
else if (/*stream->match(tokens::newline) || */stream->match(tokens::parac) || stream->match(tokens::seperator)) {
|
||||
else if (stream->match(tokens::newline) || stream->match(tokens::parac) || stream->match(tokens::seperator)) {
|
||||
if (wv == nullptr)
|
||||
return stream->restore(lastcmd, current_chunk); // Always return false and restores the position in stream!
|
||||
cmd* cc = new cmd;
|
||||
@ -769,6 +698,7 @@ namespace dms {
|
||||
cc->args.push(v);
|
||||
cc->args.push(wv);
|
||||
current_chunk->addCmd(cc);
|
||||
if(stream->match(tokens::parac))
|
||||
stream->next();
|
||||
// We done!
|
||||
int t=0;
|
||||
|
||||
@ -131,9 +131,18 @@ namespace dms {
|
||||
t_vec.push_back(token{ tokens::seperator,codes::NOOP,",",line });
|
||||
}
|
||||
else if (data == '.') {
|
||||
//doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
|
||||
// If a number starts with a .## then we need to ensure that we create the value properly
|
||||
if (std::isdigit(stream.peek()) && buffer.size()==0) {
|
||||
// If the buffer has data then something isn't right
|
||||
isNum = true;
|
||||
buffer.push_back('0');
|
||||
buffer.push_back('.');
|
||||
}
|
||||
else {
|
||||
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
|
||||
t_vec.push_back(token{ tokens::dot,codes::NOOP,".",line });
|
||||
}
|
||||
}
|
||||
else if (data == '{') {
|
||||
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
|
||||
t_vec.push_back(token{ tokens::cbracketo,codes::NOOP,"{",line });
|
||||
@ -296,7 +305,6 @@ namespace dms {
|
||||
}
|
||||
t_vec.push_back(token{ tokens::eof,codes::NOOP,"",line - 1 });
|
||||
tokenDump(&t_vec);
|
||||
print("Running tokenizer");
|
||||
// Tokens build let's parse
|
||||
tokenizer(state, t_vec);
|
||||
return state;
|
||||
@ -321,8 +329,9 @@ namespace dms {
|
||||
}
|
||||
void LineParser::_Parse(tokenstream* stream) {
|
||||
token current = stream->next();
|
||||
createBlock("$INIT", blocktype::bt_block);
|
||||
cmd* flagcmd = new cmd;
|
||||
while (stream->peek().type != tokens::eof) {
|
||||
print(current);
|
||||
if (current.type == tokens::flag) {
|
||||
temp = stream->next(tokens::newline);
|
||||
stream->prev(); // Unconsume the newline piece
|
||||
@ -333,33 +342,51 @@ namespace dms {
|
||||
tokens::tokentype tok = temp[0].type;
|
||||
if (code == codes::ENAB && tok == tokens::name) {
|
||||
tolower(temp[0].name);
|
||||
state->enables.insert_or_assign(temp[0].name, true);
|
||||
state->enable(temp[0].name);
|
||||
flagcmd->opcode = code;
|
||||
flagcmd->args.push(buildValue(temp[0].name));
|
||||
current_chunk->addCmd(flagcmd);
|
||||
flagcmd = new cmd;
|
||||
}
|
||||
else if (code == codes::ENTR && tok == tokens::name) {
|
||||
state->entry = temp[0].name;
|
||||
flagcmd->opcode = code;
|
||||
flagcmd->args.push(buildValue(temp[0].name));
|
||||
current_chunk->addCmd(flagcmd);
|
||||
flagcmd = new cmd;
|
||||
}
|
||||
else if (code == codes::DISA && tok == tokens::name) {
|
||||
tolower(temp[0].name);
|
||||
state->enables.insert_or_assign(temp[0].name, false);
|
||||
state->disable(temp[0].name);
|
||||
flagcmd->opcode = code;
|
||||
flagcmd->args.push(buildValue(temp[0].name));
|
||||
current_chunk->addCmd(flagcmd);
|
||||
flagcmd = new cmd;
|
||||
}
|
||||
else if (code == codes::VERN && tok == tokens::number) {
|
||||
state->version = std::stod(temp[0].name);
|
||||
flagcmd->opcode = code;
|
||||
flagcmd->args.push(buildValue(std::stod(temp[0].name)));
|
||||
current_chunk->addCmd(flagcmd);
|
||||
flagcmd = new cmd;
|
||||
}
|
||||
else if (code == codes::USIN && tok == tokens::name) {
|
||||
// TODO add usings, kinda useless atm since everything will be packed in. Perhaps extensions?
|
||||
}
|
||||
else if (code == codes::LOAD && tok == tokens::string) {
|
||||
flagcmd->opcode = code;
|
||||
flagcmd->args.push(buildValue(temp[0].name));
|
||||
current_chunk->addCmd(flagcmd);
|
||||
flagcmd = new cmd;
|
||||
LineParser parser = LineParser();
|
||||
parser.Parse(state, temp[0].name);// Load another file
|
||||
}
|
||||
else {
|
||||
std::stringstream str;
|
||||
str << "Expected <FLAG IDENTIFIER> " << " got: " << current << temp[0];
|
||||
state->push_error(errors::error{ errors::badtoken,str.str(),true,line,current_chunk });
|
||||
state->push_error(errors::error{ errors::badtoken,concat("Expected <FLAG IDENTIFIER> got: ", current, temp[0]),true,line,current_chunk });
|
||||
}
|
||||
}
|
||||
// Default block
|
||||
if (stream->match(tokens::newline,tokens::bracketo, tokens::name, tokens::bracketc)) {
|
||||
if (stream->match(tokens::newline,tokens::bracketo, tokens::name, tokens::bracketc,tokens::newline)) {
|
||||
stream->next();
|
||||
stream->next();
|
||||
std::string name = stream->next().name;
|
||||
@ -449,6 +476,6 @@ namespace dms {
|
||||
match_process_function(stream); // Naked Function
|
||||
current = stream->next();
|
||||
}
|
||||
createBlock("$END$", bt_block);
|
||||
createBlock("$END", blocktype::bt_block);// Runs code that ensures that last user block is processed into the chunks array. Yes, I could have simply added in the lines of code at the end, but I didn't want to rewrite code again!
|
||||
}
|
||||
}
|
||||
@ -217,21 +217,59 @@ namespace dms {
|
||||
}
|
||||
bool LineParser::createBlock(std::string bk_name, blocktype bk_type) {
|
||||
if (current_chunk != nullptr) {
|
||||
if (!state->chunks.count(current_chunk->name))
|
||||
if (state->chunks.count(bk_name)==0 && bk_name!="$END")
|
||||
state->push_chunk(current_chunk->name, current_chunk);
|
||||
else
|
||||
{
|
||||
if (bk_name == "$INIT") {
|
||||
current_chunk = state->chunks["$INIT"];
|
||||
return true;
|
||||
}
|
||||
else if (bk_name == "$END") {
|
||||
cmd* c = new cmd;
|
||||
c->opcode = codes::JUMP;
|
||||
c->args.push(buildVariable("$END"));
|
||||
current_chunk->addCmd(c);
|
||||
state->push_chunk(current_chunk->name, current_chunk);
|
||||
current_chunk = state->chunks["$END"];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
std::stringstream str;
|
||||
str << "Block <" << current_chunk->name << "> already defined!";
|
||||
state->push_error(errors::error{ errors::block_already_defined,str.str(),true,line,current_chunk });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state->isEnabled("leaking") && (current_chunk != nullptr && current_chunk->name != "$INIT")) {
|
||||
cmd* c = new cmd;
|
||||
c->opcode = codes::JUMP;
|
||||
c->args.push(buildVariable(bk_name));
|
||||
current_chunk->addCmd(c);
|
||||
}
|
||||
if (current_chunk!= nullptr && current_chunk->name == "$INIT") {
|
||||
cmd* c = new cmd;
|
||||
c->opcode = codes::JUMP;
|
||||
if(state->entry!="$undefined")
|
||||
c->args.push(buildVariable(state->entry));
|
||||
else
|
||||
c->args.push(buildVariable(bk_name));
|
||||
current_chunk->addCmd(c);
|
||||
}
|
||||
if (current_chunk != nullptr && current_chunk->name == "$END") {
|
||||
cmd* c = new cmd;
|
||||
c->opcode = codes::EXIT;
|
||||
if (state->entry != "$undefined")
|
||||
c->args.push(buildValue(0));
|
||||
else
|
||||
c->args.push(buildVariable(bk_name));
|
||||
current_chunk->addCmd(c);
|
||||
}
|
||||
current_chunk = new chunk;
|
||||
current_chunk->name = bk_name;
|
||||
chunk_type = bk_type;
|
||||
current_chunk->type = bk_type;
|
||||
|
||||
return true;
|
||||
}
|
||||
void LineParser::tokenizer(dms_state* state,std::vector<token> &toks) {
|
||||
|
||||
@ -45,7 +45,7 @@ namespace dms::codes {
|
||||
DIV,
|
||||
POW,
|
||||
MOD,
|
||||
LIST
|
||||
LIST,
|
||||
};
|
||||
extern const std::string list[];
|
||||
static bool isControl(const op code) {
|
||||
|
||||
@ -7,6 +7,20 @@ namespace dms {
|
||||
enables.insert_or_assign("warnings",false); //
|
||||
enables.insert_or_assign("statesave",true); // Allows you to save state
|
||||
enables.insert_or_assign("omniscient",true); // Allows you to know who's who when you first meet them
|
||||
chunk* c = new chunk;
|
||||
c->name = "$END";
|
||||
c->type = blocktype::bt_block;
|
||||
cmd* cc = new cmd;
|
||||
cc->opcode = codes::EXIT;
|
||||
cc->args.push(buildValue(0));
|
||||
c->addCmd(cc);
|
||||
push_chunk("$END", c);
|
||||
}
|
||||
void dms_state::enable(std::string flag) {
|
||||
enables[flag] = true;
|
||||
}
|
||||
void dms_state::disable(std::string flag) {
|
||||
enables[flag] = false;
|
||||
}
|
||||
bool dms_state::isEnabled(std::string flag) {
|
||||
if (enables.count(flag)) {
|
||||
@ -41,12 +55,13 @@ namespace dms {
|
||||
}
|
||||
void dms_state::push_error(errors::error err) {
|
||||
std::cout << err.err_msg << " On Line <" << err.linenum << ">" << std::endl;
|
||||
this->err = err;
|
||||
if (err.crash)
|
||||
std::exit(err.code);
|
||||
stop = true;
|
||||
}
|
||||
void dms_state::push_warning(errors::error err) {
|
||||
err.crash = false; // Force code to not crash then push the error
|
||||
if(enables.count("warnings"))
|
||||
if(isEnabled("warnings"))
|
||||
push_error(err);
|
||||
}
|
||||
}
|
||||
@ -5,20 +5,27 @@
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
namespace dms {
|
||||
class dms_state
|
||||
struct dms_state
|
||||
{
|
||||
public:
|
||||
std::unordered_map<std::string, value*> memory;
|
||||
std::map<std::string, chunk*> chunks;
|
||||
std::string entry = "$undefined";
|
||||
std::map<std::string, bool> enables;
|
||||
errors::error err;
|
||||
bool stop = false;
|
||||
|
||||
dms_state();
|
||||
void dump(errors::error err);
|
||||
void dump();
|
||||
void push_error(errors::error err);
|
||||
void push_warning(errors::error err);
|
||||
void push_chunk(std::string s, chunk* c);
|
||||
bool run(std::string instance = "Main");
|
||||
double version=1.0;
|
||||
std::map<std::string, chunk*> chunks;
|
||||
std::string entry = "start";
|
||||
std::map<std::string, bool> enables;
|
||||
void enable(std::string flag);
|
||||
void disable(std::string flag);
|
||||
bool isEnabled(std::string flag);
|
||||
};
|
||||
}
|
||||
|
||||
18
DMS/dms_state_interpret.cpp
Normal file
18
DMS/dms_state_interpret.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "dms_state.h"
|
||||
namespace dms {
|
||||
// Instance, multiple instances can allow different code to work side by side
|
||||
bool dms_state::run(std::string instance) {
|
||||
codes::op code;
|
||||
//TODO: parse the cmds and do stuff
|
||||
|
||||
/*switch (code)
|
||||
{
|
||||
case codes::NOOP:
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
BIN
DMS/dump.bin
BIN
DMS/dump.bin
Binary file not shown.
342
DMS/dump.txt
342
DMS/dump.txt
@ -2,8 +2,7 @@ Token Dump:
|
||||
Line <1> newline
|
||||
Line <1> newline
|
||||
Line <1> flag
|
||||
Line <1> name main
|
||||
Line <1> newline
|
||||
Line <1> name test
|
||||
Line <1> newline
|
||||
Line <2> flag
|
||||
Line <2> name warnings
|
||||
@ -14,65 +13,70 @@ Line <3> name omniscient
|
||||
Line <3> newline
|
||||
Line <3> newline
|
||||
Line <4> flag
|
||||
Line <4> name debugging
|
||||
Line <4> name leaking
|
||||
Line <4> newline
|
||||
Line <4> newline
|
||||
Line <5> flag
|
||||
Line <5> name debugging
|
||||
Line <5> newline
|
||||
Line <5> newline
|
||||
Line <6> flag
|
||||
Line <6> number 1.2
|
||||
Line <6> string loadtest.dms
|
||||
Line <6> newline
|
||||
Line <6> newline
|
||||
Line <7> flag
|
||||
Line <7> name extendedDefine
|
||||
Line <7> number 1.2
|
||||
Line <7> newline
|
||||
Line <7> newline
|
||||
Line <8> flag
|
||||
Line <8> name extendedDefine
|
||||
Line <8> newline
|
||||
Line <8> newline
|
||||
Line <9> bracketo [
|
||||
Line <9> name main
|
||||
Line <9> bracketc ]
|
||||
Line <9> newline
|
||||
Line <9> newline
|
||||
Line <10> string Testing
|
||||
Line <10> bracketo [
|
||||
Line <10> name main
|
||||
Line <10> bracketc ]
|
||||
Line <10> newline
|
||||
Line <10> newline
|
||||
Line <11> name Bob
|
||||
Line <11> colon :
|
||||
Line <11> cbracketo {
|
||||
Line <11> string Testing
|
||||
Line <11> newline
|
||||
Line <11> newline
|
||||
Line <12> name speed
|
||||
Line <12> number 50
|
||||
Line <12> name Bob
|
||||
Line <12> colon :
|
||||
Line <12> cbracketo {
|
||||
Line <12> newline
|
||||
Line <12> newline
|
||||
Line <13> name excited
|
||||
Line <13> colon :
|
||||
Line <13> string Hello Ryan!
|
||||
Line <13> name speed
|
||||
Line <13> number 50
|
||||
Line <13> newline
|
||||
Line <13> newline
|
||||
Line <14> name wait
|
||||
Line <14> number 200
|
||||
Line <14> name excited
|
||||
Line <14> colon :
|
||||
Line <14> string Hello Ryan!
|
||||
Line <14> newline
|
||||
Line <14> newline
|
||||
Line <15> string How are you doing?
|
||||
Line <15> name wait
|
||||
Line <15> number 200
|
||||
Line <15> newline
|
||||
Line <15> newline
|
||||
Line <16> cbracketc }
|
||||
Line <16> string How are you doing?
|
||||
Line <16> newline
|
||||
Line <16> newline
|
||||
Line <17> cbracketc }
|
||||
Line <17> newline
|
||||
Line <17> newline
|
||||
Line <18> name Ryan
|
||||
Line <18> colon :
|
||||
Line <18> cbracketo {
|
||||
Line <18> newline
|
||||
Line <18> newline
|
||||
Line <19> string Hey Bob I'm good how are you?
|
||||
Line <19> name Ryan
|
||||
Line <19> colon :
|
||||
Line <19> cbracketo {
|
||||
Line <19> newline
|
||||
Line <19> newline
|
||||
Line <20> cbracketc }
|
||||
Line <20> string Hey Bob I'm good how are you?
|
||||
Line <20> newline
|
||||
Line <20> newline
|
||||
Line <21> cbracketc }
|
||||
Line <21> newline
|
||||
Line <21> newline
|
||||
Line <22> name Bob
|
||||
@ -82,135 +86,239 @@ Line <22> newline
|
||||
Line <22> newline
|
||||
Line <23> newline
|
||||
Line <23> newline
|
||||
Line <24> name list
|
||||
Line <24> equal =
|
||||
Line <24> control
|
||||
Line <24> string What do you want to do?
|
||||
Line <24> cbracketo {
|
||||
Line <24> newline
|
||||
Line <24> newline
|
||||
Line <25> string Hello
|
||||
Line <25> seperator ,
|
||||
Line <25> string option 0
|
||||
Line <25> name test2
|
||||
Line <25> parao (
|
||||
Line <25> string testing
|
||||
Line <25> parac )
|
||||
Line <25> newline
|
||||
Line <25> newline
|
||||
Line <26> true true
|
||||
Line <26> seperator ,
|
||||
Line <26> string option 1
|
||||
Line <26> jump
|
||||
Line <26> string here
|
||||
Line <26> newline
|
||||
Line <26> newline
|
||||
Line <27> nil nil
|
||||
Line <27> seperator ,
|
||||
Line <27> string option 2
|
||||
Line <27> jump
|
||||
Line <27> name there
|
||||
Line <27> newline
|
||||
Line <27> newline
|
||||
Line <28> parao (
|
||||
Line <28> number 1000
|
||||
Line <28> plus +
|
||||
Line <28> string option 3
|
||||
Line <28> gotoo
|
||||
Line <28> string o3
|
||||
Line <28> newline
|
||||
Line <28> newline
|
||||
Line <29> number 342
|
||||
Line <29> parac )
|
||||
Line <29> divide /
|
||||
Line <29> name hi
|
||||
Line <29> seperator ,
|
||||
Line <29> false false
|
||||
Line <29> seperator ,
|
||||
Line <29> string option 4
|
||||
Line <29> gotoo
|
||||
Line <29> name here
|
||||
Line <29> newline
|
||||
Line <29> newline
|
||||
Line <30> string option 5
|
||||
Line <30> name test
|
||||
Line <30> parao (
|
||||
Line <30> number 1
|
||||
Line <30> seperator ,
|
||||
Line <30> number 2
|
||||
Line <30> string here
|
||||
Line <30> parac )
|
||||
Line <30> seperator ,
|
||||
Line <30> newline
|
||||
Line <30> newline
|
||||
Line <31> cbracketo {
|
||||
Line <31> cbracketc }
|
||||
Line <31> newline
|
||||
Line <31> newline
|
||||
Line <32> number 1
|
||||
Line <32> seperator ,
|
||||
Line <32> newline
|
||||
Line <32> newline
|
||||
Line <33> false false
|
||||
Line <33> seperator ,
|
||||
Line <33> bracketo [
|
||||
Line <33> name Bob
|
||||
Line <33> colon :
|
||||
Line <33> name char
|
||||
Line <33> bracketc ]
|
||||
Line <33> newline
|
||||
Line <33> newline
|
||||
Line <34> nil nil
|
||||
Line <34> name age
|
||||
Line <34> equal =
|
||||
Line <34> number .24
|
||||
Line <34> newline
|
||||
Line <34> newline
|
||||
Line <35> cbracketc }
|
||||
Line <35> name money
|
||||
Line <35> equal =
|
||||
Line <35> number 100
|
||||
Line <35> newline
|
||||
Line <35> newline
|
||||
Line <36> cbracketc }
|
||||
Line <36> name excited
|
||||
Line <36> colon :
|
||||
Line <36> string path/to/file
|
||||
Line <36> name function
|
||||
Line <36> newline
|
||||
Line <36> newline
|
||||
Line <37> newline
|
||||
Line <37> newline
|
||||
Line <38> name test
|
||||
Line <38> bracketo [
|
||||
Line <38> name newblock
|
||||
Line <38> colon :
|
||||
Line <38> name function
|
||||
Line <38> parao (
|
||||
Line <38> parac )
|
||||
Line <38> bracketc ]
|
||||
Line <38> newline
|
||||
Line <38> newline
|
||||
Line <39> cbracketo {
|
||||
Line <39> string Test #2
|
||||
Line <39> newline
|
||||
Line <39> newline
|
||||
Line <40> number 1
|
||||
Line <40> seperator ,
|
||||
Line <40> string Does it parse this part properly?
|
||||
Line <40> newline
|
||||
Line <40> newline
|
||||
Line <41> number 2
|
||||
Line <41> seperator ,
|
||||
Line <41> string huh
|
||||
Line <41> newline
|
||||
Line <41> newline
|
||||
Line <42> number 3
|
||||
Line <42> newline
|
||||
Line <42> newline
|
||||
Line <43> cbracketc }
|
||||
Line <43> newline
|
||||
Line <43> newline
|
||||
Line <44> parac )
|
||||
Line <44> newline
|
||||
Line <44> newline
|
||||
Line <45> newline
|
||||
Line <45> newline
|
||||
Line <46> bracketo [
|
||||
Line <46> name Bob
|
||||
Line <46> colon :
|
||||
Line <46> name char
|
||||
Line <46> bracketc ]
|
||||
Line <46> newline
|
||||
Line <46> newline
|
||||
Line <47> name age
|
||||
Line <47> equal =
|
||||
Line <47> number 24
|
||||
Line <47> newline
|
||||
Line <47> newline
|
||||
Line <48> name money
|
||||
Line <48> equal =
|
||||
Line <48> number 100
|
||||
Line <48> newline
|
||||
Line <48> newline
|
||||
Line <49> name excited
|
||||
Line <49> colon :
|
||||
Line <49> string path/to/file
|
||||
Line <49> name function
|
||||
Line <49> newline
|
||||
Line <49> newline
|
||||
Line <50> newline
|
||||
Line <50> newline
|
||||
Line <51> bracketo [
|
||||
Line <51> name newblock
|
||||
Line <51> colon :
|
||||
Line <51> name function
|
||||
Line <51> parao (
|
||||
Line <51> parac )
|
||||
Line <51> bracketc ]
|
||||
Line <51> newline
|
||||
Line <51> newline
|
||||
Line <52> string Test #2
|
||||
Line <52> newline
|
||||
Line <52> newline
|
||||
Line <53> string Does it parse this part properly?
|
||||
Line <53> newline
|
||||
Line <53> newline
|
||||
Line <54> string huh
|
||||
Line <54> newline
|
||||
Line <54> newline
|
||||
Line <54> eof
|
||||
Line <41> eof
|
||||
Line <1> newline
|
||||
Line <1> newline
|
||||
Line <1> bracketo [
|
||||
Line <1> name default
|
||||
Line <1> colon :
|
||||
Line <1> name char
|
||||
Line <1> bracketc ]
|
||||
Line <1> newline
|
||||
Line <1> newline
|
||||
Line <2> newline
|
||||
Line <3> name money
|
||||
Line <3> equal =
|
||||
Line <3> number 0
|
||||
Line <3> newline
|
||||
Line <3> newline
|
||||
Line <4> name test
|
||||
Line <4> equal =
|
||||
Line <4> nil nil
|
||||
Line <4> newline
|
||||
Line <4> newline
|
||||
Line <5> newline
|
||||
Line <5> newline
|
||||
Line <6> bracketo [
|
||||
Line <6> name Ryan
|
||||
Line <6> colon :
|
||||
Line <6> name char
|
||||
Line <6> bracketc ]
|
||||
Line <6> newline
|
||||
Line <6> newline
|
||||
Line <7> name age
|
||||
Line <7> equal =
|
||||
Line <7> number 21
|
||||
Line <7> newline
|
||||
Line <7> newline
|
||||
Line <8> name money
|
||||
Line <8> equal =
|
||||
Line <8> number 1000
|
||||
Line <8> newline
|
||||
Line <8> newline
|
||||
Line <9> newline
|
||||
Line <10> name calm
|
||||
Line <10> colon :
|
||||
Line <10> string ./path/to/file
|
||||
Line <10> newline
|
||||
Line <10> newline
|
||||
Line <11> name excited
|
||||
Line <11> colon :
|
||||
Line <11> string ./path/to/file
|
||||
Line <11> newline
|
||||
Line <11> newline
|
||||
Line <12> newline
|
||||
Line <12> newline
|
||||
Line <13> bracketo [
|
||||
Line <13> name step
|
||||
Line <13> colon :
|
||||
Line <13> name function
|
||||
Line <13> parao (
|
||||
Line <13> name a
|
||||
Line <13> seperator ,
|
||||
Line <13> name b
|
||||
Line <13> seperator ,
|
||||
Line <13> name c
|
||||
Line <13> parac )
|
||||
Line <13> bracketc ]
|
||||
Line <13> newline
|
||||
Line <13> newline
|
||||
Line <14> string Testing...
|
||||
Line <14> newline
|
||||
Line <15> name d
|
||||
Line <15> equal =
|
||||
Line <15> parao (
|
||||
Line <15> number 100
|
||||
Line <15> plus +
|
||||
Line <15> name b
|
||||
Line <15> parac )
|
||||
Line <15> divide /
|
||||
Line <15> name c
|
||||
Line <15> newline
|
||||
Line <15> newline
|
||||
Line <16> name e
|
||||
Line <16> equal =
|
||||
Line <16> string somestring
|
||||
Line <16> newline
|
||||
Line <16> newline
|
||||
Line <17> name e
|
||||
Line <17> equal =
|
||||
Line <17> nil nil
|
||||
Line <17> newline
|
||||
Line <17> newline
|
||||
Line <18> name g
|
||||
Line <18> equal =
|
||||
Line <18> false false
|
||||
Line <18> newline
|
||||
Line <18> newline
|
||||
Line <19> ret
|
||||
Line <19> name d
|
||||
Line <19> newline
|
||||
Line <19> newline
|
||||
Line <20> newline
|
||||
Line <20> newline
|
||||
Line <21> bracketo [
|
||||
Line <21> name inventory
|
||||
Line <21> colon :
|
||||
Line <21> name env
|
||||
Line <21> bracketc ]
|
||||
Line <21> newline
|
||||
Line <21> newline
|
||||
Line <22> name slot1
|
||||
Line <22> equal =
|
||||
Line <22> string
|
||||
Line <22> newline
|
||||
Line <22> newline
|
||||
Line <23> name slot2
|
||||
Line <23> equal =
|
||||
Line <23> string
|
||||
Line <23> newline
|
||||
Line <23> newline
|
||||
Line <24> name slot3
|
||||
Line <24> equal =
|
||||
Line <24> string
|
||||
Line <24> newline
|
||||
Line <24> newline
|
||||
Line <25> name slot4
|
||||
Line <25> equal =
|
||||
Line <25> string
|
||||
Line <25> newline
|
||||
Line <25> newline
|
||||
Line <26> name slot5
|
||||
Line <26> equal =
|
||||
Line <26> string
|
||||
Line <26> newline
|
||||
Line <26> newline
|
||||
Line <27> name slot6
|
||||
Line <27> equal =
|
||||
Line <27> string
|
||||
Line <27> newline
|
||||
Line <27> newline
|
||||
Line <28> name slot7
|
||||
Line <28> equal =
|
||||
Line <28> string
|
||||
Line <28> newline
|
||||
Line <28> newline
|
||||
Line <29> name slot8
|
||||
Line <29> equal =
|
||||
Line <29> string
|
||||
Line <29> newline
|
||||
Line <29> newline
|
||||
Line <29> eof
|
||||
|
||||
35
DMS/test.dms
35
DMS/test.dms
@ -1,8 +1,9 @@
|
||||
entry main
|
||||
entry test // Will either start the first block seen or the block supplied by you!
|
||||
enable warnings
|
||||
disable omniscient
|
||||
enable leaking
|
||||
enable debugging
|
||||
//loadfile "loadtest.dms"
|
||||
loadfile "loadtest.dms"
|
||||
version 1.2
|
||||
using extendedDefine
|
||||
|
||||
@ -18,33 +19,19 @@ using extendedDefine
|
||||
Ryan: {
|
||||
"Hey Bob I'm good how are you?"
|
||||
}
|
||||
|
||||
Bob: "Testing..."
|
||||
|
||||
list = {
|
||||
"Hello",
|
||||
true,
|
||||
nil,
|
||||
(1000+
|
||||
342)/hi,false,
|
||||
test(1,2),
|
||||
{
|
||||
1,
|
||||
false,
|
||||
nil
|
||||
choice "What do you want to do?" {
|
||||
"option 0" test2("testing")
|
||||
"option 1" jump "here"
|
||||
"option 2" jump there
|
||||
"option 3" goto "o3"
|
||||
"option 4" goto here
|
||||
"option 5" test("here")
|
||||
}
|
||||
}
|
||||
|
||||
test(
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3
|
||||
}
|
||||
)
|
||||
|
||||
[Bob:char]
|
||||
age = 24
|
||||
age = .24
|
||||
money = 100
|
||||
excited: "path/to/file" | function
|
||||
|
||||
|
||||
@ -1,10 +1,23 @@
|
||||
#include "value.h"
|
||||
#include "utils.h"
|
||||
#include "string"
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
namespace dms {
|
||||
std::vector<value*> _VALUES;
|
||||
value::value() {
|
||||
_VALUES.push_back(this); // Used for the interperter! In the end everything is a value
|
||||
// We need to clean up this stuff when it all comes crashing.
|
||||
// We also might clean things while the code is running.
|
||||
// Values at runtime aren't "Deleted, they are set to nil"
|
||||
// At the end we actually delete them!
|
||||
}
|
||||
value* value::resolve(std::unordered_map<std::string, value*> map, value* v) {
|
||||
if (v != nullptr) {
|
||||
if (this->type == datatypes::variable) {
|
||||
return resolve(map, map[this->s->getValue()]); // Variable types return the value
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
void dms_args::push(value* val) {
|
||||
args.push_back(val);
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
|
||||
namespace dms {
|
||||
struct dms_env;
|
||||
@ -41,15 +42,14 @@ namespace dms {
|
||||
dms_boolean* buildBool(bool b);
|
||||
dms_number* buildNumber(double num);
|
||||
struct value {
|
||||
/*~value() {
|
||||
nuke();
|
||||
}*/
|
||||
datatypes type = nil;
|
||||
dms_boolean* b = nullptr;
|
||||
dms_number* n = nullptr;
|
||||
dms_string* s = nullptr;
|
||||
dms_env* e = nullptr;
|
||||
dms_custom* c = nullptr;
|
||||
value();
|
||||
value* resolve(std::unordered_map<std::string,value*> map,value* v=nullptr);
|
||||
void nuke();
|
||||
void set(dms_string* str);
|
||||
void set(dms_boolean* bo);
|
||||
|
||||
BIN
Debug/DMS.exe
BIN
Debug/DMS.exe
Binary file not shown.
BIN
Debug/DMS.ilk
BIN
Debug/DMS.ilk
Binary file not shown.
BIN
Debug/DMS.pdb
BIN
Debug/DMS.pdb
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user