pingus-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Pingus-CVS] r3475 - trunk/sexpr


From: grumbel at BerliOS
Subject: [Pingus-CVS] r3475 - trunk/sexpr
Date: Sat, 3 Nov 2007 08:18:35 +0100

Author: grumbel
Date: 2007-11-03 08:18:34 +0100 (Sat, 03 Nov 2007)
New Revision: 3475

Added:
   trunk/sexpr/level-syntax.scm
   trunk/sexpr/parser.rb
Modified:
   trunk/sexpr/schema.rb
   trunk/sexpr/sexpr.rb
   trunk/sexpr/sexpr_test.rb
Log:
- some more cleanup

Added: trunk/sexpr/level-syntax.scm
===================================================================
--- trunk/sexpr/level-syntax.scm        2007-11-03 06:53:45 UTC (rev 3474)
+++ trunk/sexpr/level-syntax.scm        2007-11-03 07:18:34 UTC (rev 3475)
@@ -0,0 +1,50 @@
+;; -*- scheme -*-
+
+(element (name "pingus-level")
+  (use  "required")
+  (type (mapping
+         (children
+          (element (name "version") (type (int)))
+          (element (name "head") 
+            (type (mapping
+                   (children
+                    (element (name "levelname")        (type (string)))
+                    (element (name "description")      (type (string)))
+                    (element (name "author")           (type (string)))
+                    (element (name "number-of-pingus") (type (int)))
+                    (element (name "number-to-save")   (type (int)))
+                    (element (name "time")             (type (int)))
+                    (element (name "difficulty")       (type (int)))
+                    (element (name "playable")         (type (int)))
+                    (element (name "comment")          (type (string)))
+                    (element (name "music")            (type (string)))
+                    (element (name "actions")
+                      (type (mapping
+                             (children
+                              (element (name "basher")   (type (int (min 1))))
+                              (element (name "blocker")  (type (int (min 1))))
+                              (element (name "bomber")   (type (int (min 1))))
+                              (element (name "bridger")  (type (int (min 1))))
+                              (element (name "climber")  (type (int (min 1))))
+                              (element (name "jumper")   (type (int (min 1))))
+                              ))))
+                    ))))
+          (element (name "objects")
+            (type (sequence
+                   (children
+                    (element (name "groundpiece")
+                      (type (mapping
+                             (children
+                              (element (name "position") (type (vector2i)))
+                              (element (name "surface")  (type (surface)))))))
+
+                    (element (name "exit")
+                      (type (mapping
+                             (children
+                              (element (name "position") (type (vector2i)))
+                              (element (name "surface")  (type (surface)))
+                              (element (name "release-rate") (type (int)))))))
+                    ))))
+          ))))
+
+;; EOF ;;

Added: trunk/sexpr/parser.rb
===================================================================
--- trunk/sexpr/parser.rb       2007-11-03 06:53:45 UTC (rev 3474)
+++ trunk/sexpr/parser.rb       2007-11-03 07:18:34 UTC (rev 3475)
@@ -0,0 +1,276 @@
+#  SExpr - A simple Ruby library for parsing and validating s-expressions
+#  Copyright (C) 2007 Ingo Ruhnke <address@hidden>
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+require "sexpr.rb"
+
+module SExpr
+  class Parser
+    
+    def is_digit(c)
+      return (?0..?9).member?(c)
+    end
+
+    def is_letter(c)
+      return((?a..?z).member?(c) or (?A..?Z).member?(c))
+    end
+
+    def is_whitespace(c)
+      return(c == ?\s or c == ?\n or c == ?\t)
+    end
+
+    def is_special_initial(c)
+      return(c == ?! or
+             c == ?$ or 
+             c == ?% or 
+             c == ?& or 
+             c == ?* or 
+             c == ?/ or 
+             c == ?: or 
+             c == ?< or 
+             c == ?= or 
+             c == ?> or 
+             c == ?? or 
+             c == ?^ or 
+             c == ?_ or 
+             c == ?~)
+    end
+
+    def is_special_subsequent(c)
+      return(c == ?+ or
+             c == ?- or
+             c == ?. or
+             c == ?@)
+    end
+
+    def is_sign(c)
+      return(c == ?+ or
+             c == ?-)
+    end
+    
+    def initialize(str)
+      @str = str
+    end
+
+    def parse()
+      @state = :look_for_token
+      tokenize()
+
+      elements = []
+      sublists = []
+
+      @tokens.each{ |token|
+        if token.is_a?(SExpr) then
+          if not sublists.empty? then
+            sublists.last().append(token)
+          else
+            elements << token
+          end
+        elsif token.is_a?(Array) then
+          if token[0] == :list_start then
+            sublists.push(List.new([], token[1]))
+          elsif token[0] == :list_end then
+            if sublists.empty? then
+              raise "Unexpected List end"
+            else
+              lst = sublists.pop()
+              if not sublists.empty? then
+                sublists.last().append(lst)
+              else
+                elements << lst
+              end
+            end
+          end
+        else
+          raise "Parser bug: parse: #{token}"
+        end
+      }
+
+      return elements
+    end
+
+    def tokenize()
+      @line   = 1
+      @column = 1
+
+      @last_c = nil
+      @tokens = []
+
+      @pos = 0
+      @token_start = @pos
+      
+      @advance = true
+      while(@pos < @str.length) do
+        @c = @address@hidden
+
+        scan(@c)
+        
+        if @advance then
+          # Line/Column counting
+          if (@c == ?\n) then
+            @line   += 1
+            @column  = 1
+          else
+            @column += 1
+          end
+
+          @last_c = @c
+
+          @pos += 1
+        else
+          @advance = true
+        end
+      end
+
+      scan(nil) # EOF #
+    end
+
+    def scan(c)
+      case @state
+      when :look_for_token:
+          if is_digit(c) or is_sign(c) then
+            @state = :parse_integer_or_real
+          elsif c == ?\" then
+            @state = :parse_string
+          elsif c == ?# then
+            @state = :parse_boolean
+          elsif is_letter(c) or is_special_initial(c) then
+            @state = :parse_symbol
+          elsif is_whitespace(c) then
+            @state = :parse_whitespace
+          elsif c == ?; then
+            @state = :parse_comment
+          elsif c == ?) then
+            submit(:list_end, true)
+          elsif c == ?( then
+            submit(:list_start, true)
+          elsif c == nil then
+            # EOF is ok
+          else
+            raise "address@hidden:address@hidden: unexpected character 
'#{c.chr}'"
+          end
+
+      when :parse_integer_or_real:
+          if is_digit(c) then
+            # ok
+          elsif c == ?. then
+            @state = :parse_real
+          else
+            if @token_start == @pos - 1 and not is_digit(@address@hidden) then
+              raise "address@hidden:address@hidden: 
'address@hidden@token_start].chr}' must be followed by digit"
+            else
+              submit(:integer, false)
+            end
+          end
+
+      when :parse_boolean:
+          if c == ?t or c == ?f then
+            submit(:boolean, true)
+          else
+            raise "address@hidden:address@hidden: expected 'f' or 't', got 
'#{c.chr}"
+          end
+
+      when :parse_real:
+          if (?0..?9).member?(c) then
+            # ok
+          else
+            submit(:real, false)
+          end
+
+      when :parse_symbol:
+          if is_letter(c) or is_digit(c) or is_special_subsequent(c) or 
is_special_initial(c) then
+            # ok
+          else
+            submit(:symbol, false)
+          end
+        
+      when :parse_string:
+          if (c == ?" and @last_c != ?\\) then
+            submit(:string, true)
+          end
+
+      when :parse_whitespace
+        if not is_whitespace(c) then
+          submit(:whitespace, false)
+        end
+
+      when :parse_comment
+        if c == ?\n then
+          submit(:comment, true)
+        end     
+
+      else
+        raise "Parser error, unknown state: address@hidden"
+      end
+    end
+
+    def get_pos()
+      return "@line:@column"
+    end
+
+    def submit(type, include_current_character)
+      @state = :look_for_token
+
+      if include_current_character then
+        current_token = @address@hidden(@pos)]
+        @token_start = @pos+1
+      else
+        current_token = @address@hidden(@pos-1)]
+        @token_start = @pos
+        @advance = false
+      end
+      
+      case type
+      when :boolean
+        @tokens << Boolean.new(current_token == "#t", get_pos())
+        
+      when :integer
+        @tokens << Integer.new(current_token.to_i, get_pos())
+
+      when :real
+        @tokens << Real.new(current_token.to_f, get_pos())
+
+      when :string
+        @tokens << String.new(current_token[1..-2].
+                              gsub("\\n", "\n").
+                              gsub("\\\"", "\"").
+                              gsub("\\t", "\t"),
+                              get_pos())
+
+      when :symbol
+        @tokens << Symbol.new(current_token, get_pos())
+        
+      when :list_start
+        @tokens << [:list_start, get_pos()]
+
+      when :list_end
+        @tokens << [:list_end, get_pos()]
+
+      when :comment
+        # ignore
+
+      when :whitespace
+        # ignore
+
+      else
+        raise "Parser Bug: #{type}" 
+      end
+      # puts "#{current_token.inspect} => #{type} : 
address@hidden:address@hidden"
+    end
+  end
+end
+
+# EOF #

Modified: trunk/sexpr/schema.rb
===================================================================
--- trunk/sexpr/schema.rb       2007-11-03 06:53:45 UTC (rev 3474)
+++ trunk/sexpr/schema.rb       2007-11-03 07:18:34 UTC (rev 3475)
@@ -15,8 +15,10 @@
 #  along with this program; if not, write to the Free Software
 #  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
+require "sexpr.rb"
+require "parser.rb"
+
 module SExpr
-
   class Schema
     def initialize(schema)
       if schema.is_a?(SExpr) then
@@ -31,6 +33,50 @@
     end
   end
 
+  class Element
+    attr_reader :name  # name of the expected element
+    attr_reader :use   # required, optional, forbidden
+    attr_reader :type  # ListType, IntegerType, ...
+    
+    def validate(sexpr)
+      if not sexpr.is_a?(List) then
+        raise "#{sexpr.pos}: expected list, got #{sexpr.class}"
+      else
+        if sexpr.value.empty() then
+          raise "#{sexpr.pos}: expected a non-empty List"
+        else
+          if not sexpr[0].is_a?(Symbol) then
+            raise "#{sexpr.pos}: expected a symbol, got #{sexpr[0].class}"
+          else
+            if sexpr[0].value != @name then
+              raise "#{sexpr.pos}: expected symbol '#{name}', got 
#{sexpr[0].value}"
+            else
+              # ok, now check type and/or validate children
+              
+            end
+          end            
+        end
+      end
+    end
+  end
+
+  class IntegerType
+    
+  end
+
+  # A list of ((key value) ...) 
+  class MappingType
+    
+  end
+  
+  # A list of other elements ((foo 5) (bar 10) (baz "foo") ...)
+  class SequenceType
+    
+  end
+  
+  class ChoiceType
+    
+  end
 end
 
 # EOF #

Modified: trunk/sexpr/sexpr.rb
===================================================================
--- trunk/sexpr/sexpr.rb        2007-11-03 06:53:45 UTC (rev 3474)
+++ trunk/sexpr/sexpr.rb        2007-11-03 07:18:34 UTC (rev 3475)
@@ -16,262 +16,12 @@
 #  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 module SExpr
-  class Parser
 
-    def is_digit(c)
-      return (?0..?9).member?(c)
-    end
-
-    def is_letter(c)
-      return((?a..?z).member?(c) or (?A..?Z).member?(c))
-    end
-
-    def is_whitespace(c)
-      return(c == ?\s or c == ?\n or c == ?\t)
-    end
-
-    def is_special_initial(c)
-      return(c == ?! or
-             c == ?$ or 
-             c == ?% or 
-             c == ?& or 
-             c == ?* or 
-             c == ?/ or 
-             c == ?: or 
-             c == ?< or 
-             c == ?= or 
-             c == ?> or 
-             c == ?? or 
-             c == ?^ or 
-             c == ?_ or 
-             c == ?~)
-    end
-
-    def is_special_subsequent(c)
-      return(c == ?+ or
-             c == ?- or
-             c == ?. or
-             c == ?@)
-    end
-
-    def is_sign(c)
-      return(c == ?+ or
-             c == ?-)
-    end
-
-    def initialize(str)
-      @str = str
-    end
-
-    def parse()
-      @state = :look_for_token
-      tokenize()
-
-      elements = []
-      sublists = []
-
-      @tokens.each{ |token|
-        if token.is_a?(SExpr) then
-          if not sublists.empty? then
-            sublists.last().append(token)
-          else
-            elements << token
-          end
-        elsif token.is_a?(Array) then
-          if token[0] == :list_start then
-            sublists.push(List.new([], token[1]))
-          elsif token[0] == :list_end then
-            if sublists.empty? then
-              raise "Unexpected List end"
-            else
-              lst = sublists.pop()
-              if not sublists.empty? then
-                sublists.last().append(lst)
-              else
-                elements << lst
-              end
-            end
-          end
-        else
-          raise "Parser bug: parse: #{token}"
-        end
-      }
-
-      return elements
-    end
-
-    def tokenize()
-      @line   = 1
-      @column = 1
-
-      @last_c = nil
-      @tokens = []
-
-      @pos = 0
-      @token_start = @pos
-      
-      @advance = true
-      while(@pos < @str.length) do
-        @c = @address@hidden
-
-        scan(@c)
-        
-        if @advance then
-          # Line/Column counting
-          if (@c == ?\n) then
-            @line   += 1
-            @column  = 1
-          else
-            @column += 1
-          end
-
-          @last_c = @c
-
-          @pos += 1
-        else
-          @advance = true
-        end
-      end
-
-      scan(nil) # EOF #
-    end
-
-    def scan(c)
-      case @state
-      when :look_for_token:
-          if is_digit(c) or is_sign(c) then
-            @state = :parse_integer_or_real
-          elsif c == ?\" then
-            @state = :parse_string
-          elsif c == ?# then
-            @state = :parse_boolean
-          elsif is_letter(c) or is_special_initial(c) then
-            @state = :parse_symbol
-          elsif is_whitespace(c) then
-            @state = :parse_whitespace
-          elsif c == ?; then
-            @state = :parse_comment
-          elsif c == ?) then
-            submit(:list_end, true)
-          elsif c == ?( then
-            submit(:list_start, true)
-          elsif c == nil then
-            # EOF is ok
-          else
-            raise "address@hidden:address@hidden: unexpected character 
'#{c.chr}'"
-          end
-
-      when :parse_integer_or_real:
-          if is_digit(c) then
-            # ok
-          elsif c == ?. then
-            @state = :parse_real
-          else
-            if @token_start == @pos - 1 and not is_digit(@address@hidden) then
-              raise "address@hidden:address@hidden: 
'address@hidden@token_start].chr}' must be followed by digit"
-            else
-              submit(:integer, false)
-            end
-          end
-
-      when :parse_boolean:
-          if c == ?t or c == ?f then
-            submit(:boolean, true)
-          else
-            raise "address@hidden:address@hidden: expected 'f' or 't', got 
'#{c.chr}"
-          end
-
-      when :parse_real:
-          if (?0..?9).member?(c) then
-            # ok
-          else
-            submit(:real, false)
-          end
-
-      when :parse_symbol:
-          if is_letter(c) or is_digit(c) or is_special_subsequent(c) or 
is_special_initial(c) then
-            # ok
-          else
-            submit(:symbol, false)
-          end
-        
-      when :parse_string:
-          if (c == ?" and @last_c != ?\\) then
-            submit(:string, true)
-          end
-
-      when :parse_whitespace
-        if not is_whitespace(c) then
-          submit(:whitespace, false)
-        end
-
-      when :parse_comment
-        if c == ?\n then
-          submit(:comment, true)
-        end     
-
-      else
-        raise "Parser error, unknown state: address@hidden"
-      end
-    end
-
-    def get_pos()
-      return "@line:@column"
-    end
-
-    def submit(type, include_current_character)
-      @state = :look_for_token
-
-      if include_current_character then
-        current_token = @address@hidden(@pos)]
-        @token_start = @pos+1
-      else
-        current_token = @address@hidden(@pos-1)]
-        @token_start = @pos
-        @advance = false
-      end
-      
-      case type
-      when :boolean
-        @tokens << Boolean.new(current_token == "#t", get_pos())
-        
-      when :integer
-        @tokens << Integer.new(current_token.to_i, get_pos())
-
-      when :real
-        @tokens << Real.new(current_token.to_f, get_pos())
-
-      when :string
-        @tokens << String.new(current_token[1..-2].
-                              gsub("\\n", "\n").
-                              gsub("\\\"", "\"").
-                              gsub("\\t", "\t"),
-                              get_pos())
-
-      when :symbol
-        @tokens << Symbol.new(current_token, get_pos())
-        
-      when :list_start
-        @tokens << [:list_start, get_pos()]
-
-      when :list_end
-        @tokens << [:list_end, get_pos()]
-
-      when :comment
-        # ignore
-
-      when :whitespace
-        # ignore
-
-      else
-        raise "Parser Bug: #{type}" 
-      end
-      # puts "#{current_token.inspect} => #{type} : 
address@hidden:address@hidden"
-    end
-  end
-
   class SExpr
+    attr_reader :pos
+
     def initialize(pos = nil)
+      @pos = pos
     end
 
     def self.parse(str)
@@ -375,6 +125,14 @@
       @value << el
     end
 
+    def [](idx)
+      return @value[idx]      
+    end
+
+    def empty?()
+      return @value.empty?()
+    end
+
     def to_s()
       return "(" + @value.map{|i| i.to_s}.join(" ") + ")"
     end

Modified: trunk/sexpr/sexpr_test.rb
===================================================================
--- trunk/sexpr/sexpr_test.rb   2007-11-03 06:53:45 UTC (rev 3474)
+++ trunk/sexpr/sexpr_test.rb   2007-11-03 07:18:34 UTC (rev 3475)
@@ -1,6 +1,7 @@
 #!/usr/bin/ruby -w
 
 require "sexpr.rb"
+require "parser.rb"
 
 if ARGV.empty?() then
   puts SExpr::SExpr.parse("(pi8ngulevel -.51 a (b +1.5) -5)")





reply via email to

[Prev in Thread] Current Thread [Next in Thread]