Skip to content

Commit

Permalink
Macros no longer execute at parse time.
Browse files Browse the repository at this point in the history
Like all other built-in expressions (except !) macros only execute
when the expression containing them executes. A macro definition
can be wrapped in !() to execute it immediately and make the new
syntax available for parsing further down in the file.

This is step 4 towards #14.
  • Loading branch information
jbearer committed Oct 11, 2021
1 parent b06a35e commit 775ec69
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 145 deletions.
1 change: 1 addition & 0 deletions core/include/internal/instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ typedef struct {
// instruction is the non-terminal symbol of the production.
typedef struct {
Instruction header;
SourceRange range;
// production: stack
// handler: stack
} MACRO;
Expand Down
8 changes: 5 additions & 3 deletions core/src/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ static inline Status Emit_SEND(
return Bytecode_Append(code, (Instruction *)&instr);
}

static inline Status Emit_MACRO(Bytecode *code, ResultType result_type)
static inline Status Emit_MACRO(
Bytecode *code, ResultType result_type, SourceRange range)
{
MACRO instr = {
{INSTR_MACRO, result_type, sizeof(instr)}
{INSTR_MACRO, result_type, sizeof(instr)},
range,
};

return Bytecode_Append(code, (Instruction *)&instr);
Expand Down Expand Up @@ -246,7 +248,7 @@ static Status CompileStmt(
blimp, stmt->macro.production, RESULT_USE, depth, code));
TRY(CompileExpr(
blimp, stmt->macro.handler, RESULT_USE, depth, code));
TRY(Emit_MACRO(code, result_type));
TRY(Emit_MACRO(code, result_type, stmt->range));
break;
default:
assert(false);
Expand Down
5 changes: 4 additions & 1 deletion core/src/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,8 @@ static Status ExecuteFrom(Blimp *blimp, const Instruction *ip, Object **result)
}

case INSTR_MACRO: {
MACRO *instr = (MACRO *)ip;

// Get the production and handler from the result stack. The
// handler is on top since it was evaluated second.
Object *handler = ObjectStack_Pop(blimp, &blimp->result_stack);
Expand All @@ -872,7 +874,8 @@ static Status ExecuteFrom(Blimp *blimp, const Instruction *ip, Object **result)
// the production.
const Symbol *nt;
if (DefineMacro(
blimp, production, handler, NULL, &nt) != BLIMP_OK)
blimp, production, handler, &instr->range, &nt)
!= BLIMP_OK)
{
BlimpObject_Release(production);
BlimpObject_Release(handler);
Expand Down
50 changes: 2 additions & 48 deletions core/src/grammar.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,6 @@ static Status ParseObject(Blimp *blimp, Object *obj, ParseTree *tree)
// Release `visitor` _after_ the call to Reparse() above, as the
// finalizer might destroy the `trees` vector.

assert(!tree->grammar_symbol.is_terminal);
assert(tree->grammar_symbol.non_terminal == nt);

return BLIMP_OK;
}

Expand Down Expand Up @@ -525,49 +522,6 @@ Status DefineMacro(
return BLIMP_OK;
}

// Handler for `\> Term Term Term`
static Status PrecedenceHandler(ParserContext *ctx, ParseTree *tree)
{
ParseTree *production_tree = SubTree(tree, 1);
ParseTree *handler_tree = SubTree(tree, 2);

// Convert the production and handler parse trees to expressions so we can
// evaluate them at parse time.
Expr *production, *handler;
TRY(BlimpParseTree_Eval(ctx->blimp, production_tree, &production));
if (BlimpParseTree_Eval(ctx->blimp, handler_tree, &handler) != BLIMP_OK) {
Blimp_FreeExpr(production);
return Reraise(ctx->blimp);
}

// Evaluate the production expression to get an Object which is a stream of
// symbols (the right-hand side of the production).
Object *production_obj;
TRY(Blimp_Eval(
ctx->blimp, production, (Object *)ctx->blimp->global, &production_obj));

// Evaluate the handler Object which will be attached to this macro, to run
// whenever it is reduced.
Object *handler_obj;
if (Blimp_Eval(
ctx->blimp,
handler,
(Object *)ctx->blimp->global,
&handler_obj
) != BLIMP_OK)
{
return Reraise(ctx->blimp);
}

const Symbol *nt_sym;
Status ret = DefineMacro(
ctx->blimp, production_obj, handler_obj, ctx->range, &nt_sym);

BlimpObject_Release(production_obj);
BlimpObject_Release(handler_obj);
return ret;
}

////////////////////////////////////////////////////////////////////////////////
// Default grammar
//
Expand Down Expand Up @@ -648,9 +602,9 @@ Status DefaultGrammar(Blimp *blimp, Grammar *grammar)
NULL, NULL));
// \> Stmt Custom
TRY(ADD_GRAMMAR_RULE(grammar, Stmt, (T(MACRO), NT(Stmt), NT(Custom)),
PrecedenceHandler, NULL));
NULL, NULL));
TRY(ADD_GRAMMAR_RULE(grammar, StmtNoMsg, (T(MACRO), NT(Stmt), NT(Custom)),
PrecedenceHandler, NULL));
NULL, NULL));
// \ Custom[NoMsg]
TRY(ADD_GRAMMAR_RULE(grammar, Stmt, (NT(Custom)),
NULL, NULL));
Expand Down
Loading

0 comments on commit 775ec69

Please sign in to comment.