[
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.yml",
    "content": "name: 🐛 Bug Report\ndescription: Report a bug\ntitle: (bug report summary)\nlabels: Bug\nbody:\n  - type: textarea\n    id: description\n    attributes:\n      label: Describe the bug\n      description: What is the problem? A clear and concise description of the bug.\n    validations:\n      required: true\n\n  - type: textarea\n    id: expected\n    attributes:\n      label: Expected Behavior\n      description: What did you expect to happen?\n    validations:\n      required: true\n\n  - type: textarea\n    id: current\n    attributes:\n      label: Current Behavior\n      description: |\n        What actually happened?\n\n        Please include full errors, uncaught exceptions, stack traces, and relevant logs.\n        If service/functions responses are relevant, please include wire logs.\n    validations:\n      required: true\n\n  - type: textarea\n    id: reproduction\n    attributes:\n      label: Reproduction Steps\n      description: |\n        Provide a self-contained, concise snippet of code that can be used to reproduce the issue.\n        For more complex issues provide a repo with the smallest sample that reproduces the bug.\n\n        Avoid including business logic or unrelated code, it makes diagnosis more difficult.\n        The code sample should be an SSCCE. See http://sscce.org/ for details.\n        In short, please provide a code sample that we can copy/paste, run and reproduce.\n    validations:\n      required: true\n\n  - type: textarea\n    id: solution\n    attributes:\n      label: Possible Solution\n      description: Suggest a fix/reason for the bug\n    validations:\n      required: false\n\n  - type: textarea\n    id: context\n    attributes:\n      label: Additional Information/Context\n      description: |\n        Anything else that might be relevant for troubleshooting this bug.\n        Providing context helps us come up with a solution that is most useful in the real world.\n    validations:\n      required: false\n\n  - type: input\n    id: version\n    attributes:\n      label: Nuru version\n      description: |\n        Please make sure to use the latest version of Nuru before reporting any issues as it may have already been fixed.\n    validations:\n      required: true\n\n  - type: textarea\n    id: environment\n    attributes:\n      label: Environment details (OS name and version, etc.)\n      description: Your operating system (Windows, Linux, Android or MacOS)\n    validations:\n      required: true\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.yml",
    "content": "name: 🚀 Feature Request\ndescription: Suggest an idea for this project\ntitle: (feature request summary)\nlabels: Feature Request\nbody:\n  - type: textarea\n    id: description\n    attributes:\n      label: Describe the feature\n      description: A clear and concise description of the feature you are proposing.\n    validations:\n      required: true\n\n  - type: textarea\n    id: use-case\n    attributes:\n      label: Use Case\n      description: |\n        Why do you need this feature? For example: \"I'm always frustrated when...\"\n    validations:\n      required: true\n\n  - type: textarea\n    id: solution\n    attributes:\n      label: Proposed Solution\n      description: Suggest how to implement the addition or change. Please include prototype/workaround/sketch/reference implementation.\n    validations:\n      required: false\n\n  - type: textarea\n    id: other\n    attributes:\n      label: Other Information\n      description: Any alternative solutions or features you considered, a more detailed explanation, stack traces, related issues, links for context, etc.\n    validations:\n      required: false\n\n  - type: checkboxes\n    id: ack\n    attributes:\n      label: Acknowledgements\n      options:\n        - label: I may be able to implement this feature request\n          required: false\n\n        - label: This feature might incur a breaking change\n          required: false\n\n  - type: input\n    id: version\n    attributes:\n      label: Version used\n      description: Please provide the version of the repository or tool you are using.\n    validations:\n      required: true\n\n  - type: textarea\n    id: environment\n    attributes:\n      label: Environment details (OS name and version, etc.)\n      description: Your operating system (Linux, Windows, Android or Mac)\n    validations:\n      required: true\n\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE",
    "content": "\n\n<!--\n\nPlease title your PR as follows: `module: description` (e.g. `time: fix date format`).\nAlways start with the thing you are fixing, then describe the fix.\nDon't use past tense (e.g. \"fixed foo bar\").\n\nExplain what your PR does and why.\n\nIf you are adding a new function, please document it and add tests:\n\n```\n// foo does foo and bar\nfoo = unda() {\n    // does foo and bar \n}\n```\n\nIf you are fixing a bug, please add a detailed explanation about it.\n\nBefore submitting a PR, please run `make test` .\n\nI try to process PRs as soon as possible. They should be handled within 24 hours.\n\nApplying labels to PRs is not needed.\n\nThanks a lot for your contribution!\n\n-->\n\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Go\n\non:\n  push:\n    tags:\n      - \"*\"\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        fetch-depth: 0\n\n    - name: Set up Go\n      uses: actions/setup-go@v3\n      with:\n        go-version: 1.21\n      id: go\n\n    - name: Test\n      run: go mod tidy && make test\n    \n    - name: Run GoReleaser\n      uses: goreleaser/goreleaser-action@v5\n      with:\n        distribution: goreleaser\n        version: latest\n        args: release --clean\n      env:\n        GITHUB_TOKEN: ${{ secrets.GO_RELEASER_GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: Go\n\non:\n  push:\n    branches: [ main, dev ]\n\njobs:\n\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v3\n\n    - name: Set up Go\n      uses: actions/setup-go@v3\n      with:\n        go-version: 1.21\n\n    - name: Test\n      run: go mod tidy && make test\n\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n*.[56789ao]\n*.a[56789o]\n*.so\n*.pyc\n._*\n.nfs.*\n[56789a].out\n*~\n*.orig\n*.rej\n*.exe\n.*.swp\ncore\n*.cgo*.go\n*.cgo*.c\n_cgo_*\n_obj\n_test\n_testmain.go\n/VERSION.cache\n/bin/\n/build.out\n/doc/articles/wiki/*.bin\n/goinstall.log\n/last-change\n/misc/cgo/life/run.out\n/misc/cgo/stdio/run.out\n/misc/cgo/testso/main\n/pkg/\n/src/*.*/\n/src/cmd/cgo/zdefaultcc.go\n/src/cmd/dist/dist\n/src/cmd/go/internal/cfg/zdefaultcc.go\n/src/cmd/go/internal/cfg/zosarch.go\n/src/cmd/internal/objabi/zbootstrap.go\n/src/go/build/zcgo.go\n/src/go/doc/headscan\n/src/runtime/internal/sys/zversion.go\n/src/unicode/maketables\n/test.out\n/test/garbage/*.out\n/test/pass.out\n/test/run.out\n/test/times.out\n\n#Personal\n\ntestbinaries/\ntests_random/\nnuru\nNotes.md\ntutorials/en/*\nconfig.json\n*local*\n\n# For Nuru executables\n/nuru\n/Nuru\n\ndist/\n*.wasm\n"
  },
  {
    "path": ".goreleaser.yaml",
    "content": "project_name: nuru\nbefore:\n  hooks:\n    - go mod tidy\n    - go generate ./...\n\nbuilds:\n  - env:\n      - CGO_ENABLED=0\n    goos:\n      - linux\n      - windows\n      - darwin\n      - android\n    ldflags:\n      - \"-s -w\"\n    ignore:\n      - goos: android\n        goarch: 386\n\narchives:\n  - format: tar.gz\n    name_template: >-\n      nuru_\n      {{- title .Os }}_\n      {{- if eq .Arch \"amd64\" }}amd64\n      {{- else if eq .Arch \"386\" }}i386\n      {{- else }}{{ .Arch }}{{ end }}\n      {{- if .Arm }}v{{ .Arm }}{{ end }}\n    format_overrides:\n      - goos: windows\n        format: zip\n\nchangelog:\n  sort: asc\n  filters:\n    exclude:\n      - \"^docs:\"\n      - \"^test:\"\n\nnfpms:\n  - maintainer: \"AvicennaJr\"\n    homepage: \"https://nuruprogramming.org\"\n    description: \"Nuru is a programming language built from the ground up\"\n    formats:\n      - deb\n    file_name_template: \"{{ .ProjectName }}.{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}\"\n"
  },
  {
    "path": "ABOUT.md",
    "content": "# NURU PROGRAMMING LANGUAGE\n\nThis page intends to show the origins of Nuru, its purpose, what it can be used for, what it should not be used for and the potential future of the programming language.\n\n## Background\n\nThis language is the direct child of a programming language called \"Monkey Language\" made by Thorston Ball. He wrote a book titled \"Writing An Interpreter In Go\" and the core of the language is based on his book.\n\nWith the knowledge I gained from his book, I saw an opportunity to write a Swahili Programming Language, which would not just be a translation of an already existing one, but an actual standalone interpreted language that can be built from the ground up, where everything can be customized from the syntax, its abilities, its standard library and more. \n\nNow one may wonder, why a new programming language when there are many other much better programming languages in existence. The answer is, it is a Swahili programming language. And this is significant for two reasons:\n- Many are unable to learn programming due to the language barrier. Almost all programming languages in existence are in English and thus a non English speaker would have to first learn English before they can learn a programming language. This makes the effort twice as difficult and Nuru, a native Swahili programming language, intends to make the process of learning programming languages a bit easier.\n- Secondly, even if no one does use this programming language, then at least we can say \"We do have a fully functional Swahili programming language\", and as a person who grew up in Tanzania, this does give me pride.\n\n## Purpose\n\nNuru does not intend to replace any existing programming language. In fact, it does not intend to be used in production at all. Nuru intends to be an educational programming language, a programming language that will make it easy for anyone to get into the world of programming without knowing English. It intends to be simple enough to be taught to kids in primary and highschool and allow them to build interesting tools with it.\n\nNuru also hopes to be used by hobbyists and experienced programmers, where by they will find it easy to write scripts in Nuru that will help solve their various tasks or build interesting projects with it. As a matter of fact, someone already made a sudoku solver in Nuru.\n\nWhile being simple it also intends to be fully functional. Other than having all the core features required by a programming language, Nuru also has an extensive standard library that will make performing common tasks much easier. Thus, it intends to bring the best of both worlds, simple to use with a lot of features.\n\n## Philosophy\n\nNuru's philosophy is to keep things simple. Everything in Nuru should be consistent and intuitive, from its syntax to the keywords used. On the matter of keywords, Nuru intends to provide keywords that are simple and intuitive that can easily explain what the function or library is for. A more detailed guide on the Nuru's syntax and the proper way of writing Nuru will be provided in the near future.\n\nNuru is also community driven. We listen to our community and do our best to implement on the feedback we get from them.\n\n## Where Not To Use Nuru\n\nNuru's performance is worse than python. It has been authored by someone with very limited knowledge in programming. Thus, it is advised to never use Nuruin production code where by any kind of mistakes are critical. Nuru is still very immature and should only be used for educational and hobby projects.\n\n## Challenges\n\nThe main challenge we have in Nuru is in naming keywords. Since this is something new, there are lack of words that fully describe common programming words. However, we do intend to try our best to select the best keywords, and we often consult with our community when choosing a word.\n\n## Future Of Nuru\n\nIt is still too early to know how Nuru will evolve, or the way in which the community will use this language. However, what is certain is the core developers will do their best to provide a language that will be enjoyable to learn and code in. We listen to our community and hopefully we will soon have a large number of developers contributing to the language.\n\nWe also hope to see games and GUI applications written in Nuru in the near future... God willing.\n\n## Final Words\n\nI am very grateful to the reception of this project, we now have over 150+ downloads and its barely been a month. We hope to fulfill all your expectations and provide something that you will all enjoy to use. We also ask you to bear with us when we make mistakes and correct and advise us on areas where we can do better. I am also grateful to Thorston for writing such an amazing book, and I would recommend anyone who'd want to learn how programming languages work to read his book.\n\nAnd finally, I thank Allah for granting us the ability to learn and giving me the ability to make such a project.\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n                            NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n"
  },
  {
    "path": "Makefile",
    "content": "VERSION=0.5.1\n\nbuild_linux:\n\t@echo 'building linux binary...'\n\tenv GOOS=linux GOARCH=amd64 go build -ldflags=\"-s -w\" -o nuru\n\t@echo 'shrinking binary...'\n\t./upx --brute nuru\n\t@echo 'zipping build....'\n\ttar -zcvf nuru_linux_amd64_v${VERSION}.tar.gz nuru\n\t@echo 'cleaning up...'\n\trm nuru\n\nbuild_windows:\n\t@echo 'building windows executable...'\n\tenv GOOS=windows GOARCH=amd64 go build -ldflags=\"-s -w\" -o nuru_windows_amd64_v${VERSION}.exe\n\t@echo 'shrinking build...'\n\t./upx --brute nuru_windows_amd64_v${VERSION}.exe\n\nbuild_mac:\n\t@echo 'building mac binary...'\n\tenv GOOS=darwin GOARCH=amd64 go build -ldflags=\"-s -w\" -o nuru\n\t@echo 'shrinking binary...'\n\t./upx --brute nuru\n\t@echo 'zipping build...'\n\ttar -zcvf nuru_mac_amd64_v${VERSION}.tar.gz nuru\n\t@echo 'cleaning up...'\n\trm nuru\n\nbuild_android:\n\t@echo 'building android binary'\n\tenv GOOS=android GOARCH=arm64 go build -ldflags=\"-s -w\" -o nuru\n\t@echo 'zipping build...'\n\ttar -zcvf nuru_android_arm64_v${VERSION}.tar.gz nuru\n\t@echo 'cleaning up...'\n\trm nuru\n\nbuild_wasm:\n\t@echo 'building wasm binary'\n\tGOOS=js GOARCH=wasm go build -o nuru.wasm\n\t@echo 'zipping build...'\n\ttar -zcvf nuru_wasm_v${VERSION}.tar.gz nuru.wasm\n\t@echo 'cleaning up...'\n\trm nuru.wasm\n\n\nbuild_test:\n\tgo build -ldflags=\"-s -w\" -o nuru\n\ndependencies:\n\t@echo 'checking dependencies...'\n\tgo mod tidy\n\ntest:\n\t@echo -e '\\nTesting Lexer...'\n\t@./gotest --format testname ./lexer/ \n\t@echo -e '\\nTesting Parser...'\n\t@./gotest --format testname ./parser/\n\t@echo -e '\\nTesting AST...'\n\t@./gotest --format testname ./ast/\n\t@echo -e '\\nTesting Object...'\n\t@./gotest --format testname ./object/\n\t@echo -e '\\nTesting Evaluator...'\n\t@./gotest --format testname ./evaluator/\n\nclean:\n\tgo clean\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">NURU🔥PROGRAMMING🔥LANGUAGE</h1>\n<p align=\"center\">\n    <a href=\"https://github.com/NuruProgramming/Nuru\"><img alt=\"Nuru Programming Language\" src=\"https://img.shields.io/badge/Nuru-Programming%20Language-yellow\"></a>\n    <a href=\"https://github.com/NuruProgramming/Nuru\"><img alt=\"Nuru Programming Language\" src=\"https://img.shields.io/badge/platform-Linux | Windows | Android-green.svg\"></a>\n    <a href=\"https://github.com/NuruProgramming/Nuru\"><img alt=\"Nuru Programming Language\" src=\"https://img.shields.io/github/last-commit/AvicennaJr/Nuru\"></a>\n<br>\n    <a href=\"https://github.com/NuruProgramming/Nuru\"><img alt=\"Nuru Programming Language\" src=\"https://img.shields.io/github/downloads/avicennajr/nuru/total\"></a>\n    <a href=\"https://github.com/NuruProgramming/Nuru/releases\"><img alt=\"Nuru Programming Language\" src=\"https://img.shields.io/github/v/release/avicennajr/nuru?include_prereleases\"></a>\n    <a href=\"https://github.com/NuruProgramming/Nuru\"><img alt=\"Nuru Programming Language\" src=\"https://img.shields.io/github/actions/workflow/status/AvicennaJr/Nuru/tests.yml?style=plastic\"></a>\n<br>\n    <a href=\"https://github.com/NuruProgramming/Nuru\"><img alt=\"Nuru Programming Language\" src=\"https://img.shields.io/github/stars/AvicennaJr/Nuru?style=social\"></a>\n</p>\nA Swahili Programming Language of its kind built from the ground up.\n\n## Installation\n\nTo get started download the executables from the release page or follow the instructions for your device below:\n\n### Linux\n\n- Download the binary:\n\n```\ncurl -O -L https://github.com/NuruProgramming/Nuru/releases/download/v0.5.18/nuru_Linux_amd64.tar.gz\n```\n\n- Extract the file to make global available:\n\n```\nsudo tar -C /usr/local/bin -xzvf nuru_Linux_amd64.tar.gz\n```\n\n- Confirm installation with:\n\n```\nnuru -v\n```\n\n### MacOs ( Apple silicon Mac )\n\n- Download the binary:\n\n  - For apple silicon mac use:\n\n    ```\n    curl -O -L https://github.com/NuruProgramming/Nuru/releases/download/v0.5.18/nuru_Darwin_arm64.tar.gz\n    ```\n\n  - For apple intel mac use:\n\n    ```\n    curl -O -L https://github.com/NuruProgramming/Nuru/releases/download/v0.5.18/nuru_Darwin_amd64.tar.gz\n    ```\n\n- Extract the file to make global available:\n\n  - For apple silicon mac use:\n\n    ```\n    sudo tar -C /usr/local/bin -xzvf nuru_Darwin_arm64.tar.gz\n    ```\n\n  - For apple intel mac use:\n\n    ```\n    sudo tar -C /usr/local/bin -xzvf nuru_Darwin_amd64.tar.gz\n    ```\n\n- Confirm installation with:\n\n```\nnuru -v\n```\n\n### Android (Termux)\n\nTo install Nuru on your Android device using Termux, follow these steps:\n\n1. **Ensure Termux is installed**:\n\n   - You can download and install [Termux](https://f-droid.org/en/packages/com.termux/).\n\n2. **Create the target directory**:\n\n   ```bash\n   mkdir -p /data/data/com.termux/files/usr/share/nuru\n   ```\n\n3. **Download the Nuru package**:\n\n   ```bash\n   curl -O -L https://github.com/NuruProgramming/Nuru/releases/download/v0.5.18/nuru_Android_arm64.tar.gz\n   ```\n\n4. **Extract the files to the target directory**:\n\n   ```bash\n   tar -xzvf nuru_Android_arm64.tar.gz -C /data/data/com.termux/files/usr/share/nuru\n   ```\n\n5. **Set up an alias for easy access**:\n\n   ```bash\n   echo \"alias nuru='/data/data/com.termux/files/usr/share/nuru/nuru'\" >> ~/.bashrc\n   ```\n\n6. **Reload the .bashrc file to apply the alias**:\n\n   ```bash\n   source ~/.bashrc\n   ```\n\n7. **Verify the installation**:\n   ```bash\n   nuru -v\n   ```\n\nFor a more streamlined installation, you can use the following one-liner:\n\n```bash\ncurl -O -L https://github.com/NuruProgramming/Nuru/releases/download/v0.5.18/nuru_Android_arm64.tar.gz && mkdir -p /data/data/com.termux/files/usr/share/nuru && tar -xzvf nuru_Android_arm64.tar.gz -C /data/data/com.termux/files/usr/share/nuru && echo \"alias nuru='/data/data/com.termux/files/usr/share/nuru/nuru'\" >> ~/.bashrc && source ~/.bashrc && echo \"Installation complete..\"\n```\n\n### Windows\n\n- Executable:\n\n  - Download the Nuru zip file [Here](https://github.com/NuruProgramming/Nuru/releases/download/v0.5.18/nuru_Windows_amd64.zip)\n  - Unzip to get the executable\n  - Double click the executable\n\n- Nuru Installer\n  > Coming Soon\n\n### Building From Source\n\n- Make sure you have golang installed (atleast 1.19.0 and above)\n- Run the following command:\n\n```\ngo build -o nuru .\n```\n\n- Copy nuru binary to path destination ~/go/bin\n\n```\ncp nuru ~/go/bin\n```\n\n- Confirm installtion with:\n\n```\nnuru -v\n```\n\n## Syntax At A Glance\n\n**NOTE**\n\n> There is a more detailed documentation of the language [here](https://nuruprogramming.org).\n\nNuru, although still in its early stage, intends to be a fully functional programming language, and thus it has been baked with many features.\n\n### Defining A Variable\n\nYou can define variables like this:\n\n```\nx = 2;\ny = 3;\n\nandika(x*y) // output is 6\n```\n\nYou can also use the `fanya` keyword to define a variabe:\n\n```\nfanya x = 3\n```\n\n**Note that `fanya` keyword is OPTIONAL**\n\n### Comments\n\nNuru supports both single line and multiple line comments as shown below:\n\n```\n// Single line comment\n\n/*\nMultiple\nLine\nComment\n*/\n```\n\n### Arithmetic Operations\n\nFor now Nuru supports `+`, `-`, `/`, `*` and `%`. Nuru also provides precedence of operations using the BODMAS rule:\n\n```\n2 + 2 * 3 // output = 8\n\n2 * (2 + 3) // output = 10\n```\n\n### Types\n\nNuru has the following types:\n\n| Type   | Syntax                             | Comments                                                |\n| ------ | ---------------------------------- | ------------------------------------------------------- |\n| BOOL   | `kweli sikweli`                    | kweli == true, sikweli == false                         |\n| INT    | `1, 100, 342, -4`                  | These are signed 64 bit integers                        |\n| FLOAT  | `2.3, 4.5. 100.8094`               | Signed 64 bit floats                                    |\n| STRING | `\"\" \"mambo\" \"habari yako\"`         | They can be in double `\"` or single `'` quotes          |\n| ARRAY  | `[] [1, 2, 3] [1, \"moja\", kweli]`  | Arrays can hold any types                               |\n| DICT   | `{} {\"a\": 3, 1: \"moja\", kweli: 2}` | Keys can be int, string or bool. Values can be anything |\n| NULL   | `tupu`                             | These are nil objects                                   |\n\n### Functions\n\nThis is how you define a function in Nuru:\n\n```\njumlisha = unda(x, y) {\n        rudisha x + y\n    }\n\nandika(jumlisha(3,4))\n```\n\nNuru also supports recursion:\n\n```\nfibo = unda(x) {\n\tkama (x == 0) {\n\t\trudisha 0;\n\t} au kama (x == 1) {\n\t\t\trudisha 1;\n\t} sivyo {\n\t\t\trudisha fibo(x - 1) + fibo(x - 2);\n\t}\n}\n```\n\n### If Statements\n\nNuru supports if, elif and else statements with keywords `kama`, `au kama` and `sivyo` respectively:\n\n```\nkama (2<1) {\n    andika(\"Mbili ni ndogo kuliko moja\")\n} au kama (3 < 1) {\n    andika (\"Tatu ni ndogo kuliko moja\")\n} sivyo {\n    andika(\"Moja ni ndogo\")\n}\n```\n\n### While Loops\n\nNuru's while loop syntax is as follows:\n\n```\ni = 10\n\nwakati (i > 0) {\n\tandika(i)\n\ti--\n}\n```\n\n### Arrays\n\nThis is how you initiliaze and perform other array operations in Nuru:\n\n```\narr = []\n\n// To add elements\n\nsukuma(arr, 2)\nandika(arr) // output = [2]\n// Add two Arrays\n\narr2 = [1,2,3,4]\n\narr3 = arr1 + arr2\n\nandika(arr3) // output = [2,1,2,3,4]\n\n// reassign value\n\narr3[0] = 0\n\nandika[arr3] // output = [0,1,2,3,4]\n\n// get specific item\n\nandika(arr[3]) // output = 3\n```\n\n### Dictionaries\n\nNuru also supports dictionaries and you can do a lot with them as follows:\n\n```\nmtu = {\"jina\": \"Mojo\", \"kabila\": \"Mnyakusa\"}\n\n// get value from key\nandika(mtu[\"jina\"]) // output = Mojo\n\nandika(mtu[\"kabila\"]); // output = Mnyakusa\n\n// You can reassign values\n\nmtu[\"jina\"] = \"Avicenna\"\n\nandika(mtu[\"jina\"]) // output = Avicenna\n\n// You can also add new values like this:\n\nmtu[\"anapoishi\"] = \"Dar Es Salaam\"\n\nandika(mtu) // output = {\"jina\": \"Avicenna\", \"kabila\": \"Mnyakusa\", \"anapoishi\": \"Dar Es Salaam\"}\n\n// You can also add two Dictionaries\n\nkazi = {\"kazi\": \"jambazi\"}\n\nmtu = mtu + kazi\n\nandika(mtu) // output = {\"jina\": \"Avicenna\", \"kabila\": \"Mnyakusa\", \"anapoishi\": \"Dar Es Salaam\", \"kazi\": \"jambazi\"}\n```\n\n### For Loops\n\nThese can iterate over strings, arrays and dictionaries:\n\n```\nkwa i ktk \"habari\" {\n    andika(i)\n}\n/* //output\nh\na\nb\na\nr\ni\n*/\n```\n\n### Getting Input From User\n\nIn Nuru you can get input from users using the `jaza()` keyword as follows:\n\n```\njina = jaza(\"Unaitwa nani? \") // will prompt for input\n\nandika(\"Habari yako \" + jina)\n```\n\n## How To Run\n\n### Using The Intepreter:\n\nYou can enter the intepreter by simply running the `nuru` command:\n\n```\nnuru\n>>> andika(\"karibu\")\nkaribu\n>>> 2 + 2\n4\n```\n\nKindly Note that everything should be placed in a single line. Here's an example:\n\n```\n>>> kama (x > y) {andika(\"X ni kubwa\")} sivyo {andika(\"Y ni kubwa\")}\n```\n\n### Running From File\n\nTo run a Nuru script, write the `nuru` command followed by the name of the file with a `.nr` or `.sw` extension:\n\n```\nnuru myFile.nr\n```\n\n## Issues\n\nKindly open an [Issue](https://github.com/NuruProgramming/Nuru/issues) to make suggestions and anything else.\n\n## Contributions\n\n### Documentation\n\nThere are documentations for two languages, English and Kiswahili, which are both under the `docs` folder. All files are written in markdown. Feel free to contribute by making a pull request.\n\n### Code\n\nClone the repo, hack it, make sure all tests are passing then submit a pull request.\n\n> Make sure ALL tests are passing before making a pull request. You can confirm with running `make test`\n\n## Community\n\nNuru has a passionate community, join us on [Telegram](https://t.me/NuruProgrammingChat)\n\n## License\n\n[MIT](http://opensource.org/licenses/MIT)\n\n## Authors\n\nNuru Programming Language has been authored and being actively maintained by [Avicenna](https://github.com/AvicennaJr)\n"
  },
  {
    "path": "ast/ast.go",
    "content": "package ast\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\ntype Node interface {\n\tTokenLiteral() string\n\tString() string\n}\n\ntype Statement interface {\n\tNode\n\tstatementNode()\n}\n\ntype Expression interface {\n\tNode\n\texpressionNode()\n}\n\ntype Program struct {\n\tStatements []Statement\n}\n\nfunc (p *Program) TokenLiteral() string {\n\tif len(p.Statements) > 0 {\n\t\treturn p.Statements[0].TokenLiteral()\n\t} else {\n\t\treturn \"\"\n\t}\n}\n\nfunc (p *Program) String() string {\n\tvar out bytes.Buffer\n\n\tfor _, s := range p.Statements {\n\t\tout.WriteString(s.String())\n\t}\n\n\treturn out.String()\n}\n\ntype LetStatement struct {\n\tToken token.Token\n\tName  *Identifier\n\tValue Expression\n}\n\nfunc (ls *LetStatement) statementNode()       {}\nfunc (ls *LetStatement) TokenLiteral() string { return ls.Token.Literal }\nfunc (ls *LetStatement) String() string {\n\tvar out bytes.Buffer\n\n\tout.WriteString(ls.TokenLiteral() + \" \")\n\tout.WriteString(ls.Name.String())\n\tout.WriteString(\" = \")\n\n\tif ls.Value != nil {\n\t\tout.WriteString(ls.Value.String())\n\t}\n\n\tout.WriteString(\";\")\n\treturn out.String()\n}\n\ntype Identifier struct {\n\tToken token.Token\n\tValue string\n}\n\nfunc (i *Identifier) expressionNode()      {}\nfunc (i *Identifier) TokenLiteral() string { return i.Token.Literal }\nfunc (i *Identifier) String() string       { return i.Value }\n\ntype ReturnStatement struct {\n\tToken       token.Token\n\tReturnValue Expression\n}\n\nfunc (rs *ReturnStatement) statementNode()       {}\nfunc (rs *ReturnStatement) TokenLiteral() string { return rs.Token.Literal }\nfunc (rs *ReturnStatement) String() string {\n\tvar out bytes.Buffer\n\n\tout.WriteString(rs.TokenLiteral() + \" \")\n\n\tif rs.ReturnValue != nil {\n\t\tout.WriteString(rs.ReturnValue.String())\n\t}\n\tout.WriteString(\";\")\n\treturn out.String()\n}\n\ntype ExpressionStatement struct {\n\tToken      token.Token\n\tExpression Expression\n}\n\nfunc (es *ExpressionStatement) statementNode()       {}\nfunc (es *ExpressionStatement) TokenLiteral() string { return es.Token.Literal }\nfunc (es *ExpressionStatement) String() string {\n\tif es.Expression != nil {\n\t\treturn es.Expression.String()\n\t}\n\n\treturn \"\"\n}\n\ntype IntegerLiteral struct {\n\tToken token.Token\n\tValue int64\n}\n\nfunc (il *IntegerLiteral) expressionNode()      {}\nfunc (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal }\nfunc (il *IntegerLiteral) String() string       { return il.Token.Literal }\n\ntype PrefixExpression struct {\n\tToken    token.Token\n\tOperator string\n\tRight    Expression\n}\n\nfunc (pe *PrefixExpression) expressionNode()      {}\nfunc (pe *PrefixExpression) TokenLiteral() string { return pe.Token.Literal }\nfunc (pe *PrefixExpression) String() string {\n\tvar out bytes.Buffer\n\n\tout.WriteString(\"(\")\n\tout.WriteString(pe.Operator)\n\tout.WriteString(pe.Right.String())\n\tout.WriteString(\")\")\n\n\treturn out.String()\n}\n\ntype InfixExpression struct {\n\tToken    token.Token\n\tLeft     Expression\n\tOperator string\n\tRight    Expression\n}\n\nfunc (oe *InfixExpression) expressionNode()      {}\nfunc (oe *InfixExpression) TokenLiteral() string { return oe.Token.Literal }\nfunc (oe *InfixExpression) String() string {\n\tvar out bytes.Buffer\n\n\tout.WriteString(\"(\")\n\tout.WriteString(oe.Left.String())\n\tout.WriteString(\" \" + oe.Operator + \" \")\n\tout.WriteString(oe.Right.String())\n\tout.WriteString(\")\")\n\n\treturn out.String()\n}\n\ntype Boolean struct {\n\tToken token.Token\n\tValue bool\n}\n\nfunc (b *Boolean) expressionNode()      {}\nfunc (b *Boolean) TokenLiteral() string { return b.Token.Literal }\nfunc (b *Boolean) String() string       { return b.Token.Literal }\n\ntype IfExpression struct {\n\tToken       token.Token\n\tCondition   Expression\n\tConsequence *BlockStatement\n\tAlternative *BlockStatement\n}\n\nfunc (ie *IfExpression) expressionNode()      {}\nfunc (ie *IfExpression) TokenLiteral() string { return ie.Token.Literal }\nfunc (ie *IfExpression) String() string {\n\tvar out bytes.Buffer\n\tout.WriteString(\"kama\")\n\tout.WriteString(ie.Condition.String())\n\tout.WriteString(\" \")\n\tout.WriteString(ie.Consequence.String())\n\n\tif ie.Alternative != nil {\n\t\tout.WriteString(\"sivyo\")\n\t\tout.WriteString(ie.Alternative.String())\n\t}\n\n\treturn out.String()\n}\n\ntype BlockStatement struct {\n\tToken      token.Token\n\tStatements []Statement\n}\n\nfunc (bs *BlockStatement) statementNode()       {}\nfunc (bs *BlockStatement) TokenLiteral() string { return bs.Token.Literal }\nfunc (bs *BlockStatement) String() string {\n\tvar out bytes.Buffer\n\n\tfor _, s := range bs.Statements {\n\t\tout.WriteString(s.String())\n\t}\n\n\treturn out.String()\n}\n\ntype FunctionLiteral struct {\n\tToken      token.Token\n\tName       string\n\tParameters []*Identifier\n\tDefaults   map[string]Expression\n\tBody       *BlockStatement\n}\n\nfunc (fl *FunctionLiteral) expressionNode()      {}\nfunc (fl *FunctionLiteral) TokenLiteral() string { return fl.Token.Literal }\nfunc (fl *FunctionLiteral) String() string {\n\tvar out bytes.Buffer\n\n\tparams := []string{}\n\n\tfor _, p := range fl.Parameters {\n\t\tparams = append(params, p.String())\n\t}\n\n\tout.WriteString(fl.TokenLiteral())\n\tout.WriteString(\"(\")\n\tout.WriteString(strings.Join(params, \", \"))\n\tout.WriteString(\") \")\n\tout.WriteString(fl.Body.String())\n\n\treturn out.String()\n}\n\ntype CallExpression struct {\n\tToken     token.Token\n\tFunction  Expression // can be Identifier or FunctionLiteral\n\tArguments []Expression\n}\n\nfunc (ce *CallExpression) expressionNode()      {}\nfunc (ce *CallExpression) TokenLiteral() string { return ce.Token.Literal }\nfunc (ce *CallExpression) String() string {\n\tvar out bytes.Buffer\n\n\targs := []string{}\n\tfor _, a := range ce.Arguments {\n\t\targs = append(args, a.String())\n\t}\n\n\tout.WriteString(ce.Function.String())\n\tout.WriteString(\"(\")\n\tout.WriteString(strings.Join(args, \", \"))\n\tout.WriteString(\")\")\n\n\treturn out.String()\n}\n\ntype StringLiteral struct {\n\tToken token.Token\n\tValue string\n}\n\nfunc (sl *StringLiteral) expressionNode()      {}\nfunc (sl *StringLiteral) TokenLiteral() string { return sl.Token.Literal }\nfunc (sl *StringLiteral) String() string       { return sl.Token.Literal }\n\ntype ArrayLiteral struct {\n\tToken    token.Token\n\tElements []Expression\n}\n\nfunc (al *ArrayLiteral) expressionNode()      {}\nfunc (al *ArrayLiteral) TokenLiteral() string { return al.Token.Literal }\nfunc (al *ArrayLiteral) String() string {\n\tvar out bytes.Buffer\n\n\telements := []string{}\n\tfor _, el := range al.Elements {\n\t\telements = append(elements, el.String())\n\t}\n\n\tout.WriteString(\"[\")\n\tout.WriteString(strings.Join(elements, \", \"))\n\tout.WriteString(\"]\")\n\n\treturn out.String()\n}\n\ntype IndexExpression struct {\n\tToken token.Token\n\tLeft  Expression\n\tIndex Expression\n}\n\nfunc (ie *IndexExpression) expressionNode()      {}\nfunc (ie *IndexExpression) TokenLiteral() string { return ie.Token.Literal }\nfunc (ie *IndexExpression) String() string {\n\tvar out bytes.Buffer\n\n\tout.WriteString(\"(\")\n\tout.WriteString(ie.Left.String())\n\tout.WriteString(\"[\")\n\tout.WriteString(ie.Index.String())\n\tout.WriteString(\"])\")\n\n\treturn out.String()\n}\n\ntype DictLiteral struct {\n\tToken token.Token\n\tPairs map[Expression]Expression\n}\n\nfunc (dl *DictLiteral) expressionNode()      {}\nfunc (dl *DictLiteral) TokenLiteral() string { return dl.Token.Literal }\nfunc (dl *DictLiteral) String() string {\n\tvar out bytes.Buffer\n\tpairs := []string{}\n\tfor key, value := range dl.Pairs {\n\t\tpairs = append(pairs, key.String()+\":\"+value.String())\n\t}\n\n\tout.WriteString(\"(\")\n\tout.WriteString(strings.Join(pairs, \", \"))\n\tout.WriteString(\"}\")\n\n\treturn out.String()\n}\n\ntype Assign struct {\n\tToken token.Token\n\tName  *Identifier\n\tValue Expression\n}\n\nfunc (ae *Assign) expressionNode()      {}\nfunc (ae *Assign) TokenLiteral() string { return ae.Token.Literal }\nfunc (ae *Assign) String() string {\n\tvar out bytes.Buffer\n\n\tout.WriteString(ae.Name.String())\n\tout.WriteString(ae.TokenLiteral())\n\tout.WriteString(ae.Value.String())\n\n\treturn out.String()\n}\n\ntype AssignEqual struct {\n\tToken token.Token\n\tLeft  *Identifier\n\tValue Expression\n}\n\nfunc (ae *AssignEqual) expressionNode()      {}\nfunc (ae *AssignEqual) TokenLiteral() string { return ae.Token.Literal }\nfunc (ae *AssignEqual) String() string {\n\tvar out bytes.Buffer\n\n\tout.WriteString(ae.Left.String())\n\tout.WriteString(ae.TokenLiteral())\n\tout.WriteString(ae.Value.String())\n\n\treturn out.String()\n}\n\ntype AssignmentExpression struct {\n\tToken token.Token\n\tLeft  Expression\n\tValue Expression\n}\n\nfunc (ae *AssignmentExpression) expressionNode()      {}\nfunc (ae *AssignmentExpression) TokenLiteral() string { return ae.Token.Literal }\nfunc (ae *AssignmentExpression) String() string {\n\tvar out bytes.Buffer\n\n\tout.WriteString(ae.Left.String())\n\tout.WriteString(ae.TokenLiteral())\n\tout.WriteString(ae.Value.String())\n\n\treturn out.String()\n}\n\ntype WhileExpression struct {\n\tToken       token.Token\n\tCondition   Expression\n\tConsequence *BlockStatement\n}\n\nfunc (we *WhileExpression) expressionNode()      {}\nfunc (we *WhileExpression) TokenLiteral() string { return we.Token.Literal }\nfunc (we *WhileExpression) String() string {\n\tvar out bytes.Buffer\n\n\tout.WriteString(\"wakati\")\n\tout.WriteString(we.Condition.String())\n\tout.WriteString(\" \")\n\tout.WriteString(we.Consequence.String())\n\n\treturn out.String()\n}\n\ntype Null struct {\n\tToken token.Token\n}\n\nfunc (n *Null) expressionNode()      {}\nfunc (n *Null) TokenLiteral() string { return n.Token.Literal }\nfunc (n *Null) String() string       { return n.Token.Literal }\n\ntype Break struct {\n\tStatement\n\tToken token.Token // the 'break' token\n}\n\nfunc (b *Break) expressionNode()      {}\nfunc (b *Break) TokenLiteral() string { return b.Token.Literal }\nfunc (b *Break) String() string       { return b.Token.Literal }\n\ntype Continue struct {\n\tStatement\n\tToken token.Token // the 'continue' token\n}\n\nfunc (c *Continue) expressionNode()      {}\nfunc (c *Continue) TokenLiteral() string { return c.Token.Literal }\nfunc (c *Continue) String() string       { return c.Token.Literal }\n\ntype PostfixExpression struct {\n\tToken    token.Token\n\tOperator string\n}\n\nfunc (pe *PostfixExpression) expressionNode()      {}\nfunc (pe *PostfixExpression) TokenLiteral() string { return pe.Token.Literal }\nfunc (pe *PostfixExpression) String() string {\n\tvar out bytes.Buffer\n\tout.WriteString(\"(\")\n\tout.WriteString(pe.Token.Literal)\n\tout.WriteString(pe.Operator)\n\tout.WriteString(\")\")\n\treturn out.String()\n}\n\ntype FloatLiteral struct {\n\tToken token.Token\n\tValue float64\n}\n\nfunc (fl *FloatLiteral) expressionNode()      {}\nfunc (fl *FloatLiteral) TokenLiteral() string { return fl.Token.Literal }\nfunc (fl *FloatLiteral) String() string       { return fl.Token.Literal }\n\ntype For struct {\n\tToken        token.Token\n\tIdentifier   string      // \"i\"\n\tStarterName  *Identifier // i = 0\n\tStarterValue Expression\n\tCloser       Expression // i++\n\tCondition    Expression // i < 1\n\tBlock        *BlockStatement\n}\n\ntype ForIn struct {\n\tToken    token.Token\n\tKey      string\n\tValue    string\n\tIterable Expression\n\tBlock    *BlockStatement\n}\n\nfunc (fi *ForIn) expressionNode()      {}\nfunc (fi *ForIn) TokenLiteral() string { return fi.Token.Literal }\nfunc (fi *ForIn) String() string {\n\tvar out bytes.Buffer\n\n\tout.WriteString(\"kwa \")\n\tif fi.Key != \"\" {\n\t\tout.WriteString(fi.Key + \", \")\n\t}\n\tout.WriteString(fi.Value + \" \")\n\tout.WriteString(\"ktk \")\n\tout.WriteString(fi.Iterable.String() + \" {\\n\")\n\tout.WriteString(\"\\t\" + fi.Block.String())\n\tout.WriteString(\"\\n}\")\n\n\treturn out.String()\n}\n\ntype CaseExpression struct {\n\tToken   token.Token\n\tDefault bool\n\tExpr    []Expression\n\tBlock   *BlockStatement\n}\n\nfunc (ce *CaseExpression) expressionNode()      {}\nfunc (ce *CaseExpression) TokenLiteral() string { return ce.Token.Literal }\nfunc (ce *CaseExpression) String() string {\n\tvar out bytes.Buffer\n\n\tif ce.Default {\n\t\tout.WriteString(\"kawaida \")\n\t} else {\n\t\tout.WriteString(\"ikiwa \")\n\n\t\ttmp := []string{}\n\t\tfor _, exp := range ce.Expr {\n\t\t\ttmp = append(tmp, exp.String())\n\t\t}\n\t\tout.WriteString(strings.Join(tmp, \",\"))\n\t}\n\tout.WriteString(ce.Block.String())\n\treturn out.String()\n}\n\ntype SwitchExpression struct {\n\tToken   token.Token\n\tValue   Expression\n\tChoices []*CaseExpression\n}\n\nfunc (se *SwitchExpression) expressionNode()      {}\nfunc (se *SwitchExpression) TokenLiteral() string { return se.Token.Literal }\nfunc (se *SwitchExpression) String() string {\n\tvar out bytes.Buffer\n\tout.WriteString(\"\\nbadili (\")\n\tout.WriteString(se.Value.String())\n\tout.WriteString(\")\\n{\\n\")\n\n\tfor _, tmp := range se.Choices {\n\t\tif tmp != nil {\n\t\t\tout.WriteString(tmp.String())\n\t\t}\n\t}\n\tout.WriteString(\"}\\n\")\n\n\treturn out.String()\n}\n\ntype MethodExpression struct {\n\tToken     token.Token\n\tObject    Expression\n\tMethod    Expression\n\tArguments []Expression\n\tDefaults  map[string]Expression\n}\n\nfunc (me *MethodExpression) expressionNode()      {}\nfunc (me *MethodExpression) TokenLiteral() string { return me.Token.Literal }\nfunc (me *MethodExpression) String() string {\n\tvar out bytes.Buffer\n\tout.WriteString(me.Object.String())\n\tout.WriteString(\".\")\n\tout.WriteString(me.Method.String())\n\n\treturn out.String()\n}\n\ntype Import struct {\n\tToken       token.Token\n\tIdentifiers map[string]*Identifier\n}\n\nfunc (i *Import) expressionNode()      {}\nfunc (i *Import) TokenLiteral() string { return i.Token.Literal }\nfunc (i *Import) String() string {\n\tvar out bytes.Buffer\n\tout.WriteString(\"tumia \")\n\tfor k := range i.Identifiers {\n\t\tout.WriteString(k + \" \")\n\t}\n\treturn out.String()\n}\n\ntype PackageBlock struct {\n\tToken      token.Token\n\tStatements []Statement\n}\n\nfunc (pb *PackageBlock) statementNode()       {}\nfunc (pb *PackageBlock) TokenLiteral() string { return pb.Token.Literal }\nfunc (pb *PackageBlock) String() string {\n\tvar out bytes.Buffer\n\n\tfor _, s := range pb.Statements {\n\t\tout.WriteString(s.String())\n\t}\n\n\treturn out.String()\n}\n\ntype Package struct {\n\tToken token.Token\n\tName  *Identifier\n\tBlock *BlockStatement\n}\n\nfunc (p *Package) expressionNode()      {}\nfunc (p *Package) TokenLiteral() string { return p.Token.Literal }\nfunc (p *Package) String() string {\n\tvar out bytes.Buffer\n\n\tout.WriteString(\"pakeji \" + p.Name.Value + \"\\n\")\n\tout.WriteString(\"::\\n\")\n\tfor _, s := range p.Block.Statements {\n\t\tout.WriteString(s.String())\n\t}\n\tout.WriteString(\"\\n::\")\n\n\treturn out.String()\n}\n\ntype At struct {\n\tToken token.Token\n}\n\nfunc (a *At) expressionNode()      {}\nfunc (a *At) TokenLiteral() string { return a.Token.Literal }\nfunc (a *At) String() string       { return \"@\" }\n\ntype PropertyAssignment struct {\n\tToken token.Token // the '=' token\n\tName  *PropertyExpression\n\tValue Expression\n}\n\nfunc (pa *PropertyAssignment) expressionNode()      {}\nfunc (pa *PropertyAssignment) TokenLiteral() string { return pa.Token.Literal }\nfunc (pa *PropertyAssignment) String() string       { return \"Ngl I'm tired\" }\n\ntype PropertyExpression struct {\n\tExpression\n\tToken    token.Token // The . token\n\tObject   Expression\n\tProperty Expression\n}\n\nfunc (pe *PropertyExpression) expressionNode()      {}\nfunc (pe *PropertyExpression) TokenLiteral() string { return pe.Token.Literal }\nfunc (pe *PropertyExpression) String() string       { return \"Ngl I'm tired part two\" }\n"
  },
  {
    "path": "ast/ast_test.go",
    "content": "package ast\n\nimport (\n\t\"testing\"\n\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc TestString(t *testing.T) {\n\tprogram := &Program{\n\t\tStatements: []Statement{\n\t\t\t&LetStatement{\n\t\t\t\tToken: token.Token{Type: token.LET, Literal: \"fanya\"},\n\t\t\t\tName: &Identifier{\n\t\t\t\t\tToken: token.Token{Type: token.IDENT, Literal: \"myVar\"},\n\t\t\t\t\tValue: \"myVar\",\n\t\t\t\t},\n\t\t\t\tValue: &Identifier{\n\t\t\t\t\tToken: token.Token{Type: token.IDENT, Literal: \"anotherVar\"},\n\t\t\t\t\tValue: \"anotherVar\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif program.String() != \"fanya myVar = anotherVar;\" {\n\t\tt.Errorf(\"program.String() wrong. got=%q\", program.String())\n\t}\n}\n"
  },
  {
    "path": "evaluator/assign.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalAssign(node *ast.Assign, env *object.Environment) object.Object {\n\tval := Eval(node.Value, env)\n\tif isError(val) {\n\t\treturn val\n\t}\n\n\tobj := env.Set(node.Name.Value, val)\n\treturn obj\n}\n"
  },
  {
    "path": "evaluator/assignEqual.go",
    "content": "package evaluator\n\nimport (\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalAssignEqual(node *ast.AssignEqual, env *object.Environment) object.Object {\n\tleft := Eval(node.Left, env)\n\tif isError(left) {\n\t\treturn left\n\t}\n\n\tvalue := Eval(node.Value, env)\n\tif isError(value) {\n\t\treturn value\n\t}\n\n\tswitch node.Token.Literal {\n\tcase \"+=\":\n\t\tswitch arg := left.(type) {\n\t\tcase *object.Integer:\n\t\t\tswitch val := value.(type) {\n\t\t\tcase *object.Integer:\n\t\t\t\tv := arg.Value + val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Integer{Value: v})\n\t\t\tcase *object.Float:\n\t\t\t\tv := float64(arg.Value) + val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Float{Value: v})\n\t\t\tdefault:\n\t\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '+=' kujumlisha %v na %v\", node.Token.Line, arg.Type(), val.Type())\n\t\t\t}\n\t\tcase *object.Float:\n\t\t\tswitch val := value.(type) {\n\t\t\tcase *object.Integer:\n\t\t\t\tv := arg.Value + float64(val.Value)\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Float{Value: v})\n\t\t\tcase *object.Float:\n\t\t\t\tv := arg.Value + val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Float{Value: v})\n\t\t\tdefault:\n\t\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '+=' kujumlisha %v na %v\", node.Token.Line, arg.Type(), val.Type())\n\t\t\t}\n\t\tcase *object.String:\n\t\t\tswitch val := value.(type) {\n\t\t\tcase *object.String:\n\t\t\t\tv := arg.Value + val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.String{Value: v})\n\t\t\tdefault:\n\t\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '+=' kwa %v na %v\", node.Token.Line, arg.Type(), val.Type())\n\t\t\t}\n\t\tdefault:\n\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '+=' na %v\", node.Token.Line, arg.Type())\n\t\t}\n\tcase \"-=\":\n\t\tswitch arg := left.(type) {\n\t\tcase *object.Integer:\n\t\t\tswitch val := value.(type) {\n\t\t\tcase *object.Integer:\n\t\t\t\tv := arg.Value - val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Integer{Value: v})\n\t\t\tcase *object.Float:\n\t\t\t\tv := float64(arg.Value) - val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Float{Value: v})\n\t\t\tdefault:\n\t\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '-=' kujumlisha %v na %v\", node.Token.Line, arg.Type(), val.Type())\n\t\t\t}\n\t\tcase *object.Float:\n\t\t\tswitch val := value.(type) {\n\t\t\tcase *object.Integer:\n\t\t\t\tv := arg.Value - float64(val.Value)\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Float{Value: v})\n\t\t\tcase *object.Float:\n\t\t\t\tv := arg.Value - val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Float{Value: v})\n\t\t\tdefault:\n\t\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '-=' kujumlisha %v na %v\", node.Token.Line, arg.Type(), val.Type())\n\t\t\t}\n\t\tdefault:\n\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '-=' na %v\", node.Token.Line, arg.Type())\n\t\t}\n\tcase \"*=\":\n\t\tswitch arg := left.(type) {\n\t\tcase *object.Integer:\n\t\t\tswitch val := value.(type) {\n\t\t\tcase *object.Integer:\n\t\t\t\tv := arg.Value * val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Integer{Value: v})\n\t\t\tcase *object.Float:\n\t\t\t\tv := float64(arg.Value) * val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Float{Value: v})\n\t\t\tcase *object.String:\n\t\t\t\tv := strings.Repeat(val.Value, int(arg.Value))\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.String{Value: v})\n\t\t\tdefault:\n\t\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '*=' kujumlisha %v na %v\", node.Token.Line, arg.Type(), val.Type())\n\t\t\t}\n\t\tcase *object.Float:\n\t\t\tswitch val := value.(type) {\n\t\t\tcase *object.Integer:\n\t\t\t\tv := arg.Value * float64(val.Value)\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Float{Value: v})\n\t\t\tcase *object.Float:\n\t\t\t\tv := arg.Value * val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Float{Value: v})\n\t\t\tdefault:\n\t\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '*=' kujumlisha %v na %v\", node.Token.Line, arg.Type(), val.Type())\n\t\t\t}\n\t\tcase *object.String:\n\t\t\tswitch val := value.(type) {\n\t\t\tcase *object.Integer:\n\t\t\t\tv := strings.Repeat(arg.Value, int(val.Value))\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.String{Value: v})\n\t\t\tdefault:\n\t\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '+=' kwa %v na %v\", node.Token.Line, arg.Type(), val.Type())\n\t\t\t}\n\t\tdefault:\n\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '*=' na %v\", node.Token.Line, arg.Type())\n\t\t}\n\tcase \"/=\":\n\t\tswitch arg := left.(type) {\n\t\tcase *object.Integer:\n\t\t\tswitch val := value.(type) {\n\t\t\tcase *object.Integer:\n\t\t\t\tv := arg.Value / val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Integer{Value: v})\n\t\t\tcase *object.Float:\n\t\t\t\tv := float64(arg.Value) / val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Float{Value: v})\n\t\t\tdefault:\n\t\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '/=' kujumlisha %v na %v\", node.Token.Line, arg.Type(), val.Type())\n\t\t\t}\n\t\tcase *object.Float:\n\t\t\tswitch val := value.(type) {\n\t\t\tcase *object.Integer:\n\t\t\t\tv := arg.Value / float64(val.Value)\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Float{Value: v})\n\t\t\tcase *object.Float:\n\t\t\t\tv := arg.Value / val.Value\n\t\t\t\treturn env.Set(node.Left.Token.Literal, &object.Float{Value: v})\n\t\t\tdefault:\n\t\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '/=' kujumlisha %v na %v\", node.Token.Line, arg.Type(), val.Type())\n\t\t\t}\n\t\tdefault:\n\t\t\treturn newError(\"Mstari %d: Huwezi kutumia '/=' na %v\", node.Token.Line, arg.Type())\n\t\t}\n\tdefault:\n\t\treturn newError(\"Mstari %d: Operesheni Haifahamiki  %s\", node.Token.Line, node.Token.Literal)\n\t}\n}\n"
  },
  {
    "path": "evaluator/at.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalAt(node *ast.At, env *object.Environment) object.Object {\n\tif at, ok := env.Get(\"@\"); ok {\n\t\treturn at\n\t}\n\treturn newError(\"Iko nje ya scope\")\n}\n"
  },
  {
    "path": "evaluator/bang.go",
    "content": "package evaluator\n\nimport \"github.com/NuruProgramming/Nuru/object\"\n\nfunc evalBangOperatorExpression(right object.Object) object.Object {\n\tswitch right {\n\tcase TRUE:\n\t\treturn FALSE\n\tcase FALSE:\n\t\treturn TRUE\n\tcase NULL:\n\t\treturn TRUE\n\tdefault:\n\t\treturn FALSE\n\t}\n}\n"
  },
  {
    "path": "evaluator/block.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalBlockStatement(block *ast.BlockStatement, env *object.Environment) object.Object {\n\tvar result object.Object\n\n\tfor _, statement := range block.Statements {\n\t\tresult = Eval(statement, env)\n\n\t\tif result != nil {\n\t\t\trt := result.Type()\n\t\t\tif rt == object.RETURN_VALUE_OBJ || rt == object.ERROR_OBJ || rt == object.CONTINUE_OBJ || rt == object.BREAK_OBJ {\n\t\t\t\treturn result\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "evaluator/builtins.go",
    "content": "//go:build !js || !wasm \n\npackage evaluator\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nvar builtins = map[string]*object.Builtin{\n\t\"jaza\": {\n\t\tFn: func(args ...object.Object) object.Object {\n\n\t\t\tif len(args) > 1 {\n\t\t\t\treturn newError(\"Samahani, kiendesha hiki kinapokea hoja 0 au 1, wewe umeweka %d\", len(args))\n\t\t\t}\n\n\t\t\tif len(args) > 0 && args[0].Type() != object.STRING_OBJ {\n\t\t\t\treturn newError(fmt.Sprintf(`Tafadhali tumia alama ya nukuu: \"%s\"`, args[0].Inspect()))\n\t\t\t}\n\t\t\tif len(args) == 1 {\n\t\t\t\tprompt := args[0].(*object.String).Value\n\t\t\t\tfmt.Fprint(os.Stdout, prompt)\n\t\t\t}\n\n\t\t\tbuffer := bufio.NewReader(os.Stdin)\n\n\t\t\tline, _, err := buffer.ReadLine()\n\t\t\tif err != nil && err != io.EOF {\n\t\t\t\treturn newError(\"Nimeshindwa kusoma uliyo yajaza\")\n\t\t\t}\n\n\t\t\treturn &object.String{Value: string(line)}\n\t\t},\n\t},\n\t\"andika\": {\n\t\tFn: func(args ...object.Object) object.Object {\n\t\t\tif len(args) == 0 {\n\t\t\t\tfmt.Println(\"\")\n\t\t\t} else {\n\t\t\t\tvar arr []string\n\t\t\t\tfor _, arg := range args {\n\t\t\t\t\tif arg == nil {\n\t\t\t\t\t\treturn newError(\"Hauwezi kufanya operesheni hii\")\n\t\t\t\t\t}\n\t\t\t\t\tarr = append(arr, arg.Inspect())\n\t\t\t\t}\n\t\t\t\tstr := strings.Join(arr, \" \")\n\t\t\t\tfmt.Println(str)\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t},\n\t\"_andika\": {\n\t\tFn: func(args ...object.Object) object.Object {\n\t\t\tif len(args) == 0 {\n\t\t\t\treturn &object.String{Value: \"\\n\"}\n\t\t\t} else {\n\t\t\t\tvar arr []string\n\t\t\t\tfor _, arg := range args {\n\t\t\t\t\tif arg == nil {\n\t\t\t\t\t\treturn newError(\"Hauwezi kufanya operesheni hii\")\n\t\t\t\t\t}\n\t\t\t\t\tarr = append(arr, arg.Inspect())\n\t\t\t\t}\n\t\t\t\tstr := strings.Join(arr, \" \")\n\t\t\t\treturn &object.String{Value: str}\n\t\t\t}\n\t\t},\n\t},\n\n}\n\nfunc init(){\n\tfor name, builtin := range commonBuiltins{\n\t\tbuiltins[name]=builtin\n\t}\n}"
  },
  {
    "path": "evaluator/builtins_common.go",
    "content": "package evaluator\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nvar commonBuiltins = map[string]*object.Builtin{\n\t\"_andika\": {\n\t\tFn: func(args ...object.Object) object.Object {\n\t\t\tif len(args) == 0 {\n\t\t\t\treturn &object.String{Value: \"\\n\"}\n\t\t\t} else {\n\t\t\t\tvar arr []string\n\t\t\t\tfor _, arg := range args {\n\t\t\t\t\tif arg == nil {\n\t\t\t\t\t\treturn newError(\"Hauwezi kufanya operesheni hii\")\n\t\t\t\t\t}\n\t\t\t\t\tarr = append(arr, arg.Inspect())\n\t\t\t\t}\n\t\t\t\tstr := strings.Join(arr, \" \")\n\t\t\t\treturn &object.String{Value: str}\n\t\t\t}\n\t\t},\n\t},\n\t\"aina\": {\n\t\tFn: func(args ...object.Object) object.Object {\n\t\t\tif len(args) != 1 {\n\t\t\t\treturn newError(\"Samahani, tunahitaji hoja 1, wewe umeweka %d\", len(args))\n\t\t\t}\n\n\t\t\treturn &object.String{Value: string(args[0].Type())}\n\t\t},\n\t},\n\t\"fungua\": {\n\t\tFn: func(args ...object.Object) object.Object {\n\n\t\t\tif len(args) != 1 {\n\t\t\t\treturn newError(\"Samahani, tunahitaji hoja 1, wewe umeweka %d\", len(args))\n\t\t\t}\n\t\t\tfilename := args[0].(*object.String).Value\n\n\t\t\tfile, err := os.ReadFile(filename)\n\t\t\tif err != nil {\n\t\t\t\treturn &object.Error{Message: \"Tumeshindwa kusoma faili au faili halipo\"}\n\t\t\t}\n\t\t\treturn &object.File{Filename: filename, Content: string(file)}\n\t\t},\n\t},\n\t\"mfululizo\": {\n\t\tFn: func(args ...object.Object) object.Object {\n\t\t\tif len(args) < 1 || len(args) > 3 {\n\t\t\t\treturn newError(\"Samahani, mfululizo inahitaji hoja 1 hadi 3, wewe umeweka %d\", len(args))\n\t\t\t}\n\n\t\t\tvar start, end, step int64\n\t\t\tvar err error\n\n\t\t\tswitch len(args) {\n\t\t\tcase 1:\n\t\t\t\tend, err = getIntValue(args[0])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn newError(\"Hoja lazima iwe nambari nzima\")\n\t\t\t\t}\n\t\t\t\tstart, step = 0, 1\n\t\t\tcase 2:\n\t\t\t\tstart, err = getIntValue(args[0])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn newError(\"Hoja ya kwanza lazima iwe nambari nzima\")\n\t\t\t\t}\n\t\t\t\tend, err = getIntValue(args[1])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn newError(\"Hoja ya pili lazima iwe nambari nzima\")\n\t\t\t\t}\n\t\t\t\tstep = 1\n\t\t\tcase 3:\n\t\t\t\tstart, err = getIntValue(args[0])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn newError(\"Hoja ya kwanza lazima iwe nambari nzima\")\n\t\t\t\t}\n\t\t\t\tend, err = getIntValue(args[1])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn newError(\"Hoja ya pili lazima iwe nambari nzima\")\n\t\t\t\t}\n\t\t\t\tstep, err = getIntValue(args[2])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn newError(\"Hoja ya tatu lazima iwe nambari nzima\")\n\t\t\t\t}\n\t\t\t\tif step == 0 {\n\t\t\t\t\treturn newError(\"Hatua haiwezi kuwa sifuri\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\telements := []object.Object{}\n\t\t\tfor i := start; (step > 0 && i < end) || (step < 0 && i > end); i += step {\n\t\t\t\telements = append(elements, &object.Integer{Value: i})\n\t\t\t}\n\n\t\t\treturn &object.Array{Elements: elements}\n\t\t},\n\t},\n\n\t\"badilisha\": {\n\t\tFn: func(args ...object.Object) object.Object {\n\t\t\tif len(args) != 2 {\n\t\t\t\treturn newError(\"Samahani, badili inahitaji hoja 2, wewe umeweka %d\", len(args))\n\t\t\t}\n\n\t\t\tvalue := args[0]\n\t\t\ttargetType := args[1]\n\n\t\t\tif targetType.Type() != object.STRING_OBJ {\n\t\t\t\treturn newError(\"Aina ya lengo lazima iwe neno\")\n\t\t\t}\n\n\t\t\ttargetTypeStr := targetType.(*object.String).Value\n\n\t\t\tswitch targetTypeStr {\n\t\t\tcase \"NAMBA\":\n\t\t\t\treturn convertToInteger(value)\n\t\t\tcase \"DESIMALI\":\n\t\t\t\treturn convertToFloat(value)\n\t\t\tcase \"NENO\":\n\t\t\t\treturn convertToString(value)\n\t\t\tcase \"BOOLEAN\":\n\t\t\t\treturn convertToBoolean(value)\n\t\t\tdefault:\n\t\t\t\treturn newError(\"Aina isiyojulikana: %s\", targetTypeStr)\n\t\t\t}\n\t\t},\n\t},\n\t\"namba\": {\n\t\tFn: func(args ...object.Object) object.Object {\n\t\t\tif len(args) != 1 {\n\t\t\t\treturn newError(\"Samahani, namba inahitaji hoja 1, wewe umeweka %d\", len(args))\n\t\t\t}\n\t\t\tvalue := args[0]\n\t\t\treturn convertToInteger(value)\n\t\t},\n\t},\n\t\"tungo\": {\n\t\tFn: func(args ...object.Object) object.Object {\n\t\t\tif len(args) != 1 {\n\t\t\t\treturn newError(\"Samahani, tungo inahitaji hoja 1, wewe umeweka %d\", len(args))\n\t\t\t}\n\t\t\tvalue := args[0]\n\t\t\treturn convertToString(value)\n\t\t},\n\t},\n\n\t// \"jumla\": {\n\t// \tFn: func(args ...object.Object) object.Object {\n\t// \t\tif len(args) != 1 {\n\t// \t\t\treturn newError(\"Hoja hazilingani, tunahitaji=1, tumepewa=%d\", len(args))\n\t// \t\t}\n\n\t// \t\tswitch arg := args[0].(type) {\n\t// \t\tcase *object.Array:\n\n\t// \t\t\tvar sums float64\n\t// \t\t\tfor _, num := range arg.Elements {\n\n\t// \t\t\t\tif num.Type() != object.INTEGER_OBJ && num.Type() != object.FLOAT_OBJ {\n\t// \t\t\t\t\treturn newError(\"Samahani namba tu zinahitajika\")\n\t// \t\t\t\t} else {\n\t// \t\t\t\t\tif num.Type() == object.INTEGER_OBJ {\n\t// \t\t\t\t\t\tno, _ := strconv.Atoi(num.Inspect())\n\t// \t\t\t\t\t\tfloatnum := float64(no)\n\t// \t\t\t\t\t\tsums += floatnum\n\t// \t\t\t\t\t} else if num.Type() == object.FLOAT_OBJ {\n\t// \t\t\t\t\t\tno, _ := strconv.ParseFloat(num.Inspect(), 64)\n\t// \t\t\t\t\t\tsums += no\n\t// \t\t\t\t\t}\n\n\t// \t\t\t\t}\n\t// \t\t\t}\n\n\t// \t\t\tif math.Mod(sums, 1) == 0 {\n\t// \t\t\t\treturn &object.Integer{Value: int64(sums)}\n\t// \t\t\t}\n\n\t// \t\t\treturn &object.Float{Value: float64(sums)}\n\n\t// \t\tdefault:\n\t// \t\t\treturn newError(\"Samahani, hii function haitumiki na %s\", args[0].Type())\n\t// \t\t}\n\t// \t},\n\t// },\n}\n\nfunc getIntValue(obj object.Object) (int64, error) {\n\tswitch obj := obj.(type) {\n\tcase *object.Integer:\n\t\treturn obj.Value, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"expected integer, got %T\", obj)\n\t}\n}\n"
  },
  {
    "path": "evaluator/builtins_wasm.go",
    "content": "//go:build wasm && js\n\n// Modified version with of the builtins.go file with browser friendly versions of functions.\npackage evaluator\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n\t\"syscall/js\"\n)\n\nvar builtins = map[string]*object.Builtin{\n\t\"jaza\": {\n\t\tFn: func(args ...object.Object) object.Object {\n\n\t\t\tif len(args) > 1 {\n\t\t\t\treturn newError(\"Samahani, kiendesha hiki kinapokea hoja 0 au 1, wewe umeweka %d\", len(args))\n\t\t\t}\n\n\t\t\tif len(args) == 1 && args[0].Type() != object.STRING_OBJ {\n\t\t\t\treturn newError(fmt.Sprintf(`Tafadhali tumia alama ya nukuu: \"%s\"`, args[0].Inspect()))\n\t\t\t}\n\n\t\t\t// Get the window.prompt function\n\t\t\tjsPromptFunction := js.Global().Get(\"prompt\")\n\t\t\tif jsPromptFunction.Type() != js.TypeFunction {\n\t\t\t\treturn newError(\"prompt function not found\")\n\t\t\t}\n\n\t\t\t// invoke it!!\n\t\t\tvar result js.Value\n\t\t\tif len(args) == 0 {\n\t\t\t\tresult = jsPromptFunction.Invoke()\n\t\t\t} else {\n\t\t\t\tresult = jsPromptFunction.Invoke(args[0].Inspect())\n\t\t\t}\n\n\t\t\tif result.String() == \"\"|| result.String() == \"null\" {\n\t\t\t\treturn newError(\"Nimeshindwa kusoma uliyo yajaza\")\n\t\t\t}\n\n\t\t\treturn &object.String{Value: string(result.String())}\n\t\t},\n\t},\n\t\"andika\": {\n\t\tFn: func(args ...object.Object) object.Object {\n\t\t\tjsOutputReceiverFunction := js.Global().Get(\"nuruOutputReceiver\")\n\t\t\tif len(args) == 0 {\n\t\t\t\tjsOutputReceiverFunction.Invoke(\"\")\n\t\t\t} else {\n\t\t\t\tvar arr []string\n\t\t\t\tfor _, arg := range args {\n\t\t\t\t\tif arg == nil {\n\t\t\t\t\t\treturn newError(\"Hauwezi kufanya operesheni hii\")\n\t\t\t\t\t}\n\t\t\t\t\tarr = append(arr, arg.Inspect())\n\t\t\t\t}\n\t\t\t\tstr := strings.Join(arr, \" \")\n\t\t\t\tjsOutputReceiverFunction.Invoke(str) // pipe output to js land\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t},\n}\n\nfunc init(){\n\tfor name, builtin := range commonBuiltins{\n\t\tbuiltins[name]=builtin\n\t}\n}"
  },
  {
    "path": "evaluator/call.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalCall(node *ast.CallExpression, env *object.Environment) object.Object {\n\tfunction := Eval(node.Function, env)\n\n\tif isError(function) {\n\t\treturn function\n\t}\n\n\tvar args []object.Object\n\n\tswitch fn := function.(type) {\n\tcase *object.Function:\n\t\targs = evalArgsExpressions(node, fn, env)\n\tcase *object.Package:\n\t\tobj, ok := fn.Scope.Get(\"andaa\")\n\t\tif !ok {\n\t\t\treturn newError(\"Pakeji haina 'andaa'\")\n\t\t}\n\t\targs = evalArgsExpressions(node, obj.(*object.Function), env)\n\tdefault:\n\t\targs = evalExpressions(node.Arguments, env)\n\t}\n\n\tif len(args) == 1 && isError(args[0]) {\n\t\treturn args[0]\n\t}\n\n\treturn applyFunction(function, args, node.Token.Line)\n}\n\nfunc evalArgsExpressions(node *ast.CallExpression, fn *object.Function, env *object.Environment) []object.Object {\n\targsList := &object.Array{}\n\targsHash := &object.Dict{}\n\targsHash.Pairs = make(map[object.HashKey]object.DictPair)\n\tfor _, exprr := range node.Arguments {\n\t\tswitch exp := exprr.(type) {\n\t\tcase *ast.Assign:\n\t\t\tval := Eval(exp.Value, env)\n\t\t\tif isError(val) {\n\t\t\t\treturn []object.Object{val}\n\t\t\t}\n\t\t\tvar keyHash object.HashKey\n\t\t\tkey := &object.String{Value: exp.Name.Value}\n\t\t\tkeyHash = key.HashKey()\n\t\t\tpair := object.DictPair{Key: key, Value: val}\n\t\t\targsHash.Pairs[keyHash] = pair\n\t\tdefault:\n\t\t\tevaluated := Eval(exp, env)\n\t\t\tif isError(evaluated) {\n\t\t\t\treturn []object.Object{evaluated}\n\t\t\t}\n\t\t\targsList.Elements = append(argsList.Elements, evaluated)\n\t\t}\n\t}\n\n\tvar result []object.Object\n\tvar params = map[string]bool{}\n\tfor _, exp := range fn.Parameters {\n\t\tparams[exp.Value] = true\n\t\tif len(argsList.Elements) > 0 {\n\t\t\tresult = append(result, argsList.Elements[0])\n\t\t\targsList.Elements = argsList.Elements[1:]\n\t\t} else {\n\t\t\tkeyParam := &object.String{Value: exp.Value}\n\t\t\tkeyParamHash := keyParam.HashKey()\n\t\t\tif valParam, ok := argsHash.Pairs[keyParamHash]; ok {\n\t\t\t\tresult = append(result, valParam.Value)\n\t\t\t\tdelete(argsHash.Pairs, keyParamHash)\n\t\t\t} else {\n\t\t\t\tif _e, _ok := fn.Defaults[exp.Value]; _ok {\n\t\t\t\t\tevaluated := Eval(_e, env)\n\t\t\t\t\tif isError(evaluated) {\n\t\t\t\t\t\treturn []object.Object{evaluated}\n\t\t\t\t\t}\n\t\t\t\t\tresult = append(result, evaluated)\n\t\t\t\t} else {\n\t\t\t\t\treturn []object.Object{&object.Error{Message: \"Tumekosa Hoja\"}}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, pair := range argsHash.Pairs {\n\t\tif _, ok := params[pair.Key.(*object.String).Value]; ok {\n\t\t\treturn []object.Object{&object.Error{Message: \"Tumepewa hoja nyingi kwa parameter moja\"}}\n\t\t}\n\t}\n\n\treturn result\n\n}\n"
  },
  {
    "path": "evaluator/dict.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalDictLiteral(node *ast.DictLiteral, env *object.Environment) object.Object {\n\tpairs := make(map[object.HashKey]object.DictPair)\n\n\tfor keyNode, valueNode := range node.Pairs {\n\t\tkey := Eval(keyNode, env)\n\t\tif isError(key) {\n\t\t\treturn key\n\t\t}\n\n\t\thashKey, ok := key.(object.Hashable)\n\t\tif !ok {\n\t\t\treturn newError(\"Mstari %d: Hashing imeshindikana: %s\", node.Token.Line, key.Type())\n\t\t}\n\n\t\tvalue := Eval(valueNode, env)\n\t\tif isError(value) {\n\t\t\treturn value\n\t\t}\n\n\t\thashed := hashKey.HashKey()\n\t\tpairs[hashed] = object.DictPair{Key: key, Value: value}\n\t}\n\n\treturn &object.Dict{Pairs: pairs}\n}\n"
  },
  {
    "path": "evaluator/error_handler.go",
    "content": "package evaluator\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc newError(format string, a ...interface{}) *object.Error {\n\treturn &object.Error{Message: fmt.Sprintf(format, a...)}\n}\n"
  },
  {
    "path": "evaluator/evaluator.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nvar (\n\tNULL     = &object.Null{}\n\tTRUE     = &object.Boolean{Value: true}\n\tFALSE    = &object.Boolean{Value: false}\n\tBREAK    = &object.Break{}\n\tCONTINUE = &object.Continue{}\n)\n\nfunc Eval(node ast.Node, env *object.Environment) object.Object {\n\tswitch node := node.(type) {\n\tcase *ast.Program:\n\t\treturn evalProgram(node, env)\n\n\tcase *ast.ExpressionStatement:\n\t\treturn Eval(node.Expression, env)\n\n\tcase *ast.IntegerLiteral:\n\t\treturn &object.Integer{Value: node.Value}\n\n\tcase *ast.FloatLiteral:\n\t\treturn &object.Float{Value: node.Value}\n\n\tcase *ast.Boolean:\n\t\treturn nativeBoolToBooleanObject(node.Value)\n\n\tcase *ast.PrefixExpression:\n\t\tright := Eval(node.Right, env)\n\t\tif isError(right) {\n\t\t\treturn right\n\t\t}\n\t\treturn evalPrefixExpression(node.Operator, right, node.Token.Line)\n\n\tcase *ast.InfixExpression:\n\t\tleft := Eval(node.Left, env)\n\t\tif isError(left) {\n\t\t\treturn left\n\t\t}\n\t\tright := Eval(node.Right, env)\n\t\tif isError(right) && right != nil {\n\t\t\treturn right\n\t\t}\n\t\treturn evalInfixExpression(node.Operator, left, right, node.Token.Line)\n\tcase *ast.PostfixExpression:\n\t\treturn evalPostfixExpression(env, node.Operator, node)\n\n\tcase *ast.BlockStatement:\n\t\treturn evalBlockStatement(node, env)\n\n\tcase *ast.IfExpression:\n\t\treturn evalIfExpression(node, env)\n\n\tcase *ast.ReturnStatement:\n\t\tval := Eval(node.ReturnValue, env)\n\t\tif isError(val) {\n\t\t\treturn val\n\t\t}\n\t\treturn &object.ReturnValue{Value: val}\n\n\tcase *ast.LetStatement:\n\t\tval := Eval(node.Value, env)\n\t\tif isError(val) {\n\t\t\treturn val\n\t\t}\n\n\t\tenv.Set(node.Name.Value, val)\n\n\tcase *ast.Identifier:\n\t\treturn evalIdentifier(node, env)\n\n\tcase *ast.FunctionLiteral:\n\t\treturn evalFunction(node, env)\n\n\tcase *ast.MethodExpression:\n\t\treturn evalMethodExpression(node, env)\n\n\tcase *ast.Import:\n\t\treturn evalImport(node, env)\n\n\tcase *ast.CallExpression:\n\t\treturn evalCall(node, env)\n\n\tcase *ast.StringLiteral:\n\t\treturn &object.String{Value: node.Value}\n\tcase *ast.At:\n\t\treturn evalAt(node, env)\n\tcase *ast.ArrayLiteral:\n\t\telements := evalExpressions(node.Elements, env)\n\t\tif len(elements) == 1 && isError(elements[0]) {\n\t\t\treturn elements[0]\n\t\t}\n\t\treturn &object.Array{Elements: elements}\n\tcase *ast.IndexExpression:\n\t\tleft := Eval(node.Left, env)\n\t\tif isError(left) {\n\t\t\treturn left\n\t\t}\n\t\tindex := Eval(node.Index, env)\n\t\tif isError(index) {\n\t\t\treturn index\n\t\t}\n\t\treturn evalIndexExpression(left, index, node.Token.Line)\n\tcase *ast.DictLiteral:\n\t\treturn evalDictLiteral(node, env)\n\tcase *ast.WhileExpression:\n\t\treturn evalWhileExpression(node, env)\n\tcase *ast.Break:\n\t\treturn evalBreak(node)\n\tcase *ast.Continue:\n\t\treturn evalContinue(node)\n\tcase *ast.SwitchExpression:\n\t\treturn evalSwitchStatement(node, env)\n\tcase *ast.Null:\n\t\treturn NULL\n\t// case *ast.For:\n\t// \treturn evalForExpression(node, env)\n\tcase *ast.ForIn:\n\t\treturn evalForInExpression(node, env, node.Token.Line)\n\tcase *ast.Package:\n\t\treturn evalPackage(node, env)\n\tcase *ast.PropertyExpression:\n\t\treturn evalPropertyExpression(node, env)\n\tcase *ast.PropertyAssignment:\n\t\tval := Eval(node.Value, env)\n\t\tif isError(val) {\n\t\t\treturn val\n\t\t}\n\t\treturn evalPropertyAssignment(node.Name, val, env)\n\tcase *ast.Assign:\n\t\treturn evalAssign(node, env)\n\tcase *ast.AssignEqual:\n\t\treturn evalAssignEqual(node, env)\n\n\tcase *ast.AssignmentExpression:\n\t\tleft := Eval(node.Left, env)\n\t\tif isError(left) {\n\t\t\treturn left\n\t\t}\n\n\t\tvalue := Eval(node.Value, env)\n\t\tif isError(value) {\n\t\t\treturn value\n\t\t}\n\n\t\t// This is an easy way to assign operators like +=, -= etc\n\t\t// for index expressions (arrays and dicts) where applicable\n\t\top := node.Token.Literal\n\t\tif len(op) >= 2 {\n\t\t\top = op[:len(op)-1]\n\t\t\tvalue = evalInfixExpression(op, left, value, node.Token.Line)\n\t\t\tif isError(value) {\n\t\t\t\treturn value\n\t\t\t}\n\t\t}\n\n\t\tif ident, ok := node.Left.(*ast.Identifier); ok {\n\t\t\tenv.Set(ident.Value, value)\n\t\t} else if ie, ok := node.Left.(*ast.IndexExpression); ok {\n\t\t\tobj := Eval(ie.Left, env)\n\t\t\tif isError(obj) {\n\t\t\t\treturn obj\n\t\t\t}\n\n\t\t\tif array, ok := obj.(*object.Array); ok {\n\t\t\t\tindex := Eval(ie.Index, env)\n\t\t\t\tif isError(index) {\n\t\t\t\t\treturn index\n\t\t\t\t}\n\t\t\t\tif idx, ok := index.(*object.Integer); ok {\n\t\t\t\t\tif int(idx.Value) >= len(array.Elements) {\n\t\t\t\t\t\treturn newError(\"Index imezidi idadi ya elements\")\n\t\t\t\t\t}\n\t\t\t\t\tarray.Elements[idx.Value] = value\n\t\t\t\t} else {\n\t\t\t\t\treturn newError(\"Hauwezi kufanya operesheni hii na %#v\", index)\n\t\t\t\t}\n\t\t\t} else if hash, ok := obj.(*object.Dict); ok {\n\t\t\t\tkey := Eval(ie.Index, env)\n\t\t\t\tif isError(key) {\n\t\t\t\t\treturn key\n\t\t\t\t}\n\t\t\t\tif hashKey, ok := key.(object.Hashable); ok {\n\t\t\t\t\thashed := hashKey.HashKey()\n\t\t\t\t\thash.Pairs[hashed] = object.DictPair{Key: key, Value: value}\n\t\t\t\t} else {\n\t\t\t\t\treturn newError(\"Hauwezi kufanya operesheni hii na %T\", key)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn newError(\"%T haifanyi operesheni hii\", obj)\n\t\t\t}\n\t\t} else {\n\t\t\treturn newError(\"Tumia neno kama kibadala, sio %T\", left)\n\t\t}\n\n\t}\n\n\treturn nil\n}\n\nfunc evalProgram(program *ast.Program, env *object.Environment) object.Object {\n\tvar result object.Object\n\n\tfor _, statement := range program.Statements {\n\t\tresult = Eval(statement, env)\n\n\t\tswitch result := result.(type) {\n\t\tcase *object.ReturnValue:\n\t\t\treturn result.Value\n\t\tcase *object.Error:\n\t\t\treturn result\n\t\t}\n\t}\n\n\treturn result\n}\n\nfunc nativeBoolToBooleanObject(input bool) *object.Boolean {\n\tif input {\n\t\treturn TRUE\n\t}\n\treturn FALSE\n}\n\nfunc isTruthy(obj object.Object) bool {\n\tswitch obj {\n\tcase NULL:\n\t\treturn false\n\tcase TRUE:\n\t\treturn true\n\tcase FALSE:\n\t\treturn false\n\tdefault:\n\t\treturn true\n\t}\n}\n\nfunc isError(obj object.Object) bool {\n\tif obj != nil {\n\t\treturn obj.Type() == object.ERROR_OBJ\n\t}\n\n\treturn false\n}\n\nfunc evalExpressions(exps []ast.Expression, env *object.Environment) []object.Object {\n\tvar result []object.Object\n\n\tfor _, e := range exps {\n\t\tevaluated := Eval(e, env)\n\t\tif isError(evaluated) {\n\t\t\treturn []object.Object{evaluated}\n\t\t}\n\n\t\tresult = append(result, evaluated)\n\t}\n\n\treturn result\n}\n\nfunc applyFunction(fn object.Object, args []object.Object, line int) object.Object {\n\tswitch fn := fn.(type) {\n\tcase *object.Function:\n\t\textendedEnv := extendedFunctionEnv(fn, args)\n\t\tevaluated := Eval(fn.Body, extendedEnv)\n\t\treturn unwrapReturnValue(evaluated)\n\tcase *object.Builtin:\n\t\tif result := fn.Fn(args...); result != nil {\n\t\t\treturn result\n\t\t}\n\t\treturn NULL\n\tcase *object.Package:\n\t\tobj := &object.Instance{\n\t\t\tPackage: fn,\n\t\t\tEnv:     object.NewEnclosedEnvironment(fn.Env),\n\t\t}\n\t\tobj.Env.Set(\"@\", obj)\n\t\tnode, ok := fn.Scope.Get(\"andaa\")\n\t\tif !ok {\n\t\t\treturn newError(\"Hamna andaa kiendesha\")\n\t\t}\n\t\tnode.(*object.Function).Env.Set(\"@\", obj)\n\t\tapplyFunction(node, args, fn.Name.Token.Line)\n\t\tnode.(*object.Function).Env.Del(\"@\")\n\t\treturn obj\n\tdefault:\n\t\tif fn != nil {\n\t\t\treturn newError(\"Mstari %d: Hiki sio kiendesha: %s\", line, fn.Type())\n\t\t} else {\n\t\t\treturn newError(\"Bro how did you even get here??? Contact language maker asap!\")\n\t\t}\n\t}\n\n}\n\nfunc extendedFunctionEnv(fn *object.Function, args []object.Object) *object.Environment {\n\tenv := object.NewEnclosedEnvironment(fn.Env)\n\n\tfor paramIdx, param := range fn.Parameters {\n\t\tif paramIdx < len(args) {\n\t\t\tenv.Set(param.Value, args[paramIdx])\n\t\t}\n\t}\n\treturn env\n}\n\nfunc unwrapReturnValue(obj object.Object) object.Object {\n\tif returnValue, ok := obj.(*object.ReturnValue); ok {\n\t\treturn returnValue.Value\n\t}\n\n\treturn obj\n}\n\nfunc evalBreak(node *ast.Break) object.Object {\n\treturn BREAK\n}\n\nfunc evalContinue(node *ast.Continue) object.Object {\n\treturn CONTINUE\n}\n\n// func evalForExpression(fe *ast.For, env *object.Environment) object.Object {\n// \tobj, ok := env.Get(fe.Identifier)\n// \tdefer func() { // stay safe and not reassign an existing variable\n// \t\tif ok {\n// \t\t\tenv.Set(fe.Identifier, obj)\n// \t\t}\n// \t}()\n// \tval := Eval(fe.StarterValue, env)\n// \tif isError(val) {\n// \t\treturn val\n// \t}\n\n// \tenv.Set(fe.StarterName.Value, val)\n\n// \t// err := Eval(fe.Starter, env)\n// \t// if isError(err) {\n// \t// \treturn err\n// \t// }\n// \tfor {\n// \t\tevaluated := Eval(fe.Condition, env)\n// \t\tif isError(evaluated) {\n// \t\t\treturn evaluated\n// \t\t}\n// \t\tif !isTruthy(evaluated) {\n// \t\t\tbreak\n// \t\t}\n// \t\tres := Eval(fe.Block, env)\n// \t\tif isError(res) {\n// \t\t\treturn res\n// \t\t}\n// \t\tif res.Type() == object.BREAK_OBJ {\n// \t\t\tbreak\n// \t\t}\n// \t\tif res.Type() == object.CONTINUE_OBJ {\n// \t\t\terr := Eval(fe.Closer, env)\n// \t\t\tif isError(err) {\n// \t\t\t\treturn err\n// \t\t\t}\n// \t\t\tcontinue\n// \t\t}\n// \t\tif res.Type() == object.RETURN_VALUE_OBJ {\n// \t\t\treturn res\n// \t\t}\n// \t\terr := Eval(fe.Closer, env)\n// \t\tif isError(err) {\n// \t\t\treturn err\n// \t\t}\n// \t}\n// \treturn NULL\n// }\n\nfunc loopIterable(next func() (object.Object, object.Object), env *object.Environment, fi *ast.ForIn) object.Object {\n\tk, v := next()\n\tfor k != nil && v != nil {\n\t\tenv.Set(fi.Key, k)\n\t\tenv.Set(fi.Value, v)\n\t\tres := Eval(fi.Block, env)\n\t\tif isError(res) {\n\t\t\treturn res\n\t\t}\n\t\tif res != nil {\n\t\t\tif res.Type() == object.BREAK_OBJ {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif res.Type() == object.CONTINUE_OBJ {\n\t\t\t\tk, v = next()\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif res.Type() == object.RETURN_VALUE_OBJ {\n\t\t\t\treturn res\n\t\t\t}\n\t\t}\n\t\tk, v = next()\n\t}\n\treturn NULL\n}\n"
  },
  {
    "path": "evaluator/evaluator_test.go",
    "content": "package evaluator\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/NuruProgramming/Nuru/lexer\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n\t\"github.com/NuruProgramming/Nuru/parser\"\n)\n\nfunc TestEvalIntegerExpression(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected int64\n\t}{\n\t\t{\"5\", 5},\n\t\t{\"10\", 10},\n\t\t{\"-5\", -5},\n\t\t{\"-10\", -10},\n\t\t{\"5 + 5 + 5 + 5 - 10\", 10},\n\t\t{\"2 * 2 * 2 * 2\", 16},\n\t\t{\"2 / 2 + 1\", 2},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\ttestIntegerObject(t, evaluated, tt.expected)\n\t}\n}\n\nfunc TestEvalFloatExpression(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected float64\n\t}{\n\t\t{\"2**3\", 8.0},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\ttestFloatObject(t, evaluated, tt.expected)\n\t}\n}\n\nfunc TestEvalBooleanExpression(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected bool\n\t}{\n\t\t{\"kweli\", true},\n\t\t{\"sikweli\", false},\n\t\t{\"1 < 2\", true},\n\t\t{\"1 > 2\", false},\n\t\t{\"1 > 1\", false},\n\t\t{\"1 < 1\", false},\n\t\t{\"1 == 1\", true},\n\t\t{\"1 != 1\", false},\n\t\t{\"1 == 2\", false},\n\t\t{\"1 != 2\", true},\n\t\t{\"kweli == kweli\", true},\n\t\t{\"sikweli == sikweli\", true},\n\t\t{\"kweli == sikweli\", false},\n\t\t{\"kweli != sikweli\", true},\n\t\t{\"sikweli != kweli\", true},\n\t\t{\"(1 < 2) == kweli\", true},\n\t\t{\"!kweli\", false},\n\t\t{\"!sikweli\", true},\n\t\t{\"!tupu\", true},\n\t\t{\"!'kitu'\", false},\n\t\t{\"2 > 1 && 1 < 4\", true},\n\t\t{\"2 > 1 && 1 > 4\", false},\n\t\t{\"2 < 1 && 1 < 4\", false},\n\t\t{\"2 < 1 && 1 > 4\", false},\n\t\t{\"5 < 2 || 3 > 2\", true},\n\t\t{\"5 == 5 || 4 == 4\", true},\n\t\t{\"5 > 2 || 3 < 2\", true},\n\t\t{\"5 < 2 || 3 < 2\", false},\n\t\t{\"5 >= 2\", true},\n\t\t{\"5 <= 2\", false},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\ttestBooleanObject(t, evaluated, tt.expected)\n\t}\n}\n\nfunc TestBangOperator(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected bool\n\t}{\n\t\t{\"!kweli\", false},\n\t\t{\"!sikweli\", true},\n\t\t{\"!5\", false},\n\t\t{\"!!kweli\", true},\n\t\t{\"!!sikweli\", false},\n\t\t{\"!!5\", true},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\ttestBooleanObject(t, evaluated, tt.expected)\n\t}\n}\n\nfunc testEval(input string) object.Object {\n\tl := lexer.New(input)\n\tp := parser.New(l)\n\tprogram := p.ParseProgram()\n\tenv := object.NewEnvironment()\n\n\treturn Eval(program, env)\n}\n\nfunc testIntegerObject(t *testing.T, obj object.Object, expected int64) bool {\n\tresult, ok := obj.(*object.Integer)\n\n\tif !ok {\n\t\tt.Errorf(\"Object is not Integer, got=%T(%+v)\", obj, obj)\n\t\treturn false\n\t}\n\n\tif result.Value != expected {\n\t\tt.Errorf(\"object has wrong value. got=%d, want=%d\", result.Value, expected)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc testFloatObject(t *testing.T, obj object.Object, expected float64) bool {\n\tresult, ok := obj.(*object.Float)\n\n\tif !ok {\n\t\tt.Errorf(\"Object is not Float, got=%T(%+v)\", obj, obj)\n\t\treturn false\n\t}\n\n\tif result.Value != expected {\n\t\tt.Errorf(\"object has wrong value. got=%f, want=%f\", result.Value, expected)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc testBooleanObject(t *testing.T, obj object.Object, expected bool) bool {\n\tresult, ok := obj.(*object.Boolean)\n\tif !ok {\n\t\tt.Errorf(\"object is not Boolean, got=%T(%+v)\", obj, obj)\n\t\treturn false\n\t}\n\n\tif result.Value != expected {\n\t\tt.Errorf(\"object has wrong value, got=%t, want=%t\", result.Value, expected)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc TestIfElseExpressions(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected interface{}\n\t}{\n\t\t{\"kama (kweli) {10}\", 10},\n\t\t{\"kama (sikweli) {10}\", nil},\n\t\t{\"kama (1) {10}\", 10},\n\t\t{\"kama (1 < 2) {10}\", 10},\n\t\t{\"kama (1 > 2) {10}\", nil},\n\t\t{\"kama (1 > 2) {10} sivyo {20}\", 20},\n\t\t{\"kama (1 < 2) {10} sivyo {20}\", 10},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\tinteger, ok := tt.expected.(int)\n\t\tif ok {\n\t\t\ttestIntegerObject(t, evaluated, int64(integer))\n\t\t} else {\n\t\t\ttestNullObject(t, evaluated)\n\t\t}\n\t}\n}\n\nfunc testNullObject(t *testing.T, obj object.Object) bool {\n\tif obj != NULL {\n\t\tt.Errorf(\"object is not null, got=%T(+%v)\", obj, obj)\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc TestReturnStatements(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected int64\n\t}{\n\t\t{\"rudisha 10\", 10},\n\t\t{\"rudisha 10; 9;\", 10},\n\t\t{\"rudisha 2 * 5; 9;\", 10},\n\t\t{\"9; rudisha 2 * 5; 9;\", 10},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\ttestIntegerObject(t, evaluated, tt.expected)\n\t}\n}\n\nfunc TestErrorHandling(t *testing.T) {\n\ttests := []struct {\n\t\tinput           string\n\t\texpectedMessage string\n\t}{\n\t\t{\n\t\t\t\"5 + kweli\",\n\t\t\t\"Mstari 1: Aina Hazilingani: NAMBA + BOOLEAN\",\n\t\t},\n\t\t{\n\t\t\t\"5 + kweli; 5;\",\n\t\t\t\"Mstari 1: Aina Hazilingani: NAMBA + BOOLEAN\",\n\t\t},\n\t\t{\n\t\t\t\"-kweli\",\n\t\t\t\"Mstari 1: Operesheni Haieleweki: -BOOLEAN\",\n\t\t},\n\t\t{\n\t\t\t\"kweli + sikweli\",\n\t\t\t\"Mstari 1: Operesheni Haieleweki: BOOLEAN + BOOLEAN\",\n\t\t},\n\t\t{\n\t\t\t\"5; kweli + sikweli; 5\",\n\t\t\t\"Mstari 1: Operesheni Haieleweki: BOOLEAN + BOOLEAN\",\n\t\t},\n\t\t{\n\t\t\t\"kama (10 > 1) { kweli + sikweli;}\",\n\t\t\t\"Mstari 1: Operesheni Haieleweki: BOOLEAN + BOOLEAN\",\n\t\t},\n\t\t{\n\t\t\t`\nkama (10 > 1) {\n\tkama (10 > 1) {\n\t\trudisha kweli + kweli;\n\t}\n\n\trudisha 1;\n}\n\t\t\t`,\n\t\t\t\"Mstari 4: Operesheni Haieleweki: BOOLEAN + BOOLEAN\",\n\t\t},\n\t\t{\n\t\t\t\"bangi\",\n\t\t\t\"Mstari 1: Neno Halifahamiki: bangi\",\n\t\t},\n\t\t{\n\t\t\t`\"Habari\" - \"Habari\"`,\n\t\t\t\"Mstari 1: Operesheni Haieleweki: NENO - NENO\",\n\t\t},\n\t\t{\n\t\t\t`{\"jina\": \"Avi\"}[unda(x) {x}];`,\n\t\t\t\"Mstari 1: Samahani, UNDO (FUNCTION) haitumiki kama ufunguo\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\n\t\terrObj, ok := evaluated.(*object.Error)\n\t\tif !ok {\n\t\t\tt.Errorf(\"no error object return, got=%T(%+v)\", evaluated, evaluated)\n\t\t\tcontinue\n\t\t}\n\n\t\tif errObj.Message != fmt.Sprintf(tt.expectedMessage) {\n\t\t\tt.Errorf(\"wrong error message, expected=%q, got=%q\", fmt.Sprintf(tt.expectedMessage), errObj.Message)\n\t\t}\n\t}\n}\n\nfunc TestLetStatement(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected int64\n\t}{\n\t\t{\"fanya a = 5; a;\", 5},\n\t\t{\"fanya a = 5 * 5; a;\", 25},\n\t\t{\"fanya a = 5; fanya b = a; b;\", 5},\n\t\t{\"fanya a = 5; fanya b = a; fanya c = a + b + 5; c;\", 15},\n\t}\n\n\tfor _, tt := range tests {\n\t\ttestIntegerObject(t, testEval(tt.input), tt.expected)\n\t}\n}\n\nfunc TestFunctionObject(t *testing.T) {\n\tinput := \"unda(x) { x + 2 ;};\"\n\n\tevaluated := testEval(input)\n\tunda, ok := evaluated.(*object.Function)\n\tif !ok {\n\t\tt.Fatalf(\"object is not a Function, got=%T(%+v)\", evaluated, evaluated)\n\t}\n\n\tif len(unda.Parameters) != 1 {\n\t\tt.Fatalf(\"function has wrong parameters,Parameters=%+v\", unda.Parameters)\n\t}\n\n\tif unda.Parameters[0].String() != \"x\" {\n\t\tt.Fatalf(\"parameter is not x, got=%q\", unda.Parameters[0])\n\t}\n\n\texpectedBody := \"(x + 2)\"\n\n\tif unda.Body.String() != expectedBody {\n\t\tt.Fatalf(\"body is not %q, got=%q\", expectedBody, unda.Body.String())\n\t}\n}\n\nfunc TestFunctionApplication(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected int64\n\t}{\n\t\t{\"fanya mfano = unda(x) {x;}; mfano(5);\", 5},\n\t\t{\"fanya mfano = unda(x) {rudisha x;}; mfano(5);\", 5},\n\t\t{\"fanya double = unda(x) { x * 2;}; double(5);\", 10},\n\t\t{\"fanya add = unda(x, y) {x + y;}; add(5,5);\", 10},\n\t\t{\"fanya add = unda(x, y) {x + y;}; add(5 + 5, add(5, 5));\", 20},\n\t\t{\"unda(x) {x;}(5)\", 5},\n\t}\n\n\tfor _, tt := range tests {\n\t\ttestIntegerObject(t, testEval(tt.input), tt.expected)\n\t}\n}\n\nfunc TestClosures(t *testing.T) {\n\tinput := `\nfanya newAdder = unda(x) {\n\tunda(y) { x + y};\n};\n\nfanya addTwo = newAdder(2);\naddTwo(2);\n`\n\ttestIntegerObject(t, testEval(input), 4)\n}\n\nfunc TestStringLiteral(t *testing.T) {\n\tinput := `\"Habari yako!\"`\n\n\tevaluated := testEval(input)\n\tstr, ok := evaluated.(*object.String)\n\tif !ok {\n\t\tt.Fatalf(\"Object is not string, got=%T(%+v)\", evaluated, evaluated)\n\t}\n\n\tif str.Value != \"Habari yako!\" {\n\t\tt.Errorf(\"String has wrong value, got=%q\", str.Value)\n\t}\n}\n\nfunc TestStringconcatenation(t *testing.T) {\n\tinput := `\"Mambo\" + \" \" + \"Vipi\" + \"?\"`\n\n\tevaluated := testEval(input)\n\n\tstr, ok := evaluated.(*object.String)\n\tif !ok {\n\t\tt.Fatalf(\"object is not a string, got=%T(%+v)\", evaluated, evaluated)\n\t}\n\n\tif str.Value != \"Mambo Vipi?\" {\n\t\tt.Errorf(\"String has wrong value, got=%q\", str.Value)\n\t}\n}\n\nfunc TestStringMultiplyInteger(t *testing.T) {\n\tinput := `\"Mambo\" * 4`\n\n\tevaluated := testEval(input)\n\n\tstr, ok := evaluated.(*object.String)\n\tif !ok {\n\t\tt.Fatalf(\"object is not a string, got=%T(%+v)\", evaluated, evaluated)\n\t}\n\n\tif str.Value != \"MamboMamboMamboMambo\" {\n\t\tt.Errorf(\"String has wrong value, got=%q\", str.Value)\n\t}\n}\n\n// func TestBuiltinFunctions(t *testing.T) {\n// \ttests := []struct {\n// \t\tinput    string\n// \t\texpected interface{}\n// \t}{\n// \t\t{`jumla()`, \"Hoja hazilingani, tunahitaji=1, tumepewa=0\"},\n// \t\t{`jumla(\"\")`, \"Samahani, hii function haitumiki na NENO\"},\n// \t\t{`jumla(1)`, \"Samahani, hii function haitumiki na NAMBA\"},\n// \t\t{`jumla([1,2,3])`, 6},\n// \t\t{`jumla([1,2,3.4])`, 6.4},\n// \t\t{`jumla([1.1,2.5,3.4])`, 7},\n// \t\t{`jumla([1.1,2.5,\"q\"])`, \"Samahani namba tu zinahitajika\"},\n// \t}\n\n// \tfor _, tt := range tests {\n// \t\tevaluated := testEval(tt.input)\n\n// \t\tswitch expected := tt.expected.(type) {\n// \t\tcase int:\n// \t\t\ttestIntegerObject(t, evaluated, int64(expected))\n// \t\tcase float64:\n// \t\t\ttestFloatObject(t, evaluated, float64(expected))\n\n// \t\tcase string:\n// \t\t\terrObj, ok := evaluated.(*object.Error)\n// \t\t\tif !ok {\n// \t\t\t\tt.Errorf(\"Object is not Error, got=%T(%+v)\", evaluated, evaluated)\n// \t\t\t\tcontinue\n// \t\t\t}\n// \t\t\tif errObj.Message != fmt.Sprintf(\"\\x1b[%dm%s\\x1b[0m\", 31, expected) {\n// \t\t\t\tt.Errorf(\"Wrong eror message, expected=%q, got=%q\", expected, errObj.Message)\n// \t\t\t}\n// \t\t}\n// \t}\n// }\n\nfunc TestArrayLiterals(t *testing.T) {\n\tinput := \"[1, 2 * 2, 3 + 3]\"\n\n\tevaluated := testEval(input)\n\tresult, ok := evaluated.(*object.Array)\n\tif !ok {\n\t\tt.Fatalf(\"Object is not an Array, got=%T(%+v)\", evaluated, evaluated)\n\t}\n\n\tif len(result.Elements) != 3 {\n\t\tt.Fatalf(\"Array has wrong number of elements, got=%d\", len(result.Elements))\n\t}\n\n\ttestIntegerObject(t, result.Elements[0], 1)\n\ttestIntegerObject(t, result.Elements[1], 4)\n\ttestIntegerObject(t, result.Elements[2], 6)\n}\n\nfunc TestArrayIndexExpressions(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected interface{}\n\t}{\n\t\t{\n\t\t\t\"[1, 2, 3][0]\",\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"[1, 2, 3][1]\",\n\t\t\t2,\n\t\t},\n\t\t{\n\t\t\t\"[1, 2, 3][2]\",\n\t\t\t3,\n\t\t},\n\t\t{\n\t\t\t\"fanya i = 0; [1][i];\",\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"fanya myArr = [1, 2, 3]; myArr[2];\",\n\t\t\t3,\n\t\t},\n\t\t{\n\t\t\t\"[1, 2, 3][3]\",\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"[1, 2, 3][-1]\",\n\t\t\tnil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\tinteger, ok := tt.expected.(int)\n\t\tif ok {\n\t\t\ttestIntegerObject(t, evaluated, int64(integer))\n\t\t} else {\n\t\t\ttestNullObject(t, evaluated)\n\t\t}\n\t}\n}\n\nfunc TestDictLiterals(t *testing.T) {\n\tinput := `fanya two = \"two\";\n{\n\t\"one\": 10 - 9,\n\ttwo: 1 +1,\n\t\"thr\" + \"ee\": 6 / 2,\n\t4: 4,\n\tkweli: 5,\n\tsikweli: 6\n}`\n\n\tevaluated := testEval(input)\n\tresult, ok := evaluated.(*object.Dict)\n\tif !ok {\n\t\tt.Fatalf(\"Eval didn't return a dict, got=%T(%+v)\", evaluated, evaluated)\n\t}\n\n\texpected := map[object.HashKey]int64{\n\t\t(&object.String{Value: \"one\"}).HashKey():   1,\n\t\t(&object.String{Value: \"two\"}).HashKey():   2,\n\t\t(&object.String{Value: \"three\"}).HashKey(): 3,\n\t\t(&object.Integer{Value: 4}).HashKey():      4,\n\t\tTRUE.HashKey():                             5,\n\t\tFALSE.HashKey():                            6,\n\t}\n\n\tif len(result.Pairs) != len(expected) {\n\t\tt.Fatalf(\"Dict has wrong number of pairs, got=%d\", len(result.Pairs))\n\t}\n\n\tfor expectedKey, expectedValue := range expected {\n\t\tpair, ok := result.Pairs[expectedKey]\n\t\tif !ok {\n\t\t\tt.Errorf(\"No pair for give key\")\n\t\t}\n\n\t\ttestIntegerObject(t, pair.Value, expectedValue)\n\t}\n}\n\nfunc TestDictIndexExpression(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected interface{}\n\t}{\n\t\t{\n\t\t\t`{\"foo\": 5}[\"foo\"]`,\n\t\t\t5,\n\t\t},\n\t\t{\n\t\t\t`{\"foo\": 5}[\"bar\"]`,\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t`fanya key = \"foo\"; {\"foo\": 5}[key]`,\n\t\t\t5,\n\t\t},\n\t\t{\n\t\t\t`{}[\"foo\"]`,\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t`{5: 5}[5]`,\n\t\t\t5,\n\t\t},\n\t\t{\n\t\t\t`{kweli: 5}[kweli]`,\n\t\t\t5,\n\t\t},\n\t\t{\n\t\t\t`{sikweli: 5}[sikweli]`,\n\t\t\t5,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\tinteger, ok := tt.expected.(int)\n\t\tif ok {\n\t\t\ttestIntegerObject(t, evaluated, int64(integer))\n\t\t} else {\n\t\t\ttestNullObject(t, evaluated)\n\t\t}\n\t}\n}\n\nfunc TestPrefixInteger(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected interface{}\n\t}{\n\t\t{\n\t\t\t\"-4\",\n\t\t\t-4,\n\t\t},\n\t\t{\n\t\t\t\"+5\",\n\t\t\t5,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\tinteger, ok := tt.expected.(int)\n\t\tif !ok {\n\t\t\tt.Errorf(\"Object is not an integer\")\n\t\t}\n\t\ttestIntegerObject(t, evaluated, int64(integer))\n\t}\n}\n\nfunc TestPrefixFloat(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected interface{}\n\t}{\n\t\t{\n\t\t\t\"-4.4\",\n\t\t\t-4.4,\n\t\t},\n\t\t{\n\t\t\t\"+5.5\",\n\t\t\t5.5,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\tfloat, ok := tt.expected.(float64)\n\t\tif !ok {\n\t\t\tt.Errorf(\"Object is not a float\")\n\t\t}\n\t\ttestFloatObject(t, evaluated, float)\n\t}\n}\n\nfunc TestInExpression(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected bool\n\t}{\n\t\t{\n\t\t\t\"'a' ktk 'habari'\",\n\t\t\ttrue,\n\t\t},\n\t\t{\n\t\t\t\"'c' ktk 'habari'\",\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"1 ktk [1, 2, 3]\",\n\t\t\ttrue,\n\t\t},\n\t\t{\n\t\t\t\"4 ktk [1, 2, 3]\",\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"'a' ktk {'a': 'apple', 'b': 'banana'}\",\n\t\t\ttrue,\n\t\t},\n\t\t{\n\t\t\t\"'apple' ktk {'a': 'apple', 'b': 'banana'}\",\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"'c' ktk {'a': 'apple', 'b': 'banana'}\",\n\t\t\tfalse,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\ttestBooleanObject(t, evaluated, tt.expected)\n\t}\n}\n\nfunc TestArrayConcatenation(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\t\"['a', 'b', 'c'] + [1, 2, 3]\",\n\t\t\t\"[a, b, c, 1, 2, 3]\",\n\t\t},\n\t\t{\n\t\t\t\"[1, 2, 3] * 4\",\n\t\t\t\"[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]\",\n\t\t},\n\t\t{\n\t\t\t\"4 * [1, 2, 3]\",\n\t\t\t\"[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\tarr, ok := evaluated.(*object.Array)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"Object is not an array, got=%T(%+v)\", evaluated, evaluated)\n\t\t}\n\n\t\tif arr.Inspect() != tt.expected {\n\t\t\tt.Errorf(\"Array has wrong values, got=%s want=%s\", arr.Inspect(), tt.expected)\n\t\t}\n\t}\n}\n\nfunc TestDictConcatenation(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected map[string]string\n\t}{\n\t\t{\n\t\t\tinput:    \"{'a': 'apple', 'b': 'banana'} + {'c': 'cat'}\",\n\t\t\texpected: map[string]string{\"a\": \"apple\", \"b\": \"banana\", \"c\": \"cat\"},\n\t\t},\n\t\t{\n\t\t\tinput:    \"{'a':'bbb'} + {'a':'ccc'}\",\n\t\t\texpected: map[string]string{\"a\": \"ccc\"},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\t\tdict, ok := evaluated.(*object.Dict)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"Object is not an dict, got=%T(%+v)\", evaluated, evaluated)\n\t\t}\n\n\t\tif len(dict.Pairs) != len(tt.expected) {\n\t\t\tt.Errorf(\"Dictionary has wrong number of pairs, got=%d want=%d\", len(dict.Pairs), len(tt.expected))\n\t\t}\n\t}\n}\n\nfunc TestPostfixExpression(t *testing.T) {\n\tinttests := []struct {\n\t\tinput    string\n\t\texpected int64\n\t}{\n\t\t{\n\t\t\t\"a=5; a++\",\n\t\t\t6,\n\t\t},\n\t\t{\n\t\t\t\"a=5; a--\",\n\t\t\t4,\n\t\t},\n\t}\n\n\tfor _, tt := range inttests {\n\t\tevaluated := testEval(tt.input)\n\t\tinteger, ok := evaluated.(*object.Integer)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"Object is not an integer, got=%T(%+v)\", evaluated, evaluated)\n\t\t}\n\t\ttestIntegerObject(t, integer, tt.expected)\n\t}\n\tfloattests := []struct {\n\t\tinput    string\n\t\texpected float64\n\t}{\n\t\t{\n\t\t\t\"a=5.5; a++\",\n\t\t\t6.5,\n\t\t},\n\t\t{\n\t\t\t\"a=5.5; a--\",\n\t\t\t4.5,\n\t\t},\n\t}\n\n\tfor _, tt := range floattests {\n\t\tevaluated := testEval(tt.input)\n\t\tfloat, ok := evaluated.(*object.Float)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"Object is not an float, got=%T(%+v)\", evaluated, evaluated)\n\t\t}\n\t\ttestFloatObject(t, float, tt.expected)\n\t}\n}\n\nfunc TestWhileLoop(t *testing.T) {\n\tinput := `\n\ti = 10\n\twakati (i > 0){\n\t\ti--\n\t}\n\ti\n\t`\n\n\tevaluated := testEval(input)\n\ti, ok := evaluated.(*object.Integer)\n\tif !ok {\n\t\tt.Fatalf(\"Object is not an integer, got=%T(+%v)\", evaluated, evaluated)\n\t}\n\n\tif i.Value != 0 {\n\t\tt.Errorf(\"Incorrect value, want=0 got=%d\", i.Value)\n\t}\n}\n\nfunc TestForLoop(t *testing.T) {\n\tinput := `\n\toutput = \"\"\n\tkwa i ktk \"mojo\" {\n\t\toutput += i\n\t}\n\toutput\n\t`\n\tevaluated := testEval(input)\n\ti, ok := evaluated.(*object.String)\n\tif !ok {\n\t\tt.Fatalf(\"Object is not a string, got=%T(+%v)\", evaluated, evaluated)\n\t}\n\n\tif i.Value != \"mojo\" {\n\t\tt.Errorf(\"Wrong value: want=%s got=%s\", \"mojo\", i.Value)\n\t}\n}\n\nfunc TestBreakLoop(t *testing.T) {\n\tinput := `\n\ti = 0\n\twakati (i < 10) {\n\t\tkama (i == 5) {\n\t\t\tvunja\n\t\t}\n\t\ti++\n\t}\n\ti\n\t`\n\tevaluated := testEval(input)\n\ti, ok := evaluated.(*object.Integer)\n\tif !ok {\n\t\tt.Fatalf(\"Object is not an integer, got=%T(+%v)\", evaluated, evaluated)\n\t}\n\n\tif i.Value != 5 {\n\t\tt.Errorf(\"Wrong value: want=5, got=%d\", i.Value)\n\t}\n\n\tinput = `\n\toutput = \"\"\n\tkwa i ktk \"mojo\" {\n\t\toutput += i\n\t\tkama (i == 'o') {\n\t\t\tvunja\n\t\t}\n\t}\n\toutput\n\t`\n\n\tevaluatedFor := testEval(input)\n\tj, ok := evaluatedFor.(*object.String)\n\tif !ok {\n\t\tt.Fatalf(\"Object is not a string, got=%T\", evaluated)\n\t}\n\n\tif j.Value != \"mo\" {\n\t\tt.Errorf(\"Wrong value: want=%s, got=%s\", \"mo\", j.Value)\n\t}\n}\n\nfunc TestContinueLoop(t *testing.T) {\n\tinput := `\n\ti = 0\n\twakati (i < 10) {\n\t\ti++\n\t\tkama (i == 5) {\n\t\t\tendelea\n\t\t}\n\t\ti++\n\t}\n\ti\n\t`\n\tevaluated := testEval(input)\n\ti, ok := evaluated.(*object.Integer)\n\tif !ok {\n\t\tt.Fatalf(\"Object is not an integer, got=%T(+%v)\", evaluated, evaluated)\n\t}\n\n\tif i.Value != 11 {\n\t\tt.Errorf(\"Wrong value: want=11, got=%d\", i.Value)\n\t}\n\n\tinput = `\n\toutput = \"\"\n\tkwa i ktk \"mojo\" {\n\t\tkama (i == 'o') {\n\t\t\tendelea\n\t\t}\n\t\toutput += i\n\t}\n\toutput\n\t`\n\n\tevaluatedFor := testEval(input)\n\tj, ok := evaluatedFor.(*object.String)\n\tif !ok {\n\t\tt.Fatalf(\"Object is not a string, got=%T\", evaluated)\n\t}\n\n\tif j.Value != \"mj\" {\n\t\tt.Errorf(\"Wrong value: want=%s, got=%s\", \"mj\", j.Value)\n\t}\n}\n\nfunc TestSwitchStatement(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected interface{}\n\t}{\n\t\t{\n\t\t\t`\n\t\t\ti = 5\n\t\t\tbadili (i) {\n\t\t\t\tikiwa 2 {\n\t\t\t\t\toutput = 2\n\t\t\t\t}\n\t\t\t\tikiwa 5 {\n\t\t\t\t\toutput = 5\n\t\t\t\t}\n\t\t\t\tkawaida {\n\t\t\t\t\toutput = \"haijulikani\"\n\t\t\t\t}\n\t\t\t}\n\t\t\toutput\n\t\t\t`,\n\t\t\t5,\n\t\t},\n\t\t{\n\t\t\t`\n\t\t\ti = 5\n\t\t\tbadili (i) {\n\t\t\t\tikiwa 2 {\n\t\t\t\t\toutput = 2\n\t\t\t\t}\n\t\t\t\tkawaida {\n\t\t\t\t\toutput = \"haijulikani\"\n\t\t\t\t}\n\t\t\t}\n\t\t\toutput\n\t\t\t`,\n\t\t\t\"haijulikani\",\n\t\t},\n\t\t{\n\t\t\t`\n\t\t\ti = 5\n\t\t\tbadili (i) {\n\t\t\t\tikiwa 5 {\n\t\t\t\t\toutput = 5\n\t\t\t\t}\n\t\t\t\tikiwa 2 {\n\t\t\t\t\toutput = 2\n\t\t\t\t}\n\t\t\t\tkawaida {\n\t\t\t\t\toutput = \"haijulikani\"\n\t\t\t\t}\n\t\t\t}\n\t\t\toutput\n\t\t\t`,\n\t\t\t5,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\n\t\tswitch expected := tt.expected.(type) {\n\t\tcase int:\n\t\t\ttestIntegerObject(t, evaluated, int64(expected))\n\t\tcase string:\n\t\t\ts, ok := evaluated.(*object.String)\n\t\t\tif !ok {\n\t\t\t\tt.Fatalf(\"Object is not a string, got=%T\", evaluated)\n\t\t\t}\n\n\t\t\tif s.Value != tt.expected {\n\t\t\t\tt.Errorf(\"Wrong Value, want='haijulikani', got=%s\", s.Value)\n\t\t\t}\n\n\t\t}\n\t}\n}\n\nfunc TestAssignEqual(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected interface{}\n\t}{\n\t\t{\"a = 5; a += 5\",\n\t\t\t10,\n\t\t},\n\t\t{\n\t\t\t\"a = 5; a -= 5\",\n\t\t\t0,\n\t\t},\n\t\t{\n\t\t\t\"a = 5; a *= 10\",\n\t\t\t50,\n\t\t},\n\t\t{\n\t\t\t\"a = 100; a /= 4\",\n\t\t\t25,\n\t\t},\n\t\t{\n\t\t\t`\n\t\ta = [1, 2, 3]\n\t\ta[0] += 500\n\t\ta[0]\n\t\t`,\n\t\t\t501,\n\t\t},\n\t\t{\n\t\t\t`\n\t\ta = \"mambo\"\n\t\ta += \" vipi\"\n\t\t`,\n\t\t\t\"mambo vipi\",\n\t\t},\n\t\t{\n\t\t\t\"a = 5.5; a += 4.5\",\n\t\t\t10.0,\n\t\t},\n\t\t{\n\t\t\t\"a = 11.3; a -= 0.8\",\n\t\t\t10.5,\n\t\t},\n\t\t{\n\t\t\t\"a = 0.4; a /= 2\",\n\t\t\t0.2,\n\t\t},\n\t\t{\n\t\t\t\"a = 0.1; a *= 10\",\n\t\t\t1.0,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\n\t\tswitch expected := tt.expected.(type) {\n\t\tcase int:\n\t\t\ttestIntegerObject(t, evaluated, int64(expected))\n\t\tcase float64:\n\t\t\ttestFloatObject(t, evaluated, float64(expected))\n\t\tcase string:\n\t\t\ts, ok := evaluated.(*object.String)\n\t\t\tif !ok {\n\t\t\t\tt.Fatalf(\"Object not a string, got=%T\", evaluated)\n\t\t\t}\n\n\t\t\tif s.Value != tt.expected {\n\t\t\t\tt.Errorf(\"Wrong value, want=%s, got=%s\", tt.expected, s.Value)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestStringMethods(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected interface{}\n\t}{\n\t\t{\n\t\t\t\"'mambo'.idadi()\",\n\t\t\t5,\n\t\t},\n\t\t{\n\t\t\t\"'mambo'.herufikubwa()\",\n\t\t\t\"MAMBO\",\n\t\t},\n\t\t{\n\t\t\t\"'MaMbO'.herufindogo()\",\n\t\t\t\"mambo\",\n\t\t},\n\t\t{\n\t\t\t\"'habari'.gawa('a')\",\n\t\t\t\"[h, b, ri]\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tevaluated := testEval(tt.input)\n\n\t\tswitch expected := tt.expected.(type) {\n\t\tcase int:\n\t\t\ttestIntegerObject(t, evaluated, int64(expected))\n\t\tcase string:\n\t\t\tswitch eval := evaluated.(type) {\n\t\t\tcase *object.String:\n\t\t\t\ts, ok := evaluated.(*object.String)\n\t\t\t\tif !ok {\n\t\t\t\t\tt.Fatalf(\"Object not of type string, got=%T\", eval)\n\t\t\t\t}\n\t\t\t\tif s.Value != tt.expected {\n\t\t\t\t\tt.Errorf(\"Wrong value: want=%s, got=%s\", tt.expected, s.Value)\n\t\t\t\t}\n\t\t\tcase *object.Array:\n\t\t\t\tarr, ok := evaluated.(*object.Array)\n\t\t\t\tif !ok {\n\t\t\t\t\tt.Fatalf(\"Object not of type array, got=%T\", eval)\n\t\t\t\t}\n\n\t\t\t\tif arr.Inspect() != tt.expected {\n\t\t\t\t\tt.Errorf(\"Wrong value: want=%s, got=%s\", tt.expected, arr.Inspect())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestTimeModule(t *testing.T) {\n\tinput := `\n\ttumia muda\n\tmuda.hasahivi()\n\t`\n\n\tevaluated := testEval(input)\n\tmuda, ok := evaluated.(*object.Time)\n\tif !ok {\n\t\tt.Fatalf(\"Object is not a time object, got=%T\", evaluated)\n\t}\n\n\t_, err := time.Parse(\"15:04:05 02-01-2006\", muda.TimeValue)\n\tif err != nil {\n\t\tt.Errorf(\"Wrong time value: got=%v\", err)\n\t}\n}\n"
  },
  {
    "path": "evaluator/forin.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalForInExpression(fie *ast.ForIn, env *object.Environment, line int) object.Object {\n\titerable := Eval(fie.Iterable, env)\n\texistingKeyIdentifier, okk := env.Get(fie.Key) // again, stay safe\n\texistingValueIdentifier, okv := env.Get(fie.Value)\n\tdefer func() { // restore them later on\n\t\tif okk {\n\t\t\tenv.Set(fie.Key, existingKeyIdentifier)\n\t\t}\n\t\tif okv {\n\t\t\tenv.Set(fie.Value, existingValueIdentifier)\n\t\t}\n\t}()\n\tswitch i := iterable.(type) {\n\tcase object.Iterable:\n\t\tdefer func() {\n\t\t\ti.Reset()\n\t\t}()\n\t\treturn loopIterable(i.Next, env, fie)\n\tdefault:\n\t\treturn newError(\"Mstari %d: Huwezi kufanya operesheni hii na %s\", line, i.Type())\n\t}\n}\n"
  },
  {
    "path": "evaluator/function.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalFunction(node *ast.FunctionLiteral, env *object.Environment) object.Object {\n\tfunction := &object.Function{\n\t\tName:       node.Name,\n\t\tParameters: node.Parameters,\n\t\tDefaults:   node.Defaults,\n\t\tBody:       node.Body,\n\t\tEnv:        env,\n\t}\n\n\treturn function\n}\n"
  },
  {
    "path": "evaluator/identifier.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object {\n\tif val, ok := env.Get(node.Value); ok {\n\t\treturn val\n\t}\n\tif builtin, ok := builtins[node.Value]; ok {\n\t\treturn builtin\n\t}\n\n\treturn newError(\"Mstari %d: Neno Halifahamiki: %s\", node.Token.Line, node.Value)\n}\n"
  },
  {
    "path": "evaluator/if.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalIfExpression(ie *ast.IfExpression, env *object.Environment) object.Object {\n\tcondition := Eval(ie.Condition, env)\n\n\tif isError(condition) {\n\t\treturn condition\n\t}\n\n\tif isTruthy(condition) {\n\t\treturn Eval(ie.Consequence, env)\n\t} else if ie.Alternative != nil {\n\t\treturn Eval(ie.Alternative, env)\n\t} else {\n\t\treturn NULL\n\t}\n}\n"
  },
  {
    "path": "evaluator/import.go",
    "content": "package evaluator\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/lexer\"\n\t\"github.com/NuruProgramming/Nuru/module\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n\t\"github.com/NuruProgramming/Nuru/parser\"\n)\n\nvar searchPaths []string\n\nfunc evalImport(node *ast.Import, env *object.Environment) object.Object {\n\tfor k, v := range node.Identifiers {\n\t\tif mod, ok := module.Mapper[v.Value]; ok {\n\t\t\tenv.Set(k, mod)\n\t\t} else {\n\t\t\treturn evalImportFile(k, v, env)\n\t\t}\n\t}\n\treturn NULL\n}\n\nfunc evalImportFile(name string, ident *ast.Identifier, env *object.Environment) object.Object {\n\taddSearchPath(\"\")\n\tfilename := findFile(name)\n\tif filename == \"\" {\n\t\treturn newError(\"Moduli %s haipo\", name)\n\t}\n\tvar scope *object.Environment\n\tscope, err := evaluateFile(filename, env)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn importFile(name, ident, env, scope)\n}\n\nfunc addSearchPath(path string) {\n\tsearchPaths = append(searchPaths, path)\n}\n\nfunc findFile(name string) string {\n\tbasename := fmt.Sprintf(\"%s.nr\", name)\n\tfor _, path := range searchPaths {\n\t\tfile := filepath.Join(path, basename)\n\t\tif fileExists(file) {\n\t\t\treturn file\n\t\t}\n\t}\n\treturn \"\"\n}\n\nfunc fileExists(file string) bool {\n\t_, err := os.Stat(file)\n\treturn err == nil\n}\n\nfunc evaluateFile(file string, env *object.Environment) (*object.Environment, object.Object) {\n\tsource, err := os.ReadFile(file)\n\tif err != nil {\n\t\treturn nil, &object.Error{Message: fmt.Sprintf(\"Tumeshindwa kufungua pakeji: %s\", file)}\n\t}\n\tl := lexer.New(string(source))\n\tp := parser.New(l)\n\tprogram := p.ParseProgram()\n\tif len(p.Errors()) != 0 {\n\t\treturn nil, &object.Error{Message: fmt.Sprintf(\"Pakeji %s ina makosa yafuatayo:\\n%s\", file, strings.Join(p.Errors(), \"\\n\"))}\n\t}\n\n\tscope := object.NewEnvironment()\n\tresult := Eval(program, scope)\n\tif isError(result) {\n\t\treturn nil, result\n\t}\n\treturn scope, nil\n}\n\nfunc importFile(name string, ident *ast.Identifier, env *object.Environment, scope *object.Environment) object.Object {\n\tvalue, ok := scope.Get(ident.Value)\n\tif !ok {\n\t\treturn newError(\"%s sio pakeji\", name)\n\t}\n\tenv.Set(name, value)\n\treturn NULL\n}\n"
  },
  {
    "path": "evaluator/in.go",
    "content": "package evaluator\n\nimport (\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalInExpression(left, right object.Object, line int) object.Object {\n\tswitch right.(type) {\n\tcase *object.String:\n\t\treturn evalInStringExpression(left, right)\n\tcase *object.Array:\n\t\treturn evalInArrayExpression(left, right)\n\tcase *object.Dict:\n\t\treturn evalInDictExpression(left, right, line)\n\tdefault:\n\t\treturn FALSE\n\t}\n}\n\nfunc evalInStringExpression(left, right object.Object) object.Object {\n\tif left.Type() != object.STRING_OBJ {\n\t\treturn FALSE\n\t}\n\tleftVal := left.(*object.String)\n\trightVal := right.(*object.String)\n\tfound := strings.Contains(rightVal.Value, leftVal.Value)\n\treturn nativeBoolToBooleanObject(found)\n}\n\nfunc evalInDictExpression(left, right object.Object, line int) object.Object {\n\tleftVal, ok := left.(object.Hashable)\n\tif !ok {\n\t\treturn newError(\"Mstari %d: Huwezi kutumia kama 'key': %s\", line, left.Type())\n\t}\n\tkey := leftVal.HashKey()\n\trightVal := right.(*object.Dict).Pairs\n\t_, ok = rightVal[key]\n\treturn nativeBoolToBooleanObject(ok)\n}\n\nfunc evalInArrayExpression(left, right object.Object) object.Object {\n\trightVal := right.(*object.Array)\n\tswitch leftVal := left.(type) {\n\tcase *object.Null:\n\t\tfor _, v := range rightVal.Elements {\n\t\t\tif v.Type() == object.NULL_OBJ {\n\t\t\t\treturn TRUE\n\t\t\t}\n\t\t}\n\tcase *object.String:\n\t\tfor _, v := range rightVal.Elements {\n\t\t\tif v.Type() == object.STRING_OBJ {\n\t\t\t\telem := v.(*object.String)\n\t\t\t\tif elem.Value == leftVal.Value {\n\t\t\t\t\treturn TRUE\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase *object.Integer:\n\t\tfor _, v := range rightVal.Elements {\n\t\t\tif v.Type() == object.INTEGER_OBJ {\n\t\t\t\telem := v.(*object.Integer)\n\t\t\t\tif elem.Value == leftVal.Value {\n\t\t\t\t\treturn TRUE\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase *object.Float:\n\t\tfor _, v := range rightVal.Elements {\n\t\t\tif v.Type() == object.FLOAT_OBJ {\n\t\t\t\telem := v.(*object.Float)\n\t\t\t\tif elem.Value == leftVal.Value {\n\t\t\t\t\treturn TRUE\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn FALSE\n}\n"
  },
  {
    "path": "evaluator/index.go",
    "content": "package evaluator\n\nimport \"github.com/NuruProgramming/Nuru/object\"\n\nfunc evalIndexExpression(left, index object.Object, line int) object.Object {\n\tswitch {\n\tcase left.Type() == object.ARRAY_OBJ && index.Type() == object.INTEGER_OBJ:\n\t\treturn evalArrayIndexExpression(left, index)\n\tcase left.Type() == object.ARRAY_OBJ && index.Type() != object.INTEGER_OBJ:\n\t\treturn newError(\"Mstari %d: Tafadhali tumia number, sio: %s\", line, index.Type())\n\tcase left.Type() == object.DICT_OBJ:\n\t\treturn evalDictIndexExpression(left, index, line)\n\tdefault:\n\t\treturn newError(\"Mstari %d: Operesheni hii haiwezekani kwa: %s\", line, left.Type())\n\t}\n}\n\nfunc evalArrayIndexExpression(array, index object.Object) object.Object {\n\tarrayObject := array.(*object.Array)\n\tidx := index.(*object.Integer).Value\n\tmax := int64(len(arrayObject.Elements) - 1)\n\n\tif idx < 0 || idx > max {\n\t\treturn NULL\n\t}\n\n\treturn arrayObject.Elements[idx]\n}\n\nfunc evalDictIndexExpression(dict, index object.Object, line int) object.Object {\n\tdictObject := dict.(*object.Dict)\n\n\tkey, ok := index.(object.Hashable)\n\tif !ok {\n\t\treturn newError(\"Mstari %d: Samahani, %s haitumiki kama ufunguo\", line, index.Type())\n\t}\n\n\tpair, ok := dictObject.Pairs[key.HashKey()]\n\tif !ok {\n\t\treturn NULL\n\t}\n\n\treturn pair.Value\n}\n"
  },
  {
    "path": "evaluator/infix.go",
    "content": "package evaluator\n\nimport (\n\t\"math\"\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalInfixExpression(operator string, left, right object.Object, line int) object.Object {\n\tif right == nil {\n\t\treturn newError(\"Mstari %d: Umekosea hapa\", line)\n\t}\n\tif left == nil {\n\t\treturn newError(\"Mstari %d: Umekosea hapa\", line)\n\t}\n\tswitch {\n\n\tcase operator == \"ktk\":\n\t\treturn evalInExpression(left, right, line)\n\n\tcase left.Type() == object.STRING_OBJ && right.Type() == object.STRING_OBJ:\n\t\treturn evalStringInfixExpression(operator, left, right, line)\n\n\tcase operator == \"+\" && left.Type() == object.DICT_OBJ && right.Type() == object.DICT_OBJ:\n\t\tleftVal := left.(*object.Dict).Pairs\n\t\trightVal := right.(*object.Dict).Pairs\n\t\tpairs := make(map[object.HashKey]object.DictPair)\n\t\tfor k, v := range leftVal {\n\t\t\tpairs[k] = v\n\t\t}\n\t\tfor k, v := range rightVal {\n\t\t\tpairs[k] = v\n\t\t}\n\t\treturn &object.Dict{Pairs: pairs}\n\n\tcase operator == \"+\" && left.Type() == object.ARRAY_OBJ && right.Type() == object.ARRAY_OBJ:\n\t\tleftVal := left.(*object.Array).Elements\n\t\trightVal := right.(*object.Array).Elements\n\t\telements := append(leftVal, rightVal...)\n\t\treturn &object.Array{Elements: elements}\n\n\tcase operator == \"*\" && left.Type() == object.ARRAY_OBJ && right.Type() == object.INTEGER_OBJ:\n\t\tleftVal := left.(*object.Array).Elements\n\t\trightVal := int(right.(*object.Integer).Value)\n\t\telements := leftVal\n\t\tfor i := rightVal; i > 1; i-- {\n\t\t\telements = append(elements, leftVal...)\n\t\t}\n\t\treturn &object.Array{Elements: elements}\n\n\tcase operator == \"*\" && left.Type() == object.INTEGER_OBJ && right.Type() == object.ARRAY_OBJ:\n\t\tleftVal := int(left.(*object.Integer).Value)\n\t\trightVal := right.(*object.Array).Elements\n\t\telements := rightVal\n\t\tfor i := leftVal; i > 1; i-- {\n\t\t\telements = append(elements, rightVal...)\n\t\t}\n\t\treturn &object.Array{Elements: elements}\n\n\tcase operator == \"*\" && left.Type() == object.STRING_OBJ && right.Type() == object.INTEGER_OBJ:\n\t\tleftVal := left.(*object.String).Value\n\t\trightVal := right.(*object.Integer).Value\n\t\treturn &object.String{Value: strings.Repeat(leftVal, int(rightVal))}\n\n\tcase operator == \"*\" && left.Type() == object.INTEGER_OBJ && right.Type() == object.STRING_OBJ:\n\t\tleftVal := left.(*object.Integer).Value\n\t\trightVal := right.(*object.String).Value\n\t\treturn &object.String{Value: strings.Repeat(rightVal, int(leftVal))}\n\n\tcase left.Type() == object.INTEGER_OBJ && right.Type() == object.INTEGER_OBJ:\n\t\treturn evalIntegerInfixExpression(operator, left, right, line)\n\n\tcase left.Type() == object.FLOAT_OBJ && right.Type() == object.FLOAT_OBJ:\n\t\treturn evalFloatInfixExpression(operator, left, right, line)\n\n\tcase left.Type() == object.INTEGER_OBJ && right.Type() == object.FLOAT_OBJ:\n\t\treturn evalFloatIntegerInfixExpression(operator, left, right, line)\n\n\tcase left.Type() == object.FLOAT_OBJ && right.Type() == object.INTEGER_OBJ:\n\t\treturn evalFloatIntegerInfixExpression(operator, left, right, line)\n\n\tcase operator == \"==\":\n\t\treturn nativeBoolToBooleanObject(left == right)\n\n\tcase operator == \"!=\":\n\t\treturn nativeBoolToBooleanObject(left != right)\n\tcase left.Type() == object.BOOLEAN_OBJ && right.Type() == object.BOOLEAN_OBJ:\n\t\treturn evalBooleanInfixExpression(operator, left, right, line)\n\n\tcase left.Type() != right.Type():\n\t\treturn newError(\"Mstari %d: Aina Hazilingani: %s %s %s\",\n\t\t\tline, left.Type(), operator, right.Type())\n\n\tdefault:\n\t\treturn newError(\"Mstari %d: Operesheni Haieleweki: %s %s %s\",\n\t\t\tline, left.Type(), operator, right.Type())\n\t}\n}\n\nfunc evalFloatIntegerInfixExpression(operator string, left, right object.Object, line int) object.Object {\n\tvar leftVal, rightVal float64\n\tif left.Type() == object.FLOAT_OBJ {\n\t\tleftVal = left.(*object.Float).Value\n\t\trightVal = float64(right.(*object.Integer).Value)\n\t} else {\n\t\tleftVal = float64(left.(*object.Integer).Value)\n\t\trightVal = right.(*object.Float).Value\n\t}\n\n\tvar val float64\n\tswitch operator {\n\tcase \"+\":\n\t\tval = leftVal + rightVal\n\tcase \"-\":\n\t\tval = leftVal - rightVal\n\tcase \"*\":\n\t\tval = leftVal * rightVal\n\tcase \"**\":\n\t\tval = math.Pow(float64(leftVal), float64(rightVal))\n\tcase \"/\":\n\t\tval = leftVal / rightVal\n\tcase \"%\":\n\t\tval = math.Mod(leftVal, rightVal)\n\tcase \"<\":\n\t\treturn nativeBoolToBooleanObject(leftVal < rightVal)\n\tcase \"<=\":\n\t\treturn nativeBoolToBooleanObject(leftVal <= rightVal)\n\tcase \">\":\n\t\treturn nativeBoolToBooleanObject(leftVal > rightVal)\n\tcase \">=\":\n\t\treturn nativeBoolToBooleanObject(leftVal >= rightVal)\n\tcase \"==\":\n\t\treturn nativeBoolToBooleanObject(leftVal == rightVal)\n\tcase \"!=\":\n\t\treturn nativeBoolToBooleanObject(leftVal != rightVal)\n\tdefault:\n\t\treturn newError(\"Mstari %d: Operesheni Haieleweki: %s %s %s\",\n\t\t\tline, left.Type(), operator, right.Type())\n\t}\n\n\tif math.Mod(val, 1) == 0 {\n\t\treturn &object.Integer{Value: int64(val)}\n\t} else {\n\t\treturn &object.Float{Value: val}\n\t}\n}\n\nfunc evalStringInfixExpression(operator string, left, right object.Object, line int) object.Object {\n\n\tleftVal := left.(*object.String).Value\n\trightVal := right.(*object.String).Value\n\n\tswitch operator {\n\tcase \"+\":\n\t\treturn &object.String{Value: leftVal + rightVal}\n\tcase \"==\":\n\t\treturn nativeBoolToBooleanObject(leftVal == rightVal)\n\tcase \"!=\":\n\t\treturn nativeBoolToBooleanObject(leftVal != rightVal)\n\tdefault:\n\t\treturn newError(\"Mstari %d: Operesheni Haieleweki: %s %s %s\", line, left.Type(), operator, right.Type())\n\t}\n}\n\nfunc evalBooleanInfixExpression(operator string, left, right object.Object, line int) object.Object {\n\tleftVal := left.(*object.Boolean).Value\n\trightVal := right.(*object.Boolean).Value\n\n\tswitch operator {\n\tcase \"&&\":\n\t\treturn nativeBoolToBooleanObject(leftVal && rightVal)\n\tcase \"||\":\n\t\treturn nativeBoolToBooleanObject(leftVal || rightVal)\n\tdefault:\n\t\treturn newError(\"Mstari %d: Operesheni Haieleweki: %s %s %s\", line, left.Type(), operator, right.Type())\n\t}\n}\n\nfunc evalFloatInfixExpression(operator string, left, right object.Object, line int) object.Object {\n\tleftVal := left.(*object.Float).Value\n\trightVal := right.(*object.Float).Value\n\n\tswitch operator {\n\tcase \"+\":\n\t\treturn &object.Float{Value: leftVal + rightVal}\n\tcase \"-\":\n\t\treturn &object.Float{Value: leftVal - rightVal}\n\tcase \"*\":\n\t\treturn &object.Float{Value: leftVal * rightVal}\n\tcase \"**\":\n\t\treturn &object.Float{Value: math.Pow(float64(leftVal), float64(rightVal))}\n\tcase \"/\":\n\t\treturn &object.Float{Value: leftVal / rightVal}\n\tcase \"<\":\n\t\treturn nativeBoolToBooleanObject(leftVal < rightVal)\n\tcase \"<=\":\n\t\treturn nativeBoolToBooleanObject(leftVal <= rightVal)\n\tcase \">\":\n\t\treturn nativeBoolToBooleanObject(leftVal > rightVal)\n\tcase \">=\":\n\t\treturn nativeBoolToBooleanObject(leftVal >= rightVal)\n\tcase \"==\":\n\t\treturn nativeBoolToBooleanObject(leftVal == rightVal)\n\tcase \"!=\":\n\t\treturn nativeBoolToBooleanObject(leftVal != rightVal)\n\tdefault:\n\t\treturn newError(\"Mstari %d: Operesheni Haieleweki: %s %s %s\",\n\t\t\tline, left.Type(), operator, right.Type())\n\t}\n}\n\nfunc evalIntegerInfixExpression(operator string, left, right object.Object, line int) object.Object {\n\tleftVal := left.(*object.Integer).Value\n\trightVal := right.(*object.Integer).Value\n\n\tswitch operator {\n\tcase \"+\":\n\t\treturn &object.Integer{Value: leftVal + rightVal}\n\tcase \"-\":\n\t\treturn &object.Integer{Value: leftVal - rightVal}\n\tcase \"*\":\n\t\treturn &object.Integer{Value: leftVal * rightVal}\n\tcase \"**\":\n\t\treturn &object.Float{Value: float64(math.Pow(float64(leftVal), float64(rightVal)))}\n\tcase \"/\":\n\t\tx := float64(leftVal) / float64(rightVal)\n\t\tif math.Mod(x, 1) == 0 {\n\t\t\treturn &object.Integer{Value: int64(x)}\n\t\t} else {\n\t\t\treturn &object.Float{Value: x}\n\t\t}\n\tcase \"%\":\n\t\treturn &object.Integer{Value: leftVal % rightVal}\n\tcase \"<\":\n\t\treturn nativeBoolToBooleanObject(leftVal < rightVal)\n\tcase \"<=\":\n\t\treturn nativeBoolToBooleanObject(leftVal <= rightVal)\n\tcase \">\":\n\t\treturn nativeBoolToBooleanObject(leftVal > rightVal)\n\tcase \">=\":\n\t\treturn nativeBoolToBooleanObject(leftVal >= rightVal)\n\tcase \"==\":\n\t\treturn nativeBoolToBooleanObject(leftVal == rightVal)\n\tcase \"!=\":\n\t\treturn nativeBoolToBooleanObject(leftVal != rightVal)\n\tdefault:\n\t\treturn newError(\"Mstari %d: Operesheni Haieleweki: %s %s %s\",\n\t\t\tline, left.Type(), operator, right.Type())\n\t}\n}\n"
  },
  {
    "path": "evaluator/method.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalMethodExpression(node *ast.MethodExpression, env *object.Environment) object.Object {\n\tobj := Eval(node.Object, env)\n\tif isError(obj) {\n\t\treturn obj\n\t}\n\targs := evalExpressions(node.Arguments, env)\n\tif len(args) == 1 && isError(args[0]) {\n\t\treturn args[0]\n\t}\n\n\tdefs := make(map[string]object.Object)\n\n\tfor k, v := range node.Defaults {\n\t\tdefs[k] = Eval(v, env)\n\t}\n\treturn applyMethod(obj, node.Method, args, defs, node.Token.Line)\n}\n\nfunc applyMethod(obj object.Object, method ast.Expression, args []object.Object, defs map[string]object.Object, l int) object.Object {\n\tswitch obj := obj.(type) {\n\tcase *object.String:\n\t\treturn obj.Method(method.(*ast.Identifier).Value, args)\n\tcase *object.File:\n\t\treturn obj.Method(method.(*ast.Identifier).Value, args)\n\tcase *object.Time:\n\t\treturn obj.Method(method.(*ast.Identifier).Value, args, defs)\n\tcase *object.Array:\n\t\tswitch method.(*ast.Identifier).Value {\n\t\tcase \"map\":\n\t\t\treturn maap(obj, args)\n\t\tcase \"chuja\":\n\t\t\treturn filter(obj, args)\n\t\tdefault:\n\t\t\treturn obj.Method(method.(*ast.Identifier).Value, args)\n\t\t}\n\tcase *object.Module:\n\t\tif fn, ok := obj.Functions[method.(*ast.Identifier).Value]; ok {\n\t\t\treturn fn(args, defs)\n\t\t}\n\tcase *object.Instance:\n\t\tif fn, ok := obj.Package.Scope.Get(method.(*ast.Identifier).Value); ok {\n\t\t\tfn.(*object.Function).Env.Set(\"@\", obj)\n\t\t\tret := applyFunction(fn, args, l)\n\t\t\tfn.(*object.Function).Env.Del(\"@\")\n\t\t\treturn ret\n\t\t}\n\tcase *object.Package:\n\t\tif fn, ok := obj.Scope.Get(method.(*ast.Identifier).Value); ok {\n\t\t\tfn.(*object.Function).Env.Set(\"@\", obj)\n\t\t\tret := applyFunction(fn, args, l)\n\t\t\tfn.(*object.Function).Env.Del(\"@\")\n\t\t\treturn ret\n\t\t}\n\t}\n\treturn newError(\"Samahani, %s haina function '%s()'\", obj.Inspect(), method.(*ast.Identifier).Value)\n}\n\n// ///////////////////////////////////////////////////////////////\n// //////// Some methods here because of loop dependency ////////\n// /////////////////////////////////////////////////////////////\nfunc maap(a *object.Array, args []object.Object) object.Object {\n\tif len(args) != 1 && args[0].Type() != object.FUNCTION_OBJ {\n\t\treturn newError(\"Samahani, hoja sii sahihi\")\n\t}\n\n\tfn, ok := args[0].(*object.Function)\n\tif !ok {\n\t\treturn newError(\"Samahani, hoja sii sahihi\")\n\t}\n\tenv := object.NewEnvironment()\n\tnewArr := object.Array{Elements: []object.Object{}}\n\tfor _, obj := range a.Elements {\n\t\tenv.Set(fn.Parameters[0].Value, obj)\n\t\tr := Eval(fn.Body, env)\n\t\tif o, ok := r.(*object.ReturnValue); ok {\n\t\t\tr = o.Value\n\t\t}\n\t\tnewArr.Elements = append(newArr.Elements, r)\n\t}\n\treturn &newArr\n}\n\nfunc filter(a *object.Array, args []object.Object) object.Object {\n\tif len(args) != 1 && args[0].Type() != object.FUNCTION_OBJ {\n\t\treturn newError(\"Samahani, hoja sii sahihi\")\n\t}\n\n\tfn, ok := args[0].(*object.Function)\n\tif !ok {\n\t\treturn newError(\"Samahani, hoja sii sahihi\")\n\t}\n\tenv := object.NewEnvironment()\n\tnewArr := object.Array{Elements: []object.Object{}}\n\tfor _, obj := range a.Elements {\n\t\tenv.Set(fn.Parameters[0].Value, obj)\n\t\tcond := Eval(fn.Body, env)\n\t\tif cond.Inspect() == \"kweli\" {\n\t\t\tnewArr.Elements = append(newArr.Elements, obj)\n\t\t}\n\t}\n\treturn &newArr\n}\n"
  },
  {
    "path": "evaluator/package.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalPackage(node *ast.Package, env *object.Environment) object.Object {\n\tpakeji := &object.Package{\n\t\tName:  node.Name,\n\t\tEnv:   env,\n\t\tScope: object.NewEnclosedEnvironment(env),\n\t}\n\n\tEval(node.Block, pakeji.Scope)\n\tenv.Set(node.Name.Value, pakeji)\n\treturn pakeji\n}\n"
  },
  {
    "path": "evaluator/postfix.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalPostfixExpression(env *object.Environment, operator string, node *ast.PostfixExpression) object.Object {\n\tval, ok := env.Get(node.Token.Literal)\n\tif !ok {\n\t\treturn newError(\"Tumia KITAMBULISHI CHA NAMBA AU DESIMALI, sio %s\", node.Token.Type)\n\t}\n\tswitch operator {\n\tcase \"++\":\n\t\tswitch arg := val.(type) {\n\t\tcase *object.Integer:\n\t\t\tv := arg.Value + 1\n\t\t\treturn env.Set(node.Token.Literal, &object.Integer{Value: v})\n\t\tcase *object.Float:\n\t\t\tv := arg.Value + 1\n\t\t\treturn env.Set(node.Token.Literal, &object.Float{Value: v})\n\t\tdefault:\n\t\t\treturn newError(\"Mstari %d: %s sio kitambulishi cha namba. Tumia '++' na kitambulishi cha namba au desimali.\\nMfano:\\tfanya i = 2; i++\", node.Token.Line, node.Token.Literal)\n\n\t\t}\n\tcase \"--\":\n\t\tswitch arg := val.(type) {\n\t\tcase *object.Integer:\n\t\t\tv := arg.Value - 1\n\t\t\treturn env.Set(node.Token.Literal, &object.Integer{Value: v})\n\t\tcase *object.Float:\n\t\t\tv := arg.Value - 1\n\t\t\treturn env.Set(node.Token.Literal, &object.Float{Value: v})\n\t\tdefault:\n\t\t\treturn newError(\"Mstari %d: %s sio kitambulishi cha namba. Tumia '--' na kitambulishi cha namba au desimali.\\nMfano:\\tfanya i = 2; i++\", node.Token.Line, node.Token.Literal)\n\t\t}\n\tdefault:\n\t\treturn newError(\"Haifahamiki: %s\", operator)\n\t}\n}\n"
  },
  {
    "path": "evaluator/prefix.go",
    "content": "package evaluator\n\nimport \"github.com/NuruProgramming/Nuru/object\"\n\nfunc evalMinusPrefixOperatorExpression(right object.Object, line int) object.Object {\n\tswitch obj := right.(type) {\n\n\tcase *object.Integer:\n\t\treturn &object.Integer{Value: -obj.Value}\n\n\tcase *object.Float:\n\t\treturn &object.Float{Value: -obj.Value}\n\n\tdefault:\n\t\treturn newError(\"Mstari %d: Operesheni Haieleweki: -%s\", line, right.Type())\n\t}\n}\nfunc evalPlusPrefixOperatorExpression(right object.Object, line int) object.Object {\n\tswitch obj := right.(type) {\n\n\tcase *object.Integer:\n\t\treturn &object.Integer{Value: obj.Value}\n\n\tcase *object.Float:\n\t\treturn &object.Float{Value: obj.Value}\n\n\tdefault:\n\t\treturn newError(\"Mstari %d: Operesheni Haieleweki: +%s\", line, right.Type())\n\t}\n}\n\nfunc evalPrefixExpression(operator string, right object.Object, line int) object.Object {\n\tswitch operator {\n\tcase \"!\":\n\t\treturn evalBangOperatorExpression(right)\n\tcase \"-\":\n\t\treturn evalMinusPrefixOperatorExpression(right, line)\n\tcase \"+\":\n\t\treturn evalPlusPrefixOperatorExpression(right, line)\n\tdefault:\n\t\treturn newError(\"Mstari %d: Operesheni Haieleweki: %s%s\", line, operator, right.Type())\n\t}\n}\n"
  },
  {
    "path": "evaluator/property.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalPropertyExpression(node *ast.PropertyExpression, env *object.Environment) object.Object {\n\tleft := Eval(node.Object, env)\n\tif isError(left) {\n\t\treturn left\n\t}\n\tswitch left.(type) {\n\tcase *object.Instance:\n\t\tobj := left.(*object.Instance)\n\t\tprop := node.Property.(*ast.Identifier).Value\n\t\tif val, ok := obj.Env.Get(prop); ok {\n\t\t\treturn val\n\t\t}\n\tcase *object.Package:\n\t\tobj := left.(*object.Package)\n\t\tprop := node.Property.(*ast.Identifier).Value\n\t\tif val, ok := obj.Env.Get(prop); ok {\n\t\t\treturn val\n\t\t}\n\t\t// case *object.Module:\n\t\t// \tmod := left.(*object.Module)\n\t\t// \tprop := node.Property.(*ast.Identifier).Value\n\t\t// \tif val, ok := mod.Properties[prop]; ok {\n\t\t// \t\treturn val()\n\t\t// \t}\n\t}\n\treturn newError(\"Value %s sii sahihi kwenye %s\", node.Property.(*ast.Identifier).Value, left.Inspect())\n}\n\nfunc evalPropertyAssignment(name *ast.PropertyExpression, val object.Object, env *object.Environment) object.Object {\n\tleft := Eval(name.Object, env)\n\tif isError(left) {\n\t\treturn left\n\t}\n\tswitch left.(type) {\n\tcase *object.Instance:\n\t\tobj := left.(*object.Instance)\n\t\tprop := name.Property.(*ast.Identifier).Value\n\t\tif _, ok := obj.Env.Get(prop); ok {\n\t\t\tobj.Env.Set(prop, val)\n\t\t\treturn NULL\n\t\t}\n\t\tobj.Env.Set(prop, val)\n\t\treturn NULL\n\tcase *object.Package:\n\t\tobj := left.(*object.Package)\n\t\tprop := name.Property.(*ast.Identifier).Value\n\t\tif _, ok := obj.Env.Get(prop); ok {\n\t\t\tobj.Env.Set(prop, val)\n\t\t\treturn NULL\n\t\t}\n\t\tobj.Env.Set(prop, val)\n\t\treturn NULL\n\tdefault:\n\t\treturn newError(\"Imeshindikana kuweka kwenye pakiti %s\", left.Type())\n\t}\n}\n"
  },
  {
    "path": "evaluator/switch.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalSwitchStatement(se *ast.SwitchExpression, env *object.Environment) object.Object {\n\tobj := Eval(se.Value, env)\n\tfor _, opt := range se.Choices {\n\n\t\tif opt.Default {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, val := range opt.Expr {\n\t\t\tout := Eval(val, env)\n\t\t\tif obj.Type() == out.Type() && obj.Inspect() == out.Inspect() {\n\t\t\t\tblockOut := evalBlockStatement(opt.Block, env)\n\t\t\t\treturn blockOut\n\t\t\t}\n\t\t}\n\t}\n\tfor _, opt := range se.Choices {\n\t\tif opt.Default {\n\t\t\tout := evalBlockStatement(opt.Block, env)\n\t\t\treturn out\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "evaluator/type.go",
    "content": "package evaluator\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc convertToInteger(obj object.Object) object.Object {\n\tswitch obj := obj.(type) {\n\tcase *object.Integer:\n\t\treturn obj\n\tcase *object.Float:\n\t\treturn &object.Integer{Value: int64(obj.Value)}\n\tcase *object.String:\n\t\ti, err := strconv.ParseInt(obj.Value, 10, 64)\n\t\tif err != nil {\n\t\t\treturn newError(\"Haiwezi kubadilisha '%s' kuwa NAMBA\", obj.Value)\n\t\t}\n\t\treturn &object.Integer{Value: i}\n\tcase *object.Boolean:\n\t\tif obj.Value {\n\t\t\treturn &object.Integer{Value: 1}\n\t\t}\n\t\treturn &object.Integer{Value: 0}\n\tdefault:\n\t\treturn newError(\"Haiwezi kubadilisha %s kuwa NAMBA\", obj.Type())\n\t}\n}\n\nfunc convertToFloat(obj object.Object) object.Object {\n\tswitch obj := obj.(type) {\n\tcase *object.Float:\n\t\treturn obj\n\tcase *object.Integer:\n\t\treturn &object.Float{Value: float64(obj.Value)}\n\tcase *object.String:\n\t\tf, err := strconv.ParseFloat(obj.Value, 64)\n\t\tif err != nil {\n\t\t\treturn newError(\"Haiwezi kubadilisha '%s' kuwa DESIMALI\", obj.Value)\n\t\t}\n\t\treturn &object.Float{Value: f}\n\tcase *object.Boolean:\n\t\tif obj.Value {\n\t\t\treturn &object.Float{Value: 1.0}\n\t\t}\n\t\treturn &object.Float{Value: 0.0}\n\tdefault:\n\t\treturn newError(\"Haiwezi kubadilisha %s kuwa DESIMALI\", obj.Type())\n\t}\n}\n\nfunc convertToString(obj object.Object) object.Object {\n\treturn &object.String{Value: obj.Inspect()}\n}\n\nfunc convertToBoolean(obj object.Object) object.Object {\n\tswitch obj := obj.(type) {\n\tcase *object.Boolean:\n\t\treturn obj\n\tcase *object.Integer:\n\t\treturn &object.Boolean{Value: obj.Value != 0}\n\tcase *object.Float:\n\t\treturn &object.Boolean{Value: obj.Value != 0}\n\tcase *object.String:\n\t\treturn &object.Boolean{Value: len(obj.Value) > 0}\n\tcase *object.Null:\n\t\treturn &object.Boolean{Value: false}\n\tdefault:\n\t\treturn &object.Boolean{Value: true}\n\t}\n}\n"
  },
  {
    "path": "evaluator/while.go",
    "content": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nconst MAX_ITERATIONS = 1_000_000\n\nfunc evalWhileExpression(we *ast.WhileExpression, env *object.Environment) object.Object {\n\tvar evaluated object.Object\n\titerations := 0\n\n\tfor {\n\t\titerations++\n\t\tif iterations > MAX_ITERATIONS {\n\t\t\treturn newError(\"mzunguko usio na mwisho umegunduliwa\")\n\t\t}\n\n\t\tcondition := Eval(we.Condition, env)\n\t\tif isError(condition) {\n\t\t\treturn condition\n\t\t}\n\n\t\tif !isTruthy(condition) {\n\t\t\tbreak\n\t\t}\n\n\t\tevaluated = Eval(we.Consequence, env)\n\t\tif isError(evaluated) {\n\t\t\treturn evaluated\n\t\t}\n\n\t\tif evaluated != nil && evaluated.Type() == object.BREAK_OBJ {\n\t\t\treturn evaluated\n\t\t}\n\t}\n\n\treturn evaluated\n}\n"
  },
  {
    "path": "examples/Astart.nr",
    "content": "/*############ A*(A-star) Algorithm ##############\n             \n             By @VictorKariuki\n\n        https://github.com/VictorKariuki\n\n################################################*/\n\n\n// create a list of numbers\nfanya list = unda(first,last,interval){\n  fanya list = [first];\n  fanya i = first + interval;\n  wakati(i < last){\n    list.sukuma(i)\n    i+=interval;\n  }\n  rudisha list;\n}\n\n// Maths functions\n// find the absolute value of a number\nfanya abs_namba = unda(namba){\n  kama(namba < 0){\n    rudisha -1 * namba;\n  }\n\n  rudisha namba;\n}\n\n// square a number\nfanya square = unda(n, i, j){\n  fanya kati  = (i+j)/2;\n  fanya mul = kati * kati;\n  fanya abs_diff = abs_namba(mul-n);\n\n  kama (mul == n || abs_diff < 0.00001){\n    rudisha kati;\n  }au kama(mul < n){\n    rudisha square(n,kati,j)\n  }au{\n    rudisha square(n,i,kati)\n  }\n}\n\n// find the square root of a number\nfanya sqrt = unda(namba){\n  kwa i ktk list(0,namba,1) {\n    kama((i*i )== namba){\n      rudisha i;\n    }au kama ((i*i )> namba){\n      rudisha square(namba,i-1,i)\n    }\n  }\n}\n\n// Main function\nfanya aStar = unda(start, goal) {\n  // Initialize the open and closed lists\n  fanya openList = [start];\n  fanya closedList = [];\n\n  fanya reconstructPath = unda(node) {\n    fanya path = [node];\n    wakati (node[\"parent\"]) {\n      path = [node[\"parent\"]] + path;\n      node = node[\"parent\"];\n    }\n    rudisha path;\n  }\n\n  fanya heuristic = unda(node1, node2) {\n    // Calculate the Euclidean distance between the nodes' positions\n    fanya dx = node1[\"x\"] - node2[\"x\"];\n    fanya dy = node1[\"y\"] - node2[\"y\"];\n    rudisha sqrt(dx * dx + dy * dy);\n  }\n\n  fanya findMinNode = unda(openList) {\n    fanya i = 1;\n    fanya minNode = openList[0];\n\n    wakati (i < openList.idadi()) {\n      fanya node = openList[i];\n      kama (node[\"f\"] < minNode[\"f\"]) {\n        minNode = node;\n      }\n      i++\n    }\n\n    rudisha minNode;\n  }\n\n  fanya removeNodeFromArray = unda(array, node) {\n    fanya newArray = [];\n    fanya i = 1;\n    wakati (i < array.idadi()) {\n      kama (array[i] != node) {\n        newArray.sukuma(array[i]);\n      }\n      i++;\n    }\n    rudisha newArray;\n  }\n\n  fanya urefu = unda(node1, node2) {\n    // Assume all edges have a cost of 1\n    rudisha 1;\n  }\n\n  // Initialize the g and f scores of the starting node\n  start[\"g\"] = 0;\n  start[\"f\"] = start[\"g\"] + heuristic(start, goal);\n\n  \n\n  // Start the search loop\n  wakati (openList.idadi() > 0) {\n    // Find the node with the lowest f score in the open list\n    fanya current = findMinNode(openList);\n\n    // Check kama the goal node has been reached\n    kama (current == goal) {\n      rudisha reconstructPath(current);\n    }\n\n    // Move the current node from the open to the closed list\n    openList = removeNodeFromArray(openList, current);\n\n    closedList.sukuma(current);\n\n    // Explore the neighbors of the current node\n    kwa neighbor ktk current[\"neighbors\"] {\n      // Skip neighbors that are in the closed list\n      kama (neighbor ktk closedList) {\n        endelea\n      }\n\n      // Calculate the tentative g score of the neighbor\n      fanya tentativeG = start[\"g\"] + urefu(current, neighbor);\n\n      // Check kama the neighbor is in the open list\n      fanya tentativeIsBetter = sikweli;\n      kama (!(neighbor ktk openList)) {\n        openList.sukuma(neighbor);\n        tentativeIsBetter = kweli;\n      } au kama (tentativeG < neighbor[\"g\"]) {\n        tentativeIsBetter = kweli;\n      }\n\n      // Update the neighbor's g score kama the tentative score is better\n      kama (tentativeIsBetter) {\n        neighbor[\"g\"] = tentativeG;\n        neighbor[\"f\"] = neighbor[\"g\"] + heuristic(neighbor, goal);\n        neighbor[\"parent\"] = current;\n      }\n    }\n  }\n\n  // kama the open list is empty, no path was found\n  rudisha tupu;\n}\n\n// Define the nodes of the graph\nfanya nodeA = { \"x\": 0, \"y\": 0, \"neighbors\": [] };\nfanya nodeB = { \"x\": 1, \"y\": 2, \"neighbors\": [] };\nfanya nodeC = { \"x\": 3, \"y\": 1, \"neighbors\": [] };\nfanya nodeD = { \"x\": 4, \"y\": 3, \"neighbors\": [] };\n\n// Define the edges between the nodes\nnodeA[\"neighbors\"] = [nodeB];\nnodeB[\"neighbors\"] = [nodeA, nodeC];\nnodeC[\"neighbors\"] = [nodeB, nodeD];\nnodeD[\"neighbors\"] = [nodeC];\n\n// Call the A* function with the start and goal nodes and the heuristic and distance functions\n//fanya path = aStar(nodeA, nodeC);\n\nandika(nodeA);"
  },
  {
    "path": "examples/example.nr",
    "content": "// basics\n\njina = \"Nuru\"\nandika(jina) // Nuru\n\n// lists\n\norodha = [1, \"pili\", kweli]\n\nnamba = [10, 20, 30]\njina = namba[1]  // jina is 20\n\nnamba[1] = 25\n\na = [1, 2, 3]\nb = [4, 5, 6]\nc = a + b // c is now [1, 2, 3, 4, 5, 6]\n\nnamba = [10, 20, 30]\nandika(20 ktk namba)  // will print kweli\n\nnamba = [1, 2, 3, 4, 5]\n\nkwa thamani ktk namba {\n    andika(thamani)\n}\n\nmajina = [\"Juma\", \"Asha\", \"Haruna\"]\n\nkwa idx, jina ktk majina {\n    andika(idx, \"-\", jina)\n}\n\na = [1, 2, 3]\nurefu = a.idadi()\nandika(urefu)  // will print 3\n\na = [1, 2, 3]\na.sukuma(\"s\", \"g\")\nandika(a)  // will print [1, 2, 3, \"s\", \"g\"]\n\na = [1, 2, 3]\nmwisho = a.yamwisho()\nandika(mwisho)  // will print 3\n\nb = []\nmwisho = b.yamwisho()\nandika(mwisho)  // will print tupu\n\nandika(1 > 2) // Output: `sikweli`\n\nandika(1 + 3 < 10) // Output: `kweli`\n\na = 5\nb = 10\nc = 15\n\nresult = (a < b) && (b < c)\n\nkama (result) {\n    andika(\"Both conditions are true\")\n} sivyo {\n    andika(\"At least one condition is false\")\n}\n\n// Output: \"Both conditions are true\"\n\nandika(kweli && kweli) // Output: `kweli`\n\nandika(kweli && sikweli) // Output: `sikweli`\n\nandika(kweli || sikweli) // Output: `kweli`\n\nandika(sikweli || sikweli) // Output: `sikweli`\n\nandika(!kweli) // Output: `sikweli`\n\nandika(!sikweli) // Output: `kweli`\n\nnamba = [1, 2, 3, 4, 5]\n\nkwa thamani ktk namba {\n    kama (thamani % 2 == 0) {\n        andika(thamani, \"is even\")\n    } sivyo {\n        andika(thamani, \"is odd\")\n    }\n}\n// Output:\n// 1 is odd\n// 2 is even\n// 3 is odd\n// 4 is even\n// 5 is odd\n\nsalamu = unda() {\n    jina = jaza(\"Unaitwa nani? \")\n    andika(\"Mambo vipi\", jina)\n}\n\nsalamu()\n\naina(2) // Output: \"NAMBA\"\naina(\"Nuru\") // Output: \"NENO\"\n\n\norodha = {\"jina\": \"Juma\", \"umri\": 25}\n\nk = {\n    \"jina\": \"Juma\",\n    \"umri\": 25,\n    kweli: \"kweli\",\n    \"salimu\": unda(x) { andika(\"habari\", x) },\n    \"sina value\": tupu\n}\n\n\nandika(k[kweli]) // kweli\nandika(k[\"salimu\"](\"Juma\")) // habari Juma\n\nk['umri'] = 30\nandika(k['umri']) // 30\n\nk[\"lugha\"] = \"Kiswahili\"\nandika(k[\"lugha\"]) // Kiswahili\n\nmatunda = {\"a\": \"apple\", \"b\": \"banana\"}\nmboga = {\"c\": \"carrot\", \"d\": \"daikon\"}\nvyakula = matunda + mboga\nandika(vyakula) // {\"a\": \"apple\", \"b\": \"banana\", \"c\": \"carrot\", \"d\": \"daikon\"}\n\n\n\"umri\" ktk k // kweli\n\"urefu\" ktk k // sikweli\n\n\nhobby = {\"a\": \"asili\", \"b\": \"baiskeli\", \"c\": \"chakula\"}\nkwa i, v ktk hobby {\n    andika(i, \"=>\", v)\n}\n/* a => asili\n   b => baiskeli\n   c => chakula */\n\n\nkwa v ktk hobby {\n    andika(v)\n}\n\n/*\nasili\nbaiskeli\nchakula\n*/\n\njina = \"lugano\"\n\nkwa i ktk jina {\n    andika(i)\n}\n\nkamusi = {\"a\": \"andaa\", \"b\": \"baba\"}\n\nkwa v ktk kamusi {\n    andika(v)\n}\n\n\nkwa k, v ktk kamusi {\n    andika(k + \" ni \" + v)\n}\n\nkwa v ktk \"mojo\" {\n    andika(v)\n}\n\nkwa i, v ktk \"mojo\" {\n    andika(i, \"->\", v)\n}\n\nmajina = [\"juma\", \"asha\", \"haruna\"]\n\nkwa v ktk majina {\n    andika(v)\n}\n\nkwa i, v ktk majina {\n    andika(i, \"-\", v)\n}\n\n\nkwa i, v ktk \"mojo\" {\n    kama (i == 2) {\n        andika(\"nimevunja\")\n        vunja\n    }\n    andika(v)\n}\n\nkwa i, v ktk \"mojo\" {\n    kama (i == 2) {\n        andika(\"nimeruka\")\n        endelea\n    }\n    andika(v)\n}\n\njum = unda(x, y) {\n    rudisha x + y\n}\n\njum(2, 3) // 5\n\nsalamu = unda() {\n    andika(\"Habari yako\")\n}\n\nsalamu()\n\nsalamu = unda(jina) {\n    andika(\"Habari yako\", jina)\n}\n\nsalamu(\"asha\") // Habari yako asha\n\nsalimu = unda(salamu=\"Habari\") {\n    andika(salamu)\n}\n\nsalimu() // Habari\nsalimu(\"Mambo\") // Mambo\n\nmfano = unda(x) {\n    rudisha \"nimerudi\"\n    andika(x)\n}\n\nmfano(\"x\") // nimerudi\n\n\nfib = unda(n) {\n    kama (n <= 1) {\n        rudisha n\n    } sivyo {\n        rudisha fib(n-1) + fib(n-2)\n    }\n}\n\nandika(fib(10)) // 55\n\njum = unda(x) {\n    rudisha unda(y) {\n        rudisha x + y\n    }\n}\n\njum_x = jum(5)\nandika(jum_x(3)) // 8\n\n2 + 3 * 5 // 17\n\na = 2.5\nb = 3/5\n\na + b // 2.8\n\ni = 2.4\n\ni++ // 3.4\n\ni = 2\n\ni *= 3 // 6\ni /= 2 // 3\ni += 100 // 103\ni -= 10 // 93\ni %= 90 // 3\n\ni = -10\n\nwakati (i < 0) {\n    andika(i)\n    i++\n}\n\n\nandika(\"mambo\") // mambo\n\na = 'niaje'\n\nandika(\"mambo\", a) // mambo niaje\n\na = \"habari\" + \" \" + \"yako\"\n\nandika(a) // habari yako\n\nb = \"habari\"\n\nb += \" yako\"\n\n// habari yako\n\nandika(\"mambo \" * 4)\n\n// mambo mambo mambo mambo\n\na = \"habari\"\n\na *= 4\n\n// habarihabarihabarihabari\n\njina = \"avicenna\"\n\nkwa i ktk jina {andika(i)}\n\na = \"nuru\"\n\nandika(a == \"nuru\") // kweli\n\nandika(a == \"mambo\") // sikweli\n\na = \"mambo\"\na.idadi() // 5\n\na = \"NURU\"\na.herufindogo() // nuru\n\na = \"nuru mambo habari\"\nb = a.gawa()\nandika(b) // [\"nuru\", \"mambo\", \"habari\"]\n\na = \"nuru,mambo,habari\"\nb = a.gawa(\",\")\nandika(b) // [\"nuru\", \"mambo\", \"habari\"]\n\na = 2\n\nbadili (a){\n\tikiwa 3 {\n\t\tandika(\"a ni tatu\")\n\t}\n\tikiwa 2 {\n\t\tandika (\"a ni mbili\")\n\t}\n}\n\nbadili (a) {\n\tikiwa 1,2,3 {\n\t\tandika(\"a ni kati ya 1, 2 au 3\")\n\t}\n\tikiwa 4 {\n\t\tandika(\"a ni 4\")\n\t}\n}\n\nz = 20\n\nbadili(z) {\n\tikiwa 10 {\n\t\tandika(\"kumi\")\n\t}\n\tikiwa 30 {\n\t\tandika(\"thelathini\")\n\t}\n\tkawaida {\n\t\tandika(\"ishirini\")\n\t}\n}\n\ni = 1\n\nwakati (i <= 5) {\n\tandika(i)\n\ti++\n}\n\ni = 1\n\nwakati (i < 5) {\n\tkama (i == 3) {\n\t\tandika(\"nimevunja\")\n\t\tvunja\n\t}\n\tandika(i)\n\ti++\n}\n\ni = 0\n\nwakati (i < 5) {\n\ti++\n\tkama (i == 3) {\n\t\tandika(\"nimeruka\")\n\t\tendelea\n\t}\n\tandika(i)\n}\n\n// using time:\n\ntumia muda \n\nandika(muda.hasahivi())\nandika(\"Tunalala\")\nmuda.lala(2)\nandika(\"Tumeamka\")\n\ns = muda.hasahivi()\nmuda.lala(2)\nandika(muda.tangu(s))\n\nandika(s.ongeza(sekunde=3, miaka=10, dakika=4))\n\n// using file:\n\nfail = fungua(\"sarufi.nr\")\n\nandika(fail.soma())\n\n// using net and json:\n\ntumia mtandao, jsoni\nurl = \"https://v2.jokeapi.dev/joke/Any?type=single\"\n\nresp = mtandao.peruzi(url)\n\nresp = jsoni.dikodi(resp)\n\nandika(resp[\"joke\"])\n\n\n// os module\n\ntumia os\n\nandika(os.kimbiza(\"pwd\"))\n\nos.toka(0)\n"
  },
  {
    "path": "examples/perceptron.nr",
    "content": "tumia hisabati\n\n// Mbinu za Kupanga\n//orodhesha(kwanza, mwisho, umbali), huunda orodha ya nambari na umbali uliowekwa kati yao.\nfanya orodhesha = unda(kwanza, mwisho, umbali){\n    fanya orodha = [kwanza];\n    fanya i = kwanza + umbali;\n    wakati(i < mwisho){\n        orodha.sukuma(i);\n        i += umbali;\n    }\n    rudisha orodha;\n}\n\n// Kuanzisha uzani bila mpangilio\nfanya mizani = [\n    hisabati.random() * 2 - 1,\n    hisabati.random() * 2 - 1,\n    hisabati.random() * 2 - 1\n];\n\n// Undo la uanzishaji wa Sigmoid\nfanya sigmoid = unda(vekta) {\n    fanya tokeo = [];\n    kwa v ktk vekta {\n        tokeo.sukuma(1 / (1 + hisabati.exp(-1 * v)));\n    }\n    rudisha tokeo;\n}\n\n// Derivative ya undo la sigmoid\nfanya sigmoidDerivative  = unda(vekta) {\n    andika(\"vekta: \",vekta)\n    fanya tokeo = [];\n    kwa v ktk vekta {\n        tokeo.sukuma(v * (1 - v));\n    }\n    \n    rudisha tokeo;\n}\n\nfanya kuzidishaMatrikiVekta = unda(matriki, vekta) {\n    fanya tokeo = [];\n    kwa row ktk matriki {\n        fanya jamii = 0;\n        kwa j, kipengee ktk row {\n            jamii += kipengee * vekta[j];\n        }\n        tokeo.sukuma(jamii);        \n    }\n    rudisha tokeo;\n}\n\nfanya zidishaKwaNukta = unda(safu1, safu2) {\n    // Angalia ikiwa safu zina urefu sawa\n    kama (safu1.idadi() != safu2.idadi()) {\n        andika(\"Safu lazima ziwe na urefu sawa kwa kuzidisha kwa busara ya kipengele.\");\n    }\n\n    // Perform element-wise multiplication\n    fanya tokeo = [];\n    kwa i, kipengee ktk safu1 {\n        tokeo.sukuma(kipengee * safu2[i]);\n    }\n    rudisha tokeo;\n}\n\n// Songa mbele kupitia mtandao wa neva\nfanya waza = unda(pembejeo, mizani) {\n    fanya jumlaYaUzani = sigmoid(kuzidishaMatrikiVekta(pembejeo, mizani));\n    rudisha jumlaYaUzani;\n}\n\nfanya badiliMatriki = unda(matrix) {\n    // Pata idadi ya safu mlalo na safu wima katika matrix asili\n    fanya nambari_ya_safu_mlalo = matrix.idadi();\n    fanya nambari_ya_safu_wima = matrix[0].idadi();\n\n    // Unda matrix mpya na safu mlalo na safu wima zilizobadilishwa\n    fanya matrikiIliyobadili = [];\n\n    // Pita ndani ya safu wima\n    kwa safu_wima_ya, safuW ktk orodhesha(0, nambari_ya_safu_wima, 1){\n        // Anzisha safu mlalo mpya kwa matriki iliyopitishwa\n        fanya transposed_safu_mlalo = [];\n\n        // Pita ndani ya safu mlalo\n        kwa safu_mlalo_ya, safu ktk orodhesha(0, nambari_ya_safu_mlalo, 1){\n            // Sukuma kipengele kwenye safu wima ya sasa na safu mlalo hadi safu iliyopitishwa\n            transposed_safu_mlalo.sukuma(matrix[safu_mlalo_ya][safu_wima_ya]);\n        }\n\n        // Sukuma safu mlalo iliyopitishwa kwenye matriki lililopitishwa\n        matrikiIliyobadili.sukuma(transposed_safu_mlalo);\n    }\n\n    rudisha matrikiIliyobadili;\n}\n\n// Funza mtandao wa neva\nfanya funza = unda(mizani, mafunzoPembejeo, matokeoYaMafunzo, marudioYaMafunzo) {\n    fanya kurudia = 0\n\n    andika('\\nmafunzoPembejeo: ');\n    andika(mafunzoPembejeo);\n\n    andika('\\nmatokeoYaMafunzo: ');\n    andika(matokeoYaMafunzo);\n\n    \n    fanya orodha = orodhesha(0, marudioYaMafunzo, 1)\n    // andika(\"orodha: \",orodha)\n\n    kwa i ktk orodha{\n        andika('\\n\\nkurudia: ');\n        andika(i);\n       // Pitisha mafunzo yaliyowekwa kupitia mtandao wa neva\n        fanya pato = waza(mafunzoPembejeo, mizani);\n\n        andika('\\npato: ');\n        andika(pato);\n        \n        // Kuhesabu kiwango cha upungufu\n        fanya upungufu = [];\n        kwa i, kipengee ktk matokeoYaMafunzo {\n            upungufu.sukuma(kipengee - pato[i]);           \n        }\n\n        andika('\\nupungufu: ');\n        andika(upungufu);\n\n        fanya sigmoidDerivative_ya_pato = sigmoidDerivative(pato)\n\n        andika('\\nsigmoidDerivative tokeo: ');\n        andika(sigmoidDerivative_ya_pato);\n\n        fanya zidishaKwaNukta_tokeo = zidishaKwaNukta(upungufu, sigmoidDerivative_ya_pato);\n\n        andika('\\nzidishaKwaNukta tokeo: ');\n        andika(zidishaKwaNukta_tokeo);\n        \n        fanya mafunzoPembejeoYaliyobadili = badiliMatriki(mafunzoPembejeo)\n\n        andika('\\nmafunzo pembejeo yaliyobadili: ');\n        andika(mafunzoPembejeoYaliyobadili);\n\n        // Kuzidisha upungufu kwa pembejeo na upinde rangi ya kitendakazi cha sigmoid\n        // Uzito mdogo wa ujasiri hurekebishwa zaidi kupitia asili ya kazi\n        fanya marekebisho = kuzidishaMatrikiVekta(mafunzoPembejeo, zidishaKwaNukta_tokeo);\n        andika('\\nmarekebisho tokeo: ');\n        andika(marekebisho);\n\n\n        // Rekebisha uzani\n        kwa i, j ktk mizani {\n            mizani[i] = mizani[i] + marekebisho[i];           \n        }\n\n        andika('\\nmizani mpya: ');\n        andika(mizani);\n        kurudia++\n    }\n\n    rudisha mizani;\n}\n\n\nandika('\\nMizani ya Kuanzisha isiyo na mpangilio: ');\nandika(mizani);\n\n// Seti ya mafunzo\nfanya mafunzoPembejeo = [[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]];\nfanya matokeoYaMafunzo = [0, 1, 1, 0];\n\n// Funza mtandao wa neva\nfanya mafunzoMizani = funza(mizani, mafunzoPembejeo, matokeoYaMafunzo, 10000);\n\nandika('\\nMizani baada ya mafunzo:');\nandika(mafunzoMizani);\n\n// Ingizo la mtumiaji kwa hali mpya\nfanya A = 0;\nfanya B = 0;\nfanya C = 1;\n\nandika('\\nHali mpya: data ya pembejeo = ', A, B, C);\nandika('\\nData ya pato:');\nandika(waza([[A, B, C]], mafunzoMizani));\n"
  },
  {
    "path": "examples/reduce.nr",
    "content": "fanya reduce = unda(iterator, callback, initialValue) {\n  fanya accumulator = initialValue;\n\n  kwa thamani ktk iterator {\n    accumulator = callback(accumulator, thamani);\n  }\n\n  rudisha accumulator;\n}\n\nfanya list = [1,2,3,4,5];\nfanya employees = [{\"salary\":120},{\"salary\":135},{\"salary\":140}]\n\nfanya sum = unda(acc,value){\n  rudisha acc + value;\n}\n\nfanya mul = unda(acc,value){\n  rudisha acc * value;\n}\n\nfanya sumSalo = unda(acc,value){\n  rudisha acc + value[\"salary\"];\n}\n\nfanya sumSaloWithTax = unda(acc,value){\n  rudisha acc + (value[\"salary\"] * (1-0.34));\n}\n\nandika(reduce(list,sum,0))\nandika(reduce(list,mul,1))\n\nandika(reduce(employees,sumSalo,0))\nandika(reduce(employees,sumSaloWithTax,0))"
  },
  {
    "path": "examples/sarufi.nr",
    "content": "tumia mtandao\ntumia jsoni\npakeji sarufi {\n    andaa = unda(file) {\n        config = fungua(file)\n        configString = config.soma()\n        configDict = jsoni.dikodi(configString)\n        clientID = configDict[\"client_id\"]\n        clientSecret = configDict[\"client_secret\"]\n        params = {\"client_id\": clientID, \"client_secret\": clientSecret}\n        tokenString = mtandao.tuma(yuareli=\"https://api.sarufi.io/api/access_token\", mwili=params)\n        tokenDict = jsoni.dikodi(tokenString)\n        @.token = tokenDict[\"access_token\"]\n        @.Auth = \"Bearer \" + @.token\n        }\n\n    tokenYangu = unda() {\n            rudisha @.token\n        }\n\n    tengenezaChatbot = unda(data) {\n            majibu = mtandao.tuma(yuareli=\"https://api.sarufi.io/chatbot\", vichwa={\"Authorization\": @.Auth}, mwili = data)\n            rudisha majibu\n        }\n\n    pataChatbotZote = unda() {\n            majibu = mtandao.peruzi(yuareli=\"https://api.sarufi.io/chatbots\", vichwa={\"Authorization\": @.Auth})\n            rudisha majibu\n        }\n}\n\n\n"
  },
  {
    "path": "examples/sorting_algorithm.nr",
    "content": "/* \n############ Sorting Algorithm ##############\n             \n             By @VictorKariuki\n\n        https://github.com/VictorKariuki\n\n#############################################\n*/\n\nslice = unda(arr,start, end) {\n    result = []\n    wakati (start < end) {\n        result = result + [arr[start]]\n        start = start + 1\n    }\n    rudisha result\n}\n\nmerge = unda(left, right) {\n    result = []\n    lLen = left.idadi()\n    rLen = right.idadi()\n     l = 0\n     r = 0\n    wakati (l < lLen && r < rLen) {\n        kama (left[l] < right[r]) {\n            result = result + [left[l]]\n            l = l + 1\n        } sivyo {\n            result = result + [right[r]]\n            r = r + 1\n        }\n    }\n    andika(result)\n}\n\n\nmergeSort = unda(arr){\n    len = arr.idadi()\n    andika(\"arr is \", arr,\" of length \", len)\n    kama (len < 2) {\n        rudisha arr\n    }\n    andika(\"len is greater than or == to 2\", len > 1)\n\n    mid = (len / 2)\n    andika(\"arr has a mid point of \", mid)\n   \n    left = slice(arr, 0, mid)\n    right = slice(arr, mid, len)\n    andika(\"left slice is \", left)\n    andika(\"right slice is \", right)\n    sortedLeft = mergeSort(left)\n    sortedRight = mergeSort(right)\n    andika(\"sortedLeft is \", sortedLeft)\n    andika(\"sortedRight is \", sortedRight)\n    rudisha merge(sortedLeft, sortedRight)\n}\n\narr = [6, 5, 3, 1, 8, 7, 2, 4]\nsortedArray = mergeSort(arr)\nandika(sortedArray)\n"
  },
  {
    "path": "examples/sudoku_solver.nr",
    "content": "/*########### Backtracking Algorithm ##############\n            \n                By @VictorKariuki\n\n        https://github.com/VictorKariuki\n\nNURU program to solve Sudoku using Backtracking Algorithm\n\nThe sudoku puzzle is represented as a 2D array. The empty \ncells are represented by 0. The algorithm works by trying\nout all possible numbers for an empty cell. If the number \nis valid, it is placed in the cell. If the number is invalid,\nthe algorithm backtracks to the previous cell and tries \nanother number. The algorithm terminates when all cells \nare filled. The algorithm is implemented in the solveSudoku\nfunction. The isValid function checks kama a number is\nvalid in a given cell. The printSudoku function prints\nthe sudoku puzzle. The solveSudoku function solves the\nsudoku puzzle. The main function initializes the sudoku\npuzzle and calls the solveSudoku function.\n\n#################################################*/\n\n\nfanya printing = unda(sudoku) {\n    fanya row = 0\n    wakati (row < 9){\n        andika(sudoku[row])\n        row++\n    }\n}\n\nfanya sudoku = [[3, 0, 6, 5, 0, 8, 4, 0, 0],[5, 2, 0, 0, 0, 0, 0, 0, 0],[0, 8, 7, 0, 0, 0, 0, 3, 1],[0, 0, 3, 0, 1, 0, 0, 8, 0],[9, 0, 0, 8, 6, 3, 0, 0, 5],[0, 5, 0, 0, 9, 0, 6, 0, 0],[1, 3, 0, 0, 0, 0, 2, 5, 0],[0, 0, 0, 0, 0, 0, 0, 7, 4],[0, 0, 5, 2, 0, 6, 3, 0, 0]]\n\n\n\nfanya isSafe = unda(grid, row, col, num) {\n    kwa x ktk [0,1,2,3,4,5,6,7,8] {\n        kama (grid[row][x] == num) {\n            rudisha sikweli\n        }\n    }\n\n    kwa x ktk [0,1,2,3,4,5,6,7,8] {\n        kama (grid[x][col] == num) {\n            rudisha sikweli\n        }\n    }\n\n    fanya startRow = row - row % 3\n    fanya startCol = col - col % 3\n\n    kwa i ktk [0, 1, 2] {\n        kwa j ktk [0, 1, 2] {\n            kama (grid[i + startRow][j + startCol] == num) {\n                rudisha sikweli\n            }\n        }\n    }\n\n    rudisha kweli\n}\n\nfanya solveSudoku = unda(grid, row, col) {\n    kama (row == 8 && col == 9) {\n        rudisha kweli\n    }\n\n    kama (col == 9) {\n        row += 1\n        col = 0\n    }\n\n    kama (grid[row][col] > 0) {\n        rudisha solveSudoku(grid, row, col + 1)\n    }\n\n    kwa num ktk [1,2,3,4,5,6,7,8,9] {\n        kama (isSafe(grid, row, col, num)) {\n            grid[row][col] = num\n            kama (solveSudoku(grid, row, col + 1)) {\n                rudisha kweli\n            }\n        }\n\n        grid[row][col] = 0\n    }\n\n    rudisha sikweli\n}\nandika()\nandika(\"----- PUZZLE TO SOLVE -----\")\nprinting(sudoku)\nkama (solveSudoku(sudoku, 0, 0)){\n    andika()\n    andika(\"--------- SOLUTION --------\")\n    printing(sudoku)\n    andika()\n} sivyo {\n    andika(\"imeshindikana\")\n}"
  },
  {
    "path": "extensions/README.md",
    "content": "# Nuru Extensions For Various Editors\n\n## [VSCODE](./vscode/)\n\nNuru syntax highlighting on VSCode\n\n## [VIM](./vim)\n\nThe file contained herein has a basic syntax highlight for vim.\nThe file should be saved in `$HOME/.vim/syntax/nuru.vim`.\nYou should add the following line to your `.vimrc` or the appropriate location:\n\n```vim\nau BufRead,BufNewFile *.nr set filetype=nuru\n```\n\nOnly basic syntax highlighting is provided by the script.\n"
  },
  {
    "path": "extensions/vim/syntax/nuru.vim",
    "content": "\" Sintaksia ya nuru kwenye programu ya \"vim\"\n\" Lugha: Nuru\n\n\" Maneno tengwa\nsyntax keyword nuruKeyword unda pakeji rudisha vunja endelea tupu\nsyntax keyword nuruType fanya\nsyntax keyword nuruBool kweli sikweli\nsyntax keyword nuruConditional kama sivyo au\nsyntax match nuruComparision /[!\\|<>]/\nsyntax keyword nuruLoop ktk while badili\nsyntax keyword nuruLabel ikiwa kawaida\n\n\" Nambari\nsyntax match nuruInt '[+-]\\d\\+' contained display\nsyntax match nuruFloat '[+-]\\d+\\.\\d*' contained display\n\n\" Viendeshaji\nsyntax match nuruAssignment '='\nsyntax match nuruLogicalOP /[\\&!|]/\n\n\" Vitendakazi \nsyntax keyword nuruFunction andika aina jaza fungua\n\n\" Tungo\nsyntax region nuruString start=/\"/ skip=/\\\\\"/ end=/\"/\nsyntax region nuruString start=/'/ skip=/\\\\'/ end=/'/\n\n\" Maoni\nsyntax match nuruComment \"//.*\"\nsyntax region nuruComment start=\"/\\*\" end=\"\\*/\"\n\n\" Fafanua sintaksia\nlet b:current_syntax = \"nuru\"\n\nhighlight def link nuruComment Comment\nhighlight def link nuruBool Boolean\nhighlight def link nuruFunction Function\nhighlight def link nuruComparision Conditional\nhighlight def link nuruConditional Conditional\nhighlight def link nuruKeyword Keyword\nhighlight def link nuruString String\nhighlight def link nuruVariable Identifier\nhighlight def link nuruLoop Repeat\nhighlight def link nuruInt Number\nhighlight def link nuruFloat Float\nhighlight def link nuruAssignment Operator\nhighlight def link nuruLogicalOP Operator\nhighlight def link nuruAriOP Operator\nhighlight def link nuruType Type\nhighlight def link nuruLabel Label\n\n"
  },
  {
    "path": "extensions/vscode/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to the \"nuru\" extension will be documented in this file.\n\nCheck [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.\n\n## [Unreleased]\n\n- Initial release"
  },
  {
    "path": "extensions/vscode/README.md",
    "content": "# Nuru VSCode Extension\n\nThis is a syntax highliting extension for Nuru on vscode. It detects `.nr` and `.sw` files.\n\n## Screenshots\n<p align=\"center\">\n<img alt=\"Nuru Programming Language\" src=\"assets/screenshot.png\">\n</p>\n\n## How To Install\n\n### Download From Market Place\n\n- Simply download the Nuru Extension from VSCode Market Place\n\n### Windows\n\n- Copy the whole [nuru folder](https://github.com/NuruProgramming/Nuru/tree/main/extensions/vscode/nuru) and paste it in the VSCode extensions directory found in `%USERPROFILE%\\.vscode\\extensions`\n- Restart VSCode\n\n### Linux and MacOS\n\n- Copy the whole [nuru folder](https://github.com/NuruProgramming/Nuru/tree/main/extensions/vscode/nuru) and paste it in the VSCode extensions directory found in `~/.vscode/extensions`\n- Restart VSCode\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/NuruProgramming/Nuru\n\ngo 1.18\n\nrequire (\n\tgithub.com/AvicennaJr/GoPrompt v0.0.0-20230411215003-be2316d88e2d\n\tgithub.com/charmbracelet/bubbles v0.15.0\n\tgithub.com/charmbracelet/bubbletea v0.23.2\n\tgithub.com/charmbracelet/glamour v0.6.0\n\tgithub.com/charmbracelet/lipgloss v0.7.1\n\tgithub.com/lrstanley/bubblezone v0.0.0-20230303230241-08f906ff62a9\n)\n\nrequire (\n\tgithub.com/alecthomas/chroma v0.10.0 // indirect\n\tgithub.com/atotto/clipboard v0.1.4 // indirect\n\tgithub.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect\n\tgithub.com/aymerick/douceur v0.2.0 // indirect\n\tgithub.com/containerd/console v1.0.3 // indirect\n\tgithub.com/dlclark/regexp2 v1.4.0 // indirect\n\tgithub.com/gorilla/css v1.0.0 // indirect\n\tgithub.com/lucasb-eyer/go-colorful v1.2.0 // indirect\n\tgithub.com/mattn/go-colorable v0.1.7 // indirect\n\tgithub.com/mattn/go-isatty v0.0.18 // indirect\n\tgithub.com/mattn/go-localereader v0.0.1 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.14 // indirect\n\tgithub.com/mattn/go-tty v0.0.3 // indirect\n\tgithub.com/microcosm-cc/bluemonday v1.0.21 // indirect\n\tgithub.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect\n\tgithub.com/muesli/cancelreader v0.2.2 // indirect\n\tgithub.com/muesli/reflow v0.3.0 // indirect\n\tgithub.com/muesli/termenv v0.15.1 // indirect\n\tgithub.com/olekukonko/tablewriter v0.0.5 // indirect\n\tgithub.com/pkg/term v1.2.0-beta.2 // indirect\n\tgithub.com/rivo/uniseg v0.4.4 // indirect\n\tgithub.com/sahilm/fuzzy v0.1.0 // indirect\n\tgithub.com/yuin/goldmark v1.5.2 // indirect\n\tgithub.com/yuin/goldmark-emoji v1.0.1 // indirect\n\tgolang.org/x/net v0.0.0-20221002022538-bcab6841153b // indirect\n\tgolang.org/x/sync v0.1.0 // indirect\n\tgolang.org/x/sys v0.7.0 // indirect\n\tgolang.org/x/term v0.7.0 // indirect\n\tgolang.org/x/text v0.9.0 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/AvicennaJr/GoPrompt v0.0.0-20230411215003-be2316d88e2d h1:H+Y1MQQXd83x0xC2MPOw+gFFozKTXgcW69bV80+/wpY=\ngithub.com/AvicennaJr/GoPrompt v0.0.0-20230411215003-be2316d88e2d/go.mod h1:oo6I+tik505nlWIPCU2ogWMkOxoTt7A1YwQYlmlHqE8=\ngithub.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=\ngithub.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=\ngithub.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=\ngithub.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=\ngithub.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=\ngithub.com/aymanbagabas/go-osc52 v1.2.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=\ngithub.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=\ngithub.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=\ngithub.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=\ngithub.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=\ngithub.com/charmbracelet/bubbles v0.15.0 h1:c5vZ3woHV5W2b8YZI1q7v4ZNQaPetfHuoHzx+56Z6TI=\ngithub.com/charmbracelet/bubbles v0.15.0/go.mod h1:Y7gSFbBzlMpUDR/XM9MhZI374Q+1p1kluf1uLl8iK74=\ngithub.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU=\ngithub.com/charmbracelet/bubbletea v0.23.2 h1:vuUJ9HJ7b/COy4I30e8xDVQ+VRDUEFykIjryPfgsdps=\ngithub.com/charmbracelet/bubbletea v0.23.2/go.mod h1:FaP3WUivcTM0xOKNmhciz60M6I+weYLF76mr1JyI7sM=\ngithub.com/charmbracelet/glamour v0.6.0 h1:wi8fse3Y7nfcabbbDuwolqTqMQPMnVPeZhDM273bISc=\ngithub.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8om2538k9ITBxOc=\ngithub.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=\ngithub.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=\ngithub.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=\ngithub.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c=\ngithub.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=\ngithub.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=\ngithub.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=\ngithub.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=\ngithub.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=\ngithub.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/lrstanley/bubblezone v0.0.0-20230303230241-08f906ff62a9 h1:w7W7F0EBRNTRRy+MFNLGrhJLn2Ldzl8Ms2AtHtgFtuw=\ngithub.com/lrstanley/bubblezone v0.0.0-20230303230241-08f906ff62a9/go.mod h1:v5lEwWaguF1o2MW/ucO0ZIA/IZymdBYJJ+2cMRLE7LU=\ngithub.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=\ngithub.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=\ngithub.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=\ngithub.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=\ngithub.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=\ngithub.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=\ngithub.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=\ngithub.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=\ngithub.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=\ngithub.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=\ngithub.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=\ngithub.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI=\ngithub.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=\ngithub.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg=\ngithub.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=\ngithub.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=\ngithub.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=\ngithub.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=\ngithub.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=\ngithub.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=\ngithub.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=\ngithub.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=\ngithub.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=\ngithub.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=\ngithub.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=\ngithub.com/muesli/termenv v0.14.0/go.mod h1:kG/pF1E7fh949Xhe156crRUrHNyK221IuGO7Ez60Uc8=\ngithub.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs=\ngithub.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ=\ngithub.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=\ngithub.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=\ngithub.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw=\ngithub.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=\ngithub.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=\ngithub.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=\ngithub.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.5.2 h1:ALmeCk/px5FSm1MAcFBAsVKZjDuMVj8Tm7FFIlMJnqU=\ngithub.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngithub.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os=\ngithub.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ=\ngolang.org/x/net v0.0.0-20221002022538-bcab6841153b h1:6e93nYa3hNqAvLr0pD4PN1fFS+gKzp2zAXqrnTCstqU=\ngolang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=\ngolang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=\ngolang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=\ngolang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=\ngolang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "lexer/lexer.go",
    "content": "// This will convert the sequence of characters into a sequence of tokens\n\npackage lexer\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\ntype Lexer struct {\n\tinput        []rune\n\tposition     int\n\treadPosition int\n\tch           rune\n\tline         int\n}\n\nfunc New(input string) *Lexer {\n\tl := &Lexer{input: []rune(input), line: 1}\n\tl.readChar()\n\treturn l\n}\n\nfunc (l *Lexer) readChar() {\n\tif l.readPosition >= len(l.input) {\n\t\tl.ch = 0\n\t} else {\n\t\tl.ch = l.input[l.readPosition]\n\t}\n\n\tl.position = l.readPosition\n\tl.readPosition += 1\n}\n\nfunc (l *Lexer) NextToken() token.Token {\n\tvar tok token.Token\n\tl.skipWhitespace()\n\tif l.ch == rune('/') && l.peekChar() == rune('/') {\n\t\tl.skipSingleLineComment()\n\t\treturn l.NextToken()\n\t}\n\tif l.ch == rune('/') && l.peekChar() == rune('*') {\n\t\tl.skipMultiLineComment()\n\t\treturn l.NextToken()\n\t}\n\n\tswitch l.ch {\n\tcase rune('='):\n\t\tif l.peekChar() == rune('=') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.EQ, Literal: string(ch) + string(l.ch), Line: l.line}\n\t\t} else {\n\t\t\ttok = newToken(token.ASSIGN, l.line, l.ch)\n\t\t}\n\tcase rune(';'):\n\t\ttok = newToken(token.SEMICOLON, l.line, l.ch)\n\tcase rune('('):\n\t\ttok = newToken(token.LPAREN, l.line, l.ch)\n\tcase rune(')'):\n\t\ttok = newToken(token.RPAREN, l.line, l.ch)\n\tcase rune('{'):\n\t\ttok = newToken(token.LBRACE, l.line, l.ch)\n\tcase rune('}'):\n\t\ttok = newToken(token.RBRACE, l.line, l.ch)\n\tcase rune(','):\n\t\ttok = newToken(token.COMMA, l.line, l.ch)\n\tcase rune('+'):\n\t\tif l.peekChar() == rune('=') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.PLUS_ASSIGN, Line: l.line, Literal: string(ch) + string(l.ch)}\n\t\t} else if l.peekChar() == rune('+') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.PLUS_PLUS, Literal: string(ch) + string(l.ch), Line: l.line}\n\t\t} else {\n\t\t\ttok = newToken(token.PLUS, l.line, l.ch)\n\t\t}\n\tcase rune('-'):\n\t\tif l.peekChar() == rune('=') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.MINUS_ASSIGN, Line: l.line, Literal: string(ch) + string(l.ch)}\n\t\t} else if l.peekChar() == rune('-') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.MINUS_MINUS, Literal: string(ch) + string(l.ch), Line: l.line}\n\t\t} else {\n\t\t\ttok = newToken(token.MINUS, l.line, l.ch)\n\t\t}\n\tcase rune('!'):\n\t\tif l.peekChar() == rune('=') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.NOT_EQ, Literal: string(ch) + string(l.ch), Line: l.line}\n\t\t} else {\n\t\t\ttok = newToken(token.BANG, l.line, l.ch)\n\t\t}\n\tcase rune('/'):\n\t\tif l.peekChar() == rune('=') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.SLASH_ASSIGN, Line: l.line, Literal: string(ch) + string(l.ch)}\n\t\t} else {\n\t\t\ttok = newToken(token.SLASH, l.line, l.ch)\n\t\t}\n\tcase rune('*'):\n\t\tif l.peekChar() == rune('=') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.ASTERISK_ASSIGN, Line: l.line, Literal: string(ch) + string(l.ch)}\n\t\t} else if l.peekChar() == rune('*') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.POW, Literal: string(ch) + string(l.ch), Line: l.line}\n\t\t} else {\n\t\t\ttok = newToken(token.ASTERISK, l.line, l.ch)\n\t\t}\n\tcase rune('<'):\n\t\tif l.peekChar() == rune('=') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.LTE, Literal: string(ch) + string(l.ch), Line: l.line}\n\t\t} else {\n\t\t\ttok = newToken(token.LT, l.line, l.ch)\n\t\t}\n\tcase rune('>'):\n\t\tif l.peekChar() == rune('=') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.GTE, Literal: string(ch) + string(l.ch), Line: l.line}\n\t\t} else {\n\t\t\ttok = newToken(token.GT, l.line, l.ch)\n\t\t}\n\tcase rune('\"'):\n\t\ttok.Type = token.STRING\n\t\ttok.Literal = l.readString()\n\t\ttok.Line = l.line\n\tcase rune('\\''):\n\t\ttok = token.Token{Type: token.STRING, Literal: l.readSingleQuoteString(), Line: l.line}\n\tcase rune('['):\n\t\ttok = newToken(token.LBRACKET, l.line, l.ch)\n\tcase rune(']'):\n\t\ttok = newToken(token.RBRACKET, l.line, l.ch)\n\tcase rune(':'):\n\t\ttok = newToken(token.COLON, l.line, l.ch)\n\tcase rune('@'):\n\t\ttok = newToken(token.AT, l.line, l.ch)\n\tcase rune('.'):\n\t\ttok = newToken(token.DOT, l.line, l.ch)\n\tcase rune('&'):\n\t\tif l.peekChar() == rune('&') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.AND, Literal: string(ch) + string(l.ch), Line: l.line}\n\t\t}\n\tcase rune('|'):\n\t\tif l.peekChar() == rune('|') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.OR, Literal: string(ch) + string(l.ch), Line: l.line}\n\t\t}\n\tcase rune('%'):\n\t\tif l.peekChar() == rune('=') {\n\t\t\tch := l.ch\n\t\t\tl.readChar()\n\t\t\ttok = token.Token{Type: token.MODULUS_ASSIGN, Line: l.line, Literal: string(ch) + string(l.ch)}\n\t\t} else {\n\t\t\ttok = newToken(token.MODULUS, l.line, l.ch)\n\t\t}\n\tcase rune('#'):\n\t\tif l.peekChar() == rune('!') && l.line == 1 {\n\t\t\tl.skipSingleLineComment()\n\t\t\treturn l.NextToken()\n\t\t}\n\tcase 0:\n\t\ttok.Literal = \"\"\n\t\ttok.Type = token.EOF\n\t\ttok.Line = l.line\n\tdefault:\n\t\tif isLetter(l.ch) {\n\t\t\ttok.Literal = l.readIdentifier()\n\t\t\ttok.Type = token.LookupIdent(tok.Literal)\n\t\t\ttok.Line = l.line\n\t\t\treturn tok\n\t\t} else if isDigit(l.ch) && isLetter(l.peekChar()) {\n\t\t\ttok.Literal = l.readIdentifier()\n\t\t\ttok.Type = token.LookupIdent(tok.Literal)\n\t\t\ttok.Line = l.line\n\t\t\treturn tok\n\t\t} else if isDigit(l.ch) {\n\t\t\ttok = l.readDecimal()\n\t\t\treturn tok\n\t\t} else {\n\t\t\ttok = newToken(token.ILLEGAL, l.line, l.ch)\n\t\t}\n\t}\n\n\tl.readChar()\n\treturn tok\n}\n\nfunc newToken(tokenType token.TokenType, line int, ch rune) token.Token {\n\treturn token.Token{Type: tokenType, Literal: string(ch), Line: line}\n}\n\nfunc (l *Lexer) readIdentifier() string {\n\tposition := l.position\n\n\tfor isLetter(l.ch) || isDigit(l.ch) {\n\t\tl.readChar()\n\t}\n\treturn string(l.input[position:l.position])\n}\n\nfunc isLetter(ch rune) bool {\n\treturn 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch == '@'\n}\n\nfunc (l *Lexer) skipWhitespace() {\n\tfor l.ch == ' ' || l.ch == '\\t' || l.ch == '\\n' || l.ch == '\\r' {\n\t\tif l.ch == '\\n' {\n\t\t\tl.line++\n\t\t}\n\t\tl.readChar()\n\t}\n}\n\nfunc isDigit(ch rune) bool {\n\treturn '0' <= ch && ch <= '9'\n}\n\nfunc (l *Lexer) readNumber() string {\n\tposition := l.position\n\tfor isDigit(l.ch) {\n\t\tl.readChar()\n\t}\n\treturn string(l.input[position:l.position])\n}\n\nfunc (l *Lexer) readDecimal() token.Token {\n\tinteger := l.readNumber()\n\tif l.ch == '.' && isDigit(l.peekChar()) {\n\t\tl.readChar()\n\t\tfraction := l.readNumber()\n\t\treturn token.Token{Type: token.FLOAT, Literal: integer + \".\" + fraction, Line: l.line}\n\t}\n\treturn token.Token{Type: token.INT, Literal: integer, Line: l.line}\n}\n\nfunc (l *Lexer) peekChar() rune {\n\tif l.readPosition >= len(l.input) {\n\t\treturn rune(0)\n\t} else {\n\t\treturn l.input[l.readPosition]\n\t}\n}\n\n// func (l *Lexer) peekTwoChar() rune {\n// \tif l.readPosition+1 >= len(l.input) {\n// \t\treturn rune(0)\n// \t} else {\n// \t\treturn l.input[l.readPosition+1]\n// \t}\n// }\n\nfunc (l *Lexer) skipSingleLineComment() {\n\tfor l.ch != '\\n' && l.ch != 0 {\n\t\tl.readChar()\n\t}\n\tl.skipWhitespace()\n}\n\nfunc (l *Lexer) skipMultiLineComment() {\n\tendFound := false\n\n\tfor !endFound {\n\t\tif l.ch == 0 {\n\t\t\tendFound = true\n\t\t}\n\n\t\tif l.ch == '*' && l.peekChar() == '/' {\n\t\t\tendFound = true\n\t\t\tl.readChar()\n\t\t}\n\n\t\tl.readChar()\n\t\tl.skipWhitespace()\n\t}\n\n}\n\nfunc (l *Lexer) readString() string {\n\tvar str string\n\tfor {\n\t\tl.readChar()\n\t\tif l.ch == '\"' || l.ch == 0 {\n\t\t\tbreak\n\t\t} else if l.ch == '\\\\' {\n\t\t\tswitch l.peekChar() {\n\t\t\tcase 'n':\n\t\t\t\tl.readChar()\n\t\t\t\tl.ch = '\\n'\n\t\t\tcase 'r':\n\t\t\t\tl.readChar()\n\t\t\t\tl.ch = '\\r'\n\t\t\tcase 't':\n\t\t\t\tl.readChar()\n\t\t\t\tl.ch = '\\t'\n\t\t\tcase '\"':\n\t\t\t\tl.readChar()\n\t\t\t\tl.ch = '\"'\n\t\t\tcase '\\\\':\n\t\t\t\tl.readChar()\n\t\t\t\tl.ch = '\\\\'\n\t\t\t}\n\t\t}\n\t\tstr += string(l.ch)\n\t}\n\treturn str\n}\n\nfunc (l *Lexer) readSingleQuoteString() string {\n\tvar str string\n\tfor {\n\t\tl.readChar()\n\t\tif l.ch == '\\'' || l.ch == 0 {\n\t\t\tbreak\n\t\t} else if l.ch == '\\\\' {\n\t\t\tswitch l.peekChar() {\n\t\t\tcase 'n':\n\t\t\t\tl.readChar()\n\t\t\t\tl.ch = '\\n'\n\t\t\tcase 'r':\n\t\t\t\tl.readChar()\n\t\t\t\tl.ch = '\\r'\n\t\t\tcase 't':\n\t\t\t\tl.readChar()\n\t\t\t\tl.ch = '\\t'\n\t\t\tcase '\"':\n\t\t\t\tl.readChar()\n\t\t\t\tl.ch = '\"'\n\t\t\tcase '\\\\':\n\t\t\t\tl.readChar()\n\t\t\t\tl.ch = '\\\\'\n\t\t\t}\n\t\t}\n\t\tstr += string(l.ch)\n\t}\n\treturn str\n}\n"
  },
  {
    "path": "lexer/lexer_test.go",
    "content": "package lexer\n\nimport (\n\t\"testing\"\n\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc TestNextToken(t *testing.T) {\n\tinput := `\n\t// Testing kama lex luther iko sawa\n\tfanya tano = 5;\n\tfanya kumi = 10;\n\n\tfanya jumla = unda(x, y){\n\tx + y;\n\t};\n\n\tfanya jibu = jumla(tano, kumi);\n\n\t!-/5;\n\t5 < 10 > 5;\n\n\tkama (5 < 10) {\n\t\trudisha kweli;\n\t} sivyo {\n\t\trudisha sikweli;\n\t}\n\n\t10 == 10;\n\t10 != 9; // Hii ni comment\n\t// Comment nyingine\n\n\t/*\n\tmultiline comment\n\t*/\n\n\t/* multiline comment number twooooooooooo */\n\t5\n\t\"bangi\"\n\t\"ba ngi\"\n\t[1, 2];\n\t{\"mambo\": \"vipi\"}\n\t. // test dot\n\ttumia muda\n\t\n\tbadili (a) {\n\t\tikiwa 2 {\n\t\t\tandika(2)\n\t\t}\n\t\tkawaida {\n\t\t\tandika(0)\n\t\t}\n\t}\n\t\n\ttupu\n\t\n\tkwa i, v ktk j`\n\n\ttests := []struct {\n\t\texpectedType    token.TokenType\n\t\texpectedLiteral string\n\t}{\n\t\t{token.LET, \"fanya\"},\n\t\t{token.IDENT, \"tano\"},\n\t\t{token.ASSIGN, \"=\"},\n\t\t{token.INT, \"5\"},\n\t\t{token.SEMICOLON, \";\"},\n\t\t{token.LET, \"fanya\"},\n\t\t{token.IDENT, \"kumi\"},\n\t\t{token.ASSIGN, \"=\"},\n\t\t{token.INT, \"10\"},\n\t\t{token.SEMICOLON, \";\"},\n\t\t{token.LET, \"fanya\"},\n\t\t{token.IDENT, \"jumla\"},\n\t\t{token.ASSIGN, \"=\"},\n\t\t{token.FUNCTION, \"unda\"},\n\t\t{token.LPAREN, \"(\"},\n\t\t{token.IDENT, \"x\"},\n\t\t{token.COMMA, \",\"},\n\t\t{token.IDENT, \"y\"},\n\t\t{token.RPAREN, \")\"},\n\t\t{token.LBRACE, \"{\"},\n\t\t{token.IDENT, \"x\"},\n\t\t{token.PLUS, \"+\"},\n\t\t{token.IDENT, \"y\"},\n\t\t{token.SEMICOLON, \";\"},\n\t\t{token.RBRACE, \"}\"},\n\t\t{token.SEMICOLON, \";\"},\n\t\t{token.LET, \"fanya\"},\n\t\t{token.IDENT, \"jibu\"},\n\t\t{token.ASSIGN, \"=\"},\n\t\t{token.IDENT, \"jumla\"},\n\t\t{token.LPAREN, \"(\"},\n\t\t{token.IDENT, \"tano\"},\n\t\t{token.COMMA, \",\"},\n\t\t{token.IDENT, \"kumi\"},\n\t\t{token.RPAREN, \")\"},\n\t\t{token.SEMICOLON, \";\"},\n\t\t{token.BANG, \"!\"},\n\t\t{token.MINUS, \"-\"},\n\t\t{token.SLASH, \"/\"},\n\t\t{token.INT, \"5\"},\n\t\t{token.SEMICOLON, \";\"},\n\t\t{token.INT, \"5\"},\n\t\t{token.LT, \"<\"},\n\t\t{token.INT, \"10\"},\n\t\t{token.GT, \">\"},\n\t\t{token.INT, \"5\"},\n\t\t{token.SEMICOLON, \";\"},\n\t\t{token.IF, \"kama\"},\n\t\t{token.LPAREN, \"(\"},\n\t\t{token.INT, \"5\"},\n\t\t{token.LT, \"<\"},\n\t\t{token.INT, \"10\"},\n\t\t{token.RPAREN, \")\"},\n\t\t{token.LBRACE, \"{\"},\n\t\t{token.RETURN, \"rudisha\"},\n\t\t{token.TRUE, \"kweli\"},\n\t\t{token.SEMICOLON, \";\"},\n\t\t{token.RBRACE, \"}\"},\n\t\t{token.ELSE, \"sivyo\"},\n\t\t{token.LBRACE, \"{\"},\n\t\t{token.RETURN, \"rudisha\"},\n\t\t{token.FALSE, \"sikweli\"},\n\t\t{token.SEMICOLON, \";\"},\n\t\t{token.RBRACE, \"}\"},\n\t\t{token.INT, \"10\"},\n\t\t{token.EQ, \"==\"},\n\t\t{token.INT, \"10\"},\n\t\t{token.SEMICOLON, \";\"},\n\t\t{token.INT, \"10\"},\n\t\t{token.NOT_EQ, \"!=\"},\n\t\t{token.INT, \"9\"},\n\t\t{token.SEMICOLON, \";\"},\n\t\t{token.INT, \"5\"},\n\t\t{token.STRING, \"bangi\"},\n\t\t{token.STRING, \"ba ngi\"},\n\t\t{token.LBRACKET, \"[\"},\n\t\t{token.INT, \"1\"},\n\t\t{token.COMMA, \",\"},\n\t\t{token.INT, \"2\"},\n\t\t{token.RBRACKET, \"]\"},\n\t\t{token.SEMICOLON, \";\"},\n\t\t{token.LBRACE, \"{\"},\n\t\t{token.STRING, \"mambo\"},\n\t\t{token.COLON, \":\"},\n\t\t{token.STRING, \"vipi\"},\n\t\t{token.RBRACE, \"}\"},\n\t\t{token.DOT, \".\"},\n\t\t{token.IMPORT, \"tumia\"},\n\t\t{token.IDENT, \"muda\"},\n\t\t{token.SWITCH, \"badili\"},\n\t\t{token.LPAREN, \"(\"},\n\t\t{token.IDENT, \"a\"},\n\t\t{token.RPAREN, \")\"},\n\t\t{token.LBRACE, \"{\"},\n\t\t{token.CASE, \"ikiwa\"},\n\t\t{token.INT, \"2\"},\n\t\t{token.LBRACE, \"{\"},\n\t\t{token.IDENT, \"andika\"},\n\t\t{token.LPAREN, \"(\"},\n\t\t{token.INT, \"2\"},\n\t\t{token.RPAREN, \")\"},\n\t\t{token.RBRACE, \"}\"},\n\t\t{token.DEFAULT, \"kawaida\"},\n\t\t{token.LBRACE, \"{\"},\n\t\t{token.IDENT, \"andika\"},\n\t\t{token.LPAREN, \"(\"},\n\t\t{token.INT, \"0\"},\n\t\t{token.RPAREN, \")\"},\n\t\t{token.RBRACE, \"}\"},\n\t\t{token.RBRACE, \"}\"},\n\t\t{token.NULL, \"tupu\"},\n\t\t{token.FOR, \"kwa\"},\n\t\t{token.IDENT, \"i\"},\n\t\t{token.COMMA, \",\"},\n\t\t{token.IDENT, \"v\"},\n\t\t{token.IN, \"ktk\"},\n\t\t{token.IDENT, \"j\"},\n\t\t{token.EOF, \"\"},\n\t}\n\n\tl := New(input)\n\n\tfor i, tt := range tests {\n\t\ttok := l.NextToken()\n\n\t\tif tok.Type != tt.expectedType {\n\t\t\tt.Fatalf(\"tests[%d] - tokentype wrong. expected=%q, got=%q\",\n\t\t\t\ti, tt.expectedType, tok.Type)\n\t\t}\n\n\t\tif tok.Literal != tt.expectedLiteral {\n\t\t\tt.Fatalf(\"tests[%d] - literal wrong. expected=%q, got=%q\",\n\t\t\t\ti, tt.expectedLiteral, tok.Literal)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "main.go",
    "content": "//go:build !wasm || !js\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/repl\"\n\t\"github.com/NuruProgramming/Nuru/styles\"\n\t\"github.com/charmbracelet/lipgloss\"\n)\n\nvar (\n\tTitle = styles.TitleStyle.\n\t\tRender(`\n█░░ █░█ █▀▀ █░█ ▄▀█   █▄█ ▄▀█   █▄░█ █░█ █▀█ █░█\n█▄▄ █▄█ █▄█ █▀█ █▀█   ░█░ █▀█   █░▀█ █▄█ █▀▄ █▄█`)\n\tVersion = styles.VersionStyle.Render(\"v0.5.18\")\n\tAuthor  = styles.AuthorStyle.Render(\"by Nuru Org\")\n\tNewLogo = lipgloss.JoinVertical(lipgloss.Center, Title, lipgloss.JoinHorizontal(lipgloss.Center, Author, \" | \", Version))\n\tHelp    = styles.HelpStyle.Italic(false).Render(fmt.Sprintf(`💡 Namna ya kutumia Nuru:\n\t%s: Kuanza programu ya Nuru\n\t%s: Kuendesha faili la Nuru\n\t%s: Kusoma nyaraka za Nuru\n\t%s: Kufahamu toleo la Nuru\n`,\n\t\tstyles.HelpStyle.Bold(true).Render(\"nuru\"),\n\t\tstyles.HelpStyle.Bold(true).Render(\"nuru jinaLaFile.nr\"),\n\t\tstyles.HelpStyle.Bold(true).Render(\"nuru --nyaraka\"),\n\t\tstyles.HelpStyle.Bold(true).Render(\"nuru --toleo\")))\n)\n\nfunc main() {\n\n\targs := os.Args\n\tif len(args) < 2 {\n\n\t\thelp := styles.HelpStyle.Render(\"💡 Tumia exit() au toka() kuondoka\")\n\t\tfmt.Println(lipgloss.JoinVertical(lipgloss.Left, NewLogo, \"\\n\", help))\n\t\trepl.Start()\n\t\treturn\n\t}\n\n\tif len(args) == 2 {\n\t\tswitch args[1] {\n\t\tcase \"msaada\", \"-msaada\", \"--msaada\", \"help\", \"-help\", \"--help\", \"-h\":\n\t\t\tfmt.Println(Help)\n\t\tcase \"version\", \"-version\", \"--version\", \"-v\", \"v\", \"--toleo\", \"-toleo\":\n\t\t\tfmt.Println(NewLogo)\n\t\tcase \"-docs\", \"--docs\", \"-nyaraka\", \"--nyaraka\":\n\t\t\trepl.Docs()\n\t\tdefault:\n\t\t\tfile := args[1]\n\n\t\t\tif strings.HasSuffix(file, \"nr\") || strings.HasSuffix(file, \".sw\") {\n\t\t\t\tcontents, err := os.ReadFile(file)\n\t\t\t\tif err != nil {\n\t\t\t\t\tfmt.Println(styles.ErrorStyle.Render(\"Error: Nuru imeshindwa kusoma faili: \", args[1]))\n\t\t\t\t\tos.Exit(1)\n\t\t\t\t}\n\n\t\t\t\trepl.Read(string(contents))\n\t\t\t} else {\n\t\t\t\tfmt.Println(styles.ErrorStyle.Render(\"'\"+file+\"'\", \"sii faili sahihi. Tumia faili la '.nr' au '.sw'\"))\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfmt.Println(styles.ErrorStyle.Render(\"Error: Operesheni imeshindikana boss.\"))\n\t\tfmt.Println(Help)\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "main_wasm.go",
    "content": "//go:build wasm && js\n\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/evaluator\"\n\t\"github.com/NuruProgramming/Nuru/lexer\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n\t\"github.com/NuruProgramming/Nuru/parser\"\n\n\t\"syscall/js\"\n)\n\nfunc Read(contents string) {\n\tjsOutputReceiverFunction := js.Global().Get(\"nuruOutputReceiver\")\n\n\tenv := object.NewEnvironment()\n\n\tl := lexer.New(contents)\n\tp := parser.New(l)\n\n\tprogram := p.ParseProgram()\n\n\tif len(p.Errors()) != 0 {\n\t\tfmt.Println(\"Kuna makosa yafuatayo:\")\n\t\tjsOutputReceiverFunction.Invoke(\"Kuna makosa yafuatayo:\", true)\n\n\t\tfor _, msg := range p.Errors() {\n\t\t\t// fmt.Println(\"\\t\" + msg)\n\t\t\tjsOutputReceiverFunction.Invoke(\"\\t\" + msg, true)\n\t\t}\n\n\t}\n\tevaluated := evaluator.Eval(program, env)\n\tif evaluated != nil {\n\t\tif evaluated.Type() != object.NULL_OBJ {\n\t\t\tjsOutputReceiverFunction.Invoke(evaluated.Inspect(), true)\n\t\t}\n\t}\n\n}\n\nfunc runCode(this js.Value, args []js.Value) interface{} {\n\tcode := args[0].String()\n\tRead(code)\n\treturn nil\n}\n\nfunc main() {\n\tfmt.Println(\"Go WASM initialized\")\n\tjs.Global().Set(\"runCode\", js.FuncOf(runCode))\n\t<-make(chan bool)\n}\n"
  },
  {
    "path": "module/hisabati.go",
    "content": "package module\n\nimport (\n\t\"math\"\n\t\"math/rand\"\n\t\"time\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nvar MathFunctions = map[string]object.ModuleFunction{\n\t\"PI\":        pi,\n\t\"e\":         e,\n\t\"phi\":       phi,\n\t\"ln10\":      ln10,\n\t\"ln2\":       ln2,\n\t\"log10e\":    log10e,\n\t\"log2e\":     log2e,\n\t\"log2\":      log2,\n\t\"sqrt1_2\":   sqrt1_2,\n\t\"sqrt2\":     sqrt2,\n\t\"sqrt3\":     sqrt3,\n\t\"sqrt5\":     sqrt5,\n\t\"EPSILON\":   epsilon,\n\t\"abs\":       abs,\n\t\"sign\":      sign,\n\t\"ceil\":      ceil,\n\t\"floor\":     floor,\n\t\"sqrt\":      sqrt,\n\t\"cbrt\":      cbrt,\n\t\"root\":      root,\n\t\"hypot\":     hypot,\n\t\"random\":    random,\n\t\"factorial\": factorial,\n\t\"round\":     round,\n\t\"max\":       max,\n\t\"min\":       min,\n\t\"exp\":       exp,\n\t\"expm1\":     expm1,\n\t\"log\":       log,\n\t\"log10\":     log10,\n\t\"log1p\":     log1p,\n\t\"cos\":       cos,\n\t\"sin\":       sin,\n\t\"tan\":       tan,\n\t\"acos\":      acos,\n\t\"asin\":      asin,\n\t\"atan\":      atan,\n\t\"cosh\":      cosh,\n\t\"sinh\":      sinh,\n\t\"tanh\":      tanh,\n\t\"acosh\":     acosh,\n\t\"asinh\":     asinh,\n\t\"atanh\":     atanh,\n\t\"atan2\":     atan2,\n}\n\nvar Constants = map[string]object.Object{\n\t\"PI\":      &object.Float{Value: math.Pi},\n\t\"e\":       &object.Float{Value: math.E},\n\t\"phi\":     &object.Float{Value: (1 + math.Sqrt(5)) / 2},\n\t\"ln10\":    &object.Float{Value: math.Log10E},\n\t\"ln2\":     &object.Float{Value: math.Ln2},\n\t\"log10e\":  &object.Float{Value: math.Log10E},\n\t\"log2e\":   &object.Float{Value: math.Log2E},\n\t\"sqrt1_2\": &object.Float{Value: 1 / math.Sqrt2},\n\t\"sqrt2\":   &object.Float{Value: math.Sqrt2},\n\t\"sqrt3\":   &object.Float{Value: math.Sqrt(3)},\n\t\"sqrt5\":   &object.Float{Value: math.Sqrt(5)},\n\t\"EPSILON\": &object.Float{Value: 2.220446049250313e-16},\n}\n\nfunc pi(args []object.Object, defs map[string]object.Object) object.Object {\n\treturn &object.Float{Value: math.Pi}\n}\n\nfunc e(args []object.Object, defs map[string]object.Object) object.Object {\n\treturn &object.Float{Value: math.E}\n}\n\nfunc phi(args []object.Object, defs map[string]object.Object) object.Object {\n\treturn &object.Float{Value: (1 + math.Sqrt(5)) / 2}\n}\n\nfunc ln10(args []object.Object, defs map[string]object.Object) object.Object {\n\treturn &object.Float{Value: math.Log10E}\n}\n\nfunc ln2(args []object.Object, defs map[string]object.Object) object.Object {\n\treturn &object.Float{Value: math.Ln2}\n}\n\nfunc log10e(args []object.Object, defs map[string]object.Object) object.Object {\n\treturn &object.Float{Value: math.Log10E}\n}\n\nfunc log2e(args []object.Object, defs map[string]object.Object) object.Object {\n\treturn &object.Float{Value: math.Log2E}\n}\n\nfunc sqrt1_2(args []object.Object, defs map[string]object.Object) object.Object {\n\treturn &object.Float{Value: 1 / math.Sqrt2}\n}\n\nfunc sqrt2(args []object.Object, defs map[string]object.Object) object.Object {\n\treturn &object.Float{Value: math.Sqrt2}\n}\n\nfunc sqrt3(args []object.Object, defs map[string]object.Object) object.Object {\n\treturn &object.Float{Value: math.Sqrt(3)}\n}\n\nfunc sqrt5(args []object.Object, defs map[string]object.Object) object.Object {\n\treturn &object.Float{Value: math.Sqrt(5)}\n}\n\nfunc epsilon(args []object.Object, defs map[string]object.Object) object.Object {\n\treturn &object.Float{Value: 2.220446049250313e-16}\n}\n\nfunc abs(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n\tswitch arg := args[0].(type) {\n\tcase *object.Integer:\n\t\tif arg.Value < 0 {\n\t\t\treturn &object.Integer{Value: -arg.Value}\n\t\t}\n\t\treturn arg\n\tcase *object.Float:\n\t\tif arg.Value < 0 {\n\t\t\treturn &object.Float{Value: -arg.Value}\n\t\t}\n\t\treturn arg\n\tdefault:\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n}\n\nfunc sign(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tswitch arg := args[0].(type) {\n\tcase *object.Integer:\n\t\tif arg.Value == 0 {\n\t\t\treturn &object.Integer{Value: 0}\n\t\t} else if arg.Value > 0 {\n\t\t\treturn &object.Integer{Value: 1}\n\t\t} else {\n\t\t\treturn &object.Integer{Value: -1}\n\t\t}\n\tcase *object.Float:\n\t\tif arg.Value == 0 {\n\t\t\treturn &object.Integer{Value: 0}\n\t\t} else if arg.Value > 0 {\n\t\t\treturn &object.Integer{Value: 1}\n\t\t} else {\n\t\t\treturn &object.Integer{Value: -1}\n\t\t}\n\tdefault:\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n}\n\nfunc ceil(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n\tswitch arg := args[0].(type) {\n\tcase *object.Integer:\n\t\treturn &object.Integer{Value: arg.Value}\n\tcase *object.Float:\n\t\treturn &object.Integer{Value: int64(math.Ceil(arg.Value))}\n\tdefault:\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n}\n\nfunc floor(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n\tswitch arg := args[0].(type) {\n\tcase *object.Integer:\n\t\treturn &object.Integer{Value: arg.Value}\n\tcase *object.Float:\n\t\treturn &object.Integer{Value: int64(math.Floor(arg.Value))}\n\tdefault:\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n}\n\nfunc sqrt(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n\tswitch arg := args[0].(type) {\n\tcase *object.Integer:\n\t\treturn &object.Float{Value: math.Sqrt(float64(arg.Value))}\n\tcase *object.Float:\n\t\treturn &object.Float{Value: math.Sqrt(arg.Value)}\n\tdefault:\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n}\n\nfunc cbrt(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n\tswitch arg := args[0].(type) {\n\tcase *object.Integer:\n\t\treturn &object.Float{Value: math.Cbrt(float64(arg.Value))}\n\tcase *object.Float:\n\t\treturn &object.Float{Value: math.Cbrt(arg.Value)}\n\tdefault:\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n}\n\nfunc root(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 2 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja mbili tu\"}\n\t}\n\tif args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja ya kwanza lazima iwe namba\"}\n\t}\n\tif args[1].Type() != object.INTEGER_OBJ {\n\t\treturn &object.Error{Message: \"Hoja ya pili lazima iwe namba\"}\n\t}\n\tbase, ok := args[0].(*object.Float)\n\tif !ok {\n\t\tbase = &object.Float{Value: float64(args[0].(*object.Integer).Value)}\n\t}\n\texp := args[1].(*object.Integer).Value\n\n\tif exp == 0 {\n\t\treturn &object.Float{Value: 1.0}\n\t} else if exp < 0 {\n\t\treturn &object.Error{Message: \"Second Hoja lazima iwe a non-negative integer\"}\n\t}\n\n\tx := 1.0\n\tfor i := 0; i < 10; i++ {\n\t\tx = x - (math.Pow(x, float64(exp))-base.Value)/(float64(exp)*math.Pow(x, float64(exp-1)))\n\t}\n\n\treturn &object.Float{Value: x}\n}\n\nfunc hypot(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) < 2 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tvar sumOfSquares float64\n\tfor _, arg := range args {\n\t\tif arg.Type() != object.INTEGER_OBJ && arg.Type() != object.FLOAT_OBJ {\n\t\t\treturn &object.Error{Message: \"Hoja lazima ziwe namba\"}\n\t\t}\n\t\tswitch num := arg.(type) {\n\t\tcase *object.Integer:\n\t\t\tsumOfSquares += float64(num.Value) * float64(num.Value)\n\t\tcase *object.Float:\n\t\t\tsumOfSquares += num.Value * num.Value\n\t\t}\n\t}\n\treturn &object.Float{Value: math.Sqrt(sumOfSquares)}\n}\n\nfunc factorial(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.INTEGER_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n\tn := args[0].(*object.Integer).Value\n\tif n < 0 {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe a non-negative integer\"}\n\t}\n\tresult := int64(1)\n\tfor i := int64(2); i <= n; i++ {\n\t\tresult *= i\n\t}\n\treturn &object.Integer{Value: result}\n}\n\nfunc round(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Integer{Value: int64(num + 0.5)}\n}\n\nfunc max(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\n\targ, ok := args[0].(*object.Array)\n\tif !ok {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe an array\"}\n\t}\n\n\tif len(arg.Elements) == 0 {\n\t\treturn &object.Error{Message: \"Orodha haipaswi kuwa tupu\"}\n\t}\n\n\tvar maxNum float64\n\n\tfor _, element := range arg.Elements {\n\t\tif element.Type() != object.INTEGER_OBJ && element.Type() != object.FLOAT_OBJ {\n\t\t\treturn &object.Error{Message: \"Vipengee vya orodha lazima viwe namba\"}\n\t\t}\n\n\t\tswitch num := element.(type) {\n\t\tcase *object.Integer:\n\t\t\tif float64(num.Value) > maxNum {\n\t\t\t\tmaxNum = float64(num.Value)\n\t\t\t}\n\t\tcase *object.Float:\n\t\t\tif num.Value > maxNum {\n\t\t\t\tmaxNum = num.Value\n\t\t\t}\n\t\tdefault:\n\t\t\treturn &object.Error{Message: \"Vipengee vya orodha lazima viwe namba\"}\n\t\t}\n\t}\n\n\treturn &object.Float{Value: maxNum}\n}\n\nfunc min(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\n\targ, ok := args[0].(*object.Array)\n\tif !ok {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe an array\"}\n\t}\n\n\tif len(arg.Elements) == 0 {\n\t\treturn &object.Error{Message: \"Orodha haipaswi kuwa tupu\"}\n\t}\n\n\tminNum := math.MaxFloat64\n\n\tfor _, element := range arg.Elements {\n\t\tif element.Type() != object.INTEGER_OBJ && element.Type() != object.FLOAT_OBJ {\n\t\t\treturn &object.Error{Message: \"Vipengee vya orodha lazima viwe namba\"}\n\t\t}\n\n\t\tswitch num := element.(type) {\n\t\tcase *object.Integer:\n\t\t\tif float64(num.Value) < minNum {\n\t\t\t\tminNum = float64(num.Value)\n\t\t\t}\n\t\tcase *object.Float:\n\t\t\tif num.Value < minNum {\n\t\t\t\tminNum = num.Value\n\t\t\t}\n\t\tdefault:\n\t\t\treturn &object.Error{Message: \"Vipengee vya orodha lazima viwe namba\"}\n\t\t}\n\t}\n\n\treturn &object.Float{Value: minNum}\n}\n\nfunc exp(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Exp(num)}\n}\n\nfunc expm1(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Expm1(num)}\n}\n\nfunc log(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Log(num)}\n}\n\nfunc log10(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Log10(num)}\n}\n\nfunc log2(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe namba\"}\n\t}\n\n\targ := extractFloatValue(args[0])\n\n\tif arg <= 0 {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe kubwa kuliko 0\"}\n\t}\n\n\treturn &object.Float{Value: math.Log2(arg)}\n}\n\nfunc extractFloatValue(obj object.Object) float64 {\n\tswitch obj := obj.(type) {\n\tcase *object.Integer:\n\t\treturn float64(obj.Value)\n\tcase *object.Float:\n\t\treturn obj.Value\n\tdefault:\n\t\treturn 0\n\t}\n}\n\nfunc log1p(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Log1p(num)}\n}\n\nfunc cos(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Cos(num)}\n}\n\nfunc sin(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Sin(num)}\n}\n\nfunc tan(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Tan(num)}\n}\n\nfunc acos(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Acos(num)}\n}\n\nfunc asin(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Asin(num)}\n}\n\nfunc atan(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Atan(num)}\n}\n\nfunc cosh(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Cosh(num)}\n}\n\nfunc sinh(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Sinh(num)}\n}\n\nfunc tanh(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Tanh(num)}\n}\n\nfunc acosh(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Acosh(num)}\n}\n\nfunc asinh(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Asinh(num)}\n}\n\nfunc atan2(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 2 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja mbili tu.\"}\n\t}\n\tif args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima ziwe namba\"}\n\t}\n\tif args[1].Type() != object.INTEGER_OBJ && args[1].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima ziwe namba\"}\n\t}\n\n\ty := extractFloatValue(args[0])\n\tx := extractFloatValue(args[1])\n\n\treturn &object.Float{Value: math.Atan2(y, x)}\n}\n\nfunc atanh(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Undo hili linahitaji hoja moja tu\"}\n\t}\n\tif args[0].Type() != object.FLOAT_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe desimali\"}\n\t}\n\tnum := args[0].(*object.Float).Value\n\treturn &object.Float{Value: math.Atanh(num)}\n}\n\nfunc random(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili haliruhusu ufafanuzi.\"}\n\t}\n\n\tif len(args) != 0 {\n\t\treturn &object.Error{Message: \"Undo hili halipaswi kupokea hoja.\"}\n\t}\n\n\trand.Seed(time.Now().UnixNano())\n\tvalue := rand.Float64()\n\n\treturn &object.Float{Value: value}\n}\n"
  },
  {
    "path": "module/json.go",
    "content": "package module\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nvar JsonFunctions = map[string]object.ModuleFunction{}\n\nfunc init() {\n\tJsonFunctions[\"dikodi\"] = decode\n\tJsonFunctions[\"enkodi\"] = encode\n}\n\nfunc decode(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Hoja hii hairuhusiwi\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Tunahitaji hoja moja tu\"}\n\t}\n\n\tif args[0].Type() != object.STRING_OBJ {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe neno\"}\n\t}\n\n\tvar i interface{}\n\n\tinput := args[0].(*object.String).Value\n\terr := json.Unmarshal([]byte(input), &i)\n\tif err != nil {\n\t\treturn &object.Error{Message: \"Hii data sio jsoni\"}\n\t}\n\n\treturn convertWhateverToObject(i)\n}\n\nfunc convertWhateverToObject(i interface{}) object.Object {\n\tswitch v := i.(type) {\n\tcase map[string]interface{}:\n\t\tdict := &object.Dict{}\n\t\tdict.Pairs = make(map[object.HashKey]object.DictPair)\n\n\t\tfor k, v := range v {\n\t\t\tpair := object.DictPair{\n\t\t\t\tKey:   &object.String{Value: k},\n\t\t\t\tValue: convertWhateverToObject(v),\n\t\t\t}\n\t\t\tdict.Pairs[pair.Key.(object.Hashable).HashKey()] = pair\n\t\t}\n\n\t\treturn dict\n\tcase []interface{}:\n\t\tlist := &object.Array{}\n\t\tfor _, e := range v {\n\t\t\tlist.Elements = append(list.Elements, convertWhateverToObject(e))\n\t\t}\n\n\t\treturn list\n\tcase string:\n\t\treturn &object.String{Value: v}\n\tcase int64:\n\t\treturn &object.Integer{Value: v}\n\tcase float64:\n\t\treturn &object.Float{Value: v}\n\tcase bool:\n\t\tif v {\n\t\t\treturn &object.Boolean{Value: true}\n\t\t} else {\n\t\t\treturn &object.Boolean{Value: false}\n\t\t}\n\t}\n\treturn &object.Null{}\n}\n\nfunc encode(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Hoja hii hairuhusiwi\"}\n\t}\n\n\tinput := args[0]\n\ti := convertObjectToWhatever(input)\n\tdata, err := json.Marshal(i)\n\n\tif err != nil {\n\t\treturn &object.Error{Message: \"Siwezi kubadilisha data hii kuwa jsoni\"}\n\t}\n\n\treturn &object.String{Value: string(data)}\n}\n\nfunc convertObjectToWhatever(obj object.Object) interface{} {\n\tswitch v := obj.(type) {\n\tcase *object.Dict:\n\t\tm := make(map[string]interface{})\n\t\tfor _, pair := range v.Pairs {\n\t\t\tkey := pair.Key.(*object.String).Value\n\t\t\tm[key] = convertObjectToWhatever(pair.Value)\n\t\t}\n\t\treturn m\n\tcase *object.Array:\n\t\tlist := make([]interface{}, len(v.Elements))\n\t\tfor i, e := range v.Elements {\n\t\t\tlist[i] = convertObjectToWhatever(e)\n\t\t}\n\t\treturn list\n\tcase *object.String:\n\t\treturn v.Value\n\tcase *object.Integer:\n\t\treturn v.Value\n\tcase *object.Float:\n\t\treturn v.Value\n\tcase *object.Boolean:\n\t\treturn v.Value\n\tcase *object.Null:\n\t\treturn nil\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "module/module.go",
    "content": "package module\n\nimport \"github.com/NuruProgramming/Nuru/object\"\n\nvar Mapper = map[string]*object.Module{}\n\nfunc init() {\n\tMapper[\"os\"] = &object.Module{Name: \"os\", Functions: OsFunctions}\n\tMapper[\"muda\"] = &object.Module{Name: \"time\", Functions: TimeFunctions}\n\tMapper[\"mtandao\"] = &object.Module{Name: \"net\", Functions: NetFunctions}\n\tMapper[\"jsoni\"] = &object.Module{Name: \"json\", Functions: JsonFunctions}\n\tMapper[\"hisabati\"] = &object.Module{Name: \"hisabati\", Functions: MathFunctions}\n}\n"
  },
  {
    "path": "module/net.go",
    "content": "package module\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nvar NetFunctions = map[string]object.ModuleFunction{}\n\nfunc init() {\n\tNetFunctions[\"peruzi\"] = getRequest\n\tNetFunctions[\"tuma\"] = postRequest\n}\n\nfunc getRequest(args []object.Object, defs map[string]object.Object) object.Object {\n\n\tif len(defs) != 0 {\n\t\tvar url *object.String\n\t\tvar headers, params *object.Dict\n\t\tfor k, v := range defs {\n\t\t\tswitch k {\n\t\t\tcase \"yuareli\":\n\t\t\t\tstrUrl, ok := v.(*object.String)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn &object.Error{Message: \"Yuareli iwe neno\"}\n\t\t\t\t}\n\t\t\t\turl = strUrl\n\t\t\tcase \"vichwa\":\n\t\t\t\tdictHead, ok := v.(*object.Dict)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn &object.Error{Message: \"Vichwa lazima viwe kamusi\"}\n\t\t\t\t}\n\t\t\t\theaders = dictHead\n\t\t\tcase \"mwili\":\n\t\t\t\tdictHead, ok := v.(*object.Dict)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn &object.Error{Message: \"Mwili lazima iwe kamusi\"}\n\t\t\t\t}\n\t\t\t\tparams = dictHead\n\t\t\tdefault:\n\t\t\t\treturn &object.Error{Message: \"Hoja si sahihi. Tumia yuareli na vichwa.\"}\n\t\t\t}\n\t\t}\n\t\tif url.Value == \"\" {\n\t\t\treturn &object.Error{Message: \"Yuareli ni lazima\"}\n\t\t}\n\n\t\tvar responseBody *bytes.Buffer\n\t\tif params != nil {\n\t\t\tbooty := convertObjectToWhatever(params)\n\n\t\t\tjsonBody, err := json.Marshal(booty)\n\n\t\t\tif err != nil {\n\t\t\t\treturn &object.Error{Message: \"Huku format query yako vizuri.\"}\n\t\t\t}\n\n\t\t\tresponseBody = bytes.NewBuffer(jsonBody)\n\t\t}\n\n\t\tvar req *http.Request\n\t\tvar err error\n\t\tif responseBody != nil {\n\t\t\treq, err = http.NewRequest(\"GET\", url.Value, responseBody)\n\t\t} else {\n\t\t\treq, err = http.NewRequest(\"GET\", url.Value, nil)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn &object.Error{Message: \"Tumeshindwa kufanya request\"}\n\t\t}\n\n\t\tif headers != nil {\n\t\t\tfor _, val := range headers.Pairs {\n\t\t\t\treq.Header.Set(val.Key.Inspect(), val.Value.Inspect())\n\t\t\t}\n\t\t}\n\t\tclient := &http.Client{}\n\n\t\tresp, err := client.Do(req)\n\n\t\tif err != nil {\n\t\t\treturn &object.Error{Message: \"Tumeshindwa kutuma request.\"}\n\t\t}\n\t\tdefer resp.Body.Close()\n\t\trespBody, err := ioutil.ReadAll(resp.Body)\n\t\tif err != nil {\n\t\t\treturn &object.Error{Message: \"Tumeshindwa kusoma majibu.\"}\n\t\t}\n\n\t\treturn &object.String{Value: string(respBody)}\n\n\t}\n\n\tif len(args) == 1 {\n\t\turl, ok := args[0].(*object.String)\n\t\tif !ok {\n\t\t\treturn &object.Error{Message: \"Yuareli lazima iwe neno\"}\n\t\t}\n\t\treq, err := http.NewRequest(\"GET\", url.Value, nil)\n\t\tif err != nil {\n\t\t\treturn &object.Error{Message: \"Tumeshindwa kufanya request\"}\n\t\t}\n\n\t\tclient := &http.Client{}\n\n\t\tresp, err := client.Do(req)\n\n\t\tif err != nil {\n\t\t\treturn &object.Error{Message: \"Tumeshindwa kutuma request.\"}\n\t\t}\n\t\tdefer resp.Body.Close()\n\t\trespBody, err := ioutil.ReadAll(resp.Body)\n\t\tif err != nil {\n\t\t\treturn &object.Error{Message: \"Tumeshindwa kusoma majibu.\"}\n\t\t}\n\n\t\treturn &object.String{Value: string(respBody)}\n\t}\n\treturn &object.Error{Message: \"Hoja si sahihi. Tumia yuareli na vichwa.\"}\n}\n\nfunc postRequest(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\tvar url *object.String\n\t\tvar headers, params *object.Dict\n\t\tfor k, v := range defs {\n\t\t\tswitch k {\n\t\t\tcase \"yuareli\":\n\t\t\t\tstrUrl, ok := v.(*object.String)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn &object.Error{Message: \"Yuareli iwe neno\"}\n\t\t\t\t}\n\t\t\t\turl = strUrl\n\t\t\tcase \"vichwa\":\n\t\t\t\tdictHead, ok := v.(*object.Dict)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn &object.Error{Message: \"Vichwa lazima viwe kamusi\"}\n\t\t\t\t}\n\t\t\t\theaders = dictHead\n\t\t\tcase \"mwili\":\n\t\t\t\tdictHead, ok := v.(*object.Dict)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn &object.Error{Message: \"Mwili lazima iwe kamusi\"}\n\t\t\t\t}\n\t\t\t\tparams = dictHead\n\t\t\tdefault:\n\t\t\t\treturn &object.Error{Message: \"Hoja si sahihi. Tumia yuareli na vichwa.\"}\n\t\t\t}\n\t\t}\n\t\tif url.Value == \"\" {\n\t\t\treturn &object.Error{Message: \"Yuareli ni lazima\"}\n\t\t}\n\t\tvar responseBody *bytes.Buffer\n\t\tif params != nil {\n\t\t\tbooty := convertObjectToWhatever(params)\n\n\t\t\tjsonBody, err := json.Marshal(booty)\n\n\t\t\tif err != nil {\n\t\t\t\treturn &object.Error{Message: \"Huku format query yako vizuri.\"}\n\t\t\t}\n\n\t\t\tresponseBody = bytes.NewBuffer(jsonBody)\n\t\t}\n\t\tvar req *http.Request\n\t\tvar err error\n\t\tif responseBody != nil {\n\t\t\treq, err = http.NewRequest(\"POST\", url.Value, responseBody)\n\t\t} else {\n\t\t\treq, err = http.NewRequest(\"POST\", url.Value, nil)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn &object.Error{Message: \"Tumeshindwa kufanya request\"}\n\t\t}\n\t\tif headers != nil {\n\t\t\tfor _, val := range headers.Pairs {\n\t\t\t\treq.Header.Set(val.Key.Inspect(), val.Value.Inspect())\n\t\t\t}\n\t\t}\n\t\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\t\tclient := &http.Client{}\n\n\t\tresp, err := client.Do(req)\n\n\t\tif err != nil {\n\t\t\treturn &object.Error{Message: \"Tumeshindwa kutuma request.\"}\n\t\t}\n\t\tdefer resp.Body.Close()\n\t\trespBody, err := ioutil.ReadAll(resp.Body)\n\t\tif err != nil {\n\t\t\treturn &object.Error{Message: \"Tumeshindwa kusoma majibu.\"}\n\t\t}\n\t\treturn &object.String{Value: string(respBody)}\n\t}\n\treturn &object.Error{Message: \"Hoja si sahihi. Tumia yuareli na vichwa.\"}\n}\n"
  },
  {
    "path": "module/os.go",
    "content": "package module\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nvar OsFunctions = map[string]object.ModuleFunction{}\n\nfunc init() {\n\tOsFunctions[\"toka\"] = exit\n\tOsFunctions[\"kimbiza\"] = run\n}\n\nfunc exit(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(args) > 1 {\n\t\treturn &object.Error{Message: \"Hoja sii sahihi\"}\n\t}\n\n\tif len(args) == 1 {\n\t\tstatus, ok := args[0].(*object.Integer)\n\t\tif !ok {\n\t\t\treturn &object.Error{Message: \"Hoja sii namba\"}\n\t\t}\n\t\tos.Exit(int(status.Value))\n\t\treturn nil\n\t}\n\n\tos.Exit(0)\n\n\treturn nil\n}\n\nfunc run(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"Idadi ya hoja sii sahihi\"}\n\t}\n\n\tcmd, ok := args[0].(*object.String)\n\tif !ok {\n\t\treturn &object.Error{Message: \"Hoja lazima iwe neno\"}\n\t}\n\tcmdMain := cmd.Value\n\tcmdArgs := strings.Split(cmdMain, \" \")\n\tcmdArgs = cmdArgs[1:]\n\n\tout, err := exec.Command(cmdMain, cmdArgs...).Output()\n\tif err != nil {\n\t\treturn &object.Error{Message: \"Tumeshindwa kukimbiza komandi\"}\n\t}\n\n\treturn &object.String{Value: string(out)}\n}\n"
  },
  {
    "path": "module/time.go",
    "content": "package module\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nvar TimeFunctions = map[string]object.ModuleFunction{}\n\nfunc init() {\n\tTimeFunctions[\"hasahivi\"] = now\n\tTimeFunctions[\"lala\"] = sleep\n\tTimeFunctions[\"tangu\"] = since\n\tTimeFunctions[\"leo\"] = today\n\tTimeFunctions[\"baada_ya\"] = after\n\tTimeFunctions[\"tofauti\"] = diff\n\tTimeFunctions[\"ongeza\"] = addTime\n}\n\nfunc now(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(args) != 0 || len(defs) != 0 {\n\t\treturn &object.Error{Message: \"hatuhitaji hoja kwenye hasahivi\"}\n\t}\n\n\ttn := time.Now()\n\ttime_string := tn.Format(\"15:04:05 02-01-2006\")\n\n\treturn &object.Time{TimeValue: time_string}\n}\n\nfunc sleep(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Hoja hii hairuhusiwi\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"tunahitaji hoja moja tu\"}\n\t}\n\n\tobjvalue := args[0].Inspect()\n\tinttime, err := strconv.Atoi(objvalue)\n\n\tif err != nil {\n\t\treturn &object.Error{Message: \"namba tu zinaruhusiwa kwenye hoja\"}\n\t}\n\n\ttime.Sleep(time.Duration(inttime) * time.Second)\n\n\treturn nil\n}\n\nfunc since(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 {\n\t\treturn &object.Error{Message: \"Hoja hii hairuhusiwi\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"tunahitaji hoja moja tu\"}\n\t}\n\n\tvar (\n\t\tt   time.Time\n\t\terr error\n\t)\n\n\tswitch m := args[0].(type) {\n\tcase *object.Time:\n\t\tt, _ = time.Parse(\"15:04:05 02-01-2006\", m.TimeValue)\n\tcase *object.String:\n\t\tt, err = time.Parse(\"15:04:05 02-01-2006\", m.Value)\n\t\tif err != nil {\n\t\t\treturn &object.Error{Message: fmt.Sprintf(\"Hoja %s sii sahihi\", args[0].Inspect())}\n\t\t}\n\tdefault:\n\t\treturn &object.Error{Message: fmt.Sprintf(\"Hoja %s sii sahihi\", args[0].Inspect())}\n\t}\n\n\tcurrent_time := time.Now().Format(\"15:04:05 02-01-2006\")\n\tct, _ := time.Parse(\"15:04:05 02-01-2006\", current_time)\n\n\tdiff := ct.Sub(t)\n\tdurationInSeconds := diff.Seconds()\n\n\treturn &object.Integer{Value: int64(durationInSeconds)}\n}\n\nfunc today(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(args) != 0 || len(defs) != 0 {\n\t\treturn &object.Error{Message: \"hatuhitaji hoja kwenye leo\"}\n\t}\n\n\tdateStr := time.Now().Format(\"02-01-2006\")\n\treturn &object.String{Value: dateStr}\n}\n\nfunc after(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 || len(args) != 1 {\n\t\treturn &object.Error{Message: \"tunahitaji hoja moja tu kwenye baada_ya\"}\n\t}\n\n\tsecondsStr := args[0].Inspect()\n\tseconds, err := strconv.Atoi(secondsStr)\n\tif err != nil {\n\t\treturn &object.Error{Message: \"hoja lazima iwe namba\"}\n\t}\n\n\tfuture := time.Now().Add(time.Duration(seconds) * time.Second)\n\treturn &object.Time{TimeValue: future.Format(\"15:04:05 02-01-2006\")}\n}\n\nfunc diff(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(defs) != 0 || len(args) != 2 {\n\t\treturn &object.Error{Message: \"tunahitaji hoja mbili kwenye tofauti\"}\n\t}\n\n\tparseTime := func(o object.Object) (time.Time, error) {\n\t\tswitch v := o.(type) {\n\t\tcase *object.Time:\n\t\t\treturn time.Parse(\"15:04:05 02-01-2006\", v.TimeValue)\n\t\tcase *object.String:\n\t\t\treturn time.Parse(\"15:04:05 02-01-2006\", v.Value)\n\t\tdefault:\n\t\t\treturn time.Time{}, fmt.Errorf(\"aina batili\")\n\t\t}\n\t}\n\n\tt1, err1 := parseTime(args[0])\n\tt2, err2 := parseTime(args[1])\n\n\tif err1 != nil || err2 != nil {\n\t\treturn &object.Error{Message: \"tofauti inahitaji nyakati halali mbili\"}\n\t}\n\n\tdiff := t1.Sub(t2).Seconds()\n\treturn &object.Integer{Value: int64(diff)}\n}\n\n\nfunc addTime(args []object.Object, defs map[string]object.Object) object.Object {\n\tif len(args) != 1 {\n\t\treturn &object.Error{Message: \"ongeza inahitaji wakati mmoja wa kuanzia\"}\n\t}\n\n\tbaseTimeObj := args[0]\n\tbaseTime, err := func() (time.Time, error) {\n\t\tswitch t := baseTimeObj.(type) {\n\t\tcase *object.Time:\n\t\t\treturn time.Parse(\"15:04:05 02-01-2006\", t.TimeValue)\n\t\tcase *object.String:\n\t\t\treturn time.Parse(\"15:04:05 02-01-2006\", t.Value)\n\t\tdefault:\n\t\t\treturn time.Time{}, fmt.Errorf(\"aina ya wakati sio sahihi\")\n\t\t}\n\t}()\n\tif err != nil {\n\t\treturn &object.Error{Message: \"wakati uliotolewa sio sahihi\"}\n\t}\n\n\tsecs := getInt(defs[\"sekunde\"])\n\tmins := getInt(defs[\"dakika\"])\n\thours := getInt(defs[\"masaa\"])\n\tdays := getInt(defs[\"siku\"])\n\tweeks := getInt(defs[\"wiki\"])\n\tmonths := getInt(defs[\"miezi\"])\n\tyears := getInt(defs[\"miaka\"])\n\n\tresult := baseTime.\n\t\tAdd(time.Second * time.Duration(secs)).\n\t\tAdd(time.Minute * time.Duration(mins)).\n\t\tAdd(time.Hour * time.Duration(hours)).\n\t\tAddDate(years, months, days+(weeks*7))\n\n\treturn &object.Time{TimeValue: result.Format(\"15:04:05 02-01-2006\")}\n}\n\nfunc getInt(obj object.Object) int {\n\tif obj == nil {\n\t\treturn 0\n\t}\n\tswitch o := obj.(type) {\n\tcase *object.Integer:\n\t\treturn int(o.Value)\n\tcase *object.String:\n\t\tn, err := strconv.Atoi(o.Value)\n\t\tif err == nil {\n\t\t\treturn n\n\t\t}\n\t}\n\treturn 0\n}\n"
  },
  {
    "path": "object/array.go",
    "content": "package object\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n)\n\ntype Array struct {\n\tElements []Object\n\toffset   int\n}\n\nfunc (ao *Array) Type() ObjectType { return ARRAY_OBJ }\nfunc (ao *Array) Inspect() string {\n\tvar out bytes.Buffer\n\n\telements := []string{}\n\tif len(ao.Elements) != 0 {\n\t\tfor _, e := range ao.Elements {\n\t\t\tif e.Inspect() != \"\" {\n\t\t\t\telements = append(elements, e.Inspect())\n\t\t\t}\n\t\t}\n\t}\n\n\tout.WriteString(\"[\")\n\tout.WriteString(strings.Join(elements, \", \"))\n\tout.WriteString(\"]\")\n\n\treturn out.String()\n}\n\nfunc (ao *Array) Next() (Object, Object) {\n\tidx := ao.offset\n\tif len(ao.Elements) > idx {\n\t\tao.offset = idx + 1\n\t\treturn &Integer{Value: int64(idx)}, ao.Elements[idx]\n\t}\n\treturn nil, nil\n}\n\nfunc (ao *Array) Reset() {\n\tao.offset = 0\n}\n\nfunc (a *Array) Method(method string, args []Object) Object {\n\tswitch method {\n\tcase \"idadi\":\n\t\treturn a.len(args)\n\tcase \"sukuma\":\n\t\treturn a.push(args)\n\tcase \"yamwisho\":\n\t\treturn a.last()\n\tcase \"unga\":\n\t\treturn a.join(args)\n\tcase \"chuja\":\n\t\treturn a.filter(args)\n\tcase \"tafuta\":\n\t\treturn a.find(args)\n\tdefault:\n\t\treturn newError(\"Samahani, kiendesha hiki hakitumiki na tungo (Neno)\")\n\t}\n}\n\nfunc (a *Array) len(args []Object) Object {\n\tif len(args) != 0 {\n\t\treturn newError(\"Samahani, tunahitaji Hoja 0, wewe umeweka %d\", len(args))\n\t}\n\treturn &Integer{Value: int64(len(a.Elements))}\n}\n\nfunc (a *Array) last() Object {\n\tlength := len(a.Elements)\n\tif length > 0 {\n\t\treturn a.Elements[length-1]\n\t}\n\treturn &Null{}\n}\n\nfunc (a *Array) push(args []Object) Object {\n\ta.Elements = append(a.Elements, args...)\n\treturn a\n}\n\nfunc (a *Array) join(args []Object) Object {\n\tif len(args) > 1 {\n\t\treturn newError(\"Samahani, tunahitaji Hoja 1 au 0, wewe umeweka %d\", len(args))\n\t}\n\tif len(a.Elements) > 0 {\n\t\tglue := \"\"\n\t\tif len(args) == 1 {\n\t\t\tglue = args[0].(*String).Value\n\t\t}\n\t\tlength := len(a.Elements)\n\t\tnewElements := make([]string, length)\n\t\tfor k, v := range a.Elements {\n\t\t\tnewElements[k] = v.Inspect()\n\t\t}\n\t\treturn &String{Value: strings.Join(newElements, glue)}\n\t} else {\n\t\treturn &String{Value: \"\"}\n\t}\n}\n\nfunc (a *Array) filter(args []Object) Object {\n\tif len(args) != 1 {\n\t\treturn newError(\"Samahani, idadi ya hoja sii sahihi\")\n\t}\n\n\tdummy := []Object{}\n\tfilteredArr := Array{Elements: dummy}\n\tfor _, obj := range a.Elements {\n\t\tif obj.Inspect() == args[0].Inspect() && obj.Type() == args[0].Type() {\n\t\t\tfilteredArr.Elements = append(filteredArr.Elements, obj)\n\t\t}\n\t}\n\treturn &filteredArr\n}\n\nfunc (a *Array) find(args []Object) Object {\n\tif len(args) != 1 {\n\t\treturn newError(\"Samahani, idadi ya hoja sii sahihi\")\n\t}\n\n\tfor _, obj := range a.Elements {\n\t\tif obj.Inspect() == args[0].Inspect() && obj.Type() == args[0].Type() {\n\t\t\treturn obj\n\t\t}\n\t}\n\treturn &Null{}\n}\n"
  },
  {
    "path": "object/at.go",
    "content": "package object\n\nimport \"fmt\"\n\ntype At struct {\n\tInstance *Instance\n}\n\nfunc (a *At) Type() ObjectType { return AT }\nfunc (a *At) Inspect() string {\n\treturn fmt.Sprintf(\"@.%s\", a.Instance.Package.Name.Value)\n}\n"
  },
  {
    "path": "object/bool.go",
    "content": "package object\n\ntype Boolean struct {\n\tValue bool\n}\n\nfunc (b *Boolean) Inspect() string {\n\tif b.Value {\n\t\treturn \"kweli\"\n\t} else {\n\t\treturn \"sikweli\"\n\t}\n}\nfunc (b *Boolean) Type() ObjectType { return BOOLEAN_OBJ }\n\nfunc (b *Boolean) HashKey() HashKey {\n\tvar value uint64\n\n\tif b.Value {\n\t\tvalue = 1\n\t} else {\n\t\tvalue = 0\n\t}\n\n\treturn HashKey{Type: b.Type(), Value: value}\n}\n"
  },
  {
    "path": "object/break.go",
    "content": "package object\n\ntype Break struct{}\n\nfunc (b *Break) Type() ObjectType { return BREAK_OBJ }\nfunc (b *Break) Inspect() string  { return \"break\" }\n"
  },
  {
    "path": "object/builtin.go",
    "content": "package object\n\ntype BuiltinFunction func(args ...Object) Object\n\ntype Builtin struct {\n\tFn BuiltinFunction\n}\n\nfunc (b *Builtin) Inspect() string  { return \"builtin function\" }\nfunc (b *Builtin) Type() ObjectType { return BUILTIN_OBJ }\n"
  },
  {
    "path": "object/byte.go",
    "content": "package object\n\ntype Byte struct {\n\tValue  []byte\n\tString string\n}\n\nfunc (b *Byte) Inspect() string  { return \"b\" + b.String }\nfunc (b *Byte) Type() ObjectType { return BYTE_OBJ }\n"
  },
  {
    "path": "object/continue.go",
    "content": "package object\n\ntype Continue struct{}\n\nfunc (c *Continue) Type() ObjectType { return CONTINUE_OBJ }\nfunc (c *Continue) Inspect() string  { return \"continue\" }\n"
  },
  {
    "path": "object/dict.go",
    "content": "package object\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n)\n\ntype DictPair struct {\n\tKey   Object\n\tValue Object\n}\n\ntype Dict struct {\n\tPairs  map[HashKey]DictPair\n\toffset int\n}\n\nfunc (d *Dict) Type() ObjectType { return DICT_OBJ }\nfunc (d *Dict) Inspect() string {\n\tvar out bytes.Buffer\n\n\tpairs := []string{}\n\n\tfor _, pair := range d.Pairs {\n\t\tpairs = append(pairs, fmt.Sprintf(\"%s: %s\", pair.Key.Inspect(), pair.Value.Inspect()))\n\t}\n\n\tout.WriteString(\"{\")\n\tout.WriteString(strings.Join(pairs, \", \"))\n\tout.WriteString(\"}\")\n\n\treturn out.String()\n}\n\nfunc (d *Dict) Next() (Object, Object) {\n\tidx := 0\n\tdict := make(map[string]DictPair)\n\tvar keys []string\n\tfor _, v := range d.Pairs {\n\t\tdict[v.Key.Inspect()] = v\n\t\tkeys = append(keys, v.Key.Inspect())\n\t}\n\n\tsort.Strings(keys)\n\n\tfor _, k := range keys {\n\t\tif d.offset == idx {\n\t\t\td.offset += 1\n\t\t\treturn dict[k].Key, dict[k].Value\n\t\t}\n\t\tidx += 1\n\t}\n\treturn nil, nil\n}\n\nfunc (d *Dict) Reset() {\n\td.offset = 0\n}\n"
  },
  {
    "path": "object/environment.go",
    "content": "package object\n\nfunc NewEnclosedEnvironment(outer *Environment) *Environment {\n\tenv := NewEnvironment()\n\tenv.outer = outer\n\treturn env\n}\n\nfunc NewEnvironment() *Environment {\n\ts := make(map[string]Object)\n\treturn &Environment{store: s, outer: nil}\n}\n\ntype Environment struct {\n\tstore map[string]Object\n\touter *Environment\n}\n\nfunc (e *Environment) Get(name string) (Object, bool) {\n\tobj, ok := e.store[name]\n\n\tif !ok && e.outer != nil {\n\t\tobj, ok = e.outer.Get(name)\n\t}\n\treturn obj, ok\n}\n\nfunc (e *Environment) Set(name string, val Object) Object {\n\te.store[name] = val\n\treturn val\n}\n\nfunc (e *Environment) Del(name string) bool {\n\t_, ok := e.store[name]\n\tif ok {\n\t\tdelete(e.store, name)\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "object/error.go",
    "content": "//go:build !js || !wasm\npackage object\n\nimport \"fmt\"\n\ntype Error struct {\n\tMessage string\n}\n\nfunc (e *Error) Inspect() string {\n\tmsg := fmt.Sprintf(\"\\x1b[%dm%s\\x1b[0m\", 31, \"Kosa: \")\n\treturn msg + e.Message\n}\nfunc (e *Error) Type() ObjectType { return ERROR_OBJ }\n"
  },
  {
    "path": "object/error_wasm.go",
    "content": "//go:build wasm && js\npackage object\n\ntype Error struct {\n\tMessage string\n}\n\nfunc (e *Error) Inspect() string {\n\t// msg := fmt.Sprintf(\"\\x1b[%dm%s\\x1b[0m\", 31, \"Kosa: \") // removes ANSI codes\n\treturn \"Kosa: \" + e.Message\n}\nfunc (e *Error) Type() ObjectType { return ERROR_OBJ }\n"
  },
  {
    "path": "object/file.go",
    "content": "package object\n\nimport (\n\t\"os\"\n)\n\ntype File struct {\n\tFilename string\n\tContent  string\n}\n\nfunc (f *File) Type() ObjectType { return FILE_OBJ }\nfunc (f *File) Inspect() string  { return f.Filename }\nfunc (f *File) Method(method string, args []Object) Object {\n\tswitch method {\n\tcase \"soma\":\n\t\treturn f.read(args)\n\tcase \"andika\":\n\t\treturn f.write(args)\n\tcase \"ongeza\":\n\t\treturn f.append(args)\n\t}\n\treturn nil\n}\n\nfunc (f *File) read(args []Object) Object {\n\tif len(args) != 0 {\n\t\treturn newError(\"Samahani, tunahitaji Hoja 0, wewe umeweka %d\", len(args))\n\t}\n\treturn &String{Value: f.Content}\n}\n\nfunc (f *File) write(args []Object) Object {\n\tif len(args) != 1 {\n\t\treturn newError(\"Samahani, tunahitaji Hoja 1, wewe umeweka %d\", len(args))\n\t}\n\tcontent, ok := args[0].(*String)\n\tif !ok {\n\t\treturn newError(\"Samahani, hoja lazima iwe Tungo\")\n\t}\n\terr := os.WriteFile(f.Filename, []byte(content.Value), 0644)\n\tif err != nil {\n\t\treturn newError(\"Hitilafu katika kuandika faili: %s\", err.Error())\n\t}\n\tf.Content = content.Value\n\treturn &Boolean{Value: true}\n}\n\nfunc (f *File) append(args []Object) Object {\n\tif len(args) != 1 {\n\t\treturn newError(\"Samahani, tunahitaji Hoja 1, wewe umeweka %d\", len(args))\n\t}\n\tcontent, ok := args[0].(*String)\n\tif !ok {\n\t\treturn newError(\"Samahani, hoja lazima iwe Tungo\")\n\t}\n\tfile, err := os.OpenFile(f.Filename, os.O_APPEND|os.O_WRONLY, 0644)\n\tif err != nil {\n\t\treturn newError(\"Hitilafu katika kufungua faili: %s\", err.Error())\n\t}\n\tdefer file.Close()\n\t_, err = file.WriteString(content.Value)\n\tif err != nil {\n\t\treturn newError(\"Hitilafu katika kuongeza kwa faili: %s\", err.Error())\n\t}\n\tf.Content += content.Value\n\treturn &Boolean{Value: true}\n}\n"
  },
  {
    "path": "object/float.go",
    "content": "package object\n\nimport (\n\t\"hash/fnv\"\n\t\"strconv\"\n)\n\ntype Float struct {\n\tValue float64\n}\n\nfunc (f *Float) Inspect() string  { return strconv.FormatFloat(f.Value, 'f', -1, 64) }\nfunc (f *Float) Type() ObjectType { return FLOAT_OBJ }\n\nfunc (f *Float) HashKey() HashKey {\n\th := fnv.New64a()\n\th.Write([]byte(f.Inspect()))\n\treturn HashKey{Type: f.Type(), Value: h.Sum64()}\n}\n"
  },
  {
    "path": "object/function.go",
    "content": "package object\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\ntype Function struct {\n\tName       string\n\tParameters []*ast.Identifier\n\tDefaults   map[string]ast.Expression\n\tBody       *ast.BlockStatement\n\tEnv        *Environment\n}\n\nfunc (f *Function) Type() ObjectType { return FUNCTION_OBJ }\nfunc (f *Function) Inspect() string {\n\tvar out bytes.Buffer\n\n\tparams := []string{}\n\tfor _, p := range f.Parameters {\n\t\tparams = append(params, p.String())\n\t}\n\n\tout.WriteString(\"unda\")\n\tout.WriteString(\"(\")\n\tout.WriteString(strings.Join(params, \", \"))\n\tout.WriteString(\") {\\n\")\n\tout.WriteString(f.Body.String())\n\tout.WriteString(\"\\n}\")\n\n\treturn out.String()\n}\n"
  },
  {
    "path": "object/instance.go",
    "content": "package object\n\nimport \"fmt\"\n\ntype Instance struct {\n\tPackage *Package\n\tEnv     *Environment\n}\n\nfunc (i *Instance) Type() ObjectType { return INSTANCE }\nfunc (i *Instance) Inspect() string {\n\treturn fmt.Sprintf(\"Pakeji: %s\", i.Package.Name.Value)\n}\n"
  },
  {
    "path": "object/integer.go",
    "content": "package object\n\nimport \"fmt\"\n\ntype Integer struct {\n\tValue int64\n}\n\nfunc (i *Integer) Inspect() string  { return fmt.Sprintf(\"%d\", i.Value) }\nfunc (i *Integer) Type() ObjectType { return INTEGER_OBJ }\n\nfunc (i *Integer) HashKey() HashKey {\n\treturn HashKey{Type: i.Type(), Value: uint64(i.Value)}\n}\n"
  },
  {
    "path": "object/module.go",
    "content": "package object\n\ntype ModuleFunction func(args []Object, defs map[string]Object) Object\n\ntype Module struct {\n\tName      string\n\tFunctions map[string]ModuleFunction\n}\n\nfunc (m *Module) Type() ObjectType {\n\tswitch m.Name {\n\tcase \"time\":\n\t\treturn TIME_OBJ\n\tcase \"json\":\n\t\treturn JSON_OBJ\n\tdefault:\n\t\treturn MODULE_OBJ\n\t}\n}\nfunc (m *Module) Inspect() string { return \"Module: \" + m.Name }\n"
  },
  {
    "path": "object/null.go",
    "content": "package object\n\ntype Null struct{}\n\nfunc (n *Null) Inspect() string  { return \"null\" }\nfunc (n *Null) Type() ObjectType { return NULL_OBJ }\n"
  },
  {
    "path": "object/object.go",
    "content": "package object\n\nimport (\n\t\"fmt\"\n)\n\ntype ObjectType string\n\nconst (\n\tINTEGER_OBJ      = \"NAMBA\"\n\tFLOAT_OBJ        = \"DESIMALI\"\n\tBOOLEAN_OBJ      = \"BOOLEAN\"\n\tNULL_OBJ         = \"TUPU\"\n\tRETURN_VALUE_OBJ = \"RUDISHA\"\n\tERROR_OBJ        = \"KOSA\"\n\tFUNCTION_OBJ     = \"UNDO (FUNCTION)\"\n\tSTRING_OBJ       = \"NENO\"\n\tBUILTIN_OBJ      = \"YA_NDANI\"\n\tARRAY_OBJ        = \"ORODHA\"\n\tDICT_OBJ         = \"KAMUSI\"\n\tCONTINUE_OBJ     = \"ENDELEA\"\n\tBREAK_OBJ        = \"VUNJA\"\n\tFILE_OBJ         = \"FAILI\"\n\tTIME_OBJ         = \"MUDA\"\n\tJSON_OBJ         = \"JSONI\"\n\tMODULE_OBJ       = \"MODULE\"\n\tBYTE_OBJ         = \"BYTE\"\n\tPACKAGE_OBJ      = \"PAKEJI\"\n\tINSTANCE         = \"PAKEJI\"\n\tAT               = \"@\"\n)\n\ntype Object interface {\n\tType() ObjectType\n\tInspect() string\n}\n\ntype HashKey struct {\n\tType  ObjectType\n\tValue uint64\n}\n\ntype Hashable interface {\n\tHashKey() HashKey\n}\n\n// Iterable interface for dicts, strings and arrays\ntype Iterable interface {\n\tNext() (Object, Object)\n\tReset()\n}\n\nfunc newError(format string, a ...interface{}) *Error {\n\tformat = fmt.Sprintf(\"\\x1b[%dm%s\\x1b[0m\", 31, format)\n\treturn &Error{Message: fmt.Sprintf(format, a...)}\n}\n"
  },
  {
    "path": "object/object_test.go",
    "content": "package object\n\nimport \"testing\"\n\nfunc TestStringHashKey(t *testing.T) {\n\thello1 := &String{Value: \"Hello World\"}\n\thello2 := &String{Value: \"Hello World\"}\n\tdiff1 := &String{Value: \"My name is Avi\"}\n\tdiff2 := &String{Value: \"My name is Avi\"}\n\n\tif hello1.HashKey() != hello2.HashKey() {\n\t\tt.Errorf(\"string with the same content have different dict keys\")\n\t}\n\n\tif diff1.HashKey() != diff2.HashKey() {\n\t\tt.Errorf(\"String with the same content have different dict keys\")\n\t}\n\n\tif hello1.HashKey() == diff1.HashKey() {\n\t\tt.Errorf(\"Strings with different content have the same dict keys\")\n\t}\n}\n"
  },
  {
    "path": "object/package.go",
    "content": "package object\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\ntype Package struct {\n\tName  *ast.Identifier\n\tEnv   *Environment\n\tScope *Environment\n}\n\nfunc (p *Package) Type() ObjectType { return PACKAGE_OBJ }\nfunc (p *Package) Inspect() string {\n\treturn fmt.Sprintf(\"Pakeji: %s\", p.Name.Value)\n}\n"
  },
  {
    "path": "object/return.go",
    "content": "package object\n\ntype ReturnValue struct {\n\tValue Object\n}\n\nfunc (rv *ReturnValue) Inspect() string  { return rv.Value.Inspect() }\nfunc (rv *ReturnValue) Type() ObjectType { return RETURN_VALUE_OBJ }\n"
  },
  {
    "path": "object/strings.go",
    "content": "package object\n\nimport (\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype String struct {\n\tValue  string\n\toffset int\n}\n\nfunc (s *String) Inspect() string  { return s.Value }\nfunc (s *String) Type() ObjectType { return STRING_OBJ }\nfunc (s *String) HashKey() HashKey {\n\th := fnv.New64a()\n\th.Write([]byte(s.Value))\n\n\treturn HashKey{Type: s.Type(), Value: h.Sum64()}\n}\nfunc (s *String) Next() (Object, Object) {\n\toffset := s.offset\n\tif len(s.Value) > offset {\n\t\ts.offset = offset + 1\n\t\treturn &Integer{Value: int64(offset)}, &String{Value: string(s.Value[offset])}\n\t}\n\treturn nil, nil\n}\nfunc (s *String) Reset() {\n\ts.offset = 0\n}\nfunc (s *String) Method(method string, args []Object) Object {\n\tswitch method {\n\tcase \"idadi\":\n\t\treturn s.len(args)\n\tcase \"herufikubwa\":\n\t\treturn s.upper(args)\n\tcase \"herufindogo\":\n\t\treturn s.lower(args)\n\tcase \"gawa\":\n\t\treturn s.split(args)\n\tcase \"panga\":\n\t\treturn s.format(args)\n\tdefault:\n\t\treturn newError(\"Samahani, kiendesha hiki hakitumiki na tungo (Neno)\")\n\t}\n}\n\nfunc (s *String) len(args []Object) Object {\n\tif len(args) != 0 {\n\t\treturn newError(\"Samahani, tunahitaji Hoja 0, wewe umeweka %d\", len(args))\n\t}\n\treturn &Integer{Value: int64(len(s.Value))}\n}\n\nfunc (s *String) upper(args []Object) Object {\n\tif len(args) != 0 {\n\t\treturn newError(\"Samahani, tunahitaji Hoja 0, wewe umeweka %d\", len(args))\n\t}\n\treturn &String{Value: strings.ToUpper(s.Value)}\n}\n\nfunc (s *String) lower(args []Object) Object {\n\tif len(args) != 0 {\n\t\treturn newError(\"Samahani, tunahitaji Hoja 0, wewe umeweka %d\", len(args))\n\t}\n\treturn &String{Value: strings.ToLower(s.Value)}\n}\n\nfunc (s *String) split(args []Object) Object {\n\tif len(args) > 1 {\n\t\treturn newError(\"Samahani, tunahitaji Hoja 1 au 0, wewe umeweka %d\", len(args))\n\t}\n\tsep := \" \"\n\tif len(args) == 1 {\n\t\tsep = args[0].(*String).Value\n\t}\n\tparts := strings.Split(s.Value, sep)\n\tlength := len(parts)\n\telements := make([]Object, length)\n\tfor k, v := range parts {\n\t\telements[k] = &String{Value: v}\n\t}\n\treturn &Array{Elements: elements}\n}\n\nfunc (s *String) format(args []Object) Object {\n\tvalue, err := formatStr(s.Value, args)\n\n\tif err != nil {\n\t\treturn newError(err.Error())\n\t}\n\n\treturn &String{Value: value}\n}\n\nfunc formatStr(format string, options []Object) (string, error) {\n\tvar str strings.Builder\n\tvar val strings.Builder\n\tvar check_val bool\n\tvar opts_len int = len(options)\n\n\tvar escapeChar bool\n\n\ttype optM struct {\n\t\tval bool\n\t\tobj Object\n\t}\n\n\tvar optionsMap = make(map[int]optM, opts_len)\n\n\tfor i, optm := range options {\n\t\toptionsMap[i] = optM{val: false, obj: optm}\n\t}\n\n\tfor _, opt := range format {\n\n\t\tif !escapeChar && opt == '\\\\' {\n\t\t\tescapeChar = true\n\t\t\tcontinue\n\t\t}\n\n\t\tif opt == '{' && !escapeChar {\n\t\t\tcheck_val = true\n\t\t\tcontinue\n\t\t}\n\n\t\tif escapeChar {\n\t\t\tif opt != '{' && opt != '}' {\n\t\t\t\tstr.WriteRune('\\\\')\n\t\t\t}\n\t\t\tescapeChar = false\n\t\t}\n\n\t\tif check_val && opt == '}' {\n\t\t\tvstr := strings.TrimSpace(val.String())\n\t\t\tarrv, err := strconv.Atoi(vstr)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(fmt.Sprintf(\"Ulichopeana si NAMBA, jaribu tena: `%s'\", vstr))\n\t\t\t}\n\n\t\t\toVal, exists := optionsMap[arrv]\n\n\t\t\tif !exists {\n\t\t\t\treturn \"\", fmt.Errorf(fmt.Sprintf(\"Nambari ya chaguo unalolitaka %d ni kubwa kuliko ulizopeana (%d)\", arrv, opts_len))\n\t\t\t}\n\n\t\t\tstr.WriteString(oVal.obj.Inspect())\n\t\t\toptionsMap[arrv] = optM{val: true, obj: oVal.obj}\n\n\t\t\tcheck_val = false\n\t\t\tval.Reset()\n\t\t\tcontinue\n\t\t}\n\n\t\tif check_val {\n\t\t\tval.WriteRune(opt)\n\t\t\tcontinue\n\t\t}\n\n\t\tstr.WriteRune(opt)\n\t}\n\n\tif check_val {\n\t\treturn \"\", fmt.Errorf(fmt.Sprintf(\"Haukufunga '{', tuliokota kabla ya kufika mwisho `%s'\", val.String()))\n\t}\n\n\tfor _, v := range optionsMap {\n\t\tif !v.val {\n\t\t\treturn \"\", fmt.Errorf(fmt.Sprintf(\"Ulipeana hili chaguo (%s) {%s} lakini haukutumia\", v.obj.Inspect(), v.obj.Type()))\n\t\t}\n\t}\n\n\treturn str.String(), nil\n}\n"
  },
  {
    "path": "object/time.go",
    "content": "package object\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n)\n\ntype Time struct {\n\tTimeValue string\n}\n\nfunc (t *Time) Type() ObjectType { return TIME_OBJ }\nfunc (t *Time) Inspect() string  { return t.TimeValue }\nfunc (t *Time) Method(method string, args []Object, defs map[string]Object) Object {\n\tswitch method {\n\tcase \"ongeza\":\n\t\treturn t.add(args, defs)\n\tcase \"tangu\":\n\t\treturn t.since(args, defs)\n\t}\n\treturn nil\n}\n\nfunc (t *Time) add(args []Object, defs map[string]Object) Object {\n\tif len(defs) != 0 {\n\t\tvar sec, min, hr, d, m, y int\n\t\tfor k, v := range defs {\n\t\t\tobjvalue := v.Inspect()\n\t\t\tinttime, err := strconv.Atoi(objvalue)\n\t\t\tif err != nil {\n\t\t\t\treturn newError(\"namba tu zinaruhusiwa kwenye hoja\")\n\t\t\t}\n\t\t\tswitch k {\n\t\t\tcase \"sekunde\":\n\t\t\t\tsec = inttime\n\t\t\tcase \"dakika\":\n\t\t\t\tmin = inttime\n\t\t\tcase \"saa\":\n\t\t\t\thr = inttime\n\t\t\tcase \"siku\":\n\t\t\t\td = inttime\n\t\t\tcase \"miezi\":\n\t\t\t\tm = inttime\n\t\t\tcase \"miaka\":\n\t\t\t\ty = inttime\n\t\t\tdefault:\n\t\t\t\treturn newError(\"Hukuweka muda sahihi\")\n\t\t\t}\n\t\t}\n\t\tcur_time, _ := time.Parse(\"15:04:05 02-01-2006\", t.Inspect())\n\t\tnext_time := cur_time.\n\t\t\tAdd(time.Duration(sec)*time.Second).\n\t\t\tAdd(time.Duration(min)*time.Minute).\n\t\t\tAdd(time.Duration(hr)*time.Hour).\n\t\t\tAddDate(y, m, d)\n\t\treturn &Time{TimeValue: string(next_time.Format(\"15:04:05 02-01-2006\"))}\n\t}\n\n\tif len(args) != 1 {\n\t\treturn newError(\"Samahani, tunahitaji Hoja 1, wewe umeweka %d\", len(args))\n\t}\n\n\tcur_time, _ := time.Parse(\"15:04:05 02-01-2006\", t.Inspect())\n\n\tobjvalue := args[0].Inspect()\n\tinttime, err := strconv.Atoi(objvalue)\n\n\tif err != nil {\n\t\treturn newError(\"namba tu zinaruhusiwa kwenye hoja\")\n\t}\n\n\tnext_time := cur_time.Add(time.Duration(inttime) * time.Hour)\n\treturn &Time{TimeValue: string(next_time.Format(\"15:04:05 02-01-2006\"))}\n}\n\nfunc (t *Time) since(args []Object, defs map[string]Object) Object {\n\tif len(defs) != 0 {\n\t\treturn &Error{Message: \"Hoja hii hairuhusiwi\"}\n\t}\n\tif len(args) != 1 {\n\t\treturn &Error{Message: \"tunahitaji hoja moja tu\"}\n\t}\n\n\tvar (\n\t\to   time.Time\n\t\terr error\n\t)\n\n\tswitch m := args[0].(type) {\n\tcase *Time:\n\t\to, _ = time.Parse(\"15:04:05 02-01-2006\", m.TimeValue)\n\tcase *String:\n\t\to, err = time.Parse(\"15:04:05 02-01-2006\", m.Value)\n\t\tif err != nil {\n\t\t\treturn &Error{Message: fmt.Sprintf(\"Hoja %s sii sahihi\", args[0].Inspect())}\n\t\t}\n\tdefault:\n\t\treturn &Error{Message: fmt.Sprintf(\"Hoja %s sii sahihi\", args[0].Inspect())}\n\t}\n\n\tct, _ := time.Parse(\"15:04:05 02-01-2006\", t.TimeValue)\n\n\tdiff := ct.Sub(o)\n\tdurationInSeconds := diff.Seconds()\n\n\treturn &Integer{Value: int64(durationInSeconds)}\n}\n"
  },
  {
    "path": "parser/arrays.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseArrayLiteral() ast.Expression {\n\tarray := &ast.ArrayLiteral{Token: p.curToken}\n\n\tarray.Elements = p.parseExpressionList(token.RBRACKET)\n\n\treturn array\n}\n\nfunc (p *Parser) parseExpressionList(end token.TokenType) []ast.Expression {\n\tlist := []ast.Expression{}\n\n\tif p.peekTokenIs(end) {\n\t\tp.nextToken()\n\t\treturn list\n\t}\n\n\tp.nextToken()\n\tlist = append(list, p.parseExpression(LOWEST))\n\n\tfor p.peekTokenIs(token.COMMA) {\n\t\tp.nextToken()\n\t\tp.nextToken()\n\t\tlist = append(list, p.parseExpression(LOWEST))\n\t}\n\n\tif !p.expectPeek(end) {\n\t\treturn nil\n\t}\n\treturn list\n}\n"
  },
  {
    "path": "parser/assignEqual.go",
    "content": "package parser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseAssignEqualExpression(exp ast.Expression) ast.Expression {\n\tswitch node := exp.(type) {\n\tcase *ast.Identifier:\n\t\te := &ast.AssignEqual{\n\t\t\tToken: p.curToken,\n\t\t\tLeft:  exp.(*ast.Identifier),\n\t\t}\n\t\tprecendence := p.curPrecedence()\n\t\tp.nextToken()\n\t\te.Value = p.parseExpression(precendence)\n\t\treturn e\n\tcase *ast.IndexExpression:\n\t\tae := &ast.AssignmentExpression{Token: p.curToken, Left: exp}\n\n\t\tp.nextToken()\n\n\t\tae.Value = p.parseExpression(LOWEST)\n\n\t\treturn ae\n\tdefault:\n\t\tif node != nil {\n\t\t\tmsg := fmt.Sprintf(\"Mstari %d:Tulitegemea kupata kitambulishi au array, badala yake tumepata: %s\", p.curToken.Line, node.TokenLiteral())\n\t\t\tp.errors = append(p.errors, msg)\n\t\t} else {\n\t\t\tmsg := fmt.Sprintf(\"Mstari %d: Umekosea mkuu\", p.curToken.Line)\n\t\t\tp.errors = append(p.errors, msg)\n\t\t}\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "parser/assignment.go",
    "content": "package parser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseAssignmentExpression(exp ast.Expression) ast.Expression {\n\tswitch node := exp.(type) {\n\tcase *ast.Identifier:\n\t\te := &ast.Assign{\n\t\t\tToken: p.curToken,\n\t\t\tName:  exp.(*ast.Identifier),\n\t\t}\n\t\tprecedence := p.curPrecedence()\n\t\tp.nextToken()\n\t\te.Value = p.parseExpression(precedence)\n\t\treturn e\n\n\tcase *ast.IndexExpression:\n\tcase *ast.PropertyExpression:\n\t\te := &ast.PropertyAssignment{\n\t\t\tToken: p.curToken,\n\t\t\tName:  exp.(*ast.PropertyExpression),\n\t\t}\n\t\tprecedence := p.curPrecedence()\n\t\tp.nextToken()\n\t\te.Value = p.parseExpression(precedence)\n\t\treturn e\n\tdefault:\n\t\tif node != nil {\n\t\t\tmsg := fmt.Sprintf(\"Mstari %d:Tulitegemea kupata kitambulishi au array, badala yake tumepata: %s\", p.curToken.Line, node.TokenLiteral())\n\t\t\tp.errors = append(p.errors, msg)\n\t\t} else {\n\t\t\tmsg := fmt.Sprintf(\"Mstari %d: Umekosea mkuu\", p.curToken.Line)\n\t\t\tp.errors = append(p.errors, msg)\n\t\t}\n\t\treturn nil\n\t}\n\n\tae := &ast.AssignmentExpression{Token: p.curToken, Left: exp}\n\n\tp.nextToken()\n\n\tae.Value = p.parseExpression(LOWEST)\n\n\treturn ae\n}\n"
  },
  {
    "path": "parser/at.go",
    "content": "package parser\n\nimport \"github.com/NuruProgramming/Nuru/ast\"\n\nfunc (p *Parser) parseAt() ast.Expression {\n\treturn &ast.At{Token: p.curToken}\n}\n"
  },
  {
    "path": "parser/boolean.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseBoolean() ast.Expression {\n\treturn &ast.Boolean{Token: p.curToken, Value: p.curTokenIs(token.TRUE)}\n}\n"
  },
  {
    "path": "parser/break.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseBreak() *ast.Break {\n\tstmt := &ast.Break{Token: p.curToken}\n\tfor p.curTokenIs(token.SEMICOLON) {\n\t\tp.nextToken()\n\t}\n\treturn stmt\n}\n"
  },
  {
    "path": "parser/continue.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseContinue() *ast.Continue {\n\tstmt := &ast.Continue{Token: p.curToken}\n\tfor p.curTokenIs(token.SEMICOLON) {\n\t\tp.nextToken()\n\t}\n\treturn stmt\n}\n"
  },
  {
    "path": "parser/dict.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseDictLiteral() ast.Expression {\n\tdict := &ast.DictLiteral{Token: p.curToken}\n\tdict.Pairs = make(map[ast.Expression]ast.Expression)\n\n\tfor !p.peekTokenIs(token.RBRACE) {\n\t\tp.nextToken()\n\t\tkey := p.parseExpression(LOWEST)\n\n\t\tif !p.expectPeek(token.COLON) {\n\t\t\treturn nil\n\t\t}\n\n\t\tp.nextToken()\n\t\tvalue := p.parseExpression(LOWEST)\n\n\t\tdict.Pairs[key] = value\n\n\t\tif !p.peekTokenIs(token.RBRACE) && !p.expectPeek(token.COMMA) {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tif !p.expectPeek(token.RBRACE) {\n\t\treturn nil\n\t}\n\n\treturn dict\n}\n"
  },
  {
    "path": "parser/dot.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseMethod(obj ast.Expression) ast.Expression {\n\ttok := p.curToken\n\tprecedence := p.curPrecedence()\n\tp.nextToken()\n\tif p.peekTokenIs(token.LPAREN) {\n\t\texp := &ast.MethodExpression{Token: tok, Object: obj}\n\t\texp.Method = p.parseExpression(precedence)\n\t\tif !p.expectPeek(token.LPAREN) {\n\t\t\treturn nil\n\t\t}\n\n\t\texp.Defaults = make(map[string]ast.Expression)\n\n\t\tfor !p.peekTokenIs(token.RPAREN) {\n\t\t\tp.nextToken()\n\t\t\tif p.curTokenIs(token.COMMA) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif p.peekTokenIs(token.ASSIGN) {\n\t\t\t\tname := p.curToken.Literal\n\t\t\t\tp.nextToken()\n\t\t\t\tp.nextToken()\n\t\t\t\tval := p.parseExpression(LOWEST)\n\t\t\t\texp.Defaults[name] = val\n\t\t\t} else {\n\t\t\t\texp.Arguments = append(exp.Arguments, p.parseExpression(LOWEST))\n\t\t\t}\n\t\t}\n\n\t\tif !p.expectPeek(token.RPAREN) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn exp\n\t} else {\n\t\texp := &ast.PropertyExpression{Token: tok, Object: obj}\n\t\texp.Property = p.parseIdentifier()\n\t\treturn exp\n\t}\n}\n"
  },
  {
    "path": "parser/float.go",
    "content": "package parser\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseFloatLiteral() ast.Expression {\n\tfl := &ast.FloatLiteral{Token: p.curToken}\n\tvalue, err := strconv.ParseFloat(p.curToken.Literal, 64)\n\tif err != nil {\n\t\tmsg := fmt.Sprintf(\"Mstari %d: Hatuwezi kuparse %q kama desimali\", p.curToken.Line, p.curToken.Literal)\n\t\tp.errors = append(p.errors, msg)\n\t\treturn nil\n\t}\n\tfl.Value = value\n\treturn fl\n}\n"
  },
  {
    "path": "parser/for.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseForExpression() ast.Expression {\n\texpression := &ast.For{Token: p.curToken}\n\tp.nextToken()\n\tif !p.curTokenIs(token.IDENT) {\n\t\treturn nil\n\t}\n\tif !p.peekTokenIs(token.ASSIGN) {\n\t\treturn p.parseForInExpression(expression)\n\t}\n\n\t// In future will allow: kwa i = 0; i<10; i++ {andika(i)}\n\t// expression.Identifier = p.curToken.Literal\n\t// expression.StarterName = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}\n\t// if expression.StarterName == nil {\n\t// \treturn nil\n\t// }\n\t// if !p.expectPeek(token.ASSIGN) {\n\t// \treturn nil\n\t// }\n\n\t// p.nextToken()\n\n\t// expression.StarterValue = p.parseExpression(LOWEST)\n\t// // expression.Starter = p.parseExpression(LOWEST)\n\t// if expression.StarterValue == nil {\n\t// \treturn nil\n\t// }\n\t// p.nextToken()\n\t// for p.curTokenIs(token.SEMICOLON) {\n\t// \tp.nextToken()\n\t// }\n\t// expression.Condition = p.parseExpression(LOWEST)\n\t// if expression.Condition == nil {\n\t// \treturn nil\n\t// }\n\t// p.nextToken()\n\t// for p.curTokenIs(token.SEMICOLON) {\n\t// \tp.nextToken()\n\t// }\n\t// expression.Closer = p.parseExpression(LOWEST)\n\t// if expression.Closer == nil {\n\t// \treturn nil\n\t// }\n\t// p.nextToken()\n\t// for p.curTokenIs(token.SEMICOLON) {\n\t// \tp.nextToken()\n\t// }\n\t// if !p.curTokenIs(token.LBRACE) {\n\t// \treturn nil\n\t// }\n\t// expression.Block = p.parseBlockStatement()\n\t// return expression\n\treturn nil\n}\n\nfunc (p *Parser) parseForInExpression(initialExpression *ast.For) ast.Expression {\n\texpression := &ast.ForIn{Token: initialExpression.Token}\n\tif !p.curTokenIs(token.IDENT) {\n\t\treturn nil\n\t}\n\tval := p.curToken.Literal\n\tvar key string\n\tp.nextToken()\n\tif p.curTokenIs(token.COMMA) {\n\t\tp.nextToken()\n\t\tif !p.curTokenIs(token.IDENT) {\n\t\t\treturn nil\n\t\t}\n\t\tkey = val\n\t\tval = p.curToken.Literal\n\t\tp.nextToken()\n\t}\n\texpression.Key = key\n\texpression.Value = val\n\tif !p.curTokenIs(token.IN) {\n\t\treturn nil\n\t}\n\tp.nextToken()\n\texpression.Iterable = p.parseExpression(LOWEST)\n\tif !p.expectPeek(token.LBRACE) {\n\t\treturn nil\n\t}\n\texpression.Block = p.parseBlockStatement()\n\treturn expression\n}\n"
  },
  {
    "path": "parser/function.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseFunctionLiteral() ast.Expression {\n\tlit := &ast.FunctionLiteral{Token: p.curToken}\n\n\tif p.peekTokenIs(token.IDENT) {\n\t\tp.nextToken()\n\t\tlit.Name = p.curToken.Literal\n\t}\n\n\tif !p.expectPeek(token.LPAREN) {\n\t\treturn nil\n\t}\n\n\tif !p.parseFunctionParameters(lit) {\n\t\treturn nil\n\t}\n\n\tif !p.expectPeek(token.LBRACE) {\n\t\treturn nil\n\t}\n\n\tlit.Body = p.parseBlockStatement()\n\n\treturn lit\n}\n\nfunc (p *Parser) parseFunctionParameters(lit *ast.FunctionLiteral) bool {\n\tlit.Defaults = make(map[string]ast.Expression)\n\tfor !p.peekTokenIs(token.RPAREN) {\n\t\tp.nextToken()\n\n\t\tif p.curTokenIs(token.COMMA) {\n\t\t\tcontinue\n\t\t}\n\n\t\tident := &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}\n\t\tlit.Parameters = append(lit.Parameters, ident)\n\n\t\tif p.peekTokenIs(token.ASSIGN) {\n\t\t\tp.nextToken()\n\t\t\tp.nextToken()\n\t\t\tlit.Defaults[ident.Value] = p.parseExpression(LOWEST)\n\t\t} else {\n\t\t\tif len(lit.Defaults) > 0 {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tif !(p.peekTokenIs(token.COMMA) || p.peekTokenIs(token.RPAREN)) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn p.expectPeek(token.RPAREN)\n}\n\nfunc (p *Parser) parseCallExpression(function ast.Expression) ast.Expression {\n\texp := &ast.CallExpression{Token: p.curToken, Function: function}\n\texp.Arguments = p.parseExpressionList(token.RPAREN)\n\treturn exp\n}\n"
  },
  {
    "path": "parser/identifier.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseIdentifier() ast.Expression {\n\treturn &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}\n}\n"
  },
  {
    "path": "parser/if.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseIfExpression() ast.Expression {\n\texpression := &ast.IfExpression{Token: p.curToken}\n\n\tif !p.expectPeek(token.LPAREN) {\n\t\treturn nil\n\t}\n\n\tp.nextToken()\n\texpression.Condition = p.parseExpression(LOWEST)\n\n\tif !p.expectPeek(token.RPAREN) {\n\t\treturn nil\n\t}\n\n\tif !p.expectPeek(token.LBRACE) {\n\t\treturn nil\n\t}\n\n\texpression.Consequence = p.parseBlockStatement()\n\n\tif p.peekTokenIs(token.ELSE) {\n\t\tp.nextToken()\n\t\tif p.peekTokenIs(token.IF) {\n\t\t\tp.nextToken()\n\t\t\texpression.Alternative = &ast.BlockStatement{\n\t\t\t\tStatements: []ast.Statement{\n\t\t\t\t\t&ast.ExpressionStatement{\n\t\t\t\t\t\tExpression: p.parseIfExpression(),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t\treturn expression\n\t\t}\n\n\t\tif !p.expectPeek(token.LBRACE) {\n\t\t\treturn nil\n\t\t}\n\n\t\texpression.Alternative = p.parseBlockStatement()\n\t}\n\n\treturn expression\n}\n"
  },
  {
    "path": "parser/import.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseImport() ast.Expression {\n\texp := &ast.Import{Token: p.curToken}\n\texp.Identifiers = make(map[string]*ast.Identifier)\n\tfor p.curToken.Line == p.peekToken.Line {\n\t\tp.nextToken()\n\t\tidentifier := &ast.Identifier{Value: p.curToken.Literal}\n\t\texp.Identifiers[p.curToken.Literal] = identifier\n\t\tif p.peekTokenIs(token.COMMA) {\n\t\t\tp.nextToken()\n\t\t}\n\t\tif p.peekTokenIs(token.EOF) {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn exp\n}\n"
  },
  {
    "path": "parser/index.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseIndexExpression(left ast.Expression) ast.Expression {\n\texp := &ast.IndexExpression{Token: p.curToken, Left: left}\n\n\tp.nextToken()\n\texp.Index = p.parseExpression(LOWEST)\n\tif !p.expectPeek(token.RBRACKET) {\n\t\treturn nil\n\t}\n\n\treturn exp\n}\n"
  },
  {
    "path": "parser/integer.go",
    "content": "package parser\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseIntegerLiteral() ast.Expression {\n\tlit := &ast.IntegerLiteral{Token: p.curToken}\n\n\tvalue, err := strconv.ParseInt(p.curToken.Literal, 0, 64)\n\tif err != nil {\n\t\tmsg := fmt.Sprintf(\"Mstari %d: Hatuwezi kuparse %q kama namba\", p.curToken.Line, p.curToken.Literal)\n\t\tp.errors = append(p.errors, msg)\n\t\treturn nil\n\t}\n\tlit.Value = value\n\n\treturn lit\n}\n"
  },
  {
    "path": "parser/null.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseNull() ast.Expression {\n\treturn &ast.Null{Token: p.curToken}\n}\n"
  },
  {
    "path": "parser/package.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parsePackage() ast.Expression {\n\texpression := &ast.Package{Token: p.curToken}\n\tp.nextToken()\n\texpression.Name = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}\n\n\tif !p.expectPeek(token.LBRACE) {\n\t\treturn nil\n\t}\n\texpression.Block = p.parseBlockStatement()\n\treturn expression\n}\n"
  },
  {
    "path": "parser/parser.go",
    "content": "package parser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/lexer\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nconst (\n\t_ int = iota\n\tLOWEST\n\tASSIGN      // =\n\tCOND        // OR or AND\n\tEQUALS      // ==\n\tLESSGREATER // > OR <\n\tSUM         // +\n\tPRODUCT     // *\n\tPOWER       // ** we got the power XD\n\tMODULUS     // %\n\tPREFIX      //  -X OR !X\n\tCALL        // myFunction(X)\n\tINDEX       // Arrays\n\tDOT         // For methods\n)\n\nvar precedences = map[token.TokenType]int{\n\ttoken.AND:             COND,\n\ttoken.OR:              COND,\n\ttoken.IN:              COND,\n\ttoken.ASSIGN:          ASSIGN,\n\ttoken.EQ:              EQUALS,\n\ttoken.NOT_EQ:          EQUALS,\n\ttoken.LT:              LESSGREATER,\n\ttoken.LTE:             LESSGREATER,\n\ttoken.GT:              LESSGREATER,\n\ttoken.GTE:             LESSGREATER,\n\ttoken.PLUS:            SUM,\n\ttoken.PLUS_ASSIGN:     SUM,\n\ttoken.MINUS:           SUM,\n\ttoken.MINUS_ASSIGN:    SUM,\n\ttoken.SLASH:           PRODUCT,\n\ttoken.SLASH_ASSIGN:    PRODUCT,\n\ttoken.ASTERISK:        PRODUCT,\n\ttoken.ASTERISK_ASSIGN: PRODUCT,\n\ttoken.POW:             POWER,\n\ttoken.MODULUS:         MODULUS,\n\ttoken.MODULUS_ASSIGN:  MODULUS,\n\t// token.BANG:     PREFIX,\n\ttoken.LPAREN:   CALL,\n\ttoken.LBRACKET: INDEX,\n\ttoken.DOT:      DOT, // Highest priority\n}\n\ntype (\n\tprefixParseFn  func() ast.Expression\n\tinfixParseFn   func(ast.Expression) ast.Expression\n\tpostfixParseFn func() ast.Expression\n)\n\ntype Parser struct {\n\tl *lexer.Lexer\n\n\tcurToken  token.Token\n\tpeekToken token.Token\n\tprevToken token.Token\n\n\terrors []string\n\n\tprefixParseFns  map[token.TokenType]prefixParseFn\n\tinfixParseFns   map[token.TokenType]infixParseFn\n\tpostfixParseFns map[token.TokenType]postfixParseFn\n}\n\nfunc (p *Parser) registerPrefix(tokenType token.TokenType, fn prefixParseFn) {\n\tp.prefixParseFns[tokenType] = fn\n}\n\nfunc (p *Parser) registerInfix(tokenType token.TokenType, fn infixParseFn) {\n\tp.infixParseFns[tokenType] = fn\n}\n\nfunc (p *Parser) registerPostfix(tokenType token.TokenType, fn postfixParseFn) {\n\tp.postfixParseFns[tokenType] = fn\n}\n\nfunc New(l *lexer.Lexer) *Parser {\n\tp := &Parser{l: l, errors: []string{}}\n\n\tp.nextToken()\n\tp.nextToken()\n\n\tp.prefixParseFns = make(map[token.TokenType]prefixParseFn)\n\tp.registerPrefix(token.STRING, p.parseStringLiteral)\n\tp.registerPrefix(token.IDENT, p.parseIdentifier)\n\tp.registerPrefix(token.INT, p.parseIntegerLiteral)\n\tp.registerPrefix(token.FLOAT, p.parseFloatLiteral)\n\tp.registerPrefix(token.BANG, p.parsePrefixExpression)\n\tp.registerPrefix(token.MINUS, p.parsePrefixExpression)\n\tp.registerPrefix(token.PLUS, p.parsePrefixExpression)\n\tp.registerPrefix(token.TRUE, p.parseBoolean)\n\tp.registerPrefix(token.FALSE, p.parseBoolean)\n\tp.registerPrefix(token.LPAREN, p.parseGroupedExpression)\n\tp.registerPrefix(token.IF, p.parseIfExpression)\n\tp.registerPrefix(token.FUNCTION, p.parseFunctionLiteral)\n\tp.registerPrefix(token.LBRACKET, p.parseArrayLiteral)\n\tp.registerPrefix(token.LBRACE, p.parseDictLiteral)\n\tp.registerPrefix(token.WHILE, p.parseWhileExpression)\n\tp.registerPrefix(token.NULL, p.parseNull)\n\tp.registerPrefix(token.FOR, p.parseForExpression)\n\tp.registerPrefix(token.SWITCH, p.parseSwitchStatement)\n\tp.registerPrefix(token.IMPORT, p.parseImport)\n\tp.registerPrefix(token.PACKAGE, p.parsePackage)\n\tp.registerPrefix(token.AT, p.parseAt)\n\n\tp.infixParseFns = make(map[token.TokenType]infixParseFn)\n\tp.registerInfix(token.AND, p.parseInfixExpression)\n\tp.registerInfix(token.OR, p.parseInfixExpression)\n\tp.registerInfix(token.PLUS, p.parseInfixExpression)\n\tp.registerInfix(token.PLUS_ASSIGN, p.parseAssignEqualExpression)\n\tp.registerInfix(token.MINUS, p.parseInfixExpression)\n\tp.registerInfix(token.MINUS_ASSIGN, p.parseAssignEqualExpression)\n\tp.registerInfix(token.SLASH, p.parseInfixExpression)\n\tp.registerInfix(token.SLASH_ASSIGN, p.parseAssignEqualExpression)\n\tp.registerInfix(token.ASTERISK, p.parseInfixExpression)\n\tp.registerInfix(token.ASTERISK_ASSIGN, p.parseAssignEqualExpression)\n\tp.registerInfix(token.POW, p.parseInfixExpression)\n\tp.registerInfix(token.MODULUS, p.parseInfixExpression)\n\tp.registerInfix(token.MODULUS_ASSIGN, p.parseAssignmentExpression)\n\tp.registerInfix(token.EQ, p.parseInfixExpression)\n\tp.registerInfix(token.NOT_EQ, p.parseInfixExpression)\n\tp.registerInfix(token.LT, p.parseInfixExpression)\n\tp.registerInfix(token.LTE, p.parseInfixExpression)\n\tp.registerInfix(token.GT, p.parseInfixExpression)\n\tp.registerInfix(token.GTE, p.parseInfixExpression)\n\tp.registerInfix(token.LPAREN, p.parseCallExpression)\n\tp.registerInfix(token.LBRACKET, p.parseIndexExpression)\n\tp.registerInfix(token.ASSIGN, p.parseAssignmentExpression)\n\tp.registerInfix(token.IN, p.parseInfixExpression)\n\tp.registerInfix(token.DOT, p.parseMethod)\n\n\tp.postfixParseFns = make(map[token.TokenType]postfixParseFn)\n\tp.registerPostfix(token.PLUS_PLUS, p.parsePostfixExpression)\n\tp.registerPostfix(token.MINUS_MINUS, p.parsePostfixExpression)\n\n\treturn p\n}\n\nfunc (p *Parser) ParseProgram() *ast.Program {\n\tprogram := &ast.Program{}\n\tprogram.Statements = []ast.Statement{}\n\n\tfor !p.curTokenIs(token.EOF) {\n\t\tstmt := p.parseStatement()\n\t\tprogram.Statements = append(program.Statements, stmt)\n\n\t\tp.nextToken()\n\t}\n\treturn program\n}\n\n// manage token literals:\n\nfunc (p *Parser) nextToken() {\n\tp.prevToken = p.curToken\n\tp.curToken = p.peekToken\n\tp.peekToken = p.l.NextToken()\n}\n\nfunc (p *Parser) curTokenIs(t token.TokenType) bool {\n\treturn p.curToken.Type == t\n}\n\nfunc (p *Parser) peekTokenIs(t token.TokenType) bool {\n\treturn p.peekToken.Type == t\n}\n\nfunc (p *Parser) expectPeek(t token.TokenType) bool {\n\tif p.peekTokenIs(t) {\n\t\tp.nextToken()\n\t\treturn true\n\t} else {\n\t\tp.peekError(t)\n\t\treturn false\n\t}\n}\n\nfunc (p *Parser) peekPrecedence() int {\n\tif p, ok := precedences[p.peekToken.Type]; ok {\n\t\treturn p\n\t}\n\treturn LOWEST\n}\n\nfunc (p *Parser) curPrecedence() int {\n\tif p, ok := precedences[p.curToken.Type]; ok {\n\t\treturn p\n\t}\n\n\treturn LOWEST\n}\n\n// error messages\n\nfunc (p *Parser) Errors() []string {\n\treturn p.errors\n}\n\nfunc (p *Parser) peekError(t token.TokenType) {\n\tmsg := fmt.Sprintf(\"Mstari %d: Tulitegemea kupata %s, badala yake tumepata %s\", p.curToken.Line, t, p.peekToken.Type)\n\tp.errors = append(p.errors, msg)\n}\n\n// parse expressions\n\nfunc (p *Parser) parseExpressionStatement() *ast.ExpressionStatement {\n\tstmt := &ast.ExpressionStatement{Token: p.curToken}\n\n\tstmt.Expression = p.parseExpression(LOWEST)\n\n\tif p.peekTokenIs(token.SEMICOLON) {\n\t\tp.nextToken()\n\t}\n\n\treturn stmt\n}\n\nfunc (p *Parser) parseExpression(precedence int) ast.Expression {\n\tpostfix := p.postfixParseFns[p.curToken.Type]\n\tif postfix != nil {\n\t\treturn (postfix())\n\t}\n\tprefix := p.prefixParseFns[p.curToken.Type]\n\tif prefix == nil {\n\t\tp.noPrefixParseFnError(p.curToken.Type)\n\t\treturn nil\n\t}\n\tleftExp := prefix()\n\n\tfor !p.peekTokenIs(token.SEMICOLON) && precedence < p.peekPrecedence() {\n\t\tinfix := p.infixParseFns[p.peekToken.Type]\n\t\tif infix == nil {\n\t\t\tp.noInfixParseFnError(p.peekToken.Type)\n\t\t\treturn nil\n\t\t}\n\n\t\tp.nextToken()\n\t\tleftExp = infix(leftExp)\n\t}\n\treturn leftExp\n\n}\n\n// prefix expressions\n\nfunc (p *Parser) parsePrefixExpression() ast.Expression {\n\texpression := &ast.PrefixExpression{\n\t\tToken:    p.curToken,\n\t\tOperator: p.curToken.Literal,\n\t}\n\n\tp.nextToken()\n\n\texpression.Right = p.parseExpression(PREFIX)\n\n\treturn expression\n}\n\nfunc (p *Parser) noPrefixParseFnError(t token.TokenType) {\n\tmsg := fmt.Sprintf(\"Mstari %d: Tumeshindwa kuparse %s\", p.curToken.Line, t)\n\tp.errors = append(p.errors, msg)\n}\n\n// infix expressions\n\nfunc (p *Parser) parseInfixExpression(left ast.Expression) ast.Expression {\n\texpression := &ast.InfixExpression{\n\t\tToken:    p.curToken,\n\t\tOperator: p.curToken.Literal,\n\t\tLeft:     left,\n\t}\n\n\tprecedence := p.curPrecedence()\n\tp.nextToken()\n\texpression.Right = p.parseExpression(precedence)\n\treturn expression\n}\n\nfunc (p *Parser) noInfixParseFnError(t token.TokenType) {\n\tmsg := fmt.Sprintf(\"Mstari %d: Tumeshindwa kuparse %s\", p.curToken.Line, t)\n\tp.errors = append(p.errors, msg)\n}\n\nfunc (p *Parser) parseGroupedExpression() ast.Expression {\n\tp.nextToken()\n\n\texp := p.parseExpression(LOWEST)\n\n\tif !p.expectPeek(token.RPAREN) {\n\t\treturn nil\n\t}\n\n\treturn exp\n}\n\n// postfix expressions\n\nfunc (p *Parser) parsePostfixExpression() ast.Expression {\n\texpression := &ast.PostfixExpression{\n\t\tToken:    p.prevToken,\n\t\tOperator: p.curToken.Literal,\n\t}\n\treturn expression\n}\n"
  },
  {
    "path": "parser/parser_test.go",
    "content": "package parser\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/lexer\"\n)\n\nfunc TestLetStatements(t *testing.T) {\n\ttests := []struct {\n\t\tinput              string\n\t\texpectedIdentifier string\n\t\texpectedValue      interface{}\n\t}{\n\t\t{\"fanya x = 5;\", \"x\", 5},\n\t\t{\"fanya y = x;\", \"y\", \"x\"},\n\t\t{\"fanya bangi = y;\", \"bangi\", \"y\"},\n\t}\n\n\tfor _, tt := range tests {\n\t\tl := lexer.New(tt.input)\n\t\tp := New(l)\n\t\tprogram := p.ParseProgram()\n\t\tcheckParserErrors(t, p)\n\n\t\tif len(program.Statements) != 1 {\n\t\t\tt.Fatalf(\"program.Statements does not contain 1 statements. got=%d\",\n\t\t\t\tlen(program.Statements))\n\t\t}\n\n\t\tstmt := program.Statements[0]\n\t\tif !testLetStatement(t, stmt, tt.expectedIdentifier) {\n\t\t\treturn\n\t\t}\n\n\t\tval := stmt.(*ast.LetStatement).Value\n\t\tif !testLiteralExpression(t, val, tt.expectedValue) {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc testLetStatement(t *testing.T, s ast.Statement, name string) bool {\n\tif s.TokenLiteral() != \"fanya\" {\n\t\tt.Errorf(\"s.TokenLiteral not 'fanya', got = %q\", s.TokenLiteral())\n\t\treturn false\n\t}\n\n\tletStmt, ok := s.(*ast.LetStatement)\n\tif !ok {\n\t\tt.Errorf(\"s not *ast.LetStatement, got = %T\", s)\n\t\treturn false\n\t}\n\n\tif letStmt.Name.Value != name {\n\t\tt.Errorf(\"letStmt.Name.Value not '%s', got='%s'\", name, letStmt.Name.Value)\n\t\treturn false\n\t}\n\n\tif letStmt.Name.TokenLiteral() != name {\n\t\tt.Errorf(\"s.Name not %s, got=%s\", name, letStmt.Name)\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc checkParserErrors(t *testing.T, p *Parser) {\n\terrors := p.Errors()\n\n\tif len(errors) == 0 {\n\t\treturn\n\t}\n\n\tt.Errorf(\"Parser has %d errors\", len(errors))\n\n\tfor _, msg := range errors {\n\t\tt.Errorf(\"Parser error: %q\", msg)\n\t}\n\tt.FailNow()\n}\n\nfunc TestReturnStatements(t *testing.T) {\n\ttests := []struct {\n\t\tinput         string\n\t\texpectedValue interface{}\n\t}{\n\t\t{\"rudisha 5;\", 5},\n\t\t{\"rudisha kweli;\", true},\n\t\t{\"rudisha bangi;\", \"bangi\"},\n\t}\n\n\tfor _, tt := range tests {\n\t\tl := lexer.New(tt.input)\n\t\tp := New(l)\n\t\tprogram := p.ParseProgram()\n\t\tcheckParserErrors(t, p)\n\n\t\tif len(program.Statements) != 1 {\n\t\t\tt.Fatalf(\"program.Statements does not contain 1 statements. got=%d\",\n\t\t\t\tlen(program.Statements))\n\t\t}\n\n\t\tstmt := program.Statements[0]\n\t\treturnStmt, ok := stmt.(*ast.ReturnStatement)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"stmt not *ast.returnStatement. got=%T\", stmt)\n\t\t}\n\t\tif returnStmt.TokenLiteral() != \"rudisha\" {\n\t\t\tt.Fatalf(\"returnStmt.TokenLiteral not 'rudisha', got %q\",\n\t\t\t\treturnStmt.TokenLiteral())\n\t\t}\n\t\tif testLiteralExpression(t, returnStmt.ReturnValue, tt.expectedValue) {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc TestIdentifierExpression(t *testing.T) {\n\tinput := \"foobar;\"\n\n\tl := lexer.New(input)\n\tp := New(l)\n\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tif len(program.Statements) != 1 {\n\t\tt.Fatalf(\"program has not enough statements. got=%d\", len(program.Statements))\n\t}\n\n\tstmt, ok := program.Statements[0].(*ast.ExpressionStatement)\n\tif !ok {\n\t\tt.Fatalf(\"program.Statements[0] is not an ast.ExpressionStatement, got=%T\", program.Statements[0])\n\t}\n\n\tident, ok := stmt.Expression.(*ast.Identifier)\n\tif !ok {\n\t\tt.Fatalf(\"exp not *ast.Identifier, got=%T\", stmt.Expression)\n\t}\n\n\tif ident.Value != \"foobar\" {\n\t\tt.Errorf(\"ident.Value not %s, got=%s\", \"foobar\", ident.Value)\n\t}\n\n\tif ident.TokenLiteral() != \"foobar\" {\n\t\tt.Errorf(\"ident.TokenLiteral not %s, got=%s\", \"foobar\", ident.TokenLiteral())\n\t}\n}\n\nfunc TestIntergerLiteral(t *testing.T) {\n\tinput := \"5;\"\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tif len(program.Statements) != 1 {\n\t\tt.Fatalf(\"program has not enough statements, got=%d\", len(program.Statements))\n\t}\n\n\tstmt, ok := program.Statements[0].(*ast.ExpressionStatement)\n\tif !ok {\n\t\tt.Fatalf(\"program.statements[0] is not ast.ExpressionStatement, got=%T\", program.Statements[0])\n\t}\n\n\tliteral, ok := stmt.Expression.(*ast.IntegerLiteral)\n\tif !ok {\n\t\tt.Fatalf(\"exp not *ast.IntegerLiteral, got=%T\", stmt.Expression)\n\t}\n\n\tif literal.Value != 5 {\n\t\tt.Errorf(\"literal.Value not %d, got=%d\", 5, literal.Value)\n\t}\n\n\tif literal.TokenLiteral() != \"5\" {\n\t\tt.Errorf(\"literal.TokenLiteral not %s, got=%s\", \"5\", literal.TokenLiteral())\n\t}\n}\n\nfunc TestParsingPrefixExpressions(t *testing.T) {\n\tprefixTests := []struct {\n\t\tinput    string\n\t\toperator string\n\t\tvalue    interface{}\n\t}{\n\t\t{\"!5;\", \"!\", 5},\n\t\t{\"-15;\", \"-\", 15},\n\t\t{\"!kweli\", \"!\", true},\n\t\t{\"!sikweli\", \"!\", false},\n\t}\n\n\tfor _, tt := range prefixTests {\n\t\tl := lexer.New(tt.input)\n\t\tp := New(l)\n\t\tprogram := p.ParseProgram()\n\t\tcheckParserErrors(t, p)\n\n\t\tif len(program.Statements) != 1 {\n\t\t\tt.Fatalf(\"Program statements does not contain %d statements, got=%d\\n\", 1, len(program.Statements))\n\t\t}\n\n\t\tstmt, ok := program.Statements[0].(*ast.ExpressionStatement)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"program.Statements[0] is not ast.ExpressionStatement, got=%T\", program.Statements[0])\n\t\t}\n\n\t\texp, ok := stmt.Expression.(*ast.PrefixExpression)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"stmt is not ast.PrefixExpression, got=%T\", stmt.Expression)\n\t\t}\n\t\tif exp.Operator != tt.operator {\n\t\t\tt.Fatalf(\"exp.Operator is not %s, got=%s\", tt.operator, exp.Operator)\n\t\t}\n\n\t\tif !testLiteralExpression(t, exp.Right, tt.value) {\n\t\t\treturn\n\t\t}\n\n\t}\n}\n\nfunc testIntegerLiteral(t *testing.T, il ast.Expression, value int64) bool {\n\tinteg, ok := il.(*ast.IntegerLiteral)\n\tif !ok {\n\t\tt.Errorf(\"il not *ast.IntegerLiteral, got=%T\", il)\n\t\treturn false\n\t}\n\n\tif integ.Value != value {\n\t\tt.Errorf(\"il not %d, got=%d\", value, integ.Value)\n\t\treturn false\n\t}\n\n\tif integ.TokenLiteral() != fmt.Sprintf(\"%d\", value) {\n\t\tt.Errorf(\"integ.TokenLiteral not %d, got=%s\", value, integ.TokenLiteral())\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc TestParsingInfixExpressions(t *testing.T) {\n\tinfixTests := []struct {\n\t\tinput      string\n\t\tleftValue  interface{}\n\t\toperator   string\n\t\trightValue interface{}\n\t}{\n\t\t{\"5 + 5;\", 5, \"+\", 5},\n\t\t{\"5 - 5;\", 5, \"-\", 5},\n\t\t{\"5 * 5;\", 5, \"*\", 5},\n\t\t{\"5 / 5;\", 5, \"/\", 5},\n\t\t{\"5 > 5;\", 5, \">\", 5},\n\t\t{\"5 < 5;\", 5, \"<\", 5},\n\t\t{\"5 == 5;\", 5, \"==\", 5},\n\t\t{\"5 != 5;\", 5, \"!=\", 5},\n\t\t{\"5 >= 5;\", 5, \">=\", 5},\n\t\t{\"5 <= 5;\", 5, \"<=\", 5},\n\t\t{\"5 || 5;\", 5, \"||\", 5},\n\t\t{\"5 && 5;\", 5, \"&&\", 5},\n\t\t{\"kweli == kweli\", true, \"==\", true},\n\t\t{\"kweli != sikweli\", true, \"!=\", false},\n\t\t{\"sikweli == sikweli\", false, \"==\", false},\n\t}\n\n\tfor _, tt := range infixTests {\n\t\tl := lexer.New(tt.input)\n\t\tp := New(l)\n\t\tprogram := p.ParseProgram()\n\t\tcheckParserErrors(t, p)\n\n\t\tif len(program.Statements) != 1 {\n\t\t\tt.Fatalf(\"Program.statements does not contain %d statements, got =%d\", 1, len(program.Statements))\n\t\t}\n\n\t\tstmt, ok := program.Statements[0].(*ast.ExpressionStatement)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"program.statements[0] is not ast.ExpressionStatement, got=%T\", program.Statements[0])\n\t\t}\n\n\t\tif !testInfixExpression(t, stmt.Expression, tt.leftValue, tt.operator, tt.rightValue) {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc TestOperatorPrecedenceParsing(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\t\"-a * b\",\n\t\t\t\"((-a) * b)\",\n\t\t},\n\t\t{\n\t\t\t\"!-a\",\n\t\t\t\"(!(-a))\",\n\t\t},\n\t\t{\n\t\t\t\"a + b + c\",\n\t\t\t\"((a + b) + c)\",\n\t\t},\n\t\t{\n\t\t\t\"a + b - c\",\n\t\t\t\"((a + b) - c)\",\n\t\t},\n\t\t{\n\t\t\t\"a * b * c\",\n\t\t\t\"((a * b) * c)\",\n\t\t},\n\t\t{\n\t\t\t\"a*b /c\",\n\t\t\t\"((a * b) / c)\",\n\t\t},\n\t\t{\n\t\t\t\"a + b / c\",\n\t\t\t\"(a + (b / c))\",\n\t\t},\n\t\t{\n\t\t\t\"a + b * c + d / e - f\",\n\t\t\t\"(((a + (b * c)) + (d / e)) - f)\",\n\t\t},\n\t\t{\n\t\t\t\"3 + 4; -5 * 5\",\n\t\t\t\"(3 + 4)((-5) * 5)\",\n\t\t},\n\t\t{\n\t\t\t\"5 > 4 == 3 < 4\",\n\t\t\t\"((5 > 4) == (3 < 4))\",\n\t\t},\n\t\t{\n\t\t\t\"5 < 4 != 3 > 4\",\n\t\t\t\"((5 < 4) != (3 > 4))\",\n\t\t},\n\t\t{\n\t\t\t\"3 + 4 * 5 == 3 * 1 + 4 * 5\",\n\t\t\t\"((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))\",\n\t\t},\n\t\t{\n\t\t\t\"kweli\",\n\t\t\t\"kweli\",\n\t\t},\n\t\t{\n\t\t\t\"sikweli\",\n\t\t\t\"sikweli\",\n\t\t},\n\t\t{\n\t\t\t\"3 > 5 == sikweli\",\n\t\t\t\"((3 > 5) == sikweli)\",\n\t\t},\n\t\t{\n\t\t\t\"3 < 5 == kweli\",\n\t\t\t\"((3 < 5) == kweli)\",\n\t\t},\n\t\t{\n\t\t\t\"1 + (2 + 3) + 4\",\n\t\t\t\"((1 + (2 + 3)) + 4)\",\n\t\t},\n\t\t{\n\t\t\t\"(5 + 5) * 2\",\n\t\t\t\"((5 + 5) * 2)\",\n\t\t},\n\t\t{\n\t\t\t\"2 / (5 + 5)\",\n\t\t\t\"(2 / (5 + 5))\",\n\t\t},\n\t\t{\n\t\t\t\"-(5 + 5)\",\n\t\t\t\"(-(5 + 5))\",\n\t\t},\n\t\t{\n\t\t\t\"!(kweli == kweli)\",\n\t\t\t\"(!(kweli == kweli))\",\n\t\t},\n\t\t{\n\t\t\t\"a + add(b * c) + d\",\n\t\t\t\"((a + add((b * c))) + d)\",\n\t\t},\n\t\t{\n\t\t\t\"add(a, b, 1, 2 * 3, 4 + 5, add(6, 7 * 8))\",\n\t\t\t\"add(a, b, 1, (2 * 3), (4 + 5), add(6, (7 * 8)))\",\n\t\t},\n\t\t{\n\t\t\t\"add(a + b + c * d / f + g)\",\n\t\t\t\"add((((a + b) + ((c * d) / f)) + g))\",\n\t\t},\n\t\t{\n\t\t\t\"a * [1, 2, 3, 4][b * c] * d\",\n\t\t\t\"((a * ([1, 2, 3, 4][(b * c)])) * d)\",\n\t\t},\n\t\t{\n\t\t\t\"add(a *b[2], b[1], 2 * [1, 2][1])\",\n\t\t\t\"add((a * (b[2])), (b[1]), (2 * ([1, 2][1])))\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tl := lexer.New(tt.input)\n\t\tp := New(l)\n\t\tprogram := p.ParseProgram()\n\t\tcheckParserErrors(t, p)\n\n\t\tactual := program.String()\n\n\t\tif actual != tt.expected {\n\t\t\tt.Errorf(\"expected=%q, got=%q\", tt.expected, actual)\n\t\t}\n\t}\n}\n\nfunc testIdentifier(t *testing.T, exp ast.Expression, value string) bool {\n\tident, ok := exp.(*ast.Identifier)\n\tif !ok {\n\t\tt.Errorf(\"exp not *ast.Identifier, got=%T\", exp)\n\t\treturn false\n\t}\n\n\tif ident.Value != value {\n\t\tt.Errorf(\"ident.Value not %s, got=%s\", value, ident.Value)\n\t\treturn false\n\t}\n\n\tif ident.TokenLiteral() != value {\n\t\tt.Errorf(\"ident.TokenLiteral is not %s, got=%s\", value, ident.TokenLiteral())\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc testLiteralExpression(\n\tt *testing.T,\n\texp ast.Expression,\n\texpected interface{},\n) bool {\n\tswitch v := expected.(type) {\n\tcase int:\n\t\treturn testIntegerLiteral(t, exp, int64(v))\n\tcase int64:\n\t\treturn testIntegerLiteral(t, exp, v)\n\tcase string:\n\t\treturn testIdentifier(t, exp, v)\n\tcase bool:\n\t\treturn testBooleanLiteral(t, exp, v)\n\t}\n\n\tt.Errorf(\"type of exp not handled, got=%T\", exp)\n\treturn false\n}\n\nfunc testBooleanLiteral(t *testing.T, exp ast.Expression, value bool) bool {\n\tbo, ok := exp.(*ast.Boolean)\n\tif !ok {\n\t\tt.Errorf(\"exp not *ast.Boolean, got=%T\", exp)\n\t\treturn false\n\t}\n\n\tif bo.Value != value {\n\t\tt.Errorf(\"bo.Value not %t,got=%t\", value, bo.Value)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc testInfixExpression(\n\tt *testing.T,\n\texp ast.Expression,\n\tleft interface{},\n\toperator string,\n\tright interface{},\n) bool {\n\topExp, ok := exp.(*ast.InfixExpression)\n\tif !ok {\n\t\tt.Errorf(\"exp is not ast.OperatorExpression, got=%T(%s)\", exp, exp)\n\t\treturn false\n\t}\n\n\tif !testLiteralExpression(t, opExp.Left, left) {\n\t\treturn false\n\t}\n\n\tif opExp.Operator != operator {\n\t\tt.Errorf(\"exp.Operator is not %s, got=%q\", operator, opExp.Operator)\n\t\treturn false\n\t}\n\n\tif !testLiteralExpression(t, opExp.Right, right) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc TestBooleanExpression(t *testing.T) {\n\ttests := []struct {\n\t\tinput           string\n\t\texpectedBoolean bool\n\t}{\n\t\t{\"kweli;\", true},\n\t\t{\"sikweli;\", false},\n\t}\n\n\tfor _, tt := range tests {\n\n\t\tl := lexer.New(tt.input)\n\t\tp := New(l)\n\t\tprogram := p.ParseProgram()\n\t\tcheckParserErrors(t, p)\n\n\t\tif len(program.Statements) != 1 {\n\t\t\tt.Fatalf(\"program has not enough statements. got=%d\", len(program.Statements))\n\t\t}\n\n\t\tstmt, ok := program.Statements[0].(*ast.ExpressionStatement)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"program.Statements[0] is not an ast.ExpressionStatement, got=%T\", program.Statements[0])\n\t\t}\n\n\t\tboolean, ok := stmt.Expression.(*ast.Boolean)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"exp not *ast.Boolean, got=%T\", stmt.Expression)\n\t\t}\n\n\t\tif boolean.Value != tt.expectedBoolean {\n\t\t\tt.Errorf(\"boolean.Value not %t, got=%t\", tt.expectedBoolean, boolean.Value)\n\t\t}\n\n\t}\n}\n\nfunc TestIfExpression(t *testing.T) {\n\tinput := `kama (x < y) { x }`\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tif len(program.Statements) != 1 {\n\t\tt.Fatalf(\"program.Body does not contain %d statements, got=%d\", 1, len(program.Statements))\n\t}\n\n\tstmt, ok := program.Statements[0].(*ast.ExpressionStatement)\n\tif !ok {\n\t\tt.Fatalf(\"program.Statements[0] is not an ast.ExpressionStatement, got=%T\", program.Statements[0])\n\t}\n\n\texp, ok := stmt.Expression.(*ast.IfExpression)\n\tif !ok {\n\t\tt.Fatalf(\"stmt.Expression is not ast.IfExpression, got=%T\", stmt.Expression)\n\t}\n\n\tif !testInfixExpression(t, exp.Condition, \"x\", \"<\", \"y\") {\n\t\treturn\n\t}\n\n\tif len(exp.Consequence.Statements) != 1 {\n\t\tt.Errorf(\"Consequences is not 1 statement, got=%d\\n\", len(exp.Consequence.Statements))\n\t}\n\n\tconsequence, ok := exp.Consequence.Statements[0].(*ast.ExpressionStatement)\n\tif !ok {\n\t\tt.Fatalf(\"Statements[0] is not ast.Expression, got=%T\", exp.Consequence.Statements[0])\n\t}\n\n\tif !testIdentifier(t, consequence.Expression, \"x\") {\n\t\treturn\n\t}\n\n\tif exp.Alternative != nil {\n\t\tt.Errorf(\"exp.Alternative.Statement was not nil, got=%+v\", exp.Alternative)\n\t}\n}\n\nfunc TestIfElseExpression(t *testing.T) {\n\tinput := `kama (x < y) { x } sivyo { y }`\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tif len(program.Statements) != 1 {\n\t\tt.Fatalf(\"program.Body does not contain %d statements. got=%d\\n\",\n\t\t\t1, len(program.Statements))\n\t}\n\n\tstmt, ok := program.Statements[0].(*ast.ExpressionStatement)\n\tif !ok {\n\t\tt.Fatalf(\"program.Statements[0] is not ast.ExpressionStatement. got=%T\",\n\t\t\tprogram.Statements[0])\n\t}\n\n\texp, ok := stmt.Expression.(*ast.IfExpression)\n\tif !ok {\n\t\tt.Fatalf(\"stmt.Expression is not ast.IfExpression. got=%T\", stmt.Expression)\n\t}\n\n\tif !testInfixExpression(t, exp.Condition, \"x\", \"<\", \"y\") {\n\t\treturn\n\t}\n\n\tif len(exp.Consequence.Statements) != 1 {\n\t\tt.Errorf(\"consequence is not 1 statements. got=%d\\n\",\n\t\t\tlen(exp.Consequence.Statements))\n\t}\n\n\tconsequence, ok := exp.Consequence.Statements[0].(*ast.ExpressionStatement)\n\tif !ok {\n\t\tt.Fatalf(\"Statements[0] is not ast.ExpressionStatement. got=%T\",\n\t\t\texp.Consequence.Statements[0])\n\t}\n\n\tif !testIdentifier(t, consequence.Expression, \"x\") {\n\t\treturn\n\t}\n\n\tif len(exp.Alternative.Statements) != 1 {\n\t\tt.Errorf(\"exp.Alternative.Statements does not contain 1 statements. got=%d\\n\",\n\t\t\tlen(exp.Alternative.Statements))\n\t}\n\n\talternative, ok := exp.Alternative.Statements[0].(*ast.ExpressionStatement)\n\tif !ok {\n\t\tt.Fatalf(\"Statements[0] is not ast.ExpressionStatement. got=%T\",\n\t\t\texp.Alternative.Statements[0])\n\t}\n\n\tif !testIdentifier(t, alternative.Expression, \"y\") {\n\t\treturn\n\t}\n}\n\nfunc TestFunctionLiteralParsing(t *testing.T) {\n\tinput := `unda(x, y) {x + y}`\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tif len(program.Statements) != 1 {\n\t\tt.Fatalf(\"program.Body does not contain %d statements, got=%d\\n\", 1, len(program.Statements))\n\t}\n\n\tstmt, ok := program.Statements[0].(*ast.ExpressionStatement)\n\tif !ok {\n\t\tt.Fatalf(\"program.Statements[0] is not ast.ExpressionStatement, got=%T\", program.Statements[0])\n\t}\n\n\tfunction, ok := stmt.Expression.(*ast.FunctionLiteral)\n\tif !ok {\n\t\tt.Fatalf(\"stmt.Expression is not ast.FunctionLiteral, got=%T\", stmt.Expression)\n\t}\n\n\tif len(function.Parameters) != 2 {\n\t\tt.Fatalf(\"function literal parameters wrong, want 2, got=%d\\n\", len(function.Parameters))\n\t}\n\n\ttestLiteralExpression(t, function.Parameters[0], \"x\")\n\ttestLiteralExpression(t, function.Parameters[1], \"y\")\n\n\tif len(function.Body.Statements) != 1 {\n\t\tt.Fatalf(\"function.Body.Statements has not 1 statement, got=%d\\n\", len(function.Body.Statements))\n\t}\n\n\tbodyStmt, ok := function.Body.Statements[0].(*ast.ExpressionStatement)\n\tif !ok {\n\t\tt.Fatalf(\"function body stmt is not ast.ExpressionStatement, got=%T\", function.Body.Statements[0])\n\t}\n\n\ttestInfixExpression(t, bodyStmt.Expression, \"x\", \"+\", \"y\")\n}\n\nfunc TestFunctionParameterParsing(t *testing.T) {\n\ttests := []struct {\n\t\tinput          string\n\t\texpectedParams []string\n\t}{\n\t\t{input: \"unda() {};\", expectedParams: []string{}},\n\t\t{input: \"unda(x) {};\", expectedParams: []string{\"x\"}},\n\t\t{input: \"unda(x, y, z) {};\", expectedParams: []string{\"x\", \"y\", \"z\"}},\n\t}\n\n\tfor _, tt := range tests {\n\t\tl := lexer.New(tt.input)\n\t\tp := New(l)\n\t\tprogram := p.ParseProgram()\n\t\tcheckParserErrors(t, p)\n\n\t\tstmt := program.Statements[0].(*ast.ExpressionStatement)\n\t\tfunction := stmt.Expression.(*ast.FunctionLiteral)\n\n\t\tif len(function.Parameters) != len(tt.expectedParams) {\n\t\t\tt.Errorf(\"length parameters wrong,want %d, got=%d\\n\", len(tt.expectedParams), len(function.Parameters))\n\t\t}\n\n\t\tfor i, ident := range tt.expectedParams {\n\t\t\ttestLiteralExpression(t, function.Parameters[i], ident)\n\t\t}\n\t}\n}\n\nfunc TestCallExpressionParsing(t *testing.T) {\n\tinput := \"jumlisha(1, 2 * 3, 4 + 5);\"\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tif len(program.Statements) != 1 {\n\t\tt.Fatalf(\"program.Statements does not have 1 statements, got=%d\\n\", len(program.Statements))\n\t}\n\n\tstmt, ok := program.Statements[0].(*ast.ExpressionStatement)\n\tif !ok {\n\t\tt.Fatalf(\"stmt is not ast.ExpressionStatement, got=%T\", program.Statements[0])\n\t}\n\n\texp, ok := stmt.Expression.(*ast.CallExpression)\n\tif !ok {\n\t\tt.Fatalf(\"stmt.Expression is not ast.CallExpression, got=%T\", stmt.Expression)\n\t}\n\n\tif !testIdentifier(t, exp.Function, \"jumlisha\") {\n\t\treturn\n\t}\n\n\tif len(exp.Arguments) != 3 {\n\t\tt.Fatalf(\"wrong length of arguments, got=%d\", len(exp.Arguments))\n\t}\n\n\ttestLiteralExpression(t, exp.Arguments[0], 1)\n\ttestInfixExpression(t, exp.Arguments[1], 2, \"*\", 3)\n\ttestInfixExpression(t, exp.Arguments[2], 4, \"+\", 5)\n\n}\n\nfunc TestStringLiteralExpression(t *testing.T) {\n\tinput := `\"habari yako\"`\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tstmt := program.Statements[0].(*ast.ExpressionStatement)\n\tliteral, ok := stmt.Expression.(*ast.StringLiteral)\n\tif !ok {\n\t\tt.Fatalf(\"exp not *ast.StringLiteral, got=%T\", stmt.Expression)\n\t}\n\n\tif literal.Value != \"habari yako\" {\n\t\tt.Errorf(\"literal.Value not %q, got=%q\", \"habari yako\", literal.Value)\n\t}\n}\n\nfunc TestParsingArrayLiterals(t *testing.T) {\n\tinput := \"[1,2*2,3+3]\"\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tstmt := program.Statements[0].(*ast.ExpressionStatement)\n\tarray, ok := stmt.Expression.(*ast.ArrayLiteral)\n\tif !ok {\n\t\tt.Fatalf(\"Expression not ast.ArrayLiteral, got=%T\", len(array.Elements))\n\t}\n\n\ttestIntegerLiteral(t, array.Elements[0], 1)\n\ttestInfixExpression(t, array.Elements[1], 2, \"*\", 2)\n\ttestInfixExpression(t, array.Elements[2], 3, \"+\", 3)\n}\n\nfunc TestParsingIndexExpressions(t *testing.T) {\n\tinput := \"myArray[1+1]\"\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tstmt := program.Statements[0].(*ast.ExpressionStatement)\n\tindexExp, ok := stmt.Expression.(*ast.IndexExpression)\n\tif !ok {\n\t\tt.Fatalf(\"Expression not *ast.IndexExpression, got=%T\", stmt.Expression)\n\t}\n\n\tif !testIdentifier(t, indexExp.Left, \"myArray\") {\n\t\treturn\n\t}\n\n\tif !testInfixExpression(t, indexExp.Index, 1, \"+\", 1) {\n\t\treturn\n\t}\n}\n\nfunc TestParsingDictLiteralsStringKeys(t *testing.T) {\n\tinput := `{\"one\": 1, \"two\": 2, \"three\": 3}`\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tstmt := program.Statements[0].(*ast.ExpressionStatement)\n\tdict, ok := stmt.Expression.(*ast.DictLiteral)\n\tif !ok {\n\t\tt.Fatalf(\"Expression is not a Dict, got=%T\", stmt.Expression)\n\t}\n\n\tif len(dict.Pairs) != 3 {\n\t\tt.Errorf(\"dict.Pairs wrong, got=%d\", len(dict.Pairs))\n\t}\n\n\texpected := map[string]int64{\n\t\t\"one\":   1,\n\t\t\"two\":   2,\n\t\t\"three\": 3,\n\t}\n\n\tfor key, value := range dict.Pairs {\n\t\tliteral, ok := key.(*ast.StringLiteral)\n\t\tif !ok {\n\t\t\tt.Errorf(\"Key is not a string, got=%T\", key)\n\t\t}\n\n\t\texpectedValue := expected[literal.String()]\n\t\ttestIntegerLiteral(t, value, expectedValue)\n\t}\n}\n\nfunc TestParsingDictLiteralsIntegerKeys(t *testing.T) {\n\tinput := `{1: 1, 2: 2, 3: 3}`\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tstmt := program.Statements[0].(*ast.ExpressionStatement)\n\tdict, ok := stmt.Expression.(*ast.DictLiteral)\n\tif !ok {\n\t\tt.Fatalf(\"Expression is not a Dict, got=%T\", stmt.Expression)\n\t}\n\n\tif len(dict.Pairs) != 3 {\n\t\tt.Errorf(\"dict.Pairs wrong, got=%d\", len(dict.Pairs))\n\t}\n\n\texpected := map[int64]int64{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t}\n\n\tfor key, value := range dict.Pairs {\n\t\tliteral, ok := key.(*ast.IntegerLiteral)\n\t\tif !ok {\n\t\t\tt.Errorf(\"Key is not a string, got=%T\", key)\n\t\t}\n\n\t\texpectedValue := expected[literal.Value]\n\t\ttestIntegerLiteral(t, value, expectedValue)\n\t}\n}\n\nfunc TestParsingDictLiteralsBoolKeys(t *testing.T) {\n\tinput := `{kweli: 1, sikweli: 2}`\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tstmt := program.Statements[0].(*ast.ExpressionStatement)\n\tdict, ok := stmt.Expression.(*ast.DictLiteral)\n\tif !ok {\n\t\tt.Fatalf(\"Expression is not a Dict, got=%T\", stmt.Expression)\n\t}\n\n\tif len(dict.Pairs) != 2 {\n\t\tt.Errorf(\"dict.Pairs wrong, got=%d\", len(dict.Pairs))\n\t}\n\n\texpected := map[bool]int64{\n\t\ttrue:  1,\n\t\tfalse: 2,\n\t}\n\n\tfor key, value := range dict.Pairs {\n\t\tliteral, ok := key.(*ast.Boolean)\n\t\tif !ok {\n\t\t\tt.Errorf(\"Key is not a string, got=%T\", key)\n\t\t}\n\n\t\texpectedValue := expected[literal.Value]\n\t\ttestIntegerLiteral(t, value, expectedValue)\n\t}\n}\n\nfunc TestParsingDictLiteralWithExpressions(t *testing.T) {\n\tinput := `{\"one\": 0+1, \"two\": 100-98, \"three\": 15/5}`\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tstmt := program.Statements[0].(*ast.ExpressionStatement)\n\tdict, ok := stmt.Expression.(*ast.DictLiteral)\n\tif !ok {\n\t\tt.Fatalf(\"Expression is not a dict, got=%T\", stmt.Expression)\n\t}\n\n\tif len(dict.Pairs) != 3 {\n\t\tt.Errorf(\"Dict has wrong length, got=%d\", len(dict.Pairs))\n\t}\n\n\ttests := map[string]func(ast.Expression){\n\t\t\"one\": func(e ast.Expression) {\n\t\t\ttestInfixExpression(t, e, 0, \"+\", 1)\n\t\t},\n\t\t\"two\": func(e ast.Expression) {\n\t\t\ttestInfixExpression(t, e, 100, \"-\", 98)\n\t\t},\n\t\t\"three\": func(e ast.Expression) {\n\t\t\ttestInfixExpression(t, e, 15, \"/\", 5)\n\t\t},\n\t}\n\n\tfor key, value := range dict.Pairs {\n\t\tliteral, ok := key.(*ast.StringLiteral)\n\t\tif !ok {\n\t\t\tt.Errorf(\"key is not a string, got=%T\", key)\n\t\t\tcontinue\n\t\t}\n\n\t\ttestFunc, ok := tests[literal.String()]\n\t\tif !ok {\n\t\t\tt.Errorf(\"No test function for key %q found\", literal.String())\n\t\t\tcontinue\n\t\t}\n\n\t\ttestFunc(value)\n\t}\n}\n\nfunc TestParsingEmptyDict(t *testing.T) {\n\tinput := \"{}\"\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tstmt := program.Statements[0].(*ast.ExpressionStatement)\n\tdict, ok := stmt.Expression.(*ast.DictLiteral)\n\tif !ok {\n\t\tt.Fatalf(\"Expression not a dict, got=%T\", stmt.Expression)\n\t}\n\n\tif len(dict.Pairs) != 0 {\n\t\tt.Errorf(\"Dict pairs has wrong length, got=%d\", len(dict.Pairs))\n\t}\n}\n\nfunc TestWhileLoop(t *testing.T) {\n\tinput := `wakati ( x > y ) { fanya x = 2 }`\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tif len(program.Statements) != 1 {\n\t\tt.Fatalf(\"program.Body does not contain %d statements. got=%d\", 1, len(program.Statements))\n\t}\n\n\tstmt, ok := program.Statements[0].(*ast.ExpressionStatement)\n\tif !ok {\n\t\tt.Fatalf(\"program.Statements[0] is not ast.Expression, got=%T\", program.Statements[0])\n\t}\n\texp, ok := stmt.Expression.(*ast.WhileExpression)\n\n\tif !ok {\n\t\tt.Fatalf(\"stmt.Expression is not ast.WhileExpression. got=%T\", stmt.Expression)\n\t}\n\n\tif !testInfixExpression(t, exp.Condition, \"x\", \">\", \"y\") {\n\t\treturn\n\t}\n\n\tif len(exp.Consequence.Statements) != 1 {\n\t\tt.Errorf(\"Consequence is not 1 statements. got=%d\\n\", len(exp.Consequence.Statements))\n\t}\n\n\tconsequence, ok := exp.Consequence.Statements[0].(*ast.LetStatement)\n\n\tif !ok {\n\t\tt.Fatalf(\"exp.Consequence.Statements[0] is not ast.ExpressionStatement. got=%T\", exp.Consequence.Statements[0])\n\t}\n\n\tif !testLetStatement(t, consequence, \"x\") {\n\t\tt.Fatalf(\"exp.Consequence is not LetStatement\")\n\t}\n}\n\nfunc TestShorthandAssignment(t *testing.T) {\n\tinput := []string{\n\t\t\"fanya x = 10; x *= 20;\",\n\t\t\"fanya x = 5; x += 4;\",\n\t\t\"fanya x = 7; x /= 2;\",\n\t\t\"fanya x = 8; x -= 1;\",\n\t\t\"fanya x = 5; x++;\",\n\t\t\"fanya x = 3; x--;\",\n\t\t\"fanya x = 40; fanya y = 13; x += y;\"}\n\n\tfor _, txt := range input {\n\t\tl := lexer.New(txt)\n\t\tp := New(l)\n\t\t_ = p.ParseProgram()\n\t\tcheckParserErrors(t, p)\n\t}\n}\n\nfunc TestForExpression(t *testing.T) {\n\tinput := `kwa i, v ktk j {andika(i)}`\n\n\tl := lexer.New(input)\n\tp := New(l)\n\tprogram := p.ParseProgram()\n\tcheckParserErrors(t, p)\n\n\tif len(program.Statements) != 1 {\n\t\tt.Fatalf(\"program.Body does not contain %d statements. got=%d\", 1, len(program.Statements))\n\t}\n\n\tstmt, ok := program.Statements[0].(*ast.ExpressionStatement)\n\tif !ok {\n\t\tt.Fatalf(\"program.Statements[0] is not ast.Expression, got=%T\", program.Statements[0])\n\t}\n\n\texp, ok := stmt.Expression.(*ast.ForIn)\n\n\tif !ok {\n\t\tt.Fatalf(\"stmt.Expression is not ast.ForIn. got=%T\", stmt.Expression)\n\t}\n\n\tif exp.Key != \"i\" {\n\t\tt.Fatalf(\"Wrong Key Index, expected 'i' got %s\", exp.Key)\n\t}\n\n\tif exp.Value != \"v\" {\n\t\tt.Fatalf(\"Wrong Value Index, expected 'v' got %s\", exp.Value)\n\t}\n}\n\nfunc TestParsePostfix(t *testing.T) {\n\tinput := []string{\n\t\t\"a = 5; a++;\",\n\t\t\"b = 5; b--;\",\n\t}\n\n\tfor _, txt := range input {\n\t\tl := lexer.New(txt)\n\t\tp := New(l)\n\t\t_ = p.ParseProgram()\n\t\tcheckParserErrors(t, p)\n\t}\n}\n\nfunc TestParseDot(t *testing.T) {\n\tinput := []string{\n\t\t\"a.b()\",\n\t\t\"5.5\",\n\t}\n\n\tfor _, txt := range input {\n\t\tl := lexer.New(txt)\n\t\tp := New(l)\n\t\t_ = p.ParseProgram()\n\t\tcheckParserErrors(t, p)\n\t}\n}\n\nfunc TestParseSwitch(t *testing.T) {\n\tinput := `\n\tbadili (a) {\n\t\tikiwa 2 {\n\t\t\tandika(2)\n\t\t}\n\t\tikiwa 3 {\n\t\t\tandika(3)\n\t\t}\n\t\tkawaida {\n\t\t\tandika(0)\n\t\t}\n\t}\n\t`\n\n\tl := lexer.New(input)\n\tp := New(l)\n\t_ = p.ParseProgram()\n\tcheckParserErrors(t, p)\n}\n\nfunc TestParseImport(t *testing.T) {\n\tinput := `\n\ttumia muda\n\tmuda.hasahivi()\n\t`\n\n\tl := lexer.New(input)\n\tp := New(l)\n\t_ = p.ParseProgram()\n\tcheckParserErrors(t, p)\n}\n"
  },
  {
    "path": "parser/statements.go",
    "content": "package parser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseStatement() ast.Statement {\n\tswitch p.curToken.Type {\n\tcase token.LET:\n\t\treturn p.parseLetStatement()\n\tcase token.RETURN:\n\t\treturn p.parseReturnStatement()\n\tcase token.BREAK:\n\t\treturn p.parseBreak()\n\tcase token.CONTINUE:\n\t\treturn p.parseContinue()\n\tdefault:\n\t\treturn p.parseExpressionStatement()\n\t}\n}\n\nfunc (p *Parser) parseLetStatement() *ast.LetStatement {\n\tstmt := &ast.LetStatement{Token: p.curToken}\n\n\tif !p.expectPeek(token.IDENT) {\n\t\treturn nil\n\t}\n\n\tstmt.Name = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}\n\n\tif !p.expectPeek(token.ASSIGN) {\n\t\treturn nil\n\t}\n\n\tp.nextToken()\n\n\tstmt.Value = p.parseExpression(LOWEST)\n\n\tif p.peekTokenIs(token.SEMICOLON) {\n\t\tp.nextToken()\n\t}\n\n\treturn stmt\n}\n\nfunc (p *Parser) parseReturnStatement() *ast.ReturnStatement {\n\tstmt := &ast.ReturnStatement{Token: p.curToken}\n\tp.nextToken()\n\n\tstmt.ReturnValue = p.parseExpression(LOWEST)\n\n\tif p.peekTokenIs(token.SEMICOLON) {\n\t\tp.nextToken()\n\t}\n\n\treturn stmt\n}\n\nfunc (p *Parser) parseBlockStatement() *ast.BlockStatement {\n\tblock := &ast.BlockStatement{Token: p.curToken}\n\tblock.Statements = []ast.Statement{}\n\n\tp.nextToken()\n\n\tfor !p.curTokenIs(token.RBRACE) {\n\t\tif p.curTokenIs(token.EOF) {\n\t\t\tmsg := fmt.Sprintf(\"Mstari %d: Hukufunga Mabano '}'\", p.curToken.Line)\n\t\t\tp.errors = append(p.errors, msg)\n\t\t\treturn nil\n\t\t}\n\t\tstmt := p.parseStatement()\n\t\tblock.Statements = append(block.Statements, stmt)\n\t\tp.nextToken()\n\t}\n\n\treturn block\n}\n"
  },
  {
    "path": "parser/string.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseStringLiteral() ast.Expression {\n\treturn &ast.StringLiteral{Token: p.curToken, Value: p.curToken.Literal}\n}\n"
  },
  {
    "path": "parser/switch.go",
    "content": "package parser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseSwitchStatement() ast.Expression {\n\texpression := &ast.SwitchExpression{Token: p.curToken}\n\n\tif !p.expectPeek(token.LPAREN) {\n\t\treturn nil\n\t}\n\n\tp.nextToken()\n\texpression.Value = p.parseExpression(LOWEST)\n\n\tif expression.Value == nil {\n\t\treturn nil\n\t}\n\n\tif !p.expectPeek(token.RPAREN) {\n\t\treturn nil\n\t}\n\n\tif !p.expectPeek(token.LBRACE) {\n\t\treturn nil\n\t}\n\tp.nextToken()\n\n\tfor !p.curTokenIs(token.RBRACE) {\n\n\t\tif p.curTokenIs(token.EOF) {\n\t\t\tmsg := fmt.Sprintf(\"Mstari %d: Haukufunga ENDAPO (SWITCH)\", p.curToken.Line)\n\t\t\tp.errors = append(p.errors, msg)\n\t\t\treturn nil\n\t\t}\n\t\ttmp := &ast.CaseExpression{Token: p.curToken}\n\n\t\tif p.curTokenIs(token.DEFAULT) {\n\n\t\t\ttmp.Default = true\n\n\t\t} else if p.curTokenIs(token.CASE) {\n\n\t\t\tp.nextToken()\n\n\t\t\tif p.curTokenIs(token.DEFAULT) {\n\t\t\t\ttmp.Default = true\n\t\t\t} else {\n\t\t\t\ttmp.Expr = append(tmp.Expr, p.parseExpression(LOWEST))\n\t\t\t\tfor p.peekTokenIs(token.COMMA) {\n\t\t\t\t\tp.nextToken()\n\t\t\t\t\tp.nextToken()\n\t\t\t\t\ttmp.Expr = append(tmp.Expr, p.parseExpression(LOWEST))\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tmsg := fmt.Sprintf(\"Mstari %d: Tulitegemea Kauli IKIWA (CASE) au KAWAIDA (DEFAULT) lakini tumepewa: %s\", p.curToken.Line, p.curToken.Type)\n\t\t\tp.errors = append(p.errors, msg)\n\t\t\treturn nil\n\t\t}\n\n\t\tif !p.expectPeek(token.LBRACE) {\n\t\t\treturn nil\n\t\t}\n\n\t\ttmp.Block = p.parseBlockStatement()\n\t\tp.nextToken()\n\t\texpression.Choices = append(expression.Choices, tmp)\n\t}\n\n\tcount := 0\n\tfor _, c := range expression.Choices {\n\t\tif c.Default {\n\t\t\tcount++\n\t\t}\n\t}\n\tif count > 1 {\n\t\tmsg := fmt.Sprintf(\"Kauli ENDAPO (SWITCH) hua na kauli 'KAWAIDA' (DEFAULT) moja tu! Wewe umeweka %d\", count)\n\t\tp.errors = append(p.errors, msg)\n\t\treturn nil\n\n\t}\n\treturn expression\n\n}\n"
  },
  {
    "path": "parser/while.go",
    "content": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Parser) parseWhileExpression() ast.Expression {\n\texpression := &ast.WhileExpression{Token: p.curToken}\n\n\tif !p.expectPeek(token.LPAREN) {\n\t\treturn nil\n\t}\n\n\tp.nextToken()\n\texpression.Condition = p.parseExpression(LOWEST)\n\n\tif !p.expectPeek(token.RPAREN) {\n\t\treturn nil\n\t}\n\n\tif !p.expectPeek(token.LBRACE) {\n\t\treturn nil\n\t}\n\n\texpression.Consequence = p.parseBlockStatement()\n\n\treturn expression\n}\n"
  },
  {
    "path": "repl/docs/en/README.md",
    "content": "# NURU PROGRAMMING LANGUAGE DOCUMENTATION\n\nThis documentation is intended for people with some experience in programming. It describes the syntax, types and how to perform various operations using the language.\n\n## Table Of Contents\n\n- [Arrays in Nuru](arrays.md#arrays-in-nuru)\n    - [Creating Arrays](arrays.md#creating-arrays)\n    - [Accessing and Modifying Array Elements](arrays.md#accessing-and-modifying-array-elements)\n    - [Concatenating Arrays](arrays.md#concatenating-arrays)\n    - [Checking for Array Membership](arrays.md#checking-for-array-membership)\n    - [Looping Over Arrays](arrays.md#looping-over-arrays)\n    - [Array Methods](arrays.md#array-methods)\n        - [idadi()](arrays.md#idadi())\n        - [sukuma()](arrays.md#sukuma())\n        - [yamwisho()](arrays.md#yamwisho())\n- [Built-in Functions in Nuru](builtins.md#built-in-functions-in-nuru)\n    - [The andika() Function](builtins.md#the-andika()-function)\n    - [The jaza() Function](builtins.md#the-jaza()-function)\n    - [The aina() Function](builtins.md#the-aina()-function)\n    - [The fungua() Function](builtins.md#the-fungua()-function)\n- [Comments in Nuru](comments.md#comments-in-nuru)\n    - [Single-Line Comments](comments.md#single-line-comments)\n    - [Multi-Line Comments](comments.md#multi-line-comments)\n- [Conditional Statements in Nuru](ifStatements.md#conditional-statements-in-nuru)\n    - [If Statement (Kama)](ifStatements.md#if-statement-(kama))\n    - [Else If and Else Blocks (Au Kama and Sivyo)](ifStatements.md#else-if-and-else-blocks-(au-kama-and-sivyo))\n- [Dictionaries in Nuru](dictionaries.md#dictionaries-in-nuru)\n    - [Creating Dictionaries](dictionaries.md#creating-dictionaries)\n    - [Accessing Elements](dictionaries.md#accessing-elements)\n    - [Updating Elements](dictionaries.md#updating-elements)\n    - [Adding New Elements](dictionaries.md#adding-new-elements)\n    - [Concatenating Dictionaries](dictionaries.md#concatenating-dictionaries)\n    - [Checking If a Key Exists in a Dictionary](dictionaries.md#checking-if-a-key-exists-in-a-dictionary)\n    - [Looping Over a Dictionary](dictionaries.md#looping-over-a-dictionary)\n- [Files in Nuru](files.md#files-in-nuru)\n    - [Opening a File](files.md#opening-a-file)\n    - [Reading a File](files.md#reading-a-file)\n- [For Loops in Nuru](for.md#for-loops-in-nuru)\n    - [Basic Syntax](for.md#basic-syntax)\n    - [Iterating Over Key-Value Pairs](for.md#iterating-over-key-value-pairs)\n        - [Dictionaries](for.md#dictionaries)\n        - [Strings](for.md#strings)\n        - [Lists](for.md#lists)\n    - [Break (Vunja) and Continue (Endelea)](for.md#break-(vunja)-and-continue-(endelea))\n        - [Break (Vunja)](for.md#break-(vunja))\n        - [Continue (Endelea)](for.md#continue-(endelea))\n- [Functions in Nuru](function.md#functions-in-nuru)\n    - [Basic Syntax](function.md#basic-syntax)\n    - [Parameters](function.md#parameters)\n    - [Default Parameters](function.md#default-parameters)\n    - [Return (rudisha)](function.md#return-(rudisha))\n    - [Recursion](function.md#recursion)\n    - [Closures](function.md#closures)\n- [HTTP with Nuru](net.md#http-with-nuru)\n    - [Importing](net.md#importing)\n    - [Methods](net.md#methods)\n        - [peruzi()](net.md#peruzi())\n        - [tuma()](net.md#tuma())\n- [Identifiers in Nuru](identifiers.md#identifiers-in-nuru)\n    - [Syntax Rules](identifiers.md#syntax-rules)\n    - [Best Practices](identifiers.md#best-practices)\n- [INTEGERS (NAMBA) AND FLOATS (DESIMALI)](numbers.md#integers-(namba)-and-floats-(desimali))\n    - [PRECEDENCE](numbers.md#precedence)\n    - [UNARY INCREMENTS](numbers.md#unary-increments)\n    - [SHORTHAND ASSIGNMENT](numbers.md#shorthand-assignment)\n    - [NEGATIVE NUMBERS](numbers.md#negative-numbers)\n- [JSON in Nuru](json.md#json-in-nuru)\n    - [Import JSONI](json.md#import-jsoni)\n    - [Decoding JSON with dikodi()](json.md#decoding-json-with-dikodi())\n    - [Encoding JSON with enkodi()](json.md#encoding-json-with-enkodi())\n- [Hisabati in nuru](hisabati.md#module-hisabati)\n    - [Import Hisabati](hisabati.md#usage)\n    - [In-built Constants](hisabati.md#1-constants)\n    - [In-built Methods](hisabati.md#2-methods)\n- [KEYWORDS](keywords.md#keywords)\n    - [Reserved Keywords](keywords.md#reserved-keywords)\n    - [BuiltIns](keywords.md#builtins)\n- [Null (Tupu) in Nuru](null.md#null-(tupu)-in-nuru)\n    - [Definition](null.md#definition)\n    - [Evaluation](null.md#evaluation)\n- [NURU PROGRAMMING LANGUAGE DOCUMENTATION](README.md#nuru-programming-language-documentation)\n    - [Table Of Contents](README.md#table-of-contents)\n- [OPERATORS](operators.md#operators)\n    - [ASSIGNMENT](operators.md#assignment)\n    - [ARITHMETIC OPERATORS](operators.md#arithmetic-operators)\n    - [COMPARISON OPERATORS](operators.md#comparison-operators)\n    - [MEMBER OPERATOR](operators.md#member-operator)\n    - [LOGIC OPERATORS](operators.md#logic-operators)\n    - [PRECEDENCE OF OPERATORS](operators.md#precedence-of-operators)\n- [Strings in Nuru](strings.md#strings-in-nuru)\n    - [Basic Syntax](strings.md#basic-syntax)\n    - [Concatenating Strings](strings.md#concatenating-strings)\n    - [Looping over a String](strings.md#looping-over-a-string)\n    - [Comparing Strings](strings.md#comparing-strings)\n    - [String Methods](strings.md#string-methods)\n        - [idadi()](strings.md#idadi())\n        - [herufikubwa()](strings.md#herufikubwa())\n        - [herufindogo](strings.md#herufindogo)\n        - [gawa](strings.md#gawa)\n- [Switch Statements in Nuru](switch.md#switch-statements-in-nuru)\n    - [Basic Syntax](switch.md#basic-syntax)\n    - [Multiple Values in a Case](switch.md#multiple-values-in-a-case)\n    - [Default Case (kawaida)](switch.md#default-case-(kawaida))\n- [Time in Nuru](time.md#time-in-nuru)\n    - [Importing Time](time.md#importing-time)\n    - [Time Methods](time.md#time-methods)\n        - [hasahivi()](time.md#hasahivi())\n        - [tangu()](time.md#tangu())\n        - [lala()](time.md#lala())\n        - [ongeza()](time.md#ongeza())\n- [WHILE (WAKATI)](while.md#while-(wakati))\n    - [Basic Syntax](while.md#basic-syntax)\n    - [Break (vunja) and Continue (endelea)](while.md#break-(vunja)-and-continue-(endelea))\n        - [Break (Vunja)](while.md#break-(vunja))\n        - [Continue (Endelea)](while.md#continue-(endelea))\n- [Working with Booleans in Nuru](bool.md#working-with-booleans-in-nuru)\n    - [Evaluating Boolean Expressions](bool.md#evaluating-boolean-expressions)\n        - [Evaluating Simple Expressions](bool.md#evaluating-simple-expressions)\n        - [Evaluating Complex Expressions](bool.md#evaluating-complex-expressions)\n    - [Boolean Operators](bool.md#boolean-operators)\n        - [The && Operator](bool.md#the-&&-operator)\n        - [The || Operator](bool.md#the-||-operator)\n        - [The ! Operator](bool.md#the-!-operator)\n    - [Working with Boolean Values in Loops](bool.md#working-with-boolean-values-in-loops)\n"
  },
  {
    "path": "repl/docs/en/arrays.md",
    "content": "# Arrays in Nuru\n\nArrays in Nuru are versatile data structures that can hold multiple items, including different types such as numbers, strings, booleans, functions, and null values. This page covers various aspects of arrays, including how to create, manipulate, and iterate over them using Nuru's built-in keywords and methods.\n\n## Creating Arrays\n\nTo create an array, use square brackets [] and separate items with commas:\n\n```s\norodha = [1, \"pili\", kweli]\n```\n## Accessing and Modifying Array Elements\n\nArrays in Nuru are zero-indexed. To access an element, use the element's index in square brackets:\n\n```s\nnamba = [10, 20, 30]\njina = namba[1]  // jina is 20\n```\n\nYou can reassign an element in an array using its index:\n\n```s\nnamba[1] = 25\n```\n\n## Concatenating Arrays\n\nTo concatenate two or more arrays, use the + operator:\n\n```s\na = [1, 2, 3]\nb = [4, 5, 6]\nc = a + b\n// c is now [1, 2, 3, 4, 5, 6]\n```\n\n## Checking for Array Membership\n\nUse the `ktk` keyword to check if an item exists in an array:\n\n```s\nnamba = [10, 20, 30]\nandika(20 ktk namba)  // will print kweli\n```\n\n## Looping Over Arrays\n\nYou can use the kwa and ktk keywords to loop over array elements. To loop over just the values, use the following syntax:\n\n```\nnamba = [1, 2, 3, 4, 5]\n\nkwa thamani ktk namba {\n    andika(thamani)\n}\n```\n\nTo loop over both index and value pairs, use this syntax:\n\n```s\nmajina = [\"Juma\", \"Asha\", \"Haruna\"]\n\nkwa idx, jina ktk majina {\n    andika(idx, \"-\", jina)\n}\n```\n\n## Array Methods\n\nArrays in Nuru have several built-in methods:\n\n### idadi()\n\nidadi() returns the length of an array:\n\n```s\na = [1, 2, 3]\nurefu = a.idadi()\nandika(urefu)  // will print 3\n```\n\n### sukuma()\n\nsukuma() adds one or more items to the end of an array:\n\n```s\na = [1, 2, 3]\na.sukuma(\"s\", \"g\")\nandika(a)  // will print [1, 2, 3, \"s\", \"g\"]\n```\n\n### yamwisho()\n\nyamwisho() returns the last item in an array, or tupu if the array is empty:\n\n```s\na = [1, 2, 3]\nmwisho = a.yamwisho()\nandika(mwisho)  // will print 3\n\nb = []\nmwisho = b.yamwisho()\nandika(mwisho)  // will print tupu\n```\n\n### map()\n\nmap() goes through every element in the array and applies the passed function to each element. It will then return a new array with the updated elements:\n```s\na = [1, 2, 3]\n\nb = a.map(unda(x){rudisha x*2})\n\nandika(b) // [2, 4, 6]\n```\n\n### chuja()\n\nchuja() will go through every single element of an array and checks if that element returns true or false when passed into a function. It will return a new array with elements that returned true:\n```s\na = [1, 2, 3, 4]\n\nb = a.chuja(unda(x){\n    kama (x % 2 == 0) \n        {rudisha kweli}\n    rudisha sikweli\n    })\n\nandika(b) // [2, 4]\n```\n\nWith this information, you can now effectively work with arrays in Nuru, making it easy to manipulate collections of data in your programs.\n"
  },
  {
    "path": "repl/docs/en/bool.md",
    "content": "# Working with Booleans in Nuru\n\nBoolean objects in Nuru are truthy, meaning that any value is true, except tupu and sikweli. They are used to evaluate expressions that return true or false values.\n\n## Evaluating Boolean Expressions\n\n### Evaluating Simple Expressions\n\nIn Nuru, you can evaluate simple expressions that return a boolean value:\n\n```s\nandika(1 > 2) // Output: `sikweli`\n\nandika(1 + 3 < 10) // Output: `kweli`\n```\n\n### Evaluating Complex Expressions\n\nIn Nuru, you can use boolean operators to evaluate complex expressions:\n\n```s\na = 5\nb = 10\nc = 15\n\nresult = (a < b) && (b < c)\n\nkama (result) {\n    andika(\"Both conditions are true\")\n} sivyo {\n    andika(\"At least one condition is false\")\n}\n// Output: \"Both conditions are true\"\n```\n\nHere, we create three variables a, b, and c. We then evaluate the expression (a < b) && (b < c). Since both conditions are true, the output will be \"Both conditions are true\".\n\n## Boolean Operators\n\nNuru has several boolean operators that you can use to evaluate expressions:\n\n### The && Operator\n\nThe && operator evaluates to true only if both operands are true. Here's an example:\n\n```s\nandika(kweli && kweli) // Output: `kweli`\n\nandika(kweli && sikweli) // Output: `sikweli`\n```\n\n### The || Operator\n\nThe || operator evaluates to true if at least one of the operands is true. Here's an example:\n\n```s\nandika(kweli || sikweli) // Output: `kweli`\n\nandika(sikweli || sikweli) // Output: `sikweli`\n```\n\n### The ! Operator\n\nThe ! operator negates the value of the operand. Here's an example:\n\n```s\nandika(!kweli) // Output: `sikweli`\n\nandika(!sikweli) // Output: `kweli`\n```\n\n## Working with Boolean Values in Loops\n\nIn Nuru, you can use boolean expressions in loops to control their behavior. Here's an example:\n\n```s\nnamba = [1, 2, 3, 4, 5]\n\nkwa thamani ktk namba {\n    kama (thamani % 2 == 0) {\n        andika(thamani, \"is even\")\n    } sivyo {\n        andika(thamani, \"is odd\")\n    }\n}\n// Output:\n// 1 is odd\n// 2 is even\n// 3 is odd\n// 4 is even\n// 5 is odd\n```\n\nHere, we create an array namba with the values 1 through 5. We then loop over each value in the array and use the % operator to determine if it is even or odd. The output will be \"is even\" for even numbers and \"is odd\" for odd numbers.\n\n\nBoolean objects in Nuru can be used to evaluate expressions that return true or false values. You can use boolean operators to evaluate complex expressions and control the behavior of loops. Understanding how to work with boolean values is an essential skill for any Nuru programmer."
  },
  {
    "path": "repl/docs/en/builtins.md",
    "content": "# Built-in Functions in Nuru\n\nNuru has several built-in functions that perform specific tasks.\n\n## The andika() Function\n\nThe andika() function is used to print out messages to the console. It can take zero or more arguments, and the arguments will be printed out with a space in between them. Additionally, andika() supports basic formatting such as /n for a new line, /t for a tab space, and \\\\ for a backslash. Here's an example:\n\n```s\nandika(1, 2, 3) // Output: \"1 2 3\"\n```\n\n## The jaza() Function\n\nThe jaza() function is used to get input from the user. It can take zero or one argument, which is a string that will be used as a prompt for the user. Here's an example:\n\n```s\nfanya salamu = unda() {\n    fanya jina = jaza(\"Unaitwa nani? \")\n    andika(\"Mambo vipi\", jina)\n}\n\nsalamu()\n```\n\nIn this example, we define a function `salamu()` that prompts the user to enter their name using the `jaza()` function. We then use the `andika()` function to print out a message that includes the user's name.\n\n## The aina() Function\n\nThe `aina()` function is used to determine the type of an object. It accepts one argument, and the return value will be a string indicating the type of the object. Here's an example:\n\n```s\naina(2) // Output: \"NAMBA\"\naina(\"Nuru\") // Output: \"NENO\"\n```\n\n## The fungua() Function\n\nThe `fungua()` function is used to open a file. It accepts one argument, which is the path to the file that you want to open. Here's an example:\n\n```s\nfaili = fungua(\"data.txt\")\n```\n\nIn this example, we use the `fungua()` function to open a file named \"data.txt\". The variable faili will contain a reference to the opened file."
  },
  {
    "path": "repl/docs/en/comments.md",
    "content": "# Comments in Nuru\n\nIn Nuru, you can write comments to provide explanations and documentation for your code. Comments are lines of text that are ignored by the Nuru interpreter, so they will not affect the behavior of your program. There are two types of comments in Nuru: single-line comments and multi-line comments.\n\n## Single-Line Comments\n\nSingle-line comments are used to provide brief explanations or documentation for a single line of code. To write a single-line comment in Nuru, use two forward slashes (//) followed by your comment text. Here's an example:\n\n```s\n// This line will be ignored by the Nuru interpreter\n```\n\nIn this example, the comment text \"This line will be ignored by the Nuru interpreter\" will be ignored by the interpreter, so it will not affect the behavior of the program.\n\n## Multi-Line Comments\n\nMulti-line comments are used to provide more detailed explanations or documentation for multiple lines of code. To write a multi-line comment in Nuru, use a forward slash followed by an asterisk ( /* ) to start the comment, and an asterisk followed by a forward slash ( */ ) to end the comment. Here's an example:\n\n```s\n/*\nThese lines\nWill \nbe \nignored\n*/\n```\n\nIn this example, all the lines between the /* and */ symbols will be ignored by the Nuru interpreter, so they will not affect the behavior of the program.\n\nBy utilizing single-line and multi-line comments in Nuru, you can make your code more readable and easier to maintain for yourself and others who may need to work with your code in the future."
  },
  {
    "path": "repl/docs/en/dictionaries.md",
    "content": "# Dictionaries in Nuru\n\nDictionaries in Nuru, also known as \"kamusi,\" are powerful and flexible data structures that store key-value pairs. This page provides a comprehensive overview of dictionaries in Nuru, including how to create, access, modify, and iterate over them.\n\n## Creating Dictionaries\n\nDictionaries are enclosed in curly braces {} and consist of keys and values separated by colons. Here's an example of defining a dictionary:\n\n```s\n\norodha = {\"jina\": \"Juma\", \"umri\": 25}\n```\n\nKeys can be strings, integers, floats, or booleans, while values can be any data type, including strings, integers, floats, booleans, null, or functions:\n\n```s\nk = {\n    \"jina\": \"Juma\",\n    \"umri\": 25,\n    kweli: \"kweli\",\n    \"salimu\": unda(x) { andika(\"habari\", x) },\n    \"sina value\": tupu\n}\n```\n\n## Accessing Elements\n\nAccess individual elements in a dictionary using their keys:\n\n```s\n\nandika(k[kweli]) // kweli\nandika(k[\"salimu\"](\"Juma\")) // habari Juma\n```\n\n## Updating Elements\n\nUpdate the value of an element by assigning a new value to its key:\n\n```s\nk['umri'] = 30\nandika(k['umri']) // 30\n```\n\n## Adding New Elements\n\nAdd a new key-value pair to a dictionary by assigning a value to a non-existent key:\n\n```s\nk[\"lugha\"] = \"Kiswahili\"\nandika(k[\"lugha\"]) // Kiswahili\n```\n\n## Concatenating Dictionaries\n\nCombine two dictionaries using the + operator:\n\n```s\nmatunda = {\"a\": \"apple\", \"b\": \"banana\"}\nmboga = {\"c\": \"carrot\", \"d\": \"daikon\"}\nvyakula = matunda + mboga\nandika(vyakula) // {\"a\": \"apple\", \"b\": \"banana\", \"c\": \"carrot\", \"d\": \"daikon\"}\n```\n\n## Checking If a Key Exists in a Dictionary\n\nUse the ktk keyword to check if a key exists in a dictionary:\n\n```s\n\n\"umri\" ktk k // kweli\n\"urefu\" ktk k // sikweli\n```\n\n## Looping Over a Dictionary\n\nLoop over a dictionary to access its keys and values:\n\n```s\n\nhobby = {\"a\": \"asili\", \"b\": \"baiskeli\", \"c\": \"chakula\"}\nkwa i, v ktk hobby {\n    andika(i, \"=>\", v)\n}\n```\nOutput\n```s\na => asili\nb => baiskeli\nc => chakula\n```\n\nLoop over just the values:\n\n```s\nkwa v ktk hobby {\n    andika(v)\n}\n```\nOutput\n```s\nasili\nbaiskeli\nchakula\n```\n\nWith this knowledge, you can now effectively use dictionaries in Nuru to store and manage key-value pairs, offering a flexible way to organize and access data in your programs."
  },
  {
    "path": "repl/docs/en/files.md",
    "content": "# Files in Nuru\n\nNuru's ability to deal with files is primitive, and as for now it only allows you to read contents of a file.\n\n## Opening a File\n\nYou open a file with the `fungua` keyword. This will return an object of type `FAILI`:\n```\nfileYangu = fungua(\"file.txt\")\n\naina(fileYangu) // FAILI\n```\n\n## Reading a File\n\nOnce you have a file object you can read its contents with the `soma()` method. This will return the contents of the file as a string:\n```\nfileYangu = fungua(\"file.txt\")\n\nfileYangu.soma()\n```\n"
  },
  {
    "path": "repl/docs/en/for.md",
    "content": "# For Loops in Nuru\n\nFor loops are a fundamental control structure in Nuru, used for iterating over iterable objects such as strings, arrays, and dictionaries. This page covers the syntax and usage of for loops in Nuru, including key-value pair iteration, and the use of break and continue statements.\n\n## Basic Syntax\nTo create a for loop, use the kwa keyword followed by a temporary identifier (such as i or v) and the iterable object. Enclose the loop body in curly braces {}. Here's an example with a string:\n\n```s\njina = \"lugano\"\n\nkwa i ktk jina {\n    andika(i)\n}\n```\nOutput:\n\n```s\nl\nu\ng\na\nn\no\n```\n\n## Iterating Over Key-Value Pairs\n\n### Dictionaries\n\nNuru allows you to iterate over both the value or the key-value pair of an iterable. To iterate over just the values, use one temporary identifier:\n\n```s\nkamusi = {\"a\": \"andaa\", \"b\": \"baba\"}\n\nkwa v ktk kamusi {\n    andika(v)\n}\n```\n\nOutput:\n\n```s\nandaa\nbaba\n```\nTo iterate over both the keys and the values, use two temporary identifiers:\n\n```s\n\nkwa k, v ktk kamusi {\n    andika(k + \" ni \" + v)\n}\n```\nOutput:\n\n```s\na ni andaa\nb ni baba\n```\n\n### Strings\n\nTo iterate over just the values in a string, use one temporary identifier:\n\n```s\nkwa v ktk \"mojo\" {\n    andika(v)\n}\n```\n\nOutput:\n```s\nm\no\nj\no\n```\nTo iterate over both the keys and the values in a string, use two temporary identifiers:\n\n```s\nkwa i, v ktk \"mojo\" {\n    andika(i, \"->\", v)\n}\n```\nOutput:\n```s\n0 -> m\n1 -> o\n2 -> j\n3 -> o\n```\n\n### Lists\n\nTo iterate over just the values in a list, use one temporary identifier:\n\n```s\nmajina = [\"juma\", \"asha\", \"haruna\"]\n\nkwa v ktk majina {\n    andika(v)\n}\n```\n\nOutput:\n\n```s\njuma\nasha\nharuna\n```\n\nTo iterate over both the keys and the values in a list, use two temporary identifiers:\n\n```s\nkwa i, v ktk majina {\n    andika(i, \"-\", v)\n}\n```\n\nOutput:\n\n```s\n0 - juma\n1 - asha\n2 - haruna\n```\n\n## Break (Vunja) and Continue (Endelea)\n\n### Break (Vunja)\n\nUse the vunja keyword to terminate a loop:\n\n```s\n\nkwa i, v ktk \"mojo\" {\n    kama (i == 2) {\n        andika(\"nimevunja\")\n        vunja\n    }\n    andika(v)\n}\n```\n\nOutput:\n\n```s\nm\no\nnimevunja\n```\n\n### Continue (Endelea)\n\nUse the endelea keyword to skip a specific iteration:\n\n```s\nkwa i, v ktk \"mojo\" {\n    kama (i == 2) {\n        andika(\"nimeruka\")\n        endelea\n    }\n    andika(v)\n}\n```\n\nOutput:\n\n```s\nm\no\nnimeruka\no\n```"
  },
  {
    "path": "repl/docs/en/function.md",
    "content": "# Functions in Nuru\n\nFunctions are a fundamental part of Nuru programming, allowing you to define reusable blocks of code. This page covers the syntax and usage of functions in Nuru, including parameters, default parameters, return statements, recursion, and closures.\n\n## Basic Syntax\n\nA function block starts with the unda keyword, followed by parameters enclosed in parentheses () and the body enclosed in curly braces {}. Functions must be assigned to a variable:\n\n```s\njum = unda(x, y) {\n    rudisha x + y\n}\n\njum(2, 3) // 5\n```\n\n## Parameters\n\nFunctions can have zero or any number of arguments. Arguments can be of any type, even other functions:\n\n```s\nsalamu = unda() {\n    andika(\"Habari yako\")\n}\n\nsalamu()\n\nsalamu = unda(jina) {\n    andika(\"Habari yako\", jina)\n}\n\nsalamu(\"asha\") // Habari yako asha\n```\n\n## Default Parameters\n\nFunctions can be provided with default parameters:\n\n```s\nsalimu = unda(salamu=\"Habari\") {\n    andika(salamu)\n}\n\nsalimu() // Habari\nsalimu(\"Mambo\") // Mambo\n```\n\n## Return (rudisha)\n\nYou can return values with the rudisha keyword. The rudisha keyword will terminate the block and return the value:\n\n```s\nmfano = unda(x) {\n    rudisha \"nimerudi\"\n    andika(x)\n}\n\nmfano(\"x\") // nimerudi\n```\n\n## Recursion\n\nNuru also supports recursion. Here's an example of a recursive Fibonacci function:\n\n```s\n\nfib = unda(n) {\n    kama (n <= 1) {\n        rudisha n\n    } sivyo {\n        rudisha fib(n-1) + fib(n-2)\n    }\n}\n\nandika(fib(10)) // 55\n```\n\nThe fib function calculates the nth Fibonacci number by recursively calling itself with n-1 and n-2 as arguments until n is less than or equal to 1.\n\n## Closures\n\nClosures are anonymous functions that can capture and store references to variables from their surrounding context. In Nuru, you can create closures using the unda keyword without assigning them to a variable. Here's an example:\n\n```s\nfanya jum = unda(x) {\n    rudisha unda(y) {\n        rudisha x + y\n    }\n}\n\nfanya jum_x = jum(5)\nandika(jum_x(3)) // 8\n```\n\nIn the example above, the jum function returns another function that takes a single parameter y. The returned function has access to the x variable from its surrounding context.\n\nNow that you understand the basics of functions in Nuru, including recursion and closures, you can create reusable blocks of code to simplify your programs and improve code organization."
  },
  {
    "path": "repl/docs/en/hisabati.md",
    "content": "# Module Hisabati\n\nModule Hisabati is a inbuilt math module by [VictorKariuki](https://github.com/VictorKariuki).\n\nThis in-built module provides various mathematical functions and constants. It includes methods for `trigonometric functions`, `logarithmic functions`, `array operations`, and `utility functions`.\n\n## Usage\n\nTo use the `hisabati` in-built module follow the steps below:\n\n1. You directly import the `hisabati` in-built module and any required in-built modules in your Nuru code using the `tumia` keyword.\n\n   ```nuru\n   tumia hisabati\n   ```\n\n2. Calling the in-built module methods:\n\n   ```nuru\n   andika(hisabati.e())\n   ```\n\n## Yaliyomo\n\nThis in-built module covers a wide range of mathematical operations, including :\n\n- `Basic Mathematical Functions:`\n- `Hyperbolic` & `Trigonometric Functions`\n- `Exponential` & `Logarithmic Functions`\n- `Rounding` & `Comparison Functions`\n\nHere is an in-depth classification of the methods:\n\n1. Trigonometric Functions:\n\n   - `cos(n)`\n   - `sin(n)`\n   - `tan(n)`\n   - `acos(n)`\n   - `asin(n)`\n   - `atan(n)`\n   - `hypot(numbers)`\n\n2. Hyperbolic Functions:\n\n   - `cosh(n)`\n   - `sinh(n)`\n   - `tanh(n)`\n   - `acosh(n)`\n   - `asinh(n)`\n   - `atanh(n)`\n\n3. Exponential and Logarithmic Functions:\n\n   - `exp(n)`\n   - `expm1(n)`\n   - `log(n)`\n   - `log2(n)`\n   - `log10(n)`\n   - `log1p(n)`\n\n4. Basic Mathematical Functions:\n\n   - `abs(n)`\n   - `sqrt(n)`\n   - `cbrt(n)`\n   - `root(x, n)`\n   - `factorial(n)`\n   - `sign(n)`\n\n5. Rounding and Comparison Functions:\n\n   - `ceil(n)`\n   - `floor(n)`\n   - `round(n)`\n   - `max(numbers)`\n   - `min(numbers)`\n\n### 1. Constants:\n\n- **PI**: Represents the mathematical constant `π`.\n- **e**: Represents `Euler's Number`.\n- **phi**: Represents the `Golden Ratio`.\n- **ln10**: Represents the `natural logarithm of 10`.\n- **ln2**: Represents the `natural logarithm of 2`.\n- **log10e**: Represents the `base 10 logarithms` of Euler's number `(e)`.\n- **log2e**: Represents the `base 2 logarithm` of Euler's number` (e)`.\n- **sqrt1_2**: Represents the `square root` of `1/2`.\n- **sqrt2**: Represents the `square root` of `2`.\n- **sqrt3**: Represents the `square root` of `3`.\n- **sqrt5**: Represents the `square root` of `5`.\n- **EPSILON**: Represents a small value `2.220446049250313e-16`.\n\n### 2. Methods:\n\n1. **abs(namba)**\n\n   - Description: Calculates the absolute value of a number.\n   - Example: `hisabati.abs(-42)` returns `42`.\n\n2. **acos(n)**\n\n   - Description: Calculates the arccosine of a number.\n   - Example: `hisabati.acos(0.5)` returns `1.0471975511965979`.\n\n3. **acosh(n)**\n\n   - Description: Calculates the inverse hyperbolic cosine of a number.\n   - Example: `hisabati.acosh(2.0)` returns `1.3169578969248166`.\n\n4. **asin(n)**\n\n   - Description: Calculates the arcsine of a number using the Taylor series.\n   - Example: `hisabati.arcsin(0.5)` returns `0.5235987755982988`.\n\n5. **asinh(n)**\n\n   - Description: Calculates the inverse hyperbolic sine of a number.\n   - Example: `hisabati.arsinh(2.0)` returns `1.4436354751788103`.\n\n6. **atan(n)**\n\n   - Description: Calculates the arctangent of a number using the Taylor series.\n   - Example: `hisabati.atan(1.0)` returns `0.7853981633974483`.\n\n7. **atan2(y, x)**\n\n   - Description: Calculates the arctangent of the quotient of its arguments.\n   - Example: `hisabati.atan2(1.0, 1.0)` returns `0.7853981633974483`.\n\n8. **atanh(n)**\n\n   - Description: Calculates the inverse hyperbolic tangent of a number.\n   - Example: `hisabati.atanh(0.5)` returns `0.5493061443340549`.\n\n9. **cbrt(n)**\n\n   - Description: Calculates the cube root of a number.\n   - Example: `hisabati.cbrt(8)` returns `2`.\n\n10. **root(x, n)**\n\n    - Description: Calculates the nth root of a number using the Newton-Raphson method.\n    - Example: `hisabati.root(27, 3)` returns `3`.\n\n11. **ceil(n)**\n\n    - Description: Rounds up to the smallest integer greater than or equal to a given number.\n    - Example: `hisabati.ceil(4.3)` returns `5`.\n\n12. **cos(n)**\n\n    - Description: Calculates the cosine of an angle in radians using the Taylor series.\n    - Example: `hisabati.cos(0.0)` returns `1`.\n\n13. **cosh(n)**\n\n    - Description: Calculates the hyperbolic cosine of a number.\n    - Example: `hisabati.cosh(0.0)` returns `1`.\n\n14. **exp(n)**\n\n    - Description: Calculates the value of Euler's number raised to the power of a given number.\n    - Example: `hisabati.exp(2.0)` returns `7.38905609893065`.\n\n15. **expm1(n)**\n\n    - Description: Calculates Euler's number raised to the power of a number minus 1.\n    - Example: `hisabati.expm1(1.0)` returns `1.718281828459045`.\n\n16. **floor(n)**\n\n    - Description: Rounds down to the largest integer less than or equal to a given number.\n    - Example: `hisabati.floor(4.7)` returns `4`.\n\n17. **hypot(values)**\n\n    - Description: Calculates the square root of the sum of squares of the given values.\n    - Example: `hisabati.hypot([3, 4])` returns `5`.\n\n18. **log(n)**\n\n    - Description: Calculates the natural logarithm of a number.\n    - Example: `hisabati.log(1.0)` returns `0`.\n\n19. **log10(n)**\n\n    - Description: Calculates the base 10 logarithm of a number.\n    - Example: `hisabati.log10(100.0)` returns `2`.\n\n20. **log1p(n)**\n\n    - Description: Calculates the natural logarithm of 1 plus the given number.\n    - Example: `hisabati.log1p(1.0)` returns `0.6931471805599453`.\n\n21. **log2(n)**\n\n    - Description: Calculates the base 2 logarithm of a number.\n    - Example: `hisabati.log2(8)` returns `3`.\n\n22. **max(numbers)**\n\n    - Description: Finds the maximum value in a list of numbers.\n    - Example: `hisabati.max([4, 2, 9, 5])` returns `9`.\n\n23. **min(numbers)**\n\n    - Description: Finds the minimum value in a list of numbers.\n    - Example: `hisabati.min([4, 2, 9, 5])` returns `2`.\n\n24. **round(x, method)**\n\n    - Description: Rounds a number to the nearest integer using the specified method.\n    - Example: `hisabati.round(4.6)` returns `5`.\n\n25. **sign(n)**\n\n    - Description: Determines the sign of a number.\n    - Example: `hisabati.sign(-5)` returns `-1`.\n\n26. **sin(n)**\n\n    - Description: Calculates the sine of an angle in radians using the Taylor series.\n    - Example: `hisabati.sin(1.0)` returns `0.8414709848078965`.\n\n27. **sinh(n)**\n\n    - Description: Calculates the hyperbolic sine of a number.\n    - Example: `hisabati.sinh(1.0)` returns `1.1752011936438014`.\n\n28. **sqrt(n)**\n\n    - Description: Calculates the square root of a number.\n    - Example: `hisabati.sqrt(4)` returns `2`.\n\n29. **tan(n)**\n\n    - Description: Calculates the tangent of an angle in radians.\n    - Example: `hisabati.tan(1.0)` returns `1.557407724654902`.\n\n30. **tanh(n)**\n\n    - Description: Calculates the hyperbolic tangent of a number.\n    - Example: `hisabati.tanh(1.0)` returns `0.7615941559557649`.\n\n31. **factorial(n)**\n\n    - Description: Calculates the factorial of a number.\n    - Example: `hisabati.factorial(5)` returns `120`.\n\n### Contributing\n\nContributions to the `module hisabati` are welcome. If you have any improvements or bug fixes, feel free to create a pull request.\n\n### License\n\nThis in-built module is available under the MIT License. See the [LICENSE](LICENSE) file for more information."
  },
  {
    "path": "repl/docs/en/identifiers.md",
    "content": "# Identifiers in Nuru\n\nIdentifiers are used to name variables, functions, and other elements in your Nuru code. This page covers the rules and best practices for creating identifiers in Nuru.\n\n## Syntax Rules\n\nIdentifiers can contain letters, numbers, and underscores. However, there are a few rules you must follow when creating identifiers:\n- Identifiers cannot start with a number.\n- Identifiers are case-sensitive. For example, myVar and myvar are considered distinct identifiers.\n\nHere are some examples of valid identifiers:\n\n```s\nfanya birth_year = 2020\nandika(birth_year) // 2020\n\nfanya convert_c_to_p = \"C to P\"\nandika(convert_c_to_p) // \"C to P\"\n```\n\nIn the examples above, birth_year and convert_c_to_p are both valid identifiers.\n\n## Best Practices\n\nWhen choosing identifiers, it's important to follow best practices to ensure your code is clear and easy to understand:\n\n- Use descriptive names that clearly indicate the purpose or meaning of the variable or function.\n- Follow a consistent naming convention, such as camelCase (myVariableName) or snake_case (my_variable_name).\n- Avoid using single-letter variable names, except for commonly accepted cases like loop counters (i, j, k).\n\nBy following these best practices when creating identifiers, you will make your Nuru code more readable and maintainable for yourself and others.\n"
  },
  {
    "path": "repl/docs/en/ifStatements.md",
    "content": "# Conditional Statements in Nuru\n\nConditional statements in Nuru are used to perform different actions based on different conditions. The if/else statement is a fundamental control structure that allows you to execute code based on specific conditions. This page covers the basics of if/else statements in Nuru.\n\n## If Statement (Kama)\n\nAn if statement starts with the kama keyword, followed by a condition in parentheses (). If the condition is true, the code inside the curly braces {} will be executed.\n\n```s\nkama (2 > 1) {\n    andika(kweli) // kweli\n}\n```\n\nIn this example, the condition 2 > 1 is true, so the andika(kweli) statement is executed, and the output is kweli.\n\n## Else If and Else Blocks (Au Kama and Sivyo)\n\nYou can use au kama to test multiple conditions and sivyo to specify a default block of code to be executed when none of the conditions are true.\n\n```s\n\nfanya a = 10\n\nkama (a > 100) {\n    andika(\"a imezidi 100\")\n} au kama (a < 10) {\n    andika(\"a ndogo kuliko 10\")\n} sivyo {\n    andika(\"Thamani ya a ni\", a)\n}\n\n// The output will be 'Thamani ya a ni 10'\n```\n\nIn this example, the first condition a > 100 is false, and the second condition a < 10 is also false. Therefore, the code inside the sivyo block is executed, and the output is 'Thamani ya a ni 10'.\n\nBy using if/else statements with the kama, au kama, and sivyo keywords, you can control the flow of your Nuru code based on different conditions."
  },
  {
    "path": "repl/docs/en/json.md",
    "content": "# JSON in Nuru\n\nNuru also makes it easy to deal with JSON.\n\n## Import JSONI\n\nUse the following to import the json module:\n```\ntumia jsoni\n```\n\n## Decoding JSON with dikodi()\nUse this to convert a string to a dictionary:\n```\njsonString = '{                                                                                                            \n    \"error\": false,                                                                                          \n    \"category\": \"Pun\",                                                                                       \n    \"type\": \"single\",                                                                                        \n    \"joke\": \"I was reading a great book about an immortal dog the other day. It was impossible to put down.\"\n}'\n\n// to make it a dict\n\ntumia jsoni\n\nk = jsoni.dikodi(jsonString)\n\nk[\"joke\"] // I was reading a great book about an immortal dog the other day. It was impossible to put down.\n```\n\n## Encoding JSON with enkodi()\n\nYou can encode JSON with the `enkodi` method, this will turn a dictionary to a string:\n```\ntumia jsoni\n\nk = {\n        \"a\": \"apple\",\n        \"b\": \"banana\"\n    }\n\nj = json.enkodi(k)\n```\n"
  },
  {
    "path": "repl/docs/en/keywords.md",
    "content": "# KEYWORDS\n\nKeywords in Nuru are reserved words that have special meanings and cannot be used as identifiers for variables, functions, or classes. This page covers the syntax and usage of keywords in Nuru, including reserved keywords and built-in functions.\n\n## Reserved Keywords\n\nThe table below lists the reserved keywords in Nuru. These words have specific meanings in the language and cannot be used as identifiers:\n\n<table style=\"display: inline-table; width: 100%; text-align: center\">\n<tbody>\n  <tr>\n    <td>kweli</td>\n    <td>sikweli</td>\n    <td>unda</td>\n    <td>fanya</td>\n  </tr>\n  <tr>\n    <td>kama</td>\n    <td>au</td>\n    <td>sivyo</td>\n    <td>wakati</td>\n  </tr>\n  <tr>\n    <td>rudisha</td>\n    <td>vunja</td>\n    <td>endelea</td>\n    <td>tupu</td>\n  </tr>\n  <tr>\n    <td>ktk</td>\n    <td>kwa</td>\n    <td>badili</td>\n    <td>ikiwa</td>\n  </tr>\n  <tr>\n    <td>kawaida</td>\n    <td></td>\n    <td></td>\n    <td></td>\n  </tr>\n</tbody>\n</table>\n\n## BuiltIns\n\nNuru also provides several built-in functions that are reserved and cannot be used as identifiers. These functions offer essential functionalities for common tasks in the language:\n\n<table style=\"display: inline-table; width: 100%; text-align: center\">\n<tbody>\n<tr>\n    <td>andika</td>\n    <td>aina</td>\n    <td>jaza</td>\n    <td>fungua</td>\n  </tr>\n</tbody>\n</table>\n\nUnderstanding the keywords and built-in functions in Nuru is essential for writing clear, concise, and error-free code. By respecting the reserved words and their specific meanings, you can create more robust and maintainable programs in Nuru."
  },
  {
    "path": "repl/docs/en/net.md",
    "content": "# HTTP with Nuru\n\nYou can access the internet via http protocol using the `mtandao` module.\n\n## Importing\n\nImport the module with:\n```\ntumia mtandao\n```\n\n## Methods\n\n### peruzi()\n\nUse this as GET method. It can either accept one positional argument which will be the URL:\n\n```\ntumia mtandao\n\nmtandao.peruzi(\"http://google.com\")\n```\n\nOr you can use keyword arguments to pass in parameters and headers as shown below. Note that headers and parameters must be a dictionary:\n\n```\ntumia mtandao\n\nurl = \"http://mysite.com\"\nheaders = {\"Authentication\": \"Bearer XXXX\"}\n\nmtandao.peruzi(yuareli=url, vichwa=headers, mwili=params)\n```\n\n### tuma()\n\nUse this as POST method. Use keyword arguments to pass in parameters and headers as shown below. Note that headers and parameters must be a dictionary:\n\n```\ntumia mtandao\n\nurl = \"http://mysite.com\"\nheaders = {\"Authentication\": \"Bearer XXXX\"}\nparams = {\"key\": \"Value\"}\n\nmtandao.tuma(yuareli=url, vichwa=headers, mwili=params)\n```\n"
  },
  {
    "path": "repl/docs/en/null.md",
    "content": "# Null (Tupu) in Nuru\n\nThe null data type in Nuru represents the absence of a value or the concept of \"nothing\" or \"empty.\" This page covers the syntax and usage of the null data type in Nuru, including its definition and evaluation.\n\n## Definition\n\nA null data type is a data type with no value, defined with the tupu keyword:\n\n```s\nfanya a = tupu\n```\n## Evaluation\n\nWhen evaluating a null data type in a conditional expression, it will evaluate to false:\n\n```s\nkama (a) {\n    andika(\"niko tupu\")\n} sivyo {\n    andika(\"nimevaa nguo\")\n}\n\n// Output: nimevaa nguo\n```\n\nThe null data type is useful in Nuru when you need to represent an uninitialized, missing, or undefined value in your programs. By understanding the null data type, you can create more robust and flexible code."
  },
  {
    "path": "repl/docs/en/numbers.md",
    "content": "# INTEGERS (NAMBA) AND FLOATS (DESIMALI)\n\nIntegers and floats are the basic numeric data types in Nuru, used for representing whole numbers and decimal numbers, respectively. This page covers the syntax and usage of integers and floats in Nuru, including precedence, unary increments, shorthand assignments, and negative numbers.\n\n## PRECEDENCE\n\nIntegers and floats behave as expected in mathematical operations, following the BODMAS rule:\n```go\n2 + 3 * 5 // 17\n\nfanya a = 2.5\nfanya b = 3/5\n\na + b // 2.8\n```\n\n## UNARY INCREMENTS\n\nYou can perform unary increments (++ and --) on both floats and integers. These will add or subtract 1 from the current value. Note that the float or int have to be assigned to a variable for this operation to work. Here's an example:\n\n```go\nfanya i = 2.4\n\ni++ // 3.4\n```\n\n## SHORTHAND ASSIGNMENT\n\nNuru supports shorthand assignments with +=, -=, /=, *=, and %=:\nYou\n```go\nfanya i = 2\n\ni *= 3 // 6\ni /= 2 // 3\ni += 100 // 103\ni -= 10 // 93\ni %= 90 // 3\n```\n\n## NEGATIVE NUMBERS\n\nNegative numbers also behave as expected:\n\n```go\nfanya i = -10\n\nwakati (i < 0) {\n    andika(i)\n    i++\n}\n\n```\nOutput:\n```s\n-10\n-9\n-8\n-7\n-6\n-5\n-4\n-3\n-2\n-1\n0\n1\n2\n3\n4\n5\n6\n7\n8\n9 \n```\n"
  },
  {
    "path": "repl/docs/en/operators.md",
    "content": "# OPERATORS\nOperators are the foundation of any programming language, allowing you to perform various operations on variables and values. This page covers the syntax and usage of operators in Nuru, including assignment, arithmetic, comparison, member, and logic operators.\n\n## ASSIGNMENT\n\nAssuming `i` and `v` are predefined variables, Nuru supports the following assignment operators:\n\n- `i = v`: which is the regular assignment operator\n- `i += v`: which is the equivalent of `i = i + v`\n- `i -= v`: which is the equivalent of `i = i - v`\n- `i *= v`: which is the equivalent of `i = i * v`\n- `i /= v`: which is the equivalent of `i = i / v`\n- `i += v`: which is the equivalent of `i = i + v`\n\nFor `strings`, `arrays` and `dictionaries`, the `+=` sign operator is permissible. Example:\n```\nlist1 += list2 // this is equivalent to list1 = list1 + list2\n```\n\n## ARITHMETIC OPERATORS\n\nNuru supports the following arithmetic operators:\n\n- `+`: Additon\n- `-`: Subtraction\n- `*`: Multiplication\n- `/`: Division\n- `%`: Modulo (ie the remainder of a division)\n- `**`: Exponential power (eg: `2**3 = 8`)\n\n## COMPARISON OPERATORS\n\nNuru supports the following comparison operators:\n\n- `==`: Equal to\n- `!=`: Not equal to\n- `>`: Greater than\n- `>=`: Greater than or equal to\n- `<`: Less than\n- `<=`: Less than or equal to\n\n## MEMBER OPERATOR\n\nThe member operator in Nuru is `ktk`. It will check if an object exists in another object:\n```go\nfanya majina = ['juma', 'asha', 'haruna']\n\n\"haruna\" ktk majina // kweli\n\"halima\" ktk majina // sikweli\n```\n\n## LOGIC OPERATORS\n\nNuru supports the following logic operators:\n\n- `&&`: Logical `AND`. It will evaluate to true if both are true, otherwise it will evaluate to false.\n- `||`: Logical `OR`. It will evaluate to false if both are false, otherwise it will evaluate to true.\n- `!`: Logical `NOT`. It will evaluate to the opposite of a given expression.\n\n## PRECEDENCE OF OPERATORS\n\nOperators have the following precedence, starting from the highest priority to the lowest:\n\n- `()` : Items in paranthesis have the highest priority\n- `!`: Negation\n- `%`: Modulo\n- `**`: Exponential power\n- `/, *`: Division and Multiplication\n- `+, +=, -, -=`: Addition and Subtraction\n- `>, >=, <, <=`: Comparison operators\n- `==, !=`: Equal or Not Equal to\n- `=`: Assignment Operator\n- `ktk`: Member Operator\n- `&&, ||`: Logical AND and OR\n\nUnderstanding operators in Nuru allows you to create complex expressions, perform calculations, and make decisions based on the values of variables.\n"
  },
  {
    "path": "repl/docs/en/packages.md",
    "content": "# Packages in Nuru\n\nYou can use third packages written in Nuru with the following conditions:\n\n- The package file MUST be in the same directory\n- The package file MUST end with `nr`\n- The package name and package file MUST have the same name (eg: if `pakeji hesabu` then the file name must be `hesabu.nr`)\n- The package must have the following structure:\n```\n// imports if any\n\npakeji [name of package] {\n        andaa = unda() { // the andaa function is mandatory even if its empty\n\n            }\n        [body of package]\n    }\n```\n- The package must be initialized with the `andaa` keyword (see above).\n\nThe `andaa` keyword is for initializing your package. This is also where you'd put your global variables. The global variables should be prefixed with `@.` Eg: `@.myGlobalVar`.\n\nA variable being globally available means that the variable can be accessed and manipulated by all other methods in the package.\n\n\nBelow is an example Sarufi package:\n```\n// import modules\ntumia mtandao\ntumia jsoni\n\n// package body\npakeji sarufi {\n\n        // initialize function\n        andaa = unda(file) {\n            config = fungua(file) // read passwords from json file\n            configString = config.soma()\n\n            configDict = jsoni.dikodi(configString) // convert it to a dict\n            clientID = configDict[\"client_id\"]\n            clientSecret = configDict[\"client_secret\"]\n\n            //  fill in params\n            params = {\"client_id\": clientID, \"client_secret\": clientSecret}\n\n            // get response\n            resp = mtandao.tuma(yuareli=\"https://api.sarufi.io/api/access_token\", mwili=params)\n            tokenDict = jsoni.dikodi(resp)\n\n            // extract token and make it globally available\n            @.token = tokenDict[\"access_token\"]\n\n            // make the \"Bearer <token>\" globally available\n            @.Auth = \"Bearer \" + @.token\n            }\n\n        // a method to get token\n        tokenYangu = unda() {\n                rudisha @.token\n            }\n\n        // a method to create new chatbots.\n        // the data should be a dict\n        tengenezaChatbot = unda(data) {\n                majibu = mtandao.tuma(yuareli=\"https://api.sarufi.io/chatbot\", vichwa={\"Authorization\": @.Auth}, mwili = data)\n                rudisha majibu\n            }\n\n        // a method to get all available chatbots\n        pataChatbotZote = unda() {\n                majibu = mtandao.peruzi(yuareli=\"https://api.sarufi.io/chatbots\", vichwa={\"Authorization\": @.Auth})\n                rudisha majibu\n            }\n    }\n```\n"
  },
  {
    "path": "repl/docs/en/range.md",
    "content": "## Range Function (mfululizo)\n\nThe `mfululizo` function generates a sequence of numbers. It can be used in loops or to create arrays of sequential numbers.\n\n### Syntax\n\n```go\nmfululizo(end)\nmfululizo(start, end)\nmfululizo(start, end, step)\n```\n\n### Parameters\n\n- `end`: The upper limit of the sequence (exclusive).\n- `start` (optional): The starting value of the sequence. Default is 0.\n- `step` (optional): The increment between each number in the sequence. Default is 1.\n\n### Return Value\n\nReturns an array of integers.\n\n### Examples\n\n```go\n// Generate numbers from 0 to 4\nkwa i katika mfululizo(5) {\n    andika(i)\n}\n// Output: 0 1 2 3 4\n\n// Generate numbers from 1 to 9\nkwa i katika mfululizo(1, 10) {\n    andika(i)\n}\n// Output: 1 2 3 4 5 6 7 8 9\n\n// Generate even numbers from 0 to 8\nkwa i katika mfululizo(0, 10, 2) {\n    andika(i)\n}\n// Output: 0 2 4 6 8\n\n// Generate numbers in reverse order\nkwa i katika mfululizo(10, 0, -1) {\n    andika(i)\n}\n// Output: 10 9 8 7 6 5 4 3 2 1\n```\n\n### Notes\n\n- The `end` value is exclusive, meaning the sequence will stop before reaching this value.\n- If a negative `step` is provided, `start` should be greater than `end`.\n- The `step` value cannot be zero.\n"
  },
  {
    "path": "repl/docs/en/strings.md",
    "content": "# Strings in Nuru\n\nStrings are a sequence of characters that can represent text in the Nuru programming language. This page covers the basics of strings, their manipulation, and some built-in methods.\n\n## Basic Syntax\n\nStrings can be enclosed in either single quotes '' or double quotes \"\":\n\n```s\nandika(\"mambo\") // mambo\n\nfanya a = 'niaje'\n\nandika(\"mambo\", a) // mambo niaje\n```\n\n## Concatenating Strings\n\nStrings can be concatenated using the + operator:\n\n```s\nfanya a = \"habari\" + \" \" + \"yako\"\n\nandika(a) // habari yako\n\nfanya b = \"habari\"\n\nb += \" yako\"\n\n// habari yako\n```\n\nYou can also repeat a string n number of times using the * operator:\n\n```s\nandika(\"mambo \" * 4)\n\n// mambo mambo mambo mambo\n\nfanya a = \"habari\"\n\na *= 4\n\n// habarihabarihabarihabari\n```\n\n## Looping over a String\n\nYou can loop through a string using the kwa keyword:\n\n```s\nfanya jina = \"avicenna\"\n\nkwa i ktk jina {andika(i)}\n```\nOutput\n```s \na\nv\ni\nc\ne\nn\nn\na  \n```\n\nAnd for key-value pairs:\n\n```s\nkwa i, v ktk jina {\n\tandika(i, \"=>\", v)\n}\n```\nOutput\n```s\n0 => a\n1 => v\n2 => i\n3 => c\n4 => e\n5 => n\n6 => n\n7 => a\n```\n\n## Comparing Strings\n\nYou can compare two strings using the == operator:\n\n```s\nfanya a = \"nuru\"\n\nandika(a == \"nuru\") // kweli\n\nandika(a == \"mambo\") // sikweli\n```\n\n## String Methods\n\n### idadi()\n\nYou can find the length of a string using the idadi method. It does not accept any parameters.\n\n```s\nfanya a = \"mambo\"\na.idadi() // 5\n```\n\n### herufikubwa()\n\nThis method converts a string to uppercase. It does not accept any parameters.\n\n```s\nfanya a = \"nuru\"\na.herufikubwa() // NURU\n```\n\n### herufindogo\n\nThis method converts a string to lowercase. It does not accept any parameters.\n\n```s\nfanya a = \"NURU\"\na.herufindogo() // nuru\n```\n\n### gawa\n\nThe gawa method splits a string into an array based on a specified delimiter. If no argument is provided, it will split the string according to whitespace.\n\nExample without a parameter:\n\n```s\nfanya a = \"nuru mambo habari\"\nfanya b = a.gawa()\nandika(b) // [\"nuru\", \"mambo\", \"habari\"]\n```\n\nExample with a parameter:\n\n```s\nfanya a = \"nuru,mambo,habari\"\nfanya b = a.gawa(\",\")\nandika(b) // [\"nuru\", \"mambo\", \"habari\"]\n```\n\nBy understanding strings and their manipulation in Nuru, you can effectively work with text data in your programs."
  },
  {
    "path": "repl/docs/en/switch.md",
    "content": "# Switch Statements in Nuru\n\nSwitch statements in Nuru allow you to execute different code blocks based on the value of a given expression. This page covers the basics of switch statements and their usage.\n\n## Basic Syntax\n\nYou initialize a switch statement with the badili keyword, the expression inside parentheses (), and all cases enclosed within curly braces {}.\n\nA case statement has the keyword ikiwa followed by a value to check. Multiple values can be in a single case separated by commas ,. The consequence to execute if a condition is fulfilled must be inside curly braces {}. Here's an example:\n\n```s\nfanya a = 2\n\nbadili (a){\n\tikiwa 3 {\n\t\tandika(\"a ni tatu\")\n\t}\n\tikiwa 2 {\n\t\tandika (\"a ni mbili\")\n\t}\n}\n```\n\n## Multiple Values in a Case\n\nMultiple possibilities can be assigned to a single case (ikiwa) statement:\n\n```s\nbadili (a) {\n\tikiwa 1,2,3 {\n\t\tandika(\"a ni kati ya 1, 2 au 3\")\n\t}\n\tikiwa 4 {\n\t\tandika(\"a ni 4\")\n\t}\n}\n```\n\n## Default Case (kawaida)\n\nThe default statement will be executed when no condition is satisfied. The default statement is represented by kawaida:\n\n```s\nfanya z = 20\n\nbadili(z) {\n\tikiwa 10 {\n\t\tandika(\"kumi\")\n\t}\n\tikiwa 30 {\n\t\tandika(\"thelathini\")\n\t}\n\tkawaida {\n\t\tandika(\"ishirini\")\n\t}\n}\n```\n\nBy understanding switch statements in Nuru, you can create more efficient and organized code that can handle multiple conditions easily."
  },
  {
    "path": "repl/docs/en/time.md",
    "content": "# Time in Nuru\n\n## Importing Time\n\nTo use Time in Nuru, you first have to import the `muda` module as follows:\n\n```so\ntumia muda\n```\n\n---\n\n## Time Methods\n\n### `hasahivi()`\n\nTo get the current time, use `muda.hasahivi()`. It returns a `muda` object with the current time in the format `HH:mm:ss dd-MM-YYYY`.\n\n```so\ntumia muda\n\nsaivi = muda.hasahivi()\n```\n\n---\n\n### `leo()`\n\nTo get today’s date in the format `dd-MM-YYYY`:\n\n```so\ntumia muda\n\nleo = muda.leo()\n```\n\n---\n\n### `tangu(time)`\n\nGets the total time elapsed **in seconds** from the given time to now. Accepts a `muda` object or string in `HH:mm:ss dd-MM-YYYY` format.\n\n```so\ntumia muda\n\nmuda_ulioyopita = muda.tangu(\"15:00:00 01-01-2024\")\n```\n\n---\n\n### `lala(sekunde)`\n\nPauses the program for the given number of seconds:\n\n```so\ntumia muda\n\nmuda.lala(5) // sleeps for 5 seconds\n```\n\n---\n\n### `baada_ya(sekunde)`\n\nReturns a `muda` object representing the time after the given number of seconds from now.\n\n```so\ntumia muda\n\nbaadaye = muda.baada_ya(60) // one minute from now\n```\n\n---\n\n### `tofauti(muda1, muda2)`\n\nReturns the difference between two time values in seconds.\n\n```so\ntumia muda\n\nsaa1 = muda.hasahivi()\nsaa2 = muda.baada_ya(30)\n\ntofauti = muda.tofauti(saa2, saa1) // 30\n```\n\n---\n\n### `ongeza(...)`\n\nTo add time to a `muda` object. You must specify at least one of the following fields `sekunde`, `dakika`, `masaa`, `siku`, `wiki`, `miezi`, `miaka`.\n\nExample:\n\n```so\ntumia muda\n\nsasa = muda.hasahivi()\nkesho = sasa.ongeza(siku=1)\nmwakani = sasa.ongeza(miaka=1)\n```\n"
  },
  {
    "path": "repl/docs/en/while.md",
    "content": "# WHILE (WAKATI)\n\nWhile loops in Nuru are used to execute a block of code repeatedly, as long as a given condition is true. This page covers the basics of while loops, including how to use the break and continue keywords within them.\n\n## Basic Syntax\n\nA while loop is executed when a specified condition is true. You initiliaze a while loop with the `wakati` keyword followed by the condition in paranthesis  `()`. The consequence of the loop should be enclosed in brackets `{}`:\n```s\nfanya i = 1\n\nwakati (i <= 5) {\n\tandika(i)\n\ti++\n}\n```\nOutput\n```s\n1\n2\n3\n4\n5\n```\n\n## Break (vunja) and Continue (endelea)\n### Break (Vunja)\n\nUse the vunja keyword to terminate a loop:\n\n```s\nfanya i = 1\n\nwakati (i < 5) {\n\tkama (i == 3) {\n\t\tandika(\"nimevunja\")\n\t\tvunja\n\t}\n\tandika(i)\n\ti++\n}\n```\nOutput\n```s\n1\n2\nnimevunja\n```\n\n### Continue (Endelea)\n\nUse the endelea keyword to skip a specific iteration:\n\n```s\nfanya i = 0\n\nwakati (i < 5) {\n\ti++\n\tkama (i == 3) {\n\t\tandika(\"nimeruka\")\n\t\tendelea\n\t}\n\tandika(i)\n}\n```\nOutput\n```s\n1\n2\nnimeruka\n4\n5\n```\n\nBy understanding while loops in Nuru, you can create code that repeats a specific action or checks for certain conditions, offering more flexibility and control over your code execution."
  },
  {
    "path": "repl/docs/sw/README.md",
    "content": "# NYARAKA YA LUGHA YA PROGRAMU YA NURU\n\nHii nyaraka imeandikwa ikilenga watu wenye uzoefu na kuandika au kupanga programu. Inaelezea sintaksia, aina na namna ya kufanya operesheni mbali mbali kutumia lugha ya NURU.\n\n## Yaliyomo\n\n- [Safu Kwenye Nuru](arrays.md#arrays-in-nuru)\n    - [Kutengeneza Safu](arrays.md#creating-arrays)\n    - [Kupata na Kurekebisha vipengele vya Safu](arrays.md#accessing-and-modifying-array-elements)\n    - [Kuunganisha Safu](arrays.md#concatenating-arrays)\n    - [Kuangalia uwepo wa vipengele ndani ya safu](arrays.md#checking-for-array-membership)\n    - [Kupita na Kurejea kwenye safu](arrays.md#looping-over-arrays)\n    - [Mbinu za Safu](arrays.md#array-methods)\n        - [idadi()](arrays.md#idadi())\n        - [sukuma()](arrays.md#sukuma())\n        - [yamwisho()](arrays.md#yamwisho())\n- [Visaidia-kazi vya Nuru](builtins.md#built-in-functions-in-nuru)\n    - [Kisaidia-kazi andika() ](builtins.md#the-andika()-function)\n    - [Kisaidia-kazi jaza()](builtins.md#the-jaza()-function)\n    - [Kisaidia-kazi aina()](builtins.md#the-aina()-function)\n    - [Kisaidia-kazi fungua()](builtins.md#the-fungua()-function)\n- [Maoni kwenye Nuru](comments.md#comments-in-nuru)\n    - [Maoni ya mstari mmoja](comments.md#single-line-comments)\n    - [Maoni ya mistari mingi](comments.md#multi-line-comments)\n- [Kauli za masharti kwenye Nuru](ifStatements.md#conditional-statements-in-nuru)\n    - [Kauli ya kama](ifStatements.md#if-statement-(kama))\n    - [Kauli za Au Kama na Sivyo)](ifStatements.md#else-if-and-else-blocks-(au-kama-and-sivyo))"
  },
  {
    "path": "repl/docs/sw/arrays.md",
    "content": "# Orodha Au Safu Katika Nuru\n\nSafu katika nuru ni miundo ya data ambayo inaweza kubeba vitu vingi, ikiwa ni pamoja na aina za data tofauti tofauti kama `namba`, `tungo`, `buliani`, `vitendakazi`, na thamani `tupu`. Ukurasa huu unaangazia vipengele mbalimbali vya safu, ikiwemo namna ya kutengeneza, kuchambua, na kuzunguka ndani yake kwa kutumia vitendakazi vilivyojengwa ndani ya Nuru.\n\n## Kutengeneza Safu\n\nKutengeneza safu, tumia mabano mraba na tenganisha kila kitu kimoja kwa kutumia mkwaju:\n\n```s\norodha = [1, \"pili\", kweli]\n```\n\n## Kupata na Kubadilisha Vipengele vya Safu\n\nSafu katika Nuru ni zero-indexed; ikimaanisha kipengele cha kwanza katika safu kina kumbukumbu namba 0. Kupata kipengele, unaweza ukatumia kumbukumbu namba yake ndani ya mabano mraba:\n\n```s\nnamba = [10, 20, 30]\njina = namba[1]  // jina is 20\n```\n\nUnaweza ukabadilisha kipengele katika safu kwa kutumia kumbukumbu namba yake:\n\n```s\nnamba = [10, 20, 30]\nnamba[1] = 25\nandika(namba)  // Tokeo: [10,25,30]\n```\n\n## Kuunganisha Safu\n\nKuunganisha safu mbili au zaidi, tumia kiendeshi `+`:\n\n```s\na = [1, 2, 3]\nb = [4, 5, 6]\nc = a + b\n// c is now [1, 2, 3, 4, 5, 6]\n```\n\n## Kuangalia Uanachama Katika Safu\n\nTumia neno msingi `ktk` kuangalia kama kipengele kipo ndani ya safu:\n\n```s\nnamba = [10, 20, 30]\nandika(20 ktk namba)  // Tokeo: kweli\n```\n\n## Kuzunguka Ndani ya Safu\n\nUnaweza kutumia maneno msingi `kwa` na `ktk` kuzunguka ndani ya safu. Kuzunguka ndani ya safu na kupata kipengele peke yake tumia sintaksia ifuatayo:\n\n```s\nnamba = [1, 2, 3, 4, 5]\n\nkwa thamani ktk namba {\n    andika(thamani)\n}\n\n//Tokeo:\n1\n2\n3\n4\n5\n```\n\nKuzunguka ndani ya safu na kupata kumbukumbu namba na kipengele tumia sintaksi aifuatayo:\n\n```s\nmajina = [\"Juma\", \"Asha\", \"Haruna\"]\n\nkwa idx, jina ktk majina {\n    andika(idx, \"-\", jina)\n}\n\n//Tokeo:\n0-Juma\n1-Asha\n2-Haruna\n```\n\n## Vitendakazi vya Safu\n\nNuru ina vitendakazi mbalimbali vilivyojengwa ndani kwa ajili ya Safu:\n\n### idadi()\n\n`idadi()` hurudisha urefu wa safu:\n\n```s\na = [1, 2, 3]\nurefu = a.idadi()\nandika(urefu)  // Tokeo: 3\n```\n\n### sukuma()\n\n`sukuma()` huongeza kipengele kimoja au zaidi mwishoni mwa safu:\n\n```s\na = [1, 2, 3]\na.sukuma(\"s\", \"g\")\nandika(a)  // Tokeo [1, 2, 3, \"s\", \"g\"]\n```\n\n### yamwisho()\n\n`yamwisho()` hurudisha kipengele cha mwisho katika safu, au `tupu` kama safu haina kitu:\n\n```s\na = [1, 2, 3]\nmwisho = a.yamwisho()\nandika(mwisho)  // Tokeo: 3\n\nb = []\nmwisho = b.yamwisho()\nandika(mwisho)  // Tokeo: tupu\n```\n\nKwa kutumia taarifa hii, unaweza ukafanyakazi na safu za Nuru kwa ufanisi, kufanya iwe rahisi kuchambua mikusanyo ya data katika programu zako.\n"
  },
  {
    "path": "repl/docs/sw/bools.md",
    "content": "# Kufanya Kazi na Buliani Katika Nuru\n\nVitu vyote katika Nuru ni kweli, yaani thamani yoyote ni kweli isipokua tupu and sikweli. Hutumika kutathmini semi ambazo zinarudisha kweli au sikweli.\n\n## Kutathmini Semi za Buliani\n\n### Kutathmini Semi Rahisi\n\nKatika Nuru, unaweza kutathmini semi rahisi zinazorudisha thamani ya buliani:\n\n```go\nandika(1 > 2) // Matokeo: `sikweli`\n\nandika(1 + 3 < 10) // Matokeo: `kweli`\n```\n\n### Kutathmini Semi Tata\n\nKatika Nuru, unaweza kutumia viendeshaji vya buliani kutathmini semi tata:\n\n```go\na = 5\nb = 10\nc = 15\n\ntokeo = (a < b) && (b < c)\n\nkama (tokeo) {\n    andika(\"Hali zote mbili ni kweli\")\n} sivyo {\n    andika(\"Angalau hali moja ni sikweli\")\n}\n// Tokeo: \"Hali zote mbili ni kweli\"\n```\n\nHapa tumetengeneza vibadilika vitatu a,b,c. Kisha tukatathmini semi (a < b) && (b < c). Kwa sababu semi zote mbili ni kweli, tokeo litakua \"Hali zote mbili ni kweli\".\n\n## Vitendakazi vya Buliani\n\nNuru ina vitendakazi vya buliani kadhaa ambavyo unaweza ukatumia kutathmini semi:\n\n### Kitendakazi `&&`\n\nKitendakazi `&&` hutathmini kwenda kweli kama tu vitu vyote vinavyohusika ni kweli. Kwa mfano:\n\n```go\nandika(kweli && kweli) // Tokeo: `kweli`\n\nandika(kweli && sikweli) // Tokeo: `sikweli`\n```\n\n### Kitendakazi `||`\n\nKitendakazi || hutathmini kwenda kweli kama angalau kitu kimoja kati ya vyote vinavyohusika ni kweli. Kwa mfano:\n\n```go\nandika(kweli || sikweli) // Tokeo: `kweli`\n\nandika(sikweli || sikweli) // Tokeo: `sikweli`\n```\n\n### Kitendakazi `!`\n\nKitendakazi `!` hukanusha thamani ya kitu. Kwa mfano:\n\n```go\nandika(!kweli) // Tokeo: `sikweli`\n\nandika(!sikweli) // Tokeo: `kweli`\n```\n\n## Kufanya Kazi na Thamani za Buliani Katika Vitanzi\n\nKatika Nuru, unaweza ukatumia semi za buliani katika vitanzi kuendesha tabia zake. Kwa mfano:\n\n```go\nnamba = [1, 2, 3, 4, 5]\n\nkwa thamani ktk namba {\n    kama (thamani % 2 == 0) {\n        andika(thamani, \" ni namba shufwa\")\n    } sivyo {\n        andika(thamani, \" ni namba witiri\")\n    }\n}\n\n// Output:\n// 1 ni namba witiri\n// 2 ni namba shufwa\n// 3 ni namba witiri\n// 4 ni namba shufwa\n// 5 ni namba witiri\n```\n\nHapa , tumetengeneza safu yenye namba 1 hadi 5 kisha tukazunguka ndani ya safu hiyo na kwa kila namba tukatumia kitendakazi `%` ilikubaini kama namba ni shufwa au witiri. Matokeo yatakua ni \"ni namba shufwa\" kwa namba shufwa na \"ni namba witiri\" kwa namba witiri.\n\nVitu buliani katika Nuru vinaweza kutumika kutathmini semi ambazo zinarudisha thamani ya kweli au sikweli. Unaweza kutumia vitendakazi vya buliani kutathmini semi tata na kuendesha tabia ya vitanzi. Kuelewa namna ya kufanya kazi na thamani za buliani ni ujuzi wamsingi kwa mtengenezaji programu yeyote wa Nuru.\n"
  },
  {
    "path": "repl/docs/sw/builtins.md",
    "content": "# Vitendakazi Vilivyojengwa Ndani ya Nuru\n\nNuru ina vitendakazi kadhaa vilivyojengwa ndani vinavyofanya kazi husika.\n\n## Kitendakazi andika()\n\nKitendakazi `andika()` kinatumika kuchapisha ujumbe kwenye konsoli. Inawezakuchukua hoja sifuri au zaidi, na hoja zitachapishwa na nafasi kati yao. Kwa kuongeza, `andika()` huhimili uundaji wa msingi kama vile `/n` kwa ajili ya mstari mpya, `/t` kwa ajili ya nafasi ya kichupo, na `\\\\` kwa ajili ya mkwajunyuma. Mfano:\n\n```go\nandika(1, 2, 3) // Output: 1 2 3\n```\n\n```go\nandika(\"Jina: Asha /n Umri: 20 /n Chuo: IFM\")\n\n// Output:\n// Jina: Asha\n// Umri: 20\n// Chuo: IFM\n```\n\n## Kitendakazi jaza()\n\nKitendakazi `jaza()` kinatumika kupata ingizo kutoka kwa mtumiaji. Inawezakuchukua hoja sifuri au moja, ambayo ni utungo utakao tumika kama kimahasishi kwa mtumiaji. Mfano:\n\n```go\nfanya salamu = unda() {\n    fanya jina = jaza(\"Unaitwa nani? \")\n    andika(\"Mambo vipi\", jina)\n}\n\nsalamu()\n```\n\nKatika mfano huu, tunaainisha kitendakazi `salamu()` ambacho kinamhamasisha mtumiaji kuingiza jina kwa kutumia kitendakazi `jaza()`. Kisha tunatumia kitendakazi `andika()` kuchapisha ujumbe unaobeba jina la mtumiaji aliloingiza.\n\n## Kitendakazi aina()\n\nKitendakazi `aina()` kinatumika kutambua aina ya kitu. Inakubali hoja moja, na thamani inayorudi hua ni utungo unaoonyesha aina ya kitu. Mfano:\n\n```go\naina(2) // Output: \"NAMBA\"\naina(\"Nuru\") // Output: \"NENO\"\n```\n\n## Kitendakazi fungua()\n\nKitendakazi `fungua()` kinatumika kufungua faili. Inakubali hoja moja, ambayo ni njia ya faili unalotaka kufungua. Mfano:\n\n```go\nfaili = fungua(\"data.txt\")\n```\n\nKatika mfano huu, tumetumia kitendakazi `fungua()` kufungua faili linaloitwa \"data.txt\". Kibadilika `faili` kinabeba kumbukumbu ya faili lililofunguliwa.\n"
  },
  {
    "path": "repl/docs/sw/dictionaries.md",
    "content": "# Kamusi Katika Nuru\n\nKamusi katika Nuru ni miundo ya data inayotunza jozi za funguo-thamani. Ukurasa huu unatoa maelezo kuhusu Kamusi katika Nuru, ikiwemo namna ya kutengeneza, namna ya kubadilisha, na namna ya kuzunguka ndani yake.\n\n## Kutengeneza Kamusi\n\nKamusi zinawekwa kwenye mabano singasinga na hujumuisha funguo na thamani zake zikitenganishwa na nukta pacha. Mfano wa uainishwaji wa kamusi:\n\n```go\n\norodha = {\"jina\": \"Juma\", \"umri\": 25}\n```\n\nFunguo zinawezakua tungo, namba, desimali, au buliani na thamani inaweza kua aina ya data yoyote ikiwemo tungo, namba, desimali, buliani, tupu, au kitendakazi:\n\n```go\nk = {\n    \"jina\": \"Juma\",\n    \"umri\": 25,\n    kweli: \"kweli\",\n    \"salimu\": unda(x) { andika(\"habari\", x) },\n    \"sina thamani\": tupu\n}\n```\n\n## Kupata Vipengele\n\nUnaweza kupata vipengele vya kamusi kwa kutumia funguo zake:\n\n```go\nk = {\n    \"jina\": \"Juma\",\n    \"umri\": 25,\n    kweli: \"kweli\",\n    \"salimu\": unda(x) { andika(\"habari\", x) },\n    \"sina thamani\": tupu\n}\n\nandika(k[kweli]) // kweli\nandika(k[\"salimu\"](\"Juma\")) // habari Juma\n```\n\n## Kuboresha Vipengele\n\nBoresha thamani ya kipengele kwa kukipa thamani mpya kwenye funguo yake:\n\n```go\nk = {\n    \"jina\": \"Juma\",\n    \"umri\": 25,\n    kweli: \"kweli\",\n    \"salimu\": unda(x) { andika(\"habari\", x) },\n    \"sina thamani\": tupu\n}\n\nk['umri'] = 30\nandika(k['umri']) // 30\n```\n\n## Kuongeza Vipengele Vipya\n\nOngeza jozi mpya ya funguo-thamani kwenye kamusi kwa kuipa thamani funguo ambayo haipo kwenye kamusi husika:\n\n```go\nk[\"lugha\"] = \"Kiswahili\"\nandika(k[\"lugha\"]) // Kiswahili\n```\n\n## Kuunganisha Kamusi\n\nUnganisha kamusi mbili kwa kutumia kiendeshi `+`:\n\n```go\nmatunda = {\"a\": \"apple\", \"b\": \"banana\"}\nmboga = {\"c\": \"tembele\", \"d\": \"mchicha\"}\nvyakula = matunda + mboga\nandika(vyakula) // {\"a\": \"apple\", \"b\": \"banana\", \"c\": \"tembele\", \"d\": \"mchicha\"}\n```\n\n## Angalia Kama Funguo Ipo Kwenye Kamusi\n\nTumia neno msingi `ktk` kuangalia kama funguo ipo kwenye kamusi:\n\n```go\n\nk = {\n    \"jina\": \"Juma\",\n    \"umri\": 25,\n    kweli: \"kweli\",\n    \"salimu\": unda(x) { andika(\"habari\", x) },\n    \"sina thamani\": tupu\n}\n\n\"umri\" ktk k // kweli\n\"urefu\" ktk k // sikweli\n```\n\n## Kuzunguka Ndani Ya Kamusi\n\nZunguka ndani ya kamusi kupata funguo na thamani zake:\n\n```go\n\nhobby = {\"a\": \"kulala\", \"b\": \"kucheza mpira\", \"c\": \"kuimba\"}\n\nkwa i, v ktk hobby {\n    andika(i, \"=>\", v)\n}\n\n//Output\n\na => kulala\nb => kucheza mpira\nc => kuimba\n```\n\nKuzunguka ndani ya kamusi na kupata thamani peke yake:\n\n```go\n\nhobby = {\"a\": \"kulala\", \"b\": \"kucheza mpira\", \"c\": \"kuimba\"}\n\nkwa i, v ktk hobby {\n    andika(i, \"=>\", v)\n}\n\n//Output\n\nkulala\nkucheza mpira\nkuimba\n```\n\nKwa ufahamu huu, unaweza ukatumia kamusi kikamilifu katika Nuru kutunza na kusimamia jozi za funguo-thamani, na kupata namna nyumbufu ya kupangilia na kupata data katika programu zako.\n"
  },
  {
    "path": "repl/docs/sw/for.md",
    "content": "# Vitanzi Vya Kwa Katika Nuru\n\nVitanzi vya `kwa` ni muundo msingi wa udhibiti katika Nuru ambavyo hutumika kuzunguka vitu vinavyozungukika kama tungo, safu, na kamusi. Ukurasahuu unaangazia sintaksia na matumizi ya Vitanzi katika Nuru, ikiwemo kuzunguka ndani ya jozi ya funguo-thamani, na matumizi ya matamshi `vunja` na `endelea`.\n\n## Sintaksia\n\nKutengeneza kitanzi cha `kwa`, tumia neno msingi `kwa` likifwatiwa na kitambulishi cha muda mfupi kama vile `i` au `v` na kitu kinachozungukika. Funga mwili wa kitanzi na mabano singasinga `{}`. Mfano unaotumia tungo:\n\n```go\njina = \"lugano\"\n\nkwa i ktk jina {\n    andika(i)\n}\n\n// Tokeo:\nl\nu\ng\na\nn\no\n```\n\n## Kuzunguka Ndani ya Jozi ya Funguo-Thamani\n\n### Kamusi\n\nNuru inakuruhusu kuzunguka ndani ya kamusi kupata thamani moja moja au jozi ya funguo na thamani yake. Kupata tu thamani, tumia kitambulisha cha muda mfupi:\n\n```go\nkamusi = {\"a\": \"andaa\", \"b\": \"baba\"}\n\nkwa v ktk kamusi {\n    andika(v)\n}\n\n// Tokeo:\n\nandaa\nbaba\n```\n\nKupata thamani ya funguo na thamani zake, tumia vitambulishi vya muda mfupi viwili:\n\n```go\n\nkwa k, v ktk kamusi {\n    andika(k + \" ni \" + v)\n}\n\n// Tokeo:\n\na ni andaa\nb ni baba\n```\n\n### Tungo\n\nKuzunguka juu ya thamani za tungo, tumia kitambulishi cha muda mfupi:\n\n```go\nkwa v ktk \"mojo\" {\n    andika(v)\n}\n\n// Tokeo:\n\nm\no\nj\no\n```\n\nKuzunguka juu ya funguo na thamani zake, tumia vitambulishi vya muda mfupi viwili:\n\n```go\nkwa i, v ktk \"mojo\" {\n    andika(i, \"->\", v)\n}\n\n// Tokeo:\n\n0 -> m\n1 -> o\n2 -> j\n3 -> o\n```\n\n### Safu\n\nKuzunguka juu ya thamani za safu, tumia kitambulishi cha muda mfupi:\n\n```go\nmajina = [\"juma\", \"asha\", \"haruna\"]\n\nkwa v ktk majina {\n    andika(v)\n}\n\n// Tokeo:\n\njuma\nasha\nharuna\n```\n\nKuzunguka juu ya funguo na thamani katika safy, tumia vitambulishi vya muda mfupi viwili:\n\n```go\nkwa i, v ktk majina {\n    andika(i, \"-\", v)\n}\n\n// Tokeo:\n\n0 - juma\n1 - asha\n2 - haruna\n```\n\n## Vunja na Endelea\n\n### Vunja\n\nTumia neno msingi `vunja` kisitisha kitanzi:\n\n```go\n\nkwa i, v ktk \"mojo\" {\n    kama (i == 2) {\n        andika(\"nimevunja\")\n        vunja\n    }\n    andika(v)\n}\n\n// Tokeo:\n\nm\no\nj\nnimevunja\n\n```\n\n### Endelea\n\nTumia neno msingi `endelea` kuruka mzunguko maalum:\n\n```go\nkwa i, v ktk \"mojo\" {\n    kama (i == 2) {\n        andika(\"nimeruka\")\n        endelea\n    }\n    andika(v)\n}\n\n// Tokeo:\n\nm\no\nnimeruka\no\n```\n"
  },
  {
    "path": "repl/docs/sw/functions.md",
    "content": "# Undo (Functions)\n\nVitendakazi ni sehemu ya msingi ya Nuru inayokuwezesha kuainisha mapande ya msimbo yanayoweza kutumika tena. Ukurasa huu unaainisha sintaksia na matumizi ya vitendakazi katika nuru ikiwemo vipengele, vipengele vya msingi, matamshi ya kurudisha, kujirudia, na vifungizi.\n\n## Sintaksia\n\nPande la kitendakazi huanza na neno msingi `unda` likifuatiwa na vipengele vinavyowekwa ndani ya mabano `()` na mwili unaowekwa ndani ya mabano singasinga `{}`. Vitendakazi lazima viwekwe kwenye kibadiliki:\n\n```go\njumla = unda(x, y) {\n    rudisha x + y\n}\n\njumla(2, 3) // 5\n```\n\n## Vipengele\n\nVitendakazi vinawezakuwa nazifuri au idadi yoyote ya vipengele. Vipengele vinawezakua vya aina yoyote hata vitendakazi vingine:\n\n```go\nsalamu = unda(jina) {\n    andika(\"Habari yako\", jina)\n}\n\nsalamu(\"asha\") // Habari yako asha\n```\n\n## Vipengele Vya Msingi\n\nVitendakazi vinawezakupewa vipengele vya msingi:\n\n```go\nsalimu = unda(salamu=\"Habari\") {\n    andika(salamu)\n}\n\nsalimu() // Habari\nsalimu(\"Mambo\") // Mambo\n```\n\n## Rudisha\n\nUnaweza pia ukarudisha thamani kwa kutumia neno msingi `rudisha`. Neno msingi `rudisha` husitisha pande la msimbo na kurudisha thamani:\n\n```go\nmfano = unda(x) {\n    rudisha \"nimerudi\"\n    andika(x)\n}\n\nmfano(\"x\") // nimerudi\n```\n\n## Kujirudia\n\nNuru pia inahimili kujirudia. Mfano wa kujirudia kwa kitendakazi cha Fibonacci:\n\n```go\n\nfib = unda(n) {\n    kama (n <= 1) {\n        rudisha n\n    } sivyo {\n        rudisha fib(n-1) + fib(n-2)\n    }\n}\n\nandika(fib(10)) // 55\n```\n\nKitendakazi fib kinakokotoa namba ya Fibonacci ya n kwa kujiita yenyewe ikiwa na n-1 na n-2 kama vipengele mpaka ambapo n ni ndogo kuliko au sawa na moja.\n\n## Vifungizi\n\nVifungizi ni vitendakazi visivyo na jina ambayo vinaweza kudaka na kuhifadhi marejeo ya vibadilika kutoka katika muktadha unaovizunguka. Katika Nuru, unaweza kutengeneza vifungizi kwa kutumia neno msingin `unda` bila kuiweka kwenye kibadiliki. Mfano:\n\n```go\nfanya jum = unda(x) {\n    rudisha unda(y) {\n        rudisha x + y\n    }\n}\n\nfanya jum_x = jum(5)\nandika(jum_x(3)) // 8\n```\n\nKatika mfano hapo juu, kitendakazi `jum` kinarudisha kitendakazi kingine ambacho kinabeba kipengele kimoja tu `y`. Kitendakazi kinachorudisha kinawezakupata kibadiliki x kutoka katika muktadha unaokizunguka.\n\nSasa umeshaelewa misingi ya vitendakazi katika Nuru, ikiwemo kujirudia na vifungizi, unaweza ukatengeneza mapande ya msimbo yanayoweza kutumika tena na tena na kurahisisha programu zako na kuboresha mpangilio wa msimbo wako.\n"
  },
  {
    "path": "repl/docs/sw/identifiers.md",
    "content": "# Vitambulisho katika Nuru\n\nVitambulisho hutumika kuweka majina kwenye vigezo, vitendakazi na vipengele vingine katika msimbo wako wa Nuru. Ukurasa huu unashughulikia sheria na mbinu bora za kuunda vitambulisho katika Nuru.\n\n## Sheria za Sintaksia\n\nVitambulisho vinaweza kuwa na herufi, nambari na nistari wa chini `_`. Walakini, kuna sheria chache ambazo unapaswa kufuata wakati wa kuunda vitambulisho:\n\n- Vitambulisho haviwezi kuanza na nambari.\n- Vitambulisho huwa na tofauti kulingana na matumizi ya herufi kubwa na ndogo. Kwa mfano, `kibadilikaChangu` na `kibadilikachangu` huchukuliwa kuwa vitambulisho tofauti.\n\nHapa kuna mifano ya vitambulisho halali:\n\n```go\nfanya mwaka_wa_kuzaliwa = 2020\nandika(mwaka_wa_kuzaliwa) // 2020\n\nfanya badili_c_kwenda_p = \"C kwenda P\"\nandika(badili_c_kwenda_p) // \"C kwenda P\"\n```\n\nKatika mifano iliyo hapo juu, mwaka_wa_kuzaliwa na badili_c_kwenda_p zote ni vitambulisho halali.\n\n## Mazoea Bora\n\nWakati wa kuchagua vitambulisho, ni muhimu kufuata mazoea bora ili kuhakikisha kuwa msimbo wako uko wazi na rahisi kueleweka:\n\n- Tumia majina yanayoelezea wazi kusudi au maana ya kigezo au kitendakazi.\n- Fuata kanuni thabiti ya kuweka majina, kama vile camelCase (kibadilikaChangu) au snake_case (kibadilika_changu).\n- Epuka kutumia majina tofauti ya herufi moja, isipokuwa kwa vijisehemu vinavyokubalika kwa kawaida kama vile vihesabu vitanzi (i, j, k).\n\nKwa kufuata mbinu bora hizi unapounda vitambulisho, utafanya code yako ya Nuru iwe rahisi kusoma na kutunza kwa wewe na wengine.\n"
  },
  {
    "path": "repl/docs/sw/if.md",
    "content": "# Kama/Sivyo (If/Else)"
  },
  {
    "path": "repl/docs/sw/keywords.md",
    "content": "# Maneno Muhimu (Keywords)"
  },
  {
    "path": "repl/docs/sw/maoni.md",
    "content": "# Maoni Katika Nuru\n\nKatika Nuru, unaweza kuandika maoni kutoa maelezo na hati kwa kazi yako. Maoni ni mistari ya maandishi ambayo hupuuzwa na mfasiri (interpreter) wa Nuru, kwa hivyo haitaathiri tabia ya programu yako. Kuna aina mbili za maoni katika Nuru: maoni ya mstari mmoja na maoni ya mistari mingi.\n\n## Maoni ya Mstari Mmoja\n\nMaoni ya mstari mmoja yanatumiwa kutoa maelezo mafupi au hati kwa mstari mmoja wa kazi. Kuandika maoni ya mstari mmoja katika Nuru, tumia mikwaju miwili ya mbele (//) ikifuatiwa na maandishi ya maoni yako. Hapa kuna mfano:\n\n```s\n// Mstari huu utapuuzwa na mfasiri wa Nuru\n```\n\nKatika mfano huu, maandishi ya maoni \"Mstari huu utapuuzwa na mfasiri wa Nuru\" yatapuuzwa na mfasiri, kwa hivyo haitaathiri tabia ya programu.\n\n## Maoni ya Mistari Mingi\n\nMaoni ya mistari mingi yanatumiwa kutoa maelezo ya kina zaidi au hati kwa mistari mingi ya programu yako. Kuandika maoni ya mistari mingi katika Nuru, tumia ukwaju wa mbele ikifuatiwa na nyota ( /* ) kuanza maoni, na nyota ikifuatiwa na ukwaju wa mbele ( */ ) kumaliza maoni. Hapa kuna mfano:\n\n```s\n/\nMistari hii\nIta\npuuzwa\n/\n```\n\nKatika mfano huu, mistari yote kati ya alama /* na */ itapuuzwa na mfasiri wa Nuru, kwa hivyo haitaathiri tabia ya programu.\n\nKwa kutumia maoni ya mstari mmoja na maoni ya mistari mingi katika Nuru, unaweza kufanya kazi yako iwe rahisi kusoma na kudumisha kwa ajili yako na wengine ambao watahitaji kufanya kazi na programu yako katika siku zijazo.\n"
  },
  {
    "path": "repl/docs/sw/null.md",
    "content": "# Tupu (Null)"
  },
  {
    "path": "repl/docs/sw/numbers.md",
    "content": "# Namba na Desimali (Ints/Floats)"
  },
  {
    "path": "repl/docs/sw/operators.md",
    "content": "# Matendaji (Operators)"
  },
  {
    "path": "repl/docs/sw/range.md",
    "content": "## Kitendakazi cha Mfululizo\n\nKitendakazi cha `mfululizo` hutoa mfululizo wa nambari, sawa na kitendakazi cha `range()` cha Python. Kinaweza kutumika katika vitanzi au kuunda safu za nambari zinazofuatana.\n\n### Muundo\n\n```go\nmfululizo(mwisho)\nmfululizo(mwanzo, mwisho)\nmfululizo(mwanzo, mwisho, hatua)\n```\n\n### Vipengele\n\n- `mwisho`: Kikomo cha juu cha mfululizo (haijumuishwi).\n- `mwanzo` (si lazima): Thamani ya kuanzia ya mfululizo. Chaguo-msingi ni 0.\n- `hatua` (si lazima): Ongezeko kati ya kila nambari katika mfululizo. Chaguo-msingi ni 1.\n\n### Thamani Inayorudishwa\n\nHurudisha safu ya nambari kamili.\n\n### Mifano\n\n```go\n// Toa nambari kutoka 0 hadi 4\nkwa i katika mfululizo(5) {\n    andika(i)\n}\n// Tokeo: 0 1 2 3 4\n\n// Toa nambari kutoka 1 hadi 9\nkwa i katika mfululizo(1, 10) {\n    andika(i)\n}\n// Tokeo: 1 2 3 4 5 6 7 8 9\n\n// Toa nambari shufwa kutoka 0 hadi 8\nkwa i katika mfululizo(0, 10, 2) {\n    andika(i)\n}\n// Tokeo: 0 2 4 6 8\n\n// Toa nambari kwa mpangilio wa kurudi nyuma\nkwa i katika mfululizo(10, 0, -1) {\n    andika(i)\n}\n// Tokeo: 10 9 8 7 6 5 4 3 2 1\n```\n\n### Vidokezo\n\n- Thamani ya `mwisho` haijumuishwi, ikimaanisha mfululizo utasimama kabla ya kufikia thamani hii.\n- Ikiwa `hatua` hasi imetolewa, `mwanzo` inapaswa kuwa kubwa kuliko `mwisho`.\n- Thamani ya `hatua` haiwezi kuwa sifuri.\n"
  },
  {
    "path": "repl/docs/sw/strings.md",
    "content": "# Neno (Strings)"
  },
  {
    "path": "repl/docs/sw/switch.md",
    "content": "# Badili (Switch)"
  },
  {
    "path": "repl/docs/sw/while.md",
    "content": "# Wakati (While)"
  },
  {
    "path": "repl/docs.go",
    "content": "package repl\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/evaluator\"\n\t\"github.com/NuruProgramming/Nuru/lexer\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n\t\"github.com/NuruProgramming/Nuru/parser\"\n\t\"github.com/NuruProgramming/Nuru/styles\"\n\t\"github.com/charmbracelet/bubbles/key\"\n\t\"github.com/charmbracelet/bubbles/list\"\n\t\"github.com/charmbracelet/bubbles/textarea\"\n\t\"github.com/charmbracelet/bubbles/viewport\"\n\ttea \"github.com/charmbracelet/bubbletea\"\n\t\"github.com/charmbracelet/glamour\"\n\t\"github.com/charmbracelet/lipgloss\"\n\tzone \"github.com/lrstanley/bubblezone\"\n)\n\nvar (\n\tbuttonStyle = lipgloss.NewStyle().\n\t\t\tBorder(lipgloss.RoundedBorder(), true, false).\n\t\t\tPadding(0, 3).\n\t\t\tMarginTop(1)\n\n\tactiveButtonStyle = buttonStyle.Copy().\n\t\t\t\tForeground(lipgloss.Color(\"#FFF7DB\")).\n\t\t\t\tBackground(lipgloss.Color(\"#aa6f5a\")).\n\t\t\t\tMargin(0, 2).\n\t\t\t\tUnderline(true)\n\n\ttableOfContentStyle = lipgloss.NewStyle().Margin(1, 2).BorderStyle(lipgloss.RoundedBorder()).\n\t\t\t\tBorderForeground(lipgloss.Color(\"#aa6f5a\")).\n\t\t\t\tForeground(lipgloss.Color(\"#aa6f5a\")).\n\t\t\t\tPadding(2)\n)\n\ntype item struct {\n\ttitle, desc, filename string\n}\n\nfunc (i item) Title() string       { return i.title }\nfunc (i item) Description() string { return i.desc }\nfunc (i item) FilterValue() string { return i.title }\n\ntype languages struct {\n\ttitle, desc, dir string\n}\n\nfunc (l languages) Title() string       { return l.title }\nfunc (l languages) Description() string { return l.desc }\nfunc (l languages) FilterValue() string { return l.title }\n\ntype playground struct {\n\tid             string\n\toutput         viewport.Model\n\tcode           string\n\teditor         textarea.Model\n\tdocs           viewport.Model\n\tready          bool\n\tfilename       string\n\tcontent        []byte\n\tmybutton       string\n\tfileSelected   bool\n\ttoc            list.Model\n\twindowWidth    int\n\twindowHeight   int\n\tdocRenderer    *glamour.TermRenderer\n\tlanguage       string\n\tlanguageCursor list.Model\n}\n\nfunc (pg playground) Init() tea.Cmd {\n\treturn textarea.Blink\n}\n\nfunc (pg playground) Update(msg tea.Msg) (tea.Model, tea.Cmd) {\n\tvar (\n\t\tedCmd  tea.Cmd\n\t\topCmd  tea.Cmd\n\t\tdocCmd tea.Cmd\n\t\ttocCmd tea.Cmd\n\t)\n\n\tpg.editor, edCmd = pg.editor.Update(msg)\n\tpg.output, opCmd = pg.output.Update(msg)\n\tpg.languageCursor, _ = pg.languageCursor.Update(msg)\n\tif !pg.fileSelected {\n\t\tpg.toc, tocCmd = pg.toc.Update(msg)\n\t}\n\n\tswitch msg := msg.(type) {\n\tcase tea.KeyMsg:\n\t\tswitch msg.Type {\n\t\tcase tea.KeyCtrlC:\n\t\t\tfmt.Println(pg.editor.Value())\n\t\t\treturn pg, tea.Quit\n\t\tcase tea.KeyEnter:\n\t\t\tif pg.language == \"\" {\n\t\t\t\ti, ok := pg.languageCursor.SelectedItem().(languages)\n\t\t\t\tif ok {\n\t\t\t\t\tpg.language = i.dir\n\t\t\t\t\tif pg.language == \"en\" {\n\t\t\t\t\t\tpg.toc = list.New(englishItems, list.NewDefaultDelegate(), pg.windowWidth/2-4, pg.windowHeight-8)\n\t\t\t\t\t\tpg.toc.Title = \"Table of Contents\"\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpg.toc = list.New(kiswahiliItems, list.NewDefaultDelegate(), pg.windowWidth/2-4, pg.windowHeight-8)\n\t\t\t\t\t\tpg.toc.Title = \"Yaliyomo\"\n\t\t\t\t\t}\n\t\t\t\t\treturn pg, tea.EnterAltScreen\n\t\t\t\t}\n\t\t\t}\n\t\t\ti, ok := pg.toc.SelectedItem().(item)\n\t\t\tif ok {\n\t\t\t\tpg.filename = i.filename\n\t\t\t\tcontent, err := res.ReadFile(\"docs/\" + pg.language + \"/\" + pg.filename)\n\t\t\t\tif err != nil {\n\t\t\t\t\tpanic(err)\n\t\t\t\t}\n\t\t\t\tpg.content = content\n\t\t\t\tstr, err := pg.docRenderer.Render(string(pg.content))\n\t\t\t\tif err != nil {\n\t\t\t\t\tpanic(err)\n\t\t\t\t}\n\n\t\t\t\tpg.docs.SetContent(str + \"\\n\\n\\n\\n\\n\\n\")\n\n\t\t\t\tif err != nil {\n\t\t\t\t\tpanic(err)\n\t\t\t\t}\n\t\t\t\tpg.fileSelected = true\n\t\t\t\tpg.editor.Focus()\n\t\t\t}\n\t\tcase tea.KeyCtrlR:\n\t\t\tif strings.Contains(pg.editor.Value(), \"jaza\") {\n\t\t\t\tpg.output.SetContent(styles.HelpStyle.Italic(false).Render(\"Samahani, huwezi kutumia `jaza()` kwa sasa.\"))\n\t\t\t} else {\n\t\t\t\t// this is just for the output will find a better solution\n\t\t\t\tcode := strings.ReplaceAll(pg.editor.Value(), \"andika\", \"_andika\")\n\t\t\t\tpg.code = code\n\t\t\t\tenv := object.NewEnvironment()\n\t\t\t\tl := lexer.New(pg.code)\n\t\t\t\tp := parser.New(l)\n\t\t\t\tprogram := p.ParseProgram()\n\t\t\t\tif len(p.Errors()) != 0 {\n\t\t\t\t\tpg.output.Style = styles.ErrorStyle.PaddingLeft(3)\n\t\t\t\t\tpg.output.SetContent(strings.Join(p.Errors(), \"\\n\"))\n\t\t\t\t} else {\n\t\t\t\t\tevaluated := evaluator.Eval(program, env)\n\t\t\t\t\tif evaluated != nil {\n\t\t\t\t\t\tif evaluated.Type() != object.NULL_OBJ {\n\t\t\t\t\t\t\tpg.output.Style = styles.ReplStyle.PaddingLeft(3)\n\t\t\t\t\t\t\tcontent := evaluated.Inspect()\n\t\t\t\t\t\t\tl := strings.Split(content, \"\\n\")\n\t\t\t\t\t\t\tif len(l) > 15 {\n\t\t\t\t\t\t\t\tcontent = strings.Join(l[len(l)-16:], \"\\n\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tpg.output.SetContent(content)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\tcase tea.KeyEsc:\n\t\t\tif pg.fileSelected {\n\t\t\t\tpg.fileSelected = false\n\t\t\t\tpg.editor.Blur()\n\t\t\t}\n\t\t}\n\n\tcase tea.MouseMsg:\n\t\tif zone.Get(pg.id + \"docs\").InBounds(msg) {\n\t\t\tpg.docs, docCmd = pg.docs.Update(msg)\n\n\t\t}\n\t\tswitch msg.Type {\n\t\tcase tea.MouseLeft:\n\t\t\tif zone.Get(pg.id + \"run\").InBounds(msg) {\n\t\t\t\tif strings.Contains(pg.editor.Value(), \"jaza\") {\n\t\t\t\t\tpg.output.SetContent(styles.HelpStyle.Italic(false).Render(\"Samahani, huwezi kutumia `jaza()` kwa sasa.\"))\n\t\t\t\t} else {\n\t\t\t\t\t// this is just for the output will find a better solution\n\t\t\t\t\tcode := strings.ReplaceAll(pg.editor.Value(), \"andika\", \"_andika\")\n\t\t\t\t\tpg.code = code\n\t\t\t\t\tenv := object.NewEnvironment()\n\t\t\t\t\tl := lexer.New(pg.code)\n\t\t\t\t\tp := parser.New(l)\n\t\t\t\t\tprogram := p.ParseProgram()\n\t\t\t\t\tif len(p.Errors()) != 0 {\n\t\t\t\t\t\tpg.output.Style = styles.ErrorStyle.PaddingLeft(3)\n\t\t\t\t\t\tpg.output.SetContent(strings.Join(p.Errors(), \"\\n\"))\n\t\t\t\t\t} else {\n\t\t\t\t\t\tevaluated := evaluator.Eval(program, env)\n\t\t\t\t\t\tif evaluated != nil {\n\t\t\t\t\t\t\tif evaluated.Type() != object.NULL_OBJ {\n\t\t\t\t\t\t\t\tpg.output.Style = styles.ReplStyle.PaddingLeft(3)\n\t\t\t\t\t\t\t\tcontent := evaluated.Inspect()\n\t\t\t\t\t\t\t\tl := strings.Split(content, \"\\n\")\n\t\t\t\t\t\t\t\tif len(l) > 15 {\n\t\t\t\t\t\t\t\t\tcontent = strings.Join(l[len(l)-16:], \"\\n\")\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tpg.output.SetContent(content)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\tcase tea.WindowSizeMsg:\n\t\tif !pg.ready {\n\t\t\t// editor code\n\t\t\tpg.editor = textarea.New()\n\t\t\tif pg.language == \"en\" {\n\t\t\t\tpg.editor.Placeholder = \"Write Nuru code here...\"\n\t\t\t} else {\n\t\t\t\tpg.editor.Placeholder = \"Andika code yako hapa...\"\n\t\t\t}\n\n\t\t\tpg.editor.Prompt = \"┃ \"\n\t\t\tpg.editor.SetWidth(msg.Width / 2)\n\t\t\tpg.editor.SetHeight((2 * msg.Height / 3) - 4)\n\n\t\t\tpg.editor.CharLimit = 0\n\t\t\tpg.editor.FocusedStyle.CursorLine = lipgloss.NewStyle()\n\t\t\tpg.editor.FocusedStyle.Base = lipgloss.NewStyle().PaddingTop(2).\n\t\t\t\tBorder(lipgloss.RoundedBorder()).\n\t\t\t\tBorderForeground(lipgloss.Color(\"238\"))\n\n\t\t\tpg.editor.ShowLineNumbers = true\n\n\t\t\t// output of editor\n\t\t\tpg.output = viewport.New(msg.Width/2, msg.Height/3-4)\n\t\t\tpg.output.Style = lipgloss.NewStyle().PaddingLeft(3)\n\t\t\tvar output string\n\t\t\tif pg.language == \"en\" {\n\n\t\t\t\toutput = \"Your code output will be displayed here...\" + strings.Repeat(\" \", msg.Width-6)\n\t\t\t} else {\n\t\t\t\toutput = \"Matokeo hapa...\" + strings.Repeat(\" \", msg.Width-6)\n\t\t\t}\n\t\t\tpg.output.SetContent(output)\n\n\t\t\t// documentation\n\t\t\tpg.docs = viewport.New(msg.Width/2, msg.Height)\n\t\t\tpg.docs.KeyMap = viewport.KeyMap{\n\t\t\t\tUp: key.NewBinding(\n\t\t\t\t\tkey.WithKeys(\"up\"),\n\t\t\t\t),\n\t\t\t\tDown: key.NewBinding(\n\t\t\t\t\tkey.WithKeys(\"down\"),\n\t\t\t\t),\n\t\t\t}\n\t\t\tpg.docs.Style = lipgloss.NewStyle().\n\t\t\t\tBorderStyle(lipgloss.RoundedBorder()).\n\t\t\t\tBorderForeground(lipgloss.Color(\"62\")).\n\t\t\t\tPadding(2)\n\n\t\t\trenderer, err := glamour.NewTermRenderer(\n\t\t\t\tglamour.WithAutoStyle(),\n\t\t\t\tglamour.WithWordWrap(msg.Width/2-4),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\n\t\t\tpg.docRenderer = renderer\n\n\t\t\tpg.toc.SetSize(msg.Width, msg.Height-8)\n\t\t\tpg.windowWidth = msg.Width\n\t\t\tpg.windowHeight = msg.Height\n\n\t\t\tif pg.language == \"en\" {\n\t\t\t\tpg.mybutton = activeButtonStyle.Width(msg.Width / 2).Height(1).Align(lipgloss.Center).Render(\"Run (CTRL + R)\")\n\t\t\t} else {\n\n\t\t\t\tpg.mybutton = activeButtonStyle.Width(msg.Width / 2).Height(1).Align(lipgloss.Center).Render(\"Run (CTRL + R)\")\n\t\t\t}\n\t\t\tpg.ready = true\n\n\t\t} else {\n\t\t\tpg.editor.SetHeight((2 * msg.Height / 3) - 4)\n\t\t\tpg.editor.SetWidth(msg.Width / 2)\n\t\t\tpg.output.Height = msg.Height/3 - 4\n\t\t\tpg.output.Width = msg.Width / 2\n\n\t\t\trenderer, err := glamour.NewTermRenderer(\n\t\t\t\tglamour.WithAutoStyle(),\n\t\t\t\tglamour.WithWordWrap(msg.Width/2-4),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\n\t\t\tpg.docRenderer = renderer\n\t\t\tstr, err := pg.docRenderer.Render(string(pg.content))\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tpg.docs.Height = msg.Height\n\t\t\tpg.docs.Width = msg.Width / 2\n\n\t\t\tpg.docs.SetContent(str + \"\\n\\n\\n\\n\\n\\n\")\n\t\t\tif pg.language == \"en\" {\n\t\t\t\tpg.mybutton = activeButtonStyle.Width(msg.Width / 2).Height(1).Align(lipgloss.Center).Render(\"Run (CTRL + R)\")\n\t\t\t} else {\n\t\t\t\tpg.mybutton = activeButtonStyle.Width(msg.Width / 2).Height(1).Align(lipgloss.Center).Render(\"Run (CTRL + R)\")\n\t\t\t}\n\t\t\tpg.toc.SetSize(msg.Width, msg.Height-8)\n\t\t\tpg.windowWidth = msg.Width\n\t\t\tpg.windowHeight = msg.Height\n\t\t}\n\t}\n\n\treturn pg, tea.Batch(edCmd, opCmd, docCmd, tocCmd)\n}\n\nfunc (pg playground) View() string {\n\tif pg.language == \"\" {\n\t\treturn lipgloss.NewStyle().PaddingTop(1).Render(pg.languageCursor.View())\n\t}\n\tif !pg.ready {\n\t\treturn \"\\n Tunakuandalia.....\"\n\t}\n\tvar docs string\n\tif !pg.fileSelected {\n\t\tdocs = zone.Mark(pg.id+\"toc\", tableOfContentStyle.Width(pg.windowWidth/2-4).Height(pg.windowHeight-8).Render(pg.toc.View()))\n\t} else {\n\t\tdocs = zone.Mark(pg.id+\"docs\", pg.docs.View())\n\t}\n\tbutton := zone.Mark(pg.id+\"run\", pg.mybutton)\n\treturn zone.Scan(lipgloss.JoinHorizontal(lipgloss.Center, docs, lipgloss.JoinVertical(lipgloss.Left, pg.editor.View(), button, pg.output.View())))\n}\n"
  },
  {
    "path": "repl/repl.go",
    "content": "package repl\n\nimport (\n\t\"embed\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\tprompt \"github.com/AvicennaJr/GoPrompt\"\n\t\"github.com/NuruProgramming/Nuru/evaluator\"\n\t\"github.com/NuruProgramming/Nuru/lexer\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n\t\"github.com/NuruProgramming/Nuru/parser\"\n\t\"github.com/NuruProgramming/Nuru/styles\"\n\t\"github.com/charmbracelet/bubbles/list\"\n\ttea \"github.com/charmbracelet/bubbletea\"\n\t\"github.com/charmbracelet/lipgloss\"\n\tzone \"github.com/lrstanley/bubblezone\"\n)\n\nconst PROMPT = \">>> \"\n\n//go:embed docs\nvar res embed.FS\n\nfunc Read(contents string) {\n\tenv := object.NewEnvironment()\n\n\tl := lexer.New(contents)\n\tp := parser.New(l)\n\n\tprogram := p.ParseProgram()\n\n\tif len(p.Errors()) != 0 {\n\t\tfmt.Println(styles.ErrorStyle.Italic(false).Render(\"Kuna Errors Zifuatazo:\"))\n\n\t\tfor _, msg := range p.Errors() {\n\t\t\tfmt.Println(\"\\t\" + styles.ErrorStyle.Render(msg))\n\t\t}\n\n\t}\n\tevaluated := evaluator.Eval(program, env)\n\tif evaluated != nil {\n\t\tif evaluated.Type() != object.NULL_OBJ {\n\t\t\tfmt.Println(styles.ReplStyle.Render(evaluated.Inspect()))\n\t\t}\n\t}\n\n}\n\nfunc Start() {\n\tenv := object.NewEnvironment()\n\n\tvar d dummy\n\td.env = env\n\tp := prompt.New(\n\t\td.executor,\n\t\tcompleter,\n\t\tprompt.OptionPrefix(PROMPT),\n\t\tprompt.OptionTitle(\"Nuru Programming Language\"),\n\t)\n\n\tp.Run()\n}\n\ntype dummy struct {\n\tenv *object.Environment\n}\n\nfunc (d *dummy) executor(in string) {\n\tif strings.TrimSpace(in) == \"exit()\" || strings.TrimSpace(in) == \"toka()\" {\n\t\tfmt.Println(lipgloss.NewStyle().Render(\"\\n🔥🅺🅰🆁🅸🅱🆄 🆃🅴🅽🅰 🔥\"))\n\t\tos.Exit(0)\n\t}\n\tl := lexer.New(in)\n\tp := parser.New(l)\n\n\tprogram := p.ParseProgram()\n\n\tif len(p.Errors()) != 0 {\n\t\tfor _, msg := range p.Errors() {\n\t\t\tfmt.Println(\"\\t\" + styles.ErrorStyle.Render(msg))\n\t\t}\n\t}\n\tenv := d.env\n\tevaluated := evaluator.Eval(program, env)\n\tif evaluated != nil {\n\t\tif evaluated.Type() != object.NULL_OBJ {\n\t\t\tfmt.Println(styles.ReplStyle.Render(evaluated.Inspect()))\n\t\t}\n\t}\n\n}\n\nfunc completer(in prompt.Document) []prompt.Suggest {\n\treturn []prompt.Suggest{}\n}\n\nfunc Docs() {\n\tzone.NewGlobal()\n\n\tlanguageChoice := []list.Item{\n\t\tlanguages{title: \"Kiswahili\", desc: \"Soma nyaraka kwa Kiswahili\", dir: \"sw\"},\n\t\tlanguages{title: \"English\", desc: \"Read documentation in English\", dir: \"en\"},\n\t}\n\n\tvar p playground\n\n\tp.languageCursor = list.New(languageChoice, list.NewDefaultDelegate(), 50, 8)\n\tp.languageCursor.Title = \"Chagua Lugha\"\n\tp.languageCursor.SetFilteringEnabled(false)\n\tp.languageCursor.SetShowStatusBar(false)\n\tp.languageCursor.SetShowPagination(false)\n\tp.languageCursor.SetShowHelp(false)\n\tp.toc = list.New(englishItems, list.NewDefaultDelegate(), 0, 0)\n\tp.toc.Title = \"Table of Contents\"\n\tp.id = zone.NewPrefix()\n\n\tif _, err := tea.NewProgram(p, tea.WithMouseAllMotion()).Run(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nvar (\n\tenglishItems = []list.Item{\n\t\titem{title: \"Arrays\", desc: \"🚀 Unleash the power of arrays in Nuru\", filename: \"arrays.md\"},\n\t\titem{title: \"Booleans\", desc: \"👍👎 Master the world of 'if' and 'else' with bools\", filename: \"bool.md\"},\n\t\titem{title: \"Builtins\", desc: \"💡 Reveal the secrets of builtin functions in Nuru\", filename: \"builtins.md\"},\n\t\titem{title: \"Comments\", desc: \"💬 Speak your mind with comments in Nuru\", filename: \"comments.md\"},\n\t\titem{title: \"Dictionaries\", desc: \"📚 Unlock the knowledge of dictionaries in Nuru\", filename: \"dictionaries.md\"},\n\t\titem{title: \"Files\", desc: \"💾 Handle files effortlessly in Nuru\", filename: \"files.md\"},\n\t\titem{title: \"For\", desc: \"🔄 Loop like a pro with 'for' in Nuru\", filename: \"for.md\"},\n\t\titem{title: \"Function\", desc: \"🔧 Create powerful functions in Nuru\", filename: \"function.md\"},\n\t\titem{title: \"Identifiers\", desc: \"🔖 Give your variables their own identity in Nuru\", filename: \"identifiers.md\"},\n\t\titem{title: \"If Statements\", desc: \"🔮 Control the flow with 'if' statements in Nuru\", filename: \"ifStatements.md\"},\n\t\titem{title: \"JSON\", desc: \"📄 Master the art of JSON in Nuru\", filename: \"json.md\"},\n\t\titem{title: \"Keywords\", desc: \"🔑 Learn the secret language of Nuru's keywords\", filename: \"keywords.md\"},\n\t\titem{title: \"Net\", desc: \"🌐 Explore the world of networking in Nuru\", filename: \"net.md\"},\n\t\titem{title: \"Null\", desc: \"🌌 Embrace the void with Null in Nuru\", filename: \"null.md\"},\n\t\titem{title: \"Numbers\", desc: \"🔢 Discover the magic of numbers in Nuru\", filename: \"numbers.md\"},\n\t\titem{title: \"Operators\", desc: \"🧙 Perform spells with Nuru's operators\", filename: \"operators.md\"},\n\t\titem{title: \"Packages\", desc: \"📦 Harness the power of packages in Nuru\", filename: \"packages.md\"},\n\t\titem{title: \"Strings\", desc: \"🎼 Compose stories with strings in Nuru\", filename: \"strings.md\"},\n\t\titem{title: \"Switch\", desc: \"🧭 Navigate complex scenarios with 'switch' in Nuru\", filename: \"switch.md\"},\n\t\titem{title: \"Time\", desc: \"⏰ Manage time with ease in Nuru\", filename: \"time.md\"},\n\t\titem{title: \"While\", desc: \"⌛ Learn the art of patience with 'while' loops in Nuru\", filename: \"while.md\"},\n\t}\n\n\tkiswahiliItems = []list.Item{\n\t\titem{title: \"Maoni Katika Nuru\", desc: \"💬 Toa mawazo yako na maoni (comments) katika Nuru\", filename: \"maoni.md\"},\n\t\titem{title: \"Vitambulishi\", desc: \"🔖 Toa utambulisho wa kipekee kwa vigezo vyako katika Nuru\", filename: \"identifiers.md\"},\n\t\titem{title: \"Nambari\", desc: \"🔢 Gundua uchawi wa nambari katika Nuru\", filename: \"numbers.md\"},\n\t\titem{title: \"Maneno\", desc: \"🎼 Tunga hadithi kwa kutumia maneno katika Nuru\", filename: \"strings.md\"},\n\t\titem{title: \"Kamusi\", desc: \"📚 Fungua maarifa ya kamusi katika Nuru\", filename: \"dictionaries.md\"},\n\t\titem{title: \"Buliani\", desc: \"👍👎 Kuwa mtaalam wa ulimwengu wa 'if' na 'else' kwa kutumia bool\", filename: \"bools.md\"},\n\t\titem{title: \"Tupu\", desc: \"🌌 Kubali utupu na Null katika Nuru\", filename: \"null.md\"},\n\t\titem{title: \"Safu\", desc: \"🚀 Fungua nguvu za safu (arrays) katika Nuru\", filename: \"arrays.md\"},\n\t\titem{title: \"Kwa\", desc: \"🔄 Rudia kama mtaalam kwa kutumia 'kwa' katika Nuru\", filename: \"for.md\"},\n\t\titem{title: \"Wakati\", desc: \"⌛ Jifunze sanaa ya subira na vitanzi vya 'wakati' katika Nuru\", filename: \"while.md\"},\n\t\titem{title: \"Undo\", desc: \"🔧 Unda kazi zenye nguvu katika Nuru\", filename: \"function.md\"},\n\t\titem{title: \"Badili\", desc: \"🧭 Elekeza hali ngumu kwa kutumia 'badili' katika Nuru\", filename: \"switch.md\"},\n\t\titem{title: \"Faili\", desc: \"💾 Shughulikia faili kwa urahisi katika Nuru\", filename: \"files.md\"},\n\t\titem{title: \"Muda\", desc: \"⏰ Simamia muda kwa urahisi katika Nuru\", filename: \"time.md\"},\n\t\titem{title: \"JSON\", desc: \"📄 Kuwa mtaalam wa sanaa ya JSON katika Nuru\", filename: \"json.md\"},\n\t\titem{title: \"Mtandao\", desc: \"🌐 Chunguza ulimwengu wa mitandao katika Nuru\", filename: \"net.md\"},\n\t\titem{title: \"Vifurushi\", desc: \"📦 Tumia nguvu za vifurushi katika Nuru\", filename: \"packages.md\"},\n\t\titem{title: \"Vijenzi\", desc: \"💡 Funua siri za kazi za kujengwa katika Nuru\", filename: \"builtins.md\"},\n\t}\n)\n"
  },
  {
    "path": "sh/install.sh",
    "content": "#!/usr/bin/env sh\n\n# Hii ni skripti ya shell ili kusakinisha programu ya Nuru.\n# Programu zinazohitajika:\n#   - curl/wget: Kupakua faili za 'tar' kutoka 'Github'\n#   - cp: Nakili faili kuenda mahali sahihi\n#   - jq: Kupata uhusiano kwenye fomati ya 'JSON'\n#   - tar: Kufungua faili za tar.gz\n\nset -e\n\nARCH=\"$(uname -m)\"\nOSNAME=\"$(uname -s)\"\nPREFIX_PATH=\"/usr\"\nBIN=\"\"\nVERSION=\"latest\"\nRELEASE_URL=\"https://github.com/NuruProgramming/Nuru/releases\"\nTEMP=\"\"\n\n# Cleanup function to remove temp directory on exit\ncleanup() {\n    if [ -n \"$TEMP\" ] && [ -d \"$TEMP\" ]; then\n        rm -rf \"$TEMP\"\n    fi\n}\ntrap cleanup EXIT\n\n# Check if command exists\ncommand_exists() {\n    command -v \"$1\" >/dev/null 2>&1\n}\n\n# Print usage information\nusage() {\n    echo \"Usage: $0 [OPTIONS]\"\n    echo \"\"\n    echo \"Options:\"\n    echo \"  -p, --prefix  The base path to be used when installing (default: /usr)\"\n    echo \"  -v, --version The version to be downloaded from GitHub (default: latest)\"\n    echo \"  -h, --help    Show this help message\"\n    echo \"\"\n}\n\n# Normalize architecture names\narch_name() {\n    case \"$ARCH\" in\n        x86_64)\n            ARCH=\"amd64\"\n            ;;\n        i386|i686)\n            ARCH=\"i386\"\n            ;;\n        arm64|aarch64)\n            ARCH=\"arm64\"\n            ;;\n        *)\n            echo \"Unsupported architecture: $ARCH\"\n            exit 2\n            ;;\n    esac\n}\n\n# Validate OS name\nos_name() {\n    case \"$OSNAME\" in\n        Darwin|Linux|Android)\n            ;;\n        *)\n            echo \"Unsupported Operating System: $OSNAME\"\n            exit 2\n            ;;\n    esac\n}\n\n# Parse command line arguments\nparse_args() {\n    while [ \"$#\" -gt 0 ]; do\n        case \"$1\" in\n            -h|--help)\n                usage\n                exit 0\n                ;;\n            -p|--prefix)\n                shift\n                if [ -z \"$1\" ]; then\n                    echo \"Error: Missing argument for --prefix\"\n                    exit 1\n                fi\n                PREFIX_PATH=\"$1\"\n                ;;\n            -v|--version)\n                shift\n                if [ -z \"$1\" ]; then\n                    echo \"Error: Missing argument for --version\"\n                    exit 1\n                fi\n                VERSION=\"$1\"\n                ;;\n            --)\n                shift\n                break\n                ;;\n            *)\n                echo \"Unknown argument: $1\"\n                usage\n                exit 1\n                ;;\n        esac\n        shift\n    done\n    BIN=\"$PREFIX_PATH/bin\"\n}\n\n# Download file using curl or wget\ndownload() {\n    URL=\"$1\"\n    if command_exists curl; then\n        curl -fSL \"$URL\"\n    elif command_exists wget; then\n        wget -qO- \"$URL\"\n    else\n        echo \"Error: Neither curl nor wget is installed.\"\n        exit 1\n    fi\n}\n\nmain() {\n    os_name\n    arch_name\n    parse_args \"$@\"\n\n    # Check required commands\n    for cmd in jq tar cp; do\n        if ! command_exists \"$cmd\"; then\n            echo \"Error: Required command '$cmd' not found.\"\n            exit 1\n        fi\n    done\n\n    if [ \"$VERSION\" = \"latest\" ]; then\n        echo \"Fetching latest version tag from GitHub...\"\n        VERSION=\"$(download \"https://api.github.com/repos/NuruProgramming/Nuru/releases/latest\" | jq -r .tag_name)\"\n        if [ -z \"$VERSION\" ] || [ \"$VERSION\" = \"null\" ]; then\n            echo \"Error: Unable to determine latest version.\"\n            exit 1\n        fi\n    fi\n\n    TAR_URL=\"$RELEASE_URL/download/$VERSION/nuru_${OSNAME}_${ARCH}.tar.gz\"\n    echo \"Downloading Nuru version $VERSION for $OSNAME/$ARCH...\"\n\n    TEMP=\"$(mktemp -d)\"\n    if ! download \"$TAR_URL\" | tar -xz -C \"$TEMP\"; then\n        echo \"Error: Failed to download or extract archive.\"\n        exit 1\n    fi\n\n    # Ensure bin directory exists\n    if [ ! -d \"$BIN\" ]; then\n        echo \"Creating directory $BIN\"\n        mkdir -p \"$BIN\"\n    fi\n\n    echo \"Installing Nuru to $BIN/nuru\"\n    if ! cp \"$TEMP/nuru\" \"$BIN/\"; then\n        echo \"Error: Failed to copy binary to $BIN\"\n        exit 1\n    fi\n\n    echo \"Installation complete.\"\n}\n\nmain \"$@\"\n"
  },
  {
    "path": "styles/styles.go",
    "content": "package styles\n\nimport \"github.com/charmbracelet/lipgloss\"\n\nvar (\n\tTitleStyle   = lipgloss.NewStyle().Margin(1, 0).Foreground(lipgloss.Color(\"#aa6f5a\"))\n\tVersionStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(\"#ff9671\"))\n\tAuthorStyle  = lipgloss.NewStyle().Italic(true).Foreground(lipgloss.Color(\"#ff9671\"))\n\tHelpStyle    = lipgloss.NewStyle().Italic(true).Faint(true).Foreground(lipgloss.Color(\"#ffe6d6\"))\n\tErrorStyle   = lipgloss.NewStyle().Foreground(lipgloss.Color(\"196\")).Italic(true)\n\tReplStyle    = lipgloss.NewStyle().Foreground(lipgloss.Color(\"76\")).Italic(true)\n\tPromptStyle  = \"\"\n)\n"
  },
  {
    "path": "third_party/math/README.md",
    "content": "# Pakeji Hesabu (Math Package)\n\nPakeji Hesabu is a math package written in pure Nuru by [VictorKariuki](https://github.com/VictorKariuki).\n\nThis package provides various mathematical functions and constants implemented in nuru programming language. It includes methods for `trigonometric functions`, `logarithmic functions`, `array operations`, and `utility functions`.\n\n\n## Usage\nTo use the `pakeji hesabu` package follow the steps below:\n\n1. Copy the `hesabu.nr` file and any required third-party package files into the same directory as your project.\n\n2. Ensure that the package file names end with the `.nr` extension and match the package names. For example, if the package name is `hesabu`, the corresponding file name should be `hesabu.nr`.\n\n3. You can directly import the `hesabu.nr` package and any required third-party packages in your Nuru code using the `tumia` keyword. For example:\n\n   ```nuru\n   tumia \"hesabu\"\n   ```\n   Example of calling the package methods:\n   ```nuru\n   andika(hesabu.e())\n## What is in\nThis package covers a wide range of mathematical operations, including `basic arithmetic`, `trigonometry`, `exponential and logarithmic functions`, `rounding and comparison operations`, as well as some `utility and array operations`.\n\nThe methods provided in the `hesabu` package can be classified into different categories based on their functionalities. Here is a classification of the methods:\n\n1. Trigonometric Functions:\n   - `cos(x)`\n   - `sin(x)`\n   - `tan(x)`\n   - `acos(x)`\n   - `asin(x)`\n   - `atan(x)`\n\n2. Hyperbolic Functions:\n   - `cosh(x)`\n   - `sinh(x)`\n   - `tanh(x)`\n   - `acosh(x)`\n   - `asinh(x)`\n   - `atanh(x)`\n\n3. Exponential and Logarithmic Functions:\n   - `exp(x)`\n   - `expm1(x)`\n   - `log(x)`\n   - `log10(x)`\n   - `log1p(x)`\n\n4. Other Mathematical Functions:\n   - `abs(namba)`\n   - `ceil(x)`\n   - `floor(x)`\n   - `sqrt(x)`\n   - `cbrt(x)`\n   - `root(x, n)`\n   - `hypot(values)`\n   - `factorial(n)`\n\n5. Rounding and Comparison Functions:\n   - `round(x, method)`\n   - `max(numbers)`\n   - `min(numbers)`\n\n6. Utility Functions:\n   - `sign(x)`\n   - `isNegative(num)`\n   - `isInteger(num)`\n   - `getIntegerPart(num)`\n\n7. Array and List Operations:\n   - `list(first, last, interval)`\n   - `reduce(iterator, callback, initialValue)`\n\n\n### 1. Constants:\n   - **PI**: Represents the mathematical constant `π`.\n   - **e**: Represents `Euler's Number`.\n   - **phi**: Represents the `Golden Ratio`.\n   - **ln10**: Represents the `natural logarithm of 10`.\n   - **ln2**: Represents the `natural logarithm of 2`.\n   - **log10e**: Represents the `base 10 logarithms` of Euler's number `(e)`.\n   - **log2e**: Represents the `base 2 logarithm` of Euler's number` (e)`.\n   - **sqrt1_2**: Represents the `square root` of `1/2`.\n   - **sqrt2**: Represents the `square root` of `2`.\n   - **sqrt3**: Represents the `square root` of `3`.\n   - **sqrt5**: Represents the `square root` of `5`.\n   - **EPSILON**: Represents a small value (2.220446049250313e-16).\n\n### 2. Methods:\n\n1. **abs(namba)**\n   - Description: Calculates the absolute value of a number.\n   - Example: `hesabu.abs(-42)` returns `42`.\n\n2. **acos(x)**\n   - Description: Calculates the arccosine of a number.\n   - Example: `hesabu.acos(0.5)` returns `1.0471975511965979`.\n\n3. **acosh(x)**\n   - Description: Calculates the inverse hyperbolic cosine of a number.\n   - Example: `hesabu.acosh(2)` returns `1.3169578969248166`.\n\n4. **asin(x)**\n   - Description: Calculates the arcsine of a number using the Taylor series.\n   - Example: `hesabu.arcsin(0.5)` returns `0.5235987755982989`.\n\n5. **asinh(x)**\n   - Description: Calculates the inverse hyperbolic sine of a number.\n   - Example: `hesabu.arsinh(2)` returns `1.4436354751788103`.\n\n6. **atan(x)**\n   - Description: Calculates the arctangent of a number using the Taylor series.\n   - Example: `hesabu.atan(1)` returns `0.7853981633974485`.\n\n7. **atan2(y, x)**\n   - Description: Calculates the arctangent of the quotient of its arguments.\n   - Example: `hesabu.atan2(1, 1)` returns `0.7853981633974483`.\n\n8. **atanh(x)**\n   - Description: Calculates the inverse hyperbolic tangent of a number.\n   - Example: `hesabu.atanh(0.5)` returns `0.5493061443340549`.\n\n9. **cbrt(x)**\n   - Description: Calculates the cube root of a number.\n   - Example: `hesabu.cbrt(8)` returns `2`.\n\n10. **root(x, n)**\n    - Description: Calculates the nth root of a number using the Newton-Raphson method.\n    - Example: `hesabu.root(27, 3)` returns `3`.\n\n11. **ceil(x)**\n    - Description: Rounds up to the smallest integer greater than or equal to a given number.\n    - Example: `hesabu.ceil(4.3)` returns `5`.\n\n12. **cos(x)**\n    - Description: Calculates the cosine of an angle in radians using the Taylor series.\n    - Example: `hesabu.cos(5)` returns `0.28366218546322464`.\n\n13. **cosh(x)**\n    - Description: Calculates the hyperbolic cosine of a number.\n    - Example: `hesabu.cosh(5)` returns `74.20994842490012`.\n\n14. **exp(x)**\n    - Description: Calculates the value of Euler's number raised to the power of a given number.\n    - Example: `hesabu.exp(2)` returns `7.389056098930649`.\n\n15. **expm1(x)**\n    - Description: Calculates Euler's number raised to the power of a number minus 1.\n    - Example: `hesabu.expm1(1)` returns `1.7182818284590455`.\n\n16. **floor(x)**\n    - Description: Rounds down to the largest integer less than or equal to a given number.\n    - Example: `hesabu.floor(4.7)` returns `4`.\n\n17. **hypot(values)**\n    - Description: Calculates the square root of the sum of squares of the given values.\n    - Example: `hesabu.hypot([3, 4])` returns `5`.\n\n18. **log(x)**\n    - Description: Calculates the natural logarithm of a number.\n    - Example: `hesabu.log(2)` returns `0.69314718056`.\n\n19. **log10(x)**\n    - Description: Calculates the base 10 logarithm of a number.\n    - Example: `hesabu.log10(100)` returns `1.9999999999573126`.\n\n20. **log1p(x)**\n    - Description: Calculates the natural logarithm of 1 plus the given number.\n    - Example: `hesabu.log1p(1)` returns `0.6931471805599451`.\n\n21. **log2(x)**\n    - Description: Calculates the base 2 logarithm of a number.\n    - Example: `hesabu.log2(8)` returns `3`.\n\n22. **max(numbers)**\n    - Description: Finds the maximum value in a list of numbers.\n    - Example: `hesabu.max([4, 2, 9, 5])` returns `9`.\n\n23. **min(numbers)**\n    - Description: Finds the minimum value in a list of numbers.\n    - Example: `hesabu.min([4, 2, 9, 5])` returns `2`.\n\n24. **round(x, method)**\n    - Description: Rounds a number to the nearest integer using the specified method.\n    - supported methods:\n        - \"rpi\" (round to the nearest integer using the principle of rounding half to the nearest even)\n        - \"rni\" (round to the nearest integer using the principle of rounding half away from zero)\n        - \"ri\" (round to the nearest integer using the standard rounding method)\n        - An invalid method results in returning NaN (Not a Number)\n    - Example: `hesabu.round(4.6, \"rpi\")` returns `5`.\n\n25. **sign(x)**\n    - Description: Determines the sign of a number.\n    - Example: `hesabu.sign(-5)` returns `-1`.\n\n26. **sin(x)**\n    - Description: Calculates the sine of an angle in radians using the Taylor series.\n    - Example: `hesabu.sin(1)` returns `0.8414709848078965`.\n\n27. **sinh(x)**\n    - Description: Calculates the hyperbolic sine of a number.\n    - Example: `hesabu.sinh(0)` returns `0`.\n\n28. **sqrt(x)**\n    - Description: Calculates the square root of a number.\n    - Example: `hesabu.sqrt(4)` returns `2`.\n\n29. **tan(x)**\n    - Description: Calculates the tangent of an angle in radians.\n    - Example: `hesabu.tan(1)` returns `1.557407724654902`.\n\n30. **tanh(x)**\n    - Description: Calculates the hyperbolic tangent of a number.\n    - Example: `hesabu.tanh(0)` returns `0`.\n\n31. **factorial(n)**\n    - Description: Calculates the factorial of a number.\n    - Example: `hesabu.factorial(5)` returns `120`.\n\n32. **isNegative(num)**\n    - Description: Checks if a number is negative.\n    - Example: `hesabu.isNegative(-5)` returns `kweli`.\n\n33. **isInteger(num)**\n    - Description: Checks if a number is an integer.\n    - Example: `hesabu.isInteger(4.5)` returns `sikweli`.\n\n34. **getIntegerPart(num)**\n    - Description: Gets the integer part of a number.\n    - Example: `hesabu.getIntegerPart(4.5)` returns `4`.\n\n35. **list(first, last, interval)**\n    - Description: Creates a list of numbers with the specified interval between them.\n    - Example: `hesabu.list(1, 5, 1)` returns `[1, 2, 3, 4]`.\n\n36. **reduce(iterator, callback, initialValue)**\n      - Description: Reduces the elements of an array to a single value using a specified callback function.\n      - Example: `hesabu.reduce([1, 2, 3, 4], [callback function], 0)`\n      ```s\n        fanya callback = unda(accumulator, currentValue){\n            rudisha accumulator + currentValue;\n        }\n\n        andika(hesabu.reduce([1, 2, 3, 4], callback, 0)) \\\\ returns 10.\n### Contributing\n\nContributions to the `pakeji hesabu` package are welcome. If you have any improvements or bug fixes, feel free to create a pull request.\n\n### License\n\nThis package is available under the MIT License. See the [LICENSE](LICENSE) file for more information."
  },
  {
    "path": "third_party/math/hesabu.nr",
    "content": "tumia hisabati\n\npakeji hesabu{\n    //CONSTRUCTOR METHOD    \n    andaa = unda() {}\n\n    // Constants\n    // π (Pi)\n    PI = unda() {\n        rudisha 3.141592653589793;\n    }\n\n    // e (Euler's Number)\n    e = unda() {\n        rudisha 2.718281828459045;\n    }\n\n    // φ (Phi, Golden Ratio)\n    phi = unda() {\n        rudisha 1.618033988749895;\n    }\n\n    // Natural logarithm of 10\n    ln10 = unda() {\n        rudisha 2.302585092994046;\n    }\n\n    // Natural logarithm of 2\n    ln2 = unda() {\n        rudisha 0.6931471805599453;\n    }\n\n    // Base 10 logarithm of Euler's number (e)\n    log10e = unda() {\n        rudisha 0.4342944819032518;\n    }\n\n    // Base 2 logarithm of Euler's number (e)\n    log2e = unda() {\n        rudisha 1.4426950408889634;\n    }\n\n    // √1/2 (equivalent to 1 / sqrt(2))\n    sqrt1_2 = unda() {\n        rudisha 0.7071067811865476;\n    }\n\n    // √2 (Square Root of 2)\n    sqrt2 = unda() {\n        rudisha 1.414213562373095;\n    }\n\n    // √3 (Square Root of 3)\n    sqrt3 = unda() {\n        rudisha 1.732050807568877;\n    }\n\n    // √5 (Square Root of 5)\n    sqrt5 = unda() {\n        rudisha 2.236067977499790;\n    }\n\n    // @.EPSILON\n    EPSILON = unda() {\n        rudisha 0.0000000000000002220446049250313;\n    }\n\n    // Methods\n    //abs(namba), calculates the absolute value of a number.\n    abs = unda(namba){\n        kama(namba < 0){\n            rudisha - 1 * namba;\n        }\n\n        rudisha namba;\n    }\n\n    //acos(x), calculates the arccosine of a number.\n    acos = unda(x) {\n        kama (x < -1 || x > 1) {\n            rudisha \"NaN\";\n        }\n\n        fanya EPSILON = 1*10.0**-10; // Small value for precision\n\n        fanya acosRecursive = unda(guess) {\n            fanya f = cos(guess) - x;\n            fanya fPrime = -sin(guess);\n            fanya nextGuess = guess - f / fPrime;\n\n            kama (abs(nextGuess - guess) < EPSILON) {\n                rudisha nextGuess;\n            }\n\n            rudisha acosRecursive(nextGuess);\n        }\n\n        rudisha acosRecursive(hisabati.PI() / 2); // Initial guess for acos\n    }\n\n    //acosh(x), calculates the inverse hyperbolic cosine of a number.\n    acosh = unda(x) {\n        kama(x < 1) {\n            rudisha 0;\n        }\n\n        rudisha log(x + sqrt(x * x - 1));\n    }\n\n    //asin(x), calculates the arcsine of a number using the Newton Method.\n    asin = unda(x) {\n        kama (x < -1 || x > 1) {\n            rudisha \"NaN\";\n        }\n\n        fanya maxIterations = 50; // Maximum number of iterations\n\n        fanya newtonAsin = unda(guess, prev, iterations) {\n            fanya next = guess - (sin(guess) - x) / cos(guess);\n\n            kama (abs(next - prev) < hisabati.EPSILON() || iterations >= maxIterations) {\n                rudisha next;\n            }\n\n            rudisha newtonAsin(next, guess, iterations + 1);\n        }\n\n        rudisha newtonAsin(x, 1, 0);\n    }\n\n\n    //asinh(x), calculates the inverse hyperbolic sine of a number.\n    asinh = unda(x) {\n        // Calculate arsinh using the formula: arsinh(x) = ln(x + sqrt(x^2 + 1))\n        kama(x >= 0) {\n            rudisha log(x + sqrt(x * x + 1));\n        } sivyo {\n            // For negative values, arsinh(x) = -arsinh(-x)\n            rudisha - log(-x + sqrt(x * x + 1));\n        }\n    }\n\n    //atan(x), calculates the arctangent of a number using the Taylor series.\n    atan = unda(x) {\n        fanya EPSILON = 1*10.0**-10; // Small value for precision\n\n        fanya atanRecursive = unda(guess) {\n            fanya f = tan(guess) - x;\n            fanya fPrime = 1 / (cos(guess) * cos(guess));\n            fanya nextGuess = guess - f / fPrime;\n\n            kama (abs(nextGuess - guess) < EPSILON) {\n                rudisha nextGuess;\n            }\n\n            rudisha atanRecursive(nextGuess);\n        }\n\n        rudisha atanRecursive(x); // Initial guess for atan\n    }\n\n    //atanh(x), calculates the inverse hyperbolic tangent of a number.\n    atan2 = unda(y, x) {\n        kama(x > 0) {\n            rudisha atan(y / x);\n        } au kama(x < 0 && y >= 0) {\n            rudisha atan(y / x) + hisabati.PI();\n        } au kama(x < 0 && y < 0) {\n            rudisha atan(y / x) - hisabati.PI();\n        } au kama(x == 0 && y > 0) {\n            rudisha hisabati.PI() / 2;\n        } au kama(x == 0 && y < 0) {\n            rudisha - hisabati.PI() / 2;\n        } au kama(x == 0 && y == 0) {\n            rudisha \"NaN\"; // Undefined\n        }\n    }\n\n    //atanh(x), calculates the inverse hyperbolic tangent of a number.\n    atanh = unda(x) {\n        kama(x < -1 || x > 1) {\n            rudisha 0;\n        }\n        rudisha 0.5 * log((1.0 + x) / (1.0 - x));\n    }\n\n    //cbrt(x), calculates the cube root of a number.\n    cbrt = unda(x) {\n        kama(x == 0) {\n            rudisha 0;\n        }\n        \n        kama(x >= 0) {\n            rudisha root(x, 3);\n        } sivyo {\n            rudisha - root(-x, 3);\n        }\n    }\n\n    //root(x, n), calculates the nth root of a number using the Newton-Raphson method.\n    root =  unda(x, n) {\n        fanya guess = x / 2; // Initial guess\n        fanya tolerance = 0.0000000001; // Tolerance for convergence\n\n        fanya calculateNthRoot = unda(x, n, guess, tolerance) {\n            fanya nextGuess = ((n - 1) * guess + x / (guess ** (n - 1))) / n;\n            fanya ipotolerance = abs(nextGuess - guess);\n            kama (ipotolerance < tolerance) {rudisha nextGuess};\n            rudisha calculateNthRoot(x, n, nextGuess, tolerance);\n        }\n        \n        rudisha calculateNthRoot(x, n, guess, tolerance)\n    }\n\n    //ceil(x), rounds up to the smallest integer greater than or equal to a given number.\n    ceil = unda(x) {\n        kama(x >= 0) {\n            kama(x % 1 == 0) {\n            rudisha x; // x is already an integer\n            }\n            rudisha floor(x) + 1;\n        } sivyo {\n            rudisha - floor(abs(x));\n        }\n    }\n\n    //cos(x), calculates the cosine of an angle.\n    cos = unda(x) {\n        fanya result = 1; // Initialize the result\n        fanya term = 1;\n\n        kwa i ktk list(2,101,2) {\n            term = (-term * x * x) / (i * (i - 1));\n            result += term;\n        }\n        rudisha result;\n    }\n\n    //cosh(x), calculates the hyperbolic cosine of a number.\n    cosh = unda(x) {\n        fanya eToX = exp(x);\n        fanya eToMinusX = exp(-x);\n        rudisha(eToX + eToMinusX) / 2;\n    }\n\n    //exp(x), calculates the value of Euler's number raised to the power of a given number.\n    exp = unda(n) {\n        fanya result = 1;\n        fanya term = 1;\n       \n        kwa i, v ktk list(1,23,1) {\n            term = term*(n/v);\n            result = result + term;\n        }\n\n        rudisha result;\n    }\n\n\n    //expm1(x), calculates the value of Euler's number raised to the power of a given number minus 1.\n    expm1 = unda(x) {\n        kama (x == -1) {\n            rudisha -0.6321205588285577; // Handling the special case for -1\n        } au kama (x == 0) {\n            rudisha 0; // Handling the special case for 0\n        } au kama (abs(x) < hisabati.EPSILON()) {\n            rudisha x + 0.5 * x * x; // Approximation for very small x\n        } sivyo {\n            rudisha exp(x) - 1;\n        }\n    }\n\n\n    //floor(x), rounds down to the largest integer less than or equal to a given number.\n    floor = unda(x) {\n        kama(x >= 0) {\n            rudisha x - (x % 1);\n        } sivyo {\n            rudisha x - (1 + x % 1);\n        }\n    }\n\n    //hypot(values), calculates the square root of the sum of squares of the given values.\n    hypot = unda(values) {\n        // Calculate the sum of squares of the values\n        fanya exp = unda(acc, value){\n            rudisha acc + value ** 2;\n        }\n\n        fanya sumOfSquares = reduce(values, exp, 0);\n\n        // Calculate the square root of the sum of squares\n        fanya result = sqrt(sumOfSquares);\n\n        rudisha result;\n    }\n\n    //log(x), calculates the natural logarithm of a number.\n    log = unda(x) {\n        kama (x <= 0) {\n            rudisha \"NaN\";\n        }\n        kama (x == 1) {\n            rudisha 0;\n        }\n        kama (x < 0) {\n            rudisha -log(-x);\n        }\n        fanya n = 1000; // Number of iterations\n        fanya y = (x - 1) / (x + 1);\n        fanya ySquared = y * y;\n        fanya result = 0;\n        kwa i ktk list(1,n+1,2) {\n            result += (1 / i) * y**i;\n        }\n        rudisha 2 * result;\n    }\n\n    //log10(x), calculates the base 10 logarithm of a number.\n    log10 = unda(x) {\n        kama(x <= 0) {\n            rudisha 0;\n        }\n\n        // Calculate natural logarithm and divide by the natural logarithm of 10\n        rudisha log(x) / log(10.0);\n    }\n\n    //log1p(x), calculates the natural logarithm of 1 plus the given number.\n    log1p = unda(x) {\n        kama (x <= -1) {\n            rudisha NaN; // Not a Number\n        } au kama (abs(x) < hisabati.EPSILON()) {\n            rudisha x - 0.5 * x * x; // Series expansion for small x\n        } sivyo {\n            rudisha log(1.0 + x);\n        }\n    }\n\n    //log2(x), calculates the base 2 logarithm of a number.\n    log2 = unda(x) {\n        kama(x <= 0) {\n            rudisha 0;\n        }\n\n        fanya result = 0;\n        fanya currentValue = x;\n\n        wakati(currentValue > 1) {\n            currentValue /= 2;\n            result++;\n        }\n\n        rudisha result;\n    }\n\n    //max(numbers), finds the maximum value in a list of numbers.\n    max = unda(numbers) {\n        // Initialize a variable to store the largest number\n        fanya largest = 0;\n\n        // Iterate through the numbers and update 'largest' kama a larger number is found\n        kwa num ktk numbers {\n            kama(num > largest) {\n                largest = num;\n            }\n        }\n\n        // rudisha the largest number (or 0 kama there are no parameters)\n        rudisha largest;\n    }\n\n    //min(numbers), finds the minimum value in a list of numbers.\n    min = unda(numbers) {\n        kama(numbers.idadi() == 0) {\n            rudisha 0;\n        }\n\n        fanya minVal = numbers[0];\n\n        fanya i = 1;\n        wakati(i < numbers.idadi()) {\n            kama(numbers[i] < minVal) {\n                minVal = numbers[i];\n            }\n            i++;\n        }\n\n        rudisha minVal;\n    }\n\n    //round(x, method), rounds a number to the nearest integer using the specified method.\n    round = unda(x, method = \"ri\") {\n        kama(method == \"rpi\") {\n            rudisha floor(x + 0.5);\n        } au kama(method == \"rni\") {\n            rudisha ceiling(x - 0.5);\n        } au kama(method == \"ri\") {\n            kama(x >= 0){\n                rudisha floor(x + 0.5);\n            }sivyo{\n                rudisha ceiling(x - 0.5);\n            }\n        } sivyo {\n            rudisha NaN; // Invalid method\n        }\n    }\n\n    //sign(x), determines the sign of a number.\n    sign = unda(x) {\n        kama(x == 0 || x == -0) {\n            rudisha x;\n        } au kama(x > 0) {\n            rudisha 1;\n        } sivyo {\n            rudisha - 1;\n        }\n    }\n\n    //sin(x), calculates the sine of an angle in radians using the Taylor series.\n    sin = unda(x) {\n        fanya result = x; // Initialize the result with the angle\n        fanya term = x;\n        // Using Maclaurin series expansion for sine\n        kwa i ktk list(3,101,2) {\n            term = (-term * x * x) / (i * (i - 1));\n            result += term;\n        }\n        rudisha result;\n    }\n\n    //sinh(x), calculates the hyperbolic sine of a number.\n    sinh = unda(x) {\n        // sinh(x) = (e^x - e^(-x)) / 2\n        fanya eToX = exp(x);\n        fanya eToMinusX = exp(-x);\n        rudisha(eToX - eToMinusX) / 2;\n    }\n\n    //sqrt(x), calculates the square root of a number.\n    sqrt = unda(x) {\n        kama(x < 0) {\n            rudisha 0;\n        }\n         kama(x >= 0) {\n            rudisha root(x, 2);\n        } sivyo {\n            rudisha - root(-x, 2);\n        }\n    }\n\n    //tan(x), calculates the tangent of an angle in radians.\n    tan = unda(x) {\n        fanya sineX = sin(x);\n        fanya cosineX = sqrt(1 - sineX * sineX);\n\n        kama(cosineX == 0) {\n            rudisha 0;\n        }\n\n        rudisha sineX / cosineX;\n    }\n\n    //tanh(x), calculates the hyperbolic tangent of a number.\n    tanh = unda(x) {\n        fanya expX = exp(x);\n        fanya expNegX = exp(-x);\n        rudisha(expX - expNegX) / (expX + expNegX);\n    }\n\n    // utility methods\n    //factorial(n), calculates the factorial of a number.\n    factorial = unda(n) {\n        kama(n == 0){ \n        rudisha 1;\n        };\n        fanya result = 1;\n        fanya i = 1;\n\n        wakati(i <= n) {\n            result *= i;\n            i++;\n        }\n\n        rudisha result;\n\n    }\n\n    //isNegative(num), checks if a number is negative.\n    isNegative = unda(num) {\n        rudisha sign(num)==-1;\n    }\n\n    //isInteger(num), checks if a number is an integer.\n    isInteger = unda(num) {\n        rudisha num == floor(num);\n    }\n\n    //getIntegerPart(num), gets the integer part of a number.\n    getIntegerPart = unda(num) {\n        // Handle negative numbers separately\n        kama(isNegative(num)) {\n            // For negative numbers, we subtract the absolute value of the fractional part from 1\n            rudisha - (ceil(-num) - 1);\n        } sivyo {\n            // For positive numbers, we simply truncate the fractional part\n            rudisha floor(num);\n        }\n    }\n\n    //Arrray Methods\n    //list(first, last, interval), creates a list of numbers with the specified interval between theM.\n    list = unda(first, last, interval){\n        fanya list = [first];\n        fanya i = first + interval;\n        wakati(i < last){\n            list.sukuma(i);\n            i += interval;\n        }\n        rudisha list;\n    }\n\n    //reduce(iterator, callback, initialValue), reduces the elements of an array to a single value using a specified callback function.\n    reduce = unda(iterator, callback, initialValue) {\n        fanya accumulator = initialValue;\n\n        kwa thamani ktk iterator {\n            accumulator = callback(accumulator, thamani);\n        }\n\n        rudisha accumulator;\n    }\n}\n"
  },
  {
    "path": "third_party/math/test.nr",
    "content": "tumia \"hesabu\"\n\nandika(\"abs: \",hesabu.abs(-42));\nandika(\"acos: \",hesabu.acos(0.5));\nandika(\"acosh: \",hesabu.acosh(2));\nandika(\"asin: \", hesabu.asin(0.5));\nandika(\"asinh: \",hesabu.asinh(2));\nandika(\"atan: \",hesabu.atan(1));\nandika(\"atan2: \",hesabu.atan2(1, 1));\nandika(\"atanh: \",hesabu.atanh(0.5));\nandika(\"cbrt: \",hesabu.cbrt(8));\nandika(\"root: \",hesabu.root(27, 3));\nandika(\"ceil: \",hesabu.ceil(4.3));\nandika(\"cos: \",hesabu.cos(5));\nandika(\"cosh: \",hesabu.cosh(5));\nandika(\"exp: \",hesabu.exp(2));\nandika(\"expm1: \",hesabu.expm1(1));\nandika(\"floor: \",hesabu.floor(4.7));\nandika(\"hypot: \",hesabu.hypot([3, 4]));\nandika(\"log: \",hesabu.log(2));\nandika(\"log10: \",hesabu.log10(100));\nandika(\"log1p: \",hesabu.log1p(1));\nandika(\"log2: \",hesabu.log2(8));\nandika(\"max: \",hesabu.max([4, 2, 9, 5]));\nandika(\"min: \",hesabu.min([4, 2, 9, 5]));\nandika(\"round: \",hesabu.round(4.6, \"rpi\"));\nandika(\"sign: \",hesabu.sign(-5));\nandika(\"sin: \",hesabu.sin(1));\nandika(\"sinh: \",hesabu.sinh(0));\nandika(\"sqrt: \",hesabu.sqrt(4));\nandika(\"tan: \",hesabu.tan(1));\nandika(\"tanh: \",hesabu.tanh(0));\nandika(\"factorial: \",hesabu.factorial(5));\nandika(\"isNegative: \",hesabu.isNegative(-5));\nandika(\"isInteger: \",hesabu.isInteger(4.5));\nandika(\"getIntegerPart: \",hesabu.getIntegerPart(4.5));\nandika(\"list: \",hesabu.list(1, 5, 1));\nfanya callback = unda(accumulator, currentValue){\n    rudisha accumulator + currentValue;\n}\nandika(\"reduce: \",hesabu.reduce([1, 2, 3, 4],callback,0) );\n"
  },
  {
    "path": "token/token.go",
    "content": "// This is where we define our tokens\n\npackage token\n\ntype TokenType string\n\ntype Token struct {\n\tType    TokenType\n\tLiteral string\n\tLine    int\n}\n\nconst (\n\tILLEGAL = \"HARAMU\"\n\tEOF     = \"MWISHO\"\n\n\t// Identifiers + literals\n\tIDENT  = \"KITAMBULISHI\"\n\tINT    = \"NAMBA\"\n\tSTRING = \"NENO\"\n\tFLOAT  = \"DESIMALI\"\n\n\t// Operators\n\tASSIGN          = \"=\"\n\tPLUS            = \"+\"\n\tMINUS           = \"-\"\n\tBANG            = \"!\"\n\tASTERISK        = \"*\"\n\tPOW             = \"**\"\n\tSLASH           = \"/\"\n\tMODULUS         = \"%\"\n\tLT              = \"<\"\n\tLTE             = \"<=\"\n\tGT              = \">\"\n\tGTE             = \">=\"\n\tEQ              = \"==\"\n\tNOT_EQ          = \"!=\"\n\tAND             = \"&&\"\n\tOR              = \"||\"\n\tPLUS_ASSIGN     = \"+=\"\n\tPLUS_PLUS       = \"++\"\n\tMINUS_ASSIGN    = \"-=\"\n\tMINUS_MINUS     = \"--\"\n\tASTERISK_ASSIGN = \"*=\"\n\tSLASH_ASSIGN    = \"/=\"\n\tMODULUS_ASSIGN  = \"%=\"\n\tSHEBANG         = \"#!\"\n\n\t//Delimiters\n\tCOMMA     = \",\"\n\tSEMICOLON = \";\"\n\tLPAREN    = \"(\"\n\tRPAREN    = \")\"\n\tLBRACE    = \"{\"\n\tRBRACE    = \"}\"\n\tLBRACKET  = \"[\"\n\tRBRACKET  = \"]\"\n\tCOLON     = \":\"\n\tDOT       = \".\"\n\tAT        = \"@\"\n\n\t// Keywords\n\tFUNCTION = \"FUNCTION\"\n\tLET      = \"FANYA\"\n\tTRUE     = \"KWELI\"\n\tFALSE    = \"SIKWELI\"\n\tIF       = \"KAMA\"\n\tELSE     = \"SIVYO\"\n\tRETURN   = \"RUDISHA\"\n\tWHILE    = \"WAKATI\"\n\tNULL     = \"TUPU\"\n\tBREAK    = \"VUNJA\"\n\tCONTINUE = \"ENDELEA\"\n\tIN       = \"KTK\"\n\tFOR      = \"KWA\"\n\tSWITCH   = \"BADILI\"\n\tCASE     = \"IKIWA\"\n\tDEFAULT  = \"KAWAIDA\"\n\tIMPORT   = \"TUMIA\"\n\tPACKAGE  = \"PAKEJI\"\n)\n\nvar keywords = map[string]TokenType{\n\t\"unda\":    FUNCTION,\n\t\"fanya\":   LET,\n\t\"kweli\":   TRUE,\n\t\"sikweli\": FALSE,\n\t\"kama\":    IF,\n\t\"au\":      ELSE,\n\t\"sivyo\":   ELSE,\n\t\"wakati\":  WHILE,\n\t\"rudisha\": RETURN,\n\t\"vunja\":   BREAK,\n\t\"endelea\": CONTINUE,\n\t\"tupu\":    NULL,\n\t\"ktk\":     IN,\n\t\"kwa\":     FOR,\n\t\"badili\":  SWITCH,\n\t\"ikiwa\":   CASE,\n\t\"kawaida\": DEFAULT,\n\t\"tumia\":   IMPORT,\n\t\"pakeji\":  PACKAGE,\n\t\"@\":       AT,\n}\n\nfunc LookupIdent(ident string) TokenType {\n\tif tok, ok := keywords[ident]; ok {\n\t\treturn tok\n\t}\n\treturn IDENT\n}\n"
  }
]