]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - offlineasm/parser.rb
JavaScriptCore-1218.tar.gz
[apple/javascriptcore.git] / offlineasm / parser.rb
index 11863c72468dc944860922598ea60ceebb377b6a..4f45d30584bf812e1fe13041ff20243b1489f2af 100644 (file)
@@ -21,6 +21,7 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
 require "ast"
 require "instructions"
 require "pathname"
@@ -73,6 +74,15 @@ class Token
     end
 end
 
+class Annotation
+    attr_reader :codeOrigin, :type, :string
+    def initialize(codeOrigin, type, string)
+        @codeOrigin = codeOrigin
+        @type = type
+        @string = string
+    end
+end
+
 #
 # The lexer. Takes a string and returns an array of tokens.
 #
@@ -81,11 +91,27 @@ def lex(str, fileName)
     fileName = Pathname.new(fileName)
     result = []
     lineNumber = 1
+    annotation = nil
+    whitespaceFound = false
     while not str.empty?
         case str
         when /\A\#([^\n]*)/
             # comment, ignore
+        when /\A\/\/\ ?([^\n]*)/
+            # annotation
+            annotation = $1
+            annotationType = whitespaceFound ? :local : :global
         when /\A\n/
+            # We've found a '\n'.  Emit the last comment recorded if appropriate:
+            # We need to parse annotations regardless of whether the backend does
+            # anything with them or not. This is because the C++ backend may make
+            # use of this for its cloopDo debugging utility even if
+            # enableInstrAnnotations is not enabled.
+            if annotation
+                result << Annotation.new(CodeOrigin.new(fileName, lineNumber),
+                                         annotationType, annotation)
+                annotation = nil
+            end
             result << Token.new(CodeOrigin.new(fileName, lineNumber), $&)
             lineNumber += 1
         when /\A[a-zA-Z]([a-zA-Z0-9_]*)/
@@ -96,6 +122,9 @@ def lex(str, fileName)
             result << Token.new(CodeOrigin.new(fileName, lineNumber), $&)
         when /\A([ \t]+)/
             # whitespace, ignore
+            whitespaceFound = true
+            str = $~.post_match
+            next
         when /\A0x([0-9a-fA-F]+)/
             result << Token.new(CodeOrigin.new(fileName, lineNumber), $&.hex.to_s)
         when /\A0([0-7]+)/
@@ -109,6 +138,7 @@ def lex(str, fileName)
         else
             raise "Lexer error at #{CodeOrigin.new(fileName, lineNumber).to_s}, unexpected sequence #{str[0..20].inspect}"
         end
+        whitespaceFound = false
         str = $~.post_match
     end
     result
@@ -161,6 +191,7 @@ class Parser
     def initialize(data, fileName)
         @tokens = lex(data, fileName)
         @idx = 0
+        @annotation = nil
     end
     
     def parseError(*comment)
@@ -192,8 +223,9 @@ class Parser
     
     def parsePredicateAtom
         if @tokens[@idx] == "not"
+            codeOrigin = @tokens[@idx].codeOrigin
             @idx += 1
-            parsePredicateAtom
+            Not.new(codeOrigin, parsePredicateAtom)
         elsif @tokens[@idx] == "("
             @idx += 1
             skipNewLine
@@ -473,6 +505,20 @@ class Parser
         loop {
             if (@idx == @tokens.length and not final) or (final and @tokens[@idx] =~ final)
                 break
+            elsif @tokens[@idx].is_a? Annotation
+                # This is the only place where we can encounter a global
+                # annotation, and hence need to be able to distinguish between
+                # them.
+                # globalAnnotations are the ones that start from column 0. All
+                # others are considered localAnnotations.  The only reason to
+                # distinguish between them is so that we can format the output
+                # nicely as one would expect.
+
+                codeOrigin = @tokens[@idx].codeOrigin
+                annotationOpcode = (@tokens[@idx].type == :global) ? "globalAnnotation" : "localAnnotation"
+                list << Instruction.new(codeOrigin, annotationOpcode, [], @tokens[@idx].string)
+                @annotation = nil
+                @idx += 2 # Consume the newline as well.
             elsif @tokens[@idx] == "\n"
                 # ignore
                 @idx += 1
@@ -533,11 +579,17 @@ class Parser
                 @idx += 1
                 if (not final and @idx == @tokens.size) or (final and @tokens[@idx] =~ final)
                     # Zero operand instruction, and it's the last one.
-                    list << Instruction.new(codeOrigin, name, [])
+                    list << Instruction.new(codeOrigin, name, [], @annotation)
+                    @annotation = nil
                     break
+                elsif @tokens[@idx].is_a? Annotation
+                    list << Instruction.new(codeOrigin, name, [], @tokens[@idx].string)
+                    @annotation = nil
+                    @idx += 2 # Consume the newline as well.
                 elsif @tokens[@idx] == "\n"
                     # Zero operand instruction.
-                    list << Instruction.new(codeOrigin, name, [])
+                    list << Instruction.new(codeOrigin, name, [], @annotation)
+                    @annotation = nil
                     @idx += 1
                 else
                     # It's definitely an instruction, and it has at least one operand.
@@ -552,6 +604,10 @@ class Parser
                         elsif @tokens[@idx] == ","
                             # Has another operand.
                             @idx += 1
+                        elsif @tokens[@idx].is_a? Annotation
+                            @annotation = @tokens[@idx].string
+                            @idx += 2 # Consume the newline as well.
+                            break
                         elsif @tokens[@idx] == "\n"
                             # The end of the instruction.
                             @idx += 1
@@ -560,11 +616,14 @@ class Parser
                             parseError("Expected a comma, newline, or #{final} after #{operands.last.dump}")
                         end
                     }
-                    list << Instruction.new(codeOrigin, name, operands)
+                    list << Instruction.new(codeOrigin, name, operands, @annotation)
+                    @annotation = nil
                     if endOfSequence
                         break
                     end
                 end
+
+            # Check for potential macro invocation:
             elsif isIdentifier @tokens[@idx]
                 codeOrigin = @tokens[@idx].codeOrigin
                 name = @tokens[@idx].string
@@ -601,7 +660,13 @@ class Parser
                             end
                         }
                     end
-                    list << MacroCall.new(codeOrigin, name, operands)
+                    # Check if there's a trailing annotation after the macro invoke:
+                    if @tokens[@idx].is_a? Annotation
+                        @annotation = @tokens[@idx].string
+                        @idx += 2 # Consume the newline as well.
+                    end
+                    list << MacroCall.new(codeOrigin, name, operands, @annotation)
+                    @annotation = nil
                 else
                     parseError "Expected \"(\" after #{name}"
                 end