map can have function members by placing function declaration between the curly braces

This commit is contained in:
Francesco Cozzuto
2023-01-13 03:02:28 +01:00
parent 189bfa030b
commit 920b88c006
8 changed files with 208 additions and 131 deletions
+13 -9
View File
@@ -352,13 +352,17 @@ fun parse(src: String) {
return newRequest(method, url, version, headers); return newRequest(method, url, version, headers);
} }
sample = cat( fun test() {
"GET /search?client=firefox-b-d&q=http+request+dataset HTTP/2\r\n", sample = cat(
"Host: www.google.com\r\n", "GET /search?client=firefox-b-d&q=http+request+dataset HTTP/2\r\n",
"user-agent: curl/7.84.0\r\n", "Host: www.google.com\r\n",
"accept: */*\r\n", "user-agent: curl/7.84.0\r\n",
"\r\n"); "accept: */*\r\n",
"\r\n");
request, error = parse(sample); request, error = parse(sample);
print("request=", request, "\n"); print("request=", request, "\n");
print("error=", error, "\n"); print("error=", error, "\n");
}
return {parse: parse, test: test};
+3 -1
View File
@@ -328,4 +328,6 @@ fun test() {
print("passed: ", passed, "\n"); print("passed: ", passed, "\n");
print("failed: ", failed, "\n"); print("failed: ", failed, "\n");
print(" total: ", total, "\n"); print(" total: ", total, "\n");
} }
return {parse: parse, test: test};
+33 -35
View File
@@ -8,38 +8,40 @@ Scanner = {
consumeSpaces: Callable consumeSpaces: Callable
}; };
fun hint(scan: Scanner, n: int = 1) {
k = scan.i + n;
if k < count(scan.src):
return scan.src[k];
return none;
}
fun current(scan: Scanner)
return hint(scan, 0);
fun consume(scan: Scanner, n: int = 1) {
assert(n > 0);
limit = count(scan.src);
scan.i = min(scan.i + n, limit);
return current(scan);
}
fun consumeSpaces(scan: Scanner) {
char = current(scan);
while isSpace(char):
char = consume(scan);
return char;
}
fun newScanner(src: String) { fun newScanner(src: String) {
fun isSpace(c: String)
return c == ' '
or c == '\t'
or c == '\n';
scan = { scan = {
src: src, src: src,
i: 0, i: 0,
hint: hint,
consume: consume, fun hint(scan: Scanner, n: int = 1) {
current: current, k = scan.i + n;
consumeSpaces: consumeSpaces if k < count(scan.src):
return scan.src[k];
return none;
}
fun current(scan: Scanner)
return scan->hint(0);
fun consume(scan: Scanner, n: int = 1) {
assert(n > 0);
limit = count(scan.src);
scan.i = min(scan.i + n, limit);
return scan->current();
}
fun consumeSpaces(scan: Scanner) {
char = scan->current();
while isSpace(char):
char = scan->consume();
return char;
}
}; };
assert(istypeof(Scanner, scan)); assert(istypeof(Scanner, scan));
return scan; return scan;
@@ -48,11 +50,7 @@ fun newScanner(src: String) {
fun isDigit(char: ?String) { fun isDigit(char: ?String) {
if char == none: if char == none:
return false; return false;
return string.ord(char) >= string.ord('0') ord = string.ord;
and string.ord(char) <= string.ord('9'); return ord(char) >= ord('0')
and ord(char) <= ord('9');
} }
fun isSpace(c: String)
return c == ' '
or c == '\t'
or c == '\n';
+15
View File
@@ -0,0 +1,15 @@
Person = {name: String, age: int, sayHello: Callable};
fun newPerson(name: String, age: int)
return {
name: name,
age: age,
fun sayHello(self)
print("Hello from ", self.name, "!\n");
};
me = newPerson("Francesco", 24);
me->sayHello();
assert(istypeof(Person, me));
+2 -1
View File
@@ -56,7 +56,7 @@ fun stringFromInteger(n: int) {
temp = abs(n); # Temporary copy of the input temp = abs(n); # Temporary copy of the input
text = ""; # The output we're about to compute text = ""; # The output we're about to compute
while power >= 1: { while power >= 1: {
# Pop the leftmost digit from [temp]. # Pop the leftmost digit from [temp].
digit = temp / power; # Get the leftmost digit digit = temp / power; # Get the leftmost digit
@@ -78,6 +78,7 @@ fun floatFromInteger(n: int)
return 1.0 * n; return 1.0 * n;
fun integerFromDigit(char: String) { fun integerFromDigit(char: String) {
ord = string.ord;
res = ord(char) - ord('0'); res = ord(char) - ord('0');
if res < 0 or res > 9: if res < 0 or res > 9:
error("String isn't a digit"); error("String isn't a digit");
+13 -6
View File
@@ -70,6 +70,7 @@ typedef enum {
EXPR_INT, EXPR_INT,
EXPR_MAP, EXPR_MAP,
EXPR_CALL, EXPR_CALL,
EXPR_FUNC,
EXPR_PAIR, EXPR_PAIR,
EXPR_LIST, EXPR_LIST,
EXPR_NONE, EXPR_NONE,
@@ -157,6 +158,14 @@ typedef struct {
Node *set; Node *set;
} IndexSelectionExprNode; } IndexSelectionExprNode;
#warning "temp"
typedef struct {
ExprNode base;
Node *argv;
int argc;
Node *body;
} FuncExprNode;
typedef struct { typedef struct {
Node base; Node base;
Node *condition; Node *condition;
@@ -187,12 +196,10 @@ typedef struct {
} ReturnNode; } ReturnNode;
typedef struct { typedef struct {
Node base; Node base;
char *name; StringExprNode *name;
Node *argv; FuncExprNode *expr;
int argc; } FuncDeclNode;
Node *body;
} FunctionNode;
typedef struct { typedef struct {
Node base; Node base;
+14 -6
View File
@@ -255,7 +255,7 @@ static void emitInstrForArgumentNode(CodegenContext *ctx, ArgumentNode *arg, int
emitInstr_POP1(ctx, arg->base.offset, arg->base.length); emitInstr_POP1(ctx, arg->base.offset, arg->base.length);
} }
static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func) static void emitInstrForFuncExprNode(CodegenContext *ctx, FuncExprNode *func)
{ {
Label *label_func = Label_New(ctx); Label *label_func = Label_New(ctx);
Label *label_jump = Label_New(ctx); Label *label_jump = Label_New(ctx);
@@ -266,11 +266,9 @@ static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func)
{ .type = OPTP_PROMISE, .as_promise = Label_ToPromise(label_func) }, { .type = OPTP_PROMISE, .as_promise = Label_ToPromise(label_func) },
{ .type = OPTP_INT, .as_int = func->argc }, { .type = OPTP_INT, .as_int = func->argc },
}; };
CodegenContext_EmitInstr(ctx, OPCODE_PUSHFUN, ops, 2, func->base.offset, func->base.length); CodegenContext_EmitInstr(ctx, OPCODE_PUSHFUN, ops, 2, func->base.base.offset, func->base.base.length);
} }
emitInstr_ASS(ctx, func->name, func->base.offset, func->base.length); // Assign variable emitInstr_JUMP(ctx, label_jump, func->base.base.offset, func->base.base.length); // Jump after the function code
emitInstr_POP1(ctx, func->base.offset, func->base.length); // Pop function object
emitInstr_JUMP(ctx, label_jump, func->base.offset, func->base.length); // Jump after the function code
Label_SetHere(label_func, ctx); // This is the function code index. Label_SetHere(label_func, ctx); // This is the function code index.
// Compile the function body. // Compile the function body.
@@ -302,6 +300,12 @@ static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func)
Label_Free(label_jump); Label_Free(label_jump);
} }
static void emitInstrForFuncDeclNode(CodegenContext *ctx, FuncDeclNode *func)
{
emitInstrForFuncExprNode(ctx, func->expr);
emitInstr_ASS(ctx, func->name->val, func->base.offset, func->base.length); // Assign variable
emitInstr_POP1(ctx, func->base.offset, func->base.length); // Pop function object
}
static void flattenTupleTree(CodegenContext *ctx, ExprNode *root, ExprNode *tuple[], int max, int *count) static void flattenTupleTree(CodegenContext *ctx, ExprNode *root, ExprNode *tuple[], int max, int *count)
{ {
@@ -569,6 +573,10 @@ static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr,
emitInstrForFuncCallNode(ctx, (CallExprNode*) expr, label_break, 1); emitInstrForFuncCallNode(ctx, (CallExprNode*) expr, label_break, 1);
return; return;
case EXPR_FUNC:
emitInstrForFuncExprNode(ctx, (FuncExprNode*) expr);
return;
case EXPR_SELECT: case EXPR_SELECT:
{ {
IndexSelectionExprNode *sel = (IndexSelectionExprNode*) expr; IndexSelectionExprNode *sel = (IndexSelectionExprNode*) expr;
@@ -723,7 +731,7 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
} }
case NODE_FUNC: case NODE_FUNC:
emitInstrForFuncNode(ctx, (FunctionNode*) node); emitInstrForFuncDeclNode(ctx, (FuncDeclNode*) node);
return; return;
default: default:
+115 -73
View File
@@ -136,7 +136,7 @@ static Node *parse_expression(Context *ctx, _Bool allow_toplev_tuples, _Bool all
static Node *parse_expression_statement(Context *ctx); static Node *parse_expression_statement(Context *ctx);
static Node *parse_ifelse_statement(Context *ctx); static Node *parse_ifelse_statement(Context *ctx);
static Node *parse_compound_statement(Context *ctx, TokenKind end); static Node *parse_compound_statement(Context *ctx, TokenKind end);
static Node *parse_function_definition(Context *ctx); static FuncDeclNode *parse_function_definition(Context *ctx);
static Node *parse_postfix_expression(Context *ctx); static Node *parse_postfix_expression(Context *ctx);
static Node *parse_prefix_expression(Context *ctx); static Node *parse_prefix_expression(Context *ctx);
static Node *parse_while_statement(Context *ctx); static Node *parse_while_statement(Context *ctx);
@@ -656,7 +656,7 @@ static Node *parse_statement(Context *ctx)
} }
case TKWFUN: case TKWFUN:
return parse_function_definition(ctx); return (Node*) parse_function_definition(ctx);
case TKWWHILE: case TKWWHILE:
return parse_while_statement(ctx); return parse_while_statement(ctx);
@@ -965,58 +965,69 @@ static Node *parse_map_primary_expression(Context *ctx)
while(1) while(1)
{ {
Node *key; Node *key;
_Bool key_is_a_single_ident; Node *item;
bool item_is_func_decl = false;
if (current(ctx) == TKWFUN)
{ {
_Bool key_starts_with_an_ident = current(ctx) == TIDENT; FuncDeclNode *func = parse_function_definition(ctx);
if (func == NULL) return NULL;
next(ctx); key = (Node*) func->name;
item = (Node*) func->expr;
key_is_a_single_ident = key_starts_with_an_ident && (current(ctx) == TDONE || current(ctx) == ':'); item_is_func_decl = true;
prev(ctx);
}
if(key_is_a_single_ident)
{
assert(current(ctx) == TIDENT);
key = makeStringExprNode(ctx, ctx->src + ctx->token->offset, ctx->token->length);
next(ctx);
} }
else else
{ {
key = parse_expression(ctx, 0, 1); _Bool key_is_a_single_ident;
{
_Bool key_starts_with_an_ident = current(ctx) == TIDENT;
next(ctx);
key_is_a_single_ident = key_starts_with_an_ident && (current(ctx) == TDONE || current(ctx) == ':');
prev(ctx);
}
if(key_is_a_single_ident)
{
assert(current(ctx) == TIDENT);
key = makeStringExprNode(ctx, ctx->src + ctx->token->offset, ctx->token->length);
next(ctx);
}
else
key = parse_expression(ctx, 0, 1);
if(key == NULL)
return NULL;
if(done(ctx))
{
Error_Report(ctx->error, 0,
"Source ended where a map key-value "
"separator ':' was expected");
return NULL;
}
if(current(ctx) != ':')
{
Error_Report(ctx->error, 0,
"Got token \"%.*s\" where a map key-value "
"separator ':' was expected",
ctx->token->length,
ctx->src + ctx->token->offset);
return NULL;
}
next(ctx);
// Parse.
item = parse_expression(ctx, 0, 1);
if(item == NULL) return NULL;
} }
if(key == NULL)
return NULL;
if(done(ctx))
{
Error_Report(ctx->error, 0,
"Source ended where a map key-value "
"separator ':' was expected");
return NULL;
}
if(current(ctx) != ':')
{
Error_Report(ctx->error, 0,
"Got token \"%.*s\" where a map key-value "
"separator ':' was expected",
ctx->token->length,
ctx->src + ctx->token->offset);
return NULL;
}
next(ctx);
// Parse.
Node *item = parse_expression(ctx, 0, 1);
if(item == NULL)
return NULL;
// Append. // Append.
if(tail) if(tail)
{ {
@@ -1038,19 +1049,20 @@ static Node *parse_map_primary_expression(Context *ctx)
if(current(ctx) == '}') if(current(ctx) == '}')
break; break;
if(current(ctx) != ',') if (!item_is_func_decl) {
{ if(current(ctx) != ',')
if(current(ctx) == TDONE) {
Error_Report(ctx->error, 0, "Source ended inside a map literal"); if(current(ctx) == TDONE)
else Error_Report(ctx->error, 0, "Source ended inside a map literal");
Error_Report(ctx->error, 0, else
"Got unexpected token \"%.*s\" inside " Error_Report(ctx->error, 0,
"map literal, where ',' or '}' were expected", "Got unexpected token \"%.*s\" inside "
ctx->token->length, ctx->src + ctx->token->offset); "map literal, where ',' or '}' were expected",
return NULL; ctx->token->length, ctx->src + ctx->token->offset);
return NULL;
}
next(ctx); // Skip the ','.
} }
next(ctx); // Skip the ','.
} }
} }
@@ -2001,7 +2013,7 @@ static _Bool parse_function_arguments(Context *ctx, int *argc_, Node **argv_)
return 1; return 1;
} }
static Node *parse_function_definition(Context *ctx) static FuncDeclNode *parse_function_definition(Context *ctx)
{ {
assert(ctx != NULL); assert(ctx != NULL);
@@ -2028,13 +2040,15 @@ static Node *parse_function_definition(Context *ctx)
return NULL; return NULL;
} }
char *name = copy_token_text(ctx); char *name_val = copy_token_text(ctx);
if(name_val == NULL)
if(name == NULL)
{ {
Error_Report(ctx->error, 1, "No memory"); Error_Report(ctx->error, 1, "No memory");
return NULL; return NULL;
} }
int name_len = strlen(name_val);
int name_offset = current_token(ctx)->offset;
int name_length = current_token(ctx)->length;
int argc = 0; // Initialization for the warning. int argc = 0; // Initialization for the warning.
Node *argv; Node *argv;
@@ -2052,28 +2066,56 @@ static Node *parse_function_definition(Context *ctx)
if(body == NULL) if(body == NULL)
return NULL; return NULL;
FunctionNode *func; FuncDeclNode *func;
{ {
// Make argument node. int length = body->offset
func = BPAlloc_Malloc(ctx->alloc, sizeof(FunctionNode)); + body->length
- offset;
FuncExprNode *expr = BPAlloc_Malloc(ctx->alloc, sizeof(FuncExprNode));
if (expr == NULL)
{
Error_Report(ctx->error, 1, "No memory");
return NULL;
}
expr->base.base.kind = NODE_EXPR;
expr->base.base.next = NULL;
expr->base.base.offset = offset;
expr->base.base.length = length;
expr->base.kind = EXPR_FUNC;
expr->argv = argv;
expr->argc = argc;
expr->body = body;
StringExprNode *name = BPAlloc_Malloc(ctx->alloc, sizeof(StringExprNode));
if (name == NULL)
{
Error_Report(ctx->error, 1, "No memory");
return NULL;
}
name->base.base.kind = NODE_EXPR;
name->base.base.next = NULL;
name->base.base.offset = name_offset;
name->base.base.length = name_length;
name->base.kind = EXPR_STRING;
name->val = name_val;
name->len = name_len;
func = BPAlloc_Malloc(ctx->alloc, sizeof(FuncDeclNode));
if(func == NULL) if(func == NULL)
{ {
Error_Report(ctx->error, 1, "No memory"); Error_Report(ctx->error, 1, "No memory");
return NULL; return NULL;
} }
func->base.kind = NODE_FUNC; func->base.kind = NODE_FUNC;
func->base.next = NULL; func->base.next = NULL;
func->base.offset = offset; func->base.offset = offset;
func->base.length = body->offset + body->length - offset; func->base.length = length;
func->name = name; func->name = name;
func->argv = argv; func->expr = expr;
func->argc = argc;
func->body = body;
} }
return (Node*) func; return func;
} }
static Node *parse_while_statement(Context *ctx) static Node *parse_while_statement(Context *ctx)