new -> operator

This commit is contained in:
cozis
2022-12-08 03:01:04 +01:00
parent b114387728
commit f7d28556a1
8 changed files with 98 additions and 41 deletions
+12
View File
@@ -0,0 +1,12 @@
fun sayHello(self, other)
print("Hello ", other, " from ", self.name);
person = {
name: "Francesco",
sayHello: sayHello
};
person->sayHello("Giovanni");
+29 -24
View File
@@ -1,3 +1,4 @@
scan = import("scan.noja"); scan = import("scan.noja");
newScanner = scan.newScanner; newScanner = scan.newScanner;
@@ -7,14 +8,16 @@ consume = scan.consume;
current = scan.current; current = scan.current;
isDigit = scan.isDigit; isDigit = scan.isDigit;
consumeSpaces = scan.consumeSpaces; consumeSpaces = scan.consumeSpaces;
ord = string.ord;
cat = string.cat;
fun isAlpha(char: String) fun isAlpha(char: String)
return (string.ord(char) >= string.ord('a') and string.ord(char) <= string.ord('z')) return (ord(char) >= ord('a') and ord(char) <= ord('z'))
or (string.ord(char) >= string.ord('A') and string.ord(char) <= string.ord('Z')); or (ord(char) >= ord('A') and ord(char) <= ord('Z'));
fun isUpper(char: String) fun isUpper(char: String)
return string.ord(char) >= string.ord('A') return ord(char) >= ord('A')
and string.ord(char) <= string.ord('Z'); and ord(char) <= ord('Z');
fun isUnreserved(char: String) fun isUnreserved(char: String)
return isAlpha(char) return isAlpha(char)
@@ -46,7 +49,7 @@ fun parseMethod(scan: Scanner) {
method = ""; method = "";
do { do {
method = string.cat(method, char); method = cat(method, char);
consume(scan); consume(scan);
char = current(scan); char = current(scan);
} while char != none and isUpper(char); } while char != none and isUpper(char);
@@ -65,8 +68,8 @@ fun parsePort(scan: Scanner) {
port = 0; port = 0;
do { do {
digit = string.ord(char) digit = ord(char)
- string.ord("0"); - ord("0");
port = port * 10 + digit; port = port * 10 + digit;
consume(scan); consume(scan);
char = current(scan); char = current(scan);
@@ -90,7 +93,7 @@ fun parseHost(scan: Scanner) {
name = ""; name = "";
do { do {
name = string.cat(name, char); name = cat(name, char);
consume(scan); consume(scan);
char = current(scan); char = current(scan);
} while char != none and isHostname(char); } while char != none and isHostname(char);
@@ -104,7 +107,7 @@ fun parsePath(scan: Scanner) {
path = ""; path = "";
char = current(scan); char = current(scan);
if char != none and char == "/": { if char != none and char == "/": {
path = string.cat(path, char); path = cat(path, char);
consume(scan); consume(scan);
char = current(scan); char = current(scan);
} else { } else {
@@ -114,13 +117,13 @@ fun parsePath(scan: Scanner) {
while char != none and isPChar(char): { while char != none and isPChar(char): {
do { do {
path = string.cat(path, char); path = cat(path, char);
consume(scan); consume(scan);
char = current(scan); char = current(scan);
} while char != none and isPChar(char); } while char != none and isPChar(char);
if char == none or char != "/": if char == none or char != "/":
break; break;
path = string.cat(path, char); path = cat(path, char);
consume(scan); consume(scan);
char = current(scan); char = current(scan);
} }
@@ -143,7 +146,7 @@ fun parseQuery(scan: Scanner) {
consume(scan); # Consume the "?" consume(scan); # Consume the "?"
query = ""; query = "";
while isQuery(char = current(scan)): { while isQuery(char = current(scan)): {
query = string.cat(query, char); query = cat(query, char);
consume(scan); consume(scan);
} }
} else } else
@@ -165,7 +168,7 @@ fun parseFragment(scan: Scanner) {
consume(scan); # Consume the "#" consume(scan); # Consume the "#"
fragment = ""; fragment = "";
while isFragment(char = current(scan)): { while isFragment(char = current(scan)): {
fragment = string.cat(fragment, char); fragment = cat(fragment, char);
consume(scan); consume(scan);
} }
} else } else
@@ -174,12 +177,15 @@ fun parseFragment(scan: Scanner) {
return fragment; return fragment;
} }
Host = { name: String, port: ?int }; Host = {
name: String,
port: ?int
};
URL = { URL = {
schema: ?String, schema: ?String,
host: ?Host, host: ?Host,
path: ?String, path: String,
query: ?String, query: ?String,
fragment: ?String fragment: ?String
}; };
@@ -204,7 +210,7 @@ fun parseSchema(scan: Scanner) {
start = scan.i; start = scan.i;
schema = ""; schema = "";
do { do {
schema = string.cat(schema, char); schema = cat(schema, char);
consume(scan); consume(scan);
char = current(scan); char = current(scan);
} while isSchema(char); } while isSchema(char);
@@ -253,7 +259,6 @@ fun parseURL(scan: Scanner) {
query = parseQuery(scan); query = parseQuery(scan);
fragment = parseFragment(scan); fragment = parseFragment(scan);
print(scan);
return { return {
host : host, host : host,
@@ -272,13 +277,13 @@ fun parseVersion(scan: Scanner) {
return none, "Invalid version token"; return none, "Invalid version token";
consume(scan, 5); consume(scan, 5);
major = string.ord(current(scan)) major = ord(current(scan))
- string.ord("0"); - ord("0");
if hint(scan, 1) != "." and isDigit(hint(scan, 2)): { if hint(scan, 1) != "." and isDigit(hint(scan, 2)): {
consume(scan, 2); consume(scan, 2);
minor = string.ord(current(scan)) minor = ord(current(scan))
- string.ord("0"); - ord("0");
} else } else
minor = 0; minor = 0;
consume(scan); consume(scan);
@@ -343,7 +348,7 @@ fun parse(src: String) {
# Header name until the next ":" # Header name until the next ":"
name = ""; name = "";
do { do {
name = string.cat(name, char); name = cat(name, char);
consume(scan); consume(scan);
char = current(scan); char = current(scan);
} while char != ":" and char != none; } while char != ":" and char != none;
@@ -357,7 +362,7 @@ fun parse(src: String) {
# Header body until \r # Header body until \r
body = ""; body = "";
do { do {
body = string.cat(body, char); body = cat(body, char);
consume(scan); consume(scan);
char = current(scan); char = current(scan);
} while char != "\r" and char != none; } while char != "\r" and char != none;
@@ -371,7 +376,7 @@ fun parse(src: String) {
return newRequest(method, url, version, headers); return newRequest(method, url, version, headers);
} }
sample = string.cat( sample = cat(
"GET /search?client=firefox-b-d&q=http+request+dataset HTTP/2\r\n", "GET /search?client=firefox-b-d&q=http+request+dataset HTTP/2\r\n",
"Host: www.google.com\r\n", "Host: www.google.com\r\n",
"user-agent: curl/7.84.0\r\n", "user-agent: curl/7.84.0\r\n",
+8
View File
@@ -99,6 +99,7 @@ static const InstrInfo instr_table[] = {
INSTR(CHECKTYPE, OPTP_INT, OPTP_STRING) INSTR(CHECKTYPE, OPTP_INT, OPTP_STRING)
INSTR(CALL, OPTP_INT, OPTP_INT) INSTR(CALL, OPTP_INT, OPTP_INT)
INSTR(SELECT) INSTR(SELECT)
INSTR(SELECT2)
INSTR(INSERT) INSTR(INSERT)
INSTR(INSERT2) INSTR(INSERT2)
INSTR(PUSHINT, OPTP_INT) INSTR(PUSHINT, OPTP_INT)
@@ -520,6 +521,13 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
const InstrInfo *info = Executable_GetInstrByOpcode(opcode); const InstrInfo *info = Executable_GetInstrByOpcode(opcode);
#ifndef NDEBUG
if (info == NULL) {
Error_Report(error, 1, "Missing instruction table entry for opcode");
return 0;
}
#endif
if(opc != info->opcount) if(opc != info->opcount)
{ {
// ERROR: Too many operands were provided. // ERROR: Too many operands were provided.
+1
View File
@@ -74,6 +74,7 @@ typedef enum {
OPCODE_POP, OPCODE_POP,
OPCODE_CALL, OPCODE_CALL,
OPCODE_SELECT, OPCODE_SELECT,
OPCODE_SELECT2,
OPCODE_INSERT, OPCODE_INSERT,
OPCODE_INSERT2, OPCODE_INSERT2,
OPCODE_PUSHINT, OPCODE_PUSHINT,
+1
View File
@@ -65,6 +65,7 @@ typedef enum {
EXPR_OR, EXPR_OR,
EXPR_NOT, EXPR_NOT,
EXPR_ARW,
EXPR_ASS, EXPR_ASS,
EXPR_INT, EXPR_INT,
EXPR_MAP, EXPR_MAP,
+24 -4
View File
@@ -198,19 +198,34 @@ static void emitInstrForFuncCallNode(CodegenContext *ctx, CallExprNode *expr,
Label *label_break, int returns) Label *label_break, int returns)
{ {
Node *arg = expr->argv; Node *arg = expr->argv;
while(arg) while(arg)
{ {
emitInstrForNode(ctx, arg, label_break); emitInstrForNode(ctx, arg, label_break);
arg = arg->next; arg = arg->next;
} }
emitInstrForNode(ctx, expr->func, label_break); int argc;
if (expr->func->kind == NODE_EXPR && ((ExprNode*) expr->func)->kind == EXPR_ARW) {
IndexSelectionExprNode *selection = (IndexSelectionExprNode*) expr->func;
Node *idx = selection->idx;
Node *set = selection->set;
emitInstrForNode(ctx, set, label_break);
emitInstrForNode(ctx, idx, label_break);
CodegenContext_EmitInstr(ctx, OPCODE_SELECT2, NULL, 0,
expr->func->offset,
expr->func->length);
argc = expr->argc+1;
} else {
emitInstrForNode(ctx, expr->func, label_break);
argc = expr->argc;
}
Operand ops[2]; Operand ops[2];
ops[0] = (Operand) { .type = OPTP_INT, .as_int = expr->argc }; ops[0] = (Operand) { .type = OPTP_INT, .as_int = argc };
ops[1] = (Operand) { .type = OPTP_INT, .as_int = returns }; ops[1] = (Operand) { .type = OPTP_INT, .as_int = returns };
CodegenContext_EmitInstr(ctx, OPCODE_CALL, ops, 2, expr->base.base.offset, expr->base.base.length); CodegenContext_EmitInstr(ctx, OPCODE_CALL, ops, 2,
expr->base.base.offset,
expr->base.base.length);
} }
static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr, static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr,
@@ -394,6 +409,11 @@ static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr,
return; return;
} }
case EXPR_ARW:
CodegenContext_ReportErrorAndJump(ctx, 0, "Operator -> out of a function call");
UNREACHABLE;
return;
case EXPR_AND: case EXPR_AND:
{ {
OperExprNode *oper = (OperExprNode*) expr; OperExprNode *oper = (OperExprNode*) expr;
+13 -8
View File
@@ -52,6 +52,7 @@
** +--------------------------------------------------------------------------+ ** +--------------------------------------------------------------------------+
*/ */
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
@@ -112,6 +113,7 @@ typedef enum {
TNQL, TNQL,
TLEQ, TLEQ,
TGEQ, TGEQ,
TARW,
} TokenKind; } TokenKind;
@@ -331,6 +333,7 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
{ TCOMMA, 1, "," }, { TCOMMA, 1, "," },
{ TSMT, 1, "|" }, { TSMT, 1, "|" },
{ TMOD, 1, "%" }, { TMOD, 1, "%" },
{ TARW, 2, "->" },
}; };
_Bool found = 0; _Bool found = 0;
@@ -1364,7 +1367,7 @@ static Node *parse_primary_expresion(Context *ctx)
return NULL; return NULL;
} }
static Node *makeIndexSelectionExprNode(Context *ctx, Node *set, Node *idx) static Node *makeIndexOrArrowSelectionExprNode(Context *ctx, bool arrow, Node *set, Node *idx)
{ {
IndexSelectionExprNode *sel = BPAlloc_Malloc(ctx->alloc, sizeof(IndexSelectionExprNode)); IndexSelectionExprNode *sel = BPAlloc_Malloc(ctx->alloc, sizeof(IndexSelectionExprNode));
@@ -1378,7 +1381,7 @@ static Node *makeIndexSelectionExprNode(Context *ctx, Node *set, Node *idx)
sel->base.base.next = NULL; sel->base.base.next = NULL;
sel->base.base.offset = -1; sel->base.base.offset = -1;
sel->base.base.length = -1; sel->base.base.length = -1;
sel->base.kind = EXPR_SELECT; sel->base.kind = arrow ? EXPR_ARW : EXPR_SELECT;
sel->set = set; sel->set = set;
sel->idx = idx; sel->idx = idx;
return (Node*) sel; return (Node*) sel;
@@ -1398,20 +1401,23 @@ static Node *parse_postfix_expression(Context *ctx)
switch(current(ctx)) switch(current(ctx))
{ {
case '.': case '.':
case TARW:
{ {
bool arrow = (current(ctx) == TARW);
next(ctx); next(ctx);
// We expect an identifier after the dot. // We expect an identifier after the dot or arrow
if(done(ctx)) if(done(ctx))
{ {
Error_Report(ctx->error, 0, "Source ended after dot of dot selection expression"); Error_Report(ctx->error, 0, "Source ended after dot or arrow");
return NULL; return NULL;
} }
if(current(ctx) != TIDENT) if(current(ctx) != TIDENT)
{ {
Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after fot of dot selection expression where an identifier was expected", ctx->token->length, ctx->src + ctx->token->offset); Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after dot or arrow, where an identifier was expected", ctx->token->length, ctx->src + ctx->token->offset);
return NULL; return NULL;
} }
@@ -1419,7 +1425,7 @@ static Node *parse_postfix_expression(Context *ctx)
if(idx == NULL) if(idx == NULL)
return NULL; return NULL;
Node *sel = makeIndexSelectionExprNode(ctx, node, idx); Node *sel = makeIndexOrArrowSelectionExprNode(ctx, arrow, node, idx);
if(sel == NULL) if(sel == NULL)
return NULL; return NULL;
@@ -1446,7 +1452,7 @@ static Node *parse_postfix_expression(Context *ctx)
return NULL; return NULL;
} }
Node *sel = makeIndexSelectionExprNode(ctx, node, ls->itemc == 1 ? ls->items : (Node*) ls); Node *sel = makeIndexOrArrowSelectionExprNode(ctx, false, node, ls->itemc == 1 ? ls->items : (Node*) ls);
if(sel == NULL) if(sel == NULL)
return NULL; return NULL;
@@ -1723,7 +1729,6 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec, _Bo
case '=': temp->base.kind = EXPR_ASS; break; case '=': temp->base.kind = EXPR_ASS; break;
case '|': temp->base.kind = EXPR_SUMTYPE; break; case '|': temp->base.kind = EXPR_SUMTYPE; break;
case ',': temp->base.kind = EXPR_PAIR; break; case ',': temp->base.kind = EXPR_PAIR; break;
default: default:
UNREACHABLE; UNREACHABLE;
break; break;
+9 -4
View File
@@ -978,12 +978,18 @@ static _Bool step(Runtime *runtime, Error *error)
} }
case OPCODE_SELECT: case OPCODE_SELECT:
case OPCODE_SELECT2:
{ {
ASSERT(opc == 0); ASSERT(opc == 0);
if(runtime->frame->used < 2) int to_be_popped = (opcode == OPCODE_SELECT) ? 2 : 1;
if(runtime->frame->used < to_be_popped)
{ {
Error_Report(error, 1, "Frame has not enough values on the stack to run SELECT instruction"); const char *name = "SELECT";
if (opcode == OPCODE_SELECT2)
name = "SELECT2";
Error_Report(error, 1, "Frame has not enough values on the stack to run %s instruction", name);
return 0; return 0;
} }
@@ -992,7 +998,7 @@ static _Bool step(Runtime *runtime, Error *error)
ASSERT(col != NULL && key != NULL); ASSERT(col != NULL && key != NULL);
if(!Runtime_Pop(runtime, error, 2)) if(!Runtime_Pop(runtime, error, to_be_popped))
return 0; return 0;
ASSERT(error->occurred == 0); ASSERT(error->occurred == 0);
@@ -1007,7 +1013,6 @@ static _Bool step(Runtime *runtime, Error *error)
Error_Free(&dummy); Error_Free(&dummy);
val = Object_NewNone(runtime->heap, error); val = Object_NewNone(runtime->heap, error);
if(val == NULL) if(val == NULL)
return 0; return 0;
} }