Skip to content
This repository has been archived by the owner on May 13, 2019. It is now read-only.

Commit

Permalink
For loop appears to be working now.
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewd committed Nov 20, 2010
1 parent d21fcee commit c6c4daf
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 33 deletions.
54 changes: 23 additions & 31 deletions lib/rasp/ast/flow.rb
Expand Up @@ -59,71 +59,66 @@ def initialize(var, start, finish, step, body)
@var, @start, @finish, @step = var, start, finish, step
end
def bytecode(g)
# FIXME
if g.state.scope.variables.key? var
loop_var = g.state.scope.variable(var).reference
else
loop_var = g.state.scope.global.variable(var).reference
end

finish_var = Rubinius::Compiler::LocalVariable.new(g.state.scope.allocate_slot).reference
@finish.bytecode(g)
finish_var.set_bytecode(g)

unless Rasp::AST::Literal === @step || @step.nil?
step_var = Rubinius::Compiler::LocalVariable.new(g.state.scope.allocate_slot).reference
dir_var = Rubinius::Compiler::LocalVariable.new(g.state.scope.allocate_slot).reference

if @step
@step.bytecode(g) if @step
g.dup
step_var.set_bytecode(g)
g.meta_push_0
g.send_stack :<, 1
dir_var.set_bytecode(g)
unless Rasp::AST::Literal === @step
g.dup
g.meta_push_0
g.send :<, 1
end
end

@start.bytecode(g)
loop_var.set_bytecode(g)
g.pop

loop_body = g.new_label
loop_body.set!

@body.each do |s|
#s.bytecode(g)
s.bytecode(g)
end

if Rasp::AST::Literal === @step || @step.nil?
# Step is constant

if @step
@step.bytecode(g)
g.dup_many 2 # @step, @finish, ...
loop_var.get_bytecode(g)
g.send_stack :+, 1
g.send :+, 1
else
g.dup # @finish, ...
loop_var.get_bytecode(g)
g.send_vcall :inc
end
g.dup
loop_var.set_bytecode(g)
finish_var.get_bytecode(g)
g.swap

if @step.nil? || @step.value > 0
# Always working forwards
g.send_stack :>, 1
g.send :>, 1
elsif @step.value < 0
# Always working backwards
g.send_stack :<, 1
g.send :<, 1
else
# Constant step of zero?! Twit.
raise "For loop cannot have a zero step"
end

g.gif loop_body

# finish_var is done now; can we get rid of it?
if @step
g.pop_many 2
else
g.pop
end
else
raise "dynstep!"
# Dynamic step; have to work out which way we're going at runtime
# Experimentation shows this isn't as scary as it seems; the
# reference implementation only evaluates the Step value once, as
Expand All @@ -137,25 +132,22 @@ def bytecode(g)
check_backwards = g.new_label
end_loop = g.new_label

finish_var.get_bytecode(g)
step_var.get_bytecode(g)
g.dup_many 3 # loop_backwards, @step, @finish, ...
loop_var.get_bytecode(g)
g.send_stack :+, 1
g.dup
g.send :+, 1
loop_var.set_bytecode(g)

dir_var.get_bytecode(g)
g.git check_backwards

g.send_stack :>, 1
g.send :>, 1
g.gif loop_body
g.goto end_loop

check_backwards.set!
g.send_stack :<, 1
g.send :<, 1
g.gif loop_body

end_loop.set!
g.pop_many 3
end
end
end
Expand Down
4 changes: 3 additions & 1 deletion lib/rasp/ast/simple.rb
Expand Up @@ -37,7 +37,9 @@ def initialize(vars)
@vars = vars
end
def bytecode(g)
# Compiler directive
vars.each do |var|
g.state.scope.variable(var)
end
end
end
class ErrorControl < Statement
Expand Down
2 changes: 1 addition & 1 deletion lib/rasp/parser.citrus
Expand Up @@ -77,7 +77,7 @@ grammar Rasp::Parser
end
rule for_next
(`for` SP identifier SP? "=" SP? start:expression SP `to` SP finish:expression (SP `step` SP step:expression)? ENDSTATEMENT body:(statement*) `next` ENDSTATEMENT)
{ Rasp::AST::ForLoop.new(identifier.value, start.value, finish.value, first(:step) && first(:step).value, body.matches.map {|m| m.value }) }
{ Rasp::AST::ForLoop.new(identifier.value, start.value, finish.value, first(:step) && first(:step).value, body.matches.map {|m| m.value }.compact) }
end
rule single_line_if
(`if` SP expression SP `then` SP truepart:(single:single_line_if { [single] } | list:simple_statement_chain) (SP `else` SP falsepart:(single:single_line_if | list:simple_statement_chain EOL) | EOL) )
Expand Down

0 comments on commit c6c4daf

Please sign in to comment.