Permalink
Browse files

Ok, now let's see how the hell we test everything

  • Loading branch information...
1 parent 17f89d2 commit 3d3bb6e3fae9bb6c6f082b4626e09a94756ff04e @txus committed May 15, 2011
View
@@ -3,3 +3,4 @@ pkg/*
.bundle
coverage
*.rbc
+*.bfc
View
@@ -1,15 +1,15 @@
PATH
remote: .
specs:
- brainfuck (0.1.2)
+ brainfuck (0.2.0)
highline
parslet
GEM
remote: http://rubygems.org/
specs:
blankslate (2.1.2.4)
- highline (1.6.1)
+ highline (1.6.2)
minitest (2.0.2)
mocha (0.9.12)
parslet (1.2.0)
View
@@ -1,27 +1,9 @@
require 'parslet'
-require 'highline/system_extensions'
-require 'brainfuck/stack'
require 'brainfuck/ast'
-
+require 'brainfuck/lexer'
require 'brainfuck/parser'
-require 'brainfuck/interpreter'
require 'brainfuck/stages'
require 'brainfuck/compiler'
require 'brainfuck/main'
require 'brainfuck/code_loader'
-
-module Brainfuck
- class << self
- def run code
- Interpreter.stack.clear
-
- code = Parser.clean code
- parsed = Parser.new.parse code
- ast = Interpreter.new.apply parsed
- Compiler.compile_ast ast, 'file', Compiler::Print.new(true, true, true)
- ast.each(&:eval)
- Interpreter.stack.to_a
- end
- end
-end
View
@@ -1,68 +1,134 @@
module Brainfuck
module AST
- class FwdNode < Struct.new(:stack)
- def eval; stack.fwd ; end
+ class FwdNode
def bytecode(g)
- g.push_literal 1
- g.push 1
- g.meta_send_op_plus(0)
- puts g.state.scope.methods.sort
- g.set_literal g.state.scope.new_literal(:pointer).reference.slot
+ g.push_local 1
+ g.meta_push_1
+ g.meta_send_op_plus 0
+ g.set_local 1
+
+ # Check the contents of the new cell
+ g.push_local 0
+ g.swap_stack
+ g.send :[], 1, false
+
+ fin = g.new_label
+ g.git fin
g.pop
+
+ # If the cell is nil set it to 0
+ g.push_local 0
+ g.push_local 1
+ g.meta_push_0
+ g.send :[]=, 2, false
+
+ # Otherwise, do nothing
+ fin.set!
end
end
- class BwdNode < Struct.new(:stack)
- def eval; stack.bwd ; end
+ class BwdNode
def bytecode(g)
- g.push 1
+ g.push_local 1
+ g.meta_push_1
+ g.meta_send_op_minus 0
+ g.set_local 1
+
+ # Check the contents of the new cell
+ g.push_local 0
+ g.swap_stack
+ g.send :[], 1, false
+
+ fin = g.new_label
+ g.git fin
+ g.pop
+
+ # If the cell is nil set it to 0
+ g.push_local 0
+ g.push_local 1
+ g.meta_push_0
+ g.send :[]=, 2, false
+
+ # Otherwise, do nothing
+ fin.set!
end
end
- class IncNode < Struct.new(:stack)
- def eval; stack.inc ; end
+ class IncNode
def bytecode(g)
- g.push 1
+ g.push_local 0
+ g.push_local 1
+
+ g.dup_many(2)
+ g.send :[], 1, false
+ g.meta_push_1
+ g.meta_send_op_plus 0
+
+ g.send :[]=, 2, false
+ g.pop
end
end
- class DecNode < Struct.new(:stack)
- def eval; stack.dec ; end
+ class DecNode
def bytecode(g)
- g.push 1
+ g.push_local 0
+ g.push_local 1
+
+ g.dup_many(2)
+ g.send :[], 1, false
+ g.meta_push_1
+ g.meta_send_op_minus 0
+
+ g.send :[]=, 2, false
+ g.pop
end
end
- class PutsNode < Struct.new(:stack)
- def eval; stack.puts ; end
+ class PutsNode
def bytecode(g)
- g.push 1
+ g.push_local 0
+ g.push_local 1
+ g.send :[], 1, false
+ g.send :chr, 0, true
+ g.send :puts, 1, true
end
end
- class GetsNode < Struct.new(:stack)
- def eval; stack.gets ; end
+ class GetsNode
def bytecode(g)
- g.push 1
+ g.push :self
+ g.push_literal "stty raw -echo"
+ g.send :system, 1, true
+ g.pop
+
+ g.push_local 0
+ g.push_local 1
+
+ g.push_const :STDIN
+ g.send :getc, 0, false
+
+ g.send :[]=, 2, false
+
+ g.push :self
+ g.push_literal "stty -raw echo"
+ g.send :system, 1, true
+ g.pop
end
end
- class IterationNode < Struct.new(:stack, :exp)
- def eval
- until stack.current == 0
- exp.each do |node|
- node.eval
- end
- end
+ class IterationNode < Struct.new(:exp)
+ def bytecode(g)
+ repeat = g.new_label
+ repeat.set!
+
+ exp.bytecode(g)
+
+ g.push_local 0
+ g.push_local 1
+ g.send :[], 1, true
+ g.meta_push_0
+ g.meta_send_op_equal 0
+
+ g.gif repeat
end
end
class Script < Struct.new(:exp)
-
def bytecode(g)
- g.push 0
- g.make_array 1
- g.set_literal g.state.scope.new_literal(:heap).reference.slot
- g.pop
-
- g.push 0
- g.set_literal g.state.scope.new_literal(:pointer).reference.slot
- g.pop
-
exp.each do |e|
e.bytecode(g)
end
@@ -1,5 +1,5 @@
module Brainfuck
- class CodeLoader
+ class CodeLoader < Rubinius::CodeLoader
def self.execute_code(code, binding, from_module, print = Compiler::Print.new)
cm = Compiler.compile_for_eval(code, binding.variables,
@@ -19,10 +19,7 @@ def self.execute_code(code, binding, from_module, print = Compiler::Print.new)
be.call
end
- # Takes a .py file name, compiles it if needed and executes it.
- # Sets the module name to be __main__, so this should be called
- # only on the main program. For loading other python modules from
- # it use the load_module method.
+ # Takes a .bf file name, compiles it if needed and executes it.
def self.execute_file(name, compile_to = nil, print = Compiler::Print.new)
cm = Compiler.compile_if_needed(name, compile_to, print)
ss = ::Rubinius::StaticScope.new Object
@@ -14,14 +14,13 @@ def self.always_recompile=(flag)
end
def self.compile_if_needed(file, output = nil, print = Print.new)
- puts file.inspect
compiled = output || compiled_filename(file)
needed = @always_recompile || !File.exists?(compiled) ||
File.stat(compiled).mtime < File.stat(file).mtime
if needed
compile_file(file, compiled, print)
else
- Rubinius::CodeLoader.new(compiled).load_compiled_file(compiled, 0)
+ Brainfuck::CodeLoader.new(compiled).load_compiled_file(compiled, 0)
end
end
@@ -32,7 +31,7 @@ def self.compile_file(file, output = nil, print = Print.new)
parser.input file
- compiler.generator.root = Rubinius::AST::Script
+ compiler.generator = Rubinius::Generator.new
compiler.writer.name = output || compiled_filename(file)
parser.print = print
@@ -64,7 +63,7 @@ def self.compile_for_eval(code, variable_scope, file = "(eval)", line = 0, print
end
end
- class Print < Struct.new(:sexp, :ast, :asm)
+ class Print < Struct.new(:sexp, :ast, :heap, :asm)
def sexp?
@sexp
end
@@ -73,6 +72,10 @@ def ast?
@ast
end
+ def heap?
+ @heap
+ end
+
def asm?
@asm
end
@@ -1,20 +0,0 @@
-module Brainfuck
- class Interpreter < Parslet::Transform
- def self.stack
- @@stack ||= Stack.new
- end
-
- rule(:fwd => simple(:fwd)) { AST::FwdNode.new }
- rule(:bwd => simple(:bwd)) { AST::BwdNode.new }
-
- rule(:inc => simple(:inc)) { AST::IncNode.new }
- rule(:dec => simple(:dec)) { AST::DecNode.new }
-
- rule(:puts => simple(:puts)) { AST::PutsNode.new }
- rule(:gets => simple(:gets)) { AST::GetsNode.new }
-
- rule(:iteration => subtree(:iteration)) { AST::IterationNode.new(iteration) }
-
- rule(:exp => subtree(:exp)) { AST::Script.new(exp) }
- end
-end
@@ -0,0 +1,32 @@
+module Brainfuck
+ class Lexer < Parslet::Parser
+ INSTRUCTIONS = %w{> < + - [ ] . ,}
+
+ alias_method :tokenize, :parse
+ class << self
+ def clean code
+ code.chars.select {|c| INSTRUCTIONS.include? c }.join
+ end
+ end
+
+ rule(:lparen) { str('[') >> space? }
+ rule(:rparen) { str(']') >> space? }
+
+ rule(:space) { match('\s').repeat(1) }
+ rule(:space?) { space.maybe }
+
+ rule(:fwd) { str('>') >> space? }
+ rule(:bwd) { str('<') >> space? }
+
+ rule(:inc) { str('+') >> space? }
+ rule(:dec) { str('-') >> space? }
+
+ rule(:puts) { str('.') >> space? }
+ rule(:gets) { str(',') >> space? }
+
+ rule(:iteration) { lparen >> expression >> rparen }
+
+ rule(:expression) { (iteration.as(:iteration) | fwd.as(:fwd) | bwd.as(:bwd) | inc.as(:inc) | dec.as(:dec) | puts.as(:puts) | gets.as(:gets)).repeat.as(:exp) }
+ root :expression
+ end
+end
Oops, something went wrong.

0 comments on commit 3d3bb6e

Please sign in to comment.