diff --git a/DMS/Character.h b/DMS/Character.h index 5510591..eefa71a 100644 --- a/DMS/Character.h +++ b/DMS/Character.h @@ -6,9 +6,12 @@ namespace dms { struct character { std::string fname = ""; std::string lname = ""; + std::string unknown = "Unknown"; + std::string nickname = ""; bool seen = false; double spd = 100; std::unordered_map paths; std::unordered_map values; + std::string getName(); }; } \ No newline at end of file diff --git a/DMS/DMS.cpp b/DMS/DMS.cpp index 157e43a..b839caf 100644 --- a/DMS/DMS.cpp +++ b/DMS/DMS.cpp @@ -1,11 +1,9 @@ #include "dms.h" -#include "Handlers.h" -#include "utils.h" #include using namespace dms; // You can use your own choice handler! class myHandler : public Handler { - uint8_t manageChoice(dms_state* state, std::string prompt, std::vector args) const override { + uint8_t handleChoice(dms_state* state, std::string prompt, std::vector args) const override { std::string pos; for (size_t i = 0; i < args.size(); i++) std::cout << i << ": " << args[i] << std::endl; diff --git a/DMS/DMS.vcxproj b/DMS/DMS.vcxproj index e9f7214..dd463cb 100644 --- a/DMS/DMS.vcxproj +++ b/DMS/DMS.vcxproj @@ -142,6 +142,8 @@ + + @@ -160,7 +162,8 @@ - + + diff --git a/DMS/DMS.vcxproj.filters b/DMS/DMS.vcxproj.filters index 71b05d2..b5fd767 100644 --- a/DMS/DMS.vcxproj.filters +++ b/DMS/DMS.vcxproj.filters @@ -19,6 +19,12 @@ {e3410a7b-6408-4022-b606-2c14cfaac52c} + + {978b41cd-27e4-4b8c-874e-3b6e927b3d4d} + + + {4c0bb4c5-388c-4f15-abb7-143cb6d6232f} + @@ -67,7 +73,13 @@ Source Files\DMS - Source Files + Source Files\DMS + + + Source Files\DMS\blocks + + + Source Files\DMS\blocks @@ -111,10 +123,13 @@ Header Files\DMS - Header Files - - Header Files\DMS + + Header Files\DMS\blocks + + + Header Files\DMS\blocks + \ No newline at end of file diff --git a/DMS/Handlers.cpp b/DMS/Handlers.cpp index 8633c7f..f542385 100644 --- a/DMS/Handlers.cpp +++ b/DMS/Handlers.cpp @@ -1,6 +1,6 @@ #include "Handlers.h" namespace dms { - uint8_t Handler::manageChoice(dms_state* state, std::string prompt, std::vector args) const { + uint8_t Handler::handleChoice(dms_state* state, std::string prompt, std::vector args) const { std::string pos; for (size_t i = 0; i < args.size(); i++) std::cout << i+1 << ": " << args[i] << std::endl; @@ -14,8 +14,28 @@ namespace dms { } catch (std::exception e) { std::cout << "Invalid Choice!" << std::endl; - return manageChoice(state,prompt,args); + return handleChoice(state,prompt,args); } - + } + bool Handler::handleSpeaker(dms_state* state, character* speaker) const { + if (speaker == nullptr) + return false; // Something went wrong and we pushed the error! + if (speaker->seen) { + if (speaker->lname != "") { + utils::write(speaker->fname, " ", speaker->lname, ": "); + } + else { + utils::write(speaker->fname, ": "); + } + } + else { + utils::write(speaker->unknown, ": "); + speaker->seen = true; + } + } + + // Simple one conn event + bool Handler::OnSpeakerCreated(dms_state* state, character* chara) const { + return true; } } \ No newline at end of file diff --git a/DMS/Handlers.h b/DMS/Handlers.h index 73d6154..ec284c8 100644 --- a/DMS/Handlers.h +++ b/DMS/Handlers.h @@ -1,13 +1,16 @@ #pragma once #include "value.h" #include "utils.h" -#include "Character.h" +#include "character.h" #include namespace dms { struct Handler { - virtual uint8_t manageChoice(dms_state* state, std::string prompt, std::vector args) const; - //virtual bool manageSpeaker(dms_state* state, character* chara) const; + virtual uint8_t handleChoice(dms_state* state, std::string prompt, std::vector args) const; + virtual bool handleSpeaker(dms_state* state, character* chara) const; //virtual bool manageMessage(dms_state* state, value* msg) const; + + // Simple Events: only one connector! + virtual bool OnSpeakerCreated(dms_state* state, character* chara) const; }; } diff --git a/DMS/LineParserMatchProcess.cpp b/DMS/LineParserMatchProcess.cpp index 5d1d3c6..097603c 100644 --- a/DMS/LineParserMatchProcess.cpp +++ b/DMS/LineParserMatchProcess.cpp @@ -146,6 +146,20 @@ namespace dms { current_chunk->addCmd(new cmd{ codes::HALT }); return true; } + else if ((isBlock(bt_block) || isBlock(bt_method)) && stream->match(tokens::newline,tokens::pipe ,tokens::string, tokens::newline)) { + stream->next(); // Standard consumption + stream->next(); // pipe consumption + if (current_chunk->cmds.size() && current_chunk->cmds.back()->opcode == codes::HALT) { + current_chunk->cmds.pop_back(); + } + std::string msg = stream->next().name; + cmd* c = new cmd; + c->opcode = codes::APND; + c->args.push(buildValue(concat(" ", msg))); + current_chunk->addCmd(c); // Add the cmd to the current chunk + current_chunk->addCmd(new cmd{ codes::HALT }); + return true; + } else if (isBlock(bt_character) && stream->match(tokens::newline, tokens::name, tokens::colon, tokens::string, tokens::newline)) { stream->next(); // Standard consumption std::string name = stream->next().name; @@ -245,11 +259,6 @@ namespace dms { current_chunk->addCmd(new cmd{ codes::HALT }); return true; } - // 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)) { - return true; - } return false; } bool LineParser::match_process_assignment(tokenstream* stream) { @@ -318,31 +327,18 @@ namespace dms { The bytecode generated by this code might look something like this: off op opcodes - 0 CHOI "Pick one!" "Choice 1" "Choice 2" "Choice 3" "Choice 4" - 1 FUNC print "You picked 1!" - 2 GOTO $CHOI_END_1 - 3 FUNC print "You picked 2!" - 4 GOTO $CHOI_END_1 - 5 JUMP park - 6 NOOP - 7 GOTO mylabel - 8 LABL $CHOI_END_1 - - The CHOI code tells the vm that we need to process user input. The input we get in a number 0-3 - I know we have 4 choices - If the user provides us with a 0 then we need to move to off 1 - If the user provides us with a 1 then we need to move to off 3 - If the user provides us with a 2 then we need to move to off 5 - If the user provides us with a 3 then we need to move to off 7 - I'm sure you see the pattern here. 1 (+2) 3 (+2) 5... We only need to jump once then let the vm continue like normal. - The math for this is: [current_pos] + (n*2+1) - n*2+1 (n = 0) = 1 - n*2+1 (n = 1) = 3 - n*2+1 (n = 2) = 5 - n*2+1 (n = 3) = 7 - Which is why you see NOOP for the JUMP code. If GOTO wasn't the last choice possible to make there would be a NOOP after that as well. - The NOOP ensures the pattern stays. - If we are provided with a number greater than 3 then we can push an execption. + 0 CHOI "Pick one!" CHOI_filename_index "Choice 1" "Choice 2" "Choice 3" "Choice 4" + 1 LABL CHOI_filename_1 + 2 FUNC print "You picked 1!" + 3 GOTO $CHOI_END_1 + 4 LABL CHOI_filename_2 + 5 FUNC print "You picked 2!" + 6 GOTO $CHOI_END_1 + 7 LABL CHOI_filename_3 + 8 JUMP park + 9 LABL CHOI_filename_4 + 10 GOTO mylabel + 11 LABL $CHOI_END_1 */ while (!stream->match(tokens::cbracketc)) { debugInvoker(stream); @@ -451,6 +447,10 @@ namespace dms { tokenstream tempstream; // This is a balanced consuming method (()(())) std::vector t = stream->next(tokens::parao, tokens::parac); // Consume and get tokens + if (t.size() == 1) { // No arg function! + current_chunk->addCmd(c); + return true; + } token end = t.back(); t.pop_back(); t.push_back(token{ tokens::seperator,codes::NOOP,"",t[0].line_num }); @@ -548,7 +548,7 @@ namespace dms { return false; } bool LineParser::match_process_jump(tokenstream* stream) { - if (stream->match(tokens::jump, tokens::name) || tokens::jump, tokens::string) { + if (stream->match(tokens::jump, tokens::name) || stream->match(tokens::jump, tokens::string)) { cmd* c = new cmd; c->opcode = codes::JUMP; stream->next(); // consume jump diff --git a/DMS/LineParserParse.cpp b/DMS/LineParserParse.cpp index e49207c..2d91e1f 100644 --- a/DMS/LineParserParse.cpp +++ b/DMS/LineParserParse.cpp @@ -20,6 +20,11 @@ namespace dms { return Parse(state, fn); } dms_state* dms::LineParser::Parse(dms_state* state, std::string file) { + bool isFirst = false; + if (!state->hasFirst) { + isFirst = true; + state->hasFirst = true; + } std::vector t_vec; std::string li; std::ifstream myfile(file); @@ -88,6 +93,10 @@ namespace dms { buffer.push_back('"'); stream.next(); } + else if (data == '\\' && stream.peek() == 'n' && isStr) { + buffer.push_back('\n'); + stream.next(); + } else if (data == '"' && isStr) { isStr = false; t_vec.push_back(token{ tokens::string,codes::NOOP,stream.processBuffer(buffer),line }); @@ -199,6 +208,10 @@ namespace dms { doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer); t_vec.push_back(token{ tokens::backtick,codes::NOOP,"`",line }); } + else if (data == '|') { + doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer); + t_vec.push_back(token{ tokens::pipe,codes::NOOP,"|",line }); + } else if (data == '@') { doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer); t_vec.push_back(token{ tokens::at,codes::NOOP,"@",line }); @@ -307,6 +320,29 @@ namespace dms { tokenDump(&t_vec); // Tokens build let's parse tokenizer(state, t_vec); + if (isFirst) { + cmd* c = new cmd; + for (const auto& [key, val] : state->chunks) { + if (val->type == blocktype::bt_character) { + value* v = buildVariable(); + v->set(buildString(key)); + v->type = datatypes::block; + c->opcode = codes::ASGN; + c->args.push(buildVariable(key)); + c->args.push(v); + state->chunks["$INIT"]->addCmd(c); + c = new cmd; + } + } + + + c->opcode = codes::JUMP; + if (state->entry != "$undefined") + c->args.push(buildValue(state->entry)); + else + c->args.push(buildValue(state->chunks.begin()->first)); + state->chunks["$INIT"]->addCmd(c); + } return state; } void LineParser::tokenDump(std::vector* v) { @@ -338,6 +374,7 @@ namespace dms { current_chunk->addCmd(c); } while (stream->peek().type != tokens::eof) { + //print(stream->peek()); debugInvoker(stream); if (current.type == tokens::flag) { temp = stream->next(tokens::newline); @@ -381,10 +418,10 @@ namespace dms { // 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->opcode = code; flagcmd->args.push(buildValue(temp[0].name)); current_chunk->addCmd(flagcmd); - flagcmd = new cmd; + flagcmd = new cmd;*/ LineParser parser = LineParser(); parser.Parse(state, temp[0].name);// Load another file } @@ -470,17 +507,19 @@ namespace dms { // This will probably be the toughest one of them all } } - - // Displays both with a target and without + // Display cmd must be first!!! match_process_disp(stream); // Match and process dialogue + if (stream->match(tokens::newline,tokens::label)) { // Match and process labels stream->next(); buildLabel(stream->next().name); } + match_process_function(stream); // Naked Function match_process_assignment(stream); match_process_debug(stream); match_process_goto(stream); - match_process_function(stream); // Naked Function + + match_process_jump(stream); current = stream->next(); } 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! diff --git a/DMS/LineParserUtils.cpp b/DMS/LineParserUtils.cpp index d212c79..62437c6 100644 --- a/DMS/LineParserUtils.cpp +++ b/DMS/LineParserUtils.cpp @@ -230,7 +230,7 @@ namespace dms { } } bool LineParser::createBlock(std::string bk_name, blocktype bk_type) { - if (current_chunk != nullptr) { + if (current_chunk != nullptr || (bk_name == "$INIT" && state->chunks.count("$INIT"))) { if (state->chunks.count(bk_name)==0 && bk_name!="$END") state->push_chunk(current_chunk->name, current_chunk); else @@ -262,15 +262,6 @@ namespace dms { c->args.push(buildValue(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(buildValue(state->entry)); - else - c->args.push(buildValue(bk_name)); - current_chunk->addCmd(c); - } if (current_chunk != nullptr && current_chunk->name == "$END") { cmd* c = new cmd; c->opcode = codes::EXIT; @@ -284,6 +275,7 @@ namespace dms { current_chunk->name = bk_name; chunk_type = bk_type; current_chunk->type = bk_type; + state->push_chunk(bk_name, current_chunk); return true; } void LineParser::tokenizer(dms_state* state,std::vector &toks) { diff --git a/DMS/character.cpp b/DMS/character.cpp new file mode 100644 index 0000000..6230760 --- /dev/null +++ b/DMS/character.cpp @@ -0,0 +1,18 @@ +#include "character.h" +#include "utils.h" +namespace dms { + std::string character::getName() { + if (nickname != "") { + return nickname; + } + if (seen && lname !="") { + return utils::concat(fname," ", lname); + } + else if (seen) { + return utils::concat(fname); + } + else { + return unknown; + } + } +} \ No newline at end of file diff --git a/DMS/dms.h b/DMS/dms.h index a4c962f..95f02bb 100644 --- a/DMS/dms.h +++ b/DMS/dms.h @@ -1,4 +1,6 @@ #pragma once +#include "Handlers.h" +#include "character.h" #include "chunk.h" #include "cmd.h" #include "codes.h" diff --git a/DMS/dms_state.cpp b/DMS/dms_state.cpp index a6ddd94..b08edb6 100644 --- a/DMS/dms_state.cpp +++ b/DMS/dms_state.cpp @@ -7,7 +7,7 @@ namespace dms { enables.insert_or_assign("debugging",false); 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 + enables.insert_or_assign("omniscient",false); // Allows you to know who's who when you first meet them chunk* c = new chunk; c->name = "$END"; c->type = blocktype::bt_block; @@ -18,6 +18,13 @@ namespace dms { push_chunk("$END", c); setHandler(new Handler); // Use the default implementation } + bool dms_state::typeAssert(value* val, datatypes type) { + if (val->type != type) { + push_error(errors::error{ errors::invalid_type ,utils::concat("Expected a ",datatype[type]," got a ",datatype[val->type],"!") }); + return false; + } + return true; + } bool dms_state::characterExists(std::string bk_name) { return (chunks.count(bk_name) && chunks[bk_name]->type == blocktype::bt_character); } @@ -65,11 +72,13 @@ namespace dms { memory[var->s->getValue()] = val; } } - void dms_state::dump() { - std::cout << "Number of chunks: " << chunks.size() << std::endl; + void dms_state::dump(bool print) { + if (print) + std::cout << "Number of chunks: " << chunks.size() << std::endl; std::ofstream outputFile("dump.bin"); for (const auto& [key, val] : chunks) { - std::cout << "Key: " << key << "<" << getBlockType(val->type) << ">" << std::endl << *val << std::endl; + if(print) + std::cout << "Key: " << key << "<" << getBlockType(val->type) << ">" << std::endl << *val << std::endl; outputFile << "Key: " << key << "<" << getBlockType(val->type) << ">" << std::endl << *val << std::endl; } outputFile.close(); @@ -90,7 +99,9 @@ namespace dms { } void dms_state::push_warning(errors::error err) { err.crash = false; // Force code to not crash then push the error - if(isEnabled("warnings")) + if (isEnabled("warnings")) { + err.err_msg = utils::concat("Warning: ", err.err_msg); push_error(err); + } } } \ No newline at end of file diff --git a/DMS/dms_state.h b/DMS/dms_state.h index dc0c74f..605661c 100644 --- a/DMS/dms_state.h +++ b/DMS/dms_state.h @@ -16,6 +16,7 @@ namespace dms { struct dms_state { void* handler = nullptr; + bool hasFirst = false; std::unordered_map memory; std::vector garbage; std::map chunks; @@ -25,13 +26,13 @@ namespace dms { std::map enables; std::size_t cur_line=0; const double Iversion = 1.0; - double Cversion; // The version of + double Sversion; // The version of errors::error err; bool stop = false; dms_state(); void dump(errors::error err); - void dump(); + void dump(bool print=false); void push_error(errors::error err); void push_warning(errors::error err); void push_chunk(std::string s, chunk* c); @@ -43,11 +44,13 @@ namespace dms { void setHandler(void* hand); // Gets or creates a character + character* getCharacter(std::string c); + bool assign(value* var, value* val); size_t seek(std::string label,std::vector cmds ,codes::op code, size_t pos); - character* getCharacter(std::string c); bool characterExists(std::string bk_name); bool blockExists(std::string bk_name); + bool typeAssert(value* val, datatypes type); bool run(); private: // From what I gathered diff --git a/DMS/dms_state_interpret.cpp b/DMS/dms_state_interpret.cpp index 9ef9b79..5ecc702 100644 --- a/DMS/dms_state_interpret.cpp +++ b/DMS/dms_state_interpret.cpp @@ -2,6 +2,7 @@ #include "utils.h" #include "Handlers.h" #include +#include using namespace dms::utils; using namespace dms::exceptions; using namespace dms::codes; @@ -25,6 +26,12 @@ namespace dms { size_t max = 0; std::vector cmds; init(chunks[cha], pos, max, cmds); + if (isEnabled("omniscient")) { + cc->seen = true; + } + else { + cc->seen = false; + } while (true) { c = cmds[pos++]; code = c->opcode; @@ -40,11 +47,25 @@ namespace dms { break; case ASGN: if (c->args.args[0]->s->getValue() == "fname") { + if(!typeAssert(c->args.args[1],datatypes::string)) + return nullptr; cc->fname = c->args.args[1]->s->getValue(); } - else if (c->args.args[0]->s->getValue() == "lname") { + else if (c->args.args[0]->s->getValue() == "lname" && c->args.args[1]->type == datatypes::string) { + if (!typeAssert(c->args.args[1], datatypes::string)) + return nullptr; cc->lname = c->args.args[1]->s->getValue(); } + else if (c->args.args[0]->s->getValue() == "unknown" && c->args.args[1]->type == datatypes::string) { + if (!typeAssert(c->args.args[1], datatypes::string)) + return nullptr; + cc->unknown = c->args.args[1]->s->getValue(); + } + else if (c->args.args[0]->s->getValue() == "known" && c->args.args[1]->type == datatypes::boolean) { + if (!typeAssert(c->args.args[1], datatypes::boolean)) + return nullptr; + cc->seen = c->args.args[1]->b->getValue(); + } else { cc->values.insert_or_assign(c->args.args[0]->s->getValue(), c->args.args[1]); } @@ -58,6 +79,9 @@ namespace dms { break; } } + characters.insert_or_assign(cha, cc); + // Call Character event! + (*(Handler*)handler).OnSpeakerCreated(this,cc); return cc; } else { @@ -125,7 +149,17 @@ namespace dms { // Nothing needs to be done here break; case VERN: - Cversion = c->args.args[0]->n->getValue(); + Sversion = c->args.args[0]->n->getValue(); + // Version X.xx + // X: Will not guarantee compatibality. Code breaking changes should be expected especially on lower versions + // xx: Will not break compatibality. They may add features as it goes up the ranks, but those changes do not break older code. If they do they will increase the X part and not the xx part + if (Sversion > Iversion) { + push_error(errors::error{errors::incompatible_version ,"This script was made for a later version of this interperter!"}); + return false; + } + else if ((int)Iversion > (int)(Sversion)) { + push_warning(errors::error{ errors::incompatible_version ,"This script was made for an older version of this interperter, some features might not work!" }); + } break; case USIN: // How we add modules into the code. This is the code that actually loads that data! @@ -149,6 +183,8 @@ namespace dms { break; case HALT: //wait(); + std::this_thread::sleep_for(std::chrono::milliseconds(700)); + std::cout << std::endl; break; case DSPD: if (speaker == nullptr) { @@ -160,21 +196,22 @@ namespace dms { } break; case SSPK: + //Because we are using void* we must cast our pointers if (characterExists(c->args.args[0]->s->getValue())){ speaker = getCharacter(c->args.args[0]->s->getValue()); - if (speaker->lname != "") { - utils::write(speaker->fname, " ", speaker->lname, ": "); - } - else { - utils::write(speaker->fname, ": "); - } + if (!(*(Handler*)handler).handleSpeaker(this, speaker)) + return false; + } + else { + push_error(errors::error{ errors::disp_unknown,concat("Unknown character '",c->args.args[0]->s->getValue(),"'!")}); + return false; } break; case APND: - utils::write(c->args.args[0]->s->getValue()); + utils::write(c->args.args[0]->s->getValue(this)); break; case DISP: - utils::write(c->args.args[0]->s->getValue()); + utils::write(c->args.args[0]->s->getValue(this)); break; case ASGN: assign(c->args.args[0], c->args.args[1]); @@ -186,24 +223,20 @@ namespace dms { break; case CHOI: //Because we are using void* we must cast our pointers - //The implementation of this however should mean that you only ever have to deal with one "ChoiceHandler. One annoying void*" { std::vector args; std::string prompt = c->args.args[0]->s->getValue(); std::string fn = c->args.args[1]->s->getValue(); for (size_t i = 2; i < c->args.args.size(); i++) args.push_back(c->args.args[i]->resolve(memory)->s->getValue()); - size_t npos = (*(Handler*)handler).manageChoice(this, prompt, args); - print("CHOI_", fn, "_", npos); + size_t npos = (*(Handler*)handler).handleChoice(this, prompt, args); size_t nnpos = seek(concat("CHOI_", fn, "_", npos),cmds,LABL,npos); if (!nnpos) { push_error(errors::error{ errors::choice_unknown ,utils::concat("Unknown choice!") }); return false; } else { - print(nnpos); pos = nnpos; - wait(); } } break; @@ -225,7 +258,7 @@ namespace dms { } else { datatypes set = c->args.args[0]->resolve(memory)->type; - push_error(errors::error{ errors::invalid_arguments, utils::concat("String expected got ",set), true,ln }); + push_error(errors::error{ errors::invalid_arguments, utils::concat("String expected got ",datatype[set]), true,ln }); return false; } break; diff --git a/DMS/dump.bin b/DMS/dump.bin index 6fa8aac..45a5e46 100644 Binary files a/DMS/dump.bin and b/DMS/dump.bin differ diff --git a/DMS/dump.txt b/DMS/dump.txt index 955e521..667625e 100644 --- a/DMS/dump.txt +++ b/DMS/dump.txt @@ -4,9 +4,6 @@ Line <1> newline Line <1> flag Line <1> name main Line <1> newline -Line <2> flag -Line <2> name warnings -Line <2> newline Line <2> newline Line <3> flag Line <3> name omniscient @@ -16,352 +13,305 @@ Line <4> flag Line <4> name forseelabels Line <4> newline Line <4> newline +Line <5> flag +Line <5> name savestate +Line <5> newline Line <5> newline Line <6> newline -Line <7> flag -Line <7> string loadtest.dms -Line <7> newline Line <7> newline Line <8> flag -Line <8> number 1.2 +Line <8> string loadtest.dms Line <8> newline Line <8> newline Line <9> flag -Line <9> name extendedDefine +Line <9> number 0.2 Line <9> newline Line <9> newline +Line <10> flag +Line <10> name extendedDefine Line <10> newline Line <10> newline -Line <11> bracketo [ -Line <11> name main -Line <11> bracketc ] Line <11> newline Line <11> newline -Line <12> string why +Line <12> bracketo [ +Line <12> name main +Line <12> bracketc ] Line <12> newline Line <12> newline -Line <13> name works -Line <13> equal = -Line <13> true true +Line <13> string why Line <13> newline Line <13> newline -Line <14> jump Line <14> name Bob -Line <14> newline -Line <14> newline -Line <15> string Testing -Line <15> newline -Line <15> newline -Line <16> name Bob -Line <16> colon : -Line <16> cbracketo { -Line <16> newline -Line <16> newline -Line <17> name speed -Line <17> number 50 -Line <17> newline -Line <17> newline -Line <18> name excited -Line <18> colon : -Line <18> string Hello Ryan! -Line <18> newline -Line <18> newline -Line <19> name wait -Line <19> number 200 -Line <19> newline -Line <19> newline -Line <20> string How are you doing? -Line <20> newline -Line <20> newline -Line <21> cbracketc } -Line <21> newline -Line <21> newline -Line <22> newline -Line <22> newline -Line <23> name Ryan -Line <23> colon : -Line <23> cbracketo { -Line <23> newline -Line <23> newline -Line <24> string Hey Bob I'm good how are you? -Line <24> newline -Line <24> newline -Line <25> cbracketc } -Line <25> newline -Line <25> newline -Line <26> name Bob -Line <26> colon : -Line <26> string Testing... -Line <26> newline -Line <26> newline -Line <27> newline -Line <27> newline -Line <28> control -Line <28> string What do you want to do? -Line <28> cbracketo { -Line <28> newline -Line <28> newline -Line <29> string option 1 -Line <29> name test2 -Line <29> parao ( -Line <29> string testing -Line <29> seperator , -Line <29> cbracketo { -Line <29> number 1 -Line <29> seperator , -Line <29> number 2 -Line <29> seperator , -Line <29> number 3 -Line <29> cbracketc } -Line <29> parac ) -Line <29> newline -Line <29> newline -Line <30> string option 2 -Line <30> jump -Line <30> string test -Line <30> newline -Line <30> newline -Line <31> string option 3 -Line <31> jump -Line <31> name there -Line <31> newline -Line <31> newline -Line <32> string option 4 -Line <32> gotoo -Line <32> string o3 -Line <32> newline -Line <32> newline -Line <33> string option 5 -Line <33> gotoo -Line <33> name here -Line <33> newline -Line <33> newline -Line <34> string option 6 -Line <34> name test -Line <34> parao ( -Line <34> string here -Line <34> parac ) -Line <34> newline -Line <34> newline -Line <35> cbracketc } -Line <35> newline -Line <35> newline -Line <36> newline -Line <36> newline -Line <37> bracketo [ -Line <37> name test -Line <37> bracketc ] -Line <37> newline -Line <37> newline -Line <38> name Ryan -Line <38> colon : -Line <38> string We are here now! -Line <38> newline -Line <38> newline -Line <39> string hehe -Line <39> newline -Line <39> newline -Line <40> newline -Line <40> newline -Line <41> bracketo [ -Line <41> name Bob -Line <41> colon : -Line <41> name char -Line <41> bracketc ] -Line <41> newline -Line <41> newline -Line <42> name fname -Line <42> equal = -Line <42> string Bob -Line <42> newline -Line <42> newline -Line <43> newline -Line <44> name age -Line <44> equal = -Line <44> number 0.24 -Line <44> newline -Line <44> newline -Line <45> name money -Line <45> equal = -Line <45> number 100 -Line <45> newline -Line <45> newline -Line <46> name excited -Line <46> colon : -Line <46> string path/to/file -Line <46> newline -Line <46> newline -Line <47> newline -Line <47> newline -Line <48> bracketo [ -Line <48> name newblock -Line <48> colon : -Line <48> name function -Line <48> parao ( -Line <48> parac ) -Line <48> bracketc ] -Line <48> newline -Line <48> newline -Line <49> string Test #2 -Line <49> newline -Line <49> newline -Line <50> string Does it parse this part properly? -Line <50> newline -Line <50> newline -Line <51> string huh -Line <51> newline -Line <51> newline -Line <51> 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> name lname -Line <9> equal = -Line <9> string Ward -Line <9> newline -Line <9> newline -Line <10> newline -Line <11> name calm -Line <11> colon : -Line <11> string ./path/to/file -Line <11> newline -Line <11> newline -Line <12> name excited -Line <12> colon : -Line <12> string ./path/to/file -Line <12> newline -Line <12> newline -Line <13> newline -Line <13> newline -Line <14> bracketo [ -Line <14> name step Line <14> colon : -Line <14> name function -Line <14> parao ( -Line <14> name a -Line <14> seperator , -Line <14> name b -Line <14> seperator , -Line <14> name c -Line <14> parac ) -Line <14> bracketc ] +Line <14> cbracketo { Line <14> newline Line <14> newline -Line <15> string Testing... +Line <15> name speed +Line <15> number 50 Line <15> newline -Line <16> name d -Line <16> equal = -Line <16> parao ( -Line <16> number 100 -Line <16> plus + -Line <16> name b -Line <16> parac ) -Line <16> divide / -Line <16> name c +Line <15> newline +Line <16> name excited +Line <16> colon : +Line <16> string Hello `Ryan:fname`! Line <16> newline Line <16> newline -Line <17> name e -Line <17> equal = -Line <17> string somestring +Line <17> name wait +Line <17> number 200 Line <17> newline Line <17> newline -Line <18> name e -Line <18> equal = -Line <18> nil nil +Line <18> string How are you doing? I hear you have $`Ryan:money` in your account, nice! Line <18> newline Line <18> newline -Line <19> name g +Line <19> cbracketc } +Line <19> newline +Line <19> newline +Line <20> newline +Line <20> newline +Line <21> name Ryan +Line <21> colon : +Line <21> cbracketo { +Line <21> newline +Line <21> newline +Line <22> string Hey Bob I'm good how are you? +Line <22> newline +Line <22> newline +Line <23> cbracketc } +Line <23> newline +Line <23> newline +Line <24> newline +Line <24> newline +Line <25> name Bob +Line <25> colon : +Line <25> string I am great thanks! +Line <25> newline +Line <25> newline +Line <26> newline +Line <26> newline +Line <27> control +Line <27> string What do you want to do? +Line <27> cbracketo { +Line <27> newline +Line <27> newline +Line <28> string option 1 +Line <28> name test2 +Line <28> parao ( +Line <28> string testing +Line <28> seperator , +Line <28> cbracketo { +Line <28> number 1 +Line <28> seperator , +Line <28> number 2 +Line <28> seperator , +Line <28> number 3 +Line <28> cbracketc } +Line <28> parac ) +Line <28> newline +Line <28> newline +Line <29> string option 2 +Line <29> jump +Line <29> string test +Line <29> newline +Line <29> newline +Line <30> string option 3 +Line <30> jump +Line <30> name there +Line <30> newline +Line <30> newline +Line <31> string option 4 +Line <31> gotoo +Line <31> string o3 +Line <31> newline +Line <31> newline +Line <32> string option 5 +Line <32> gotoo +Line <32> name here +Line <32> newline +Line <32> newline +Line <33> string option 6 +Line <33> name test +Line <33> parao ( +Line <33> string here +Line <33> parac ) +Line <33> newline +Line <33> newline +Line <34> cbracketc } +Line <34> newline +Line <34> newline +Line <35> newline +Line <35> newline +Line <36> bracketo [ +Line <36> name test +Line <36> bracketc ] +Line <36> newline +Line <36> newline +Line <37> name Ryan +Line <37> colon : +Line <37> string We are here now! +Line <37> newline +Line <37> newline +Line <38> Line <1> newline +Line <1> newline +Line <1> flag +Line <1> name tests +Line <1> newline +Line <1> newline +Line <2> flag +Line <2> name hello +Line <2> newline +Line <2> newline +Line <3> bracketo [ +Line <3> name default +Line <3> colon : +Line <3> name char +Line <3> bracketc ] +Line <3> newline +Line <3> newline +Line <4> newline +Line <5> name money +Line <5> equal = +Line <5> number 0 +Line <5> newline +Line <5> newline +Line <6> name test +Line <6> equal = +Line <6> nil nil +Line <6> newline +Line <6> newline +Line <7> newline +Line <7> newline +Line <8> bracketo [ +Line <8> name Ryan +Line <8> colon : +Line <8> name char +Line <8> bracketc ] +Line <8> newline +Line <8> newline +Line <9> name age +Line <9> equal = +Line <9> number 21 +Line <9> newline +Line <9> newline +Line <10> name money +Line <10> equal = +Line <10> number 1000 +Line <10> newline +Line <10> newline +Line <11> name lname +Line <11> equal = +Line <11> string Ward +Line <11> newline +Line <11> newline +Line <12> name known +Line <12> equal = +Line <12> true true +Line <12> newline +Line <12> newline +Line <13> newline +Line <14> name calm +Line <14> colon : +Line <14> string ./path/to/file +Line <14> newline +Line <14> newline +Line <15> name excited +Line <15> colon : +Line <15> string ./path/to/file +Line <15> newline +Line <15> newline +Line <16> newline +Line <16> newline +Line <17> bracketo [ +Line <17> name step +Line <17> colon : +Line <17> name function +Line <17> parao ( +Line <17> name a +Line <17> seperator , +Line <17> name b +Line <17> seperator , +Line <17> name c +Line <17> parac ) +Line <17> bracketc ] +Line <17> newline +Line <17> newline +Line <18> string Testing... +Line <18> newline +Line <19> name d Line <19> equal = -Line <19> false false +Line <19> parao ( +Line <19> number 100 +Line <19> plus + +Line <19> name b +Line <19> parac ) +Line <19> divide / +Line <19> name c Line <19> newline Line <19> newline -Line <20> ret -Line <20> name d +Line <20> name e +Line <20> equal = +Line <20> string somestring Line <20> newline Line <20> newline +Line <21> name e +Line <21> equal = +Line <21> nil nil Line <21> newline Line <21> newline -Line <22> bracketo [ -Line <22> name inventory -Line <22> colon : -Line <22> name env -Line <22> bracketc ] +Line <22> name g +Line <22> equal = +Line <22> false false Line <22> newline Line <22> newline -Line <23> name slot1 -Line <23> equal = -Line <23> string +Line <23> ret +Line <23> name d Line <23> newline Line <23> newline -Line <24> name slot2 -Line <24> equal = -Line <24> string Line <24> newline Line <24> newline -Line <25> name slot3 -Line <25> equal = -Line <25> string +Line <25> bracketo [ +Line <25> name inventory +Line <25> colon : +Line <25> name env +Line <25> bracketc ] Line <25> newline Line <25> newline -Line <26> name slot4 +Line <26> name slot1 Line <26> equal = Line <26> string Line <26> newline Line <26> newline -Line <27> name slot5 +Line <27> name slot2 Line <27> equal = Line <27> string Line <27> newline Line <27> newline -Line <28> name slot6 +Line <28> name slot3 Line <28> equal = Line <28> string Line <28> newline Line <28> newline -Line <29> name slot7 +Line <29> name slot4 Line <29> equal = Line <29> string Line <29> newline Line <29> newline -Line <30> name slot8 +Line <30> name slot5 Line <30> equal = Line <30> string Line <30> newline Line <30> newline -Line <30> eof +Line <31> name slot6 +Line <31> equal = +Line <31> string +Line <31> newline +Line <31> newline +Line <32> name slot7 +Line <32> equal = +Line <32> string +Line <32> newline +Line <32> newline +Line <33> name slot8 +Line <33> equal = +Line <33> string +Line <33> newline +Line <33> newline +Line <33> eof diff --git a/DMS/enviroment.cpp b/DMS/enviroment.cpp new file mode 100644 index 0000000..b2b03b0 --- /dev/null +++ b/DMS/enviroment.cpp @@ -0,0 +1,12 @@ +#include "enviroment.h" +namespace dms { + bool enviroment::has(std::string index) { + return values.count(index); + } + void enviroment::set(std::string index, value* val) { + values.insert_or_assign(index,val); + } + value* enviroment::get(std::string index) { + return values[index]; + } +} \ No newline at end of file diff --git a/DMS/enviroment.h b/DMS/enviroment.h new file mode 100644 index 0000000..c1949d2 --- /dev/null +++ b/DMS/enviroment.h @@ -0,0 +1,13 @@ +#pragma once +#include +#include +#include "value.h" +namespace dms { + struct enviroment { + std::string name=""; + std::unordered_map values; + bool has(std::string index); + void set(std::string index, value* val); + value* get(std::string index); + }; +} \ No newline at end of file diff --git a/DMS/errors.h b/DMS/errors.h index 2184458..2f47810 100644 --- a/DMS/errors.h +++ b/DMS/errors.h @@ -13,7 +13,8 @@ namespace dms::errors { choice_unknown, nested_function, disp_unknown, - non_existing_block + non_existing_block, + incompatible_version }; struct error { errortype code=unknown; diff --git a/DMS/loadtest.dms b/DMS/loadtest.dms index 260081e..b3a00aa 100644 --- a/DMS/loadtest.dms +++ b/DMS/loadtest.dms @@ -1,3 +1,5 @@ +enable tests +disable hello [default:char] // The default stats for all characters. money = 0 @@ -7,6 +9,7 @@ age = 21 money = 1000 lname = "Ward" + known = true // Inside a character block this syntax defines animation/image file for an emotion calm: "./path/to/file" excited: "./path/to/file" @@ -20,11 +23,11 @@ return d [inventory:env] - slot1 = "" - slot2 = "" - slot3 = "" - slot4 = "" - slot5 = "" - slot6 = "" - slot7 = "" - slot8 = "" \ No newline at end of file + slot1 = "S1" + slot2 = "S2" + slot3 = "S3" + slot4 = "S4" + slot5 = "S5" + slot6 = "S6" + slot7 = "S7" + slot8 = "S8" \ No newline at end of file diff --git a/DMS/test.dms b/DMS/test.dms index cff9b7c..ffdff6d 100644 --- a/DMS/test.dms +++ b/DMS/test.dms @@ -1,30 +1,29 @@ entry main // Will either start the first block seen or the block supplied by you! -enable warnings +//enable warnings disable omniscient enable forseelabels +enable savestate //enable leaking //enable debugging loadfile "loadtest.dms" -version 1.2 +version 0.2 using extendedDefine [main] "why" - works = true - jump Bob - "Testing" Bob: { speed 50 - excited: "Hello Ryan! " + excited: "Hello `Ryan:fname`! " wait 200 - "How are you doing?" + "How are you doing? I hear you have $`Ryan:money` in your account, nice!" } Ryan: { "Hey Bob I'm good how are you?" } - Bob: "Testing..." + Bob: "I am great thanks!" + choice "What do you want to do?" { "option 1" test2("testing",{1,2,3}) "option 2" jump "test" @@ -36,11 +35,16 @@ using extendedDefine [test] Ryan: "We are here now!" - "hehe" + |"This continues from the last message!" + |"Keeps code readable. This does not cause a new line!" + Ryan: "This does trigger a new line tho!" + "This also will cause a new line!" [Bob:char] fname = "Bob" - //lname = "" + //known = true // defaults to false + lname = "" + unknown = "Some Rando" age = .24 money = 100 excited: "path/to/file" diff --git a/DMS/token.h b/DMS/token.h index c485bcc..754cafa 100644 --- a/DMS/token.h +++ b/DMS/token.h @@ -48,7 +48,8 @@ namespace dms::tokens { pound, dollar, ampersand, - nil + nil, + pipe };//stream, t_vec, line, isNum, buffer struct token { tokentype type = noop; diff --git a/DMS/value.cpp b/DMS/value.cpp index 69dda40..d8d1452 100644 --- a/DMS/value.cpp +++ b/DMS/value.cpp @@ -11,17 +11,154 @@ namespace dms { // Values at runtime aren't "Deleted, they are set to nil" // At the end we actually delete them! } - value* value::resolve(std::unordered_map map, value* v) { - if (v != nullptr) { - if (this->type == datatypes::variable) { - return resolve(map, map[this->s->getValue()]); // Variable types return the value - } + value* value::resolve(std::unordered_map memory) { + if (type == datatypes::variable) { + return memory[s->getValue()]->resolve(memory); // Variable types return the value } return this; } void dms_args::push(value* val) { args.push_back(val); } + std::string dms_string::getValue(dms_state* state) { + std::stringstream temp; + std::stringstream var; + std::stringstream ind; + bool varStart = false; + bool indStart = false; + for (size_t i = 0; i < length; i++) { + if (indStart && val[i] == '`') { + std::string lookup = var.str(); + std::string index = ind.str(); + var.str(""); + var.clear(); + ind.str(""); + ind.clear(); + varStart = false; + indStart = false; + if (state->memory.count(lookup)) { + value* v = state->memory[lookup]; + if (v->type == datatypes::block) { + if (state->getCharacter(v->s->getValue())!=nullptr) { + character* cha = state->getCharacter(v->s->getValue()); + if (index == "fname") { + temp << cha->fname; + } + else if (index == "lname") { + temp << cha->lname; + } + else if (index == "nickname") { + temp << cha->nickname; + } + else if (cha->values.count(index)) { + temp << cha->values[index]->getPrintable(); + } + else { + temp << cha->getName(); + } + } + else { + temp << "nil"; + } + } + else { + temp << v->getPrintable(); + } + } + else { + temp << "nil"; + } + } + else if (indStart && val[i] == ':') { + state->push_error(errors::error{ errors::badtoken,"Cannot index more than once in a string injection!" }); + varStart = false; + indStart = false; + var.str(""); + var.clear(); + ind.str(""); + ind.clear(); + return ""; + } + else if (indStart) { + ind << val[i]; + } + else if (val[i] == '`' && !varStart) { + varStart = true; + + } + else if (val[i] == '`' && varStart) { + std::string lookup = var.str(); + var.str(""); + var.clear(); + varStart = false; + if (state->memory.count(lookup)) { + value* v = state->memory[lookup]; + if (v->type == datatypes::block) { + if (state->getCharacter(v->s->getValue())) { + temp << state->characters[v->s->getValue()]->getName(); + } + else { + temp << "nil"; + } + } + else { + temp << v->getPrintable(); + } + } + else { + temp << "nil"; + } + } + // A space is not allowed at all + else if (val[i] == ':' && varStart) { + indStart = true; + } + else if (val[i] == ' ' && varStart) { + temp << var.str(); + varStart = false; + var.str(""); + var.clear(); + } + else if (varStart) { + var << val[i]; + } + else { + temp << val[i]; + } + } + return temp.str(); + } + std::string value::getPrintable() const { + std::stringstream out; + if (type == string) { + out << s->getValue(); + } + else if (type == number) { + out << n->getValue(); + } + else if (type == nil) { + out << "nil"; + } + else if (type == boolean) { + if (b->getValue()) + out << "true"; + else + out << "false"; + } + else if (type == env) { + out << "Env: " << this; + } + else if (type == custom) { + out << "Custom Data: " << this; + } + else if (type == block) { + out << s->getValue(); + } + else if (type == datatypes::variable) { + out << s->getValue(); // Do the lookup + } + return out.str(); + } dms_string* buildString(std::string str) { size_t len = str.length(); uint8_t* arr = new uint8_t[len]; diff --git a/DMS/value.h b/DMS/value.h index f959438..c834a4a 100644 --- a/DMS/value.h +++ b/DMS/value.h @@ -27,10 +27,12 @@ namespace dms { return out; }; }; + struct dms_state; struct dms_string { size_t length = 0; uint8_t* val = nullptr; std::string getValue(); + std::string getValue(dms_state* state); friend std::ostream& operator << (std::ostream& out, const dms_string& c) { for (size_t i = 0; i < c.length; i++) { std::cout << c.val[i]; @@ -64,7 +66,7 @@ namespace dms { dms_env* e = nullptr; dms_custom* c = nullptr; value(); - value* resolve(std::unordered_map map,value* v=nullptr); + value* resolve(std::unordered_map map); void nuke(); void set(dms_string* str); void set(dms_boolean* bo); @@ -72,6 +74,7 @@ namespace dms { void set(dms_env* en); void set(); bool typeMatch(const value* o) const; + std::string getPrintable() const; std::string toString() const; friend std::ostream& operator << (std::ostream& out, const value& c) { if (c.type == string) { @@ -98,7 +101,6 @@ namespace dms { else if (c.type == block) { out << (char)c.type << c.s->getValue(); } - // Internal kinda else if (c.type == datatypes::variable) { out << (char)c.type << c.s->getValue(); // Do the lookup }