Class: Glaemscribe::API::RuleGroup
Constant Summary collapse
- VAR_NAME_REGEXP =
/{([0-9A-Z_]+)}/
- UNICODE_VAR_NAME_REGEXP_IN =
/^UNI_([0-9A-F]+)$/
- UNICODE_VAR_NAME_REGEXP_OUT =
/{UNI_([0-9A-F]+)}/
- VAR_DECL_REGEXP =
/^\s*{([0-9A-Z_]+)}\s+===\s+(.+?)\s*$/
- POINTER_VAR_DECL_REGEXP =
/^\s*{([0-9A-Z_]+)}\s+<=>\s+(.+?)\s*$/
- RULE_REGEXP =
/^\s*(.*?)\s+-->\s+(.+?)\s*$/
- CROSS_SCHEMA_REGEXP =
/[0-9]+(\s*,\s*[0-9]+)*/
- CROSS_RULE_REGEXP =
/^\s*(.*?)\s+-->\s+(#{CROSS_SCHEMA_REGEXP}|#{VAR_NAME_REGEXP}|identity)\s+-->\s+(.+?)\s*$/
Instance Attribute Summary collapse
-
#in_charset ⇒ Object
readonly
Returns the value of attribute in_charset.
-
#macros ⇒ Object
readonly
Returns the value of attribute macros.
-
#mode ⇒ Object
readonly
Returns the value of attribute mode.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#root_code_block ⇒ Object
readonly
Returns the value of attribute root_code_block.
-
#rules ⇒ Object
readonly
Returns the value of attribute rules.
Instance Method Summary collapse
- #add_var(var_name, value, is_pointer) ⇒ Object
-
#apply_vars(line, string, allow_unicode_vars = false) ⇒ Object
Replace all vars in expression.
- #descend_if_tree(code_block, trans_options) ⇒ Object
- #finalize(trans_options) ⇒ Object
- #finalize_code_line(code_line) ⇒ Object
- #finalize_rule(line, match_exp, replacement_exp, cross_schema = nil) ⇒ Object
-
#initialize(mode, name) ⇒ RuleGroup
constructor
A new instance of RuleGroup.
Constructor Details
Instance Attribute Details
#in_charset ⇒ Object (readonly)
Returns the value of attribute in_charset.
54 55 56 |
# File 'lib/api/rule_group.rb', line 54 def in_charset @in_charset end |
#macros ⇒ Object (readonly)
Returns the value of attribute macros.
54 55 56 |
# File 'lib/api/rule_group.rb', line 54 def macros @macros end |
#mode ⇒ Object (readonly)
Returns the value of attribute mode.
54 55 56 |
# File 'lib/api/rule_group.rb', line 54 def mode @mode end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
54 55 56 |
# File 'lib/api/rule_group.rb', line 54 def name @name end |
#root_code_block ⇒ Object (readonly)
Returns the value of attribute root_code_block.
54 55 56 |
# File 'lib/api/rule_group.rb', line 54 def root_code_block @root_code_block end |
#rules ⇒ Object (readonly)
Returns the value of attribute rules.
54 55 56 |
# File 'lib/api/rule_group.rb', line 54 def rules @rules end |
Instance Method Details
#add_var(var_name, value, is_pointer) ⇒ Object
63 64 65 |
# File 'lib/api/rule_group.rb', line 63 def add_var(var_name, value, is_pointer) @vars[var_name] = RuleGroupVar.new(var_name, value, is_pointer) end |
#apply_vars(line, string, allow_unicode_vars = false) ⇒ Object
Replace all vars in expression
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/api/rule_group.rb', line 68 def apply_vars(line, string, allow_unicode_vars=false) ret = string stack_depth = 0 had_replacements = true while had_replacements had_replacements = false ret = ret.gsub(VAR_NAME_REGEXP) { |cap_var| vname = $1 v = @vars[vname] if !v if vname =~ UNICODE_VAR_NAME_REGEXP_IN # A unicode variable. if allow_unicode_vars # Just keep this variable intact, it will be replaced at the last moment of the parsing rep = cap_var else @mode.errors << Glaeml::Error.new(line, "In expression: #{string}: making wrong use of unicode variable: #{cap_var}. Unicode vars can only be used in source members of a rule or in the definition of another variable.") return nil end else @mode.errors << Glaeml::Error.new(line, "In expression: #{string}: failed to evaluate variable: #{cap_var}.") return nil end else rep = v.value # Only count replacements on non unicode vars had_replacements = true end rep } stack_depth += 1 break if !had_replacements if stack_depth > 16 @mode.errors << Glaeml::Error.new(line, "In expression: #{string}: evaluation stack overflow.") return nil end end ret end |
#descend_if_tree(code_block, trans_options) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/api/rule_group.rb', line 114 def descend_if_tree(code_block, ) code_block.terms.each{ |term| if(term.is_code_lines?) term.code_lines.each{ |cl| finalize_code_line(cl) } elsif(term.is_macro_deploy?) # Ok this is a bit dirty but I don't want to rewrite the error managamenet # So add an error and if it's still the last (meaning there were no error) one remove it possible_error = Glaeml::Error.new(term.line, ">> Macro backtrace : #{term.macro.name}") @mode.errors << possible_error # First, test if variable is pushable arg_values = [] term.macro.arg_names.each_with_index { |arg_name, i| var_value = nil if @vars[arg_name] @mode.errors << Glaeml::Error.new(term.line, "Local variable #{arg_name} hinders a variable with the same name in this context. Use only local variable names in macros!") else # Evaluate local var var_value_ex = term.arg_value_expressions[i] var_value = apply_vars(term.line, var_value_ex, true) if !var_value @mode.errors << Glaeml::Error.new(term.line, "Thus, variable {#{arg_name}} could not be declared.") end end arg_values << {name: arg_name, val: var_value} } # We push local vars after the whole loop to avoid interferences between them when evaluating them arg_values.each { |v| if v[:val] add_var(v[:name],v[:val],false) end } descend_if_tree(term.macro.root_code_block, ) # Remove the local vars from the scope (only if they were leggit) arg_values.each { |v| if v[:val] @vars[v[:name]] = nil end } if mode.errors.last == possible_error # Remove the error scope if there were no errors mode.errors.pop else # Add another one to close the context @mode.errors << Glaeml::Error.new(term.line, "<< Macro backtrace : #{term.macro.name}") end else term.if_conds.each{ |if_cond| if_eval = Eval::Parser.new() begin if(if_eval.parse(if_cond.expression,) == true) descend_if_tree(if_cond.child_code_block, ) break end rescue Eval::IfEvalError => e @mode.errors << Glaeml::Error.new(if_cond.line, "Failed to evaluate condition '#{if_cond.expression}' (#{e})") end } end } end |
#finalize(trans_options) ⇒ Object
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/api/rule_group.rb', line 268 def finalize() @vars = {} @in_charset = {} @rules = [] add_var("NULL","",false) # Characters that are not easily entered or visible in a text editor add_var("NBSP", "{UNI_A0}", false) add_var("WJ", "{UNI_2060}", false) add_var("ZWSP", "{UNI_200B}", false) add_var("ZWNJ", "{UNI_200C}", false) # The following characters are used by the mode syntax. # Redefine some convenient tools. add_var("UNDERSCORE", "{UNI_5F}", false) add_var("ASTERISK", "{UNI_2A}", false) add_var("COMMA", "{UNI_2C}", false) add_var("LPAREN", "{UNI_28}", false) add_var("RPAREN", "{UNI_29}", false) add_var("LBRACKET", "{UNI_5B}", false) add_var("RBRACKET", "{UNI_5D}", false) descend_if_tree(@root_code_block, ) # Now that we have selected our rules, create the in_charset of the rule_group rules.each{ |r| r.sub_rules.each { |sr| sr.src_combination.join("").split(//).each{ |inchar| # Add the character to the map of input characters # Ignore '\u0000' (bounds of word) and '|' (word breaker) @in_charset[inchar] = self if inchar != WORD_BREAKER && inchar != WORD_BOUNDARY_TREE } } } end |
#finalize_code_line(code_line) ⇒ Object
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/api/rule_group.rb', line 207 def finalize_code_line(code_line) begin if code_line.expression =~ VAR_DECL_REGEXP var_name = $1 var_value_ex = $2 var_value = apply_vars(code_line.line, var_value_ex, true) if !var_value @mode.errors << Glaeml::Error.new(code_line.line, "Thus, variable {#{var_name}} could not be declared.") return end add_var(var_name, var_value, false) elsif code_line.expression =~ POINTER_VAR_DECL_REGEXP var_name = $1 var_value_ex = $2 add_var(var_name, var_value_ex, true) elsif code_line.expression =~ CROSS_RULE_REGEXP match = $1 cross = $2 var_name = $4 replacement = $5 if var_name # This was a variable declaration var_value = apply_vars(code_line.line, cross, false) if !var_value @mode.errors << Glaeml::Error.new(code_line.line, "Thus, variable {#{var_name}} could not be declared.") return end cross = var_value end if cross == "identity" cross = nil end finalize_rule(code_line.line, match, replacement, cross) elsif code_line.expression =~ RULE_REGEXP match = $1 replacement = $2 finalize_rule(code_line.line, match, replacement) elsif code_line.expression.empty? # puts "Empty" else @mode.errors << Glaeml::Error.new(code_line.line,"Cannot understand: #{code_line.expression}") end end end |
#finalize_rule(line, match_exp, replacement_exp, cross_schema = nil) ⇒ Object
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/api/rule_group.rb', line 191 def finalize_rule(line, match_exp, replacement_exp, cross_schema = nil) match = apply_vars(line, match_exp, true) replacement = apply_vars(line, replacement_exp, false) return if !match || !replacement # Failed rule = Rule.new(line, self) rule.src_sheaf_chain = SheafChain.new(rule,match,true) rule.dst_sheaf_chain = SheafChain.new(rule,replacement,false) rule.finalize(cross_schema) self.rules << rule end |