ITS WORKING HOLY SHIT

This commit is contained in:
lachrymaL 2021-12-12 22:20:28 -05:00
parent e182ffc14a
commit 084acbba1e
No known key found for this signature in database
GPG key ID: F3640ACFA174B1C1
9 changed files with 237 additions and 131 deletions

View file

@ -4,7 +4,7 @@
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "clang_cl_x64_x64" ],
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",

View file

@ -4,6 +4,6 @@
cmake_minimum_required (VERSION 3.8)
# Add source to this project's executable.
add_executable (NouVeL "NouVeL.cpp" "NVL.cpp")
add_executable (NouVeL "NouVeL.cpp" "Parser.cpp" "Environment.cpp" "Environment.h")
# TODO: Add tests and install targets if needed.

51
NouVeL/Environment.cpp Normal file
View file

@ -0,0 +1,51 @@
#include <unordered_map>
#include <functional>
#include <any>
#include <variant>
#include <stdexcept>
#include "Environment.h"
namespace NVL {
const unsigned LOG_SIZE = 50;
bool Variable::operator==(const Variable& other) const {
if (other.type != type)
return false;
switch (type) {
case Type::Number:
return std::get<Number>(other.value) == std::get<Number>(value);
case Type::String:
return std::get<std::string>(other.value) == std::get<std::string>(value);
default:
return false;
}
}
Variable::Variable() {}
Variable::Variable(const Number& v) : type(Type::Number), value(v), length(1) {}
Variable::Variable(const std::string& v) : type(Type::String), value(v), length(1) {}
Variable::Variable(const std::vector<Variable>& v) : type(Type::Array), value(v), length(v.size()) {}
Variable::Variable(void* v, int l) : type(Type::Procedure), value(v), length(l) {}
Environment ENVIRONMENT;
void Environment::enter(const std::string& name, Variable p) {
if (env.find(name) != env.end())
throw std::runtime_error("Redefinition of symbol in environment");
env[name] = p;
}
void Environment::set(const std::string& name, Variable p) {
if (env.find(name) == env.end())
throw std::runtime_error("Attempting to set undefined variable");
env[name] = p;
}
Variable Environment::get(const std::string& name) {
return env.at(name);
}
bool Environment::exists(const std::string& name) {
return env.find(name) != env.end();
}
}

33
NouVeL/Environment.h Normal file
View file

@ -0,0 +1,33 @@
#pragma once
#include <unordered_map>
#include <functional>
#include <any>
#include <variant>
namespace NVL {
using Number = float;
enum class Type { Procedure, Number, String, Array };
struct Variable {
Type type;
std::variant<Number, std::string, std::vector<Variable>, void*> value;
int length;
bool operator==(const Variable& other) const;
Variable();
Variable(const Number& v);
Variable(const std::string& v);
Variable(const std::vector<Variable>& v);
Variable(void* v, int l);
};
class Environment {
private:
std::unordered_map<std::string, Variable> env{};
public:
void enter(const std::string& name, Variable p);
void set(const std::string& name, Variable p);
Variable get(const std::string& name);
bool exists(const std::string& name);
};
extern Environment ENVIRONMENT;
}

View file

@ -1,8 +1,16 @@
#include "NVL.h"
#include "Parser.h"
#include "Environment.h"
#include <functional>
#include <any>
#include <string>
#include <iostream>
int main() {
auto f = [](std::string& what) -> std::any { return true; };
NVL::Variable v(&f, 3);
NVL::ENVIRONMENT.enter("hello", v);
const std::string PJ_DIR = "E:\\Archive\\Projects\\NouVeL\\NouVeL\\";
NVL::ParseFile(PJ_DIR + "test.nvl");
return 0;

View file

@ -1,23 +1,26 @@
#include <string>
#include <vector>
#include <variant>
#include <unordered_map>
#include <fstream>
#include <sstream>
#include <iostream>
#include <functional>
#include <stdexcept>
#include "SymbolConfig.h"
const unsigned LOG_SIZE = 50;
#include "Environment.h"
namespace {
struct ParseGroup {
std::string accept;
operator std::string() const {
return accept;
}
constexpr bool operator== (const std::string& other) const {
return accept == other;
}
};
struct Match {
@ -48,13 +51,19 @@ namespace {
const ParseGroup SYMBOL = { ALPHA.accept + NUMERIC.accept + "_-" };
const ParseGroup WS = { " \t\v\f\r\n" };
const ParseGroup SEPARATOR = {
WS.accept + char(ARRAY_OPEN) + char(ARRAY_CLOSE) + char(GROUP_OPEN) + char(GROUP_CLOSE)
WS.accept +
char(ARRAY_OPEN) +
char(ARRAY_CLOSE) +
char(GROUP_OPEN) +
char(GROUP_CLOSE) +
char(ARRAY_DELIM) +
char(COMMENT_BEGIN)
};
const Match NEWLINE = { "\n" };
const Match ESCAPE = { "\\" };
const ParseGroup ESCAPED = { "\\\"" };
enum class Type { Symbol, Number, String, Array };
enum class ParseType { Symbol, Number, String, Array, Subexpression };
std::string read_file_to_string(const std::string& path) {
std::ifstream f(path);
@ -67,8 +76,7 @@ namespace {
std::vector<std::string> lines;
int pos = 0;
int prev = 0;
while ((pos = str.find(NEWLINE.accept[0], prev)) != std::string::npos)
{
while ((pos = str.find(NEWLINE, prev)) != std::string::npos) {
lines.push_back(str.substr(prev, pos - prev));
prev = pos + 1;
}
@ -94,56 +102,28 @@ namespace {
return true;
}
enum class ParseState { Root, Scene, Command, Dialogue, String, Array };
using NVL_Number = float;
struct Environment {
private:
std::unordered_map<std::string, void*> env;
public:
void enter(const std::string& name, void* p) {
if (env.find(name) != env.end())
throw std::runtime_error("Redefinition of symbol in environment");
env[name] = p;
}
void set(const std::string& name, void* p) {
if (env.find(name) == env.end())
throw std::runtime_error("Attempting to set undefined variable");
env[name] = p;
}
auto get(const std::string& name) {
return env.at(name);
}
bool exists(const std::string& name) {
return env.find(name) != env.end();
}
} ENV;
/*struct Command {
Object procedure;
std::vector<Object> args{};
};*/
class Object {
public:
Type type;
ParseType type;
std::variant<
NVL_Number,
NVL::Number,
std::string,
std::vector<Object>
> value;
};
using Command = std::vector<Object>;
struct Command {
Object procedure;
std::vector<Object> args{};
};
class Scene {
std::string name;
std::vector<Command> commands{};
public:
Scene(const std::string& name) : name(name) {
ENV.enter(name, this);
//NVL::ENVIRONMENT.enter(name, this);
}
void append(const Command& c) {
commands.push_back(c);
@ -169,6 +149,11 @@ namespace {
}
}
void SkipOverFirstChar(const std::string& f, size_t& pos) {
SkipWS(f, pos);
pos++;
}
std::string GetToken(const std::string& f, size_t& pos) {
SkipWS(f, pos);
auto start = pos;
@ -189,7 +174,7 @@ namespace {
return f.substr(start, pos - start);
}
bool IsSymbol(const std::string& token) {
bool IsLegalSymbolName(const std::string& token) {
if (ALPHA.accept.find(token[0]) == std::string::npos)
return false;
for (auto& i : token)
@ -197,47 +182,41 @@ namespace {
return false;
return true;
}
void ParseArray(ParseState& state, const std::string& f, size_t& pos, Command& command) {
SkipWS(f, pos);
/*
// Read until array end OR end of line, state wont change if array end was not found
auto start = pos;
while (pos < line.length()) {
if (ARRAY_OPEN.accept[0] == line[pos])
parse.layer++;
else if (ARRAY_CLOSE.accept[0] == line[pos])
break;
pos++;
}
parse.parse = line.substr(start, pos++ - start);
if (parse.parse.back() == ARRAY_CLOSE.accept[0]) {
parse.layer--;
if (parse.layer == 0) {
Object ParseExpression(const std::string& f, size_t& pos);
Object ParseArray(const std::string& f, size_t& pos, int layer) {
SkipComments(f, pos);
}
std::vector<Object> array{};
array.push_back(ParseExpression(f, pos));
while (PeekToken(f, pos)[0] != ARRAY_CLOSE) {
if (PeekToken(f, pos)[0] == ARRAY_DELIM)
SkipOverFirstChar(f, pos);
else
throw std::runtime_error("Invalid array member");
array.push_back(ParseExpression(f, pos));
}
return;
*/
return { ParseType::Array, array };
}
std::string ParseString(ParseState& state, const std::string& f, size_t& pos) {
SkipWS(f, pos);
std::string ParseString(const std::string& f, size_t& pos) {
SkipComments(f, pos);
std::vector<int> discards{};
auto start = ++pos; // skip opening quote
do {
if (f[pos] == char(QUOTE)) {
if (f[pos] == QUOTE) {
break;
}
else if (f[pos] == char(ESCAPE)) {
else if (f[pos] == ESCAPE) {
if (ESCAPED.accept.find(f[pos]) != std::string::npos) {
discards.push_back(pos++);
}
else
throw std::runtime_error("Unrecognized escape sequence");
}
else if (f[pos] == char(NEWLINE)) {
else if (f[pos] == NEWLINE) {
throw std::runtime_error("Unclosed String");
}
} while (pos++);
@ -247,74 +226,110 @@ namespace {
}
return str;
}
// Handles dialogue as well
void ParseCommand(ParseState& state, const std::string& f, size_t& pos, Scene& scene) {
int initial = pos; // TEMP
int exp_layer = 0;
bool exp_complete = false;
auto proc = GetToken(f, pos);
if (!IsSymbol(proc)) throw std::runtime_error("Illegal Procedure name");
Command c{ { Type::Symbol, proc }, {} };
while (!exp_complete) {
SkipComments(f, pos);
if (pos > f.find('\n', initial)) // TEMP
exp_complete = true; // TEMP
auto t = PeekToken(f, pos);
if (t[0] == ARRAY_OPEN) {
state = ParseState::Array;
ParseArray(state, f, pos, c);
break;
}
else if (t[0] == GROUP_OPEN) {
}
else if (t[0] == GROUP_CLOSE) {
}
else if (t[0] == QUOTE) {
state = ParseState::String;
c.args.push_back(Object{ Type::String, ParseString(state, f, pos) });
}
else if (t[0] == ARRAY_CLOSE)
throw std::runtime_error("Cannot match array");
else {
auto token = GetToken(f, pos);
if (IsNumeric(token)) {
c.args.push_back(Object{ Type::Number, std::stof(token) });
}
else if (IsSymbol(token)) {
c.args.push_back(Object{ Type::Symbol, token });
}
else
throw std::runtime_error("Illegal symbol");
}
}
scene.append(c);
unsigned GetProcedureArity(const std::string& key) {
return NVL::ENVIRONMENT.get(key).length;
}
void ParseScene(ParseState& state, const std::string& f, size_t& pos, std::vector<Scene>& scenes) {
Command ParseCommand(const std::string& f, size_t& pos) {
SkipComments(f, pos);
auto proc = GetToken(f, pos);
if (!IsLegalSymbolName(proc)) throw std::runtime_error("Illegal Procedure name");
Command c{ Object{ ParseType::Symbol, proc } };
for (int i = 0; i < GetProcedureArity(proc); i++) {
c.push_back(ParseExpression(f, pos));
};
return c;
}
Object ParseExpression(const std::string& f, size_t& pos) {
SkipComments(f, pos);
auto t = PeekToken(f, pos);
if (t[0] == ARRAY_OPEN) {
SkipOverFirstChar(f, pos);
auto c = ParseArray(f, pos, 0);
if (PeekToken(f, pos)[0] != ARRAY_CLOSE)
throw std::runtime_error("Cannot match closing Array");
else
SkipOverFirstChar(f, pos);
return c;
}
else if (t[0] == GROUP_OPEN) {
SkipOverFirstChar(f, pos);
auto c = ParseCommand(f, pos);
if (PeekToken(f, pos)[0] != GROUP_CLOSE)
throw std::runtime_error("Cannot match closing subexpression");
else
SkipOverFirstChar(f, pos);
return Object(ParseType::Subexpression, c);
}
else if (t[0] == GROUP_CLOSE)
throw std::runtime_error("Cannot match closing subexpression, likely too few arguments");
else if (t[0] == QUOTE)
return { ParseType::String, ParseString(f, pos) };
else if (t[0] == ARRAY_CLOSE)
throw std::runtime_error("Cannot match closing array");
else {
auto token = GetToken(f, pos);
if (IsNumeric(token))
return { ParseType::Number, std::stof(token) };
else if (IsLegalSymbolName(token))
return { ParseType::Symbol, token };
else
throw std::runtime_error("Illegal symbol");
}
}
Command ParseDialogue(const std::string& s) {
return { { ParseType::Symbol, "Say" }, { ParseType::String, s } };
}
Scene ParseScene(const std::string& f, size_t& pos) {
SkipComments(f, pos);
if (!(GetToken(f, pos) == BEGIN.accept))
throw std::runtime_error("Could not match accept at root");
auto scene_name = GetToken(f, pos);
if (!IsSymbol(scene_name)) throw std::runtime_error("Illegal Scene name");
if (!IsLegalSymbolName(scene_name)) throw std::runtime_error("Illegal Scene name");
Scene s{ scene_name };
state = ParseState::Command;
bool dialogue_mode = false;
while (PeekToken(f, pos) != END.accept) {
ParseCommand(state, f, pos, s);
if (!dialogue_mode)
if (PeekToken(f, pos) == DIALOGUE_OPEN.accept) {
dialogue_mode = true;
GetToken(f, pos); // skip DIALOGUE_OPEN
SkipComments(f, pos);
}
else
s.append(ParseCommand(f, pos));
else {
auto end = f.find(NEWLINE.accept + DIALOGUE_CLOSE.accept, pos);
if (end == std::string::npos)
throw std::runtime_error("Dialogue does not terminate");
auto lines = split_string_by_lines(f.substr(pos, end - pos));
for (auto& l : lines) {
s.append(ParseDialogue(l));
}
dialogue_mode = false;
pos = end;
GetToken(f, pos); // skip DIALOGUE_CLOSE
SkipComments(f, pos);
}
}
if (dialogue_mode)
throw std::runtime_error("Illegal Scene end");
GetToken(f, pos); // skip END
scenes.push_back(s);
return s;
}
/*Scene EvalScene(const std::vector<std::vector<Parse>>& parses) { // TODO THIS IS TOTALLY FUCKED
@ -352,11 +367,10 @@ namespace {
namespace NVL {
void ParseFile(const std::string& path) {
std::string f = read_file_to_string(path);
ParseState state = ParseState::Root;
std::vector<Scene> list {}; // Vector of scenes which each contain a vector of Parses
for (size_t i = 0; i < f.length(); i++) {
ParseScene(state, f, i, list);
list.push_back(ParseScene(f, i));
}
}

View file

@ -61,6 +61,6 @@ Choice var4 ["Apple", "Orange"]
// to have ways to terminate a scene other than END, for instance JUMP can be an alternative like this:
// JUMP Scene2
// we can equally do something like this
// JUMP (switch var4 ("Apple" RouteA) ("Orange" RouteB) (default RouteC))
// JUMP (switch var4 [["Apple", RouteA], ["Orange", RouteB], [default, RouteC]])
END

View file

@ -1,3 +1,3 @@
BEGIN Scene1
hello "String \\ sdsd \" \\ \" sds"
hello "String \\ sdsd \" \\ \" sds" 873482384 .2342342
END