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')
|
# Allow bigger test cases ('examples')
|
||||||
RSpec/ExampleLength:
|
RSpec/ExampleLength:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Max: 8
|
Max: 10
|
||||||
|
|
||||||
Metrics/BlockLength:
|
Metrics/BlockLength:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -2,5 +2,5 @@ source "https://rubygems.org"
|
||||||
|
|
||||||
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
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
|
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:
|
Add this line to your application's Gemfile:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
gem 'mm2ep_depend'
|
gem 'namarara'
|
||||||
```
|
```
|
||||||
|
|
||||||
And then execute:
|
And then execute:
|
||||||
|
@ -25,7 +25,7 @@ And then execute:
|
||||||
|
|
||||||
Or install it yourself as:
|
Or install it yourself as:
|
||||||
|
|
||||||
$ gem install mm2ep_depend
|
$ gem install namarara
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ Or install it yourself as:
|
||||||
|
|
||||||
```
|
```
|
||||||
# Initialize Namarara
|
# Initialize Namarara
|
||||||
namarara = Namarara.new
|
namarara = Namarara::Parser.new(Namarara::Lexer.new)
|
||||||
|
|
||||||
# Build the binary expression tree (BET)
|
# Build the binary expression tree (BET)
|
||||||
namarara_bet = namarara.parse('this AND (that OR other) AND something_else')
|
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
|
# A set of rules i want to check
|
||||||
rules = [
|
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: 'has_constraints', expr: 'is_adult AND has_children' },
|
||||||
{name: 'is_child', expr: 'NOT is_adult'}
|
{name: 'is_child', expr: 'NOT is_adult'}
|
||||||
# ...
|
# ...
|
||||||
|
@ -86,8 +86,7 @@ puts warnings.join("\n")
|
||||||
else
|
else
|
||||||
puts "Rien à dire :-)"
|
puts "Rien à dire :-)"
|
||||||
end
|
end
|
||||||
|
```
|
||||||
TODO: Write usage instructions here
|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
@ -97,7 +96,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
||||||
|
|
||||||
## Contributing
|
## 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
|
## License
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
require "bundler/setup"
|
require "bundler/setup"
|
||||||
require "mm2ep_depend"
|
require "namarara"
|
||||||
|
|
||||||
# You can add fixtures and/or initialization code here to make experimenting
|
# 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.
|
# 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')
|
$:.insert(0, 'lib')
|
||||||
require 'mm2ep_depend'
|
require 'namarara'
|
||||||
|
|
||||||
def verify_input
|
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
|
# on démarre avec zéro alertes
|
||||||
warnings = []
|
warnings = []
|
||||||
|
|
|
@ -5,45 +5,42 @@ $:.insert(0, 'lib')
|
||||||
require 'thor'
|
require 'thor'
|
||||||
require 'rly'
|
require 'rly'
|
||||||
require 'pry'
|
require 'pry'
|
||||||
require 'mm2ep_depend'
|
require 'namarara'
|
||||||
require 'pp'
|
require 'pp'
|
||||||
require 'logger'
|
require 'logger'
|
||||||
|
|
||||||
module Mm2ep
|
module Namarara
|
||||||
module Depend
|
class ParseCli < Thor
|
||||||
|
desc 'parse OPTIONS INFILE VARS', 'Parse INFILE into tokens and evaluate VARS'
|
||||||
class ParseCli < Thor
|
method_option :logfile, :type => :string, :aliases => '-l', :default => '-', :desc => "Logger with logfile"
|
||||||
desc 'parse OPTIONS INFILE VARS', 'Parse INFILE into tokens and evaluate VARS'
|
def parse(infile, *vars)
|
||||||
method_option :logfile, :type => :string, :aliases => '-l', :default => '-', :desc => "Logger with logfile"
|
unless options[:logfile].eql? '-'
|
||||||
def parse(infile, *vars)
|
logger = Logger.new("#{options[:logfile]}.log")
|
||||||
unless options[:logfile].eql? '-'
|
else
|
||||||
logger = Logger.new("#{options[:logfile]}.log")
|
logger = Logger.new(STDOUT)
|
||||||
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
|
||||||
|
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
|
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
|
VERSION = '0.9.4'.freeze
|
||||||
end
|
end
|
|
@ -1,16 +1,16 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
lib = File.expand_path("../lib", __FILE__)
|
lib = File.expand_path("../lib", __FILE__)
|
||||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||||
require 'mm2ep_depend/version'
|
require 'namarara/version'
|
||||||
|
|
||||||
Gem::Specification.new do |spec|
|
Gem::Specification.new do |spec|
|
||||||
spec.name = 'mm2ep_depend'
|
spec.name = 'namarara'
|
||||||
spec.version = Mm2epDepend::VERSION
|
spec.version = Namarara::VERSION
|
||||||
spec.authors = ['Roguelearg']
|
spec.authors = ['Brendon Torre', 'Glenn Y. Rolland']
|
||||||
spec.email = ["torre.brendon@gmail.com"]
|
spec.email = ['glenux@glenux.net']
|
||||||
|
|
||||||
spec.summary = %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 expressions}
|
spec.description = %q{A library and tools for parsing boolean expressions}
|
||||||
spec.homepage = 'https://datatransition.net'
|
spec.homepage = 'https://datatransition.net'
|
||||||
spec.license = 'MIT'
|
spec.license = 'MIT'
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
|
||||||
spec.add_development_dependency "bundler", "~> 1.15"
|
spec.add_development_dependency "bundler", "~> 1.15"
|
||||||
spec.add_development_dependency "rake", "~> 10.0"
|
spec.add_development_dependency "rake", "~> 10.0"
|
||||||
spec.add_development_dependency "minitest", "~> 5.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 "pry"
|
||||||
spec.add_development_dependency "rubocop"
|
spec.add_development_dependency "rubocop"
|
||||||
spec.add_development_dependency "rubocop-rspec"
|
spec.add_development_dependency "rubocop-rspec"
|
|
@ -1,9 +1,9 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
require 'mm2ep_depend'
|
require 'namarara'
|
||||||
|
|
||||||
describe Mm2ep::Depend::Lexer do
|
describe Namarara::Lexer do
|
||||||
let(:lexer) do
|
let(:lexer) do
|
||||||
Mm2ep::Depend::Lexer.new
|
Namarara::Lexer.new
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has to recognize AND operator' do
|
it 'has to recognize AND operator' do
|
|
@ -1,18 +1,18 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
require 'mm2ep_depend'
|
require 'namarara'
|
||||||
|
|
||||||
describe Mm2ep::Depend::Parser do
|
describe Namarara::Parser do
|
||||||
let(:parser) do
|
let(:parser) do
|
||||||
Mm2ep::Depend::Parser.new(
|
Namarara::Parser.new(Namarara::Lexer.new)
|
||||||
Mm2ep::Depend::Lexer.new
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has to report var which is not defined' do
|
it 'has to report var which is not defined' do
|
||||||
line = 'character = true'
|
line = 'character = true'
|
||||||
parser.names = {}
|
parser.names = {}
|
||||||
token = parser.parse(line)
|
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.size.must_equal 1
|
||||||
errors[0].var.must_equal 'character'
|
errors[0].var.must_equal 'character'
|
||||||
end
|
end
|
||||||
|
@ -21,7 +21,9 @@ describe Mm2ep::Depend::Parser do
|
||||||
line = 'a_girl_has_no_name AND character'
|
line = 'a_girl_has_no_name AND character'
|
||||||
parser.names = {}
|
parser.names = {}
|
||||||
token = parser.parse(line)
|
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.size.must_equal 2
|
||||||
errors[0].var.must_equal 'a_girl_has_no_name'
|
errors[0].var.must_equal 'a_girl_has_no_name'
|
||||||
errors[1].var.must_equal 'character'
|
errors[1].var.must_equal 'character'
|
||||||
|
@ -34,7 +36,7 @@ describe Mm2ep::Depend::Parser do
|
||||||
token = parser.parse(line)
|
token = parser.parse(line)
|
||||||
parser.check_grammar line, token
|
parser.check_grammar line, token
|
||||||
token.errors.select do |elem|
|
token.errors.select do |elem|
|
||||||
elem.is_a? Mm2ep::Depend::InvalidGrammar
|
elem.is_a? Namarara::Errors::InvalidGrammar
|
||||||
end.size.must_equal 1
|
end.size.must_equal 1
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
require 'mm2ep_depend'
|
require 'namarara'
|
||||||
|
|
||||||
describe Mm2ep::Depend::Parser do
|
describe Namarara::Parser do
|
||||||
let(:parser) do
|
let(:parser) do
|
||||||
Mm2ep::Depend::Parser.new(Mm2ep::Depend::Lexer.new)
|
Namarara::Parser.new(Namarara::Lexer.new)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has to do not before or' do
|
it 'has to do not before or' do
|
|
@ -1,11 +1,9 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
require 'mm2ep_depend'
|
require 'namarara'
|
||||||
|
|
||||||
describe Mm2ep::Depend::Parser do
|
describe Namarara::Parser do
|
||||||
let(:parser) do
|
let(:parser) do
|
||||||
Mm2ep::Depend::Parser.new(
|
Namarara::Parser.new(Namarara::Lexer.new)
|
||||||
Mm2ep::Depend::Lexer.new
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has to find var and compute it to expr' do
|
it 'has to find var and compute it to expr' do
|
|
@ -1,5 +1,5 @@
|
||||||
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
||||||
require "mm2ep_depend"
|
require "namarara"
|
||||||
|
|
||||||
require "minitest/autorun"
|
require "minitest/autorun"
|
||||||
require 'pathname'
|
require 'pathname'
|
||||||
|
|
Loading…
Reference in a new issue