TudorLang/include/Interpreter.hpp
2025-07-18 21:25:22 +08:00

138 lines
5.7 KiB
C++

#pragma once
#include "Lexer.hpp"
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <format>
#include <iostream>
#include <map>
#include <stdexcept>
#include <string>
#include <utility>
#include <variant>
#include <vector>
namespace ztl{
inline void interpreter(const std::vector<Token> &tokens){
using ObjectType = std::variant<int64_t>;
std::map<std::string, ObjectType> objects;
const auto getValueOrLiteral = [&tokens,&objects](size_t i){
ObjectType a;
if(tokens[i].type==TokenType::Literal){
a=atoi(tokens[i].str.data());
}else if(tokens[i].type==TokenType::Identifier){
if(auto it = objects.find(tokens[i].str);it!=objects.end()){
a=(*it).second;
}else{
throw std::runtime_error(std::format("error in getting value named '{}'",tokens[i].str));
}
}else{
throw std::runtime_error("error in getting expression result");
}
return a;
};
const auto getExprAns = [&getValueOrLiteral,&objects,&tokens](size_t i)->std::pair<ObjectType, size_t>{
ObjectType a=getValueOrLiteral(i);
ObjectType b;
if(i+1<tokens.size()&&tokens[i+1].type==TokenType::Operator){
if(tokens[i+1].type==TokenType::Operator){
if(i+2<tokens.size()){
b=getValueOrLiteral(i+2);
}else{
throw std::runtime_error(std::format("error getting a op b, b is not found. a named '{}'",tokens[i].str));
}
}else{
throw std::runtime_error(std::format("unknown operator '{}'",tokens[i+1].str));
}
}else{
return {a,1};
}
ObjectType res;
if(std::holds_alternative<int64_t>(a) && std::holds_alternative<int64_t>(b)){
if(tokens[i+1].str=="+"){
res = std::get<int64_t>(a) + std::get<int64_t>(b);
}else if(tokens[i+1].str=="-"){
res = std::get<int64_t>(a) - std::get<int64_t>(b);
}
else{
throw std::runtime_error(std::format("unknown operator '{}' ",tokens[i+1].str));
}
}else{
throw std::runtime_error(std::format("unknown value type '{}' ,'{}'",tokens[i].str,tokens[i+2].str));
}
return {res,3};
};
for(size_t i=0;i<tokens.size();i++){
const auto eat = [&i,&tokens](const std::string &s){
if(i+1<tokens.size()&&tokens[i+1].str==s){
i++;
}else{
throw std::runtime_error(std::format("cannot get '{}' after '{}'",s,tokens[i].str));
}
};
if(tokens[i].type==TokenType::Keyword){
if(tokens[i].str=="int"){
if( i+2<tokens.size()
&&tokens[i+1].type==TokenType::Identifier
&& tokens[i+2].str=="="
){
std::string valueName = tokens[i+1].str;
i+=2;
auto res = getExprAns(i+1);
objects[valueName] = res.first;
i+=res.second;
}else{
throw std::runtime_error(std::format("error when creatting int value '{}'",tokens[i].str));
}
}
else if(tokens[i].str=="print"){
if(i+1<tokens.size()&&tokens[i+1].str=="("){
i++;
}else{
throw std::runtime_error("cannot get '(' when printing value");
}
if(!(i+1<tokens.size()))throw std::runtime_error("cannot get value be printed when printing value");
auto [res,addi] = getExprAns(i+1);
i+=addi;
if(i+1<tokens.size()&&tokens[i+1].str==")"){
i++;
}else{
throw std::runtime_error("cannot get ')' when printing value");
}
std::visit([](auto &res){
std::cout<<res<<'\n';
},res);
}
else{
throw std::runtime_error(std::format("interpreter error Cannot find Keyword '{}'",tokens[i].str));
}
}else if(tokens[i].type==TokenType::Identifier){
if( i+1<tokens.size()
&& tokens[i+1].str=="="
){
std::string valueName = tokens[i].str;
i+=1;
auto res = getExprAns(i+1);
if(auto it = objects.find(valueName);it!=objects.end()){
if(it->second.index()!=res.first.index()){
throw std::runtime_error(std::format("cannot give value to {}, because type is not same",valueName));
}
}else{
throw std::runtime_error(std::format("error when getting int value named '{}'",valueName));
}
objects[valueName] = res.first;
i+=res.second;
}else{
throw std::runtime_error(std::format("error when creatting int value '{}'",tokens[i].str));
}
}
else{
throw std::runtime_error(std::format("interpreter error at '{}'",tokens[i].str));
}
eat(";");
}
}
}