Modules/Objects/private/parser/Parser.cpp
Шурупов Илья Викторович 1ecdc9a12a Objects: fix interpreter ownership and add program test matrix
Compile the self expression to its dedicated opcode, stop double-referencing locals and arguments, and return the null singleton without an extra reference. Run arithmetic, loop, conditional, function-return, class-method, and method-call programs both headless and through IDE stepping with state-object assertions, and guard runtime tabs against small immediate operands.
2026-10-27 18:17:31 +03:00

245 lines
8 KiB
C++

#include "parser/Parser.hpp"
#include "Private.hpp"
#include "interpreter/OperatoinCodes.hpp"
using namespace tp;
using namespace obj;
#include "oscript.g.hpp"
namespace {
class AstBuilder {
public:
AstBuilder(OScriptParser& parser, const char* source) :
mParser(parser),
mSource(source) {}
Statement* buildScript(OScriptNode node) {
if (node->leafs.size() == 0) {
return new StatementScope({}, true);
}
return buildStatementScope(node->leafs[0]);
}
private:
OScriptParser& mParser;
const char* mSource;
String action(OScriptNode node) { return mParser.actionOf(node); }
std::string lexeme(OScriptNode node) {
String s = mParser.lexemeOf(mSource, node);
return std::string(s.read());
}
static bool is(const String& action, const char* name) {
const char* a = action.read();
const char* b = name;
while (*a && *b) {
if (*a != *b) return false;
a++;
b++;
}
return *a == *b;
}
StatementScope* buildStatementScope(OScriptNode stmts) {
String act = action(stmts);
if (is(act, "stm_list_create")) {
return new StatementScope({ buildStatement(stmts->leafs[0]) }, true);
}
auto scope = buildStatementScope(stmts->leafs[0]);
scope->mStatements.append(buildStatement(stmts->leafs[1]));
return scope;
}
StatementScope* buildScope(OScriptNode node) {
String act = action(node);
if (is(act, "scope_empty")) {
return new StatementScope({}, true);
}
return buildStatementScope(node->leafs[1]);
}
Statement* buildStatement(OScriptNode stmt) {
OScriptNode inner = stmt->leafs[0];
String act = action(inner);
if (is(act, "stm_def_method")) return buildDefMethod(inner);
if (is(act, "stm_def_class")) return buildDefClass(inner);
if (is(act, "stm_if")) return buildIf(inner);
if (is(act, "stm_while_loop")) return buildWhile(inner);
if (is(act, "stm_return")) return buildReturn(inner);
if (is(act, "stm_var_def_new_type")) return buildVarDefNewType(inner);
if (is(act, "stm_var_def_assign")) return buildVarDefAssign(inner);
if (is(act, "stm_log")) return buildLog(inner);
if (is(act, "stm_assign")) return buildAssign(inner);
if (is(act, "stm_ignore")) return buildIgnore(inner);
if (is(act, "stm_break")) return nullptr;
return nullptr;
}
Statement* buildDefMethod(OScriptNode node) {
auto method = new StatementFuncDef(lexeme(node->leafs[1]));
method->mStatements = buildScope(node->leafs[5]);
Buffer<std::string> args;
buildIdList(node->leafs[3], args);
method->mArgs = args;
return method;
}
Statement* buildDefClass(OScriptNode node) {
return new StatementClassDef(lexeme(node->leafs[1]), buildScope(node->leafs[2]));
}
Statement* buildIf(OScriptNode node) {
Expression* cond = buildExpr(node->leafs[2]);
StatementScope* onTrue = buildScope(node->leafs[4]);
if (node->leafs.size() == 5) {
return new StatementIf(cond, onTrue, nullptr);
}
return new StatementIf(cond, onTrue, buildScope(node->leafs[6]));
}
Statement* buildWhile(OScriptNode node) {
return new StatementWhile(buildExpr(node->leafs[2]), buildScope(node->leafs[4]));
}
Statement* buildReturn(OScriptNode node) {
if (node->leafs.size() == 2) {
return new StatementReturn(buildExpr(node->leafs[1]));
}
return new StatementReturn();
}
Statement* buildVarDefNewType(OScriptNode node) {
return new StatementLocalDef(lexeme(node->leafs[1]), new ExpressionNew(lexeme(node->leafs[3])));
}
Statement* buildVarDefAssign(OScriptNode node) {
return new StatementLocalDef(lexeme(node->leafs[1]), buildExpr(node->leafs[3]));
}
Statement* buildLog(OScriptNode node) { return new StatementPrint(buildExpr(node->leafs[1])); }
Statement* buildAssign(OScriptNode node) {
return new StatementCopy(buildExpr(node->leafs[0]), buildExpr(node->leafs[2]));
}
Statement* buildIgnore(OScriptNode node) { return new StatementIgnore(buildExpr(node->leafs[0])); }
void buildIdList(OScriptNode node, Buffer<std::string>& out) {
if (node->leafs.size() == 0) return;
String act = action(node);
if (is(act, "id_list_create")) {
out.append(lexeme(node->leafs[0]));
return;
}
buildIdList(node->leafs[0], out);
out.append(lexeme(node->leafs[2]));
}
Expression* buildExpr(OScriptNode node) {
String act = action(node);
if (is(act, "expr_function")) {
auto fn = new ExpressionLocal(lexeme(node->leafs[0]).c_str());
auto args = (ExpressionList*) buildExprList(node->leafs[2]);
return fn->ExprCall(args);
}
if (is(act, "expr_method")) {
auto parent = buildExpr(node->leafs[0]);
auto args = (ExpressionList*) buildExprList(node->leafs[4]);
auto method = new ExpressionChild(parent, lexeme(node->leafs[2]).c_str());
return method->ExprCall(args);
}
if (is(act, "expr_child")) {
return new ExpressionChild(buildExpr(node->leafs[0]), lexeme(node->leafs[2]).c_str());
}
if (is(act, "expr_bool_eq")) return boolExpr(node, ExpressionBoolean::BoolType::EQUAL);
if (is(act, "expr_bool_neq")) return boolExpr(node, ExpressionBoolean::BoolType::NOT_EQUAL);
if (is(act, "expr_bool_grater")) return boolExpr(node, ExpressionBoolean::BoolType::MORE);
if (is(act, "expr_bool_lesser")) return boolExpr(node, ExpressionBoolean::BoolType::LESS);
if (is(act, "expr_bool_grater_eq")) return boolExpr(node, ExpressionBoolean::BoolType::EQUAL_OR_MORE);
if (is(act, "expr_bool_lesser_eq")) return boolExpr(node, ExpressionBoolean::BoolType::EQUAL_OR_LESS);
if (is(act, "expr_bool_negate")) return new ExpressionBoolean(buildExpr(node->leafs[1]));
if (is(act, "expr_add")) return arithExpr(node, obj::OpCode::OBJ_ADD);
if (is(act, "expr_subtract")) return arithExpr(node, obj::OpCode::OBJ_SUB);
if (is(act, "expr_multiply")) return arithExpr(node, obj::OpCode::OBJ_MUL);
if (is(act, "expr_divide")) return arithExpr(node, obj::OpCode::OBJ_DIV);
if (is(act, "expr_compound")) return buildExpr(node->leafs[1]);
if (is(act, "expr_bool")) return new ExpressionConst(lexeme(node->leafs[0]) == "true");
if (is(act, "expr_int")) return new ExpressionConst((alni) stoll(lexeme(node->leafs[0])));
if (is(act, "expr_float")) return new ExpressionConst((flt4) stof(lexeme(node->leafs[0])));
if (is(act, "expr_string")) {
std::string raw = lexeme(node->leafs[0]);
std::string inner = raw.size() >= 2 ? raw.substr(1, raw.size() - 2) : std::string();
return new ExpressionConst(inner.c_str());
}
if (is(act, "expr_id")) {
auto id = lexeme(node->leafs[0]);
if (id == "self") return new ExpressionSelf();
return new ExpressionLocal(id.c_str());
}
return nullptr;
}
Expression* buildExprList(OScriptNode node) {
if (node->leafs.size() == 0) {
return new ExpressionList();
}
String act = action(node);
if (is(act, "expr_list_create")) {
auto list = new ExpressionList();
list->mItems.append(buildExpr(node->leafs[0]));
return list;
}
auto list = (ExpressionList*) buildExprList(node->leafs[0]);
list->mItems.append(buildExpr(node->leafs[2]));
return list;
}
Expression* boolExpr(OScriptNode node, ExpressionBoolean::BoolType type) {
return new ExpressionBoolean(buildExpr(node->leafs[0]), buildExpr(node->leafs[2]), type);
}
Expression* arithExpr(OScriptNode node, obj::OpCode op) {
return new ExpressionArithmetics(buildExpr(node->leafs[0]), buildExpr(node->leafs[2]), op);
}
};
struct GrammarHolder {
OScriptParser parser;
bool compiled = false;
GrammarHolder() { compiled = parser.compileTables(oscript_grammar, String::Logic::calcLength(oscript_grammar)); }
};
OScriptParser& grammarParser() {
static GrammarHolder holder;
return holder.parser;
}
}
obj::Parser::Result obj::Parser::parse(const std::string& stream) {
std::string src = stream;
src += "\n";
OScriptParser& parser = grammarParser();
auto res = parser.parse(src.c_str(), (ualni) src.size());
if (!res.accepted || !res.ast) {
return { nullptr, true };
}
AstBuilder builder(parser, src.c_str());
auto* scope = (StatementScope*) builder.buildScript(res.ast);
return { scope, false };
}