diff --git a/biju.gemspec b/biju.gemspec index a4aa2a4..5798961 100644 --- a/biju.gemspec +++ b/biju.gemspec @@ -18,4 +18,5 @@ Gem::Specification.new do |gem| gem.add_development_dependency "minitest", "3.0.0" gem.add_dependency "serialport", ">=1.0.4" + gem.add_dependency "parslet", "~> 1.5.0" end diff --git a/lib/biju/parser.rb b/lib/biju/parser.rb new file mode 100644 index 0000000..d4210e5 --- /dev/null +++ b/lib/biju/parser.rb @@ -0,0 +1,76 @@ +require 'parslet' +require 'date' + +module Biju + class ATParser < Parslet::Parser + root :at_string + + rule(:at_string) { request | response } + + # REQUEST + rule(:request) { str('+++') | str('A/') | (prefix >> match('[^\r]').repeat) } + rule(:prefix) { str('AT') | str('at') } + + # RESPONSE + rule(:response) { (status | command) >> crlf } + rule(:command) { mgl | pms | mserror } + + rule(:mserror) { str('+CMS ERROR').as(:cmd) >> str(': ') >> message } + rule(:mgl) do + (str('+CMGL').as(:cmd) >> str(': ') >> infos >> crlf >> message).repeat.as(:sms) >> + crlf >> status + end + rule(:pms) do + str('+CPMS').as(:cmd) >> str(': ') >> str('(').maybe >> array >> str(')').maybe + end + + rule(:array) do + (data >> (comma >> data).repeat).as(:array) + end + rule(:data) { (str('(') >> array >> str(')')) | info } + rule(:infos) { (info >> (comma >> info).repeat).as(:infos) } + rule(:info) { datetime | string | int | empty_string } + rule(:message) { match('[^\r]').repeat.as(:message) >> crlf } + + # MISC + rule(:status) { (ok | error).as(:status) } + rule(:ok) { str('OK').as(:ok) } + rule(:error) { str('ERROR').as(:error) } + + rule(:crlf) { str("\r") } + rule(:comma) { str(',') } + rule(:quote) { str('"') } + + rule(:empty_string) { str('').as(:empty_string) } + rule(:string) { quote >> match('[^\"]').repeat.as(:string) >> quote } + rule(:int) { match('[0-9]').repeat(1).as(:int) } + + rule(:datetime) { quote >> (date >> str(',') >> time).as(:datetime) >> quote } + rule(:date) do + (match('[0-9]').repeat(2) >> str('/')).repeat(2) >> match('[0-9]').repeat(2) + end + rule(:time) do + (match('[0-9]').repeat(2) >> str(':')).repeat(2) >> match('[0-9]').repeat(2) >> + str('+') >> match('[0-9]').repeat(2) + end + end + + class ATTransform < Parslet::Transform + rule(cmd: simple(:cmd), infos: subtree(:infos), message: simple(:message)) do + {cmd: cmd.to_s, infos: infos, message: message.to_s} + end + rule(cmd: simple(:cmd), array: subtree(:array)) do + {cmd: cmd.to_s, array: array} + end + + rule(empty_string: simple(:empty_string)) { '' } + rule(int: simple(:int)) { int.to_i } + rule(string: simple(:string)) { string.to_s } + rule(datetime: simple(:datetime)) { DateTime.strptime(datetime.to_s, "%y/%m/%d,%T") } + rule(array: subtree(:array)) { array } + + rule(status: simple(:status)) { { status: status } } + rule(ok: simple(:ok)) { true } + rule(error: simple(:error)) { false } + end +end