Skip to content

Commit

Permalink
Rewrite the parsing loop using one single regular expression to match…
Browse files Browse the repository at this point in the history
… all active macros

The object has a stack of current parsers, using the parser at the top of the stack.
This allows different parsers to be used e.g. to match text with macros to be expanded,
and to extract macro parameters from the input text.

The main parser is built around one single regular expression that matches all macros,
scripts and variables and definition statements. This regular expression is extended each time
a new macro/variable/script is defined.

Module not yet fully functional, only %DEFINE_VARIABLE implemented.

New test files prefixed with new_, as all the old test cases will fail until the implementation
is complete.

- Fix #7: expansion depends on size of script name
  The regular expression matches first the longer macros/variables/scripts.

- Fix #2: expand() does not accept a multi-line text
  Allow the multi-line definitions to be split across different input lines, and more than
  one definition on the same line.

- Fix #28: #varname syntax should be accepted in both scripts and macros
  Fix #37: Variables should be expanded in all input text, not only in macro scripts
  Fix #38: Variables with # syntax not parsed by $Macro->define()
  Allow variables to be expanded anywhere in the input by the sequence #VARNAME, and
  not only within scripts.

- Fix #40: Variables should accept expressions and compute them
  Allow perl expressions in the definition of variables, that are computed before storing
  the result in the variable, e.g. "%DEFINE_VARIABLE NAME [uc('#name')]".

- Fix #41: Macro/script arguments do not nest
  Parser of macro arguments counts the number of unescaped '[' and ']' stopping when the
  initial '[' is matched by a corresponding ']', allowing calls like
  "ADD[ADD1[ADD2[ADD3[4]]] | 10])"

- Allow variables to be computed based on their previous value, allowing for example a
  variable to be incremented by "%DEFINE_VARIABLE X [#X+1]".

- Implement escaping of special characters ([ | ] # %) by preceding them with back-slash,
  so that "\#varname" is expanded to "#varname".

- Simplify test scripts
  No need to include Test::Differences in every test script, as it is
  included in mytests.pl

- Update documentation
  • Loading branch information
pauloscustodio committed Jul 5, 2015
1 parent f8d87c1 commit 6a9c739
Show file tree
Hide file tree
Showing 12 changed files with 588 additions and 70 deletions.
511 changes: 448 additions & 63 deletions MacroScript.pm

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Makefile.PL
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ WriteMakefile(
AUTHOR => 'Mark Summerfield <summer@perlpress.com>',
) : () ),
'PREREQ_PM' => {
'enum' => 1.10,
'Path::Tiny' => 0.068,
'Capture::Tiny' => 0.22,
'Test::Differences' => 0.61,
Expand Down
1 change: 0 additions & 1 deletion t/expand_file.t
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use strict;
use warnings;
use Capture::Tiny 'capture';
use Path::Tiny;
use Test::Differences;
use Test::More;

use_ok 'Text::MacroScript';
Expand Down
1 change: 0 additions & 1 deletion t/macrodir.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use strict;
use warnings;
use Test::More;
use Test::Differences;
use Capture::Tiny 'capture';
use Path::Tiny;
use Time::HiRes 'usleep';
Expand Down
1 change: 0 additions & 1 deletion t/macropp.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use strict;
use warnings;
use Test::More;
use Test::Differences;
use Capture::Tiny 'capture';
use Path::Tiny;

Expand Down
1 change: 0 additions & 1 deletion t/macros.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use strict;
use warnings;
use Capture::Tiny 'capture';
use Test::Differences;
use Test::More;

my $ms;
Expand Down
1 change: 1 addition & 0 deletions t/mytests.pl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use strict;
use warnings;
use Test::Differences;

# normalize output and expected strings before eq test
sub _normalize_expected {
Expand Down
1 change: 0 additions & 1 deletion t/new.t
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use warnings;
use Capture::Tiny 'capture';
use Path::Tiny;
use POSIX 'strftime';
use Test::Differences;
use Test::More;

use_ok 'Text::MacroScript';
Expand Down
46 changes: 46 additions & 0 deletions t/new_define_embedded.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/perl

# Copyright (c) 2015 Paulo Custodio. All Rights Reserved.
# May be used/distributed under the GPL.

use strict;
use warnings;
use Test::More;
use Data::Dump 'dump';

my $ms;
use_ok 'Text::MacroScript';
require_ok 't/mytests.pl';

sub void(&) { $_[0]->(); () }

# escapes and concat
$ms = new_ok('Text::MacroScript', [-embedded => 1]);
is $ms->expand(), "";
is $ms->expand("hello"), "hello";

is $ms->expand("hello \\\n world"), "hello \\\n world";
is $ms->expand("hello \\% world"), "hello \\% world";
is $ms->expand("hello \\# world"), "hello \\# world";
is $ms->expand("hello ## world"), "hello ## world";

is $ms->expand("hello <:\\\n:> world"), "hello world";
is $ms->expand("hello <:\\% world"), "hello % world";
is $ms->expand("hello \\# :>world"), "hello # world";
is $ms->expand("<:hello ## :>world"), "helloworld";

# variable expansion
$ms = new_ok('Text::MacroScript', [-embedded => 1]);
is $ms->expand("abc<:%DEFINE_VARIABLE*HELLO*[1+]:>def"), "abcdef";
is $ms->expand("<:#*HELLO*:>"), "1+";
is $ms->expand("<:#*HELL:><:O*:>"), "#*HELLO*";

# multiple line value and counting of []
$ms = new_ok('Text::MacroScript', [-embedded => 1]);
is $ms->expand("a<:%DEFINE_VARIABLE X [:>b"), "ab";
is $ms->expand("c<:[hello:>d"), "cd";
is $ms->expand("e<:|:>f"), "ef";
is $ms->expand("g<:world]:>h"), "gh";
is $ms->expand("i<:]:>j<:#X:>k"), "ij[hello|world]k";

done_testing;
92 changes: 92 additions & 0 deletions t/new_define_variable.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/usr/bin/perl

# Copyright (c) 2015 Paulo Custodio. All Rights Reserved.
# May be used/distributed under the GPL.

use strict;
use warnings;
use Test::More;

my $ms;
use_ok 'Text::MacroScript';
require_ok 't/mytests.pl';

# API call
$ms = new_ok('Text::MacroScript');
$ms->define_variable('X', 123);
is $ms->expand("#X"), "123";

$ms->define(-variable, 'X', 321);
is $ms->expand("#X"), "321";

# escapes and concat
$ms = new_ok('Text::MacroScript');
is $ms->expand(), "";
is $ms->expand("hello"), "hello";
is $ms->expand("hello \\\n world"), "hello world";
is $ms->expand("hello \\% world"), "hello % world";
is $ms->expand("hello \\# world"), "hello # world";
is $ms->expand("hello ## world"), "helloworld";

# syntax errors
$ms = new_ok('Text::MacroScript');
eval {$ms->expand("%DEFINE_VARIABLE")};
is $@, "Error at file - line 1: Expected NAME [EXPR]\n";

$ms = new_ok('Text::MacroScript');
eval {$ms->expand("%DEFINE_VARIABLE", "file.asm", 10)};
is $@, "Error at file file.asm line 10: Expected NAME [EXPR]\n";

$ms = new_ok('Text::MacroScript');
eval {$ms->expand("%DEFINE_VARIABLE*HELLO*")};
is $@, "Error at file - line 1: Expected NAME [EXPR]\n";

$ms = new_ok('Text::MacroScript');
$ms->expand("%DEFINE_VARIABLE*HELLO*[");
eval { $ms->DESTROY };
is $@, "Error at file - line 1: Unbalanced open structure at end of file\n";

$ms = new_ok('Text::MacroScript');
eval { $ms->expand("%DEFINE_VARIABLE*HELLO*[1|2]") };
is $@, "Error at file - line 1: Only one argument expected\n";

$ms = new_ok('Text::MacroScript');
eval { $ms->define(-xxx, "xxx", "ZZZ") };
check_error(__LINE__-1, $@, "-xxx method not supported __LOC__.\n");

# variable expansion
$ms = new_ok('Text::MacroScript');
is $ms->expand(" %DEFINE_VARIABLE*HELLO*[1+]"), "";
is $ms->expand("*HELLO*"), "*HELLO*";
is $ms->expand("#*HELLO"), "#*HELLO";
is $ms->expand("#*HELLO*"), "1+";
is $ms->expand("\\#*HELLO*"), "#*HELLO*";
is $ms->expand("#*HELLO*#*HELLO*"), "1+1+";
is $ms->expand("#*HELLO* ## #*HELLO*"), "1+1+";

# arithmetic expressions
is $ms->expand("%DEFINE_VARIABLE*HELLO*[1+2]#*HELLO*"), "3";

# perl expressions
is $ms->expand("%DEFINE_VARIABLE hello [ola]#hello"), "ola";
is $ms->expand("%DEFINE_VARIABLE HELLO [uc('#hello')]#HELLO"), "OLA";

# self referencing variable
is $ms->expand("%DEFINE_VARIABLEX[#X+1]#X"), "1";
is $ms->expand("%DEFINE_VARIABLEX[#X+1]#X"), "2";
is $ms->expand("%DEFINE_VARIABLEX[#X+1]#X"), "3";

# multiple line value and counting of []
$ms = new_ok('Text::MacroScript');
is $ms->expand("%DEFINE_VARIABLE X ["), "";
is $ms->expand("[hello"), "";
is $ms->expand("|"), "";
is $ms->expand("world]"), "";
is $ms->expand("]#X"), "[hello|world]";

# escape [ | ]
is $ms->expand("%DEFINE_VARIABLE X [a\\[b]#X"), "a[b";
is $ms->expand("%DEFINE_VARIABLE X [a\\|b]#X"), "a|b";
is $ms->expand("%DEFINE_VARIABLE X [a\\]b]#X"), "a]b";

done_testing;
1 change: 0 additions & 1 deletion t/scripts.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use strict;
use warnings;
use Capture::Tiny 'capture';
use Test::Differences;
use Test::More;

my $ms;
Expand Down
1 change: 0 additions & 1 deletion t/variables.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use strict;
use warnings;
use Capture::Tiny 'capture';
use Test::Differences;
use Test::More;

use_ok 'Text::MacroScript';
Expand Down

0 comments on commit 6a9c739

Please sign in to comment.