<commit_before>module Malady
  class Parser
    attr_reader :filename

    def initialize(filename)
      @filename = filename
      @line = 0
      @symbols = Hash.new do |hash, key|
        Malady::AST::SymbolNode.new @filename, @line, key
      end
      @symbols = @symbols.merge builtins
    end

    def parse_string(string)
      sexp = Reader.read_str(string)
      program_body = [parse(sexp)]
      Malady::AST::Program.new @filename, @line, program_body
    end

    def parse(sexp)
      type, *rest = sexp
      if type == :list
        symbol = rest.first
        case symbol[1]
        when 'def!'
          parse_def(sexp)
        when 'let*'
          parse_let(sexp)
        else
          fn, *args = parse_sexp(sexp)
          apply(fn, args)
        end
      else
        parse_sexp(sexp)
      end
    end

    def parse_sexp(sexp)
      type, *rest = sexp
      case type
      when :symbol
        @symbols[sexp[1]]
      when :integer
        Malady::AST::IntegerNode.new @filename, @line, sexp[1]
      when :list
        rest.map { |sexp| parse(sexp) }
      end
    end

    def parse_def(sexp)
      # [:list, [:symbol, 'def!'], [:symbol, 'blah'], sexp]
      name = sexp[2][1]
      value = sexp[3]
      Malady::AST::AssignNode.new(@filename, @line, name, parse(value))
    end

    def parse_let(sexp)
      # [:list, [:symbol, 'let'], [:list, [:symbol, 'c'], sexp], sexp]
      bindings = sexp[2][1..-1].each_slice(2).to_a
      body = sexp[3]
      parsed_bindings = bindings.map { |s, val| [s[1], parse(val)] }
      Malady::AST::LetNode.new(@filename, @line, parsed_bindings, parse(body))
    end

    def apply(fn, args)
      fn.new(@filename, @line, *args)
    end

    def builtins
      {
        '+' => Malady::AST::AddNode,
        '-' => Malady::AST::MinusNode,
        '/' => Malady::AST::DivideNode,
        '*' => Malady::AST::MultiplyNode,
        'def!' => Malady::AST::AssignNode
      }
    end

    # the following methods are needed to conform with RBX's parser interface
    def pre_exe<commit_msg>Remove def! from builtins hash<commit_after>module Malady
  class Parser
    attr_reader :filename

    def initialize(filename)
      @filename = filename
      @line = 0
      @symbols = Hash.new do |hash, key|
        Malady::AST::SymbolNode.new @filename, @line, key
      end
      @symbols = @symbols.merge builtins
    end

    def parse_string(string)
      sexp = Reader.read_str(string)
      program_body = [parse(sexp)]
      Malady::AST::Program.new @filename, @line, program_body
    end

    def parse(sexp)
      type, *rest = sexp
      if type == :list
        symbol = rest.first
        case symbol[1]
        when 'def!'
          parse_def(sexp)
        when 'let*'
          parse_let(sexp)
        else
          fn, *args = parse_sexp(sexp)
          apply(fn, args)
        end
      else
        parse_sexp(sexp)
      end
    end

    def parse_sexp(sexp)
      type, *rest = sexp
      case type
      when :symbol
        @symbols[sexp[1]]
      when :integer
        Malady::AST::IntegerNode.new @filename, @line, sexp[1]
      when :list
        rest.map { |sexp| parse(sexp) }
      end
    end

    def parse_def(sexp)
      # [:list, [:symbol, 'def!'], [:symbol, 'blah'], sexp]
      name = sexp[2][1]
      value = sexp[3]
      Malady::AST::AssignNode.new(@filename, @line, name, parse(value))
    end

    def parse_let(sexp)
      # [:list, [:symbol, 'let'], [:list, [:symbol, 'c'], sexp], sexp]
      bindings = sexp[2][1..-1].each_slice(2).to_a
      body = sexp[3]
      parsed_bindings = bindings.map { |s, val| [s[1], parse(val)] }
      Malady::AST::LetNode.new(@filename, @line, parsed_bindings, parse(body))
    end

    def apply(fn, args)
      fn.new(@filename, @line, *args)
    end

    def builtins
      {
        '+' => Malady::AST::AddNode,
        '-' => Malady::AST::MinusNode,
        '/' => Malady::AST::DivideNode,
        '*' => Malady::AST::MultiplyNode,
      }
    end

    # the following methods are needed to conform with RBX's parser interface
    def pre_exe
{'fraction_non_alphanumeric': 0.13967164910561136, 'fraction_numerical': 0.006370987503062975, 'mean_word_length': 2.169254658385093, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 12, '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': '5860028', 'n_tokens_mistral': 1432, 'n_tokens_neox': 1397, 'n_words': 321}