Skip to content

Commit c1f4027

Browse files
v0.13.1 (#470)
* v0.13.1 * clean up for C++ * avoid memleak * fix fallthrough for mathc * clean up list sorting implementation * list sort WIP * add list sorting logic but leave disabled for now * update macOS pipelines * clean up * make list methods static * allow defining globals from command line * fix for C++ * fix mem leak * fix version * clean up compiler implementation * Explicitly state that the function array does not need to be mutable (#476) * clean up init of state * fix bug with ref counting in comparison operators * add newline --------- Co-authored-by: Ryan Andersen <[email protected]>
1 parent 6ea631a commit c1f4027

File tree

21 files changed

+328
-167
lines changed

21 files changed

+328
-167
lines changed

azure-pipelines.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ jobs:
198198
- job:
199199
displayName: "C Clang MacOS"
200200
pool:
201-
vmImage: 'macOS-10.15'
201+
vmImage: 'macOS-11'
202202
steps:
203203
- script: |
204204
set -e
@@ -218,7 +218,7 @@ jobs:
218218
- job:
219219
displayName: "C++ Clang MacOS"
220220
pool:
221-
vmImage: 'macOS-10.15'
221+
vmImage: 'macOS-11'
222222
steps:
223223
- script: |
224224
set -e

compiler/parser.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,12 @@ static struct Node *parse_match(struct Parser *const parser) {
851851
eattok(parser, T_SEMI);
852852
}
853853
eattok(parser, T_RBRC);
854+
855+
struct Node *n = new_Undef(parser, line);
856+
n->nodetype = N_PATANY;
857+
body_append(parser, &pats, n);
858+
body_append(parser, &guards, NULL);
859+
body_append(parser, &bodies, new_Body(parser, line));
854860
return new_Match(parser, expr, pats, guards, bodies, line);
855861
}
856862

@@ -1266,10 +1272,23 @@ static struct Node *parse_string(struct Parser *const parser) {
12661272
eattok(parser, T_LBRC);
12671273
parser->lex.mode = L_NORMAL;
12681274
struct Node *expr = parse_expr(parser);
1269-
parser->lex.mode = L_INTERP;
12701275
const size_t line = parserline(parser);
1276+
1277+
// Handle format strings
1278+
if (matcheattok(parser, T_COLON)) {
1279+
struct Node *fmt = parse_id(parser);
1280+
fmt->nodetype = N_STR;
1281+
const size_t line = parserline(parser);
1282+
struct Node *block = new_Exprs(parser, line);
1283+
body_append(parser, &block, fmt);
1284+
static char tostr[] = "tostr";
1285+
expr = new_MethodCall(parser, block, expr, tostr, 1, line);
1286+
}
1287+
12711288
cur_node = new_BinOp(parser, T_TILDE, cur_node, expr, line);
12721289

1290+
parser->lex.mode = L_INTERP;
1291+
12731292
if (parser->lex.c == '}') {
12741293
parser->lex.c = lxgetc(parser->lex.file);
12751294
} else {

data-structures/YASL_ByteBuffer.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ void YASL_ByteBuffer_del(YASL_ByteBuffer *const bb);
2121

2222
void YASL_ByteBuffer_extend(YASL_ByteBuffer *const bb, const byte *const bytes, const size_t bytes_len);
2323
#define YASL_ByteBuffer_add_byte BUFFER_PUSH(byte)
24-
// void YASL_ByteBuffer_add_byte(YASL_ByteBuffer *const buffer, const byte v);
2524
void YASL_ByteBuffer_add_vint(YASL_ByteBuffer *const bb, size_t val);
2625
void YASL_ByteBuffer_add_float(YASL_ByteBuffer *const bb, const yasl_float value);
2726
void YASL_ByteBuffer_add_int(YASL_ByteBuffer *const bb, const yasl_int value);

interpreter/VM.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -529,19 +529,21 @@ static void vm_CNCT(struct VM *const vm) {
529529

530530
#define DEFINE_COMP(name, opstr, overload_name) \
531531
static void vm_##name(struct VM *const vm) {\
532-
struct YASL_Object right = vm_pop(vm);\
533-
struct YASL_Object left = vm_pop(vm);\
532+
struct YASL_Object right = vm_peek(vm);\
533+
struct YASL_Object left = vm_peek(vm, vm->sp -1);\
534534
bool c;\
535535
if (obj_isstr(&left) && obj_isstr(&right)) {\
536+
vm_pop(vm);\
537+
vm_pop(vm);\
536538
vm_pushbool(vm, name(YASL_String_cmp(obj_getstr(&left), obj_getstr(&right)), 0));\
537539
return;\
538540
}\
539541
if (obj_isnum(&left) && obj_isnum(&right)) {\
542+
vm_pop(vm);\
543+
vm_pop(vm);\
540544
COMP(vm, left, right, name);\
541545
return;\
542546
}\
543-
vm_push(vm, left);\
544-
vm_push(vm, right);\
545547
vm_call_binop_method_now(vm, left, right, overload_name, "%s not supported for operands of types %s and %s.",\
546548
opstr,\
547549
obj_typename(&left),\

interpreter/list_methods.c

Lines changed: 104 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -395,71 +395,119 @@ int list_count(struct YASL_State *S) {
395395
return 1;
396396
}
397397

398-
static const int SORT_TYPE_EMPTY = 0;
399-
static const int SORT_TYPE_STR = -1;
400-
static const int SORT_TYPE_NUM = 1;
401-
void sort(struct YASL_Object *list, const size_t len) {
402-
// Base cases
403-
struct YASL_Object tmpObj;
404-
if (len < 2) return;
405-
if (len == 2) {
406-
if (yasl_object_cmp(list[0], list[1]) > 0) {
407-
tmpObj = list[0];
408-
list[0] = list[1];
409-
list[1] = tmpObj;
410-
}
411-
return;
398+
enum SortType {
399+
SORT_TYPE_STR = -1,
400+
SORT_TYPE_EMPTY = 0,
401+
SORT_TYPE_NUM = 1
402+
};
403+
404+
405+
int custom_comp(struct YASL_State *S, struct YASL_Object a, struct YASL_Object b) {
406+
YASL_duptop(S);
407+
vm_push((struct VM *)S, a);
408+
vm_push((struct VM *)S, b);
409+
YASL_functioncall(S, 2);
410+
if (!YASL_isbool(S)) {
411+
YASL_print_err(S, "TypeError: Expected a function returning bool, got %s.", YASL_peektypename(S));
412+
YASL_throw_err(S, YASL_TYPE_ERROR);
412413
}
413-
414-
// YASL_Set sorting bounds
415-
size_t left = 0;
416-
size_t right = len - 1;
417-
418-
// Determine random midpoint to use (good average case)
419-
const size_t randIndex = rand() % len;
420-
const struct YASL_Object mid = list[randIndex];
421-
422-
// Determine exact number of items less than mid (mid's index)
423-
// Furthermore, ensure list is not homogenous to avoid infinite loops
424-
size_t ltCount = 0;
425-
int seenDifferent = 0;
426-
for (size_t i = 0; i < len; i++) {
427-
if (yasl_object_cmp(list[i], mid) < 0) ltCount++;
428-
if (seenDifferent == 0 && yasl_object_cmp(list[0], list[i]) != 0) seenDifferent = 1;
414+
bool a_lt_b = YASL_popbool(S);
415+
416+
YASL_duptop(S);
417+
vm_push((struct VM *)S, b);
418+
vm_push((struct VM *)S, a);
419+
YASL_functioncall(S, 2);
420+
if (!YASL_isbool(S)) {
421+
YASL_print_err(S, "TypeError: Expected a function returning bool, got %s.", YASL_peektypename(S));
422+
YASL_throw_err(S, YASL_TYPE_ERROR);
429423
}
430-
if (seenDifferent == 0) return;
431424

432-
// Ensure all items are on the correct side of mid
433-
while (left < right) {
434-
while (yasl_object_cmp(list[left], mid) < 0) left++;
435-
while (yasl_object_cmp(list[right], mid) >= 0) {
436-
if (right == 0) break;
437-
right--;
438-
}
425+
bool a_gt_b = YASL_popbool(S);
439426

440-
int cmp = yasl_object_cmp(list[left], list[right]);
441-
if (cmp > 0 && left < right) {
442-
tmpObj = list[right];
443-
list[right] = list[left];
444-
list[left++] = tmpObj;
445-
if (right == 0) break;
446-
right--;
447-
} else if (cmp == 0) {
448-
left++;
449-
if (right == 0) break;
450-
right--;
451-
}
452-
}
427+
if (a_lt_b == a_gt_b) return 0;
428+
return a_lt_b ? -1 : a_gt_b ? 1 : 0;
429+
}
453430

454-
// Let sort() finish that for us...
455-
sort(list, ltCount);
456-
sort(&list[ltCount], len - ltCount);
431+
#define CUSTOM_COMP(a, b) custom_comp(S, a, b)
432+
433+
#define DEF_SORT(name, COMP) \
434+
static void name##sort(struct YASL_State *S, struct YASL_Object *list, const size_t len) {\
435+
/* Base cases*/ \
436+
struct YASL_Object tmpObj;\
437+
if (len < 2) return;\
438+
if (len == 2) {\
439+
if (COMP(list[0], list[1]) > 0) {\
440+
tmpObj = list[0];\
441+
list[0] = list[1];\
442+
list[1] = tmpObj;\
443+
}\
444+
return;\
445+
}\
446+
\
447+
/* YASL_Set sorting bounds */\
448+
size_t left = 0;\
449+
size_t right = len - 1;\
450+
\
451+
/* Determine random midpoint to use (good average case) */\
452+
const size_t randIndex = rand() % len;\
453+
const struct YASL_Object mid = list[randIndex];\
454+
\
455+
/* Determine exact number of items less than mid (mid's index)\
456+
Furthermore, ensure list is not homogeneous to avoid infinite loops */\
457+
size_t ltCount = 0;\
458+
bool seenDifferent = false;\
459+
for (size_t i = 0; i < len; i++) {\
460+
if (COMP(list[i], mid) < 0) ltCount++;\
461+
if (seenDifferent == 0 && COMP(list[0], list[i]) != 0) seenDifferent = true;\
462+
}\
463+
if (!seenDifferent) return;\
464+
\
465+
/* Ensure all items are on the correct side of mid */\
466+
while (left < right) {\
467+
while (COMP(list[left], mid) < 0) left++;\
468+
while (COMP(list[right], mid) >= 0) {\
469+
if (right == 0) break;\
470+
right--;\
471+
}\
472+
\
473+
int cmp = COMP(list[left], list[right]);\
474+
if (cmp > 0 && left < right) {\
475+
tmpObj = list[right];\
476+
list[right] = list[left];\
477+
list[left++] = tmpObj;\
478+
if (right == 0) break;\
479+
right--;\
480+
} else if (cmp == 0) {\
481+
left++;\
482+
if (right == 0) break;\
483+
right--;\
484+
}\
485+
}\
486+
\
487+
/* Let sort() finish that for us...*/ \
488+
name##sort(S, list, ltCount);\
489+
name##sort(S, &list[ltCount], len - ltCount);\
457490
}
458491

492+
DEF_SORT(default, yasl_object_cmp)
493+
// DEF_SORT(fn, CUSTOM_COMP)
494+
459495
// TODO: clean this up
460496
int list_sort(struct YASL_State *S) {
461497
struct YASL_List *list = YASLX_checknlist(S, "list.sort", 0);
462-
int type = SORT_TYPE_EMPTY;
498+
499+
/*
500+
if (!YASL_isundef(S)) {
501+
fnsort(S, list->items, list->count);
502+
return 0;
503+
}
504+
*/
505+
506+
if (YASL_List_length(list) <= 1) {
507+
return 0;
508+
}
509+
510+
enum SortType type = SORT_TYPE_EMPTY;
463511

464512
int err = 0;
465513
for (size_t i = 0; i < list->count; i++) {
@@ -489,7 +537,7 @@ int list_sort(struct YASL_State *S) {
489537
}
490538

491539
if (type != SORT_TYPE_EMPTY) {
492-
sort(list->items, list->count);
540+
defaultsort(S, list->items, list->count);
493541
}
494542

495543
return 0;

main.c

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,47 @@ static inline void main_init_platform() {
5656
}
5757

5858
static int main_file(int argc, char **argv) {
59-
(void) argc;
60-
struct YASL_State *S = YASL_newstate(argv[1]);
59+
YASL_ByteBuffer *buffer = YASL_ByteBuffer_new(8);
60+
struct YASL_State *S = YASL_newstate_bb(NULL, 0);
61+
// Load Standard Libraries
62+
YASLX_decllibs(S);
63+
64+
while (argc > 1 && !strncmp(argv[1], "-D", 2)) {
65+
const char *equals = strchr(argv[1], '=');
66+
if (!equals) {
67+
fprintf(stderr, "Error: Expected an initial value for variable: %s\n", argv[1] + 2);
68+
exit(EXIT_FAILURE);
69+
}
70+
const long int len = equals - argv[1] -2;
71+
if (len <= 0) {
72+
fprintf(stderr, "Error: Non-empty name required for variable: %s\n", argv[1] + 2);
73+
exit(EXIT_FAILURE);
74+
}
75+
char *name = (char *)malloc(len + 1);
76+
strncpy(name, argv[1] + 2, len);
77+
name[len] = '\0';
78+
puts(name);
79+
YASL_declglobal(S, name);
80+
YASL_pushundef(S);
81+
YASL_setglobal(S, name);
82+
83+
YASL_ByteBuffer_extend(buffer, (unsigned char *)argv[1] + 2, strlen(argv[1]) - 2 );
84+
YASL_ByteBuffer_add_byte(buffer, '\n');
85+
YASL_resetstate_bb(S, (char *)buffer->items, buffer->count);
86+
buffer->count = 0;
87+
YASL_execute(S);
88+
89+
argc--;
90+
argv++;
91+
}
92+
93+
YASL_resetstate(S, argv[argc - 1]);
6194

6295
if (!S) {
6396
puts("ERROR: cannot open file.");
6497
exit(EXIT_FAILURE);
6598
}
6699

67-
// Load Standard Libraries
68-
YASLX_decllibs(S);
69-
70100
YASL_declglobal(S, "args");
71101
YASL_pushlist(S);
72102
for (int i = 1; i < argc; i++) {
@@ -78,6 +108,7 @@ static int main_file(int argc, char **argv) {
78108
int status = YASL_execute(S);
79109

80110
YASL_delstate(S);
111+
YASL_ByteBuffer_del(buffer);
81112

82113
return status;
83114
}
@@ -87,7 +118,7 @@ static int main_compile(int argc, char **argv) {
87118
struct YASL_State *S = YASL_newstate(argv[2]);
88119

89120
if (!S) {
90-
puts("ERROR: cannot open file.");
121+
fprintf(stderr, "Error: cannot open file.");
91122
exit(EXIT_FAILURE);
92123
}
93124

@@ -113,7 +144,7 @@ static int main_gen_bytecode(int argc, char **argv) {
113144
struct YASL_State *S = YASL_newstate(argv[2]);
114145

115146
if (!S) {
116-
puts("ERROR: cannot open file.");
147+
fprintf(stderr, "Error: cannot open file.");
117148
exit(EXIT_FAILURE);
118149
}
119150

@@ -213,14 +244,17 @@ int main(int argc, char **argv) {
213244
}
214245
#else
215246
int main(int argc, char **argv) {
247+
// These don't require any state, so just return immediately.
248+
if (argc == 2 && !strcmp(argv[1], "-h")) {
249+
return main_help(argc, argv);
250+
} else if (argc == 2 && !strcmp(argv[1], "-V")) {
251+
return main_version(argc, argv);
252+
}
253+
216254
main_init_platform();
217255

218256
if (argc == 1) {
219257
return main_REPL(argc, argv);
220-
} else if (argc == 2 && !strcmp(argv[1], "-h")) {
221-
return main_help(argc, argv);
222-
} else if (argc == 2 && !strcmp(argv[1], "-V")) {
223-
return main_version(argc, argv);
224258
} else if (argc == 3 && !strcmp(argv[1], "-e")) {
225259
return main_command_REPL(argc, argv);
226260
} else if (argc == 3 && !strcmp(argv[1], "-E")) {

opcode.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ enum Opcode {
2323
O_ASS = 0x50, // assert
2424
O_ASSERT_STACK_HEIGHT = 0x58,
2525

26-
2726
O_ADD = 0x60, // add two numbers
2827
O_SUB = 0x61, // subtract two numbers
2928
O_MUL = 0x62, // multiply two integers

test/errors/type/list/__lt.yasl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
echo [] < []
2+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TypeError: < not supported for operands of types list and list. (line 1)

test/inputs.inl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ static const char *inputs[] = {
129129
"test/inputs/match/alt/alt_nested_right.yasl",
130130
"test/inputs/match/alt/alt_nested_left.yasl",
131131
"test/inputs/match/alt/alt.yasl",
132+
"test/inputs/match/fallthrough.yasl",
132133
"test/inputs/match/basic_1.yasl",
133134
"test/inputs/match/bool.yasl",
134135
"test/inputs/match/list/const_vlist.yasl",

0 commit comments

Comments
 (0)