Initial commit
This commit is contained in:
27
src/data/data.cpp
Normal file
27
src/data/data.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "data.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "../defs/defs.h"
|
||||
#include "../error/error.h"
|
||||
|
||||
namespace data {
|
||||
std::map<std::string, Value> vars;
|
||||
std::map<std::string, std::vector<Instruction>> functions;
|
||||
void modifyValue(std::string key, Value value) {
|
||||
if (vars.find(key) != vars.end()) {
|
||||
vars[key] = value;
|
||||
} else {
|
||||
error("Could not find variable " + key + "to modify (try defining first with let?)");
|
||||
}
|
||||
}
|
||||
Value getValue(std::string key) {
|
||||
if (vars.find(key) != vars.end()) {
|
||||
return vars[key];
|
||||
} else {
|
||||
error("Could not find variable " + key + " to access (try defining first with let?)");
|
||||
return Value();
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/data/data.h
Normal file
13
src/data/data.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "../defs/defs.h"
|
||||
|
||||
namespace data {
|
||||
extern std::map<std::string, Value> vars;
|
||||
extern std::map<std::string, std::vector<Instruction>> functions;
|
||||
void modifyValue(std::string key, Value value);
|
||||
Value getValue(std::string key);
|
||||
}
|
||||
205
src/defs/defs.cpp
Normal file
205
src/defs/defs.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
#include "defs.h"
|
||||
#include "../error/error.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
InstructionType strToInstructionType(std::string in) {
|
||||
if (in == "println") return InstructionType::Println;
|
||||
else if (in == "print") return InstructionType::Print;
|
||||
else if (in == "math") return InstructionType::Math;
|
||||
else if (in == "let") return InstructionType::Let;
|
||||
else if (in == "exit") return InstructionType::Exit;
|
||||
else if (in == "if") return InstructionType::If;
|
||||
else if (in == "while") return InstructionType::While;
|
||||
else if (in == "compare") return InstructionType::Compare;
|
||||
else if (in == "input") return InstructionType::Input;
|
||||
else return InstructionType::Variable;
|
||||
}
|
||||
|
||||
Instruction::Instruction(std::vector<std::string> toks) {
|
||||
if (!toks.empty()) {
|
||||
// Get type of instruction from first token
|
||||
instruction = strToInstructionType(toks[0]);
|
||||
if (instruction == InstructionType::Variable) {
|
||||
for (std::string tok : toks) {
|
||||
args.push_back(Value(tok));
|
||||
}
|
||||
} else {
|
||||
// The rest are the args, convert them to values first
|
||||
for (size_t i = 1; i < toks.size(); i++) {
|
||||
args.push_back(Value(toks[i]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error("Empty tokens!");
|
||||
}
|
||||
}
|
||||
|
||||
Instruction::Instruction(std::vector<Value> toks) {
|
||||
if (!toks.empty()) {
|
||||
// Check type of value in first token, then compute token
|
||||
if (toks[0].valtype == ValueType::Real) {
|
||||
instruction = strToInstructionType(toks[0].real);
|
||||
} else {
|
||||
error("Instruction should be a real");
|
||||
}
|
||||
if (instruction == InstructionType::Variable) {
|
||||
for (const auto& tok : toks) {
|
||||
args.push_back(tok);
|
||||
}
|
||||
} else {
|
||||
// The rest are the args
|
||||
for (size_t i = 1; i < toks.size(); i++) {
|
||||
args.push_back(toks[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error("Empty tokens!");
|
||||
}
|
||||
}
|
||||
|
||||
Value::Value(std::string stringval) : valtype(ValueType::Real), real(stringval) {}
|
||||
|
||||
Value::Value(Instruction instval) : valtype(ValueType::Processed), processed(std::make_unique<Instruction>(std::move(instval))) {}
|
||||
|
||||
Value::Value() : valtype(ValueType::Real) {}
|
||||
|
||||
Value::Value(InstructionGroup instgroup) : valtype(ValueType::InstructionGroup), instructionGroup(instgroup) {};
|
||||
|
||||
Value::Value(const Value& other) : valtype(other.valtype), real(other.real), varName(other.varName), instructionGroup(other.instructionGroup) {
|
||||
if (other.processed) {
|
||||
processed = std::make_unique<Instruction>(*other.processed);
|
||||
}
|
||||
}
|
||||
|
||||
Value::Value(Varname varname) : valtype(ValueType::Variable), varName(varname) {}
|
||||
|
||||
Varname::Varname(std::string in) : key(in.substr(1)) {}
|
||||
Varname::Varname() : key("") {}
|
||||
|
||||
Value& Value::operator=(const Value& other) {
|
||||
if (this != &other) {
|
||||
valtype = other.valtype;
|
||||
real = other.real;
|
||||
varName = other.varName;
|
||||
instructionGroup = other.instructionGroup;
|
||||
if (other.processed) {
|
||||
processed = std::make_unique<Instruction>(*other.processed);
|
||||
} else {
|
||||
processed.reset();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string Value::toString() const {
|
||||
std::string out = "Value(type: ";
|
||||
switch (valtype) {
|
||||
case ValueType::Real:
|
||||
out += "Real, value: " + real + ")";
|
||||
break;
|
||||
case ValueType::Processed:
|
||||
out += "Processed, value: ";
|
||||
if (processed) {
|
||||
out += processed->toString();
|
||||
} else {
|
||||
out += "null";
|
||||
}
|
||||
out += ")";
|
||||
break;
|
||||
case ValueType::InstructionGroup:
|
||||
out += "InstructionGroup, contains " + std::to_string(instructionGroup.size()) + " instructions)";
|
||||
break;
|
||||
default:
|
||||
out += "FIXME)";
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string Instruction::toString() const {
|
||||
std::string out = "Instruction(type: ";
|
||||
switch (instruction) {
|
||||
case InstructionType::None:
|
||||
out += "None";
|
||||
break;
|
||||
case InstructionType::Println:
|
||||
out += "Println";
|
||||
break;
|
||||
case InstructionType::Math:
|
||||
out += "Math";
|
||||
break;
|
||||
case InstructionType::Let:
|
||||
out += "Let";
|
||||
break;
|
||||
case InstructionType::If:
|
||||
out += "If";
|
||||
break;
|
||||
case InstructionType::Compare:
|
||||
out += "Compare";
|
||||
break;
|
||||
case InstructionType::Input:
|
||||
out += "Input";
|
||||
break;
|
||||
default:
|
||||
out += "FIXME";
|
||||
break;
|
||||
}
|
||||
out += ", args: [";
|
||||
for (const auto& val : args) {
|
||||
out += val.toString() + ", ";
|
||||
}
|
||||
out += "])";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<Value> split(std::string line) {
|
||||
std::vector<Value> splitvals;
|
||||
std::string buf;
|
||||
bool instring = false;
|
||||
int brackets = 0;
|
||||
for (char chr : line) {
|
||||
if (chr == ' ' && !instring && brackets == 0 && !buf.empty()) {
|
||||
if (buf[0] == '$') {
|
||||
splitvals.push_back(Value(Varname(buf)));
|
||||
} else {
|
||||
splitvals.push_back(Value(buf));
|
||||
}
|
||||
buf = "";
|
||||
} else if (chr == '(' || chr == '[') {
|
||||
brackets += 1;
|
||||
if (brackets == 1) {
|
||||
if (!buf.empty()) {
|
||||
splitvals.push_back(Value(buf));
|
||||
buf = "";
|
||||
}
|
||||
} else {
|
||||
buf += chr;
|
||||
}
|
||||
} else if (chr == ')' || chr == ']') {
|
||||
brackets -= 1;
|
||||
if (brackets == 0) {
|
||||
if (!buf.empty()) {
|
||||
splitvals.push_back(Value(Instruction(split(buf))));
|
||||
buf = "";
|
||||
}
|
||||
}
|
||||
} else if (chr == '"') {
|
||||
instring = !instring;
|
||||
} else {
|
||||
buf += chr;
|
||||
}
|
||||
}
|
||||
if (!buf.empty()) {
|
||||
if (buf[0] == '$') {
|
||||
splitvals.push_back(Value(Varname(buf)));
|
||||
} else {
|
||||
splitvals.push_back(Value(buf));
|
||||
}
|
||||
}
|
||||
return splitvals;
|
||||
}
|
||||
|
||||
bool inReplMode = false;
|
||||
55
src/defs/defs.h
Normal file
55
src/defs/defs.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
|
||||
enum class InstructionType {
|
||||
None, Print, Println, Math, Let, Variable, Exit, If, While, Input, Compare
|
||||
};
|
||||
|
||||
enum class ValueType {
|
||||
Real, Processed, Variable, InstructionGroup
|
||||
};
|
||||
|
||||
struct Instruction;
|
||||
|
||||
typedef std::vector<Instruction> InstructionGroup;
|
||||
|
||||
struct Varname {
|
||||
std::string key;
|
||||
Varname(std::string in);
|
||||
Varname();
|
||||
};
|
||||
|
||||
struct Value {
|
||||
ValueType valtype = ValueType::Real;
|
||||
std::unique_ptr<Instruction> processed;
|
||||
std::string real = "";
|
||||
InstructionGroup instructionGroup;
|
||||
std::string toString() const;
|
||||
Varname varName = Varname();
|
||||
Value(std::string stringval);
|
||||
Value(Instruction instval);
|
||||
Value(InstructionGroup instgroup);
|
||||
Value(Varname var);
|
||||
Value();
|
||||
Value(const Value& other);
|
||||
Value& operator=(const Value& other);
|
||||
Value(Value&& other) = default;
|
||||
Value& operator=(Value&& other) = default;
|
||||
};
|
||||
|
||||
struct Instruction {
|
||||
InstructionType instruction = InstructionType::None;
|
||||
std::vector<Value> args;
|
||||
std::string toString() const;
|
||||
Instruction() = default;
|
||||
Instruction(std::vector<std::string> toks);
|
||||
Instruction(std::vector<Value> toks);
|
||||
};
|
||||
|
||||
std::vector<Value> split(std::string in);
|
||||
InstructionType strToInstructionType(std::string in);
|
||||
extern bool inReplMode;
|
||||
11
src/error/error.cpp
Normal file
11
src/error/error.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "error.h"
|
||||
#include "../defs/defs.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
void error(std::string err) {
|
||||
std::cout << "Error: " << err << std::endl;
|
||||
if (!inReplMode) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
6
src/error/error.h
Normal file
6
src/error/error.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
void error(std::string err);
|
||||
80
src/executor/executor.cpp
Normal file
80
src/executor/executor.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#include "executor.h"
|
||||
#include "../defs/defs.h"
|
||||
#include "../data/data.h"
|
||||
#include "../error/error.h"
|
||||
#include "../vars/vars.h"
|
||||
#include "../modules/println/println.h"
|
||||
#include "../modules/print/print.h"
|
||||
#include "../modules/math/math.h"
|
||||
#include "../modules/let/let.h"
|
||||
#include "../modules/exit/exit.h"
|
||||
#include "../modules/if/if.h"
|
||||
#include "../modules/while/while.h"
|
||||
#include "../modules/compare/compare.h"
|
||||
#include "../modules/input/input.h"
|
||||
|
||||
Value execute(Instruction inst) {
|
||||
// Special cases that need to manage their own argument evaluation
|
||||
if (inst.instruction == InstructionType::Let) {
|
||||
return modules::let(inst.args);
|
||||
}
|
||||
if (inst.instruction == InstructionType::If) {
|
||||
return modules::ifs(inst.args);
|
||||
}
|
||||
if (inst.instruction == InstructionType::While) {
|
||||
return modules::whiles(inst.args);
|
||||
}
|
||||
|
||||
// For all other instructions, evaluate the arguments first
|
||||
size_t i = 0;
|
||||
while (i < inst.args.size()) {
|
||||
bool evaluated = false;
|
||||
if (inst.args[i].valtype == ValueType::Processed) {
|
||||
if (inst.args[i].processed) {
|
||||
inst.args[i] = execute(*inst.args[i].processed);
|
||||
evaluated = true;
|
||||
}
|
||||
} else if (inst.args[i].valtype == ValueType::Variable) {
|
||||
inst.args[i] = data::getValue(inst.args[i].varName.key);
|
||||
evaluated = true;
|
||||
}
|
||||
|
||||
if (!evaluated) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Then, execute the instruction with the evaluated arguments
|
||||
switch (inst.instruction) {
|
||||
case InstructionType::Print:
|
||||
return modules::print(inst.args);
|
||||
break;
|
||||
case InstructionType::Println:
|
||||
return modules::println(inst.args);
|
||||
break;
|
||||
case InstructionType::Math:
|
||||
return modules::math(inst.args);
|
||||
break;
|
||||
case InstructionType::Compare:
|
||||
return modules::compare(inst.args);
|
||||
break;
|
||||
case InstructionType::Input:
|
||||
return modules::input(inst.args);
|
||||
break;
|
||||
case InstructionType::Exit:
|
||||
return modules::exit(inst.args);
|
||||
break;
|
||||
case InstructionType::Variable:
|
||||
if (inst.args.size() > 2 && inst.args[1].valtype == ValueType::Real && inst.args[1].real == "=") {
|
||||
return varmod(inst.args);
|
||||
} else {
|
||||
error("Unknown instruction or variable");
|
||||
return Value("");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Note: 'If' and 'Let' are already handled.
|
||||
error("Unknown instruction");
|
||||
return Value("");
|
||||
}
|
||||
}
|
||||
5
src/executor/executor.h
Normal file
5
src/executor/executor.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defs/defs.h"
|
||||
|
||||
Value execute(Instruction inst);
|
||||
18
src/filerun/filerun.cpp
Normal file
18
src/filerun/filerun.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "filerun.h"
|
||||
#include "../parser/parser.h"
|
||||
#include "../executor/executor.h"
|
||||
#include <fstream>
|
||||
|
||||
void execFile(std::string filename) {
|
||||
std::string program;
|
||||
std::ifstream file(filename);
|
||||
std::string buf;
|
||||
while (getline(file, buf)) {
|
||||
program += buf + "\n";
|
||||
}
|
||||
file.close();
|
||||
std::vector<Instruction> parsed = parse(program);
|
||||
for (Instruction inst : parsed) {
|
||||
execute(inst);
|
||||
}
|
||||
}
|
||||
5
src/filerun/filerun.h
Normal file
5
src/filerun/filerun.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
void execFile(std::string filename);
|
||||
22
src/main.cpp
Normal file
22
src/main.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "filerun/filerun.h"
|
||||
#include "repl/repl.h"
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
repl();
|
||||
} else {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-h") || strcmp(argv[i], "--help")) {
|
||||
std::cout << "Kyn programming language" << std::endl;
|
||||
std::cout << "Usage: " << argv[0] << " (filename).kyn" << std::endl;
|
||||
std::cout << "Kyn is licensed to you under the Mozilla Public License v2.0" << std::endl;
|
||||
std::cout << "See the code at https://chookspace.com/max/kyn" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
execFile(argv[1]);
|
||||
}
|
||||
}
|
||||
45
src/modules/compare/compare.cpp
Normal file
45
src/modules/compare/compare.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "compare.h"
|
||||
#include "../../error/error.h"
|
||||
#include "../math/math.h"
|
||||
|
||||
Value modules::compare(std::vector<Value> values) {
|
||||
if (values.size() != 3) {
|
||||
error("Compare instruction requires 3 arguments (e.g., compare 5 == 10)");
|
||||
return Value("0");
|
||||
}
|
||||
|
||||
if (values[0].valtype != ValueType::Real || values[1].valtype != ValueType::Real || values[2].valtype != ValueType::Real) {
|
||||
error("Compare arguments must be real values for now");
|
||||
return Value("0");
|
||||
}
|
||||
|
||||
std::string op = values[1].real;
|
||||
|
||||
if (mathstuff::strisdigit(values[0].real) && mathstuff::strisdigit(values[2].real)) {
|
||||
int lhs = std::stoi(values[0].real);
|
||||
int rhs = std::stoi(values[2].real);
|
||||
bool result = false;
|
||||
|
||||
if (op == "==") result = (lhs == rhs);
|
||||
else if (op == "!=") result = (lhs != rhs);
|
||||
else if (op == ">") result = (lhs > rhs);
|
||||
else if (op == "<") result = (lhs < rhs);
|
||||
else if (op == ">=") result = (lhs >= rhs);
|
||||
else if (op == "<=") result = (lhs <= rhs);
|
||||
else {
|
||||
error("Unknown comparison operator: " + op);
|
||||
}
|
||||
return Value(result ? "1" : "0");
|
||||
} else {
|
||||
std::string lhs = values[0].real;
|
||||
std::string rhs = values[2].real;
|
||||
bool result = false;
|
||||
|
||||
if (op == "==") result = (lhs == rhs);
|
||||
else if (op == "!=") result = (lhs != rhs);
|
||||
else {
|
||||
error("Unknown comparison operator: " + op);
|
||||
}
|
||||
return Value(result ? "1" : "0");
|
||||
}
|
||||
}
|
||||
8
src/modules/compare/compare.h
Normal file
8
src/modules/compare/compare.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../defs/defs.h"
|
||||
#include <vector>
|
||||
|
||||
namespace modules {
|
||||
Value compare(std::vector<Value> values);
|
||||
}
|
||||
12
src/modules/exit/exit.cpp
Normal file
12
src/modules/exit/exit.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "exit.h"
|
||||
#include "../../defs/defs.h"
|
||||
#include <vector>
|
||||
#include "../math/math.h"
|
||||
|
||||
Value modules::exit(std::vector<Value> args) {
|
||||
if (args.size() > 0 && args[0].valtype == ValueType::Real && mathstuff::strisdigit(args[0].real)) {
|
||||
std::exit(stoi(args[0].real));
|
||||
} else {
|
||||
std::exit(0);
|
||||
}
|
||||
}
|
||||
8
src/modules/exit/exit.h
Normal file
8
src/modules/exit/exit.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../defs/defs.h"
|
||||
#include <vector>
|
||||
|
||||
namespace modules {
|
||||
Value exit(std::vector<Value> args);
|
||||
}
|
||||
47
src/modules/if/if.cpp
Normal file
47
src/modules/if/if.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "if.h"
|
||||
#include "../../executor/executor.h"
|
||||
#include "../../error/error.h"
|
||||
|
||||
Value modules::ifs(std::vector<Value> args) {
|
||||
if (args.size() < 2) {
|
||||
error("Syntax error: 'if' statement requires a condition and a body");
|
||||
return Value();
|
||||
}
|
||||
if (args[0].valtype != ValueType::Processed) {
|
||||
error("Syntax error: 'if' condition must be an instruction");
|
||||
return Value();
|
||||
}
|
||||
if (args[1].valtype != ValueType::InstructionGroup) {
|
||||
error("Syntax error: 'if' body must be an instruction group");
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value condition_result = execute(*args[0].processed);
|
||||
|
||||
bool is_true = false;
|
||||
if (condition_result.valtype == ValueType::Real) {
|
||||
if (condition_result.real != "0" && condition_result.real != "false" && !condition_result.real.empty()) {
|
||||
is_true = true;
|
||||
}
|
||||
}
|
||||
|
||||
Value return_val;
|
||||
|
||||
if (is_true) {
|
||||
for (const auto& inst : args[1].instructionGroup) {
|
||||
return_val = execute(inst);
|
||||
}
|
||||
} else {
|
||||
if (args.size() > 2) {
|
||||
if (args[2].valtype == ValueType::InstructionGroup) {
|
||||
for (const auto& inst : args[2].instructionGroup) {
|
||||
return_val = execute(inst);
|
||||
}
|
||||
} else {
|
||||
error("Syntax error: 'else' body must be an instruction group");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return return_val;
|
||||
}
|
||||
8
src/modules/if/if.h
Normal file
8
src/modules/if/if.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../defs/defs.h"
|
||||
#include <vector>
|
||||
|
||||
namespace modules {
|
||||
Value ifs(std::vector<Value> args);
|
||||
}
|
||||
11
src/modules/input/input.cpp
Normal file
11
src/modules/input/input.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "input.h"
|
||||
#include "../../defs/defs.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
Value modules::input(std::vector<Value> args) {
|
||||
std::string userin;
|
||||
std::getline(std::cin, userin);
|
||||
return Value(userin);
|
||||
}
|
||||
8
src/modules/input/input.h
Normal file
8
src/modules/input/input.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../defs/defs.h"
|
||||
#include <vector>
|
||||
|
||||
namespace modules {
|
||||
Value input(std::vector<Value> args);
|
||||
}
|
||||
33
src/modules/let/let.cpp
Normal file
33
src/modules/let/let.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "let.h"
|
||||
#include "../../data/data.h"
|
||||
#include "../../defs/defs.h"
|
||||
#include "../../error/error.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
Value modules::let(std::vector<Value> values) {
|
||||
std::string varName;
|
||||
if (values.size() > 0) {
|
||||
if (values[0].valtype == ValueType::Real) {
|
||||
varName = values[0].real;
|
||||
} else {
|
||||
error("FIXME unprocessed processed (in let module)");
|
||||
}
|
||||
if (values.size() > 1) {
|
||||
if (values[1].valtype == ValueType::Real && values[1].real == "=") {
|
||||
if (values.size() > 2) {
|
||||
data::vars[varName] = values[2];
|
||||
} else {
|
||||
error("Expecting value after token '=' (in let module)");
|
||||
}
|
||||
} else {
|
||||
error("Expecting token '=' (in let module)");
|
||||
}
|
||||
} else {
|
||||
data::vars[varName] = Value("");
|
||||
}
|
||||
} else {
|
||||
error("Expecting variable name (in let module)");
|
||||
}
|
||||
return Value("");
|
||||
}
|
||||
8
src/modules/let/let.h
Normal file
8
src/modules/let/let.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../data/data.h"
|
||||
#include "../../defs/defs.h"
|
||||
|
||||
namespace modules {
|
||||
Value let(std::vector<Value> values);
|
||||
}
|
||||
139
src/modules/math/math.cpp
Normal file
139
src/modules/math/math.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
#include "math.h"
|
||||
#include "../../defs/defs.h"
|
||||
#include "../../error/error.h"
|
||||
#include <vector>
|
||||
|
||||
mathstuff::Part::Part(int in) {
|
||||
num = in;
|
||||
}
|
||||
|
||||
mathstuff::Part::Part(mathstuff::Operators in) {
|
||||
isOperator = true;
|
||||
op = in;
|
||||
}
|
||||
|
||||
bool mathstuff::strisdigit(std::string in) {
|
||||
for (char c : in) {
|
||||
if (!isdigit(c)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Value modules::math(std::vector<Value> values) {
|
||||
std::vector<mathstuff::Part> expression;
|
||||
for (Value value : values) {
|
||||
if (value.valtype == ValueType::Real) {
|
||||
if (value.real == "+") {
|
||||
expression.push_back(mathstuff::Part(mathstuff::Operators::Add));
|
||||
} else if (value.real == "-") {
|
||||
expression.push_back(mathstuff::Part(mathstuff::Operators::Subtract));
|
||||
} else if (value.real == "*") {
|
||||
expression.push_back(mathstuff::Part(mathstuff::Operators::Multiply));
|
||||
} else if (value.real == "/") {
|
||||
expression.push_back(mathstuff::Part(mathstuff::Operators::Divide));
|
||||
} else if (value.real == "^") {
|
||||
expression.push_back(mathstuff::Part(mathstuff::Operators::Power));
|
||||
} else if (value.real == "%") {
|
||||
expression.push_back(mathstuff::Part(mathstuff::Operators::Mod));
|
||||
} else {
|
||||
if (mathstuff::strisdigit(value.real)) {
|
||||
expression.push_back(mathstuff::Part(std::stoi(value.real)));
|
||||
} else {
|
||||
error("Expected an integer or operator (in math module)");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error("FIXME unprocessed process (in math module)");
|
||||
}
|
||||
}
|
||||
|
||||
// Power
|
||||
size_t i = 0;
|
||||
while (i < expression.size()) {
|
||||
if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Power) {
|
||||
if (i >= expression.size() || expression[i + 1].isOperator) {
|
||||
error("Expecting number after * (in math module)");
|
||||
}
|
||||
if (i == 0 || expression[i - 1].isOperator) {
|
||||
error("Expecting number after * (in math module)");
|
||||
}
|
||||
expression[i] = mathstuff::Part(expression[i - 1].num * expression[i + 1].num);
|
||||
expression.erase(std::next(expression.begin(), i + 1));
|
||||
expression.erase(std::next(expression.begin(), i - 1));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// Modulo
|
||||
i = 0;
|
||||
while (i < expression.size()) {
|
||||
if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Mod) {
|
||||
if (i >= expression.size() || expression[i + 1].isOperator) {
|
||||
error("Expecting number after % (in math module)");
|
||||
}
|
||||
if (i == 0 || expression[i - 1].isOperator) {
|
||||
error("Expecting number after % (in math module)");
|
||||
}
|
||||
expression[i] = mathstuff::Part(expression[i - 1].num % expression[i + 1].num);
|
||||
expression.erase(std::next(expression.begin(), i + 1));
|
||||
expression.erase(std::next(expression.begin(), i - 1));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// Multiplication + Division
|
||||
i = 0;
|
||||
while (i < expression.size()) {
|
||||
if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Multiply) {
|
||||
if (i >= expression.size() || expression[i + 1].isOperator) {
|
||||
error("Expecting number after * (in math module)");
|
||||
}
|
||||
if (i == 0 || expression[i - 1].isOperator) {
|
||||
error("Expecting number after * (in math module)");
|
||||
}
|
||||
expression[i] = mathstuff::Part(expression[i - 1].num * expression[i + 1].num);
|
||||
expression.erase(std::next(expression.begin(), i + 1));
|
||||
expression.erase(std::next(expression.begin(), i - 1));
|
||||
} else if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Divide) {
|
||||
if (i >= expression.size() || expression[i].isOperator) {
|
||||
error("Expecting number after / (in math module)");
|
||||
}
|
||||
if (i == 0 || expression[i].isOperator) {
|
||||
error("Expecting number after / (in math module)");
|
||||
}
|
||||
expression[i] = mathstuff::Part(expression[i - 1].num / expression[i + 1].num);
|
||||
expression.erase(std::next(expression.begin(), i + 1));
|
||||
expression.erase(std::next(expression.begin(), i - 1));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// Addition + Subtraction
|
||||
i = 0;
|
||||
while (i < expression.size()) {
|
||||
if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Add) {
|
||||
if (i >= expression.size() || expression[i + 1].isOperator) {
|
||||
error("Expecting number after + (in math module)");
|
||||
}
|
||||
if (i == 0 || expression[i - 1].isOperator) {
|
||||
error("Expecting number after + (in math module)");
|
||||
}
|
||||
expression[i] = mathstuff::Part(expression[i - 1].num + expression[i + 1].num);
|
||||
expression.erase(std::next(expression.begin(), i + 1));
|
||||
expression.erase(std::next(expression.begin(), i - 1));
|
||||
} else if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Subtract) {
|
||||
if (i >= expression.size() || expression[i].isOperator) {
|
||||
error("Expecting number after - (in math module)");
|
||||
}
|
||||
if (i == 0 || expression[i].isOperator) {
|
||||
error("Expecting number after - (in math module)");
|
||||
}
|
||||
expression[i] = mathstuff::Part(expression[i - 1].num - expression[i + 1].num);
|
||||
expression.erase(std::next(expression.begin(), i + 1));
|
||||
expression.erase(std::next(expression.begin(), i - 1));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return Value(std::to_string(expression[0].num));
|
||||
}
|
||||
24
src/modules/math/math.h
Normal file
24
src/modules/math/math.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../defs/defs.h"
|
||||
#include <vector>
|
||||
|
||||
namespace mathstuff {
|
||||
enum class Operators {
|
||||
Add, Subtract, Multiply, Divide, Mod, Power, None
|
||||
};
|
||||
|
||||
bool strisdigit(std::string in);
|
||||
|
||||
struct Part {
|
||||
Part(int in);
|
||||
Part(Operators in);
|
||||
bool isOperator = false;
|
||||
int num = 0;
|
||||
Operators op = Operators::None;
|
||||
};
|
||||
}
|
||||
|
||||
namespace modules {
|
||||
Value math(std::vector<Value> values);
|
||||
}
|
||||
17
src/modules/print/print.cpp
Normal file
17
src/modules/print/print.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "print.h"
|
||||
#include "../../defs/defs.h"
|
||||
#include "../../error/error.h"
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
Value modules::print(std::vector<Value> values) {
|
||||
for (Value value : values) {
|
||||
if (value.valtype == ValueType::Real) {
|
||||
std::cout << value.real << " ";
|
||||
} else {
|
||||
error("FIXME unprocessed processed (in print module)");
|
||||
}
|
||||
}
|
||||
return Value("");
|
||||
}
|
||||
8
src/modules/print/print.h
Normal file
8
src/modules/print/print.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../defs/defs.h"
|
||||
#include <vector>
|
||||
|
||||
namespace modules {
|
||||
Value print(std::vector<Value> values);
|
||||
}
|
||||
18
src/modules/println/println.cpp
Normal file
18
src/modules/println/println.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "println.h"
|
||||
#include "../../defs/defs.h"
|
||||
#include "../../error/error.h"
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
Value modules::println(std::vector<Value> values) {
|
||||
for (Value value : values) {
|
||||
if (value.valtype == ValueType::Real) {
|
||||
std::cout << value.real << " ";
|
||||
} else {
|
||||
error("FIXME unprocessed processed (in println module)");
|
||||
}
|
||||
}
|
||||
std::cout << "\n";
|
||||
return Value("");
|
||||
}
|
||||
8
src/modules/println/println.h
Normal file
8
src/modules/println/println.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../defs/defs.h"
|
||||
#include <vector>
|
||||
|
||||
namespace modules {
|
||||
Value println(std::vector<Value> values);
|
||||
}
|
||||
45
src/modules/while/while.cpp
Normal file
45
src/modules/while/while.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "while.h"
|
||||
#include "../../executor/executor.h"
|
||||
#include "../../error/error.h"
|
||||
|
||||
Value modules::whiles(std::vector<Value> args) {
|
||||
if (args.size() < 2) {
|
||||
error("Syntax error: 'while' statement requires a condition and a body");
|
||||
return Value();
|
||||
}
|
||||
if (args[0].valtype != ValueType::Processed) {
|
||||
error("Syntax error: 'while' condition must be an instruction");
|
||||
return Value();
|
||||
}
|
||||
if (args[1].valtype != ValueType::InstructionGroup) {
|
||||
error("Syntax error: 'while' body must be an instruction group");
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value condition_result = execute(*args[0].processed);
|
||||
|
||||
bool is_true = false;
|
||||
if (condition_result.valtype == ValueType::Real) {
|
||||
if (condition_result.real != "0" && condition_result.real != "false" && !condition_result.real.empty()) {
|
||||
is_true = true;
|
||||
}
|
||||
}
|
||||
|
||||
Value return_val;
|
||||
|
||||
while (is_true) {
|
||||
for (const auto& inst : args[1].instructionGroup) {
|
||||
return_val = execute(inst);
|
||||
}
|
||||
condition_result = execute(*args[0].processed);
|
||||
|
||||
is_true = false;
|
||||
if (condition_result.valtype == ValueType::Real) {
|
||||
if (condition_result.real != "0" && condition_result.real != "false" && !condition_result.real.empty()) {
|
||||
is_true = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return return_val;
|
||||
}
|
||||
8
src/modules/while/while.h
Normal file
8
src/modules/while/while.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../defs/defs.h"
|
||||
#include <vector>
|
||||
|
||||
namespace modules {
|
||||
Value whiles(std::vector<Value> args);
|
||||
}
|
||||
145
src/parser/parser.cpp
Normal file
145
src/parser/parser.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
#include "parser.h"
|
||||
#include "../error/error.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Helper to trim whitespace
|
||||
std::string trim(const std::string& str) {
|
||||
size_t first = str.find_first_not_of(" \t\n\r");
|
||||
if (std::string::npos == first) {
|
||||
return str;
|
||||
}
|
||||
size_t last = str.find_last_not_of(" \t\n\r");
|
||||
return str.substr(first, (last - first + 1));
|
||||
}
|
||||
|
||||
std::vector<Instruction> parse(std::string program) {
|
||||
std::vector<Instruction> instructions;
|
||||
std::vector<std::string> lines;
|
||||
std::string buf;
|
||||
int blockTracker = 0;
|
||||
|
||||
for (char chr : program) {
|
||||
if (chr == '{') {
|
||||
blockTracker++;
|
||||
} else if (chr == '}') {
|
||||
if (blockTracker > 0) {
|
||||
blockTracker--;
|
||||
} else {
|
||||
error("Expected opening '{' to match closing '}'");
|
||||
}
|
||||
}
|
||||
|
||||
if ((chr == '\n' || chr == ';') && blockTracker == 0) {
|
||||
if (!buf.empty()) {
|
||||
lines.push_back(buf);
|
||||
buf.clear();
|
||||
}
|
||||
} else {
|
||||
buf.push_back(chr);
|
||||
}
|
||||
}
|
||||
|
||||
if (blockTracker != 0) {
|
||||
error("Expected closing '}' to match opening '{'");
|
||||
}
|
||||
if (!buf.empty()) {
|
||||
lines.push_back(buf);
|
||||
}
|
||||
|
||||
for (std::string line : lines) {
|
||||
line = trim(line);
|
||||
if (line.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.rfind("if", 0) == 0) {
|
||||
Instruction if_inst;
|
||||
if_inst.instruction = InstructionType::If;
|
||||
|
||||
size_t block_start = line.find('{');
|
||||
if (block_start == std::string::npos) {
|
||||
error("Expected '{' for if statement");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 1. Condition
|
||||
std::string condition_str = line.substr(2, block_start - 2);
|
||||
if_inst.args.push_back(Value(Instruction(split(trim(condition_str)))));
|
||||
|
||||
// 2. Find 'then' block
|
||||
size_t block_end = 0;
|
||||
int brace_level = 0;
|
||||
for (size_t i = block_start; i < line.length(); ++i) {
|
||||
if (line[i] == '{') brace_level++;
|
||||
else if (line[i] == '}') brace_level--;
|
||||
if (brace_level == 0) {
|
||||
block_end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (block_end == 0) {
|
||||
error("Mismatched braces in if statement");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string then_content = line.substr(block_start + 1, block_end - block_start - 1);
|
||||
if_inst.args.push_back(Value(parse(then_content))); // Recursive call
|
||||
|
||||
// 3. Else block (optional)
|
||||
std::string remaining_line = trim(line.substr(block_end + 1));
|
||||
if (remaining_line.rfind("else", 0) == 0) {
|
||||
size_t else_block_start = remaining_line.find('{');
|
||||
if (else_block_start == std::string::npos) {
|
||||
error("Expected '{' for else statement");
|
||||
continue;
|
||||
}
|
||||
size_t else_block_end = remaining_line.find_last_of('}');
|
||||
if (else_block_end == std::string::npos) {
|
||||
error("Expected '}' for else statement");
|
||||
continue;
|
||||
}
|
||||
std::string else_content = remaining_line.substr(else_block_start + 1, else_block_end - else_block_start - 1);
|
||||
if_inst.args.push_back(Value(parse(else_content)));
|
||||
}
|
||||
|
||||
instructions.push_back(if_inst);
|
||||
} else if (line.rfind("while", 0) == 0) {
|
||||
Instruction while_inst;
|
||||
while_inst.instruction = InstructionType::While;
|
||||
|
||||
size_t block_start = line.find('{');
|
||||
if (block_start == std::string::npos) {
|
||||
error("Expected '{' for while statement");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 1. Condition
|
||||
std::string condition_str = line.substr(5, block_start - 5);
|
||||
while_inst.args.push_back(Value(Instruction(split(trim(condition_str)))));
|
||||
|
||||
// 2. Find 'then' block
|
||||
size_t block_end = 0;
|
||||
int brace_level = 0;
|
||||
for (size_t i = block_start; i < line.length(); ++i) {
|
||||
if (line[i] == '{') brace_level++;
|
||||
else if (line[i] == '}') brace_level--;
|
||||
if (brace_level == 0) {
|
||||
block_end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (block_end == 0) {
|
||||
error("Mismatched braces in while statement");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string then_content = line.substr(block_start + 1, block_end - block_start - 1);
|
||||
while_inst.args.push_back(Value(parse(then_content))); // Recursive call
|
||||
instructions.push_back(while_inst);
|
||||
} else {
|
||||
instructions.push_back(Instruction(split(line)));
|
||||
}
|
||||
}
|
||||
return instructions;
|
||||
}
|
||||
7
src/parser/parser.h
Normal file
7
src/parser/parser.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "../defs/defs.h"
|
||||
|
||||
std::vector<Instruction> parse(std::string lines);
|
||||
21
src/repl/repl.cpp
Normal file
21
src/repl/repl.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "repl.h"
|
||||
#include "../executor/executor.h"
|
||||
#include "../parser/parser.h"
|
||||
#include "../defs/defs.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
void repl() {
|
||||
inReplMode = true;
|
||||
std::cout << "Kyn REPL v0.0.1" << std::endl;
|
||||
std::cout << "Type 'exit' to exit" << std::endl;
|
||||
std::string buf;
|
||||
while (true) {
|
||||
std::cout << "kyn> ";
|
||||
getline(std::cin, buf);
|
||||
std::vector<Instruction> parsed = parse(buf);
|
||||
for (Instruction inst : parsed) {
|
||||
execute(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
1
src/repl/repl.h
Normal file
1
src/repl/repl.h
Normal file
@@ -0,0 +1 @@
|
||||
void repl();
|
||||
22
src/vars/vars.cpp
Normal file
22
src/vars/vars.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "vars.h"
|
||||
|
||||
#include "../data/data.h"
|
||||
#include "../defs/defs.h"
|
||||
#include "../error/error.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
Value varmod(std::vector<Value> args) {
|
||||
if (args.size() < 3) {
|
||||
error("Not enough args to reassign variable");
|
||||
}
|
||||
if (args[1].real != "=") {
|
||||
error("Expecting '=' token");
|
||||
}
|
||||
if (args[0].valtype == ValueType::Real) {
|
||||
data::modifyValue(args[0].real, args[2]);
|
||||
} else {
|
||||
error("Invalid variable name for assignment");
|
||||
}
|
||||
return Value("");
|
||||
}
|
||||
6
src/vars/vars.h
Normal file
6
src/vars/vars.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defs/defs.h"
|
||||
#include <vector>
|
||||
|
||||
Value varmod(std::vector<Value> args);
|
||||
Reference in New Issue
Block a user