Full Code of alehander42/hivemind for AI

master 8a0727078b56 cached
31 files
42.3 KB
12.7k tokens
149 symbols
1 requests
Download .txt
Repository: alehander42/hivemind
Branch: master
Commit: 8a0727078b56
Files: 31
Total size: 42.3 KB

Directory structure:
gitextract_mc_17_3g/

├── .gitignore
├── .travis.yml
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── bin/
│   └── hivemind
├── examples/
│   ├── a.hm
│   ├── a_paren.hm
│   ├── b.hm
│   ├── shape.hm
│   ├── shape_paren.hm
│   └── shape_pythonic.hm
├── hivemind.gemspec
├── lib/
│   ├── hivemind/
│   │   ├── code_viewer.rb
│   │   ├── combinators.rb
│   │   ├── environment.rb
│   │   ├── errors.rb
│   │   ├── renderer.rb
│   │   ├── runtime.rb
│   │   ├── syntax.rb
│   │   ├── universal_ast.rb
│   │   └── vm.rb
│   └── hivemind.rb
├── spec/
│   ├── hivemind/
│   │   ├── parser_spec.rb
│   │   ├── universal_ast_spec.rb
│   │   └── vm_spec.rb
│   └── spec_helper.rb
└── syntaxes/
    ├── lolcode.syntax
    ├── paren.syntax
    └── pythonic.syntax

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
#Logs
application/logs/*.php

# Content types
/application/xml/types/*.xml

# Custom builds and generated php files
/core/documentation/build
/core/views/admin/content/translations.php

# Attachs and cache files #
*.tmp
/attach/cache/
/attach/
/application/cache/_bancha/*.css
/application/cache/_bancha/*.js

Gemfile.lock
*.pyc
*.doc
*.txt



================================================
FILE: .travis.yml
================================================
language: ruby
rvm:
  - 2.2.3
script:
  - bundle exec rake


================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'

group :development, :test do
  gem 'bundler'
  gem 'rspec'
  gem 'skeptic'
  gem 'rake'
end

================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2016 Alexander Ivanov

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
[![Build Status](https://travis-ci.org/alehander42/hivemind.svg?branch=master)](https://travis-ci.org/alehander42/hivemind)
[![MIT License](http://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

# hivemind

A prototype of a multi-syntax programming language.

Hivemind has a core language defined by its AST and configurable syntaxes acting like plugins.

The concept of "syntax" for hivemind is similar to

* a theme for a text editor
* a skin for a gui app
* a json/html/xml template for a MVC web app

Syntaxes are defined using code-like examples for core ast nodes and they act in a bidirectional way:
  * they are used to parse source code using that syntax
  * and to render code in that syntax
  * **source in each syntax is automatically transltable to another syntax**

Tools for the language would also support representations of source grouped by class or methods or as a graph 

Syntaxes look like that:

A pythonic syntax:

```python
#if_statement
if <test>:
    <true_branch>
else:
    <else_branch>

#assign
<left> = <right>

#call
<function>(<<args:', '>>)

#attribute
<object>.<label>

#attribute_assign
<object>.<label> = <right>

#binary
<left> <operation> <right>

#list
[<<elements:', '>>]

#method_statement
method <method_name>(<<args:', '>>):
    <<body>>

#class_statement
class <class_name>:
    <<methods:''>>

#module_statement
module <module_name>:
    <<elements>>

```

A lisp-like syntax

```
#if_statement
(if <test>
    <true_branch>
    <else_branch>)

#assign
(define <left> <right>)

#method_statement
(method <method_name> (<<args:' '>>)
    <<body>>)

#attribute
<object>.<label>

#attribute_assign
(update <object>.<label> <right>)

#binary
(<operation> <left> <right>)

#call
(! <function> <<args:' '>>)

#list
_(<<elements:' '>>)

#class_statement
(class <class_name>
    <<methods>>)

#module_statement
(module <module_name>
    <<elements>>)
```

# Examples

[pythonic example](examples/shape_pythonic.hm)
[schemelike example](examples/shape_paren.hm)

# Installation

```
gem install hivemind
```

# Usage

Run a file

```bash
hivemind <filename>
```

Translate a file into another syntax representation

```bash
hivemind render a.hm pythonic a2.hm
```

# Goals

* Experiment with diffent syntaxes in different contexts
* Use different sub-language seamlessly across the same codebase
* A possible solution for the expression problem (just convert between different representations)


# Language

The core language is just a simple python/ruby-like language for now.


# History

Created for the HackFMI 5

# Future development

* fluid folder/file structure representations
* editor plugins
* more syntaxes

## License

Copyright 2016 [Alexander Ivanov](https://twitter.com/alehander42)

Distributed under the MIT License.



================================================
FILE: Rakefile
================================================
require 'rubygems'
require 'bundler'
begin
  Bundler.setup(:default, :development)
rescue Bundler::BundlerError => e
  $stderr.puts e.message
  $stderr.puts "Run `bundle install` to install missing gems"
  exit e.status_code
end
require 'rake'

require 'rspec/core'
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec) do |spec|
  spec.pattern = FileList['spec/**/*_spec.rb']
end

task :default => :spec


================================================
FILE: bin/hivemind
================================================
#!/usr/bin/env ruby

$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))

require 'hivemind'

SYNTAXES_PATH = File.join(File.expand_path(File.join(File.dirname(__FILE__), '..')), 'syntaxes')

def astify(source, syntax)
  parser, refs = Hivemind::Syntax.generate_syntax(syntax)
  success, tree, _ = parser.parse(source, refs)
  tree
end

def syntax_file(f)
  File.read(File.join(SYNTAXES_PATH, "#{f}.syntax"))
end

if ARGV.length == 1
  filename = ARGV[0]
  source = File.read(filename)
  syntax_line, _, source = source.partition("\n")
  if !syntax_line.start_with? 'syntax: '
    puts "file doesn't specify a syntax"
    exit 1
  end
  syntax = syntax_file(syntax_line.partition(': ').last)
  tree = astify(source.lstrip, syntax)
  vm = Hivemind::VM.new(tree)
  result = vm.run Hivemind::Runtime::HivemindEnv
elsif ARGV.length == 4
  filename, second_syntax_name, save = ARGV[1..-1]
  source = File.read(filename)
  syntax_line, _, source = source.partition("\n")
  if !syntax_line.start_with? 'syntax: '
    puts "first line of file doesn't specify a syntax"
    exit 1
  end
  first  = syntax_file(syntax_line.partition(': ').last)
  second = syntax_file(second_syntax_name)
  tree = astify(source.lstrip, first)
  result = Hivemind::Renderer.new(tree, second).render
  File.write(save, "syntax: #{second_syntax_name}\n\n#{result}")
else
  puts <<-USAGE
    hivemind <filename>
      runs the file
    hivemind render <filename> <syntax> <new_filename>
      renders the source with <syntax>
  USAGE
end



================================================
FILE: examples/a.hm
================================================
syntax: pythonic

class Object:
    method start(self):
        e = 2
        e.display()


================================================
FILE: examples/a_paren.hm
================================================
syntax: paren

(class Rectangle
    (method init (self a b)
        (update self.a a)
        (update self.b b))

    (method area (self)
        (* self.a self.b)))


================================================
FILE: examples/b.hm
================================================
syntax: pythonic

class Rectangle:
    method init(self, a, b):
        self.a = a
        self.b = b

    method area(self):
        self.a * self.b


================================================
FILE: examples/shape.hm
================================================
syntax: pythonic

class Rectangle:
    method init(self, a, b):
        self.a = a
        self.b = b

    method area(self):
        self.a * self.b

class Circle:
    method init(self, r):
        self.r = r

    method area(self):
        3.14 * self.r * self.r

class Object:
    method start(self):
        e = Rectangle.new(2, 4)
        f = e.area()
        f.display()
        c = Circle.new(4)
        g = c.area()
        g.display()


================================================
FILE: examples/shape_paren.hm
================================================
syntax: paren

(class Rectangle
    (method init (self a b)
        (update self.a a)
        (update self.b b))

    (method area (self)
        (* self.a self.b)))

(class Circle
    (method init (self r)
        (update self.r r))

    (method area (self)
        (* 3.14 (* self.r self.r))))

(class Object
    (method start (self)
        (define e (! Rectangle.new 2 4))
        (define f (! e.area ))
        (! f.display )
        (define c (! Circle.new 4))
    (define g (! c.area ))
        (! g.display )))



================================================
FILE: examples/shape_pythonic.hm
================================================
syntax: pythonic

class Rectangle:
        method init(self, a, b):
        self.a = a
    self.b = b

    method area(self):
        self.a * self.b

class Circle:
        method init(self, r):
        self.r = r

    method area(self):
        3.14 * self.r * self.r

class Object:
        method start(self):
        e = Rectangle.new(2, 4)
    f = e.area()
    f.display()
    c = Circle.new(4)
    g = c.area()
    g.display()



================================================
FILE: hivemind.gemspec
================================================
# Generated by jeweler
# DO NOT EDIT THIS FILE DIRECTLY
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
# -*- encoding: utf-8 -*-
# stub: skeptic 0.0.16 ruby lib

Gem::Specification.new do |s|
  s.name = "hivemind"
  s.version = "0.1"

  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
  s.require_paths = ["lib"]
  s.authors = ["Alexander Ivanov"]
  s.date = "2016-03-12"
  s.description = "A multi-syntax programming language"
  s.email = "alehande42@gmail.com"
  s.executables = ["hivemind"]
  s.extra_rdoc_files = [
    "LICENSE",
    "README.md"
  ]
  s.files = [
    "bin/hivemind",
    "lib/hivemind.rb",
    ".gitignore",
    "Gemfile",
    "LICENSE",
    "README.md",
    "Rakefile",
    "hivemind.gemspec",
    "lib/hivemind/code_viewer.rb",
    "lib/hivemind/combinators.rb",
    "lib/hivemind/environment.rb",
    "lib/hivemind/errors.rb",
    "lib/hivemind/renderer.rb",
    "lib/hivemind/runtime.rb",
    "lib/hivemind/syntax.rb",
    "lib/hivemind/universal_ast.rb",
    "lib/hivemind/vm.rb",
    "spec/spec_helper.rb",
    "spec/hivemind/parser_spec.rb",
    "spec/hivemind/vm_spec.rb",
    "spec/hivemind/universal_ast_spec.rb",
    "syntaxes/pythonic.syntax",
    "syntaxes/lolcode.syntax",
    "syntaxes/paren.syntax"
  ]
  s.homepage = "http://github.com/alehander42/hivemind"
  s.licenses = ["MIT"]
  s.rubygems_version = "2.4.8"
  s.summary = "A multi-syntax language"

  s.add_development_dependency(%q<rspec>, ["= 2.14.1"])
  s.add_development_dependency(%q<bundler>, [">= 0"])
  s.add_development_dependency(%q<skeptic>, [">= 0"])
end



================================================
FILE: lib/hivemind/code_viewer.rb
================================================
#  'universal_ast'

# module Hivemind
#   class CodeViewer
#     def initialize(tree)
#       @tree = tree
#     end

#     def view_as(query)
#       hierarchy = QueryAnalyzer.parse(query)
#       rebuild_tree(hierarchy)
#     end

#     def rebuild_tree(hierarchy)
#       if hierarchy[0].type == @code_view.hierarchy[0].type
#         # only sorting maybe
#         # and sorting still not supported
#         @tree
#       else
#         # method > code
#         new_tree = UniversalAST::Image.new([])
#         top = {}
#         if hierarchy[0].type == :method
#           @tree.statements.each do |statement|
#             statement.methods.each do |method|
#               top[method.method_name.value] ||= {}
#               top[method.method_name.value][statement.class_name.value] = [args, method.body]
#             end
#           end
#         else
#            @tree.statements.each do |statement|
#              statement.body.each do |method|
#                top[method.class_name.value] ||= {}
#                top[method.class_name.value][statement.method_name.value] = [args, method.body]
#              end
#            end
#         end
#       end
#     end
#   end
# end


================================================
FILE: lib/hivemind/combinators.rb
================================================
require_relative 'universal_ast'

class Combinator
  def &(other)
    And.new(self, other)
  end

  def |(other)
    Or.new(self, other)
  end
end

class Lit < Combinator
  attr_reader :value

  def initialize(value)
    @value = value
  end

  def parse(input, refs)
    if input.start_with?(@value)
      [true, @value, input[@value.length.. -1]]
    else
      [false, '', input]
    end
  end
end

class Mat < Combinator
  attr_reader :regex

  def initialize(regex)
    @regex = /\A#{regex}/
  end

  def parse(input, refs)
    match = @regex.match(input)
    if match
      [true, input[0..match.to_s.size - 1], input[match.to_s.size.. -1]]
    else
      [false, '', input]
    end
  end
end

class Binary < Combinator
  attr_accessor :first, :second

  def initialize(first, second)
    @first, @second = first, second
  end
end

class And < Binary
  def parse(input, refs)
    first_success, first_result, remaining = @first.parse(input, refs)
    if first_success
      second_success, second_result, remaining  = @second.parse(remaining, refs)
      if second_success
        return [true, combine(first_result, second_result), remaining]
      end
    end
    [false, [], input]
  end

  def combine(first_result, second_result)
    if @first.is_a?(And)
      first_result + [second_result]
    else
      [first_result, second_result]
    end
  end
end

class Or < Binary
  def parse(input, refs)
    [@first, @second].each do |combinator|
      success, result, remaining = combinator.parse(input, refs)
      return [true, result, remaining] if success
    end
    [false, '', input]
  end
end

class Many < Combinator
  attr_accessor :parser

  def initialize(parser, as: nil)
    @parser = parser
  end

  def parse(input, refs)
    success = true
    remaining = input
    results = []
    while success
      success, result, remaining = @parser.parse(remaining, refs)
      results.push(result) if success
    end
    [true, results, remaining]
  end
end

class Join < Combinator
  attr_accessor :parser, :as

  def initialize(parser, separator, as: nil)
    @parser = parser
    @separator = separator
    @as = as.to_sym
    @separator_parser = Lit.new(@separator) & Mat.new(/ */) #workaround hivemind
    @@depth ||= 0
  end

  def parse(input, refs)
    success = true
    remaining = input
    results = []
    while success
      # puts "#{'  ' * @@depth}BEFORE " + @parser.label.to_s
      # p ["  " * @@depth, remaining]

      # @@depth += 1
      success, result, remaining = @parser.parse(remaining, refs)
      # @@depth -= 1
      # puts "#{'  ' * @@depth}AFTER " + @parser.label.to_s
      # p ["  " * @@depth, success, remaining, results.length]
      # puts

      results.push(result) if success
      if success
        if remaining.start_with? '    (' # fix later
          remaining = "\n#{remaining}"
        end
        success, result, remaining = @separator_parser.parse(remaining, refs)
      end
    end
    [true, results, remaining]
  end
end

class Ref < Combinator
  attr_accessor :label

  def initialize(label, as: nil)
    @label = label
    @as = as
  end

  def parse(input, refs)
    ref_parser = refs[@label.to_sym]
    ref_parser.parse(input, refs)
  end
end

class Maybe < Combinator
  attr_accessor :parser

  def initialize(parser)
    @parser = parser
  end

  def parse(input, refs)
    _, result, remaining = @parser.parse(input, refs)
    [true, result, remaining]
  end
end

class Apply < Combinator
  attr_accessor :parser
  attr_reader :transformation

  def initialize(parser, &transformation)
    @parser, @transformation = parser, transformation
  end

  def parse(input, refs)
    success, result, remaining = @parser.parse(input, refs)
    result = @transformation.call(result) if success
    [success, result, remaining]
  end
end

def literal(value)
  Literal.new(value)
end

def many(combinator)
  Many.new(combinator)
end

def maybe(combinator)
  Maybe.new(combinator)
end

def apply(combinator, &transformation)
  Apply.new(combinator, &transformation)
end

def match(regex)
  Match.new(regex)
end


================================================
FILE: lib/hivemind/environment.rb
================================================
require_relative 'errors'

module Hivemind
  class Environment
    attr_reader :parent, :values, :top
    attr_accessor :current_self

    def initialize(parent, **values)
      @parent, @values, @top = parent, values, (parent.nil? ? values : parent.top)
    end

    def [](key)
      value = fetch key
      return value if value
      raise HivemindMissingNameError.new("#{key} is missing")
    end

    def fetch(key)
      current = self
      until current.nil? || current.values.key?(key)
        current = current.parent
      end
      return current.values[key] unless current.nil?
      nil
    end

    def []=(key, value)
      @values[key] = value
    end
  end
end



================================================
FILE: lib/hivemind/errors.rb
================================================
module Hivemind
  class HivemindMissingNameError < StandardError
  end

  class HivemindAccessError < StandardError
  end
end


================================================
FILE: lib/hivemind/renderer.rb
================================================
require_relative 'syntax'

module Hivemind
  
  BASE_RULES = {
    image: -> element, depth = 0 do
      element.statements.map { |s| render_element(s) }.join("\n")
    end,

    int: -> element, depth = 0 do
      element.value.to_s
    end,

    float: -> element, depth = 0 do
      element.value.to_s
    end,

    string: -> element, depth = 0 do
      '"' + element.value.to_s + '"'
    end,

    name: -> element, depth = 0 do
      element.value.to_s
    end,

    operation: -> element, depth = 0 do
      element.value.to_s
    end
  }

  class Renderer
    def initialize(tree, syntax)
      @tree, @syntax = tree, syntax
      @rules = BASE_RULES.merge(Syntax.load_rules(syntax))
    end

    def render(depth = 0)
      render_element(@tree, depth).gsub(/\n\n+/, "\n\n").gsub(/\)\s+\)/, '))').gsub(/\}\s+\}/, '}}')
    end

    def offset(depth = 0)
      '    ' * depth
    end

    def render_element(element, depth = 0)
      rule = @rules[element.class.name.split('::').last.downcase.gsub('attributeassign', 'attribute_assign').gsub('statement', '_statement').to_sym]
      depth += 1 if element.class.name.end_with?('MethodStatement')
      # p "for #{element.class.name.split('::').last.downcase.gsub('statement', '_statement').to_sym} #{depth}"
      offset(depth) + if rule.is_a?(String)
        render_template rule, element, depth
      elsif rule.is_a?(Proc)
        instance_exec element, depth, &rule
      end
    end

    def render_template(plan, element, depth = 0)
      plan = plan.gsub(/\<\<([a-zA-Z_]+)\:'([^\']*)'\>\>/) do
        element.send(Regexp.last_match[1]).map(&method(:render_element)).join(Regexp.last_match[2])
      end
      # p plan
      plan = plan.gsub(/\<\<([a-zA-Z_]+)\>\>/) do
        element.send(Regexp.last_match[1]).map { |e| render_element(e, depth) }.join("\n")
      end
      p plan
      plan = plan.gsub(/\<([a-zA-Z_]+)\>/) do
        render_element(element.send(Regexp.last_match[1]))
      end
      plan
    end
  end
end


================================================
FILE: lib/hivemind/runtime.rb
================================================
require_relative 'environment'

module Hivemind
  module Runtime
    class HivemindObject
      attr_reader :data, :klass

      def initialize(data, klass)
      	@data, @klass = data, klass
      end
    end

    class HivemindClass
      attr_reader :label, :methods, :parent

      def initialize(label, parent = nil, methods = {})
      	@label, @parent, @methods = label, parent, methods
      end

      def define_hivemind_method(label, &handler)
        @methods[label] = handler
      end

      def dispatch_method(label)
        current = self
        until current.nil? || current.methods.key?(label)
          current = current.parent
        end
        !current ? nil : current.methods[label]
      end
    end

    class HivemindModule
      attr_reader :label, :elements

      def initialize(label, elements = [])
        @elements = elements
      end
    end

    def self.hivemind_string(value)
      HivemindObject.new({_value: value}, HivemindEnv[:String])
    end

    def self.hivemind_numbr(value)
      HivemindObject.new({_value: value}, HivemindEnv[value.is_a?(Fixnum) ? :Int : :Float])
    end

    def self.hivemind_object(data)
      HivemindObject.new(data, HivemindEnv[:Object])
    end

    HivemindEnv = Environment.new(nil, 
      Object: HivemindClass.new('Object')
    )

    HivemindEnv[:Class] = HivemindClass.new('Class', HivemindEnv[:Object])
    HivemindEnv[:String] = HivemindClass.new('String', HivemindEnv[:Object])
    HivemindEnv[:Int] = HivemindClass.new('Int', HivemindEnv[:Object])
    HivemindEnv[:Float] = HivemindClass.new('Float', HivemindEnv[:Object])
    HivemindEnv[:Boolean] = HivemindClass.new('Boolean', HivemindEnv[:Object])
    HivemindEnv[:@true] = HivemindObject.new({}, HivemindEnv[:Boolean])
    HivemindEnv[:NilClass] = HivemindClass.new('NilClass', HivemindEnv[:Object])
    HivemindEnv[:@nil] = HivemindObject.new({}, HivemindEnv[:NilClass])

    HivemindEnv[:Object].define_hivemind_method(:display) do |hivemind_self, *args, env|
      puts hivemind_self.call(hivemind_self.klass.dispatch_method(:to_string), args, env).data[:_value]
    end

    HivemindEnv[:Object].define_hivemind_method(:to_string) do |hivemind_self, *args, env|
      # p hivemind_self
      if [HivemindEnv[:Int], HivemindEnv[:Float], HivemindEnv[:String], HivemindEnv[:Boolean]].include? hivemind_self.klass
        hivemind_string(hivemind_self.data[:_value])
      elsif hivemind_self.klass == HivemindEnv[:NilClass]
        hivemind_string('null')
      else
        y = ''
        i = 0
        y2 = []
        hivemind_self.data.each do |key, value|
          y2 << key.to_s + ':' + value.call(value.klass.dispatch_method(:to_string), [], env).data[:_value].to_s
        end
        y = y2.join(', ') 
        hivemind_string("{#{y}}")
      end
    end
  end
end




================================================
FILE: lib/hivemind/syntax.rb
================================================
require_relative 'combinators'

module Hivemind

  # BaseGrammar = Phoenix::Grammar.new
  # BaseGrammar.rules = {
  #   segment: many(ref(:keyword_structure), as: :elements),
  #   keyword_structure: ref(:module) | ref(:class) | ref(:method),
  #   method: lit('module') & some(ws) & ref(:name, as: :module_name) & 
  #           many(ref(:expr), as: :body),
  #   expr:   ref(:if) | ref(:sequence) | ref(:attribute) | ref(:attribute_assign) |
  #           ref(:assign) | ref(:literal),
  #   sequence: ref(:list) | ref(:dictionary),
  #   list:   lit('[') & join(ref(:expr), ', ', as: :elements) & lit(']'),
  #   dictionary: lit('{') & join(ref(:pair), ', ', as: :elements) & lit('}'),
  #   pair: ref(:expr, as: :key) & some(ws) & '=>' & some(ws) & ref(:expr, as: :value),
  #   attribute: ref(:expr, as: :object, except: :attribute) & '.' & ref(:name, as: :label),
  #   attribute_assign: ref(:expr, as: :object, except: :attribute) & '.' & ref(:name, as: :label) & some(ws) & lit('=') & some(ws) & ref(:expr, as: :right),
  #   assign: ref(:name, as: :left) & some(ws) & lit('=') & some(ws) & ref(:expr, as: :right),
  #   literal: ref(:string) | ref(:boolean) | ref(:nil_literal) | ref(:number) | ref(:name)
  #   name: regex(/[a-zA-Z_]+/, as: :value),
  #   string: lit('"') & regex(/[^"]*/, as: :value) + lit('"'),
  #   number: regex(/[0-9]+(\.[0-9]+)?/, as: :value),
  #   boolean: ref(:true_literal) | ref(:false_literal),
  #   true_literal: 'true',
  #   false_literal: 'false',
  #   nil_literal: 'nil',
  #   :if => lit('if') & some(ws) & ref(:expr, as: :test) & lit(':') & nl & indent & join(ref(:expr), "\n", as: :true_branch) &
  #          nl & dedent & lit('else') & lit(':') & nl & indent & join(ref(:expr), "\n", as: :else_branch) & nl & dedent,
  #   :class => lit('class') & some(ws) & ref(:name, as: :class_name) &
  #             many(ref(:ex)

  # }


  TYPES = {
    assign: {
      left: :name,
      right: :expr
    },

    attribute: {
      object: :expr_no_attr,
      label: :name_or_attr
    },

    image: {
      statements: :class_statement
    },

    binary: {
      left: :expr_no_binary,
      operation: :operation,
      right: :expr
    },

    attribute_assign: {
      object: :expr_no_attr,
      label: :name_or_attr,
      right: :expr
    },

    call: {
      function: :expr_no_call,
      args: :expr
    },

    list: {
      elements: :expr
    },

    dictionary: {
      pair: :pair
    },

    pair: {
      key: :string,
      value: :expr
    },

    method_statement: {
      method_name: :name,
      args: :name,
      body: :expr
    },

    class_statement: {
      class_name: :name,
      methods: :method_statement
    },

    module_statement: {
      module_name: :name,
      elements: :statement
    },

    if_statement: {
      test: :expr,
      true_branch: :expr,
      else_branch: :expr
    }
  }

  class Syntax
    def self.generate_syntax(bidirectional_grammar)
      new(bidirectional_grammar).generate
    end

    def initialize(grammar)
      @grammar_source = grammar
    end

    def generate
      # parse grammar
      # combine into base grammar
      rules = self.class.load_rules(@grammar_source)
      refs = {}

      rules.each do |name, rule|
        refs[:"_#{name}"] = parse_rule rule, TYPES[name]
      end

      [REFS[:image], REFS.merge(refs)]
    end

    def parse_rule(rule, types)
      parsers = []
      tokens = []
      token = ''
      i = 0
      while i < rule.length
        z = rule[i]
        if '<>'.include?(z)
          tokens << token unless token.empty?
          token = ''
          if z == '>'
            if rule[i + 1] == '>'
              tokens << '>>'
              i += 1
            else
              tokens << '>'
            end
          elsif z == '<'
            if rule[i + 1] == '<'
              tokens << '<<'
              i += 1
            else
              tokens << '<'
            end
          end
        elsif z == "'"
          tokens << token unless token.empty?
          token = ''
          j = i
          i += 1
          while rule[i] != "'"
            i += 1
          end
          tokens << rule[j..i]
        elsif z == ' '
          tokens << token unless token.empty?
          token = ''
          j = i
          while rule[i] == ' '
            i += 1
          end
          tokens << rule[j..i - 1]
          i -= 1
        elsif z == "\n"
          tokens << token unless token.empty?
          tokens << "\n"
        elsif z.match /[a-zA-Z_0-9]/
          token += z
        else
          tokens << token unless token.empty?
          token = ''
          tokens << z
        end
        i += 1
      end
      tokens << token unless token.empty?

      r = 0
      in_var = false

      tokens.each_with_index do |token, i|
        if token == '>>'
          if tokens[i - 2] == ':'
            parsers << Join.new(
                Ref.new(types[tokens[i - 3].to_sym]),
                tokens[i - 1][1..-2], as: tokens[i - 3])
          else
            parsers << Join.new(Ref.new(types[tokens[i - 1].to_sym]), "\n#{'    ' * r}", as: tokens[i - 1])
            #Many.new(Ref.new(types[tokens[i - 1].to_sym]), as: tokens[i - 1])
          end
          in_var = false
        elsif token == '>'
          parsers << Ref.new(types[tokens[i - 1].to_sym])
          in_var = false
        elsif token == "\n"
          parsers << Ref.new(:nl)
          if tokens[i + 1] == "\n"
            e = 2
          elsif tokens[i + 1]
            match = tokens[i + 1].match /([    ]+)/
            if match.nil? || match.captures.empty?
              indent = 0
            else
              indent = match.captures.first.size / 4
            end
            if indent > r
              parsers << Ref.new(:indent)
            elsif indent < r
              parsers << Ref.new(:dedent)
            end
            r = indent
          end 
        elsif token.match(/\A +\z/) 
          parsers << Ref.new(:ws)
        elsif (token == '<<' || token == '<') && tokens[i + 1] >= 'a' && tokens[i + 1] <= 'z'
          in_var = true
        elsif !in_var 
          parsers << Lit.new(token)
        end
      end
      # parsers.map { |pa| puts pa.inspect }
      parsers.reduce(:&)
    end

    def self.load_rules(grammar)
      lines = grammar.split("\n")
      rules = {}
      current_rule = nil
      rule_body = []
      lines.each do |line|
        if line.start_with? '#'
          if not current_rule.nil?
            rule_body << "\n" if rule_body.length > 1
            rules[current_rule.to_sym] = rule_body.join("\n")
            rule_body = []
          end
          current_rule = line[1..-1].strip
        elsif line.strip != ''
          rule_body << line
        end
      end
      rule_body << "\n" if rule_body.length > 1
      rules[current_rule.to_sym] = rule_body.join("\n")
      rules
    end
  end
  
  Name = UniversalAST::Name
  Number = UniversalAST::Number
  Assign = UniversalAST::Assign
  Element = UniversalAST::Element
  Call = UniversalAST::Call
  List = UniversalAST::List
  Dictionary = UniversalAST::Dictionary
  Pair = UniversalAST::Pair
  Attribute = UniversalAST::Attribute
  AttributeAssign = UniversalAST::AttributeAssign
  IfStatement = UniversalAST::IfStatement
  MethodStatement = UniversalAST::MethodStatement
  ClassStatement = UniversalAST::ClassStatement
  Image = UniversalAST::Image
  Operation = UniversalAST::Operation
  Float = UniversalAST::Float
  Int = UniversalAST::Int

  REFS = {
    name: Apply.new(Mat.new(/[a-zA-Z][a-zA-Z_]*/)) do |result|
      Name.new(result.to_sym)
    end,
    
    image: Apply.new(Join.new(Ref.new(:class_statement), "", as: :statements)) do |children|
      # d = children.select { |child| child.is_a?(MethodStatement) }
      e = children.select { |child| child.is_a?(ClassStatement) }
      # obj = e.find { |element| element.is_a?(ClassStatement) && element.class_name == :Object }
      # p e[0].class_name
      # if obj.nil? && !d.empty?
      #   obj = ClassStatement.new(Name.new(:Object), d)
      #   e << obj
      # elsif obj
      #   obj.methods += d
      # end
      Image.new(e)
    end,

    statement: Ref.new(:module_statement) | Ref.new(:class_statement) | Ref.new(:method_statement), 

    number: Ref.new(:float) | Ref.new(:int),

    float: Apply.new(Mat.new(/[0-9]+\.[0-9]+/)) do |result|
      Float.new(result.to_f)
    end,

    int: Apply.new(Mat.new(/[0-9]+/)) do |result|
      Int.new(result.to_i)
    end,

    string: Apply.new(Mat.new(/\"[^\"]*\"/)) do |result|
      String.new(result[1..-2])
    end,

    ws: Mat.new(/ +/),

    nl: Mat.new(/\n*/),

    indent: Lit.new(''),

    dedent: Lit.new(''),

    expr: Ref.new(:attribute_assign) | Ref.new(:assign) | Ref.new(:binary) | Ref.new(:call) | Ref.new(:attribute) | Ref.new(:number) | Ref.new(:name) | Ref.new(:string),

    expr_no_attr: Ref.new(:number) | Ref.new(:nil) | Ref.new(:name) | Ref.new(:string),

    expr_no_call: Ref.new(:binary) | Ref.new(:attribute) | Ref.new(:number) | Ref.new(:name) | Ref.new(:string),

    nil: Lit.new('nil'),

    name_or_attr: Ref.new(:name) | Ref.new(:attribute), 

    assign: Apply.new(Ref.new(:_assign)) do |results|
      Assign.new(*results.select { |r| r.is_a?(Element) })
    end,

    attribute_assign: Apply.new(Ref.new(:_attribute_assign)) do |results|
      AttributeAssign.new(*results.select { |r| r.is_a?(Element) })
    end,

    call: Apply.new(Ref.new(:_call)) do |results|
      function, args = results.select { |r| r.is_a?(Element) || r.is_a?(Array) }
      Call.new(function, args)
    end,

    list: Apply.new(Ref.new(:_list)) do |results|
      List.new(results[1])
    end,

    dictionary: Apply.new(Ref.new(:_dictionary)) do |results|
      Dictionary.new(results[1])
    end,

    pair: Apply.new(Ref.new(:_pair)) do |results|
      key, value = results.select { |r| r.is_a?(Element) }
      Pair.new(key, value)
    end,

    binary: Apply.new(Ref.new(:_binary)) do |results|
      if results[0].is_a?(String)
        results = results[1..-1]
      end
      # detect operation intelligently
      tokens = results[0], results[2], results[4]      
      if tokens[0].is_a?(UniversalAST::Operation)
        operation, left, right = tokens
      elsif tokens[1].is_a?(UniversalAST::Operation)
        left, operation, right = tokens
      else
        left, right, operation = tokens
      end
      # p results
      UniversalAST::Binary.new(left, operation, right)
    end,

    expr_no_binary: Ref.new(:attribute) | Ref.new(:number) | Ref.new(:name) | Ref.new(:string),

    operation: Apply.new(Lit.new('+') | Lit.new('-') | Lit.new('**') | Lit.new('/') | Lit.new('*') | Lit.new('||')) do |result|
      Operation.new(result)
    end, 

    attribute: Apply.new(Ref.new(:_attribute)) do |results|
      object, label = results.select { |r| r.is_a?(Element) }
      Attribute.new(object, label)
    end, 

    if_statement: Apply.new(Ref.new(:_if_statement)) do |results|
      test, true_branch, else_branch = results.select { |r| r.is_a?(Element) || r.is_a?(Array) }
      IfStatement.new(test, true_branch, else_branch)
    end,

    method_statement: Apply.new(Ref.new(:_method_statement)) do |results|
      method_name, args, body = results.select { |r| r.is_a?(Element) || r.is_a?(Array) }
      MethodStatement.new(method_name, args, body)
    end,
    
    class_statement: Apply.new(Ref.new(:_class_statement)) do |results|
      class_name, methods = results.select { |r| r.is_a?(Element) || r.is_a?(Array) }
      ClassStatement.new(class_name, methods)
    end,

    module_statement: Apply.new(Ref.new(:_module_statement)) do |results|
      module_name, classes = results.select { |r| r.is_a?(Element) || r.is_a?(Array) }
      ModuleStatement.new(module_name, classes)
    end
  }

end







================================================
FILE: lib/hivemind/universal_ast.rb
================================================
module Hivemind
  module UniversalAST
    class Element
      def self.fields(*labels)
        define_method(:initialize) do |*args|
          args.zip(labels).each do |arg, label|
            instance_variable_set "@#{label}", arg
          end
        end
        attr_reader *labels
      end

      def offset(depth)
        '    ' * depth
      end
    end

    class IfStatement < Element
      # if <test>:
      #   <<true-branch>>
      # else:
      #   <<else-branch>>

      fields :test, :true_branch, :else_branch

      def render(depth = 0)
        "#{offset(depth)}If\n#{offset(depth + 1)}#{@test.render(depth + 1)}\n"
        "#{@true_branch.render(depth + 1)}\n#{@else_branch.render(depth + 1)}\n"
      end
    end

    class Assign < Element
      # <left> = <right>

      fields :left, :right

      def render(depth = 0)
        "#{offset(depth)}Assign left: #{@left.render} right: #{@right.render}"
      end
    end

    class Attribute < Element
      # <object>.<label>

      fields :object, :label

      def render(depth = 0)
        "#{offset(depth)}Attribute : #{@object.render} #{@label.render}"
      end
    end

    class AttributeAssign < Element
      # <object>.<label> = <right>

      fields :object, :label, :right

      def render(depth = 0)
        "#{offset(depth)}AttributeAssign : #{@object.render} #{@label.render} #{@right.render}"
      end
    end

    class Call < Element
      # <function>(<<args:', '>>)

      fields :function, :args

      def render(depth = 0)
        "#{offset(depth)}Call\n#{@function.render(depth + 1)}\n#{offset(depth + 1)}#{@args.map(&:render).join(' ')}\n"
      end
    end

    class List < Element
      # [el1, el2..]

      fields :elements

      def render(depth = 0)
        "#{offset(depth)}List\n#{@elements.map { |e| e.render(depth + 1) }.join("\n")}"
      end
    end

    class Dictionary < Element
      # {key1: val1, key2: val2..}

      fields :pairs
    end

    class Binary < Element
      # <left> <operation> <right>

      fields :left, :operation, :right

      def render(depth = 0)
        "#{offset(depth)}Binary #{@left.render} #{@operation.value} #{@right.render}"
      end
    end

    class MethodStatement < Element
      # method <method-name>(<<args:', '):
      #   <<body>>

      fields :method_name, :args, :body

      def render(depth = 0)
        "#{offset(depth)}MethodStatement #{@method_name.value} #{@args.map(&:render).join(' ')}\n" +
        "#{@body.map { |e| e.render(depth + 1) }.join("\n")}\n"
      end
    end

    class ClassStatement < Element
      # type <class-name>:
      #   <<methods>>

      fields :class_name, :methods

      def render(depth = 0)
        "#{offset(depth)}ClassStatement #{@class_name.value}\n" + 
        "#{@methods.map { |e| e.render(depth + 1) }.join("\n")}\n"
      end
    end

    class Value < Element
      fields :value

      def render(depth = 0)
        "#{offset(depth)}#{@value}"
      end
    end

    class Name < Value
    end

    class String < Value
    end

    class Number < Value
    end

    class Int < Number
    end

    class Float < Number
    end

    class Operation < Value
    end

    class ModuleStatement < Element
      # module <module-name>:
      #   <<children>>

      fields :module_name, :elements
    end

    class Pair < Element
      # key => value
      fields :key, :value
    end

    class Image < Element
      fields :statements

      def render(depth = 0)
        @statements.map(&:render).join "\n"
      end
    end
  end
end



================================================
FILE: lib/hivemind/vm.rb
================================================
require_relative 'runtime'
require_relative 'universal_ast'

module Hivemind
  class VM
    def initialize(ast)
      @ast = ast
    end

    def run(env)
      @ast.run env
    end
  end

  class Runtime::HivemindObject
    def call(function, args, env)
      if function.is_a?(UniversalAST::MethodStatement)
        args_values = {:self => self}
        function.args[1..-1].zip(args) do |label, arg|
          args_values[label.value.to_sym] = arg
        end
        body_env = Environment.new(env, **args_values)
        function.body.map { |expr| expr.run(body_env) }[-1] || env.top[:@nil]
      else
        function.call self, *args, env
      end
    end
  end

  class Runtime::HivemindClass
    def call(function, args, env)
      h = Runtime::HivemindObject.new({}, self)
      function = dispatch_method(:init)
      if function.is_a?(UniversalAST::MethodStatement)
        args_values = {:self => h}
        function.args[1..-1].zip(args) do |label, arg|
          args_values[label.value.to_sym] = arg
        end
        body_env = Environment.new(env, **args_values)
        function.body.map { |expr| expr.run(body_env) }[-1] || env.top[:@nil]
      else
        function.call h, *args, env
      end
      h
    end
  end
    
  module UniversalAST
    class Image
      def run(env)
        @statements.each do |statement|
          statement.run(env)
        end
        # puts env.top[:Object].methods.keys
        if env.top[:Object].methods.key? :start
          weird_object = Runtime::hivemind_object({})
          weird_object.call(env.top[:Object].methods[:start], [], env)
        else
          env.top[:@nil]
        end
      end
    end

    class ModuleStatement
      def run(env)
        module_statement = Runtime::HivemindModule.new(@module_name)
        @statements.each do |statement|
          module_statement.elements[@statement.is_a?(ModuleStatement) ? @statement.module_name : @statement.class_name] =
            statement.run(env)
        end
        env
      end
    end

    class If
      def run(env)
        if @test.run(env) == env.top[:@true]
          @true_branch.run env
        else
          @else_branch.run env
        end
      end
    end

    class Assign
      def run(env)
        env[@left.value.to_sym] = @right.run(env)
      end
    end

    class Attribute
      def run(env)
        obj = @object.run(env)
        env.current_self = obj

        if obj.respond_to?(:data) 
          if obj.data.key? @label.value
            obj.data[@label.value]
          else
            method = obj.klass.dispatch_method(@label.value)
            if method
              method
            else
              raise HivemindAccessError.new("No #{@label.value} in obj")
            end
          end
        else
          obj.methods[@label.value]
        end
      end
    end

    class AttributeAssign
      def run(env)
        @object.run(env).data[@label.value] = @right.run(env)
      end
    end

    class Call
      def run(env)
        if !@function.is_a?(Attribute)
          function = @function.run(env)
          env.current_self.call(function, @args.map { |arg| arg.run(env) }, env)
        elsif @function.label.value != :new
          obj = @function.object.run(env)
          function = obj.klass.dispatch_method(@function.label.value)
          obj.call(function, @args.map { |arg| arg.run(env) }, env)
        else
          obj = @function.object.run(env)
          function == obj.dispatch_method(:init)
          obj.call(function, @args.map { |arg| arg.run(env) }, env)
        end
      end
    end

    class Binary
      def run(env)
        Runtime::hivemind_numbr(@left.run(env).data[:_value].send(@operation.value, @right.run(env).data[:_value]))
      end
    end

    class List
      def run(env)
        Runtime::HivemindObject.new({_elements: @elements.map { |elem| elem.run(env) }}, env.top[:List])
      end
    end

    class Dictionary
      def run(env)
        dict = {}
        @pairs.each do |pair|
          dict[pair.key.value.to_sym] = pair.value.run(env)
        end
        Runtime::HivemindObject.new({_dict: dict}, env.top[:Dict])
      end
    end

    class Value
      def run(env)
        Runtime::HivemindObject.new({_value: @value}, env.top[self.class.name.split('::').last.to_sym])
      end
    end

    class ClassStatement
      def run(env)
        definition = env.fetch(@class_name.value) || Runtime::HivemindClass.new(@class_name.value, env.top[:Object], {})
        @methods.each do |method|
          definition.methods[method.method_name.value] = method
        end
        env[@class_name.value] = definition
      end
    end

    class MethodStatement
      def run(env)
        self
      end
    end

    class Name
      def run(env)
        env[@value]
      end
    end
  end
end


================================================
FILE: lib/hivemind.rb
================================================
require_relative 'hivemind/universal_ast'
require_relative 'hivemind/environment'
require_relative 'hivemind/vm'
require_relative 'hivemind/runtime'
require_relative 'hivemind/syntax'
require_relative 'hivemind/renderer'


================================================
FILE: spec/hivemind/parser_spec.rb
================================================


================================================
FILE: spec/hivemind/universal_ast_spec.rb
================================================
require 'spec_helper'

module Hivemind
  module UniversalAST
    describe Element do
      it 'fields initializes a class with given labels' do
        class A < Element
          fields :a
        end
        
        expect(A.new(2).a).to eq(2)
      end
    end
    
    describe ModuleStatement do
      it 'is initialized with an elements attribute' do
        mod = ModuleStatement.new('ha', [])
        expect(mod.elements).to eq([])
      end
    end
  end
end


================================================
FILE: spec/hivemind/vm_spec.rb
================================================
require 'spec_helper'

module Hivemind
  describe VM do
    it 'should work for a program with a single number' do
      vm = VM.new UniversalAST::Number.new(44)
      expect(vm.run(Runtime::HivemindEnv).data[:_value]).to eq 44
    end
  end
end


================================================
FILE: spec/spec_helper.rb
================================================
# well, really, no time for a lot of tests now
# dirty fast prototyping

$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'rspec'
require 'hivemind'


================================================
FILE: syntaxes/lolcode.syntax
================================================
#if_statement
<test> O RLY
    YA RLY
    <<true_branch>>
    NO WAI
    <<else_branch>>


#assign
DO <left> <right>

#method_statement
HOW DUZ I <method_name>(<<args:' '>>)
    <<body>>
IF U SAY SO

#attribute
<object> HEY <label>

#attribute_assign
<object> BE <label> <right>

#call
GIMME <function> (<<args:' '>>)

#class_statement
TOM SAYS <class_name>
    <<methods>>
LOVE

#module_statement
HAI <module_name>
    <<elements>>
KTHXBYE


================================================
FILE: syntaxes/paren.syntax
================================================
#if_statement
(if <test>
    <true_branch>
    <else_branch>)

#assign
(define <left> <right>)

#method_statement
(method <method_name> (<<args:' '>>)
    <<body>>)

#attribute
<object>.<label>

#attribute_assign
(update <object>.<label> <right>)

#binary
(<operation> <left> <right>)

#call
(! <function> <<args:' '>>)

#list
_(<<elements:' '>>)

#class_statement
(class <class_name>
    <<methods>>)

#module_statement
(module <module_name>
    <<elements>>)


================================================
FILE: syntaxes/pythonic.syntax
================================================
#if_statement
if <test>:
    <true_branch>
else:
    <else_branch>

#assign
<left> = <right>

#call
<function>(<<args:', '>>)

#attribute
<object>.<label>

#attribute_assign
<object>.<label> = <right>

#binary
<left> <operation> <right>

#list
[<<elements:', '>>]

#method_statement
method <method_name>(<<args:', '>>):
    <<body>>

#class_statement
class <class_name>:
    <<methods:''>>

#module_statement
module <module_name>:
    <<elements>>

Download .txt
gitextract_mc_17_3g/

├── .gitignore
├── .travis.yml
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── bin/
│   └── hivemind
├── examples/
│   ├── a.hm
│   ├── a_paren.hm
│   ├── b.hm
│   ├── shape.hm
│   ├── shape_paren.hm
│   └── shape_pythonic.hm
├── hivemind.gemspec
├── lib/
│   ├── hivemind/
│   │   ├── code_viewer.rb
│   │   ├── combinators.rb
│   │   ├── environment.rb
│   │   ├── errors.rb
│   │   ├── renderer.rb
│   │   ├── runtime.rb
│   │   ├── syntax.rb
│   │   ├── universal_ast.rb
│   │   └── vm.rb
│   └── hivemind.rb
├── spec/
│   ├── hivemind/
│   │   ├── parser_spec.rb
│   │   ├── universal_ast_spec.rb
│   │   └── vm_spec.rb
│   └── spec_helper.rb
└── syntaxes/
    ├── lolcode.syntax
    ├── paren.syntax
    └── pythonic.syntax
Download .txt
SYMBOL INDEX (149 symbols across 10 files)

FILE: lib/hivemind/combinators.rb
  class Combinator (line 3) | class Combinator
    method & (line 4) | def &(other)
    method | (line 8) | def |(other)
  class Lit (line 13) | class Lit < Combinator
    method initialize (line 16) | def initialize(value)
    method parse (line 20) | def parse(input, refs)
  class Mat (line 29) | class Mat < Combinator
    method initialize (line 32) | def initialize(regex)
    method parse (line 36) | def parse(input, refs)
  class Binary (line 46) | class Binary < Combinator
    method initialize (line 49) | def initialize(first, second)
  class And (line 54) | class And < Binary
    method parse (line 55) | def parse(input, refs)
    method combine (line 66) | def combine(first_result, second_result)
  class Or (line 75) | class Or < Binary
    method parse (line 76) | def parse(input, refs)
  class Many (line 85) | class Many < Combinator
    method initialize (line 88) | def initialize(parser, as: nil)
    method parse (line 92) | def parse(input, refs)
  class Join (line 104) | class Join < Combinator
    method initialize (line 107) | def initialize(parser, separator, as: nil)
    method parse (line 115) | def parse(input, refs)
  class Ref (line 142) | class Ref < Combinator
    method initialize (line 145) | def initialize(label, as: nil)
    method parse (line 150) | def parse(input, refs)
  class Maybe (line 156) | class Maybe < Combinator
    method initialize (line 159) | def initialize(parser)
    method parse (line 163) | def parse(input, refs)
  class Apply (line 169) | class Apply < Combinator
    method initialize (line 173) | def initialize(parser, &transformation)
    method parse (line 177) | def parse(input, refs)
  function literal (line 184) | def literal(value)
  function many (line 188) | def many(combinator)
  function maybe (line 192) | def maybe(combinator)
  function apply (line 196) | def apply(combinator, &transformation)
  function match (line 200) | def match(regex)

FILE: lib/hivemind/environment.rb
  type Hivemind (line 3) | module Hivemind
    class Environment (line 4) | class Environment
      method initialize (line 8) | def initialize(parent, **values)
      method [] (line 12) | def [](key)
      method fetch (line 18) | def fetch(key)
      method []= (line 27) | def []=(key, value)

FILE: lib/hivemind/errors.rb
  type Hivemind (line 1) | module Hivemind
    class HivemindMissingNameError (line 2) | class HivemindMissingNameError < StandardError
    class HivemindAccessError (line 5) | class HivemindAccessError < StandardError

FILE: lib/hivemind/renderer.rb
  type Hivemind (line 3) | module Hivemind
    class Renderer (line 31) | class Renderer
      method initialize (line 32) | def initialize(tree, syntax)
      method render (line 37) | def render(depth = 0)
      method offset (line 41) | def offset(depth = 0)
      method render_element (line 45) | def render_element(element, depth = 0)
      method render_template (line 56) | def render_template(plan, element, depth = 0)

FILE: lib/hivemind/runtime.rb
  type Hivemind (line 3) | module Hivemind
    type Runtime (line 4) | module Runtime
      class HivemindObject (line 5) | class HivemindObject
        method initialize (line 8) | def initialize(data, klass)
      class HivemindClass (line 13) | class HivemindClass
        method initialize (line 16) | def initialize(label, parent = nil, methods = {})
        method define_hivemind_method (line 20) | def define_hivemind_method(label, &handler)
        method dispatch_method (line 24) | def dispatch_method(label)
      class HivemindModule (line 33) | class HivemindModule
        method initialize (line 36) | def initialize(label, elements = [])
      function hivemind_string (line 41) | def self.hivemind_string(value)
      function hivemind_numbr (line 45) | def self.hivemind_numbr(value)
      function hivemind_object (line 49) | def self.hivemind_object(data)

FILE: lib/hivemind/syntax.rb
  type Hivemind (line 3) | module Hivemind
    class Syntax (line 104) | class Syntax
      method generate_syntax (line 105) | def self.generate_syntax(bidirectional_grammar)
      method initialize (line 109) | def initialize(grammar)
      method generate (line 113) | def generate
      method parse_rule (line 126) | def parse_rule(rule, types)
      method load_rules (line 230) | def self.load_rules(grammar)

FILE: lib/hivemind/universal_ast.rb
  type Hivemind (line 1) | module Hivemind
    type UniversalAST (line 2) | module UniversalAST
      class Element (line 3) | class Element
        method fields (line 4) | def self.fields(*labels)
        method offset (line 13) | def offset(depth)
      class IfStatement (line 18) | class IfStatement < Element
        method render (line 26) | def render(depth = 0)
      class Assign (line 32) | class Assign < Element
        method render (line 37) | def render(depth = 0)
      class Attribute (line 42) | class Attribute < Element
        method render (line 47) | def render(depth = 0)
      class AttributeAssign (line 52) | class AttributeAssign < Element
        method render (line 57) | def render(depth = 0)
      class Call (line 62) | class Call < Element
        method render (line 67) | def render(depth = 0)
      class List (line 72) | class List < Element
        method render (line 77) | def render(depth = 0)
      class Dictionary (line 82) | class Dictionary < Element
      class Binary (line 88) | class Binary < Element
        method render (line 93) | def render(depth = 0)
      class MethodStatement (line 98) | class MethodStatement < Element
        method render (line 104) | def render(depth = 0)
      class ClassStatement (line 110) | class ClassStatement < Element
        method render (line 116) | def render(depth = 0)
      class Value (line 122) | class Value < Element
        method render (line 125) | def render(depth = 0)
      class Name (line 130) | class Name < Value
      class String (line 133) | class String < Value
      class Number (line 136) | class Number < Value
      class Int (line 139) | class Int < Number
      class Float (line 142) | class Float < Number
      class Operation (line 145) | class Operation < Value
      class ModuleStatement (line 148) | class ModuleStatement < Element
      class Pair (line 155) | class Pair < Element
      class Image (line 160) | class Image < Element
        method render (line 163) | def render(depth = 0)

FILE: lib/hivemind/vm.rb
  type Hivemind (line 4) | module Hivemind
    class VM (line 5) | class VM
      method initialize (line 6) | def initialize(ast)
      method run (line 10) | def run(env)
    class Runtime::HivemindObject (line 15) | class Runtime::HivemindObject
      method call (line 16) | def call(function, args, env)
    class Runtime::HivemindClass (line 30) | class Runtime::HivemindClass
      method call (line 31) | def call(function, args, env)
    type UniversalAST (line 48) | module UniversalAST
      class Image (line 49) | class Image
        method run (line 50) | def run(env)
      class ModuleStatement (line 64) | class ModuleStatement
        method run (line 65) | def run(env)
      class If (line 75) | class If
        method run (line 76) | def run(env)
      class Assign (line 85) | class Assign
        method run (line 86) | def run(env)
      class Attribute (line 91) | class Attribute
        method run (line 92) | def run(env)
      class AttributeAssign (line 113) | class AttributeAssign
        method run (line 114) | def run(env)
      class Call (line 119) | class Call
        method run (line 120) | def run(env)
      class Binary (line 136) | class Binary
        method run (line 137) | def run(env)
      class List (line 142) | class List
        method run (line 143) | def run(env)
      class Dictionary (line 148) | class Dictionary
        method run (line 149) | def run(env)
      class Value (line 158) | class Value
        method run (line 159) | def run(env)
      class ClassStatement (line 164) | class ClassStatement
        method run (line 165) | def run(env)
      class MethodStatement (line 174) | class MethodStatement
        method run (line 175) | def run(env)
      class Name (line 180) | class Name
        method run (line 181) | def run(env)

FILE: spec/hivemind/universal_ast_spec.rb
  type Hivemind (line 3) | module Hivemind
    type UniversalAST (line 4) | module UniversalAST
      class A (line 7) | class A < Element

FILE: spec/hivemind/vm_spec.rb
  type Hivemind (line 3) | module Hivemind
Condensed preview — 31 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (47K chars).
[
  {
    "path": ".gitignore",
    "chars": 342,
    "preview": "#Logs\napplication/logs/*.php\n\n# Content types\n/application/xml/types/*.xml\n\n# Custom builds and generated php files\n/cor"
  },
  {
    "path": ".travis.yml",
    "chars": 59,
    "preview": "language: ruby\nrvm:\n  - 2.2.3\nscript:\n  - bundle exec rake\n"
  },
  {
    "path": "Gemfile",
    "chars": 122,
    "preview": "source 'https://rubygems.org'\n\ngroup :development, :test do\n  gem 'bundler'\n  gem 'rspec'\n  gem 'skeptic'\n  gem 'rake'\ne"
  },
  {
    "path": "LICENSE",
    "chars": 1083,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016 Alexander Ivanov\n\nPermission is hereby granted, free of charge, to any person "
  },
  {
    "path": "README.md",
    "chars": 2777,
    "preview": "[![Build Status](https://travis-ci.org/alehander42/hivemind.svg?branch=master)](https://travis-ci.org/alehander42/hivemi"
  },
  {
    "path": "Rakefile",
    "chars": 415,
    "preview": "require 'rubygems'\nrequire 'bundler'\nbegin\n  Bundler.setup(:default, :development)\nrescue Bundler::BundlerError => e\n  $"
  },
  {
    "path": "bin/hivemind",
    "chars": 1523,
    "preview": "#!/usr/bin/env ruby\n\n$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))\n\nrequire 'hivemind'\n\nSYNTAXES_PA"
  },
  {
    "path": "examples/a.hm",
    "chars": 90,
    "preview": "syntax: pythonic\n\nclass Object:\n    method start(self):\n        e = 2\n        e.display()\n"
  },
  {
    "path": "examples/a_paren.hm",
    "chars": 166,
    "preview": "syntax: paren\n\n(class Rectangle\n    (method init (self a b)\n        (update self.a a)\n        (update self.b b))\n\n    (m"
  },
  {
    "path": "examples/b.hm",
    "chars": 150,
    "preview": "syntax: pythonic\n\nclass Rectangle:\n    method init(self, a, b):\n        self.a = a\n        self.b = b\n\n    method area(s"
  },
  {
    "path": "examples/shape.hm",
    "chars": 444,
    "preview": "syntax: pythonic\n\nclass Rectangle:\n    method init(self, a, b):\n        self.a = a\n        self.b = b\n\n    method area(s"
  },
  {
    "path": "examples/shape_paren.hm",
    "chars": 520,
    "preview": "syntax: paren\n\n(class Rectangle\n    (method init (self a b)\n        (update self.a a)\n        (update self.b b))\n\n    (m"
  },
  {
    "path": "examples/shape_pythonic.hm",
    "chars": 433,
    "preview": "syntax: pythonic\n\nclass Rectangle:\n        method init(self, a, b):\n        self.a = a\n    self.b = b\n\n    method area(s"
  },
  {
    "path": "hivemind.gemspec",
    "chars": 1636,
    "preview": "# Generated by jeweler\n# DO NOT EDIT THIS FILE DIRECTLY\n# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspe"
  },
  {
    "path": "lib/hivemind/code_viewer.rb",
    "chars": 1197,
    "preview": "#  'universal_ast'\n\n# module Hivemind\n#   class CodeViewer\n#     def initialize(tree)\n#       @tree = tree\n#     end\n\n# "
  },
  {
    "path": "lib/hivemind/combinators.rb",
    "chars": 4076,
    "preview": "require_relative 'universal_ast'\n\nclass Combinator\n  def &(other)\n    And.new(self, other)\n  end\n\n  def |(other)\n    Or."
  },
  {
    "path": "lib/hivemind/environment.rb",
    "chars": 681,
    "preview": "require_relative 'errors'\n\nmodule Hivemind\n  class Environment\n    attr_reader :parent, :values, :top\n    attr_accessor "
  },
  {
    "path": "lib/hivemind/errors.rb",
    "chars": 126,
    "preview": "module Hivemind\n  class HivemindMissingNameError < StandardError\n  end\n\n  class HivemindAccessError < StandardError\n  en"
  },
  {
    "path": "lib/hivemind/renderer.rb",
    "chars": 1991,
    "preview": "require_relative 'syntax'\n\nmodule Hivemind\n  \n  BASE_RULES = {\n    image: -> element, depth = 0 do\n      element.stateme"
  },
  {
    "path": "lib/hivemind/runtime.rb",
    "chars": 2819,
    "preview": "require_relative 'environment'\n\nmodule Hivemind\n  module Runtime\n    class HivemindObject\n      attr_reader :data, :klas"
  },
  {
    "path": "lib/hivemind/syntax.rb",
    "chars": 11827,
    "preview": "require_relative 'combinators'\n\nmodule Hivemind\n\n  # BaseGrammar = Phoenix::Grammar.new\n  # BaseGrammar.rules = {\n  #   "
  },
  {
    "path": "lib/hivemind/universal_ast.rb",
    "chars": 3554,
    "preview": "module Hivemind\n  module UniversalAST\n    class Element\n      def self.fields(*labels)\n        define_method(:initialize"
  },
  {
    "path": "lib/hivemind/vm.rb",
    "chars": 4817,
    "preview": "require_relative 'runtime'\nrequire_relative 'universal_ast'\n\nmodule Hivemind\n  class VM\n    def initialize(ast)\n      @a"
  },
  {
    "path": "lib/hivemind.rb",
    "chars": 221,
    "preview": "require_relative 'hivemind/universal_ast'\nrequire_relative 'hivemind/environment'\nrequire_relative 'hivemind/vm'\nrequire"
  },
  {
    "path": "spec/hivemind/parser_spec.rb",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "spec/hivemind/universal_ast_spec.rb",
    "chars": 469,
    "preview": "require 'spec_helper'\n\nmodule Hivemind\n  module UniversalAST\n    describe Element do\n      it 'fields initializes a clas"
  },
  {
    "path": "spec/hivemind/vm_spec.rb",
    "chars": 246,
    "preview": "require 'spec_helper'\n\nmodule Hivemind\n  describe VM do\n    it 'should work for a program with a single number' do\n     "
  },
  {
    "path": "spec/spec_helper.rb",
    "chars": 218,
    "preview": "# well, really, no time for a lot of tests now\n# dirty fast prototyping\n\n$LOAD_PATH.unshift(File.join(File.dirname(__FIL"
  },
  {
    "path": "syntaxes/lolcode.syntax",
    "chars": 441,
    "preview": "#if_statement\n<test> O RLY\n    YA RLY\n    <<true_branch>>\n    NO WAI\n    <<else_branch>>\n\n\n#assign\nDO <left> <right>\n\n#m"
  },
  {
    "path": "syntaxes/paren.syntax",
    "chars": 461,
    "preview": "#if_statement\n(if <test>\n    <true_branch>\n    <else_branch>)\n\n#assign\n(define <left> <right>)\n\n#method_statement\n(metho"
  },
  {
    "path": "syntaxes/pythonic.syntax",
    "chars": 449,
    "preview": "#if_statement\nif <test>:\n    <true_branch>\nelse:\n    <else_branch>\n\n#assign\n<left> = <right>\n\n#call\n<function>(<<args:',"
  }
]

About this extraction

This page contains the full source code of the alehander42/hivemind GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 31 files (42.3 KB), approximately 12.7k tokens, and a symbol index with 149 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!