mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
some reconstruct
This commit is contained in:
parent
f8df138b94
commit
01bbda85ec
@ -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"]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
68
src/error.h
68
src/error.h
@ -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, "") {}
|
||||||
};
|
};
|
14
src/main.cpp
14
src/main.cpp
@ -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
|
||||||
|
@ -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()) {}
|
||||||
|
2
src/vm.h
2
src/vm.h
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user