Add better error message

This commit is contained in:
2025-12-16 03:11:52 -06:00
parent bbf122a7eb
commit deb492b8c4
18 changed files with 300 additions and 20 deletions

View File

@@ -173,6 +173,7 @@ src/vm/filereader.cpp
src/vm/gc.cpp src/vm/gc.cpp
src/vm/gclist.cpp src/vm/gclist.cpp
src/vm/vm.cpp src/vm/vm.cpp
src/vm/exception.cpp
src/archive.cpp src/archive.cpp
src/markedtobject.cpp src/markedtobject.cpp
) )

View File

@@ -661,7 +661,8 @@ typedef enum {
JMPIFBREAK, JMPIFBREAK,
JMPIFCONTINUE, JMPIFCONTINUE,
JMPIFDEFINED, JMPIFDEFINED,
DECLARECONSTVARIABLE DECLARECONSTVARIABLE,
LINEINFO
} Instruction; } Instruction;
/** /**
* @brief Base type for bytecode instruction * @brief Base type for bytecode instruction
@@ -1239,6 +1240,10 @@ constexpr std::string_view AwaitExpression = "awaitExpression";
* @brief ?? operator * @brief ?? operator
*/ */
constexpr std::string_view NullCoalescingExpression = "nullCoalescingExpression"; constexpr std::string_view NullCoalescingExpression = "nullCoalescingExpression";
/**
* @brief For debugging (store line info and filename)
*/
constexpr std::string_view LineNode="lineNode";
/** /**
* @brief Advanced AST node * @brief Advanced AST node
* *
@@ -1315,8 +1320,11 @@ class Parser {
void ParseHtml(std::vector<SyntaxNode>& nodes,std::string var); void ParseHtml(std::vector<SyntaxNode>& nodes,std::string var);
GC* gc; GC* gc;
TRootEnvironment* env; TRootEnvironment* env;
int lastLine=-1;
std::string lastFile="";
bool CanEmit(LexTokenLineInfo& token);
public: public:
bool debug=true;
/** /**
* @brief Construct a new Parser object * @brief Construct a new Parser object
* *
@@ -1455,6 +1463,7 @@ class GC {
TFile* file; TFile* file;
std::vector<uint8_t> code; std::vector<uint8_t> code;
std::vector<std::string> args; std::vector<std::string> args;
std::optional<std::string> name;
void Mark(); void Mark();
}; };
@@ -1642,6 +1651,7 @@ class GC {
void DeclareFunction(GC* gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy); void DeclareFunction(GC* gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy);
void DeclareFunction(GC& gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy); void DeclareFunction(GC& gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy);
TObject CallMethod(GCList& ls, std::string key, std::vector<TObject> args); TObject CallMethod(GCList& ls, std::string key, std::vector<TObject> args);
TObject CallMethodWithFatalError(GCList& ls, std::string key, std::vector<TObject> args);
}; };
@@ -1655,9 +1665,12 @@ class GC {
TObject tag; TObject tag;
std::string documentation; std::string documentation;
virtual TObject Call(GCList& ls,std::vector<TObject> args)=0; virtual TObject Call(GCList& ls,std::vector<TObject> args)=0;
TObject CallWithFatalError(GCList& ls, std::vector<TObject> args);
virtual void Mark(); virtual void Mark();
}; };
void ThrowFatalError(std::exception& ex);
void ThrowConstError(std::string key); void ThrowConstError(std::string key);
class TEnvironment : public THeapObject { class TEnvironment : public THeapObject {
@@ -1694,7 +1707,7 @@ class GC {
void DeclareFunction(GC* gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy); void DeclareFunction(GC* gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy);
void DeclareFunction(GC& gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy); void DeclareFunction(GC& gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy);
TObject CallFunction(GCList& ls, std::string key, std::vector<TObject> args); TObject CallFunction(GCList& ls, std::string key, std::vector<TObject> args);
TObject CallFunctionWithFatalError(GCList& ls, std::string key, std::vector<TObject> args);
}; };
class TClassEnvironment; class TClassEnvironment;
class TClassObject : public THeapObject class TClassObject : public THeapObject
@@ -2134,18 +2147,21 @@ class GC {
~TDynamicDictionary(); ~TDynamicDictionary();
}; };
class InterperterThread;
class CallStackEntry : public THeapObject class CallStackEntry : public THeapObject
{ {
public: public:
static CallStackEntry* Create(GCList* ls); static CallStackEntry* Create(GCList* ls);
static CallStackEntry* Create(GCList& ls); static CallStackEntry* Create(GCList& ls);
InterperterThread* thread;
std::vector<TObject> stack; std::vector<TObject> stack;
TEnvironment* env; TEnvironment* env;
TClosure* callable; TClosure* callable;
uint32_t ip; uint32_t ip;
uint32_t scopes; uint32_t scopes;
int64_t srcline;
std::string srcfile;
bool mustReturn; bool mustReturn;
void Mark(); void Mark();
@@ -2262,6 +2278,7 @@ class GC {
bool PushContinue(GC* gc); bool PushContinue(GC* gc);
bool JumpIfBreak(GC* gc); bool JumpIfBreak(GC* gc);
bool JumpIfContinue(GC* gc); bool JumpIfContinue(GC* gc);
bool LineInfo(GC* gc);
public: public:
static InterperterThread* Create(GCList* ls); static InterperterThread* Create(GCList* ls);
static InterperterThread* Create(GCList& ls); static InterperterThread* Create(GCList& ls);
@@ -2387,22 +2404,30 @@ class GC {
public: public:
TObject exception; TObject exception;
std::vector<CallStackEntry*> stack_trace;
VMByteCodeException() VMByteCodeException()
{ {
} }
VMByteCodeException(GC* gc,TObject obj) VMByteCodeException(GC* gc,TObject obj, CallStackEntry* ent)
{ {
gcList = std::make_shared<GCList>(gc); gcList = std::make_shared<GCList>(gc);
gcList.get()->Add(obj); gcList->Add(obj);
if(ent != nullptr && ent->thread != nullptr)
{
this->stack_trace = ent->thread->call_stack_entries;
for(auto item : this->stack_trace)
gcList->Add(item);
}
this->exception = obj; this->exception = obj;
UpdateError(); UpdateError();
} }
void UpdateError() void UpdateError()
{ {
lastErrorText = ToString(gcList.get()->GetGC(),exception); lastErrorText = ToString(gcList->GetGC(),exception);
} }
@@ -2410,14 +2435,19 @@ class GC {
{ {
return lastErrorText.c_str(); return lastErrorText.c_str();
} }
std::shared_ptr<GCList> GetGCList() {
return this->gcList;
}
}; };
class SyntaxException : public std::exception class SyntaxException : public std::exception
{ {
std::string msg={}; std::string msg={};
LexTokenLineInfo line;
std::string message;
public: public:
SyntaxException(LexTokenLineInfo lineInfo, std::string message) SyntaxException(LexTokenLineInfo lineInfo, std::string message) : line(lineInfo), message(message)
{ {
msg.append("in file: "); msg.append("in file: ");
msg.append(lineInfo.filename); msg.append(lineInfo.filename);
@@ -2434,6 +2464,9 @@ class GC {
{ {
return msg.c_str(); return msg.c_str();
} }
std::string Message() { return message;}
LexTokenLineInfo LineInfo() { return line;}
}; };

View File

@@ -281,6 +281,10 @@ namespace Tesses::CrossLang {
{ {
instrs.push_back(std::make_shared<SimpleChunkInstruction>(NOP)); instrs.push_back(std::make_shared<SimpleChunkInstruction>(NOP));
} }
else if(name == "lineinfo")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(LINEINFO));
}
else if(name == "pushclosure") else if(name == "pushclosure")
{ {
auto closure = std::make_shared<ClosureChunkInstruction>(true); auto closure = std::make_shared<ClosureChunkInstruction>(true);

View File

@@ -571,6 +571,9 @@ namespace Tesses::CrossLang {
case BREAKPOINT: case BREAKPOINT:
buffer.append("breakpoint"); buffer.append("breakpoint");
break; break;
case LINEINFO:
buffer.append("lineinfo");
break;
case PUSHBREAK: case PUSHBREAK:
buffer.append("push break"); buffer.append("push break");
break; break;

View File

@@ -522,7 +522,14 @@ namespace Tesses::CrossLang
TWO_EXPR(NotEqualsExpression, NEQ) TWO_EXPR(NotEqualsExpression, NEQ)
TWO_EXPR(EqualsExpression, EQ) TWO_EXPR(EqualsExpression, EQ)
TWO_EXPR(XOrExpression, XOR) TWO_EXPR(XOrExpression, XOR)
if(adv.nodeName == NullCoalescingExpression && adv.nodes.size() == 2) if(adv.nodeName == LineNode && adv.nodes.size() == 2)
{
GenNode(instructions,adv.nodes[0],scope,contscope,brkscope,contI,brkI);
GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI);
instructions.push_back(new SimpleInstruction(LINEINFO));
}
else if(adv.nodeName == NullCoalescingExpression && adv.nodes.size() == 2)
{ {
uint32_t ifId = NewId(); uint32_t ifId = NewId();
std::string ifIdTrue = "__compGenTrue"; std::string ifIdTrue = "__compGenTrue";

View File

@@ -1304,6 +1304,15 @@ namespace Tesses::CrossLang
} }
return node; return node;
} }
bool Parser::CanEmit(LexTokenLineInfo& ifo)
{
if(!this->debug) return false;
bool same = ifo.line == this->lastLine && ifo.filename == this->lastFile;
this->lastFile = ifo.filename;
this->lastLine = ifo.line;
return !same;
}
SyntaxNode Parser::ParseNode(bool isRoot) SyntaxNode Parser::ParseNode(bool isRoot)
{ {
std::string documentation=""; std::string documentation="";
@@ -1324,6 +1333,8 @@ namespace Tesses::CrossLang
while(i < tokens.size() && (isRoot || !IsSymbol("}",false))) while(i < tokens.size() && (isRoot || !IsSymbol("}",false)))
{ {
auto token = tokens[i];
if(CanEmit(token.lineInfo)) aSN.nodes.push_back(AdvancedSyntaxNode::Create(LineNode,false, {(int64_t)tokens[i].lineInfo.line,tokens[i].lineInfo.filename}));
aSN.nodes.push_back(ParseNode()); aSN.nodes.push_back(ParseNode());
IsSymbol(";"); IsSymbol(";");
} }

View File

@@ -127,7 +127,7 @@ int main(int argc, char** argv)
for(int arg=1;arg<argc;arg++) for(int arg=1;arg<argc;arg++)
args->Add(std::string(argv[arg])); args->Add(std::string(argv[arg]));
auto res = env->CallFunction(ls,"main",{args}); auto res = env->CallFunctionWithFatalError(ls,"main",{args});
int64_t iresult; int64_t iresult;
if(GetObject(res,iresult)) if(GetObject(res,iresult))
return (int)iresult; return (int)iresult;

View File

@@ -13,6 +13,7 @@ void Help(const char* filename)
printf(" -I: Set icon resource name (in the resource folder), should be a 128x128 png\n"); printf(" -I: Set icon resource name (in the resource folder), should be a 128x128 png\n");
printf(" -v: Set version (1.0.0.0-prod defaults to 1.0.0.0-dev)\n"); printf(" -v: Set version (1.0.0.0-prod defaults to 1.0.0.0-dev)\n");
printf(" -d: Add dependency (DependencyName-1.0.0.0-prod)\n"); printf(" -d: Add dependency (DependencyName-1.0.0.0-prod)\n");
printf(" -D: enable debug)\n");
printf(" -t: Declare a tool (ToolName-1.0.0.0-prod)\n"); printf(" -t: Declare a tool (ToolName-1.0.0.0-prod)\n");
printf(" -n: Set name (MyAppOrLibName defaults to out)\n"); printf(" -n: Set name (MyAppOrLibName defaults to out)\n");
printf(" -r: Set resource directory (RESDIR defaults to res)\n"); printf(" -r: Set resource directory (RESDIR defaults to res)\n");
@@ -46,7 +47,7 @@ int main(int argc, char** argv)
std::string icon=""; std::string icon="";
std::string comptime="none"; std::string comptime="none";
TVMVersion version; TVMVersion version;
bool debug=false;
@@ -56,6 +57,7 @@ int main(int argc, char** argv)
{ {
Help(argv[0]); Help(argv[0]);
} }
else if(strcmp(argv[i], "-o") == 0) else if(strcmp(argv[i], "-o") == 0)
{ {
i++; i++;
@@ -187,6 +189,10 @@ int main(int argc, char** argv)
} }
} }
} }
else if(strcmp(argv[i],"-D") == 0)
{
debug = true;
}
else { else {
source.push_back(argv[i]); source.push_back(argv[i]);
} }
@@ -202,7 +208,7 @@ int main(int argc, char** argv)
for(auto src : source) for(auto src : source)
{ {
std::ifstream strm(src,std::ios_base::in|std::ios_base::binary); std::ifstream strm(src,std::ios_base::in|std::ios_base::binary);
int res = Lex(argv[1],strm,tokens); int res = Lex(std::filesystem::absolute(src).string(),strm,tokens);
} }
@@ -248,7 +254,7 @@ int main(int argc, char** argv)
} }
Parser parser(tokens,gc,env); Parser parser(tokens,gc,env);
parser.debug = debug;
CodeGen gen; CodeGen gen;
gen.GenRoot(parser.ParseRoot()); gen.GenRoot(parser.ParseRoot());
gen.name = name; gen.name = name;

View File

@@ -49,7 +49,7 @@ int main(int argc, char** argv)
for(int arg=1;arg<argc;arg++) for(int arg=1;arg<argc;arg++)
args->Add(std::string(argv[arg])); args->Add(std::string(argv[arg]));
auto res = env->CallFunction(ls,"main",{args}); auto res = env->CallFunctionWithFatalError(ls,"main",{args});
int64_t iresult; int64_t iresult;
if(GetObject(res,iresult)) if(GetObject(res,iresult))
return (int)iresult; return (int)iresult;

View File

@@ -35,7 +35,7 @@ int main(int argc, char** argv)
args2->Add(item); args2->Add(item);
} }
auto res = env->CallFunction(ls, "WebAppMain", {args2}); auto res = env->CallFunctionWithFatalError(ls, "WebAppMain", {args2});
auto svr2 = Tesses::CrossLang::ToHttpServer(&gc,res); auto svr2 = Tesses::CrossLang::ToHttpServer(&gc,res);
if(svr2 == nullptr) return 1; if(svr2 == nullptr) return 1;
Tesses::Framework::Http::HttpServer svr(port,svr2); Tesses::Framework::Http::HttpServer svr(port,svr2);
@@ -58,7 +58,7 @@ int main(int argc, char** argv)
for(int arg=1;arg<argc;arg++) for(int arg=1;arg<argc;arg++)
args->Add(std::string(argv[arg])); args->Add(std::string(argv[arg]));
auto res = env->CallFunction(ls,"main",{args}); auto res = env->CallFunctionWithFatalError(ls,"main",{args});
int64_t iresult; int64_t iresult;
if(GetObject(res,iresult)) if(GetObject(res,iresult))
return (int)iresult; return (int)iresult;

View File

@@ -138,6 +138,7 @@ namespace Tesses::CrossLang
std::vector<std::pair<std::string,TVMVersion>> tools; std::vector<std::pair<std::string,TVMVersion>> tools;
std::string info; std::string info;
std::string icon; std::string icon;
bool debug=false;
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs; std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
ls.GetGC()->BarrierBegin(); ls.GetGC()->BarrierBegin();
@@ -152,6 +153,7 @@ namespace Tesses::CrossLang
TObject _resourceFileSystem = dict->GetValue("ResourceFileSystem"); TObject _resourceFileSystem = dict->GetValue("ResourceFileSystem");
TObject _out = dict->GetValue("Output"); TObject _out = dict->GetValue("Output");
TObject _dbg = dict->GetValue("Debug");
TList* _toolList; TList* _toolList;
TList* _depList; TList* srcLst; TList* _depList; TList* srcLst;
TRootEnvironment* comptimeEnv=nullptr; TRootEnvironment* comptimeEnv=nullptr;
@@ -160,6 +162,7 @@ namespace Tesses::CrossLang
GetObject<std::string>(_icon,icon); GetObject<std::string>(_icon,icon);
GetObject(_resourceFileSystem, vfs); GetObject(_resourceFileSystem, vfs);
GetObjectHeap(_comptime,comptimeEnv); GetObjectHeap(_comptime,comptimeEnv);
GetObject(_dbg,debug);
std::string v2; std::string v2;
if(GetObject<std::string>(_version,v2)) if(GetObject<std::string>(_version,v2))
TVMVersion::TryParse(v2, version); TVMVersion::TryParse(v2, version);
@@ -258,6 +261,7 @@ namespace Tesses::CrossLang
} }
} }
Parser parser(tokens,ls.GetGC(),comptimeEnv); Parser parser(tokens,ls.GetGC(),comptimeEnv);
parser.debug = debug;
SyntaxNode n = parser.ParseRoot(); SyntaxNode n = parser.ParseRoot();
CodeGen gen; CodeGen gen;
gen.GenRoot(n); gen.GenRoot(n);
@@ -282,11 +286,43 @@ namespace Tesses::CrossLang
return Failure(ls, ex.what()); return Failure(ls, ex.what());
} }
} }
static TObject VM_GetStacktrace(GCList& ls, std::vector<TObject> args)
{
if(current_function != nullptr)
{
if(current_function->thread != nullptr)
{
TList* list = TList::Create(ls);
ls.GetGC()->BarrierBegin();
for(auto item : current_function->thread->call_stack_entries)
{
auto dict = TDictionary::Create(ls);
if(item->callable->closure->name)
dict->SetValue("Name", *item->callable->closure->name);
dict->SetValue("Closure", item->callable->closure);
dict->SetValue("FileName", item->callable->file->name + "-" + item->callable->file->version.ToString() + ".crvm");
dict->SetValue("IP",(int64_t)item->ip);
if(item->srcline >= 1)
{
dict->SetValue("SourceFile", item->srcfile);
dict->SetValue("SourceLine",item->srcline);
}
list->Add(dict);
}
ls.GetGC()->BarrierEnd();
return list;
}
}
return nullptr;
}
void TStd::RegisterVM(GC* gc,TRootEnvironment* env) void TStd::RegisterVM(GC* gc,TRootEnvironment* env)
{ {
env->permissions.canRegisterVM=true; env->permissions.canRegisterVM=true;
GCList ls(gc); GCList ls(gc);
TDictionary* dict = TDictionary::Create(ls); TDictionary* dict = TDictionary::Create(ls);
dict->DeclareFunction(gc, "GetStacktrace","Get the current stack trace", {}, VM_GetStacktrace);
dict->DeclareFunction(gc, "getRootEnvironmentAsDictionary","Get root environment as a dictionary",{},[env](GCList& ls, std::vector<TObject> args)-> TObject{ dict->DeclareFunction(gc, "getRootEnvironmentAsDictionary","Get root environment as a dictionary",{},[env](GCList& ls, std::vector<TObject> args)-> TObject{
return env->GetDictionary(); return env->GetDictionary();
}); });

View File

@@ -154,6 +154,7 @@ namespace Tesses::CrossLang
else else
{ {
auto clos = TClosure::Create(ls,obj->env,file,entry.chunkId); auto clos = TClosure::Create(ls,obj->env,file,entry.chunkId);
clos->closure->name = obj->name + "::" + ent.name;
clos->className = ownerNow; clos->className = ownerNow;
clos->documentation = entry.documentation; clos->documentation = entry.documentation;
ent.value = clos; ent.value = clos;
@@ -163,6 +164,7 @@ namespace Tesses::CrossLang
if(entry.isAbstract) ent.value = Undefined(); if(entry.isAbstract) ent.value = Undefined();
else { else {
auto clos = TClosure::Create(ls,obj->env,file,entry.chunkId); auto clos = TClosure::Create(ls,obj->env,file,entry.chunkId);
clos->closure->name = obj->name + "::" + ent.name;
clos->className = ownerNow; clos->className = ownerNow;
ent.value = clos->Call(*ls,{}); ent.value = clos->Call(*ls,{});
} }

View File

@@ -126,6 +126,33 @@ namespace Tesses::CrossLang {
} }
return Undefined(); return Undefined();
} }
TObject TDictionary::CallMethodWithFatalError(GCList& ls, std::string key, std::vector<TObject> args)
{
ls.GetGC()->BarrierBegin();
auto res = this->GetValue(key);
ls.GetGC()->BarrierEnd();
TCallable* callable;
if(GetObjectHeap(res,callable))
{
auto closure = dynamic_cast<TClosure*>(callable);
if(closure != nullptr && !closure->closure->args.empty() && closure->closure->args.front() == "this")
{
std::vector<TObject> args2;
args2.push_back(this);
args2.insert(args2.end(), args.begin(),args.end());
return closure->CallWithFatalError(ls,args2);
}
else
{
return callable->CallWithFatalError(ls,args);
}
}
return Undefined();
}
void TDictionary::DeclareFunction(GC* gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb) void TDictionary::DeclareFunction(GC* gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb)
{ {
gc->BarrierBegin(); gc->BarrierBegin();
@@ -204,4 +231,5 @@ namespace Tesses::CrossLang {
_gc->Watch(dict); _gc->Watch(dict);
return dict; return dict;
} }
}; };

View File

@@ -118,6 +118,7 @@ namespace Tesses::CrossLang {
throw VMException("Lex error at line: " + std::to_string(res)); throw VMException("Lex error at line: " + std::to_string(res));
} }
Parser parser(tokens); Parser parser(tokens);
SyntaxNode n = parser.ParseRoot(); SyntaxNode n = parser.ParseRoot();
CodeGen gen; CodeGen gen;
gen.GenRoot(n); gen.GenRoot(n);
@@ -230,6 +231,9 @@ namespace Tesses::CrossLang {
std::vector<std::string> method=file->classes[i].name; std::vector<std::string> method=file->classes[i].name;
method.push_back(meth.name); method.push_back(meth.name);
auto clo = TClosure::Create(ls,this,file,meth.chunkId); auto clo = TClosure::Create(ls,this,file,meth.chunkId);
clo->closure->name = JoinPeriod(method);
clo->documentation = meth.documentation; clo->documentation = meth.documentation;
this->DeclareVariable(gc, method, clo); this->DeclareVariable(gc, method, clo);
} }
@@ -239,7 +243,6 @@ namespace Tesses::CrossLang {
for(auto fn : file->functions) for(auto fn : file->functions)
{ {
std::string name;
if(fn.first.size() < 2) throw VMException("No function name."); if(fn.first.size() < 2) throw VMException("No function name.");
@@ -248,6 +251,7 @@ namespace Tesses::CrossLang {
if(fn.second >= file->chunks.size()) throw VMException("ChunkId out of bounds."); if(fn.second >= file->chunks.size()) throw VMException("ChunkId out of bounds.");
TFileChunk* chunk = file->chunks[fn.second]; TFileChunk* chunk = file->chunks[fn.second];
chunk->name = JoinPeriod(items);
GCList ls(gc); GCList ls(gc);
TClosure* closure=TClosure::Create(ls,this,file,fn.second); TClosure* closure=TClosure::Create(ls,this,file,fn.second);
closure->documentation = fn.first[0]; closure->documentation = fn.first[0];

View File

@@ -163,6 +163,19 @@ namespace Tesses::CrossLang {
} }
return Undefined(); return Undefined();
} }
TObject TEnvironment::CallFunctionWithFatalError(GCList& ls, std::string key, std::vector<TObject> args)
{
ls.GetGC()->BarrierBegin();
auto res = this->GetVariable(key);
ls.GetGC()->BarrierEnd();
TCallable* callable;
if(GetObjectHeap(res,callable))
{
return callable->CallWithFatalError(ls,args);
}
return Undefined();
}
TSubEnvironment* TEnvironment::GetSubEnvironment(GCList* gc) TSubEnvironment* TEnvironment::GetSubEnvironment(GCList* gc)
{ {
auto dict=TDictionary::Create(gc); auto dict=TDictionary::Create(gc);

107
src/vm/exception.cpp Normal file
View File

@@ -0,0 +1,107 @@
#include "CrossLang.hpp"
namespace Tesses::CrossLang {
TObject TCallable::CallWithFatalError(GCList& ls, std::vector<TObject> args)
{
try {
return Call(ls,args);
}
catch(VMByteCodeException& ex)
{
ThrowFatalError(ex);
}
catch(VMException& ex)
{
ThrowFatalError(ex);
}
catch(SyntaxException& ex)
{
ThrowFatalError(ex);
}
catch(std::runtime_error& ex)
{
ThrowFatalError(ex);
}
catch(std::exception& ex)
{
ThrowFatalError(ex);
}
return (int64_t)1;
}
void ThrowFatalError(std::exception& ex)
{
using namespace Tesses::Framework::TextStreams;
std::exception* ex2 = &ex;
auto clexcept = dynamic_cast<VMByteCodeException*>(ex2);
auto clrtexcept = dynamic_cast<VMException*>(ex2);
auto compiler = dynamic_cast<SyntaxException*>(ex2);
Tesses::Framework::TextStreams::ConsoleWriter error(true);
if(clexcept != nullptr)
{
error.WriteLine("CrossLang has encountered a fatal exception");
error.WriteLine();
error.WriteLine(ToString(clexcept->GetGCList()->GetGC(),clexcept->exception));
error.WriteLine();
error.WriteLine("STACKTRACE:");
for(auto ittr = clexcept->stack_trace.crbegin(); ittr != clexcept->stack_trace.crend(); ittr++)
{
auto item = *ittr;
std::string text = "\t";
text += item->callable->closure->name.value_or((std::string)"<Closure>");
text += "(";
bool first=true;
for(auto& arg : item->callable->closure->args)
{
if(!first) text += ", ";
text += arg;
first=false;
}
text += ")";
if(item->srcline >= 1)
{
text += " at ";
text += item->srcfile;
text += ":";
text += std::to_string(item->srcline);
}
error.WriteLine(text);
}
exit(1);
}
if(clrtexcept != nullptr)
{
error.WriteLine("CrossLang has encountered a fatal runtime exception");
error.WriteLine();
error.WriteLine(clrtexcept->what());
exit(1);
}
if(compiler != nullptr)
{
error.WriteLine("CrossLang has encountered a compiler error");
error.WriteLine();
error.WriteLine(compiler->Message());
error.WriteLine();
auto li = compiler->LineInfo();
error.Write("in file: ");
error.Write(li.filename);
error.Write(":");
error.Write((int64_t)li.line);
error.Write(":");
error.Write((int64_t)li.column);
error.Write(":");
error.WriteLine((int64_t)li.offset);
exit(1);
}
error.WriteLine("CrossLang has encountered a fatal C++ exception");
error.WriteLine();
error.Write("what(): ");
error.WriteLine(ex2->what());
exit(1);
}
}

View File

@@ -4237,7 +4237,7 @@ namespace Tesses::CrossLang {
if(args.size() > 0) if(args.size() > 0)
{ {
try { try {
throw VMByteCodeException(gc,args[0]); throw VMByteCodeException(gc,args[0],cse.back());
} catch(...) { } catch(...) {
ttask->SetFailed(std::current_exception()); ttask->SetFailed(std::current_exception());
} }
@@ -7012,7 +7012,7 @@ namespace Tesses::CrossLang {
{ {
auto env = cse.back()->env; auto env = cse.back()->env;
if(!env->GetRootEnvironment()->HandleException(gc,env, _res2)) if(!env->GetRootEnvironment()->HandleException(gc,env, _res2))
throw VMByteCodeException(gc,_res2); throw VMByteCodeException(gc,_res2,cse.back());
} }
return false; return false;
} }
@@ -7167,6 +7167,24 @@ namespace Tesses::CrossLang {
auto stk = cse.back(); auto stk = cse.back();
stk->Push(gc,Undefined()); stk->Push(gc,Undefined());
return false;
}
bool InterperterThread::LineInfo(GC* gc)
{
GCList ls(gc);
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
auto stk = cse.back();
auto file = stk->Pop(ls);
auto line = stk->Pop(ls);
//Set the fields in this cse
GetObject(file,stk->srcfile);
GetObject(line,stk->srcline);
//TODO: implement lines (this will make the language work until we get it rigged up)
return false; return false;
} }
bool InterperterThread::PushFalse(GC* gc) bool InterperterThread::PushFalse(GC* gc)
@@ -7867,6 +7885,9 @@ namespace Tesses::CrossLang {
{ {
CallStackEntry* cse = new CallStackEntry(); CallStackEntry* cse = new CallStackEntry();
cse->mustReturn=false; cse->mustReturn=false;
cse->srcline = -1;
cse->srcfile = "";
cse->thread=nullptr;
GC* _gc = ls.GetGC(); GC* _gc = ls.GetGC();
ls.Add(cse); ls.Add(cse);
_gc->Watch(cse); _gc->Watch(cse);
@@ -7877,6 +7898,9 @@ namespace Tesses::CrossLang {
{ {
CallStackEntry* cse = new CallStackEntry(); CallStackEntry* cse = new CallStackEntry();
cse->mustReturn=false; cse->mustReturn=false;
cse->srcline = -1;
cse->srcfile = "";
cse->thread=nullptr;
GC* _gc = ls->GetGC(); GC* _gc = ls->GetGC();
ls->Add(cse); ls->Add(cse);
_gc->Watch(cse); _gc->Watch(cse);
@@ -7886,6 +7910,7 @@ namespace Tesses::CrossLang {
{ {
ls.GetGC()->BarrierBegin(); ls.GetGC()->BarrierBegin();
CallStackEntry* cse = CallStackEntry::Create(ls); CallStackEntry* cse = CallStackEntry::Create(ls);
cse->thread = this;
cse->callable = closure; cse->callable = closure;
cse->env = closure->chunkId == 0 ? closure->env : closure->ownScope ? closure->env->GetSubEnvironment(ls) : closure->env; cse->env = closure->chunkId == 0 ? closure->env : closure->ownScope ? closure->env->GetSubEnvironment(ls) : closure->env;
cse->ip = 0; cse->ip = 0;

View File

@@ -64,7 +64,7 @@ static opcode opcodes[256]={
&InterperterThread::JumpIfContinue, &InterperterThread::JumpIfContinue,
&InterperterThread::JumpIfDefined, &InterperterThread::JumpIfDefined,
&InterperterThread::DeclareConstVariable, &InterperterThread::DeclareConstVariable,
&InterperterThread::Illegal, &InterperterThread::LineInfo,
&InterperterThread::Illegal, &InterperterThread::Illegal,
&InterperterThread::Illegal, &InterperterThread::Illegal,
&InterperterThread::Illegal, &InterperterThread::Illegal,