Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Design] command like function call #283

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 64 additions & 30 deletions src/core/compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ typedef enum {
TK_LPARAN, // (
TK_RPARAN, // )
TK_LBRACKET, // [
TK_LBRACKETEX, // ' ' + [
TK_RBRACKET, // ]
TK_LBRACE, // {
TK_RBRACE, // }
Expand Down Expand Up @@ -492,6 +493,9 @@ struct Compiler {
// meaningless).
bool is_last_call;

// Avoid _compileOptionalParanCall parsing error in interpolation.
bool in_interpolation;

// Since the compiler manually call some builtin functions we need to cache
// the index of the functions in order to prevent search for them each time.
int bifn_list_join;
Expand Down Expand Up @@ -572,6 +576,7 @@ static void compilerInit(Compiler* compiler, PKVM* vm, const char* source,
compiler->can_define = true;
compiler->new_local = false;
compiler->is_last_call = false;
compiler->in_interpolation = false;

const char* source_path = "@??";
if (module->path != NULL) {
Expand Down Expand Up @@ -814,6 +819,12 @@ static char peekNextChar(Parser* parser) {
return *(parser->current_char + 1);
}

// Returns the prev char of the compiler on.
static char peekPrevChar(Parser* parser) {
if (parser->current_char - 2 < parser->source) return '\0';
return *(parser->current_char - 2);
}

// Advance the compiler by 1 char.
static char eatChar(Parser* parser) {
char c = peekChar(parser);
Expand Down Expand Up @@ -1092,7 +1103,15 @@ static void lexToken(Compiler* compiler) {
case '#': skipLineComment(parser); break;
case '(': setNextToken(parser, TK_LPARAN); return;
case ')': setNextToken(parser, TK_RPARAN); return;
case '[': setNextToken(parser, TK_LBRACKET); return;
case '[': {
char c = peekPrevChar(parser);
if (c == '\t' || c == ' ') {
setNextToken(parser, TK_LBRACKETEX); return;
}
else {
setNextToken(parser, TK_LBRACKET); return;
}
}
case ']': setNextToken(parser, TK_RBRACKET); return;
case '%':
setNextTwoCharToken(parser, '=', TK_PERCENT, TK_MODEQ);
Expand Down Expand Up @@ -1601,6 +1620,7 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence
/* TK_LPARAN */ { exprGrouping, exprCall, PREC_CALL },
/* TK_RPARAN */ NO_RULE,
/* TK_LBRACKET */ { exprList, exprSubscript, PREC_SUBSCRIPT },
/* TK_LBRACKETEX */ { exprList, exprSubscript, PREC_SUBSCRIPT },
/* TK_RBRACKET */ NO_RULE,
/* TK_LBRACE */ { exprMap, NULL, NO_INFIX },
/* TK_RBRACE */ NO_RULE,
Expand Down Expand Up @@ -1769,26 +1789,23 @@ static void _compileCall(Compiler* compiler, Opcode call_type, int method) {
(call_type == OP_SUPER_CALL), OOPS);
// Compile parameters.
int argc = 0;
bool noparan = compiler->parser.optional_call_paran;
compiler->parser.optional_call_paran = false;

if (compiler->parser.optional_call_paran) {
compiler->parser.optional_call_paran = false;
compileExpression(compiler);
argc = 1;
if (noparan || !match(compiler, TK_RPARAN)) {
do {
skipNewLines(compiler);
compileExpression(compiler);
if (!noparan) skipNewLines(compiler);
argc++;
} while (match(compiler, TK_COMMA));

} else {
if (!match(compiler, TK_RPARAN)) {
do {
skipNewLines(compiler);
compileExpression(compiler);
skipNewLines(compiler);
argc++;
} while (match(compiler, TK_COMMA));
if (!noparan) {
consume(compiler, TK_RPARAN, "Expected ')' after parameter list.");
}
}

emitOpcode(compiler, call_type);

emitByte(compiler, argc);

if ((call_type == OP_METHOD_CALL) || (call_type == OP_SUPER_CALL)) {
Expand All @@ -1805,24 +1822,38 @@ static void _compileCall(Compiler* compiler, Opcode call_type, int method) {
// literals that can be passed for no pranthese call (a syntax sugar) and
// emit the call. Return true if such call matched. If [method] >= 0 it'll
// compile a method call otherwise a regular call.

// Add more syntax sugar: name, string, number, primitive, map, list, etc.
// If there is some space before '[', parse it to a list instead of subscript.
static bool _compileOptionalParanCall(Compiler* compiler, int method) {
static _TokenType tk[] = {
TK_FN,
//TK_STRING,
//TK_STRING_INTERP,
TK_ERROR, // Sentinel to stop the iteration.
};

for (int i = 0; tk[i] != TK_ERROR; i++) {
if (peek(compiler) == tk[i]) {
compiler->parser.optional_call_paran = true;
Opcode call_type = ((method >= 0) ? OP_METHOD_CALL : OP_CALL);
_compileCall(compiler, call_type, method);
return true;
}
_TokenType tk = peek(compiler);
switch (tk) {
case TK_LBRACKETEX:
case TK_LBRACE:
case TK_FN:
case TK_NULL:
case TK_NOT:
case TK_TRUE:
case TK_FALSE:
case TK_SELF:
case TK_SUPER:
case TK_NAME:
case TK_NUMBER:
case TK_STRING:
case TK_STRING_INTERP:
break;
default:
return false;
}

return false;
// In interpolation we just return.
if (compiler->in_interpolation &&
(tk == TK_STRING || tk == TK_STRING_INTERP)) return false;

compiler->parser.optional_call_paran = true;
Opcode call_type = ((method >= 0) ? OP_METHOD_CALL : OP_CALL);
_compileCall(compiler, call_type, method);
return true;
}

static void exprLiteral(Compiler* compiler) {
Expand All @@ -1848,6 +1879,8 @@ static void exprInterpolation(Compiler* compiler) {
int size_index = emitShort(compiler, 0);

int size = 0;
bool in_interpolation = compiler->in_interpolation;
compiler->in_interpolation = true;
do {
// Push the string on the stack and append it to the list.
exprLiteral(compiler);
Expand All @@ -1861,6 +1894,7 @@ static void exprInterpolation(Compiler* compiler) {
size++;
skipNewLines(compiler);
} while (match(compiler, TK_STRING_INTERP));
compiler->in_interpolation = in_interpolation;

// The last string is not TK_STRING_INTERP but it would be
// TK_STRING. Apped it.
Expand Down Expand Up @@ -2707,7 +2741,7 @@ static bool matchOperatorMethod(Compiler* compiler,
"Expected keyword self for unary operator definition.");
return false;
}
if (match(compiler, TK_LBRACKET)) {
if (match(compiler, TK_LBRACKET) || match(compiler, TK_LBRACKETEX)) {
if (match(compiler, TK_RBRACKET)) {
if (match(compiler, TK_EQ)) _RET("[]=", 2);
_RET("[]", 1);
Expand Down