Module: Flexr::DSL
- Included in:
- Lexer
- Defined in:
- lib/flexr/dsl.rb,
lib/flexr/generated.rb
Constant Summary collapse
- DSL_METHODS =
%i[rule state all_states on_eof emits backend token_kind encoding option accel].freeze
Instance Attribute Summary collapse
-
#__flexr_compiled ⇒ Object
readonly
Returns the value of attribute __flexr_compiled.
-
#__flexr_config ⇒ Object
readonly
Returns the value of attribute __flexr_config.
-
#__flexr_generated_actions ⇒ Object
readonly
Returns the value of attribute __flexr_generated_actions.
-
#__flexr_rules ⇒ Object
readonly
Returns the value of attribute __flexr_rules.
-
#__flexr_states ⇒ Object
readonly
Returns the value of attribute __flexr_states.
Instance Method Summary collapse
- #__flexr_add_generated_eof(state, action) ⇒ Object
- #__flexr_add_generated_rule(definition) ⇒ Object
- #__flexr_bind_generated_action(index, action) ⇒ Object
- #__flexr_generated? ⇒ Boolean
- #__flexr_mark_generated! ⇒ Object
- #__flexr_reset! ⇒ Object
- #__flexr_set_compiled!(compiled) ⇒ Object
- #__flexr_spec ⇒ Object
- #accel(value) ⇒ Object
- #all_states ⇒ Object
- #backend(name) ⇒ Object
- #compile! ⇒ Object
- #dfa ⇒ Object
- #emits(*tokens) ⇒ Object
- #encoding(value) ⇒ Object
- #inherited(child) ⇒ Object
- #on_eof(&action) ⇒ Object
- #option(*values) ⇒ Object
- #rule(pattern, skip: false, emit: nil, followed_by: nil, &action) ⇒ Object
- #state(*names, inclusive: false, &block) ⇒ Object
- #token_kind(name) ⇒ Object
Instance Attribute Details
#__flexr_compiled ⇒ Object (readonly)
Returns the value of attribute __flexr_compiled.
154 155 156 |
# File 'lib/flexr/dsl.rb', line 154 def __flexr_compiled @__flexr_compiled end |
#__flexr_config ⇒ Object (readonly)
Returns the value of attribute __flexr_config.
154 155 156 |
# File 'lib/flexr/dsl.rb', line 154 def __flexr_config @__flexr_config end |
#__flexr_generated_actions ⇒ Object (readonly)
Returns the value of attribute __flexr_generated_actions.
154 155 156 |
# File 'lib/flexr/dsl.rb', line 154 def __flexr_generated_actions @__flexr_generated_actions end |
#__flexr_rules ⇒ Object (readonly)
Returns the value of attribute __flexr_rules.
154 155 156 |
# File 'lib/flexr/dsl.rb', line 154 def __flexr_rules @__flexr_rules end |
#__flexr_states ⇒ Object (readonly)
Returns the value of attribute __flexr_states.
154 155 156 |
# File 'lib/flexr/dsl.rb', line 154 def __flexr_states @__flexr_states end |
Instance Method Details
#__flexr_add_generated_eof(state, action) ⇒ Object
156 157 158 |
# File 'lib/flexr/dsl.rb', line 156 def __flexr_add_generated_eof(state, action) __flexr_mutate! { @__flexr_eof_rules[state.to_sym] = action } end |
#__flexr_add_generated_rule(definition) ⇒ Object
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/flexr/generated.rb', line 132 def __flexr_add_generated_rule(definition) __flexr_mutate! do action = definition.fetch(:action) @__flexr_rules << IR::Rule.new( index: definition.fetch(:index), patterns: Array(definition.fetch(:patterns)), trailing: normalize_trailing(definition[:trailing]), action: action, states: Array(definition.fetch(:states)).map(&:to_sym), bol_only: definition.fetch(:bol_only, false), end_anchor: definition[:end_anchor], location: definition[:span] || definition[:location], pattern_conditions: Array(definition[:pattern_conditions]).map do |condition| next unless condition Automaton::Acceptance.new(rule_index: condition[0], pattern_index: condition[1], bol_only: condition[2], end_anchor: condition[3]) end ) end end |
#__flexr_bind_generated_action(index, action) ⇒ Object
171 172 173 174 175 |
# File 'lib/flexr/dsl.rb', line 171 def __flexr_bind_generated_action(index, action) raise FrozenSpecificationError, "generated actions can only be bound on a generated lexer" unless @__flexr_generated @__flexr_generated_actions[index] = action end |
#__flexr_generated? ⇒ Boolean
177 178 179 |
# File 'lib/flexr/dsl.rb', line 177 def __flexr_generated? @__flexr_generated == true end |
#__flexr_mark_generated! ⇒ Object
167 168 169 |
# File 'lib/flexr/dsl.rb', line 167 def __flexr_mark_generated! @__flexr_generated = true end |
#__flexr_reset! ⇒ Object
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/flexr/dsl.rb', line 11 def __flexr_reset! @__flexr_rules = [] @__flexr_states = { initial: IR::State.new(name: :initial, inclusive: true, id: 0) } @__flexr_state_stack = [] @__flexr_eof_rules = {} @__flexr_config = IR::Config.new( backend: :table, token_kind: :array, encoding: Encoding::UTF_8, options: {}, declared_tokens: [], states: @__flexr_states ) @__flexr_compiled = nil @__flexr_generated = false @__flexr_generated_actions = [] @__flexr_specification_frozen = false @__flexr_compile_mutex = Monitor.new end |
#__flexr_set_compiled!(compiled) ⇒ Object
160 161 162 163 164 165 |
# File 'lib/flexr/dsl.rb', line 160 def __flexr_set_compiled!(compiled) @__flexr_compile_mutex.synchronize do @__flexr_compiled = freeze_compiled!(compiled) freeze_specification! end end |
#__flexr_spec ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/flexr/dsl.rb', line 138 def __flexr_spec IR::Spec.new( class_name: name, superclass: superclass&.name, backend: @__flexr_config.backend, token_kind: @__flexr_config.token_kind, encoding: @__flexr_config.encoding, options: @__flexr_config., declared_tokens: @__flexr_config.declared_tokens, states: @__flexr_states, rules: @__flexr_rules, eof_rules: @__flexr_eof_rules, verbatim: nil ) end |
#accel(value) ⇒ Object
114 115 116 |
# File 'lib/flexr/dsl.rb', line 114 def accel(value) __flexr_mutate! { @__flexr_config.[:accel] = Configuration.accelerator!(value) } end |
#all_states ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/flexr/dsl.rb', line 65 def all_states(&) raise ArgumentError, "all_states requires a block" unless block_given? __flexr_mutate! do names = @__flexr_states.keys @__flexr_state_stack.concat(names) begin class_eval(&) ensure names.length.times { @__flexr_state_stack.pop } end end end |
#backend(name) ⇒ Object
90 91 92 |
# File 'lib/flexr/dsl.rb', line 90 def backend(name) __flexr_mutate! { @__flexr_config.backend = Configuration.backend!(name) } end |
#compile! ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/flexr/dsl.rb', line 118 def compile! @__flexr_compile_mutex.synchronize do # The ivar is part of the generated/runtime class contract. # rubocop:disable Naming/MemoizedInstanceVariableName @__flexr_compiled ||= begin compiled = Automaton::Compiler.new(__flexr_spec).compile @__flexr_config.backend = auto_direct?(compiled) ? :direct : :table if @__flexr_config.backend == :auto freeze_specification! freeze_compiled!(compiled) compiled end # rubocop:enable Naming/MemoizedInstanceVariableName end end |
#dfa ⇒ Object
133 134 135 136 |
# File 'lib/flexr/dsl.rb', line 133 def dfa compile! __flexr_compiled end |
#emits(*tokens) ⇒ Object
86 87 88 |
# File 'lib/flexr/dsl.rb', line 86 def emits(*tokens) __flexr_mutate! { @__flexr_config.declared_tokens.concat(tokens.flatten.map(&:to_sym)).uniq! } end |
#encoding(value) ⇒ Object
98 99 100 101 102 103 104 105 106 |
# File 'lib/flexr/dsl.rb', line 98 def encoding(value) encoding = value.is_a?(Encoding) ? value : Encoding.find(value.to_s) unless [Encoding::UTF_8, Encoding::BINARY].include?(encoding) diagnostic = Diagnostics.error("FLEXR-E011", "flexr supports UTF-8 and BINARY only") raise CompileError.new(diagnostic., diagnostic: diagnostic) end __flexr_mutate! { @__flexr_config.encoding = encoding } end |
#inherited(child) ⇒ Object
6 7 8 9 |
# File 'lib/flexr/dsl.rb', line 6 def inherited(child) super child.__flexr_reset! end |
#on_eof(&action) ⇒ Object
79 80 81 82 83 84 |
# File 'lib/flexr/dsl.rb', line 79 def on_eof(&action) __flexr_mutate! do state_name = @__flexr_state_stack.last || :initial @__flexr_eof_rules[state_name] = action end end |
#option(*values) ⇒ Object
108 109 110 111 112 |
# File 'lib/flexr/dsl.rb', line 108 def option(*values) __flexr_mutate! do values.each { |value| @__flexr_config.[Configuration.option!(value)] = true } end end |
#rule(pattern, skip: false, emit: nil, followed_by: nil, &action) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/flexr/dsl.rb', line 27 def rule(pattern, skip: false, emit: nil, followed_by: nil, &action) __flexr_mutate! do patterns = normalize_patterns(pattern) rule_action = ActionResolver.resolve( skip: skip, emit: emit, block: action, default: proc { emit(nil, text) } ) states = @__flexr_state_stack.empty? ? [:initial] : @__flexr_state_stack.dup @__flexr_rules << IR::Rule.new( index: @__flexr_rules.length, patterns: patterns, trailing: normalize_trailing(followed_by), action: rule_action, states: states, bol_only: false, end_anchor: nil ) end nil end |
#state(*names, inclusive: false, &block) ⇒ Object
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/flexr/dsl.rb', line 42 def state(*names, inclusive: false, &block) raise ArgumentError, "state requires a block" unless block raise ArgumentError, "state requires a name" if names.empty? __flexr_mutate! do names.each do |name| symbol = name.to_sym existing = @__flexr_states[symbol] raise ArgumentError, "state #{symbol.inspect} already declared with inclusive: #{existing.inclusive}" if existing && existing.inclusive != inclusive @__flexr_states[symbol] ||= IR::State.new( name: symbol, inclusive: inclusive, id: @__flexr_states.length ) end @__flexr_state_stack.concat(names.map(&:to_sym)) begin class_eval(&block) ensure names.length.times { @__flexr_state_stack.pop } end end end |
#token_kind(name) ⇒ Object
94 95 96 |
# File 'lib/flexr/dsl.rb', line 94 def token_kind(name) __flexr_mutate! { @__flexr_config.token_kind = Configuration.token_kind!(name) } end |