update the reader rewrite and reflect name changes

This commit is contained in:
Torsten Ruger 2015-10-09 17:51:14 +03:00
parent 02e9975ad6
commit 4c17ed2e6e
30 changed files with 114 additions and 119 deletions

View File

@ -12,9 +12,9 @@ GIT
GIT GIT
remote: git://github.com/salama/salama-reader.git remote: git://github.com/salama/salama-reader.git
revision: 58b3553251bd23d2b666b25e23c8bc13ad87acdb revision: 6bd5e9b5ee26e4e0157283e9af4389b13d660193
specs: specs:
salama-reader (0.3.0) salama-reader (0.4.0)
ast (~> 2.1.0) ast (~> 2.1.0)
parslet (~> 1.7.0) parslet (~> 1.7.0)

View File

@ -74,7 +74,7 @@ The full list is on the net and involves mostly just work.
Parse Phisol, using Parslet. This has been separated out as it's own gem, [salama-reader](https://github.com/salama/salama-reader). Parse Phisol, using Parslet. This has been separated out as it's own gem, [salama-reader](https://github.com/salama/salama-reader).
Phisol is now fully typed (all variables, arguments and return). Also it has statements, unlike ruby Phisol is now fully typed (all variables, arguments and return). Also it has statements, unlike ruby
where everything is an expressions. Statements have no value. Otherwise it is quite basic, and where everything is an statements. Statements have no value. Otherwise it is quite basic, and
it's main purpose is to have an oo system language to compile to. it's main purpose is to have an oo system language to compile to.
I spent some time on the parse testing framework, so it is safe to fiddle and add. I spent some time on the parse testing framework, so it is safe to fiddle and add.

View File

@ -10,7 +10,7 @@ Some things that would be nice . . (if you did them :-) )
- utf8 support (string improvements generally) - utf8 support (string improvements generally)
- SOF parser - SOF parser
- more ruby grammar niceties. At the moment i am keeping it simple, so if there is a way around it - more ruby grammar niceties. At the moment i am keeping it simple, so if there is a way around it
i won't implement it. Multi-assignments, all that chique where newline is used as expression demarcation i won't implement it. Multi-assignments, all that chique where newline is used as statement demarcation
Or the list of things i am not even planning of tackling at the moment Or the list of things i am not even planning of tackling at the moment

View File

@ -13,35 +13,35 @@ module Phisol
# Some compile methods just add code, some may add structure (ie Blocks) while # Some compile methods just add code, some may add structure (ie Blocks) while
# others instantiate Class and Method objects # others instantiate Class and Method objects
# #
# Everything in ruby is an expression, ie returns a value. So the effect of every compile # Everything in ruby is an statement, ie returns a value. So the effect of every compile
# is that a value is put into the ReturnSlot of the current Message. # is that a value is put into the ReturnSlot of the current Message.
# The compile method (so every compile method) returns the value that it deposits. # The compile method (so every compile method) returns the value that it deposits.
# #
# The process uses a visitor pattern (from AST::Processor) to dispatch according to the # The process uses a visitor pattern (from AST::Processor) to dispatch according to the
# type the expression. So a s(:if xx) will become an on_if(node) call. # type the statement. So a s(:if xx) will become an on_if(node) call.
# This makes the dispatch extensible, ie Expressions may be added by external code, # This makes the dispatch extensible, ie Expressions may be added by external code,
# as long as matching compile methods are supplied too. # as long as matching compile methods are supplied too.
# #
def self.compile expression def self.compile statement
compiler = Compiler.new compiler = Compiler.new
compiler.process expression compiler.process statement
end end
end end
end end
require_relative "ast_helper" require_relative "ast_helper"
require_relative "compiler/basic_expressions" require_relative "compiler/basic_values"
require_relative "compiler/callsite_expression" require_relative "compiler/call_site"
require_relative "compiler/class_field" require_relative "compiler/class_field"
require_relative "compiler/compound_expressions" require_relative "compiler/collections"
require_relative "compiler/expression_list" require_relative "compiler/statement_list"
require_relative "compiler/field_def" require_relative "compiler/field_def"
require_relative "compiler/field_access" require_relative "compiler/field_access"
require_relative "compiler/function_expression" require_relative "compiler/function_definition"
require_relative "compiler/if_expression" require_relative "compiler/if_statement"
require_relative "compiler/module_expression" require_relative "compiler/class_statement"
require_relative "compiler/name_expression" require_relative "compiler/name_expression"
require_relative "compiler/operator_expressions" require_relative "compiler/operator_value"
require_relative "compiler/return_expression" require_relative "compiler/return_statement"
require_relative "compiler/while_expression" require_relative "compiler/while_statement"

View File

@ -3,7 +3,7 @@ module Phisol
Compiler.class_eval do Compiler.class_eval do
# Constant expressions can by definition be evaluated at compile time. # Constant statements can by definition be evaluated at compile time.
# But that does not solve their storage, ie they need to be accessible at runtime from _somewhere_ # But that does not solve their storage, ie they need to be accessible at runtime from _somewhere_
# So we view ConstantExpressions like functions that return the value of the constant. # So we view ConstantExpressions like functions that return the value of the constant.
# In other words, their storage is the return slot as it would be for a method # In other words, their storage is the return slot as it would be for a method
@ -11,34 +11,34 @@ module Phisol
# The current approach moves the constant into a variable before using it # The current approach moves the constant into a variable before using it
# But in the future (in the one that holds great things) we optimize those unneccesay moves away # But in the future (in the one that holds great things) we optimize those unneccesay moves away
def on_int expression def on_int statement
int = expression.first int = statement.first
to = Virtual::Return.new(Virtual::Integer , int) to = Virtual::Return.new(Virtual::Integer , int)
@method.source.add_code Virtual::Set.new( int , to ) @method.source.add_code Virtual::Set.new( int , to )
to to
end end
def on_true expression def on_true statement
to = Virtual::Return.new(Virtual::Reference , true ) to = Virtual::Return.new(Virtual::Reference , true )
@method.source.add_code Virtual::Set.new( true , to ) @method.source.add_code Virtual::Set.new( true , to )
to to
end end
def on_false expression def on_false statement
to = Virtual::Return.new(Virtual::Reference , false) to = Virtual::Return.new(Virtual::Reference , false)
@method.source.add_code Virtual::Set.new( false , to ) @method.source.add_code Virtual::Set.new( false , to )
to to
end end
def on_nil expression def on_nil statement
to = Virtual::Return.new(Virtual::Reference , nil) to = Virtual::Return.new(Virtual::Reference , nil)
@method.source.add_code Virtual::Set.new( nil , to ) @method.source.add_code Virtual::Set.new( nil , to )
to to
end end
def on_string expression def on_string statement
# Clearly a TODO here to implement strings rather than reusing symbols # Clearly a TODO here to implement strings rather than reusing symbols
value = expression.first.to_sym value = statement.first.to_sym
to = Virtual::Return.new(Virtual::Reference , value) to = Virtual::Return.new(Virtual::Reference , value)
@method.source.constants << value @method.source.constants << value
@method.source.add_code Virtual::Set.new( value , to ) @method.source.add_code Virtual::Set.new( value , to )

View File

@ -1,8 +1,8 @@
module Phisol module Phisol
Compiler.class_eval do Compiler.class_eval do
def on_call expression def on_call statement
name , arguments , receiver = *expression name , arguments , receiver = *statement
name = name.to_a.first name = name.to_a.first
raise "not inside method " unless @method raise "not inside method " unless @method
if receiver if receiver
@ -65,7 +65,7 @@ module Phisol
end end
raise "Method not implemented #{me.value}.#{name}" unless method raise "Method not implemented #{me.value}.#{name}" unless method
# the effect of the method is that the NewMessage Return slot will be filled, return it # the effect of the method is that the NewMessage Return slot will be filled, return it
# (this is what is moved _inside_ above loop for such expressions that are calls (or constants)) # (this is what is moved _inside_ above loop for such statements that are calls (or constants))
Virtual::Return.new( method.source.return_type ) Virtual::Return.new( method.source.return_type )
end end
end end

View File

@ -1,9 +1,9 @@
module Phisol module Phisol
Compiler.class_eval do Compiler.class_eval do
def on_class_field expression def on_class_field statement
#puts expression.inspect #puts statement.inspect
type , name , value = *expression type , name , value = *statement
for_class = @clazz for_class = @clazz
raise "no class" unless for_class raise "no class" unless for_class

View File

@ -0,0 +1,15 @@
module Phisol
Compiler.class_eval do
def on_class statement
#puts statement.inspect
name , derives , statements = *statement
raise "classes dont yet play babushka, get coding #{name}" if @clazz
@clazz = Parfait::Space.object_space.get_class_by_name! name
puts "Compiling class #{@clazz.name.inspect}"
statement_value = process_all(statements).last
@clazz = nil
return statement_value
end
end
end

View File

@ -2,7 +2,7 @@ module Phisol
Compiler.class_eval do Compiler.class_eval do
# attr_reader :values # attr_reader :values
def on_array expession, context def on_array statement, context
end end
# attr_reader :key , :value # attr_reader :key , :value
def on_association context def on_association context

View File

@ -1,8 +0,0 @@
module Phisol
Compiler.class_eval do
# list - attr_reader :expressions
def on_expressions expession
process_all( expession.children )
end
end
end

View File

@ -1,9 +1,9 @@
module Phisol module Phisol
Compiler.class_eval do Compiler.class_eval do
def on_field_access expression def on_field_access statement
#puts expression.inspect #puts statement.inspect
receiver_ast , field_ast = *expression receiver_ast , field_ast = *statement
receiver = receiver_ast.first_from(:name) receiver = receiver_ast.first_from(:name)
field_name = field_ast.first_from(:name) field_name = field_ast.first_from(:name)

View File

@ -1,9 +1,9 @@
module Phisol module Phisol
Compiler.class_eval do Compiler.class_eval do
def on_field_def expression def on_field_def statement
#puts expression.inspect #puts statement.inspect
type , name , value = *expression type , name , value = *statement
index = @method.ensure_local( name , type ) index = @method.ensure_local( name , type )

View File

@ -1,9 +1,9 @@
module Phisol module Phisol
Compiler.class_eval do Compiler.class_eval do
def on_function expression def on_function statement
#puts expression.inspect #puts statement.inspect
return_type , name , parameters, kids , receiver = *expression return_type , name , parameters, kids , receiver = *statement
name = name.to_a.first name = name.to_a.first
args = parameters.to_a.collect do |p| args = parameters.to_a.collect do |p|
raise "error, argument must be a identifier, not #{p}" unless p.type == :parameter raise "error, argument must be a identifier, not #{p}" unless p.type == :parameter

View File

@ -2,8 +2,8 @@ module Phisol
Compiler.class_eval do Compiler.class_eval do
# if - attr_reader :cond, :if_true, :if_false # if - attr_reader :cond, :if_true, :if_false
def on_if expression def on_if statement
condition , if_true , if_false = *expression condition , if_true , if_false = *statement
condition = condition.first condition = condition.first
# to execute the logic as the if states it, the blocks are the other way around # to execute the logic as the if states it, the blocks are the other way around
# so we can the jump over the else if true , # so we can the jump over the else if true ,
@ -25,7 +25,7 @@ module Phisol
# compile the false block # compile the false block
@method.source.current false_block @method.source.current false_block
last = process_all(if_false).last if if_false last = process_all(if_false).last if if_false
@method.source.add_code Register::AlwaysBranch.new(expression, merge_block ) @method.source.add_code Register::AlwaysBranch.new(statement, merge_block )
#puts "compiled if: end" #puts "compiled if: end"
@method.source.current merge_block @method.source.current merge_block

View File

@ -1,20 +0,0 @@
module Phisol
Compiler.class_eval do
# module attr_reader :name ,:expressions
def on_module expression
name , rest = *expression
return process_all(rest).last
end
def on_class expression
#puts expression.inspect
name , derives , expressions = *expression
raise "classes dont yet play babushka, get coding #{name}" if @clazz
@clazz = Parfait::Space.object_space.get_class_by_name! name
puts "Compiling class #{@clazz.name.inspect}"
expression_value = process_all(expressions).last
@clazz = nil
return expression_value
end
end
end

View File

@ -5,8 +5,8 @@ module Phisol
# compiling name needs to check if it's a variable and if so resolve it # compiling name needs to check if it's a variable and if so resolve it
# otherwise it's a method without args and a send is issued. # otherwise it's a method without args and a send is issued.
# whichever way this goes the result is stored in the return slot (as all compiles) # whichever way this goes the result is stored in the return slot (as all compiles)
def on_name expression def on_name statement
name = expression.to_a.first name = statement.to_a.first
return Virtual::Self.new( Virtual::Reference.new(@clazz)) if name == :self return Virtual::Self.new( Virtual::Reference.new(@clazz)) if name == :self
# either an argument, so it's stored in message # either an argument, so it's stored in message
if( index = @method.has_arg(name)) if( index = @method.has_arg(name))

View File

@ -1,30 +1,30 @@
module Phisol module Phisol
Compiler.class_eval do Compiler.class_eval do
def on_operator expression def on_operator statement
puts "operator #{expression.inspect}" puts "operator #{statement.inspect}"
operator , left_e , right_e = *expression operator , left_e , right_e = *statement
left_slot = process(left_e) left_slot = process(left_e)
right_slot = process(right_e) right_slot = process(right_e)
puts "left #{left_slot}" puts "left #{left_slot}"
puts "right #{right_slot}" puts "right #{right_slot}"
tmp1 = Register.tmp_reg tmp1 = Register.tmp_reg
tmp2 = tmp1.next_reg_use tmp2 = tmp1.next_reg_use
get = Register.get_slot_to(expression , left_slot , tmp1 ) get = Register.get_slot_to(statement , left_slot , tmp1 )
get2 = Register.get_slot_to(expression , right_slot , tmp2 ) get2 = Register.get_slot_to(statement , right_slot , tmp2 )
puts "GET #{get}" puts "GET #{get}"
puts "GET2 #{get2}" puts "GET2 #{get2}"
@method.source.add_code get @method.source.add_code get
@method.source.add_code get2 @method.source.add_code get2
@method.source.add_code Register::OperatorInstruction.new(expression,operator, tmp1,tmp2) @method.source.add_code Register::OperatorInstruction.new(statement,operator, tmp1,tmp2)
Virtual::Return.new(:int ) Virtual::Return.new(:int )
end end
def on_assign expression def on_assign statement
puts expression.inspect puts statement.inspect
name , value = *expression name , value = *statement
name = name.to_a.first name = name.to_a.first
v = process(value) v = process(value)
index = @method.has_local( name ) index = @method.has_local( name )

View File

@ -1,9 +0,0 @@
module Phisol
Compiler.class_eval do
# return attr_reader :expression
def on_return expression
return process(expression.to_a.first )
end
end
end

View File

@ -0,0 +1,9 @@
module Phisol
Compiler.class_eval do
# return attr_reader :statement
def on_return statement
return process(statement.to_a.first )
end
end
end

View File

@ -0,0 +1,8 @@
module Phisol
Compiler.class_eval do
def on_statements statement
process_all( statement.children )
end
end
end

View File

@ -1,9 +1,9 @@
module Phisol module Phisol
Compiler.class_eval do Compiler.class_eval do
def on_while expression def on_while statement
#puts expression.inspect #puts statement.inspect
condition , expressions = *expression condition , statements = *statement
condition = condition.first condition = condition.first
# this is where the while ends and both branches meet # this is where the while ends and both branches meet
@ -16,10 +16,10 @@ module Phisol
@method.source.add_code Register::IsZeroBranch.new(condition,merge) @method.source.add_code Register::IsZeroBranch.new(condition,merge)
last = process_all(expressions).last last = process_all(statements).last
# unconditionally branch to the start # unconditionally branch to the start
@method.source.add_code Register::AlwaysBranch.new(expression,start) @method.source.add_code Register::AlwaysBranch.new(statement,start)
# continue execution / compiling at the merge block # continue execution / compiling at the merge block
@method.source.current merge @method.source.current merge

View File

@ -108,7 +108,7 @@ module Virtual
# happened # happened
# But subsequent statements are still using the original block (self) to add code to # But subsequent statements are still using the original block (self) to add code to
# So the while expression creates the extra blocks, adds them and the code and then "moves" # So the while statement creates the extra blocks, adds them and the code and then "moves"
# the insertion point along # the insertion point along
def current block def current block
@current = block @current = block

View File

@ -11,11 +11,11 @@ class Object
end end
HERE HERE
expressions = Virtual.machine.boot.parse_and_compile input statements = Virtual.machine.boot.parse_and_compile input
if( expressions.first.is_a? Virtual::Self ) if( statements.first.is_a? Virtual::Self )
expressions.first.type.instance_variable_set :@of_class , nil statements.first.type.instance_variable_set :@of_class , nil
end end
is = Sof.write(expressions) is = Sof.write(statements)
#puts is #puts is
assert_equal @output , is assert_equal @output , is
end end

View File

@ -7,16 +7,16 @@ class CompilerTest < MiniTest::Test
Virtual.machine.boot Virtual.machine.boot
end end
def check def check
res = Phisol::Compiler.compile( @expression ) res = Phisol::Compiler.compile( @statement )
assert res.is_a?(Virtual::Slot) , "compiler must compile to slot, not #{res.inspect}" assert res.is_a?(Virtual::Slot) , "compiler must compile to slot, not #{res.inspect}"
end end
def test_function_expression def test_function_statement
@expression = s(:class, :Foo, @statement = s(:class, :Foo,
s(:derives, :Object), s(:derives, :Object),
s(:expressions, s(:statements,
s(:function, :int, s(:name, :foo), s(:function, :int, s(:name, :foo),
s(:parameters, s(:parameter, :ref, :x)), s(:parameters, s(:parameter, :ref, :x)),
s(:expressions, s(:int, 5))))) s(:statements, s(:int, 5)))))
check check
end end
end end

View File

@ -6,7 +6,7 @@ class HelloTest < MiniTest::Test
machine = Virtual.machine.boot machine = Virtual.machine.boot
Parfait::Space.object_space.get_class_by_name(:Integer).remove_instance_method :plus Parfait::Space.object_space.get_class_by_name(:Integer).remove_instance_method :plus
#TODO remove this hack: write proper aliases #TODO remove this hack: write proper aliases
expressions = machine.parse_and_compile @string_input statements = machine.parse_and_compile @string_input
output_at = "Register::CallImplementation" output_at = "Register::CallImplementation"
#{}"Register::CallImplementation" #{}"Register::CallImplementation"
machine.run_before output_at machine.run_before output_at

View File

@ -2,14 +2,14 @@ require_relative '../helper'
# simple tests to check parsing pworks and the first classes come out right. # simple tests to check parsing pworks and the first classes come out right.
# #
# build up from small to check larger expressions are correct # build up from small to check larger statements are correct
module Fragments module Fragments
def check def check
expressions = Virtual.machine.boot.parse_and_compile @string_input statements = Virtual.machine.boot.parse_and_compile @string_input
@expect.each_with_index do | should , i | @expect.each_with_index do | should , i |
exp_i = expressions[i] exp_i = statements[i]
assert exp_i.is_a?(Virtual::Slot) , "compiles should return #{should}, not #{exp_i}" assert exp_i.is_a?(Virtual::Slot) , "compiles should return #{should}, not #{exp_i}"
assert_equal should , exp_i.class assert_equal should , exp_i.class
end end

View File

@ -8,11 +8,11 @@ class AddTest < MiniTest::Test
Virtual.machine.boot Virtual.machine.boot
code = s(:class, :Object, code = s(:class, :Object,
s(:derives, nil), s(:derives, nil),
s(:expressions, s(:statements,
s(:function, :int, s(:function, :int,
s(:name, :main), s(:name, :main),
s(:parameters), s(:parameters),
s(:expressions, s(:statements,
s(:call, s(:call,
s(:name, :plus), s(:name, :plus),
s(:arguments , s(:int , 5)), s(:arguments , s(:int , 5)),

View File

@ -53,8 +53,8 @@ HERE
puts parts.inspect puts parts.inspect
Phisol::Compiler.compile( parts ) Phisol::Compiler.compile( parts )
# expressions = Virtual.machine.boot.parse_and_compile @string_input # statements = Virtual.machine.boot.parse_and_compile @string_input
# Phisol::Compiler.compile( expressions , Virtual.machine.space.get_main ) # Phisol::Compiler.compile( statements , Virtual.machine.space.get_main )
Virtual.machine.run_before "Register::CallImplementation" Virtual.machine.run_before "Register::CallImplementation"
@interpreter = Interpreter::Interpreter.new @interpreter = Interpreter::Interpreter.new
@interpreter.start Virtual.machine.init @interpreter.start Virtual.machine.init

View File

@ -7,11 +7,11 @@ class TestPuts < MiniTest::Test
Virtual.machine.boot Virtual.machine.boot
code = s(:class, :Object, code = s(:class, :Object,
s(:derives, nil), s(:derives, nil),
s(:expressions, s(:statements,
s(:function, :int, s(:function, :int,
s(:name, :main), s(:name, :main),
s(:parameters), s(:parameters),
s(:expressions, s(:statements,
s(:call, s(:call,
s(:name, :putstring), s(:name, :putstring),
s(:arguments), s(:arguments),

View File

@ -24,7 +24,7 @@ class TestRunner < MiniTest::Test
syntax = parser.parse_with_debug(string) syntax = parser.parse_with_debug(string)
assert syntax assert syntax
parts = Parser::Transform.new.apply(syntax) parts = Parser::Transform.new.apply(syntax)
# file is a list of expressions, all but the last must be a function # file is a list of statements, all but the last must be a function
# and the last is wrapped as a main # and the last is wrapped as a main
parts.each_with_index do |part,index| parts.each_with_index do |part,index|
if index == (parts.length - 1) if index == (parts.length - 1)