update to use new ast
soml was updated to have a typed ast layer to make programatic creation easier this brings LOTS of syntax change with it, that does not really mean anything at all All tests pass again so back to the same
This commit is contained in:
parent
d7b210d63a
commit
229f5896c6
@ -12,7 +12,7 @@ GIT
|
|||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: git://github.com/salama/soml-parser.git
|
remote: git://github.com/salama/soml-parser.git
|
||||||
revision: 4a9b492dd9fb1d7cbc6f114aee226ff227753568
|
revision: 5c03db709fa3a326288a57a65643bd9ddf905bec
|
||||||
specs:
|
specs:
|
||||||
soml-parser (0.5.0)
|
soml-parser (0.5.0)
|
||||||
ast (~> 2.1.0)
|
ast (~> 2.1.0)
|
||||||
|
@ -18,10 +18,10 @@ module Register
|
|||||||
def div10 context
|
def div10 context
|
||||||
s = "div_10"
|
s = "div_10"
|
||||||
compiler = Soml::Compiler.new.create_method(:Integer,:div10 ).init_method
|
compiler = Soml::Compiler.new.create_method(:Integer,:div10 ).init_method
|
||||||
me = compiler.process( s(:name , :self) )
|
me = compiler.process( Soml::NameExpression.new( :self) )
|
||||||
tmp = compiler.process( s(:name , :self) )
|
tmp = compiler.process( Soml::NameExpression.new( :self) )
|
||||||
q = compiler.process( s(:name , :self) )
|
q = compiler.process( Soml::NameExpression.new( :self) )
|
||||||
const = compiler.process( s(:int , 1) )
|
const = compiler.process( Soml::IntegerExpression.new(1) )
|
||||||
# int tmp = self >> 1
|
# int tmp = self >> 1
|
||||||
compiler.add_code Register.op( s , ">>" , tmp , const)
|
compiler.add_code Register.op( s , ">>" , tmp , const)
|
||||||
# int q = self >> 2
|
# int q = self >> 2
|
||||||
|
@ -13,7 +13,7 @@ module Register
|
|||||||
compiler = Soml::Compiler.new.create_method(:Object , :get_internal_word , {:index => :Integer}).init_method
|
compiler = Soml::Compiler.new.create_method(:Object , :get_internal_word , {:index => :Integer}).init_method
|
||||||
source = "get_internal_word"
|
source = "get_internal_word"
|
||||||
#Load self by "calling" on_name
|
#Load self by "calling" on_name
|
||||||
me = compiler.process( s(:name , :self) )
|
me = compiler.process( Soml::NameExpression.new( :self) )
|
||||||
# Load the argument
|
# Load the argument
|
||||||
index = compiler.use_reg :Integer
|
index = compiler.use_reg :Integer
|
||||||
compiler.add_code Register.get_slot(source , :message , Parfait::Message.get_indexed(1), index )
|
compiler.add_code Register.get_slot(source , :message , Parfait::Message.get_indexed(1), index )
|
||||||
@ -31,7 +31,7 @@ module Register
|
|||||||
{:index => :Integer, :value => :Object} ).init_method
|
{:index => :Integer, :value => :Object} ).init_method
|
||||||
source = "set_internal_word"
|
source = "set_internal_word"
|
||||||
#Load self by "calling" on_name
|
#Load self by "calling" on_name
|
||||||
me = compiler.process( s(:name , :self) )
|
me = compiler.process( Soml::NameExpression.new( :self) )
|
||||||
# Load the index
|
# Load the index
|
||||||
index = compiler.use_reg :Integer
|
index = compiler.use_reg :Integer
|
||||||
compiler.add_code Register.get_slot(source , :message , Parfait::Message.get_indexed(1), index )
|
compiler.add_code Register.get_slot(source , :message , Parfait::Message.get_indexed(1), index )
|
||||||
|
@ -13,14 +13,14 @@ module Register
|
|||||||
Kernel.emit_syscall( compiler , :putstring )
|
Kernel.emit_syscall( compiler , :putstring )
|
||||||
compiler.method
|
compiler.method
|
||||||
end
|
end
|
||||||
|
|
||||||
# self[index] basically. Index is the first arg > 0
|
# self[index] basically. Index is the first arg > 0
|
||||||
# return (and word sized int) is stored in return_value
|
# return (and word sized int) is stored in return_value
|
||||||
def get_internal_byte context
|
def get_internal_byte context
|
||||||
compiler = Soml::Compiler.new.create_method(:Word , :get_internal_byte , {:index => :Integer }).init_method
|
compiler = Soml::Compiler.new.create_method(:Word , :get_internal_byte , {:index => :Integer }).init_method
|
||||||
source = "get_internal_word"
|
source = "get_internal_word"
|
||||||
#Load self by "calling" on_name
|
#Load self by "calling" on_name
|
||||||
me = compiler.process( s(:name , :self) )
|
me = compiler.process( Soml::NameExpression.new( :self) )
|
||||||
# Load the argument
|
# Load the argument
|
||||||
index = compiler.use_reg :Integer
|
index = compiler.use_reg :Integer
|
||||||
compiler.add_code Register.get_slot(source , :message , Parfait::Message.get_indexed(1), index )
|
compiler.add_code Register.get_slot(source , :message , Parfait::Message.get_indexed(1), index )
|
||||||
@ -39,7 +39,7 @@ module Register
|
|||||||
{:index => :Integer, :value => :Integer } ).init_method
|
{:index => :Integer, :value => :Integer } ).init_method
|
||||||
source = "set_internal_word"
|
source = "set_internal_word"
|
||||||
#Load self by "calling" on_name
|
#Load self by "calling" on_name
|
||||||
me = compiler.process( s(:name , :self) )
|
me = compiler.process( Soml::NameExpression.new( :self) )
|
||||||
# Load the index
|
# Load the index
|
||||||
index = compiler.use_reg :Integer
|
index = compiler.use_reg :Integer
|
||||||
compiler.add_code Register.get_slot(source , :message , Parfait::Message.get_indexed(1), index )
|
compiler.add_code Register.get_slot(source , :message , Parfait::Message.get_indexed(1), index )
|
||||||
|
@ -19,7 +19,7 @@ module Register
|
|||||||
@source = source
|
@source = source
|
||||||
@next = nekst
|
@next = nekst
|
||||||
return unless source
|
return unless source
|
||||||
raise "Source must be string or ast node, not #{source.class}" unless source.is_a?(String) or source.is_a?(AST::Node)
|
raise "Source must be string or ast node, not #{source.class}" unless source.is_a?(String) or source.is_a?(Soml::Code)
|
||||||
end
|
end
|
||||||
attr_reader :source
|
attr_reader :source
|
||||||
|
|
||||||
|
@ -32,10 +32,11 @@ module Soml
|
|||||||
# Helper function to create a new compiler and compie the statement(s)
|
# Helper function to create a new compiler and compie the statement(s)
|
||||||
def self.compile statement
|
def self.compile statement
|
||||||
compiler = Compiler.new
|
compiler = Compiler.new
|
||||||
compiler.process statement
|
code = Soml.ast_to_code statement
|
||||||
|
compiler.process code
|
||||||
end
|
end
|
||||||
|
|
||||||
class Compiler < AST::Processor
|
class Compiler
|
||||||
|
|
||||||
def initialize( method = nil )
|
def initialize( method = nil )
|
||||||
@regs = []
|
@regs = []
|
||||||
@ -46,8 +47,33 @@ module Soml
|
|||||||
end
|
end
|
||||||
attr_reader :clazz , :method
|
attr_reader :clazz , :method
|
||||||
|
|
||||||
def handler_missing node
|
|
||||||
raise "No handler on_#{node.type}(node)"
|
# Dispatches `code` according to it's class name, for class NameExpression
|
||||||
|
# a method named `on_NameExpression` is invoked with one argument, the `code`
|
||||||
|
#
|
||||||
|
# @param [Soml::Code, nil] code
|
||||||
|
def process(code)
|
||||||
|
name = code.class.name.split("::").last
|
||||||
|
# Invoke a specific handler
|
||||||
|
on_handler = :"on_#{name}"
|
||||||
|
if respond_to? on_handler
|
||||||
|
return send on_handler, code
|
||||||
|
else
|
||||||
|
raise "No handler on_#{name}(code) #{code.inspect}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# {#process}es each code from `codes` and returns an array of
|
||||||
|
# results.
|
||||||
|
#
|
||||||
|
def process_all(codes)
|
||||||
|
codes.to_a.map do |code|
|
||||||
|
process code
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_Statements(codes)
|
||||||
|
process_all codes.statements
|
||||||
end
|
end
|
||||||
|
|
||||||
# create the method, do some checks and set it as the current method to be added to
|
# create the method, do some checks and set it as the current method to be added to
|
||||||
@ -150,7 +176,8 @@ module Soml
|
|||||||
|
|
||||||
def self.load_parfait
|
def self.load_parfait
|
||||||
each_parfait do |parts|
|
each_parfait do |parts|
|
||||||
self.new.process( parts )
|
code = Soml.ast_to_code parts
|
||||||
|
self.new.process( code )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
module Soml
|
module Soml
|
||||||
Compiler.class_eval do
|
Compiler.class_eval do
|
||||||
|
|
||||||
def on_assignment statement
|
def on_Assignment statement
|
||||||
reset_regs # statements reset registers, ie have all at their disposal
|
reset_regs # statements reset registers, ie have all at their disposal
|
||||||
#puts statement.inspect
|
#puts statement.inspect
|
||||||
name , value = *statement
|
# name , value = *statement
|
||||||
name = no_space name.to_a.first
|
name_s = no_space statement.name
|
||||||
v = process(value)
|
v = process(statement.value)
|
||||||
raise "Not register #{v}" unless v.is_a?(Register::RegisterValue)
|
raise "Not register #{v}" unless v.is_a?(Register::RegisterValue)
|
||||||
code = nil
|
code = nil
|
||||||
if( index = @method.has_arg(name))
|
if( index = @method.has_arg(name_s.name))
|
||||||
# TODO, check type @method.arguments[index].type
|
# TODO, check type @method.arguments[index].type
|
||||||
code = Register.set_slot(statement , v , :message , Parfait::Message.get_indexed(index) )
|
code = Register.set_slot(statement , v , :message , Parfait::Message.get_indexed(index) )
|
||||||
else # or a local so it is in the frame
|
else # or a local so it is in the frame
|
||||||
index = @method.has_local( name )
|
index = @method.has_local( name_s.name )
|
||||||
if(index)
|
if(index)
|
||||||
# TODO, check type @method.locals[index].type
|
# TODO, check type @method.locals[index].type
|
||||||
frame = use_reg(:Frame)
|
frame = use_reg(:Frame)
|
||||||
|
@ -10,41 +10,41 @@ module Soml
|
|||||||
|
|
||||||
# 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_IntegerExpression expression
|
||||||
int = expression.first
|
int = expression.value
|
||||||
reg = use_reg :Integer , int
|
reg = use_reg :Integer , int
|
||||||
add_code Register::LoadConstant.new( expression, int , reg )
|
add_code Register::LoadConstant.new( expression, int , reg )
|
||||||
return reg
|
return reg
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_true expression
|
def on_TrueExpression expression
|
||||||
reg = use_reg :Boolean
|
reg = use_reg :Boolean
|
||||||
add_code Register::LoadConstant.new( expression, true , reg )
|
add_code Register::LoadConstant.new( expression, true , reg )
|
||||||
return reg
|
return reg
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_false expression
|
def on_FalseExpression expression
|
||||||
reg = use_reg :Boolean
|
reg = use_reg :Boolean
|
||||||
add_code Register::LoadConstant.new( expression, false , reg )
|
add_code Register::LoadConstant.new( expression, false , reg )
|
||||||
return reg
|
return reg
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_nil expression
|
def on_NilExpression expression
|
||||||
reg = use_reg :NilClass
|
reg = use_reg :NilClass
|
||||||
add_code Register::LoadConstant.new( expression, nil , reg )
|
add_code Register::LoadConstant.new( expression, nil , reg )
|
||||||
return reg
|
return reg
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_string expression
|
def on_StringExpression expression
|
||||||
value = Parfait.new_word expression.first.to_sym
|
value = Parfait.new_word expression.value.to_sym
|
||||||
reg = use_reg :Word
|
reg = use_reg :Word
|
||||||
Register.machine.constants << value
|
Register.machine.constants << value
|
||||||
add_code Register::LoadConstant.new( expression, value , reg )
|
add_code Register::LoadConstant.new( expression, value , reg )
|
||||||
return reg
|
return reg
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_class_name expression
|
def on_ClassExpression expression
|
||||||
name = expression.first
|
name = expression.value
|
||||||
clazz = Parfait::Space.object_space.get_class_by_name! name
|
clazz = Parfait::Space.object_space.get_class_by_name! name
|
||||||
raise "No such class #{name}" unless clazz
|
raise "No such class #{name}" unless clazz
|
||||||
reg = use_reg :MetaClass , clazz
|
reg = use_reg :MetaClass , clazz
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
module Soml
|
module Soml
|
||||||
Compiler.class_eval do
|
Compiler.class_eval do
|
||||||
|
|
||||||
def on_call statement
|
def on_CallSite statement
|
||||||
#puts statement
|
#puts statement
|
||||||
name_s , arguments , receiver = *statement
|
# name_s , arguments , receiver = *statement
|
||||||
raise "not inside method " unless @method
|
raise "not inside method " unless @method
|
||||||
reset_regs
|
reset_regs
|
||||||
#move the new message (that we need to populate to make a call) to std register
|
#move the new message (that we need to populate to make a call) to std register
|
||||||
new_message = Register.resolve_to_register(:new_message)
|
new_message = Register.resolve_to_register(:new_message)
|
||||||
add_code Register.get_slot(statement, :message , :next_message , new_message )
|
add_code Register.get_slot(statement, :message , :next_message , new_message )
|
||||||
if receiver
|
if statement.receiver
|
||||||
me = process( receiver.first )
|
me = process( statement.receiver )
|
||||||
else
|
else
|
||||||
me = use_reg @method.for_class.name
|
me = use_reg @method.for_class.name
|
||||||
add_code Register.get_slot(statement, :message , :receiver , me )
|
add_code Register.get_slot(statement, :message , :receiver , me )
|
||||||
@ -24,8 +24,8 @@ module Soml
|
|||||||
# move our receiver there
|
# move our receiver there
|
||||||
add_code Register.set_slot( statement , me , :new_message , :receiver)
|
add_code Register.set_slot( statement , me , :new_message , :receiver)
|
||||||
|
|
||||||
set_message_details(name_s , arguments)
|
set_message_details(statement , statement.arguments)
|
||||||
set_arguments(arguments)
|
set_arguments(statement.arguments)
|
||||||
ret = use_reg( :Integer ) #TODO real return type
|
ret = use_reg( :Integer ) #TODO real return type
|
||||||
do_call(clazz , statement)
|
do_call(clazz , statement)
|
||||||
# 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
|
||||||
@ -36,7 +36,7 @@ module Soml
|
|||||||
|
|
||||||
private
|
private
|
||||||
def do_call clazz , statement
|
def do_call clazz , statement
|
||||||
name = statement.first.first
|
name = statement.name
|
||||||
#puts "clazz #{clazz.name}"
|
#puts "clazz #{clazz.name}"
|
||||||
raise "No such class" unless clazz
|
raise "No such class" unless clazz
|
||||||
method = clazz.resolve_method(name)
|
method = clazz.resolve_method(name)
|
||||||
@ -45,15 +45,15 @@ module Soml
|
|||||||
Register.issue_call( self , method )
|
Register.issue_call( self , method )
|
||||||
end
|
end
|
||||||
def set_message_details name_s , arguments
|
def set_message_details name_s , arguments
|
||||||
name = name_s.to_a.first
|
name = name_s.name
|
||||||
# load method name and set to new message (for exceptions/debug)
|
# load method name and set to new message (for exceptions/debug)
|
||||||
name_tmp = use_reg(:Word)
|
name_tmp = use_reg(:Word)
|
||||||
add_code Register::LoadConstant.new(name_s, name , name_tmp)
|
add_code Register::LoadConstant.new(name_s, name , name_tmp)
|
||||||
add_code Register.set_slot( name_s , name_tmp , :new_message , :name)
|
add_code Register.set_slot( name_s , name_tmp , :new_message , :name)
|
||||||
# next arguments. first length then args
|
# next arguments. first length then args
|
||||||
len_tmp = use_reg(:Integer , arguments.to_a.length )
|
len_tmp = use_reg(:Integer , arguments.to_a.length )
|
||||||
add_code Register::LoadConstant.new(arguments, arguments.to_a.length , len_tmp)
|
add_code Register::LoadConstant.new(name_s, arguments.to_a.length , len_tmp)
|
||||||
add_code Register.set_slot( arguments , len_tmp , :new_message , :indexed_length)
|
add_code Register.set_slot( name_s , len_tmp , :new_message , :indexed_length)
|
||||||
end
|
end
|
||||||
def set_arguments arguments
|
def set_arguments arguments
|
||||||
# reset tmp regs for each and load result into new_message
|
# reset tmp regs for each and load result into new_message
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
module Soml
|
module Soml
|
||||||
Compiler.class_eval do
|
Compiler.class_eval do
|
||||||
|
|
||||||
def on_class_field statement
|
def on_ClassField statement
|
||||||
#puts statement.inspect
|
#puts statement.inspect
|
||||||
type , name , value = *statement
|
#type , name , value = *statement
|
||||||
|
|
||||||
for_class = @clazz
|
for_class = @clazz
|
||||||
raise "no class" unless for_class
|
raise "no class" unless for_class
|
||||||
index = for_class.instance_type.variable_index(name)
|
index = for_class.instance_type.variable_index(statement.name)
|
||||||
#raise "class field already defined:#{name} for class #{for_class.name}" if index
|
#raise "class field already defined:#{name} for class #{for_class.name}" if index
|
||||||
#puts "Define field #{name} on class #{for_class.name}"
|
#puts "Define field #{name} on class #{for_class.name}"
|
||||||
index = for_class.instance_type.add_instance_variable( name , type )
|
index = for_class.instance_type.add_instance_variable( statement.name , statement.type )
|
||||||
|
|
||||||
# not sure how to run class code yet. later
|
|
||||||
raise "value #{value}" if value
|
|
||||||
|
|
||||||
return nil # statements don't reurn values, only expressions
|
return nil # statements don't reurn values, only expressions
|
||||||
end
|
end
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
module Soml
|
module Soml
|
||||||
Compiler.class_eval do
|
Compiler.class_eval do
|
||||||
|
|
||||||
def on_class statement
|
def on_ClassStatement statement
|
||||||
#puts statement.inspect
|
#puts statement.inspect
|
||||||
name , derives , statements = *statement
|
|
||||||
raise "classes dont yet play babushka, get coding #{name}" if @clazz
|
raise "classes dont yet play babushka, get coding #{name}" if @clazz
|
||||||
@clazz = Parfait::Space.object_space.get_class_by_name! name
|
@clazz = Parfait::Space.object_space.get_class_by_name! statement.name
|
||||||
#puts "Compiling class #{@clazz.name.inspect}"
|
#puts "Compiling class #{@clazz.name.inspect}"
|
||||||
statement_value = process_all(statements).last
|
statement_value = process(statement.statements).last
|
||||||
@clazz = nil
|
@clazz = nil
|
||||||
return statement_value
|
return statement_value
|
||||||
end
|
end
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
module Soml
|
module Soml
|
||||||
Compiler.class_eval do
|
Compiler.class_eval do
|
||||||
|
|
||||||
def on_field_access statement
|
def on_FieldAccess statement
|
||||||
receiver_ast , field_ast = *statement
|
# receiver_ast , field_ast = *statement
|
||||||
receiver = process(receiver_ast)
|
receiver = process(statement.receiver)
|
||||||
|
|
||||||
clazz = Register.machine.space.get_class_by_name receiver.type
|
clazz = Register.machine.space.get_class_by_name receiver.type
|
||||||
|
|
||||||
field_name = field_ast.first_from(:name)
|
field_name = statement.field.name
|
||||||
|
|
||||||
|
|
||||||
index = clazz.instance_type.variable_index(field_name)
|
index = clazz.instance_type.variable_index(field_name)
|
||||||
|
@ -2,14 +2,14 @@ module Soml
|
|||||||
Compiler.class_eval do
|
Compiler.class_eval do
|
||||||
include AST::Sexp
|
include AST::Sexp
|
||||||
|
|
||||||
def on_field_def statement
|
def on_FieldDef statement
|
||||||
reset_regs # field_def is a statement, no return and all regs
|
reset_regs # field_def is a statement, no return and all regs
|
||||||
#puts statement.inspect
|
#puts statement.inspect
|
||||||
type , name , value = *statement
|
# type , name , value = *statement
|
||||||
name_s = no_space( name.first )
|
name_s = no_space( statement.name.value )
|
||||||
@method.ensure_local( name_s, type ) unless( @method.has_arg(name_s))
|
@method.ensure_local( name_s, statement.type ) unless( @method.has_arg(name_s))
|
||||||
# if there is a value assigned, process it as am assignemnt statement (kind of call on_assign)
|
# if there is a value assigned, process it as am assignemnt statement (kind of call on_assign)
|
||||||
process( s(:assignment , name , value ) ) if value
|
process( Soml::Assignment.new(statement.name , statement.value ) ) if statement.value
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
module Soml
|
module Soml
|
||||||
Compiler.class_eval do
|
Compiler.class_eval do
|
||||||
|
|
||||||
def on_function statement
|
def on_FunctionStatement statement
|
||||||
#puts statement.inspect
|
#puts statement.inspect
|
||||||
return_type , name , parameters, kids , receiver = *statement
|
# return_type , name , parameters, kids , receiver = *statement
|
||||||
name = name.to_a.first
|
name = statement.name
|
||||||
raise "Already in method #{@method}" if @method
|
raise "Already in method #{@method}" if @method
|
||||||
|
|
||||||
args = parameters.to_a.collect do |p|
|
args = statement.parameters.collect do |p|
|
||||||
raise "error, argument must be a identifier, not #{p}" unless p.type == :parameter
|
Parfait::Variable.new( *p )
|
||||||
Parfait::Variable.new( *p)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class_method = nil
|
class_method = nil
|
||||||
if(receiver )
|
if(statement.receiver )
|
||||||
if( receiver.first == :self) #class method
|
if( statement.receiver.first == :self) #class method
|
||||||
class_method = @clazz
|
class_method = @clazz
|
||||||
@clazz = @clazz.meta
|
@clazz = @clazz.meta
|
||||||
else
|
else
|
||||||
raise "Not covered #{receiver}"
|
raise "Not covered #{statement.receiver}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -33,9 +32,8 @@ module Soml
|
|||||||
@method.source = statement
|
@method.source = statement
|
||||||
#puts "compile method #{@method.name}"
|
#puts "compile method #{@method.name}"
|
||||||
|
|
||||||
kids.to_a.each do |ex|
|
process(statement.statements)
|
||||||
process(ex)
|
|
||||||
end
|
|
||||||
@clazz = class_method if class_method
|
@clazz = class_method if class_method
|
||||||
@method = nil
|
@method = nil
|
||||||
# function definition is a statement, does not return any value
|
# function definition is a statement, does not return any value
|
||||||
|
@ -4,27 +4,27 @@ module Soml
|
|||||||
# an if evaluates the condition and jumps to the true block if true
|
# an if evaluates the condition and jumps to the true block if true
|
||||||
# so the else block is automatically after that.
|
# so the else block is automatically after that.
|
||||||
# But then the else needs to jump over the true block unconditionally.
|
# But then the else needs to jump over the true block unconditionally.
|
||||||
def on_if_statement statement
|
def on_IfStatement statement
|
||||||
branch_type , condition , if_true , if_false = *statement
|
# branch_type , condition , if_true , if_false = *statement
|
||||||
condition = condition.first
|
# condition = condition.first
|
||||||
|
|
||||||
reset_regs
|
reset_regs
|
||||||
process(condition)
|
process(statement.condition)
|
||||||
|
|
||||||
branch_class = Object.const_get "Register::Is#{branch_type.capitalize}"
|
branch_class = Object.const_get "Register::Is#{statement.branch_type.capitalize}"
|
||||||
true_block = Register::Label.new(if_true, "if_true")
|
true_block = Register::Label.new(statement, "if_true")
|
||||||
add_code branch_class.new( condition , true_block )
|
add_code branch_class.new( statement.condition , true_block )
|
||||||
|
|
||||||
# compile the false block
|
# compile the false block
|
||||||
reset_regs
|
reset_regs
|
||||||
process_all(if_false) if if_false
|
process(statement.if_false) if statement.if_false.statements
|
||||||
merge = Register::Label.new(statement , "if_merge")
|
merge = Register::Label.new(statement , "if_merge")
|
||||||
add_code Register::Branch.new(if_false, merge )
|
add_code Register::Branch.new(statement.if_false, merge )
|
||||||
|
|
||||||
# compile the true block
|
# compile the true block
|
||||||
add_code true_block
|
add_code true_block
|
||||||
reset_regs
|
reset_regs
|
||||||
process_all(if_true)
|
process(statement.if_true)
|
||||||
|
|
||||||
#puts "compiled if: end"
|
#puts "compiled if: end"
|
||||||
add_code merge
|
add_code merge
|
||||||
|
@ -2,11 +2,11 @@ module Soml
|
|||||||
Compiler.class_eval do
|
Compiler.class_eval do
|
||||||
|
|
||||||
# attr_reader :name
|
# attr_reader :name
|
||||||
# compiling name needs to check if it's a variable and if so resolve it
|
# compiling name needs to check if it's a local variable
|
||||||
# otherwise it's a method without args and a send is issued.
|
# or an argument
|
||||||
# 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 statement
|
def on_NameExpression statement
|
||||||
name = statement.to_a.first
|
name = statement.name
|
||||||
if( name == :self)
|
if( name == :self)
|
||||||
ret = use_reg @clazz.name
|
ret = use_reg @clazz.name
|
||||||
add_code Register.get_slot(statement , :message , :receiver , ret )
|
add_code Register.get_slot(statement , :message , :receiver , ret )
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
module Soml
|
module Soml
|
||||||
Compiler.class_eval do
|
Compiler.class_eval do
|
||||||
|
|
||||||
def on_operator_value statement
|
def on_OperatorExpression statement
|
||||||
#puts "operator #{statement.inspect}"
|
#puts "operator #{statement.inspect}"
|
||||||
operator , left_e , right_e = *statement
|
# operator , left_e , right_e = *statement
|
||||||
# left and right must be expressions. Expressions return a register when compiled
|
# left and right must be expressions. Expressions return a register when compiled
|
||||||
left_reg = process(left_e)
|
left_reg = process(statement.left_expression)
|
||||||
right_reg = process(right_e)
|
right_reg = process(statement.right_expression)
|
||||||
raise "Not register #{left_reg}" unless left_reg.is_a?(Register::RegisterValue)
|
raise "Not register #{left_reg}" unless left_reg.is_a?(Register::RegisterValue)
|
||||||
raise "Not register #{right_reg}" unless right_reg.is_a?(Register::RegisterValue)
|
raise "Not register #{right_reg}" unless right_reg.is_a?(Register::RegisterValue)
|
||||||
#puts "left #{left_reg}"
|
#puts "left #{left_reg}"
|
||||||
#puts "right #{right_reg}"
|
#puts "right #{right_reg}"
|
||||||
add_code Register::OperatorInstruction.new(statement,operator,left_reg,right_reg)
|
add_code Register::OperatorInstruction.new(statement,statement.operator,left_reg,right_reg)
|
||||||
return left_reg # though this has wrong value attached
|
return left_reg # though this has wrong value attached
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
module Soml
|
module Soml
|
||||||
Compiler.class_eval do
|
Compiler.class_eval do
|
||||||
|
|
||||||
def on_return statement
|
def on_ReturnStatement statement
|
||||||
reg = process(statement.first)
|
reg = process(statement.return_value)
|
||||||
add_code Register.set_slot( statement, reg , :message , :return_value)
|
add_code Register.set_slot( statement, reg , :message , :return_value)
|
||||||
nil # statements don't return
|
nil # statements don't return
|
||||||
end
|
end
|
||||||
|
@ -1,27 +1,26 @@
|
|||||||
module Soml
|
module Soml
|
||||||
Compiler.class_eval do
|
Compiler.class_eval do
|
||||||
|
|
||||||
def on_while_statement statement
|
def on_WhileStatement statement
|
||||||
#puts statement.inspect
|
#puts statement.inspect
|
||||||
branch_type , condition , statements = *statement
|
#branch_type , condition , statements = *statement
|
||||||
condition = condition.first
|
|
||||||
|
|
||||||
condition_label = Register::Label.new(statement , "condition_label")
|
condition_label = Register::Label.new(statement.condition , "condition_label")
|
||||||
# unconditionally branch to the condition upon entering the loop
|
# unconditionally branch to the condition upon entering the loop
|
||||||
add_code Register::Branch.new(statement,condition_label)
|
add_code Register::Branch.new(statement.condition,condition_label)
|
||||||
|
|
||||||
add_code start = Register::Label.new(statement , "while_start" )
|
add_code start = Register::Label.new(statement , "while_start" )
|
||||||
reset_regs
|
reset_regs
|
||||||
process_all(statements)
|
process(statement.statements)
|
||||||
|
|
||||||
# This is where the loop starts, though in subsequent iterations it's in the middle
|
# This is where the loop starts, though in subsequent iterations it's in the middle
|
||||||
add_code condition_label
|
add_code condition_label
|
||||||
reset_regs
|
reset_regs
|
||||||
process(condition)
|
process(statement.condition)
|
||||||
|
|
||||||
branch_class = Object.const_get "Register::Is#{branch_type.capitalize}"
|
branch_class = Object.const_get "Register::Is#{statement.branch_type.capitalize}"
|
||||||
# this is where the while ends and both branches meet
|
# this is where the while ends and both branches meet
|
||||||
add_code branch_class.new( condition , start )
|
add_code branch_class.new( statement.condition , start )
|
||||||
|
|
||||||
nil # statements don't return anything
|
nil # statements don't return anything
|
||||||
end
|
end
|
||||||
|
@ -21,10 +21,11 @@ module ExpressionHelper
|
|||||||
parser = parser.send @root
|
parser = parser.send @root
|
||||||
syntax = parser.parse_with_debug(@string_input, reporter: Parslet::ErrorReporter::Deepest.new)
|
syntax = parser.parse_with_debug(@string_input, reporter: Parslet::ErrorReporter::Deepest.new)
|
||||||
parts = Parser::Transform.new.apply(syntax)
|
parts = Parser::Transform.new.apply(syntax)
|
||||||
|
codes = Soml.ast_to_code parts
|
||||||
#puts parts.inspect
|
#puts parts.inspect
|
||||||
compiler = Soml::Compiler.new
|
compiler = Soml::Compiler.new
|
||||||
set_main(compiler)
|
set_main(compiler)
|
||||||
produced = compiler.process( parts )
|
produced = compiler.process( codes )
|
||||||
assert @output , "No output given"
|
assert @output , "No output given"
|
||||||
assert_equal produced.class, @output , "Wrong class"
|
assert_equal produced.class, @output , "Wrong class"
|
||||||
produced
|
produced
|
||||||
|
@ -30,7 +30,7 @@ class TestBasic < MiniTest::Test
|
|||||||
def test_var
|
def test_var
|
||||||
@string_input = 'int foo '
|
@string_input = 'int foo '
|
||||||
@root = :field_def
|
@root = :field_def
|
||||||
@output = AST::Node
|
@output = NilClass
|
||||||
check
|
check
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -40,19 +40,6 @@ HERE
|
|||||||
check
|
check
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_class_field_value
|
|
||||||
@string_input = <<HERE
|
|
||||||
class Space
|
|
||||||
field int boo1 = 1
|
|
||||||
int main()
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
HERE
|
|
||||||
@expect = [Label, LoadConstant,SetSlot,Label,FunctionReturn]
|
|
||||||
assert_raises{check}
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_class_field
|
def test_class_field
|
||||||
@string_input = <<HERE
|
@string_input = <<HERE
|
||||||
class Space
|
class Space
|
||||||
|
Loading…
x
Reference in New Issue
Block a user