Module: Hivemind

Defined in:
lib/hivemind/vm.rb,
lib/hivemind/errors.rb,
lib/hivemind/syntax.rb,
lib/hivemind/runtime.rb,
lib/hivemind/renderer.rb,
lib/hivemind/environment.rb,
lib/hivemind/universal_ast.rb

Defined Under Namespace

Modules: Runtime, UniversalAST Classes: Environment, HivemindAccessError, HivemindMissingNameError, Renderer, Syntax, VM

Constant Summary collapse

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
  }
}
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
}
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
}