Skip to content
Snippets Groups Projects
ast_interpreter.c 9.52 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include <stdlib.h>
    #include <stdio.h>
    #include <inttypes.h>
    
    #include "parser.h"
    #include "ast_interpreter.h"
    
    bool value_to_bool ( Value value ) {
      if ( value . kind == VALUE_NULL )
        return false;
      if ( value . kind == VALUE_BOOLEAN )
        return value . boolean;
      return true;
    }
    
    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;
      }
      fprintf ( stderr, "Variable with name %.*s does not exist.\n", (int) name . len, name . str );
      exit ( 1 );
    }
    
    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 ) ) {
          fprintf ( stderr, "Variable with name %.*s already exists.\n", (int) name . len, name . str );
          exit ( 1 );
        }
        parent = entry;
        entry = entry -> next;
      }
      entry = (EnvironmentEntry*) malloc ( sizeof (EnvironmentEntry) );
      (*entry) = (EnvironmentEntry) {.name = name, .value = value, .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;
      }
      // fprintf ( stderr, "Variable with name %.*s does not exist.\n", (int) name . len, name . str );
      // exit ( 1 );
    
    Michal Štěpánek's avatar
    Michal Štěpánek committed
      // return (Value) { .kind = VALUE_NULL };
      env = state -> current_env;
      env = env ? env : & state -> global_env;
      entry = (EnvironmentEntry*) malloc ( sizeof (EnvironmentEntry) );
      (*entry) = (EnvironmentEntry) {.name = name, .value = (Value) { .kind = VALUE_NULL }, .next = env -> start };
      env -> start = entry;
      return entry -> value;
    
    }
    
    void * heap_alloc ( 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 >= 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 );
    }
    
    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;
      }
    }
    
    
    Michal Štěpánek's avatar
    Michal Štěpánek committed
    Value function_call ( ASTInterpreterState * state, Value function, bool is_function, Ast ** arguments, size_t argc ) {
      Value * values = (Value *) malloc ( argc * sizeof (Value) );
      for ( size_t i = 0; i < argc; ++i )
        values [ i ] = evaluate ( state, arguments [ i ] );
      if ( is_function ) {
        if ( function . kind != VALUE_FUNCTION ) {
          fprintf ( stderr, "Invalid calee.\n" );
          exit ( 4 );
        }
        Environment * tmp = state -> current_env;
        state -> current_env = NULL;
        env_push ( state );
        env_def ( state, STR ("this"), (Value) { .kind = VALUE_NULL} );
        for ( size_t i = 0; i < argc; ++i )
          env_def ( state, function . function -> parameters [ i ], values [ i ] );
        Value ret = evaluate ( state, function . function -> body );
        env_pop ( state );
        state -> current_env = tmp;
        return ret;
      }
      return (Value) { .kind = VALUE_NULL };
    }
    
    
    void print_value ( Value value ) {
      switch ( value . kind ) {
        case VALUE_INTEGER:
          printf ( "%" PRIi32, value . integer );
          break;
        case VALUE_BOOLEAN:
          if ( value . boolean )
            printf ( "true" );
          else
            printf ( "false" );
          break;
        case VALUE_NULL:
          printf ( "null" );
          break;
    
    Michal Štěpánek's avatar
    Michal Štěpánek committed
        case VALUE_FUNCTION:
          printf ( "function" );
          break;
    
      }
    }
    
    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 (Value) { .kind = VALUE_INTEGER, .integer = ((AstInteger*) ast ) -> value };
        case AST_BOOLEAN:
          return (Value) { .kind = VALUE_BOOLEAN, .boolean = ((AstBoolean*) ast ) -> value };
        case AST_NULL:
          return (Value) { .kind = VALUE_NULL };
        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 (Value) { .kind = VALUE_NULL };
        }
        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 );
          Value value;
          Ast * cont = value_to_bool ( cond ) ? condAst -> consequent : condAst -> alternative;
          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 (Value) { .kind = VALUE_NULL };
        }
    
    Michal Štěpánek's avatar
    Michal Štěpánek committed
        case AST_FUNCTION:
          return (Value) { .kind = VALUE_FUNCTION, .function = (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 ); 
        }
    
      }
      return (Value) { .kind = VALUE_NULL };
    }