Skip to content

Instantly share code, notes, and snippets.

@antonijn
Created August 2, 2017 10:16
Show Gist options
  • Save antonijn/f817b028cfffb76498e14797593d5760 to your computer and use it in GitHub Desktop.
Save antonijn/f817b028cfffb76498e14797593d5760 to your computer and use it in GitHub Desktop.
Perl 6 version of `spt` program (CTokens.pm6 should be in lib dir relative to the main spt file)
use v6;
unit module CTokens;
grammar CTokens::Token is export {
token TOP {
[
<preproc> |
<comment> |
<line-comment> |
<number> |
<operator> |
<word> |
<string-literal> |
<char-literal> |
\s+
]*
}
token preproc { ^^ [ <comment> | \h ]* <directive> [ <-[\\\n]>+ | \\<-[\n]> | \\\n ]* $$ }
token directive { '#' [ <comment> | \h ]* <word> }
token comment { '/*' .*? '*/' }
token line-comment { '//' [ <-[\\\n]>+ | \\<-[\n]> | \\\n ]* $$ }
token number { '.'? \d+ [ <[eEpP]><[+-]> | <[.\w]> ]* }
token operator {
[
'++' | '--' | '&&' | '||' | '->' |
'+=' | '-=' | '*=' | '/=' | '%=' | '^=' | '&=' | '|=' | '~=' | '<<=' | '>>=' |
'==' | '!=' | '>=' | '<=' |
'<<' | '>>' |
'+' | '-' | '*' | '/' | '%' | '^' | '&' | '|' | '!' | '<' | '>' |
'.' | ';' | ':' | '(' | ')' | '{' | '}' | '[' | ']' | ',' | '~' | '='
]
}
token word { <[a..zA..Z_]>+ \w* }
token string-literal { \" [ <-[\\"]>+ | \\<-["]> | \\\"]* \" }
token char-literal { \' [ <-[\\']>+ | \\<-[']> | \\\']* \' }
}
#!/usr/bin/perl6
use strict;
use lib 'lib';
use CTokens;
class ArgFormatter {
# makes a list of argument strings
method TOP($/) {
# keeps track of parenthesis level
my $levels = 0;
# the index after last comma
my $origIdx = 0;
# list of argument strings
my @result = ();
for $/<operator> -> $tok {
if $levels == 0 and $tok eq ',' {
my $len = $tok.from - $origIdx;
my $argStr = $tok.orig.substr($origIdx, $len);
@result.push($argStr);
$origIdx = $tok.to;
} elsif $tok eq '(' {
$levels++;
} elsif $tok eq ')' {
$levels--;
}
}
@result.push($/.orig.substr($origIdx));
make @result;
}
}
my $fmtr = ArgFormatter.new();
for lines() -> $line {
if not $line ~~ /(\t*) (.*?) '(' (.*) ')' (.*)/ {
put $line;
next;
}
my ($indent, $name, $args, $post) = ($0, $1, $2, $3);
print $indent, $name;
# the whitespace that comes before the arguments to align them
my $preArgWS = $indent ~ $name.subst(/./, ' ', :g);
# an attempt to split the arguments into tokens
my $argMatch = CTokens::Token.parse($args, actions => $fmtr);
# revert to simple string split if tokenization fails
my @argv = $argMatch ?? $argMatch.made !! $args.split(',');
print '(', @argv[0].trim;
for @argv[1..*] -> $arg {
print ",\n", $preArgWS, ' ', $arg.trim;
}
put ')', $post;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment