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
remote: git://github.com/salama/salama-reader.git
revision: 58b3553251bd23d2b666b25e23c8bc13ad87acdb
revision: 6bd5e9b5ee26e4e0157283e9af4389b13d660193
specs:
salama-reader (0.3.0)
salama-reader (0.4.0)
ast (~> 2.1.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).
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.
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)
- SOF parser
- 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

View File

@ -13,35 +13,35 @@ module Phisol
# Some compile methods just add code, some may add structure (ie Blocks) while
# 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.
# 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
# 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,
# as long as matching compile methods are supplied too.
#
def self.compile expression
def self.compile statement
compiler = Compiler.new
compiler.process expression
compiler.process statement
end
end
end
require_relative "ast_helper"
require_relative "compiler/basic_expressions"
require_relative "compiler/callsite_expression"
require_relative "compiler/basic_values"
require_relative "compiler/call_site"
require_relative "compiler/class_field"
require_relative "compiler/compound_expressions"
require_relative "compiler/expression_list"
require_relative "compiler/collections"
require_relative "compiler/statement_list"
require_relative "compiler/field_def"
require_relative "compiler/field_access"
require_relative "compiler/function_expression"
require_relative "compiler/if_expression"
require_relative "compiler/module_expression"
require_relative "compiler/function_definition"
require_relative "compiler/if_statement"
require_relative "compiler/class_statement"
require_relative "compiler/name_expression"
require_relative "compiler/operator_expressions"
require_relative "compiler/return_expression"
require_relative "compiler/while_expression"
require_relative "compiler/operator_value"
require_relative "compiler/return_statement"
require_relative "compiler/while_statement"

View File

@ -3,7 +3,7 @@ module Phisol
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_
# 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
@ -11,34 +11,34 @@ module Phisol
# 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
def on_int expression
int = expression.first
def on_int statement
int = statement.first
to = Virtual::Return.new(Virtual::Integer , int)
@method.source.add_code Virtual::Set.new( int , to )
to
end
def on_true expression
def on_true statement
to = Virtual::Return.new(Virtual::Reference , true )
@method.source.add_code Virtual::Set.new( true , to )
to
end
def on_false expression
def on_false statement
to = Virtual::Return.new(Virtual::Reference , false)
@method.source.add_code Virtual::Set.new( false , to )
to
end
def on_nil expression
def on_nil statement
to = Virtual::Return.new(Virtual::Reference , nil)
@method.source.add_code Virtual::Set.new( nil , to )
to
end
def on_string expression
def on_string statement
# 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)
@method.source.constants << value
@method.source.add_code Virtual::Set.new( value , to )

View File

@ -1,8 +1,8 @@
module Phisol
Compiler.class_eval do
def on_call expression
name , arguments , receiver = *expression
def on_call statement
name , arguments , receiver = *statement
name = name.to_a.first
raise "not inside method " unless @method
if receiver
@ -65,7 +65,7 @@ module Phisol
end
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
# (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 )
end
end

View File

@ -1,9 +1,9 @@
module Phisol
Compiler.class_eval do
def on_class_field expression
#puts expression.inspect
type , name , value = *expression
def on_class_field statement
#puts statement.inspect
type , name , value = *statement
for_class = @clazz
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
# attr_reader :values
def on_array expession, context
def on_array statement, context
end
# attr_reader :key , :value
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
Compiler.class_eval do
def on_field_access expression
#puts expression.inspect
receiver_ast , field_ast = *expression
def on_field_access statement
#puts statement.inspect
receiver_ast , field_ast = *statement
receiver = receiver_ast.first_from(:name)
field_name = field_ast.first_from(:name)

View File

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

View File

@ -1,9 +1,9 @@
module Phisol
Compiler.class_eval do
def on_function expression
#puts expression.inspect
return_type , name , parameters, kids , receiver = *expression
def on_function statement
#puts statement.inspect
return_type , name , parameters, kids , receiver = *statement
name = name.to_a.first
args = parameters.to_a.collect do |p|
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
# if - attr_reader :cond, :if_true, :if_false
def on_if expression
condition , if_true , if_false = *expression
def on_if statement
condition , if_true , if_false = *statement
condition = condition.first
# 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 ,
@ -25,7 +25,7 @@ module Phisol
# compile the false block
@method.source.current false_block
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"
@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
# 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)
def on_name expression
name = expression.to_a.first
def on_name statement
name = statement.to_a.first
return Virtual::Self.new( Virtual::Reference.new(@clazz)) if name == :self
# either an argument, so it's stored in message
if( index = @method.has_arg(name))

View File

@ -1,30 +1,30 @@
module Phisol
Compiler.class_eval do
def on_operator expression
puts "operator #{expression.inspect}"
operator , left_e , right_e = *expression
def on_operator statement
puts "operator #{statement.inspect}"
operator , left_e , right_e = *statement
left_slot = process(left_e)
right_slot = process(right_e)
puts "left #{left_slot}"
puts "right #{right_slot}"
tmp1 = Register.tmp_reg
tmp2 = tmp1.next_reg_use
get = Register.get_slot_to(expression , left_slot , tmp1 )
get2 = Register.get_slot_to(expression , right_slot , tmp2 )
get = Register.get_slot_to(statement , left_slot , tmp1 )
get2 = Register.get_slot_to(statement , right_slot , tmp2 )
puts "GET #{get}"
puts "GET2 #{get2}"
@method.source.add_code get
@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 )
end
def on_assign expression
puts expression.inspect
name , value = *expression
def on_assign statement
puts statement.inspect
name , value = *statement
name = name.to_a.first
v = process(value)
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
Compiler.class_eval do
def on_while expression
#puts expression.inspect
condition , expressions = *expression
def on_while statement
#puts statement.inspect
condition , statements = *statement
condition = condition.first
# 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)
last = process_all(expressions).last
last = process_all(statements).last
# 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
@method.source.current merge

View File

@ -108,7 +108,7 @@ module Virtual
# happened
# 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
def current block
@current = block

View File

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

View File

@ -7,16 +7,16 @@ class CompilerTest < MiniTest::Test
Virtual.machine.boot
end
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}"
end
def test_function_expression
@expression = s(:class, :Foo,
def test_function_statement
@statement = s(:class, :Foo,
s(:derives, :Object),
s(:expressions,
s(:statements,
s(:function, :int, s(:name, :foo),
s(:parameters, s(:parameter, :ref, :x)),
s(:expressions, s(:int, 5)))))
s(:statements, s(:int, 5)))))
check
end
end

View File

@ -6,7 +6,7 @@ class HelloTest < MiniTest::Test
machine = Virtual.machine.boot
Parfait::Space.object_space.get_class_by_name(:Integer).remove_instance_method :plus
#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"
#{}"Register::CallImplementation"
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.
#
# build up from small to check larger expressions are correct
# build up from small to check larger statements are correct
module Fragments
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 |
exp_i = expressions[i]
exp_i = statements[i]
assert exp_i.is_a?(Virtual::Slot) , "compiles should return #{should}, not #{exp_i}"
assert_equal should , exp_i.class
end

View File

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

View File

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

View File

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

View File

@ -24,7 +24,7 @@ class TestRunner < MiniTest::Test
syntax = parser.parse_with_debug(string)
assert 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
parts.each_with_index do |part,index|
if index == (parts.length - 1)