<commit_before>#include <assert.h>

#include "ast.hpp"

#include "parse.hpp"
#include "parse_op.hpp"
#include "parse_decl.hpp"

#include "hash-t.hpp"

// each AST node pushes the result on the top of the stack
//   unless the type is void

namespace AST {

  const NameSpace * DEFAULT_NS = new NameSpace(".default");
  const NameSpace * TAG_NS = new NameSpace(".tag");

  template <typename T>
  void add_ast_nodes(T & container, AST * node);

  void AST::print() {
    printf(" (%s", name_.c_str());
    for (int i = 0; i != parse_->num_args(); ++i) {
      part(i)->print();
    }
    printf(")");
  }

  template <typename T>
  void resolve_to(ResolveEnviron & env, T * & exp, const Type * type) {
    exp = static_cast<T *>(env.type_relation->resolve_to(static_cast<AST *>(exp), type));
  }

  int ct_value(const Parse * p, ParseEnviron & env) {
    // need to convert ids or exps to integers
    // for now require a literal
    if (p->name != "literal")
      throw error(p, "Expected Interger Literal.");
    const char * s = p->arg(0)->name.c_str();
    char * e = (char *)s;
    int value = strtol(s, &e, 10);
    if (s == e) 
      throw error(p->arg(0), "Expected Integer");
    return value;
  }

  AST * parse_top_level(const Parse * p, ParseEnviron & env);
  AST * parse_member(const Parse * p, ParseEnviron & env);
  AST * parse_stmt(const Parse * p, ParseEnviron & env);
  AST * parse_stmt_decl(const Parse * p, ParseEnviron & env);
  AST * parse_exp(const Parse * p, ParseEnviron & env);

  struct NoOp : public AST {
    NoOp() : AST("noop") {}
    AST * parse_self(const Parse * p, ParseEnviron & env) {
      parse_ = p;
      assert_num_args(0);
      type = env.void_type();
      return this;
    }
    void eval(ExecEnviron &) {}
    void compile(CompileWriter & f, CompileEnviron &) {
      f << indent << "noop();\n";
    }
  };

  struct Empty : public AST {
    Empty() : AST("empty") {}
    AST * parse_self(const Parse * p, ParseEnviron & env) {
      parse_ = p;
      assert_num_args(0);
      type = env.void_type();
      return this;
    }
    void eval(ExecEnviron &) {}
    void compile(CompileWriter & f, CompileEnviron &) {
      // do absolutely nothing
    }
  };

  struct Terminal : public AST {
    Terminal(const Parse * p) : AST(p->name, p) {}
    AST * parse_self(const Parse * p, ParseEnviron & env) {abort();}
    void eval(ExecEnviron & env) {abort();}
    void compile(CompileWriter & f, CompileEnviron &) {abort();}
  };

  struct Generic : public AST {
    Vector<AST *> parts;
    Generic(const Parse * p) 
      : AST(p->name, p) {
      for (int i = 0; i != p->num_args(); ++i)
        parts.push_back(new Terminal(p->arg(i)));
    }
    Generic(const Parse * p, const Vector<AST *> & pts) 
      : AST(p->name, p), parts(pts) {}
    AST * part(unsigned i) {return parts[i];}
    AST * parse_self(const Parse*, ParseEnviron&) {abort();}
    void eval(ExecEnviron & env) {abort();}
    void compile(CompileWriter & f, CompileEnviron &) {abort();}
  };

  struct LStmt : public AST {
    LStmt() : AST("lstmt") {}
    bool local;
    String label;
    AST * stmt;
    AST * parse_self(const Parse * p, ParseEnviron & env) {
      parse_ = p;
      assert_num_args(2);
      label = p->arg(0)->arg(0)->name;
      if (p->arg(0)->name == "local") {
        env.labels->add(label, label);
        local = true;
      } else {
        env.labels->root->add(label, label);
      }
      stmt = parse_stmt(p->arg(1), env);
      type = stmt->type;
      return this;
    }
    void eval(ExecEnviron & env) {
      stmt->eval(env);
    }
    void compile(CompileWriter & o, CompileEnviron &) {
      o << adj_indent(-2) << indent << o.label_map->lookup(label) << ":\n";
      o << stmt;
    }
  };

  struct LCStmt : public AST {
    LCStmt() : AST("lcstmt") {}
    AST * exp; 
    AST * stmt;
    AST * parse_self(const Parse * p, ParseEnviron & env) {
      parse_ = p;
      assert_num_args(2);
      if (p->arg(0)->name == "case") {
        exp = parse_exp(p->arg(0)->arg(0), env);
      } else /* default */ {
      }
      stmt = parse_stmt(p->arg(1), env);
      type = stmt->type;
      return this;
    }
    void eval(ExecEnviron & env) {
      stmt->eval(env);
    }
    void compile(CompileWriter & o, CompileEnviron &) {
      if (exp)
        o << adj_indent(-2) << indent << "case " << exp << ":\n";
      else
        o << adj_indent(-2) << indent << "default:\n";
      o << stmt;
    }
    
  };

  struct Goto : public AST {
    Goto() : AST("goto") {}
    String label;
    AST * parse_self(const Parse * p, ParseEnviron & env) {
      parse_ = p;
      assert_num_args(1);
      assert(p->arg(0)->name == "id");
      label = p->arg(0)->arg(0)->name;
      return this;
    }
    // FIXME, move into compile ...
    //void resolve(ResolveEnviron & env) {
    //  if (!env.labels->exists(label))
    //    throw error(parse_->arg(0)->arg(0), "Unknown label %s", ~label);
    //  type = env.void_type();
    //}
    void eval(ExecEnviron&) {abort();}
    void compile(CompileWriter & o, CompileEnviron &) {
      o << indent << "goto " << o.label_map->lookup(label) << ";\n";
    }
  };

  AST * Literal::part(unsigned i) {return new Terminal(parse_->arg(0));}
  
  AST * Literal::parse_self(const Parse * p, ParseEnviron & env) {
    parse_ = p;
    assert_num_args(1,2);
    const char * s = p->arg(0)->name.c_str();
    char * e = (char *)s;
    value = strtol(s, &e, 0);
    if (*e) 
      throw error(p->arg(0), "Expected Integer");
    type = env.types->inst(p->num_args() > 1 ? p->arg(1)->name : "int");
    if (value == 0)
      type = env.types->inst(".zero", type);
    type = env.types->ct_const(type);<commit_msg>Add FIXME note.<commit_after>#include <assert.h>

#include "ast.hpp"

#include "parse.hpp"
#include "parse_op.hpp"
#include "parse_decl.hpp"

#include "hash-t.hpp"

// each AST node pushes the result on the top of the stack
//   unless the type is void

namespace AST {

  const NameSpace * DEFAULT_NS = new NameSpace(".default");
  const NameSpace * TAG_NS = new NameSpace(".tag");

  template <typename T>
  void add_ast_nodes(T & container, AST * node);

  void AST::print() {
    printf(" (%s", name_.c_str());
    for (int i = 0; i != parse_->num_args(); ++i) {
      part(i)->print();
    }
    printf(")");
  }

  template <typename T>
  void resolve_to(ResolveEnviron & env, T * & exp, const Type * type) {
    exp = static_cast<T *>(env.type_relation->resolve_to(static_cast<AST *>(exp), type));
  }

  int ct_value(const Parse * p, ParseEnviron & env) {
    // need to convert ids or exps to integers
    // for now require a literal
    if (p->name != "literal")
      throw error(p, "Expected Interger Literal.");
    const char * s = p->arg(0)->name.c_str();
    char * e = (char *)s;
    int value = strtol(s, &e, 10);
    if (s == e) 
      throw error(p->arg(0), "Expected Integer");
    return value;
  }

  AST * parse_top_level(const Parse * p, ParseEnviron & env);
  AST * parse_member(const Parse * p, ParseEnviron & env);
  AST * parse_stmt(const Parse * p, ParseEnviron & env);
  AST * parse_stmt_decl(const Parse * p, ParseEnviron & env);
  AST * parse_exp(const Parse * p, ParseEnviron & env);

  struct NoOp : public AST {
    NoOp() : AST("noop") {}
    AST * parse_self(const Parse * p, ParseEnviron & env) {
      parse_ = p;
      assert_num_args(0);
      type = env.void_type();
      return this;
    }
    void eval(ExecEnviron &) {}
    void compile(CompileWriter & f, CompileEnviron &) {
      f << indent << "noop();\n";
    }
  };

  struct Empty : public AST {
    Empty() : AST("empty") {}
    AST * parse_self(const Parse * p, ParseEnviron & env) {
      parse_ = p;
      assert_num_args(0);
      type = env.void_type();
      return this;
    }
    void eval(ExecEnviron &) {}
    void compile(CompileWriter & f, CompileEnviron &) {
      // do absolutely nothing
    }
  };

  struct Terminal : public AST {
    Terminal(const Parse * p) : AST(p->name, p) {}
    AST * parse_self(const Parse * p, ParseEnviron & env) {abort();}
    void eval(ExecEnviron & env) {abort();}
    void compile(CompileWriter & f, CompileEnviron &) {abort();}
  };

  struct Generic : public AST {
    Vector<AST *> parts;
    Generic(const Parse * p) 
      : AST(p->name, p) {
      for (int i = 0; i != p->num_args(); ++i)
        parts.push_back(new Terminal(p->arg(i)));
    }
    Generic(const Parse * p, const Vector<AST *> & pts) 
      : AST(p->name, p), parts(pts) {}
    AST * part(unsigned i) {return parts[i];}
    AST * parse_self(const Parse*, ParseEnviron&) {abort();}
    void eval(ExecEnviron & env) {abort();}
    void compile(CompileWriter & f, CompileEnviron &) {abort();}
  };

  struct LStmt : public AST {
    LStmt() : AST("lstmt") {}
    bool local;
    String label;
    AST * stmt;
    AST * parse_self(const Parse * p, ParseEnviron & env) {
      parse_ = p;
      assert_num_args(2);
      label = p->arg(0)->arg(0)->name;
      if (p->arg(0)->name == "local") {
        env.labels->add(label, label);
        local = true;
      } else {
        env.labels->root->add(label, label);
      }
      stmt = parse_stmt(p->arg(1), env);
      type = stmt->type;
      return this;
    }
    void eval(ExecEnviron & env) {
      stmt->eval(env);
    }
    void compile(CompileWriter & o, CompileEnviron &) {
      o << adj_indent(-2) << indent << o.label_map->lookup(label) << ":\n";
      o << stmt;
    }
  };

  struct LCStmt : public AST {
    LCStmt() : AST("lcstmt") {}
    AST * exp; 
    AST * stmt;
    AST * parse_self(const Parse * p, ParseEnviron & env) {
      parse_ = p;
      assert_num_args(2);
      if (p->arg(0)->name == "case") {
        exp = parse_exp(p->arg(0)->arg(0), env);
      } else /* default */ {
      }
      stmt = parse_stmt(p->arg(1), env);
      type = stmt->type;
      return this;
    }
    void eval(ExecEnviron & env) {
      stmt->eval(env);
    }
    void compile(CompileWriter & o, CompileEnviron &) {
      if (exp)
        o << adj_indent(-2) << indent << "case " << exp << ":\n";
      else
        o << adj_indent(-2) << indent << "default:\n";
      o << stmt;
    }
    
  };

  struct Goto : public AST {
    Goto() : AST("goto") {}
    String label;
    AST * parse_self(const Parse * p, ParseEnviron & env) {
      parse_ = p;
      assert_num_args(1);
      assert(p->arg(0)->name == "id");
      label = p->arg(0)->arg(0)->name;
      return this;
    }
    // FIXME, move into compile ...
    //void resolve(ResolveEnviron & env) {
    //  if (!env.labels->exists(label))
    //    throw error(parse_->arg(0)->arg(0), "Unknown label %s", ~label);
    //  type = env.void_type();
    //}
    void eval(ExecEnviron&) {abort();}
    void compile(CompileWriter & o, CompileEnviron &) {
      o << indent << "goto " << o.label_map->lookup(label) << ";\n";
    }
  };

  AST * Literal::part(unsigned i) {return new Terminal(parse_->arg(0));}
  
  AST * Literal::parse_self(const Parse * p, ParseEnviron & env) {
    // FIXME: Need to promote type as indicated in the standard if
    //   the specified type is too small for the literal
    parse_ = p;
    assert_num_args(1,2);
    const char * s = p->arg(0)->name.c_str();
    char * e = (char *)s;
    value = strtol(s, &e, 0);
    if (*e) 
      throw error(p->arg(0), "Expected Integer");
    type = env.types->inst(p->num_args() > 1 ? p->arg(1)->name : "int");
    if (value == 0)
      type = env.types->inst(".zero", type);
    type = env.types->ct_const(type);
{'fraction_non_alphanumeric': 0.17257559958289886, 'fraction_numerical': 0.006256517205422315, 'mean_word_length': 2.530368098159509, 'pattern_counts': {'":': 4, '<': 97, '<?xml version=': 0, '>': 119, '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': '2504904', 'n_tokens_mistral': 4167, 'n_tokens_neox': 4024, 'n_words': 1015}