~ubuntu-branches/ubuntu/oneiric/ctioga2/oneiric

« back to all changes in this revision

Viewing changes to lib/ctioga2/commands/parsers/file.rb

  • Committer: Bazaar Package Importer
  • Author(s): Vincent Fourmond
  • Date: 2011-01-24 21:36:06 UTC
  • Revision ID: james.westby@ubuntu.com-20110124213606-9ettx0ugl83z0bzp
Tags: upstream-0.1
ImportĀ upstreamĀ versionĀ 0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# file.rb: a file parser for ctioga2
 
2
# copyright (c) 2009 by Vincent Fourmond
 
3
  
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
  
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details (in the COPYING file).
 
13
 
 
14
require 'stringio'
 
15
require 'ctioga2/utils'
 
16
require 'ctioga2/log'
 
17
require 'ctioga2/commands/commands'
 
18
require 'ctioga2/commands/strings'
 
19
 
 
20
module CTioga2
 
21
 
 
22
  Version::register_svn_info('$Revision: 151 $', '$Date: 2010-06-19 23:45:20 +0200 (Sat, 19 Jun 2010) $')
 
23
 
 
24
  module Commands
 
25
 
 
26
    module Parsers
 
27
 
 
28
      # Raised when EOF is encountered during a symbol parsing
 
29
      class UnterminatedSymbol < Exception
 
30
      end
 
31
 
 
32
      # Unexepected character.
 
33
      class UnexpectedCharacter < Exception
 
34
      end
 
35
 
 
36
      # Syntax error
 
37
      class ParserSyntaxError < Exception
 
38
      end
 
39
 
 
40
      # This class is in charge of parsing a command-line against a list
 
41
      # of known commands. 
 
42
      class FileParser
 
43
 
 
44
        include Log
 
45
 
 
46
        # Runs a command file targeting the given _interpreter_.
 
47
        def self.run_command_file(file, interpreter)
 
48
          FileParser.new.run_command_file(file, interpreter)
 
49
        end
 
50
 
 
51
        # Runs the given command strings
 
52
        def self.run_commands(strings, interpreter)
 
53
          FileParser.new.run_commands(strings, interpreter)
 
54
        end
 
55
 
 
56
        # Runs a command file targeting the given _interpreter_.
 
57
        def run_command_file(file, interpreter)
 
58
          f = open(file)
 
59
          parse_io_object(f, interpreter)
 
60
        end
 
61
 
 
62
        # Runs the given command strings
 
63
        def run_commands(strings, interpreter)
 
64
          io = StringIO.new(strings)
 
65
          parse_io_object(io, interpreter)
 
66
        end
 
67
 
 
68
        # Parses a given _io_ object, sending commands/variable
 
69
        # definitions to the given _interpreter_.
 
70
        def parse_io_object(io, interpreter)
 
71
          # The process is simple: we look for symbols and
 
72
          # corresponding syntax element: parentheses or assignments
 
73
          while(1)
 
74
            symbol = up_to_next_symbol(io)
 
75
            break if not symbol
 
76
            
 
77
            while(1)
 
78
              c = io.getc
 
79
              if ! c              # EOF
 
80
                raise ParserSyntaxError, "Expecting something after symbol #{symbol}"
 
81
              end
 
82
              ch = c.chr
 
83
              if ch =~ /\s/      # blank...
 
84
                next
 
85
              elsif ch == '('    # beginning of a function call
 
86
                # Parse string:
 
87
                str = InterpreterString.parse_until_unquoted(io,")")
 
88
                # Now, we need to split str.
 
89
                args = str.expand_and_split(/\s*,\s*/, interpreter)
 
90
 
 
91
                cmd = interpreter.get_command(symbol)
 
92
                real_args = args.slice!(0, cmd.argument_number)
 
93
                # And now the options:
 
94
                options = {}
 
95
 
 
96
                # Problem: the space on the right of the = sign is
 
97
                # *significant*. 
 
98
                for o in args
 
99
                  if o =~ /^\s*\/?([\w-]+)\s*=(.*)/
 
100
                    if cmd.has_option? $1
 
101
                      options[$1] = $2
 
102
                    else
 
103
                      error { 
 
104
                        "Command #{cmd.name} does not take option #{$1}" 
 
105
                      }
 
106
                    end
 
107
                  end
 
108
                end
 
109
 
 
110
                interpreter.run_command(cmd, real_args, options)
 
111
                io.getc         # Slurp up the )
 
112
                break
 
113
              elsif ch == ':'   # Assignment
 
114
                c = io.getc
 
115
                if ! c          # EOF
 
116
                  raise ParserSyntaxError, "Expecting = after :"
 
117
                end
 
118
                ch = c.chr
 
119
                if ch != '='
 
120
                  raise ParserSyntaxError, "Expecting = after :"
 
121
                end
 
122
                str = InterpreterString.parse_until_unquoted(io,"\n", false)
 
123
                interpreter.variables.define_variable(symbol, str, 
 
124
                                                      interpreter)
 
125
                break
 
126
              elsif ch == '='
 
127
                str = InterpreterString.parse_until_unquoted(io,"\n", false)
 
128
                interpreter.variables.define_variable(symbol, str, nil) 
 
129
                break
 
130
              else
 
131
                raise UnexpectedCharacter, "Did not expect #{ch} after #{symbol}"
 
132
              end
 
133
            end
 
134
          end
 
135
        end
 
136
 
 
137
        protected
 
138
 
 
139
        SYMBOL_CHAR_REGEX = /[a-zA-Z0-9_-]/
 
140
        
 
141
        # Parses the _io_ stream up to and including the next
 
142
        # symbol. Only white space or comments may be found on the
 
143
        # way. This function returns the symbol.
 
144
        #
 
145
        # Symbols are composed of the alphabet SYMBOL_CHAR_REGEX.
 
146
        def up_to_next_symbol(io)
 
147
 
 
148
          symbol = nil          # As long as no symbol as been started
 
149
          # it will stay nil.
 
150
          while(1)
 
151
            c = io.getc
 
152
            if ! c              # EOF
 
153
              if symbol
 
154
                raise UnterminatedSymbol, "EOF reached during symbol parsing"
 
155
              else
 
156
                # File is finished and we didn't meet any symbol.
 
157
                # Nothing to do !
 
158
                return nil
 
159
              end
 
160
            end
 
161
            ch = c.chr
 
162
            if symbol           # We have started
 
163
              if ch =~ SYMBOL_CHAR_REGEX
 
164
                symbol += ch
 
165
              else
 
166
                io.ungetc(c)
 
167
                return symbol
 
168
              end
 
169
            else
 
170
              if ch =~ SYMBOL_CHAR_REGEX
 
171
                symbol = ch
 
172
              elsif ch =~ /\s/
 
173
                # Nothing
 
174
              elsif ch == '#'
 
175
                io.gets
 
176
              else
 
177
                raise UnexpectedCharacter, "Unexpected character: #{ch}, when looking for a symbol"
 
178
              end
 
179
            end
 
180
          end
 
181
        end
 
182
 
 
183
      end
 
184
 
 
185
    end
 
186
  end
 
187
end
 
188