refactoring of the instruction table; removed unused instructions PUSHTYPTYP and ERROR; new modulo operator %; new examples fibonacci.noja and isprime.noja

This commit is contained in:
cozis
2022-12-07 18:31:35 +01:00
parent d483822538
commit 98374ee491
12 changed files with 194 additions and 11453 deletions
+1 -1
View File
@@ -11,4 +11,4 @@ vgcore.*
*.gcov *.gcov
lib*.a lib*.a
*.noja ./*.noja
+17
View File
@@ -0,0 +1,17 @@
fun fibonacci(n: int) {
if n < 0:
error("Only non-negative integers allowed");
if n == 0 or n == 1:
return 1;
if n == 2:
return 2;
return fibonacci(n-1)
+ fibonacci(n-2);
}
print(fibonacci(10), "\n");
+50
View File
@@ -0,0 +1,50 @@
fun isPrime(n: int) {
prime = true; # First assumption
if n < 3: {
if n == 2:
prime = true;
else
prime = false;
} else {
i = 2;
sqrt = math.sqrt(n/1.0);
do {
if n % i == 0: {
prime = false;
break;
}
i = i+1;
} while i <= sqrt;
}
return prime;
}
numbers = [
[-1, false],
[ 0, false],
[ 1, false],
[ 2, true],
[ 3, true],
[ 4, false],
[ 5, true],
[ 6, false],
[ 7, true],
[ 9, false],
[10, false],
[11, true],
[12, false],
[13, true],
[14, false],
[15, false]
];
i = 0;
while i < count(numbers): {
num = numbers[i][0];
exp = numbers[i][1];
res = isPrime(numbers[i][0]);
print("isPrime(", num, ") == ", res, "\n");
assert(res == exp);
i = i+1;
}
-11352
View File
File diff suppressed because one or more lines are too long
+77 -57
View File
@@ -37,6 +37,7 @@
#include "executable.h" #include "executable.h"
#define MAX_OPS 3 #define MAX_OPS 3
#define MAX_OPCODE_NAME_SIZE 127
typedef struct { typedef struct {
Opcode opcode; Opcode opcode;
@@ -62,84 +63,104 @@ struct xExeBuilder {
}; };
typedef struct { typedef struct {
Opcode opcode;
const char *name; const char *name;
int opcount; int opcount;
OperandType *optypes; OperandType *optypes;
} InstrInfo; } InstrInfo;
#define INSTR(name, ...) \
{ \
OPCODE_##name, \
#name, \
sizeof((OperandType[]) { __VA_ARGS__ }) / sizeof(OperandType), \
(OperandType[]) { __VA_ARGS__ }, \
},
static const InstrInfo instr_table[] = { static const InstrInfo instr_table[] = {
[OPCODE_NOPE] = {"NOPE", 0, NULL}, INSTR(NOPE)
[OPCODE_POS] = {"POS", 0, NULL}, INSTR(POS)
[OPCODE_NEG] = {"NEG", 0, NULL}, INSTR(NEG)
[OPCODE_NOT] = {"NOT", 0, NULL}, INSTR(NOT)
[OPCODE_ADD] = {"ADD", 0, NULL}, INSTR(ADD)
[OPCODE_SUB] = {"SUB", 0, NULL}, INSTR(SUB)
[OPCODE_MUL] = {"MUL", 0, NULL}, INSTR(MUL)
[OPCODE_DIV] = {"DIV", 0, NULL}, INSTR(DIV)
[OPCODE_EQL] = {"EQL", 0, NULL}, INSTR(EQL)
[OPCODE_NQL] = {"NQL", 0, NULL}, INSTR(NQL)
[OPCODE_LSS] = {"LSS", 0, NULL}, INSTR(LSS)
[OPCODE_GRT] = {"GRT", 0, NULL}, INSTR(GRT)
[OPCODE_LEQ] = {"LEQ", 0, NULL}, INSTR(LEQ)
[OPCODE_GEQ] = {"GEQ", 0, NULL}, INSTR(GEQ)
[OPCODE_NLB] = {"NLB", 0, NULL}, INSTR(NLB)
[OPCODE_STP] = {"STP", 0, NULL}, INSTR(STP)
[OPCODE_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}}, INSTR(ASS, OPTP_STRING)
[OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}}, INSTR(POP, OPTP_INT)
[OPCODE_CHECKTYPE] = {"CHECKTYPE", 2, (OperandType[]) {OPTP_INT, OPTP_STRING}}, INSTR(CHECKTYPE, OPTP_INT, OPTP_STRING)
[OPCODE_CALL] = {"CALL", 2, (OperandType[]) {OPTP_INT, OPTP_INT}}, INSTR(CALL, OPTP_INT, OPTP_INT)
[OPCODE_SELECT] = {"SELECT", 0, NULL}, INSTR(SELECT)
[OPCODE_INSERT] = {"INSERT", 0, NULL}, INSTR(INSERT)
[OPCODE_INSERT2] = {"INSERT2", 0, NULL}, INSTR(INSERT2)
[OPCODE_PUSHINT] = {"PUSHINT", 1, (OperandType[]) {OPTP_INT}}, INSTR(PUSHINT, OPTP_INT)
[OPCODE_PUSHFLT] = {"PUSHFLT", 1, (OperandType[]) {OPTP_FLOAT}}, INSTR(PUSHFLT, OPTP_FLOAT)
[OPCODE_PUSHSTR] = {"PUSHSTR", 1, (OperandType[]) {OPTP_STRING}}, INSTR(PUSHSTR, OPTP_STRING)
[OPCODE_PUSHVAR] = {"PUSHVAR", 1, (OperandType[]) {OPTP_STRING}}, INSTR(PUSHVAR, OPTP_STRING)
[OPCODE_PUSHTRU] = {"PUSHTRU", 0, NULL}, INSTR(PUSHTRU)
[OPCODE_PUSHFLS] = {"PUSHFLS", 0, NULL}, INSTR(PUSHFLS)
[OPCODE_PUSHNNE] = {"PUSHNNE", 0, NULL}, INSTR(PUSHNNE)
[OPCODE_PUSHFUN] = {"PUSHFUN", 2, (OperandType[]) {OPTP_IDX, OPTP_INT}}, INSTR(PUSHFUN, OPTP_IDX, OPTP_INT)
[OPCODE_PUSHLST] = {"PUSHLST", 1, (OperandType[]) {OPTP_INT}}, INSTR(PUSHLST, OPTP_INT)
[OPCODE_PUSHMAP] = {"PUSHMAP", 1, (OperandType[]) {OPTP_INT}}, INSTR(PUSHMAP, OPTP_INT)
[OPCODE_PUSHTYP] = {"PUSHTYP", 0, NULL}, INSTR(PUSHTYP)
[OPCODE_PUSHTYPTYP] = {"PUSHTYPTYP", 0, NULL}, INSTR(PUSHNNETYP)
[OPCODE_PUSHNNETYP] = {"PUSHNNETYP", 0, NULL}, INSTR(RETURN, OPTP_INT)
[OPCODE_RETURN] = {"RETURN", 1, (OperandType[]) {OPTP_INT}}, INSTR(EXIT)
[OPCODE_ERROR] = {"ERROR", 1, (OperandType[]) {OPTP_STRING}}, INSTR(JUMPIFNOTANDPOP, OPTP_IDX)
[OPCODE_EXIT] = {"EXIT", 0, NULL}, INSTR(JUMPIFANDPOP, OPTP_IDX)
[OPCODE_JUMPIFNOTANDPOP] = {"JUMPIFNOTANDPOP", 1, (OperandType[]) {OPTP_IDX}}, INSTR(JUMP, OPTP_IDX)
[OPCODE_JUMPIFANDPOP] = {"JUMPIFANDPOP", 1, (OperandType[]) {OPTP_IDX}},
[OPCODE_JUMP] = {"JUMP", 1, (OperandType[]) {OPTP_IDX}},
}; };
_Bool Executable_GetOpcodeBinaryFromName(const char *name, size_t name_len, Opcode *opcode) static const size_t instr_count = sizeof(instr_table)/sizeof(instr_table[0]);
_Bool Executable_GetOpcodeBinaryFromName(const char *name, size_t len, Opcode *opcode)
{ {
// The input name is assumed not zero-terminated, // The input name is assumed not zero-terminated,
// so to simplify things we duplicate it to add // so to simplify things we duplicate it to add
// an extra null byte. // an extra null byte.
char buff[128]; // No opcode should have a name this big. char buff[MAX_OPCODE_NAME_SIZE+1]; // No opcode should have a name this big.
ASSERT(name_len < sizeof(buff)); // If this is triggered, [buff] should be made bigger. if (len >= sizeof(buff))
return false;
memcpy(buff, name, name_len); memcpy(buff, name, len);
buff[name_len] = '\0'; buff[len] = '\0';
name = buff; name = buff;
// Now name is zero terminated. // Now name is zero terminated.
ASSERT(name[name_len] == '\0'); ASSERT(name[len] == '\0');
for(size_t i = 0; i < sizeof(instr_table)/sizeof(instr_table[0]); i += 1) { for(size_t i = 0; i < instr_count; i += 1) {
if(!strcmp(name, instr_table[i].name)) { if(!strcmp(name, instr_table[i].name)) {
*opcode = i; // Is this safe? if (opcode != NULL)
*opcode = instr_table[i].opcode;
return 1; return 1;
} }
} }
return 0; return 0;
} }
static const InstrInfo *Executable_GetInstrByOpcode(Opcode opcode)
{
for (size_t i = 0; i < instr_count; i++)
if (instr_table[i].opcode == opcode)
return instr_table + i;
return NULL;
}
const char *Executable_GetOpcodeName(Opcode opcode) const char *Executable_GetOpcodeName(Opcode opcode)
{ {
return instr_table[opcode].name; const InstrInfo *instr = Executable_GetInstrByOpcode(opcode);
if (instr == NULL)
return NULL;
return instr->name;
} }
Executable *Executable_Copy(Executable *exe) Executable *Executable_Copy(Executable *exe)
@@ -173,7 +194,7 @@ void Executable_Dump(Executable *exe)
(void) Executable_Fetch(exe, i, &opcode, ops, &opc); (void) Executable_Fetch(exe, i, &opcode, ops, &opc);
const InstrInfo *info = instr_table + exe->body[i].opcode; const InstrInfo *info = Executable_GetInstrByOpcode(opcode);
fprintf(stderr, "%d: %s ", i, info->name); fprintf(stderr, "%d: %s ", i, info->name);
@@ -250,7 +271,7 @@ _Bool Executable_Fetch(Executable *exe, int index, Opcode *opcode, Operand *ops,
return 0; return 0;
const Instruction *instr = exe->body + index; const Instruction *instr = exe->body + index;
const InstrInfo *info = instr_table + instr->opcode; const InstrInfo *info = Executable_GetInstrByOpcode(instr->opcode);
if(opcode) if(opcode)
*opcode = instr->opcode; *opcode = instr->opcode;
@@ -497,7 +518,7 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
[OPTP_STRING] = membersizeof(Operand, as_string), [OPTP_STRING] = membersizeof(Operand, as_string),
}; };
const InstrInfo *info = instr_table + opcode; const InstrInfo *info = Executable_GetInstrByOpcode(opcode);
if(opc != info->opcount) if(opc != info->opcount)
{ {
@@ -634,4 +655,3 @@ int ExeBuilder_InstrCount(ExeBuilder *exeb)
return raw_size / sizeof(Instruction); return raw_size / sizeof(Instruction);
} }
+1 -2
View File
@@ -61,6 +61,7 @@ typedef enum {
OPCODE_SUB, OPCODE_SUB,
OPCODE_MUL, OPCODE_MUL,
OPCODE_DIV, OPCODE_DIV,
OPCODE_MOD,
OPCODE_EQL, OPCODE_EQL,
OPCODE_NQL, OPCODE_NQL,
OPCODE_LSS, OPCODE_LSS,
@@ -86,10 +87,8 @@ typedef enum {
OPCODE_PUSHLST, OPCODE_PUSHLST,
OPCODE_PUSHMAP, OPCODE_PUSHMAP,
OPCODE_PUSHTYP, OPCODE_PUSHTYP,
OPCODE_PUSHTYPTYP,
OPCODE_PUSHNNETYP, OPCODE_PUSHNNETYP,
OPCODE_RETURN, OPCODE_RETURN,
OPCODE_ERROR,
OPCODE_EXIT, OPCODE_EXIT,
OPCODE_JUMPIFANDPOP, OPCODE_JUMPIFANDPOP,
OPCODE_JUMPIFNOTANDPOP, OPCODE_JUMPIFNOTANDPOP,
+1
View File
@@ -52,6 +52,7 @@ typedef enum {
EXPR_SUB, EXPR_SUB,
EXPR_MUL, EXPR_MUL,
EXPR_DIV, EXPR_DIV,
EXPR_MOD,
EXPR_EQL, EXPR_EQL,
EXPR_NQL, EXPR_NQL,
+2 -14
View File
@@ -135,14 +135,6 @@ static void emitInstr_EQL(CodegenContext *ctx, int off, int len)
CodegenContext_EmitInstr(ctx, OPCODE_EQL, NULL, 0, off, len); CodegenContext_EmitInstr(ctx, OPCODE_EQL, NULL, 0, off, len);
} }
static void emitInstr_ERROR(CodegenContext *ctx, const char *msg, int off, int len)
{
Operand opv[1] = {
{ .type = OPTP_STRING, .as_string = msg },
};
CodegenContext_EmitInstr(ctx, OPCODE_ERROR, opv, 1, off, len);
}
static void emitInstr_CHECKTYPE(CodegenContext *ctx, int arg_index, const char *arg_name, int off, int len) static void emitInstr_CHECKTYPE(CodegenContext *ctx, int arg_index, const char *arg_name, int off, int len)
{ {
Operand opv[2] = { Operand opv[2] = {
@@ -167,11 +159,6 @@ static void emitInstr_PUSHTYP(CodegenContext *ctx, int off, int len)
CodegenContext_EmitInstr(ctx, OPCODE_PUSHTYP, NULL, 0, off, len); CodegenContext_EmitInstr(ctx, OPCODE_PUSHTYP, NULL, 0, off, len);
} }
static void emitInstr_PUSHTYPTYP(CodegenContext *ctx, int off, int len)
{
CodegenContext_EmitInstr(ctx, OPCODE_PUSHTYPTYP, NULL, 0, off, len);
}
static void emitInstr_PUSHNNETYP(CodegenContext *ctx, int off, int len) static void emitInstr_PUSHNNETYP(CodegenContext *ctx, int off, int len)
{ {
CodegenContext_EmitInstr(ctx, OPCODE_PUSHNNETYP, NULL, 0, off, len); CodegenContext_EmitInstr(ctx, OPCODE_PUSHNNETYP, NULL, 0, off, len);
@@ -192,6 +179,7 @@ static Opcode exprkind_to_opcode(ExprKind kind)
case EXPR_SUB: return OPCODE_SUB; case EXPR_SUB: return OPCODE_SUB;
case EXPR_MUL: return OPCODE_MUL; case EXPR_MUL: return OPCODE_MUL;
case EXPR_DIV: return OPCODE_DIV; case EXPR_DIV: return OPCODE_DIV;
case EXPR_MOD: return OPCODE_MOD;
case EXPR_EQL: return OPCODE_EQL; case EXPR_EQL: return OPCODE_EQL;
case EXPR_NQL: return OPCODE_NQL; case EXPR_NQL: return OPCODE_NQL;
case EXPR_LSS: return OPCODE_LSS; case EXPR_LSS: return OPCODE_LSS;
@@ -391,7 +379,7 @@ static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr,
case EXPR_NULLABLETYPE: case EXPR_NULLABLETYPE:
case EXPR_SUMTYPE: case EXPR_SUMTYPE:
case EXPR_NOT: case EXPR_NOT: case EXPR_MOD:
case EXPR_POS: case EXPR_NEG: case EXPR_POS: case EXPR_NEG:
case EXPR_ADD: case EXPR_SUB: case EXPR_ADD: case EXPR_SUB:
case EXPR_MUL: case EXPR_DIV: case EXPR_MUL: case EXPR_DIV:
+7 -2
View File
@@ -71,6 +71,7 @@ typedef enum {
TSUB = '-', TSUB = '-',
TMUL = '*', TMUL = '*',
TDIV = '/', TDIV = '/',
TMOD = '%',
TLSS = '<', TLSS = '<',
TGRT = '>', TGRT = '>',
@@ -145,7 +146,8 @@ static inline _Bool isoper(char c)
c == '*' || c == '/' || c == '*' || c == '/' ||
c == '<' || c == '>' || c == '<' || c == '>' ||
c == '!' || c == '=' || c == '!' || c == '=' ||
c == ',' || c == '|'; c == ',' || c == '|' ||
c == '%';
} }
/* Symbol: tokenize /* Symbol: tokenize
@@ -328,6 +330,7 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
{ TASS, 1, "=" }, { TASS, 1, "=" },
{ TCOMMA, 1, "," }, { TCOMMA, 1, "," },
{ TSMT, 1, "|" }, { TSMT, 1, "|" },
{ TMOD, 1, "%" },
}; };
_Bool found = 0; _Bool found = 0;
@@ -1603,7 +1606,7 @@ static inline _Bool isbinop(Token *tok)
tok->kind == TEQL || tok->kind == TNQL || tok->kind == TEQL || tok->kind == TNQL ||
tok->kind == TKWAND || tok->kind == TKWOR || tok->kind == TKWAND || tok->kind == TKWOR ||
tok->kind == '=' || tok->kind == ',' || tok->kind == '=' || tok->kind == ',' ||
tok->kind == '|'; tok->kind == '|' || tok->kind == '%';
} }
static inline _Bool isrightassoc(Token *tok) static inline _Bool isrightassoc(Token *tok)
@@ -1645,6 +1648,7 @@ static inline int precedenceof(Token *tok)
case '*': case '*':
case '/': case '/':
case '%':
return 6; return 6;
case ',': case ',':
@@ -1707,6 +1711,7 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec, _Bo
case '-': temp->base.kind = EXPR_SUB; break; case '-': temp->base.kind = EXPR_SUB; break;
case '*': temp->base.kind = EXPR_MUL; break; case '*': temp->base.kind = EXPR_MUL; break;
case '/': temp->base.kind = EXPR_DIV; break; case '/': temp->base.kind = EXPR_DIV; break;
case '%': temp->base.kind = EXPR_MOD; break;
case '<': temp->base.kind = EXPR_LSS; break; case '<': temp->base.kind = EXPR_LSS; break;
case '>': temp->base.kind = EXPR_GRT; break; case '>': temp->base.kind = EXPR_GRT; break;
case TLEQ: temp->base.kind = EXPR_LEQ; break; case TLEQ: temp->base.kind = EXPR_LEQ; break;
+34 -21
View File
@@ -739,6 +739,40 @@ static _Bool step(Runtime *runtime, Error *error)
return 1; return 1;
} }
case OPCODE_MOD:
{
ASSERT(opc == 0);
Object *rop = Stack_Top(runtime->stack, 0);
Object *lop = Stack_Top(runtime->stack, -1);
if(!Runtime_Pop(runtime, error, 2))
return 0;
// We managed to pop rop and lop,
// so we know they're not NULL.
ASSERT(rop != NULL);
ASSERT(lop != NULL);
if (!Object_IsInt(rop) || !Object_IsInt(lop)) {
Error_Report(error, 0, "Arithmetic operation on a non-numeric object");
return 0;
}
long long int x, y, z;
y = Object_GetInt(rop);
x = Object_GetInt(lop);
z = x % y;
Object *res = Object_FromInt(z, runtime->heap, error);
if(res == NULL)
return 0;
if(!Runtime_Push(runtime, error, res))
return 0;
return 1;
}
case OPCODE_EQL: case OPCODE_EQL:
case OPCODE_NQL: case OPCODE_NQL:
{ {
@@ -1213,18 +1247,6 @@ static _Bool step(Runtime *runtime, Error *error)
return 1; return 1;
} }
case OPCODE_PUSHTYPTYP:
{
ASSERT(opc == 0);
Object *obj = (Object*) Object_GetTypeType();
ASSERT(obj != NULL);
if(!Runtime_Push(runtime, error, obj))
return 0;
return 1;
}
case OPCODE_PUSHNNETYP: case OPCODE_PUSHNNETYP:
{ {
ASSERT(opc == 0); ASSERT(opc == 0);
@@ -1282,15 +1304,6 @@ static _Bool step(Runtime *runtime, Error *error)
return 0; return 0;
} }
case OPCODE_ERROR:
{
ASSERT(opc == 1);
ASSERT(ops[0].type == OPTP_STRING);
const char *msg = ops[0].as_string;
Error_Report(error, 0, "%s", msg);
return 0;
}
case OPCODE_JUMP: case OPCODE_JUMP:
ASSERT(opc == 1); ASSERT(opc == 1);
ASSERT(ops[0].type == OPTP_IDX); ASSERT(ops[0].type == OPTP_IDX);
Binary file not shown.
@@ -15,7 +15,7 @@
}, },
{ {
"name": "keyword.operator.noja", "name": "keyword.operator.noja",
"match": "(\\+|-|\\*|\\/|=|==|!=|\\>|\\<|\\>=|\\<=|\\|)" "match": "(\\+|-|\\*|\\/|%|=|==|!=|\\>|\\<|\\>=|\\<=|\\|)"
}, },
{ {
"name": "keyword.operator.logical.noja", "name": "keyword.operator.logical.noja",