Rename project mm2ep_depend to namarara
This commit is contained in:
parent
e0498abb05
commit
c6c2e90e7f
25 changed files with 402 additions and 414 deletions
|
@ -11,7 +11,7 @@ require: rubocop-rspec
|
|||
# Allow bigger test cases ('examples')
|
||||
RSpec/ExampleLength:
|
||||
Enabled: true
|
||||
Max: 8
|
||||
Max: 10
|
||||
|
||||
Metrics/BlockLength:
|
||||
Enabled: false
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -2,5 +2,5 @@ source "https://rubygems.org"
|
|||
|
||||
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
||||
|
||||
# Specify your gem's dependencies in mm2ep_depend.gemspec
|
||||
# Specify your gem's dependencies in namarara.gemspec
|
||||
gemspec
|
||||
|
|
13
README.md
13
README.md
|
@ -16,7 +16,7 @@ and computes a boolean result from this AST.
|
|||
Add this line to your application's Gemfile:
|
||||
|
||||
```ruby
|
||||
gem 'mm2ep_depend'
|
||||
gem 'namarara'
|
||||
```
|
||||
|
||||
And then execute:
|
||||
|
@ -25,7 +25,7 @@ And then execute:
|
|||
|
||||
Or install it yourself as:
|
||||
|
||||
$ gem install mm2ep_depend
|
||||
$ gem install namarara
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -33,7 +33,7 @@ Or install it yourself as:
|
|||
|
||||
```
|
||||
# Initialize Namarara
|
||||
namarara = Namarara.new
|
||||
namarara = Namarara::Parser.new(Namarara::Lexer.new)
|
||||
|
||||
# Build the binary expression tree (BET)
|
||||
namarara_bet = namarara.parse('this AND (that OR other) AND something_else')
|
||||
|
@ -58,7 +58,7 @@ namarara = Namarara::Parser.new(Namarara::Lexer.new)
|
|||
|
||||
# A set of rules i want to check
|
||||
rules = [
|
||||
{name: 'vulnetable_person', expr: 'is_adult AND is_subordinate'},
|
||||
{name: 'vulnerable_person', expr: 'is_adult AND is_subordinate'},
|
||||
{name: 'has_constraints', expr: 'is_adult AND has_children' },
|
||||
{name: 'is_child', expr: 'NOT is_adult'}
|
||||
# ...
|
||||
|
@ -86,8 +86,7 @@ puts warnings.join("\n")
|
|||
else
|
||||
puts "Rien à dire :-)"
|
||||
end
|
||||
|
||||
TODO: Write usage instructions here
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
|
@ -97,7 +96,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|||
|
||||
## Contributing
|
||||
|
||||
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/mm2ep_depend.
|
||||
Bug reports and pull requests are welcome on GitHub at https://github.com/glenux/namarara
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require "bundler/setup"
|
||||
require "mm2ep_depend"
|
||||
require "namarara"
|
||||
|
||||
# You can add fixtures and/or initialization code here to make experimenting
|
||||
# with your gem easier. You can also use a different console, if you like.
|
||||
|
|
4
demo.rb
4
demo.rb
|
@ -1,9 +1,9 @@
|
|||
|
||||
$:.insert(0, 'lib')
|
||||
require 'mm2ep_depend'
|
||||
require 'namarara'
|
||||
|
||||
def verify_input
|
||||
parser = Mm2ep::Depend::Parser.new(Mm2ep::Depend::Lexer.new)
|
||||
parser = Namarara::Parser.new(Namarara::Lexer.new)
|
||||
|
||||
# on démarre avec zéro alertes
|
||||
warnings = []
|
||||
|
|
|
@ -5,45 +5,42 @@ $:.insert(0, 'lib')
|
|||
require 'thor'
|
||||
require 'rly'
|
||||
require 'pry'
|
||||
require 'mm2ep_depend'
|
||||
require 'namarara'
|
||||
require 'pp'
|
||||
require 'logger'
|
||||
|
||||
module Mm2ep
|
||||
module Depend
|
||||
|
||||
class ParseCli < Thor
|
||||
desc 'parse OPTIONS INFILE VARS', 'Parse INFILE into tokens and evaluate VARS'
|
||||
method_option :logfile, :type => :string, :aliases => '-l', :default => '-', :desc => "Logger with logfile"
|
||||
def parse(infile, *vars)
|
||||
unless options[:logfile].eql? '-'
|
||||
logger = Logger.new("#{options[:logfile]}.log")
|
||||
else
|
||||
logger = Logger.new(STDOUT)
|
||||
end
|
||||
line = File.read(infile).gsub(/\n/,'')
|
||||
lexer = Lexer.new(logger)
|
||||
parser = Parser.new(lexer)
|
||||
tab_vars = {}
|
||||
vars.each do |var|
|
||||
tab_vars[var.split('=')[0]] = var.split('=')[1]
|
||||
end
|
||||
|
||||
# Give vars name and value from shell command to parser
|
||||
parser.names=tab_vars
|
||||
|
||||
token = parser.parse(line.chomp, true)
|
||||
pp token
|
||||
puts "RAW : #{line}"
|
||||
puts "EVAL: #{token.to_s}"
|
||||
parser.check_grammar line, token
|
||||
exit 1 unless !token.nil? && token.errors.empty?
|
||||
|
||||
puts "RESULT: #{token.compute}"
|
||||
|
||||
module Namarara
|
||||
class ParseCli < Thor
|
||||
desc 'parse OPTIONS INFILE VARS', 'Parse INFILE into tokens and evaluate VARS'
|
||||
method_option :logfile, :type => :string, :aliases => '-l', :default => '-', :desc => "Logger with logfile"
|
||||
def parse(infile, *vars)
|
||||
unless options[:logfile].eql? '-'
|
||||
logger = Logger.new("#{options[:logfile]}.log")
|
||||
else
|
||||
logger = Logger.new(STDOUT)
|
||||
end
|
||||
line = File.read(infile).gsub(/\n/,'')
|
||||
lexer = Lexer.new(logger)
|
||||
parser = Parser.new(lexer)
|
||||
tab_vars = {}
|
||||
vars.each do |var|
|
||||
tab_vars[var.split('=')[0]] = var.split('=')[1]
|
||||
end
|
||||
|
||||
# Give vars name and value from shell command to parser
|
||||
parser.names=tab_vars
|
||||
|
||||
token = parser.parse(line.chomp, true)
|
||||
pp token
|
||||
puts "RAW : #{line}"
|
||||
puts "EVAL: #{token.to_s}"
|
||||
parser.check_grammar line, token
|
||||
exit 1 unless !token.nil? && token.errors.empty?
|
||||
|
||||
puts "RESULT: #{token.compute}"
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Mm2ep::Depend::ParseCli.start(ARGV)
|
||||
Namarara::ParseCli.start(ARGV)
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
module Mm2ep
|
||||
module Depend
|
||||
class InvalidGrammar < Depend::EvalError
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,6 +0,0 @@
|
|||
module Mm2ep
|
||||
module Depend
|
||||
class VarNotDefined < Depend::EvalError
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
require 'mm2ep_depend/version'
|
||||
|
||||
module Mm2epDepend
|
||||
# Your code goes here...
|
||||
end
|
||||
|
||||
require 'rly'
|
||||
|
||||
require 'mm2ep_depend/lexer'
|
||||
require 'mm2ep_depend/parser'
|
||||
require 'mm2ep_depend/eval_error'
|
||||
require 'errors/var_not_defined'
|
||||
require 'errors/invalid_grammar'
|
|
@ -1,17 +0,0 @@
|
|||
module Mm2ep
|
||||
module Depend
|
||||
class EvalError
|
||||
attr_accessor :var
|
||||
attr_accessor :message
|
||||
|
||||
def initialize(hash)
|
||||
# validate input
|
||||
raise ArgumentError unless hash[:message]
|
||||
|
||||
# load input
|
||||
@message = hash[:message]
|
||||
@var = hash[:var]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,39 +0,0 @@
|
|||
module Mm2ep
|
||||
module Depend
|
||||
class Lexer < Rly::Lex
|
||||
attr_reader :logger
|
||||
|
||||
ignore "\t\n "
|
||||
|
||||
# token :SPACE, /\s+/
|
||||
token :L_PAR, /\(/
|
||||
token :R_PAR, /\)/
|
||||
token :NUMBER, /[0-9]+(\.[0-9]+)?/
|
||||
token :STRING, /"([^"]*)"/ do |s|
|
||||
s.value.gsub!(/"(.*)"/, '\1')
|
||||
s
|
||||
end
|
||||
|
||||
token :EQ_OP, /\=/
|
||||
token :T_BOOL, /true/i
|
||||
token :F_BOOL, /false/i
|
||||
token :VAR, /[a-z][a-zA-Z0-9_]+/
|
||||
token :AND_OP, /AND/
|
||||
token :OR_OP, /OR/
|
||||
token :NOT_OP, /NOT/
|
||||
|
||||
def initialize(logger = nil)
|
||||
@logger = logger
|
||||
super()
|
||||
end
|
||||
|
||||
on_error do |t|
|
||||
unless t.lexer.logger.nil?
|
||||
t.lexer.logger.error "Illegal character #{t.value}"
|
||||
end
|
||||
t.lexer.pos += 1
|
||||
nil
|
||||
end
|
||||
end # class
|
||||
end # module
|
||||
end # module
|
|
@ -1,258 +0,0 @@
|
|||
module Mm2ep
|
||||
module Depend
|
||||
class TreeExpr
|
||||
def compute
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
|
||||
class TreeValue
|
||||
attr_reader :value
|
||||
|
||||
def to_s
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
|
||||
class VarValue < TreeValue
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(str, value)
|
||||
@errors = []
|
||||
@name = str
|
||||
@value = value
|
||||
@value = true if value =~ /^true$/i
|
||||
@value = false if value =~ /^false$/i
|
||||
return unless @value.nil?
|
||||
@errors << VarNotDefined.new(
|
||||
message: "No value for #{@name}",
|
||||
var: @name
|
||||
)
|
||||
end
|
||||
|
||||
def compute
|
||||
@value
|
||||
end
|
||||
|
||||
def to_s
|
||||
"var:#{@name}<-(#{@value})"
|
||||
end
|
||||
end
|
||||
|
||||
class NumberValue < TreeValue
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(str)
|
||||
@errors = []
|
||||
@value = str
|
||||
end
|
||||
|
||||
def compute
|
||||
@value
|
||||
end
|
||||
|
||||
def to_s
|
||||
"number:#{@value}"
|
||||
end
|
||||
end
|
||||
|
||||
class StringValue < TreeValue
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(str)
|
||||
@errors = []
|
||||
@value = str
|
||||
end
|
||||
|
||||
def compute
|
||||
@value
|
||||
end
|
||||
|
||||
def to_s
|
||||
"string:\"#{@value}\""
|
||||
end
|
||||
end
|
||||
|
||||
class BoolValue < TreeValue
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(str)
|
||||
@errors = []
|
||||
@value = case str
|
||||
when /true/i then true
|
||||
when /false/i then false
|
||||
end
|
||||
end
|
||||
|
||||
def compute
|
||||
@value
|
||||
end
|
||||
|
||||
def to_s
|
||||
"bool:#{@value}"
|
||||
end
|
||||
end
|
||||
|
||||
class AndOp < TreeExpr
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(lval, rval)
|
||||
@errors = []
|
||||
@errors.concat lval.errors
|
||||
@errors.concat rval.errors
|
||||
@lval = lval
|
||||
@rval = rval
|
||||
end
|
||||
|
||||
def compute
|
||||
@lval.compute && @rval.compute
|
||||
end
|
||||
|
||||
def to_s
|
||||
"( #{@lval} ) AND ( #{@rval} )"
|
||||
end
|
||||
end
|
||||
|
||||
class OrOp
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(lval, rval)
|
||||
@errors = []
|
||||
@errors.concat lval.errors
|
||||
@errors.concat rval.errors
|
||||
@lval = lval
|
||||
@rval = rval
|
||||
end
|
||||
|
||||
def compute
|
||||
@lval.compute || @rval.compute
|
||||
end
|
||||
|
||||
def to_s
|
||||
"( #{@lval} ) OR ( #{@rval} )"
|
||||
end
|
||||
end
|
||||
|
||||
class NotOp
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(expr)
|
||||
@errors = []
|
||||
@errors.concat expr.errors
|
||||
@expr = expr
|
||||
end
|
||||
|
||||
def compute
|
||||
!@expr.compute
|
||||
end
|
||||
|
||||
def to_s
|
||||
"NOT ( #{@expr} )"
|
||||
end
|
||||
end
|
||||
|
||||
class EqOp
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(lval, rval)
|
||||
@errors = []
|
||||
@errors.concat lval.errors
|
||||
@errors.concat rval.errors
|
||||
@lval = lval
|
||||
@rval = rval
|
||||
end
|
||||
|
||||
def compute
|
||||
@lval.value == @rval.value
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{@lval} = #{@rval}"
|
||||
end
|
||||
end
|
||||
|
||||
# Cut HERE
|
||||
# 8< ---- 8< ---- ...
|
||||
|
||||
class Parser < Rly::Yacc
|
||||
attr_writer :names
|
||||
|
||||
# Check if grammar is valid
|
||||
def check_grammar(line, tokens)
|
||||
grammar = tokens.to_s.split(/=|AND|OR/)
|
||||
expr = line.split(/=|AND|OR/)
|
||||
return if grammar.size == expr.size
|
||||
return if grammar.empty?
|
||||
tokens.errors << InvalidGrammar.new(
|
||||
message: 'Invalid Grammar'
|
||||
)
|
||||
end
|
||||
|
||||
precedence :left, :OR_OP
|
||||
precedence :left, :AND_OP
|
||||
precedence :left, :EQ_OP
|
||||
precedence :right, :L_PAR, :R_PAR
|
||||
precedence :right, :UMINUS
|
||||
|
||||
rule 'statement : expr' do |st, e|
|
||||
st.value = e.value
|
||||
end
|
||||
|
||||
rule 'expr : VAR' do |ex, l|
|
||||
ex.value = EqOp.new(
|
||||
VarValue.new(l.value, @names[l.value]),
|
||||
BoolValue.new('true')
|
||||
)
|
||||
end
|
||||
|
||||
rule 'bool_expr : F_BOOL' do |ex, l|
|
||||
ex.value = l.value
|
||||
end
|
||||
|
||||
rule 'bool_expr : T_BOOL' do |ex, l|
|
||||
ex.value = l.value
|
||||
end
|
||||
|
||||
rule 'expr : bool_expr' do |ex, l|
|
||||
ex.value = BoolValue.new(l.value.to_s)
|
||||
end
|
||||
|
||||
rule 'expr : expr OR_OP expr' do |ex, l, _e, r|
|
||||
ex.value = OrOp.new(l.value, r.value)
|
||||
end
|
||||
|
||||
rule 'expr : expr AND_OP expr' do |ex, l, _e, r|
|
||||
ex.value = AndOp.new(l.value, r.value)
|
||||
end
|
||||
|
||||
rule 'expr : L_PAR expr R_PAR' do |ex, _l, e, _r|
|
||||
ex.value = e.value
|
||||
end
|
||||
|
||||
rule 'expr : NOT_OP expr %prec UMINUS' do |ex, _l, e|
|
||||
ex.value = NotOp.new(e.value)
|
||||
end
|
||||
|
||||
rule 'expr : VAR EQ_OP bool_expr' do |ex, v, _eq, n|
|
||||
ex.value = EqOp.new(
|
||||
VarValue.new(v.value.to_s, @names[v.value]),
|
||||
BoolValue.new(n.value)
|
||||
)
|
||||
end
|
||||
|
||||
rule 'expr : VAR EQ_OP STRING' do |ex, v, _eq, n|
|
||||
ex.value = EqOp.new(
|
||||
VarValue.new(v.value.to_s, @names[v.value]),
|
||||
StringValue.new(n.value)
|
||||
)
|
||||
end
|
||||
|
||||
rule 'expr : VAR EQ_OP NUMBER' do |ex, v, _eq, n|
|
||||
ex.value = EqOp.new(
|
||||
VarValue.new(v.value.to_s, @names[v.value]),
|
||||
NumberValue.new(n.value)
|
||||
)
|
||||
end
|
||||
end # class
|
||||
end # module
|
||||
end # module
|
11
lib/namarara.rb
Normal file
11
lib/namarara.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
require 'namarara/version'
|
||||
|
||||
module Namarara; end
|
||||
|
||||
require 'rly'
|
||||
|
||||
require 'namarara/lexer'
|
||||
require 'namarara/parser'
|
||||
require 'namarara/eval_error'
|
||||
require 'namarara/errors/var_not_defined'
|
||||
require 'namarara/errors/invalid_grammar'
|
6
lib/namarara/errors/invalid_grammar.rb
Normal file
6
lib/namarara/errors/invalid_grammar.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
module Namarara
|
||||
module Errors
|
||||
class InvalidGrammar < EvalError
|
||||
end
|
||||
end
|
||||
end
|
6
lib/namarara/errors/var_not_defined.rb
Normal file
6
lib/namarara/errors/var_not_defined.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
module Namarara
|
||||
module Errors
|
||||
class VarNotDefined < EvalError
|
||||
end
|
||||
end
|
||||
end
|
15
lib/namarara/eval_error.rb
Normal file
15
lib/namarara/eval_error.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
module Namarara
|
||||
class EvalError
|
||||
attr_accessor :var
|
||||
attr_accessor :message
|
||||
|
||||
def initialize(hash)
|
||||
# validate input
|
||||
raise ArgumentError unless hash[:message]
|
||||
|
||||
# load input
|
||||
@message = hash[:message]
|
||||
@var = hash[:var]
|
||||
end
|
||||
end
|
||||
end
|
37
lib/namarara/lexer.rb
Executable file
37
lib/namarara/lexer.rb
Executable file
|
@ -0,0 +1,37 @@
|
|||
module Namarara
|
||||
class Lexer < Rly::Lex
|
||||
attr_reader :logger
|
||||
|
||||
ignore "\t\n "
|
||||
|
||||
# token :SPACE, /\s+/
|
||||
token :L_PAR, /\(/
|
||||
token :R_PAR, /\)/
|
||||
token :NUMBER, /[0-9]+(\.[0-9]+)?/
|
||||
token :STRING, /"([^"]*)"/ do |s|
|
||||
s.value.gsub!(/"(.*)"/, '\1')
|
||||
s
|
||||
end
|
||||
|
||||
token :EQ_OP, /\=/
|
||||
token :T_BOOL, /true/i
|
||||
token :F_BOOL, /false/i
|
||||
token :VAR, /[a-z][a-zA-Z0-9_]+/
|
||||
token :AND_OP, /AND/
|
||||
token :OR_OP, /OR/
|
||||
token :NOT_OP, /NOT/
|
||||
|
||||
def initialize(logger = nil)
|
||||
@logger = logger
|
||||
super()
|
||||
end
|
||||
|
||||
on_error do |t|
|
||||
unless t.lexer.logger.nil?
|
||||
t.lexer.logger.error "Illegal character #{t.value}"
|
||||
end
|
||||
t.lexer.pos += 1
|
||||
nil
|
||||
end
|
||||
end # class
|
||||
end # module
|
256
lib/namarara/parser.rb
Executable file
256
lib/namarara/parser.rb
Executable file
|
@ -0,0 +1,256 @@
|
|||
module Namarara
|
||||
class TreeExpr
|
||||
def compute
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
|
||||
class TreeValue
|
||||
attr_reader :value
|
||||
|
||||
def to_s
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
|
||||
class VarValue < TreeValue
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(str, value)
|
||||
@errors = []
|
||||
@name = str
|
||||
@value = value
|
||||
@value = true if value =~ /^true$/i
|
||||
@value = false if value =~ /^false$/i
|
||||
return unless @value.nil?
|
||||
@errors << Errors::VarNotDefined.new(
|
||||
message: "No value for #{@name}",
|
||||
var: @name
|
||||
)
|
||||
end
|
||||
|
||||
def compute
|
||||
@value
|
||||
end
|
||||
|
||||
def to_s
|
||||
"var:#{@name}<-(#{@value})"
|
||||
end
|
||||
end
|
||||
|
||||
class NumberValue < TreeValue
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(str)
|
||||
@errors = []
|
||||
@value = str
|
||||
end
|
||||
|
||||
def compute
|
||||
@value
|
||||
end
|
||||
|
||||
def to_s
|
||||
"number:#{@value}"
|
||||
end
|
||||
end
|
||||
|
||||
class StringValue < TreeValue
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(str)
|
||||
@errors = []
|
||||
@value = str
|
||||
end
|
||||
|
||||
def compute
|
||||
@value
|
||||
end
|
||||
|
||||
def to_s
|
||||
"string:\"#{@value}\""
|
||||
end
|
||||
end
|
||||
|
||||
class BoolValue < TreeValue
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(str)
|
||||
@errors = []
|
||||
@value = case str
|
||||
when /true/i then true
|
||||
when /false/i then false
|
||||
end
|
||||
end
|
||||
|
||||
def compute
|
||||
@value
|
||||
end
|
||||
|
||||
def to_s
|
||||
"bool:#{@value}"
|
||||
end
|
||||
end
|
||||
|
||||
class AndOp < TreeExpr
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(lval, rval)
|
||||
@errors = []
|
||||
@errors.concat lval.errors
|
||||
@errors.concat rval.errors
|
||||
@lval = lval
|
||||
@rval = rval
|
||||
end
|
||||
|
||||
def compute
|
||||
@lval.compute && @rval.compute
|
||||
end
|
||||
|
||||
def to_s
|
||||
"( #{@lval} ) AND ( #{@rval} )"
|
||||
end
|
||||
end
|
||||
|
||||
class OrOp
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(lval, rval)
|
||||
@errors = []
|
||||
@errors.concat lval.errors
|
||||
@errors.concat rval.errors
|
||||
@lval = lval
|
||||
@rval = rval
|
||||
end
|
||||
|
||||
def compute
|
||||
@lval.compute || @rval.compute
|
||||
end
|
||||
|
||||
def to_s
|
||||
"( #{@lval} ) OR ( #{@rval} )"
|
||||
end
|
||||
end
|
||||
|
||||
class NotOp
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(expr)
|
||||
@errors = []
|
||||
@errors.concat expr.errors
|
||||
@expr = expr
|
||||
end
|
||||
|
||||
def compute
|
||||
!@expr.compute
|
||||
end
|
||||
|
||||
def to_s
|
||||
"NOT ( #{@expr} )"
|
||||
end
|
||||
end
|
||||
|
||||
class EqOp
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(lval, rval)
|
||||
@errors = []
|
||||
@errors.concat lval.errors
|
||||
@errors.concat rval.errors
|
||||
@lval = lval
|
||||
@rval = rval
|
||||
end
|
||||
|
||||
def compute
|
||||
@lval.value == @rval.value
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{@lval} = #{@rval}"
|
||||
end
|
||||
end
|
||||
|
||||
# Cut HERE
|
||||
# 8< ---- 8< ---- ...
|
||||
|
||||
class Parser < Rly::Yacc
|
||||
attr_writer :names
|
||||
|
||||
# Check if grammar is valid
|
||||
def check_grammar(line, tokens)
|
||||
grammar = tokens.to_s.split(/=|AND|OR/)
|
||||
expr = line.split(/=|AND|OR/)
|
||||
return if grammar.size == expr.size
|
||||
return if grammar.empty?
|
||||
tokens.errors << Errors::InvalidGrammar.new(
|
||||
message: 'Invalid Grammar'
|
||||
)
|
||||
end
|
||||
|
||||
precedence :left, :OR_OP
|
||||
precedence :left, :AND_OP
|
||||
precedence :left, :EQ_OP
|
||||
precedence :right, :L_PAR, :R_PAR
|
||||
precedence :right, :UMINUS
|
||||
|
||||
rule 'statement : expr' do |st, e|
|
||||
st.value = e.value
|
||||
end
|
||||
|
||||
rule 'expr : VAR' do |ex, l|
|
||||
ex.value = EqOp.new(
|
||||
VarValue.new(l.value, @names[l.value]),
|
||||
BoolValue.new('true')
|
||||
)
|
||||
end
|
||||
|
||||
rule 'bool_expr : F_BOOL' do |ex, l|
|
||||
ex.value = l.value
|
||||
end
|
||||
|
||||
rule 'bool_expr : T_BOOL' do |ex, l|
|
||||
ex.value = l.value
|
||||
end
|
||||
|
||||
rule 'expr : bool_expr' do |ex, l|
|
||||
ex.value = BoolValue.new(l.value.to_s)
|
||||
end
|
||||
|
||||
rule 'expr : expr OR_OP expr' do |ex, l, _e, r|
|
||||
ex.value = OrOp.new(l.value, r.value)
|
||||
end
|
||||
|
||||
rule 'expr : expr AND_OP expr' do |ex, l, _e, r|
|
||||
ex.value = AndOp.new(l.value, r.value)
|
||||
end
|
||||
|
||||
rule 'expr : L_PAR expr R_PAR' do |ex, _l, e, _r|
|
||||
ex.value = e.value
|
||||
end
|
||||
|
||||
rule 'expr : NOT_OP expr %prec UMINUS' do |ex, _l, e|
|
||||
ex.value = NotOp.new(e.value)
|
||||
end
|
||||
|
||||
rule 'expr : VAR EQ_OP bool_expr' do |ex, v, _eq, n|
|
||||
ex.value = EqOp.new(
|
||||
VarValue.new(v.value.to_s, @names[v.value]),
|
||||
BoolValue.new(n.value)
|
||||
)
|
||||
end
|
||||
|
||||
rule 'expr : VAR EQ_OP STRING' do |ex, v, _eq, n|
|
||||
ex.value = EqOp.new(
|
||||
VarValue.new(v.value.to_s, @names[v.value]),
|
||||
StringValue.new(n.value)
|
||||
)
|
||||
end
|
||||
|
||||
rule 'expr : VAR EQ_OP NUMBER' do |ex, v, _eq, n|
|
||||
ex.value = EqOp.new(
|
||||
VarValue.new(v.value.to_s, @names[v.value]),
|
||||
NumberValue.new(n.value)
|
||||
)
|
||||
end
|
||||
end # class
|
||||
end # module
|
|
@ -1,3 +1,3 @@
|
|||
module Mm2epDepend
|
||||
module Namarara
|
||||
VERSION = '0.9.4'.freeze
|
||||
end
|
|
@ -1,16 +1,16 @@
|
|||
# coding: utf-8
|
||||
lib = File.expand_path("../lib", __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'mm2ep_depend/version'
|
||||
require 'namarara/version'
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = 'mm2ep_depend'
|
||||
spec.version = Mm2epDepend::VERSION
|
||||
spec.authors = ['Roguelearg']
|
||||
spec.email = ["torre.brendon@gmail.com"]
|
||||
spec.name = 'namarara'
|
||||
spec.version = Namarara::VERSION
|
||||
spec.authors = ['Brendon Torre', 'Glenn Y. Rolland']
|
||||
spec.email = ['glenux@glenux.net']
|
||||
|
||||
spec.summary = %q{A library and tools for expressions}
|
||||
spec.description = %q{A library and tools for expressions}
|
||||
spec.summary = %q{A library and tools for parsing boolean expressions}
|
||||
spec.description = %q{A library and tools for parsing boolean expressions}
|
||||
spec.homepage = 'https://datatransition.net'
|
||||
spec.license = 'MIT'
|
||||
|
||||
|
@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
|
|||
spec.add_development_dependency "bundler", "~> 1.15"
|
||||
spec.add_development_dependency "rake", "~> 10.0"
|
||||
spec.add_development_dependency "minitest", "~> 5.0"
|
||||
spec.add_development_dependency "opal"
|
||||
# spec.add_development_dependency "opal"
|
||||
spec.add_development_dependency "pry"
|
||||
spec.add_development_dependency "rubocop"
|
||||
spec.add_development_dependency "rubocop-rspec"
|
|
@ -1,9 +1,9 @@
|
|||
require 'spec_helper'
|
||||
require 'mm2ep_depend'
|
||||
require 'namarara'
|
||||
|
||||
describe Mm2ep::Depend::Lexer do
|
||||
describe Namarara::Lexer do
|
||||
let(:lexer) do
|
||||
Mm2ep::Depend::Lexer.new
|
||||
Namarara::Lexer.new
|
||||
end
|
||||
|
||||
it 'has to recognize AND operator' do
|
|
@ -1,18 +1,18 @@
|
|||
require 'spec_helper'
|
||||
require 'mm2ep_depend'
|
||||
require 'namarara'
|
||||
|
||||
describe Mm2ep::Depend::Parser do
|
||||
describe Namarara::Parser do
|
||||
let(:parser) do
|
||||
Mm2ep::Depend::Parser.new(
|
||||
Mm2ep::Depend::Lexer.new
|
||||
)
|
||||
Namarara::Parser.new(Namarara::Lexer.new)
|
||||
end
|
||||
|
||||
it 'has to report var which is not defined' do
|
||||
line = 'character = true'
|
||||
parser.names = {}
|
||||
token = parser.parse(line)
|
||||
errors = token.errors.select { |el| el.is_a? Mm2ep::Depend::VarNotDefined }
|
||||
errors = token.errors.select do |el|
|
||||
el.is_a? Namarara::Errors::VarNotDefined
|
||||
end
|
||||
errors.size.must_equal 1
|
||||
errors[0].var.must_equal 'character'
|
||||
end
|
||||
|
@ -21,7 +21,9 @@ describe Mm2ep::Depend::Parser do
|
|||
line = 'a_girl_has_no_name AND character'
|
||||
parser.names = {}
|
||||
token = parser.parse(line)
|
||||
errors = token.errors.select { |el| el.is_a? Mm2ep::Depend::VarNotDefined }
|
||||
errors = token.errors.select do |el|
|
||||
el.is_a? Namarara::Errors::VarNotDefined
|
||||
end
|
||||
errors.size.must_equal 2
|
||||
errors[0].var.must_equal 'a_girl_has_no_name'
|
||||
errors[1].var.must_equal 'character'
|
||||
|
@ -34,7 +36,7 @@ describe Mm2ep::Depend::Parser do
|
|||
token = parser.parse(line)
|
||||
parser.check_grammar line, token
|
||||
token.errors.select do |elem|
|
||||
elem.is_a? Mm2ep::Depend::InvalidGrammar
|
||||
elem.is_a? Namarara::Errors::InvalidGrammar
|
||||
end.size.must_equal 1
|
||||
end
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
require 'spec_helper'
|
||||
require 'mm2ep_depend'
|
||||
require 'namarara'
|
||||
|
||||
describe Mm2ep::Depend::Parser do
|
||||
describe Namarara::Parser do
|
||||
let(:parser) do
|
||||
Mm2ep::Depend::Parser.new(Mm2ep::Depend::Lexer.new)
|
||||
Namarara::Parser.new(Namarara::Lexer.new)
|
||||
end
|
||||
|
||||
it 'has to do not before or' do
|
|
@ -1,11 +1,9 @@
|
|||
require 'spec_helper'
|
||||
require 'mm2ep_depend'
|
||||
require 'namarara'
|
||||
|
||||
describe Mm2ep::Depend::Parser do
|
||||
describe Namarara::Parser do
|
||||
let(:parser) do
|
||||
Mm2ep::Depend::Parser.new(
|
||||
Mm2ep::Depend::Lexer.new
|
||||
)
|
||||
Namarara::Parser.new(Namarara::Lexer.new)
|
||||
end
|
||||
|
||||
it 'has to find var and compute it to expr' do
|
|
@ -1,5 +1,5 @@
|
|||
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
||||
require "mm2ep_depend"
|
||||
require "namarara"
|
||||
|
||||
require "minitest/autorun"
|
||||
require 'pathname'
|
||||
|
|
Loading…
Reference in a new issue