# RPerl System Developers # Getting Started, A How-To Guide # Last Updated 20160824 2016.208 Welcome to RPerl, and thank you for your interest in joining the RPerl system developers! If you would like to create software libraries and applications (AKA "programs" or "apps") to be utilized by end-users, then this is not the correct document for you. Instead, please read the book Learning RPerl and join the RPerl application developers: Learning RPerl http://rperl.org/learning_rperl.html RPerl App Devs Group https://www.facebook.com/groups/1551887621787018 RPerl App Devs Intake Board https://trello.com/b/XmmPJQJj/austin-pm-rperl-app-devs-intake If, however, you are interested in contributing to the development of the RPerl compiler itself, then you are in the right place! This document will take you through the steps required to create a new RPerl operator, which will help you start learning the basic architecture of RPerl. STEP 0. Complete RPerl Developers Intake Process The intake process for RPerl system developers is the same as used for RPerl application developers. If you already have a Trello account, then please follow the URL for Trello above. If you have a Facebook account, then please submit a request to join at the URL below: RPerl System Devs Group https://www.facebook.com/groups/999476090136466 If you have neither a Trello nor Facebook account, then please send an e-mail with the subject line "RPerl System Devs" to the address below (remove NOSPAM): william.braswell at NOSPAM.autoparallel.com STEP 1. Choose An Operator When you have completed the intake process and are ready to start contributing, then the first main step is to choose an operator which has not yet been implemented. Start by opening up the URL below to Learning RPerl section 2.1.11, then perform a browser search for the string "Coming Soon": http://rperl.org/learning_rperl.html#Section_2.1.11%3A_Arithmetic_Operators You should be able to choose among most or all of the "Coming Soon" operators, although it is possible that another RPerl system developer is currently working on your first choice operator, so be sure to check with the lead developers on Trello and Facebook before finalizing your selection. For this example, we will choose the absolute value operator 'abs', implemented by our first authorized RPerl system developer, Pablo RodrÃguez González. Imagine that you are Pablo, and this is the process you are going through to implement the 'abs' operator. (Obviously you will not actually be implementing the 'abs' operator because Pablo already did, you will choose a different operator instead.) Technically, absolute value is a "named operator", as found in the RPerl grammar file with the token OP01_NAMED_SCOLON: https://github.com/wbraswell/rperl/blob/master/lib/RPerl/Grammar.eyp By searching for 'OP01_NAMED_SCOLON' at the URL above, you can see a long list showing that all of Perl's named operators are already enabled, but in the grammar only. Also, search for the token 'OP10_NAMED_UNARY_SCOLON' to see all the "named unary operators", which are a type of named operator that accept exactly one argument. Many of the remaining non-named operators are already fully implemented, whereas most of the named operators are not yet implemented outside of the grammar. To see a list of all operators which are already (at least partially) implemented, view the URLs below: https://github.com/wbraswell/rperl/blob/master/lib/rperloperations.pm https://github.com/wbraswell/rperl/tree/master/lib/RPerl/Operation/Expression/Operator/Named https://github.com/wbraswell/rperl/tree/master/lib/RPerl/Operation/Expression/Operator/NamedUnary Some of the operators listed in the URL above are only partially implemented, in that they only support PERLOPS_PERLTYPES mode (see step 2 below for modes explanation), whereas we need both PERLOPS_PERLTYPES mode as well as CPPOPS_CPPTYPES mode implemented for each operator. Thus, any operators which have a stub subroutine for CPPOPS_CPPTYPES mode are eligible for you to choose, simply search for anywhere the string 'DUMMY_SOURCE_CODE' appears inside a subroutine named 'ast_to_cpp__generate__CPPOPS_CPPTYPES()'. STEP 2. Study Similar Operators From an RPerl system developer's point of view, absolute value is a named operator, as specified in the RPerl grammar and overall architecture. However, absolute value is included in the "Arithmetic Operators" section of Learning RPerl, for easier understanding by RPerl application developers. There is no "Named Operators" section of Learning RPerl, because it would be a long unorganized list which is not easy to grasp or utilize for reference. Again, absolute value is technically not an "Arithmetic Operator" like the '+' (addition) or '*' (multiplication) operators, even though they are all used for math. Thus, before implementing absolute value, you should study the existing implementations of other named operators at the URL below: https://github.com/wbraswell/rperl/tree/master/lib/RPerl/Operation/Expression/Operator/Named If you have instead chosen to implement a named unary operator, they may be found here: https://github.com/wbraswell/rperl/tree/master/lib/RPerl/Operation/Expression/Operator/NamedUnary Each operator's Perl module file in the 2 URLs above has 3 primary subroutines, which correspond to RPerl's 3 primary modes, and each generate source code as output: ast_to_rperl__generate() ast_to_cpp__generate__CPPOPS_PERLTYPES() ast_to_cpp__generate__CPPOPS_CPPTYPES() The corresponding 3 primary modes of RPerl are: 0. Perl Operations & Perl Data Types, AKA "slow mode" or "interpreted mode" or "test mode" or "normal Perl mode", runs via normal dynamic Perl interpreter, 1x speed 1. C++ Operations & Perl Data Types, AKA "medium mode" or "mixed mode", runs via combination of dynamic Perl interpreter & static C++ compiler, approx 7x - 10x speed 2. C++ Operations & C++ Data Types, AKA "fast mode" or "compiled mode", runs via static C++ compiler, approx 100x - 400x speed Each of these 3 code generation subroutines accepts as input an RPerl abstract syntax tree (AST), which is a Perl object (blessed hashref) data structure generated by lexing and parsing some RPerl application source code. Because all named operators are combined together into just 2 groups in the RPerl grammar (named and named unary), they require special handling in the RPerl architecture. All RPerl code generation subroutines use the same names as these 3 subroutines, and most RPerl code generation subroutines accept their AST argument in the $self variable as part of RPerl's object-oriented architecture. However, the special handling for named operators causes use to receive an artificially-generated dummy object into the $self variable, while our real AST object is received into the $operator_named variable. All RPerl code generation subroutines also accept as their final input argument the globally-utilized $modes variable, which is a string_hashref data structure containing the current RPerl modes, symbol table, and a number of other possible flags or values required for proper RPerl functionality. The $modes variable should be passed as the final argument to all RPerl code generation subroutines, as well as many (or perhaps most) other RPerl system subroutines. Each of the subroutines generates as output a source group variable, which is another Perl string_hashref data structure containing all generated source code. In the PERLOPS_PERLTYPES code generation subroutines, this return value variable is named $rperl_source group, and in the other 2 modes it is named $cpp_source_group. Each key in the source group hashes is the all-uppercase equivalent of the generated source code file suffix, so in PERLOPS_PERLTYPES mode the $rperl_source_group hash variable only contains the key 'PMC' ("Perl Module Compiled"), and all generated Perl source code is stored within the corresponding 'PMC' hash value, which could eventually be saved to a file ending with the suffix '.pmc'. The generated '.pmc' file should be exactly equivalent to the original '.pm' input file, not counting code comments, which is why PERLOPS_PERLTYPES is also called "test mode", as the original RPerl input source code is completely parsed and then generated back into the matching original form as a test of the RPerl grammar, etc. In CPPOPS_PERLTYPES and CPPOPS_CPPTYPES modes, the $cpp_source_group hash variable contains at least the 'CPP' key which can be saved to a '.cpp' output C++ source code file. The $cpp_source_group hash may also contain 'H' and 'PMC' keys, although most named operators will only need to output into the 'CPP' source code. The PERLOPS_PERLTYPES subroutine is implemented first for all operators, and in the cases where an operator's Perl module file has already been created, there should already be a completed 'ast_to_rperl__generate()' subroutine present. The CPPOPS_PERLTYPES mode is currently not implemented for most RPerl operators, and will be left as a stub containing "DUMMY_SOURCE_CODE" until a later version of RPerl. The CPPOPS_CPPTYPES mode is the main focus of our RPerl system development efforts, because it offers the most speed benefits by far. Do not attempt to implement any CPPOPS_PERLTYPES code whatsoever, only the other 2 modes. STEP 3. Make A Fork On GitHub If you did not already have a GitHub account, then you should have created one during step 0. Also, you should know how to use git itself, at least the basic functionality, or else you could end up accidentally messing up your own code and losing work! Now you will create your own fork of RPerl on GitHub, which means you will have your own new copy of RPerl in a GitHub repository (AKA "repo"). This forked repository will contain all your new code changes, without accidentally breaking the main RPerl repo. While logged in to your GitHub account, visit the URL below and select the "Fork" button in the upper-right, then follow the instructions: https://github.com/wbraswell/rperl For all commits you make in any branches of your new repo, please always use the following format for git commit messages: Operator, Absolute Value, Your Concise Message Here In the next step, you will notice the commits by Pablo do not use this uniform message format, while the commits from Will do use the proper format. You may optionally create as many branches as you like within your new forked repository, or you can stay at 1 branch in the new repo to keep it simple. In step 7, you will carefully merge your new code back in to the main RPerl repo. STEP 4. Create Tests, Part 1 We will practice test-driven development (TDD), which means you should create at least 1 of your new 'abs' tests before you create your actual Perl module file. At this point the new 'abs' operator is not implemented in RPerl except for parsing through the RPerl grammar, but 'abs' will work just fine in normal interpreted Perl code, which is why you can write some tests before fully implementing the operator itself. This is a bit of a chicken-and-egg issue, because you will not be able to run your new tests through the `rperl` command until after you complete steps 5 and 6. Thus, we have split the creation of tests into 2 parts, step 4 and step 7. First, you will create a new test directory "lib/RPerl/Test/Operator01NamedAbsoluteValue" containing test files for the 'abs' operator. For this step, it is likely you will go through a similar process of development as you will experience while creating the Perl module file in step 5. (Please see step 5 for a relatively thorough explanation of the multi-commit development thought process, for brevity I will not repeat it in this step.) As in step 5, you find the most similar reference file with CPPOPS_CPPTYPES already implemented is the named unary 'scalar' operator, which has tests here: https://github.com/wbraswell/rperl/blob/master/lib/RPerl/Test/Operator10NamedUnaryScalar You make a copy of the file "lib/RPerl/Test/Operator10NamedUnaryScalar/program_00_good.pl" into "lib/RPerl/Test/Operator01NamedAbsoluteValue/program_00_good.pl". (In reality, you can copy 'scalar' operator files for named unary operators, and you can copy 'abs' operator files for non-unary named operators.) You notice the file names for all tests contain either "Good", "good", "Bad", or "bad"; this tells RPerl if the test file should succeed or fail. All "good" tests with file names ending in ".pl" should contain the following RPerl preprocessor directive: # <<< EXECUTE_SUCCESS: 'FOO' >>> All "bad" tests should contain exactly 1 of the following RPerl preprocessor directives: # <<< PARSE_ERROR: 'FOO' >>> # <<< GENERATE_ERROR: 'FOO' >>> # <<< COMPILE_ERROR: 'FOO' >>> # <<< EXECUTE_ERROR: 'FOO' >>> Finally, edit your newly-copied test file named "program_00_good.pl", so it tests proper usage of the new 'abs' operator instead of the 'scalar' operator. Be sure the file uses the 'print' operator to display meaningful output. Manually run the test program to ensure it at least executes correctly via the normal Perl interpreter, without the `rperl` command involved: $ lib/RPerl/Test/Operator01NamedAbsoluteValue/program_00_good.pl STEP 5. Create The Operator's Perl Module File You will be creating a new file named 'lib/RPerl/Operation/Expression/Operator/Named/AbsoluteValue.pm' which will contain most of your new code. To find a file which you can use as a starting template, you start by looking in the directory containing all named operators: https://github.com/wbraswell/rperl/tree/master/lib/RPerl/Operation/Expression/Operator/Named You see that RPerl support for the 'chomp' operator only allows the low-magic 'chomp VARIABLE' syntax, which is similar to the 'abs VALUE' syntax you need to support: https://github.com/wbraswell/rperl/blob/master/lib/RPerl/Operation/Expression/Operator/Named/Chomp.pm Thus, you create a copy of the "Chomp.pm" file and rename it to "AbsoluteValue.pm", then begin changing anywhere specific to 'chomp' to become 'abs', etc. Follow the URL below to see Pablo's first commit of the Perl module file, which includes support for PERLOPS_PERLTYPES mode only: https://github.com/wbraswell/rperl/blob/4d997f91a52a34d8f4fa1a47830bc246aacd736e/lib/RPerl/Operation/Expression/Operator/Named/AbsoluteValue.pm But wait! While you were working, a change was made to the RPerl grammar in the main RPerl repo, so we have to update the grammar rule serial numbers as seen here: https://github.com/wbraswell/rperl/commit/9d6b53f447a370869fb32835d1266a4f7f825f2e#diff-fc9b0cbe0168b9b1c7ec7026ea8175efL9 Hopefully you won't have a grammar change happen while you are working on your own operator, but as we can see it is definitely possible. Next, you have noticed that you need to implement CPPOPS_CPPTYPES, because the 'chomp' operator only supports PERLOPS_PERLTYPES. The most similar reference file with CPPOPS_CPPTYPES already implemented is the named unary 'scalar' operator: https://github.com/wbraswell/rperl/blob/master/lib/RPerl/Operation/Expression/Operator/NamedUnary/Scalar.pm So you copy the ast_to_cpp__generate__CPPOPS_CPPTYPES() subroutine from "Scalar.pm" into your new "AbsoluteValue.pm" and modify as needed: https://github.com/wbraswell/rperl/blob/99f74bd40d0214713f92c4efaac746f89d0821d6/lib/RPerl/Operation/Expression/Operator/Named/AbsoluteValue.pm (As in step 4, in reality you can copy 'scalar' operator files for named unary operators, and you can copy 'abs' operator files for non-unary named operators.) And we forgot to change the PERLOPS_PERLTYPES error code to the correct format for CPPOPS_CPPTYPES, so you fix that: https://github.com/wbraswell/rperl/commit/1350e0bbe8a21659faa4798f536e78fafe720034 Next, you realize we want our generated C++ code to match the original RPerl input source code as closely as possible, which means we want to generate 'abs' in C++ instead of 'std::abs', which is achieved by removing 'std::' from "AbsoluteValue.pm" and adding a C++ '#define' statement to the "rperloperations.h" file: https://github.com/wbraswell/rperl/commit/3153a85327dd7116eeb757692c05d2ec077ada2d#diff-fc9b0cbe0168b9b1c7ec7026ea8175efL111 https://github.com/wbraswell/rperl/commit/3153a85327dd7116eeb757692c05d2ec077ada2d#diff-1e5c0f27b0c43112d615cf4e6b903899R16 Oops, another bug! (Remember this one, we'll revist it shortly...) We can not add extra parentheses where there were none required, so they must be removed: https://github.com/wbraswell/rperl/commit/c893b70e9e047c6a7a0f9b1d9029c2f5195af53f#diff-fc9b0cbe0168b9b1c7ec7026ea8175efL114 All RPerl source code files should be auto-formatted using the Perltidy utility: http://perltidy.sourceforge.net It is important that you are using the official RPerl formatting configuration file, contained within the Perltidy run commands ("RC") file: https://github.com/wbraswell/lampuniversity.org/blob/master/docs/.perltidyrc When formatted with the correct Perltidy RC file, you see some minor cosmetic changes: https://github.com/wbraswell/rperl/commit/272a7ffc7a515839803168dd696bd1ae2711d06d#diff-fc9b0cbe0168b9b1c7ec7026ea8175efL21 Almost there! You forgot to update the 'abs' calling convention in the Perl module file's "DOCUMENTATION" section, so you fix that minor error: https://github.com/wbraswell/rperl/commit/125160fb375b9378f42069ce49473c87d6783ea2#diff-fc9b0cbe0168b9b1c7ec7026ea8175efL2 Last but not least, you realize that you actually DID need to generate extra parentheses after all, in order to avoid a C++ compiler error: $ rperl -V -D -nop lib/RPerl/Test/Operator01NamedAbsoluteValue/program_00_good.pl "... cannot resolve overloaded function ‘abs’ based on conversion to type ..." So it was actually a bug to remove the parentheses, and thus you replace them to finish this step: https://github.com/wbraswell/rperl/commit/e99125474340ca3f1867ff77ccadb9693e9dec6c#diff-fc9b0cbe0168b9b1c7ec7026ea8175efR103 To test your new operator in PERLOPS_PERLTYPES mode, run this command: $ rperl -V -D -nop -t lib/RPerl/Test/Operator01NamedAbsoluteValue/program_00_good.pl To test your new operator in CPPOPS_CPPTYPES mode, run these 2 commands: $ rperl -V -D -nop lib/RPerl/Test/Operator01NamedAbsoluteValue/program_00_good.pl $ ./lib/RPerl/Test/Operator01NamedAbsoluteValue/program_00_good DEBUGGING NOTES #1: The '-V' command-line argument turns on "verbose" output, and the '-D' argument turns on "debugging" or "diagnostic" output. These 2 arguments are exactly equivalent to setting the 'RPERL_VERBOSE=1' and 'RPERL_DEBUG=1' environmental variables. Within any RPerl system file, such as your "AbsoluteValue.pm" module file, all verbose output must be displayed by using the 'RPerl::verbose()' subroutine. Similarly, any RPerl system file should display all debugging output via the identical 'RPerl::diag()' or 'RPerl::debug()' subroutines, which are interchangeable. Within any RPerl application file, such as your "program_00_good.pl" test file, all normal output should be displayed using the 'print' operator. If an RPerl application file requires actual debugging output, you may use either the normal 'print' operator or the 'print {*STDERR}' variant. (Technically, RPerl apps can also call 'RPerl::verbose()' and friends, but this would be an app generating system output, which is probably not right.) Verbose output is meant to be viewed by our users (RPerl application developers), so most calls to 'RPerl::verbose()' should remain enabled in the RPerl source code. Diagnostic output is meant for us (RPerl system developers), so calls to 'RPerl::debug()' and 'RPerl::diag()' should be commented-out when not in use, in order to optimize runtime performance of the compiler itself. It is possible to run RPerl software within a Perl debugger or a C++ debugger, although both represent their own difficulties, and are not supported. That's it! Your new Perl module file is now complete. As you can see from the multiple URLs in this step, it took multiple commits to reach this point. The new "AbsoluteValue.pm" file was merged into the main RPerl repo before CPPOPS_CPPTYPES was implemented and before all bugs were worked out. It is fine if it takes you several commits in your forked repo to complete work on your new operator, but hopefully you will NOT try to merge your unfinished code into the main RPerl repo before all the work is done and all the bugs are fixed. To see the full, real history of this file, follow the URL below: https://github.com/wbraswell/rperl/commits/master/lib/RPerl/Operation/Expression/Operator/Named/AbsoluteValue.pm To view the latest copy of this Perl module file, follow this URL: https://github.com/wbraswell/rperl/blob/master/lib/RPerl/Operation/Expression/Operator/Named/AbsoluteValue.pm STEP 6. Update Appendant Files Whenever you create a new named operator, you will need to update a few extra files so RPerl will know about it. In the RPerl source code, this step is referenced with the following comment: # DEV NOTE, CORRELATION #rp020: upon adding new named op file lib/RPerl/Operation/Expression/Operator/Named*/* also add in Named*.pm and rperloperations.* Thus, you can search for everywhere affected by this step by executing the following command while in the RPerl source code directory: $ grep -nr '#rp020' ./* ./lib/rperloperations.pm ./lib/rperloperations.h ./lib/RPerl/Operation/Expression/Operator/Named.pm ./lib/RPerl/Operation/Expression/Operator/NamedUnary.pm First, you will need to update the "rperloperations.pm" file, if it does not already contain a 'use' command for your new Perl module file. Check the latest copy of "rperloperations.pm" to see if 'use RPerl::Operation::Expression::Operator::Named::AbsoluteValue;' is already included: https://github.com/wbraswell/rperl/blob/master/lib/rperloperations.pm When Pablo first checked the URL above, his new absolute value Perl module was not included, so we can see when he added it here: https://github.com/wbraswell/rperl/commit/4d997f91a52a34d8f4fa1a47830bc246aacd736e#diff-66e6372bddd4fc051a1cde1a632880a8R43 Second, you will need to update "rperloperations.h" with any C++ header code which may be required by your operator. Only some operators will need C++ header code, some may not. In this case, we do need to perform a C++ preprocessor directive to define the 'abs' operator to be the same as the 'std::abs' operator, as mentioned in step 5: https://github.com/wbraswell/rperl/commit/3153a85327dd7116eeb757692c05d2ec077ada2d#diff-1e5c0f27b0c43112d615cf4e6b903899R16 Third, you need to add the 'abs' operator into either the "Named.pm" or "NamedUnary.pm" files (but not both), depending on which category your operator falls within: https://github.com/wbraswell/rperl/commit/01e556314f967762f494270d6e3335eaf1f70b4d#diff-6276b3143f4ba5b5e1cb10e8bbf8b30fR22 At this point the new 'abs' operator should be working in both PERLOPS_PERLTYPES and CPPOPS_CPPTYPES modes. RPerl should be able to load and recognize your new operator! STEP 7. Create Tests, Part 2 Now we will continue where we left off in step 4. Manually run the `rperl` compiler front-end command in test mode to ensure your good test parses without any errors: $ rperl -V -D -nop -t lib/RPerl/Test/Operator01NamedAbsoluteValue/program_00_good.pl When your first good test is working properly, run it and copy all pertinent output into 1 or more "EXECUTE_SUCCESS" RPerl preprocessor directives. In most cases, you will want to match multiple success output strings to be sure a single good test is correct, which is accomplished by multiple "EXECUTE_SUCCESS" preprocessor directives in the correct order of appearance: https://github.com/wbraswell/rperl/blob/master/lib/RPerl/Test/Operator01NamedAbsoluteValue/program_00_good.pl Next, copy the "program_00_good.pl" file into another file named "program_00_bad_00.pl", and introduce exactly 1 error of some kind. For failures, you will use one of the "ERROR" preprocessor directives listed above. You must manually run the `rperl` command to know which error message each bad test should produce. As with good tests, you will usually want to match multiple error message strings to be sure a single failure is correct, which is accomplished by multiple error preprocessor directives of the same kind. For example, it is okay to have 2 or more "PARSE_ERROR" directives, but it is not okay to mix different kinds of preprocessor test directives in one test file. To determine the correct error message for each test, simply supply the test file as the input to the `rperl` command: $ rperl -V -D -nop lib/RPerl/Test/Operator01NamedAbsoluteValue/program_00_bad_00.pl You can see the "PARSE_ERROR" messages we want to match here: https://github.com/wbraswell/rperl/blob/master/lib/RPerl/Test/Operator01NamedAbsoluteValue/program_00_bad_00.pl Now you will want to create "program_00_bad_01.pl" and so forth, which should all be failing variations on the "program_00_good.pl" test. Each bad test should be designed to cause a different error when using the 'abs' operator, such as passing 0 or 2 arguments to abs, or passing invalid arguments, or other grammar errors like omitting a semicolon after properly calling abs. Next, make another copy of "program_00_good.pl" into "program_01_good.pl" and change it to test the 'abs' operator in some different way, such as by utilizing different input data, or different data types, or different combinations of operators. As before, "program_01_good.pl" should then be used to create "program_01_bad_00.pl" and so on. You should always plan to create at least a half dozen failing (bad) tests and 2 or 3 passing (good) tests for each new operator. Lastly, enable testing of the CPPOPS_CPPTYPES mode by manually calling the `rperl` command again, in order to generate C++ output reference code: $ rperl -V -D -nop lib/RPerl/Test/Operator01NamedAbsoluteValue/program_00_good.pl If the C++ output code is correctly generated with no "DUMMY_SOURCE_CODE" or errors, then the reference files are denoted by appending the ".CPPOPS_CPPTYPES" file suffix to each generated file ending with ".cpp" or ".h". For advanced developers who choose to generate test classes or packages instead of test programs only, then the reference ".pmc" files are denoted by appending the ".CPPOPS_DUALTYPES" file suffix. https://github.com/wbraswell/rperl/blob/master/lib/RPerl/Test/Operator01NamedAbsoluteValue/program_00_good.cpp.CPPOPS_CPPTYPES Please create enough tests to thoroughly ensure your new operator is both running correctly and also failing correctly. Of course, please run the full RPerl test suite on your local machine to make sure all new tests (and current tests) pass: $ perl Makefile.PL; make realclean; perl Makefile.PL; make test DEBUGGING NOTES #2: Your new tests will be automatically accessed by 3 parts of the RPerl system test suite: t/09, t/12, and t/13. https://github.com/wbraswell/rperl/blob/master/t/09_interpret_execute.t https://github.com/wbraswell/rperl/blob/master/t/12_parse.t https://github.com/wbraswell/rperl/blob/master/t/13_generate.t You can run tests for your new 'abs' operator only. You can just run 1 test at a time, using the environmental variables to enable verbose and debugging output: $ export RPERL_VERBOSE=1 $ export RPERL_DEBUG=1 $ $ #### you may want to use perl switches '-Mblib' and '-Mlib=lib' #### $ $ perl ./t/09_interpret_execute.t lib/RPerl/Test/Operator01NamedAbsoluteValue $ perl ./t/12_parse.t lib/RPerl/Test/Operator01NamedAbsoluteValue $ perl ./t/13_generate.t lib/RPerl/Test/Operator01NamedAbsoluteValue You should see over 3,300 tests pass without 1 single failure when the entire test suite runs correctly via the `make test` command above. Feels good, doesn't it? You can see the final product of creating the 'abs' tests here: https://github.com/wbraswell/rperl/tree/master/lib/RPerl/Test/Operator01NamedAbsoluteValue From the URL above, you can view the full history for each test file by clicking on the file's name, then clicking on the "History" button. STEP 8. Make A Pull Request On GitHub Before submitting a pull request on GitHub, please make sure your development branch or fork is up to date and compatible with the latest GitHub master branch. (Remember the issue with the grammar rule serial numbers changing in the main RPerl repo in step 5? That actually caused real problems with git.) You should be able to achieve this by performing a pull from your forked repo, which will import the latest code from the main RPerl repo. WARNING! Always backup your work in another folder before performing unfamiliar git commands such as `git pull`, which could accidentally mess up your own code. When you are confident that all your code and tests are correct, you may request your new changes be merged into the main RPerl repo for general public usage. Visit the URL below, then click the "New pull request" button and follow the directions: https://github.com/wbraswell/rperl/pulls The main RPerl repo should automatically run your new tests via the Travis CI (continuous integration) platform: https://travis-ci.org/wbraswell/rperl/pull_requests If your code passes on Travis and looks good in general, then your pull request should be accepted and merged into the main RPerl repository. Congratulations, you are now a published RPerl author! Give yourself a small gift or treat of some kind. :-) STEP 9. Update Learning RPerl After your new operator is proven to work correctly, we will want to update all corresponding sections of the Learning RPerl book, written using the POD format: http://perldoc.perl.org/perlpod.html The very latest version of Learning RPerl is always on GitHub: https://github.com/wbraswell/rperl/blob/master/lib/RPerl/Learning.pm The latest published version of Learning RPerl is always on the official RPerl website, although it may well be older than the GitHub version: http://rperl.org/learning_rperl.html Please do a thorough search for your new operator in all sections of the Learning RPerl book, and update it as necessary. At the very least, you will need to change the "Coming Soon" label to "Yes" in the table of supported operators! As with the previous steps, you should make all changes to the "Learning.pm" file within your own forked repo, then make a pull request like in step 8. Double congratulations, you are now a published Learning RPerl author! Give yourself a slightly larger gift or treat! ;-) ... THAT'S ALL, FOLKS!