Class: BBSexp::Compiler

Inherits:
Object
  • Object
show all
Defined in:
lib/bbsexp/compiler.rb

Instance Method Summary collapse

Constructor Details

#initialize(parser, text) ⇒ Compiler

Returns a new instance of Compiler.



3
4
5
6
7
8
9
10
11
# File 'lib/bbsexp/compiler.rb', line 3

def initialize(parser, text)
  @parser = parser
  @text = text
  @result = ''
  @stack = []
  @func_stack = []
  @state = [3]
  @locks = Hash[ @parser.exps.keys.map{|k| [k, false] } ]
end

Instance Method Details

#buildObject



13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/bbsexp/compiler.rb', line 13

def build
  @result <<  tokens.map do |type, value|
                case type
                when :string  then eval_string value
                when :exp     then eval_exp value
                end
              end.join

  # close unclosed expressions
  @result << @stack.reverse.map {|token|
              token.reverse.map {|exp|
                @parser.exps[exp].tags.last }.join }.join
end

#eval_exp(exp) ⇒ Object



44
45
46
47
48
49
50
51
52
53
# File 'lib/bbsexp/compiler.rb', line 44

def eval_exp(exp)
  # dont parse if we are in the no parse zone
  return eval_string(@parser.brackets(exp)) if @state.last == 0 and not exp.include? @parser.no_parse
  # process expressions
  unless exp[0] == @parser.end_exp
    register(exp)  #returns start tags
  else
    terminate(exp) #returns end tags
  end
end

#eval_string(string) ⇒ Object



39
40
41
42
# File 'lib/bbsexp/compiler.rb', line 39

def eval_string(string)
  # run callbacks on string
  @func_stack.reduce(string) {|memo, func| func.(memo) }
end

#register(token) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/bbsexp/compiler.rb', line 55

def register(token)
  @stack << active_exps =               # append valid expressions to the stack
  token.chars.to_a.uniq.select do |exp| # ignore redundant and illegal expressions 
    @locks[exp] == false and @parser.exps[exp] <= @state.last
  end.sort do |a,b|
    @parser.exps[b] <=> @parser.exps[a] # sort nocode > block > inline
  end.map do |exp|
    @locks[exp] = true                  # lock this expression to prevent its use deeper in the stack
    @state << @parser.exps[exp].state   # set parser state to current element's level
    exp                                 # return to token.active_exps as a valid expression
  end
  
  @func_stack += active_exps.map {|exp| @parser.exps[exp].block }.compact

  # return the start tags for the token
  active_exps.map {|exp| @parser.exps[exp].tags.first }.join
end

#terminate(token) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/bbsexp/compiler.rb', line 73

def terminate(token) 
  return @parser.brackets(token) if @stack.empty? # don't do anything if the stack is empty

  token.chars.map do |close|
    if exps = @stack.pop
      exps.map do |exp|
        @locks[exp] = false                        # unlock this expression so it can be used again
        @state.pop                                 # return parser state to parent scope
        @func_stack.pop if @parser.exps[exp].block # disable function
        @parser.exps[exp].tags.last                # return end tag
      end.reverse.join
    end
  end.join
end

#tokens {|[:string, scanner.rest]| ... } ⇒ Object

Yields:

  • ([:string, scanner.rest])


27
28
29
30
31
32
33
34
35
36
37
# File 'lib/bbsexp/compiler.rb', line 27

def tokens
  return to_enum(:tokens) unless block_given?
  scanner = StringScanner.new(@text)

  while string = scanner.scan_until(@parser.regexp) 
   exp = scanner.matched
   yield [:string, string[0..-(exp.size + 1)]] unless string == exp
   yield [:exp, exp[1..-2]]
  end
  yield [:string, scanner.rest] unless scanner.eos?
end