1899 lines
55 KiB
C
1899 lines
55 KiB
C
|
////////////////////////////////
|
||
|
// NOTE(allen): Cells
|
||
|
|
||
|
internal C_CellMemory
|
||
|
C_InitCellMemory(void){
|
||
|
C_CellMemory memory = {0};
|
||
|
memory.arena = M_ArenaInitializeWithAlign(1);
|
||
|
memory.cells = PushArray(&memory.arena, C_Cell, C_BLOCK_CAP);
|
||
|
{
|
||
|
C_Cell *block = memory.cells;
|
||
|
block->kind = C_CellKind_BlockHeader;
|
||
|
SLLStackPush(memory.free_block, block);
|
||
|
}
|
||
|
return(memory);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
_C_AllocateBlock(C_CellMemory *memory){
|
||
|
C_Cell *result = memory->free_block;
|
||
|
if (result != 0){
|
||
|
SLLStackPop(memory->free_block);
|
||
|
}
|
||
|
else{
|
||
|
result = PushArray(&memory->arena, C_Cell, C_BLOCK_CAP);
|
||
|
result->kind = C_CellKind_BlockHeader;
|
||
|
}
|
||
|
Assert((result - memory->cells)%C_BLOCK_CAP == 0);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
_C_FreeBlock(C_CellMemory *memory, C_Cell *block){
|
||
|
Assert((block - memory->cells)%C_BLOCK_CAP == 0);
|
||
|
Assert(block->kind == C_CellKind_BlockHeader);
|
||
|
SLLStackPush(memory->free_block, block);
|
||
|
}
|
||
|
|
||
|
internal C_CellBucket
|
||
|
C_InitCellBucket(C_CellMemory *memory){
|
||
|
C_CellBucket bucket = {memory};
|
||
|
bucket.first_block = bucket.last_block = 0;
|
||
|
return(bucket);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_AllocateCell(C_CellBucket *bucket){
|
||
|
C_Cell *result = 0;
|
||
|
if (bucket->last_block != 0 && bucket->cursor < C_BLOCK_CAP){
|
||
|
result = bucket->last_block + bucket->cursor;
|
||
|
bucket->cursor += 1;
|
||
|
}
|
||
|
else{
|
||
|
C_Cell *new_block = _C_AllocateBlock(bucket->memory);
|
||
|
SLLQueuePush(bucket->first_block, bucket->last_block, new_block);
|
||
|
new_block->bucket = bucket;
|
||
|
result = new_block + 1;
|
||
|
bucket->cursor = 2;
|
||
|
}
|
||
|
MemoryZeroStruct(result);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
C_ClearBucket(C_CellBucket *bucket){
|
||
|
for (C_Cell *block = bucket->first_block, *next = 0;
|
||
|
block != 0;
|
||
|
block = next){
|
||
|
next = block->next;
|
||
|
_C_FreeBlock(bucket->memory, block);
|
||
|
}
|
||
|
bucket->first_block = bucket->last_block = 0;
|
||
|
bucket->cursor = 0;
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
_C_BlockHeaderFromCell(C_CellMemory *memory, C_Cell *cell){
|
||
|
u64 indx = (cell - memory->cells);
|
||
|
u64 header_indx = indx - (indx%C_BLOCK_CAP);
|
||
|
return(memory->cells + header_indx);
|
||
|
}
|
||
|
|
||
|
internal C_CellBucket*
|
||
|
_C_BucketFromCell(C_CellMemory *memory, C_Cell *cell){
|
||
|
C_Cell *block = _C_BlockHeaderFromCell(memory, cell);
|
||
|
return(block->bucket);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////
|
||
|
// NOTE(allen): Cell Inits
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_GetNilCell(C_Statics *statics){
|
||
|
return(statics->Nil);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_GetBuiltIn(C_Statics *statics, C_BuiltInIndex index){
|
||
|
C_Cell *result = statics->Nil;
|
||
|
if (index < C_BuiltInIndex_COUNT){
|
||
|
result = statics->built_in[index];
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal String8
|
||
|
C_GetBuiltInKeyword(C_BuiltInIndex index){
|
||
|
String8 result = {0};
|
||
|
if (0 < index && index < C_BuiltInIndex_COUNT){
|
||
|
local_persist String8 keywords[] = {
|
||
|
#define DefineS8Lit(N,F) {N, sizeof(N) - 1},
|
||
|
C_BuiltInXList(DefineS8Lit)
|
||
|
#undef DefineS8Lit
|
||
|
};
|
||
|
result = keywords[index - 1];
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_NewCellPair(C_CellBucket *bucket, C_CellKind kind, C_Cell *left, C_Cell *right){
|
||
|
C_Cell *cell = C_AllocateCell(bucket);
|
||
|
cell->kind = kind;
|
||
|
cell->first_child = left;
|
||
|
cell->next = right;
|
||
|
cell->depth_counter = right->depth_counter;
|
||
|
AssertImplies(kind == C_CellKind_Constructed,
|
||
|
right->kind == C_CellKind_Constructed ||
|
||
|
right->kind == C_CellKind_Nil);
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
#define C_InitListBuilder(C) {(C), (&(C)), 0}
|
||
|
#define C_ListBuilderPush_(Bt,Br,C) \
|
||
|
Stmnt( C_Cell *m_ = *Br.u = C_AllocateCell(Bt); m_->kind = C_CellKind_Constructed; m_->first_child = C; Br.u = &m_->next; Br.c += 1; )
|
||
|
#define C_ListBuilderPush(Bt,Br,C) C_ListBuilderPush_((Bt),(Br),(C))
|
||
|
|
||
|
internal void
|
||
|
_C_ListBuilderTerminate(C_ListBuilder builder){
|
||
|
for (C_Cell *node = builder.f;
|
||
|
node != 0;
|
||
|
node = node->next){
|
||
|
node->depth_counter = builder.c;
|
||
|
builder.c -= 1;
|
||
|
}
|
||
|
}
|
||
|
#define C_ListBuilderTerminate(S,Br) \
|
||
|
Stmnt( (*(Br).u = C_GetNilCell(S)); _C_ListBuilderTerminate(Br); )
|
||
|
|
||
|
internal C_Cell*
|
||
|
_C_NewCellList(C_Statics *statics, C_CellBucket *bucket, ...){
|
||
|
va_list args;
|
||
|
va_start(args, bucket);
|
||
|
C_Cell *result = 0;
|
||
|
C_ListBuilder builder = C_InitListBuilder(result);
|
||
|
for (;;){
|
||
|
C_Cell *cell = va_arg(args, C_Cell*);
|
||
|
if (cell == 0){
|
||
|
break;
|
||
|
}
|
||
|
C_ListBuilderPush(bucket, builder, cell);
|
||
|
}
|
||
|
C_ListBuilderTerminate(statics, builder);
|
||
|
va_end(args);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
#define C_NewCellList(S,B,...) _C_NewCellList((S), (B), __VA_ARGS__, 0)
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_NewF64Cell(C_CellBucket *bucket, f64 f){
|
||
|
C_Cell *cell = C_AllocateCell(bucket);
|
||
|
cell->kind = C_CellKind_F64;
|
||
|
cell->f = f;
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_NewIdCell(C_CellBucket *bucket, C_Id id){
|
||
|
C_Cell *cell = C_AllocateCell(bucket);
|
||
|
cell->kind = C_CellKind_Id;
|
||
|
cell->id = id;
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_NewRegCell(C_CellBucket *bucket, C_Id id){
|
||
|
C_Cell *cell = C_AllocateCell(bucket);
|
||
|
cell->kind = C_CellKind_Register;
|
||
|
cell->id = id;
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_NewIdentifierCell(C_CellBucket *bucket, STR_Index string){
|
||
|
C_Cell *cell = C_AllocateCell(bucket);
|
||
|
cell->kind = C_CellKind_Identifier;
|
||
|
cell->identifier = string;
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_NewIdentifierCellLit(C_CellBucket *bucket, String8 string){
|
||
|
return(C_NewIdentifierCell(bucket, STR_Save(APP_GetStringHash(), string)));
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_NewCellFromLabel(C_Statics *statics, C_CellBucket *bucket, STR_Index string_indx){
|
||
|
C_Cell *cell = C_GetNilCell(statics);
|
||
|
|
||
|
String8 string = STR_Read(APP_GetStringHash(), string_indx);
|
||
|
if (string.size > 0){
|
||
|
if (CharIsDigit(string.str[0]) || string.str[0] == '.'){
|
||
|
f64 f = 0;
|
||
|
b32 error = 0;
|
||
|
u8 *ptr = string.str;
|
||
|
u64 i = 0;
|
||
|
for (; i < string.size; i += 1, ptr += 1){
|
||
|
if (*ptr == '.'){
|
||
|
i += 1;
|
||
|
ptr += 1;
|
||
|
break;
|
||
|
}
|
||
|
if (!CharIsDigit(*ptr)){
|
||
|
error = 1;
|
||
|
break;
|
||
|
}
|
||
|
f *= 10.;
|
||
|
u64 x = (*ptr - '0');
|
||
|
f += (f64)x;
|
||
|
}
|
||
|
f64 div = 1.;
|
||
|
f64 frac = 0.;
|
||
|
for (; i < string.size; i += 1, ptr += 1){
|
||
|
if (!CharIsDigit(*ptr)){
|
||
|
error = 1;
|
||
|
break;
|
||
|
}
|
||
|
frac *= 10.;
|
||
|
div *= 10.;
|
||
|
u64 x = (*ptr - '0');
|
||
|
frac += ((f64)x);
|
||
|
}
|
||
|
f += frac/div;
|
||
|
if (!error){
|
||
|
cell = C_NewF64Cell(bucket, f);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else if (string.str[0] == '#'){
|
||
|
C_Id id = 0;
|
||
|
b32 error = 0;
|
||
|
u8 *ptr = string.str + 1;
|
||
|
u64 i = 1;
|
||
|
for (; i < string.size; i += 1, ptr += 1){
|
||
|
if (!CharIsDigit(*ptr)){
|
||
|
error = 1;
|
||
|
break;
|
||
|
}
|
||
|
id *= 10;
|
||
|
u64 x = (*ptr - '0');
|
||
|
id += (C_Id)x;
|
||
|
}
|
||
|
if (!error){
|
||
|
cell = C_NewIdCell(bucket, id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else{
|
||
|
cell = C_NewIdentifierCell(bucket, string_indx);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_NewBuiltInCell(C_CellBucket *bucket, String8 name, C_BuiltInFunctionType *built_in){
|
||
|
C_Cell *cell = C_AllocateCell(bucket);
|
||
|
cell->kind = C_CellKind_BuiltIn;
|
||
|
cell->built_in = built_in;
|
||
|
cell->identifier = STR_Save(APP_GetStringHash(), name);
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_ExtendEnvironment(C_CellBucket *bucket, u64 x, C_Cell *body, C_Cell *env){
|
||
|
Assert(x != 0 && body != 0 && env != 0);
|
||
|
C_Cell *result = C_NewCellPair(bucket, C_CellKind_Environment, body, env);
|
||
|
result->x = x;
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_ExtendEnvironmentLiteral(C_CellBucket *bucket, String8 key, C_Cell *body, C_Cell *env){
|
||
|
C_Cell *result = C_ExtendEnvironment(bucket, STR_Save(APP_GetStringHash(), key), body, env);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_NewVerbCell(C_CellBucket *bucket, C_CellKind kind, C_Cell *params, C_Cell *body, C_Cell *env){
|
||
|
C_Cell *result = 0;
|
||
|
if (params->kind == C_CellKind_Constructed ||
|
||
|
params->kind == C_CellKind_Nil){
|
||
|
b32 valid = 1;
|
||
|
for (C_Cell *node = params;
|
||
|
!C_IsNil(node);
|
||
|
node = node->next){
|
||
|
if (node->first_child->kind != C_CellKind_Identifier){
|
||
|
valid = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (valid){
|
||
|
result = C_AllocateCell(bucket);
|
||
|
result->kind = kind;
|
||
|
result->first_child = params;
|
||
|
result->next = body;
|
||
|
result->env = env;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_NewVerbCellV(C_CellBucket *bucket, C_CellKind kind, C_Cell *params, C_Cell *body, C_Cell *env){
|
||
|
C_Cell *result = 0;
|
||
|
if (params->kind == C_CellKind_Identifier){
|
||
|
result = C_AllocateCell(bucket);
|
||
|
result->kind = kind;
|
||
|
result->first_child = params;
|
||
|
result->next = body;
|
||
|
result->env = env;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_NewDeferredCell(C_CellBucket *bucket, C_Deferred *deferred, C_Cell *cell){
|
||
|
C_Cell *result = C_AllocateCell(bucket);
|
||
|
result->kind = C_CellKind_Deferred;
|
||
|
result->first_child = cell;
|
||
|
result->deferred = deferred;
|
||
|
deferred->cell = cell;
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_NewSpaceCell(C_CellBucket *bucket, void *space_ptr){
|
||
|
C_Cell *cell = C_AllocateCell(bucket);
|
||
|
cell->kind = C_CellKind_Space;
|
||
|
cell->space = space_ptr;
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////
|
||
|
// NOTE(allen): Parser
|
||
|
|
||
|
internal void
|
||
|
_C_ParseSkip(C_ParseCtx *ctx){
|
||
|
C_Token *token = ctx->token;
|
||
|
C_Token *opl = ctx->opl;
|
||
|
for (;token < opl; token += 1){
|
||
|
if (C_TokenKind_FIRST_HARD <= token->kind && token->kind <= C_TokenKind_LAST_HARD){
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
ctx->token = token;
|
||
|
}
|
||
|
|
||
|
internal C_ParseCtx
|
||
|
_C_InitParseCtx(C_Statics *statics, C_CellBucket *bucket, C_Token *tokens, u64 count, C_ParseError *error_buffer, u64 error_count){
|
||
|
C_ParseCtx ctx = {0};
|
||
|
ctx.statics = statics;
|
||
|
ctx.bucket = bucket;
|
||
|
ctx.token = tokens;
|
||
|
ctx.opl = tokens + count;
|
||
|
ctx.error_max = error_count;
|
||
|
ctx.errors = error_buffer;
|
||
|
_C_ParseSkip(&ctx);
|
||
|
return(ctx);
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
_C_ParseError(C_ParseCtx *ctx, String8 message, C_Token *token){
|
||
|
if (ctx->error_count < ctx->error_max){
|
||
|
C_ParseError *new_error = ctx->errors + ctx->error_count;
|
||
|
ctx->error_count += 1;
|
||
|
new_error->message = message;
|
||
|
new_error->token = token;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
internal b32
|
||
|
_C_ParseEOF(C_ParseCtx *ctx){
|
||
|
b32 result = (ctx->token >= ctx->opl);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal b32
|
||
|
_C_ParsePeekToken(C_ParseCtx *ctx, C_Token **token_ptr){
|
||
|
b32 result = 0;
|
||
|
if (ctx->token < ctx->opl){
|
||
|
*token_ptr = ctx->token;
|
||
|
result = 1;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal b32
|
||
|
_C_ParseMatch(C_ParseCtx *ctx, C_TokenKind kind, C_Token **token_ptr){
|
||
|
b32 result = 0;
|
||
|
if (ctx->token < ctx->opl && ctx->token->kind == kind){
|
||
|
*token_ptr = ctx->token;
|
||
|
ctx->token += 1;
|
||
|
_C_ParseSkip(ctx);
|
||
|
result = 1;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell* _C_ParseExpr(C_ParseCtx *ctx);
|
||
|
|
||
|
internal C_Cell*
|
||
|
_C_ParseExpr(C_ParseCtx *ctx){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Token *token = 0;
|
||
|
|
||
|
// NOTE(allen): Any label starts an expression
|
||
|
if (_C_ParseMatch(ctx, C_TokenKind_Label, &token)){
|
||
|
result = C_NewCellFromLabel(ctx->statics, ctx->bucket, token->string);
|
||
|
}
|
||
|
|
||
|
// NOTE(allen): ' starts an expression
|
||
|
else if (_C_ParseMatch(ctx, C_TokenKind_Quote, &token)){
|
||
|
C_ListBuilder builder = C_InitListBuilder(result);
|
||
|
C_Cell *quote = C_GetBuiltIn(ctx->statics, C_BuiltInIndex_Quote);
|
||
|
C_ListBuilderPush(ctx->bucket, builder, quote);
|
||
|
C_ListBuilderPush(ctx->bucket, builder, _C_ParseExpr(ctx));
|
||
|
C_ListBuilderTerminate(ctx->statics, builder);
|
||
|
}
|
||
|
|
||
|
// NOTE(allen): An open paren starts an expression
|
||
|
else if (_C_ParseMatch(ctx, C_TokenKind_OpenParen, &token)){
|
||
|
C_ListBuilder builder = C_InitListBuilder(result);
|
||
|
for (;;){
|
||
|
C_Token *ignore = 0;
|
||
|
if (_C_ParseMatch(ctx, C_TokenKind_CloseParen, &ignore)){
|
||
|
break;
|
||
|
}
|
||
|
if (_C_ParseEOF(ctx)){
|
||
|
_C_ParseError(ctx, S8Lit("Unclosed parentheses"), token);
|
||
|
break;
|
||
|
}
|
||
|
C_ListBuilderPush(ctx->bucket, builder, _C_ParseExpr(ctx));
|
||
|
}
|
||
|
C_ListBuilderTerminate(ctx->statics, builder);
|
||
|
}
|
||
|
|
||
|
// NOTE(allen): No other valid ways to start an expression
|
||
|
else{
|
||
|
if (_C_ParsePeekToken(ctx, &token)){
|
||
|
_C_ParseError(ctx, S8Lit("Unexpected token"), token);
|
||
|
}
|
||
|
if (_C_ParseEOF(ctx)){
|
||
|
_C_ParseError(ctx, S8Lit("Unexpected end of file"), 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_Parse(C_Statics *statics, C_CellBucket *bucket, C_Token *tokens, u64 count,
|
||
|
C_ParseError *error_buffer, u64 error_count, u64 *error_count_out){
|
||
|
C_ParseCtx ctx = _C_InitParseCtx(statics, bucket, tokens, count, error_buffer, error_count);
|
||
|
C_Cell *result = _C_ParseExpr(&ctx);
|
||
|
*error_count_out = ctx.error_count;
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////
|
||
|
// NOTE(allen): Evaluation
|
||
|
|
||
|
internal C_EvalCtx
|
||
|
C_InitEvalCtx(C_Statics *statics, C_CellBucket *bucket, C_Cell *id_env){
|
||
|
C_EvalCtx ctx = {0};
|
||
|
ctx.statics = statics;
|
||
|
ctx.bucket = bucket;
|
||
|
ctx.id_env = id_env;
|
||
|
ctx.regs = C_GetNilCell(statics);
|
||
|
ctx.max_depth = 100;
|
||
|
ctx.loop_lim = Thousand(1);
|
||
|
ctx.reg_id_counter = 1;
|
||
|
return(ctx);
|
||
|
}
|
||
|
|
||
|
#define DeclBuiltIn(N,F) internal C_BUILT_IN_SIG(C_BuiltIn_##F);
|
||
|
C_BuiltInXList(DeclBuiltIn);
|
||
|
#undef DeclBuiltIn
|
||
|
|
||
|
internal C_Cell* C_Evaluate(C_EvalCtx *ctx, C_Cell *cell, C_Cell **env);
|
||
|
|
||
|
internal b32
|
||
|
C_IsNil(C_Cell *cell){
|
||
|
return(cell == 0 || cell->kind == C_CellKind_Nil || cell->kind >= C_CellKind_BlockHeader);
|
||
|
}
|
||
|
|
||
|
internal b32
|
||
|
C_IsF64(C_Cell *cell){
|
||
|
return(cell != 0 && cell->kind == C_CellKind_F64);
|
||
|
}
|
||
|
|
||
|
internal b32
|
||
|
C_IsTruthy(C_Cell *cell){
|
||
|
b32 result = 0;
|
||
|
if (!C_IsNil(cell)){
|
||
|
if (cell->kind != C_CellKind_F64 || cell->f != 0.){
|
||
|
result = 1;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal STR_Index
|
||
|
C_GetIdentifierFromCell(C_Cell *cell){
|
||
|
STR_Index result = 0;
|
||
|
if (cell != 0 && cell->kind == C_CellKind_Identifier){
|
||
|
result = cell->identifier;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Id
|
||
|
C_GetIdFromCell(C_Cell *cell){
|
||
|
C_Id result = 0;
|
||
|
if (cell != 0 && cell->kind == C_CellKind_Id){
|
||
|
result = cell->id;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal u64
|
||
|
C_ListCount(C_Cell *cell){
|
||
|
u64 count = 0;
|
||
|
for (C_Cell *node = cell;
|
||
|
!C_IsNil(node);
|
||
|
node = node->next){
|
||
|
count += 1;
|
||
|
}
|
||
|
return(count);
|
||
|
}
|
||
|
|
||
|
internal b32
|
||
|
C_CellEquality(C_Cell *a, C_Cell *b){
|
||
|
b32 result = 0;
|
||
|
b32 an = C_IsNil(a);
|
||
|
b32 bn = C_IsNil(b);
|
||
|
if (an || bn){
|
||
|
if (an && bn){
|
||
|
result = 1;
|
||
|
}
|
||
|
}
|
||
|
else if (a->kind == b->kind){
|
||
|
switch (a->kind){
|
||
|
default:
|
||
|
{
|
||
|
result = 1;
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Constructed:
|
||
|
{
|
||
|
result = (C_CellEquality(a->first_child, b->first_child) && C_CellEquality(a->next, b->next));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_F64:
|
||
|
case C_CellKind_Identifier:
|
||
|
case C_CellKind_Id:
|
||
|
case C_CellKind_Register:
|
||
|
case C_CellKind_BuiltIn:
|
||
|
{
|
||
|
result = (a->x == b->x);
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Function:
|
||
|
case C_CellKind_FunctionV:
|
||
|
case C_CellKind_Macro:
|
||
|
case C_CellKind_MacroV:
|
||
|
{
|
||
|
result = (a->first_child == b->first_child && a->next == b->next && C_CellEquality(a->env, b->env));
|
||
|
}break;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_EnvironmentResolve(C_Statics *statics, C_Cell *env, u64 lookup_key){
|
||
|
C_Cell *result = C_GetNilCell(statics);
|
||
|
|
||
|
for (;!C_IsNil(env) && env->kind == C_CellKind_Environment;
|
||
|
env = env->next){
|
||
|
u64 key = env->x;
|
||
|
C_Cell *val = env->first_child;
|
||
|
if (key == 0 || val == 0){
|
||
|
break;
|
||
|
}
|
||
|
if (key == lookup_key){
|
||
|
result = val;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_Apply(C_EvalCtx *ctx, C_Cell *verb, C_Cell *args, C_Cell **env){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
|
||
|
Assert(verb != 0 && args != 0 && *env != 0);
|
||
|
|
||
|
if (ctx->depth < ctx->max_depth){
|
||
|
ctx->depth += 1;
|
||
|
|
||
|
switch (verb->kind){
|
||
|
default: break;
|
||
|
|
||
|
case C_CellKind_BuiltIn:
|
||
|
{
|
||
|
result = verb->built_in(ctx, args, env);
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Function:
|
||
|
{
|
||
|
// NOTE(allen): Step 1: check that arguments match parameters
|
||
|
C_Cell *params = verb->first_child;
|
||
|
u64 args_count = C_ListCount(args);
|
||
|
u64 param_count = C_ListCount(verb->first_child);
|
||
|
if (args_count == param_count){
|
||
|
|
||
|
// NOTE(allen): Step 2: evaluate and record each argument
|
||
|
C_Cell *old_env = verb->env;
|
||
|
C_Cell *new_env = old_env;
|
||
|
for (C_Cell *arg_node = args, *param_node = params;
|
||
|
!C_IsNil(arg_node) && !C_IsNil(params);
|
||
|
arg_node = arg_node->next, param_node = param_node->next){
|
||
|
C_Cell *evaluated = C_Evaluate(ctx, arg_node->first_child, env);
|
||
|
STR_Index name = C_GetIdentifierFromCell(param_node->first_child);
|
||
|
new_env = C_ExtendEnvironment(ctx->bucket, name, evaluated, new_env);
|
||
|
}
|
||
|
|
||
|
// NOTE(allen): Step 3: evaluate the body expression and return the result
|
||
|
result = C_Evaluate(ctx, verb->next, &new_env);
|
||
|
}
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_FunctionV:
|
||
|
{
|
||
|
// NOTE(allen): Step 1: evaluate and list each argument
|
||
|
C_Cell *params = 0;
|
||
|
C_ListBuilder builder = C_InitListBuilder(params);
|
||
|
for (C_Cell *arg_node = args;
|
||
|
!C_IsNil(arg_node);
|
||
|
arg_node = arg_node->next){
|
||
|
C_Cell *evaluated = C_Evaluate(ctx, arg_node->first_child, env);
|
||
|
C_ListBuilderPush(ctx->bucket, builder, evaluated);
|
||
|
}
|
||
|
C_ListBuilderTerminate(ctx->statics, builder);
|
||
|
|
||
|
// NOTE(allen): Step 2: record the argument list
|
||
|
STR_Index name = C_GetIdentifierFromCell(verb->first_child);
|
||
|
C_Cell *new_env = C_ExtendEnvironment(ctx->bucket, name, params, verb->env);
|
||
|
|
||
|
// NOTE(allen): Step 3: evaluate the body expression and return the result
|
||
|
result = C_Evaluate(ctx, verb->next, &new_env);
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Macro:
|
||
|
{
|
||
|
// NOTE(allen): Step 1: check that arguments match parameters
|
||
|
C_Cell *params = verb->first_child;
|
||
|
u64 args_count = C_ListCount(args);
|
||
|
u64 param_count = C_ListCount(verb->first_child);
|
||
|
if (args_count == param_count){
|
||
|
|
||
|
// NOTE(allen): Step 2: record each argument
|
||
|
C_Cell *old_env = verb->env;
|
||
|
C_Cell *new_env = old_env;
|
||
|
for (C_Cell *arg_node = args, *param_node = params;
|
||
|
!C_IsNil(arg_node) && !C_IsNil(params);
|
||
|
arg_node = arg_node->next, param_node = param_node->next){
|
||
|
STR_Index name = C_GetIdentifierFromCell(param_node->first_child);
|
||
|
new_env = C_ExtendEnvironment(ctx->bucket, name, arg_node->first_child, new_env);
|
||
|
}
|
||
|
|
||
|
// NOTE(allen): Step 3: evaluate the body expression and return the result
|
||
|
C_Cell *macro_eval = C_Evaluate(ctx, verb->next, &new_env);
|
||
|
|
||
|
// NOTE(allen): Step 4: evaluate in the calling context
|
||
|
result = C_Evaluate(ctx, macro_eval, env);
|
||
|
}
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_MacroV:
|
||
|
{
|
||
|
// NOTE(allen): Step 1: list each argument
|
||
|
C_Cell *params = 0;
|
||
|
C_ListBuilder builder = C_InitListBuilder(params);
|
||
|
for (C_Cell *arg_node = args;
|
||
|
!C_IsNil(arg_node);
|
||
|
arg_node = arg_node->next){
|
||
|
C_ListBuilderPush(ctx->bucket, builder, arg_node->first_child);
|
||
|
}
|
||
|
C_ListBuilderTerminate(ctx->statics, builder);
|
||
|
|
||
|
// NOTE(allen): Step 2: record the argument list
|
||
|
STR_Index name = C_GetIdentifierFromCell(verb->first_child);
|
||
|
C_Cell *new_env = C_ExtendEnvironment(ctx->bucket, name, params, verb->env);
|
||
|
|
||
|
// NOTE(allen): Step 3: evaluate the body expression and return the result
|
||
|
C_Cell *macro_eval = C_Evaluate(ctx, verb->next, &new_env);
|
||
|
|
||
|
// NOTE(allen): Step 4: evaluate in the calling context
|
||
|
result = C_Evaluate(ctx, macro_eval, env);
|
||
|
}break;
|
||
|
}
|
||
|
|
||
|
ctx->depth -= 1;
|
||
|
}
|
||
|
|
||
|
Assert(result != 0);
|
||
|
Assert(result->kind < C_CellKind_BlockHeader);
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_EvaluateDeferred(C_EvalCtx *ctx, C_Deferred *deferred, C_Cell **env){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
if (!deferred->doing_eval){
|
||
|
if (!deferred->finished_eval){
|
||
|
deferred->doing_eval = 1;
|
||
|
C_Cell *defer_env = deferred->env;
|
||
|
deferred->cell = C_Evaluate(ctx, deferred->cell, &defer_env);
|
||
|
Assert(deferred->cell->kind != C_CellKind_Deferred);
|
||
|
deferred->doing_eval = 0;
|
||
|
}
|
||
|
deferred->finished_eval = 1;
|
||
|
result = deferred->cell;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_Evaluate(C_EvalCtx *ctx, C_Cell *cell, C_Cell **env){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
|
||
|
if (cell != 0 && env != 0 && *env != 0){
|
||
|
switch (cell->kind){
|
||
|
default: break;
|
||
|
|
||
|
case C_CellKind_Constructed:
|
||
|
{
|
||
|
C_Cell *verb = C_Evaluate(ctx, cell->first_child, env);
|
||
|
result = C_Apply(ctx, verb, cell->next, env);
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_F64:
|
||
|
case C_CellKind_BuiltIn:
|
||
|
case C_CellKind_Function:
|
||
|
case C_CellKind_Macro:
|
||
|
case C_CellKind_FunctionV:
|
||
|
case C_CellKind_MacroV:
|
||
|
case C_CellKind_Deferred:
|
||
|
case C_CellKind_Space:
|
||
|
case C_CellKind_Register:
|
||
|
{
|
||
|
result = cell;
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Identifier:
|
||
|
{
|
||
|
result = C_EnvironmentResolve(ctx->statics, *env, C_GetIdentifierFromCell(cell));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Id:
|
||
|
{
|
||
|
result = C_EnvironmentResolve(ctx->statics, ctx->id_env, cell->id);
|
||
|
}break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (result->kind == C_CellKind_Deferred){
|
||
|
result = C_EvaluateDeferred(ctx, result->deferred, env);
|
||
|
}
|
||
|
|
||
|
Assert(result != 0);
|
||
|
Assert(result->kind < C_CellKind_BlockHeader);
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
C_EvaluateArray(C_EvalCtx *ctx, C_Cell **cell, u64 count, C_Cell **env){
|
||
|
for (u64 i = 0; i < count; i += 1){
|
||
|
cell[i] = C_Evaluate(ctx, cell[i], env);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////
|
||
|
// NOTE(allen): Built Ins
|
||
|
|
||
|
typedef struct C_NumComp C_NumComp;
|
||
|
struct C_NumComp{
|
||
|
b32 valid;
|
||
|
f64 f;
|
||
|
};
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_GetCellFromNumComp(C_EvalCtx *ctx, C_NumComp *comp){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
if (comp->valid){
|
||
|
result = C_NewF64Cell(ctx->bucket, comp->f);
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal C_Cell*
|
||
|
C_GetCellFromBoolean(C_EvalCtx *ctx, b32 b){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
if (b){
|
||
|
result = C_NewF64Cell(ctx->bucket, 1.f);
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal b32
|
||
|
C_TakeFixedArguments(C_Cell *cell, C_Cell **out, u64 count){
|
||
|
b32 result = 1;
|
||
|
for (u64 i = 0; i < count; i += 1){
|
||
|
if (cell == 0 || cell->kind != C_CellKind_Constructed ||
|
||
|
cell->first_child == 0){
|
||
|
result = 0;
|
||
|
break;
|
||
|
}
|
||
|
out[i] = cell->first_child;
|
||
|
cell = cell->next;
|
||
|
}
|
||
|
if (!C_IsNil(cell)){
|
||
|
result = 0;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Function){
|
||
|
C_Cell *result = 0;
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
args[0] = C_Evaluate(ctx, args[0], env);
|
||
|
result = C_NewVerbCell(ctx->bucket, C_CellKind_Function, args[0], args[1], *env);
|
||
|
}
|
||
|
if (result == 0){
|
||
|
result = C_GetNilCell(ctx->statics);
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_FunctionV){
|
||
|
C_Cell *result = 0;
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
args[0] = C_Evaluate(ctx, args[0], env);
|
||
|
result = C_NewVerbCellV(ctx->bucket, C_CellKind_FunctionV, args[0], args[1], *env);
|
||
|
}
|
||
|
if (result == 0){
|
||
|
result = C_GetNilCell(ctx->statics);
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Macro){
|
||
|
C_Cell *result = 0;
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
args[0] = C_Evaluate(ctx, args[0], env);
|
||
|
result = C_NewVerbCell(ctx->bucket, C_CellKind_Macro, args[0], args[1], *env);
|
||
|
}
|
||
|
if (result == 0){
|
||
|
result = C_GetNilCell(ctx->statics);
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_MacroV){
|
||
|
C_Cell *result = 0;
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
args[0] = C_Evaluate(ctx, args[0], env);
|
||
|
result = C_NewVerbCellV(ctx->bucket, C_CellKind_MacroV, args[0], args[1], *env);
|
||
|
}
|
||
|
if (result == 0){
|
||
|
result = C_GetNilCell(ctx->statics);
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_WriteRegister){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_Register){
|
||
|
result = args[1];
|
||
|
ctx->regs = C_ExtendEnvironment(ctx->bucket, args[0]->id, args[1], ctx->regs);
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_ReadRegister){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[1];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_Register){
|
||
|
result = C_EnvironmentResolve(ctx->statics, ctx->regs, args[0]->id);
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_GetUniqueRegister){
|
||
|
C_Cell *result = C_NewRegCell(ctx->bucket, ctx->reg_id_counter);
|
||
|
ctx->reg_id_counter += 1;
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Block){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *local_env = *env;
|
||
|
for (C_Cell *node = cell;
|
||
|
!C_IsNil(node);
|
||
|
node = node->next){
|
||
|
result = C_Evaluate(ctx, node->first_child, &local_env);
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Quote){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[1];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
result = args[0];
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_First){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[1];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_Constructed){
|
||
|
result = args[0]->first_child;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Next){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[1];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_Constructed){
|
||
|
result = args[0]->next;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Push){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
M_Arena *scratch = OS_GetScratch();
|
||
|
C_Cell **push_cells = PushArray(scratch, C_Cell*, 0);
|
||
|
for (C_Cell *node = cell;
|
||
|
!C_IsNil(node);
|
||
|
node = node->next){
|
||
|
C_Cell **cell_ptr = PushArray(scratch, C_Cell*, 1);
|
||
|
*cell_ptr = C_Evaluate(ctx, node->first_child, env);
|
||
|
}
|
||
|
C_Cell **opl = PushArray(scratch, C_Cell*, 0);
|
||
|
u64 count = (opl - push_cells);
|
||
|
if (count > 0){
|
||
|
result = opl[-1];
|
||
|
if (result->kind == C_CellKind_Nil ||
|
||
|
result->kind == C_CellKind_Constructed){
|
||
|
for (C_Cell **cell_ptr = opl - 2;
|
||
|
cell_ptr >= push_cells;
|
||
|
cell_ptr -= 1){
|
||
|
result = C_NewCellPair(ctx->bucket, C_CellKind_Constructed, *cell_ptr, result);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
OS_ReleaseScratch(scratch);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_List){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_ListBuilder builder = C_InitListBuilder(result);
|
||
|
for (C_Cell *node = cell;
|
||
|
!C_IsNil(node);
|
||
|
node = node->next){
|
||
|
C_Cell *evaluated = C_Evaluate(ctx, node->first_child, env);
|
||
|
C_ListBuilderPush(ctx->bucket, builder, evaluated);
|
||
|
}
|
||
|
C_ListBuilderTerminate(ctx->statics, builder);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_ListCount){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[1];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_Constructed ||
|
||
|
args[0]->kind == C_CellKind_Nil){
|
||
|
result = C_NewF64Cell(ctx->bucket, (f64)args[0]->f);
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Id){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[1];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_Identifier){
|
||
|
C_Cell *resolved = C_EnvironmentResolve(ctx->statics, *env, args[0]->identifier);
|
||
|
if (resolved != 0 && resolved->kind == C_CellKind_Deferred){
|
||
|
E_Definition *resolved_definition = (E_Definition*)resolved->deferred->user_ptr;
|
||
|
result = C_NewIdCell(ctx->bucket, resolved_definition->id);
|
||
|
}
|
||
|
}
|
||
|
else if (args[0]->kind == C_CellKind_Id){
|
||
|
result = args[0];
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_AllIds){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[1];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_Space){
|
||
|
E_Space *space = (E_Space*)args[0]->space;
|
||
|
result = space->id_list;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Eval){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[1];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
result = C_Evaluate(ctx, args[0], env);
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Apply){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
result = C_Apply(ctx, args[0], args[1], env);
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_FarEval){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_Space){
|
||
|
E_Space *space = (E_Space*)args[0]->space;
|
||
|
C_EvalCtx far_ctx = C_InitEvalCtx(ctx->statics, ctx->bucket, space->id_env);
|
||
|
far_ctx.max_depth = ctx->max_depth;
|
||
|
far_ctx.depth = ctx->depth;
|
||
|
far_ctx.regs = ctx->regs;
|
||
|
C_Cell *far_env = space->defines_env;
|
||
|
result = C_Evaluate(&far_ctx, args[1], &far_env);
|
||
|
ctx->regs = far_ctx.regs;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Kind){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[1];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
switch (args[0]->kind){
|
||
|
case C_CellKind_Nil:
|
||
|
{
|
||
|
result = C_NewIdentifierCellLit(ctx->bucket, S8Lit("Nil"));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Constructed:
|
||
|
{
|
||
|
result = C_NewIdentifierCellLit(ctx->bucket, S8Lit("Constructed"));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_F64:
|
||
|
case C_CellKind_BuiltIn:
|
||
|
case C_CellKind_Function:
|
||
|
case C_CellKind_Macro:
|
||
|
case C_CellKind_FunctionV:
|
||
|
case C_CellKind_MacroV:
|
||
|
case C_CellKind_Space:
|
||
|
case C_CellKind_Register:
|
||
|
{
|
||
|
result = C_NewIdentifierCellLit(ctx->bucket, S8Lit("Idempotent"));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Id:
|
||
|
{
|
||
|
result = C_NewIdentifierCellLit(ctx->bucket, S8Lit("Id"));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Identifier:
|
||
|
{
|
||
|
result = C_NewIdentifierCellLit(ctx->bucket, S8Lit("Identifier"));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Environment:
|
||
|
{
|
||
|
result = C_NewIdentifierCellLit(ctx->bucket, S8Lit("Environment"));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Deferred:
|
||
|
{
|
||
|
result = C_NewIdentifierCellLit(ctx->bucket, S8Lit("Deferred"));
|
||
|
}break;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Define){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
args[0] = C_Evaluate(ctx, args[0], env);
|
||
|
STR_Index name = C_GetIdentifierFromCell(args[0]);
|
||
|
if (name != 0){
|
||
|
C_Cell *body = C_Evaluate(ctx, args[1], env);
|
||
|
*env = C_ExtendEnvironment(ctx->bucket, name, body, *env);
|
||
|
// NOTE(allen): When we define a function, the function's environment will
|
||
|
// not see itself! This is inconvenient so we poke it in here.
|
||
|
if (body->kind == C_CellKind_Function){
|
||
|
body->env = *env;
|
||
|
}
|
||
|
result = body;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Increment){
|
||
|
C_NumComp comp = {0};
|
||
|
C_Cell *args[1];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_F64){
|
||
|
comp.f = args[0]->f + 1.0;
|
||
|
comp.valid = 1;
|
||
|
}
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromNumComp(ctx, &comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Decrement){
|
||
|
C_NumComp comp = {0};
|
||
|
C_Cell *args[1];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_F64){
|
||
|
comp.f = args[0]->f - 1.0;
|
||
|
comp.valid = 1;
|
||
|
}
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromNumComp(ctx, &comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Add){
|
||
|
C_NumComp comp = {1};
|
||
|
for (C_Cell *node = cell;
|
||
|
!C_IsNil(node);
|
||
|
node = node->next){
|
||
|
C_Cell *evaluated = C_Evaluate(ctx, node->first_child, env);
|
||
|
if (C_IsF64(evaluated)){
|
||
|
comp.f += evaluated->f;
|
||
|
}
|
||
|
else{
|
||
|
comp.valid = 0;
|
||
|
}
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromNumComp(ctx, &comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Mul){
|
||
|
C_NumComp comp = {1, 1.};
|
||
|
for (C_Cell *node = cell;
|
||
|
!C_IsNil(node);
|
||
|
node = node->next){
|
||
|
C_Cell *evaluated = C_Evaluate(ctx, node->first_child, env);
|
||
|
if (C_IsF64(evaluated)){
|
||
|
comp.f *= evaluated->f;
|
||
|
}
|
||
|
else{
|
||
|
comp.valid = 0;
|
||
|
}
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromNumComp(ctx, &comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Sub){
|
||
|
C_NumComp comp = {0};
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (C_IsF64(args[0]) && C_IsF64(args[1])){
|
||
|
comp.valid = 1;
|
||
|
comp.f = args[0]->f - args[1]->f;
|
||
|
}
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromNumComp(ctx, &comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Div){
|
||
|
C_NumComp comp = {0};
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (C_IsF64(args[0]) && C_IsF64(args[1])){
|
||
|
comp.valid = 1;
|
||
|
comp.f = args[0]->f/args[1]->f;
|
||
|
}
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromNumComp(ctx, &comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Mod){
|
||
|
C_NumComp comp = {0};
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (C_IsF64(args[0]) && C_IsF64(args[1])){
|
||
|
comp.valid = 1;
|
||
|
comp.f = FMod(args[0]->f, args[1]->f);
|
||
|
}
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromNumComp(ctx, &comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Pow){
|
||
|
C_NumComp comp = {0};
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (C_IsF64(args[0]) && C_IsF64(args[1])){
|
||
|
comp.valid = 1;
|
||
|
comp.f = Pow32(args[0]->f, args[1]->f);
|
||
|
}
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromNumComp(ctx, &comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Ls){
|
||
|
b32 comp = 0;
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (C_IsF64(args[0]) && C_IsF64(args[1])){
|
||
|
comp = (args[0]->f < args[1]->f);
|
||
|
}
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromBoolean(ctx, comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Gr){
|
||
|
b32 comp = 0;
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (C_IsF64(args[0]) && C_IsF64(args[1])){
|
||
|
comp = (args[0]->f > args[1]->f);
|
||
|
}
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromBoolean(ctx, comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_LsEq){
|
||
|
b32 comp = 0;
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (C_IsF64(args[0]) && C_IsF64(args[1])){
|
||
|
comp = (args[0]->f <= args[1]->f);
|
||
|
}
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromBoolean(ctx, comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_GrEq){
|
||
|
b32 comp = 0;
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (C_IsF64(args[0]) && C_IsF64(args[1])){
|
||
|
comp = (args[0]->f >= args[1]->f);
|
||
|
}
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromBoolean(ctx, comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Eq){
|
||
|
b32 comp = 0;
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
comp = C_CellEquality(args[0], args[1]);
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromBoolean(ctx, comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_NotEq){
|
||
|
b32 comp = 0;
|
||
|
C_Cell *args[2];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
comp = !C_CellEquality(args[0], args[1]);
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromBoolean(ctx, comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Not){
|
||
|
b32 comp = 0;
|
||
|
C_Cell *args[1];
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
comp = !C_IsTruthy(args[0]);
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromBoolean(ctx, comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_And){
|
||
|
b32 comp = 1;
|
||
|
for (C_Cell *node = cell;
|
||
|
comp && !C_IsNil(node);
|
||
|
node = node->next){
|
||
|
comp = comp && C_IsTruthy(node->first_child);
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromBoolean(ctx, comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Or){
|
||
|
b32 comp = 0;
|
||
|
for (C_Cell *node = cell;
|
||
|
!comp && !C_IsNil(node);
|
||
|
node = node->next){
|
||
|
comp = comp || C_IsTruthy(node->first_child);
|
||
|
}
|
||
|
C_Cell *result = C_GetCellFromBoolean(ctx, comp);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_If){
|
||
|
C_Cell *args[3];
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
if (C_IsTruthy(C_Evaluate(ctx, args[0], env))){
|
||
|
result = C_Evaluate(ctx, args[1], env);
|
||
|
}
|
||
|
else{
|
||
|
result = C_Evaluate(ctx, args[2], env);
|
||
|
}
|
||
|
}
|
||
|
else if (C_TakeFixedArguments(cell, args, 2)){
|
||
|
if (C_IsTruthy(C_Evaluate(ctx, args[0], env))){
|
||
|
result = C_Evaluate(ctx, args[1], env);
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Switch){
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
C_Cell *node = cell;
|
||
|
C_Cell *switch_val = C_Evaluate(ctx, node->first_child, env);
|
||
|
node = node->next;
|
||
|
for (;!C_IsNil(node);){
|
||
|
C_Cell *extended_env = *env;
|
||
|
C_Cell *check_val = C_Evaluate(ctx, node->first_child, &extended_env);
|
||
|
if (C_CellEquality(switch_val, check_val)){
|
||
|
node = node->next;
|
||
|
result = C_Evaluate(ctx, node->first_child, &extended_env);
|
||
|
*env = extended_env;
|
||
|
break;
|
||
|
}
|
||
|
node = node->next;
|
||
|
if (!C_IsNil(node)){
|
||
|
node = node->next;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Loop){
|
||
|
u64 count = 0;
|
||
|
for (u64 lim = 0;
|
||
|
lim < ctx->loop_lim &&
|
||
|
C_IsTruthy(C_Evaluate(ctx, cell->first_child, env));
|
||
|
lim += 1){
|
||
|
for (C_Cell *node = cell->next;
|
||
|
!C_IsNil(node);
|
||
|
node = node->next){
|
||
|
C_Evaluate(ctx, node->first_child, env);
|
||
|
}
|
||
|
count += 1;
|
||
|
}
|
||
|
C_Cell *result = C_NewF64Cell(ctx->bucket, (f64)count);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Ceil){
|
||
|
C_Cell *args[1];
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_F64){
|
||
|
result = C_NewF64Cell(ctx->bucket, f32Ceil(args[0]->f));
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Floor){
|
||
|
C_Cell *args[1];
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_F64){
|
||
|
result = C_NewF64Cell(ctx->bucket, f32Floor(args[0]->f));
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal
|
||
|
C_BUILT_IN_SIG(C_BuiltIn_Round){
|
||
|
C_Cell *args[1];
|
||
|
C_Cell *result = C_GetNilCell(ctx->statics);
|
||
|
if (C_TakeFixedArguments(cell, args, ArrayCount(args))){
|
||
|
C_EvaluateArray(ctx, args, ArrayCount(args), env);
|
||
|
if (args[0]->kind == C_CellKind_F64){
|
||
|
result = C_NewF64Cell(ctx->bucket, f32Round(args[0]->f));
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////
|
||
|
// NOTE(allen): Statics
|
||
|
|
||
|
internal C_Statics
|
||
|
C_InitStatics(C_CellBucket *bucket){
|
||
|
C_Statics statics = {0};
|
||
|
|
||
|
statics.Nil = C_AllocateCell(bucket);
|
||
|
statics.env = statics.Nil;
|
||
|
#define DefineStatic(N,F) \
|
||
|
statics.F = C_NewBuiltInCell(bucket, S8Lit(N), C_BuiltIn_##F); \
|
||
|
statics.env = C_ExtendEnvironmentLiteral(bucket, S8Lit(N), statics.F, statics.env);
|
||
|
C_BuiltInXList(DefineStatic)
|
||
|
#undef DefineStatic
|
||
|
return(statics);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////
|
||
|
// NOTE(allen): Stringize
|
||
|
|
||
|
internal void
|
||
|
C_StringizeCellStream(M_Arena *arena, C_Cell *cell, String8_List *list){
|
||
|
switch (cell->kind){
|
||
|
default:
|
||
|
{
|
||
|
StringListPush(arena, list, S8Lit("[err]()"));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Nil:
|
||
|
{
|
||
|
StringListPush(arena, list, S8Lit("()"));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Constructed:
|
||
|
{
|
||
|
b32 is_list = 1;
|
||
|
for (C_Cell *node = cell;
|
||
|
!C_IsNil(node);
|
||
|
node = node->next){
|
||
|
if (node->kind != C_CellKind_Constructed){
|
||
|
is_list = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
StringListPush(arena, list, S8Lit("("));
|
||
|
for (C_Cell *node = cell;
|
||
|
!C_IsNil(node);
|
||
|
node = node->next){
|
||
|
if (node != cell){
|
||
|
StringListPush(arena, list, S8Lit(" "));
|
||
|
}
|
||
|
if (node->kind == C_CellKind_Constructed){
|
||
|
C_StringizeCellStream(arena, node->first_child, list);
|
||
|
}
|
||
|
else{
|
||
|
C_StringizeCellStream(arena, node, list);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
StringListPush(arena, list, S8Lit(")"));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_F64:
|
||
|
{
|
||
|
String8_Node *node = StringListPushF(arena, list, "%f", cell->f);
|
||
|
u64 og_size = node->string.size;
|
||
|
u8 *first = node->string.str;
|
||
|
u8 *ptr = first;
|
||
|
u8 *opl = first + node->string.size;
|
||
|
u8 *saw_period_at = 0;
|
||
|
u8 *last_significand_at = 0;
|
||
|
for (;ptr < opl; ptr += 1){
|
||
|
if (*ptr == '.'){
|
||
|
saw_period_at = ptr;
|
||
|
ptr += 1;
|
||
|
for (;ptr < opl; ptr += 1){
|
||
|
if (*ptr != '0'){
|
||
|
last_significand_at = ptr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (last_significand_at != 0){
|
||
|
node->string.size = (last_significand_at + 1 - first);
|
||
|
}
|
||
|
else if (saw_period_at != 0){
|
||
|
node->string.size = (saw_period_at - first);
|
||
|
}
|
||
|
list->total_size -= (og_size - node->string.size);
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Identifier:
|
||
|
{
|
||
|
StringListPush(arena, list, STR_Read(APP_GetStringHash(), cell->identifier));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Id:
|
||
|
{
|
||
|
StringListPushF(arena, list, "#%llu", cell->id);
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Register:
|
||
|
{
|
||
|
StringListPushF(arena, list, "[reg] #%llu", cell->id);
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Environment:
|
||
|
{
|
||
|
StringListPush(arena, list, S8Lit("[env] "));
|
||
|
for (C_Cell *node = cell;
|
||
|
!C_IsNil(node);
|
||
|
node = node->next){
|
||
|
if (node != cell){
|
||
|
StringListPush(arena, list, S8Lit(" "));
|
||
|
}
|
||
|
C_StringizeCellStream(arena, node->first_child, list);
|
||
|
}
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_BuiltIn:
|
||
|
{
|
||
|
String8 identifier = STR_Read(APP_GetStringHash(), cell->identifier);
|
||
|
StringListPushF(arena, list, "[prm]%.*s", StringExpand(identifier));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Function:
|
||
|
{
|
||
|
StringListPush(arena, list, S8Lit("[fun] "));
|
||
|
}goto verb_body;
|
||
|
|
||
|
case C_CellKind_FunctionV:
|
||
|
{
|
||
|
StringListPush(arena, list, S8Lit("[fnv] "));
|
||
|
}goto verb_body;
|
||
|
|
||
|
case C_CellKind_Macro:
|
||
|
{
|
||
|
StringListPush(arena, list, S8Lit("[mac] "));
|
||
|
}goto verb_body;
|
||
|
|
||
|
case C_CellKind_MacroV:
|
||
|
{
|
||
|
StringListPush(arena, list, S8Lit("[mcv] "));
|
||
|
}goto verb_body;
|
||
|
|
||
|
verb_body:
|
||
|
{
|
||
|
C_StringizeCellStream(arena, cell->first_child, list);
|
||
|
StringListPush(arena, list, S8Lit(" "));
|
||
|
C_StringizeCellStream(arena, cell->next, list);
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_Deferred:
|
||
|
{
|
||
|
StringListPush(arena, list, S8Lit("[def]"));
|
||
|
}break;
|
||
|
|
||
|
case C_CellKind_BlockHeader:
|
||
|
{
|
||
|
StringListPush(arena, list, S8Lit("[blk]"));
|
||
|
}break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal String8
|
||
|
C_StringizeCell(M_Arena *arena, C_Cell *cell){
|
||
|
String8_List list = {0};
|
||
|
C_StringizeCellStream(arena, cell, &list);
|
||
|
return(StringListJoin(arena, &list, 0));
|
||
|
}
|
||
|
|
||
|
////////////////////////////////
|
||
|
// NOTE(allen): Lex
|
||
|
|
||
|
internal b32
|
||
|
C_ValidLabel(String8 string){
|
||
|
b32 result = (string.size > 0);
|
||
|
u8 *ptr = string.str;
|
||
|
u8 *opl = string.str + string.size;
|
||
|
for (;result && ptr < opl; ptr += 1){
|
||
|
switch (*ptr){
|
||
|
case '(':
|
||
|
case ')':
|
||
|
case '\'':
|
||
|
case ';':
|
||
|
{
|
||
|
result = 0;
|
||
|
}break;
|
||
|
default:
|
||
|
{
|
||
|
if (*ptr <= ' ' || 127 <= *ptr){
|
||
|
result = 0;
|
||
|
}
|
||
|
}break;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
C_StringizeTokensStream(M_Arena *arena, C_Token *tokens, u64 count, String8_List *out){
|
||
|
u8 escape_byte = 1;
|
||
|
String8 escape = S8(&escape_byte, 1);
|
||
|
STR_Hash *string_hash = APP_GetStringHash();
|
||
|
C_Token *token = tokens;
|
||
|
for (u64 i = 0; i < count; i += 1, token += 1){
|
||
|
switch (token->kind){
|
||
|
default:
|
||
|
{
|
||
|
StringListPush(arena, out, escape);
|
||
|
StringListPushF(arena, out, "%u", token->kind);
|
||
|
StringListPush(arena, out, escape);
|
||
|
}break;
|
||
|
|
||
|
case C_TokenKind_Space:
|
||
|
{
|
||
|
StringListPush(arena, out, S8Lit(" "));
|
||
|
}break;
|
||
|
|
||
|
case C_TokenKind_Newline:
|
||
|
{
|
||
|
StringListPush(arena, out, S8Lit("\n"));
|
||
|
}break;
|
||
|
|
||
|
case C_TokenKind_Comment:
|
||
|
{
|
||
|
String8 string = STR_Read(string_hash, token->string);
|
||
|
StringListPushF(arena, out, ";%.*s\t", StringExpand(string));
|
||
|
}break;
|
||
|
|
||
|
case C_TokenKind_OpenParen:
|
||
|
{
|
||
|
StringListPush(arena, out, S8Lit("("));
|
||
|
}break;
|
||
|
|
||
|
case C_TokenKind_CloseParen:
|
||
|
{
|
||
|
StringListPush(arena, out, S8Lit(")"));
|
||
|
}break;
|
||
|
|
||
|
case C_TokenKind_Quote:
|
||
|
{
|
||
|
StringListPush(arena, out, S8Lit("\'"));
|
||
|
}break;
|
||
|
|
||
|
case C_TokenKind_Label:
|
||
|
{
|
||
|
String8 string = STR_Read(string_hash, token->string);
|
||
|
StringListPushF(arena, out, "%.*s", StringExpand(string));
|
||
|
}break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal C_TokenArray
|
||
|
C_Lex(M_Arena *arena, String8 string){
|
||
|
STR_Hash *string_hash = APP_GetStringHash();
|
||
|
|
||
|
C_TokenArray result = {0};
|
||
|
result.vals = PushArray(arena, C_Token, 0);
|
||
|
|
||
|
u8 *ptr = string.str;
|
||
|
u8 *opl = string.str + string.size;
|
||
|
for (;ptr < opl;){
|
||
|
switch (*ptr){
|
||
|
case 0:
|
||
|
{
|
||
|
ptr = opl;
|
||
|
}break;
|
||
|
|
||
|
case 1:
|
||
|
{
|
||
|
ptr += 1;
|
||
|
u8 *first = ptr;
|
||
|
for (;ptr < opl; ptr += 1){
|
||
|
if (*ptr == 1){
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
C_Token *token = PushArrayZero(arena, C_Token, 1);
|
||
|
token->kind = (C_TokenKind)GetFirstIntegerFromString(S8Range(first, ptr));
|
||
|
ptr += 1;
|
||
|
}break;
|
||
|
|
||
|
case ' ':
|
||
|
{
|
||
|
C_Token *token = PushArrayZero(arena, C_Token, 1);
|
||
|
token->kind = C_TokenKind_Space;
|
||
|
ptr += 1;
|
||
|
}break;
|
||
|
|
||
|
case '\n':
|
||
|
{
|
||
|
C_Token *token = PushArrayZero(arena, C_Token, 1);
|
||
|
token->kind = C_TokenKind_Newline;
|
||
|
ptr += 1;
|
||
|
}break;
|
||
|
|
||
|
case '(':
|
||
|
{
|
||
|
C_Token *token = PushArrayZero(arena, C_Token, 1);
|
||
|
token->kind = C_TokenKind_OpenParen;
|
||
|
ptr += 1;
|
||
|
}break;
|
||
|
|
||
|
case ')':
|
||
|
{
|
||
|
C_Token *token = PushArrayZero(arena, C_Token, 1);
|
||
|
token->kind = C_TokenKind_CloseParen;
|
||
|
ptr += 1;
|
||
|
}break;
|
||
|
|
||
|
case '\'':
|
||
|
{
|
||
|
C_Token *token = PushArrayZero(arena, C_Token, 1);
|
||
|
token->kind = C_TokenKind_Quote;
|
||
|
ptr += 1;
|
||
|
}break;
|
||
|
|
||
|
case ';':
|
||
|
{
|
||
|
ptr += 1;
|
||
|
u8 *first = ptr;
|
||
|
for (;ptr < opl; ptr += 1){
|
||
|
if (*ptr == '\t'){
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
C_Token *token = PushArrayZero(arena, C_Token, 1);
|
||
|
token->kind = C_TokenKind_Comment;
|
||
|
token->string = STR_Save(string_hash, S8Range(first, ptr));
|
||
|
ptr += 1;
|
||
|
}break;
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
u8 *first = ptr;
|
||
|
ptr += 1;
|
||
|
for (;ptr < opl; ptr += 1){
|
||
|
u8 c = *ptr;
|
||
|
if (c == 0 || c == 1 || c == ' ' || c == '\n' || c == '(' || c == ')' || c == '\'' || c == ';'){
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
C_Token *token = PushArrayZero(arena, C_Token, 1);
|
||
|
token->kind = C_TokenKind_Label;
|
||
|
token->string = STR_Save(string_hash, S8Range(first, ptr));
|
||
|
}break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
result.count = (PushArray(arena, C_Token, 0) - result.vals);
|
||
|
return(result);
|
||
|
}
|