<commit_before>#include <cstdlib>
#include <cstdio>

#include "parser.h"
#include "../fancy_exception.h"
#include "../utils.h"
#include "../bootstrap/core_classes.h"

/* prototype of bison-generated parser function */
extern int yyparse();
extern void yyrestart(FILE*);
extern yy_buffer_state* yy_create_buffer(FILE*, int);
extern yy_buffer_state* yy_scan_string(const char*);
extern int yy_switch_to_buffer(yy_buffer_state*);
extern int yy_delete_buffer(yy_buffer_state*);

namespace fancy {
  namespace parser {
    
    string current_file;
    stack<parser_buffer> parse_buffers;
    list<string> load_path;
    FancyObject* last_value = nil;

    void parse_file(string &filename)
    {
      // put the path of the file into the load_path vector
      // this makes requiring files in the same directory easier
      string filepath = dirname_for_path(filename);

      // check for file ending
      if(filename_for_path(filename) != "fnc") {
        filename = filename + ".fnc";
      }

      if(!is_whitespace(filepath)) {
        load_path.push_back(filepath);
        load_path.unique(); // remove double entries
      }

      if(push_buffer(filename)) {
        try {
          yyparse();
        } catch(FancyException* ex) {
          errorln("GOT UNCAUGHT EXCEPTION, ABORTING.");
          errorln(ex->to_s());
          exit(1);
        }

        pop_buffer();
      }
    }

    FancyObject* parse_string(const string &code)
    {
      parser_buffer buf;
      buf.buffstate = yy_scan_string(code.c_str());
      buf.lineno = yylineno;
      buf.file = NULL;
      buf.filename = "";

      yylineno = 1;
      yy_switch_to_buffer(buf.buffstate);

      yyparse();

      // delete string buffer
      yy_delete_buffer(buf.buffstate);

      // reset to what we had before
      if(!parse_buffers.empty()) {
        parser_buffer prev = parse_buffers.top();
        yy_switch_to_buffer(prev.buffstate);
        yylineno = prev.lineno;
        current_file = prev.filename;
      }

      // finally, return the last evaluated value
      return last_value;
    }

    void parse_stdin()
    {
      parser_buffer buf;
      buf.buffstate = yy_create_buffer(stdin, YY_BUF_SIZE);
      buf.file = stdin;
      buf.filename = "STDIN";
      buf.lineno = yylineno;
      parse_buffers.push(buf);
      current_file = "STDIN";
      yylineno = 1;
      yy_switch_to_buffer(buf.buffstate);
      // keep it running!
      while(true) {
        try {
          yyparse();
        } catch(FancyException* ex) {
          errorln("GOT UNCAUGHT EXCEPTION, ABORTING.");
          errorln(ex->to_s());
        }
      }
    }

    bool push_buffer(const string &filename)
    {
      parser_buffer buf;
      FILE *f = find_open_file(filename);
      if(!f) {
        error("");
        perror(filename.c_str());
        return false;
      }  
      buf.buffstate = yy_create_buffer(f, YY_BUF_SIZE);
      buf.file = f;
      buf.filename = filename;
      buf.lineno = yylineno;
      parse_buffers.push(buf);<commit_msg>src/parser/parser.cc: Small change to explicitly allow files to not end with the ".fnc" extension (e.g. bin/ifancy)<commit_after>#include <cstdlib>
#include <cstdio>

#include "parser.h"
#include "../fancy_exception.h"
#include "../utils.h"
#include "../bootstrap/core_classes.h"

/* prototype of bison-generated parser function */
extern int yyparse();
extern void yyrestart(FILE*);
extern yy_buffer_state* yy_create_buffer(FILE*, int);
extern yy_buffer_state* yy_scan_string(const char*);
extern int yy_switch_to_buffer(yy_buffer_state*);
extern int yy_delete_buffer(yy_buffer_state*);

namespace fancy {
  namespace parser {
    
    string current_file;
    stack<parser_buffer> parse_buffers;
    list<string> load_path;
    FancyObject* last_value = nil;

    void try_parse()
    {
      try {
        yyparse();
      } catch(FancyException* ex) {
        errorln("GOT UNCAUGHT EXCEPTION, ABORTING.");
        errorln(ex->to_s());
        exit(1);
      }
      pop_buffer();
    }

    void parse_file(string &filename)
    {
      // put the path of the file into the load_path vector
      // this makes requiring files in the same directory easier
      string filepath = dirname_for_path(filename);
      bool has_ending = true;

      // check for file ending
      string filename_with_ending = filename;
      if(filename_for_path(filename) != "fnc") {
        has_ending = false;
        filename_with_ending = filename + ".fnc";
      }

      if(!is_whitespace(filepath)) {
        load_path.push_back(filepath);
        load_path.unique(); // remove double entries
      }

      if(!push_buffer(filename)) {
        // try with file ending, if not given
        if(!has_ending) {
          if(push_buffer(filename_with_ending)) {
            try_parse();
          } else {
            error(filename) << ": No such file or directory\n";
            return;
          }
        } else {
          error(filename) << ": No such file or directory\n";
          return;
        }
      } else {
        try_parse();
      }
    }

    FancyObject* parse_string(const string &code)
    {
      parser_buffer buf;
      buf.buffstate = yy_scan_string(code.c_str());
      buf.lineno = yylineno;
      buf.file = NULL;
      buf.filename = "";

      yylineno = 1;
      yy_switch_to_buffer(buf.buffstate);

      yyparse();

      // delete string buffer
      yy_delete_buffer(buf.buffstate);

      // reset to what we had before
      if(!parse_buffers.empty()) {
        parser_buffer prev = parse_buffers.top();
        yy_switch_to_buffer(prev.buffstate);
        yylineno = prev.lineno;
        current_file = prev.filename;
      }

      // finally, return the last evaluated value
      return last_value;
    }

    void parse_stdin()
    {
      parser_buffer buf;
      buf.buffstate = yy_create_buffer(stdin, YY_BUF_SIZE);
      buf.file = stdin;
      buf.filename = "STDIN";
      buf.lineno = yylineno;
      parse_buffers.push(buf);
      current_file = "STDIN";
      yylineno = 1;
      yy_switch_to_buffer(buf.buffstate);
      // keep it running!
      while(true) {
        try {
          yyparse();
        } catch(FancyException* ex) {
          errorln("GOT UNCAUGHT EXCEPTION, ABORTING.");
          errorln(ex->to_s());
        }
      }
    }

    bool push_buffer(const string &filename)
    {
      parser_buffer buf;
      FILE *f = find_open_file(filename);
      if(!f) {
        // error("");
        // perror(filename.c_str());
        return false;
      }  
      buf.buffstate = yy_create_buffer(f, YY_BUF_SIZE);
      buf.file = f;
      buf.filename = filename;
      buf.lineno = yylineno;
      parse_buffers.push(buf);
{'fraction_non_alphanumeric': 0.11366006256517205, 'fraction_numerical': 0.0008937881722031879, 'mean_word_length': 2.3057607090103396, 'pattern_counts': {'":': 2, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1417916', 'n_tokens_mistral': 2157, 'n_tokens_neox': 2141, 'n_words': 456}