Permalink
Browse files

SketchCompiler does pre-processing for constants and creates the list…

… of methods
  • Loading branch information...
1 parent b0603cd commit b63bccb7cdef9670eb9361f967543891677ea481 Greg Borenstein committed Aug 4, 2008
@@ -1,13 +1,10 @@
class BasicBlink < ArduinoSketch
-
-
# hello world (uncomment to run)
output_pin 13, :as => :led
- def loop
- blink led, 100
- x = 4
- end
-
+ def loop
+ blink led, 100
+ x = 4
+ end
end
@@ -1,24 +1,26 @@
class ExternalVariableFu < ArduinoSketch
-@one = int
-@two = long
-@three = unsigned
-@four = short
-@five = byte
-@six = 1
-@seven = 1.2
-@eight = "0x00"
-@nine = "arduino"
-@ten = true
-@eleven = false
-@twelve = "1, long"
-@thirteen = "1, unsigned"
-@fourteen = "1, byte"
+ @one = int
+ @two = long
+ @three = unsigned
+ @four = short
+ @five = byte
+ @six = 1
+ @seven = 1.2
+ @eight = "0x00"
+ @nine = "arduino"
+ @ten = true
+ @eleven = false
+ @twelve = "1, long"
+ @thirteen = "1, unsigned"
+ @fourteen = "1, byte"
+ @fifteen = HIGH
+ @sixteen = LOW
+ @seventeen = ON
+ @eighteen = OFF
-
-
- def loop
- delay @six
- end
+ def loop
+ delay @six
+ end
end
@@ -14,10 +14,7 @@ class ExternalVariables < ArduinoSketch
@boom = "1, int"
@rad = "1.00"
-
-
def loop
-
delay 1
@foo = 2
@foo = KOOL
@@ -2,9 +2,9 @@ class HelloWorld < ArduinoSketch
output_pin 13, :as => :led
- def loop
- blink led, 100
- end
+ def loop
+ blink led, 100
+ end
end
View
@@ -186,11 +186,30 @@ def initialize #:nodoc:
@other_setup = [] # specifically, Serial.begin
@assembler_declarations = []
@accessors = []
+# @signatures = ["void blink();", "int main();", "void track_total_loop_time(void);", "unsigned long find_total_loop_time(void);"]
+# @signatures = ["int main();", "void track_total_loop_time(void);", "unsigned long find_total_loop_time(void);"]
@signatures = ["int main();"]
helper_methods = []
+# helper_methods << "void blink(int pin, int ms) {"
+# helper_methods << "\tdigitalWrite( pin, HIGH );"
+# helper_methods << "\tdelay( ms );"
+# helper_methods << "\tdigitalWrite( pin, LOW );"
+# helper_methods << "\tdelay( ms );"
+# helper_methods << "}"
+# helper_methods << "void track_total_loop_time(void)"
+# helper_methods << "{"
+# helper_methods << "\ttotal_loop_time = millis() - start_loop_time;"
+# helper_methods << "\tstart_loop_time = millis();"
+# helper_methods << "}"
+# helper_methods << "unsigned long find_total_loop_time(void)"
+# helper_methods << "{"
+# helper_methods << "\nreturn total_loop_time;"
+# helper_methods << "}"
@helper_methods = helper_methods.join( "\n" )
+# @declarations << "unsigned long start_loop_time = 0;"
+# @declarations << "unsigned long total_loop_time = 0;"
end
# Setup variables outside of the loop. Does some magic based on type of arguments. Subject to renaming. Use with caution.
@@ -548,23 +567,6 @@ def serial_begin(opts={})
end
- def formatted_print(opts={})
-
- buffer_size = opts[:buffer_size] ? opts[:buffer_size] : 64
-
- if opts[:as]
- @@sprintf_inc ||= FALSE
- if @@sprintf_inc == FALSE
- @@sprintf_inc = TRUE
- accessor = []
- accessor << "\n#undef int\n#include <stdio.h>"
- accessor << "#define write_line(...) sprintf(#{opts[:as]},__VA_ARGS__);"
- @accessors << accessor.join( "\n" )
- array("char #{opts[:as]}[#{buffer_size}]")
- end
- end
- end
-
# Treat a pair of digital I/O pins as a serial line. See: http://www.arduino.cc/en/Tutorial/SoftwareSerial
def software_serial(rx, tx, opts={})
raise ArgumentError, "can only define rx from Fixnum, got #{rx.class}" unless rx.is_a?(Fixnum)
@@ -650,6 +652,34 @@ def swser_LCDpa(tx, opts={})
accessor << "void print( SWSerLCDpa& s, long i, int b ) {"
accessor << "\treturn s.print( i, b );"
accessor << "}"
+ # ------------------- print line generics -------------------------------
+ accessor << "void println(SWSerLCDpa& s) {"
+ accessor << "\treturn s.println();"
+ accessor << "}"
+ accessor << "void println( SWSerLCDpa& s, uint8_t b ) {"
+ accessor << "\treturn s.println( b );"
+ accessor << "}"
+ accessor << "void println( SWSerLCDpa& s, char* str ) {"
+ accessor << "\treturn s.println( str );"
+ accessor << "}"
+ accessor << "void println( SWSerLCDpa& s, char c ) {"
+ accessor << "\treturn s.println( c );"
+ accessor << "}"
+ accessor << "void println( SWSerLCDpa& s, const char c[] ) {"
+ accessor << "\treturn s.println( c );"
+ accessor << "}"
+ accessor << "void println( SWSerLCDpa& s, int i ) {"
+ accessor << "\treturn s.println( i );"
+ accessor << "}"
+ accessor << "void println( SWSerLCDpa& s, long i ) {"
+ accessor << "\treturn s.println( i );"
+ accessor << "}"
+ accessor << "void println( SWSerLCDpa& s, unsigned long i ) {"
+ accessor << "\treturn s.println( i );"
+ accessor << "}"
+ accessor << "void println( SWSerLCDpa& s, long i, int b ) {"
+ accessor << "\treturn s.println( i, b );"
+ accessor << "}"
# ------------------ PA-LCD specific functions ---------------------------------
accessor << "void clearscr(SWSerLCDpa& s) {"
accessor << "\treturn s.clearscr();"
@@ -660,9 +690,6 @@ def swser_LCDpa(tx, opts={})
accessor << "void clearscr(SWSerLCDpa& s, int n) {"
accessor << "\treturn s.clearscr(n);"
accessor << "}"
- accessor << "void clearscr(SWSerLCDpa& s, long n, int b) {"
- accessor << "\treturn s.clearscr(n, b);"
- accessor << "}"
accessor << "void clearline(SWSerLCDpa& s, int line) {"
accessor << "\treturn s.clearline( line );"
accessor << "}"
@@ -672,9 +699,6 @@ def swser_LCDpa(tx, opts={})
accessor << "void clearline(SWSerLCDpa& s, int line, int n) {"
accessor << "\treturn s.clearline( line, n );"
accessor << "}"
- accessor << "void clearline(SWSerLCDpa& s, int line, long n, int b) {"
- accessor << "\treturn s.clearline( line, n, b );"
- accessor << "}"
accessor << "void home( SWSerLCDpa& s) {"
accessor << "\treturn s.home();"
accessor << "}"
@@ -683,18 +707,12 @@ def swser_LCDpa(tx, opts={})
accessor << "}"
accessor << "void home( SWSerLCDpa& s, int n) {"
accessor << "\treturn s.home( n );"
- accessor << "}"
- accessor << "void home( SWSerLCDpa& s, long n, int b) {"
- accessor << "\treturn s.home( n, b );"
accessor << "}"
accessor << "void setxy( SWSerLCDpa& s, int x, int y) {"
accessor << "\treturn s.setxy( x, y );"
accessor << "}"
accessor << "void setxy( SWSerLCDpa& s, int x, int y, const char *str) {"
accessor << "\treturn s.setxy( x, y, str );"
- accessor << "}"
- accessor << "void setxy( SWSerLCDpa& s, int x, int y, long n, int b) {"
- accessor << "\treturn s.setxy( x, y, n, b );"
accessor << "}"
accessor << "void setxy( SWSerLCDpa& s, int x, int y, int n) {"
accessor << "\treturn s.setxy( x, y, n );"
@@ -1359,18 +1377,9 @@ def assembler(name, signature, code)
end
def self.pre_process(sketch_string) #:nodoc:
- result = sketch_string
# add external vars to each method (needed for better translation, will be removed in make:upload)
- result.gsub!(/(^\s*def\s.\w*(\(.*\))?)/, '\1' + " \n #{$external_vars.join(" \n ")}" )
- # gather method names
- sketch_methods = result.scan(/^\s*def\s.\w*/)
- sketch_methods.each {|m| $sketch_methods << m.gsub(/\s*def\s*/, "") }
-
- result.gsub!("HIGH", "1")
- result.gsub!("LOW", "0")
- result.gsub!("ON", "1")
- result.gsub!("OFF", "0")
- result
+ sketch_string.gsub!(/(^\s*def\s.\w*(\(.*\))?)/, '\1' + " \n #{$external_vars.join(" \n ")}" )
+ sketch_string
end
def self.add_to_setup(meth)
View
@@ -21,17 +21,27 @@ def initialize path_to_sketch
end
def parent_dir
- @path.split("/")[0..@path.split("/").length-2].join("/")
+ self.path.split("/")[0..@path.split("/").length-2].join("/")
end
def build_dir
- "#{@target_dir}/#{@name}"
+ "#{self.target_dir}/#{self.name}"
end
def create_build_dir! optional_path_prefix=nil
- @target_dir = optional_path_prefix if optional_path_prefix
+ self.target_dir = optional_path_prefix if optional_path_prefix
mkdir_p build_dir
end
+ def process_constants
+ self.body.gsub!("HIGH", "1")
+ self.body.gsub!("LOW", "0")
+ self.body.gsub!("ON", "1")
+ self.body.gsub!("OFF", "0")
+ end
+
+ def sketch_methods
+ self.body.scan(/^\s*def\s.\w*/).collect{ |m| m.gsub(/\s*def\s*/, "") }
+ end
end
@@ -19,18 +19,20 @@ namespace :test do
end
task :compile => :gather do
+
@examples.each {|e| run_tests(e, "compile")}
- end
end
desc "gather all tests"
task :gather do # => "make:upload" do
@examples = []
- @test_results = []
- Dir.entries( File.expand_path("#{RAD_ROOT}/examples/") ).each do |f|
- if (f =~ /\.rb$/)
- @examples << f.split('.').first
+ if ENV['sketch']
+ @examples << ENV['sketch']
+ else
+ Dir.entries( File.expand_path("#{RAD_ROOT}/examples/") ).each do |f|
+ @examples << f.split('.').first if (f =~ /\.rb$/)
end
+ end
end
end
@@ -49,10 +51,8 @@ namespace :make do
desc "generate a makefile and use it to compile the .cpp"
task :compile => [:clean_sketch_dir, "build:sketch"] do # should also depend on "build:sketch"
- puts; puts
- puts @compiler.name
- puts
Makefile.compose_for_sketch( @compiler.build_dir )
+
# not allowed? sh %{export PATH=#{Makefile.software_params[:arduino_root]}/tools/avr/bin:$PATH}
sh %{cd #{@compiler.build_dir}; make depend; make}
end
@@ -86,7 +86,7 @@ namespace :build do
c_methods = []
sketch_signatures = []
# until we better understand RubyToC let's see what's happening on errors
- $sketch_methods.each do |meth|
+ @compiler.sketch_methods.each do |meth|
raw_rtc_meth = RADProcessor.translate(constantize(@compiler.klass), meth)
puts "Translator Error: #{raw_rtc_meth.inspect}" if raw_rtc_meth[0..8] == "// ERROR:"
c_methods << raw_rtc_meth unless meth == "setup"
@@ -137,6 +137,9 @@ namespace :build do
end
CODE
end
+
+ @compiler.process_constants
+
eval ArduinoSketch.pre_process(@compiler.body)
@@as.process_external_vars(constantize(@compiler.klass))
@setup = @@as.compose_setup
@@ -177,18 +180,15 @@ namespace :build do
desc "setup target directory named after your sketch class"
task :sketch_dir => [:file_list] do
@compiler.create_build_dir!
- # mkdir_p "#{@test_dir + @sketch_class.split(".").first}"
end
task :file_list do
# take another look at this, since if the root directory name is changed, everything breaks
# perhaps we generate a constant when the project is generated an pop it here or in the init file
- # assume the only .rb file in the sketch dir is the sketch:
if ENV['sketch']
-
@compiler = SketchCompiler.new File.expand_path("#{ENV['sketch']}.rb")
-
else
+ # assume the only .rb file in the sketch dir is the sketch:
@compiler = SketchCompiler.new Dir.glob("#{File.expand_path(File.dirname(__FILE__))}/../../../*.rb").first
end
@@ -1,6 +1,35 @@
require File.dirname(__FILE__) + '/spec_helper.rb'
require File.expand_path(File.dirname(__FILE__) + "/../../lib/rad/sketch_compiler.rb")
+context "SketchCompiler#sketch_methods" do
+ before do
+ @as = File.expand_path(File.dirname(__FILE__)) + "/../../lib/examples/i2c_with_clock_chip.rb"
+ @sc = SketchCompiler.new @as
+ end
+
+ it "should locate all the methods defined in the sketch" do
+ @sc.sketch_methods.should include( "loop")
+ @sc.sketch_methods.should include( "printlz")
+ @sc.sketch_methods.should include( "print_hexbyte")
+ @sc.sketch_methods.should include( "clear_bottom_line")
+ end
+end
+
+context "SketchCompiler#process_constants" do
+ before do
+ @as = File.expand_path(File.dirname(__FILE__)) + "/../../lib/examples/external_variable_fu.rb"
+ @sc = SketchCompiler.new @as
+ end
+
+ it "should correctly process constants" do
+ @sc.process_constants
+ @sc.body.should_not match(/HIGH/)
+ @sc.body.should_not match(/LOW/)
+ @sc.body.should_not match(/ON/)
+ @sc.body.should_not match(/OFF/)
+ end
+end
+
context "SketchCompiler.new" do
before do
@as = File.expand_path(File.dirname(__FILE__)) + "/../../lib/examples/add_hysteresis.rb"

0 comments on commit b63bccb

Please sign in to comment.