|
|
@@ -3255,7 +3255,7 @@ struct Parser {
|
|
|
int count = 0;
|
|
|
while (true) {
|
|
|
switch (peekChar()) {
|
|
|
- case ' ': count++; break;
|
|
|
+ case ' ' : count+=1; break;
|
|
|
case '\t': count+=4; break;
|
|
|
default: return count;
|
|
|
}
|
|
|
@@ -3266,6 +3266,8 @@ struct Parser {
|
|
|
bool eatIndentation(){
|
|
|
if(brackets_level_0 > 0 || brackets_level_1 > 0 || brackets_level_2 > 0) return true;
|
|
|
int spaces = eatSpaces();
|
|
|
+ if(peekChar() == '#') skipLineComment();
|
|
|
+ if(peekChar() == '\0' || peekChar() == '\n') return true;
|
|
|
// https://docs.python.org/3/reference/lexical_analysis.html#indentation
|
|
|
if(spaces > indents.top()){
|
|
|
indents.push(spaces);
|
|
|
@@ -5236,7 +5238,7 @@ public:
|
|
|
parser->previous = parser->current;
|
|
|
parser->current = parser->nextToken();
|
|
|
|
|
|
- //_Str _info = parser->current.info(); printf("%s\n", (const char*)_info);
|
|
|
+ //_Str _info = parser->current.info(); std::cout << _info << '[' << parser->current_line << ']' << std::endl;
|
|
|
|
|
|
while (parser->peekChar() != '\0') {
|
|
|
parser->token_start = parser->current_char;
|
|
|
@@ -5311,7 +5313,7 @@ public:
|
|
|
case '\r': break; // just ignore '\r'
|
|
|
case ' ': case '\t': parser->eatSpaces(); break;
|
|
|
case '\n': {
|
|
|
- parser->setNextToken(TK("@eol")); while(parser->matchChar('\n'));
|
|
|
+ parser->setNextToken(TK("@eol"));
|
|
|
if(!parser->eatIndentation()) indentationError("unindent does not match any outer indentation level");
|
|
|
return;
|
|
|
}
|
|
|
@@ -5324,7 +5326,7 @@ public:
|
|
|
eatNumber();
|
|
|
} else if (parser->isNameStart(c)) {
|
|
|
int ret = parser->eatName();
|
|
|
- if(ret!=0) syntaxError("identifier is illegal, err " + std::to_string(ret));
|
|
|
+ if(ret!=0) syntaxError("@id is illegal, err " + std::to_string(ret));
|
|
|
} else {
|
|
|
syntaxError("unknown character: " + std::string(1, c));
|
|
|
}
|
|
|
@@ -5427,7 +5429,7 @@ public:
|
|
|
_Func func = pkpy::make_shared<Function>();
|
|
|
func->name = "<lambda>";
|
|
|
if(!match(TK(":"))){
|
|
|
- __compileFunctionArgs(func);
|
|
|
+ __compileFunctionArgs(func, false);
|
|
|
consume(TK(":"));
|
|
|
}
|
|
|
func->code = pkpy::make_shared<CodeObject>(parser->src, func->name);
|
|
|
@@ -5962,7 +5964,7 @@ __LISTCOMP:
|
|
|
emitCode(OP_BUILD_CLASS, clsNameIdx);
|
|
|
}
|
|
|
|
|
|
- void __compileFunctionArgs(_Func func){
|
|
|
+ void __compileFunctionArgs(_Func func, bool enableTypeHints){
|
|
|
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
|
|
|
do {
|
|
|
if(state == 3) syntaxError("**kwargs should be the last argument");
|
|
|
@@ -5979,6 +5981,9 @@ __LISTCOMP:
|
|
|
const _Str& name = parser->previous.str();
|
|
|
if(func->hasName(name)) syntaxError("duplicate argument name");
|
|
|
|
|
|
+ // eat type hints
|
|
|
+ if(enableTypeHints && match(TK(":"))) consume(TK("@id"));
|
|
|
+
|
|
|
if(state == 0 && peek() == TK("=")) state = 2;
|
|
|
|
|
|
switch (state)
|
|
|
@@ -6009,10 +6014,13 @@ __LISTCOMP:
|
|
|
func->name = parser->previous.str();
|
|
|
|
|
|
if (match(TK("(")) && !match(TK(")"))) {
|
|
|
- __compileFunctionArgs(func);
|
|
|
+ __compileFunctionArgs(func, true);
|
|
|
consume(TK(")"));
|
|
|
}
|
|
|
|
|
|
+ // eat type hints
|
|
|
+ if(match(TK("->"))) consume(TK("@id"));
|
|
|
+
|
|
|
func->code = pkpy::make_shared<CodeObject>(parser->src, func->name);
|
|
|
this->codes.push(func->code);
|
|
|
compileBlockBody();
|
|
|
@@ -6082,7 +6090,7 @@ __LISTCOMP:
|
|
|
|
|
|
/***** Error Reporter *****/
|
|
|
_Str getLineSnapshot(){
|
|
|
- int lineno = parser->current_line;
|
|
|
+ int lineno = parser->current.line;
|
|
|
if(parser->peekChar() == '\n') lineno--;
|
|
|
return parser->src->snapshot(lineno);
|
|
|
}
|