move sof to own repo
This commit is contained in:
parent
91e2ff886c
commit
8180c67d48
5
Gemfile
5
Gemfile
@ -1,7 +1,8 @@
|
||||
source "http://rubygems.org"
|
||||
|
||||
gem "parslet"
|
||||
gem "salama-reader" , "0.0.2" , :require => "parser" , :git => "https://github.com/salama/salama-reader.git"
|
||||
gem "parslet"
|
||||
gem "salama-reader" , "0.0.2" , :require => "parser" , :git => "https://github.com/salama/salama-reader.git"
|
||||
gem "salama-object-file" , "0.1" , :git => "https://github.com/salama/salama-object-file.git"
|
||||
|
||||
group :development do
|
||||
gem "minitest"
|
||||
|
@ -1,3 +1,9 @@
|
||||
GIT
|
||||
remote: https://github.com/salama/salama-object-file.git
|
||||
revision: c8d35adef4858b14d75f14f0c2de1883762ef4ad
|
||||
specs:
|
||||
salama-object-file (0.1)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/salama/salama-reader.git
|
||||
revision: 1272af6c660efe0af93d7f5ad87d98bd04ce5d22
|
||||
@ -19,4 +25,5 @@ PLATFORMS
|
||||
DEPENDENCIES
|
||||
minitest
|
||||
parslet
|
||||
salama-object-file (= 0.1)!
|
||||
salama-reader (= 0.0.2)!
|
||||
|
14
Rakefile
14
Rakefile
@ -11,20 +11,6 @@ rescue Bundler::BundlerError => e
|
||||
end
|
||||
require 'rake'
|
||||
|
||||
require 'jeweler'
|
||||
Jeweler::Tasks.new do |gem|
|
||||
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
||||
gem.name = "salama"
|
||||
gem.homepage = "http://github.com/salama-ruby/salama"
|
||||
gem.license = "MIT"
|
||||
gem.summary = %Q{Create fast code}
|
||||
gem.description = %Q{A long way to china and back}
|
||||
gem.email = "torsten@villataika.fi"
|
||||
gem.authors = ["Torsten Ruger"]
|
||||
# dependencies defined in Gemfile
|
||||
end
|
||||
Jeweler::RubygemsDotOrgTasks.new
|
||||
|
||||
require 'rake/testtask'
|
||||
Rake::TestTask.new(:test) do |test|
|
||||
test.libs << 'lib' << 'test'
|
||||
|
@ -1,59 +0,0 @@
|
||||
### Reading the code
|
||||
|
||||
Knowing what's going on while coding salama is not so easy: Hence the need to look at code dumps
|
||||
|
||||
Hence the need for a code/object file format
|
||||
(remember an oo program is just objects, some data, some code, all objects)
|
||||
|
||||
I started with yaml, which is nice in that it has a solid implementation, reads and writes,
|
||||
handles arbitrary objects, handles graphs and is a sort of readable text format.
|
||||
|
||||
But the "sort of" started to get to me, because
|
||||
|
||||
- 1) it's way to verbose (long files, object groups over many pages) and
|
||||
- 2) does not allow for (easy) ordering.
|
||||
|
||||
To fix this i started on Sof, with an eye to expand it.
|
||||
|
||||
The main starting goal was quite like yaml, but with
|
||||
|
||||
- more text per line, specifically objects with simple attributes to have a constructor like syntax
|
||||
- also short versions of arrays and hashes
|
||||
- Shorter class names (no ruby/object or even ruby/struct stuff)
|
||||
- references at the most shallow level
|
||||
- an easy way to order attributes and specify attributes that should not be serialized
|
||||
|
||||
### Salama Object File
|
||||
|
||||
Ok, so we all heard about object files, it's the things compilers create so we don't have to have
|
||||
huge compiles and can link them later.
|
||||
|
||||
Much fewer know what they include, and that is not because they are not very useful,
|
||||
but rather very complicated.
|
||||
|
||||
An object machine must off course have it's own object files, because:
|
||||
|
||||
- otherwise we'd have to express the object machine in c (nischt gut)
|
||||
- we would be forced to read the source every time (slow)
|
||||
- we would have no language independant format
|
||||
|
||||
And i was going to get there, juust not now. I mean i think it's a great idea to have many languages
|
||||
compile and run on the same object machine.
|
||||
Not neccessarily my idea, but i haven't seen it pulled off. Not that i will.
|
||||
|
||||
I just want to be able to read my compiled code!!
|
||||
|
||||
And so this is a little start, just some outputter.
|
||||
|
||||
#### Direction
|
||||
|
||||
The way this is meant to go (planned for 2020+) was a salama core with only a sof parser
|
||||
(as that is soo much simpler).
|
||||
|
||||
Then to_ruby for all the ast classes to be able to roundtrip ruby code.
|
||||
|
||||
Then go to storing sof in git, rather than ruby.
|
||||
|
||||
Then write a python/java parser and respective runtime conversion. Extracting common features.
|
||||
With the respective to_python on the ast's to roundtrip that too.
|
||||
Have to since by now we work on sof's. Etc . ..
|
@ -1,39 +0,0 @@
|
||||
require_relative "util"
|
||||
require_relative "node"
|
||||
require_relative "members"
|
||||
require_relative "volotile"
|
||||
require_relative "writer"
|
||||
require_relative "array"
|
||||
require_relative "hash"
|
||||
require_relative "occurence"
|
||||
|
||||
Symbol.class_eval do
|
||||
def to_sof()
|
||||
":#{to_s}"
|
||||
end
|
||||
end
|
||||
TrueClass.class_eval do
|
||||
def to_sof()
|
||||
"true"
|
||||
end
|
||||
end
|
||||
NilClass.class_eval do
|
||||
def to_sof()
|
||||
"nil"
|
||||
end
|
||||
end
|
||||
FalseClass.class_eval do
|
||||
def to_sof()
|
||||
"false"
|
||||
end
|
||||
end
|
||||
String.class_eval do
|
||||
def to_sof()
|
||||
"'" + self + "'"
|
||||
end
|
||||
end
|
||||
Fixnum.class_eval do
|
||||
def to_sof()
|
||||
to_s
|
||||
end
|
||||
end
|
@ -1,51 +0,0 @@
|
||||
module Sof
|
||||
class ArrayNode < Node
|
||||
def initialize ref
|
||||
super(ref)
|
||||
@children = []
|
||||
end
|
||||
attr_reader :children
|
||||
def add c
|
||||
@children << c
|
||||
end
|
||||
def out io , level = 0
|
||||
super
|
||||
short = true
|
||||
children.each do |c|
|
||||
short = false unless c.is_a?(SimpleNode)
|
||||
end
|
||||
if(short and children.length < 7 )
|
||||
short_out(io,level)
|
||||
else
|
||||
long_out(io , level)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def short_out(io,level)
|
||||
io.write("[")
|
||||
@children.each_with_index do |child , i|
|
||||
child.out(io , level + 1)
|
||||
io.write ", " unless (i+1) == children.length
|
||||
end
|
||||
io.write("]")
|
||||
end
|
||||
def long_out io , level
|
||||
indent = " " * level
|
||||
@children.each_with_index do |child , i|
|
||||
io.write "\n#{indent}" unless i == 0
|
||||
io.write "-"
|
||||
child.out(io , level + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Array.class_eval do
|
||||
def to_sof_node(writer , level , ref )
|
||||
node = Sof::ArrayNode.new(ref)
|
||||
each do |object|
|
||||
node.add writer.to_sof_node( object , level + 1)
|
||||
end
|
||||
node
|
||||
end
|
||||
end
|
@ -1,60 +0,0 @@
|
||||
module Sof
|
||||
class HashNode < Node
|
||||
def initialize ref
|
||||
super(ref)
|
||||
@children = []
|
||||
end
|
||||
attr_reader :children
|
||||
def add key , val
|
||||
@children << [key,val]
|
||||
end
|
||||
def out io , level = 0
|
||||
super
|
||||
short = true
|
||||
children.each do |k,v|
|
||||
short = false unless k.is_a?(SimpleNode)
|
||||
short = false unless v.is_a?(SimpleNode)
|
||||
end
|
||||
if(short and children.length < 7 )
|
||||
short_out(io,level)
|
||||
else
|
||||
long_out(io , level)
|
||||
end
|
||||
end
|
||||
def short_out(io,level)
|
||||
io.write("{")
|
||||
children.each_with_index do |child , i|
|
||||
key , val = child
|
||||
key.out(io , level + 1)
|
||||
io.write " => "
|
||||
val.out(io , level + 1)
|
||||
io.write ", " unless (i+1) == children.length
|
||||
end
|
||||
io.write("}")
|
||||
end
|
||||
def long_out io , level
|
||||
indent = " " * level
|
||||
children.each_with_index do |child , i|
|
||||
key , val = child
|
||||
io.write "\n#{indent}" unless i == 0
|
||||
io.write "-"
|
||||
key.out(io , level + 1)
|
||||
io.write " => "
|
||||
val.out(io , level + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Hash.class_eval do
|
||||
def to_sof_node(writer , level , ref)
|
||||
node = Sof::HashNode.new(ref)
|
||||
each do |key , object|
|
||||
k = writer.to_sof_node( key ,level + 1)
|
||||
v = writer.to_sof_node( object ,level +1)
|
||||
node.add(k , v)
|
||||
end
|
||||
node
|
||||
end
|
||||
end
|
||||
|
@ -1,49 +0,0 @@
|
||||
module Sof
|
||||
|
||||
class Members
|
||||
include Util
|
||||
|
||||
def initialize root
|
||||
@root = root
|
||||
@counter = 1
|
||||
@objects = {}
|
||||
@referenced = false
|
||||
add(root , 0)
|
||||
end
|
||||
attr_reader :objects , :root , :referenced
|
||||
|
||||
def add object , level
|
||||
return if is_value?(object)
|
||||
if( occurence = @objects[object.object_id] )
|
||||
#puts "reset level #{level} at #{occurence.level}"
|
||||
if occurence.level > level
|
||||
occurence.level = level
|
||||
end
|
||||
unless occurence.referenced
|
||||
#puts "referencing #{@counter} , at level #{level}/#{occurence.level} "
|
||||
occurence.set_reference(@counter)
|
||||
@counter = @counter + 1
|
||||
end
|
||||
return
|
||||
end
|
||||
o = Occurence.new( object , level )
|
||||
@objects[object.object_id] = o
|
||||
attributes = attributes_for(object)
|
||||
attributes.each do |a|
|
||||
val = get_value( object , a)
|
||||
add(val , level + 1)
|
||||
end
|
||||
if( object.is_a? Array )
|
||||
object.each do |a|
|
||||
add(a , level + 1)
|
||||
end
|
||||
end
|
||||
if( object.is_a? Hash )
|
||||
object.each do |a,b|
|
||||
add(a , level + 1)
|
||||
add(b , level + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,58 +0,0 @@
|
||||
# We transform objects into a tree of nodes
|
||||
|
||||
module Sof
|
||||
#abstract base class for nodes in the tree
|
||||
# may be referenced (should be a simple name or number)
|
||||
class Node
|
||||
include Util
|
||||
def initialize ref
|
||||
@referenced = ref
|
||||
end
|
||||
# must be able to output to a stream
|
||||
def out io ,level
|
||||
io.write "&#{@referenced} " if @referenced
|
||||
end
|
||||
def as_string(level)
|
||||
io = StringIO.new
|
||||
out(io,level)
|
||||
io.string
|
||||
end
|
||||
attr_reader :referenced
|
||||
end
|
||||
|
||||
class SimpleNode < Node
|
||||
def initialize data , ref = nil
|
||||
super(ref)
|
||||
@data = data
|
||||
end
|
||||
attr_reader :data
|
||||
def out io , level
|
||||
super(io,level)
|
||||
io.write(data)
|
||||
end
|
||||
end
|
||||
|
||||
class ObjectNode < Node
|
||||
def initialize data , ref
|
||||
super(ref)
|
||||
@data = data
|
||||
@children = []
|
||||
end
|
||||
attr_reader :children , :data
|
||||
def add k , v
|
||||
@children << [k,v]
|
||||
end
|
||||
def out io , level = 0
|
||||
super
|
||||
io.write(@data)
|
||||
indent = " " * (level + 1)
|
||||
@children.each_with_index do |child , i|
|
||||
k , v = child
|
||||
io.write "\n#{indent}"
|
||||
k.out(io , level + 2)
|
||||
io.write " "
|
||||
v.out(io , level + 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,16 +0,0 @@
|
||||
module Sof
|
||||
|
||||
class Occurence
|
||||
def initialize object , level
|
||||
@object = object
|
||||
@level = level
|
||||
@referenced = nil
|
||||
end
|
||||
def set_reference r
|
||||
@referenced = r
|
||||
end
|
||||
attr_reader :object , :referenced
|
||||
attr_accessor :level
|
||||
end
|
||||
|
||||
end
|
@ -1,25 +0,0 @@
|
||||
module Sof
|
||||
module Util
|
||||
def is_value? o
|
||||
return true if o == true
|
||||
return true if o == false
|
||||
return true if o == nil
|
||||
return true if o.class == Fixnum
|
||||
return true if o.class == Symbol
|
||||
return true if o.class == String
|
||||
return false
|
||||
end
|
||||
|
||||
def get_value(object,name)
|
||||
object.instance_variable_get "@#{name}".to_sym
|
||||
end
|
||||
|
||||
def attributes_for object
|
||||
Sof::Util.attributes(object)
|
||||
end
|
||||
def self.attributes( object )
|
||||
atts = object.instance_variables.collect{|i| i.to_s[1..-1].to_sym } # chop of @
|
||||
atts - Volotile.attributes(object.class)
|
||||
end
|
||||
end
|
||||
end
|
@ -1,11 +0,0 @@
|
||||
module Sof
|
||||
class Volotile
|
||||
@@mapping = { }
|
||||
def self.attributes clazz
|
||||
@@mapping[clazz] || []
|
||||
end
|
||||
def self.add clazz , attributes
|
||||
@@mapping[clazz] = attributes
|
||||
end
|
||||
end
|
||||
end
|
@ -1,60 +0,0 @@
|
||||
module Sof
|
||||
class Writer
|
||||
include Util
|
||||
def initialize members
|
||||
@members = members
|
||||
end
|
||||
|
||||
def write
|
||||
node = to_sof_node(@members.root , 0)
|
||||
io = StringIO.new
|
||||
node.out( io , 0 )
|
||||
io.string
|
||||
end
|
||||
|
||||
def to_sof_node(object , level)
|
||||
if is_value?(object)
|
||||
return SimpleNode.new(object.to_sof())
|
||||
end
|
||||
occurence = @members.objects[object.object_id]
|
||||
raise "no object #{object}" unless occurence
|
||||
if(level > occurence.level )
|
||||
#puts "ref #{occurence.referenced} level #{level} at #{occurence.level}"
|
||||
return SimpleNode.new("*#{occurence.referenced}")
|
||||
end
|
||||
ref = occurence.referenced
|
||||
if(object.respond_to? :to_sof_node) #mainly meant for arrays and hashes
|
||||
object.to_sof_node(self , level , ref )
|
||||
else
|
||||
object_sof_node(object , level , ref )
|
||||
end
|
||||
end
|
||||
|
||||
def object_sof_node( object , level , ref)
|
||||
if( object.is_a? Class )
|
||||
return SimpleNode.new( object.name , ref )
|
||||
end
|
||||
head = object.class.name + "("
|
||||
atts = {}
|
||||
attributes_for(object).each() do |a|
|
||||
val = get_value(object , a)
|
||||
next if val.nil?
|
||||
atts[a] = to_sof_node(val , level + 1)
|
||||
end
|
||||
immediate , extended = atts.partition {|a,val| val.is_a?(SimpleNode) }
|
||||
head += immediate.collect {|a,val| "#{a.to_sof()} => #{val.as_string(level)}"}.join(", ") + ")"
|
||||
return SimpleNode.new(head) if( ref.nil? and extended.empty? and head.length < 30 )
|
||||
node = ObjectNode.new(head , ref)
|
||||
extended.each do |a , val|
|
||||
node.add( to_sof_node(a,level + 1) , val )
|
||||
end
|
||||
node
|
||||
end
|
||||
|
||||
def self.write object
|
||||
writer = Writer.new(Members.new(object) )
|
||||
writer.write
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -15,16 +15,9 @@ time comes to move to salama, less work.
|
||||
ruby test/test_all.rb
|
||||
''''
|
||||
|
||||
### sof
|
||||
|
||||
''''
|
||||
ruby test/test_sof.rb
|
||||
''''
|
||||
|
||||
### vm
|
||||
|
||||
As this is all quite new, i tend to test only when i know that the functionality will stay that way.
|
||||
Otherwise it's just too much effort to rewrite and rewrite the tests.
|
||||
|
||||
There used to be better tests, but rewrites bring fluctuation, so poke around and make suggestion :-)
|
||||
|
||||
There used to be better tests, but rewrites bring fluctuation, so poke around and make suggestion :-)
|
||||
|
106
test/sof.rb
106
test/sof.rb
@ -1,106 +0,0 @@
|
||||
require_relative "helper"
|
||||
require "yaml"
|
||||
|
||||
class ObjectWithAttributes
|
||||
def initialize
|
||||
@name = "some name"
|
||||
@number = 1234
|
||||
end
|
||||
attr_accessor :extra
|
||||
end
|
||||
OBJECT_STRING = "ObjectWithAttributes(:name => 'some name', :number => 1234)"
|
||||
|
||||
class BasicSof < MiniTest::Test
|
||||
def check should
|
||||
same = (should == @out)
|
||||
puts "Shouldda\n#{@out}" unless same
|
||||
assert_equal should , @out
|
||||
end
|
||||
def test_true
|
||||
@out = Sof::Writer.write(true)
|
||||
check "true"
|
||||
end
|
||||
def test_num
|
||||
@out = Sof::Writer.write(124)
|
||||
check "124"
|
||||
end
|
||||
def test_simple_object
|
||||
@out = Sof::Writer.write(ObjectWithAttributes.new)
|
||||
check "#{OBJECT_STRING}"
|
||||
end
|
||||
def test_object_extra_array
|
||||
object = ObjectWithAttributes.new
|
||||
object.extra = [:sym , 123]
|
||||
@out = Sof::Writer.write(object)
|
||||
check "#{OBJECT_STRING}\n :extra [:sym, 123]"
|
||||
end
|
||||
def test_simple_array
|
||||
@out = Sof::Writer.write([true, 1234])
|
||||
check "[true, 1234]"
|
||||
end
|
||||
def test_array_object
|
||||
@out = Sof::Writer.write([true, 1234 , ObjectWithAttributes.new])
|
||||
check "-true\n-1234\n-#{OBJECT_STRING}"
|
||||
end
|
||||
def test_array_array
|
||||
@out = Sof::Writer.write([true, 1 , [true , 12 ]])
|
||||
check "-true\n-1\n-[true, 12]"
|
||||
end
|
||||
def test_array_array_reverse
|
||||
@out = Sof::Writer.write([ [true , 12 ], true, 1])
|
||||
check "-[true, 12]\n-true\n-1"
|
||||
end
|
||||
def test_array_array_array
|
||||
@out = Sof::Writer.write([true, 1 , [true , 12 , [true , 123 ]]])
|
||||
check "-true\n-1\n--true\n -12\n -[true, 123]"
|
||||
end
|
||||
def test_array_array_object
|
||||
@out = Sof::Writer.write([true, 1 , [true , 12 , ObjectWithAttributes.new]])
|
||||
check "-true\n-1\n--true\n -12\n -#{OBJECT_STRING}"
|
||||
end
|
||||
def test_simple_hash
|
||||
@out = Sof::Writer.write({ one: 1 , tru: true })
|
||||
check "{:one => 1, :tru => true}"
|
||||
end
|
||||
def test_hash_object
|
||||
@out = Sof::Writer.write({ one: 1 , two: ObjectWithAttributes.new })
|
||||
check "-:one => 1\n-:two => #{OBJECT_STRING}"
|
||||
end
|
||||
def test_array_hash
|
||||
@out = Sof::Writer.write([true, 1 , { one: 1 , tru: true }])
|
||||
check "-true\n-1\n-{:one => 1, :tru => true}"
|
||||
end
|
||||
def test_hash_array
|
||||
@out = Sof::Writer.write({ one: [1 , ObjectWithAttributes.new] , two: true })
|
||||
check "-:one => -1\n -#{OBJECT_STRING}\n-:two => true"
|
||||
end
|
||||
def test_array_recursive
|
||||
ar = [true, 1 ]
|
||||
ar << ar
|
||||
@out = Sof::Writer.write(ar)
|
||||
check "&1 [true, 1, *1]"
|
||||
end
|
||||
def test_object_recursive
|
||||
object = ObjectWithAttributes.new
|
||||
object.extra = object
|
||||
@out = Sof::Writer.write(object)
|
||||
check "&1 ObjectWithAttributes(:name => 'some name', :number => 1234, :extra => *1)"
|
||||
end
|
||||
def test_object_inline
|
||||
object = ObjectWithAttributes.new
|
||||
object.extra = Object.new
|
||||
@out = Sof::Writer.write(object)
|
||||
check "ObjectWithAttributes(:name => 'some name', :number => 1234, :extra => Object())"
|
||||
end
|
||||
def test_class
|
||||
@out = Sof::Writer.write(ObjectWithAttributes)
|
||||
check "ObjectWithAttributes"
|
||||
end
|
||||
def test_class_ref
|
||||
object = ObjectWithAttributes.new
|
||||
object.extra = ObjectWithAttributes
|
||||
ar = [object , ObjectWithAttributes]
|
||||
@out = Sof::Writer.write(ar)
|
||||
check "-ObjectWithAttributes(:name => 'some name', :number => 1234, :extra => *1)\n-&1 ObjectWithAttributes"
|
||||
end
|
||||
end
|
@ -1,6 +1,5 @@
|
||||
# All working tests (ahm), still working on the others, so no use to be constantly reminded
|
||||
require_relative "arm/test_all"
|
||||
require_relative "sof"
|
||||
require "parfait/hash_test"
|
||||
|
||||
#require_relative "virtual/test_all"
|
||||
|
Loading…
Reference in New Issue
Block a user