Skip to content

Commit

Permalink
start making it postfix
Browse files Browse the repository at this point in the history
prefix by default is too confusing. better to provide syntax for things
that work better as prefix (eg if, while), and leave everything else
left-to-right. idk i've felt committed to the prefix thing for a while
but I can just feel the language fighting against it. now I get why
everything is postfix. HOWEVER the whole "condition [then] [else] if"
thing is awful, so I'm providing syntax to avoid stuff like that.
  • Loading branch information
cassowarii committed Jun 9, 2018
1 parent 5a80d3e commit 20d64e8
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 51 deletions.
3 changes: 1 addition & 2 deletions lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,7 @@ IDONECH [^{}[\]()\"\' \t\n,;]|{UONLY}
: |
; |
, |
# |
\| return yytext[0];
# return yytext[0];

\r|\n {
return '\n';
Expand Down
16 changes: 8 additions & 8 deletions lib_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
* below B and C, take the top element, and run
* B if truthy, C if falsy. (integerwise.) */
void lib_if(AStack *stack, AVarBuffer *buffer) {
AValue *ifpart = stack_get(stack, 0);
AValue *ifpart = stack_get(stack, 2);
AValue *thenpart = stack_get(stack, 1);
AValue *elsepart = stack_get(stack, 2);
AValue *elsepart = stack_get(stack, 0);
stack_pop(stack, 3);

eval_block(stack, buffer, ifpart);
Expand All @@ -31,9 +31,9 @@ void lib_if(AStack *stack, AVarBuffer *buffer) {
* B if truthy, C if falsy. But put the top element
* of the stack back before running B or C. */
void lib_ifstar(AStack *stack, AVarBuffer *buffer) {
AValue *ifpart = stack_get(stack, 0);
AValue *ifpart = stack_get(stack, 2);
AValue *thenpart = stack_get(stack, 1);
AValue *elsepart = stack_get(stack, 2);
AValue *elsepart = stack_get(stack, 0);
AValue *top = stack_get(stack, 3);

/* don't pop off 'top' */
Expand Down Expand Up @@ -62,8 +62,8 @@ void lib_ifstar(AStack *stack, AVarBuffer *buffer) {
* the stack below B and apply B over and over
* again until applying A gives a falsy value. */
void lib_while (AStack *stack, AVarBuffer *buffer) {
AValue *condpart = stack_get(stack, 0);
AValue *looppart = stack_get(stack, 1);
AValue *condpart = stack_get(stack, 1);
AValue *looppart = stack_get(stack, 0);
stack_pop(stack, 2);

eval_block(stack, buffer, condpart);
Expand Down Expand Up @@ -94,8 +94,8 @@ void lib_while (AStack *stack, AVarBuffer *buffer) {
* But keep the top value on the stack after
* applying A each time. */
void lib_whilestar(AStack *stack, AVarBuffer *buffer) {
AValue *condpart = stack_get(stack, 0);
AValue *looppart = stack_get(stack, 1);
AValue *condpart = stack_get(stack, 1);
AValue *looppart = stack_get(stack, 0);
AValue *top = stack_get(stack, 2);

stack_pop(stack, 2);
Expand Down
111 changes: 70 additions & 41 deletions parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,9 +415,9 @@ ANameSeqNode *parse_nameseq_opt(AParseState *state) {
return result;
}

/* Parse either a '|' or a newline. Doesn't matter which. */
/* Parse either a ';' or a newline. Doesn't matter which. */
int parse_separator(AParseState *state) {
if (ACCEPT('|')) {
if (ACCEPT(';')) {
return 1;
} else if (ACCEPT('\n')) {
return 1;
Expand Down Expand Up @@ -661,50 +661,79 @@ AAstNode *parse_word(AParseState *state) {
* - a binding:
* - an arrow, a list of names, a cmplx_word.
* Thus we can write something like:
* 5 6 -> a b (+ a b)
* 5 6 -> a b (a b +)
* and this counts as a 'full' wordline. */
AWordSeqNode *parse_wordline(AParseState *state) {
AWordSeqNode *result = ast_wordseq_new();

/* If there's no words before the binding arrow,
* we'll never enter this loop in the first place
* -- perfect! */
AAstNode *word = parse_word(state);
while (1) {
/* Represents everything between the last colon we've
* seen and the next colon (or end line or whatever.) */
AWordSeqNode *section = ast_wordseq_new();

while (word != &nonword) {
if (word == NULL) {
free_wordseq_node(result);
return NULL;
}
/* If there's no words before the binding arrow,
* we'll never enter this loop in the first place
* -- perfect! */
AAstNode *word = parse_word(state);

if (word->type == paren_node) {
/* Unwrap the paren node, and put the stuff
* we've done before AFTER it. */
AWordSeqNode *newresult = word->data.inside;
ast_wordseq_concat(newresult, result);
/* Essentially the inside of the paren-node
* becomes the new main sequence. */
free(result);
free(word);
result = newresult;
} else {
ast_wordseq_prepend(result, word);
}
while (word != &nonword) {
if (word == NULL) {
free_wordseq_node(result);
free_wordseq_node(section);
return NULL;
}

word = parse_word(state);
}
if (word->type == paren_node) {
/* Unwrap the paren node, and put the stuff
* we've done before AFTER it. */
AWordSeqNode *newresult = word->data.inside;
ast_wordseq_concat(section, newresult);
/* Essentially the inside of the paren-node
* becomes the new main sequence. */
free(section);
free(word);
section = newresult;
} else {
ast_wordseq_append(section, word);
}

/* If we found a bind arrow, then the optional
* second part must be here. */
if (ACCEPT(T_BIND)) {
unsigned int bindline = LINENUM;
ANameSeqNode *names = parse_nameseq_opt(state);
word = parse_word(state);
}

AAstNode *node = parse_cmplx_word(state);
if (node != NULL) {
AWordSeqNode *innerbind = unwrap_node(node);
AAstNode *bind = ast_bindnode(bindline, names, innerbind);
ast_wordseq_append(result, bind);
/* If we found a bind arrow, then the optional
* second part must be here. */
if (ACCEPT(T_BIND)) {
unsigned int bindline = LINENUM;
ANameSeqNode *names = parse_nameseq_opt(state);

AAstNode *node = parse_cmplx_word(state);
if (node != NULL) {
AWordSeqNode *innerbind = unwrap_node(node);
AAstNode *bind = ast_bindnode(bindline, names, innerbind);
ast_wordseq_append(result, bind);
}
/* Now that must be the end of the line... I guess? */
/* TODO we don't need a special case here anymore actually.
* Please move the bind-arrow-parsing code into parse_cmplx_word
* instead, and add the bind-arrow to complex_word_leadin.
* Then we can just chain them together now since we go left-to-right */
break;
} else if (ACCEPT(':')) {
/* Everything we've done so far is to be done AFTER the stuff we find next.
* So we put these at the beginning of the overall sequence. */
/* TODO this is inefficient, fix up later */
ast_wordseq_concat(section, result);
free(result);
result = section;
section = ast_wordseq_new();
} else {
/* We probably hit a new line. Stick what we've got at the beginning and
* call it a day. */
ast_wordseq_concat(section, result);
free(result);
result = section;
section = ast_wordseq_new();
break;
}
}

Expand All @@ -715,7 +744,7 @@ AWordSeqNode *parse_wordline(AParseState *state) {
* This is what makes up the elements of lists,
* the inside of blocks, etc.
* A series of 'word-lines' separated by newlines
* or pipe characters ('|'). */
* or semicolons. */
AWordSeqNode *parse_words(AParseState *state) {
AWordSeqNode *result = ast_wordseq_new();

Expand Down Expand Up @@ -748,7 +777,7 @@ AWordSeqNode *parse_interactive_words(AParseState *state) {
}
ast_wordseq_concat(result, line);
free(line);
} while (ACCEPT('|'));
} while (ACCEPT(';'));

if (!EXPECT('\n')) {
PANIC('\n');
Expand Down Expand Up @@ -1013,8 +1042,8 @@ void interact(ASymbolTable *symtab) {
NULL, /* current interactive string */
0, /* chars left to read from string */
0, /* current index into string */
"> ", /* Prompt #1 */
"? ", /* Prompt #2 */
"alma> ", /* Prompt #1 */
"... > ", /* Prompt #2 */
0, /* Nested let..in */
0, /* Nested function decls */
0, /* Nested comments */
Expand Down

0 comments on commit 20d64e8

Please sign in to comment.