diff options
Diffstat (limited to 'lib/IRC/Client')
-rw-r--r-- | lib/IRC/Client/Grammar.pm6 | 21 | ||||
-rw-r--r-- | lib/IRC/Client/Grammar/Actions.pm6 | 119 | ||||
-rw-r--r-- | lib/IRC/Client/Message.pm6 | 70 | ||||
-rw-r--r-- | lib/IRC/Client/Plugin.pm6 | 3 | ||||
-rw-r--r-- | lib/IRC/Client/Plugin/Debugger.pm6 | 8 | ||||
-rw-r--r-- | lib/IRC/Client/Plugin/PingPong.pm6 | 2 |
6 files changed, 210 insertions, 13 deletions
diff --git a/lib/IRC/Client/Grammar.pm6 b/lib/IRC/Client/Grammar.pm6 new file mode 100644 index 0000000..feec9fd --- /dev/null +++ b/lib/IRC/Client/Grammar.pm6 @@ -0,0 +1,21 @@ +unit grammar IRC::Client::Grammar; +token TOP { <message>+ <left-overs> } +token left-overs { \N* } +token SPACE { ' '+ } +token message { [':' <prefix> <SPACE> ]? <command> <params> \n } + token prefix { + [ <servername> || <nick> ['!' <user>]? ['@' <host>]? ] + <before <SPACE>> + } + token servername { <host> } + token nick { <letter> [ <letter> | <number> | <special> ]* } + token user { <-[\ \x[0]\r\n]>+? <before [<SPACE> | '@']>} + token host { <-[\s!@]>+ } + token command { <letter>+ | <number>**3 } + token params { <SPACE>* [ ':' <trailing> | <middle> <params> ]? } + token middle { <-[:\ \x[0]\r\n]> <-[\ \x[0]\r\n]>* } + token trailing { <-[\x[0]\r\n]>* } + + token letter { <[a..zA..Z]> } + token number { <[0..9]> } + token special { <[-_\[\]\\`^{}]> } diff --git a/lib/IRC/Client/Grammar/Actions.pm6 b/lib/IRC/Client/Grammar/Actions.pm6 new file mode 100644 index 0000000..b1fcc53 --- /dev/null +++ b/lib/IRC/Client/Grammar/Actions.pm6 @@ -0,0 +1,119 @@ +unit class IRC::Client::Grammar::Actions; + +use IRC::Client::Message; + +has $.irc; +has $.server; + +method TOP ($/) { + $/.make: ( + $<message>».made, + ~( $<left-overs> // '' ), + ); +} + +method message ($match) { + my %args; + my $pref = $match<prefix>; + for qw/nick user host/ { + $pref{$_}.defined or next; + %args<who>{$_} = ~$pref{$_}; + } + %args<who><host> = ~$pref<servername> if $pref<servername>.defined; + + my $p = $match<params>; + loop { + %args<params>.append: ~$p<middle> if $p<middle>.defined; + + if ( $p<trailing>.defined ) { + %args<params>.append: ~$p<trailing>; + last; + } + last unless $p<params>.defined; + $p = $p<params>; + } + + my %msg-args = + command => $match<command>.uc, + args => %args<params>, + host => %args<who><host>//'', + irc => $!irc, + nick => %args<who><nick>//'', + server => $!server, + usermask => ~($match<prefix>//''), + username => %args<who><user>//''; + + my $msg; + given %msg-args<command> { + when /^ <[0..9]>**3 $/ { + $msg = IRC::Client::Message::Numeric.new: |%msg-args; + } + when 'JOIN' { + $msg = IRC::Client::Message::Join.new: + :channel( %args<params>[0] ), + |%msg-args; + } + when 'PART' { + $msg = IRC::Client::Message::Part.new: + :channel( %args<params>[0] ), + |%msg-args; + } + when 'NICK' { + $msg = IRC::Client::Message::Nick.new: + :new-nick( %args<params>[0] ), + |%msg-args; + } + when 'NOTICE' { $msg = msg-notice %args, %msg-args } + when 'MODE' { $msg = msg-mode %args, %msg-args } + when 'PING' { $msg = IRC::Client::Message::Ping.new: |%msg-args } + when 'PRIVMSG' { $msg = msg-privmsg %args, %msg-args } + when 'QUIT' { $msg = IRC::Client::Message::Quit.new: |%msg-args } + default { $msg = IRC::Client::Message::Unknown.new: |%msg-args } + } + + $match.make: $msg; +} + +sub msg-privmsg (%args, %msg-args) { + %args<params>[0] ~~ /^<[#&]>/ + and return IRC::Client::Message::Privmsg::Channel.new: + :channel( %args<params>[0] ), + :text( %args<params>[1] ), + |%msg-args; + + return IRC::Client::Message::Privmsg::Me.new: + :text( %args<params>[1] ), + |%msg-args; +} + +sub msg-notice (%args, %msg-args) { + %args<params>[0] ~~ /^<[#&]>/ + and return IRC::Client::Message::Notice::Channel.new: + :channel( %args<params>[0] ), + :text( %args<params>[1] ), + |%msg-args; + + return IRC::Client::Message::Notice::Me.new: + :text( %args<params>[1] ), + |%msg-args; +} + +sub msg-mode (%args, %msg-args) { + if %args<params>[0] ~~ /^<[#&]>/ { + my @modes; + for %args<params>[1..*-1].join.comb: /\S/ { + state $sign; + /<[+-]>/ and $sign = $_ and next; + @modes.push: $sign => $_; + }; + return IRC::Client::Message::Mode::Channel.new: + :channel( %args<params>[0] ), + :modes( @modes ), + |%msg-args; + } + else { + return IRC::Client::Message::Mode::Me.new: + :modes( %args<params>[1..*-1].join.comb: /<[a..zA..Z]>/ ), + |%msg-args; + } +} diff --git a/lib/IRC/Client/Message.pm6 b/lib/IRC/Client/Message.pm6 new file mode 100644 index 0000000..9559fd1 --- /dev/null +++ b/lib/IRC/Client/Message.pm6 @@ -0,0 +1,70 @@ +unit package IRC::Client::Message; + +role IRC::Client::Message { + has $.irc is required; + has Str:D $.nick is required; + has Str:D $.username is required; + has Str:D $.host is required; + has Str:D $.usermask is required; + has Str:D $.command is required; + has Str:D $.server is required; + has $.args is required; + + method Str { ":$!usermask $!command $!args[]" } +} + +constant M = IRC::Client::Message; + +role Join does M { has $.channel; } +role Mode does M { has @.modes; } +role Mode::Channel does Mode { has $.channel; } +role Mode::Me does Mode { } +role Nick does M { has $.new-nick; } +role Numeric does M { } +role Part does M { has $.channel; } +role Quit does M { } +role Unknown does M { + method Str { "❚⚠❚ :$.usermask $.command $.args[]" } +} + +role Ping does M { + method reply { $.irc.send-cmd: 'PONG', $.args, :$.server; } +} + +role Privmsg does M { + has $.text is rw; + has Bool $.replied is rw = False; + method Str { $.text } +} +role Privmsg::Channel does Privmsg { + has $.channel; + method reply ($text, :$where) { + $.irc.send-cmd: 'PRIVMSG', $where // $.channel, $text, + :$.server, :prefix("$.nick, "); + } +} +role Privmsg::Me does Privmsg { + method reply ($text, :$where) { + $.irc.send-cmd: 'PRIVMSG', $where // $.nick, $text, :$.server; + } +} + +role Notice does M { + has $.text is rw; + has Bool $.replied is rw = False; + method Str { $.text } +} +role Notice::Channel does Notice { + has $.channel; + method reply ($text, :$where) { + $.irc.send-cmd: 'NOTICE', $where // $.channel, $text, + :$.server, :prefix("$.nick, "); + $.replied = True; + } +} +role Notice::Me does Notice { + method reply ($text, :$where) { + $.irc.send-cmd: 'NOTICE', $where // $.nick, $text, :$.server; + $.replied = True; + } +} diff --git a/lib/IRC/Client/Plugin.pm6 b/lib/IRC/Client/Plugin.pm6 deleted file mode 100644 index d73d7bd..0000000 --- a/lib/IRC/Client/Plugin.pm6 +++ /dev/null @@ -1,3 +0,0 @@ -constant IRC_HANDLED = "irc plugin handled \x1"; -constant IRC_NOT_HANDLED = "irc plugin not-handled \x2"; -unit class IRC::Client::Plugin; diff --git a/lib/IRC/Client/Plugin/Debugger.pm6 b/lib/IRC/Client/Plugin/Debugger.pm6 deleted file mode 100644 index 13b1461..0000000 --- a/lib/IRC/Client/Plugin/Debugger.pm6 +++ /dev/null @@ -1,8 +0,0 @@ -use Data::Dump; -use IRC::Client::Plugin; -unit class IRC::Client::Plugin::Debugger is IRC::Client::Plugin; - -method irc-all-events ($irc, $e) { - say Dump $e, :indent(4); - return IRC_NOT_HANDLED; -} diff --git a/lib/IRC/Client/Plugin/PingPong.pm6 b/lib/IRC/Client/Plugin/PingPong.pm6 deleted file mode 100644 index 2651fd6..0000000 --- a/lib/IRC/Client/Plugin/PingPong.pm6 +++ /dev/null @@ -1,2 +0,0 @@ -unit class IRC::Client::Plugin::PingPong; -method irc-ping ($irc, $e) { $irc.ssay("PONG {$irc.nick} $e<params>[0]") } |