Permalink
Browse files

Whitespace cleanup

  • Loading branch information...
1 parent 79752e4 commit 3b9d818faf14d80eced305a009ddeb67e88c65f3 @matthewd committed Oct 24, 2010
Showing with 3,044 additions and 3,044 deletions.
  1. +75 −75 convertor.rb
  2. +15 −15 foo.asp
  3. +374 −374 parser.rb
  4. +1,258 −1,258 rasp.rb
  5. +1 −1 reformat.rb
  6. +391 −391 reformat.y
  7. +168 −168 run.rb
  8. +20 −20 t/class.vbs
  9. +18 −18 t/math.vbs
  10. +20 −20 t/math2.vbs
  11. +4 −4 t/meta/error.vbs
  12. +1 −1 t/meta/happy.vbs
  13. +1 −1 t/meta/loop.vbs
  14. +4 −4 t/meta/zero.vbs
  15. +5 −5 t/perf/rand1.vbs
  16. +8 −8 t/perf/str.vbs
  17. +32 −32 t/samples/style.css
  18. +58 −58 t/samples/test.vbs
  19. +32 −32 t/samples/test2.vbs
  20. +37 −37 t/samples/test3.asp
  21. +6 −6 t/samples/test3.vbs
  22. +8 −8 t/samples/test4.asp
  23. +9 −9 t/samples/test4.vbs
  24. +20 −20 t/samples/test5.vbs
  25. +7 −7 t/samples/test6.vbs
  26. +58 −58 test.sh
  27. +414 −414 vbscript.y
View
150 convertor.rb
@@ -1,75 +1,75 @@
-require 'syntax/convertors/abstract'
-
-module Syntax
- module Convertors
- class Meta < Abstract
- def type= new_type
- @tokenizer.type = new_type
- end
- def type
- @tokenizer.type
- end
- def virtual_root= new_value
- @tokenizer.virtual_root = new_value
- end
- def virtual_root; @tokenizer.virtual_root; end
- def follow_includes= new_value
- @tokenizer.follow_includes = new_value
- end
- def swallow= new_value
- @tokenizer.swallow = new_value
- end
- attr_accessor :start_group
- def convert text, filename
- @tokenizer.filename = filename
- @tokenizer.start( text ) do |token|
- start_group.call token.group, token
- end
- @tokenizer.step until @tokenizer.eos?
- @tokenizer.finish
- end
- end
- class CodeTree < Abstract
- def type= new_type
- @tokenizer.type = new_type
- end
- def type
- @tokenizer.type
- end
- def virtual_root; @tokenizer.virtual_root; end
- def virtual_root= new_value
- @tokenizer.virtual_root = new_value
- end
- def follow_includes= new_value
- @tokenizer.follow_includes = new_value
- end
- def swallow= new_value
- @tokenizer.swallow = new_value
- end
- def convert text, filename
- @text = text
- @filename = filename
- VbScriptRaccParser.new.run_parse self, :go
- end
- def go
- @tokenizer.filename = @filename
- @tokenizer.start( @text ) do |token|
- if $DEBUG
- if token.group.is_a? Symbol then
- puts "Yielding :#{token.group} for '#{token}'"
- else
- puts "Yielding characters for '#{token}'"
- end
- end
- yield [token.group, token] unless token.group == :token_sep
- end
- @tokenizer.step until @tokenizer.eos?
- @tokenizer.finish
- puts "Yielding final :fake_newline" if $DEBUG
- yield [:fake_newline, nil]
- puts "Yielding EOF" if $DEBUG
- yield [false, false]
- end
- end
- end
-end
+require 'syntax/convertors/abstract'
+
+module Syntax
+ module Convertors
+ class Meta < Abstract
+ def type= new_type
+ @tokenizer.type = new_type
+ end
+ def type
+ @tokenizer.type
+ end
+ def virtual_root= new_value
+ @tokenizer.virtual_root = new_value
+ end
+ def virtual_root; @tokenizer.virtual_root; end
+ def follow_includes= new_value
+ @tokenizer.follow_includes = new_value
+ end
+ def swallow= new_value
+ @tokenizer.swallow = new_value
+ end
+ attr_accessor :start_group
+ def convert text, filename
+ @tokenizer.filename = filename
+ @tokenizer.start( text ) do |token|
+ start_group.call token.group, token
+ end
+ @tokenizer.step until @tokenizer.eos?
+ @tokenizer.finish
+ end
+ end
+ class CodeTree < Abstract
+ def type= new_type
+ @tokenizer.type = new_type
+ end
+ def type
+ @tokenizer.type
+ end
+ def virtual_root; @tokenizer.virtual_root; end
+ def virtual_root= new_value
+ @tokenizer.virtual_root = new_value
+ end
+ def follow_includes= new_value
+ @tokenizer.follow_includes = new_value
+ end
+ def swallow= new_value
+ @tokenizer.swallow = new_value
+ end
+ def convert text, filename
+ @text = text
+ @filename = filename
+ VbScriptRaccParser.new.run_parse self, :go
+ end
+ def go
+ @tokenizer.filename = @filename
+ @tokenizer.start( @text ) do |token|
+ if $DEBUG
+ if token.group.is_a? Symbol then
+ puts "Yielding :#{token.group} for '#{token}'"
+ else
+ puts "Yielding characters for '#{token}'"
+ end
+ end
+ yield [token.group, token] unless token.group == :token_sep
+ end
+ @tokenizer.step until @tokenizer.eos?
+ @tokenizer.finish
+ puts "Yielding final :fake_newline" if $DEBUG
+ yield [:fake_newline, nil]
+ puts "Yielding EOF" if $DEBUG
+ yield [false, false]
+ end
+ end
+ end
+end
View
30 foo.asp
@@ -1,15 +1,15 @@
-<%
-
-Dim o
-Set o = Server.CreateObject("Scripting.Dictionary")
-
-o.Add "foo", "bar"
-o.Add "baz", "quux"
-
-Response.Write o("foo") & vbCrLf & vbCrLf
-
-o("foo") = o("baz")
-
-Response.Write o("foo")
-
-%>
+<%
+
+Dim o
+Set o = Server.CreateObject("Scripting.Dictionary")
+
+o.Add "foo", "bar"
+o.Add "baz", "quux"
+
+Response.Write o("foo") & vbCrLf & vbCrLf
+
+o("foo") = o("baz")
+
+Response.Write o("foo")
+
+%>
View
748 parser.rb
@@ -1,374 +1,374 @@
-
-require 'syntax'
-
-class Syntax::Tokenizer
- def token tok
- @callback.call( tok )
- end
-end
-
-class Syntax::Token
- def downcase; to_s.downcase; end
-end
-class PositionedToken < Syntax::Token
- attr_accessor :position
- def initialize data, group, position
- super data, group
- self.position = position
- end
-end
-class VbScriptTokenizer < Syntax::Tokenizer
- def initialize
- @type = nil
- @filename = ""
- @follow_includes = false
- @virtual_root = nil
- @swallow = true
- end
- attr_accessor :type
-
- attr_accessor :filename
- def setup
- @mode = nil
- @file_type = @type
- @allow_keyword = true
- @last_space = true
- @asp_expr = false
- self.last_pos = 0
- end
-
- def start_group(a, b=nil)
- a, b = map_group(a, b)
- if a
- flush_chunk
- @group = a
- append b
- flush_chunk
- #super :token_sep
- end
- end
-
- attr_accessor :follow_includes
- attr_accessor :virtual_root
- attr_accessor :swallow
-
- attr_accessor :last_pos
- alias :scan_without_storing_position :scan
- def scan_after_storing_position pattern
- self.last_pos = pos
- scan_without_storing_position pattern
- end
- alias :scan :scan_after_storing_position
-
- def position
- pre = @text.string.slice( 0, last_pos + 1 )
- line = pre.count( "\n" ) + 1
- char = pre.reverse.index( "\n" )
- char = pre.length if line == 1
- "#{filename}(#{line}, #{char})"
- end
- def append data
- if @chunk.empty?
- @chunk = data
- else
- @chunk << data
- end
- end
- def flush_chunk
- tok = @chunk || ""
- @chunk = ""
-
- unless tok.empty?
- tok = PositionedToken.new( tok, @group, position ) unless tok.is_a? Syntax::Token
- token( tok )
- end
- end
- def start_region(a, b=nil)
- start_group a, b
- end
- def end_region(a, b=nil)
- start_group(a, b) if b
- end
-
- def map_group(group, value)
- group = :ident if group == :'asp constant'
- return nil, nil if group == :space || group == :line_continuation || ((group == :comment) && @swallow)
- return value, value if group == :operator || group == :asp_marker
- #return :keyword, value if group.to_s.upcase == group.to_s
- return :ident, value if group.to_s.upcase == group.to_s and @allow_keyword == false
- return group, value
- end
-
- def step
- allow_next_keyword = true
- is_space = false
-
- unless @mode
- @file_type = check( /\s*</ ) ? :asp : :vbs unless @file_type
- case @file_type
- when :asp
- @mode = :html
- when :vbs
- @mode = :normal
- else
- @mode = check( /\s*</ ) ? :html : :normal
- end
- end
-
- case @mode
- when :html
- @mode = :normal
- start_group :html, scan_until( /(?=<!-- *#include)|(?=<%)|(?![^X]|X)/i )
- if scan(/<% *=/)
- start_group :asp_marker, '<%='
- @asp_expr = true
- elsif directive = scan( /<!-- *#include +(virtual|file)="([^"]*)" *-->/i )
- if follow_includes
- path = subgroup(2)
- if subgroup(1).downcase == 'virtual' && subgroup(2)[0] == ?/
- path = Pathname.new( virtual_root + path.sub( /./, '' ) )
- else
- path = Pathname.new( path )
- current_dir = Pathname.new( filename ).parent
- path = current_dir + path
- end
-
- c = Syntax::Convertors::Meta.for_syntax 'vbscript'
- c.start_group = lambda {|group, content| start_group group, content }
- c.type = :asp
- c.follow_includes = true
- c.virtual_root = virtual_root
- puts "Entering #{path}"
- c.convert File.read( path ), path
- puts "Leaving #{path}"
- @mode = :html
- else
- start_group :directive, directive
- @mode = :html
- end
- else
- start_group :asp_marker, scan( /<%/ )
- @asp_expr = false
- end
- is_space = true
- when :normal
- if nl = scan(/\r\n?|\n/)
- start_group :newline, nl
- is_space = true
- elsif nl = scan(/:/)
- start_group :operator, nl
- is_space = true
- elsif continue = scan(/_ *(\r\n?|\n)/)
- start_group :line_continuation, continue
- is_space = true
- elsif @file_type == :asp and marker = scan( /%>/ )
- unless @asp_expr
- start_group :fake_newline, ' '
- end
- @mode = :html
- start_group :asp_marker, marker
- elsif comment = scan(/(Rem +|').*/i)
- start_group :comment, comment
-
- # FIXME: This is just for testing convenience
- if comment == "'__END__"
- # Swallow the whole file
- scan( /(X|[^X])*/ )
- end
- elsif quote = scan(/"/)
- start_group :operator, quote
- start_region :string_text, scan(/([^"%]|%[^>])+%?/)
- @mode = :string
-
- elsif reserved = scan( /(TypeOf)\b/i )
- start_group :reserved, reserved
-
- elsif constant = scan( /True\b/i )
- start_group :TRUE, constant
- elsif constant = scan( /False\b/i )
- start_group :FALSE, constant
-
- # FIXME
- elsif constant = scan( /(Empty|Nothing|Null|Err)\b/i )
- start_group :ident, constant
-
- # FIXME
- elsif constant = scan( /(Response|Request|Server)\b/i )
- start_group :ident, constant
-
- elsif operator = scan( /With\b/i )
- start_group :WITH, operator
- elsif operator = scan( /Class\b/i )
- start_group :CLASS, operator
- elsif operator = scan( /Sub\b/i )
- start_group :SUB, operator
- elsif operator = scan( /Function\b/i )
- start_group :FUNCTION, operator
- elsif operator = scan( /Property\b/i )
- start_group :PROPERTY, operator
- elsif operator = scan( /End\b/i )
- start_group :END, operator
- elsif operator = scan( /Exit\b/i )
- start_group :EXIT, operator
- elsif operator = scan( /Get\b/i )
- start_group :GET, operator
-
- elsif keyword = scan( /New\b/i )
- start_group :NEW, keyword
-
- elsif operator = scan( /On +Error +Resume +Next\b/i )
- start_group :IGNORE_ERRORS, operator
- elsif operator = scan( /On +Error +Goto +0\b/i )
- start_group :THROW_ERRORS, operator
- elsif operator = scan( /Option +Explicit\b/i )
- start_group :EXPLICIT, operator
- elsif operator = scan( /Call\b/i )
- start_group :CALL, operator
- elsif operator = scan( /Randomize\b/i )
- start_group :RANDOMIZE, operator
- elsif operator = scan( /Private\b/i )
- start_group :PRIVATE, operator
- elsif operator = scan( /Public\b/i )
- start_group :PUBLIC, operator
- elsif operator = scan( /Erase\b/i )
- start_group :ERASE, operator
- elsif operator = scan( /Const\b/i )
- start_group :CONST, operator
- elsif operator = scan( /Dim\b/i )
- start_group :DIM, operator
- elsif operator = scan( /ReDim\b/i )
- start_group :REDIM, operator
- elsif operator = scan( /Preserve\b/i )
- start_group :PRESERVE, operator
- elsif operator = scan( /Let\b/i )
- start_group :LET, operator
- elsif operator = scan( /Set\b/i )
- start_group :SET, operator
- elsif operator = scan( /Do\b/i )
- start_group :DO, operator
- elsif operator = scan( /Loop\b/i )
- start_group :LOOP, operator
- elsif operator = scan( /For\b/i )
- start_group :FOR, operator
- elsif operator = scan( /In\b/i ) # FIXME: Not actually a reserved word! :(
- start_group :IN, operator
- elsif operator = scan( /To\b/i ) # FIXME: Not actually a reserved word! :(
- start_group :TO, operator
- elsif operator = scan( /Step\b/i ) # FIXME: Not actually a reserved word! :(
- start_group :STEP, operator
- elsif operator = scan( /Next\b/i )
- start_group :NEXT, operator
- elsif operator = scan( /Each\b/i )
- start_group :EACH, operator
- elsif operator = scan( /If\b/i )
- start_group :IF, operator
- elsif operator = scan( /With\b/i )
- start_group :WITH, operator
- elsif operator = scan( /Then\b/i )
- start_group :THEN, operator
- elsif operator = scan( /Else\b/i )
- start_group :ELSE, operator
- elsif operator = scan( /ElseIf\b/i )
- start_group :ELSEIF, operator
- elsif operator = scan( /Select\b/i )
- start_group :SELECT, operator
- elsif operator = scan( /Case\b/i )
- start_group :CASE, operator
- elsif operator = scan( /While\b/i )
- start_group :WHILE, operator
- elsif operator = scan( /Until\b/i )
- start_group :UNTIL, operator
- elsif operator = scan( /Wend\b/i )
- start_group :WEND, operator
-
- # FIXME
- elsif builtin = scan( /(IsArray|LBound|UBound|Abs|Asc|AscB|AscW|Chr|ChrB|ChrW|CBool|CByte|CDate|CDbl|CInt|CLng|CSng|CStr|DateSerial|DateValue|Hex|Oct|Fix|Int|Sgn|TimeSerial|TimeValue|Date|Time|Day|Month|Weekday|Year|Hour|Minute|Second|Now|Atn|Cos|Sin|Tan|Exp|Log|Sqr|Rnd|CreateObject|IsObject|InStr|InStrB|Len|LenB|LCase|UCase|Left|LeftB|Mid|MidB|Right|RightB|Space|StrComp|String|LTrim|RTrim|Trim|IsDate|IsEmpty|IsNull|IsNumeric|VarType)(?= *\()/i )
- start_group :ident, builtin
-
- elsif operator = scan( /ByVal\b/i )
- start_group :BYVAL, operator
- elsif operator = scan( /ByRef\b/i )
- start_group :BYREF, operator
-
- elsif operator = scan( /Mod\b/i )
- start_group :MOD, operator
- elsif operator = scan( /Is\b/i )
- start_group :IS, operator
- elsif operator = scan( /Not\b/i )
- start_group :NOT, operator
- elsif operator = scan( /And\b/i )
- start_group :AND, operator
- elsif operator = scan( /Or\b/i )
- start_group :OR, operator
- elsif operator = scan( /Xor\b/i )
- start_group :XOR, operator
- elsif operator = scan( /Eqv\b/i )
- start_group :EQV, operator
- elsif operator = scan( /Imp\b/i )
- start_group :IMP, operator
-
- elsif digits = scan(/\d*\.\d+/)
- start_group :float, digits
-
- elsif digits = scan(/\d+/)
- start_group :integer, digits
-
- elsif words = scan(/\w+/)
- start_group :ident, words
-
- elsif punct = scan(/[,]/)
- start_group :operator, punct
- is_space = true
-
- elsif punct = scan(/[(]/)
- start_group @last_space ? :operator : :arg_paren, punct
- is_space = true
-
- elsif punct = scan(/[.]/)
- start_group @last_space ? :with_dot : :operator, punct
- allow_next_keyword = false
-
- elsif punct = scan(/[)]/)
- start_group :operator, punct
- allow_next_keyword = false
- is_space = false
-
- elsif punct = scan(/[-+*\\\/^&=]|[<>]=|<>|[<>]/)
- start_group :operator, punct
- allow_next_keyword = false
- is_space = true
-
- elsif space = scan(/\s/)
- start_group :space, space
- is_space = true
-
- elsif ext_ident = scan(/\[([^\]]*)\]/)
- start_group :operator, '['
- start_group :ident, subgroup( 1 )
- start_group :operator, ']'
-
- else
- start_group :unknown, scan(/./)
- end
- when :string
- if @file_type == :asp and marker = scan( /%>/ )
- raise "Syntax error: Can't have %> in a string!"
- elsif escaped = scan(/""/)
- start_group :escaped_atom, escaped
- start_group :string_text, scan(/([^"%]|%[^>])+%?/)
- elsif quote = scan(/"/)
- end_region :string_text
- start_group :operator, quote
- @mode = :normal
- else
- start_group :string_text, scan(/./)
- end
- end
-
- @allow_keyword = allow_next_keyword
- @last_space = is_space
- end
-end
-
-Syntax::SYNTAX['vbscript'] = VbScriptTokenizer
-
+
+require 'syntax'
+
+class Syntax::Tokenizer
+ def token tok
+ @callback.call( tok )
+ end
+end
+
+class Syntax::Token
+ def downcase; to_s.downcase; end
+end
+class PositionedToken < Syntax::Token
+ attr_accessor :position
+ def initialize data, group, position
+ super data, group
+ self.position = position
+ end
+end
+class VbScriptTokenizer < Syntax::Tokenizer
+ def initialize
+ @type = nil
+ @filename = ""
+ @follow_includes = false
+ @virtual_root = nil
+ @swallow = true
+ end
+ attr_accessor :type
+
+ attr_accessor :filename
+ def setup
+ @mode = nil
+ @file_type = @type
+ @allow_keyword = true
+ @last_space = true
+ @asp_expr = false
+ self.last_pos = 0
+ end
+
+ def start_group(a, b=nil)
+ a, b = map_group(a, b)
+ if a
+ flush_chunk
+ @group = a
+ append b
+ flush_chunk
+ #super :token_sep
+ end
+ end
+
+ attr_accessor :follow_includes
+ attr_accessor :virtual_root
+ attr_accessor :swallow
+
+ attr_accessor :last_pos
+ alias :scan_without_storing_position :scan
+ def scan_after_storing_position pattern
+ self.last_pos = pos
+ scan_without_storing_position pattern
+ end
+ alias :scan :scan_after_storing_position
+
+ def position
+ pre = @text.string.slice( 0, last_pos + 1 )
+ line = pre.count( "\n" ) + 1
+ char = pre.reverse.index( "\n" )
+ char = pre.length if line == 1
+ "#{filename}(#{line}, #{char})"
+ end
+ def append data
+ if @chunk.empty?
+ @chunk = data
+ else
+ @chunk << data
+ end
+ end
+ def flush_chunk
+ tok = @chunk || ""
+ @chunk = ""
+
+ unless tok.empty?
+ tok = PositionedToken.new( tok, @group, position ) unless tok.is_a? Syntax::Token
+ token( tok )
+ end
+ end
+ def start_region(a, b=nil)
+ start_group a, b
+ end
+ def end_region(a, b=nil)
+ start_group(a, b) if b
+ end
+
+ def map_group(group, value)
+ group = :ident if group == :'asp constant'
+ return nil, nil if group == :space || group == :line_continuation || ((group == :comment) && @swallow)
+ return value, value if group == :operator || group == :asp_marker
+ #return :keyword, value if group.to_s.upcase == group.to_s
+ return :ident, value if group.to_s.upcase == group.to_s and @allow_keyword == false
+ return group, value
+ end
+
+ def step
+ allow_next_keyword = true
+ is_space = false
+
+ unless @mode
+ @file_type = check( /\s*</ ) ? :asp : :vbs unless @file_type
+ case @file_type
+ when :asp
+ @mode = :html
+ when :vbs
+ @mode = :normal
+ else
+ @mode = check( /\s*</ ) ? :html : :normal
+ end
+ end
+
+ case @mode
+ when :html
+ @mode = :normal
+ start_group :html, scan_until( /(?=<!-- *#include)|(?=<%)|(?![^X]|X)/i )
+ if scan(/<% *=/)
+ start_group :asp_marker, '<%='
+ @asp_expr = true
+ elsif directive = scan( /<!-- *#include +(virtual|file)="([^"]*)" *-->/i )
+ if follow_includes
+ path = subgroup(2)
+ if subgroup(1).downcase == 'virtual' && subgroup(2)[0] == ?/
+ path = Pathname.new( virtual_root + path.sub( /./, '' ) )
+ else
+ path = Pathname.new( path )
+ current_dir = Pathname.new( filename ).parent
+ path = current_dir + path
+ end
+
+ c = Syntax::Convertors::Meta.for_syntax 'vbscript'
+ c.start_group = lambda {|group, content| start_group group, content }
+ c.type = :asp
+ c.follow_includes = true
+ c.virtual_root = virtual_root
+ puts "Entering #{path}"
+ c.convert File.read( path ), path
+ puts "Leaving #{path}"
+ @mode = :html
+ else
+ start_group :directive, directive
+ @mode = :html
+ end
+ else
+ start_group :asp_marker, scan( /<%/ )
+ @asp_expr = false
+ end
+ is_space = true
+ when :normal
+ if nl = scan(/\r\n?|\n/)
+ start_group :newline, nl
+ is_space = true
+ elsif nl = scan(/:/)
+ start_group :operator, nl
+ is_space = true
+ elsif continue = scan(/_ *(\r\n?|\n)/)
+ start_group :line_continuation, continue
+ is_space = true
+ elsif @file_type == :asp and marker = scan( /%>/ )
+ unless @asp_expr
+ start_group :fake_newline, ' '
+ end
+ @mode = :html
+ start_group :asp_marker, marker
+ elsif comment = scan(/(Rem +|').*/i)
+ start_group :comment, comment
+
+ # FIXME: This is just for testing convenience
+ if comment == "'__END__"
+ # Swallow the whole file
+ scan( /(X|[^X])*/ )
+ end
+ elsif quote = scan(/"/)
+ start_group :operator, quote
+ start_region :string_text, scan(/([^"%]|%[^>])+%?/)
+ @mode = :string
+
+ elsif reserved = scan( /(TypeOf)\b/i )
+ start_group :reserved, reserved
+
+ elsif constant = scan( /True\b/i )
+ start_group :TRUE, constant
+ elsif constant = scan( /False\b/i )
+ start_group :FALSE, constant
+
+ # FIXME
+ elsif constant = scan( /(Empty|Nothing|Null|Err)\b/i )
+ start_group :ident, constant
+
+ # FIXME
+ elsif constant = scan( /(Response|Request|Server)\b/i )
+ start_group :ident, constant
+
+ elsif operator = scan( /With\b/i )
+ start_group :WITH, operator
+ elsif operator = scan( /Class\b/i )
+ start_group :CLASS, operator
+ elsif operator = scan( /Sub\b/i )
+ start_group :SUB, operator
+ elsif operator = scan( /Function\b/i )
+ start_group :FUNCTION, operator
+ elsif operator = scan( /Property\b/i )
+ start_group :PROPERTY, operator
+ elsif operator = scan( /End\b/i )
+ start_group :END, operator
+ elsif operator = scan( /Exit\b/i )
+ start_group :EXIT, operator
+ elsif operator = scan( /Get\b/i )
+ start_group :GET, operator
+
+ elsif keyword = scan( /New\b/i )
+ start_group :NEW, keyword
+
+ elsif operator = scan( /On +Error +Resume +Next\b/i )
+ start_group :IGNORE_ERRORS, operator
+ elsif operator = scan( /On +Error +Goto +0\b/i )
+ start_group :THROW_ERRORS, operator
+ elsif operator = scan( /Option +Explicit\b/i )
+ start_group :EXPLICIT, operator
+ elsif operator = scan( /Call\b/i )
+ start_group :CALL, operator
+ elsif operator = scan( /Randomize\b/i )
+ start_group :RANDOMIZE, operator
+ elsif operator = scan( /Private\b/i )
+ start_group :PRIVATE, operator
+ elsif operator = scan( /Public\b/i )
+ start_group :PUBLIC, operator
+ elsif operator = scan( /Erase\b/i )
+ start_group :ERASE, operator
+ elsif operator = scan( /Const\b/i )
+ start_group :CONST, operator
+ elsif operator = scan( /Dim\b/i )
+ start_group :DIM, operator
+ elsif operator = scan( /ReDim\b/i )
+ start_group :REDIM, operator
+ elsif operator = scan( /Preserve\b/i )
+ start_group :PRESERVE, operator
+ elsif operator = scan( /Let\b/i )
+ start_group :LET, operator
+ elsif operator = scan( /Set\b/i )
+ start_group :SET, operator
+ elsif operator = scan( /Do\b/i )
+ start_group :DO, operator
+ elsif operator = scan( /Loop\b/i )
+ start_group :LOOP, operator
+ elsif operator = scan( /For\b/i )
+ start_group :FOR, operator
+ elsif operator = scan( /In\b/i ) # FIXME: Not actually a reserved word! :(
+ start_group :IN, operator
+ elsif operator = scan( /To\b/i ) # FIXME: Not actually a reserved word! :(
+ start_group :TO, operator
+ elsif operator = scan( /Step\b/i ) # FIXME: Not actually a reserved word! :(
+ start_group :STEP, operator
+ elsif operator = scan( /Next\b/i )
+ start_group :NEXT, operator
+ elsif operator = scan( /Each\b/i )
+ start_group :EACH, operator
+ elsif operator = scan( /If\b/i )
+ start_group :IF, operator
+ elsif operator = scan( /With\b/i )
+ start_group :WITH, operator
+ elsif operator = scan( /Then\b/i )
+ start_group :THEN, operator
+ elsif operator = scan( /Else\b/i )
+ start_group :ELSE, operator
+ elsif operator = scan( /ElseIf\b/i )
+ start_group :ELSEIF, operator
+ elsif operator = scan( /Select\b/i )
+ start_group :SELECT, operator
+ elsif operator = scan( /Case\b/i )
+ start_group :CASE, operator
+ elsif operator = scan( /While\b/i )
+ start_group :WHILE, operator
+ elsif operator = scan( /Until\b/i )
+ start_group :UNTIL, operator
+ elsif operator = scan( /Wend\b/i )
+ start_group :WEND, operator
+
+ # FIXME
+ elsif builtin = scan( /(IsArray|LBound|UBound|Abs|Asc|AscB|AscW|Chr|ChrB|ChrW|CBool|CByte|CDate|CDbl|CInt|CLng|CSng|CStr|DateSerial|DateValue|Hex|Oct|Fix|Int|Sgn|TimeSerial|TimeValue|Date|Time|Day|Month|Weekday|Year|Hour|Minute|Second|Now|Atn|Cos|Sin|Tan|Exp|Log|Sqr|Rnd|CreateObject|IsObject|InStr|InStrB|Len|LenB|LCase|UCase|Left|LeftB|Mid|MidB|Right|RightB|Space|StrComp|String|LTrim|RTrim|Trim|IsDate|IsEmpty|IsNull|IsNumeric|VarType)(?= *\()/i )
+ start_group :ident, builtin
+
+ elsif operator = scan( /ByVal\b/i )
+ start_group :BYVAL, operator
+ elsif operator = scan( /ByRef\b/i )
+ start_group :BYREF, operator
+
+ elsif operator = scan( /Mod\b/i )
+ start_group :MOD, operator
+ elsif operator = scan( /Is\b/i )
+ start_group :IS, operator
+ elsif operator = scan( /Not\b/i )
+ start_group :NOT, operator
+ elsif operator = scan( /And\b/i )
+ start_group :AND, operator
+ elsif operator = scan( /Or\b/i )
+ start_group :OR, operator
+ elsif operator = scan( /Xor\b/i )
+ start_group :XOR, operator
+ elsif operator = scan( /Eqv\b/i )
+ start_group :EQV, operator
+ elsif operator = scan( /Imp\b/i )
+ start_group :IMP, operator
+
+ elsif digits = scan(/\d*\.\d+/)
+ start_group :float, digits
+
+ elsif digits = scan(/\d+/)
+ start_group :integer, digits
+
+ elsif words = scan(/\w+/)
+ start_group :ident, words
+
+ elsif punct = scan(/[,]/)
+ start_group :operator, punct
+ is_space = true
+
+ elsif punct = scan(/[(]/)
+ start_group @last_space ? :operator : :arg_paren, punct
+ is_space = true
+
+ elsif punct = scan(/[.]/)
+ start_group @last_space ? :with_dot : :operator, punct
+ allow_next_keyword = false
+
+ elsif punct = scan(/[)]/)
+ start_group :operator, punct
+ allow_next_keyword = false
+ is_space = false
+
+ elsif punct = scan(/[-+*\\\/^&=]|[<>]=|<>|[<>]/)
+ start_group :operator, punct
+ allow_next_keyword = false
+ is_space = true
+
+ elsif space = scan(/\s/)
+ start_group :space, space
+ is_space = true
+
+ elsif ext_ident = scan(/\[([^\]]*)\]/)
+ start_group :operator, '['
+ start_group :ident, subgroup( 1 )
+ start_group :operator, ']'
+
+ else
+ start_group :unknown, scan(/./)
+ end
+ when :string
+ if @file_type == :asp and marker = scan( /%>/ )
+ raise "Syntax error: Can't have %> in a string!"
+ elsif escaped = scan(/""/)
+ start_group :escaped_atom, escaped
+ start_group :string_text, scan(/([^"%]|%[^>])+%?/)
+ elsif quote = scan(/"/)
+ end_region :string_text
+ start_group :operator, quote
+ @mode = :normal
+ else
+ start_group :string_text, scan(/./)
+ end
+ end
+
+ @allow_keyword = allow_next_keyword
+ @last_space = is_space
+ end
+end
+
+Syntax::SYNTAX['vbscript'] = VbScriptTokenizer
+
View
2,516 rasp.rb
@@ -1,1258 +1,1258 @@
-
-class Hash
- def self.from_two_arrays keys, values
- hash = {}
- keys.size.times { |i| hash[keys[i]] = values[i] }
- hash
- end
-end
-class Array
- def debug_info action
- puts
- puts "#{action} code block:"
- puts
- p self
- puts
- end
- def token
- self[0].token rescue self[0]
- end
- def append other
- if other.is_a? Array
- self + other
- else
- self.push other
- end
- end
- def compile context
- debug_info 'Compiling' if $DEBUG
- compile_all(context).last
- end
- def run context
- run_all(context).last
- end
- def compile_all context
- map { |item| item.compile context }
- end
- def run_all context
- debug_info 'Running' if $DEBUG
- map { |item| item.run context }
- end
- def context= new_value
- each { |item| item.context = new_value }
- end
-end
-class Object
- def run context; self; end
- def compile context; self; end
- def simple; self; end
- def is_intrinsic?; false; end
-end
-class Array; def is_intrinsic?; true; end; end
-class Number; def is_intrinsic?; true; end; end
-class String; def is_intrinsic?; true; end; end
-
-module Rasp
- def self.name_of_member_to_call obj, original_name
- name = original_name.to_s.dup
- return name if obj.respond_to? name
- name.gsub!( /([A-Z])/ ) { |letter| "_#{letter.downcase}" }
- name.gsub!( /^_/, '' )
- return name if obj.respond_to? name
- name.gsub!( /(_[a-z])/ ) { |letter| letter.upcase[1,1] }
- return name if obj.respond_to? name
- name.gsub!( /^([a-z])/ ) { |letter| letter.upcase }
- return name if obj.respond_to? name
- name.downcase!
- return name if obj.respond_to? name
- name.gsub!( '_', '' )
- return name if obj.respond_to? name
-
- matches = obj.methods.select { |method_name| method_name.downcase.gsub( '_', '' ) == name }
- return matches[0] if matches.size == 1
-
- return original_name
- end
-
- class Context
- attr_accessor :local_variables
- attr_accessor :methods
- attr_accessor :parent_context
- attr_accessor :constants
- attr_accessor :errors_fatal
- attr_accessor :self_object
-
- def all_constant?; @all_constant; end
- def all_constant!; @all_constant = true; end
-
- def errors_fatal?
- return errors_fatal unless errors_fatal.nil?
- return parent_context.errors_fatal? unless parent_context.nil?
- true
- end
-
- def root_context
- return parent_context.root_context unless parent_context.nil?
- return self
- end
-
- def initialize options=nil
- @self_object = nil
- @parent_context = nil
- @methods = {}
- @local_variables = {}
- @constants = []
- options.each { |key, value| instance_variable_set('@' + key.to_s, value) } if options
- @all_constant = false
- @explicit = false
- end
-
- def get_method name, failure_fatal = true
- puts "Getting method #{name} in #{self}" if $DEBUG
-
- method = nil
- #name_on_object = Rasp::name_of_member_to_call( self_object, name )
- name_on_object = name.downcase
- method ||= self_object.method( name_on_object ) if self_object.respond_to? name_on_object
- method ||= methods[name.downcase]
- method ||= parent_context.get_method(name, failure_fatal) if parent_context
- raise "Unable to find method: #{name}" if method.nil? && failure_fatal
- method
- end
-
- def define_method name, args, body, exit_symbol, returns
- throw :constant_context if all_constant?
- throw :variable if variable_exists? name
- methods[name.downcase] = Method.new(:name => name, :arguments => args, :body => body, :context => self, :exit_symbol => exit_symbol, :returns => returns)
- end
- def define_native_method name, &block
- throw :constant_context if all_constant?
- throw :variable if variable_exists? name
- puts "Defining #{name.downcase}" if $DEBUG
- methods[name.downcase] = RubyMethod.new(:name => name, :block => block, :context => self)
- end
-
- def variable_context variable_name
- return self if local_variables.key? variable_name.downcase
- return parent_context.variable_context( variable_name ) unless parent_context.nil?
- end
-
- def define_variable variable_name, self_value = false
- return false if all_constant?
- return false if local_variables.key? variable_name.downcase
- return false if method_exists? variable_name and !self_value
- puts "Defining #{variable_name} (#{variable_name.class}) in #{self}" if $DEBUG
- local_variables[variable_name.downcase] = Empty.get
- return true
- end
-
- def [] variable_name
- return self_object if variable_name.downcase == 'me' unless self_object.nil?
- #name_on_object = Rasp::name_of_member_to_call( self_object, variable_name )
- name_on_object = variable_name.downcase
- return self_object.__send__( name_on_object ) if self_object.respond_to? name_on_object
- context = variable_context(variable_name)
- if context.nil?
- if method = get_method(variable_name, false)
- raise "#{variable_name} does not return a value" if method.respond_to?( :returns ) && !method.returns
- raise "Incorrect number of arguments for #{variable_name}; got 0, expected #{method.arity}" unless method.arity.zero? or method.arity == -1
- return method.call
- end
-
- if explicit?
- raise "Variable undefined: #{variable_name} (known: #{known_variables}); current context: #{self}"
- else
- define_variable variable_name
- context = self
- end
- end
- context.local_variables[variable_name.downcase]
- end
-
- def known_variables
- l_known = local_variables.keys.join(', ')
- p_known = parent_context.known_variables if parent_context
- return "#{l_known}; #{p_known}"
- end
-
- def []= variable_name, new_value
- throw :constant_context if all_constant?
- throw :constant if is_constant? variable_name
- context = variable_context(variable_name)
- unless context
- throw :variable_undefined if explicit?
- context = self
- end
- context.local_variables[variable_name.downcase] = new_value
- end
-
- def explicit?
- return parent_context.explicit? if parent_context
- @explicit
- end
- def explicit!
- @explicit = true
- end
-
- def exists? name
- variable_exists?(name) || method_exists?(name)
- end
-
- def variable_exists? name
- !variable_context(name).nil?
- end
-
- def method_exists? name
- !get_method(name, false).nil?
- end
-
- def is_constant? name
- constants.include? name.downcase
- end
-
- def define_constant name, value
- self[name] = value
- constants.push name.downcase
- value
- end
- end
-
- class MetaObject
- attr_accessor :__context__
- def simple
- throw :no_default_property
- end
- def method_missing target, *args
- name = Rasp::name_of_member_to_call( self, target )
- if name != target
- __send__ name, *args
- else
- super
- end
- end
- def generous_respond_to? method
- name = Rasp::name_of_member_to_call( self, method )
- respond_to? name
- end
- def initialize
- class_initialize if generous_respond_to? :class_initialize
- end
- def self.create_finalizer obj
- proc {|id| obj.class_terminate if obj.generous_respond_to? :class_terminate }
- end
- end
-
- # SYNTAX ERRORS
- # 1052 Cannot have multiple default property/method in a Class
- # 1044 Cannot use parentheses when calling a Sub
- # 1053 Class initialize or terminate do not have arguments
- # 1058 'Default' specification can only be on Property Get
- # 1057 'Default' specification must also specify 'Public'
- # 1005 Expected '('
- # 1006 Expected ')'
- # 1011 Expected '='
- # 1021 Expected 'Case'
- # 1047 Expected 'Class'
- # 1025 Expected end of statement
- # 1014 Expected 'End'
- # 1023 Expected expression
- # 1015 Expected 'Function'
- # 1010 Expected identifier
- # 1012 Expected 'If'
- # 1046 Expected 'In'
- # 1026 Expected integer constant
- # 1049 Expected Let or Set or Get in property declaration
- # 1045 Expected literal constant
- # 1019 Expected 'Loop'
- # 1020 Expected 'Next'
- # 1050 Expected 'Property'
- # 1022 Expected 'Select'
- # 1024 Expected statement
- # 1016 Expected 'Sub'
- # 1017 Expected 'Then'
- # 1013 Expected 'To'
- # 1018 Expected 'Wend'
- # 1027 Expected 'While' or 'Until'
- # 1028 Expected 'While,' 'Until,' or end of statement
- # 1029 Expected 'With'
- # 1030 Identifier too long
- # 1014 Invalid character
- # 1039 Invalid 'exit' statement
- # 1040 Invalid 'for' loop control variable
- # 1013 Invalid number
- # 1037 Invalid use of 'Me' keyword
- ## 1038 'loop' without 'do'
- # 1048 Must be defined inside a Class
- # 1042 Must be first statement on the line
- ## 1041 Name redefined
- # 1051 Number of arguments must be consistent across properties specification
- # 1001 Out of Memory
- # 1054 Property Set or Let must have at least one argument
- ## 1002 Syntax error
- # 1055 Unexpected 'Next'
- # 1015 Unterminated string constant
- #
- # RUNTIME ERRORS
- # 429 ActiveX component can't create object
- # 507 An exception occurred
- # 449 Argument not optional
- # 17 Can't perform requested operation
- # 430 Class doesn't support Automation
- # 506 Class not defined
- ## 11 Division by zero
- # 48 Error in loading DLL
- # 5020 Expected ')' in regular expression
- # 5019 Expected ']' in regular expression
- # 432 File name or class name not found during Automation operation
- # 92 For loop not initialized
- # 5008 Illegal assignment
- ## 51 Internal error
- # 505 Invalid or unqualified reference
- # 481 Invalid picture
- # 5 Invalid procedure call or argument
- # 5021 Invalid range in character set
- # 94 Invalid use of Null
- # 448 Named argument not found
- # 447 Object doesn't support current locale setting
- # 445 Object doesn't support this action
- # 438 Object doesn't support this property or method
- # 451 Object not a collection
- # 504 Object not safe for creating
- # 503 Object not safe for initializing
- # 502 Object not safe for scripting
- # 424 Object required
- # 91 Object variable not set
- # 7 Out of Memory
- # 28 Out of stack space
- # 14 Out of string space
- # 6 Overflow
- # 35 Sub or function not defined
- # 9 Subscript out of range
- # 5017 Syntax error in regular expression
- # 462 The remote server machine does not exist or is unavailable
- # 10 This array is fixed or temporarily locked
- # 13 Type mismatch
- # 5018 Unexpected quantifier
- # 500 Variable is undefined
- # 458 Variable uses an Automation type not supported in VBScript
- # 450 Wrong number of arguments or invalid property assignment
- #
- class ScriptError < RuntimeError
- def exception; self; end
- attr_accessor :error_symbol
- attr_accessor :statement
- attr_accessor :token
- attr_accessor :inner
- def initialize error_symbol, statement, token=nil
- self.error_symbol = error_symbol
- self.statement = statement
- self.token = token.nil? ? (statement.nil? ? nil : statement.token) : token
-
- @number, @description = \
- case error_symbol
- when :divide_by_zero
- [11, 'Division by zero']
- when :syntax_error
- [1002, 'Syntax error']
- when :name_redefined
- [1041, 'Name redefined']
- when :loop_without_do
- [1038, "'loop' without 'do'"]
- else
- [51, 'Internal error']
- end
- end
- attr_reader :number
- attr_accessor :description
- def location
- puts "token nil!" if token.nil?
- puts "token #{token.class} can't position!" unless token.nil? || token.respond_to?( :position )
- unless token.nil? || !token.respond_to?( :position )
- token.position + ' '
- end
- end
- def to_s
- "#{location}Microsoft VBScript runtime error: #{description}"
- end
- end
-
- class Statement
- def initialize options
- @token = nil
- options.each { |key, value| instance_variable_set('@' + key.to_s, value) }
- end
- attr_writer :token
- def token
- t = @token
- t = t.token while t.respond_to? :token
- t
- end
- def compile context
- end
- def run context
- begin
- run_statement context
- rescue ScriptError => error
- error.statement = self
- error.token = self.token # Maybe?
- raise error if context.errors_fatal?
- context.root_context['err'].load_from_ruby_exception error
- rescue StandardError => error
- wrapper = ScriptError.new :internal_error, self
- wrapper.inner = error
-# FIXME
- raise error
- raise wrapper if context.errors_fatal?
- context.root_context['err'].load_from_ruby_exception wrapper
-# ensure
-# GC.start
- end
- end
- end
-
- class ControlStructure < Statement
- def initialize options
- super options
- end
- end
-
- # For, Do, While
- class Loop < ControlStructure
- def initialize options
- super options
- end
-
- attr_accessor :init
- attr_accessor :pre
- attr_accessor :body
- attr_accessor :post
-
- def run_statement context
- init.run context
- loop do
- pre.run(context) or return
- body.run context
- post.run(context) or return
- end
- end
- end
-
- # For Each
- class Each < ControlStructure
- def initialize options
- super options
- end
-
- attr_accessor :variable
- attr_accessor :collection
- attr_accessor :body
-
- def run_statement context
- collection.run(context).each do |item|
- context[variable] = item
- body.run context
- end
- end
- end
-
- # On Error ...
- class OnError < ControlStructure
- def initialize options
- super options
- end
-
- attr_accessor :fatal
-
- def run_statement context
- context.errors_fatal = fatal
- end
- end
-
- # Option Explicit
- class Explicit < ControlStructure
- def compile context
- context.explicit!
- end
- def run_statement context
- end
- end
-
- # If
- class Conditional < ControlStructure
- def initialize options
- super options
- end
-
- attr_accessor :condition
- attr_accessor :true_part
- attr_accessor :false_part
-
- def run_statement context
- if condition.run(context).simple
- true_part.run context
- else
- false_part.run context
- end
- end
- end
-
- # Select Case
- class Select < ControlStructure
- def initialize options
- super options
- end
-
- attr_accessor :expression
- attr_accessor :alternatives
-
- def run_statement context
- value = expression.run(context).simple
- for alt in alternatives
- if alt[0] == :else || alt[0].find {|a| Rasp::Expression::Operator::Equal.new(:lvalue => value, :rvalue => a).run(context).simple }
- return alt[1].run(context)
- end
- end
- end
- end
-
- # Dim
- class Define < Statement
- def initialize options
- super options
- end
-
- attr_accessor :variable_name
-
- def compile context
- unless context.define_variable(variable_name)
- error = ScriptError.new(:name_redefined, self)
- raise error if context.errors_fatal?
- context.root_context['err'].load_from_ruby_exception error
- end
- end
- def run_statement context
- end
- end
-
- # Function
- class MethodDefine < Statement
- def initialize options
- super options
- end
-
- attr_accessor :name
- attr_accessor :arguments
- attr_accessor :body
- attr_accessor :exit_symbol
- attr_accessor :returns
- attr_accessor :scope
-
- def run_statement context
- context.define_method name, arguments, body, exit_symbol, returns
- end
- end
-
- # Class
- class ClassDefine < Statement
- def initialize options
- super options
- end
-
- attr_accessor :name
- attr_accessor :content
-
- def compile context
- klass = Class.new( MetaObject )
- class_context = Context.new(:parent_context => context)
- class_context.define_variable 'Me'
- get_destructor = nil
- content.flatten.each do |item|
- if item.is_a? Rasp::MethodDefine
- method = Method.new(:name => item.name, :arguments => item.arguments, :body => item.body, :context => context, :exit_symbol => item.exit_symbol, :returns => item.returns)
- # FIXME: Really shouldn't play with the name they're trying to define :(
- klass.send :define_method, item.name.downcase do |*args|
- method.call_with_context( self.__context__, *args )
- end
- if item.name.downcase == 'class_terminate'
- get_destructor = lambda do |context|
- lambda do |id|
- method.call_with_context( context )
- end
- end
- end
- end
- end
- # FIXME: This finalizer won't ever run because I've created a
- # circular reference :(
- klass.send :define_method, :initialize do
- #super
- self.__context__ = class_context.clone
- self.__context__.self_object = self
- self.__context__['Me'] = self
- ObjectSpace.define_finalizer( self, get_destructor.call( self.__context__ ) ) unless get_destructor.nil?
- #puts "Defining finalizer" unless get_destructor.nil?
- #get_destructor.call( self.__context ).call( 0 ) unless get_destructor.nil?
- end
-
- context[self.name] = klass
- end
-
- def run_statement context
- end
- end
-
- # =, Let, Set
- class Assignment < Statement
- def initialize options
- @object = nil
- @constant = nil
- super options
- end
-
- attr_accessor :lvalue
- attr_accessor :expression
- attr_accessor :constant
- attr_accessor :object
-
- def run_statement context
-# FIXME: Why are the next two lines required?!
- @object = nil unless defined? @object
- @constant = nil unless defined? @constant
-
- value = expression.run(context)
- value = value.simple unless object
-
- if constant
- context.define_constant lvalue, value
- elsif lvalue.is_a? String
- context[lvalue] = value
- else
- if lvalue.is_a? Rasp::Expression::MethodCall
- # Convert it to a member-call on the default method
- name = if lvalue.respond_to? :method_name
- if lvalue.method_name.respond_to? :variable_name
- lvalue.method_name.variable_name
- else
- lvalue.method_name
- end
- elsif lvalue.respond_to? :variable_name
- lvalue.variable_name
- end.downcase
- args = lvalue.respond_to?(:arguments) ? lvalue.arguments : []
-
- puts "lvalue is a method call... this must be an assignment to the default property" if $DEBUG
-
- lvalue = Rasp::Expression::MemberCall.new(
- :object => Rasp::Expression::Variable.new(:variable_name => name),
- :member => Rasp::Expression::MethodCall.new(:method_name => 'ASP_Default', :arguments => args))
- end
-
- args = lvalue.member.arguments.run_all(context) if lvalue.member.respond_to?(:arguments)
- args.push value
- name = if lvalue.member.respond_to? :method_name
- lvalue.member.method_name
- elsif lvalue.member.respond_to? :variable_name
- lvalue.member.variable_name
- end.downcase
-
- o = lvalue.object.run( context )
- name = Rasp::name_of_member_to_call( o, name )
-
- if o.respond_to?( :ole_methods ) && name == 'asp_default'
- name = o.ole_methods.find {|m| m.dispid == 0 }.name
- end
- name = '[]' if name == 'asp_default' and !o.respond_to?( :asp_default= ) and o.respond_to?( :[]= )
- if o.is_a? WIN32OLE
- o.setproperty( name, *args )
- else
- o.__send__(name + '=', *args)
- end
- end
- end
- end
- class Exit < Statement
- def initialize options
- super options
- end
- attr_accessor :symbol
- def run_statement context
- throw symbol
- end
- end
-
- # Response.Write
- class Print < Statement
- def initialize options
- super options
- end
-
- attr_accessor :expression
-
- def run_statement context
- puts expression.run(context).simple
- end
- end
-
- class Randomize < Statement
- def initialize options
- super options
- end
-
- attr_accessor :expression
-
- def run_statement context
- ignore = expression.run(context).simple
- end
- end
-
- class RubyMethod < ControlStructure
- def initialize options
- super options
- end
-
- attr_accessor :name
- attr_accessor :block
- attr_accessor :context
-
- def arity
- block.arity
- end
-
- def call *argument_values
- block.call( *argument_values )
- end
-
- def returns; true; end
- end
- class Method < ControlStructure
- def initialize options
- super options
- end
-
- attr_accessor :name
- attr_accessor :body
- attr_accessor :arguments
- attr_accessor :context
- attr_accessor :exit_symbol
- attr_accessor :returns
-
- def arity
- arguments.length
- end
-
- def call *argument_values
- call_with_context context, *argument_values
- end
- def call_with_context context, *argument_values
- c = Context.new(:parent_context => context)
- c.errors_fatal = true
-
- # The name of the method is also a variable, through which the
- # return value will be retrieved
- c.define_variable name, true
-
- # The method's arguments are defined as locally-scoped
- # variables
- args = Hash.from_two_arrays arguments, argument_values
- args.each { |name, value| c.define_variable(name); c[name] = value }
-
- catch exit_symbol do
- body.compile(c)
- body.run(c)
- end
-
- # The return value is the current value of the variable sharing
- # its name with this method
- c[self.name]
- end
- end
-
- module Expression
- class Atom
- def initialize options
- options.each { |key, value| instance_variable_set('@' + key.to_s, value) }
- end
- attr_writer :token
- def token
- t = @token
- t = t.token while t.respond_to? :token
- t
- end
- def compile context
- end
- end
-
- class Literal < Atom
- def initialize options
- super options
- end
-
- attr_accessor :value
-
- def run context
- value
- end
- end
-
- class NewObject < Atom
- def initialize options
- super options
- end
-
- attr_accessor :class_name
-
- def run context
- context[class_name].new
- end
- end
-
- class Variable < Atom
- def initialize options
- super options
- end
-
- attr_accessor :variable_name
-
- def run context
- puts "Getting variable #{variable_name}" if $DEBUG
- context[variable_name]
- end
- end
-
- class MemberCall < Atom
- def initialize options
- super options
- end
-
- attr_accessor :object
- attr_accessor :member
-
- def run context, *arguments
- puts "Calling member #{member.to_s} on #{object.to_s}" if $DEBUG
-
- name = if member.respond_to? :method_name
- member.method_name
- elsif member.respond_to? :variable_name
- member.variable.name
- else
- member
- end.downcase
- o = object.run( context )
- name = Rasp::name_of_member_to_call( o, name )
- args = member.respond_to?(:arguments) ? member.arguments : arguments
-
- args = args.run_all( context )
-
- if o.respond_to?( :ole_methods ) && name == 'asp_default'
- name = o.ole_methods.find {|m| m.dispid == 0 }.name
- end
- name = '[]' if name == 'asp_default' and !o.respond_to?( :asp_default ) and o.respond_to?( :[] )
- o.__send__( name, *args )
- end
- end
- class MemberSet < Atom
- def initialize options
- super options
- end
-
- attr_accessor :object
- attr_accessor :name
- attr_accessor :arguments
- attr_accessor :expression
- attr_accessor :action
-
- def run context
- value = expression.run(context)
- value = value.simple if :action == :let
- args = arguments.run_all(context)
- args.push value
- object.run.__send__ name + '=', *args
- end
- end
-
- class MethodCall < Atom
- def initialize options
- super options
- end
-
- attr_accessor :method_name
- attr_accessor :arguments
- attr_accessor :expect_return
-
- def run context
- self.method_name = method_name.variable_name if method_name.respond_to?( :variable_name )
- if method_name.is_a? Rasp::Expression::MemberCall
- return method_name.run( context, *arguments )
- #puts "method_name.object"
- #p method_name.object
- #puts "-- "
- #puts "method_name.member"
- #p method_name.member
- #puts "-- "
- #puts "arguments"
- #p arguments
- #puts "-- "
- end
- if method = context.get_method(method_name, false)
- args = arguments.run_all(context)
- raise "#{method_name} does not return a value" if expect_return && !method.returns
- unless method.arity.zero? && args.length > 0
- required = method.arity
- required = -required - 1 if required < 0
- expected = required
- expected = "at least #{expected}" if method.arity < 0
- raise "Incorrect number of arguments for #{method_name}; got #{args.length}, expected #{expected}" unless required == args.length or (args.length > required and method.arity < 0)
- return method.call(*args)
- else
- object = Rasp::Expression::MethodCall.new(:method_name => method_name, :arguments => [], :expect_return => true)
- end
- elsif context.exists? method_name
- object = Rasp::Expression::Variable.new(:variable_name => method_name)
- else
- raise "No such method: #{method_name}"
- end
-
- puts "Didn't find a method #{method_name}, maybe it's a default method call on an object... (#{context})" if $DEBUG
-
- # Convert it to a member-call on the default method
- return Rasp::Expression::MemberCall.new(
- :object => object,
- :member => Rasp::Expression::MethodCall.new(:method_name => 'ASP_Default', :arguments => arguments)
- ).run(context)
- end
- end
-
- module Operator
- class Operator < Rasp::Expression::Atom
- def initialize options
- super options
- end
- end
-
- class BinaryOperator < Operator
- def initialize options
- super options
- end
-
- attr_accessor :lvalue
- attr_accessor :rvalue
- end
-
- class UnaryOperator < Operator
- def initialize options
- super options
- end
-
- attr_accessor :value
- end
-
- class And < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple & rvalue.run(context).simple
- end
- end
- class Or < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple | rvalue.run(context).simple
- end
- end
- class Xor < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple ^ rvalue.run(context).simple
- end
- end
- class Eqv < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple ^ ~rvalue.run(context).simple
- end
- end
- class Imp < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- ~lvalue.run(context).simple | rvalue.run(context).simple
- end
- end
-
- class TypeOf < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).class.to_s == rvalue
- end
- end
-
- class Equal < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple == rvalue.run(context).simple
- end
- end
- class ObjEqual < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- #left = lvalue.run( context )
- #right = rvalue.run( context )
-
- #left.__id__ == right.__id__
- lvalue.run(context).__id__ == rvalue.run(context).__id__
- end
- end
- class NotEqual < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple != rvalue.run(context).simple
- end
- end
- class GreaterThan < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple > rvalue.run(context).simple
- end
- end
- class GreaterThanEqual < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple >= rvalue.run(context).simple
- end
- end
- class LessThan < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple < rvalue.run(context).simple
- end
- end
- class LessThanEqual < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple <= rvalue.run(context).simple
- end
- end
-
- class Concat < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple.to_s + rvalue.run(context).simple.to_s
- end
- end
-
- class Plus < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple + rvalue.run(context).simple
- end
- end
- class Minus < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple - rvalue.run(context).simple
- end
- end
- class Multiply < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple * rvalue.run(context).simple
- end
- end
- class Divide < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- begin
- lvalue.run(context).simple / rvalue.run(context).simple
- rescue ZeroDivisionError => error
- raise ScriptError.new(:divide_by_zero, nil, self.token)
- end
- end
- end
- class IntDivide < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- (lvalue.run(context).simple / rvalue.run(context).simple).to_i
- end
- end
- class Modulo < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple % rvalue.run(context).simple
- end
- end
- class Exponent < BinaryOperator
- def initialize options
- super options
- end
-
- def run context
- lvalue.run(context).simple ** rvalue.run(context).simple
- end
- end
-
- class UnaryMinus < UnaryOperator
- def initialize options
- super options
- end
-
- def run context
- -value.run(context).simple
- end
- end
- class UnaryPlus < UnaryOperator
- def initialize options
- super options
- end
-
- def run context
- value.run(context).simple
- end
- end
- class Not < UnaryOperator
- def initialize options
- super options
- end
-
- def run context
- ~value.run(context).simple
- end
- end
- end
- end
-end
-
-def test1
- c = Rasp::Context.new
- a_expr = Rasp::Expression::Literal.new(:value => 1)
- assignment = Rasp::Assignment.new(:lvalue => :a, :expression => a_expr)
- a_ref = Rasp::Expression::Variable.new(:variable_name => :a)
- comp = Rasp::Expression::Operator::GreaterThan.new(:lvalue => a_ref, :rvalue => 2)
- truepart = Rasp::Print.new(:expression => 'Foo')
- falsepart = Rasp::Print.new(:expression => 'Bar')
- if_stmt = Rasp::Conditional.new(:condition => comp, :true_part => truepart, :false_part => falsepart)
-
- file = [assignment, if_stmt]
- file.run c
-
- # a = 1
- # If a > 2 Then
- # Response.Write "Foo"
- # Else
- # Response.Write "Bar"
- # End If
-end
-
-def test2
- a_expr = Rasp::Expression::Literal.new(:value => 4)
- a_expr_2 = Rasp::Expression::Literal.new(:value => 23)
- a_assignment = Rasp::Assignment.new(:lvalue => :a, :expression => a_expr)
- a_assignment_2 = Rasp::Assignment.new(:lvalue => :a, :expression => a_expr_2)
- a_def = Rasp::Define.new(:variable_name => :a)
- a_ref = Rasp::Expression::Variable.new(:variable_name => :a)
- b_expr = Rasp::Expression::Literal.new(:value => 51)
- b_expr_2 = Rasp::Expression::Literal.new(:value => 17)
- b_assignment = Rasp::Assignment.new(:lvalue => :b, :expression => b_expr)
- b_assignment_2 = Rasp::Assignment.new(:lvalue => :b, :expression => b_expr_2)
- b_ref = Rasp::Expression::Variable.new(:variable_name => :b)
- method_call = Rasp::Expression::MethodCall.new(:method_name => :frob, :arguments => [])
-
- a_out = Rasp::Print.new(:expression => a_ref.dup)
- b_out = Rasp::Print.new(:expression => b_ref.dup)
- sep_out = Rasp::Print.new(:expression => '-')
-
- method_body = [a_def, a_assignment_2, b_assignment_2, a_out.dup, b_out.dup, sep_out.dup]
-
- method_def = Rasp::MethodDefine.new(:name => :frob, :arguments => [], :body => method_body)
-
- file = [method_def, a_assignment, b_assignment, a_out, b_out, sep_out, method_call, a_out, b_out]
- file.run Rasp::Context.new
-
- # Sub frob
- # Dim a
- # a = 23
- # b = 17
- #
- # Response.Write a
- # Response.Write b
- # Response.Write "-"
- # End Sub
- #
- # a = 4
- # b = 51
- #
- # Response.Write a
- # Response.Write b
- # Response.Write "-"
- #
- # frob
- #
- # Response.Write a
- # Response.Write b
-end
-
-#puts 'test1:'
-#test1
-#puts '-- '
-
-#puts 'test2:'
-#test2
-#puts '-- '
-
+
+class Hash
+ def self.from_two_arrays keys, values
+ hash = {}
+ keys.size.times { |i| hash[keys[i]] = values[i] }
+ hash
+ end
+end
+class Array
+ def debug_info action
+ puts
+ puts "#{action} code block:"
+ puts
+ p self
+ puts
+ end
+ def token
+ self[0].token rescue self[0]
+ end
+ def append other
+ if other.is_a? Array
+ self + other
+ else
+ self.push other
+ end
+ end
+ def compile context
+ debug_info 'Compiling' if $DEBUG
+ compile_all(context).last
+ end
+ def run context
+ run_all(context).last
+ end
+ def compile_all context
+ map { |item| item.compile context }
+ end
+ def run_all context
+ debug_info 'Running' if $DEBUG
+ map { |item| item.run context }
+ end
+ def context= new_value
+ each { |item| item.context = new_value }
+ end
+end
+class Object
+ def run context; self; end
+ def compile context; self; end
+ def simple; self; end
+ def is_intrinsic?; false; end
+end
+class Array; def is_intrinsic?; true; end; end
+class Number; def is_intrinsic?; true; end; end
+class String; def is_intrinsic?; true; end; end
+
+module Rasp
+ def self.name_of_member_to_call obj, original_name
+ name = original_name.to_s.dup
+ return name if obj.respond_to? name
+ name.gsub!( /([A-Z])/ ) { |letter| "_#{letter.downcase}" }
+ name.gsub!( /^_/, '' )
+ return name if obj.respond_to? name
+ name.gsub!( /(_[a-z])/ ) { |letter| letter.upcase[1,1] }
+ return name if obj.respond_to? name
+ name.gsub!( /^([a-z])/ ) { |letter| letter.upcase }
+ return name if obj.respond_to? name
+ name.downcase!
+ return name if obj.respond_to? name
+ name.gsub!( '_', '' )
+ return name if obj.respond_to? name
+
+ matches = obj.methods.select { |method_name| method_name.downcase.gsub( '_', '' ) == name }
+ return matches[0] if matches.size == 1
+
+ return original_name
+ end
+
+ class Context
+ attr_accessor :local_variables
+ attr_accessor :methods
+ attr_accessor :parent_context
+ attr_accessor :constants
+ attr_accessor :errors_fatal
+ attr_accessor :self_object
+
+ def all_constant?; @all_constant; end
+ def all_constant!; @all_constant = true; end
+
+ def errors_fatal?
+ return errors_fatal unless errors_fatal.nil?
+ return parent_context.errors_fatal? unless parent_context.nil?
+ true
+ end
+
+ def root_context
+ return parent_context.root_context unless parent_context.nil?
+ return self
+ end
+
+ def initialize options=nil
+ @self_object = nil
+ @parent_context = nil
+ @methods = {}
+ @local_variables = {}
+ @constants = []
+ options.each { |key, value| instance_variable_set('@' + key.to_s, value) } if options
+ @all_constant = false
+ @explicit = false
+ end
+
+ def get_method name, failure_fatal = true
+ puts "Getting method #{name} in #{self}" if $DEBUG
+
+ method = nil
+ #name_on_object = Rasp::name_of_member_to_call( self_object, name )
+ name_on_object = name.downcase
+ method ||= self_object.method( name_on_object ) if self_object.respond_to? name_on_object
+ method ||= methods[name.downcase]
+ method ||= parent_context.get_method(name, failure_fatal) if parent_context
+ raise "Unable to find method: #{name