Module: Liquidscript::Compiler::Base::Helpers

Included in:
Liquidscript::Compiler::Base
Defined in:
lib/liquidscript/compiler/base/helpers.rb

Instance Method Summary collapse

Instance Method Details

#action(act = nil) { ... } ⇒ Proc, Action

Normalizes an action for the hash passed to #expect. If a block is given, it returns that block. If the argument is a proc, it returns that proc. If none of those conditions are met, it returns the Action.

Parameters:

  • act (Proc, nil) (defaults to: nil)

    the proc to return, if it is a proc.

Yields:

  • nothing.

Returns:



14
15
16
17
18
19
20
21
22
# File 'lib/liquidscript/compiler/base/helpers.rb', line 14

def action(act = nil)
  if block_given?
    Proc.new
  elsif act.is_a? Proc
    act
  else
    @action
  end
end

#collect_compiles(compile, *end_on) ⇒ Array<Object> #collect_compiles(*end_on, &block) ⇒ Object

last element of ‘end_on` is a Hash, it is merged with the

default actions that this takes and passes it to `expect`.

 @example
   collect_compiles(:test) { shift :_ }

 @yieldreturn The value you want to be placed in the
   array.
 @param end_on [Array<Symbol>] an array of symbols to end
   the loop.
 @return [Array<Object>] the results of all of the block
   calls.

Overloads:

  • #collect_compiles(compile, *end_on) ⇒ Array<Object>

    Calls the method ‘:compile_#Liquidscript::Compiler::Base#compile` for every peeked token that isn’t a part of ‘end_on`. Once it encounters that, it returns the values of all of those calls. If the last element of `end_on` is a Hash, it is merged with the default actions that this takes and passes it to `expect`.

    Examples:

    def compile_if
      shift :if
      shift :lparen
      conditional = compile_expression
      shift :rparen
      shift :lbrack
      body = collect_compiles(:expression, :rbrack)
      [:if, conditional, body]
    end

    Parameters:

    • compile (Symbol)

      the method to call.

    • end_on (Array<Symbol>)

      an array of symbols to end the loop.

    Returns:

  • #collect_compiles(*end_on, &block) ⇒ Object

    Calls the block for every peeked token that isn’t in ‘end_on`. Once it encounters a token that it, it returns the value of all of the block calls. If the



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/liquidscript/compiler/base/helpers.rb', line 105

def collect_compiles(*end_on)
  compiles = []

  if block_given?
    compile = Proc.new
  else
    compile = end_on.shift
  end

  block = Callable.new(self, compile)

  hash = if end_on.last.is_a? Hash
    end_on.pop.dup
  else
    {}
  end

  do_compile = action do
    compiles << block.call
  end

  hash.merge! end_on => action.end_loop,
              :_     => do_compile

  loop do
    expect hash
  end

  compiles
end

#expect(*args) ⇒ Object

The meat and potatos of the compiler. This maps actions to tokens. In its basic form, it is passed a hash, with the keys being token types, and the values the corresponding actions to take. It can be passed individual types, from which it’ll assume the method name (normally, ‘compile_<type>`); or, you can pass it a symbol key, which is the last part of the method name (i.e., not including `compile_`). It will check the next token, and look for the correct action; if the next token doesn’t match any of the given keys, it checks for the special type ‘:_` (which is basically a catch-all), and if it still doesn’t get it, it raises an UnexpectedError. From there, it calls the corresponding block.

If the block or method accepts one argument, it Liquidscript::Compiler::Base#pops the token, and passes it in as an argument. If it accepts no arguments, it doesn’t.

Examples:

# If the next token has type `:test`, it will output
# "hello!"  If the next token has any other type, it
# raises an error.
expect :test => action { puts "hello!" }
# If the next token has the type `:number`, it calls
# the method `compile_number`; if the next token has
# the type `:dstring`, it calls the method
# `compile_string`.
expect :number, :dstring => :string
# Just pops the comma token.
expect :comma => action.shift
# When given a hash with one of the keys as an array, each
# element of that array is treated as a token type, and
# that token type is mapped to the value as an action.
expect [:identifier, :dstring] => action.end_loop
# When given `:_` as an argument, it'll map the next token
# to its corresponding compile function.
expect :_
# If the next token's type is `:identifier`, it will call
# `compile_identifier`.

Parameters:

  • *args (Array<Symbol, Hash<Symbol, Object>>)

Returns:

  • (Object)

    the result of the block/method call.

Raises:

  • (UnexpectedError)

    if the next token’s type didn’t match any of the given types, and the ‘:_` type wasn’t given.



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/liquidscript/compiler/base/helpers.rb', line 184

def expect(*args)
  hash = normalize_arguments(args)

  block = hash.fetch(peek.type) do
    hash.fetch(:_)
  end

  out = if block.arity == 1
    block.call pop
  else
    block.call
  end

  out

rescue KeyError
  raise UnexpectedError.new(hash.keys, peek)
end

#loopvoid

This method returns an undefined value.

Performs a loop while the yield returns true. This overwrites the core loop on purpose.

Yield Returns:

  • (Boolean)

    whether or not to continue looping.



29
30
31
32
33
34
35
# File 'lib/liquidscript/compiler/base/helpers.rb', line 29

def loop
  result = true

  while result
    result = yield
  end
end

#maybe(*types) ⇒ #type

Shifts a token if its one of the given types; if it’s not, it returns the value of Liquidscript::Compiler::Base#scanner_nil.

Parameters:

  • types (Symbol)

    the token types to look for.

Returns:

  • (#type)

    the token.



53
54
55
# File 'lib/liquidscript/compiler/base/helpers.rb', line 53

def maybe(*types)
  expect types => action.shift, :_ => action { scanner_nil }
end

#peek?(*types) ⇒ Boolean

Checks to see if the next token is of any of the given types. Note that the special type ‘:_` does not work here.

Parameters:

  • types (Symbol)

    the token types to match.

Returns:

  • (Boolean)

    whether or not the next token’s type matches any of the given types.



63
64
65
# File 'lib/liquidscript/compiler/base/helpers.rb', line 63

def peek?(*types)
  types.any? { |type| peek.type == type }
end

#shift(*types) ⇒ #type

Shift a token over. The given types can be any types. If the next token’s type doesn’t match any of the types, then it will raise an error. In order to shift any token, use the special type ‘:_`.

Parameters:

  • types (Symbol)

    the token types to look for.

Returns:

  • (#type)

    the token.



44
45
46
# File 'lib/liquidscript/compiler/base/helpers.rb', line 44

def shift(*types)
  expect types => action.shift
end