Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • vlasami6/ni-run-template
  • chybijan/ni-run
  • ruzict16/FML
  • rozhovoj/ni-run-template
  • skrabmir/cfml
  • plodeada/ni-run-plodeada
  • stepam38/ni-run
  • hrncikar/ni-run
  • balikvo1/ni-run
9 results
Show changes
Commits on Source (30)
......@@ -2,8 +2,25 @@ image: $CI_REGISTRY/vlasami6/fmltest:master
 
test:
script:
- meson setup build
- meson compile -C build
- cppcheck --error-exitcode=1 *.c
- env FML="$(readlink -f ./build/fml)" FML_REF_BC_INT=/cfml/fml /FMLtest/suite ast_interpret
hello_world.fml
- make
#- cppcheck --error-exitcode=1 *.c
- env FML="$(readlink -f ./fml)" FML_REF_BC_INT=/cfml/fml /FMLtest/suite ast_interpret
$(/FMLtest/suite show fml)
#hello_world
#literals
#variables
#conditionals
#loops
#functions
#function_value
#builtins
#arrays
#iterator
#fibonacci
#fizzbuzz_fun
#fizzbuzz_loop
#roman
#stack
#brainfuck
#langtons_ant
#sudoku
CC=gcc
CFLAGS=-Wall -pedantic -Wextra -g #-fsanitize=address,undefined
LFLAGS=
OUTPUT=fml
SRC_DIR=./src
BUILD_DIR=./build
.PHONY: init fml
all: init fml
fml: $(BUILD_DIR)/arena.o $(BUILD_DIR)/parser.o $(BUILD_DIR)/ast_interpreter.o $(BUILD_DIR)/bc_interpreter.o $(SRC_DIR)/fml.c \
$(BUILD_DIR)/heap.o #$(BUILD_DIR)/%.o
$(CC) $(CFLAGS) $(LFLAGS) $? -o $(OUTPUT)
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $@
# $(SRC_DIR)/parser.o $(BUILD_DIR)/heap.o
$(BUILD_DIR)/bc_interpreter.o: $(SRC_DIR)/bc_interpreter.c
$(CC) $(CFLAGS) -c $? -o $@
# $(SRC_DIR)/parser.o $(BUILD_DIR)/heap.o
$(BUILD_DIR)/ast_interpreter.o: $(SRC_DIR)/ast_interpreter.c
$(CC) $(CFLAGS) -c $? -o $@
$(BUILD_DIR)/parser.o: $(SRC_DIR)/parser.c
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/arena.o: $(SRC_DIR)/arena.c
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/heap.o: $(SRC_DIR)/heap.c
$(CC) $(CFLAGS) -c $< -o $@
init:
mkdir -p build
File moved
File moved
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include "parser.h"
#include "ast_interpreter.h"
void env_push ( ASTInterpreterState * state ) {
Environment * env = (Environment*) malloc ( sizeof (Environment) );
(*env) = (Environment) { .prev = state -> current_env, .start = NULL };
state -> current_env = env;
}
void env_pop ( ASTInterpreterState * state ) {
Environment * tmp = state -> current_env;
EnvironmentEntry * entry;
EnvironmentEntry * next = tmp -> start;
while ( (entry = next) ) {
next = entry -> next;
free ( entry );
}
state -> current_env = tmp -> prev;
free (tmp);
}
void env_put ( ASTInterpreterState * state, Str name, Value * value ) {
Environment * env = state -> current_env;
EnvironmentEntry * entry;
while ( env ) {
entry = env -> start;
while ( entry ) {
if ( str_eq ( entry -> name, name ) ) {
entry -> value = value;
return;
}
entry = entry -> next;
}
env = env -> prev;
}
entry = state -> global_env . start;
while ( entry ) {
if ( str_eq ( entry -> name, name ) ) {
entry -> value = value;
return;
}
entry = entry -> next;
}
env = state -> current_env;
env = env ? env : & state -> global_env;
entry = (EnvironmentEntry*) malloc ( sizeof (EnvironmentEntry) );
(*entry) = (EnvironmentEntry) {.name = name, .value = value, .next = env -> start };
env -> start = entry;
}
void env_def ( ASTInterpreterState * state, Str name, Value * value ) {
Environment * env = state -> current_env ? state -> current_env : & state -> global_env;
EnvironmentEntry * parent = NULL;
EnvironmentEntry * entry = env -> start;
while ( entry ) {
if ( str_eq ( name, entry -> name ) ) {
entry -> value = value;
return;
}
parent = entry;
entry = entry -> next;
}
entry = (EnvironmentEntry*) malloc ( sizeof (EnvironmentEntry) );
entry -> name = name;
entry -> value = value;
entry -> next = NULL;
if ( parent )
parent -> next = entry;
else
env -> start = entry;
}
Value * env_get ( ASTInterpreterState * state, Str name ) {
Environment * env = state -> current_env;
EnvironmentEntry * entry;
while ( env ) {
entry = env -> start;
while ( entry ) {
if ( str_eq ( entry -> name, name ) )
return entry -> value;
entry = entry -> next;
}
env = env -> prev;
}
entry = state -> global_env . start;
while ( entry ) {
if ( str_eq ( entry -> name, name ) )
return entry -> value;
entry = entry -> next;
}
env = state -> current_env;
env = env ? env : & state -> global_env;
entry = (EnvironmentEntry*) malloc ( sizeof (EnvironmentEntry) );
(*entry) = (EnvironmentEntry) {.name = name, .value = make_null ( state -> heap ), .next = env -> start };
env -> start = entry;
return entry -> value;
}
void state_init ( ASTInterpreterState * state, Heap * heap ) {
state -> heap = heap;
state -> global_env . prev = NULL;
state -> global_env . start = NULL;
state -> current_env = NULL;
}
void state_destroy ( ASTInterpreterState * state ) {
heap_destroy ( state -> heap );
Environment * env = & state -> global_env;
EnvironmentEntry * entry;
EnvironmentEntry * next = env -> start;
while ( (entry = next) ) {
next = entry -> next;
free ( entry );
}
Environment * next_env = state -> current_env;
while ( (env = next_env) ) {
next = env -> start;
while ( (entry = next) ) {
next = entry -> next;
free ( entry );
}
next_env = env -> prev;
}
}
Value * function_call ( ASTInterpreterState * state, Value * callee, bool is_function, Ast ** arguments, size_t argc, Str * name ) {
Value ** values = (Value **) malloc ( argc * sizeof (Value*) );
for ( size_t i = 0; i < argc; ++i )
values [ i ] = evaluate ( state, arguments [ i ] );
Value * ret = NULL;
Value * function = callee;
if ( ! is_function ) {
function = NULL;
Value * next = callee;
Value * curr;
ObjectValue * tmp;
while ( next -> kind == VALUE_OBJECT ) {
curr = next;
tmp = (ObjectValue *) curr;
for ( size_t i = 0; i < tmp -> member_cnt; ++i )
if ( str_eq ( tmp -> members [ i ] . name, *name ) ) {
function = tmp -> members [ i ] . value;
callee = curr;
break;
}
next = tmp -> extends;
}
if ( ! function ) {
Value * base = get_base ( callee );
ret = try_operator ( state -> heap, base, values, argc, name );
free ( values );
if ( ret )
return ret;
fprintf ( stderr, "Method %.*s does not exist for this object and/or arguments.\n", (int) name -> len, name -> str );
exit ( 13 );
}
}
if ( function -> kind != VALUE_FUNCTION ) {
fprintf ( stderr, "Invalid callee.\n" );
exit ( 4 );
}
FunctionValue * f = (FunctionValue*) function;
Environment * tmp;
tmp = state -> current_env;
state -> current_env = NULL;
env_push ( state );
env_def ( state, STR ("this"), is_function ? make_null ( state -> heap ) : callee );
for ( size_t i = 0; i < argc; ++i )
env_def ( state, f -> function -> parameters [ i ], values [ i ] );
ret = evaluate ( state, f -> function -> body );
env_pop ( state );
state -> current_env = tmp;
free ( values );
return ret;
}
void print_value ( Value * value ) {
switch ( value -> kind ) {
case VALUE_INTEGER:
printf ( "%" PRIi32, ((IntValue*) value ) -> integer );
break;
case VALUE_BOOLEAN:
if ( ((BoolValue*) value ) -> boolean )
printf ( "true" );
else
printf ( "false" );
break;
case VALUE_NULL:
printf ( "null" );
break;
case VALUE_FUNCTION:
printf ( "function" );
break;
case VALUE_ARRAY:
putchar ( '[' );
ArrayValue * arr = (ArrayValue*) value;
for ( i32 i = 0; i < arr -> length; ++i ) {
if ( i != 0 )
printf ( ", " );
print_value ( arr -> elements [ i ] );
}
putchar ( ']' );
break;
case VALUE_OBJECT:
printf ( "object(");
ObjectValue * obj = (ObjectValue*) value;
bool parent = false;
if ( obj -> extends -> kind != VALUE_NULL ) {
parent = true;
printf ( "..=" );
print_value ( obj -> extends );
}
if ( obj -> member_cnt )
qsort ( obj -> members, obj -> member_cnt, sizeof (SimpleEntry), compare_entry );
for ( size_t i = 0; i < obj -> member_cnt; ++i ) {
if ( i != 0 || parent )
printf ( ", " );
printf ( "%.*s=", (int) obj -> members [ i ] . name . len, obj -> members [ i ] . name . str );
print_value ( obj -> members [ i ] . value );
}
putchar ( ')' );
break;
case VALUE_INVALID:
fprintf ( stderr, "Invalid value.\n" );
}
}
void fml_print ( Str format, Value ** args, size_t argc ) {
u8 c;
size_t arg = 0;
for ( size_t i = 0; i < format . len; ++i ) {
c = format . str [ i ];
if ( c == '\\' ) {
++i;
c = format . str [ i ];
switch ( c ) {
case '~':
putchar ( '~' );
break;
case 'n':
putchar ( '\n' );
break;
case '"':
putchar ( '"' );
break;
case 'r':
putchar ( '\r' );
break;
case 't':
putchar ( '\t' );
break;
case '\\':
putchar ( '\\' );
break;
default:
fprintf ( stderr, "Invalid escaped character %c.\n", c );
exit ( 1 );
}
} else if ( c == '~' ) {
if ( arg == argc ) {
fprintf ( stderr, "Too many placeholders, not enough arguments.\n" );
exit ( 1 );
}
print_value ( args [ arg++ ] );
} else
putchar ( c );
}
}
Value * evaluate ( ASTInterpreterState * state, Ast * ast ) {
switch ( ast -> kind ) {
case AST_INTEGER:
return make_int ( state -> heap, ((AstInteger*) ast ) -> value );
case AST_BOOLEAN:
return make_bool ( state -> heap, ((AstBoolean*) ast ) -> value );
case AST_NULL:
return make_null ( state -> heap );
case AST_PRINT: {
AstPrint * printAst = (AstPrint*) ast;
Value ** args = (Value **) malloc ( sizeof (Value*) * printAst -> argument_cnt );
for ( size_t i = 0; i < printAst -> argument_cnt; ++i )
args [ i ] = evaluate ( state, printAst -> arguments [ i ] );
fml_print ( printAst -> format, args, printAst -> argument_cnt );
free ( args );
return make_null ( state -> heap );
}
case AST_TOP: {
AstTop * topAst = (AstTop*) ast;
Value * val = evaluate ( state, topAst -> expressions [ 0 ] );
for ( size_t i = 1; i < topAst -> expression_cnt; ++i )
val = evaluate ( state, topAst -> expressions [ i ] );
return val;
}
case AST_DEFINITION: {
AstDefinition * defAst = (AstDefinition*) ast;
Value * value = evaluate ( state, defAst -> value );
env_def ( state, defAst -> name, value );
return value;
}
case AST_VARIABLE_ACCESS:
return env_get ( state, ((AstVariableAccess*) ast ) -> name );
case AST_VARIABLE_ASSIGNMENT: {
AstVariableAssignment * assignAst = (AstVariableAssignment*) ast;
Value * value = evaluate ( state, assignAst -> value );
env_put ( state, assignAst -> name, value );
return value;
}
case AST_BLOCK: {
AstBlock * blockAst = (AstBlock*) ast;
env_push ( state );
Value * value = evaluate ( state, blockAst -> expressions [ 0 ] );
for ( size_t i = 1; i < blockAst -> expression_cnt; ++i )
value = evaluate ( state, blockAst -> expressions [ i ] );
env_pop ( state );
return value;
}
case AST_CONDITIONAL: {
AstConditional * condAst = (AstConditional*) ast;
Value * cond = evaluate ( state, condAst -> condition );
env_push ( state );
Ast * cont = value_to_bool ( cond ) ? condAst -> consequent : condAst -> alternative;
Value * value = evaluate ( state, cont );
env_pop ( state );
return value;
}
case AST_LOOP: {
AstLoop * loopAst = (AstLoop*) ast;
while ( value_to_bool ( evaluate ( state, loopAst -> condition ) ) ) {
env_push ( state );
evaluate ( state, loopAst -> body );
env_pop ( state );
}
return make_null ( state -> heap );
}
case AST_FUNCTION:
return make_function ( state -> heap, (AstFunction*) ast );
case AST_FUNCTION_CALL: {
AstFunctionCall * callAst = (AstFunctionCall*) ast;
Value * function = evaluate ( state, callAst -> function );
return function_call ( state, function, true, callAst -> arguments, callAst -> argument_cnt, NULL );
}
case AST_METHOD_CALL: {
AstMethodCall * methodAst = (AstMethodCall*) ast;
Value * object = evaluate ( state, methodAst -> object );
if ( object -> kind == VALUE_FUNCTION ) {
fprintf ( stderr, "Calling method on function.\n" );
exit ( 4 );
}
return function_call ( state, object, false, methodAst -> arguments, methodAst -> argument_cnt, &methodAst -> name );
}
case AST_ARRAY: {
AstArray * arrAst = (AstArray*) ast;
Value * size = evaluate ( state, arrAst -> size );
IntValue * int_size = (IntValue*) size;
if ( size -> kind != VALUE_INTEGER || int_size -> integer < 0 ) {
fprintf ( stderr, "Invalid array size.\n" );
exit ( 5 );
}
ArrayValue * array = (ArrayValue*) make_array ( state -> heap, int_size -> integer );
for ( i32 i = 0; i < array -> length; ++i ) {
env_push ( state );
array -> elements [ i ] = evaluate ( state, arrAst -> initializer );
env_pop ( state );
}
return (Value*) array;
}
case AST_INDEX_ACCESS: {
AstIndexAccess * iaccess = (AstIndexAccess*) ast;
Value * object = evaluate ( state, iaccess -> object );
Str tmp = STR ("get");
return function_call ( state, object, false, &iaccess -> index, 1, &tmp );
}
case AST_INDEX_ASSIGNMENT: {
AstIndexAssignment * iassign = (AstIndexAssignment*) ast;
Value * object = evaluate ( state, iassign -> object );
Ast * arguments [2];
arguments [ 0 ] = iassign -> index;
arguments [ 1 ] = iassign -> value;
Str tmp = STR ("set");
return function_call ( state, object, false, arguments, 2, &tmp );
}
case AST_OBJECT: {
AstObject * objAst = (AstObject*) ast;
ObjectValue * object = (ObjectValue*) make_object ( state -> heap, objAst -> member_cnt );
object -> extends = evaluate ( state, objAst -> extends );
Value * value;
AstDefinition * defAst;
for ( size_t i = 0; i < object -> member_cnt; ++i ) {
if ( objAst -> members [ i ] -> kind != AST_DEFINITION ) {
fprintf ( stderr, "Invalid object member.\n" );
exit ( 7 );
}
defAst = (AstDefinition*) objAst -> members [ i ];
env_push ( state );
value = evaluate ( state, defAst -> value );
env_pop ( state );
object -> members [ i ] . name = defAst -> name;
object -> members [ i ] . value = value;
}
return (Value*) object;
}
case AST_FIELD_ACCESS: {
AstFieldAccess * accessAst = (AstFieldAccess *) ast;
Value * object_value = evaluate ( state, accessAst -> object );
if ( object_value -> kind != VALUE_OBJECT ) {
fprintf ( stderr, "Trying to access field of non object.\n" );
exit ( 8 );
}
Value ** result = get_object_field ( object_value, accessAst -> field );
if ( ! result ) {
fprintf ( stderr, "Field %.*s was not found in specified object.\n", (int) accessAst -> field . len, accessAst -> field . str );
exit ( 8 );
}
return *result;
}
case AST_FIELD_ASSIGNMENT: {
AstFieldAssignment * assignAst = (AstFieldAssignment*) ast;
Value * object_value = evaluate ( state, assignAst -> object );
if ( object_value -> kind != VALUE_OBJECT ) {
fprintf ( stderr, "Trying to assign to a field of non object.\n" );
exit ( 8 );
}
Value * value = evaluate ( state, assignAst -> value );
Value ** result = get_object_field ( object_value, assignAst -> field );
if ( ! result ) {
fprintf ( stderr, "Field %.*s was not found in specified object.\n", (int) assignAst -> field . len, assignAst -> field . str );
exit ( 8 );
}
*result = value;
return value;
}
}
return NULL;
}
#pragma once
#include "parser.h"
#include "heap.h"
/*typedef struct Object {
struct Value * extends;
size_t member_cnt;
SimpleEntry members [];
} Object;
typedef struct Array {
i32 length;
Value * members [];
} Array;*/
typedef struct EnvironmentEntry {
struct EnvironmentEntry * next;
Str name;
Value * value;
} EnvironmentEntry;
typedef struct Environment {
struct Environment * prev;
EnvironmentEntry * start;
} Environment;
typedef struct ASTInterpreterState {
Heap * heap;
Environment global_env;
Environment * current_env;
} ASTInterpreterState;
void env_push ( ASTInterpreterState * state );
void env_pop ( ASTInterpreterState * state );
Value * env_get ( ASTInterpreterState * state, Str name );
void env_put ( ASTInterpreterState * state, Str name, Value * value );
void env_def ( ASTInterpreterState * state, Str name, Value * value );
void state_init ( ASTInterpreterState * state, Heap * heap );
void state_destroy ( ASTInterpreterState * state );
Value * function_call ( ASTInterpreterState * state, Value * callee, bool is_function, Ast ** arguments, size_t argc, Str * name );
void print_value ( Value * value );
void fml_print ( Str format, Value ** args, size_t argc );
Value * evaluate ( ASTInterpreterState * state, Ast * ast );
\ No newline at end of file
#include <stdio.h>
#include <inttypes.h>
#include <assert.h>
#include <string.h>
#include "bc_interpreter.h"
void ostack_init ( OperandStack * stack ) {
stack -> elements = (Value**) malloc ( OPERAND_STACK_INIT_CAPACITY * sizeof (Value*) );
stack -> size = 0;
stack -> capacity = OPERAND_STACK_INIT_CAPACITY;
}
Value * ostack_pop ( OperandStack * stack ) {
assert ( stack -> size );
stack -> size--;
return stack -> elements [ stack -> size ];
}
Value * ostack_top ( OperandStack * stack ) {
return stack -> elements [ stack -> size - 1 ];
}
void ostack_push ( OperandStack * stack , Value * value ) {
if ( stack -> size == stack -> capacity ) {
Value ** tmp = (Value**) malloc ( 2 * stack -> capacity * sizeof (Value*) );
memcpy ( tmp, stack -> elements, stack -> size * sizeof (Value*) );
free ( stack -> elements );
stack -> elements = tmp;
}
stack -> elements [ stack -> size++ ] = value;
}
void ostack_destroy ( OperandStack * stack ) {
free ( stack -> elements );
}
void vm_init ( VM * vm, size_t heap_size ) {
heap_init ( & vm -> heap, heap_size );
make_null ( & vm -> heap );
ostack_init ( & vm -> stack );
vm -> local_frame = NULL;
vm -> instruction_pointer = 0;
}
void vm_destroy ( VM * vm ) {
heap_destroy ( & vm -> heap );
ostack_destroy ( & vm -> stack );
for ( size_t i = 0; i < vm -> program . constant_count; ++i ) {
Constant constant = vm -> program . constant_pool [ i ];
if ( constant . kind == CONSTANT_CLASS )
free ( constant . class . members );
}
free ( vm -> program . globals . members );
free ( vm -> program . constant_pool );
}
Value * alloc_constant ( VM * vm, u16 index ) {
assert ( vm -> program . constant_count > index );
Constant constant = vm -> program . constant_pool [ index ];
switch ( constant . kind ) {
case CONSTANT_INTEGER:
return make_int ( & vm -> heap, constant . integer );
case CONSTANT_NULL:
return make_null ( & vm -> heap );
case CONSTANT_BOOLEAN:
return make_bool ( & vm -> heap, constant . boolean );
case CONSTANT_FUNCTION:
return make_cfunction ( & vm -> heap, constant . function );
default:
assert ( false );
}
return NULL;
}
ObjectValue * create_object ( VM * vm, Class * class ) {
ObjectValue * object = (ObjectValue*) make_object ( & vm -> heap, class -> member_count );
Constant * pool = vm -> program . constant_pool;
for ( size_t i = 0; i < class -> member_count; ++i ) {
Constant constant = pool [ class -> members [ i ] ];
assert ( constant . kind == CONSTANT_STRING );
object -> members [ i ] = (SimpleEntry) { .name = constant . string, .value = NULL };
}
return object;
}
void print_operand_value ( Value * value ) {
switch ( value -> kind ) {
case VALUE_INTEGER:
printf ( "%" PRIi32, ((IntValue*) value ) -> integer );
break;
case VALUE_BOOLEAN:
if ( ((BoolValue*) value ) -> boolean )
printf ( "true" );
else
printf ( "false" );
break;
case VALUE_NULL:
printf ( "null" );
break;
case VALUE_FUNCTION:
printf ( "function" );
break;
case VALUE_ARRAY:
putchar ( '[' );
ArrayValue * arr = (ArrayValue*) value;
for ( i32 i = 0; i < arr -> length; ++i ) {
if ( i != 0 )
printf ( ", " );
print_operand_value ( arr -> elements [ i ] );
}
putchar ( ']' );
break;
case VALUE_OBJECT:
printf ( "object(");
ObjectValue * obj = (ObjectValue*) value;
bool parent = false;
if ( obj -> extends -> kind != VALUE_NULL ) {
parent = true;
printf ( "..=" );
print_operand_value ( obj -> extends );
}
if ( obj -> member_cnt )
qsort ( obj -> members, obj -> member_cnt, sizeof (SimpleEntry), compare_entry );
for ( size_t i = 0; i < obj -> member_cnt; ++i ) {
if ( i != 0 || parent )
printf ( ", " );
printf ( "%.*s=", (int) obj -> members [ i ] . name . len, obj -> members [ i ] . name . str );
print_operand_value ( obj -> members [ i ] . value );
}
putchar ( ')' );
break;
default:
assert ( false );
}
}
void print_call ( VM * vm, u16 index, u8 arguments ) {
assert ( vm -> program . constant_count > index );
Constant constant = vm -> program . constant_pool [ index ];
assert ( constant . kind == CONSTANT_STRING );
assert ( arguments <= vm -> stack . size );
Value ** args = (Value**) malloc ( arguments * sizeof (Value*) );
for ( size_t i = arguments; i != 0; --i )
args [ i - 1 ] = ostack_pop ( & vm -> stack );
size_t arg = 0;
Str format = constant . string;
u8 c;
for ( size_t i = 0; i < format . len; ++i ) {
c = format . str [ i ];
if ( c == '\\' ) {
++i;
c = format . str [ i ];
switch ( c ) {
case '~':
putchar ( '~' );
break;
case 'n':
putchar ( '\n' );
break;
case '"':
putchar ( '"' );
break;
case 'r':
putchar ( '\r' );
break;
case 't':
putchar ( '\t' );
break;
case '\\':
putchar ( '\\' );
break;
default:
assert ( false );
}
} else if ( c == '~' ) {
assert ( arg != arguments );
print_operand_value ( args [ arg++ ] );
} else
putchar ( c );
}
free ( args );
assert ( arg == arguments );
}
static inline u8 read_byte ( const u8 * data, size_t * pos ) {
return data [ (*pos)++ ];
}
static inline u16 read_u16 ( const u8 * data, size_t * pos ) {
u8 bytes [ 2 ] = { read_byte ( data, pos ), read_byte ( data, pos ) };
return (uint16_t) (255 & bytes [ 1 ]) << 8 | (255 & bytes [ 0 ]);
}
static inline i32 read_i32 ( const u8 * data, size_t * pos ) {
u8 bytes [4];
for ( size_t i = 0; i < 4; ++i )
bytes [ i ] = read_byte ( data, pos );
return bytes [ 3 ] << 24 | bytes [ 2 ] << 16 | bytes [ 1 ] << 8 | bytes [ 0 ];
}
static inline Class read_class ( const u8 * data, size_t * pos ) {
Class class;
u16 elements = read_u16 ( data, pos );
class . member_count = elements;
class . members = (u16*) malloc ( elements * sizeof (u16) );
for ( size_t i = 0; i < elements; ++i )
class . members [ i ] = read_u16 ( data, pos );
return class;
}
void read_header ( Str input, size_t * pos ) {
u8 bytes [4];
for ( size_t i = 0; i < 4; ++i )
bytes [ i ] = read_byte ( input . str, pos );
Str header;
header . str = bytes;
header . len = 4;
assert ( str_eq ( header, STR ( "FML\n" ) ) );
}
void read_constant_pool ( Program * program, Str input, size_t * pos ) {
// printf ( "%u, %u\n", count_bytes [ 0 ], count_bytes [ 1 ] );
program -> constant_count = read_u16 ( input . str, pos );
// printf ( "%x, %x\n", count_bytes [ 0 ], count_bytes [ 1 ] );
u8 tag;
//printf ( "size is %u\n", program -> constant_count );
Constant * constant_pool = (Constant*) malloc ( program -> constant_count * sizeof (Constant) );
for ( size_t i = 0; i < program -> constant_count; ++i ) {
tag = read_byte ( input . str, pos );
switch ( tag ) {
case 0x00:
constant_pool [ i ] = (Constant) { .kind = CONSTANT_INTEGER, .integer = read_i32 ( input . str, pos ) };
// printf ( "%d\n", constant_pool [ i ] . integer );
break;
case 0x01:
constant_pool [ i ] = (Constant) { .kind = CONSTANT_NULL };
// printf ( "null\n" );
break;
case 0x02: {
u32 len = (u32) read_i32 ( input . str, pos );
const u8 * start = input . str + *pos;
*pos += len;
constant_pool [ i ] = (Constant) { .kind = CONSTANT_STRING, .string = (Str) { .len = len, .str = start } };
// printf ( "%.*s\n", (int) constant_pool [ i ] . string . len, constant_pool [ i ] . string . str );
break;
}
case 0x03: {
u8 parameters = read_byte ( input . str, pos );
u16 locals = read_u16 ( input . str, pos );
u32 len = (u32) read_i32 ( input . str, pos );
const u8 * start = input . str + *pos;
*pos += len;
constant_pool [ i ] = (Constant) { .kind = CONSTANT_FUNCTION, .function = (ConstantFunction) { .parameters = parameters, .locals = locals, .len = len, .start = start } };
// printf ( "func: p=%u, l=%u, len=%u, start=%lu\n", parameters, locals, len, *pos - len );
break;
}
case 0x04:
constant_pool [ i ] = (Constant) { .kind = CONSTANT_BOOLEAN, .boolean = read_byte ( input . str, pos ) };
// printf ( "%s\n", constant_pool [ i ] . boolean == true ? "true" : "false" );
break;
case 0x05: {
constant_pool [ i ] = (Constant) { .kind = CONSTANT_CLASS, .class = read_class ( input . str, pos ) };
}
default:
// printf ( "unsupported type\n" );
break;
}
}
program -> constant_pool = constant_pool;
}
// void read_globals ( Program * program, Str input, size_t * pos ) {
// program -> globals = read_class ( input . str, pos );
// }
void parse_program ( Program * program, Str input ) {
// read + check header
size_t pos = 0;
read_header ( input, &pos );
// read constant pool
read_constant_pool ( program, input, &pos );
// read globals
program -> globals = read_class ( input . str, &pos );
// read EP
program -> entry_point = read_u16 ( input . str, &pos );
}
void bc_function_call ( VM * vm, u8 arguments, bool is_function, Str * name ) {
Value * tmp [256];
arguments = is_function ? arguments : arguments - 1;
for ( size_t i = arguments; i > 0; ++i )
tmp [ i - 1 ] = ostack_pop ( & vm -> stack );
Value * callee = ostack_pop ( & vm -> stack );
ConstantFunction function;
if ( is_function ) {
assert ( callee -> kind == VALUE_FUNCTION );
function = ((CFunctionValue*) callee ) -> function;
} else {
Value * field = *get_object_field ( callee, *name );
while ( ! field ) {
callee = ((ObjectValue*) callee ) -> extends;
if ( callee -> kind != VALUE_OBJECT )
break;
field = *get_object_field ( callee, *name );
}
if ( ! field ) {
Value * result = try_operator ( & vm -> heap, callee, tmp, arguments, name );
assert ( result );
ostack_push ( & vm -> stack, result );
}
assert ( field -> kind == VALUE_FUNCTION );
function = ((CFunctionValue*) field) -> function;
}
size_t local_count = function . parameters + function . locals;
Frame * new_frame = (Frame *) malloc ( sizeof (Frame) + local_count * sizeof (Value*) );
new_frame -> prev = vm -> local_frame;
new_frame -> return_ip = vm -> instruction_pointer;
vm -> local_frame = new_frame;
assert ( arguments + 1 == function . parameters );
if ( is_function )
new_frame -> locals [ 0 ] = make_null ( & vm -> heap );
else
new_frame -> locals [ 0 ] = callee;
for ( size_t i = 1; i <= arguments; ++i )
new_frame -> locals [ i ] = tmp [ i - 1 ];
for ( size_t i = arguments + 1; i < local_count; ++i )
new_frame -> locals [ i ] = make_null ( & vm -> heap );
u8 opcode;
for ( vm -> instruction_pointer = 0; vm -> instruction_pointer < function . len; ) {
opcode = read_byte ( function . start, & vm -> instruction_pointer );
switch ( opcode ) {
case 0x00:
// printf ("drop\n");
ostack_pop ( & vm -> stack );
break;
case 0x01: {
u16 index = read_u16 ( function . start, & vm -> instruction_pointer );
// printf ("constant %u\n", index);
ostack_push ( & vm -> stack, alloc_constant ( vm, index ) );
break;
}
case 0x02: {
// printf ("print\n");
u16 index = read_u16 ( function . start, & vm -> instruction_pointer );
u8 arguments = read_byte ( function . start, & vm -> instruction_pointer );
print_call ( vm, index, arguments );
ostack_push ( & vm -> stack, make_null ( & vm -> heap) );
break;
}
case 0x04: {
// printf ("object\n");
u16 index = read_u16 ( function . start, & vm -> instruction_pointer );
Constant constant = vm -> program . constant_pool [ index ];
assert ( constant . kind == CONSTANT_CLASS );
assert ( constant . class . member_count < vm -> stack . size );
ObjectValue * obj = create_object ( vm, & constant . class );
for ( size_t i = obj -> member_cnt; i > 0; --i )
obj -> members [ i - 1 ] . value = ostack_pop ( & vm -> stack );
obj -> extends = ostack_pop ( & vm -> stack );
ostack_push ( & vm -> stack, (Value*) obj );
break;
}
case 0x05: {
// printf ("get field\n");
u16 index = read_u16 ( function . start, & vm -> instruction_pointer );
assert ( index < vm -> program . constant_count );
Constant name = vm -> program . constant_pool [ index ];
assert ( name . kind == CONSTANT_STRING );
Value * object = ostack_pop ( & vm -> stack );
assert ( object -> kind == VALUE_OBJECT );
Value ** field = get_object_field ( object, name . string );
assert ( field );
ostack_push ( & vm -> stack, *field );
break;
}
case 0x06: {
// printf ("set field\n");
u16 index = read_u16 ( function . start, & vm -> instruction_pointer );
assert ( index < vm -> program . constant_count );
Constant name = vm -> program . constant_pool [ index ];
assert ( name . kind == CONSTANT_STRING );
Value * value = ostack_pop ( & vm -> stack );
Value * object = ostack_pop ( & vm -> stack );
assert ( object -> kind == VALUE_OBJECT );
Value ** field = get_object_field ( object, name . string );
assert ( field );
*field = value;
ostack_push ( & vm -> stack, value );
break;
}
case 0x07: {
// printf ("method call\n");
u16 index = read_u16 ( function . start, & vm -> instruction_pointer );
u8 arguments = read_byte ( function . start, & vm -> instruction_pointer );
assert ( index < vm -> program . constant_count );
Constant name = vm -> program . constant_pool [ index ];
assert ( name . kind == CONSTANT_STRING );
bc_function_call ( vm, arguments, false, & name . string );
break;
}
case 0x08: {
// printf ("function call\n");
u8 arguments = read_byte ( function . start, & vm -> instruction_pointer );
bc_function_call ( vm, arguments, true, NULL );
break;
}
case 0x09: {
// printf ("set local\n");
u16 index = read_u16 ( function . start, & vm -> instruction_pointer );
assert ( index < local_count );
assert ( vm -> stack . size );
new_frame -> locals [ index ] = ostack_top ( & vm -> stack );
break;
}
case 0x0A: {
// printf ("get local\n");
u16 index = read_u16 ( function . start, & vm -> instruction_pointer );
assert ( index < local_count );
ostack_push ( & vm -> stack, new_frame -> locals [ index ] );
break;
}
case 0x0B: {
// printf ("set global\n");
u16 index = read_u16 ( function . start, & vm -> instruction_pointer );
assert ( index < vm -> program . constant_count );
Constant name = vm -> program . constant_pool [ index ];
assert ( name . kind == CONSTANT_STRING );
Value ** field = get_object_field ( vm -> globals, name . string );
assert ( field );
*field = ostack_top ( & vm -> stack );
break;
}
case 0x0C: {
// printf ("get global\n");
u16 index = read_u16 ( function . start, & vm -> instruction_pointer );
assert ( index < vm -> program . constant_count );
Constant name = vm -> program . constant_pool [ index ];
assert ( name . kind == CONSTANT_STRING );
Value ** field = get_object_field ( vm -> globals, name . string );
assert ( field );
ostack_push ( & vm -> stack, *field );
break;
}
case 0x0D: {
// printf ("cond\n");
i16 offset = (i16) read_u16 ( function . start, & vm -> instruction_pointer );
assert ( (i32) vm -> instruction_pointer >= offset && vm -> instruction_pointer + offset < function . len );
Value * cond = ostack_top ( & vm -> stack );
if ( value_to_bool ( cond ) )
vm -> instruction_pointer += offset;
break;
}
case 0x0E: {
// printf ("jump\n");
i16 offset = (i16) read_u16 ( function . start, & vm -> instruction_pointer );
assert ( (i32) vm -> instruction_pointer >= offset && vm -> instruction_pointer + offset < function . len );
vm -> instruction_pointer += offset;
break;
}
case 0x0F: {
// printf ("ret\n");
Frame * tmp = vm -> local_frame;
vm -> local_frame = tmp -> prev;
vm -> instruction_pointer = tmp -> return_ip;
free ( tmp );
return;
}
default:
// printf ( "%d\n", opcode );
assert ( false );
}
}
}
int vm_interpret ( VM * vm, Str input ) {
parse_program ( & vm -> program, input );
ostack_push ( & vm -> stack, alloc_constant ( vm, vm -> program . entry_point ) );
ObjectValue * obj = create_object ( vm, & vm -> program . globals );
for ( size_t i = 0; i < obj -> member_cnt; ++i )
obj -> members [ i ] . value = make_null ( & vm -> heap );
vm -> globals = (Value*) obj;
bc_function_call ( vm, 0, true, NULL );
//Constant start = vm -> program . constant_pool [ vm -> program . entry_point ];
//u8 opcode;
//size_t addr = f . start - input . str;
//ostack_push ( & vm -> stack, (Value*) vm -> heap . begin );
return 0;
}
#pragma once
#include "parser.h"
#include "heap.h"
#define OPERAND_STACK_INIT_CAPACITY 512
#define FRAME_STACK_CAPACITY 512
//#define READ_BYTE(str,pos) str . str [ *pos++ ]
typedef enum {
CONSTANT_INTEGER,
CONSTANT_BOOLEAN,
CONSTANT_NULL,
CONSTANT_STRING,
CONSTANT_FUNCTION,
CONSTANT_CLASS
// VALUE_ARRAY,
// VALUE_OBJECT,
// VALUE_INVALID
} ConstantType;
typedef struct Class {
u16 member_count;
u16 * members;
} Class;
typedef struct Constant {
ConstantType kind;
union {
i32 integer;
bool boolean;
Str string;
ConstantFunction function;
Class class;
};
} Constant;
typedef struct Program {
u16 constant_count;
Constant * constant_pool;
Class globals;
//size_t entry_point;
u16 entry_point;
} Program;
typedef struct OperandStack {
Value ** elements;
size_t size;
size_t capacity;
} OperandStack;
void ostack_init ( OperandStack * stack );
Value * ostack_pop ( OperandStack * stack );
Value * ostack_top ( OperandStack * stack );
void ostack_push ( OperandStack * stack , Value * value );
void ostack_destroy ( OperandStack * stack );
typedef struct Frame {
struct Frame * prev;
size_t return_ip;
Value * locals [];
} Frame;
typedef struct VM {
Program program;
Heap heap;
OperandStack stack;
Value * globals;
Frame * local_frame;
size_t instruction_pointer;
} VM;
void vm_init ( VM * vm, size_t heap_size );
void vm_destroy ( VM * vm );
// void * heap_alloc_alligned ( Heap * heap, size_t len, size_t align );
// void * heap_alloc ( Heap * heap, size_t len );
// void heap_init ( Heap * heap, size_t heap_size );
// void heap_destroy ( Heap * heap );
// Value * make_null ( ASTInterpreterState * state );
// Value * make_int ( ASTInterpreterState * state, i32 val );
// Value * make_bool ( ASTInterpreterState * state, bool val );
//inline u8 read_byte ( Str str, size_t * pos );
Value * alloc_constant ( VM * vm, u16 index );
ObjectValue * create_object ( VM * vm, Class * class );
void print_operand_value ( Value * value );
void print_call ( VM * vm, u16 index, u8 arguments );
void read_header ( Str input, size_t * pos );
void read_constant_pool ( Program * program, Str input, size_t * pos );
//void read_globals ( Program * program, Str input, size_t * pos );
void parse_program ( Program * program, Str input );
void bc_function_call ( VM * vm, u8 arguments, bool is_function, Str * name );
//void bc_intepret ( VM * vm, Str input, size_t & offset );
int vm_interpret ( VM * vm, Str input );
File moved
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <ctype.h>
#include "arena.h"
#include "parser.h"
#include "ast_interpreter.h"
#include "bc_interpreter.h"
#define AST_INTERPRETER_COMMAND "ast_interpret"
#define BC_INTERPRETER_COMMAND "bc_interpret"
#define RUN "run"
#define HEAP_SIZE_COMMAND "--heap-size"
#define HEAP_LOG_COMMAND "--heap-log"
#define DEFAULT_HEAP_SIZE 128
int main ( int argc, char **argv ) {
if ( argc < 2 ) {
fprintf( stderr, "Input error: expected at least one argument\n" );
return 1;
}
size_t heap_size = DEFAULT_HEAP_SIZE;
char * log_file = NULL;
u8 flag = 0;
u8 ast_interpreter = 0;
u8 bc_interpreter = 0;
size_t len;
int f = -1;
for ( int arg = 1; arg < argc; ++arg ) {
len = strlen ( argv [ arg ] );
for ( size_t j = 0; j < len; j++ )
argv [ arg ] [ j ] = tolower ( argv [ arg ] [ j ] );
if ( len == strlen ( AST_INTERPRETER_COMMAND ) && strncmp ( argv [ arg ], AST_INTERPRETER_COMMAND, len ) == 0 ) {
ast_interpreter = 1;
f = ++arg;
} else if ( len == strlen ( BC_INTERPRETER_COMMAND ) && strncmp ( argv [ arg ], BC_INTERPRETER_COMMAND, len ) == 0 ) {
bc_interpreter = 1;
f = ++arg;
} else if ( len == strlen ( RUN ) && strncmp ( argv [ arg ], RUN, len ) == 0 ) {
ast_interpreter = 1;
for ( size_t opt = 0; opt < 2; ++opt ) {
len = strlen ( argv [ ++arg ] );
if ( len == strlen ( HEAP_SIZE_COMMAND ) && strncmp ( argv [ arg ], HEAP_SIZE_COMMAND, len ) == 0 ) {
heap_size = atoi ( argv [ ++arg ] );
if ( heap_size == 0 ) {
fprintf( stderr, "Input error: invalid heap size %s.\n", argv [ arg ] );
flag = 2;
}
} else if ( len == strlen ( HEAP_LOG_COMMAND ) && strncmp ( argv [ arg ], HEAP_LOG_COMMAND, len ) == 0 ) {
log_file = argv [ ++arg ];
}
}
f = ++arg;
} else {
fprintf( stderr, "Input error: unknown argument %s.\n", argv [ arg ] );
flag = 1;
}
}
if ( flag || f <= 0 )
return 1;
FILE * fp = fopen ( argv [ f ], "r" );
(void) log_file;
if ( ! fp ) {
fprintf ( stderr, "Input error: file does not exists.\n" );
return 1;
}
if ( fseek ( fp, 0, SEEK_END ) ) {
fprintf ( stderr, "Input error: could not advance to the end of the file.\n" );
return 1;
}
int file_len = ftell ( fp );
if ( file_len < 0 ) {
fprintf ( stderr, "Input error: could not count the size of the file.\n" );
return 1;
}
size_t flen = file_len;
rewind ( fp );
u8 * buffer = malloc ( flen );
if ( fread ( buffer, 1, flen, fp ) != flen ) {
fprintf ( stderr, "Input error: could not read to the file.\n" );
return 1;
}
fclose ( fp );
Str file_str = (Str) { .str = buffer, .len = flen };
if ( ast_interpreter ) {
Arena arena;
arena_init( &arena );
Ast *ast = parse_src ( &arena, file_str );
if ( ast == NULL ) {
fprintf ( stderr, "Failed to parse source\n" );
arena_destroy ( &arena );
return 1;
}
ASTInterpreterState state;
Heap heap;
heap_init ( &heap, heap_size * 1024 * 1024 );
state_init ( &state, &heap );
evaluate ( &state, ast );
state_destroy ( &state );
arena_destroy( &arena );
}
if ( bc_interpreter ) {
VM vm;
vm_init ( &vm, heap_size * 1024 * 1024 );
vm_interpret ( &vm, file_str );
vm_destroy ( &vm );
}
free ( buffer );
return 0;
}
#include <stdio.h>
#include "heap.h"
void * heap_alloc_alligned ( Heap * heap, size_t len, size_t align ) {
size_t pos = (size_t) heap -> next;
size_t rem = pos % align;
if ( rem )
heap -> next = heap -> next + align - rem;
if ( heap -> next + len >= heap -> end )
return NULL;
void * ret = heap -> next;
heap -> next += len;
return ret;
}
void * heap_alloc ( Heap * heap, size_t len ) {
size_t pos = (size_t) heap -> next;
size_t rem = pos % 8;
if ( rem )
heap -> next = heap -> next + 8 - rem;
if ( heap -> next + len >= heap -> end )
return NULL;
void * ret = heap -> next;
heap -> next += len;
return ret;
}
void heap_init ( Heap * heap, size_t heap_size ) {
heap -> begin = (u8*) malloc ( heap_size );
heap -> next = heap -> begin;
heap -> end = heap -> begin + heap_size;
}
void heap_destroy ( Heap * heap ) {
free ( heap -> begin );
}
int compare_entry ( const void * a, const void * b ) {
return str_cmp ( ((SimpleEntry*) a) -> name, ((SimpleEntry*) b) -> name );
}
bool value_to_bool ( Value * value ) {
if ( value -> kind == VALUE_NULL )
return false;
if ( value -> kind == VALUE_BOOLEAN )
return ((BoolValue*) value ) -> boolean;
return true;
}
Value * try_operator ( Heap * heap, Value * object, Value ** arguments, size_t argc, Str * name ) {
switch ( object -> kind ) {
case VALUE_INTEGER: {
if ( argc != 1 ) {
fprintf ( stderr, "Invalid argument count for integer operation %.*s.\n", (int) name -> len, name -> str );
exit ( 10 );
}
IntValue * this = (IntValue*) object;
bool is_int = arguments [ 0 ] -> kind == VALUE_INTEGER;
if ( is_int ) {
IntValue * other = (IntValue*) arguments [ 0 ];
if ( str_eq ( *name, STR ("+") ) )
return make_int ( heap, this -> integer + other -> integer );
if ( str_eq ( *name, STR ("-") ) )
return make_int ( heap, this -> integer - other -> integer );
if ( str_eq ( *name, STR ("*") ) )
return make_int ( heap, this -> integer * other -> integer );
if ( str_eq ( *name, STR ("/") ) )
return make_int ( heap, this -> integer / other -> integer );
if ( str_eq ( *name, STR ("%") ) )
return make_int ( heap, this -> integer % other -> integer );
if ( str_eq ( *name, STR ("<=") ) )
return make_bool ( heap, this -> integer <= other -> integer );
if ( str_eq ( *name, STR (">=") ) )
return make_bool ( heap, this -> integer >= other -> integer );
if ( str_eq ( *name, STR ("<") ) )
return make_bool ( heap, this -> integer < other -> integer );
if ( str_eq ( *name, STR (">") ) )
return make_bool ( heap, this -> integer > other -> integer );
if ( str_eq ( *name, STR ("==") ) )
return make_bool ( heap, this -> integer == other -> integer );
if ( str_eq ( *name, STR ("!=") ) )
return make_bool ( heap, this -> integer != other -> integer );
break;
}
if ( str_eq ( *name, STR ("==") ) )
return make_bool ( heap, false );
if ( str_eq ( *name, STR ("!=") ) )
return make_bool ( heap, true );
break;
}
case VALUE_BOOLEAN: {
if ( argc != 1 ) {
fprintf ( stderr, "Invalid argument count for bool operation %.*s.\n", (int) name -> len, name -> str );
exit ( 10 );
}
BoolValue * this = (BoolValue*) object;
bool is_bool = arguments [ 0 ] -> kind == VALUE_BOOLEAN;
if ( is_bool ) {
BoolValue * other = (BoolValue*) arguments [ 0 ];
if ( str_eq ( *name, STR ("&") ) )
return make_bool ( heap, this -> boolean & other -> boolean );
if ( str_eq ( *name, STR ("|") ) )
return make_bool ( heap, this -> boolean | other -> boolean );
if ( str_eq ( *name, STR ("==") ) )
return make_bool ( heap, this -> boolean == other -> boolean );
if ( str_eq ( *name, STR ("!=") ) )
return make_bool ( heap, this -> boolean != other -> boolean );
break;
}
if ( str_eq ( *name, STR ("==") ) )
return make_bool ( heap, false );
if ( str_eq ( *name, STR ("!=") ) )
return make_bool ( heap, true );
break;
}
case VALUE_NULL: {
if ( argc != 1 ) {
fprintf ( stderr, "Invalid amount of arguments for null operation %.*s.\n", (int) name -> len, name -> str );
exit ( 10 );
}
if ( str_eq ( *name, STR ("==") ) )
return make_bool ( heap, arguments [ 0 ] -> kind == VALUE_NULL ? true : false );
if ( str_eq ( *name, STR ("!=") ) )
return make_bool ( heap, arguments [ 0 ] -> kind != VALUE_NULL ? true : false );
break;
}
case VALUE_ARRAY:
if ( str_eq ( *name, STR ("get") ) ) {
if ( argc != 1 || arguments [ 0 ] -> kind != VALUE_INTEGER ) {
fprintf ( stderr, "Invalid argument for array get.\n" );
exit ( 11 );
}
ArrayValue * array = (ArrayValue*) object;
i32 index = ((IntValue*) arguments [ 0 ]) -> integer;
if ( index < 0 || index >= array -> length ) {
fprintf ( stderr, "Index is out of bounds.\n" );
exit ( 11 );
}
return array -> elements [ index ];
}
if ( str_eq ( *name, STR ("set") ) ) {
if ( argc != 2 || arguments [ 0 ] -> kind != VALUE_INTEGER ) {
fprintf ( stderr, "Invalid arguments for array set.\n" );
exit ( 12 );
}
ArrayValue * array = (ArrayValue*) object;
i32 index = ((IntValue*) arguments [ 0 ]) -> integer;
if ( index < 0 || index >= array -> length ) {
fprintf ( stderr, "Index is out of bounds.\n" );
exit ( 12 );
}
array -> elements [ index ] = arguments [ 1 ];
return arguments [ 1 ];
}
break;
default:
break;
}
return NULL;
}
Value * get_base ( Value * object ) {
Value * curr = object;
while ( curr -> kind == VALUE_OBJECT )
curr = ((ObjectValue *) curr) -> extends;
return curr;
}
Value ** get_object_field ( Value * object, Str name ) {
Value * next = object;
ObjectValue * curr;
do {
curr = (ObjectValue*) next;
for ( size_t i = 0; i < curr -> member_cnt; ++i )
if ( str_eq ( curr -> members [ i ] . name, name ) )
return & curr -> members [ i ] . value;
next = curr -> extends;
} while ( next -> kind == VALUE_OBJECT );
return NULL;
}
Value * make_int ( Heap * heap, i32 val ) {
IntValue * value = heap_alloc ( heap, sizeof (IntValue) );
*value = (IntValue) { .kind = (Value) { .kind = VALUE_INTEGER }, .integer = val };
return (Value*) value;
}
Value * make_bool ( Heap * heap, bool val ) {
BoolValue * value = heap_alloc ( heap, sizeof (BoolValue) );
*value = (BoolValue) { .kind = (Value) { .kind = VALUE_BOOLEAN }, .boolean = val };
return (Value*) value;
}
Value * make_function ( Heap * heap, AstFunction * function ) {
FunctionValue * value = heap_alloc ( heap, sizeof (FunctionValue) );
*value = (FunctionValue) { .kind = (Value) { .kind = VALUE_FUNCTION }, .function = function };
return (Value*) value;
}
Value * make_cfunction ( Heap * heap, ConstantFunction function ) {
CFunctionValue * value = heap_alloc ( heap, sizeof (CFunctionValue) );
*value = (CFunctionValue) { .kind = (Value) { .kind = VALUE_FUNCTION }, .function = function };
return (Value*) value;
}
Value * make_array ( Heap * heap, size_t len ) {
ArrayValue * value = heap_alloc ( heap, sizeof (ArrayValue) + len * sizeof (Value*) );
*value = (ArrayValue) { .kind = (Value) { .kind = VALUE_ARRAY }, .length = len };
return (Value*) value;
}
Value * make_object ( Heap * heap, size_t member_cnt ) {
ObjectValue * value = heap_alloc ( heap, sizeof (ObjectValue) + member_cnt * sizeof (SimpleEntry) );
*value = (ObjectValue) { .kind = (Value) { .kind = VALUE_OBJECT }, .member_cnt = member_cnt };
return (Value*) value;
}
Value * make_null ( Heap * heap ) {
NullValue * value = heap_alloc ( heap, sizeof (NullValue) );
*value = (NullValue) { .kind = (Value) { .kind = VALUE_NULL } };
return (Value*) value;
}
#pragma once
#include "parser.h"
typedef enum {
VALUE_INTEGER,
VALUE_BOOLEAN,
VALUE_NULL,
VALUE_FUNCTION,
VALUE_ARRAY,
VALUE_OBJECT,
VALUE_INVALID
} ValueType;
typedef struct Heap {
u8 * begin;
u8 * next;
u8 * end;
} Heap;
typedef struct Value {
ValueType kind;
} Value;
typedef struct SimpleEntry {
Str name;
Value * value;
} SimpleEntry;
typedef struct NullValue {
Value kind;
} NullValue;
typedef struct IntValue {
Value kind;
i32 integer;
} IntValue;
typedef struct BoolValue {
Value kind;
bool boolean;
} BoolValue;
typedef struct FunctionValue {
Value kind;
AstFunction * function;
} FunctionValue;
typedef struct ConstantFunction {
u32 len;
const u8 * start;
u16 locals;
u8 parameters;
} ConstantFunction;
typedef struct CFunctionValue {
Value kind;
ConstantFunction function;
} CFunctionValue;
typedef struct ObjectValue {
Value kind;
Value * extends;
size_t member_cnt;
SimpleEntry members [];
} ObjectValue;
typedef struct ArrayValue {
Value kind;
i32 length;
Value * elements [];
} ArrayValue;
void * heap_alloc_alligned ( Heap * heap, size_t len, size_t align );
void * heap_alloc ( Heap * heap, size_t len );
void heap_init ( Heap * heap, size_t heap_size );
void heap_destroy ( Heap * heap );
int compare_entry ( const void * a, const void * b );
bool value_to_bool ( Value * value );
Value * try_operator ( Heap * heap, Value * object, Value ** arguments, size_t argc, Str * name );
Value * get_base ( Value * object );
Value ** get_object_field ( Value * object, Str name );
Value * make_null ( Heap * heap );
Value * make_int ( Heap * heap, i32 val );
Value * make_bool ( Heap * heap, bool val );
Value * make_function ( Heap * heap, AstFunction * function );
Value * make_cfunction ( Heap * heap, ConstantFunction function );
Value * make_array ( Heap * heap, size_t len );
Value * make_object ( Heap * heap, size_t member_cnt );
File moved
File moved