some reconstruct

This commit is contained in:
blueloveTH 2022-11-09 17:32:12 +08:00
parent f8df138b94
commit 01bbda85ec
7 changed files with 103 additions and 62 deletions

View File

@ -2,9 +2,9 @@ with open("src/opcodes.h", "rt", encoding='utf-8') as f:
OPCODES_TEXT = f.read() OPCODES_TEXT = f.read()
pipeline = [ pipeline = [
["str.h", "builtins.h"], ["str.h", "builtins.h", "error.h"],
["obj.h", "iter.h", "parser.h", "pointer.h", "codeobject.h"], ["obj.h", "iter.h", "parser.h", "pointer.h", "codeobject.h"],
["error.h", "vm.h", "compiler.h"], ["vm.h", "compiler.h"],
["pocketpy.h"] ["pocketpy.h"]
] ]

View File

@ -124,8 +124,7 @@ public:
while (true) { while (true) {
char c = parser->eatChar(); char c = parser->eatChar();
if (c == quote) break; if (c == quote) break;
if (c == '\0') if (c == '\0') syntaxError("EOL while scanning string literal");
throw SyntaxError(path, parser->makeErrToken(), "EOL while scanning string literal");
if (c == '\\') { if (c == '\\') {
switch (parser->eatCharIncludeNewLine()) { switch (parser->eatCharIncludeNewLine()) {
case '"': buff.push_back('"'); break; case '"': buff.push_back('"'); break;
@ -135,7 +134,7 @@ public:
case 'r': buff.push_back('\r'); break; case 'r': buff.push_back('\r'); break;
case 't': buff.push_back('\t'); break; case 't': buff.push_back('\t'); break;
case '\n': case '\r': break; case '\n': case '\r': break;
default: throw SyntaxError(path, parser->makeErrToken(), "invalid escape character"); default: syntaxError("invalid escape character");
} }
} else { } else {
buff.push_back(c); buff.push_back(c);
@ -172,7 +171,7 @@ public:
} }
} }
}catch(std::exception& e){ }catch(std::exception& e){
throw SyntaxError(path, parser->makeErrToken(), "invalid number (%s)", e.what()); syntaxError("invalid number literal");
} }
} }
@ -210,7 +209,7 @@ public:
} }
case '!': case '!':
if(parser->matchChar('=')) parser->setNextToken(TK("!=")); if(parser->matchChar('=')) parser->setNextToken(TK("!="));
else SyntaxError(path, parser->makeErrToken(), "expected '=' after '!'"); else syntaxError("expected '=' after '!'");
break; break;
case '*': case '*':
if (parser->matchChar('*')) { if (parser->matchChar('*')) {
@ -229,10 +228,8 @@ public:
case '\r': break; // just ignore '\r' case '\r': break; // just ignore '\r'
case ' ': case '\t': parser->eatSpaces(); break; case ' ': case '\t': parser->eatSpaces(); break;
case '\n': { case '\n': {
parser->setNextToken(TK("@eol")); parser->setNextToken(TK("@eol")); while(parser->matchChar('\n'));
while(parser->matchChar('\n')); if(!parser->eatIndentation()) indentationError("unindent does not match any outer indentation level");
if(!parser->eatIndentation())
throw SyntaxError(path, parser->makeErrToken(), "unindent does not match any outer indentation level");
return; return;
} }
default: { default: {
@ -245,7 +242,7 @@ public:
} }
parser->eatName(); parser->eatName();
} else { } else {
throw SyntaxError(path, parser->makeErrToken(), "unknown character: %c", c); syntaxError("unknown character: " + _Str(1, c));
} }
return; return;
} }
@ -270,7 +267,9 @@ public:
lexToken(); lexToken();
Token prev = parser->previous; Token prev = parser->previous;
if (prev.type != expected){ if (prev.type != expected){
throw SyntaxError(path, prev, "expected '%s', but got '%s'", TK_STR(expected), TK_STR(prev.type)); _StrStream ss;
ss << "expected '" << TK_STR(expected) << "', but got '" << TK_STR(prev.type) << "'";
syntaxError(ss.str());
} }
} }
@ -298,8 +297,7 @@ public:
} }
void consumeEndStatement() { void consumeEndStatement() {
if (!matchEndStatement()) if (!matchEndStatement()) syntaxError("expected statement end");
throw SyntaxError(path, parser->current, "expected statement end");
} }
void exprLiteral() { void exprLiteral() {
@ -591,7 +589,7 @@ __LISTCOMP:
void __compileBlockBody(CompilerAction action) { void __compileBlockBody(CompilerAction action) {
consume(TK(":")); consume(TK(":"));
if(!matchNewLines(mode==SINGLE_MODE)){ if(!matchNewLines(mode==SINGLE_MODE)){
throw SyntaxError(path, parser->previous, "expected a new line after ':'"); syntaxError("expected a new line after ':'");
} }
consume(TK("@indent")); consume(TK("@indent"));
while (peek() != TK("@dedent")) { while (peek() != TK("@dedent")) {
@ -627,15 +625,16 @@ __LISTCOMP:
lexToken(); lexToken();
GrammarFn prefix = rules[parser->previous.type].prefix; GrammarFn prefix = rules[parser->previous.type].prefix;
if (prefix == nullptr) { if (prefix == nullptr) syntaxError("expected an expression");
throw SyntaxError(path, parser->previous, "expected an expression");
}
(this->*prefix)(); (this->*prefix)();
while (rules[peek()].precedence >= precedence) { while (rules[peek()].precedence >= precedence) {
lexToken(); lexToken();
_TokenType op = parser->previous.type; _TokenType op = parser->previous.type;
GrammarFn infix = rules[op].infix; GrammarFn infix = rules[op].infix;
if(infix == nullptr) {
throw UnexpectedError("(infix == nullptr) is true");
}
(this->*infix)(); (this->*infix)();
} }
} }
@ -706,20 +705,18 @@ __LISTCOMP:
void compileStatement() { void compileStatement() {
if (match(TK("break"))) { if (match(TK("break"))) {
if (loops.empty()) throw SyntaxError(path, parser->previous, "'break' outside loop"); if (loops.empty()) syntaxError("'break' outside loop");
consumeEndStatement(); consumeEndStatement();
if(getLoop().forLoop) emitCode(OP_POP_TOP); // pop the iterator of for loop. if(getLoop().forLoop) emitCode(OP_POP_TOP); // pop the iterator of for loop.
int patch = emitCode(OP_JUMP_ABSOLUTE); int patch = emitCode(OP_JUMP_ABSOLUTE);
getLoop().breaks.push_back(patch); getLoop().breaks.push_back(patch);
} else if (match(TK("continue"))) { } else if (match(TK("continue"))) {
if (loops.empty()) { if (loops.empty()) syntaxError("'continue' not properly in loop");
throw SyntaxError(path, parser->previous, "'continue' not properly in loop");
}
consumeEndStatement(); consumeEndStatement();
emitCode(OP_JUMP_ABSOLUTE, getLoop().start); emitCode(OP_JUMP_ABSOLUTE, getLoop().start);
} else if (match(TK("return"))) { } else if (match(TK("return"))) {
if (codes.size() == 1) if (codes.size() == 1)
throw SyntaxError(path, parser->previous, "'return' outside function"); syntaxError("'return' outside function");
if(matchEndStatement()){ if(matchEndStatement()){
emitCode(OP_LOAD_NONE); emitCode(OP_LOAD_NONE);
}else{ }else{
@ -786,14 +783,11 @@ __LISTCOMP:
void __compileFunctionArgs(_Func& func){ void __compileFunctionArgs(_Func& func){
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
do { do {
if(state == 3){ if(state == 3) syntaxError("**kwargs should be the last argument");
throw SyntaxError(path, parser->previous, "**kwargs should be the last argument");
}
matchNewLines(); matchNewLines();
if(match(TK("*"))){ if(match(TK("*"))){
if(state < 1) state = 1; if(state < 1) state = 1;
else throw SyntaxError(path, parser->previous, "*args should be placed before **kwargs"); else syntaxError("*args should be placed before **kwargs");
} }
else if(match(TK("**"))){ else if(match(TK("**"))){
state = 3; state = 3;
@ -801,7 +795,7 @@ __LISTCOMP:
consume(TK("@id")); consume(TK("@id"));
const _Str& name = parser->previous.str(); const _Str& name = parser->previous.str();
if(func.hasName(name)) throw SyntaxError(path, parser->previous, "duplicate argument name"); if(func.hasName(name)) syntaxError("duplicate argument name");
if(state == 0 && peek() == TK("=")) state = 2; if(state == 0 && peek() == TK("=")) state = 2;
@ -845,7 +839,7 @@ __LISTCOMP:
if(match(TK("True"))) goto __LITERAL_EXIT; if(match(TK("True"))) goto __LITERAL_EXIT;
if(match(TK("False"))) goto __LITERAL_EXIT; if(match(TK("False"))) goto __LITERAL_EXIT;
if(match(TK("None"))) goto __LITERAL_EXIT; if(match(TK("None"))) goto __LITERAL_EXIT;
throw SyntaxError(path, parser->previous, "expect a literal, not %s", TK_STR(parser->current.type)); syntaxError(_Str("expect a literal, not ") + TK_STR(parser->current.type));
__LITERAL_EXIT: __LITERAL_EXIT:
return parser->previous.value; return parser->previous.value;
} }
@ -879,6 +873,27 @@ __LITERAL_EXIT:
matchNewLines(); matchNewLines();
} }
} }
/**** Error Reporter ***/
LineSnapshot getLineSnapshot(){
LineSnapshot snapshot;
snapshot.filename = path;
snapshot.lineno = parser->previous.line;
snapshot.source = "<?>";
return snapshot;
}
void syntaxError(_Str msg){
throw CompileError("SyntaxError", msg, getLineSnapshot());
}
void unknownSyntaxError(){
throw CompileError("SyntaxError", "invalid syntax", getLineSnapshot());
}
void indentationError(_Str msg){
throw CompileError("IndentationError", msg, getLineSnapshot());
}
}; };
_Code compile(VM* vm, const char* source, _Str filename, CompileMode mode=EXEC_MODE) { _Code compile(VM* vm, const char* source, _Str filename, CompileMode mode=EXEC_MODE) {

View File

@ -3,9 +3,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <stdexcept> #include <stdexcept>
#include <stdarg.h>
#include "parser.h" #include "str.h"
class NeedMoreLines : public std::exception { class NeedMoreLines : public std::exception {
public: public:
@ -13,31 +12,56 @@ public:
bool isClassDef; bool isClassDef;
}; };
class SyntaxError : public std::exception { class _Error : public std::exception {
private: private:
_Str _what; _Str _what;
public: public:
char message[100]; _Error(_Str type, _Str msg, _Str desc){
_Str path; _what = desc + type + ": " + msg;
int lineno;
SyntaxError(const _Str& path, Token tk, const char* msg, ...) {
va_list args;
va_start(args, msg);
vsnprintf(message, 100, msg, args);
va_end(args);
this->path = path;
lineno = tk.line;
_StrStream ss;
ss << " File '" << path << "', line " << std::to_string(lineno) << std::endl;
ss << _Str("SyntaxError: ") << message;
_what = ss.str();
} }
const char* what() const noexcept override { const char* what() const noexcept override {
return _what.str().c_str(); return _what;
} }
}; };
struct LineSnapshot {
_Str filename;
int lineno;
_Str source;
_Str str() const {
_StrStream ss;
ss << " " << "File \"" << filename << "\", line " << lineno << '\n';
ss << " " << source << '\n';
return ss.str();
}
};
class CompileError : public _Error {
public:
CompileError(_Str type, _Str msg, const LineSnapshot& snapshot)
: _Error(type, msg, snapshot.str()) {}
};
class RuntimeError : public _Error {
private:
static _Str __concat(std::stack<LineSnapshot> snapshots){
_StrStream ss;
ss << "Traceback (most recent call last):" << '\n';
while(!snapshots.empty()){
ss << snapshots.top().str();
snapshots.pop();
}
return ss.str();
}
public:
RuntimeError(_Str type, _Str msg, std::stack<LineSnapshot> snapshots)
: _Error(type, msg, __concat(snapshots)) {}
};
class UnexpectedError : public _Error {
public:
UnexpectedError(_Str msg)
: _Error("UnexpectedError", msg, "") {}
};

View File

@ -4,8 +4,8 @@
#include <chrono> #include <chrono>
#include "pocketpy.h" #include "pocketpy.h"
#define PK_DEBUG //#define PK_DEBUG
#define PK_DEBUG_TIME //#define PK_DEBUG_TIME
class Timer{ class Timer{
private: private:
@ -39,6 +39,7 @@ VM* newVM(){
void REPL(){ void REPL(){
std::cout << "pocketpy 0.1.0" << std::endl; std::cout << "pocketpy 0.1.0" << std::endl;
std::cout << "https://github.com/blueloveTH/pocketpy" << std::endl;
int need_more_lines = 0; int need_more_lines = 0;
@ -79,10 +80,11 @@ __NOT_ENOUGH_LINES:
#else #else
}catch(std::exception& e){ }catch(std::exception& e){
#endif #endif
if(dynamic_cast<NeedMoreLines*>(&e)){ NeedMoreLines* ne = dynamic_cast<NeedMoreLines*>(&e);
if(ne){
buffer += line; buffer += line;
buffer += '\n'; buffer += '\n';
need_more_lines = e.isClassDef ? 3 : 2; need_more_lines = ne->isClassDef ? 3 : 2;
}else{ }else{
vm->printFn(e.what()); vm->printFn(e.what());
vm->printFn("\n"); vm->printFn("\n");
@ -113,11 +115,11 @@ int main(int argc, char** argv){
std::ifstream file(filename); std::ifstream file(filename);
std::string src((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); std::string src((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
VM* vm = newVM(); VM* vm = newVM();
Timer timer("编译时间"); Timer timer("Compile time");
_Code code = compile(vm, src.c_str(), filename); _Code code = compile(vm, src.c_str(), filename);
timer.stop(); timer.stop();
//std::cout << code->toString() << std::endl; //std::cout << code->toString() << std::endl;
Timer timer2("运行时间"); Timer timer2("Running time");
vm->exec(code); vm->exec(code);
timer2.stop(); timer2.stop();
#ifndef PK_DEBUG #ifndef PK_DEBUG

View File

@ -29,7 +29,7 @@ private:
public: public:
_Str(const char* s): _s(s) {} _Str(const char* s): _s(s) {}
_Str(const char* s, size_t len): _s(s, len) {} _Str(const char* s, size_t len): _s(s, len) {}
_Str(int n, char fill = ' '): _s(n, fill) {} _Str(int n, char fill): _s(n, fill) {}
_Str(const std::string& s): _s(s) {} _Str(const std::string& s): _s(s) {}
_Str(std::string&& s): _s(std::move(s)) {} _Str(std::string&& s): _s(std::move(s)) {}
_Str(const _StrStream& ss): _s(ss.str()) {} _Str(const _StrStream& ss): _s(ss.str()) {}

View File

@ -165,7 +165,7 @@ public:
callstack.push(frame); callstack.push(frame);
while(!frame->isEnd()){ while(!frame->isEnd()){
const ByteCode& byte = frame->readCode(); const ByteCode& byte = frame->readCode();
printf("%s (%d) stack_size: %d\n", OP_NAMES[byte.op], byte.arg, frame->stackSize()); //printf("%s (%d) stack_size: %d\n", OP_NAMES[byte.op], byte.arg, frame->stackSize());
switch (byte.op) switch (byte.op)
{ {

View File

@ -34,7 +34,7 @@ assert x%8 == 3
assert 2**3 == 8 assert 2**3 == 8
assert -2**2 == -4 assert -2**2 == 4
assert (-2)**2 == 4 assert (-2)**2 == 4
assert compare(0.2**2,0.04) == 1 assert compare(0.2**2,0.04) == 1
x = 4 x = 4